Skip to content

Commit

Permalink
add a generic call-tokenuri strategy
Browse files Browse the repository at this point in the history
The purpose of this generic call-tokenuri strategy is to remove the
need of diffferent strategies such as soundxyz-call-tokenuri,
zora-call-tokenuri, catalog-call-tokenuri etc.

The benefits include:
- Less number of files to mantain
- Easier to refactor
- Easier to integrate new indie contracts

This new call-tokenuri strategy has been modified to not need
logs-to-subgraph strategy.

I have tested this commit and the output files are the same as before.
  • Loading branch information
il3ven committed Oct 4, 2022
1 parent 94a65e8 commit a40e82e
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 0 deletions.
116 changes: 116 additions & 0 deletions src/strategies/call-tokenuri/extractor.mjs
@@ -0,0 +1,116 @@
// @format
import { env } from "process";
import { createInterface } from "readline";
import { createReadStream } from "fs";

import { toHex, encodeFunctionCall } from "eth-fun";

import logger from "../../logger.mjs";
import { fileExists } from "../../disc.mjs";
import { eth_callSchema } from "./schema.mjs";

// Instead of querying at the block number soundxyz NFT
// was minted, we query at a higher block number because
// soundxyz changed their tokenURI and the previous one
// doesn't work anymore. https://github.com/neume-network/data/issues/19
const BLOCK_NUMBER = 15050010;

export const name = "call-tokenuri";
export const version = "0.0.1";

const log = logger(name);

const options = {
url: env.RPC_HTTP_HOST,
};

if (env.RPC_API_KEY) {
options.headers = {
Authorization: `Bearer ${env.RPC_API_KEY}`,
};
}

async function init(filePath, signature, filterFunc) {
if (!(await fileExists(filePath))) {
log(
`Skipping "${name}" extractor execution as file doesn't exist "${filePath}"`
);
return {
write: "",
messages: [],
};
}
const rl = createInterface({
input: createReadStream(filePath),
crlfDelay: Infinity,
});

let messages = [];
for await (const line of rl) {
// NOTE: We're ignoring empty lines
if (line === "") continue;
const nfts = JSON.parse(line);

messages = [
...messages,
...nfts
.filter(filterFunc)
.map(({ log }) =>
makeRequest(
BigInt(log.topics[3]).toString(10),
parseInt(log.blockNumber, 16),
log.address,
signature
)
),
];
}
return {
write: null,
messages,
};
}

function makeRequest(tokenId, blockNumber, address, signature) {
const data = encodeFunctionCall(signature, [tokenId]);

const from = null;
return {
type: "json-rpc",
options,
version,
method: "eth_call",
params: [
{
from,
to: address,
data,
},
toHex(Math.max(blockNumber, BLOCK_NUMBER)),
],
metadata: {
block: {
number: blockNumber,
},
contract: {
address,
},
tokenId,
},
results: null,
schema: eth_callSchema,
error: null,
};
}

function update(message) {
return {
messages: [],
write: JSON.stringify({
metadata: message.metadata,
results: message.results,
}),
};
}

export { init, update };
5 changes: 5 additions & 0 deletions src/strategies/call-tokenuri/schema.mjs
@@ -0,0 +1,5 @@
export const eth_callSchema = {
$schema: "http://json-schema.org/draft-07/schema#",
description: "Hex representation of a variable length byte array",
type: "string",
};
43 changes: 43 additions & 0 deletions src/strategies/call-tokenuri/transformer.mjs
@@ -0,0 +1,43 @@
// @format
import { decodeParameters } from "eth-fun";

import logger from "../../logger.mjs";

export const name = "call-tokenuri";
export const version = "0.0.1";

const log = logger(name);

function onClose() {
return;
}

function onError(error) {
log(error.toString());
throw error;
}

function onLine(line, resultKey) {
let obj;

try {
obj = JSON.parse(line);
} catch (err) {
log(err.toString());
return;
}

let decodedOutput;
try {
[decodedOutput] = decodeParameters(["string"], obj.results);
} catch (err) {
log(err.toString());
return;
}
return JSON.stringify({
metadata: obj.metadata,
[resultKey]: decodedOutput,
});
}

export { onClose, onLine, onError };

0 comments on commit a40e82e

Please sign in to comment.