Skip to content

Commit

Permalink
Add option to simulate a contract execution in the tx view in sidebar
Browse files Browse the repository at this point in the history
  • Loading branch information
spoo-bar committed Jun 19, 2024
1 parent d630806 commit b6474ca
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 11 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ All notable changes to the Cosmy Wasmy extension will be documented in this file
### Added

- For testnet and mainnet chain, all contracts by the selected account can be imported in a single click
- Add option to simulate a contract execution in the tx view in sidebar

### Changed

- Cosmwasm history view now shows the input at the end of the table as it can be unknowingly long

### Deprecated

### Removed
Expand Down
49 changes: 43 additions & 6 deletions src/helpers/cosmwasm/api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CodeDetails, CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { CodeDetails, CosmWasmClient, MsgExecuteContractEncodeObject } from "@cosmjs/cosmwasm-stargate";
import { MsgExecuteContract, } from "cosmjs-types/cosmwasm/wasm/v1/tx";
import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { WrapWallet } from '../sign/wrapwallet';
import { GasPrice } from '@cosmjs/stargate';
Expand All @@ -8,6 +9,7 @@ import { Workspace } from "../workspace";
import { ResponseHandler } from "../responseHandler";
import { Account } from "../../models/account";
import { Utils } from "../../views/utils";
import { TextEncoder } from "util";


export class CosmwasmAPI {
Expand All @@ -25,8 +27,8 @@ export class CosmwasmAPI {
for (let code of codes) {
const contracts = await client.getContracts(code.id);
for (let contract of contracts) {
let contractInfo = await client.getContract(contract);
importedContracts.push(new Contract(contractInfo.label, contractInfo.address, contractInfo.codeId, contractInfo.creator, global.workspaceChain.configName));
let contractInfo = await client.getContract(contract);
importedContracts.push(new Contract(contractInfo.label, contractInfo.address, contractInfo.codeId, contractInfo.creator, global.workspaceChain.configName));
}
}
return importedContracts;
Expand All @@ -52,7 +54,7 @@ export class CosmwasmAPI {
if (!isNaN(parseFloat(decimals))) {
return Utils.TransDecimals(balance.amount, decimals);
}

return balance.amount;
}

Expand All @@ -72,7 +74,7 @@ export class CosmwasmAPI {

export class Cosmwasm {

public static async GetQueryClient(): Promise<CosmWasmClient> {
public static async GetQueryClient(): Promise<CosmWasmClient> {
const rpcEndpoint = global.workspaceChain.rpcEndpoint;
return CosmWasmClient.connect(rpcEndpoint);
}
Expand All @@ -86,7 +88,7 @@ export class Cosmwasm {
if (!gasDenom) {
gasDenom = global.workspaceChain.chainDenom;
}

let gasPrice = global.workspaceChain.defaultGasPrice + gasDenom;
let client = await SigningCosmWasmClient.connectWithSigner(
global.workspaceChain.rpcEndpoint,
Expand Down Expand Up @@ -134,6 +136,38 @@ export class Cosmwasm {
}
}

public static async Simulate(account: Account, contract: string, req: any, memo: string, fundsStr: string) {
try {
let client = await Cosmwasm.GetSigningClient();
let funds = Utils.ParseCoins(fundsStr);
const inputJson = JSON.stringify(req);
const encodeInput = toUtf8(inputJson);
const encodeMsg = MsgExecuteContract.fromPartial({
sender: account.address,
contract: contract,
msg: encodeInput,
funds: [...(funds || [])],
});
const msg: MsgExecuteContractEncodeObject = {
typeUrl: "/cosmwasm.wasm.v1.MsgExecuteContract",
value: encodeMsg,
};
let gasConsumed = await client.simulate(account.address, [msg], memo)
ResponseHandler.OutputSuccess(JSON.stringify(req, null, 4), "Gas Consumed: " + gasConsumed, "Simulate");
return {
isSuccess: true,
response: gasConsumed
};
}
catch (err: any) {
ResponseHandler.OutputError(JSON.stringify(req, null, 4), err, "Simulate");
return {
isSuccess: false,
response: err
};
}
}

// public static async ExecuteMultiple(account: Account, txs: ExecuteInstruction[]) {
// try {
// let client = await Cosmwasm.GetSigningClient();
Expand Down Expand Up @@ -206,3 +240,6 @@ export class Cosmwasm {
}
}
}
function toUtf8(str: string): Uint8Array {
return new TextEncoder().encode(str);
}
41 changes: 41 additions & 0 deletions src/helpers/cosmwasm/executer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,47 @@ export class Executer {
}
});
}

public Simulate(value: any, location: vscode.ProgressLocation | { viewId: string }) {
const account = Workspace.GetSelectedAccount();
if (!account) {
vscode.window.showErrorMessage(vscode.l10n.t("No account selected. Select an account from the Accounts view."));
return;
}
const contract = Workspace.GetSelectedContract();
if (!contract) {
vscode.window.showErrorMessage(vscode.l10n.t("No contract selected. Select a contract in the Contracts view."));
return;
}
try {
JSON.parse(value.input);
} catch {
vscode.window.showErrorMessage(vscode.l10n.t("The input is not valid JSON"));
return;
}

const req = JSON.parse(value.input);

if (this.useHistoryHandler) {
HistoryHandler.RecordAction(this.context, contract, Action.Simulate, value);
}

vscode.window.withProgress({
location: location,
title: vscode.l10n.t("Simulating msg on the contract - {label}", { label: contract.label }),
cancellable: false
}, async (progress, token) => {
token.onCancellationRequested(() => { });
progress.report({ message: '' });
const gasUsed = await Cosmwasm.Simulate(account, contract.contractAddress, req, "Sent from cosmy-wasmy", value.funds);
if (gasUsed.isSuccess) {
return Promise.resolve();
}
else {
return Promise.reject();
}
});
}
}


3 changes: 2 additions & 1 deletion src/helpers/extensionData/historyHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,6 @@ export enum Action {
Tx,
Migrate,
Initialize,
Invalid
Invalid,
Simulate
}
12 changes: 8 additions & 4 deletions src/views/cosmwasmHistoryView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export class CosmwasmHistoryView {
this.executer.Execute(action.inputData, vscode.ProgressLocation.Notification)
break;
}
case Action.Simulate: {
this.executer.Simulate(action.inputData, vscode.ProgressLocation.Notification);
break;
}
default: { }
}
}
Expand Down Expand Up @@ -136,9 +140,9 @@ export class CosmwasmHistoryView {
<th>Run</th>
<th>Type</th>
<th>Label</th>
<th>Input Data</th>
<th>Input Funds</th>
<th>Contract Address</th>
<th>Input Funds</th>
<th>Input Data</th>
</tr>`;
content += this.getTableData();
content += "</table></div><br />";
Expand Down Expand Up @@ -175,9 +179,9 @@ export class CosmwasmHistoryView {
else {
tableContent += "<td><span class=\"error\"><i>" + vscode.l10n.t("Contract not found in imported contracts.") + "</i></span></td>";
}
tableContent += "<td>" + inputData + "</td>";
tableContent += "<td>" + inputFunds + "</td>";
tableContent += "<td>" + item.contractAddr + "</td>";
tableContent += "<td>" + inputFunds + "</td>";
tableContent += "<td>" + inputData + "</td>";
tableContent += "</tr>";
});
return tableContent;
Expand Down
14 changes: 14 additions & 0 deletions src/views/txProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export class TxProvider implements vscode.WebviewViewProvider {
new Executer(this.context, true).Execute(data.value, { viewId: Constants.VIEWS_EXECUTE });
break;
}
case 'simulate-text':
{
new Executer(this.context, true).Simulate(data.value, { viewId: Constants.VIEWS_EXECUTE });
break;
}
}
});
}
Expand Down Expand Up @@ -56,6 +61,7 @@ export class TxProvider implements vscode.WebviewViewProvider {
<textarea id="input-text" placeholder="{'increment':{}}"></textarea>
<input id="funds-text" placeholder="10${denom}"></input>
<button id="exec-button">${vscode.l10n.t("Execute")}</button>
<button id="simulate-button" class="secondary">${vscode.l10n.t("Simulate")}</button>
<script>
(function () {
const vscode = acquireVsCodeApi();
Expand All @@ -67,6 +73,14 @@ export class TxProvider implements vscode.WebviewViewProvider {
funds: funds
}});
});
document.querySelector('#simulate-button').addEventListener('click', () => {
const input = document.getElementById('input-text').value;
const funds = document.getElementById('funds-text').value;
vscode.postMessage({ type: 'simulate-text', value: {
input: input,
funds: funds
}});
});
}());
</script>
</body>
Expand Down

0 comments on commit b6474ca

Please sign in to comment.