blub-sdk
Version:
A modular SDK for interacting with the BLUB ecosystem on the Sui blockchain.
169 lines (168 loc) • 6.44 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports._queryUserPositionIds = _queryUserPositionIds;
exports._getPositions = _getPositions;
exports.parseUserPosition = parseUserPosition;
exports._getUserTotalStaked = _getUserTotalStaked;
exports._calculatePendingReward = _calculatePendingReward;
exports.queryRewardManager = queryRewardManager;
exports.queryRewardInfo = queryRewardInfo;
/* eslint-disable @typescript-eslint/no-explicit-any */
// src/queries/stakingRepository.ts
const transactions_1 = require("@mysten/sui/transactions");
const StakingBuilder_1 = require("../../builder/StakingBuilder");
const sui_1 = require("../../utils/sui");
const client_1 = require("../../utils/client");
/**
* Fetches all stake position IDs registered for the given user.
*/
async function _queryUserPositionIds(client, userPositionRecordId, wallet) {
const resq = await client.getDynamicFieldObject({
parentId: userPositionRecordId,
name: {
type: "address",
value: wallet,
},
});
const fields = (0, sui_1.getObjectFields)(resq);
if (!fields) {
throw new Error("fields is null");
}
const tableId = fields.value.fields.id.id;
const positionFields = await client.getDynamicFields({ parentId: tableId });
return positionFields.data.map((item) => item.name.value);
}
/**
* Fetches and parses all stake positions for the given IDs.
*/
async function _getPositions(positionIds, client = client_1.defaultSuiClient) {
//
const resq = await client.multiGetObjects({
ids: positionIds,
options: { showContent: true },
});
const positions = [];
for (const item of resq) {
const fields = (0, sui_1.getObjectFields)(item);
if (!fields) {
throw new Error("fields is null");
}
const position = await parseUserPosition(client, fields);
positions.push(position);
}
return positions;
}
/**
* Parses a single stake position object into a StakePosition structure.
*/
async function parseUserPosition(client, fields) {
const waitingClaim = new Map();
const rewardDebt = new Map();
const waitClaimRewardTableId = fields.waiting_claim_reward.fields.id.id;
const waitClaimRewardFields = await client.getDynamicFields({
parentId: waitClaimRewardTableId,
});
for (const item of waitClaimRewardFields.data) {
const object = await client.getObject({
id: item.objectId,
options: { showContent: true },
});
const f = (0, sui_1.getObjectFields)(object);
if (!f)
throw new Error("fields is null");
waitingClaim.set(f.name.fields.name, BigInt(f.value));
}
const rewardDebtTableId = fields.reward_debt.fields.id.id;
const rewardDebtFields = await client.getDynamicFields({
parentId: rewardDebtTableId,
});
for (const item of rewardDebtFields.data) {
const object = await client.getObject({
id: item.objectId,
options: { showContent: true },
});
const f = (0, sui_1.getObjectFields)(object);
if (!f)
throw new Error("fields is null");
rewardDebt.set(f.name.fields.name, BigInt(f.value));
}
return {
id: fields.id.id,
stakedAmount: BigInt(fields.staked_amount),
rewardDebt,
waitingClaimReward: waitingClaim,
};
}
/**
* Calculates the total staked amount across all user positions.
*/
async function _getUserTotalStaked(client, userPositionRecordId, wallet) {
const positionIds = await _queryUserPositionIds(client, userPositionRecordId, wallet);
if (!positionIds || positionIds.length === 0)
return BigInt(0);
const positions = await _getPositions(positionIds);
if (!positions || positions.length === 0)
return BigInt(0);
return positions.reduce((total, p) => (p.stakedAmount > BigInt(0) ? total + p.stakedAmount : total), BigInt(0));
}
/**
* Simulates a reward calculation for a position using `devInspectTransactionBlock`,
* without executing a real on-chain transaction.
*/
async function _calculatePendingReward(owner, { position, coinType }, packageId, client = client_1.defaultSuiClient) {
const builder = new StakingBuilder_1.StakingBuilder();
const txb = builder.calculatePendingReward({ position, coinType }, new transactions_1.Transaction());
const inspection = await client.devInspectTransactionBlock({
transactionBlock: txb,
sender: owner,
});
const events = inspection.events ?? [];
const pending = [];
for (const e of events) {
if (e.type === `${packageId}::events::CalculatePendingRewardEvent`) {
const dat = e.parsedJson.reward_info;
pending.push({
coinType: dat.coin_type.name,
pendingReward: BigInt(dat.pending_reward_amount),
});
}
}
return pending;
}
async function queryRewardManager(client, rewardManagerId) {
const resq = await client.getObject({
id: rewardManagerId,
options: { showContent: true },
});
const fields = (0, sui_1.getObjectFields)(resq);
if (!fields)
throw new Error("fields is null");
const rewardsInfos = new Map();
const contents = fields.rewards_infos?.fields?.contents ?? [];
contents.forEach((item) => {
const rewardCoinType = (0, sui_1.completionCoin)(item.fields.key.fields.name);
const rewardInfo = parseRewardInfo(item.fields.value.fields);
rewardsInfos.set(rewardCoinType, rewardInfo);
});
return {
id: rewardManagerId,
totalStakedAmount: BigInt(fields.total_staked_amount),
rewardsInfos,
userPositionsRecordId: fields.user_positions_record.fields.id.id,
};
}
function parseRewardInfo(fields) {
const rewardInfo = {
rewardCoinType: (0, sui_1.completionCoin)(fields.reward_coin_type.fields.name),
accRewardPerShare: BigInt(fields.acc_reward_per_share),
lastRewardTime: BigInt(fields.last_reward_time),
};
return rewardInfo;
}
async function queryRewardInfo(client, rewardManagerId, rewardCoinType) {
const rewardManager = await queryRewardManager(client, rewardManagerId);
if (!rewardManager) {
return null;
}
return rewardManager.rewardsInfos.get((0, sui_1.completionCoin)(rewardCoinType)) ?? null;
}