Skip to content

Commit

Permalink
feat(payload): #24 multiple send restored + memo fast implementation … (
Browse files Browse the repository at this point in the history
#35)

* feat(payload): #24 multiple send restored + memo fast implementation (usestate)

* chore(payload): docs for #24 execute multi added
  • Loading branch information
dimkk authored May 4, 2022
1 parent 61897df commit 08bbd1e
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 102 deletions.
20 changes: 7 additions & 13 deletions apps/payload/src/auth/hooks/useAuth.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import { useCallback, useMemo } from "react"
import { atom, useRecoilState } from "recoil"
import { encode } from "js-base64"
import { CreateTxOptions, Tx, isTxError } from "@terra-money/terra.js"
import { AccAddress, SignDoc } from "@terra-money/terra.js"
import { MnemonicKey, RawKey, SignatureV2 } from "@terra-money/terra.js"
import { LedgerKey } from "@terra-money/ledger-terra-js"
import { useChainID } from "data/wallet"
import { AccAddress, CreateTxOptions, isTxError, MnemonicKey, RawKey, SignatureV2, SignDoc, Tx } from "@terra-money/terra.js"
import { useLCDClient } from "data/queries/lcdClient"
import is from "../scripts/is"
import { PasswordError } from "../scripts/keystore"
import { getDecryptedKey, testPassword } from "../scripts/keystore"
import { getWallet, storeWallet } from "../scripts/keystore"
import { clearWallet, lockWallet } from "../scripts/keystore"
import { getStoredWallet, getStoredWallets } from "../scripts/keystore"
import { useChainID } from "data/wallet"
import { encode } from "js-base64"
import { useCallback, useMemo } from "react"
import { atom, useRecoilState } from "recoil"
import encrypt from "../scripts/encrypt"
import is from "../scripts/is"
import { clearWallet, getDecryptedKey, getStoredWallet, getStoredWallets, getWallet, lockWallet, PasswordError, storeWallet, testPassword } from "../scripts/keystore"
import useAvailable from "./useAvailable"

const walletState = atom({
Expand Down
70 changes: 33 additions & 37 deletions apps/payload/src/outpost/components/Tx.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,43 @@
import { Fragment, ReactNode } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { QueryKey, useQuery } from "react-query";
import { useNavigate } from "react-router-dom";
import { useRecoilValue, useSetRecoilState } from "recoil";
import classNames from "classnames";
import BigNumber from "bignumber.js";
import { head, isNil } from "ramda";

import AccountBalanceWalletIcon from "@mui/icons-material/AccountBalanceWallet";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import { Coin, Coins, CreateTxOptions, Fee, LCDClient } from "@terra-money/terra.js";
import { ConnectType, CreateTxFailed, TxFailed, useConnectedWallet, UserDenied, useWallet } from "@terra-money/wallet-provider";
import { isDenom, isDenomIBC, readDenom } from "@terra.kitchen/utils";
import { Coin, Coins, LCDClient } from "@terra-money/terra.js";
import { CreateTxOptions, Fee } from "@terra-money/terra.js";
import { ConnectType, UserDenied } from "@terra-money/wallet-provider";
import { CreateTxFailed, TxFailed } from "@terra-money/wallet-provider";
import { useWallet, useConnectedWallet } from "@terra-money/wallet-provider";

import { Contents } from "types/components";
import { DEFAULT_GAS_ADJUSTMENT } from "config/constants";
import { has } from "utils/num";
import { getAmount, sortCoins } from "utils/coin";
import { getErrorMessage } from "utils/error";
import { useCurrency } from "data/settings/Currency";
import { queryKey, RefetchOptions } from "data/query";
import { useAddress, useNetwork } from "data/wallet";
import { isBroadcastingState, latestTxState } from "data/queries/tx";
import { useBankBalance, useIsWalletEmpty } from "data/queries/bank";

import ConnectWallet from "app/sections/ConnectWallet";
import { isWallet, useAuth } from "auth";
import { PasswordError } from "auth/scripts/keystore";
import BigNumber from "bignumber.js";
import classNames from "classnames";
import { Details } from "components/display";
import { Modal } from "components/feedback";
import { FormError, FormItem, Input, Select, Submit } from "components/form";
import { Pre } from "components/general";
import { Flex, Grid } from "components/layout";
import { FormError, Submit, Select, Input, FormItem } from "components/form";
import { Modal } from "components/feedback";
import { Details } from "components/display";
import { Read } from "components/token";
import ConnectWallet from "app/sections/ConnectWallet";
import { DEFAULT_GAS_ADJUSTMENT } from "config/constants";
import { useBankBalance, useIsWalletEmpty } from "data/queries/bank";
import { isBroadcastingState, latestTxState } from "data/queries/tx";
import { queryKey, RefetchOptions } from "data/query";
import { useCurrency } from "data/settings/Currency";
import { useAddress, useNetwork } from "data/wallet";
import useToPostMultisigTx from "pages/multisig/utils/useToPostMultisigTx";
import { isWallet, useAuth } from "auth";
import { PasswordError } from "auth/scripts/keystore";

import styles from "./Tx.module.scss";
import { head, isNil } from "ramda";
import { Fragment, ReactNode, useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { QueryKey, useQuery } from "react-query";
import { useNavigate } from "react-router-dom";
import { useRecoilValue, useSetRecoilState } from "recoil";
import { useTx } from "txs/TxContext";
import { toInput } from "txs/utils";
import { Contents } from "types/components";
import { getAmount, sortCoins } from "utils/coin";
import { getErrorMessage } from "utils/error";
import { has } from "utils/num";
import styles from "./Tx.module.scss";





interface Props<TxValues> {
/* Only when the token is paid out of the balance held */
Expand Down Expand Up @@ -222,12 +218,12 @@ function Tx<TxValues>(props: Props<TxValues>) {
throw new Error("Fee is not estimated");

const tx = createTx(values);

console.log({tx});
if (!tx) throw new Error("Tx is not defined");

const gasCoins = new Coins([Coin.fromData(gasFee)]);
const fee = new Fee(estimatedGas, gasCoins);

if (isWallet.multisig(wallet)) {
const unsignedTx = await auth.create({ ...tx, fee });
navigate(toPostMultisigTx(unsignedTx));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Button, Collapse } from '@mui/material';
import { ContractMessage, ContractMessageTypes } from '@outp0st/core';
import { ContractMessage, ContractMessageRenderModes, ContractMessageTypes } from '@outp0st/core';
import { useRO } from 'outpost/hooks/useRO';
import { useOutpostState } from 'outpost/state/useOutpostState';
import { FC, ReactNode } from 'react';
Expand All @@ -25,24 +25,24 @@ const generateButtons = (message: ContractMessage, updateMessage: any) => {
return buttons;
};

// const generateButtonsRender = (
// message: ContractMessage,
// updateMessage: any,
// ) => {
// let buttons: ReactNode[] = [];
// for (let item in ContractMessageRenderModes) {
// buttons.push(
// <Button
// key={item}
// variant={message.renderMode === item ? 'contained' : 'outlined'}
// onClick={() => updateMessage({ ...message, renderMode: item })}
// >
// {item}
// </Button>,
// );
// }
// return buttons;
// };
const generateButtonsRender = (
message: ContractMessage,
updateMessage: any,
) => {
let buttons: ReactNode[] = [];
for (let item in ContractMessageRenderModes) {
buttons.push(
<Button
key={item}
variant={message.renderMode === item ? 'contained' : 'outlined'}
onClick={() => updateMessage({ ...message, renderMode: item })}
>
{item}
</Button>,
);
}
return buttons;
};

// const generateButtonsMulti = (message: ContractMessage, updateMessage: any) => {
// let buttons: ReactNode[] = [];
Expand All @@ -68,11 +68,11 @@ const OutpostCardMessageBody: FC<OutpostCardMessageBodyProps> = ({
const ro = useRO();
return (
<Collapse in={!message.collapsed} timeout="auto" unmountOnExit>
{/* {!ro && (
{!ro && (
<BtnGroup label="Render mode">
{generateButtonsRender(message, updateMessage)}
</BtnGroup>
)} */}
)}
{!ro && (
<BtnGroup label="Message type">
{generateButtons(message, updateMessage)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface OutpostCardMessageRendererProps {
message: ContractMessage;
failMessage?: string | undefined;
validateError?: string | undefined;
placeholder?: string;
}

function OutpostCardMessageRenderer(props: OutpostCardMessageRendererProps) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ const OutpostMessageQuery = React.lazy(
const OutpostMessageExecute = React.lazy(
() => import('../../messages/OutpostMessageExecute'),
);
// const OutpostMessageExecuteMulti = React.lazy(
// () => import('../../messages/OutpostMessageExecuteMulti'),
// );
const OutpostMessageExecuteMulti = React.lazy(
() => import('../../messages/OutpostMessageExecuteMulti'),
);
const OutpostMessageInsta = React.lazy(
() => import('../../messages/OutpostMessageInsta'),
);
Expand Down Expand Up @@ -50,8 +50,8 @@ function GetMessageByType(message: ContractMessage) {
return <OutpostMessageQuery message={message} />;
case ContractMessageTypes.EXECUTE:
return <OutpostMessageExecute message={message} />;
// case ContractMessageTypes.EXECUTE_MULTI:
// return <OutpostMessageExecuteMulti message={message} />;
case ContractMessageTypes.EXECUTE_MULTI:
return <OutpostMessageExecuteMulti message={message} />;
case ContractMessageTypes.DOC:
return <OutpostMessageDoc message={message} />;
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ interface JsonRenderProps {
message: ContractMessage;
failMessage?: string | undefined;
validateError?: string | undefined;
placeholder?:string;
}

// function addNumbersToJsonString(noNumbersJsonString: string) {
// const parsed = parseJSON(noNumbersJsonString);

// }

function JsonRender({ message, failMessage, validateError }: JsonRenderProps) {
function JsonRender({ message, failMessage, validateError, placeholder }: JsonRenderProps) {
const { updateMessage } = useOutpostState();
let error: string = '';
if (validateError) error = `JSON error: ${validateError}`;
Expand All @@ -23,6 +24,7 @@ function JsonRender({ message, failMessage, validateError }: JsonRenderProps) {
<FormItem label="json msg" error={error}>
<EditorInput
value={message.message}
placeholder={placeholder}
onChange={e => {
updateMessage({ ...message, message: e.target.value });
}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { ContractMessage } from '@outp0st/core';
import { ContractMessage, ContractMessageTypes } from '@outp0st/core';
import { MsgExecuteContract } from '@terra-money/terra.js';
import { FormItem, Input } from 'components/form';
import { Button } from 'components/general';
import { useExecuteMessageCustom } from 'outpost/hooks/useExecuteMessageCustom';
import { validateMsg } from 'outpost/utils';
import { useState } from 'react';
// import Tx from "txs/Tx"
import TxContext from 'txs/TxContext';
import Tx from '../../Tx';
Expand All @@ -13,22 +16,22 @@ interface OutpostMessageExecuteMultiProps {
message: ContractMessage;
}

// interface CW20TransferMsg {
// transfer: {
// amount: string;
// recipient: string;
// };
// }
interface CW20TransferMsg {
transfer: {
amount: string;
recipient: string;
};
}

export default function OutpostMessageExecuteMulti({
message,
}: OutpostMessageExecuteMultiProps) {
const [memo, setMemo] = useState("");
const { tx } = useExecuteMessageCustom(
message,
// (address, contractAddress, exec_msg, coins)
() => {
(address, contractAddress, exec_msg, coins) => {
//console.log({ exec_msg });
let result: any[] = [];
let result_msgs: any[] = [];
// if (
// message.type === ContractMessageTypes.EXECUTE_MULTI &&
// message.multiType === ContractExecuteMultiMessageTypes.TRANSFER_LUV
Expand All @@ -48,29 +51,58 @@ export default function OutpostMessageExecuteMulti({
// coins,
// );
// });
// } else if (
// message.type === ContractMessageTypes.EXECUTE_MULTI &&
// message.multiType === ContractExecuteMultiMessageTypes.SIMPLE
// ) {
// const msgs: CW20TransferMsg[] = exec_msg;
// result = msgs.map(msg => {
// return new MsgExecuteContract(address, contractAddress, msg, coins);
// });
// }
//}
if (
message.type === ContractMessageTypes.EXECUTE_MULTI
// && message.multiType === ContractExecuteMultiMessageTypes.SIMPLE
) {
const msgs: CW20TransferMsg[] = exec_msg;
if (Array.isArray(msgs))
result_msgs = msgs.map(msg => {
return new MsgExecuteContract(address, contractAddress, msg, coins);
});
}
//console.log({ result });
return result;
return {memo, msgs:result_msgs};
},
);
const placeholderString = `
[
{
"transfer": {
"amount": "2000000",
"recipient": "terra1ejksjvfvzpcqzg88nfd82hx2cv7g7lj9gjz669"
}
},
{
"transfer": {
"amount": "2000000",
"recipient": "terra1ejksjvfvzpcqzg88nfd82hx2cv7g7lj9gjz669"
}
}
]
`
const validateError = validateMsg(message.message || '');
const finalTx = {...tx, memo}
return (
<TxContext>
<Tx {...tx}>
<Tx { ...finalTx }>
{({ fee, submit, failMessage, resultQuery, disabled }) => (
<Fetching {...resultQuery}>
<FormItem label="Memo">
<Input
placeholder="Can be empty"
value={memo}
onChange={e =>
setMemo(e.target.value)
}
/>
</FormItem>
<OutpostCardMessageRenderer
message={message}
failMessage={failMessage}
validateError={validateError}
placeholder={placeholderString}
/>

{fee.render()}
Expand Down
6 changes: 3 additions & 3 deletions apps/payload/src/outpost/hooks/useExecuteMessageCustom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function useExecuteMessageCustom(
contractAddress: string,
exec_msg: any,
coins: Coins,
) => any[],
) => {memo:string, msgs:any[]},
): any {
const { getContract } = useOutpostState();
const bankBalance = useBankBalance();
Expand All @@ -34,9 +34,9 @@ export function useExecuteMessageCustom(

const exec_msg = parseJSON(msg);
const coins = getCoins([defaultItem]);
const msgs = createMessagesFn(address, contractAddress!, exec_msg, coins); //[new MsgExecuteContract(address, contractAddress!, exec_msg, coins)];
const {memo, msgs} = createMessagesFn(address, contractAddress!, exec_msg, coins); //[new MsgExecuteContract(address, contractAddress!, exec_msg, coins)];

return { msgs };
return { memo, msgs };
}, [address, contractAddress, msg, initialGasDenom, createMessagesFn]);
const estimationTxValues = useMemo(
() => [msg, contractAddress],
Expand Down
6 changes: 6 additions & 0 deletions apps/web/docs/payload/ui/message.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ _Sometimes, we can't submit message - check the error message (often, it's not t

1. You can create Doc type message to document next step, or to indicate action
2. Click on Description text, to open/close markdown editor

## EXECUTE_MULTI
![Message execute multi](/outpost/OPMessageExecuteMulti.png)

1. You can arrange messages to execute them in one transaction
2. You can provide memo for this transaction
Binary file added apps/web/static/outpost/OPMessageExecuteMulti.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion packages/core/src/types/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export enum ContractExecuteMultiMessageTypes {
export enum ContractMessageTypes {
INSTA = 'INSTA',
EXECUTE = 'EXECUTE',
// EXECUTE_MULTI = 'EXECUTE_MULTI',
EXECUTE_MULTI = 'EXECUTE_MULTI',
QUERY = 'QUERY',
DOC = 'DOC',
}
Expand Down

0 comments on commit 08bbd1e

Please sign in to comment.