@unloc-xyz/unloc-sdk
Version:
469 lines • 21.3 kB
JavaScript
"use strict";
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 (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.harvest = exports.unstake = exports.createStakingUser = exports.stake = exports.calculateTiers = exports.TIERS_XCRP = exports.getStakingPoolUserAccount = exports.changeStakingPoolPoint = exports.changeStakingTokenPerSecond = exports.changeStakingPoolAmountMultipler = exports.closeStakingPool = exports.createStakingPool = exports.getFirstStakingPool = exports.getAllStakingPools = exports.fundToStakingProgram = exports.setStakingExtraReward = exports.createStakingExtraReward = exports.getStakingExtraRewardConfigs = exports.getStakingState = exports.createStakingState = exports.estimateStakingRewardsPerSec = exports.estimateRewards = exports.getStakingStateAddress = exports.initStakingProgram = void 0;
// @ts-ignore
const anchor = __importStar(require("@project-serum/anchor"));
const spl_token_1 = require("@solana/spl-token");
const { BN, web3, Program, AnchorProvider } = anchor;
const { PublicKey, SystemProgram, Transaction } = web3;
const utf8 = anchor.utils.bytes.utf8;
const defaultAccounts = {
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
clock: anchor.web3.SYSVAR_CLOCK_PUBKEY,
systemProgram: SystemProgram.programId,
};
const unloc_staking_1 = require("../types/unloc_staking");
const utils_1 = require("../utils");
const global_config_1 = require("../global-config");
let StakingProgram = null;
function initStakingProgram(connection, wallet, programId = global_config_1.STAKING_PID) {
const provider = new anchor.AnchorProvider(connection, wallet, {
commitment: 'confirmed',
});
// Generate the program client from IDL.
const program = new anchor.Program(unloc_staking_1.IDL, programId, provider);
StakingProgram = program;
}
exports.initStakingProgram = initStakingProgram;
async function getStakingStateAddress() {
const [stateSigner, stateBump] = await anchor.web3.PublicKey.findProgramAddress([utf8.encode('state')], StakingProgram.programId);
return stateSigner;
}
exports.getStakingStateAddress = getStakingStateAddress;
async function getStakingExtraRewardAddress() {
const [stateSigner, stateBump] = await anchor.web3.PublicKey.findProgramAddress([utf8.encode('extra')], StakingProgram.programId);
return stateSigner;
}
async function getStakingPoolAddressFromMint(mint) {
const [stateSigner, stateBump] = await anchor.web3.PublicKey.findProgramAddress([new PublicKey(mint).toBuffer()], StakingProgram.programId);
return stateSigner;
}
const ACC_PRECISION = new BN(100 * 1000 * 1000 * 1000);
const FULL_100 = new BN(100 * 1000 * 1000 * 1000);
function estimateRewards(stateData, extraConfigData, poolData, userData) {
const currentTimeStamp = Math.ceil(new Date().getTime() / 1000);
const duration = new BN(Math.max(currentTimeStamp - poolData.lastRewardTime, 0));
const reward_per_share = stateData.tokenPerSecond.mul(duration).mul(ACC_PRECISION).div(poolData.amount);
const acc_reward_per_share = poolData.accRewardPerShare.add(reward_per_share);
let extraPercentage = new BN(0);
extraConfigData.configs.forEach((item) => {
if (item.duration.toString() === userData.lockDuration.toString()) {
extraPercentage = item.extraPercentage;
return;
}
});
const pending_amount = userData.amount.mul(acc_reward_per_share).div(ACC_PRECISION).sub(userData.rewardDebt);
const extra_amount = userData.extraReward.add(pending_amount.mul(extraPercentage).div(FULL_100));
const total_reward = userData.rewardAmount.add(pending_amount).add(extra_amount);
return total_reward.toString();
}
exports.estimateRewards = estimateRewards;
function estimateStakingRewardsPerSec(stateData, extraConfigData, poolData, userData) {
const currentTimeStamp = Math.ceil(new Date().getTime() / 1000);
const duration = new BN(Math.max(currentTimeStamp - poolData.lastRewardTime, 0));
const reward_per_share = stateData.tokenPerSecond.mul(duration).mul(ACC_PRECISION).div(poolData.amount);
const acc_reward_per_share = poolData.accRewardPerShare.add(reward_per_share);
let extraPercentage = new BN(0);
extraConfigData.configs.forEach((item) => {
if (item.duration.toString() === userData.lockDuration.toString()) {
extraPercentage = item.extraPercentage;
return;
}
});
const pending_amount = userData.amount.mul(acc_reward_per_share).div(ACC_PRECISION).sub(userData.rewardDebt);
const extra_amount = userData.extraReward.add(pending_amount.mul(extraPercentage).div(FULL_100));
const total_reward = userData.rewardAmount.add(pending_amount).add(extra_amount);
return ((total_reward / 1000000000) / ((currentTimeStamp - poolData.lastRewardTime.toString()) * 1000));
}
exports.estimateStakingRewardsPerSec = estimateStakingRewardsPerSec;
async function createStakingState(connection, wallet, tokenPerSecond, earlyUnlocFee, profileLevels, rewardMint) {
const transaction = new Transaction();
const [stateSigner, stateBump] = await anchor.web3.PublicKey.findProgramAddress([utf8.encode('state')], StakingProgram.programId);
const stateRewardVault = await (0, utils_1.createAssociatedTokenAccountIfNotExist2)(null, stateSigner, wallet.publicKey, rewardMint, transaction);
const tx = await StakingProgram.rpc.createState(stateBump, new BN(tokenPerSecond), new BN(earlyUnlocFee), profileLevels, {
accounts: {
state: stateSigner,
rewardMint: rewardMint,
rewardVault: stateRewardVault,
feeVault: stateRewardVault,
authority: wallet.publicKey,
...defaultAccounts
},
preInstructions: transaction.instructions
});
return tx;
}
exports.createStakingState = createStakingState;
async function getStakingState() {
const stateSigner = await getStakingStateAddress();
return await StakingProgram.account.stateAccount.fetch(stateSigner);
}
exports.getStakingState = getStakingState;
async function getStakingExtraRewardConfigs() {
const [extraRewardSigner, extraRewardBump] = await anchor.web3.PublicKey.findProgramAddress([utf8.encode('extra')], StakingProgram.programId);
const extraRewardConfigs = await StakingProgram.account.extraRewardsAccount.fetchNullable(extraRewardSigner);
// assert.ok(extraRewardConfigs.configs.length === 3)
// assert.ok(new BN(1).eq(extraRewardConfigs.configs[1].duration))
// assert.ok(getNumber(50).eq(extraRewardConfigs.configs[1].extraPercentage))
return extraRewardConfigs;
}
exports.getStakingExtraRewardConfigs = getStakingExtraRewardConfigs;
async function createStakingExtraReward(connection, wallet) {
const transaction = new Transaction();
const signers = [];
const [extraRewardSigner, extraRewardBump] = await anchor.web3.PublicKey.findProgramAddress([utf8.encode('extra')], StakingProgram.programId);
console.log(extraRewardSigner.toString(), extraRewardBump);
const tx = await StakingProgram.instruction.createExtraRewardConfigs(extraRewardBump, [
{ duration: new BN(43200 * 60), extraPercentage: new BN(0) },
{ duration: new BN(129600 * 60), extraPercentage: new BN(10 * 1000 * 1000 * 1000) },
{ duration: new BN(259200 * 60), extraPercentage: new BN(30 * 1000 * 1000 * 1000) },
{ duration: new BN(525600 * 60), extraPercentage: new BN(100 * 1000 * 1000 * 1000) }
], {
accounts: {
extraRewardAccount: extraRewardSigner,
authority: wallet.publicKey,
...defaultAccounts
},
});
transaction.add(tx);
return await (0, utils_1.sendTransaction)(connection, wallet, transaction, signers);
}
exports.createStakingExtraReward = createStakingExtraReward;
async function setStakingExtraReward(connection, wallet, extraRewards) {
const transaction = new Transaction();
const signers = [];
const [extraRewardSigner, extraRewardBump] = await anchor.web3.PublicKey.findProgramAddress([utf8.encode('extra')], StakingProgram.programId);
transaction.add(StakingProgram.instruction.setExtraRewardConfigs(extraRewards, {
accounts: {
extraRewardAccount: extraRewardSigner,
authority: wallet.publicKey,
...defaultAccounts
},
}));
return await (0, utils_1.sendTransaction)(connection, wallet, transaction, signers);
}
exports.setStakingExtraReward = setStakingExtraReward;
async function fundToStakingProgram(connection, wallet, poolSigner, masterRewardVault, amount) {
const transaction = new Transaction();
const signers = [];
const stateSigner = await getStakingStateAddress();
const state = await getStakingState();
// await rewardMint.mintTo(stateRewardVault, wallet, [provider.wallet], getNumber(10000).toString())
const tx = StakingProgram.instruction.fundRewardToken(new BN(amount), {
accounts: {
state: stateSigner,
rewardVault: state.rewardVault,
userVault: masterRewardVault,
authority: wallet.publicKey,
...defaultAccounts
}
});
transaction.add(tx);
return await (0, utils_1.sendTransaction)(connection, wallet, transaction, signers);
}
exports.fundToStakingProgram = fundToStakingProgram;
async function getAllStakingPools() {
const pools = await StakingProgram.account.farmPoolAccount.all();
return pools;
}
exports.getAllStakingPools = getAllStakingPools;
async function getFirstStakingPool() {
const pools = await StakingProgram.account.farmPoolAccount.all();
return pools[0];
}
exports.getFirstStakingPool = getFirstStakingPool;
async function createStakingPool(connection, wallet, rewardMint, pools) {
const transaction = new Transaction();
const signers = [];
const [poolSigner, poolBump] = await anchor.web3.PublicKey.findProgramAddress([new PublicKey(rewardMint).toBuffer()], StakingProgram.programId);
const stateSigner = await getStakingStateAddress();
const poolVault = await (0, utils_1.createAssociatedTokenAccountIfNotExist2)(null, poolSigner, wallet.publicKey, rewardMint, transaction);
// let pools = await StakingProgram.account.farmPoolAccount.all()
transaction.add(StakingProgram.instruction.createPool(poolBump, new BN('0'), new BN('0'), {
accounts: {
pool: poolSigner,
state: stateSigner,
mint: rewardMint,
vault: poolVault,
authority: wallet.publicKey,
...defaultAccounts
},
remainingAccounts: pools.map(p => ({
pubkey: p.publicKey,
isWritable: true,
isSigner: false
}))
}));
// let stateInfo = await program.account.stateAccount.fetch(stateSigner)
// let poolInfo = await program.account.farmPoolAccount.fetch(poolSigner)
// assert.ok(poolInfo.point.eq(stateInfo.totalPoint))
// assert.ok(poolInfo.point.eq(new BN('0')))
// assert.ok(poolInfo.amountMultipler.eq(new BN(0)))
return await (0, utils_1.sendTransaction)(connection, wallet, transaction, signers);
}
exports.createStakingPool = createStakingPool;
async function closeStakingPool(connection, wallet, poolSigner, pools) {
const transaction = new Transaction();
const signers = [];
const stateSigner = await getStakingStateAddress();
StakingProgram.instruction.closePool({
accounts: {
pool: new PublicKey(poolSigner),
state: stateSigner,
authority: wallet,
...defaultAccounts
},
remainingAccounts: pools.map(p => ({
pubkey: p.publicKey,
isWritable: true,
isSigner: false
}))
});
return await (0, utils_1.sendTransaction)(connection, wallet, transaction, signers);
}
exports.closeStakingPool = closeStakingPool;
async function changeStakingPoolAmountMultipler(connection, wallet, poolSigner) {
const transaction = new Transaction();
const signers = [];
const stateSigner = await getStakingStateAddress();
const tx = StakingProgram.instruction.changePoolAmountMultipler(new BN(1), {
accounts: {
pool: new PublicKey(poolSigner),
state: stateSigner,
authority: wallet.publicKey,
...defaultAccounts
}
});
transaction.add(tx);
return await (0, utils_1.sendTransaction)(connection, wallet, transaction, signers);
}
exports.changeStakingPoolAmountMultipler = changeStakingPoolAmountMultipler;
async function changeStakingTokenPerSecond(connection, wallet, pools, tokenPerSecond) {
const transaction = new Transaction();
const signers = [];
const stateSigner = await getStakingStateAddress();
const tx = StakingProgram.instruction.changeTokensPerSecond(new BN(tokenPerSecond), {
accounts: {
state: stateSigner,
authority: wallet.publicKey,
...defaultAccounts
},
remainingAccounts: pools.map(p => ({
pubkey: p.publicKey,
isWritable: true,
isSigner: false
}))
});
transaction.add(tx);
return await (0, utils_1.sendTransaction)(connection, wallet, transaction, signers);
}
exports.changeStakingTokenPerSecond = changeStakingTokenPerSecond;
async function changeStakingPoolPoint(connection, wallet, poolSigner) {
const transaction = new Transaction();
const signers = [];
const stateSigner = await getStakingStateAddress();
let pools = await getAllStakingPools();
const ix = StakingProgram.instruction.changePoolPoint(new BN(1000), {
accounts: {
pool: new PublicKey(poolSigner),
state: stateSigner,
authority: wallet.publicKey,
...defaultAccounts
},
remainingAccounts: pools.map((p) => ({
pubkey: p.publicKey,
isWritable: true,
isSigner: false
}))
});
transaction.add(ix);
return await (0, utils_1.sendTransaction)(connection, wallet, transaction, signers);
}
exports.changeStakingPoolPoint = changeStakingPoolPoint;
async function getStakingPoolUserAccount(wallet, poolSigner) {
const [poolUserAccount, bump1] = await PublicKey.findProgramAddress([
poolSigner.toBuffer(), wallet.publicKey.toBuffer()
], StakingProgram.programId);
return await StakingProgram.account.farmPoolUserAccount.fetchNullable(poolUserAccount);
}
exports.getStakingPoolUserAccount = getStakingPoolUserAccount;
const ONE_YEAR_SECOND = 365 * 24 * 3600;
exports.TIERS_XCRP = [0, 200, 2000];
function calculateTiers(amount, lockDuration) {
const rate = Number((lockDuration / ONE_YEAR_SECOND).toFixed(3));
const xCRP = rate * amount;
let i = 0;
for (; i < exports.TIERS_XCRP.length; i++) {
if (exports.TIERS_XCRP[i] > xCRP) {
break;
}
}
i--;
return {
xCRP: Number(xCRP.toFixed(2)),
tiers: i,
};
}
exports.calculateTiers = calculateTiers;
async function stake(connection, wallet, poolSigner, rewardMint, poolVault, rewardUserVault, amount, lock = 0, signers = []) {
const transaction = new Transaction();
const stateSigner = await getStakingStateAddress();
const state = await getStakingState();
const extraRewardSigner = await getStakingExtraRewardAddress();
// const poolSigner = await getPoolAddressFromMint(rewardMint)
const [userAccount, bump1] = await PublicKey.findProgramAddress([
new PublicKey(poolSigner).toBuffer(), wallet.publicKey.toBuffer()
], StakingProgram.programId);
const userAccountData = await StakingProgram.account.farmPoolUserAccount.fetchNullable(userAccount);
if (!userAccountData) {
console.log("You are the new user to stake");
transaction.add(StakingProgram.instruction.createUser(bump1, {
accounts: {
user: userAccount,
state: stateSigner,
pool: poolSigner,
authority: wallet.publicKey,
...defaultAccounts
}
}));
}
try {
const txHash = await StakingProgram.rpc.stake(new BN(amount), new BN(lock), {
accounts: {
mint: rewardMint,
extraRewardAccount: extraRewardSigner,
poolVault: poolVault,
userVault: rewardUserVault,
feeVault: state.feeVault,
user: userAccount,
state: stateSigner,
pool: poolSigner,
authority: wallet.publicKey,
...defaultAccounts
},
preInstructions: transaction.instructions,
signers
});
return txHash;
}
catch (e) {
console.log(e);
}
return '';
}
exports.stake = stake;
async function createStakingUser(connection, wallet, poolSigner, signers = []) {
const stateSigner = await getStakingStateAddress();
const [userAccount, bump1] = await PublicKey.findProgramAddress([
new PublicKey(poolSigner).toBuffer(), wallet.publicKey.toBuffer()
], StakingProgram.programId);
const userAccountData = await StakingProgram.account.farmPoolUserAccount.fetchNullable(userAccount);
if (!userAccountData) {
console.log("You are the new user to stake");
try {
const tx = await StakingProgram.rpc.createUser(bump1, {
accounts: {
user: userAccount,
state: stateSigner,
pool: poolSigner,
authority: wallet.publicKey,
...defaultAccounts
},
signers
});
return tx;
}
catch (e) {
console.log(e);
return null;
}
}
return null;
}
exports.createStakingUser = createStakingUser;
async function unstake(connection, wallet, poolSigner, rewardMint, poolVault, rewardUserVault, amount, signers = []) {
const stateSigner = await getStakingStateAddress();
const programState = await getStakingState();
const extraRewardSigner = await getStakingExtraRewardAddress();
// const poolSigner = await getPoolAddressFromMint(rewardMint)
const [poolUserAccount, bump1] = await PublicKey.findProgramAddress([
new PublicKey(poolSigner).toBuffer(), wallet.publicKey.toBuffer()
], StakingProgram.programId);
try {
const txHash = await StakingProgram.rpc.unstake(new BN(amount), {
accounts: {
mint: rewardMint,
extraRewardAccount: extraRewardSigner,
poolVault: poolVault,
userVault: rewardUserVault,
feeVault: programState.feeVault,
user: poolUserAccount,
state: stateSigner,
pool: poolSigner,
authority: wallet.publicKey,
...defaultAccounts
},
signers
});
return txHash;
}
catch (e) {
console.log(e);
return null;
}
}
exports.unstake = unstake;
async function harvest(connection, wallet, poolSigner, rewardMint, rewardUserVault, stateRewardVault, signers = []) {
const stateSigner = await getStakingStateAddress();
const extraRewardSigner = await getStakingExtraRewardAddress();
// const poolSigner = await getPoolAddressFromMint(rewardMint)
const [poolUserAccount, bump1] = await PublicKey.findProgramAddress([
new PublicKey(poolSigner).toBuffer(), wallet.publicKey.toBuffer()
], StakingProgram.programId);
try {
const txHash = await StakingProgram.rpc.harvest({
accounts: {
mint: rewardMint,
extraRewardAccount: extraRewardSigner,
rewardVault: stateRewardVault,
userVault: rewardUserVault,
user: poolUserAccount,
state: stateSigner,
pool: poolSigner,
authority: wallet.publicKey,
...defaultAccounts
},
signers
});
return txHash;
}
catch (e) {
console.log(e);
return null;
}
}
exports.harvest = harvest;
//# sourceMappingURL=index.js.map