R2: Interfaces
IR2BeaconEmitter.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
/**
* @title IR2BeaconEmitter
* @notice Standard interface for emitting business-aware actions to R2 Beacon
* @dev Implement this interface to make your contract R2 Beacon compatible
*/
interface IR2BeaconEmitter {
/**
* @dev Emitted when a business-aware action occurs
*/
event R2Action(
address indexed user,
bytes32 indexed appId,
bytes32 indexed action,
uint256 amount,
bytes data
);
/// @notice Returns the registered APP_ID for this contract
function getAppId() external view returns (bytes32);
}
/**
* @title R2BeaconEmitter
* @notice Basic implementation of R2 Beacon emission capabilities
* @dev Inherit this contract to add R2 Beacon support to your DApp
*/
abstract contract R2BeaconEmitter is IR2BeaconEmitter {
/// @dev Application identifier assigned by R2 Registry
bytes32 public immutable APP_ID;
/// @dev Custom errors for better gas efficiency and clarity
error R2Beacon_InvalidAppId();
error R2Beacon_InvalidActionId();
constructor(bytes32 appId) {
if (appId == bytes32(0)) {
revert R2Beacon_InvalidAppId();
}
APP_ID = appId;
}
/// @inheritdoc IR2BeaconEmitter
function getAppId() external view returns (bytes32) {
return APP_ID;
}
/**
* @dev Internal function to emit business-aware actions
* @param action Registered action identifier
* @param amount Value/amount involved (optional)
* @param data Additional data (optional)
*/
function _emitR2Action(
bytes32 action,
uint256 amount,
bytes calldata data
) internal virtual {
if (action == bytes32(0)) {
revert R2Beacon_InvalidActionId();
}
emit R2Action({
user: msg.sender,
appId: APP_ID,
action: action,
amount: amount,
data: data
});
}
/**
* @dev Utility function to create action identifiers
* @param actionName Name of the action
* @return actionId Hash of the action name
*/
function _createActionId(string calldata actionName) internal pure returns (bytes32 actionId) {
assembly {
actionId := keccak256(actionName.offset, actionName.length)
}
}
}
Example Implementation
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {R2BeaconEmitter} from "./R2BeaconEmitter.sol";
contract GameApp is R2BeaconEmitter {
/// @dev Game-specific actions
bytes32 public constant GAME_START = keccak256("GAME_START");
bytes32 public constant GAME_WIN = keccak256("GAME_WIN");
bytes32 public constant ITEM_PURCHASE = keccak256("ITEM_PURCHASE");
/// @dev Game-specific errors
error Game_InsufficientPayment();
error Game_InvalidItem();
constructor(bytes32 appId) R2BeaconEmitter(appId) {}
function startGame(uint256 gameMode) external {
// Game start logic here
_emitR2Action(
GAME_START,
0,
abi.encode(gameMode)
);
}
function purchaseItem(uint256 itemId) external payable {
// Item purchase logic here
if (msg.value < getItemPrice(itemId)) {
revert Game_InsufficientPayment();
}
_emitR2Action(
ITEM_PURCHASE,
msg.value,
abi.encode(itemId)
);
}
function getItemPrice(uint256 itemId) public pure returns (uint256) {
// Price logic here
return 0.1 ether;
}
}
Last updated