# Multiple messages transaction with a few members

**URL:** <https://forum.cosmos.network/t/multiple-messages-transaction-with-a-few-members/5607>\
**Category:** Cosmos-SDK\
**Created:** [December 23, 2021, 7:46am UTC](https://forum.cosmos.network/t/multiple-messages-transaction-with-a-few-members/5607 "2021-12-23T07:46:44Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![fulldiver](https://yyz1.discourse-cdn.com/flex031/user_avatar/forum.cosmos.network/fulldiver/32/2244_2.png) [@fulldiver](https://forum.cosmos.network/u/fulldiver)\
**Post date:** [December 23, 2021, 7:46am UTC](https://forum.cosmos.network/t/multiple-messages-transaction-with-a-few-members/5607/1 "2021-12-23T07:46:44Z")

</div>

Hello, Cosmos community!

I have an interesting situation, I need to implement some mechanism over cosmos-sdk, and that sounds like:

1. Alice want to send something that she has to Bob and take some penny back from Bob
2. Alice could make a multiple messages transaction sign it and send it to Bob.
3. Bob would take that semi-signed partial request, inspect all the things inside the request. And if all is ok Bob could sign that request and send it to the blockchain

And that’s all, just three steps

There is a pseudo-code for step 2

```auto
{
    "body": {
        "messages": [
            {
                "@type": "send-something-message",
                "sender": "alice-address",
                "recipient": "bob-address"
            },
            {
                "@type": "send-penny-message",
                "sender": "bob-address",
                "recipient": "alice-address"
            }
        ]
    },
    "auth_info": {
        "signer_infos": [
            {
                "public_key": {
                    "@type": "/cosmos.crypto.secp256k1.PubKey",
                    "key": "alice-public-key"
                },
                "mode_info": {
                    "single": {
                        "mode": "SIGN_MODE_DIRECT"
                    }
                },
                "sequence": "1"
            }
        ],
        "fee": {
            "amount": [],
            "gas_limit": "200000",
            "payer": "",
            "granter": ""
        }
    },
    "signatures": [
        "alice-signature-with-sign-doc"
    ]
}

```

Look a the `signer_infos` and `signatures here`

And there is a 3 step json

```auto
{
    ...

    "auth_info": {
        "signer_infos": [
            {
                "public_key": {
                    "@type": "/cosmos.crypto.secp256k1.PubKey",
                    "key": "alice-public-key"
                },
                "mode_info": {
                    "single": {
                        "mode": "SIGN_MODE_DIRECT"
                    }
                },
                "sequence": "1"
            },
            {
                "public_key": {
                    "@type": "/cosmos.crypto.secp256k1.PubKey",
                    "key": "bob-public-key"
                },
                "mode_info": {
                    "single": {
                        "mode": "SIGN_MODE_DIRECT"
                    }
                },
                "sequence": "1"
            }
        ],
        ...
    },
    "signatures": [
        "alice-signature-with-sign-doc",
        "bob-signature-with-sign-doc"
    ]
}

```

Bob just add his signs and finish a complete transaction

And my question is: is it real to make something like this over cosmos-sdk with grpc broadcasts from clients?

Who will be charged with fees? Could it be Alice or Bob? Or it’s always someone who sends the transaction to the blockchain?

---

<div class="post-metadata">

**Author:** ![uditvira](https://yyz1.discourse-cdn.com/flex031/user_avatar/forum.cosmos.network/uditvira/32/1907_2.png) [@uditvira](https://forum.cosmos.network/u/uditvira)\
**Post date:** [December 23, 2021, 6:06pm UTC](https://forum.cosmos.network/t/multiple-messages-transaction-with-a-few-members/5607/2 "2021-12-23T18:06:30Z")

</div>

I think you should ask in the [Cosmos Developers](https://discord.gg/cosmosnetwork) discord

---

<div class="post-metadata">

**Author:** ![fulldiver](https://yyz1.discourse-cdn.com/flex031/user_avatar/forum.cosmos.network/fulldiver/32/2244_2.png) [@fulldiver](https://forum.cosmos.network/u/fulldiver)\
**Post date:** [December 24, 2021, 6:00am UTC](https://forum.cosmos.network/t/multiple-messages-transaction-with-a-few-members/5607/3 "2021-12-24T06:00:03Z")

</div>

don’t think so, but I will wait for the answer here and in the discord, thank you 🙂

---

<div class="post-metadata">

**Author:** ![fulldiver](https://yyz1.discourse-cdn.com/flex031/user_avatar/forum.cosmos.network/fulldiver/32/2244_2.png) [@fulldiver](https://forum.cosmos.network/u/fulldiver)\
**Post date:** [December 28, 2021, 1:19pm UTC](https://forum.cosmos.network/t/multiple-messages-transaction-with-a-few-members/5607/4 "2021-12-28T13:19:01Z")

</div>

> <https://github.com/cosmos/cosmos-sdk/issues/10843>
>
> \<!-- \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< \< ☺ 
> v … ✰ Thanks for opening an issue! ✰    
> v Before smashing the submit button please review the template.
> v Please also ensure that this is not a duplicate issue :)  
> ☺ \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> \> --\>
> 
> \<!--
> IMPORTANT: Prior to opening a bug report, check if it affects one of the core modules
> and if its elegible for a bug bounty on \`SECURITY.md\`. Bugs that are not submitted
> through the appropriate channels won't receive any bounty.
> --\>
> 
> \## Summary of Bug
> 
> I want to implement 2 signers 2 messages transaction from a client via gRPC, but I always receive the same error:
> \`\`\`
> signature verification failed; please verify account number (x) and chain-id (y): unauthorized
> \`\`\`
> \`x\` — is an account number of transaction composer and he is the first signer
> \`y\` — is a correct chain-id of my node
> 
> \## Version
> 
> 
> cosmos-sdk v0.44.2
> 
> \## Steps to Reproduce
> 
> \### The flow is pretty simple:
> \*\*Alice\*\* is a first signer and transaction composer
> \*\*Bob\*\* is a second signer, fee payer and user who broadcast complete transaction
> 
> \*\*Alice\*\* prepare the transaction, that looks like 
> \`\`\`json
> {
> "body": {
> "messages": \[
> {
> "@type": "send-something-message",
> "sender": "alice-address",
> "recipient": "bob-address"
> },
> {
> "@type": "send-penny-message",
> "sender": "bob-address",
> "recipient": "alice-address"
> }
> \]
> },
> "auth\_info": {
> "signer\_infos": \[
> {
> "public\_key": {
> "@type": "/cosmos.crypto.secp256k1.PubKey",
> "key": "alice-public-key"
> },
> "mode\_info": {
> "single": {
> "mode": "SIGN\_MODE\_DIRECT\_AUX"
> }
> },
> "sequence": "1"
> }
> \],
> "fee": {
> "amount": \[some-coins\],
> "gas\_limit": "200000",
> "payer": "bob-address",
> "granter": ""
> }
> },
> "signatures": \[
> "alice-signature-with-sign-doc-aux"
> \]
> }
> \`\`\`
> \*\*Alice\*\* encode that json into an array of bytes as a partial tx request and send it to \*\*Bob\*\* with 3party transport
> 
> \*\*Bob\*\* receive that bytes array and decode it into Protobuff messages, he read all the things inside that transaction and add his own signature (DIRECT)
> \`\`\`json
> {
> ...
> 
> "auth\_info": {
> "signer\_infos": \[
> {
> "public\_key": {
> "@type": "/cosmos.crypto.secp256k1.PubKey",
> "key": "alice-public-key"
> },
> "mode\_info": {
> "single": {
> "mode": "SIGN\_MODE\_DIRECT\_AUX"
> }
> },
> "sequence": "1"
> },
> {
> "public\_key": {
> "@type": "/cosmos.crypto.secp256k1.PubKey",
> "key": "bob-public-key"
> },
> "mode\_info": {
> "single": {
> "mode": "SIGN\_MODE\_DIRECT"
> }
> },
> "sequence": "3"
> }
> \],
> ...
> },
> "signatures": \[
> "alice-signature-with-sign-doc-aux",
> "bob-signature-with-sign-doc"
> \]
> }
> \`\`\`
> and after that \*\*Bob\*\* broadcast that complete tx request and receive an error described earlier.
> 
> There is 2 raw code snippets with Swift language
> 1) Generating transaction semi-signed by \*\*Alice\*\*
> \`\`\`swift
> static func prepareSemiSignedTransaction(
> messages: \[(route: String, data: Data)\],
> fees: (fee: Fee, payer: String),
> keys: Wallet.Mnemonic.RawKeys, // (\`private\`: Data, \`public\`: Data) generated by HDWalletKit swift library
> environment: Environment // all the fields here obtained right before calling that method by querying node and account info
> ) -\> Data {
> let body = Cosmos\_Tx\_V1beta1\_TxBody.with({
> $0.messages = messages.map({ m in
> Google\_Protobuf\_Any.with({
> $0.typeURL = m.route
> $0.value = m.data
> })
> })
> })
>     
> let authInfo = Cosmos\_Tx\_V1beta1\_AuthInfo.with({
> $0.fee = Cosmos\_Tx\_V1beta1\_Fee.with({
> $0.payer = fees.payer
> $0.gasLimit = fees.fee.gasLimit
> $0.amount = \[
> Cosmos\_Base\_V1beta1\_Coin.with({
> $0.amount = String(fees.fee.coins.amount)
> $0.denom = fees.fee.coins.denom.rawValue
> })
> \]
> })
> $0.signerInfos = \[
> Cosmos\_Tx\_V1beta1\_SignerInfo.with({
> $0.publicKey = Google\_Protobuf\_Any.with({
> $0.typeURL = "/cosmos.crypto.secp256k1.PubKey"
> $0.value = try! Cosmos\_Crypto\_Secp256k1\_PubKey.with({
> $0.key = keys.public
> }).serializedData()
> })
> $0.sequence = environment.account.sequence
> $0.modeInfo = Cosmos\_Tx\_V1beta1\_ModeInfo.with({
> $0.single = Cosmos\_Tx\_V1beta1\_ModeInfo.Single.with({
> $0.mode = .directAux
> })
> })
> })
> \]
> })
>     
> let signDoc = Cosmos\_Tx\_V1beta1\_SignDocDirectAux.with({
> $0.chainID = environment.node.network
> $0.accountNumber = environment.account.number
> $0.sequence = environment.account.sequence
> $0.publicKey = Google\_Protobuf\_Any.with({
> $0.typeURL = "/cosmos.crypto.secp256k1.PubKey"
> $0.value = try! Cosmos\_Crypto\_Secp256k1\_PubKey.with({
> $0.key = keys.public
> }).serializedData()
> })
> $0.bodyBytes = try! body.serializedData()
> })
>     
> let hash = try! signDoc.serializedData().sha256()
> let signature = try! ECDSA.compactsign(hash, privateKey: keys.private)
>     
> let rawTx = Cosmos\_Tx\_V1beta1\_TxRaw.with({
> $0.bodyBytes = try! body.serializedData()
> $0.authInfoBytes = try! authInfo.serializedData()
> $0.signatures = \[signature\]
> })
>     
> return try! rawTx.serializedData(partial: true)
> }
> \`\`\`
> 
> \> (\`private\`: Data, \`public\`: Data) generated by HDWalletKit swift library
> 
> That keys works fine when I use them with single message (single signer) transactions
> 
> 
> 2) \*\*Bob\*\*'s signing part after receiving a partially serialized transaction from \*\*Alice\*\*
> \`\`\`swift
> static func complete(
> semiSigned partialTransaction: Data,
> keys: Wallet.Mnemonic.RawKeys,
> environment: Environment
> ) -\> Cosmos\_Tx\_V1beta1\_BroadcastTxRequest {
> var partialRawTx = try! Cosmos\_Tx\_V1beta1\_TxRaw(serializedData: partialTransaction, partial: true)
> let body = try! Cosmos\_Tx\_V1beta1\_TxBody(serializedData: partialRawTx.bodyBytes)
> var authInfo = try! Cosmos\_Tx\_V1beta1\_AuthInfo(serializedData: partialRawTx.authInfoBytes)
>     
> authInfo.signerInfos.append({
> Cosmos\_Tx\_V1beta1\_SignerInfo.with({
> $0.publicKey = Google\_Protobuf\_Any.with({
> $0.typeURL = "/cosmos.crypto.secp256k1.PubKey"
> $0.value = try! Cosmos\_Crypto\_Secp256k1\_PubKey.with({
> $0.key = keys.public
> }).serializedData()
> })
> $0.sequence = environment.account.sequence
> $0.modeInfo = Cosmos\_Tx\_V1beta1\_ModeInfo.with({
> $0.single = Cosmos\_Tx\_V1beta1\_ModeInfo.Single.with({
> $0.mode = .direct
> })
> })
> })
> }())
>     
> let signDoc = Cosmos\_Tx\_V1beta1\_SignDoc.with({
> $0.accountNumber = environment.account.number
> $0.chainID = environment.node.network
> $0.bodyBytes = try! body.serializedData()
> $0.authInfoBytes = try! authInfo.serializedData()
> })
>     
> let hash = try! signDoc.serializedData().sha256()
> let signature = try! ECDSA.compactsign(hash, privateKey: keys.private)
> partialRawTx.signatures.append(signature)
>     
> let completeRawTx = Cosmos\_Tx\_V1beta1\_TxRaw.with({
> $0.bodyBytes = try! body.serializedData()
> $0.authInfoBytes = try! authInfo.serializedData()
> $0.signatures = partialRawTx.signatures
> })
>     
> return Cosmos\_Tx\_V1beta1\_BroadcastTxRequest.with({
> $0.mode = .sync
> $0.txBytes = try! completeRawTx.serializedData()
> })
> }
> \`\`\`
> 
> I tried to use \`.legacyAminoJson\` with custom \`StdSignDoc\` with sorted keys when encoding that struct to json at \*\*Alice\*\* step
> \`\`\`swift
> struct StdSignDoc: Encodable {
> struct Coin: Encodable {
> let denom: String
> let amount: UInt64
>         
> enum CodingKeys: String, CodingKey {
> case denom = "denom"
> case amount = "amount"
> }
> }
>     
> struct Fee: Encodable {
> let amount: \[Coin\]
> let gas: UInt64
> let payer: String
>         
> enum CodingKeys: String, CodingKey {
> case amount = "amount"
> case gas = "gas"
> case payer = "payer"
> }
> }
>     
> struct AminoMsg: Encodable {
> let type: String
> let value: String // json-encoded tx-message
>         
> enum CodingKeys: String, CodingKey {
> case type = "type"
> case value = "value"
> }
> }
>     
> let accountNumber: UInt64
> let sequence: UInt64
> let chainId: String
> let memo: String = ""
> let fee: Fee
> let messages: \[AminoMsg\]
>     
> enum CodingKeys: String, CodingKey {
> case accountNumber = "account\_number"
> case sequence = "sequence"
> case chainId = "chain\_id"
> case memo = "memo"
> case fee = "fee"
> case messages = "msgs"
> }
> }
> \`\`\`
> 
> \`\`\`swift
> ...
> let signDoc = StdSignDoc(
> accountNumber: environment.account.number,
> sequence: environment.account.sequence,
> chainId: environment.node.network,
> fee: .init(
> amount: \[
> .init(denom: fees.fee.coins.denom.rawValue, amount: fees.fee.coins.amount)
> \],
> gas: fees.fee.gasLimit,
> payer: fees.payer
> ),
> messages: messages.compactMap({
> guard let data = $0.message.jsonData, let jsonString = String(data: data, encoding: .utf8) else {
> return nil
> }
> return .init(type: $0.route, value: jsonString)
> })
> )
> 
> 
> let signDocEncoder: JSONEncoder = {
> let e = JSONEncoder()
> e.outputFormatting = .sortedKeys
> return e
> }()
> 
> let hash = try! signDocEncoder.encode(signDoc).sha256()
> let signature = try! ECDSA.compactsign(hash, privateKey: keys.private)
> ...
> \`\`\`
> 
> but I always get the same error :\]
> 
> Does anyone know it is valid usage of gRPC cosmos API? And what I'm doing wrong?
> 
> \_\_\_\_
> 
> \## For Admin Use
> 
> \- \[\] Not duplicate issue
> \- \[\] Appropriate labels applied
> \- \[\] Appropriate contributors tagged
> \- \[\] Contributor assigned/self-assigned

just for anyone who will faced with the same issue as me, in short, it’s my fault :]
