Skip to content

Commit

Permalink
Merge pull request #1012 from InjectiveLabs/dev
Browse files Browse the repository at this point in the history
#PRMaster
  • Loading branch information
bangjelkoski authored Dec 20, 2023
2 parents f8ec90e + 7509392 commit 1a120a7
Show file tree
Hide file tree
Showing 578 changed files with 27,256 additions and 12,491 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/mainnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
- name: Using Node ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: 16.x
node-version: 18.x

- name: Remove prev build
run: yarn clean-up
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:
- name: Using Node ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: 16.x
node-version: 18.x

- name: Remove prev build
run: yarn clean-up
Expand Down
13 changes: 6 additions & 7 deletions .github/workflows/testnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ jobs:
VITE_GEO_IP_RESTRICTIONS_ENABLED: false

## Endpoints
VITE_INDEXER_API_ENDPOINT: 'https://testnet.sentry.exchange.grpc-web.injective.network'
VITE_CHRONOS_API_ENDPOINT: 'https://testnet.sentry.exchange.grpc-web.injective.network'
VITE_EXPLORER_API_ENDPOINT: 'https://testnet.sentry.explorer.grpc-web.injective.network'
VITE_SENTRY_GRPC_ENDPOINT: 'https://testnet.sentry.chain.grpc-web.injective.network'
VITE_SENTRY_REST_ENDPOINT: 'https://testnet.sentry.tm.injective.network'
VITE_SENTRY_HTTP_ENDPOINT: 'https://testnet.sentry.tm.injective.network'
VITE_INDEXER_API_ENDPOINT: ''
VITE_CHRONOS_API_ENDPOINT: ''
VITE_EXPLORER_API_ENDPOINT: ''
VITE_SENTRY_GRPC_ENDPOINT: ''
VITE_SENTRY_REST_ENDPOINT: ''

## Secret
VITE_FEE_PAYER_PUB_KEY: ${{ secrets.VITE_TESTNET_FEE_PAYER_PUB_KEY }}
Expand All @@ -60,7 +59,7 @@ jobs:
- name: Using Node ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: 16.x
node-version: 18.x

- name: Remove prev build
run: yarn clean-up
Expand Down
12 changes: 11 additions & 1 deletion app/Services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
IndexerGrpcOracleApi,
IndexerGrpcAccountApi,
IndexerGrpcTradingApi,
IndexerGrpcCampaignApi,
IndexerGrpcExplorerApi,
IndexerRestExplorerApi,
ChainGrpcDistributionApi,
Expand Down Expand Up @@ -58,17 +59,26 @@ export const exchangeApi = new ChainGrpcExchangeApi(ENDPOINTS.grpc)
export const insuranceApi = new ChainGrpcInsuranceFundApi(ENDPOINTS.grpc)
export const distributionApi = new ChainGrpcDistributionApi(ENDPOINTS.grpc)
export const authZApi = new ChainGrpcAuthZApi(ENDPOINTS.grpc)
export const chainGrpcWasmApi = new ChainGrpcWasmApi(ENDPOINTS.grpc)

export const indexerOracleApi = new IndexerGrpcOracleApi(ENDPOINTS.indexer)
export const indexerAccountApi = new IndexerGrpcAccountApi(ENDPOINTS.indexer)

export const indexerGrpcCampaignApi = new IndexerGrpcCampaignApi(
ENDPOINTS.campaign
)
export const indexerAccountPortfolioApi = new IndexerGrpcAccountPortfolioApi(
ENDPOINTS.indexer
)

/** TODO remove conditional when resync is done */
export const indexerGrpcTradingApi = new IndexerGrpcTradingApi(
ENDPOINTS.indexer
)

export const indexerExplorerApi = new IndexerGrpcExplorerApi(ENDPOINTS.explorer)
export const indexerExplorerApi = new IndexerGrpcExplorerApi(
ENDPOINTS.explorer || ENDPOINTS.indexer
)
export const indexerRestExplorerApi = new IndexerRestExplorerApi(
`${ENDPOINTS.explorer}/api/explorer/v1`
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export abstract class BaseDataIntegrityStrategy<T> {
public args: T

constructor(args: T) {
this.args = args
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Coin } from '@injectivelabs/ts-types'
import { ConcreteDataIntegrityStrategy } from '@/app/client/streams/data-integrity/types'
import { BaseDataIntegrityStrategy } from '@/app/client/streams/data-integrity/strategies'
import { indexerAccountPortfolioApi } from '@/app/Services'

export class BankBalanceIntegrityStrategy
extends BaseDataIntegrityStrategy<void>
implements ConcreteDataIntegrityStrategy<void, Coin[]>
{
static make(): BankBalanceIntegrityStrategy {
return new BankBalanceIntegrityStrategy()
}

async validate(): Promise<void> {
const walletStore = useWalletStore()
const accountStore = useAccountStore()

if (!walletStore.isUserWalletConnected) {
return
}

const latestBankBalances = await this.fetchData()

if (latestBankBalances.length === 0) {
return
}

const existingBankBalances = [...accountStore.bankBalances]
const isDataValid = this.verifyData(
existingBankBalances,
latestBankBalances
)

if (!isDataValid) {
accountStore.cancelBankBalanceStream()
accountStore.$patch({ bankBalances: await this.fetchData() })
accountStore.streamBankBalance()
}
}

verifyData(
existingBankBalances: Coin[],
latestBankBalances: Coin[]
): boolean {
if (existingBankBalances.length !== latestBankBalances.length) {
return false
}

return latestBankBalances.every((latestBalance) => {
const existingBalance = existingBankBalances.find(
(b) => b.denom === latestBalance.denom
)
return existingBalance && existingBalance.amount === latestBalance.amount
})
}

async fetchData(): Promise<Coin[]> {
const walletStore = useWalletStore()

const { bankBalancesList } =
await indexerAccountPortfolioApi.fetchAccountPortfolio(
walletStore.authZOrInjectiveAddress
)

return bankBalancesList || []
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { ConcreteDataIntegrityStrategy } from '@/app/client/streams/data-integrity/types'
import { BaseDataIntegrityStrategy } from '@/app/client/streams/data-integrity/strategies'
import { SubaccountBalance } from '@/types'
import { indexerAccountPortfolioApi } from '@/app/Services'
import {
getDefaultAccountBalances,
getNonDefaultSubaccountBalances
} from '@/app/client/utils/account'

export class SubaccountBalanceIntegrityStrategy
extends BaseDataIntegrityStrategy<void>
implements
ConcreteDataIntegrityStrategy<void, Record<string, SubaccountBalance[]>>
{
static make(): SubaccountBalanceIntegrityStrategy {
return new SubaccountBalanceIntegrityStrategy()
}

async validate(): Promise<void> {
const walletStore = useWalletStore()
const accountStore = useAccountStore()

if (!walletStore.isUserWalletConnected) {
return
}

if (walletStore.authZOrDefaultSubaccountId === accountStore.subaccountId) {
return
}

const latestSubaccountBalancesMap = await this.fetchData()

const existingSubaccountBalancesMap = {
...accountStore.subaccountBalancesMap
}

const isDataValid = this.verifyData(
existingSubaccountBalancesMap,
latestSubaccountBalancesMap
)

if (!isDataValid) {
accountStore.cancelSubaccountBalanceStream()
accountStore.$patch({
subaccountBalancesMap: await this.fetchData()
})
accountStore.streamSubaccountBalance()
}
}

verifyData(
existingMap: Record<string, SubaccountBalance[]>,
latestMap: Record<string, SubaccountBalance[]>
): boolean {
const existingKeys = Object.keys(existingMap)
const latestKeys = Object.keys(latestMap)
if (
existingKeys.length !== latestKeys.length ||
!existingKeys.every((key) => latestKeys.includes(key))
) {
return false
}

return latestKeys.every((subaccountId) => {
const existingBalances = existingMap[subaccountId] || []
const latestBalances = latestMap[subaccountId] || []

if (existingBalances.length !== latestBalances.length) {
return false
}

return latestBalances.every((latestBalance) => {
const existingBalance = existingBalances.find(
(b) => b.denom === latestBalance.denom
)

return (
existingBalance &&
existingBalance.availableBalance === latestBalance.availableBalance &&
existingBalance.totalBalance === latestBalance.totalBalance
)
})
})
}

async fetchData(): Promise<Record<string, SubaccountBalance[]>> {
const walletStore = useWalletStore()

const accountPortfolio =
await indexerAccountPortfolioApi.fetchAccountPortfolio(
walletStore.authZOrInjectiveAddress
)

const defaultAccountBalances = getDefaultAccountBalances(
accountPortfolio.subaccountsList,
walletStore.authZOrDefaultSubaccountId
)

const nonDefaultSubaccounts = getNonDefaultSubaccountBalances(
accountPortfolio.subaccountsList,
walletStore.authZOrDefaultSubaccountId
)

return {
[walletStore.authZOrDefaultSubaccountId]: defaultAccountBalances,
...nonDefaultSubaccounts
}
}
}
2 changes: 2 additions & 0 deletions app/client/streams/data-integrity/strategies/account/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './BankBalance'
export * from './SubaccountBalance'
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import {
MarketType,
UiPerpetualMarketWithToken,
UiBinaryOptionsMarketWithToken
} from '@injectivelabs/sdk-ui-ts'
import {
MarketIdsArgs,
ConcreteDataIntegrityStrategy
} from '@/app/client/streams/data-integrity/types'
import { BaseDataIntegrityStrategy } from '@/app/client/streams/data-integrity/strategies'
import { MarketMarkPriceMap } from '@/types'
import { indexerOracleApi } from '@/app/Services'

export class DerivativeOraclePriceIntegrityStrategy
extends BaseDataIntegrityStrategy<MarketIdsArgs>
implements ConcreteDataIntegrityStrategy<MarketIdsArgs, MarketMarkPriceMap>
{
static make(
marketIds: MarketIdsArgs
): DerivativeOraclePriceIntegrityStrategy {
return new DerivativeOraclePriceIntegrityStrategy(marketIds)
}

async validate(): Promise<void> {
const { args: marketIds } = this

if (!marketIds) {
return
}

const latestMarketPrices = await this.fetchData()

if (!latestMarketPrices) {
return
}

if (Object.keys(latestMarketPrices).length === 0) {
return
}

const derivativeStore = useDerivativeStore()

const existingMarketPrices = { ...derivativeStore.marketMarkPriceMap }
const isDataValid = this.verifyData(
existingMarketPrices,
latestMarketPrices
)

if (!isDataValid) {
derivativeStore.cancelMarketsMarkPrices()
derivativeStore.$patch({ marketMarkPriceMap: await this.fetchData() })
derivativeStore.streamMarketsMarkPrices()
}
}

verifyData(
existingMarketPrices: MarketMarkPriceMap,
latestMarketPrices: MarketMarkPriceMap
): boolean {
return Object.entries(latestMarketPrices).every(
([marketId, latestPrice]) => {
const existingPrice = existingMarketPrices[marketId]

return existingPrice && existingPrice.price === latestPrice.price
}
)
}

async fetchData(): Promise<MarketMarkPriceMap> {
const { args: marketIds } = this

if (!marketIds) {
return {}
}

const derivativeStore = useDerivativeStore()
const markets = derivativeStore.markets.filter((market) =>
marketIds.includes(market.marketId)
)

const pricePromises = markets.map((market) =>
(market.subType !== MarketType.BinaryOptions
? indexerOracleApi.fetchOraclePrice({
oracleType: market.oracleType,
baseSymbol: (market as UiPerpetualMarketWithToken).oracleBase,
quoteSymbol: (market as UiPerpetualMarketWithToken).oracleQuote
})
: indexerOracleApi.fetchOraclePriceNoThrow({
baseSymbol: (market as UiBinaryOptionsMarketWithToken).oracleSymbol,
quoteSymbol: (market as UiBinaryOptionsMarketWithToken)
.oracleProvider,
oracleType: market.oracleType
})
).then((oraclePrice) => ({
marketId: market.marketId,
price: oraclePrice.price
}))
)

const marketPricesResults = await Promise.all(pricePromises)

return marketPricesResults.reduce(
(accumulatedMarketPrices, marketPrice) => {
if (marketPrice) {
accumulatedMarketPrices[marketPrice.marketId] = marketPrice
}

return accumulatedMarketPrices
},
{} as MarketMarkPriceMap
)
}
}
Loading

0 comments on commit 1a120a7

Please sign in to comment.