Skip to content

Instantly share code, notes, and snippets.

@Muhammad-Altabba
Forked from critesjosh/Contract_calls.sol
Last active February 20, 2024 10:45
Show Gist options
  • Save Muhammad-Altabba/55ac6974ac9396d723fdfd792d51eb5d to your computer and use it in GitHub Desktop.
Save Muhammad-Altabba/55ac6974ac9396d723fdfd792d51eb5d to your computer and use it in GitHub Desktop.
CALL vs CALLCODE vs DELEGATECALL in Solidity
pragma solidity ^0.5.0;
contract C1 {
uint public num;
address public sender;
function callSetNum(address c2, uint _num) public {
(bool res,) = c2.call(abi.encodePacked(bytes4(keccak256("setNum(uint256)")), _num));
if(!res) revert(); // C2's num is set
}
function c2setNum(address _c2, uint _num) public {
C2 c2 = C2(_c2);
c2.setNum(_num);
}
// Function callcode is now disallowed (in favor of delegatecall).
// It is still possible to use it via inline assembly.
// https://solidity.readthedocs.io/en/v0.5.0/050-breaking-changes.html
// function callcodeSetNum(address c2, uint _num) public {
// bool res;
// In version 5.0 and upward the next line will case:
// TypeError: "callcode" has been deprecated in favour of "delegatecall"
// (res,) = c2.callcode(abi.encodePacked(bytes4(keccak256("setNum(uint256)")), _num));
// if(!res) revert(); // C1's num is set
// }
function delegatecallSetNum(address c2, uint _num) public {
(bool res,) = c2.delegatecall(abi.encodePacked(bytes4(keccak256("setNum(uint256)")), _num));
if(!res) revert(); // C1's num is set
}
}
contract C2 {
uint public num;
address public sender;
function setNum(uint _num) public {
num = _num;
sender = msg.sender;
// msg.sender is C1 if invoked by C1.callcodeSetNum
// msg.sender is C3 if invoked by C3.f1()
}
}
contract C3 {
function f1(C1 c1, C2 c2, uint _num) public {
c1.delegatecallSetNum((address)(c2), _num);
}
}
@Muhammad-Altabba
Copy link
Author

Forked from critesjosh/Contract_calls.sol and updated for Solidity version 0.5.0 and onward.

@Am0rfu5
Copy link

Am0rfu5 commented Jul 22, 2019

I think the comment on line 41 should read callSetNum now that callcode is deprecated.
// msg.sender is C1 if invoked by C1.callcodeSetNum
should read
// msg.sender is C1 if invoked by C1.callSetNum

As an aside callcode will actually show c2 address as the msg.sender in pre-0.5.0 versions and likely will do the same in inline assembly.

@advancod
Copy link

Please very please

can someone explain me why the function transferDai doesnot work in the following code? you ll save my life

pragma solidity ^0.5.9;

// Adding only the ERC-20 function we need
interface DaiToken {
function balanceOf(address guy) external view returns (uint);
}

contract DaiFaucet {

address dai;
DaiToken daitoken;

constructor() public{
    dai = 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359;
    daitoken = DaiToken(dai);
}

function balance() public view returns (uint) {
    return daitoken.balanceOf(msg.sender); // I have dai here
}

function balanceBis() public view returns (uint) {
	return daitoken.balanceOf(0x820Af9cea6CF890F36CAe589853190C622d39058); // a custom target address of mine
}

function transferdai() public  {
    uint value = 1; 
    address target = 0x820Af9cea6CF890F36CAe589853190C622d39058;
    (bool res,) = dai.delegatecall(abi.encodePacked(bytes4(keccak256("transfer(address,uint256)")), target, value));
     if(!res) revert();
    
}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment