npm package: @somnia-chain/reactivity-contracts
Description: Solidity NPM package for building event-driven applications on the Somnia blockchain
Author: Somnia Foundation
Latest version: 0.1.6

# @somnia-chain/reactivity-contracts

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Solidity contracts and interfaces for building reactive smart contracts on the Somnia chain. This package enables on-chain reactivity: subscribe to events from other contracts and trigger automated responses via a the Reactivity precompile.

Key features:
- **Abstract Handler**: Inherit from `SomniaEventHandler` to easily implement event reactions with minimal boilerplate.
- **Precompile Interface**: Interact with the Somnia Reactivity Precompile at `0x0100` for subscription management.
- **Event Filtering**: Fine-grained filters for topics, origins, callers, and emitters.
- **Gas Management**: Customizable fees and limits for efficient handling.

This powers event-driven smart contracts, like auto-rewards on transfers or real-time protocol updates. There is no ceiling.

## Installation

```bash
npm install @somnia-chain/reactivity-contracts
# or
yarn add @somnia-chain/reactivity-contracts
```

or for `forge`, install this repo with the `forge install` command.

## Usage

### Core Components
- **SomniaEventHandler.sol**: Abstract contract to inherit from. Override `_onEvent` for your logic. Ensures only the precompile can invoke.
- **ISomniaEventHandler.sol**: Interface for handler contracts.
- **ISomniaReactivityPrecompile.sol**: Interface for the precompile at `0x0100`.
- **IERC165.sol**: Standard interface detection.

Import in your Solidity files:

```solidity
import { SomniaEventHandler } from "@somnia-chain/reactivity-contracts/contracts/SomniaEventHandler.sol";
import { ISomniaReactivityPrecompile } from "@somnia-chain/reactivity-contracts/contracts/interfaces/ISomniaReactivityPrecompile.sol";
```

### Creating a Handler Contract
Inherit from `SomniaEventHandler` and implement your reaction logic in `_onEvent`.

Example: Reward NFTs on large ERC20 transfers.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { SomniaEventHandler } from "@somnia-chain/reactivity-contracts/contracts/SomniaEventHandler.sol";
import { ISomniaReactivityPrecompile } from "@somnia-chain/reactivity-contracts/contracts/interfaces/ISomniaReactivityPrecompile.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
// Import your NFT contract or other dependencies

contract RewardHandler is SomniaEventHandler, Ownable {
    address public tokenAddress; // ERC20 to monitor
    uint256 public minTransferThreshold = 1000 ether; // Example threshold

    constructor(address _tokenAddress) Ownable(msg.sender) {
        tokenAddress = _tokenAddress;
    }

    function _onEvent(
        address emitter,
        bytes32[] calldata eventTopics,
        bytes calldata data
    ) internal override {
        // Decode Transfer event (assuming standard ERC20)
        // topic[1] == from address (20 bytes padded to 32 bytes)
        // topic[2] == to address (20 bytes padded to 32 bytes)
        // abi.decode(data, (uint256 value));
        // Example logic: If value > threshold, mint NFT to from
        // Be cautious: Avoid reentrancy or loops
    }

    // Optional: Function to create subscription (fully on-chain)
    function createSubscription() external onlyOwner {
        ISomniaReactivityPrecompile precompile = ISomniaReactivityPrecompile(SomniaExtensions.SOMNIA_REACTIVITY_PRECOMPILE_ADDRESS);

        ISomniaReactivityPrecompile.SubscriptionData memory subData = ISomniaReactivityPrecompile.SubscriptionData({
            eventTopics: [keccak256("Transfer(address,address,uint256)"), bytes32(0), bytes32(0), bytes32(0)],
            origin: address(0),
            caller: address(0),
            emitter: tokenAddress,
            handlerContractAddress: address(this),
            handlerFunctionSelector: this.onEvent.selector, // From ISomniaEventHandler
            priorityFeePerGas: 10,
            maxFeePerGas: 20,
            gasLimit: 500_000,
            isGuaranteed: true, // Regardless of block inclusion distance, always notify
            isCoalesced: false  // Never merge multiple notifications in a block into a single callback
        });

        precompile.subscribe(subData);
    }
}
```

- **Security**: `onEvent` checks `msg.sender == 0x0100`. Avoid emitting events that retrigger the handler.
- **IERC165 Support**: Built-in for precompile detection by the nodes.

### Managing Subscriptions
Use the precompile interface to subscribe/unsubscribe. Owners (EOA or contract) must hold min SOM (currently 32) for gas fees.

#### SubscriptionData Struct
```solidity
struct SubscriptionData {
    bytes32[4] eventTopics;      // Filters (0x0 = wildcard)
    address origin;              // tx.origin filter (0x0 = wildcard)
    address caller;              // msg.sender filter (0x0 = wildcard)
    address emitter;             // Emitter filter (0x0 = wildcard)
    address handlerContractAddress;
    bytes4 handlerFunctionSelector; // Optional
    uint64 priorityFeePerGas;
    uint64 maxFeePerGas;
    uint64 gasLimit;
    bool isGuaranteed;           // Retry if block full
    bool isCoalesced;            // Batch events
}
```

#### Precompile Methods
- `subscribe(SubscriptionData)`: Returns subscriptionId.
- `unsubscribe(uint64 subscriptionId)`.
- `getSubscriptions(address owner)`: View owner's IDs.
- `getSubscriptionInfo(uint64)`: View details.

Events:
- `SubscriptionCreated(uint64, address, SubscriptionData)`
- `SubscriptionRemoved(uint64, address)`

#### Off-Chain Setup (via SDK)
Use `@somnia-chain/reactivity` SDK for wallet-based creation.

```typescript
import { SDK } from '@somnia-chain/reactivity';

const sdk = new SDK({ /* config */ });

const subData = { /* Matching SubscriptionData */ };
await sdk.createSoliditySubscription(subData);
```

### Event Handling
On match, precompile calls your handler:
- `msg.sender`: `0x0100`
- `tx.origin`: Subscription owner
- Payload: Emitter, topics, data.

### Docs
See [here](https://docs.somnia.network/developer/reactivity) for more info from our official docs.

## Repo Structure
- `/contracts/`: SomniaEventHandler.sol
- `/interfaces/`: IERC165.sol, ISomniaEventHandler.sol, ISomniaReactivityPrecompile.sol

## License
MIT - see [LICENSE](./LICENSE).