FeatherScript

FeatherScript

chain::4663

Docs

03 / 09

Smart Contract

API reference, events, gas, and security

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.

PropiedadValor
Visibilidadexternal
EstadoModifica storage
PayableNo
PermisosCualquier dirección

Comportamiento:

  1. Incrementa inscriptionCount (pre-incremento, IDs empiezan en 1)
  2. Crea struct Inscription con msg.sender, block.timestamp, block.number y data
  3. Guarda en _inscriptions[id]
  4. 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.

PropiedadValor
Visibilidadexternal 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
);
CampoIndexedUso
inscriptionIdFiltrar por ID específico
creatorFiltrar por dirección creadora
dataNoPayload completo en el log
timestampNoUnix timestamp del bloque
blockNumberNoNú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

SlotVariableTipo
0inscriptionCountuint256
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 gasNotas
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, sin selfdestruct
  • Sin funciones administrativas
  • Sin transferencias de valor
  • Sin llamadas externas a otros contratos
  • Sin bucles dependientes de input del usuario

Consideraciones

RiesgoMitigación
Spam de inscripcionesCoste de gas por cada registro
Datos maliciosos en bytesEl contrato no ejecuta ni interpreta el contenido
ReentrancyNo hay llamadas externas; no aplica
Overflow de IDsuint256 — 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

TestVerifica
test_InscribeStoresDataDatos, creator, timestamp y block se guardan correctamente
test_MultipleInscriptionsIncrementIdIDs incrementales y datos independientes
test_RevertOnInvalidIdRevert 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)"
]

Siguiente lectura

← Back to AppInscribe On-Chain