Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
/* ===================== Shared Base: Ownership ===================== */
abstract contract OwnableBase {
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
address public owner;
constructor(address initialOwner) {
require(initialOwner != address(0), "owner=0");
owner = initialOwner;
emit OwnershipTransferred(address(0), initialOwner);
}
modifier onlyOwner() { require(msg.sender == owner, "only owner"); _; }
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), "newOwner=0");
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
/* ===================== Optional: Global Fee Registry ===================== */
contract FeeRegistry is OwnableBase {
address public feeSink; // where protocol skim goes
uint16 public feeBps; // basis points (e.g., 20 = 0.20%)
event FeeUpdated(address indexed sink, uint16 bps);
constructor(address _owner, address _sink, uint16 _bps) OwnableBase(_owner) {
require(_sink != address(0), "sink=0");
require(_bps <= 1000, "bps>10%");
feeSink = _sink;
feeBps = _bps;
emit FeeUpdated(_sink, _bps);
}
function setFee(address sink, uint16 bps) external onlyOwner {
require(sink != address(0), "sink=0");
require(bps <= 1000, "bps>10%");
feeSink = sink;
feeBps = bps;
emit FeeUpdated(sink, bps);
}
}
interface IFeeRegistry {
function feeSink() external view returns (address);
function feeBps() external view returns (uint16);
}
/* ===================== Main tie-in interface ===================== */
interface IMain {
function protocolFeeBps() external view returns (uint16);
function protocolFeeSink() external view returns (address);
}
/* ===================== Pause Base ===================== */
abstract contract PausableBase is OwnableBase {
event Paused(address indexed account);
event Unpaused(address indexed account);
bool public paused;
constructor(address o) OwnableBase(o) {}
modifier whenNotPaused() { require(!paused, "paused"); _; }
function pause() external onlyOwner { paused = true; emit Paused(msg.sender); }
function unpause() external onlyOwner { paused = false; emit Unpaused(msg.sender); }
}
/* ===================== Satellite ERC20 with dual fee source ===================== */
contract CommunityToken is PausableBase {
/* ERC20 metadata */
string public name;
string public symbol;
function decimals() public pure returns (uint8) { return 18; }
/* ERC20 storage */
uint256 public totalSupply;
mapping(address => uint256) private _bal;
mapping(address => mapping(address => uint256)) private _allow;
/* ERC20 events */
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed tokenOwner, address indexed spender, uint256 value);
/* Fee source mode */
enum FeeSource { Registry, Main }
FeeSource public feeSource;
/* Sources */
address public registry; // FeeRegistry (if using Registry mode)
address public main; // Main Cosigo (if using Main mode)
/* Optional community fee (local) */
address public communityTreasury; // can be zero to disable
uint16 public communityFeeBps; // 0..1000 (0..10%)
/* Optional: allow MAIN to pause when enabled */
bool public mainGuardianEnabled;
event FeeSourceChanged(FeeSource mode);
event RegistryUpdated(address indexed registry);
event MainUpdated(address indexed main);
event MainGuardianToggled(bool enabled);
event CommunityTreasuryUpdated(address indexed treasury);
event CommunityFeeBpsUpdated(uint16 bps);
modifier onlyOwnerOrMainGuardian() {
require(msg.sender == owner || (mainGuardianEnabled && msg.sender == main), "owner/guardian only");
_;
}
constructor(
string memory name_,
string memory symbol_,
address owner_, // your EOA (MetaMask)
uint8 feeSourceMode_, // 0=Registry, 1=Main
address registry_, // required if Registry mode
address main_, // required if Main mode
address initialHolder_, // initial recipient
uint256 initialSupply_, // 18 decimals
address communityTreasury_, // optional (0 to disable)
uint16 communityFeeBps_ // usually 0
) PausableBase(owner_) {
require(bytes(name_).length > 0 && bytes(symbol_).length > 0, "bad meta");
require(initialHolder_ != address(0), "holder=0");
require(communityFeeBps_ <= 1000, "comm>10%");
name = name_;
symbol = symbol_;
// set fee source
require(feeSourceMode_ <= 1, "mode");
feeSource = FeeSource(feeSourceMode_);
if (feeSource == FeeSource.Registry) {
require(registry_ != address(0), "registry=0");
registry = registry_;
emit RegistryUpdated(registry_);
} else {
require(main_ != address(0), "main=0");
main = main_;
emit MainUpdated(main_);
}
communityTreasury = communityTreasury_;
communityFeeBps = communityFeeBps_;
if (communityTreasury_ != address(0)) emit CommunityTreasuryUpdated(communityTreasury_);
if (communityFeeBps_ > 0) emit CommunityFeeBpsUpdated(communityFeeBps_);
_mint(initialHolder_, initialSupply_);
}
/* ----- owner controls ----- */
function setRegistry(address r) external onlyOwner {
require(r != address(0), "registry=0");
registry = r;
emit RegistryUpdated(r);
}
function setMain(address m) external onlyOwner {
require(m != address(0), "main=0");
main = m;
emit MainUpdated(m);
}
function setFeeSource(uint8 mode) external onlyOwner {
require(mode <= 1, "mode");
feeSource = FeeSource(mode);
emit FeeSourceChanged(feeSource);
}
function toggleMainGuardian(bool enabled) external onlyOwner {
mainGuardianEnabled = enabled;
emit MainGuardianToggled(enabled);
}
function setCommunityTreasury(address a) external onlyOwner {
communityTreasury = a; // can be zero
emit CommunityTreasuryUpdated(a);
}
function setCommunityFeeBps(uint16 bps) external onlyOwner {
require(bps <= 1000, "max 10%");
communityFeeBps = bps;
emit CommunityFeeBpsUpdated(bps);
}
function mainPause() external onlyOwnerOrMainGuardian { paused = true; emit Paused(msg.sender); }
function mainUnpause() external onlyOwnerOrMainGuardian { paused = false; emit Unpaused(msg.sender); }
/* ----- ERC20 views ----- */
function balanceOf(address a) public view returns (uint256) { return _bal[a]; }
function allowance(address o, address s) public view returns (uint256) { return _allow[o][s]; }
/* ----- ERC20 writes ----- */
function approve(address spender, uint256 value) external returns (bool) {
_allow[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
function transfer(address to, uint256 value) external returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(address from, address to, uint256 value) external returns (bool) {
uint256 cur = _allow[from][msg.sender];
require(cur >= value, "allowance");
unchecked { _allow[from][msg.sender] = cur - value; }
emit Approval(from, msg.sender, _allow[from][msg.sender]);
_transfer(from, to, value);
return true;
}
/* ----- internal mint/burn (mint used in constructor) ----- */
function _mint(address to, uint256 amt) internal {
totalSupply += amt;
_bal[to] += amt;
emit Transfer(address(0), to, amt);
}
function _burn(address from, uint256 amt) internal {
require(_bal[from] >= amt, "bal");
unchecked { _bal[from] -= amt; }
totalSupply -= amt;
emit Transfer(from, address(0), amt);
}
/* ----- core transfer (ceil rounding, dual fee source) ----- */
function _transfer(address from, address to, uint256 amount) internal whenNotPaused {
require(from != address(0) && to != address(0), "zero addr");
require(_bal[from] >= amount, "bal");
if (amount == 0) { emit Transfer(from, to, 0); return; }
// get protocol fee from selected source
address sink;
uint16 bps;
if (feeSource == FeeSource.Registry) {
sink = IFeeRegistry(registry).feeSink();
bps = IFeeRegistry(registry).feeBps();
} else {
sink = IMain(main).protocolFeeSink();
bps = IMain(main).protocolFeeBps();
}
require(sink != address(0), "sink=0");
require(bps <= 1000, "bps>10%");
uint256 protoFee = bps == 0 ? 0 : (amount * bps + 9999) / 10000;
uint256 commFee = 0;
if (communityTreasury != address(0) && communityFeeBps > 0) {
commFee = (amount * communityFeeBps + 9999) / 10000;
}
require(protoFee + commFee <= amount, "fees>amount");
uint256 net = amount - protoFee - commFee;
unchecked { _bal[from] -= amount; }
if (protoFee > 0) { _bal[sink] += protoFee; emit Transfer(from, sink, protoFee); }
if (commFee > 0) { _bal[communityTreasury] += commFee; emit Transfer(from, communityTreasury, commFee); }
_bal[to] += net; emit Transfer(from, to, net);
}
}
Submitted on: 2025-09-22 10:56:05
Comments
Log in to comment.
No comments yet.