Source code for erc7730.model.calldata.v1.instruction

"""
Data model for calldata descriptor instructions.

These model classes represent the exact same data fields that are serialized into TLV structs.
See documentation in https://github.com/LedgerHQ/app-ethereum for specifications of this protocol
"""

from abc import ABC
from functools import cached_property
from typing import Annotated, Literal

from eth_typing import ChainId as EthChainId
from pydantic import Field, computed_field
from pydantic_string_url import HttpUrl

from erc7730.model.calldata.v1.param import (
    CalldataDescriptorParamV1,
)
from erc7730.model.calldata.v1.struct import (
    CalldataDescriptorStructV1,
)
from erc7730.model.types import Address, HexStr, Selector

CalldataDescriptorInstructionHex = Annotated[
    HexStr,
    Field(
        title="Serialized TLV instruction payload",
        description="Serialized, hex encoded TLV payload.",
        min_length=8,
        max_length=32768,
    ),
]

CalldataDescriptorInstructionProtobuf = Annotated[
    HexStr,
    Field(
        title="Serialized production signature payload",
        description="Serialized, hex encoded Protobuf payload used for production signature.",
        min_length=8,
        max_length=32768,
    ),
]


# extra must be ignored because of descriptor computed field
[docs] class CalldataDescriptorInstructionBaseV1(CalldataDescriptorStructV1, ABC, extra="ignore"): """Base class for calldata descriptor instructions."""
[docs] class CalldataDescriptorInstructionTransactionInfoV1(CalldataDescriptorInstructionBaseV1): """Instruction descriptor for the TRANSACTION_INFO struct.""" version: Literal[1] = Field( default=1, title="Struct version", description="Version of the TRANSACTION_INFO struct", ) chain_id: EthChainId = Field( title="Chain ID", description="The contract deployment EIP-155 chain id.", ) address: Address = Field( title="Contract address", description="The contract deployment address.", ) selector: Selector = Field( title="Function selector", description="The 4-bytes function selector this descriptor applies to.", ) hash: str = Field( title="Structs hash", description="Hash of all the FIELD structs", pattern=r"^[a-f0-9]+$", min_length=64, max_length=64, ) operation_type: str = Field( title="Operation type", description="Displayed in review first screens", min_length=1, max_length=32, # TODO to be refined ) creator_name: str | None = Field( default=None, title="Creator name", description="Displayed in review first screens", min_length=1, max_length=32, # TODO to be refined ) creator_legal_name: str | None = Field( default=None, title="Creator legal name", description="Displayed in review first screens", min_length=1, max_length=32, # TODO to be refined ) creator_url: HttpUrl | None = Field( default=None, title="Creator URL", description="Displayed in review first screens", min_length=1, max_length=256, # TODO to be refined ) contract_name: str | None = Field( default=None, title="Contract name", description="Displayed in review first screens", min_length=1, max_length=32, # TODO to be refined ) deploy_date: str | None = Field( default=None, title="Deploy date", description="Displayed in review first screens", ) @computed_field(title="Descriptor", description="Hex encoded TRANSACTION_INFO TLV struct") # type: ignore[misc] @cached_property def descriptor(self) -> CalldataDescriptorInstructionHex: from erc7730.convert.calldata.v1.tlv import ( tlv_transaction_info, ) return tlv_transaction_info(self).hex()
[docs] class CalldataDescriptorInstructionEnumValueV1(CalldataDescriptorInstructionBaseV1): """Instruction descriptor for the ENUM_VALUE struct.""" version: Literal[1] = Field( default=1, title="Struct version", description="Version of the ENUM struct", ) chain_id: EthChainId = Field( title="Chain ID", description="The contract deployment EIP-155 chain id.", ) address: Address = Field( title="Contract address", description="The contract deployment address.", ) selector: Selector = Field( title="Function selector", description="The 4-bytes function selector this descriptor applies to.", ) enum_id: str = Field( title="Source enum identifier", description="Source identifier of the enum (to differentiate multiple enums in one contract)", ) id: int = Field( title="Enum identifier", description="Identifier of the enum (to differentiate multiple enums in one contract)", ge=0, le=255, ) value: int = Field( title="Enum entry value", description="Identifier of this specific entry (ordinal of the entry, type agnostic)", ge=0, le=32, ) name: str = Field( title="Enum entry name", description="Enum display name (ASCII)", min_length=1, max_length=32, # TODO to be refined ) @computed_field(title="Descriptor", description="Hex encoded ENUM TLV struct") # type: ignore[misc] @cached_property def descriptor(self) -> CalldataDescriptorInstructionHex: from erc7730.convert.calldata.v1.tlv import tlv_enum_value return tlv_enum_value(self).hex()
[docs] class CalldataDescriptorInstructionFieldV1(CalldataDescriptorInstructionBaseV1): """Instruction descriptor for the FIELD struct.""" version: Literal[1] = Field( default=1, title="Struct version", description="Version of the FIELD struct", ) name: str = Field( title="Field name", description="Field display name (ASCII)", min_length=1, max_length=32, # TODO to be refined ) param: CalldataDescriptorParamV1 = Field( title="Field parameter", description="Parameter of the field", ) @computed_field(title="Descriptor", description="Hex encoded FIELD TLV struct") # type: ignore[misc] @cached_property def descriptor(self) -> CalldataDescriptorInstructionHex: from erc7730.convert.calldata.v1.tlv import tlv_field return tlv_field(self).hex()