Merge pull request #129 from confio/events
Search transactions by events
This commit is contained in:
commit
567ada8d51
@ -589,6 +589,124 @@ describe("CosmWasmConnection", () => {
|
||||
connection.disconnect();
|
||||
});
|
||||
|
||||
it("can post an ERC20 transfer and search for the transaction", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const profile = new UserProfile();
|
||||
const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(faucet.mnemonic));
|
||||
const sender = await profile.createIdentity(wallet.id, defaultChainId, faucet.path);
|
||||
const senderAddress = connection.codec.identityToAddress(sender);
|
||||
|
||||
const recipient = makeRandomAddress();
|
||||
const unsigned = await connection.withDefaultFee<SendTransaction>({
|
||||
kind: "bcp/send",
|
||||
chainId: defaultChainId,
|
||||
sender: senderAddress,
|
||||
recipient: recipient,
|
||||
memo: "My first payment",
|
||||
amount: {
|
||||
quantity: "75",
|
||||
fractionalDigits: 0,
|
||||
tokenTicker: "ISA" as TokenTicker,
|
||||
},
|
||||
});
|
||||
const nonce = await connection.getNonce({ address: senderAddress });
|
||||
const signed = await profile.signTransaction(sender, unsigned, connection.codec, nonce);
|
||||
const postableBytes = connection.codec.bytesToPost(signed);
|
||||
const response = await connection.postTx(postableBytes);
|
||||
const { transactionId } = response;
|
||||
const blockInfo = await response.blockInfo.waitFor(info => !isBlockInfoPending(info));
|
||||
expect(blockInfo.state).toEqual(TransactionState.Succeeded);
|
||||
|
||||
// search by id
|
||||
const byIdResults = await connection.searchTx({ id: transactionId });
|
||||
expect(byIdResults.length).toEqual(1);
|
||||
const byIdResult = byIdResults[0];
|
||||
expect(byIdResult.transactionId).toEqual(transactionId);
|
||||
assert(isConfirmedTransaction(byIdResult), "Expected transaction to succeed");
|
||||
assert(byIdResult.log, "Log must be available");
|
||||
const [firstByIdlog] = JSON.parse(byIdResult.log);
|
||||
expect(firstByIdlog.events.length).toEqual(2);
|
||||
expect(firstByIdlog.events[0].type).toEqual("message");
|
||||
expect(firstByIdlog.events[1].type).toEqual("wasm");
|
||||
// wasm event attributes added by contract
|
||||
expect(firstByIdlog.events[1].attributes).toContain({ key: "action", value: "transfer" });
|
||||
expect(firstByIdlog.events[1].attributes).toContain({ key: "sender", value: senderAddress });
|
||||
expect(firstByIdlog.events[1].attributes).toContain({ key: "recipient", value: recipient });
|
||||
// wasm event attributes added wasmd
|
||||
expect(firstByIdlog.events[1].attributes).toContain({
|
||||
key: "contract_address",
|
||||
value: defaultConfig.erc20Tokens![1].contractAddress,
|
||||
});
|
||||
const byIdTransaction = byIdResult.transaction;
|
||||
assert(isSendTransaction(byIdTransaction), "Expected send transaction");
|
||||
expect(byIdTransaction).toEqual(unsigned);
|
||||
|
||||
// search by sender address
|
||||
const bySenderResults = await connection.searchTx({ sentFromOrTo: senderAddress });
|
||||
expect(bySenderResults).toBeTruthy();
|
||||
expect(bySenderResults.length).toBeGreaterThanOrEqual(1);
|
||||
const bySenderResult = bySenderResults[bySenderResults.length - 1];
|
||||
expect(bySenderResult.transactionId).toEqual(transactionId);
|
||||
assert(isConfirmedTransaction(bySenderResult), "Expected transaction to succeed");
|
||||
assert(bySenderResult.log, "Log must be available");
|
||||
const [firstBySenderLog] = JSON.parse(bySenderResult.log);
|
||||
expect(firstBySenderLog.events.length).toEqual(2);
|
||||
expect(firstBySenderLog.events[0].type).toEqual("message");
|
||||
expect(firstBySenderLog.events[1].type).toEqual("wasm");
|
||||
// wasm event attributes added by contract
|
||||
expect(firstBySenderLog.events[1].attributes).toContain({ key: "action", value: "transfer" });
|
||||
expect(firstBySenderLog.events[1].attributes).toContain({ key: "sender", value: senderAddress });
|
||||
expect(firstBySenderLog.events[1].attributes).toContain({ key: "recipient", value: recipient });
|
||||
// wasm event attributes added wasmd
|
||||
expect(firstBySenderLog.events[1].attributes).toContain({
|
||||
key: "contract_address",
|
||||
value: defaultConfig.erc20Tokens![1].contractAddress,
|
||||
});
|
||||
const bySenderTransaction = bySenderResult.transaction;
|
||||
assert(isSendTransaction(bySenderTransaction), "Expected send transaction");
|
||||
expect(bySenderTransaction).toEqual(unsigned);
|
||||
|
||||
// search by recipient address
|
||||
const byRecipientResults = await connection.searchTx({ sentFromOrTo: recipient });
|
||||
expect(byRecipientResults.length).toBeGreaterThanOrEqual(1);
|
||||
const byRecipientResult = byRecipientResults[byRecipientResults.length - 1];
|
||||
expect(byRecipientResult.transactionId).toEqual(transactionId);
|
||||
assert(isConfirmedTransaction(byRecipientResult), "Expected transaction to succeed");
|
||||
assert(byRecipientResult.log, "Log must be available");
|
||||
const [firstByRecipientLog] = JSON.parse(bySenderResult.log);
|
||||
expect(firstByRecipientLog.events.length).toEqual(2);
|
||||
expect(firstByRecipientLog.events[0].type).toEqual("message");
|
||||
expect(firstByRecipientLog.events[1].type).toEqual("wasm");
|
||||
// wasm event attributes added by contract
|
||||
expect(firstByRecipientLog.events[1].attributes).toContain({ key: "action", value: "transfer" });
|
||||
expect(firstByRecipientLog.events[1].attributes).toContain({ key: "sender", value: senderAddress });
|
||||
expect(firstByRecipientLog.events[1].attributes).toContain({ key: "recipient", value: recipient });
|
||||
// wasm event attributes added wasmd
|
||||
expect(firstByRecipientLog.events[1].attributes).toContain({
|
||||
key: "contract_address",
|
||||
value: defaultConfig.erc20Tokens![1].contractAddress,
|
||||
});
|
||||
const byRecipeintTransaction = byRecipientResult.transaction;
|
||||
assert(isSendTransaction(byRecipeintTransaction), "Expected send transaction");
|
||||
expect(byRecipeintTransaction).toEqual(unsigned);
|
||||
|
||||
// search by height
|
||||
const heightResults = await connection.searchTx({ height: byIdResult.height });
|
||||
expect(heightResults.length).toEqual(1);
|
||||
const heightResult = heightResults[0];
|
||||
expect(heightResult.transactionId).toEqual(transactionId);
|
||||
assert(isConfirmedTransaction(heightResult), "Expected transaction to succeed");
|
||||
assert(heightResult.log, "Log must be available");
|
||||
const [firstHeightLog] = JSON.parse(heightResult.log);
|
||||
expect(firstHeightLog.events.length).toEqual(2);
|
||||
const heightTransaction = heightResult.transaction;
|
||||
assert(isSendTransaction(heightTransaction), "Expected send transaction");
|
||||
expect(heightTransaction).toEqual(unsigned);
|
||||
|
||||
connection.disconnect();
|
||||
});
|
||||
|
||||
it("can search by minHeight and maxHeight", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
@ -980,47 +1098,4 @@ describe("CosmWasmConnection", () => {
|
||||
})().catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
describe("integration tests", () => {
|
||||
it("can send ERC20 tokens", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const profile = new UserProfile();
|
||||
const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(faucet.mnemonic));
|
||||
const sender = await profile.createIdentity(wallet.id, defaultChainId, faucet.path);
|
||||
const senderAddress = connection.codec.identityToAddress(sender);
|
||||
const recipient = makeRandomAddress();
|
||||
|
||||
const unsigned = await connection.withDefaultFee<SendTransaction>({
|
||||
kind: "bcp/send",
|
||||
chainId: defaultChainId,
|
||||
sender: senderAddress,
|
||||
recipient: recipient,
|
||||
memo: "My first payment",
|
||||
amount: {
|
||||
quantity: "75",
|
||||
fractionalDigits: 0,
|
||||
tokenTicker: "ISA" as TokenTicker,
|
||||
},
|
||||
});
|
||||
const nonce = await connection.getNonce({ address: senderAddress });
|
||||
const signed = await profile.signTransaction(sender, unsigned, connection.codec, nonce);
|
||||
const postableBytes = connection.codec.bytesToPost(signed);
|
||||
const response = await connection.postTx(postableBytes);
|
||||
const blockInfo = await response.blockInfo.waitFor(info => !isBlockInfoPending(info));
|
||||
expect(blockInfo.state).toEqual(TransactionState.Succeeded);
|
||||
|
||||
const recipientAccount = await connection.getAccount({ address: recipient });
|
||||
assert(recipientAccount, "Recipient account must have ISA tokens");
|
||||
expect(recipientAccount.balance).toEqual([
|
||||
{
|
||||
tokenTicker: "ISA" as TokenTicker,
|
||||
quantity: "75",
|
||||
fractionalDigits: 0,
|
||||
},
|
||||
]);
|
||||
|
||||
connection.disconnect();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -60,6 +60,25 @@ function isDefined<X>(value: X | undefined): value is X {
|
||||
return value !== undefined;
|
||||
}
|
||||
|
||||
function deduplicate<T>(input: ReadonlyArray<T>, comparator: (a: T, b: T) => number): Array<T> {
|
||||
const out = new Array<T>();
|
||||
for (const element of input) {
|
||||
if (!out.find(o => comparator(o, element) === 0)) {
|
||||
out.push(element);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Compares transaxtion by height. If the height is equal, compare by hash to ensure deterministic order */
|
||||
function compareByHeightAndHash(a: TxsResponse, b: TxsResponse): number {
|
||||
if (a.height === b.height) {
|
||||
return a.txhash.localeCompare(b.txhash);
|
||||
} else {
|
||||
return parseInt(a.height, 10) - parseInt(b.height, 10);
|
||||
}
|
||||
}
|
||||
|
||||
/** Account and undefined are valid events. The third option means no event fired yet */
|
||||
type LastWatchAccountEvent = Account | undefined | "no_event_fired_yet";
|
||||
|
||||
@ -324,7 +343,35 @@ export class CosmWasmConnection implements BlockchainConnection {
|
||||
} else if (height) {
|
||||
txs = await this.cosmWasmClient.searchTx({ height: height }, filter);
|
||||
} else if (sentFromOrTo) {
|
||||
txs = await this.cosmWasmClient.searchTx({ sentFromOrTo: sentFromOrTo }, filter);
|
||||
const pendingRequests = new Array<Promise<readonly TxsResponse[]>>();
|
||||
pendingRequests.push(this.cosmWasmClient.searchTx({ sentFromOrTo: sentFromOrTo }, filter));
|
||||
for (const contract of this.erc20Tokens.map(token => token.contractAddress)) {
|
||||
const searchBySender = [
|
||||
{
|
||||
key: "wasm.contract_address",
|
||||
value: contract,
|
||||
},
|
||||
{
|
||||
key: "wasm.sender",
|
||||
value: sentFromOrTo,
|
||||
},
|
||||
];
|
||||
const searchByRecipient = [
|
||||
{
|
||||
key: "wasm.contract_address",
|
||||
value: contract,
|
||||
},
|
||||
{
|
||||
key: "wasm.recipient",
|
||||
value: sentFromOrTo,
|
||||
},
|
||||
];
|
||||
pendingRequests.push(this.cosmWasmClient.searchTx({ tags: searchBySender }, filter));
|
||||
pendingRequests.push(this.cosmWasmClient.searchTx({ tags: searchByRecipient }, filter));
|
||||
}
|
||||
const responses = await Promise.all(pendingRequests);
|
||||
const allResults = responses.reduce((accumulator, results) => accumulator.concat(results), []);
|
||||
txs = deduplicate(allResults, (a, b) => a.txhash.localeCompare(b.txhash)).sort(compareByHeightAndHash);
|
||||
} else {
|
||||
throw new Error("Unsupported query");
|
||||
}
|
||||
|
||||
361
packages/sdk/src/cosmwasmclient.searchtx.spec.ts
Normal file
361
packages/sdk/src/cosmwasmclient.searchtx.spec.ts
Normal file
@ -0,0 +1,361 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import { assert, sleep } from "@iov/utils";
|
||||
|
||||
import { CosmWasmClient } from "./cosmwasmclient";
|
||||
import { Secp256k1Pen } from "./pen";
|
||||
import { RestClient } from "./restclient";
|
||||
import { SigningCosmWasmClient } from "./signingcosmwasmclient";
|
||||
import {
|
||||
deployedErc20,
|
||||
faucet,
|
||||
fromOneElementArray,
|
||||
makeRandomAddress,
|
||||
pendingWithoutWasmd,
|
||||
wasmdEnabled,
|
||||
wasmdEndpoint,
|
||||
} from "./testutils.spec";
|
||||
import { Coin, CosmosSdkTx, isMsgExecuteContract, isMsgInstantiateContract, isMsgSend } from "./types";
|
||||
|
||||
describe("CosmWasmClient.searchTx", () => {
|
||||
let postedSend:
|
||||
| {
|
||||
readonly sender: string;
|
||||
readonly recipient: string;
|
||||
readonly hash: string;
|
||||
readonly height: number;
|
||||
readonly tx: CosmosSdkTx;
|
||||
}
|
||||
| undefined;
|
||||
let postedExecute:
|
||||
| {
|
||||
readonly sender: string;
|
||||
readonly contract: string;
|
||||
readonly hash: string;
|
||||
readonly height: number;
|
||||
readonly tx: CosmosSdkTx;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
beforeAll(async () => {
|
||||
if (wasmdEnabled()) {
|
||||
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
||||
const client = new SigningCosmWasmClient(wasmdEndpoint, faucet.address, signBytes =>
|
||||
pen.sign(signBytes),
|
||||
);
|
||||
|
||||
{
|
||||
const recipient = makeRandomAddress();
|
||||
const transferAmount: Coin = {
|
||||
denom: "ucosm",
|
||||
amount: "1234567",
|
||||
};
|
||||
const result = await client.sendTokens(recipient, [transferAmount]);
|
||||
await sleep(50); // wait until tx is indexed
|
||||
const txDetails = await new RestClient(wasmdEndpoint).txsById(result.transactionHash);
|
||||
postedSend = {
|
||||
sender: faucet.address,
|
||||
recipient: recipient,
|
||||
hash: result.transactionHash,
|
||||
height: Number.parseInt(txDetails.height, 10),
|
||||
tx: txDetails.tx,
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
const hashInstance = deployedErc20.instances[0];
|
||||
const msg = {
|
||||
approve: {
|
||||
spender: makeRandomAddress(),
|
||||
amount: "12",
|
||||
},
|
||||
};
|
||||
const result = await client.execute(hashInstance, msg);
|
||||
await sleep(50); // wait until tx is indexed
|
||||
const txDetails = await new RestClient(wasmdEndpoint).txsById(result.transactionHash);
|
||||
postedExecute = {
|
||||
sender: faucet.address,
|
||||
contract: hashInstance,
|
||||
hash: result.transactionHash,
|
||||
height: Number.parseInt(txDetails.height, 10),
|
||||
tx: txDetails.tx,
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
describe("with SearchByIdQuery", () => {
|
||||
it("can search by ID", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(postedSend, "value must be set in beforeAll()");
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const result = await client.searchTx({ id: postedSend.hash });
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0]).toEqual(
|
||||
jasmine.objectContaining({
|
||||
height: postedSend.height.toString(),
|
||||
txhash: postedSend.hash,
|
||||
tx: postedSend.tx,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("can search by ID (non existent)", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const nonExistentId = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
const result = await client.searchTx({ id: nonExistentId });
|
||||
expect(result.length).toEqual(0);
|
||||
});
|
||||
|
||||
it("can search by ID and filter by minHeight", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(postedSend);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const query = { id: postedSend.hash };
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: 0 });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: postedSend.height - 1 });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: postedSend.height });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: postedSend.height + 1 });
|
||||
expect(result.length).toEqual(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("with SearchByHeightQuery", () => {
|
||||
it("can search by height", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(postedSend, "value must be set in beforeAll()");
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const result = await client.searchTx({ height: postedSend.height });
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0]).toEqual(
|
||||
jasmine.objectContaining({
|
||||
height: postedSend.height.toString(),
|
||||
txhash: postedSend.hash,
|
||||
tx: postedSend.tx,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with SearchBySentFromOrToQuery", () => {
|
||||
it("can search by sender", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(postedSend, "value must be set in beforeAll()");
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const results = await client.searchTx({ sentFromOrTo: postedSend.sender });
|
||||
expect(results.length).toBeGreaterThanOrEqual(1);
|
||||
|
||||
// Check basic structure of all results
|
||||
for (const result of results) {
|
||||
const msg = fromOneElementArray(result.tx.value.msg);
|
||||
assert(isMsgSend(msg), `${result.txhash} (height ${result.height}) is not a bank send transaction`);
|
||||
expect(
|
||||
msg.value.to_address === postedSend.sender || msg.value.from_address == postedSend.sender,
|
||||
).toEqual(true);
|
||||
}
|
||||
|
||||
// Check details of most recent result
|
||||
expect(results[results.length - 1]).toEqual(
|
||||
jasmine.objectContaining({
|
||||
height: postedSend.height.toString(),
|
||||
txhash: postedSend.hash,
|
||||
tx: postedSend.tx,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("can search by recipient", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(postedSend, "value must be set in beforeAll()");
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const results = await client.searchTx({ sentFromOrTo: postedSend.recipient });
|
||||
expect(results.length).toBeGreaterThanOrEqual(1);
|
||||
|
||||
// Check basic structure of all results
|
||||
for (const result of results) {
|
||||
const msg = fromOneElementArray(result.tx.value.msg);
|
||||
assert(isMsgSend(msg), `${result.txhash} (height ${result.height}) is not a bank send transaction`);
|
||||
expect(
|
||||
msg.value.to_address === postedSend.recipient || msg.value.from_address == postedSend.recipient,
|
||||
).toEqual(true);
|
||||
}
|
||||
|
||||
// Check details of most recent result
|
||||
expect(results[results.length - 1]).toEqual(
|
||||
jasmine.objectContaining({
|
||||
height: postedSend.height.toString(),
|
||||
txhash: postedSend.hash,
|
||||
tx: postedSend.tx,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("can search by recipient and filter by minHeight", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(postedSend);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const query = { sentFromOrTo: postedSend.recipient };
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: 0 });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: postedSend.height - 1 });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: postedSend.height });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: postedSend.height + 1 });
|
||||
expect(result.length).toEqual(0);
|
||||
}
|
||||
});
|
||||
|
||||
it("can search by recipient and filter by maxHeight", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(postedSend);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const query = { sentFromOrTo: postedSend.recipient };
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { maxHeight: 9999999999999 });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { maxHeight: postedSend.height + 1 });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { maxHeight: postedSend.height });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { maxHeight: postedSend.height - 1 });
|
||||
expect(result.length).toEqual(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("with SearchByTagsQuery", () => {
|
||||
it("can search by transfer.recipient", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(postedSend, "value must be set in beforeAll()");
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const results = await client.searchTx({
|
||||
tags: [{ key: "transfer.recipient", value: postedSend.recipient }],
|
||||
});
|
||||
expect(results.length).toBeGreaterThanOrEqual(1);
|
||||
|
||||
// Check basic structure of all results
|
||||
for (const result of results) {
|
||||
const msg = fromOneElementArray(result.tx.value.msg);
|
||||
assert(isMsgSend(msg), `${result.txhash} (height ${result.height}) is not a bank send transaction`);
|
||||
expect(msg.value.to_address).toEqual(postedSend.recipient);
|
||||
}
|
||||
|
||||
// Check details of most recent result
|
||||
expect(results[results.length - 1]).toEqual(
|
||||
jasmine.objectContaining({
|
||||
height: postedSend.height.toString(),
|
||||
txhash: postedSend.hash,
|
||||
tx: postedSend.tx,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("can search by message.contract_address", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(postedExecute, "value must be set in beforeAll()");
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const results = await client.searchTx({
|
||||
tags: [{ key: "message.contract_address", value: postedExecute.contract }],
|
||||
});
|
||||
expect(results.length).toBeGreaterThanOrEqual(1);
|
||||
|
||||
// Check basic structure of all results
|
||||
for (const result of results) {
|
||||
const msg = fromOneElementArray(result.tx.value.msg);
|
||||
assert(
|
||||
isMsgExecuteContract(msg) || isMsgInstantiateContract(msg),
|
||||
`${result.txhash} (at ${result.height}) not an execute or instantiate msg`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the first result is the instantiation
|
||||
const first = fromOneElementArray(results[0].tx.value.msg);
|
||||
assert(isMsgInstantiateContract(first), "First contract search result must be an instantiation");
|
||||
expect(first).toEqual({
|
||||
type: "wasm/instantiate",
|
||||
value: {
|
||||
sender: faucet.address,
|
||||
code_id: deployedErc20.codeId.toString(),
|
||||
label: "HASH",
|
||||
init_msg: jasmine.objectContaining({ symbol: "HASH" }),
|
||||
init_funds: [],
|
||||
},
|
||||
});
|
||||
|
||||
// Check details of most recent result
|
||||
expect(results[results.length - 1]).toEqual(
|
||||
jasmine.objectContaining({
|
||||
height: postedExecute.height.toString(),
|
||||
txhash: postedExecute.hash,
|
||||
tx: postedExecute.tx,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("can search by message.contract_address + message.action", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(postedExecute, "value must be set in beforeAll()");
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const results = await client.searchTx({
|
||||
tags: [
|
||||
{ key: "message.contract_address", value: postedExecute.contract },
|
||||
{ key: "message.action", value: "execute" },
|
||||
],
|
||||
});
|
||||
expect(results.length).toBeGreaterThanOrEqual(1);
|
||||
|
||||
// Check basic structure of all results
|
||||
for (const result of results) {
|
||||
const msg = fromOneElementArray(result.tx.value.msg);
|
||||
assert(isMsgExecuteContract(msg), `${result.txhash} (at ${result.height}) not an execute msg`);
|
||||
expect(msg.value.contract).toEqual(postedExecute.contract);
|
||||
}
|
||||
|
||||
// Check details of most recent result
|
||||
expect(results[results.length - 1]).toEqual(
|
||||
jasmine.objectContaining({
|
||||
height: postedExecute.height.toString(),
|
||||
txhash: postedExecute.hash,
|
||||
tx: postedExecute.tx,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,39 +1,29 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import { Sha256 } from "@iov/crypto";
|
||||
import { Bech32, Encoding } from "@iov/encoding";
|
||||
import { assert, sleep } from "@iov/utils";
|
||||
import { assert } from "@iov/utils";
|
||||
import { ReadonlyDate } from "readonly-date";
|
||||
|
||||
import { Code, CosmWasmClient } from "./cosmwasmclient";
|
||||
import { makeSignBytes } from "./encoding";
|
||||
import { findAttribute } from "./logs";
|
||||
import { Secp256k1Pen } from "./pen";
|
||||
import { RestClient } from "./restclient";
|
||||
import { SigningCosmWasmClient } from "./signingcosmwasmclient";
|
||||
import cosmoshub from "./testdata/cosmoshub.json";
|
||||
import {
|
||||
deployedErc20,
|
||||
faucet,
|
||||
getRandomizedHackatom,
|
||||
makeRandomAddress,
|
||||
pendingWithoutWasmd,
|
||||
tendermintIdMatcher,
|
||||
wasmdEnabled,
|
||||
wasmdEndpoint,
|
||||
} from "./testutils.spec";
|
||||
import { CosmosSdkTx, MsgSend, StdFee } from "./types";
|
||||
import { MsgSend, StdFee } from "./types";
|
||||
|
||||
const { fromAscii, fromHex, fromUtf8, toAscii, toBase64 } = Encoding;
|
||||
|
||||
const httpUrl = "http://localhost:1317";
|
||||
|
||||
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 unused = {
|
||||
address: "cosmos1cjsxept9rkggzxztslae9ndgpdyt2408lk850u",
|
||||
};
|
||||
@ -53,7 +43,7 @@ interface HackatomInstance {
|
||||
describe("CosmWasmClient", () => {
|
||||
describe("makeReadOnly", () => {
|
||||
it("can be constructed", () => {
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
expect(client).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -61,7 +51,7 @@ describe("CosmWasmClient", () => {
|
||||
describe("chainId", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
expect(await client.chainId()).toEqual("testing");
|
||||
});
|
||||
});
|
||||
@ -69,7 +59,7 @@ describe("CosmWasmClient", () => {
|
||||
describe("getNonce", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
expect(await client.getNonce(unused.address)).toEqual({
|
||||
accountNumber: 5,
|
||||
sequence: 0,
|
||||
@ -78,7 +68,7 @@ describe("CosmWasmClient", () => {
|
||||
|
||||
it("throws for missing accounts", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const missing = makeRandomAddress();
|
||||
await client.getNonce(missing).then(
|
||||
() => fail("this must not succeed"),
|
||||
@ -90,7 +80,7 @@ describe("CosmWasmClient", () => {
|
||||
describe("getAccount", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
expect(await client.getAccount(unused.address)).toEqual({
|
||||
address: unused.address,
|
||||
account_number: 5,
|
||||
@ -105,7 +95,7 @@ describe("CosmWasmClient", () => {
|
||||
|
||||
it("returns undefined for missing accounts", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const missing = makeRandomAddress();
|
||||
expect(await client.getAccount(missing)).toBeUndefined();
|
||||
});
|
||||
@ -114,7 +104,7 @@ describe("CosmWasmClient", () => {
|
||||
describe("getBlock", () => {
|
||||
it("works for latest block", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const response = await client.getBlock();
|
||||
|
||||
// id
|
||||
@ -134,7 +124,7 @@ describe("CosmWasmClient", () => {
|
||||
|
||||
it("works for block by height", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const height = parseInt((await client.getBlock()).block.header.height, 10);
|
||||
const response = await client.getBlock(height - 1);
|
||||
|
||||
@ -157,7 +147,7 @@ describe("CosmWasmClient", () => {
|
||||
describe("getIdentifier", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
expect(await client.getIdentifier(cosmoshub.tx)).toEqual(cosmoshub.id);
|
||||
});
|
||||
});
|
||||
@ -166,7 +156,7 @@ describe("CosmWasmClient", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
|
||||
const memo = "My first contract on chain";
|
||||
const sendMsg: MsgSend = {
|
||||
@ -210,205 +200,18 @@ describe("CosmWasmClient", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("searchTx", () => {
|
||||
let posted:
|
||||
| {
|
||||
readonly sender: string;
|
||||
readonly recipient: string;
|
||||
readonly hash: string;
|
||||
readonly height: number;
|
||||
readonly tx: CosmosSdkTx;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
beforeAll(async () => {
|
||||
if (wasmdEnabled()) {
|
||||
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
||||
const client = new SigningCosmWasmClient(httpUrl, faucet.address, signBytes => pen.sign(signBytes));
|
||||
|
||||
const recipient = makeRandomAddress();
|
||||
const transferAmount = [
|
||||
{
|
||||
denom: "ucosm",
|
||||
amount: "1234567",
|
||||
},
|
||||
];
|
||||
const result = await client.sendTokens(recipient, transferAmount);
|
||||
|
||||
await sleep(50); // wait until tx is indexed
|
||||
const txDetails = await new RestClient(httpUrl).txsById(result.transactionHash);
|
||||
posted = {
|
||||
sender: faucet.address,
|
||||
recipient: recipient,
|
||||
hash: result.transactionHash,
|
||||
height: Number.parseInt(txDetails.height, 10),
|
||||
tx: txDetails.tx,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
it("can search by ID", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted, "value must be set in beforeAll()");
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const result = await client.searchTx({ id: posted.hash });
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0]).toEqual(
|
||||
jasmine.objectContaining({
|
||||
height: posted.height.toString(),
|
||||
txhash: posted.hash,
|
||||
tx: posted.tx,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("can search by ID (non existent)", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const nonExistentId = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
const result = await client.searchTx({ id: nonExistentId });
|
||||
expect(result.length).toEqual(0);
|
||||
});
|
||||
|
||||
it("can search by height", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted, "value must be set in beforeAll()");
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const result = await client.searchTx({ height: posted.height });
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0]).toEqual(
|
||||
jasmine.objectContaining({
|
||||
height: posted.height.toString(),
|
||||
txhash: posted.hash,
|
||||
tx: posted.tx,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("can search by sender", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted, "value must be set in beforeAll()");
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const result = await client.searchTx({ sentFromOrTo: posted.sender });
|
||||
expect(result.length).toBeGreaterThanOrEqual(1);
|
||||
expect(result[result.length - 1]).toEqual(
|
||||
jasmine.objectContaining({
|
||||
height: posted.height.toString(),
|
||||
txhash: posted.hash,
|
||||
tx: posted.tx,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("can search by recipient", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted, "value must be set in beforeAll()");
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const result = await client.searchTx({ sentFromOrTo: posted.recipient });
|
||||
expect(result.length).toBeGreaterThanOrEqual(1);
|
||||
expect(result[result.length - 1]).toEqual(
|
||||
jasmine.objectContaining({
|
||||
height: posted.height.toString(),
|
||||
txhash: posted.hash,
|
||||
tx: posted.tx,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("can search by ID and filter by minHeight", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted);
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const query = { id: posted.hash };
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: 0 });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: posted.height - 1 });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: posted.height });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: posted.height + 1 });
|
||||
expect(result.length).toEqual(0);
|
||||
}
|
||||
});
|
||||
|
||||
it("can search by recipient and filter by minHeight", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted);
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const query = { sentFromOrTo: posted.recipient };
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: 0 });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: posted.height - 1 });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: posted.height });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { minHeight: posted.height + 1 });
|
||||
expect(result.length).toEqual(0);
|
||||
}
|
||||
});
|
||||
|
||||
it("can search by recipient and filter by maxHeight", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted);
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const query = { sentFromOrTo: posted.recipient };
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { maxHeight: 9999999999999 });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { maxHeight: posted.height + 1 });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { maxHeight: posted.height });
|
||||
expect(result.length).toEqual(1);
|
||||
}
|
||||
|
||||
{
|
||||
const result = await client.searchTx(query, { maxHeight: posted.height - 1 });
|
||||
expect(result.length).toEqual(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("getCodes", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const result = await client.getCodes();
|
||||
expect(result.length).toBeGreaterThanOrEqual(1);
|
||||
const [first] = result;
|
||||
expect(first).toEqual({
|
||||
id: 1,
|
||||
checksum: "aff8c8873d79d2153a8b9066a0683fec3c903669267eb806ffa831dcd4b3daae",
|
||||
source: undefined,
|
||||
builder: undefined,
|
||||
id: deployedErc20.codeId,
|
||||
source: deployedErc20.source,
|
||||
builder: deployedErc20.builder,
|
||||
checksum: deployedErc20.checksum,
|
||||
creator: faucet.address,
|
||||
});
|
||||
});
|
||||
@ -417,14 +220,14 @@ describe("CosmWasmClient", () => {
|
||||
describe("getCodeDetails", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const result = await client.getCodeDetails(1);
|
||||
|
||||
const expectedInfo: Code = {
|
||||
id: 1,
|
||||
checksum: "aff8c8873d79d2153a8b9066a0683fec3c903669267eb806ffa831dcd4b3daae",
|
||||
source: undefined,
|
||||
builder: undefined,
|
||||
id: deployedErc20.codeId,
|
||||
source: deployedErc20.source,
|
||||
builder: deployedErc20.builder,
|
||||
checksum: deployedErc20.checksum,
|
||||
creator: faucet.address,
|
||||
};
|
||||
|
||||
@ -438,7 +241,7 @@ describe("CosmWasmClient", () => {
|
||||
describe("getContracts", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const result = await client.getContracts(1);
|
||||
expect(result.length).toBeGreaterThanOrEqual(3);
|
||||
const [hash, isa, jade] = result;
|
||||
@ -466,7 +269,7 @@ describe("CosmWasmClient", () => {
|
||||
describe("getContract", () => {
|
||||
it("works for HASH instance", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const hash = await client.getContract("cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5");
|
||||
expect(hash).toEqual({
|
||||
address: "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5",
|
||||
@ -505,7 +308,9 @@ describe("CosmWasmClient", () => {
|
||||
if (wasmdEnabled()) {
|
||||
pendingWithoutWasmd();
|
||||
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
||||
const client = new SigningCosmWasmClient(httpUrl, faucet.address, signBytes => pen.sign(signBytes));
|
||||
const client = new SigningCosmWasmClient(wasmdEndpoint, faucet.address, signBytes =>
|
||||
pen.sign(signBytes),
|
||||
);
|
||||
const { codeId } = await client.upload(getRandomizedHackatom());
|
||||
const initMsg = { verifier: makeRandomAddress(), beneficiary: makeRandomAddress() };
|
||||
const contractAddress = await client.instantiate(codeId, initMsg, "random hackatom");
|
||||
@ -517,7 +322,7 @@ describe("CosmWasmClient", () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(contract);
|
||||
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const raw = await client.queryContractRaw(contract.address, configKey);
|
||||
assert(raw, "must get result");
|
||||
expect(JSON.parse(fromUtf8(raw))).toEqual({
|
||||
@ -531,7 +336,7 @@ describe("CosmWasmClient", () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(contract);
|
||||
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const raw = await client.queryContractRaw(contract.address, otherKey);
|
||||
expect(raw).toBeNull();
|
||||
});
|
||||
@ -541,7 +346,7 @@ describe("CosmWasmClient", () => {
|
||||
assert(contract);
|
||||
|
||||
const nonExistentAddress = makeRandomAddress();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
await client.queryContractRaw(nonExistentAddress, configKey).then(
|
||||
() => fail("must not succeed"),
|
||||
error => expect(error).toMatch(`No contract found at address "${nonExistentAddress}"`),
|
||||
@ -556,7 +361,9 @@ describe("CosmWasmClient", () => {
|
||||
if (wasmdEnabled()) {
|
||||
pendingWithoutWasmd();
|
||||
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
||||
const client = new SigningCosmWasmClient(httpUrl, faucet.address, signBytes => pen.sign(signBytes));
|
||||
const client = new SigningCosmWasmClient(wasmdEndpoint, faucet.address, signBytes =>
|
||||
pen.sign(signBytes),
|
||||
);
|
||||
const { codeId } = await client.upload(getRandomizedHackatom());
|
||||
const initMsg = { verifier: makeRandomAddress(), beneficiary: makeRandomAddress() };
|
||||
const contractAddress = await client.instantiate(codeId, initMsg, "a different hackatom");
|
||||
@ -568,7 +375,7 @@ describe("CosmWasmClient", () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(contract);
|
||||
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const verifier = await client.queryContractSmart(contract.address, { verifier: {} });
|
||||
expect(fromAscii(verifier)).toEqual(contract.initMsg.verifier);
|
||||
});
|
||||
@ -577,7 +384,7 @@ describe("CosmWasmClient", () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(contract);
|
||||
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
await client.queryContractSmart(contract.address, { broken: {} }).then(
|
||||
() => fail("must not succeed"),
|
||||
error => expect(error).toMatch(/Error parsing QueryMsg/i),
|
||||
@ -588,7 +395,7 @@ describe("CosmWasmClient", () => {
|
||||
pendingWithoutWasmd();
|
||||
|
||||
const nonExistentAddress = makeRandomAddress();
|
||||
const client = new CosmWasmClient(httpUrl);
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
await client.queryContractSmart(nonExistentAddress, { verifier: {} }).then(
|
||||
() => fail("must not succeed"),
|
||||
error => expect(error).toMatch(`No contract found at address "${nonExistentAddress}"`),
|
||||
|
||||
@ -13,7 +13,7 @@ export interface GetNonceResult {
|
||||
export interface PostTxResult {
|
||||
readonly logs: readonly Log[];
|
||||
readonly rawLog: string;
|
||||
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-exmpty upper-case hex */
|
||||
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
|
||||
readonly transactionHash: string;
|
||||
}
|
||||
|
||||
@ -29,7 +29,19 @@ export interface SearchBySentFromOrToQuery {
|
||||
readonly sentFromOrTo: string;
|
||||
}
|
||||
|
||||
export type SearchTxQuery = SearchByIdQuery | SearchByHeightQuery | SearchBySentFromOrToQuery;
|
||||
/**
|
||||
* This query type allows you to pass arbitrary key/value pairs to the backend. It is
|
||||
* more powerful and slightly lower level than the other search options.
|
||||
*/
|
||||
export interface SearchByTagsQuery {
|
||||
readonly tags: readonly { readonly key: string; readonly value: string }[];
|
||||
}
|
||||
|
||||
export type SearchTxQuery =
|
||||
| SearchByIdQuery
|
||||
| SearchByHeightQuery
|
||||
| SearchBySentFromOrToQuery
|
||||
| SearchByTagsQuery;
|
||||
|
||||
function isSearchByIdQuery(query: SearchTxQuery): query is SearchByIdQuery {
|
||||
return (query as SearchByIdQuery).id !== undefined;
|
||||
@ -43,6 +55,10 @@ function isSearchBySentFromOrToQuery(query: SearchTxQuery): query is SearchBySen
|
||||
return (query as SearchBySentFromOrToQuery).sentFromOrTo !== undefined;
|
||||
}
|
||||
|
||||
function isSearchByTagsQuery(query: SearchTxQuery): query is SearchByTagsQuery {
|
||||
return (query as SearchByTagsQuery).tags !== undefined;
|
||||
}
|
||||
|
||||
export interface SearchTxFilter {
|
||||
readonly minHeight?: number;
|
||||
readonly maxHeight?: number;
|
||||
@ -159,11 +175,16 @@ export class CosmWasmClient {
|
||||
}
|
||||
} else if (isSearchBySentFromOrToQuery(query)) {
|
||||
// We cannot get both in one request (see https://github.com/cosmos/gaia/issues/75)
|
||||
const sent = await this.txsQuery(withFilters(`message.sender=${query.sentFromOrTo}`));
|
||||
const received = await this.txsQuery(withFilters(`transfer.recipient=${query.sentFromOrTo}`));
|
||||
const sentQuery = withFilters(`message.module=bank&message.sender=${query.sentFromOrTo}`);
|
||||
const receivedQuery = withFilters(`message.module=bank&transfer.recipient=${query.sentFromOrTo}`);
|
||||
const sent = await this.txsQuery(sentQuery);
|
||||
const received = await this.txsQuery(receivedQuery);
|
||||
|
||||
const sentHashes = sent.map(t => t.txhash);
|
||||
txs = [...sent, ...received.filter(t => !sentHashes.includes(t.txhash))];
|
||||
} else if (isSearchByTagsQuery(query)) {
|
||||
const rawQuery = withFilters(query.tags.map(t => `${t.key}=${t.value}`).join("&"));
|
||||
txs = await this.txsQuery(rawQuery);
|
||||
} else {
|
||||
throw new Error("Unknown query type");
|
||||
}
|
||||
|
||||
@ -13,6 +13,9 @@ import { SigningCosmWasmClient } from "./signingcosmwasmclient";
|
||||
import cosmoshub from "./testdata/cosmoshub.json";
|
||||
import {
|
||||
bech32AddressMatcher,
|
||||
deployedErc20,
|
||||
faucet,
|
||||
fromOneElementArray,
|
||||
getRandomizedHackatom,
|
||||
makeRandomAddress,
|
||||
pendingWithoutWasmd,
|
||||
@ -20,9 +23,12 @@ import {
|
||||
tendermintIdMatcher,
|
||||
tendermintOptionalIdMatcher,
|
||||
wasmdEnabled,
|
||||
wasmdEndpoint,
|
||||
} from "./testutils.spec";
|
||||
import {
|
||||
Coin,
|
||||
isMsgInstantiateContract,
|
||||
isMsgStoreCode,
|
||||
Msg,
|
||||
MsgExecuteContract,
|
||||
MsgInstantiateContract,
|
||||
@ -35,17 +41,7 @@ import {
|
||||
|
||||
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",
|
||||
@ -168,7 +164,7 @@ async function executeContract(
|
||||
|
||||
describe("RestClient", () => {
|
||||
it("can be constructed", () => {
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
expect(client).toBeTruthy();
|
||||
});
|
||||
|
||||
@ -177,7 +173,7 @@ describe("RestClient", () => {
|
||||
describe("authAccounts", () => {
|
||||
it("works for unused account without pubkey", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const { result } = await client.authAccounts(unusedAccount.address);
|
||||
expect(result).toEqual({
|
||||
type: "cosmos-sdk/Account",
|
||||
@ -203,7 +199,7 @@ describe("RestClient", () => {
|
||||
// This fails in the first test run if you forget to run `./scripts/wasmd/init.sh`
|
||||
it("has correct pubkey for faucet", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const { result } = await client.authAccounts(faucet.address);
|
||||
expect(result.value).toEqual(
|
||||
jasmine.objectContaining({
|
||||
@ -215,7 +211,7 @@ describe("RestClient", () => {
|
||||
// This property is used by CosmWasmClient.getAccount
|
||||
it("returns empty address for non-existent account", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const nonExistentAccount = makeRandomAddress();
|
||||
const { result } = await client.authAccounts(nonExistentAccount);
|
||||
expect(result).toEqual({
|
||||
@ -230,7 +226,7 @@ describe("RestClient", () => {
|
||||
describe("blocksLatest", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const response = await client.blocksLatest();
|
||||
|
||||
// id
|
||||
@ -263,7 +259,7 @@ describe("RestClient", () => {
|
||||
describe("blocks", () => {
|
||||
it("works for block by height", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const height = parseInt((await client.blocksLatest()).block.header.height, 10);
|
||||
const response = await client.blocks(height - 1);
|
||||
|
||||
@ -299,7 +295,7 @@ describe("RestClient", () => {
|
||||
describe("nodeInfo", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const info = await client.nodeInfo();
|
||||
expect(info.node_info.network).toEqual(defaultNetworkId);
|
||||
});
|
||||
@ -321,7 +317,9 @@ describe("RestClient", () => {
|
||||
beforeAll(async () => {
|
||||
if (wasmdEnabled()) {
|
||||
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
||||
const client = new SigningCosmWasmClient(httpUrl, faucet.address, signBytes => pen.sign(signBytes));
|
||||
const client = new SigningCosmWasmClient(wasmdEndpoint, faucet.address, signBytes =>
|
||||
pen.sign(signBytes),
|
||||
);
|
||||
|
||||
const recipient = makeRandomAddress();
|
||||
const transferAmount = [
|
||||
@ -333,7 +331,7 @@ describe("RestClient", () => {
|
||||
const result = await client.sendTokens(recipient, transferAmount);
|
||||
|
||||
await sleep(50); // wait until tx is indexed
|
||||
const txDetails = await new RestClient(httpUrl).txsById(result.transactionHash);
|
||||
const txDetails = await new RestClient(wasmdEndpoint).txsById(result.transactionHash);
|
||||
posted = {
|
||||
sender: faucet.address,
|
||||
recipient: recipient,
|
||||
@ -347,7 +345,7 @@ describe("RestClient", () => {
|
||||
it("can query transactions by height", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted);
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const result = await client.txsQuery(`tx.height=${posted.height}&limit=26`);
|
||||
expect(parseInt(result.count, 10)).toEqual(1);
|
||||
expect(parseInt(result.limit, 10)).toEqual(26);
|
||||
@ -360,7 +358,7 @@ describe("RestClient", () => {
|
||||
it("can query transactions by ID", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted);
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const result = await client.txsQuery(`tx.hash=${posted.hash}&limit=26`);
|
||||
expect(parseInt(result.count, 10)).toEqual(1);
|
||||
expect(parseInt(result.limit, 10)).toEqual(26);
|
||||
@ -373,7 +371,7 @@ describe("RestClient", () => {
|
||||
it("can query transactions by sender", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted);
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const result = await client.txsQuery(`message.sender=${posted.sender}&limit=200`);
|
||||
expect(parseInt(result.count, 10)).toBeGreaterThanOrEqual(1);
|
||||
expect(parseInt(result.limit, 10)).toEqual(200);
|
||||
@ -387,7 +385,7 @@ describe("RestClient", () => {
|
||||
it("can query transactions by recipient", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted);
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const result = await client.txsQuery(`transfer.recipient=${posted.recipient}&limit=200`);
|
||||
expect(parseInt(result.count, 10)).toEqual(1);
|
||||
expect(parseInt(result.limit, 10)).toEqual(200);
|
||||
@ -402,7 +400,7 @@ describe("RestClient", () => {
|
||||
pending("This combination is broken 🤷♂️. Handle client-side at higher level.");
|
||||
pendingWithoutWasmd();
|
||||
assert(posted);
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const hashQuery = `tx.hash=${posted.hash}`;
|
||||
|
||||
{
|
||||
@ -429,7 +427,7 @@ describe("RestClient", () => {
|
||||
it("can filter by recipient and tx.minheight", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted);
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const recipientQuery = `transfer.recipient=${posted.recipient}`;
|
||||
|
||||
{
|
||||
@ -456,7 +454,7 @@ describe("RestClient", () => {
|
||||
it("can filter by recipient and tx.maxheight", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted);
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const recipientQuery = `transfer.recipient=${posted.recipient}`;
|
||||
|
||||
{
|
||||
@ -479,12 +477,114 @@ describe("RestClient", () => {
|
||||
expect(count).toEqual("0");
|
||||
}
|
||||
});
|
||||
|
||||
it("can query by tags (module + code_id)", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const result = await client.txsQuery(`message.module=wasm&message.code_id=${deployedErc20.codeId}`);
|
||||
expect(parseInt(result.count, 10)).toBeGreaterThanOrEqual(4);
|
||||
|
||||
// Check first 4 results
|
||||
const [store, hash, isa, jade] = result.txs.map(tx => fromOneElementArray(tx.tx.value.msg));
|
||||
assert(isMsgStoreCode(store));
|
||||
assert(isMsgInstantiateContract(hash));
|
||||
assert(isMsgInstantiateContract(isa));
|
||||
assert(isMsgInstantiateContract(jade));
|
||||
expect(store.value).toEqual(
|
||||
jasmine.objectContaining({
|
||||
sender: faucet.address,
|
||||
source: deployedErc20.source,
|
||||
builder: deployedErc20.builder,
|
||||
}),
|
||||
);
|
||||
expect(hash.value).toEqual({
|
||||
code_id: deployedErc20.codeId.toString(),
|
||||
init_funds: [],
|
||||
init_msg: jasmine.objectContaining({
|
||||
symbol: "HASH",
|
||||
}),
|
||||
label: "HASH",
|
||||
sender: faucet.address,
|
||||
});
|
||||
expect(isa.value).toEqual({
|
||||
code_id: deployedErc20.codeId.toString(),
|
||||
init_funds: [],
|
||||
init_msg: jasmine.objectContaining({ symbol: "ISA" }),
|
||||
label: "ISA",
|
||||
sender: faucet.address,
|
||||
});
|
||||
expect(jade.value).toEqual({
|
||||
code_id: deployedErc20.codeId.toString(),
|
||||
init_funds: [],
|
||||
init_msg: jasmine.objectContaining({ symbol: "JADE" }),
|
||||
label: "JADE",
|
||||
sender: faucet.address,
|
||||
});
|
||||
});
|
||||
|
||||
// Like previous test but filtered by message.action=store-code and message.action=instantiate
|
||||
it("can query by tags (module + code_id + action)", async () => {
|
||||
pendingWithoutWasmd();
|
||||
assert(posted);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
|
||||
{
|
||||
const uploads = await client.txsQuery(
|
||||
`message.module=wasm&message.code_id=${deployedErc20.codeId}&message.action=store-code`,
|
||||
);
|
||||
expect(parseInt(uploads.count, 10)).toEqual(1);
|
||||
const store = fromOneElementArray(uploads.txs[0].tx.value.msg);
|
||||
assert(isMsgStoreCode(store));
|
||||
expect(store.value).toEqual(
|
||||
jasmine.objectContaining({
|
||||
sender: faucet.address,
|
||||
source: deployedErc20.source,
|
||||
builder: deployedErc20.builder,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
const instantiations = await client.txsQuery(
|
||||
`message.module=wasm&message.code_id=${deployedErc20.codeId}&message.action=instantiate`,
|
||||
);
|
||||
expect(parseInt(instantiations.count, 10)).toBeGreaterThanOrEqual(3);
|
||||
const [hash, isa, jade] = instantiations.txs.map(tx => fromOneElementArray(tx.tx.value.msg));
|
||||
assert(isMsgInstantiateContract(hash));
|
||||
assert(isMsgInstantiateContract(isa));
|
||||
assert(isMsgInstantiateContract(jade));
|
||||
expect(hash.value).toEqual({
|
||||
code_id: deployedErc20.codeId.toString(),
|
||||
init_funds: [],
|
||||
init_msg: jasmine.objectContaining({
|
||||
symbol: "HASH",
|
||||
}),
|
||||
label: "HASH",
|
||||
sender: faucet.address,
|
||||
});
|
||||
expect(isa.value).toEqual({
|
||||
code_id: deployedErc20.codeId.toString(),
|
||||
init_funds: [],
|
||||
init_msg: jasmine.objectContaining({ symbol: "ISA" }),
|
||||
label: "ISA",
|
||||
sender: faucet.address,
|
||||
});
|
||||
expect(jade.value).toEqual({
|
||||
code_id: deployedErc20.codeId.toString(),
|
||||
init_funds: [],
|
||||
init_msg: jasmine.objectContaining({ symbol: "JADE" }),
|
||||
label: "JADE",
|
||||
sender: faucet.address,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("encodeTx", () => {
|
||||
it("works for cosmoshub example", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
expect(await client.encodeTx(cosmoshub.tx)).toEqual(fromBase64(cosmoshub.tx_data));
|
||||
});
|
||||
});
|
||||
@ -519,7 +619,7 @@ describe("RestClient", () => {
|
||||
gas: "890000",
|
||||
};
|
||||
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const { account_number, sequence } = (await client.authAccounts(faucet.address)).result.value;
|
||||
|
||||
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account_number, sequence);
|
||||
@ -533,7 +633,7 @@ describe("RestClient", () => {
|
||||
it("can upload, instantiate and execute wasm", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
|
||||
const transferAmount: readonly Coin[] = [
|
||||
{
|
||||
@ -607,7 +707,7 @@ describe("RestClient", () => {
|
||||
it("can list upload code", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
|
||||
// check with contracts were here first to compare
|
||||
const existingInfos = await client.listCodeInfo();
|
||||
@ -647,7 +747,7 @@ describe("RestClient", () => {
|
||||
it("can list contracts and get info", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const beneficiaryAddress = makeRandomAddress();
|
||||
const transferAmount: readonly Coin[] = [
|
||||
{
|
||||
@ -708,7 +808,7 @@ describe("RestClient", () => {
|
||||
});
|
||||
|
||||
describe("contract state", () => {
|
||||
const client = new RestClient(httpUrl);
|
||||
const client = new RestClient(wasmdEndpoint);
|
||||
const noContract = makeRandomAddress();
|
||||
const expectedKey = toAscii("config");
|
||||
let contractAddress: string | undefined;
|
||||
|
||||
@ -83,6 +83,8 @@ export interface UploadReceipt {
|
||||
|
||||
export interface ExecuteResult {
|
||||
readonly logs: readonly Log[];
|
||||
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
|
||||
readonly transactionHash: string;
|
||||
}
|
||||
|
||||
export class SigningCosmWasmClient extends CosmWasmClient {
|
||||
@ -220,6 +222,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
|
||||
const result = await this.postTx(signedTx);
|
||||
return {
|
||||
logs: result.logs,
|
||||
transactionHash: result.transactionHash,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -63,6 +63,31 @@ export const tendermintAddressMatcher = /^[0-9A-F]{40}$/;
|
||||
// https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32
|
||||
export const bech32AddressMatcher = /^[\x21-\x7e]{1,83}1[02-9ac-hj-np-z]{38}$/;
|
||||
|
||||
/** Deployed as part of scripts/wasmd/init.sh */
|
||||
export const deployedErc20 = {
|
||||
codeId: 1,
|
||||
source: "https://crates.io/api/v1/crates/cw-erc20/0.2.0/download",
|
||||
builder: "confio/cosmwasm-opt:0.7.0",
|
||||
checksum: "aff8c8873d79d2153a8b9066a0683fec3c903669267eb806ffa831dcd4b3daae",
|
||||
instances: [
|
||||
"cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", // HASH
|
||||
"cosmos1hqrdl6wstt8qzshwc6mrumpjk9338k0lr4dqxd", // ISA
|
||||
"cosmos18r5szma8hm93pvx6lwpjwyxruw27e0k5uw835c", // JADE
|
||||
],
|
||||
};
|
||||
|
||||
export const wasmdEndpoint = "http://localhost:1317";
|
||||
|
||||
export 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",
|
||||
};
|
||||
|
||||
export function wasmdEnabled(): boolean {
|
||||
return !!process.env.WASMD_ENABLED;
|
||||
}
|
||||
@ -73,6 +98,12 @@ export function pendingWithoutWasmd(): void {
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns first element. Throws if array has a different length than 1. */
|
||||
export function fromOneElementArray<T>(elements: ArrayLike<T>): T {
|
||||
if (elements.length !== 1) throw new Error(`Expected exactly one element but got ${elements.length}`);
|
||||
return elements[0];
|
||||
}
|
||||
|
||||
describe("leb128", () => {
|
||||
describe("leb128Encode", () => {
|
||||
it("works for single byte values", () => {
|
||||
|
||||
18
packages/sdk/types/cosmwasmclient.d.ts
vendored
18
packages/sdk/types/cosmwasmclient.d.ts
vendored
@ -8,7 +8,7 @@ export interface GetNonceResult {
|
||||
export interface PostTxResult {
|
||||
readonly logs: readonly Log[];
|
||||
readonly rawLog: string;
|
||||
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-exmpty upper-case hex */
|
||||
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
|
||||
readonly transactionHash: string;
|
||||
}
|
||||
export interface SearchByIdQuery {
|
||||
@ -20,7 +20,21 @@ export interface SearchByHeightQuery {
|
||||
export interface SearchBySentFromOrToQuery {
|
||||
readonly sentFromOrTo: string;
|
||||
}
|
||||
export declare type SearchTxQuery = SearchByIdQuery | SearchByHeightQuery | SearchBySentFromOrToQuery;
|
||||
/**
|
||||
* This query type allows you to pass arbitrary key/value pairs to the backend. It is
|
||||
* more powerful and slightly lower level than the other search options.
|
||||
*/
|
||||
export interface SearchByTagsQuery {
|
||||
readonly tags: readonly {
|
||||
readonly key: string;
|
||||
readonly value: string;
|
||||
}[];
|
||||
}
|
||||
export declare type SearchTxQuery =
|
||||
| SearchByIdQuery
|
||||
| SearchByHeightQuery
|
||||
| SearchBySentFromOrToQuery
|
||||
| SearchByTagsQuery;
|
||||
export interface SearchTxFilter {
|
||||
readonly minHeight?: number;
|
||||
readonly maxHeight?: number;
|
||||
|
||||
@ -31,6 +31,8 @@ export interface UploadReceipt {
|
||||
}
|
||||
export interface ExecuteResult {
|
||||
readonly logs: readonly Log[];
|
||||
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
|
||||
readonly transactionHash: string;
|
||||
}
|
||||
export declare class SigningCosmWasmClient extends CosmWasmClient {
|
||||
readonly senderAddress: string;
|
||||
|
||||
@ -17,6 +17,11 @@ const guest = {
|
||||
address: "cosmos17d0jcz59jf68g52vq38tuuncmwwjk42u6mcxej",
|
||||
};
|
||||
|
||||
const codeMeta = {
|
||||
source: "https://crates.io/api/v1/crates/cw-erc20/0.2.0/download",
|
||||
builder: "confio/cosmwasm-opt:0.7.0",
|
||||
};
|
||||
|
||||
const initMsgHash = {
|
||||
decimals: 5,
|
||||
name: "Hash token",
|
||||
@ -72,7 +77,7 @@ async function main() {
|
||||
const client = new SigningCosmWasmClient(httpUrl, faucet.address, signBytes => pen.sign(signBytes));
|
||||
|
||||
const wasm = fs.readFileSync(__dirname + "/contracts/cw-erc20.wasm");
|
||||
const uploadReceipt = await client.upload(wasm, {}, "Upload ERC20 contract");
|
||||
const uploadReceipt = await client.upload(wasm, codeMeta, "Upload ERC20 contract");
|
||||
console.info(`Upload succeeded. Receipt: ${JSON.stringify(uploadReceipt)}`);
|
||||
|
||||
for (const initMsg of [initMsgHash, initMsgIsa, initMsgJade]) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user