navio-blsct
Version:
TypeScript bindings for the `libblsct` library used by the [Navio](https://nav.io/) blockchain to construct confidential transactions based on the BLS12-381 curve.
147 lines (146 loc) • 6.43 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CTx = void 0;
const blsct_1 = require("./blsct");
const ctxId_1 = require("./ctxId");
const ctxIns_1 = require("./ctxIns");
const ctxOuts_1 = require("./ctxOuts");
const managedObj_1 = require("./managedObj");
/** Represents a confidential transaction. Also known as `CMutableTransaction` on the C++ side.
* Examples:
* ```ts
* const { CTx, CTxId, TxIn, TxOut, ChildKey, Scalar, SubAddr, SubAddrId, DoublePublicKey, OutPoint, PublicKey, TokenId, CTX_ID_SIZE } = require('navio-blsct')
* const { randomBytes } = require('crypto')
* const cTxIdHex = randomBytes(CTX_ID_SIZE).toString('hex')
* const cTxId = CTxId.deserialize(cTxIdHex)
* const numTxIn = 1
* const numTxOut = 1
* const defaultFee = 200000
* const fee = (numTxIn + numTxOut) * defaultFee
* const outAmount = 10000
* const inAmount = fee + outAmount
* const outIndex = 0
* const outPoint = OutPoint.generate(cTxId, outIndex)
* const gamma = 100
* const spendingKey = Scalar.random()
* const tokenId = TokenId.default()
* const txIn = TxIn.generate(inAmount, gamma, spendingKey, tokenId, outPoint)
* const viewKey = new ChildKey().toTxKey().toViewKey()
* const spendingPubKey = new PublicKey()
* const subAddrId = SubAddrId.generate(123, 456)
* const subAddr = SubAddr.generate(viewKey, spendingPubKey, subAddrId)
* const txOut = TxOut.generate(subAddr, outAmount, 'navio')
* const cTx = CTx.generate([txIn], [txOut])
* for (const cTxIn of cTx.getCTxIns()) {
* console.log(`prevOutHash: ${cTxIn.getPrevOutHash()}`)
* console.log(`prevOutN: ${cTxIn.getPrevOutN()}`)
* console.log(`scriptSig: ${cTxIn.getScriptSig()}`)
* console.log(`sequence: ${cTxIn.getSequence()}`)
* console.log(`scriptWitness: ${cTxIn.getScriptWitness()}`)
* }
* for (const cTxOut of cTx.getCTxOuts()) {
* console.log(`value: ${cTxOut.getValue()}`)
* console.log(`script_pub_key: ${cTxOut.getScriptPubKey()}`)
* console.log(`blsctData.spendingKey: ${cTxOut.blsctData().getSpendingKey()}`)
* console.log(`blsctData.ephemeralKey: ${cTxOut.blsctData().getEphemeralKey()}`)
* console.log(`blsctData.blindingKey: ${cTxOut.blsctData().getBlindingKey()}`)
* console.log(`blsctData.viewTag: ${cTxOut.blsctData().getViewTag()}`)
* const rp = cTxOut.blsctData().getRangeProof()
* console.log(`blsctData.rangeProof.A: ${rp.get_A()}`)
* console.log(`blsctData.rangeProof.A_wip: ${rp.get_A_wip()}`)
* console.log(`blsctData.rangeProof.B: ${rp.get_B()}`)
* console.log(`blsctData.rangeProof.r_prime: ${rp.get_r_prime()}`)
* console.log(`blsctData.rangeProof.s_prime: ${rp.get_s_prime()}`)
* console.log(`blsctData.rangeProof.delta_prime: ${rp.get_delta_prime()}`)
* console.log(`blsctData.rangeProof.alpha_hat: ${rp.get_alpha_hat()}`)
* console.log(`blsctData.rangeProof.tau_x: ${rp.get_tau_x()}`)
* console.log(`tokenId: token=${cTxOut.getTokenId().getToken()}, subid=${cTxOut.getTokenId().getSubid()}`)
* console.log(`vector_predicate: ${cTxOut.getVectorPredicate()}`)
* }
* const ser = cTx.serialize()
* const deser = CTx.deserialize(ser)
* ser === deser.serialize() // true
*/
class CTx extends managedObj_1.ManagedObj {
constructor(obj) {
super(obj, () => (0, blsct_1.deleteCTx)(obj));
}
/** Constructs a new `CTx` instance.
* @param srcTxIns - An array of `TxIn` objects representing the transaction inputs.
* @param srcTxOuts - An array of `TxOut` objects representing the transaction outputs.
* @returns A new `CTx` instance.
*/
static generate(txIns, txOuts) {
// create vector and add txIns to it
const txInVec = (0, blsct_1.createTxInVec)();
for (const txIn of txIns) {
(0, blsct_1.addToTxInVec)(txInVec, txIn.value());
}
// create vector and add txOuts to it
const txOutVec = (0, blsct_1.createTxOutVec)();
for (const txOut of txOuts) {
(0, blsct_1.addToTxOutVec)(txOutVec, txOut.value());
}
const rv = (0, blsct_1.buildCTx)(txInVec, txOutVec);
// free the temporary vectors
(0, blsct_1.deleteTxInVec)(txInVec);
(0, blsct_1.deleteTxOutVec)(txOutVec);
if (rv.result === blsct_1.BLSCT_IN_AMOUNT_ERROR) {
const msg = `Failed to build transaction. txIns[${rv.in_amount_err_index}] has an invalid amount`;
(0, blsct_1.freeObj)(rv);
throw new Error(msg);
}
if (rv.result === blsct_1.BLSCT_OUT_AMOUNT_ERROR) {
const msg = `Failed to build transaciton. tx_outs[${rv.out_amount_err_index}] has an invalid amount`;
(0, blsct_1.freeObj)(rv);
throw new Error(msg);
}
if (rv.result !== 0) {
const msg = `building tx failed. Error code = ${rv.result}`;
(0, blsct_1.freeObj)(rv);
throw new Error(msg);
}
const obj = rv.ctx;
(0, blsct_1.freeObj)(rv);
return CTx.fromObjAndSize(obj, 0);
}
value() {
return (0, blsct_1.castToUint8_tPtr)(this.obj);
}
/** Returns the transaction ID of this confidential transaction.
* @returns The transaction ID.
*/
getCTxId() {
const txIdHex = (0, blsct_1.getCTxId)(this.value());
return ctxId_1.CTxId.deserialize(txIdHex);
}
/** Returns the number of transaction inputs in this confidential transaction.
* @returns The number of transaction inputs.
*/
getCTxIns() {
return new ctxIns_1.CTxIns((0, blsct_1.getCTxIns)(this.value()));
}
/** Returns the number of transaction outputs in this confidential transaction.
* @returns The number of transaction outputs.
*/
getCTxOuts() {
return new ctxOuts_1.CTxOuts((0, blsct_1.getCTxOuts)(this.value()));
}
serialize() {
const buf = (0, blsct_1.castToUint8_tPtr)(this.value());
return (0, blsct_1.toHex)(buf, this.size());
}
/** Deserializes a hexadecimal string into a `CTx` instance.
* @param hex - The hexadecimal string to deserialize.
* @returns A new `CTx` instance.
*/
static deserialize(hex) {
if (hex.length % 2 !== 0) {
hex = `0${hex}`;
}
const objSize = hex.length / 2;
const obj = (0, blsct_1.hexToMallocedBuf)(hex);
return CTx.fromObjAndSize(obj, objSize);
}
}
exports.CTx = CTx;