UNPKG

@unloc-xyz/unloc-sdk

Version:
469 lines 21.3 kB
"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