Skip to content

Handle scSpecTypeVal in Spec.nativeToScVal for raw JS types - #1485

Merged
Ryang-21 merged 10 commits into
stellar:mainfrom
Shadow-MMN:fix/spec-nativetoscval-handle-scspectypeval
Jul 14, 2026
Merged

Handle scSpecTypeVal in Spec.nativeToScVal for raw JS types #1485
Ryang-21 merged 10 commits into
stellar:mainfrom
Shadow-MMN:fix/spec-nativetoscval-handle-scspectypeval

Conversation

@Shadow-MMN

@Shadow-MMN Shadow-MMN commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

What

Spec.prototype.nativeToScVal currently throws when the target Soroban type is scSpecTypeVal (value 0) and the input is a raw JavaScript primitive (string, number, or boolean). This makes it impossible to pass contract function arguments typed as Val without manually constructing xdr.ScVal objects.

This PR adds handling for scSpecTypeVal by converting JS primitives to their corresponding xdr.ScVal types:

Conversion table (scSpecTypeVal → ScVal)

JS type ScVal conversion
string scvAddress (try/catch fallback to scvString)
number / bigint smallest fitting type via ScInt (u64 → u128 → u256 → i64 → i128 → i256)
boolean scvBool
undefined / null scvVoid
array scvVec
Map scvMap (sorted)
plain object {} scvMap with string keys (sorted)
Address / Contract scvAddress
Uint8Array / Buffer scvBytes
xdr.ScVal returned as-is
class instance TypeError (prevents private field leaks)

Why

When a smart contract defines a function parameter as Val (i.e., scSpecTypeVal), the type is unconstrained — it accepts any ScVal. The SDK should be able to convert native JS values to the appropriate ScVal without the user having to manually construct XDR objects.

This was originally discovered and monkey-patched in the tansu project (see Consulting-Manao/tansu#174) and @chadoh requested the fix be pushed upstream. (Closes #1480)

Testing

Added 9 unit tests covering string, Stellar address, contract ID, number, bigint, boolean, and funcArgsToScVals integration. All 2,058 existing tests continue to pass.

Files changed

  • src/contract/spec.ts — Added scSpecTypeVal handler in nativeToScVal() with all conversions above; plain-object guard uses Object.prototype.toString.call + prototype check to exclude class instances
  • test/unit/spec/contract_spec.test.ts — Added tests for all conversion paths

Sited from Consulting-Manao/tansu#174
Closes #1480

Copilot AI review requested due to automatic review settings June 17, 2026 17:17
@github-project-automation github-project-automation Bot moved this to Backlog (Not Ready) in DevX Jun 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds support for converting JS “val”-typed inputs (scSpecTypeVal) into appropriate ScVal variants, with tests and updated reference docs.

Changes:

  • Implement scSpecTypeVal handling in Spec.nativeToScVal (string/address, i128, bool).
  • Add unit tests covering nativeToScVal and funcArgsToScVals with val-typed inputs.
  • Replace @ts-ignore with @ts-expect-error and update docs source links.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
test/unit/spec/contract_spec.test.ts Adds tests for scSpecTypeVal conversions and tightens TS suppression directives.
src/contract/spec.ts Implements conversion logic for scSpecTypeVal in nativeToScVal.
docs/reference/contracts-client.md Updates generated “Source” links to match new line numbers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/contract/spec.ts Outdated
Comment thread src/contract/spec.ts Outdated
Comment thread test/unit/spec/contract_spec.test.ts Outdated
Comment thread test/unit/spec/contract_spec.test.ts Outdated
@Shadow-MMN
Shadow-MMN marked this pull request as draft June 17, 2026 17:20

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: deb6c38476

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/contract/spec.ts Outdated
Comment thread src/contract/spec.ts Outdated
@Shadow-MMN
Shadow-MMN marked this pull request as ready for review June 17, 2026 17:32

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5217f20576

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/contract/spec.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8de3fc3edb

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/contract/spec.ts Outdated
Comment thread src/contract/spec.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

Comment thread src/contract/spec.ts Outdated
Comment thread src/contract/spec.ts Outdated
Comment thread src/contract/spec.ts Outdated
Comment thread src/contract/spec.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7f3e9fda73

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/contract/spec.ts Outdated
Comment thread src/contract/spec.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

Comment thread src/contract/spec.ts Outdated
Comment thread src/contract/spec.ts Outdated
Comment thread test/unit/spec/contract_spec.test.ts
Comment thread test/unit/spec/contract_spec.test.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e33b4475c0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/contract/spec.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1120c1a8da

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/contract/spec.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9c0e714406

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/contract/spec.ts Outdated
@Shadow-MMN
Shadow-MMN force-pushed the fix/spec-nativetoscval-handle-scspectypeval branch from 9c0e714 to 599d394 Compare June 18, 2026 10:20

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 599d3947e4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/contract/spec.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 599d3947e4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/contract/spec.ts Outdated
@quietbits
quietbits changed the base branch from master to main June 30, 2026 13:07
@Ryang-21

Copy link
Copy Markdown
Contributor

Hey @Shadow-MMN, thanks for taking this on! I'd like to see changed before merging though:

1. Most of this already exists in the SDK — let's delegate instead of duplicating.

We already have a generic typeless converter: nativeToScVal in src/base/scval.ts. With no options it does basically everything this branch hand-rolls: strings, numbers/bigints via ScInt, booleans, undefined/null → void, arrays, sorted maps with string keys, Address/Contract/Uint8Array/ScVal passthrough, and it rejects class instances. So the whole scSpecTypeVal branch could pretty much just be:

if (value === xdr.ScSpecType.scSpecTypeVal().value) {
  return nativeToScVal(val);
}

The only thing it doesn't handle is Map — I'd add that to the base helper instead, so the two code paths can't drift apart over time.

  1. I'd drop the address-guessing on strings.

It makes the output type depend on the string's content — any strkey that happens to checksum becomes scvAddress, everything else becomes scvString. Address.fromString also accepts B.../L... strkeys, which aren't valid contract inputs. This is why the base helper makes you opt in with {type: 'address'}. If someone wants an address they can just pass an Address object — no ambiguity.

Smaller stuff:

  • val.constructor === Map misses Map subclasses; instanceof Map is safer.
  • The guard change at the bottom of the object case (constructor?.name → Object.prototype.toString.call) doesn't change what throws — both paths still error — but it does route class instances to the vaguer "did not match the provided type" message instead of the more helpful "cannot interpret Foo value as ScVal". If the goal was handling null-prototype objects, the getPrototypeOf check you use in the Val branch is the cleaner fix.

The nice thing is your test suite should carry over basically unchanged after the restructure, and that's the hard part. Happy to take another look once it's updated!

@Ryang-21
Ryang-21 self-requested a review July 14, 2026 19:04
@Shadow-MMN

Copy link
Copy Markdown
Contributor Author

Hey @Shadow-MMN, thanks for taking this on! I'd like to see changed before merging though:

1. Most of this already exists in the SDK — let's delegate instead of duplicating.

We already have a generic typeless converter: nativeToScVal in src/base/scval.ts. With no options it does basically everything this branch hand-rolls: strings, numbers/bigints via ScInt, booleans, undefined/null → void, arrays, sorted maps with string keys, Address/Contract/Uint8Array/ScVal passthrough, and it rejects class instances. So the whole scSpecTypeVal branch could pretty much just be:

if (value === xdr.ScSpecType.scSpecTypeVal().value) {
  return nativeToScVal(val);
}

The only thing it doesn't handle is Map — I'd add that to the base helper instead, so the two code paths can't drift apart over time.

  1. I'd drop the address-guessing on strings.

It makes the output type depend on the string's content — any strkey that happens to checksum becomes scvAddress, everything else becomes scvString. Address.fromString also accepts B.../L... strkeys, which aren't valid contract inputs. This is why the base helper makes you opt in with {type: 'address'}. If someone wants an address they can just pass an Address object — no ambiguity.

Smaller stuff:

  • val.constructor === Map misses Map subclasses; instanceof Map is safer.
  • The guard change at the bottom of the object case (constructor?.name → Object.prototype.toString.call) doesn't change what throws — both paths still error — but it does route class instances to the vaguer "did not match the provided type" message instead of the more helpful "cannot interpret Foo value as ScVal". If the goal was handling null-prototype objects, the getPrototypeOf check you use in the Val branch is the cleaner fix.

The nice thing is your test suite should carry over basically unchanged after the restructure, and that's the hard part. Happy to take another look once it's updated!

Thank you for the detailed review, will be pushing a change to address them.

@Ryang-21
Ryang-21 merged commit 8c6de2e into stellar:main Jul 14, 2026
11 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog (Not Ready) to Done in DevX Jul 14, 2026
Comment thread src/base/scval.ts
// The Soroban runtime expects maps to have their keys in sorted
// order, so let's do that here as part of the conversion to prevent
// confusing error messages on execution.
.sort(([key1], [key2]) => (key1 < key2 ? -1 : key1 > key2 ? 1 : 0))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of hand-rolling the sort, can we leverage scvSortedMap here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Spec.nativeToScVal does not handle scSpecTypeVal for raw JS types

4 participants