From d5e53b4e4ccf8aa90c7e2bb47a3a0e6b86b738ac Mon Sep 17 00:00:00 2001 From: Altynbek Orumbayev Date: Fri, 3 Jan 2025 20:58:07 +0100 Subject: [PATCH] fix: patching algosdkv3 compatibility issues --- package-lock.json | 64 ++++++------------------------------------- package.json | 2 +- src/utils.ts | 69 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 74 insertions(+), 61 deletions(-) diff --git a/package-lock.json b/package-lock.json index 00087f2..a8fd465 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "license": "MIT", "dependencies": { - "algosdk": "^2.9.0", + "algosdk": "^3.0.0", "avm-debug-adapter": "^0.3.0", "lodash": "^4.17.21" }, @@ -4145,14 +4145,6 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, - "node_modules/algo-msgpack-with-bigint": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/algo-msgpack-with-bigint/-/algo-msgpack-with-bigint-2.1.1.tgz", - "integrity": "sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==", - "engines": { - "node": ">= 10" - } - }, "node_modules/algorand-msgpack": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/algorand-msgpack/-/algorand-msgpack-1.1.0.tgz", @@ -4163,12 +4155,12 @@ } }, "node_modules/algosdk": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/algosdk/-/algosdk-2.9.0.tgz", - "integrity": "sha512-o0n0nLMbTX6SFQdMUk2/2sy50jmEmZk5OTPYSh2aAeP8DUPxrhjMPfwGsYNvaO+qk75MixC2eWpfA9vygCQ/Mg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/algosdk/-/algosdk-3.0.0.tgz", + "integrity": "sha512-PIKZ/YvbBpCudduug4KSH1CY/pTotI7/ccbUIbXKtcI9Onevl+57E+K5X4ow4gsCdysZ8zVvSLdxuCcXvsmPOw==", + "license": "MIT", "dependencies": { - "algo-msgpack-with-bigint": "^2.1.1", - "buffer": "^6.0.3", + "algorand-msgpack": "^1.1.0", "hi-base32": "^0.5.1", "js-sha256": "^0.9.0", "js-sha3": "^0.8.0", @@ -4181,29 +4173,6 @@ "node": ">=18.0.0" } }, - "node_modules/algosdk/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -4607,25 +4576,6 @@ "node": ">=18.0.0" } }, - "node_modules/avm-debug-adapter/node_modules/algosdk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/algosdk/-/algosdk-3.0.0.tgz", - "integrity": "sha512-PIKZ/YvbBpCudduug4KSH1CY/pTotI7/ccbUIbXKtcI9Onevl+57E+K5X4ow4gsCdysZ8zVvSLdxuCcXvsmPOw==", - "license": "MIT", - "dependencies": { - "algorand-msgpack": "^1.1.0", - "hi-base32": "^0.5.1", - "js-sha256": "^0.9.0", - "js-sha3": "^0.8.0", - "js-sha512": "^0.8.0", - "json-bigint": "^1.0.0", - "tweetnacl": "^1.0.3", - "vlq": "^2.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/avvio": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.3.0.tgz", @@ -4707,6 +4657,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, "funding": [ { "type": "github", @@ -9031,6 +8982,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, "funding": [ { "type": "github", diff --git a/package.json b/package.json index 00e9599..442efad 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "package": "vsce package" }, "dependencies": { - "algosdk": "^2.9.0", + "algosdk": "^3.0.0", "avm-debug-adapter": "^0.3.0", "lodash": "^4.17.21" }, diff --git a/src/utils.ts b/src/utils.ts index f59b2a0..720b47b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,13 +5,74 @@ import * as vscode from 'vscode' import { MAX_FILES_TO_SHOW, NO_WORKSPACE_ERROR_MESSAGE } from './constants' import { workspaceFileAccessor } from './fileAccessor' +// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars +function parseAlgosdkV2SimulateResponse(obj: any): any { + if (obj === null || typeof obj !== 'object') return obj + + const addressFields = new Set(['snd', 'close', 'aclose', 'rekey', 'rcv', 'arcv', 'fadd', 'asnd']) + const toUintFields = new Set(['gh', 'apaa']) + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const processValue = (key: string, value: any): any => { + if (typeof value === 'string') { + if (addressFields.has(key)) { + try { + return algosdk.encodeAddress(algosdk.base64ToBytes(value)) + } catch { + return value + } + } + if (toUintFields.has(key)) { + return algosdk.base64ToBytes(value) + } + } else if (Array.isArray(value)) { + if (toUintFields.has(key)) { + return value.map((item) => (typeof item === 'string' ? algosdk.base64ToBytes(item) : item)) + } + return value.map((item) => parseAlgosdkV2SimulateResponse(item)) + } else if (typeof value === 'object' && value !== null) { + return parseAlgosdkV2SimulateResponse(value) + } + return value + } + + return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, processValue(key, value)])) +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function objectToMapRecursive(obj: any): any { + if (obj === null || typeof obj !== 'object' || obj instanceof Uint8Array) { + return obj + } + + if (Array.isArray(obj)) { + return obj.map(objectToMapRecursive) + } + + return new Map(Object.entries(obj).map(([key, value]) => [key, objectToMapRecursive(value)])) +} + +function tryParseAlgosdkV2SimulateResponse(rawSimulateTrace: object): algosdk.modelsv2.SimulateResponse { + const algosdkV2Response = parseAlgosdkV2SimulateResponse(rawSimulateTrace) + + if (algosdkV2Response.version !== 2) { + throw new Error(`Unsupported simulate response version: ${algosdkV2Response.version}`) + } + + return algosdk.modelsv2.SimulateResponse.fromEncodingData(objectToMapRecursive(algosdkV2Response)) +} + export async function getSimulateTrace(filePath: string): Promise { const traceFileContent = await readFileAsJson>(filePath) if (!traceFileContent) { vscode.window.showErrorMessage(`Could not open the simulate trace file at path "${filePath}".`) return null } - return algosdk.modelsv2.SimulateResponse.from_obj_for_encoding(traceFileContent) + try { + return algosdk.decodeJSON(JSON.stringify(traceFileContent), algosdk.modelsv2.SimulateResponse) + } catch (e) { + return tryParseAlgosdkV2SimulateResponse(traceFileContent) + } } export function getUniqueHashes(simulateTrace: algosdk.modelsv2.SimulateResponse): string[] { @@ -52,12 +113,12 @@ export function getSourceMapQuickPickItems( const { txn, lsig } = txnResult.txn if (hash === bytesToBase64(approvalProgramHash) || hash === bytesToBase64(clearStateProgramHash)) { - const title = txn.apid - ? `Select source maps for Application with ID: ${txn.apid}, hash: ${hash}` + const title = txn.applicationCall?.appIndex + ? `Select source maps for Application with ID: ${txn.applicationCall.appIndex}, hash: ${hash}` : `Select source map for Application with hash: ${hash}` identifiers[hash] = { hash, title } } else if (hash === bytesToBase64(logicSigHash)) { - let lsigBytes: Uint8Array | undefined = lsig?.l + let lsigBytes: Uint8Array | undefined = lsig?.logic if (typeof lsigBytes === 'string') { lsigBytes = new Uint8Array(Buffer.from(lsigBytes, 'base64')) }