From 41dd43ddef3a4fb80804d324d8475ce5f3e5e705 Mon Sep 17 00:00:00 2001 From: Thai Tran Date: Thu, 6 Jul 2023 09:48:50 +0700 Subject: [PATCH 1/2] change the value of AminoMsg to the general type, add deletege tx testing --- .../network/finschia/sdk/example/Client.kt | 142 +++++++++++++++++- .../finschia/sdk/legacymultisig/SignDoc.kt | 11 +- 2 files changed, 143 insertions(+), 10 deletions(-) diff --git a/examples/multisig-example/src/main/kotlin/network/finschia/sdk/example/Client.kt b/examples/multisig-example/src/main/kotlin/network/finschia/sdk/example/Client.kt index 9f1820d..252f9eb 100644 --- a/examples/multisig-example/src/main/kotlin/network/finschia/sdk/example/Client.kt +++ b/examples/multisig-example/src/main/kotlin/network/finschia/sdk/example/Client.kt @@ -29,6 +29,78 @@ class TxClient(private val channel: ManagedChannel) : Closeable { } } +class MultisigMsgDelegate { + companion object { + fun createMsgDelegate( + delegatorAddress: String, + validatorAddress: String, + amounts: cosmos.base.v1beta1.CoinOuterClass.Coin + ): cosmos.staking.v1beta1.Tx.MsgDelegate { + return cosmos.staking.v1beta1.msgDelegate { + this.delegatorAddress = delegatorAddress + this.validatorAddress = validatorAddress + this.amount = amounts + } + } + fun convertMsgDelegatorToAminoMsg(msgDelegate: cosmos.staking.v1beta1.Tx.MsgDelegate): AminoMsg { + + val jsonAminoMsgDelegateValue = AminoMsgDelegateValue( + delegatorAddress = msgDelegate.delegatorAddress, + validatorAddress = msgDelegate.validatorAddress, + amount = Coin( + denom = msgDelegate.amount.denom, + amount = msgDelegate.amount.amount + ) + + ) + + return AminoMsg( + type = "cosmos-sdk/MsgDelegate", + value = Json.encodeToJsonElement(jsonAminoMsgDelegateValue) + ) + } + + fun generateTxBody( + delegateMsg: cosmos.staking.v1beta1.Tx.MsgDelegate, + timeoutHeight: Int + ): cosmos.tx.v1beta1.TxOuterClass.TxBody { + return cosmos.tx.v1beta1.txBody { + this.messages += com.google.protobuf.any { + this.typeUrl = "/cosmos.staking.v1beta1.MsgDelegate" + this.value = delegateMsg.toByteString() + } + this.timeoutHeight = timeoutHeight.toLong() + } + } + + fun getSignDigest(signDoc: StdSignDoc): ByteArray { + return SHA256.Digest() + .digest(Json.encodeToJsonElement(signDoc).removeNull().sort().toString().toByteArray()) + } + + fun generateSignDoc( + sendMsgs: List, + accNum: Int, + accSeq: Int, + timeoutHeight: Int = 0, + gasLimit: Int, + chainId: String + ): StdSignDoc { + return StdSignDoc( + accountNumber = accNum.toString(), + sequence = accSeq.toString(), + timeoutHeight = if (timeoutHeight <= 0) null else timeoutHeight.toString(), + chainId = chainId, + memo = "", + fee = StdFee( + amount = listOf(Coin(amount = "20", denom = "cony")), + gas = gasLimit.toString(), + ), + msgs = sendMsgs.map { convertMsgDelegatorToAminoMsg(it) }, + ) + } + } +} class MultisigMsgSend { companion object { fun addressFromMultiPubKey( @@ -62,14 +134,15 @@ class MultisigMsgSend { amount = it.amount.toString() ) } + val jsonAminoMsgSend = AminoMsgSendValue( + fromAddress = msgSend.fromAddress, + amount = coins, + toAddress = msgSend.toAddress, + ) return AminoMsg( type = "cosmos-sdk/MsgSend", - value = AminoMsgValue( - amount = coins, - fromAddress = msgSend.fromAddress, - toAddress = msgSend.toAddress, - ) + value = Json.encodeToJsonElement(jsonAminoMsgSend) ) } @@ -106,7 +179,7 @@ class MultisigMsgSend { chainId = chainId, memo = "", fee = StdFee( - amount = emptyList(), + amount = listOf(Coin(amount = "20", denom = "cony")), gas = gasLimit.toString(), ), msgs = sendMsgs.map { convertMsgSendToAminoMsg(it) }, @@ -166,14 +239,14 @@ suspend fun main() { // multi-sig address val multiSigAddress = pubkeyToAddress(multiSigPubKey, accountPrefix) val multiSigAccNum = 9 - val multiSigAccSeq = 0 + var multiSigAccSeq = 0 val timeoutHeight = 0 // receiver address val recipientAddress = Address(hdWallet.getKeyWallet(pubKeyNum + 1).pubKey).toBech32(accountPrefix) // remittance amount val fundAmount = 1 - val baseDenom = "stake" + val baseDenom = "cony" // scenario description println( @@ -237,4 +310,57 @@ suspend fun main() { //----------------------------------------- val result = client.broadcastTx(signedTx) println("result: $result") + multiSigAccSeq++ + val stakeDenom = "stake" + // scenario description + val validatorAddress = "linkvaloper1twsfmuj28ndph54k4nw8crwu8h9c8mh33lyrp8" //change for yourself + println( + "scenario: " + + "$multiSigAddress ($threshold of $pubKeyNum multi-sig address, acc num: $multiSigAccNum, acc seq: $multiSigAccSeq) delegate $fundAmount$stakeDenom to $validatorAddress on $chainId chain. " + + "Gas limit is set to $gasLimit and timeout height is ${if (timeoutHeight <= 0) "not set" else "set to $timeoutHeight"}." + ) + + // generate sendDelegate + val msgDelegate = MultisigMsgDelegate.createMsgDelegate( + multiSigAddress, + validatorAddress, + cosmos.base.v1beta1.coin { + this.amount = fundAmount.toString() + this.denom = stakeDenom + } + ) + + // generate unsigned tx body(amino type) + val txDelegateBody = MultisigMsgDelegate.generateTxBody(msgDelegate, timeoutHeight) + + // generate amino signDoc + val delegateUnsignedSignDoc = MultisigMsgDelegate.generateSignDoc( + listOf(msgDelegate), + multiSigAccNum, + multiSigAccSeq, + timeoutHeight, + gasLimit, + chainId + ) + + // generate sign digest + val signDigestDelegate = MultisigMsgDelegate.getSignDigest(delegateUnsignedSignDoc) + + val signerToSigsDelegate: Map = signers.map { + it.address.toBech32(accountPrefix) to ByteString.copyFrom(it.sign(signDigestDelegate).copyOfRange(0, 64)) + }.toMap() + + val signedDelegateTx = makeMultisignedTx( + multiSigPubKey, + multiSigAccSeq, + unsignedSignDoc.fee, + txDelegateBody.toByteString(), + signerToSigsDelegate + ) + + //----------------------------------------- + // step 6: broadcast the signed tx + //----------------------------------------- + val resultDelegate = client.broadcastTx(signedDelegateTx) + println("result: $resultDelegate") } diff --git a/tx/src/main/kotlin/network/finschia/sdk/legacymultisig/SignDoc.kt b/tx/src/main/kotlin/network/finschia/sdk/legacymultisig/SignDoc.kt index 642fc78..0e41802 100644 --- a/tx/src/main/kotlin/network/finschia/sdk/legacymultisig/SignDoc.kt +++ b/tx/src/main/kotlin/network/finschia/sdk/legacymultisig/SignDoc.kt @@ -12,16 +12,23 @@ import kotlinx.serialization.json.* @Serializable data class AminoMsg( @SerialName("type") val type: String, - @SerialName("value") val value: AminoMsgValue, + @SerialName("value") val value: JsonElement, ) @Serializable -data class AminoMsgValue( +data class AminoMsgSendValue( @SerialName("amount") val amount: List, @SerialName("from_address") val fromAddress: String, @SerialName("to_address") val toAddress: String, ) +@Serializable +data class AminoMsgDelegateValue( + @SerialName("amount") val amount: Coin, + @SerialName("delegator_address") val delegatorAddress: String, + @SerialName("validator_address") val validatorAddress: String, +) + @Serializable data class StdFee( @SerialName("amount") val amount: List, From ca8295838e6c7943e751a4d340377b0864341c10 Mon Sep 17 00:00:00 2001 From: Thai Tran Date: Mon, 10 Jul 2023 09:31:39 +0700 Subject: [PATCH 2/2] adding some comments, changelog --- CHANGELOG.md | 1 + .../kotlin/network/finschia/sdk/example/Client.kt | 12 +++++++++--- .../network/finschia/sdk/legacymultisig/SignDoc.kt | 3 +++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 247aec6..b3467d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Added ### Changed +build: [#19](https://github.com/Finschia/finschia-kt/pull/19) Change the value of AminoMsg to the general type ### Deprecated diff --git a/examples/multisig-example/src/main/kotlin/network/finschia/sdk/example/Client.kt b/examples/multisig-example/src/main/kotlin/network/finschia/sdk/example/Client.kt index 252f9eb..762692a 100644 --- a/examples/multisig-example/src/main/kotlin/network/finschia/sdk/example/Client.kt +++ b/examples/multisig-example/src/main/kotlin/network/finschia/sdk/example/Client.kt @@ -4,6 +4,8 @@ import network.finschia.sdk.legacymultisig.* import com.google.protobuf.ByteString import io.grpc.ManagedChannel import io.grpc.ManagedChannelBuilder +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import java.io.Closeable import java.util.concurrent.TimeUnit import kotlinx.serialization.json.* @@ -310,6 +312,12 @@ suspend fun main() { //----------------------------------------- val result = client.broadcastTx(signedTx) println("result: $result") + + + //----------------------------------------- + // `MsgDelegate` scenario example + //----------------------------------------- + multiSigAccSeq++ val stakeDenom = "stake" // scenario description @@ -358,9 +366,7 @@ suspend fun main() { signerToSigsDelegate ) - //----------------------------------------- - // step 6: broadcast the signed tx - //----------------------------------------- + // broadcast the signed tx val resultDelegate = client.broadcastTx(signedDelegateTx) println("result: $resultDelegate") } diff --git a/tx/src/main/kotlin/network/finschia/sdk/legacymultisig/SignDoc.kt b/tx/src/main/kotlin/network/finschia/sdk/legacymultisig/SignDoc.kt index 0e41802..fe04ca5 100644 --- a/tx/src/main/kotlin/network/finschia/sdk/legacymultisig/SignDoc.kt +++ b/tx/src/main/kotlin/network/finschia/sdk/legacymultisig/SignDoc.kt @@ -15,6 +15,9 @@ data class AminoMsg( @SerialName("value") val value: JsonElement, ) +/** + * You can create many amino messages for other Msg: MsgUndelegate, MsgCreateValidator, MsgEditValidator.... by yourself + */ @Serializable data class AminoMsgSendValue( @SerialName("amount") val amount: List,