From e5d00dc081ee92f4a331edc7ff9c016eb341b286 Mon Sep 17 00:00:00 2001 From: Gabe Hamilton Date: Thu, 9 Nov 2023 16:20:09 -0700 Subject: [PATCH 1/2] Helper functions to simplify writing social indexers. --- runner/src/indexer/indexer.ts | 46 ++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/runner/src/indexer/indexer.ts b/runner/src/indexer/indexer.ts index fd69a3898..d29b2b41c 100644 --- a/runner/src/indexer/indexer.ts +++ b/runner/src/indexer/indexer.ts @@ -19,6 +19,13 @@ interface Context { log: (...log: any[]) => Promise fetchFromSocialApi: (path: string, options?: any) => Promise db: Record any>> + base64Decode: (base64EncodedString: string) => string + getFunctionCalls: ( + block: Block, + contract: string, + method: string, + ) => Array<{ Operation, args: string }> + getSocialOperations: (block: Block, operation: string) => Array> } interface IndexerFunction { @@ -140,6 +147,25 @@ export default class Indexer { const functionNameWithoutAccount = functionName.split('/')[1].replace(/[.-]/g, '_'); const schemaName = functionName.replace(/[^a-zA-Z0-9]/g, '_'); + const base64DecodeFunction = (base64EncodedString: string): string => { + const buff = Buffer.from(base64EncodedString, 'base64'); + return JSON.parse(buff.toString('utf-8')); + }; + const getFunctionCallsFunction = (block: Block, contract: string, method: string): any[] => { + return block + .actions() + .filter((action) => action.receiverId === contract) + .flatMap((action) => + action.operations + .map(({ FunctionCall }) => FunctionCall) + .filter((operation) => operation?.methodName === method) + .map((functionCallOperation) => ({ + ...functionCallOperation, + args: base64DecodeFunction(functionCallOperation.args), + })), + ); + }; + return { graphql: async (operation, variables) => { console.log(`${functionName}: Running context graphql`, operation); @@ -164,7 +190,25 @@ export default class Indexer { fetchFromSocialApi: async (path, options) => { return await this.deps.fetch(`https://api.near.social${path}`, options); }, - db: this.buildDatabaseContext(account, schemaName, schema, blockHeight) + db: this.buildDatabaseContext(account, schemaName, schema, blockHeight), + base64Decode: base64DecodeFunction, + getFunctionCalls: getFunctionCallsFunction, + getSocialOperations: (block, operation) => { + const contract = 'social.near'; + const method = 'set'; + return getFunctionCallsFunction(block, contract, method) + .filter((functionCall) => { + const accountId = Object.keys(functionCall.args.data)[0]; + return functionCall.args.data[accountId][operation]; + }) + .map((functionCall) => { + const accountId = Object.keys(functionCall.args.data)[0]; + return { + accountId, + data: functionCall.args.data[accountId][operation], + }; + }); + }, }; } From 0f1ccfbe3d523789940866c772b9baa7bc18eb78 Mon Sep 17 00:00:00 2001 From: Gabe Hamilton Date: Fri, 10 Nov 2023 10:03:01 -0700 Subject: [PATCH 2/2] Handle near-primitives type mismatch, provide type for FunctionCall with decoded args. --- runner/src/indexer/indexer.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/runner/src/indexer/indexer.ts b/runner/src/indexer/indexer.ts index d29b2b41c..6a8c43267 100644 --- a/runner/src/indexer/indexer.ts +++ b/runner/src/indexer/indexer.ts @@ -13,6 +13,15 @@ interface Dependencies { parser: Parser }; +// '@near-lake/primitives/receipt' FunctionCall but with base64 decoded args +declare class DecodedFunctionCall { + readonly methodName: string; + readonly args: string; + readonly gas: number; + readonly deposit: string; + constructor (methodName: string, args: string, gas: number, deposit: string); +} + interface Context { graphql: (operation: string, variables?: Record) => Promise set: (key: string, value: any) => Promise @@ -24,7 +33,7 @@ interface Context { block: Block, contract: string, method: string, - ) => Array<{ Operation, args: string }> + ) => DecodedFunctionCall[] getSocialOperations: (block: Block, operation: string) => Array> } @@ -157,6 +166,7 @@ export default class Indexer { .filter((action) => action.receiverId === contract) .flatMap((action) => action.operations + // @ts-expect-error block data is an object keyed by type .map(({ FunctionCall }) => FunctionCall) .filter((operation) => operation?.methodName === method) .map((functionCallOperation) => ({