# Proposal to improve multicall, allowing to chain transactions

**URL:** <https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038>\
**Category:** Starknet Technical Development\
**Tags:** cairo\
**Created:** [September 14, 2022, 3:39pm UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038 "2022-09-14T15:39:17Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![th0rgal](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/th0rgal/32/951_2.png) [@th0rgal](https://community.starknet.io/u/th0rgal)\
**Post date:** [September 14, 2022, 3:39pm UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/1 "2022-09-14T15:39:17Z")

</div>

## Simple summary

A proposal to allow multicalls where a transaction uses a previous transaction output (from the same multicall) as an input.  
Here is the proof of concept repo: [GitHub - Th0rgal/better-multicall: An experiment to improve multicall on StarkNet](https://github.com/Th0rgal/better-multicall)

## Why is this important?

Multicall is a great tool on Starknet, it improves the user experience by not having to wait for one transaction to complete and helps reducing fees. For instance, this allows you to change your ETH allowance for a specific contract and call this contract function which spends this allowance in one go. You save two data writes and take advantage of sublinear computation fees. The thing is that for now, this is limited to functions that are not dependent on each other and whose parameters can be determined in advance. If you want to mint an NFT and then change its name, you have to do two transactions because you can’t know your nft id before minting it (it might not be the same if someone mints another nft at the same time).

## Proposed solution

I propose to change the **execute** function so that it can take felts or references to felts as parameters. I used the `execute` implementation from open zeppelin repo (cairo 0.10.0) as a basis.

I created a Felt struct, which takes two parameters : a type (it can be a default felt, or a reference), I also added a Type struct to be used as an enum to make the code cleaner. Instead of using a felt in your calldata, you could use `Felt(Type.DEFAULT, your_value)`. To put a reference to the first felt from the returned output, you could use `Felt(Type.REFERENCE, 0)`. Please note that you can only use a reference to an output given by a previous call. If you merge 2 calls that both return a felt, you can only use the first returned felt as an input for the second call, since you don’t know the rest of the output.  
This is just a proposal and I am curious to hear your ideas to make it clearer.

## Example

Here is an example contract interface where this improved multicall could be useful. Implementation is available here: [better-multicall/tests/example/contract.cairo at master · Th0rgal/better-multicall · GitHub](https://github.com/Th0rgal/better-multicall/blob/master/tests/example/contract.cairo).  
This contract allows you to mint a NFT and returns its id to you. It also allows you to change a NFT name if you own it and know its id. You can read the NFT to find its owner and its name.

### Example contract

```cairo
struct NFT {
    owner: felt,
    name: felt,
}

@contract_interface
namespace ExampleContract {
    func mint_nft() -> (nft_id: felt) {
    }

    func set_nft_name(id, name) {
    }

    func read_nft(id) -> (nft: NFT) {
    }
}

```

## Using the old fashion (two calls)

```cairo
    // 1st tx: minting the nft
    let (callarray: AccountCallArray*) = alloc();
    assert callarray[0] = AccountCallArray(example_contract_addr, mint_nft_selector, 0, 0);
    let (result_len, result: felt*) = execute(1, callarray, 0, new ());
    assert result_len = 1;
    local minted_nft = result[0];

    // 2nd tx: changing nft name
    let (calldata: felt*) = alloc();
    assert calldata[0] = minted_nft;
    assert calldata[1] = 'aloha';
    let (callarray: AccountCallArray*) = alloc();
    assert callarray[0] = AccountCallArray(example_contract_addr, set_nft_name_selector, 0, 2);
    let (result_len, result: felt*) = execute(1, callarray, 2, calldata);

```

## Using the improved execute (a single transaction)

```cairo
    let (calldata: Felt*) = alloc();
    assert calldata[0] = Felt(Type.REFERENCE, 0);
    assert calldata[1] = Felt(Type.DEFAULT, 'aloha');

    let (callarray: BetterAccountCallArray*) = alloc();
    assert callarray[0] = BetterAccountCallArray(example_contract_addr, mint_nft_selector, 0, 0);
    assert callarray[1] = BetterAccountCallArray(example_contract_addr, set_nft_name_selector, 0, 2);

    let (result_len, result: felt*) = better_execute(2, callarray, 2, calldata);

```

Full test is available here (written in cairo 0.10.0 using protostar): _actually I don’t have the right to post more than two links, it’s in tests folder on the github repo_.

Please let me know what you think. I’m not sure if we should replace the account interface, or add a second dedicated execute, or maybe even do this as a plugin? My guess is that it would be nice to have it available on all accounts so that dapps can assume that it’s possible, but if it turns out that it adds a significant additional cost for transactions that don’t require it, maybe having two versions of execute would make sense.

---

<div class="post-metadata">

**Author:** ![abdel.1559](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/abdel.1559/32/85849_2.png) [@abdel.1559](https://community.starknet.io/u/abdel.1559)\
**Post date:** [September 16, 2022, 11:57am UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/2 "2022-09-16T11:57:17Z")

</div>

Thanks for this proposal Thomas.  
Generally I think it makes sense and that it could enable interesting use cases.  
We should consider a security analysis to check if it could introduce unexpected attack vectors.  
Assuming we move forward with this proposal and we want to enable this in all account contracts I would suggest that we add a second execute. It would be better in terms of backward compatibility, and also let more flexibility regarding using in it or not, since it adds a little overhead.

---

<div class="post-metadata">

**Author:** ![abdel.1559](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/abdel.1559/32/85849_2.png) [@abdel.1559](https://community.starknet.io/u/abdel.1559)\
**Post date:** [September 16, 2022, 12:05pm UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/3 "2022-09-16T12:05:34Z")

</div>

btw @th0rgal could you benchmark the overhead if we replace the existing exectue ?

---

<div class="post-metadata">

**Author:** ![th0rgal](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/th0rgal/32/951_2.png) [@th0rgal](https://community.starknet.io/u/th0rgal)\
**Post date:** [September 16, 2022, 12:12pm UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/4 "2022-09-16T12:12:11Z")

</div>

When running the tests through protostar with this example, I get:

**Using two executes:**  
steps=734  
memory\_holes=50

**Using better multicall:**  
steps=725 (-1%)  
memory\_holes=48 (-4%)

I’m going to try with a normal call which doesn’t benefit from this new execute.

---

<div class="post-metadata">

**Author:** ![abdel.1559](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/abdel.1559/32/85849_2.png) [@abdel.1559](https://community.starknet.io/u/abdel.1559)\
**Post date:** [September 19, 2022, 7:40am UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/5 "2022-09-19T07:40:19Z")

</div>

Ok thanks. Let us know the results.

---

<div class="post-metadata">

**Author:** ![TotalPizza](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/totalpizza/32/837_2.png) [@TotalPizza](https://community.starknet.io/u/TotalPizza)\
**Post date:** [September 20, 2022, 9:17am UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/6 "2022-09-20T09:17:10Z")

</div>

If secure, this is a great idea.  
There are a bunch more scenarios in which I could see this saving some gas as you will not have to write/read to/from storage in order for the 2nd transaction to evaluate results of the 1st one.

---

<div class="post-metadata">

**Author:** ![th0rgal](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/th0rgal/32/951_2.png) [@th0rgal](https://community.starknet.io/u/th0rgal)\
**Post date:** [September 21, 2022, 4:54pm UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/7 "2022-09-21T16:54:57Z")

</div>

Thanks for reminding me. I tried calling only the mint function from the test contract using current execute and better execute. I got:

**Current execute:**  
steps=307  
memory\_holes=15

**Using better execute:**  
steps=319 (+4%)  
memory\_holes=16 (+6%)

The difference would probably increase if the calldata is very large as it would take up more space in the execute.

---

<div class="post-metadata">

**Author:** ![milan](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/milan/32/23836_2.png) [@milan](https://community.starknet.io/u/milan)\
**Post date:** [September 30, 2022, 2:05pm UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/8 "2022-09-30T14:05:20Z")

</div>

Great proposal th0rgal 🙏 I’d like to see this in production as well. My use case:

Imagine a defi protocol which has two primitive functions: open an account and fund an account. The first one returns an account ID, second one expects an ID. To call `open` and `fund` in a single TX, I have to create a wrapper function `open_and_fund`, because I don’t know the account ID to pass in to `fund` in advance. Obviously, I’d much rather do it using this proposed mechanism and ditch the wrapper function altogether.

---

<div class="post-metadata">

**Author:** ![JakubPtak](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/jakubptak/32/867_2.png) [@JakubPtak](https://community.starknet.io/u/JakubPtak)\
**Post date:** [October 3, 2022, 6:41am UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/9 "2022-10-03T06:41:01Z")

</div>

I like this idea. How flexible is it when output interface doesn’t match the input of the next call?

---

<div class="post-metadata">

**Author:** ![th0rgal](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/th0rgal/32/951_2.png) [@th0rgal](https://community.starknet.io/u/th0rgal)\
**Post date:** [October 10, 2022, 9:20pm UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/10 "2022-10-10T21:20:04Z")

</div>

Hello Jakub, I am not sure to understand the question. In your next call you can specify any felt from any previous call as an input (or a hardcoded felt value). The output of a specific call doesn’t need to match input of next one, you are really free to use them like you want, like if you were declaring the outputs with multiple let.

---

<div class="post-metadata">

**Author:** ![JakubPtak](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/jakubptak/32/867_2.png) [@JakubPtak](https://community.starknet.io/u/JakubPtak)\
**Post date:** [October 11, 2022, 1:14pm UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/11 "2022-10-11T13:14:53Z")

</div>

Thank you, that’s exactly what I wanted to know.  
I didn’t notice that you have a structure called Felt that declares usage of data or reference. So you can reference any output as long as you know it’s position, nice.

Let’s say we have a function like this:

```auto
func get_winners() -> (winners_len: felt, winners: felt*, winning_value: felt)

```

It seems that without knowing winners\_len it is not possible to chain it with calls to functions:

- accepting all winners - since the supported calldata must be constant,
- accepting winning\_value - since we don’t know the position of winning\_value in result.

Is this correct? I just want to see understand what would be possible with this proposal.

---

<div class="post-metadata">

**Author:** ![th0rgal](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/th0rgal/32/951_2.png) [@th0rgal](https://community.starknet.io/u/th0rgal)\
**Post date:** [October 14, 2022, 12:27pm UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/12 "2022-10-14T12:27:06Z")

</div>

That’s a great point, I think you are right. May be a Felt should be able to contain a calculation using Felt as a reference, so that you could define the reference using another reference?

So for example, if your calldata is something like:  
array\_len  
array\_value\_0  
…  
array\_value\_n  
thing1  
thing2  
thing3

And you want to use thing3, you should be able to give something like `Felt(Type.COMPUTED_REFERENCE, function_to_compute );`

where function to compute is defined like `Felt(Type.REFERENCE, 0) + Felt(Type.DEFAULT, 2 )`

I think this is possible, lemme know if you have a better idea, I can try to work on a poc.

---

<div class="post-metadata">

**Author:** ![JakubPtak](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/jakubptak/32/867_2.png) [@JakubPtak](https://community.starknet.io/u/JakubPtak)\
**Post date:** [October 17, 2022, 6:59am UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/13 "2022-10-17T06:59:55Z")

</div>

I am afraid that going this route (calculating the end position) would make it very complex and users would not know how to use it. I would rather stick with the original approach in this case.

I think a structural approach could simplify the flow. Let’s say you have functions like this:

```auto
func get_winners() -> (winners_len: felt, winners: felt*, winning_value: felt)
func process_all_winners(winners_len: felt, winners: felt*) -> ()

```

ABI would have to be available for all used functions, either provided by the caller or added as some meta info by the StarkNet OS.  
User would be able to specify that `process_all_winners` should take the second result from `get_winners` and since account knows that it is an array it will process it properly. So instead of operating on calldata level it would operate on values with their types.

I think it would make it easier for users, but on the cost of complicating the code and increasing overhead.

---

<div class="post-metadata">

**Author:** ![th0rgal](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/th0rgal/32/951_2.png) [@th0rgal](https://community.starknet.io/u/th0rgal)\
**Post date:** [November 12, 2022, 2:18am UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/14 "2022-11-12T02:18:55Z")

</div>

Hey Jakub, thank you for the proposition. I thought for a long time about it and I have something to show you. What’s cool is that it’s more flexible so we can add features if we want to.

I changed the interface to make sure it stays compatible with existing one, we no longer need to replace felt by the Felt struct and AccountCallArray stays the same. What changes is you will be able to replace any felt from the calldata by a sequence of multiple felts. The first one would be a prefix indicating how to handle the next ones. I thought about those:  
VALUE → 0  
REF → 1  
CALL\_REF → 2  
FUNC → 3  
FUNC\_CALL → 4

Value would mean you just need to use the next felt as it is. Ref would mean you need to look into the output values at index the next felt. Call ref would be followed by two felts : the first one would be the call index, the second one the index of a value from this call. Func would take a contract and a function and call it with the output\* to find the felt. Func\_call would be the same but would only pass a specific call output to the function.  
I already implemented and tested VALUE, REF and CALL\_REF. Here is what it looks like:

```nohighlight
    let (calldata: felt*) = alloc();
    assert calldata[0] = CallDataType.CALL_REF;
    assert calldata[1] = 1; // we want to get data from second call
    assert calldata[2] = 0; // at index 0
    assert calldata[3] = CallDataType.VALUE;
    assert calldata[4] = 'aloha';

    let (callarray: AccountCallArray*) = alloc();
    assert callarray[0] = AccountCallArray(example_contract_addr, get_bullshit_selector, 0, 0);
    assert callarray[1] = AccountCallArray(example_contract_addr, mint_nft_selector, 0, 0);
    assert callarray[2] = AccountCallArray(example_contract_addr, set_nft_name_selector, 0, 2);

```

Here you can see I first call the get\_bullshit() function which returns my an array of an unknown size, but it doesn’t matter : I can still refer to the first value returned by mint\_nft. I still need to implement the function calls to be able to do more magic things. Imagine taking the output of a call, doing some arithmetics operations or security assertions to it before using it as an input for another call, that would be so cool. Please tell me what you think about it and if you have other ideas

---

<div class="post-metadata">

**Author:** ![JakubPtak](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/jakubptak/32/867_2.png) [@JakubPtak](https://community.starknet.io/u/JakubPtak)\
**Post date:** [November 14, 2022, 8:47am UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/15 "2022-11-14T08:47:55Z")

</div>

I am not sure if I understand `FUNC` and `FUNC_CALL`. Do you mean that there would be a contract call performed to process calldata?

---

<div class="post-metadata">

**Author:** ![th0rgal](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/th0rgal/32/951_2.png) [@th0rgal](https://community.starknet.io/u/th0rgal)\
**Post date:** [November 16, 2022, 2:26am UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/16 "2022-11-16T02:26:52Z")

</div>

Yes exactly. I don’t know if it will be useful in real life but it would be a fallback solution to manage if the necessary felt is located after an indeterminate number of elements (for example several arrays).

---

<div class="post-metadata">

**Author:** ![th0rgal](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/th0rgal/32/951_2.png) [@th0rgal](https://community.starknet.io/u/th0rgal)\
**Post date:** [June 14, 2023, 8:00am UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/17 "2023-06-14T08:00:52Z")

</div>

Hey,

I started a rewrite in Cairo 1: [GitHub - Th0rgal/multicalls: Alternative interpretations of the Starknet transaction calls, allowing their composition.](https://github.com/Th0rgal/multicalls)

I still need to test it, but hopefully we could soon deploy a Cairo 1 account with composable multicall feature. What @juniset from Argent suggested is to support both multicall and composable (better) multicall by checking the first call: if it’s a call to the contract 0 on the selector “bettermulticall”, the rest of the calls would be interpreted with the composition algorithm. This allows to keep support with existing transactions and make sure you can’t forge a tx that would be malicious only on specific accounts.

---

<div class="post-metadata">

**Author:** ![jon](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/jon/32/54733_2.png) [@jon](https://community.starknet.io/u/jon)\
**Post date:** [June 20, 2023, 11:21am UTC](https://community.starknet.io/t/proposal-to-improve-multicall-allowing-to-chain-transactions/2038/18 "2023-06-20T11:21:37Z")

</div>

supporting both will be a good idea  
using multicall can be confusing or complex for users sometime .  
this was a good thread too.
