Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Signed-off-by: Matt Rice <[email protected]>
  • Loading branch information
mrice32 committed May 18, 2024
1 parent a82b3a7 commit cfb417a
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 46 deletions.
1 change: 1 addition & 0 deletions src/factories/BaseFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ contract BaseFactory is Ownable {
address[] public defaultUnlockers;

event DefaultUnlockersSet(address[] defaultUnlockers);
event OvalDeployed(address indexed deployer, address indexed oval, uint256 indexed lockWindow, uint256 maxTraversal, address owner, address[] unlockers);

constructor(uint256 maxTraversal, address[] memory _defaultUnlockers) {
MAX_TRAVERSAL = maxTraversal;
Expand Down
16 changes: 9 additions & 7 deletions src/factories/StandardChainlinkFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ import {IAggregatorV3Source} from "../interfaces/chainlink/IAggregatorV3Source.s
import {BaseFactory} from "./BaseFactory.sol";

/**
* @title StandardOvalChainlink is the recommended Oval Chainlink contract that allows Oval to extract OEV generated by
* @title OvalChainlink is the recommended Oval Chainlink contract that allows Oval to extract OEV generated by
* Chainlink usage.
*/
contract StandardOvalChainlink is MutableUnlockersController, ChainlinkSourceAdapter, ChainlinkDestinationAdapter {
constructor(IAggregatorV3Source source, address[] memory unlockers, uint256 _lockWindow, uint256 _maxTraversal, address owner)
contract OvalChainlink is MutableUnlockersController, ChainlinkSourceAdapter, ChainlinkDestinationAdapter {
constructor(IAggregatorV3Source source, address[] memory unlockers, uint256 lockWindow, uint256 maxTraversal, address owner)
ChainlinkSourceAdapter(source)
MutableUnlockersController(_lockWindow, _maxTraversal, unlockers)
MutableUnlockersController(lockWindow, maxTraversal, unlockers)
ChainlinkDestinationAdapter(source.decimals())
{
_transferOwnership(owner);
}
}

/**
* @title StandardChainlinkFactory is the reccomended factory for use cases that want a Chainlink source and Chainlink
* @title StandardChainlinkFactory is the recommended factory for use cases that want a Chainlink source and Chainlink
* interface.
* @dev This is the best factory for most use cases, but there are other variants that may be needed if different
* mutability choices are desired.
Expand All @@ -36,8 +36,10 @@ contract StandardChainlinkFactory is Ownable, BaseFactory {
* @param source the Chainlink oracle source contract.
* @param lockWindow the lockWindow used for this Oval instance. This is the length of the window
* for the Oval auction to be run and, thus, the maximum time that prices will be delayed.
* @return oval deployed oval address.
*/
function create(IAggregatorV3Source source, uint256 lockWindow) external returns (address) {
return address(new StandardOvalChainlink(source, defaultUnlockers, lockWindow, MAX_TRAVERSAL, owner()));
function create(IAggregatorV3Source source, uint256 lockWindow) external returns (address oval) {
oval = address(new OvalChainlink(source, defaultUnlockers, lockWindow, MAX_TRAVERSAL, owner()));
emit OvalDeployed(msg.sender, oval, lockWindow, MAX_TRAVERSAL, owner(), defaultUnlockers);
}
}
46 changes: 46 additions & 0 deletions src/factories/StandardChronicleFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;

import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol";
import {MutableUnlockersController} from "../controllers/MutableUnlockersController.sol";
import {ChronicleMedianSourceAdapter} from "../adapters/source-adapters/ChronicleMedianSourceAdapter.sol";
import {ChainlinkDestinationAdapter} from "../adapters/destination-adapters/ChainlinkDestinationAdapter.sol";
import {IAggregatorV3Source} from "../interfaces/chainlink/IAggregatorV3Source.sol";
import {BaseFactory} from "./BaseFactory.sol";
import {IMedian} from "../interfaces/chronicle/IMedian.sol";

/**
* @title OvalChronicle is the reccomended Oval contract that allows Oval to extract OEV generated by
* Chronicle price feeds and allow usage via the Chainlink interface.
*/
contract OvalChronicle is MutableUnlockersController, ChronicleMedianSourceAdapter, ChainlinkDestinationAdapter {
constructor(IMedian source, address[] memory unlockers, uint256 lockWindow, uint256 maxTraversal, address owner)
ChronicleMedianSourceAdapter(source)
MutableUnlockersController(lockWindow, maxTraversal, unlockers)
ChainlinkDestinationAdapter(18)
{
_transferOwnership(owner);
}
}

/**
* @title StandardPythFactory is the recommended factory for use cases that want a Chronicle source and Chainlink
* interface.
* @dev This is the best factory for most use cases that need a Chronicle source, but there are other variants that may be
* needed if different mutability or interface choices are desired.
*/
contract StandardChronicleFactory is Ownable, BaseFactory {
constructor(uint256 maxTraversal, address[] memory _defaultUnlockers) BaseFactory(maxTraversal, _defaultUnlockers) {}

/**
* @notice Creates the Pyth Oval instance.
* @param chronicle Chronicle source contract.
* @param lockWindow the lockWindow used for this Oval instance. This is the length of the window
* for the Oval auction to be run and, thus, the maximum time that prices will be delayed.
* @return oval deployed oval address.
*/
function create(IMedian chronicle, uint256 lockWindow) external returns (address oval) {
oval = address(new OvalChronicle(chronicle, defaultUnlockers, lockWindow, MAX_TRAVERSAL, owner()));
emit OvalDeployed(msg.sender, oval, lockWindow, MAX_TRAVERSAL, owner(), defaultUnlockers);
}
}
83 changes: 47 additions & 36 deletions src/factories/StandardPythFactory.sol
Original file line number Diff line number Diff line change
@@ -1,39 +1,50 @@
// // SPDX-License-Identifier: BUSL-1.1
// pragma solidity 0.8.17;
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;

// import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol";
// import {MutableUnlockersController} from "../controllers/MutableUnlockersController.sol";
// import {PythSourceAdapter} from "../adapters/source-adapters/PythSourceAdapter.sol";
// import {ChainlinkDestinationAdapter} from "../adapters/destination-adapters/ChainlinkDestinationAdapter.sol";
// import {IAggregatorV3Source} from "../interfaces/chainlink/IAggregatorV3Source.sol";
// import {BaseFactory} from "./BaseFactory.sol";
import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol";
import {MutableUnlockersController} from "../controllers/MutableUnlockersController.sol";
import {PythSourceAdapter} from "../adapters/source-adapters/PythSourceAdapter.sol";
import {ChainlinkDestinationAdapter} from "../adapters/destination-adapters/ChainlinkDestinationAdapter.sol";
import {IAggregatorV3Source} from "../interfaces/chainlink/IAggregatorV3Source.sol";
import {BaseFactory} from "./BaseFactory.sol";
import {IPyth} from "../interfaces/pyth/IPyth.sol";

// /**
// * @title OvalPyth is the reccomended Oval contract that allows Oval to extract OEV generated by
// * Pyth price feeds and allow usage via the Chainlink interface.
// */
// contract OvalPyth is MutableUnlockersController, PythSourceAdapter, ChainlinkDestinationAdapter {
// constructor(IAggregatorV3Source source, address[] memory unlockers, uint256 _lockWindow, uint256 _maxTraversal, address owner)
// PythSourceAdapter(source)
// MutableUnlockersController(_lockWindow, _maxTraversal, unlockers)
// ChainlinkDestinationAdapter(source.decimals())
// {
// _transferOwnership(owner);
// }
// }
/**
* @title OvalPyth is the reccomended Oval contract that allows Oval to extract OEV generated by
* Pyth price feeds and allow usage via the Chainlink interface.
*/
contract OvalPyth is MutableUnlockersController, PythSourceAdapter, ChainlinkDestinationAdapter {
constructor(IPyth source, bytes32 pythPriceId, address[] memory unlockers, uint256 lockWindow, uint256 maxTraversal, address owner)
PythSourceAdapter(source, pythPriceId)
MutableUnlockersController(lockWindow, maxTraversal, unlockers)
ChainlinkDestinationAdapter(18)
{
_transferOwnership(owner);
}
}

// /**
// * @title StandardChainlinkFactory is the reccomended factory for Chainlink source/destination contracts that allow
// * Oval to extract OEV generated by Chainlink usage.
// */
// contract StandardChainlinkFactory is Ownable {
// /**
// * @notice Creates the Chainlink Oval instance.
// * @param source the Chainlink oracle source contract.
// * @param lockWindow the lockWindow used for this Oval instance. This is the length of the window
// * for the Oval auction to be run and, thus, the maximum time that prices will be delayed.
// */
// function create(IAggregatorV3Source source, uint256 lockWindow) external returns (address) {
// return address(new OvalChainlink(source, defaultUnlockers, lockWindow, MAX_TRAVERSAL, owner()));
// }
// }
/**
* @title StandardPythFactory is the recommended factory for use cases that want a Pyth source and Chainlink
* interface.
* @dev This is the best factory for most use cases that need a Pyth source, but there are other variants that may be
* needed if different mutability or interface choices are desired.
*/
contract StandardPythFactory is Ownable, BaseFactory {
IPyth immutable pyth;

constructor(IPyth _pyth, uint256 maxTraversal, address[] memory _defaultUnlockers) BaseFactory(maxTraversal, _defaultUnlockers) {
pyth = _pyth;
}

/**
* @notice Creates the Pyth Oval instance.
* @param pythPriceId the Pyth price id.
* @param lockWindow the lockWindow used for this Oval instance. This is the length of the window
* for the Oval auction to be run and, thus, the maximum time that prices will be delayed.
* @return oval deployed oval address.
*/
function create(bytes32 pythPriceId, uint256 lockWindow) external returns (address oval) {
oval = address(new OvalPyth(pyth, pythPriceId, defaultUnlockers, lockWindow, MAX_TRAVERSAL, owner()));
emit OvalDeployed(msg.sender, oval, lockWindow, MAX_TRAVERSAL, owner(), defaultUnlockers);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {StandardChainlinkFactory} from "../../src/factories/StandardChainlinkFactory.sol";
import {StandardOvalChainlink} from "../../src/factories/StandardChainlinkFactory.sol";
import {OvalChainlink} from "../../src/factories/StandardChainlinkFactory.sol";
import {IAggregatorV3Source} from "../../src/interfaces/chainlink/IAggregatorV3Source.sol";
import {MockChainlinkV3Aggregator} from "../mocks/MockChainlinkV3Aggregator.sol";
import {CommonTest} from "../Common.sol";
Expand All @@ -24,7 +24,7 @@ contract StandardChainlinkFactoryTest is CommonTest {

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

StandardOvalChainlink instance = StandardOvalChainlink(created);
OvalChainlink instance = OvalChainlink(created);
assertTrue(instance.lockWindow() == lockWindow);
assertTrue(instance.maxTraversal() == maxTraversal);

Expand All @@ -39,7 +39,7 @@ contract StandardChainlinkFactoryTest is CommonTest {
address created = factory.create(
IAggregatorV3Source(address(mockSource)), lockWindow
);
StandardOvalChainlink instance = StandardOvalChainlink(created);
OvalChainlink instance = OvalChainlink(created);

address newUnlocker = address(0x789);
instance.setUnlocker(newUnlocker, true); // Correct method to add unlockers
Expand Down
53 changes: 53 additions & 0 deletions test/unit/StandardChronicleFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;

import {StandardChronicleFactory} from "../../src/factories/StandardChronicleFactory.sol";
import {OvalChronicle} from "../../src/factories/StandardChronicleFactory.sol";
import {IMedian} from "../../src/interfaces/chronicle/IMedian.sol";
import {CommonTest} from "../Common.sol";

contract StandardChronicleFactoryTest is CommonTest {
StandardChronicleFactory factory;
IMedian mockSource;
address[] unlockers;
uint256 lockWindow = 300;
uint256 maxTraversal = 15;

function setUp() public {
mockSource = IMedian(address(0x456));
unlockers.push(address(0x123));
factory = new StandardChronicleFactory(maxTraversal, unlockers);
}

function testCreateMutableUnlockerOvalChronicle() public {
address created = factory.create(
mockSource, lockWindow
);

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

OvalChronicle instance = OvalChronicle(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 created = factory.create(
mockSource, lockWindow
);
OvalChronicle instance = OvalChronicle(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));
}
}
53 changes: 53 additions & 0 deletions test/unit/StandardPythFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;

import {StandardPythFactory} from "../../src/factories/StandardPythFactory.sol";
import {OvalPyth} from "../../src/factories/StandardPythFactory.sol";
import {IPyth} from "../../src/interfaces/pyth/IPyth.sol";
import {CommonTest} from "../Common.sol";

contract StandardPythFactoryTest is CommonTest {
StandardPythFactory factory;
IPyth mockSource;
address[] unlockers;
uint256 lockWindow = 300;
uint256 maxTraversal = 15;

function setUp() public {
mockSource = IPyth(address(0x456));
unlockers.push(address(0x123));
factory = new StandardPythFactory(mockSource, maxTraversal, unlockers);
}

function testCreateMutableUnlockerOvalPyth() public {
address created = factory.create(
bytes32(uint256(0x789)), lockWindow
);

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

OvalPyth instance = OvalPyth(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 created = factory.create(
bytes32(uint256(0x789)), lockWindow
);
OvalPyth instance = OvalPyth(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 cfb417a

Please sign in to comment.