@flarenetwork/flare-stake-tool
Version:
Utilities for staking on the Flare network
484 lines • 18 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.toBuffer = toBuffer;
exports.toHex = toHex;
exports.isHex = isHex;
exports.isZeroHex = isZeroHex;
exports.isEqualHex = isEqualHex;
exports.toCB58 = toCB58;
exports.flrToGwei = flrToGwei;
exports.weiToFlr = weiToFlr;
exports.gweiToFlr = gweiToFlr;
exports.gweiToWei = gweiToWei;
exports.weiToGwei = weiToGwei;
exports.weiToGweiCeil = weiToGweiCeil;
exports.dateToDateTimeLocalString = dateToDateTimeLocalString;
exports.timestamp = timestamp;
exports.dateToDateTimeString = dateToDateTimeString;
exports.adjustStartTime = adjustStartTime;
exports.adjustStartTimeForDefi = adjustStartTimeForDefi;
exports.waitWhile = waitWhile;
exports.sleep = sleep;
exports.saveToFile = saveToFile;
exports.copyToClipboard = copyToClipboard;
exports.privateKeyToEncodedPublicKey = privateKeyToEncodedPublicKey;
exports.privateKeyToPublicKey = privateKeyToPublicKey;
exports.decodePublicKey = decodePublicKey;
exports.compressPublicKey = compressPublicKey;
exports.publicKeyToBech32AddressBuffer = publicKeyToBech32AddressBuffer;
exports.publicKeyToBech32AddressString = publicKeyToBech32AddressString;
exports.publicKeyToEthereumAddressString = publicKeyToEthereumAddressString;
exports.validatePublicKey = validatePublicKey;
exports.recoverMessageSigner = recoverMessageSigner;
exports.recoverTransactionSigner = recoverTransactionSigner;
exports.recoverPublicKey = recoverPublicKey;
exports.sleepms = sleepms;
exports.unPrefix0x = unPrefix0x;
exports.prefix0x = prefix0x;
exports.decimalToInteger = decimalToInteger;
exports.integerToDecimal = integerToDecimal;
exports.toBN = toBN;
exports.initCtxJson = initCtxJson;
exports.saveUnsignedTxJson = saveUnsignedTxJson;
exports.readUnsignedTxJson = readUnsignedTxJson;
exports.readSignedTxJson = readSignedTxJson;
exports.addFlagForSentSignedTx = addFlagForSentSignedTx;
exports.isAlreadySentToChain = isAlreadySentToChain;
exports.waitFinalize = waitFinalize;
const bn_js_1 = __importDefault(require("bn.js"));
const web3_utils_1 = require("web3-utils");
const base_1 = require("@scure/base");
function toBuffer(value) {
if (Buffer.isBuffer(value)) {
return value;
}
else {
return Buffer.from(toHex(value, false), 'hex');
}
}
function toHex(value, prefix0x = true) {
let hex;
if (!value) {
value = '0';
}
if (typeof value === 'string') {
if (isHex(value)) {
hex = value;
}
else {
hex = toHex(base_1.base58.decode(value), prefix0x);
}
}
else if (typeof value === 'number') {
hex = value.toString(16);
}
else if (Buffer.isBuffer(value)) {
hex = value.toString('hex');
}
else if (value instanceof Uint8Array || Array.isArray(value)) {
hex = Buffer.from(value).toString('hex');
}
else {
throw new Error('The given value cannot be converted to hex');
}
if (hex.startsWith('0x')) {
return prefix0x ? hex : hex.substring(2);
}
else {
return prefix0x ? `0x${hex}` : hex;
}
}
function isHex(value) {
return /^(0x)?[A-F0-9]+$/i.test(value);
}
function isZeroHex(value) {
return /^0x0+$/.test(value);
}
function isEqualHex(value1, value2) {
return (isHex(value1) && isHex(value2) && toHex(value1).toLowerCase() === toHex(value2).toLowerCase());
}
function toCB58(value) {
return base_1.base58.encode(value);
}
function flrToGwei(flrValue) {
return new bn_js_1.default((0, web3_utils_1.toWei)(flrValue, 'ether')).div(new bn_js_1.default(1e9));
}
function weiToFlr(weiValue) {
return (0, web3_utils_1.fromWei)(weiValue, 'ether');
}
function gweiToFlr(gweiValue, thousandsSeparator = false) {
let value = (0, web3_utils_1.fromWei)(new bn_js_1.default(gweiValue).mul(new bn_js_1.default(1e9)).toString(), 'ether');
if (thousandsSeparator) {
value = parseFloat(value).toLocaleString();
}
return value;
}
function gweiToWei(gweiValue) {
return (gweiValue instanceof bn_js_1.default ? gweiValue : new bn_js_1.default(gweiValue.toString())).mul(new bn_js_1.default(1e9));
}
function weiToGwei(weiValue) {
return (weiValue instanceof bn_js_1.default ? weiValue : new bn_js_1.default(weiValue.toString())).divRound(new bn_js_1.default(1e9));
}
function weiToGweiCeil(weiValue) {
let weiValueBN = weiValue instanceof bn_js_1.default ? weiValue : new bn_js_1.default(weiValue.toString());
let dm = weiValueBN.divmod(new bn_js_1.default(1e9));
return dm.mod.isZero() ? dm.div : dm.div.iaddn(1);
}
function dateToDateTimeLocalString(date) {
return new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000).toISOString().slice(0, -1);
}
function timestamp() {
return dateToDateTimeLocalString(new Date()).replace(/[-:.]+/g, '_');
}
function dateToDateTimeString(date) {
return date.toLocaleString();
}
function adjustStartTime(startTime) {
return Number(startTime) || Math.round(Date.now() / 1000);
}
function adjustStartTimeForDefi(startTime) {
return Number(startTime) || 1;
}
async function waitWhile(condition, timeoutMs, delayMs) {
let start = Date.now();
while (Date.now() - start < timeoutMs) {
if (await condition()) {
break;
}
await sleep(delayMs);
}
}
async function sleep(ms) {
await new Promise((resolve) => setTimeout(resolve, ms));
}
function saveToFile(text, filename) {
let file = new Blob([text], { type: 'text/plain' });
let a = document.createElement('a');
let url = URL.createObjectURL(file);
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
setTimeout(function () {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
async function copyToClipboard(text) {
let result = await navigator.permissions.query({
name: 'clipboard-write'
});
if (result.state === 'granted' || result.state === 'prompt') {
await navigator.clipboard.writeText(text);
}
}
const fs_1 = __importDefault(require("fs"));
const ethutil = __importStar(require("ethereumjs-util"));
const elliptic = __importStar(require("elliptic"));
const bech32_1 = require("bech32");
const forDefi_1 = require("./constants/forDefi");
//////////////////////////////////////////////////////////////////////////////////////////
// public keys and bech32 addresses
const ec = new elliptic.ec('secp256k1');
function privateKeyToEncodedPublicKey(privateKey, compress = true) {
const keyPair = ec.keyFromPrivate(privateKey);
return keyPair.getPublic().encode('hex', compress);
}
function privateKeyToPublicKey(privateKey) {
const keyPair = ec.keyFromPrivate(privateKey).getPublic();
const x = keyPair.getX().toBuffer(undefined, 32);
const y = keyPair.getY().toBuffer(undefined, 32);
return [x, y];
}
function decodePublicKey(publicKey) {
publicKey = unPrefix0x(publicKey);
if (publicKey.length == 128) {
publicKey = '04' + publicKey;
}
const keyPair = ec.keyFromPublic(publicKey, 'hex').getPublic();
const x = keyPair.getX().toBuffer(undefined, 32);
const y = keyPair.getY().toBuffer(undefined, 32);
return [x, y];
}
function compressPublicKey(x, y) {
return Buffer.from(ec
.keyFromPublic({
x: x.toString('hex'),
y: y.toString('hex')
})
.getPublic()
.encode('hex', true), 'hex');
}
function publicKeyToBech32AddressBuffer(x, y) {
const compressed = compressPublicKey(x, y);
return ethutil.ripemd160(ethutil.sha256(compressed), false);
}
function publicKeyToBech32AddressString(publicKey, hrp) {
const [pubX, pubY] = decodePublicKey(publicKey);
const addressBuffer = publicKeyToBech32AddressBuffer(pubX, pubY);
return `${bech32_1.bech32.encode(hrp, bech32_1.bech32.toWords(addressBuffer))}`;
}
function publicKeyToEthereumAddressString(publicKey) {
const [pubX, pubY] = decodePublicKey(publicKey);
const decompressedPubk = Buffer.concat([pubX, pubY]);
const ethAddress = ethutil.publicToAddress(decompressedPubk);
return prefix0x(ethAddress.toString('hex'));
}
function validatePublicKey(publicKey) {
try {
decodePublicKey(publicKey);
return true;
}
catch (error) {
console.error('Invalid public key:', error);
return false;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
// signatures
function recoverMessageSigner(message, signature) {
const messageHash = ethutil.hashPersonalMessage(message);
return recoverTransactionSigner(messageHash, signature);
}
function recoverTransactionSigner(message, signature) {
let split = ethutil.fromRpcSig(signature);
let publicKey = ethutil.ecrecover(message, split.v, split.r, split.s);
let signer = ethutil.pubToAddress(publicKey).toString('hex');
return signer;
}
function recoverPublicKey(message, signature) {
const split = ethutil.fromRpcSig(signature);
return ethutil.ecrecover(message, split.v, split.r, split.s);
}
//export function expandSignature(signature: string): EcdsaSignature {
// let recoveryParam = parseInt(signature.slice(128, 130), 16);
// if (recoveryParam === 27 || recoveryParam === 28) recoveryParam -= 27;
// return {
// r: new BN(signature.slice(0, 64), "hex"),
// s: new BN(signature.slice(64, 128), "hex"),
// recoveryParam: recoveryParam,
// };
//}
//////////////////////////////////////////////////////////////////////////////////////////
// general helper functions
async function sleepms(milliseconds) {
await new Promise((resolve) => {
setTimeout(resolve, milliseconds);
});
}
function unPrefix0x(tx) {
if (!tx) {
return '0x0';
}
return tx.startsWith('0x') ? tx.slice(2) : tx;
}
function prefix0x(hexString) {
if (!hexString) {
return '0x0';
}
return hexString.startsWith('0x') ? hexString : '0x' + unPrefix0x(hexString);
}
function decimalToInteger(dec, offset) {
let ret = dec;
if (ret.includes('.')) {
const split = ret.split('.');
ret = split[0] + split[1].slice(0, offset).padEnd(offset, '0');
}
else {
ret = ret + '0'.repeat(offset);
}
return ret;
}
function integerToDecimal(int, offset) {
if (int === '0') {
return '0';
}
int = int.padStart(offset, '0');
const part1 = int.slice(0, -offset) || '0';
const part2 = int.slice(-offset).replace(/0+$/, '');
return part1 + (part2 === '' ? '' : '.' + part2);
}
//export function parseRelativeTime(time: string): string {
// // assume time starts with now+
// return UnixNow()
// .add(new BN(time.split("+")[1]))
// .toString();
//}
function toBN(num) {
return num ? new bn_js_1.default(num) : undefined;
}
////////////////////////////////////////////////////////////////////////////////////////////
//// key and unsigned/signed transaction storage
//
function initCtxJson(contextFile) {
if (fs_1.default.existsSync('ctx.json')) {
throw new Error('ctx.json already exists');
}
fs_1.default.writeFileSync('ctx.json', JSON.stringify(contextFile, null, 2));
}
function saveUnsignedTxJson(unsignedTxJson, id, dir) {
if (dir === undefined) {
dir = `${forDefi_1.forDefiDirectory}/${forDefi_1.forDefiUnsignedTxnDirectory}`;
}
fs_1.default.mkdirSync(dir, { recursive: true });
const fname = `${dir}/${id}.unsignedTx.json`;
if (fs_1.default.existsSync(fname)) {
throw new Error(`unsignedTx file ${fname} already exists`);
}
const forDefiHash = Buffer.from(unsignedTxJson.signatureRequests[0].message, 'hex').toString('base64');
const unsignedTxJsonForDefi = {
...unsignedTxJson,
forDefiHash: forDefiHash,
};
const serialization = JSON.stringify(unsignedTxJsonForDefi, null, 2);
fs_1.default.writeFileSync(fname, serialization);
return forDefiHash;
}
function readUnsignedTxJson(id) {
const fname = `${forDefi_1.forDefiDirectory}/${forDefi_1.forDefiUnsignedTxnDirectory}/${id}.unsignedTx.json`;
if (!fs_1.default.existsSync(fname)) {
throw new Error(`unsignedTx file ${fname} does not exist`);
}
const serialization = fs_1.default.readFileSync(fname, 'utf-8').toString();
return JSON.parse(serialization);
}
function readSignedTxJson(id) {
const fname = `${forDefi_1.forDefiDirectory}/${forDefi_1.forDefiSignedTxnDirectory}/${id}.signedTx.json`;
if (!fs_1.default.existsSync(fname)) {
throw new Error(`signedTx file ${fname} does not exist`);
}
const serialization = fs_1.default.readFileSync(fname).toString();
const resp = JSON.parse(serialization);
if (!resp.signature) {
throw new Error(`unsignedTx file ${fname} does not contain signature`);
}
return resp;
}
/**
* @description Adds a flag to the signed txn to indicate it has been submitted to the blockchain
* @param {string} id Transaction Id used to create the transaction file
*/
function addFlagForSentSignedTx(id) {
const fname = `${forDefi_1.forDefiDirectory}/${forDefi_1.forDefiSignedTxnDirectory}/${id}.signedTx.json`;
if (!fs_1.default.existsSync(fname)) {
throw new Error(`signedTx file ${fname} does not exist`);
}
const serialization = fs_1.default.readFileSync(fname).toString();
const txObj = JSON.parse(serialization);
txObj.isSentToChain = true;
fs_1.default.writeFileSync(`${forDefi_1.forDefiDirectory}/${forDefi_1.forDefiSignedTxnDirectory}/${id}.signedTx.json`, JSON.stringify(txObj), "utf8");
}
/**
* @description Checks whether the transaction has already been submitted to the blockchain
* @param {string} id Transaction Id used to create the transaction file
* @returns {boolean}
*/
function isAlreadySentToChain(id) {
const fname = `${forDefi_1.forDefiDirectory}/${forDefi_1.forDefiSignedTxnDirectory}/${id}.signedTx.json`;
if (!fs_1.default.existsSync(fname)) {
return false;
}
const serialization = fs_1.default.readFileSync(fname).toString();
const txObj = JSON.parse(serialization);
return !!txObj.isSentToChain;
}
//////////////////////////////////////////////////////////////////////////////////////////
// limiting delegation number
//function countpAddressInDelegation(
// validators: any[],
// pAddressBech32: string,
//): { count: number; validatorNodeIds: string[] } {
// let count = 0;
// const validatorNodeIds = [];
// for (const item of validators) {
// if (item.delegators) {
// for (const delegator of item.delegators) {
// for (const addr of delegator.rewardOwner.addresses) {
// if (addr.toLowerCase() === pAddressBech32.toLowerCase()) {
// count++;
// validatorNodeIds.push(item.nodeID.toLowerCase());
// }
// }
// }
// }
// }
// return { count, validatorNodeIds };
//}
///**
// * @description Count number of p-chain address used for delegation
// * @param {Context} ctx context file
// * @returns number of times p address used in current validators delegation list
// */
//export async function delegationAddressCount(ctx: Context) {
// const current = await ctx.pchain.getCurrentValidators();
// const pending = await ctx.pchain.getPendingValidators();
// const pendingValidtaor = JSON.parse(JSON.stringify(pending));
// const pCurrent = JSON.parse(JSON.stringify(current));
// const currentDelegationDetails = countpAddressInDelegation(
// pCurrent.validators,
// ctx.pAddressBech32!,
// );
// const pendingDelegationDetails = countpAddressInDelegation(
// pendingValidtaor.validators,
// ctx.pAddressBech32!,
// );
// return {
// count: currentDelegationDetails.count + pendingDelegationDetails.count,
// validatorNodeId: [
// ...currentDelegationDetails.validatorNodeIds,
// ...pendingDelegationDetails.validatorNodeIds,
// ],
// };
//}
//
////////////////////////////////////////////////////////////////////////////////////////////
//// finalization
//
async function waitFinalize(ctx, prms) {
if (!ctx.web3 || !ctx.cAddressHex) {
throw new Error('Web3 or contract address is not initialized in the context');
}
const txcount1 = await ctx.web3.eth.getTransactionCount(ctx.cAddressHex);
const resp = await prms;
while ((await ctx.web3.eth.getTransactionCount(ctx.cAddressHex)) == txcount1) {
await sleepms(1000);
}
return resp;
}
//# sourceMappingURL=utils.js.map