Degen Code

Degen Code

Share this post

Degen Code
Degen Code
Multicall Requests
Copy link
Facebook
Email
Notes
More

Multicall Requests

Batch Please

Apr 16, 2022
∙ Paid
18

Share this post

Degen Code
Degen Code
Multicall Requests
Copy link
Facebook
Email
Notes
More
14
Share

One of the most irritating things about running a bot is the time-consuming need to look up addresses for liquidity pools and tokens. Much of this is done by hand, which is terribly inefficient and error-prone, since a typo or a misconfiguration can lead to a dysfunctional bot and weird errors that are hard to diagnose.

A long-standing item on my to-do list has been automating the process of retrieving pool and token addresses from the Factory contract. Until now I’ve been doing this by hand, but learning about multicall has solved that problem.

So first I’ll talk about multicall, then use it to build a script that retrieves addresses for every known liquidity pool on Avalanche (TraderJoe, SushiSwap, and Pangolin), plus the token addresses inside those pools. Once we have this information, it suddenly becomes much easier to design an algorithm that answers the question “what arbitrage pathways are available on this blockchain?”

Multicall

I’m not sure who implemented multicall first, but the MakerDAO multicall GitHub repo has commits dating back to 2018. Many examples are forked from this codebase, so I’ll assume they were either the original authors or early pioneers.

Multicall allows multiple read-only requests (calls) to be made to a single smart contract using a single request at the node. This has three advantages:

  • Calls are grouped together, so you only use a single eth_call at the node per batched request. This saves you from burning through API requests if you're using a 3rd party RPC and have a rate limit.

  • Since all requests are sent and returned at once, latency becomes less critical. Instead of waiting avg_latency * 2 * num_requests, you wait only avg_latency * 2 (assuming the multicall returns in similar time vs. a single request)

  • All requests from a multicall are returned from the same block. This eliminates errors caused by data changing over multiple blocks as your individual calls return.

Multicall in Brownie

Brownie provides native multicall functionality which you can use if you set a special key in your network config called multicall2.

It’s easy enough, open .brownie/network-config.yaml and add this line in your Avalanche network block:

multicall2: '0xcA11bde05977b3631167028862bE2a173976CA11'

Mine looks like this, for reference:

- name: Avalanche
  networks:
  - chainid: 43114
    explorer: https://api.snowtrace.io/api
    host: https://speedy-nodes-nyc.moralis.io/[redacted]/avalanche/mainnet
    multicall2: '0xcA11bde05977b3631167028862bE2a173976CA11'
    id: moralis-avax-main
    name: Mainnet (Moralis)

The easiest way to execute a multicall request in Brownie is to instantiate a multicall object using with and then build all of your calls inside a list comprehension. The calls will be batched together through multicall, and the results stored inside that list.

A Brief Introduction to List Comprehensions

If you’ve never worked with a Python list comprehension, you’re in for a real treat. It allows you to quickly build a complex list with a single line of code, as long as you have an iterable object to feed data into it.

As a very simple example, please refer to the list comprehension I use inside the flash_borrow_to_lp_swap arbitrage helper for degenbot (GitHub link):

self.token_path = [token.address for token in self.tokens]

The general format for a list comprehension is [expression for item in iterable]

  • expression is any valid expression allowed by Python, such as x+1, x == 2 (evaluates to True or False), some_function(), or even an inline lambda.

  • item is simply a placeholder reference to some element from the iterable that you pass into your expression

  • iterable is any iterable object that you can loop through

At a high level, you can think of a list comprehension as flowing from the right side to the left. You begin with an iterable object, pick an item out of it, then feed it into the expression. Whatever that expression does with it is then saved to the list, and the process repeats.

Let’s take a simple math example:

>>> numbers = [0,1,2,3,4,5,6,7,8,9,10]
>>> [f"Is {number} even? {number % 2 == 0}" for number in numbers]
['Is 0 even? True', 
 'Is 1 even? False', 
 'Is 2 even? True', 
 'Is 3 even? False', 
 'Is 4 even? True', 
 'Is 5 even? False', 
 'Is 6 even? True', 
 'Is 7 even? False', 
 'Is 8 even? True', 
 'Is 9 even? False', 
 'Is 10 even? True']

I define a list called numbers, which holds integers from 0 to 10. The comprehension iterates through the list, pulling out the next integer and storing it as a variable called number. Then it feeds that integer into the expression f"Is {number} even? {number % 2 == 0}", which is an f-string with an inline boolean expression that returns True if the number is even, and False if the number is odd. Finally the list comprehension aggregates all of the results inside a new list.

You can also add filters to exclude stuff from the iterable. Let’s say we hate the number 3 for some reason, and want to ignore it:

>>> numbers = [0,1,2,3,4,5,6,7,8,9,10]
>>> [f"Is {number} even? {number % 2 == 0}" for number in numbers if number != 3]
['Is 0 even? True', 
 'Is 1 even? False', 
 'Is 2 even? True', 
 'Is 4 even? True', 
 'Is 5 even? False', 
 'Is 6 even? True', 
 'Is 7 even? False', 
 'Is 8 even? True', 
 'Is 9 even? False', 
 'Is 10 even? True']

For more on list comprehensions, I recommend checking out Real Python or other free resources.

Getting Pool Data with Multicall

Now let’s get to the code!

This post is for paid subscribers

Already a paid subscriber? Sign in
© 2025 BowTiedDevil
Privacy ∙ Terms ∙ Collection notice
Start writingGet the app
Substack is the home for great culture

Share

Copy link
Facebook
Email
Notes
More