다중 서명 트랜잭션

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 Console > [Security] > [Credential]에서 발급받은 accessKeyId
secret-access-key 인증 비밀번호 KAS Console > [Security] > [Credential]에서 발급받은 secretAccessKey
krn (optional) 계정 저장소의 ID 기본 계정 저장소 사용 시 불필요

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

danger

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

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

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

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

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

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

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

  1. KAS에 Klaytn 계정 생성
  2. 계정을 다중 서명용 계정으로 업데이트(=계정 키를 다중 서명 키로 바꾸기)
  3. KLAY 전송 트랜잭션 생성
  4. 보류 중인 KLAY 전송 트랜잭션에 모든 계정이 서명
info

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

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

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

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

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

info

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

API 호출

입력한 Klaytn 계정 주소(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
cURLJavaScriptJava
Copy
Copied
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}" \
Copy
Copied
const result = await caver.kas.wallet.getMultiSigTransactionList(
  "0x3EE8aC5eBDDcF408020D1125437302B2267e5A8C"
);
Copy
Copied
MultisigTransactions transactions = caver.kas.wallet.getMultiSigTransactionList("0xBF19457580DcF1ed9E586F0C74747311a0d9d070");
System.out.println(transactions);

API 응답

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

cURLJavaScriptJava
Copy
Copied
{
  "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
    }
  ]
}
Copy
Copied
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'
    }
  ]
}
Copy
Copied
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: 1000000
            gasPrice: 0x5d21dba00
            input: null
            to: 0x95e3fd82ecd2b32cae8618599971f5f47f4bc110
            typeInt: 8
            value: 0x1
        }
        type: TX
        updatedAt: 1602562698
    }]
}
info

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

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

보류 중인 트랜잭션 서명

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

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

info

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

API 호출

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

cURLJavaScriptJava
Copy
Copied
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}" \
Copy
Copied
const address = "0x127089fF8154B145e8dcad7C112A949C2a452cb8";
const transactionId =
  "0xfe2be4de37ed40c6c049d3c2771a6e7577916c951dd331b297b517b25609b4ad";
const result = await caver.kas.wallet.signMultiSigTransction(
  address,
  transactionId
);
Copy
Copied
String address = "0x9dF8f1c6d7E6A1206083DB8e1e51d7dAe28B0312";
String transactionId = "0x86e3ab3978a73264af4fa968240b278f81196189803d038ef2da3e92f364c5aa";

MultisigTransactionStatus status = caver.kas.wallet.signMultiSigTransaction(address, transactionId);
System.out.println(status);

API 응답

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

cURLJavaScriptJava
Copy
Copied
// 전체 가중치 합계가 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
}
Copy
Copied
MultisigTransactionStatus {
  signedWeight: 1,
  status: 'Signed',
  threshold: 3,
  transactionId: '0xfe2be4de37ed40c6c049d3c2771a6e7577916c951dd331b297b517b25609b4ad',
  weight: 1,
  reminders: [
    '0xc4Dd4D041430c65d95CaaF6fB1506A542d6583d0',
    '0x55afF286674559caB1Fd4427C91C4cC045766140'
  ]
}
Copy
Copied
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를 호출하려면 계정 저장소와 계정을 생성하고 사용할 계정을 선택해야 합니다.

info

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

API 호출

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

cURLJavaScriptJava
Copy
Copied
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"
    }
  ]
}"
Copy
Copied
const transactionId = '0x7e7f18b16fb1807654d9cd2b1ad1c0cbb649b81648543a792a6db2f43e1a8ad5'
const signatures = [
  {
    V: '0x7f6'
    R: '0xc2902ebb52f554fd257eda57a3fe7cbf1e046bb43d1472bd396f2c3053f8bf55',
    S: '0x32f7d5b99e91510ecaefc5fe65816e6e43043c408873b2453d02116be1674278',
  }
]
const result = await caver.kas.wallet.appendSignatures(transactionId, signatures)
Copy
Copied
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의 응답은 아래와 같습니다.

cURLJavaScriptJava
Copy
Copied
// 다중 서명이 필요한 상황에서, 일부 서명만 받았을 경우: 기준치 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
}
Copy
Copied
MultisigTransactionStatus {
  signedWeight: 1,
  status: 'Signed',
  threshold: 3,
  transactionId: '0x7e7f18b16fb1807654d9cd2b1ad1c0cbb649b81648543a792a6db2f43e1a8ad5',
  weight: 1,
  reminders: [
    '0x54f91a712DAd60F78Fbb49E6043DF35dA37842Fd',
    '0x7725Ef7B7372Fd6E9093E8fA57f2c8a4c0622b8c'
  ]
}
Copy
Copied
class MultisigTransactionStatus {
    signedWeight: 4
    status: Submitted
    threshold: 3
    transactionHash: 0x9d969960396e66c4abe2e2495b852f1b99835f310c3f66d2f7b34eea43e29122
    transactionId: 0x7e7f18b16fb1807654d9cd2b1ad1c0cbb649b81648543a792a6db2f43e1a8ad5
    weight: 2
    reminders: [0x9dF8f1c6d7E6A1206083DB8e1e51d7dAe28B0312]
}
  • reminders : 아직 서명하지 않은 키의 주인인 계정 주소
  • signedWeight : 이 트랜잭션에 여태까지 서명된 키들의 가중치 누적합으로 이 값이 threshold 보다 커야 트랜잭션이 전송됨
  • weight : 서명된 키의 가중치

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