2021-06-15 10:16:39 +00:00
|
|
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2021-06-02 05:53:33 +00:00
|
|
|
import { Contract } from '@ethersproject/contracts';
|
|
|
|
import { expect } from 'chai';
|
|
|
|
import { ethers } from 'hardhat';
|
|
|
|
import '@nomiclabs/hardhat-ethers';
|
2021-05-31 05:37:11 +00:00
|
|
|
|
2021-06-02 05:53:33 +00:00
|
|
|
import { getStorageInfo, getStorageValue, StorageLayout } from './storage';
|
|
|
|
import { getStorageLayout, getStorageAt } from '../test/utils';
|
2021-05-31 05:37:11 +00:00
|
|
|
|
2021-06-02 05:53:33 +00:00
|
|
|
const TEST_DATA = [
|
|
|
|
{
|
|
|
|
name: 'TestBooleans',
|
|
|
|
variable: 'bool1',
|
|
|
|
output: {
|
|
|
|
label: 'bool1',
|
|
|
|
offset: 0,
|
|
|
|
slot: '0x00',
|
|
|
|
type: 't_bool'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'TestIntegers',
|
|
|
|
variable: 'int2',
|
|
|
|
output: {
|
|
|
|
slot: '0x00',
|
|
|
|
offset: 1,
|
|
|
|
type: 't_int16',
|
|
|
|
label: 'int2'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'TestUnsignedIntegers',
|
|
|
|
variable: 'uint3',
|
|
|
|
output: {
|
|
|
|
label: 'uint3',
|
|
|
|
offset: 0,
|
|
|
|
slot: '0x01',
|
|
|
|
type: 't_uint256'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'TestAddress',
|
|
|
|
variable: 'address1',
|
|
|
|
output: {
|
|
|
|
label: 'address1',
|
|
|
|
offset: 0,
|
|
|
|
slot: '0x00',
|
|
|
|
type: 't_address'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'TestStrings',
|
|
|
|
variable: 'string2',
|
|
|
|
output: {
|
|
|
|
label: 'string2',
|
|
|
|
offset: 0,
|
|
|
|
slot: '0x01',
|
|
|
|
type: 't_string_storage'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
it('get storage information', async () => {
|
2021-06-02 05:53:33 +00:00
|
|
|
const testPromises = TEST_DATA.map(async ({ name, variable, output }) => {
|
|
|
|
const Contract = await ethers.getContractFactory(name);
|
|
|
|
const contract = await Contract.deploy();
|
|
|
|
await contract.deployed();
|
|
|
|
const storageLayout = await getStorageLayout(name);
|
|
|
|
|
|
|
|
const storageInfo = getStorageInfo(storageLayout, variable);
|
|
|
|
expect(storageInfo).to.include(output);
|
|
|
|
});
|
|
|
|
|
|
|
|
await Promise.all(testPromises);
|
|
|
|
});
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
describe('Get value from storage', () => {
|
2021-06-03 06:22:23 +00:00
|
|
|
const getBlockHash = async () => {
|
|
|
|
const blockNumber = await ethers.provider.getBlockNumber();
|
|
|
|
const { hash } = await ethers.provider.getBlock(blockNumber);
|
|
|
|
return hash;
|
|
|
|
};
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
it('get value for integer type variables packed together', async () => {
|
2021-06-02 05:53:33 +00:00
|
|
|
const Integers = await ethers.getContractFactory('TestIntegers');
|
2021-05-31 05:37:11 +00:00
|
|
|
const integers = await Integers.deploy();
|
|
|
|
await integers.deployed();
|
2021-06-02 05:53:33 +00:00
|
|
|
const storageLayout = await getStorageLayout('TestIntegers');
|
2021-05-31 05:37:11 +00:00
|
|
|
|
2021-06-03 06:22:23 +00:00
|
|
|
let expectedValue = 12;
|
|
|
|
await integers.setInt1(expectedValue);
|
|
|
|
let blockHash = await getBlockHash();
|
|
|
|
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, integers.address, 'int1');
|
2021-06-08 05:44:27 +00:00
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
2021-06-03 06:22:23 +00:00
|
|
|
|
|
|
|
expectedValue = 34;
|
|
|
|
await integers.setInt2(expectedValue);
|
|
|
|
blockHash = await getBlockHash();
|
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, integers.address, 'int2'));
|
2021-06-08 05:44:27 +00:00
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
2021-05-31 05:37:11 +00:00
|
|
|
});
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
it('get value for integer type variables using single slot', async () => {
|
2021-06-02 05:53:33 +00:00
|
|
|
const Integers = await ethers.getContractFactory('TestIntegers');
|
|
|
|
const integers = await Integers.deploy();
|
|
|
|
await integers.deployed();
|
|
|
|
const storageLayout = await getStorageLayout('TestIntegers');
|
|
|
|
|
2021-06-03 06:22:23 +00:00
|
|
|
const expectedValue = 123;
|
|
|
|
await integers.setInt3(expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, integers.address, 'int3');
|
2021-06-08 05:44:27 +00:00
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
2021-06-02 05:53:33 +00:00
|
|
|
});
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
it('get value for unsigned integer type variables packed together', async () => {
|
2021-06-02 05:53:33 +00:00
|
|
|
const UnsignedIntegers = await ethers.getContractFactory('TestUnsignedIntegers');
|
2021-05-31 05:37:11 +00:00
|
|
|
const unsignedIntegers = await UnsignedIntegers.deploy();
|
|
|
|
await unsignedIntegers.deployed();
|
2021-06-02 05:53:33 +00:00
|
|
|
const storageLayout = await getStorageLayout('TestUnsignedIntegers');
|
2021-05-31 05:37:11 +00:00
|
|
|
|
2021-06-03 06:22:23 +00:00
|
|
|
let expectedValue = 12;
|
|
|
|
await unsignedIntegers.setUint1(expectedValue);
|
|
|
|
let blockHash = await getBlockHash();
|
|
|
|
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, unsignedIntegers.address, 'uint1');
|
2021-06-08 05:44:27 +00:00
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
2021-06-03 06:22:23 +00:00
|
|
|
|
|
|
|
expectedValue = 34;
|
|
|
|
await unsignedIntegers.setUint2(expectedValue);
|
|
|
|
blockHash = await getBlockHash();
|
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, unsignedIntegers.address, 'uint2'));
|
2021-06-08 05:44:27 +00:00
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
2021-06-02 05:53:33 +00:00
|
|
|
});
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
it('get value for unsigned integer type variables using single slot', async () => {
|
2021-06-02 05:53:33 +00:00
|
|
|
const UnsignedIntegers = await ethers.getContractFactory('TestUnsignedIntegers');
|
|
|
|
const unsignedIntegers = await UnsignedIntegers.deploy();
|
|
|
|
await unsignedIntegers.deployed();
|
|
|
|
const storageLayout = await getStorageLayout('TestUnsignedIntegers');
|
|
|
|
|
2021-06-03 06:22:23 +00:00
|
|
|
const expectedValue = 123;
|
|
|
|
await unsignedIntegers.setUint3(expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, unsignedIntegers.address, 'uint3');
|
2021-06-08 05:44:27 +00:00
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
2021-05-31 05:37:11 +00:00
|
|
|
});
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
it('get value for boolean type', async () => {
|
2021-06-02 05:53:33 +00:00
|
|
|
const Booleans = await ethers.getContractFactory('TestBooleans');
|
2021-05-31 05:37:11 +00:00
|
|
|
const booleans = await Booleans.deploy();
|
|
|
|
await booleans.deployed();
|
2021-06-02 05:53:33 +00:00
|
|
|
const storageLayout = await getStorageLayout('TestBooleans');
|
2021-05-31 05:37:11 +00:00
|
|
|
|
2021-06-03 06:22:23 +00:00
|
|
|
let expectedValue = true;
|
|
|
|
await booleans.setBool1(expectedValue);
|
|
|
|
let blockHash = await getBlockHash();
|
|
|
|
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, booleans.address, 'bool1');
|
|
|
|
expect(value).to.equal(expectedValue);
|
|
|
|
|
|
|
|
expectedValue = false;
|
|
|
|
await booleans.setBool2(expectedValue);
|
|
|
|
blockHash = await getBlockHash();
|
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, booleans.address, 'bool2'));
|
|
|
|
expect(value).to.equal(expectedValue);
|
2021-05-31 05:37:11 +00:00
|
|
|
});
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
it('get value for address type', async () => {
|
2021-06-02 05:53:33 +00:00
|
|
|
const Address = await ethers.getContractFactory('TestAddress');
|
2021-05-31 05:37:11 +00:00
|
|
|
const address = await Address.deploy();
|
|
|
|
await address.deployed();
|
2021-06-02 05:53:33 +00:00
|
|
|
const storageLayout = await getStorageLayout('TestAddress');
|
2021-05-31 05:37:11 +00:00
|
|
|
|
2021-06-02 05:53:33 +00:00
|
|
|
const [signer] = await ethers.getSigners();
|
2021-05-31 05:37:11 +00:00
|
|
|
await address.setAddress1(signer.address);
|
2021-06-03 06:22:23 +00:00
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, address.address, 'address1');
|
|
|
|
expect(value).to.be.a('string');
|
|
|
|
expect(String(value).toLowerCase()).to.equal(signer.address.toLowerCase());
|
2021-05-31 05:37:11 +00:00
|
|
|
});
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
it('get value for contract type', async () => {
|
2021-06-02 05:53:33 +00:00
|
|
|
const contracts = ['TestContractTypes', 'TestAddress'];
|
|
|
|
|
|
|
|
const contractPromises = contracts.map(async (contractName) => {
|
|
|
|
const Contract = await ethers.getContractFactory(contractName);
|
|
|
|
const contract = await Contract.deploy();
|
|
|
|
return contract.deployed();
|
|
|
|
});
|
|
|
|
|
|
|
|
const [testContractTypes, testAddress] = await Promise.all(contractPromises);
|
|
|
|
const storageLayout = await getStorageLayout('TestContractTypes');
|
|
|
|
|
|
|
|
await testContractTypes.setAddressContract1(testAddress.address);
|
2021-06-03 06:22:23 +00:00
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testContractTypes.address, 'addressContract1');
|
|
|
|
expect(value).to.equal(testAddress.address.toLowerCase());
|
2021-06-02 05:53:33 +00:00
|
|
|
});
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
it('get value for fixed size byte arrays packed together', async () => {
|
2021-06-02 05:53:33 +00:00
|
|
|
const TestBytes = await ethers.getContractFactory('TestBytes');
|
|
|
|
const testBytes = await TestBytes.deploy();
|
|
|
|
await testBytes.deployed();
|
|
|
|
const storageLayout = await getStorageLayout('TestBytes');
|
|
|
|
|
2021-06-03 06:22:23 +00:00
|
|
|
let expectedValue = ethers.utils.hexlify(ethers.utils.randomBytes(10));
|
|
|
|
await testBytes.setBytesTen(expectedValue);
|
|
|
|
let blockHash = await getBlockHash();
|
|
|
|
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testBytes.address, 'bytesTen');
|
|
|
|
expect(value).to.equal(expectedValue);
|
|
|
|
|
|
|
|
expectedValue = ethers.utils.hexlify(ethers.utils.randomBytes(20));
|
|
|
|
await testBytes.setBytesTwenty(expectedValue);
|
|
|
|
blockHash = await getBlockHash();
|
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testBytes.address, 'bytesTwenty'));
|
|
|
|
expect(value).to.equal(expectedValue);
|
2021-06-02 05:53:33 +00:00
|
|
|
});
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
it('get value for fixed size byte arrays using single slot', async () => {
|
2021-06-02 05:53:33 +00:00
|
|
|
const TestBytes = await ethers.getContractFactory('TestBytes');
|
|
|
|
const testBytes = await TestBytes.deploy();
|
|
|
|
await testBytes.deployed();
|
|
|
|
const storageLayout = await getStorageLayout('TestBytes');
|
|
|
|
|
2021-06-03 06:22:23 +00:00
|
|
|
const expectedValue = ethers.utils.hexlify(ethers.utils.randomBytes(30));
|
|
|
|
await testBytes.setBytesThirty(expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testBytes.address, 'bytesThirty');
|
|
|
|
expect(value).to.equal(expectedValue);
|
2021-06-02 05:53:33 +00:00
|
|
|
});
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
it('get value for enum types', async () => {
|
2021-06-02 05:53:33 +00:00
|
|
|
const TestEnums = await ethers.getContractFactory('TestEnums');
|
|
|
|
const testEnums = await TestEnums.deploy();
|
|
|
|
await testEnums.deployed();
|
|
|
|
const storageLayout = await getStorageLayout('TestEnums');
|
|
|
|
|
2021-06-03 06:22:23 +00:00
|
|
|
const expectedValue = 1;
|
|
|
|
await testEnums.setChoicesEnum1(expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testEnums.address, 'choicesEnum1');
|
2021-06-08 05:44:27 +00:00
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
2021-06-02 05:53:33 +00:00
|
|
|
});
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
describe('string type', () => {
|
2021-05-31 05:37:11 +00:00
|
|
|
let strings: Contract, storageLayout: StorageLayout;
|
|
|
|
|
|
|
|
before(async () => {
|
2021-06-02 05:53:33 +00:00
|
|
|
const Strings = await ethers.getContractFactory('TestStrings');
|
2021-05-31 05:37:11 +00:00
|
|
|
strings = await Strings.deploy();
|
|
|
|
await strings.deployed();
|
2021-06-02 05:53:33 +00:00
|
|
|
storageLayout = await getStorageLayout('TestStrings');
|
|
|
|
});
|
2021-05-31 05:37:11 +00:00
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
// Test for string of size less than 32 bytes which use only one slot.
|
|
|
|
it('get value for string length less than 32 bytes', async () => {
|
2021-06-03 06:22:23 +00:00
|
|
|
const expectedValue = 'Hello world.';
|
|
|
|
await strings.setString1(expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, strings.address, 'string1');
|
|
|
|
expect(value).to.equal(expectedValue);
|
2021-05-31 05:37:11 +00:00
|
|
|
});
|
|
|
|
|
2021-06-03 09:33:39 +00:00
|
|
|
// Test for string of size 32 bytes or more which use multiple slots.
|
|
|
|
it('get value for string length more than 32 bytes', async () => {
|
2021-06-03 06:22:23 +00:00
|
|
|
const expectedValue = 'This sentence is more than 32 bytes long.';
|
|
|
|
await strings.setString2(expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, strings.address, 'string2');
|
|
|
|
expect(value).to.equal(expectedValue);
|
2021-05-31 05:37:11 +00:00
|
|
|
});
|
2021-06-02 05:53:33 +00:00
|
|
|
});
|
2021-06-03 09:33:39 +00:00
|
|
|
|
2021-06-11 05:46:02 +00:00
|
|
|
describe('fixed size arrays', () => {
|
|
|
|
let testFixedArrays: Contract, storageLayout: StorageLayout;
|
2021-06-11 09:22:03 +00:00
|
|
|
const int128Array = [100, 200, 300, 400, 500];
|
|
|
|
const uint16Array = [10, 20, 30, 40, 50];
|
|
|
|
const boolArray = [true, false];
|
|
|
|
let addressArray: string[] = [];
|
2021-06-03 09:33:39 +00:00
|
|
|
|
2021-06-11 05:46:02 +00:00
|
|
|
before(async () => {
|
|
|
|
const TestFixedArrays = await ethers.getContractFactory('TestFixedArrays');
|
|
|
|
testFixedArrays = await TestFixedArrays.deploy();
|
|
|
|
await testFixedArrays.deployed();
|
|
|
|
storageLayout = await getStorageLayout('TestFixedArrays');
|
2021-06-11 09:22:03 +00:00
|
|
|
|
|
|
|
const signers = await ethers.getSigners();
|
|
|
|
addressArray = signers.map(signer => signer.address.toLowerCase())
|
|
|
|
.slice(0, 4);
|
2021-06-11 05:46:02 +00:00
|
|
|
});
|
2021-06-03 09:33:39 +00:00
|
|
|
|
2021-06-11 09:22:03 +00:00
|
|
|
// Get all elements of array.
|
2021-06-11 05:46:02 +00:00
|
|
|
// Test for array variables which are 32 bytes or less and packed into a single slot.
|
|
|
|
it('get value for fixed size arrays using single slot', async () => {
|
2021-06-11 09:22:03 +00:00
|
|
|
await testFixedArrays.setBoolArray(boolArray);
|
2021-06-11 05:46:02 +00:00
|
|
|
let blockHash = await getBlockHash();
|
|
|
|
let { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'boolArray');
|
2021-06-11 09:22:03 +00:00
|
|
|
expect(value).to.eql(boolArray);
|
2021-06-11 05:46:02 +00:00
|
|
|
let proofData = JSON.parse(proof.data);
|
2021-06-11 09:22:03 +00:00
|
|
|
expect(proofData.length).to.equal(boolArray.length);
|
2021-06-11 05:46:02 +00:00
|
|
|
|
2021-06-11 09:22:03 +00:00
|
|
|
await testFixedArrays.setUint16Array(uint16Array);
|
2021-06-11 05:46:02 +00:00
|
|
|
blockHash = await getBlockHash();
|
|
|
|
({ value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'uint16Array'));
|
2021-06-11 09:22:03 +00:00
|
|
|
expect(value).to.eql(uint16Array.map(el => BigInt(el)));
|
2021-06-11 05:46:02 +00:00
|
|
|
proofData = JSON.parse(proof.data);
|
2021-06-11 09:22:03 +00:00
|
|
|
expect(proofData.length).to.equal(uint16Array.length);
|
2021-06-11 05:46:02 +00:00
|
|
|
});
|
2021-06-03 09:33:39 +00:00
|
|
|
|
2021-06-11 05:46:02 +00:00
|
|
|
// Test for array variables which are more than 32 bytes and use multiple slots.
|
|
|
|
it('get value for fixed size arrays using multiple slots', async () => {
|
2021-06-11 09:22:03 +00:00
|
|
|
await testFixedArrays.setInt128Array(int128Array);
|
2021-06-11 05:46:02 +00:00
|
|
|
let blockHash = await getBlockHash();
|
|
|
|
let { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'int128Array');
|
2021-06-11 09:22:03 +00:00
|
|
|
expect(value).to.eql(int128Array.map(el => BigInt(el)));
|
2021-06-11 05:46:02 +00:00
|
|
|
let proofData = JSON.parse(proof.data);
|
2021-06-11 09:22:03 +00:00
|
|
|
expect(proofData.length).to.equal(int128Array.length);
|
2021-06-11 05:46:02 +00:00
|
|
|
|
2021-06-11 09:22:03 +00:00
|
|
|
await testFixedArrays.setUintArray(uint16Array);
|
2021-06-11 05:46:02 +00:00
|
|
|
blockHash = await getBlockHash();
|
|
|
|
({ value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'uintArray'));
|
2021-06-11 09:22:03 +00:00
|
|
|
expect(value).to.eql(uint16Array.map(el => BigInt(el)));
|
2021-06-11 05:46:02 +00:00
|
|
|
proofData = JSON.parse(proof.data);
|
2021-06-11 09:22:03 +00:00
|
|
|
expect(proofData.length).to.equal(uint16Array.length);
|
2021-06-11 05:46:02 +00:00
|
|
|
});
|
2021-06-03 09:33:39 +00:00
|
|
|
|
2021-06-11 05:46:02 +00:00
|
|
|
it('get value for fixed size arrays of address type', async () => {
|
2021-06-11 09:22:03 +00:00
|
|
|
await testFixedArrays.setAddressArray(addressArray);
|
2021-06-11 05:46:02 +00:00
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'addressArray');
|
2021-06-11 09:22:03 +00:00
|
|
|
expect(value).to.eql(addressArray);
|
2021-06-11 05:46:02 +00:00
|
|
|
const proofData = JSON.parse(proof.data);
|
2021-06-11 09:22:03 +00:00
|
|
|
expect(proofData.length).to.equal(addressArray.length);
|
2021-06-11 05:46:02 +00:00
|
|
|
});
|
2021-06-03 09:33:39 +00:00
|
|
|
|
2021-06-11 05:46:02 +00:00
|
|
|
it.skip('get value for fixed size arrays of fixed size bytes type', async () => {
|
|
|
|
const expectedValue = Array.from({ length: 5 }, () => ethers.utils.hexlify(ethers.utils.randomBytes(10)));
|
2021-06-03 09:33:39 +00:00
|
|
|
|
2021-06-11 05:46:02 +00:00
|
|
|
await testFixedArrays.setBytesArray(expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'bytesArray');
|
|
|
|
expect(value).to.eql(expectedValue);
|
|
|
|
const proofData = JSON.parse(proof.data);
|
|
|
|
expect(proofData.length).to.equal(expectedValue.length);
|
|
|
|
});
|
2021-06-11 09:22:03 +00:00
|
|
|
|
2021-06-14 10:53:41 +00:00
|
|
|
it('get value for fixed size array of struct type', async () => {
|
|
|
|
const expectedValue = [];
|
|
|
|
|
|
|
|
for (let i = 0; i < 5; i++) {
|
|
|
|
const structElement = {
|
|
|
|
int1: BigInt(i + 1),
|
|
|
|
uint1: BigInt(i + 2),
|
|
|
|
bool1: Boolean(i % 2)
|
|
|
|
};
|
|
|
|
|
|
|
|
expectedValue[i] = structElement;
|
|
|
|
await testFixedArrays.setStructArray(structElement, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'structArray');
|
|
|
|
expect(value).to.eql(expectedValue);
|
|
|
|
const proofData = JSON.parse(proof.data);
|
|
|
|
expect(proofData.length).to.equal(expectedValue.length);
|
|
|
|
});
|
|
|
|
|
2021-06-11 09:22:03 +00:00
|
|
|
// Get element of array by index.
|
|
|
|
it('get value of signed integer type array by index', async () => {
|
|
|
|
const arrayIndex = 2;
|
|
|
|
await testFixedArrays.setInt128Array(int128Array);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'int128Array', arrayIndex);
|
|
|
|
expect(value).to.equal(BigInt(int128Array[arrayIndex]));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value of unsigned integer type array by index', async () => {
|
|
|
|
const arrayIndex = 3;
|
|
|
|
await testFixedArrays.setUint16Array(uint16Array);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'uint16Array', arrayIndex);
|
|
|
|
expect(value).to.equal(BigInt(uint16Array[arrayIndex]));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value of boolean type array by index', async () => {
|
|
|
|
const arrayIndex = 0;
|
|
|
|
await testFixedArrays.setBoolArray(boolArray);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'boolArray', arrayIndex);
|
|
|
|
expect(value).to.equal(boolArray[arrayIndex]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value of address type array by index', async () => {
|
|
|
|
const arrayIndex = 1;
|
|
|
|
await testFixedArrays.setAddressArray(addressArray);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'addressArray', arrayIndex);
|
|
|
|
expect(value).to.equal(addressArray[arrayIndex]);
|
|
|
|
});
|
2021-06-14 10:53:41 +00:00
|
|
|
|
|
|
|
it('get value of struct type array by index', async () => {
|
|
|
|
const expectedValue = {
|
|
|
|
int1: BigInt(123),
|
|
|
|
uint1: BigInt(456),
|
|
|
|
bool1: false
|
|
|
|
};
|
|
|
|
|
|
|
|
const arrayIndex = 2;
|
|
|
|
await testFixedArrays.setStructArray(expectedValue, arrayIndex);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'structArray', arrayIndex);
|
|
|
|
expect(value).to.eql(expectedValue);
|
|
|
|
|
|
|
|
// Get value of specified struct member in array element.
|
|
|
|
const structMember = 'uint1';
|
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'structArray', arrayIndex, structMember));
|
|
|
|
expect(value).to.eql(expectedValue[structMember]);
|
|
|
|
});
|
2021-06-03 09:33:39 +00:00
|
|
|
});
|
2021-06-09 04:48:19 +00:00
|
|
|
|
2021-06-15 10:16:39 +00:00
|
|
|
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]);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2021-06-14 10:42:42 +00:00
|
|
|
describe('structs with value type members', () => {
|
|
|
|
let testValueStructs: Contract, storageLayout: StorageLayout;
|
2021-06-11 10:27:09 +00:00
|
|
|
let addressStruct: { [key: string]: any }, contractStruct: { [key: string]: any };
|
|
|
|
|
2021-06-14 10:53:41 +00:00
|
|
|
const singleSlotStruct = {
|
|
|
|
int1: BigInt(123),
|
|
|
|
uint1: BigInt(4)
|
|
|
|
};
|
|
|
|
|
|
|
|
const multipleSlotStruct: { [key: string]: any } = {
|
2021-06-11 10:27:09 +00:00
|
|
|
uint1: BigInt(123),
|
|
|
|
bool1: false,
|
|
|
|
int1: BigInt(456)
|
|
|
|
};
|
|
|
|
|
|
|
|
const fixedBytesStruct = {
|
|
|
|
uint1: BigInt(123),
|
|
|
|
bytesTen: ethers.utils.hexlify(ethers.utils.randomBytes(10)),
|
|
|
|
bytesTwenty: ethers.utils.hexlify(ethers.utils.randomBytes(20))
|
|
|
|
};
|
|
|
|
|
|
|
|
const enumStruct = {
|
|
|
|
uint1: BigInt(123),
|
|
|
|
choice1: BigInt(2),
|
|
|
|
choice2: BigInt(3)
|
|
|
|
};
|
2021-06-11 05:49:20 +00:00
|
|
|
|
|
|
|
before(async () => {
|
2021-06-14 10:42:42 +00:00
|
|
|
const TestValueStructs = await ethers.getContractFactory('TestValueStructs');
|
|
|
|
testValueStructs = await TestValueStructs.deploy();
|
|
|
|
await testValueStructs.deployed();
|
|
|
|
storageLayout = await getStorageLayout('TestValueStructs');
|
2021-06-11 10:27:09 +00:00
|
|
|
|
|
|
|
const [signer1, signer2] = await ethers.getSigners();
|
|
|
|
|
|
|
|
addressStruct = {
|
|
|
|
int1: BigInt(123),
|
|
|
|
address1: signer1.address.toLowerCase(),
|
|
|
|
address2: signer2.address.toLowerCase(),
|
|
|
|
uint1: BigInt(456)
|
|
|
|
};
|
|
|
|
|
|
|
|
const Contract = await ethers.getContractFactory('TestContractTypes');
|
|
|
|
const contract = await Contract.deploy();
|
|
|
|
await contract.deployed();
|
|
|
|
|
|
|
|
contractStruct = {
|
|
|
|
uint1: BigInt(123),
|
|
|
|
testContract: contract.address.toLowerCase()
|
|
|
|
};
|
2021-06-11 05:49:20 +00:00
|
|
|
});
|
|
|
|
|
2021-06-11 10:27:09 +00:00
|
|
|
// Get all members of a struct.
|
2021-06-11 05:49:20 +00:00
|
|
|
it('get value for struct using a single slot', async () => {
|
2021-06-14 10:53:41 +00:00
|
|
|
await testValueStructs.setSingleSlotStruct(singleSlotStruct.int1, singleSlotStruct.uint1);
|
2021-06-11 05:49:20 +00:00
|
|
|
const blockHash = await getBlockHash();
|
2021-06-14 10:42:42 +00:00
|
|
|
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'singleSlotStruct');
|
2021-06-14 10:53:41 +00:00
|
|
|
expect(value).to.eql(singleSlotStruct);
|
2021-06-11 05:49:20 +00:00
|
|
|
const proofData = JSON.parse(proof.data);
|
|
|
|
expect(proofData).to.have.all.keys('int1', 'uint1');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for struct using multiple slots', async () => {
|
2021-06-14 10:42:42 +00:00
|
|
|
await testValueStructs.setMultipleSlotStruct(multipleSlotStruct.uint1, multipleSlotStruct.bool1, multipleSlotStruct.int1);
|
2021-06-11 05:49:20 +00:00
|
|
|
const blockHash = await getBlockHash();
|
2021-06-14 10:42:42 +00:00
|
|
|
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'multipleSlotStruct');
|
2021-06-11 10:27:09 +00:00
|
|
|
expect(value).to.eql(multipleSlotStruct);
|
2021-06-11 05:49:20 +00:00
|
|
|
const proofData = JSON.parse(proof.data);
|
2021-06-11 10:27:09 +00:00
|
|
|
expect(proofData).to.have.all.keys(Object.keys(multipleSlotStruct));
|
2021-06-11 05:49:20 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for struct with address type members', async () => {
|
2021-06-14 10:53:41 +00:00
|
|
|
await testValueStructs.setAddressStruct(addressStruct);
|
2021-06-11 05:49:20 +00:00
|
|
|
const blockHash = await getBlockHash();
|
2021-06-14 10:42:42 +00:00
|
|
|
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'addressStruct');
|
2021-06-11 10:27:09 +00:00
|
|
|
expect(value).to.eql(addressStruct);
|
2021-06-11 05:49:20 +00:00
|
|
|
const proofData = JSON.parse(proof.data);
|
2021-06-11 10:27:09 +00:00
|
|
|
expect(proofData).to.have.all.keys(Object.keys(addressStruct));
|
2021-06-11 05:49:20 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for struct with contract type members', async () => {
|
2021-06-14 10:42:42 +00:00
|
|
|
await testValueStructs.setContractStruct(contractStruct.uint1, contractStruct.testContract);
|
2021-06-11 05:49:20 +00:00
|
|
|
const blockHash = await getBlockHash();
|
2021-06-14 10:42:42 +00:00
|
|
|
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'contractStruct');
|
2021-06-11 10:27:09 +00:00
|
|
|
expect(value).to.eql(contractStruct);
|
2021-06-11 05:49:20 +00:00
|
|
|
const proofData = JSON.parse(proof.data);
|
2021-06-11 10:27:09 +00:00
|
|
|
expect(proofData).to.have.all.keys(Object.keys(contractStruct));
|
2021-06-11 05:49:20 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for struct with fixed-sized byte array members', async () => {
|
2021-06-14 10:42:42 +00:00
|
|
|
await testValueStructs.setFixedBytesStruct(fixedBytesStruct.uint1, fixedBytesStruct.bytesTen, fixedBytesStruct.bytesTwenty);
|
2021-06-11 05:49:20 +00:00
|
|
|
const blockHash = await getBlockHash();
|
2021-06-14 10:42:42 +00:00
|
|
|
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'fixedBytesStruct');
|
2021-06-11 10:27:09 +00:00
|
|
|
expect(value).to.eql(fixedBytesStruct);
|
2021-06-11 05:49:20 +00:00
|
|
|
const proofData = JSON.parse(proof.data);
|
|
|
|
expect(proofData).to.have.all.keys('uint1', 'bytesTen', 'bytesTwenty');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for struct with enum type members', async () => {
|
2021-06-14 10:42:42 +00:00
|
|
|
await testValueStructs.setEnumStruct(enumStruct.uint1, enumStruct.choice1, enumStruct.choice2);
|
2021-06-11 05:49:20 +00:00
|
|
|
const blockHash = await getBlockHash();
|
2021-06-14 10:42:42 +00:00
|
|
|
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'enumStruct');
|
2021-06-11 10:27:09 +00:00
|
|
|
expect(value).to.eql(enumStruct);
|
2021-06-11 05:49:20 +00:00
|
|
|
const proofData = JSON.parse(proof.data);
|
|
|
|
expect(proofData).to.have.all.keys('uint1', 'choice1', 'choice2');
|
|
|
|
});
|
2021-06-11 10:27:09 +00:00
|
|
|
|
|
|
|
// Get value of a member in a struct
|
|
|
|
it('get value of signed integer type member in a struct', async () => {
|
|
|
|
const member = 'int1';
|
2021-06-14 10:53:41 +00:00
|
|
|
await testValueStructs.setSingleSlotStruct(singleSlotStruct.int1, singleSlotStruct.uint1);
|
2021-06-11 10:27:09 +00:00
|
|
|
const blockHash = await getBlockHash();
|
2021-06-14 10:53:41 +00:00
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'singleSlotStruct', member);
|
|
|
|
expect(value).to.equal(singleSlotStruct[member]);
|
2021-06-11 10:27:09 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('get value of unsigned integer type member in a struct', async () => {
|
|
|
|
const member = 'uint1';
|
|
|
|
const blockHash = await getBlockHash();
|
2021-06-14 10:53:41 +00:00
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'singleSlotStruct', member);
|
|
|
|
expect(value).to.equal(singleSlotStruct[member]);
|
2021-06-11 10:27:09 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('get value of boolean type member in a struct', async () => {
|
2021-06-14 10:53:41 +00:00
|
|
|
await testValueStructs.setMultipleSlotStruct(multipleSlotStruct.uint1, multipleSlotStruct.bool1, multipleSlotStruct.int1);
|
2021-06-11 10:27:09 +00:00
|
|
|
const blockHash = await getBlockHash();
|
2021-06-14 10:53:41 +00:00
|
|
|
|
|
|
|
let member = 'bool1';
|
|
|
|
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'multipleSlotStruct', member);
|
|
|
|
expect(value).to.equal(multipleSlotStruct[member]);
|
|
|
|
|
|
|
|
member = 'int1';
|
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'multipleSlotStruct', member));
|
|
|
|
expect(value).to.equal(multipleSlotStruct[member]);
|
|
|
|
|
|
|
|
member = 'uint1';
|
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'multipleSlotStruct', member));
|
2021-06-11 10:27:09 +00:00
|
|
|
expect(value).to.equal(multipleSlotStruct[member]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value of address type member in a struct', async () => {
|
2021-06-14 10:53:41 +00:00
|
|
|
await testValueStructs.setAddressStruct(addressStruct);
|
2021-06-11 10:27:09 +00:00
|
|
|
const blockHash = await getBlockHash();
|
2021-06-14 10:53:41 +00:00
|
|
|
let member = 'address1';
|
|
|
|
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'addressStruct', member);
|
|
|
|
expect(value).to.equal(addressStruct[member]);
|
|
|
|
|
|
|
|
member = 'uint1';
|
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'addressStruct', member));
|
2021-06-11 10:27:09 +00:00
|
|
|
expect(value).to.equal(addressStruct[member]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value of contract type member in a struct', async () => {
|
|
|
|
const member = 'testContract';
|
2021-06-14 10:42:42 +00:00
|
|
|
await testValueStructs.setContractStruct(contractStruct.uint1, contractStruct.testContract);
|
2021-06-11 10:27:09 +00:00
|
|
|
const blockHash = await getBlockHash();
|
2021-06-14 10:42:42 +00:00
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'contractStruct', member);
|
2021-06-11 10:27:09 +00:00
|
|
|
expect(value).to.equal(contractStruct[member]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value of fixed byte array member in a struct', async () => {
|
|
|
|
const member = 'bytesTen';
|
2021-06-14 10:42:42 +00:00
|
|
|
await testValueStructs.setFixedBytesStruct(fixedBytesStruct.uint1, fixedBytesStruct.bytesTen, fixedBytesStruct.bytesTwenty);
|
2021-06-11 10:27:09 +00:00
|
|
|
const blockHash = await getBlockHash();
|
2021-06-14 10:42:42 +00:00
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'fixedBytesStruct', member);
|
2021-06-11 10:27:09 +00:00
|
|
|
expect(value).to.equal(fixedBytesStruct[member]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value of enum type member in a struct', async () => {
|
|
|
|
const member = 'choice2';
|
2021-06-14 10:42:42 +00:00
|
|
|
await testValueStructs.setEnumStruct(enumStruct.uint1, enumStruct.choice1, enumStruct.choice2);
|
2021-06-11 10:27:09 +00:00
|
|
|
const blockHash = await getBlockHash();
|
2021-06-14 10:42:42 +00:00
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'enumStruct', member);
|
2021-06-11 10:27:09 +00:00
|
|
|
expect(value).to.equal(enumStruct[member]);
|
|
|
|
});
|
2021-06-11 05:49:20 +00:00
|
|
|
});
|
|
|
|
|
2021-06-14 10:42:42 +00:00
|
|
|
describe('structs with reference type members', () => {
|
|
|
|
let testReferenceStructs: Contract, storageLayout: StorageLayout;
|
|
|
|
|
2021-06-14 14:27:29 +00:00
|
|
|
let fixedArrayStruct: {[key: string]: any},
|
|
|
|
bytesStruct: {[key: string]: any},
|
|
|
|
stringStruct: {[key: string]: any},
|
|
|
|
nestedStruct: {[key: string]: any};
|
2021-06-14 10:42:42 +00:00
|
|
|
|
|
|
|
before(async () => {
|
|
|
|
const TestReferenceStructs = await ethers.getContractFactory('TestReferenceStructs');
|
|
|
|
testReferenceStructs = await TestReferenceStructs.deploy();
|
|
|
|
await testReferenceStructs.deployed();
|
|
|
|
storageLayout = await getStorageLayout('TestReferenceStructs');
|
|
|
|
|
|
|
|
const signers = await ethers.getSigners();
|
|
|
|
|
|
|
|
fixedArrayStruct = {
|
|
|
|
int1: BigInt(123),
|
|
|
|
uintArray: [1, 2, 3, 4].map(el => BigInt(el)),
|
|
|
|
addressArray: signers.slice(0, 3).map(signer => signer.address.toLowerCase())
|
|
|
|
};
|
2021-06-14 14:27:29 +00:00
|
|
|
|
|
|
|
bytesStruct = {
|
|
|
|
byteArray: ethers.utils.hexlify(ethers.utils.randomBytes(40)),
|
|
|
|
address1: signers[1].address.toLowerCase(),
|
|
|
|
uint1: BigInt(1234)
|
|
|
|
};
|
|
|
|
|
|
|
|
stringStruct = {
|
|
|
|
string1: 'string1',
|
|
|
|
int1: BigInt(123),
|
|
|
|
uint1: BigInt(456),
|
|
|
|
string2: 'string2',
|
|
|
|
address1: signers[2].address.toLowerCase(),
|
|
|
|
bool1: false
|
|
|
|
};
|
|
|
|
|
|
|
|
nestedStruct = {
|
|
|
|
bytesStruct,
|
|
|
|
address1: signers[3].address.toLowerCase()
|
|
|
|
};
|
2021-06-14 10:42:42 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// Get all members of a struct.
|
|
|
|
it('get value for struct with fixed-size array members', async () => {
|
|
|
|
await testReferenceStructs.setFixedArrayStruct(fixedArrayStruct.int1, fixedArrayStruct.uintArray, fixedArrayStruct.addressArray);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'fixedArrayStruct');
|
|
|
|
expect(value).to.eql(fixedArrayStruct);
|
|
|
|
});
|
|
|
|
|
2021-06-14 14:27:29 +00:00
|
|
|
it('get value for struct with dynamically sized byte members', async () => {
|
|
|
|
await testReferenceStructs.setBytesStruct(bytesStruct);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'bytesStruct');
|
|
|
|
expect(value).to.eql(bytesStruct);
|
|
|
|
});
|
|
|
|
|
2021-06-14 10:42:42 +00:00
|
|
|
it('get value for struct with string type members', async () => {
|
2021-06-14 14:27:29 +00:00
|
|
|
await testReferenceStructs.setStringStruct(stringStruct);
|
2021-06-14 10:42:42 +00:00
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'stringStruct');
|
|
|
|
expect(value).to.eql(stringStruct);
|
|
|
|
});
|
|
|
|
|
2021-06-14 14:27:29 +00:00
|
|
|
it('get value for nested struct with struct type members', async () => {
|
|
|
|
await testReferenceStructs.setNestedStruct(nestedStruct);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'nestedStruct');
|
|
|
|
expect(value).to.eql(nestedStruct);
|
|
|
|
});
|
|
|
|
|
2021-06-14 10:42:42 +00:00
|
|
|
// Get value of a member in a struct
|
|
|
|
it('get value of fixed-size array member in a struct', async () => {
|
|
|
|
const member = 'uintArray';
|
|
|
|
await testReferenceStructs.setFixedArrayStruct(fixedArrayStruct.int1, fixedArrayStruct.uintArray, fixedArrayStruct.addressArray);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'fixedArrayStruct', member);
|
|
|
|
expect(value).to.eql(fixedArrayStruct[member]);
|
|
|
|
});
|
|
|
|
|
2021-06-14 14:27:29 +00:00
|
|
|
it('get value of bytes member in a struct', async () => {
|
|
|
|
const member = 'byteArray';
|
|
|
|
await testReferenceStructs.setBytesStruct(bytesStruct);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'bytesStruct', member);
|
|
|
|
expect(value).to.equal(bytesStruct[member]);
|
|
|
|
});
|
|
|
|
|
2021-06-14 10:42:42 +00:00
|
|
|
it('get value of string member in a struct', async () => {
|
|
|
|
const member = 'string2';
|
2021-06-14 14:27:29 +00:00
|
|
|
await testReferenceStructs.setStringStruct(stringStruct);
|
2021-06-14 10:42:42 +00:00
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'stringStruct', member);
|
|
|
|
expect(value).to.eql(stringStruct[member]);
|
|
|
|
});
|
|
|
|
|
2021-06-15 10:16:39 +00:00
|
|
|
it('get value of mapping type member in a struct', async () => {
|
2021-06-14 10:42:42 +00:00
|
|
|
const [signer1, signer2] = await ethers.getSigners();
|
|
|
|
|
|
|
|
const valueMappingStruct: { [key: string]: any } = {
|
|
|
|
uintAddressMap: new Map(),
|
|
|
|
uint1: 123,
|
|
|
|
addressIntMap: new Map()
|
|
|
|
};
|
|
|
|
|
|
|
|
const mappingKey = 456;
|
|
|
|
valueMappingStruct.uintAddressMap.set(mappingKey, signer1.address.toLowerCase());
|
|
|
|
valueMappingStruct.addressIntMap.set(signer2.address, 789);
|
|
|
|
let member = 'uintAddressMap';
|
|
|
|
|
|
|
|
await testReferenceStructs.setValueMappingStruct(mappingKey, valueMappingStruct.uintAddressMap.get(mappingKey), valueMappingStruct.uint1, signer2.address, valueMappingStruct.addressIntMap.get(signer2.address));
|
|
|
|
let blockHash = await getBlockHash();
|
|
|
|
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'valueMappingStruct', member, mappingKey);
|
|
|
|
expect(value).to.equal(valueMappingStruct[member].get(mappingKey));
|
|
|
|
|
2021-06-15 10:16:39 +00:00
|
|
|
// Get value for structs with mapping of reference type keys.
|
2021-06-14 10:42:42 +00:00
|
|
|
const referenceMappingStruct: { [key: string]: any } = {
|
|
|
|
bytesAddressMap: new Map(),
|
|
|
|
stringUintMap: new Map()
|
|
|
|
};
|
|
|
|
|
|
|
|
const bytesKey = ethers.utils.hexlify(ethers.utils.randomBytes(40));
|
|
|
|
const stringKey = 'abc';
|
|
|
|
referenceMappingStruct.bytesAddressMap.set(bytesKey, signer1.address.toLowerCase());
|
2021-06-15 10:16:39 +00:00
|
|
|
referenceMappingStruct.stringUintMap.set(stringKey, BigInt(123));
|
|
|
|
member = 'stringUintMap';
|
2021-06-14 10:42:42 +00:00
|
|
|
|
|
|
|
await testReferenceStructs.setReferenceMappingStruct(bytesKey, referenceMappingStruct.bytesAddressMap.get(bytesKey), stringKey, referenceMappingStruct.stringUintMap.get(stringKey));
|
|
|
|
blockHash = await getBlockHash();
|
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'referenceMappingStruct', member, stringKey));
|
|
|
|
expect(value).to.equal(referenceMappingStruct[member].get(stringKey));
|
|
|
|
});
|
2021-06-14 14:27:29 +00:00
|
|
|
|
|
|
|
it('get value of nested struct member', async () => {
|
|
|
|
await testReferenceStructs.setNestedStruct(nestedStruct);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const member = 'bytesStruct';
|
|
|
|
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'nestedStruct', member);
|
|
|
|
expect(value).to.eql(nestedStruct[member]);
|
|
|
|
|
|
|
|
// Get value inside the nested struct member.
|
|
|
|
let nestedMember = 'address1';
|
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'nestedStruct', member, nestedMember));
|
|
|
|
expect(value).to.eql(nestedStruct[member][nestedMember]);
|
|
|
|
|
|
|
|
nestedMember = 'byteArray';
|
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'nestedStruct', member, nestedMember));
|
|
|
|
expect(value).to.eql(nestedStruct[member][nestedMember]);
|
|
|
|
});
|
2021-06-14 10:42:42 +00:00
|
|
|
});
|
|
|
|
|
2021-06-10 05:52:03 +00:00
|
|
|
describe('basic mapping type', () => {
|
2021-06-09 04:48:19 +00:00
|
|
|
let testMappingTypes: Contract, storageLayout: StorageLayout;
|
|
|
|
|
|
|
|
before(async () => {
|
2021-06-10 05:52:03 +00:00
|
|
|
const TestMappingTypes = await ethers.getContractFactory('TestBasicMapping');
|
2021-06-09 04:48:19 +00:00
|
|
|
testMappingTypes = await TestMappingTypes.deploy();
|
|
|
|
await testMappingTypes.deployed();
|
2021-06-10 05:52:03 +00:00
|
|
|
storageLayout = await getStorageLayout('TestBasicMapping');
|
2021-06-09 04:48:19 +00:00
|
|
|
});
|
|
|
|
|
2021-06-14 10:53:41 +00:00
|
|
|
// Tests for value type keys.
|
2021-06-10 05:52:03 +00:00
|
|
|
it('get value for mapping with address type keys', async () => {
|
2021-06-09 04:48:19 +00:00
|
|
|
const expectedValue = 123;
|
|
|
|
const [, signer1] = await ethers.getSigners();
|
|
|
|
await testMappingTypes.connect(signer1).setAddressUintMap(expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'addressUintMap', signer1.address);
|
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
|
|
|
});
|
|
|
|
|
2021-06-10 05:52:03 +00:00
|
|
|
it('get value for mapping with boolean type keys', async () => {
|
|
|
|
const expectedValue = 123;
|
|
|
|
const mapKey = true;
|
|
|
|
await testMappingTypes.setBoolIntMap(mapKey, expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'boolIntMap', mapKey);
|
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for mapping with signed integer type keys', async () => {
|
|
|
|
const mapKey = 123;
|
|
|
|
const [, signer1] = await ethers.getSigners();
|
|
|
|
await testMappingTypes.setIntAddressMap(mapKey, signer1.address);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'intAddressMap', mapKey);
|
|
|
|
expect(value).to.equal(signer1.address.toLowerCase());
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for mapping with unsigned integer type keys', async () => {
|
|
|
|
const expectedValue = ethers.utils.hexlify(ethers.utils.randomBytes(16));
|
|
|
|
const mapKey = 123;
|
|
|
|
await testMappingTypes.setUintBytesMap(mapKey, expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'uintBytesMap', mapKey);
|
|
|
|
expect(value).to.equal(expectedValue);
|
|
|
|
});
|
|
|
|
|
|
|
|
it.skip('get value for mapping with fixed-size byte array keys', async () => {
|
|
|
|
const mapKey = ethers.utils.hexlify(ethers.utils.randomBytes(8));
|
|
|
|
const [, signer1] = await ethers.getSigners();
|
|
|
|
await testMappingTypes.setBytesAddressMap(mapKey, signer1.address);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'bytesAddressMap', mapKey);
|
|
|
|
expect(value).to.equal(signer1.address);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for mapping with enum type keys', async () => {
|
|
|
|
const mapKey = 1;
|
|
|
|
const expectedValue = 123;
|
|
|
|
await testMappingTypes.setEnumIntMap(mapKey, expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'enumIntMap', mapKey);
|
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
|
|
|
});
|
|
|
|
|
2021-06-14 10:53:41 +00:00
|
|
|
// Tests for reference type keys.
|
2021-06-10 05:52:03 +00:00
|
|
|
it('get value for mapping with string type keys', async () => {
|
|
|
|
const mapKey = 'abc';
|
|
|
|
const expectedValue = 123;
|
|
|
|
await testMappingTypes.setStringIntMap(mapKey, expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'stringIntMap', mapKey);
|
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for mapping with dynamically-sized byte array as keys', async () => {
|
|
|
|
const mapKey = ethers.utils.hexlify(ethers.utils.randomBytes(64));
|
|
|
|
const expectedValue = 123;
|
|
|
|
await testMappingTypes.setBytesUintMap(mapKey, expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'bytesUintMap', mapKey);
|
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
|
|
|
});
|
2021-06-14 10:53:41 +00:00
|
|
|
|
|
|
|
// Tests for reference type values.
|
|
|
|
it('get value for mapping with struct type values', async () => {
|
2021-06-14 14:27:29 +00:00
|
|
|
const [signer1] = await ethers.getSigners();
|
|
|
|
|
|
|
|
const expectedValue: {[key: string]: any} = {
|
2021-06-14 10:53:41 +00:00
|
|
|
uint1: BigInt(123),
|
|
|
|
int1: BigInt(456),
|
2021-06-14 14:27:29 +00:00
|
|
|
bool1: true,
|
|
|
|
address1: signer1.address.toLowerCase()
|
2021-06-14 10:53:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const mapKey = 123;
|
|
|
|
await testMappingTypes.setIntStructMap(mapKey, expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'intStructMap', mapKey);
|
|
|
|
expect(value).to.eql(expectedValue);
|
|
|
|
|
|
|
|
// Get value of specified struct member in mapping.
|
2021-06-14 14:27:29 +00:00
|
|
|
let structMember = 'bool1';
|
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'intStructMap', mapKey, structMember));
|
|
|
|
expect(value).to.equal(expectedValue[structMember]);
|
|
|
|
|
|
|
|
structMember = 'address1';
|
2021-06-14 10:53:41 +00:00
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'intStructMap', mapKey, structMember));
|
|
|
|
expect(value).to.equal(expectedValue[structMember]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for mapping of fixed size bytes keys and struct type values', async () => {
|
2021-06-14 14:27:29 +00:00
|
|
|
const [signer1] = await ethers.getSigners();
|
|
|
|
|
2021-06-14 10:53:41 +00:00
|
|
|
const expectedValue = {
|
|
|
|
uint1: BigInt(123),
|
|
|
|
int1: BigInt(456),
|
2021-06-14 14:27:29 +00:00
|
|
|
bool1: true,
|
|
|
|
address1: signer1.address.toLowerCase()
|
2021-06-14 10:53:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const mapKey = ethers.utils.hexlify(ethers.utils.randomBytes(32));
|
|
|
|
await testMappingTypes.setFixedBytesStructMap(mapKey, expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'fixedBytesStructMap', mapKey);
|
|
|
|
expect(value).to.eql(expectedValue);
|
|
|
|
|
|
|
|
// Get value of specified struct member in mapping.
|
|
|
|
const structMember = 'int1';
|
|
|
|
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'fixedBytesStructMap', mapKey, structMember));
|
|
|
|
expect(value).to.equal(expectedValue[structMember]);
|
|
|
|
});
|
2021-06-15 10:16:39 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
});
|
2021-06-10 05:52:03 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
describe('nested mapping type', () => {
|
|
|
|
let testNestedMapping: Contract, storageLayout: StorageLayout;
|
|
|
|
|
|
|
|
before(async () => {
|
|
|
|
const TestNestedMapping = await ethers.getContractFactory('TestNestedMapping');
|
|
|
|
testNestedMapping = await TestNestedMapping.deploy();
|
|
|
|
await testNestedMapping.deployed();
|
|
|
|
storageLayout = await getStorageLayout('TestNestedMapping');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for nested mapping with address type keys', async () => {
|
2021-06-09 04:48:19 +00:00
|
|
|
const expectedValue = 123;
|
|
|
|
const [, signer1, signer2] = await ethers.getSigners();
|
2021-06-10 05:52:03 +00:00
|
|
|
await testNestedMapping.connect(signer1).setNestedAddressUintMap(signer2.address, expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testNestedMapping.address, 'nestedAddressUintMap', signer1.address, signer2.address);
|
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for nested mapping with signed integer type keys', async () => {
|
|
|
|
const expectedValue = false;
|
|
|
|
const key = 123;
|
|
|
|
const [, signer1] = await ethers.getSigners();
|
|
|
|
await testNestedMapping.setIntAddressBoolMap(key, signer1.address, expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testNestedMapping.address, 'intAddressBoolMap', key, signer1.address);
|
|
|
|
expect(value).to.equal(expectedValue);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for nested mapping with unsigned integer type keys', async () => {
|
|
|
|
const expectedValue = 123;
|
|
|
|
const key = 456;
|
|
|
|
const nestedKey = 'abc';
|
|
|
|
await testNestedMapping.setUintStringIntMap(key, nestedKey, expectedValue);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testNestedMapping.address, 'uintStringIntMap', key, nestedKey);
|
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for nested mapping with dynamically-sized byte array as keys', async () => {
|
|
|
|
const key = ethers.utils.hexlify(ethers.utils.randomBytes(64));
|
|
|
|
const nestedKey = 123;
|
|
|
|
const [, signer1] = await ethers.getSigners();
|
|
|
|
await testNestedMapping.setBytesIntAddressMap(key, nestedKey, signer1.address);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testNestedMapping.address, 'bytesIntAddressMap', key, nestedKey);
|
|
|
|
expect(value).to.equal(signer1.address.toLowerCase());
|
|
|
|
});
|
|
|
|
|
|
|
|
it('get value for nested mapping with string type keys', async () => {
|
|
|
|
const key = 'abc';
|
|
|
|
const expectedValue = 123;
|
|
|
|
const [, signer1] = await ethers.getSigners();
|
|
|
|
await testNestedMapping.setStringAddressIntMap(key, signer1.address, expectedValue);
|
2021-06-09 04:48:19 +00:00
|
|
|
const blockHash = await getBlockHash();
|
2021-06-10 05:52:03 +00:00
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testNestedMapping.address, 'stringAddressIntMap', key, signer1.address);
|
2021-06-09 04:48:19 +00:00
|
|
|
expect(value).to.equal(BigInt(expectedValue));
|
|
|
|
});
|
2021-06-14 10:53:41 +00:00
|
|
|
|
|
|
|
it('get value for double nested mapping with address type keys', async () => {
|
|
|
|
const [signer1, signer2, signer3] = await ethers.getSigners();
|
|
|
|
const uintKey = 123;
|
|
|
|
await testNestedMapping.setDoubleNestedAddressMap(signer1.address, signer2.address, uintKey, signer3.address);
|
|
|
|
const blockHash = await getBlockHash();
|
|
|
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testNestedMapping.address, 'doubleNestedAddressMap', signer1.address, signer2.address, uintKey);
|
|
|
|
expect(value).to.equal(signer3.address.toLowerCase());
|
|
|
|
});
|
2021-06-09 04:48:19 +00:00
|
|
|
});
|
2021-05-31 05:37:11 +00:00
|
|
|
});
|