merge main

This commit is contained in:
saml33 2023-09-08 09:53:01 +10:00
commit d0845efbae
26 changed files with 292 additions and 102 deletions

View File

@ -1,57 +1,78 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
This repo contains the Next.js app for the Mango v4 user interface.
## Dependency Management
## ⚡️ Quickstart
When updating dependencies, there are various files that must be kept up-to-date. Newly added, or updated dependencies can introduce unwanted/malicious scripts that can introduce risks for users and/or developers. The `lavamoat allow-scripts` feature allows us to deny by default, but adds some additional steps to the usual workflow.
To get started, follow these steps:
`yarn.lock`:
- Instead of running `yarn` or `yarn install`, run `yarn setup` to ensure the `yarn.lock` file is in sync and that dependency scripts are run according to the `allowScripts` policy (set in `packages.json`)
- If `lavamoat` detects new scripts that are not explicitely allowed/denied, it'll throw and error with details (see below)
- Running `yarn setup` will also dedupe the `yarn.lock` file to reduce the dependency tree. Note CI will fail if there are dupes in `yarn.lock`!
The `allowScripts` configuration in `package.json`:
- There are two ways to configure script policies:
1. Update the allow-scripts section manually by adding the missing package in the `allowScripts` section in `package.json`
2. Run `yarn allow-scripts auto` to update the `allowScripts` configuration automatically
- Review each new package to determine whether the install script needs to run or not, testing if necessary.
- Use `npx can-i-ignore-scripts` to help assessing whether scripts are needed
## Getting Started
First, run the development server:
1. **Clone the repo:** Begin by cloning the repository using the command:
```bash
git clone git@github.com:blockworks-foundation/mango-v4-ui.git
```
2. **Install Dependencies:** Move into the directory and install the dependencies:
```bash
cd mango-v4-ui
yarn setup
```
3. **Run the app:**
```bash
npm run dev
# or
yarn dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
4. Browse to http://localhost:3000
You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
## ⌨️ Contributor's Guide
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
### Code quality
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
- Avoid duplication
- Consider performance (use useMemo and useCallback where appropriate)
- Create logical components and give them descriptive names
- Destructure objects and arrays
- Define constants for event functions unless they are very simple e.g. a single state update
- Create hooks for shared logic
- Add translation keys in alphabetical order
## Learn More
### Branching
To learn more about Next.js, take a look at the following resources:
Prefix your branches with your Git username and give them concise and descriptive names
e.g. username/branch-name
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
### Commits
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
Add commits for each self-contained change and give your commits clear messages that describe the change. Smaller commits that encompass a specific change are preferred over large commits with many changes
## Deploy on Vercel
### PRs
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
All PRs should have a meaningful name and include a description of what the changes are.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
If there are visual changes, include screenshots in the description.
## Creating Color Themes
If the PR is unfinished include a "TODO" section with work not yet completed. If there are known issues/bugs include a section outlining what they are.
#### Drafts
Opening draft PRs is a good way for other contributors to know a feature is being worked on. This is most useful for larger/complex features and is not a requirement. When your feature is at a point where you'd like to gather feedback or it's close to completion open a draft PR and share the preview link in the relevant Discord channel
Prefix "WIP:" to your draft PR name
### Reviews
When your changes are finished, who you request review from depends on the type of changes.
For complex changes e.g. new transactions, large features, lots of client or backend interactions you should at a minimum include @tlrsssss in your review
For changes that affect visual elements of the app (including text changes), request a review from @saml33 at a minimum
If you're unsure, request a review from @tlrssss and @saml33
If your work involves other parts of the stack (backend, client, etc.) request a review from the relevant person in that area
## 🎨 Creating Color Themes
1. Copy one of the other color themes in [tailwind.config.js](https://github.com/blockworks-foundation/mango-v4-ui/blob/main/tailwind.config.js) (starting line 25)
2. Modify the colors. For the variables bkg-\* and fgd-\* pick a base color for bkg-1 and fgd-1 then adjust the lightness for 2-4. Use this same process to create dark/hover variations for the colors that have these properties. The base color can be anything that works for your theme.

View File

@ -37,6 +37,8 @@ import { NFT } from 'types'
import { useViewport } from 'hooks/useViewport'
import useLocalStorageState from 'hooks/useLocalStorageState'
import { SIDEBAR_COLLAPSE_KEY } from 'utils/constants'
import { createTransferInstruction } from '@solana/spl-token'
import { PublicKey, TransactionInstruction } from '@solana/web3.js'
const SideNav = ({ collapsed }: { collapsed: boolean }) => {
const { t } = useTranslation(['common', 'search'])
@ -46,6 +48,10 @@ const SideNav = ({ collapsed }: { collapsed: boolean }) => {
const themeData = mangoStore((s) => s.themeData)
const nfts = mangoStore((s) => s.wallet.nfts.data)
const { mangoAccount } = useMangoAccount()
const setPrependedGlobalAdditionalInstructions = mangoStore(
(s) => s.actions.setPrependedGlobalAdditionalInstructions,
)
const router = useRouter()
const { pathname } = router
@ -88,14 +94,39 @@ const SideNav = ({ collapsed }: { collapsed: boolean }) => {
return mangoNfts
}, [nfts])
//mark transactions with used nfts
useEffect(() => {
let newInstruction: TransactionInstruction[] = []
if (mangoNfts.length && theme) {
const collectionAddress = CUSTOM_SKINS[theme.toLowerCase()]
const usedNft = mangoNfts.find(
(nft) => nft.collectionAddress === collectionAddress,
)
if (usedNft && publicKey && collectionAddress) {
newInstruction = [
createTransferInstruction(
new PublicKey(usedNft.tokenAccount),
new PublicKey(usedNft.tokenAccount),
publicKey,
1,
),
]
}
}
setPrependedGlobalAdditionalInstructions(newInstruction)
}, [mangoNfts, theme, themeData])
// find sidebar image url from skin nft for theme
const sidebarImageUrl = useMemo(() => {
if (!theme) return themeData.sideImagePath
const collectionAddress = CUSTOM_SKINS[theme.toLowerCase()]
if (collectionAddress && mangoNfts.length) {
const sidebarImageUrl =
mangoNfts.find((nft) => nft.collectionAddress === collectionAddress)
?.image || themeData.sideImagePath
const attributes = mangoNfts.find(
(nft) => nft.collectionAddress === collectionAddress,
)?.json?.attributes
const sidebarImageUrl = attributes
? attributes[0].value || themeData.sideImagePath
: ''
return sidebarImageUrl
}
return themeData.sideImagePath

View File

@ -468,9 +468,18 @@ const ListToken = ({ goBack }: { goBack: () => void }) => {
Number(tierPreset.maintLiabWeight),
Number(tierPreset.initLiabWeight),
Number(tierPreset.liquidationFee),
Number(tierPreset.delayIntervalSeconds),
Number(tierPreset.delayGrowthLimit),
Number(tierPreset.stableGrowthLimit),
Number(tierPreset.minVaultToDepositsRatio),
new BN(tierPreset.netBorrowLimitWindowSizeTs),
new BN(tierPreset.netBorrowLimitPerWindowQuote),
Number(tierPreset.borrowWeightScale),
Number(tierPreset.depositWeightScale),
Number(tierPreset.reduceOnly),
Number(tierPreset.tokenConditionalSwapTakerFeeRate),
Number(tierPreset.tokenConditionalSwapMakerFeeRate),
Number(tierPreset.flashLoanDepositFeeRate),
)
.accounts({
admin: MANGO_DAO_WALLET,
@ -502,13 +511,16 @@ const ListToken = ({ goBack }: { goBack: () => void }) => {
null,
null,
null,
tierPreset.borrowWeightScale,
tierPreset.depositWeightScale,
null,
null,
false,
false,
null,
null,
null,
null,
null,
null,
)
.accounts({
oracle: new PublicKey(advForm.oraclePk),
@ -524,7 +536,9 @@ const ListToken = ({ goBack }: { goBack: () => void }) => {
} as AccountMeta,
])
.instruction()
proposalTx.push(editIx)
if (!tierPreset.insuranceFound) {
proposalTx.push(editIx)
}
} else {
const trustlessIx = await client!.program.methods
.tokenRegisterTrustless(Number(advForm.tokenIndex), advForm.name)

View File

@ -15,7 +15,7 @@ const CreateAccountModal = ({ isOpen, onClose }: ModalProps) => {
return (
<Modal isOpen={isOpen} onClose={onClose}>
<div className="flex min-h-[264px] flex-col items-center justify-center">
<div className="flex min-h-[400px] flex-col items-center justify-center">
<CreateAccountForm customClose={handleClose} />
</div>
</Modal>

View File

@ -122,7 +122,7 @@ const CreateSwitchboardOracleModal = ({
minRequiredOracleResults: 3,
minRequiredJobResults: 2,
minUpdateDelaySeconds: 6,
forceReportPeriod: 24 * 60 * 60,
forceReportPeriod: 60 * 60,
withdrawAuthority: MANGO_DAO_WALLET,
authority: payer,
crankDataBuffer: crankAccount.dataBuffer?.publicKey,

View File

@ -196,6 +196,9 @@ const DashboardSuggestedValues = ({
bank.reduceOnly ? 0 : null,
null,
null,
getNullOrVal(fieldsToChange.tokenConditionalSwapTakerFeeRate),
getNullOrVal(fieldsToChange.tokenConditionalSwapMakerFeeRate),
getNullOrVal(fieldsToChange.loanFeeRate),
)
.accounts({
group: group!.publicKey,

View File

@ -102,7 +102,7 @@ const MangoAccountsListModal = ({
return (
<Modal isOpen={isOpen} onClose={onClose}>
<div className="inline-block w-full transform overflow-x-hidden">
<div className="flex min-h-[364px] flex-col justify-between">
<div className="flex min-h-[400px] flex-col justify-between">
<div>
<h2 className="text-center">{t('accounts')}</h2>
{loading ? (

View File

@ -14,7 +14,11 @@ import {
TrHead,
} from '@components/shared/TableElements'
import Tooltip from '@components/shared/Tooltip'
import { NoSymbolIcon, UsersIcon } from '@heroicons/react/20/solid'
import {
EyeSlashIcon,
NoSymbolIcon,
UsersIcon,
} from '@heroicons/react/20/solid'
import { useWallet } from '@solana/wallet-adapter-react'
import { PublicKey } from '@solana/web3.js'
import mangoStore from '@store/mangoStore'
@ -32,6 +36,7 @@ import PerpSideBadge from './PerpSideBadge'
import TableMarketName from './TableMarketName'
import { useSortableData } from 'hooks/useSortableData'
import { useCallback } from 'react'
import { useHiddenMangoAccounts } from 'hooks/useHiddenMangoAccounts'
const TradeHistory = () => {
const { t } = useTranslation(['common', 'trade'])
@ -45,6 +50,7 @@ const TradeHistory = () => {
} = useTradeHistory()
const { width } = useViewport()
const { connected } = useWallet()
const { hiddenAccounts } = useHiddenMangoAccounts()
const showTableView = width ? width > breakpoints.md : false
const formattedTableData = useCallback(() => {
@ -142,6 +148,14 @@ const TradeHistory = () => {
{tableData.map((trade, index: number) => {
const { side, price, market, size, feeCost, liquidity, value } =
trade
let counterpartyAddress = ''
if ('taker' in trade) {
counterpartyAddress =
trade.liquidity === 'Taker'
? trade.maker.toString()
: trade.taker.toString()
}
return (
<TrBody
key={`${side}${size}${price}${index}`}
@ -184,29 +198,41 @@ const TradeHistory = () => {
<Td className="xl:!pl-0">
{'taker' in trade ? (
<div className="flex justify-end">
<Tooltip
content={`View Counterparty ${abbreviateAddress(
trade.liquidity === 'Taker'
? new PublicKey(trade.maker)
: new PublicKey(trade.taker),
)}`}
delay={0}
>
<a
className=""
target="_blank"
rel="noopener noreferrer"
href={`/?address=${
trade.liquidity === 'Taker'
? trade.maker
: trade.taker
}`}
{!hiddenAccounts?.includes(counterpartyAddress) ? (
<Tooltip
content={t('trade:tooltip-view-counterparty', {
pk: abbreviateAddress(
trade.liquidity === 'Taker'
? new PublicKey(trade.maker)
: new PublicKey(trade.taker),
),
})}
delay={0}
>
<IconButton size="small">
<UsersIcon className="h-4 w-4" />
<a
className=""
target="_blank"
rel="noopener noreferrer"
href={`/?address=${counterpartyAddress}`}
>
<IconButton size="small">
<UsersIcon className="h-4 w-4" />
</IconButton>
</a>
</Tooltip>
) : (
<Tooltip
content={t('trade:tooltip-private-counterparty')}
>
<IconButton
className="bg-th-bkg-1"
disabled
size="small"
>
<EyeSlashIcon className="h-4 w-4" />
</IconButton>
</a>
</Tooltip>
</Tooltip>
)}
</div>
) : null}
</Td>
@ -220,6 +246,13 @@ const TradeHistory = () => {
<div>
{combinedTradeHistory.map((trade, index: number) => {
const { side, price, market, size, liquidity } = trade
let counterpartyAddress = ''
if ('taker' in trade) {
counterpartyAddress =
trade.liquidity === 'Taker'
? trade.maker.toString()
: trade.taker.toString()
}
return (
<div
className="flex items-center justify-between border-b border-th-bkg-3 p-4"
@ -259,18 +292,41 @@ const TradeHistory = () => {
</div>
</div>
{'taker' in trade ? (
<a
className=""
target="_blank"
rel="noopener noreferrer"
href={`/?address=${
liquidity === 'Taker' ? trade.maker : trade.taker
}`}
>
<IconButton size="small">
<UsersIcon className="h-4 w-4" />
</IconButton>
</a>
!hiddenAccounts?.includes(counterpartyAddress) ? (
<Tooltip
content={t('trade:tooltip-view-counterparty', {
pk: abbreviateAddress(
liquidity === 'Taker'
? new PublicKey(trade.maker)
: new PublicKey(trade.taker),
),
})}
delay={0}
>
<a
className=""
target="_blank"
rel="noopener noreferrer"
href={`/?address=${counterpartyAddress}`}
>
<IconButton size="small">
<UsersIcon className="h-4 w-4" />
</IconButton>
</a>
</Tooltip>
) : (
<Tooltip
content={t('trade:tooltip-private-counterparty')}
>
<IconButton
className="bg-th-bkg-1"
disabled
size="small"
>
<EyeSlashIcon className="h-4 w-4" />
</IconButton>
</Tooltip>
)
) : null}
</div>
</div>

View File

@ -39,7 +39,7 @@ export const getOracleProvider = (
case OracleProvider.Switchboard:
return [
'Switchboard',
`https://switchboard.xyz/explorer/3/${marketOrBase.oracle.toString()}`,
`https://app.switchboard.xyz/solana/mainnet-beta/feed/${marketOrBase.oracle.toString()}`,
]
case OracleProvider.Stub:
return ['Stub', '']

View File

@ -22,8 +22,8 @@
},
"dependencies": {
"@blockworks-foundation/mango-feeds": "0.1.7",
"@blockworks-foundation/mango-v4": "^0.19.15",
"@blockworks-foundation/mango-v4-settings": "0.2.6",
"@blockworks-foundation/mango-v4": "^0.19.20",
"@blockworks-foundation/mango-v4-settings": "0.2.8",
"@headlessui/react": "1.6.6",
"@heroicons/react": "2.0.10",
"@metaplex-foundation/js": "0.19.4",

View File

@ -197,6 +197,7 @@
"vote": "Vote",
"yes": "Yes",
"you": "You",
"using-ledger": "Using Ledger"
"using-ledger": "Using Ledger",
"sign-to-in-app-notifications": "Sign to in app notifications"
}

View File

@ -106,9 +106,11 @@
"tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled",
"tooltip-insured": "Whether or not {{tokenOrMarket}} losses can be recovered from the insurance fund in the event of bankruptcies.",
"tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled",
"tooltip-private-counterparty": "Counterparty has Private Account enabled",
"tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at",
"tooltip-volume-alert": "Volume Alert Settings",
"tooltip-stable-price": "Stable price is used in a safety mechanism that limits a user's ability to enter risky positions when the oracle price is changing rapidly",
"tooltip-view-counterparty": "View counterparty {{pk}}",
"tooltip-volume-alert": "Volume Alert Settings",
"total-pnl": "Total PnL",
"trade-sounds-tooltip": "Play a sound alert for every new trade",
"trades": "Trades",

View File

@ -197,6 +197,7 @@
"vote": "Vote",
"yes": "Yes",
"you": "You",
"using-ledger": "Using Ledger"
"using-ledger": "Using Ledger",
"sign-to-in-app-notifications": "Sign to in app notifications"
}

View File

@ -106,9 +106,11 @@
"tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled",
"tooltip-insured": "Whether or not {{tokenOrMarket}} losses can be recovered from the insurance fund in the event of bankruptcies.",
"tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled",
"tooltip-private-counterparty": "Counterparty has Private Account enabled",
"tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at",
"tooltip-volume-alert": "Volume Alert Settings",
"tooltip-stable-price": "Stable price is used in a safety mechanism that limits a user's ability to enter risky positions when the oracle price is changing rapidly",
"tooltip-view-counterparty": "View counterparty {{pk}}",
"tooltip-volume-alert": "Volume Alert Settings",
"total-pnl": "Total PnL",
"trade-sounds-tooltip": "Play a sound alert for every new trade",
"trades": "Trades",
@ -119,6 +121,7 @@
"tweet-position": "Tweet",
"unrealized-pnl": "Unrealized PnL",
"unsettled": "Unsettled",
"view-counterparty": "View counterparty {{pk}}",
"volume-alert": "Volume Alert",
"volume-alert-desc": "Play a sound whenever volume exceeds your alert threshold"
}

View File

@ -197,6 +197,7 @@
"vote": "Vote",
"yes": "Yes",
"you": "You",
"using-ledger": "Using Ledger"
"using-ledger": "Using Ledger",
"sign-to-in-app-notifications": "Sign to in app notifications"
}

View File

@ -106,9 +106,11 @@
"tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled",
"tooltip-insured": "Whether or not {{tokenOrMarket}} losses can be recovered from the insurance fund in the event of bankruptcies.",
"tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled",
"tooltip-private-counterparty": "Counterparty has Private Account enabled",
"tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at",
"tooltip-volume-alert": "Volume Alert Settings",
"tooltip-stable-price": "Stable price is used in a safety mechanism that limits a user's ability to enter risky positions when the oracle price is changing rapidly",
"tooltip-view-counterparty": "View counterparty {{pk}}",
"tooltip-volume-alert": "Volume Alert Settings",
"total-pnl": "Total PnL",
"trade-sounds-tooltip": "Play a sound alert for every new trade",
"trades": "Trades",
@ -119,6 +121,7 @@
"tweet-position": "Tweet",
"unrealized-pnl": "Unrealized PnL",
"unsettled": "Unsettled",
"view-counterparty": "View counterparty {{pk}}",
"volume-alert": "Volume Alert",
"volume-alert-desc": "Play a sound whenever volume exceeds your alert threshold"
}

View File

@ -196,6 +196,7 @@
"vote": "投票",
"yes": "是",
"you": "你",
"using-ledger": "Using Ledger"
"using-ledger": "Using Ledger",
"sign-to-in-app-notifications": "Sign to in app notifications"
}

View File

@ -110,8 +110,10 @@
"tooltip-insured": "如果发生破产,{{tokenOrMarket}}损失是否可以从保险基金中归还",
"tooltip-ioc": "IOC交易若不吃单就会被取消。任何无法立刻成交的部分将被取消",
"tooltip-post": "Post交易若不挂单就会被取消。",
"tooltip-private-counterparty": "Counterparty has Private Account enabled",
"tooltip-slippage": "当前价格与您的交易将执行的价格之间的差值的估计",
"tooltip-stable-price": "稳定价格用于一个安全机制。此机制可以限制用户在预言机价格快速波动时下风险高的订单",
"tooltip-view-counterparty": "View counterparty {{pk}}",
"tooltip-volume-alert": "交易量警报设定",
"total-pnl": "总盈亏",
"trade-sounds-tooltip": "为每笔新交易播放警报声音",
@ -119,6 +121,7 @@
"tweet-position": "分享至Twitter",
"unrealized-pnl": "未实现盈亏",
"unsettled": "未结清",
"view-counterparty": "View counterparty {{pk}}",
"volume-alert": "交易量警报",
"volume-alert-desc": "交易量超过警报设定时播放声音"
}

View File

@ -196,5 +196,7 @@
"vote": "投票",
"yes": "是",
"you": "你",
"using-ledger": "Using Ledger",
"sign-to-in-app-notifications": "Sign to in app notifications"
"using-ledger": "Using Ledger"
}

View File

@ -106,8 +106,10 @@
"tooltip-insured": "如果發生破產,{{tokenOrMarket}}損失是否可以從保險基金中歸還",
"tooltip-ioc": "IOC交易若不吃單就會被取消。任何無法立刻成交的部分將被取消",
"tooltip-post": "Post交易若不掛單就會被取消。",
"tooltip-private-counterparty": "Counterparty has Private Account enabled",
"tooltip-slippage": "當前價格與您的交易將執行的價格之間的差值的估計",
"tooltip-stable-price": "穩定價格用於一個安全機制。此機制可以限制用戶在預言機價格快速波動時下風險高的訂單",
"tooltip-view-counterparty": "View counterparty {{pk}}",
"tooltip-volume-alert": "交易量警報設定",
"total-pnl": "總盈虧",
"trade-sounds-tooltip": "為每筆新交易播放警報聲音",
@ -119,6 +121,7 @@
"tweet-position": "分享至Twitter",
"unrealized-pnl": "未實現盈虧",
"unsettled": "未結清",
"view-counterparty": "View counterparty {{pk}}",
"volume-alert": "交易量警報",
"volume-alert-desc": "交易量超過警報設定時播放聲音"
}

View File

@ -9,6 +9,7 @@ import {
Keypair,
PublicKey,
RecentPrioritizationFees,
TransactionInstruction,
} from '@solana/web3.js'
import { OpenOrders, Order } from '@project-serum/serum/lib/market'
import { Orderbook } from '@project-serum/serum'
@ -114,10 +115,18 @@ export const emptyWallet = new EmptyWallet(Keypair.generate())
const initMangoClient = (
provider: AnchorProvider,
opts = { prioritizationFee: DEFAULT_PRIORITY_FEE },
opts: {
prioritizationFee: number
prependedGlobalAdditionalInstructions: TransactionInstruction[]
} = {
prioritizationFee: DEFAULT_PRIORITY_FEE,
prependedGlobalAdditionalInstructions: [],
},
): MangoClient => {
return MangoClient.connect(provider, CLUSTER, MANGO_V4_ID[CLUSTER], {
prioritizationFee: opts.prioritizationFee,
prependedGlobalAdditionalInstructions:
opts.prependedGlobalAdditionalInstructions,
idsSource: 'api',
postSendTxCallback: ({ txid }: { txid: string }) => {
notify({
@ -193,6 +202,7 @@ export type MangoStore = {
details: ProfileDetails | null
loadDetails: boolean
}
prependedGlobalAdditionalInstructions: TransactionInstruction[]
priorityFee: number
selectedMarket: {
name: string | undefined
@ -283,6 +293,9 @@ export type MangoStore = {
connectMangoClientWithWallet: (wallet: WalletAdapter) => Promise<void>
loadMarketFills: () => Promise<void>
updateConnection: (url: string) => void
setPrependedGlobalAdditionalInstructions: (
instructions: TransactionInstruction[],
) => void
estimatePriorityFee: (feeMultiplier: number) => Promise<void>
}
}
@ -358,6 +371,7 @@ const mangoStore = create<MangoStore>()(
details: { profile_name: '', trader_category: '', wallet_pk: '' },
},
priorityFee: DEFAULT_PRIORITY_FEE,
prependedGlobalAdditionalInstructions: [],
selectedMarket: {
name: 'SOL/USDC',
current: undefined,
@ -1016,8 +1030,11 @@ const mangoStore = create<MangoStore>()(
)
provider.opts.skipPreflight = true
const priorityFee = get().priorityFee ?? DEFAULT_PRIORITY_FEE
const client = initMangoClient(provider, {
prioritizationFee: priorityFee,
prependedGlobalAdditionalInstructions:
get().prependedGlobalAdditionalInstructions,
})
set((s) => {
@ -1033,6 +1050,25 @@ const mangoStore = create<MangoStore>()(
}
}
},
async setPrependedGlobalAdditionalInstructions(
instructions: TransactionInstruction[],
) {
const set = get().set
const client = mangoStore.getState().client
const provider = client.program.provider as AnchorProvider
provider.opts.skipPreflight = true
const newClient = initMangoClient(provider, {
prioritizationFee: get().priorityFee,
prependedGlobalAdditionalInstructions: instructions,
})
set((s) => {
s.client = newClient
s.prependedGlobalAdditionalInstructions = instructions
})
},
async fetchProfileDetails(walletPk: string) {
const set = get().set
set((state) => {
@ -1128,7 +1164,11 @@ const mangoStore = create<MangoStore>()(
options,
)
newProvider.opts.skipPreflight = true
const newClient = initMangoClient(newProvider)
const newClient = initMangoClient(newProvider, {
prependedGlobalAdditionalInstructions:
get().prependedGlobalAdditionalInstructions,
prioritizationFee: DEFAULT_PRIORITY_FEE,
})
set((state) => {
state.connection = newConnection
state.client = newClient
@ -1180,6 +1220,8 @@ const mangoStore = create<MangoStore>()(
provider.opts.skipPreflight = true
const newClient = initMangoClient(provider, {
prioritizationFee: feeEstimate,
prependedGlobalAdditionalInstructions:
get().prependedGlobalAdditionalInstructions,
})
set((state) => {
state.priorityFee = feeEstimate

View File

@ -7,6 +7,7 @@ import {
Serum3Market,
} from '@blockworks-foundation/mango-v4'
import { Modify } from '@blockworks-foundation/mango-v4'
import { JsonMetadata } from '@metaplex-foundation/js'
import { Event } from '@project-serum/serum/lib/queue'
import { PublicKey } from '@solana/web3.js'
import { formatTradeHistory } from 'hooks/useTradeHistory'
@ -305,6 +306,7 @@ export interface NFT {
name: string
mint: string
tokenAccount: string
json: JsonMetadata | null
}
export interface PerpStatsItem {

View File

@ -49,7 +49,7 @@ export const FAVORITE_SWAPS_KEY = 'favoriteSwaps-0.1'
export const THEME_KEY = 'theme-0.1'
export const RPC_PROVIDER_KEY = 'rpcProviderKey-0.8'
export const RPC_PROVIDER_KEY = 'rpcProviderKey-0.9'
export const PRIORITY_FEE_KEY = 'priorityFeeKey-0.2'

View File

@ -84,5 +84,5 @@ export const nftThemeMeta: NftThemeMeta = {
export const CUSTOM_SKINS: { [key: string]: string } = {
bonk: '6FUYsgvSPiLsMpKZqLWswkw7j4juudZyVopU6RYKLkQ3',
pepe: '6FUYsgvSPiLsMpKZqLWswkw7j4juudZyVopU6RYKLkQ3',
pepe: 'B4QhXJaSnUBT8aWiPz5GmB9sjXdQDtHXv8x1WsRFHNJx',
}

View File

@ -93,6 +93,7 @@ const enhanceNFT = (nft: NftWithATA) => {
collectionAddress: nft.collection?.address.toBase58(),
mint: nft.mint.address.toBase58(),
tokenAccount: nft.tokenAccountAddress?.toBase58() || '',
json: nft.json,
}
}

View File

@ -26,24 +26,24 @@
dependencies:
ws "^8.13.0"
"@blockworks-foundation/mango-v4-settings@0.2.6":
version "0.2.6"
resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4-settings/-/mango-v4-settings-0.2.6.tgz#725a8cf669e164cd7694d97989472f7852afad68"
integrity sha512-RK8O8lbflIN9IgNE1uUkjrtlv/7f0BjIqTwcuLNFos6/e/Q2/AnlXRlD5Y9WnO6xS7mXNsw9kr05xCxeYZzM1Q==
"@blockworks-foundation/mango-v4-settings@0.2.8":
version "0.2.8"
resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4-settings/-/mango-v4-settings-0.2.8.tgz#fa88d6ddb6dcc1dd1cd8f75ab96bc0d41629799d"
integrity sha512-20h5+Vky3YZfd3ekcnMgUxp1XaddFgtSNE6SPCy1oOAOjzvDHgZ3AVJd95WTTjTONGTZqqmTbP2ReWIu4ZfP6w==
dependencies:
bn.js "^5.2.1"
eslint-config-prettier "^9.0.0"
"@blockworks-foundation/mango-v4@^0.19.15":
version "0.19.15"
resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4/-/mango-v4-0.19.15.tgz#0e62d9c2f06c103b39abb648a529702048fd2706"
integrity sha512-aWtnBgbPJ2F1RZ4dCpu2ans5KQmt7d4en55Dp/n17hWjRUGA4tTPwthE8uoeRqc6ih19ldgDj2oMQAl6XzWQzg==
"@blockworks-foundation/mango-v4@^0.19.20":
version "0.19.20"
resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4/-/mango-v4-0.19.20.tgz#5932b98bfc94eed1f7cdffdef535afe19c1cce03"
integrity sha512-UGPmJ/NPDdIHM7BcYSOOZHDYDse6mefTGI2IK9MRxaqAVpqfFj3Kjk8mM12O+CW1cySaMl3NUAyR/Ul0jGY+jg==
dependencies:
"@coral-xyz/anchor" "^0.27.0"
"@project-serum/serum" "0.13.65"
"@pythnetwork/client" "~2.14.0"
"@solana/spl-token" "0.3.7"
"@solana/web3.js" "^1.73.2"
"@solana/web3.js" "^1.78.2"
"@switchboard-xyz/sbv2-lite" "^0.1.6"
big.js "^6.1.1"
binance-api-node "^0.12.0"
@ -1999,7 +1999,7 @@
"@wallet-standard/app" "^1.0.1"
"@wallet-standard/base" "^1.0.1"
"@solana/web3.js@^1.17.0", "@solana/web3.js@^1.21.0", "@solana/web3.js@^1.22.0", "@solana/web3.js@^1.32.0", "@solana/web3.js@^1.36.0", "@solana/web3.js@^1.44.3", "@solana/web3.js@^1.50.1", "@solana/web3.js@^1.56.2", "@solana/web3.js@^1.63.1", "@solana/web3.js@^1.66.2", "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.73.2", "@solana/web3.js@^1.78.3":
"@solana/web3.js@^1.17.0", "@solana/web3.js@^1.21.0", "@solana/web3.js@^1.22.0", "@solana/web3.js@^1.32.0", "@solana/web3.js@^1.36.0", "@solana/web3.js@^1.44.3", "@solana/web3.js@^1.50.1", "@solana/web3.js@^1.56.2", "@solana/web3.js@^1.63.1", "@solana/web3.js@^1.66.2", "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.78.2", "@solana/web3.js@^1.78.3":
version "1.78.4"
resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.78.4.tgz#e8ca9abe4ec2af5fc540c1d272efee24aaffedb3"
integrity sha512-up5VG1dK+GPhykmuMIozJZBbVqpm77vbOG6/r5dS7NBGZonwHfTLdBbsYc3rjmaQ4DpCXUa3tUc4RZHRORvZrw==