diff --git a/contracts/MultiSigFactory.sol b/contracts/MultiSigFactory.sol deleted file mode 100644 index 62bc00a..0000000 --- a/contracts/MultiSigFactory.sol +++ /dev/null @@ -1,14 +0,0 @@ -pragma solidity ^0.4.15; - -import "./MultiSigStub.sol"; - -contract MultiSigFactory { - - event Create(address indexed caller, address createdContract); - - function create(address[] owners, uint256 required) returns (address wallet) { - wallet = new MultiSigStub(owners, required); - Create(msg.sender, wallet); - } - -} \ No newline at end of file diff --git a/contracts/MultiSigStub.sol b/contracts/MultiSigStub.sol deleted file mode 100644 index 4857129..0000000 --- a/contracts/MultiSigStub.sol +++ /dev/null @@ -1,232 +0,0 @@ -pragma solidity ^0.4.15; - -/** - * @title MultiSigStub - * Contract that delegates calls to a library to build a full MultiSigWallet that is cheap to create. - */ -contract MultiSigStub { - - address[] public owners; - address[] public tokens; - mapping (uint => Transaction) public transactions; - mapping (uint => mapping (address => bool)) public confirmations; - uint public transactionCount; - - struct Transaction { - address destination; - uint value; - bytes data; - bool executed; - } - - function MultiSigStub(address[] _owners, uint256 _required) { - //bytes4 sig = bytes4(sha3("constructor(address[],uint256)")); - bytes4 sig = 0x36756a23; - uint argarraysize = (2 + _owners.length); - uint argsize = (1 + argarraysize) * 32; - uint size = 4 + argsize; - bytes32 mData = _malloc(size); - - assembly { - mstore(mData, sig) - codecopy(add(mData, 0x4), sub(codesize, argsize), argsize) - } - _delegatecall(mData, size); - } - - modifier delegated { - uint size = msg.data.length; - bytes32 mData = _malloc(size); - - assembly { - calldatacopy(mData, 0x0, size) - } - - bytes32 mResult = _delegatecall(mData, size); - _; - assembly { - return(mResult, 0x20) - } - } - - function() - payable - delegated - { - - } - - function submitTransaction(address destination, uint value, bytes data) - public - delegated - returns (uint) - { - - } - - function confirmTransaction(uint transactionId) - public - delegated - { - - } - - function watch(address _tokenAddr) - public - delegated - { - - } - - function setMyTokenList(address[] _tokenList) - public - delegated - { - - } - /// @dev Returns the confirmation status of a transaction. - /// @param transactionId Transaction ID. - /// @return Confirmation status. - function isConfirmed(uint transactionId) - public - constant - delegated - returns (bool) - { - - } - - /* - * Web3 call functions - */ - function tokenBalances(address tokenAddress) - public - constant - delegated - returns (uint) - { - - } - - - /// @dev Returns number of confirmations of a transaction. - /// @param transactionId Transaction ID. - /// @return Number of confirmations. - function getConfirmationCount(uint transactionId) - public - constant - delegated - returns (uint) - { - - } - - /// @dev Returns total number of transactions after filters are applied. - /// @param pending Include pending transactions. - /// @param executed Include executed transactions. - /// @return Total number of transactions after filters are applied. - function getTransactionCount(bool pending, bool executed) - public - constant - delegated - returns (uint) - { - - } - - /// @dev Returns list of owners. - /// @return List of owner addresses. - function getOwners() - public - constant - returns (address[]) - { - return owners; - } - - /// @dev Returns list of tokens. - /// @return List of token addresses. - function getTokenList() - public - constant - returns (address[]) - { - return tokens; - } - - /// @dev Returns array with owner addresses, which confirmed transaction. - /// @param transactionId Transaction ID. - /// @return Returns array of owner addresses. - function getConfirmations(uint transactionId) - public - constant - returns (address[] _confirmations) - { - address[] memory confirmationsTemp = new address[](owners.length); - uint count = 0; - uint i; - for (i = 0; i < owners.length; i++) { - if (confirmations[transactionId][owners[i]]) { - confirmationsTemp[count] = owners[i]; - count += 1; - } - } - _confirmations = new address[](count); - for (i = 0; i < count; i++) { - _confirmations[i] = confirmationsTemp[i]; - } - } - - /// @dev Returns list of transaction IDs in defined range. - /// @param from Index start position of transaction array. - /// @param to Index end position of transaction array. - /// @param pending Include pending transactions. - /// @param executed Include executed transactions. - /// @return Returns array of transaction IDs. - function getTransactionIds(uint from, uint to, bool pending, bool executed) - public - constant - returns (uint[] _transactionIds) - { - uint[] memory transactionIdsTemp = new uint[](transactionCount); - uint count = 0; - uint i; - for (i = 0; i < transactionCount; i++) { - if (pending && !transactions[i].executed || executed && transactions[i].executed) { - transactionIdsTemp[count] = i; - count += 1; - } - } - _transactionIds = new uint[](to - from); - for (i = from; i < to; i++) { - _transactionIds[i - from] = transactionIdsTemp[i]; - } - } - - - function _malloc(uint size) - private - returns(bytes32 mData) - { - assembly { - mData := mload(0x40) - mstore(0x40, add(mData, size)) - } - } - - function _delegatecall(bytes32 mData, uint size) - private - returns(bytes32 mResult) - { - address target = 0xc0FFeEE61948d8993864a73a099c0E38D887d3F4; //Multinetwork - mResult = _malloc(32); - bool failed; - - assembly { - failed := iszero(delegatecall(sub(gas, 10000), target, mData, size, mResult, 0x20)) - } - - assert(!failed); - } - -} \ No newline at end of file diff --git a/contracts/common/Controlled.sol b/contracts/common/Controlled.sol new file mode 100644 index 0000000..334b6c5 --- /dev/null +++ b/contracts/common/Controlled.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.4.8; + +contract Controlled { + /// @notice The address of the controller is the only address that can call + /// a function with this modifier + modifier onlyController { + require(msg.sender == controller); + _; + } + + address public controller; + + function Controlled() public { + controller = msg.sender; + } + + /// @notice Changes the controller of the contract + /// @param _newController The new controller of the contract + function changeController(address _newController) public onlyController { + controller = _newController; + } +} diff --git a/contracts/deploy/DelegatedCall.sol b/contracts/deploy/DelegatedCall.sol new file mode 100644 index 0000000..0526c76 --- /dev/null +++ b/contracts/deploy/DelegatedCall.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.4.17; + + +/** + * @title DelegatedCall + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Abstract contract that delegates calls by `delegated` modifier to result of `targetDelegatedCall()` + * Important to avoid overwriting wrong storage pointers is that never define storage to this contract + */ +contract DelegatedCall { + /** + * @dev delegates the call of this function + */ + modifier delegated { + //require successfull delegate call to remote `_target()` + require(targetDelegatedCall().delegatecall(msg.data)); + assembly { + let outSize := returndatasize + let outDataPtr := mload(0x40) //load memory + returndatacopy(outDataPtr, 0, outSize) //copy last return into pointer + return(outDataPtr, outSize) + } + assert(false); //should never reach here + _; //never will execute local logic + } + + /** + * @dev defines the address for delegation of calls + */ + function targetDelegatedCall() + internal + constant + returns(address); + +} diff --git a/contracts/deploy/Factory.sol b/contracts/deploy/Factory.sol new file mode 100644 index 0000000..f63bf71 --- /dev/null +++ b/contracts/deploy/Factory.sol @@ -0,0 +1,57 @@ +pragma solidity ^0.4.17; + +import "../common/Controlled.sol"; + +contract Factory is Controlled { + + event NewKernel(address newKernel, bytes infohash); + + struct Version { + uint256 blockNumber; + uint256 timestamp; + address kernel; + bytes infohash; + } + mapping (address => uint256) versionMap; + + Version[] versionLog; + uint256 latestUpdate; + address latestKernel; + + function Factory(address _kernel, bytes _infohash) + public + { + _setKernel(_kernel, _infohash); + } + + function setKernel(address _kernel, bytes _infohash) + external + onlyController + { + _setKernel(_kernel, _infohash); + } + + function getVersion(uint256 index) public view + returns(uint256 blockNumber, + uint256 timestamp, + address kernel, + bytes infohash) + { + return (versionLog[index].blockNumber, + versionLog[index].timestamp, + versionLog[index].kernel, + versionLog[index].infohash); + } + + function _setKernel(address _kernel, bytes _infohash) + internal + { + require(_kernel != latestKernel); + versionMap[_kernel] = versionLog.length; + versionLog.push(Version({blockNumber: block.number, timestamp: block.timestamp, kernel: _kernel, infohash: _infohash})); + latestUpdate = block.timestamp; + latestKernel = _kernel; + NewKernel(_kernel, _infohash); + } + +} \ No newline at end of file diff --git a/contracts/deploy/Instance.sol b/contracts/deploy/Instance.sol new file mode 100644 index 0000000..f9d60cb --- /dev/null +++ b/contracts/deploy/Instance.sol @@ -0,0 +1,39 @@ +pragma solidity ^0.4.17; + +import "./InstanceStorage.sol"; +import "./DelegatedCall.sol"; + + +/** + * @title Instance + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Contract that forward everything through delegatecall to defined kernel + */ +contract Instance is InstanceStorage, DelegatedCall { + + function Instance(address _kernel) public { + kernel = _kernel; + } + + /** + * @dev delegatecall everything (but declared functions) to `_target()` + * @notice Verify `kernel()` code to predict behavior + */ + function () external delegated { + //all goes to kernel + } + + /** + * @dev returns kernel if kernel that is configured + * @return kernel address + */ + function targetDelegatedCall() + internal + constant + returns(address) + { + return kernel; + } + + +} \ No newline at end of file diff --git a/contracts/deploy/InstanceStorage.sol b/contracts/deploy/InstanceStorage.sol new file mode 100644 index 0000000..ba84f64 --- /dev/null +++ b/contracts/deploy/InstanceStorage.sol @@ -0,0 +1,15 @@ +pragma solidity ^0.4.17; + + +/** + * @title InstanceStorage + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Defines kernel vars that Kernel contract share with Instance. + * Important to avoid overwriting wrong storage pointers is that + * InstanceStorage should be always the first contract at heritance. + */ +contract InstanceStorage { + // protected zone start (InstanceStorage vars) + address public kernel; + // protected zone end +} \ No newline at end of file diff --git a/contracts/deploy/UpdatableInstance.sol b/contracts/deploy/UpdatableInstance.sol new file mode 100644 index 0000000..60f6d0a --- /dev/null +++ b/contracts/deploy/UpdatableInstance.sol @@ -0,0 +1,28 @@ +pragma solidity ^0.4.17; + +import "./Instance.sol"; + + +/** + * @title UpdatableInstance + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Contract that can be updated by a call from itself. + */ +contract UpdatableInstance is Instance { + + event InstanceUpdated(address oldKernel, address newKernel); + + function UpdatableInstance(address _kernel) + Instance(_kernel) + public + { + + } + + function updateUpdatableInstance(address _kernel) external { + require(msg.sender == address(this)); + InstanceUpdated(kernel, _kernel); + kernel = _kernel; + } + +} \ No newline at end of file diff --git a/contracts/open-bounty/BountyFactory.sol b/contracts/open-bounty/BountyFactory.sol new file mode 100644 index 0000000..3b92020 --- /dev/null +++ b/contracts/open-bounty/BountyFactory.sol @@ -0,0 +1,36 @@ +pragma solidity ^0.4.17; + +import "../deploy/Factory.sol"; +import "../deploy/UpdatableInstance.sol"; +import "./BountyKernel.sol"; + + +contract BountyFactory is Factory { + + event IdentityCreated(address instance); + + function BountyFactory(bytes _infohash) + public + Factory(initializeFirstVersion(), _infohash) + { + + } + + function initializeFirstVersion() private returns (address a){ + address[] memory dummyOwners = new address[](1); + dummyOwners[0] = address(this); + a = address(new BountyKernel(dummyOwners)); + } + + function createBounty(address _pivot, address _repoOwner) + public + { + BountyKernel instance = BountyKernel(new UpdatableInstance(address(latestKernel))); + address[] memory multisigOwners = new address[](2); + multisigOwners[0] = _pivot; + multisigOwners[1] = _repoOwner; + instance.initBounty(multisigOwners, 2); + IdentityCreated(address(instance)); + } + +} diff --git a/contracts/open-bounty/BountyKernel.sol b/contracts/open-bounty/BountyKernel.sol new file mode 100644 index 0000000..383fea0 --- /dev/null +++ b/contracts/open-bounty/BountyKernel.sol @@ -0,0 +1,38 @@ +pragma solidity ^0.4.17; + +import "../deploy/InstanceStorage.sol"; +import "./MultiSigTokenWallet.sol"; + +/** + * + */ +contract BountyKernel is InstanceStorage, MultiSigTokenWallet { + + + function BountyKernel(address[] _dummyOwners) MultiSigTokenWallet(_dummyOwners,1) public { + //remove ownership of Kernel + uint len = _dummyOwners.length; + for (uint i = 0; i < len; i++) { + delete isOwner[_dummyOwners[i]]; + } + delete owners; + //keep required > 0 to prevent initialization + required = 1; + } + + + /// @dev Instance constructor sets initial owners and required number of confirmations. + /// @param _owners List of initial owners. + /// @param _required Number of required confirmations. + function initBounty(address[] _owners, uint _required) external { + require(owners.length == 0 && required == 0); + uint len = _owners.length; + for (uint i = 0; i < len; i++) { + require(!isOwner[_owners[i]] && _owners[i] != 0); + isOwner[_owners[i]] = true; + } + owners = _owners; + required = _required; + } + +} diff --git a/contracts/MultiSigTokenWallet.sol b/contracts/open-bounty/MultiSigTokenWallet.sol similarity index 99% rename from contracts/MultiSigTokenWallet.sol rename to contracts/open-bounty/MultiSigTokenWallet.sol index 80d16c7..46290d8 100644 --- a/contracts/MultiSigTokenWallet.sol +++ b/contracts/open-bounty/MultiSigTokenWallet.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.15; -import "./ERC20Token.sol"; +import "../token/ERC20Token.sol"; contract MultiSigTokenWallet { diff --git a/contracts/TokenReg.sol b/contracts/registry/TokenReg.sol similarity index 100% rename from contracts/TokenReg.sol rename to contracts/registry/TokenReg.sol diff --git a/contracts/ERC20Token.sol b/contracts/token/ERC20Token.sol similarity index 100% rename from contracts/ERC20Token.sol rename to contracts/token/ERC20Token.sol diff --git a/contracts/TestToken.sol b/contracts/token/TestToken.sol similarity index 95% rename from contracts/TestToken.sol rename to contracts/token/TestToken.sol index 2a045e8..4544cab 100644 --- a/contracts/TestToken.sol +++ b/contracts/token/TestToken.sol @@ -1,7 +1,9 @@ -pragma solidity ^0.4.14; +pragma solidity ^0.4.18; + +import "./ERC20Token.sol"; /// @title Test token contract - Allows testing of token transfers with multisig wallet. -contract TestToken { +contract TestToken is ERC20Token { event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); @@ -14,7 +16,7 @@ contract TestToken { string public symbol; uint8 public decimals; - function TestToken(string _name, string _symbol, uint8 _decimals) { + function TestToken(string _name, string _symbol, uint8 _decimals) public { require(bytes(_name).length > 0); require(bytes(_symbol).length > 0); name = _name;