@flarenetwork/flare-stake-tool
Version:
Utilities for staking on the Flare network
759 lines • 31.8 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildExportCTx = buildExportCTx;
exports.buildImportCTx = buildImportCTx;
exports.buildImportPTx = buildImportPTx;
exports.buildExportPTx = buildExportPTx;
exports.buildAddDelegatorTx = buildAddDelegatorTx;
exports.buildAddValidatorTx = buildAddValidatorTx;
exports.buildBaseTx = buildBaseTx;
exports.buildEvmTx = buildEvmTx;
exports.finalizeAndConvertEvmTx = finalizeAndConvertEvmTx;
exports.signAndSubmitTx = signAndSubmitTx;
exports.submitTxHex = submitTxHex;
exports.getStakeTransaction = getStakeTransaction;
const utils = __importStar(require("../utils"));
const settings = __importStar(require("../settings"));
const chain = __importStar(require("./chain"));
const pubk = __importStar(require("./pubk"));
const bn_js_1 = __importDefault(require("bn.js"));
const flarejs_1 = require("@flarenetwork/flarejs");
const tx_1 = require("@ethereumjs/tx");
const rlp_1 = require("@ethereumjs/rlp");
const common_1 = require("@ethereumjs/common");
const context_1 = require("./context");
const TX_WAIT_MS = 15000;
const TX_CHECK_MS = 1000;
async function buildExportCTx(account, params) {
const importFeeReservation = await chain.getPTxDefaultFee(account.network);
if (!params.exportFee || params.exportFee.isZero()) {
params.exportFee = await _getExportCTxFee(account, params.amount, importFeeReservation);
}
const unsignedTx = await _getUnsignedExportCTx(account, params.amount, params.exportFee, importFeeReservation);
const unsignedTxHex = _unsignedTxToHex(unsignedTx);
return {
txDetails: {
...params,
importFeeReservation,
unsignedTxHex,
},
unsignedTx,
};
}
async function _getExportCTxFee(account, amount, importFeeReservation) {
const baseFee = await chain.getCTxBaseFee(account.network);
const tx = await _getUnsignedExportCTx(account, amount, new bn_js_1.default(0), importFeeReservation);
const cost = new bn_js_1.default(flarejs_1.utils.costCorethTx(tx).toString());
return baseFee.mul(cost);
}
async function _getUnsignedExportCTx(account, amount, exportFee, importFeeReservation) {
const context = await (0, context_1.getContext)(account.network);
const cAddress = flarejs_1.utils.hexToBuffer(account.cAddress);
const pAddress = flarejs_1.utils.bech32ToBytes(account.pAddress);
const nonce = await chain.numberOfCTxs(account.network, account.cAddress);
return flarejs_1.evm.newExportTx(context, BigInt(amount.add(importFeeReservation).toString()), context.pBlockchainID, cAddress, [pAddress], BigInt(exportFee.toString()), BigInt(nonce));
}
async function buildImportCTx(account, params) {
if (!params.importFee || params.importFee.isZero()) {
params.importFee = await _getImportCTxFee(account);
}
const unsignedTx = await _getUnsignedImportCTx(account, params.importFee);
const amount = await chain.getPCBalance(account.network, account.pAddress);
const unsignedTxHex = _unsignedTxToHex(unsignedTx);
return {
txDetails: { ...params, amount, unsignedTxHex },
unsignedTx,
};
}
async function _getImportCTxFee(account) {
const baseFee = await chain.getCTxBaseFee(account.network);
const tx = await _getUnsignedImportCTx(account, new bn_js_1.default(0));
const cost = new bn_js_1.default(flarejs_1.utils.costCorethTx(tx).toString());
return baseFee.mul(cost);
}
async function _getUnsignedImportCTx(account, importFee) {
const context = await (0, context_1.getContext)(account.network);
const pAddressString = `C-${account.pAddress.slice(2)}`;
const pAddress = flarejs_1.utils.bech32ToBytes(pAddressString);
const cAddress = flarejs_1.utils.hexToBuffer(account.cAddress);
const evmapi = new flarejs_1.evm.EVMApi(settings.URL[account.network]);
const { utxos } = await evmapi.getUTXOs({
addresses: [pAddressString],
sourceChain: "P",
});
return flarejs_1.evm.newImportTx(context, cAddress, [pAddress], utxos, context.pBlockchainID, BigInt(importFee.toString()));
}
async function buildImportPTx(account, params) {
const context = await (0, context_1.getContext)(account.network);
const pvmapi = new flarejs_1.pvm.PVMApi(settings.URL[account.network]);
const feeState = await pvmapi.getFeeState();
const pAddressString = account.pAddress;
const pAddress = flarejs_1.utils.bech32ToBytes(pAddressString);
const { utxos } = await pvmapi.getUTXOs({
addresses: [pAddressString],
sourceChain: "C",
});
const isEtnaForkActive = await (0, context_1.isEtnaActive)(account.network);
let unsignedTx;
if (isEtnaForkActive) {
unsignedTx = flarejs_1.pvm.e.newImportTx({
feeState,
sourceChainId: context.cBlockchainID,
utxos,
fromAddressesBytes: [pAddress],
toAddressesBytes: [pAddress],
}, context);
}
else {
unsignedTx = flarejs_1.pvm.newImportTx(context, context.cBlockchainID, utxos, [pAddress], [pAddress]);
}
const amount = await chain.getCPBalance(account.network, account.pAddress);
const importFee = await chain.getPTxDefaultFee(account.network);
const unsignedTxHex = _unsignedTxToHex(unsignedTx);
return {
txDetails: {
...params,
amount,
importFee,
unsignedTxHex,
},
unsignedTx,
};
}
async function buildExportPTx(account, params) {
const context = await (0, context_1.getContext)(account.network);
const pvmapi = new flarejs_1.pvm.PVMApi(settings.URL[account.network]);
const feeState = await pvmapi.getFeeState();
const pAddressString = account.pAddress;
const pAddress = flarejs_1.utils.bech32ToBytes(pAddressString);
const isEtnaForkActive = await (0, context_1.isEtnaActive)(account.network);
const exportFee = await chain.getPTxDefaultFee(account.network);
let amount = params.amount;
if (!amount || amount.isZero()) {
amount = (await chain.getPBalance(account.network, account.pAddress)).sub(exportFee);
}
if (amount.lte(new bn_js_1.default(0))) {
throw new Error("Export amount is smaller than or equal to zero");
}
const { utxos } = await pvmapi.getUTXOs({ addresses: [pAddressString] });
const output = flarejs_1.TransferableOutput.fromNative(context.avaxAssetID, BigInt(amount.toString()), [pAddress]);
let unsignedTx;
if (isEtnaForkActive) {
unsignedTx = flarejs_1.pvm.e.newExportTx({
feeState,
destinationChainId: context.cBlockchainID,
fromAddressesBytes: [pAddress],
utxos,
outputs: [output],
}, context);
}
else {
unsignedTx = flarejs_1.pvm.newExportTx(context, context.cBlockchainID, [pAddress], utxos, [output]);
}
const unsignedTxHex = _unsignedTxToHex(unsignedTx);
return {
txDetails: { ...params, exportFee, unsignedTxHex },
unsignedTx,
};
}
async function buildAddDelegatorTx(account, params) {
const context = await (0, context_1.getContext)(account.network);
const pvmapi = new flarejs_1.pvm.PVMApi(settings.URL[account.network]);
const feeState = await pvmapi.getFeeState();
const pAddressString = account.pAddress;
const pAddress = flarejs_1.utils.bech32ToBytes(pAddressString);
const { utxos } = await pvmapi.getUTXOs({ addresses: [pAddressString] });
const isEtnaForkActive = await (0, context_1.isEtnaActive)(account.network);
let unsignedTx;
if (isEtnaForkActive) {
unsignedTx = flarejs_1.pvm.e.newAddPermissionlessDelegatorTx({
feeState,
utxos,
fromAddressesBytes: [pAddress],
nodeId: params.nodeId,
subnetId: flarejs_1.networkIDs.PrimaryNetworkID.toString(),
start: BigInt(params.startTime.toString()),
end: BigInt(params.endTime.toString()),
weight: BigInt(params.amount.toString()),
rewardAddresses: [pAddress],
}, context);
}
else {
unsignedTx = flarejs_1.pvm.newAddPermissionlessDelegatorTx(context, utxos, [pAddress], params.nodeId, flarejs_1.networkIDs.PrimaryNetworkID.toString(), BigInt(params.startTime.toString()), BigInt(params.endTime.toString()), BigInt(params.amount.toString()), [pAddress]);
}
const unsignedTxHex = _unsignedTxToHex(unsignedTx);
return {
txDetails: { ...params, unsignedTxHex },
unsignedTx,
};
}
async function buildAddValidatorTx(account, params) {
const context = await (0, context_1.getContext)(account.network);
const pvmapi = new flarejs_1.pvm.PVMApi(settings.URL[account.network]);
const feeState = await pvmapi.getFeeState();
const pAddressString = account.pAddress;
const pAddress = flarejs_1.utils.bech32ToBytes(pAddressString);
const { utxos } = await pvmapi.getUTXOs({ addresses: [pAddressString] });
const isEtnaForkActive = await (0, context_1.isEtnaActive)(account.network);
let unsignedTx;
if (isEtnaForkActive) {
unsignedTx = flarejs_1.pvm.e.newAddPermissionlessValidatorTx({
feeState,
utxos,
delegatorRewardsOwner: [pAddress],
nodeId: params.nodeId,
subnetId: flarejs_1.networkIDs.PrimaryNetworkID.toString(),
start: BigInt(params.startTime.toString()),
end: BigInt(params.endTime.toString()),
weight: BigInt(params.amount.toString()),
rewardAddresses: [pAddress],
fromAddressesBytes: [pAddress],
shares: params.delegationFee,
changeAddressesBytes: [pAddress],
publicKey: params.popBLSPublicKey,
signature: params.popBLSSignature,
}, context);
}
else {
unsignedTx = flarejs_1.pvm.newAddPermissionlessValidatorTx(context, utxos, [pAddress], params.nodeId, flarejs_1.networkIDs.PrimaryNetworkID.toString(), BigInt(params.startTime.toString()), BigInt(params.endTime.toString()), BigInt(params.amount.toString()), [pAddress], [pAddress], params.delegationFee, undefined, 1, 0n, params.popBLSPublicKey, params.popBLSSignature);
}
const unsignedTxHex = _unsignedTxToHex(unsignedTx);
return {
txDetails: { ...params, unsignedTxHex },
unsignedTx,
};
}
async function buildBaseTx(account, params) {
const context = await (0, context_1.getContext)(account.network);
const pvmapi = new flarejs_1.pvm.PVMApi(settings.URL[account.network]);
const feeState = await pvmapi.getFeeState();
const pAddressString = account.pAddress;
const pAddressBytes = flarejs_1.utils.bech32ToBytes(pAddressString);
const { utxos } = await pvmapi.getUTXOs({ addresses: [pAddressString] });
const recipientAddressBytes = flarejs_1.utils.bech32ToBytes(params.recipientAddress);
const isEtnaForkActive = await (0, context_1.isEtnaActive)(account.network);
let unsignedTx;
if (isEtnaForkActive) {
unsignedTx = flarejs_1.pvm.e.newBaseTx({
feeState,
fromAddressesBytes: [pAddressBytes],
utxos,
outputs: [flarejs_1.TransferableOutput.fromNative(context.avaxAssetID, BigInt(params.amount), [recipientAddressBytes])],
}, context);
}
else {
unsignedTx = flarejs_1.pvm.newBaseTx(context, [pAddressBytes], utxos, [
flarejs_1.TransferableOutput.fromNative(context.avaxAssetID, BigInt(params.amount), [recipientAddressBytes]),
]);
}
const unsignedTxHex = _unsignedTxToHex(unsignedTx);
return {
txDetails: { ...params, unsignedTxHex },
unsignedTx,
};
}
function _unsignedTxToHex(unsignedTx) {
return utils.toHex(unsignedTx.toBytes());
}
async function buildEvmTx(account, params, evmTx) {
const txData = {
from: account.cAddress,
chainId: BigInt(settings.CHAIN_ID[account.network]),
...evmTx,
};
if (!txData.value) {
txData.value = BigInt(0);
}
if (!txData.nonce) {
txData.nonce = await chain.numberOfCTxs(account.network, account.cAddress);
}
if (!txData.maxFeePerGas || !txData.maxPriorityFeePerGas) {
const feeEstimate = await chain.estimateEIP1559Fee(account.network);
txData.maxFeePerGas = feeEstimate[0];
txData.maxPriorityFeePerGas = feeEstimate[1];
}
if (!txData.gasLimit) {
const web3 = chain.getWeb3(account.network);
const estimatedGasLimit = await web3.eth.estimateGas(txData);
txData.gasLimit = (estimatedGasLimit * BigInt(10500)) / BigInt(10000);
}
let unsignedTx;
let unsignedTxHex;
if (params.txType === 0) {
const common = common_1.Common.custom({ chainId: txData.chainId });
const evmLegacyTx = {
from: txData.from,
to: Uint8Array.from(utils.toBuffer(txData.to)),
data: Uint8Array.from(utils.toBuffer(txData.data ?? "")),
value: txData.value,
gasLimit: txData.gasLimit,
gasPrice: txData.maxFeePerGas - txData.maxPriorityFeePerGas,
nonce: txData.nonce,
chainId: txData.chainId,
};
unsignedTx = tx_1.LegacyTransaction.fromTxData(evmLegacyTx, { common });
unsignedTxHex = utils.toHex(rlp_1.RLP.encode(unsignedTx.getMessageToSign()));
}
else if (params.txType === 2) {
const evmEIP1559Tx = {
from: txData.from,
to: Uint8Array.from(utils.toBuffer(txData.to)),
data: Uint8Array.from(utils.toBuffer(txData.data ?? "")),
value: txData.value,
gasLimit: txData.gasLimit,
maxPriorityFeePerGas: txData.maxPriorityFeePerGas,
maxFeePerGas: txData.maxFeePerGas,
nonce: txData.nonce,
chainId: txData.chainId,
};
unsignedTx = tx_1.FeeMarketEIP1559Transaction.fromTxData(evmEIP1559Tx);
unsignedTxHex = utils.toHex(unsignedTx.getMessageToSign());
}
else {
throw new Error("Unsupported transaction type");
}
return {
txDetails: {
...params,
...txData,
unsignedTxHex,
isEvmTx: true,
},
unsignedTx,
};
}
async function finalizeAndConvertEvmTx(from, txHex, txType) {
const tx = tx_1.TransactionFactory.fromSerializedData(utils.toBuffer(txHex));
let chainId;
let accessList;
if (tx instanceof tx_1.LegacyTransaction) {
if (!tx.v) {
throw new Error("Legacy transaction must have v field defined");
}
chainId = tx.v;
accessList = null;
}
else if (tx instanceof tx_1.FeeMarketEIP1559Transaction) {
chainId = tx.chainId;
accessList = tx.accessList;
}
else {
throw new Error("Unsupported EVM transaction type given");
}
const network = _getNetworkFromChainId(chainId);
const to = utils.toHex(tx.to ? tx.to.toString() : "");
const value = tx.value;
const data = utils.toHex(tx.data);
const nonce = await chain.numberOfCTxs(network, from);
const feeEstimate = await chain.estimateEIP1559Fee(network);
const maxFeePerGas = feeEstimate[0];
const maxPriorityFeePerGas = feeEstimate[1];
const web3 = chain.getWeb3(network);
const estimatedGasLimit = await web3.eth.estimateGas({
from,
to,
value,
data,
nonce,
});
const gasLimit = (estimatedGasLimit * BigInt(10500)) / BigInt(10000);
let unsignedTxHex;
if (txType === 0) {
const toArray = Uint8Array.from(utils.toBuffer(to));
const dataArray = Uint8Array.from(utils.toBuffer(data));
const common = common_1.Common.custom({ chainId });
const gasPrice = maxFeePerGas - maxPriorityFeePerGas;
const unsignedTx = tx_1.LegacyTransaction.fromTxData({ to: toArray, value, data: dataArray, nonce, gasLimit, gasPrice }, { common });
unsignedTxHex = utils.toHex(rlp_1.RLP.encode(unsignedTx.getMessageToSign()));
}
else if (txType === 2) {
const toArray = Uint8Array.from(utils.toBuffer(to));
const dataArray = Uint8Array.from(utils.toBuffer(data));
const unsignedTx = tx_1.FeeMarketEIP1559Transaction.fromTxData({
chainId,
to: toArray,
value,
data: dataArray,
nonce,
gasLimit,
maxFeePerGas,
maxPriorityFeePerGas,
accessList,
});
unsignedTxHex = utils.toHex(unsignedTx.getMessageToSign());
}
else {
throw new Error("Unsupported EVM transaction type requested");
}
return unsignedTxHex;
}
async function signAndSubmitTx(unsignedTxData, sign, presubmit) {
let unsignedTxHash;
const unsignedTx = unsignedTxData.unsignedTx;
if (unsignedTx instanceof tx_1.LegacyTransaction) {
unsignedTxHash = utils.toHex(unsignedTx.getHashedMessageToSign());
}
else if (unsignedTx instanceof tx_1.FeeMarketEIP1559Transaction) {
unsignedTxHash = utils.toHex(unsignedTx.getHashedMessageToSign());
}
else if (unsignedTx instanceof flarejs_1.UnsignedTx) {
unsignedTxHash = utils.toHex((0, flarejs_1.messageHashFromUnsignedTx)(unsignedTx));
}
else {
throw new Error(`Can't issue transaction of type ${typeof unsignedTx}`);
}
const signatureResponse = await sign({
...unsignedTxData.txDetails,
unsignedTxHash,
});
let id = "";
let submitted = false;
const network = unsignedTxData.txDetails.network;
const signedTxData = { ...unsignedTxData, signature: "", signedTx: "" };
if (signatureResponse.startsWith("id:")) {
// the transaction was not just signed but also submitted to the network
id = signatureResponse.slice(3);
submitted = true;
}
else {
const signature = utils.toHex(signatureResponse, false);
signedTxData.signature = signature;
let publicKey = pubk.recoverPublicKeyFromMsg(unsignedTxHash, signature);
if (!pubk.equalPublicKey(publicKey, unsignedTxData.txDetails.publicKey)) {
if (unsignedTx instanceof flarejs_1.UnsignedTx) {
publicKey = pubk.recoverPublicKeyFromEthMsg(utils.toHex(unsignedTxHash, false), signature);
if (!pubk.equalPublicKey(publicKey, unsignedTxData.txDetails.publicKey)) {
throw new Error("The public key recovered from the (ETH) signature does not match the expected public key");
}
}
else {
throw new Error("The public key recovered from the signature does not match the expected public key");
}
}
let signedTx;
if (unsignedTx instanceof tx_1.LegacyTransaction || unsignedTx instanceof tx_1.FeeMarketEIP1559Transaction) {
const expandedSignature = _expandSignature(signature);
let tx;
if (unsignedTx instanceof tx_1.LegacyTransaction) {
let v = expandedSignature.recoveryParam;
if (v === 0 || v === 1) {
v += 27;
}
if (v === 27 || v === 28) {
v += 8 + 2 * parseInt(settings.CHAIN_ID[network], 16);
}
tx = tx_1.LegacyTransaction.fromTxData({
...unsignedTx.toJSON(),
v: BigInt(v.toString()),
r: BigInt(expandedSignature.r.toString()),
s: BigInt(expandedSignature.s.toString()),
});
}
else {
const txData = unsignedTx.toJSON();
delete txData.gasPrice;
tx = tx_1.FeeMarketEIP1559Transaction.fromTxData({
...txData,
v: BigInt(expandedSignature.recoveryParam.toString()),
r: BigInt(expandedSignature.r.toString()),
s: BigInt(expandedSignature.s.toString()),
});
}
signedTx = tx.serialize();
}
else if (unsignedTx instanceof flarejs_1.EVMUnsignedTx) {
const compressedPublicKey = pubk.compressPublicKey(Buffer.from("04" + publicKey, "hex"));
const expandedSignature = _expandSignature(signature);
signTxDbg(unsignedTx, [
{
signature: _transformSignature(expandedSignature),
publicKey: compressedPublicKey,
},
]);
signedTx = unsignedTx.getSignedTx().toBytes();
}
else {
// unsignedTx instanceof UnsignedTx
const compressedPublicKey = pubk.compressPublicKey(Buffer.from("04" + publicKey, "hex"));
const expandedSignature = _expandSignature(signature);
signTxDbg(unsignedTx, [
{
signature: _transformSignature(expandedSignature),
// signature: Buffer.from(signature, "hex"),
publicKey: compressedPublicKey,
},
]);
signedTx = unsignedTx.getSignedTx().toBytes();
}
signedTxData.signedTx = utils.toHex(signedTx);
const txSummary = {
network: signedTxData.txDetails.network,
type: signedTxData.txDetails.type,
publicKey: signedTxData.txDetails.publicKey,
unsignedTx: signedTxData.txDetails.unsignedTxHex,
unsignedTxHash: signedTxData.txDetails.unsignedTxHash,
signature: signedTxData.signature,
signedTx: signedTxData.signedTx,
};
if (!presubmit || (await presubmit(txSummary))) {
if (unsignedTx instanceof tx_1.LegacyTransaction || unsignedTx instanceof tx_1.FeeMarketEIP1559Transaction) {
const web3 = chain.getWeb3(network);
id = await _submitEvmTx(web3, signedTxData.signedTx);
}
else {
if (unsignedTx instanceof flarejs_1.EVMUnsignedTx) {
const evmapi = new flarejs_1.evm.EVMApi(settings.URL[network]);
id = (await evmapi.issueTx({
tx: utils.toHex(flarejs_1.utils.addChecksum(signedTx)),
})).txID;
}
else if (unsignedTx instanceof flarejs_1.UnsignedTx) {
const pvmapi = new flarejs_1.pvm.PVMApi(settings.URL[network]);
id = (await pvmapi.issueTx({
tx: utils.toHex(flarejs_1.utils.addChecksum(signedTx)),
})).txID;
}
else {
throw new Error(`Can not issue transaction of type ${typeof unsignedTx}`);
}
}
submitted = true;
}
}
let status = "";
let confirmed = false;
if (submitted) {
let result;
if (unsignedTx instanceof tx_1.LegacyTransaction || unsignedTx instanceof tx_1.FeeMarketEIP1559Transaction) {
result = await _waitForEvmTxConfirmation(chain.getWeb3(network), id);
}
else if (unsignedTx instanceof flarejs_1.EVMUnsignedTx) {
const evmapi = new flarejs_1.evm.EVMApi(settings.URL[network]);
result = await _waitForCTxConfirmation(evmapi, id);
}
else if (unsignedTx instanceof flarejs_1.UnsignedTx) {
const pvmapi = new flarejs_1.pvm.PVMApi(settings.URL[network]);
result = await _waitForPTxConfirmation(pvmapi, id);
}
else {
throw new Error(`Can not issue transaction of type ${typeof unsignedTx}`);
}
status = result[0];
confirmed = result[1];
}
return { ...signedTxData, id, status, submitted, confirmed };
}
function _expandSignature(signature) {
let recoveryParam = parseInt(signature.slice(128, 130), 16);
if (recoveryParam === 27 || recoveryParam === 28) {
recoveryParam -= 27;
}
return {
r: new bn_js_1.default(signature.slice(0, 64), "hex"),
s: new bn_js_1.default(signature.slice(64, 128), "hex"),
recoveryParam: recoveryParam,
};
}
async function submitTxHex(txHex) {
try {
// let ctx = new CTx()
// ctx.fromBuffer(utils.toBuffer(txHex) as any)
// let network = _getNetworkFromChainId(ctx.getUnsignedTx().getTransaction().getNetworkID())
// const context = await getContext(network)
// let avajs = chain.getAvalanche(network)
// TODO: obtain network name from ...
const evmapi = new flarejs_1.evm.EVMApi(settings.URL["localflare"]);
const id = await _submitCTx(evmapi, txHex);
const result = await _waitForCTxConfirmation(evmapi, id);
const status = result[0];
const confirmed = result[1];
return [id, status, confirmed];
}
catch (e) {
console.log("Error submitting CTx", e);
}
try {
// let ptx = new PTx()
// ptx.fromBuffer(utils.toBuffer(txHex) as any)
// let network = _getNetworkFromChainId(ptx.getUnsignedTx().getTransaction().getNetworkID())
// let avajs = chain.getAvalanche(network)
const pvmapi = new flarejs_1.pvm.PVMApi(settings.URL["localflare"]);
const id = await _submitPTx(pvmapi, txHex);
const result = await _waitForPTxConfirmation(pvmapi, id);
const status = result[0];
const confirmed = result[1];
return [id, status, confirmed];
}
catch (e) {
console.log("Error submitting PTx", e);
}
try {
const evmTx = tx_1.TransactionFactory.fromSerializedData(utils.toBuffer(txHex));
let chainId;
if (evmTx instanceof tx_1.LegacyTransaction) {
if (!evmTx.v) {
throw new Error("Legacy transaction must have v field defined");
}
chainId = evmTx.v;
}
else {
chainId = evmTx.chainId;
}
const network = _getNetworkFromChainId(chainId);
const web3 = chain.getWeb3(network);
const id = await _submitEvmTx(web3, txHex);
const result = await _waitForEvmTxConfirmation(web3, id);
const status = result[0];
const confirmed = result[1];
return [id, status, confirmed];
}
catch (e) {
console.log("Error submitting EVM Tx", e);
}
return null;
}
async function _submitCTx(evmapi, txHex) {
const { txID } = await evmapi.issueTx({ tx: txHex });
return txID;
}
async function _submitPTx(pvmapi, txHex) {
const { txID } = await pvmapi.issueTx({ tx: txHex });
return txID;
}
async function _submitEvmTx(web3, txHex) {
let id = "";
await web3.eth.sendSignedTransaction(txHex).on("transactionHash", (txHash) => {
id = txHash;
});
return id;
}
async function _waitForCTxConfirmation(evmapi, txId) {
let status = "Unkown";
const start = Date.now();
while (Date.now() - start < TX_WAIT_MS) {
status = (await evmapi.getAtomicTxStatus(txId)).status;
await utils.sleep(TX_CHECK_MS); // wait regardless of status for added safety
if (status === "Accepted" || status === "Rejected") {
break;
}
}
const confirmed = status === "Accepted";
return [status, confirmed];
}
async function _waitForPTxConfirmation(pvmapi, txId) {
let status = "Unkown";
const start = Date.now();
while (Date.now() - start < TX_WAIT_MS) {
status = (await pvmapi.getTxStatus({ txID: txId })).status;
await utils.sleep(TX_CHECK_MS); // wait regardless of status for added safety
if (status === "Committed" || status === "Rejected") {
break;
}
}
const confirmed = status === "Committed";
return [status, confirmed];
}
async function _waitForEvmTxConfirmation(web3, txId) {
let status = "Unkown";
const start = Date.now();
while (Date.now() - start < TX_WAIT_MS) {
let receipt;
try {
receipt = await web3.eth.getTransactionReceipt(txId);
}
catch (e) {
console.log("Error getting transaction receipt", e);
}
if (receipt) {
status = receipt.status === BigInt(1) ? "Confirmed" : "Failed";
break;
}
await utils.sleep(TX_CHECK_MS);
}
const confirmed = status === "Confirmed";
return [status, confirmed];
}
function _getNetworkFromChainId(chainId) {
let network = "";
const chainIdHex = utils.toHex(chainId.toString(16));
for (const entry of Object.entries(settings.CHAIN_ID)) {
if (entry[1] === chainIdHex) {
network = entry[0];
break;
}
}
if (!network) {
throw new Error("Unsupported network");
}
return network;
}
async function getStakeTransaction(network, txId) {
const pvmapi = new flarejs_1.pvm.PVMApi(settings.URL[network]);
const tx = await pvmapi.getTx({ txID: txId });
switch (tx.unsignedTx._type) {
case flarejs_1.TypeSymbols.AddDelegatorTx:
return tx.unsignedTx;
case flarejs_1.TypeSymbols.AddValidatorTx:
return tx.unsignedTx;
case flarejs_1.TypeSymbols.AddPermissionlessDelegatorTx:
return tx.unsignedTx;
case flarejs_1.TypeSymbols.AddPermissionlessValidatorTx:
return tx.unsignedTx;
default:
throw new Error("Not a stake transaction");
}
}
function _transformSignature(sig) {
const recovery = Buffer.alloc(1);
recovery.writeUInt8(sig.recoveryParam, 0);
const r = Buffer.from(sig.r.toArray("be", 32)); //we have to skip native Buffer class, so this is the way
const s = Buffer.from(sig.s.toArray("be", 32)); //we have to skip native Buffer class, so this is the way
return Buffer.concat([r, s, recovery], 65);
}
function signTxDbg(tx, signingData) {
for (const data of signingData) {
const coordinates = tx.getSigIndicesForPubKey(data.publicKey);
if (coordinates) {
coordinates.forEach(([index, subIndex]) => {
tx.addSignatureAt(data.signature, index, subIndex);
});
}
}
}
//# sourceMappingURL=txs.js.map