Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(std-contracts): use assembly for delegation in UpgradableSystem (#…
  • Loading branch information
Kooshaba committed Oct 29, 2022
1 parent 7d78c07 commit 1fa46fd
Showing 1 changed file with 32 additions and 5 deletions.
37 changes: 32 additions & 5 deletions packages/std-contracts/src/systems/UpgradableSystem.sol
Expand Up @@ -14,14 +14,41 @@ contract UpgradableSystem is PayableSystem {
constructor(IWorld _world, address _components) PayableSystem(_world, _components) {}

function execute(bytes memory args) public payable returns (bytes memory) {
(bool success, bytes memory returndata) = implementation.delegatecall(
bytes.concat(IPayableSystem.execute.selector, args)
);
if (!success) revert("delegate call failed");
return returndata;
_delegate(implementation);
}

function upgrade(address impl) public onlyOwner {
implementation = impl;
}

/**
* From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.3/contracts/proxy/Proxy.sol
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address impl) internal {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())

// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), impl, 0, calldatasize(), 0, 0)

// Copy the returned data.
returndatacopy(0, 0, returndatasize())

switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
}

0 comments on commit 1fa46fd

Please sign in to comment.