From a5b3c7942d4cb432876bebb8ba075c0c6bcd5fd0 Mon Sep 17 00:00:00 2001 From: prathamesh0 <42446521+prathamesh0@users.noreply.github.com> Date: Fri, 19 Aug 2022 11:06:11 +0530 Subject: [PATCH] Add test package (#164) * Add test package * Add a separate command to perform an eth-call * Add snapshot test suite * Add eth-calls for UniswapV2 Pair, USDC, Compound, Dai contracts * Add args for Uniswap and USDC contracts * Add args for Compound and Dai contracts * Add getStorageAt calls to the test suite * Refactor code and add documentation * Loop over test slots for getStorageAt calls * Add support for individual calls * Use debug for logging --- packages/test/.eslintignore | 5 + packages/test/.eslintrc.json | 23 + packages/test/.mocharc.yml | 4 + packages/test/README.md | 76 +++ packages/test/abis/Comp.json | 1 + packages/test/abis/Dai.json | 1 + packages/test/abis/FiatTokenV2_1.json | 1 + packages/test/abis/UniswapV2Factory.json | 1 + packages/test/abis/UniswapV2Pair.json | 1 + packages/test/environments/local.toml | 5 + packages/test/package.json | 32 + packages/test/src/common.ts | 46 ++ packages/test/src/eth-call.ts | 70 +++ packages/test/src/get-storage-at.ts | 53 ++ packages/test/src/snapshot.test.ts | 741 +++++++++++++++++++++++ packages/test/src/test-data.ts | 25 + packages/test/tsconfig.json | 104 ++++ 17 files changed, 1189 insertions(+) create mode 100644 packages/test/.eslintignore create mode 100644 packages/test/.eslintrc.json create mode 100644 packages/test/.mocharc.yml create mode 100644 packages/test/README.md create mode 100644 packages/test/abis/Comp.json create mode 100644 packages/test/abis/Dai.json create mode 100644 packages/test/abis/FiatTokenV2_1.json create mode 100644 packages/test/abis/UniswapV2Factory.json create mode 100644 packages/test/abis/UniswapV2Pair.json create mode 100644 packages/test/environments/local.toml create mode 100644 packages/test/package.json create mode 100644 packages/test/src/common.ts create mode 100644 packages/test/src/eth-call.ts create mode 100644 packages/test/src/get-storage-at.ts create mode 100644 packages/test/src/snapshot.test.ts create mode 100644 packages/test/src/test-data.ts create mode 100644 packages/test/tsconfig.json diff --git a/packages/test/.eslintignore b/packages/test/.eslintignore new file mode 100644 index 00000000..653874b5 --- /dev/null +++ b/packages/test/.eslintignore @@ -0,0 +1,5 @@ +# Don't lint node_modules. +node_modules + +# Don't lint build output. +dist diff --git a/packages/test/.eslintrc.json b/packages/test/.eslintrc.json new file mode 100644 index 00000000..746934f0 --- /dev/null +++ b/packages/test/.eslintrc.json @@ -0,0 +1,23 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "overrides": [ + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "@typescript-eslint/no-explicit-any": "off" + } +} diff --git a/packages/test/.mocharc.yml b/packages/test/.mocharc.yml new file mode 100644 index 00000000..bfcbf2c4 --- /dev/null +++ b/packages/test/.mocharc.yml @@ -0,0 +1,4 @@ +timeout: '0' # No timeout since RPC calls may take longer +bail: true +exit: true +require: 'ts-node/register' diff --git a/packages/test/README.md b/packages/test/README.md new file mode 100644 index 00000000..74d67367 --- /dev/null +++ b/packages/test/README.md @@ -0,0 +1,76 @@ +# test + +## Setup + +* Run the following command to install required packages: + + ```bash + yarn + ``` + +## Test Snapshot + +* The snapshot test suite compares results for eth-calls and `getStorageAt` calls to the provided endpoints. + +* Contracts considered: + * UniswapV2 Factory + * UniswapV2 Pair + * USDC + * Compound + * Dai / Maker + +* Edit the [config file](./environments/local.toml): + + Eg: + + ```toml + blockTag = "0xB5FFFF" # block tag to perform eth-call and getStorageAt call with (eg. block number in hex) + + [endpoints] + endpoint1 = "http://127.0.0.1:8545" # endpoint1 URL + endpoint2 = "http://127.0.0.1:8082" # endpoint2 URL + ``` + +* Run the following command to run the snapshot test suite: + + ```bash + yarn test:snapshot + ``` + +## Individual Calls + +* Run the following to make an eth-call: + + ```bash + yarn eth-call -e -c -a -m --method-args [method-args] -b [block-tag] + ``` + + * `endpoint` (`e`): Endpoint to perform eth-call against + * `contract` (`c`): Contract address + * `abi` (`a`): Contract ABI path + * `method-name` (`m`): Contract method to call + * `method-args`: Contract method arguments + * `block-tag` (`b`): Block tag to make eth-call with (block number (hex) / block hash) + + Eg. + + ```bash + yarn eth-call -e http://127.0.0.1:8545 -c 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f -a abis/UniswapV2Factory.json -m allPairs --method-args 100 -b 0xB5FFFF + ``` + +* Run the following to make a `getStorageAt` call: + + ```bash + yarn get-storage-at -e -c -s -b [block-tag] + ``` + + * `endpoint` (`e`): Endpoint to perform getStorageAt call against + * `contract` (`c`): Contract address + * `slot` (`s`): Storge slot + * `block-tag` (`b`): Block tag to make getStorageAt call with (block number (hex) / block hash) + + Eg. + + ```bash + yarn get-storage-at -e http://127.0.0.1:8545 -c 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f -s 0x1 -b 0xB5FFFF + ``` diff --git a/packages/test/abis/Comp.json b/packages/test/abis/Comp.json new file mode 100644 index 00000000..fdea1589 --- /dev/null +++ b/packages/test/abis/Comp.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"account","type":"address"}],"payable":false,"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":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"DelegateVotesChanged","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":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[],"name":"DELEGATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"rawAmount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"}],"name":"checkpoints","outputs":[{"internalType":"uint32","name":"fromBlock","type":"uint32"},{"internalType":"uint96","name":"votes","type":"uint96"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getCurrentVotes","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getPriorVotes","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"rawAmount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"rawAmount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}] diff --git a/packages/test/abis/Dai.json b/packages/test/abis/Dai.json new file mode 100644 index 00000000..3cdd67f0 --- /dev/null +++ b/packages/test/abis/Dai.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"uint256","name":"chainId_","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"guy","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":true,"inputs":[{"indexed":true,"internalType":"bytes4","name":"sig","type":"bytes4"},{"indexed":true,"internalType":"address","name":"usr","type":"address"},{"indexed":true,"internalType":"bytes32","name":"arg1","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"arg2","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"LogNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"guy","type":"address"}],"name":"deny","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"mint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"move","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"bool","name":"allowed","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"pull","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"push","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"guy","type":"address"}],"name":"rely","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}] diff --git a/packages/test/abis/FiatTokenV2_1.json b/packages/test/abis/FiatTokenV2_1.json new file mode 100644 index 00000000..a306ec83 --- /dev/null +++ b/packages/test/abis/FiatTokenV2_1.json @@ -0,0 +1 @@ +[{"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":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationUsed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_account","type":"address"}],"name":"Blacklisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newBlacklister","type":"address"}],"name":"BlacklisterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"burner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newMasterMinter","type":"address"}],"name":"MasterMinterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"minterAllowedAmount","type":"uint256"}],"name":"MinterConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldMinter","type":"address"}],"name":"MinterRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"PauserChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newRescuer","type":"address"}],"name":"RescuerChanged","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_account","type":"address"}],"name":"UnBlacklisted","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"},{"inputs":[],"name":"CANCEL_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RECEIVE_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"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":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer","type":"address"},{"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"authorizationState","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"blacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"blacklister","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer","type":"address"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"cancelAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"minterAllowedAmount","type":"uint256"}],"name":"configureMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currency","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"decrement","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"increment","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"string","name":"tokenCurrency","type":"string"},{"internalType":"uint8","name":"tokenDecimals","type":"uint8"},{"internalType":"address","name":"newMasterMinter","type":"address"},{"internalType":"address","name":"newPauser","type":"address"},{"internalType":"address","name":"newBlacklister","type":"address"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newName","type":"string"}],"name":"initializeV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lostAndFound","type":"address"}],"name":"initializeV2_1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"masterMinter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"minterAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"receiveWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"removeMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenContract","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rescuer","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"transferWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"unBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newBlacklister","type":"address"}],"name":"updateBlacklister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newMasterMinter","type":"address"}],"name":"updateMasterMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newPauser","type":"address"}],"name":"updatePauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRescuer","type":"address"}],"name":"updateRescuer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}] diff --git a/packages/test/abis/UniswapV2Factory.json b/packages/test/abis/UniswapV2Factory.json new file mode 100644 index 00000000..f6ba56aa --- /dev/null +++ b/packages/test/abis/UniswapV2Factory.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"PairCreated","type":"event"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allPairs","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allPairsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"createPair","outputs":[{"internalType":"address","name":"pair","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"feeToSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeTo","type":"address"}],"name":"setFeeTo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"name":"setFeeToSetter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}] diff --git a/packages/test/abis/UniswapV2Pair.json b/packages/test/abis/UniswapV2Pair.json new file mode 100644 index 00000000..6a6ef031 --- /dev/null +++ b/packages/test/abis/UniswapV2Pair.json @@ -0,0 +1 @@ +[{"inputs":[],"payable":false,"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":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0Out","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1Out","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint112","name":"reserve0","type":"uint112"},{"indexed":false,"internalType":"uint112","name":"reserve1","type":"uint112"}],"name":"Sync","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"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"burn","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint112","name":"_reserve0","type":"uint112"},{"internalType":"uint112","name":"_reserve1","type":"uint112"},{"internalType":"uint32","name":"_blockTimestampLast","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token0","type":"address"},{"internalType":"address","name":"_token1","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"kLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"price0CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"price1CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"skim","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount0Out","type":"uint256"},{"internalType":"uint256","name":"amount1Out","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"sync","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}] diff --git a/packages/test/environments/local.toml b/packages/test/environments/local.toml new file mode 100644 index 00000000..e005d67b --- /dev/null +++ b/packages/test/environments/local.toml @@ -0,0 +1,5 @@ +blockTag = "" # block tag to perform eth-call and getStorageAt call with (eg. block number in hex) + +[endpoints] + endpoint1 = "" # endpoint1 URL + endpoint2 = "" # endpoint2 URL diff --git a/packages/test/package.json b/packages/test/package.json new file mode 100644 index 00000000..a7af6f6b --- /dev/null +++ b/packages/test/package.json @@ -0,0 +1,32 @@ +{ + "name": "@vulcanize/test", + "version": "0.1.0", + "main": "dist/index.js", + "license": "AGPL-3.0", + "scripts": { + "lint": "eslint .", + "build": "tsc", + "eth-call": "DEBUG=vulcanize:* ts-node src/eth-call.ts", + "get-storage-at": "DEBUG=vulcanize:* ts-node src/get-storage-at.ts", + "test:snapshot": "DEBUG=vulcanize:* mocha src/snapshot.test.ts" + }, + "dependencies": { + "chai": "^4.3.4", + "ethers": "^5.4.4", + "fs-extra": "^10.0.0", + "lodash": "^4.17.21", + "mocha": "^8.4.0", + "toml": "^3.0.0", + "debug": "^4.3.1", + "yargs": "^17.0.1" + }, + "devDependencies": { + "@types/chai": "^4.2.19", + "@types/mocha": "^8.2.2", + "@typescript-eslint/eslint-plugin": "^4.25.0", + "@typescript-eslint/parser": "^4.25.0", + "eslint": "^7.27.0", + "ts-node": "^10.0.0", + "typescript": "^4.3.2" + } +} diff --git a/packages/test/src/common.ts b/packages/test/src/common.ts new file mode 100644 index 00000000..7c314ae1 --- /dev/null +++ b/packages/test/src/common.ts @@ -0,0 +1,46 @@ +// +// Copyright 2022 Vulcanize, Inc. +// + +import fs from 'fs-extra'; +import path from 'path'; +import assert from 'assert'; +import toml from 'toml'; + +export interface Config { + endpoint1URL: string, + endpoint2URL: string, + blockTag: string +} + +export const getConfig = async (configFile: string): Promise => { + const configFilePath = path.resolve(configFile); + const fileExists = await fs.pathExists(configFilePath); + if (!fileExists) { + throw new Error(`Config file not found: ${configFilePath}`); + } + + const configString = await fs.readFile(configFilePath, 'utf8'); + const config = toml.parse(configString); + + const { endpoints: endpointConfig, blockTag } = config; + assert(endpointConfig, 'Missing endpoints config'); + + const {endpoint1: endpoint1URL, endpoint2: endpoint2URL} = endpointConfig; + assert(endpoint1URL, 'Missing endpoint1 URL'); + assert(endpoint2URL, 'Missing endpoint2 URL'); + + assert(blockTag); + + return { + endpoint1URL, + endpoint2URL, + blockTag + }; +} + +export const readAbi = (abiPath: string): any => { + const fullAbiPath = path.resolve(abiPath); + + return JSON.parse(fs.readFileSync(fullAbiPath).toString()); +} diff --git a/packages/test/src/eth-call.ts b/packages/test/src/eth-call.ts new file mode 100644 index 00000000..b8783338 --- /dev/null +++ b/packages/test/src/eth-call.ts @@ -0,0 +1,70 @@ +// +// Copyright 2022 Vulcanize, Inc. +// + +import yargs from 'yargs'; +import { ethers, providers } from 'ethers'; +import debug from 'debug'; + +import { readAbi } from './common'; + +const log = debug('vulcanize:test'); + +const main = async (): Promise => { + const argv = await yargs.parserConfiguration({ + 'parse-numbers': false + }).options({ + endpoint: { + alias: 'e', + demandOption: true, + describe: 'Endpoint to perform eth-call against', + type: 'string' + }, + contract: { + alias: 'c', + demandOption: true, + describe: 'Contract address', + type: 'string' + }, + abi: { + alias: 'a', + demandOption: true, + describe: 'Contract ABI path', + type: 'string' + }, + methodName: { + alias: 'm', + demandOption: true, + describe: 'Contract method to call', + type: 'string' + }, + methodArgs: { + describe: 'Contract method arguments', + type: 'array' + }, + blockTag: { + alias: 'b', + describe: 'Block tag to make eth-call with (block number (hex) / block hash)', + type: 'string' + } + }).argv; + + const abi = readAbi(argv.abi); + const provider = new providers.JsonRpcProvider(argv.endpoint); + const contract = new ethers.Contract(argv.contract, abi, provider); + + let args: (string | number)[] = [] + if(argv.methodArgs !== undefined) { + args = argv.methodArgs + } + + log(`Making an eth-call (${argv.methodName}) to endpoint ${argv.endpoint}`); + const result = await contract[argv.methodName](...args, {blockTag: argv.blockTag}); + + log("Result:"); + log(result); +} + +main().catch(err => { + log(err); +}); diff --git a/packages/test/src/get-storage-at.ts b/packages/test/src/get-storage-at.ts new file mode 100644 index 00000000..0a4dcdea --- /dev/null +++ b/packages/test/src/get-storage-at.ts @@ -0,0 +1,53 @@ +// +// Copyright 2022 Vulcanize, Inc. +// + +import yargs from 'yargs'; +import { ethers, providers } from 'ethers'; +import debug from 'debug'; + +import { readAbi } from './common'; + +const log = debug('vulcanize:test'); + +const main = async (): Promise => { + const argv = await yargs.parserConfiguration({ + 'parse-numbers': false + }).options({ + endpoint: { + alias: 'e', + demandOption: true, + describe: 'Endpoint to perform getStorageAt against', + type: 'string' + }, + contract: { + alias: 'c', + demandOption: true, + describe: 'Contract address', + type: 'string' + }, + slot: { + alias: 's', + demandOption: true, + describe: 'Storge slot', + type: 'string' + }, + blockTag: { + alias: 'b', + describe: 'Block tag to make eth-call with (block number (hex) / block hash)', + type: 'string' + }, + }).argv; + + const provider = new providers.JsonRpcProvider(argv.endpoint); + + log(`Making a getStorageAt call for slot ${argv.slot} to endpoint ${argv.endpoint}`); + const result = await provider.getStorageAt(argv.contract, argv.slot, argv.blockTag); + + log("Result:"); + log(result); +} + +main().catch(err => { + log(err); +}); diff --git a/packages/test/src/snapshot.test.ts b/packages/test/src/snapshot.test.ts new file mode 100644 index 00000000..b8daf473 --- /dev/null +++ b/packages/test/src/snapshot.test.ts @@ -0,0 +1,741 @@ +// +// Copyright 2022 Vulcanize, Inc. +// + +import { expect } from 'chai'; +import { providers, Contract } from 'ethers'; +import 'mocha'; + +import { Config, getConfig } from './common'; +import { + uniswapV2FactoryABI, + uniswapV2FactoryAddress, + uniswapV2PairABI, + uniswapV2PairAddress, + usdcABI, + usdcAddress, + compoundABI, + compoundAddress, + daiABI, + daiAddress +} from './test-data'; + +const DEFAULT_CONFIG_FILE = './environments/local.toml'; + +describe('snapshot-test', () => { + let config: Config; + + let provider1: providers.JsonRpcProvider; + let provider2: providers.JsonRpcProvider; + + before("initialize providers", async () => { + config = await getConfig(DEFAULT_CONFIG_FILE); + + provider1 = new providers.JsonRpcProvider(config.endpoint1URL); + provider2 = new providers.JsonRpcProvider(config.endpoint2URL); + }); + + // Compare eth-call results + describe('match results for eth-calls', async () => { + let contract1: Contract; + let contract2: Contract; + + describe('match results for eth-calls to UniswapV2 Factory', async () => { + before("initialize contracts", async () => { + contract1 = new Contract(uniswapV2FactoryAddress, uniswapV2FactoryABI, provider1); + contract2 = new Contract(uniswapV2FactoryAddress, uniswapV2FactoryABI, provider2); + }); + + it('should match results for allPairs', async () => { + const args = [100] + + const result1 = await contract1.allPairs(...args, {blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.allPairs(...args, {blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for allPairsLength', async () => { + const result1 = await contract1.allPairsLength({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.allPairsLength({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for feeTo', async () => { + const result1 = await contract1.feeTo({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.feeTo({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for feeToSetter', async () => { + const result1 = await contract1.feeToSetter({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.feeToSetter({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for getPair', async () => { + const args = ["0x8e870d67f660d95d5be530380d0ec0bd388289e1", "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"] + + const result1 = await contract1.getPair(...args, {blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.getPair(...args, {blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + }); + + describe('match results for eth-calls to UniswapV2 Pair', async () => { + before("initialize contracts", async () => { + contract1 = new Contract(uniswapV2PairAddress, uniswapV2PairABI, provider1); + contract2 = new Contract(uniswapV2PairAddress, uniswapV2PairABI, provider2); + }); + + it('should match results for DOMAIN_SEPARATOR', async () => { + const result1 = await contract1.DOMAIN_SEPARATOR({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.DOMAIN_SEPARATOR({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for MINIMUM_LIQUIDITY', async () => { + const result1 = await contract1.MINIMUM_LIQUIDITY({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.MINIMUM_LIQUIDITY({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for PERMIT_TYPEHASH', async () => { + const result1 = await contract1.PERMIT_TYPEHASH({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.PERMIT_TYPEHASH({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for allowance', async () => { + const args = ["0x9c77233bbd235a3ed219daa051e0a3de5ce03c3e", "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"] + + const result1 = await contract1.allowance(...args, {blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.allowance(...args, {blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for balanceOf', async () => { + const args = ["0x052ba6f57c9184a89c34196ee4f3adacaeb58e8d"] + + const result1 = await contract1.balanceOf(...args, {blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.balanceOf(...args, {blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for decimals', async () => { + const result1 = await contract1.decimals({blockTag: config.blockTag}); + const result2 = await contract2.decimals({blockTag: config.blockTag}); + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for factory', async () => { + const result1 = await contract1.factory({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.factory({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for getReserves', async () => { + const result1 = await contract1.getReserves({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.getReserves({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for kLast', async () => { + const result1 = await contract1.kLast({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.kLast({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for name', async () => { + const result1 = await contract1.name({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.name({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for nonces', async () => { + const args = ["0xE0e8C1D735698060477e79a8e4C20276Fc2Ec7A7"] + + const result1 = await contract1.nonces(...args, {blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.nonces(...args, {blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for price0CumulativeLast', async () => { + const result1 = await contract1.price0CumulativeLast({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.price0CumulativeLast({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for price1CumulativeLast', async () => { + const result1 = await contract1.price1CumulativeLast({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.price1CumulativeLast({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for symbol', async () => { + const result1 = await contract1.symbol({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.symbol({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for token0', async () => { + const result1 = await contract1.token0({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.token0({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for token1', async () => { + const result1 = await contract1.token1({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.token1({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for totalSupply', async () => { + const result1 = await contract1.totalSupply({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.totalSupply({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + }); + + describe('match results for eth-calls to USDC', async () => { + before("initialize contracts", async () => { + contract1 = new Contract(usdcAddress, usdcABI, provider1); + contract2 = new Contract(usdcAddress, usdcABI, provider2); + }); + + it('should match results for CANCEL_AUTHORIZATION_TYPEHASH', async () => { + const result1 = await contract1.CANCEL_AUTHORIZATION_TYPEHASH({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.CANCEL_AUTHORIZATION_TYPEHASH({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for DOMAIN_SEPARATOR', async () => { + const result1 = await contract1.DOMAIN_SEPARATOR({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.DOMAIN_SEPARATOR({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for PERMIT_TYPEHASH', async () => { + const result1 = await contract1.PERMIT_TYPEHASH({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.PERMIT_TYPEHASH({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for TRANSFER_WITH_AUTHORIZATION_TYPEHASH', async () => { + const result1 = await contract1.TRANSFER_WITH_AUTHORIZATION_TYPEHASH({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.TRANSFER_WITH_AUTHORIZATION_TYPEHASH({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for allowance', async () => { + const args = ["0xa064c5d674b0de5ac8d1d1ade3fba7569525ac44", "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"]; + + const result1 = await contract1.allowance(...args, {blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.allowance(...args, {blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for balanceOf', async () => { + const args = ["0x95ba4cf87d6723ad9c0db21737d862be80e93911"] + + const result1 = await contract1.balanceOf(...args, {blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.balanceOf(...args, {blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for blacklister', async () => { + const result1 = await contract1.blacklister({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.blacklister({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for currency', async () => { + const result1 = await contract1.currency({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.currency({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for decimals', async () => { + const result1 = await contract1.decimals({blockTag: config.blockTag}); + const result2 = await contract2.decimals({blockTag: config.blockTag}); + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for masterMinter', async () => { + const result1 = await contract1.masterMinter({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.masterMinter({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for name', async () => { + const result1 = await contract1.name({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.name({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for owner', async () => { + const result1 = await contract1.owner({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.owner({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for paused', async () => { + const result1 = await contract1.paused({blockTag: config.blockTag}); + const result2 = await contract2.paused({blockTag: config.blockTag}); + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for pauser', async () => { + const result1 = await contract1.pauser({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.pauser({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for rescuer', async () => { + const result1 = await contract1.rescuer({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.rescuer({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for symbol', async () => { + const result1 = await contract1.symbol({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.symbol({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for totalSupply', async () => { + const result1 = await contract1.totalSupply({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.totalSupply({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + }); + + describe('match results for eth-calls to Compound', async () => { + before("initialize contracts", async () => { + contract1 = new Contract(compoundAddress, compoundABI, provider1); + contract2 = new Contract(compoundAddress, compoundABI, provider2); + }); + + it('should match results for DELEGATION_TYPEHASH', async () => { + const result1 = await contract1.DELEGATION_TYPEHASH({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.DELEGATION_TYPEHASH({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for DOMAIN_TYPEHASH', async () => { + const result1 = await contract1.DOMAIN_TYPEHASH({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.DOMAIN_TYPEHASH({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for allowance', async () => { + const args = ["0xa5ffc832b23606f82005688d734c099dfabd5313", "0x70e36f6bf80a52b3b46b3af8e106cc0ed743e8e4"] + + const result1 = await contract1.allowance(...args, {blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.allowance(...args, {blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for balanceOf', async () => { + const args = ["0x2FAF487A4414Fe77e2327F0bf4AE2a264a776AD2"] + + const result1 = await contract1.balanceOf(...args, {blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.balanceOf(...args, {blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for decimals', async () => { + const result1 = await contract1.decimals({blockTag: config.blockTag}); + const result2 = await contract2.decimals({blockTag: config.blockTag}); + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for delegates', async () => { + const args = ["0xdaaf40dae51ad67f1eeb8c8bded831f7ab150830"] + + const result1 = await contract1.delegates(...args, {blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.delegates(...args, {blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for name', async () => { + const result1 = await contract1.name({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.name({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for numCheckpoints', async () => { + const args = ["0xc00e94Cb662C3520282E6f5717214004A7f26888"] + + const result1 = await contract1.numCheckpoints(...args, {blockTag: config.blockTag}); + const result2 = await contract2.numCheckpoints(...args, {blockTag: config.blockTag}); + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for symbol', async () => { + const result1 = await contract1.symbol({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.symbol({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for totalSupply', async () => { + const result1 = await contract1.totalSupply({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.totalSupply({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + }); + + describe('match results for eth-calls to Dai', async () => { + before("initialize contracts", async () => { + contract1 = new Contract(daiAddress, daiABI, provider1); + contract2 = new Contract(daiAddress, daiABI, provider2); + }); + + it('should match results for DOMAIN_SEPARATOR', async () => { + const result1 = await contract1.DOMAIN_SEPARATOR({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.DOMAIN_SEPARATOR({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for PERMIT_TYPEHASH', async () => { + const result1 = await contract1.PERMIT_TYPEHASH({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.PERMIT_TYPEHASH({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for allowance', async () => { + const args = ["0x74ae284dd6044db63dc268f52131571a3b80ad33", "0xa91902085405CE0F648a7Eb82045Aefc1B7BAC01"] + + const result1 = await contract1.allowance(...args, {blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.allowance(...args, {blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for balanceOf', async () => { + const args = ["0xab78b4c4a28f6e449e0bf2d6eb4f4f0316343d2a"] + + const result1 = await contract1.balanceOf(...args, {blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.balanceOf(...args, {blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for decimals', async () => { + const result1 = await contract1.decimals({blockTag: config.blockTag}); + const result2 = await contract2.decimals({blockTag: config.blockTag}); + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for name', async () => { + const result1 = await contract1.name({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.name({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for symbol', async () => { + const result1 = await contract1.symbol({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.symbol({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for totalSupply', async () => { + const result1 = await contract1.totalSupply({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.totalSupply({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + + it('should match results for version', async () => { + const result1 = await contract1.version({blockTag: config.blockTag}); + expect(result1).to.not.be.empty; + + const result2 = await contract2.version({blockTag: config.blockTag}); + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + }); + }); + + // Compare getStorageAt results + describe('match results for getStorageAt calls', async () => { + const testSlots = ['0x0', '0x1', '0x2', '0x3', '0x4', '0x5', '0x6', '0x7', '0x8', '0x9', '0xa', '0xb', '0xc', '0xd', '0xe', '0xf'] + + describe('match results for getStorageAt for UniswapV2 Factory', async () => { + testSlots.forEach((testSlot: string) => { + it(`should match results for slot ${testSlot}`, async () => { + const result1 = await provider1.getStorageAt(uniswapV2FactoryAddress, testSlot, config.blockTag) + expect(result1).to.not.be.empty; + + const result2 = await provider2.getStorageAt(uniswapV2FactoryAddress, testSlot, config.blockTag) + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + }); + }); + + describe('match results for getStorageAt for UniswapV2 Pair', async () => { + testSlots.forEach((testSlot: string) => { + it(`should match results for slot ${testSlot}`, async () => { + const result1 = await provider1.getStorageAt(uniswapV2PairAddress, testSlot, config.blockTag) + expect(result1).to.not.be.empty; + + const result2 = await provider2.getStorageAt(uniswapV2PairAddress, testSlot, config.blockTag) + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + }); + }); + + describe('match results for getStorageAt for USDC', async () => { + testSlots.forEach((testSlot: string) => { + it(`should match results for slot ${testSlot}`, async () => { + const result1 = await provider1.getStorageAt(usdcAddress, testSlot, config.blockTag) + expect(result1).to.not.be.empty; + + const result2 = await provider2.getStorageAt(usdcAddress, testSlot, config.blockTag) + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + }); + }); + + describe('match results for getStorageAt for Compound', async () => { + testSlots.forEach((testSlot: string) => { + it(`should match results for slot ${testSlot}`, async () => { + const result1 = await provider1.getStorageAt(compoundAddress, testSlot, config.blockTag) + expect(result1).to.not.be.empty; + + const result2 = await provider2.getStorageAt(compoundAddress, testSlot, config.blockTag) + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + }); + }); + + describe('match results for getStorageAt for Dai', async () => { + testSlots.forEach((testSlot: string) => { + it(`should match results for slot ${testSlot}`, async () => { + const result1 = await provider1.getStorageAt(daiAddress, testSlot, config.blockTag) + expect(result1).to.not.be.empty; + + const result2 = await provider2.getStorageAt(daiAddress, testSlot, config.blockTag) + expect(result2).to.not.be.empty; + + expect(result1).to.deep.equal(result2); + }); + }); + }); + }); +}); diff --git a/packages/test/src/test-data.ts b/packages/test/src/test-data.ts new file mode 100644 index 00000000..ea28f0c8 --- /dev/null +++ b/packages/test/src/test-data.ts @@ -0,0 +1,25 @@ +// +// Copyright 2022 Vulcanize, Inc. +// + +import { readAbi } from "./common"; + +// UniswapV2 Factory contract +export const uniswapV2FactoryAddress = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"; +export const uniswapV2FactoryABI = readAbi("abis/UniswapV2Factory.json"); + +// UniswapV2 Pair contract +export const uniswapV2PairAddress = "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc"; +export const uniswapV2PairABI = readAbi("abis/UniswapV2Pair.json"); + +// USDC contract +export const usdcAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; +export const usdcABI = readAbi("abis/FiatTokenV2_1.json"); + +// Compound contract +export const compoundAddress = "0xc00e94Cb662C3520282E6f5717214004A7f26888"; +export const compoundABI = readAbi("abis/Comp.json"); + +// Dai/Maker contract +export const daiAddress = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; +export const daiABI = readAbi("abis/Dai.json"); diff --git a/packages/test/tsconfig.json b/packages/test/tsconfig.json new file mode 100644 index 00000000..6e6d282d --- /dev/null +++ b/packages/test/tsconfig.json @@ -0,0 +1,104 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "dist", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "exclude": ["dist", "artifacts"] +}