Javascript
Using Javascript/node.js to sign a transaction
Encode and Sign Raw Message
The parameters should consist with your account information. The accountNumber
and sequence
could be found by querying LCD /cosmos/auth/v1beta1/accounts/{fromAddress}
endpoint.
const secp256k1 = require('secp256k1');
const createHash = require('create-hash');
const Long = require('long');
const { MsgSend } = require("./build/codec/cosmos/bank/v1beta1/tx");
const { TxBody, AuthInfo, SignDoc, TxRaw } = require("./build/codec/cosmos/tx/v1beta1/tx");
const { PubKey } = require("./build/codec/cosmos/crypto/secp256k1/keys");
// define parameters
const chainId = "likechain-local-testnet";
const privateKey = "69b4e47d3aa61ad6184493529cd0feb0d2dfb55ea31aa9799af42607de3cd1a9";
const publicKey = "A4Fj1Y4k77Qaxuy496CHYB2rpfWXkM3LCnlyrU8eKbH7";
const accountNumber = 2;
const fromAddress = "cosmos1lsagfzrm4gz28he4wunt63sts5xzmczw8pkek3";
const toAddress = "cosmos1mnyn7x24xj6vraxeeq56dfkxa009tvhgknhm04";
const tokenAmount = 1000000;
const memo = "Enjoy your money";
const gasLimit = 100000;
const sequence = 17;
const messages = [{
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: {
fromAddress,
toAddress,
amount: [
{
denom: "nanolike",
amount: tokenAmount.toString(),
},
],
}
}];
const wrappedMessages = messages.map(msg => {
return {
typeUrl: msg.typeUrl,
value: MsgSend.encode(msg.value).finish(),
}
})
const body = {
typeUrl: "/cosmos.tx.v1beta1.TxBody",
value: {
memo,
messages: wrappedMessages,
timeoutHeight: Long.UZERO,
extensionOptions: [],
nonCriticalExtensionOptions: [],
},
}
const bodyBytes = TxBody.encode(body.value).finish();
const pubkeyBytes = PubKey.encode({ key: publicKey }).finish();
const authInfo = {
signerInfos: [
{
sequence: Long.fromNumber(sequence),
publicKey: {
typeUrl: "/cosmos.crypto.secp256k1.PubKey",
value: pubkeyBytes,
},
modeInfo: {
single: {
mode: 1,
},
},
},
],
fee: {
gasLimit: Long.fromNumber(gasLimit),
payer: "",
granter: "",
amount: [
{
denom: "nanolike",
amount: "0",
},
],
},
}
const authInfoBytes = AuthInfo.encode(authInfo).finish();
const signDoc = {
bodyBytes,
authInfoBytes,
chainId,
accountNumber: Long.fromNumber(accountNumber),
}
const signBytes = SignDoc.encode(signDoc).finish();
const privkeyBytes = Buffer.from(privateKey, 'hex')
const sign = (msg, privateKey) => {
const msgSha256 = createHash('sha256');
msgSha256.update(msg);
const msgHash = msgSha256.digest();
const { signature: signatureArr } = secp256k1.ecdsaSign(msgHash, privateKey);
const signature = Buffer.from(signatureArr)
return signature;
}
const signatureBytes = sign(signBytes, privkeyBytes);
const tx = {
bodyBytes,
authInfoBytes,
signatures: [signatureBytes],
}
const txBytes = TxRaw.encode(tx).finish();
console.log("signature_bytes:", signatureBytes.toString('base64'));
console.log("sign_bytes:", signBytes.toString('base64'));
console.log("tx_bytes:", txBytes.toString('base64'));
// signature_bytes: zIfF132OINwGz0psHn+nxeYVQdHZXiqO/94qaXrowcRFEL2jA0qFarz22VBXYXQudOV6y0BL84/m475awNkiFA==
// sign_bytes: CqgBCpMBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnMKLWNvc21vczFsc2FnZnpybTRnejI4aGU0d3VudDYzc3RzNXh6bWN6dzhwa2VrMxItY29zbW9zMW1ueW43eDI0eGo2dnJheGVlcTU2ZGZreGEwMDl0dmhna25obTA0GhMKCG5hbm9saWtlEgcxMDAwMDAwEhBFbmpveSB5b3VyIG1vbmV5EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQOBY9WOJO+0GsbsuPegh2Adq6X1l5DNywp5cq1PHimx+xIECgIIARgREhMKDQoIbmFub2xpa2USATAQoI0GGhdsaWtlY2hhaW4tbG9jYWwtdGVzdG5ldCAC
// tx_bytes: CqgBCpMBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnMKLWNvc21vczFsc2FnZnpybTRnejI4aGU0d3VudDYzc3RzNXh6bWN6dzhwa2VrMxItY29zbW9zMW1ueW43eDI0eGo2dnJheGVlcTU2ZGZreGEwMDl0dmhna25obTA0GhMKCG5hbm9saWtlEgcxMDAwMDAwEhBFbmpveSB5b3VyIG1vbmV5EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQOBY9WOJO+0GsbsuPegh2Adq6X1l5DNywp5cq1PHimx+xIECgIIARgREhMKDQoIbmFub2xpa2USATAQoI0GGkDMh8XXfY4g3AbPSmwef6fF5hVB0dleKo7/3ippeujBxEUQvaMDSoVqvPbZUFdhdC505XrLQEvzj+bjvlrA2SIU
Commit a Transaction
Put the tx_bytes
from above step in the JSON request body as below, and post the LCD/cosmos/tx/v1beta1/txs
endpoint.
{
"tx_bytes": "Your tx bytes here",
"mode": "BROADCAST_MODE_SYNC"
}
For details of the POST /txs
and other chain RPC API, please refer to the LikeCoin chain RPC API section.
Verify Transaction Signature
const secp256k1 = require('secp256k1');
const createHash = require('create-hash');
const publicKey = Buffer.from("A4Fj1Y4k77Qaxuy496CHYB2rpfWXkM3LCnlyrU8eKbH7", "base64");
const signature = Buffer.from("zIfF132OINwGz0psHn+nxeYVQdHZXiqO/94qaXrowcRFEL2jA0qFarz22VBXYXQudOV6y0BL84/m475awNkiFA==", "base64");
const signBytes = Buffer.from("CqgBCpMBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnMKLWNvc21vczFsc2FnZnpybTRnejI4aGU0d3VudDYzc3RzNXh6bWN6dzhwa2VrMxItY29zbW9zMW1ueW43eDI0eGo2dnJheGVlcTU2ZGZreGEwMDl0dmhna25obTA0GhMKCG5hbm9saWtlEgcxMDAwMDAwEhBFbmpveSB5b3VyIG1vbmV5EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQOBY9WOJO+0GsbsuPegh2Adq6X1l5DNywp5cq1PHimx+xIECgIIARgREhMKDQoIbmFub2xpa2USATAQoI0GGhdsaWtlY2hhaW4tbG9jYWwtdGVzdG5ldCAC", "base64");
const msgSha256 = createHash('sha256');
msgSha256.update(signBytes);
const msgHash = msgSha256.digest();
console.log(secp256k1.ecdsaVerify(signature, msgHash, publicKey));
// true
Last updated