A simple example for how to use Solidity’s Inline Assembly
With Solidity being a relatively new language it has some limitations. To address this Solidity makes it possible to interweave your Solidity statements with its own version of inline assembly. This gives developers a way to build smart contracts that require more fine-grained control.
Writing manual assembly can be difficult due to the fact that the EVM is a stack machine. This makes it hard to address the correct stack slot and provide arguments to opcodes at the correct point on the stack. You can use Solidity’s defined inline assembly language to help you navigate these challenges and other issues when writing manual assembly.
Let’s take a look at an example.
The Multisig Wallet
Multisig wallets are used to add additional security to cryptocurrency transactions. The purpose of multisig wallets is to increase security by requiring multiple parties to agree on transactions before execution. Transactions can be executed only when confirmed by a predefined number of owners.
The Gnosis Multisig Wallet is a really nice open source implementation and a handy codebase to reference when it comes to using Solidity’s inline assembly.
How does the Gnosis Multisig Wallet use Solidity’s Inline Assembly
In the MultiSigWallet contract itself you’ll notice that a user must first submit a transaction via the submitTransaction
function which takes three arguments: the destination address for the transaction, the value of ETH to send in the transaction, and lastly (and most importantly in the context of this article), the transaction’s data payload:
function submitTransaction(address destination, uint value, bytes data)
After a user submits a transaction, before it will ultimately execute, the other required parties must confirm the transaction via the confirmTransaction
function. Upon confirmation, the executeTransaction
function is called which in turn calls the external_call
function in the contract.
Here is where we’ll find the use of Solidity’s inline assembly:
function external_call(address destination, uint value, uint dataLength, bytes data)
private
returns (bool)
{
bool result;
assembly {
let x := mload(0x40)
let d := add(data, 32)
result := call(
sub(gas, 34710),
destination,
value,
d,
dataLength,
x,
0
)
}
return result;
}
What’s happening here is that the call
opcode is used to interact with the EVM and execute the transaction. It takes seven arguments, including the original data payload from the submitTransaction
function, and provides them to the call
opcode at the correct point on the EVM’s stack.
You can learn more about Solidity’s inline assembly opcodes here.
Takeaways
- There are times when developing your smart contracts where you’ll require more granular control and perhaps need to execute logic that may not be possible with just Solidity.
- This would be difficult to do using manual assembly as we’d have to handle memory allocation and ensure we provide arguments to opcodes at the correct points on the EVM’s stack.
- Solidity defined inline assembly helps us with this and provides high-level syntax which makes these circumstances easier to navigate.
- It gives you more control over your smart contracts and lets you interact directly with the EVM using opcodes (like
call
). - That said, even though Solidity’s Inline assembly appears high-level, it is actually extremely low-level.
- Ultimately, Solidity’s inline assembly gives you more control over your smart contracts and permits you to execute logic that may not be possible with just plain old Solidity
I hope you found this helpful! Please don’t hesitate to reach out if you have any questions or would be interested in learning more — doug@upstate.agency
PS — Here’s a great article from Elizabeth Binks that dives into Solidity’s inline assembly more in depth