Skip to content

Commit

Permalink
Custom network test support (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
CjHare committed Oct 6, 2021
1 parent 258f858 commit 064e5f0
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 3 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,29 @@ npm run test --strategy=eth-balance
npm run test --strategy=eth-balance --more=200
```

#### Local network test strategy
Testing using a custom network (e.g. dev testing or CI) overrides the default networks, requiring a few extra steps.

##### 1. Create your network
- JSON-RPC endpoint accessible from script run location.
- Governance contract (e.g. your ERC20 contract) deployed and populated with test data.
- Multicall contract deployed (used by snapshot to aggregate data retrieval calls).

##### 2. Update your networks file (e.g. `network/local.json`)
- `multicall`; Multicall contract address on your network.
- `chainId`; Chain Id matching that of your created network.
- `rpc`; connection details for your JSON-RPC endpoint.

##### 3. Update your Strategy test data (e.g. `example.json`)
- `strategy` `address`; governance contract address from deployment on your network.
- `addresses`; test accounts created earlier when creating your network.
- `snapshot`; to an appropriate block height for your network.

##### 4. Test
```bash
# Test default strategy (erc20-balance-of) using local.json networks file
npm run test --network=../../network/local.json
```

### License
[MIT](LICENSE).
14 changes: 14 additions & 0 deletions network/local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"1": {
"key": "1",
"name": "In Memory Ethereum Mainnet",
"chainId": 33133,
"network": "homestead",
"multicall": "0x9fe46736679d2d9a65f0992f2272de9f3c7fa6e0",
"rpc": [
{
"url": "http://localhost:8545/"
}
]
}
}
38 changes: 36 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import _strategies from './strategies';
import snapshot from '@snapshot-labs/snapshot.js';
import { Contract } from "@ethersproject/contracts";
import { Interface } from "@ethersproject/abi";
import Multicaller from './utils/multicaller';
const networks = require('./utils/networks');

export async function getScoresDirect(
space: string,
Expand Down Expand Up @@ -32,16 +36,46 @@ export async function getScoresDirect(
}
}

export async function multicall(
network: string,
provider,
abi: any[],
calls: any[],
options?
) {
const multicallAbi = [
'function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)'
];
const multi = new Contract(
networks[network].multicall,
multicallAbi,
provider
);
const itf = new Interface(abi);
try {
const [, res] = await multi.aggregate(
calls.map((call) => [
call[0].toLowerCase(),
itf.encodeFunctionData(call[1], call[2])
]),
options || {}
);
return res.map((call, i) => itf.decodeFunctionResult(calls[i][1], call));
} catch (e) {
return Promise.reject(e);
}
}

export const {
multicall,
Multicaller,
subgraphRequest,
ipfsGet,
call,
getBlockNumber,
getProvider
} = snapshot.utils;

export { Multicaller };

export default {
getScoresDirect,
multicall,
Expand Down
45 changes: 45 additions & 0 deletions src/utils/multicaller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { StaticJsonRpcProvider } from '@ethersproject/providers';
import set from 'lodash.set';
import { multicall } from '../utils';

export default class Multicaller {
public network: string;
public provider: StaticJsonRpcProvider;
public abi: any[];
public options: any = {};
public calls: any[] = [];
public paths: any[] = [];

constructor(
network: string,
provider: StaticJsonRpcProvider,
abi: any[],
options?
) {
this.network = network;
this.provider = provider;
this.abi = abi;
this.options = options || {};
}

call(path, address, fn, params?): Multicaller {
this.calls.push([address, fn, params]);
this.paths.push(path);
return this;
}

async execute(from?: any): Promise<any> {
const obj = from || {};
const result = await multicall(
this.network,
this.provider,
this.abi,
this.calls,
this.options
);
result.forEach((r, i) => set(obj, this.paths[i], r.length > 1 ? r : r[0]));
this.calls = [];
this.paths = [];
return obj;
}
}
22 changes: 22 additions & 0 deletions src/utils/networks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
function loadNetworks() {
const networksFile =
process.env['npm_config_networks_file'] ||
process.argv
.find((arg) => arg.includes('--networks-file'))
?.split('--networks-file')
?.pop();

if (networksFile === undefined) {
return require('@snapshot-labs/snapshot.js/src/networks.json');
} else {
try {
return require(networksFile);
} catch (e) {
throw new Error('Cannot find networks file: ' + networksFile);
}
}
}

const networks = loadNetworks();

module.exports = networks;
3 changes: 2 additions & 1 deletion test/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const { JsonRpcProvider } = require('@ethersproject/providers');
const { getAddress } = require('@ethersproject/address');
const snapshot = require('../').default;
const networks = require('@snapshot-labs/snapshot.js/src/networks.json');
const addresses = require('./addresses.json');
const networks = require('../src/utils/networks');

const strategyArg =
process.env['npm_config_strategy'] ||
Expand All @@ -22,6 +22,7 @@ const moreArg =

const strategy = Object.keys(snapshot.strategies).find((s) => strategyArg == s);
if (!strategy) throw 'Strategy not found';

const example = require(`../src/strategies/${strategy}/examples.json`)[0];

function callGetScores(example) {
Expand Down

0 comments on commit 064e5f0

Please sign in to comment.