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
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)

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.

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/.

__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.

__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.

__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.

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]

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

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]

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]

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

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. The vault name is matched first and takes precedence over the manager name.

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 (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 when unknown.

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

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]

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_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]

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]