-
Notifications
You must be signed in to change notification settings - Fork 344
What can CosmJS do for me?
- Create various unsigned Cosmos Hub transactions?
- Sign an unsigned transaction when I have a mnemonic phrase? (12 word? 24 word?)
- Sign an unsigned transaction when I have a private key?
- Submit a signed transaction to a Cosmos Hub endpoint?
- Create a multi-sig signature on an unsigned transaction?
- Query state from a Cosmos Hub module using the legacy REST endpoint?
- Query state from a Cosmos Hub module using the gRPC endpoint?
- Query state from a custom module using the legacy REST endpoint?
- Query state from a custom module using the gRPC endpoint?
- Make it easier to submit multiple messages in a single transaction?
If you have a list of complete transactions like this
{
"txs": [
"9AEoKBapCjCMTXENChQmiMbn/hEgc2noEV+vJkHASIhPShIUU7SyT3IQK/OJv+xZUz5LP9dR4FQKPpIdLk4KFCaIxuf+ESBzaegRX68mQcBIiE9KEhRTtLJPchAr84m/7FlTPks/11HgVBoMCgV1YXRvbRIDMTQ1EhAKCgoFdWF0b20SATAQ4KcSGmoKJuta6YchA9E/2C2Tibu+oguuOS2AwO9sGwy1ejes+u8hBdGJ2guiEkBZ7JjaZhENW56nbqaUH0SdgnuWHmPlPfgWs2LVwbOj6BDacUL+vcKqd4vxmkYRB9ORmqnDlj9ppaupmIPnOQuK",
"ywEoKBapCkWoo2GaChQxrczb/flZmTC8mDh3uKwKyZCnpRIUWYCZ0lvC4PM8HrDaaR1oSU65PLoaEwoFdWF0b20SCjM4MDQwMDAwMDASEgoMCgV1YXRvbRIDNzUwEMCaDBpqCibrWumHIQMgfOISgYzdsLJnQtnhdT6c+pd1cZX0iiaWLE2i+Fa6xBJAIvmDdjJstWPWqshZxCtMXWXL1CBw06a9oYH8f2l7f19I5RsDDYJz1QTnKwor765rLsdAcF+5ucCBnkUnvy7I+g==",
"twEoKBapCjCMTXENChQkQV2iWcShdar5UshUoWev/JUSfxIUyTRRx8hJmGRpUL1G+yw8xXQRSHsSEwoNCgV1YXRvbRIEMjUwMBDAzyQaagom61rphyEC1bbqM5eBuRSZ/jeQH1o25g7ybaQw3BlY4zQWmJb+k2QSQOSikSCd7AkDDjeCoNwdhdwgEOPiIZIHzF8TCSQSVdA/Iru/g9xE5eZTA4Cg2Q48idWyIHadYME5cKhVm3S8lHw=",
"4gIoKBapCkOSHS5OChQ9NPQdHwRlRIc1MUP7Vy+gGRKtixIUYmtWnpmEfXd8qa3Khj8v1Xb//7oaEQoFdWF0b20SCDEwMDAwMDAwCkOSHS5OChQ9NPQdHwRlRIc1MUP7Vy+gGRKtixIUppAElPH3PNriuvHIuI/1/AuKM5waEQoFdWF0b20SCDEwMDAwMDAwCkOSHS5OChQ9NPQdHwRlRIc1MUP7Vy+gGRKtixIUyTRRx8hJmGRpUL1G+yw8xXQRSHsaEQoFdWF0b20SCDEwMDAwMDAwEhQKDgoFdWF0b20SBTIxODc5EJS1NRpqCibrWumHIQIT+U7tHv1kX5BoKGClAbKOf4nTI32tfFVX+AnedBYFnhJA/AedifYkknYTGcztoNn3VH7gMpeJXGsUxydWUMJ6wC8IT8uV5UWeHdmW0HbVsjRSxyKPDO+NLJbO35zwb1cT5CILTGVkZ2VyIExpdmU="
]
}
(from Cosmos Hub height 2421996), you can calculate a transaction ID like this:
import { sha256 } from "@cosmjs/crypto";
import { fromBase64, toHex } from "@cosmjs/encoding";
const tx = "9AEoKBapCjCMTXENChQmiMbn/hEgc2noEV+vJkHASIhPShIUU7SyT3IQK/OJv+xZUz5LP9dR4FQKPpIdLk4KFCaIxuf+ESBzaegRX68mQcBIiE9KEhRTtLJPchAr84m/7FlTPks/11HgVBoMCgV1YXRvbRIDMTQ1EhAKCgoFdWF0b20SATAQ4KcSGmoKJuta6YchA9E/2C2Tibu+oguuOS2AwO9sGwy1ejes+u8hBdGJ2guiEkBZ7JjaZhENW56nbqaUH0SdgnuWHmPlPfgWs2LVwbOj6BDacUL+vcKqd4vxmkYRB9ORmqnDlj9ppaupmIPnOQuK";
const transactionHash = sha256(fromBase64(tx));
const transactionId = toHex(transactionHash).toUpperCase();
console.log(transactionId); // 697D4B1394AEFB95676E775236600D2A60FC87593114316DA4238EE0DEC1EC88
Given a secp256k1 public key, this gives you a Cosmos Hub address:
import { pubkeyToAddress } from "@cosmjs/amino";
const pubkey = {
type: "tendermint/PubKeySecp256k1",
value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP",
};
const address = pubkeyToAddress(pubkey, "cosmos");
console.log(address); // cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r
Given a consensus pubkey like coralvalconspub1zcjduepqafdn8uprnsr35ptz653409ar3ft6uuu065f33f42fee67s67k3lqud5zqu
, this derives an address in the Tendermint format. This is used e.g. in "proposer_address": "A8C66A16AC1FF07B390504D0DB211128440754F1"
from /blockchain
of Tendermint RPC.
import { sha256 } from "@cosmjs/crypto";
import { fromBase64, toHex } from "@cosmjs/encoding";
import { decodeBech32Pubkey } from "@cosmjs/launchpad";
const pubkey = decodeBech32Pubkey(
"coralvalconspub1zcjduepqafdn8uprnsr35ptz653409ar3ft6uuu065f33f42fee67s67k3lqud5zqu",
);
const addressData = sha256(fromBase64(pubkey.value)).slice(0, 20);
const address = toHex(addressData).toUpperCase();
console.log(address); // 0C0A3D4E86CD4B104BF2972851647161074D1BB8
The *valconspub1*
identifiers are bech32 encoded Amino pubkeys. Usually Ed25519 is used for consensus (=Tendermint) keypairs. But this can change.
*valcons1*
are bech32 encoded Tendermint addresses, which are derived differently than Cosmos SDK addresses.
import { sha256 } from "@cosmjs/crypto";
import { Bech32, fromBase64 } from "@cosmjs/encoding";
import { encodeBech32Pubkey } from "@cosmjs/launchpad";
// Ed25519 pubkey from genesis
const pubkey = {
type: "tendermint/PubKeyEd25519",
value: "iARPJIXVwen//D6qB5CoQT1KrTK7ffGOkIstFF3KIgk=",
};
const bech32Pubkey = encodeBech32Pubkey(pubkey, "regen:valconspub");
console.log(bech32Pubkey); // regen:valconspub1zcjduepq3qzy7fy96hq7nllu864q0y9ggy754tfjhd7lrr5s3vk3ghw2ygyspmhej4
const ed25519PubkeyRaw = fromBase64(pubkey.value);
const addressData = sha256(ed25519PubkeyRaw).slice(0, 20);
const bech32Address = Bech32.encode("regen:valcons", addressData);
console.log(bech32Address); // regen:valcons14y3uv3g3fp5k473qtdenmn5cv89y2s5nz7cshu
import { fromHex, toHex } from "@cosmjs/encoding";
import { keccak256, Secp256k1 } from "@cosmjs/crypto";
const privkey = fromHex("1da6847600b0ee25e9ad9a52abbd786dd2502fa4005dd5af9310b7cc7a3b25db");
const keypair = await Secp256k1.makeKeypair(privkey);
toHex(keypair.pubkey) // 04b9e72dfd423bcf95b3801ac93f4392be5ff22143f9980eb78b3a860c4843bfd04829ae61cdba4b3b1978ac5fc64f5cc2f4350e35a108a9c9a92a81200a60cd64
const compressed = Secp256k1.compressPubkey(keypair.pubkey);
toHex(compressed) // 02b9e72dfd423bcf95b3801ac93f4392be5ff22143f9980eb78b3a860c4843bfd0
const address = `0x${toHex(keccak256(keypair.pubkey.slice(1)).slice(-20))}`; // 0x71cb05ee1b1f506ff321da3dac38f25c0c9ce6e1
Cosmos SDK expects compressed secp256k1 public keys. Those are 33 bytes long, starting with 0x02 or 0x03. If you have an uncompressed pubkey key from an external source, you con compress it.
import { fromHex, toHex } from "@cosmjs/encoding";
import { Secp256k1 } from "@cosmjs/crypto";
// Uncompressed format (65 bytes, starting with 0x04)
const pubkey = fromHex("044f04181eeba35391b858633a765c4a0c189697b40d216354d50890d350c7029013b587a681e836cc187a8164b98a5848a2b89b3173315fdd0740d5032e259cd5");
const compressed = Secp256k1.compressPubkey(pubkey);
console.log(toHex(compressed)); // 034f04181eeba35391b858633a765c4a0c189697b40d216354d50890d350c70290
Given a delegation rewards response like
{
rewards: [
{
validatorAddress: 'junovaloper1juczud9nep06t0khghvm643hf9usw45r23gsmr',
reward: [Array]
}
],
total: [ { denom: 'ujuno', amount: '1519872422095573900000' } ]
}
you can use CosmJS to parse the amount in a human readable representation without loosing precision as follows:
import { Decimal } from "@cosmjs/math";
const amount = Decimal.fromAtomics("1519872422095573900000", 18);
console.log(amount.toString()); // "1519.8724220955739"
console.log(amount.atomics); // "1519872422095573900000"
console.log(amount.fractionalDigits); // 18
console.log(amount.toFloatApproximation()); // 1519.872422095574 (please note the rounding in the last position!)