Skip to content

Commit

Permalink
Merge 3365119 into 7869b05
Browse files Browse the repository at this point in the history
  • Loading branch information
aodhgan committed Apr 28, 2021
2 parents 7869b05 + 3365119 commit 961d44b
Show file tree
Hide file tree
Showing 25 changed files with 341 additions and 715 deletions.
24 changes: 0 additions & 24 deletions .circleci/config.yml

This file was deleted.

23 changes: 23 additions & 0 deletions .github/workflows/main.yml
@@ -0,0 +1,23 @@
name: Coveralls

on: ["push", "pull_request"]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2
with:
node-version: 15.x
- name: yarn, compile, hint, coverage
run: |
yarn
yarn compile
yarn hint
yarn coverage
- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion .nvmrc
@@ -1 +1 @@
v14.15.3
15.11.0
14 changes: 5 additions & 9 deletions README.md
Expand Up @@ -7,19 +7,15 @@ PoolTogether Operations contracts is PoolTogether's integration with ChainLinks

## How it works

The goal of this system is to fully automate the awarding of the PoolTogether governance owned prize pools.
The goal of this system is to automate calling the `batch` function of the PoolTogether governance owned prize pool pods.

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.
A registry of these prize pools exists (as an Ownable MappedSinglyLinkedList) and logic is run to see if the batch function requires running. This is determined by:
- A time period (in blocks), as calculated by `upkeepBlockInterval`
- A float level calculation

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


The upkeepers performing the upkeep are compensated in LINK so the PrizeStrategyUpkeep contact needs to maintain a healthy balance of LINK.

# Installation
Install the repo and dependencies by running:
Expand Down
119 changes: 119 additions & 0 deletions contracts/PodsUpkeep.sol
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.6;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";

import "@pooltogether/pooltogether-generic-registry/contracts/AddressRegistry.sol";

import "./interfaces/IPod.sol";
import "./interfaces/KeeperCompatibleInterface.sol";


///@notice Contract implements Chainlink's Upkeep system interface, automating the upkeep of a registry of Pod contracts
contract PodsUpkeep is KeeperCompatibleInterface, Ownable {

using SafeMathUpgradeable for uint256;

/// @notice Address of the registry of pods contract which require upkeep
AddressRegistry public podsRegistry;

/// @notice Interval at which pods.batch() will be called
uint256 public upkeepBlockInterval;

/// @notice Block number when batch was last called successfully
uint256 public lastUpkeepBlockNumber;

/// @notice Minimum pod float fraction
uint256 public targetFloatFraction;

/// @notice Emitted when the upkeep block interval is updated
event UpkeepBlockIntervalUpdated(uint upkeepBlockInterval);

/// @notice Emitted when the float fraction is updated
event TargetFloatFractionUpdated(uint targetFloatFraction);


/// @notice Contract Constructor. No initializer.
constructor(AddressRegistry _podsRegistry, address _owner) Ownable() {

podsRegistry = _podsRegistry;

transferOwnership(_owner);

lastUpkeepBlockNumber = block.number;

// initialize values for block interval and float rate?
}

/// @notice Checks if Pods 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) override external view returns (bool upkeepNeeded, bytes memory performData) {

address[] memory pods = podsRegistry.getAddresses();
for(uint256 i = 0; i < pods.length; i++){ // can get out of gas here -- do we want to implement a batchLimit ?
if(checkUpkeepRequired(IPod(pods[i]))){
return (true, "");
}
}
return (false, "");
}

/// @notice Performs upkeep on the pods contract
/// @param performData Not used in this implementation.
function performUpkeep(bytes calldata performData) override external {

address[] memory pods = podsRegistry.getAddresses();
for(uint256 i = 0; i < pods.length; i++){
(bool required, uint256 batchAmount) = amountAboveFloat(IPod(pods[i]));
if(required) {
require(IPod(pods[i]).batch(batchAmount), "PodsUpkeep: batch() failed");
}
}
}

/// @notice Checks if the float conditions indicate that upkeep is required
/// @param pod The pod for which the check is carried out
function checkUpkeepRequired(IPod pod) internal view returns (bool) {

(bool aboveFloat, uint256 amount) = amountAboveFloat(pod);

if(block.number >= lastUpkeepBlockNumber + upkeepBlockInterval && aboveFloat){
return true;
}
return false;
}

/// @notice Checks the amount
/// @param _pod The pod for which the check is carried out
function amountAboveFloat(IPod _pod) public view returns (bool aboveFloat, uint256 batchAmount) {

uint256 vaultTokenBalance = _pod.vaultTokenBalance();
uint256 targetFloat = vaultTokenBalance.mul(targetFloatFraction).div(1 ether); // are these going to be appropriate decimals

if(vaultTokenBalance > targetFloat){
batchAmount = vaultTokenBalance - targetFloat;
return (true, batchAmount);
}

return (false, 0);
}

/// @notice Updates the upkeepBlockInterval. Can only be called by the contract owner
/// @param _upkeepBlockInterval The new upkeepBlockInterval (in blocks)
function updateBlockUpkeepInterval(uint256 _upkeepBlockInterval) external onlyOwner {
upkeepBlockInterval = _upkeepBlockInterval;
emit UpkeepBlockIntervalUpdated(_upkeepBlockInterval);
}

/// @notice Performs upkeep on the pods contract
/// @param _targetFloatFraction The new targetFloatFraction
/// @dev Should account for number of decimals of pod
function updateTargetFloatFraction(uint256 _targetFloatFraction) external onlyOwner {
targetFloatFraction = _targetFloatFraction;
emit TargetFloatFractionUpdated(_targetFloatFraction);
}

}
52 changes: 0 additions & 52 deletions contracts/PrizePoolRegistry.sol

This file was deleted.

79 changes: 0 additions & 79 deletions contracts/PrizeStrategyUpkeep.sol

This file was deleted.

14 changes: 14 additions & 0 deletions contracts/interfaces/IPod.sol
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.6;


interface IPod {
/// @notice Allows someone to batch deposit funds into the underlying prize pool. This should be called periodically.
/// @dev This function should deposit the float into the prize pool, and claim any POOL tokens and distribute to users (possibly via adaptation of Token Faucet)
function batch(uint256 batchAmount) external returns (bool);


function vaultTokenBalance() external view returns (uint256);

}
9 changes: 0 additions & 9 deletions contracts/interfaces/PeriodicPrizeStrategyInterface.sol

This file was deleted.

7 changes: 0 additions & 7 deletions contracts/interfaces/PrizePoolInterface.sol

This file was deleted.

7 changes: 0 additions & 7 deletions contracts/interfaces/PrizePoolRegistryInterface.sol

This file was deleted.

0 comments on commit 961d44b

Please sign in to comment.