Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"hymx-bridge.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
pragma abicoder v2;
contract HymxBridge {
// Event
event Submission(
bytes32 indexed id,
uint256 indexed proposalID,
bytes32 indexed everHash,
address owner,
address to,
uint256 value,
bytes data
);
event SubmissionFailure(
bytes32 indexed id,
uint256 indexed proposalID,
bytes32 indexed everHash,
address owner,
address to,
uint256 value,
bytes data
);
event Execution(
bytes32 indexed id,
uint256 indexed proposalID,
bytes32 indexed everHash,
address to,
uint256 value,
bytes data
);
event ExecutionFailure(
bytes32 indexed id,
uint256 indexed proposalID,
bytes32 indexed everHash,
address to,
uint256 value,
bytes data
);
// event Revocation(address indexed sender, bytes32 indexed id); // TODO
event Deposit(address indexed sender, uint256 value);
event OwnerAddition(address indexed owner);
event OwnerRemoval(address indexed owner);
event RequirementChange(uint256 required);
event OperatorChange(address indexed operator);
event PausedChange(bool paused);
// Event End
// Storage & Struct
uint256 public chainID;
bool public paused;
address public operator;
uint256 public required;
address[] public owners;
mapping(address => bool) public isOwner;
mapping(bytes32 => bool) public executed;// tx id => bool
mapping(bytes32 => mapping(address => bool)) public confirmations;
// Storage & Struct End
// Modifier
modifier validRequirement(uint256 ownerCount, uint256 _required) {
require(
ownerCount >= _required && ownerCount != 0 && _required != 0,
"invalid_required"
);
_;
}
modifier onlyWallet() {
require(msg.sender == address(this), "not_wallet");
_;
}
modifier onlyOperator() {
require(msg.sender == operator, "not_operator");
_;
}
modifier whenNotPaused() {
require(!paused, "paused");
_;
}
// Modifier End
// Manage
function getPaused() public view returns (bool) {
return paused;
}
function getOperator() public view returns (address) {
return operator;
}
function getOwners() public view returns (address[] memory) {
return owners;
}
function getRequire() public view returns (uint256) {
return required;
}
function setOperator(address _operator) public onlyWallet {
require(_operator != address(0), "null_address");
operator = _operator;
emit OperatorChange(operator);
}
function setPaused(bool _paused) public onlyOperator {
paused = _paused;
emit PausedChange(paused);
}
function addOwner(address owner) public onlyWallet {
require(owner != address(0), "null_address");
isOwner[owner] = true;
owners.push(owner);
emit OwnerAddition(owner);
}
function removeOwner(address owner) public onlyWallet {
require(isOwner[owner], "no_owner_found");
isOwner[owner] = false;
for (uint256 i = 0; i < owners.length - 1; i++) {
if (owners[i] == owner) {
owners[i] = owners[owners.length - 1];
break;
}
}
owners.pop();
if (required > owners.length) {
changeRequirement(owners.length);
}
OwnerRemoval(owner);
}
function replaceOwner(address owner, address newOwner) public onlyWallet {
require(isOwner[owner], "no_owner_found");
require(newOwner != address(0), "null_address");
for (uint256 i = 0; i < owners.length; i++) {
if (owners[i] == owner) {
owners[i] = newOwner;
break;
}
}
isOwner[owner] = false;
isOwner[newOwner] = true;
OwnerRemoval(owner);
OwnerAddition(newOwner);
}
function changeRequirement(uint256 _required)
public
onlyWallet
validRequirement(owners.length, _required)
{
required = _required;
emit RequirementChange(_required);
}
// Manage End
// Base
receive() external payable {
if (msg.value != 0) emit Deposit(msg.sender, msg.value);
}
constructor(address[] memory _owners, uint256 _required) validRequirement(_owners.length, _required)
{
for (uint256 i = 0; i < _owners.length; i++) {
isOwner[_owners[i]] = true;
}
owners = _owners;
required = _required;
uint256 _chainID;
assembly {
_chainID := chainid()
}
chainID = _chainID;
}
function submit(
uint256 proposalID, // ar tx id
bytes32 everHash,
address to,
uint256 value,
bytes memory data,
bytes[] memory sigs
) public whenNotPaused returns (bytes32, bool) {
bytes32 id = txHash(proposalID, everHash, to, value, data);
require(!executed[id], "tx_executed");
for (uint256 i = 0; i < sigs.length; i++) {
address owner = ecAddress(id, sigs[i]);
if (!isOwner[owner]) {
emit SubmissionFailure(id, proposalID, everHash, owner, to, value, data);
continue;
}
confirmations[id][owner] = true;
emit Submission(id, proposalID, everHash, owner, to, value, data);
}
if (!isConfirmed(id)) return (id, false);
executed[id] = true;
(bool ok, ) = to.call{value: value}(data);
if (ok) {
emit Execution(id, proposalID, everHash, to, value, data);
} else {
emit ExecutionFailure(id, proposalID, everHash, to, value, data);
}
return (id, true);
}
// execute multi calls
function executes(address[] memory tos, uint256[] memory values, bytes[] memory datas) payable public onlyWallet {
require(tos.length == values.length, "invalid_length");
require(tos.length == datas.length, "invalid_length");
for (uint256 i = 0; i < tos.length; i++) {
(bool ok, ) = tos[i].call{value: values[i]}(datas[i]);
require(ok, "executed_falied");
}
}
function isConfirmed(bytes32 id) public view returns (bool) {
uint256 count = 0;
for (uint256 i = 0; i < owners.length; i++) {
if (confirmations[id][owners[i]]) count += 1;
if (count >= required) return true;
}
return false;
}
// Base End
// Utils
function txHash(uint256 proposalID, bytes32 everHash, address to, uint256 value, bytes memory data) public view returns (bytes32) {
return keccak256(abi.encodePacked(chainID, address(this), proposalID, everHash, to, value, data));
}
function ecAddress(bytes32 id, bytes memory sig)
public
pure
returns (address)
{
require(sig.length == 65, "invalid_sig_len");
uint8 v;
bytes32 r;
bytes32 s;
assembly {
r := mload(add(sig, 0x20))
s := mload(add(sig, 0x40))
v := byte(0, mload(add(sig, 0x60)))
}
require(v == 27 || v == 28, "invalid_sig_v");
return
ecrecover(
keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\
32", id)
), v, r, s
);
}
// Utils End
}"
}
},
"settings": {
"evmVersion": "istanbul",
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": [],
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}
}}
Submitted on: 2025-11-05 12:31:50
Comments
Log in to comment.
No comments yet.