@tatumio/tatum-v1
Version:
Tatum API client allows browsers and Node.js clients to interact with Tatum API.
215 lines • 23.2 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.adaToLovelace = exports.lovelaceToAda = exports.signTransaction = exports.processFeeAndRest = exports.makeWitness = exports.createWitnesses = exports.initTransactionBuilder = exports.addInput = exports.addOutputAda = exports.addOutputLovelace = exports.addUtxoInputs = exports.addInputsPrivateKeys = exports.addAddressInputsWithoutPrivateKey = exports.addAddressInputs = exports.addInputs = exports.addChangeIfNeeded = exports.addFee = exports.addOutputs = exports.signAdaKMSTransaction = exports.sendAdaTransaction = exports.prepareAdaTransaction = void 0;
const cardano_serialization_lib_nodejs_1 = require("@emurgo/cardano-serialization-lib-nodejs");
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const ada_1 = require("../blockchain/ada");
const tatum_1 = require("../connector/tatum");
const model_1 = require("../model");
/**
* Prepare a signed Ada transaction with the private key locally. Nothing is broadcasted to the blockchain.
* @param transferAdaBlockchain content of the transaction to prepare.
* @returns raw transaction data in hex, to be broadcasted to blockchain.
*/
const prepareAdaTransaction = async (transferAdaBlockchain) => {
await tatum_1.validateBody(transferAdaBlockchain, model_1.TransferAdaBlockchain);
const txBuilder = await exports.initTransactionBuilder();
const { to } = transferAdaBlockchain;
const { privateKeysToSign, amount: fromAmount } = await exports.addInputs(txBuilder, transferAdaBlockchain);
const toAmount = exports.addOutputs(txBuilder, to);
await exports.processFeeAndRest(txBuilder, fromAmount, toAmount, transferAdaBlockchain);
return exports.signTransaction(txBuilder, transferAdaBlockchain, privateKeysToSign);
};
exports.prepareAdaTransaction = prepareAdaTransaction;
/**
* Send Ada transaction to the blockchain. This method broadcasts signed transaction to the blockchain.
* This operation is irreversible.
* @param body content of the transaction to broadcast
* @returns transaction id of the transaction in the blockchain
*/
const sendAdaTransaction = async (body) => {
return ada_1.adaBroadcast(await exports.prepareAdaTransaction(body));
};
exports.sendAdaTransaction = sendAdaTransaction;
/**
* Sign Ada pending transaction from Tatum KMS
* @param tx pending transaction from KMS
* @param privateKeys private keys to sign transaction with.
* @returns transaction data to be broadcast to blockchain.
*/
const signAdaKMSTransaction = async (tx, privateKeys) => {
if (tx.chain !== model_1.Currency.ADA) {
throw Error('Unsupported chain.');
}
const transferAdaBlockchain = JSON.parse(tx.serializedTransaction).txData;
const txBuilder = await exports.initTransactionBuilder();
const { to } = transferAdaBlockchain;
const { amount: fromAmount } = await exports.addInputs(txBuilder, transferAdaBlockchain);
const toAmount = exports.addOutputs(txBuilder, to);
await exports.processFeeAndRest(txBuilder, fromAmount, toAmount, transferAdaBlockchain);
const txBody = txBuilder.build();
const txHash = cardano_serialization_lib_nodejs_1.hash_transaction(txBody);
const vKeyWitnesses = cardano_serialization_lib_nodejs_1.Vkeywitnesses.new();
for (const key of privateKeys) {
exports.makeWitness(key, txHash, vKeyWitnesses);
}
const witnesses = cardano_serialization_lib_nodejs_1.TransactionWitnessSet.new();
witnesses.set_vkeys(vKeyWitnesses);
return Buffer.from(cardano_serialization_lib_nodejs_1.Transaction.new(txBody, witnesses).to_bytes()).toString('hex');
};
exports.signAdaKMSTransaction = signAdaKMSTransaction;
const addOutputs = (transactionBuilder, tos) => {
let amount = new bignumber_js_1.default(0);
for (const to of tos) {
const valueAdded = exports.addOutputAda(transactionBuilder, to.address, to.value);
amount = amount.plus(valueAdded);
}
return amount;
};
exports.addOutputs = addOutputs;
const addFee = (txBuilder, feeInLovelace) => {
txBuilder.set_fee(cardano_serialization_lib_nodejs_1.BigNum.from_str(feeInLovelace.toString()));
};
exports.addFee = addFee;
const addChangeIfNeeded = (txBuilder, changeAddress) => {
txBuilder.add_change_if_needed(cardano_serialization_lib_nodejs_1.Address.from_bech32(changeAddress));
};
exports.addChangeIfNeeded = addChangeIfNeeded;
const addInputs = async (transactionBuilder, transferAdaBlockchain) => {
const { fromUTXO, fromAddress } = transferAdaBlockchain;
if (fromAddress) {
return exports.addAddressInputs(transactionBuilder, fromAddress);
}
if (fromUTXO) {
return exports.addUtxoInputs(transactionBuilder, fromUTXO);
}
throw new Error('Field fromAddress or fromUTXO is not filled.');
};
exports.addInputs = addInputs;
const addAddressInputs = async (transactionBuilder, fromAddresses) => {
const amount = await exports.addAddressInputsWithoutPrivateKey(transactionBuilder, fromAddresses);
const privateKeysToSign = await exports.addInputsPrivateKeys(fromAddresses);
return { amount, privateKeysToSign };
};
exports.addAddressInputs = addAddressInputs;
const addAddressInputsWithoutPrivateKey = async (transactionBuilder, fromAddresses) => {
let amount = new bignumber_js_1.default(0);
for (const fromAddress of fromAddresses) {
const { address } = fromAddress;
const utxos = await ada_1.adaGetUtxos(address);
for (const utxo of utxos) {
amount = amount.plus(utxo.value);
exports.addInput(transactionBuilder, utxo, address);
}
}
return amount;
};
exports.addAddressInputsWithoutPrivateKey = addAddressInputsWithoutPrivateKey;
const addInputsPrivateKeys = async (froms) => {
const privateKeysToSign = [];
for (const from of froms) {
privateKeysToSign.push(from.signatureId || from.privateKey);
}
return privateKeysToSign;
};
exports.addInputsPrivateKeys = addInputsPrivateKeys;
const addUtxoInputs = async (transactionBuilder, fromUTXOs) => {
let amount = new bignumber_js_1.default(0);
const privateKeysToSign = [];
for (const utxo of fromUTXOs) {
const transaction = await ada_1.adaGetTransaction(utxo.txHash);
const output = transaction.outputs.find(output => output.index === utxo.index);
if (output) {
const value = output.value;
amount = amount.plus(value);
exports.addInput(transactionBuilder, Object.assign({ value }, utxo), output.address);
privateKeysToSign.push(utxo.signatureId || utxo.privateKey);
}
}
return { amount, privateKeysToSign };
};
exports.addUtxoInputs = addUtxoInputs;
const addOutputLovelace = (transactionBuilder, address, amount) => {
transactionBuilder.add_output(cardano_serialization_lib_nodejs_1.TransactionOutput.new(cardano_serialization_lib_nodejs_1.Address.from_bech32(address), cardano_serialization_lib_nodejs_1.Value.new(cardano_serialization_lib_nodejs_1.BigNum.from_str(amount))));
};
exports.addOutputLovelace = addOutputLovelace;
const addOutputAda = (transactionBuilder, address, amount) => {
const amountLovelace = exports.adaToLovelace(amount);
exports.addOutputLovelace(transactionBuilder, address, amountLovelace);
return amountLovelace;
};
exports.addOutputAda = addOutputAda;
const addInput = (transactionBuilder, utxo, address) => {
transactionBuilder.add_input(cardano_serialization_lib_nodejs_1.Address.from_bech32(address), cardano_serialization_lib_nodejs_1.TransactionInput.new(cardano_serialization_lib_nodejs_1.TransactionHash.from_bytes(Buffer.from(utxo.txHash, 'hex')), utxo.index), cardano_serialization_lib_nodejs_1.Value.new(cardano_serialization_lib_nodejs_1.BigNum.from_str(utxo.value)));
};
exports.addInput = addInput;
const initTransactionBuilder = async () => {
const txBuilder = cardano_serialization_lib_nodejs_1.TransactionBuilder.new(cardano_serialization_lib_nodejs_1.LinearFee.new(cardano_serialization_lib_nodejs_1.BigNum.from_str('44'), cardano_serialization_lib_nodejs_1.BigNum.from_str('155381')), cardano_serialization_lib_nodejs_1.BigNum.from_str('1000000'), cardano_serialization_lib_nodejs_1.BigNum.from_str('500000000'), cardano_serialization_lib_nodejs_1.BigNum.from_str('2000000'));
const { tip: { slotNo } } = await ada_1.adaGetBlockChainInfo();
txBuilder.set_ttl(slotNo + 50000);
return txBuilder;
};
exports.initTransactionBuilder = initTransactionBuilder;
const createWitnesses = (transactionBody, transferAdaBlockchain) => {
const { fromAddress, fromUTXO } = transferAdaBlockchain;
const txHash = cardano_serialization_lib_nodejs_1.hash_transaction(transactionBody);
const vKeyWitnesses = cardano_serialization_lib_nodejs_1.Vkeywitnesses.new();
if (fromAddress) {
for (const address of fromAddress) {
if (address.privateKey) {
exports.makeWitness(address.privateKey, txHash, vKeyWitnesses);
}
}
}
else if (fromUTXO) {
for (const utxo of fromUTXO) {
if (utxo.privateKey) {
exports.makeWitness(utxo.privateKey, txHash, vKeyWitnesses);
}
}
}
else {
throw new Error('No private key for witness found.');
}
const witnesses = cardano_serialization_lib_nodejs_1.TransactionWitnessSet.new();
witnesses.set_vkeys(vKeyWitnesses);
return witnesses;
};
exports.createWitnesses = createWitnesses;
const makeWitness = (privateKey, txHash, vKeyWitnesses) => {
const privateKeyCardano = cardano_serialization_lib_nodejs_1.Bip32PrivateKey.from_128_xprv(Buffer.from(privateKey, 'hex')).to_raw_key();
vKeyWitnesses.add(cardano_serialization_lib_nodejs_1.make_vkey_witness(txHash, privateKeyCardano));
};
exports.makeWitness = makeWitness;
const processFeeAndRest = async (transactionBuilder, fromAmountInLovelace, toAmountInLovelace, transferAdaBlockchain) => {
const feeInLovelace = new bignumber_js_1.default(exports.adaToLovelace((transferAdaBlockchain === null || transferAdaBlockchain === void 0 ? void 0 : transferAdaBlockchain.fee) || 0));
const changeAddress = transferAdaBlockchain.changeAddress;
if (feeInLovelace.isEqualTo(0)) {
exports.addChangeIfNeeded(transactionBuilder, changeAddress);
}
else {
const changeInLovelace = fromAmountInLovelace.minus(toAmountInLovelace).minus(feeInLovelace);
if (changeInLovelace.gt(0))
exports.addOutputLovelace(transactionBuilder, changeAddress, changeInLovelace.toString());
exports.addFee(transactionBuilder, feeInLovelace);
}
};
exports.processFeeAndRest = processFeeAndRest;
const signTransaction = (transactionBuilder, transferAdaBlockchain, privateKeysToSign) => {
const txBody = transactionBuilder.build();
const { fromAddress, fromUTXO } = transferAdaBlockchain;
if ((fromAddress && fromAddress[0].signatureId) || (fromUTXO && fromUTXO[0].signatureId)) {
return JSON.stringify({ txData: transferAdaBlockchain, privateKeysToSign });
}
const witnesses = exports.createWitnesses(txBody, transferAdaBlockchain);
return Buffer.from(cardano_serialization_lib_nodejs_1.Transaction.new(txBody, witnesses).to_bytes()).toString('hex');
};
exports.signTransaction = signTransaction;
const lovelaceToAda = (lovelace) => new bignumber_js_1.default(lovelace).dividedBy(1000000).toFixed(8, bignumber_js_1.default.ROUND_FLOOR).toString();
exports.lovelaceToAda = lovelaceToAda;
const adaToLovelace = (ada) => new bignumber_js_1.default(ada).times(1000000).toString();
exports.adaToLovelace = adaToLovelace;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zYWN0aW9uL2FkYS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSwrRkFNaUQ7QUFDakQsZ0VBQW9DO0FBQ3BDLDJDQUFzRztBQUN0Ryw4Q0FBaUQ7QUFDakQsb0NBQThHO0FBRTlHOzs7O0dBSUc7QUFDSSxNQUFNLHFCQUFxQixHQUFHLEtBQUssRUFBRSxxQkFBNEMsRUFBRSxFQUFFO0lBQzFGLE1BQU0sb0JBQVksQ0FBQyxxQkFBcUIsRUFBRSw2QkFBcUIsQ0FBQyxDQUFBO0lBQ2hFLE1BQU0sU0FBUyxHQUFHLE1BQU0sOEJBQXNCLEVBQUUsQ0FBQTtJQUNoRCxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcscUJBQXFCLENBQUE7SUFFcEMsTUFBTSxFQUFFLGlCQUFpQixFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsR0FBRyxNQUFNLGlCQUFTLENBQUMsU0FBUyxFQUFFLHFCQUFxQixDQUFDLENBQUE7SUFDbkcsTUFBTSxRQUFRLEdBQUcsa0JBQVUsQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUFDLENBQUE7SUFDMUMsTUFBTSx5QkFBaUIsQ0FBQyxTQUFTLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxxQkFBcUIsQ0FBQyxDQUFBO0lBRS9FLE9BQU8sdUJBQWUsQ0FBQyxTQUFTLEVBQUUscUJBQXFCLEVBQUUsaUJBQWlCLENBQUMsQ0FBQTtBQUM3RSxDQUFDLENBQUE7QUFWWSxRQUFBLHFCQUFxQix5QkFVakM7QUFFRDs7Ozs7R0FLRztBQUNJLE1BQU0sa0JBQWtCLEdBQUcsS0FBSyxFQUFFLElBQTJCLEVBQUUsRUFBRTtJQUN0RSxPQUFPLGtCQUFZLENBQUMsTUFBTSw2QkFBcUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFBO0FBQ3hELENBQUMsQ0FBQTtBQUZZLFFBQUEsa0JBQWtCLHNCQUU5QjtBQUVEOzs7OztHQUtHO0FBQ0ksTUFBTSxxQkFBcUIs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