Skip to content

Commit

Permalink
feature(Contract): Migrate contract
Browse files Browse the repository at this point in the history
  • Loading branch information
sim committed Jan 24, 2022
1 parent 5700909 commit 41027dd
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 43 deletions.
2 changes: 2 additions & 0 deletions src/app/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import VoteTx from "txs/gov/VoteTx"
import StoreCodeTx from "txs/wasm/StoreCodeTx"
import InstantiateContractTx from "txs/wasm/InstantiateContractTx"
import ExecuteContractTx from "txs/wasm/ExecuteContractTx"
import MigrateContractTx from "txs/wasm/MigrateContractTx"
import AnchorEarnTx from "txs/earn/AnchorEarnTx"
import SignMultisigTxPage from "pages/multisig/SignMultisigTxPage"
import PostMultisigTxPage from "pages/multisig/PostMultisigTxPage"
Expand Down Expand Up @@ -127,6 +128,7 @@ export const useNav = () => {
{ path: "/contract/instantiate", element: <InstantiateContractTx /> },
{ path: "/contract/store", element: <StoreCodeTx /> },
{ path: "/contract/execute/:contract", element: <ExecuteContractTx /> },
{ path: "/contract/migrate/:contract", element: <MigrateContractTx /> },
{ path: "/earn", element: <AnchorEarnTx /> },

/* auth */
Expand Down
10 changes: 5 additions & 5 deletions src/pages/contract/Contract.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { useState } from "react"
import { useTranslation } from "react-i18next"
import ManageSearchIcon from "@mui/icons-material/ManageSearch"
import { AccAddress } from "@terra-money/terra.js"
import { AccAddress, ContractInfo } from "@terra-money/terra.js"
import createContext from "utils/createContext"
import { useContractInfo } from "data/queries/wasm"
import { Page, Card, Grid } from "components/layout"
import { Fetching, State, Empty } from "components/feedback"
import { SearchInput } from "components/form"
import ContractActions from "./ContractActions"
import ContractDetails from "./ContractDetails"
import ContractItem from "./ContractItem"

export const [useContract, ContractProvider] =
createContext<AccAddress>("useContract")
createContext<ContractInfo>("useContract")

const Contract = () => {
const { t } = useTranslation()
Expand Down Expand Up @@ -41,8 +41,8 @@ const Contract = () => {
) : (
<Fetching {...state}>
{result && (
<ContractProvider value={address}>
<ContractDetails {...result} />
<ContractProvider value={result}>
<ContractItem {...result} />
</ContractProvider>
)}
</Fetching>
Expand Down
9 changes: 0 additions & 9 deletions src/pages/contract/ContractDetails.module.scss
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
@import "mixins";

.main {
overflow: hidden;
width: 100%;
}

.header {
@include desktop {
@include flex(flex-start);
Expand All @@ -20,7 +15,3 @@
.link {
font-weight: var(--normal);
}

.wrapper {
overflow: hidden;
}
44 changes: 18 additions & 26 deletions src/pages/contract/ContractDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { useTranslation } from "react-i18next"
import { ContractInfo } from "@terra-money/terra.js"
import { Pre, FinderLink } from "components/general"
import { Card, Grid } from "components/layout"
import ContractItemActions from "./ContractItemActions"
import { Grid } from "components/layout"
import styles from "./ContractDetails.module.scss"

const ContractDetails = (props: ContractInfo) => {
const { t } = useTranslation()
const { code_id, address, admin, creator, init_msg } = props
const { code_id, admin, creator, init_msg } = props

const contents = [
{
Expand All @@ -25,31 +24,24 @@ const ContractDetails = (props: ContractInfo) => {
]

return (
<Card
title={<FinderLink className={styles.link}>{address}</FinderLink>}
extra={<ContractItemActions />}
bordered
mainClassName={styles.main}
>
<Grid gap={32}>
<header className={styles.header}>
{contents.map(({ title, content }) =>
!content ? null : (
<Grid gap={4} key={title}>
<h1>{title}</h1>
<p>{content}</p>
</Grid>
)
)}
</header>
<Grid gap={32}>
<header className={styles.header}>
{contents.map(({ title, content }) =>
!content ? null : (
<Grid gap={4} key={title}>
<h1>{title}</h1>
<p>{content}</p>
</Grid>
)
)}
</header>

<Grid gap={4} className={styles.wrapper}>
{/* Do not translate this */}
<h1>InitMsg</h1>
<Pre height={240}>{init_msg}</Pre>
</Grid>
<Grid gap={4} className={styles.wrapper}>
{/* Do not translate this */}
<h1>InitMsg</h1>
<Pre height={240}>{init_msg}</Pre>
</Grid>
</Card>
</Grid>
)
}

Expand Down
8 changes: 8 additions & 0 deletions src/pages/contract/ContractItem.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.main {
overflow: hidden;
width: 100%;
}

.link {
font-weight: var(--normal);
}
23 changes: 23 additions & 0 deletions src/pages/contract/ContractItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ContractInfo } from "@terra-money/terra.js"
import { FinderLink } from "components/general"
import { Card } from "components/layout"
import ContractItemActions from "./ContractItemActions"
import ContractDetails from "./ContractDetails"
import styles from "./ContractItem.module.scss"

const ContractItem = (props: ContractInfo) => {
const { address } = props

return (
<Card
title={<FinderLink className={styles.link}>{address}</FinderLink>}
extra={<ContractItemActions />}
mainClassName={styles.main}
bordered
>
<ContractDetails {...props} />
</Card>
)
}

export default ContractItem
10 changes: 9 additions & 1 deletion src/pages/contract/ContractItemActions.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useTranslation } from "react-i18next"
import { useAddress } from "data/wallet"
import { Button, LinkButton } from "components/general"
import { ModalButton } from "components/feedback"
import { ExtraActions } from "components/layout"
Expand All @@ -7,7 +8,8 @@ import { useContract } from "./Contract"

const ContractItemActions = () => {
const { t } = useTranslation()
const address = useContract()
const connectedAddress = useAddress()
const { address, admin } = useContract()

return (
<ExtraActions>
Expand All @@ -25,6 +27,12 @@ const ContractItemActions = () => {
<LinkButton to={`/contract/execute/${address}`} size="small" outline>
{t("Execute")}
</LinkButton>

{admin && connectedAddress === admin && (
<LinkButton to={`/contract/migrate/${address}`} size="small" outline>
{t("Migrate")}
</LinkButton>
)}
</ExtraActions>
)
}
Expand Down
4 changes: 2 additions & 2 deletions src/pages/contract/ContractQuery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface Values {

const ContractQuery = () => {
const { t } = useTranslation()
const contract = useContract()
const { address } = useContract()

/* form */
const form = useForm<Values>({ mode: "onChange" })
Expand All @@ -32,7 +32,7 @@ const ContractQuery = () => {
const [query, setQuery] = useState<object>({})

const { data, error, ...state } = useQuery({
...getContractQuery<object>(contract, query),
...getContractQuery<object>(address, query),
enabled: !isEmpty(query),
retry: false,
})
Expand Down
96 changes: 96 additions & 0 deletions src/txs/wasm/MigrateContractForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { useCallback, useMemo } from "react"
import { useTranslation } from "react-i18next"
import { useForm } from "react-hook-form"
import { AccAddress, MsgMigrateContract } from "@terra-money/terra.js"
import { parseJSON, validateMsg } from "utils/data"
import { useAddress } from "data/wallet"
import { useBankBalance } from "data/queries/bank"
import { Form, FormItem } from "components/form"
import { Input, EditorInput } from "components/form"
import validate from "../validate"
import Tx, { getInitialGasDenom } from "../Tx"

interface TxValues {
id?: number
msg?: string
}

const MigrateContractForm = ({ contract }: { contract: AccAddress }) => {
const { t } = useTranslation()

const address = useAddress()
const bankBalance = useBankBalance()

/* tx context */
const initialGasDenom = getInitialGasDenom(bankBalance)

/* form */
const form = useForm<TxValues>({ mode: "onChange" })
const { register, watch, handleSubmit, formState } = form
const { errors } = formState
const values = watch()

/* tx */
const createTx = useCallback(
({ id, msg }: TxValues) => {
if (!address || !(id && msg)) return
if (!validateMsg(msg)) return

const migrate_msg = parseJSON(msg)
const msgs = [new MsgMigrateContract(address, contract, id, migrate_msg)]

return { msgs }
},
[address, contract]
)

/* fee */
const estimationTxValues = useMemo(() => values, [values])

const tx = {
initialGasDenom,
estimationTxValues,
createTx,
onSuccess: { label: t("Contract"), path: "/contract" },
}

return (
<Tx {...tx}>
{({ fee, submit }) => (
<Form onSubmit={handleSubmit(submit.fn)}>
<FormItem label={t("Code ID")} error={errors.id?.message}>
<Input
{...register("id", {
valueAsNumber: true,
required: "Code ID is required",
min: {
value: 0,
message: "Code ID must be a positive integer",
},
validate: {
integer: (value) =>
Number.isInteger(value) || "Code ID must be an integer",
},
})}
inputMode="decimal"
placeholder="1"
autoFocus
/>
</FormItem>

<FormItem
label="Migrate msg" // do not translate this
error={errors.msg?.message}
>
<EditorInput {...register("msg", { validate: validate.msg() })} />
</FormItem>

{fee.render()}
{submit.button}
</Form>
)}
</Tx>
)
}

export default MigrateContractForm
24 changes: 24 additions & 0 deletions src/txs/wasm/MigrateContractTx.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { Page, Card } from "components/layout"
import TxContext from "../TxContext"
import MigrateContractForm from "./MigrateContractForm"

const MigrateContractTx = () => {
const { t } = useTranslation()
const { contract } = useParams()

if (!contract) throw new Error("Contract is not defined")

return (
<Page title={t("Migrate")} small>
<Card>
<TxContext>
<MigrateContractForm contract={contract} />
</TxContext>
</Card>
</Page>
)
}

export default MigrateContractTx

0 comments on commit 41027dd

Please sign in to comment.