Onchain.ERC7730.Binding (onchain v0.7.0)

Copy Markdown View Source

Binding evaluator for ERC-7730 descriptors.

Given a parsed descriptor and a concrete signing request — calldata, an EIP-712 typed message, or an ERC-4337 UserOperation — resolve/3 decides which display format applies and decodes the bound data into a name → value map ready for the display-rule engine.

Binding rules

RequestMatch on
{:calldata, address, chain_id, hex_data}contract deployment {chain_id, address} + 4-byte selector
{:eip712, payload}EIP-712 domain fields + primaryType
{:user_op, address, chain_id, user_op}unwraps callData, then binds as calldata

Proxy detection

Reference implementations (Ledger's python-erc7730, Uniswap's descriptors) bind by matching the transaction's target against the deployments list, and delegate proxy/implementation resolution to an optional addressMatcher URI. Resolving a matcher (or an EIP-1967 implementation slot behind a proxy) requires on-chain reads and is registry/runtime-side — out of scope here. This evaluator binds against the literal deployments list; when a descriptor carries an addressMatcher and no deployment matches, the error reason notes that an unresolved matcher was present.

The resolution result is a map consumed by Onchain.ERC7730.Formatter:

%{
  format: format(),            # the matched display format
  signature: %ABI.FunctionSelector{} | nil,
  message: %{name => value},   # decoded bound data (path "#." root)
  types: %{name => abi_type},  # ABI type per message field
  envelope: %{to: _, value: _, from: _}  # transaction envelope (path "@." root)
}

API Functions

FunctionArityDescriptionParam Kinds
resolve3Resolve which display format applies to a signing request and decode the bound data.descriptor: value, request: value, opts: value

Summary

Functions

Resolve which display format applies to a signing request and decode the bound data.

Types

request()

@type request() ::
  {:calldata, String.t() | binary(), non_neg_integer(), String.t()}
  | {:eip712, map()}
  | {:user_op, String.t() | binary(), non_neg_integer(), map()}

resolution()

@type resolution() :: %{
  format: Onchain.ERC7730.Descriptor.format(),
  signature: ABI.FunctionSelector.t() | nil,
  message: %{optional(String.t()) => term()},
  types: %{optional(String.t()) => term()},
  envelope: map()
}

Functions

resolve(descriptor, request, opts \\ [])

@spec resolve(Onchain.ERC7730.Descriptor.t(), request(), keyword()) ::
  {:ok, resolution()} | {:error, {atom(), term()}}

Resolve which display format applies to a signing request and decode the bound data.

Parameters

  • descriptor - Parsed %Onchain.ERC7730.Descriptor{} (value)
  • request - {:calldata, address, chain_id, hex_data} | {:eip712, payload} | {:user_op, address, chain_id, user_op} (value)

  • opts - Envelope overrides for the @. root: :value (native value), :from (sender) (default: [], value)

Returns

Resolution map (format/signature/message/types/envelope). Errors: :context_mismatch, :no_deployment_match, :no_format_match, :decode_error, :invalid_request, :missing_calldata ({:ok, resolution} | {:error, {tag, reason}})

# descripex:contract
%{
  params: %{
    request: %{
      description: "{:calldata, address, chain_id, hex_data} | {:eip712, payload} | {:user_op, address, chain_id, user_op}",
      kind: :value
    },
    opts: %{
      default: [],
      description: "Envelope overrides for the @. root: :value (native value), :from (sender)",
      kind: :value
    },
    descriptor: %{
      description: "Parsed %Onchain.ERC7730.Descriptor{}",
      kind: :value
    }
  },
  returns: %{
    type: "{:ok, resolution} | {:error, {tag, reason}}",
    description: "Resolution map (format/signature/message/types/envelope). Errors: :context_mismatch, :no_deployment_match, :no_format_match, :decode_error, :invalid_request, :missing_calldata"
  }
}