Merge remote-tracking branch 'origin/main' into stats-page
This commit is contained in:
commit
d31eb4b119
1
.babelrc
1
.babelrc
|
@ -12,6 +12,7 @@
|
|||
],
|
||||
"plugins": [
|
||||
"babel-plugin-macros",
|
||||
"@babel/plugin-proposal-logical-assignment-operators",
|
||||
["styled-components", { "ssr": true }],
|
||||
"@emotion/babel-plugin"
|
||||
]
|
||||
|
|
|
@ -139,13 +139,17 @@ const AccountSelect = ({
|
|||
|
||||
return (
|
||||
<Listbox.Option
|
||||
disabled={getBalanceForAccount(account) === '0'}
|
||||
key={account?.publicKey.toString()}
|
||||
value={account?.publicKey.toString()}
|
||||
>
|
||||
{({ selected }) => (
|
||||
{({ disabled, selected }) => (
|
||||
<div
|
||||
className={`p-2 hover:bg-th-bkg-2 hover:cursor-pointer ${
|
||||
selected && `text-th-primary`
|
||||
} ${
|
||||
disabled &&
|
||||
'opacity-50 hover:bg-th-bkg-1 hover:cursor-not-allowed'
|
||||
}`}
|
||||
>
|
||||
<div className={`flex items-center text-th-fgd-1`}>
|
||||
|
|
|
@ -62,7 +62,7 @@ const BalancesTable = () => {
|
|||
({ borrows, marginDeposits }) => borrows > 0 && marginDeposits > 0
|
||||
)) ? (
|
||||
<div
|
||||
className={`flex items-center justify-between p-4 mb-2 rounded-md bg-th-bkg-1`}
|
||||
className={`flex items-center justify-between px-4 py-2 mb-2 rounded-md bg-th-bkg-1`}
|
||||
>
|
||||
<div className="flex items-center text-fgd-1 font-semibold pr-4">
|
||||
You have unsettled funds
|
||||
|
@ -86,37 +86,37 @@ const BalancesTable = () => {
|
|||
<Tr className="text-th-fgd-3">
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left font-normal`}
|
||||
className={`px-6 py-2 text-left font-normal`}
|
||||
>
|
||||
Coin
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left font-normal`}
|
||||
className={`px-6 py-2 text-left font-normal`}
|
||||
>
|
||||
Deposits
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left font-normal`}
|
||||
className={`px-6 py-2 text-left font-normal`}
|
||||
>
|
||||
Borrows
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left font-normal`}
|
||||
className={`px-6 py-2 text-left font-normal`}
|
||||
>
|
||||
In Orders
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left font-normal`}
|
||||
className={`px-6 py-2 text-left font-normal`}
|
||||
>
|
||||
Unsettled
|
||||
</Th>
|
||||
<Th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left font-normal`}
|
||||
className={`px-6 py-2 text-left font-normal`}
|
||||
>
|
||||
Net
|
||||
</Th>
|
||||
|
|
|
@ -267,8 +267,7 @@ const DepositModal: FunctionComponent<DepositModalProps> = ({
|
|||
}
|
||||
}
|
||||
|
||||
const validateAmountInput = (e) => {
|
||||
const amount = e.target.value
|
||||
const validateAmountInput = (amount) => {
|
||||
if (Number(amount) <= 0) {
|
||||
setInvalidAmountMessage('Enter an amount to deposit')
|
||||
}
|
||||
|
@ -289,9 +288,14 @@ const DepositModal: FunctionComponent<DepositModalProps> = ({
|
|||
const onChangeSlider = async (percentage) => {
|
||||
const max = getBalanceForAccount(selectedAccount)
|
||||
const amount = (percentage / 100) * max
|
||||
setInputAmount(trimDecimals(amount, DECIMALS[symbol]))
|
||||
if (percentage === 100) {
|
||||
setInputAmount(amount)
|
||||
} else {
|
||||
setInputAmount(trimDecimals(amount, DECIMALS[symbol]))
|
||||
}
|
||||
setSliderPercentage(percentage)
|
||||
setInvalidAmountMessage('')
|
||||
validateAmountInput(amount)
|
||||
}
|
||||
|
||||
// turn off slider transition for dragging slider handle interaction
|
||||
|
@ -344,7 +348,7 @@ const DepositModal: FunctionComponent<DepositModalProps> = ({
|
|||
className={`border border-th-fgd-4 flex-grow pr-11`}
|
||||
placeholder="0.00"
|
||||
error={!!invalidAmountMessage}
|
||||
onBlur={validateAmountInput}
|
||||
onBlur={(e) => validateAmountInput(e.target.value)}
|
||||
value={inputAmount}
|
||||
onChange={(e) => onChangeAmountInput(e.target.value)}
|
||||
suffix={symbol}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { percentFormat } from '../utils/index'
|
||||
import useSrmAccount from '../hooks/useSrmAccount'
|
||||
import { SRM_DECIMALS } from '@project-serum/serum/lib/token-instructions'
|
||||
import Tooltip from './Tooltip'
|
||||
import { InformationCircleIcon } from '@heroicons/react/outline'
|
||||
|
||||
const FeeDiscountsTable = () => {
|
||||
const { totalSrm, rates } = useSrmAccount()
|
||||
|
@ -27,9 +29,24 @@ const FeeDiscountsTable = () => {
|
|||
</div>
|
||||
</div>
|
||||
<div className="px-4 mt-4 sm:mt-0">
|
||||
<div>Taker Fee</div>
|
||||
<div className="flex items-center">
|
||||
<div>Taker Fee</div>
|
||||
<div className="flex items-center">
|
||||
<Tooltip
|
||||
content={`Taker fee is ${percentFormat.format(
|
||||
rates.taker
|
||||
)} before the 20% GUI hoster fee is rebated.`}
|
||||
>
|
||||
<div>
|
||||
<InformationCircleIcon
|
||||
className={`h-5 w-5 ml-2 text-th-fgd-4 cursor-help`}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-th-fgd-1 text-lg font-semibold">
|
||||
{rates ? percentFormat.format(rates.taker) : null}
|
||||
{rates ? percentFormat.format(rates.taker * 0.8) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -20,6 +20,8 @@ const MarketHeader = () => {
|
|||
const volume = ohlcv ? ohlcv.v[0] : '--'
|
||||
|
||||
const fetchOhlcv = useCallback(async () => {
|
||||
if (!selectedMarketName) return
|
||||
|
||||
// calculate from and to date (0:00UTC to 23:59:59UTC)
|
||||
const date = new Date()
|
||||
const utcFrom = new Date(
|
||||
|
|
|
@ -111,8 +111,7 @@ const NewAccount: FunctionComponent<NewAccountProps> = ({
|
|||
})
|
||||
}
|
||||
|
||||
const validateAmountInput = (e) => {
|
||||
const amount = e.target.value
|
||||
const validateAmountInput = (amount) => {
|
||||
if (Number(amount) <= 0) {
|
||||
setInvalidAmountMessage('Enter an amount to deposit')
|
||||
}
|
||||
|
@ -133,9 +132,14 @@ const NewAccount: FunctionComponent<NewAccountProps> = ({
|
|||
const onChangeSlider = async (percentage) => {
|
||||
const max = getBalanceForAccount(selectedAccount)
|
||||
const amount = (percentage / 100) * max
|
||||
setInputAmount(trimDecimals(amount, DECIMALS[symbol]))
|
||||
if (percentage === 100) {
|
||||
setInputAmount(amount)
|
||||
} else {
|
||||
setInputAmount(trimDecimals(amount, DECIMALS[symbol]))
|
||||
}
|
||||
setSliderPercentage(percentage)
|
||||
setInvalidAmountMessage('')
|
||||
validateAmountInput(amount)
|
||||
}
|
||||
|
||||
// turn off slider transition for dragging slider handle interaction
|
||||
|
@ -173,7 +177,7 @@ const NewAccount: FunctionComponent<NewAccountProps> = ({
|
|||
className={`border border-th-fgd-4 flex-grow pr-11`}
|
||||
placeholder="0.00"
|
||||
error={!!invalidAmountMessage}
|
||||
onBlur={validateAmountInput}
|
||||
onBlur={(e) => validateAmountInput(e.target.value)}
|
||||
value={inputAmount}
|
||||
onChange={(e) => onChangeAmountInput(e.target.value)}
|
||||
suffix={symbol}
|
||||
|
@ -187,7 +191,6 @@ const NewAccount: FunctionComponent<NewAccountProps> = ({
|
|||
) : null}
|
||||
<div className="pt-3 pb-4">
|
||||
<Slider
|
||||
disabled={null}
|
||||
value={sliderPercentage}
|
||||
onChange={(v) => onChangeSlider(v)}
|
||||
step={1}
|
||||
|
@ -195,7 +198,14 @@ const NewAccount: FunctionComponent<NewAccountProps> = ({
|
|||
/>
|
||||
</div>
|
||||
<div className={`pt-8 flex justify-center`}>
|
||||
<Button onClick={handleNewAccountDeposit} className="w-full">
|
||||
<Button
|
||||
disabled={
|
||||
inputAmount <= 0 ||
|
||||
inputAmount > getBalanceForAccount(selectedAccount)
|
||||
}
|
||||
onClick={handleNewAccountDeposit}
|
||||
className="w-full"
|
||||
>
|
||||
<div className={`flex items-center justify-center`}>
|
||||
{submitting && <Loading className="-ml-1 mr-3" />}
|
||||
Create Account
|
||||
|
|
|
@ -13,6 +13,8 @@ export default function PublicTrades() {
|
|||
const [trades, setTrades] = useState([])
|
||||
|
||||
const fetchTradesForChart = useCallback(async () => {
|
||||
if (!marketAddress) return
|
||||
|
||||
const newTrades = await ChartApi.getRecentTrades(marketAddress)
|
||||
if (!newTrades) return null
|
||||
if (newTrades.length && trades.length === 0) {
|
||||
|
|
|
@ -75,16 +75,18 @@ const StyledSliderButton = styled.button<StyledSliderButtonProps>`
|
|||
`
|
||||
|
||||
type SliderProps = {
|
||||
onChange: (...args: any[]) => any
|
||||
onChange: (x) => void
|
||||
onAfterChange?: (x) => void
|
||||
step: number
|
||||
value: number
|
||||
disabled: boolean
|
||||
disabled?: boolean
|
||||
max?: number
|
||||
maxButtonTransition?: boolean
|
||||
}
|
||||
|
||||
const AmountSlider: FunctionComponent<SliderProps> = ({
|
||||
onChange,
|
||||
onAfterChange,
|
||||
step,
|
||||
value,
|
||||
disabled,
|
||||
|
@ -120,6 +122,7 @@ const AmountSlider: FunctionComponent<SliderProps> = ({
|
|||
max={max}
|
||||
value={value || 0}
|
||||
onChange={onChange}
|
||||
onAfterChange={onAfterChange}
|
||||
step={step}
|
||||
enableTransition={enableTransition}
|
||||
disabled={disabled}
|
||||
|
|
|
@ -332,7 +332,11 @@ export default function TradeForm() {
|
|||
'border-th-green hover:border-th-green-dark'
|
||||
} text-th-green hover:text-th-fgd-1 hover:bg-th-green-dark flex-grow`}
|
||||
>
|
||||
{`${baseSize > 0 ? 'Buy ' + baseSize : 'Set BUY bid >= ' + market?.minOrderSize} ${baseCurrency}`}
|
||||
{`${
|
||||
baseSize > 0
|
||||
? 'Buy ' + baseSize
|
||||
: 'Set BUY bid >= ' + market?.minOrderSize
|
||||
} ${baseCurrency}`}
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
|
@ -343,7 +347,11 @@ export default function TradeForm() {
|
|||
'border-th-red hover:border-th-red-dark'
|
||||
} text-th-red hover:text-th-fgd-1 hover:bg-th-red-dark flex-grow`}
|
||||
>
|
||||
{`${baseSize > 0 ? 'Sell ' + baseSize : 'Set SELL bid >= ' + market?.minOrderSize} ${baseCurrency}`}
|
||||
{`${
|
||||
baseSize > 0
|
||||
? 'Sell ' + baseSize
|
||||
: 'Set SELL bid >= ' + market?.minOrderSize
|
||||
} ${baseCurrency}`}
|
||||
</Button>
|
||||
)
|
||||
) : (
|
||||
|
|
|
@ -25,7 +25,7 @@ export const defaultLayouts = {
|
|||
{ i: 'tradeForm', x: 9, y: 0, w: 3, h: 12 },
|
||||
{ i: 'marketTrades', x: 6, y: 1, w: 3, h: 13 },
|
||||
{ i: 'balanceInfo', x: 9, y: 1, w: 3, h: 15 },
|
||||
{ i: 'userInfo', x: 0, y: 2, w: 9, h: 18 },
|
||||
{ i: 'userInfo', x: 0, y: 2, w: 9, h: 19 },
|
||||
{ i: 'marginInfo', x: 9, y: 2, w: 3, h: 13 },
|
||||
],
|
||||
lg: [
|
||||
|
@ -35,7 +35,7 @@ export const defaultLayouts = {
|
|||
{ i: 'orderbook', x: 0, y: 2, w: 4, h: 17, minW: 2 },
|
||||
{ i: 'tradeForm', x: 4, y: 2, w: 4, h: 17, minW: 3 },
|
||||
{ i: 'marketTrades', x: 8, y: 2, w: 4, h: 17, minW: 2 },
|
||||
{ i: 'userInfo', x: 0, y: 3, w: 12, h: 18, minW: 6 },
|
||||
{ i: 'userInfo', x: 0, y: 3, w: 12, h: 19, minW: 6 },
|
||||
],
|
||||
md: [
|
||||
{ i: 'tvChart', x: 0, y: 0, w: 8, h: 26, minW: 2 },
|
||||
|
@ -44,7 +44,7 @@ export const defaultLayouts = {
|
|||
{ i: 'orderbook', x: 0, y: 2, w: 4, h: 17, minW: 2 },
|
||||
{ i: 'tradeForm', x: 4, y: 2, w: 4, h: 17, minW: 3 },
|
||||
{ i: 'marketTrades', x: 8, y: 2, w: 4, h: 17, minW: 2 },
|
||||
{ i: 'userInfo', x: 0, y: 3, w: 12, h: 18, minW: 6 },
|
||||
{ i: 'userInfo', x: 0, y: 3, w: 12, h: 19, minW: 6 },
|
||||
],
|
||||
sm: [
|
||||
{ i: 'tvChart', x: 0, y: 0, w: 12, h: 25, minW: 6 },
|
||||
|
@ -53,7 +53,7 @@ export const defaultLayouts = {
|
|||
{ i: 'tradeForm', x: 0, y: 2, w: 12, h: 13, minW: 3 },
|
||||
{ i: 'orderbook', x: 0, y: 3, w: 6, h: 17, minW: 3 },
|
||||
{ i: 'marketTrades', x: 6, y: 3, w: 6, h: 17, minW: 2 },
|
||||
{ i: 'userInfo', x: 0, y: 4, w: 12, h: 18, minW: 6 },
|
||||
{ i: 'userInfo', x: 0, y: 4, w: 12, h: 19, minW: 6 },
|
||||
],
|
||||
xs: [
|
||||
{ i: 'tvChart', x: 0, y: 0, w: 0, h: 0, minW: 6 },
|
||||
|
@ -62,11 +62,11 @@ export const defaultLayouts = {
|
|||
{ i: 'tradeForm', x: 0, y: 3, w: 12, h: 13, minW: 3 },
|
||||
{ i: 'orderbook', x: 0, y: 4, w: 6, h: 17, minW: 3 },
|
||||
{ i: 'marketTrades', x: 0, y: 5, w: 6, h: 17, minW: 2 },
|
||||
{ i: 'userInfo', x: 0, y: 6, w: 12, h: 18, minW: 6 },
|
||||
{ i: 'userInfo', x: 0, y: 6, w: 12, h: 19, minW: 6 },
|
||||
],
|
||||
}
|
||||
|
||||
export const GRID_LAYOUT_KEY = 'mangoSavedLayouts-2.1'
|
||||
export const GRID_LAYOUT_KEY = 'mangoSavedLayouts-2.2'
|
||||
|
||||
const TradePageGrid = () => {
|
||||
const { uiLocked } = useMangoStore((s) => s.settings)
|
||||
|
|
|
@ -290,22 +290,39 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
|
||||
const onChangeSlider = async (percentage) => {
|
||||
const amount = (percentage / 100) * maxAmount
|
||||
setInputAmount(trimDecimals(amount, DECIMALS[withdrawTokenSymbol] + 2))
|
||||
if (percentage === 100) {
|
||||
setInputAmount(trimDecimals(maxAmount, DECIMALS[withdrawTokenSymbol] + 4))
|
||||
} else {
|
||||
setInputAmount(trimDecimals(amount, DECIMALS[withdrawTokenSymbol] + 2))
|
||||
}
|
||||
setSliderPercentage(percentage)
|
||||
setInvalidAmountMessage('')
|
||||
validateAmountInput(amount)
|
||||
}
|
||||
|
||||
const validateAmountInput = (e) => {
|
||||
const amount = e.target.value
|
||||
if (Number(amount) <= 0) {
|
||||
setInvalidAmountMessage('Withdrawal amount must be greater than 0')
|
||||
const validateAmountInput = (amount) => {
|
||||
if (
|
||||
(Number(amount) <= 0 && getMaxForSelectedAsset() > 0) ||
|
||||
(Number(amount) <= 0 && includeBorrow)
|
||||
) {
|
||||
setInvalidAmountMessage('Enter an amount to withdraw')
|
||||
}
|
||||
if (simulation.collateralRatio < 1.2) {
|
||||
if (
|
||||
(getMaxForSelectedAsset() === 0 ||
|
||||
Number(amount) > getMaxForSelectedAsset()) &&
|
||||
!includeBorrow
|
||||
) {
|
||||
setInvalidAmountMessage('Insufficient balance. Borrow funds to withdraw')
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (simulation && simulation.collateralRatio < 1.2 && includeBorrow) {
|
||||
setInvalidAmountMessage(
|
||||
'Leverage too high. Reduce the amount to withdraw'
|
||||
)
|
||||
}
|
||||
}
|
||||
}, [simulation])
|
||||
|
||||
const trimDecimals = (n, digits) => {
|
||||
const step = Math.pow(10, digits || 0)
|
||||
|
@ -414,8 +431,9 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
<div className="flex justify-between pb-2 pt-4">
|
||||
<div className="text-th-fgd-1">Amount</div>
|
||||
<div className="flex space-x-4">
|
||||
<div
|
||||
className="text-th-fgd-1 underline cursor-pointer default-transition hover:text-th-primary hover:no-underline"
|
||||
<button
|
||||
className="font-normal text-th-fgd-1 underline cursor-pointer default-transition hover:text-th-primary hover:no-underline focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
disabled={!includeBorrow && getMaxForSelectedAsset() === 0}
|
||||
onClick={
|
||||
includeBorrow
|
||||
? setMaxBorrowForSelectedAsset
|
||||
|
@ -423,7 +441,7 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
}
|
||||
>
|
||||
Max
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex">
|
||||
|
@ -435,7 +453,7 @@ const WithdrawModal: FunctionComponent<WithdrawModalProps> = ({
|
|||
error={!!invalidAmountMessage}
|
||||
placeholder="0.00"
|
||||
value={inputAmount}
|
||||
onBlur={validateAmountInput}
|
||||
onBlur={(e) => validateAmountInput(e.target.value)}
|
||||
onChange={(e) => onChangeAmountInput(e.target.value)}
|
||||
suffix={withdrawTokenSymbol}
|
||||
/>
|
||||
|
|
|
@ -8,18 +8,15 @@ import {
|
|||
floorToDecimal,
|
||||
} from '../utils'
|
||||
import useAllMarkets from './useAllMarkets'
|
||||
import { sumBy } from 'lodash'
|
||||
|
||||
export function useBalances(): Balances[] {
|
||||
let balances = []
|
||||
const balances = []
|
||||
const markets = useAllMarkets()
|
||||
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
const marginAccount = useMangoStore((s) => s.selectedMarginAccount.current)
|
||||
const { symbols } = useMarketList()
|
||||
|
||||
let nativeQuoteFree = 0
|
||||
let nativeQuoteLocked = 0
|
||||
let nativeQuoteUnsettled = 0
|
||||
|
||||
for (const { market, baseCurrency, quoteCurrency } of markets) {
|
||||
if (!marginAccount || !mangoGroup || !market) {
|
||||
return []
|
||||
|
@ -44,24 +41,23 @@ export function useBalances(): Balances[] {
|
|||
}
|
||||
|
||||
const nativeBaseFree = openOrders?.baseTokenFree || 0
|
||||
nativeQuoteFree += openOrders?.quoteTokenFree || 0
|
||||
const nativeQuoteFree =
|
||||
(openOrders?.quoteTokenFree || 0) +
|
||||
(openOrders?.['referrerRebatesAccrued'].toNumber() || 0)
|
||||
|
||||
const nativeBaseLocked = openOrders
|
||||
? openOrders.baseTokenTotal - nativeBaseFree
|
||||
? openOrders.baseTokenTotal - openOrders?.baseTokenFree
|
||||
: 0
|
||||
nativeQuoteLocked += openOrders
|
||||
? openOrders?.quoteTokenTotal - nativeQuoteFree
|
||||
const nativeQuoteLocked = openOrders
|
||||
? openOrders?.quoteTokenTotal - (openOrders?.quoteTokenFree || 0)
|
||||
: 0
|
||||
|
||||
const nativeBaseUnsettled = openOrders?.baseTokenFree || 0
|
||||
nativeQuoteUnsettled += openOrders?.quoteTokenFree || 0
|
||||
|
||||
const tokenIndex = marketIndex
|
||||
|
||||
const net = (borrows, currencyIndex) => {
|
||||
const net = (locked, currencyIndex) => {
|
||||
const amount =
|
||||
marginAccount.getNativeDeposit(mangoGroup, currencyIndex) +
|
||||
borrows -
|
||||
locked -
|
||||
marginAccount.getNativeBorrow(mangoGroup, currencyIndex)
|
||||
|
||||
return floorToDecimal(
|
||||
|
@ -89,9 +85,8 @@ export function useBalances(): Balances[] {
|
|||
nativeBaseLocked,
|
||||
mangoGroup.mintDecimals[tokenIndex]
|
||||
),
|
||||
openOrders,
|
||||
unsettled: nativeToUi(
|
||||
nativeBaseUnsettled,
|
||||
nativeBaseFree,
|
||||
mangoGroup.mintDecimals[tokenIndex]
|
||||
),
|
||||
net: net(nativeBaseLocked, tokenIndex),
|
||||
|
@ -110,26 +105,41 @@ export function useBalances(): Balances[] {
|
|||
mangoGroup,
|
||||
quoteCurrencyIndex
|
||||
),
|
||||
openOrders,
|
||||
orders: nativeToUi(
|
||||
nativeQuoteLocked,
|
||||
mangoGroup.mintDecimals[quoteCurrencyIndex]
|
||||
),
|
||||
unsettled: nativeToUi(
|
||||
nativeQuoteUnsettled,
|
||||
nativeQuoteFree,
|
||||
mangoGroup.mintDecimals[quoteCurrencyIndex]
|
||||
),
|
||||
net: net(nativeQuoteLocked, quoteCurrencyIndex),
|
||||
},
|
||||
]
|
||||
balances = balances.concat(marketPair)
|
||||
balances.push(marketPair)
|
||||
}
|
||||
|
||||
balances.sort((a, b) => (a.coin > b.coin ? 1 : -1))
|
||||
const baseBalances = balances.map((b) => b[0])
|
||||
const quoteBalances = balances.map((b) => b[1])
|
||||
const quoteMeta = quoteBalances[0]
|
||||
const quoteInOrders = sumBy(quoteBalances, 'orders')
|
||||
const unsettled = sumBy(quoteBalances, 'unsettled')
|
||||
const net =
|
||||
quoteMeta.marginDeposits + unsettled - quoteMeta.borrows - quoteInOrders
|
||||
const quoteCurrencyIndex = Object.entries(symbols).findIndex(
|
||||
(x) => x[0] === quoteMeta.coin
|
||||
)
|
||||
|
||||
balances = balances.filter((elem, index, self) => {
|
||||
return index === self.map((a) => a.coin).indexOf(elem.coin)
|
||||
})
|
||||
|
||||
return balances
|
||||
return baseBalances.concat([
|
||||
{
|
||||
market: null,
|
||||
key: `${quoteMeta.coin}${quoteMeta.coin}`,
|
||||
coin: quoteMeta.coin,
|
||||
marginDeposits: quoteMeta.marginDeposits,
|
||||
borrows: quoteMeta.borrows,
|
||||
orders: quoteInOrders,
|
||||
unsettled,
|
||||
net: floorToDecimal(net, mangoGroup.mintDecimals[quoteCurrencyIndex]),
|
||||
},
|
||||
])
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ const SANCTIONED_COUNTRIES = [
|
|||
{ country: 'Venezuela', code: 'VE' },
|
||||
{ country: 'Yemen', code: 'YE' },
|
||||
{ country: 'Zimbabwe', code: 'ZW' },
|
||||
{ country: 'United States', code: 'US' },
|
||||
]
|
||||
|
||||
const SANCTIONED_COUNTRY_CODES = SANCTIONED_COUNTRIES.map(({ code }) => code)
|
||||
|
|
|
@ -16,6 +16,7 @@ export default function useOraclePrice() {
|
|||
|
||||
const fetchOraclePrice = useCallback(() => {
|
||||
if (selectedMangoGroup) {
|
||||
setOraclePrice(null)
|
||||
const marketIndex = getMarketIndex(marketAddress)
|
||||
selectedMangoGroup.getPrices(connection).then((prices) => {
|
||||
const oraclePriceForMarket = prices[marketIndex]
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"build": "next build",
|
||||
"start": "next start",
|
||||
"type-check": "tsc --pretty --noEmit",
|
||||
"format": "prettier --check .",
|
||||
"format": "prettier --write .",
|
||||
"lint": "eslint . --ext ts --ext tsx --ext js --quiet",
|
||||
"test": "jest",
|
||||
"test-all": "yarn lint && yarn type-check && yarn test"
|
||||
|
@ -31,7 +31,7 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@blockworks-foundation/mango-client": "^2.0.0",
|
||||
"@blockworks-foundation/mango-client": "2.1.0",
|
||||
"@emotion/react": "^11.1.5",
|
||||
"@emotion/styled": "^11.1.5",
|
||||
"@headlessui/react": "^1.2.0",
|
||||
|
@ -47,6 +47,7 @@
|
|||
"dayjs": "^1.10.4",
|
||||
"immer": "^9.0.1",
|
||||
"immutable-tuple": "^0.4.10",
|
||||
"lodash-es": "^4.17.21",
|
||||
"next": "^10.1.3",
|
||||
"next-themes": "^0.0.14",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
|
|
|
@ -24,8 +24,8 @@ export const ENDPOINTS: EndpointInfo[] = [
|
|||
},
|
||||
{
|
||||
name: 'devnet',
|
||||
url: 'https://devnet.solana.com',
|
||||
websocket: 'https://devnet.solana.com',
|
||||
url: 'https://api.devnet.solana.com',
|
||||
websocket: 'https://api.devnet.solana.com',
|
||||
custom: false,
|
||||
},
|
||||
]
|
||||
|
|
|
@ -856,13 +856,15 @@ export async function placeAndSettle(
|
|||
)
|
||||
const rates = getFeeRates(feeTier)
|
||||
const maxQuoteQuantity = new BN(
|
||||
spotMarket['_decoded'].quoteLotSize.toNumber() * (1 + rates.taker)
|
||||
).mul(
|
||||
spotMarket
|
||||
.baseSizeNumberToLots(size)
|
||||
.mul(spotMarket.priceNumberToLots(price))
|
||||
maxBaseQuantity
|
||||
.mul(limitPrice)
|
||||
.mul(spotMarket['_decoded'].quoteLotSize)
|
||||
.toNumber() *
|
||||
(1 + rates.taker)
|
||||
)
|
||||
|
||||
console.log(maxBaseQuantity.toString(), maxQuoteQuantity.toString())
|
||||
|
||||
if (maxBaseQuantity.lte(new BN(0))) {
|
||||
throw new Error('size too small')
|
||||
}
|
||||
|
@ -917,6 +919,26 @@ export async function placeAndSettle(
|
|||
}
|
||||
}
|
||||
|
||||
// Only send a pre-settle instruction if open orders account already exists
|
||||
if (!marginAccount.openOrders[marketIndex].equals(zeroKey)) {
|
||||
const settleFundsInstr = makeSettleFundsInstruction(
|
||||
programId,
|
||||
mangoGroup.publicKey,
|
||||
wallet.publicKey,
|
||||
marginAccount.publicKey,
|
||||
spotMarket.programId,
|
||||
spotMarket.publicKey,
|
||||
openOrdersKeys[marketIndex],
|
||||
mangoGroup.signerKey,
|
||||
spotMarket['_decoded'].baseVault,
|
||||
spotMarket['_decoded'].quoteVault,
|
||||
mangoGroup.vaults[marketIndex],
|
||||
mangoGroup.vaults[NUM_TOKENS - 1],
|
||||
dexSigner
|
||||
)
|
||||
transaction.add(settleFundsInstr)
|
||||
}
|
||||
|
||||
const keys = [
|
||||
{ isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey },
|
||||
{ isSigner: true, isWritable: false, pubkey: wallet.publicKey },
|
||||
|
@ -1281,14 +1303,18 @@ export async function settleAll(
|
|||
if (openOrdersAccount === undefined) {
|
||||
continue
|
||||
} else if (
|
||||
openOrdersAccount.quoteTokenFree.toNumber() === 0 &&
|
||||
openOrdersAccount.quoteTokenFree.toNumber() +
|
||||
openOrdersAccount['referrerRebatesAccrued'].toNumber() ===
|
||||
0 &&
|
||||
openOrdersAccount.baseTokenFree.toNumber() === 0
|
||||
) {
|
||||
continue
|
||||
}
|
||||
|
||||
assetGains[i] += openOrdersAccount.baseTokenFree.toNumber()
|
||||
assetGains[NUM_TOKENS - 1] += openOrdersAccount.quoteTokenFree.toNumber()
|
||||
assetGains[NUM_TOKENS - 1] +=
|
||||
openOrdersAccount.quoteTokenFree.toNumber() +
|
||||
openOrdersAccount['referrerRebatesAccrued'].toNumber()
|
||||
|
||||
const spotMarket = markets[i]
|
||||
const dexSigner = await PublicKey.createProgramAddress(
|
||||
|
@ -1338,6 +1364,7 @@ export async function settleAll(
|
|||
data,
|
||||
programId,
|
||||
})
|
||||
|
||||
transaction.add(settleFundsInstruction)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue