Skip to content

이더리움의 안전한 관리를 위한 멀티시그 월렛

Share on facebook
Facebook
Share on twitter
Twitter
Share on linkedin
LinkedIn

시작하는 말

일반적으로 암호화폐 지갑에는 크게 핫 월렛(HotWallet) 과 콜드 월렛(Cold Wallet) 이 있으며, 더 나아가 이더리움의 스마트 컨트랙트를 기반으로 한 멀티시그 월렛(Multi-Signature Wallet) 이 있다. 핫 월렛과 콜드 월렛은 인터넷에 연결되느냐 되지 않느냐의 차이로 구분을 하는데 그렇게 따지면 멀티시그 월렛은 핫 월렛으로 볼 수 있다. 컨트랙트를 기반으로 한 멀티시그 월렛이란 무엇이며 사용하려면 어떻게 해야 하는지 알아보려고 한다.

멀티시그 월렛이란?

멀티시그 월렛은 단일 서명을 통해 지갑에서 암호화폐를 출금하던 방식과 다르게 다중 서명을 통해 출금이 가능하도록 한 스마트 컨트랙트이다.

보통 개인이 사용하기보다는 거래소나 기업들처럼 공동의 자산을 보관하고 사용하는 곳에서 주로 사용된다.

이더리움은 트랜잭션 생성 시 하나의 서명만 할 수 있기 때문에 다중 서명(예를 들어 2 of 3)을 위해 스마트 컨트랙트를 이용한다.

이러한 방식의 멀티시그 월렛은 일반 월렛에 비해 보안이 더 우수하고 실수나 해킹으로 인한 사고를 방지할 수 있기를 기대하고 사용한다.

하지만 편의성이 부족하여 일반 월렛에 비해 사용하기가 쉽지 않고 해킹사고가 없었던 것도 아니다.

2017년 11월에 멀티시그 월렛(패리티)이 해킹되어 약 2억 8000만 달러가 묶여버리는 사고가 있었다.

또한 2019년 11월에는 업비트 핫 월렛에서 해커의 지갑으로 이더리움 34만 2천 개가 이동되는 사고가 있었다.

  • 컨트랙트를 이용한 멀티시그 월렛이라면 아래처럼 Contract로 표시되어야 한다.
위 사례들처럼 아무리 멀티시그 월렛이라고 해도 사고가 없는 것은 아니므로 사용하는데 각별한 주의가 필요할 것 같다.

멀티시그 월렛 종류

ConsenSys

  • 멀티시그 컨트랙트에 필요한 모든 공통 기능을 포함하였으나, 꾸준한 유지 관리가 되지 않았다.
  • Gnosis 멀티시그 월렛에서 계속 개발이 되고 있다.
  • https://github.com/ConsenSysMesh/MultiSigWallet

Gnosis

Argent

  • “Guardians” 기능으로 다른 Argent 사용자를 선택하여 모든 출금에 그 사용자의 승인이 필요하도록 한다.
  • https://www.argent.xyz/security/

BitGo

  • end user 가 off-chain에서 서명을 하고 이 데이터를 또 다른 signer가 서명하여 트랜잭션을 발생시켜서 2 of 3을 만족해야 출금이 되는 방식이다.
  • https://github.com/BitGo/eth-multisig-v2

나만의 멀티시그 월렛을 만들고 사용해 보자

본 아티클에서 말하는 멀티시그 월렛은 스마트 컨트랙트라고 했으니 생성하려면 컨트랙트를 배포해야 한다. 위에 소개한 멀티시그 월렛 목록 중 필자는 Gnosis 멀티시그 컨트랙트를 이용해 보려고 한다.

1. Gnosis 멀티시그 컨트랙트 다운로드

2. Remix에서 컴파일

  • 크롬 브라우저를 실행하고 Remix 사이트로 이동한다.

  • 다운로드한 MultiSigWallet.sol 파일을 Remix에서 컴파일 한다.

    • 단, compiler 버전을 아무거나 하면 에러가 표시되었고, 0.4.16+commit.d7661dd9를 사용해야 에러 없이 컴파일이 되었다.

     

3. MultiSigWallet 배포

  • 컴파일이 끝났으면 컨트랙트를 체인에 배포 한다.

    • 좌측 메뉴 중 Deploy & Run Transactions를 선택한다.

    • Environment 를 “Injected Web3″로 변경한다.

    • 메타마스크를 연결한다.

      • Ropsten network 선택
    • Deploy 버튼 우측에 owner address로 쓸 주소 2개 이상과 필요한 confirm 수 2 이상을 입력 후 transact 버튼을 누른다.

      • 주의할 사항은 메타마스크 지갑 하나에서 계정을 여러 개 생성해서 그것들을 owner address로 설정하면 나중에 confirm transaction 을 날릴 때 한 개는 성공해도 같은 지갑 다른 주소로 두 번째 날릴 때부터는 실패가 뜨게 된다.
      • 그러므로 owner address는 각각 다른 지갑의 주소를 입력해 주도록 하자.
      // 예를 들어 아래와 같이 입력한다.
      _OWNERS: ["0xBc42F665C48A3C9Fe9263994D02b87d6983f0665","0x1D2A53AF862D3315Dc61F1A21AE42A5C02e91Ee6"]
      _REQUIRED: 2
      

       

  • 그러면 메타마스크에 확인 노티 팝업이 뜨는데 확인 버튼을 눌러 준다.
  • 그러면 우측 아래 콘솔에 Ropsten 이더스캔 페이지의 url 이 출력되고 잠시 기다리면 배포 완료 메시지가 뜬다.
  • Deploy & Run Transactions 메뉴의 하단에 보면 MULTISIGWALLET AT 0xF70… 확장 메뉴가 보인다.
    • 이를 확장해 보면 컨트랙트의 기능 목록이 보이고 트랜잭션을 날려볼 수 있는 UI가 보인다.

4. Ether 를 전송해 보자.

4-1. 이더 입금

  • 우측 하단 콘솔창에 출력된 링크로 들어가서 생성된 Contract 주소를 클릭해 보면 아래와 같이 현재 멀티시그 월렛의 상태를 볼수 있다.
    • 멀티시그 월렛 주소: 0xF70f1631B4Cf7d7aD54fE687B59bA970FAcD5B8d
  • 멀티시그가 잘 되는지 확인해 보려면 저 멀티시그 월렛에 이더를 넣어야 한다.

  • 메타마스크를 이용해 멀티시그 월렛 주소로 이더를 전송한다. (2 이더가 전송 완료되었다.)

     

4-2. 멀티시그 월렛에서 이더 전송

  • 좌측 Deployed Contracts 항목에 표시된 MultiSigWallet 기능 중 submitTransaction 부분을 확장하여 이더를 전송할 주소, value, data를 넣고 transact 버튼을 클릭한다.

    • data 항목에 아무것도 안넣으면 아래와 같은 메시지가 뜨고 transact가 실패하므로 0x라고 넣자.
    • 여기서는 0.1 Ether를 보내보겠다.
  • 이때 submitTransaction 하는 owner의 address에는 당연히 수수료가 있어야 한다.
  • 아래와 같이 submit transaction이 멀티시그 월렛에 등록되었다.
  • 하지만 아직 이더는 전송되지 않고 멀티시그 월렛에 2이더가 그대로 남아있다.

4-3. confirm transaction (Ether)

  • confirm transaction 을 하기 전에 submitTransaction의 confirm 수를 조회해 보자.

    • 아무도 confirm 하지 않았는데 주소가 들어있다.
    • 이는 submitTransaction 함수 안에 confirmTransaction까지 불러주는 코드가 있기 때문이다.

     

/// @dev Allows an owner to submit and confirm a transaction.
/// @param destination Transaction target address.
/// @param value Transaction ether value.
/// @param data Transaction data payload.
/// @return Returns transaction ID.
function submitTransaction(address destination, uint value, bytes data)
        public
        returns (uint transactionId)
{
    transactionId = addTransaction(destination, value, data);
    confirmTransaction(transactionId);
}
  • transactionId는 최초 submitTransaction 이면 0일 것이다.

  • 우측 하단의 콘솔 창에 submitTransaction 실행한 것을 확장해보면 transactionId를 확인할 수 있다.
  • 또 다른 owner 계정으로 메타마스크에 로그인하여 confirmTransaction 을 실행해 보자.
  • confirmTransaction 이 승인되면서 submitTransaction 이 실행된 로그가 보인다.
  • getConfirmations 0 해보면 주소 두 개가 보인다.
  • Ropsten scan으로 확인해 보면 트랜잭션들이 정상적으로 승인되고 1.9 Ether 가 남은 것을 볼 수 있다.
  • 왜 executeTransaction 을 실행하지 않았는데도 이더가 전송되었을까? 그건 confirmTransaction 함수에서 executeTransaction 을 실행하도록 되어있기 때문에 confirm 수가 맞춰지는 confirmTransaction 이 들어오게 되면 자연스럽게 executeTransaction 이 실행된다.
/// @dev Allows an owner to confirm a transaction.
/// @param transactionId Transaction ID.
function confirmTransaction(uint transactionId)
    public
    ownerExists(msg.sender)
    transactionExists(transactionId)
    notConfirmed(transactionId, msg.sender)
{
    confirmations[transactionId][msg.sender] = true;
    Confirmation(msg.sender, transactionId);
    executeTransaction(transactionId);
}

5. ERC20 토큰을 전송해 보자.

5-1. ERC 20 토큰 배포

  • 미리 ERC 20 JUSTIN 토큰을 배포해 두었다.
    • JUSTIN 토큰 주소: 0x30F5b49C8Eb7DE72C7B370805071FB4Aa49B457d
  • 미리 필자가 만들어 뒀던 ERC20 JUSTIN 토큰을 멀티시그 월렛으로 100개를 전송해보면 아래와 같이 보이게 된다.

5-2. 멀티시그 월렛에 있는 토큰을 다른 주소로 전송해 보자.

  • destination 은 JUSTIN token의 주소를 입력한다.
  • value는 0 을 넣고,
  • data에는 abi encoding 된 byte code를 넣어야 한다.
    • 온라인 abi encoding 사이트가 있어서 사용했다.
    • 위 사이트에서 아래쪽 “enter your parameters manually” 부분에 아래와 같이 입력하면 encoding 을 해준다.
      • Address에는 실제 토큰을 받을 주소를 입력한다.
  • 바이트 코드를 복사하고 앞에 “0x”를 붙여 submitTransaction의 data 항목에 넣고 transact 한다.

5-3. confirm transaction (ERC 20)

  • 토큰 전송 submitTransaction에 대해 마찬가지로 다른 owner의 confirm 이 필요하다.
  • 이번 transactionId는 1이다.  
  • 또 다른 owner로 confirmTransaction 을 해준다.
  • 0.05 JUSTIN 토큰이 전송된것을 확인할 수 있다.

5-4. 전송된 토큰 확인

  • 메타마스크로 들어가 보면 토큰이 전송되지 않은 상태이다.

    • 토큰을 직접 추가해 줘야 보인다.
  • 토큰 추가 버튼을 통해 토큰 주소를 입력하면 등록이 되고 전송된 0.05 JUSTIN 토큰이 보인다.

    • JUSTIN 토큰 주소: 0x30F5b49C8Eb7DE72C7B370805071FB4Aa49B457d

     

6. 이더와 토큰을 동시에 보낼 수 있을까?

  • 궁금해서 해봤는데 안 되는 것 같다.
  • value 와 data 둘 다 입력하고 transact 하면 메타마스크 팝업이 뜨는데 value 가 0으로 되어있고 수정도 할 수 없다.
  • 확인 누른 후 트랜잭션을 열어보면 value 는 0이고 data만 들어있는 걸 확인할 수 있다.
  • 이더와 토큰을 동시에 전송하는 건 안되는 걸 알 수 있었다.

마치는 말

이렇게 특별히 코드 수정 없이도 나만의 이더리움 멀티시그 월렛이 간단하게 완성된 것을 확인할 수 있었다.

해킹 뉴스를 심심치 않게 볼 수 있는 요즘, 사용에 약간의 불편함이 있겠지만 중요한 자산인 경우 멀티시그 월렛을 사용하여 조금 더 안전하게 보관, 관리하면 좋을것 같다.

<참고>

Share your blockchain-related digital insights with your friends

Share on facebook
Facebook
Share on twitter
Twitter
Share on linkedin
LinkedIn

Get more insights