mirror of
https://github.com/cerc-io/watcher-ts
synced 2026-09-08 16:54:08 +00:00
Implement method for storage based access in subgraph mapping code (#162)
* Implement storage call in subgraph mapping code * Add test for mapping type variable storage call * Use vulcanize graph-ts * Revert to graph-ts version 0.22.1
This commit is contained in:
@@ -25,7 +25,8 @@ import {
|
||||
toEthereumValue,
|
||||
resolveEntityFieldConflicts,
|
||||
getEthereumTypes,
|
||||
jsonFromBytes
|
||||
jsonFromBytes,
|
||||
getStorageValueType
|
||||
} from './utils';
|
||||
import { Database } from './database';
|
||||
|
||||
@@ -236,6 +237,41 @@ export const instantiate = async (
|
||||
const [decoded] = utils.defaultAbiCoder.decode([typesString], dataString);
|
||||
|
||||
return toEthereumValue(instanceExports, utils.ParamType.from(typesString), decoded);
|
||||
},
|
||||
'ethereum.storageValue': async (contractName: number, contractAddress: number, variable: number, mappingKeys: number) => {
|
||||
const contractNameString = __getString(contractName);
|
||||
const address = await Address.wrap(contractAddress);
|
||||
const addressStringPtr = await address.toHexString();
|
||||
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(contractNameString);
|
||||
assert(storageLayout);
|
||||
assert(context.block);
|
||||
|
||||
const result = await indexer.getStorageValue(
|
||||
storageLayout,
|
||||
context.block.blockHash,
|
||||
addressString,
|
||||
variableString,
|
||||
...mappingKeyValues
|
||||
);
|
||||
|
||||
const storageValueType = getStorageValueType(storageLayout, variableString, mappingKeyValues);
|
||||
|
||||
return toEthereumValue(
|
||||
instanceExports,
|
||||
storageValueType,
|
||||
result.value
|
||||
);
|
||||
}
|
||||
},
|
||||
conversion: {
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Copyright 2022 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import assert from 'assert';
|
||||
import path from 'path';
|
||||
|
||||
import { BaseProvider } from '@ethersproject/providers';
|
||||
|
||||
import { instantiate } from './loader';
|
||||
import exampleAbi from '../test/subgraph/example1/build/Example1/abis/Example1.json';
|
||||
import { storageLayout } from '../test/artifacts/Example1.json';
|
||||
import { getTestDatabase, getTestIndexer, getTestProvider, getDummyEventData } from '../test/utils';
|
||||
import { Database } from './database';
|
||||
import { Indexer } from '../test/utils/indexer';
|
||||
import { EventData } from './utils';
|
||||
|
||||
xdescribe('storage-call wasm tests', () => {
|
||||
let exports: any;
|
||||
let db: Database;
|
||||
let indexer: Indexer;
|
||||
let provider: BaseProvider;
|
||||
|
||||
const contractAddress = process.env.EXAMPLE_CONTRACT_ADDRESS;
|
||||
assert(contractAddress);
|
||||
|
||||
const data = {
|
||||
abis: {
|
||||
Example1: exampleAbi
|
||||
},
|
||||
dataSource: {
|
||||
address: contractAddress,
|
||||
network: 'mainnet'
|
||||
}
|
||||
};
|
||||
|
||||
let dummyEventData: EventData;
|
||||
|
||||
before(async () => {
|
||||
db = getTestDatabase();
|
||||
indexer = getTestIndexer(new Map([['Example1', storageLayout]]));
|
||||
provider = getTestProvider();
|
||||
|
||||
// Create dummy test data.
|
||||
dummyEventData = await getDummyEventData();
|
||||
});
|
||||
|
||||
it('should load the subgraph example wasm', async () => {
|
||||
const filePath = path.resolve(__dirname, '../test/subgraph/example1/build/Example1/Example1.wasm');
|
||||
const instance = await instantiate(
|
||||
db,
|
||||
indexer,
|
||||
provider,
|
||||
{
|
||||
block: dummyEventData.block,
|
||||
contractAddress
|
||||
},
|
||||
filePath,
|
||||
data
|
||||
);
|
||||
exports = instance.exports;
|
||||
const { _start } = exports;
|
||||
|
||||
// Important to call _start for built subgraphs on instantiation!
|
||||
// TODO: Check api version https://github.com/graphprotocol/graph-node/blob/6098daa8955bdfac597cec87080af5449807e874/runtime/wasm/src/module/mod.rs#L533
|
||||
_start();
|
||||
});
|
||||
|
||||
it('should execute contract getStorageValue function', async () => {
|
||||
const { testGetStorageValue } = exports;
|
||||
|
||||
await testGetStorageValue();
|
||||
});
|
||||
|
||||
it('should execute getStorageValue function for mapping type variable', async () => {
|
||||
const { testMapStorageValue } = exports;
|
||||
|
||||
await testMapStorageValue();
|
||||
});
|
||||
});
|
||||
@@ -4,10 +4,12 @@ import fs from 'fs-extra';
|
||||
import debug from 'debug';
|
||||
import yaml from 'js-yaml';
|
||||
import { ColumnMetadata } from 'typeorm/metadata/ColumnMetadata';
|
||||
import assert from 'assert';
|
||||
|
||||
import { GraphDecimal } from '@vulcanize/util';
|
||||
|
||||
import { TypeId, EthereumValueKind, ValueKind } from './types';
|
||||
import { MappingKey, StorageLayout } from '@vulcanize/solidity-mapper';
|
||||
|
||||
const log = debug('vulcanize:utils');
|
||||
|
||||
@@ -767,3 +769,32 @@ export const jsonFromBytes = async (instanceExports: any, bytesPtr: number): Pro
|
||||
|
||||
return jsonValue;
|
||||
};
|
||||
|
||||
export const getStorageValueType = (storageLayout: StorageLayout, variableString: string, mappingKeys: MappingKey[]): utils.ParamType => {
|
||||
const storage = storageLayout.storage.find(({ label }) => label === variableString);
|
||||
assert(storage);
|
||||
|
||||
return getEthereumType(storageLayout.types, storage.type, mappingKeys);
|
||||
};
|
||||
|
||||
const getEthereumType = (storageTypes: StorageLayout['types'], type: string, mappingKeys: MappingKey[]): utils.ParamType => {
|
||||
const { label, encoding, members, value } = storageTypes[type];
|
||||
|
||||
if (encoding === 'mapping') {
|
||||
assert(value);
|
||||
|
||||
return getEthereumType(storageTypes, value, mappingKeys.slice(1));
|
||||
}
|
||||
|
||||
// Struct type contains members field.
|
||||
if (members) {
|
||||
const mappingKey = mappingKeys.shift();
|
||||
const member = members.find(({ label }) => label === mappingKey);
|
||||
assert(member);
|
||||
const { type } = member;
|
||||
|
||||
return getEthereumType(storageTypes, type, mappingKeys);
|
||||
}
|
||||
|
||||
return utils.ParamType.from(label);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user