Skip to content

contract invoke: Map keys with Symbol/String type are double-encoded in output #2421

@fnando

Description

@fnando

Description

When invoking a contract that returns a Map<Symbol, V> or Map<String, V>, the keys in the JSON output are incorrectly double-encoded, making them unreadable.

Steps to Reproduce

Given a contract function:

pub fn echo_map(_env: Env, value: Map<Symbol, u32>) -> Map<Symbol, u32> {
    value
}

Invoke it:

stellar contract invoke --id mycontract -- echo_map --value '{"bar":1,"foo":2}'

Actual Output

{"\"bar\"":1,"\"foo\"":2}

The keys contain literal backslash-quote sequences, making the output invalid as idiomatic JSON (the key values have embedded double-quote characters).

Expected Output

{"bar":1,"foo":2}

Root Cause

In Spec::sc_map_to_json (cmd/crates/soroban-spec-tools/src/lib.rs:616):

let key_s = self.xdr_to_json(key, &type_.key_type)?.to_string();

xdr_to_json for a ScVal::Symbol("bar") correctly returns Value::String("bar"). However, calling .to_string() on a serde_json::Value invokes serde_json::to_string(), which JSON-serializes the value — wrapping the string in quotes and escaping them. The resulting string is "\"bar\"" (seven characters, including the surrounding quotes), which is then inserted as the JSON object key.

The fix should extract the raw inner string from Value::String instead of JSON-serializing it, for example by matching on Value::String(s) => s or by using the free-function to_string from soroban-spec-tools (which already handles ScVal::Symbol correctly without the extra encoding).

Affected Types

Any Map<K, V> where K is Symbol, String, or any other type whose xdr_to_json representation is Value::String.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

Status

In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions