diff --git a/src/query/compute.ts b/src/query/compute.ts index 54ddbc01..a627bc4e 100644 --- a/src/query/compute.ts +++ b/src/query/compute.ts @@ -4,8 +4,7 @@ // 2. Abstract "address: Uint8Array" in the underlying types as "address: string". // 3. Add Secret Network encryption -import { fromBase64, fromUtf8, toBase64 } from "@cosmjs/encoding"; -import { bech32 } from "bech32"; +import { fromBase64, fromUtf8 } from "@cosmjs/encoding"; import { getMissingCodeHashWarning } from ".."; import { EncryptionUtils, EncryptionUtilsImpl } from "../encryption"; import { Empty } from "../grpc_gateway/google/protobuf/empty.pb"; @@ -19,11 +18,14 @@ import { QueryCodesResponse, QueryContractAddressResponse, QueryContractHistoryRequest, - QueryContractHistoryResponse, QueryContractInfoResponse, QueryContractLabelResponse, QueryContractsByCodeIdResponse, } from "../grpc_gateway/secret/compute/v1beta1/query.pb"; +import { + AbsoluteTxPosition, + ContractCodeHistoryOperationType, +} from "../grpc_gateway/secret/compute/v1beta1/types.pb"; export type QueryContractRequest = { /** The address of the contract */ @@ -45,6 +47,13 @@ export type QueryContractRequest = { query: T; }; +export type ContractCodeHistoryEntry = { + operation: ContractCodeHistoryOperationType; + code_id: string; + updated: AbsoluteTxPosition; + msg: string; +}; + export class ComputeQuerier { private codeHashCache = new Map(); @@ -233,13 +242,38 @@ export class ComputeQuerier { } } - contractHistory( + async contractHistory( req: QueryContractHistoryRequest, headers?: HeadersInit, - ): Promise { - return Query.ContractHistory(req, { + ): Promise<{ entries: ContractCodeHistoryEntry[] }> { + const { entries } = await Query.ContractHistory(req, { headers, pathPrefix: this.url, }); + + let decryptedEntries: ContractCodeHistoryEntry[] = []; + for (const entry of entries ?? []) { + let msg = entry.msg as unknown as string; + try { + const encryptedInput = fromBase64(msg); + const nonce = encryptedInput.slice(0, 32); + const encryptedInitMsg = encryptedInput.slice(64); + + const plaintextInitMsg = await this.encryption!.decrypt( + encryptedInitMsg, + nonce, + ); + msg = fromUtf8(plaintextInitMsg).slice(64); + } catch (err) {} + + decryptedEntries.push({ + operation: entry.operation!, + code_id: entry.code_id!, + updated: entry.updated!, + msg, + }); + } + + return { entries: decryptedEntries }; } } diff --git a/test/test.ts b/test/test.ts index 452eaa34..e21c9905 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1284,6 +1284,8 @@ describe("tx.compute", () => { tx.data[0], ).address; + const initHeight = String(tx.height); + tx = await secretjs.tx.compute.storeCode( { sender: secretjs.address, @@ -1358,13 +1360,6 @@ describe("tx.compute", () => { key: "contract_address", value: contract_address, }, - { - msg: 0, - type: "migrate", - key: "contract_address", - value: contract_address, - }, - { msg: 0, type: "migrate", key: "code_id", value: new_code_id }, { msg: 0, type: "wasm", @@ -1384,6 +1379,31 @@ describe("tx.compute", () => { value: "Nop", }, ]); + + const { entries } = await secretjs.query.compute.contractHistory({ + contract_address, + }); + + expect(entries).toStrictEqual([ + { + code_id: code_id, + msg: '{"name":"Secret SCRT","admin":"secret1ap26qrlp8mcq2pg6r47w43l0y8zkqm8a450s03","symbol":"SSCRT","decimals":6,"initial_balances":[{"address":"secret1ap26qrlp8mcq2pg6r47w43l0y8zkqm8a450s03","amount":"1"}],"prng_seed":"eW8=","config":{"public_total_supply":true,"enable_deposit":true,"enable_redeem":true,"enable_mint":false,"enable_burn":false},"supported_denoms":["uscrt"]}', + operation: "CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT", + updated: { + block_height: initHeight, + tx_index: "0", + }, + }, + { + code_id: new_code_id, + msg: '{"nop":{}}', + operation: "CONTRACT_CODE_HISTORY_OPERATION_TYPE_MIGRATE", + updated: { + block_height: String(tx.height), + tx_index: "0", + }, + }, + ]); }); });