feat: Extend #[export] with per-function transport/encoding opt-in (scale and ethabi)#1303
Merged
vobradovich merged 17 commits intomasterfrom Apr 17, 2026
Merged
feat: Extend #[export] with per-function transport/encoding opt-in (scale and ethabi)#1303vobradovich merged 17 commits intomasterfrom
vobradovich merged 17 commits intomasterfrom
Conversation
…e-transport methods
Contributor
There was a problem hiding this comment.
Code Review
This pull request introduces explicit transport selection for service exports, allowing methods to be specifically targeted for scale, ethabi, or both. The macro system and InvocationIo trait were refactored to support this, including the ability to define ABI-only metadata without SCALE decoding requirements. Additionally, support for alloy-primitives was added to the reflection and type registry systems. Feedback was provided regarding the use of let_chains in the macro argument parsing logic, suggesting a nested if statement to maintain compatibility with older Rust versions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
m62624
approved these changes
Apr 17, 2026
…syntax Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.
Resolves #1263 .
Summary
Extends
#[export]on service methods with per-transport opt-in flags so a method can be exposed only through the Gear/SCALE dispatch path, only through the Solidity/ethexeABI path, or both:Plain
#[export]remains backward-compatible and implies both transports.Why
Before this change, every
#[export]method was generated into both the SCALE and Solidity ABI dispatch paths unconditionally. That made#[export]too coarse:abi_decode_params/abi_encode_sequence, requiring its types to satisfySolValue.Decode/Encode, requiring its types to satisfyparity_scale_codecbounds — blocking ABI-native primitives likealloy_primitives::Address/B256.Transport selection decouples contract membership from dispatch visibility:
#[export]still controls whether a method is part of the service's contract (IDL,INTERFACE_ID, method metadata), while the new flags control which runtime dispatch paths actually route to it.Core Invariant
#[export]controls contract membership; transport flags control runtime dispatch only.CommandsMeta/QueriesMeta,MethodMetadata, method hashes, andINTERFACE_IDare computed from the full exported method surface regardless of transport visibility.#[annotate(scale)]or#[annotate(ethabi)]so downstream consumers can see the restriction without losing the method itself.try_handlefor SCALE,try_handle_solidity+ServiceSignature::METHODSfor ABI) is filtered by transport.Key Changes
rs/macros/core/src/export/args.rs— parsescale/ethabiflags; reject duplicate flags; rejectpayablewithoutethabi(with spans anchored on the offending token).rs/macros/core/src/shared.rs— propagate transport flags throughInvocationExportandFnBuilder; addhas_scale_transport()/has_ethabi_transport()helpers.rs/src/gstd/mod.rs— refactorInvocationIointo a marker trait (type Params;with noDecodebound); extract SCALE encode/decode helpers to free functions (decode_invocation_params,encode_invocation_payload,encode_invocation_payload_with_id) so ethabi-only params structs don't have to satisfy SCALE codec bounds.rs/src/gstd/macros.rs— extendinvocation_io!with adecode = falsevariant that omits#[derive(Decode)]and#[codec(...)]for ethabi-only params.rs/macros/core/src/service/exposure.rs— filter generated SCALE dispatch arms byhas_scale_transport(); migrate generated encode calls to the newencode_invocation_payloadfree function.rs/macros/core/src/service/ethexe.rs— filter generated Solidity dispatch arms andServiceSignature::METHODSbyhas_ethabi_transport().rs/macros/core/src/service/meta.rs— emit#[annotate(scale)]/#[annotate(ethabi)]for single-transport methods; metadata and interface hashing remain unfiltered.rs/reflect-hash,rs/type-registry) —TypeInfo+ReflectHashforalloy_primitives::Address/B256, mapped to the same logical IDL shapes asH160/H256, so ethabi-only methods can use ABI-native types in IDL/hash generation.Test Plan
insta) cover scale-only, ethabi-only, dual, mixed, and backward-compatible bare#[export].CommandsMeta/QueriesMeta/METHODS/INTERFACE_IDinclude every exported method regardless of transport.#[annotate(scale)]/#[annotate(ethabi)].#[derive(Decode)].ethabi, duplicatescale, andpayablewithoutethabi.alloy_primitives::Address/B256.try_handleon ethabi-only,try_handle_solidityon scale-only) returnsNone.Out of Scope
#[ctor]/program_ctor!) remain dual-transport. Constructor transport selection is a separate design problem.Address/B256are deferred; they reuseH160/H256shapes for now.