Safe
Safe (Multisig)
Multi-signature wallet with threshold confirmations
Safe (Multisig)
Multi-signature wallet with support for confirmations using signed messages based on EIP-712.
Overview
Safe is a secure multi-signature wallet that requires multiple owners to confirm transactions before execution. It supports:
- Configurable threshold (m-of-n signatures)
- Module extensions
- Transaction guards
- Fallback handlers
Key Concepts
| Concept | Description |
|---|---|
| Threshold | Number of required confirmations for a transaction |
| Owners | Addresses that control the Safe and approve transactions |
| Nonce | Each transaction has unique nonce to prevent replay attacks |
| Guards | Pre/post transaction checks |
| Modules | Extensions for additional functionality |
Core Functions
setup
function setup(
address[] calldata _owners,
uint256 _threshold,
address to,
bytes calldata data,
address fallbackHandler,
address paymentToken,
uint256 payment,
address payable paymentReceiver
) externalInitialize the Safe with owners and threshold.
execTransaction
function execTransaction(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address payable refundReceiver,
bytes memory signatures
) public payable returns (bool success)Execute a Safe transaction with collected signatures.
approveHash
function approveHash(bytes32 hashToApprove) externalApprove a transaction hash (for on-chain signing).
getTransactionHash
function getTransactionHash(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 _nonce
) public view returns (bytes32)Get the transaction hash for signing.
Owner Management
function addOwnerWithThreshold(address owner, uint256 _threshold) public
function removeOwner(address prevOwner, address owner, uint256 _threshold) public
function swapOwner(address prevOwner, address oldOwner, address newOwner) public
function changeThreshold(uint256 _threshold) publicModule Management
function enableModule(address module) public
function disableModule(address prevModule, address module) public
function execTransactionFromModule(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
) public returns (bool success)Deployment
import "@luxfi/standard/src/safe/contracts/Safe.sol";
import "@luxfi/standard/src/safe/contracts/proxies/SafeProxyFactory.sol";
// Deploy factory
SafeProxyFactory factory = new SafeProxyFactory();
// Create Safe with 2-of-3 threshold
address[] memory owners = new address[](3);
owners[0] = owner1;
owners[1] = owner2;
owners[2] = owner3;
bytes memory initializer = abi.encodeCall(
Safe.setup,
(
owners,
2, // threshold
address(0), // to
"", // data
address(0), // fallbackHandler
address(0), // paymentToken
0, // payment
payable(address(0)) // paymentReceiver
)
);
SafeProxy proxy = factory.createProxyWithNonce(
address(safeSingleton),
initializer,
salt
);
Safe safe = Safe(payable(address(proxy)));Usage Example
// 1. Get transaction hash
bytes32 txHash = safe.getTransactionHash(
to,
value,
data,
Enum.Operation.Call,
0, // safeTxGas
0, // baseGas
0, // gasPrice
address(0), // gasToken
address(0), // refundReceiver
safe.nonce()
);
// 2. Collect signatures off-chain (EIP-712)
bytes memory signatures = collectSignatures(txHash);
// 3. Execute transaction
safe.execTransaction(
to,
value,
data,
Enum.Operation.Call,
0,
0,
0,
address(0),
payable(address(0)),
signatures
);Threshold Signers (MPC)
Safe supports threshold signature schemes as owners, enabling advanced custody solutions without exposing private keys.
Available Signers
| Signer | Protocol | Curve | Quantum Safe | Use Case |
|---|---|---|---|---|
| SafeCGGMP21Signer | CGGMP21 | secp256k1 | ❌ | Institutional ECDSA custody |
| SafeFROSTSigner | FROST | secp256k1 | ❌ | Bitcoin Taproot, Schnorr |
| SafeFROSTCoSigner | FROST | secp256k1 | ❌ | Co-signing workflows |
| SafeRingtailSigner | Ringtail | Lattice | ✅ | Post-quantum security |
| SafeLSSSigner | LSS | secp256k1 | ❌ | Dynamic resharing |
| SafeMLDSASigner | ML-DSA | Lattice | ✅ | FIPS 204 compliant |
CGGMP21 Threshold ECDSA
import "@luxfi/standard/contracts/safe/SafeCGGMP21Signer.sol";
// Deploy with 2-of-3 threshold and aggregated public key
SafeCGGMP21Signer signer = new SafeCGGMP21Signer(
2, // threshold
3, // total signers
publicKey // 65-byte uncompressed secp256k1
);
// Add as Safe owner
safe.addOwnerWithThreshold(address(signer), threshold);FROST Schnorr Threshold
import "@luxfi/standard/contracts/safe/SafeFROSTSigner.sol";
// Deploy with public key coordinates
SafeFROSTSigner signer = new SafeFROSTSigner(px, py);
// Verify signature
bool valid = signer._isValidSignature(messageHash, signature);Post-Quantum (Ringtail)
import "@luxfi/standard/contracts/safe/SafeRingtailSigner.sol";
// Deploy with Ringtail public key
SafeRingtailSigner signer = new SafeRingtailSigner(
threshold,
totalSigners,
ringtailPublicKey // Lattice-based public key
);Integration with MPC Nodes
The threshold signers integrate with the Lux MPC node cluster (github.com/luxfi/mpc):
- Key Generation: Run distributed key generation across MPC nodes
- Deploy Signer: Deploy threshold signer contract with aggregated public key
- Add to Safe: Add signer contract as a Safe owner
- Collaborative Signing: MPC nodes sign transactions without exposing keys
┌─────────────────────────────────────────────────────────────────────────────┐
│ MPC + SAFE INTEGRATION │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ MPC Node 1 │ │ MPC Node 2 │ │ MPC Node 3 │ │
│ │ (Share 1) │ │ (Share 2) │ │ (Share 3) │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └───────────────────┼───────────────────┘ │
│ │ Threshold Signing (2-of-3) │
│ ▼ │
│ ┌─────────────────┐ │
│ │ CGGMP21/FROST │ │
│ │ Signature │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ SafeCGGMP21Signer │ │
│ │ (verifies threshold signature) │ │
│ └─────────────────────┬───────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Safe Wallet │ │
│ │ (executes tx) │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘Related LPs
- LP-7321: FROST Threshold Signature Precompile
- LP-7322: CGGMP21 Threshold ECDSA Precompile
- LP-7324: Ringtail Threshold Signature Precompile
- LP-7340: Threshold Cryptography Library
- LP-3310: Safe Multisig Standard
Security
- Threshold Enforcement: All transactions require threshold confirmations
- EIP-712 Signatures: Typed structured data for secure signing
- Guards: Optional pre/post execution checks
- Replay Protection: Nonce prevents transaction replay
- MPC Security: No single party holds complete private key
- Quantum Resistance: Ringtail and ML-DSA signers provide post-quantum security