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_address column exists but is always NULL
- No
wallet_address column on entity_registry
- V2 Phase 3 (per-reviewer signing via
cosmos.authz) requires this mapping but has no implementation path
Proposed Changes
- Add
wallet_address TEXT column to entity_registry (nullable, new migration)
- Populate
claim_attestations.attestor_address when creating attestations (if the reviewer entity has a mapped wallet address)
- Add API endpoint or field for registering wallet address mappings:
PATCH /entities/{uri}/wallet or similar
- Document the identity model: KOI entity URI = semantic identity, wallet address = cryptographic identity, both reference the same real-world entity
Why This Matters
Related
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 v
4. 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
Summary
The claims engine has no mapping between KOI entity URIs (
urn:koi:entity:...) and on-chain wallet addresses (regen1...). Theattestor_addresscolumn exists in theclaim_attestationsschema (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
entity_registry.fuseki_uriclaim_attestations.attestor_addresscolumn exists but is always NULLwallet_addresscolumn onentity_registrycosmos.authz) requires this mapping but has no implementation pathProposed Changes
wallet_address TEXTcolumn toentity_registry(nullable, new migration)claim_attestations.attestor_addresswhen creating attestations (if the reviewer entity has a mapped wallet address)PATCH /entities/{uri}/walletor similarWhy This Matters
AttestClaimrequires anattester(wallet address) -- no way to link back to KOI reviewercosmos.authzMsgGrant for per-reviewer signing needs a target addresswalletAddress(see feat: Claim and Attestation schemas for claims engine interop regen-network/regen-data-standards#53)Related
Implementation Spec (for Darren)
1. Add
wallet_addresstoentity_registryNew Alembic migration:
The partial unique index ensures no two entities share a wallet address while allowing multiple NULL values (entities without wallets).
2. Populate
attestor_addressduring attestation creationIn the attestation creation code path (likely
claims_router.pyor attestation service):This populates the existing (currently always-NULL)
attestor_addresscolumn without requiring any schema change toclaim_attestations.3. New endpoint:
PATCH /entities/{uri}/walletRequest model:
4. Address format validation
5. Include in entity responses
Update the entity serialization (response model) to include
wallet_addresswhen present:This ensures API consumers (including CLAMS and EAS integrations) can discover wallet mappings through normal entity queries.
Acceptance Criteria
wallet_address TEXTtoentity_registrywith partial unique indexattestor_addressis populated from reviewer'swallet_addressduring attestation creationPATCH /entities/{uri}/walletendpoint registers/updates wallet addressesregen1[a-z0-9]{38}and0x[0-9a-fA-F]{40}formatswallet_addresswhen present