Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: migrate options and upload #108

Merged
merged 24 commits into from
Jan 30, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ff63719
feat: migrate options and upload
songwongtp Jan 19, 2023
2921ea4
fix: changelog
songwongtp Jan 19, 2023
2b878b2
Merge branch 'develop' into component/migrate-step1
songwongtp Jan 19, 2023
1bb7d37
fix: handle not admin case
songwongtp Jan 20, 2023
ca80ab0
Merge branch 'develop' into component/migrate-step1
songwongtp Jan 22, 2023
be68a48
fix: use useForm in upload section
songwongtp Jan 22, 2023
59aaf9a
feat: migration step 2
songwongtp Jan 23, 2023
9754107
feat: add validate code id
songwongtp Jan 24, 2023
e1407c5
Merge branch 'develop' into component/migrate-step2
songwongtp Jan 25, 2023
7478f4b
fix: stop migrate button from loading
songwongtp Jan 25, 2023
3222b91
fix: text
songwongtp Jan 25, 2023
19fb156
fix: as commented
songwongtp Jan 25, 2023
066bef3
fix: navigate to contract page after migrate
songwongtp Jan 26, 2023
a577a37
fix: navigate after clicking close
songwongtp Jan 26, 2023
2b1cd8e
Merge branch 'develop' into component/migrate-step1
songwongtp Jan 26, 2023
a0c5fec
Merge branch 'develop' into component/migrate-step1
songwongtp Jan 27, 2023
65d1622
Merge branch 'component/migrate-step1' into component/migrate-step2
songwongtp Jan 27, 2023
b6261a2
Merge pull request #120 from alleslabs/component/migrate-step2
songwongtp Jan 27, 2023
a797530
fix: as comments
songwongtp Jan 30, 2023
4292ceb
fix: upload access type
songwongtp Jan 30, 2023
5f57aa9
fix: as comments
songwongtp Jan 30, 2023
a18559c
Merge branch 'develop' into component/migrate-step1
songwongtp Jan 30, 2023
36a8fc5
fix: add span
songwongtp Jan 30, 2023
d5ae6db
Merge branch 'develop' into component/migrate-step1
evilpeach Jan 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- [#120](https://github.com/alleslabs/celatone-frontend/pull/120) Add simulate migrate fee and the final migration step
- [#108](https://github.com/alleslabs/celatone-frontend/pull/108) Add migrate options on migrate page and upload new code for migration
- [#113](https://github.com/alleslabs/celatone-frontend/pull/113) Update admin page ui and wireup
- [#98](https://github.com/alleslabs/celatone-frontend/pull/98) Add migrate, update admin, clear admin menu on contract list and detail
- [#121](https://github.com/alleslabs/celatone-frontend/pull/121) Fix code snippet for query axios
Expand Down
85 changes: 85 additions & 0 deletions src/lib/app-fns/tx/migrate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Icon } from "@chakra-ui/react";
import type {
MigrateResult,
SigningCosmWasmClient,
} from "@cosmjs/cosmwasm-stargate";
import type { StdFee } from "@cosmjs/stargate";
import { pipe } from "@rx-stream/pipe";
import { MdCheckCircle } from "react-icons/md";
import type { Observable } from "rxjs";

import { ExplorerLink } from "lib/components/ExplorerLink";
import type { ContractAddr, TxResultRendering } from "lib/types";
import { TxStreamPhase } from "lib/types";
import { formatUFee } from "lib/utils";

import { catchTxError } from "./common/catchTxError";
import { postTx } from "./common/post";
import { sendingTx } from "./common/sending";

interface MigrateTxParams {
sender: string;
contractAddress: ContractAddr;
codeId: number;
migrateMsg: object;
fee: StdFee;
client: SigningCosmWasmClient;
onTxSucceed?: (txHash: string) => void;
onTxFailed?: () => void;
}

export const migrateContractTx = ({
sender,
contractAddress,
codeId,
migrateMsg,
fee,
client,
onTxSucceed,
onTxFailed,
}: MigrateTxParams): Observable<TxResultRendering> => {
return pipe(
sendingTx(fee),
postTx<MigrateResult>({
postFn: () =>
client.migrate(
sender,
contractAddress,
codeId,
migrateMsg,
fee,
undefined
),
}),
({ value: txInfo }) => {
onTxSucceed?.(txInfo.transactionHash);
return {
value: null,
phase: TxStreamPhase.SUCCEED,
receipts: [
{
title: "Tx Hash",
value: txInfo.transactionHash,
html: (
<ExplorerLink type="tx_hash" value={txInfo.transactionHash} />
),
},
{
title: "Tx Fee",
value: `${formatUFee(
txInfo.events.find((e) => e.type === "tx")?.attributes[0].value ??
"0u"
)}`,
},
],
receiptInfo: {
header: "Migration Completed",
headerIcon: (
<Icon as={MdCheckCircle} fontSize="24px" color="success.main" />
),
},
actionVariant: "migrate",
} as TxResultRendering;
}
)().pipe(catchTxError(onTxFailed));
};
8 changes: 5 additions & 3 deletions src/lib/app-fns/tx/upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ interface UploadTxParams {
memo?: string;
client: SigningCosmWasmClient;
onTxSucceed?: (codeId: number) => void;
isMigrate: boolean;
}

export const uploadContractTx = ({
Expand All @@ -37,6 +38,7 @@ export const uploadContractTx = ({
memo,
client,
onTxSucceed,
isMigrate,
}: UploadTxParams): Observable<TxResultRendering> => {
return pipe(
sendingTx(fee),
Expand Down Expand Up @@ -80,15 +82,15 @@ export const uploadContractTx = ({
<span style={{ fontWeight: 700 }}>
‘{codeDesc || `${wasmFileName}(${txInfo.codeId})`}’
</span>{" "}
is available on your stored code. Would you like to instantiate
your code now?
is available on your stored code. Would you like to{" "}
{isMigrate ? "migrate" : "instantiate"} your code now?
</>
),
headerIcon: (
<Icon as={MdCloudUpload} fontSize="24px" color="text.dark" />
),
},
actionVariant: "upload",
actionVariant: isMigrate ? "upload-migrate" : "upload",
} as TxResultRendering;
}
)().pipe(catchTxError());
Expand Down
47 changes: 47 additions & 0 deletions src/lib/app-provider/tx/migrate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import type { StdFee } from "@cosmjs/stargate";
import { useWallet } from "@cosmos-kit/react";
import { useCallback } from "react";

import { migrateContractTx } from "lib/app-fns/tx/migrate";
import type { ContractAddr, Option } from "lib/types";

export interface MigrateStreamParams {
contractAddress: ContractAddr;
codeId: number;
migrateMsg: object;
estimatedFee: Option<StdFee>;
onTxSucceed?: (txHash: string) => void;
onTxFailed?: () => void;
}

export const useMigrateTx = () => {
const { address, getCosmWasmClient } = useWallet();

return useCallback(
async ({
contractAddress,
codeId,
migrateMsg,
estimatedFee,
onTxSucceed,
onTxFailed,
}: MigrateStreamParams) => {
const client = await getCosmWasmClient();
if (!address || !client)
throw new Error("Please check your wallet connection.");
if (!estimatedFee) return null;

return migrateContractTx({
sender: address,
contractAddress,
codeId,
migrateMsg,
fee: estimatedFee,
client,
onTxSucceed,
onTxFailed,
});
},
[address, getCosmWasmClient]
);
};
23 changes: 15 additions & 8 deletions src/lib/app-provider/tx/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,27 @@ import { useWallet } from "@cosmos-kit/react";
import { useCallback } from "react";

import { uploadContractTx } from "lib/app-fns/tx/upload";
import type { Option } from "lib/types";

export interface UploadStreamParams {
onTxSucceed?: (codeId: number) => void;
wasmFileName: Option<string>;
wasmCode: Option<Promise<ArrayBuffer>>;
codeDesc: string;
estimatedFee: Option<StdFee>;
onTxSucceed?: (codeId: number) => void;
}

export const useUploadContractTx = (
wasmFileName: string | undefined,
wasmCode: Promise<ArrayBuffer> | undefined,
estimatedFee: StdFee | undefined
) => {
export const useUploadContractTx = (isMigrate: boolean) => {
const { address, getCosmWasmClient } = useWallet();

return useCallback(
async ({ onTxSucceed, codeDesc }: UploadStreamParams) => {
async ({
wasmFileName,
wasmCode,
codeDesc,
estimatedFee,
onTxSucceed,
}: UploadStreamParams) => {
const client = await getCosmWasmClient();
if (!address || !client)
throw new Error("Please check your wallet connection.");
Expand All @@ -31,8 +37,9 @@ export const useUploadContractTx = (
fee: estimatedFee,
client,
onTxSucceed,
isMigrate,
});
},
[address, getCosmWasmClient, estimatedFee, wasmCode, wasmFileName]
[address, getCosmWasmClient, isMigrate]
);
};
76 changes: 76 additions & 0 deletions src/lib/components/CodeSelectSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Flex, Radio, RadioGroup } from "@chakra-ui/react";
import { useState } from "react";
import type { Control, FieldPath, FieldValues } from "react-hook-form";

import { CodeSelect } from "lib/pages/instantiate/component";
import type { Option } from "lib/types";

import type { FormStatus } from "./forms";
import { ControllerInput } from "./forms";

interface CodeSelectSectionProps<T extends FieldValues> {
codeId: string;
name: FieldPath<T>;
control: Control<T>;
error: Option<string>;
onCodeSelect: (codeId: string) => void;
status: FormStatus;
}

export const CodeSelectSection = <T extends FieldValues>({
codeId,
name,
control,
error,
onCodeSelect,
status,
}: CodeSelectSectionProps<T>) => {
const [method, setMethod] = useState<"select-existing" | "fill-manually">(
"select-existing"
);

return (
<>
<RadioGroup
onChange={(nextVal: "select-existing" | "fill-manually") =>
setMethod(nextVal)
}
value={method}
w="100%"
>
<Flex justify="space-around">
<Radio value="select-existing" size="lg">
Select from your code
</Radio>
<Radio value="fill-manually" size="lg">
Fill Code ID manually
</Radio>
</Flex>
</RadioGroup>
<form style={{ width: "100%" }}>
{method === "select-existing" ? (
<CodeSelect
mt="16px"
mb="32px"
onCodeSelect={onCodeSelect}
codeId={codeId}
status={status}
/>
) : (
<ControllerInput
name={name}
control={control}
type="number"
status={status}
error={error}
label="Code ID"
helperText="Input existing Code ID manually"
variant="floating"
my="32px"
rules={{ required: "Code ID is required" }}
/>
)}
</form>
</>
);
};
2 changes: 1 addition & 1 deletion src/lib/components/ContractSelectSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export const ContractSelectSection = observer(
});

const { refetch } = useQuery(
["query", "instantiateInfo", contractAddress],
["query", "instantiateInfo", endpoint, contractAddress],
async () =>
queryInstantiateInfo(endpoint, indexerGraphClient, contractAddress),
{
Expand Down
28 changes: 17 additions & 11 deletions src/lib/components/forms/ControllerInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
FormHelperText,
FormLabel,
Input,
InputGroup,
InputRightElement,
Text,
} from "@chakra-ui/react";
import type {
Expand All @@ -15,7 +17,7 @@ import type {
import { useWatch, useController } from "react-hook-form";

import type { FormStatus } from "./FormStatus";
import { getResponseMsg } from "./FormStatus";
import { getStatusIcon, getResponseMsg } from "./FormStatus";
import type { TextInputProps } from "./TextInput";

interface ControllerInputProps<T extends FieldValues>
Expand Down Expand Up @@ -58,7 +60,7 @@ export const ControllerInput = <T extends FieldValues>({
return (
<FormControl
size={size}
isInvalid={isError}
isInvalid={!!error || status?.state === "error"}
isRequired={isRequired}
{...componentProps}
{...field}
Expand All @@ -68,15 +70,19 @@ export const ControllerInput = <T extends FieldValues>({
{label}
</FormLabel>
)}
<Input
size={size}
placeholder={placeholder}
type={type}
value={watcher}
onChange={field.onChange}
maxLength={maxLength}
/>
{/* TODO: add status */}
<InputGroup>
<Input
size={size}
placeholder={placeholder}
type={type}
value={watcher}
onChange={field.onChange}
maxLength={maxLength}
/>
<InputRightElement h="full">
{status && getStatusIcon(status.state)}
</InputRightElement>
</InputGroup>
{isError ? (
<FormErrorMessage className="error-text">{error}</FormErrorMessage>
) : (
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/forms/FormStatus.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Icon, Spinner, Text } from "@chakra-ui/react";
import { MdCheckCircle, MdOutlineWarning } from "react-icons/md";

type ResponseState = "init" | "loading" | "success" | "error";
export type ResponseState = "init" | "loading" | "success" | "error";

export interface FormStatus {
state: ResponseState;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/modal/contract/SaveNewContract.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export function SaveNewContract({ list, buttonProps }: SaveNewContractProps) {

// TODO: Abstract query
const { refetch } = useQuery(
["query", "instantiateInfo", contractAddressState],
["query", "instantiateInfo", endpoint, contractAddressState],
async () =>
queryInstantiateInfo(
endpoint,
Expand Down
Loading