UNPKG

@frakt-protocol/frakt-sdk

Version:

Frakt SDK for interacting with frakt.xyz protocols

330 lines (329 loc) 18.1 kB
"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()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.findRuleSetPDA = exports.getMetaplexMetadata = exports.findTokenRecordPda = exports.createAndSendV0Tx = exports.objectBNsAndPubkeysToNums = exports.getMostOptimalLoansClosestToNeededSolInBulk = exports.anchorRawBNsAndPubkeysToNumsAndStrings = exports.getMetaplexEditionPda = exports.decodeLotTicket = exports.decodeLoan = exports.decodedLoan = exports.decodedDeposit = exports.decodedPriceBasedLiquidityPool = exports.decodedTimeBasedLiquidityPool = exports.decodedFarmer = exports.decodedLendingStake = exports.decodedCollectionInfo = exports.returnAnchorProgram = void 0; const anchor_1 = require("@project-serum/anchor"); const nft_lending_v2_1 = require("./idl/nft_lending_v2"); const common_1 = require("../common"); const constants_1 = require("./constants"); const returnAnchorProgram = (programId, connection) => new anchor_1.Program(nft_lending_v2_1.IDL, programId, new anchor_1.AnchorProvider(connection, (0, common_1.createFakeWallet)(), anchor_1.AnchorProvider.defaultOptions())); exports.returnAnchorProgram = returnAnchorProgram; const decodedCollectionInfo = (decodedCollection, address) => ({ collectionInfoPubkey: address.toBase58(), creator: decodedCollection.creator.toBase58(), liquidityPool: decodedCollection.liquidityPool.toBase58(), pricingLookupAddress: decodedCollection.pricingLookupAddress.toBase58(), royaltyAddress: decodedCollection.royaltyAddress.toBase58(), royaltyFeeTime: decodedCollection.royaltyFeeTime.toNumber(), royaltyFeePrice: decodedCollection.royaltyFeePrice.toNumber(), loanToValue: decodedCollection.loanToValue.toNumber(), collaterizationRate: decodedCollection.collaterizationRate.toNumber(), availableLoanTypes: Object.keys(decodedCollection.availableLoanTypes)[0], expirationTime: decodedCollection.expirationTime.toNumber(), }); exports.decodedCollectionInfo = decodedCollectionInfo; const decodedLendingStake = (decodedStake, address) => { var _a; return ({ lendingStakePubkey: address.toBase58(), stakeType: Object.keys(decodedStake.stakeType)[0], loan: decodedStake.loan.toBase58(), stakeContract: decodedStake.stakeContract.toBase58(), stakeConstractOptional: (_a = decodedStake.stakeConstractOptional) === null || _a === void 0 ? void 0 : _a.toBase58(), stakeState: Object.keys(decodedStake.stakeState)[0], identity: decodedStake.identity.toBase58(), dataA: decodedStake.dataA.toBase58(), dataB: decodedStake.dataB.toBase58(), dataC: decodedStake.dataC.toBase58(), dataD: decodedStake.dataD.toBase58(), totalHarvested: decodedStake.totalHarvested.toNumber(), totalHarvestedOptional: decodedStake.totalHarvestedOptional.toNumber(), lastTime: decodedStake.lastTime.toNumber(), }); }; exports.decodedLendingStake = decodedLendingStake; const decodedFarmer = (decodedFarmer, address) => ({ farmerPubkey: address.toBase58(), farm: decodedFarmer.farm.toBase58(), identity: decodedFarmer.identity.toBase58(), vault: decodedFarmer.vault.toBase58(), state: Object.keys(decodedFarmer.state)[0], gemsStaked: decodedFarmer.gemsStaked.toNumber(), minStakingEndsTs: decodedFarmer.minStakingEndsTs.toNumber(), cooldownEndsTs: decodedFarmer.cooldownEndsTs.toNumber(), rewardA: decodedReward(decodedFarmer.rewardA), rewardB: decodedReward(decodedFarmer.rewardB), }); exports.decodedFarmer = decodedFarmer; const decodedReward = (decodedReward) => { var _a, _b; return ({ paidOutReward: decodedReward.paidOutReward.toNumber(), accruedReward: decodedReward.accruedReward.toNumber(), variableRate: (_b = (_a = decodedReward.lastRecordedAccruedRewardPerRarityPoint) === null || _a === void 0 ? void 0 : _a.n) === null || _b === void 0 ? void 0 : _b.toNumber(), fixedRate: decodedFixedRate(decodedReward.fixedRate), }); }; const decodedFixedRate = (decodedFixedRate) => ({ beginScheduleTs: decodedFixedRate.beginScheduleTs.toNumber(), beginStakingTs: decodedFixedRate.beginStakingTs.toNumber(), lastUpdatedTs: decodedFixedRate.lastUpdatedTs.toNumber(), promisedDuration: decodedFixedRate.promisedDuration.toNumber(), promisedSchedule: decodedPromisedSchedule(decodedFixedRate.promisedSchedule), }); const decodedPromisedSchedule = (decodedSchedule) => { var _a, _b, _c, _d, _e; return ({ baseRate: (_a = decodedSchedule.baseRate) === null || _a === void 0 ? void 0 : _a.toNumber(), tier1: (_b = decodedSchedule.tier1) === null || _b === void 0 ? void 0 : _b.toNumber(), tier2: (_c = decodedSchedule.tier2) === null || _c === void 0 ? void 0 : _c.toNumber(), tier3: (_d = decodedSchedule.tier3) === null || _d === void 0 ? void 0 : _d.toNumber(), denominator: (_e = decodedSchedule.denominator) === null || _e === void 0 ? void 0 : _e.toNumber(), }); }; const decodedTimeBasedLiquidityPool = (decodedLiquidityPool, address) => ({ liquidityPoolPubkey: address.toBase58(), id: decodedLiquidityPool.id.toNumber(), rewardInterestRateTime: decodedLiquidityPool.rewardInterestRateTime.toNumber(), feeInterestRateTime: decodedLiquidityPool.feeInterestRateTime.toNumber(), rewardInterestRatePrice: decodedLiquidityPool.rewardInterestRatePrice.toNumber(), feeInterestRatePrice: decodedLiquidityPool.feeInterestRatePrice.toNumber(), liquidityAmount: decodedLiquidityPool.liquidityAmount.toNumber(), liqOwner: decodedLiquidityPool.liqOwner.toBase58(), amountOfStaked: decodedLiquidityPool.amountOfStaked.toNumber(), userRewardsAmount: decodedLiquidityPool.userRewardsAmount.toNumber(), apr: decodedLiquidityPool.apr.toNumber(), cumulative: decodedLiquidityPool.cumulative.toNumber(), lastTime: decodedLiquidityPool.lastTime.toNumber(), oldCumulative: decodedLiquidityPool.oldCumulative.toNumber(), period: decodedLiquidityPool.period.toNumber(), }); exports.decodedTimeBasedLiquidityPool = decodedTimeBasedLiquidityPool; const decodedPriceBasedLiquidityPool = (decodedLiquidityPool, address) => ({ liquidityPoolPubkey: address.toBase58(), id: decodedLiquidityPool.id.toNumber(), baseBorrowRate: decodedLiquidityPool.baseBorrowRate, variableSlope1: decodedLiquidityPool.variableSlope1, variableSlope2: decodedLiquidityPool.variableSlope2, utilizationRateOptimal: decodedLiquidityPool.utilizationRateOptimal, reserveFactor: decodedLiquidityPool.reserveFactor, reserveAmount: decodedLiquidityPool.reserveAmount.toString(), liquidityAmount: decodedLiquidityPool.liquidityAmount.toNumber(), liqOwner: decodedLiquidityPool.liqOwner.toBase58(), amountOfStaked: decodedLiquidityPool.amountOfStaked.toNumber(), depositApr: decodedLiquidityPool.depositApr.toNumber(), depositCumulative: decodedLiquidityPool.depositCumulative.toNumber(), borrowApr: decodedLiquidityPool.borrowApr.toNumber(), borrowCumulative: decodedLiquidityPool.borrowCumulative.toNumber(), lastTime: decodedLiquidityPool.lastTime.toNumber(), depositCommission: decodedLiquidityPool.depositCommission, borrowCommission: decodedLiquidityPool.borrowCommission, }); exports.decodedPriceBasedLiquidityPool = decodedPriceBasedLiquidityPool; const decodedDeposit = (decodedDeposit, address) => ({ depositPubkey: address.toBase58(), liquidityPool: decodedDeposit.liquidityPool.toBase58(), user: decodedDeposit.user.toBase58(), amount: decodedDeposit.amount.toNumber(), stakedAt: decodedDeposit.stakedAt.toNumber(), stakedAtCumulative: decodedDeposit.stakedAtCumulative.toNumber(), }); exports.decodedDeposit = decodedDeposit; const decodedLoan = (decodedLoan, address) => ({ loanPubkey: address.toBase58(), user: decodedLoan.user.toBase58(), nftMint: decodedLoan.nftMint.toBase58(), nftUserTokenAccount: decodedLoan.nftUserTokenAccount.toBase58(), liquidityPool: decodedLoan.liquidityPool.toBase58(), collectionInfo: decodedLoan.collectionInfo.toBase58(), startedAt: decodedLoan.startedAt.toNumber(), expiredAt: new anchor_1.BN(decodedLoan.expiredAt || 0).toNumber(), finishedAt: decodedLoan.finishedAt.toNumber(), originalPrice: decodedLoan.originalPrice.toNumber(), amountToGet: decodedLoan.amountToGet.toNumber(), rewardAmount: decodedLoan.rewardAmount.toNumber(), feeAmount: decodedLoan.feeAmount.toNumber(), royaltyAmount: decodedLoan.royaltyAmount.toNumber(), borrowedAtCumulative: new anchor_1.BN(decodedLoan.rewardInterestRate || 0).toNumber(), alreadyPaidBack: new anchor_1.BN(decodedLoan.feeInterestRate || 0).toNumber(), loanStatus: Object.keys(decodedLoan.loanStatus)[0], loanType: Object.keys(decodedLoan.loanType)[0], }); exports.decodedLoan = decodedLoan; const decodeLoan = (buffer, connection, programId) => { const program = (0, exports.returnAnchorProgram)(programId, connection); return program.coder.accounts.decode('Loan', buffer); }; exports.decodeLoan = decodeLoan; const decodeLotTicket = (buffer, lotTicketPubkey, connection, programId) => { const program = (0, exports.returnAnchorProgram)(programId, connection); const rawAccount = program.coder.accounts.decode('LotTicket', buffer); return (0, exports.anchorRawBNsAndPubkeysToNumsAndStrings)({ account: rawAccount, publicKey: lotTicketPubkey }); }; exports.decodeLotTicket = decodeLotTicket; const getMetaplexEditionPda = (mintPubkey) => { const editionPda = anchor_1.utils.publicKey.findProgramAddressSync([ Buffer.from(constants_1.METADATA_PREFIX), constants_1.METADATA_PROGRAM_PUBKEY.toBuffer(), new anchor_1.web3.PublicKey(mintPubkey).toBuffer(), Buffer.from(constants_1.EDITION_PREFIX), ], constants_1.METADATA_PROGRAM_PUBKEY); return editionPda[0]; }; exports.getMetaplexEditionPda = getMetaplexEditionPda; const anchorRawBNsAndPubkeysToNumsAndStrings = (rawAccount) => { const copyRawAccount = Object.assign({}, rawAccount); for (let key in copyRawAccount.account) { if (copyRawAccount.account[key] === null) continue; if (copyRawAccount.account[key].toNumber) { copyRawAccount.account[key] = copyRawAccount.account[key].toNumber(); } if (copyRawAccount.account[key].toBase58) { copyRawAccount.account[key] = copyRawAccount.account[key].toBase58(); } if (typeof copyRawAccount.account[key] === 'object') { copyRawAccount.account[key] = Object.keys(copyRawAccount.account[key])[0]; } } return Object.assign(Object.assign({}, copyRawAccount.account), { publicKey: copyRawAccount.publicKey.toBase58() }); }; exports.anchorRawBNsAndPubkeysToNumsAndStrings = anchorRawBNsAndPubkeysToNumsAndStrings; const knapsackAlgorithm = (items, capacity) => { const getLast = (memo) => { let lastRow = memo[memo.length - 1]; return lastRow[lastRow.length - 1]; }; const getSolution = (row, cap, memo) => { const NO_SOLUTION = { maxValue: 0, subset: [] }; // the column number starts from zero. let col = cap - 1; let lastItem = items[row]; // The remaining capacity for the sub-problem to solve. let remaining = cap - lastItem.w; // Refer to the last solution for this capacity, // which is in the cell of the previous row with the same column let lastSolution = row > 0 ? memo[row - 1][col] || NO_SOLUTION : NO_SOLUTION; // Refer to the last solution for the remaining capacity, // which is in the cell of the previous row with the corresponding column let lastSubSolution = row > 0 ? memo[row - 1][remaining - 1] || NO_SOLUTION : NO_SOLUTION; // If any one of the items weights greater than the 'cap', return the last solution if (remaining < 0) { return lastSolution; } // Compare the current best solution for the sub-problem with a specific capacity // to a new solution trial with the lastItem(new item) added let lastValue = lastSolution.maxValue; let lastSubValue = lastSubSolution.maxValue; let newValue = lastSubValue + lastItem.v; if (newValue >= lastValue) { // copy the subset of the last sub-problem solution let _lastSubSet = lastSubSolution.subset.slice(); _lastSubSet.push(lastItem); return { maxValue: newValue, subset: _lastSubSet }; } else { return lastSolution; } }; // This implementation uses dynamic programming. // Variable 'memo' is a grid(2-dimentional array) to store optimal solution for sub-problems, // which will be later used as the code execution goes on. // This is called memoization in programming. // The cell will store best solution objects for different capacities and selectable items. let memo = []; // Filling the sub-problem solutions grid. for (let i = 0; i < items.length; i++) { // Variable 'cap' is the capacity for sub-problems. In this example, 'cap' ranges from 1 to 6. let row = []; for (let cap = 1; cap <= capacity; cap++) { row.push(getSolution(i, cap, memo)); } memo.push(row); } // The right-bottom-corner cell of the grid contains the final solution for the whole problem. return getLast(memo); }; /* Returns most optimal loans by lowest interest using Knapsack Algorithm. */ const getMostOptimalLoansClosestToNeededSolInBulk = ({ neededSol, possibleLoans, }) => { const divider = 1e7; const preparedItems = possibleLoans.map((loan) => (Object.assign(Object.assign({}, loan), { v: Math.ceil((loan.loanValue - loan.interest) / divider), w: Math.ceil(loan.loanValue / divider) }))); const preparedNeededSol = Math.ceil(neededSol / divider); const { maxValue, subset } = knapsackAlgorithm(preparedItems, preparedNeededSol); const result = subset.map((item) => ({ nftMint: item.nftMint, loanValue: item.loanValue, interest: item.interest })); return result; }; exports.getMostOptimalLoansClosestToNeededSolInBulk = getMostOptimalLoansClosestToNeededSolInBulk; function objectBNsAndPubkeysToNums(obj) { const copyobj = Object.assign({}, obj); for (const key in copyobj.account) { if (copyobj.account[key] === null) continue; if (copyobj.account[key].toNumber) { copyobj.account[key] = copyobj.account[key].toNumber(); } if (copyobj.account[key].toBase58) { copyobj.account[key] = copyobj.account[key].toBase58(); } if (typeof copyobj.account[key] === 'object') { copyobj.account[key] = Object.keys(copyobj.account[key])[0]; } } return Object.assign(Object.assign({}, copyobj.account), { publicKey: copyobj.publicKey.toBase58() }); } exports.objectBNsAndPubkeysToNums = objectBNsAndPubkeysToNums; const createAndSendV0Tx = (connection, txInstructions, signer, additionalSigners, lookupTablePubkey, skipPreflight) => __awaiter(void 0, void 0, void 0, function* () { let latestBlockhash = yield connection.getLatestBlockhash('finalized'); const lookupTable = (yield connection.getAddressLookupTable(lookupTablePubkey)).value; if (!lookupTable) return; const messageV0 = new anchor_1.web3.TransactionMessage({ payerKey: signer.publicKey, recentBlockhash: latestBlockhash.blockhash, instructions: txInstructions, }).compileToV0Message([lookupTable]); const transaction = new anchor_1.web3.VersionedTransaction(messageV0); transaction.sign([signer, ...additionalSigners]); const txid = yield connection.sendTransaction(transaction, { maxRetries: 5, skipPreflight: skipPreflight ? true : false, }); const confirmation = yield connection.confirmTransaction({ signature: txid, blockhash: latestBlockhash.blockhash, lastValidBlockHeight: latestBlockhash.lastValidBlockHeight, }); console.log(`txid ${txid}`); if (confirmation.value.err) { throw new Error(' ❌ - Transaction not confirmed.'); } }); exports.createAndSendV0Tx = createAndSendV0Tx; const findTokenRecordPda = (mintPubkey, token) => { return anchor_1.web3.PublicKey.findProgramAddressSync([ Buffer.from(constants_1.METADATA_PREFIX), constants_1.METADATA_PROGRAM_PUBKEY.toBuffer(), mintPubkey.toBuffer(), Buffer.from(constants_1.TOKEN_RECORD), token.toBuffer(), ], constants_1.METADATA_PROGRAM_PUBKEY)[0]; }; exports.findTokenRecordPda = findTokenRecordPda; const getMetaplexMetadata = (mintPubkey) => { return anchor_1.web3.PublicKey.findProgramAddressSync([Buffer.from(constants_1.METADATA_PREFIX), constants_1.METADATA_PROGRAM_PUBKEY.toBuffer(), mintPubkey.toBuffer()], constants_1.METADATA_PROGRAM_PUBKEY)[0]; }; exports.getMetaplexMetadata = getMetaplexMetadata; const findRuleSetPDA = (payer, name) => __awaiter(void 0, void 0, void 0, function* () { return (yield anchor_1.web3.PublicKey.findProgramAddress([Buffer.from('rule_set'), payer.toBuffer(), Buffer.from(name)], constants_1.AUTHORIZATION_RULES_PROGRAM))[0]; }); exports.findRuleSetPDA = findRuleSetPDA;