체인의정석

운영용 멀티시그 지갑 선택하기 & 멀티시그 지갑 테스트 및 사용을 위해 ethers.js로 encode된 data 만들기 본문

블록체인/Solidity

운영용 멀티시그 지갑 선택하기 & 멀티시그 지갑 테스트 및 사용을 위해 ethers.js로 encode된 data 만들기

체인의정석 2022. 5. 12. 14:21
728x90
반응형

현재 gnosis의 멀티시그 지갑을 0.5.0 버전으로 업데이트하여 사용하기로 한 후 테스트 중이다.

consensys의 멀티시그 지갑을 2년반전에 사용했었는데 같은 프로그래머가 gnosis의 멀티시그 지갑을 만들었고 현재는 gnosisSafe를 사용하고 있다.

 

gnosis safe는 툴이 생각보다 잘 지원된다. 개발자용 배포툴도 있지만, 다중 체인을 지원하기에는 무리가 있다. 따라서 이건 패스!

 

https://docs.gnosis-safe.io/

 

Introduction - Developer Docs

 

docs.gnosis-safe.io

https://dev.gnosis-safe.io/

 

Gnosis Safe Developer

 

dev.gnosis-safe.io

 

또한 gnosisSafe의 경우 일반 유저를 대상으로 한 nft나 디파이, 표준 지키기, 가스토큰 처리,오프체인 처리 , 확장 모듈 등에 초점이 맞추어져있어 시스템운영에서의 멀티시그로는 적합하지 않다는 판단을 내렸다.

 

예전부터 참고되는 널리 사용되는 멀티시그 지갑은 아래와  같다.

 

→ 구버전 gnosis 멀티시그 지갑

https://github.com/gnosis/MultiSigWallet/blob/master/contracts/MultiSigWallet.sol

 

GitHub - gnosis/MultiSigWallet: Allows multiple parties to agree on transactions before execution.

Allows multiple parties to agree on transactions before execution. - GitHub - gnosis/MultiSigWallet: Allows multiple parties to agree on transactions before execution.

github.com

 

→ Consensys의 멀티시그 지갑 https://github.com/ConsenSysMesh/MultiSigWallet/blob/master/MultiSigWalletWithDailyLimit.sol

 

GitHub - ConsenSysMesh/MultiSigWallet: Ethereum MultiSigWallet

Ethereum MultiSigWallet. Contribute to ConsenSysMesh/MultiSigWallet development by creating an account on GitHub.

github.com

같은 사람이 코드를 작성한것으로 되어 있는데 컨센시스 소속인거 같다. 믿음직스럽다.

 

컨트렉트도 하나라서 그냥 리믹스에 넣고 테스트 하기에도 좋다.

 

오픈제플린 소속 개발자가 만든 코드도 찾을 수 있었다. 검증되어 오픈되고 사용되는 코드이다.

https://etherscan.io/address/0xba2906b18b069b40c6d2cafd392e76ad479b1b53#code

 

PartiallyDelayedMultiSig | Address 0xba2906b18b069b40c6d2cafd392e76ad479b1b53 | Etherscan

The Contract Address 0xba2906b18b069b40c6d2cafd392e76ad479b1b53 page allows users to view the source code, transactions, balances, and analytics for the contract address. Users can also interact and make transactions to the contract directly on Etherscan.

etherscan.io

https://etherscan.io/txs?a=0xba2906b18b069b40c6d2cafd392e76ad479b1b53&f=3 

 

Ethereum Transactions Information | Etherscan

Transactions that have been mined and confirmed on the Ethereum Blockchain. The list consists of transactions from sending Ether and the transactions for interacting with a smart contract.

etherscan.io

여기서 자주 사용되는 함수들을 볼 수있다.

 

테스트 코드 작성하기

예전 web3에서 멀티시그 지갑을 사용한 경험을 바탕으로 abi.encdoe를 통해서 encoded된 데이터를 받아오기로 생각하고 검색하엿다. 아래 예시처럼 데이터를 encode 해오고 이를 멀티시그 지갑에 변수로 넣어서 제출 한 후 승인을 받은 후 실행 시키고 결과값을 확인하는 테스트 코드를 작성해 보려고 한다.

https://docs.ethers.io/v5/api/utils/abi/coder/#AbiCoder-encode

 

AbiCoder

Documentation for ethers, a complete, tiny and simple Ethereum library.

docs.ethers.io

테스트 코드 작성에는 시간이 오래 걸리니 일단 리믹스 환경에서 임시로 토큰 하나를 배포해보고 전송이 잘 되나 확인할 예정이다.

 

그리고 evm계열 다른 체인의 적용 여부도 크게 상관없다는 결론이 나왓다. gas가 명시된 부분이 있긴하지만 이는 evm의 기본 전송 gas로 영향을 받는 체인은 없을것이다. 최소 가스의 경우 트랜잭션이 실패할경우 반환되기 때문에 바이트코드 레벨에서 컨트렉트 소스코드로 구현이 되어 있다.

 

일단 함수의 경우 abi를 사용해서 encode를 시키면 된다. 아래 예시를 찾아서 적용하였다.

https://github.com/ethers-io/ethers.js/issues/211

 

Using the ABI coder to encode and decode eth_call · Issue #211 · ethers-io/ethers.js

https://github.com/ethjs/ethjs-abi says that it is from ethers.js, but it is fairly out of date and doesn't support structs. I'm using ethers.js elsewhere in my app and would like to levera...

github.com

var abi = [ { name: 'foo', type: 'function', inputs: [ { type: 'uint256' } ], outputs: [ { type: 'uint8' }] } ];
var iface = new ethers.Interface(abi)

// Example
var calldata = iface.functions.foo.encode(42);
// "0x2fbebd38000000000000000000000000000000000000000000000000000000000000002a"

// Parsing call response
var response = "0x000000000000000000000000000000000000000000000000000000000000002b";
var result = iface.functions.foo.decode(response);
// 43

 

테스트 코드에서는 abi는 따로 모듈화를 시킨 ts 파일에서 빼와서 사용하고 기존에 일반 사인으로 된 부분을 abi를 이용해 encode 시킨후 보내버릴 예정이다. 인터페이스에 대한 abi를 가져와서 사용하면 위의 소스코드 처럼 사용할 수 있다. 지금은 모두 contractFactory로 컨트렉트 클래스가 있으니 거기서 바로 아래와같이 대입해서 encode시키려고 한다.

const encodedData = contractName.functionName.encode(input);
const transactionId = await multiSigContract.connect(singer).submitTransaction(encodedData);

근데 안되어서 예제대로 해보기로 하였다. 예제도 오류가 난다. 확인해본 결과

In v4, it has been moved to ethers.utils.Interface. That should fix that problem. :)

v4 버전의 문법대로 하려면 코드가 업데이트 되어야 한다고 한다.

var abi = [ { name: 'foo', type: 'function', inputs: [ { type: 'uint256' } ], outputs: [ { type: 'uint8' }] } ];
var iface = new ethers.utils.Interface(abi)

// Example
var calldata = iface.functions.foo.encode(42);
// "0x2fbebd38000000000000000000000000000000000000000000000000000000000000002a"

// Parsing call response
var response = "0x000000000000000000000000000000000000000000000000000000000000002b";
var result = iface.functions.foo.decode(response);
// 43

 

근데 이젠 또 v5라서 문법이 한번 더 바뀌었다고 한다.

In v5, Interface is no longer a meta-class, which should make interacting with it much easier, but will require your code to change.

See: https://docs.ethers.io/v5/api/utils/abi/interface/

So, for example, to encode function data, you now use:

const abi = [
    "function transfer(address to, uint value)"
];
const iface = new Interface(abi);
const data = iface.encodeFunctionData("transfer", (someAddress, someValue));

You can also now perform encoding and decoding of both data and results (in v4, you could only encode data and only decode results).

근데 안되어서 값을 보니 값은 배열 형태로 들어가야 한다고 한다.

 

const abi = [
    "function transfer(address to, uint value)"
];
const iface = new Interface(abi);
const data = iface.encodeFunctionData("transfer", [someAddress, someValue]);

이런식으로 배열을 잡으니 잘 되었다.

 

사실 data를 인코딩 하는 부분은 멀티 시그 지갑이 아니면 사용할 일이 없어서 생소했지만, 결국 어떤 기능이 필요한지 파악하고 현재 사용하는 해당 모듈의 버전에 맞게 예제를 수정해주면 되는거 같다.

 

어떻게든 예제 하나만 찾아서 뚫어봐야지..

 

아무튼 이렇게 abi encode 된걸 멀티시그의 data칸 안에 넣으면 나머지는 일반 적인 테스트 코드 작성할때 처럼 풀어서 사용하면 될 것이다.

 

그리고 테스트 중에 하나 더 발견했다. 

chai에서 배열을 비교할때는

to.equal이 아닌 to.deep.equal을 사용해야 한다고 한다.

https://stackoverflow.com/questions/17526805/chai-test-array-equality-doesnt-work-as-expected

 

chai test array equality doesn't work as expected

Why does the following fail? expect([0,0]).to.equal([0,0]); and what is the right way to test that?

stackoverflow.com

배열의 경우 단순 비교가 아니라 자료형이기 때문인거 같다.

 

이것도 익숙해져놔야 할거 같아서 일단 기록해두겠다.

728x90
반응형
Comments