본문 바로가기

blockchain

[Cosmos + JS] ADR-036 구현하기

 

 

P.S.

SignArbitrary의 구현 명세는 ADR-036에 명세되어있는데, 현재 이슈란에 올라와있는 대화를 보면 cosmos레벨 에선 구현할 생각이 없는 듯하다. 

 

즉, sei-js에서 채용하는 지갑들이 사용하는 signArbitrary는 현재 리스크를 감수하고 사용하는 것인데, 이것을 구현하는게 맞는질 모르겠다.

Implementation

 

 

Message type

먼저 위 MsgSignData가 메세지 인터페이스다. signer와 data를 SignArbitrary의 인자로 받으면 될듯하다.

 

StdSign.json

그리고 위가 ADR-036에서 지정한 signDoc 예시인데, 명세 규칙에 대해서 명시해주자면 다음과 같다.

 

  • fee 프로퍼티는 amount = [] , gas = 0
  • 시그니처 데이터의 type은 "cosmos-sdk/StdTx" 
  • 메세지의 타입은 "sign/MsgSignData"로 통일
  • memo값은 빈 문자열
  • chainId = ''
  • nonce , sequence  = 0

 

먼저 그럼 adr36 signDoc 함수부터 만들자.

 

import { StdSignDoc } from "@cosmjs/amino";

export function makeADR36AminoSignDoc(signer: string, data: string) {

  let encodedData = '';
  if (Buffer) {
    encodedData = Buffer.from(data).toString('base64');
  } else {
    encodedData = btoa(data)
  }
  return {
    chain_id: "",
    account_number: "0",
    sequence: "0",
    fee: {
      gas: "0",
      amount: [],
    },
    msgs: [
      {
        type: "sign/MsgSignData",
        value: {
          signer,
          data: encodedData,
        },
      },
    ],
    memo: "",
  } as StdSignDoc
}

 

 

여기서 Amino가 그저 Sei만의 서비스 명칭으로 치부하여 시간을 굉장히 많이 낭비했다. "Amino"가 구버전, "Direct"가 최신 버전으로 이해하면 편하다.

 

함수명으로 명시했듯이, 'Amino' 다. 즉, Secp256k1HdWallet으로 서명해야지, DirectSecp256k1HdWallet으로 백날 서명해봤자 절대 안된다.

 

그리고 두번째는 명세에 나와있듯, 데이터가 한번 인코딩 된다.

Data represents the raw bytes of the content that is signed (text, json, etc)

 

명세서엔 위처럼 나와있는데, 일단 다른 cosmjs 기반 지갑 라이브러리들이 구현해놓은 ADR-36을 보면 base64인코딩을 사용한다.

 

 

**Base64 판별법**

더보기

대충 문자열이 온갖 알파벳에 숫자에 특수기호로 점철되었다? -> base64의심해보기

 

만약 문자열의 마지막이 '='로 끝난다? -> base64 99%확신

 

 

이제 위에서 얻은 도큐멘트를 서명만 하면 끝이다.

 

async function signArbitrary(mnemonic, message){
	const signer = Secp256k1HdWallet.fromMnemonic(
      mnemonic,
      {
        prefix
      }
    );
    const [account] = await signer.getAccounts();
    const ADR36SignDoc = makeADR36AminoSignDoc(account.address, 'hello world');
    const signature = await signer.signAmino(account.address, ADR36SignDoc);
    return signature
}