diff --git a/package.json b/package.json index 28ddd03c..df5b96bb 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@mui/material": "^5.14.14", "@mui/x-date-pickers": "^5.0.2", "@taquito/beacon-wallet": "^17.3.1", + "@taquito/michel-codec": "^20.0.0", "@taquito/signer": "^17.3.1", "@taquito/taquito": "^17.3.1", "@taquito/tzip12": "^17.3.1", @@ -39,6 +40,7 @@ "@types/react-router-hash-link": "^2.4.5", "@types/valid-url": "^1.0.4", "assert": "^2.0.0", + "assert-never": "^1.2.1", "bignumber.js": "^9.0.1", "blockies-ts": "^1.0.0", "crypto-browserify": "^3.12.0", diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx new file mode 100644 index 00000000..92d1e735 --- /dev/null +++ b/src/components/ui/Button.tsx @@ -0,0 +1,28 @@ +import { styled, Button as MaterialButton } from "@material-ui/core" + +export const Button = styled(MaterialButton)(({ theme }) => ({ + "fontSize": "14px", + "justifyItems": "center", + "color": "#000", + "boxShadow": "0px 0px 7px -2px rgba(0, 0, 0, 0.2)", + "transition": ".15s ease-in", + "background": theme.palette.secondary.main, + "textTransform": "none", + "borderRadius": 4, + "padding": "8px 15px", + "marginRight": "8px", + + "&$disabled": { + boxShadow: "none" + }, + + "&:hover": { + boxShadow: "0px 0px 7px -2px rgba(0, 0, 0, 0.2)", + backgroundColor: "#62eda5 !important", + transition: ".15s ease-in" + }, + + ["@media (max-width:1030px)"]: { + fontSize: "14px" + } +})) diff --git a/src/modules/explorer/components/ArbitraryContractInteractionForm.tsx b/src/modules/explorer/components/ArbitraryContractInteractionForm.tsx index 88c31761..1b69f4f4 100644 --- a/src/modules/explorer/components/ArbitraryContractInteractionForm.tsx +++ b/src/modules/explorer/components/ArbitraryContractInteractionForm.tsx @@ -21,6 +21,11 @@ import { toShortAddress } from "services/contracts/utils" import { useArbitraryContractData } from "services/aci/useArbitratyContractData" import { useTezos } from "services/beacon/hooks/useTezos" import { ArbitraryContract } from "models/Contract" +import { evalTaquitoParam, generateExecuteContractMichelson } from "services/aci" +import { emitMicheline, Parser } from "@taquito/michel-codec" +import type { ContractAbstraction } from "@taquito/taquito" +import ProposalExecuteForm from "./ProposalExecuteForm" +import { useLambdaExecutePropose } from "services/contracts/baseDAO/hooks/useLambdaExecutePropose" interface Parameter { key: string @@ -79,7 +84,8 @@ const BackButtonIcon = styled(ArrowBackIos)(({ theme }) => ({ })) type ACIValues = { - destination_contract: string + destination_contract: any + destination_contract_address: string amount: number target_endpoint: string parameters: Parameter[] @@ -124,15 +130,17 @@ const ContractInteractionForm = ({ showHeader }: any) => { const [state, setState] = useState(Status.NEW_INTERACTION) + const [formState, setFormState] = useState({ address: "", amount: 0, shape: {} }) const [endpoint, setEndpoint] = useState(undefined) const theme = useTheme() const isMobileSmall = useMediaQuery(theme.breakpoints.down("sm")) const { mutate: fetchContractData, data } = useArbitraryContractData() - const { network } = useTezos() + // console.log("FormData", data) + const { tezos, network } = useTezos() const [isLoading, setIsLoading] = useState(false) const shouldContinue = useMemo(() => { - if (values.destination_contract !== "" && !errors.destination_contract) { + if (values.destination_contract_address !== "" && !errors.destination_contract_address) { return false } return true @@ -144,7 +152,7 @@ const ContractInteractionForm = ({ } setIsLoading(true) fetchContractData({ - contract: getIn(values, "destination_contract"), + contract: getIn(values, "destination_contract_address"), network: network, handleContinue: () => setState(Status.CONTRACT_VALIDATED), finishLoad: () => setIsLoading(false), @@ -171,22 +179,32 @@ const ContractInteractionForm = ({ setFieldTouched("destination_contract")} + onClick={() => setFieldTouched("destination_contract_address")} onChange={(newValue: any) => { - setFieldValue("destination_contract", newValue.target.value) + const contractAddress = newValue.target.value.trim() + console.log("Destination Contract Address", contractAddress) + setFieldValue("destination_contract_address", contractAddress) + + if (validateContractAddress(contractAddress) === 3) { + tezos.contract.at(contractAddress).then((contract: any) => { + setFieldValue("destination_contract", contract) + }) + } else { + console.log("invalid address", contractAddress) + } }} - value={getIn(values, "destination_contract")} + value={getIn(values, "destination_contract_address")} inputProps={{ maxLength: 36 }} /> - {errors.destination_contract && touched.destination_contract ? ( - {errors.destination_contract} + {errors.destination_contract_address && touched.destination_contract_address ? ( + {errors.destination_contract_address} ) : null} @@ -219,8 +237,8 @@ const ContractInteractionForm = ({ Calling Contract {isMobileSmall - ? toShortAddress(getIn(values, "destination_contract")) - : getIn(values, "destination_contract")} + ? toShortAddress(getIn(values, "destination_contract_address")) + : getIn(values, "destination_contract_address")} @@ -229,10 +247,36 @@ const ContractInteractionForm = ({ Contract Endpoint - - - + setFormState({ address: "", amount: 0, shape: {} })} + setField={(lambda: string, metadata: string) => { + // debugger + console.log("SetField", lambda, metadata) + }} + setLoading={() => {}} + setState={shape => { + // debugger + console.log("New Shape", shape) + setFormState((v: any) => ({ ...v, shape })) + }} + onReset={() => { + setFormState({ address: "", amount: 0, shape: {} }) + // props.onReset() + }} + loading={false} + onShapeChange={shapeInitValue => { + setFormState((v: any) => ({ + ...v, + shape: { ...v?.shape, ...shapeInitValue } + })) + }} + /> + + {/* ACI: Endpoint list */} {endpoint && ( - - Submit + { + console.log({ formState }) + // debugger + let entrypoint = formState.shape.token.initValue // accept_ownership | default etc + let taquitoParam + + const execContract = formState.shape.contract + const taquitoFullParam = evalTaquitoParam(formState.shape.token, formState.shape.init) + if (execContract?.parameterSchema.isMultipleEntryPoint) { + const p = Object.entries(taquitoFullParam) + if (p.length !== 1) { + throw new Error("should only one entrypoint is selected") + } + ;[entrypoint, taquitoParam] = p[0] + } else { + taquitoParam = taquitoFullParam + } + const param = emitMicheline( + execContract?.methodsObject[entrypoint](taquitoParam).toTransferParams()?.parameter?.value + ) + + const micheline_type = execContract?.parameterSchema.isMultipleEntryPoint + ? execContract?.entrypoints.entrypoints[entrypoint] + : execContract?.parameterSchema.root.val + + // const micheline_type = values.destination_contract?.parameterSchema.isMultipleEntryPoint + // ? values.destination_contract.entrypoints.entrypoints[entrypoint] + // : values.destination_contract?.parameterSchema.root.val + + const p = new Parser() + const type = emitMicheline(p.parseJSON(micheline_type), { + indent: "", + newline: "" + }) + + const lambda = generateExecuteContractMichelson("1.0.0", { + address: values.destination_contract_address, + entrypoint, + type, + amount: values.amount, + param + }) + + // TODO: Deploy this to DAO + console.log({ lambda }) + }} + variant="contained" + disabled={!isValid} + > + Submit Form @@ -316,22 +409,26 @@ const ContractInteractionForm = ({ export const ArbitraryContractInteractionForm: React.FC<{ showHeader: (state: boolean) => void }> = ({ showHeader }) => { + const { mutate: executeProposeLambda } = useLambdaExecutePropose() const isInvalidKtOrTzAddress = (address: string) => validateContractAddress(address) !== 3 const initialValue: ACIValues = { - destination_contract: "", + destination_contract: {} as ArbitraryContract, + destination_contract_address: "", amount: 0, target_endpoint: "", parameters: [] } const validateForm = (values: ACIValues) => { + console.log("validateFormValues", values) + return {} const errors: FormikErrors = {} - if (!values.destination_contract) { - errors.destination_contract = "Required" + if (!values.destination_contract_address) { + errors.destination_contract_address = "Required" } - if (values.destination_contract && isInvalidKtOrTzAddress(values.destination_contract)) { - errors.destination_contract = "Invalid contract address" + if (values.destination_contract_address && isInvalidKtOrTzAddress(values.destination_contract_address)) { + errors.destination_contract_address = "Invalid contract address" } if (!values.target_endpoint) { errors.target_endpoint = "Required" diff --git a/src/modules/explorer/components/ConfigProposalForm.tsx b/src/modules/explorer/components/ConfigProposalForm.tsx index 28436398..b27fefd3 100644 --- a/src/modules/explorer/components/ConfigProposalForm.tsx +++ b/src/modules/explorer/components/ConfigProposalForm.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/display-name */ import { Grid, Typography, TextField, styled } from "@material-ui/core" -import React, { useCallback } from "react" +import React, { useCallback, useMemo } from "react" import { useDAO } from "services/services/dao/hooks/useDAO" import { SendButton } from "./ProposalFormSendButton" import { Controller, FormProvider, useForm } from "react-hook-form" @@ -10,6 +10,7 @@ import { useProposeConfigChange } from "../../../services/contracts/baseDAO/hook import { ResponsiveDialog } from "./ResponsiveDialog" import * as yup from "yup" import { yupResolver } from "@hookform/resolvers/yup" +import { code } from "services/contracts/metadataCarrier/code" const ErrorText = styled(Typography)({ fontSize: 14, @@ -27,13 +28,6 @@ type Values = { export type ProposalFormDefaultValues = RecursivePartial -interface Props { - open: boolean - handleClose: () => void - defaultValues?: ProposalFormDefaultValues - defaultTab?: number -} - const validationSchema = yup.object({ frozen_extra_value: yup.number().typeError("Amount must be a number"), returnedPercentage: yup @@ -43,7 +37,12 @@ const validationSchema = yup.object({ .typeError("Amount must be a number") }) -export const ConfigProposalForm: React.FC = ({ open, handleClose }) => { +export const ConfigProposalForm: React.FC<{ + open: boolean + handleClose: () => void + defaultValues?: ProposalFormDefaultValues + defaultTab?: number +}> = ({ open, handleClose }) => { const daoId = useDAOID() const { data: dao } = useDAO(daoId) diff --git a/src/modules/explorer/components/ConfigProposalFormLambda.tsx b/src/modules/explorer/components/ConfigProposalFormLambda.tsx index 2b40d8c6..098be09a 100644 --- a/src/modules/explorer/components/ConfigProposalFormLambda.tsx +++ b/src/modules/explorer/components/ConfigProposalFormLambda.tsx @@ -1,5 +1,5 @@ import { Grid, Typography, styled, CircularProgress } from "@material-ui/core" -import React, { useCallback, useEffect, useState } from "react" +import React, { useCallback, useEffect, useMemo, useState } from "react" import { useDAO } from "services/services/dao/hooks/useDAO" import { FormProvider, useForm } from "react-hook-form" import { useDAOID } from "../pages/DAO/router" @@ -20,8 +20,13 @@ import { parseLambdaCode } from "utils" import { ArbitraryContractInteractionForm } from "./ArbitraryContractInteractionForm" const StyledSendButton = styled(MainButton)(({ theme }) => ({ - width: 101, - color: "#1C1F23" + "width": 101, + "color": "#1C1F23", + "&$disabled": { + opacity: 0.5, + boxShadow: "none", + cursor: "not-allowed" + } })) const StyledRow = styled(Grid)({ @@ -67,10 +72,22 @@ type Values = { } type ACIValues = { - destination_contract: string + destination_contract_address: string amount?: number } +type AciToken = { + counter: number + name?: string + type: string + children: AciToken[] + placeholder?: string + validate?: (value: string) => string | undefined + initValue: tokenValueType +} +type tokenMap = Record<"key" | "value", AciToken> +type tokenValueType = string | boolean | number | AciToken | AciToken[] | tokenMap[] + export enum ProposalAction { new, remove, @@ -78,12 +95,6 @@ export enum ProposalAction { none } -interface Props { - open: boolean - action: ProposalAction - handleClose: () => void -} - enum LambdaProposalState { write_action, wallet_action, @@ -144,7 +155,11 @@ Eg:- ` } -export const ProposalFormLambda: React.FC = ({ open, handleClose, action }) => { +export const ProposalFormLambda: React.FC<{ + open: boolean + action: ProposalAction + handleClose: () => void +}> = ({ open, handleClose, action }) => { const grammar = Prism.languages.javascript const daoId = useDAOID() @@ -158,14 +173,12 @@ export const ProposalFormLambda: React.FC = ({ open, handleClose, action const [showHeader, setShowHeader] = useState(true) const lambdaForm = useForm() - const ACIForm = useForm() const [lambda, setLambda] = React.useState(null) const [state, setState] = React.useState(LambdaProposalState.write_action) const [lambdaParams, setLambdaParams] = React.useState("") const [lambdaArguments, setLambdaArguments] = React.useState("") const [code, setCode] = React.useState("") - const [ACIData, setACIData] = React.useState() const ARBITRARY_CONTRACT_INTERACTION = "arbitrary_contract_interaction" @@ -203,7 +216,7 @@ export const ProposalFormLambda: React.FC = ({ open, handleClose, action const onSubmit = useCallback( (_: Values) => { const agoraPostId = Number(0) - + // debugger switch (action) { case ProposalAction.new: { lambdaAdd({ @@ -275,6 +288,14 @@ export const ProposalFormLambda: React.FC = ({ open, handleClose, action [dao, lambdaAdd, code, action, lambda, lambdaRemove, lambdaArguments, lambdaExecute, lambdaParams, handleClose] ) + const isDisabled = useMemo(() => { + // if (lambda?.key === ARBITRARY_CONTRACT_INTERACTION) return false + if (!code) return true + if (action === ProposalAction.execute && (!lambda || lambdaArguments === "" || lambdaParams === "")) return true + }, [code, action, lambda, lambdaArguments, lambdaParams, ACI.key]) + + // console.log({ isDisabled }) + const handleSearchChange = (data: Lambda) => { if (!data?.value) { lambdaForm.reset() @@ -412,7 +433,7 @@ export const ProposalFormLambda: React.FC = ({ open, handleClose, action {lambda && lambda.key !== ARBITRARY_CONTRACT_INTERACTION ? ( - + Submit diff --git a/src/modules/explorer/components/ProposalExecuteForm.tsx b/src/modules/explorer/components/ProposalExecuteForm.tsx new file mode 100644 index 00000000..1a597ce0 --- /dev/null +++ b/src/modules/explorer/components/ProposalExecuteForm.tsx @@ -0,0 +1,133 @@ +import { Form, Formik } from "formik" +import React, { Context, createContext, useContext, useEffect } from "react" +import { genLambda, parseContract } from "../../../services/aci" +import { RenderItem } from "./aci/Fields" +import type { TezosToolkit } from "@taquito/taquito" +import type { BeaconWallet } from "@taquito/beacon-wallet" +import type BigNumber from "bignumber.js" +import { useTezos } from "services/beacon/hooks/useTezos" +import { SmallButtonDialog } from "modules/common/SmallButton" +import { useDAOID } from "../pages/DAO/router" +import { useDAO } from "services/services/dao/hooks/useDAO" +// import ErrorMessage from "./ErrorMessage" +// import renderError from "./formUtils" + +type contractStorage = { version: string } & { + [key: string]: any + proposal_counter: BigNumber + balance: string + threshold: BigNumber + owners: Array +} + +type tezosState = { + beaconWallet: BeaconWallet + contracts: any // DAO Contracts + address: string | null // Logged in User Address + balance: string | null // Logged in user balance + currentContract: string | null // Contract Address + currentStorage: contractStorage | null +} + +// const AppStateContext: Context = createContext(null) + +function ProposalExecuteForm( + props: React.PropsWithoutRef<{ + address: string // Input contract Address + amount: number + shape: any + reset: () => void + setField: (lambda: string, metadata: string) => void + setLoading: (x: boolean) => void + setState: (shape: any) => void + onReset?: () => void + loading: boolean + onShapeChange: (v: object) => void + }> +) { + const daoId = useDAOID() + const { data: dao } = useDAO(daoId) + + const address = props.address + const setLoading = props.setLoading + const loading = props.loading + const { tezos } = useTezos() + + useEffect(() => { + // debugger + if (!Object.keys(props.shape).length && !loading) { + ;(async () => { + try { + const c = await tezos.contract.at(address) + const initTokenTable: Record = {} + const token = await parseContract(c, initTokenTable) + props.setState({ init: initTokenTable, token, contract: c }) + } catch (e) { + console.error("Error fetching contract:", e) + } + })() + } + }, [address, loading, props.shape]) + + // return <>Proposal Execute Form + + return ( +
+ {}} + validateOnMount={true} + validate={values => { + // console.log("Validate For ProposalExecuteForm", dao?.data) + props.onShapeChange(values) + // debugger; + try { + // ACI: This sets the lambda and metadata fields + // if (state?.contracts[state?.currentContract ?? ""]?.version) { + if (dao?.data?.address) { + genLambda("1.0.0", props, values) + } + } catch (e) { + // setSubmitError((e as Error).message); + } + }} + > + {_ => { + // debugger; + return ( +
+
+ {!!props.shape.token && } +
+
+ { + e.preventDefault() + props.reset() + props.onReset?.() + }} + > + Reset + + {/* */} +
+
+ ) + }} +
+
+ ) +} +export default ProposalExecuteForm diff --git a/src/modules/explorer/components/ResponsiveDialog.tsx b/src/modules/explorer/components/ResponsiveDialog.tsx index e903d802..522916ba 100644 --- a/src/modules/explorer/components/ResponsiveDialog.tsx +++ b/src/modules/explorer/components/ResponsiveDialog.tsx @@ -72,7 +72,15 @@ export const ResponsiveDialog: React.FC<{ ) : ( - + { + // TODO: Comment this while creating PR + if (reason && reason === "backdropClick") return + onClose() + }} + maxWidth={template} + > {onGoBack !== undefined ? ( diff --git a/src/modules/explorer/components/SearchEndpoints.tsx b/src/modules/explorer/components/SearchEndpoints.tsx index bcbbe2e6..beb8ad2d 100644 --- a/src/modules/explorer/components/SearchEndpoints.tsx +++ b/src/modules/explorer/components/SearchEndpoints.tsx @@ -85,7 +85,7 @@ const useStyles = makeStyles({ }) export const SearchEndpoints: React.FC<{ - endpoints: Array | undefined + endpoints: Array | undefined handleChange?: any }> = ({ endpoints, handleChange }) => { useStyles() @@ -111,7 +111,7 @@ export const SearchEndpoints: React.FC<{ endpoint.params.push(param) break case "pair": - item.children.map(child => { + item.children.map((child: any) => { const pairParam = { type: child.type, placeholder: child.name diff --git a/src/modules/explorer/components/aci/Fields.tsx b/src/modules/explorer/components/aci/Fields.tsx new file mode 100644 index 00000000..335994b2 --- /dev/null +++ b/src/modules/explorer/components/aci/Fields.tsx @@ -0,0 +1,511 @@ +import React from "react" +import assertNever from "assert-never" +import { Field, FieldArray, FieldProps, Form, Formik, useFormikContext } from "formik" +import type { token, tokenMap, tokenValueType } from "../../../../services/aci" +import { showName, getFieldName, allocateNewTokenCounter } from "../../../../services/aci" +import { styled, Typography } from "@material-ui/core" +import { ProposalFormInput } from "../ProposalFormInput" +import { Button } from "components/ui/Button" + +const Title = styled(Typography)({ + fontSize: 18, + fontWeight: 450 +}) + +function capitalizeFirstLetter(s: string): string { + return s.charAt(0).toUpperCase() + s.slice(1) +} +function RenderItem({ + token: token, + showTitle: showTitle +}: React.PropsWithoutRef<{ + token: token + showTitle: boolean +}>) { + // debugger + const { setFieldValue, getFieldProps } = useFormikContext>() + const counter: number = getFieldProps("counter").value + const fieldName = getFieldName(token.counter) + const fieldValue: tokenValueType = getFieldProps(fieldName).value + + try { + switch (token.type) { + case "bls12_381_fr": + case "bls12_381_g1": + case "bls12_381_g2": + case "chain_id": + case "key_hash": + case "key": + case "bytes": + case "address": + case "signature": + case "string": + case "contract": + case "int": + case "nat": + case "mutez": + case "timestamp": + case "sapling_transaction_deprecated": + case "sapling_transaction": + case "sapling_state": + return RenderInputField(token, fieldName, showTitle) + case "never": + case "unit": + return RenderConstant(token, showTitle) + case "bool": + return RenderCheckbox(token, fieldName, fieldValue, showTitle) + case "or": + return RenderSelection(token, fieldName, fieldValue, showTitle) + case "set": + case "list": + return RenderArray(token, fieldName, fieldValue, showTitle, counter, setFieldValue) + case "pair": + return RenderPair(token, showTitle) + case "map": + return RenderMap(token, fieldName, fieldValue, showTitle, counter, setFieldValue) + case "option": + return RenderOption(token, fieldName, fieldValue, showTitle) + case "lambda": + return RenderLambda(token, fieldName, showTitle) + case "ticket_deprecated": + case "ticket": + case "operation": + case "chest": + case "chest_key": + case "tx_rollup_l2_address": + case "constant": + case "big_map": + return RenderNonsupport(token) + default: + return assertNever(token.type) + } + } catch (e) { + return null + // return renderError((e as Error).message, true) + } +} + +function RenderInputField(token: token, fieldName: string, showTitle: boolean) { + return ( +
+ + + + {/* */} +
+ ) +} + +function RenderConstant(token: token, showTitle: boolean) { + return ( +
+ +
+

{capitalizeFirstLetter(token.type)}

+
+
+ ) +} + +// This can be improved with material checkbox +function RenderCheckbox(token: token, fieldName: string, values: tokenValueType, showTitle: boolean) { + if (typeof values !== "boolean") { + throw new Error("internal error: the value of bool is incorrect") + } else { + return ( +
+ +
+ {" "} + {capitalizeFirstLetter(`${values}`)} +
+
+ ) + } +} + +function RenderArray( + token: token, + fieldName: string, + elements: tokenValueType, + showTitle: boolean, + counter: number, + setFieldValue: (field: string, value: tokenValueType, shouldValidate?: boolean | undefined) => void +) { + if (!Array.isArray(elements)) { + throw new Error("internal error: the value of array is incorrect") + } + return ( +
+ + + {({ push, pop }) => { + return ( +
+ {elements && + elements.map((v, idx) => { + if (!("counter" in v)) { + throw new Error("internal error: the value of array is incorrect") + } + return ( +
+ +
+ ) + })} +
+ {elements && elements.length > 0 && ( + + )} + +
+
+ ) + }} +
+
+ ) +} + +function RenderPair(token: token, showTitle: boolean) { + return ( +
+ + { +
+ {token.children.map((v, idx) => { + return ( +
+ +
+ ) + })} +
+ } +
+ ) +} + +function RenderOption(token: token, fieldName: string, value: tokenValueType, showTitle: boolean) { + if (typeof value !== "string") { + throw new Error("internal error: the value of option is incorrect") + } + return ( +
+ + + + + + {value == "some" ? :
} +
+ ) +} + +function RenderLambda(token: token, fieldName: string, showTitle: boolean) { + return ( +
+ + + {/* */} +
+ ) +} + +function RenderNonsupport(token: token) { + return ( +
+ {`Type, ${token.type}, isn't supported as a user input`} +
+ ) +} + +function RenderMap( + token: token, + fieldName: string, + elements: tokenValueType, + showTitle: boolean, + counter: number, + setFieldValue: (field: string, value: tokenValueType, shouldValidate?: boolean | undefined) => void +) { + if (!Array.isArray(elements)) { + throw new Error("internal: the value of array is incorrect") + } + return ( +
+ + + {({ push, pop }) => { + return ( +
+ {elements && + elements.map((element, idx) => { + if ("counter" in element) { + throw new Error("internal error: the value of array is incorrect") + } + return ( +
+ + +
+ ) + })} +
+ {elements && elements.length > 0 && ( + + )} + +
+
+ ) + }} +
+
+ ) +} + +function RenderSelection(token: token, fieldName: string, selected: tokenValueType, showTitle: boolean) { + const { setFieldValue, setFieldError } = useFormikContext() + + const defaultChildToken = token.children.length > 0 ? token.children[0] : undefined + const childToken = + token.children.find(x => { + return selected && x.name == selected + }) || defaultChildToken + + // console.log("OldSelectToken", token) + + return ( +
+ {showTitle && showName(token.type, token.name)} + + {({ field }: FieldProps) => ( + + + + )} + + {childToken ? :
} +
+ ) + + // return ( + //
+ // + // + // {({ field }: FieldProps) => ( + // + // )} + // + // {childToken ? :
} + //
+ // ) +} + +export { + RenderInputField, + RenderConstant, + RenderCheckbox, + RenderArray, + RenderPair, + RenderMap, + RenderOption, + RenderLambda, + RenderNonsupport, + RenderItem, + RenderSelection +} diff --git a/src/modules/explorer/utils/contract.ts b/src/modules/explorer/utils/contract.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/services/aci/endpoint.ts b/src/services/aci/endpoint.ts new file mode 100644 index 00000000..ec4875b4 --- /dev/null +++ b/src/services/aci/endpoint.ts @@ -0,0 +1,361 @@ +import { TezosToolkit } from "@taquito/taquito" +import { validateAddress, encodePubKey, encodeKey, encodeKeyHash } from "@taquito/utils" +import { TokenSchema, Schema } from "@taquito/michelson-encoder" +import { rpcNodes } from "services/beacon" +import { assertNever } from "assert-never" +import type { token, tokenValueType } from "." +import type { MichelineMichelsonV1Expression } from "@airgap/beacon-sdk" + +function getFieldName(id: any): string { + return `input-${id.toString()}` +} + +function initTokenTable(init: any, counter: any, defaultInit: tokenValueType = "") { + init[getFieldName(counter)] = defaultInit +} + +function parseSchema(counter: number, token: TokenSchema, init: Record, name?: string): [token, number] { + switch (token.__michelsonType) { + case "bls12_381_fr": + case "bls12_381_g1": + case "bls12_381_g2": + case "chain_id": + case "key_hash": + case "key": + case "bytes": + case "signature": + case "string": + initTokenTable(init, counter) + return [ + { + counter, + name, + type: token.__michelsonType, + children: [], + placeholder: token.__michelsonType, + initValue: "" + }, + counter + ] + case "address": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + placeholder: token.__michelsonType, + validate(value) { + if (validateAddress(value) !== 3) { + return `invalid address ${value}` + } + }, + initValue: "" + }, + counter + ] + case "contract": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + placeholder: "contract", + validate(value) { + if (validateAddress(value) !== 3) { + return `invalid address ${value}` + } + }, + initValue: "" + }, + counter + ] + case "bool": + initTokenTable(init, counter, false) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + placeholder: token.__michelsonType, + initValue: false + }, + counter + ] + case "int": + case "nat": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + placeholder: token.__michelsonType, + validate(value) { + if (value && isNaN(Number(value))) { + return `Invalid number, got: ${value}` + } + }, + initValue: "" + }, + counter + ] + case "mutez": + case "timestamp": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + placeholder: token.__michelsonType, + validate(value) { + const n = Number(value) + if (isNaN(n)) { + return `Invalid number, got: ${value}` + } + if (n < 0) { + return `Number should be greater or equal to 0, got ${value}` + } + }, + initValue: "" + }, + counter + ] + case "never": + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + initValue: "" + }, + counter + ] + case "operation": + throw new Error("can't happen: operation is forbidden in the parameter") + case "chest": + case "chest_key": + throw new Error( + "can't happen(Tezos bug): time lock related instructions is disabled in the client because of a vulnerability" + ) + case "unit": + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + initValue: "" + }, + counter + ] + case "tx_rollup_l2_address": + throw new Error("can't happen: this type has been disable") + case "or": { + const schemas = Object.entries(token.schema) + let new_counter = counter + const children: token[] = [] + let child + schemas.forEach(([k, v]) => { + ;[child, new_counter] = parseSchema(new_counter + 1, v, init, k) + children.push(child) + }) + initTokenTable(init, counter, schemas[0][0]) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children, + initValue: schemas[0][0] + }, + new_counter + ] + } + case "set": + case "list": { + initTokenTable(init, counter, []) + const [child, new_counter] = parseSchema(counter + 1, token.schema, init) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [child], + initValue: [] + }, + new_counter + ] + } + case "pair": { + const schemas = Object.entries(token.schema) + let new_counter = counter + const children: token[] = [] + let child + schemas.forEach(([k, v]) => { + ;[child, new_counter] = parseSchema(new_counter + 1, v, init, k) + children.push(child) + }) + initTokenTable(init, counter, []) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children, + initValue: [] + }, + new_counter + ] + } + case "map": + case "big_map": { + const schemas = Object.entries(token.schema) + let new_counter = counter + const children: token[] = [] + let child + schemas.forEach(([k, v]) => { + ;[child, new_counter] = parseSchema(new_counter + 1, v, init, k) + children.push(child) + }) + initTokenTable(init, counter, []) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children, + initValue: [] + }, + new_counter + ] + } + case "option": { + const [child, new_counter] = parseSchema(counter + 1, token.schema, init) + + initTokenTable(init, counter, "none") + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [child], + initValue: "none" + }, + new_counter + ] + } + case "constant": + throw new Error("can't happen: constant will never be in parameter") + case "lambda": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + placeholder: "lambda", + children: [], + initValue: "" + }, + counter + ] + case "sapling_transaction_deprecated": + case "sapling_transaction": + case "sapling_state": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + placeholder: token.__michelsonType + " " + token.schema.memoSize, + children: [], + initValue: "" + }, + counter + ] + case "ticket_deprecated": + case "ticket": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + initValue: "" + }, + counter + ] + default: + return assertNever(token as never) + } +} + +async function parseContractScript(c: any, initTokenTable: Record) { + let token, + counter = 0 + const entryponts = Object.entries(c.entrypoints.entrypoints).reverse() + if (entryponts.length == 0) { + ;[token, counter] = parseSchema(0, c.parameterSchema.generateSchema(), initTokenTable, "entrypoint") + console.log("Token:", token) + } else { + console.log("Case 2") + // handle the case of multiple entrypoints + const childrenToken = [] + let childToken + let init + let setInit = false + for (let i = 0; i < entryponts.length; i++) { + const [entrypoint, type] = entryponts[i] + const schema = new Schema(type as MichelineMichelsonV1Expression).generateSchema() + if (schema.__michelsonType !== "or") { + if (!setInit) { + init = entrypoint + setInit = true + } + let new_counter + ;[childToken, new_counter] = parseSchema(counter, schema, initTokenTable, entrypoint) + counter = new_counter + 1 + childrenToken.push(childToken) + } + } + counter = counter + 1 + if (typeof init === "undefined") throw new Error("internal error: initial entrypoint is undefined") + token = { + counter, + name: "entrypoint", + type: "or", + children: childrenToken, + initValue: init + } + initTokenTable[getFieldName(token.counter)] = token.initValue + } + initTokenTable["counter"] = counter + return token +} + +async function getContractEndpoints(network: string, contractAddress: string) { + try { + const tezosNetwork = network === "ghostnet" ? "ghostnet" : "mainnet" + const tezos = new TezosToolkit(rpcNodes[tezosNetwork]) + const contract = await tezos.contract.at(contractAddress) + const endpoints = await parseContractScript(contract, {}) + console.log("Endpoints:", endpoints) + return [endpoints, null] + } catch (error) { + console.error("Error fetching contract:", error) + return [null, error] + } +} + +export { getContractEndpoints } diff --git a/src/services/aci/index.ts b/src/services/aci/index.ts new file mode 100644 index 00000000..33d48798 --- /dev/null +++ b/src/services/aci/index.ts @@ -0,0 +1,681 @@ +import { emitMicheline, Parser } from "@taquito/michel-codec" +import { MichelsonMap } from "@taquito/taquito" +import { validateAddress } from "@taquito/utils" + +import { assertNever } from "assert-never" +import { BigNumber } from "bignumber.js" + +import { Schema } from "@taquito/michelson-encoder" +import type { MichelineMichelsonV1Expression } from "@airgap/beacon-sdk" +import type { TokenSchema } from "@taquito/michelson-encoder" + +type version = "1.0.0" | "unknown version" + +type michelsonType = + | "address" + | "bool" + | "bytes" + | "int" + | "key" + | "key_hash" + | "mutez" + | "nat" + | "string" + | "timestamp" + | "bls12_381_fr" + | "bls12_381_g1" + | "bls12_381_g2" + | "chain_id" + | "never" + | "operation" + | "chest" + | "chest_key" + | "signature" + | "unit" + | "tx_rollup_l2_address" + | "or" + | "pair" + | "list" + | "set" + | "option" + | "map" + | "big_map" + | "constant" + | "contract" + | "lambda" + | "sapling_state" + | "sapling_transaction" + | "sapling_transaction_deprecated" + | "ticket" + | "ticket_deprecated" + +export type tokenMap = Record<"key" | "value", token> + +export type tokenValueType = string | boolean | number | token | token[] | tokenMap[] + +export type token = { + counter: number + name?: string + type: michelsonType + children: token[] + placeholder?: string + validate?: (value: string) => string | undefined + initValue: tokenValueType +} + +export type makeContractExecutionParam = { + address: string + entrypoint: string + type: string + amount: number + param: string +} + +function generateExecuteContractMichelson( + version: version, + { address, entrypoint, type, amount, param }: makeContractExecutionParam +) { + let michelsonEntrypoint = "" + if (entrypoint !== "default") { + michelsonEntrypoint = `%${entrypoint}` + } + console.log("Lambda Generate", { address, entrypoint, type, amount, param }) + if (version === "1.0.0") { + return `{ + DROP; + NIL operation ; + PUSH address "${address}"; + CONTRACT ${michelsonEntrypoint} ${type}; + IF_NONE { PUSH string "contract dosen't exist"; FAILWITH } { }; + PUSH mutez ${amount}; + PUSH ${type} ${param} ; + TRANSFER_TOKENS ; + CONS ; + }` + } else if (version !== "unknown version") { + return `{ + DROP; + PUSH address "${address}"; + CONTRACT ${michelsonEntrypoint} ${type}; + IF_NONE { PUSH string "contract dosen't exist"; FAILWITH } { }; + PUSH mutez ${amount}; + PUSH ${type} ${param} ; + TRANSFER_TOKENS ; + }` + } + + throw new Error("Can't generate for an unknow version") +} + +function showName(type: string, name?: string) { + if (name && isNaN(Number(name))) { + return `${name} : ${type}` + } else { + return type + } +} + +function getFieldName(id: number): string { + return `input-${id.toString()}` +} + +function initTokenTable(init: Record, counter: number, defaultInit: tokenValueType = ""): void { + init[getFieldName(counter)] = defaultInit +} + +function parseSchema( + counter: number, + token: TokenSchema, + init: Record, + name?: string +): [token, number] { + switch (token.__michelsonType) { + case "bls12_381_fr": + case "bls12_381_g1": + case "bls12_381_g2": + case "chain_id": + case "key_hash": + case "key": + case "bytes": + case "signature": + case "string": + initTokenTable(init, counter) + return [ + { + counter, + name, + type: token.__michelsonType, + children: [], + placeholder: token.__michelsonType, + initValue: "" + }, + counter + ] + case "address": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + placeholder: token.__michelsonType, + validate(value: string): string | undefined { + if (validateAddress(value) !== 3) { + return `invalid address ${value}` + } + }, + initValue: "" + }, + counter + ] + case "contract": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + placeholder: "contract", + validate(value: string): string | undefined { + if (validateAddress(value) !== 3) { + return `invalid address ${value}` + } + }, + initValue: "" + }, + counter + ] + case "bool": + initTokenTable(init, counter, false) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + placeholder: token.__michelsonType, + initValue: false + }, + counter + ] + case "int": + case "nat": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + placeholder: token.__michelsonType, + validate(value: string): string | undefined { + if (value && isNaN(Number(value))) { + return `Invalid number, got: ${value}` + } + }, + initValue: "" + }, + counter + ] + case "mutez": + case "timestamp": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + placeholder: token.__michelsonType, + validate(value: string): string | undefined { + const n = Number(value) + if (isNaN(n)) { + return `Invalid number, got: ${value}` + } + if (n < 0) { + return `Number should be greater or equal to 0, got ${value}` + } + }, + initValue: "" + }, + counter + ] + case "never": + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + initValue: "" + }, + counter + ] + case "operation": + throw new Error("can't happen: operation is forbidden in the parameter") + case "chest": + case "chest_key": + throw new Error( + "can't happen(Tezos bug): time lock related instructions is disabled in the client because of a vulnerability" + ) + case "unit": + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + initValue: "" + }, + counter + ] + case "tx_rollup_l2_address": + throw new Error("can't happen: this type has been disable") + case "or": { + const schemas = Object.entries(token.schema) + let new_counter = counter + const children: token[] = [] + let child: token + schemas.forEach(([k, v]) => { + ;[child, new_counter] = parseSchema(new_counter + 1, v, init, k) + children.push(child) + }) + initTokenTable(init, counter, schemas[0][0]) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children, + initValue: schemas[0][0] + }, + new_counter + ] + } + case "set": + case "list": { + initTokenTable(init, counter, [] as token[]) + const [child, new_counter] = parseSchema(counter + 1, token.schema, init) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [child], + initValue: [] as token[] + }, + new_counter + ] + } + case "pair": { + const schemas = Object.entries(token.schema) + let new_counter = counter + const children: token[] = [] + let child: token + schemas.forEach(([k, v]) => { + ;[child, new_counter] = parseSchema(new_counter + 1, v, init, k) + children.push(child) + }) + initTokenTable(init, counter, []) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children, + initValue: [] + }, + new_counter + ] + } + case "map": + case "big_map": { + const schemas = Object.entries(token.schema) + let new_counter = counter + const children: token[] = [] + let child: token + schemas.forEach(([k, v]) => { + ;[child, new_counter] = parseSchema(new_counter + 1, v, init, k) + children.push(child) + }) + initTokenTable(init, counter, []) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children, + initValue: [] + }, + new_counter + ] + } + case "option": { + const [child, new_counter] = parseSchema(counter + 1, token.schema, init) + + initTokenTable(init, counter, "none") + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [child], + initValue: "none" + }, + new_counter + ] + } + case "constant": + throw new Error("can't happen: constant will never be in parameter") + case "lambda": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + placeholder: "lambda", + children: [], + initValue: "" + }, + counter + ] + case "sapling_transaction_deprecated": + case "sapling_transaction": + case "sapling_state": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + placeholder: token.__michelsonType + " " + token.schema.memoSize, + children: [], + initValue: "" + }, + counter + ] + case "ticket_deprecated": + case "ticket": + initTokenTable(init, counter) + return [ + { + counter: counter, + name, + type: token.__michelsonType, + children: [], + initValue: "" + }, + counter + ] + default: + return assertNever(token) + } +} +function evalTaquitoParam(token: token, tableValue: Record): any { + switch (token.type) { + case "bls12_381_fr": + case "bls12_381_g1": + case "bls12_381_g2": + case "chain_id": + case "key_hash": + case "key": + case "bytes": + case "address": + case "signature": + case "string": + case "contract": + return tableValue[getFieldName(token.counter)] + case "bool": + return tableValue[getFieldName(token.counter)] + case "int": + case "nat": + case "mutez": + case "timestamp": { + const value = tableValue[getFieldName(token.counter)] + if (typeof value !== "string") + throw new Error(`The value get from UI should be in string, ${showName(token.type, token.name)}`) + if (!value) { + throw new Error(`Incorrect or empty value, ${showName(token.type, token.name)}`) + } + return new BigNumber(value) + } + case "never": + return undefined + case "operation": + throw new Error("can't happen: operation is forbidden in the parameter") + case "chest": + case "chest_key": + throw new Error( + "can't happen(Tezos bug): time lock related instructions is disabled in the client because of a vulnerability" + ) + case "unit": + return [["unit"]] + case "tx_rollup_l2_address": + throw new Error("can't happen: this type has been disabled") + case "or": { + const key = tableValue[getFieldName(token.counter)] + const child = key && token.children.find(x => x.name == key) + if (!child) { + throw new Error(`the selection ${key} doesn't exist`) + } + const value = evalTaquitoParam(child, tableValue) + return Object.fromEntries([[key, value]]) + } + case "set": + case "list": { + const values = tableValue[getFieldName(token.counter)] + if (!Array.isArray(values)) { + throw new Error(`internal error: the expected type of list or set is incorrect.`) + } + return values + .map(v => { + if ("counter" in v) { + return evalTaquitoParam(v, tableValue) + } else { + throw new Error(`internal error: the expected type of element of list or set is incorrect.`) + } + }) + .filter(v => v !== undefined) + } + case "pair": { + const raw: token[] = token.children + const values = raw.map((v, idx) => { + const check_key = isNaN(Number(v.name)) + return [check_key ? v.name : idx, evalTaquitoParam(v, tableValue)] + }) + return Object.fromEntries(values) as object + } + case "map": + case "big_map": { + const values = tableValue[getFieldName(token.counter)] + if (!Array.isArray(values)) { + throw new Error(`internal error: the expected type of map is incorrect.`) + } + const map = new MichelsonMap() + values.map(v => { + if ("counter" in v) { + throw new Error(`internal error: the expected type of element of list or set is incorrect.`) + } else { + map.set(evalTaquitoParam(v.key, tableValue), evalTaquitoParam(v.value, tableValue)) + } + }) + return map + } + case "option": { + const values = tableValue[getFieldName(token.counter)] + if (typeof values !== "string") { + throw new Error(`internal error: the expected value of option is incorrect.`) + } + if (values === "some") { + return evalTaquitoParam(token.children[0], tableValue) + } else { + return null + } + } + case "constant": + throw new Error("can't happen: constant will never be in parameter") + case "lambda": { + const values = tableValue[getFieldName(token.counter)] + if (typeof values !== "string") { + throw new Error(`internal error: the expected value of lambda is incorrect.`) + } + const p = new Parser() + return p.parseMichelineExpression(values) + } + case "sapling_transaction_deprecated": + case "sapling_transaction": + case "sapling_state": + return tableValue[getFieldName(token.counter)] + case "ticket_deprecated": + case "ticket": + return tableValue[getFieldName(token.counter)] + default: + return assertNever(token.type) + } +} + +function genLambda( + version: version, + props: { + address: string + amount: number + shape: any + reset: () => void + setField: (lambda: string, metadata: string) => void + setLoading: (x: boolean) => void + setState: (shape: any) => void + loading: boolean + }, + values: any +) { + let entrypoint = "default" + let taquitoParam + + const taquitoFullParam = evalTaquitoParam(props.shape.token, values) + console.log("token", props.shape.token, values, taquitoFullParam) + console.log("props shape", props.shape) + if (props.shape.contract.parameterSchema.isMultipleEntryPoint) { + const p = Object.entries(taquitoFullParam) + if (p.length !== 1) { + throw new Error("should only one entrypoint is selected") + } + ;[entrypoint, taquitoParam] = p[0] + } else { + taquitoParam = taquitoFullParam + } + const param = emitMicheline( + props.shape.contract.methodsObject[entrypoint](taquitoParam).toTransferParams().parameter.value + ) + + const micheline_type = props.shape.contract.parameterSchema.isMultipleEntryPoint + ? props.shape.contract.entrypoints.entrypoints[entrypoint] + : props.shape.contract.parameterSchema.root.val + const p = new Parser() + const type = emitMicheline(p.parseJSON(micheline_type), { + indent: "", + newline: "" + }) + + // This functione executes on client side + const lambda = generateExecuteContractMichelson(version, { + address: props.address, + entrypoint, + type, + amount: props.amount, + param + }) + console.log({ lambda }) + + props.setField( + lambda, + JSON.stringify( + { + contract_addr: props.address, + mutez_amount: props.amount, + entrypoint, + payload: param + }, + null, + 2 + ) + ) + props.setLoading(false) +} + +function allocateNewTokenCounter( + token: token, + counter: number, + setFieldValue: (field: string, value: any, shouldValidate?: boolean | undefined) => void +): number { + let new_counter = counter + token.children.forEach((v, i) => { + new_counter = allocateNewTokenCounter(v, new_counter, setFieldValue) + new_counter = new_counter + 1 + v.counter = new_counter + setFieldValue(getFieldName(v.counter), v.initValue) + }) + return new_counter +} + +function parseContract(c: any, initTokenTable: Record) { + let token: token + let counter = 0 + // reverse the elements so the order of entrypoints will be in alphabet + const entryponts = Object.entries(c.entrypoints.entrypoints).reverse() + if (entryponts.length == 0) { + // handle the case of only "default" entrypoint + ;[token, counter] = parseSchema(0, c.parameterSchema.generateSchema(), initTokenTable, "entrypoint") + } else { + // handle the case of multiple entrypoints + const childrenToken: token[] = [] + let childToken + let init + let setInit = false + for (let i = 0; i < entryponts.length; i++) { + const [entrypoint, type] = entryponts[i] + const schema = new Schema(type as MichelineMichelsonV1Expression).generateSchema() + /** If the michelson type is "or", it means it's a nested entrypoint. + * The entrypoint is repeated. Therefore, don't make it as a child. + */ + if (schema.__michelsonType !== "or") { + /** + * Chose default value for selection component. + * Pick up the first non-nested entrypoint. + */ + if (!setInit) { + init = entrypoint + setInit = true + } + let new_counter + ;[childToken, new_counter] = parseSchema(counter, schema, initTokenTable, entrypoint) + counter = new_counter + 1 + childrenToken.push(childToken) + } + } + counter = counter + 1 + if (typeof init === "undefined") throw new Error("internal error: initial entrypoint is undefined") + token = { + counter, + name: "entrypoint", + type: "or", + children: childrenToken, + initValue: init + } + initTokenTable[getFieldName(token.counter)] = token.initValue + } + initTokenTable["counter"] = counter + return token +} + +export { + getFieldName, + evalTaquitoParam, + generateExecuteContractMichelson, + parseContract, + genLambda, + showName, + allocateNewTokenCounter +} diff --git a/src/services/beacon/utils.ts b/src/services/beacon/utils.ts index 179ae0ff..c9779ed9 100644 --- a/src/services/beacon/utils.ts +++ b/src/services/beacon/utils.ts @@ -10,7 +10,7 @@ export const ALICE_PRIV_KEY = "edsk3QoqBuvdamxouPhin7swCvkQNgq4jP5KZPbwWNnwdZpSp export const rpcNodes: Record = { mainnet: "https://mainnet.api.tez.ie", - ghostnet: "https://ghostnet.tezos.marigold.dev" + ghostnet: "https://ghostnet.smartpy.io" } export const getTezosNetwork = (): Network => { diff --git a/src/services/contracts/baseDAO/hooks/useLambdaExecutePropose.ts b/src/services/contracts/baseDAO/hooks/useLambdaExecutePropose.ts index bab4818d..53ac5fb2 100644 --- a/src/services/contracts/baseDAO/hooks/useLambdaExecutePropose.ts +++ b/src/services/contracts/baseDAO/hooks/useLambdaExecutePropose.ts @@ -18,6 +18,7 @@ export const useLambdaExecutePropose = () => { { dao: LambdaDAO; args: LambdaExecuteArgs; handleClose: () => void } >( async ({ dao, args, handleClose }) => { + // debugger const { key: proposalNotification, closeSnackbar: closeProposalNotification } = openNotification({ message: "Proposal is being created...", persist: true, @@ -30,6 +31,7 @@ export const useLambdaExecutePropose = () => { tezosToolkit = await connect() } + // debugger const data = await dao.proposeLambdaExecute(args, tezosToolkit) mixpanel.track("Proposal Created", { diff --git a/src/services/contracts/baseDAO/lambdaDAO/index.ts b/src/services/contracts/baseDAO/lambdaDAO/index.ts index b4580893..8319cb39 100644 --- a/src/services/contracts/baseDAO/lambdaDAO/index.ts +++ b/src/services/contracts/baseDAO/lambdaDAO/index.ts @@ -199,6 +199,13 @@ export class LambdaDAO extends BaseDAO { return await contractMethod.send() } + /** + * This function sets of lambda in proposal to be executed + * @param param0 + * @param tezos + * @returns any + * + */ public async proposeLambdaExecute( { handler_name, agoraPostId, handler_code, handler_params, lambda_arguments }: LambdaExecuteArgs, tezos: TezosToolkit diff --git a/yarn.lock b/yarn.lock index a6a9d403..10a45b2d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2830,6 +2830,13 @@ dependencies: json-stringify-safe "^5.0.1" +"@taquito/core@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@taquito/core/-/core-20.0.0.tgz#9f371bb398338a04f5e29bd004cf213fda3e7a43" + integrity sha512-JSDWLaVeaSqI98Xwd2TQwNy/fznSLEhikUxM7da6WbGJGtH8lG9SI9q6N9LLPfOFNGlP5RVQLO9HK/Pcmn4H8Q== + dependencies: + json-stringify-safe "^5.0.1" + "@taquito/http-utils@^17.5.2": version "17.5.2" resolved "https://registry.yarnpkg.com/@taquito/http-utils/-/http-utils-17.5.2.tgz#2fa1ac5fd4d2e02603eafe052d27b9c39938d7fc" @@ -2854,6 +2861,13 @@ dependencies: "@taquito/core" "^17.5.2" +"@taquito/michel-codec@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@taquito/michel-codec/-/michel-codec-20.0.0.tgz#c7d4831e3875dfbbd43ea02b7c0628ce76cae1b0" + integrity sha512-Xe6zHI8d5o/v9xNFJSvtspMK9Zf/iPDgUU7mIbucF/ppAYm1pofm5zL4SY5+tK0/Xz7irXjVx0a5l2sgGCBZmQ== + dependencies: + "@taquito/core" "^20.0.0" + "@taquito/michelson-encoder@^17.5.2": version "17.5.2" resolved "https://registry.yarnpkg.com/@taquito/michelson-encoder/-/michelson-encoder-17.5.2.tgz#ed97b6b13c18f15af6c703065cbb79d18b1fb6d0" @@ -4484,6 +4498,11 @@ asn1.js@^4.10.1: inherits "^2.0.1" minimalistic-assert "^1.0.0" +assert-never@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/assert-never/-/assert-never-1.2.1.tgz#11f0e363bf146205fb08193b5c7b90f4d1cf44fe" + integrity sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw== + assert@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/assert/-/assert-2.1.0.tgz#6d92a238d05dc02e7427c881fb8be81c8448b2dd" @@ -13066,7 +13085,7 @@ string-natural-compare@^3.0.1: resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -13083,6 +13102,15 @@ string-width@^2.0.0, string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -13170,7 +13198,7 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -13184,6 +13212,13 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -14634,7 +14669,16 @@ workbox-window@6.6.1: "@types/trusted-types" "^2.0.2" workbox-core "6.6.1" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==