-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
The claims engine has no mapping between KOI entity URIs (urn:koi:entity:...) and on-chain wallet addresses (regen1...). The attestor_address column exists in the claim_attestations schema (migration 066) but is never populated by any code path.
This blocks interop with the CLAMS CosmWasm contract where identity is wallet-based, and with EAS where identity is Ethereum address-based.
Current State
- All identity uses KOI entity URIs via FK to
entity_registry.fuseki_uri claim_attestations.attestor_addresscolumn exists but is always NULL- No
wallet_addresscolumn onentity_registry - V2 Phase 3 (per-reviewer signing via
cosmos.authz) requires this mapping but has no implementation path
Proposed Changes
- Add
wallet_address TEXTcolumn toentity_registry(nullable, new migration) - Populate
claim_attestations.attestor_addresswhen creating attestations (if the reviewer entity has a mapped wallet address) - Add API endpoint or field for registering wallet address mappings:
PATCH /entities/{uri}/walletor similar - Document the identity model: KOI entity URI = semantic identity, wallet address = cryptographic identity, both reference the same real-world entity
Why This Matters
- CLAMS contract
AttestClaimrequires anattester(wallet address) -- no way to link back to KOI reviewer - EAS attestations on Ethereum require an attestor address
cosmos.authzMsgGrant for per-reviewer signing needs a target address- The FWG Entity schema (regen-data-standards) is being extended with
walletAddress(see feat: Claim and Attestation schemas for claims engine interop regen-network/regen-data-standards#53)
Related
- Integrate regen-data-standards schemas: add @context, reference FWG taxonomy #11 (regen-data-standards schema integration)
- Unify content hash strategy: align RID and anchor hashing #12 (content hash unification)
- V2 Phase 3 design: per-reviewer key delegation via cosmos.authz
Implementation Spec (for Darren)
1. Add wallet_address to entity_registry
New Alembic migration:
"""Add wallet_address to entity_registry"""
def upgrade():
op.add_column('entity_registry', sa.Column('wallet_address', sa.Text(), nullable=True))
# Partial unique index: only enforce uniqueness where wallet_address is not null
op.execute("""
CREATE UNIQUE INDEX ix_entity_registry_wallet_address
ON entity_registry (wallet_address)
WHERE wallet_address IS NOT NULL
""")The partial unique index ensures no two entities share a wallet address while allowing multiple NULL values (entities without wallets).
2. Populate attestor_address during attestation creation
In the attestation creation code path (likely claims_router.py or attestation service):
# When creating an attestation, look up the reviewer's wallet
reviewer = db.query(EntityRegistry).filter_by(fuseki_uri=reviewer_uri).first()
attestor_address = reviewer.wallet_address if reviewer else None
# Pass to attestation INSERT/UPSERT
new_attestation = ClaimAttestation(
...existing fields...,
attestor_address=attestor_address, # Populate from entity registry
)This populates the existing (currently always-NULL) attestor_address column without requiring any schema change to claim_attestations.
3. New endpoint: PATCH /entities/{uri}/wallet
@router.patch("/entities/{uri:path}/wallet")
async def register_wallet(
uri: str,
request: WalletRegistrationRequest,
db: Session = Depends(get_db),
):
"""Register or update a wallet address for an entity.
Links a semantic KOI entity URI to an on-chain wallet address,
enabling interop with CLAMS contract and EAS attestations.
"""
entity = db.query(EntityRegistry).filter_by(fuseki_uri=uri).first()
if not entity:
raise HTTPException(404, f"Entity not found: {uri}")
validate_wallet_address(request.wallet_address)
entity.wallet_address = request.wallet_address
db.commit()
return {"entity_uri": uri, "wallet_address": request.wallet_address}Request model:
class WalletRegistrationRequest(BaseModel):
wallet_address: str
@validator('wallet_address')
def validate_address(cls, v):
if not validate_wallet_address(v):
raise ValueError(f"Invalid wallet address format: {v}")
return v4. Address format validation
import re
REGEN_ADDRESS_PATTERN = re.compile(r'^regen1[a-z0-9]{38}$')
ETH_ADDRESS_PATTERN = re.compile(r'^0x[0-9a-fA-F]{40}$')
def validate_wallet_address(address: str) -> bool:
"""Validate wallet address format.
Accepts:
- Regen Network bech32 addresses: regen1[a-z0-9]{38}
- Ethereum hex addresses: 0x[0-9a-fA-F]{40}
Does NOT validate checksum — that's the wallet's responsibility.
"""
return bool(
REGEN_ADDRESS_PATTERN.match(address) or
ETH_ADDRESS_PATTERN.match(address)
)5. Include in entity responses
Update the entity serialization (response model) to include wallet_address when present:
class EntityResponse(BaseModel):
fuseki_uri: str
name: str
type: str
wallet_address: Optional[str] = None # Add this field
# ...existing fields...This ensures API consumers (including CLAMS and EAS integrations) can discover wallet mappings through normal entity queries.
Acceptance Criteria
- New migration adds
wallet_address TEXTtoentity_registrywith partial unique index -
attestor_addressis populated from reviewer'swallet_addressduring attestation creation -
PATCH /entities/{uri}/walletendpoint registers/updates wallet addresses - Validation accepts
regen1[a-z0-9]{38}and0x[0-9a-fA-F]{40}formats - Entity API responses include
wallet_addresswhen present - Existing entities and attestations unaffected (wallet_address is nullable)