Skip to content

Commit

Permalink
Add poc Hedgey Strategy (#319)
Browse files Browse the repository at this point in the history
* Add hedgey strategy poc

* remove unused error

* Correct formatting (forge fmt)

* Add missing events

* Add new events to tests

* Fix & tests for withdraw

* Remove duplicate event

* Restore version from main (with virtual)

* Update register methods

* Rerun fmt
  • Loading branch information
TheShobo authored Jan 9, 2024
1 parent 018640f commit 3c19092
Show file tree
Hide file tree
Showing 9 changed files with 561 additions and 6 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
[submodule "lib/permit2"]
path = lib/permit2
url = https://github.com/Uniswap/permit2
[submodule "lib/hedgey-vesting"]
path = lib/hedgey-vesting
url = https://github.com/hedgey-finance/Locked_VestingTokenPlans
[submodule "lib/hats-protocol"]
path = lib/hats-protocol
url = https://github.com/Hats-Protocol/hats-protocol
Expand Down
10 changes: 7 additions & 3 deletions contracts/core/libraries/Transfer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ contract Transfer is Native {
/// @param _token The address of the token
/// @param _transferData TransferData[]
/// @return Whether the transfer was successful or not
function _transferAmountsFrom(address _token, TransferData[] memory _transferData) internal returns (bool) {
function _transferAmountsFrom(address _token, TransferData[] memory _transferData)
internal
virtual
returns (bool)
{
uint256 msgValue = msg.value;

for (uint256 i; i < _transferData.length;) {
Expand All @@ -67,7 +71,7 @@ contract Transfer is Native {
/// @param _token The address of the token
/// @param _transferData Individual TransferData
/// @return Whether the transfer was successful or not
function _transferAmountFrom(address _token, TransferData memory _transferData) internal returns (bool) {
function _transferAmountFrom(address _token, TransferData memory _transferData) internal virtual returns (bool) {
uint256 amount = _transferData.amount;
if (_token == NATIVE) {
// Native Token
Expand All @@ -84,7 +88,7 @@ contract Transfer is Native {
/// @param _token The token to transfer
/// @param _to The address to transfer to
/// @param _amount The amount to transfer
function _transferAmount(address _token, address _to, uint256 _amount) internal {
function _transferAmount(address _token, address _to, uint256 _amount) internal virtual {
if (_token == NATIVE) {
SafeTransferLib.safeTransferETH(_to, _amount);
} else {
Expand Down
145 changes: 145 additions & 0 deletions contracts/strategies/_poc/hedgey/HedgeyRFPCommitteeStrategy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;

// Core Contracts
import {RFPCommitteeStrategy} from "../../rfp-committee/RFPCommitteeStrategy.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

// Internal Libraries
import {Metadata} from "../../../core/libraries/Metadata.sol";

interface ITokenVestingPlans {
function createPlan(
address recipient,
address token,
uint256 amount,
uint256 start,
uint256 cliff,
uint256 rate,
uint256 period,
address vestingAdmin,
bool adminTransferOBO
) external returns (uint256 newPlanId);
}

contract HedgeyRFPCommitteeStrategy is RFPCommitteeStrategy {
/// ================================
/// ========== Storage =============
/// ================================

mapping(address => uint256) internal _recipientLockupTerm;

struct HedgeyInitializeParamsCommittee {
bool adminTransferOBO;
address hedgeyContract;
address adminAddress;
InitializeParamsCommittee params;
}

bool public adminTransferOBO;
address public hedgeyContract;
address public adminAddress;

/// ===============================
/// ========== Events =============
/// ===============================

event AdminAddressUpdated(address adminAddress, address sender);
event AdminTransferOBOUpdated(bool adminTransferOBO, address sender);

/// ===============================
/// ======== Constructor ==========
/// ===============================

constructor(address _allo, string memory _name) RFPCommitteeStrategy(_allo, _name) {}

/// ===============================
/// ========= Initialize ==========
/// ===============================

function initialize(uint256 _poolId, bytes memory _data) external override {
(HedgeyInitializeParamsCommittee memory hedgeyInitializeParamsCommittee) =
abi.decode(_data, (HedgeyInitializeParamsCommittee));
__HedgeyRPFCommiteeStrategy_init(_poolId, hedgeyInitializeParamsCommittee);
}

function __HedgeyRPFCommiteeStrategy_init(
uint256 _poolId,
HedgeyInitializeParamsCommittee memory _hedgeyInitializeParamsCommittee
) internal {
// Initialize the RPFCommiteeStrategy
__RPFCommiteeStrategy_init(_poolId, _hedgeyInitializeParamsCommittee.params);

// Set the strategy specific variables
adminTransferOBO = _hedgeyInitializeParamsCommittee.adminTransferOBO;
hedgeyContract = _hedgeyInitializeParamsCommittee.hedgeyContract;
adminAddress = _hedgeyInitializeParamsCommittee.adminAddress;
}

/// ===============================
/// ======= External/Custom =======
/// ===============================

/// @notice Update the default Admin wallet used when creating Hedgey plans
/// @param _adminAddress The admin wallet to use
function setAdminAddress(address _adminAddress) external onlyPoolManager(msg.sender) {
adminAddress = _adminAddress;
emit AdminAddressUpdated(_adminAddress, msg.sender);
}

/// @notice Update the default Admin wallet used when creating Hedgey plans
/// @param _adminTransferOBO Set if the admin is allowed to transfer on behalf of the recipient
function setAdminTransferOBO(bool _adminTransferOBO) external onlyPoolManager(msg.sender) {
adminTransferOBO = _adminTransferOBO;
emit AdminTransferOBOUpdated(_adminTransferOBO, msg.sender);
}

/// @notice Get the lockup term for a recipient
/// @param _recipient The recipient to get the lockup term for
function getRecipientLockupTerm(address _recipient) external view returns (uint256) {
return _recipientLockupTerm[_recipient];
}

/// @notice Withdraw the tokens from the pool
/// @dev Callable by the pool manager
/// @param _token The token to withdraw
function withdraw(address _token) external virtual override onlyPoolManager(msg.sender) onlyInactivePool {
uint256 amount = _getBalance(_token, address(this));

// Transfer the tokens to the 'msg.sender' (pool manager calling function)
super._transferAmount(_token, msg.sender, amount);
}

/// ====================================
/// ============ Internal ==============
/// ====================================

function _transferAmount(address _token, address _recipient, uint256 _amount) internal override {
IERC20(_token).approve(hedgeyContract, _amount);

uint256 rate = _amount / _recipientLockupTerm[_recipient];
ITokenVestingPlans(hedgeyContract).createPlan(
_recipient,
_token,
_amount,
block.timestamp,
0, // No cliff
rate,
1, // Linear period
adminAddress,
adminTransferOBO
);
}

/// ====================================
/// ============== Hooks ===============
/// ====================================

function _afterRegisterRecipient(bytes memory _data, address) internal override {
uint256 lockupTerm;
address recipientAddress;
(, recipientAddress,,, lockupTerm) = abi.decode(_data, (address, address, uint256, Metadata, uint256));

_recipientLockupTerm[recipientAddress] = lockupTerm;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ contract RFPCommitteeStrategy is RFPSimpleStrategy {
/// @param _poolId ID of the pool
/// @param _data The data to be decoded
/// @custom:data (uint256 voteThreshold, InitializeParams params)
function initialize(uint256 _poolId, bytes memory _data) external override {
function initialize(uint256 _poolId, bytes memory _data) external virtual override {
(InitializeParamsCommittee memory initializeParamsCommittee) = abi.decode(_data, (InitializeParamsCommittee));
__RPFCommiteeStrategy_init(_poolId, initializeParamsCommittee);
emit Initialized(_poolId, _data);
Expand Down
2 changes: 1 addition & 1 deletion contracts/strategies/rfp-simple/RFPSimpleStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ contract RFPSimpleStrategy is BaseStrategy, ReentrancyGuard {
/// @notice Withdraw the tokens from the pool
/// @dev Callable by the pool manager
/// @param _token The token to withdraw
function withdraw(address _token) external onlyPoolManager(msg.sender) onlyInactivePool {
function withdraw(address _token) external virtual onlyPoolManager(msg.sender) onlyInactivePool {
uint256 amount = _getBalance(_token, address(this));

// Transfer the tokens to the 'msg.sender' (pool manager calling function)
Expand Down
1 change: 1 addition & 0 deletions lib/hedgey-vesting
Submodule hedgey-vesting added at 083fa5
3 changes: 2 additions & 1 deletion remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ hats-protocol/=lib/hats-protocol/src/
@superfluid-finance/=lib/superfluid-protocol-monorepo/packages/
solady/=lib/solady/src/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
lib/ERC1155/=lib/hats-protocol/lib/ERC1155/
lib/ERC1155/=lib/hats-protocol/lib/ERC1155/
hedgey-vesting/=lib/hedgey-vesting/contracts/
Loading

0 comments on commit 3c19092

Please sign in to comment.