@crypto-org-chain/chain-jslib
v1.1.2
Published
Crypto.org Chain JavaScript library
Downloads
21,921
Readme
Crypto.org Chain JS library
Warning
Crypto.org Chain and this library is currently in the alpha development phase and subjects to changes. Before proceeding, please be aware of the following:
This library is not production-ready, do not use in production systems.
Do not transfer any ERC20 tokens to addresses generated by this sample code as it can cause loss of funds.
Crypto.org is not liable for any potential damage, loss of data/files arising from the use of the library.
1. Quick Guide
1.0. Installing the library ⬇️
npm install @crypto-org-chain/chain-jslib
1.1. Working with private keys and key pairs 🔐
// Imports
const sdk = require("@crypto-org-chain/chain-jslib");
const HDKey = sdk.HDKey;
const Secp256k1KeyPair = sdk.Secp256k1KeyPair;
const Bytes = sdk.utils.Bytes;
// Initializing the library configurations with TestNet config
const cro = sdk.CroSDK({ network: sdk.CroNetwork.Testnet });
// Generating a random mnemonic phrase
let randomPhrase = HDKey.generateMnemonic(12); // This returns a 12 words mnemonic phrase
// Import an HDKey from a previous mnemonic phrase
const importedHDKey = HDKey.fromMnemonic(
"curtain maid fetch push pilot frozen speak motion island pigeon habit suffer gap purse royal hollow among orange pluck mutual eager cement void panther"
);
// Derive a private key from an HDKey at the specified path
const privateKey = importedHDKey.derivePrivKey("m/44'/1'/0'/0/0");
// Getting a keyPair from a private key
const keyPair = Secp256k1KeyPair.fromPrivKey(privateKey);
1.2. Generating an address 🔖
// Initializing the library configurations with TestNet config
const cro = sdk.CroSDK({ network: sdk.CroNetwork.Testnet });
// Import private key from hex key value
let privKey = Bytes.fromHexString(
"66633d18513bec30dd11a209f1ceb1787aa9e2069d5d47e590174dc9665102b3"
);
// Get keyPair from the imported private key
const importedKeyPair = Secp256k1KeyPair.fromPrivKey(privKey);
// Generate address from the imported key pair
let address = new cro.Address(importedKeyPair).account();
console.log(address); // tcro1sxe3v6gka3u8j7d2xhl8rmfyjnmggqlh6e82hq
1.3. Build and Sign a transfer transaction ✅
// Imports
const sdk = require("@crypto-org-chain/chain-jslib");
const HDKey = sdk.HDKey;
const Secp256k1KeyPair = sdk.Secp256k1KeyPair;
const Units = sdk.Units;
const Big = sdk.utils.Big;
// Initialize the library configurations with TestNet configs
const cro = sdk.CroSDK({ network: sdk.CroNetwork.Testnet });
const importedHDKey = HDKey.fromMnemonic(
"curtain maid fetch push pilot frozen speak motion island pigeon habit suffer gap purse royal hollow among orange pluck mutual eager cement void panther"
);
// Derive a private key from an HDKey at the specified path
const privateKey = importedHDKey.derivePrivKey("m/44'/1'/0'/0/0");
// Getting a keyPair from a private key
const keyPair = Secp256k1KeyPair.fromPrivKey(privateKey);
// Init Raw transaction
const rawTx = new cro.RawTransaction();
const feeAmount = new cro.Coin("6500", Units.BASE);
// Custom properties set
rawTx.setMemo("Hello Test Memo");
rawTx.setGasLimit("280000");
rawTx.setFee(feeAmount);
rawTx.setTimeOutHeight(341910);
const msgSend = new cro.bank.MsgSend({
fromAddress: "tcro165tzcrh2yl83g8qeqxueg2g5gzgu57y3fe3kc3",
toAddress: "tcro165tzcrh2yl83g8qeqxueg2g5gzgu57y3fe3kc3",
amount: new cro.Coin("1210", Units.BASE),
});
const signableTx = rawTx
.appendMessage(msgSend)
.addSigner({
publicKey: keyPair.getPubKey(),
accountNumber: new Big(41),
accountSequence: new Big(13),
})
.toSignable();
const signedTx = signableTx
.setSignature(0, keyPair.sign(signableTx.toSignDoc(0)))
.toSigned();
console.log(signedTx.getHexEncoded());
// 0aa4010a8c010a1c2f636f736d6f732e62616e6b2e763162657461312e4d736753656e64126c0a2b7463726f313635747a63726832796c3833673871657178756567326735677a6775353779336665336b6333122b7463726f313635747a63726832796c3833673871657178756567326735677a6775353779336665336b63331a100a08626173657463726f120431323130120f48656c6c6f2054657374204d656d6f1896ef14126a0a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a2103c3d281a28592adce81bee3094f00eae26932cbc682fba239b90f47dac9fe703612040a020801180d12160a100a08626173657463726f12043635303010c08b111a40fe9b30f29bb9a83df3685f5bf8b7e6c34bae9ee8ba93115af4136289354c5bf947698ef3a3c0a1f6092ba7a2069616c436f4bcf6f3ecef11b92ad4d319ec0347
// Note that the result of signedTx.getHexEncoded() can be directly broadcasted to the network as a raw tx
1.4. Sending transactions 📨
The SDK uses cosmjs stargate client to send transactions. For more information, check https://github.com/cosmos/cosmjs/tree/main/packages/stargate
// Imports
const sdk = require("@crypto-org-chain/chain-jslib");
const cro = sdk.CroSDK({ network: sdk.CroNetwork.Testnet });
const client = await cro.CroClient.connect();
await client.broadcastTx(signedTx.encode().toUint8Array());
1.5. Query the chain ❓
The SDK uses cosmjs queryclient to query the blockchain. For more information, check https://github.com/cosmos/cosmjs/tree/main/packages/stargate/src/queries
// Imports
const sdk = require("@crypto-org-chain/chain-jslib");
const cro = sdk.CroSDK({ network: sdk.CroNetwork.Testnet });
const client = await cro.CroClient.connect();
const queryResult = await client.query().<module>.<operation>
// example client.query().bank.allBalances(<address>)
1.6. Transaction Decoding/Encoding support
Our SDK supports transaction decoding from hex-encoded strings.
import { TxDecoder } from './txDecoder';
const txDecoder = new TxDecoder();
const decodedTx = txDecoder.fromHex('0a9b010a8c010a1c2f636f736d6f732e62616e6b2e763162657461312e4d736753656e64126c0a2b7463726f31667a63727a61336a3466323637376a667578756c6b6733337a36383532717371733868783530122b7463726f31667a63727a61336a3466323637376a667578756c6b6733337a363835327173717338687835301a100a08626173657463726f120431303030120a616d696e6f2074657374126b0a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a210223c9395d41013e6470c8d27da8b75850554faada3fe3e812660cbdf4534a85d712040a020801180112170a110a08626173657463726f1205313030303010a08d061a4031f4c489b98decb367972790747139c7706f54aafd9e5a3a5ada4f72c7b017646f1eb5cb1bdf518603d5d8991466a13c3f68844dcd9b168b5d4ca0cb5ea514bc');
//Prints decoded in Cosmos compatible JSON format
console.log(decodedTx.toCosmosJSON())
// Prints
// "{"tx":{"body":{"messages":[{"@type":"/cosmos.bank.v1beta1.MsgSend","amount":[{"denom":"basetcro","amount":"1000"}],"from_address":"tcro1fzcrza3j4f2677jfuxulkg33z6852qsqs8hx50","to_address":"tcro1fzcrza3j4f2677jfuxulkg33z6852qsqs8hx50"}],"memo":"amino test","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AiPJOV1BAT5kcMjSfai3WFBVT6raP+PoEmYMvfRTSoXX"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}},"sequence":"1"}],"fee":{"amount":[{"denom":"basetcro","amount":"10000"}],"gas_limit":"100000","payer":"","granter":""}},"signatures":["MfTEibmN7LNnlyeQdHE5x3BvVKr9nlo6WtpPcsewF2RvHrXLG99RhgPV2JkUZqE8P2iETc2bFotdTKDLXqUUvA=="]}}"
1.7. Offline Signing
Our SDK supports offline signing for secure external transaction management.
Flow:
Machine 1 (Online):
- Build a
RawTransactionV2
instance. - Export Cosmos compatible JSON by using
.toCosmosJSON()
. - Export Signer(s) list using
.exportSignerAccounts()
.
Machine 2 (Offline/Online):
- Create a
SignableTransactionV2
instance from a stringified cosmos compatible JSON string. - You can import Signer(s) list using two methods:
- call
importSignerAccounts()
on the instance above OR - (Advance usage) call
setSignerAccountNumberAtIndex()
to manually set AccountNumber at a specified index.
- call
- You can choose to export the signed hex encoded transaction and broadcast it manually
Eg:
// import respective classes
// ....
/* Machine 1: */
const rawTx = new cro.v2.RawTransactionV2();
// .... Do rest operations here
const exportUnsignedCosmosJSON = rawTx.toCosmosJSON();
const exportSignerInfoToJSON = rawTx.exportSignerAccounts();
/* Machine 2: */
const signerAccountsOptional: SignerAccount[] = cro
.v2
.RawTransactionV2
.parseSignerAccounts(exportSignerInfoToJSON);
/* SignerAccount[] has the structure of
[{
publicKey: <Bytes>;
accountNumber: new Big(0);
signMode: SIGN_MODE.DIRECT;
}];
*/
const signableTx = new SignableTransactionV2({
rawTxJSON: exportUnsignedCosmosJSON,
network: <CroNetwork>,
signerAccounts: signerAccountsOptional,
});
/* `Import SignerAccounts` starts */
// METHOD 1: using importSignerAccounts()
signableTx.importSignerAccounts([
// SignerAccount 1
{
publicKey: Bytes.fromHexString('hexString');
accountNumber: new Big(0);
signMode: SIGN_MODE.DIRECT;
},
// SignerAccount 2
{
publicKey: Bytes.fromUint8Array(<Uint8>);
accountNumber: new Big(2);
signMode: SIGN_MODE.DIRECT;
}
]);
// METHOD 2 (For Advance Users): using setSignerAccountNumberAtIndex()
const signerInfoListINDEX: number = 1;
const newAccountNumber: Big = new Big(1);
signableTx.setSignerAccountNumberAtIndex(signerInfoListINDEX, newAccountNumber);
/* `Import SignerAccounts` ends */
// .... Do rest operations here on SignableTransaction
const signedTx = signableTx.toSigned();
console.log(signedTx.getHexEncoded());
// 0aa4010a8c010a1c2f636f736d6f732e62616e6b2e763162657461312e4d736753656e64126c0a2b7463726f313635747a63726832796c3833673871657178756567326735677a6775353779336665336b6333122b7463726f313635747a63726832796c3833673871657178756567326735677a6775353779336665336b63331a100a08626173657463726f120431323130120f48656c6c6f2054657374204d656d6f1896ef14126a0a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a2103c3d281a28592adce81bee3094f00eae26932cbc682fba239b90f47dac9fe703612040a020801180d12160a100a08626173657463726f12043635303010c08b111a40fe9b30f29bb9a83df3685f5bf8b7e6c34bae9ee8ba93115af4136289354c5bf947698ef3a3c0a1f6092ba7a2069616c436f4bcf6f3ecef11b92ad4d319ec0347
// Note that the result of signedTx.getHexEncoded() can be directly broadcasted to the network as a raw tx
1.8. Create a message from Cosmos compatible JSON
All Cosmos message types supported on our SDK can be instantiated using the function .fromCosmosMsgJSON()
on respective classes. You need to pass a valid Msg JSON
string and a network
instance.
Eg.
const msgSendJson ='{ "@type": "/cosmos.bank.v1beta1.MsgSend", "amount": [{ "denom": "basetcro", "amount": "3478499933290496" }], "from_address": "tcro1x07kkkepfj2hl8etlcuqhej7jj6myqrp48y4hg", "to_address": "tcro184lta2lsyu47vwyp2e8zmtca3k5yq85p6c4vp3" }';
const msgSend = cro.v2.bank.MsgSendV2.fromCosmosMsgJSON(msgSendJson, CroNetwork.Testnet);
// `msgSend` is a valid instance of `MsgSendV2` and can be used for Transaction building
const msgFundCommunityPoolJson = '{"@type":"/cosmos.distribution.v1beta1.MsgFundCommunityPool","amount":[{ "denom": "basetcro", "amount": "3478499933290496" }],"depositor":"tcro165tzcrh2yl83g8qeqxueg2g5gzgu57y3fe3kc3"}';
const msgFundCommPool = cro.v2.distribution.MsgFundCommunityPoolV2.fromCosmosMsgJSON(msgFundCommunityPoolJson, CroNetwork.Testnet);
// `msgFundCommPool`is a valid instance of `MsgFundCommunityPoolV2` and can be used for Transaction building
1.9. Using the gas estimator for a transaction
You can estimate gas for your transaction before signing and broadcasting it to the network. Eg.
//... initialising
const coin = new cro.Coin('99999999', Units.BASE);
const msgSendV2 = new cro.v2.bank.MsgSendV2({
fromAddress: 'tcro165tzcrh2yl83g8qeqxueg2g5gzgu57y3fe3kc3',
toAddress: 'tcro184lta2lsyu47vwyp2e8zmtca3k5yq85p6c4vp3',
amount: [coin],
});
const rawTxV2 = new cro.v2.RawTransactionV2();
rawTxV2.addMessage(msgSendV2);
const unsignedCosmosTx = rawTxV2.toCosmosJSON();
const estimatedGas = await cro.CroClient.estimateGasLimit(unsignedCosmosTx);
// set `gas_used` to the rawTx
rawTxV2.setGasLimit(estimatedGas.gas_used);
//... Do rest operations
2. Introducing V2
message types
Our SDK has introduced V2
message types in order to support:
- Custom
denom
- Multiple
amount
in several Cosmos Message types - Multiple
fee
amount inSignerInfo
You can use the v2
property on the CroSDK
instance like in the example below:
// imports here
const cro = CroSDK({ network: sdk.CroNetwork.Testnet });
// v2 methods below
const coin1 = new cro.Coin('88888888', Units.BASE);
const coin2 = new cro.Coin('99999999', Units.BASE);
const msgSendV2 = new cro.v2.bank.MsgSendV2({
fromAddress: 'tcro165tzcrh2yl83g8qeqxueg2g5gzgu57y3fe3kc3',
toAddress: 'tcro184lta2lsyu47vwyp2e8zmtca3k5yq85p6c4vp3',
amount: [coin1, coin2],
});
2.1 List of new V2
methods
- New classes for external transaction management:
RawTransactionV2
.toCosmosJSON()
: Get a Cosmos-sdk compatible JSON string.exportSignerAccounts()
: Exports a human readable JSON ofSignerAccount
appendFeeAmount(...)
: Add multiple fee amount toSignerInfo
list
CoinV2
: Supports custom denom supportSignableTransactionV2
: Load your Cosmos Tx JSON for transaction management.
Please note new message types may be added under the CroSDK
instance.
3. Cosmos Protobuf Definitions
Generate Cosmos Protobuf Definitions in JavaScript
Download Cosmos proto definitions folder
npm run get-proto
Generate definitions files in JavaScript
npm run define-proto
Update Supported Modules
To support more Cosmos modules, edit
lib/src/cosmos/v1beta1/scripts/predefine-proto.sh
and append the lines"$COSMOS_PROTO_DIR/bank/v1beta1/bank.proto" \ "$COSMOS_PROTO_DIR/bank/v1beta1/tx.proto" \
In this example it is adding
bank
module support, replace the paths with the modules and its protbuf files accordingly.edit
lib/src/cosmos/v1beta1/types/typeurls.ts
to add the protobuf type URLs to JS definitions mapping
3. API Documentation
The library API documentation can be generated by running
npm run docs:build
The resulting generated documentation will be created in the docs/dist
directory