네, 안녕하세요
그럼 아래의 상황을 가정으로 답변 드리겠습니다.
-
test account의 accountKey가 AccountKeyWeightedMultiSig로 업데이트 되었다.
test account ===> (privateKey1, publicKey1) -> address 1 에서
test account ===> [(privateKey2, publicKey2), (privateKey3, publicKey3), (privateKey4, publicKey4)] -> address 1으로 업데이트 된 상황. (threshold: 2)
-
AccountKeyWeightedMultiSig는 3 개의 키로 업데이트 되었으며 각 키의 weight가 다르며 소유자도 다르다.
owner ===> [ address1, (privateKey2, publicKey2) ] wieght 2
operator1 ===> [address1, (privateKey3, publicKey3) ] weight 1
operator2 ===> [address1, (privateKey4, publicKey4) ] weight 1
위의 상황에서 operator들이 소유한 credential들을 사용하여 트랜잭션에 서명하고 전송하는 방법에 대해서 말씀드리겠습니다.
// ValueTransferTransaction 생성. multiSigAccount의 threshold는 2 임.
ValueTransferTransaction valueTransferTransaction = ValueTransferTransaction.create(
multiSigAccountAddress,
"0xe97f27e9a5765ce36a7b919b1cb6004c7209217e",
BigInteger.ONE,
BigInteger.valueOf(100_000)
);
// operator1이 소유한 credential로 서명. 이는 weight 1 이므로 아직 threshold에 충족되지 않음.
TransactionManager transactionManagerForOperator1 = new TransactionManager.Builder(caver, operator1Credential).setChaindId(chainId.getValue().intValue()).build();
KlayRawTransaction rawTransactionForOperator1 = transactionManagerForOperator1.sign(valueTransferTransaction);
// operator2가 소유한 credential로 서명. 여기서는 operator1이 서명한 결과에 이어서 서명하므로 기존에 operator1이 서명한 weight 1에 operator2가 서명 함으로써 weight 1이 추가 됨.
TransactionManager transactionManagerForOperator2 = new TransactionManager.Builder(caver, operator2Credential).setChaindId(chainId.getValue().intValue()).build();
KlayRawTransaction rawTransactionForOperator2 = transactionManagerForOperator2.sign(rawTransactionForOperator1.getValueAsString());
// threshold를 만족했으므로 서명된 결과를 네트워크로 전송
KlayTransactionReceipt.TransactionReceipt receiptWithOperators = transactionManagerForOperator2.executeTransaction(rawTransactionForOperator2.getValueAsString());
System.out.println(receiptWithOperators);
위의 코드와 같이, valueTransfer 트랜잭션에 operator1이 소유한 credential로 서명하고, operator1이 서명한 결과를 사용하여 operator2가 자신의 credential로 서명할 수 있습니다.
이렇게 진행하면 operator2가 서명한 결과인 rawTransactionForOperator2는 2개의 signatures를 소유하게 됩니다.
위의 테스트를 위한 전체 코드를 아래에 첨부하겠습니다 .참고 부탁드립니다.
// caver 연결 with Klaytn Node
Caver caver = Caver.build("http://52.78.238.123:8551/");
Quantity chainId = caver.klay().getChainID().send();
// 테스트 계정 생성을 위한 작업
String walletKey = "c126e2987dc32e96b0ce795614836a381e225975b7e312567fc87b75be87fa440x000x7ea9b9015ac473cdfa9c231e7bb939c02571fa22";
KlayCredentials credentials = KlayCredentials.createWithKlaytnWalletKey(walletKey);
TransactionManager transactionManager = new TransactionManager.Builder(caver, credentials).setChaindId(chainId.getValue().intValue()).build();
// update를 하기 위한 계정. KLAY가 필요하므로 아래는 테스트에 필요한 KLAY를 전송하는 과정
KlayCredentials updateCredential = KlayCredentials.create(Keys.createEcKeyPair());
String toAddress = updateCredential.getAddress();
KlayTransactionReceipt.TransactionReceipt receipt = ValueTransfer.create(caver, credentials, chainId.getValue().intValue())
.sendFunds(credentials.getAddress(), toAddress, BigDecimal.ONE, Convert.Unit.KLAY, BigInteger.valueOf(100_000)).send();
System.out.println(receipt);
// 실제 AccountKeyWeightedMultiSig를 위한 테스트 시작
// AccountKeyWeightedMultiSig를 위한 WeightedPublicKey 생성. 각 weight와 publicKey를 통해서 생성
String multiSigAccountAddress = updateCredential.getAddress();
ECKeyPair ownerKey = Keys.createEcKeyPair();
KlayCredentials ownerCredential = KlayCredentials.create(ownerKey, multiSigAccountAddress); // owner가 소유할 credential
AccountKeyWeightedMultiSig.WeightedPublicKey pubKey1 = AccountKeyWeightedMultiSig.WeightedPublicKey.create(
BigInteger.valueOf(2), // weight 2
AccountKeyPublic.create(ownerKey.getPublicKey())
);
ECKeyPair operator1Key = Keys.createEcKeyPair();
KlayCredentials operator1Credential = KlayCredentials.create(operator1Key, multiSigAccountAddress); // operator1이 소유할 credential
AccountKeyWeightedMultiSig.WeightedPublicKey pubKey2 = AccountKeyWeightedMultiSig.WeightedPublicKey.create(
BigInteger.valueOf(1), // weight 1
AccountKeyPublic.create(operator1Key.getPublicKey())
);
ECKeyPair operator2Key = Keys.createEcKeyPair();
KlayCredentials operator2Credential = KlayCredentials.create(operator2Key, multiSigAccountAddress); // operator2가 소유할 credential
AccountKeyWeightedMultiSig.WeightedPublicKey pubKey3 = AccountKeyWeightedMultiSig.WeightedPublicKey.create(
BigInteger.valueOf(1), // weight 1
AccountKeyPublic.create(operator2Key.getPublicKey())
);
// 여러 개의 WeightedPublicKey를 포함하는 리스트 생성
List<AccountKeyWeightedMultiSig.WeightedPublicKey> weightedKeys = new ArrayList<>();
weightedKeys.add(pubKey1);
weightedKeys.add(pubKey2);
weightedKeys.add(pubKey3);
// AccountKeyWeightedMultiSig 생성. threshold와 weightedPublicKey들을 포함하는 리스트를 통하여 생성.
AccountKeyWeightedMultiSig newAccountKey = AccountKeyWeightedMultiSig.create(BigInteger.valueOf(2), weightedKeys); // threshold 2
// Account update 트랜잭션 생성.
AccountUpdateTransaction updateTx = AccountUpdateTransaction.create(
multiSigAccountAddress,
newAccountKey,
BigInteger.valueOf(300_000)
);
// accountkey를 업데이트 하기 위하여 account update transaction을 서명 및 전송
transactionManager = new TransactionManager.Builder(caver, updateCredential).setChaindId(chainId.getValue().intValue()).build();
KlayRawTransaction klayRawTransaction = transactionManager.sign(updateTx);
KlayTransactionReceipt.TransactionReceipt transactionReceipt = transactionManager.executeTransaction(klayRawTransaction.getValueAsString());
System.out.println(transactionReceipt);
// ValueTransferTransaction 생성. multiSigAccount의 threshold는 2 임.
ValueTransferTransaction valueTransferTransaction = ValueTransferTransaction.create(
multiSigAccountAddress,
"0xe97f27e9a5765ce36a7b919b1cb6004c7209217e",
BigInteger.ONE,
BigInteger.valueOf(100_000)
);
// operator1이 소유한 credential로 서명. 이는 weight 1 이므로 아직 threshold에 충족되지 않음.
TransactionManager transactionManagerForOperator1 = new TransactionManager.Builder(caver, operator1Credential).setChaindId(chainId.getValue().intValue()).build();
KlayRawTransaction rawTransactionForOperator1 = transactionManagerForOperator1.sign(valueTransferTransaction);
// operator2가 소유한 credential로 서명. 여기서는 operator1이 서명한 결과에 이어서 서명하므로 기존에 operator1이 서명한 weight 1에 operator2가 서명 함으로써 weight 1이 추가 됨.
TransactionManager transactionManagerForOperator2 = new TransactionManager.Builder(caver, operator2Credential).setChaindId(chainId.getValue().intValue()).build();
KlayRawTransaction rawTransactionForOperator2 = transactionManagerForOperator2.sign(rawTransactionForOperator1.getValueAsString());
// threshold를 만족했으므로 서명된 결과를 네트워크로 전송
KlayTransactionReceipt.TransactionReceipt receiptWithOperators = transactionManagerForOperator2.executeTransaction(rawTransactionForOperator2.getValueAsString());
System.out.println(receiptWithOperators);
혹시 추가적으로 더 궁금한 부분이나 이해가 되지 않는 부분이 있다면 말씀해 주세요