@graphprotocol/graph-cli 0.37.4 → 0.37.5
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 +8 -0
- package/dist/bin.js +6 -0
- package/dist/cli.js +26 -0
- package/dist/codegen/schema.js +244 -0
- package/dist/codegen/schema.test.js +455 -0
- package/dist/codegen/template.js +66 -0
- package/dist/codegen/types/conversions.js +335 -0
- package/dist/codegen/types/index.js +71 -0
- package/dist/codegen/types/index.test.js +563 -0
- package/dist/codegen/typescript.js +200 -0
- package/dist/codegen/util.js +40 -0
- package/dist/codegen/util.test.js +93 -0
- package/dist/command-helpers/abi.js +76 -0
- package/dist/command-helpers/auth.js +76 -0
- package/dist/command-helpers/compiler.js +66 -0
- package/dist/command-helpers/data-sources.js +29 -0
- package/dist/command-helpers/fs.js +9 -0
- package/dist/command-helpers/gluegun.js +48 -0
- package/dist/command-helpers/ipfs.js +5 -0
- package/dist/command-helpers/jsonrpc.js +27 -0
- package/dist/command-helpers/network.js +90 -0
- package/dist/command-helpers/network.test.js +86 -0
- package/dist/command-helpers/node.js +40 -0
- package/dist/command-helpers/scaffold.js +110 -0
- package/dist/command-helpers/spinner.js +80 -0
- package/dist/command-helpers/studio.js +14 -0
- package/dist/command-helpers/studio.test.js +41 -0
- package/dist/command-helpers/subgraph.js +22 -0
- package/dist/command-helpers/version.js +66 -0
- package/dist/command-helpers/version.test.js +186 -0
- package/dist/commands/add.js +187 -0
- package/dist/commands/auth.js +122 -0
- package/dist/commands/build.js +136 -0
- package/dist/commands/codegen.js +128 -0
- package/dist/commands/create.js +94 -0
- package/dist/commands/deploy.js +335 -0
- package/dist/commands/init.js +800 -0
- package/dist/commands/local.js +380 -0
- package/dist/commands/remove.js +95 -0
- package/dist/commands/test.js +293 -0
- package/dist/compiler/asc.js +83 -0
- package/dist/compiler/index.js +466 -0
- package/dist/debug.js +16 -0
- package/dist/migrations/mapping_api_version_0_0_1.js +83 -0
- package/dist/migrations/mapping_api_version_0_0_2.js +83 -0
- package/dist/migrations/mapping_api_version_0_0_3.js +83 -0
- package/dist/migrations/mapping_api_version_0_0_4.js +85 -0
- package/dist/migrations/mapping_api_version_0_0_5.js +85 -0
- package/dist/migrations/spec_version_0_0_2.js +45 -0
- package/dist/migrations/spec_version_0_0_3.js +50 -0
- package/dist/migrations/util/load-manifest.js +16 -0
- package/dist/migrations/util/versions.js +28 -0
- package/dist/migrations.js +54 -0
- package/dist/protocols/arweave/manifest.graphql +57 -0
- package/dist/protocols/arweave/scaffold/manifest.js +18 -0
- package/dist/protocols/arweave/scaffold/mapping.js +52 -0
- package/dist/protocols/arweave/subgraph.js +23 -0
- package/dist/protocols/contract.js +2 -0
- package/dist/protocols/cosmos/manifest.graphql +76 -0
- package/dist/protocols/cosmos/scaffold/manifest.js +15 -0
- package/dist/protocols/cosmos/scaffold/mapping.js +38 -0
- package/dist/protocols/cosmos/subgraph.js +28 -0
- package/dist/protocols/ethereum/abi.js +138 -0
- package/dist/protocols/ethereum/codegen/abi.js +474 -0
- package/dist/protocols/ethereum/codegen/abi.test.js +325 -0
- package/dist/protocols/ethereum/codegen/template.js +52 -0
- package/dist/protocols/ethereum/contract.js +22 -0
- package/dist/protocols/ethereum/manifest.graphql +94 -0
- package/dist/protocols/ethereum/scaffold/manifest.js +32 -0
- package/dist/protocols/ethereum/scaffold/mapping.js +65 -0
- package/dist/protocols/ethereum/subgraph.js +172 -0
- package/dist/protocols/ethereum/type-generator.js +123 -0
- package/dist/protocols/index.js +266 -0
- package/dist/protocols/ipfs/codegen/file_template.js +53 -0
- package/dist/protocols/near/contract.js +41 -0
- package/dist/protocols/near/manifest.graphql +64 -0
- package/dist/protocols/near/scaffold/manifest.js +16 -0
- package/dist/protocols/near/scaffold/mapping.js +38 -0
- package/dist/protocols/near/subgraph.js +23 -0
- package/dist/protocols/subgraph.js +2 -0
- package/dist/protocols/substreams/manifest.graphql +45 -0
- package/dist/protocols/substreams/scaffold/manifest.js +12 -0
- package/dist/protocols/substreams/subgraph.js +23 -0
- package/dist/scaffold/cosmos.test.js +82 -0
- package/dist/scaffold/ethereum.test.js +496 -0
- package/dist/scaffold/index.js +133 -0
- package/dist/scaffold/mapping.js +57 -0
- package/dist/scaffold/near.test.js +85 -0
- package/dist/scaffold/schema.js +86 -0
- package/dist/scaffold/tests.js +179 -0
- package/dist/schema.js +54 -0
- package/dist/subgraph.js +243 -0
- package/dist/type-generator.js +225 -0
- package/dist/validation/contract.js +44 -0
- package/dist/validation/index.js +10 -0
- package/dist/validation/manifest.js +266 -0
- package/dist/validation/schema.js +768 -0
- package/dist/validation/schema.test.js +35 -0
- package/dist/watcher.js +79 -0
- package/package.json +1 -1
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const immutable_1 = __importDefault(require("immutable"));
|
|
7
|
+
const protocols_1 = __importDefault(require("../protocols"));
|
|
8
|
+
const abi_1 = __importDefault(require("../protocols/ethereum/abi"));
|
|
9
|
+
const index_1 = __importDefault(require("./index"));
|
|
10
|
+
const TEST_EVENT = {
|
|
11
|
+
name: 'ExampleEvent',
|
|
12
|
+
type: 'event',
|
|
13
|
+
inputs: [
|
|
14
|
+
{ name: 'a', type: 'uint256', indexed: true },
|
|
15
|
+
{ name: 'b', type: 'bytes[4]' },
|
|
16
|
+
{ type: 'string' },
|
|
17
|
+
{
|
|
18
|
+
name: 'c',
|
|
19
|
+
type: 'tuple',
|
|
20
|
+
components: [
|
|
21
|
+
{ name: 'c1', type: 'uint256' },
|
|
22
|
+
{ type: 'bytes32' },
|
|
23
|
+
{ type: 'string' },
|
|
24
|
+
{
|
|
25
|
+
name: 'c3',
|
|
26
|
+
type: 'tuple',
|
|
27
|
+
components: [{ name: 'c31', type: 'uint96' }, { type: 'string' }, { type: 'bytes32' }],
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
{ name: 'd', type: 'string', indexed: true },
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
const OVERLOADED_EVENT = {
|
|
35
|
+
name: 'ExampleEvent',
|
|
36
|
+
type: 'event',
|
|
37
|
+
inputs: [{ name: 'a', type: 'bytes32' }],
|
|
38
|
+
};
|
|
39
|
+
const TEST_CONTRACT = {
|
|
40
|
+
name: 'ExampleContract',
|
|
41
|
+
type: 'contract',
|
|
42
|
+
};
|
|
43
|
+
const TEST_CALLABLE_FUNCTIONS = [
|
|
44
|
+
{
|
|
45
|
+
name: 'someVariable',
|
|
46
|
+
type: 'function',
|
|
47
|
+
stateMutability: 'view',
|
|
48
|
+
outputs: [{ type: 'uint256' }],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'getSomeValue',
|
|
52
|
+
type: 'function',
|
|
53
|
+
stateMutability: 'pure',
|
|
54
|
+
outputs: [{ type: 'tuple', components: [{ type: 'uint256' }] }],
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
const TEST_ABI = new abi_1.default('Contract', undefined, immutable_1.default.fromJS([TEST_EVENT, OVERLOADED_EVENT, TEST_CONTRACT, ...TEST_CALLABLE_FUNCTIONS]));
|
|
58
|
+
const protocol = new protocols_1.default('ethereum');
|
|
59
|
+
const scaffoldOptions = {
|
|
60
|
+
protocol,
|
|
61
|
+
abi: TEST_ABI,
|
|
62
|
+
contract: '0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d',
|
|
63
|
+
network: 'kovan',
|
|
64
|
+
contractName: 'Contract',
|
|
65
|
+
};
|
|
66
|
+
const scaffold = new index_1.default(scaffoldOptions);
|
|
67
|
+
const scaffoldWithIndexEvents = new index_1.default({
|
|
68
|
+
...scaffoldOptions,
|
|
69
|
+
indexEvents: true,
|
|
70
|
+
});
|
|
71
|
+
describe('Ethereum subgraph scaffolding', () => {
|
|
72
|
+
test('Manifest', () => {
|
|
73
|
+
expect(scaffold.generateManifest()).toEqual(`\
|
|
74
|
+
specVersion: 0.0.5
|
|
75
|
+
schema:
|
|
76
|
+
file: ./schema.graphql
|
|
77
|
+
dataSources:
|
|
78
|
+
- kind: ethereum
|
|
79
|
+
name: Contract
|
|
80
|
+
network: kovan
|
|
81
|
+
source:
|
|
82
|
+
address: "0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d"
|
|
83
|
+
abi: Contract
|
|
84
|
+
mapping:
|
|
85
|
+
kind: ethereum/events
|
|
86
|
+
apiVersion: 0.0.7
|
|
87
|
+
language: wasm/assemblyscript
|
|
88
|
+
entities:
|
|
89
|
+
- ExampleEvent
|
|
90
|
+
- ExampleEvent1
|
|
91
|
+
abis:
|
|
92
|
+
- name: Contract
|
|
93
|
+
file: ./abis/Contract.json
|
|
94
|
+
eventHandlers:
|
|
95
|
+
- event: ExampleEvent(indexed uint256,bytes[4],string,(uint256,bytes32,string,(uint96,string,bytes32)),indexed string)
|
|
96
|
+
handler: handleExampleEvent
|
|
97
|
+
- event: ExampleEvent(bytes32)
|
|
98
|
+
handler: handleExampleEvent1
|
|
99
|
+
file: ./src/contract.ts
|
|
100
|
+
`);
|
|
101
|
+
});
|
|
102
|
+
test('Schema (default)', () => {
|
|
103
|
+
expect(scaffold.generateSchema()).toEqual(`\
|
|
104
|
+
type ExampleEntity @entity {
|
|
105
|
+
id: Bytes!
|
|
106
|
+
count: BigInt!
|
|
107
|
+
a: BigInt! # uint256
|
|
108
|
+
b: [Bytes]! # bytes[4]
|
|
109
|
+
}
|
|
110
|
+
`);
|
|
111
|
+
});
|
|
112
|
+
test('Schema (for indexing events)', () => {
|
|
113
|
+
expect(scaffoldWithIndexEvents.generateSchema()).toEqual(`\
|
|
114
|
+
type ExampleEvent @entity(immutable: true) {
|
|
115
|
+
id: Bytes!
|
|
116
|
+
a: BigInt! # uint256
|
|
117
|
+
b: [Bytes]! # bytes[4]
|
|
118
|
+
param2: String! # string
|
|
119
|
+
c_c1: BigInt! # uint256
|
|
120
|
+
c_value1: Bytes! # bytes32
|
|
121
|
+
c_value2: String! # string
|
|
122
|
+
c_c3_c31: BigInt! # uint96
|
|
123
|
+
c_c3_value1: String! # string
|
|
124
|
+
c_c3_value2: Bytes! # bytes32
|
|
125
|
+
d: String! # string
|
|
126
|
+
blockNumber: BigInt!
|
|
127
|
+
blockTimestamp: BigInt!
|
|
128
|
+
transactionHash: Bytes!
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
type ExampleEvent1 @entity(immutable: true) {
|
|
132
|
+
id: Bytes!
|
|
133
|
+
a: Bytes! # bytes32
|
|
134
|
+
blockNumber: BigInt!
|
|
135
|
+
blockTimestamp: BigInt!
|
|
136
|
+
transactionHash: Bytes!
|
|
137
|
+
}
|
|
138
|
+
`);
|
|
139
|
+
});
|
|
140
|
+
test('Mapping (default)', () => {
|
|
141
|
+
expect(scaffold.generateMapping()).toEqual(`\
|
|
142
|
+
import { BigInt } from "@graphprotocol/graph-ts"
|
|
143
|
+
import {
|
|
144
|
+
Contract,
|
|
145
|
+
ExampleEvent,
|
|
146
|
+
ExampleEvent1
|
|
147
|
+
} from "../generated/Contract/Contract"
|
|
148
|
+
import { ExampleEntity } from "../generated/schema"
|
|
149
|
+
|
|
150
|
+
export function handleExampleEvent(event: ExampleEvent): void {
|
|
151
|
+
// Entities can be loaded from the store using a string ID; this ID
|
|
152
|
+
// needs to be unique across all entities of the same type
|
|
153
|
+
let entity = ExampleEntity.load(event.transaction.from)
|
|
154
|
+
|
|
155
|
+
// Entities only exist after they have been saved to the store;
|
|
156
|
+
// \`null\` checks allow to create entities on demand
|
|
157
|
+
if (!entity) {
|
|
158
|
+
entity = new ExampleEntity(event.transaction.from)
|
|
159
|
+
|
|
160
|
+
// Entity fields can be set using simple assignments
|
|
161
|
+
entity.count = BigInt.fromI32(0)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// BigInt and BigDecimal math are supported
|
|
165
|
+
entity.count = entity.count + BigInt.fromI32(1)
|
|
166
|
+
|
|
167
|
+
// Entity fields can be set based on event parameters
|
|
168
|
+
entity.a = event.params.a
|
|
169
|
+
entity.b = event.params.b
|
|
170
|
+
|
|
171
|
+
// Entities can be written to the store with \`.save()\`
|
|
172
|
+
entity.save()
|
|
173
|
+
|
|
174
|
+
// Note: If a handler doesn't require existing field values, it is faster
|
|
175
|
+
// _not_ to load the entity from the store. Instead, create it fresh with
|
|
176
|
+
// \`new Entity(...)\`, set the fields that should be updated and save the
|
|
177
|
+
// entity back to the store. Fields that were not set or unset remain
|
|
178
|
+
// unchanged, allowing for partial updates to be applied.
|
|
179
|
+
|
|
180
|
+
// It is also possible to access smart contracts from mappings. For
|
|
181
|
+
// example, the contract that has emitted the event can be connected to
|
|
182
|
+
// with:
|
|
183
|
+
//
|
|
184
|
+
// let contract = Contract.bind(event.address)
|
|
185
|
+
//
|
|
186
|
+
// The following functions can then be called on this contract to access
|
|
187
|
+
// state variables and other data:
|
|
188
|
+
//
|
|
189
|
+
// - contract.someVariable(...)
|
|
190
|
+
// - contract.getSomeValue(...)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function handleExampleEvent1(event: ExampleEvent1): void {}
|
|
194
|
+
`);
|
|
195
|
+
});
|
|
196
|
+
test('Mapping (for indexing events)', () => {
|
|
197
|
+
expect(scaffoldWithIndexEvents.generateMapping()).toEqual(`\
|
|
198
|
+
import {
|
|
199
|
+
ExampleEvent as ExampleEventEvent,
|
|
200
|
+
ExampleEvent1 as ExampleEvent1Event
|
|
201
|
+
} from "../generated/Contract/Contract"
|
|
202
|
+
import { ExampleEvent, ExampleEvent1 } from "../generated/schema"
|
|
203
|
+
|
|
204
|
+
export function handleExampleEvent(event: ExampleEventEvent): void {
|
|
205
|
+
let entity = new ExampleEvent(
|
|
206
|
+
event.transaction.hash.concatI32(event.logIndex.toI32())
|
|
207
|
+
)
|
|
208
|
+
entity.a = event.params.a
|
|
209
|
+
entity.b = event.params.b
|
|
210
|
+
entity.param2 = event.params.param2
|
|
211
|
+
entity.c_c1 = event.params.c.c1
|
|
212
|
+
entity.c_value1 = event.params.c.value1
|
|
213
|
+
entity.c_value2 = event.params.c.value2
|
|
214
|
+
entity.c_c3_c31 = event.params.c.c3.c31
|
|
215
|
+
entity.c_c3_value1 = event.params.c.c3.value1
|
|
216
|
+
entity.c_c3_value2 = event.params.c.c3.value2
|
|
217
|
+
entity.d = event.params.d
|
|
218
|
+
|
|
219
|
+
entity.blockNumber = event.block.number
|
|
220
|
+
entity.blockTimestamp = event.block.timestamp
|
|
221
|
+
entity.transactionHash = event.transaction.hash
|
|
222
|
+
|
|
223
|
+
entity.save()
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function handleExampleEvent1(event: ExampleEvent1Event): void {
|
|
227
|
+
let entity = new ExampleEvent1(
|
|
228
|
+
event.transaction.hash.concatI32(event.logIndex.toI32())
|
|
229
|
+
)
|
|
230
|
+
entity.a = event.params.a
|
|
231
|
+
|
|
232
|
+
entity.blockNumber = event.block.number
|
|
233
|
+
entity.blockTimestamp = event.block.timestamp
|
|
234
|
+
entity.transactionHash = event.transaction.hash
|
|
235
|
+
|
|
236
|
+
entity.save()
|
|
237
|
+
}
|
|
238
|
+
`);
|
|
239
|
+
});
|
|
240
|
+
test('Test Files (default)', () => {
|
|
241
|
+
const files = scaffoldWithIndexEvents.generateTests();
|
|
242
|
+
const testFile = files?.['contract.test.ts'];
|
|
243
|
+
const utilsFile = files?.['contract-utils.ts'];
|
|
244
|
+
expect(testFile).toEqual(`\
|
|
245
|
+
import {
|
|
246
|
+
assert,
|
|
247
|
+
describe,
|
|
248
|
+
test,
|
|
249
|
+
clearStore,
|
|
250
|
+
beforeAll,
|
|
251
|
+
afterAll
|
|
252
|
+
} from "matchstick-as/assembly/index"
|
|
253
|
+
import { BigInt, Bytes } from "@graphprotocol/graph-ts"
|
|
254
|
+
import { ExampleEvent } from "../generated/schema"
|
|
255
|
+
import { ExampleEvent as ExampleEventEvent } from "../generated/Contract/Contract"
|
|
256
|
+
import { handleExampleEvent } from "../src/contract"
|
|
257
|
+
import { createExampleEventEvent } from "./contract-utils"
|
|
258
|
+
|
|
259
|
+
// Tests structure (matchstick-as >=0.5.0)
|
|
260
|
+
// https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0
|
|
261
|
+
|
|
262
|
+
describe("Describe entity assertions", () => {
|
|
263
|
+
beforeAll(() => {
|
|
264
|
+
let a = BigInt.fromI32(234)
|
|
265
|
+
let b = [Bytes.fromI32(1234567890)]
|
|
266
|
+
let param2 = "Example string value"
|
|
267
|
+
let c = "ethereum.Tuple Not implemented"
|
|
268
|
+
let d = "Example string value"
|
|
269
|
+
let newExampleEventEvent = createExampleEventEvent(a, b, param2, c, d)
|
|
270
|
+
handleExampleEvent(newExampleEventEvent)
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
afterAll(() => {
|
|
274
|
+
clearStore()
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
// For more test scenarios, see:
|
|
278
|
+
// https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test
|
|
279
|
+
|
|
280
|
+
test("ExampleEvent created and stored", () => {
|
|
281
|
+
assert.entityCount("ExampleEvent", 1)
|
|
282
|
+
|
|
283
|
+
// 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function
|
|
284
|
+
assert.fieldEquals(
|
|
285
|
+
"ExampleEvent",
|
|
286
|
+
"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1",
|
|
287
|
+
"a",
|
|
288
|
+
"234"
|
|
289
|
+
)
|
|
290
|
+
assert.fieldEquals(
|
|
291
|
+
"ExampleEvent",
|
|
292
|
+
"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1",
|
|
293
|
+
"b",
|
|
294
|
+
"[1234567890]"
|
|
295
|
+
)
|
|
296
|
+
assert.fieldEquals(
|
|
297
|
+
"ExampleEvent",
|
|
298
|
+
"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1",
|
|
299
|
+
"param2",
|
|
300
|
+
"Example string value"
|
|
301
|
+
)
|
|
302
|
+
assert.fieldEquals(
|
|
303
|
+
"ExampleEvent",
|
|
304
|
+
"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1",
|
|
305
|
+
"c",
|
|
306
|
+
"ethereum.Tuple Not implemented"
|
|
307
|
+
)
|
|
308
|
+
assert.fieldEquals(
|
|
309
|
+
"ExampleEvent",
|
|
310
|
+
"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1",
|
|
311
|
+
"d",
|
|
312
|
+
"Example string value"
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
// More assert options:
|
|
316
|
+
// https://thegraph.com/docs/en/developer/matchstick/#asserts
|
|
317
|
+
})
|
|
318
|
+
})
|
|
319
|
+
`);
|
|
320
|
+
expect(utilsFile).toEqual(`\
|
|
321
|
+
import { newMockEvent } from "matchstick-as"
|
|
322
|
+
import { ethereum, BigInt, Bytes } from "@graphprotocol/graph-ts"
|
|
323
|
+
import { ExampleEvent, ExampleEvent1 } from "../generated/Contract/Contract"
|
|
324
|
+
|
|
325
|
+
export function createExampleEventEvent(
|
|
326
|
+
a: BigInt,
|
|
327
|
+
b: Array<Bytes>,
|
|
328
|
+
param2: string,
|
|
329
|
+
c: ethereum.Tuple,
|
|
330
|
+
d: string
|
|
331
|
+
): ExampleEvent {
|
|
332
|
+
let exampleEventEvent = changetype<ExampleEvent>(newMockEvent())
|
|
333
|
+
|
|
334
|
+
exampleEventEvent.parameters = new Array()
|
|
335
|
+
|
|
336
|
+
exampleEventEvent.parameters.push(
|
|
337
|
+
new ethereum.EventParam("a", ethereum.Value.fromUnsignedBigInt(a))
|
|
338
|
+
)
|
|
339
|
+
exampleEventEvent.parameters.push(
|
|
340
|
+
new ethereum.EventParam("b", ethereum.Value.fromBytesArray(b))
|
|
341
|
+
)
|
|
342
|
+
exampleEventEvent.parameters.push(
|
|
343
|
+
new ethereum.EventParam("param2", ethereum.Value.fromString(param2))
|
|
344
|
+
)
|
|
345
|
+
exampleEventEvent.parameters.push(
|
|
346
|
+
new ethereum.EventParam("c", ethereum.Value.fromTuple(c))
|
|
347
|
+
)
|
|
348
|
+
exampleEventEvent.parameters.push(
|
|
349
|
+
new ethereum.EventParam("d", ethereum.Value.fromString(d))
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
return exampleEventEvent
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export function createExampleEvent1Event(a: Bytes): ExampleEvent1 {
|
|
356
|
+
let exampleEvent1Event = changetype<ExampleEvent1>(newMockEvent())
|
|
357
|
+
|
|
358
|
+
exampleEvent1Event.parameters = new Array()
|
|
359
|
+
|
|
360
|
+
exampleEvent1Event.parameters.push(
|
|
361
|
+
new ethereum.EventParam("a", ethereum.Value.fromFixedBytes(a))
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
return exampleEvent1Event
|
|
365
|
+
}
|
|
366
|
+
`);
|
|
367
|
+
});
|
|
368
|
+
test('Test Files (for indexing events)', () => {
|
|
369
|
+
const files = scaffoldWithIndexEvents.generateTests();
|
|
370
|
+
const testFile = files?.['contract.test.ts'];
|
|
371
|
+
const utilsFile = files?.['contract-utils.ts'];
|
|
372
|
+
expect(testFile).toEqual(`\
|
|
373
|
+
import {
|
|
374
|
+
assert,
|
|
375
|
+
describe,
|
|
376
|
+
test,
|
|
377
|
+
clearStore,
|
|
378
|
+
beforeAll,
|
|
379
|
+
afterAll
|
|
380
|
+
} from "matchstick-as/assembly/index"
|
|
381
|
+
import { BigInt, Bytes } from "@graphprotocol/graph-ts"
|
|
382
|
+
import { ExampleEvent } from "../generated/schema"
|
|
383
|
+
import { ExampleEvent as ExampleEventEvent } from "../generated/Contract/Contract"
|
|
384
|
+
import { handleExampleEvent } from "../src/contract"
|
|
385
|
+
import { createExampleEventEvent } from "./contract-utils"
|
|
386
|
+
|
|
387
|
+
// Tests structure (matchstick-as >=0.5.0)
|
|
388
|
+
// https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0
|
|
389
|
+
|
|
390
|
+
describe("Describe entity assertions", () => {
|
|
391
|
+
beforeAll(() => {
|
|
392
|
+
let a = BigInt.fromI32(234)
|
|
393
|
+
let b = [Bytes.fromI32(1234567890)]
|
|
394
|
+
let param2 = "Example string value"
|
|
395
|
+
let c = "ethereum.Tuple Not implemented"
|
|
396
|
+
let d = "Example string value"
|
|
397
|
+
let newExampleEventEvent = createExampleEventEvent(a, b, param2, c, d)
|
|
398
|
+
handleExampleEvent(newExampleEventEvent)
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
afterAll(() => {
|
|
402
|
+
clearStore()
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
// For more test scenarios, see:
|
|
406
|
+
// https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test
|
|
407
|
+
|
|
408
|
+
test("ExampleEvent created and stored", () => {
|
|
409
|
+
assert.entityCount("ExampleEvent", 1)
|
|
410
|
+
|
|
411
|
+
// 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function
|
|
412
|
+
assert.fieldEquals(
|
|
413
|
+
"ExampleEvent",
|
|
414
|
+
"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1",
|
|
415
|
+
"a",
|
|
416
|
+
"234"
|
|
417
|
+
)
|
|
418
|
+
assert.fieldEquals(
|
|
419
|
+
"ExampleEvent",
|
|
420
|
+
"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1",
|
|
421
|
+
"b",
|
|
422
|
+
"[1234567890]"
|
|
423
|
+
)
|
|
424
|
+
assert.fieldEquals(
|
|
425
|
+
"ExampleEvent",
|
|
426
|
+
"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1",
|
|
427
|
+
"param2",
|
|
428
|
+
"Example string value"
|
|
429
|
+
)
|
|
430
|
+
assert.fieldEquals(
|
|
431
|
+
"ExampleEvent",
|
|
432
|
+
"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1",
|
|
433
|
+
"c",
|
|
434
|
+
"ethereum.Tuple Not implemented"
|
|
435
|
+
)
|
|
436
|
+
assert.fieldEquals(
|
|
437
|
+
"ExampleEvent",
|
|
438
|
+
"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1",
|
|
439
|
+
"d",
|
|
440
|
+
"Example string value"
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
// More assert options:
|
|
444
|
+
// https://thegraph.com/docs/en/developer/matchstick/#asserts
|
|
445
|
+
})
|
|
446
|
+
})
|
|
447
|
+
`);
|
|
448
|
+
expect(utilsFile).toEqual(`\
|
|
449
|
+
import { newMockEvent } from "matchstick-as"
|
|
450
|
+
import { ethereum, BigInt, Bytes } from "@graphprotocol/graph-ts"
|
|
451
|
+
import { ExampleEvent, ExampleEvent1 } from "../generated/Contract/Contract"
|
|
452
|
+
|
|
453
|
+
export function createExampleEventEvent(
|
|
454
|
+
a: BigInt,
|
|
455
|
+
b: Array<Bytes>,
|
|
456
|
+
param2: string,
|
|
457
|
+
c: ethereum.Tuple,
|
|
458
|
+
d: string
|
|
459
|
+
): ExampleEvent {
|
|
460
|
+
let exampleEventEvent = changetype<ExampleEvent>(newMockEvent())
|
|
461
|
+
|
|
462
|
+
exampleEventEvent.parameters = new Array()
|
|
463
|
+
|
|
464
|
+
exampleEventEvent.parameters.push(
|
|
465
|
+
new ethereum.EventParam("a", ethereum.Value.fromUnsignedBigInt(a))
|
|
466
|
+
)
|
|
467
|
+
exampleEventEvent.parameters.push(
|
|
468
|
+
new ethereum.EventParam("b", ethereum.Value.fromBytesArray(b))
|
|
469
|
+
)
|
|
470
|
+
exampleEventEvent.parameters.push(
|
|
471
|
+
new ethereum.EventParam("param2", ethereum.Value.fromString(param2))
|
|
472
|
+
)
|
|
473
|
+
exampleEventEvent.parameters.push(
|
|
474
|
+
new ethereum.EventParam("c", ethereum.Value.fromTuple(c))
|
|
475
|
+
)
|
|
476
|
+
exampleEventEvent.parameters.push(
|
|
477
|
+
new ethereum.EventParam("d", ethereum.Value.fromString(d))
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
return exampleEventEvent
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
export function createExampleEvent1Event(a: Bytes): ExampleEvent1 {
|
|
484
|
+
let exampleEvent1Event = changetype<ExampleEvent1>(newMockEvent())
|
|
485
|
+
|
|
486
|
+
exampleEvent1Event.parameters = new Array()
|
|
487
|
+
|
|
488
|
+
exampleEvent1Event.parameters.push(
|
|
489
|
+
new ethereum.EventParam("a", ethereum.Value.fromFixedBytes(a))
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
return exampleEvent1Event
|
|
493
|
+
}
|
|
494
|
+
`);
|
|
495
|
+
});
|
|
496
|
+
});
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const gluegun_1 = require("gluegun");
|
|
7
|
+
const prettier_1 = __importDefault(require("prettier"));
|
|
8
|
+
const subgraph_1 = require("../command-helpers/subgraph");
|
|
9
|
+
const mapping_1 = require("./mapping");
|
|
10
|
+
const schema_1 = require("./schema");
|
|
11
|
+
const tests_1 = require("./tests");
|
|
12
|
+
const GRAPH_CLI_VERSION = process.env.GRAPH_CLI_TESTS
|
|
13
|
+
? // JSON.stringify should remove this key, we will install the local
|
|
14
|
+
// graph-cli for the tests using `npm link` instead of fetching from npm.
|
|
15
|
+
undefined
|
|
16
|
+
: // For scaffolding real subgraphs
|
|
17
|
+
String(module.exports.version);
|
|
18
|
+
class Scaffold {
|
|
19
|
+
protocol;
|
|
20
|
+
abi;
|
|
21
|
+
indexEvents;
|
|
22
|
+
contract;
|
|
23
|
+
network;
|
|
24
|
+
contractName;
|
|
25
|
+
subgraphName;
|
|
26
|
+
node;
|
|
27
|
+
constructor(options) {
|
|
28
|
+
this.protocol = options.protocol;
|
|
29
|
+
this.abi = options.abi;
|
|
30
|
+
this.indexEvents = options.indexEvents;
|
|
31
|
+
this.contract = options.contract;
|
|
32
|
+
this.network = options.network;
|
|
33
|
+
this.contractName = options.contractName;
|
|
34
|
+
this.subgraphName = options.subgraphName;
|
|
35
|
+
this.node = options.node;
|
|
36
|
+
}
|
|
37
|
+
generatePackageJson() {
|
|
38
|
+
return prettier_1.default.format(JSON.stringify({
|
|
39
|
+
name: (0, subgraph_1.getSubgraphBasename)(String(this.subgraphName)),
|
|
40
|
+
license: 'UNLICENSED',
|
|
41
|
+
scripts: {
|
|
42
|
+
codegen: 'graph codegen',
|
|
43
|
+
build: 'graph build',
|
|
44
|
+
deploy: `graph deploy ` + `--node ${this.node} ` + this.subgraphName,
|
|
45
|
+
'create-local': `graph create --node http://localhost:8020/ ${this.subgraphName}`,
|
|
46
|
+
'remove-local': `graph remove --node http://localhost:8020/ ${this.subgraphName}`,
|
|
47
|
+
'deploy-local': `graph deploy ` +
|
|
48
|
+
`--node http://localhost:8020/ ` +
|
|
49
|
+
`--ipfs http://localhost:5001 ` +
|
|
50
|
+
this.subgraphName,
|
|
51
|
+
test: 'graph test',
|
|
52
|
+
},
|
|
53
|
+
dependencies: {
|
|
54
|
+
'@graphprotocol/graph-cli': GRAPH_CLI_VERSION,
|
|
55
|
+
'@graphprotocol/graph-ts': `0.29.1`,
|
|
56
|
+
},
|
|
57
|
+
devDependencies: this.protocol.hasEvents() ? { 'matchstick-as': `0.5.0` } : undefined,
|
|
58
|
+
}), { parser: 'json' });
|
|
59
|
+
}
|
|
60
|
+
generateManifest() {
|
|
61
|
+
const protocolManifest = this.protocol.getManifestScaffold();
|
|
62
|
+
return prettier_1.default.format(`
|
|
63
|
+
specVersion: 0.0.5
|
|
64
|
+
schema:
|
|
65
|
+
file: ./schema.graphql
|
|
66
|
+
dataSources:
|
|
67
|
+
- kind: ${this.protocol.name}
|
|
68
|
+
name: ${this.contractName}
|
|
69
|
+
network: ${this.network}
|
|
70
|
+
source: ${protocolManifest.source(this)}
|
|
71
|
+
mapping: ${protocolManifest.mapping(this)}
|
|
72
|
+
`, { parser: 'yaml' });
|
|
73
|
+
}
|
|
74
|
+
generateSchema() {
|
|
75
|
+
const hasEvents = this.protocol.hasEvents();
|
|
76
|
+
const events = hasEvents ? (0, schema_1.abiEvents)(this.abi).toJS() : [];
|
|
77
|
+
return prettier_1.default.format(hasEvents && this.indexEvents
|
|
78
|
+
? events.map((event) => (0, schema_1.generateEventType)(event, this.protocol.name)).join('\n\n')
|
|
79
|
+
: (0, schema_1.generateExampleEntityType)(this.protocol, events), {
|
|
80
|
+
parser: 'graphql',
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
generateTsConfig() {
|
|
84
|
+
return prettier_1.default.format(JSON.stringify({
|
|
85
|
+
extends: '@graphprotocol/graph-ts/types/tsconfig.base.json',
|
|
86
|
+
include: ['src'],
|
|
87
|
+
}), { parser: 'json' });
|
|
88
|
+
}
|
|
89
|
+
generateMappings() {
|
|
90
|
+
return this.protocol.getMappingScaffold()
|
|
91
|
+
? { [`${gluegun_1.strings.kebabCase(this.contractName)}.ts`]: this.generateMapping() }
|
|
92
|
+
: undefined;
|
|
93
|
+
}
|
|
94
|
+
generateMapping() {
|
|
95
|
+
const hasEvents = this.protocol.hasEvents();
|
|
96
|
+
const events = hasEvents ? (0, schema_1.abiEvents)(this.abi).toJS() : [];
|
|
97
|
+
const protocolMapping = this.protocol.getMappingScaffold();
|
|
98
|
+
return prettier_1.default.format(hasEvents && this.indexEvents
|
|
99
|
+
? (0, mapping_1.generateEventIndexingHandlers)(events, this.contractName)
|
|
100
|
+
: protocolMapping.generatePlaceholderHandlers({
|
|
101
|
+
...this,
|
|
102
|
+
events,
|
|
103
|
+
}), { parser: 'typescript', semi: false });
|
|
104
|
+
}
|
|
105
|
+
generateABIs() {
|
|
106
|
+
return this.protocol.hasABIs()
|
|
107
|
+
? {
|
|
108
|
+
[`${this.contractName}.json`]: prettier_1.default.format(JSON.stringify(this.abi?.data), {
|
|
109
|
+
parser: 'json',
|
|
110
|
+
}),
|
|
111
|
+
}
|
|
112
|
+
: undefined;
|
|
113
|
+
}
|
|
114
|
+
generateTests() {
|
|
115
|
+
const hasEvents = this.protocol.hasEvents();
|
|
116
|
+
const events = hasEvents ? (0, schema_1.abiEvents)(this.abi).toJS() : [];
|
|
117
|
+
return events.length > 0
|
|
118
|
+
? (0, tests_1.generateTestsFiles)(this.contractName, events, this.indexEvents)
|
|
119
|
+
: undefined;
|
|
120
|
+
}
|
|
121
|
+
generate() {
|
|
122
|
+
return {
|
|
123
|
+
'package.json': this.generatePackageJson(),
|
|
124
|
+
'subgraph.yaml': this.generateManifest(),
|
|
125
|
+
'schema.graphql': this.generateSchema(),
|
|
126
|
+
'tsconfig.json': this.generateTsConfig(),
|
|
127
|
+
src: this.generateMappings(),
|
|
128
|
+
abis: this.generateABIs(),
|
|
129
|
+
tests: this.generateTests(),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.default = Scaffold;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.generateEventIndexingHandlers = exports.generateEventFieldAssignments = exports.generateFieldAssignments = exports.generateFieldAssignment = void 0;
|
|
27
|
+
const util = __importStar(require("../codegen/util"));
|
|
28
|
+
const generateFieldAssignment = (path) => `entity.${path.join('_')} = event.params.${path.join('.')}`;
|
|
29
|
+
exports.generateFieldAssignment = generateFieldAssignment;
|
|
30
|
+
const generateFieldAssignments = ({ index, input }) => input.type === 'tuple'
|
|
31
|
+
? util
|
|
32
|
+
.unrollTuple({ value: input, index, path: [input.name || `param${index}`] })
|
|
33
|
+
.map(({ path }) => (0, exports.generateFieldAssignment)(path))
|
|
34
|
+
: (0, exports.generateFieldAssignment)([input.name || `param${index}`]);
|
|
35
|
+
exports.generateFieldAssignments = generateFieldAssignments;
|
|
36
|
+
const generateEventFieldAssignments = (event) => event.inputs.reduce((acc, input, index) => acc.concat((0, exports.generateFieldAssignments)({ input, index })), []);
|
|
37
|
+
exports.generateEventFieldAssignments = generateEventFieldAssignments;
|
|
38
|
+
const generateEventIndexingHandlers = (events, contractName) => `
|
|
39
|
+
import { ${events.map(event => `${event._alias} as ${event._alias}Event`)}} from '../generated/${contractName}/${contractName}'
|
|
40
|
+
import { ${events.map(event => event._alias)} } from '../generated/schema'
|
|
41
|
+
|
|
42
|
+
${events
|
|
43
|
+
.map(event => `
|
|
44
|
+
export function handle${event._alias}(event: ${event._alias}Event): void {
|
|
45
|
+
let entity = new ${event._alias}(event.transaction.hash.concatI32(event.logIndex.toI32()))
|
|
46
|
+
${(0, exports.generateEventFieldAssignments)(event).join('\n')}
|
|
47
|
+
|
|
48
|
+
entity.blockNumber = event.block.number
|
|
49
|
+
entity.blockTimestamp = event.block.timestamp
|
|
50
|
+
entity.transactionHash = event.transaction.hash
|
|
51
|
+
|
|
52
|
+
entity.save()
|
|
53
|
+
}
|
|
54
|
+
`)
|
|
55
|
+
.join('\n')}
|
|
56
|
+
`;
|
|
57
|
+
exports.generateEventIndexingHandlers = generateEventIndexingHandlers;
|