mirror of
https://github.com/cerc-io/watcher-ts
synced 2024-11-19 20:36:19 +00:00
Get value for nested array, mapping with address keys and struct value (#64)
* Add test for mapping with address keys and struct value. * Implement getting value for nested array. Co-authored-by: nikugogoi <95nikass@gmail.com>
This commit is contained in:
parent
3815853f7b
commit
3439dd4041
@ -49,7 +49,7 @@ $ yarn test
|
|||||||
* [ ] Struct Type
|
* [ ] Struct Type
|
||||||
* [ ] Mapping Type
|
* [ ] Mapping Type
|
||||||
* [ ] Nested Arrays
|
* [ ] Nested Arrays
|
||||||
* [ ] Fixed size arrays
|
* [x] Fixed size arrays
|
||||||
* [ ] Dynamically-sized arrays
|
* [ ] Dynamically-sized arrays
|
||||||
* [ ] Dynamically-sized byte array
|
* [ ] Dynamically-sized byte array
|
||||||
* [ ] Bytes
|
* [ ] Bytes
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { Contract } from '@ethersproject/contracts';
|
import { Contract } from '@ethersproject/contracts';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { ethers } from 'hardhat';
|
import { ethers } from 'hardhat';
|
||||||
@ -416,9 +417,63 @@ describe('Get value from storage', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('nested arrays', () => {
|
||||||
|
let testNestedArrays: Contract, storageLayout: StorageLayout;
|
||||||
|
const nestedStructArray: Array<Array<{[key: string]: any}>> = [];
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
const TestNestedArrays = await ethers.getContractFactory('TestNestedArrays');
|
||||||
|
testNestedArrays = await TestNestedArrays.deploy();
|
||||||
|
await testNestedArrays.deployed();
|
||||||
|
storageLayout = await getStorageLayout('TestNestedArrays');
|
||||||
|
|
||||||
|
const signers = await ethers.getSigners();
|
||||||
|
|
||||||
|
// Set value for nestedStructArray.
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
nestedStructArray[i] = [];
|
||||||
|
|
||||||
|
for (let j = 0; j < 3; j++) {
|
||||||
|
const value = {
|
||||||
|
uint1: BigInt((i + j) * 100),
|
||||||
|
address1: signers[(i + j) % 5].address.toLowerCase()
|
||||||
|
};
|
||||||
|
|
||||||
|
nestedStructArray[i][j] = value;
|
||||||
|
|
||||||
|
// Set value in contract.
|
||||||
|
await testNestedArrays.setNestedStructArray(i, j, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get all elements of array.
|
||||||
|
it('get value for fixed size nested array of struct type', async () => {
|
||||||
|
const blockHash = await getBlockHash();
|
||||||
|
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testNestedArrays.address, 'nestedStructArray');
|
||||||
|
expect(value).to.eql(nestedStructArray);
|
||||||
|
const proofData = JSON.parse(proof.data);
|
||||||
|
expect(proofData.length).to.equal(nestedStructArray.length);
|
||||||
|
expect(proofData[0].length).to.equal(nestedStructArray[0].length);
|
||||||
|
expect(proofData[0]).to.have.all.keys(Object.keys(nestedStructArray[0]));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get element of array by index.
|
||||||
|
it('get value of fixed size struct type nested array by index', async () => {
|
||||||
|
const arrayIndex = 2;
|
||||||
|
const nestedArrayIndex = 1;
|
||||||
|
const blockHash = await getBlockHash();
|
||||||
|
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testNestedArrays.address, 'nestedStructArray', arrayIndex, nestedArrayIndex);
|
||||||
|
expect(value).to.eql(nestedStructArray[arrayIndex][nestedArrayIndex]);
|
||||||
|
|
||||||
|
const structMember = 'address1';
|
||||||
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testNestedArrays.address, 'nestedStructArray', arrayIndex, nestedArrayIndex, structMember));
|
||||||
|
expect(value).to.equal(nestedStructArray[arrayIndex][nestedArrayIndex][structMember]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('structs with value type members', () => {
|
describe('structs with value type members', () => {
|
||||||
let testValueStructs: Contract, storageLayout: StorageLayout;
|
let testValueStructs: Contract, storageLayout: StorageLayout;
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
let addressStruct: { [key: string]: any }, contractStruct: { [key: string]: any };
|
let addressStruct: { [key: string]: any }, contractStruct: { [key: string]: any };
|
||||||
|
|
||||||
const singleSlotStruct = {
|
const singleSlotStruct = {
|
||||||
@ -691,7 +746,7 @@ describe('Get value from storage', () => {
|
|||||||
expect(value).to.eql(stringStruct[member]);
|
expect(value).to.eql(stringStruct[member]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('get value of mapping type member in a struct', async () => {
|
it('get value of mapping type member in a struct', async () => {
|
||||||
const [signer1, signer2] = await ethers.getSigners();
|
const [signer1, signer2] = await ethers.getSigners();
|
||||||
|
|
||||||
const valueMappingStruct: { [key: string]: any } = {
|
const valueMappingStruct: { [key: string]: any } = {
|
||||||
@ -710,6 +765,7 @@ describe('Get value from storage', () => {
|
|||||||
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'valueMappingStruct', member, mappingKey);
|
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'valueMappingStruct', member, mappingKey);
|
||||||
expect(value).to.equal(valueMappingStruct[member].get(mappingKey));
|
expect(value).to.equal(valueMappingStruct[member].get(mappingKey));
|
||||||
|
|
||||||
|
// Get value for structs with mapping of reference type keys.
|
||||||
const referenceMappingStruct: { [key: string]: any } = {
|
const referenceMappingStruct: { [key: string]: any } = {
|
||||||
bytesAddressMap: new Map(),
|
bytesAddressMap: new Map(),
|
||||||
stringUintMap: new Map()
|
stringUintMap: new Map()
|
||||||
@ -718,8 +774,8 @@ describe('Get value from storage', () => {
|
|||||||
const bytesKey = ethers.utils.hexlify(ethers.utils.randomBytes(40));
|
const bytesKey = ethers.utils.hexlify(ethers.utils.randomBytes(40));
|
||||||
const stringKey = 'abc';
|
const stringKey = 'abc';
|
||||||
referenceMappingStruct.bytesAddressMap.set(bytesKey, signer1.address.toLowerCase());
|
referenceMappingStruct.bytesAddressMap.set(bytesKey, signer1.address.toLowerCase());
|
||||||
referenceMappingStruct.stringUintMap.set(stringKey, 123);
|
referenceMappingStruct.stringUintMap.set(stringKey, BigInt(123));
|
||||||
member = 'stringAddressMap';
|
member = 'stringUintMap';
|
||||||
|
|
||||||
await testReferenceStructs.setReferenceMappingStruct(bytesKey, referenceMappingStruct.bytesAddressMap.get(bytesKey), stringKey, referenceMappingStruct.stringUintMap.get(stringKey));
|
await testReferenceStructs.setReferenceMappingStruct(bytesKey, referenceMappingStruct.bytesAddressMap.get(bytesKey), stringKey, referenceMappingStruct.stringUintMap.get(stringKey));
|
||||||
blockHash = await getBlockHash();
|
blockHash = await getBlockHash();
|
||||||
@ -877,6 +933,23 @@ describe('Get value from storage', () => {
|
|||||||
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'fixedBytesStructMap', mapKey, structMember));
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'fixedBytesStructMap', mapKey, structMember));
|
||||||
expect(value).to.equal(expectedValue[structMember]);
|
expect(value).to.equal(expectedValue[structMember]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('get value for mapping of address type keys and struct type values', async () => {
|
||||||
|
const [signer1, signer2] = await ethers.getSigners();
|
||||||
|
|
||||||
|
const expectedValue = {
|
||||||
|
uint1: BigInt(123),
|
||||||
|
int1: BigInt(456),
|
||||||
|
bool1: true,
|
||||||
|
address1: signer1.address.toLowerCase()
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapKey = signer2.address;
|
||||||
|
await testMappingTypes.setAddressStructMap(mapKey, expectedValue);
|
||||||
|
const blockHash = await getBlockHash();
|
||||||
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'addressStructMap', mapKey);
|
||||||
|
expect(value).to.eql(expectedValue);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('nested mapping type', () => {
|
describe('nested mapping type', () => {
|
||||||
|
@ -105,11 +105,13 @@ const getDecodedValue = async (getStorageAt: GetStorageAt, blockHash: string, ad
|
|||||||
const { slot, offset, type } = storageInfo;
|
const { slot, offset, type } = storageInfo;
|
||||||
const { encoding, numberOfBytes, label: typeLabel, base, value: mappingValueType, key: mappingKeyType, members } = types[type];
|
const { encoding, numberOfBytes, label: typeLabel, base, value: mappingValueType, key: mappingKeyType, members } = types[type];
|
||||||
|
|
||||||
const [isArray, arraySize] = typeLabel.match(/\[([0-9]*)\]/) || [false];
|
|
||||||
let value: string, proof: { data: string };
|
let value: string, proof: { data: string };
|
||||||
|
const arrayMatch = [...typeLabel.matchAll(/\[([0-9]*)\]/g)];
|
||||||
|
|
||||||
// If variable is array type.
|
// If variable is array type.
|
||||||
if (isArray && base) {
|
if (arrayMatch.length && base) {
|
||||||
|
const arraySize = arrayMatch[arrayMatch.length - 1][1];
|
||||||
|
|
||||||
return getArrayValue(getStorageAt, blockHash, address, types, mappingKeys, slot, base, Number(arraySize));
|
return getArrayValue(getStorageAt, blockHash, address, types, mappingKeys, slot, base, Number(arraySize));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,9 @@ contract TestBasicMapping {
|
|||||||
// Mapping with signed integer as keys and struct type values.
|
// Mapping with signed integer as keys and struct type values.
|
||||||
mapping(bytes32 => TestStruct) public fixedBytesStructMap;
|
mapping(bytes32 => TestStruct) public fixedBytesStructMap;
|
||||||
|
|
||||||
|
// Mapping with address as keys and struct type values.
|
||||||
|
mapping(address => TestStruct) public addressStructMap;
|
||||||
|
|
||||||
// Set variable addressUintMap.
|
// Set variable addressUintMap.
|
||||||
function setAddressUintMap(uint value) external {
|
function setAddressUintMap(uint value) external {
|
||||||
addressUintMap[msg.sender] = value;
|
addressUintMap[msg.sender] = value;
|
||||||
@ -93,4 +96,9 @@ contract TestBasicMapping {
|
|||||||
function setFixedBytesStructMap(bytes32 key, TestStruct calldata value) external {
|
function setFixedBytesStructMap(bytes32 key, TestStruct calldata value) external {
|
||||||
fixedBytesStructMap[key] = value;
|
fixedBytesStructMap[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set variable fixedBytesStructMap.
|
||||||
|
function setAddressStructMap(address key, TestStruct calldata value) external {
|
||||||
|
addressStructMap[key] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
17
packages/solidity-mapper/test/contracts/TestNestedArrays.sol
Normal file
17
packages/solidity-mapper/test/contracts/TestNestedArrays.sol
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.7.6;
|
||||||
|
pragma abicoder v2;
|
||||||
|
|
||||||
|
contract TestNestedArrays {
|
||||||
|
struct TestStruct {
|
||||||
|
uint256 uint1;
|
||||||
|
address address1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestStruct[3][5] nestedStructArray;
|
||||||
|
|
||||||
|
// Set variable nestedStructArray.
|
||||||
|
function setNestedStructArray(uint index, uint nestedIndex, TestStruct calldata value) external {
|
||||||
|
nestedStructArray[index][nestedIndex] = value;
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@
|
|||||||
// "incremental": true, /* Enable incremental compilation */
|
// "incremental": true, /* Enable incremental compilation */
|
||||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
||||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
"lib": [ "ES2020" ], /* Specify library files to be included in the compilation. */
|
||||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||||
// "checkJs": true, /* Report errors in .js files. */
|
// "checkJs": true, /* Report errors in .js files. */
|
||||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
||||||
@ -21,7 +21,7 @@
|
|||||||
// "removeComments": true, /* Do not emit comments to output. */
|
// "removeComments": true, /* Do not emit comments to output. */
|
||||||
// "noEmit": true, /* Do not emit outputs. */
|
// "noEmit": true, /* Do not emit outputs. */
|
||||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
"downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||||
|
|
||||||
/* Strict Type-Checking Options */
|
/* Strict Type-Checking Options */
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
// "incremental": true, /* Enable incremental compilation */
|
// "incremental": true, /* Enable incremental compilation */
|
||||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
||||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||||
"lib": [ "ES5", "ES6" ], /* Specify library files to be included in the compilation. */
|
"lib": [ "ES5", "ES6", "ES2020" ], /* Specify library files to be included in the compilation. */
|
||||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||||
// "checkJs": true, /* Report errors in .js files. */
|
// "checkJs": true, /* Report errors in .js files. */
|
||||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
||||||
@ -21,7 +21,7 @@
|
|||||||
// "removeComments": true, /* Do not emit comments to output. */
|
// "removeComments": true, /* Do not emit comments to output. */
|
||||||
// "noEmit": true, /* Do not emit outputs. */
|
// "noEmit": true, /* Do not emit outputs. */
|
||||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
"downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||||
|
|
||||||
/* Strict Type-Checking Options */
|
/* Strict Type-Checking Options */
|
||||||
|
Loading…
Reference in New Issue
Block a user