Skip to content

Commit

Permalink
more tests
Browse files Browse the repository at this point in the history
Signed-off-by: chrismaree <christopher.maree@gmail.com>
  • Loading branch information
chrismaree committed May 17, 2024
1 parent 0c2402f commit e6ed161
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 36 deletions.
29 changes: 19 additions & 10 deletions src/factories/ImmutableOvalChainlinkFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,37 @@ import {ChainlinkSourceAdapter} from "../adapters/source-adapters/ChainlinkSourc
import {ChainlinkDestinationAdapter} from "../adapters/destination-adapters/ChainlinkDestinationAdapter.sol";
import {IAggregatorV3Source} from "../interfaces/chainlink/IAggregatorV3Source.sol";

/**
* @title OvalChainlinkImmutable, providing an immutable controller for Oval wapped Chainlink.
*/
contract OvalChainlinkImmutable is ImmutableController, ChainlinkSourceAdapter, ChainlinkDestinationAdapter {
constructor(
IAggregatorV3Source source,
address[] memory unlockers,
uint256 _lockWindow,
uint256 _maxTraversal,
address owner
)
constructor(IAggregatorV3Source source, address[] memory unlockers, uint256 _lockWindow, uint256 _maxTraversal)
ChainlinkSourceAdapter(source)
ImmutableController(_lockWindow, _maxTraversal, unlockers)
ChainlinkDestinationAdapter(source.decimals())
{}
}

contract MutableUnlockersOvalChainlinkFactory {
/**
* @title ImmutableUnlockersOvalChainlinkFactory
* @dev Factory contract to create instances of OvalChainlinkImmutable. If Oval instances are deployed from this factory
* then downstream contracts can be sure the inheretence structure is defined correctly.
*/
contract ImmutableUnlockersOvalChainlinkFactory {
/**
* @dev Creates an instance of OvalChainlinkImmutable.
* @param source The Chainlink source aggregator. This is the address of the contract to be wrapped by Oval.
* @param lockWindow The time window during which the unlockers can operate.
* @param maxTraversal The maximum number of historical data points to traverse.
* @param unlockers Array of addresses that can unlock the controller.
* @return The address of the newly created OvalChainlinkImmutable instance.
*/
function createImmutableOvalChainlink(
IAggregatorV3Source source,
uint256 lockWindow,
uint256 maxTraversal,
address owner,
address[] memory unlockers
) external returns (address) {
return address(new OvalChainlinkImmutable(source, unlockers, lockWindow, maxTraversal, owner));
return address(new OvalChainlinkImmutable(source, unlockers, lockWindow, maxTraversal));
}
}
17 changes: 17 additions & 0 deletions src/factories/MutableUnlockersOvalChainlinkFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import {ChainlinkSourceAdapter} from "../adapters/source-adapters/ChainlinkSourc
import {ChainlinkDestinationAdapter} from "../adapters/destination-adapters/ChainlinkDestinationAdapter.sol";
import {IAggregatorV3Source} from "../interfaces/chainlink/IAggregatorV3Source.sol";

/**
* @title OvalChainlinkMutableUnlocker, providing a mutable-unlocker controller for Oval wapped Chainlink.
*/
contract OvalChainlinkMutableUnlocker is
MutableUnlockersController,
ChainlinkSourceAdapter,
Expand All @@ -26,7 +29,21 @@ contract OvalChainlinkMutableUnlocker is
}
}

/**
* @title MutableUnlockersOvalChainlinkFactory
* @dev Factory contract to create instances of OvalChainlinkMutableUnlocker. If Oval instances are deployed from this
* factory then downstream contracts can be sure the inheretence structure is defined correctly.
*/
contract MutableUnlockersOvalChainlinkFactory {
/**
* @dev Creates an instance of OvalChainlinkMutableUnlocker.
* @param source The Chainlink source aggregator. This is the address of the contract to be wrapped by Oval.
* @param lockWindow The time window during which the unlockers can operate.
* @param maxTraversal The maximum number of historical data points to traverse.
* @param owner The address that will own the created OvalChainlinkMutableUnlocker instance.
* @param unlockers Array of addresses that can unlock the controller.
* @return The address of the newly created OvalChainlinkMutableUnlocker instance.
*/
function createMutableUnlockerOvalChainlink(
IAggregatorV3Source source,
uint256 lockWindow,
Expand Down
2 changes: 1 addition & 1 deletion test/unit/BaseController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ contract TestBaseController is BaseController, MockSourceAdapter, BaseDestinatio
constructor(uint8 decimals) MockSourceAdapter(decimals) BaseController() BaseDestinationAdapter() {}
}

contract OvalUnlockLatestValue is CommonTest {
contract BaseControllerTest is CommonTest {
uint256 lastUnlockTime = 1690000000;

TestBaseController baseController;
Expand Down
26 changes: 1 addition & 25 deletions test/unit/ImmutableController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ contract TestImmutableController is ImmutableController, MockSourceAdapter, Base
{}
}

contract OvalUnlockLatestValue is CommonTest {
contract ImmutableControllerTest is CommonTest {
uint8 decimals = 8;
uint256 lockWindow = 60;
uint256 maxTraversal = 10;
Expand Down Expand Up @@ -47,28 +47,4 @@ contract OvalUnlockLatestValue is CommonTest {
function testMaxTraversalSetCorrectly() public {
assertTrue(immutableController.maxTraversal() == maxTraversal);
}

function testCannotSetUnlocker() public {
bytes4 selector = bytes4(keccak256("setUnlocker(address,bool)"));
bytes memory data = abi.encodeWithSelector(selector, random, true);
vm.prank(owner);
(bool success,) = address(immutableController).call(data);
assertFalse(success);
}

function testCannotSetLockWindow() public {
bytes4 selector = bytes4(keccak256("setLockWindow(uint256)"));
bytes memory data = abi.encodeWithSelector(selector, lockWindow + 1);
vm.prank(owner);
(bool success,) = address(immutableController).call(data);
assertFalse(success);
}

function testCannotSetMaxTraversal() public {
bytes4 selector = bytes4(keccak256("setMaxTraversal(uint256)"));
bytes memory data = abi.encodeWithSelector(selector, maxTraversal + 1);
vm.prank(owner);
(bool success,) = address(immutableController).call(data);
assertFalse(success);
}
}
37 changes: 37 additions & 0 deletions test/unit/ImmutableOvalChainlinkFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {ImmutableUnlockersOvalChainlinkFactory} from "../../src/factories/ImmutableOvalChainlinkFactory.sol";
import {OvalChainlinkImmutable} from "../../src/factories/ImmutableOvalChainlinkFactory.sol";
import {IAggregatorV3Source} from "../../src/interfaces/chainlink/IAggregatorV3Source.sol";
import {MockChainlinkV3Aggregator} from "../mocks/MockChainlinkV3Aggregator.sol";
import {CommonTest} from "../Common.sol";

contract ImmutableOvalChainlinkFactoryTest is CommonTest {
ImmutableUnlockersOvalChainlinkFactory factory;
MockChainlinkV3Aggregator mockSource;
address[] unlockers;
uint256 lockWindow = 300; // 5 minutes
uint256 maxTraversal = 15;

function setUp() public {
mockSource = new MockChainlinkV3Aggregator(8, 420); // 8 decimals
unlockers.push(address(0x123));
factory = new ImmutableUnlockersOvalChainlinkFactory();
}

function testCreateImmutableOvalChainlink() public {
address created = factory.createImmutableOvalChainlink(
IAggregatorV3Source(address(mockSource)), lockWindow, maxTraversal, unlockers
);

assertTrue(created != address(0)); // Check if the address is set, non-zero.

OvalChainlinkImmutable instance = OvalChainlinkImmutable(created);
assertTrue(instance.lockWindow() == lockWindow);
assertTrue(instance.maxTraversal() == maxTraversal);

// Check if the unlockers are set correctly
for (uint256 i = 0; i < unlockers.length; i++) {
assertTrue(instance.canUnlock(unlockers[i], 0));
}
assertFalse(instance.canUnlock(address(0x456), 0)); // Check if a random address cannot unlock
}
}
57 changes: 57 additions & 0 deletions test/unit/MutableUnlockersController.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
pragma solidity 0.8.17;

import {CommonTest} from "../Common.sol";
import {MutableUnlockersController} from "../../src/controllers/MutableUnlockersController.sol";
import {MockSourceAdapter} from "../mocks/MockSourceAdapter.sol";
import {BaseDestinationAdapter} from "../../src/adapters/destination-adapters/BaseDestinationAdapter.sol";

contract TestMutableUnlockersController is MutableUnlockersController, MockSourceAdapter, BaseDestinationAdapter {
constructor(address[] memory _unlockers)
MutableUnlockersController(300, 15, _unlockers)
MockSourceAdapter(18) // Assuming 18 decimals for the mock source adapter
BaseDestinationAdapter()
{}
}

contract MutableUnlockersControllerTest is CommonTest {
TestMutableUnlockersController mutableController;
address[] initialUnlockers;

function setUp() public {
initialUnlockers.push(permissionedUnlocker);
vm.prank(owner);
mutableController = new TestMutableUnlockersController(initialUnlockers);
}

function testInitialUnlockersCanUnlock() public {
assertTrue(mutableController.canUnlock(initialUnlockers[0], 0));
}

function testNonInitialUnlockerCannotUnlock() public {
assertFalse(mutableController.canUnlock(random, 0));
}

function testOwnerCanAddUnlocker() public {
vm.prank(owner);
mutableController.setUnlocker(random, true);
assertTrue(mutableController.canUnlock(random, 0));
}

function testOwnerCanRemoveUnlocker() public {
vm.prank(owner);
mutableController.setUnlocker(permissionedUnlocker, false);
assertFalse(mutableController.canUnlock(permissionedUnlocker, 0));
}

function testNonOwnerCannotAddUnlocker() public {
vm.prank(random);
vm.expectRevert("Ownable: caller is not the owner");
mutableController.setUnlocker(random, true);
}

function testNonOwnerCannotRemoveUnlocker() public {
vm.prank(random);
vm.expectRevert("Ownable: caller is not the owner");
mutableController.setUnlocker(permissionedUnlocker, false);
}
}
53 changes: 53 additions & 0 deletions test/unit/MutableUnlockersOvalChainlinkFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {MutableUnlockersOvalChainlinkFactory} from "../../src/factories/MutableUnlockersOvalChainlinkFactory.sol";
import {OvalChainlinkMutableUnlocker} from "../../src/factories/MutableUnlockersOvalChainlinkFactory.sol";
import {IAggregatorV3Source} from "../../src/interfaces/chainlink/IAggregatorV3Source.sol";
import {MockChainlinkV3Aggregator} from "../mocks/MockChainlinkV3Aggregator.sol";
import {CommonTest} from "../Common.sol";

contract MutableUnlockersOvalChainlinkFactoryTest is CommonTest {
MutableUnlockersOvalChainlinkFactory factory;
MockChainlinkV3Aggregator mockSource;
address[] unlockers;
uint256 lockWindow = 300;
uint256 maxTraversal = 15;

function setUp() public {
mockSource = new MockChainlinkV3Aggregator(8, 420);
unlockers.push(address(0x123));
factory = new MutableUnlockersOvalChainlinkFactory();
}

function testCreateMutableUnlockerOvalChainlink() public {
address owner = address(this);
address created = factory.createMutableUnlockerOvalChainlink(
IAggregatorV3Source(address(mockSource)), lockWindow, maxTraversal, owner, unlockers
);

assertTrue(created != address(0)); // Check if the address is set, non-zero.

OvalChainlinkMutableUnlocker instance = OvalChainlinkMutableUnlocker(created);
assertTrue(instance.lockWindow() == lockWindow);
assertTrue(instance.maxTraversal() == maxTraversal);

// Check if the unlockers are set correctly
for (uint256 i = 0; i < unlockers.length; i++) {
assertTrue(instance.canUnlock(unlockers[i], 0));
}
assertFalse(instance.canUnlock(address(0x456), 0)); // Check if a random address cannot unlock
}

function testOwnerCanChangeUnlockers() public {
address owner = address(this);
address created = factory.createMutableUnlockerOvalChainlink(
IAggregatorV3Source(address(mockSource)), lockWindow, maxTraversal, owner, unlockers
);
OvalChainlinkMutableUnlocker instance = OvalChainlinkMutableUnlocker(created);

address newUnlocker = address(0x789);
instance.setUnlocker(newUnlocker, true); // Correct method to add unlockers
assertTrue(instance.canUnlock(newUnlocker, 0));

instance.setUnlocker(address(0x123), false); // Correct method to remove unlockers
assertFalse(instance.canUnlock(address(0x123), 0));
}
}

0 comments on commit e6ed161

Please sign in to comment.