InscriptionRegistry
Archivo: contracts/src/InscriptionRegistry.sol
Licencia: MIT
Solidity: ^0.8.24
Código fuente
contract InscriptionRegistry {
struct Inscription {
address creator;
uint256 timestamp;
uint256 blockNumber;
bytes data;
}
uint256 public inscriptionCount;
mapping(uint256 => Inscription) private _inscriptions;
event Inscribed(
uint256 indexed inscriptionId,
address indexed creator,
bytes data,
uint256 timestamp,
uint256 blockNumber
);
function inscribe(bytes calldata data) external;
function getInscription(uint256 inscriptionId) external view returns (...);
}
API pública
inscribe(bytes calldata data)
Registra una nueva inscripción permanente.
| Propiedad | Valor |
|---|---|
| Visibilidad | external |
| Estado | Modifica storage |
| Payable | No |
| Permisos | Cualquier dirección |
Comportamiento:
- Incrementa
inscriptionCount(pre-incremento, IDs empiezan en1) - Crea struct
Inscriptionconmsg.sender,block.timestamp,block.numberydata - Guarda en
_inscriptions[id] - Emite evento
Inscribed
Ejemplo con cast (Foundry):
cast send $CONTRACT "inscribe(bytes)" "0x48656c6c6f" \
--rpc-url https://rpc.testnet.chain.robinhood.com \
--private-key $PRIVATE_KEY
(0x48656c6c6f = "Hello" en hex)
getInscription(uint256 inscriptionId)
Lee una inscripción existente.
| Propiedad | Valor |
|---|---|
| Visibilidad | external view |
| Revert | "Invalid ID" si id == 0 o id > inscriptionCount |
Retorna:
(
address creator,
uint256 timestamp,
uint256 blockNumber,
bytes memory data
)
Ejemplo:
cast call $CONTRACT "getInscription(uint256)(address,uint256,uint256,bytes)" 1 \
--rpc-url https://rpc.mainnet.chain.robinhood.com
inscriptionCount()
Variable pública auto-generada. Retorna el número total de inscripciones registradas.
cast call $CONTRACT "inscriptionCount()(uint256)" \
--rpc-url https://rpc.mainnet.chain.robinhood.com
Evento Inscribed
event Inscribed(
uint256 indexed inscriptionId,
address indexed creator,
bytes data,
uint256 timestamp,
uint256 blockNumber
);
| Campo | Indexed | Uso |
|---|---|---|
inscriptionId | Sí | Filtrar por ID específico |
creator | Sí | Filtrar por dirección creadora |
data | No | Payload completo en el log |
timestamp | No | Unix timestamp del bloque |
blockNumber | No | Número de bloque L2 |
Filtro por creador (viem):
const logs = await publicClient.getLogs({
address: REGISTRY_ADDRESS,
event: parseAbiItem('event Inscribed(uint256 indexed inscriptionId, address indexed creator, bytes data, uint256 timestamp, uint256 blockNumber)'),
args: { creator: '0x...' },
fromBlock: 0n,
toBlock: 'latest',
});
Almacenamiento y gas
Layout de storage
| Slot | Variable | Tipo |
|---|---|---|
| 0 | inscriptionCount | uint256 |
| mapping | _inscriptions[id] | Inscription struct |
Cada Inscription ocupa múltiples slots por el campo dinámico bytes data.
Estimación de gas
El coste principal es el calldata (16 gas por byte no-cero, 4 por byte cero) más el storage de bytes.
| Tamaño aprox. | Calldata gas | Notas |
|---|---|---|
| 100 bytes texto | ~1,600+ | Muy económico en L2 |
| 1 KB | ~16,000+ | Razonable |
| 24 KB | ~384,000+ | Límite recomendado UI |
En Robinhood Chain L2, las tarifas son significativamente menores que en Ethereum L1.
Seguridad
Superficie de ataque mínima
- Sin
delegatecall, sin proxies, sinselfdestruct - Sin funciones administrativas
- Sin transferencias de valor
- Sin llamadas externas a otros contratos
- Sin bucles dependientes de input del usuario
Consideraciones
| Riesgo | Mitigación |
|---|---|
| Spam de inscripciones | Coste de gas por cada registro |
Datos maliciosos en bytes | El contrato no ejecuta ni interpreta el contenido |
| Reentrancy | No hay llamadas externas; no aplica |
| Overflow de IDs | uint256 — prácticamente ilimitado |
Lo que el contrato NO garantiza
- Privacidad del contenido (todo es público)
- Disponibilidad off-chain de datos históricos sin nodo RPC
- Inmutabilidad del contrato desplegado (depende de que no haya proxy)
Tests
Archivo: contracts/test/InscriptionRegistry.t.sol
| Test | Verifica |
|---|---|
test_InscribeStoresData | Datos, creator, timestamp y block se guardan correctamente |
test_MultipleInscriptionsIncrementId | IDs incrementales y datos independientes |
test_RevertOnInvalidId | Revert en ID inválido |
cd contracts
forge install foundry-rs/forge-std
forge test -vv
Salida esperada: 3 passed
Script de despliegue
Archivo: contracts/script/Deploy.s.sol
cd contracts
forge script script/Deploy.s.sol \
--rpc-url https://rpc.testnet.chain.robinhood.com \
--broadcast \
--private-key $PRIVATE_KEY
Alternativa directa:
forge create src/InscriptionRegistry.sol:InscriptionRegistry \
--rpc-url https://rpc.testnet.chain.robinhood.com \
--private-key $PRIVATE_KEY
ABI completa (JSON)
La ABI está embebida en lib/contract.ts para el frontend. Funciones:
[
"function inscribe(bytes calldata data)",
"function getInscription(uint256 inscriptionId) view returns (address, uint256, uint256, bytes)",
"function inscriptionCount() view returns (uint256)",
"event Inscribed(uint256 indexed inscriptionId, address indexed creator, bytes data, uint256 timestamp, uint256 blockNumber)"
]