Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Aodhgan
committed
Apr 16, 2021
0 parents
commit 7869b05
Showing
26 changed files
with
10,690 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
version: 2.1 | ||
orbs: | ||
coveralls: coveralls/coveralls@1.0.6 | ||
jobs: | ||
build-and-test: | ||
docker: | ||
- image: 'circleci/node:14.15.3' | ||
steps: | ||
- checkout | ||
- run: | ||
name: Install and Test | ||
no_output_timeout: 30m | ||
command: yarn && yarn hint && yarn coverage | ||
- coveralls/upload | ||
- store_artifacts: | ||
path: coverage | ||
- store_artifacts: | ||
path: test-results.xml | ||
- store_artifacts: | ||
path: coverage.json | ||
workflows: | ||
build-and-test: | ||
jobs: | ||
- build-and-test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#Builder files | ||
cache | ||
.cache-openzeppelin | ||
artifacts | ||
.history | ||
build | ||
.build-openzeppelin | ||
node_modules | ||
dist | ||
coverage | ||
coverage.json | ||
.envrc | ||
.openzeppelin/dev-* | ||
.openzeppelin/.session | ||
.oz-migrate/dev-* | ||
abis | ||
test-results.xml | ||
.DS_Store | ||
deployments/local* | ||
Networks.md | ||
deployments/fork* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
v14.15.3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
module.exports = { | ||
mocha: { reporter: 'mocha-junit-reporter' }, | ||
providerOptions: { | ||
network_id: 1337, | ||
_chainId: 1337, | ||
_chainIdRpc: 1337 | ||
}, | ||
skipFiles: [ | ||
"external", | ||
"test" | ||
] | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"extends": "solhint:recommended", | ||
"plugins": [], | ||
"rules": { | ||
"func-order": "off", | ||
"mark-callable-contracts": "off", | ||
"no-empty-blocks": "off", | ||
"compiler-version": ["error", ">=0.6.0 <0.8.0"], | ||
"private-vars-leading-underscore": "off", | ||
"code-complexity": "warn", | ||
"const-name-snakecase": "warn", | ||
"function-max-lines": "warn", | ||
"max-line-length": ["warn", 160], | ||
"avoid-suicide": "error", | ||
"avoid-sha3": "warn", | ||
"not-rely-on-time": "off", | ||
"reason-string": ["warn", {"maxLength": 64}] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# pooltogether-pods-operations | ||
|
||
[![Coverage Status](https://coveralls.io/repos/github/pooltogether/pooltogether-operations-contracts/badge.svg?branch=main)](https://coveralls.io/github/pooltogether/pooltogether-operations-contracts?branch=main) | ||
|
||
|
||
PoolTogether Operations contracts is PoolTogether's integration with ChainLinks upkeep system for pods. | ||
|
||
## How it works | ||
|
||
The goal of this system is to fully automate the awarding of the PoolTogether governance owned prize pools. | ||
|
||
A registry of these prize pools exists (as an Ownable MappedSinglyLinkedList) and the prize strategy for each prize pool checked every block (`canStartAward()` and `canCompleteAward()`) to see if upkeep is required. | ||
|
||
If upkeep is required then either `startAward()` or `completeAward()` are called on the prize pool. | ||
|
||
To prevent out-of-gas situations, a prize pool upkeep batch size is defined in the constructor. | ||
|
||
The upkeepers performing the upkeep are compensated in LINK so the PrizeStrategyUpkeep contact needs to maintain a balance of LINK. | ||
|
||
### Registry Interface | ||
|
||
|
||
|
||
# Installation | ||
Install the repo and dependencies by running: | ||
`yarn` | ||
|
||
## Deployment | ||
These contracts can be deployed to a network by running: | ||
`yarn deploy <networkName>` | ||
|
||
# Testing | ||
Run the unit tests locally with: | ||
`yarn test` | ||
|
||
## Coverage | ||
Generate the test coverage report with: | ||
`yarn coverage` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.7.6; | ||
pragma experimental ABIEncoderV2; | ||
|
||
import "@openzeppelin/contracts/access/Ownable.sol"; | ||
|
||
import "./interfaces/KeeperCompatibleInterface.sol"; | ||
import "./interfaces/PeriodicPrizeStrategyInterface.sol"; | ||
import "./interfaces/PrizePoolInterface.sol"; | ||
import "./utils/MappedSinglyLinkedList.sol"; | ||
|
||
|
||
|
||
///@notice A registry to hold Prize Pool addresses. Underlying data structure is a singly linked list. | ||
contract PrizePoolRegistry is Ownable { | ||
|
||
using MappedSinglyLinkedList for MappedSinglyLinkedList.Mapping; | ||
|
||
event PrizePoolAdded(address indexed prizePool); | ||
event PrizePoolRemoved(address indexed prizePool); | ||
|
||
MappedSinglyLinkedList.Mapping internal prizePoolList; | ||
|
||
constructor() Ownable(){ | ||
prizePoolList.initialize(); | ||
} | ||
|
||
|
||
/// @notice Returns an array of all prizePools in the linked list | ||
///@return Array of prize pool addresses | ||
function getPrizePools() view external returns(address[] memory){ | ||
return prizePoolList.addressArray(); | ||
} | ||
|
||
/// @notice Adds addresses to the linked list. Will revert if the address is already in the list. Can only be called by the Registry owner. | ||
/// @param _prizePools Array of prizePool addresses | ||
function addPrizePools(address[] calldata _prizePools) public onlyOwner { | ||
for(uint256 prizePool = 0; prizePool < _prizePools.length; prizePool++ ){ | ||
prizePoolList.addAddress(_prizePools[prizePool]); | ||
emit PrizePoolAdded(_prizePools[prizePool]); | ||
} | ||
} | ||
|
||
/// @notice Removes an address from the linked list. Can only be called by the Registry owner. | ||
/// @param _previousPrizePool The address positionally localed before the address that will be deleted. This may be the SENTINEL address if the list contains one prize pool address | ||
/// @param _prizePool The address to remove from the linked list. | ||
function removePrizePool(address _previousPrizePool, address _prizePool) public onlyOwner{ | ||
prizePoolList.removeAddress(_previousPrizePool, _prizePool); | ||
emit PrizePoolRemoved(_prizePool); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.7.6; | ||
pragma experimental ABIEncoderV2; | ||
|
||
|
||
import "./interfaces/KeeperCompatibleInterface.sol"; | ||
import "./interfaces/PeriodicPrizeStrategyInterface.sol"; | ||
import "./interfaces/PrizePoolRegistryInterface.sol"; | ||
import "./interfaces/PrizePoolInterface.sol"; | ||
import "./utils/SafeAwardable.sol"; | ||
|
||
|
||
///@notice Contract implements Chainlink's Upkeep system interface, automating the upkeep of PrizePools in the associated registry. | ||
contract PrizeStrategyUpkeep is KeeperCompatibleInterface { | ||
|
||
using SafeAwardable for address; | ||
|
||
address public prizePoolRegistry; | ||
|
||
uint public upkeepBatchSize; | ||
|
||
constructor(address _prizePoolRegistry, uint256 _upkeepBatchSize) public { | ||
prizePoolRegistry = _prizePoolRegistry; | ||
upkeepBatchSize = _upkeepBatchSize; | ||
} | ||
|
||
/// @notice Checks if PrizePools require upkeep. Call in a static manner every block by the Chainlink Upkeep network. | ||
/// @param checkData Not used in this implementation. | ||
/// @return upkeepNeeded as true if performUpkeep() needs to be called, false otherwise. performData returned empty. | ||
function checkUpkeep(bytes calldata checkData) view override external returns (bool upkeepNeeded, bytes memory performData){ // check view | ||
|
||
address[] memory prizePools = PrizePoolRegistryInterface(prizePoolRegistry).getPrizePools(); | ||
|
||
// check if canStartAward() | ||
for(uint256 pool = 0; pool < prizePools.length; pool++){ | ||
address prizeStrategy = PrizePoolInterface(prizePools[pool]).prizeStrategy(); | ||
if(prizeStrategy.canStartAward()){ | ||
return (true, performData); | ||
} | ||
} | ||
// check if canCompleteAward() | ||
for(uint256 pool = 0; pool < prizePools.length; pool++){ | ||
address prizeStrategy = PrizePoolInterface(prizePools[pool]).prizeStrategy(); | ||
if(prizeStrategy.canCompleteAward()){ | ||
return (true, performData); | ||
} | ||
} | ||
return (false, performData); | ||
} | ||
/// @notice Performs upkeep on the prize pools. | ||
/// @param performData Not used in this implementation. | ||
function performUpkeep(bytes calldata performData) override external{ | ||
|
||
address[] memory prizePools = PrizePoolRegistryInterface(prizePoolRegistry).getPrizePools(); | ||
|
||
uint256 batchCounter = upkeepBatchSize; //counter for batch | ||
uint256 poolIndex = 0; | ||
|
||
while(batchCounter > 0 && poolIndex < prizePools.length){ | ||
|
||
address prizeStrategy = PrizePoolInterface(prizePools[poolIndex]).prizeStrategy(); | ||
|
||
if(prizeStrategy.canStartAward()){ | ||
PeriodicPrizeStrategyInterface(prizeStrategy).startAward(); | ||
batchCounter--; | ||
} | ||
else if(prizeStrategy.canCompleteAward()){ | ||
PeriodicPrizeStrategyInterface(prizeStrategy).completeAward(); | ||
batchCounter--; | ||
} | ||
poolIndex++; | ||
} | ||
|
||
} | ||
|
||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity 0.7.6; | ||
|
||
interface KeeperCompatibleInterface { | ||
|
||
/** | ||
* @notice method that is simulated by the keepers to see if any work actually | ||
* needs to be performed. This method does does not actually need to be | ||
* executable, and since it is only ever simulated it can consume lots of gas. | ||
* @dev To ensure that it is never called, you may want to add the | ||
* cannotExecute modifier from KeeperBase to your implementation of this | ||
* method. | ||
* @param checkData specified in the upkeep registration so it is always the | ||
* same for a registered upkeep. This can easily be broken down into specific | ||
* arguments using `abi.decode`, so multiple upkeeps can be registered on the | ||
* same contract and easily differentiated by the contract. | ||
* @return upkeepNeeded boolean to indicate whether the keeper should call | ||
* performUpkeep or not. | ||
* @return performData bytes that the keeper should call performUpkeep with, if | ||
* upkeep is needed. If you would like to encode data to decode later, try | ||
* `abi.encode`. | ||
*/ | ||
function checkUpkeep( | ||
bytes calldata checkData | ||
) | ||
external | ||
returns ( | ||
bool upkeepNeeded, | ||
bytes memory performData | ||
); | ||
/** | ||
* @notice method that is actually executed by the keepers, via the registry. | ||
* The data returned by the checkUpkeep simulation will be passed into | ||
* this method to actually be executed. | ||
* @dev The input to this method should not be trusted, and the caller of the | ||
* method should not even be restricted to any single registry. Anyone should | ||
* be able call it, and the input should be validated, there is no guarantee | ||
* that the data passed in is the performData returned from checkUpkeep. This | ||
* could happen due to malicious keepers, racing keepers, or simply a state | ||
* change while the performUpkeep transaction is waiting for confirmation. | ||
* Always validate the data passed in. | ||
* @param performData is the data which was passed back from the checkData | ||
* simulation. If it is encoded, it can easily be decoded into other types by | ||
* calling `abi.decode`. This data should not be trusted, and should be | ||
* validated against the contract's current state. | ||
*/ | ||
function performUpkeep( | ||
bytes calldata performData | ||
) external; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.7.6; | ||
|
||
interface PeriodicPrizeStrategyInterface { | ||
function startAward() external; | ||
function completeAward() external; | ||
function canStartAward() external view returns (bool); | ||
function canCompleteAward() external view returns (bool); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.7.6; | ||
|
||
interface PrizePoolInterface { | ||
function prizeStrategy() external view returns (address); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.7.6; | ||
|
||
interface PrizePoolRegistryInterface { | ||
function getPrizePools() external view returns(address[] memory); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.7.6; | ||
|
||
import "../utils/MappedSinglyLinkedList.sol"; | ||
|
||
contract MappedSinglyLinkedListExposed { | ||
using MappedSinglyLinkedList for MappedSinglyLinkedList.Mapping; | ||
|
||
MappedSinglyLinkedList.Mapping public list; | ||
|
||
function initialize() external { | ||
list.initialize(); | ||
} | ||
|
||
function addressArray() external view returns (address[] memory) { | ||
return list.addressArray(); | ||
} | ||
|
||
function addAddresses(address[] calldata addresses) external { | ||
list.addAddresses(addresses); | ||
} | ||
|
||
function addAddress(address newAddress) external { | ||
list.addAddress(newAddress); | ||
} | ||
|
||
function removeAddress(address prevAddress, address addr) external { | ||
list.removeAddress(prevAddress, addr); | ||
} | ||
|
||
function contains(address addr) external view returns (bool) { | ||
return list.contains(addr); | ||
} | ||
|
||
function clearAll() external { | ||
list.clearAll(); | ||
} | ||
|
||
} |
Oops, something went wrong.