593 lines
21 KiB
TypeScript
593 lines
21 KiB
TypeScript
/* eslint-disable @typescript-eslint/camelcase */
|
|
import { Sha256 } from "@iov/crypto";
|
|
import { Encoding } from "@iov/encoding";
|
|
import { assert } from "@iov/utils";
|
|
import { ReadonlyDate } from "readonly-date";
|
|
|
|
import { makeSignBytes, marshalTx } from "./encoding";
|
|
import { findAttribute, parseLogs } from "./logs";
|
|
import { Pen, Secp256k1Pen } from "./pen";
|
|
import { encodeBech32Pubkey } from "./pubkey";
|
|
import { PostTxsResponse, RestClient } from "./restclient";
|
|
import cosmoshub from "./testdata/cosmoshub.json";
|
|
import {
|
|
getRandomizedHackatom,
|
|
makeRandomAddress,
|
|
tendermintAddressMatcher,
|
|
tendermintIdMatcher,
|
|
tendermintOptionalIdMatcher,
|
|
} from "./testutils.spec";
|
|
import {
|
|
Coin,
|
|
Msg,
|
|
MsgExecuteContract,
|
|
MsgInstantiateContract,
|
|
MsgSend,
|
|
MsgStoreCode,
|
|
StdFee,
|
|
StdSignature,
|
|
StdTx,
|
|
} from "./types";
|
|
|
|
const { fromAscii, fromBase64, fromHex, toAscii, toBase64, toHex } = Encoding;
|
|
|
|
const httpUrl = "http://localhost:1317";
|
|
const defaultNetworkId = "testing";
|
|
const faucet = {
|
|
mnemonic:
|
|
"economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone",
|
|
pubkey: {
|
|
type: "tendermint/PubKeySecp256k1",
|
|
value: "A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ",
|
|
},
|
|
address: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
|
};
|
|
const emptyAddress = "cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k";
|
|
const unusedAccount = {
|
|
address: "cosmos1cjsxept9rkggzxztslae9ndgpdyt2408lk850u",
|
|
};
|
|
|
|
function cosmosEnabled(): boolean {
|
|
return !!process.env.COSMOS_ENABLED;
|
|
}
|
|
|
|
function pendingWithoutCosmos(): void {
|
|
if (!cosmosEnabled()) {
|
|
return pending("Set COSMOS_ENABLED to enable Cosmos node-based tests");
|
|
}
|
|
}
|
|
|
|
function makeSignedTx(firstMsg: Msg, fee: StdFee, memo: string, firstSignature: StdSignature): StdTx {
|
|
return {
|
|
msg: [firstMsg],
|
|
fee: fee,
|
|
memo: memo,
|
|
signatures: [firstSignature],
|
|
};
|
|
}
|
|
|
|
async function uploadCustomContract(
|
|
client: RestClient,
|
|
pen: Pen,
|
|
wasmCode: Uint8Array,
|
|
): Promise<PostTxsResponse> {
|
|
const memo = "My first contract on chain";
|
|
const theMsg: MsgStoreCode = {
|
|
type: "wasm/store-code",
|
|
value: {
|
|
sender: faucet.address,
|
|
wasm_byte_code: toBase64(wasmCode),
|
|
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_number, sequence } = (await client.authAccounts(faucet.address)).result.value;
|
|
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account_number, sequence);
|
|
const signature = await pen.sign(signBytes);
|
|
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
|
|
return client.postTx(marshalTx(signedTx));
|
|
}
|
|
|
|
async function uploadContract(client: RestClient, pen: Pen): Promise<PostTxsResponse> {
|
|
return uploadCustomContract(client, pen, getRandomizedHackatom());
|
|
}
|
|
|
|
async function instantiateContract(
|
|
client: RestClient,
|
|
pen: Pen,
|
|
codeId: number,
|
|
beneficiaryAddress: string,
|
|
transferAmount?: readonly Coin[],
|
|
): Promise<PostTxsResponse> {
|
|
const memo = "Create an escrow instance";
|
|
const theMsg: MsgInstantiateContract = {
|
|
type: "wasm/instantiate",
|
|
value: {
|
|
sender: faucet.address,
|
|
code_id: codeId.toString(),
|
|
init_msg: {
|
|
verifier: faucet.address,
|
|
beneficiary: beneficiaryAddress,
|
|
},
|
|
init_funds: transferAmount || [],
|
|
},
|
|
};
|
|
const fee: StdFee = {
|
|
amount: [
|
|
{
|
|
amount: "5000000",
|
|
denom: "ucosm",
|
|
},
|
|
],
|
|
gas: "89000000",
|
|
};
|
|
|
|
const { account_number, sequence } = (await client.authAccounts(faucet.address)).result.value;
|
|
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account_number, sequence);
|
|
const signature = await pen.sign(signBytes);
|
|
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
|
|
return client.postTx(marshalTx(signedTx));
|
|
}
|
|
|
|
async function executeContract(
|
|
client: RestClient,
|
|
pen: Pen,
|
|
contractAddress: string,
|
|
): Promise<PostTxsResponse> {
|
|
const memo = "Time for action";
|
|
const theMsg: MsgExecuteContract = {
|
|
type: "wasm/execute",
|
|
value: {
|
|
sender: faucet.address,
|
|
contract: contractAddress,
|
|
msg: {},
|
|
sent_funds: [],
|
|
},
|
|
};
|
|
const fee: StdFee = {
|
|
amount: [
|
|
{
|
|
amount: "5000000",
|
|
denom: "ucosm",
|
|
},
|
|
],
|
|
gas: "89000000",
|
|
};
|
|
|
|
const { account_number, sequence } = (await client.authAccounts(faucet.address)).result.value;
|
|
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account_number, sequence);
|
|
const signature = await pen.sign(signBytes);
|
|
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
|
|
return client.postTx(marshalTx(signedTx));
|
|
}
|
|
|
|
describe("RestClient", () => {
|
|
it("can be constructed", () => {
|
|
const client = new RestClient(httpUrl);
|
|
expect(client).toBeTruthy();
|
|
});
|
|
|
|
describe("nodeInfo", () => {
|
|
it("works", async () => {
|
|
pendingWithoutCosmos();
|
|
const client = new RestClient(httpUrl);
|
|
const info = await client.nodeInfo();
|
|
expect(info.node_info.network).toEqual(defaultNetworkId);
|
|
});
|
|
});
|
|
|
|
describe("blocksLatest", () => {
|
|
it("works", async () => {
|
|
pendingWithoutCosmos();
|
|
const client = new RestClient(httpUrl);
|
|
const response = await client.blocksLatest();
|
|
|
|
// id
|
|
expect(response.block_id.hash).toMatch(tendermintIdMatcher);
|
|
|
|
// header
|
|
expect(response.block.header.version).toEqual({ block: "10", app: "0" });
|
|
expect(parseInt(response.block.header.height, 10)).toBeGreaterThanOrEqual(1);
|
|
expect(response.block.header.chain_id).toEqual(defaultNetworkId);
|
|
expect(new ReadonlyDate(response.block.header.time).getTime()).toBeLessThan(ReadonlyDate.now());
|
|
expect(new ReadonlyDate(response.block.header.time).getTime()).toBeGreaterThanOrEqual(
|
|
ReadonlyDate.now() - 5_000,
|
|
);
|
|
expect(response.block.header.last_commit_hash).toMatch(tendermintIdMatcher);
|
|
expect(response.block.header.last_block_id.hash).toMatch(tendermintIdMatcher);
|
|
expect(response.block.header.data_hash).toMatch(tendermintOptionalIdMatcher);
|
|
expect(response.block.header.validators_hash).toMatch(tendermintIdMatcher);
|
|
expect(response.block.header.next_validators_hash).toMatch(tendermintIdMatcher);
|
|
expect(response.block.header.consensus_hash).toMatch(tendermintIdMatcher);
|
|
expect(response.block.header.app_hash).toMatch(tendermintIdMatcher);
|
|
expect(response.block.header.last_results_hash).toMatch(tendermintOptionalIdMatcher);
|
|
expect(response.block.header.evidence_hash).toMatch(tendermintOptionalIdMatcher);
|
|
expect(response.block.header.proposer_address).toMatch(tendermintAddressMatcher);
|
|
|
|
// data
|
|
expect(response.block.data.txs === null || Array.isArray(response.block.data.txs)).toEqual(true);
|
|
});
|
|
});
|
|
|
|
describe("blocks", () => {
|
|
it("works for block by height", async () => {
|
|
pendingWithoutCosmos();
|
|
const client = new RestClient(httpUrl);
|
|
const height = parseInt((await client.blocksLatest()).block.header.height, 10);
|
|
const response = await client.blocks(height - 1);
|
|
|
|
// id
|
|
expect(response.block_id.hash).toMatch(tendermintIdMatcher);
|
|
|
|
// header
|
|
expect(response.block.header.version).toEqual({ block: "10", app: "0" });
|
|
expect(response.block.header.height).toEqual(`${height - 1}`);
|
|
expect(response.block.header.chain_id).toEqual(defaultNetworkId);
|
|
expect(new ReadonlyDate(response.block.header.time).getTime()).toBeLessThan(ReadonlyDate.now());
|
|
expect(new ReadonlyDate(response.block.header.time).getTime()).toBeGreaterThanOrEqual(
|
|
ReadonlyDate.now() - 5_000,
|
|
);
|
|
expect(response.block.header.last_commit_hash).toMatch(tendermintIdMatcher);
|
|
expect(response.block.header.last_block_id.hash).toMatch(tendermintIdMatcher);
|
|
expect(response.block.header.data_hash).toMatch(tendermintOptionalIdMatcher);
|
|
expect(response.block.header.validators_hash).toMatch(tendermintIdMatcher);
|
|
expect(response.block.header.next_validators_hash).toMatch(tendermintIdMatcher);
|
|
expect(response.block.header.consensus_hash).toMatch(tendermintIdMatcher);
|
|
expect(response.block.header.app_hash).toMatch(tendermintIdMatcher);
|
|
expect(response.block.header.last_results_hash).toMatch(tendermintOptionalIdMatcher);
|
|
expect(response.block.header.evidence_hash).toMatch(tendermintOptionalIdMatcher);
|
|
expect(response.block.header.proposer_address).toMatch(tendermintAddressMatcher);
|
|
|
|
// data
|
|
expect(response.block.data.txs === null || Array.isArray(response.block.data.txs)).toEqual(true);
|
|
});
|
|
});
|
|
|
|
describe("authAccounts", () => {
|
|
it("works for unused account without pubkey", async () => {
|
|
pendingWithoutCosmos();
|
|
const client = new RestClient(httpUrl);
|
|
const { result } = await client.authAccounts(unusedAccount.address);
|
|
expect(result).toEqual({
|
|
type: "cosmos-sdk/Account",
|
|
value: {
|
|
address: unusedAccount.address,
|
|
public_key: "", // not known to the chain
|
|
coins: [
|
|
{
|
|
amount: "1000000000",
|
|
denom: "ucosm",
|
|
},
|
|
{
|
|
amount: "1000000000",
|
|
denom: "ustake",
|
|
},
|
|
],
|
|
account_number: 5,
|
|
sequence: 0,
|
|
},
|
|
});
|
|
});
|
|
|
|
// This fails in the first test run if you forget to run `./scripts/cosm/init.sh`
|
|
it("has correct pubkey for faucet", async () => {
|
|
pendingWithoutCosmos();
|
|
const client = new RestClient(httpUrl);
|
|
const { result } = await client.authAccounts(faucet.address);
|
|
expect(result.value).toEqual(
|
|
jasmine.objectContaining({
|
|
public_key: encodeBech32Pubkey(faucet.pubkey, "cosmospub"),
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("encodeTx", () => {
|
|
it("works for cosmoshub example", async () => {
|
|
pendingWithoutCosmos();
|
|
const client = new RestClient(httpUrl);
|
|
expect(await client.encodeTx(cosmoshub.tx)).toEqual(fromBase64(cosmoshub.tx_data));
|
|
});
|
|
});
|
|
|
|
describe("post", () => {
|
|
it("can send tokens", async () => {
|
|
pendingWithoutCosmos();
|
|
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
|
|
|
const memo = "My first contract on chain";
|
|
const theMsg: MsgSend = {
|
|
type: "cosmos-sdk/MsgSend",
|
|
value: {
|
|
from_address: faucet.address,
|
|
to_address: emptyAddress,
|
|
amount: [
|
|
{
|
|
denom: "ucosm",
|
|
amount: "1234567",
|
|
},
|
|
],
|
|
},
|
|
};
|
|
|
|
const fee: StdFee = {
|
|
amount: [
|
|
{
|
|
amount: "5000",
|
|
denom: "ucosm",
|
|
},
|
|
],
|
|
gas: "890000",
|
|
};
|
|
|
|
const client = new RestClient(httpUrl);
|
|
const { account_number, sequence } = (await client.authAccounts(faucet.address)).result.value;
|
|
|
|
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account_number, sequence);
|
|
const signature = await pen.sign(signBytes);
|
|
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
|
|
const result = await client.postTx(marshalTx(signedTx));
|
|
// console.log("Raw log:", result.raw_log);
|
|
expect(result.code).toBeFalsy();
|
|
});
|
|
|
|
it("can upload, instantiate and execute wasm", async () => {
|
|
pendingWithoutCosmos();
|
|
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
|
const client = new RestClient(httpUrl);
|
|
|
|
const transferAmount: readonly Coin[] = [
|
|
{
|
|
amount: "1234",
|
|
denom: "ucosm",
|
|
},
|
|
{
|
|
amount: "321",
|
|
denom: "ustake",
|
|
},
|
|
];
|
|
const beneficiaryAddress = makeRandomAddress();
|
|
|
|
let codeId: number;
|
|
|
|
// upload
|
|
{
|
|
// console.log("Raw log:", result.raw_log);
|
|
const result = await uploadContract(client, pen);
|
|
expect(result.code).toBeFalsy();
|
|
const logs = parseLogs(result.logs);
|
|
const codeIdAttr = findAttribute(logs, "message", "code_id");
|
|
codeId = Number.parseInt(codeIdAttr.value, 10);
|
|
expect(codeId).toBeGreaterThanOrEqual(1);
|
|
expect(codeId).toBeLessThanOrEqual(200);
|
|
}
|
|
|
|
let contractAddress: string;
|
|
|
|
// instantiate
|
|
{
|
|
const result = await instantiateContract(client, pen, codeId, beneficiaryAddress, transferAmount);
|
|
expect(result.code).toBeFalsy();
|
|
// console.log("Raw log:", result.raw_log);
|
|
const logs = parseLogs(result.logs);
|
|
const contractAddressAttr = findAttribute(logs, "message", "contract_address");
|
|
contractAddress = contractAddressAttr.value;
|
|
const amountAttr = findAttribute(logs, "transfer", "amount");
|
|
expect(amountAttr.value).toEqual("1234ucosm,321ustake");
|
|
|
|
const balance = (await client.authAccounts(contractAddress)).result.value.coins;
|
|
expect(balance).toEqual(transferAmount);
|
|
}
|
|
|
|
// execute
|
|
{
|
|
const result = await executeContract(client, pen, contractAddress);
|
|
expect(result.code).toBeFalsy();
|
|
// console.log("Raw log:", result.raw_log);
|
|
const [firstLog] = parseLogs(result.logs);
|
|
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([]);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("query", () => {
|
|
it("can list upload code", async () => {
|
|
pendingWithoutCosmos();
|
|
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
|
const client = new RestClient(httpUrl);
|
|
|
|
// check with contracts were here first to compare
|
|
const existingInfos = await client.listCodeInfo();
|
|
existingInfos.forEach((val, idx) => expect(val.id).toEqual(idx + 1));
|
|
const numExisting = existingInfos.length;
|
|
|
|
// upload data
|
|
const wasmCode = getRandomizedHackatom();
|
|
const result = await uploadCustomContract(client, pen, wasmCode);
|
|
expect(result.code).toBeFalsy();
|
|
const logs = parseLogs(result.logs);
|
|
const codeIdAttr = findAttribute(logs, "message", "code_id");
|
|
const codeId = Number.parseInt(codeIdAttr.value, 10);
|
|
|
|
// ensure we were added to the end of the list
|
|
const newInfos = await client.listCodeInfo();
|
|
expect(newInfos.length).toEqual(numExisting + 1);
|
|
const lastInfo = newInfos[newInfos.length - 1];
|
|
expect(lastInfo.id).toEqual(codeId);
|
|
expect(lastInfo.creator).toEqual(faucet.address);
|
|
|
|
// ensure metadata is present
|
|
expect(lastInfo.source).toEqual(
|
|
"https://github.com/confio/cosmwasm/raw/0.7/lib/vm/testdata/contract_0.6.wasm",
|
|
);
|
|
expect(lastInfo.builder).toEqual("cosmwasm-opt:0.6.2");
|
|
|
|
// check code hash matches expectation
|
|
const wasmHash = new Sha256(wasmCode).digest();
|
|
expect(lastInfo.code_hash.toLowerCase()).toEqual(toHex(wasmHash));
|
|
|
|
// download code and check against auto-gen
|
|
const download = await client.getCode(codeId);
|
|
expect(download).toEqual(wasmCode);
|
|
});
|
|
|
|
it("can list contracts and get info", async () => {
|
|
pendingWithoutCosmos();
|
|
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
|
const client = new RestClient(httpUrl);
|
|
const beneficiaryAddress = makeRandomAddress();
|
|
const transferAmount: readonly Coin[] = [
|
|
{
|
|
amount: "707707",
|
|
denom: "ucosm",
|
|
},
|
|
];
|
|
|
|
// reuse an existing contract, or upload if needed
|
|
let codeId: number;
|
|
const existingInfos = await client.listCodeInfo();
|
|
if (existingInfos.length > 0) {
|
|
codeId = existingInfos[existingInfos.length - 1].id;
|
|
} else {
|
|
const uploadResult = await uploadContract(client, pen);
|
|
expect(uploadResult.code).toBeFalsy();
|
|
const uploadLogs = parseLogs(uploadResult.logs);
|
|
const codeIdAttr = findAttribute(uploadLogs, "message", "code_id");
|
|
codeId = Number.parseInt(codeIdAttr.value, 10);
|
|
}
|
|
|
|
// create new instance and compare before and after
|
|
const existingContracts = await client.listContractAddresses();
|
|
const existingContractsByCode = await client.listContractsByCodeId(codeId);
|
|
existingContractsByCode.forEach(ctc => expect(ctc.code_id).toEqual(codeId));
|
|
|
|
const result = await instantiateContract(client, pen, codeId, beneficiaryAddress, transferAmount);
|
|
expect(result.code).toBeFalsy();
|
|
const logs = parseLogs(result.logs);
|
|
const contractAddressAttr = findAttribute(logs, "message", "contract_address");
|
|
const myAddress = contractAddressAttr.value;
|
|
|
|
// ensure we were added to the list
|
|
const newContracts = await client.listContractAddresses();
|
|
expect(newContracts.length).toEqual(existingContracts.length + 1);
|
|
// note: we are NOT guaranteed to be added to the end
|
|
const diff = newContracts.filter(x => !existingContracts.includes(x));
|
|
expect(diff.length).toEqual(1);
|
|
const lastContract = diff[0];
|
|
expect(lastContract).toEqual(myAddress);
|
|
|
|
// also by codeID list
|
|
const newContractsByCode = await client.listContractsByCodeId(codeId);
|
|
newContractsByCode.forEach(ctc => expect(ctc.code_id).toEqual(codeId));
|
|
expect(newContractsByCode.length).toEqual(existingContractsByCode.length + 1);
|
|
|
|
// check out info
|
|
const myInfo = await client.getContractInfo(myAddress);
|
|
expect(myInfo.code_id).toEqual(codeId);
|
|
expect(myInfo.creator).toEqual(faucet.address);
|
|
expect((myInfo.init_msg as any).beneficiary).toEqual(beneficiaryAddress);
|
|
|
|
// make sure random addresses don't give useful info
|
|
const nonExistentAddress = makeRandomAddress();
|
|
await client
|
|
.getContractInfo(nonExistentAddress)
|
|
.then(() => fail("this shouldn't succeed"))
|
|
.catch(error => expect(error).toMatch(`No contract found at address "${nonExistentAddress}"`));
|
|
});
|
|
|
|
describe("contract state", () => {
|
|
const client = new RestClient(httpUrl);
|
|
const noContract = makeRandomAddress();
|
|
const expectedKey = toAscii("config");
|
|
let contractAddress: string | undefined;
|
|
|
|
beforeAll(async () => {
|
|
if (cosmosEnabled()) {
|
|
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
|
const uploadResult = await uploadContract(client, pen);
|
|
assert(!uploadResult.code);
|
|
const uploadLogs = parseLogs(uploadResult.logs);
|
|
const codeId = Number.parseInt(findAttribute(uploadLogs, "message", "code_id").value, 10);
|
|
const instantiateResult = await instantiateContract(client, pen, codeId, makeRandomAddress());
|
|
assert(!instantiateResult.code);
|
|
const instantiateLogs = parseLogs(instantiateResult.logs);
|
|
const contractAddressAttr = findAttribute(instantiateLogs, "message", "contract_address");
|
|
contractAddress = contractAddressAttr.value;
|
|
}
|
|
});
|
|
|
|
it("can get all state", async () => {
|
|
pendingWithoutCosmos();
|
|
|
|
// get contract state
|
|
const state = await client.getAllContractState(contractAddress!);
|
|
expect(state.length).toEqual(1);
|
|
const data = state[0];
|
|
expect(data.key).toEqual(expectedKey);
|
|
const value = JSON.parse(fromAscii(data.val));
|
|
expect(value.verifier).toBeDefined();
|
|
expect(value.beneficiary).toBeDefined();
|
|
|
|
// bad address is empty array
|
|
const noContractState = await client.getAllContractState(noContract);
|
|
expect(noContractState).toEqual([]);
|
|
});
|
|
|
|
it("can query by key", async () => {
|
|
pendingWithoutCosmos();
|
|
|
|
// query by one key
|
|
const raw = await client.queryContractRaw(contractAddress!, expectedKey);
|
|
assert(raw, "must get result");
|
|
const model = JSON.parse(fromAscii(raw));
|
|
expect(model.verifier).toBeDefined();
|
|
expect(model.beneficiary).toBeDefined();
|
|
|
|
// missing key is null
|
|
const missing = await client.queryContractRaw(contractAddress!, fromHex("cafe0dad"));
|
|
expect(missing).toBeNull();
|
|
|
|
// bad address is null
|
|
const noContractModel = await client.queryContractRaw(noContract, expectedKey);
|
|
expect(noContractModel).toBeNull();
|
|
});
|
|
|
|
it("can make smart queries", async () => {
|
|
pendingWithoutCosmos();
|
|
|
|
// we can query the verifier properly
|
|
const verifier = await client.queryContractSmart(contractAddress!, { verifier: {} });
|
|
expect(fromAscii(verifier)).toEqual(faucet.address);
|
|
|
|
// invalid query syntax throws an error
|
|
await client.queryContractSmart(contractAddress!, { nosuchkey: {} }).then(
|
|
() => fail("shouldn't succeed"),
|
|
error => expect(error).toMatch("Error parsing QueryMsg"),
|
|
);
|
|
|
|
// invalid address throws an error
|
|
await client.queryContractSmart(noContract, { verifier: {} }).then(
|
|
() => fail("shouldn't succeed"),
|
|
error => expect(error).toMatch("not found"),
|
|
);
|
|
});
|
|
});
|
|
});
|
|
});
|