From b373e8a10a10cedcbaabfe00f6e0734c1d4d194b Mon Sep 17 00:00:00 2001 From: Iveta Date: Thu, 29 Feb 2024 09:04:01 -0500 Subject: [PATCH] Improve Soroban XDR rendering (#746) --- src/helpers/extrapolateFromXdr.js | 32 +++++++++---- src/helpers/sorobanXdrUtils.ts | 79 +++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 src/helpers/sorobanXdrUtils.ts diff --git a/src/helpers/extrapolateFromXdr.js b/src/helpers/extrapolateFromXdr.js index 5b3e31af..c937eeb5 100644 --- a/src/helpers/extrapolateFromXdr.js +++ b/src/helpers/extrapolateFromXdr.js @@ -9,24 +9,25 @@ // - string: string values that appear as just plain text // - object: typed values always with a type and value `{type: 'code', value: 'Foo();'}` -import * as StellarSdk from "stellar-sdk"; +import { + xdr, + StrKey, + Keypair, + Operation, + scValToNative, + nativeToScVal, +} from "stellar-sdk"; import isArray from "lodash/isArray"; import isString from "lodash/isString"; import functionsIn from "lodash/functionsIn"; import includes from "lodash/includes"; import without from "lodash/without"; +import { scValByType } from "helpers/sorobanXdrUtils"; export default function extrapolateFromXdr(input, type) { // TODO: Check to see if type exists // TODO: input validation - let xdr, StrKey, Keypair, Operation; - - xdr = StellarSdk.xdr; - StrKey = StellarSdk.StrKey; - Keypair = StellarSdk.Keypair; - Operation = StellarSdk.Operation; - function buildTreeFromObject(object, anchor, name) { anchor.type = name; @@ -59,7 +60,8 @@ export default function extrapolateFromXdr(input, type) { if (isString(object.arm())) { anchor.nodes = [{}]; buildTreeFromObject( - object[object.arm()](), + // Soroban or Classic + scValByType(object) ?? object[object.arm()](), anchor.nodes[anchor.nodes.length - 1], object.arm(), ); @@ -181,6 +183,18 @@ export default function extrapolateFromXdr(input, type) { return object.toString(); } + if (name === "contractId") { + return StrKey.encodeContract(object); + } + + if (name === "functionName" || name === "sym") { + return object.toString(); + } + + if (name === "durability") { + return JSON.stringify(object); + } + if (object && object._isBuffer) { return { type: "code", diff --git a/src/helpers/sorobanXdrUtils.ts b/src/helpers/sorobanXdrUtils.ts new file mode 100644 index 00000000..a0b25dff --- /dev/null +++ b/src/helpers/sorobanXdrUtils.ts @@ -0,0 +1,79 @@ +import { StrKey, scValToNative, xdr } from "stellar-sdk"; + +export const scValByType = (scVal: xdr.ScVal) => { + switch (scVal.switch()) { + case xdr.ScValType.scvAddress(): { + const address = scVal.address(); + const addressType = address.switch(); + if (addressType.name === "scAddressTypeAccount") { + return StrKey.encodeEd25519PublicKey(address.accountId().ed25519()); + } + return StrKey.encodeContract(address.contractId()); + } + + case xdr.ScValType.scvBool(): { + return scVal.b(); + } + + case xdr.ScValType.scvBytes(): { + return JSON.stringify(scVal.bytes().toJSON().data); + } + + case xdr.ScValType.scvContractInstance(): { + const instance = scVal.instance(); + return instance.executable().wasmHash()?.toString("base64"); + } + + case xdr.ScValType.scvError(): { + const error = scVal.error(); + return error.value(); + } + + case xdr.ScValType.scvTimepoint(): + case xdr.ScValType.scvDuration(): + case xdr.ScValType.scvI128(): + case xdr.ScValType.scvI256(): + case xdr.ScValType.scvI32(): + case xdr.ScValType.scvI64(): + case xdr.ScValType.scvU128(): + case xdr.ScValType.scvU256(): + case xdr.ScValType.scvU32(): + case xdr.ScValType.scvU64(): { + return scValToNative(scVal).toString(); + } + + case xdr.ScValType.scvLedgerKeyNonce(): + case xdr.ScValType.scvLedgerKeyContractInstance(): { + if (scVal.switch().name === "scvLedgerKeyNonce") { + const val = scVal.nonceKey().nonce(); + return val.toString(); + } + return scVal.value(); + } + + case xdr.ScValType.scvVec(): + case xdr.ScValType.scvMap(): { + return JSON.stringify( + scValToNative(scVal), + (_, val) => (typeof val === "bigint" ? val.toString() : val), + 2, + ); + } + + case xdr.ScValType.scvString(): + case xdr.ScValType.scvSymbol(): { + const native = scValToNative(scVal); + if (native.constructor === "Uint8Array") { + return native.toString(); + } + return native; + } + + case xdr.ScValType.scvVoid(): { + return null; + } + + default: + return null; + } +};