multipool-staking-sdk
Version:
This is an sdk for solmask staking pool program
251 lines • 15.5 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.StakingService = void 0;
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const buffer_1 = require("buffer");
const anchor_1 = require("@project-serum/anchor");
const spl_token_1 = require("@solana/spl-token");
const web3_js_1 = require("@solana/web3.js");
const constants_1 = require("./constants");
const payload_1 = require("./payload");
const utils_1 = require("./utils");
class StakingService {
static deriveLockupInfoAddress(lockerName, programId) {
const _programId = new web3_js_1.PublicKey(programId);
const [lockupAddress] = web3_js_1.PublicKey.findProgramAddressSync([
buffer_1.Buffer.from(anchor_1.utils.bytes.utf8.encode(constants_1.PROGRAM_SEEDS_PHRASES.LockupInfo)),
buffer_1.Buffer.from(anchor_1.utils.bytes.utf8.encode(lockerName)),
], _programId);
return lockupAddress;
}
static deriveStakeVaultAddress(lockupAddress, programId) {
const _lockupAddress = new web3_js_1.PublicKey(lockupAddress);
const _programId = new web3_js_1.PublicKey(programId);
const [stakeVaultAddress] = web3_js_1.PublicKey.findProgramAddressSync([
buffer_1.Buffer.from(anchor_1.utils.bytes.utf8.encode(constants_1.PROGRAM_SEEDS_PHRASES.LockupVault)),
_lockupAddress.toBuffer(),
], _programId);
return stakeVaultAddress;
}
static deriveStakeInfoAddress(lockupAddress, stakerAddress, programId) {
const _lockupAddress = new web3_js_1.PublicKey(lockupAddress);
const _stakerAddress = new web3_js_1.PublicKey(stakerAddress);
const _programId = new web3_js_1.PublicKey(programId);
const [stakeInfoAddress] = web3_js_1.PublicKey.findProgramAddressSync([_stakerAddress.toBuffer(), _lockupAddress.toBuffer()], _programId);
return stakeInfoAddress;
}
constructor(instructions, _connection, _signTransaction) {
this.instructions = instructions;
this._connection = _connection;
this._signTransaction = _signTransaction;
this._programId = this.instructions.program.programId;
this._programErrorMap = new Map();
for (const error of this.instructions.program.idl.errors) {
this._programErrorMap.set(error.code, error.msg);
}
}
_createPayload(tx, signers) {
return new payload_1.TransactionPayload(this._connection, this._signTransaction, this._programErrorMap, tx, signers);
}
initLockup(params) {
return __awaiter(this, void 0, void 0, function* () {
const { creatorAddress, rewardTokenAddress, stakeTokenAddress } = params;
const creator = new web3_js_1.PublicKey(creatorAddress);
const rewardToken = new web3_js_1.PublicKey(rewardTokenAddress);
const stakeToken = new web3_js_1.PublicKey(stakeTokenAddress);
const lockup = StakingService.deriveLockupInfoAddress(params.name, this._programId);
console.debug("lockup: %s", lockup.toString());
const stakeVault = StakingService.deriveStakeVaultAddress(lockup, this._programId);
console.debug("stakeVault: %s", stakeVault.toString());
const stakeVaultRewardTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(rewardToken, stakeVault, true);
const stakeVaultStakeTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(stakeToken, stakeVault, true);
const rewardTokenDecimals = yield (0, utils_1.getDecimals)(this._connection, rewardToken);
const totalAllocationReward = (0, bignumber_js_1.default)(params.totalAllocationReward)
.times((0, bignumber_js_1.default)(10).pow(rewardTokenDecimals))
.toFixed(0);
const ix = yield this.instructions.getInitLockupInstruction(creator, lockup, stakeVaultRewardTokenAccount, stakeVaultStakeTokenAccount, rewardToken, stakeToken, stakeVault, {
totalAllocationReward: new anchor_1.BN(totalAllocationReward),
lockTimespan: new anchor_1.BN(params.lockTimespan),
name: params.name,
stakingEndTime: new anchor_1.BN(params.stakingEndTime),
stakingStartTime: new anchor_1.BN(params.stakingStartTime),
});
const { blockhash, lastValidBlockHeight } = yield this._connection.getLatestBlockhash();
const tx = new web3_js_1.Transaction({
feePayer: creator,
blockhash,
lastValidBlockHeight,
}).add(ix);
return this._createPayload(tx, []);
});
}
stake(params) {
return __awaiter(this, void 0, void 0, function* () {
const { lockupAddress, stakeAmount, stakerAddress } = params;
const lockup = new web3_js_1.PublicKey(lockupAddress);
const decoded = yield this.instructions.program.account.lockupInfo.fetch(lockup);
const stakeToken = decoded.stakedToken;
const staker = new web3_js_1.PublicKey(stakerAddress);
const stakeVault = StakingService.deriveStakeVaultAddress(lockup, this._programId);
const stakeInfo = StakingService.deriveStakeInfoAddress(lockup, staker, this._programId);
const stakerTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(stakeToken, staker);
const stakeVaultTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(stakeToken, stakeVault, true);
const stakeTokenDecimals = yield (0, utils_1.getDecimals)(this._connection, stakeToken);
const amount = (0, bignumber_js_1.default)(stakeAmount).times((0, bignumber_js_1.default)(10).pow(stakeTokenDecimals)).toFixed(0);
const ix = yield this.instructions.getStakeInstruction(lockup, stakeInfo, staker, stakerTokenAccount, stakeToken, stakeVault, stakeVaultTokenAccount, new anchor_1.BN(amount));
const { blockhash, lastValidBlockHeight } = yield this._connection.getLatestBlockhash();
const tx = new web3_js_1.Transaction({
feePayer: staker,
blockhash,
lastValidBlockHeight,
}).add(ix);
return this._createPayload(tx, []);
});
}
unstake(params) {
return __awaiter(this, void 0, void 0, function* () {
const { lockupAddress, stakerAddress } = params;
const lockup = new web3_js_1.PublicKey(lockupAddress);
const decoded = yield this.instructions.program.account.lockupInfo.fetch(lockup);
const stakeToken = decoded.stakedToken;
const staker = new web3_js_1.PublicKey(stakerAddress);
const stakeInfo = StakingService.deriveStakeInfoAddress(lockup, staker, this._programId);
const stakeVault = StakingService.deriveStakeVaultAddress(lockup, this._programId);
const stakerTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(stakeToken, staker);
const stakeVaultTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(stakeToken, stakeVault, true);
const ix = yield this.instructions.getUnstakeInstruction(lockup, stakeInfo, staker, stakerTokenAccount, stakeToken, stakeVault, stakeVaultTokenAccount);
const { blockhash, lastValidBlockHeight } = yield this._connection.getLatestBlockhash();
const tx = new web3_js_1.Transaction({
feePayer: staker,
blockhash,
lastValidBlockHeight,
}).add(ix);
return this._createPayload(tx, []);
});
}
claimRewardToken(params) {
return __awaiter(this, void 0, void 0, function* () {
const { lockupAddress, stakerAddress } = params;
const lockup = new web3_js_1.PublicKey(lockupAddress);
const decoded = yield this.instructions.program.account.lockupInfo.fetch(lockup);
const rewardToken = decoded.rewardToken;
const stakeToken = decoded.stakedToken;
const staker = new web3_js_1.PublicKey(stakerAddress);
const stakeInfo = StakingService.deriveStakeInfoAddress(lockup, staker, this._programId);
const stakeVault = StakingService.deriveStakeVaultAddress(lockup, this._programId);
const stakerRewardTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(rewardToken, staker);
const stakeVaultRewardTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(rewardToken, stakeVault, true);
const ix = yield this.instructions.getClaimRewardTokenInstruction(lockup, rewardToken, stakeInfo, staker, stakerRewardTokenAccount, stakeToken, stakeVault, stakeVaultRewardTokenAccount);
const { blockhash, lastValidBlockHeight } = yield this._connection.getLatestBlockhash();
const tx = new web3_js_1.Transaction({
feePayer: staker,
blockhash,
lastValidBlockHeight,
}).add(ix);
return this._createPayload(tx, []);
});
}
getLockupInfo(lockupAddress) {
return __awaiter(this, void 0, void 0, function* () {
const lockup = new web3_js_1.PublicKey(lockupAddress);
const decoded = yield this.instructions.program.account.lockupInfo.fetch(lockup);
const rewardTokenDecimals = yield (0, utils_1.getDecimals)(this._connection, decoded.rewardToken);
const stakeTokenDecimals = yield (0, utils_1.getDecimals)(this._connection, decoded.stakedToken);
const totalAllocationReward = (0, bignumber_js_1.default)(decoded.totalAllocationReward.toString())
.div((0, bignumber_js_1.default)(10).pow(rewardTokenDecimals))
.toFixed();
const globalStaked = (0, bignumber_js_1.default)(decoded.globalStaked.toString())
.div((0, bignumber_js_1.default)(10).pow(stakeTokenDecimals))
.toFixed();
return {
creator: decoded.creator.toString(),
globalStaked,
lockupCreatedTime: decoded.lockupCreatedTime.toString(),
lockupTimespan: decoded.lockTimespan.toString(),
name: decoded.name,
rewardToken: decoded.rewardToken.toString(),
stakedToken: decoded.stakedToken.toString(),
stakingEndTime: decoded.stakingEndTime.toString(),
stakingStartTime: decoded.stakingStartTime.toString(),
totalAllocationReward,
};
});
}
getStakeInfo(lockupAddress, stakerAddress) {
return __awaiter(this, void 0, void 0, function* () {
const lockup = new web3_js_1.PublicKey(lockupAddress);
const staker = new web3_js_1.PublicKey(stakerAddress);
const stakerInfo = StakingService.deriveStakeInfoAddress(lockup, staker, this._programId);
const decodedLockup = yield this.instructions.program.account.lockupInfo.fetch(lockup);
const rewardTokenDecimals = yield (0, utils_1.getDecimals)(this._connection, decodedLockup.rewardToken);
const stakeTokenDecimals = yield (0, utils_1.getDecimals)(this._connection, decodedLockup.stakedToken);
const decoded = yield this.instructions.program.account.stakeInfo.fetch(stakerInfo);
const rewardAmount = (0, bignumber_js_1.default)(decoded.rewardAmount.toString())
.div((0, bignumber_js_1.default)(10).pow(rewardTokenDecimals))
.toFixed();
const stakedAmount = (0, bignumber_js_1.default)(decoded.stakedAmount.toString())
.div((0, bignumber_js_1.default)(10).pow(stakeTokenDecimals))
.toFixed();
return {
createdTime: decoded.createdTime.toString(),
rewardAmount,
stakedAmount,
staker: decoded.staker.toString(),
rewardClaimed: decoded.rewardClaimed,
stakeClaimed: decoded.stakeClaimed,
};
});
}
calculateReward(lockupAdress, stakerAddress) {
return __awaiter(this, void 0, void 0, function* () {
const lockup = new web3_js_1.PublicKey(lockupAdress);
const staker = new web3_js_1.PublicKey(stakerAddress);
const stakerInfo = StakingService.deriveStakeInfoAddress(lockup, staker, this._programId);
const [lockInfoDecoded, stakeInfoDecoded] = yield Promise.all([
this.instructions.program.account.lockupInfo.fetch(lockup, "confirmed"),
this.instructions.program.account.stakeInfo.fetch(stakerInfo, "confirmed"),
]);
const rewardTokenDecimals = yield (0, utils_1.getDecimals)(this._connection, lockInfoDecoded.rewardToken);
const slot = yield this._connection.getSlot("confirmed");
const blockTime = yield this._connection.getBlockTime(slot);
(0, utils_1.assert)(blockTime, "blocktime is null!");
if ((0, bignumber_js_1.default)(lockInfoDecoded.stakingEndTime.toString()).isGreaterThanOrEqualTo(blockTime)) {
return "0";
}
const lockTimeSpanInDays = (0, bignumber_js_1.default)(lockInfoDecoded.lockTimespan.toString()).div(constants_1.ONE_DAY_BIGNUM);
let stakedTimespan;
if ((0, bignumber_js_1.default)(lockInfoDecoded.stakingEndTime.toString())
.plus(lockInfoDecoded.lockTimespan.toString())
.isLessThan(blockTime)) {
stakedTimespan = lockTimeSpanInDays;
}
else {
stakedTimespan = (0, bignumber_js_1.default)(blockTime)
.minus(lockInfoDecoded.stakingEndTime.toString())
.div(constants_1.ONE_DAY_BIGNUM);
}
const stakerShare = (0, bignumber_js_1.default)(stakeInfoDecoded.stakedAmount.toString()).div(lockInfoDecoded.globalStaked.toString());
const dailyAllocationReward = (0, bignumber_js_1.default)(lockInfoDecoded.totalAllocationReward.toString()).div(lockTimeSpanInDays);
const totalRewardAmount = dailyAllocationReward
.times(stakedTimespan)
.times(stakerShare)
.decimalPlaces(0, bignumber_js_1.default.ROUND_DOWN);
const parsedReward = totalRewardAmount.div((0, bignumber_js_1.default)(10).pow(rewardTokenDecimals)).toFixed();
return parsedReward;
});
}
}
exports.StakingService = StakingService;
//# sourceMappingURL=service.js.map