Skip to content

Commit ad38d40

Browse files
committed
address: shorten batch contract writes section
1 parent d9c36a6 commit ad38d40

File tree

1 file changed

+5
-32
lines changed

1 file changed

+5
-32
lines changed

smart-contracts/advanced/multicall.md

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -114,39 +114,12 @@ This example demonstrates how to use Multicall3 to batch multiple `balanceOf` ca
114114

115115
### Batch Contract Writes
116116

117-
_If using Multicall3 for this purpose, be aware it is unaudited, so use at your own risk._
118-
_However, because it is a stateless contract, it should be safe when used correctly—**it should never hold your funds after a transaction ends, and you should never approve Multicall3 to spend your tokens**_.
117+
Multicall3, while unaudited, can be safely used for batching on-chain writes when used correctly. As a stateless contract, it should never hold funds after a transaction ends, and users should never approve it to spend tokens.
119118

120-
Multicall3 can also be used to batch on-chain transactions using the methods described in the [Batch Contract Reads](#batch-contract-reads) section.
119+
When using Multicall3, it's crucial to understand two key aspects: the behavior of `msg.sender` in calls versus delegatecalls, and the risks associated with `msg.value` in multicalls.
121120

122-
When using Multicall3 for this purpose, there are **two important details you MUST understand**.
121+
In FVM, there are two types of accounts: Externally Owned Accounts (EOAs) controlled by private keys, and Contract Accounts controlled by code. The `msg.sender` value during contract execution depends on whether a CALL or DELEGATECALL opcode is used. CALL changes the execution context, while DELEGATECALL preserves it.
123122

124-
1. How `msg.sender` behaves when calling vs. delegatecalling to a contract.
125-
2. The risks of using `msg.value` in a multicall.
123+
For EOAs, which can only use CALL, Multicall3's address becomes the `msg.sender` for subsequent calls. This limits its usefulness from EOAs to scenarios where **`msg.sender` is irrelevant**. However, contract wallets or other contracts can use either CALL or DELEGATECALL, with the latter preserving the original `msg.sender`.
126124

127-
Before explaining both of these, let's first cover some background.
128-
129-
There are two types of accounts: Externally Owned Accounts (EOAs) and Contract Accounts.
130-
EOAs are controlled by private keys, and Contract Accounts are controlled by code.
131-
132-
When an EOA calls a contract, the `msg.sender` value during execution of the call provides the address of that EOA. This is also true if the call was executed by a contract.
133-
The word "call" here specifically refers to the [`CALL`](https://www.evm.codes/#f1?fork=shanghai) opcode.
134-
Whenever a CALL is executed, the _context_ changes.
135-
New context means storage operations will be performed on the called contract, there is a new value (i.e. `msg.value`), and a new caller (i.e. `msg.sender`).
136-
137-
The FVM also supports the [`DELEGATECALL`](https://www.evm.codes/#f4) opcode, which is similar to `CALL`, but different in a very important way: it _does not_ change the context of the call.
138-
This means the contract being delegatecalled will see the same `msg.sender`, the same `msg.value`, and operate on the same storage as the calling contract.
139-
140-
It's important to note that you cannot delegatecall from an EOA — an EOA can only call a contract, not delegatecall it.
141-
142-
Because you cannot delegatecall from an EOA, this significantly reduces the benefit of calling Multicall3 from an EOA—any calls the Multicall3 executes will have the MultiCall3 address as the `msg.sender`.
143-
144-
**This means you should only call Multicall3 from an EOA if the `msg.sender` does not matter.** `msg.sender` will be different depending on which opcode you use.
145-
146-
If you are using a contract wallet or executing a call to Multicall3 from another contract, you can either CALL or DELEGATECALL.
147-
Calls will behave the same as described above for the EOA case, and delegatecalls will preserve the context.
148-
This means if you delegatecall to Multicall3 from a contract, the `msg.sender` of the calls executed by Multicall3 will be that contract.
149-
This can be very useful, and is how the Gnosis Safe [Transaction Builder](https://help.safe.global/en/articles/40841-transaction-builder) works to batch calls from a Safe.
150-
151-
Similarly, because `msg.value` does not change with a delegatecall, you must be careful relying on `msg.value` within a multicall.
152-
To learn more about this, see [here](https://github.com/runtimeverification/verified-smart-contracts/wiki/List-of-Security-Vulnerabilities#payable-multicall) and [here](https://samczsun.com/two-rights-might-make-a-wrong/).
125+
The handling of `msg.value` in multicalls requires caution. Since `msg.value` doesn't change with delegatecalls, relying on it within a multicall can lead to security vulnerabilities. To learn more about this, see [here](https://github.com/runtimeverification/verified-smart-contracts/wiki/List-of-Security-Vulnerabilities#payable-multicall) and [here](https://samczsun.com/two-rights-might-make-a-wrong/).

0 commit comments

Comments
 (0)