Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
496 changes: 495 additions & 1 deletion .gas-snapshot

Large diffs are not rendered by default.

56 changes: 31 additions & 25 deletions src/TierRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import {Ownable2Step} from "openzeppelin/contracts/access/Ownable2Step.sol";
import {Pausable} from "openzeppelin/contracts/security/Pausable.sol";
import {Migration} from "./abstract/Migration.sol";
import "openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import {ITierRegistry} from "./interfaces/ITierRegistry.sol";
Expand All @@ -14,7 +13,7 @@ import {ITierRegistry} from "./interfaces/ITierRegistry.sol";
*
* @custom:security-contact [email protected]
*/
contract TierRegistry is ITierRegistry, Ownable2Step, Pausable {
contract TierRegistry is ITierRegistry, Migration {
using SafeERC20 for IERC20;

/*//////////////////////////////////////////////////////////////
Expand All @@ -27,7 +26,7 @@ contract TierRegistry is ITierRegistry, Ownable2Step, Pausable {
string public constant VERSION = "2025.06.01";

/*//////////////////////////////////////////////////////////////
STORAGE
STORAGE
//////////////////////////////////////////////////////////////*/

/**
Expand All @@ -41,7 +40,7 @@ contract TierRegistry is ITierRegistry, Ownable2Step, Pausable {
/**
* @inheritdoc ITierRegistry
*/
uint256 public nextTierId;
uint256 public nextTierId = 1;

/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
Expand All @@ -50,14 +49,10 @@ contract TierRegistry is ITierRegistry, Ownable2Step, Pausable {
/**
* @notice Set the initial parameters and pause the contract.
*
* @param _migrator Migrator address.
* @param _initialOwner Initial owner address.
*/
constructor(
address _initialOwner
) {
_transferOwnership(_initialOwner);
_pause();
}
constructor(address _migrator, address _initialOwner) Migration(24 hours, _migrator, _initialOwner) {}

/*//////////////////////////////////////////////////////////////
VIEWS
Expand Down Expand Up @@ -123,21 +118,36 @@ contract TierRegistry is ITierRegistry, Ownable2Step, Pausable {
if (numDays < info.minDays) revert InvalidDuration();
if (numDays > info.maxDays) revert InvalidDuration();
totalCost += info.tokenPricePerDay * numDays;
}

for (uint256 i; i < fids.length; ++i) {
// The payer field in the event will point to a contract if the caller is a contract
emit PurchasedTier(fids[i], tier, forDays[i], msg.sender);
}

// Payment is made in a single transaction to save gas
info.paymentToken.safeTransferFrom(msg.sender, info.vault, totalCost);
}

/*//////////////////////////////////////////////////////////////
PERMISSIONED ACTIONS
//////////////////////////////////////////////////////////////*/

/**
* @inheritdoc ITierRegistry
*/
function batchCreditTier(uint256 tier, uint256[] calldata fids, uint256 forDays) external onlyMigrator {
if (fids.length == 0) revert InvalidBatchInput();

TierInfo memory info = _tierInfoByTier[tier];
if (!info.isActive) revert InvalidTier();

for (uint256 i; i < fids.length; ++i) {
if (forDays == 0) revert InvalidDuration();
if (forDays < info.minDays) revert InvalidDuration();
if (forDays > info.maxDays) revert InvalidDuration();
emit PurchasedTier(fids[i], tier, forDays, msg.sender);
}
}

/**
* @inheritdoc ITierRegistry
*/
function setTier(
uint256 tier,
address paymentToken,
Expand All @@ -152,6 +162,7 @@ contract TierRegistry is ITierRegistry, Ownable2Step, Pausable {
if (minDays > maxDays) revert InvalidDuration();
if (tokenPricePerDay == 0) revert InvalidPrice();
if (vault == address(0)) revert InvalidVaultAddress();
if (tier == 0) revert InvalidTier();
if (tier > nextTierId) revert InvalidTier();

emit SetTier(tier, minDays, maxDays, vault, paymentToken, tokenPricePerDay);
Expand Down Expand Up @@ -186,14 +197,9 @@ contract TierRegistry is ITierRegistry, Ownable2Step, Pausable {
/**
* @inheritdoc ITierRegistry
*/
function pause() external onlyOwner {
_pause();
}

/**
* @inheritdoc ITierRegistry
*/
function unpause() external onlyOwner {
_unpause();
function sweepToken(address token, address to) external onlyOwner {
uint256 balance = IERC20(token).balanceOf(address(this));
emit SweepToken(token, to, balance);
IERC20(token).safeTransfer(to, balance);
}
}
34 changes: 23 additions & 11 deletions src/interfaces/ITierRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import {IMigration} from "./abstract/IMigration.sol";
import "openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

/**
* @title ITierRegistry
* @notice Interface for the TierRegistry contract that manages tier purchases for Farcaster IDs
*/
interface ITierRegistry {
interface ITierRegistry is IMigration {
/**
* @notice Information about a user tier
* @param minDays Minimum number of days that can be purchased for this tier
Expand Down Expand Up @@ -85,6 +86,14 @@ interface ITierRegistry {
uint256 tokenPricePerDay
);

/**
* @notice Emitted when owner sweeps an ERC20 token balance
* @param token ERC20 token address
* @param to Address that receives the full balance
* @param balance Token balance sent
*/
event SweepToken(address indexed token, address to, uint256 balance);

/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
Expand All @@ -105,7 +114,7 @@ interface ITierRegistry {
function nextTierId() external view returns (uint256);

/*//////////////////////////////////////////////////////////////
GETTERS
GETTERS
//////////////////////////////////////////////////////////////*/

/**
Expand Down Expand Up @@ -149,6 +158,14 @@ interface ITierRegistry {
PERMISSIONED ACTIONS
//////////////////////////////////////////////////////////////*/

/**
* @notice Credit a tier to multiple Farcaster IDs in a single transaction
* @param tier The tier ID to credit for all FIDs
* @param fids Array of Farcaster IDs to credit for
* @param forDays Number of days to credit
*/
function batchCreditTier(uint256 tier, uint256[] calldata fids, uint256 forDays) external;

/**
* @notice Update/create a user tier configuration
* Only callable by owner.
Expand Down Expand Up @@ -178,14 +195,9 @@ interface ITierRegistry {
) external;

/**
* @notice Pause, disabling rentals and credits.
* Only callable by owner.
*/
function pause() external;

/**
* @notice Unpause, enabling rentals and credits.
* Only callable by owner.
* @notice Rescue an ERC20 token accidentally sent to this contract
* @param token The token address
* @param to Receiver address that will receive the full token balance
*/
function unpause() external;
function sweepToken(address token, address to) external;
}
4 changes: 3 additions & 1 deletion src/interfaces/abstract/IMigration.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

interface IMigration {
import {IGuardians} from "./IGuardians.sol";

interface IMigration is IGuardians {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
Expand Down
Loading
Loading