From f6cd08041bf5a3b18f97677a3442fae7f4a64531 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Wed, 21 Dec 2022 15:41:29 +0700 Subject: [PATCH 1/5] feat: load all contract detail --- src/lib/app-provider/contexts/app.tsx | 12 ++ src/lib/components/modal/code/SaveNewCode.tsx | 2 +- .../modal/contract/SaveNewContract.tsx | 8 +- src/lib/data/queries.ts | 11 ++ src/lib/gql/gql.ts | 5 + src/lib/gql/graphql.ts | 98 ++++++++++++++ src/lib/model/contract.ts | 62 ++++++++- src/lib/pages/execute/index.tsx | 2 +- src/lib/pages/query/index.tsx | 2 +- src/lib/services/code.ts | 6 + src/lib/services/contract.ts | 121 +++++++++++++----- src/lib/services/contractService.ts | 28 ++++ 12 files changed, 319 insertions(+), 38 deletions(-) create mode 100644 src/lib/services/code.ts diff --git a/src/lib/app-provider/contexts/app.tsx b/src/lib/app-provider/contexts/app.tsx index 5c3f431a4..be09470b4 100644 --- a/src/lib/app-provider/contexts/app.tsx +++ b/src/lib/app-provider/contexts/app.tsx @@ -35,6 +35,8 @@ interface AppContextInterface< ContractAddress, Constants extends AppConstants = AppConstants > { + chainName: string; + chainId: string; chainGasPrice: ChainGasPrice; contractAddress: ContractAddress; constants: Constants; @@ -48,6 +50,8 @@ interface AppContextInterface< // eslint-disable-next-line @typescript-eslint/no-explicit-any const AppContext = createContext>({ + chainName: "", + chainId: "", chainGasPrice: { denom: "", gasPrice: "0" as U }, contractAddress: {}, constants: { gasAdjustment: 0 }, @@ -69,6 +73,11 @@ export const AppProvider = ({ const { setCodeUserKey, isCodeUserKeyExist } = useCodeStore(); const { setContractUserKey, isContractUserKeyExist } = useContractStore(); + const chainId = useMemo(() => { + if (!currentChainRecord) return ""; + return currentChainRecord.chain.chain_id; + }, [currentChainRecord]); + const chainGasPrice = useMemo(() => { if ( !currentChainRecord || @@ -99,12 +108,15 @@ export const AppProvider = ({ AppContextInterface >(() => { return { + chainName: currentChainName, + chainId, chainGasPrice, contractAddress: contractAddress(currentChainName), constants, ...chainBoundStates, }; }, [ + chainId, chainGasPrice, contractAddress, currentChainName, diff --git a/src/lib/components/modal/code/SaveNewCode.tsx b/src/lib/components/modal/code/SaveNewCode.tsx index 4aefbb9ae..7879d0f80 100644 --- a/src/lib/components/modal/code/SaveNewCode.tsx +++ b/src/lib/components/modal/code/SaveNewCode.tsx @@ -12,7 +12,7 @@ import { MAX_CODE_DESCRIPTION_LENGTH, } from "lib/data"; import { useCodeStore, useEndpoint, useUserKey } from "lib/hooks"; -import { getCodeIdInfo } from "lib/services/contract"; +import { getCodeIdInfo } from "lib/services/code"; interface ModalProps { buttonProps: ButtonProps; diff --git a/src/lib/components/modal/contract/SaveNewContract.tsx b/src/lib/components/modal/contract/SaveNewContract.tsx index 6537864a2..0a5383c6a 100644 --- a/src/lib/components/modal/contract/SaveNewContract.tsx +++ b/src/lib/components/modal/contract/SaveNewContract.tsx @@ -18,7 +18,7 @@ import { } from "lib/data"; import { useContractStore, useEndpoint } from "lib/hooks"; import { useHandleContractSave } from "lib/hooks/useHandleSave"; -import { queryContractWithTime } from "lib/services/contract"; +import { queryInstantiateInfo } from "lib/services/contract"; import type { Option, RpcContractError } from "lib/types"; import { formatSlugName } from "lib/utils"; @@ -62,8 +62,8 @@ export function SaveNewContract({ list, buttonProps }: SaveNewContractProps) { // TODO: Abstract query const { refetch } = useQuery( - ["query", "contractWithTime", contractAddress], - async () => queryContractWithTime(endpoint, contractAddress), + ["query", "instantiateInfo", contractAddress], + async () => queryInstantiateInfo(endpoint, contractAddress), { enabled: false, retry: false, @@ -72,7 +72,7 @@ export function SaveNewContract({ list, buttonProps }: SaveNewContractProps) { onSuccess(data) { setInstantiator(data.instantiator); setLabel(data.label); - setCreated(data.created); + setCreated(data.createdTime); setName(data.label); setStatus({ state: "success", diff --git a/src/lib/data/queries.ts b/src/lib/data/queries.ts index 6b9ced4e5..5f869b5bf 100644 --- a/src/lib/data/queries.ts +++ b/src/lib/data/queries.ts @@ -59,3 +59,14 @@ export const getInstantiatedListByUserQueryDocument = graphql(` } } `); + +export const getInstantiateDetailByContractQueryDocument = graphql(` + query getInstantiateDetailByContractQueryDocument($contractAddr: String!) { + contracts(where: { address: { _eq: $contractAddr } }) { + init_msg + transaction { + hash + } + } + } +`); diff --git a/src/lib/gql/gql.ts b/src/lib/gql/gql.ts index 1572d58f7..f7eb89fc5 100644 --- a/src/lib/gql/gql.ts +++ b/src/lib/gql/gql.ts @@ -11,6 +11,8 @@ const documents = { types.GetInstantiatedCountByUserQueryDocumentDocument, "\n query getInstantiatedListByUserQueryDocument($walletAddr: String!) {\n contracts(\n where: { transaction: { account: { address: { _eq: $walletAddr } } } }\n limit: 500\n offset: 0\n order_by: { transaction: { block: { timestamp: desc } } }\n ) {\n label\n address\n transaction {\n block {\n timestamp\n }\n }\n }\n }\n": types.GetInstantiatedListByUserQueryDocumentDocument, + "\n query getInstantiateDetailByContractQueryDocument($contractAddr: String!) {\n contracts(where: { address: { _eq: $contractAddr } }) {\n init_msg\n transaction {\n hash\n }\n }\n }\n": + types.GetInstantiateDetailByContractQueryDocumentDocument, }; export function graphql( @@ -25,6 +27,9 @@ export function graphql( export function graphql( source: "\n query getInstantiatedListByUserQueryDocument($walletAddr: String!) {\n contracts(\n where: { transaction: { account: { address: { _eq: $walletAddr } } } }\n limit: 500\n offset: 0\n order_by: { transaction: { block: { timestamp: desc } } }\n ) {\n label\n address\n transaction {\n block {\n timestamp\n }\n }\n }\n }\n" ): typeof documents["\n query getInstantiatedListByUserQueryDocument($walletAddr: String!) {\n contracts(\n where: { transaction: { account: { address: { _eq: $walletAddr } } } }\n limit: 500\n offset: 0\n order_by: { transaction: { block: { timestamp: desc } } }\n ) {\n label\n address\n transaction {\n block {\n timestamp\n }\n }\n }\n }\n"]; +export function graphql( + source: "\n query getInstantiateDetailByContractQueryDocument($contractAddr: String!) {\n contracts(where: { address: { _eq: $contractAddr } }) {\n init_msg\n transaction {\n hash\n }\n }\n }\n" +): typeof documents["\n query getInstantiateDetailByContractQueryDocument($contractAddr: String!) {\n contracts(where: { address: { _eq: $contractAddr } }) {\n init_msg\n transaction {\n hash\n }\n }\n }\n"]; export function graphql(source: string): unknown; export function graphql(source: string) { diff --git a/src/lib/gql/graphql.ts b/src/lib/gql/graphql.ts index 52bcd3460..b7af869bf 100644 --- a/src/lib/gql/graphql.ts +++ b/src/lib/gql/graphql.ts @@ -4722,6 +4722,19 @@ export type GetInstantiatedListByUserQueryDocumentQuery = { }>; }; +export type GetInstantiateDetailByContractQueryDocumentQueryVariables = Exact<{ + contractAddr: Scalars["String"]; +}>; + +export type GetInstantiateDetailByContractQueryDocumentQuery = { + __typename?: "query_root"; + contracts: Array<{ + __typename?: "contracts"; + init_msg?: string | null; + transaction?: { __typename?: "transactions"; hash: any } | null; + }>; +}; + export const GetCodeListByUserQueryDocument = { kind: "Document", definitions: [ @@ -5200,3 +5213,88 @@ export const GetInstantiatedListByUserQueryDocumentDocument = { GetInstantiatedListByUserQueryDocumentQuery, GetInstantiatedListByUserQueryDocumentQueryVariables >; +export const GetInstantiateDetailByContractQueryDocumentDocument = { + kind: "Document", + definitions: [ + { + kind: "OperationDefinition", + operation: "query", + name: { + kind: "Name", + value: "getInstantiateDetailByContractQueryDocument", + }, + variableDefinitions: [ + { + kind: "VariableDefinition", + variable: { + kind: "Variable", + name: { kind: "Name", value: "contractAddr" }, + }, + type: { + kind: "NonNullType", + type: { + kind: "NamedType", + name: { kind: "Name", value: "String" }, + }, + }, + }, + ], + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "contracts" }, + arguments: [ + { + kind: "Argument", + name: { kind: "Name", value: "where" }, + value: { + kind: "ObjectValue", + fields: [ + { + kind: "ObjectField", + name: { kind: "Name", value: "address" }, + value: { + kind: "ObjectValue", + fields: [ + { + kind: "ObjectField", + name: { kind: "Name", value: "_eq" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "contractAddr" }, + }, + }, + ], + }, + }, + ], + }, + }, + ], + selectionSet: { + kind: "SelectionSet", + selections: [ + { kind: "Field", name: { kind: "Name", value: "init_msg" } }, + { + kind: "Field", + name: { kind: "Name", value: "transaction" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { kind: "Field", name: { kind: "Name", value: "hash" } }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode< + GetInstantiateDetailByContractQueryDocumentQuery, + GetInstantiateDetailByContractQueryDocumentQueryVariables +>; diff --git a/src/lib/model/contract.ts b/src/lib/model/contract.ts index 9aea23c03..da1716951 100644 --- a/src/lib/model/contract.ts +++ b/src/lib/model/contract.ts @@ -1,14 +1,34 @@ +import type { Coin } from "@cosmjs/stargate"; import { useWallet } from "@cosmos-kit/react"; +import { useQuery } from "@tanstack/react-query"; +import { useApp } from "lib/app-provider"; import { INSTANTIATED_LIST_NAME } from "lib/data"; -import { useContractStore } from "lib/hooks"; +import { useContractStore, useEndpoint } from "lib/hooks"; +import type { InstantiateInfo, PublicInfo } from "lib/services/contract"; +import { + queryPublicInfo, + queryContractBalances, + queryInstantiateInfo, +} from "lib/services/contract"; import { useInstantiatedCountByUserQuery, + useInstantiateDetailByContractQuery, useInstantiatedListByUserQuery, } from "lib/services/contractService"; -import type { ContractListInfo } from "lib/stores/contract"; +import type { ContractInfo, ContractListInfo } from "lib/stores/contract"; import { formatSlugName } from "lib/utils"; +interface ContractDetail { + instantiateInfo: InstantiateInfo | undefined; + contractInfo: ContractInfo | undefined; + publicInfo: PublicInfo | undefined; + balances: Coin[]; + initMsg: string; + initTxHash?: string; + initProposalId?: number; +} + export const useInstantiatedByMe = (enable: boolean): ContractListInfo => { const { address } = useWallet(); const { data: contracts = [] } = useInstantiatedListByUserQuery( @@ -48,3 +68,41 @@ export const useInstantiatedMockInfoByMe = (): ContractListInfo => { isContractRemovable: false, }; }; + +export const useContractDetail = (contract: string): ContractDetail => { + const { getContractInfo } = useContractStore(); + const { chainName, chainId } = useApp(); + const endpoint = useEndpoint(); + + const { data: instantiateInfo } = useQuery( + ["query", "instantiateInfo", contract], + async () => queryInstantiateInfo(endpoint, contract) + ); + const { data: contractBalances = { balances: [] } } = useQuery( + ["query", "contractBalances", contract], + async () => queryContractBalances(endpoint, contract) + ); + const { data: publicInfo } = useQuery( + ["query", "publicInfo", contract], + async () => queryPublicInfo(chainName, chainId, contract) + ); + + const contractInfo = getContractInfo(contract); + const { + data: instantiateDetail = { + initMsg: "{}", + }, + } = useInstantiateDetailByContractQuery(contract); + // TODO: contract proposal id + const proposalId = undefined; + + return { + instantiateInfo, + contractInfo, + publicInfo, + balances: contractBalances.balances, + initMsg: instantiateDetail.initMsg, + initTxHash: instantiateDetail.initTxHash, + initProposalId: proposalId, + }; +}; diff --git a/src/lib/pages/execute/index.tsx b/src/lib/pages/execute/index.tsx index 90a80ce41..8a51b7a9e 100644 --- a/src/lib/pages/execute/index.tsx +++ b/src/lib/pages/execute/index.tsx @@ -94,7 +94,7 @@ const Execute = () => { if (!contractState) { try { const onChainDetail = await queryContract(endpoint, contractAddr); - setContractName(onChainDetail.result?.label); + setContractName(onChainDetail.contract_info.label); } catch { setContractName("Invalid Contract"); } diff --git a/src/lib/pages/query/index.tsx b/src/lib/pages/query/index.tsx index cd21590e2..a09410f45 100644 --- a/src/lib/pages/query/index.tsx +++ b/src/lib/pages/query/index.tsx @@ -86,7 +86,7 @@ const Query = () => { if (!contractState) { try { const onChainDetail = await queryContract(endpoint, contractAddr); - setName(onChainDetail.result?.label); + setName(onChainDetail.contract_info.label); } catch { setName("Invalid Contract"); } diff --git a/src/lib/services/code.ts b/src/lib/services/code.ts new file mode 100644 index 000000000..bdbebbe48 --- /dev/null +++ b/src/lib/services/code.ts @@ -0,0 +1,6 @@ +import axios from "axios"; + +export const getCodeIdInfo = async (endpoint: string, id: number) => { + const { data } = await axios.get(`${endpoint}/cosmwasm/wasm/v1/code/${id}`); + return data; +}; diff --git a/src/lib/services/contract.ts b/src/lib/services/contract.ts index f11f061a8..c752b6392 100644 --- a/src/lib/services/contract.ts +++ b/src/lib/services/contract.ts @@ -1,26 +1,21 @@ +import type { Coin } from "@cosmjs/stargate"; import axios from "axios"; import { encode } from "lib/utils"; -export const queryData = async ( - endpoint: string, - contract: string, - msg: string -) => { - const b64 = encode(msg); - const { data } = await axios.get( - `${endpoint}/cosmwasm/wasm/v1/contract/${contract}/smart/${b64}` - ); - return data; -}; - interface ContractResponse { - height: string; - result: { - address: string; - code_id: number; + address: string; + contract_info: { + code_id: string; creator: string; + admin: string; label: string; + created?: { + block_height: number; + tx_index: number; + }; + ibc_port_id: string; + extension: string; }; } @@ -32,32 +27,100 @@ interface BlockResponse { }; } +interface BalancesResponse { + balances: Coin[]; +} + +export interface InstantiateInfo { + address: string; + codeId: string; + instantiator: string; + admin: string; + label: string; + createdHeight: number; + createdTime: Date; + ibcPortId: string; + raw: ContractResponse; +} + +export interface PublicInfo { + slug: string; + name: string; + address: string; + description: string; +} + +export const queryData = async ( + endpoint: string, + contract: string, + msg: string +) => { + const b64 = encode(msg); + const { data } = await axios.get( + `${endpoint}/cosmwasm/wasm/v1/contract/${contract}/smart/${b64}` + ); + return data; +}; + export const queryContract = async (endpoint: string, contract: string) => { - // TODO: change to `${endpoint}/cosmwasm/wasm/v1/contract/${contract}` const { data } = await axios.get( - `${endpoint}/wasm/contract/${contract}` + `${endpoint}/cosmwasm/wasm/v1/contract/${contract}` ); return data; }; -export const queryContractWithTime = async ( +export const queryInstantiateInfo = async ( endpoint: string, contract: string -) => { +): Promise => { const res = await queryContract(endpoint, contract); - const { data } = await axios.get( - `${endpoint}/cosmos/base/tendermint/v1beta1/blocks/${res.height}` - ); + + // TODO: check `created` field for contracts created with proposals + let createdHeight; + let createdTime; + if (res.contract_info.created) { + const { data } = await axios.get( + `${endpoint}/cosmos/base/tendermint/v1beta1/blocks/${res.contract_info.created.block_height}` + ); + createdHeight = res.contract_info.created.block_height; + createdTime = new Date(data.block.header.time); + } else { + // TODO: revisit default value + createdHeight = 0; + createdTime = new Date(0); + } return { - address: res.result.address, - instantiator: res.result.creator, - label: res.result.label, - created: new Date(data.block.header.time), + address: res.address, + codeId: res.contract_info.code_id, + instantiator: res.contract_info.creator, + admin: res.contract_info.admin, + label: res.contract_info.label, + createdHeight, + createdTime, + ibcPortId: res.contract_info.ibc_port_id, + raw: res, }; }; -export const getCodeIdInfo = async (endpoint: string, id: number) => { - const { data } = await axios.get(`${endpoint}/cosmwasm/wasm/v1/code/${id}`); +export const queryContractBalances = async ( + endpoint: string, + contract: string +) => { + const { data } = await axios.get( + `${endpoint}/cosmos/bank/v1beta1/balances/${contract}?pagination.limit=0` + ); return data; }; + +export const queryPublicInfo = async ( + chainName: string, + chainId: string, + contract: string +): Promise => { + return axios + .get( + `https://cosmos-registry.alleslabs.dev/data/${chainName}/${chainId}/contracts.json` + ) + .then(({ data }) => data.find((info) => info.address === contract)); +}; diff --git a/src/lib/services/contractService.ts b/src/lib/services/contractService.ts index 28dd57826..d6bffa783 100644 --- a/src/lib/services/contractService.ts +++ b/src/lib/services/contractService.ts @@ -6,9 +6,15 @@ import { indexerGraphClient } from "lib/data/graphql"; import { getInstantiatedListByUserQueryDocument, getInstantiatedCountByUserQueryDocument, + getInstantiateDetailByContractQueryDocument, } from "lib/data/queries"; import type { ContractInfo } from "lib/stores/contract"; +interface InstantiateDetail { + initMsg: string; + initTxHash?: string; +} + export const useInstantiatedCountByUserQuery = ( walletAddr: string | undefined ): UseQueryResult => { @@ -55,3 +61,25 @@ export const useInstantiatedListByUserQuery = ( enabled: !!walletAddr, }); }; + +export const useInstantiateDetailByContractQuery = ( + contractAddr: string +): UseQueryResult => { + const queryFn = useCallback(async () => { + return indexerGraphClient + .request(getInstantiateDetailByContractQueryDocument, { contractAddr }) + .then(({ contracts }) => + contracts + .map((contract) => ({ + // TODO: revisit undefined after backend remove nullable + initMsg: contract.init_msg ?? "{}", + initTxHash: (contract.transaction?.hash as string).substring(2), + })) + ?.at(0) + ); + }, [contractAddr]); + + return useQuery(["instantiate_detail_by_contract", contractAddr], queryFn, { + keepPreviousData: true, + }); +}; From fdf216b6c1fd2ddf0b9ac4c6582c87f0739d56ee Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 23 Dec 2022 14:51:45 +0700 Subject: [PATCH 2/5] fix: as commented and contractAddr variables --- src/lib/app-fns/tx/execute.tsx | 10 ++-- src/lib/app-provider/contexts/app.tsx | 35 +++++--------- src/lib/app-provider/tx/execute.ts | 7 +-- .../modal/contract/SaveNewContract.tsx | 4 +- .../modal/select-contract/SelectContract.tsx | 4 +- src/lib/model/contract.ts | 41 +++++++++++----- .../pages/execute/components/ExecuteArea.tsx | 16 +++---- src/lib/pages/execute/index.tsx | 30 ++++++------ src/lib/pages/query/components/QueryArea.tsx | 14 +++--- src/lib/pages/query/index.tsx | 48 +++++++++++-------- src/lib/services/code.ts | 23 ++++++++- src/lib/services/contract.ts | 35 ++++++++------ src/lib/services/contractService.ts | 7 +-- src/lib/stores/contract.ts | 4 +- 14 files changed, 157 insertions(+), 121 deletions(-) diff --git a/src/lib/app-fns/tx/execute.tsx b/src/lib/app-fns/tx/execute.tsx index 2c6e20fc3..e28b6a474 100644 --- a/src/lib/app-fns/tx/execute.tsx +++ b/src/lib/app-fns/tx/execute.tsx @@ -10,7 +10,7 @@ import type { Observable } from "rxjs"; import { ExplorerLink } from "lib/components/ExplorerLink"; import type { Activity } from "lib/stores/contract"; -import type { TxResultRendering } from "lib/types"; +import type { ContractAddr, TxResultRendering } from "lib/types"; import { TxStreamPhase } from "lib/types"; import { encode, formatUFee } from "lib/utils"; @@ -18,7 +18,7 @@ import { catchTxError, postTx, sendingTx } from "./common"; interface ExecuteTxParams { address: string; - contractAddress: string; + contractAddr: ContractAddr; fee: StdFee; msg: object; client: SigningCosmWasmClient; @@ -29,7 +29,7 @@ interface ExecuteTxParams { export const executeContractTx = ({ address, - contractAddress, + contractAddr, fee, msg, client, @@ -40,14 +40,14 @@ export const executeContractTx = ({ return pipe( sendingTx(fee), postTx({ - postFn: () => client.execute(address, contractAddress, msg, fee), + postFn: () => client.execute(address, contractAddr, msg, fee), }), ({ value: txInfo }) => { onTxSucceed?.(userKey, { type: "execute", action: Object.keys(msg)[0], sender: address, - contractAddress, + contractAddr, msg: encode(JSON.stringify(msg)), // base64 timestamp: new Date(), }); diff --git a/src/lib/app-provider/contexts/app.tsx b/src/lib/app-provider/contexts/app.tsx index be09470b4..1b443b5dc 100644 --- a/src/lib/app-provider/contexts/app.tsx +++ b/src/lib/app-provider/contexts/app.tsx @@ -35,8 +35,6 @@ interface AppContextInterface< ContractAddress, Constants extends AppConstants = AppConstants > { - chainName: string; - chainId: string; chainGasPrice: ChainGasPrice; contractAddress: ContractAddress; constants: Constants; @@ -50,8 +48,6 @@ interface AppContextInterface< // eslint-disable-next-line @typescript-eslint/no-explicit-any const AppContext = createContext>({ - chainName: "", - chainId: "", chainGasPrice: { denom: "", gasPrice: "0" as U }, contractAddress: {}, constants: { gasAdjustment: 0 }, @@ -73,11 +69,6 @@ export const AppProvider = ({ const { setCodeUserKey, isCodeUserKeyExist } = useCodeStore(); const { setContractUserKey, isContractUserKeyExist } = useContractStore(); - const chainId = useMemo(() => { - if (!currentChainRecord) return ""; - return currentChainRecord.chain.chain_id; - }, [currentChainRecord]); - const chainGasPrice = useMemo(() => { if ( !currentChainRecord || @@ -104,25 +95,21 @@ export const AppProvider = ({ }; }, [currentChainName]); - const states = useMemo< - AppContextInterface - >(() => { - return { - chainName: currentChainName, - chainId, + const states = useMemo>( + () => ({ chainGasPrice, contractAddress: contractAddress(currentChainName), constants, ...chainBoundStates, - }; - }, [ - chainId, - chainGasPrice, - contractAddress, - currentChainName, - constants, - chainBoundStates, - ]); + }), + [ + chainGasPrice, + contractAddress, + currentChainName, + constants, + chainBoundStates, + ] + ); useEffect(() => { if (currentChainName) { diff --git a/src/lib/app-provider/tx/execute.ts b/src/lib/app-provider/tx/execute.ts index 8a29742a8..3f246e9a9 100644 --- a/src/lib/app-provider/tx/execute.ts +++ b/src/lib/app-provider/tx/execute.ts @@ -5,12 +5,13 @@ import { useCallback } from "react"; import { executeContractTx } from "lib/app-fns/tx/execute"; import { useUserKey } from "lib/hooks/useUserKey"; import type { Activity } from "lib/stores/contract"; +import type { ContractAddr } from "lib/types"; export interface ExecuteStreamParams { onTxSucceed?: (userKey: string, activity: Activity) => void; onTxFailed?: () => void; estimatedFee: StdFee | undefined; - contractAddress: string; + contractAddr: ContractAddr; msg: object; } @@ -23,7 +24,7 @@ export const useExecuteContractTx = () => { onTxSucceed, onTxFailed, estimatedFee, - contractAddress, + contractAddr, msg, }: ExecuteStreamParams) => { const client = await getCosmWasmClient(); @@ -33,7 +34,7 @@ export const useExecuteContractTx = () => { return executeContractTx({ address, - contractAddress, + contractAddr, fee: estimatedFee, msg, client, diff --git a/src/lib/components/modal/contract/SaveNewContract.tsx b/src/lib/components/modal/contract/SaveNewContract.tsx index 0a5383c6a..a24ab4227 100644 --- a/src/lib/components/modal/contract/SaveNewContract.tsx +++ b/src/lib/components/modal/contract/SaveNewContract.tsx @@ -19,7 +19,7 @@ import { import { useContractStore, useEndpoint } from "lib/hooks"; import { useHandleContractSave } from "lib/hooks/useHandleSave"; import { queryInstantiateInfo } from "lib/services/contract"; -import type { Option, RpcContractError } from "lib/types"; +import type { ContractAddr, Option, RpcContractError } from "lib/types"; import { formatSlugName } from "lib/utils"; interface SaveNewContractProps { @@ -63,7 +63,7 @@ export function SaveNewContract({ list, buttonProps }: SaveNewContractProps) { // TODO: Abstract query const { refetch } = useQuery( ["query", "instantiateInfo", contractAddress], - async () => queryInstantiateInfo(endpoint, contractAddress), + async () => queryInstantiateInfo(endpoint, contractAddress as ContractAddr), { enabled: false, retry: false, diff --git a/src/lib/components/modal/select-contract/SelectContract.tsx b/src/lib/components/modal/select-contract/SelectContract.tsx index 8de579efe..7ecec2a89 100644 --- a/src/lib/components/modal/select-contract/SelectContract.tsx +++ b/src/lib/components/modal/select-contract/SelectContract.tsx @@ -25,7 +25,7 @@ import { DEFAULT_RPC_ERROR } from "lib/data"; import { useContractStore, useEndpoint } from "lib/hooks"; import { useInstantiatedByMe } from "lib/model/contract"; import { queryContract } from "lib/services/contract"; -import type { RpcContractError } from "lib/types"; +import type { ContractAddr, RpcContractError } from "lib/types"; import { AllContractLists } from "./AllContractLists"; import { ListDetail } from "./ListDetail"; @@ -71,7 +71,7 @@ export const SelectContract = ({ // TODO: Abstract query const { refetch, isFetching, isRefetching } = useQuery( ["query", "contract", searchManual], - async () => queryContract(endpoint, searchManual), + async () => queryContract(endpoint, searchManual as ContractAddr), { enabled: false, retry: false, diff --git a/src/lib/model/contract.ts b/src/lib/model/contract.ts index da1716951..7cc14f0d2 100644 --- a/src/lib/model/contract.ts +++ b/src/lib/model/contract.ts @@ -2,7 +2,6 @@ import type { Coin } from "@cosmjs/stargate"; import { useWallet } from "@cosmos-kit/react"; import { useQuery } from "@tanstack/react-query"; -import { useApp } from "lib/app-provider"; import { INSTANTIATED_LIST_NAME } from "lib/data"; import { useContractStore, useEndpoint } from "lib/hooks"; import type { InstantiateInfo, PublicInfo } from "lib/services/contract"; @@ -17,6 +16,7 @@ import { useInstantiatedListByUserQuery, } from "lib/services/contractService"; import type { ContractInfo, ContractListInfo } from "lib/stores/contract"; +import type { ContractAddr, HumanAddr } from "lib/types"; import { formatSlugName } from "lib/utils"; interface ContractDetail { @@ -32,7 +32,7 @@ interface ContractDetail { export const useInstantiatedByMe = (enable: boolean): ContractListInfo => { const { address } = useWallet(); const { data: contracts = [] } = useInstantiatedListByUserQuery( - enable ? address : undefined + enable ? (address as HumanAddr) : undefined ); const { getContractInfo } = useContractStore(); @@ -52,7 +52,9 @@ export const useInstantiatedByMe = (enable: boolean): ContractListInfo => { export const useInstantiatedMockInfoByMe = (): ContractListInfo => { const { address } = useWallet(); - const { data: count = 0 } = useInstantiatedCountByUserQuery(address); + const { data: count = 0 } = useInstantiatedCountByUserQuery( + address as HumanAddr + ); return { contracts: Array.from({ length: count }, () => ({ @@ -69,32 +71,45 @@ export const useInstantiatedMockInfoByMe = (): ContractListInfo => { }; }; -export const useContractDetail = (contract: string): ContractDetail => { +export const useContractDetail = ( + contractAddr: ContractAddr +): ContractDetail | undefined => { + const { currentChainRecord } = useWallet(); const { getContractInfo } = useContractStore(); - const { chainName, chainId } = useApp(); const endpoint = useEndpoint(); const { data: instantiateInfo } = useQuery( - ["query", "instantiateInfo", contract], - async () => queryInstantiateInfo(endpoint, contract) + ["query", "instantiateInfo", contractAddr], + async () => queryInstantiateInfo(endpoint, contractAddr), + { enabled: !!currentChainRecord } ); const { data: contractBalances = { balances: [] } } = useQuery( - ["query", "contractBalances", contract], - async () => queryContractBalances(endpoint, contract) + ["query", "contractBalances", contractAddr], + async () => queryContractBalances(endpoint, contractAddr), + { enabled: !!currentChainRecord } ); const { data: publicInfo } = useQuery( - ["query", "publicInfo", contract], - async () => queryPublicInfo(chainName, chainId, contract) + ["query", "publicInfo", contractAddr], + async () => + queryPublicInfo( + currentChainRecord?.name, + currentChainRecord?.chain.chain_id, + contractAddr + ), + { enabled: !!currentChainRecord } ); - const contractInfo = getContractInfo(contract); + const contractInfo = getContractInfo(contractAddr); const { data: instantiateDetail = { initMsg: "{}", }, - } = useInstantiateDetailByContractQuery(contract); + } = useInstantiateDetailByContractQuery(contractAddr); // TODO: contract proposal id const proposalId = undefined; + // TODO: get all related transactions + + if (!currentChainRecord) return undefined; return { instantiateInfo, diff --git a/src/lib/pages/execute/components/ExecuteArea.tsx b/src/lib/pages/execute/components/ExecuteArea.tsx index af5d4daf0..27d56a70c 100644 --- a/src/lib/pages/execute/components/ExecuteArea.tsx +++ b/src/lib/pages/execute/components/ExecuteArea.tsx @@ -20,13 +20,13 @@ import { MsgType } from "lib/types"; import { composeMsg, jsonPrettify, jsonValidate } from "lib/utils"; interface ExecuteAreaProps { - contractAddress: string; + contractAddr: ContractAddr; initialMsg: string; cmds: [string, string][]; } export const ExecuteArea = ({ - contractAddress, + contractAddr, initialMsg, cmds, }: ExecuteAreaProps) => { @@ -46,7 +46,7 @@ export const ExecuteArea = ({ msg.trim().length && jsonValidate(msg) === null && address && - contractAddress + contractAddr ); const { isFetching } = useSimulateFeeQuery({ @@ -70,14 +70,14 @@ export const ExecuteArea = ({ }, onTxFailed: () => setProcessing(false), estimatedFee: fee, - contractAddress, + contractAddr, msg: JSON.parse(msg), }); if (stream) { setProcessing(true); broadcast(stream); } - }, [contractAddress, fee, msg, addActivity, executeTx, broadcast]); + }, [contractAddr, fee, msg, addActivity, executeTx, broadcast]); useEffect(() => setMsg(initialMsg), [initialMsg]); @@ -86,7 +86,7 @@ export const ExecuteArea = ({ setError(""); const composedMsg = composeMsg(MsgType.EXECUTE, { sender: address as HumanAddr, - contract: contractAddress as ContractAddr, + contract: contractAddr as ContractAddr, msg: Buffer.from(msg), funds: [], }); @@ -96,7 +96,7 @@ export const ExecuteArea = ({ return () => clearTimeout(timeoutId); } return () => {}; - }, [address, contractAddress, enableExecute, msg]); + }, [address, contractAddr, enableExecute, msg]); useEffect(() => { const keydownHandler = (e: KeyboardEvent) => { @@ -135,7 +135,7 @@ export const ExecuteArea = ({ ))} ) : ( - contractAddress && ( + contractAddr && ( No ExecuteMsgs suggestion available diff --git a/src/lib/pages/execute/index.tsx b/src/lib/pages/execute/index.tsx index 8a51b7a9e..b4c74bb29 100644 --- a/src/lib/pages/execute/index.tsx +++ b/src/lib/pages/execute/index.tsx @@ -31,7 +31,7 @@ const Execute = () => { const { address = "" } = useWallet(); const endpoint = useEndpoint(); - const [contractAddress, setContractAddress] = useState(""); + const [contractAddr, setContractAddr] = useState(""); const [contractName, setContractName] = useState(""); const [initialMsg, setInitialMsg] = useState(""); const [cmds, setCmds] = useState<[string, string][]>([]); @@ -39,7 +39,7 @@ const Execute = () => { const goToQuery = () => { router.push({ pathname: "/query", - query: { ...(contractAddress && { contract: contractAddress }) }, + query: { ...(contractAddr && { contract: contractAddr }) }, }); }; const onContractSelect = useCallback( @@ -57,18 +57,18 @@ const Execute = () => { ); const { isFetching } = useSimulateFeeQuery({ - enabled: !!contractAddress, + enabled: !!contractAddr, messages: [ composeMsg(MsgType.EXECUTE, { sender: address as HumanAddr, - contract: contractAddress as ContractAddr, + contract: contractAddr as ContractAddr, msg: Buffer.from('{"": {}}'), funds: [], }), ], onError: (e) => { if (e.message.includes("contract: ")) { - setContractAddress(""); + setContractAddr(""); setCmds([]); } else { const executeCmds: string[] = []; @@ -82,18 +82,20 @@ const Execute = () => { useEffect(() => { (async () => { - const contractAddr = getFirstQueryParam(router.query.contract); - const contractState = getContractInfo(contractAddr); + const contractAddress = getFirstQueryParam( + router.query.contract + ) as ContractAddr; + const contractState = getContractInfo(contractAddress); let decodeMsg = decode(getFirstQueryParam(router.query.msg)); if (decodeMsg && jsonValidate(decodeMsg) !== null) { - onContractSelect(contractAddr); + onContractSelect(contractAddress); decodeMsg = ""; } const jsonMsg = jsonPrettify(decodeMsg); if (!contractState) { try { - const onChainDetail = await queryContract(endpoint, contractAddr); + const onChainDetail = await queryContract(endpoint, contractAddress); setContractName(onChainDetail.contract_info.label); } catch { setContractName("Invalid Contract"); @@ -102,13 +104,13 @@ const Execute = () => { setContractName(contractState.name ?? contractState.label); } - setContractAddress(contractAddr); + setContractAddr(contractAddress); setInitialMsg(jsonMsg); - if (!contractAddr) setCmds([]); + if (!contractAddress) setCmds([]); })(); }, [router, endpoint, getContractInfo, onContractSelect]); - const notSelected = contractAddress.length === 0; + const notSelected = contractAddr.length === 0; return ( @@ -149,7 +151,7 @@ const Execute = () => { Contract Address {!notSelected ? ( { diff --git a/src/lib/pages/query/components/QueryArea.tsx b/src/lib/pages/query/components/QueryArea.tsx index 2f02b1665..afcd34226 100644 --- a/src/lib/pages/query/components/QueryArea.tsx +++ b/src/lib/pages/query/components/QueryArea.tsx @@ -11,19 +11,19 @@ import JsonInput from "lib/components/Json/JsonInput"; import { DEFAULT_RPC_ERROR } from "lib/data"; import { useContractStore, useEndpoint, useUserKey } from "lib/hooks"; import { queryData } from "lib/services/contract"; -import type { RpcQueryError } from "lib/types"; +import type { ContractAddr, RpcQueryError } from "lib/types"; import { encode, jsonPrettify, jsonValidate } from "lib/utils"; import JsonReadOnly from "./JsonReadOnly"; interface QueryAreaProps { - contractAddress: string; + contractAddr: ContractAddr; initialMsg: string; cmds: [string, string][]; } export const QueryArea = ({ - contractAddress, + contractAddr, initialMsg, cmds, }: QueryAreaProps) => { @@ -37,8 +37,8 @@ export const QueryArea = ({ // TODO: Abstract query const { refetch, isFetching, isRefetching } = useQuery( - ["query", endpoint, contractAddress, msg], - async () => queryData(endpoint, contractAddress, msg), + ["query", endpoint, contractAddr, msg], + async () => queryData(endpoint, contractAddr, msg), { enabled: false, retry: false, @@ -52,7 +52,7 @@ export const QueryArea = ({ type: "query", action: Object.keys(JSON.parse(msg))[0] ?? "Unknown", sender: address, - contractAddress, + contractAddr, msg: encode(msg), timestamp: new Date(), }); @@ -103,7 +103,7 @@ export const QueryArea = ({ ))} ) : ( - contractAddress && ( + contractAddr && ( No QueryMsgs suggestion available diff --git a/src/lib/pages/query/index.tsx b/src/lib/pages/query/index.tsx index a09410f45..cc96ea586 100644 --- a/src/lib/pages/query/index.tsx +++ b/src/lib/pages/query/index.tsx @@ -11,7 +11,7 @@ import { SelectContract } from "lib/components/modal/select-contract"; import PageContainer from "lib/components/PageContainer"; import { useContractStore, useEndpoint, useMobile } from "lib/hooks"; import { queryContract, queryData } from "lib/services/contract"; -import type { RpcQueryError } from "lib/types"; +import type { ContractAddr, RpcQueryError } from "lib/types"; import { jsonPrettify, getFirstQueryParam, @@ -27,15 +27,15 @@ const Query = () => { const endpoint = useEndpoint(); const isMobile = useMobile(); - const [addr, setAddr] = useState(""); - const [name, setName] = useState(""); + const [contractAddr, setContractAddr] = useState(""); + const [contractName, setContractName] = useState(""); + const [initialMsg, setInitialMsg] = useState(""); const [cmds, setCmds] = useState<[string, string][]>([]); - const [initialMsg, setInitialMsg] = useState(""); const goToExecute = () => { router.push({ pathname: "/execute", - query: { ...(addr && { contract: addr }) }, + query: { ...(contractAddr && { contract: contractAddr }) }, }); }; @@ -55,10 +55,10 @@ const Query = () => { // TODO: Abstract query and make query key const { isFetching } = useQuery( - ["query", "cmds", endpoint, addr, '{"": {}}'], - async () => queryData(endpoint, addr, '{"": {}}'), + ["query", "cmds", endpoint, contractAddr, '{"": {}}'], + async () => queryData(endpoint, contractAddr as ContractAddr, '{"": {}}'), { - enabled: !!addr, + enabled: !!contractAddr, retry: false, cacheTime: 0, refetchOnWindowFocus: false, @@ -74,33 +74,35 @@ const Query = () => { useEffect(() => { (async () => { - const contractAddr = getFirstQueryParam(router.query.contract); - const contractState = getContractInfo(contractAddr); + const contractAddress = getFirstQueryParam( + router.query.contract + ) as ContractAddr; + const contractState = getContractInfo(contractAddress); let decodeMsg = decode(getFirstQueryParam(router.query.msg)); if (decodeMsg && jsonValidate(decodeMsg) !== null) { - onContractSelect(contractAddr); + onContractSelect(contractAddress); decodeMsg = ""; } const jsonMsg = jsonPrettify(decodeMsg); if (!contractState) { try { - const onChainDetail = await queryContract(endpoint, contractAddr); - setName(onChainDetail.contract_info.label); + const onChainDetail = await queryContract(endpoint, contractAddress); + setContractName(onChainDetail.contract_info.label); } catch { - setName("Invalid Contract"); + setContractName("Invalid Contract"); } } else { - setName(contractState.name ?? contractState.label); + setContractName(contractState.name ?? contractState.label); } - setAddr(contractAddr); + setContractAddr(contractAddress); setInitialMsg(jsonMsg); - if (!contractAddr) setCmds([]); + if (!contractAddress) setCmds([]); })(); }, [router, endpoint, getContractInfo, onContractSelect]); - const notSelected = addr.length === 0; + const notSelected = contractAddr.length === 0; return ( @@ -139,7 +141,7 @@ const Query = () => { Contract Address {!notSelected ? ( { textColor={notSelected ? "text.disabled" : "text.dark"} variant="body2" > - {notSelected ? "Not Selected" : name} + {notSelected ? "Not Selected" : contractName} @@ -168,7 +170,11 @@ const Query = () => { /> - + ); }; diff --git a/src/lib/services/code.ts b/src/lib/services/code.ts index bdbebbe48..b59d19a63 100644 --- a/src/lib/services/code.ts +++ b/src/lib/services/code.ts @@ -1,6 +1,25 @@ import axios from "axios"; -export const getCodeIdInfo = async (endpoint: string, id: number) => { - const { data } = await axios.get(`${endpoint}/cosmwasm/wasm/v1/code/${id}`); +interface CodeIdInfoResponse { + code_info: { + code_id: string; + creator: string; + data_hash: string; + instantiate_permission: { + permission: string; + address: string; + addresses: string[]; + }; + }; + data: string; +} + +export const getCodeIdInfo = async ( + endpoint: string, + id: number +): Promise => { + const { data } = await axios.get( + `${endpoint}/cosmwasm/wasm/v1/code/${id}` + ); return data; }; diff --git a/src/lib/services/contract.ts b/src/lib/services/contract.ts index c752b6392..0e95f3a13 100644 --- a/src/lib/services/contract.ts +++ b/src/lib/services/contract.ts @@ -1,10 +1,11 @@ import type { Coin } from "@cosmjs/stargate"; import axios from "axios"; +import type { ContractAddr } from "lib/types"; import { encode } from "lib/utils"; interface ContractResponse { - address: string; + address: ContractAddr; contract_info: { code_id: string; creator: string; @@ -32,7 +33,7 @@ interface BalancesResponse { } export interface InstantiateInfo { - address: string; + address: ContractAddr; codeId: string; instantiator: string; admin: string; @@ -46,34 +47,37 @@ export interface InstantiateInfo { export interface PublicInfo { slug: string; name: string; - address: string; + address: ContractAddr; description: string; } export const queryData = async ( endpoint: string, - contract: string, + contractAddr: ContractAddr, msg: string ) => { const b64 = encode(msg); const { data } = await axios.get( - `${endpoint}/cosmwasm/wasm/v1/contract/${contract}/smart/${b64}` + `${endpoint}/cosmwasm/wasm/v1/contract/${contractAddr}/smart/${b64}` ); return data; }; -export const queryContract = async (endpoint: string, contract: string) => { +export const queryContract = async ( + endpoint: string, + contractAddr: ContractAddr +) => { const { data } = await axios.get( - `${endpoint}/cosmwasm/wasm/v1/contract/${contract}` + `${endpoint}/cosmwasm/wasm/v1/contract/${contractAddr}` ); return data; }; export const queryInstantiateInfo = async ( endpoint: string, - contract: string + contractAddr: ContractAddr ): Promise => { - const res = await queryContract(endpoint, contract); + const res = await queryContract(endpoint, contractAddr); // TODO: check `created` field for contracts created with proposals let createdHeight; @@ -105,22 +109,23 @@ export const queryInstantiateInfo = async ( export const queryContractBalances = async ( endpoint: string, - contract: string + contractAddr: ContractAddr ) => { const { data } = await axios.get( - `${endpoint}/cosmos/bank/v1beta1/balances/${contract}?pagination.limit=0` + `${endpoint}/cosmos/bank/v1beta1/balances/${contractAddr}?pagination.limit=0` ); return data; }; export const queryPublicInfo = async ( - chainName: string, - chainId: string, - contract: string + chainName: string | undefined, + chainId: string | undefined, + contractAddr: ContractAddr ): Promise => { + if (!chainName || !chainId) return undefined; return axios .get( `https://cosmos-registry.alleslabs.dev/data/${chainName}/${chainId}/contracts.json` ) - .then(({ data }) => data.find((info) => info.address === contract)); + .then(({ data }) => data.find((info) => info.address === contractAddr)); }; diff --git a/src/lib/services/contractService.ts b/src/lib/services/contractService.ts index d6bffa783..abfc3569a 100644 --- a/src/lib/services/contractService.ts +++ b/src/lib/services/contractService.ts @@ -9,6 +9,7 @@ import { getInstantiateDetailByContractQueryDocument, } from "lib/data/queries"; import type { ContractInfo } from "lib/stores/contract"; +import type { ContractAddr, HumanAddr } from "lib/types"; interface InstantiateDetail { initMsg: string; @@ -16,7 +17,7 @@ interface InstantiateDetail { } export const useInstantiatedCountByUserQuery = ( - walletAddr: string | undefined + walletAddr: HumanAddr | undefined ): UseQueryResult => { const queryFn = useCallback(async () => { if (!walletAddr) return undefined; @@ -36,7 +37,7 @@ export const useInstantiatedCountByUserQuery = ( }; export const useInstantiatedListByUserQuery = ( - walletAddr: string | undefined + walletAddr: HumanAddr | undefined ): UseQueryResult => { const queryFn = useCallback(async () => { if (!walletAddr) return undefined; @@ -63,7 +64,7 @@ export const useInstantiatedListByUserQuery = ( }; export const useInstantiateDetailByContractQuery = ( - contractAddr: string + contractAddr: ContractAddr ): UseQueryResult => { const queryFn = useCallback(async () => { return indexerGraphClient diff --git a/src/lib/stores/contract.ts b/src/lib/stores/contract.ts index d8ae85eef..d2f571714 100644 --- a/src/lib/stores/contract.ts +++ b/src/lib/stores/contract.ts @@ -2,7 +2,7 @@ import { makeAutoObservable } from "mobx"; import { isHydrated, makePersistable } from "mobx-persist-store"; import { INSTANTIATED_LIST_NAME, SAVED_LIST_NAME } from "lib/data"; -import type { Option, Dict } from "lib/types"; +import type { Option, Dict, ContractAddr } from "lib/types"; import { formatSlugName } from "lib/utils"; export interface ContractInfo { @@ -47,7 +47,7 @@ export interface Activity { type: "query" | "execute"; action: string; sender: string | undefined; - contractAddress: string; + contractAddr: ContractAddr; msg: string; // base64 timestamp: Date; } From 46faf0e091525886f4cfb99f4f7b5f85da2d4b57 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 23 Dec 2022 14:56:50 +0700 Subject: [PATCH 3/5] fix: txhash parser --- src/lib/services/contractService.ts | 3 ++- src/lib/utils/parser.ts | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 src/lib/utils/parser.ts diff --git a/src/lib/services/contractService.ts b/src/lib/services/contractService.ts index abfc3569a..1dadcc10c 100644 --- a/src/lib/services/contractService.ts +++ b/src/lib/services/contractService.ts @@ -10,6 +10,7 @@ import { } from "lib/data/queries"; import type { ContractInfo } from "lib/stores/contract"; import type { ContractAddr, HumanAddr } from "lib/types"; +import { parseTxHash } from "lib/utils/parser"; interface InstantiateDetail { initMsg: string; @@ -74,7 +75,7 @@ export const useInstantiateDetailByContractQuery = ( .map((contract) => ({ // TODO: revisit undefined after backend remove nullable initMsg: contract.init_msg ?? "{}", - initTxHash: (contract.transaction?.hash as string).substring(2), + initTxHash: parseTxHash(contract.transaction?.hash), })) ?.at(0) ); diff --git a/src/lib/utils/parser.ts b/src/lib/utils/parser.ts new file mode 100644 index 000000000..12c7eb24f --- /dev/null +++ b/src/lib/utils/parser.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const parseTxHash = (txHash: any) => (txHash as string).substring(2); From 24115405a23777f01403ae1e95d34b9d13f4635a Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 23 Dec 2022 15:52:20 +0700 Subject: [PATCH 4/5] fix: rename contractAddress variables --- src/env.ts | 2 +- src/lib/app-fns/tx/execute.tsx | 8 +-- src/lib/app-provider/contexts/app.tsx | 32 +++++------ src/lib/app-provider/tx/execute.ts | 6 +- .../components/InstantiateOffchainDetail.tsx | 3 +- src/lib/components/modal/EditTags.tsx | 2 +- .../modal/contract/AddToOtherList.tsx | 2 +- .../modal/contract/EditContract.tsx | 2 +- .../modal/contract/RemoveContract.tsx | 2 +- .../modal/contract/SaveNewContract.tsx | 4 +- .../modal/select-contract/SelectContract.tsx | 6 +- src/lib/data/queries.ts | 4 +- src/lib/gql/gql.ts | 6 +- src/lib/gql/graphql.ts | 6 +- src/lib/hooks/useHandleSave.tsx | 8 +-- src/lib/model/contract.ts | 20 +++---- .../components/table/ContractNameCell.tsx | 2 +- .../pages/execute/components/ExecuteArea.tsx | 16 +++--- src/lib/pages/execute/index.tsx | 31 ++++++----- .../home/components/RecentlyViewContracts.tsx | 9 +-- src/lib/pages/instantiate/completed.tsx | 3 +- .../pages/pastTxs/components/PastTxTable.tsx | 4 +- src/lib/pages/pastTxs/query/graphqlQuery.ts | 6 +- src/lib/pages/pastTxs/query/useTxQuery.ts | 2 +- src/lib/pages/query/components/QueryArea.tsx | 12 ++-- src/lib/pages/query/index.tsx | 32 ++++++----- src/lib/services/contract.ts | 20 +++---- src/lib/services/contractService.ts | 18 +++--- src/lib/stores/contract.ts | 55 ++++++++++--------- src/pages/_app.tsx | 4 +- 30 files changed, 174 insertions(+), 153 deletions(-) diff --git a/src/env.ts b/src/env.ts index 8d90c643c..87e400b31 100644 --- a/src/env.ts +++ b/src/env.ts @@ -13,7 +13,7 @@ export const CELATONE_FALLBACK_GAS_PRICE: Record = { }, }; -export const CELATONE_CONTRACT_ADDRESS = ( +export const CELATONE_APP_CONTRACT_ADDRESS = ( chainName: string ): CelatoneContractAddress => { switch (chainName) { diff --git a/src/lib/app-fns/tx/execute.tsx b/src/lib/app-fns/tx/execute.tsx index e28b6a474..339b27f8e 100644 --- a/src/lib/app-fns/tx/execute.tsx +++ b/src/lib/app-fns/tx/execute.tsx @@ -18,7 +18,7 @@ import { catchTxError, postTx, sendingTx } from "./common"; interface ExecuteTxParams { address: string; - contractAddr: ContractAddr; + contractAddress: ContractAddr; fee: StdFee; msg: object; client: SigningCosmWasmClient; @@ -29,7 +29,7 @@ interface ExecuteTxParams { export const executeContractTx = ({ address, - contractAddr, + contractAddress, fee, msg, client, @@ -40,14 +40,14 @@ export const executeContractTx = ({ return pipe( sendingTx(fee), postTx({ - postFn: () => client.execute(address, contractAddr, msg, fee), + postFn: () => client.execute(address, contractAddress, msg, fee), }), ({ value: txInfo }) => { onTxSucceed?.(userKey, { type: "execute", action: Object.keys(msg)[0], sender: address, - contractAddr, + contractAddress, msg: encode(JSON.stringify(msg)), // base64 timestamp: new Date(), }); diff --git a/src/lib/app-provider/contexts/app.tsx b/src/lib/app-provider/contexts/app.tsx index 1b443b5dc..b53c8cc47 100644 --- a/src/lib/app-provider/contexts/app.tsx +++ b/src/lib/app-provider/contexts/app.tsx @@ -21,12 +21,12 @@ import { useCodeStore, useContractStore } from "lib/hooks"; import type { ChainGasPrice, Token, U } from "lib/types"; import { formatUserKey } from "lib/utils"; -interface AppProviderProps { +interface AppProviderProps { children: ReactNode; fallbackGasPrice: Record; - contractAddress: (currentChainName: string) => ContractAddress; + appContractAddressMap: (currentChainName: string) => AppContractAddress; constants: Constants; } @@ -36,12 +36,12 @@ interface AppContextInterface< Constants extends AppConstants = AppConstants > { chainGasPrice: ChainGasPrice; - contractAddress: ContractAddress; + appContractAddress: ContractAddress; constants: Constants; explorerLink: { - contractAddr: string; - txs: string; - address: string; + contractUrl: string; + txUrl: string; + userUrl: string; }; indexerGraphClient: GraphQLClient; } @@ -49,12 +49,12 @@ interface AppContextInterface< // eslint-disable-next-line @typescript-eslint/no-explicit-any const AppContext = createContext>({ chainGasPrice: { denom: "", gasPrice: "0" as U }, - contractAddress: {}, + appContractAddress: {}, constants: { gasAdjustment: 0 }, explorerLink: { - contractAddr: "", - txs: "", - address: "", + contractUrl: "", + txUrl: "", + userUrl: "", }, indexerGraphClient: new GraphQLClient(""), }); @@ -62,7 +62,7 @@ const AppContext = createContext>({ export const AppProvider = ({ children, fallbackGasPrice, - contractAddress, + appContractAddressMap, constants, }: AppProviderProps) => { const { currentChainName, currentChainRecord, setCurrentChain } = useWallet(); @@ -87,9 +87,9 @@ export const AppProvider = ({ const chainBoundStates = useMemo(() => { return { explorerLink: { - contractAddr: getExplorerContractAddressUrl(currentChainName), - txs: getExplorerTxUrl(currentChainName), - address: getExplorerUserAddressUrl(currentChainName), + contractUrl: getExplorerContractAddressUrl(currentChainName), + txUrl: getExplorerTxUrl(currentChainName), + userUrl: getExplorerUserAddressUrl(currentChainName), }, indexerGraphClient: getIndexerGraphClient(currentChainName), }; @@ -98,13 +98,13 @@ export const AppProvider = ({ const states = useMemo>( () => ({ chainGasPrice, - contractAddress: contractAddress(currentChainName), + appContractAddress: appContractAddressMap(currentChainName), constants, ...chainBoundStates, }), [ chainGasPrice, - contractAddress, + appContractAddressMap, currentChainName, constants, chainBoundStates, diff --git a/src/lib/app-provider/tx/execute.ts b/src/lib/app-provider/tx/execute.ts index 3f246e9a9..d34ac1bb6 100644 --- a/src/lib/app-provider/tx/execute.ts +++ b/src/lib/app-provider/tx/execute.ts @@ -11,7 +11,7 @@ export interface ExecuteStreamParams { onTxSucceed?: (userKey: string, activity: Activity) => void; onTxFailed?: () => void; estimatedFee: StdFee | undefined; - contractAddr: ContractAddr; + contractAddress: ContractAddr; msg: object; } @@ -24,7 +24,7 @@ export const useExecuteContractTx = () => { onTxSucceed, onTxFailed, estimatedFee, - contractAddr, + contractAddress, msg, }: ExecuteStreamParams) => { const client = await getCosmWasmClient(); @@ -34,7 +34,7 @@ export const useExecuteContractTx = () => { return executeContractTx({ address, - contractAddr, + contractAddress, fee: estimatedFee, msg, client, diff --git a/src/lib/components/InstantiateOffchainDetail.tsx b/src/lib/components/InstantiateOffchainDetail.tsx index 04ec81485..6e258c461 100644 --- a/src/lib/components/InstantiateOffchainDetail.tsx +++ b/src/lib/components/InstantiateOffchainDetail.tsx @@ -14,6 +14,7 @@ import { } from "lib/data"; import { useContractStore } from "lib/hooks"; import { useUserKey } from "lib/hooks/useUserKey"; +import type { ContractAddr } from "lib/types"; import { ListSelection } from "./forms/ListSelection"; import { TagSelection } from "./forms/TagSelection"; @@ -22,7 +23,7 @@ interface InstantiateOffChainFormProps { title?: string; subtitle?: string; cta?: boolean; - contractAddress: string; + contractAddress: ContractAddr; contractLabel: string; } diff --git a/src/lib/components/modal/EditTags.tsx b/src/lib/components/modal/EditTags.tsx index 43b306dbd..36ea6008e 100644 --- a/src/lib/components/modal/EditTags.tsx +++ b/src/lib/components/modal/EditTags.tsx @@ -19,7 +19,7 @@ export function EditTags({ contractInfo }: EditTagsProps) { const [tagResult, setTagResult] = useState(contractInfo.tags ?? []); const handleSave = useHandleContractSave({ title: "Updated tags successfully!", - address: contractInfo.address, + contractAddress: contractInfo.address, instantiator: contractInfo.instantiator, label: contractInfo.label, created: contractInfo.created, diff --git a/src/lib/components/modal/contract/AddToOtherList.tsx b/src/lib/components/modal/contract/AddToOtherList.tsx index b2be7ede4..15a20fafe 100644 --- a/src/lib/components/modal/contract/AddToOtherList.tsx +++ b/src/lib/components/modal/contract/AddToOtherList.tsx @@ -25,7 +25,7 @@ export function AddToOtherList({ const handleSave = useHandleContractSave({ title: "Action complete!", - address: contractInfo.address, + contractAddress: contractInfo.address, instantiator: contractInfo.instantiator, label: contractInfo.label, created: contractInfo.created, diff --git a/src/lib/components/modal/contract/EditContract.tsx b/src/lib/components/modal/contract/EditContract.tsx index 82ab15329..3ceb2f549 100644 --- a/src/lib/components/modal/contract/EditContract.tsx +++ b/src/lib/components/modal/contract/EditContract.tsx @@ -34,7 +34,7 @@ export const EditContract = ({ contractInfo, menuItemProps }: ModalProps) => { const handleSave = useHandleContractSave({ title: "Action Complete", - address: contractInfo.address, + contractAddress: contractInfo.address, instantiator: contractInfo.instantiator, label: contractInfo.label, created: contractInfo.created, diff --git a/src/lib/components/modal/contract/RemoveContract.tsx b/src/lib/components/modal/contract/RemoveContract.tsx index 85f7ac746..ae7916af6 100644 --- a/src/lib/components/modal/contract/RemoveContract.tsx +++ b/src/lib/components/modal/contract/RemoveContract.tsx @@ -25,7 +25,7 @@ export function RemoveContract({ const handleRemove = useHandleContractSave({ title: `Removed ${displayName} from ${list.label}`, - address: contractInfo.address, + contractAddress: contractInfo.address, instantiator: contractInfo.instantiator, label: contractInfo.label, created: contractInfo.created, diff --git a/src/lib/components/modal/contract/SaveNewContract.tsx b/src/lib/components/modal/contract/SaveNewContract.tsx index a24ab4227..8d07f4247 100644 --- a/src/lib/components/modal/contract/SaveNewContract.tsx +++ b/src/lib/components/modal/contract/SaveNewContract.tsx @@ -28,7 +28,7 @@ interface SaveNewContractProps { } export function SaveNewContract({ list, buttonProps }: SaveNewContractProps) { const { - contractAddress: { example: exampleContractAddress }, + appContractAddress: { example: exampleContractAddress }, } = useCelatoneApp(); const initialList = list.value === formatSlugName(INSTANTIATED_LIST_NAME) ? [] : [list]; @@ -121,7 +121,7 @@ export function SaveNewContract({ list, buttonProps }: SaveNewContractProps) { const handleSave = useHandleContractSave({ title: `Saved ${name.trim().length ? name : label}`, - address: contractAddress, + contractAddress: contractAddress as ContractAddr, instantiator, label, created, diff --git a/src/lib/components/modal/select-contract/SelectContract.tsx b/src/lib/components/modal/select-contract/SelectContract.tsx index 7ecec2a89..843b184b6 100644 --- a/src/lib/components/modal/select-contract/SelectContract.tsx +++ b/src/lib/components/modal/select-contract/SelectContract.tsx @@ -39,7 +39,9 @@ export const SelectContract = ({ notSelected, onContractSelect, }: SelectContractProps) => { - const { contractAddress } = useCelatoneApp(); + const { + appContractAddress: { example: exampleContractAddress }, + } = useCelatoneApp(); const { isOpen, onOpen, onClose } = useDisclosure(); const [listSlug, setListSlug] = useState(""); @@ -124,7 +126,7 @@ export const SelectContract = ({ const inputValue = e.target.value; setSearchManual(inputValue); }} - placeholder={`ex. ${contractAddress.example}`} + placeholder={`ex. ${exampleContractAddress}`} size="md" /> - + diff --git a/src/lib/pages/contracts/components/table/ContractNameCell.tsx b/src/lib/pages/contracts/components/table/ContractNameCell.tsx index 9e033df08..4e92dd1d2 100644 --- a/src/lib/pages/contracts/components/table/ContractNameCell.tsx +++ b/src/lib/pages/contracts/components/table/ContractNameCell.tsx @@ -14,7 +14,7 @@ export const ContractNameCell = ({ }: ContractNameCellProps) => { const onSave = useHandleContractSave({ title: "Changed name successfully!", - contractAddress: contract.address, + contractAddress: contract.contractAddress, instantiator: contract.instantiator, label: contract.label, created: contract.created, diff --git a/src/lib/pages/home/components/RecentlyViewContracts.tsx b/src/lib/pages/home/components/RecentlyViewContracts.tsx index 1937fab09..99a14cdfe 100644 --- a/src/lib/pages/home/components/RecentlyViewContracts.tsx +++ b/src/lib/pages/home/components/RecentlyViewContracts.tsx @@ -6,7 +6,8 @@ import type { ContractAddr } from "lib/types"; /* TODO: change data -> recently view contracts */ const contracts = [ { - address: "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq" as ContractAddr, + contractAddress: + "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq" as ContractAddr, name: "Deposit asset", tags: ["deposit", "lending"], instantiator: "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq", @@ -16,7 +17,8 @@ const contracts = [ created: new Date(), }, { - address: "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq" as ContractAddr, + contractAddress: + "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq" as ContractAddr, name: "Borrow asset", tags: ["deposit", "lending", "borrow", "beeb", "margin"], instantiator: "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq", @@ -25,7 +27,8 @@ const contracts = [ created: new Date(), }, { - address: "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq" as ContractAddr, + contractAddress: + "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq" as ContractAddr, name: "", tags: ["deposit", "lending", "borrow", "margin"], instantiator: "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq", @@ -34,7 +37,8 @@ const contracts = [ created: new Date(), }, { - address: "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq" as ContractAddr, + contractAddress: + "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq" as ContractAddr, name: "Deposit asset to Lorem", tags: [], instantiator: "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq", diff --git a/src/lib/pages/query/index.tsx b/src/lib/pages/query/index.tsx index a4620811e..49c865d27 100644 --- a/src/lib/pages/query/index.tsx +++ b/src/lib/pages/query/index.tsx @@ -27,9 +27,9 @@ const Query = () => { const endpoint = useEndpoint(); const isMobile = useMobile(); - const [contractAddress, setContractAddress] = useState(""); - const [contractName, setContractName] = useState(""); - const [initialMsg, setInitialMsg] = useState(""); + const [contractAddress, setContractAddress] = useState(""); + const [contractName, setContractName] = useState(""); + const [initialMsg, setInitialMsg] = useState(""); const [cmds, setCmds] = useState<[string, string][]>([]); const goToExecute = () => { diff --git a/src/lib/services/code.ts b/src/lib/services/code.ts index b59d19a63..762f6663c 100644 --- a/src/lib/services/code.ts +++ b/src/lib/services/code.ts @@ -1,9 +1,11 @@ import axios from "axios"; +import type { ContractAddr, HumanAddr } from "lib/types"; + interface CodeIdInfoResponse { code_info: { code_id: string; - creator: string; + creator: HumanAddr | ContractAddr; data_hash: string; instantiate_permission: { permission: string; diff --git a/src/lib/services/contract.ts b/src/lib/services/contract.ts index 40e8b7bd2..2424fff7f 100644 --- a/src/lib/services/contract.ts +++ b/src/lib/services/contract.ts @@ -1,22 +1,22 @@ import type { Coin } from "@cosmjs/stargate"; import axios from "axios"; -import type { ContractAddr } from "lib/types"; +import type { ContractAddr, HumanAddr } from "lib/types"; import { encode } from "lib/utils"; interface ContractResponse { address: ContractAddr; contract_info: { code_id: string; - creator: string; - admin: string; + creator: HumanAddr | ContractAddr; + admin?: HumanAddr | ContractAddr; label: string; created?: { block_height: number; tx_index: number; }; ibc_port_id: string; - extension: string; + extension?: string; }; } @@ -32,11 +32,18 @@ interface BalancesResponse { balances: Coin[]; } -export interface InstantiateInfo { +interface PublicInfoResponse { + slug: string; + name: string; address: ContractAddr; + description: string; +} + +export interface InstantiateInfo { + contractAddress: ContractAddr; codeId: string; - instantiator: string; - admin: string; + instantiator: HumanAddr | ContractAddr; + admin?: HumanAddr | ContractAddr; label: string; createdHeight: number; createdTime: Date; @@ -47,7 +54,7 @@ export interface InstantiateInfo { export interface PublicInfo { slug: string; name: string; - address: ContractAddr; + contractAddress: ContractAddr; description: string; } @@ -95,7 +102,7 @@ export const queryInstantiateInfo = async ( } return { - address: res.address, + contractAddress: res.address, codeId: res.contract_info.code_id, instantiator: res.contract_info.creator, admin: res.contract_info.admin, @@ -124,8 +131,13 @@ export const queryPublicInfo = async ( ): Promise => { if (!chainName || !chainId) return undefined; return axios - .get( + .get( `https://cosmos-registry.alleslabs.dev/data/${chainName}/${chainId}/contracts.json` ) - .then(({ data }) => data.find((info) => info.address === contractAddress)); + .then(({ data }) => { + const publicInfo = data.find((info) => info.address === contractAddress); + return publicInfo + ? { ...publicInfo, contractAddress: publicInfo.address } + : undefined; + }); }; diff --git a/src/lib/services/contractService.ts b/src/lib/services/contractService.ts index 4aa01c7ee..397387133 100644 --- a/src/lib/services/contractService.ts +++ b/src/lib/services/contractService.ts @@ -49,7 +49,7 @@ export const useInstantiatedListByUserQuery = ( }) .then(({ contracts }) => contracts.map((contract) => ({ - address: contract.address as ContractAddr, + contractAddress: contract.address as ContractAddr, instantiator: walletAddr, label: contract.label, created: new Date(`${contract.transaction?.block?.timestamp}Z`), @@ -70,15 +70,11 @@ export const useInstantiateDetailByContractQuery = ( const queryFn = useCallback(async () => { return indexerGraphClient .request(getInstantiateDetailByContractQueryDocument, { contractAddress }) - .then(({ contracts }) => - contracts - .map((contract) => ({ - // TODO: revisit undefined after backend remove nullable - initMsg: contract.init_msg ?? "{}", - initTxHash: parseTxHash(contract.transaction?.hash), - })) - ?.at(0) - ); + .then(({ contracts_by_pk }) => ({ + // TODO: revisit undefined after backend remove nullable + initMsg: contracts_by_pk?.init_msg ?? "{}", + initTxHash: parseTxHash(contracts_by_pk?.transaction?.hash), + })); }, [contractAddress]); return useQuery( diff --git a/src/lib/stores/contract.ts b/src/lib/stores/contract.ts index 6110373e7..f54ad0c20 100644 --- a/src/lib/stores/contract.ts +++ b/src/lib/stores/contract.ts @@ -6,7 +6,7 @@ import type { Option, Dict, ContractAddr } from "lib/types"; import { formatSlugName } from "lib/utils"; export interface ContractInfo { - address: ContractAddr; + contractAddress: ContractAddr; instantiator: string; label: string; created: Date; @@ -130,7 +130,7 @@ export class ContractStore { contracts: contractListInfo.contracts.map((contractAddress) => { if (!contractInfoByUserKey) return { - address: contractAddress, + contractAddress, instantiator: "TODO", label: "TODO", created: new Date(0), @@ -239,7 +239,7 @@ export class ContractStore { lists?: Option[] ) { const contractInfo = this.contractInfo[userKey]?.[contractAddress] ?? { - address: contractAddress, + contractAddress, instantiator, label, created,