Main update (#801)

* fix: fixed transaction messages (#792)

* Open Source + Docker image (#793)

* feat: added dummy charting library

* feat: added docker workflow

* feat: remove tests and code-coverage

* feat: added final TradingView fallback

* env: set private to false

* fix: added production env

* env: added README and LICENSE

* env: cleanup variables

* env: add license field

* env: finish docker setup

* fix: updated the description of the dummy data

* docker: update actions to node 20 (#796)

* docker: added v2 prefix to tags

* perps: trading fee + expected price (#800)

* env: updated dependencies (#799)

* update docker CI to node 20 (#797)

* fix: fixed transaction messages (#792)

* Open Source + Docker image (#793)

* feat: added dummy charting library

* feat: added docker workflow

* feat: remove tests and code-coverage

* feat: added final TradingView fallback

* env: set private to false

* fix: added production env

* env: added README and LICENSE

* env: cleanup variables

* env: add license field

* env: finish docker setup

* fix: updated the description of the dummy data

* docker: update actions to node 20 (#796)

* docker: added v2 prefix to tags

* env: updated dependencies

---------

Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>
This commit is contained in:
Linkie Link 2024-02-13 17:30:04 +01:00 committed by GitHub
parent 2ca6771f48
commit 0bc3dcc687
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 780 additions and 894 deletions

View File

@ -24,7 +24,7 @@
"@delphi-labs/shuttle-react": "^3.19.1", "@delphi-labs/shuttle-react": "^3.19.1",
"@keplr-wallet/cosmos": "^0.12.67", "@keplr-wallet/cosmos": "^0.12.67",
"@splinetool/react-spline": "^2.2.6", "@splinetool/react-spline": "^2.2.6",
"@splinetool/runtime": "^1.0.51", "@splinetool/runtime": "^1.0.52",
"@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/container-queries": "^0.1.1",
"@tanstack/react-table": "^8.11.8", "@tanstack/react-table": "^8.11.8",
"@tippyjs/react": "^4.2.6", "@tippyjs/react": "^4.2.6",
@ -35,7 +35,7 @@
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"moment": "^2.30.1", "moment": "^2.30.1",
"next": "^13.5.4", "next": "^14.1.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-device-detect": "^2.2.3", "react-device-detect": "^2.2.3",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
@ -47,7 +47,6 @@
"react-toastify": "^10.0.4", "react-toastify": "^10.0.4",
"react-use-clipboard": "^1.0.9", "react-use-clipboard": "^1.0.9",
"recharts": "^2.12.0", "recharts": "^2.12.0",
"sharp": "^0.33.2",
"swr": "^2.2.4", "swr": "^2.2.4",
"tailwind-scrollbar-hide": "^1.1.7", "tailwind-scrollbar-hide": "^1.1.7",
"zustand": "^4.5.0" "zustand": "^4.5.0"
@ -62,7 +61,7 @@
"@types/react-dom": "18.2.19", "@types/react-dom": "18.2.19",
"@types/react-helmet": "^6.1.11", "@types/react-helmet": "^6.1.11",
"autoprefixer": "^10.4.17", "autoprefixer": "^10.4.17",
"dotenv": "^16.4.1", "dotenv": "^16.4.3",
"dotenv-cli": "^7.3.0", "dotenv-cli": "^7.3.0",
"eslint": "^8.56.0", "eslint": "^8.56.0",
"eslint-config-next": "^14.1.0", "eslint-config-next": "^14.1.0",

View File

@ -0,0 +1,28 @@
import BigNumber from 'bignumber.js'
import { CircularProgress } from 'components/common/CircularProgress'
import DisplayCurrency from 'components/common/DisplayCurrency'
import useTradingFeeAndPrice from 'hooks/perps/useTradingFeeAndPrice'
import { BNCoin } from 'types/classes/BNCoin'
type Props = {
denom: string
newAmount: BigNumber
previousAmount: BigNumber
}
export const ExpectedPrice = (props: Props) => {
const { data: tradingFeeAndPrice, isLoading } = useTradingFeeAndPrice(
props.denom,
props.newAmount,
props.previousAmount,
)
if (isLoading) return <CircularProgress className='h-full' size={12} />
if (tradingFeeAndPrice?.price) {
return <DisplayCurrency coin={BNCoin.fromDenomAndBigNumber('usd', tradingFeeAndPrice.price)} />
}
return '-'
}

View File

@ -7,10 +7,11 @@ import { ArrowRight } from 'components/common/Icons'
import SummaryLine from 'components/common/SummaryLine' import SummaryLine from 'components/common/SummaryLine'
import Text from 'components/common/Text' import Text from 'components/common/Text'
import TradeDirection from 'components/perps/BalancesTable/Columns/TradeDirection' import TradeDirection from 'components/perps/BalancesTable/Columns/TradeDirection'
import { ExpectedPrice } from 'components/perps/Module/ExpectedPrice'
import TradingFee from 'components/perps/Module/TradingFee' import TradingFee from 'components/perps/Module/TradingFee'
import { BN_ZERO } from 'constants/math' import { BN_ZERO } from 'constants/math'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount' import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useTradingFee from 'hooks/perps/useTradingFee' import useTradingFeeAndPrice from 'hooks/perps/useTradingFeeAndPrice'
import useStore from 'store' import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { formatLeverage } from 'utils/formatters' import { formatLeverage } from 'utils/formatters'
@ -20,7 +21,7 @@ type Props = {
amount: BigNumber amount: BigNumber
tradeDirection: TradeDirection tradeDirection: TradeDirection
asset: Asset asset: Asset
previousAmount?: BigNumber | null previousAmount: BigNumber
previousTradeDirection?: 'long' | 'short' previousTradeDirection?: 'long' | 'short'
previousLeverage?: number | null previousLeverage?: number | null
hasActivePosition: boolean hasActivePosition: boolean
@ -32,17 +33,21 @@ export default function PerpsSummary(props: Props) {
const modifyPerpPosition = useStore((s) => s.modifyPerpPosition) const modifyPerpPosition = useStore((s) => s.modifyPerpPosition)
const closePerpPosition = useStore((s) => s.closePerpPosition) const closePerpPosition = useStore((s) => s.closePerpPosition)
const currentAccount = useCurrentAccount() const currentAccount = useCurrentAccount()
const { data: tradingFee, isLoading } = useTradingFee(props.asset.denom, props.amount)
const newAmount = useMemo( const newAmount = useMemo(
() => (props.previousAmount ?? BN_ZERO).plus(props.amount), () => (props.previousAmount ?? BN_ZERO).plus(props.amount),
[props.amount, props.previousAmount], [props.amount, props.previousAmount],
) )
const { data: tradingFee } = useTradingFeeAndPrice(
props.asset.denom,
newAmount,
props.previousAmount,
)
const onConfirm = useCallback(async () => { const onConfirm = useCallback(async () => {
if (!currentAccount) return if (!currentAccount) return
if (props.previousAmount && newAmount.isZero()) { if (!props.previousAmount.isZero() && newAmount.isZero()) {
await closePerpPosition({ await closePerpPosition({
accountId: currentAccount.id, accountId: currentAccount.id,
denom: props.asset.denom, denom: props.asset.denom,
@ -50,7 +55,7 @@ export default function PerpsSummary(props: Props) {
return props.onTxExecuted() return props.onTxExecuted()
} }
if (props.previousAmount && newAmount) { if (!props.previousAmount.isZero() && !newAmount.isZero()) {
await modifyPerpPosition({ await modifyPerpPosition({
accountId: currentAccount.id, accountId: currentAccount.id,
coin: BNCoin.fromDenomAndBigNumber(props.asset.denom, newAmount), coin: BNCoin.fromDenomAndBigNumber(props.asset.denom, newAmount),
@ -75,12 +80,22 @@ export default function PerpsSummary(props: Props) {
<Text size='xs' className='font-bold mb-2'> <Text size='xs' className='font-bold mb-2'>
Summary Summary
</Text> </Text>
<SummaryLine label='Expected Price'>-</SummaryLine> <SummaryLine label='Expected Price'>
<ExpectedPrice
denom={props.asset.denom}
newAmount={newAmount}
previousAmount={props.previousAmount}
/>
</SummaryLine>
<SummaryLine <SummaryLine
label='Fees' label='Fees'
tooltip={`${tradingFee ? tradingFee.rate.times(100) + '% ' : ''}Trading Fees`} tooltip={`${tradingFee ? tradingFee.rate.times(100) + '% ' : ''}Trading Fees`}
> >
<TradingFee denom={props.asset.denom} amount={props.amount} /> <TradingFee
denom={props.asset.denom}
newAmount={newAmount}
previousAmount={props.previousAmount}
/>
</SummaryLine> </SummaryLine>
<SummaryLine label='Total'>-</SummaryLine> <SummaryLine label='Total'>-</SummaryLine>
</div> </div>

View File

@ -2,18 +2,23 @@ import BigNumber from 'bignumber.js'
import { CircularProgress } from 'components/common/CircularProgress' import { CircularProgress } from 'components/common/CircularProgress'
import DisplayCurrency from 'components/common/DisplayCurrency' import DisplayCurrency from 'components/common/DisplayCurrency'
import useTradingFee from 'hooks/perps/useTradingFee' import useTradingFeeAndPrice from 'hooks/perps/useTradingFeeAndPrice'
type Props = { type Props = {
denom: string denom: string
amount: BigNumber newAmount: BigNumber
previousAmount: BigNumber
} }
export default function TradingFee(props: Props) { export default function TradingFee(props: Props) {
const { data: openingFee, isLoading } = useTradingFee(props.denom, props.amount) const { data: tradingFeeAndPrice, isLoading } = useTradingFeeAndPrice(
props.denom,
props.newAmount,
props.previousAmount,
)
if (isLoading) return <CircularProgress className='h-full' size={12} /> if (isLoading) return <CircularProgress className='h-full' size={12} />
if (props.amount.isZero() || !openingFee) return '-' if (props.newAmount.isEqualTo(props.previousAmount) || !tradingFeeAndPrice?.fee) return '-'
return <DisplayCurrency coin={openingFee.fee} /> return <DisplayCurrency coin={tradingFeeAndPrice.fee} />
} }

View File

@ -38,7 +38,11 @@ export default function usePerpsModule(amount: BigNumber | null) {
const previousLeverage = useMemo( const previousLeverage = useMemo(
() => () =>
previousAmount previousAmount
? price.times(demagnify(previousAmount, perpsAsset)).div(accountNetValue).plus(1).toNumber() ? price
.times(demagnify(previousAmount.abs(), perpsAsset))
.div(accountNetValue)
.plus(1)
.toNumber()
: null, : null,
[accountNetValue, perpsAsset, previousAmount, price], [accountNetValue, perpsAsset, previousAmount, price],
) )
@ -46,7 +50,7 @@ export default function usePerpsModule(amount: BigNumber | null) {
const leverage = useMemo( const leverage = useMemo(
() => () =>
price price
.times(demagnify(previousAmount.plus(amount ?? BN_ZERO), perpsAsset)) .times(demagnify(previousAmount.plus(amount ?? BN_ZERO).abs(), perpsAsset))
.div(accountNetValue) .div(accountNetValue)
.plus(1) .plus(1)
.toNumber(), .toNumber(),

View File

@ -21,14 +21,14 @@ const Pion1: ChainConfig = {
id: ChainInfoID.Pion1, id: ChainInfoID.Pion1,
name: 'Neutron Testnet', name: 'Neutron Testnet',
contracts: { contracts: {
redBank: 'neutron1gpv59ff87mfvx8s3fn5ku3l8dn94fkj4q37sruhwfl0zzgjsejqs3xejyj', redBank: 'neutron1h7lvw8nm64x3zxlue6ec3vrk4e504d7c2wqq6y9uq2nu2shygh8qxm22up',
incentives: 'neutron1au78lscqqh77ghvl6eq2d58vy439q0gprhz0sc5q4r9svh63hquqtwlrsw', incentives: 'neutron1e28g4d93rthgjrtrxsze2f5lcljsxst24szhx0gjsvcmwzqsdruswau7hv',
oracle: 'neutron1z44naqtpn20z5yws7updsgcplm7tcfkcn67uejvc0l7n8hy6vupq0894qs', oracle: 'neutron1lwwmygj9cfm5jy623vvk37athq5fnjnm00wfjap2q49lfk8wylkqtujcym',
swapper: 'neutron1td4dn53k7ythdj8ah3xv5p66swq3sy2a9jzq4yrue8aa4dvwacrs7dachf', swapper: 'neutron1yk90r8efz897ev7vve9anfl4w342czn8f35qlyd3s2hsg4tctdms7vwexp',
params: 'neutron16l9j74q6ht9ycd37qxt6tz83l3r3cwec4qu9r5mkd66kcve23ywspjqhjp', params: 'neutron16kqg3hr2qc36gz2wqvdzsctatkmzd3ss5gc07tnj6u3n5ajw89asrx8hfp',
creditManager: 'neutron1swud86k6acvpjfn68cv6tz3h7z72nz395d7y5e3yxknrc8yl9faqxn5jjw', creditManager: 'neutron1kj50g96c86nu7jmy5y7uy5cyjanntgru0eekmwz2qcmyyvx6383s8dgvm6',
accountNft: 'neutron1apus79ka5v30wmwdxzzapprrzxxw6mz0hc0uk3g030t0m5f0asuq8x3ldf', accountNft: 'neutron17wvpxdc3k37054ume0ga4r0r6ra2rpfe622m0ecgd9s7xd5s0qusspc4ct',
perps: 'neutron1ssnc38h40fu0d2et8f38z83ealgugh06r4anqa6dn6hlz6syqaqsmj6zcy', perps: 'neutron14v9g7regs90qvful7djcajsvrfep5pg9qau7qm6wya6c2lzcpnms692dlt',
pyth: 'neutron15ldst8t80982akgr8w8ekcytejzkmfpgdkeq4xgtge48qs7435jqp87u3t', pyth: 'neutron15ldst8t80982akgr8w8ekcytejzkmfpgdkeq4xgtge48qs7435jqp87u3t',
}, },
endpoints: { endpoints: {

View File

@ -1,21 +0,0 @@
import BigNumber from 'bignumber.js'
import useSWR from 'swr'
import useChainConfig from 'hooks/useChainConfig'
import useClients from 'hooks/useClients'
import useDebounce from 'hooks/useDebounce'
import { BNCoin } from 'types/classes/BNCoin'
import { BN } from 'utils/helpers'
export default function useTradingFee(denom: string, amount: BigNumber) {
const chainConfig = useChainConfig()
const debouncedAmount = useDebounce<string>(amount.toString(), 500)
const clients = useClients()
const enabled = !amount.isZero() && clients
return useSWR(enabled && `${chainConfig.id}/perps/${denom}/tradingFee/${debouncedAmount}`, () =>
clients!.perps
.openingFee({ denom, size: amount as any })
.then((resp) => ({ rate: BN(resp.rate), fee: BNCoin.fromCoin(resp.fee) })),
)
}

View File

@ -0,0 +1,77 @@
import BigNumber from 'bignumber.js'
import useSWR from 'swr'
import { BN_ZERO } from 'constants/math'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useChainConfig from 'hooks/useChainConfig'
import useClients from 'hooks/useClients'
import useDebounce from 'hooks/useDebounce'
import { BNCoin } from 'types/classes/BNCoin'
import { BN } from 'utils/helpers'
export default function useTradingFeeAndPrice(
denom: string,
newAmount: BigNumber,
previousAmount: BigNumber,
) {
const chainConfig = useChainConfig()
const accountId = useCurrentAccount()?.id
const debouncedAmount = useDebounce<BigNumber>(newAmount, 500)
const clients = useClients()
const enabled = !debouncedAmount.isEqualTo(previousAmount) && clients && !!accountId
return useSWR(
enabled && `${chainConfig.id}/perps/${denom}/positionFeeAndPrice/${debouncedAmount}`,
async () => {
const isChangingTradeDirection =
newAmount.isNegative() !== previousAmount.isNegative() && !previousAmount.isZero()
if (!isChangingTradeDirection) {
const positionFees = await clients!.perps.positionFees({
denom,
newSize: newAmount.toString() as any,
accountId: accountId!,
})
return {
price: positionFees.opening_exec_price
? BN(positionFees.opening_exec_price)
: BN(positionFees.closing_exec_price ?? BN_ZERO),
fee: BNCoin.fromDenomAndBigNumber(
positionFees.base_denom,
BN(positionFees.opening_fee).plus(positionFees.closing_fee),
),
rate: BN(0.005),
}
}
// WHen direction is changed, we need to query both the 'closing' fees
// and also query how the new position would be opened. SC limits flipping trade direction.
const closingPositionFees$ = clients!.perps.positionFees({
denom,
newSize: '0' as any,
accountId: accountId!,
})
const openingPositionFees$ = clients!.perps.positionFees({
denom,
newSize: newAmount.toString() as any,
accountId: '91283123987467', // TODO: Remove this hard-coded value. SC currently does not allow flipping, so providing arbitrary accountId prevents this
})
return await Promise.all([closingPositionFees$, openingPositionFees$]).then(
([closingPositionFees, openingPositionFees]) => ({
price: BN(openingPositionFees.opening_exec_price ?? 0),
fee: BNCoin.fromDenomAndBigNumber(
closingPositionFees.base_denom,
BN(closingPositionFees.opening_fee)
.plus(closingPositionFees.closing_fee)
.plus(openingPositionFees.opening_fee)
.plus(openingPositionFees.closing_fee),
),
rate: BN(0.005),
}),
)
},
)
}

View File

@ -5,41 +5,32 @@
* and run the @cosmwasm/ts-codegen generate command to regenerate this file. * and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/ */
import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult } from '@cosmjs/cosmwasm-stargate' import { StdFee } from "@cosmjs/amino";
import { StdFee } from '@cosmjs/amino' import { CosmWasmClient, ExecuteResult, SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { import {
Decimal, Accounting,
Uint128,
OracleBaseForString,
ParamsBaseForString,
InstantiateMsg,
ExecuteMsg,
OwnerUpdate,
SignedDecimal,
QueryMsg,
ConfigForString,
DenomStateResponse,
Funding,
ArrayOfDenomStateResponse, ArrayOfDenomStateResponse,
DepositResponse,
ArrayOfDepositResponse, ArrayOfDepositResponse,
TradingFee,
Coin,
OwnerResponse,
PerpDenomState,
DenomPnlValues,
PnL,
PositionResponse,
PerpPosition,
PositionPnl,
PnlCoins,
PnlValues,
ArrayOfPositionResponse, ArrayOfPositionResponse,
PositionsByAccountResponse,
ArrayOfUnlockState, ArrayOfUnlockState,
UnlockState, Coin,
VaultState, ConfigForString,
} from './MarsPerps.types' Decimal,
DenomStateResponse,
DepositResponse,
OwnerResponse,
OwnerUpdate,
PerpDenomState,
PnlAmounts,
PositionFeesResponse,
PositionResponse,
PositionsByAccountResponse,
SignedDecimal,
TradingFee,
Uint128,
VaultState
} from "./MarsPerps.types";
export interface MarsPerpsReadOnlyInterface { export interface MarsPerpsReadOnlyInterface {
contractAddress: string contractAddress: string
owner: () => Promise<OwnerResponse> owner: () => Promise<OwnerResponse>
@ -63,13 +54,7 @@ export interface MarsPerpsReadOnlyInterface {
startAfter?: string startAfter?: string
}) => Promise<ArrayOfDepositResponse> }) => Promise<ArrayOfDepositResponse>
unlocks: ({ depositor }: { depositor: string }) => Promise<ArrayOfUnlockState> unlocks: ({ depositor }: { depositor: string }) => Promise<ArrayOfUnlockState>
position: ({ denomAccounting: ({ denom }: { denom: string }) => Promise<Accounting>
accountId,
denom,
}: {
accountId: string
denom: string
}) => Promise<PositionResponse>
positions: ({ positions: ({
limit, limit,
startAfter, startAfter,
@ -80,6 +65,32 @@ export interface MarsPerpsReadOnlyInterface {
positionsByAccount: ({ accountId }: { accountId: string }) => Promise<PositionsByAccountResponse> positionsByAccount: ({ accountId }: { accountId: string }) => Promise<PositionsByAccountResponse>
totalPnl: () => Promise<SignedDecimal> totalPnl: () => Promise<SignedDecimal>
openingFee: ({ denom, size }: { denom: string; size: SignedDecimal }) => Promise<TradingFee> openingFee: ({ denom, size }: { denom: string; size: SignedDecimal }) => Promise<TradingFee>
denomRealizedPnlForAccount: ({
accountId,
denom,
}: {
accountId: string
denom: string
}) => Promise<PnlAmounts>
position: ({
accountId,
denom,
newSize,
}: {
accountId: string
denom: string
newSize?: SignedDecimal
}) => Promise<PositionResponse>
positionFees: ({
accountId,
denom,
newSize,
}: {
accountId: string
denom: string
newSize: SignedDecimal
}) => Promise<PositionFeesResponse>
totalAccounting: () => Promise<Accounting>
} }
export class MarsPerpsQueryClient implements MarsPerpsReadOnlyInterface { export class MarsPerpsQueryClient implements MarsPerpsReadOnlyInterface {
client: CosmWasmClient client: CosmWasmClient
@ -102,6 +113,10 @@ export class MarsPerpsQueryClient implements MarsPerpsReadOnlyInterface {
this.positionsByAccount = this.positionsByAccount.bind(this) this.positionsByAccount = this.positionsByAccount.bind(this)
this.totalPnl = this.totalPnl.bind(this) this.totalPnl = this.totalPnl.bind(this)
this.openingFee = this.openingFee.bind(this) this.openingFee = this.openingFee.bind(this)
this.denomAccounting = this.denomAccounting.bind(this)
this.totalAccounting = this.totalAccounting.bind(this)
this.denomRealizedPnlForAccount = this.denomRealizedPnlForAccount.bind(this)
this.positionFees = this.positionFees.bind(this)
} }
owner = async (): Promise<OwnerResponse> => { owner = async (): Promise<OwnerResponse> => {
@ -175,16 +190,10 @@ export class MarsPerpsQueryClient implements MarsPerpsReadOnlyInterface {
}, },
}) })
} }
position = async ({
accountId, denomAccounting = async ({ denom }: { denom: string }): Promise<Accounting> => {
denom,
}: {
accountId: string
denom: string
}): Promise<PositionResponse> => {
return this.client.queryContractSmart(this.contractAddress, { return this.client.queryContractSmart(this.contractAddress, {
position: { denom_accounting: {
account_id: accountId,
denom, denom,
}, },
}) })
@ -233,6 +242,63 @@ export class MarsPerpsQueryClient implements MarsPerpsReadOnlyInterface {
}, },
}) })
} }
denomRealizedPnlForAccount = async ({
accountId,
denom,
}: {
accountId: string
denom: string
}): Promise<PnlAmounts> => {
return this.client.queryContractSmart(this.contractAddress, {
denom_realized_pnl_for_account: {
account_id: accountId,
denom,
},
})
}
position = async ({
accountId,
denom,
newSize,
}: {
accountId: string
denom: string
newSize?: SignedDecimal
}): Promise<PositionResponse> => {
return this.client.queryContractSmart(this.contractAddress, {
position: {
account_id: accountId,
denom,
new_size: newSize,
},
})
}
positionFees = async ({
accountId,
denom,
newSize,
}: {
accountId: string
denom: string
newSize: SignedDecimal
}): Promise<PositionFeesResponse> => {
return this.client.queryContractSmart(this.contractAddress, {
position_fees: {
account_id: accountId,
denom,
new_size: newSize,
},
})
}
totalAccounting = async (): Promise<Accounting> => {
return this.client.queryContractSmart(this.contractAddress, {
total_accounting: {},
})
}
} }
export interface MarsPerpsInterface extends MarsPerpsReadOnlyInterface { export interface MarsPerpsInterface extends MarsPerpsReadOnlyInterface {
contractAddress: string contractAddress: string
@ -323,6 +389,20 @@ export interface MarsPerpsInterface extends MarsPerpsReadOnlyInterface {
memo?: string, memo?: string,
_funds?: Coin[], _funds?: Coin[],
) => Promise<ExecuteResult> ) => Promise<ExecuteResult>
modifyPosition: (
{
accountId,
denom,
newSize,
}: {
accountId: string
denom: string
newSize: SignedDecimal
},
fee?: number | StdFee | 'auto',
memo?: string,
_funds?: Coin[],
) => Promise<ExecuteResult>
} }
export class MarsPerpsClient extends MarsPerpsQueryClient implements MarsPerpsInterface { export class MarsPerpsClient extends MarsPerpsQueryClient implements MarsPerpsInterface {
client: SigningCosmWasmClient client: SigningCosmWasmClient
@ -343,6 +423,7 @@ export class MarsPerpsClient extends MarsPerpsQueryClient implements MarsPerpsIn
this.withdraw = this.withdraw.bind(this) this.withdraw = this.withdraw.bind(this)
this.openPosition = this.openPosition.bind(this) this.openPosition = this.openPosition.bind(this)
this.closePosition = this.closePosition.bind(this) this.closePosition = this.closePosition.bind(this)
this.modifyPosition = this.modifyPosition.bind(this)
} }
updateOwner = async ( updateOwner = async (
@ -547,4 +628,33 @@ export class MarsPerpsClient extends MarsPerpsQueryClient implements MarsPerpsIn
_funds, _funds,
) )
} }
modifyPosition = async (
{
accountId,
denom,
newSize,
}: {
accountId: string
denom: string
newSize: SignedDecimal
},
fee: number | StdFee | 'auto' = 'auto',
memo?: string,
_funds?: Coin[],
): Promise<ExecuteResult> => {
return await this.client.execute(
this.sender,
this.contractAddress,
{
modify_position: {
account_id: accountId,
denom,
new_size: newSize,
},
},
fee,
memo,
_funds,
)
}
} }

View File

@ -19,6 +19,10 @@ import {
SignedDecimal, SignedDecimal,
QueryMsg, QueryMsg,
ConfigForString, ConfigForString,
Accounting,
Balance,
CashFlow,
PnlAmounts,
DenomStateResponse, DenomStateResponse,
Funding, Funding,
ArrayOfDenomStateResponse, ArrayOfDenomStateResponse,
@ -28,13 +32,13 @@ import {
Coin, Coin,
OwnerResponse, OwnerResponse,
PerpDenomState, PerpDenomState,
DenomPnlValues, PnlValues,
PnL, PnL,
PositionResponse, PositionResponse,
PerpPosition, PerpPosition,
PositionPnl, PositionPnl,
PnlCoins, PnlCoins,
PnlValues, PositionFeesResponse,
ArrayOfPositionResponse, ArrayOfPositionResponse,
PositionsByAccountResponse, PositionsByAccountResponse,
ArrayOfUnlockState, ArrayOfUnlockState,
@ -82,6 +86,27 @@ export const marsPerpsQueryKeys = {
[{ ...marsPerpsQueryKeys.address(contractAddress)[0], method: 'total_pnl', args }] as const, [{ ...marsPerpsQueryKeys.address(contractAddress)[0], method: 'total_pnl', args }] as const,
openingFee: (contractAddress: string | undefined, args?: Record<string, unknown>) => openingFee: (contractAddress: string | undefined, args?: Record<string, unknown>) =>
[{ ...marsPerpsQueryKeys.address(contractAddress)[0], method: 'opening_fee', args }] as const, [{ ...marsPerpsQueryKeys.address(contractAddress)[0], method: 'opening_fee', args }] as const,
denomAccounting: (contractAddress: string | undefined, args?: Record<string, unknown>) =>
[
{ ...marsPerpsQueryKeys.address(contractAddress)[0], method: 'denom_accounting', args },
] as const,
totalAccounting: (contractAddress: string | undefined, args?: Record<string, unknown>) =>
[
{ ...marsPerpsQueryKeys.address(contractAddress)[0], method: 'total_accounting', args },
] as const,
denomRealizedPnlForAccount: (
contractAddress: string | undefined,
args?: Record<string, unknown>,
) =>
[
{
...marsPerpsQueryKeys.address(contractAddress)[0],
method: 'denom_realized_pnl_for_account',
args,
},
] as const,
positionFees: (contractAddress: string | undefined, args?: Record<string, unknown>) =>
[{ ...marsPerpsQueryKeys.address(contractAddress)[0], method: 'position_fees', args }] as const,
} }
export interface MarsPerpsReactQuery<TResponse, TData = TResponse> { export interface MarsPerpsReactQuery<TResponse, TData = TResponse> {
client: MarsPerpsQueryClient | undefined client: MarsPerpsQueryClient | undefined
@ -92,6 +117,90 @@ export interface MarsPerpsReactQuery<TResponse, TData = TResponse> {
initialData?: undefined initialData?: undefined
} }
} }
export interface MarsPerpsPositionFeesQuery<TData>
extends MarsPerpsReactQuery<PositionFeesResponse, TData> {
args: {
accountId: string
denom: string
newSize: SignedDecimal
}
}
export function useMarsPerpsPositionFeesQuery<TData = PositionFeesResponse>({
client,
args,
options,
}: MarsPerpsPositionFeesQuery<TData>) {
return useQuery<PositionFeesResponse, Error, TData>(
marsPerpsQueryKeys.positionFees(client?.contractAddress, args),
() =>
client
? client.positionFees({
accountId: args.accountId,
denom: args.denom,
newSize: args.newSize,
})
: Promise.reject(new Error('Invalid client')),
{ ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) },
)
}
export interface MarsPerpsDenomRealizedPnlForAccountQuery<TData>
extends MarsPerpsReactQuery<PnlAmounts, TData> {
args: {
accountId: string
denom: string
}
}
export function useMarsPerpsDenomRealizedPnlForAccountQuery<TData = PnlAmounts>({
client,
args,
options,
}: MarsPerpsDenomRealizedPnlForAccountQuery<TData>) {
return useQuery<PnlAmounts, Error, TData>(
marsPerpsQueryKeys.denomRealizedPnlForAccount(client?.contractAddress, args),
() =>
client
? client.denomRealizedPnlForAccount({
accountId: args.accountId,
denom: args.denom,
})
: Promise.reject(new Error('Invalid client')),
{ ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) },
)
}
export interface MarsPerpsTotalAccountingQuery<TData>
extends MarsPerpsReactQuery<Accounting, TData> {}
export function useMarsPerpsTotalAccountingQuery<TData = Accounting>({
client,
options,
}: MarsPerpsTotalAccountingQuery<TData>) {
return useQuery<Accounting, Error, TData>(
marsPerpsQueryKeys.totalAccounting(client?.contractAddress),
() => (client ? client.totalAccounting() : Promise.reject(new Error('Invalid client'))),
{ ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) },
)
}
export interface MarsPerpsDenomAccountingQuery<TData>
extends MarsPerpsReactQuery<Accounting, TData> {
args: {
denom: string
}
}
export function useMarsPerpsDenomAccountingQuery<TData = Accounting>({
client,
args,
options,
}: MarsPerpsDenomAccountingQuery<TData>) {
return useQuery<Accounting, Error, TData>(
marsPerpsQueryKeys.denomAccounting(client?.contractAddress, args),
() =>
client
? client.denomAccounting({
denom: args.denom,
})
: Promise.reject(new Error('Invalid client')),
{ ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) },
)
}
export interface MarsPerpsOpeningFeeQuery<TData> extends MarsPerpsReactQuery<TradingFee, TData> { export interface MarsPerpsOpeningFeeQuery<TData> extends MarsPerpsReactQuery<TradingFee, TData> {
args: { args: {
denom: string denom: string
@ -177,6 +286,7 @@ export interface MarsPerpsPositionQuery<TData>
args: { args: {
accountId: string accountId: string
denom: string denom: string
newSize?: SignedDecimal
} }
} }
export function useMarsPerpsPositionQuery<TData = PositionResponse>({ export function useMarsPerpsPositionQuery<TData = PositionResponse>({
@ -191,6 +301,7 @@ export function useMarsPerpsPositionQuery<TData = PositionResponse>({
? client.position({ ? client.position({
accountId: args.accountId, accountId: args.accountId,
denom: args.denom, denom: args.denom,
newSize: args.newSize,
}) })
: Promise.reject(new Error('Invalid client')), : Promise.reject(new Error('Invalid client')),
{ ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) }, { ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) },
@ -364,6 +475,31 @@ export function useMarsPerpsOwnerQuery<TData = OwnerResponse>({
{ ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) }, { ...options, enabled: !!client && (options?.enabled != undefined ? options.enabled : true) },
) )
} }
export interface MarsPerpsModifyPositionMutation {
client: MarsPerpsClient
msg: {
accountId: string
denom: string
newSize: SignedDecimal
}
args?: {
fee?: number | StdFee | 'auto'
memo?: string
funds?: Coin[]
}
}
export function useMarsPerpsModifyPositionMutation(
options?: Omit<
UseMutationOptions<ExecuteResult, Error, MarsPerpsModifyPositionMutation>,
'mutationFn'
>,
) {
return useMutation<ExecuteResult, Error, MarsPerpsModifyPositionMutation>(
({ client, msg, args: { fee, memo, funds } = {} }) =>
client.modifyPosition(msg, fee, memo, funds),
options,
)
}
export interface MarsPerpsClosePositionMutation { export interface MarsPerpsClosePositionMutation {
client: MarsPerpsClient client: MarsPerpsClient
msg: { msg: {

View File

@ -22,70 +22,70 @@ export interface InstantiateMsg {
} }
export type ExecuteMsg = export type ExecuteMsg =
| { | {
update_owner: OwnerUpdate update_owner: OwnerUpdate
} }
| { | {
init_denom: { init_denom: {
denom: string denom: string
max_funding_velocity: Decimal max_funding_velocity: Decimal
skew_scale: Decimal skew_scale: Decimal
} }
} }
| { | {
enable_denom: { enable_denom: {
denom: string denom: string
} }
} }
| { | {
disable_denom: { disable_denom: {
denom: string denom: string
} }
} }
| { | {
deposit: {} deposit: {}
} }
| { | {
unlock: { unlock: {
shares: Uint128 shares: Uint128
} }
} }
| { | {
withdraw: {} withdraw: {}
} }
| { | {
open_position: { open_position: {
account_id: string account_id: string
denom: string denom: string
size: SignedDecimal size: SignedDecimal
} }
} }
| { | {
close_position: { close_position: {
account_id: string account_id: string
denom: string denom: string
} }
} }
| { | {
modify_position: { modify_position: {
account_id: string account_id: string
denom: string denom: string
new_size: SignedDecimal new_size: SignedDecimal
} }
} }
export type OwnerUpdate = export type OwnerUpdate =
| { | {
propose_new_owner: { propose_new_owner: {
proposed: string proposed: string
} }
} }
| 'clear_proposed' | 'clear_proposed'
| 'accept_proposed' | 'accept_proposed'
| 'abolish_owner_role' | 'abolish_owner_role'
| { | {
set_emergency_owner: { set_emergency_owner: {
emergency_owner: string emergency_owner: string
} }
} }
| 'clear_emergency_owner' | 'clear_emergency_owner'
export interface SignedDecimal { export interface SignedDecimal {
abs: Decimal abs: Decimal
@ -94,86 +94,94 @@ export interface SignedDecimal {
} }
export type QueryMsg = export type QueryMsg =
| { | {
owner: {} owner: {}
} }
| { | {
config: {} config: {}
} }
| { | {
vault_state: {} vault_state: {}
} }
| { | {
denom_state: { denom_state: {
denom: string denom: string
} }
} }
| { | {
perp_denom_state: { perp_denom_state: {
denom: string denom: string
} }
} }
| { | {
denom_states: { denom_states: {
limit?: number | null limit?: number | null
start_after?: string | null start_after?: string | null
} }
} }
| { | {
deposit: { deposit: {
depositor: string depositor: string
} }
} }
| { | {
deposits: { deposits: {
limit?: number | null limit?: number | null
start_after?: string | null start_after?: string | null
} }
} }
| { | {
unlocks: { unlocks: {
depositor: string depositor: string
} }
} }
| { | {
position: { position: {
account_id: string account_id: string
denom: string denom: string
} new_size?: SignedDecimal | null
} }
}
| { | {
positions: { positions: {
limit?: number | null limit?: number | null
start_after?: [string, string] | null start_after?: [string, string] | null
} }
} }
| { | {
positions_by_account: { positions_by_account: {
account_id: string account_id: string
} }
} }
| { | {
total_pnl: {} total_pnl: {}
} }
| { | {
opening_fee: { opening_fee: {
denom: string denom: string
size: SignedDecimal size: SignedDecimal
} }
} }
| { | {
denom_accounting: { denom_accounting: {
denom: string denom: string
} }
} }
| { | {
total_accounting: {} total_accounting: {}
} }
| { | {
denom_realized_pnl_for_account: { denom_realized_pnl_for_account: {
account_id: string account_id: string
denom: string denom: string
} }
} }
| {
position_fees: {
account_id: string
denom: string
new_size: SignedDecimal
}
}
export interface ConfigForString { export interface ConfigForString {
base_denom: string base_denom: string
closing_fee_rate: Decimal closing_fee_rate: Decimal
@ -203,7 +211,7 @@ export interface CashFlow {
opening_fee: SignedDecimal opening_fee: SignedDecimal
price_pnl: SignedDecimal price_pnl: SignedDecimal
} }
export interface RealizedPnlAmounts { export interface PnlAmounts {
accrued_funding: SignedDecimal accrued_funding: SignedDecimal
closing_fee: SignedDecimal closing_fee: SignedDecimal
opening_fee: SignedDecimal opening_fee: SignedDecimal
@ -250,26 +258,26 @@ export interface PerpDenomState {
denom: string denom: string
enabled: boolean enabled: boolean
long_oi: Decimal long_oi: Decimal
pnl_values: DenomPnlValues pnl_values: PnlValues
rate: SignedDecimal rate: SignedDecimal
short_oi: Decimal short_oi: Decimal
total_entry_cost: SignedDecimal total_entry_cost: SignedDecimal
total_entry_funding: SignedDecimal total_entry_funding: SignedDecimal
} }
export interface DenomPnlValues { export interface PnlValues {
accrued_funding: SignedDecimal accrued_funding: SignedDecimal
closing_fees: SignedDecimal closing_fee: SignedDecimal
pnl: SignedDecimal pnl: SignedDecimal
price_pnl: SignedDecimal price_pnl: SignedDecimal
} }
export type PnL = export type PnL =
| 'break_even' | 'break_even'
| { | {
profit: Coin profit: Coin
} }
| { | {
loss: Coin loss: Coin
} }
export interface PositionResponse { export interface PositionResponse {
account_id: string account_id: string
position: PerpPosition position: PerpPosition
@ -282,11 +290,12 @@ export interface PerpPosition {
denom: string denom: string
entry_exec_price: Decimal entry_exec_price: Decimal
entry_price: Decimal entry_price: Decimal
realised_pnl: RealizedPnlAmounts realised_pnl: PnlAmounts
size: SignedDecimal size: SignedDecimal
unrealised_pnl: PositionPnl unrealised_pnl: PositionPnl
} }
export interface PositionPnl { export interface PositionPnl {
amounts: PnlAmounts
coins: PnlCoins coins: PnlCoins
values: PnlValues values: PnlValues
} }
@ -294,11 +303,12 @@ export interface PnlCoins {
closing_fee: Coin closing_fee: Coin
pnl: PnL pnl: PnL
} }
export interface PnlValues { export interface PositionFeesResponse {
accrued_funding: SignedDecimal base_denom: string
closing_fee: SignedDecimal closing_exec_price?: Decimal | null
pnl: SignedDecimal closing_fee: Uint128
price_pnl: SignedDecimal opening_exec_price?: Decimal | null
opening_fee: Uint128
} }
export type ArrayOfPositionResponse = PositionResponse[] export type ArrayOfPositionResponse = PositionResponse[]
export interface PositionsByAccountResponse { export interface PositionsByAccountResponse {

867
yarn.lock

File diff suppressed because it is too large Load Diff