I deployed two contracts 'WalletLibrary' and 'Wallet': most of the functions in Wallet delegateCall() the functions from WalletLibrary. I want to recreate an Attack, where I call the initWallet() function from WalletLibrary by triggering the fallback function from Wallet. However when I do that, the Owner in Wallet is updated to my address, but the one in WalletLibrary is not. Further the owner of WalletLibrary is 0000000000000000 when deployed (did I do sth wrong with deploying maybe?), I would expect the owner should be the address I deployed it from.
From my understanding, when I update some variable in Wallet, then it should also be updated in WalletLibrary, because delegateCall() preserves context, right? My Question is, why it does not work. Please tell me, if I got something wrong. Hope anyone can help.
Below, the code for both contracts...
WalletLibrary.sol:
pragma solidity ^0.5.4;
contract WalletLibrary {
address walletLibrary;
address payable owner;
address payable student;
event LogValue(uint256 exitcode,uint256 amount);
function initWallet(address payable _owner) public payable {
owner = _owner;
}
function getOwner() public view returns (address payable) {
return owner;
}
function changeOwner(address payable new_owner) public returns (bool success) {
if (msg.sender == owner) {
owner = new_owner;
return true;
} else {
return false;
}
}
function withdraw(uint256 amount) public returns (bool success) {
if (msg.sender == owner) {
return owner.send(amount);
} else {
return false;
}
}
function () external payable {
emit LogValue(200,msg.value);
}
}
Wallet.sol:
pragma solidity ^0.5.4;
contract Wallet {
address walletLibrary;
address payable owner;
address payable student;
event LogValue(uint256 exitcode,uint256 amount);
// constructor, called once when this contract is created
constructor(address payable _student, address lib) public payable {
student = _student;
walletLibrary = lib; // hardcode lib address at deploy time
// init the owner with the respective lib contract
walletLibrary.delegatecall(abi.encodeWithSignature("initWallet(address)", msg.sender));
}
function getOwner() public view returns (address payable) {
return owner;
}
function getWalletLibrary() public view returns (address) {
return walletLibrary;
}
function withdraw(uint256 amount) public returns (bool) {
(bool success, bytes memory data) = walletLibrary.delegatecall(abi.encodeWithSignature("withdraw(uint256)", amount));
if ( success ) {
emit LogValue(200,amount);
} else {
emit LogValue(401,amount);
}
return success;
}
function changeOwner(address payable new_owner) public returns (bool) {
(bool success, bytes memory data) = walletLibrary.delegatecall(abi.encodeWithSignature("changeOwner(address)", new_owner));
return success;
}
function getStudent() public view returns (address) {
return student;
}
// fallback function gets called if no other function matches call
function () external payable {
emit LogValue(301,msg.value);
require( tx.origin == student );
walletLibrary.delegatecall(msg.data);
}
}