From 83e876b49af35ec44693bcfb138fe0c0cafa4e9b Mon Sep 17 00:00:00 2001 From: "nicoacosta.eth" Date: Fri, 1 Nov 2024 00:38:51 -0300 Subject: [PATCH] refactor(stamps): quadratic inherits linear --- src/points/MultipleFollowerSincePoints.sol | 5 +- .../MultipleFollowerSincePointsQuadratic.sol | 109 +++--------------- 2 files changed, 17 insertions(+), 97 deletions(-) diff --git a/src/points/MultipleFollowerSincePoints.sol b/src/points/MultipleFollowerSincePoints.sol index 3185936..ca3ed49 100644 --- a/src/points/MultipleFollowerSincePoints.sol +++ b/src/points/MultipleFollowerSincePoints.sol @@ -115,7 +115,10 @@ contract MultipleFollowerSincePoints is Points, IMultipleFollowerSincePoints { /// @param followerSince Timestamp when the user started following /// @param timestamp Current timestamp for calculation /// @return uint256 Calculated points, scaled to 18 decimal places - function _calculatePointsAtTimestamp(uint256 followerSince, uint256 timestamp) private pure returns (uint256) { + function _calculatePointsAtTimestamp( + uint256 followerSince, + uint256 timestamp + ) internal pure virtual returns (uint256) { uint256 durationInSeconds = timestamp - followerSince; // Convert duration to days with 18 decimal precision // 1e18 * duration / seconds_per_day diff --git a/src/points/MultipleFollowerSincePointsQuadratic.sol b/src/points/MultipleFollowerSincePointsQuadratic.sol index 460b810..a7282fb 100644 --- a/src/points/MultipleFollowerSincePointsQuadratic.sol +++ b/src/points/MultipleFollowerSincePointsQuadratic.sol @@ -1,107 +1,19 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import { Points } from "./Points.sol"; -import { IFollowerSinceStamp } from "../stamps/interfaces/IFollowerSinceStamp.sol"; +import { MultipleFollowerSincePoints } from "./MultipleFollowerSincePoints.sol"; import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; -import { IMultipleFollowerSincePoints } from "./interfaces/IMultipleFollowerSincePoints.sol"; - -/// @title MultipleFollowerSincePoints - A non-transferable token based on multiple follower durations -/// @notice This contract calculates points based on how long a user has been a follower across multiple accounts -/// @dev Inherits from Points and implements IMultipleFollowerSincePoints, using multiple IFollowerSinceStamp for duration calculation -contract MultipleFollowerSincePoints is Points, IMultipleFollowerSincePoints { - StampInfo[] private _stamps; - uint256 private immutable _stampCount; +/// @title MultipleFollowerSincePointsQuadratic - A quadratic version of MultipleFollowerSincePoints +/// @notice This contract calculates points using a quadratic formula instead of linear +/// @dev Inherits from MultipleFollowerSincePoints and overrides only the points calculation +contract MultipleFollowerSincePointsQuadratic is MultipleFollowerSincePoints { constructor( address[] memory _stampAddresses, uint256[] memory _multipliers, string memory _name, string memory _symbol - ) Points(_name, _symbol, 18) { - if (_stampAddresses.length != _multipliers.length) revert ArrayLengthMismatch(); - for (uint256 i = 0; i < _stampAddresses.length; ++i) { - _stamps.push(StampInfo(IFollowerSinceStamp(_stampAddresses[i]), _multipliers[i])); - } - _stampCount = _stampAddresses.length; - } - - /// @inheritdoc IMultipleFollowerSincePoints - function stamps() external view returns (StampInfo[] memory) { - return _stamps; - } - - /// @inheritdoc IMultipleFollowerSincePoints - function stampByIndex(uint256 index) external view returns (StampInfo memory) { - if (index >= _stamps.length) revert IndexOutOfBounds(); - return _stamps[index]; - } - - /// @inheritdoc Points - function _balanceAtTimestamp(address account, uint256 timestamp) internal view override returns (uint256) { - uint256 totalPoints; - - for (uint256 i; i < _stampCount; ) { - totalPoints += _calculatePointsForStamp(_stamps[i], account, timestamp); - unchecked { - ++i; - } - } - return totalPoints; - } - - /// @inheritdoc Points - function _totalSupplyAtTimestamp(uint256 timestamp) internal view override returns (uint256) { - uint256 totalPoints; - - for (uint256 i; i < _stampCount; ) { - totalPoints += _calculateTotalPointsForStamp(_stamps[i], timestamp); - unchecked { - ++i; - } - } - return totalPoints; - } - - /// @dev Calculates points for a specific stamp and account at a given timestamp - /// @param stampInfo The StampInfo struct containing stamp and multiplier information - /// @param account The address of the account to calculate points for - /// @param timestamp The timestamp at which to calculate points - /// @return The calculated points for the stamp and account - function _calculatePointsForStamp( - StampInfo storage stampInfo, - address account, - uint256 timestamp - ) private view returns (uint256) { - uint256 followerSince = stampInfo.stamp.getFollowerSinceTimestamp(account); - if (followerSince != 0 && followerSince <= timestamp) { - return _calculatePointsAtTimestamp(followerSince, timestamp) * stampInfo.multiplier; - } - return 0; - } - - /// @dev Calculates total points for a specific stamp at a given timestamp - /// @param stampInfo The StampInfo struct containing stamp and multiplier information - /// @param timestamp The timestamp at which to calculate total points - /// @return The calculated total points for the stamp - function _calculateTotalPointsForStamp( - StampInfo storage stampInfo, - uint256 timestamp - ) private view returns (uint256) { - uint256 totalPoints; - uint256 stampTotalSupply = stampInfo.stamp.totalSupply(); - - for (uint256 j = 1; j <= stampTotalSupply; ) { - uint256 followerSince = stampInfo.stamp.followStartTimestamp(j); - if (followerSince != 0 && followerSince <= timestamp) { - totalPoints += _calculatePointsAtTimestamp(followerSince, timestamp) * stampInfo.multiplier; - } - unchecked { - ++j; - } - } - return totalPoints; - } + ) MultipleFollowerSincePoints(_stampAddresses, _multipliers, _name, _symbol) {} /// @notice Calculates points based on the duration of following using a square root formula /// @dev Uses a square root calculation for non-linear growth curve: @@ -111,8 +23,13 @@ contract MultipleFollowerSincePoints is Points, IMultipleFollowerSincePoints { /// @param followerSince Timestamp when the user started following /// @param timestamp Current timestamp for calculation /// @return uint256 Calculated points, scaled to 18 decimal places - function _calculatePointsAtTimestamp(uint256 followerSince, uint256 timestamp) private pure returns (uint256) { + function _calculatePointsAtTimestamp( + uint256 followerSince, + uint256 timestamp + ) internal pure override returns (uint256) { uint256 durationInSeconds = timestamp - followerSince; - return (Math.sqrt(durationInSeconds) * 1e18) / Math.sqrt(86400); + uint256 scaledDuration = durationInSeconds * 1e18; + uint256 scaledDay = 86400 * 1e18; + return (Math.sqrt(scaledDuration) * 1e18) / Math.sqrt(scaledDay); } }