diff --git a/packages/sdk/src/restclient.spec.ts b/packages/sdk/src/restclient.spec.ts index 5c12db17..1ae9bb2f 100644 --- a/packages/sdk/src/restclient.spec.ts +++ b/packages/sdk/src/restclient.spec.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/camelcase */ -import { ChainId, PrehashType, SignableBytes } from "@iov/bcp"; +import { ChainId, Identity, PrehashType, SignableBytes } from "@iov/bcp"; import { Random } from "@iov/crypto"; import { Bech32, Encoding } from "@iov/encoding"; import { HdPaths, Secp256k1HdWallet } from "@iov/keycontrol"; @@ -7,7 +7,7 @@ import { HdPaths, Secp256k1HdWallet } from "@iov/keycontrol"; import { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding"; import { leb128Encode } from "./leb128.spec"; import { Attribute, Log, parseLogs } from "./logs"; -import { RestClient } from "./restclient"; +import { PostTxsResponse, RestClient } from "./restclient"; import contract from "./testdata/contract.json"; import cosmoshub from "./testdata/cosmoshub.json"; import { @@ -174,6 +174,112 @@ describe("RestClient", () => { expect(result.code).toBeFalsy(); }); + async function uploadContract( + client: RestClient, + wallet: Secp256k1HdWallet, + signer: Identity, + ): Promise { + const memo = "My first contract on chain"; + const theMsg: MsgStoreCode = { + type: "wasm/store-code", + value: { + sender: faucetAddress, + wasm_byte_code: toBase64(getRandomizedContract()), + source: "https://github.com/confio/cosmwasm/raw/0.7/lib/vm/testdata/contract_0.6.wasm", + builder: "cosmwasm-opt:0.6.2", + }, + }; + 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); + return client.postTx(marshalTx(signedTx)); + } + + async function instantiateContract( + client: RestClient, + wallet: Secp256k1HdWallet, + signer: Identity, + codeId: number, + beneficiaryAddress: string, + transferAmount: readonly Coin[], + ): Promise { + const memo = "Create an escrow instance"; + const theMsg: MsgInstantiateContract = { + type: "wasm/instantiate", + value: { + sender: faucetAddress, + code_id: codeId.toString(), + init_msg: { + verifier: faucetAddress, + beneficiary: beneficiaryAddress, + }, + init_funds: transferAmount, + }, + }; + 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); + return client.postTx(marshalTx(signedTx)); + } + + async function executeContract( + client: RestClient, + wallet: Secp256k1HdWallet, + signer: Identity, + contractAddress: string, + ): Promise { + 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); + return client.postTx(marshalTx(signedTx)); + } + it("can upload, instantiate and execute wasm", async () => { pendingWithoutCosmos(); const wallet = Secp256k1HdWallet.fromMnemonic(faucetMnemonic); @@ -196,33 +302,8 @@ describe("RestClient", () => { // upload { - const memo = "My first contract on chain"; - const theMsg: MsgStoreCode = { - type: "wasm/store-code", - value: { - sender: faucetAddress, - wasm_byte_code: toBase64(getRandomizedContract()), - source: "https://github.com/confio/cosmwasm/raw/0.7/lib/vm/testdata/contract_0.6.wasm", - builder: "cosmwasm-opt:0.6.2", - }, - }; - 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)); // console.log("Raw log:", result.raw_log); + const result = await uploadContract(client, wallet, signer); expect(result.code).toBeFalsy(); const logs = parseSuccess(result.raw_log); const codeIdAttr = findAttribute(logs, "message", "code_id"); @@ -235,35 +316,14 @@ describe("RestClient", () => { // instantiate { - const memo = "Create an escrow instance"; - const theMsg: MsgInstantiateContract = { - type: "wasm/instantiate", - value: { - sender: faucetAddress, - code_id: codeId.toString(), - init_msg: { - verifier: faucetAddress, - beneficiary: beneficiaryAddress, - }, - init_funds: transferAmount, - }, - }; - 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)); + const result = await instantiateContract( + client, + wallet, + signer, + codeId, + beneficiaryAddress, + transferAmount, + ); expect(result.code).toBeFalsy(); // console.log("Raw log:", result.raw_log); const logs = parseSuccess(result.raw_log); @@ -278,32 +338,7 @@ describe("RestClient", () => { // 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)); + const result = await executeContract(client, wallet, signer, contractAddress); expect(result.code).toBeFalsy(); // console.log("Raw log:", result.raw_log); const [firstLog] = parseSuccess(result.raw_log); diff --git a/packages/sdk/src/restclient.ts b/packages/sdk/src/restclient.ts index 8f121628..a2a71e27 100644 --- a/packages/sdk/src/restclient.ts +++ b/packages/sdk/src/restclient.ts @@ -73,7 +73,7 @@ interface SearchTxsResponse { interface PostTxsParams {} -interface PostTxsResponse { +export interface PostTxsResponse { readonly height: string; readonly txhash: string; readonly code?: number; @@ -236,6 +236,7 @@ export class RestClient { // this will download the original wasm bytecode by code id // throws error if no code with this id public async getCode(id: number): Promise { + // TODO: broken currently const path = `/wasm/code/${id}`; const responseData = await this.get(path); const { code } = parseWasmResponse(responseData as WasmResponse); diff --git a/packages/sdk/types/restclient.d.ts b/packages/sdk/types/restclient.d.ts index 59934755..e9feca7c 100644 --- a/packages/sdk/types/restclient.d.ts +++ b/packages/sdk/types/restclient.d.ts @@ -1,4 +1,4 @@ -import { AminoTx, BaseAccount, CodeInfo, CodeInfoWithId, ContractInfo, StdTx } from "./types"; +import { AminoTx, BaseAccount, CodeInfo, ContractInfo, StdTx, WasmData } from "./types"; interface NodeInfo { readonly network: string; } @@ -29,9 +29,14 @@ interface AuthAccountsResponse { readonly value: BaseAccount; }; } -interface WasmResponse { +declare type WasmResponse = WasmSuccess | WasmError; +interface WasmSuccess { + readonly height: string; readonly result: string; } +interface WasmError { + readonly error: string; +} export interface TxsResponse { readonly height: string; readonly txhash: string; @@ -47,7 +52,7 @@ interface SearchTxsResponse { readonly txs: readonly TxsResponse[]; } interface PostTxsParams {} -interface PostTxsResponse { +export interface PostTxsResponse { readonly height: string; readonly txhash: string; readonly code?: number; @@ -87,9 +92,12 @@ export declare class RestClient { txs(query: string): Promise; txsById(id: string): Promise; postTx(tx: Uint8Array): Promise; - listCodeInfo(): Promise; - getCodeInfo(id: number): Promise; + listCodeInfo(): Promise; + getCode(id: number): Promise; listContractAddresses(): Promise; getContractInfo(address: string): Promise; + getAllContractState(address: string): Promise; + getContractKey(address: string, key: Uint8Array): Promise; + queryContract(address: string, query: object): Promise; } export {}; diff --git a/packages/sdk/types/types.d.ts b/packages/sdk/types/types.d.ts index fd4e8605..2d26a1b3 100644 --- a/packages/sdk/types/types.d.ts +++ b/packages/sdk/types/types.d.ts @@ -121,6 +121,7 @@ export interface BaseAccount { /** The data we need from BaseAccount to create a nonce */ export declare type NonceInfo = Pick; export interface CodeInfo { + readonly id: number; /** Bech32 account address */ readonly creator: string; /** Hex-encoded sha256 hash of the code stored here */ @@ -128,8 +129,8 @@ export interface CodeInfo { readonly source?: string; readonly builder?: string; } -export interface CodeInfoWithId extends CodeInfo { - readonly id: number; +export interface CodeDetails { + readonly code: string; } export interface ContractInfo { readonly code_id: number; @@ -138,4 +139,8 @@ export interface ContractInfo { /** Argument passed on initialization of the contract */ readonly init_msg: object; } +export interface WasmData { + readonly key: string; + readonly val: unknown; +} export {};