UNPKG

@unloc-xyz/unloc-sdk

Version:
1,014 lines 45.9 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; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MINT_LAYOUT = exports.ACCOUNT_LAYOUT = exports.NFTMetadata = exports.MultipleNFT = exports.getOfferBalance = exports.logObject = exports.checkWalletATA = exports.addTokenAccountInstruction = exports.getLoanSubOffersKeysByState = exports.SubOfferState = exports.OfferState = exports.claimExpiredCollateral = exports.claimLoanCollateral = exports.repayLoan = exports.acceptLoanOffer = exports.acceptLoanOfferByVoting = exports.cancelLoanSubOffer = exports.updateLoanSubOfferByStaking = exports.updateLoanSubOffer = exports.createLoanSubOfferByStaking = exports.createLoanSubOffer = exports.cancelLoanOffer = exports.setLoanOffer = exports.claimRewards = exports.depositRewards = exports.setLoanInternalInfo = exports.setLoanGlobalState = exports.getLoanSubOfferMultiple = exports.getAllLoanSubOffers = exports.getLoanSubOfferList = exports.getLoanSubOffer = exports.getLoanOffersBy = exports.getLoanOffer = exports.getLoanOfferMultiple = exports.getLoanOfferList = exports.getCurrentVotingKey = exports.getLoanGlobalState = exports.initLoanProgram = exports.programId = exports.programProvider = exports.program = void 0; const anchor = __importStar(require("@project-serum/anchor")); const borsh_1 = require("@project-serum/borsh"); const spl_token_1 = require("@solana/spl-token"); const unloc_loan_1 = require("../types/unloc_loan"); const global_config_1 = require("../global-config"); const web3_js_1 = require("@solana/web3.js"); const bytes_1 = require("@project-serum/anchor/dist/cjs/utils/bytes"); const mpl_token_metadata_1 = require("@metaplex-foundation/mpl-token-metadata"); const axios_1 = __importDefault(require("axios")); const voting_1 = require("./../voting"); const utils_1 = require("./../utils"); exports.program = null; exports.programProvider = null; exports.programId = null; const GLOBAL_STATE_TAG = Buffer.from('GLOBAL_STATE_SEED'); const OFFER_TAG = Buffer.from('OFFER_SEED'); const SUB_OFFER_TAG = Buffer.from('SUB_OFFER_SEED'); const NFT_VAULT_TAG = Buffer.from('NFT_VAULT_SEED'); const OFFER_VAULT_TAG = Buffer.from('OFFER_VAULT_SEED'); const TREASURY_VAULT_TAG = Buffer.from('TREASURY_VAULT_SEED'); const REWARD_VAULT_TAG = Buffer.from('REWARD_VAULT_SEED'); const USER_REWARD_TAG = Buffer.from('LENDER_REWARD_SEED'); const WSOL_MINT = new anchor.web3.PublicKey('So11111111111111111111111111111111111111112'); // This command makes an Lottery const initLoanProgram = (wallet, connection = utils_1.SOLANA_CONNECTION, pid = global_config_1.NFT_LOAN_PID) => { if (exports.program != null) { return; } exports.programId = pid; const provider = new anchor.AnchorProvider(connection, wallet, { skipPreflight: true }); exports.programProvider = provider; // Generate the program client from IDL. exports.program = new anchor.Program(unloc_loan_1.IDL, exports.programId, provider); }; exports.initLoanProgram = initLoanProgram; // initLoanProgram(SOLANA_CONNECTION, Keypair.generate()) const getLoanGlobalState = async () => { const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); return await exports.program.account.globalState.fetchNullable(globalState); }; exports.getLoanGlobalState = getLoanGlobalState; const getCurrentVotingKey = async () => { const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const globalStateData = await exports.program.account.globalState.fetch(globalState); const currentVotingNum = globalStateData === null || globalStateData === void 0 ? void 0 : globalStateData.currentVotingNum; const votingPid = globalStateData === null || globalStateData === void 0 ? void 0 : globalStateData.votingPid; const voting = await (0, utils_1.pda)([voting_1.VOTING_TAG, currentVotingNum.toArrayLike(Buffer, "be", 8)], votingPid); return voting; }; exports.getCurrentVotingKey = getCurrentVotingKey; const getLoanOfferList = async () => { return await exports.program.account.offer.all(); }; exports.getLoanOfferList = getLoanOfferList; const getLoanOfferMultiple = async (keys) => { return await exports.program.account.offer.fetchMultiple(keys); }; exports.getLoanOfferMultiple = getLoanOfferMultiple; const getLoanOffer = async (key) => { return await exports.program.account.offer.fetchNullable(key); }; exports.getLoanOffer = getLoanOffer; const getLoanOffersBy = async (owner, nftMint, state) => { const filters = []; if (owner) { const filter = { memcmp: { offset: utils_1.discriminatorLen, bytes: owner.toBase58() } }; filters.push(filter); } if (nftMint) { const filter = { memcmp: { offset: utils_1.discriminatorLen + 32, bytes: nftMint.toBase58() } }; filters.push(filter); } if (state) { const filter = { memcmp: { offset: utils_1.discriminatorLen + 96, bytes: bytes_1.bs58.encode([state]) } }; filters.push(filter); } return await exports.program.account.offer.all(filters); }; exports.getLoanOffersBy = getLoanOffersBy; const getLoanSubOffer = async (key) => { const subOffer = await exports.program.account.subOffer.fetchNullable(key); if (subOffer) { const offerKey = subOffer.offer; const offerData = await exports.program.account.offer.fetch(offerKey); if (offerData.startSubOfferNum.toNumber() > subOffer.subOfferNumber.toNumber()) { return null; } } return subOffer; }; exports.getLoanSubOffer = getLoanSubOffer; const getLoanSubOfferList = async (offer, nftMint, state) => { const accountName = 'subOffer'; const filters = []; if (offer) { const filter = { memcmp: { offset: utils_1.discriminatorLen + 97, bytes: offer.toBase58() } }; filters.push(filter); } if (nftMint) { const filter = { memcmp: { offset: utils_1.discriminatorLen + 32, bytes: nftMint.toBase58() } }; filters.push(filter); } if (state) { const filter = { memcmp: { offset: utils_1.discriminatorLen + 96, bytes: bytes_1.bs58.encode([state]) } }; filters.push(filter); } const subOffers = await exports.program.account.subOffer.all(filters); const result = []; for (let i = 0; i < subOffers.length; i++) { const offerKey = subOffers[i].account.offer; const offerData = await exports.program.account.offer.fetch(offerKey); if (offerData.startSubOfferNum.toNumber() <= subOffers[i].account.subOfferNumber.toNumber()) { result.push(subOffers[i]); } } return result; }; exports.getLoanSubOfferList = getLoanSubOfferList; const getAllLoanSubOffers = async () => { const subOffers = await exports.program.account.subOffer.all(); const result = []; for (let i = 0; i < subOffers.length; i++) { const offerKey = subOffers[i].account.offer; const offerData = await exports.program.account.offer.fetch(offerKey); if (offerData.startSubOfferNum.toNumber() <= subOffers[i].account.subOfferNumber.toNumber()) { result.push(subOffers[i]); } } return result; }; exports.getAllLoanSubOffers = getAllLoanSubOffers; const getLoanSubOfferMultiple = async (keys, offerState) => { const subOffers = await exports.program.account.subOffer.fetchMultiple(keys); // Filter for nulls and get the offer address const offerAddresses = subOffers.filter((subOffer) => subOffer).map((subOffer) => subOffer.offer); // Get all offer data in a single call instead of a loop, filter for nulls const offers = (await exports.program.account.offer.fetchMultiple(offerAddresses)).filter((data) => data); const result = []; for (let i = 0; i < subOffers.length; i++) { if (subOffers[i]) { const offerKey = subOffers[i].offer; const offerKeyIndex = offerAddresses.findIndex((address) => address.equals(offerKey)); const offerData = offers[offerKeyIndex]; // If we want to, check the offer state too. // Suboffer can be proposed when the offer isn't, so that's why we check the state on the offer, not just the suboffer. // Be careful, offerState = 0 can coerce to false. if (typeof offerState === 'number') { if (offerData.startSubOfferNum.toNumber() <= subOffers[i].subOfferNumber.toNumber() && offerData.state === offerState) { result.push({ ...subOffers[i], subOfferKey: keys[i] }); } } else { if (offerData.startSubOfferNum.toNumber() <= subOffers[i].subOfferNumber.toNumber()) { result.push({ ...subOffers[i], subOfferKey: keys[i] }); } } } } return result; }; exports.getLoanSubOfferMultiple = getLoanSubOfferMultiple; const setLoanGlobalState = async (accruedInterestNumerator, denominator, aprNumerator, expireLoanDuration, rewardPerSol, rewardPerUsdc, lenderRewardsPercentage, rewardMint, treasury, signer = exports.programProvider.wallet.publicKey, signers = []) => { const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const rewardVault = await (0, utils_1.pda)([REWARD_VAULT_TAG], exports.programId); const superOwner = signer; try { const tx = await exports.program.rpc.setGlobalState(accruedInterestNumerator, denominator, aprNumerator, expireLoanDuration, rewardPerSol, rewardPerUsdc, lenderRewardsPercentage, { accounts: { superOwner, globalState, rewardMint, rewardVault, newSuperOwner: superOwner, treasuryWallet: treasury, ...utils_1.defaults }, signers }); // eslint-disable-next-line no-console console.log('setGlobalState tx = ', tx); } catch (e) { console.log(e); } }; exports.setLoanGlobalState = setLoanGlobalState; const setLoanInternalInfo = async (unlocStakingPid, unlocStakingPoolId, votingPid, tokenMetadataPid, currentVotingNum, signer = exports.programProvider.wallet.publicKey, signers = []) => { const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const superOwner = signer; try { const tx = await exports.program.rpc.setInternalInfo(unlocStakingPid, unlocStakingPoolId, votingPid, tokenMetadataPid, currentVotingNum, { accounts: { superOwner, globalState, }, signers }); // eslint-disable-next-line no-console console.log('setInternalInfo tx = ', tx); } catch (e) { console.log(e); } }; exports.setLoanInternalInfo = setLoanInternalInfo; const depositRewards = async (amount, signer = exports.programProvider.wallet.publicKey, signers = []) => { const rewardMint = global_config_1.UNLOC_MINT; const rewardVault = await (0, utils_1.pda)([REWARD_VAULT_TAG], exports.programId); const authority = signer; const userRewardVault = await (0, exports.checkWalletATA)(rewardMint.toBase58(), exports.programProvider.connection, authority); const tx = await exports.program.rpc.depositRewards(amount, { accounts: { authority, rewardVault, userRewardVault, ...utils_1.defaults }, signers }); // eslint-disable-next-line no-console console.log('deposit rewards tx = ', tx); }; exports.depositRewards = depositRewards; const claimRewards = async (userReward, signer = exports.programProvider.wallet.publicKey, signers = []) => { const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const rewardMint = global_config_1.UNLOC_MINT; const rewardVault = await (0, utils_1.pda)([REWARD_VAULT_TAG], exports.programId); const authority = signer; let userRewardVault = await (0, exports.checkWalletATA)(rewardMint.toBase58(), exports.programProvider.connection, authority); const preInstructions = []; if (!userRewardVault) { userRewardVault = await (0, exports.addTokenAccountInstruction)(rewardMint, authority, preInstructions, signer, signers); } const tx = await exports.program.rpc.claimRewards({ accounts: { authority, globalState, rewardVault, userReward, userRewardVault, ...utils_1.defaults }, preInstructions, signers }); // eslint-disable-next-line no-console console.log('claim rewards tx = ', tx); }; exports.claimRewards = claimRewards; const setLoanOffer = async (nftMint, signer = exports.programProvider.wallet.publicKey, signers = []) => { const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const borrowerNftVault = await (0, exports.checkWalletATA)(nftMint.toBase58(), exports.programProvider.connection, signer); const borrower = signer; const offer = await (0, utils_1.pda)([OFFER_TAG, borrower.toBuffer(), nftMint.toBuffer()], exports.programId); const nftMetadata = await mpl_token_metadata_1.Metadata.getPDA(nftMint); const edition = await mpl_token_metadata_1.Edition.getPDA(nftMint); try { const tx = await exports.program.rpc.setOffer({ accounts: { borrower, globalState, offer, nftMint, nftMetadata, edition, userVault: borrowerNftVault, metadataProgram: global_config_1.TOKEN_META_PID, ...utils_1.defaults }, signers }); // eslint-disable-next-line no-console console.log('setOffer tx = ', tx); } catch (e) { console.log(e); } }; exports.setLoanOffer = setLoanOffer; const cancelLoanOffer = async (nftMint, signer = exports.programProvider.wallet.publicKey, signers = []) => { const borrower = signer; const offer = await (0, utils_1.pda)([OFFER_TAG, borrower.toBuffer(), nftMint.toBuffer()], exports.programId); let borrowerNftVault = await (0, exports.checkWalletATA)(nftMint.toBase58(), exports.programProvider.connection, borrower); const preInstructions = []; if (!borrowerNftVault) { borrowerNftVault = await (0, exports.addTokenAccountInstruction)(nftMint, borrower, preInstructions, signer, signers); } const edition = await mpl_token_metadata_1.Edition.getPDA(nftMint); try { const tx = await exports.program.rpc.cancelOffer({ accounts: { borrower, offer, nftMint, edition, userVault: borrowerNftVault, metadataProgram: global_config_1.TOKEN_META_PID, ...utils_1.defaults }, preInstructions, signers }); // eslint-disable-next-line no-console console.log('cancelOffer tx = ', tx); } catch (e) { console.log(e); } }; exports.cancelLoanOffer = cancelLoanOffer; const createLoanSubOffer = async (offerAmount, loanDuration, minRepaidNumerator, aprNumerator, nftMint, offerMint, signer = exports.programProvider.wallet.publicKey, signers = []) => { if (offerMint.equals(spl_token_1.NATIVE_MINT)) { offerMint = WSOL_MINT; } const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const borrower = signer; const offer = await (0, utils_1.pda)([OFFER_TAG, borrower.toBuffer(), nftMint.toBuffer()], exports.programId); const offerData = await exports.program.account.offer.fetch(offer); const subOfferNumer = offerData.subOfferCount; const subOffer = await (0, utils_1.pda)([SUB_OFFER_TAG, offer.toBuffer(), subOfferNumer.toArrayLike(Buffer, 'be', 8)], exports.programId); const treasuryVault = await (0, utils_1.pda)([TREASURY_VAULT_TAG, offerMint.toBuffer()], exports.programId); const globalStateData = await exports.program.account.globalState.fetch(globalState); const treasuryWallet = globalStateData.treasuryWallet; try { const tx = await exports.program.rpc.setSubOffer(offerAmount, subOfferNumer, loanDuration, minRepaidNumerator, aprNumerator, { accounts: { borrower, globalState, offer, subOffer, offerMint, treasuryWallet, treasuryVault, ...utils_1.defaults }, signers }); // eslint-disable-next-line no-console console.log('createSubOffer tx = ', tx); } catch (e) { console.log(e); } }; exports.createLoanSubOffer = createLoanSubOffer; const createLoanSubOfferByStaking = async (offerAmount, loanDuration, minRepaidNumerator, aprNumerator, nftMint, offerMint, signer = exports.programProvider.wallet.publicKey, signers = []) => { if (offerMint.equals(spl_token_1.NATIVE_MINT)) { offerMint = WSOL_MINT; } const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const borrower = signer; const offer = await (0, utils_1.pda)([OFFER_TAG, borrower.toBuffer(), nftMint.toBuffer()], exports.programId); const offerData = await exports.program.account.offer.fetch(offer); const subOfferNumer = offerData.subOfferCount; const subOffer = await (0, utils_1.pda)([SUB_OFFER_TAG, offer.toBuffer(), subOfferNumer.toArrayLike(Buffer, 'be', 8)], exports.programId); const treasuryVault = await (0, utils_1.pda)([TREASURY_VAULT_TAG, offerMint.toBuffer()], exports.programId); const globalStateData = await exports.program.account.globalState.fetch(globalState); const stakingUser = await (0, utils_1.pda)([globalStateData.unlocStakingPoolId.toBuffer(), borrower.toBuffer()], globalStateData.unlocStakingPid); const treasuryWallet = globalStateData.treasuryWallet; try { const tx = await exports.program.rpc.setSubOfferByStaking(offerAmount, subOfferNumer, loanDuration, minRepaidNumerator, aprNumerator, { accounts: { borrower, globalState, offer, subOffer, stakingUser, offerMint, treasuryWallet, treasuryVault, ...utils_1.defaults }, signers }); // eslint-disable-next-line no-console console.log('createSubOffer tx = ', tx); } catch (e) { console.log(e); } }; exports.createLoanSubOfferByStaking = createLoanSubOfferByStaking; const updateLoanSubOffer = async (offerAmount, loanDuration, minRepaidNumerator, aprNumerator, subOffer, signer = exports.programProvider.wallet.publicKey, signers = []) => { const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const borrower = signer; const subOfferData = await exports.program.account.subOffer.fetch(subOffer); const offer = await (0, utils_1.pda)([OFFER_TAG, borrower.toBuffer(), subOfferData.nftMint.toBuffer()], exports.programId); const subOfferNumer = subOfferData.subOfferNumber; const offerMint = subOfferData.offerMint; const treasuryVault = await (0, utils_1.pda)([TREASURY_VAULT_TAG, subOfferData.offerMint.toBuffer()], exports.programId); const globalStateData = await exports.program.account.globalState.fetch(globalState); const treasuryWallet = globalStateData.treasuryWallet; try { const tx = await exports.program.rpc.setSubOffer(offerAmount, subOfferNumer, loanDuration, minRepaidNumerator, aprNumerator, { accounts: { borrower, globalState, offer, subOffer, offerMint, treasuryWallet, treasuryVault, ...utils_1.defaults }, signers }); // eslint-disable-next-line no-console console.log('updateSubOffer tx = ', tx); } catch (e) { console.log(e); } }; exports.updateLoanSubOffer = updateLoanSubOffer; const updateLoanSubOfferByStaking = async (offerAmount, loanDuration, minRepaidNumerator, aprNumerator, subOffer, signer = exports.programProvider.wallet.publicKey, signers = []) => { const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const borrower = signer; const subOfferData = await exports.program.account.subOffer.fetch(subOffer); const offer = await (0, utils_1.pda)([OFFER_TAG, borrower.toBuffer(), subOfferData.nftMint.toBuffer()], exports.programId); const subOfferNumer = subOfferData.subOfferNumber; const offerMint = subOfferData.offerMint; const treasuryVault = await (0, utils_1.pda)([TREASURY_VAULT_TAG, subOfferData.offerMint.toBuffer()], exports.programId); const globalStateData = await exports.program.account.globalState.fetch(globalState); const stakingUser = await (0, utils_1.pda)([globalStateData.unlocStakingPoolId.toBuffer(), borrower.toBuffer()], globalStateData.unlocStakingPid); const treasuryWallet = globalStateData.treasuryWallet; try { const tx = await exports.program.rpc.setSubOfferByStaking(offerAmount, subOfferNumer, loanDuration, minRepaidNumerator, aprNumerator, { accounts: { borrower, globalState, offer, subOffer, stakingUser, offerMint, treasuryWallet, treasuryVault, ...utils_1.defaults }, signers }); // eslint-disable-next-line no-console console.log('updateSubOffer tx = ', tx); } catch (e) { console.log(e); } }; exports.updateLoanSubOfferByStaking = updateLoanSubOfferByStaking; const cancelLoanSubOffer = async (subOffer, signer = exports.programProvider.wallet.publicKey, signers = []) => { const borrower = signer; const subOfferData = await exports.program.account.subOffer.fetch(subOffer); const offer = await (0, utils_1.pda)([OFFER_TAG, borrower.toBuffer(), subOfferData.nftMint.toBuffer()], exports.programId); try { const tx = await exports.program.rpc.cancelSubOffer({ accounts: { borrower, offer, subOffer }, signers }); // eslint-disable-next-line no-console console.log('cancelSubOffer tx = ', tx); } catch (e) { console.log(e); } }; exports.cancelLoanSubOffer = cancelLoanSubOffer; const acceptLoanOfferByVoting = async (subOffer, signer = exports.programProvider.wallet.publicKey, signers = []) => { const lender = signer; const subOfferData = await exports.program.account.subOffer.fetch(subOffer); const offer = subOfferData.offer; const offerMint = subOfferData.offerMint; const offerData = await exports.program.account.offer.fetch(subOfferData.offer); const borrower = offerData.borrower; let borrowerOfferVault = await (0, exports.checkWalletATA)(offerMint.toBase58(), exports.programProvider.connection, borrower); let lenderOfferVault = await (0, exports.checkWalletATA)(offerMint.toBase58(), exports.programProvider.connection, lender); const preInstructions = []; const postInstructions = []; if (offerMint.equals(WSOL_MINT)) { const treasuryVault = await (0, utils_1.pda)([TREASURY_VAULT_TAG, offerMint.toBuffer()], exports.programId); lenderOfferVault = treasuryVault; borrowerOfferVault = treasuryVault; } else { if (!borrowerOfferVault) { console.log("borrower doesn't have offer token account!"); borrowerOfferVault = await (0, exports.addTokenAccountInstruction)(offerMint, borrower, preInstructions, signer, signers); } if (!lenderOfferVault) { console.log("lender doesn't have offer token!"); return; } } const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const globalStateData = await exports.program.account.globalState.fetch(globalState); const userReward = await (0, utils_1.pda)([USER_REWARD_TAG, lender.toBuffer(), borrower.toBuffer(), subOffer.toBuffer()], exports.programId); const votingPid = globalStateData.votingPid; const currentVotingKey = await (0, exports.getCurrentVotingKey)(); const votingItemKey = await (0, utils_1.pda)([voting_1.VOTING_ITEM_TAG, currentVotingKey.toBuffer(), offerData.collection.toBuffer()], votingPid); try { const tx = await exports.program.rpc.acceptOfferByVoting({ accounts: { lender, borrower, globalState, offer, subOffer, offerMint, userReward, voting: currentVotingKey, votingItem: votingItemKey, borrowerOfferVault, lenderOfferVault, ...utils_1.defaults }, preInstructions, postInstructions, signers }); // eslint-disable-next-line no-console console.log('acceptOffer tx = ', tx); } catch (e) { console.log(e); } }; exports.acceptLoanOfferByVoting = acceptLoanOfferByVoting; const acceptLoanOffer = async (subOffer, signer = exports.programProvider.wallet.publicKey, signers = []) => { const lender = signer; const subOfferData = await exports.program.account.subOffer.fetch(subOffer); const offer = subOfferData.offer; const offerMint = subOfferData.offerMint; const offerData = await exports.program.account.offer.fetch(subOfferData.offer); const borrower = offerData.borrower; let borrowerOfferVault = await (0, exports.checkWalletATA)(offerMint.toBase58(), exports.programProvider.connection, borrower); let lenderOfferVault = await (0, exports.checkWalletATA)(offerMint.toBase58(), exports.programProvider.connection, lender); const preInstructions = []; const postInstructions = []; if (offerMint.equals(WSOL_MINT)) { const treasuryVault = await (0, utils_1.pda)([TREASURY_VAULT_TAG, offerMint.toBuffer()], exports.programId); lenderOfferVault = treasuryVault; borrowerOfferVault = treasuryVault; } else { if (!borrowerOfferVault) { console.log("borrower doesn't have offer token account!"); borrowerOfferVault = await (0, exports.addTokenAccountInstruction)(offerMint, borrower, preInstructions, signer, signers); } if (!lenderOfferVault) { console.log("lender doesn't have offer token!"); return; } } const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const userReward = await (0, utils_1.pda)([USER_REWARD_TAG, lender.toBuffer(), borrower.toBuffer(), subOffer.toBuffer()], exports.programId); try { const tx = await exports.program.rpc.acceptOffer({ accounts: { lender, borrower, globalState, offer, subOffer, offerMint, userReward, borrowerOfferVault, lenderOfferVault, ...utils_1.defaults }, preInstructions, postInstructions, signers }); // eslint-disable-next-line no-console console.log('acceptOffer tx = ', tx); } catch (e) { console.log(e); } }; exports.acceptLoanOffer = acceptLoanOffer; const repayLoan = async (subOffer, signer = exports.programProvider.wallet.publicKey, signers = []) => { const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const borrower = signer; const globalStateData = await exports.program.account.globalState.fetch(globalState); const treasuryWallet = globalStateData.treasuryWallet; const subOfferData = await exports.program.account.subOffer.fetch(subOffer); const offer = subOfferData.offer; const lender = subOfferData.lender; const offerData = await exports.program.account.offer.fetch(offer); const offerMint = subOfferData.offerMint; const nftMint = offerData.nftMint; const treasuryVault = await (0, utils_1.pda)([TREASURY_VAULT_TAG, offerMint.toBuffer()], exports.programId); let borrowerOfferVault = await (0, exports.checkWalletATA)(offerMint.toBase58(), exports.programProvider.connection, borrower); let borrowerNftVault = await (0, exports.checkWalletATA)(nftMint.toBase58(), exports.programProvider.connection, borrower); let lenderOfferVault = await (0, exports.checkWalletATA)(offerMint.toBase58(), exports.programProvider.connection, lender); const preInstructions = []; const postInstructions = []; if (offerMint.equals(WSOL_MINT)) { const treasuryVault = await (0, utils_1.pda)([TREASURY_VAULT_TAG, offerMint.toBuffer()], exports.programId); lenderOfferVault = treasuryVault; borrowerOfferVault = treasuryVault; } if (!borrowerOfferVault) { console.log("borrower doesn't have offer token!"); return; } if (!borrowerNftVault) { console.log("borrower doesn't have nft token token account!"); borrowerNftVault = await (0, exports.addTokenAccountInstruction)(nftMint, borrower, preInstructions, signer, signers); } if (!lenderOfferVault) { console.log("lender doesn't have offer token account!", lender.toBase58()); lenderOfferVault = await (0, exports.addTokenAccountInstruction)(offerMint, lender, preInstructions, signer, signers); } const userReward = await (0, utils_1.pda)([USER_REWARD_TAG, lender.toBuffer(), borrower.toBuffer(), subOffer.toBuffer()], exports.programId); const edition = await mpl_token_metadata_1.Edition.getPDA(nftMint); try { const tx = await exports.program.rpc.repayLoan({ accounts: { borrower, lender, globalState, treasuryWallet, offer, subOffer, nftMint, edition, userReward, borrowerNftVault, lenderOfferVault, borrowerOfferVault, treasuryVault, metadataProgram: global_config_1.TOKEN_META_PID, ...utils_1.defaults }, preInstructions, postInstructions, signers }); // eslint-disable-next-line no-console console.log('repayLoan tx = ', tx); } catch (e) { console.log(e); } }; exports.repayLoan = repayLoan; const claimLoanCollateral = async (subOffer, signer = exports.programProvider.wallet.publicKey, signers = []) => { const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const lender = signer; const globalStateData = await exports.program.account.globalState.fetch(globalState); const treasuryWallet = globalStateData.treasuryWallet; const subOfferData = await exports.program.account.subOffer.fetch(subOffer); const offer = subOfferData.offer; const offerData = await exports.program.account.offer.fetch(offer); const offerMint = subOfferData.offerMint; const nftMint = offerData.nftMint; const treasuryVault = await (0, utils_1.pda)([TREASURY_VAULT_TAG, offerMint.toBuffer()], exports.programId); let borrowerNftVault = await (0, exports.checkWalletATA)(nftMint.toBase58(), exports.programProvider.connection, offerData.borrower); let lenderNftVault = await (0, exports.checkWalletATA)(nftMint.toBase58(), exports.programProvider.connection, lender); let lenderOfferVault = await (0, exports.checkWalletATA)(offerMint.toBase58(), exports.programProvider.connection, lender); const preInstructions = []; const postInstructions = []; if (offerMint.equals(WSOL_MINT)) { const treasuryVault = await (0, utils_1.pda)([TREASURY_VAULT_TAG, offerMint.toBuffer()], exports.programId); lenderOfferVault = treasuryVault; } if (!lenderNftVault) { console.log("lender doesn't have nft token token account!"); lenderNftVault = await (0, exports.addTokenAccountInstruction)(nftMint, lender, preInstructions, signer, signers); } if (!lenderOfferVault) { console.log("lender doesn't have offer token account!", lender.toBase58()); lenderOfferVault = await (0, exports.addTokenAccountInstruction)(offerMint, lender, preInstructions, signer, signers); } const edition = await mpl_token_metadata_1.Edition.getPDA(nftMint); try { const tx = await exports.program.rpc.claimCollateral({ accounts: { lender, globalState, treasuryWallet, offer, subOffer, nftMint, edition, lenderNftVault, borrowerNftVault, lenderOfferVault, treasuryVault, metadataProgram: global_config_1.TOKEN_META_PID, ...utils_1.defaults }, preInstructions, postInstructions, signers }); // eslint-disable-next-line no-console console.log('claimCollateral tx = ', tx); } catch (e) { console.log(e); } }; exports.claimLoanCollateral = claimLoanCollateral; // super owner can call this function const claimExpiredCollateral = async (subOffer, signer = exports.programProvider.wallet.publicKey, signers = []) => { const globalState = await (0, utils_1.pda)([GLOBAL_STATE_TAG], exports.programId); const globalStateData = await exports.program.account.globalState.fetch(globalState); const treasuryWallet = globalStateData.treasuryWallet; const subOfferData = await exports.program.account.subOffer.fetch(subOffer); const offer = subOfferData.offer; const offerData = await exports.program.account.offer.fetch(offer); const nftMint = offerData.nftMint; let userNftVault = await (0, exports.checkWalletATA)(nftMint.toBase58(), exports.programProvider.connection, signer); const preInstructions = []; if (!userNftVault) { userNftVault = await (0, exports.addTokenAccountInstruction)(nftMint, signer, preInstructions, signer, signers); } let borrowerNftVault = await (0, exports.checkWalletATA)(nftMint.toBase58(), exports.programProvider.connection, offerData.borrower); const edition = await mpl_token_metadata_1.Edition.getPDA(nftMint); try { const tx = await exports.program.rpc.claimExpiredCollateral({ accounts: { superOwner: signer, globalState, treasuryWallet, offer, subOffer, nftMint, edition, userNftVault, borrowerNftVault, metadataProgram: global_config_1.TOKEN_META_PID, ...utils_1.defaults }, preInstructions, signers }); // eslint-disable-next-line no-console console.log('claimExpiredCollateral tx = ', tx); } catch (e) { console.log(e); } }; exports.claimExpiredCollateral = claimExpiredCollateral; var OfferState; (function (OfferState) { OfferState[OfferState["Proposed"] = 0] = "Proposed"; OfferState[OfferState["Accepted"] = 1] = "Accepted"; OfferState[OfferState["Expired"] = 2] = "Expired"; OfferState[OfferState["Fulfilled"] = 3] = "Fulfilled"; OfferState[OfferState["NFTClaimed"] = 4] = "NFTClaimed"; OfferState[OfferState["Canceled"] = 5] = "Canceled"; })(OfferState = exports.OfferState || (exports.OfferState = {})); var SubOfferState; (function (SubOfferState) { SubOfferState[SubOfferState["Proposed"] = 0] = "Proposed"; SubOfferState[SubOfferState["Accepted"] = 1] = "Accepted"; SubOfferState[SubOfferState["Expired"] = 2] = "Expired"; SubOfferState[SubOfferState["Fulfilled"] = 3] = "Fulfilled"; SubOfferState[SubOfferState["LoanPaymentClaimed"] = 4] = "LoanPaymentClaimed"; SubOfferState[SubOfferState["Canceled"] = 5] = "Canceled"; })(SubOfferState = exports.SubOfferState || (exports.SubOfferState = {})); const getLoanSubOffersKeysByState = async (state) => { try { const accountName = 'subOffer'; const data = await exports.programProvider.connection.getProgramAccounts(exports.programId, { dataSlice: { offset: 0, length: 0 }, filters: [ { memcmp: exports.program.account.subOffer.coder.accounts.memcmp(accountName) }, { memcmp: { offset: utils_1.discriminatorLen + 96, bytes: bytes_1.bs58.encode(state) } } // add filters for nftMint, APR, Duration, Amount and this function will be glorious ] }); return data.map((offer) => offer.pubkey); } catch (e) { console.log(e); } }; exports.getLoanSubOffersKeysByState = getLoanSubOffersKeysByState; const addTokenAccountInstruction = async (mint, owner, instructions, signer, signers, rent = 0) => { const newKeypair = web3_js_1.Keypair.generate(); const rentForTokenAccount = await spl_token_1.Token.getMinBalanceRentForExemptAccount(exports.programProvider.connection); instructions.push(web3_js_1.SystemProgram.createAccount({ fromPubkey: signer, newAccountPubkey: newKeypair.publicKey, lamports: rent > 0 ? rent : rentForTokenAccount, space: exports.ACCOUNT_LAYOUT.span, programId: spl_token_1.TOKEN_PROGRAM_ID })); const instruction = spl_token_1.Token.createInitAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, mint, newKeypair.publicKey, owner); instructions.push(instruction); signers.push(newKeypair); return newKeypair.publicKey; }; exports.addTokenAccountInstruction = addTokenAccountInstruction; const checkWalletATA = async (mint, connection = exports.programProvider.connection, walletPubkey = exports.programProvider.wallet.publicKey) => { const parsedTokenAccounts = await connection.getParsedTokenAccountsByOwner(walletPubkey, { programId: spl_token_1.TOKEN_PROGRAM_ID }, 'confirmed'); let result = null; let maxAmount = 0; parsedTokenAccounts.value.forEach(async (tokenAccountInfo) => { const tokenAccountPubkey = tokenAccountInfo.pubkey; const parsedInfo = tokenAccountInfo.account.data.parsed.info; const mintAddress = parsedInfo.mint; const amount = parsedInfo.tokenAmount.uiAmount; if (mintAddress === mint && amount >= maxAmount) { result = tokenAccountPubkey; maxAmount = amount; } }); return result; }; exports.checkWalletATA = checkWalletATA; const logObject = (title, obj) => { console.log(title, obj); }; exports.logObject = logObject; const getOfferBalance = async (subOffer, connection = exports.programProvider.connection, walletPubkey = exports.programProvider.wallet.publicKey) => { try { const tokenAccount = await (0, utils_1.pda)([OFFER_VAULT_TAG, subOffer.toBuffer()], exports.programId); const balance = (await connection.getTokenAccountBalance(tokenAccount)).value.uiAmount; return balance; } catch (e) { console.log(e); } return 0; }; exports.getOfferBalance = getOfferBalance; // --------------------utilities--------------------- class MultipleNFT { constructor(keys) { this.metadatas = []; this.mints = keys; } async initialize() { if (this.metadatas.length == 0) { const metadataPDAs = []; for (let i = 0; i < this.mints.length; i++) { const metadataPDA = await mpl_token_metadata_1.Metadata.getPDA(this.mints[i]); metadataPDAs.push(metadataPDA); } let i = 0; const metaInfos = await mpl_token_metadata_1.Metadata.getInfos(exports.programProvider.connection, metadataPDAs); metaInfos.forEach((value, key, map) => { const metadata = mpl_token_metadata_1.MetadataData.deserialize(value.data); const nftMetadata = new NFTMetadata(this.mints[i], metadataPDAs[i], metadata); this.metadatas.push(nftMetadata); i++; }); } } getNftMeta(mint) { for (let i = 0; i < this.metadatas.length; i++) { if (this.metadatas[i].mint === mint.toBase58()) { return this.metadatas[i]; } } return null; } async initArweavedata() { for (let i = 0; i < this.metadatas.length; i++) { await this.metadatas[i].getAreaveMetadata(); } } } exports.MultipleNFT = MultipleNFT; class NFTMetadata { constructor(mint, metadataPDA, onChainMetadata) { this.mint = ''; this.metadataPDA = ''; this.onChainMetadata = null; this.arweaveMetadata = null; this.masterEdition = null; this.mint = mint.toBase58(); this.metadataPDA = metadataPDA.toBase58(); this.onChainMetadata = onChainMetadata; } async getAreaveMetadata() { if (this.arweaveMetadata === null) { try { const arweaveData = await axios_1.default.get(this.onChainMetadata.data.uri); if (arweaveData) { this.arweaveMetadata = arweaveData.data; } } catch (e) { // eslint-disable-next-line no-console console.log(e); } } return this.arweaveMetadata; } currentAreaveMetadata() { return this.arweaveMetadata; } async getMasterEdition() { if (this.arweaveMetadata === null) { const masterEditionPDA = await mpl_token_metadata_1.Edition.getPDA(new web3_js_1.PublicKey(this.mint)); const editionAccountInfo = await exports.programProvider.connection.getAccountInfo(masterEditionPDA); if (editionAccountInfo) { const key = editionAccountInfo === null || editionAccountInfo === void 0 ? void 0 : editionAccountInfo.data[0]; let masterEditionData; let data; switch (key) { case mpl_token_metadata_1.MetadataKey.MasterEditionV1: case mpl_token_metadata_1.MetadataKey.MasterEditionV2: ; ({ data } = new mpl_token_metadata_1.MasterEdition(masterEditionPDA, editionAccountInfo)); masterEditionData = data; break; default: masterEditionData = undefined; break; } this.masterEdition = { masterEditionPDA: masterEditionPDA.toString(), masterEditionData }; } } return this.masterEdition; } } exports.NFTMetadata = NFTMetadata; exports.ACCOUNT_LAYOUT = (0, borsh_1.struct)([ (0, borsh_1.publicKey)('mint'), (0, borsh_1.publicKey)('owner'), (0, borsh_1.u64)('amount'), (0, borsh_1.u32)('delegateOption'), (0, borsh_1.publicKey)('delegate'), (0, borsh_1.u8)('state'), (0, borsh_1.u32)('isNativeOption'), (0, borsh_1.u64)('isNative'), (0, borsh_1.u64)('delegatedAmount'), (0, borsh_1.u32)('closeAuthorityOption'), (0, borsh_1.publicKey)('closeAuthority') ]); exports.MINT_LAYOUT = (0, borsh_1.struct)([ (0, borsh_1.u32)('mintAuthorityOption'), (0, borsh_1.publicKey)('mintAuthority'), (0, borsh_1.u64)('supply'), (0, borsh_1.u8)('decimals'), (0, borsh_1.bool)('initialized'), (0, borsh_1.u32)('freezeAuthorityOption'), (0, borsh_1.publicKey)('freezeAuthority') ]); //# sourceMappingURL=index.js.map