Skip to content

Commit

Permalink
refactor(stamps): quadratic inherits linear
Browse files Browse the repository at this point in the history
  • Loading branch information
NicoAcosta committed Nov 1, 2024
1 parent d411bce commit 83e876b
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 97 deletions.
5 changes: 4 additions & 1 deletion src/points/MultipleFollowerSincePoints.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
109 changes: 13 additions & 96 deletions src/points/MultipleFollowerSincePointsQuadratic.sol
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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);
}
}

0 comments on commit 83e876b

Please sign in to comment.