@terra-money/core
Version:
This package provides Terra Blockchain client side APIs to support building transaction, singing, or querying chain data.
108 lines • 3.71 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const CryptoJS = require("crypto-js");
const secp256k1 = require("secp256k1");
const Amino = require("@terra-money/amino-js");
function byteArrayToWordArray(ba) {
const wa = [];
for (let i = 0; i < ba.length; i += 1) {
wa[(i / 4) | 0] |= ba[i] << (24 - 8 * i);
}
return CryptoJS.lib.WordArray.create(wa, ba.length);
}
// Transactions often have amino decoded objects in them {type, value}.
// We need to strip this clutter as we need to sign only the values.
function prepareSignBytes(jsonTx) {
if (Array.isArray(jsonTx)) {
return jsonTx.map(prepareSignBytes);
}
// string or number
if (typeof jsonTx !== `object`) {
return jsonTx;
}
const sorted = {};
Object.keys(jsonTx)
.sort()
.forEach(key => {
if (jsonTx[key] === undefined || jsonTx[key] === null)
return;
sorted[key] = prepareSignBytes(jsonTx[key]);
});
return sorted;
}
exports.prepareSignBytes = prepareSignBytes;
/*
The SDK expects a certain message format to serialize and then sign.
type StdSignMsg struct {
ChainID string `json:"chain_id"`
AccountNumber uint64 `json:"account_number"`
Sequence uint64 `json:"sequence"`
Fee auth.StdFee `json:"fee"`
Msgs []sdk.Msg `json:"msgs"`
Memo string `json:"memo"`
}
*/
/* eslint-disable @typescript-eslint/camelcase */
function createSignMessage(tx, { sequence, account_number, chain_id }) {
// sign bytes need amount to be an array
const fee = {
amount: tx.fee.amount || [],
gas: tx.fee.gas
};
return JSON.stringify(prepareSignBytes({
fee,
memo: tx.memo,
msgs: tx.msg,
sequence,
account_number,
chain_id
}));
}
// produces the signature for a message (returns Buffer)
function signWithPrivateKey(signMessage, privateKey) {
const signHash = Buffer.from(CryptoJS.SHA256(signMessage).toString(), `hex`);
const { signature } = secp256k1.ecdsaSign(signHash, Buffer.from(privateKey, `hex`));
return signature;
}
function createSignature(signature, publicKey) {
return {
signature: signature.toString(`base64`),
pub_key: {
type: `tendermint/PubKeySecp256k1`,
value: publicKey.toString(`base64`)
}
};
}
// main function to sign a jsonTx using the local keystore wallet
// returns the complete signature object to add to the tx
function sign(jsonTx, keyPair, requestMetaData) {
const signMessage = createSignMessage(jsonTx, requestMetaData);
const signatureBuffer = Buffer.from(signWithPrivateKey(signMessage, keyPair.privateKey));
return createSignature(signatureBuffer, keyPair.publicKey);
}
exports.sign = sign;
// adds the signature object to the tx
function createSignedTx(tx, signature) {
return Object.assign({}, tx, {
signatures: [signature]
});
}
exports.createSignedTx = createSignedTx;
function getAminoDecodedTxBytes(tx) {
return Amino.marshalTx(tx, true);
}
exports.getAminoDecodedTxBytes = getAminoDecodedTxBytes;
function getTxHash(txbytes) {
return CryptoJS.SHA256(byteArrayToWordArray(txbytes)).toString();
}
exports.getTxHash = getTxHash;
// the broadcast body consists of the signed tx and a return type
// returnType can be block (inclusion in block), async (right away), sync (after checkTx has passed)
function createBroadcastBody(signedTx, modeType = `block`) {
return JSON.stringify({
tx: signedTx,
mode: modeType
});
}
exports.createBroadcastBody = createBroadcastBody;
//# sourceMappingURL=txUtils.js.map