diff --git a/AddressRegistry.sol b/AddressRegistry.sol index 5f97715..122e6ae 100644 --- a/AddressRegistry.sol +++ b/AddressRegistry.sol @@ -8,6 +8,7 @@ contract AddressRegistry { constructor() public { registry[keccak256(abi.encodePacked("admin"))] = msg.sender; + registry[keccak256(abi.encodePacked("owner"))] = msg.sender; } function getAddr(string memory name) public view returns(address) { diff --git a/LogicProxy.sol b/LogicProxy.sol index 1b5f85f..a836cfd 100644 --- a/LogicProxy.sol +++ b/LogicProxy.sol @@ -1,5 +1,6 @@ pragma solidity ^0.4.23; + interface AddrRegistry { function getAddr(string calldata name) external view returns(address); } diff --git a/ProxyCache.sol b/ProxyCache.sol deleted file mode 100644 index e0674e8..0000000 --- a/ProxyCache.sol +++ /dev/null @@ -1,32 +0,0 @@ -// DSProxyCache -// This global cache stores addresses of contracts previously deployed -// by a proxy. This saves gas from repeat deployment of the same -// contracts and eliminates blockchain bloat. - -// By default, all proxies deployed from the same factory store -// contracts in the same cache. The cache a proxy instance uses can be -// changed. The cache uses the sha3 hash of a contract's bytecode to -// lookup the address -pragma solidity ^0.4.23; - -contract DSProxyCache { - mapping(bytes32 => address) cache; - - function read(bytes _code) public view returns (address) { - bytes32 hash = keccak256(_code); - return cache[hash]; - } - - function write(bytes _code) public returns (address target) { - assembly { - target := create(0, add(_code, 0x20), mload(_code)) - switch iszero(extcodesize(target)) - case 1 { - // throw if contract failed to deploy - revert(0, 0) - } - } - bytes32 hash = keccak256(_code); - cache[hash] = target; - } -} \ No newline at end of file diff --git a/ProxyRegistry.sol b/ProxyRegistry.sol index 37928f7..a7ff67a 100644 --- a/ProxyRegistry.sol +++ b/ProxyRegistry.sol @@ -1,5 +1,6 @@ pragma solidity ^0.4.23; + contract UserAuthority { function canCall(address src, address dst, bytes4 sig) public view returns (bool); } @@ -77,35 +78,31 @@ contract UserNote { } } +interface LogicRegistry { + function getLogic(address logicAddr) external view returns(bool); +} + +contract LogicProxy { + address public logicProxyAddr; + + function isLogic(address logicAddr) internal view returns(bool) { + LogicRegistry logicProxy = LogicRegistry(logicProxyAddr); + return logicProxy.getLogic(logicAddr); + } +} + // UserProxy // Allows code execution using a persistant identity This can be very // useful to execute a sequence of atomic actions. Since the owner of // the proxy can be changed, this allows for dynamic ownership models // i.e. a multisig -contract UserProxy is UserAuth, UserNote { - UserProxyCache public cache; // global cache for contracts +contract UserProxy is UserAuth, UserNote, LogicProxy { - constructor(address _cacheAddr) public { - setCache(_cacheAddr); + constructor(address logicProxyAddr_) public { + logicProxyAddr = logicProxyAddr_; } - function() external payable { - } - - // use the proxy to execute calldata _data on contract _code - function execute(bytes memory _code, bytes memory _data) - public - payable - returns (address target, bytes memory response) - { - target = cache.read(_code); - if (target == address(0)) { - // deploy contract & store its address in cache - target = cache.write(_code); - } - - response = execute(target, _data); - } + function() external payable {} function execute(address _target, bytes memory _data) public @@ -114,7 +111,8 @@ contract UserProxy is UserAuth, UserNote { payable returns (bytes memory response) { - require(_target != address(0), "User-proxy-target-address-required"); + require(_target != address(0), "user-proxy-target-address-required"); + require(isLogic(_target), "invalid-logic-proxy-address"); // call contract in current context assembly { @@ -133,68 +131,29 @@ contract UserProxy is UserAuth, UserNote { } } } - - //set new cache - function setCache(address _cacheAddr) - public - auth - note - returns (bool) - { - require(_cacheAddr != address(0), "User-proxy-cache-address-required"); - cache = UserProxyCache(_cacheAddr); // overwrite cache - return true; - } -} - -// UserProxyCache -// This global cache stores addresses of contracts previously deployed -// by a proxy. This saves gas from repeat deployment of the same -// contracts and eliminates blockchain bloat. - -// By default, all proxies deployed from the same factory store -// contracts in the same cache. The cache a proxy instance uses can be -// changed. The cache uses the sha3 hash of a contract's bytecode to -// lookup the address -contract UserProxyCache { - mapping(bytes32 => address) cache; - - function read(bytes memory _code) public view returns (address) { - bytes32 hash = keccak256(_code); - return cache[hash]; - } - - function write(bytes memory _code) public returns (address target) { - assembly { - target := create(0, add(_code, 0x20), mload(_code)) - switch iszero(extcodesize(target)) - case 1 { - // throw if contract failed to deploy - revert(0, 0) - } - } - bytes32 hash = keccak256(_code); - cache[hash] = target; - } } // ProxyRegistry contract ProxyRegistry { event Created(address indexed sender, address indexed owner, address proxy); - mapping(address => DSProxy) public proxies; - DSProxyCache cache = new DSProxyCache(); + mapping(address => UserProxy) public proxies; + address public logicProxyAddr; + + constructor(address logicProxyAddr_) public { + logicProxyAddr = logicProxyAddr_; + } // deploys a new proxy instance // sets owner of proxy to caller - function build() public returns (DSProxy proxy) { + function build() public returns (UserProxy proxy) { proxy = build(msg.sender); } // deploys a new proxy instance // sets custom owner of proxy - function build(address owner) public returns (DSProxy proxy) { - require(proxies[owner] == DSProxy(0) || proxies[owner].owner() != owner); // Not allow new proxy if the user already has one and remains being the owner - proxy = new DSProxy(cache); + function build(address owner) public returns (UserProxy proxy) { + require(proxies[owner] == UserProxy(0) || proxies[owner].owner() != owner); // Not allow new proxy if the user already has one and remains being the owner + proxy = new UserProxy(logicProxyAddr); emit Created(msg.sender, owner, address(proxy)); proxy.setOwner(owner); proxies[owner] = proxy; diff --git a/UserProxy.sol b/UserProxy.sol index 7486ec7..897c85a 100644 --- a/UserProxy.sol +++ b/UserProxy.sol @@ -1,5 +1,6 @@ pragma solidity ^0.4.23; + contract UserAuthority { function canCall(address src, address dst, bytes4 sig) public view returns (bool); } @@ -77,35 +78,31 @@ contract UserNote { } } +interface LogicRegistry { + function getLogic(address logicAddr) external view returns(bool); +} + +contract LogicProxy { + address public logicProxyAddr; + + function isLogic(address logicAddr) internal view returns(bool) { + LogicRegistry logicProxy = LogicRegistry(logicProxyAddr); + return logicProxy.getLogic(logicAddr); + } +} + // UserProxy // Allows code execution using a persistant identity This can be very // useful to execute a sequence of atomic actions. Since the owner of // the proxy can be changed, this allows for dynamic ownership models // i.e. a multisig -contract UserProxy is UserAuth, UserNote { - UserProxyCache public cache; // global cache for contracts +contract UserProxy is UserAuth, UserNote, LogicProxy { - constructor(address _cacheAddr) public { - setCache(_cacheAddr); + constructor(address logicProxyAddr_) public { + logicProxyAddr = logicProxyAddr_; } - function() external payable { - } - - // use the proxy to execute calldata _data on contract _code - function execute(bytes memory _code, bytes memory _data) - public - payable - returns (address target, bytes memory response) - { - target = cache.read(_code); - if (target == address(0)) { - // deploy contract & store its address in cache - target = cache.write(_code); - } - - response = execute(target, _data); - } + function() external payable {} function execute(address _target, bytes memory _data) public @@ -114,7 +111,8 @@ contract UserProxy is UserAuth, UserNote { payable returns (bytes memory response) { - require(_target != address(0), "User-proxy-target-address-required"); + require(_target != address(0), "user-proxy-target-address-required"); + require(isLogic(_target), "invalid-logic-proxy-address"); // call contract in current context assembly { @@ -133,47 +131,4 @@ contract UserProxy is UserAuth, UserNote { } } } - - //set new cache - function setCache(address _cacheAddr) - public - auth - note - returns (bool) - { - require(_cacheAddr != address(0), "User-proxy-cache-address-required"); - cache = UserProxyCache(_cacheAddr); // overwrite cache - return true; - } -} - -// UserProxyCache -// This global cache stores addresses of contracts previously deployed -// by a proxy. This saves gas from repeat deployment of the same -// contracts and eliminates blockchain bloat. - -// By default, all proxies deployed from the same factory store -// contracts in the same cache. The cache a proxy instance uses can be -// changed. The cache uses the sha3 hash of a contract's bytecode to -// lookup the address -contract UserProxyCache { - mapping(bytes32 => address) cache; - - function read(bytes memory _code) public view returns (address) { - bytes32 hash = keccak256(_code); - return cache[hash]; - } - - function write(bytes memory _code) public returns (address target) { - assembly { - target := create(0, add(_code, 0x20), mload(_code)) - switch iszero(extcodesize(target)) - case 1 { - // throw if contract failed to deploy - revert(0, 0) - } - } - bytes32 hash = keccak256(_code); - cache[hash] = target; - } } \ No newline at end of file