UNPKG

@graphprotocol/graph-cli

Version:

CLI for building for and deploying to The Graph

502 lines (455 loc) • 15.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const immutable_1 = __importDefault(require("immutable")); const vitest_1 = require("vitest"); const protocols_1 = __importDefault(require("../protocols")); const abi_1 = __importDefault(require("../protocols/ethereum/abi")); const index_1 = __importDefault(require("./index")); const TEST_EVENT = { name: 'ExampleEvent', type: 'event', inputs: [ { name: 'a', type: 'uint256', indexed: true }, { name: 'b', type: 'bytes[4]' }, { type: 'string' }, { name: 'c', type: 'tuple', components: [ { name: 'c1', type: 'uint256' }, { type: 'bytes32' }, { type: 'string' }, { name: 'c3', type: 'tuple', components: [{ name: 'c31', type: 'uint96' }, { type: 'string' }, { type: 'bytes32' }], }, ], }, { name: 'd', type: 'string', indexed: true }, ], }; const OVERLOADED_EVENT = { name: 'ExampleEvent', type: 'event', inputs: [{ name: 'a', type: 'bytes32' }], }; const TEST_CONTRACT = { name: 'ExampleContract', type: 'contract', }; const TEST_CALLABLE_FUNCTIONS = [ { name: 'someVariable', type: 'function', stateMutability: 'view', outputs: [{ type: 'uint256' }], }, { name: 'getSomeValue', type: 'function', stateMutability: 'pure', outputs: [{ type: 'tuple', components: [{ type: 'uint256' }] }], }, ]; const TEST_ABI = new abi_1.default('Contract', undefined, immutable_1.default.fromJS([TEST_EVENT, OVERLOADED_EVENT, TEST_CONTRACT, ...TEST_CALLABLE_FUNCTIONS])); const protocol = new protocols_1.default('ethereum'); const scaffoldOptions = { protocol, abi: TEST_ABI, contract: '0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d', network: 'kovan', contractName: 'Contract', startBlock: '12345', }; const scaffold = new index_1.default(scaffoldOptions); const scaffoldWithIndexEvents = new index_1.default({ ...scaffoldOptions, indexEvents: true, }); vitest_1.describe.concurrent('Ethereum subgraph scaffolding', () => { (0, vitest_1.test)('Manifest', async () => { (0, vitest_1.expect)(await scaffold.generateManifest()).toEqual(`\ specVersion: 1.0.0 indexerHints: prune: auto schema: file: ./schema.graphql dataSources: - kind: ethereum name: Contract network: kovan source: address: "0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d" abi: Contract startBlock: 12345 mapping: kind: ethereum/events apiVersion: 0.0.7 language: wasm/assemblyscript entities: - ExampleEvent - ExampleEvent1 abis: - name: Contract file: ./abis/Contract.json eventHandlers: - event: ExampleEvent(indexed uint256,bytes[4],string,(uint256,bytes32,string,(uint96,string,bytes32)),indexed string) handler: handleExampleEvent - event: ExampleEvent(bytes32) handler: handleExampleEvent1 file: ./src/contract.ts `); }); (0, vitest_1.test)('Schema (default)', async () => { (0, vitest_1.expect)(await scaffold.generateSchema()).toEqual(`\ type ExampleEntity @entity { id: Bytes! count: BigInt! a: BigInt! # uint256 b: [Bytes!]! # bytes[4] } `); }); (0, vitest_1.test)('Schema (for indexing events)', async () => { (0, vitest_1.expect)(await scaffoldWithIndexEvents.generateSchema()).toEqual(`\ type ExampleEvent @entity(immutable: true) { id: Bytes! a: BigInt! # uint256 b: [Bytes!]! # bytes[4] param2: String! # string c_c1: BigInt! # uint256 c_value1: Bytes! # bytes32 c_value2: String! # string c_c3_c31: BigInt! # uint96 c_c3_value1: String! # string c_c3_value2: Bytes! # bytes32 d: String! # string blockNumber: BigInt! blockTimestamp: BigInt! transactionHash: Bytes! } type ExampleEvent1 @entity(immutable: true) { id: Bytes! a: Bytes! # bytes32 blockNumber: BigInt! blockTimestamp: BigInt! transactionHash: Bytes! } `); }); (0, vitest_1.test)('Mapping (default)', async () => { (0, vitest_1.expect)(await scaffold.generateMapping()).toEqual(`\ import { BigInt } from "@graphprotocol/graph-ts" import { Contract, ExampleEvent, ExampleEvent1 } from "../generated/Contract/Contract" import { ExampleEntity } from "../generated/schema" export function handleExampleEvent(event: ExampleEvent): void { // Entities can be loaded from the store using a string ID; this ID // needs to be unique across all entities of the same type let entity = ExampleEntity.load(event.transaction.from) // Entities only exist after they have been saved to the store; // \`null\` checks allow to create entities on demand if (!entity) { entity = new ExampleEntity(event.transaction.from) // Entity fields can be set using simple assignments entity.count = BigInt.fromI32(0) } // BigInt and BigDecimal math are supported entity.count = entity.count + BigInt.fromI32(1) // Entity fields can be set based on event parameters entity.a = event.params.a entity.b = event.params.b // Entities can be written to the store with \`.save()\` entity.save() // Note: If a handler doesn't require existing field values, it is faster // _not_ to load the entity from the store. Instead, create it fresh with // \`new Entity(...)\`, set the fields that should be updated and save the // entity back to the store. Fields that were not set or unset remain // unchanged, allowing for partial updates to be applied. // It is also possible to access smart contracts from mappings. For // example, the contract that has emitted the event can be connected to // with: // // let contract = Contract.bind(event.address) // // The following functions can then be called on this contract to access // state variables and other data: // // - contract.someVariable(...) // - contract.getSomeValue(...) } export function handleExampleEvent1(event: ExampleEvent1): void {} `); }); (0, vitest_1.test)('Mapping (for indexing events)', async () => { (0, vitest_1.expect)(await scaffoldWithIndexEvents.generateMapping()).toEqual(`\ import { ExampleEvent as ExampleEventEvent, ExampleEvent1 as ExampleEvent1Event } from "../generated/Contract/Contract" import { ExampleEvent, ExampleEvent1 } from "../generated/schema" export function handleExampleEvent(event: ExampleEventEvent): void { let entity = new ExampleEvent( event.transaction.hash.concatI32(event.logIndex.toI32()) ) entity.a = event.params.a entity.b = event.params.b entity.param2 = event.params.param2 entity.c_c1 = event.params.c.c1 entity.c_value1 = event.params.c.value1 entity.c_value2 = event.params.c.value2 entity.c_c3_c31 = event.params.c.c3.c31 entity.c_c3_value1 = event.params.c.c3.value1 entity.c_c3_value2 = event.params.c.c3.value2 entity.d = event.params.d entity.blockNumber = event.block.number entity.blockTimestamp = event.block.timestamp entity.transactionHash = event.transaction.hash entity.save() } export function handleExampleEvent1(event: ExampleEvent1Event): void { let entity = new ExampleEvent1( event.transaction.hash.concatI32(event.logIndex.toI32()) ) entity.a = event.params.a entity.blockNumber = event.block.number entity.blockTimestamp = event.block.timestamp entity.transactionHash = event.transaction.hash entity.save() } `); }); (0, vitest_1.test)('Test Files (default)', async () => { const files = await scaffoldWithIndexEvents.generateTests(); const testFile = files?.['contract.test.ts']; const utilsFile = files?.['contract-utils.ts']; (0, vitest_1.expect)(testFile).toEqual(`\ import { assert, describe, test, clearStore, beforeAll, afterAll } from "matchstick-as/assembly/index" import { BigInt, Bytes } from "@graphprotocol/graph-ts" import { ExampleEvent } from "../generated/schema" import { ExampleEvent as ExampleEventEvent } from "../generated/Contract/Contract" import { handleExampleEvent } from "../src/contract" import { createExampleEventEvent } from "./contract-utils" // Tests structure (matchstick-as >=0.5.0) // https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0 describe("Describe entity assertions", () => { beforeAll(() => { let a = BigInt.fromI32(234) let b = [Bytes.fromI32(1234567890)] let param2 = "Example string value" let c = "ethereum.Tuple Not implemented" let d = "Example string value" let newExampleEventEvent = createExampleEventEvent(a, b, param2, c, d) handleExampleEvent(newExampleEventEvent) }) afterAll(() => { clearStore() }) // For more test scenarios, see: // https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test test("ExampleEvent created and stored", () => { assert.entityCount("ExampleEvent", 1) // 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function assert.fieldEquals( "ExampleEvent", "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", "a", "234" ) assert.fieldEquals( "ExampleEvent", "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", "b", "[1234567890]" ) assert.fieldEquals( "ExampleEvent", "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", "param2", "Example string value" ) assert.fieldEquals( "ExampleEvent", "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", "c", "ethereum.Tuple Not implemented" ) assert.fieldEquals( "ExampleEvent", "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", "d", "Example string value" ) // More assert options: // https://thegraph.com/docs/en/developer/matchstick/#asserts }) }) `); (0, vitest_1.expect)(utilsFile).toEqual(`\ import { newMockEvent } from "matchstick-as" import { ethereum, BigInt, Bytes } from "@graphprotocol/graph-ts" import { ExampleEvent, ExampleEvent1 } from "../generated/Contract/Contract" export function createExampleEventEvent( a: BigInt, b: Array<Bytes>, param2: string, c: ethereum.Tuple, d: string ): ExampleEvent { let exampleEventEvent = changetype<ExampleEvent>(newMockEvent()) exampleEventEvent.parameters = new Array() exampleEventEvent.parameters.push( new ethereum.EventParam("a", ethereum.Value.fromUnsignedBigInt(a)) ) exampleEventEvent.parameters.push( new ethereum.EventParam("b", ethereum.Value.fromBytesArray(b)) ) exampleEventEvent.parameters.push( new ethereum.EventParam("param2", ethereum.Value.fromString(param2)) ) exampleEventEvent.parameters.push( new ethereum.EventParam("c", ethereum.Value.fromTuple(c)) ) exampleEventEvent.parameters.push( new ethereum.EventParam("d", ethereum.Value.fromString(d)) ) return exampleEventEvent } export function createExampleEvent1Event(a: Bytes): ExampleEvent1 { let exampleEvent1Event = changetype<ExampleEvent1>(newMockEvent()) exampleEvent1Event.parameters = new Array() exampleEvent1Event.parameters.push( new ethereum.EventParam("a", ethereum.Value.fromFixedBytes(a)) ) return exampleEvent1Event } `); }); (0, vitest_1.test)('Test Files (for indexing events)', async () => { const files = await scaffoldWithIndexEvents.generateTests(); const testFile = files?.['contract.test.ts']; const utilsFile = files?.['contract-utils.ts']; (0, vitest_1.expect)(testFile).toEqual(`\ import { assert, describe, test, clearStore, beforeAll, afterAll } from "matchstick-as/assembly/index" import { BigInt, Bytes } from "@graphprotocol/graph-ts" import { ExampleEvent } from "../generated/schema" import { ExampleEvent as ExampleEventEvent } from "../generated/Contract/Contract" import { handleExampleEvent } from "../src/contract" import { createExampleEventEvent } from "./contract-utils" // Tests structure (matchstick-as >=0.5.0) // https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0 describe("Describe entity assertions", () => { beforeAll(() => { let a = BigInt.fromI32(234) let b = [Bytes.fromI32(1234567890)] let param2 = "Example string value" let c = "ethereum.Tuple Not implemented" let d = "Example string value" let newExampleEventEvent = createExampleEventEvent(a, b, param2, c, d) handleExampleEvent(newExampleEventEvent) }) afterAll(() => { clearStore() }) // For more test scenarios, see: // https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test test("ExampleEvent created and stored", () => { assert.entityCount("ExampleEvent", 1) // 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function assert.fieldEquals( "ExampleEvent", "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", "a", "234" ) assert.fieldEquals( "ExampleEvent", "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", "b", "[1234567890]" ) assert.fieldEquals( "ExampleEvent", "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", "param2", "Example string value" ) assert.fieldEquals( "ExampleEvent", "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", "c", "ethereum.Tuple Not implemented" ) assert.fieldEquals( "ExampleEvent", "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", "d", "Example string value" ) // More assert options: // https://thegraph.com/docs/en/developer/matchstick/#asserts }) }) `); (0, vitest_1.expect)(utilsFile).toEqual(`\ import { newMockEvent } from "matchstick-as" import { ethereum, BigInt, Bytes } from "@graphprotocol/graph-ts" import { ExampleEvent, ExampleEvent1 } from "../generated/Contract/Contract" export function createExampleEventEvent( a: BigInt, b: Array<Bytes>, param2: string, c: ethereum.Tuple, d: string ): ExampleEvent { let exampleEventEvent = changetype<ExampleEvent>(newMockEvent()) exampleEventEvent.parameters = new Array() exampleEventEvent.parameters.push( new ethereum.EventParam("a", ethereum.Value.fromUnsignedBigInt(a)) ) exampleEventEvent.parameters.push( new ethereum.EventParam("b", ethereum.Value.fromBytesArray(b)) ) exampleEventEvent.parameters.push( new ethereum.EventParam("param2", ethereum.Value.fromString(param2)) ) exampleEventEvent.parameters.push( new ethereum.EventParam("c", ethereum.Value.fromTuple(c)) ) exampleEventEvent.parameters.push( new ethereum.EventParam("d", ethereum.Value.fromString(d)) ) return exampleEventEvent } export function createExampleEvent1Event(a: Bytes): ExampleEvent1 { let exampleEvent1Event = changetype<ExampleEvent1>(newMockEvent()) exampleEvent1Event.parameters = new Array() exampleEvent1Event.parameters.push( new ethereum.EventParam("a", ethereum.Value.fromFixedBytes(a)) ) return exampleEvent1Event } `); }); });