Skip to content

Filipe/substreams mappings #1490

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Dec 7, 2023
5 changes: 5 additions & 0 deletions .changeset/nervous-windows-serve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphprotocol/graph-cli': minor
---

substreams based triggers support
26 changes: 24 additions & 2 deletions packages/cli/src/compiler/index.ts
Original file line number Diff line number Diff line change
@@ -548,7 +548,7 @@ export default class Compiler {
);
}

if (protocol.name == 'substreams') {
if (protocol.name == 'substreams' || protocol.name == 'substreams/triggers') {
updatedDataSource = updatedDataSource
// Write data source ABIs to the output directory
.updateIn(['source', 'package'], (substreamsPackage: any) =>
@@ -569,6 +569,17 @@ export default class Compiler {
}),
);

if (updatedDataSource.getIn(['mapping', 'file'])) {
updatedDataSource = updatedDataSource.updateIn(
['mapping', 'file'],
(mappingFile: string) =>
path.relative(
this.options.outputDir,
path.resolve(this.sourceDir, mappingFile),
),
);
}

return updatedDataSource;
}

@@ -662,7 +673,7 @@ export default class Compiler {
}

// Upload all mappings
if (this.protocol.name === 'substreams') {
if (this.protocol.name === 'substreams' || this.protocol.name === 'substreams/triggers') {
for (const [i, dataSource] of subgraph.get('dataSources').entries()) {
updates.push({
keyPath: ['dataSources', i, 'source', 'package', 'file'],
@@ -672,6 +683,17 @@ export default class Compiler {
spinner,
),
});

if (dataSource.getIn(['mapping', 'file'])) {
updates.push({
keyPath: ['dataSources', i, 'mapping', 'file'],
value: await this._uploadFileToIPFS(
dataSource.getIn(['mapping', 'file']),
uploadedFiles,
spinner,
),
});
}
}
} else {
for (const [i, dataSource] of subgraph.get('dataSources').entries()) {
37 changes: 32 additions & 5 deletions packages/cli/src/protocols/index.ts
Original file line number Diff line number Diff line change
@@ -27,17 +27,24 @@ const protocolDebug = debug('graph-cli:protocol');

export default class Protocol {
static fromDataSources(dataSourcesAndTemplates: any) {
const firstDataSourceKind = dataSourcesAndTemplates[0].kind;
return new Protocol(firstDataSourceKind);
const firstDataSource = dataSourcesAndTemplates[0];
return new Protocol(firstDataSource);
}

name: ProtocolName;

// TODO: should assert non null? see the constructor switch default case comment
config!: ProtocolConfig;

constructor(name: ProtocolName) {
constructor(datasource: any) {
/**
* TODO: we should improve this `any` type, because some places
* we can initiate a Protocol with just a string (the name) and
* some other places use datasource object
*/
const name = typeof datasource === 'string' ? datasource : datasource.kind;
this.name = Protocol.normalizeName(name)!;
protocolDebug('Initializing protocol %s', this.name);

switch (this.name) {
case 'arweave':
@@ -54,6 +61,14 @@ export default class Protocol {
break;
case 'substreams':
this.config = substreamsProtocol;

/**
* Substreams triggers are a special case of substreams data sources
* which have a mapping file and a handler.
*/
if (datasource?.mapping?.file && datasource?.mapping.handler) {
this.name = 'substreams/triggers';
}
break;
default:
// Do not throw when undefined, a better error message is printed after the constructor
@@ -126,7 +141,13 @@ export default class Protocol {
],
substreams: ['mainnet'],
}) as immutable.Map<
'arweave' | 'ethereum' | 'near' | 'cosmos' | 'substreams',
| 'arweave'
| 'ethereum'
| 'near'
| 'cosmos'
| 'substreams'
// this is temporary, until we have a better way to handle substreams triggers
| 'substreams/triggers',
immutable.List<string>
>;
}
@@ -207,7 +228,13 @@ export default class Protocol {
}
}

export type ProtocolName = 'arweave' | 'ethereum' | 'near' | 'cosmos' | 'substreams';
export type ProtocolName =
| 'arweave'
| 'ethereum'
| 'near'
| 'cosmos'
| 'substreams'
| 'substreams/triggers';

export interface ProtocolConfig {
displayName: string;
4 changes: 4 additions & 0 deletions packages/cli/src/protocols/substreams/manifest.graphql
Original file line number Diff line number Diff line change
@@ -32,14 +32,18 @@ type DataSource {

type SubstreamsSource {
package: SubstreamsPackage!
startBlock: BigInt
}

type SubstreamsPackage {
moduleName: String!
file: String!
params: String
}

type SubstreamMapping {
apiVersion: String!
kind: String!
file: File
handler: String
}
8 changes: 7 additions & 1 deletion packages/cli/src/subgraph.ts
Original file line number Diff line number Diff line change
@@ -53,7 +53,13 @@ export default class Subgraph {
// Parse the default subgraph schema
const schema = graphql.parse(
await fs.readFile(
path.join(__dirname, 'protocols', protocol.name, `manifest.graphql`),
path.join(
__dirname,
'protocols',
// TODO: substreams/triggers is a special case, should be handled better
protocol.name === 'substreams/triggers' ? 'substreams' : protocol.name,
`manifest.graphql`,
),
'utf-8',
),
);