UNPKG

navskit

Version:

Deploy TypeScript logic on Ethereum. Includes core library, CLI tools, and utilities.

109 lines (108 loc) 3.98 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Tools = void 0; exports.percentToWad = percentToWad; const viem_1 = require("viem"); const deploy_1 = require("./deploy"); const protocol_kit_1 = __importDefault(require("@safe-global/protocol-kit")); const deploy_2 = require("./deploy"); /** * Convert a percentage (e.g. 50.3 for 50.3 %) to an 18-decimal “wad”. * * EigenLayer’s slashing code treats 1 wad = 1 × 10⁻¹⁸ of “one”. * Because 100 % == 1.0, the conversion is: * * wad = (percent / 100) × 1e18 = percent × 1e16 * * The result must be an integer, so we use BigInt. * * @param {number|string} pct A number in the range 0 … 100 (inclusive). * @returns {bigint} The wad-scaled integer (0 … 1e18). */ function percentToWad(pct) { const n = Number(pct); if (!Number.isFinite(n)) throw new TypeError('percent must be a finite number'); if (n < 0 || n > 100) throw new RangeError('percent must be between 0 and 100'); // n * 1e16 may exceed 2⁵³-1, so run the math in strings -> BigInt const wad = BigInt(Math.round(n * 1e14)) * 10000n; // 1e14 × 1e4 = 1e18 return wad; } class Tools { toolsParams; calls = []; constructor(toolsParams) { this.toolsParams = toolsParams; this.calls = []; } slash(operator, percentageOutOf100, description) { if (percentageOutOf100 < 0 || percentageOutOf100 > 100) { throw new Error('invalid percentage.'); } this.calls.push({ to: process.env.ALLOCATION_MANAGER, value: (0, viem_1.toHex)(0), data: (0, viem_1.encodeFunctionData)({ abi: deploy_1.AllocationManagerAbi, functionName: 'slashOperator', args: [ this.toolsParams.avs, { operator, operatorSetId: deploy_2.DEFAULT_OPERATOR_SET_ID, strategies: [deploy_1.Addresses['11155111'].Strategy], wadsToSlash: [percentToWad(percentageOutOf100)], description } ] }) }); } eject(operator) { this.calls.push({ to: process.env.ALLOCATION_MANAGER, value: (0, viem_1.toHex)(0), data: (0, viem_1.encodeFunctionData)({ abi: deploy_1.AllocationManagerAbi, functionName: 'deregisterFromOperatorSets', args: [ { operator, avs: this.toolsParams.avs, operatorSetIds: [deploy_2.DEFAULT_OPERATOR_SET_ID] } ] }) }); } async getTransaction() { if (this.calls.length === 0) { return; } const mapCall = (call) => { return { target: call.to, allowFailure: false, callData: call.data }; }; const to = deploy_1.Addresses[11155111].NavsMultisig; const value = (0, viem_1.toHex)(0); const data = (0, viem_1.encodeFunctionData)({ abi: deploy_1.Multicall3Abi, functionName: 'aggregate3', args: [ [ mapCall(this.calls[0]), ...this.calls.map(mapCall) ] ] }); // TODO: what happens if gas parameters are different across different runs?... const safe = await protocol_kit_1.default.init({ provider: process.env.NODE_SEPOLIA ?? 'https://rpc.sepolia.ethpandaops.io', safeAddress: deploy_1.Addresses[11155111].NavsMultisig }); const txn = await safe.createTransaction({ transactions: [ { to, value, data } ] }); return [txn, await safe.getTransactionHash(txn)]; } } exports.Tools = Tools;