1. 개념
MultiSig(Multi-Signature) Wallet 은 여러 명의 사용자가 공동으로 자금을 관리하도록 설계된 스마트 컨트랙트입니다. 특정 수의 승인자가 서명해야만 트랜잭션이 실행되도록 설정할 수 있어 보안성을 강화할 수 있습니다.
2. 주요특징
- 다중 서명 요구: 단일 개인키가 아닌 여러 개인 키가 필요하여 보안성이 높음.
- M-of-N 승인 방식 : N명의 소유자 중 M 명이 서명해야 트랜잭션이 실행됨 (e.g. 2-of-3)
- 보안성: 개인 키가 유출되더라도 다중 서명이 필요하여 해킹 위험이 감소
3. 코드 구현
다음 기능들을 반영한 예제 코드를 작성해 봅시다.
- 지갑 소유자 등록 및 병경 가능
- 지정된 최소 서명 개수만큼 서명이 모이면 트랜잭션 실행
- 트랜잭션이 승인되지 않으면 실행되지 않음
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MultiSigWallet {
address[] public owners; // 다중 서명 지갑 소유자 목록
uint public requiredSignatures; // 필요한 서명 개수
struct Transaction {
address to;
uint value;
bytes data;
bool executed;
uint numConfirmations;
}
mapping(uint => mapping(address => bool)) public isConfirmed; // 특정 트랜잭션에 대한 승인 상태
Transaction[] public transactions;
event Deposit(address indexed sender, uint amount);
event TransactionSubmitted(uint indexed txIndex, address indexed to, uint value, bytes data);
event TransactionConfirmed(uint indexed txIndex, address indexed owner);
event TransactionExecuted(uint indexed txIndex, address indexed to, uint value);
modifier onlyOwner() {
require(isOwner(msg.sender), "Not an owner");
_;
}
modifier txExists(uint _txIndex) {
require(_txIndex < transactions.length, "Transaction does not exist");
_;
}
modifier notExecuted(uint _txIndex) {
require(!transactions[_txIndex].executed, "Transaction already executed");
_;
}
modifier notConfirmed(uint _txIndex) {
require(!isConfirmed[_txIndex][msg.sender], "Transaction already confirmed");
_;
}
constructor(address[] memory _owners, uint _requiredSignatures) {
require(_owners.length > 0, "At least one owner required");
require(_requiredSignatures > 0 && _requiredSignatures <= _owners.length, "Invalid required signatures");
owners = _owners;
requiredSignatures = _requiredSignatures;
}
function isOwner(address _address) public view returns (bool) {
for (uint i = 0; i < owners.length; i++) {
if (owners[i] == _address) {
return true;
}
}
return false;
}
receive() external payable {
emit Deposit(msg.sender, msg.value);
}
function submitTransaction(address _to, uint _value, bytes memory _data) public onlyOwner {
uint txIndex = transactions.length;
transactions.push(Transaction({
to: _to,
value: _value,
data: _data,
executed: false,
numConfirmations: 0
}));
emit TransactionSubmitted(txIndex, _to, _value, _data);
}
function confirmTransaction(uint _txIndex) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) notConfirmed(_txIndex) {
Transaction storage transaction = transactions[_txIndex];
transaction.numConfirmations += 1;
isConfirmed[_txIndex][msg.sender] = true;
emit TransactionConfirmed(_txIndex, msg.sender);
if (transaction.numConfirmations >= requiredSignatures) {
executeTransaction(_txIndex);
}
}
function executeTransaction(uint _txIndex) internal txExists(_txIndex) notExecuted(_txIndex) {
Transaction storage transaction = transactions[_txIndex];
require(transaction.numConfirmations >= requiredSignatures, "Not enough confirmations");
transaction.executed = true;
(bool success, ) = transaction.to.call{value: transaction.value}(transaction.data);
require(success, "Transaction execution failed");
emit TransactionExecuted(_txIndex, transaction.to, transaction.value);
}
function getTransaction(uint _txIndex) public view returns (
address to,
uint value,
bytes memory data,
bool executed,
uint numConfirmations
) {
Transaction storage transaction = transactions[_txIndex];
return (
transaction.to,
transaction.value,
transaction.data,
transaction.executed,
transaction.numConfirmations
);
}
}
4. 코드 설명
- 지갑 소유자 등록
- 생성자에서 MultiSig 지갑의 소유자 목록을 등록
- 특정 숫자의 서명이 필요함(requiredSignatures)
- 입금 기능
- receive() 함수를 통해 ETH 입금 기능
- 트랜잭션 제출
- submitTransaction() 함수를 호출하여 출금 트랜잭션을 제출
- 트랜잭션 스인
- confirmTransaction() 을 호출하여 각 소유자가 서명
- 서명이 requiredSignatures 이상 모이면 자동으로 실행
- 트랜잭션 실행
- 서명이 충분하면 executeTransaction() 을 호출하여 송금 수행
5. MultiSig 의 장점과 단점
- 장점
- 보안성: 단일 키를 탈취해도 자금 이동 불가능
- 거버넌스: 팀이나 조직이 공동으로 자금을 관리할 수 있음
- 탈중앙화: 신뢰할 수 있는 단일 관리자가 필요 없음
- 단점
- 사용성: 다수의 서명자가 직접 승인해야 하므로 빠른 트랜잭션 실행이 어려움
- 비용: 다중 서명 검증을 위한 추가적인 가스 비용이 발생
6. MultiSig Wallet 이 사용되는 사례
- DAO: 팀이 공동 자금을 관리
- 크립토 펀드: 투자금 보호
- 스마트 계약 기반 서비스: 보안이 중요한 대규모 거래에서 활용
7. 결론
- MultiSig Wallet 은 보안과 분산화를 강화하는 필수적인 스마트 컨트랙트.
- 2-of-3, 3-of-5 등의 설정을 통해 다양한 협업 시나리오에 활용 가능.
- DeFi, DAO 등에서 신뢰 없이 공동 자금을 관리하는 솔루션으로 널리 사용됨.
'이더리움' 카테고리의 다른 글
| MPC Wallet 의 서명 합계 과정에 대한 수학적 증명 (0) | 2025.01.31 |
|---|---|
| MPC Wallet 의 개념 및 구현 (0) | 2025.01.31 |
| 이더리움에서의 ECDSA - 계정 생성과 트랜잭션 서명 (기초편) (2) | 2025.01.06 |
| 비대칭키(공개키) 암호화 (1) | 2025.01.06 |
| 암호화 기술의 종류와 사용처 (2) | 2025.01.06 |