vault.curator

Documentation for eth_defi.vault.curator Python module.

Vault curator identification and metadata.

Vault curators are professional risk managers and strategy operators that brand their vaults by embedding their organisation name in the vault’s token name or display name. Examples include Gauntlet, RE7 Labs, Steakhouse Financial, and MEV Capital.

This module provides:

  • Curator identification — given a vault name, detect which curator manages it using word-boundary regex matching against known curator names loaded from YAML feeder files

  • Protocol-curated detection — some vaults are operated by the protocol itself (Ostium, Gains Network, Hyperliquid HLP, Lighter LLP) rather than a third-party curator; these are identified by address lookups against known system vault address sets

  • Curator metadata loading — load curator metadata from the shared feeder YAML files in eth_defi/data/feeds/curators/

  • R2 metadata export — upload per-curator metadata JSON and an aggregate index to Cloudflare R2 for frontend consumption

Curator YAML files use the shared feeder schema defined in eth_defi.feed.sources. Each file lives under eth_defi/data/feeds/curators/ and follows this format:

feeder-id: gauntlet
name: Gauntlet
role: curator
website: https://www.gauntlet.xyz
curatorwatch: https://curatorwatch.com/curator/gauntlet
twitter: gauntlet_xyz
linkedin: gauntlet-xyz
rss: https://medium.com/feed/gauntlet-networks
short_description: Gauntlet is a DeFi risk manager.
long_description: |
  Gauntlet builds risk management systems for lending markets,
  vaults and other on-chain financial applications.

Canonical feeder aliases

When the same organisation appears as both a curator and a stablecoin issuer or vault protocol, duplicate feed fetching is avoided by using canonical-feeder-id. An alias YAML file contains identity and description metadata, but no feed source fields (twitter, linkedin, rss):

feeder-id: ethena
name: Ethena
role: curator
canonical-feeder-id: usde

The priority order determines which role keeps the feed sources:

  1. Stablecoin — highest priority, always keeps feeds

  2. Protocol — keeps feeds only when no stablecoin overlap exists

  3. Curator — lowest priority, defers to stablecoin or protocol

Metadata inheritance happens at export time: build_curator_metadata_json() resolves the canonical feeder YAML by role priority and inherits website, twitter, linkedin and rss from it.

Post resolution happens at consumption time — consumers use resolve_feeder_id() to map an alias feeder_id to the canonical feeder_id, then look up posts under that canonical feeder’s tracked sources. The canonical_feeder_id field is included in the exported CuratorMetadata JSON so that frontends can resolve without accessing YAML files.

Identification approach

The curator name is matched against the vault display name using word-boundary regular expressions (\b). This avoids false positives such as bare "Gamma" matching "GammaSwap V1" or "August" matching "Prize imToken August Campaign".

For curators whose YAML name field alone is insufficient (e.g. "RE7 Labs" vaults often appear as just "RE7 …"), additional short patterns are registered in CURATOR_NAME_PATTERNS.

Protocol-curated vaults are identified before name matching:

Usage example:

from eth_defi.vault.curator import identify_curator, get_curator_name

slug = identify_curator(
    chain_id=1,
    vault_token_symbol="gtUSDC",
    vault_name="Gauntlet USDC Core",
    vault_address="0x1234…",
    protocol_slug="morpho",
)
assert slug == "gauntlet"
assert get_curator_name(slug) == "Gauntlet"

# Protocol-curated vault — returns the protocol slug itself
slug = identify_curator(
    chain_id=999,
    vault_token_symbol="HLP",
    vault_name="Hyperliquid Liquidity Pool",
    vault_address="0xdfc24b077bc1425ad1dea75bcb6f8158e10df303",
    protocol_slug="hyperliquid",
)
assert slug == "hyperliquid"
assert get_curator_name(slug) == "Hyperliquid"
assert is_protocol_curator(slug)

Module Attributes

LOGO_VARIANTS

Logo variants supported by the shared vault logo folder.

PROTOCOL_CURATED_SLUGS

Protocol slugs where all vaults are protocol-curated.

PROTOCOL_CURATOR_SLUG_ALIASES

Protocol slug aliases that should resolve to the canonical protocol-curator slug emitted by identify_curator().

ALL_PROTOCOL_CURATOR_SLUGS

Complete set of protocol slugs that can appear as curator slugs.

PROTOCOL_CURATOR_NAMES

Human-readable names for protocol-curator slugs.

CURATOR_NAME_PATTERNS

Additional name patterns for curator matching.

SPONSOR_CURATOR_SLUGS

Distributor / sponsor curators whose brand is a white-label wrapper.

PROTOCOL_BOUND_CURATOR_SLUGS

Protocol curator slugs that must never be inferred from a name alone.

PROTOCOL_MANAGER_YAML_FIELDS

Protocol-specific curator metadata fields in curator YAML files.

CURATOR_ADDRESS_OVERRIDES

Exact vault address to curator overrides from Dune dashboards.

Functions

build_curator_index([public_url])

Build the aggregate curator metadata index.

build_curator_metadata_json(yaml_path[, ...])

Build a CuratorMetadata dict from a curator YAML file.

get_curator_available_logos(slug)

Check which logo variants are available for a curator.

get_curator_name(slug)

Look up the human-readable name for a curator slug.

identify_curator(chain_id, ...[, ...])

Identify the curator managing a vault.

is_protocol_curator(slug)

Check whether a curator slug represents a protocol-curated vault.

load_curator_map()

Load all curator metadata from YAML files.

process_and_upload_curator_metadata(...[, ...])

Process and upload a single curator's metadata and logos to R2.

upload_curator_index(bucket_name, ...[, ...])

Build and upload the aggregate curator index to R2.

upload_protocol_curator_metadata(...[, ...])

Upload metadata entries for all protocol-curated slugs to R2.

Classes

CuratorInfo

Metadata for a single curator loaded from YAML.

CuratorLogos

Logo URLs for a vault curator.

CuratorMetadata

Curator metadata as exported to JSON for R2 upload.

VAULTS_DATA_DIR: pathlib.Path = PosixPath('/home/runner/work/web3-ethereum-defi/web3-ethereum-defi/eth_defi/data/vaults')

Base directory for shared vault protocol and curator data.

FORMATTED_LOGOS_DIR: pathlib.Path = PosixPath('/home/runner/work/web3-ethereum-defi/web3-ethereum-defi/eth_defi/data/vaults/formatted_logos')

Directory containing formatted 256x256 PNG logos.

LOGO_VARIANTS: tuple[str, ...] = ('generic', 'dark', 'light')

Logo variants supported by the shared vault logo folder.

CURATORS_DATA_DIR: pathlib.Path = PosixPath('/home/runner/work/web3-ethereum-defi/web3-ethereum-defi/eth_defi/data/feeds/curators')

Path to the curator feeder YAML files.

These files use the shared feeder schema from eth_defi.feed.sources and are also consumed by the feed post collector.

PROTOCOL_CURATED_SLUGS: set[str] = {'3jane', 'atoma', 'd2-finance', 'domination-finance', 'frankencoin', 'frax-finance', 'gains-network', 'ondo', 'ostium', 'usyc', 'wstgbp'}

Protocol slugs where all vaults are protocol-curated.

For these protocols there is no external curator — the protocol itself operates every vault. Values use the canonical curator slug after applying PROTOCOL_CURATOR_SLUG_ALIASES.

PROTOCOL_CURATOR_SLUG_ALIASES: dict[str, str] = {'frax': 'frax-finance', 'gtrade': 'gains-network'}

Protocol slug aliases that should resolve to the canonical protocol-curator slug emitted by identify_curator().

ALL_PROTOCOL_CURATOR_SLUGS: set[str] = {'3jane', 'atoma', 'd2-finance', 'domination-finance', 'frankencoin', 'frax-finance', 'gains-network', 'grvt', 'hyperliquid', 'lighter', 'ondo', 'ostium', 'spiko-curator', 'theo-curator', 'usyc', 'wstgbp'}

Complete set of protocol slugs that can appear as curator slugs.

Includes both blanket protocol-curated slugs and protocols whose system vaults are protocol-curated (Hyperliquid HLP, Lighter LLP, GRVT GLP). Use is_protocol_curator() to check membership.

PROTOCOL_CURATOR_NAMES: dict[str, str] = {'3jane': '3Jane', 'atoma': 'Atoma', 'd2-finance': 'D2 Finance', 'domination-finance': 'Domination Finance', 'frankencoin': 'Frankencoin', 'frax-finance': 'Frax Finance', 'gains-network': 'Gains Network', 'grvt': 'GRVT', 'hyperliquid': 'Hyperliquid', 'lighter': 'Lighter', 'ondo': 'Ondo Finance', 'ostium': 'Ostium', 'spiko-curator': 'Spiko', 'theo-curator': 'Theo', 'usyc': 'Circle USYC', 'wstgbp': 'wstGBP'}

Human-readable names for protocol-curator slugs.

These names are used by get_curator_name() when the curator slug matches a protocol rather than a third-party curator YAML file.

CURATOR_NAME_PATTERNS: dict[str, list[str]] = {'9summits': ['9 Summits'], 'agora-finance': ['Agora'], 'apollo-crypto': ['mAPOLLO'], 'august-digital': ['August Digital', 'August USDC', 'August AUSD'], 'avantgarde-finance': ['Avantgarde'], 'b-cube-ai': ['B-CUBE', 'BCUBE'], 'b-protocol': ['B.Protocol'], 'bizantine': ['Bizantine'], 'clearstar-labs': ['Clearstar'], 'damm-capital': ['DAMM Capital', 'DAMM'], 'edge-and-hedge': ['Edge & Hedge', 'Edge and Hedge'], 'edge-capital': ['mEDGE'], 'fasanara': ['mF-ONE', 'mFONE'], 'felix': ['Felix'], 'fija': ['Fija'], 'fisher8-capital': ['Fisher8'], 'gamma-strategies': ['Gamma Strategies'], 'growi-finance': ['Growi'], 'harvest': ['Harvest'], 'ignight-capital': ['Ignight'], 'insertive-capital': ['Insertive'], 'ipor': ['IPOR', 'Autopilot'], 'k3-capital': ['K3 Capital', 'K3'], 'kappa-lab': ['Fire Liquidity Provider', 'FLP'], 'keyring-network': ['Keyring'], 'llama-risk': ['LlamaRisk', 'Llama Risk'], 'm11-credit': ['M11C'], 'pareto-technologies': ['Pareto'], 'pistachio': ['Pistachio'], 're7-labs': ['RE7'], 'reservoir': ['Reservoir'], 'rogue-traders': ['Rogue Traders'], 'sentora': ['IntoTheBlock'], 'singularity': ['Singularity'], 'stake-dao': ['StakeDAO'], 'steakhouse-financial': ['Steakhouse', 'Smokehouse'], 'strata': ['Strata-Money', 'Strata'], 'systemic-strategies': ['Systemic Strategies'], 'tangent-finance': ['Tangent'], 'tanken': ['Tanken'], 'tau': ['TAU'], 'telosc': ['TelosC'], 'tid-capital': ['TiD Capital', 'TiD'], 'tulipa-capital': ['Tulipa'], 'usdai': ['USD.AI', 'USDai'], 'varlamore-capital': ['Varlamore'], 'woo': ['Woo'], 'xerberus': ['Xerberus'], 'yo': ['yoUSD', 'yoETH', 'yoBTC', 'yoEUR', 'yoGOLD', 'yoUSDT', 'yUSD', 'YO Treasury']}

Additional name patterns for curator matching.

Maps curator slug to a list of extra patterns (beyond the YAML name field) that should also trigger a match. Each pattern is compiled as a word-boundary regex (\\bPATTERN\\b).

Use full compound names to avoid false positives — e.g. "Gamma Strategies" not "Gamma" (which would match "GammaSwap V1").

SPONSOR_CURATOR_SLUGS: set[str] = {'cool-wallet', 'trust-wallet'}

Distributor / sponsor curators whose brand is a white-label wrapper.

These organisations brand a vault family (e.g. “Trust Wallet Morpho Smokehouse USDC”) but the underlying strategy is run by another curator named in the same vault title. Their name patterns are matched at the lowest priority so the real risk curator (Smokehouse/Steakhouse, Gauntlet, …) wins on co-branded vaults, while sponsor-only vaults (e.g. “Trust Wallet AAVE v3 USDT”, where the underlying is an uncurated Aave market) still resolve to the sponsor.

PROTOCOL_BOUND_CURATOR_SLUGS: set[str] = {'frax-finance'}

Protocol curator slugs that must never be inferred from a name alone.

Frax assets are widely used by third-party protocols and curators. A vault name containing FRAX or frxUSD establishes its denomination or strategy, not that Frax operates the vault.

PROTOCOL_MANAGER_YAML_FIELDS: dict[str, str] = {'accountable': 'accountable-company', 'asseto': 'asseto-role', 'euler': 'euler-entity', 'ipor-fusion': 'ipor-atomist', 'lagoon-finance': 'lagoon-curator', 'morpho': 'morpho-curator', 't3tris': 't3tris-curator', 'upshift': 'upshift-strategist'}

Protocol-specific curator metadata fields in curator YAML files.

CURATOR_ADDRESS_OVERRIDES: dict[tuple[int, str], str] = {(1, '0x0324dd195d0cd53f9f07bee6a48ee7a20bad738f'): 'spice-vc', (1, '0x09864f52b035ae22ee739dfa5c748fa080d07bd8'): 'jpmorgan', (1, '0x098697ba3fee4ea76294c5d6a466a4e3b3e95fe6'): 'piku', (1, '0x0f0a9d3f0bc6006143c96e6995572b51413cb3c4'): 'rockawayx', (1, '0x17418038ecf73ba4026c4f428547bf099706f27b'): 'apollo', (1, '0x1b19c19393e2d034d8ff31ff34c81252fcbbee92'): 'ondo', (1, '0x1f41e42d0a9e3c0dd3ba15b527342783b43200a9'): 'blockchain-capital', (1, '0x1fecf3d9d4fee7f2c02917a66028a48c6706c179'): 'wisdomtree', (1, '0x2255718832bc9fd3be1caf75084f4803da14ff01'): 'vaneck', (1, '0x237c717df1b60501f8d029d3fe7385fd090df180'): 'bosera-asset-management-international', (1, '0x252739487c1fa66eaeae7ced41d6358ab2a6bca9'): 'arca', (1, '0x286d9f099587f567ece2b70ebb64b94acd672d76'): 'cncb-capital', (1, '0x2bf11d2e04bc40daa95c24b8b90ec4f5c57dd326'): 'piku', (1, '0x383730608d98b82470d733369a839f6b7e8cfda5'): 'dl-holdings', (1, '0x3be5dd4a34f1c6a112048b9df908ced4372d5049'): 'epoch-rwa', (1, '0x3ddc84940ab509c11b20b76b466933f40b750dc9'): 'franklin-templeton', (1, '0x42975aae7a124257e7fda7f5e8382f51449b784a'): 'blackrock', (1, '0x43415eb6ff9db7e26a15b704e7a3edce97d31c4e'): 'superstate', (1, '0x4867ad1a74b38b0aeff4fff251ed0dadae4f4630'): 'cms-asset-management-hk', (1, '0x48ab4e39ac59f4e88974804b04a991b3a402717f'): 'fidelity', (1, '0x498d9329555471bf6073a5f2d047f746d522a373'): 'cms-asset-management-hk', (1, '0x50293dd8889b931eb3441d2664dce8396640b419'): 'wellington-management', (1, '0x50bdaff4bceb852f006f657f47c68fcc417f7beb'): 'haitong-international-asset-management', (1, '0x51c2d74017390cbbd30550179a16a1c28f7210fc'): 'bny-investments', (1, '0x54a4fc78431f9201824643e99bec891bb7462a1d'): 'fidelity', (1, '0x5e17f6f450dcb0bc69b232ea554e224d7e88067a'): 'protos-asset-management', (1, '0x5f829b1b473cba86838e1b7bb7e144dbde228e21'): 'rockawayx', (1, '0x5fa487bca6158c64046b2813623e20755091da0b'): 'theo-curator', (1, '0x63e19fb814eb737730ac0afbb52b351695b97176'): 'gaoteng-global-asset-management', (1, '0x64c18dcc4ccb3b8d27877a4aebb4c3126cb39cb9'): 'rockawayx', (1, '0x67e1f506b148d0fc95a4e3ffb49068ceb6855c05'): 'rockawayx', (1, '0x682ef9cc637ef56577092b29ae9275a629aae7db'): 'science-inc', (1, '0x6a7c6aa2b8b8a6a891de552bdeffa87c3f53bd46'): 'jpmorgan', (1, '0x6a9da2d710bb9b700acde7cb81f10f1ff8c89041'): 'blackrock', (1, '0x6dc4674573380aff6c3359e19da5cbb6afceb5c3'): 'cms-asset-management-hk', (1, '0x7712c34205737192402172409a8f7ccef8aa2aec'): 'blackrock', (1, '0x78e80da0616887b46a31f39310c2a8b0fbd6a42d'): 'chinaamc-hong-kong', (1, '0x827ce7e8e35861d9ac7fe002755767b695a5594a'): 'piku', (1, '0x85d38585c3ac08268f598282a84b7c0ddfc0d04f'): 'chinaamc-hong-kong', (1, '0x8ac91877b93330f52b2979a31a4879506021475c'): 'rockawayx', (1, '0x8c213ee79581ff4984583c6a801e5263418c4b86'): 'janus-henderson-anemoy', (1, '0x90276e9d4a023b5229e0c2e9d4b2a83fe3a2b48c'): 'franklin-templeton', (1, '0x907c00d587daff16d028fe1e131d6dd3c6bf2f4b'): 'cms-asset-management-hk', (1, '0x953972ea0c1703c58f09fb6fd2477fdcf0fee074'): 'rockawayx', (1, '0x96f6ef951840721adbf46ac996b59e0235cb985c'): 'ondo', (1, '0x99351baed3d8ab544ccb08af96a105910fda71e7'): 'piku', (1, '0xb9c317cae7dd05ecb0c0925020e529934c96f84d'): 'rockawayx', (1, '0xc0c61c29ef8beabc694987c93e5fe4af647042e7'): 'cosimo-digital', (1, '0xc87dbbb8c67e4f19fcd2e297c05937567b2572ce'): 'rockawayx', (1, '0xcd69123b3fbbfc666e1f6a501da27b564c00de54'): 'rockawayx', (1, '0xd65d6e8dbc3cd3d12418199e6f4014db3aaa0097'): 'rockawayx', (1, '0xda2ffa104356688e74d9340519b8c17f00d7752e'): 'hamilton-lane', (1, '0xe0181090c22579b6a217f1522cbf8c9f1f0c1965'): 'rockawayx', (1, '0xe4880249745eac5f1ed9d8f7df844792d560e750'): 'spiko-curator', (1, '0xe99a27169c2aa26a8f2757949d09fa3f9a8f0b3b'): 'rockawayx', (1, '0xf0db6f529581e7f6ebac7a7f6882923c00fc3a66'): 'fidelity', (1, '0xf252c5bd43907a6cab079e990845a37a7c5730d9'): 'partners-group', (1, '0xf3a2a5de306b063d75c86b6352832639b7263a3b'): 'muzinich', (10, '0xa1cdab15bba75a80df4089cafba013e376957cf5'): 'blackrock', (56, '0x1775504c5873e179ea2f8abfce3861ec74d159bc'): 'cms-asset-management-hk', (56, '0x1ec3aa07e3898f1e6d4f23b5dce1bdbecb5c1fe1'): 'chinaamc-hong-kong', (56, '0x50bf2924cee59737ead76e881643ed8569bae6e8'): 'partners-group', (56, '0xb5a30e1fa2cf3c8dea882124b3ab5a47a27c5dd2'): 'rockawayx', (56, '0xfb8cb7630bc3cb34a6a9846ec03de3a32393ee65'): 'muzinich', (137, '0x2893ef551b6dd69f661ac00f11d93e5dc5dc0e99'): 'blackrock', (1329, '0x6137dcfdd3c83fe2922b1cba4105d2e92b327a06'): 'rockawayx', (5000, '0x671642ac281c760e34251d51bc9eef27026f3b7a'): 'mantle-guard', (8453, '0xae4181cfb5aaa08bbe77d269c6b595672b9f9edc'): 'rockawayx', (42161, '0xa6525ae43edcd03dc08e775774dcabd3bb925872'): 'blackrock', (42161, '0xc26af85ede9cc25d449bcebef866bb85afd5d346'): 'wellington-management', (43114, '0x53fc82f14f009009b440a706e31c9021e1196a2f'): 'blackrock', (43114, '0xb2ea3e7b80317c4e20d1927034162176e25834e2'): 'dfzq'}

Exact vault address to curator overrides from Dune dashboards.

Used when the public vault display name does not carry the curator brand, or carries a co-branded protocol/issuer name that would otherwise win fuzzy matching. Keys are (chain_id, lowercase_vault_address).

class CuratorInfo

Bases: TypedDict

Metadata for a single curator loaded from YAML.

Represents the in-memory view of a curator feeder file from eth_defi/data/feeds/curators/.

slug: str

URL-safe slug identifier, matches the YAML filename stem and feeder-id field (e.g. "gauntlet", "re7-labs").

name: str

Human-readable display name (e.g. "Gauntlet", "RE7 Labs").

website: Optional[str]

Company website URL, or None if not configured in YAML.

curatorwatch: Optional[str]

CuratorWatch profile URL, or None if not configured in YAML.

short_description: Optional[str]

One-line description of the curator.

long_description: Optional[str]

Multi-paragraph Markdown description of the curator.

twitter: Optional[str]

Twitter/X handle without @ prefix (e.g. "gauntlet_xyz"), or None if not configured.

linkedin: Optional[str]

LinkedIn company identifier (e.g. "gauntlet-xyz"), or None if not configured.

rss: Optional[str]

RSS or Atom feed URL for the curator’s blog or newsletter, or None if not configured.

protocol_curator: bool

Whether this is a protocol-native curator (the protocol itself acts as curator) rather than a third-party risk manager.

True for protocol-curated vaults (Ostium, Gains Network, HLP, LLP). False for third-party curators (Gauntlet, RE7 Labs, etc.).

canonical_feeder_id: Optional[str]

When set, this curator’s feed sources are provided by another feeder identified by this slug. The canonical feeder may be in a different role (e.g. a stablecoin feeder). Posts for this curator should be looked up under the canonical feeder’s sources. None for curators that have their own feed sources.

protocol_manager_names: dict[str, str | tuple[str, ...]]

Exact protocol manager names keyed by protocol slug.

These values are sourced from protocol-specific YAML fields such as euler-entity, lagoon-curator and upshift-strategist.

__init__(*args, **kwargs)
__new__(**kwargs)
clear()

Remove all items from the dict.

copy()

Return a shallow copy of the dict.

fromkeys(value=None, /)

Create a new dictionary with keys from iterable and values set to value.

get(key, default=None, /)

Return the value for key if key is in the dictionary, else default.

items()

Return a set-like object providing a view on the dict’s items.

keys()

Return a set-like object providing a view on the dict’s keys.

pop(k[, d]) v, remove specified key and return the corresponding value.

If the key is not found, return the default if given; otherwise, raise a KeyError.

popitem()

Remove and return a (key, value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.

setdefault(key, default=None, /)

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

update([E, ]**F) None.  Update D from mapping/iterable E and F.

If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values()

Return an object providing a view on the dict’s values.

class CuratorLogos

Bases: TypedDict

Logo URLs for a vault curator.

Logo URLs point to 256x256 PNG files in R2 storage. None if the logo variant is not available.

generic: Optional[str]

Generic logo variant for neutral display contexts.

dark: Optional[str]

Logo for dark background themes when available.

light: Optional[str]

Logo for light background themes when available.

__init__(*args, **kwargs)
__new__(**kwargs)
clear()

Remove all items from the dict.

copy()

Return a shallow copy of the dict.

fromkeys(value=None, /)

Create a new dictionary with keys from iterable and values set to value.

get(key, default=None, /)

Return the value for key if key is in the dictionary, else default.

items()

Return a set-like object providing a view on the dict’s items.

keys()

Return a set-like object providing a view on the dict’s keys.

pop(k[, d]) v, remove specified key and return the corresponding value.

If the key is not found, return the default if given; otherwise, raise a KeyError.

popitem()

Remove and return a (key, value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.

setdefault(key, default=None, /)

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

update([E, ]**F) None.  Update D from mapping/iterable E and F.

If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values()

Return an object providing a view on the dict’s values.

class CuratorMetadata

Bases: TypedDict

Curator metadata as exported to JSON for R2 upload.

This is the public API shape consumed by the frontend. Twitter and LinkedIn fields are expanded to full URLs rather than bare handles/identifiers.

slug: str

URL-safe slug identifier (e.g. "gauntlet", "ostium").

name: str

Human-readable display name.

website: Optional[str]

Company website URL, or None.

curatorwatch: Optional[str]

CuratorWatch profile URL, or None.

short_description: Optional[str]

One-line description of the curator.

long_description: Optional[str]

Multi-paragraph Markdown description of the curator.

twitter: Optional[str]

Full Twitter/X profile URL (e.g. "https://x.com/gauntlet_xyz"), or None.

linkedin: Optional[str]

Full LinkedIn company URL (e.g. "https://www.linkedin.com/company/gauntlet-xyz"), or None.

rss: Optional[str]

RSS or Atom feed URL, or None.

logos: eth_defi.vault.curator.CuratorLogos

Logo URLs for available 256x256 PNG variants.

protocol_curator: bool

Whether this curator is the protocol itself (not a third party).

True for protocol-curated vaults (e.g. Ostium, Gains Network, HLP, LLP). False for third-party curators (e.g. Gauntlet, RE7 Labs).

canonical_feeder_id: Optional[str]

When this curator is an alias, the slug of the canonical feeder whose posts should be used. None for non-alias curators. Consumers should look up posts under this feeder_id instead.

__init__(*args, **kwargs)
__new__(**kwargs)
clear()

Remove all items from the dict.

copy()

Return a shallow copy of the dict.

fromkeys(value=None, /)

Create a new dictionary with keys from iterable and values set to value.

get(key, default=None, /)

Return the value for key if key is in the dictionary, else default.

items()

Return a set-like object providing a view on the dict’s items.

keys()

Return a set-like object providing a view on the dict’s keys.

pop(k[, d]) v, remove specified key and return the corresponding value.

If the key is not found, return the default if given; otherwise, raise a KeyError.

popitem()

Remove and return a (key, value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.

setdefault(key, default=None, /)

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

update([E, ]**F) None.  Update D from mapping/iterable E and F.

If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values()

Return an object providing a view on the dict’s values.

load_curator_map()

Load all curator metadata from YAML files.

Returns a dict mapping slug to CuratorInfo. Cached in-process after first call (same pattern as eth_defi.stablecoin_metadata.load_all_stablecoin_metadata()).

Returns

Dict keyed by curator slug.

Return type

dict[str, eth_defi.vault.curator.CuratorInfo]

identify_curator(chain_id, vault_token_symbol, vault_name, vault_address, protocol_slug='', manager_name='', declared_curator_slug=None)

Identify the curator managing a vault.

Checks protocol-curated status first (by protocol slug and vault address), then falls back to word-boundary regex matching against the vault display name and the manager name.

Some native marketplace protocols (notably GRVT) brand the curator in a separate manager_name field rather than the vault display name — the vault name there is the strategy name (e.g. "Ethereum Moving Average Long/Short") while the curator identity (e.g. "Gerhard - Bitcoin Strategy") is the manager. Pass manager_name so these curators are detected. Exact protocol manager metadata runs before ordinary vault-name and manager-name fuzzy matching. Protocol-bound curators such as Frax are never inferred from asset names.

Parameters
  • chain_id (int) – Chain ID where the vault is deployed.

  • vault_token_symbol (str) – The vault’s share token symbol (e.g. "gtUSDC").

  • vault_name (str) – The vault’s human-readable display name, which curators typically brand with their organisation name.

  • vault_address (str) – The vault’s on-chain address (hex or synthetic format).

  • protocol_slug (str) – Slugified protocol name from eth_defi.research.vault_metrics.slugify_protocol() (e.g. "morpho", "hyperliquid", "lighter").

  • manager_name (Optional[str]) – Optional name of the vault manager/operator, used by native marketplace protocols (e.g. GRVT) where the curator brand lives in the manager field rather than the vault name. Empty string or None when unknown.

  • declared_curator_slug (Optional[str]) – Optional curator slug exported directly by a reviewed vault adapter. Exact chain/address overrides still take precedence so corrected attribution also applies to stale cached scan metadata.

Returns

Curator slug (e.g. "gauntlet", "ostium", "hyperliquid"), or None if no curator could be identified. For protocol-curated vaults the protocol slug itself is returned. Use is_protocol_curator() to distinguish protocol-curated from third-party curators.

Return type

Optional[str]

is_protocol_curator(slug)

Check whether a curator slug represents a protocol-curated vault.

Protocol-curated means the protocol itself operates the vault rather than a third-party risk manager.

Parameters

slug (str) – Curator slug as returned by identify_curator().

Returns

True if the slug identifies a protocol acting as its own curator.

Return type

bool

get_curator_name(slug)

Look up the human-readable name for a curator slug.

Handles both third-party curators (looked up from YAML) and protocol-curated slugs (looked up from PROTOCOL_CURATOR_NAMES).

Parameters

slug (str) – Curator slug as returned by identify_curator().

Returns

Human-readable curator name, or None if not found.

Return type

Optional[str]

get_curator_available_logos(slug)

Check which logo variants are available for a curator.

Curator and vault protocol logos share eth_defi/data/vaults/formatted_logos/{slug}/.

Parameters

slug (str) – Curator slug, e.g. "gauntlet".

Returns

Dictionary keyed by generic, dark and light.

Return type

dict[str, bool]

build_curator_metadata_json(yaml_path, public_url='')

Build a CuratorMetadata dict from a curator YAML file.

Twitter handles are expanded to full https://x.com/{handle} URLs. LinkedIn company identifiers are expanded to full https://www.linkedin.com/company/{id} URLs.

Parameters
  • yaml_path (pathlib.Path) – Path to a curator YAML file.

  • public_url (str) – Public base URL for constructing logo URLs.

Returns

Metadata dict ready for JSON serialisation.

Return type

eth_defi.vault.curator.CuratorMetadata

process_and_upload_curator_metadata(yaml_path, bucket_name, endpoint_url, access_key_id, secret_access_key, public_url='', key_prefix='')

Process and upload a single curator’s metadata and logos to R2.

Uploads:

  • curator-metadata/{key_prefix}{slug}/metadata.json — JSON metadata

  • curator-metadata/{key_prefix}{slug}/{variant}.png — 256x256 logo

Parameters
  • yaml_path (pathlib.Path) – Path to the curator YAML file.

  • bucket_name (str) – R2 bucket name.

  • endpoint_url (str) – R2 API endpoint URL.

  • access_key_id (str) – R2 access key ID.

  • secret_access_key (str) – R2 secret access key.

  • public_url (str) – Public base URL for constructing logo URLs in metadata.

  • key_prefix (str) – Optional prefix for R2 keys (e.g. "test-" for testing).

Returns

The processed CuratorMetadata.

Return type

eth_defi.vault.curator.CuratorMetadata

upload_protocol_curator_metadata(bucket_name, endpoint_url, access_key_id, secret_access_key, public_url='', key_prefix='')

Upload metadata entries for all protocol-curated slugs to R2.

Ensures that curator-metadata/{slug}/metadata.json exists for every protocol in ALL_PROTOCOL_CURATOR_SLUGS so that frontend slug lookups never 404.

Parameters
  • bucket_name (str) – R2 bucket name.

  • endpoint_url (str) – R2 API endpoint URL.

  • access_key_id (str) – R2 access key ID.

  • secret_access_key (str) – R2 secret access key.

  • public_url (str) – Public base URL for constructing logo URLs in metadata.

  • key_prefix (str) – Optional prefix for R2 keys.

Returns

List of uploaded CuratorMetadata entries.

Return type

list[eth_defi.vault.curator.CuratorMetadata]

build_curator_index(public_url='')

Build the aggregate curator metadata index.

Loads all curator YAML files and appends synthetic entries for protocol-curated slugs. The result is suitable for JSON serialisation and R2 upload as curator-metadata/index.json.

Parameters

public_url (str) – Public base URL for constructing logo URLs.

Returns

List of CuratorMetadata dicts for all known curators.

Return type

list[eth_defi.vault.curator.CuratorMetadata]

upload_curator_index(bucket_name, endpoint_url, access_key_id, secret_access_key, public_url='', key_prefix='')

Build and upload the aggregate curator index to R2.

Uploads to curator-metadata/{key_prefix}index.json.

Parameters
  • bucket_name (str) – R2 bucket name.

  • endpoint_url (str) – R2 API endpoint URL.

  • access_key_id (str) – R2 access key ID.

  • secret_access_key (str) – R2 secret access key.

  • public_url (str) – Public base URL for constructing logo URLs in metadata.

  • key_prefix (str) – Optional prefix for R2 keys.

Returns

The full index list.

Return type

list[eth_defi.vault.curator.CuratorMetadata]