web/docs/contracts/membership-platform-interfaces.md

5.1 KiB

EDUT Membership Platform Interfaces (v1)

This document freezes interface targets for membership-gated commerce.

Solidity Interfaces

interface IEdutMembership {
    event MembershipMinted(address indexed wallet, uint256 indexed tokenId, uint256 amountPaid, address currency);
    event MintPriceUpdated(address indexed currency, uint256 amountAtomic);
    event MembershipStatusUpdated(address indexed wallet, uint8 status);

    function mintMembership(address recipient) external payable returns (uint256 tokenId);
    function hasMembership(address wallet) external view returns (bool);
    function membershipStatus(address wallet) external view returns (uint8 status);
    function currentMintPrice() external view returns (address currency, uint256 amountAtomic);
}

interface IEdutOfferRegistry {
    event OfferUpserted(bytes32 indexed offerKey, bytes32 policyHash, address indexed issuer);
    event OfferStatusChanged(bytes32 indexed offerKey, uint8 status);

    function upsertOffer(bytes32 offerKey, bytes32 policyHash, bytes calldata encodedOffer) external;
    function setOfferStatus(bytes32 offerKey, uint8 status) external;
    function getOffer(bytes32 offerKey) external view returns (bytes memory encodedOffer);
}

interface IEdutEntitlement {
    event EntitlementMinted(bytes32 indexed entitlementId, bytes32 indexed offerKey, address indexed wallet);
    event EntitlementStateChanged(bytes32 indexed entitlementId, uint8 state);

    function mintEntitlement(bytes32 offerKey, address wallet, bytes32 policyHash) external returns (bytes32 entitlementId);
    function entitlementState(bytes32 entitlementId) external view returns (uint8 state);
}

interface IEdutSuiteEntitlement {
    event SuiteEntitlementBound(bytes32 indexed suiteEntitlementId, bytes32 indexed orgRootId, address indexed ownerWallet);
    event HumanAccessClassSet(bytes32 indexed orgRootId, bytes32 indexed principalId, uint8 accessClass);
    event HumanRoleSet(bytes32 indexed orgRootId, bytes32 indexed principalId, uint8 principalRole);
    event AvailabilityStateChanged(bytes32 indexed orgRootId, bytes32 indexed principalId, uint8 availabilityState);

    function bindSuiteEntitlement(bytes32 orgRootId, address ownerWallet, bytes32 policyHash) external returns (bytes32 suiteEntitlementId);
    function setHumanAccessClass(bytes32 orgRootId, bytes32 principalId, uint8 accessClass) external;
    function setHumanRole(bytes32 orgRootId, bytes32 principalId, uint8 principalRole) external;
    function availabilityState(bytes32 orgRootId, bytes32 principalId) external view returns (uint8 state);
}

Status Enums

MembershipStatus:
0 = NONE
1 = ACTIVE
2 = SUSPENDED
3 = REVOKED

OfferStatus:
0 = DRAFT
1 = ACTIVE
2 = PAUSED
3 = RETIRED

EntitlementState:
0 = ACTIVE
1 = SUSPENDED
2 = REVOKED
3 = EXPIRED

AccessClass:
0 = CONNECTED
1 = SOVEREIGN

AvailabilityState:
0 = ACTIVE
1 = GRACE
2 = CONTINUITY
3 = PARKED

PrincipalRole:
0 = WORKSPACE_MEMBER
1 = ORG_ROOT_OWNER

API Surface (Backend)

Wallet + Membership

  1. POST /secret/wallet/intent
  2. POST /secret/wallet/verify
  3. POST /secret/membership/quote
  4. POST /secret/membership/confirm
  5. GET /secret/membership/status?designation_code=...

Marketplace

  1. GET /marketplace/offers
  2. GET /marketplace/offers/{offer_id}
  3. POST /marketplace/checkout/quote
  4. POST /marketplace/checkout/confirm
  5. GET /marketplace/entitlements
  6. GET /marketplace/availability?org_root_id=...&principal_id=...

Governance Installer

  1. POST /governance/install/token
  2. POST /governance/install/confirm
  3. GET /governance/install/status
  4. POST /governance/lease/heartbeat
  5. POST /governance/lease/offline-renew

Issuer APIs

  1. POST /issuer/offers/upsert
  2. POST /issuer/offers/{offer_id}/status
  3. POST /issuer/manifests/upsert

Deterministic Gate Requirements

  1. Every checkout quote must include:
    • quote_id
    • wallet (ownership wallet)
    • payer_wallet (optional)
    • offer_id
    • currency
    • amount_atomic
    • policy_hash
    • expires_at
  2. Checkout confirm must fail closed if:
    • membership is not active,
    • suite boundary checks fail (org_root_id mismatch),
    • availability state is PARKED,
    • quote expired,
    • tx amount/currency mismatch,
    • policy hash mismatch.
  3. Entitlement activation must fail closed when state is not ACTIVE.
  4. Cross-boundary paid execution must fail closed unless target boundary has active suite entitlement.
  5. CONTINUITY state must block growth actions (new member/workspace/install/worker spawn).
  6. Admin operations (health/config/update/support ticket escalation) require ORG_ROOT_OWNER role.

Evidence Requirements

Each successful purchase must emit/record:

  1. wallet
  2. membership status snapshot
  3. offer_id and policy_hash
  4. quote_id
  5. tx_hash and chain_id
  6. entitlement_id
  7. org_root_id
  8. principal_id
  9. access_class + availability_state snapshot
  10. principal_role snapshot
  11. receipt timestamp

Compatibility Rule

Interfaces can only evolve through additive changes in v1. Breaking changes require v2 namespace and migration plan.