Building an Arbitrage Bot on Starknet: Part 0 - Understanding the Fundamentals

󰃭 2024-07-18

Introduction

This article is part of a series on building an arbitrage bot between centralised (CEX) and decentralised (DEX) exchanges on Starknet.

We’ll explore Starknet’s architecture, focusing on elements crucial for arbitrage: the sequencer system and transaction lifecycle.

What is Starknet

Starknet is a permissionless Layer 2 solution for Ethereum that uses zero-knowledge rollups (zk-rollups) to enhance scalability and security. Unlike optimistic rollups, Starknet’s approach allows for faster transaction finality and enhanced security. Key features include:

Here’s how Starknet works:

  1. The chain produces a cryptographic proof for each block.
  2. These proofs are then aggregated and published on Ethereum.
  3. Anyone can take the proof and verify it independently.

This process ensures transparency and security while leveraging the scalability benefits of Layer 2 technology. Starknet consists of two specialised actors: sequencers and provers. In this article, we will focus on the sequencers.

The sequencer

Sequencers are the backbone of the Starknet network, similar to Ethereum’s validators. While validators ensure network security, sequencers in Starknet provide transaction capacity. They serve as the access point for users to interact with the chain, necessitating high reliability and availability.

Starknet sequencer

Sequencers play a crucial role in Starknet’s operation, following a systematic approach to transaction processing:

Sequencers follow this systematic method of processing transactions:

  1. Sequencing: collecting transactions from users and ordering them.
  2. Executing: processing the transactions
  3. Batching: executed transactions are grouped into batches
  4. Block production: batches are grouped into blocks

Once sequencers complete these steps, provers take over to generate cryptographic proofs of these blocks, which are then submitted to Ethereum for final verification.

Although there are plans to decentralise Starknet (here and here), the current centralised sequencer model provides us with two interesting features: efficient transaction ordering and predictable transaction execution.

First-Come-First-Serve (FCFS) model

The sequencer operates on a First-Come-First-Serve (FCFS) basis, processing transactions as they are received. This eliminates the need for mempool monitoring and gas price competition, as the first transaction sent is the first to be processed. In Starknet, it is all about being first.

Understanding the sequencer’s role and the FCFS model is crucial for arbitrage bot developers. The FCFS model shifts the focus from gas price optimization to being the first to submit a transaction, fundamentally changing arbitrage strategies on Starknet compared to other blockchain networks.

Block production limits

Starknet implements block production limits to ensure network stability and efficiency. Blocks are typically created every ~6 minutes or when specific thresholds are met. For the most current information on these limits, refer to the official Starknet Current Limits guide.

Transaction lifecycle

To better understand the execution of transactions within the sequencer, let’s examine the transaction lifecycle. There are three different types of transactions:

  • INVOKE used for calling an existing function in a contract
  • DECLARE used for declaring new contract classes and activating new contract instances
  • DEPLOY_ACCOUNT used for deploying new account contracts in smart wallets.

Transaction lifecycle

At a high level, the Starknet transaction flow is as follows:

  1. Transaction submission
    • User signs the transaction and sends it to a node.
    • The node broadcast the transaction
    • The transaction is marked as RECEIVED and added to the mempool
  2. Mempool validation
    • Mempool performs a validation on the transaction (similar to the Ethereum’s signature)
    • __validate__ function is called (or __validate_declare__, __validate_deploy__ for respective transaction type) to ensure that the transaction is valid
    • Invalid transaction are discarded
  3. Sequencer validation
    • The sequencer performs a validation on the transaction before the execution to ensure the transaction is still valid.
    • Invalid transaction are discarded
  4. Execution:
    • Valid transactions are executed
    • Transactions are inserted into the pending block and state is updated
    • Transaction is marked as ACCEPTED ON L2. If a transaction fails during execution, the status is set to REVERTED. Otherwise, the status is SUCCESSED.
  5. Proof generation and verification: The prover computes the proof and sends it to the L1 verifier.

Combining the two: sequencer and transaction lifecycle

Why are these two aspects important to our arbitrage bot? While I was writing this article explaining their importance, Starknet made a tweet that answer the question perfetcly.

Starknet tweet

The answer is in “transaction finality extremely fast”. Although the tweet uses the wrong term, in Starknet finality occurs when the prover generates the block proof and publishes it on Ethereum. Validity, on the other hand, is when the sequencer builds the block. The ~2 seconds can be seen as fast validity.

But how is this possible? How can we have “finality” in ~2 seconds when a block is generated every ~6 minutes? The answer lies in stage 4 of the transaction lifecycle or point 2 of the sequencer. After execution, the sequencer updates the state of the chain. Because the sequencer is centralised and operate on a FCFS basis, it can ensure that the transaction order is preserved, allowing the chain state to be updated immediately. Block creation is a formality and only useful for the provers.

This is very important for us because it means we can completely ignore the mempool. We do not need to check it for pending swaps since the chain state has already been updated. But Matteo, are you 100% sure? Let’s follow the motto “Don’t trust, verify” and check if what I wrote is true.

I will illustrate this with two examples: first, the creation of an account, and second, a simple swap on Ekubo.

Account creation

Once we have created the signer and generated the account we need to fund it for deployment. The address of the account is 0x067902aa3c1c65b35995d5bfe04f1fe949795f3510da71ba86bbf0e134402645.

> starkli balance 0x067902aa3c1c65b35995d5bfe04f1fe949795f3510da71ba86bbf0e134402645 --network sepolia
0.000000000000000000

After the faucet

> starkli balance 0x067902aa3c1c65b35995d5bfe04f1fe949795f3510da71ba86bbf0e134402645 --network sepolia
0.025000000000000000

And deploy

> starkli account deploy account3.json --keystore keystore3.json
The estimated account deployment fee is 0.000001863236340482 ETH. However, to avoid failure, fund at least:
    0.000002794854510723 ETH
to the following address:
    0x067902aa3c1c65b35995d5bfe04f1fe949795f3510da71ba86bbf0e134402645
Press [ENTER] once you've funded the address.
Account deployment transaction: 0x06e1e2e16e28bdfe7d7faa6d49ebe080865e7b0b30e579322bf9aaf8656df4c3
Waiting for transaction 0x06e1e2e16e28bdfe7d7faa6d49ebe080865e7b0b30e579322bf9aaf8656df4c3 to confirm. If this process is interrupted, you will need to run `starkli account fetch` to update the account file.
Transaction not confirmed yet...
Transaction not confirmed yet...
Transaction 0x06e1e2e16e28bdfe7d7faa6d49ebe080865e7b0b30e579322bf9aaf8656df4c3 confirmed

>starkli balance 0x067902aa3c1c65b35995d5bfe04f1fe949795f3510da71ba86bbf0e134402645 --network sepolia
0.024998136763659518

From Voyager you can see that the transactions have been executed, the chain status has been updated and they are in the pending block.

voyager account

Swap

For this example we swap STRK for ETH using Ekubo. As you can see before the swap we have 20.0 STRK tokens.

balance before

Swap

Ekubo swap

Finally, the balance update

balance after

I found this group to discuss MEV on Starknet. If you are interested in the argument, want to discuss or have some interesting information, you can find me there. Feel free to join the group.

References