@flarenetwork/flare-stake-tool
Version:
Utilities for staking on the Flare network
234 lines • 10.3 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._getAccount = _getAccount;
exports.moveCP = moveCP;
exports.exportCP = exportCP;
exports.importCP = importCP;
exports.movePC = movePC;
exports.exportPC = exportPC;
exports.importPC = importPC;
exports.addDelegator = addDelegator;
exports.addValidator = addValidator;
exports.internalTransfer = internalTransfer;
exports._checkNumberOfStakes = _checkNumberOfStakes;
exports._checkNodeId = _checkNodeId;
exports.submitTxHex = submitTxHex;
const chain = __importStar(require("./chain"));
const pubk = __importStar(require("./pubk"));
const txs = __importStar(require("./txs"));
const bn_js_1 = __importDefault(require("bn.js"));
const utils = __importStar(require("../utils"));
const TX_EFFECT_TIMEOUT = 10000;
const TX_EFFECT_DELAY = 500;
function _getAccount(network, publicKey) {
return {
network,
publicKey: pubk.normalizePublicKey(publicKey),
cAddress: pubk.publicKeyToCAddress(publicKey),
pAddress: 'P-' + pubk.publicKeyToPAddress(network, publicKey)
};
}
// transactions
async function moveCP(exportParams, importParams, sign, presubmit) {
if (exportParams.network !== importParams.network ||
exportParams.publicKey !== importParams.publicKey) {
throw new Error('Inconsistent export and import parameters');
}
await exportCP(exportParams, sign, presubmit);
return await importCP(importParams, sign, presubmit);
}
async function exportCP(params, sign, presubmit) {
let exportTx = await _exportCP(params, sign, presubmit);
if (exportTx.submitted && !exportTx.confirmed) {
throw new Error(`Export transaction ${exportTx.id} on C-chain not confirmed (status is ${exportTx.status})`);
}
return exportTx.id;
}
async function importCP(params, sign, presubmit) {
let importTx = await _importCP(params, sign, presubmit);
if (importTx.submitted && !importTx.confirmed) {
throw new Error(`Import transaction ${importTx.id} on P-chain not confirmed (status is ${importTx.status})`);
}
return importTx.id;
}
async function _exportCP(params, sign, presubmit) {
let account = _getAccount(params.network, params.publicKey);
let unsignedTx = await txs.buildExportCTx(account, params);
let balance = await chain.getCPBalance(account.network, account.pAddress);
let tx = await _signAndSubmitTx(unsignedTx, sign, presubmit);
if (tx.submitted) {
await _waitForBalanceChange(balance, () => chain.getCPBalance(account.network, account.pAddress));
}
return tx;
}
async function _importCP(params, sign, presubmit) {
let account = _getAccount(params.network, params.publicKey);
let unsignedTx = await txs.buildImportPTx(account, params);
let balance = await chain.getPBalance(account.network, account.pAddress);
let tx = await _signAndSubmitTx(unsignedTx, sign, presubmit);
if (tx.submitted) {
await _waitForBalanceChange(balance, () => chain.getPBalance(account.network, account.pAddress));
}
return tx;
}
async function movePC(exportParams, importParams, sign, presubmit) {
if (exportParams.network !== importParams.network ||
exportParams.publicKey !== importParams.publicKey) {
throw new Error('Inconsistent export and import parameters');
}
await exportPC(exportParams, sign, presubmit);
return await importPC(importParams, sign, presubmit);
}
async function exportPC(params, sign, presubmit) {
let exportTx = await _exportPC(params, sign, presubmit);
if (exportTx.submitted && !exportTx.confirmed) {
throw new Error(`Export transaction ${exportTx.id} on P-chain not confirmed (status is ${exportTx.status})`);
}
return exportTx.id;
}
async function importPC(params, sign, presubmit) {
let importTx = await _importPC(params, sign, presubmit);
if (importTx.submitted && !importTx.confirmed) {
throw new Error(`Import transaction ${importTx.id} on C-chain not confirmed (status is ${importTx.status})`);
}
return importTx.id;
}
async function _exportPC(params, sign, presubmit) {
let account = _getAccount(params.network, params.publicKey);
let unsignedTx = await txs.buildExportPTx(account, params);
let balance = await chain.getPCBalance(account.network, account.pAddress);
let tx = await _signAndSubmitTx(unsignedTx, sign, presubmit);
if (tx.submitted) {
await _waitForBalanceChange(balance, () => chain.getPCBalance(account.network, account.pAddress));
}
return tx;
}
async function _importPC(params, sign, presubmit) {
let account = _getAccount(params.network, params.publicKey);
let unsignedTx = await txs.buildImportCTx(account, params);
let balance = await chain.getCBalance(account.network, account.cAddress);
let tx = await _signAndSubmitTx(unsignedTx, sign, presubmit);
if (tx.submitted) {
await _waitForBalanceChange(balance, () => chain.getCBalance(account.network, account.cAddress));
}
return tx;
}
async function _waitForBalanceChange(startBalance, balance) {
await utils.waitWhile(async () => {
return (await balance()).gt(startBalance);
}, TX_EFFECT_TIMEOUT, TX_EFFECT_DELAY);
}
async function addDelegator(params, sign, validate, presubmit) {
let account = _getAccount(params.network, params.publicKey);
let stakes = await chain.getPStakes(account.network);
if (validate) {
await _checkNumberOfStakes(account, params.nodeId, params.startTime, params.endTime, stakes);
await _checkNodeId(account, params.nodeId, stakes);
}
let unsignedTx = await txs.buildAddDelegatorTx(account, params);
let tx = await _signAndSubmitTx(unsignedTx, sign, presubmit);
if (tx.submitted && !tx.confirmed) {
throw new Error(`Delegation transaction ${tx.id} on P-chain not confirmed (status is ${tx.status})`);
}
// TODO: possibly redundant (if address delegated to multiple nodes it can find the existing stake)
// fix it ore remove it?
if (tx.submitted) {
await _waitForStake(account, tx.id);
}
return tx.id;
}
async function addValidator(params, sign, validate, presubmit) {
let account = _getAccount(params.network, params.publicKey);
if (validate) {
await _checkNumberOfStakes(account, params.nodeId, params.startTime, params.endTime);
}
let unsignedTx = await txs.buildAddValidatorTx(account, params);
let tx = await _signAndSubmitTx(unsignedTx, sign, presubmit);
if (tx.submitted && !tx.confirmed) {
throw new Error(`Staking transaction ${tx.id} on P-chain not confirmed (status is ${tx.status})`);
}
if (tx.submitted) {
await _waitForStake(account, tx.id);
}
return tx.id;
}
async function internalTransfer(params, sign, presubmit) {
const account = _getAccount(params.network, params.publicKey);
const unsignedTx = await txs.buildBaseTx(account, params);
let tx = await _signAndSubmitTx(unsignedTx, sign, presubmit);
if (tx.submitted && !tx.confirmed) {
throw new Error(`Transfer transaction ${tx.id} on P-chain not confirmed (status is ${tx.status})`);
}
return tx.id;
}
async function _checkNumberOfStakes(account, nodeId, startTime, endTime, stakes) {
let allStakesOf = await chain.getPStakesOf(account.network, account.pAddress, stakes);
let stakesOf = allStakesOf.filter((s) => new bn_js_1.default(s.endTime.getTime() / 1e3).gte(startTime) &&
new bn_js_1.default(s.startTime.getTime() / 1e3).lte(endTime));
let nodeIds = Array.from(new Set(stakesOf.map((s) => s.nodeId.toLowerCase())));
if (nodeIds.length >= 3 && !nodeIds.includes(nodeId.toLowerCase())) {
throw new Error(`In the selected time period the account already has active stakes to ${nodeIds.length} different nodes`);
}
}
async function _checkNodeId(account, nodeId, stakes) {
if (!stakes) {
stakes = await chain.getPStakes(account.network);
}
let nodeIds = stakes.filter((s) => s.type === 'validator').map((s) => s.nodeId);
if (!nodeIds.includes(nodeId)) {
throw new Error(`Unknown node id`);
}
}
async function _waitForStake(account, txId) {
await utils.waitWhile(async () => (await chain.getPStakesOf(account.network, account.pAddress)).some((x) => x.txId === txId), TX_EFFECT_TIMEOUT, TX_EFFECT_DELAY);
}
async function _signAndSubmitTx(unsignedTx, sign, presubmit) {
return txs.signAndSubmitTx(unsignedTx, sign, presubmit);
}
async function submitTxHex(txHex) {
let result = await txs.submitTxHex(txHex);
if (result == null) {
throw new Error(`Transaction can not be decoded`);
}
else if (!result[2]) {
throw new Error(`Transaction ${result[0]} not confirmed (status is ${result[1]})`);
}
return result[0];
}
//# sourceMappingURL=index.js.map