From 6fb99db6cee7cec7f70c632c5d5d3475e14af591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Brzezi=C5=84ski?= Date: Thu, 28 Dec 2023 19:39:46 +0100 Subject: [PATCH] token tiers adjustments + refactor (#356) * fix * fix * add simulation * fix * improve decode logic for oderbook --- components/governance/ListToken/ListToken.tsx | 310 ++++++++---------- .../modals/CreateSwitchboardOracleModal.tsx | 51 +-- .../modals/DashboardSuggestedValuesModal.tsx | 107 +++--- components/trade/DepthChart.tsx | 6 +- components/trade/Orderbook.tsx | 23 +- package.json | 4 +- pages/dashboard/index.tsx | 4 +- .../governance/instructions/createProposal.ts | 2 + utils/governance/listingTools.ts | 15 +- utils/notifications.ts | 2 +- yarn.lock | 16 +- 11 files changed, 279 insertions(+), 261 deletions(-) diff --git a/components/governance/ListToken/ListToken.tsx b/components/governance/ListToken/ListToken.tsx index c33b0f67..00b7c756 100644 --- a/components/governance/ListToken/ListToken.tsx +++ b/components/governance/ListToken/ListToken.tsx @@ -10,11 +10,10 @@ import { JUPITER_REFERRAL_PK, USDC_MINT, } from 'utils/constants' -import { PublicKey, SYSVAR_RENT_PUBKEY } from '@solana/web3.js' +import { PublicKey, SYSVAR_RENT_PUBKEY, Transaction } from '@solana/web3.js' import { useWallet } from '@solana/wallet-adapter-react' import { OPENBOOK_PROGRAM_ID, toNative } from '@blockworks-foundation/mango-v4' import { - MANGO_DAO_FAST_LISTING_GOVERNANCE, MANGO_DAO_FAST_LISTING_WALLET, MANGO_DAO_WALLET, MANGO_DAO_WALLET_GOVERNANCE, @@ -44,11 +43,12 @@ import CreateOpenbookMarketModal from '@components/modals/CreateOpenbookMarketMo import useJupiterMints from 'hooks/useJupiterMints' import CreateSwitchboardOracleModal from '@components/modals/CreateSwitchboardOracleModal' import { - LISTING_PRESETS_KEYS, LISTING_PRESETS, - coinTiersToNames, calculateMarketTradingParams, - LISTING_PRESETS_PYTH, + getSwitchBoardPresets, + getPythPresets, + LISTING_PRESET, + getPresetWithAdjustedDepositLimit, } from '@blockworks-foundation/mango-v4-settings/lib/helpers/listingTools' import Checkbox from '@components/forms/Checkbox' import { ReferralProvider } from '@jup-ag/referral-sdk' @@ -125,22 +125,24 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { const [orcaPoolAddress, setOrcaPoolAddress] = useState('') const [raydiumPoolAddress, setRaydiumPoolAddress] = useState('') const [oracleModalOpen, setOracleModalOpen] = useState(false) - const [liqudityTier, setLiqudityTier] = useState( - '', - ) const [isPyth, setIsPyth] = useState(false) - const tierLowerThenCurrent = - liqudityTier === 'ULTRA_PREMIUM' || liqudityTier === 'PREMIUM' - ? 'MID' - : liqudityTier === 'MID' - ? 'MEME' - : liqudityTier - const isPythRecommended = - liqudityTier === 'MID' || - liqudityTier === 'PREMIUM' || - liqudityTier === 'ULTRA_PREMIUM' - const listingTier = - isPythRecommended && !isPyth ? tierLowerThenCurrent : liqudityTier + const presets = useMemo(() => { + return !isPyth + ? getSwitchBoardPresets(LISTING_PRESETS) + : getPythPresets(LISTING_PRESETS) + }, [isPyth]) + const [proposedPresetTargetAmount, setProposedProposedTargetAmount] = + useState(0) + + const preset: LISTING_PRESET = + Object.values(presets).find( + (x) => x.preset_target_amount === proposedPresetTargetAmount, + ) || presets.UNTRUSTED + const proposedPreset = getPresetWithAdjustedDepositLimit( + preset, + baseTokenPrice, + currentTokenInfo?.decimals || 0, + ) const quoteBank = group?.getFirstBankByMint(new PublicKey(USDC_MINT)) const minVoterWeight = useMemo( @@ -174,13 +176,6 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { priceIncrementRelative: 0, } }, [quoteBank, currentTokenInfo, baseTokenPrice]) - const tierPreset = useMemo(() => { - return listingTier - ? isPyth - ? LISTING_PRESETS_PYTH[listingTier] - : LISTING_PRESETS[listingTier] - : {} - }, [listingTier]) const handleSetAdvForm = ( propertyName: string, @@ -191,14 +186,14 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { } const getListingParams = useCallback( - async (tokenInfo: Token, tier: LISTING_PRESETS_KEYS) => { + async (tokenInfo: Token, targetAmount: number) => { setLoadingListingParams(true) const [{ oraclePk, isPyth }, marketPk] = await Promise.all([ getOracle({ baseSymbol: tokenInfo.symbol, quoteSymbol: 'usd', connection, - tier: tier, + targetAmount: targetAmount, }), getBestMarket({ baseMint: mint, @@ -235,7 +230,7 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { marketIndex: index, openBookMarketExternalPk: marketPk?.toBase58() || '', proposalTitle: `List ${tokenInfo.symbol} on Mango-v4`, - listForSwapOnly: tier === 'UNTRUSTED', + listForSwapOnly: false, }) setLoadingListingParams(false) setIsPyth(isPyth) @@ -272,31 +267,32 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { [wallet.publicKey], ) - const handleLiqudityCheck = useCallback( + const handleLiquidityCheck = useCallback( async (tokenMint: PublicKey) => { try { - const TIERS: LISTING_PRESETS_KEYS[] = [ - 'ULTRA_PREMIUM', - 'PREMIUM', - 'MID', - 'MEME', - 'SHIT', + const targetAmounts = [ + ...new Set([ + ...Object.values(presets).map((x) => x.preset_target_amount), + ]), ] const swaps = await Promise.all([ handleGetRoutesWithFixedArgs(250000, tokenMint, 'ExactIn'), handleGetRoutesWithFixedArgs(100000, tokenMint, 'ExactIn'), handleGetRoutesWithFixedArgs(20000, tokenMint, 'ExactIn'), + handleGetRoutesWithFixedArgs(10000, tokenMint, 'ExactIn'), handleGetRoutesWithFixedArgs(5000, tokenMint, 'ExactIn'), handleGetRoutesWithFixedArgs(1000, tokenMint, 'ExactIn'), handleGetRoutesWithFixedArgs(250000, tokenMint, 'ExactOut'), handleGetRoutesWithFixedArgs(100000, tokenMint, 'ExactOut'), handleGetRoutesWithFixedArgs(20000, tokenMint, 'ExactOut'), + handleGetRoutesWithFixedArgs(10000, tokenMint, 'ExactOut'), handleGetRoutesWithFixedArgs(5000, tokenMint, 'ExactOut'), handleGetRoutesWithFixedArgs(1000, tokenMint, 'ExactOut'), ]) const bestRoutesSwaps = swaps .filter((x) => x.bestRoute) .map((x) => x.bestRoute!) + const averageSwaps = bestRoutesSwaps.reduce( (acc: { amount: string; priceImpactPct: number }[], val) => { if (val.swapMode === 'ExactIn') { @@ -319,43 +315,33 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { const midTierCheck = averageSwaps.find( (x) => x.amount === TWENTY_K_USDC_BASE, ) - const indexForTierFromSwaps = averageSwaps.findIndex( + const indexForTargetAmount = averageSwaps.findIndex( (x) => x?.priceImpactPct && x?.priceImpactPct * 100 < 1, ) - const tier = - indexForTierFromSwaps > -1 - ? TIERS[indexForTierFromSwaps] - : 'UNTRUSTED' - setLiqudityTier(tier) + const targetAmount = + indexForTargetAmount > -1 ? targetAmounts[indexForTargetAmount] : 0 + setProposedProposedTargetAmount(targetAmount) setPriceImpact(midTierCheck ? midTierCheck.priceImpactPct * 100 : 100) - handleGetPoolParams(tier, tokenMint) - return tier + handleGetPoolParams(targetAmount, tokenMint) + return targetAmount } catch (e) { notify({ title: t('liquidity-check-error'), description: `${e}`, type: 'error', }) - return 'UNTRUSTED' + return 0 } }, [t, handleGetRoutesWithFixedArgs], ) const handleGetPoolParams = async ( - tier: LISTING_PRESETS_KEYS, + targetAmount: number, tokenMint: PublicKey, ) => { - const tierToSwapValue: { [key: string]: number } = { - ULTRA_PREMIUM: 250000, - PREMIUM: 100000, - MID: 20000, - MEME: 5000, - SHIT: 1000, - UNTRUSTED: 100, - } const swaps = await handleGetRoutesWithFixedArgs( - tierToSwapValue[tier], + targetAmount ? targetAmount : 100, tokenMint, 'ExactIn', true, @@ -393,10 +379,10 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { setBaseTokenPrice(priceInfo.data[mint]?.price || 0) setCurrentTokenInfo(tokenInfo) if (tokenInfo) { - const tier = await handleLiqudityCheck(new PublicKey(mint)) - getListingParams(tokenInfo, tier) + const targetAmount = await handleLiquidityCheck(new PublicKey(mint)) + getListingParams(tokenInfo, targetAmount) } - }, [getListingParams, handleLiqudityCheck, jupiterTokens, mint, t]) + }, [getListingParams, handleLiquidityCheck, jupiterTokens, mint, t]) const cancel = () => { setCurrentTokenInfo(null) @@ -405,7 +391,7 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { setProposalPk(null) setOrcaPoolAddress('') setRaydiumPoolAddress('') - setLiqudityTier('') + setProposedProposedTargetAmount(0) setBaseTokenPrice(0) } @@ -472,46 +458,46 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { const mint = new PublicKey(advForm.mintPk) const proposalTx = [] - if (Object.keys(tierPreset).length) { + if (Object.keys(proposedPreset).length) { const registerTokenIx = await client!.program.methods .tokenRegister( Number(advForm.tokenIndex), advForm.name, { - confFilter: Number(tierPreset.oracleConfFilter), - maxStalenessSlots: tierPreset.maxStalenessSlots, + confFilter: Number(proposedPreset.oracleConfFilter), + maxStalenessSlots: proposedPreset.maxStalenessSlots, }, { - adjustmentFactor: Number(tierPreset.adjustmentFactor), - util0: Number(tierPreset.util0), - rate0: Number(tierPreset.rate0), - util1: Number(tierPreset.util1), - rate1: Number(tierPreset.rate1), - maxRate: Number(tierPreset.maxRate), + adjustmentFactor: Number(proposedPreset.adjustmentFactor), + util0: Number(proposedPreset.util0), + rate0: Number(proposedPreset.rate0), + util1: Number(proposedPreset.util1), + rate1: Number(proposedPreset.rate1), + maxRate: Number(proposedPreset.maxRate), }, - Number(tierPreset.loanFeeRate), - Number(tierPreset.loanOriginationFeeRate), - Number(tierPreset.maintAssetWeight), - Number(tierPreset.initAssetWeight), - Number(tierPreset.maintLiabWeight), - Number(tierPreset.initLiabWeight), - Number(tierPreset.liquidationFee), - Number(tierPreset.stablePriceDelayIntervalSeconds), - Number(tierPreset.stablePriceDelayGrowthLimit), - Number(tierPreset.stablePriceGrowthLimit), - Number(tierPreset.minVaultToDepositsRatio), - new BN(tierPreset.netBorrowLimitWindowSizeTs), - new BN(tierPreset.netBorrowLimitPerWindowQuote), - Number(tierPreset.borrowWeightScaleStartQuote), - Number(tierPreset.depositWeightScaleStartQuote), - Number(tierPreset.reduceOnly), - Number(tierPreset.tokenConditionalSwapTakerFeeRate), - Number(tierPreset.tokenConditionalSwapMakerFeeRate), - Number(tierPreset.flashLoanSwapFeeRate), - Number(tierPreset.interestCurveScaling), - Number(tierPreset.interestTargetUtilization), - tierPreset.groupInsuranceFund, - new BN(tierPreset.depositLimit), + Number(proposedPreset.loanFeeRate), + Number(proposedPreset.loanOriginationFeeRate), + Number(proposedPreset.maintAssetWeight), + Number(proposedPreset.initAssetWeight), + Number(proposedPreset.maintLiabWeight), + Number(proposedPreset.initLiabWeight), + Number(proposedPreset.liquidationFee), + Number(proposedPreset.stablePriceDelayIntervalSeconds), + Number(proposedPreset.stablePriceDelayGrowthLimit), + Number(proposedPreset.stablePriceGrowthLimit), + Number(proposedPreset.minVaultToDepositsRatio), + new BN(proposedPreset.netBorrowLimitWindowSizeTs), + new BN(proposedPreset.netBorrowLimitPerWindowQuote), + Number(proposedPreset.borrowWeightScaleStartQuote), + Number(proposedPreset.depositWeightScaleStartQuote), + Number(proposedPreset.reduceOnly), + Number(proposedPreset.tokenConditionalSwapTakerFeeRate), + Number(proposedPreset.tokenConditionalSwapMakerFeeRate), + Number(proposedPreset.flashLoanSwapFeeRate), + Number(proposedPreset.interestCurveScaling), + Number(proposedPreset.interestTargetUtilization), + proposedPreset.groupInsuranceFund, + new BN(proposedPreset.depositLimit.toString()), ) .accounts({ admin: MANGO_DAO_WALLET, @@ -539,12 +525,12 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { proposalTx.push(trustlessIx) } - if (listingTier !== 'UNTRUSTED' && !advForm.listForSwapOnly) { + if (!advForm.listForSwapOnly) { const registerMarketix = await client!.program.methods .serum3RegisterMarket( Number(advForm.marketIndex), advForm.marketName, - tierPreset.oraclePriceBand, + proposedPreset.oraclePriceBand, ) .accounts({ group: group!.publicKey, @@ -561,10 +547,7 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { const rp = new ReferralProvider(connection) const tx = await rp.initializeReferralTokenAccount({ - payerPubKey: - listingTier === 'UNTRUSTED' - ? MANGO_DAO_FAST_LISTING_WALLET - : MANGO_DAO_WALLET, + payerPubKey: MANGO_DAO_WALLET, referralAccountPubKey: JUPITER_REFERRAL_PK, mint: mint, }) @@ -579,22 +562,29 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { setCreatingProposal(true) try { - const proposalAddress = await createProposal( - connection, - walletSigner, - listingTier === 'UNTRUSTED' - ? MANGO_DAO_FAST_LISTING_GOVERNANCE - : MANGO_DAO_WALLET_GOVERNANCE, - voter.tokenOwnerRecord!, - advForm.proposalTitle, - advForm.proposalDescription, - advForm.tokenIndex, - proposalTx, - vsrClient, - fee, - ) - setProposalPk(proposalAddress.toBase58()) + const simTransaction = new Transaction({ feePayer: wallet.publicKey }) + simTransaction.add(...proposalTx) + const simulation = await connection.simulateTransaction(simTransaction) + + if (!simulation.value.err) { + const proposalAddress = await createProposal( + connection, + walletSigner, + MANGO_DAO_WALLET_GOVERNANCE, + voter.tokenOwnerRecord!, + advForm.proposalTitle, + advForm.proposalDescription, + advForm.tokenIndex, + proposalTx, + vsrClient, + fee, + ) + setProposalPk(proposalAddress.toBase58()) + } else { + throw simulation.value.logs + } } catch (e) { + console.log(e) notify({ title: t('error-proposal-creation'), description: `${e}`, @@ -604,34 +594,34 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { setCreatingProposal(false) }, [ - listingTier, + isFormValid, advForm, - client, - connection, + wallet, + vsrClient, connectionContext, getCurrentVotingPower, - group, - isFormValid, - minVoterWeight, - mintVoterWeightNumber, - t, - tierPreset, - voter.tokenOwnerRecord, voter.voteWeight, - vsrClient, - wallet, + voter.tokenOwnerRecord, + minVoterWeight, + proposedPreset, + connection, + t, + mintVoterWeightNumber, + client, + group, + fee, ]) const closeCreateOpenBookMarketModal = () => { setCreateOpenbookMarket(false) - if (currentTokenInfo && liqudityTier) { - getListingParams(currentTokenInfo, liqudityTier) + if (currentTokenInfo && proposedPresetTargetAmount) { + getListingParams(currentTokenInfo, proposedPresetTargetAmount) } } const closeCreateOracleModal = () => { setOracleModalOpen(false) - if (currentTokenInfo && liqudityTier) { - getListingParams(currentTokenInfo, liqudityTier) + if (currentTokenInfo && proposedPresetTargetAmount) { + getListingParams(currentTokenInfo, proposedPresetTargetAmount) } } @@ -701,17 +691,8 @@ const ListToken = ({ goBack }: { goBack: () => void }) => {

{t('tier')}

-

- {listingTier && coinTiersToNames[listingTier]} -

+

{proposedPreset.preset_name}

- {isPythRecommended && !isPyth && ( -
-

- Pyth oracle needed for higher tier -

-
- )}

{t('mint')}

@@ -822,30 +803,28 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { )}

)} - {listingTier !== 'UNTRUSTED' && ( -
-
- )} +
+
diff --git a/components/modals/DashboardSuggestedValuesModal.tsx b/components/modals/DashboardSuggestedValuesModal.tsx index 0022e0fc..e3b066b0 100644 --- a/components/modals/DashboardSuggestedValuesModal.tsx +++ b/components/modals/DashboardSuggestedValuesModal.tsx @@ -14,7 +14,7 @@ import { OracleProvider, PriceImpact, } from '@blockworks-foundation/mango-v4' -import { AccountMeta } from '@solana/web3.js' +import { AccountMeta, Transaction } from '@solana/web3.js' import { BN } from '@project-serum/anchor' import { MANGO_DAO_WALLET, @@ -26,16 +26,19 @@ import Button from '@components/shared/Button' import { compareObjectsAndGetDifferentKeys } from 'utils/governance/tools' import { Disclosure } from '@headlessui/react' import { + LISTING_PRESET, LISTING_PRESETS, - LISTING_PRESETS_KEYS, - LISTING_PRESETS_PYTH, - ListingPreset, + LISTING_PRESETS_KEY, MidPriceImpact, getMidPriceImpacts, - getProposedTier, - getTierWithAdjustedNetBorrows, + getPresetWithAdjustedDepositLimit, + getPresetWithAdjustedNetBorrows, + getProposedKey, + getPythPresets, + getSwitchBoardPresets, } from '@blockworks-foundation/mango-v4-settings/lib/helpers/listingTools' import Select from '@components/forms/Select' +import Loading from '@components/shared/Loading' const DashboardSuggestedValues = ({ isOpen, @@ -58,11 +61,12 @@ const DashboardSuggestedValues = ({ const proposals = GovernanceStore((s) => s.proposals) const PRESETS = bank?.oracleProvider === OracleProvider.Pyth - ? LISTING_PRESETS_PYTH - : LISTING_PRESETS + ? getPythPresets(LISTING_PRESETS) + : getSwitchBoardPresets(LISTING_PRESETS) const [suggestedTier, setSuggestedTier] = - useState('SHIT') + useState('liab_1') + const [proposing, setProposing] = useState(false) const getApiTokenName = (bankName: string) => { if (bankName === 'ETH (Portal)') { @@ -93,25 +97,19 @@ const DashboardSuggestedValues = ({ }, {}) const priceImpact = filteredResp[getApiTokenName(bank.name)] - const suggestedTier = getProposedTier( - PRESETS, + const suggestedTier = getProposedKey( priceImpact?.target_amount, bank.oracleProvider === OracleProvider.Pyth, ) - setSuggestedTier(suggestedTier as LISTING_PRESETS_KEYS) - }, [ - PRESETS, - bank.name, - bank.oracleProvider, - JSON.stringify(priceImpactsFiltered), - ]) + setSuggestedTier(suggestedTier) + }, [bank.name, bank.oracleProvider, priceImpactsFiltered]) const proposeNewSuggestedValues = useCallback( async ( bank: Bank, invalidFieldsKeys: string[], - tokenTier: LISTING_PRESETS_KEYS, + tokenTier: LISTING_PRESETS_KEY, ) => { const proposalTx = [] const mintInfo = group!.mintInfosMapByTokenIndex.get(bank.tokenIndex)! @@ -228,7 +226,7 @@ const DashboardSuggestedValues = ({ false, false, getNullOrVal(fieldsToChange.depositLimit) - ? new BN(fieldsToChange.depositLimit!) + ? new BN(fieldsToChange.depositLimit!.toString()) : null, ) .accounts({ @@ -248,24 +246,34 @@ const DashboardSuggestedValues = ({ proposalTx.push(ix) const walletSigner = wallet as never + try { - const index = proposals ? Object.values(proposals).length : 0 - const proposalAddress = await createProposal( - connection, - walletSigner, - MANGO_DAO_WALLET_GOVERNANCE, - voter.tokenOwnerRecord!, - `Edit token ${bank.name}`, - 'Adjust settings to current liquidity', - index, - proposalTx, - vsrClient!, - fee, - ) - window.open( - `https://dao.mango.markets/dao/MNGO/proposal/${proposalAddress.toBase58()}`, - '_blank', - ) + setProposing(true) + const simTransaction = new Transaction({ feePayer: wallet.publicKey }) + simTransaction.add(...proposalTx) + const simulation = await connection.simulateTransaction(simTransaction) + + if (!simulation.value.err) { + const index = proposals ? Object.values(proposals).length : 0 + const proposalAddress = await createProposal( + connection, + walletSigner, + MANGO_DAO_WALLET_GOVERNANCE, + voter.tokenOwnerRecord!, + `Edit token ${bank.name}`, + 'Adjust settings to current liquidity', + index, + proposalTx, + vsrClient!, + fee, + ) + window.open( + `https://dao.mango.markets/dao/MNGO/proposal/${proposalAddress.toBase58()}`, + '_blank', + ) + } else { + throw simulation.value.logs + } } catch (e) { notify({ title: 'Error during proposal creation', @@ -273,11 +281,13 @@ const DashboardSuggestedValues = ({ type: 'error', }) } + setProposing(false) }, [ PRESETS, client, connection, + fee, group, proposals, voter.tokenOwnerRecord, @@ -294,16 +304,21 @@ const DashboardSuggestedValues = ({ const formattedBankValues = getFormattedBankValues(group, bank) - const suggestedVaules = getTierWithAdjustedNetBorrows( - PRESETS[suggestedTier as LISTING_PRESETS_KEYS] as ListingPreset, - bank.nativeDeposits().mul(bank.price).toNumber(), + const suggestedValues = getPresetWithAdjustedDepositLimit( + getPresetWithAdjustedNetBorrows( + PRESETS[suggestedTier as LISTING_PRESETS_KEY] as LISTING_PRESET, + bank.nativeDeposits().mul(bank.price).toNumber(), + ), + bank.uiPrice, + bank.mintDecimals, ) - const suggestedFormattedPreset = formatSuggestedValues(suggestedVaules) + + const suggestedFormattedPreset = formatSuggestedValues(suggestedValues) type SuggestedFormattedPreset = typeof suggestedFormattedPreset const invalidKeys: (keyof SuggestedFormattedPreset)[] = Object.keys( - suggestedVaules, + suggestedValues, ).length ? compareObjectsAndGetDifferentKeys( formattedBankValues, @@ -339,7 +354,7 @@ const DashboardSuggestedValues = ({ onChange={(tier) => setSuggestedTier(tier)} className="w-full" > - {Object.keys(LISTING_PRESETS) + {Object.keys(PRESETS) .filter((x) => x !== 'UNTRUSTED') .map((name) => ( @@ -630,12 +645,12 @@ const DashboardSuggestedValues = ({ proposeNewSuggestedValues( bank, invalidKeys, - suggestedTier as LISTING_PRESETS_KEYS, + suggestedTier as LISTING_PRESETS_KEY, ) } - disabled={!wallet.connected} + disabled={!wallet.connected || proposing} > - Propose new suggested values + {proposing ? : 'Propose new suggested values'} )} diff --git a/components/trade/DepthChart.tsx b/components/trade/DepthChart.tsx index a12603e8..d4efc173 100644 --- a/components/trade/DepthChart.tsx +++ b/components/trade/DepthChart.tsx @@ -316,11 +316,11 @@ const DepthChart = () => {
- + { connection .getAccountInfoAndContext(bidsPk) .then(({ context, value: info }) => { - if (!info) return + if (!info || !isMarketReadyForDecode(market)) return const decodedBook = decodeBook(client, market, info, 'bids') set((state) => { state.selectedMarket.lastSeenSlot.bids = context.slot @@ -319,8 +319,8 @@ const Orderbook = () => { mangoStore.getState().selectedMarket.lastSeenSlot.bids if (context.slot > lastSeenSlot) { const market = getMarket() - if (!market) return - const decodedBook = decodeBook(client, market, info, 'bids') + if (!isMarketReadyForDecode(market)) return + const decodedBook = decodeBook(client, market!, info, 'bids') if (decodedBook instanceof BookSide) { updatePerpMarketOnGroup(decodedBook, 'bids') } @@ -340,7 +340,7 @@ const Orderbook = () => { connection .getAccountInfoAndContext(asksPk) .then(({ context, value: info }) => { - if (!info) return + if (!info || !isMarketReadyForDecode(market)) return const decodedBook = decodeBook(client, market, info, 'asks') set((state) => { state.selectedMarket.asksAccount = decodedBook @@ -355,8 +355,8 @@ const Orderbook = () => { mangoStore.getState().selectedMarket.lastSeenSlot.asks if (context.slot > lastSeenSlot) { const market = getMarket() - if (!market) return - const decodedBook = decodeBook(client, market, info, 'asks') + if (!isMarketReadyForDecode(market)) return + const decodedBook = decodeBook(client, market!, info, 'asks') if (decodedBook instanceof BookSide) { updatePerpMarketOnGroup(decodedBook, 'asks') } @@ -812,3 +812,14 @@ function usersOpenOrderPrices(market: Market | PerpMarket | null) { } return usersOpenOrderPrices } + +const isMarketReadyForDecode = (market: PerpMarket | Market | undefined) => { + if ( + !market || + (market instanceof Market && + (!market.decoded.accountFlags.initialized || + !(market.decoded.accountFlags.bids ^ market.decoded.accountFlags.asks))) + ) + return false + else return true +} diff --git a/package.json b/package.json index ea1f5613..47e8ec39 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ "dependencies": { "@blockworks-foundation/mango-feeds": "0.1.7", "@blockworks-foundation/mango-mints-redemption": "^0.0.10", - "@blockworks-foundation/mango-v4": "0.21.3", - "@blockworks-foundation/mango-v4-settings": "0.3.3", + "@blockworks-foundation/mango-v4": "0.21.5", + "@blockworks-foundation/mango-v4-settings": "0.4.3", "@blockworks-foundation/mangolana": "0.0.1-beta.15", "@headlessui/react": "1.6.6", "@heroicons/react": "2.0.18", diff --git a/pages/dashboard/index.tsx b/pages/dashboard/index.tsx index 4428b7d7..e1624aca 100644 --- a/pages/dashboard/index.tsx +++ b/pages/dashboard/index.tsx @@ -953,7 +953,9 @@ const VaultData = ({ bank }: { bank: Bank }) => { ) diff --git a/utils/governance/instructions/createProposal.ts b/utils/governance/instructions/createProposal.ts index 613d48c7..e67516e0 100644 --- a/utils/governance/instructions/createProposal.ts +++ b/utils/governance/instructions/createProposal.ts @@ -141,12 +141,14 @@ export const createProposal = async ( tx.feePayer = payer transactions.push(tx) } + const signedTransactions = await wallet.signAllTransactions(transactions) for (const tx of signedTransactions) { const rawTransaction = tx.serialize() const address = await connection.sendRawTransaction(rawTransaction, { skipPreflight: true, }) + await connection.confirmTransaction({ blockhash: latestBlockhash.blockhash, lastValidBlockHeight: latestBlockhash.lastValidBlockHeight, diff --git a/utils/governance/listingTools.ts b/utils/governance/listingTools.ts index b87b381b..e257ae38 100644 --- a/utils/governance/listingTools.ts +++ b/utils/governance/listingTools.ts @@ -15,21 +15,18 @@ import { Market } from '@project-serum/serum' import { Connection, Keypair, PublicKey } from '@solana/web3.js' import EmptyWallet from 'utils/wallet' import dayjs from 'dayjs' -import { - LISTING_PRESETS_KEYS, - ListingPreset, -} from '@blockworks-foundation/mango-v4-settings/lib/helpers/listingTools' +import { LISTING_PRESET } from '@blockworks-foundation/mango-v4-settings/lib/helpers/listingTools' export const getOracle = async ({ baseSymbol, quoteSymbol, connection, - tier, + targetAmount, }: { baseSymbol: string quoteSymbol: string connection: Connection - tier: LISTING_PRESETS_KEYS + targetAmount: number }) => { try { let oraclePk = '' @@ -38,6 +35,7 @@ export const getOracle = async ({ quoteSymbol, connection, }) + if (pythOracle) { oraclePk = pythOracle } else { @@ -45,13 +43,14 @@ export const getOracle = async ({ baseSymbol, quoteSymbol, connection, - noLock: tier === 'SHIT' || tier === 'UNTRUSTED', + noLock: targetAmount === 0 || targetAmount === 1000, }) oraclePk = switchBoardOracle } return { oraclePk, isPyth: !!pythOracle } } catch (e) { + console.log(e) notify({ title: 'Oracle not found', description: `${e}`, @@ -268,7 +267,7 @@ export const getQuoteSymbol = (quoteTokenSymbol: string) => { } export const formatSuggestedValues = ( - suggestedParams: Record | Omit, + suggestedParams: Record | Omit, ) => { return { maxStalenessSlots: suggestedParams.maxStalenessSlots, diff --git a/utils/notifications.ts b/utils/notifications.ts index ad8e3295..1835e682 100644 --- a/utils/notifications.ts +++ b/utils/notifications.ts @@ -71,7 +71,7 @@ export function notify(newNotification: { } if ( - newNotif.txid && + !newNotif.txid || !notifications.find( (n) => n.txid == newNotif.txid && n.type == newNotif.type, ) diff --git a/yarn.lock b/yarn.lock index 4ac868c6..b7744eaf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,10 +42,10 @@ keccak256 "^1.0.6" merkletreejs "^0.3.11" -"@blockworks-foundation/mango-v4-settings@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4-settings/-/mango-v4-settings-0.3.3.tgz#84f37cb02dfe6371b30b6051f76fa11eef6c0b47" - integrity sha512-eIQK0593IOcoN3xITpKCU7toq8xG1x5yQL1pVgaZLEdBLv0M2QlUimBg9OVJ04t7Ch2SHDMcL+QMbqi8NKqUYg== +"@blockworks-foundation/mango-v4-settings@0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4-settings/-/mango-v4-settings-0.4.3.tgz#03a77096e2802479d284af21d8c90ca6e7f61ddb" + integrity sha512-95uEKS0rC06P+YK6uYLzlznfA95B2Vs7zpM0gVp6Q8oftaVMeIHg/BHadhESHLrAi3AzasuLwn4IzcKVOtX3Kw== dependencies: bn.js "^5.2.1" eslint-config-prettier "^9.0.0" @@ -58,10 +58,10 @@ bn.js "^5.2.1" eslint-config-prettier "^9.0.0" -"@blockworks-foundation/mango-v4@0.21.3": - version "0.21.3" - resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4/-/mango-v4-0.21.3.tgz#906800f63b4e847264444e13a628356b2afd6fbe" - integrity sha512-LBc5QjUrJwWcrUSnzW0KvXwfjDQMrg9gRujyHI6eV/BMLBhqw+NqrNMBDjdxgpcAnAna+WoX9aAsEPV9rmi7tQ== +"@blockworks-foundation/mango-v4@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4/-/mango-v4-0.21.5.tgz#5e3b3257de0a0efc98c1f9057982e434c1665120" + integrity sha512-tCBFb+eBltsJbFkcBPBgfk5Wzmwa+9MfNU7FTWX8vMycl+ck4svE8K05HEO25dWRSJmZbwx8osGxaqCsricAbQ== dependencies: "@blockworks-foundation/mango-v4-settings" "^0.2.16" "@coral-xyz/anchor" "^0.28.1-beta.2"