tokenised_fund.securitize.backfill
Documentation for eth_defi.tokenised_fund.securitize.backfill Python module.
Backfill all reviewed Securitize leads and supported price history.
This migration preserves unrelated vault database rows, reader states and
Parquet histories. It upserts the reviewed products in
SECURITIZE_PRODUCTS and rewrites price history only for products with an
explicit adapter estimate or reviewed on-chain RedStone NAV feed. Products
without an authoritative NAV source are registered as leads but excluded from
the price scan.
Important operational note: RedStone push feeds do not necessarily contain the oldest available Securitize NAV observations.
This script intentionally uses reviewed on-chain RedStone push feeds for
variable-NAV products because archive-state calls to latestRoundData() are
reproducible. They can be re-run months later from any archive node and do not
depend on RedStone’s short-lived HTTP cache. See the RedStone feed catalogue:
https://app.redstone.finance/app/feeds/
However, the push-feed deployment date can be later than the first NAV value RedStone collected off-chain from Securitize. The BCAP integration is the canonical example and should be treated as a warning for future Securitize products:
Product: Blockchain Capital III Digital Liquid Venture Fund (BCAP).
DSToken:
0x1f41e42d0a9e3c0dd3ba15b527342783b43200a9.RedStone feed id:
BCAP_FUNDAMENTAL.On-chain push feed:
0x46f1b5f29a2dc1a730508a1b41a8b5b93e316eb2.Feed contract first has code at Ethereum block
25_493_848(2026-07-09 08:32:11 UTC).latestRoundData()first returns a valid value at block25_494_164(2026-07-09 09:35:35 UTC), value106.63.eth_getLogsfrom deployment onward only returned setup/proxy logs (Upgraded(address),Initialized(uint8)and one admin/setup event) during the 2026-07-17 investigation. There were no Chainlink-styleAnswerUpdatedorNewRoundNAV events to replay.Before block
25_494_164archive calls either see no feed contract code orlatestRoundData()reverts, so this script cannot reconstruct older BCAP NAV from Ethereum chain state alone.
At the time of the 2026-07-17 investigation, RedStone’s public HTTP cache did
contain older BCAP_FUNDAMENTAL observations sourced from
securitize-api and securitize-tsso. Example endpoint:
https://api.redstone.finance/prices?symbol=BCAP_FUNDAMENTAL&provider=redstone
Observed older cache points included:
2026-06-17 12:59 UTC:107.07.2026-06-22 23:59 UTC:107.03.2026-06-29 23:59 UTC:106.97.2026-07-06 23:59 UTC:106.63.
The same HTTP API rejected older requests with
{"error":"Data older than 30 days is not available"}, which is why the
production backfill in this script does not depend on it. This means a newly
registered Securitize feed may have a one-time recoverable pre-push-feed REST
window that will disappear if it is not imported quickly. For BCAP, a pure
PROTOCOLS=securitize scripts/backfill-tokenised-funds.py run starts around 2026-07-09/10
because the script only trusts the archive-readable push feed.
If future operators need maximum history for a new Securitize RedStone feed,
run a separate, explicitly documented one-off importer for the RedStone REST
*_FUNDAMENTAL symbol before the 30-day cache expires, then let this script
take over from the push feed’s first valid block. Do not silently extend this
script to depend on REST history for normal production backfills unless the
retention, failure and provenance semantics are made explicit. The PRs that
introduced the current behaviour are:
https://github.com/tradingstrategy-ai/web3-ethereum-defi/pull/1299 https://github.com/tradingstrategy-ai/web3-ethereum-defi/pull/1306
Run with:
source .local-test.env && PROTOCOLS=securitize poetry run python scripts/backfill-tokenised-funds.py
Environment variables:
DRY_RUNShow the plan without writing data. Default:
false.SECURITIZE_SCAN_PRICESScan DSTokens with a reviewed estimated or external NAV source. Default:
true.SECURITIZE_PRODUCTSOptional comma-separated DSToken addresses to backfill.
SECURITIZE_CLEAN_PRICESRebuild selected cleaned histories after the raw scan. Default:
true.FREQUENCYHistorical sample interval,
1hor1d. Default:1d.START_BLOCK/END_BLOCKOptional inclusive block boundaries for a carefully scoped run.
MAX_WORKERSHistorical multicall worker count. Default:
8.
VAULT_DB_PATH, UNCLEANED_PRICE_DATABASE, CLEANED_PRICE_DATABASE
and READER_STATE_DATABASE
Optional paths for isolated tests or production-data overrides.
The script reads archive-capable RPC URLs from JSON_RPC_<CHAIN_NAME>.
Functions
|
Upsert one chain's DSToken leads and rewrite only priced histories. |
|
Build adapters only for DSTokens with a configured historical NAV. |
|
Create a scanner-compatible detection for a reviewed DSToken. |
|
Create a lead row without discovering the whole chain again. |
|
Create and validate the per-product historical row report. |
|
Find the first block where an address has deployed contract code. |
|
Read the naive UTC timestamp for a product deployment block. |
|
Check whether the scanner can produce price history for a product. |
Iterate every reviewed Securitize product exactly once. |
|
|
Run the targeted Securitize lead and price-history migration. |
|
Parse a conventional boolean environment setting. |
|
Read an optional integer block boundary from the environment. |
|
Read a filesystem override while retaining production defaults. |
|
Load saved price-reader states from a trusted local pickle. |
|
Load an existing metadata database without replacing its entries. |
Resolve the requested historical sampling frequency. |
|
|
Choose the earliest history start block for selected products. |
|
Persist reader state atomically after the scoped history scan. |
- parse_bool_env(name, *, default=False)
Parse a conventional boolean environment setting.
The migration is operated through environment variables so it can run from the same production wrapper as other vault scripts without another command line parser.
- parse_optional_int_env(name)
Read an optional integer block boundary from the environment.
Operators can use this only to narrow a controlled rerun. The normal path discovers the first contract-code block automatically.
- parse_path_env(name, default)
Read a filesystem override while retaining production defaults.
Isolated test runs use this to keep state files out of the normal vault pipeline directory.
- Parameters
name (str) – Environment variable holding a path.
default (pathlib.Path) – Default production path.
- Returns
Expanded configured path.
- Return type
- resolve_frequency()
Resolve the requested historical sampling frequency.
The execution plan and the price scanner use the same validated value so a displayed daily run cannot silently perform hourly work.
- Returns
One-hour or one-day scan interval.
- Raises
ValueError – If the requested interval is unsupported.
- Return type
Literal[‘1h’, ‘1d’]
- iter_products()
Iterate every reviewed Securitize product exactly once.
The registry is keyed for direct chain-and-address lookup, so guard against an accidental duplicate product when future aliases are added.
- Returns
Unique registry products.
- Return type
collections.abc.Iterable[eth_defi.tokenised_fund.securitize.description.SecuritizeProduct]
- has_historical_price(product)
Check whether the scanner can produce price history for a product.
Descriptive source labels are not executable configuration. A product is price-capable only when it has a reviewed static estimate or an actual RedStone feed registry entry.
- Parameters
product (eth_defi.tokenised_fund.securitize.description.SecuritizeProduct) – Reviewed Securitize product.
- Returns
Truewhen the historical reader can calculate NAV and TVL.- Return type
- create_price_row_report(products, scan_result, *, scan_enabled)
Create and validate the per-product historical row report.
Counts come from the scanner’s existing in-memory export pass. The report therefore does not reread the output Parquet file. A completed scan must produce at least one non-null share-price row for every product whose static estimate or RedStone feed is available in the scanned block range.
- Parameters
products (collections.abc.Iterable[eth_defi.tokenised_fund.securitize.description.SecuritizeProduct]) – Reviewed products on one chain.
scan_result (Optional[eth_defi.vault.historical.ParquetScanResult]) – Completed scan result, or
Nonefor a dry run or disabled scan.scan_enabled (bool) – Whether historical scanning was requested.
- Returns
Tabular rows covering priced and metadata-only products.
- Raises
RuntimeError – If an expected priced product emitted no non-null share-price rows.
- Return type
- fetch_contract_deployment_block(web3, address, end_block)
Find the first block where an address has deployed contract code.
The reviewed DSToken registry does not duplicate a manually maintained creation-block list. An archive-node binary search yields the first code block in logarithmic RPC calls and remains correct when a new product is added to the registry.
- Parameters
web3 (web3.main.Web3) – Archive-capable connection for the product chain.
address (eth_typing.evm.HexAddress) – DSToken proxy address.
end_block (int) – Highest block that may be inspected.
- Returns
First block with non-empty runtime code.
- Raises
ValueError – If the address has no contract code at
end_block.- Return type
- fetch_product_first_seen_at(web3, deployment_block)
Read the naive UTC timestamp for a product deployment block.
Shared lead records carry both the discovery block and its timestamp. The timestamp comes from the same archive endpoint used to locate deployment.
- Parameters
web3 (web3.main.Web3) – Archive-capable connection for the product chain.
deployment_block (int) – First block with the product’s runtime code.
- Returns
Naive UTC deployment timestamp.
- Return type
- create_detection(product, deployment_block, first_seen_at)
Create a scanner-compatible detection for a reviewed DSToken.
A migration uses the product registry as its authoritative lead source, rather than reprocessing unrelated discovery events from the chain.
- Parameters
product (eth_defi.tokenised_fund.securitize.description.SecuritizeProduct) – Reviewed Securitize product.
deployment_block (int) – First block containing the DSToken proxy code.
first_seen_at (datetime.datetime) – Deployment timestamp in naive UTC.
- Returns
Detection record accepted by metadata extraction.
- Return type
- create_lead(product, deployment_block, first_seen_at)
Create a lead row without discovering the whole chain again.
The lead carries the same initial position as its synthetic detection so downstream metadata and history readers retain the expected ordering.
- Parameters
product (eth_defi.tokenised_fund.securitize.description.SecuritizeProduct) – Reviewed Securitize product.
deployment_block (int) – First block containing the DSToken proxy code.
first_seen_at (datetime.datetime) – Deployment timestamp in naive UTC.
- Returns
Lead record for the shared vault database.
- Return type
- read_vault_database(path)
Load an existing metadata database without replacing its entries.
A missing path starts an empty database for isolated use. Existing files are read intact and later updated only for selected Securitize rows.
- Parameters
path (pathlib.Path) – Metadata database pickle path.
- Returns
Existing or empty vault database.
- Return type
- read_reader_states(path)
Load saved price-reader states from a trusted local pickle.
Only selected Securitize states are removed before their histories are rewritten; all unrelated states are retained.
- Parameters
path (pathlib.Path) – Reader-state pickle path.
- Returns
Existing states, or an empty mapping when the file is absent.
- Return type
- write_reader_states(path, states)
Persist reader state atomically after the scoped history scan.
Atomic replacement ensures that an interrupted process cannot leave a partially serialised reader-state file.
- Parameters
path (pathlib.Path) – Reader-state pickle path.
states (dict[eth_defi.vault.base.VaultSpec, dict]) – Complete state mapping returned by the historical scanner.
- Returns
None.
- Return type
None
- resolve_price_scan_start_block(deployment_blocks)
Choose the earliest history start block for selected products.
A targeted rewrite must begin at deployment, not at the ordinary scanner’s latest cursor. HyperSync fills missing block timestamps, so a partial local timestamp cache must never truncate the requested history.
- Parameters
deployment_blocks (collections.abc.Iterable[int]) – Deployment blocks for products with a configured price source.
- Returns
Explicit override or the earliest deployment block.
- Return type
- build_priced_vaults(web3, products, token_cache)
Build adapters only for DSTokens with a configured historical NAV.
Unpriced DSTokens must remain leads and metadata rows, but their history cannot be inferred from supply alone and therefore must not rewrite price parquet rows.
- Parameters
web3 (web3.main.Web3) – Connection for one product chain.
products (collections.abc.Iterable[tuple[eth_defi.tokenised_fund.securitize.description.SecuritizeProduct, int]]) – Product and deployment-block pairs with a price estimate.
token_cache (eth_defi.token.TokenDiskCache) – Shared ERC-20 metadata cache.
- Returns
Vault adapters with their individual history start blocks.
- Return type
- backfill_chain(chain_id, products, *, dry_run, scan_prices, clean_prices, frequency, vault_db, vault_db_path, price_database_path, cleaned_price_database_path, reader_state_database_path, token_cache)
Upsert one chain’s DSToken leads and rewrite only priced histories.
Product deployments are derived independently for the selected addresses. The shared metadata database receives only their rows, and the historical scanner receives only priced address filters.
- Parameters
chain_id (int) – EVM chain being migrated.
products (list[eth_defi.tokenised_fund.securitize.description.SecuritizeProduct]) – Reviewed Securitize products on that chain.
dry_run (bool) – Whether writes to state and Parquet files are disabled.
scan_prices (bool) – Whether to rebuild supported price histories.
clean_prices (bool) – Whether to rebuild corresponding cleaned histories.
frequency (Literal['1h', '1d']) – Historical sampling interval.
vault_db (eth_defi.vault.vaultdb.VaultDatabase) – Existing shared metadata database.
vault_db_path (pathlib.Path) – Metadata database destination.
price_database_path (pathlib.Path) – Uncleaned price Parquet destination.
cleaned_price_database_path (pathlib.Path) – Cleaned price Parquet destination.
reader_state_database_path (pathlib.Path) – Shared reader-state pickle destination.
token_cache (eth_defi.token.TokenDiskCache) – Shared ERC-20 metadata cache.
- Returns
Tabular migration summary for the chain.
- Return type
- main()
Run the targeted Securitize lead and price-history migration.
The full registry is grouped by chain so future Securitize deployments can be added without expanding this operational entry point.
- Returns
None.
- Return type
None