Skip to content

feat: in-progress state for vault deployment #294

@filo87

Description

@filo87

[Follow-up] Track "Deploy vault" in-progress state

Parent: [Feature] Track progress of Vault deployments (Link/Unlink are implemented; this issue covers the Deploy path only.)

Description

When a deploy vault is initiated from the Hub, we want to show the vault as "deploy in progress" on the destination chain until it is actually deployed and linked (i.e. until the Spoke emits DeployVault).

Current gap: We only know the factory address when the Hub sends the deploy message. The vault address is created later on the destination chain and is not known at the time we see the Hub event. Our data model identifies a vault by its contract address + centrifugeId, so we cannot create a single vault row that goes from "in progress" to "deployed" without knowing the vault address up front.

Chosen approach (Option 1 – predict the vault address): Use CREATE2 semantics to compute the future vault address when we see the Hub UpdateVault event (kind = deploy). Then we can create/update one vault row with "in progress" and later update the same row to "deployed" when the Spoke confirms via DeployVault. This requires having the init bytecode hash (or equivalent) for the vault type per chain—e.g. from a small config in the API (derived once from the protocol build) or hard-coded and updated when the vault bytecode changes.

On-Chain Specifications

1. Hub domain (initiation)

  • Contract: Hub.sol
  • Function: updateVault(PoolId poolId, ShareClassId scId, AssetId assetId, bytes32 vaultOrFactory, VaultUpdateKind kind, uint128 extraGasLimit, address refund)
  • Event: UpdateVault(PoolId indexed poolId, ShareClassId scId, AssetId assetId, bytes32 vaultOrFactory, VaultUpdateKind kind)
  • Order: Initiating event; triggers cross-chain message to the Spoke. For this follow-up, only kind = deploy (deploy new vault via factory) is in scope.

2. Spoke domain (finalization)

  • Contract: VaultRegistry.sol (via message handler from Hub).
  • Event: DeployVault(PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IVaultFactory factory, IVault vault, VaultKind kind)
  • Order: Finalizing event when the cross-chain message is delivered and processed; at this point the vault address is known.

3. CREATE2 address derivation (for in-progress row)

The Spoke creates the vault with CREATE2. For example, in AsyncVaultFactory:

  • Deployer: factory address (from Hub payload / event).
  • Salt: keccak256(abi.encode(poolId, scId, asset)).z
  • Initcode: creation bytecode of the vault (e.g. AsyncVault) + constructor args. The CREATE2 formula uses keccak256(initcode).

So we have: address = CREATE2(deployer, salt, keccak256(initcode)). We have deployer and salt from the Hub event and from AssetId resolution; we need initcode hash from somewhere (see Indexer requirements).

Data Type Notes

  • AssetId (Hub) maps to address asset and uint256 tokenId on the Spoke; used for salt and for matching DeployVault.
  • vaultOrFactory on the Hub is bytes32; for deploy, it is the factory address (encoded). On the Spoke, DeployVault exposes IVaultFactory factory and IVault vault.
  • VaultUpdateKind: only the deploy variant is in scope for this follow-up; Link and Unlink are already handled.

Indexer Requirements (cfg-api-v3)

  • Listen to Hub.UpdateVault and filter for kind = deploy (Deploy vault).
  • Derive destination chain from AssetId (AssetId is uniquely from a specific chain).
  • Obtain initcode hash for the vault type per chain (e.g. AsyncVault) from config or constants—computed once from the protocol repo (e.g. Forge build) and stored in the API, or hard-coded and updated when vault bytecode changes.
  • When a deploy UpdateVault is seen: compute the predicted vault address using CREATE2 (factory, salt = keccak256(abi.encode(poolId, scId, asset)), initcode hash from config); create or update one vault row for that address + centrifugeId with status "deploy in progress".
  • Listen to VaultRegistry.DeployVault on the Spoke; match by poolId, scId, asset/tokenId (and chain). Update the same vault row to "deployed" (and set final vault address if needed for consistency).
  • No protocol change: address prediction is done off-chain using existing CREATE2 semantics and a stored initcode hash.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions