watcher-ts/packages/graph-node/src/loader.ts
prathamesh0 ffd1d267d8
Implement remaining json host APIs (#487)
* Instantiate a new wasm string to convert JSON value to BigInt

* Implement remaining json host APIs

* Upgrade graph-ts and graph-cli in test example subgraph

* Handle null context for dataSource context host API

* Use JSONBig for parsing JSON strings
2023-11-22 18:03:21 +05:30

803 lines
29 KiB
TypeScript

//
// Copyright 2021 Vulcanize, Inc.
//
import assert from 'assert';
import fs from 'fs/promises';
import {
utils,
BigNumber,
Contract,
ContractInterface
} from 'ethers';
import BN from 'bn.js';
import debug from 'debug';
import { BaseProvider } from '@ethersproject/providers';
import loader from '@cerc-io/assemblyscript/lib/loader';
import {
IndexerInterface,
GraphDecimal,
getGraphDigitsAndExp,
prepareEntityState,
TypeId,
Level,
GraphDatabase,
Block,
fromEthereumValue,
toEthereumValue,
getEthereumTypes,
jsonFromBytes,
getStorageValueType
} from '@cerc-io/util';
// Endianness of BN used in bigInt store host API.
// Negative bigInt is being stored in wasm in 2's compliment, 'le' representation.
// (for eg. bigInt.fromString(negativeI32Value))
const BN_ENDIANNESS = 'le';
type idOfType = (TypeId: number) => number
export interface GraphData {
abis?: {[key: string]: ContractInterface};
dataSource: {
network: string;
name: string;
};
}
export interface Context {
rpcSupportsBlockHashParam: boolean;
block?: Block;
contractAddress?: string;
}
const log = debug('vulcanize:graph-node');
export const instantiate = async (
database: GraphDatabase,
indexer: IndexerInterface,
provider: BaseProvider,
context: Context,
filePathOrModule: string | WebAssembly.Module,
data: GraphData
): Promise<loader.ResultObject & { exports: any }> => {
const { abis = {}, dataSource } = data;
let source = filePathOrModule;
if (!(filePathOrModule instanceof WebAssembly.Module)) {
source = await fs.readFile(filePathOrModule);
}
const imports: WebAssembly.Imports = {
index: {
'store.get': async (entity: number, id: number) => {
const entityName = __getString(entity);
const entityId = __getString(id);
assert(context.block);
const entityData = await database.getEntity(entityName, entityId, context.block.blockHash);
if (!entityData || entityData.isRemoved) {
return null;
}
assert(indexer.getEntityTypesMap);
const entityTypesMap = indexer.getEntityTypesMap();
const entityTypes = entityTypesMap.get(entityName);
assert(entityTypes);
return database.toGraphEntity(instanceExports, entityName, entityData, entityTypes);
},
'store.set': async (entity: number, id: number, data: number) => {
const entityName = __getString(entity);
const entityInstance = await Entity.wrap(data);
assert(context.block);
const dbData = await database.fromGraphEntity(instanceExports, context.block, entityName, entityInstance);
const dbEntity = await database.saveEntity(entityName, dbData);
database.cacheUpdatedEntityByName(entityName, dbEntity);
// Update the in-memory subgraph state if enabled
if (indexer.serverConfig.enableState) {
// Prepare diff data for the entity update
assert(indexer.getRelationsMap);
const diffData = prepareEntityState(dbData, entityName, indexer.getRelationsMap());
assert(indexer.updateSubgraphState);
assert(context.contractAddress);
indexer.updateSubgraphState(context.contractAddress, diffData);
}
},
'store.remove': async (entity: number, id: number) => {
const entityName = __getString(entity);
const entityId = __getString(id);
assert(context.block);
const entityData = await database.getEntity(entityName, entityId, context.block.blockHash);
if (!entityData || entityData.isRemoved) {
return;
}
// Add an additional entry at block with isRemoved set to true
entityData.blockHash = context.block.blockHash;
entityData.blockNumber = context.block.blockNumber;
entityData.isRemoved = true;
const dbEntity = await database.saveEntity(entityName, entityData);
database.cacheUpdatedEntityByName(entityName, dbEntity);
},
'log.log': (level: number, msg: number) => {
log('log %s | %s', Level[level], __getString(msg));
},
'crypto.keccak256': async (input: number) => {
const byteArray = await ByteArray.wrap(input);
const hexStringPtr = await byteArray.toHexString();
const hexString = __getString(hexStringPtr);
const keccak256 = utils.keccak256(hexString);
const keccak256Ptr = await __newString(keccak256);
return ByteArray.fromHexString(keccak256Ptr);
},
'test.asyncMethod': async () => {
console.log('before timer start');
await new Promise(resolve => {
setTimeout(() => {
resolve(1);
}, 3000);
});
console.log('after timer complete');
return 123;
}
},
ethereum: {
'ethereum.call': async (call: number) => {
const smartContractCall = await ethereum.SmartContractCall.wrap(call);
const contractAddressPtr = await smartContractCall.contractAddress;
const contractAddress = await Address.wrap(contractAddressPtr);
const contractNamePtr = await smartContractCall.contractName;
const contractName = __getString(contractNamePtr);
const functionNamePtr = await smartContractCall.functionName;
const functionName = __getString(functionNamePtr);
const functionSignaturePtr = await smartContractCall.functionSignature;
const functionSignature = __getString(functionSignaturePtr);
const functionParamsPtr = await smartContractCall.functionParams;
let functionParams = __getArray(functionParamsPtr);
console.log('ethereum.call functionSignature:', functionSignature);
const abi = abis[contractName];
const contractAddressStringPtr = await contractAddress.toHexString();
const contract = new Contract(__getString(contractAddressStringPtr), abi, provider);
try {
const functionParamsPromise = functionParams.map(async param => {
const ethereumValue = await ethereum.Value.wrap(param);
return fromEthereumValue(instanceExports, ethereumValue);
});
functionParams = await Promise.all(functionParamsPromise);
assert(context.block);
let result: any;
// TODO: Check for function overloading.
console.time(`time:loader#ethereum.call-${functionName}`);
if (context.rpcSupportsBlockHashParam) {
result = await contract[functionName](
...functionParams,
{ blockTag: context.block.blockHash }
);
} else {
result = await contract[functionName](
...functionParams,
{ blockTag: BigNumber.from(context.block.blockNumber).toHexString() }
);
}
console.timeEnd(`time:loader#ethereum.call-${functionName}`);
// Using function signature does not work.
const { outputs } = contract.interface.getFunction(functionName);
assert(outputs);
// If method returns a single value, ethers returns it directly compared to returning multiple values in an array.
if (outputs.length === 1) {
// Put result in an array to map with the outputs array from abi.
result = [result];
}
const resultPtrArrayPromise = outputs.map(
async (
output: any,
index: number
) => toEthereumValue(
instanceExports,
output,
result[index]
)
);
const resultPtrArray: any[] = await Promise.all(resultPtrArrayPromise);
const arrayEthereumValueId = await getIdOfType(TypeId.ArrayEthereumValue);
const res = await __newArray(arrayEthereumValueId, resultPtrArray);
return res;
} catch (err: any) {
log('eth_call error', err.message);
return null;
}
},
'ethereum.encode': async (token: number) => {
const ethValue = await ethereum.Value.wrap(token);
const data = await fromEthereumValue(instanceExports, ethValue);
const type = await getEthereumTypes(instanceExports, ethValue);
const encoded = utils.defaultAbiCoder.encode([type], [data]);
const encodedString = await __newString(encoded);
return ByteArray.fromHexString(encodedString);
},
'ethereum.decode': async (types: number, data: number) => {
const typesString = __getString(types);
const byteArray = await ByteArray.wrap(data);
const bytesHex = await byteArray.toHex();
const dataString = __getString(bytesHex);
const [decoded] = utils.defaultAbiCoder.decode([typesString], dataString);
return toEthereumValue(instanceExports, utils.ParamType.from(typesString), decoded);
},
'ethereum.storageValue': async (variable: number, mappingKeys: number) => {
assert(context.contractAddress);
const addressStringPtr = await __newString(context.contractAddress);
const addressString = __getString(addressStringPtr);
const variableString = __getString(variable);
const mappingKeyPtrs = __getArray(mappingKeys);
const mappingKeyPromises = mappingKeyPtrs.map(async mappingKeyPtr => {
const ethereumValue = await ethereum.Value.wrap(mappingKeyPtr);
return fromEthereumValue(instanceExports, ethereumValue);
});
const mappingKeyValues = await Promise.all(mappingKeyPromises);
const storageLayout = indexer.storageLayoutMap.get(dataSource.name);
assert(storageLayout);
assert(context.block);
console.time(`time:loader#ethereum.storageValue-${variableString}`);
const result = await indexer.getStorageValue(
storageLayout,
context.block.blockHash,
addressString,
variableString,
...mappingKeyValues
);
console.timeEnd(`time:loader#ethereum.storageValue-${variableString}`);
const storageValueType = getStorageValueType(storageLayout, variableString, mappingKeyValues);
return toEthereumValue(
instanceExports,
storageValueType,
result.value
);
}
},
conversion: {
'typeConversion.stringToH160': async (s: number) => {
const string = __getString(s);
const address = utils.getAddress(string.trim());
const byteArray = utils.arrayify(address);
const uint8ArrayId = await getIdOfType(TypeId.Uint8Array);
const ptr = __newArray(uint8ArrayId, byteArray);
return ptr;
},
'typeConversion.bigIntToString': (bigInt: number) => {
const bigIntByteArray = __getArray(bigInt);
// Create a BN with 'le' endianness.
const bigNumber = new BN(bigIntByteArray, BN_ENDIANNESS);
// Convert BN from two's compliment and to string.
const bigNumberString = bigNumber.fromTwos(bigIntByteArray.length * 8).toString();
const ptr = __newString(bigNumberString);
return ptr;
},
'typeConversion.bigIntToHex': async (bigInt: number) => {
const bigIntInstance = await ASBigInt.wrap(bigInt);
const bigIntString = await bigIntInstance.toString();
const bigNumber = BigNumber.from(__getString(bigIntString));
const bigNumberHex = bigNumber.toHexString();
return __newString(bigNumberHex);
},
'typeConversion.bytesToHex': async (bytes: number) => {
const byteArray = __getArray(bytes);
const hexString = utils.hexlify(byteArray);
const ptr = await __newString(hexString);
return ptr;
},
'typeConversion.bytesToString': async (bytes: number) => {
const byteArray = __getArray(bytes);
const string = utils.toUtf8String(byteArray);
const ptr = await __newString(string);
return ptr;
},
'typeConversion.bytesToBase58': async (n: number) => {
const uint8Array = __getArray(n);
const string = utils.base58.encode(uint8Array);
const ptr = await __newString(string);
return ptr;
}
},
numbers: {
'bigDecimal.dividedBy': async (x: number, y: number) => {
// Creating decimal x.
const xBigDecimal = await BigDecimal.wrap(x);
const xStringPtr = await xBigDecimal.toString();
const xDecimalString = __getString(xStringPtr);
const xDecimal = new GraphDecimal(xDecimalString);
// Create decimal y.
const yBigDecimal = await BigDecimal.wrap(y);
const yStringPtr = await yBigDecimal.toString();
const yDecimalString = __getString(yStringPtr);
// Performing the decimal division operation.
const divResult = xDecimal.dividedBy(yDecimalString);
const ptr = await __newString(divResult.toString());
const divResultBigDecimal = await BigDecimal.fromString(ptr);
return divResultBigDecimal;
},
'bigDecimal.toString': async (bigDecimal: number) => {
const bigDecimalInstance = BigDecimal.wrap(bigDecimal);
const digitsPtr = await bigDecimalInstance.digits;
const digitsBigInt = ASBigInt.wrap(digitsPtr);
const expPtr = await bigDecimalInstance.exp;
const expBigInt = ASBigInt.wrap(expPtr);
const digitsStringPtr = await digitsBigInt.toString();
const digits = __getString(digitsStringPtr);
const expStringPtr = await expBigInt.toString();
const exp = __getString(expStringPtr);
const decimal = new GraphDecimal(`${digits}e${exp}`);
const ptr = __newString(decimal.toFixed());
return ptr;
},
'bigDecimal.fromString': async (s: number) => {
const string = __getString(s);
// Creating a decimal using custom decimal implementation.
const decimal = new GraphDecimal(string);
// Get digits string and exp using decimal 'd' and 'e' properties.
const { digits, exp } = getGraphDigitsAndExp(decimal.value.d, decimal.value.e);
// Create a digits BigInt using digits string and decimal sign 's' property.
const digitsBigNumber = BigNumber.from(digits);
const signBigNumber = BigNumber.from(decimal.value.s);
const digitsStringPtr = await __newString(digitsBigNumber.mul(signBigNumber).toString());
const digitsBigInt = await ASBigInt.fromString(digitsStringPtr);
// Create an exp BigInt.
const expStringPtr = await __newString(exp.toString());
const expBigInt = await ASBigInt.fromString(expStringPtr);
// Create a BigDecimal using digits and exp BigInts.
const bigDecimal = await BigDecimal.__new(digitsBigInt);
bigDecimal.exp = expBigInt;
return bigDecimal;
},
'bigDecimal.plus': async (x: number, y: number) => {
// Create decimal x string.
const xBigDecimal = await BigDecimal.wrap(x);
const xStringPtr = await xBigDecimal.toString();
const xDecimalString = __getString(xStringPtr);
const xDecimal = new GraphDecimal(xDecimalString);
// Create decimal y string.
const yBigDecimal = await BigDecimal.wrap(y);
const yStringPtr = await yBigDecimal.toString();
const yDecimalString = __getString(yStringPtr);
// Perform the decimal plus operation.
const sumResult = xDecimal.plus(yDecimalString);
const ptr = await __newString(sumResult.toString());
const sumResultBigDecimal = await BigDecimal.fromString(ptr);
return sumResultBigDecimal;
},
'bigDecimal.minus': async (x: number, y: number) => {
// Create decimal x string.
const xBigDecimal = await BigDecimal.wrap(x);
const xStringPtr = await xBigDecimal.toString();
const xDecimalString = __getString(xStringPtr);
const xDecimal = new GraphDecimal(xDecimalString);
// Create decimal y string.
const yBigDecimal = await BigDecimal.wrap(y);
const yStringPtr = await yBigDecimal.toString();
const yDecimalString = __getString(yStringPtr);
// Perform the decimal minus operation.
const subResult = xDecimal.minus(yDecimalString);
const ptr = await __newString(subResult.toString());
const subResultBigDecimal = await BigDecimal.fromString(ptr);
return subResultBigDecimal;
},
'bigDecimal.times': async (x: number, y: number) => {
// Create decimal x string.
const xBigDecimal = await BigDecimal.wrap(x);
const xStringPtr = await xBigDecimal.toString();
const xDecimalString = __getString(xStringPtr);
const xDecimal = new GraphDecimal(xDecimalString);
// Create decimal y string.
const yBigDecimal = await BigDecimal.wrap(y);
const yStringPtr = await yBigDecimal.toString();
const yDecimalString = __getString(yStringPtr);
// Perform the decimal times operation.
const mulResult = xDecimal.times(yDecimalString);
const ptr = await __newString(mulResult.toString());
const mulResultBigDecimal = await BigDecimal.fromString(ptr);
return mulResultBigDecimal;
},
'bigDecimal.pow': async (x: number, y: number) => {
// Create decimal x string.
const xBigDecimal = await BigDecimal.wrap(x);
const xStringPtr = await xBigDecimal.toString();
const xDecimalString = __getString(xStringPtr);
const xDecimal = new GraphDecimal(xDecimalString);
// Create decimal y string.
const yBigDecimal = await BigDecimal.wrap(y);
const yStringPtr = await yBigDecimal.toString();
const yDecimalString = __getString(yStringPtr);
// Perform the decimal pow operation.
const powResult = xDecimal.pow(yDecimalString);
const ptr = await __newString(powResult.toString());
const powResultBigDecimal = await BigDecimal.fromString(ptr);
return powResultBigDecimal;
},
'bigDecimal.equals': async (x: number, y: number) => {
// Create decimal x string.
const xBigDecimal = await BigDecimal.wrap(x);
const xStringPtr = await xBigDecimal.toString();
const xDecimalString = __getString(xStringPtr);
const xDecimal = new GraphDecimal(xDecimalString);
// Create decimal y string.
const yBigDecimal = await BigDecimal.wrap(y);
const yStringPtr = await yBigDecimal.toString();
const yDecimalString = __getString(yStringPtr);
// Perform the decimal equal operation.
const isEqual = xDecimal.equals(yDecimalString);
return isEqual;
},
'bigInt.fromString': async (s: number) => {
const string = __getString(s);
// The BN is being stored as a byte array in wasm memory in 2's compliment representation and interpreted as such in other APIs.
// Create a BN in 2's compliment representation.
// Need to use BN as ethers.BigNumber:
// Doesn't store -ve numbers in 2's compilment form
// Stores in big endian form.
let bigNumber = new BN(string);
// Size (in bytes) of the BN stored.
// Add an extra byte to the BNs byte length to allow for 2's compiment.
const bnSize = bigNumber.byteLength() + 1;
bigNumber = bigNumber.toTwos(bnSize * 8);
// Create a byte array out of BN in 'le' endianness.
const bytes = bigNumber.toArray(BN_ENDIANNESS, bnSize);
const uint8ArrayId = await getIdOfType(TypeId.Uint8Array);
const ptr = await __newArray(uint8ArrayId, bytes);
const bigInt = await ASBigInt.fromSignedBytes(ptr);
return bigInt;
},
'bigInt.plus': async (x: number, y: number) => {
const xBigInt = await ASBigInt.wrap(x);
const xStringPtr = await xBigInt.toString();
const xBigNumber = BigNumber.from(__getString(xStringPtr));
const yBigInt = await ASBigInt.wrap(y);
const yStringPtr = await yBigInt.toString();
const yBigNumber = BigNumber.from(__getString(yStringPtr));
const sum = xBigNumber.add(yBigNumber);
const ptr = await __newString(sum.toString());
const sumBigInt = await ASBigInt.fromString(ptr);
return sumBigInt;
},
'bigInt.minus': async (x: number, y: number) => {
const xBigInt = await ASBigInt.wrap(x);
const xStringPtr = await xBigInt.toString();
const xBigNumber = BigNumber.from(__getString(xStringPtr));
const yBigInt = await ASBigInt.wrap(y);
const yStringPtr = await yBigInt.toString();
const yBigNumber = BigNumber.from(__getString(yStringPtr));
const diff = xBigNumber.sub(yBigNumber);
const ptr = await __newString(diff.toString());
const diffBigInt = ASBigInt.fromString(ptr);
return diffBigInt;
},
'bigInt.times': async (x: number, y: number) => {
const xBigInt = await ASBigInt.wrap(x);
const xStringPtr = await xBigInt.toString();
const xBigNumber = BigNumber.from(__getString(xStringPtr));
const yBigInt = await ASBigInt.wrap(y);
const yStringPtr = await yBigInt.toString();
const yBigNumber = BigNumber.from(__getString(yStringPtr));
const product = xBigNumber.mul(yBigNumber);
const ptr = await __newString(product.toString());
const productBigInt = ASBigInt.fromString(ptr);
return productBigInt;
},
'bigInt.dividedBy': async (x: number, y: number) => {
const xBigInt = await ASBigInt.wrap(x);
const xStringPtr = await xBigInt.toString();
const xBigNumber = BigNumber.from(__getString(xStringPtr));
const yBigInt = await ASBigInt.wrap(y);
const yStringPtr = await yBigInt.toString();
const yBigNumber = BigNumber.from(__getString(yStringPtr));
const quotient = xBigNumber.div(yBigNumber);
const ptr = await __newString(quotient.toString());
const quotientBigInt = ASBigInt.fromString(ptr);
return quotientBigInt;
},
'bigInt.dividedByDecimal': async (x: number, y: number) => {
// Create a decimal out of bigInt x.
const xBigInt = await ASBigInt.wrap(x);
const xStringPtr = await xBigInt.toString();
const xDecimal = new GraphDecimal(__getString(xStringPtr));
// Create decimal y.
const yBigDecimal = await BigDecimal.wrap(y);
const yStringPtr = await yBigDecimal.toString();
const yDecimal = new GraphDecimal(__getString(yStringPtr));
// Perform the decimal division operation.
const divResult = xDecimal.dividedBy(yDecimal);
const ptr = await __newString(divResult.toString());
const divResultBigDecimal = await BigDecimal.fromString(ptr);
return divResultBigDecimal;
},
'bigInt.mod': async (x: number, y: number) => {
// Create a bigNumber x.
const xBigInt = await ASBigInt.wrap(x);
const xStringPtr = await xBigInt.toString();
const xBigNumber = BigNumber.from(__getString(xStringPtr));
// Create a bigNumber y.
const yBigInt = await ASBigInt.wrap(y);
const yStringPtr = await yBigInt.toString();
const yBigNumber = BigNumber.from(__getString(yStringPtr));
// Perform the bigNumber mod operation.
const remainder = xBigNumber.mod(yBigNumber);
const ptr = await __newString(remainder.toString());
const remainderBigInt = ASBigInt.fromString(ptr);
return remainderBigInt;
},
'bigInt.bitOr': async (x: number, y: number) => {
// Create a bigNumber x.
const xBigInt = await ASBigInt.wrap(x);
const xStringPtr = await xBigInt.toString();
const xBigNumber = BigNumber.from(__getString(xStringPtr));
// Create a bigNumber y.
const yBigInt = await ASBigInt.wrap(y);
const yStringPtr = await yBigInt.toString();
const yBigNumber = BigNumber.from(__getString(yStringPtr));
// Perform the bigNumber bit or operation.
const res = xBigNumber.or(yBigNumber);
const ptr = await __newString(res.toString());
const resBigInt = ASBigInt.fromString(ptr);
return resBigInt;
},
'bigInt.bitAnd': async (x: number, y: number) => {
// Create a bigNumber x.
const xBigInt = await ASBigInt.wrap(x);
const xStringPtr = await xBigInt.toString();
const xBigNumber = BigNumber.from(__getString(xStringPtr));
// Create a bigNumber y.
const yBigInt = await ASBigInt.wrap(y);
const yStringPtr = await yBigInt.toString();
const yBigNumber = BigNumber.from(__getString(yStringPtr));
// Perform the bigNumber bit and operation.
const res = xBigNumber.and(yBigNumber);
const ptr = await __newString(res.toString());
const resBigInt = ASBigInt.fromString(ptr);
return resBigInt;
},
'bigInt.leftShift': async (x: number, y: number) => {
// Create a bigNumber x.
const xBigInt = await ASBigInt.wrap(x);
const xStringPtr = await xBigInt.toString();
const xBigNumber = BigNumber.from(__getString(xStringPtr));
// Perform the bigNumber left shift operation.
const res = xBigNumber.shl(y);
const ptr = await __newString(res.toString());
const resBigInt = ASBigInt.fromString(ptr);
return resBigInt;
},
'bigInt.rightShift': async (x: number, y: number) => {
// Create a bigNumber x.
const xBigInt = await ASBigInt.wrap(x);
const xStringPtr = await xBigInt.toString();
const xBigNumber = BigNumber.from(__getString(xStringPtr));
// Perform the bigNumber right shift operation.
const res = xBigNumber.shr(y);
const ptr = await __newString(res.toString());
const resBigInt = ASBigInt.fromString(ptr);
return resBigInt;
},
'bigInt.pow': async (x: number, y: number) => {
// Create a bigNumber x.
const xBigInt = await ASBigInt.wrap(x);
const xStringPtr = await xBigInt.toString();
const xBigNumber = BigNumber.from(__getString(xStringPtr));
// Perform the bigNumber pow operation.
const res = xBigNumber.pow(y);
const ptr = await __newString(res.toString());
const resBigInt = ASBigInt.fromString(ptr);
return resBigInt;
}
},
datasource: {
'dataSource.address': async () => {
assert(context.contractAddress);
const addressStringPtr = await __newString(context.contractAddress);
return Address.fromString(addressStringPtr);
},
'dataSource.context': async () => {
assert(context.contractAddress);
const contract = indexer.isWatchedContract(context.contractAddress);
if (!contract) {
return null;
}
return database.toGraphContext(instanceExports, contract.context);
},
'dataSource.network': async () => {
assert(dataSource);
return __newString(dataSource.network);
},
'dataSource.create': async (name: number, params: number) => {
const [addressStringPtr] = __getArray(params);
const addressString = __getString(addressStringPtr);
const contractKind = __getString(name);
assert(indexer.watchContract);
assert(context.block);
await indexer.watchContract(utils.getAddress(addressString), contractKind, true, Number(context.block.blockNumber));
},
'dataSource.createWithContext': async (name: number, params: number, dataSourceContext: number) => {
const [addressStringPtr] = __getArray(params);
const addressString = __getString(addressStringPtr);
const contractKind = __getString(name);
const contextInstance = await Entity.wrap(dataSourceContext);
const dbData = await database.fromGraphContext(instanceExports, contextInstance);
assert(indexer.watchContract);
assert(context.block);
await indexer.watchContract(utils.getAddress(addressString), contractKind, true, Number(context.block.blockNumber), dbData);
}
},
json: {
'json.fromBytes': async (bytes: number) => {
return jsonFromBytes(instanceExports, bytes);
},
'json.try_fromBytes': async (bytes: number) => {
try {
const jsonValue = await jsonFromBytes(instanceExports, bytes);
return JSONResult.__new(jsonValue);
} catch (error) {
log('json.try_fromBytes error', error);
return JSONResult.__new(null);
}
},
'json.toI64': (decimal: number) => {
return BigInt(__getString(decimal));
},
'json.toU64': (decimal: number) => {
return BigInt(__getString(decimal));
},
'json.toF64': (decimal: number) => {
return Number(__getString(decimal));
},
'json.toBigInt': async (decimal: number) => {
const ptr = await __newString(__getString(decimal));
return ASBigInt.fromString(ptr);
}
}
};
const instance = await loader.instantiate(source, imports);
const { exports: instanceExports } = instance;
const { __getString, __newString, __getArray, __newArray } = instanceExports;
// TODO: Assign from types file generated by graph-cli
const getIdOfType: idOfType = instanceExports.id_of_type as idOfType;
const BigDecimal: any = instanceExports.BigDecimal as any;
const ASBigInt: any = instanceExports.BigInt as any;
const Address: any = instanceExports.Address as any;
const ethereum: any = instanceExports.ethereum as any;
const Entity: any = instanceExports.Entity as any;
const ByteArray: any = instanceExports.ByteArray as any;
const JSONResult: any = instanceExports.JSONResult as any;
return instance;
};