Referencia Técnica
Documentación técnica detallada de la arquitectura interna de ISBE para desarrolladores avanzados.
Componentes Core
Los Componentes Core son las capacidades fundamentales que heredan automáticamente todos los contratos desplegados en ISBE.
Visión General
El Core agrupa las funcionalidades base del sistema:
- Inicialización: Patrón seguro para proxies Diamond
- Introspección: Detección de interfaces soportadas (ERC165)
- Control de Acceso: Sistema RBAC integrado con DIDs
- Propiedad: Gestión de propietario del contrato
- Pausabilidad: Capacidad de pausa de emergencia
- Utilidades: Validaciones y acceso a contexto blockchain
Todos estos componentes se agregan en Common, que actúa como clase base universal.
Common
Common agrega todas las capacidades Core. Todos los contratos ISBE heredan de Common.
contract MiCasoDeUso is Common {
// Tu contrato hereda automáticamente todas las capacidades Core
}
Inicialización de Proxies
ISBE usa el patrón Diamond Proxy (EIP-2535). Los proxies no pueden usar constructores, por lo que el Core proporciona inicialización segura.
bytes32 constant FACET_KEY = keccak256("MiToken.v1");
function initialize(string memory nombre)
external
initializer(FACET_KEY)
{
// Se ejecuta solo una vez por facet
}
El modificador initializer(_facetKey) garantiza ejecución única y previene re-inicializaciones.
Introspección de Interfaces
Implementa el estándar ERC165 para detección de interfaces. Permite consultar qué capacidades soporta un contrato:
bool soportaERC20 = contrato.supportsInterface(type(IERC20).interfaceId);
Los contratos registran automáticamente sus interfaces implementadas (ERC20, ERC721, AccessControl, etc.).
Control de Acceso (RBAC)
Sistema de control de acceso basado en roles integrado con identidades descentralizadas (DIDs).
Protección de Funciones:
modifier onlyRole(bytes32 _role) {
_checkRole(_role);
_;
}
Gestión de Roles:
// Otorgar/revocar roles por dirección (EOA)
function _grantRole(bytes32 role, address account) internal;
function _revokeRole(bytes32 role, address account) internal;
// Otorgar/revocar roles por DID
function _grantDidRole(bytes32 role, bytes32 did) internal;
function _revokeDidRole(bytes32 role, bytes32 did) internal;
// Verificar roles
function _hasRole(bytes32 role, address account) internal view returns (bool);
function _hasDidRole(bytes32 role, bytes32 did) internal view returns (bool);
Ejemplo de Uso:
contract MiCasoDeUso is Common {
bytes32 public constant OPERADOR_ROLE = keccak256("OPERADOR_ROLE");
function operar() external onlyRole(OPERADOR_ROLE) {
// Solo operadores pueden ejecutar
}
}
Nota: Los roles iniciales se configuran durante el despliegue del proxy (parámetros roles y members en deployUseCase). Las actualizaciones posteriores se realizan mediante AccessControlFacet (grantRole/revokeRole)
Integración DID: Los roles pueden asignarse tanto a direcciones Ethereum como a DIDs. Si una dirección tiene un DID asociado, se validan ambos automáticamente.
Gestión de Propiedad
Mecanismo de propiedad única del contrato. Solo el propietario puede ejecutar funciones protegidas.
modifier onlyOwner() {
_checkOwner();
_;
}
Funciones:
function _owner() internal view returns (address);
function _transferOwnership(address newOwner) internal;
Pausabilidad
Capacidad de pausar todas las operaciones del contrato en caso de emergencia.
modifier whenNotPaused() {
_requireNotPaused();
_;
}
Funciones:
function _paused() internal view returns (bool);
function _requireNotPaused() internal view;
Ejemplo:
function transfer(address to, uint256 amount)
external
whenNotPaused
returns (bool)
{
// Bloqueado si el contrato está pausado
}
Todas las plantillas ISBE implementan pausabilidad automática en operaciones críticas.
Utilidades y Validaciones
Funciones de contexto blockchain y validaciones comunes.
Contexto Blockchain:
function _blockTimestamp() internal view returns (uint256);
function _blockChainId() internal view returns (uint256);
function _msgSender() internal view returns (address);
function _msgSig() internal view returns (bytes4);
Validaciones:
// Validaciones de contenido
function _checkAddressIsNotZero(address addr) internal pure;
function _checkBytes32IsNotZero(bytes32 hash) internal pure;
function _checkEmptyBytes(bytes memory code) internal pure;
function _checkEmptyString(string memory str) internal pure;
function _checkUintIsNotZero(uint256 value) internal pure;
// Comparaciones
function _equalStrings(string memory a, string memory b) internal pure returns (bool);
function _equalBytes(bytes memory a, bytes memory b) internal pure returns (bool);
// Validación temporal
function _checkValidDates(uint256 before, uint256 after) internal pure;
Resumen Componentes Core
| Componente | Capacidad |
|---|---|
| Common | Clase base universal |
| Inicialización | initializer(_facetKey) |
| Introspección | supportsInterface() |
| Control de Acceso | onlyRole(), integración DID |
| Propiedad | onlyOwner() |
| Pausabilidad | whenNotPaused() |
| Utilidades | Validaciones y contexto blockchain |
Al heredar de Common, todos estos componentes están disponibles automáticamente.
Sistema de Identidad Descentralizada (DID)
ISBE usa identidades descentralizadas (DIDs) basadas en el estándar W3C, adaptadas para entornos permisionados con verificación institucional.
Qué es un DID
Un DID es un identificador único que representa una organización verificada en ISBE. Permite que múltiples wallets (empleados, dispositivos) operen bajo una misma identidad corporativa.
did:isbe:0x1234567890abcdef...
Ventajas vs Solo Direcciones
| Direcciones Ethereum | DIDs en ISBE |
|---|---|
| Una dirección = una cuenta | Un DID = múltiples wallets de una organización |
| Cambiar wallet = perder historial | Rotar wallets manteniendo identidad |
| Sin metadata verificada | Información corporativa verificada |
| Sin gestión delegada | Controladores autorizados |
Creación de DIDs (Onboarding)
Importante: Los DIDs NO se auto-registran. ISBE los crea tras verificar la identidad corporativa.
Flujo de Onboarding:
- Organización solicita acceso a ISBE
- Verificación institucional (certificados cualificados, documentación legal)
- Firma de acuerdos contractuales
- ISBE admin crea el DID con rol
ISBE_ROLE - Se designan controladores autorizados (representantes legales)
// Solo ISBE admin
function insertFirstDidDocument(
bytes32 did,
string memory baseDocument,
bytes memory signature
) external onlyRole(ISBE_ROLE);
Componentes del DID
1. Controladores
Quién puede modificar el DID. Representantes legales autorizados de la organización.
// Añadir controlador
function addController(bytes32 did, bytes32 newController) external;
// Revocar controlador
function revokeController(bytes32 did, bytes32 controller) external;
// Consultar control
function checkController(bytes32 did, address account) external view returns (bool);
2. Verification Methods (Claves/Wallets)
Wallets de empleados asociadas al DID corporativo.
// Añadir wallet de empleado
function addVerificationMethod(
bytes32 did,
bytes32 vMethodId,
bytes memory publicKey
) external;
// Revocar wallet
function revokeVerificationMethod(bytes32 did, bytes32 vMethodId) external;
// Rotar wallet (cambiar antigua por nueva)
function rollVerificationMethod(
bytes32 did,
bytes32 oldVMethodId,
bytes32 newVMethodId,
bytes memory newPublicKey
) external;
3. Verification Relationships (Propósitos)
Define para qué sirve cada clave:
authentication: Login/autenticaciónassertionMethod: Firma de documentoskeyAgreement: CifradocapabilityInvocation: Invocar permisos
// Asignar propósito a una clave
function addVerificationRelationship(
bytes32 did,
bytes32 vMethodId,
string memory relationship,
uint256 notBefore,
uint256 notAfter
) external;
Consultas
// ¿Está registrada esta dirección?
function isKnownDid(address account) external view returns (bool);
// ¿Qué DID tiene esta dirección?
function didOf(address account) external view returns (bytes32);
// Obtener DID Document actual
function getDidDocument(bytes32 did) external view returns (DidDocument memory);
// Obtener DID Document histórico
function getDidDocumentByTimestamp(bytes32 did, uint256 timestamp) external view
returns (DidDocument memory);
// Listar todos los DIDs (paginado)
function getDids(uint256 page, uint256 pageSize) external view
returns (bytes32[] memory);
Integración con Control de Acceso
ISBE integra DIDs con RBAC, permitiendo asignar roles a identidades (no solo direcciones).
Fallback Automático:
Cuando se verifica un rol:
- ¿La dirección tiene el rol? → Permitir
- Si no, obtener DID de esa dirección
- ¿El DID tiene el rol? → Permitir
- Si ninguno → Denegar
function hasRole(bytes32 role, address account) public view returns (bool) {
// 1. Verificar por dirección
if (_hasRoleByAddress(role, account)) return true;
// 2. Obtener DID
bytes32 did = didRegistry.didOf(account);
if (did == bytes32(0)) return false;
// 3. Verificar por DID
return _hasRoleByDid(role, did);
}
Ventajas:
- Multiwallet: Un DID, múltiples empleados con acceso
- Rotación de claves: Cambiar wallet sin perder roles
- Recuperación: Añadir nueva wallet si se pierde una
Ejemplo: Un DID, Tres Wallets
DID Corporativo: did:isbe:empresa-abc
├─ Wallet CEO: 0x123...
├─ Wallet CFO: 0x456...
└─ Wallet Manager: 0x789...
Rol OPERATOR asignado al DID
→ Las 3 wallets tienen el rol automáticamente
Resumen Sistema de Identidad
| Componente | Descripción |
|---|---|
| DID | Identidad corporativa única y verificada |
| Onboarding | ISBE crea DIDs tras verificación institucional |
| Controladores | Representantes legales que gestionan el DID |
| Verification Methods | Wallets de empleados asociadas al DID |
| Verification Relationships | Propósitos de cada wallet (auth, firma, etc.) |
| Consultas | Resolución dirección → DID |
| Integración RBAC | Roles asignados a identidades, no solo direcciones |
El sistema DID de ISBE combina la flexibilidad de identidades descentralizadas con la verificación institucional requerida en entornos regulados.
Patrón Diamond (EIP-2535)
El Patrón Diamond (EIP-2535) es la arquitectura obligatoria en ISBE para todos los contratos de negocio. Permite construir contratos modulares, actualizables y sin límites de tamaño mediante facets (módulos independientes).
Qué es el Patrón Diamond
Arquitectura que permite que un único contrato (diamond) enrute llamadas a múltiples módulos (facets):
Usuario → Diamond → Facet 1 (HashTimestamp)
├→ Facet 2 (AccessControl)
├→ Facet 3 (Pausable)
└→ Facet N (BusinessLogic)
Características:
- Un punto de entrada: Dirección única del diamond
- Múltiples facets: Funcionalidades modulares
- Storage compartido: Todas las facets acceden al mismo storage
- Actualizable: Sin cambiar dirección del contrato
- Sin límites de tamaño: Supera el límite de 24KB de la EVM
Por qué Diamond en ISBE
ISBE adopta Diamond como único estándar.
Ventajas:
| Aspecto | Beneficio |
|---|---|
| Modularidad | Cada funcionalidad es un módulo autocontenido |
| Escalabilidad | Sin límites de tamaño |
| Upgradeabilidad | Actualizar módulos sin migración |
| Gobernanza | Control centralizado de cambios |
| Pausado global | Todas las facets pausables desde un punto |
| RBAC unificado | Roles y permisos gestionados centralmente |
| Auditoría | Una dirección, trazabilidad completa |
Arquitectura Diamond en ISBE
1. Diamond Contract (Núcleo)
Recibe todas las llamadas y enruta a las facets mediante delegatecall:
abstract contract EIP2535 is FacetAddressResolver {
receive() external payable {}
fallback() external payable {
// Get facet from function selector
address facet = _resolveFacetAddress(msg.sig);
// Execute external function from facet using delegatecall
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
function _resolveFacetAddress(bytes4 _sig) private view returns (address) {
address facet = _facetAddress(_sig);
require(facet != address(0), FunctionNotFound(_sig));
return facet;
}
}
2. Facets (Módulos)
| Facet | Propósito |
|---|---|
| DiamondLoupeFacet | Introspección (consultar estructura) |
| DiamondCutFacet | Gestión de facets (añadir/actualizar/eliminar) |
| Business Logic Facets | Lógica específica del caso de uso |
3. Diamond Storage
Storage compartido usando unstructured storage (slots únicos calculados con keccak256):
// Estructura del storage del diamond
struct DiamondStorage {
mapping(bytes4 => FacetAddressAndItemPosition) facetAddressAndSelectorPosition;
bytes4[] selectors;
mapping(bytes4 => FacetAddressAndItemPosition) facetAddressAndInterfacePosition;
bytes4[] interfaces;
}
// Posición fija del storage
bytes32 constant _DIAMOND_STORAGE_POSITION =
keccak256("isbe.contracts.diamond.storage");
function _diamondStorage()
private
pure
returns (DiamondStorage storage storage_)
{
bytes32 position = _DIAMOND_STORAGE_POSITION;
assembly {
storage_.slot := position
}
}
Storage de Facets: Cada facet usa su propio slot único para evitar colisiones:
struct MyFacetStorage {
mapping(bytes32 => uint256) data;
}
bytes32 constant _MY_FACET_STORAGE_POSITION =
keccak256("isbe.contracts.myfacet.storage");
function _myFacetStorage()
internal
pure
returns (MyFacetStorage storage storage_)
{
bytes32 position = _MY_FACET_STORAGE_POSITION;
assembly {
storage_.slot := position
}
}
Estructura de Facets en ISBE
Interfaz Obligatoria: IEIP2535Introspection
interface IEIP2535Introspection {
// Interfaces ERC-165 soportadas
function interfacesIntrospection() external pure returns (bytes4[] memory);
// Identificador único de la facet
function businessIdIntrospection() external pure returns (bytes32);
// Funciones expuestas
function selectorsIntrospection() external pure returns (bytes4[] memory);
}
Patrón Internal/External:
Las facets separan lógica interna de funciones públicas:
Internal: Storage y lógica interna con prefijo _
abstract contract HashTimestampInternal {
struct HashTimestampStorage {
mapping(bytes32 => uint256) hashTimestamps;
}
function _hashTimestampStorage()
internal pure
returns (HashTimestampStorage storage storage_)
{
bytes32 position = _HASH_TIMESTAMP_STORAGE_POSITION;
assembly {
storage_.slot := position
}
}
function _timestampHash(bytes32 _hash) internal {
uint256 timestamp = _blockTimestamp();
_hashTimestampStorage().hashTimestamps[_hash] = timestamp;
emit IHashTimestamp.HashTimestamped(_hash, msg.sender, timestamp);
}
}
External: Funciones públicas que usan las internas
abstract contract HashTimestamp is HashTimestampInternal {
function timestampHash(bytes32 _hash)
external
override
whenNotPaused
onlyRole(_HASH_TIMESTAMP_ROLE)
{
_timestampHash(_hash);
}
}
Facet: Combina external + introspección
contract HashTimestampFacet is HashTimestamp, IEIP2535Introspection {
function businessIdIntrospection() external pure returns (bytes32) {
return _HASH_TIMESTAMP_RESOLVER_KEY;
}
function selectorsIntrospection() external pure returns (bytes4[] memory) {
// ... retorna selectores
}
}
Patrón clave: Funciones externas usan métodos internos. NUNCA acceden directamente al storage.
Gestión de Facets (DiamondCut)
Operaciones:
enum ItemCutAction {
Add, // Agregar nuevos selectores
Replace, // Reemplazar selectores existentes
Remove // Eliminar selectores
}
struct ItemCut {
address facetAddress;
ItemCutAction action;
bytes4[] items;
}
Funciones:
interface IDiamondCut {
function diamondCut(
ItemCut[] calldata _diamondCut,
address _init,
bytes calldata _calldata
) external;
}
Seguridad: Solo DEFAULT_ADMIN_ROLE puede ejecutar diamondCut.
Introspección (DiamondLoupe)
Consultar estructura del diamond:
interface IDiamondLoupe {
function facets() external view returns (Facet[] memory);
function facetFunctionSelectors(address facet) external view returns (bytes4[] memory);
function facetAddresses() external view returns (address[] memory);
function facetAddress(bytes4 selector) external view returns (address);
}
Interacción con Diamond
Desde Solidity:
import {IHashTimestamp} from '@isbe/contracts/hashtimestamp/IHashTimestamp.sol';
IHashTimestamp hashRegistry = IHashTimestamp(diamondAddress);
hashRegistry.timestampHash(hash);
Desde Web3/Ethers:
const diamondAbi = [...hashTimestampAbi, ...accessControlAbi];
const diamond = new ethers.Contract(diamondAddress, diamondAbi, signer);
await diamond.timestampHash(documentHash);
Comparación con Otros Patrones
| Característica | Standalone | Proxy UUPS | Diamond |
|---|---|---|---|
| Tamaño máximo | 24KB | 24KB | Ilimitado |
| Actualización | Migración | Mono-implementación | Multi-facet granular |
| Dirección | Cambia | Fija | Fija |
| Modularidad | Baja | Baja | Alta |
| Introspección | No | Limitada | Completa |
Resumen Diamond
| Aspecto | Descripción |
|---|---|
| Arquitectura | Un diamond + múltiples facets |
| Storage | Unstructured, compartido |
| Actualización | Granular, sin cambio de dirección |
| Tamaño | Ilimitado |
| Introspección | Completa (DiamondLoupe) |
| Obligatorio en ISBE | Sí, único patrón permitido |
Diamond permite a ISBE mantener control centralizado de gobernanza con máxima flexibilidad modular.
Sistema de Gobernanza
El Sistema de Gobernanza de ISBE es el contrato central que controla el despliegue y gestión de todos los casos de uso en la red mediante el patrón Diamond (EIP-2535).
Visión General
ISBE utiliza una arquitectura de gobernanza centralizada:
- Diamond de Gobernanza: Contrato central que coordina toda la red
- Diamonds de Casos de Uso: Cada aplicación/organización tiene su propio diamond independiente
- Facets: Módulos reutilizables desplegados mediante factories
Principios:
- Centralización: Un único diamond de gobernanza coordina toda la red
- Modularidad: Casos de uso independientes mediante patrón Diamond
- Control de Acceso: Roles específicos para cada operación
- Seguridad: Pausado global y gestión centralizada de DIDs
Capacidades del Diamond de Gobernanza
Factories (Despliegue):
- BusinessLogicFactory: Despliega y versiona facets reutilizables
- ConfigurationManagement: Crea configuraciones (conjuntos de facets)
- ProxyFactory: Despliega diamonds de casos de uso
Gestión:
- AccessControl: Control de roles y permisos
- DiamondCut/Loupe: Gestión e introspección del diamond
- GlobalPause: Pausado de emergencia de cualquier caso de uso
- DidRegistry: Registro centralizado de identidades (DIDs)
- ENS: Sistema de nombres descentralizado
Roles
Roles de Gobernanza:
- GOVERNANCE_MANAGER_ROLE: Gestiona el diamond de gobernanza
- BUSINESS_LOGIC_DEPLOYER_ROLE: Despliega facets mediante factory
- GOVERNANCE_CONFIGURATION_MANAGER_ROLE: Crea configuraciones
- PROXY_DEPLOYER_ROLE: Despliega casos de uso
- ISBE_PAUSER_ROLE: Pausado global de emergencia
- DID_REGISTRY_ROLE: Gestiona DIDs (onboarding institucional)
- DEFAULT_ADMIN_ROLE: Administración de roles
Roles en Casos de Uso:
- DEFAULT_ADMIN_ROLE: Admin local del caso de uso
- ISBE_ROLE: Representante de gobernanza (inmutable)
- PAUSER_ROLE: Pausado local
- Roles específicos: Según las facets incluidas
ISBE_ROLE: Este rol es inmutable y garantiza que gobernanza siempre mantiene control sobre los casos de uso.
Cómo Funciona
1. Despliegue de Facets
ISBE despliega facets mediante la BusinessLogicFactory:
- Cada facet se identifica con un businessId único
- El sistema versiona automáticamente: misma facet → v1, v2, v3...
- Las facets son módulos reutilizables que implementan funcionalidad específica
2. Configuraciones
Las configuraciones son conjuntos predefinidos de facets:
- Se crean mediante ConfigurationManagement
- Ejemplo: Config "Trazabilidad" = HashTimestamp + Pausable + AccessControl
- También se versionan automáticamente al actualizarse
3. Despliegue de Casos de Uso
La ProxyFactory crea diamonds de casos de uso:
- Se selecciona una configuración existente
- Se añaden automáticamente facets de gobernanza
- Se configuran roles iniciales
- Resultado: Diamond completo listo para usar
4. Gestión Continua
- Pausado local: Cada caso de uso puede pausarse individualmente
- Pausado global: Gobernanza puede pausar cualquier caso de uso (emergencias)
- DIDs: Registro centralizado consultable por todos los casos de uso
Resumen Gobernanza
| Aspecto | Descripción |
|---|---|
| Arquitectura | Diamond central de gobernanza coordina todos los casos de uso |
| Factories | BusinessLogic, Configuration, Proxy - despliegan facets y casos de uso |
| Roles | Control granular: GOVERNANCE_MANAGER, BUSINESS_LOGIC_DEPLOYER, PROXY_DEPLOYER, etc. |
| Configuraciones | Conjuntos predefinidos de facets, versionados automáticamente |
| Seguridad | Pausado local/global, roles inmutables (ISBE_ROLE), DIDs centralizados |
| Modularidad | Patrón Diamond (EIP-2535) permite facets ilimitadas y actualizables |
El sistema de gobernanza proporciona despliegue controlado y gestión centralizada de toda la red ISBE.
¿Tienes dudas frecuentes sobre el desarrollo en ISBE?