Skip to content

Commit 8f6b330

Browse files
authored
Add contract-call strategy (snapshot-labs#4)
1 parent 361dc05 commit 8f6b330

File tree

3 files changed

+121
-1
lines changed

3 files changed

+121
-1
lines changed
+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Contract call strategy
2+
3+
Allows any contract method to be used to calculate voter scores.
4+
5+
## Examples
6+
7+
Can be used instead of the erc20-balance-of strategy, the space config will look like this:
8+
9+
```JSON
10+
{
11+
"strategies": [
12+
["contract-call", {
13+
// token address
14+
"address": "0x6887DF2f4296e8B772cb19479472A16E836dB9e0",
15+
// token decimals
16+
"decimals": 18,
17+
// token symbol
18+
"symbol": "DAI",
19+
// ABI for balanceOf method
20+
"methodABI": {
21+
"constant": true,
22+
"inputs": [{
23+
"internalType": "address",
24+
"name": "account",
25+
"type": "address"
26+
}],
27+
"name": "balanceOf",
28+
"outputs": [{
29+
"internalType": "uint256",
30+
"name": "",
31+
"type": "uint256"
32+
}],
33+
"payable": false,
34+
"stateMutability": "view",
35+
"type": "function"
36+
}
37+
}],
38+
]
39+
}
40+
```
41+
42+
You can call methods with multiple inputs in any contract:
43+
44+
```JSON
45+
{
46+
"strategies": [
47+
["contract-call", {
48+
// contract address
49+
"address": "0x6887DF2f4296e8B772cb19479472A16E836dB9e0",
50+
// output decimals
51+
"decimals": 18,
52+
// strategy symbol
53+
"symbol": "mySCORE",
54+
// arguments are passed to the method; "%{address}" is replaced with the voter's address; default value ["%{address}"]
55+
"args": ["0x6887DF2f4296e8B772cb19479472A16E836dB9e0", "%{address}"],
56+
// method ABI, output type should be uint256
57+
"methodABI": {
58+
"constant": true,
59+
"inputs": [{
60+
"internalType": "address",
61+
"name": "_someAddress",
62+
"type": "address"
63+
}, {
64+
"internalType": "address",
65+
"name": "_voterAddress",
66+
"type": "address"
67+
}],
68+
"name": "totalScoresFor",
69+
"outputs": [{
70+
"internalType": "uint256",
71+
"name": "",
72+
"type": "uint256"
73+
}],
74+
"payable": false,
75+
"stateMutability": "view",
76+
"type": "function"
77+
}
78+
}],
79+
]
80+
}
81+
```

src/strategies/contract-call/index.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { formatUnits } from '@ethersproject/units';
2+
import { multicall } from '../../utils';
3+
4+
function getArgs(options, address: string) {
5+
const args: Array<string | number> = options.args || ['%{address}'];
6+
return args.map(arg =>
7+
typeof arg === 'string' ? arg.replace(/%{address}/g, address) : arg
8+
);
9+
}
10+
11+
export async function strategy(
12+
network,
13+
provider,
14+
addresses,
15+
options,
16+
snapshot
17+
) {
18+
const blockTag = typeof snapshot === 'number' ? snapshot : 'latest';
19+
const response = await multicall(
20+
network,
21+
provider,
22+
[options.methodABI],
23+
addresses.map((address: any) => [
24+
options.address,
25+
options.methodABI.name,
26+
getArgs(options, address)
27+
]),
28+
{ blockTag }
29+
);
30+
31+
return Object.fromEntries(
32+
response.map((value, i) => [
33+
addresses[i],
34+
parseFloat(formatUnits(value.toString(), options.decimals))
35+
])
36+
);
37+
}

src/strategies/index.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import { strategy as erc20BalanceOfFixedTotal } from './erc20-balance-of-fixed-t
44
import { strategy as erc20BalanceOfCv } from './erc20-balance-of-cv';
55
import { strategy as makerDsChief } from './maker-ds-chief';
66
import { strategy as uni } from './uni';
7+
import { strategy as contractCall } from './contract-call';
78

89
export default {
910
balancer,
1011
'erc20-balance-of': erc20BalanceOf,
1112
'erc20-balance-of-fixed-total': erc20BalanceOfFixedTotal,
1213
'erc20-balance-of-cv': erc20BalanceOfCv,
1314
'maker-ds-chief': makerDsChief,
14-
'uni': uni
15+
'uni': uni,
16+
'contract-call': contractCall
1517
};

0 commit comments

Comments
 (0)