Implement contract execution

This commit is contained in:
Simon Warta 2020-02-05 09:45:45 +01:00
parent ce18a5296d
commit e3c294ed2e
4 changed files with 110 additions and 18 deletions

View File

@ -311,7 +311,11 @@ export class CosmWasmConnection implements BlockchainConnection {
let senderAddress: string;
if (types.isMsgSend(firstMsg)) {
senderAddress = firstMsg.value.from_address;
} else if (types.isMsgStoreCode(firstMsg) || types.isMsgInstantiateContract(firstMsg)) {
} else if (
types.isMsgStoreCode(firstMsg) ||
types.isMsgInstantiateContract(firstMsg) ||
types.isMsgExecuteContract(firstMsg)
) {
senderAddress = firstMsg.value.sender;
} else {
throw new Error(`Got unsupported type of message: ${firstMsg.type}`);

View File

@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/camelcase */
import { ChainId, PrehashType, SignableBytes } from "@iov/bcp";
import { Encoding } from "@iov/encoding";
import { Random } from "@iov/crypto";
import { Bech32, Encoding } from "@iov/encoding";
import { HdPaths, Secp256k1HdWallet } from "@iov/keycontrol";
import { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding";
@ -12,6 +13,7 @@ import cosmoshub from "./testdata/cosmoshub.json";
import {
Coin,
Msg,
MsgExecuteContract,
MsgInstantiateContract,
MsgSend,
MsgStoreCode,
@ -76,6 +78,10 @@ function getRandomizedContract(): Uint8Array {
return data;
}
function makeRandomAddress(): string {
return Bech32.encode("cosmos", Random.getBytes(20));
}
describe("RestClient", () => {
it("can be constructed", () => {
const client = new RestClient(httpUrl);
@ -154,12 +160,24 @@ describe("RestClient", () => {
expect(result.code).toBeFalsy();
});
it("can upload and instantiate wasm", async () => {
it("can upload, instantiate and execute wasm", async () => {
pendingWithoutCosmos();
const wallet = Secp256k1HdWallet.fromMnemonic(faucetMnemonic);
const signer = await wallet.createIdentity("abc" as ChainId, faucetPath);
const client = new RestClient(httpUrl);
const transferAmount: readonly Coin[] = [
{
amount: "1234",
denom: "ucosm",
},
{
amount: "321",
denom: "ustake",
},
];
const beneficiaryAddress = makeRandomAddress();
let codeId: number;
// upload
@ -207,24 +225,14 @@ describe("RestClient", () => {
// instantiate
{
const memo = "Create an escrow instance";
const transferAmount: readonly Coin[] = [
{
amount: "1234",
denom: "ucosm",
},
{
amount: "321",
denom: "ustake",
},
];
const theMsg: MsgInstantiateContract = {
type: "wasm/instantiate",
value: {
sender: faucetAddress,
code_id: codeId.toString(),
init_msg: {
verifier: "cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k",
beneficiary: "cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k",
verifier: faucetAddress,
beneficiary: beneficiaryAddress,
},
init_funds: transferAmount,
},
@ -264,6 +272,46 @@ describe("RestClient", () => {
const balance = (await client.authAccounts(contractAddress)).result.value.coins;
expect(balance).toEqual(transferAmount);
}
});
// execute
{
const memo = "Time for action";
const theMsg: MsgExecuteContract = {
type: "wasm/execute",
value: {
sender: faucetAddress,
contract: contractAddress,
msg: {},
sent_funds: [],
},
};
const fee: StdFee = {
amount: [
{
amount: "5000000",
denom: "ucosm",
},
],
gas: "89000000",
};
const account = (await client.authAccounts(faucetAddress)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account) as SignableBytes;
const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256);
const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature);
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
const result = await client.postTx(marshalTx(signedTx));
expect(result.code).toBeFalsy();
// console.log("Raw log:", result.raw_log);
const [firstLog] = parseSuccess(result.raw_log);
expect(firstLog.log).toEqual(`released funds to ${beneficiaryAddress}`);
// Verify token transfer from contract to beneficiary
const beneficiaryBalance = (await client.authAccounts(beneficiaryAddress)).result.value.coins;
expect(beneficiaryBalance).toEqual(transferAmount);
const contractBalance = (await client.authAccounts(contractAddress)).result.value.coins;
expect(contractBalance).toEqual([]);
}
}, 30_000);
});
});

View File

@ -76,7 +76,25 @@ export interface MsgInstantiateContract extends MsgTemplate {
};
}
export type Msg = MsgSend | MsgStoreCode | MsgInstantiateContract | MsgTemplate;
/**
* Creates an instance of contract that was uploaded before.
*
* @see https://github.com/cosmwasm/wasmd/blob/9842678d89/x/wasm/internal/types/msg.go#L103
*/
export interface MsgExecuteContract extends MsgTemplate {
readonly type: "wasm/execute";
readonly value: {
/** Bech32 account address */
readonly sender: string;
/** Bech32 account address */
readonly contract: string;
/** Handle message as JavaScript object */
readonly msg: object;
readonly sent_funds: ReadonlyArray<Coin>;
};
}
export type Msg = MsgSend | MsgStoreCode | MsgInstantiateContract | MsgExecuteContract | MsgTemplate;
export function isMsgSend(msg: Msg): msg is MsgSend {
return (msg as MsgSend).type === "cosmos-sdk/MsgSend";
@ -90,6 +108,10 @@ export function isMsgInstantiateContract(msg: Msg): msg is MsgInstantiateContrac
return (msg as MsgInstantiateContract).type === "wasm/instantiate";
}
export function isMsgExecuteContract(msg: Msg): msg is MsgExecuteContract {
return (msg as MsgExecuteContract).type === "wasm/execute";
}
export interface StdFee {
readonly amount: ReadonlyArray<Coin>;
readonly gas: string;

View File

@ -62,10 +62,28 @@ export interface MsgInstantiateContract extends MsgTemplate {
readonly init_funds: ReadonlyArray<Coin>;
};
}
export declare type Msg = MsgSend | MsgStoreCode | MsgInstantiateContract | MsgTemplate;
/**
* Creates an instance of contract that was uploaded before.
*
* @see https://github.com/cosmwasm/wasmd/blob/9842678d89/x/wasm/internal/types/msg.go#L103
*/
export interface MsgExecuteContract extends MsgTemplate {
readonly type: "wasm/execute";
readonly value: {
/** Bech32 account address */
readonly sender: string;
/** Bech32 account address */
readonly contract: string;
/** Handle message as JavaScript object */
readonly msg: object;
readonly sent_funds: ReadonlyArray<Coin>;
};
}
export declare type Msg = MsgSend | MsgStoreCode | MsgInstantiateContract | MsgExecuteContract | MsgTemplate;
export declare function isMsgSend(msg: Msg): msg is MsgSend;
export declare function isMsgStoreCode(msg: Msg): msg is MsgStoreCode;
export declare function isMsgInstantiateContract(msg: Msg): msg is MsgInstantiateContract;
export declare function isMsgExecuteContract(msg: Msg): msg is MsgExecuteContract;
export interface StdFee {
readonly amount: ReadonlyArray<Coin>;
readonly gas: string;