cosmos-multisig-ui/lib/multisigHelpers.ts
2023-04-18 15:11:58 +02:00

95 lines
3.3 KiB
TypeScript

import {
createMultisigThresholdPubkey,
isMultisigThresholdPubkey,
MultisigThresholdPubkey,
pubkeyToAddress,
} from "@cosmjs/amino";
import { Account, StargateClient } from "@cosmjs/stargate";
import { assert } from "@cosmjs/utils";
import axios from "axios";
import { checkAddress } from "./displayHelpers";
/**
* Turns array of compressed Secp256k1 pubkeys
* into a multisig using comsjs
*
* @param {array} compressedPubkeys Must be an array of compressed Secp256k1 pubkeys (e.g 'A8B5KVhRz1oQuV1dguzFdGBhHrIU/I+R/QfBZcbZFWVG').
* @param {number} threshold the number of signers required to sign messages from this multisig
* @param {string} addressPrefix chain based prefix for the address (e.g. 'cosmos')
* @param {string} chainId chain-id for the multisig (e.g. 'cosmoshub-4')
* @return {string} The multisig address.
*/
const createMultisigFromCompressedSecp256k1Pubkeys = async (
compressedPubkeys: string[],
threshold: number,
addressPrefix: string,
chainId: string,
): Promise<string> => {
const pubkeys = compressedPubkeys.map((compressedPubkey) => {
return {
type: "tendermint/PubKeySecp256k1",
value: compressedPubkey,
};
});
const multisigPubkey = createMultisigThresholdPubkey(pubkeys, threshold);
const multisigAddress = pubkeyToAddress(multisigPubkey, addressPrefix);
// save multisig to fauna
const multisig = {
address: multisigAddress,
pubkeyJSON: JSON.stringify(multisigPubkey),
chainId,
};
const res = await axios.post(`/api/chain/${chainId}/multisig`, multisig);
console.log(res.data);
return res.data.address;
};
/**
* This gets a multisigs account (pubkey, sequence, account number, etc) from
* a node and/or the api if the multisig was made on this app.
*
* The public key should always be available, either on chain or in the app's database.
* The account is only available when the there was any on-chain activity such as
* receipt of tokens.
*/
const getMultisigAccount = async (
address: string,
addressPrefix: string,
client: StargateClient,
): Promise<[MultisigThresholdPubkey, Account | null]> => {
// we need the multisig pubkeys to create transactions, if the multisig
// is new, and has never submitted a transaction its pubkeys will not be
// available from a node. If the multisig was created with this instance
// of this tool its pubkey will be available in the fauna datastore
const addressError = checkAddress(address, addressPrefix);
if (addressError) {
throw new Error(addressError);
}
const accountOnChain = await client.getAccount(address);
const chainId = await client.getChainId();
let pubkey: MultisigThresholdPubkey;
if (accountOnChain?.pubkey) {
assert(
isMultisigThresholdPubkey(accountOnChain.pubkey),
"Pubkey on chain is not of type MultisigThreshold",
);
pubkey = accountOnChain.pubkey;
} else {
console.log("No pubkey on chain for: ", address);
const res = await axios.get(`/api/chain/${chainId}/multisig/${address}`);
if (res.status !== 200) {
throw new Error("Multisig has no pubkey on node, and was not created using this tool.");
}
pubkey = JSON.parse(res.data.pubkeyJSON);
}
return [pubkey, accountOnChain];
};
export { createMultisigFromCompressedSecp256k1Pubkeys, getMultisigAccount };