EntryPoint IntelligenceERC-4337 on Avalanche C-Chain Data to 2026-10-25

Evidence

Attribution & evidence

Each dimension is its own claim with its own evidence. Knowing one never settles another.

An EntryPoint transaction proves authorisation and execution on this chain very precisely. Identity, intent, off-chain billing and other chains sit outside it. So every attribution is a separate claim, in one dimension, with its own evidence.

Attribution dimensions and their traps

The central rule from the earlier research: each dimension is a separate claim with its own evidence. A strong answer on one does not lift the others. "Unknown" is a valid, honest value.

Dimension What answers it What it does not prove
Operation (requested) Decoded op.callData → target + selector + args, exact ABI re-encode That it happened. A selector can collide (fakeApprove_6350575210(address,address) also fits 0x095ea7b3). A request is not a result.
Outcome (realized) UserOperationEvent.success and the target's own logs (e.g. a Transfer matching the requested amount and recipient) Outer status 1 says nothing about ops. success = true can hide a caught sub-call failure. A matching Transfer is not "economic purpose".
Application Exact address in a project-owned registry/docs (e.g. LI.FI 0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae evidence level: primary source in LI.FI's official deployments; Relay Depository in Relay's chains API) Token names, decompiler names and signature-DB hits are clues. "EtherArcade" from a name() getter does not make a game, a project or an issuer.
Assets Exact token address with an identity source (official USDC/USDt) Asset identity says nothing about who or why. Bridged USDt 0xc7198437…5118 evidence level: primary source is a different asset from native USDt.
Routes Decoded swap/bridge request fields (e.g. LI.FI destination chain IDs 1, 10, 56); source-chain events A requested destination is not an arrival. Arrival needs destination-chain evidence.
Wallet implementation Factory/implementation/module address bound to vendor docs (Kernel factory, Safe + Candide module 0x22939e83…aead evidence level: primary source) The wallet brand is not the app the user is using, and not the user.
Control / signers Signature recovery under the correct, version-specific schema; owner getters at a block Recovered key ≠ a person. A getter at block X ≠ continuous control. Same signer across accounts = one key, not necessarily one human.
Bundlers tx.from Bundler ≠ user ≠ app. A 0x4337… vanity prefix suggests bundler software but doesn't identify the operator.
Beneficiaries handleOps last argument Where compensation went; not the end user, not profit.
Sponsorship Nonzero paymaster in op + topic3; paymaster's own events (mode, token amount) Not "free to user", not "the app paid". Off-chain billing is invisible.
Deployment AccountDeployed A new account isn't a new person (one script can deploy 75). In v0.9, non-empty initCode can be ignored, so count events, not initCode.
Automation Precise repeated patterns + recovered signer + nonce scheme, ideally plus an exact operator/script binding Regular timing, sponsorship or repetition alone don't prove a bot. A burst supports a coordination hypothesis.
Fees Receipt fee per outer (once); actualGasCost per op (separate layer) Fees by target/leg overlap and aren't additive.

The habit to build: for any label, ask "which of these columns does my evidence actually sit in?"


Evidence grades: how a value was obtained

Strongest first. Each fact on an example page carries one.

  • grade: observed read directly from the receipt, logs or transaction
  • grade: decoded decoded from calldata and re-encoded byte-for-byte
  • grade: recomputed independently recomputed (e.g. the userOpHash)
  • grade: recovered recovered cryptographically (signature recovery)
  • grade: contract read read from a contract getter at a stated block
  • grade: registry taken from the address registry at the stated level
  • grade: inferred derived from other facts (e.g. log order); weaker than an observation
  • grade: hint a clue only
  • grade: unknown not established

Evidence levels: how strong an address label is

level meaning example
evidence level: primary source The protocol/vendor itself publishes this exact address (official docs, official GitHub deployment file / constants). URL is in source. A same-address deterministic (CREATE2) deployment listed for other chains qualifies only when the address matches exactly; the builder then also compares runtime code hashes with Ethereum mainnet and records the result in notes. EntryPoints, Safe singletons, Pimlico singleton paymasters
evidence level: self-description What the contract says about itself through a getter at a stated block (name(), eip712Domain(), VERSION()). Contracts can claim any name. Signed result registry eip712Domain().name == "Avax-dle"
evidence level: cluster Shared key / getter / bytecode with other labelled addresses: same recovered signer, same owner(), identical runtime code hash, consistent co-occurrence. Shows "same machinery", not the same operator or a named organization. Safe self-call cluster B and its sole owner key
evidence level: hint Ranking position, deployer lineage, explorer name tags, metadata names. Never used as a heading or as proof. "Unattributed bundler #7 (EOA)"

A name is never a real-world identity. EOAs (bundlers, signers, owners) are keys; we never infer who controls them.

Carry-forward rules, in plain language

  1. Keep every dimension separate: what was requested, what actually happened, which app, which asset, which route, which wallet software, which key, who bundled, who sponsored. A strong answer on one never settles another.
  2. Outer success does not prove inner success; a successful UserOperation can still hide a caught failure in one of its calls.
  3. Count the outer fee exactly once per transaction. The per-operation charge (actualGasCost) is a different layer and is never added to it, and fees are never split across legs and summed.
  4. Sponsored is not free: a paymaster paying the gas says nothing about who paid the paymaster.
  5. A signer is a key. Signature recovery proves control of a key, never a person’s identity.
  6. A third-party label (explorer tag, dashboard, another vendor’s list) is a hint and can never raise an evidence level.
  7. A claim is only as strong as its weakest link: a log that is observed but tied to an operation by log order is “inferred”.
  8. Capability is not usage: a version supporting a feature (EIP-7702, block-number validity) does not mean anyone used it.
  9. “Unknown” is a valid, honest answer. Leave it unknown until the evidence exists.

The ontology

The rules above are also written down as a small formal vocabulary (OWL + SKOS + PROV-O in Turtle) with SHACL shapes that reject data breaking them. Download: epi-ontology.ttl · epi-shapes.ttl.

1. Four ideas

1. Chain artifacts are the skeleton. An OuterTransaction (in a Block) carries one or more Envelopes (a handleOps call; DirectEnvelope when tx.to is the EntryPoint, EmbeddedEnvelope when found inside a wrapper's calldata). An envelope holds UserOperations. A UserOperation has Legs: the calls the account was asked to make. A ContainerLeg (e.g. Safe MultiSend) has sub-legs. The transaction has Logs, each placed in a lifecycle phase (validation, execution, compensation ...). These are facts read or decoded from the chain.

2. Addresses play roles; they are not roles. An address is a ChainAddress: an EOA or a Contract. Some contract kinds follow from protocol semantics (EntryPoint, SmartAccount, Paymaster, Factory, AccountImplementation, Module/Validator, Token, WrapperContract). What an address did in a given transaction is a RoleAssignment: player + role + context. The roles are bundler, beneficiary, entrypoint, sender, factory, paymaster, signer, aggregator, account implementation, validator module, leg target, wrapper and token-payment recipient. The same address can play several roles at once. A bundler is usually also the beneficiary, and in one v0.8 bundle the beneficiary is the paymaster. That is a coincidence of addresses, not an identity. epio:Bundler and epio:Beneficiary are defined classes: "any address that played that role somewhere".

Signers are different: the signer role is played by a SignerKey, never by an address or a person. An EOAKey (secp256k1) controlsAddress exactly one EOA. A PasskeyP256 (WebAuthn) has a public key (x, y) and no address.

3. Every attribution is a claim, in one independent dimension. An epio:Claim has a claimSubject, a dimension, a claimPredicate and claimValue, an evidenceGrade, an evidenceLevel for labels, sourceLocator (URL, file or field), method, qualification (caveats), observedAtBlock and prov:wasDerivedFrom / prov:generatedAtTime. The dimensions (epio:DimensionScheme) are the ones in the research notes: operation, outcome (outer status / UserOp success / leg evidence as three separate sub-dimensions), application, asset, route, wallet implementation, control, bundling, compensation, sponsorship, deployment, automation, fees (receipt fee / actualGasCost as two separate sub-dimensions) and labelling. Knowing one dimension never settles another. The paymaster being Pimlico tells you nothing about who runs the bundler, and "unknown application" does not erase a well-evidenced asset transfer.

4. Evidence has two orthogonal scales.

  • Grade: how a value was obtained (epio:EvidenceGradeScheme, from epi/attribution/claims.py): observed > decoded_canonical > recomputed > recovered > endpoint_getter > registry > inferred > hint > unknown.
  • Level: how strong an address label is (epio:EvidenceLevelScheme, from epi/registry.py): primary_source > self_description > cluster > hint, with epio:rank 1–4 and the transitive epio:strongerThan.

The registry's protocol field becomes one of three distinct relations so that a weak claim can't pass for a strong one:

relation meaning level
epio:publishedBy the organisation itself publishes this exact address primary_source only (enforced)
epio:sharesMachineryWith same owner key / implementation / bytecode as that organisation's contracts: same machinery, not same operator cluster (or weaker)
epio:thirdPartyAttributedTo Arkham, BundleBear, 4337-stats, Dune or another vendor says so always hint (enforced)

Third-party sources (epio:Arkham, epio:Snowtrace, epio:BundleBear, epio:Stats4337, epio:DuneSpellbook, epio:OtherVendorPublication) are typed epio:ThirdPartySource. Any claim prov:wasDerivedFrom one of them must be level hint, so a third party can never raise a level. Each one becomes an epio:ThirdPartyClaim, carrying the explorer URL, the verbatim tag and the fetch date (2026-10-19).

2. Core class diagram

This diagram is wider than the screen: scroll sideways inside its frame.

classDiagram
    direction TB
    class OuterTransaction { txHash; gasUsed }
    class Envelope { handleFunction; canonical }
    class DirectEnvelope
    class EmbeddedEnvelope
    class UserOperation { userOpHash; versionLabel; nonceKey }
    class Leg { legForm; selector; valueWei }
    class Log { logKind; index }
    class ChainAddress { address }
    class EOA
    class Contract
    class EntryPoint
    class SmartAccount
    class Paymaster
    class Factory
    class AccountImplementation
    class SignerKey
    class EOAKey
    class PasskeyP256 { publicKeyX; publicKeyY }
    class Organization
    class Claim { sourceLocator; method; qualification; observedAtBlock }
    class RoleAssignment
    class LabelClaim
    class ThirdPartyClaim
    class FeeObservation { amountWei }
    class ReceiptFee
    class ActualGasCharge
    class Source
    class ThirdPartySource

    OuterTransaction "1" --> "1..*" Envelope : hasEnvelope
    Envelope <|-- DirectEnvelope
    Envelope <|-- EmbeddedEnvelope
    Envelope --> EntryPoint : envelopeEntryPoint
    Envelope "1" --> "1..*" UserOperation : hasUserOperation
    UserOperation "1" --> "*" Leg : hasLeg
    OuterTransaction --> Log : hasLog
    ChainAddress <|-- EOA
    ChainAddress <|-- Contract
    Contract <|-- EntryPoint
    Contract <|-- SmartAccount
    Contract <|-- Paymaster
    Contract <|-- Factory
    Contract <|-- AccountImplementation
    SignerKey <|-- EOAKey
    SignerKey <|-- PasskeyP256
    EOAKey --> EOA : controlsAddress
    Claim <|-- RoleAssignment
    Claim <|-- LabelClaim
    Claim <|-- ThirdPartyClaim
    Claim <|-- FeeObservation
    FeeObservation <|-- ReceiptFee
    FeeObservation <|-- ActualGasCharge
    RoleAssignment --> ChainAddress : player (or SignerKey)
    RoleAssignment --> UserOperation : inContext (or Leg)
    ReceiptFee --> OuterTransaction : feeOf (exactly one)
    ActualGasCharge --> UserOperation : feeOf
    Claim --> Source : prov wasDerivedFrom
    Source <|-- ThirdPartySource
    LabelClaim --> Organization : publishedBy / sharesMachineryWith
    ThirdPartyClaim --> Organization : thirdPartyAttributedTo (hint)

Every Claim also points to a dimension, a grade and (for labels) a level, which are SKOS concepts. They are left out of the diagram for space.

4. What SHACL enforces (epi-shapes.ttl)

rule (research notes / registry contract) shape
Every claim has one subject, one dimension, one grade (from the schemes), provenance ClaimShape, LevelInSchemeShape
A label is never shown without its level RegistryGradeNeedsLevel
primary_source needs an http(s) URL PrimarySourceNeedsURL
Third parties never raise a level ThirdPartyIsHint, ThirdPartyClaimShape
"Published by" only at primary_source PublishedByIsPrimary
A key/EOA claim may not assert a Person KeyIsNotPerson
Passkeys have no address; an EOA key has exactly one PasskeyShape, EOAKeyShape
The signer role is played by a key SignerRoleShape
A role has one type and one context, and a player unless the grade is unknown RoleAssignmentShape
A paymaster role or sponsorship mode does not imply "free to the user" PaymasterNotFree
One receipt fee per outer tx; actualGasCost belongs to an op; a fee is in exactly one layer OuterFeeOnce, ReceiptFeeShape, ActualGasChargeShape, NoSummedFees
Outer status / UserOp success / leg outcome stay on their own artifact OutcomeLayers
Addresses are lowercase 40-hex; EOA and Contract are disjoint; skeleton cardinalities AddressShape, OuterTransactionShape, UserOperationShape, EnvelopeShape, LegShape

Result on real data: registry + 7 showcases = 20,570 triples (with the ontology), 1,497 claims, 0 violations. With --all, every explain record (17 transactions, 1,974 claims) also conforms. tests/test_ontology.py adds 14 deliberately bad fixtures, one per rule. Each one fails with the expected message.

Competency questions, answered over the example data

CQ1: Which vendors' infrastructure touched this UserOperation (tx 0x0c9f5c6d..., v0.6 Pimlico ERC20 paymaster + Safe), through which role, and at what evidence level?

ontology/queries/cq1-vendors-touching-userop.rq - 10 row(s)

role address organization relation level source
account_impl 0x29fcb43b46531bca003ddc8fcb67ffe91900c762 evidence level: primary source Safe publishedBy primary_source https://github.com/safe-global/safe-deployments/blob/main/src/assets/v1.4.1/safe_l2.json
entrypoint 0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789 evidence level: primary source eth-infinitism publishedBy primary_source https://github.com/eth-infinitism/account-abstraction/releases/tag/v0.6.0
module 0xa581c4a4db7175302464ff3c06380bc3270b4037 evidence level: primary source Safe publishedBy primary_source https://github.com/safe-global/safe-modules-deployments/blob/main/src/assets/safe-4337-module/v0.2.0/safe-4337-module.json
paymaster 0x6666666666667849c56f2850848ce1c4da65c68b evidence level: primary source Pimlico publishedBy primary_source https://raw.githubusercontent.com/pimlicolabs/docs/main/docs/pages/references/paymaster/erc20-paymaster/contract-addresses.mdx
target 0x9641d764fc13c8b624c04430c7356c1c7c8102e2 evidence level: primary source Safe publishedBy primary_source https://github.com/safe-global/safe-deployments/blob/main/src/assets/v1.4.1/multi_send_call_only.json
target 0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7 evidence level: primary source Tether publishedBy primary_source https://tether.to/en/supported-protocols/
beneficiary 0x4337001fff419768e088ce247456c1b892888084 evidence level: hint Pimlico thirdPartyAttributedTo hint BundleBear
beneficiary 0x4337001fff419768e088ce247456c1b892888084 evidence level: hint Pimlico thirdPartyAttributedTo hint Arkham Intelligence
bundler 0x4337001fff419768e088ce247456c1b892888084 evidence level: hint Pimlico thirdPartyAttributedTo hint BundleBear
bundler 0x4337001fff419768e088ce247456c1b892888084 evidence level: hint Pimlico thirdPartyAttributedTo hint Arkham Intelligence

ontology/queries/cq4-third-party-only.rq - 7 row(s)

address roles organization thirdPartySources level
0x4337001fff419768e088ce247456c1b892888084 evidence level: hint bundler+beneficiary Pimlico Arkham Intelligence, BundleBear hint
0x4337003fcd2f56de3977ccb806383e9161628d0e evidence level: hint bundler+beneficiary Pimlico Arkham Intelligence hint
0x4337005db25dbad41da5692ba1188751ee5d98b6 evidence level: hint beneficiary+bundler Pimlico Arkham Intelligence hint
0x91e60e0613810449d098b0b5ec8b51a0fe8c8985 evidence level: hint factory Pimlico Arkham Intelligence hint
0xf70da97812cb96acdf810712aa562db8dfa3dbef evidence level: hint bundler Relay.link Arkham Intelligence hint
0x91e60e0613810449d098b0b5ec8b51a0fe8c8985 evidence level: hint factory eth-infinitism Another vendor's publication hint
0x5fa66dfe8a3983e55071e8c4631ab43b5f33a4ab evidence level: hint paymaster thirdweb BundleBear, pimlicolabs/4337-stats hint

CQ9: For the addresses that played each role in the examples, how strong are their labels? (Distinct addresses per role and evidence level; 'none' = unlabelled.)

ontology/queries/cq9-label-levels-by-role.rq - 25 row(s)

role level addresses
account_impl primary_source 2
account_impl cluster 1
account_impl none 2
beneficiary hint 4
beneficiary none 2
beneficiary cluster 1
bundler hint 5
bundler none 1
bundler cluster 1
entrypoint primary_source 4
factory primary_source 1
factory hint 1
module primary_source 2
paymaster primary_source 3
paymaster hint 1
paymaster none 1
sender none 7
sender cluster 1
signer none 7
signer cluster 1
target primary_source 3
target cluster 3
target none 2
token_payment_recipient none 1
wrapper none 1