Skip to content

Instantly share code, notes, and snippets.

@izqui
Last active July 27, 2018 17:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save izqui/27f228b13671f687f194676436b23aac to your computer and use it in GitHub Desktop.
Save izqui/27f228b13671f687f194676436b23aac to your computer and use it in GitHub Desktop.
Prototype of Aragon app that can be used for interacting with other protocols and external contracts. 🚨Unaudited and experimental code, do not deploy to production!
pragma solidity 0.4.18;
import "./Vault.sol";
contract Actor is Vault {
bytes32 constant public PERFORM_ACTION_ROLE = keccak256("PERFORM_ACTION_ROLE");
bytes32 constant public RETURN_TO_PARENT_ROLE = keccak256("RETURN_TO_PARENT_ROLE");
bytes4 constant internal ERC20_TRANSFER_SIG = 0xa9059cbb; // bytes4(keccak256("transfer(address,uint256)"))
Vault public parentVault;
event PerformAction(address indexed target, uint256 ethAmount, bytes data, bytes returnData);
event ReturnToParentVault(address indexed parentVault, address indexed token, uint256 value);
function initialize(Vault _parentVault) onlyInit public {
initialized();
parentVault = _parentVault;
}
function performAction(address _target, uint256 _ethAmount, bytes _data)
authP(PERFORM_ACTION_ROLE, arr(_target, _ethAmount, uint256(getSig(_data)))) public returns (bytes) {
// TODO: are this checks even needed??
// ERC20 transfers are disallowed through performAction (vault.transfer()) should be used instead
// Note that they could still be done using erc20.approve + erc20.transferFrom, but
// this could be useful for actions such as staking tokens. These signatures can be
// disallowed by ACL params.
require(getSig(_data) != ERC20_TRANSFER_SIG);
if (_ethAmount > 0) {
// eth transfers without data should be done using vault.transfer()
// TODO: vault.transfer() should stop allowing sending ETH with calldata
require(_data.length > 0);
}
require(_target.call.value(_ethAmount)(_data));
bytes memory returnData;
assembly {
returnData := mload(0x40)
let size := returndatasize
mstore(0x40, add(returnData, add(0x20, size)))
mstore(returnData, size)
returndatacopy(add(returnData, 0x20), 0, size)
}
PerformAction(_target, _ethAmount, _data, returnData);
return returnData;
}
function returnToParentVault(address _token, uint256 _value) authP(RETURN_TO_PARENT_ROLE, arr(_token, _value)) public {
if (_token == ETH) {
// make sure it triggers a deposit in the parent vault
// .send and .transfer would only use 2.3k gas which would be intercepted by the proxy
require(parentVault.call.value(_value)());
} else {
ERC20(_token).approve(parentVault, _value);
parentVault.deposit(_token, this, _value);
}
ReturnToParentVault(parentVault, _token, _value);
}
function getSig(bytes _data) internal pure returns (bytes4 sig) {
assembly {
sig := mload(add(_data, 0x20))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment