Software SDK
To interact with HEAT blockchain natives we use https://github.com/heatcrypto/heat-sdk-v2
,
heat-sdk-v2
offers all native operations available on HEAT blockchain.
To name a few:
- building, signing and parsing binary transactions
- crypto native operations (signing, validating, encryption/decryption)
- supports all available transaction types
To use heat-sdk-v2
in your code use it directly from github like this.
/* package.json */
{
"name": "heat_app_js",
"version": "0.1.0",
"description": "Js crypto routines for Heat Wallet app",
"main": "index.js",
"engines": {
"node": ">=0.12"
},
"scripts": {
"build": "npm run test && node build.js",
"test": "mocha --recursive"
},
"author": "me",
"license": "UNLICENSED",
"browser": {
"stream": "stream-browserify",
"crypto": "crypto-browserify",
"big.js": "./node_modules/big.js/big.js",
"curve25519": "./node_modules/curve25519/dist/curve25519.js",
"cryptojs": "./node_modules/cryptojs/dist/CryptoJs.js"
},
"dependencies": {
"big.js": "dmdeklerk/big.js#master",
"buffer": "6.0.3",
"crypto-browserify": "3.12.0",
"cryptojs": "heatcrypto/CryptoJs#master",
"curve25519": "heatcrypto/curve25519#master",
"heat-sdk-v2": "heatcrypto/heat-sdk-v2#master", // <-- Use from github.com
"stream-browserify": "3.0.0"
}
}
Get Public Key From Private Key
This example shows how to obtain a public key from a private key.
const { getPublicKeyFromPrivateKey } = require('heat-sdk-v2/dist/crypto')
/**
* @param {{
* privateKeyAsHex: string,
* }} params
* @returns string
*/
function HEAT_GET_PUBLICKEY_FROM_PRIVATEKEY(params) {
const { privateKeyAsHex } = params;
return getPublicKeyFromPrivateKey(privateKeyAsHex)
}
module.exports = { HEAT_GET_PUBLICKEY_FROM_PRIVATEKEY }
Get Address From Public Key
This example shows how to obtain an address from a public key
const { getAccountIdFromPublicKey } = require('heat-sdk-v2/dist/crypto')
/**
* @param {{
* publicKeyAsHex: string,
* }} params
* @returns string
*/
function HEAT_GET_ADDRESS_FROM_PUBLICKEY(params) {
const { publicKeyAsHex } = params;
return getAccountIdFromPublicKey(publicKeyAsHex)
}
module.exports = { HEAT_GET_ADDRESS_FROM_PUBLICKEY }
Transfer HEAT Transaction
This example shows how to build and sign a HEAT transfer
const { HeatSDK, Configuration, Builder, attachment, Transaction } = require("heat-sdk-v2")
const isString = require("lodash/isString")
const isBoolean = require('lodash/isBoolean')
/**
* @typedef {"prod" | "test"} NetworkType
*/
/**
* @param {{
* key: string,
* recipientAddress: string,
* recipientPublicKey: string,
* amount: string,
* fee: string,
* networkType: ('prod' | 'test' | null),
* message: string,
* messageIsPrivate: boolean,
* messageIsBinary: boolean
* }} params
* @returns hex string
*/
function HEAT_TRANSFER_HEAT(params) {
const { key, recipientAddress, recipientPublicKey, amount, fee, networkType, message, messageIsPrivate, messageIsBinary, } = params
return transferHeat(key, recipientAddress, recipientPublicKey, amount, fee, networkType, message, messageIsPrivate, messageIsBinary,)
}
/**
* Create a transaction to transfer HEAT.
*
* @param {String} key
* @param {String | null} recipientAddress
* @param {String | null} recipientPublicKey
* @param {String} amount
* @param {String | null} fee
* @param {'prod' | 'test' | null} networkType
* @param {String | null} message
* @param {Boolean | null} messageIsPrivate
* @param {Boolean | null} messageIsBinary
*
* @returns bytes HEX string
*/
function transferHeat(key, recipientAddress, recipientPublicKey, amount, fee, networkType, message, messageIsPrivate, messageIsBinary) {
if (!isString(key)) throw new Error(`Key arg should be "String"`)
if (!isValidAddress(recipientAddress)) throw new Error(`recipientAddress arg should be "String"`)
if (recipientPublicKey && !isString(recipientPublicKey)) throw new Error(`recipientPublicKey arg should be "String"`)
if (!isString(amount) && !isNaN(Number(amount)) && Number(amount) > 0) throw new Error(`amount arg should be "String"`)
if (!isString(fee) && !isNaN(Number(fee)) && Number(fee) > 0) throw new Error(`fee arg should be "String"`)
if (!isString(networkType)) throw new Error(`networkType arg should be "String"`)
if (message && !isString(message)) throw new Error(`message arg should be "String"`)
if (!isBoolean(messageIsPrivate)) throw new Error(`messageIsPrivate arg should be "Boolean"`)
if (!isBoolean(messageIsBinary)) throw new Error(`messageIsBinary arg should be "Boolean"`)
const isTestnet = networkType == 'test' ? true : false
const sdk = new HeatSDK(new Configuration({ isTestnet: isTestnet }))
const recipientAddressOrPublicKey = (isString(recipientPublicKey) ? recipientPublicKey : recipientAddress)
let builder = new Builder()
.isTestnet(sdk.config.isTestnet)
.genesisKey(sdk.config.genesisKey)
.attachment(attachment.ORDINARY_PAYMENT)
.amountHQT(amount)
.feeHQT(fee)
let txn = new Transaction(sdk, recipientAddressOrPublicKey, builder)
if (message) {
txn = messageIsPrivate ? txn.privateMessage(message, messageIsBinary) : txn.publicMessage(message, messageIsBinary)
}
return txn.sign(key).then(t => {
let transaction = t.getTransaction()
let bytes = transaction.getBytesAsHex()
return bytes
})
}
function isValidAddress(value) {
return isString(value) && !isNaN(Number(value)) && Number(value) != 0
}
module.exports = { HEAT_TRANSFER_HEAT }
Transfer Asset Transaction
This example shows how to build and sign an Asset Transfer
const { HeatSDK, Configuration, Builder, attachment, Transaction } = require("heat-sdk-v2")
const isString = require("lodash/isString")
const isBoolean = require('lodash/isBoolean')
/**
* @param {{
* key: string,
* recipientAddress: string,
* recipientPublicKey: string,
* amount: string,
* fee: string,
* networkType: "prod" | "test",
* asset: string,
* message: string,
* messageIsPrivate: boolean,
* messageIsBinary: boolean
* }} params
* @returns hex string
*/
function HEAT_TRANSFER_ASSET(params) {
const { key, recipientAddress, recipientPublicKey, amount, fee, networkType, asset, message, messageIsPrivate, messageIsBinary } = params
return transferAsset(key, recipientAddress, recipientPublicKey, amount, fee, networkType, asset, message, messageIsPrivate, messageIsBinary)
}
/**
* Create a transaction to transfer HEAT.
*
* @param {String} key
* @param {String | null} recipientAddress
* @param {String | null} recipientPublicKey
* @param {String} amount
* @param {String | null} fee
* @param {'prod' | 'test' | null} networkType
* @param {String} asset
* @param {String | null} message
* @param {Boolean | null} messageIsPrivate
* @param {Boolean | null} messageIsBinary
*
* @returns bytes HEX string
*/
function transferAsset(key, recipientAddress, recipientPublicKey, amount, fee, networkType, asset, message, messageIsPrivate, messageIsBinary) {
if (!isString(key)) throw new Error(`Key arg should be "String"`)
if (!isValidAddress(recipientAddress)) throw new Error(`recipientAddress arg should be "String"`)
if (recipientPublicKey && !isString(recipientPublicKey)) throw new Error(`recipientPublicKey arg should be "String"`)
if (!isString(amount) && !isNaN(Number(amount)) && Number(amount) > 0) throw new Error(`amount arg should be "String"`)
if (!isString(fee) && !isNaN(Number(fee)) && Number(fee) > 0) throw new Error(`fee arg should be "String"`)
if (!isString(networkType)) throw new Error(`networkType arg should be "String"`)
if (!isValidAddress(asset)) throw new Error(`asset arg not valid should be "String"`)
if (message && !isString(message)) throw new Error(`message arg should be "String"`)
if (!isBoolean(messageIsPrivate)) throw new Error(`messageIsPrivate arg should be "Boolean"`)
if (!isBoolean(messageIsBinary)) throw new Error(`messageIsBinary arg should be "Boolean"`)
const isTestnet = networkType == 'test' ? true : false
const sdk = new HeatSDK(new Configuration({isTestnet:isTestnet}))
const recipientAddressOrPublicKey = (isString(recipientPublicKey) ? recipientPublicKey : recipientAddress)
let builder = new Builder()
.isTestnet(sdk.config.isTestnet)
.genesisKey(sdk.config.genesisKey)
.attachment(new attachment.AssetTransfer().init(asset, amount))
.amountHQT("0")
.feeHQT(fee)
let txn = new Transaction(sdk, recipientAddressOrPublicKey, builder)
if (message) {
txn = messageIsPrivate ? txn.privateMessage(message, messageIsBinary) : txn.publicMessage(message, messageIsBinary)
}
return txn.sign(key).then(t => {
let transaction = t.getTransaction()
let bytes = transaction.getBytesAsHex()
return bytes
})
}
function isValidAddress(value) {
return isString(value) && !isNaN(Number(value)) && Number(value) != 0
}
module.exports = { HEAT_TRANSFER_ASSET }
Parse Raw Transaction Bytes
This example shows how to parse raw transaction bytes
const { byteArrayToHexString } = require("heat-sdk-v2/dist/converters");
const { calculateFullHash, calculateTransactionId } = require("heat-sdk-v2/dist/crypto");
const { TransactionImpl } = require("heat-sdk-v2/dist/builder");
const { isObject, find } = require("lodash");
/**
* @param {{
* hex: string,
* isTestnet: boolean
* }} params
* @returns {{
* id?: string,
* amount: string,
* fee: string,
* recipient: string,
* deadline: number
* isTestnet: boolean,
* assetId?: string,
* message?: string,
* }}
*/
function HEAT_PARSE_TRANSACTION(params) {
const { hex, isTestnet } = params;
return parseTransaction(hex, isTestnet);
}
/**
* @param {string} hex
* @param {boolean} _isTestnet
* @returns {{
* id?: string,
* amount: string,
* fee: string,
* recipient: string,
* deadline: number
* isTestnet: boolean,
* assetId?: string,
* message?: string,
* senderPublicKey?: string,
* }}
*/
function parseTransaction(hex, _isTestnet) {
const transaction = TransactionImpl.parse(hex, _isTestnet);
const amount = transaction.amountHQT;
const fee = transaction.feeHQT;
const recipient = transaction.recipientId;
const deadline = transaction.deadline;
const isTestnet = transaction.isTestnet;
const message = transaction.message;
const transactionId = getTransactionId(transaction.getUnsignedBytes(), transaction.signature);
const senderPublicKey = byteArrayToHexString(transaction.senderPublicKey);
// @ts-ignore
const assetTransfer = getAssetTransfer(transaction);
return {
id: transactionId,
amount: assetTransfer ? assetTransfer.quantity : amount,
fee,
recipient,
deadline,
isTestnet,
assetId: assetTransfer ? assetTransfer.assetId : null,
message,
senderPublicKey,
};
}
/**
* @param {{
* appendages: [{
* assetId:any,
* quantity: any
* }]
* }} transaction
* @returns {{
* assetId:string,
* quantity: string
* }}
*/
function getAssetTransfer(transaction) {
const appendage = find(
transaction.appendages,
(attachment) =>
isObject(attachment.assetId) && isObject(attachment.quantity)
);
if (appendage) {
return {
assetId: appendage.assetId.toUnsigned().toString(),
quantity: appendage.quantity.toString(),
};
}
}
/**
* @param {Buffer} unsignedBytes
* @param {Buffer} signture
* @returns {String}
*/
function getTransactionId(unsignedBytes, signture) {
const unsignedBytesHex = byteArrayToHexString(unsignedBytes)
const signatureHex = byteArrayToHexString(signture)
const fullHash = calculateFullHash(unsignedBytesHex, signatureHex)
return calculateTransactionId(fullHash)
}
module.exports = { HEAT_PARSE_TRANSACTION };