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.
npm install @crypto-org-chain/chain-jslib
// 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);
// 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
// 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
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());
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>)
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=="]}}"
Our SDK supports offline signing for secure external transaction management.
Machine 1 (Online):
RawTransactionV2
instance. .toCosmosJSON()
. .exportSignerAccounts()
. Machine 2 (Offline/Online):
SignableTransactionV2
instance from a stringified cosmos compatible JSON string.importSignerAccounts()
on the instance above ORsetSignerAccountNumberAtIndex()
to manually set AccountNumber at a specified index.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
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
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
V2
message typesOur SDK has introduced V2
message types in order to support:
denom
amount
in several Cosmos Message typesfee
amount in SignerInfo
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],
});
V2
methodsRawTransactionV2
.toCosmosJSON()
: Get a Cosmos-sdk compatible JSON string.exportSignerAccounts()
: Exports a human readable JSON of SignerAccount
appendFeeAmount(...)
: Add multiple fee amount to SignerInfo
listCoinV2
: Supports custom denom supportSignableTransactionV2
: Load your Cosmos Tx JSON for transaction management.Please note new message types may be added under the CroSDK
instance.
Download Cosmos proto definitions folder
npm run get-proto
Generate definitions files in JavaScript
npm run define-proto
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
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