Skip to content

Instantly share code, notes, and snippets.

@izqui
Last active June 17, 2018 16:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save izqui/1f9847dddd5f399bbc3879b1cf1c69fe to your computer and use it in GitHub Desktop.
Save izqui/1f9847dddd5f399bbc3879b1cf1c69fe to your computer and use it in GitHub Desktop.
Quick spike to demonstrate a generic account proxy pattern and a specific implementation for cold/hot wallets. Not reviewed, use it at your own risk.
contract AccountProxy {
event Fwded(address indexed to, uint256 value, bytes calldata, bool succeeded);
// must be implemented by super contract
function canFwd(address who, address to, uint256 value, bytes calldata) public view returns (bool);
function () payable {} // allow to deposit eth
function fwd(address to, uint256 value, bytes calldata) external {
require(canFwd(msg.sender, to, value, calldata));
bool succeeded = to.call.value(value)(calldata);
emit Fwded(to, value, calldata, succeeded);
}
}
contract HotColdProxy is AccountProxy {
address public hot;
address public cold;
mapping (bytes4 => bool) onlyColdFunctions;
mapping (address => bool) onlyColdAddresses;
constructor (address _cold, address _hot, bytes4[] _onlyColdFunctions, address[] _onlyColdAddresses) public {
cold = _cold;
hot = _hot;
for (uint i = 0; i < _onlyColdFunctions.length; i++) {
onlyColdFunctions[_onlyColdFunctions[i]] = true;
}
for (uint j = 0; j < _onlyColdAddresses.length; j++) {
onlyColdAddresses[_onlyColdAddresses[j]] = true;
}
onlyColdAddresses[this] = true;
}
function changeHot(address _hot) external {
require(msg.sender == address(this)); // proxy must call itself to allow flexibility
hot = _hot;
}
function changeCold(address _cold) external {
require(msg.sender == _cold); // could also require for proxy to call itself, but it is sensible to limit it to only cold
cold = _cold;
}
function canFwd(address who, address to, uint256 value, bytes calldata) public view returns (bool) {
if (who == hot) {
bool onlyCold = value > 0 || onlyColdAddresses[to] || onlyColdFunctions[sig(calldata)];
return !onlyCold;
}
return who == cold;
}
// TODO: Functions to change onlyCold addresses and functions
function sig(bytes calldata) internal pure returns (bytes4 sig) {
assembly { sig := mload(calldata) }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment