Skip to content
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

feat: add AllocatorsAllowlistExtension.sol #655

Merged
merged 18 commits into from
Sep 5, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;

import {AllocationExtension} from "contracts/strategies/extensions/allocate/AllocationExtension.sol";
import {IAllocatorsAllowlistExtension} from "contracts/strategies/extensions/allocate/IAllocatorsAllowlistExtension.sol";

abstract contract AllocatorsAllowlistExtension is AllocationExtension, IAllocatorsAllowlistExtension {
/// ================================
/// ========== Storage =============
/// ================================

/// @dev allocator => isAllowed
mapping(address => bool) public allowedAllocators;

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

/// @notice Checks if the allocator is valid
/// @param _allocator The allocator address
/// @return true if the allocator is valid
function _isValidAllocator(address _allocator) internal view virtual override returns (bool) {
return allowedAllocators[_allocator];
}

/// @dev Mark an address as valid allocator
function _addAllocator(address _allocator) internal virtual {
allowedAllocators[_allocator] = true;
}

/// @dev Remove an address from the valid allocators
function _removeAllocator(address _allocator) internal virtual {
allowedAllocators[_allocator] = false;
}

// ====================================
// ==== External/Public Functions =====
// ====================================

/// @notice Add allocator
/// @dev Only the pool manager(s) can call this function and emits an `AllocatorAdded` event
/// @param _allocators The allocator addresses
function addAllocators(address[] memory _allocators) external onlyPoolManager(msg.sender) {
uint256 length = _allocators.length;
for (uint256 i = 0; i < length; i++) {
_addAllocator(_allocators[i]);
}

emit AllocatorsAdded(_allocators, msg.sender);
}

/// @notice Remove allocators
/// @dev Only the pool manager(s) can call this function and emits an `AllocatorRemoved` event
/// @param _allocators The allocator addresses
function removeAllocators(address[] memory _allocators) external onlyPoolManager(msg.sender) {
uint256 length = _allocators.length;
for (uint256 i = 0; i < length; i++) {
_removeAllocator(_allocators[i]);
}

emit AllocatorsRemoved(_allocators, msg.sender);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;

interface IAllocatorsAllowlistExtension {
/// @notice Emitted when an allocator is added
/// @param allocators The allocator addresses
/// @param sender The sender of the transaction
event AllocatorsAdded(address[] allocators, address sender);

/// @notice Emitted when an allocator is removed
/// @param allocators The allocator addresses
/// @param sender The sender of the transaction
event AllocatorsRemoved(address[] allocators, address sender);

/// @notice Returns TRUE if the allocator is allowed, FALSE otherwise
/// @param _allocator The allocator address to check
/// @return TRUE if the allocator is allowed, FALSE otherwise
function allowedAllocators(address _allocator) external view returns (bool);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import {Test} from "forge-std/Test.sol";
import {MockMockAllocatorsAllowlistExtension} from "test/smock/MockMockAllocatorsAllowlistExtension.sol";

contract AllocatorsAllowlistExtension is Test {
MockMockAllocatorsAllowlistExtension extension;

event AllocatorsAdded(address[] allocators, address sender);
event AllocatorsRemoved(address[] allocators, address sender);

function setUp() public {
extension = new MockMockAllocatorsAllowlistExtension(address(0));
}

function test__isValidAllocatorShouldReturnTRUEOrFALSEGivenTheStatusOfTheAllocator(
bool _isAllowed,
address _allocator
) external {
extension.call__addAllocator(_allocator);

if (!_isAllowed) extension.call__removeAllocator(_allocator);

// It should return TRUE or FALSE given the status of the allocator
assertEq(extension.call__isValidAllocator(_allocator), _isAllowed);
}

function test__addAllocatorShouldSetToTrueTheStatusOfTheAllocator(address _allocator) external {
extension.call__addAllocator(_allocator);

// It should set to true the status of the allocator
assertTrue(extension.allowedAllocators(_allocator));
}

function test__removeAllocatorShouldSetToFalseTheStatusOfTheAllocator(address _allocator) external {
extension.call__addAllocator(_allocator);
extension.call__removeAllocator(_allocator);

// It should set to false the status of the allocator
assertFalse(extension.allowedAllocators(_allocator));
}

function test_AddAllocatorsGivenSenderIsPoolManager(address[] memory _allocators) external {
extension.mock_call__checkOnlyPoolManager(address(this));

// It should call _addAllocator for each allocator in the list
for (uint256 i; i < _allocators.length; i++) {
extension.expectCall__addAllocator(_allocators[i]);
}

// It should emit event
vm.expectEmit();
emit AllocatorsAdded(_allocators, address(this));

extension.addAllocators(_allocators);
}

function test_RemoveAllocatorsGivenSenderIsPoolManager(address[] memory _allocators) external {
extension.mock_call__checkOnlyPoolManager(address(this));

// It should call _removeAllocator for each allocator in the list
for (uint256 i; i < _allocators.length; i++) {
extension.expectCall__removeAllocator(_allocators[i]);
}

// It should emit event
vm.expectEmit();
emit AllocatorsRemoved(_allocators, address(this));

extension.removeAllocators(_allocators);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
AllocatorsAllowlistExtension::_isValidAllocator
└── It should return TRUE or FALSE given the status of the allocator

AllocatorsAllowlistExtension::_addAllocator
└── It should set to true the status of the allocator

AllocatorsAllowlistExtension::_removeAllocator
└── It should set to false the status of the allocator

AllocatorsAllowlistExtension::addAllocators
└── Given sender is pool manager
├── It should call _addAllocator for each allocator in the list
└── It should emit event

AllocatorsAllowlistExtension::removeAllocators
└── Given sender is pool manager
├── It should call _removeAllocator for each allocator in the list
└── It should emit event
42 changes: 42 additions & 0 deletions test/utils/mocks/MockAllocatorsAllowlistExtension.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;

import {AllocatorsAllowlistExtension} from "contracts/strategies/extensions/allocate/AllocatorsAllowlistExtension.sol";
import {BaseStrategy} from "contracts/strategies/BaseStrategy.sol";

contract MockAllocatorsAllowlistExtension is BaseStrategy, AllocatorsAllowlistExtension {
constructor(address _allo) BaseStrategy(_allo) {}

function initialize(uint256 _poolId, bytes memory _data) external override {
__BaseStrategy_init(_poolId);
(
address[] memory _allowedTokens,
uint64 _allocationStartTime,
uint64 _allocationEndTime,
bool _isUsingAllocationMetadata
) = abi.decode(_data, (address[], uint64, uint64, bool));
__AllocationExtension_init(_allowedTokens, _allocationStartTime, _allocationEndTime, _isUsingAllocationMetadata);
}

function _isValidAllocator(address _allocator) internal view virtual override returns (bool) {
return super._isValidAllocator(_allocator);
}

function _addAllocator(address _allocator) internal virtual override {
super._addAllocator(_allocator);
}

function _removeAllocator(address _allocator) internal virtual override {
super._removeAllocator(_allocator);
}

function _checkOnlyPoolManager(address _sender) internal view virtual override {
super._checkOnlyPoolManager(_sender);
}

function _allocate(address[] memory, uint256[] memory, bytes memory, address) internal override {}

function _distribute(address[] memory, bytes memory, address) internal override {}

function _register(address[] memory, bytes memory, address) internal override returns (address[] memory) {}
}
Loading