我在同时向多个地址发送令牌时遇到麻烦。据我所知,Cosmos不支持批量发送,所以我必须为每个接收方进行一次发送,并确保每个发送的帐户序列(nonce)是正确的。
因此,如果我手动指定帐户序列,我可以一次创建许多发送交易-但我仍然必须等待节点确认一个tx并在发送下一个之前更新帐户序列。
在这种情况下我们能做什么?
Cosmos实际上支持银行模块上的MultiSend操作,不幸的是,它通常没有连接到客户端以获得支持,但它被Coinbase等交易所广泛用于优化转账。
https://github.com/cosmos/cosmos-sdk/blob/e957fad1a7ffd73712cd681116c9b6e09fa3e60b/x/bank/keeper/msg_server.go L73
有人提醒我,单个Cosmos事务可以由多个Message组成,其中每个Message是向银行模块发送令牌到一个帐户的消息。这就是批量发送在Cosmos中的工作原理。
不幸的是,这不能通过命令行获得,因此必须使用SDK来进行这样的事务。
下面是CosmJS演示在v0.39上发送带有两条消息和两个签名的事务的链接。x LTS版本的Cosmos SDK在这里发布(感谢Confio的Ethan Frey指出这一点)
如果链接在任何地方发生变化,代码如下:
describe("appendSignature", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const wallet0 = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(0));
const wallet1 = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(1));
const client0 = new SigningCosmosClient(launchpad.endpoint, faucet.address0, wallet0);
const client1 = new SigningCosmosClient(launchpad.endpoint, faucet.address1, wallet1);
const msg1: MsgSend = {
type: "cosmos-sdk/MsgSend",
value: {
from_address: faucet.address0,
to_address: makeRandomAddress(),
amount: coins(1234567, "ucosm"),
},
};
const msg2: MsgSend = {
type: "cosmos-sdk/MsgSend",
value: {
from_address: faucet.address1,
to_address: makeRandomAddress(),
amount: coins(1234567, "ucosm"),
},
};
const fee = {
amount: coins(2000, "ucosm"),
gas: "160000", // 2*80k
};
const memo = "This must be authorized by the two of us";
const signed = await client0.sign([msg1, msg2], fee, memo);
const cosigned = await client1.appendSignature(signed);
expect(cosigned.msg).toEqual([msg1, msg2]);
expect(cosigned.fee).toEqual(fee);
expect(cosigned.memo).toEqual(memo);
expect(cosigned.signatures).toEqual([
{
pub_key: faucet.pubkey0,
signature: jasmine.stringMatching(base64Matcher),
},
{
pub_key: faucet.pubkey1,
signature: jasmine.stringMatching(base64Matcher),
},
]);
// Ensure signed transaction is valid
const broadcastResult = await client0.broadcastTx(cosigned);
assertIsBroadcastTxSuccess(broadcastResult);
});
});
要在Golang中做这种事情,就像使用Cosmos SDK客户端CLI一样,您可以以distribution
模块为例:https://github.com/cosmos/cosmos-sdk/blob/master/x/distribution/client/cli/tx.go#L165-L180
msgs := make([]sdk.Msg, 0, len(validators))
for _, valAddr := range validators {
val, err := sdk.ValAddressFromBech32(valAddr)
if err != nil {
return err
}
msg := types.NewMsgWithdrawDelegatorReward(delAddr, val)
if err := msg.ValidateBasic(); err != nil {
return err
}
msgs = append(msgs, msg)
}
chunkSize, _ := cmd.Flags().GetInt(FlagMaxMessagesPerTx)
return newSplitAndApply(tx.GenerateOrBroadcastTxCLI, clientCtx, cmd.Flags(), msgs, chunkSize)