diff --git a/CHANGELOG.md b/CHANGELOG.md index b02c2afce..6155c3313 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 +- [#544](https://github.com/alleslabs/celatone-frontend/pull/544) Show module source code if available - [#534](https://github.com/alleslabs/celatone-frontend/pull/534) Wire up initia execute function - [#533](https://github.com/alleslabs/celatone-frontend/pull/533) Wire up initia view function - [#536](https://github.com/alleslabs/celatone-frontend/pull/536) Add publish module validation and decode query diff --git a/src/lib/components/module/ModuleSourceCode.tsx b/src/lib/components/module/ModuleSourceCode.tsx new file mode 100644 index 000000000..718d1cf09 --- /dev/null +++ b/src/lib/components/module/ModuleSourceCode.tsx @@ -0,0 +1,80 @@ +import { + Accordion, + AccordionButton, + AccordionIcon, + AccordionItem, + AccordionPanel, + Box, + Flex, + Text, +} from "@chakra-ui/react"; +import dynamic from "next/dynamic"; + +import { CopyButton } from "../copy"; +import { CURR_THEME } from "env"; +import type { Option } from "lib/types"; + +const AceEditor = dynamic(() => import("react-ace"), { + ssr: false, +}); + +interface ModuleSourceCodeProps { + sourceCode: Option; +} +export const ModuleSourceCode = ({ sourceCode }: ModuleSourceCodeProps) => { + if (!sourceCode) return null; + return ( + + + + + + + Module Source Code + + + The source code is uploaded by the deployer and pulled from + Initia API + + + + + + + + + + + + + + + + ); +}; diff --git a/src/lib/components/module/index.ts b/src/lib/components/module/index.ts index e4d9b173a..5b95371fb 100644 --- a/src/lib/components/module/index.ts +++ b/src/lib/components/module/index.ts @@ -1,3 +1,4 @@ export * from "./CountBadge"; export * from "./FunctionCard"; export * from "./ModuleCard"; +export * from "./ModuleSourceCode"; diff --git a/src/lib/pages/interaction/index.tsx b/src/lib/pages/interaction/index.tsx index 3499961e4..2738965c7 100644 --- a/src/lib/pages/interaction/index.tsx +++ b/src/lib/pages/interaction/index.tsx @@ -5,15 +5,17 @@ import { Flex, Heading, Text, + Box, } from "@chakra-ui/react"; import { useCallback, useState } from "react"; import { CustomIcon } from "lib/components/icon"; import { LabelText } from "lib/components/LabelText"; +import { ModuleSourceCode } from "lib/components/module"; import PageContainer from "lib/components/PageContainer"; import type { IndexedModule } from "lib/services/moduleService"; -import type { ExposedFunction } from "lib/types"; -import { parseJsonABI } from "lib/utils"; +import { useVerifyModule } from "lib/services/moduleService"; +import type { ExposedFunction, HexAddr, Option } from "lib/types"; import { ModuleSelectDrawerTrigger, @@ -28,8 +30,6 @@ export const Interaction = () => { const [module, setModule] = useState(); const [selectedFn, setSelectedFn] = useState(); - const abi = module ? parseJsonABI(module.abi) : undefined; - const handleModuleSelect = useCallback( (selectedModule: IndexedModule, fn?: ExposedFunction) => { setModule(selectedModule); @@ -38,93 +38,110 @@ export const Interaction = () => { [] ); + const { data: verificationData } = useVerifyModule({ + address: module?.address as Option, + moduleName: module?.moduleName, + }); + return ( - - - Module Interactions - - + - {module ? ( - <> - - - - {module.address.toString()} - - - {module.moduleName} + + Module Interactions + + + {module ? ( + <> + + + + {module.address.toString()} + + + {module.moduleName} + + + + + + {module?.parsedAbi.friends + ? JSON.stringify(module?.parsedAbi.friends) + : "N/A"} - - - - - {abi?.friends ? JSON.stringify(abi.friends) : "N/A"} - - - - + + + + + + + + ) : ( + <> +

Select a module to interact with ...

- -
- - ) : ( - <> -

Select a module to interact with ...

- - - )} - - - - {/* Left side */} - - {/* Right side */} - - -
+ + )} + + + + {/* Left side */} + + {/* Right side */} + + + + + + + ); }; diff --git a/src/lib/pages/module-details/components/ModuleInfo.tsx b/src/lib/pages/module-details/components/ModuleInfo.tsx index 9d93ef6d0..e2f257617 100644 --- a/src/lib/pages/module-details/components/ModuleInfo.tsx +++ b/src/lib/pages/module-details/components/ModuleInfo.tsx @@ -3,8 +3,7 @@ import { Flex, Heading, Text } from "@chakra-ui/react"; import { ExplorerLink } from "lib/components/ExplorerLink"; import { CustomIcon } from "lib/components/icon"; import { LabelText } from "lib/components/LabelText"; - -import { ModuleSourceCode } from "./ModuleSourceCode"; +import { ModuleSourceCode } from "lib/components/module"; interface ModuleInfoProps { isVerified?: boolean; @@ -76,7 +75,8 @@ export const ModuleInfo = ({ isVerified = false }: ModuleInfoProps) => { /> - + {/* TODO: Wireup */} + ); }; diff --git a/src/lib/pages/module-details/components/ModuleSourceCode.tsx b/src/lib/pages/module-details/components/ModuleSourceCode.tsx deleted file mode 100644 index a1b2dda15..000000000 --- a/src/lib/pages/module-details/components/ModuleSourceCode.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { - Accordion, - AccordionButton, - AccordionIcon, - AccordionItem, - AccordionPanel, - Button, - Flex, - Text, -} from "@chakra-ui/react"; - -import { CustomIcon } from "lib/components/icon"; - -export const ModuleSourceCode = () => { - return ( - - - - - - - - Module Source Code - - - The source code is uploaded by the deployer and pulled from - Initia API - - - - - - - - - - TODO JSON INPUT HERE - - - - - ); -}; diff --git a/src/lib/services/module.ts b/src/lib/services/module.ts index 1dc579aa9..de0936714 100644 --- a/src/lib/services/module.ts +++ b/src/lib/services/module.ts @@ -6,6 +6,7 @@ import type { ResponseModules, InternalModule, HexAddr, + SnakeToCamelCaseNested, ResponseABI, ExposedFunction, AbiFormData, @@ -64,17 +65,29 @@ interface ModuleVerificationReturn { chain_id: string; } +// TODO: Figure out how to correctly infer NominalType intersection +export interface ModuleVerificationInternal + extends Omit< + SnakeToCamelCaseNested, + "moduleAddress" + > { + moduleAddress: HexAddr; +} + export const getModuleVerificationStatus = async ( address: MoveAccountAddr, moduleName: string -): Promise => +): Promise => // TODO: move url to base api route? wait for celatone api implementation? axios .get( `https://stone-compiler.initia.tech/contracts/${address}/${moduleName}` ) - .then(() => true) - .catch(() => false); + .then(({ data }) => ({ + ...snakeToCamel(data), + moduleAddress: data.module_address, + })) + .catch(() => null); export const getFunctionView = async ( baseEndpoint: string, diff --git a/src/lib/services/moduleService.ts b/src/lib/services/moduleService.ts index 26d0642f2..bfc9489ce 100644 --- a/src/lib/services/moduleService.ts +++ b/src/lib/services/moduleService.ts @@ -21,6 +21,7 @@ import type { RpcQueryError, HumanAddr, UpgradePolicy, + HexAddr, } from "lib/types"; import { bech32AddressToHex, @@ -102,12 +103,15 @@ export const useVerifyModule = ({ address, moduleName, }: { - address: MoveAccountAddr; - moduleName: string; + address: Option; + moduleName: Option; }) => useQuery( [CELATONE_QUERY_KEYS.MODULE_VERIFICATION, address, moduleName], - () => getModuleVerificationStatus(address, moduleName), + () => { + if (!address || !moduleName) return null; + return getModuleVerificationStatus(address, moduleName); + }, { enabled: Boolean(address && moduleName), retry: 0, @@ -185,7 +189,7 @@ export const useDecodeModule = ({ const currentPolicy = await getAccountModule( baseEndpoint, - abi.address, + abi.address as HexAddr, abi.name ) .then((data) => data.upgradePolicy) diff --git a/src/lib/types/abi.ts b/src/lib/types/abi.ts index 5e47eb844..c4c9b2b73 100644 --- a/src/lib/types/abi.ts +++ b/src/lib/types/abi.ts @@ -1,4 +1,3 @@ -import type { HexAddr } from "./addrs"; import type { Option } from "./common"; import type { SnakeToCamelCaseNested } from "./converter"; @@ -28,8 +27,9 @@ interface ABIFunction { } /* response */ +// TODO: change address type to HexAddr after figuring out how to correctly infer NominalType intersection export interface ResponseModule { - address: HexAddr; + address: string; module_name: string; abi: string; raw_bytes: string; @@ -46,8 +46,9 @@ export interface ModulePagination { total: string; } +// TODO: change address type to HexAddr after figuring out how to correctly infer NominalType intersection export interface ResponseABI { - address: HexAddr; + address: string; name: string; friends: string[]; exposed_functions: ExposedFunction[]; diff --git a/src/lib/types/addrs.ts b/src/lib/types/addrs.ts index bd8b8d0fe..8119999bd 100644 --- a/src/lib/types/addrs.ts +++ b/src/lib/types/addrs.ts @@ -1,4 +1,4 @@ -import type { NominalType } from "./currency/common"; +import type { NominalType } from "./common"; export type HumanAddr = string & NominalType<"HumanAddr">; export type HexAddr = string & NominalType<"HexAddr">; diff --git a/src/lib/types/common.ts b/src/lib/types/common.ts index 9a120421d..1a9b50659 100644 --- a/src/lib/types/common.ts +++ b/src/lib/types/common.ts @@ -1,3 +1,5 @@ export type Dict = Partial>; export type Option = T | undefined; + +export type NominalType = { __type: T }; diff --git a/src/lib/types/currency/common.ts b/src/lib/types/currency/common.ts deleted file mode 100644 index fb4a0510b..000000000 --- a/src/lib/types/currency/common.ts +++ /dev/null @@ -1 +0,0 @@ -export type NominalType = { __type: T }; diff --git a/src/lib/types/currency/index.ts b/src/lib/types/currency/index.ts index 4e267ac75..0111c632e 100644 --- a/src/lib/types/currency/index.ts +++ b/src/lib/types/currency/index.ts @@ -1,3 +1,2 @@ -export * from "./common"; export * from "./token"; export * from "./balance"; diff --git a/src/lib/types/currency/token.ts b/src/lib/types/currency/token.ts index 8c7649382..73c69e271 100644 --- a/src/lib/types/currency/token.ts +++ b/src/lib/types/currency/token.ts @@ -1,4 +1,4 @@ -import type { NominalType } from "./common"; +import type { NominalType } from "../common"; export type U = T & { __micro: true };