Pull out makeMultisignedTx

This commit is contained in:
Simon Warta 2021-03-24 01:06:36 +01:00
parent dc052d8229
commit 447b82b66f

View File

@ -1,4 +1,10 @@
import { createMultisigThresholdPubkey, encodeSecp256k1Pubkey, pubkeyToAddress } from "@cosmjs/amino";
import {
createMultisigThresholdPubkey,
encodeSecp256k1Pubkey,
MultisigThresholdPubkey,
pubkeyToAddress,
} from "@cosmjs/amino";
import { Bech32 } from "@cosmjs/encoding";
import { coins, makeCosmoshubPath, Secp256k1HdWallet } from "@cosmjs/launchpad";
import { encodePubkey } from "@cosmjs/proto-signing";
import { MultiSignature } from "@cosmjs/proto-signing/build/codec/cosmos/crypto/multisig/v1beta1/multisig";
@ -9,9 +15,63 @@ import { MsgSend } from "./codec/cosmos/bank/v1beta1/tx";
import { CompactBitArray } from "./codec/cosmos/crypto/multisig/v1beta1/multisig";
import { SignMode } from "./codec/cosmos/tx/signing/v1beta1/signing";
import { AuthInfo, SignerInfo, TxRaw } from "./codec/cosmos/tx/v1beta1/tx";
import { StdFee } from "./fee";
import { SigningStargateClient } from "./signingstargateclient";
import { assertIsBroadcastTxSuccess } from "./stargateclient";
import { faucet, makeRandomAddress, simapp } from "./testutils.spec";
import { faucet, simapp } from "./testutils.spec";
function makeMultisignedTx(
multisigPubkey: MultisigThresholdPubkey,
sequence: number,
fee: StdFee,
bodyBytes: Uint8Array,
signatures: Map<string, Uint8Array>,
): TxRaw {
const addresses = Array.from(signatures.keys());
const prefix = Bech32.decode(addresses[0]).prefix;
let bits = 0;
const signaturesList = new Array<Uint8Array>();
for (let i = 0; i < multisigPubkey.value.pubkeys.length; i++) {
const signerAddress = pubkeyToAddress(multisigPubkey.value.pubkeys[i], prefix);
const signature = signatures.get(signerAddress);
if (signature) {
// eslint-disable-next-line no-bitwise
bits |= 0b1 << (8 - 1 - i);
signaturesList.push(signature);
}
}
const signerInfo: SignerInfo = {
publicKey: encodePubkey(multisigPubkey),
modeInfo: {
multi: {
bitarray: CompactBitArray.fromPartial({
elems: new Uint8Array([bits]),
extraBitsStored: multisigPubkey.value.pubkeys.length,
}),
modeInfos: signaturesList.map((_) => ({ single: { mode: SignMode.SIGN_MODE_LEGACY_AMINO_JSON } })),
},
},
sequence: Long.fromNumber(sequence),
};
const authInfo = AuthInfo.fromPartial({
signerInfos: [signerInfo],
fee: {
amount: [...fee.amount],
gasLimit: Long.fromString(fee.gas),
},
});
const authInfoBytes = AuthInfo.encode(authInfo).finish();
const signedTx = TxRaw.fromPartial({
bodyBytes: bodyBytes,
authInfoBytes: authInfoBytes,
signatures: [MultiSignature.encode(MultiSignature.fromPartial({ signatures: signaturesList })).finish()],
});
return signedTx;
}
describe("SigningStargateClient multisig", () => {
it("works", async () => {
@ -25,6 +85,11 @@ describe("SigningStargateClient multisig", () => {
const pubkey2 = encodeSecp256k1Pubkey((await wallet2.getAccounts())[0].pubkey);
const pubkey3 = encodeSecp256k1Pubkey((await wallet3.getAccounts())[0].pubkey);
const pubkey4 = encodeSecp256k1Pubkey((await wallet4.getAccounts())[0].pubkey);
const address0 = (await wallet0.getAccounts())[0].address;
const address1 = (await wallet1.getAccounts())[0].address;
const address2 = (await wallet2.getAccounts())[0].address;
const address3 = (await wallet3.getAccounts())[0].address;
const address4 = (await wallet4.getAccounts())[0].address;
const multisigPubkey = createMultisigThresholdPubkey([pubkey0, pubkey1, pubkey2, pubkey3, pubkey4], 2);
const multisigAddress = pubkeyToAddress(multisigPubkey, "cosmos");
expect(multisigAddress).toEqual("cosmos1h90ml36rcu7yegwduzgzderj2jmq49hcpfclw9");
@ -37,7 +102,7 @@ describe("SigningStargateClient multisig", () => {
const msgSend: MsgSend = {
fromAddress: multisigAddress,
toAddress: makeRandomAddress(),
toAddress: "cosmos19rvl6ja9h0erq9dc2xxfdzypc739ej8k5esnhg",
amount: coins(1234, "ucosm"),
};
const msg = {
@ -64,54 +129,29 @@ describe("SigningStargateClient multisig", () => {
signatures: [signature0],
} = await client0.signAmino(faucet.address0, [msg], fee, memo, signData);
const {
signatures: [_signature1],
signatures: [signature1],
} = await client1.signAmino(faucet.address1, [msg], fee, memo, signData);
const {
signatures: [_signature2],
signatures: [signature2],
} = await client2.signAmino(faucet.address2, [msg], fee, memo, signData);
const {
signatures: [_signature3],
signatures: [signature3],
} = await client3.signAmino(faucet.address3, [msg], fee, memo, signData);
const {
signatures: [signature4],
} = await client4.signAmino(faucet.address4, [msg], fee, memo, signData);
const multisignature = MultiSignature.fromPartial({ signatures: [signature0, signature4] });
const signerInfo: SignerInfo = {
publicKey: encodePubkey(multisigPubkey),
modeInfo: {
multi: {
bitarray: CompactBitArray.fromPartial({
elems: new Uint8Array([0b10001000]),
extraBitsStored: 5,
}),
modeInfos: [
{ single: { mode: SignMode.SIGN_MODE_LEGACY_AMINO_JSON } },
{ single: { mode: SignMode.SIGN_MODE_LEGACY_AMINO_JSON } },
],
},
},
sequence: Long.fromNumber(multisigAccount.sequence),
};
const authInfo = {
signerInfos: [signerInfo],
fee: {
amount: [...fee.amount],
gasLimit: Long.fromNumber(gasLimit),
},
};
const authInfoBytes = AuthInfo.encode(AuthInfo.fromPartial(authInfo)).finish();
const signedTx = TxRaw.fromPartial({
bodyBytes: bodyBytes,
authInfoBytes: authInfoBytes,
signatures: [MultiSignature.encode(multisignature).finish()],
});
const signatures = new Map<string, Uint8Array>([
[address0, signature0],
[address1, signature1],
[address2, signature2],
[address3, signature3],
[address4, signature4],
]);
const signedTx = makeMultisignedTx(multisigPubkey, multisigAccount.sequence, fee, bodyBytes, signatures);
// ensure signature is valid
const result = await client0.broadcastTx(Uint8Array.from(TxRaw.encode(signedTx).finish()));
assertIsBroadcastTxSuccess(result);
const result04 = await client0.broadcastTx(Uint8Array.from(TxRaw.encode(signedTx).finish()));
assertIsBroadcastTxSuccess(result04);
});
});