GIP-0017: Allow batching calls in Staking contract

Hi all, this is a proposal to add batching transactions in the Staking contract like in the GNS.


Expose a way to batch multiple calls into a single transaction. It provides great flexibility for indexer agents to combine multiple functions in different ways. It also reduce the gas cost by saving the initial gas, and in some cases, accessing a “used” slot by the other bundled transactions.


A new contract called MultiCall is introduced, inspired by the one used by Uniswap. The payable keyword was removed from the multicall() as the protocol does not deal with ETH. Additionally, it is insecure in some instances if the contract relies on msg.value.

The Staking contract inherits from MultiCall that expose a public multicall(bytes[] calldata data) function that receives an array of payloads to send to the contract itself. This allows to batch ANY publicly callable contract function.

By using a multicall a user can batch an arbitrary number of operations into a single transaction. The indexer agent can combine close, open, claim transactions in any way it sees more effective.

Closing multiple allocations

// Close multiple allocations in one tx
const requests = await Promise.all(
    allocationID: allocationID,
    poi: poi,
    allocationID: allocationID2,
    poi: poi,
].map(({ allocationID, poi }) =>
  staking.connect(indexer.signer).populateTransaction.closeAllocation(allocationID, poi),
).then((e) => PopulatedTransaction) =>
await staking.connect(indexer.signer).multicall(requests)


See @graphprotocol/contracts#475

Backwards Compatibility

The proposal introduces some breaking changes to save bytecode.

The following functions are removed as they can be constructed using a

  • closeAllocationMany()
  • closeAndAllocate()
  • claimMany()



The implementation was audited by Consensys Dilligence.


The implementation has not yet been deployed to Testnet.

Copyright Waiver

Copyright and related rights waived via CC0.


Great improvement for Indexers operations, would be awesome to have such flexibility!

I’d like to emphasize how this GIP can improve gas cost when operating on the network. By using the multicall we can batch arbitrary combination of calls, for example: [allocate, closeAllocation, allocate, claim] in a single call. This would be a nice improvements to the way the indexer-agent works.

Apart from that we can do things like combining multiple delegations instead of delegating in a single transaction for each indexer by combining [delegate, delegate, delegate...] calls.

About gas reduction, this is from the gas reporter on a test that does closeAllocation using a multicall:

1x |  GNS  · multicall ·  248323 gas │
2x |  GNS  · multicall ·  337280 gas │
3x |  GNS  · multicall ·  396261 gas │

You can see that gas is not linear to amount of closeAllocation transactions. You save the initial gas (21,000 for each transaction) and it also takes advantage of some cold slots already being loaded on past SLOAD which makes re-reading them cheaper, from 2100 to 100 gas.


Hey, I created a new PR based on the original implementation for this GIP that retains the deleted functions that are currently used to send bulk transactions. These are:

* closeAllocationMany()
* closeAndAllocate()
* claimMany()

The idea is that it might be easier to upgrade the indexer-agent this way and then remove those legacy functions on any of the next approved upgrades to the Staking contract.

The Graph Council executed the upgrade of the Staking contract that includes the changes described in this GIP.


Thank you for improving the protocol.

Is there already a plan when this will be part of the indexer agent?
If yes, what will be the functionality? For example will it be possible to manually create a batch of operations (n close, m allocate) using graph indexer cli?

Hey @spa,

Yes, adding multicall support into indexer-agent is planned. @Ford has been working on an action queue, which is where we would apply multicall to batch calls against the Staking contract.

The next official release is 0.19.x, which adds voucher redemption batching, revamps indexing rules, and a number of other things. The action queue may come in the release after that, with multicall support either landing in that release or a subsequent one.

As always contributions are very welcomed!