Delegatecall | Solidity 0.8
Summary
TLDRThe video explains delegate call in Solidity, where a contract can execute code in another contract while retaining the context of the calling contract. It demonstrates an example where Contract A calls Contract B which delegate calls Contract C. Despite Contract C's code executing, message.sender remains Contract A and message.value remains what A sent since the context is preserved from B. The video then shows how delegate call allows upgrading a contract's logic by deploying a new version of the called contract. However, it warns that the called contract must keep identical state variable declarations to avoid issues.
Takeaways
- 😀 With delegatecall, the called contract executes with the context of the calling contract. Message sender and msg.value are preserved.
- 👍🏻 When contract B delegatecalls contract C, msg.sender in C is the original caller to B. This differs from a regular call.
- 🔑 State variables are stored in the calling contract, not the one being delegatecalled. So contract C uses B's storage.
- ✨ You can upgrade a contract's logic via delegatecall since it uses the calling contract's state.
- 🚧 If you change state variable order when upgrading, it will break compatibility and cause issues.
- 👀 delegatecall allows "logic separation" - state stored separately from logic.
- ⚠️ Security risk: delegatecalled code can withdraw funds from the calling contract.
- 📝 delegatecall returns a bool for success and bytes for any return data.
- 💡 Can specify the function sig instead of a string when encoding for delegatecall.
- 😊 Overall delegatecall allows you to efficiently reuse and upgrade code & logic in contracts.
Q & A
What is delegate call in Solidity?
-Delegate call is a function in Solidity that allows a contract to execute code from another contract, while retaining the context of the calling contract. The called contract's code executes in the environment of the calling contract.
How does message.sender work with delegate call?
-With delegate call, message.sender inside the called contract will be the original caller to the calling contract. This preserves the original message sender context.
How does message.value work with delegate call?
-Message.value inside the called contract via delegate call will be the original amount sent to the calling contract that initiated the delegate call. The context including the amount sent is preserved.
Which contract's state variables are updated with delegate call?
-The calling contract's state variables are updated when using delegate call. The called contract code executes using the calling contract's storage and state.
Can you upgrade contract logic using delegate call?
-Yes, delegate call allows upgrading the logic executed by a contract even though the contract code itself is immutable. The calling contract delegates execution to updated logic contracts.
What are the risks of changing state variable order with delegate call upgrades?
-If new state variables are added or order is changed in an upgrade, it can break the delegate call mapping to storage. Existing state must be preserved in original order.
Does ether sent from the called contract go to the calling contract?
-Yes, any ether sent from the called contract is deducted from the calling contract's balance. The context of the calling contract is fully preserved.
Can new state variables be safely added to upgrade contracts?
-New state variables can be safely added in upgrade contracts as long as they are appended after existing variables, preserving original order.
What data is returned from a delegate call function?
-Like a regular call, delegate call returns a boolean indicating success and bytes data returned from the function call.
When would you use delegate call over a regular function call?
-Delegate call is useful to leverage an existing contract's storage and context for execution. It saves deploying new contracts in some upgrade cases.
Outlines
😊 What is delegatecall and how it executes code in the context of the calling contract
This paragraph explains delegatecall which allows a contract to execute code from another contract while retaining the context of the calling contract. It illustrates this with an example where Contract A calls Contract B which then delegatecalls Contract C. When executing Contract C's code via delegatecall, msg.sender is preserved as Contract A rather than Contract B which called it. Similarly, msg.value in Contract C is the amount sent from A to B. The code in Contract C runs with the state variables of B. Overall, delegatecall allows code execution in one contract using the context of another.
👍 Using delegatecall to upgrade contract logic by delegating to a new contract instance
This paragraph demonstrates how delegatecall can be used to upgrade contract logic. A contract called DelegateCall is shown that delegatecalls TestDelegateCall. By redeploying TestDelegateCall but keeping DelegateCall the same, the logic executed from DelegateCall is updated even though DelegateCall's own code is immutable. Important best practices when using this pattern are called out - state variables must be kept identical between contract versions including order, otherwise storage collisions can cause issues.
Mindmap
Keywords
💡delegate call
💡message.sender
💡message.value
💡storage layout
💡function signature
💡encode function
💡selector
💡storage
💡state variables
💡update contract logic
Highlights
Delegate call executes code in another contract in the context of the contract that called it
Message.sender will be the account that originally called the first contract
Message.value will be based on the amount sent from the first contract
Code inside the delegate called contract uses state variables of the calling contract
Delegate call preserves context - message.sender and message.value remain the same in the called contract
Can update delegate calling contract's logic even though its code can't change after deploying
Must keep same state variables and order when upgrading via delegate call
Changing state variable order messes up storage layout and causes issues
Add new state variables by appending, not inserting, to avoid problems
Encode function signature instead of function name string for delegate call
Delegate call returns success boolean and data like regular call function
Require success to check delegate call didn't fail
Called contract's state variables remain uninitialized after delegate call
Can update delegate called contract's logic to change functionality
Delegate call allows upgrading contract functionality without changing its code
Transcripts
delegate call executes code in another
contract in the context of the contract
that called it let's take a look for
example let's say that a this can be a
contract or it can be an account so a
calls b and then sends 100 way
next b calls c and then sends 50 weight
inside contract c message.sender will be
equal to b
message.value will be equal to 50. this
is because b sent to c 50 way
and whatever code that is inside
contract c
will be executed with the state
variables inside contract c
if there's a code inside contract c that
queries the balance of the stored in
contract c or it might send some leave
to another contract then it's going to
use the if stored in contract c this is
a regular call so let's take a look how
it's different when we use delegate call
again a calls b and sends 100 way now
unlike the first example this type b
delegates call to c
delegate call means that it's going to
be executing the code inside the
contract that is being called with the
state variables and other context of the
contract that called
so when b delegates call to c
message.sender will be a
this is a little bit surprising since b
called c so we expect message.sender to
be equal to b
but since we called delegate call
here message.center will be a
this is because when we query
message.sender inside contract b
it will be equal to a
a called b
and inside b message.sender will be
equal to a
delegate call preserves the context so
when b delegates call to c
message.sender remains it is still equal
to a for the same reason
message.value will be equal to 100.
a sent 100 way to b
so inside contract b message.value will
be equal to 100 delegate call preserves
the context so inside contract c
message.value will still be equal to
100. code inside contract c will be
executed with the state variables of b
and inside contract c if it sends ether
to another contract or it queries the
ether balance inside the contract
then it's going to use the if stored in
contract b
for this example we'll call the function
set bars
and we'll delegate call to this contract
test delegate call calling this function
inside this function we will set a state
variable num to the input num and then
also record message.sender and amount of
if that was sent message.value to use
delegate call we type test dot
delegate
call
and similar to call inside here we abi
encode the function that we're going to
be calling followed by the parameters
that we're going to be passing the
function that we're going to be calling
is set bars so you'll say abi dot
encode with
signature
the function that we're calling is set
bars
parentheses and the input is uint256
and for the input we'll pass in the num
now instead of typing a string to
specify the function that we're calling
there is another way so let me show you
that
so i'm going to comment this
watch i'm going to copy this
paste it here
and replace this whole line with abi dot
encode
with
selector
parentheses
and then we'll say
test
delegate call dot
set
bars dot
selector
so these two code will do exactly the
same thing
the benefit of writing it this way is
that now you don't have to write a
string so if you change the function
signature of testdelegatecall.setbars
then you don't have to make any change
here whereas if you were to use a string
then you will have to update the
function signature of the string
for this example we'll use this syntax
but both syntax accomplish the same
thing testificate call returns two
outputs similar to call so it'll be
boolean
success and some kind of output data
bytes
memory
data
and lastly we'll check that the delegate
call was successful by typing require
success
delegate call fail
this should be abi encode with selector
and that is how you use delegate call
let's deploy this contract and also this
contract and then we'll call the
function set bars i'll hit ctrl s to
compile the contract
we'll deploy delegate call and test the
date call
scroll down and then open delegate call
we'll call a function set bars and this
will delegate call to test delegate call
execute the code inside here
but since we're delegating call to test
delegate call
the state variable that you see over
here will not be updated
instead it is the state variable of the
contract that called in this case
delegate call that will be updated i'll
copy the address of test delegate call
paste it here
for the input to pass to the function
set bars i'll pass in
one two three
and we'll also send some
ether
we'll send one one one
way
scroll down and then call set bars check
the state variable num and it is equal
to one two three the sender that is the
account that you see over here
and the amount of ether that we sent
is 111. since we executed the code
inside here using the state variable
over here
we expect to see that these state
variables inside test delegate call to
be uninitialized
so i'll scroll down expand test delegate
call and then call num
and it is still equal to zero sender is
zero address and the value is zero all
of these state variables are
uninitialized
now using delegate call we can update
this delegate call contract the state
variables will be the same but the code
that we're executing can be updated
which means that we can update this
contract even though once this contract
is deployed we cannot change the code
inside here for example let's change how
the num state variable is set
previously we just set it to the input
this time i'll just double it
and then set it to no
we'll redeploy test delegate call
but the contract delegate call will use
the previous example so i'll compile the
contract and then we'll redeploy test
delegate call hit deploy
scroll down
and then expand on the contract delegate
call
clear the inputs
copy the address of the new contract
task delegate call this will double the
input
paste it in here
and for the input we'll pass in 100
and then call set bars
get the new state variable and look it
is equal to 200. what we just did here
was we were able to update the logic the
code of delegate call even though we
cannot change any of the code inside
this contract now it is important to
remember that when you're using delegate
call to update your contract logic
then all of the state variables have to
be the same in the exact same order so
if you were to change the order of the
state variables or maybe add a new state
variable on top of the old one
then you would see some weird stuff
going on with your contract delegate
call and to show you this i'll add an
address say public and then owner
we'll call set bars again and i'll show
you that now when we call this function
we'll get some weird results i'll
compile the contract and we'll redeploy
the new test delegate call contract
scroll down
clear the input
copy the azure subtest delegate call
paste it here and then pass in some
input for no
passing one two three again and then
call set bars since we passed in one to
three we expect num to be two times one
to three which will be two four six
however if we call the function num
notice that it is still equal to 200.
sender we expect it to be this account
but if we call sender now we get
something weird
and we set zero for the value so we
expect to be zero
but we get some very large number the
reason why you're seeing some weird
results here is because when we added a
new state variable on top of the old one
we changed the storage layout so the
code that is being executed here
writes to a different storage from the
storage that is defined over here
how state variables mapped to the
storage of the contract is an advanced
topic that i've covered in another video
search for a video about hack solidity
accessing private data the point is when
you're using delegate call to update
your contract code make sure that the
original state variables are declared in
the same order so instead of declaring
address public owner at the top
if you preserve the original state
variables and then appended new state
variables then this would have worked
Voir Plus de Vidéos Connexes
Contract Law Overview: What is the Gateway Issue on ALL Contracts Essays?
Contract Assets and Contract Liabilities
Arithmetic Overflow and Underflow | Hack Solidity (0.6)
Create a Cryptocurrency - Crash Course | Part 1 - Deploy ERC-20 Token
OBLICON_GENERAL PROVISION ON CONTRACTS PART 3
Lawyer Up on Contracts: Elura & Michele discuss Mutuality of Consideration
5.0 / 5 (0 votes)