다중 서명 트랜잭션

이 페이지는 Wallet API로 여러 계정이 서명해야하는 트랜잭션을 전송하는 방법을 안내합니다.

튜토리얼에 앞서

  • API 호출에 사용되는 x-chain-id 값은 8217(Cypress) 또는 1001(Baobab)입니다.

  • API 호출에 필요한 필수 파라미터는 각 예시에 설명됩니다.

API 호출 시 사용자가 입력해야 하는 값은 중괄호 1개({})로 표시합니다. 사용자가 입력해야 하는 값은 아래 테이블과 같습니다.

항목

비고

chain-id

8217 또는 1001

Cypress(Klaytn 메인넷) 또는 Baobab(Klaytn 테스트넷)

access-key-id

인증 아이디

KAS 콘솔 - Security - Credential에서 발급받은 accessKeyId

secret-access-key

인증 비밀번호

KAS 콘솔 - Security - Credential에서 발급받은 secretAccessKey

krn

(optional) 계정 저장소의 ID

기본 계정 저장소 사용 시 불필요

API 인증 키가 있으면 모든 KAS 서비스를 사용할 수 있으며 Wallet API를 호출해 만든 Klaytn 계정에 대한 모든 권한을 소유합니다. 모든 권한에는 Klaytn 계정의 자산(KLAY 등) 이동이나 트랜잭션 전송 및 실행 권한이 포함됩니다. 만약 API 인증 키에 타인이 접근한다면 Klaytn 계정 권한을 탈취당해 원치 않는 트랜잭션이 발생할 수 있습니다.

KAS/Klaytn 계정 보안을 위해 KAS API 인증 키(Secret Access Key)를 타인과 함부로 공유하지 말고 주의해 관리하십시오.

다중 서명이란?

다중 서명이란 말 그대로 여러개의 서명을 의미합니다. 클레이튼은 트랜잭션을 보내기 전에 트랜잭션에 서명을 받아야 합니다. 이 때, 1개 트랜잭션에 여러 클레이튼 계정이 서명해야 하는 경우가 있습니다. 이는 트랜잭션을 보내려는 계정이 다중 서명 계정, 즉 다중 서명 키를 가진 계정인 경우입니다.

트랜잭션과 트랜잭션 서명에 관한 자세한 내용은 다음을 확인하십시오. 여러분의 계정 키를 다중 서명 키로 바꾸는 방법은 다음을 확인하십시오.

다중 서명을 받는 트랜잭션 보내기

여러분은 다중 서명 계정(=다중 서명 키를 가진 계정)으로 트랜잭션에 여러 클레이튼 계정의 서명을 받은 후 트랜잭션을 전송할 수 있습니다. 여기에서는 다중 서명을 받은 KLAY 전송 트랜잭션을 보내는 방법을 안내합니다.

Klay를 보내려면 Klaytn Node에 트랜잭션을 보내야 하며, 트랜잭션을 보내려면 트랜잭션 수수료를 지불해야 합니다. API를 호출하려면 계정 저장소와 계정을 생성하고 사용할 계정을 선택해야 합니다. 이 예시를 따라 트랜잭션을 보내면, 보내는는 계정(Account)이 트랜잭션 수수료를 직접 부담합니다.

다중 서명을 받는 트랜잭션 전송 예시로써, KLAY 전송 트랜잭션을 보낼 때 여러 계정으로 서명하는 단계는 아래와 같습니다.

보류중인 트랜잭션이 필요한 모든 서명을 받으면 트랜잭션은 자동으로 클레이튼에 전송됩니다.

보류 중인 트랜잭션 목록 조회

현재 계정에서 보낸 트랜잭션 중 보류중인 트랜잭션 목록을 조회합니다.

현재 계정이 다중 서명 계정이고 트랜잭션을 전송하는 데 서명을 충분히 받지 못한 경우(=이미 서명에 사용된 키들의 가중치 합이 기준치를 넘지 못한 경우) 트랜잭션 상태(status)는 보류(Pending) 상태입니다. 다중 서명 계정으로 트랜잭션을 전송했어도 트랜잭션을 전송하기 위한 서명 개수가 부족하다면 트랜잭션은 필요한 서명을 모두 받을 때까지 보류 상태입니다.

API를 호출하려면 계정 저장소와 계정을 생성하고 사용할 계정을 선택해야 합니다.

KAS SDK(caver-js/caver-java extension) 설치, 실행에 관한 자세한 내용은 KAS SDK를 확인하십시오. 계정 저장소 생성, 계정 생성, 계정 선택에 관한 자세한 내용은 Getting Started를 확인하십시오.

API 호출

입력한 클레이튼 계정 주소(EOA)에서 보낸 트랜잭션 중에서 보류 중인 트랜잭션들을 불러오는 API를 호출합니다. API 호출 시 REST API 또는 SDKs(caver-js, caver-java extensions)를 사용할 수 있습니다.

쿼리 파라미터

여러분은 커서 방식 페이지네이션을 사용해 API 응답값을 받아올 수 있습니다. 검색 범위를 초단위로 지정할 수 있습니다.

파라미터 이름

설명

예시

필수

size

응답 아이템 개수 (min=1, max=1000, default=100)

size=100

False

cursor

페이지네이션으로 다음 요청을 보낼 때 필요한 커서

cursor=J9Ag...VM6z

False

to-timestamp

검색 범위: 마지막 시간의 타임스탬프 (초단위)

to-timestamp=

False

from-timestamp

검색 범위: 시작 시간의 타임스탬프 (초단위)

from-timestamp=

False

curl
javascript
java
curl
curl --location --request GET "https://wallet-api.klaytnapi.com/v2/multisig/account/0xc6C9356887b7F7887918Bf577417E5D8De253295/tx" \
-u {access-key-id}:{secret-access-key} \
--header "x-chain-id: {chain-id}" \
javascript
const result = await caver.kas.wallet.getMultiSigTransactionList('0x3EE8aC5eBDDcF408020D1125437302B2267e5A8C')
java
MultisigTransactions transactions = caver.kas.wallet.getMultiSigTransactionList("0xBF19457580DcF1ed9E586F0C74747311a0d9d070");
System.out.println(transactions);

API 응답

보류 중인 트랜잭션 목록 조회 API의 응답은 아래와 같습니다.

curl
javascript
java
curl
{
"cursor": "",
"items": [
{
"address": "0xc6C9356887b7F7887918Bf577417E5D8De253295",
"chainId": 1001,
"createdAt": 1599144020,
"multiSigKeys": [
{
"address": "0xc6C9356887b7F7887918Bf577417E5D8De253295",
"weight": 3
},
{
"address": "0x0b7caaf70e7A0a5399041c64711E535CE8B3cf7d",
"weight": 1
}
],
"status": 2,
"threshold": 4,
"transactionId": "0x65111d4fba621a1bfa3bd97c219b3e0454471cf3c07827396f1202946df51ee2",
"txData": {
"from": "0xc6c9356887b7f7887918bf577417e5d8de253295",
"gasLimit": 1000000,
"gasPrice": "0x5d21dba00",
"input": "0x6d656d6f",
"to": "0x2f87ba64de5526f7880f21481effbf950f70005c",
"typeInt": 16,
"value": "0x1001"
},
"type": "TX",
"updatedAt": 1599144020
},
{
"address": "0xc6C9356887b7F7887918Bf577417E5D8De253295",
"chainId": 1001,
"createdAt": 1599144013,
"multiSigKeys": [
{
"address": "0xc6C9356887b7F7887918Bf577417E5D8De253295",
"weight": 3
},
{
"address": "0x0b7caaf70e7A0a5399041c64711E535CE8B3cf7d",
"weight": 1
}
],
"status": 2,
"threshold": 4,
"transactionId": "0x36f9c5794fc141d3625e89a1164e6105fa973e8214d23bc6a210d2afe9dba6dd",
"txData": {
"from": "0xc6c9356887b7f7887918bf577417e5d8de253295",
"gasLimit": 1000000,
"gasPrice": "0x5d21dba00",
"input": "0x6d656d6f",
"to": "0x2f87ba64de5526f7880f21481effbf950f70005c",
"typeInt": 16,
"value": "0x100"
},
"type": "TX",
"updatedAt": 1599144013
}
]
}
javascript
MultisigTransactions {
cursor: '',
items: [
PendedTransaction {
chainId: 1001,
createdAt: 1602119611,
status: 2,
threshold: 3,
transactionId: '0xff94d85dd096b8f7d46763e226e0998346e9d75ba813cfd73520f700bf0207a0',
updatedAt: 1602119611,
address: '0x3EE8aC5eBDDcF408020D1125437302B2267e5A8C',
multiSigKeys: [
MultisigAddress {
address: '0x38614901Dcd4FAF796A0e2FE8aC19E5147A59f3f',
weight: 1
},
MultisigAddress {
address: '0x9E5FE19695ac38239E4432eC5BE7bBEFcc4d415A',
weight: 1
},
MultisigAddress {
address: '0xB7B4f049eFC6B650ACCDa59229a46B19210c2cfA',
weight: 1
}
],
txData: TxData {
from: '0x3ee8ac5ebddcf408020d1125437302b2267e5a8c',
gas: 25000,
gasPrice: '0x5d21dba00',
to: '0x76c6b1f34562ed7a843786e1d7f57d0d7948a6f1',
typeInt: 8,
value: '0x1'
},
type: 'TX'
}
]
}
java
class MultisigTransactions {
cursor:
items: [class PendedTransaction {
address: 0xBF19457580DcF1ed9E586F0C74747311a0d9d070
chainId: 1001
createdAt: 1602562698
multiSigKeys: [class MultisigAddress {
address: 0xBF19457580DcF1ed9E586F0C74747311a0d9d070
weight: 2
}, class MultisigAddress {
address: 0x9dF8f1c6d7E6A1206083DB8e1e51d7dAe28B0312
weight: 2
}, class MultisigAddress {
address: 0xB011BE8EB2898417D53A91E6979118D157638C5d
weight: 2
}]
status: 2
threshold: 3
transactionId: 0x86e3ab3978a73264af4fa968240b278f81196189803d038ef2da3e92f364c5aa
txData: class TxData {
from: 0xbf19457580dcf1ed9e586f0c74747311a0d9d070
gas: 100000
gasPrice: 0x5d21dba00
input: null
to: 0x95e3fd82ecd2b32cae8618599971f5f47f4bc110
typeInt: 8
value: 0x1
}
type: TX
updatedAt: 1602562698
}]
}

typeInt 변수는 트랜잭션 종류를 구별하는 값입니다. 트랜잭션의 종류에 관한 자세한 내용은 다음을 확인하십시오.

이 API에 관한 자세한 내용은 다음을 확인하십시오. 이 문서 혹은 KAS에 관한 문의는 개발자 포럼을 방문해 도움을 받으십시오.

보류 중인 트랜잭션에 서명하기

계정으로 특정 트랜잭션에 서명하기 API를 호출해 보류중인 트랜잭션에 서명합니다. 현재 계정이 다중 서명 계정이고 트랜잭션을 전송하는 데 서명을 충분히 받지 못한 경우(=이미 서명에 사용된 키들의 가중치 합이 기준치를 넘지 못한 경우) 트랜잭션 상태(status)는 보류(Pending) 상태입니다.

API를 호출하려면 계정 저장소와 계정을 생성하고 사용할 계정을 선택해야 합니다.

KAS SDK(caver-js/caver-java extension) 설치, 실행에 관한 자세한 내용은 KAS SDK를 확인하십시오. 계정 저장소 생성, 계정 생성, 계정 선택에 관한 자세한 내용은 Getting Started를 확인하십시오.

API 호출

보류 중인 트랜잭션 서명 API를 호출합니다. API 호출 시 REST API 또는 SDKs(caver-js, caver-java extensions)를 사용할 수 있습니다.

curl
javascript
java
curl
curl --location --request POST "https://wallet-api.klaytnapi.com/v2/multisig/account/0x68Da92c0557A62C292598A3156B770df6e07BD83/tx/0x5d7beaf43d63d27bf8ddd11ac32ee3c853abfe869988526f92431a63fe3dcb1d/sign" \
-u {access-key-id}:{secret-access-key} \
--header "x-chain-id: {chain-id}" \
javascript
const address = '0x127089fF8154B145e8dcad7C112A949C2a452cb8'
const transactionId = '0xfe2be4de37ed40c6c049d3c2771a6e7577916c951dd331b297b517b25609b4ad'
const result = await caver.kas.wallet.signMultiSigTransction(address, transactionId)
java
String address = "0x9dF8f1c6d7E6A1206083DB8e1e51d7dAe28B0312";
String transactionId = "0x86e3ab3978a73264af4fa968240b278f81196189803d038ef2da3e92f364c5aa";
MultisigTransactionStatus status = caver.kas.wallet.signMultiSigTransaction(address, transactionId);
System.out.println(status);

API 응답

보류 중인 트랜잭션 서명 API의 응답은 아래와 같습니다.

curl
javascript
java
curl
// 전체 가중치 합계가 4(=기준치) 이상이어야 하는 상황에서, 일부 서명만 받았을 경우: 가중치 1짜리 서명만 받은 경우
{
"reminders": [
"0xf24e881d3cFF241859203DB09a28421267B7F6E6"
],
"signedWeight": 1,
"status": "Signed",
"threshold": 4,
"transactionID": "0xfa275dba88d197a85504ef70e0dd2640acc708817e9eb3933d7850acfb048649",
"weight": 1
}
// 전체 가중치 합계가 4(=기준치) 이상이어야 하는 상황에서, 트랜잭션 전송에 필요한 모든 서명을 받았을 경우: : 가중치 1짜리 서명과 가중치 3짜리 서명까지 받은 경우
{
"signedWeight": 4,
"status": "Submitted",
"threshold": 4,
"transactionHash": "0x81f2ff422eae9b40d65b7a6f1e3c5ca598f83d1473ccc87e53d51b875fe75c82",
"transactionID": "0xfa275dba88d197a85504ef70e0dd2640acc708817e9eb3933d7850acfb048649",
"weight": 3
}
javascript
MultisigTransactionStatus {
signedWeight: 1,
status: 'Signed',
threshold: 3,
transactionId: '0xfe2be4de37ed40c6c049d3c2771a6e7577916c951dd331b297b517b25609b4ad',
weight: 1,
reminders: [
'0xc4Dd4D041430c65d95CaaF6fB1506A542d6583d0',
'0x55afF286674559caB1Fd4427C91C4cC045766140'
]
}
java
class MultisigTransactionStatus {
signedWeight: 4
status: Submitted
threshold: 3
transactionHash: 0xa9286090d32df1aa8aa08235293bc0ddaffc84dc74b712d827a7a93e7eff9e36
transactionId: 0x86e3ab3978a73264af4fa968240b278f81196189803d038ef2da3e92f364c5aa
weight: 2
reminders: [0xB011BE8EB2898417D53A91E6979118D157638C5d]
}
  • reminders: 아직 서명하지 않은 키의 주인인 계정 주소

  • signedWeight: 이 트랜잭션에 여태까지 서명된 키들의 가중치 누적합으로 이 값이 threshold보다 커야 트랜잭션이 전송됨

  • weight: 서명된 키의 가중치

이 API에 관한 자세한 내용은 다음을 확인하십시오. 이 문서 혹은 KAS에 관한 문의는 개발자 포럼을 방문해 도움을 받으십시오.

보류 중인 트랜잭션에 서명하기 - 미리 준비한 서명 사용하기

보류중인 트랜잭션에 서명합니다. 이 때 미리 준비한 서명 값으로 보류중인 트랜잭션에 서명합니다.

KAS 외부에서 만든 Klaytn 계정이 있고 이 계정의 서명 값이 있다면, 이 서명 값으로 트랜잭션에 서명할 수 있습니다. 현재 계정이 다중 서명 계정이고 트랜잭션을 전송하는 데 서명을 충분히 받지 못한 경우(=이미 서명에 사용된 키들의 가중치 합이 기준치를 넘지 못한 경우) 트랜잭션 상태(status)는 보류(Pending) 상태입니다.

API를 호출하려면 계정 저장소와 계정을 생성하고 사용할 계정을 선택해야 합니다.

KAS SDK(caver-js/caver-java extension) 설치, 실행에 관한 자세한 내용은 KAS SDK를 확인하십시오. 계정 저장소 생성, 계정 생성, 계정 선택에 관한 자세한 내용은 Getting Started를 확인하십시오.

API 호출

보류 중인 트랜잭션 서명 API를 호출합니다. API 호출 시 REST API 또는 SDKs(caver-js, caver-java extensions)를 사용할 수 있습니다.

curl
javascript
java
curl
curl --location --request POST "https://wallet-api.klaytnapi.com/v2/multisig/tx/0x5d7beaf43d63d27bf8ddd11ac32ee3c853abfe869988526f92431a63fe3dcb1d/sign" \
-u {access-key-id}:{secret-access-key} \
--header "x-chain-id: {chain-id}" \
--header "Content-Type: application/json" \
--data-raw "{
"signatures": [
{
"R": "0xaa2ae446f5dd35df839e8ec2005aede91f0b3ea0f1e6889f4294d4760529bfaf",
"S": "0x7b3efab682bcc86f7050819e12a2b5ea916871d684b9e1c8ca8f49869df41896",
"V": "0x7f5"
}
]
}"
javascript
const transactionId = '0x7e7f18b16fb1807654d9cd2b1ad1c0cbb649b81648543a792a6db2f43e1a8ad5'
const signatures = [
{
V: '0x7f6'
R: '0xc2902ebb52f554fd257eda57a3fe7cbf1e046bb43d1472bd396f2c3053f8bf55',
S: '0x32f7d5b99e91510ecaefc5fe65816e6e43043c408873b2453d02116be1674278',
}
]
const result = await caver.kas.wallet.appendSignatures(transactionId, signatures)
java
String transactionID = "0x7e7f18b16fb1807654d9cd2b1ad1c0cbb649b81648543a792a6db2f43e1a8ad5";
Signature signature = new Signature();
signature.setV("0x7f6");
signature.setR("0xeacce28162b45142d2eefb77f124e15384597745cbf5996d3bfa5d61186e1769");
signature.setS("0x5254543d277f7b471dd684d349cde586f34e04ed935ed57fd4c66171883e947b");
SignPendingTransactionBySigRequest request = new SignPendingTransactionBySigRequest();
request.setSignatures(Arrays.asList(signature));
MultisigTransactionStatus transactionStatus = caver.kas.wallet.appendSignatures(transactionID, request);
System.out.println(transactionStatus);
  • signatures: ECDSA 서명 정보(R,S)와 공개키 복원 정보(V)로 구성된 미리 준비한 서명값입니다.

API 응답

보류 중인 트랜잭션 서명 API의 응답은 아래와 같습니다.

curl
javascript
java
curl
// 다중 서명이 필요한 상황에서, 일부 서명만 받았을 경우: 기준치 4에 가중치 3짜리 서명만 받은 경우
{
"reminders": [
"0xA9183eD590ebEDf06D415ae684E3f18d06789f8d"
],
"signedWeight": 3,
"status": "Signed",
"threshold": 4,
"transactionId": "0xa0cabe28c75aa6babbf7e85b5033641c46d0f2e7b714e47103716695d454a45a",
"weight": 3
}
// 다중 서명이 필요한 상황에서, 트랜잭션 전송에 필요한 모든 서명을 받았을 경우: : 기준치 4에 가중치 1짜리 서명까지 받은 경우
{
"signedWeight": 4,
"status": "Submitted",
"threshold": 4,
"transactionHash": "0xf1ced3855f3cd1d5220f2991ec4ba845ec747a0c01028c2d63de3662ddad2083",
"transactionId": "0xae20ed8ce084d372fb804ea6f6073ba2f485a64bac086199efb83d665d0b31f2",
"weight": 1
}
javascript
MultisigTransactionStatus {
signedWeight: 1,
status: 'Signed',
threshold: 3,
transactionId: '0x7e7f18b16fb1807654d9cd2b1ad1c0cbb649b81648543a792a6db2f43e1a8ad5',
weight: 1,
reminders: [
'0x54f91a712DAd60F78Fbb49E6043DF35dA37842Fd',
'0x7725Ef7B7372Fd6E9093E8fA57f2c8a4c0622b8c'
]
}
java
class MultisigTransactionStatus {
signedWeight: 4
status: Submitted
threshold: 3
transactionHash: 0x9d969960396e66c4abe2e2495b852f1b99835f310c3f66d2f7b34eea43e29122
transactionId: 0x7e7f18b16fb1807654d9cd2b1ad1c0cbb649b81648543a792a6db2f43e1a8ad5
weight: 2
reminders: [0x9dF8f1c6d7E6A1206083DB8e1e51d7dAe28B0312]
}
  • reminders: 아직 서명하지 않은 키의 주인인 계정 주소

  • signedWeight: 이 트랜잭션에 여태까지 서명된 키들의 가중치 누적합으로 이 값이 threshold보다 커야 트랜잭션이 전송됨

  • weight: 서명된 키의 가중치

이 API에 관한 자세한 내용은 다음을 확인하십시오. 이 문서 혹은 KAS에 관한 문의는 개발자 포럼을 방문해 도움을 받으십시오.