UNPKG

@unloc-xyz/unloc-sdk

Version:
952 lines 39 kB
import * as anchor from '@project-serum/anchor'; import { bool, publicKey, struct, u32, u64, u8 } from '@project-serum/borsh'; import { NATIVE_MINT, Token, TOKEN_PROGRAM_ID } from '@solana/spl-token'; import { IDL as idl } from '../types/unloc_loan'; import { NFT_LOAN_PID, TOKEN_META_PID, UNLOC_MINT } from '../global-config'; import { Keypair, PublicKey, SystemProgram } from '@solana/web3.js'; import { bs58 } from '@project-serum/anchor/dist/cjs/utils/bytes'; import { Edition, MasterEdition, Metadata, MetadataData, MetadataKey } from '@metaplex-foundation/mpl-token-metadata'; import axios from 'axios'; import { VOTING_ITEM_TAG, VOTING_TAG } from './../voting'; import { defaults, discriminatorLen, pda, SOLANA_CONNECTION } from './../utils'; export let program = null; export let programProvider = null; export let 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 export const initLoanProgram = (wallet, connection = SOLANA_CONNECTION, pid = NFT_LOAN_PID) => { if (program != null) { return; } programId = pid; const provider = new anchor.AnchorProvider(connection, wallet, { skipPreflight: true }); programProvider = provider; // Generate the program client from IDL. program = new anchor.Program(idl, programId, provider); }; // initLoanProgram(SOLANA_CONNECTION, Keypair.generate()) export const getLoanGlobalState = async () => { const globalState = await pda([GLOBAL_STATE_TAG], programId); return await program.account.globalState.fetchNullable(globalState); }; export const getCurrentVotingKey = async () => { const globalState = await pda([GLOBAL_STATE_TAG], programId); const globalStateData = await program.account.globalState.fetch(globalState); const currentVotingNum = globalStateData?.currentVotingNum; const votingPid = globalStateData?.votingPid; const voting = await pda([VOTING_TAG, currentVotingNum.toArrayLike(Buffer, "be", 8)], votingPid); return voting; }; export const getLoanOfferList = async () => { return await program.account.offer.all(); }; export const getLoanOfferMultiple = async (keys) => { return await program.account.offer.fetchMultiple(keys); }; export const getLoanOffer = async (key) => { return await program.account.offer.fetchNullable(key); }; export const getLoanOffersBy = async (owner, nftMint, state) => { const filters = []; if (owner) { const filter = { memcmp: { offset: discriminatorLen, bytes: owner.toBase58() } }; filters.push(filter); } if (nftMint) { const filter = { memcmp: { offset: discriminatorLen + 32, bytes: nftMint.toBase58() } }; filters.push(filter); } if (state) { const filter = { memcmp: { offset: discriminatorLen + 96, bytes: bs58.encode([state]) } }; filters.push(filter); } return await program.account.offer.all(filters); }; export const getLoanSubOffer = async (key) => { const subOffer = await program.account.subOffer.fetchNullable(key); if (subOffer) { const offerKey = subOffer.offer; const offerData = await program.account.offer.fetch(offerKey); if (offerData.startSubOfferNum.toNumber() > subOffer.subOfferNumber.toNumber()) { return null; } } return subOffer; }; export const getLoanSubOfferList = async (offer, nftMint, state) => { const accountName = 'subOffer'; const filters = []; if (offer) { const filter = { memcmp: { offset: discriminatorLen + 97, bytes: offer.toBase58() } }; filters.push(filter); } if (nftMint) { const filter = { memcmp: { offset: discriminatorLen + 32, bytes: nftMint.toBase58() } }; filters.push(filter); } if (state) { const filter = { memcmp: { offset: discriminatorLen + 96, bytes: bs58.encode([state]) } }; filters.push(filter); } const subOffers = await program.account.subOffer.all(filters); const result = []; for (let i = 0; i < subOffers.length; i++) { const offerKey = subOffers[i].account.offer; const offerData = await program.account.offer.fetch(offerKey); if (offerData.startSubOfferNum.toNumber() <= subOffers[i].account.subOfferNumber.toNumber()) { result.push(subOffers[i]); } } return result; }; export const getAllLoanSubOffers = async () => { const subOffers = await program.account.subOffer.all(); const result = []; for (let i = 0; i < subOffers.length; i++) { const offerKey = subOffers[i].account.offer; const offerData = await program.account.offer.fetch(offerKey); if (offerData.startSubOfferNum.toNumber() <= subOffers[i].account.subOfferNumber.toNumber()) { result.push(subOffers[i]); } } return result; }; export const getLoanSubOfferMultiple = async (keys, offerState) => { const subOffers = await 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 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; }; export const setLoanGlobalState = async (accruedInterestNumerator, denominator, aprNumerator, expireLoanDuration, rewardPerSol, rewardPerUsdc, lenderRewardsPercentage, rewardMint, treasury, signer = programProvider.wallet.publicKey, signers = []) => { const globalState = await pda([GLOBAL_STATE_TAG], programId); const rewardVault = await pda([REWARD_VAULT_TAG], programId); const superOwner = signer; try { const tx = await program.rpc.setGlobalState(accruedInterestNumerator, denominator, aprNumerator, expireLoanDuration, rewardPerSol, rewardPerUsdc, lenderRewardsPercentage, { accounts: { superOwner, globalState, rewardMint, rewardVault, newSuperOwner: superOwner, treasuryWallet: treasury, ...defaults }, signers }); // eslint-disable-next-line no-console console.log('setGlobalState tx = ', tx); } catch (e) { console.log(e); } }; export const setLoanInternalInfo = async (unlocStakingPid, unlocStakingPoolId, votingPid, tokenMetadataPid, currentVotingNum, signer = programProvider.wallet.publicKey, signers = []) => { const globalState = await pda([GLOBAL_STATE_TAG], programId); const superOwner = signer; try { const tx = await 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); } }; export const depositRewards = async (amount, signer = programProvider.wallet.publicKey, signers = []) => { const rewardMint = UNLOC_MINT; const rewardVault = await pda([REWARD_VAULT_TAG], programId); const authority = signer; const userRewardVault = await checkWalletATA(rewardMint.toBase58(), programProvider.connection, authority); const tx = await program.rpc.depositRewards(amount, { accounts: { authority, rewardVault, userRewardVault, ...defaults }, signers }); // eslint-disable-next-line no-console console.log('deposit rewards tx = ', tx); }; export const claimRewards = async (userReward, signer = programProvider.wallet.publicKey, signers = []) => { const globalState = await pda([GLOBAL_STATE_TAG], programId); const rewardMint = UNLOC_MINT; const rewardVault = await pda([REWARD_VAULT_TAG], programId); const authority = signer; let userRewardVault = await checkWalletATA(rewardMint.toBase58(), programProvider.connection, authority); const preInstructions = []; if (!userRewardVault) { userRewardVault = await addTokenAccountInstruction(rewardMint, authority, preInstructions, signer, signers); } const tx = await program.rpc.claimRewards({ accounts: { authority, globalState, rewardVault, userReward, userRewardVault, ...defaults }, preInstructions, signers }); // eslint-disable-next-line no-console console.log('claim rewards tx = ', tx); }; export const setLoanOffer = async (nftMint, signer = programProvider.wallet.publicKey, signers = []) => { const globalState = await pda([GLOBAL_STATE_TAG], programId); const borrowerNftVault = await checkWalletATA(nftMint.toBase58(), programProvider.connection, signer); const borrower = signer; const offer = await pda([OFFER_TAG, borrower.toBuffer(), nftMint.toBuffer()], programId); const nftMetadata = await Metadata.getPDA(nftMint); const edition = await Edition.getPDA(nftMint); try { const tx = await program.rpc.setOffer({ accounts: { borrower, globalState, offer, nftMint, nftMetadata, edition, userVault: borrowerNftVault, metadataProgram: TOKEN_META_PID, ...defaults }, signers }); // eslint-disable-next-line no-console console.log('setOffer tx = ', tx); } catch (e) { console.log(e); } }; export const cancelLoanOffer = async (nftMint, signer = programProvider.wallet.publicKey, signers = []) => { const borrower = signer; const offer = await pda([OFFER_TAG, borrower.toBuffer(), nftMint.toBuffer()], programId); let borrowerNftVault = await checkWalletATA(nftMint.toBase58(), programProvider.connection, borrower); const preInstructions = []; if (!borrowerNftVault) { borrowerNftVault = await addTokenAccountInstruction(nftMint, borrower, preInstructions, signer, signers); } const edition = await Edition.getPDA(nftMint); try { const tx = await program.rpc.cancelOffer({ accounts: { borrower, offer, nftMint, edition, userVault: borrowerNftVault, metadataProgram: TOKEN_META_PID, ...defaults }, preInstructions, signers }); // eslint-disable-next-line no-console console.log('cancelOffer tx = ', tx); } catch (e) { console.log(e); } }; export const createLoanSubOffer = async (offerAmount, loanDuration, minRepaidNumerator, aprNumerator, nftMint, offerMint, signer = programProvider.wallet.publicKey, signers = []) => { if (offerMint.equals(NATIVE_MINT)) { offerMint = WSOL_MINT; } const globalState = await pda([GLOBAL_STATE_TAG], programId); const borrower = signer; const offer = await pda([OFFER_TAG, borrower.toBuffer(), nftMint.toBuffer()], programId); const offerData = await program.account.offer.fetch(offer); const subOfferNumer = offerData.subOfferCount; const subOffer = await pda([SUB_OFFER_TAG, offer.toBuffer(), subOfferNumer.toArrayLike(Buffer, 'be', 8)], programId); const treasuryVault = await pda([TREASURY_VAULT_TAG, offerMint.toBuffer()], programId); const globalStateData = await program.account.globalState.fetch(globalState); const treasuryWallet = globalStateData.treasuryWallet; try { const tx = await program.rpc.setSubOffer(offerAmount, subOfferNumer, loanDuration, minRepaidNumerator, aprNumerator, { accounts: { borrower, globalState, offer, subOffer, offerMint, treasuryWallet, treasuryVault, ...defaults }, signers }); // eslint-disable-next-line no-console console.log('createSubOffer tx = ', tx); } catch (e) { console.log(e); } }; export const createLoanSubOfferByStaking = async (offerAmount, loanDuration, minRepaidNumerator, aprNumerator, nftMint, offerMint, signer = programProvider.wallet.publicKey, signers = []) => { if (offerMint.equals(NATIVE_MINT)) { offerMint = WSOL_MINT; } const globalState = await pda([GLOBAL_STATE_TAG], programId); const borrower = signer; const offer = await pda([OFFER_TAG, borrower.toBuffer(), nftMint.toBuffer()], programId); const offerData = await program.account.offer.fetch(offer); const subOfferNumer = offerData.subOfferCount; const subOffer = await pda([SUB_OFFER_TAG, offer.toBuffer(), subOfferNumer.toArrayLike(Buffer, 'be', 8)], programId); const treasuryVault = await pda([TREASURY_VAULT_TAG, offerMint.toBuffer()], programId); const globalStateData = await program.account.globalState.fetch(globalState); const stakingUser = await pda([globalStateData.unlocStakingPoolId.toBuffer(), borrower.toBuffer()], globalStateData.unlocStakingPid); const treasuryWallet = globalStateData.treasuryWallet; try { const tx = await program.rpc.setSubOfferByStaking(offerAmount, subOfferNumer, loanDuration, minRepaidNumerator, aprNumerator, { accounts: { borrower, globalState, offer, subOffer, stakingUser, offerMint, treasuryWallet, treasuryVault, ...defaults }, signers }); // eslint-disable-next-line no-console console.log('createSubOffer tx = ', tx); } catch (e) { console.log(e); } }; export const updateLoanSubOffer = async (offerAmount, loanDuration, minRepaidNumerator, aprNumerator, subOffer, signer = programProvider.wallet.publicKey, signers = []) => { const globalState = await pda([GLOBAL_STATE_TAG], programId); const borrower = signer; const subOfferData = await program.account.subOffer.fetch(subOffer); const offer = await pda([OFFER_TAG, borrower.toBuffer(), subOfferData.nftMint.toBuffer()], programId); const subOfferNumer = subOfferData.subOfferNumber; const offerMint = subOfferData.offerMint; const treasuryVault = await pda([TREASURY_VAULT_TAG, subOfferData.offerMint.toBuffer()], programId); const globalStateData = await program.account.globalState.fetch(globalState); const treasuryWallet = globalStateData.treasuryWallet; try { const tx = await program.rpc.setSubOffer(offerAmount, subOfferNumer, loanDuration, minRepaidNumerator, aprNumerator, { accounts: { borrower, globalState, offer, subOffer, offerMint, treasuryWallet, treasuryVault, ...defaults }, signers }); // eslint-disable-next-line no-console console.log('updateSubOffer tx = ', tx); } catch (e) { console.log(e); } }; export const updateLoanSubOfferByStaking = async (offerAmount, loanDuration, minRepaidNumerator, aprNumerator, subOffer, signer = programProvider.wallet.publicKey, signers = []) => { const globalState = await pda([GLOBAL_STATE_TAG], programId); const borrower = signer; const subOfferData = await program.account.subOffer.fetch(subOffer); const offer = await pda([OFFER_TAG, borrower.toBuffer(), subOfferData.nftMint.toBuffer()], programId); const subOfferNumer = subOfferData.subOfferNumber; const offerMint = subOfferData.offerMint; const treasuryVault = await pda([TREASURY_VAULT_TAG, subOfferData.offerMint.toBuffer()], programId); const globalStateData = await program.account.globalState.fetch(globalState); const stakingUser = await pda([globalStateData.unlocStakingPoolId.toBuffer(), borrower.toBuffer()], globalStateData.unlocStakingPid); const treasuryWallet = globalStateData.treasuryWallet; try { const tx = await program.rpc.setSubOfferByStaking(offerAmount, subOfferNumer, loanDuration, minRepaidNumerator, aprNumerator, { accounts: { borrower, globalState, offer, subOffer, stakingUser, offerMint, treasuryWallet, treasuryVault, ...defaults }, signers }); // eslint-disable-next-line no-console console.log('updateSubOffer tx = ', tx); } catch (e) { console.log(e); } }; export const cancelLoanSubOffer = async (subOffer, signer = programProvider.wallet.publicKey, signers = []) => { const borrower = signer; const subOfferData = await program.account.subOffer.fetch(subOffer); const offer = await pda([OFFER_TAG, borrower.toBuffer(), subOfferData.nftMint.toBuffer()], programId); try { const tx = await program.rpc.cancelSubOffer({ accounts: { borrower, offer, subOffer }, signers }); // eslint-disable-next-line no-console console.log('cancelSubOffer tx = ', tx); } catch (e) { console.log(e); } }; export const acceptLoanOfferByVoting = async (subOffer, signer = programProvider.wallet.publicKey, signers = []) => { const lender = signer; const subOfferData = await program.account.subOffer.fetch(subOffer); const offer = subOfferData.offer; const offerMint = subOfferData.offerMint; const offerData = await program.account.offer.fetch(subOfferData.offer); const borrower = offerData.borrower; let borrowerOfferVault = await checkWalletATA(offerMint.toBase58(), programProvider.connection, borrower); let lenderOfferVault = await checkWalletATA(offerMint.toBase58(), programProvider.connection, lender); const preInstructions = []; const postInstructions = []; if (offerMint.equals(WSOL_MINT)) { const treasuryVault = await pda([TREASURY_VAULT_TAG, offerMint.toBuffer()], programId); lenderOfferVault = treasuryVault; borrowerOfferVault = treasuryVault; } else { if (!borrowerOfferVault) { console.log("borrower doesn't have offer token account!"); borrowerOfferVault = await addTokenAccountInstruction(offerMint, borrower, preInstructions, signer, signers); } if (!lenderOfferVault) { console.log("lender doesn't have offer token!"); return; } } const globalState = await pda([GLOBAL_STATE_TAG], programId); const globalStateData = await program.account.globalState.fetch(globalState); const userReward = await pda([USER_REWARD_TAG, lender.toBuffer(), borrower.toBuffer(), subOffer.toBuffer()], programId); const votingPid = globalStateData.votingPid; const currentVotingKey = await getCurrentVotingKey(); const votingItemKey = await pda([VOTING_ITEM_TAG, currentVotingKey.toBuffer(), offerData.collection.toBuffer()], votingPid); try { const tx = await program.rpc.acceptOfferByVoting({ accounts: { lender, borrower, globalState, offer, subOffer, offerMint, userReward, voting: currentVotingKey, votingItem: votingItemKey, borrowerOfferVault, lenderOfferVault, ...defaults }, preInstructions, postInstructions, signers }); // eslint-disable-next-line no-console console.log('acceptOffer tx = ', tx); } catch (e) { console.log(e); } }; export const acceptLoanOffer = async (subOffer, signer = programProvider.wallet.publicKey, signers = []) => { const lender = signer; const subOfferData = await program.account.subOffer.fetch(subOffer); const offer = subOfferData.offer; const offerMint = subOfferData.offerMint; const offerData = await program.account.offer.fetch(subOfferData.offer); const borrower = offerData.borrower; let borrowerOfferVault = await checkWalletATA(offerMint.toBase58(), programProvider.connection, borrower); let lenderOfferVault = await checkWalletATA(offerMint.toBase58(), programProvider.connection, lender); const preInstructions = []; const postInstructions = []; if (offerMint.equals(WSOL_MINT)) { const treasuryVault = await pda([TREASURY_VAULT_TAG, offerMint.toBuffer()], programId); lenderOfferVault = treasuryVault; borrowerOfferVault = treasuryVault; } else { if (!borrowerOfferVault) { console.log("borrower doesn't have offer token account!"); borrowerOfferVault = await addTokenAccountInstruction(offerMint, borrower, preInstructions, signer, signers); } if (!lenderOfferVault) { console.log("lender doesn't have offer token!"); return; } } const globalState = await pda([GLOBAL_STATE_TAG], programId); const userReward = await pda([USER_REWARD_TAG, lender.toBuffer(), borrower.toBuffer(), subOffer.toBuffer()], programId); try { const tx = await program.rpc.acceptOffer({ accounts: { lender, borrower, globalState, offer, subOffer, offerMint, userReward, borrowerOfferVault, lenderOfferVault, ...defaults }, preInstructions, postInstructions, signers }); // eslint-disable-next-line no-console console.log('acceptOffer tx = ', tx); } catch (e) { console.log(e); } }; export const repayLoan = async (subOffer, signer = programProvider.wallet.publicKey, signers = []) => { const globalState = await pda([GLOBAL_STATE_TAG], programId); const borrower = signer; const globalStateData = await program.account.globalState.fetch(globalState); const treasuryWallet = globalStateData.treasuryWallet; const subOfferData = await program.account.subOffer.fetch(subOffer); const offer = subOfferData.offer; const lender = subOfferData.lender; const offerData = await program.account.offer.fetch(offer); const offerMint = subOfferData.offerMint; const nftMint = offerData.nftMint; const treasuryVault = await pda([TREASURY_VAULT_TAG, offerMint.toBuffer()], programId); let borrowerOfferVault = await checkWalletATA(offerMint.toBase58(), programProvider.connection, borrower); let borrowerNftVault = await checkWalletATA(nftMint.toBase58(), programProvider.connection, borrower); let lenderOfferVault = await checkWalletATA(offerMint.toBase58(), programProvider.connection, lender); const preInstructions = []; const postInstructions = []; if (offerMint.equals(WSOL_MINT)) { const treasuryVault = await pda([TREASURY_VAULT_TAG, offerMint.toBuffer()], 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 addTokenAccountInstruction(nftMint, borrower, preInstructions, signer, signers); } if (!lenderOfferVault) { console.log("lender doesn't have offer token account!", lender.toBase58()); lenderOfferVault = await addTokenAccountInstruction(offerMint, lender, preInstructions, signer, signers); } const userReward = await pda([USER_REWARD_TAG, lender.toBuffer(), borrower.toBuffer(), subOffer.toBuffer()], programId); const edition = await Edition.getPDA(nftMint); try { const tx = await program.rpc.repayLoan({ accounts: { borrower, lender, globalState, treasuryWallet, offer, subOffer, nftMint, edition, userReward, borrowerNftVault, lenderOfferVault, borrowerOfferVault, treasuryVault, metadataProgram: TOKEN_META_PID, ...defaults }, preInstructions, postInstructions, signers }); // eslint-disable-next-line no-console console.log('repayLoan tx = ', tx); } catch (e) { console.log(e); } }; export const claimLoanCollateral = async (subOffer, signer = programProvider.wallet.publicKey, signers = []) => { const globalState = await pda([GLOBAL_STATE_TAG], programId); const lender = signer; const globalStateData = await program.account.globalState.fetch(globalState); const treasuryWallet = globalStateData.treasuryWallet; const subOfferData = await program.account.subOffer.fetch(subOffer); const offer = subOfferData.offer; const offerData = await program.account.offer.fetch(offer); const offerMint = subOfferData.offerMint; const nftMint = offerData.nftMint; const treasuryVault = await pda([TREASURY_VAULT_TAG, offerMint.toBuffer()], programId); let borrowerNftVault = await checkWalletATA(nftMint.toBase58(), programProvider.connection, offerData.borrower); let lenderNftVault = await checkWalletATA(nftMint.toBase58(), programProvider.connection, lender); let lenderOfferVault = await checkWalletATA(offerMint.toBase58(), programProvider.connection, lender); const preInstructions = []; const postInstructions = []; if (offerMint.equals(WSOL_MINT)) { const treasuryVault = await pda([TREASURY_VAULT_TAG, offerMint.toBuffer()], programId); lenderOfferVault = treasuryVault; } if (!lenderNftVault) { console.log("lender doesn't have nft token token account!"); lenderNftVault = await addTokenAccountInstruction(nftMint, lender, preInstructions, signer, signers); } if (!lenderOfferVault) { console.log("lender doesn't have offer token account!", lender.toBase58()); lenderOfferVault = await addTokenAccountInstruction(offerMint, lender, preInstructions, signer, signers); } const edition = await Edition.getPDA(nftMint); try { const tx = await program.rpc.claimCollateral({ accounts: { lender, globalState, treasuryWallet, offer, subOffer, nftMint, edition, lenderNftVault, borrowerNftVault, lenderOfferVault, treasuryVault, metadataProgram: TOKEN_META_PID, ...defaults }, preInstructions, postInstructions, signers }); // eslint-disable-next-line no-console console.log('claimCollateral tx = ', tx); } catch (e) { console.log(e); } }; // super owner can call this function export const claimExpiredCollateral = async (subOffer, signer = programProvider.wallet.publicKey, signers = []) => { const globalState = await pda([GLOBAL_STATE_TAG], programId); const globalStateData = await program.account.globalState.fetch(globalState); const treasuryWallet = globalStateData.treasuryWallet; const subOfferData = await program.account.subOffer.fetch(subOffer); const offer = subOfferData.offer; const offerData = await program.account.offer.fetch(offer); const nftMint = offerData.nftMint; let userNftVault = await checkWalletATA(nftMint.toBase58(), programProvider.connection, signer); const preInstructions = []; if (!userNftVault) { userNftVault = await addTokenAccountInstruction(nftMint, signer, preInstructions, signer, signers); } let borrowerNftVault = await checkWalletATA(nftMint.toBase58(), programProvider.connection, offerData.borrower); const edition = await Edition.getPDA(nftMint); try { const tx = await program.rpc.claimExpiredCollateral({ accounts: { superOwner: signer, globalState, treasuryWallet, offer, subOffer, nftMint, edition, userNftVault, borrowerNftVault, metadataProgram: TOKEN_META_PID, ...defaults }, preInstructions, signers }); // eslint-disable-next-line no-console console.log('claimExpiredCollateral tx = ', tx); } catch (e) { console.log(e); } }; export 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 || (OfferState = {})); export 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 || (SubOfferState = {})); export const getLoanSubOffersKeysByState = async (state) => { try { const accountName = 'subOffer'; const data = await programProvider.connection.getProgramAccounts(programId, { dataSlice: { offset: 0, length: 0 }, filters: [ { memcmp: program.account.subOffer.coder.accounts.memcmp(accountName) }, { memcmp: { offset: discriminatorLen + 96, bytes: 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); } }; export const addTokenAccountInstruction = async (mint, owner, instructions, signer, signers, rent = 0) => { const newKeypair = Keypair.generate(); const rentForTokenAccount = await Token.getMinBalanceRentForExemptAccount(programProvider.connection); instructions.push(SystemProgram.createAccount({ fromPubkey: signer, newAccountPubkey: newKeypair.publicKey, lamports: rent > 0 ? rent : rentForTokenAccount, space: ACCOUNT_LAYOUT.span, programId: TOKEN_PROGRAM_ID })); const instruction = Token.createInitAccountInstruction(TOKEN_PROGRAM_ID, mint, newKeypair.publicKey, owner); instructions.push(instruction); signers.push(newKeypair); return newKeypair.publicKey; }; export const checkWalletATA = async (mint, connection = programProvider.connection, walletPubkey = programProvider.wallet.publicKey) => { const parsedTokenAccounts = await connection.getParsedTokenAccountsByOwner(walletPubkey, { programId: 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; }; export const logObject = (title, obj) => { console.log(title, obj); }; export const getOfferBalance = async (subOffer, connection = programProvider.connection, walletPubkey = programProvider.wallet.publicKey) => { try { const tokenAccount = await pda([OFFER_VAULT_TAG, subOffer.toBuffer()], programId); const balance = (await connection.getTokenAccountBalance(tokenAccount)).value.uiAmount; return balance; } catch (e) { console.log(e); } return 0; }; // --------------------utilities--------------------- export class MultipleNFT { mints; metadatas = []; constructor(keys) { this.mints = keys; } async initialize() { if (this.metadatas.length == 0) { const metadataPDAs = []; for (let i = 0; i < this.mints.length; i++) { const metadataPDA = await Metadata.getPDA(this.mints[i]); metadataPDAs.push(metadataPDA); } let i = 0; const metaInfos = await Metadata.getInfos(programProvider.connection, metadataPDAs); metaInfos.forEach((value, key, map) => { const metadata = 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(); } } } export class NFTMetadata { mint = ''; metadataPDA = ''; onChainMetadata = null; arweaveMetadata = null; masterEdition = null; constructor(mint, metadataPDA, onChainMetadata) { this.mint = mint.toBase58(); this.metadataPDA = metadataPDA.toBase58(); this.onChainMetadata = onChainMetadata; } async getAreaveMetadata() { if (this.arweaveMetadata === null) { try { const arweaveData = await axios.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 Edition.getPDA(new PublicKey(this.mint)); const editionAccountInfo = await programProvider.connection.getAccountInfo(masterEditionPDA); if (editionAccountInfo) { const key = editionAccountInfo?.data[0]; let masterEditionData; let data; switch (key) { case MetadataKey.MasterEditionV1: case MetadataKey.MasterEditionV2: ; ({ data } = new MasterEdition(masterEditionPDA, editionAccountInfo)); masterEditionData = data; break; default: masterEditionData = undefined; break; } this.masterEdition = { masterEditionPDA: masterEditionPDA.toString(), masterEditionData }; } } return this.masterEdition; } } export const ACCOUNT_LAYOUT = struct([ publicKey('mint'), publicKey('owner'), u64('amount'), u32('delegateOption'), publicKey('delegate'), u8('state'), u32('isNativeOption'), u64('isNative'), u64('delegatedAmount'), u32('closeAuthorityOption'), publicKey('closeAuthority') ]); export const MINT_LAYOUT = struct([ u32('mintAuthorityOption'), publicKey('mintAuthority'), u64('supply'), u8('decimals'), bool('initialized'), u32('freezeAuthorityOption'), publicKey('freezeAuthority') ]); //# sourceMappingURL=index.js.map