Skip to content
This repository was archived by the owner on Aug 12, 2023. It is now read-only.

Commit cbde728

Browse files
committed
options
1 parent 3433f71 commit cbde728

File tree

6 files changed

+200
-31
lines changed

6 files changed

+200
-31
lines changed

jest.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const config: Config.InitialOptions = {
88
coverageProvider: 'v8',
99
preset: 'ts-jest',
1010
testEnvironment: 'node',
11-
testMatch: ['**/tests/*.test.ts'],
11+
testMatch: ['**/*.test.ts'],
1212
};
1313

1414
export default config;

src/AbiMapper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ const abiMap = (options?: Options): Mapping => {
9696
// If we have options
9797
if (options) {
9898
// Deconstruct our option parameters
99-
const { multicall: address, network } = options;
99+
const { address, network } = options;
100100

101101
if (network) {
102102
const networkObject: object = networks[network.toString()];

src/Multicall.ts

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import {
88
ContractCall,
99
Options,
1010
} from './models';
11-
import abiMap, { Mapping } from 'AbiMapper';
12-
import { Address, Network } from './types';
11+
import { abiMap, Mapping } from './AbiMapper';
12+
import { Address } from './types';
13+
import { Interface } from '@ethersproject/abi';
1314

1415
// Multicall - A library for calling multiple contracts in aggregate
1516
export class Multicall {
@@ -18,12 +19,9 @@ export class Multicall {
1819
public network: object;
1920
public multicall: string;
2021
public abi: object;
22+
public interface: Interface;
2123

22-
constructor(options?: {
23-
address?: Address;
24-
provider?: ethers.providers.Provider | ethers.Signer;
25-
network?: Network;
26-
}) {
24+
constructor(options?: Options) {
2725
// Extract the network or default to 1
2826
this.chainId = options && options.network ? options.network : 1;
2927
// If we have a network but not a provider, let's get the default provider for the given network
@@ -48,6 +46,7 @@ export class Multicall {
4846
this.multicall = this.network['multicall2'];
4947
}
5048
}
49+
this.interface = new ethers.utils.Interface(JSON.stringify(this.abi));
5150
}
5251

5352
public static encode(calls: ContractCall[] | ContractCall): AggregatedCall[] {
@@ -259,27 +258,42 @@ export class Multicall {
259258
const encoded: AggregatedCall[] = Multicall.encode(calls);
260259

261260
// Craft default configuration
262-
const abi: Mapping = abiMap(options);
263-
const multicall3Address: string = networks['1']['multicall3'];
261+
const map: Mapping = abiMap(options);
262+
const abi: object = map.abi;
263+
const address: Address = map.address;
264264
const provider: ethers.providers.Provider | ethers.Signer =
265-
ethers.getDefaultProvider();
265+
options && options.provider
266+
? options.provider
267+
: ethers.getDefaultProvider();
266268

267269
// Execute and return the calls
268-
return await Multicall.execute(abi, multicall3Address, provider, encoded);
270+
return await Multicall.execute(abi, address, provider, encoded);
269271
}
270272

271273
public async call(
272-
calls: ContractCall[] | ContractCall
274+
calls: ContractCall[] | ContractCall,
275+
options?: Options
273276
): Promise<AggregateFullResponse> {
274277
// Encode the calls
275278
const encoded: AggregatedCall[] = Multicall.encode(calls);
276279

280+
// Craft custom configuration
281+
const map: Mapping =
282+
options && (options.address || options.network)
283+
? abiMap(options)
284+
: {
285+
found: false,
286+
abi: this.abi,
287+
address: this.multicall,
288+
network: this.chainId,
289+
interface: this.interface,
290+
};
291+
const abi: object = map.abi;
292+
const address: Address = map.address;
293+
const provider: ethers.providers.Provider | ethers.Signer =
294+
options && options.provider ? options.provider : this.provider;
295+
277296
// Execute and return the calls
278-
return await Multicall.execute(
279-
this.abi,
280-
this.multicall,
281-
this.provider,
282-
encoded
283-
);
297+
return await Multicall.execute(abi, address, provider, encoded);
284298
}
285299
}

src/models/Options.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ethers } from 'ethers';
22

33
export interface Options {
44
abi?: any[];
5-
multicall?: string;
5+
address?: string;
66
provider?: ethers.providers.Provider | ethers.Signer;
77
network?: number;
88
}

tests/AbiMapper.test.ts

Lines changed: 144 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,31 @@
1-
import { multicall1, multicall2, multicall3 } from '../src/abis';
21
import { networks } from '../src/networks';
32
import { Address, Mapping } from '../src/types';
4-
import { constructWithAddress } from '../src';
3+
import {
4+
abiMap,
5+
constructWithAddress,
6+
networkToMapping,
7+
} from '../src/AbiMapper';
8+
import { multicall1, multicall2, multicall3 } from '../src/abis';
9+
import { ethers } from 'ethers';
10+
11+
// IMMUTABLES
12+
const MULTICALL_3_ADDRESS: Address =
13+
'0xcA11bde05977b3631167028862bE2a173976CA11';
14+
const GOERLI_MULTICALL_ADDRESS: Address =
15+
'0x77dca2c955b15e9de4dbbcf1246b4b85b651e50e';
16+
const DEFAULT_MAPPING: Mapping = {
17+
found: false,
18+
address: MULTICALL_3_ADDRESS,
19+
network: 1,
20+
interface: new ethers.utils.Interface(multicall3),
21+
abi: multicall3,
22+
};
523

624
describe('Constructs Mapping with Address', () => {
725
it('Non-existent address returns default mapping', () => {
826
const zero: Address = '0x0000000000000000000000000000000000000000';
927
const mapping: Mapping = constructWithAddress(zero);
10-
11-
expect(mapping.found).toBe(false);
12-
expect(mapping.address).toEqual(networks['1']['multicall3']);
13-
expect(mapping.network).toEqual(1);
14-
expect(mapping.abi).toEqual(multicall3);
28+
expect(mapping).toEqual(DEFAULT_MAPPING);
1529
});
1630

1731
it('Existing Multicall 3 properly construct mappings', () => {
@@ -20,7 +34,8 @@ describe('Constructs Mapping with Address', () => {
2034

2135
expect(mapping.found).toBe(true);
2236
expect(mapping.address).toEqual(goerliMulticall3);
23-
expect(mapping.network).toEqual(5);
37+
// Since all the multicall3 addresses are the same, we will get back network 1
38+
expect(mapping.network).toEqual(1);
2439
expect(mapping.abi).toEqual(multicall3);
2540
});
2641

@@ -30,12 +45,13 @@ describe('Constructs Mapping with Address', () => {
3045

3146
expect(mapping.found).toBe(true);
3247
expect(mapping.address).toEqual(rinkebyMulticall2);
33-
expect(mapping.network).toEqual(4);
48+
// MakerDAO deployed five instances of multicall2 to the same address so we'll get back network 1
49+
expect(mapping.network).toEqual(1);
3450
expect(mapping.abi).toEqual(multicall2);
3551
});
3652

3753
it('Existing Multicall 1 properly construct mappings', () => {
38-
const ropstenMulticall1: Address = networks['3']['multicall1'];
54+
const ropstenMulticall1: Address = networks['3']['multicall'];
3955
const mapping: Mapping = constructWithAddress(ropstenMulticall1);
4056

4157
expect(mapping.found).toBe(true);
@@ -44,3 +60,121 @@ describe('Constructs Mapping with Address', () => {
4460
expect(mapping.abi).toEqual(multicall1);
4561
});
4662
});
63+
64+
describe('Maps Network to Mapping Object', () => {
65+
it('Constructs Correct Mapping with Zero', () => {
66+
const zero: Address = '0x0000000000000000000000000000000000000000';
67+
const mapping: Mapping = networkToMapping(5, networks['5'], zero);
68+
expect(mapping).toEqual(DEFAULT_MAPPING);
69+
});
70+
71+
it('Constructs Correct Mapping with Multicall Address', () => {
72+
const m1addr: Address = '0x77dca2c955b15e9de4dbbcf1246b4b85b651e50e';
73+
const mapping: Mapping = networkToMapping(5, networks['5'], m1addr);
74+
75+
expect(mapping.found).toBe(true);
76+
expect(mapping.address).toEqual(m1addr);
77+
expect(mapping.network).toEqual(5);
78+
expect(mapping.abi).toEqual(multicall1);
79+
});
80+
81+
it('Constructs Correct Mapping with Multicall 2 Address', () => {
82+
const m2addr: Address = '0x5ba1e12693dc8f9c48aad8770482f4739beed696';
83+
const mapping: Mapping = networkToMapping(5, networks['5'], m2addr);
84+
85+
expect(mapping.found).toBe(true);
86+
expect(mapping.address).toEqual(m2addr);
87+
expect(mapping.network).toEqual(5);
88+
expect(mapping.abi).toEqual(multicall2);
89+
});
90+
91+
it('Constructs Correct Mapping with Multicall 3 Address', () => {
92+
const mapping: Mapping = networkToMapping(
93+
5,
94+
networks['5'],
95+
MULTICALL_3_ADDRESS
96+
);
97+
98+
expect(mapping.found).toBe(true);
99+
expect(mapping.address).toEqual(MULTICALL_3_ADDRESS);
100+
expect(mapping.network).toEqual(5);
101+
expect(mapping.abi).toEqual(multicall3);
102+
});
103+
});
104+
105+
describe('Abi Mapper', () => {
106+
it('Returns Default Mapping with no Options', () => {
107+
const mapping: Mapping = abiMap();
108+
expect(mapping).toEqual(DEFAULT_MAPPING);
109+
});
110+
111+
it('returns default mapping for invalid network', () => {
112+
const mapping: Mapping = abiMap({ network: -1 });
113+
expect(mapping).toEqual(DEFAULT_MAPPING);
114+
});
115+
116+
it('returns default mapping for an out of bounds network', () => {
117+
const mapping: Mapping = abiMap({ network: 10e6 });
118+
expect(mapping).toEqual(DEFAULT_MAPPING);
119+
});
120+
121+
it('returns the network mapping for invalid address', () => {
122+
const mapping: Mapping = abiMap({ network: 5, address: '0x' });
123+
expect(mapping.found).toBe(true);
124+
expect(mapping.address).toEqual(MULTICALL_3_ADDRESS);
125+
expect(mapping.network).toEqual(5);
126+
expect(mapping.abi).toEqual(multicall3);
127+
});
128+
129+
it('returns the network mapping for invalid network but valid address', () => {
130+
const mapping: Mapping = abiMap({
131+
network: -1,
132+
address: GOERLI_MULTICALL_ADDRESS,
133+
});
134+
expect(mapping.found).toBe(true);
135+
expect(mapping.address).toEqual(GOERLI_MULTICALL_ADDRESS);
136+
expect(mapping.network).toEqual(5);
137+
expect(mapping.abi).toEqual(multicall1);
138+
});
139+
140+
it('returns the network mapping for an out of bounds network but valid address', () => {
141+
const mapping: Mapping = abiMap({
142+
network: 10e6,
143+
address: GOERLI_MULTICALL_ADDRESS,
144+
});
145+
expect(mapping.found).toBe(true);
146+
expect(mapping.address).toEqual(GOERLI_MULTICALL_ADDRESS);
147+
expect(mapping.network).toEqual(5);
148+
expect(mapping.abi).toEqual(multicall1);
149+
});
150+
151+
it('returns the network mapping for valid network', () => {
152+
const mapping: Mapping = abiMap({ network: 5 });
153+
expect(mapping.found).toBe(true);
154+
expect(mapping.address).toEqual(MULTICALL_3_ADDRESS);
155+
expect(mapping.network).toEqual(5);
156+
expect(mapping.abi).toEqual(multicall3);
157+
});
158+
159+
it('returns the network mapping for both valid network and valid address', () => {
160+
const mapping: Mapping = abiMap({
161+
network: 5,
162+
address: GOERLI_MULTICALL_ADDRESS,
163+
});
164+
expect(mapping.found).toBe(true);
165+
expect(mapping.address).toEqual(GOERLI_MULTICALL_ADDRESS);
166+
expect(mapping.network).toEqual(5);
167+
expect(mapping.abi).toEqual(multicall1);
168+
});
169+
170+
it('prioritizes address over network', () => {
171+
const mapping: Mapping = abiMap({
172+
network: 4,
173+
address: GOERLI_MULTICALL_ADDRESS,
174+
});
175+
expect(mapping.found).toBe(true);
176+
expect(mapping.address).toEqual(GOERLI_MULTICALL_ADDRESS);
177+
expect(mapping.network).toEqual(5);
178+
expect(mapping.abi).toEqual(multicall1);
179+
});
180+
});

tests/Multicall.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,27 @@ describe('Multicalls', () => {
192192
);
193193
});
194194

195+
it('Statically Multicalls With Options', async () => {
196+
// Call the Multicall associated functions directly
197+
const res = await Multicall.call(multicalls, { network: 5 });
198+
199+
// Expect results to equal the number of calls we made
200+
expect(res.results.length).toBe(multicalls.length);
201+
202+
// Expect each call to have length 1
203+
res.results.map((result) => expect(result.methodResults.length).toBe(1));
204+
205+
// Expect each call to be successful
206+
res.results.map((result) =>
207+
expect(result.methodResults[0].returnData[0]).toBe(true)
208+
);
209+
res.results.map((result) =>
210+
expect(
211+
BigNumber.from(result.methodResults[0].returnData[1]).toNumber()
212+
).toBeGreaterThan(0)
213+
);
214+
});
215+
195216
it('Multicalls With Recommended Instantiation', async () => {
196217
// Use the default provider ;P
197218
const provider = ethers.getDefaultProvider();

0 commit comments

Comments
 (0)