본문으로 건너뛰기

다중 서명 인증

다음 단계는 다중 서명(multisig) transaction을 생성한 다음 Sui CLI를 사용해 network에 제출하는 방법을 보여준다. transaction은 object transfer, package publish 또는 upgrade, SUI payment 등이 될 수 있다.

TypeScript SDK를 사용해 다중 서명 주소(multisig address)를 만들고 다중 서명 transaction을 생성하는 방법을 더 알아보려면 SDK documentation을 참조한다.

Click to open

Create Sui account and setup CLI environment

$ sui client

If this is the first time running the sui client CLI tool, it asks you to provide a Sui full node server URL and a meaningful environment alias. It also generates an address with a random key pair in sui.keystore and a config client.yaml.

By default, the client.yaml and sui.keystore files are located in ~/.sui/sui_config. For more information, refer to the Sui client CLI tutorial.

If this is not your first time running sui client, then you already have a client.yaml file in your local environment. If you'd like to create a new address for this tutorial, use the command:

$ sui client new-address ed25519
  • Obtain test tokens.
Click to open

How to obtain tokens

If you are connected to Devnet or Testnet networks, use the Faucet UI to request tokens.

If you are connected to a local full node, learn how to get local network tokens.

이 문서는 Sui CLI, 특히 sui clientsui keytool command에 어느 정도 익숙하다고 가정한다. 따라서 어떤 command는 별도의 맥락 설명 없이 소개될 수 있다. 참조된 command의 세부사항이 확실하지 않다면 Sui CLI documentation에서 자세한 정보를 확인한다.

object를 받으려면 작업 중인 network에 이미 존재하는 address가 하나 필요하다. 이 문서는 이 address가 현재 active address(sui client active-address)라고 가정하지만, 접근 가능한 어떤 address여도 괜찮다.

이 문서는 또한 active environment가 Testnet(sui client active-env)이라고 가정한다. 이 단계는 Devnet 또는 local network에서도 수행할 수 있지만, command를 그에 맞게 조정해야 한다.

Executing multisig transactions

다중 서명을 보여주기 위해 이 문서는 Sui CLI를 사용해 다중 서명 transaction을 설정하고 실행하는 과정을 안내한다.

Create addresses with different schemes

먼저 나중에 instruction에서 수행할 transaction의 signer 역할을 할 address 세 개를 만든다. sui client new-address command를 사용해 지원되는 세 가지 key scheme에 대한 Sui address와 public key를 생성한다.

$ sui client new-address ed25519
$ sui client new-address secp256k1
$ sui client new-address secp256r1

console은 각 성공적인 호출에 대해 다음과 비슷한 response를 표시한다:

╭──────────────────────────────────────────────────╮
│ Created new key pair and saved it to keystore. │
├────────────────┬─────────────────────────────────┤
│ alias │ <ALIAS> │
│ address │ <SUI-ADDRESS> │
│ keyScheme │ <KEY-SCHEME> │
│ recoveryPhrase │ <RECOVERY-PHRASE> │
╰────────────────┴─────────────────────────────────╯

blockchain data를 다룰 때 address와 hashed value는 CLI 환경에서 다루기 번거로운 긴 string을 만든다. 후속 command에서 값을 더 쉽게 참조하고(그리고 copy and paste를 쉽게 하기 위해) 이 문서는 shell variable을 사용한다. console response에서 받은 값을 사용해 이 address들에 대한 shell variable을 설정하되, <SUI-ADDRESS-*> 변수는 적절한 address로 바꾼다.

$ ADDRESS1=<SUI-ADDRESS-ED25519>
$ ADDRESS2=<SUI-ADDRESS-SECP256K1>
$ ADDRESS3=<SUI-ADDRESS-SECP256R1>

active address를 할당한 shell variable도 하나 더 만든다.

$ ACTIVE=<ACTIVE-ADDRESS>

원한다면 shell variable에 address 대신 alias 값을 설정해도 된다.

Verify addresses

sui keytool을 사용해 이전 section에서 만든 address를 나열한다.

$ sui keytool list

response는 다음과 비슷하지만 실제 alias 이름, address, key, peer ID를 표시한다:

╭────────────────────────────────────────────────────────────────────╮
│ ╭─────────────────┬──────────────────────────────────────────────╮ │
| | alias | <ALIAS-NAME> | |
│ │ suiAddress │ <SUI-ADDRESS> │ │
│ │ publicBase64Key │ <PUBLIC-KEY> │ │
│ │ keyScheme │ ed25519 │ │
│ │ flag │ 0 │ │
│ │ peerId │ <PEER-ID> │ │
│ ╰─────────────────┴──────────────────────────────────────────────╯ │
│ ╭─────────────────┬──────────────────────────────────────────────╮ │
| | alias | <ALIAS-NAME> | |
│ │ suiAddress │ <SUI-ADDRESS> │ │
│ │ publicBase64Key │ <PUBLIC-KEY> │ │
│ │ keyScheme │ secp256k1 │ │
│ │ flag │ 0 │ │
│ │ peerId │ <PEER-ID> │ │
│ ╰─────────────────┴──────────────────────────────────────────────╯ │
│ ╭─────────────────┬──────────────────────────────────────────────╮ │
| | alias | <ALIAS-NAME> | |
│ │ suiAddress │ <SUI-ADDRESS> │ │
│ │ publicBase64Key │ <PUBLIC-KEY> │ │
│ │ keyScheme │ secp256r1 │ │
│ │ flag │ 0 │ │
│ │ peerId │ <PEER-ID> │ │
│ ╰─────────────────┴──────────────────────────────────────────────╯ │
╰────────────────────────────────────────────────────────────────────╯

output에는 나중에 사용할 public key 데이터가 포함되어 있으므로, 이 정보를 저장할 shell variable을 만든다. <PUBLIC-KEY-*>를 이전 console response에서 받은 실제 값으로 바꾸는 것을 잊지 않는다.

$ PKEY_1=<PUBLIC-KEY-ED25519>
$ PKEY_2=<PUBLIC-KEY-SECP256K1>
$ PKEY_3=<PUBLIC-KEY-SECP256R1>

Create a multisig address

다중 서명을 사용해 transaction에 서명하려면 sui keytool multi-sig-address를 사용해 다중 서명 주소를 만들어야 한다. 다중 서명 주소는 각 개별 참여 address의 public key를 사용해 생성된다. 또한 각 address에는 유효한 signature를 만드는 데 얼마나 필요한지를 결정하는 weight 값이 할당된다. 합산했을 때 포함된 signature의 weight는 command에서 함께 설정하는 threshold 값 이상이어야 한다. 이 예시에서는 다음 command를 사용하며, 이는 첫 번째 두 address는 유효한 다중 서명을 만들기 위해 적어도 하나의 signature가 더 필요하다는 뜻이다. 마지막 address는 threshold 값과 같은 3의 weight를 가지므로 그 소유자만으로도 유효한 signature를 만들 수 있다.

$ sui keytool multi-sig-address --pks $PKEY_1 $PKEY_2 $PKEY_3 --weights 1 2 3 --threshold 3

response는 다음과 비슷하다:

╭─────────────────┬─────────────────────────────────────────────────────────╮
│ multisigAddress │ <MULTISIG-ADDRESS> │
│ multisig │ ╭─────────────────────────────────────────────────────╮ │
│ │ │ ╭─────────────────┬───────────────────────────────╮ │ │
│ │ │ │ address │ <SUI-ADDRESS> │ │ │
│ │ │ │ publicBase64Key │ <PUBLIC-KEY> │ │ │
│ │ │ │ weight │ 1 │ │ │
│ │ │ ╰─────────────────┴───────────────────────────────╯ │ │
│ │ │ ╭─────────────────┬───────────────────────────────╮ │ │
│ │ │ │ address │ <SUI-ADDRESS> │ │ │
│ │ │ │ publicBase64Key │ <PUBLIC-KEY> │ │ │
│ │ │ │ weight │ 2 │ │ │
│ │ │ ╰─────────────────┴───────────────────────────────╯ │ │
│ │ │ ╭─────────────────┬───────────────────────────────╮ │ │
│ │ │ │ address │ <SUI-ADDRESS> │ │ │
│ │ │ │ publicBase64Key │ <PUBLIC-KEY> │ │ │
│ │ │ │ weight │ 3 │ │ │
│ │ │ ╰─────────────────┴───────────────────────────────╯ │ │
│ │ ╰─────────────────────────────────────────────────────╯ │
╰─────────────────┴─────────────────────────────────────────────────────────╯

Add SUI to the multisig address

SUI를 받기 전에 이전 response의 맨 위에 있는 다중 서명 주소를 MULTISIG shell variable에 설정한다(<MULTISIG-ADDRESS>를 실제 address로 대체한다).

$ MULTISIG=<MULTISIG-ADDRESS>

sui client objects $MULTISIG command를 사용하면 새로 만든 다중 서명 주소에 object가 없다는 것을 볼 수 있다. 이는 transaction을 수행하기 전에 SUI를 받아야 함을 뜻한다. 다중 서명 계정에 SUI를 받으려면 sui client faucet command를 사용하고 --address flag로 다중 서명 주소를 제공한다. 이 command를 두 번 실행하여 다중 서명 주소가 적어도 SUI 두 개를 소유하게 한다. 이 예시에서는 하나는 transfer에 사용하고 다른 하나는 gas를 지불하는 데 사용하기 위해 SUI 두 개를 사용한다.

$ sui client faucet --address $MULTISIG

sui client gas command를 사용해 이제 해당 address에 적어도 SUI 두 개가 있는지 확인한다.

$ sui client gas $MULTISIG

Transfer SUI to your active address

이제 다중 서명 주소에서 object를 transfer할 차례이다. 단순화를 위해 이 예시는 다중 서명 주소가 소유한 coin 중 하나를 transfer object로 사용한다. address의 coin 하나에 대한 object ID를 복사하고 이를 사용해 shell variable 값을 설정한다.

$ COIN=<COIN-OBJECT-ID>

sui client transfer command를 사용해 transfer를 설정한다. --serialize-unsigned-transaction flag는 Base64로 인코딩된 transaction bytes를 출력한다.

Beginning with the Sui v1.24.1 release, the --gas-budget option is no longer required for CLI commands.

$ sui client transfer --to $ACTIVE --object-id $COIN --gas-budget <GAS-AMOUNT> --serialize-unsigned-transaction

console은 결과값(<TX-BYTES-RESULT>)을 표시하며, 이를 다른 shell variable에 할당할 수 있다.

$ TXBYTES=<TX-BYTES-RESULT>

Sign the transaction with two public keys

sui keytool sign command를 사용해 앞서 만든 address 중 두 개로 transaction에 서명한다.

정보

flag || sig || pk로 serialize하기만 하면 다른 도구를 사용해 signature를 생성할 수도 있다.

$ sui keytool sign --address $ADDRESS1 --data $TXBYTES
$ sui keytool sign --address $ADDRESS2 --data $TXBYTES

command를 성공적으로 호출할 때마다 다음과 비슷한 response를 받는다.

╭──────────────┬─────────────────────────────╮
│ suiAddress │ <ADDRESS> │
│ rawTxData │ <TRANSACTION-HASH> │
│ intent │ ╭─────────┬─────╮ │
│ │ │ scope │ 0 │ |
│ │ │ version │ 0 │ |
│ │ │ app_id │ 0 │ |
| | ╰─────────┴─────╯ │
│ rawIntentMsg │ <INTENT-MSG-HASH> │
│ digest │ <DIGEST-HASH> │
│ suiSignature │ <SIGNATURE-HASH> │
╰──────────────┴─────────────────────────────╯

signature를 저장할 shell variable 두 개를 더 만들되, <SIGNATURE-HASH-*>는 이전 command response의 값으로 바꾼다.

$ SIG_1=<SIGNATURE-HASH-ED25519>
$ SIG_2=<SIGNATURE-HASH-SECP256K1>

Combine individual signatures into a multisig

앞서 언급했듯 다중 서명은 참여 signer의 weight 합이 threshold 값 이상이 되도록 충분한 개별 signature로 구성되어야 한다. sui keytool multi-sig-combine-partial-sig command를 사용해 ed25519 signature(weight: 1)와 secp256k1(weight: 2)를 결합한다. command를 완성하려면 다중 서명 주소를 정의했던 모든 public key, 각 weight, threshold를 제공해야 한다.

$ sui keytool multi-sig-combine-partial-sig --pks $PKEY_1 $PKEY_2 $PKEY_3 --weights 1 2 3 --threshold 3 --sigs $SIG_1 $SIG_2

성공하면 console은 다음과 비슷한 메시지로 응답한다.

╭────────────────────┬──────────────────────────────╮
│ multisigAddress │ <MULTISIG-ADDRESS> │
│ multisigParsed │ <MULTISIG-PARSED-HASH> │
│ multisigSerialized │ <MULTISIG-SERIALIZED-HASH> │
╰────────────────────┴──────────────────────────────╯

Execute the transaction

sui client execute-signed-tx를 사용해 다중 서명 transaction을 실행한다. 이전 response에서 받은 multisigSerialized 값을 shell variable로 설정한 다음, 이를 사용해 execute-signed-tx command를 구성한다.

$ MULTISIG_SERIALIZED=<MULTISIG-SERIALIZED-HASH>
$ sui client execute-signed-tx --tx-bytes $TXBYTES --signatures $MULTISIG_SERIALIZED

성공하면 console은 transaction detail을 응답한다.

Click to open

Transaction response

이 response는 테스트 서명에서 나온 실제 값을 담고 있다. response의 형식은 같아야 하지만, 여러분이 받는 값은 다를 것이다.

Transaction Digest: 7mBWUxT6HUVDa8bii3PZJc7nhWqefTLNTsGbHYnx7ZA4
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Data │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Sender: 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 │
│ Gas Owner: 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 │
│ Gas Budget: 2997880 MIST │
│ Gas Price: 1000 MIST │
│ Gas Payment: │
│ ┌── │
│ │ ID: 0xc62a5e163e599729509d6cebde097cac04e5d1b3bbc9a169144e8dfa602a0768 │
│ │ Version: 289574879 │
│ │ Digest: 2PMc8L67YbZmna4hoaryX9cZZFSgFNPEYPEeCqcDPCcX │
│ └── │
│ │
│ Transaction Kind: Programmable │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Input Objects │ │
│ ├──────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │
│ │ 0 Pure Arg: Type: address, Value: "0x65437300e280695a40df8cf524c7bca6ad62574cac3a52d3b085ad628c797241" │ │
│ │ 1 Imm/Owned Object ID: 0xe7acb59c190d7fcfcb622916e929c92007f6da15128fd84c8a2afd94a39edf11 │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ ╭──────────────────────╮ │
│ │ Commands │ │
│ ├──────────────────────┤ │
│ │ 0 TransferObjects: │ │
│ │ ┌ │ │
│ │ │ Arguments: │ │
│ │ │ Input 1 │ │
│ │ │ Address: Input 0 │ │
│ │ └ │ │
│ ╰──────────────────────╯ │
│ │
│ Signatures: │
│ AwICIrr3sYG1hx2DaVkS3levGuTv68GA1RL+6ZFbtnFV5PBPkEHuysjme9nG0hZ3hQ0eDds2CedbKkLqDyCUXMNQDwEUtr9SYWRGiJJih21cAXgpSxf5Y53HFcmzJPWfxac54l21YVx6hc7vhI1xunMzhVeQlCa53vVJiAtWKLKz+H7FBgADAPZrm85y/Gn83R6kUhXme9J8W2ilJyda6cAObtuyJ3CqAQICAwSWHr3Q2vGVFH4SQckaQs76X89S6hX3NUarydSY3jgCAQNqj1MFWmTysOPFDXdNfD2kJlQhWTiT3AbxdlJDDWozIgMDAA== │
│ │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Effects │
├───────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Digest: 7mBWUxT6HUVDa8bii3PZJc7nhWqefTLNTsGbHYnx7ZA4 │
│ Status: Success │
│ Executed Epoch: 600 │
│ Mutated Objects: │
│ ┌── │
│ │ ID: 0xc62a5e163e599729509d6cebde097cac04e5d1b3bbc9a169144e8dfa602a0768 │
│ │ Owner: Account Address ( 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 ) │
│ │ Version: 289574880 │
│ │ Digest: DWmLziJZEHwhkAfdBWVhn8HnJU7DMepDmjVLps2peSx8 │
│ └── │
│ ┌── │
│ │ ID: 0xe7acb59c190d7fcfcb622916e929c92007f6da15128fd84c8a2afd94a39edf11 │
│ │ Owner: Account Address ( 0x65437300e280695a40df8cf524c7bca6ad62574cac3a52d3b085ad628c797241 ) │
│ │ Version: 289574880 │
│ │ Digest: JBA6PrhWuTUJ3P8NXBpgBetFBaSJacEvQKS4USK9EfAr │
│ └── │
│ Gas Object: │
│ ┌── │
│ │ ID: 0xc62a5e163e599729509d6cebde097cac04e5d1b3bbc9a169144e8dfa602a0768 │
│ │ Owner: Account Address ( 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 ) │
│ │ Version: 289574880 │
│ │ Digest: DWmLziJZEHwhkAfdBWVhn8HnJU7DMepDmjVLps2peSx8 │
│ └── │
│ Gas Cost Summary: │
│ Storage Cost: 1976000 MIST │
│ Computation Cost: 1000000 MIST │
│ Storage Rebate: 1956240 MIST │
│ Non-refundable Storage Fee: 19760 MIST │
│ │
│ Transaction Dependencies: │
│ F6TBXbvdK9fi4BnxZMBkL7QeNyv1612778i12ZPhafJD │
│ HFi4TniDvgL1jDzgPHjzJhxR8nbavLmPH3LLDnNL5Tqd │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─────────────────────────────╮
│ No transaction block events │
╰─────────────────────────────╯

╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes │
├──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Mutated Objects: │
│ ┌── │
│ │ ObjectID: 0xc62a5e163e599729509d6cebde097cac04e5d1b3bbc9a169144e8dfa602a0768 │
│ │ Sender: 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 │
│ │ Owner: Account Address ( 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 ) │
│ │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI> │
│ │ Version: 289574880 │
│ │ Digest: DWmLziJZEHwhkAfdBWVhn8HnJU7DMepDmjVLps2peSx8 │
│ └── │
│ ┌── │
│ │ ObjectID: 0xe7acb59c190d7fcfcb622916e929c92007f6da15128fd84c8a2afd94a39edf11 │
│ │ Sender: 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 │
│ │ Owner: Account Address ( 0x65437300e280695a40df8cf524c7bca6ad62574cac3a52d3b085ad628c797241 ) │
│ │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI> │
│ │ Version: 289574880 │
│ │ Digest: JBA6PrhWuTUJ3P8NXBpgBetFBaSJacEvQKS4USK9EfAr │
│ └── │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Balance Changes │
├───────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ┌── │
│ │ Owner: Account Address ( 0x65437300e280695a40df8cf524c7bca6ad62574cac3a52d3b085ad628c797241 ) │
│ │ CoinType: 0x2::sui::SUI │
│ │ Amount: 1000000000 │
│ └── │
│ ┌── │
│ │ Owner: Account Address ( 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 ) │
│ │ CoinType: 0x2::sui::SUI │
│ │ Amount: -1001019760 │
│ └── │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯