@@ -2,14 +2,14 @@ import { Contract, ContractInterface, ethers } from 'ethers';
22import { networks } from './networks' ;
33import { multicall1 , multicall2 , multicall3 } from './abis' ;
44import {
5- AggregateCallResponse ,
6- AggregatedCall ,
7- AggregateFullResponse ,
5+ MulticallResponse ,
86 ContractCall ,
7+ EncodedCall ,
98 Options ,
9+ RawCallResponse ,
10+ Address ,
1011} from './models' ;
1112import { abiMap , Mapping } from './AbiMapper' ;
12- import { Address } from './types' ;
1313import { Interface } from '@ethersproject/abi' ;
1414
1515// Multicall - A library for calling multiple contracts in aggregate
@@ -49,27 +49,20 @@ export class Multicall {
4949 this . interface = new ethers . utils . Interface ( JSON . stringify ( this . abi ) ) ;
5050 }
5151
52- public static encode ( calls : ContractCall [ ] | ContractCall ) : AggregatedCall [ ] {
53- const callray : ContractCall [ ] = ! Array . isArray ( calls ) ? [ calls ] : calls ;
54- const encodedCalls : AggregatedCall [ ] = [ ] ;
55- callray . forEach ( ( call , index ) => {
52+ public static encode ( calls : ContractCall [ ] | ContractCall ) : EncodedCall [ ] {
53+ const callArray : ContractCall [ ] = ! Array . isArray ( calls ) ? [ calls ] : calls ;
54+ const encodedCalls : EncodedCall [ ] = [ ] ;
55+ callArray . forEach ( ( call ) => {
5656 // Grab each call's abi
57- const calliface = new ethers . utils . Interface ( call . abi ) ;
58- call . calls . forEach ( ( method , calli ) => {
59- // Encode the call
60- const encodedData = calliface . encodeFunctionData (
61- method . method ,
62- method . params
63- ) ;
64- // Push to the list of encoded calls
65- encodedCalls . push ( {
66- contractContextIndex : index ,
67- contractMethodIndex : calli ,
68- allowFailure : method . allowFailure || false ,
69- target : call . contractAddress ,
70- encodedData,
71- } ) ;
72- } ) ;
57+ const callInterface = new ethers . utils . Interface ( call . abi ) ;
58+ // Encode the call
59+ const encodedData = callInterface . encodeFunctionData (
60+ call . method ,
61+ call . params
62+ ) ;
63+ // Push to the list of encoded calls
64+ const newCall = { encodedData, ...call } ;
65+ encodedCalls . push ( newCall ) ;
7366 } ) ;
7467
7568 return encodedCalls ;
@@ -91,57 +84,39 @@ export class Multicall {
9184 }
9285
9386 // Explodes an Aggregate Response into the Full Response
94- public static explodeResponse (
95- res : AggregateCallResponse ,
96- calls : AggregatedCall [ ]
97- ) : AggregateFullResponse {
98- // Build the AggregateFullResponse from the Multicall3 Aggregate3Response
99- const a3Response : AggregateFullResponse = {
87+ public static explode (
88+ callres : RawCallResponse ,
89+ calls : EncodedCall [ ]
90+ ) : MulticallResponse {
91+ // Build the final result
92+ const exploded : MulticallResponse = {
93+ blockNumber : callres . blockNumber ,
94+ blockHash : callres . blockHash ,
10095 results : [ ] ,
10196 } ;
10297
103- // Iterate over the return data
104- for ( let i = 0 ; i < res . returnData . length ; i ++ ) {
105- // For existing contracts in the multicall, we can just append to the method results
106- const existingResponse = a3Response . results . find (
107- ( c ) => c . contractContextIndex === calls [ i ] . contractContextIndex
108- ) ;
109- if ( existingResponse ) {
110- existingResponse . methodResults . push ( {
111- blockHash : res . blockHash ,
112- blockNumber : res . blockNumber ,
113- returnData : res . returnData [ i ] ,
114- contractMethodIndex : calls [ i ] . contractMethodIndex ,
115- } ) ;
116- } else {
117- a3Response . results . push ( {
118- methodResults : [
119- {
120- blockHash : res . blockHash ,
121- blockNumber : res . blockNumber ,
122- returnData : res . returnData [ i ] ,
123- contractMethodIndex : calls [ i ] . contractMethodIndex ,
124- } ,
125- ] ,
126- contractContextIndex : calls [ i ] . contractContextIndex ,
127- } ) ;
128- }
129- }
98+ // Map call responses to their original calls
99+ exploded . results = callres . returnData . map ( ( res : any , index : number ) => {
100+ return {
101+ returnData : res ,
102+ ...calls [ index ] ,
103+ } ;
104+ } ) ;
130105
131106 // Finally, return the full response
132- return a3Response ;
107+ return exploded ;
133108 }
134109
135110 // Aggregate3 Call on Multicall3 Contract
136111 // Builds response from Multicall3 specific response format
137112 public static async aggregate3 (
138- calls : AggregatedCall [ ] ,
113+ calls : EncodedCall [ ] ,
139114 contract : Contract
140- ) : Promise < AggregateFullResponse > {
115+ ) : Promise < MulticallResponse > {
141116 // Construct Multicall3 Aggregate3 Calls
142117 const a3calls = calls . map ( ( call ) => {
143118 return {
144- target : call . target ,
119+ target : call . address ,
145120 allowFailure : call . allowFailure ,
146121 callData : call . encodedData ,
147122 } ;
@@ -150,22 +125,22 @@ export class Multicall {
150125 const callres = await contract . callStatic . aggregate3 ( a3calls ) ;
151126
152127 // Call Multicall3 aggregate3 method and get back the returnData[]
153- const res : AggregateCallResponse = {
128+ const res : RawCallResponse = {
154129 returnData : callres ,
155130 } ;
156131
157- return Multicall . explodeResponse ( res , calls ) ;
132+ return Multicall . explode ( res , calls ) ;
158133 }
159134
160135 // tryAggregate Call on Multicall2 or Multicall3 Contract
161136 public static async tryAggregate (
162- calls : AggregatedCall [ ] ,
137+ calls : EncodedCall [ ] ,
163138 contract : Contract
164- ) : Promise < AggregateFullResponse > {
139+ ) : Promise < MulticallResponse > {
165140 // Map calls to the Multicall Call Struct format
166141 const mcalls = calls . map ( ( call ) => {
167142 return {
168- target : call . target ,
143+ target : call . address ,
169144 callData : call . encodedData ,
170145 } ;
171146 } ) ;
@@ -178,52 +153,48 @@ export class Multicall {
178153 mcalls
179154 ) ;
180155
181- const res : AggregateCallResponse = {
156+ const res : RawCallResponse = {
182157 blockNumber : callres [ 0 ] ,
183158 blockHash : callres [ 1 ] ,
184159 returnData : callres [ 2 ] ,
185160 } ;
186161
187- return Multicall . explodeResponse ( res , calls ) ;
162+ return Multicall . explode ( res , calls ) ;
188163 }
189164
190165 // tryAggregate Call on Multicall2 or Multicall3 Contract
191166 public static async aggregate (
192- calls : AggregatedCall [ ] ,
167+ calls : EncodedCall [ ] ,
193168 contract : Contract
194- ) : Promise < AggregateFullResponse > {
169+ ) : Promise < MulticallResponse > {
195170 // Map calls to the Multicall Call Struct format
196171 const mcalls = calls . map ( ( call ) => {
197172 return {
198- target : call . target ,
173+ target : call . address ,
199174 callData : call . encodedData ,
200175 } ;
201176 } ) ;
202177
203178 // Statically call on the multicall contract
204179 const res = await contract . callStatic . aggregate ( mcalls ) ;
205180
206- // Translate the raw response into an aggregate3 and tryAggregate response
207- // NOTE: Ignores the block number from the response
208- const aggregatedResponse : AggregateCallResponse = {
181+ // Translate the raw response into our response format
182+ const callres : RawCallResponse = {
209183 blockNumber : res [ 0 ] ,
210184 returnData : res [ 1 ] ,
211185 } ;
212186
213- return Multicall . explodeResponse ( aggregatedResponse , calls ) ;
187+ return Multicall . explode ( callres , calls ) ;
214188 }
215189
216190 public static async execute (
217191 abi : object ,
218192 multicall : string ,
219193 provider : ethers . providers . Provider | ethers . Signer ,
220- calls : AggregatedCall [ ]
221- ) : Promise < AggregateFullResponse > {
194+ calls : EncodedCall [ ]
195+ ) : Promise < MulticallResponse > {
222196 const contract : Contract = Multicall . getContract ( multicall , abi , provider ) ;
223197
224- // TODO: make this "adaptive" by allowing calls to not specify graceful/allowFailure param
225- // TODO: in this case, multicalls should fall back to backwards-compatible method
226-
227198 // If the multicall contract has an aggregate3 method, use it
228199 if (
229200 contract . interface . functions [ 'aggregate3((address,bool,bytes)[])' ] ?. name
@@ -253,9 +224,9 @@ export class Multicall {
253224 public static async call (
254225 calls : ContractCall [ ] | ContractCall ,
255226 options ?: Options
256- ) : Promise < AggregateFullResponse > {
227+ ) : Promise < MulticallResponse > {
257228 // Encode the calls
258- const encoded : AggregatedCall [ ] = Multicall . encode ( calls ) ;
229+ const encoded : EncodedCall [ ] = Multicall . encode ( calls ) ;
259230
260231 // Craft default configuration
261232 const map : Mapping = abiMap ( options ) ;
@@ -273,9 +244,9 @@ export class Multicall {
273244 public async call (
274245 calls : ContractCall [ ] | ContractCall ,
275246 options ?: Options
276- ) : Promise < AggregateFullResponse > {
247+ ) : Promise < MulticallResponse > {
277248 // Encode the calls
278- const encoded : AggregatedCall [ ] = Multicall . encode ( calls ) ;
249+ const encoded : EncodedCall [ ] = Multicall . encode ( calls ) ;
279250
280251 // Craft custom configuration
281252 const map : Mapping =
0 commit comments