diff --git a/CHANGELOG.md b/CHANGELOG.md index d68a72b89..ea9b58501 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#648](https://github.com/alleslabs/celatone-frontend/pull/648) Support OPInit transaction in initia - [#654](https://github.com/alleslabs/celatone-frontend/pull/654) Add recent modules page - [#653](https://github.com/alleslabs/celatone-frontend/pull/653) Migrate from stone-12 to stone-12-1 - [#637](https://github.com/alleslabs/celatone-frontend/pull/637) Add amp module interaction and code snippet property diff --git a/src/lib/app-provider/env.ts b/src/lib/app-provider/env.ts index 2d83f663f..0c584e4cc 100644 --- a/src/lib/app-provider/env.ts +++ b/src/lib/app-provider/env.ts @@ -89,8 +89,7 @@ export enum CELATONE_QUERY_KEYS { TXS_BY_ADDRESS_PAGINATION = "CELATONE_QUERY_TXS_BY_ADDRESS_PAGINATION", TXS_BY_ADDRESS_COUNT = "CELATONE_QUERY_TXS_BY_ADDRESS_COUNT", TXS = "CELATONE_QUERY_TXS", - TXS_BY_BLOCK_HEIGHT_PAGINATION = "CELATONE_QUERY_TXS_BY_BLOCK_HEIGHT", - TXS_BY_BLOCK_HEIGHT_COUNT = "CELATONE_QUERY_TXS_BY_BLOCK_HEIGHT_COUNT", + TXS_BY_BLOCK_HEIGHT = "CELATONE_QUERY_TXS_BY_BLOCK_HEIGHT", // ICNS ICNS_NAMES_BY_ADDRESS = "CELATONE_QUERY_ICNS_NAMES_BY_ADDRESS", ADDRESS_BY_ICNS_NAME = "CELATONE_QUERY_ADDRESS_BY_ICNS_NAME", diff --git a/src/lib/app-provider/hooks/index.ts b/src/lib/app-provider/hooks/index.ts index 4e3b8f29b..a5cb86e64 100644 --- a/src/lib/app-provider/hooks/index.ts +++ b/src/lib/app-provider/hooks/index.ts @@ -14,3 +14,4 @@ export * from "./useConfig"; export * from "./useCurrentChain"; export * from "./useConvertHexAddress"; export * from "./usePlatform"; +export * from "./useInitia"; diff --git a/src/lib/app-provider/hooks/useInitia.ts b/src/lib/app-provider/hooks/useInitia.ts new file mode 100644 index 000000000..410e301d8 --- /dev/null +++ b/src/lib/app-provider/hooks/useInitia.ts @@ -0,0 +1,8 @@ +import { useCelatoneApp } from "../contexts"; + +export const useInitia = () => { + const { + chainConfig: { chain }, + } = useCelatoneApp(); + return chain === "initia"; +}; diff --git a/src/lib/components/TxFilterSelection.tsx b/src/lib/components/TxFilterSelection.tsx index f9a6d010e..820e20667 100644 --- a/src/lib/components/TxFilterSelection.tsx +++ b/src/lib/components/TxFilterSelection.tsx @@ -16,12 +16,13 @@ import { matchSorter } from "match-sorter"; import type { CSSProperties } from "react"; import { useMemo, useState, useRef, forwardRef } from "react"; -import { useMoveConfig, useWasmConfig } from "lib/app-provider"; +import { useInitia, useMoveConfig, useWasmConfig } from "lib/app-provider"; import { CustomIcon } from "lib/components/icon"; import { DEFAULT_BASE_TX_FILTERS, DEFAULT_MOVE_TX_FILTERS, DEFAULT_WASM_TX_FILTERS, + DEFAULT_INITIA_TX_FILTERS, } from "lib/data"; import { displayActionValue, mergeRefs } from "lib/utils"; @@ -50,6 +51,7 @@ const listItemProps: CSSProperties = { const BASE_OPTIONS = Object.keys(DEFAULT_BASE_TX_FILTERS); const WASM_OPTIONS = Object.keys(DEFAULT_WASM_TX_FILTERS); const MOVE_OPTIONS = Object.keys(DEFAULT_MOVE_TX_FILTERS); +const INITIA_OPTIONS = Object.keys(DEFAULT_INITIA_TX_FILTERS); // TODO - Refactor this along with TagSelection export const TxFilterSelection = forwardRef< @@ -80,13 +82,16 @@ export const TxFilterSelection = forwardRef< const wasm = useWasmConfig({ shouldRedirect: false }); const move = useMoveConfig({ shouldRedirect: false }); + const isInitia = useInitia(); + const options = useMemo( () => [ ...BASE_OPTIONS, ...(wasm.enabled ? WASM_OPTIONS : []), ...(move.enabled ? MOVE_OPTIONS : []), + ...(isInitia ? INITIA_OPTIONS : []), ], - [wasm.enabled, move.enabled] + [wasm.enabled, move.enabled, isInitia] ); const partialResults = useMemo( diff --git a/src/lib/components/table/transactions/TransactionsTableMobileCard.tsx b/src/lib/components/table/transactions/TransactionsTableMobileCard.tsx index 16967e43e..9080f78bd 100644 --- a/src/lib/components/table/transactions/TransactionsTableMobileCard.tsx +++ b/src/lib/components/table/transactions/TransactionsTableMobileCard.tsx @@ -51,10 +51,15 @@ export const TransactionsTableMobileCard = ({ {transaction.isIbc && ( - + IBC )} + {transaction.isOpinit && ( + + OPInit + + )} } bottomContent={ diff --git a/src/lib/components/table/transactions/TransactionsTableRow.tsx b/src/lib/components/table/transactions/TransactionsTableRow.tsx index e4bbba2e9..100ca9cc7 100644 --- a/src/lib/components/table/transactions/TransactionsTableRow.tsx +++ b/src/lib/components/table/transactions/TransactionsTableRow.tsx @@ -36,7 +36,6 @@ export const TransactionsTableRow = ({ }: TransactionsTableRowProps) => { const { isOpen, onToggle } = useDisclosure(); const isAccordion = transaction.messages.length > 1; - return ( )} + {transaction.isOpinit && ( + + OPInit + + )} diff --git a/src/lib/data/constant.ts b/src/lib/data/constant.ts index cb4a364d2..bffee8350 100644 --- a/src/lib/data/constant.ts +++ b/src/lib/data/constant.ts @@ -1,5 +1,6 @@ import type { BaseTxFilters, + InitiaTxFilters, LVPair, MoveTxFilters, TxFilters, @@ -59,10 +60,15 @@ export const DEFAULT_MOVE_TX_FILTERS: MoveTxFilters = { isMoveScript: false, }; +export const DEFAULT_INITIA_TX_FILTERS: InitiaTxFilters = { + isOpinit: false, +}; + export const DEFAULT_TX_FILTERS: TxFilters = { ...DEFAULT_BASE_TX_FILTERS, ...DEFAULT_WASM_TX_FILTERS, ...DEFAULT_MOVE_TX_FILTERS, + ...DEFAULT_INITIA_TX_FILTERS, }; export const UPPERBOUND_COUNT = 10000; diff --git a/src/lib/pages/account-details/components/tables/txs/index.tsx b/src/lib/pages/account-details/components/tables/txs/index.tsx index 59323c8b2..66085bae6 100644 --- a/src/lib/pages/account-details/components/tables/txs/index.tsx +++ b/src/lib/pages/account-details/components/tables/txs/index.tsx @@ -60,7 +60,7 @@ export const TxsTable = ({ data: rawTxCount, isLoading: isTxCountLoading, refetch: refetchTxsCount, - } = useAPITxsCountByAddress(address, isSigner, filters); + } = useAPITxsCountByAddress(address, undefined, isSigner, filters); const txsCount = rawTxCount ?? undefined; const isTxsCountTimeout = rawTxCount === null; @@ -97,6 +97,7 @@ export const TxsTable = ({ const { data: transactions, isLoading } = useTxsByAddress( address, + undefined, isSigner, filters, offset, diff --git a/src/lib/pages/block-details/components/BlockTxsTable.tsx b/src/lib/pages/block-details/components/BlockTxsTable.tsx index e30aa3f86..a72f5de90 100644 --- a/src/lib/pages/block-details/components/BlockTxsTable.tsx +++ b/src/lib/pages/block-details/components/BlockTxsTable.tsx @@ -1,13 +1,8 @@ -import type { ChangeEvent } from "react"; - import { Pagination } from "lib/components/pagination"; import { usePaginator } from "lib/components/pagination/usePaginator"; import { EmptyState } from "lib/components/state"; import { TransactionsTable } from "lib/components/table"; -import { - useTxsByBlockHeightPagination, - useTxsCountByBlockHeight, -} from "lib/services/txService"; +import { useTxsByBlockHeight } from "lib/services/txService"; const scrollComponentId = "block_tx_table_header"; @@ -16,41 +11,30 @@ interface BlockTxsTableProps { } export const BlockTxsTable = ({ height }: BlockTxsTableProps) => { - const { data: blockTxsCount = 0 } = useTxsCountByBlockHeight(height); const { pagesQuantity, + setTotalData, currentPage, setCurrentPage, pageSize, setPageSize, offset, } = usePaginator({ - total: blockTxsCount, initialState: { pageSize: 10, currentPage: 1, isDisabled: false, }, }); - - const { data: blockTxs, isLoading: isBlockTxsLoading } = - useTxsByBlockHeightPagination(height, pageSize, offset); - - const onPageChange = (nextPage: number) => { - setCurrentPage(nextPage); - }; - - const onPageSizeChange = (e: ChangeEvent) => { - const size = Number(e.target.value); - setPageSize(size); - setCurrentPage(1); - }; + const { data, isLoading } = useTxsByBlockHeight(height, pageSize, offset, { + onSuccess: ({ total }) => setTotalData(total), + }); return ( <> { showRelations={false} showTimestamp={false} /> - {blockTxsCount > 10 && ( + {data && data.total > 10 && ( { + const size = Number(e.target.value); + setPageSize(size); + setCurrentPage(1); + }} /> )} diff --git a/src/lib/pages/module-details/components/tables/ModuleTxsTable.tsx b/src/lib/pages/module-details/components/tables/ModuleTxsTable.tsx index 0a2409ccb..ab6ae644e 100644 --- a/src/lib/pages/module-details/components/tables/ModuleTxsTable.tsx +++ b/src/lib/pages/module-details/components/tables/ModuleTxsTable.tsx @@ -6,11 +6,12 @@ import { Pagination } from "lib/components/pagination"; import { usePaginator } from "lib/components/pagination/usePaginator"; import { EmptyState } from "lib/components/state"; import { TransactionsTable, ViewMore } from "lib/components/table"; -import { useModuleTxsByPagination } from "lib/services/txService"; -import type { Nullable, Option } from "lib/types"; +import { useTxsByModule } from "lib/services/txService"; +import type { HexAddr, Option } from "lib/types"; interface ModuleTxsTableProps { - moduleId: Option>; + address: HexAddr; + moduleName: string; txCount: Option; onViewMore?: () => void; scrollComponentId?: string; @@ -18,7 +19,8 @@ interface ModuleTxsTableProps { } export const ModuleTxsTable = ({ - moduleId, + address, + moduleName, txCount, onViewMore, scrollComponentId, @@ -46,11 +48,7 @@ export const ModuleTxsTable = ({ data: moduleTxs, isLoading, error, - } = useModuleTxsByPagination({ - moduleId, - pageSize, - offset, - }); + } = useTxsByModule(address, moduleName, offset, pageSize); const onPageChange = (nextPage: number) => { refetchCount(); @@ -72,10 +70,10 @@ export const ModuleTxsTable = ({ return ( <> { { @@ -408,7 +409,8 @@ export const ModuleDetailsBody = ({ moduleData }: ModuleDetailsBodyProps) => { { defaultValues, mode: "all", }); - const pastTxsState = watch(); - const { data: accountId } = useAccountId(address as HumanAddr); - const { data: countTxs = 0 } = useTxsCountByAddress({ - accountId, - search: pastTxsState.search, - filters: pastTxsState.filters, - isSigner: pastTxsState.isSigner, - }); + const { data: rawTxCount } = useAPITxsCountByAddress( + address as HumanAddr, + pastTxsState.search, + pastTxsState.isSigner, + pastTxsState.filters + ); + const txCount = rawTxCount ?? undefined; const { pagesQuantity, @@ -71,7 +69,7 @@ const PastTxs = () => { setPageSize, offset, } = usePaginator({ - total: countTxs, + total: txCount, initialState: { pageSize: 10, currentPage: 1, @@ -79,63 +77,45 @@ const PastTxs = () => { }, }); - const { data: txs, isLoading } = useTxsByAddressPagination( - accountId, + const { data: txs, isLoading } = useTxsByAddress( + address as HumanAddr, pastTxsState.search, - pastTxsState.filters, pastTxsState.isSigner, + pastTxsState.filters, offset, pageSize ); - const resetPagination = () => { - setPageSize(10); + const handleOnSearchChange = (e: ChangeEvent) => { setCurrentPage(1); + setValue("search", e.target.value); }; - const setFilter = (filter: string, bool: boolean) => { - resetPagination(); - setValue("filters", { ...pastTxsState.filters, [filter]: bool }); - }; - - const onPageChange = (nextPage: number) => { - setCurrentPage(nextPage); + const handleOnIsSignerChange = (value: Option) => { + setCurrentPage(1); + setValue("isSigner", value); }; - const onPageSizeChange = (e: ChangeEvent) => { - const size = Number(e.target.value); - setPageSize(size); + const handleOnFiltersChange = (filter: string, bool: boolean) => { setCurrentPage(1); + setValue("filters", { ...pastTxsState.filters, [filter]: bool }); }; - const filterSelected = useMemo(() => { - return Object.keys(pastTxsState.filters).reduce( - (acc: string[], key: string) => { + const filterSelected = useMemo( + () => + Object.keys(pastTxsState.filters).reduce((acc: string[], key: string) => { if (pastTxsState.filters[key as keyof typeof pastTxsState.filters]) { acc.push(key); } return acc; - }, - [] - ); - }, [pastTxsState]); + }, []), + [pastTxsState] + ); useEffect(() => { if (router.isReady) track(AmpEvent.TO_PAST_TXS); }, [router.isReady]); - useEffect(() => { - setPageSize(10); - setCurrentPage(1); - }, [ - chainId, - setCurrentPage, - setPageSize, - pastTxsState.search, - pastTxsState.isSigner, - pastTxsState.filters, - ]); - useEffect(() => { reset(); }, [chainId, address, reset]); @@ -155,10 +135,7 @@ const PastTxs = () => { { - setCurrentPage(1); - setValue("search", e.target.value); - }} + onChange={handleOnSearchChange} placeholder={`Search with Transaction Hash${ wasm.enabled ? " or Contract Address" : "" }`} @@ -171,22 +148,19 @@ const PastTxs = () => { { - resetPagination(); - setValue("isSigner", value); - }} + setValue={handleOnIsSignerChange} w="165px" /> 0 || @@ -194,7 +168,9 @@ const PastTxs = () => { filterSelected.length > 0 ? ( ) : ( @@ -206,15 +182,19 @@ const PastTxs = () => { ) } /> - {countTxs > 10 && ( + {!!txCount && txCount > 10 && ( { + const size = Number(e.target.value); + setPageSize(size); + setCurrentPage(1); + }} /> )} diff --git a/src/lib/pages/tx-details/components/tx-message/TxMsgExpand.tsx b/src/lib/pages/tx-details/components/tx-message/TxMsgExpand.tsx index e7accd737..cbd134bfb 100644 --- a/src/lib/pages/tx-details/components/tx-message/TxMsgExpand.tsx +++ b/src/lib/pages/tx-details/components/tx-message/TxMsgExpand.tsx @@ -37,6 +37,7 @@ export const TxMsgExpand = ({ type.startsWith("/ibc"); let msgIcon: IconKeys = "info-circle"; let content: ReactNode; + const isOpinit = Boolean(type.startsWith("/opinit")); switch (type) { case "/cosmwasm.wasm.v1.MsgStoreCode": @@ -334,18 +335,28 @@ export const TxMsgExpand = ({ mt={{ base: 1, md: 0 }} /> {content} - {isIBC && !isMobile && ( + {!isMobile && isIBC && ( IBC )} + {!isMobile && isOpinit && ( + + OPInit + + )} - {isIBC && isMobile && ( + {isMobile && isIBC && ( IBC )} + {isMobile && isOpinit && ( + + OPInit + + )} { - if (lastPage.nextKey) { - return lastPage.nextKey; - } - - return false; // No more pages - }, + getNextPageParam: (lastPage) => lastPage.nextKey, refetchOnWindowFocus: false, } ); diff --git a/src/lib/services/expression/txExpression.ts b/src/lib/services/expression/txExpression.ts index 89c8ae20a..673341aa6 100644 --- a/src/lib/services/expression/txExpression.ts +++ b/src/lib/services/expression/txExpression.ts @@ -7,6 +7,7 @@ import { isTxHash } from "lib/utils"; const actions = { isSend: "is_send", isIbc: "is_ibc", + isOpinit: "is_opinit", isExecute: "is_execute", isInstantiate: "is_instantiate", isStoreCode: "is_store_code", diff --git a/src/lib/services/tx.ts b/src/lib/services/tx.ts index aca6e580b..949c7defb 100644 --- a/src/lib/services/tx.ts +++ b/src/lib/services/tx.ts @@ -6,7 +6,14 @@ import type { Any } from "cosmjs-types/google/protobuf/any"; import { z } from "zod"; import type { TypeUrl } from "lib/data"; -import type { Transaction, Option, Fee, TxFilters, Addr } from "lib/types"; +import type { + Transaction, + Option, + Fee, + TxFilters, + Addr, + HexAddr, +} from "lib/types"; import { zAddr, MsgFurtherAction, zUtcDate } from "lib/types"; import { getActionMsgType, @@ -108,6 +115,8 @@ const zBaseTxsResponseItem = z.object({ success: z.boolean(), is_ibc: z.boolean(), is_send: z.boolean(), + // initia + is_opinit: z.boolean().optional(), // wasm is_clear_admin: z.boolean().optional(), is_execute: z.boolean().optional(), @@ -142,6 +151,7 @@ const zTxsResponseItem = zBaseTxsResponseItem.transform((val) => ({ ]), furtherAction: MsgFurtherAction.NONE, isIbc: val.is_ibc, + isOpinit: val.is_opinit ?? false, isInstantiate: val.is_instantiate ?? false, })); @@ -156,7 +166,8 @@ export const getTxs = async ( limit: number, offset: number, isWasm: boolean, - isMove: boolean + isMove: boolean, + isInitia: boolean ) => axios .get(`${endpoint}`, { @@ -165,6 +176,7 @@ export const getTxs = async ( offset, is_wasm: isWasm, is_move: isMove, + is_initia: isInitia, }, }) .then((res) => zTxsResponse.parse(res.data)); @@ -211,6 +223,7 @@ const zAccountTxsResponseItem = zBaseTxsResponseItem val.is_signer ), isIbc: val.is_ibc, + isOpinit: val.is_opinit ?? false, isInstantiate: val.is_instantiate ?? false, })); @@ -222,12 +235,14 @@ export type AccountTxsResponse = z.infer; export const getTxsByAddress = async ( endpoint: string, address: Addr, + search: Option, isSigner: Option, txFilters: TxFilters, limit: number, offset: number, isWasm: boolean, - isMove: boolean + isMove: boolean, + isInitia: boolean ) => { const filterParams = camelToSnake(txFilters); @@ -238,13 +253,72 @@ export const getTxsByAddress = async ( offset, is_wasm: isWasm, is_move: isMove, + is_initia: isInitia, ...filterParams, ...(isSigner !== undefined && { is_signer: isSigner }), + ...(search !== undefined && { search }), }, }) .then((res) => zAccountTxsResponse.parse(res.data)); }; +const zBlockTxsResponse = z.object({ + items: z.array(zTxsResponseItem), + total: z.number().positive(), +}); +export type BlockTxsResponse = z.infer; + +export const getTxsByBlockHeight = async ( + endpoint: string, + height: number, + limit: number, + offset: number, + isWasm: boolean, + isMove: boolean, + isInitia: boolean +) => + axios + .get(`${endpoint}/${height}/txs`, { + params: { + limit, + offset, + is_wasm: isWasm, + is_move: isMove, + is_initia: isInitia, + }, + }) + .then((res) => zBlockTxsResponse.parse(res.data)); + +const zModuleTxsResponse = z.object({ + items: z.array(zTxsResponseItem), +}); +export type ModuleTxsResponse = z.infer; + +export const getTxsByModule = async ( + endpoint: string, + address: HexAddr, + moduleName: string, + limit: number, + offset: number, + isWasm: boolean, + isMove: boolean, + isInitia: boolean +) => + axios + .get( + `${endpoint}/modules/${encodeURIComponent(address)}/${moduleName}/txs`, + { + params: { + limit, + offset, + is_wasm: isWasm, + is_move: isMove, + is_initia: isInitia, + }, + } + ) + .then((res) => zModuleTxsResponse.parse(res.data)); + const zTxsCountResponse = z .object({ count: z.number().nullish(), @@ -254,8 +328,10 @@ const zTxsCountResponse = z export const getAPITxsCountByAddress = async ( endpoint: string, address: Addr, + search: Option, isSigner: Option, - txFilters: TxFilters + txFilters: TxFilters, + isWasm: boolean ) => { const filterParams = camelToSnake(txFilters); @@ -263,7 +339,9 @@ export const getAPITxsCountByAddress = async ( .get(`${endpoint}/${encodeURIComponent(address)}/txs-count`, { params: { ...filterParams, + is_wasm: isWasm, // only for `searching` contract txs ...(isSigner !== undefined && { is_signer: isSigner }), + ...(search !== undefined && { search }), }, }) .then((res) => zTxsCountResponse.parse(res.data)); diff --git a/src/lib/services/txService.ts b/src/lib/services/txService.ts index 0d4417db5..ba2011f56 100644 --- a/src/lib/services/txService.ts +++ b/src/lib/services/txService.ts @@ -10,6 +10,7 @@ import { CELATONE_QUERY_KEYS, useBaseApiRoute, useCelatoneApp, + useInitia, useMoveConfig, useWasmConfig, } from "lib/app-provider"; @@ -18,9 +19,6 @@ import { getTxsCountByAddress, getTxsCountByPoolId, getTxsByPoolIdPagination, - getBlockTransactionCountByHeightQueryDocument, - getBlockTransactionsByHeightQueryDocument, - getModuleTransactionsQueryDocument, getModuleTransactionsCountQueryDocument, } from "lib/query"; import { createQueryFnWithTimeout } from "lib/query-utils"; @@ -32,7 +30,7 @@ import type { Message, PoolTxFilter, Nullable, - HumanAddr, + HexAddr, } from "lib/types"; import { ActionMsgType, MsgFurtherAction } from "lib/types"; import { @@ -45,12 +43,20 @@ import { } from "lib/utils"; import { usePoolTxExpression, useTxExpression } from "./expression"; -import type { AccountTxsResponse, TxResponse, TxsResponse } from "./tx"; +import type { + AccountTxsResponse, + ModuleTxsResponse, + TxResponse, + TxsResponse, + BlockTxsResponse, +} from "./tx"; import { getTxs, getTxsByAddress, queryTxData, getAPITxsCountByAddress, + getTxsByModule, + getTxsByBlockHeight, } from "./tx"; export interface TxData extends TxResponse { @@ -87,20 +93,23 @@ export const useTxData = ( export const useTxsByAddress = ( address: Addr, + search: Option, isSigner: Option, txFilters: TxFilters, offset: number, limit: number -): UseQueryResult => { +) => { const endpoint = useBaseApiRoute("accounts"); const { enabled: isWasm } = useWasmConfig({ shouldRedirect: false }); const { enabled: isMove } = useMoveConfig({ shouldRedirect: false }); + const isInitia = useInitia(); - return useQuery( + return useQuery( [ CELATONE_QUERY_KEYS.TXS_BY_ADDRESS, endpoint, address, + search, isSigner, JSON.stringify(txFilters), limit, @@ -112,12 +121,14 @@ export const useTxsByAddress = ( getTxsByAddress( endpoint, address, + search, isSigner, txFilters, limit, offset, isWasm, - isMove + isMove, + isInitia ), { retry: 1, refetchOnWindowFocus: false } ); @@ -191,6 +202,8 @@ export const useTxsByAddressPagination = ( ), isIbc: transaction.transaction.is_ibc, isInstantiate: transaction.transaction.is_instantiate ?? false, + // TODO: use API + isOpinit: false, })) ); }, [ @@ -274,20 +287,31 @@ export const useTxsCountByAddress = ({ // TODO: this will replace useTxsCountByAddress export const useAPITxsCountByAddress = ( address: Addr, + search: Option, isSigner: Option, txFilters: TxFilters ) => { const endpoint = useBaseApiRoute("accounts"); + const { enabled: wasmEnable } = useWasmConfig({ shouldRedirect: false }); return useQuery( [ CELATONE_QUERY_KEYS.API_TXS_COUNT_BY_ADDRESS, endpoint, address, + search, isSigner, JSON.stringify(txFilters), ], - async () => getAPITxsCountByAddress(endpoint, address, isSigner, txFilters), + async () => + getAPITxsCountByAddress( + endpoint, + address, + search, + isSigner, + txFilters, + wasmEnable + ), { retry: 1, refetchOnWindowFocus: false } ); }; @@ -322,6 +346,7 @@ export const useTxsByPoolIdPagination = ( furtherAction: MsgFurtherAction.NONE, isIbc: transaction.transaction.is_ibc, isInstantiate: false, + isOpinit: false, })) ); }, [expression, indexerGraphClient, offset, pageSize]); @@ -379,167 +404,69 @@ export const useTxsCountByPoolId = ( export const useTxs = ( limit: number, offset: number, - options: Pick< - UseQueryOptions, - "onSuccess" | "onError" - > = {} -): UseQueryResult => { + options: Pick, "onSuccess"> = {} +) => { const endpoint = useBaseApiRoute("txs"); const { enabled: wasmEnable } = useWasmConfig({ shouldRedirect: false }); const { enabled: moveEnable } = useMoveConfig({ shouldRedirect: false }); + const isInitia = useInitia(); - return useQuery( - [CELATONE_QUERY_KEYS.TXS, endpoint, limit, offset, wasmEnable, moveEnable], - async () => getTxs(endpoint, limit, offset, wasmEnable, moveEnable), + return useQuery( + [ + CELATONE_QUERY_KEYS.TXS, + endpoint, + limit, + offset, + wasmEnable, + moveEnable, + isInitia, + ], + async () => + getTxs(endpoint, limit, offset, wasmEnable, moveEnable, isInitia), { ...options, retry: 1, refetchOnWindowFocus: false } ); }; -export const useTxsByBlockHeightPagination = ( +export const useTxsByBlockHeight = ( height: number, limit: number, - offset: number -): UseQueryResult => { - const { indexerGraphClient } = useCelatoneApp(); + offset: number, + options: Pick, "onSuccess"> = {} +) => { + const endpoint = useBaseApiRoute("blocks"); const { enabled: wasmEnable } = useWasmConfig({ shouldRedirect: false }); const { enabled: moveEnable } = useMoveConfig({ shouldRedirect: false }); + const isInitia = useInitia(); - const queryFn = useCallback( - async () => - indexerGraphClient - .request(getBlockTransactionsByHeightQueryDocument, { - limit, - offset, - height, - isWasm: wasmEnable, - isMove: moveEnable, - }) - .then(({ transactions }) => - transactions.map((transaction) => ({ - hash: parseTxHash(transaction.hash), - messages: snakeToCamel(transaction.messages), - sender: transaction.account.address as Addr, - isSigner: false, - height, - created: parseDate(transaction.block.timestamp), - success: transaction.success, - actionMsgType: getActionMsgType([ - transaction.is_execute, - transaction.is_instantiate, - transaction.is_send, - transaction.is_store_code, - transaction.is_migrate, - transaction.is_update_admin, - transaction.is_clear_admin, - ]), - furtherAction: MsgFurtherAction.NONE, - isIbc: transaction.is_ibc, - isInstantiate: transaction.is_instantiate ?? false, - })) - ), - [height, limit, offset, indexerGraphClient, wasmEnable, moveEnable] - ); - - return useQuery( + return useQuery( [ - CELATONE_QUERY_KEYS.TXS_BY_BLOCK_HEIGHT_PAGINATION, - indexerGraphClient, + CELATONE_QUERY_KEYS.TXS_BY_BLOCK_HEIGHT, + endpoint, limit, offset, height, + wasmEnable, + moveEnable, + isInitia, ], - queryFn, - { - keepPreviousData: true, - enabled: !!height, - } - ); -}; - -export const useTxsCountByBlockHeight = ( - height: number -): UseQueryResult> => { - const { indexerGraphClient } = useCelatoneApp(); - - const queryFn = useCallback( async () => - indexerGraphClient - .request(getBlockTransactionCountByHeightQueryDocument, { - height, - }) - .then( - ({ transactions_aggregate }) => - transactions_aggregate.aggregate?.count - ), - [height, indexerGraphClient] - ); - - return useQuery( - [CELATONE_QUERY_KEYS.TXS_BY_BLOCK_HEIGHT_COUNT, indexerGraphClient, height], - queryFn, + getTxsByBlockHeight( + endpoint, + height, + limit, + offset, + wasmEnable, + moveEnable, + isInitia + ), { + ...options, keepPreviousData: true, enabled: !!height, } ); }; -export const useModuleTxsByPagination = ({ - moduleId, - pageSize, - offset, -}: { - moduleId: Option>; - pageSize: number; - offset: number; -}) => { - const { indexerGraphClient } = useCelatoneApp(); - - const queryFn = async () => { - if (!moduleId) return []; - return indexerGraphClient - .request(getModuleTransactionsQueryDocument, { - moduleId, - pageSize, - offset, - }) - .then(({ module_transactions }) => - module_transactions.map((transaction) => ({ - hash: parseTxHash(transaction.transaction.hash), - messages: snakeToCamel(transaction.transaction.messages), - sender: transaction.transaction.account.address as HumanAddr, - height: transaction.block.height, - created: parseDate(transaction.block.timestamp), - success: transaction.transaction.success, - actionMsgType: getActionMsgType([ - transaction.transaction.is_send, - // TODO: handle more action Move msg type - ]), - furtherAction: MsgFurtherAction.NONE, - isSigner: false, - isIbc: transaction.transaction.is_ibc, - isInstantiate: false, - })) - ); - }; - - return useQuery( - [ - CELATONE_QUERY_KEYS.MODULE_TXS, - indexerGraphClient, - moduleId, - pageSize, - offset, - ], - createQueryFnWithTimeout(queryFn), - { - enabled: Boolean(moduleId), - retry: 1, - refetchOnWindowFocus: false, - } - ); -}; - export const useModuleTxsCount = (moduleId: Option>) => { const { indexerGraphClient } = useCelatoneApp(); @@ -565,3 +492,40 @@ export const useModuleTxsCount = (moduleId: Option>) => { } ); }; + +export const useTxsByModule = ( + address: HexAddr, + moduleName: string, + offset: number, + limit: number +) => { + const endpoint = useBaseApiRoute("move"); + const { enabled: isWasm } = useWasmConfig({ shouldRedirect: false }); + const { enabled: isMove } = useMoveConfig({ shouldRedirect: false }); + const isInitia = useInitia(); + + return useQuery( + [ + CELATONE_QUERY_KEYS.MODULE_TXS, + endpoint, + address, + moduleName, + limit, + offset, + isWasm, + isMove, + ], + async () => + getTxsByModule( + endpoint, + address, + moduleName, + limit, + offset, + isWasm, + isMove, + isInitia + ), + { retry: 1, refetchOnWindowFocus: false } + ); +}; diff --git a/src/lib/styles/theme/components/tag.ts b/src/lib/styles/theme/components/tag.ts index f85c810b4..143ef1d3b 100644 --- a/src/lib/styles/theme/components/tag.ts +++ b/src/lib/styles/theme/components/tag.ts @@ -4,6 +4,13 @@ import { createMultiStyleConfigHelpers } from "@chakra-ui/react"; const { definePartsStyle, defineMultiStyleConfig } = createMultiStyleConfigHelpers(tagAnatomy.keys); +const teal = definePartsStyle({ + container: { + bg: "#69DEC9", + color: "gray.900", + }, +}); + const accentDark = definePartsStyle({ container: { bg: "accent.dark", @@ -67,6 +74,7 @@ export const Tag = defineMultiStyleConfig({ "primary-light": primaryLight, "accent-dark": accentDark, "accent-darker": accentDarker, + teal, gray, }, defaultProps: { diff --git a/src/lib/types/tx/transaction.ts b/src/lib/types/tx/transaction.ts index 495e91764..0507c8ad0 100644 --- a/src/lib/types/tx/transaction.ts +++ b/src/lib/types/tx/transaction.ts @@ -37,6 +37,12 @@ export interface Transaction { furtherAction: MsgFurtherAction; isIbc: boolean; isInstantiate: boolean; + isOpinit: boolean; +} + +/* Filter for INITIA */ +export interface InitiaTxFilters { + isOpinit: boolean; } export interface BaseTxFilters { @@ -62,7 +68,8 @@ export interface MoveTxFilters { export interface TxFilters extends BaseTxFilters, WasmTxFilters, - MoveTxFilters {} + MoveTxFilters, + InitiaTxFilters {} export type PoolTxFilter = | "is_all" diff --git a/src/lib/utils/extractActionValue.ts b/src/lib/utils/extractActionValue.ts index 3757a3680..573112254 100644 --- a/src/lib/utils/extractActionValue.ts +++ b/src/lib/utils/extractActionValue.ts @@ -4,6 +4,8 @@ export const displayActionValue = (isActionName: string) => { return "Send"; case "isIbc": return "IBC"; + case "isOpinit": + return "OPInit"; case "isStoreCode": return "Store Code"; case "isInstantiate":