@lidofinance/lido-ethereum-sdk
Version:
<div style="display: flex;" align="center"> <h1 align="center">Lido Ethereum SDK</h1> </div>
382 lines • 22.9 kB
JavaScript
;
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LidoSDKRewards = void 0;
const viem_1 = require("viem");
const index_js_1 = require("../common/decorators/index.js");
const sdk_module_js_1 = require("../common/class-primitives/sdk-module.js");
const rewardsEvents_js_1 = require("./abi/rewardsEvents.js");
const constants_js_1 = require("../common/constants.js");
const index_js_2 = require("./subgraph/index.js");
const index_js_3 = require("./subgraph/index.js");
const utils_js_1 = require("./utils.js");
const apr_js_1 = require("../statistics/apr.js");
const index_js_4 = require("../common/index.js");
let LidoSDKRewards = (() => {
var _a;
let _classSuper = sdk_module_js_1.LidoSDKModule;
let _instanceExtraInitializers = [];
let _contractAddressStETH_decorators;
let _contractAddressWithdrawalQueue_decorators;
let _earliestRebaseEventBlock_decorators;
let _getContractStETH_decorators;
let _getRewardsFromChain_decorators;
let _getRewardsFromSubgraph_decorators;
return _a = class LidoSDKRewards extends _classSuper {
async contractAddressStETH() {
return await this.core.getContractAddress(constants_js_1.LIDO_CONTRACT_NAMES.lido);
}
async contractAddressWithdrawalQueue() {
return await this.core.getContractAddress(constants_js_1.LIDO_CONTRACT_NAMES.withdrawalQueue);
}
earliestRebaseEventBlock() {
const block = constants_js_1.EARLIEST_TOKEN_REBASED_EVENT[this.core.chainId];
(0, index_js_4.invariant)(block, `No rebase event for chain:${this.core.chainId}`, index_js_4.ERROR_CODE.NOT_SUPPORTED);
return block;
}
async getContractStETH() {
const address = await this.contractAddressStETH();
return (0, viem_1.getContract)({
address,
abi: rewardsEvents_js_1.rewardsEventsAbi,
client: this.core.publicClient,
});
}
async getRewardsFromChain(props) {
const [{ address, fromBlock, toBlock, includeZeroRebases, includeOnlyRebases }, stethContract, withdrawalQueueAddress,] = await Promise.all([
this.parseProps(props),
this.getContractStETH(),
this.contractAddressWithdrawalQueue(),
]);
const step = props.stepBlock ?? _a.DEFAULT_STEP_BLOCK;
(0, index_js_4.invariantArgument)(step > 0, 'stepBlock must be a positive integer');
const lowerBound = this.earliestRebaseEventBlock();
if (fromBlock < lowerBound)
throw this.core.error({
message: `Cannot index events earlier than first TokenRebased event at block ${lowerBound.toString()}`,
code: index_js_4.ERROR_CODE.NOT_SUPPORTED,
});
const preBlock = fromBlock === 0n ? 0n : fromBlock - 1n;
const [baseBalanceShares, baseTotalEther, baseTotalShares, transferOutEvents, transferInEvents, rebaseEvents,] = await (0, index_js_4.withSDKError)(Promise.all([
stethContract.read.sharesOf([address], {
blockNumber: preBlock,
}),
stethContract.read.getTotalPooledEther({ blockNumber: preBlock }),
stethContract.read.getTotalShares({ blockNumber: preBlock }),
(0, utils_js_1.requestWithBlockStep)(step, fromBlock, toBlock, (fromBlock, toBlock) => stethContract.getEvents.TransferShares({ from: address }, { fromBlock, toBlock })),
(0, utils_js_1.requestWithBlockStep)(step, fromBlock, toBlock, (fromBlock, toBlock) => stethContract.getEvents.TransferShares({ to: address }, { fromBlock, toBlock })),
(0, utils_js_1.requestWithBlockStep)(step, fromBlock, toBlock, (fromBlock, toBlock) => stethContract.getEvents.TokenRebased({}, {
fromBlock,
toBlock,
})),
]), index_js_4.ERROR_CODE.READ_ERROR);
const events = [].concat(transferInEvents, transferOutEvents, rebaseEvents);
events.sort((event1, event2) => {
const block = event1.blockNumber - event2.blockNumber;
if (block === 0n) {
return event1.logIndex - event2.logIndex;
}
return block > 0n ? 1 : -1;
});
let currentTotalEther = baseTotalEther;
let currentTotalShares = baseTotalShares;
const getCurrentStethFromShares = (shares) => (0, utils_js_1.sharesToSteth)(shares, currentTotalEther, currentTotalShares, _a.PRECISION);
const getCurrentShareRate = () => (0, utils_js_1.calcShareRate)(currentTotalEther, currentTotalShares, _a.PRECISION);
const baseBalance = getCurrentStethFromShares(baseBalanceShares);
const baseShareRate = getCurrentShareRate();
let totalRewards = 0n;
let shareRate = baseShareRate;
let prevSharesBalance = baseBalanceShares;
let rewards = events
.map((event) => {
if (event.eventName === 'TransferShares') {
const { from, to, sharesValue } = event.args;
if ((0, viem_1.isAddressEqual)(to, from)) {
return null;
}
let type, changeShares, balanceShares;
if ((0, viem_1.isAddressEqual)(to, address)) {
type = (0, viem_1.isAddressEqual)(from, viem_1.zeroAddress) ? 'submit' : 'transfer_in';
balanceShares = prevSharesBalance + sharesValue;
changeShares = sharesValue;
}
else {
type = (0, viem_1.isAddressEqual)(to, withdrawalQueueAddress)
? 'withdrawal'
: 'transfer_out';
balanceShares = prevSharesBalance - sharesValue;
changeShares = -sharesValue;
}
prevSharesBalance = balanceShares;
return {
type,
balanceShares,
changeShares,
change: getCurrentStethFromShares(changeShares),
balance: getCurrentStethFromShares(balanceShares),
shareRate,
originalEvent: event,
};
}
if (event.eventName === 'TokenRebased') {
const { postTotalEther, postTotalShares } = event.args;
const oldBalance = getCurrentStethFromShares(prevSharesBalance);
currentTotalEther = postTotalEther;
currentTotalShares = postTotalShares;
const newBalance = getCurrentStethFromShares(prevSharesBalance);
shareRate = getCurrentShareRate();
const change = newBalance - oldBalance;
totalRewards += change;
return {
type: 'rebase',
change,
apr: apr_js_1.LidoSDKApr.calculateAprFromRebaseEvent(event.args),
changeShares: 0n,
balance: newBalance,
balanceShares: prevSharesBalance,
shareRate,
originalEvent: event,
};
}
(0, index_js_4.invariant)(false, 'Impossible event');
})
.filter((event) => !!event);
if (includeOnlyRebases) {
rewards = rewards.filter((r) => r.type === 'rebase');
}
if (!includeZeroRebases) {
rewards = rewards.filter((r) => !(r.type === 'rebase' && r.change === 0n));
}
return {
rewards,
baseBalanceShares,
baseShareRate,
baseBalance,
totalRewards,
fromBlock: fromBlock,
toBlock: toBlock,
};
}
async getRewardsFromSubgraph(props) {
const [{ getSubgraphUrl, address, fromBlock, toBlock, includeZeroRebases, includeOnlyRebases, }, withdrawalQueueAddress,] = await Promise.all([
this.parseProps(props),
this.contractAddressWithdrawalQueue(),
]);
const url = getSubgraphUrl(this.core.getSubgraphId(), this.core.chainId);
const step = props.stepEntities ?? _a.DEFAULT_STEP_ENTITIES;
(0, index_js_4.invariantArgument)(step > 0, 'stepEntities must be a positive integer');
const lastIndexedBlock = BigInt((await (0, index_js_2.getLastIndexedBlock)({ url })).number);
const cappedToBlock = lastIndexedBlock < toBlock ? lastIndexedBlock : toBlock;
const preBlock = fromBlock === 0n ? 0n : fromBlock - 1n;
const [transfers, rebases, { transfer: initialTransfer, rebase: initialRebase },] = await (0, index_js_4.withSDKError)(Promise.all([
(0, index_js_2.getTransfers)({
url,
address,
fromBlock,
toBlock: cappedToBlock,
step,
}),
(0, index_js_2.getTotalRewards)({ url, fromBlock, toBlock: cappedToBlock, step }),
(0, index_js_3.getInitialData)({ url, address, block: preBlock }),
]), index_js_4.ERROR_CODE.READ_ERROR);
const events = [].concat(rebases, transfers);
events.sort((event1, event2) => {
const block = BigInt(event1.block) - BigInt(event2.block);
if (block === 0n) {
return Number(event1.logIndex) - Number(event2.logIndex);
}
return block > 0n ? 1 : -1;
});
let prevBalanceShares = 0n;
let prevBalance = 0n;
let baseShareRate = 0;
if (initialTransfer) {
const { to, from, balanceAfterDecrease, balanceAfterIncrease, sharesAfterDecrease, sharesAfterIncrease, } = initialTransfer;
if ((0, viem_1.isAddressEqual)(to, address)) {
prevBalanceShares = BigInt(sharesAfterIncrease);
prevBalance = BigInt(balanceAfterIncrease);
}
else if ((0, viem_1.isAddressEqual)(from, address)) {
prevBalanceShares = BigInt(sharesAfterDecrease);
prevBalance = BigInt(balanceAfterDecrease);
}
}
if (initialRebase) {
const { totalPooledEtherAfter, totalSharesAfter } = initialRebase;
const totalEther = BigInt(totalPooledEtherAfter);
const totalShares = BigInt(totalSharesAfter);
baseShareRate = (0, utils_js_1.calcShareRate)(totalEther, totalShares, _a.PRECISION);
prevBalance = (0, utils_js_1.sharesToSteth)(prevBalanceShares, totalEther, totalShares, _a.PRECISION);
}
const baseBalance = prevBalance;
const baseBalanceShares = prevBalanceShares;
let totalRewards = 0n;
let rewards = events
.map((event) => {
if ('value' in event) {
const { from, to, shares, sharesAfterIncrease, value, balanceAfterDecrease, balanceAfterIncrease, sharesAfterDecrease, totalPooledEther, totalShares, } = event;
let type, changeShares, balanceShares, change, balance;
if ((0, viem_1.isAddressEqual)(to, from)) {
return null;
}
if ((0, viem_1.isAddressEqual)(to, address)) {
type = (0, viem_1.isAddressEqual)(from, viem_1.zeroAddress)
? 'submit'
: 'transfer_in';
changeShares = BigInt(shares);
balanceShares = BigInt(sharesAfterIncrease);
change = BigInt(value);
balance = BigInt(balanceAfterIncrease);
}
else {
type = (0, viem_1.isAddressEqual)(to, withdrawalQueueAddress)
? 'withdrawal'
: 'transfer_out';
balance = BigInt(balanceAfterDecrease);
change = -BigInt(value);
changeShares = -BigInt(shares);
balanceShares = BigInt(sharesAfterDecrease);
}
const shareRate = (0, utils_js_1.calcShareRate)(BigInt(totalPooledEther), BigInt(totalShares), _a.PRECISION);
prevBalance = balance;
prevBalanceShares = balanceShares;
return {
type,
balanceShares,
changeShares,
change,
balance,
shareRate,
originalEvent: event,
};
}
if ('apr' in event) {
const { totalPooledEtherAfter, totalSharesAfter, apr: eventApr, } = event;
const totalEther = BigInt(totalPooledEtherAfter);
const totalShares = BigInt(totalSharesAfter);
const newBalance = (0, utils_js_1.sharesToSteth)(prevBalanceShares, totalEther, totalShares, _a.PRECISION);
const change = newBalance - prevBalance;
totalRewards += change;
prevBalance = newBalance;
return {
type: 'rebase',
change,
apr: Number(eventApr),
changeShares: 0n,
balance: newBalance,
balanceShares: prevBalanceShares,
shareRate: (0, utils_js_1.calcShareRate)(totalEther, totalShares, _a.PRECISION),
originalEvent: event,
};
}
(0, index_js_4.invariant)(false, 'impossible event');
})
.filter((events) => !!events);
if (includeOnlyRebases) {
rewards = rewards.filter((r) => r.type === 'rebase');
}
if (!includeZeroRebases) {
rewards = rewards.filter((r) => !(r.type === 'rebase' && r.change === 0n));
}
return {
rewards,
baseBalance,
lastIndexedBlock,
baseBalanceShares,
totalRewards,
baseShareRate,
fromBlock,
toBlock: cappedToBlock,
};
}
async parseProps(props) {
const toBlock = await this.core.toBlockNumber(props.to ?? { block: 'latest' });
const fromBlock = props.from
? await this.core.toBlockNumber(props.from)
: await this.core.toBackBlock(props.back, toBlock);
(0, index_js_4.invariantArgument)(toBlock >= fromBlock, 'toBlock is lower than fromBlock');
const { includeZeroRebases = false, includeOnlyRebases = false } = props;
return {
...props,
fromBlock,
includeZeroRebases,
includeOnlyRebases,
toBlock,
};
}
constructor() {
super(...arguments);
__runInitializers(this, _instanceExtraInitializers);
}
},
(() => {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
_contractAddressStETH_decorators = [(0, index_js_1.Logger)('Contracts:'), (0, index_js_1.Cache)(30 * 60 * 1000, ['core.chain.id'])];
_contractAddressWithdrawalQueue_decorators = [(0, index_js_1.Logger)('Contracts:'), (0, index_js_1.Cache)(30 * 60 * 1000, ['core.chain.id'])];
_earliestRebaseEventBlock_decorators = [(0, index_js_1.Logger)('Contracts:'), (0, index_js_1.Cache)(30 * 60 * 1000, ['core.chain.id'])];
_getContractStETH_decorators = [(0, index_js_1.Logger)('Contracts:'), (0, index_js_1.Cache)(30 * 60 * 1000, ['core.chain.id', 'contractAddressStETH'])];
_getRewardsFromChain_decorators = [(0, index_js_1.Logger)('Rewards:'), (0, index_js_1.ErrorHandler)('Rewards:')];
_getRewardsFromSubgraph_decorators = [(0, index_js_1.Logger)('Rewards:'), (0, index_js_1.ErrorHandler)('Rewards:')];
__esDecorate(_a, null, _contractAddressStETH_decorators, { kind: "method", name: "contractAddressStETH", static: false, private: false, access: { has: obj => "contractAddressStETH" in obj, get: obj => obj.contractAddressStETH }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _contractAddressWithdrawalQueue_decorators, { kind: "method", name: "contractAddressWithdrawalQueue", static: false, private: false, access: { has: obj => "contractAddressWithdrawalQueue" in obj, get: obj => obj.contractAddressWithdrawalQueue }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _earliestRebaseEventBlock_decorators, { kind: "method", name: "earliestRebaseEventBlock", static: false, private: false, access: { has: obj => "earliestRebaseEventBlock" in obj, get: obj => obj.earliestRebaseEventBlock }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _getContractStETH_decorators, { kind: "method", name: "getContractStETH", static: false, private: false, access: { has: obj => "getContractStETH" in obj, get: obj => obj.getContractStETH }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _getRewardsFromChain_decorators, { kind: "method", name: "getRewardsFromChain", static: false, private: false, access: { has: obj => "getRewardsFromChain" in obj, get: obj => obj.getRewardsFromChain }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _getRewardsFromSubgraph_decorators, { kind: "method", name: "getRewardsFromSubgraph", static: false, private: false, access: { has: obj => "getRewardsFromSubgraph" in obj, get: obj => obj.getRewardsFromSubgraph }, metadata: _metadata }, null, _instanceExtraInitializers);
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
})(),
Object.defineProperty(_a, "PRECISION", {
enumerable: true,
configurable: true,
writable: true,
value: 10n ** 27n
}),
Object.defineProperty(_a, "DEFAULT_STEP_ENTITIES", {
enumerable: true,
configurable: true,
writable: true,
value: 1000
}),
Object.defineProperty(_a, "DEFAULT_STEP_BLOCK", {
enumerable: true,
configurable: true,
writable: true,
value: 50000
}),
_a;
})();
exports.LidoSDKRewards = LidoSDKRewards;
//# sourceMappingURL=rewards.js.map