feat: vault factory POC — single-tenant vc-vault + vc-vault-factory#52
feat: vault factory POC — single-tenant vc-vault + vc-vault-factory#52aguilar1x wants to merge 11 commits into
Conversation
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (23)
📝 WalkthroughWalkthroughThis PR introduces a new vault factory contract for deterministic, single-tenant vault deployment and refactors the existing vc-vault contract from a multi-owner/multi-vault model to a single-vault-per-instance architecture. Vault ownership and operations are now fixed at contract initialization; issuance, revocation, and issuer management no longer require per-call owner parameters. Sponsored vaults and linked VCs have been removed. ChangesNew Vault Factory
VC Vault Single-Instance Refactoring
🎯 4 (Complex) | ⏱️ ~75 minutes Possibly Related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
contracts/vc-vault/src/storage/issuer.rs (1)
198-206: 💤 Low valueConsider adding a limit check for denied issuers.
append_denied_issuer_to_indexlacks theMAX_ISSUERS_LISTcheck thatappend_issuer_to_indexhas at line 84. While the denied list is typically smaller, this allows unbounded storage growth if many issuers are denied over time.Suggested fix
pub fn append_denied_issuer_to_index(e: &Env, issuer: &Address) { if denied_issuer_index_contains(e, issuer) { return; } let count = read_denied_issuer_count(e); + if count >= MAX_ISSUERS_LIST { + panic_with_error!(e, ContractError::IssuerListTooLong); + } write_denied_issuer_at(e, count, issuer); write_denied_issuer_position(e, issuer, count); write_denied_issuer_count(e, count + 1); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@contracts/vc-vault/src/storage/issuer.rs` around lines 198 - 206, append_denied_issuer_to_index allows unbounded growth; add the same MAX_ISSUERS_LIST check used by append_issuer_to_index: read the current count with read_denied_issuer_count(e) and if count >= MAX_ISSUERS_LIST, bail out (return or revert as the contract pattern requires) before writing; keep the existing denied_issuer_index_contains check and only perform write_denied_issuer_at, write_denied_issuer_position, and write_denied_issuer_count when the count is below MAX_ISSUERS_LIST.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@contracts/vc-vault-factory/src/test.rs`:
- Around line 163-180: The test function
test_deploy_and_deploy_sponsored_same_owner_same_salt_same_address is
inconsistent with its assertions: it declares the intent "same owner + same salt
+ same address" but creates owner2 and asserts the two derived addresses differ;
either restore the intended same-owner scenario by using the original owner for
the deploy_sponsored call (replace owner2 with owner and change addr_sponsored =
client.deploy_sponsored(&deployer, &owner, &did_uri, &salt) and
assert_eq!(addr_normal, addr_sponsored)), or rename the test and its comment to
reflect "different owner -> different address" and keep owner2 and assert_ne;
update the test name and any inline comment accordingly and ensure the
assertions match client.deploy and client.deploy_sponsored behavior.
---
Nitpick comments:
In `@contracts/vc-vault/src/storage/issuer.rs`:
- Around line 198-206: append_denied_issuer_to_index allows unbounded growth;
add the same MAX_ISSUERS_LIST check used by append_issuer_to_index: read the
current count with read_denied_issuer_count(e) and if count >= MAX_ISSUERS_LIST,
bail out (return or revert as the contract pattern requires) before writing;
keep the existing denied_issuer_index_contains check and only perform
write_denied_issuer_at, write_denied_issuer_position, and
write_denied_issuer_count when the count is below MAX_ISSUERS_LIST.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 838de906-b5f4-4047-ae12-335df3aaba17
📒 Files selected for processing (22)
Cargo.tomlcontracts/vc-vault-factory/Cargo.tomlcontracts/vc-vault-factory/src/contract.rscontracts/vc-vault-factory/src/events.rscontracts/vc-vault-factory/src/lib.rscontracts/vc-vault-factory/src/storage.rscontracts/vc-vault-factory/src/test.rscontracts/vc-vault/src/contract.rscontracts/vc-vault/src/error.rscontracts/vc-vault/src/events.rscontracts/vc-vault/src/interface.rscontracts/vc-vault/src/storage/credential.rscontracts/vc-vault/src/storage/issuer.rscontracts/vc-vault/src/storage/mod.rscontracts/vc-vault/src/storage/sponsor.rscontracts/vc-vault/src/storage/ttl.rscontracts/vc-vault/src/storage/vault.rscontracts/vc-vault/src/test.rscontracts/vc-vault/src/validator.rscontracts/vc-vault/src/vault/credential.rscontracts/vc-vault/src/vault/issuer.rscontracts/vc-vault/src/vault/mod.rs
💤 Files with no reviewable changes (2)
- contracts/vc-vault/src/storage/sponsor.rs
- contracts/vc-vault/src/error.rs
Each vault is now its own contract, so no key needs to be scoped by owner address. VaultOwner is written once at construction and read from instance storage. sponsor.rs removed — sponsored vault deferred.
All require_* helpers now read vault state from instance storage instead of taking owner: &Address. require_vault_admin reads VaultAdmin directly; require_vault_active reads VaultRevoked.
store_vc, store_vc_with_fee, revoke_vc, authorize_issuer, authorize_issuers, revoke_issuer and is_authorized no longer take owner: &Address. push_vc removed — cross-contract push is deferred.
… entrypoints __constructor(vault_owner, contract_admin, did_uri) replaces create_vault. All public functions drop owner: Address. Removed: create_vault, create_sponsored_vault, sponsor management, push, issue_linked, get_vc_parent. Dead error codes VaultAlreadyExists and NotAuthorizedSponsor removed.
Constructor registers via env.register(VcVaultContract, (owner, admin, did_uri)). All client calls drop the owner first arg. Removed tests for create_vault, sponsored vault, push, issue_linked and get_vc_parent. 93 tests passing.
Factory deploys single-tenant vc-vault instances via deploy_v2. Salt = keccak256(user_salt || owner_bytes) prevents frontrunning and makes vault addresses deterministic per (owner, salt) pair. deploy(owner, did_uri, salt) — owner signs their own vault. deploy_sponsored(deployer, owner, did_uri, salt) — any third party signs and pays; vault ownership goes to owner from creation. is_vault(address) queries the persistent registry of deployed vaults. 10 tests passing including full integration and sponsored flow.
Adds VaultFactory persistent key to store the factory that deployed each vault, enabling cross-vault source verification in receive_push.
push() moves a VC from the source vault to a destination vault via a cross-contract call. receive_push() verifies the source is a legitimate factory-deployed vault before accepting the credential and sets itself as the new issuance authority.
c3c58f4 to
fe78dab
Compare
Summary
vc-vaultfrom multi-tenant to single-tenant: each holder gets their own deployed contract instance,owner: Addressremoved from all public functions, owner stored at constructionvc-vault-factorycontract: deploys vault instances deterministically viadeploy_v2, registers them, and exposesis_vaultfor cross-contract verificationdeploy_sponsored: anyone can deploy a vault on behalf of an owner (deployer signs/pays, vault belongs to owner from creation)push/receive_push: production-ready cross-vault VC transfer — source vault calls destination'sreceive_push, which verifies the source is a legitimate factory vault before accepting the credentialChanges
contracts/vc-vault(vault_owner, contract_admin, did_uri, factory_address)create_vault,create_sponsored_vault, sponsored-vault whitelist functionspush(vc_id, dest_vault),receive_push(source_vault, vc_id, vc_data, issuer_did)VaultOwnerandVaultFactorypersistent keys; all keys flattened (owner no longer part of key)contracts/vc-vault-factorydeploy(owner, did_uri, salt)— owner signsdeploy_sponsored(deployer, owner, did_uri, salt)— deployer signs, vault belongs to owneris_vault(address)— registry lookup used byreceive_pushfor source validationSalt = keccak256(user_salt ‖ owner_bytes) to prevent frontrunning
Closes feat: vc-vault-factory POC — single-tenant vaults deployed per holder #54