From 6a64d2e6af1bf77f9104672e8fc3983416dce19f Mon Sep 17 00:00:00 2001 From: willclarktech Date: Tue, 13 Oct 2020 11:48:47 +0200 Subject: [PATCH] cosmwasm: Deduplicate launchpad logs module --- packages/cosmwasm/src/cosmwasmclient.spec.ts | 7 +- packages/cosmwasm/src/cosmwasmclient.ts | 6 +- packages/cosmwasm/src/index.ts | 3 - packages/cosmwasm/src/lcdapi/wasm.spec.ts | 32 ++-- packages/cosmwasm/src/logs.spec.ts | 165 ------------------ packages/cosmwasm/src/logs.ts | 86 --------- .../cosmwasm/src/signingcosmwasmclient.ts | 16 +- packages/cosmwasm/types/index.d.ts | 2 - packages/cosmwasm/types/logs.d.ts | 28 --- .../cosmwasm/types/signingcosmwasmclient.d.ts | 12 +- 10 files changed, 36 insertions(+), 321 deletions(-) delete mode 100644 packages/cosmwasm/src/logs.spec.ts delete mode 100644 packages/cosmwasm/src/logs.ts delete mode 100644 packages/cosmwasm/types/logs.d.ts diff --git a/packages/cosmwasm/src/cosmwasmclient.spec.ts b/packages/cosmwasm/src/cosmwasmclient.spec.ts index ea3e4cb7..66b5b8be 100644 --- a/packages/cosmwasm/src/cosmwasmclient.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.spec.ts @@ -4,6 +4,7 @@ import { Bech32, fromHex, fromUtf8, toAscii, toBase64 } from "@cosmjs/encoding"; import { assertIsBroadcastTxSuccess, isWrappedStdTx, + logs, makeSignDoc, makeStdTx, MsgSend, @@ -14,7 +15,6 @@ import { assert, sleep } from "@cosmjs/utils"; import { ReadonlyDate } from "readonly-date"; import { Code, CosmWasmClient, PrivateCosmWasmClient } from "./cosmwasmclient"; -import { findAttribute } from "./logs"; import { SigningCosmWasmClient } from "./signingcosmwasmclient"; import cosmoshub from "./testdata/cosmoshub.json"; import { @@ -244,10 +244,9 @@ describe("CosmWasmClient", () => { const signedTx = makeStdTx(signed, signature); const result = await client.broadcastTx(signedTx); assertIsBroadcastTxSuccess(result); - const { logs, transactionHash } = result; - const amountAttr = findAttribute(logs, "transfer", "amount"); + const amountAttr = logs.findAttribute(result.logs, "transfer", "amount"); expect(amountAttr.value).toEqual("1234567ucosm"); - expect(transactionHash).toMatch(/^[0-9A-F]{64}$/); + expect(result.transactionHash).toMatch(/^[0-9A-F]{64}$/); }); }); diff --git a/packages/cosmwasm/src/cosmwasmclient.ts b/packages/cosmwasm/src/cosmwasmclient.ts index f053f801..b87b29a5 100644 --- a/packages/cosmwasm/src/cosmwasmclient.ts +++ b/packages/cosmwasm/src/cosmwasmclient.ts @@ -7,6 +7,7 @@ import { Coin, IndexedTx, LcdClient, + logs, normalizePubkey, PubKey, setupAuthExtension, @@ -17,7 +18,6 @@ import { import { Uint53 } from "@cosmjs/math"; import { setupWasmExtension, WasmExtension } from "./lcdapi/wasm"; -import { parseLogs } from "./logs"; import { JsonObject } from "./types"; export interface GetSequenceResult { @@ -335,7 +335,7 @@ export class CosmWasmClient { rawLog: result.raw_log || "", } : { - logs: result.logs ? parseLogs(result.logs) : [], + logs: result.logs ? logs.parseLogs(result.logs) : [], rawLog: result.raw_log || "", transactionHash: result.txhash, data: result.data ? fromHex(result.data) : undefined, @@ -470,7 +470,7 @@ export class CosmWasmClient { hash: restItem.txhash, code: restItem.code || 0, rawLog: restItem.raw_log, - logs: parseLogs(restItem.logs || []), + logs: logs.parseLogs(restItem.logs || []), tx: restItem.tx, timestamp: restItem.timestamp, }), diff --git a/packages/cosmwasm/src/index.ts b/packages/cosmwasm/src/index.ts index f7900667..e5eee5a5 100644 --- a/packages/cosmwasm/src/index.ts +++ b/packages/cosmwasm/src/index.ts @@ -1,6 +1,3 @@ -import * as logs from "./logs"; -export { logs }; - export { setupWasmExtension, WasmExtension } from "./lcdapi/wasm"; export { Account, diff --git a/packages/cosmwasm/src/lcdapi/wasm.spec.ts b/packages/cosmwasm/src/lcdapi/wasm.spec.ts index cd34a1a6..c95fa988 100644 --- a/packages/cosmwasm/src/lcdapi/wasm.spec.ts +++ b/packages/cosmwasm/src/lcdapi/wasm.spec.ts @@ -10,6 +10,7 @@ import { coin, coins, LcdClient, + logs, makeSignDoc, makeStdTx, OfflineSigner, @@ -20,7 +21,6 @@ import { } from "@cosmjs/launchpad"; import { assert } from "@cosmjs/utils"; -import { findAttribute, parseLogs } from "../logs"; import { isMsgInstantiateContract, isMsgStoreCode, @@ -142,14 +142,14 @@ describe("WasmExtension", () => { const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic); const result = await uploadContract(wallet, hackatom); assertIsBroadcastTxSuccess(result); - const logs = parseLogs(result.logs); - const codeIdAttr = findAttribute(logs, "message", "code_id"); + const parsedLogs = logs.parseLogs(result.logs); + const codeIdAttr = logs.findAttribute(parsedLogs, "message", "code_id"); hackatomCodeId = Number.parseInt(codeIdAttr.value, 10); const instantiateResult = await instantiateContract(wallet, hackatomCodeId, makeRandomAddress()); assertIsBroadcastTxSuccess(instantiateResult); - const instantiateLogs = parseLogs(instantiateResult.logs); - const contractAddressAttr = findAttribute(instantiateLogs, "message", "contract_address"); + const instantiateLogs = logs.parseLogs(instantiateResult.logs); + const contractAddressAttr = logs.findAttribute(instantiateLogs, "message", "contract_address"); hackatomContractAddress = contractAddressAttr.value; } }); @@ -205,8 +205,8 @@ describe("WasmExtension", () => { const result = await instantiateContract(wallet, hackatomCodeId, beneficiaryAddress, transferAmount); assertIsBroadcastTxSuccess(result); - const logs = parseLogs(result.logs); - const contractAddressAttr = findAttribute(logs, "message", "contract_address"); + const parsedLogs = logs.parseLogs(result.logs); + const contractAddressAttr = logs.findAttribute(parsedLogs, "message", "contract_address"); const myAddress = contractAddressAttr.value; const newContractsByCode = await client.wasm.listContractsByCodeId(hackatomCodeId); @@ -254,8 +254,8 @@ describe("WasmExtension", () => { // create new instance and compare before and after const result = await instantiateContract(wallet, hackatomCodeId, beneficiaryAddress, transferAmount); assertIsBroadcastTxSuccess(result); - const logs = parseLogs(result.logs); - const contractAddressAttr = findAttribute(logs, "message", "contract_address"); + const parsedLogs = logs.parseLogs(result.logs); + const contractAddressAttr = logs.findAttribute(parsedLogs, "message", "contract_address"); const myAddress = contractAddressAttr.value; const history = await client.wasm.getContractCodeHistory(myAddress); @@ -496,8 +496,8 @@ describe("WasmExtension", () => { // console.log("Raw log:", result.raw_log); const result = await uploadContract(wallet, getHackatom()); assertIsBroadcastTxSuccess(result); - const logs = parseLogs(result.logs); - const codeIdAttr = findAttribute(logs, "message", "code_id"); + const parsedLogs = logs.parseLogs(result.logs); + const codeIdAttr = logs.findAttribute(parsedLogs, "message", "code_id"); codeId = Number.parseInt(codeIdAttr.value, 10); expect(codeId).toBeGreaterThanOrEqual(1); expect(codeId).toBeLessThanOrEqual(200); @@ -511,10 +511,10 @@ describe("WasmExtension", () => { const result = await instantiateContract(wallet, codeId, beneficiaryAddress, transferAmount); assertIsBroadcastTxSuccess(result); // console.log("Raw log:", result.raw_log); - const logs = parseLogs(result.logs); - const contractAddressAttr = findAttribute(logs, "message", "contract_address"); + const parsedLogs = logs.parseLogs(result.logs); + const contractAddressAttr = logs.findAttribute(parsedLogs, "message", "contract_address"); contractAddress = contractAddressAttr.value; - const amountAttr = findAttribute(logs, "transfer", "amount"); + const amountAttr = logs.findAttribute(parsedLogs, "transfer", "amount"); expect(amountAttr.value).toEqual("1234ucosm,321ustake"); expect(result.data).toEqual(Bech32.decode(contractAddress).data); @@ -528,8 +528,8 @@ describe("WasmExtension", () => { assert(!result.code); expect(result.data).toEqual("F00BAA"); // console.log("Raw log:", result.logs); - const logs = parseLogs(result.logs); - const wasmEvent = logs.find(() => true)?.events.find((e) => e.type === "wasm"); + const parsedLogs = logs.parseLogs(result.logs); + const wasmEvent = parsedLogs.find(() => true)?.events.find((e) => e.type === "wasm"); assert(wasmEvent, "Event of type wasm expected"); expect(wasmEvent.attributes).toContain({ key: "action", value: "release" }); expect(wasmEvent.attributes).toContain({ diff --git a/packages/cosmwasm/src/logs.spec.ts b/packages/cosmwasm/src/logs.spec.ts deleted file mode 100644 index 37be68e8..00000000 --- a/packages/cosmwasm/src/logs.spec.ts +++ /dev/null @@ -1,165 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -import { parseAttribute, parseEvent, parseLog, parseLogs } from "./logs"; - -describe("logs", () => { - describe("parseAttribute", () => { - it("works", () => { - const attr = parseAttribute({ key: "a", value: "b" }); - expect(attr).toEqual({ key: "a", value: "b" }); - }); - - it("works for empty value", () => { - const attr = parseAttribute({ key: "foobar", value: "" }); - expect(attr).toEqual({ key: "foobar", value: "" }); - }); - - it("normalized unset value to empty string", () => { - const attr = parseAttribute({ key: "amount" }); - expect(attr).toEqual({ key: "amount", value: "" }); - }); - }); - - describe("parseEvent", () => { - it("works", () => { - const original = { - type: "message", - attributes: [ - { - key: "action", - value: "store-code", - }, - { - key: "module", - value: "wasm", - }, - { - key: "action", - value: "store-code", - }, - { - key: "sender", - value: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6", - }, - { - key: "code_id", - value: "1", - }, - ], - } as const; - - const event = parseEvent(original); - expect(event).toEqual(original); - }); - - it("works for transfer event", () => { - const original = { - type: "transfer", - attributes: [ - { - key: "recipient", - value: "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", - }, - { - key: "amount", - }, - ], - } as const; - const expected = { - type: "transfer", - attributes: [ - { - key: "recipient", - value: "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", - }, - { - key: "amount", - value: "", - }, - ], - } as const; - - const event = parseEvent(original); - expect(event).toEqual(expected); - }); - }); - - describe("parseLog", () => { - it("works", () => { - const original = { - msg_index: 0, - log: "", - events: [ - { - type: "message", - attributes: [ - { - key: "action", - value: "store-code", - }, - { - key: "module", - value: "wasm", - }, - { - key: "action", - value: "store-code", - }, - { - key: "sender", - value: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6", - }, - { - key: "code_id", - value: "1", - }, - ], - }, - ], - } as const; - - const log = parseLog(original); - expect(log).toEqual(original); - }); - }); - - describe("parseLogs", () => { - it("works", () => { - const original = [ - { - msg_index: 0, - log: "", - events: [ - { - type: "message", - attributes: [ - { - key: "action", - value: "store-code", - }, - { - key: "module", - value: "wasm", - }, - { - key: "action", - value: "store-code", - }, - { - key: "sender", - value: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6", - }, - { - key: "code_id", - value: "1", - }, - ], - }, - ], - }, - ] as const; - - const logs = parseLogs(original); - expect(logs).toEqual(original); - }); - }); -}); diff --git a/packages/cosmwasm/src/logs.ts b/packages/cosmwasm/src/logs.ts deleted file mode 100644 index bd5798af..00000000 --- a/packages/cosmwasm/src/logs.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -import { isNonNullObject } from "@cosmjs/utils"; - -export interface Attribute { - readonly key: string; - readonly value: string; -} - -export interface Event { - readonly type: string; - readonly attributes: readonly Attribute[]; -} - -export interface Log { - readonly msg_index: number; - readonly log: string; - readonly events: readonly Event[]; -} - -export function parseAttribute(input: unknown): Attribute { - if (!isNonNullObject(input)) throw new Error("Attribute must be a non-null object"); - const { key, value } = input as any; - if (typeof key !== "string" || !key) throw new Error("Attribute's key must be a non-empty string"); - if (typeof value !== "string" && typeof value !== "undefined") { - throw new Error("Attribute's value must be a string or unset"); - } - - return { - key: key, - value: value || "", - }; -} - -export function parseEvent(input: unknown): Event { - if (!isNonNullObject(input)) throw new Error("Event must be a non-null object"); - const { type, attributes } = input as any; - if (typeof type !== "string" || type === "") { - throw new Error(`Event type must be a non-empty string`); - } - if (!Array.isArray(attributes)) throw new Error("Event's attributes must be an array"); - return { - type: type, - attributes: attributes.map(parseAttribute), - }; -} - -export function parseLog(input: unknown): Log { - if (!isNonNullObject(input)) throw new Error("Log must be a non-null object"); - const { msg_index, log, events } = input as any; - if (typeof msg_index !== "number") throw new Error("Log's msg_index must be a number"); - if (typeof log !== "string") throw new Error("Log's log must be a string"); - if (!Array.isArray(events)) throw new Error("Log's events must be an array"); - return { - msg_index: msg_index, - log: log, - events: events.map(parseEvent), - }; -} - -export function parseLogs(input: unknown): readonly Log[] { - if (!Array.isArray(input)) throw new Error("Logs must be an array"); - return input.map(parseLog); -} - -/** - * Searches in logs for the first event of the given event type and in that event - * for the first first attribute with the given attribute key. - * - * Throws if the attribute was not found. - */ -export function findAttribute( - logs: readonly Log[], - eventType: "message" | "transfer", - attrKey: string, -): Attribute { - const firstLogs = logs.find(() => true); - const out = firstLogs?.events - .find((event) => event.type === eventType) - ?.attributes.find((attr) => attr.key === attrKey); - if (!out) { - throw new Error( - `Could not find attribute '${attrKey}' in first event of type '${eventType}' in first log.`, - ); - } - return out; -} diff --git a/packages/cosmwasm/src/signingcosmwasmclient.ts b/packages/cosmwasm/src/signingcosmwasmclient.ts index 834112fc..31a6dd91 100644 --- a/packages/cosmwasm/src/signingcosmwasmclient.ts +++ b/packages/cosmwasm/src/signingcosmwasmclient.ts @@ -11,6 +11,7 @@ import { GasLimits, GasPrice, isBroadcastTxFailure, + logs, makeSignDoc, makeStdTx, Msg, @@ -23,7 +24,6 @@ import pako from "pako"; import { isValidBuilder } from "./builder"; import { Account, CosmWasmClient, GetSequenceResult } from "./cosmwasmclient"; -import { findAttribute, Log } from "./logs"; import { MsgClearAdmin, MsgExecuteContract, @@ -91,7 +91,7 @@ export interface UploadResult { readonly compressedChecksum: string; /** The ID of the code asigned by the chain */ readonly codeId: number; - readonly logs: readonly Log[]; + readonly logs: readonly logs.Log[]; /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ readonly transactionHash: string; } @@ -113,7 +113,7 @@ export interface InstantiateOptions { export interface InstantiateResult { /** The address of the newly instantiated contract */ readonly contractAddress: string; - readonly logs: readonly Log[]; + readonly logs: readonly logs.Log[]; /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ readonly transactionHash: string; } @@ -122,19 +122,19 @@ export interface InstantiateResult { * Result type of updateAdmin and clearAdmin */ export interface ChangeAdminResult { - readonly logs: readonly Log[]; + readonly logs: readonly logs.Log[]; /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ readonly transactionHash: string; } export interface MigrateResult { - readonly logs: readonly Log[]; + readonly logs: readonly logs.Log[]; /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ readonly transactionHash: string; } export interface ExecuteResult { - readonly logs: readonly Log[]; + readonly logs: readonly logs.Log[]; /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ readonly transactionHash: string; } @@ -209,7 +209,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { if (isBroadcastTxFailure(result)) { throw new Error(createBroadcastTxErrorMessage(result)); } - const codeIdAttr = findAttribute(result.logs, "message", "code_id"); + const codeIdAttr = logs.findAttribute(result.logs, "message", "code_id"); return { originalSize: wasmCode.length, originalChecksum: toHex(sha256(wasmCode)), @@ -242,7 +242,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { if (isBroadcastTxFailure(result)) { throw new Error(createBroadcastTxErrorMessage(result)); } - const contractAddressAttr = findAttribute(result.logs, "message", "contract_address"); + const contractAddressAttr = logs.findAttribute(result.logs, "message", "contract_address"); return { contractAddress: contractAddressAttr.value, logs: result.logs, diff --git a/packages/cosmwasm/types/index.d.ts b/packages/cosmwasm/types/index.d.ts index f74c9ba5..e5eee5a5 100644 --- a/packages/cosmwasm/types/index.d.ts +++ b/packages/cosmwasm/types/index.d.ts @@ -1,5 +1,3 @@ -import * as logs from "./logs"; -export { logs }; export { setupWasmExtension, WasmExtension } from "./lcdapi/wasm"; export { Account, diff --git a/packages/cosmwasm/types/logs.d.ts b/packages/cosmwasm/types/logs.d.ts deleted file mode 100644 index 2e1decb3..00000000 --- a/packages/cosmwasm/types/logs.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -export interface Attribute { - readonly key: string; - readonly value: string; -} -export interface Event { - readonly type: string; - readonly attributes: readonly Attribute[]; -} -export interface Log { - readonly msg_index: number; - readonly log: string; - readonly events: readonly Event[]; -} -export declare function parseAttribute(input: unknown): Attribute; -export declare function parseEvent(input: unknown): Event; -export declare function parseLog(input: unknown): Log; -export declare function parseLogs(input: unknown): readonly Log[]; -/** - * Searches in logs for the first event of the given event type and in that event - * for the first first attribute with the given attribute key. - * - * Throws if the attribute was not found. - */ -export declare function findAttribute( - logs: readonly Log[], - eventType: "message" | "transfer", - attrKey: string, -): Attribute; diff --git a/packages/cosmwasm/types/signingcosmwasmclient.d.ts b/packages/cosmwasm/types/signingcosmwasmclient.d.ts index 568c2017..5c2bf6e2 100644 --- a/packages/cosmwasm/types/signingcosmwasmclient.d.ts +++ b/packages/cosmwasm/types/signingcosmwasmclient.d.ts @@ -5,12 +5,12 @@ import { CosmosFeeTable, GasLimits, GasPrice, + logs, Msg, OfflineSigner, StdFee, } from "@cosmjs/launchpad"; import { Account, CosmWasmClient, GetSequenceResult } from "./cosmwasmclient"; -import { Log } from "./logs"; /** * These fees are used by the higher level methods of SigningCosmWasmClient */ @@ -48,7 +48,7 @@ export interface UploadResult { readonly compressedChecksum: string; /** The ID of the code asigned by the chain */ readonly codeId: number; - readonly logs: readonly Log[]; + readonly logs: readonly logs.Log[]; /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ readonly transactionHash: string; } @@ -68,7 +68,7 @@ export interface InstantiateOptions { export interface InstantiateResult { /** The address of the newly instantiated contract */ readonly contractAddress: string; - readonly logs: readonly Log[]; + readonly logs: readonly logs.Log[]; /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ readonly transactionHash: string; } @@ -76,17 +76,17 @@ export interface InstantiateResult { * Result type of updateAdmin and clearAdmin */ export interface ChangeAdminResult { - readonly logs: readonly Log[]; + readonly logs: readonly logs.Log[]; /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ readonly transactionHash: string; } export interface MigrateResult { - readonly logs: readonly Log[]; + readonly logs: readonly logs.Log[]; /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ readonly transactionHash: string; } export interface ExecuteResult { - readonly logs: readonly Log[]; + readonly logs: readonly logs.Log[]; /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ readonly transactionHash: string; }