-
Notifications
You must be signed in to change notification settings - Fork 2
Create: Allo strategy contract to accept donations to allo pool and allocate them to Hyperfund and Hyperstaker #54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
18079e0
f503225
a9f9710
d9ec3f5
ea7b421
4282bf7
67eb4b9
9379e82
5665e72
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
{ | ||
"language": "Solidity", | ||
"settings": { | ||
"optimizer": { | ||
"enabled": true, | ||
"runs": 200 | ||
}, | ||
"outputSelection": { | ||
"*": { | ||
"": [ | ||
"ast" | ||
], | ||
"*": [ | ||
"abi", | ||
"metadata", | ||
"devdoc", | ||
"userdoc", | ||
"storageLayout", | ||
"evm.legacyAssembly", | ||
"evm.bytecode", | ||
"evm.deployedBytecode", | ||
"evm.methodIdentifiers", | ||
"evm.gasEstimates", | ||
"evm.assembly" | ||
] | ||
} | ||
}, | ||
"remappings": [ | ||
"ds-test/=lib/forge-std/lib/ds-test/src/", | ||
"forge-std/=lib/forge-std/src/", | ||
"strategies/=lib/allo-v2.1/contracts/strategies/", | ||
"libraries/=lib/allo-v2.1/contracts/core/libraries/", | ||
"solady/=lib/allo-v2.1/lib/solady/src/" | ||
] | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.19; | ||
|
||
import {AccessControl} from "lib/allo-v2.1/lib/openzeppelin-contracts/contracts/access/AccessControl.sol"; | ||
import {BaseStrategy} from "strategies/BaseStrategy.sol"; | ||
import {IAllo} from "lib/allo-v2.1/contracts/core/interfaces/IAllo.sol"; | ||
import {IHypercertToken} from "./interfaces/IHypercertToken.sol"; | ||
import {IHyperfund} from "./interfaces/IHyperfund.sol"; | ||
|
||
contract HyperStrategy is AccessControl, BaseStrategy { | ||
// Roles | ||
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE"); | ||
|
||
// Interfaces | ||
IHyperfund public hyperfund; | ||
IHypercertToken public hypercertMinter; | ||
|
||
// Events | ||
event Donated(address indexed donor, address token, uint256 amount, uint256 indexed hypercertUnits); | ||
|
||
// Errors | ||
error NOOP(); | ||
|
||
function initialize(uint256 _poolId, bytes memory _data) external virtual override { | ||
(address _manager, address _hyperfund) = abi.decode(_data, (address, address)); | ||
|
||
hyperfund = IHyperfund(_hyperfund); | ||
hypercertMinter = IHypercertToken(hyperfund.hypercertMinter()); | ||
|
||
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender); | ||
_grantRole(MANAGER_ROLE, _manager); | ||
__BaseStrategy_init(_poolId); | ||
emit Initialized(_poolId, _data); | ||
} | ||
|
||
/// =============================== | ||
/// ========= Constructor ========= | ||
/// =============================== | ||
constructor(address _allo, string memory _name) BaseStrategy(_allo, _name) {} | ||
|
||
/// @notice Allocate funds hyperfund and hyperstaker pools | ||
/// @param _data The data to decode | ||
/// @param _sender The sender | ||
function _allocate(bytes memory _data, address _sender) internal virtual override onlyRole(MANAGER_ROLE) { | ||
(address[] memory _recipients, uint256[] memory _amounts) = abi.decode(_data, (address[], uint256[])); | ||
|
||
// Assert recipient and amounts length are equal | ||
if (_recipients.length != _amounts.length) { | ||
revert ARRAY_MISMATCH(); | ||
} | ||
|
||
IAllo.Pool memory pool = allo.getPool(poolId); | ||
for (uint256 i; i < _recipients.length; ++i) { | ||
uint256 _amount = _amounts[i]; | ||
address _recipientAddress = _recipients[i]; | ||
|
||
_transferAmount(pool.token, _recipientAddress, _amount); | ||
|
||
emit Allocated(_recipientAddress, _amount, pool.token, _sender); | ||
} | ||
} | ||
|
||
function _afterIncreasePoolAmount(uint256 _amount) internal virtual override { | ||
IAllo.Pool memory pool = allo.getPool(poolId); | ||
uint256 hypercertFraction = hyperfund.hypercertId(); | ||
int256 multiplier = hyperfund.tokenMultipliers(pool.token); | ||
uint256 units; | ||
if (multiplier > 0) { | ||
units = _amount * uint256(multiplier); | ||
} else { | ||
units = _amount / uint256(-multiplier); | ||
} | ||
|
||
uint256 availableSupply = hypercertMinter.unitsOf(hypercertFraction); | ||
require(availableSupply >= units); | ||
_mintFraction(tx.origin, units, hypercertFraction); | ||
emit Donated(tx.origin, pool.token, _amount, units); | ||
} | ||
|
||
function _distribute(address[] memory _recipientIds, bytes memory _recipientAmounts, address _sender) | ||
internal | ||
virtual | ||
override | ||
{ | ||
revert NOOP(); | ||
} | ||
|
||
function _getRecipientStatus(address) internal view virtual override returns (Status) { | ||
revert NOOP(); | ||
} | ||
|
||
function _isValidAllocator(address _allocator) internal view virtual override returns (bool) {} | ||
|
||
function _registerRecipient(bytes memory _data, address _sender) internal virtual override returns (address) {} | ||
|
||
function _getPayout(address _recipientId, bytes memory _data) | ||
internal | ||
view | ||
virtual | ||
override | ||
returns (PayoutSummary memory) | ||
{} | ||
|
||
function _mintFraction(address account, uint256 units, uint256 hypercertId) internal { | ||
uint256[] memory newallocations = new uint256[](2); | ||
newallocations[0] = hypercertMinter.unitsOf(hypercertId) - units; | ||
newallocations[1] = units; | ||
hypercertMinter.splitFraction(account, hypercertId, newallocations); | ||
} | ||
|
||
receive() external payable {} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Creating a seperate factory for compatibility issues | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.19; | ||
|
||
import "./HyperStrategy.sol"; // Import Hyperstrategy contract | ||
|
||
contract HyperStrategyFactory { | ||
address hypercertMinter; | ||
|
||
// Event to emit when a new HyperStrategy is created | ||
event HyperstrategyCreated(address indexed hyperstrategyAddress, address allo); | ||
|
||
constructor(address _hypercertMinter) { | ||
require(_hypercertMinter != address(0)); | ||
hypercertMinter = _hypercertMinter; | ||
} | ||
|
||
// Function to create a new Hyperstrategy | ||
function createHyperstrategy(address _allo, string memory _name) external returns (address) { | ||
require(_allo != address(0)); | ||
|
||
address newHyperStrategy = address(new HyperStrategy(_allo, _name)); | ||
require(newHyperStrategy != address(0)); | ||
|
||
IHypercertToken(hypercertMinter).setApprovalForAll(newHyperStrategy, true); | ||
emit HyperstrategyCreated(newHyperStrategy, _allo); | ||
return newHyperStrategy; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,8 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
// SPDX-License-Identifier: UNLICENSED | ||||||||||||||||||||||||||||||||||||||||||||||||||||
pragma solidity ^0.8.19; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
interface IHyperfund { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
function hypercertId() external view returns (uint256); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
function tokenMultipliers(address token) external view returns (int256); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
function hypercertMinter() external view returns (address); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+4
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add documentation to explain interface functions The interface lacks documentation explaining the purpose and expected behavior of each function. Consider adding NatSpec comments to improve code readability and maintainability. interface IHyperfund {
+ /**
+ * @notice Returns the ID of the hypercert associated with this fund
+ * @return The hypercert ID
+ */
function hypercertId() external view returns (uint256);
+
+ /**
+ * @notice Returns the multiplier for a given token
+ * @param token The address of the token
+ * @return The multiplier value for the token (can be negative)
+ */
function tokenMultipliers(address token) external view returns (int256);
+
+ /**
+ * @notice Returns the address of the hypercert minter contract
+ * @return The address of the hypercert minter
+ */
function hypercertMinter() external view returns (address);
} 📝 Committable suggestion
Suggested change
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Prevent multiple calls to
initialize(...)
You’re using a standalone
initialize
function, but there’s no safeguard against being called more than once. To avoid re-initialization issues and maintain security, consider usinginitializer
modifiers (e.g., from OpenZeppelin) or adding a guard to ensure it’s invoked only once.