mirror of
https://github.com/cerc-io/watcher-ts
synced 2025-01-08 12:28:05 +00:00
Get slot for ERC20 variable from storage layout (#13)
* Get slot for ERC20 variable from storage layout. * Fix solidity-mapper build for importing library functions. * Implement lint command in solidity-mapper package. Co-authored-by: nikugogoi <95nikass@gmail.com>
This commit is contained in:
parent
72ca980198
commit
a0aae09f83
5
packages/solidity-mapper/.eslintignore
Normal file
5
packages/solidity-mapper/.eslintignore
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Don't lint node_modules.
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Don't lint build output.
|
||||||
|
dist
|
20
packages/solidity-mapper/.eslintrc.json
Normal file
20
packages/solidity-mapper/.eslintrc.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es2021": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"semistandard",
|
||||||
|
"plugin:@typescript-eslint/recommended"
|
||||||
|
],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 12,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"@typescript-eslint"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
}
|
||||||
|
}
|
@ -17,17 +17,17 @@ $ yarn test
|
|||||||
|
|
||||||
## Different Types
|
## Different Types
|
||||||
|
|
||||||
* Booleans
|
* [x] Booleans
|
||||||
* Integers
|
* [x] Integers
|
||||||
* Fixed Point Numbers
|
* [ ] Fixed Point Numbers
|
||||||
* Address
|
* [x] Address
|
||||||
* Contract Types
|
* [ ] Contract Types
|
||||||
* Fixed-size byte arrays
|
* [ ] Fixed-size byte arrays
|
||||||
* Enums
|
* [ ] Enums
|
||||||
* Function Types
|
* [ ] Function Types
|
||||||
* Arrays
|
* [ ] Arrays
|
||||||
* Structs
|
* [ ] Structs
|
||||||
* Mapping Types
|
* [ ] Mapping Types
|
||||||
|
|
||||||
## Observations
|
## Observations
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@vulcanize/solidity-mapper",
|
"name": "@vulcanize/solidity-mapper",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"main": "dist/index.js",
|
"main": "src/index.ts",
|
||||||
"types": "dist/index.d.ts",
|
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||||
@ -10,7 +9,16 @@
|
|||||||
"@types/chai": "^4.2.18",
|
"@types/chai": "^4.2.18",
|
||||||
"@types/mocha": "^8.2.2",
|
"@types/mocha": "^8.2.2",
|
||||||
"@types/node": "^15.6.1",
|
"@types/node": "^15.6.1",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^4.25.0",
|
||||||
|
"@typescript-eslint/parser": "^4.25.0",
|
||||||
"chai": "^4.3.4",
|
"chai": "^4.3.4",
|
||||||
|
"eslint": "^7.27.0",
|
||||||
|
"eslint-config-semistandard": "^15.0.1",
|
||||||
|
"eslint-config-standard": "^16.0.3",
|
||||||
|
"eslint-plugin-import": "^2.23.3",
|
||||||
|
"eslint-plugin-node": "^11.1.0",
|
||||||
|
"eslint-plugin-promise": "^5.1.0",
|
||||||
|
"eslint-plugin-standard": "^5.0.0",
|
||||||
"ethereum-waffle": "^3.3.0",
|
"ethereum-waffle": "^3.3.0",
|
||||||
"ethers": "^5.2.0",
|
"ethers": "^5.2.0",
|
||||||
"hardhat": "^2.3.0",
|
"hardhat": "^2.3.0",
|
||||||
@ -19,6 +27,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"test": "hardhat test"
|
"test": "hardhat test",
|
||||||
|
"lint": "eslint ."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
export { getStorageValue, StorageLayout, GetStorageAt } from './storage';
|
export { getStorageValue, getStorageInfo, StorageLayout, GetStorageAt } from './storage';
|
||||||
|
@ -1,23 +1,50 @@
|
|||||||
import { utils, BigNumber } from 'ethers';
|
import { utils, BigNumber } from 'ethers';
|
||||||
|
|
||||||
export interface StorageLayout {
|
interface Storage {
|
||||||
storage: [{
|
|
||||||
slot: string;
|
slot: string;
|
||||||
offset: number;
|
offset: number;
|
||||||
type: string;
|
type: string;
|
||||||
label: string;
|
label: string;
|
||||||
}];
|
}
|
||||||
types: {
|
|
||||||
[type: string]: {
|
interface Type {
|
||||||
encoding: string;
|
encoding: string;
|
||||||
numberOfBytes: string;
|
numberOfBytes: string;
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
export interface StorageLayout {
|
||||||
|
storage: Storage[];
|
||||||
|
types: { [type: string]: Type; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StorageInfo extends Storage {
|
||||||
|
types: { [type: string]: Type; }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetStorageAt = (address: string, position: string) => Promise<string>
|
export type GetStorageAt = (address: string, position: string) => Promise<string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to get storage information of variable from storage layout.
|
||||||
|
* @param storageLayout
|
||||||
|
* @param variableName
|
||||||
|
*/
|
||||||
|
export const getStorageInfo = (storageLayout: StorageLayout, variableName: string): StorageInfo => {
|
||||||
|
const { storage, types } = storageLayout;
|
||||||
|
const targetState = storage.find((state) => state.label === variableName)
|
||||||
|
|
||||||
|
// Throw if state variable could not be found in storage layout.
|
||||||
|
if (!targetState) {
|
||||||
|
throw new Error('Variable not present in storage layout.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...targetState,
|
||||||
|
slot: utils.hexlify(BigNumber.from(targetState.slot)),
|
||||||
|
types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to get the value from storage for a contract variable.
|
* Function to get the value from storage for a contract variable.
|
||||||
* @param address
|
* @param address
|
||||||
@ -26,15 +53,7 @@ export type GetStorageAt = (address: string, position: string) => Promise<string
|
|||||||
* @param variableName
|
* @param variableName
|
||||||
*/
|
*/
|
||||||
export const getStorageValue = async (address: string, storageLayout: StorageLayout, getStorageAt: GetStorageAt, variableName: string): Promise<number | string | boolean | undefined> => {
|
export const getStorageValue = async (address: string, storageLayout: StorageLayout, getStorageAt: GetStorageAt, variableName: string): Promise<number | string | boolean | undefined> => {
|
||||||
const { storage, types } = storageLayout;
|
const { slot, offset, type, types } = getStorageInfo(storageLayout, variableName);
|
||||||
const targetState = storage.find((state) => state.label === variableName)
|
|
||||||
|
|
||||||
// Return if state variable could not be found in storage layout.
|
|
||||||
if (!targetState) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { slot, offset, type } = targetState;
|
|
||||||
const { encoding, numberOfBytes, label } = types[type]
|
const { encoding, numberOfBytes, label } = types[type]
|
||||||
|
|
||||||
// Get value according to encoding i.e. how the data is encoded in storage.
|
// Get value according to encoding i.e. how the data is encoded in storage.
|
||||||
@ -79,7 +98,7 @@ export const getStorageValue = async (address: string, storageLayout: StorageLay
|
|||||||
* @param getStorageAt
|
* @param getStorageAt
|
||||||
*/
|
*/
|
||||||
const getInplaceArray = async (address: string, slot: string, offset: number, numberOfBytes: string, getStorageAt: GetStorageAt) => {
|
const getInplaceArray = async (address: string, slot: string, offset: number, numberOfBytes: string, getStorageAt: GetStorageAt) => {
|
||||||
const value = await getStorageAt(address, BigNumber.from(slot).toHexString());
|
const value = await getStorageAt(address, slot);
|
||||||
const uintArray = utils.arrayify(value);
|
const uintArray = utils.arrayify(value);
|
||||||
|
|
||||||
// Get value according to offset.
|
// Get value according to offset.
|
||||||
@ -97,7 +116,7 @@ const getInplaceArray = async (address: string, slot: string, offset: number, nu
|
|||||||
* @param getStorageAt
|
* @param getStorageAt
|
||||||
*/
|
*/
|
||||||
const getBytesArray = async (address: string, slot: string, getStorageAt: GetStorageAt) => {
|
const getBytesArray = async (address: string, slot: string, getStorageAt: GetStorageAt) => {
|
||||||
let value = await getStorageAt(address, BigNumber.from(slot).toHexString());
|
let value = await getStorageAt(address, slot);
|
||||||
const uintArray = utils.arrayify(value);
|
const uintArray = utils.arrayify(value);
|
||||||
let length = 0;
|
let length = 0;
|
||||||
|
|
||||||
@ -122,8 +141,8 @@ const getBytesArray = async (address: string, slot: string, getStorageAt: GetSto
|
|||||||
|
|
||||||
// Compute zero padded hexstring to calculate hashed position of storage.
|
// Compute zero padded hexstring to calculate hashed position of storage.
|
||||||
// https://github.com/ethers-io/ethers.js/issues/1079#issuecomment-703056242
|
// https://github.com/ethers-io/ethers.js/issues/1079#issuecomment-703056242
|
||||||
const slotHex = utils.hexZeroPad(BigNumber.from(slot).toHexString(), 32);
|
const paddedSlotHex = utils.hexZeroPad(slot, 32);
|
||||||
const position = utils.keccak256(slotHex);
|
const position = utils.keccak256(paddedSlotHex);
|
||||||
|
|
||||||
// Get value from consecutive storage slots for longer data.
|
// Get value from consecutive storage slots for longer data.
|
||||||
for(let i = 0; i < length / 32; i++) {
|
for(let i = 0; i < length / 32; i++) {
|
||||||
|
@ -70,5 +70,5 @@
|
|||||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
||||||
},
|
},
|
||||||
"include": ["src/**/*"],
|
"include": ["src/**/*"],
|
||||||
"exclude": ["node_modules"],
|
"exclude": ["src/**/*.test.ts"]
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"@types/lodash": "^4.14.168",
|
"@types/lodash": "^4.14.168",
|
||||||
"@vulcanize/cache": "^0.1.0",
|
"@vulcanize/cache": "^0.1.0",
|
||||||
"@vulcanize/ipld-eth-client": "^0.1.0",
|
"@vulcanize/ipld-eth-client": "^0.1.0",
|
||||||
|
"@vulcanize/solidity-mapper": "^0.1.0",
|
||||||
"apollo-type-bigint": "^0.1.3",
|
"apollo-type-bigint": "^0.1.3",
|
||||||
"canonical-json": "^0.0.4",
|
"canonical-json": "^0.0.4",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
|
365
packages/watcher/src/artifacts/ERC20.json
Normal file
365
packages/watcher/src/artifacts/ERC20.json
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
{
|
||||||
|
"abi": [
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "string",
|
||||||
|
"name": "name_",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "string",
|
||||||
|
"name": "symbol_",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "constructor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "spender",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Approval",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "from",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Transfer",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "spender",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "allowance",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "spender",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "approve",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bool",
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "account",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "balanceOf",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "decimals",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint8",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "spender",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "subtractedValue",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "decreaseAllowance",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bool",
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "spender",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "addedValue",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "increaseAllowance",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bool",
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "name",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "string",
|
||||||
|
"name": "",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "symbol",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "string",
|
||||||
|
"name": "",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "totalSupply",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "recipient",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "transfer",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bool",
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "sender",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "recipient",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "transferFrom",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bool",
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageLayout": {
|
||||||
|
"storage": [
|
||||||
|
{
|
||||||
|
"astId": 15,
|
||||||
|
"contract": "@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20",
|
||||||
|
"label": "_balances",
|
||||||
|
"offset": 0,
|
||||||
|
"slot": "0",
|
||||||
|
"type": "t_mapping(t_address,t_uint256)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"astId": 21,
|
||||||
|
"contract": "@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20",
|
||||||
|
"label": "_allowances",
|
||||||
|
"offset": 0,
|
||||||
|
"slot": "1",
|
||||||
|
"type": "t_mapping(t_address,t_mapping(t_address,t_uint256))"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"astId": 23,
|
||||||
|
"contract": "@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20",
|
||||||
|
"label": "_totalSupply",
|
||||||
|
"offset": 0,
|
||||||
|
"slot": "2",
|
||||||
|
"type": "t_uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"astId": 25,
|
||||||
|
"contract": "@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20",
|
||||||
|
"label": "_name",
|
||||||
|
"offset": 0,
|
||||||
|
"slot": "3",
|
||||||
|
"type": "t_string_storage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"astId": 27,
|
||||||
|
"contract": "@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20",
|
||||||
|
"label": "_symbol",
|
||||||
|
"offset": 0,
|
||||||
|
"slot": "4",
|
||||||
|
"type": "t_string_storage"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"types": {
|
||||||
|
"t_address": {
|
||||||
|
"encoding": "inplace",
|
||||||
|
"label": "address",
|
||||||
|
"numberOfBytes": "20"
|
||||||
|
},
|
||||||
|
"t_mapping(t_address,t_mapping(t_address,t_uint256))": {
|
||||||
|
"encoding": "mapping",
|
||||||
|
"key": "t_address",
|
||||||
|
"label": "mapping(address => mapping(address => uint256))",
|
||||||
|
"numberOfBytes": "32",
|
||||||
|
"value": "t_mapping(t_address,t_uint256)"
|
||||||
|
},
|
||||||
|
"t_mapping(t_address,t_uint256)": {
|
||||||
|
"encoding": "mapping",
|
||||||
|
"key": "t_address",
|
||||||
|
"label": "mapping(address => uint256)",
|
||||||
|
"numberOfBytes": "32",
|
||||||
|
"value": "t_uint256"
|
||||||
|
},
|
||||||
|
"t_string_storage": {
|
||||||
|
"encoding": "bytes",
|
||||||
|
"label": "string",
|
||||||
|
"numberOfBytes": "32"
|
||||||
|
},
|
||||||
|
"t_uint256": {
|
||||||
|
"encoding": "inplace",
|
||||||
|
"label": "uint256",
|
||||||
|
"numberOfBytes": "32"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,11 +4,9 @@ import debug from 'debug';
|
|||||||
|
|
||||||
import { getCache } from '@vulcanize/cache';
|
import { getCache } from '@vulcanize/cache';
|
||||||
import { EthClient, getMappingSlot, topictoAddress } from '@vulcanize/ipld-eth-client';
|
import { EthClient, getMappingSlot, topictoAddress } from '@vulcanize/ipld-eth-client';
|
||||||
|
import { getStorageInfo } from '@vulcanize/solidity-mapper';
|
||||||
|
|
||||||
// Event slots.
|
import { storageLayout } from './artifacts/ERC20.json';
|
||||||
// TODO: Read from storage layout file.
|
|
||||||
const ERC20_BALANCE_OF_SLOT = "0x00";
|
|
||||||
const ERC20_ALLOWANCE_SLOT = "0x01";
|
|
||||||
|
|
||||||
// Event signatures.
|
// Event signatures.
|
||||||
// TODO: Generate from ABI.
|
// TODO: Generate from ABI.
|
||||||
@ -55,7 +53,8 @@ export const createResolvers = async (config) => {
|
|||||||
balanceOf: async (_, { blockHash, token, owner }) => {
|
balanceOf: async (_, { blockHash, token, owner }) => {
|
||||||
log('balanceOf', blockHash, token, owner);
|
log('balanceOf', blockHash, token, owner);
|
||||||
|
|
||||||
const slot = getMappingSlot(ERC20_BALANCE_OF_SLOT, owner);
|
const { slot: balancesSlot } = getStorageInfo(storageLayout, '_balances')
|
||||||
|
const slot = getMappingSlot(balancesSlot, owner);
|
||||||
|
|
||||||
const vars = {
|
const vars = {
|
||||||
blockHash,
|
blockHash,
|
||||||
@ -89,7 +88,8 @@ export const createResolvers = async (config) => {
|
|||||||
allowance: async (_, { blockHash, token, owner, spender }) => {
|
allowance: async (_, { blockHash, token, owner, spender }) => {
|
||||||
log('allowance', blockHash, token, owner, spender);
|
log('allowance', blockHash, token, owner, spender);
|
||||||
|
|
||||||
const slot = getMappingSlot(getMappingSlot(ERC20_ALLOWANCE_SLOT, owner), spender);
|
const { slot: allowancesSlot } = getStorageInfo(storageLayout, '_allowances')
|
||||||
|
const slot = getMappingSlot(getMappingSlot(allowancesSlot, owner), spender);
|
||||||
|
|
||||||
const vars = {
|
const vars = {
|
||||||
blockHash,
|
blockHash,
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
|
|
||||||
/* Advanced Options */
|
/* Advanced Options */
|
||||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
||||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
|
||||||
|
"resolveJsonModule": true /* Enabling the option allows importing JSON, and validating the types in that JSON file. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user