feat: decode contract method signature and args in /construction/parse - #165
Merged
potterbm-cb merged 2 commits intoAug 6, 2026
Merged
Conversation
/construction/parse previously omitted method_signature and method_args for contract-call transactions, so consumers had to fall back to caller-supplied (self-declared) values from the unsigned transaction when verifying transaction intent. This let a payload whose calldata targets one address declare a different intended address and still pass validation. This change decodes the method signature and arguments directly from the transaction calldata for methods on a configurable allowlist (RosettaCfg.SupportedContractMethods), populating them in the parse response metadata. Because a 4-byte selector is a one-way hash of the signature, decoding is only possible against known signatures; selectors that do not match the allowlist are left undecoded (no fields emitted) so consumers fail closed instead of trusting unverified data. The decoder is the exact inverse of ConstructContractCallDataGeneric, so a decoded (method_signature, method_args) pair round-trips back to identical calldata. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
✅ Heimdall Review Status
|
Address two verification-safety gaps in contract-call parsing: 1. parseSigArgTypes now rejects tuple/struct signatures (nested parens) with an explicit error instead of silently returning empty arg types, which previously produced misleading empty method_args. Adds ValidateSupportedContractMethods for loud startup validation of the configured allowlist (well-formedness + valid ABI arg types). 2. /construction/parse now fails closed on a matched-but-undecodable signature: it logs and omits method_signature/method_args instead of returning a 500 for otherwise-valid transactions. Adds tests for tuple rejection, the startup validator, and the request-time fail-closed path. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
potterbm-cb
approved these changes
Aug 6, 2026
Contributor
|
For posterity: looks like the github actions are broken at the moment. Andrew ran the checks locally and they passed so I'm merging this without CI running in GHA |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
/construction/parseomittedmethod_signatureandmethod_argsfor contract-call transactions (there was even a//TODO: add logic for contract call parsing). Consumers that need to verify a transaction's intent — e.g. confirming adelegate(address)call targets the address the customer intended — had nothing decoded from the calldata to check against, so they fell back to the caller-supplied (self-declared) values.That's a verification gap: a payload whose calldata targets address X could declare intended address Y and still pass validation, because nothing independently re-derived the destination from the signed bytes.
Solution
Decode the method signature and arguments directly from the transaction calldata and surface them in the parse response metadata, so they become a verified source of truth rather than an echo of the declaration.
RosettaConfig.SupportedContractMethods []stringlets each chain declare the method signatures (e.g."delegate(address)") it wants decoded — mirroring the existingTokenWhiteListpattern.ParseContractCallData) invertsConstructContractCallDataGeneric, emitting args in the same string form the encoder accepts, so a decoded(method_signature, method_args)pair round-trips back to identical calldata (verified across address / uint / int / bool / bytes / bytesN / array types).Behavior: fail-open, never blocks a parse
/construction/parsenever fails or blocks a request because of contract-call decoding:method_signature/method_argsare simply omitted (omitempty). For any unmatched call the endpoint behaves byte-for-byte as it did before this PR.Safety around misconfiguration
ValidateSupportedContractMethodslets a chain validate its configured allowlist at boot (well-formedness + valid, decodable ABI arg types) so misconfiguration fails loudly rather than at request time.Scope
This PR only exposes the capability in the SDK. It does not turn decoding on for any chain: the
SupportedContractMethodsallowlist is populated per chain in the chain-specific implementation repos (e.g.rosetta-zksync), which will also opt in and callValidateSupportedContractMethodsat startup. With no list configured, behavior is unchanged.Tests
Unit tests for
MatchMethodSignature,ParseContractCallData(round-trip), tuple rejection, andValidateSupportedContractMethods, plus/construction/parsetests covering a supported method decoding from calldata, an unsupported method emitting no method fields, and the request-time fail-open (matched-but-undecodable) path.go build ./...,go vet, and the construction suite pass.