Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x490f82F5...E90c9235f The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
MultiSigNode
Compiler Version
v0.5.0+commit.1d4f565a
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2019-04-18 */ pragma solidity >=0.5.0 <0.6.0; /** * Author: Sik Jean Soon */ /** * @title SafeMath for uint256 * @dev Math operations with safety checks that throw on error */ library SafeMathUint256 { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { if (a == 0) { return 0; } c = a * b; require(c / a == b, "Multiplier exception"); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; // Solidity automatically throws when dividing by 0 } /** * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "Subtraction exception"); return a - b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256 c) { c = a + b; require(c >= a, "Addition exception"); return c; } /** * @dev Divides two numbers and returns the remainder (unsigned integer modulo), * reverts when dividing by zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "Modulo exception"); return a % b; } } /** * @title SafeMath for uint8 * @dev Math operations with safety checks that throw on error */ library SafeMathUint8 { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint8 a, uint8 b) internal pure returns (uint8 c) { if (a == 0) { return 0; } c = a * b; require(c / a == b, "Multiplier exception"); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint8 a, uint8 b) internal pure returns (uint8) { return a / b; // Solidity automatically throws when dividing by 0 } /** * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint8 a, uint8 b) internal pure returns (uint8) { require(b <= a, "Subtraction exception"); return a - b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint8 a, uint8 b) internal pure returns (uint8 c) { c = a + b; require(c >= a, "Addition exception"); return c; } /** * @dev Divides two numbers and returns the remainder (unsigned integer modulo), * reverts when dividing by zero. */ function mod(uint8 a, uint8 b) internal pure returns (uint8) { require(b != 0, "Modulo exception"); return a % b; } } contract Common { bytes32 internal LABEL_CODE_STAKER; bytes32 internal LABEL_CODE_STAKER_CONTROLLER; bytes32 internal LABEL_CODE_SIGNER_CONTROLLER; bytes32 internal LABEL_CODE_SIGNER; bytes32 internal LABEL_CODE_BACKSYS; bytes32 internal LABEL_CODE_OPS; uint8 constant internal MAX_WALLET = 64; uint256 constant internal WALLET_FLAG_ALL = (2 ** (uint256(MAX_WALLET))) - 1; constructor() public { LABEL_CODE_STAKER = encodePacked("STAKER"); LABEL_CODE_STAKER_CONTROLLER = encodePacked("STAKER_CONTROLLER"); LABEL_CODE_SIGNER_CONTROLLER = encodePacked("SIGNER_CONTROLLER"); LABEL_CODE_SIGNER = encodePacked("SIGNER"); LABEL_CODE_BACKSYS = encodePacked("BACKSYS"); LABEL_CODE_OPS = encodePacked("OPS"); } function encodePacked(string memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked(s)); } function convertBytesToBytes4(bytes memory _in) internal pure returns (bytes4 out) { if (0 == _in.length) return 0x0; assembly { out := mload(add(_in, 32)) } } function isContract(address _address) internal view returns (bool) { uint32 size; assembly { size := extcodesize(_address) } return (0 < size); } } contract Label is Common { string public class; string public label; string public description; bytes32 public classCode; bytes32 public labelCode; constructor(string memory _class, string memory _label, string memory _description) public { class = _class; label = _label; description = _description; classCode = encodePacked(_class); labelCode = encodePacked(_label); } } contract MultiSigNode is Label { using SafeMathUint8 for uint8; address payable public root; address public parent; // wallet index => wallet address mapping(uint8 => address) public wallets; // wallet address => wallet bit position mapping(address => uint8) public walletsIndex; // Normal wallet uint8 public walletCount; // Total wallet = normal wallet + contract wallet uint8 public totalWallet; modifier onlyRoot() { require(msg.sender == root, "Node.onlyRoot: Access denied"); _; } constructor(address payable _root, address[] memory _wallets, string memory _label, string memory _description) public Label("NODE", _label, _description) { require(address(0) != _root, "Node: Root address is empty"); require(MAX_WALLET >= _wallets.length, "Node: Wallet list exceeded limit"); root = _root; for (uint8 i = 1; _wallets.length >= i; i = i.add(1)) { address wallet = _wallets[i.sub(1)]; require(address(0) != wallet, "Node: Wallet address is empty"); require(0 == walletsIndex[wallet], "Node: Duplicated wallet address"); wallets[i] = wallet; walletsIndex[wallet] = i; if (!isContract(wallet)) walletCount = walletCount.add(1); } totalWallet = uint8(_wallets.length); } function init(address _parent) external onlyRoot { parent = _parent; if (0 < totalWallet) { uint8 count = 0; for (uint8 i = 1; i <= MAX_WALLET && count <= totalWallet; i = i.add(1)) { address wallet = wallets[i]; if (address(0) != wallet) { count = count.add(1); // Notify root this attached wallet, root will set parent address (if this is node) MultiSigRoot(root).attachWalletOrNode(wallet); } } } } function term() external onlyRoot { if (0 < totalWallet) { uint8 count = 0; for (uint8 i = 1; i <= MAX_WALLET && count <= totalWallet; i = i.add(1)) { address wallet = wallets[i]; if (address(0) != wallet) { count = count.add(1); // Notify root to remove this wallet from list MultiSigRoot(root).detachWalletOrNode(wallet); } } } } function attach(uint8 _index, address _wallet) external onlyRoot returns (bool) { require(0 < _index && MAX_WALLET >= _index, "Node.attach: Index out of range"); require(address(0) != _wallet, "Node.attach: Wallet address is empty"); require(0 == walletsIndex[_wallet], "Node.attach: Duplicated wallet address"); if (address(0) != wallets[_index]) detach(wallets[_index]); walletsIndex[_wallet] = _index; wallets[_index] = _wallet; if (!isContract(_wallet)) walletCount = walletCount.add(1); totalWallet = totalWallet.add(1); // Notify root this attached wallet, root will trigger attach operation (if this wallet is a contract) MultiSigRoot(root).attachWalletOrNode(_wallet); return true; } function detach(address _wallet) public onlyRoot returns (bool) { require(address(0) != _wallet, "Node.detach: Wallet address is empty"); uint8 index = walletsIndex[_wallet]; require(0 < index && MAX_WALLET >= index, "Node.detach: Wallet address is not registered"); if (!isContract(_wallet)) walletCount = walletCount.sub(1); totalWallet = totalWallet.sub(1); delete wallets[index]; delete walletsIndex[_wallet]; // Notify root to remove this wallet from list MultiSigRoot(root).detachWalletOrNode(_wallet); return true; } function getRootNode() external view returns (address) { if (address(0) == parent) return address(this); return MultiSigNode(parent).getRootNode(); } } /** * NOTE: Regulator is meant for changable rules for multi-sig */ contract MultiSigRegulator is Label { using SafeMathUint8 for uint8; using SafeMathUint256 for uint256; event TransactionLimitChanged(string requirementType, uint256 limit); address payable public root; address private creator; // Cached parameters address private argTo; uint256 private argValue; bool public isSealed; // Daily transaction limit (mapped: requirement type => TransactionLimit) mapping(bytes32 => TransactionLimit) public transactionLimits; struct TransactionLimit { uint256 datetime; uint256 volume; uint256 upperLimit; } modifier onlySealed() { require(isSealed, "Regulator.onlySealed: Not sealed"); _; } modifier onlyMe() { require(msg.sender == address(this), "Regulator.onlyMe: Access denied"); _; } modifier onlyRoot() { require(msg.sender == root, "Regulator.onlyRoot: Access denied"); _; } modifier onlyCreator() { require(msg.sender == creator, "Regulator.onlyCreator: Access denied"); _; } /** * Supported non-payable default function */ function () external onlyMe onlySealed { revert("Regulator: Not supported"); } constructor(address payable _root, string memory _label, string memory _description) public Label("REGULATOR", _label, _description) { require(address(0) != _root, "Regulator: Root address is empty"); root = _root; creator = msg.sender; } /** * Supported non-payable function: ERC_ER_SHI.increaseSupply * Only can be called by this contract itself to resolve calldata */ function increaseSupply(uint256 _value, address /* _to */) external onlyMe onlySealed { defaultRequirement("increaseSupply", _value); } /** * Supported non-payable function: ERC_ER_SHI.decreaseSupply * Only can be called by this contract itself to resolve calldata */ function decreaseSupply(uint256 _value, address /* _from */) external onlyMe onlySealed { defaultRequirement("decreaseSupply", _value); } /** * Supported non-payable function: ERC_ER_SHI.freeze * Only can be called by this contract itself to resolve calldata */ function freeze(address /* _from */, uint256 /* _value */) external onlyMe onlySealed { requirement1Backsys(); } /** * Supported non-payable function: ERC_ER_SHI.unfreeze * Only can be called by this contract itself to resolve calldata */ function unfreeze(address /* _from */, uint256 /* _value */) external onlyMe onlySealed { requirement1Backsys(); } /** * Supported non-payable function: ERC_ER_SHI.freezeAddress * Only can be called by this contract itself to resolve calldata */ function freezeAddress(address /* _addressOf */) external onlyMe onlySealed { requirement1Backsys(); } /** * Supported non-payable function: ERC_ER_SHI.unfreezeAddress * Only can be called by this contract itself to resolve calldata */ function unfreezeAddress(address /* _addressOf */) external onlyMe onlySealed { requirement1Backsys(); } /** * Supported non-payable function: Ownership.acceptOwnership * Only can be called by this contract itself to resolve calldata */ function acceptOwnership () external onlyMe onlySealed { requirement(LABEL_CODE_OPS, 2, 1); // INDEX 2: ONE SIGNABLE requirement(LABEL_CODE_SIGNER_CONTROLLER, 1, 1); // INDEX 1: ONE SIGNABLE } /** * Supported non-payable function: Ownership.transferOwnership * Only can be called by this contract itself to resolve calldata */ function transferOwnership (address payable /* _newOwner */) external onlyMe onlySealed { requirement(LABEL_CODE_STAKER, WALLET_FLAG_ALL, 1); // ANY ONE SIGNABLE requirement(LABEL_CODE_STAKER_CONTROLLER, WALLET_FLAG_ALL, uint8(-1)); // ALL SIGNABLE requirement(LABEL_CODE_SIGNER_CONTROLLER, WALLET_FLAG_ALL, 1); // ANY ONE SIGNABLE } /** * Supported non-payable function: Controllable.pause * Only can be called by this contract itself to resolve calldata */ function pause () external onlyMe onlySealed { requirement(LABEL_CODE_STAKER_CONTROLLER, WALLET_FLAG_ALL, 1); // ANY ONE SIGNABLE } /** * Supported non-payable function: Controllable.resume * Only can be called by this contract itself to resolve calldata */ function resume () external onlyMe onlySealed { requirement(LABEL_CODE_STAKER_CONTROLLER, WALLET_FLAG_ALL, 2); // ANY TWO SIGNABLE } /** * Supported non-payable function: MultiSigRegulator.setTransactionLimit */ function setTransactionLimit(string calldata _requirementType, uint256 _limit) external { if (msg.sender == root || !isSealed) { // Set transaction limit transactionLimits[encodePacked(_requirementType)].upperLimit = _limit; emit TransactionLimitChanged(_requirementType, _limit); } else { require(msg.sender == address(this), "Regulator.setTransactionLimit: Access denied"); // Create requirements for this transaction requirement(LABEL_CODE_STAKER_CONTROLLER, WALLET_FLAG_ALL, 2); // ANY TWO SIGNABLE } } function seal() external onlyCreator { require(!isSealed, "Regulator.seal: Access denied"); isSealed = true; } function createRequirement(uint256 /* _transactionCode */, address /* _from */, address _to, uint256 _value, bytes calldata _data) external onlyRoot { // Cache parameters argTo = _to; argValue = _value; // Perform self call to determine function details for requirement setup (bool success, bytes memory returnData) = address(this).call.value(_value)(_data); if (!success) { // Check the error string is available or not if (0 == returnData.length || bytes4(0x08c379a0) != convertBytesToBytes4(returnData)) revert("Regulator.createRequirement: Function call failed"); else { bytes memory bytesArray = new bytes(returnData.length); for (uint256 i = 0; i < returnData.length.sub(4); i = i.add(1)) { bytesArray[i] = returnData[i.add(4)]; } (string memory reason) = abi.decode(bytesArray, (string)); revert(reason); } } } function requirement(bytes32 _labelCode, uint256 _flag, uint8 _required) private { MultiSigRoot(root).createRequirement(_labelCode, _flag, _required); } function defaultRequirement(string memory _requirementType, uint256 _value) private { bytes32 t = encodePacked(_requirementType); // Check transaction volume limit TransactionLimit storage limit = transactionLimits[t]; // Check transaction volume limit if (0 < limit.upperLimit) { // Truncate timestamp (YYYYMMDD) to daily (UTC time) uint256 dt = now - (now % 86400); if (dt == limit.datetime) limit.volume = limit.volume.add(_value); else { // Reset volume on new day limit.datetime = dt; limit.volume = _value; } require(limit.upperLimit >= limit.volume, "Regulator.defaultRequirement: Exceeded limit"); } // Create requirement for this transaction requirement(LABEL_CODE_OPS, WALLET_FLAG_ALL, 4); // ANY FOUR SIGNABLE } function requirement1Backsys() private { requirement(LABEL_CODE_BACKSYS, WALLET_FLAG_ALL, 1); // ANY ONE SIGNABLE } } contract MultiSigRoot is Label { using SafeMathUint8 for uint8; using SafeMathUint256 for uint256; uint8 constant private WALLET_TYPE_WALLET = 1; uint8 constant private WALLET_TYPE_NODE = 2; uint8 constant private TRANSACTION_STATUS_EMPTY = 0; uint8 constant private TRANSACTION_STATUS_PENDING = 1; uint8 constant private TRANSACTION_STATUS_EXECUTED = 2; uint8 constant private TRANSACTION_STATUS_FAILURE = 3; uint8 constant private TRANSACTION_STATUS_REVOKED = 4; event Confirmation(address indexed sender, uint256 indexed transactionCode); event Revocation(address indexed sender, uint256 indexed transactionCode); event Submission(uint256 indexed transactionCode); event Requirement(uint256 indexed transactionCode, bytes32 labelCode, uint256 flag, uint8 required); event Execution(uint256 indexed transactionCode); event ExecutionFailure(uint256 indexed transactionCode); event Deposit(address indexed sender, uint256 value); event StakersChanged(address indexed stakers); event SignersChanged(address indexed signers); event RegulatorChanged(address indexed regulator); event StakersControllerChanged(address indexed stakersController); event SignersControllerChanged(address indexed signersController); event WalletOrNodeAttached(address indexed wallet); event WalletOrNodeDetached(address indexed wallet); address public stakers; address public signers; address public stakersController; address public signersController; address public regulator; // Transaction (mapped: transactionCode => Transaction) mapping(uint256 => Transaction) public transactions; uint256 public transactionCode; // Requirement (mapped: transactionCode + label code => requirement) mapping(uint256 => mapping(bytes32 => TransactionRequirement)) public requirements; // Prevent duplicated confirmation (mapped: transactionCode + wallet address => bool) mapping(uint256 => mapping(address => bool)) public confirmations; // Registered wallets or nodes (mapped: address => type) mapping(address => uint8) public registered; // Search node address by wallet address (mapped: wallet address => node address) mapping(address => address) public walletToNodes; // Search wallet index by wallet address (mapped: wallet address => wallet index) mapping(address => uint8) private walletToIndexes; // Search label code by wallet address (mapped: wallet address => label code) mapping(address => bytes32) private walletToLabelCodes; // Search node address by label code (mapped: label code => node address) mapping(bytes32 => address) private labelCodeToNodes; struct Transaction { uint8 status; uint8 totalRequired; address to; uint256 value; bytes data; string reason; } struct TransactionRequirement { uint8 required; uint256 flag; } modifier onlyEligible(uint256 _transactionCode) { require(isEligible(_transactionCode, msg.sender), "Root.onlyEligible: Not eligible"); _; } modifier onlySignable(uint256 _transactionCode) { require(isSignable(_transactionCode, msg.sender), "Root.onlySignable: Not signable"); _; } modifier onlyNode() { require(WALLET_TYPE_NODE == registered[msg.sender], "Root.onlyNode: Access denied"); _; } modifier onlyWallet() { require(WALLET_TYPE_WALLET == registered[msg.sender], "Root.onlyWallet: Access denied"); require(!isContract(msg.sender), "Root.onlyWallet: Is not node"); _; } modifier onlyRegulator() { require(msg.sender == regulator, "Root.onlyRegulator: Access denied"); _; } constructor(string memory _label, string memory _description) public Label("ROOT", _label, _description) { } function () external payable { if (0 < msg.value) emit Deposit(msg.sender, msg.value); } function isEligible(uint256 _transactionCode, address _sender) public view returns (bool) { uint256 flag = requirements[_transactionCode][walletToLabelCodes[_sender]].flag; if (0 != flag) { uint8 index = walletToIndexes[_sender]; if (0 != index) { index = index.sub(1); // Check the bit is on for wallet index return (0 != ((flag >> index) & 1)); } } return false; } function isSignable(uint256 _transactionCode, address _sender) public view returns (bool) { if (TRANSACTION_STATUS_PENDING == transactions[_transactionCode].status) { if (!confirmations[_transactionCode][_sender]) { if (0 != requirements[_transactionCode][walletToLabelCodes[_sender]].required) return true; } } return false; } function createRequirement(bytes32 _labelCode, uint256 _flag, uint8 _required) external onlyRegulator { setRequirement(_labelCode, _flag, _required); } function setRequirement(bytes32 _labelCode, uint256 _flag, uint8 _required) private { require(0 < _flag, "Root.setRequirement: Confirmation flag is empty"); uint8 totalRequired; // Required all wallet in the node if (uint8(-1) == _required) { address node = labelCodeToNodes[_labelCode]; require(address(0) != node, "Root.setRequirement: Node is not found"); totalRequired = MultiSigNode(node).walletCount(); if (node != signers) { // Stakers and controllers must have at least 1 wallet attached require(0 < totalRequired, "Root.setRequirement: No wallet"); } else { // Signer node allowed to be empty if (0 == totalRequired) return; } require(0 < totalRequired, "Root.setRequirement: Confirmation required is empty"); } else { // allowed 0 requirement, in order to support eligible user but not signable (view transaction only) totalRequired = _required; } require(0 == requirements[transactionCode][_labelCode].flag, "Root.setRequirement: Duplicated requirement"); requirements[transactionCode][_labelCode] = TransactionRequirement({ required: totalRequired, flag: _flag }); // Increase total required in transaction transactions[transactionCode].totalRequired = transactions[transactionCode].totalRequired.add(totalRequired); emit Requirement(transactionCode, _labelCode, _flag, totalRequired); } function submit(address _to, uint256 _value, bytes calldata _data) external onlyWallet returns (uint256 /* transactionCode */) { require(address(0) != _to, "Root.submit: Target address is empty"); // Generate transaction id transactionCode = transactionCode.add(1); bytes4 functionId = convertBytesToBytes4(_data); // Create requirement that based on destination address if (address(this) != _to) { // Check this is node address or not if (WALLET_TYPE_NODE == registered[_to]) { // Calling node function // - 0x80882800: node.attach // - 0xceb6c343: node.detach if (bytes4(0x80882800) == functionId || bytes4(0xceb6c343) == functionId) { // node.attach or node.detach address rootNode = MultiSigNode(_to).getRootNode(); if (rootNode == signers) { // Change SIGNER need ALL SIGNER_CONTROLLER setRequirement(LABEL_CODE_SIGNER_CONTROLLER, WALLET_FLAG_ALL, uint8(-1)); // ALL signable } else if (rootNode == signersController || rootNode == stakersController) { // Change SIGNERS_CONTROLLER or STAKER_CONTROLLER need ALL STAKER setRequirement(LABEL_CODE_STAKER, WALLET_FLAG_ALL, uint8(-1)); // ALL signable } else if (rootNode == stakers) { // Change STAKER need ALL STAKER_CONTROLLER setRequirement(LABEL_CODE_STAKER_CONTROLLER, WALLET_FLAG_ALL, uint8(-1)); // ALL signable } else { revert("Root.submit: Unknown node"); } } else revert("Root.submit: Not supported"); } else { // Regulator create requirement MultiSigRegulator(regulator).createRequirement(transactionCode, msg.sender, _to, _value, _data); } } else { // Calling self functions // - 0xcde0a4f8: root.setRegulator // - 0xb47876ea: root.setSigners // - 0xc27dbe63: root.setStakers // - 0x26bc178c: root.setStakersController // - 0x51d996bf: root.setSignersController if (bytes4(0xcde0a4f8) == functionId || bytes4(0xc27dbe63) == functionId) // setRegulator or setStakers setRequirement(LABEL_CODE_STAKER_CONTROLLER, WALLET_FLAG_ALL, uint8(-1)); // ALL signable else if (bytes4(0x26bc178c) == functionId || bytes4(0x51d996bf) == functionId) // setStakersController or setSignersController setRequirement(LABEL_CODE_STAKER, WALLET_FLAG_ALL, uint8(-1)); // ALL signable else if (bytes4(0xb47876ea) == functionId) // setSigners setRequirement(LABEL_CODE_SIGNER_CONTROLLER, WALLET_FLAG_ALL, uint8(-1)); // ALL signable else revert("Root.submit: Not supported"); } require(0 < transactions[transactionCode].totalRequired, "Root.submit: Requirement is empty"); // Create transaction structure transactions[transactionCode] = Transaction({ status: TRANSACTION_STATUS_PENDING, totalRequired: transactions[transactionCode].totalRequired, to: _to, value: _value, data: _data, reason: "" }); emit Submission(transactionCode); // Confirm transaction if eligible and signable if (isEligible(transactionCode, msg.sender) && isSignable(transactionCode, msg.sender)) confirmTransaction(transactionCode, transactions[transactionCode]); return transactionCode; } function confirm(uint256 _transactionCode) external onlyWallet onlyEligible(_transactionCode) onlySignable(_transactionCode) returns (bool) { Transaction storage transaction = transactions[_transactionCode]; return confirmTransaction(_transactionCode, transaction); } function revoke(uint256 _transactionCode) external onlyWallet onlyEligible(_transactionCode) returns (bool) { require(TRANSACTION_STATUS_PENDING == transactions[_transactionCode].status, "Root.revoke: Transaction has been completed"); transactions[_transactionCode].status = TRANSACTION_STATUS_REVOKED; emit Revocation(msg.sender, _transactionCode); return true; } function confirmTransaction(uint256 _transactionCode, Transaction storage _transaction) private returns (bool) { TransactionRequirement storage requirement = requirements[_transactionCode][walletToLabelCodes[msg.sender]]; require(0 != requirement.flag && 0 != requirement.required, "Root.confirmTransaction: Requirement is empty"); // Prevent duplicated confirmation require(!confirmations[_transactionCode][msg.sender], "root.confirmTransaction: Duplicated confirmation"); confirmations[_transactionCode][msg.sender] = true; requirement.required = requirement.required.sub(1); _transaction.totalRequired = _transaction.totalRequired.sub(1); emit Confirmation(msg.sender, _transactionCode); return executeTransaction(_transactionCode, _transaction); } function executeTransaction(uint256 _transactionCode, Transaction storage _transaction) private returns (bool) { require(TRANSACTION_STATUS_PENDING == _transaction.status, "Root.executeTransaction: Status not active"); if (0 == _transaction.totalRequired) { _transaction.status = TRANSACTION_STATUS_EXECUTED; // Perform remote call (bool success, bytes memory returnData) = _transaction.to.call.value(_transaction.value)(_transaction.data); if (success) emit Execution(_transactionCode); else { // Check the error string is available or not if (0 == returnData.length || bytes4(0x08c379a0) != convertBytesToBytes4(returnData)) _transaction.reason = "Root.executeTransaction: Function call failed"; else { bytes memory bytesArray = new bytes(returnData.length); for (uint256 i = 0; i < returnData.length.sub(4); i = i.add(1)) { bytesArray[i] = returnData[i.add(4)]; } (string memory reason) = abi.decode(bytesArray, (string)); _transaction.reason = reason; } _transaction.status = TRANSACTION_STATUS_FAILURE; emit ExecutionFailure(_transactionCode); } return success; } return true; } function setRegulator(address _addressOf) external { if (address(0) != regulator) require(msg.sender == address(this), "Root.setRegulator: Access denied"); require(MultiSigRegulator(_addressOf).isSealed(), "Root.setRegulator: Regulator is not sealed"); regulator = setNode(regulator, _addressOf, false); emit RegulatorChanged(regulator); } function setStakers(address _addressOf) external { if (address(0) != stakers) require(msg.sender == address(this), "Root.setStakers: Access denied"); if (isContract(_addressOf)) require(0 < MultiSigNode(_addressOf).walletCount(), "Root.setStakers: No wallet"); stakers = setNode(stakers, _addressOf, true); emit StakersChanged(stakers); } function setSigners(address _addressOf) external returns (bool) { if (address(0) != signers) require(msg.sender == address(this), "Root.setSigners: Access denied"); // Signer node allowed to be empty signers = setNode(signers, _addressOf, true); emit SignersChanged(signers); return true; } function setStakersController(address _addressOf) external { if (address(0) != stakersController) require(msg.sender == address(this), "Root.setStakersController: Access denied"); if (isContract(_addressOf)) require(0 < MultiSigNode(_addressOf).walletCount(), "Root.setStakersController: No wallet"); stakersController = setNode(stakersController, _addressOf, true); emit StakersControllerChanged(stakersController); } function setSignersController(address _addressOf) external { if (address(0) != signersController) require(msg.sender == address(this), "Root.setSignersController: Access denied"); if (isContract(_addressOf)) require(0 < MultiSigNode(_addressOf).walletCount(), "Root.setSignersController: No wallet"); signersController = setNode(signersController, _addressOf, true); emit SignersControllerChanged(signersController); } function setNode(address _from, address _to, bool needAttachment) private returns (address) { require(address(0) != _to, "Root.setNode: Address is empty"); if (needAttachment) { require(0 == registered[_to], "Root.setNode: Duplicated node"); // Remove node from list if (address(0) != _from) { if (isContract(_from)) { // detach node MultiSigNode(_from).term(); } delete registered[_from]; } if (isContract(_to)) { // Mark address as registered node registered[_to] = WALLET_TYPE_NODE; if (needAttachment) { // Attach node (parrent address = 0x0) MultiSigNode(_to).init(address(0)); } } else { // Mark address as registered wallet registered[_to] = WALLET_TYPE_WALLET; } } return _to; } function attachWalletOrNode(address _wallet) external onlyNode returns (bool) { require(address(0) != _wallet, "Root.attachWalletOrNode: Wallet address is empty"); require(0 == registered[_wallet], "Root.attachWalletOrNode: Duplicated wallet address"); bytes32 labelCode = MultiSigNode(msg.sender).labelCode(); walletToNodes[_wallet] = msg.sender; walletToIndexes[_wallet] = MultiSigNode(msg.sender).walletsIndex(_wallet); walletToLabelCodes[_wallet] = labelCode; labelCodeToNodes[labelCode] = msg.sender; if (isContract(_wallet)) { // Mark address as registered node registered[_wallet] = WALLET_TYPE_NODE; // Attach node with their parent address MultiSigNode(_wallet).init(msg.sender); } else { // Mark address as registered wallet registered[_wallet] = WALLET_TYPE_WALLET; } emit WalletOrNodeAttached(_wallet); return true; } function detachWalletOrNode(address _wallet) external onlyNode returns (bool) { require(address(0) != _wallet, "Root.detachWalletOrNode: Wallet address is empty"); require(0 != registered[_wallet], "Root.detachWalletOrNode: Wallet address is not registered"); if (isContract(_wallet)) { // Detach node with their parent MultiSigNode(_wallet).term(); bytes32 labelCode = MultiSigNode(msg.sender).labelCode(); delete labelCodeToNodes[labelCode]; } delete registered[_wallet]; delete walletToNodes[_wallet]; delete walletToIndexes[_wallet]; delete walletToLabelCodes[_wallet]; emit WalletOrNodeDetached(_wallet); return true; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"constant":false,"inputs":[{"name":"_parent","type":"address"}],"name":"init","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"walletCount","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getRootNode","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"parent","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"description","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint8"}],"name":"wallets","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_index","type":"uint8"},{"name":"_wallet","type":"address"}],"name":"attach","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalWallet","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"term","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"class","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"labelCode","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"walletsIndex","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"label","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_wallet","type":"address"}],"name":"detach","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"classCode","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"root","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_root","type":"address"},{"name":"_wallets","type":"address[]"},{"name":"_label","type":"string"},{"name":"_description","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
Deployed Bytecode
0x6080604052600436106100e6576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806319ab453c146100eb57806329b57c691461013c57806338d1fcc31461016d57806360f96a8f146101c45780637284e4161461021b578063733f28a8146102ab57806380882800146103295780638628993f1461039f578063a10ffbed146103d0578063bff852fa146103e7578063c47d1a7a14610477578063c79e6429146104a2578063cb4774c41461050d578063ceb6c3431461059d578063e24ff74414610606578063ebf0c71714610631575b600080fd5b3480156100f757600080fd5b5061013a6004803603602081101561010e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610688565b005b34801561014857600080fd5b50610151610992565b604051808260ff1660ff16815260200191505060405180910390f35b34801561017957600080fd5b506101826109a5565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101d057600080fd5b506101d9610acb565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561022757600080fd5b50610230610af1565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610270578082015181840152602081019050610255565b50505050905090810190601f16801561029d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156102b757600080fd5b506102e7600480360360208110156102ce57600080fd5b81019080803560ff169060200190929190505050610b8f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561033557600080fd5b506103856004803603604081101561034c57600080fd5b81019080803560ff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bc2565b604051808215151515815260200191505060405180910390f35b3480156103ab57600080fd5b506103b46111c5565b604051808260ff1660ff16815260200191505060405180910390f35b3480156103dc57600080fd5b506103e56111d8565b005b3480156103f357600080fd5b506103fc6114a0565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561043c578082015181840152602081019050610421565b50505050905090810190601f1680156104695780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561048357600080fd5b5061048c61153e565b6040518082815260200191505060405180910390f35b3480156104ae57600080fd5b506104f1600480360360208110156104c557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611544565b604051808260ff1660ff16815260200191505060405180910390f35b34801561051957600080fd5b50610522611564565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610562578082015181840152602081019050610547565b50505050905090810190601f16801561058f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156105a957600080fd5b506105ec600480360360208110156105c057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611602565b604051808215151515815260200191505060405180910390f35b34801561061257600080fd5b5061061b611ab7565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b50610646611abd565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561074d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4e6f64652e6f6e6c79526f6f743a204163636573732064656e6965640000000081525060200191505060405180910390fd5b80600c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600f60019054906101000a900460ff1660ff166000101561098f5760008090506000600190505b604060ff168160ff16111580156107e15750600f60019054906101000a900460ff1660ff168260ff1611155b1561098c576000600d60008360ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff1614151561096d5761087160018460ff16611ae390919063ffffffff16565b9250600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c4def70a826040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561093057600080fd5b505af1158015610944573d6000803e3d6000fd5b505050506040513d602081101561095a57600080fd5b8101908080519060200190929190505050505b5061098560018260ff16611ae390919063ffffffff16565b90506107b5565b50505b50565b600f60009054906101000a900460ff1681565b6000600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff161415610a0657309050610ac8565b600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338d1fcc36040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b158015610a8a57600080fd5b505afa158015610a9e573d6000803e3d6000fd5b505050506040513d6020811015610ab457600080fd5b810190808051906020019092919050505090505b90565b600c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60088054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b875780601f10610b5c57610100808354040283529160200191610b87565b820191906000526020600020905b815481529060010190602001808311610b6a57829003601f168201915b505050505081565b600d6020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610c89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4e6f64652e6f6e6c79526f6f743a204163636573732064656e6965640000000081525060200191505060405180910390fd5b8260ff166000108015610ca357508260ff16604060ff1610155b1515610d17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f4e6f64652e6174746163683a20496e646578206f7574206f662072616e67650081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff1614151515610de2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001807f4e6f64652e6174746163683a2057616c6c65742061646472657373206973206581526020017f6d7074790000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b600e60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1660ff166000141515610ecf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001807f4e6f64652e6174746163683a204475706c6963617465642077616c6c6574206181526020017f646472657373000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b600d60008460ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff16141515610f8257610f80600d60008560ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611602565b505b82600e60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360ff16021790555081600d60008560ff1660ff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061103b82611b71565b1515611082576110676001600f60009054906101000a900460ff1660ff16611ae390919063ffffffff16565b600f60006101000a81548160ff021916908360ff1602179055505b6110a86001600f60019054906101000a900460ff1660ff16611ae390919063ffffffff16565b600f60016101000a81548160ff021916908360ff160217905550600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c4def70a836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561117f57600080fd5b505af1158015611193573d6000803e3d6000fd5b505050506040513d60208110156111a957600080fd5b8101908080519060200190929190505050506001905092915050565b600f60019054906101000a900460ff1681565b600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561129d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4e6f64652e6f6e6c79526f6f743a204163636573732064656e6965640000000081525060200191505060405180910390fd5b600f60019054906101000a900460ff1660ff166000101561149e5760008090506000600190505b604060ff168160ff16111580156112f05750600f60019054906101000a900460ff1660ff168260ff1611155b1561149b576000600d60008360ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff1614151561147c5761138060018460ff16611ae390919063ffffffff16565b9250600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d4ab68e4826040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561143f57600080fd5b505af1158015611453573d6000803e3d6000fd5b505050506040513d602081101561146957600080fd5b8101908080519060200190929190505050505b5061149460018260ff16611ae390919063ffffffff16565b90506112c4565b50505b565b60068054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156115365780601f1061150b57610100808354040283529160200191611536565b820191906000526020600020905b81548152906001019060200180831161151957829003601f168201915b505050505081565b600a5481565b600e6020528060005260406000206000915054906101000a900460ff1681565b60078054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156115fa5780601f106115cf576101008083540402835291602001916115fa565b820191906000526020600020905b8154815290600101906020018083116115dd57829003601f168201915b505050505081565b6000600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156116c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4e6f64652e6f6e6c79526f6f743a204163636573732064656e6965640000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff1614151515611794576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001807f4e6f64652e6465746163683a2057616c6c65742061646472657373206973206581526020017f6d7074790000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b6000600e60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1690508060ff1660001080156117ff57508060ff16604060ff1610155b1515611899576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602d8152602001807f4e6f64652e6465746163683a2057616c6c65742061646472657373206973206e81526020017f6f7420726567697374657265640000000000000000000000000000000000000081525060400191505060405180910390fd5b6118a283611b71565b15156118e9576118ce6001600f60009054906101000a900460ff1660ff16611b8a90919063ffffffff16565b600f60006101000a81548160ff021916908360ff1602179055505b61190f6001600f60019054906101000a900460ff1660ff16611b8a90919063ffffffff16565b600f60016101000a81548160ff021916908360ff160217905550600d60008260ff1660ff16815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600e60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81549060ff0219169055600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d4ab68e4846040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611a7157600080fd5b505af1158015611a85573d6000803e3d6000fd5b505050506040513d6020811015611a9b57600080fd5b8101908080519060200190929190505050506001915050919050565b60095481565b600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081830190508260ff168160ff1610151515611b68576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4164646974696f6e20657863657074696f6e000000000000000000000000000081525060200191505060405180910390fd5b80905092915050565b600080823b90508063ffffffff16600010915050919050565b60008260ff168260ff1611151515611c0a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f5375627472616374696f6e20657863657074696f6e000000000000000000000081525060200191505060405180910390fd5b81830390509291505056fea165627a7a723058204aea8e7ad23668107a3b2b5be25f4a6fe69e1bd29b74cc8affbbbe701b6a48680029
Swarm Source
bzzr://4aea8e7ad23668107a3b2b5be25f4a6fe69e1bd29b74cc8affbbbe701b6a4868
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.