diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index a60d32c50c..538e18567f 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -172,7 +172,7 @@ func (w *wizard) makeGenesis() { fmt.Println() fmt.Println("What is foundation wallet address? (default = 0x0000000000000000000000000000000000000068)") - genesis.Config.XDPoS.FoudationWalletAddr = w.readDefaultAddress(common.HexToAddress("0x0000000000000000000000000000000000000068")) + genesis.Config.XDPoS.FoudationWalletAddr = w.readDefaultAddress(common.HexToAddress(common.FoudationAddr)) // Validator Smart Contract Code pKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -206,6 +206,37 @@ func (w *wizard) makeGenesis() { Storage: storage, } + fmt.Println() + fmt.Println("Which accounts are allowed to confirm in MultiSignWallet?") + var owners []common.Address + for { + if address := w.readAddress(); address != nil { + owners = append(owners, *address) + continue + } + if len(owners) > 0 { + break + } + } + fmt.Println() + fmt.Println("How many require for confirm tx in MultiSignWallet? (default = 2)") + required := int64(w.readDefaultInt(2)) + + // MultiSigWallet. + multiSignWalletAddr, _, err := multiSignWalletContract.DeployMultiSigWallet(transactOpts, contractBackend, owners, big.NewInt(required)) + if err != nil { + fmt.Println("Can't deploy MultiSignWallet SMC") + } + contractBackend.Commit() + code, _ = contractBackend.CodeAt(ctx, multiSignWalletAddr, nil) + storage = make(map[common.Hash]common.Hash) + contractBackend.ForEachStorageAt(ctx, multiSignWalletAddr, nil, f) + genesis.Alloc[common.HexToAddress(common.FoudationAddr)] = core.GenesisAccount{ + Balance: big.NewInt(0), + Code: code, + Storage: storage, + } + // Block Signers Smart Contract blockSignerAddress, _, err := blockSignerContract.DeployBlockSigner(transactOpts, contractBackend, big.NewInt(int64(epochNumber))) if err != nil { @@ -238,6 +269,20 @@ func (w *wizard) makeGenesis() { Storage: storage, } + fmt.Println() + fmt.Println("What is swap wallet address for fund 55m XDC?") + swapAddr := w.readDefaultAddress(common.HexToAddress(common.FoudationAddr)) + baseBalance := big.NewInt(0) // 55m + baseBalance.Add(baseBalance, big.NewInt(55*1000*1000)) + baseBalance.Mul(baseBalance, big.NewInt(1000000000000000000)) + subBalance := big.NewInt(0) // 150k + subBalance.Add(subBalance, big.NewInt(150*1000)) + subBalance.Mul(subBalance, big.NewInt(1000000000000000000)) + baseBalance.Sub(baseBalance, subBalance) // 55m - 150k + genesis.Alloc[swapAddr] = core.GenesisAccount{ + Balance: baseBalance, + } + default: log.Crit("Invalid consensus engine choice", "choice", choice) } diff --git a/common/types.go b/common/types.go index 96ff8fa7c0..9836e28191 100644 --- a/common/types.go +++ b/common/types.go @@ -33,6 +33,7 @@ const ( BlockSigners = "0x0000000000000000000000000000000000000089" MasternodeVotingSMC = "0x0000000000000000000000000000000000000088" RandomizeSMC = "0x0000000000000000000000000000000000000090" + FoudationAddr = "0x0000000000000000000000000000000000000068" ) var ( diff --git a/contracts/multisigwallet/contract/MultiSigWallet.sol b/contracts/multisigwallet/contract/MultiSigWallet.sol new file mode 100644 index 0000000000..01f5e82479 --- /dev/null +++ b/contracts/multisigwallet/contract/MultiSigWallet.sol @@ -0,0 +1,370 @@ +pragma solidity ^0.4.21; + + +/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution. +/// @author Stefan George - +contract MultiSigWallet { + + /* + * Events + */ + event Confirmation(address indexed sender, uint indexed transactionId); + event Revocation(address indexed sender, uint indexed transactionId); + event Submission(uint indexed transactionId); + event Execution(uint indexed transactionId); + event ExecutionFailure(uint indexed transactionId); + event Deposit(address indexed sender, uint value); + event OwnerAddition(address indexed owner); + event OwnerRemoval(address indexed owner); + event RequirementChange(uint required); + + /* + * Constants + */ + uint constant public MAX_OWNER_COUNT = 50; + + /* + * Storage + */ + mapping (uint => Transaction) public transactions; + mapping (uint => mapping (address => bool)) public confirmations; + mapping (address => bool) public isOwner; + address[] public owners; + uint public required; + uint public transactionCount; + + struct Transaction { + address destination; + uint value; + bytes data; + bool executed; + } + + /* + * Modifiers + */ + modifier onlyWallet() { + require(msg.sender == address(this)); + _; + } + + modifier ownerDoesNotExist(address owner) { + require(!isOwner[owner]); + _; + } + + modifier ownerExists(address owner) { + require(isOwner[owner]); + _; + } + + modifier transactionExists(uint transactionId) { + require(transactions[transactionId].destination != 0); + _; + } + + modifier confirmed(uint transactionId, address owner) { + require(confirmations[transactionId][owner]); + _; + } + + modifier notConfirmed(uint transactionId, address owner) { + require(!confirmations[transactionId][owner]); + _; + } + + modifier notExecuted(uint transactionId) { + require(!transactions[transactionId].executed); + _; + } + + modifier notNull(address _address) { + require(_address != 0); + _; + } + + modifier validRequirement(uint ownerCount, uint _required) { + require(ownerCount <= MAX_OWNER_COUNT + && _required <= ownerCount + && _required != 0 + && ownerCount != 0); + _; + } + + /// @dev Fallback function allows to deposit ether. + function() + payable + { + if (msg.value > 0) + Deposit(msg.sender, msg.value); + } + + /* + * Public functions + */ + /// @dev Contract constructor sets initial owners and required number of confirmations. + /// @param _owners List of initial owners. + /// @param _required Number of required confirmations. + function MultiSigWallet(address[] _owners, uint _required) + public + validRequirement(_owners.length, _required) + { + for (uint i=0; i<_owners.length; i++) { + require(!isOwner[_owners[i]] && _owners[i] != 0); + isOwner[_owners[i]] = true; + } + owners = _owners; + required = _required; + } + + /// @dev Allows to add a new owner. Transaction has to be sent by wallet. + /// @param owner Address of new owner. + function addOwner(address owner) + public + onlyWallet + ownerDoesNotExist(owner) + notNull(owner) + validRequirement(owners.length + 1, required) + { + isOwner[owner] = true; + owners.push(owner); + OwnerAddition(owner); + } + + /// @dev Allows to remove an owner. Transaction has to be sent by wallet. + /// @param owner Address of owner. + function removeOwner(address owner) + public + onlyWallet + ownerExists(owner) + { + isOwner[owner] = false; + for (uint i=0; i owners.length) + changeRequirement(owners.length); + OwnerRemoval(owner); + } + + /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet. + /// @param owner Address of owner to be replaced. + /// @param newOwner Address of new owner. + function replaceOwner(address owner, address newOwner) + public + onlyWallet + ownerExists(owner) + ownerDoesNotExist(newOwner) + { + for (uint i=0; i