diff --git a/docs/docs/debugging.md b/docs/docs/debugging.md index f5a71f4..f735b53 100644 --- a/docs/docs/debugging.md +++ b/docs/docs/debugging.md @@ -89,7 +89,7 @@ The exchange rate is **1:100** — for each **ETH** sent, you receive **100 lREA ### ReacDEFI Swap -You can also swap ETH for lREACT directly using [ReacDEFI](https://reacdefi.app/markets). Select the desired lREACT amount, and the app will calculate the required ETH. An Ethereum/Base Sepolia wallet (MetaMask or Coinbase) must be connected. +You can also swap ETH for lREACT directly using [ReacDEFI](https://reacdefi.app/markets#testnet-faucet). Select the desired lREACT amount, and the app will calculate the required ETH. An Ethereum/Base Sepolia wallet (MetaMask or Coinbase) must be connected. ### Terminal Request diff --git a/docs/docs/demos.md b/docs/docs/demos.md index d9552af..1216c51 100644 --- a/docs/docs/demos.md +++ b/docs/docs/demos.md @@ -1,7 +1,7 @@ --- title: Demos sidebar_position: 12 -description: Discover the Reactive Network's capabilities through practical demos. From basic log monitoring to advanced Uniswap V2 stop order implementation, discover versatile real-world applications and refinements. +description: Practical Reactive Network demos covering event subscriptions, log monitoring, dynamic callbacks, and real-world automation examples including Uniswap V2 stop orders. slug: /demos hide_title: true --- @@ -10,36 +10,32 @@ hide_title: true ## Overview -This section is dedicated to practical demonstrations explaining the capabilities of the Reactive Network. +This section contains practical demos of how Reactive Network enables event-driven, cross-chain smart contract automation. Each demo highlights a specific pattern from basic event callbacks to advanced DeFi protection mechanisms. ## Reactive Network Demo -The [Reactive Network Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/basic) serves as an introduction, illustrating the Reactive Network's functionality in monitoring logs emitted by contracts in the L1 Network and initiating calls back to L1 contracts. It outlines the interaction between three smart contracts: the Origin chain contract [BasicDemoL1Contract.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/basic/BasicDemoL1Contract.sol), the Destination chain contract [BasicDemoL1Callback.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/basic/BasicDemoL1Callback.sol), and the Reactive contract [BasicDemoReactiveContract.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/basic/BasicDemoReactiveContract.sol). +The [Reactive Network Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/basic) is the starting point. It demonstrates the lifecycle of a Reactive Contract: an event emitted on an origin chain is detected by a Reactive Contract, which then triggers a callback on a destination chain. If you’re new to Reactive Network, begin here. ## Uniswap V2 Stop Order Demo -The [Uniswap V2 Stop Order Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/uniswap-v2-stop-order) extends the functionality to implement stop orders for Uniswap V2 liquidity pools. It elaborates on three smart contracts: the Origin chain contract [UniswapDemoToken.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/uniswap-v2-stop-order/UniswapDemoToken.sol), the Destination chain contract [UniswapDemoStopOrderCallback.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/uniswap-v2-stop-order/UniswapDemoStopOrderCallback.sol), and the Reactive contract [UniswapDemoStopOrderReactive.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/uniswap-v2-stop-order/UniswapDemoStopOrderReactive.sol), executing stop orders based on exchange rate thresholds. It also ponders potential refinements and improvements for a production-grade stop order system. +The [Uniswap V2 Stop Order Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/uniswap-v2-stop-order) implements automated stop orders on Uniswap V2 liquidity pools. A Reactive Contract subscribes to `Sync` events from a Uniswap pair. When the exchange rate crosses a user-defined threshold, it triggers a callback that executes the swap on the destination chain. This demo shows how price-based automation can run without off-chain bots. -## Approval Magic Demo - -The [Approval Magic Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/approval-magic) demonstrates the use of reactive and subscription-based smart contracts to enable automated token approvals and cross-chain exchanges. It elaborates on contracts like [ApprovalService.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/approval-magic/ApprovalService.sol) for managing subscriptions, [ApprovalListener.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/approval-magic/ApprovalListener.sol) for handling reactive events, and additional contracts for token initialization, exchanges, and swaps. - -## Hyperlane Demo +## Uniswap V2 Stop-Loss & Take-Profit Orders Demo -The [Hyperlane Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/hyperlane) demonstrates real-time cross-chain interaction between smart contracts without relying on centralized relayers or callback proxies. It uses Reactive for subscribing to on-chain events and Hyperlane for message delivery between chains. The demo includes two contracts. The [`HyperlaneOrigin.sol`](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/hyperlane/HyperlaneOrigin.sol) contract emits trigger events and records messages received from other chains via a trusted Hyperlane mailbox. [`HyperlaneReactive.sol`](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/hyperlane/HyperlaneReactive.sol) listens for these events via the Reactive Network, responds through a `react()` function, and can send messages back. +The [Uniswap V2 Stop-Loss & Take-Profit Orders Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/uniswap-v2-stop-take-profit-order) expands on stop orders by supporting both stop-loss and take-profit strategies within a personal deployment. A user-owned Reactive Contract monitors pair reserve updates and triggers execution when thresholds are crossed. Each user deploys their own callback and Reactive Contracts, ensuring isolated order management and full control. This example demonstrates structured, event-driven trade automation directly tied to on-chain liquidity changes. -## Uniswap V2 Exchange Rate History Demo +## Aave Liquidation Protection Demo -The [Uniswap V2 Exchange Rate History Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/uniswap-v2-history) captures and stores historical exchange rates from Uniswap V2 liquidity pools. It elaborates on two smart contracts: the Origin chain contract [UniswapHistoryDemoL1.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/uniswap-v2-history/UniswapHistoryDemoL1.sol), and the Reactive contract [UniswapHistoryDemoReactive.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/uniswap-v2-history/UniswapHistoryDemoReactive.sol), which collaborate to record exchange rate data based on specific block numbers. The purpose of this demo is to monitor sync events on all Uniswap V2 liquidity pools and provide historical exchange rate information upon request. +The [Aave Liquidation Protection Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/aave-liquidation-protection) shows how to automate position protection on Aave. A Reactive Contract subscribes to periodic CRON events and triggers health checks for a user’s lending position. If the health factor drops below a defined threshold, the callback contract executes protection actions — depositing collateral, repaying debt, or both. This demo illustrates time-based automation for DeFi risk management. -## ERC-20 Turnovers Demo +## Approval Magic Demo -The [ERC-20 Turnovers Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/erc20-turnovers) records and reports the turnover of ERC-20 tokens. It details two smart contracts: the Origin chain contract [TokenTurnoverL1.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/erc20-turnovers/TokenTurnoverL1.sol), and the Reactive contract [TokenTurnoverReactive.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/erc20-turnovers/TokenTurnoverReactive.sol), which work together to calculate and report token turnovers based on specific events. The purpose of this demo is to monitor token turnovers on all ERC-20 contracts and provide this information upon request. +The [Approval Magic Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/approval-magic) shows subscription-based automation triggered by ERC-20 approval events. A Reactive Contract monitors approval logs, while a service contract manages user registrations. When an approval is detected, the system can automatically initiate follow-up actions such as swaps or exchanges. This demo highlights how event-centric logic can simplify multi-step token workflows. -## ERC-721 Ownership Demo +## Hyperlane Demo -The [ERC-721 Ownership Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/erc721-ownership) tracks and reports the ownership of ERC-721 tokens. It details two smart contracts: the Origin chain contract [NftOwnershipL1.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/erc721-ownership/NftOwnershipL1.sol), and the Reactive contract [NftOwnershipReactive.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/erc721-ownership/NftOwnershipReactive.sol), which work together to record and report token ownership changes. The purpose of this demo is to monitor token ownership changes on all ERC-721 contracts and provide this information upon request. +The [Hyperlane Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/hyperlane) shows cross-chain communication using Hyperlane alongside Reactive Network. This example shows how Reactive Network can integrate with external messaging protocols for two-way cross-chain interaction. -## Reactive Faucet App/Demo +## CRON Demo -The [Reactive Faucet App/Demo](https://github.com/Reactive-Network/testnet-faucet) facilitates fund transfers between any chain and the Reactive Network. This is the same faucet that operates on our testnet. It involves two smart contracts: [ReactiveFaucetL1.sol](https://github.com/Reactive-Network/testnet-faucet/blob/main/src/faucet/ReactiveFaucetL1.sol) and [ReactiveFaucet.sol](https://github.com/Reactive-Network/testnet-faucet/blob/main/src/faucet/ReactiveFaucet.sol). \ No newline at end of file +The [Cron Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/cron) shows time-based automation using Reactive Network’s built-in CRON events. Instead of waiting for external transactions, the Reactive Contract subscribes to periodic system-emitted events and executes logic on a fixed schedule. This pattern is useful for recurring tasks such as scheduled updates, reward distributions, or regular DeFi position checks. \ No newline at end of file diff --git a/docs/docs/economy.md b/docs/docs/economy.md index e13315c..6b663f2 100644 --- a/docs/docs/economy.md +++ b/docs/docs/economy.md @@ -1,7 +1,7 @@ --- title: Economy sidebar_position: 6 -description: Explore the Reactive Network's economy and callback payment mechanisms. +description: Learn how Reactive Contracts pay for execution and cross-chain callbacks, including REACT funding, transaction fees, and callback pricing. slug: /economy hide_title: true --- @@ -10,19 +10,17 @@ hide_title: true ## Overview -This section covers RVM transaction payments, including direct transfers and system contract deposits. It also explains callback payments, on-the-spot settlements, and the pricing model for callbacks. +This section explains how Reactive Contracts pay for execution and cross-chain callbacks, including REACT funding, transaction fees, and callback pricing. RVM transactions and callbacks are executed first and accounted for later. Contracts must maintain sufficient balances to remain active. -## RVM Transactions +## RVM Transactions -RVM transactions have no gas price or any monetary value. Payments occur post-factum in a later block (ideally the next one, but not guaranteed). The fee appears only then, determined by the base fee of that block. Reactscan can't directly link this fee to specific RVM transactions. +RVM transactions do not include a gas price at execution time. Fees are calculated and charged later using the base fee of a subsequent block (typically the next block). Because accounting is aggregated at the block level, Reactscan can't associate fees with individual RVM transactions. :::info[Max Gas Limit] The maximum gas limit for RVM transactions is 900,000 units. ::: -An RVM transaction happens in block *n*, while accounting occurs in block *n+1* (or later) using that block’s base fee. However, it’s impossible to trace which specific RVM transaction was accounted for, as the block aggregates all transactions without distinction. - -The Reactive Transaction Fee is determined by the formula: +The Reactive transaction fee is calculated as: $$ fee = BaseFee ⋅ GasUsed @@ -30,46 +28,62 @@ $$ Where: -- `BaseFee`: Base fee per unit of gas in the block header, ensuring alignment with the network's current pricing conditions. -- `GasUsed`: Actual gas consumed by the reactive transaction during execution. +- `BaseFee` — base fee per gas unit in the accounting block +- `GasUsed` — gas consumed during execution :::info[Reactive Network Transactions] -RNK transactions operate the same way as standard EVM transactions. +RNK transactions follow the standard EVM gas model. ::: ### Direct Transfers -All RVM transactions must be paid in REACT by transferring funds to a specific reactive contract. A direct payment can be made as follows: +Reactive Contracts must be funded in REACT before executing RVM transactions. + +Fund a contract: ```bash -cast send $CONTRACT_ADDR --rpc-url $REACTIVE_RPC --private-key $REACTIVE_PRIVATE_KEY --value 0.1ether +cast send $CONTRACT_ADDR \ + --rpc-url $REACTIVE_RPC \ + --private-key $REACTIVE_PRIVATE_KEY \ + --value 0.1ether ``` -After funding the contract, you must settle any outstanding debt using the `coverDebt()` method: +Then settle outstanding debt: ```bash -cast send --rpc-url $REACTIVE_RPC --private-key $REACTIVE_PRIVATE_KEY $CONTRACT_ADDR "coverDebt()" +cast send \ + --rpc-url $REACTIVE_RPC \ + --private-key $REACTIVE_PRIVATE_KEY \ + $CONTRACT_ADDR "coverDebt()" ``` :::info[Contract Status] -The contract's status is available on [Reactive Scan](https://reactscan.net/) under its dedicated RVM. If `active`, it will execute transactions normally. If `inactive`, outstanding debt must be settled. +Contract status is available on [Reactscan](https://reactscan.net/). + +- `active` — contract executes normally +- `inactive` — outstanding debt must be settled ::: -### Depositing via System Contract +### System Contract Deposits -The `depositTo()` method allows funding through the system contract. The transaction fee is covered by the sender (EOA), and the system contract automatically settles any debt, eliminating the need to call coverDebt(). +Contracts can be funded through the system contract using `depositTo()`. The sender pays the transaction fee, and any outstanding debt is settled automatically. ```bash -cast send --rpc-url $REACTIVE_RPC --private-key $REACTIVE_PRIVATE_KEY $SYSTEM_CONTRACT_ADDR "depositTo(address)" $CONTRACT_ADDR --value 0.1ether +cast send \ + --rpc-url $REACTIVE_RPC \ + --private-key $REACTIVE_PRIVATE_KEY \ + $SYSTEM_CONTRACT_ADDR "depositTo(address)" \ + $CONTRACT_ADDR \ + --value 0.1ether ``` :::info[System Contract] -On the Reactive Network, the system contract and callback proxy share the same address: `0x0000000000000000000000000000000000fffFfF`. +On Reactive Network, the system contract and callback proxy share the same address: `0x0000000000000000000000000000000000fffFfF`. ::: ## Callback Pricing -Callback pricing dynamically adjusts based on block base fees. The cost, $$p_{callback}$$, is calculated as follows: +Callback costs depend on the destination network and current base fees. The callback price $$p_{callback}$$ is calculated as: $$ p_{callback} = p_{base} ⋅ C ⋅ (g_{callback} + K) @@ -77,92 +91,103 @@ $$ Where: -- $$p_{base}$$: Base gas price, determined by `tx.gasprice` and `block.basefee`. -- $$C$$: Pricing coefficient specific to the destination network. -- $$g_{callback}$$: Gas consumed during callback execution. -- $$K$$: Fixed gas surcharge for the destination network. +- $$p_{base}$$ — base gas price (`tx.gasprice` or `block.basefee`) +- $$C$$ — destination-network pricing coefficient +- $$g_{callback}$$ — callback gas usage +- $$K$$ — fixed gas surcharge ## Callback Payment -Callbacks require the same payment mechanism as reactive transactions. If a contract fails to pay, it is blocklisted, preventing future callbacks and transactions. +Callbacks use the same payment model as RVM transactions. Contracts without sufficient funds are blocklisted and can't execute transactions or callbacks. :::warning[Callback Gas Limit] -The Reactive Network enforces a minimum callback gas limit of 100,000 gas. Callback requests below this threshold are ignored, as this minimum ensures sufficient gas for internal audits and computations required to process the callback. +Reactive Network enforces a minimum callback gas limit of 100,000 gas. Callback requests below this threshold are ignored, as this minimum ensures sufficient gas for internal audits and computations required to process the callback. ::: ### Direct Transfers -To directly fund your callback contract: +Fund a callback contract: ```bash -cast send $CALLBACK_ADDR --rpc-url $DESTINATION_RPC --private-key $DESTINATION_PRIVATE_KEY --value 0.1ether +cast send $CALLBACK_ADDR \ + --rpc-url $DESTINATION_RPC \ + --private-key $DESTINATION_PRIVATE_KEY \ + --value 0.1ether ``` -Then, settle any outstanding debt with `coverDebt()`: +Then settle outstanding debt: ```bash -cast send --rpc-url $DESTINATION_RPC --private-key $DESTINATION_PRIVATE_KEY $CALLBACK_ADDR "coverDebt()" +cast send \ + --rpc-url $DESTINATION_RPC \ + --private-key $DESTINATION_PRIVATE_KEY \ + $CALLBACK_ADDR "coverDebt()" ``` -### Depositing via Callback Proxy +### Callback Proxy Deposits -The `depositTo()` method allows callback contracts to be funded via the callback proxy. The fee is covered by the sender (EOA), and the proxy automatically settles any debt. +Callback contracts can be funded through the callback proxy using `depositTo()`. Debt is settled automatically. ```bash -cast send --rpc-url $DESTINATION_RPC --private-key $DESTINATION_PRIVATE_KEY $CALLBACK_PROXY_ADDR "depositTo(address)" $CALLBACK_ADDR --value 0.1ether +cast send \ + --rpc-url $DESTINATION_RPC \ + --private-key $DESTINATION_PRIVATE_KEY \ + $CALLBACK_PROXY_ADDR "depositTo(address)" \ + $CALLBACK_ADDR \ + --value 0.1ether ``` :::tip[On-The-Spot Payment] -Implementing the `pay()` method or inheriting from `AbstractPayer` enables automatic settlement. The callback proxy triggers `pay()` when a callback results in contract debt. The standard implementation verifies the caller is the proxy, checks for sufficient funds, and then settles the debt. +Implementing `pay()` or inheriting from `AbstractPayer` enables automatic settlement. The callback proxy calls `pay()` when a callback creates debt. The standard implementation verifies the caller, checks balances, and settles the debt. ::: ## Callback Contract Balance -### Contract Balance +### Balance -To retrieve the balance of a callback contract, run: +Retrieve the balance of a callback contract: ```bash cast balance $CONTRACT_ADDR --rpc-url $DESTINATION_RPC ``` -### Contract Debt +### Debt -To query the debt of a callback contract as recorded by the callback proxy, run: +Query the debt recorded by the callback proxy: ```bash cast call $CALLBACK_PROXY_ADDR "debts(address)" $CONTRACT_ADDR --rpc-url $DESTINATION_RPC | cast to-dec ``` -### Contract Reserves +### Reserves -To retrieve the reserve amount of a callback contract held by the callback proxy, run: +Retrieve reserves held by the callback proxy: ```bash cast call $CALLBACK_PROXY_ADDR "reserves(address)" $CONTRACT_ADDR --rpc-url $DESTINATION_RPC | cast to-dec ``` -## Reactive Balance +## Reactive Contract Balance -### Contract Balance +### Balance -To retrieve the balance of a reactive contract in REACT, run: +Retrieve the REACT balance of a reactive contract: ```bash cast balance $CONTRACT_ADDR --rpc-url $REACTIVE_RPC ``` -### Contract Debt +### Debt -To query the debt of a reactive contract as recorded by the system contract, run: +Query the debt recorded by the system contract: ```bash cast call $SYSTEM_CONTRACT_ADDR "debts(address)" $CONTRACT_ADDR --rpc-url $REACTIVE_RPC | cast to-dec ``` -### Contract Reserves +### Reserves -To retrieve the reserve amount of a reactive contract held by the system contract, run: +Retrieve reserves held by the system contract: ```bash cast call $SYSTEM_CONTRACT_ADDR "reserves(address)" $CONTRACT_ADDR --rpc-url $REACTIVE_RPC | cast to-dec diff --git a/docs/docs/events-and-callbacks.md b/docs/docs/events-and-callbacks.md index 4acc3e3..6fd9142 100644 --- a/docs/docs/events-and-callbacks.md +++ b/docs/docs/events-and-callbacks.md @@ -1,7 +1,7 @@ --- title: Events & Callbacks sidebar_position: 9 -description: Explore how EVM events and callbacks operate within the Reactive Network. +description: Learn how Reactive Contracts process events and trigger cross-chain callback transactions. slug: /events-&-callbacks hide_title: true --- @@ -10,13 +10,15 @@ hide_title: true ## Overview -In the Reactive Network, reactive contracts operate within isolated environments known as [ReactVMs](./reactvm.md). These contracts can process incoming events, create transactions on destination chains, and use callbacks to communicate between networks. +Reactive Contracts process on-chain events and trigger transactions on destination chains through callbacks. Contracts run inside isolated environments called [ReactVMs](./reactvm.md), where incoming events are processed and callback transactions are generated when conditions are met. ## Event Processing -To handle incoming events, a reactive contract must implement the [IReactive](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/IReactive.sol) interface. +To process events, a Reactive Contract must implement the `react()` function defined in the [IReactive](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/IReactive.sol) interface: ```solidity +// SPDX-License-Identifier: UNLICENSED + pragma solidity >=0.8.0; import './IPayer.sol'; @@ -36,42 +38,22 @@ interface IReactive is IPayer { uint256 tx_hash; uint256 log_index; } - - event Callback( - uint256 indexed chain_id, - address indexed _contract, - uint64 indexed gas_limit, - bytes payload - ); - - function react(LogRecord calldata log) external; + ... } ``` -The Reactive Network feeds events matching a contract's subscriptions by triggering this method. Reactive contracts can access all EVM capabilities but are limited to executing within a private ReactVM tied to the deployer's address, preventing interaction with contracts deployed by others. Below is the `react()` function of the [Basic Reactive Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/basic): +Reactive Network calls `react()` whenever a subscribed event is detected. The `LogRecord` structure contains the event metadata, including chain ID, contract address, topics, and event data. -```solidity -// State specific to reactive network instance of the contract -address private _callback; +Reactive Contracts execute inside a private ReactVM associated with the deployer's address. Contracts inside one ReactVM **can't** interact directly with contracts deployed by other users. -// State specific to ReactVM instance of the contract -uint256 public counter; +Below is an example `react()` function from the [Basic Reactive Demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/basic/BasicDemoReactiveContract.sol): +```solidity function react(LogRecord calldata log) external vmOnly { - emit Event( - log.chain_id, - log._contract, - log.topic_0, - log.topic_1, - log.topic_2, - log.topic_3, - log.data, - ++counter - ); - - if (log.topic_3 >= 0.01 ether) { + + if (log.topic_3 >= 0.001 ether) { bytes memory payload = abi.encodeWithSignature("callback(address)", address(0)); - emit Callback(log.chain_id, _callback, GAS_LIMIT, payload); + emit Callback(destinationChainId, callback, GAS_LIMIT, payload); } } ``` @@ -80,7 +62,7 @@ function react(LogRecord calldata log) external vmOnly { ## Callbacks to Destination Chains -Reactive contracts can initiate transactions on destination chains by emitting structured log records. The format of the log event is as follows: +Reactive Contracts initiate transactions on destination chains by emitting `Callback` events, which are also part of the [IReactive](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/IReactive.sol) interface: ```solidity event Callback( @@ -91,15 +73,20 @@ event Callback( ); ``` -When the Reactive Network detects this event in the transaction trace, it submits a new transaction to the specified destination network, using the `chain_id`. +When this event appears in the transaction trace, Reactive Network submits a transaction to the specified destination chain. + +- **chain_id** — destination network +- **_contract** — target contract +- **gas_limit** — execution gas limit +- **payload** — encoded function call -:::info[Authorization] -The Reactive Network automatically replaces the first 160 bits of the call arguments in the `payload` with the ReactVM ID (equivalent to the contract deployer's address). As a result, the first argument in your callback will always be the ReactVM address (of type `address`), regardless of the variable name you use in your Solidity code. This ensures that the transaction is authorized and tied to the correct contract within the network. +:::info[Callback Authorization] +Reactive Network automatically replaces the first 160 bits of the callback payload with the ReactVM ID (the deployer's address). As a result, the first callback argument is always the ReactVM address (`address` type), regardless of how it is named in Solidity. This ensures that callbacks are tied to the correct Reactive Contract. ::: ### Example: Uniswap Stop Order Demo -Here’s how the Uniswap Stop Order Demo uses this feature: +Example callback payload construction from the [Uniswap Stop Order Reactive Contract](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/uniswap-v2-stop-order/UniswapDemoStopOrderReactive.sol): ```solidity bytes memory payload = abi.encodeWithSignature( @@ -111,10 +98,11 @@ bytes memory payload = abi.encodeWithSignature( coefficient, threshold ); -emit Callback(chain_id, stop_order, CALLBACK_GAS_LIMIT, payload); +triggered = true; +emit Callback(log.chain_id, stop_order, CALLBACK_GAS_LIMIT, payload); ``` -The payload encodes the function signature and parameters needed for the stop order. The `Callback` event is emitted with the destination chain ID, target contract, gas limit, and the constructed payload. +The payload encodes the function call and parameters that will be executed on the destination chain. [More on Callback Payment →](./economy#callback-payment) diff --git a/docs/docs/hyperlane.mdx b/docs/docs/hyperlane.mdx index a4e2d7c..ed91e9f 100644 --- a/docs/docs/hyperlane.mdx +++ b/docs/docs/hyperlane.mdx @@ -1,23 +1,24 @@ --- title: Hyperlane sidebar_position: 3 -description: Discover Hyperlane mailboxes as alternative transport to callback proxy contracts for providing cross-chain communication. +description: Learn how to use Hyperlane Mailboxes as an alternative transport for cross-chain callbacks in Reactive Contracts. slug: /hyperlane hide_title: true --- import MailboxAddressTable from "../../src/components/hyperlane-mailbox-table"; -import TransportComparisonTable from "../../src/components/hyperlane-comparison"; ![Hyperlane Image](./img/hyperlane.jpg) ## Overview -An alternative to Reactive transport can be Hyperlane Mailboxes. Hyperlane is a modular interoperability protocol for cross-chain messaging. Its core component, the Mailbox contract, is deployed on each supported blockchain. The Mailbox acts as both the entry and exit point for cross-chain messages, allowing smart contracts to transmit and receive data across networks. +Reactive Contracts send **cross-chain callback transactions** to destination chains. By default, callbacks are delivered through the Reactive **Callback Proxy**. Hyperlane Mailboxes provide an alternative transport for these callbacks. The Mailbox contract on each supported chain acts as the entry and exit point for cross-chain messages. -## Hyperlane/Reactive Transport Comparison +Reactive Contracts still listen to event logs and trigger actions in the same way, only the callback transport changes. Hyperlane transport is useful when: - +- A chain does not yet support the Callback Proxy +- You need additional routing flexibility +- You want to integrate Reactive Contracts with existing Hyperlane-based systems ## Hyperlane Mailboxes diff --git a/docs/docs/index.md b/docs/docs/index.md index a101fa2..f6f396d 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -1,7 +1,7 @@ --- sidebar_position: 1 title: Getting Started -description: Explore Reactive Network, an EVM-compatible layer for advanced dApps. Learn about Reactive Contracts that use data flows from multiple blockchains. Get started with setup, development and testing, and our unique architecture. +description: Explore Reactive Network — an automation layer for EVM chains. Build Reactive Contracts — event-driven smart contracts for cross-chain, on-chain automation. slug: / hide_title: true --- @@ -10,47 +10,55 @@ hide_title: true ## Overview -The Reactive Network is an EVM-compatible execution layer that allows developers to create dApps using reactive contracts. These contracts differ from traditional smart contracts by using inversion-of-control for the transaction lifecycle, driven by data flows across blockchains rather than user input. +Reactive Network is an EVM-compatible chain built around Reactive Contracts (RCs) — event-driven smart contracts for cross-chain, on-chain automation. -Reactive contracts receive event logs from various chains, executing Solidity logic based on these events instead of user transactions. They can independently determine the need to transmit data to destination chains, enabling conditional state changes. The Reactive Network offers fast and cost-effective computation through a proprietary parallelized EVM implementation. +Reactive Contracts monitor event logs across EVM chains and execute Solidity logic automatically when conditions are met. Instead of waiting for users or bots to trigger transactions, RCs run continuously and decide when to send cross-chain callback transactions — essentially providing **if-this-then-that automation for smart contracts**. + +This makes it possible to build conditional cross-chain workflows such as: + +* Automated stop-loss and take-profit orders +* Liquidation protection +* Automated portfolio rebalancing +* Yield optimization +* Cross-chain workflows ## Step 1 — Reactive Basics -[Origins & Destinations →](./origins-and-destinations.mdx) Check on Reactive's origins and destinations, along with their Callback Proxy addresses. +[Origins & Destinations →](./origins-and-destinations.mdx) Understand origin and destination chains and their Callback Proxy addresses. -[Hyperlane →](./hyperlane.mdx) Explore an alternative transport system for callbacks like Hyperlane. +[Hyperlane →](./hyperlane.mdx) Learn how cross-chain callbacks are transported using Hyperlane. -[Reactive Contracts →](./reactive-contracts.md) Understand the core concept of reactive contracts. +[Reactive Contracts →](./reactive-contracts.md) Learn how Reactive Contracts subscribe to events and trigger actions. -[ReactVM →](./reactvm.md) Learn about ReactVM and its purpose. +[ReactVM →](./reactvm.md) Understand ReactVM and how Reactive execution works. -[Economy →](./economy) Explore the Reactive Network's economy and callback payment mechanism. +[Economy →](./economy) Understand callback payments and Reactive's economy. ## Step 2 — Reactive Essentials [Reactive Mainnet & Lasna Testnet →](./reactive-mainnet.mdx) Connect to Reactive Mainnet or Lasna Testnet. -[Reactive Library →](./reactive-lib.mdx) Implement abstract contracts and interfaces in your project. +[Reactive Library →](./reactive-lib.mdx) Use Reactive abstract contracts and interfaces. -[Events & Callbacks →](./events-and-callbacks.md#callbacks-to-destination-chains) Read up on how to work with events and callbacks in reactive contracts. +[Events & Callbacks →](./events-and-callbacks.md) Learn how event subscriptions trigger cross-chain callbacks. -[Subscriptions →](./subscriptions.md) Set up and manage subscriptions. +[Subscriptions →](./subscriptions.md) Configure event subscriptions. -[RNK RPC Methods →](./rnk-rpc-methods.md) Key RPC methods for the Reactive Network's Geth version. +[RNK RPC Methods →](./rnk-rpc-methods.md) Reference RPC methods for Reactive nodes. ## Step 3 — Reactive Building -[Reactive Demos →](./demos.md) Hands-on demonstrations for the Reactive Network. +[Reactive Demos →](./demos.md) Explore working examples. -[Reactive Demos on GitHub →](https://github.com/Reactive-Network/reactive-smart-contract-demos) Clone the GitHub project and start building. +[Reactive Demos on GitHub →](https://github.com/Reactive-Network/reactive-smart-contract-demos) Clone demo projects and start building. ## Extra -[Reactscan →](./reactscan.md) Learn to navigate the Reactive block explorer. +[Reactscan →](./reactscan.md) Explore Reactive transactions and contracts. -[Reactive Education →](../education/introduction/index.md) Begin a Reactive Tech education course. +[Reactive Education →](../education/introduction/index.md) Take the Reactive technical course. -[Debugging →](debugging.md) Debug errors and issues related to Reactive and beyond. +[Debugging →](debugging.md) Troubleshoot common issues. -[Contacts →](../contacts/index.md) Reach out via socials for technical or trading inquiries. +[Contacts →](../contacts/index.md) Get support and connect with the community. diff --git a/docs/docs/origins-and-destinations.mdx b/docs/docs/origins-and-destinations.mdx index 2c093e1..91b72bb 100644 --- a/docs/docs/origins-and-destinations.mdx +++ b/docs/docs/origins-and-destinations.mdx @@ -1,7 +1,7 @@ --- title: Origins & Destinations sidebar_position: 2 -description: Discover how Reactive Network manages event streams and transactions across different ecosystems and learn about network compatibility. +description: Learn how Reactive Contracts subscribe to event logs on origin chains and send callback transactions to destination chains. slug: /origins-and-destinations hide_title: true --- @@ -13,22 +13,30 @@ import TestnetChainTable from "../../src/components/origins-destinations-testnet ## Overview -The Reactive Network reads event streams and enables transactions across different ecosystems. An Origin acts as an event log provider, delivering events to reactive contracts within the Reactive Network. A Destination is the ecosystem where the actual state transition (transaction) takes place. +Reactive Contracts (RCs) can **listen to event logs on one chain** and **trigger actions on another**. To describe that flow, we use two roles: -Origins and destinations don't have to be the same. Reactive contracts can be configured to work with multiple origins, and the system allows for multiple destinations, enabling conditional selection of which destination ecosystem will be used. +- **Origin** — the chain where events happen and event logs are read from (the event source). +- **Destination** — the chain where Reactive Network delivers a callback transaction (the chain where state changes happen). + +Origins and destinations don’t have to be the same. A single Reactive Contract can subscribe to events from multiple origin chains, and it can send callbacks to one or more destination chains. Your Solidity logic can also choose the destination conditionally. ## Callback Proxy Address -The Callback Proxy address ensures the validity of a callback transaction by enforcing two key conditions. First, it checks that the callback is genuinely initiated by the Reactive Network by verifying that the sender address matches the Callback Proxy address. Then, it confirms the legitimacy of the callback’s origin by checking the RVM ID embedded in the transaction payload, which should correspond to the intended reactive contract. +Callbacks are delivered to destination chains via a **Callback Proxy** contract. Its job is to make callback transactions verifiable and safe for destination-side contracts. + +A destination contract can validate a callback by checking: + +1. **The sender is the Callback Proxy** (so the call is coming through the expected entry point). +2. **The embedded RVM ID matches the intended Reactive Contract** (so the callback is tied to the correct RC). :::info[Hyperlane] -Some networks are currently unable to act as destination chains because the callback proxy contract has not yet been deployed on them. In such cases, it is recommended to use [Hyperlane](./hyperlane) as the cross-chain message relayer. +Some networks can’t act as destination chains yet because the Callback Proxy contract hasn’t been deployed there. In that case, use [Hyperlane](./hyperlane) as the transport for cross-chain callbacks. ::: ## Mainnet Chains :::info[Origin/Destination] -Origin is the chain where events originate and are read from. Destination is the chain where callbacks are delivered in response to those events. Mainnets and testnets must not be mixed. If origin is a mainnet, destination must also be a mainnet. +Origin is the chain where events originate (and are read from). Destination is the chain where callbacks are delivered in response to those events. Mainnets and testnets must not be mixed: if the origin is a mainnet, the destination must also be a mainnet. ::: @@ -36,7 +44,7 @@ Origin is the chain where events originate and are read from. Destination is the ## Testnet Chains :::info[Origin/Destination] -Origin is the chain where events originate and are read from. Destination is the chain where callbacks are delivered in response to those events. Mainnets and testnets must not be mixed. If origin is a testnet, destination must also be a testnet. +Origin is the chain where events originate (and are read from). Destination is the chain where callbacks are delivered in response to those events. Mainnets and testnets must not be mixed: if the origin is a testnet, the destination must also be a testnet. ::: diff --git a/docs/docs/reactive-contracts.md b/docs/docs/reactive-contracts.md index 1d63b13..bdc16df 100644 --- a/docs/docs/reactive-contracts.md +++ b/docs/docs/reactive-contracts.md @@ -1,7 +1,7 @@ --- title: Reactive Contracts sidebar_position: 4 -description: Explore Reactive Contracts, which enable event-driven interactions and transaction creation. Learn their setup, processing, and applications through clear examples. +description: Learn about Reactive Contracts (RCs) — event-driven smart contracts for cross-chain, on-chain automation that monitor event logs and trigger callback transactions. slug: /reactive-contracts hide_title: true --- @@ -10,35 +10,35 @@ hide_title: true ## Overview -Reactive Contracts (RCs) operate on a standard Ethereum Virtual Machine (EVM) and can be written in any EVM-compatible language, with Application Binary Interfaces (ABIs) particularly customized for Solidity. Their unique capabilities stem from Reactive nodes and a specialized pre-deployed system contract. +Reactive Contracts (RCs) are event-driven smart contracts for cross-chain, on-chain automation. They monitor event logs across EVM chains, execute Solidity logic when subscribed events occur, and can trigger cross-chain callback transactions. -## Key Features +RCs define which chains, contracts, and events to monitor and operate autonomously based on on-chain events rather than user transactions or bots. -Reactive Contracts monitor blockchains for specific events and respond automatically, unlike traditional contracts that rely on EOAs to trigger actions. This reactivity and their use of Inversion of Control (IoC) — where contracts decide when to act — set them apart. +## Deployment -RCs define which blockchains, contracts, and events to watch. When a relevant event occurs, they execute logic, update state, and perform trustless transactions within the Reactive Network. +Reactive Contracts deploy in two environments: -### Deployment +- **Reactive Network (RNK)** — the public chain where EOAs interact with the contract and subscriptions are managed -RCs deploy to both the main Reactive Network and a private [ReactVM](./reactvm.md). The main copy interacts with EOAs and manages subscriptions via the system contract. The ReactVM copy handles event processing but is not accessible to EOAs. +- **ReactVM (RVM)** — a private execution environment where event processing takes place -### State and Separation +Both copies use identical bytecode but operate independently. -The two copies are isolated and don’t share state. Since they use the same bytecode, use constructor flags or checks to distinguish the environment. You can detect if a contract is on ReactVM by calling the system contract — calls will revert outside ReactVMs. See [examples](./demos.md) for details. +## State Separation -### ReactVM Limitations +The two deployments do not share state. Constructor flags or runtime checks can be used to distinguish environments. A contract can detect execution inside ReactVM by calling the system contract — calls revert outside ReactVM. See our [demos](./demos.md) for details. -In [ReactVM](./reactvm.md), RCs can’t access external systems directly. They receive logs from the Reactive Network and can call destination chain contracts but nothing else. +## ReactVM Limitations -## Contract Verification +Inside [ReactVM](./reactvm.md), Reactive Contracts can't access external systems directly. They receive event logs from Reactive Network and can send callback transactions to destination chains, but can't interact with external RPC endpoints or off-chain services. -Contracts can be verified either after or during deployment with the Sourcify endpoint. Sourcify is a decentralized verification service that stores and verifies source code for smart contracts. It allows anyone to match deployed bytecode with human-readable source code, making smart contracts auditable and transparent. +## Verifying Reactive Contracts -**Reactive Sourcify Endpoint**: https://sourcify.rnk.dev/ +Contracts can be verified during or after deployment using the Sourcify endpoint. Sourcify is a decentralized verification service that matches deployed bytecode with source code, making contracts auditable and transparent. -### Verify After Deployment +**Reactive Sourcify Endpoint**: https://sourcify.rnk.dev/ -For contract verification after deployment, run the following command: +## Verify After Deployment ```bash forge verify-contract \ @@ -48,15 +48,13 @@ forge verify-contract \ $CONTRACT_ADDR $CONTRACT_NAME ``` -**Replace:** +Replace: -- `$CHAIN_ID` with `1597` for Reactive Mainnet and `5318007` for Lasna Testnet -- `$CONTRACT_ADDR` with your deployed contract’s address -- `$CONTRACT_NAME` with the name of the contract (e.g., `MyContract`) +- `$CHAIN_ID` → `1597` (Reactive Mainnet) or `5318007` (Lasna Testnet) +- `$CONTRACT_ADDR` → deployed contract address +- `$CONTRACT_NAME` → contract name (e.g. `MyContract`) -### Verify on Deployment - -You can also verify the contract during deployment by appending the relevant flags to `forge create`. The following command submits your contract source to Sourcify right after deployment: +## Verify on Deployment ```bash forge create \ @@ -68,13 +66,13 @@ forge create \ $PATH ``` -**Replace:** +Replace: -- `$CHAIN_ID` with `1597` for Reactive Mainnet and `5318007` for Lasna Testnet -- `$PATH` with something like `src/MyContract.sol:MyContract` -- `$PRIVATE_KEY` with your signer’s private key +- `$CHAIN_ID` → `1597` (Reactive Mainnet) or `5318007` (Lasna Testnet) +- `$PATH` → e.g. `src/MyContract.sol:MyContract` +- `$PRIVATE_KEY` → deployer key -An example of verifying on deployment could look like so: +Example: ```bash forge create \ @@ -95,26 +93,29 @@ forge create \ ``` :::warning[Broadcast Error] -If you encounter the error described below, it means your Foundry version (or local setup) does not expect the `--broadcast flag` for `forge create`. Simply remove `--broadcast` from your command and re-run it. +If you encounter the error below, your Foundry version doesn't expect the `--broadcast` flag for `forge create`. Remove `--broadcast` and retry. ```go error: unexpected argument '--broadcast' found ``` ::: -### Verified Contracts on Reactscan +## Verified Contracts on Reactscan + +After verification: -**Reactive Block Explorers:** [Mainnet](https://reactscan.net/) and [Lasna Testnet](https://lasna.reactscan.net/). +1. Open Reactscan ([Reactive Mainnet](https://reactscan.net/), [Lasna Testnet](https://lasna.reactscan.net/)) +2. Navigate to your RVM +3. Open Contracts -After verification, go to the relevant **Reactscan.** While in your RVM, navigate to **Contracts** and click the required contract address. ![Image a](./img/verify-a.png) -Open the “Contract” tab. +4. Select the contract address ![Image b](./img/verify-b.png) -If successful, you’ll see the following: +Successful verification shows: ```json Contract Address: 0xc3e185561D2a8b04F0Fcd104A562f460D6cC503c @@ -124,6 +125,6 @@ Compiler: 0.8.28 ![Image c](./img/verify-c.png) -The source code will be publicly viewable, with full syntax highlighting and structure, helping others understand and trust the contract logic. +Verified contracts expose full source code with syntax highlighting and file structure. [More on Reactive Contracts →](../education/module-1/reactive-contracts) diff --git a/docs/docs/reactive-lib.mdx b/docs/docs/reactive-lib.mdx index 99a077b..ca7726c 100644 --- a/docs/docs/reactive-lib.mdx +++ b/docs/docs/reactive-lib.mdx @@ -1,7 +1,7 @@ --- title: Reactive Library sidebar_position: 8 -description: Explore the core functionality of Reactive library – abstract contracts and interfaces +description: Reference for the Reactive Library — abstract contracts and interfaces for building Reactive Contracts. slug: /reactive-library hide_title: true --- @@ -12,7 +12,9 @@ import CronTable from "../../src/components/cron-table"; ## Overview -[Reactive Library](https://github.com/Reactive-Network/reactive-lib) is a set of abstract contracts and interfaces that reduce boilerplate by integrating common functionalities. Run the following command in your project to install the library: +[Reactive Library](https://github.com/Reactive-Network/reactive-lib) provides abstract contracts and interfaces for building Reactive Contracts. The library includes components for subscriptions, callbacks, payments, and system contract interaction. + +Install the library in your Foundry project: ```bash forge install Reactive-Network/reactive-lib @@ -22,16 +24,23 @@ forge install Reactive-Network/reactive-lib ### AbstractCallback -[AbstractCallback](https://github.com/Reactive-Network/reactive-lib/blob/main/src/abstract-base/AbstractCallback.sol) extends `AbstractPayer` and provides a callback system. It initializes a specific `rvm_id` and a `vendor` in the constructor to enable callback functionality. The `rvm_id` ensures that only an authorized RVM ID can invoke certain functions, enforced by the `rvmIdOnly` modifier. +[AbstractCallback](https://github.com/Reactive-Network/reactive-lib/blob/main/src/abstract-base/AbstractCallback.sol) extends `AbstractPayer.sol` and provides callback authorization for Reactive Contracts. + +The contract initializes: + +- `rvm_id` — authorized ReactVM identifier +- `vendor` — callback proxy address + +The `rvmIdOnly` modifier restricts functions to the authorized ReactVM. ```solidity - modifier rvmIdOnly(address _rvm_id) { - require(rvm_id == address(0) || rvm_id == _rvm_id, 'Authorized RVM ID only'); - _; +modifier rvmIdOnly(address _rvm_id) { + require(rvm_id == address(0) || rvm_id == _rvm_id, 'Authorized RVM ID only'); + _; } ``` -The constructor accepts the Callback Proxy address (`_callback_sender`), which is assigned to the `vendor` variable. The `rvm_id` is initialized as the address deploying the contract (`msg.sender`). The constructor also authorizes the `_callback_sender` by interacting with `AbstractPayer`. +The constructor sets the deploying ReactVM as the authorized `rvm_id` and registers the callback proxy as an authorized payment sender. ```solidity constructor(address _callback_sender) { @@ -43,11 +52,18 @@ constructor(address _callback_sender) { ### AbstractPausableReactive -[AbstractPausableReactive](https://github.com/Reactive-Network/reactive-lib/blob/main/src/abstract-base/AbstractPausableReactive.sol) combines functionalities from `IReactive` and `AbstractReactive` for managing pausable event subscriptions. It introduces a `Subscription` struct, which defines criteria for subscriptions, including chain ID, contract address, and event topics. +[AbstractPausableReactive](https://github.com/Reactive-Network/reactive-lib/blob/main/src/abstract-base/AbstractPausableReactive.sol) extends `AbstractReactive.sol` and provides pausable event subscriptions. -The contract includes mechanisms to pause and resume all active subscriptions. The `pause` function unsubscribes from all subscriptions retrieved through the `getPausableSubscriptions` function, while the `resume` function reactivates them. These operations are restricted to the contract owner, with access controlled by the `onlyOwner` modifier. +Subscriptions are defined using the `Subscription` struct, which specifies chain ID, contract address, and event topics. -The constructor assigns the deploying address (`msg.sender`) as the owner and initializes the contract in an unpaused state. +The contract provides: + +- `pause()` — unsubscribes all pausable subscriptions +- `resume()` — restores subscriptions + +Access is restricted to the contract owner. + +The constructor sets the deployer as the owner. ```solidity constructor() { @@ -55,7 +71,7 @@ constructor() { } ``` -The `pause` function ensures that only the owner can deactivate subscriptions when the contract is not already paused: +The `pause()` function unsubscribes all subscriptions returned by `getPausableSubscriptions()`: ```solidity function pause() external rnOnly onlyOwner { @@ -75,7 +91,7 @@ function pause() external rnOnly onlyOwner { } ``` -Similarly, the `resume` function reactivates subscriptions when the contract is paused: +The `resume()` function restores the same subscriptions: ```solidity function resume() external rnOnly onlyOwner { @@ -97,7 +113,15 @@ function resume() external rnOnly onlyOwner { ### AbstractPayer -[AbstractPayer](https://github.com/Reactive-Network/reactive-lib/blob/main/src/abstract-base/AbstractPayer.sol) provides payment-related functionality for smart contracts. It manages a mapping of authorized senders and defines mechanisms for initiating payments or covering vendor debts. The `authorizedSenderOnly` modifier restricts payment initiation to senders explicitly authorized by the contract. +[AbstractPayer](https://github.com/Reactive-Network/reactive-lib/blob/main/src/abstract-base/AbstractPayer.sol) provides payment and debt-settlement functionality for Reactive Contracts. + +Features include: + +- Authorized payment senders +- Vendor debt settlement +- Direct contract funding + +The `authorizedSenderOnly` modifier restricts payment initiation to authorized senders. ```solidity modifier authorizedSenderOnly() { @@ -106,7 +130,10 @@ modifier authorizedSenderOnly() { } ``` -The contract includes a `pay` function, which allows authorized senders to transfer a specified amount, and a `coverDebt` function, which retrieves the outstanding debt of the contract to the vendor and attempts to settle it. The `vendor` is defined as an instance of the `IPayable` interface, enabling interactions with external systems for debt management. Payments are processed through an internal `_pay` function, which validates the contract's balance before executing a transfer. +The contract provides: + +- `pay()` — transfers funds to the authorized sender +- `coverDebt()` — settles outstanding vendor debt ```solidity function pay(uint256 amount) external authorizedSenderOnly { @@ -127,7 +154,7 @@ function _pay(address payable recipient, uint256 amount) internal { } ``` -Authorized senders are managed through `addAuthorizedSender` and `removeAuthorizedSender` functions, ensuring control over who can initiate payments. +Authorized senders are managed with: ```solidity function addAuthorizedSender(address sender) internal { @@ -139,7 +166,7 @@ function removeAuthorizedSender(address sender) internal { } ``` -The contract also supports receiving Ether, using an empty `receive` function to handle direct transfers. +The contract accepts direct transfers: ```solidity receive() virtual external payable { @@ -148,9 +175,16 @@ receive() virtual external payable { ### AbstractReactive -[AbstractReactive](https://github.com/Reactive-Network/reactive-lib/blob/main/src/abstract-base/AbstractReactive.sol) extends `AbstractPayer` and implements `IReactive`, providing functionality for interacting with the Reactive Network and system contracts. It introduces two distinct operational modes: `vm` for reactVM and non-`vm` for the Reactive Network, ensuring that certain functions are executed in the appropriate mode. The `vmOnly` and `rnOnly` modifiers enforce these mode restrictions. +[AbstractReactive](https://github.com/Reactive-Network/reactive-lib/blob/main/src/abstract-base/AbstractReactive.sol) is the base contract for Reactive Contracts. It extends `AbstractPayer.sol` and implements `IReactive.sol`, providing access to the Reactive Network system contract and subscription service. + +The contract defines two execution modes: -The contract uses an internal mechanism, `detectVm()`, to dynamically detect whether it is running in a ReactVM context or within the Reactive Network. This detection is based on the contract size of the `SERVICE_ADDR` system contract, which is predefined and used to assign the `vendor` and `service` variables automatically. The address of `SERVICE_ADDR` is set in the constructor and authorized as a sender for payment-related actions. +- `vmOnly` — ReactVM execution +- `rnOnly` — Reactive Network execution + +These modes ensure functions run in the appropriate environment. + +The constructor initializes the system contract as both the payment vendor and subscription service, and authorizes it for payment operations. ```solidity constructor() { @@ -160,7 +194,7 @@ constructor() { } ``` -The `detectVm` function inspects the size of the `SERVICE_ADDR` contract to determine the current execution context, setting the `vm` flag accordingly: +Execution mode is determined automatically using `detectVm()`, which checks whether the system contract is deployed. ```solidity function detectVm() internal { @@ -175,23 +209,25 @@ function detectVm() internal { ### IPayable -The [IPayable](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/IPayable.sol) interface defines functionalities for handling payments and debt management. The `receive` function enables contracts to accept Ether payments directly, allowing them to settle debts and resume subscriptions as necessary. +[IPayable](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/IPayable.sol) defines payment and debt-query functionality for Reactive Contracts. -Additionally, the `debt` function provides a way for reactive contracts to query their outstanding debts. It takes the address of a reactive contract as input and returns the amount of debt owed, enabling precise debt tracking and efficient fund management. +- `receive()` — accepts direct payments +- `debt()` — returns the outstanding debt of a contract ```solidity interface IPayable { receive() external payable; - + function debt(address _contract) external view returns (uint256); } ``` ### IPayer -The [IPayer](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/IPayer.sol) interface defines a minimal contract for managing payments within the Reactive Network. It ensures that implementing contracts can both initiate payments and accept Ether directly. +[IPayer](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/IPayer.sol) defines a minimal interface for initiating payments and receiving funds. -The `pay()` function allows the calling contract to make a payment of the specified `amount`. This function is external and is designed to verify the `msg.sender` to ensure that only authorized entities can initiate payments. The `receive()` function allows the implementing contract to accept Ether transfers directly. The function is automatically invoked when the contract receives Ether with no accompanying calldata. +- `pay()` — initiates a payment +- `receive()` — accepts direct transfers ```solidity interface IPayer { @@ -203,9 +239,9 @@ interface IPayer { ### IReactive -The [IReactive](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/IReactive.sol) interface extends the `IPayer` interface, enabling reactive contracts to integrate with the Reactive Network. It facilitates event-driven interactions by allowing contracts to subscribe to specific criteria and handle notifications for matching events. This interface defines core structures, events, and functions required for reactive contracts. +[IReactive](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/IReactive.sol) defines the core interface for Reactive Contracts. It extends `IPayer.sol` and provides event notifications and the execution entry point. -The `LogRecord` struct represents detailed information about an event notification. It includes metadata such as chain ID, contract address, topics, data, block details, and transaction identifiers, making it a container for event data. +The `LogRecord` struct contains event data delivered to the contract. ```solidity struct LogRecord { @@ -224,7 +260,7 @@ struct LogRecord { } ``` -The `Callback` event is emitted when a reactive contract is notified of a new event matching its subscription criteria. It provides key details about the event, such as the chain ID, the originating contract, the gas limit for processing the callback, and the payload data. +The `Callback` event is emitted when a Reactive Contract triggers a callback transaction. ```solidity event Callback( @@ -235,7 +271,7 @@ event Callback( ); ``` -The `react` function serves as the entry point for handling event notifications. It processes the `LogRecord` data associated with an event and executes the necessary logic within the contract. +The `react()` function processes event notifications. ```solidity function react(LogRecord calldata log) external; @@ -243,9 +279,9 @@ function react(LogRecord calldata log) external; ### ISubscriptionService -The [ISubscriptionService](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/ISubscriptionService.sol) interface extends `IPayable` and provides methods for reactive contracts to create or remove subscriptions, specifying detailed criteria for the events they want to monitor. +[ISubscriptionService](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/ISubscriptionService.sol) defines functions for managing event subscriptions. It extends `IPayable.sol` and allows Reactive Contracts to subscribe to or unsubscribe from event logs. -The `subscribe()` function enables a contract to subscribe to receive events that match specified criteria. +The `subscribe()` function registers a subscription with the specified event criteria. ```solidity function subscribe( @@ -258,7 +294,7 @@ function subscribe( ) external; ``` -The `unsubscribe` function removes an existing subscription matching the specified criteria, if one exists. +The `unsubscribe()` function removes a subscription matching the specified criteria. ```solidity function unsubscribe( @@ -273,7 +309,7 @@ function unsubscribe( ### ISystemContract -The [ISystemContract](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/ISystemContract.sol) interface acts as an integrative contract that combines the functionalities of `IPayable` and `ISubscriptionService`. It represents a system-level abstraction within the Reactive Network, designed to handle payments and manage event subscriptions for reactive contracts. +[ISystemContract](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/ISystemContract.sol) combines the functionality of `IPayable.sol` and `ISubscriptionService.sol`. It represents the Reactive Network system contract interface used for payments and subscription management. ```solidity import './IPayable.sol'; @@ -285,34 +321,36 @@ interface ISystemContract is IPayable, ISubscriptionService { ## System Contract -The Reactive Network’s key operations are managed by three core contracts: +Reactive Network operations are handled by three core contracts: -[System Contract](https://github.com/Reactive-Network/system-smart-contracts/blob/main/src/SystemContract.sol) oversees: +[System Contract](https://github.com/Reactive-Network/system-smart-contracts/blob/main/src/SystemContract.sol): -- Payments: Handles service payments for reactive contracts. -- Access Control: Manages contract whitelisting/blacklisting. -- Cron Events: Triggers periodic block interval actions. +- Handles payments for Reactive Contracts +- Manages contract access control (whitelist/blacklist) +- Emits cron events for periodic triggers -[Callback Proxy](https://github.com/Reactive-Network/system-smart-contracts/blob/main/src/CallbackProxy.sol) ensures interactions with: +[Callback Proxy](https://github.com/Reactive-Network/system-smart-contracts/blob/main/src/CallbackProxy.sol): -- Callback Management: Restricted to authorized senders. -- Payment & Reserves: Manages deposits, reserves, and debts. -- Gas Adjustment & Kickbacks: Calculates gas prices and rewards originators. -- Access Control: Tracks authorized contracts, emitting whitelist/blacklist updates. +- Delivers callback transactions to destination contracts +- Manages deposits, reserves, and debts +- Restricts callbacks to authorized Reactive Contracts +- Calculates callback gas costs and kickbacks -[AbstractSubscriptionService](https://github.com/Reactive-Network/system-smart-contracts/blob/main/src/AbstractSubscriptionService.sol) manages event subscriptions with: +[AbstractSubscriptionService](https://github.com/Reactive-Network/system-smart-contracts/blob/main/src/AbstractSubscriptionService.sol): -- Flexible Criteria: Subscribes/unsubscribes based on chain ID, address, or topics. -- Recursive Tracking: Supports complex criteria structures. -- Wildcard Support: Uses `REACTIVE_IGNORE` for broader matches. -- Event Emissions: Tracks subscription updates, including deployer events. +- Manages event subscriptions +- Supports filtering by chain, contract, and topics +- Supports wildcard matching via `REACTIVE_IGNORE` +- Emits subscription update events ### CRON Functionality -The `SystemContract` has a built-in cron mechanism that enables time-based automation by emitting events at fixed block intervals. Instead of running continuous on-chain checks, nodes listen for these predictable signals and create transactions to invoke the appropriate cron function when triggered. This native scheduling layer simplifies the creation of automated workflows, on-chain triggers, and off-chain watchers. +The `SystemContract` provides a cron mechanism for time-based automation by emitting events at fixed block intervals. Reactive Contracts can subscribe to these events to implement scheduled execution without polling or external automation. + +Only authorized validator root addresses can call `cron()`. Each call to `cron()` emits one or more `Cron` events depending on the divisibility of the current block number. Larger intervals produce less frequent events. -To maintain the reliability and predictability of this mechanism, only authorized validator root addresses are permitted to trigger the relevant functions. +Each `Cron` event contains a single parameter: -Each call to `cron()` emits one or more `Cron` events based on the divisibility of the provided block number. This forms a pyramid of timing signals, growing less frequent as the interval increases. Each event includes a single parameter: `number`, representing the current block number. +- `number` — the current block number diff --git a/docs/docs/reactive-mainnet.mdx b/docs/docs/reactive-mainnet.mdx index d14be4c..0e5972a 100644 --- a/docs/docs/reactive-mainnet.mdx +++ b/docs/docs/reactive-mainnet.mdx @@ -1,7 +1,7 @@ --- title: Reactive Mainnet / Lasna Testnet sidebar_position: 7 -description: Explore Reactive Mainnet and Lasna Testnet information, a proof-of-stake EVM-compatible chain. +description: RPC endpoints, chain IDs, and faucet instructions for Reactive Mainnet and Lasna Testnet. slug: /reactive-mainnet hide_title: true --- @@ -13,19 +13,22 @@ import LasnaButton from "../../src/components/lasna-button"; ## Overview -Reactive Mainnet is a proof-of-stake blockchain for the Reactive Network. Lasna Testnet serves as a testing environment, allowing developers to test and refine features before deploying them on the mainnet. +Reactive Mainnet is the production network for Reactive Contracts. Lasna Testnet provides a testing environment for development and experimentation before mainnet deployment. :::info[System Contract] -Reactive Mainnet and Lasna Testnet use the same system contract address: `0x0000000000000000000000000000000000fffFfF` +Reactive Mainnet and Lasna Testnet share the same system contract address: +`0x0000000000000000000000000000000000fffFfF` ::: ## Reactive Mainnet -* Network Name — Reactive Mainnet -* RPC URL — https://mainnet-rpc.rnk.dev/ -* Chain ID — 1597 -* Currency Symbol — REACT -* Block Explorer URL — https://reactscan.net/ +Network parameters: + +* **Network Name:** Reactive Mainnet +* **RPC URL:** https://mainnet-rpc.rnk.dev/ +* **Chain ID:** 1597 +* **Currency Symbol:** REACT +* **Block Explorer:** https://reactscan.net/ @@ -35,35 +38,38 @@ Reactive Mainnet and Lasna Testnet use the same system contract address: `0x0000 ### Reactive Faucet -To obtain **testnet REACT (lREACT)**, send **ETH** to one of the Reactive faucet contracts: +To obtain **testnet REACT (lREACT)**, send **ETH** to one of the faucet contracts: ```json -Ethereum Sepolia: 0x9b9BB25f1A81078C544C829c5EB7822d747Cf434 +Ethereum Sepolia: `0x9b9BB25f1A81078C544C829c5EB7822d747Cf434` -Base Sepolia: 0x2afaFD298b23b62760711756088F75B7409f5967 +Base Sepolia: `0x2afaFD298b23b62760711756088F75B7409f5967` ``` -The exchange rate is **1:100** — for each **ETH** sent, you receive **100 lREACT**. You can make the transfer using **MetaMask** or any Ethereum-compatible wallet. +Exchange rate: **1 ETH → 100 lREACT**. + +Transfers can be made using MetaMask or any Ethereum-compatible wallet. :::info[Important] -**Do not** send more than **5 ETH** in a single transaction. -* **Maximum per transaction**: 5 ETH -* **Maximum received**: 500 lREACT -* Any amount above 5 ETH will be **lost** and **will not** generate extra lREACT +Do **not** send more than **5 ETH** per transaction. + +- Maximum sent: **5 ETH** +- Maximum received: **500 lREACT** + +Amounts above 5 ETH are **lost** and will not generate additional lREACT. ::: ### ReacDEFI Swap -You can also swap ETH for lREACT directly using [ReacDEFI](https://reacdefi.app/markets), Reactive’s app: +You can swap ETH for lREACT using [ReacDEFI](https://reacdefi.app/markets#testnet-faucet): -1. Choose how much **lREACT** you want to receive. -2. The app automatically calculates the required **ETH**. -3. Connect an Ethereum/Base Sepolia wallet via MetaMask or Coinbase. -4. Confirm the transaction. +1. Choose the amount of **lREACT** +2. Connect a Sepolia or Base Sepolia wallet +3. Confirm the transaction ### Terminal Request -Alternatively, call the `request(address)` method on one of the Reactive faucet contracts: +You can request lREACT by calling `request(address)` on a faucet contract: ```bash cast send 0x9b9BB25f1A81078C544C829c5EB7822d747Cf434 --rpc-url $ETHEREUM_SEPOLIA_RPC --private-key $ETHEREUM_SEPOLIA_PRIVATE_KEY "request(address)" $CONTRACT_ADDR --value 0.1ether @@ -75,11 +81,13 @@ cast send 0x2afaFD298b23b62760711756088F75B7409f5967 --rpc-url $BASE_SEPOLIA_RPC ## Lasna Testnet -* Network Name — Reactive Lasna -* RPC URL — https://lasna-rpc.rnk.dev/ -* Chain ID — 5318007 -* Currency Symbol — lREACT -* Block Explorer URL — https://lasna.reactscan.net +Network parameters: + +* **Network Name:** Reactive Lasna +* **RPC URL:** https://lasna-rpc.rnk.dev/ +* **Chain ID:** 5318007 +* **Currency Symbol:** lREACT +* **Block Explorer:** https://lasna.reactscan.net diff --git a/docs/docs/reactvm.md b/docs/docs/reactvm.md index 770c47b..98a751e 100644 --- a/docs/docs/reactvm.md +++ b/docs/docs/reactvm.md @@ -1,7 +1,7 @@ --- title: ReactVM sidebar_position: 5 -description: Explore ReactVM, a dedicated EVM within the Reactive Network for executing Reactive Contracts. It enables random transactions while maintaining order, serving as a sandbox for contract deployment. +description: Learn about ReactVM, the execution environment where Reactive Contracts process event logs and execute event-driven automation across chains. slug: /reactvm hide_title: true --- @@ -10,37 +10,39 @@ hide_title: true ## Overview -The ReactVM is a specialized Ethereum Virtual Machine (EVM) within the Reactive Network, designed to execute [Reactive Contracts](./reactive-contracts) (RCs). It allows transactions to occur in random order across multiple threads while maintaining order within each ReactVM. - -Technically, ReactVM is an isolated execution environment that activates when an event matches an RC's subscription. Although this approach introduces some overhead, we've optimized the process by separating the EVM from Geth, reducing ReactVm's boot time to approximately 100 microseconds. This overhead is insignificant relative to the network's processing capabilities. +ReactVM is a private execution environment within Reactive Network where [Reactive Contracts](./reactive-contracts) process events and execute logic. Each Reactive Contract runs inside a dedicated ReactVM that activates when subscribed events occur. Event logs are delivered to the ReactVM, where the contract executes Solidity logic and determines whether callback transactions should be sent to destination chains. ReactVMs run independently and can execute in parallel, allowing Reactive Contracts to process events while maintaining deterministic execution within each ReactVM. ## My ReactVM -When you deploy a Reactive Contract, it is assigned to a ReactVM. The ReactVM's address will match the Externally Owned Account (EOA) address used for the deployment. All smart contracts deployed to the Reactive Network will ultimately reside within your personal ReactVM, enabling shared state and interaction among contracts. Although multiple RCs can be deployed within a single ReactVM, this practice is generally discouraged. +Each deployed Reactive Contract is assigned to a ReactVM derived from the deployer’s address. Contracts deployed from the same EOA share the same ReactVM and can interact through shared state. Although multiple Reactive Contracts can be deployed within one ReactVM, separating contracts across ReactVMs is generally recommended. ### Calling subscribe() -Invoking `subscribe()` or `unsubscribe()` within an RVM will not have any tangible effect. For interactions, use callbacks instead of directly calling these functions within RVMs. +Calling `subscribe()` or `unsubscribe()` inside ReactVM has no effect. Subscriptions must be managed through the Reactive Network instance of the contract. ReactVM contracts should communicate through callback transactions instead of direct subscription calls. ## State -The Reactive Network's state is determined by the collective states of individual ReactVMs and their connections to external blockchains. Each ReactVM's state is tied to specific block numbers and hashes from these chains, embedded within ReactVM blocks. This linkage is necessary for tracking and managing reorgs in the originating chains, enabling the network to respond to changes. +Each ReactVM maintains its own state based on processed events. ReactVM blocks include references to origin-chain block numbers and hashes, allowing Reactive Network to track and handle chain reorganizations. ReactVM states operate independently, and the overall Reactive Network state is the combination of all ReactVM states. ### Dual-State Environment -The Reactive Network operates within a dual-state environment that supports parallel transaction execution. While the EVM processes commands sequentially in a single-threaded manner, ReactVMs can operate independently and in parallel across different cores or threads. This architecture facilitates the management of various operations, including fund flows and token management, with each contract copy having its own state and execution context. +Each Reactive Contract exists in two environments with separate state: + +- **ReactVM State** — updated automatically when subscribed events occur +- **Reactive Network State** — updated when EOAs call contract functions -Each [Reactive Contract](./reactive-contracts) has two instances with different states, both initialized in the constructor: +Both instances share the same bytecode but operate independently. -     **ReactVM State**: Updates when an event occurs. +For example, in a governance contract: -     **Reactive Network State**: Updates when you manually call its functions. +- Vote counts may be maintained in ReactVM state +- Administrative actions such as `pause()` may exist in the Reactive Network state -For example, in a governance contract, vote counts are maintained in the ReactVM state, whereas operational commands like `pause()` are part of the Reactive Network state. The primary logic resides within the ReactVM state. +Most automation logic runs inside ReactVM. ## Reactive Network Processing Flow -The following diagram illustrates a process involving the interaction between an Origin Chain, the Reactive Network along with ReactVM, and a Destination Chain. +The diagram below shows how events from an origin chain are processed by Reactive Network and ReactVM, and how resulting actions are delivered to destination chains. ![Reactive Network Lifecycle](./img/global-processing-flow.png) diff --git a/docs/docs/rnk-rpc-methods.md b/docs/docs/rnk-rpc-methods.md index 30cf3fb..93b869a 100644 --- a/docs/docs/rnk-rpc-methods.md +++ b/docs/docs/rnk-rpc-methods.md @@ -1,7 +1,7 @@ --- title: RNK RPC Methods sidebar_position: 11 -description: Explore Reactive Network's Geth version RPC methods used for interaction with reactive nodes and ReactVMs. +description: Learn about Reactive Network's Geth version RPC methods used for interaction with Reactive nodes and ReactVMs. slug: /rnk-rpc-methods hide_title: true --- @@ -10,15 +10,15 @@ hide_title: true ## Overview -This page provides an overview of the RPC methods specific to the Reactive Network's Geth version, essential for interacting with nodes and ReactVMs within the Reactive Network (RNK). These methods enable transaction retrieval, log access, callback information, etc. Below, you will find a detailed description of each method, including its parameters, cURLs, and responses. +This page documents **Reactive-specific JSON-RPC methods** available in Reactive Network’s (RNK) Geth version. Use them to inspect **ReactVM activity** (transactions, logs, code, storage), and to query network metadata like subscribers, filters, and origin-chain stats. :::tip[Ethereum RPC Methods] -Reactive Network is fully compatible with [standard Geth RPC methods](https://geth.ethereum.org/docs/interacting-with-geth/rpc). This page covers additional Reactive-specific methods. +Reactive Network supports standard [Geth RPC methods](https://geth.ethereum.org/docs/interacting-with-geth/rpc). This page lists RNK extensions only. ::: ## rnk_getTransactionByHash -Returns the details of a transaction for the specified ReactVM ID and transaction hash. +Returns a ReactVM transaction by RVM ID and transaction hash. #### Parameters @@ -91,7 +91,7 @@ Returns an object with the following fields: ## rnk_getTransactionByNumber -Returns the details of a transaction based on its sequence number within the specified ReactVM. +Returns a ReactVM transaction by RVM ID and transaction number. #### Parameters @@ -164,7 +164,7 @@ Returns an object with the following fields: ## rnk_getTransactionLogs -Returns logs for a transaction based on its sequence number within the specified ReactVM. +Returns the logs emitted by a ReactVM transaction number. #### Parameters @@ -222,7 +222,7 @@ Returns an array of objects with the following fields: ## rnk_getHeadNumber -Returns the latest transaction number for the specified ReactVM. +Returns the latest transaction number for a given ReactVM. #### Parameters @@ -259,7 +259,7 @@ Returns an object with the following field: ## rnk_getTransactions -Returns a range of transactions starting from a specified transaction number within the ReactVM. +Returns a range of transactions from a given starting number. #### Parameters @@ -336,7 +336,7 @@ Returns an object with the following fields: ## rnk_getRnkAddressMapping -Returns the RVM ID mapped to the specified reactive contract address. +Returns the ReactVM ID associated with a Reactive Network contract address. #### Parameters @@ -375,7 +375,7 @@ Returns an object with the following field: ## rnk_getStat -Returns and compiles statistics about origin chain data. +Returns aggregated statistics per origin chain. #### Parameters @@ -439,7 +439,7 @@ Returns an object with the following fields: ## rnk_getVms -Returns information about all RVMs, including the number of transactions processed and the count of associated contracts. +Returns information about all known ReactVMs. #### Parameters @@ -502,7 +502,7 @@ Returns a list of active RVMs with the following fields: ## rnk_getVm -Returns detailed information about a specific RVM, including the latest transaction number and the number of contracts deployed within it. +Returns information about a specific ReactVM. #### Parameters @@ -543,7 +543,7 @@ Returns an object with the following fields: ## rnk_getSubscribers -Returns a list of contracts that have subscribed to events from a specified RVM, along with their filter topics. +Returns subscriptions associated with a given ReactVM. #### Parameters @@ -623,7 +623,7 @@ Returns a list of RVM-related contract events with the following fields: ## rnk_getCode -Retrieves the bytecode of a deployed contract at a specific transaction or block state for a given RVM. +Retrieves the deployed contract bytecode for a given ReactVM at a specific state. #### Parameters @@ -658,13 +658,14 @@ Returns the bytecode of a contract: { "jsonrpc": "2.0", "id": 1, - "result": "0x60806040526004361061007e575f3560e01c80638456cb591161004d5780638456cb591461010757806396f90b451461011d578063995e4b9814610147578063c290d6911461017157610085565b806303ac52b314610089578063046f7da2146100b35780630d152c2c146100c95780637a90b990146100f157610085565b3661008557005b5f5ffd5b348015610094575f5ffd5b5061009d610199565b6040516100aa9190610cb0565b60405180910390f35b3480156100be575f5ffd5b506100c761019f565b005b3480156100d4575f5ffd5b506100ef60048036038101906100ea9190610cf4565b610458565b005b3480156100fc575f5ffd5b5061010561059d565b005b348015610112575f5ffd5b5061011b610665565b005b348015610128575f5ffd5b50610131610920565b60405161013e9190610cb0565b60405180910390f35b348015610152575f5ffd5b5061015b610929565b6040516101689190610cb0565b60405180910390f35b34801561017c575f5ffd5b5061019760048036038101906101929190610d65565b61092f565b005b60055481565b60025f9054906101000a900460ff16156101ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101e590610dea565b60405180910390fd5b60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461027d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161027490610e52565b60405180910390fd5b600360149054906101000a900460ff166102cc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c390610eba565b60405180910390fd5b5f6102d56109c5565b90505f5f90505b8151811461043a57600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a6aced083838151811061033557610334610ed8565b5b60200260200101515f015184848151811061035357610352610ed8565b5b60200260200101516020015185858151811061037257610371610ed8565b5b60200260200101516040015186868151811061039157610390610ed8565b5b6020026020010151606001518787815181106103b0576103af610ed8565b5b6020026020010151608001518888815181106103cf576103ce610ed8565b5b602002602001015160a001516040518763ffffffff1660e01b81526004016103fc96959493929190610f44565b5f604051808303815f87803b158015610413575f5ffd5b505af1158015610425573d5f5f3e3d5ffd5b505050508061043390610fd0565b90506102dc565b505f600360146101000a81548160ff02191690831515021790555050565b60025f9054906101000a900460ff166104a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161049d90611061565b60405180910390fd5b60045481604001350361059a5743600581905550620f424067ffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16467f8dd725fa9d6cd150017ab9e60318d40616439424e2fade9c1c58854950917dfc6040516024016040516020818303038152906040527f083b2732000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161059191906110ef565b60405180910390a45b50565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639b6c56ec306040518263ffffffff1660e01b81526004016105f7919061110f565b602060405180830381865afa158015610612573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610636919061113c565b90506106625f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682610b0b565b50565b60025f9054906101000a900460ff16156106b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106ab90610dea565b60405180910390fd5b60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610743576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161073a90610e52565b60405180910390fd5b600360149054906101000a900460ff1615610793576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161078a906111b1565b60405180910390fd5b5f61079c6109c5565b90505f5f90505b8151811461090157600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632f8073368383815181106107fc576107fb610ed8565b5b60200260200101515f015184848151811061081a57610819610ed8565b5b60200260200101516020015185858151811061083957610838610ed8565b5b60200260200101516040015186868151811061085857610857610ed8565b5b60200260200101516060015187878151811061087757610876610ed8565b5b60200260200101516080015188888151811061089657610895610ed8565b5b602002602001015160a001516040518763ffffffff1660e01b81526004016108c396959493929190610f44565b5f604051808303815f87803b1580156108da575f5ffd5b505af11580156108ec573d5f5f3e3d5ffd5b50505050806108fa90610fd0565b90506107a3565b506001600360146101000a81548160ff02191690831515021790555050565b5f600554905090565b60045481565b60015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff166109b8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109af90611219565b60405180910390fd5b6109c23382610b0b565b50565b60605f600167ffffffffffffffff8111156109e3576109e2611237565b5b604051908082528060200260200182016040528015610a1c57816020015b610a09610c52565b815260200190600190039081610a015790505b5090506040518060c00160405280468152602001600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200160045481526020017fa65f96fc951c35ead38878e0f0b7a3c744a6f5ccc1476b313353ce31712313ad81526020017fa65f96fc951c35ead38878e0f0b7a3c744a6f5ccc1476b313353ce31712313ad81526020017fa65f96fc951c35ead38878e0f0b7a3c744a6f5ccc1476b313353ce31712313ad815250815f81518110610af957610af8610ed8565b5b60200260200101819052508091505090565b80471015610b4e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b45906112ae565b60405180910390fd5b5f811115610c4e575f8273ffffffffffffffffffffffffffffffffffffffff16825f67ffffffffffffffff811115610b8957610b88611237565b5b6040519080825280601f01601f191660200182016040528015610bbb5781602001600182028036833780820191505090505b50604051610bc99190611306565b5f6040518083038185875af1925050503d805f8114610c03576040519150601f19603f3d011682016040523d82523d5f602084013e610c08565b606091505b5050905080610c4c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c4390611366565b60405180910390fd5b505b5050565b6040518060c001604052805f81526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020015f81526020015f81526020015f81526020015f81525090565b5f819050919050565b610caa81610c98565b82525050565b5f602082019050610cc35f830184610ca1565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f6101808284031215610ceb57610cea610cd1565b5b81905092915050565b5f60208284031215610d0957610d08610cc9565b5b5f82013567ffffffffffffffff811115610d2657610d25610ccd565b5b610d3284828501610cd5565b91505092915050565b610d4481610c98565b8114610d4e575f5ffd5b50565b5f81359050610d5f81610d3b565b92915050565b5f60208284031215610d7a57610d79610cc9565b5b5f610d8784828501610d51565b91505092915050565b5f82825260208201905092915050565b7f5265616374697665204e6574776f726b206f6e6c7900000000000000000000005f82015250565b5f610dd4601583610d90565b9150610ddf82610da0565b602082019050919050565b5f6020820190508181035f830152610e0181610dc8565b9050919050565b7f556e617574686f72697a656400000000000000000000000000000000000000005f82015250565b5f610e3c600c83610d90565b9150610e4782610e08565b602082019050919050565b5f6020820190508181035f830152610e6981610e30565b9050919050565b7f4e6f7420706175736564000000000000000000000000000000000000000000005f82015250565b5f610ea4600a83610d90565b9150610eaf82610e70565b602082019050919050565b5f6020820190508181035f830152610ed181610e98565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610f2e82610f05565b9050919050565b610f3e81610f24565b82525050565b5f60c082019050610f575f830189610ca1565b610f646020830188610f35565b610f716040830187610ca1565b610f7e6060830186610ca1565b610f8b6080830185610ca1565b610f9860a0830184610ca1565b979650505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610fda82610c98565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361100c5761100b610fa3565b5b600182019050919050565b7f564d206f6e6c79000000000000000000000000000000000000000000000000005f82015250565b5f61104b600783610d90565b915061105682611017565b602082019050919050565b5f6020820190508181035f8301526110788161103f565b9050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6110c18261107f565b6110cb8185611089565b93506110db818560208601611099565b6110e4816110a7565b840191505092915050565b5f6020820190508181035f83015261110781846110b7565b905092915050565b5f6020820190506111225f830184610f35565b92915050565b5f8151905061113681610d3b565b92915050565b5f6020828403121561115157611150610cc9565b5b5f61115e84828501611128565b91505092915050565b7f416c7265616479207061757365640000000000000000000000000000000000005f82015250565b5f61119b600e83610d90565b91506111a682611167565b602082019050919050565b5f6020820190508181035f8301526111c88161118f565b9050919050565b7f417574686f72697a65642073656e646572206f6e6c79000000000000000000005f82015250565b5f611203601683610d90565b915061120e826111cf565b602082019050919050565b5f6020820190508181035f830152611230816111f7565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f496e73756666696369656e742066756e647300000000000000000000000000005f82015250565b5f611298601283610d90565b91506112a382611264565b602082019050919050565b5f6020820190508181035f8301526112c58161128c565b9050919050565b5f81905092915050565b5f6112e08261107f565b6112ea81856112cc565b93506112fa818560208601611099565b80840191505092915050565b5f61131182846112d6565b915081905092915050565b7f5472616e73666572206661696c656400000000000000000000000000000000005f82015250565b5f611350600f83610d90565b915061135b8261131c565b602082019050919050565b5f6020820190508181035f83015261137d81611344565b905091905056fea264697066735822122034fc1c6a89fb4e371bf625c4ac368d40ce079d62f9661894e35ec6c69efb147864736f6c634300081c0033" + "result": "0x60806040526004361061007e575f3560e01c80638456cb591161004d5780638456cb591461010757806396f90b451461011d578063995e4b9814610147578063c290d6911461017157610085565b806303ac52b314610089578063046f7da2146100b3578063...efb147864736f6c634300081c0033", + } ``` ## rnk_getStorageAt -Retrieves the storage value at a specified key for a contract on a given RVM at a specific transaction or block state. +Returns the value stored at a given 32-byte storage key for a contract inside a specific ReactVM, evaluated at a chosen state. #### Parameters @@ -707,7 +708,7 @@ Returns the storage value: ## rnk_call -Performs a read-only simulation of a Reactive contract function call on a given RVM, without creating a transaction. +Runs a read-only EVM call against a contract inside a ReactVM at a chosen state (no transaction is created). #### Parameters @@ -757,7 +758,7 @@ Returns the result of the simulated call: ## rnk_getBlockRvms -Retrieves the history of RVMs for a given block number, specifically those RVMs that have generated an RVM transaction. +Returns the ReactVMs that produced at least one ReactVM transaction in a given Reactive Network block, plus per-RVM counters. #### Parameters @@ -804,7 +805,7 @@ Returns an array of objects representing RVMs that were active in the given bloc ## rnk_getFilters -Returns all the active log filters registered on the Reactive Network, along with their configurations and target contracts. +Lists all active log filters (subscriptions) currently registered on Reactive Network. #### Parameters diff --git a/docs/docs/subscriptions.md b/docs/docs/subscriptions.md index 8be0fac..20042d0 100644 --- a/docs/docs/subscriptions.md +++ b/docs/docs/subscriptions.md @@ -1,7 +1,7 @@ --- title: Subscriptions sidebar_position: 10 -description: Explore how to subscribe to events via Reactive Contracts, allowing for event-driven interactions and transaction creation. +description: Learn how Reactive Contracts subscribe to events and configure event-driven automation. slug: /subscriptions hide_title: true --- @@ -10,13 +10,24 @@ hide_title: true ## Overview -This section explains how to configure and manage subscriptions in a reactive contract within the Reactive Network. It covers the basics of setting up subscriptions in the contract's constructor, handling dynamic subscriptions through callbacks, and applying filtering criteria like chain ID, contract address, and event topics. +Subscriptions define which events Reactive Contracts (RCs) listens to. RCs subscribe to events through the system contract by specifying: + +- Origin chain ID +- Contract address +- Event topics + +When a matching event is detected, the contract's `react()` function is triggered. + +Subscriptions can be configured: + +- During deployment (constructor) +- Dynamically via callbacks ## Subscription Basics -In a reactive contract, subscriptions are established by invoking the `subscribe()` method of the Reactive Network's [system contract](./economy). This method is typically called in the contract's `constructor()` or dynamically via a callback (see [Dynamic Subscriptions](./subscriptions.md#dynamic-subscriptions)). +Subscriptions are created by calling `subscribe()` on the system contract. This is typically done inside the contract constructor. Since contracts deploy both on Reactive Network (RNK) and inside a ReactVM (where the system contract doesn't exist), the constructor must avoid calling `subscribe()` inside ReactVM. -Since deployments occur both on the Reactive Network and in the deployer's private ReactVM, where the system contract is not present, the reactive contract must handle potential reverts. [IReactive](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/IReactive.sol), [AbstractReactive](https://github.com/Reactive-Network/reactive-lib/blob/main/src/abstract-base/AbstractReactive.sol), and [ISystemContract](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/ISystemContract.sol) should be implemented. Here's a subscription example in the constructor, taken from the [Basic Demo reactive contract](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/basic/BasicDemoReactiveContract.sol). +[IReactive](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/IReactive.sol), [AbstractReactive](https://github.com/Reactive-Network/reactive-lib/blob/main/src/abstract-base/AbstractReactive.sol), and [ISystemContract](https://github.com/Reactive-Network/reactive-lib/blob/main/src/interfaces/ISystemContract.sol) should be implemented. Here's a subscription example in the constructor from the [Basic Demo Reactive Contract](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/basic/BasicDemoReactiveContract.sol): ```solidity uint256 public originChainId; @@ -34,6 +45,7 @@ constructor( address _callback ) payable { service = ISystemContract(payable(_service)); + originChainId = _originChainId; destinationChainId = _destinationChainId; callback = _callback; @@ -51,100 +63,120 @@ constructor( } ``` -The Reactive Network uses the subscription system to link various `uint256` fields to specific events. Subscribers can then filter events based on exact matches of these fields. +Subscriptions filter events using: + +- Chain ID +- Contract address +- Topics 0–3 :::info[Filtering Criteria] -The Reactive Network provides filtering criteria based on the originating contract's chain ID, address, and all four topics. +Reactive Network provides filtering criteria based on the origin contract's chain ID, address, and all four topics. ::: -### Using 'REACTIVE_IGNORE' and '0' +## Wildcards & Matching -`REACTIVE_IGNORE` is an arbitrary predefined value `0xa65f96fc951c35ead38878e0f0b7a3c744a6f5ccc1476b313353ce31712313ad` that allows you to subscribe to any topic. +### REACTIVE_IGNORE -`address(0)` can be used for contract address and `uint256(0)` for chain ID to match any value. Ensure at least one criterion is specific to create a meaningful subscription. +`REACTIVE_IGNORE` is a predefined wildcard value that matches any topic value: -### Subscription Examples +```json +0xa65f96fc951c35ead38878e0f0b7a3c744a6f5ccc1476b313353ce31712313ad +``` -**All Events from a Specific Contract**: Subscribe to all events from `0x7E0987E5b3a30e3f2828572Bb659A548460a3003`. +### Zero Values -```solidity -service.subscribe(CHAIN_ID, 0x7E0987E5b3a30e3f2828572Bb659A548460a3003, REACTIVE_IGNORE, REACTIVE_IGNORE, REACTIVE_IGNORE, REACTIVE_IGNORE) -``` +Wildcards can also be specified with: -**Specific Topic 0**: Subscribe to all Uniswap V2 Sync events. +- `uint256(0)` → any chain ID +- `address(0)` → any contract + +**At least one parameter must be specific.** + +### Subscription Examples + +#### All Events From One Contract ```solidity -service.subscribe(CHAIN_ID, 0, 0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1, REACTIVE_IGNORE, REACTIVE_IGNORE, REACTIVE_IGNORE) +service.subscribe( + CHAIN_ID, + 0x7E0987E5b3a30e3f2828572Bb659A548460a3003, + REACTIVE_IGNORE, + REACTIVE_IGNORE, + REACTIVE_IGNORE, + REACTIVE_IGNORE +); ``` -**Specific Contract with Specific Topic 0**: Subscribe to events from `0x7E0987E5b3a30e3f2828572Bb659A548460a3003` with topic 0 `0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1`. +#### Specific Event Type + +Example: Uniswap V2 Sync events ```solidity -service.subscribe(CHAIN_ID, 0x7E0987E5b3a30e3f2828572Bb659A548460a3003, 0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1, REACTIVE_IGNORE, REACTIVE_IGNORE, REACTIVE_IGNORE) +service.subscribe( + CHAIN_ID, + address(0), + 0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1, + REACTIVE_IGNORE, + REACTIVE_IGNORE, + REACTIVE_IGNORE +); ``` -**Multiple Independent Subscriptions**: Call the `subscribe()` method multiple times in the constructor to create multiple independent subscriptions. +#### Specific Contract and Event ```solidity -uint256 public originChainId; -uint256 public destinationChainId; -uint64 private constant GAS_LIMIT = 1000000; +service.subscribe( + CHAIN_ID, + 0x7E0987E5b3a30e3f2828572Bb659A548460a3003, + 0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1, + REACTIVE_IGNORE, + REACTIVE_IGNORE, + REACTIVE_IGNORE +); +``` -address private callback; +#### Multiple Subscriptions -constructor( - address _service, - uint256 _originChainId, - uint256 _destinationChainId, - address _contract1, - uint256 _topic0, - address _contract2, - uint256 _topic1, - address _callback -) payable { - service = ISystemContract(payable(_service)); - originChainId = _originChainId; - destinationChainId = _destinationChainId; - callback = _callback; - - if (!vm) { - // First subscription - service.subscribe( - originChainId, - _contract1, - _topic0, - REACTIVE_IGNORE, - REACTIVE_IGNORE, - REACTIVE_IGNORE - ); +Call `subscribe()` multiple times: - // Second subscription - service.subscribe( - originChainId, - _contract2, - REACTIVE_IGNORE, - _topic1, - REACTIVE_IGNORE, - REACTIVE_IGNORE - ); - } +```solidity +if (!vm) { + + service.subscribe( + originChainId, + _contract1, + _topic0, + REACTIVE_IGNORE, + REACTIVE_IGNORE, + REACTIVE_IGNORE + ); + + service.subscribe( + originChainId, + _contract2, + REACTIVE_IGNORE, + _topic1, + REACTIVE_IGNORE, + REACTIVE_IGNORE + ); } ``` -### Unsubscribing via System Contract +### Unsubscribing -There may be situations where a reactive contract needs to stop listening to a particular topic — such as for revoking automation, optimizing gas usage, or replacing an outdated listener. To do this, you need to invoke the `unsubscribeContract()` function on the system contract by executing the command given below. +Subscriptions can be removed through the system contract. -First, export the `REACTIVE_IGNORE` constant, which is used as a wildcard value when you want to ignore certain topic parameters: +Export the wildcard constant: ```bash export REACTIVE_IGNORE=0xa65f96fc951c35ead38878e0f0b7a3c744a6f5ccc1476b313353ce31712313ad ``` -If you're only interested in unsubscribing from a contract with a specific `topic0` and don't care about the values of `topic1`, `topic2`, or `topic3`, use `REACTIVE_IGNORE` in those positions: +Example: ```bash -cast send --rpc-url $REACTIVE_RPC \ +cast send \ + --rpc-url $REACTIVE_RPC \ --private-key $REACTIVE_PRIVATE_KEY \ $SYSTEM_CONTRACT_ADDR \ "unsubscribeContract(address,uint256,address,uint256,uint256,uint256,uint256)" \ @@ -157,29 +189,71 @@ cast send --rpc-url $REACTIVE_RPC \ $REACTIVE_IGNORE ``` -### Prohibited Subscriptions +### Subscription Limitations + +#### Equality Matching Only + +Subscriptions support exact matches only. + +Not supported: + +- `<` or `>` +- Ranges +- Bitwise filters + +#### Complex Criteria Sets + +Each subscription defines **one set of matching criteria**. -**Non-Equality Operations**: Subscriptions can’t match event parameters using less than (\<), greater than (\>), range, or bitwise operations. Only strict equality is supported. +Not supported: -**Complex Criteria Sets**: Subscriptions can’t use disjunction or sets of criteria within a single subscription. While calling the `subscribe()` method multiple times can achieve similar results, it may lead to combinatorial explosion. +- Disjunctions (OR conditions) +- Multiple criteria sets within one subscription -**Single Chain and All Contracts**: Subscribing to events from all chains or all contracts simultaneously is not allowed. Subscribing to all events from only one chain is also prohibited, as it is considered unnecessary. +Workaround: -**Duplicate Subscriptions**: While duplicate subscriptions are technically allowed, they function as a single subscription. Users are charged for each transaction sent to the system contract. Preventing duplicates in the system contract is costly due to EVM storage limitations, so duplicate subscriptions are permitted to keep costs manageable. +- Use multiple `subscribe()` calls +- May lead to a **large number of subscriptions** + +#### No Global Subscriptions + +Not allowed: + +- All chains +- All contracts +- All events on a chain + +#### Duplicate Subscriptions + +Duplicate subscriptions are allowed but behave as one subscription. + +Each `subscribe()` transaction still costs gas. ## Dynamic Subscriptions -Subscriptions in the Reactive Network are managed through the system contract, which is accessible only from the network. Events are sent to the ReactVM's contract copy, which has no direct access to the system contract. Therefore, dynamic subscriptions and unsubscriptions based on incoming events must be handled via callbacks. +Subscriptions can be created or removed dynamically based on incoming events. + +Subscription management is performed through the system contract, which is accessible only from Reactive Network (RNK). The ReactVM instance of a contract can't call the system contract directly, so dynamic subscription changes must be performed through callback transactions. -The `react()` method from the [reactive contract](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/approval-magic/ApprovalListener.sol) of the [Approval Magic demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/approval-magic) processes incoming events and checks if `topic_0` indicates a `subscribe` or `unsubscribe` event. If so, it generates a callback to the Reactive Network to manage the subscription. +The typical flow is: + +1. An event is received in the ReactVM. +2. The contract decides whether to subscribe or unsubscribe. +3. A `Callback` event is emitted. +4. Reactive Network (RNK) executes the subscription change. ### Subscribing & Unsubscribing -These functions allow the contract to subscribe or unsubscribe a subscriber address to/from the `APPROVAL_TOPIC_0` in the Reactive Network. +These functions run on the Reactive Network contract instance and modify subscriptions through the system contract. The example below is based on the [ApprovalListener.sol](https://github.com/Reactive-Network/reactive-smart-contract-demos/blob/main/src/demos/approval-magic/ApprovalListener.sol) contract from the [Approval Magic demo](https://github.com/Reactive-Network/reactive-smart-contract-demos/tree/main/src/demos/approval-magic). ```solidity - // Methods specific to reactive network contract instance - function subscribe(address rvm_id, address subscriber) external rnOnly callbackOnly(rvm_id) { +// Methods specific to Reactive Network contract instance + +function subscribe(address rvm_id, address subscriber) + external + rnOnly + callbackOnly(rvm_id) + { service.subscribe( SEPOLIA_CHAIN_ID, address(0), @@ -190,7 +264,11 @@ These functions allow the contract to subscribe or unsubscribe a subscriber addr ); } - function unsubscribe(address rvm_id, address subscriber) external rnOnly callbackOnly(rvm_id) { +function unsubscribe(address rvm_id, address subscriber) + external + rnOnly + callbackOnly(rvm_id) + { service.unsubscribe( SEPOLIA_CHAIN_ID, address(0), @@ -202,59 +280,82 @@ These functions allow the contract to subscribe or unsubscribe a subscriber addr } ``` -**Parameters**: +Parameters: -- `rvm_id`: The ID of the reactive virtual machine (RVM). -- `subscriber`: The address that will be subscribed or unsubscribed. +- **rvm_id** — ReactVM identifier (injected automatically) +- **subscriber** — address to subscribe or unsubscribe -**Operations**: +Operations: -- `subscribe`: Registers a subscriber to the `APPROVAL_TOPIC_0`. -- `unsubscribe`: Removes a subscriber from the `APPROVAL_TOPIC_0`. +- **subscribe** — registers a subscriber for `APPROVAL_TOPIC_0` +- **unsubscribe** — removes a subscriber from `APPROVAL_TOPIC_0` -### react Function & Logic +### react() Logic -The function processes incoming log records from the ReactVM and executes different actions based on the topic in the log. +The `react()` function processes incoming events and emits callbacks when subscription changes are required. ```solidity // Methods specific to ReactVM contract instance - function react(LogRecord calldata log) external vmOnly { - if (log.topic_0 == SUBSCRIBE_TOPIC_0) { - bytes memory payload = abi.encodeWithSignature( - "subscribe(address,address)", - address(0), - address(uint160(log.topic_1)) - ); - emit Callback(REACTIVE_CHAIN_ID, address(this), CALLBACK_GAS_LIMIT, payload); - } else if (log.topic_0 == UNSUBSCRIBE_TOPIC_0) { - bytes memory payload = abi.encodeWithSignature( - "unsubscribe(address,address)", - address(0), - address(uint160(log.topic_1)) - ); - emit Callback(REACTIVE_CHAIN_ID, address(this), CALLBACK_GAS_LIMIT, payload); - } else { - (uint256 amount) = abi.decode(log.data, (uint256)); - bytes memory payload = abi.encodeWithSignature( - "onApproval(address,address,address,address,uint256)", - address(0), - address(uint160(log.topic_2)), - address(uint160(log.topic_1)), - log._contract, - amount - ); - emit Callback(SEPOLIA_CHAIN_ID, address(approval_service), CALLBACK_GAS_LIMIT, payload); - } +function react(LogRecord calldata log) external vmOnly { + + if (log.topic_0 == SUBSCRIBE_TOPIC_0) { + + bytes memory payload = abi.encodeWithSignature( + "subscribe(address,address)", + address(0), + address(uint160(log.topic_1)) + ); + + emit Callback( + REACTIVE_CHAIN_ID, + address(this), + CALLBACK_GAS_LIMIT, + payload + ); + + } else if (log.topic_0 == UNSUBSCRIBE_TOPIC_0) { + + bytes memory payload = abi.encodeWithSignature( + "unsubscribe(address,address)", + address(0), + address(uint160(log.topic_1)) + ); + + emit Callback( + REACTIVE_CHAIN_ID, + address(this), + CALLBACK_GAS_LIMIT, + payload); + + } else { + + (uint256 amount) = abi.decode(log.data, (uint256)); + + bytes memory payload = abi.encodeWithSignature( + "onApproval(address,address,address,address,uint256)", + address(0), + address(uint160(log.topic_2)), + address(uint160(log.topic_1)), + log._contract, + amount + ); + + emit Callback( + SEPOLIA_CHAIN_ID, + address(approval_service), + CALLBACK_GAS_LIMIT, + payload + ); } } ``` -**Log Processing**: +Event handling: -- Subscribe Logic: If the log's `topic_0` matches the `SUBSCRIBE_TOPIC_0`, the function encodes a payload for the `subscribe()` method and emits a callback. -- Unsubscribe Logic: If the log's `topic_0` matches the `UNSUBSCRIBE_TOPIC_0`, the function encodes a payload for the `unsubscribe()` method and emits a callback. -- Approval Logic: For any other log, it decodes the approval amount and creates a payload for the `onApproval` method, then emits a callback to the `approval_service` on Sepolia. +- **Subscribe event** → emits a callback that creates a subscription +- **Unsubscribe event** → emits a callback that removes a subscription +- **Other events** → emit callbacks that trigger application logic -**Callback Emission**: The function uses the `emit Callback` statement to send the appropriate payload and trigger the corresponding action on the Reactive chain. +Callbacks are executed by Reactive Network after the event is processed. [More on Subscriptions →](../education/module-1/subscriptions.md) \ No newline at end of file diff --git a/sidebars.js b/sidebars.js index 85fd2e9..a066ede 100644 --- a/sidebars.js +++ b/sidebars.js @@ -25,12 +25,6 @@ const sidebars = { dirName: "education", }, ], - debugging: [ - { - type: "autogenerated", - dirName: "debugging", - }, - ], contacts: [ { type: "autogenerated", diff --git a/src/components/cron-table.js b/src/components/cron-table.js index 3a6ac7e..d512a68 100644 --- a/src/components/cron-table.js +++ b/src/components/cron-table.js @@ -8,8 +8,8 @@ const CronTable = () => { Event Interval - Approx. Time - Topic0 + Approximate Time + Topic 0 diff --git a/src/components/hyperlane-comparison.js b/src/components/hyperlane-comparison.js deleted file mode 100644 index 2f41b51..0000000 --- a/src/components/hyperlane-comparison.js +++ /dev/null @@ -1,75 +0,0 @@ -import React from 'react'; - -const TransportComparisonTable = () => { - const categories = ['Pros', 'Cons']; - - const hyperlane = { - Pros: [ - '✅ Decentralized and highly secure', - '🌐 Broad chain and dApp compatibility', - '💸 Entire flow can be funded in REACT', - ], - Cons: [ - '⚠️ Relayer-dependent, operational and liveness risks', - '🐢 Slower due to multi-step message relay and network latency', - '🔒 Requires `handle()` interface on the destination contract', - '💰 Higher cost due to relayer fee overhead', - ], - }; - - const reactive = { - Pros: [ - '🚀 Direct execution without relayers → faster and cheaper', - '🔁 Deterministic finality with minimal latency', - '⚙️ Supports arbitrary function calls — `no handle()` constraint', - '💸 Cost-efficient, fees only cover raw gas on both ends', - ], - Cons: [ - '🧱 Smaller but growing ecosystem', - '⚠️ Higher trust assumptions due to controlled execution environment', - '💰 Gas must be paid in REACT on Reactive Network and the native token on destination for full execution', - ], - }; - - return ( -
- - - - - - - - - - - - - - - {categories.map((category) => - Array.from({ length: Math.max(hyperlane[category].length, reactive[category].length) }).map((_, idx) => ( - - {idx === 0 ? ( - - ) : null} - - - - )) - )} - -
CategoryHyperlaneReactive
-
{category}
-
{hyperlane[category][idx] || ''}{reactive[category][idx] || ''}
-
- ); -}; - -export default TransportComparisonTable; diff --git a/src/components/hyperlane-mailbox-table.js b/src/components/hyperlane-mailbox-table.js index 575b5a3..832d60a 100644 --- a/src/components/hyperlane-mailbox-table.js +++ b/src/components/hyperlane-mailbox-table.js @@ -3,46 +3,46 @@ import React from 'react'; const MailboxAddressTable = () => { const data = [ { - chain: 'Ethereum Mainnet', + chain: 'Ethereum', chainId: 1, address: '0xc005dc82818d67AF737725bD4bf75435d065D239', - link: 'https://etherscan.io/', + explorer: 'https://etherscan.io/', rpcUrl: 'https://chainlist.org/chain/1' }, { - chain: 'Binance Smart Chain', + chain: 'BSC', chainId: 56, address: '0x2971b9Aec44bE4eb673DF1B88cDB57b96eefe8a4', - link: 'https://bscscan.com/', + explorer: 'https://bscscan.com/', rpcUrl: 'https://chainlist.org/chain/56' }, { - chain: 'Avalanche C-Chain', + chain: 'Avalanche', chainId: 43114, address: '0xFf06aFcaABaDDd1fb08371f9ccA15D73D51FeBD6', - link: 'https://avascan.info/', + explorer: 'https://avascan.info/', rpcUrl: 'https://chainlist.org/chain/43114' }, { - chain: 'Base Chain', + chain: 'Base', chainId: 8453, address: '0xeA87ae93Fa0019a82A727bfd3eBd1cFCa8f64f1D', - link: 'https://basescan.org/', + explorer: 'https://basescan.org/', rpcUrl: 'https://chainlist.org/chain/8453' }, { - chain: 'Sonic Mainnet', + chain: 'Sonic', chainId: 146, address: '0x3a464f746D23Ab22155710f44dB16dcA53e0775E', - link: 'https://sonicscan.org/', + explorer: 'https://sonicscan.org/', rpcUrl: 'https://chainlist.org/chain/146' }, { - chain: 'Reactive Mainnet', + chain: 'Reactive', chainId: 1597, address: '0x3a464f746D23Ab22155710f44dB16dcA53e0775E', - link: 'https://reactscan.net', - rpcUrl: 'https://mainnet-rpc.rnk.dev/' // plain text + explorer: 'https://reactscan.net/', + rpcUrl: 'https://mainnet-rpc.rnk.dev/' }, ]; @@ -52,29 +52,36 @@ const MailboxAddressTable = () => { Chain - Origin - Destination - Chain ID - Mailbox Address - Recommended RPC URL + Chain ID + Hyperlane Mailbox + RPC {data.map((row, idx) => ( - + {row.chain} - ✅ - ✅ {row.chainId} - {row.address} + + + {row.address} + + {row.rpcUrl.includes('chainlist.org') ? ( - - Find on Chainlist + + Chainlist ) : ( {row.rpcUrl} diff --git a/src/components/origins-destinations-testnet.js b/src/components/origins-destinations-testnet.js index 6ab9b02..861af18 100644 --- a/src/components/origins-destinations-testnet.js +++ b/src/components/origins-destinations-testnet.js @@ -5,7 +5,7 @@ const TestnetChainTable = () => { { chain: 'Avalanche Fuji', chainId: 43113, - link: 'https://43113.testnet.routescan.io/', + explorer: 'https://43113.testnet.routescan.io/', callbackAddress: '', rpcUrl: 'https://chainlist.org/chain/43113', origin: true, @@ -14,16 +14,16 @@ const TestnetChainTable = () => { { chain: 'Base Sepolia', chainId: 84532, - link: 'https://sepolia.basescan.org/', + explorer: 'https://sepolia.basescan.org/', callbackAddress: '0xa6eA49Ed671B8a4dfCDd34E36b7a75Ac79B8A5a6', rpcUrl: 'https://chainlist.org/chain/84532', origin: true, destination: true }, { - chain: 'Binance Smart Chain', + chain: 'BSC Testnet', chainId: 97, - link: 'https://testnet.bscscan.com/', + explorer: 'https://testnet.bscscan.com/', callbackAddress: '', rpcUrl: 'https://chainlist.org/chain/97', origin: true, @@ -32,7 +32,7 @@ const TestnetChainTable = () => { { chain: 'Ethereum Sepolia', chainId: 11155111, - link: 'https://sepolia.etherscan.io/', + explorer: 'https://sepolia.etherscan.io/', callbackAddress: '0xc9f36411C9897e7F959D99ffca2a0Ba7ee0D7bDA', rpcUrl: 'https://chainlist.org/chain/11155111', origin: true, @@ -41,7 +41,7 @@ const TestnetChainTable = () => { { chain: 'Reactive Lasna', chainId: 5318007, - link: 'https://lasna.reactscan.net', + explorer: 'https://lasna.reactscan.net', callbackAddress: '0x0000000000000000000000000000000000fffFfF', rpcUrl: 'https://lasna-rpc.rnk.dev/', origin: true, @@ -50,7 +50,7 @@ const TestnetChainTable = () => { { chain: 'Polygon Amoy', chainId: 80002, - link: 'https://www.oklink.com/amoy', + explorer: 'https://amoy.polygonscan.com/', callbackAddress: '', rpcUrl: 'https://chainlist.org/chain/80002', origin: true, @@ -67,26 +67,34 @@ const TestnetChainTable = () => { Origin Destination Chain ID - Callback Proxy Address - Recommended RPC URL + Callback Proxy + RPC {data.map((row, idx) => ( - + {row.chain} {row.origin ? '✅' : '➖'} {row.destination ? '✅' : '➖'} {row.chainId} - {row.callbackAddress || '➖'} + + {row.callbackAddress ? ( + + {row.callbackAddress} + + ) : ( + '➖' + )} + {row.rpcUrl.includes('chainlist.org') ? ( - Find on Chainlist + Chainlist ) : ( {row.rpcUrl} diff --git a/src/components/origins-destinations.js b/src/components/origins-destinations.js index 5af3b0e..a66fc56 100644 --- a/src/components/origins-destinations.js +++ b/src/components/origins-destinations.js @@ -5,43 +5,43 @@ const MainnetChainTable = () => { { chain: 'Abstract', chainId: 2741, - link: 'https://abscan.org/', + explorer: 'https://abscan.org/', callbackAddress: '0x9299472A6399Fd1027ebF067571Eb3e3D7837FC4', rpcUrl: 'https://chainlist.org/chain/2741', origin: true, destination: true }, { - chain: 'Arbitrum One', + chain: 'Arbitrum', chainId: 42161, - link: 'https://www.arbiscan.io/', + explorer: 'https://www.arbiscan.io/', callbackAddress: '0x4730c58FDA9d78f60c987039aEaB7d261aAd942E', rpcUrl: 'https://chainlist.org/chain/42161', origin: true, destination: true }, { - chain: 'Avalanche C-Chain', + chain: 'Avalanche', chainId: 43114, - link: 'https://avascan.info/', + explorer: 'https://avascan.info/', callbackAddress: '0x934Ea75496562D4e83E80865c33dbA600644fCDa', rpcUrl: 'https://chainlist.org/chain/43114', origin: true, destination: true }, { - chain: 'Base Chain', + chain: 'Base', chainId: 8453, - link: 'https://basescan.org/', + explorer: 'https://basescan.org/', callbackAddress: '0x0D3E76De6bC44309083cAAFdB49A088B8a250947', rpcUrl: 'https://chainlist.org/chain/8453', origin: true, destination: true }, { - chain: 'Binance Smart Chain', + chain: 'BSC', chainId: 56, - link: 'https://bscscan.com/', + explorer: 'https://bscscan.com/', callbackAddress: '0xdb81A196A0dF9Ef974C9430495a09B6d535fAc48', rpcUrl: 'https://chainlist.org/chain/56', origin: true, @@ -50,7 +50,7 @@ const MainnetChainTable = () => { { chain: 'Ethereum', chainId: 1, - link: 'https://etherscan.io/', + explorer: 'https://etherscan.io/', callbackAddress: '0x1D5267C1bb7D8bA68964dDF3990601BDB7902D76', rpcUrl: 'https://chainlist.org/chain/1', origin: true, @@ -59,7 +59,7 @@ const MainnetChainTable = () => { { chain: 'HyperEVM', chainId: 999, - link: 'https://hyperevmscan.io/', + explorer: 'https://hyperevmscan.io/', callbackAddress: '0x9299472A6399Fd1027ebF067571Eb3e3D7837FC4', rpcUrl: 'https://chainlist.org/chain/999', origin: true, @@ -68,7 +68,7 @@ const MainnetChainTable = () => { { chain: 'Linea', chainId: 59144, - link: 'https://lineascan.build/', + explorer: 'https://lineascan.build/', callbackAddress: '0x9299472A6399Fd1027ebF067571Eb3e3D7837FC4', rpcUrl: 'https://chainlist.org/chain/59144', origin: true, @@ -77,16 +77,16 @@ const MainnetChainTable = () => { { chain: 'Plasma', chainId: 9745, - link: 'https://plasmascan.to/', + explorer: 'https://plasmascan.to/', callbackAddress: '0x9299472A6399Fd1027ebF067571Eb3e3D7837FC4', rpcUrl: 'https://chainlist.org/chain/9745', origin: true, destination: true }, { - chain: 'Reactive Mainnet', + chain: 'Reactive', chainId: 1597, - link: 'https://reactscan.net', + explorer: 'https://reactscan.net', callbackAddress: '0x0000000000000000000000000000000000fffFfF', rpcUrl: 'https://mainnet-rpc.rnk.dev/', origin: true, @@ -95,7 +95,7 @@ const MainnetChainTable = () => { { chain: 'Sonic', chainId: 146, - link: 'https://sonicscan.org/', + explorer: 'https://sonicscan.org/', callbackAddress: '0x9299472A6399Fd1027ebF067571Eb3e3D7837FC4', rpcUrl: 'https://chainlist.org/chain/146', origin: true, @@ -104,7 +104,7 @@ const MainnetChainTable = () => { { chain: 'Unichain', chainId: 130, - link: 'https://uniscan.xyz/', + explorer: 'https://uniscan.xyz/', callbackAddress: '0x9299472A6399Fd1027ebF067571Eb3e3D7837FC4', rpcUrl: 'https://chainlist.org/chain/130', origin: true, @@ -121,26 +121,26 @@ const MainnetChainTable = () => { Origin Destination Chain ID - Callback Proxy Address - Recommended RPC URL + Callback Proxy + RPC {data.map((row, idx) => ( - - - {row.chain} - - + {row.chain} {row.origin ? '✅' : '➖'} {row.destination ? '✅' : '➖'} {row.chainId} - {row.callbackAddress} + + + {row.callbackAddress} + + {row.rpcUrl.includes('chainlist.org') ? ( - Find on Chainlist + Chainlist ) : ( {row.rpcUrl}