Skip to content

Commit

Permalink
Merge pull request #274 from alleslabs/pages/proposal-store-code
Browse files Browse the repository at this point in the history
Pages/proposal store code
  • Loading branch information
bkioshn authored May 8, 2023
2 parents cdbe870 + bcc9a91 commit 9cb6deb
Show file tree
Hide file tree
Showing 29 changed files with 1,150 additions and 104 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- [#274](https://github.com/alleslabs/celatone-frontend/pull/274) Add proposal to store code page
- [#279](https://github.com/alleslabs/celatone-frontend/pull/279) Add instantiate permission to msg store code, change error display design, and upgrade cosmjs to version 0.30.1

### Improvements
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@cosmjs/encoding": "^0.30.1",
"@cosmjs/proto-signing": "^0.30.1",
"@cosmjs/stargate": "^0.30.1",
"@cosmjs/crypto": "^0.30.1",
"@cosmos-kit/core": "^0.20.0",
"@cosmos-kit/keplr": "^0.20.0",
"@cosmos-kit/react": "^0.19.0",
Expand Down
1 change: 1 addition & 0 deletions src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export const MAX_FILE_SIZE = 800_000;

export const CELATONE_CONSTANTS: CelatoneConstants = {
gasAdjustment: 1.6,
maxGasLimit: 25_000_000,
maxFileSize: MAX_FILE_SIZE,
};

Expand Down
89 changes: 85 additions & 4 deletions src/lib/app-fns/tx/submitProposal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import { CustomIcon } from "lib/components/icon";
import { AmpEvent, AmpTrack } from "lib/services/amplitude";
import type { HumanAddr, TxResultRendering } from "lib/types";
import { TxStreamPhase } from "lib/types";
import { findAttr, formatUFee } from "lib/utils";
import { capitalize, findAttr, formatUFee } from "lib/utils";

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

interface SubmitProposalTxParams {
interface SubmitWhitelistProposalTxParams {
address: HumanAddr;
client: SigningCosmWasmClient;
onTxSucceed?: () => void;
Expand All @@ -24,7 +24,7 @@ interface SubmitProposalTxParams {
amountToVote: string | null;
}

export const submitProposalTx = ({
export const submitWhitelistProposalTx = ({
address,
client,
onTxSucceed,
Expand All @@ -33,7 +33,7 @@ export const submitProposalTx = ({
messages,
whitelistNumber,
amountToVote,
}: SubmitProposalTxParams): Observable<TxResultRendering> => {
}: SubmitWhitelistProposalTxParams): Observable<TxResultRendering> => {
return pipe(
sendingTx(fee),
postTx({
Expand Down Expand Up @@ -99,3 +99,84 @@ export const submitProposalTx = ({
}
)().pipe(catchTxError(onTxFailed));
};

interface SubmitStoreCodeProposalTxParams {
address: HumanAddr;
client: SigningCosmWasmClient;
fee: StdFee;
chainName: string;
wasmFileName: string;
messages: EncodeObject[];
amountToVote: string | null;
onTxSucceed?: () => void;
onTxFailed?: () => void;
}

export const submitStoreCodeProposalTx = ({
address,
client,
fee,
chainName,
wasmFileName,
messages,
amountToVote,
onTxSucceed,
onTxFailed,
}: SubmitStoreCodeProposalTxParams): Observable<TxResultRendering> => {
return pipe(
sendingTx(fee),
postTx({
postFn: () => client.signAndBroadcast(address, messages, fee),
}),
({ value: txInfo }) => {
AmpTrack(AmpEvent.TX_SUCCEED);
onTxSucceed?.();
const mimicLog: logs.Log = {
msg_index: 0,
log: "",
events: txInfo.events,
};
const txFee = findAttr(mimicLog, "tx", "fee");
const proposalId =
findAttr(mimicLog, "submit_proposal", "proposal_id") ?? "";
return {
value: null,
phase: TxStreamPhase.SUCCEED,
receipts: [
{
title: "Proposal ID",
value: proposalId,
html: <ExplorerLink type="proposal_id" value={proposalId} />,
},
{
title: "Tx Hash",
value: txInfo.transactionHash,
html: (
<ExplorerLink type="tx_hash" value={txInfo.transactionHash} />
),
},
{
title: "Tx Fee",
value: txFee ? formatUFee(txFee) : "N/A",
},
],
receiptInfo: {
header: "Proposal Submitted",
description: `${wasmFileName} is uploaded and pending ${
amountToVote
? ` minimum deposit of ${amountToVote} to trigger voting period.`
: ` ${capitalize(chainName)} governance voting.`
}`,
headerIcon: (
<CustomIcon
name="submit-proposal-solid"
color="pebble.600"
boxSize="5"
/>
),
},
actionVariant: "proposal",
} as TxResultRendering;
}
)().pipe(catchTxError(onTxFailed));
};
16 changes: 11 additions & 5 deletions src/lib/app-provider/hooks/useFabricateFee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ export const useFabricateFee = () => {

return useCallback(
(estimatedGas: number): StdFee => {
const adjustedGas = big(estimatedGas)
.mul(constants.gasAdjustment)
.toFixed(0);
const adjustedGas = Math.min(
Number(big(estimatedGas).mul(constants.gasAdjustment).toFixed(0)),
constants.maxGasLimit
);

return {
amount: [
Expand All @@ -22,9 +23,14 @@ export const useFabricateFee = () => {
amount: big(adjustedGas).mul(chainGasPrice.gasPrice).toFixed(0),
},
],
gas: adjustedGas as Gas<string>,
gas: adjustedGas.toString() as Gas<string>,
};
},
[chainGasPrice, constants.gasAdjustment]
[
chainGasPrice.denom,
chainGasPrice.gasPrice,
constants.gasAdjustment,
constants.maxGasLimit,
]
);
};
95 changes: 92 additions & 3 deletions src/lib/app-provider/queries/simulateFee.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Coin } from "@cosmjs/amino";
import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { useWallet } from "@cosmos-kit/react";
import { useQuery } from "@tanstack/react-query";
Expand All @@ -11,7 +12,7 @@ import type {
HumanAddr,
Option,
} from "lib/types";
import { composeStoreCodeMsg } from "lib/utils";
import { composeStoreCodeMsg, composeStoreCodeProposalMsg } from "lib/utils";

interface SimulateQueryParams {
enabled: boolean;
Expand Down Expand Up @@ -94,15 +95,15 @@ export const useSimulateFeeForStoreCode = ({
const client = await getCosmWasmClient();
if (!client) throw new Error("Fail to get client");

const submitStoreCodeProposalMsg = async () => {
const submitStoreCodeMsg = async () => {
return composeStoreCodeMsg({
sender: address as HumanAddr,
wasmByteCode: new Uint8Array(await wasmFile.arrayBuffer()),
permission,
addresses,
});
};
const craftMsg = await submitStoreCodeProposalMsg();
const craftMsg = await submitStoreCodeMsg();
return (await client.simulate(address, [craftMsg], undefined)) as Gas;
};
return useQuery({
Expand All @@ -122,3 +123,91 @@ export const useSimulateFeeForStoreCode = ({
onError,
});
};

interface SimulateQueryParamsForProposalStoreCode {
enabled: boolean;
title: string;
description: string;
runAs: Addr;
initialDeposit: Coin;
unpinCode: boolean;
builder: string;
source: string;
codeHash: string;
wasmFile: Option<File>;
permission: AccessType;
addresses: Addr[];
onSuccess?: (gas: Gas<number> | undefined) => void;
onError?: (err: Error) => void;
}

export const useSimulateFeeForProposalStoreCode = ({
enabled,
title,
description,
runAs,
initialDeposit,
unpinCode,
builder,
source,
codeHash,
wasmFile,
permission,
addresses,
onSuccess,
onError,
}: SimulateQueryParamsForProposalStoreCode) => {
const { address, getCosmWasmClient, currentChainName } = useWallet();

const simulateFn = async () => {
if (!address) throw new Error("Please check your wallet connection.");
if (!wasmFile) throw new Error("Fail to get Wasm file");

const client = await getCosmWasmClient();
if (!client) throw new Error("Fail to get client");

const submitStoreCodeProposalMsg = async () => {
return composeStoreCodeProposalMsg({
proposer: address as HumanAddr,
title,
description,
runAs: runAs as Addr,
wasmByteCode: new Uint8Array(await wasmFile.arrayBuffer()),
permission,
addresses,
unpinCode,
source,
builder,
codeHash: Uint8Array.from(Buffer.from(codeHash, "hex")),
initialDeposit,
});
};

const craftMsg = await submitStoreCodeProposalMsg();
return (await client.simulate(address, [craftMsg], undefined)) as Gas;
};

return useQuery({
queryKey: [
"simulate_fee_store_code_proposal",
currentChainName,
runAs,
initialDeposit,
unpinCode,
builder,
source,
codeHash,
wasmFile,
permission,
addresses,
enabled,
],
queryFn: async () => simulateFn(),
enabled,
retry: false,
refetchOnReconnect: false,
refetchOnWindowFocus: false,
onSuccess,
onError,
});
};
53 changes: 48 additions & 5 deletions src/lib/app-provider/tx/submitProposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import type { StdFee } from "@cosmjs/stargate";
import { useWallet } from "@cosmos-kit/react";
import { useCallback } from "react";

import { submitProposalTx } from "lib/app-fns/tx/submitProposal";
import {
submitStoreCodeProposalTx,
submitWhitelistProposalTx,
} from "lib/app-fns/tx/submitProposal";
import type { HumanAddr } from "lib/types";

export interface SubmitProposalStreamParams {
export interface SubmitWhitelistProposalStreamParams {
onTxSucceed?: () => void;
onTxFailed?: () => void;
estimatedFee?: StdFee;
Expand All @@ -15,7 +18,7 @@ export interface SubmitProposalStreamParams {
amountToVote: string | null;
}

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

return useCallback(
Expand All @@ -26,12 +29,12 @@ export const useSubmitProposalTx = () => {
messages,
whitelistNumber,
amountToVote,
}: SubmitProposalStreamParams) => {
}: SubmitWhitelistProposalStreamParams) => {
const client = await getCosmWasmClient();
if (!address || !client)
throw new Error("Please check your wallet connection.");
if (!estimatedFee) return null;
return submitProposalTx({
return submitWhitelistProposalTx({
address: address as HumanAddr,
client,
onTxSucceed,
Expand All @@ -45,3 +48,43 @@ export const useSubmitProposalTx = () => {
[address, getCosmWasmClient]
);
};

interface SubmitStoreCodeProposalStreamParams {
wasmFileName: string;
messages: EncodeObject[];
amountToVote: string | null;
estimatedFee?: StdFee;
onTxSucceed?: () => void;
onTxFailed?: () => void;
}

export const useSubmitStoreCodeProposalTx = () => {
const { address, getCosmWasmClient, currentChainName } = useWallet();
return useCallback(
async ({
estimatedFee,
messages,
wasmFileName,
amountToVote,
onTxSucceed,
onTxFailed,
}: SubmitStoreCodeProposalStreamParams) => {
const client = await getCosmWasmClient();
if (!address || !client || !currentChainName)
throw new Error("Please check your wallet connection.");
if (!estimatedFee) return null;
return submitStoreCodeProposalTx({
address: address as HumanAddr,
chainName: currentChainName,
client,
onTxSucceed,
onTxFailed,
fee: estimatedFee,
messages,
wasmFileName,
amountToVote,
});
},
[address, currentChainName, getCosmWasmClient]
);
};
1 change: 1 addition & 0 deletions src/lib/app-provider/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export interface AppConstants {
gasAdjustment: number;
maxGasLimit: number;
}
Loading

0 comments on commit 9cb6deb

Please sign in to comment.