From 399d300cf3fe52edac5fcd1b207327908cd58f34 Mon Sep 17 00:00:00 2001 From: Aodhgan Date: Fri, 14 May 2021 14:27:07 -0700 Subject: [PATCH] added interval check to checkUpkeep() --- contracts/PrizeStrategyUpkeep.sol | 14 ++- deployments/rinkeby/PrizeStrategyUpkeep.json | 96 +++++++++++-------- .../4d99ccacf7db9715d082cf53f38b8750.json | 66 +++++++++++++ package.json | 2 +- 4 files changed, 133 insertions(+), 45 deletions(-) create mode 100644 deployments/rinkeby/solcInputs/4d99ccacf7db9715d082cf53f38b8750.json diff --git a/contracts/PrizeStrategyUpkeep.sol b/contracts/PrizeStrategyUpkeep.sol index 5e2bbaf..f57c908 100644 --- a/contracts/PrizeStrategyUpkeep.sol +++ b/contracts/PrizeStrategyUpkeep.sol @@ -59,8 +59,12 @@ contract PrizeStrategyUpkeep is KeeperCompatibleInterface, Ownable { /// @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) { + function checkUpkeep(bytes calldata checkData) external view override returns (bool upkeepNeeded, bytes memory performData) { + if(block.number < upkeepLastUpkeepBlockNumber + upkeepMinimumBlockInterval){ + return (false, performData); + } + address[] memory prizePools = prizePoolRegistry.getAddresses(); // check if canStartAward() @@ -82,9 +86,9 @@ contract PrizeStrategyUpkeep is KeeperCompatibleInterface, Ownable { /// @notice Performs upkeep on the prize pools. /// @param performData Not used in this implementation. - function performUpkeep(bytes calldata performData) override external { + function performUpkeep(bytes calldata performData) external override { - uint256 _upkeepLastUpkeepBlockNumber = upkeepLastUpkeepBlockNumber; + uint256 _upkeepLastUpkeepBlockNumber = upkeepLastUpkeepBlockNumber; // SLOAD require(block.number > _upkeepLastUpkeepBlockNumber + upkeepMinimumBlockInterval, "PrizeStrategyUpkeep::minimum block interval not reached"); address[] memory prizePools = prizePoolRegistry.getAddresses(); @@ -119,9 +123,9 @@ contract PrizeStrategyUpkeep is KeeperCompatibleInterface, Ownable { updatedUpkeepBlockNumber = block.number; } - // SSTORE upkeepLastUpkeepBlockNumber once + // update if required if(_upkeepLastUpkeepBlockNumber != updatedUpkeepBlockNumber){ - upkeepLastUpkeepBlockNumber = updatedUpkeepBlockNumber; + upkeepLastUpkeepBlockNumber = updatedUpkeepBlockNumber; //SSTORE emit UpkeepPerformed(startAwardCounter, completeAwardCounter); } diff --git a/deployments/rinkeby/PrizeStrategyUpkeep.json b/deployments/rinkeby/PrizeStrategyUpkeep.json index 0142e18..0476a5e 100644 --- a/deployments/rinkeby/PrizeStrategyUpkeep.json +++ b/deployments/rinkeby/PrizeStrategyUpkeep.json @@ -1,5 +1,5 @@ { - "address": "0xfc0962247f8b80BfB24159bb998D28857B0365D8", + "address": "0xaa55c780C88803Ad26e030eA00945D42a7434E68", "abi": [ { "inputs": [ @@ -12,6 +12,11 @@ "internalType": "uint256", "name": "_upkeepBatchSize", "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_upkeepMinimumBlockInterval", + "type": "uint256" } ], "stateMutability": "nonpayable", @@ -67,15 +72,15 @@ "inputs": [ { "indexed": false, - "internalType": "uint8", + "internalType": "uint256", "name": "startAwardsPerformed", - "type": "uint8" + "type": "uint256" }, { "indexed": false, - "internalType": "uint8", + "internalType": "uint256", "name": "completeAwardsPerformed", - "type": "uint8" + "type": "uint256" } ], "name": "UpkeepPerformed", @@ -256,69 +261,82 @@ "type": "function" } ], - "transactionHash": "0xa9af8df07597e7b45a9fe53062fd8c3fb652e75f6f4b99fb686737644cd1bddb", + "transactionHash": "0xa3c5ec3a2d12c2774a46cd60375a48e35b94d59b8c3e7c88195f64814f70cc80", "receipt": { "to": null, "from": "0x3F0556bCA55Bdbb78A9316936067a47fd4C4C4f4", - "contractAddress": "0xfc0962247f8b80BfB24159bb998D28857B0365D8", - "transactionIndex": 13, - "gasUsed": "957381", - "logsBloom": "0x00002000000000000000000000008000000000000000000000800000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000040000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000040000400000000200000004000000000000000000000000000000001000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000010000000000080000000000000000000000000000020000000000000000000000008000000000000000000000000000000000000000000", - "blockHash": "0x7ca48ea3b8964c9f88508ed80563822702c1c07a6f6923c00abc5dd4941dcccd", - "transactionHash": "0xa9af8df07597e7b45a9fe53062fd8c3fb652e75f6f4b99fb686737644cd1bddb", + "contractAddress": "0xaa55c780C88803Ad26e030eA00945D42a7434E68", + "transactionIndex": 9, + "gasUsed": "1008328", + "logsBloom": "0x00002000100000000000000000008000000000000000000000800000000000000000000000000000000000000000000000010000000000000020000000000000000000000000400000000041000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000040000400000000000000004000000000000000000000000000000000000000000000000000000000000000400000020000000000000000000000000000000000000000000000000000000000010000000000000000000000008000000000000000020000000000000000000000008000000000000000000000000000000000000000000", + "blockHash": "0xfaf1f724c1105073b5faaa4e3ef37d88c46683a120be7ee9411fde70cd6ae2e2", + "transactionHash": "0xa3c5ec3a2d12c2774a46cd60375a48e35b94d59b8c3e7c88195f64814f70cc80", "logs": [ { - "transactionIndex": 13, - "blockNumber": 8573519, - "transactionHash": "0xa9af8df07597e7b45a9fe53062fd8c3fb652e75f6f4b99fb686737644cd1bddb", - "address": "0xfc0962247f8b80BfB24159bb998D28857B0365D8", + "transactionIndex": 9, + "blockNumber": 8579615, + "transactionHash": "0xa3c5ec3a2d12c2774a46cd60375a48e35b94d59b8c3e7c88195f64814f70cc80", + "address": "0xaa55c780C88803Ad26e030eA00945D42a7434E68", "topics": [ "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000003f0556bca55bdbb78a9316936067a47fd4c4c4f4" ], "data": "0x", - "logIndex": 19, - "blockHash": "0x7ca48ea3b8964c9f88508ed80563822702c1c07a6f6923c00abc5dd4941dcccd" + "logIndex": 11, + "blockHash": "0xfaf1f724c1105073b5faaa4e3ef37d88c46683a120be7ee9411fde70cd6ae2e2" }, { - "transactionIndex": 13, - "blockNumber": 8573519, - "transactionHash": "0xa9af8df07597e7b45a9fe53062fd8c3fb652e75f6f4b99fb686737644cd1bddb", - "address": "0xfc0962247f8b80BfB24159bb998D28857B0365D8", + "transactionIndex": 9, + "blockNumber": 8579615, + "transactionHash": "0xa3c5ec3a2d12c2774a46cd60375a48e35b94d59b8c3e7c88195f64814f70cc80", + "address": "0xaa55c780C88803Ad26e030eA00945D42a7434E68", "topics": [ "0x3945779a0b94143e19ceb0254d7ff1fbe6c4265b6328031e7cc1274c2b8d77c7" ], "data": "0x000000000000000000000000f76f17682888a738a6df40aa63ac2b4b1a380831", - "logIndex": 20, - "blockHash": "0x7ca48ea3b8964c9f88508ed80563822702c1c07a6f6923c00abc5dd4941dcccd" + "logIndex": 12, + "blockHash": "0xfaf1f724c1105073b5faaa4e3ef37d88c46683a120be7ee9411fde70cd6ae2e2" }, { - "transactionIndex": 13, - "blockNumber": 8573519, - "transactionHash": "0xa9af8df07597e7b45a9fe53062fd8c3fb652e75f6f4b99fb686737644cd1bddb", - "address": "0xfc0962247f8b80BfB24159bb998D28857B0365D8", + "transactionIndex": 9, + "blockNumber": 8579615, + "transactionHash": "0xa3c5ec3a2d12c2774a46cd60375a48e35b94d59b8c3e7c88195f64814f70cc80", + "address": "0xaa55c780C88803Ad26e030eA00945D42a7434E68", "topics": [ "0xb722c0a05d55d91208263d973f28b92fc9599d46d7c490ff2efae89d8f3ddfe8" ], "data": "0x0000000000000000000000000000000000000000000000000000000000000003", - "logIndex": 21, - "blockHash": "0x7ca48ea3b8964c9f88508ed80563822702c1c07a6f6923c00abc5dd4941dcccd" + "logIndex": 13, + "blockHash": "0xfaf1f724c1105073b5faaa4e3ef37d88c46683a120be7ee9411fde70cd6ae2e2" + }, + { + "transactionIndex": 9, + "blockNumber": 8579615, + "transactionHash": "0xa3c5ec3a2d12c2774a46cd60375a48e35b94d59b8c3e7c88195f64814f70cc80", + "address": "0xaa55c780C88803Ad26e030eA00945D42a7434E68", + "topics": [ + "0x7a5354403e343fa02d40d3906b696f894d8b73fb8a898b07d7414f29866ef5d3" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000000a", + "logIndex": 14, + "blockHash": "0xfaf1f724c1105073b5faaa4e3ef37d88c46683a120be7ee9411fde70cd6ae2e2" } ], - "blockNumber": 8573519, - "cumulativeGasUsed": "3863519", + "blockNumber": 8579615, + "cumulativeGasUsed": "4993454", "status": 1, "byzantium": true }, "args": [ "0xF76f17682888a738a6DF40aa63ac2b4B1a380831", - 3 + 3, + 10 ], - "solcInputHash": "38d7677229f35bcf169409114f3634a1", - "metadata": "{\"compiler\":{\"version\":\"0.7.6+commit.7338295f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract AddressRegistry\",\"name\":\"_prizePoolRegistry\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_upkeepBatchSize\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"upkeepBatchSize\",\"type\":\"uint256\"}],\"name\":\"UpkeepBatchSizeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"upkeepMinimumBlockInterval\",\"type\":\"uint256\"}],\"name\":\"UpkeepMinimumBlockIntervalUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"startAwardsPerformed\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"completeAwardsPerformed\",\"type\":\"uint8\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract AddressRegistry\",\"name\":\"prizePoolRegistry\",\"type\":\"address\"}],\"name\":\"UpkeepPrizePoolRegistryUpdated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"prizePoolRegistry\",\"outputs\":[{\"internalType\":\"contract AddressRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract AddressRegistry\",\"name\":\"_prizePoolRegistry\",\"type\":\"address\"}],\"name\":\"updatePrizePoolRegistry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_upkeepBatchSize\",\"type\":\"uint256\"}],\"name\":\"updateUpkeepBatchSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_upkeepMinimumBlockInterval\",\"type\":\"uint256\"}],\"name\":\"updateUpkeepMinimumBlockInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepBatchSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepLastUpkeepBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepMinimumBlockInterval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"checkUpkeep(bytes)\":{\"params\":{\"checkData\":\"Not used in this implementation.\"},\"returns\":{\"upkeepNeeded\":\"as true if performUpkeep() needs to be called, false otherwise. performData returned empty. \"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"performUpkeep(bytes)\":{\"params\":{\"performData\":\"Not used in this implementation.\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updatePrizePoolRegistry(address)\":{\"params\":{\"_prizePoolRegistry\":\"New registry address\"}},\"updateUpkeepBatchSize(uint256)\":{\"params\":{\"_upkeepBatchSize\":\"Amount upkeepBatchSize will be set to\"}},\"updateUpkeepMinimumBlockInterval(uint256)\":{\"params\":{\"_upkeepMinimumBlockInterval\":\"New upkeepMinimumBlockInterval\"}}},\"stateVariables\":{\"upkeepBatchSize\":{\"details\":\"Set accordingly to prevent out-of-gas transactions during calls to performUpkeep\"}},\"version\":1},\"userdoc\":{\"events\":{\"UpkeepBatchSizeUpdated(uint256)\":{\"notice\":\"Emitted when the upkeepBatchSize has been changed\"},\"UpkeepMinimumBlockIntervalUpdated(uint256)\":{\"notice\":\"Emitted when the Upkeep Minimum Block interval is updated\"},\"UpkeepPerformed(uint8,uint8)\":{\"notice\":\"Emitted when the Upkeep has been performed\"},\"UpkeepPrizePoolRegistryUpdated(address)\":{\"notice\":\"Emitted when the prize pool registry has been changed\"}},\"kind\":\"user\",\"methods\":{\"checkUpkeep(bytes)\":{\"notice\":\"Checks if PrizePools require upkeep. Call in a static manner every block by the Chainlink Upkeep network.\"},\"performUpkeep(bytes)\":{\"notice\":\"Performs upkeep on the prize pools. \"},\"prizePoolRegistry()\":{\"notice\":\"Stores the maximum number of prize strategies to upkeep. \"},\"updatePrizePoolRegistry(address)\":{\"notice\":\"Updates the prize pool registry\"},\"updateUpkeepBatchSize(uint256)\":{\"notice\":\"Updates the upkeepBatchSize which is set to prevent out of gas situations\"},\"updateUpkeepMinimumBlockInterval(uint256)\":{\"notice\":\"Updates the upkeep minimum interval blocks\"},\"upkeepBatchSize()\":{\"notice\":\"Stores the maximum number of prize strategies to upkeep. \"},\"upkeepLastUpkeepBlockNumber()\":{\"notice\":\"Stores the last upkeep block number\"},\"upkeepMinimumBlockInterval()\":{\"notice\":\"Stores the last upkeep block number\"}},\"notice\":\"Contract implements Chainlink's Upkeep system interface, automating the upkeep of PrizePools in the associated registry. \",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PrizeStrategyUpkeep.sol\":\"PrizeStrategyUpkeep\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.6.0 <0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor () internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n emit OwnershipTransferred(_owner, address(0));\\n _owner = address(0);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x15e2d5bd4c28a88548074c54d220e8086f638a71ed07e6b3ba5a70066fcf458d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.6.0 <0.8.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x8d3cb350f04ff49cfb10aef08d87f19dcbaecc8027b0bed12f3275cd12f38cf0\",\"license\":\"MIT\"},\"@pooltogether/pooltogether-generic-registry/contracts/AddressRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.6.12 <=0.7.6;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\nimport \\\"./utils/MappedSinglyLinkedList.sol\\\";\\n\\n///@notice A registry to hold Contract addresses. Underlying data structure is a singly linked list. \\ncontract AddressRegistry is Ownable {\\n\\n using MappedSinglyLinkedList for MappedSinglyLinkedList.Mapping;\\n\\n MappedSinglyLinkedList.Mapping internal addressList;\\n\\n /// @notice Emmitted when a contract has been added to the registry\\n event AddressAdded(address indexed _address);\\n \\n /// @notice Emmitted when a contract has been removed to the registry\\n event AddressRemoved(address indexed _address);\\n\\n /// @notice Emitted when all the registry addresses are cleared\\n event AllAddressesCleared();\\n\\n /// @notice Storage field for what type of contract this Registry is storing \\n string public addressType; \\n\\n /// @notice Contract constructor sets addressType, intializes list and transfers ownership\\n /// @param _addressType The type of contracts stored in this registry \\n /// @param _owner The address to set as owner of the contract\\n constructor(string memory _addressType, address _owner) Ownable() {\\n addressType = _addressType;\\n addressList.initialize();\\n transferOwnership(_owner);\\n }\\n\\n /// @notice Returns an array of all contract addresses in the linked list\\n /// @return Array of contract addresses\\n function getAddresses() view external returns(address[] memory) {\\n return addressList.addressArray();\\n } \\n\\n /// @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.\\n /// @param _addresses Array of contract addresses to be added\\n function addAddresses(address[] calldata _addresses) public onlyOwner {\\n for(uint256 _address = 0; _address < _addresses.length; _address++ ){\\n addressList.addAddress(_addresses[_address]);\\n emit AddressAdded(_addresses[_address]);\\n }\\n }\\n\\n /// @notice Removes an address from the linked list. Can only be called by the Registry owner.\\n /// @param _previousContract The address positionally located before the address that will be deleted. This may be the SENTINEL address if the list contains one contract address\\n /// @param _address The address to remove from the linked list. \\n function removeAddress(address _previousContract, address _address) public onlyOwner {\\n addressList.removeAddress(_previousContract, _address); \\n emit AddressRemoved(_address);\\n } \\n\\n /// @notice Removes every address from the list\\n function clearAll() public onlyOwner {\\n addressList.clearAll();\\n emit AllAddressesCleared();\\n }\\n \\n /// @notice Determines whether the list contains the given address\\n /// @param _addr The address to check\\n /// @return True if the address is contained, false otherwise.\\n function contains(address _addr) public returns (bool) {\\n return addressList.contains(_addr);\\n }\\n\\n /// @notice Gives the address at the start of the list\\n /// @return The address at the start of the list\\n function start() public view returns (address) {\\n return addressList.start();\\n }\\n\\n /// @notice Exposes the internal next() iterator\\n /// @param current The current address\\n /// @return Returns the next address in the list\\n function next(address current) public view returns (address) {\\n return addressList.next(current);\\n }\\n \\n /// @notice Exposes the end of the list\\n /// @return The sentinel address\\n function end() public view returns (address) {\\n return addressList.end();\\n }\\n\\n}\",\"keccak256\":\"0xaf747d27e0da5eeeffd0496d32bd4e202f18253452d22bb816c541d4b09ea2f1\",\"license\":\"MIT\"},\"@pooltogether/pooltogether-generic-registry/contracts/utils/MappedSinglyLinkedList.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.7.6;\\n\\n/// @notice An efficient implementation of a singly linked list of addresses\\n/// @dev A mapping(address => address) tracks the 'next' pointer. A special address called the SENTINEL is used to denote the beginning and end of the list.\\nlibrary MappedSinglyLinkedList {\\n\\n /// @notice The special value address used to denote the end of the list\\n address public constant SENTINEL = address(0x1);\\n\\n /// @notice The data structure to use for the list.\\n struct Mapping {\\n uint256 count;\\n\\n mapping(address => address) addressMap;\\n }\\n\\n /// @notice Initializes the list.\\n /// @dev It is important that this is called so that the SENTINEL is correctly setup.\\n function initialize(Mapping storage self) internal {\\n require(self.count == 0, \\\"Already init\\\");\\n self.addressMap[SENTINEL] = SENTINEL;\\n }\\n\\n function start(Mapping storage self) internal view returns (address) {\\n return self.addressMap[SENTINEL];\\n }\\n\\n function next(Mapping storage self, address current) internal view returns (address) {\\n return self.addressMap[current];\\n }\\n\\n function end(Mapping storage) internal pure returns (address) {\\n return SENTINEL;\\n }\\n\\n function addAddresses(Mapping storage self, address[] memory addresses) internal {\\n for (uint256 i = 0; i < addresses.length; i++) {\\n addAddress(self, addresses[i]);\\n }\\n }\\n\\n /// @notice Adds an address to the front of the list.\\n /// @param self The Mapping struct that this function is attached to\\n /// @param newAddress The address to shift to the front of the list\\n function addAddress(Mapping storage self, address newAddress) internal {\\n require(newAddress != SENTINEL && newAddress != address(0), \\\"Invalid address\\\");\\n require(self.addressMap[newAddress] == address(0), \\\"Already added\\\");\\n self.addressMap[newAddress] = self.addressMap[SENTINEL];\\n self.addressMap[SENTINEL] = newAddress;\\n self.count = self.count + 1;\\n }\\n\\n /// @notice Removes an address from the list\\n /// @param self The Mapping struct that this function is attached to\\n /// @param prevAddress The address that precedes the address to be removed. This may be the SENTINEL if at the start.\\n /// @param addr The address to remove from the list.\\n function removeAddress(Mapping storage self, address prevAddress, address addr) internal {\\n require(addr != SENTINEL && addr != address(0), \\\"Invalid address\\\");\\n require(self.addressMap[prevAddress] == addr, \\\"Invalid prevAddress\\\");\\n self.addressMap[prevAddress] = self.addressMap[addr];\\n delete self.addressMap[addr];\\n self.count = self.count - 1;\\n }\\n\\n /// @notice Determines whether the list contains the given address\\n /// @param self The Mapping struct that this function is attached to\\n /// @param addr The address to check\\n /// @return True if the address is contained, false otherwise.\\n function contains(Mapping storage self, address addr) internal view returns (bool) {\\n return addr != SENTINEL && addr != address(0) && self.addressMap[addr] != address(0);\\n }\\n\\n /// @notice Returns an address array of all the addresses in this list\\n /// @dev Contains a for loop, so complexity is O(n) wrt the list size\\n /// @param self The Mapping struct that this function is attached to\\n /// @return An array of all the addresses\\n function addressArray(Mapping storage self) internal view returns (address[] memory) {\\n address[] memory array = new address[](self.count);\\n uint256 count;\\n address currentAddress = self.addressMap[SENTINEL];\\n while (currentAddress != address(0) && currentAddress != SENTINEL) {\\n array[count] = currentAddress;\\n currentAddress = self.addressMap[currentAddress];\\n count++;\\n }\\n return array;\\n }\\n\\n /// @notice Removes every address from the list\\n /// @param self The Mapping struct that this function is attached to\\n function clearAll(Mapping storage self) internal {\\n address currentAddress = self.addressMap[SENTINEL];\\n while (currentAddress != address(0) && currentAddress != SENTINEL) {\\n address nextAddress = self.addressMap[currentAddress];\\n delete self.addressMap[currentAddress];\\n currentAddress = nextAddress;\\n }\\n self.addressMap[SENTINEL] = SENTINEL;\\n self.count = 0;\\n }\\n}\\n\",\"keccak256\":\"0x14a99407202bafc5988b8ea002afabac73c13f88372083cf381d447ef30edc85\",\"license\":\"GPL-3.0\"},\"contracts/PrizeStrategyUpkeep.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.7.6;\\npragma experimental ABIEncoderV2;\\n\\n\\nimport \\\"./interfaces/KeeperCompatibleInterface.sol\\\";\\nimport \\\"./interfaces/PeriodicPrizeStrategyInterface.sol\\\";\\nimport \\\"./interfaces/PrizePoolRegistryInterface.sol\\\";\\nimport \\\"./interfaces/PrizePoolInterface.sol\\\";\\nimport \\\"./utils/SafeAwardable.sol\\\";\\n\\nimport \\\"@pooltogether/pooltogether-generic-registry/contracts/AddressRegistry.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n///@notice Contract implements Chainlink's Upkeep system interface, automating the upkeep of PrizePools in the associated registry. \\ncontract PrizeStrategyUpkeep is KeeperCompatibleInterface, Ownable {\\n\\n /// @notice Ensures the target address is a prize strategy (has both canStartAward and canCompleteAward)\\n using SafeAwardable for address;\\n\\n /// @notice Stores the maximum number of prize strategies to upkeep. \\n AddressRegistry public prizePoolRegistry;\\n\\n /// @notice Stores the maximum number of prize strategies to upkeep. \\n /// @dev Set accordingly to prevent out-of-gas transactions during calls to performUpkeep\\n uint256 public upkeepBatchSize;\\n\\n /// @notice Stores the last upkeep block number\\n uint256 public upkeepLastUpkeepBlockNumber;\\n\\n /// @notice Stores the last upkeep block number\\n uint256 public upkeepMinimumBlockInterval;\\n\\n /// @notice Emitted when the upkeepBatchSize has been changed\\n event UpkeepBatchSizeUpdated(uint256 upkeepBatchSize);\\n\\n /// @notice Emitted when the prize pool registry has been changed\\n event UpkeepPrizePoolRegistryUpdated(AddressRegistry prizePoolRegistry);\\n\\n /// @notice Emitted when the Upkeep Minimum Block interval is updated\\n event UpkeepMinimumBlockIntervalUpdated(uint256 upkeepMinimumBlockInterval);\\n\\n /// @notice Emitted when the Upkeep has been performed\\n event UpkeepPerformed(uint8 startAwardsPerformed, uint8 completeAwardsPerformed);\\n\\n\\n constructor(AddressRegistry _prizePoolRegistry, uint256 _upkeepBatchSize) Ownable() public {\\n prizePoolRegistry = _prizePoolRegistry;\\n emit UpkeepPrizePoolRegistryUpdated(_prizePoolRegistry);\\n\\n upkeepBatchSize = _upkeepBatchSize;\\n emit UpkeepBatchSizeUpdated(_upkeepBatchSize);\\n }\\n\\n\\n /// @notice Checks if PrizePools require upkeep. Call in a static manner every block by the Chainlink Upkeep network.\\n /// @param checkData Not used in this implementation.\\n /// @return upkeepNeeded as true if performUpkeep() needs to be called, false otherwise. performData returned empty. \\n function checkUpkeep(bytes calldata checkData) view override external returns (bool upkeepNeeded, bytes memory performData) {\\n\\n address[] memory prizePools = prizePoolRegistry.getAddresses();\\n\\n // check if canStartAward()\\n for(uint256 pool = 0; pool < prizePools.length; pool++){\\n address prizeStrategy = PrizePoolInterface(prizePools[pool]).prizeStrategy();\\n if(prizeStrategy.canStartAward()){\\n return (true, performData);\\n } \\n }\\n // check if canCompleteAward()\\n for(uint256 pool = 0; pool < prizePools.length; pool++){\\n address prizeStrategy = PrizePoolInterface(prizePools[pool]).prizeStrategy();\\n if(prizeStrategy.canCompleteAward()){\\n return (true, performData);\\n } \\n }\\n return (false, performData);\\n }\\n \\n /// @notice Performs upkeep on the prize pools. \\n /// @param performData Not used in this implementation.\\n function performUpkeep(bytes calldata performData) override external {\\n\\n uint256 _upkeepLastUpkeepBlockNumber = upkeepLastUpkeepBlockNumber;\\n require(block.number > _upkeepLastUpkeepBlockNumber + upkeepMinimumBlockInterval);\\n\\n address[] memory prizePools = prizePoolRegistry.getAddresses();\\n\\n \\n uint256 batchCounter = upkeepBatchSize; //counter for batch\\n\\n uint256 poolIndex = 0;\\n uint8 startAwardCounter = 0;\\n uint8 completeAwardCounter = 0;\\n\\n uint256 updatedUpkeepBlockNumber;\\n\\n while(batchCounter > 0 && poolIndex < prizePools.length){\\n \\n address prizeStrategy = PrizePoolInterface(prizePools[poolIndex]).prizeStrategy();\\n \\n if(prizeStrategy.canStartAward()){\\n PeriodicPrizeStrategyInterface(prizeStrategy).startAward();\\n updatedUpkeepBlockNumber = block.number;\\n startAwardCounter++;\\n batchCounter--;\\n }\\n else if(prizeStrategy.canCompleteAward()){\\n PeriodicPrizeStrategyInterface(prizeStrategy).completeAward();\\n updatedUpkeepBlockNumber = block.number;\\n completeAwardCounter++;\\n batchCounter--;\\n }\\n poolIndex++; \\n }\\n\\n // SSTORE upkeepLastUpkeepBlockNumber once\\n if(_upkeepLastUpkeepBlockNumber != updatedUpkeepBlockNumber){\\n upkeepLastUpkeepBlockNumber = updatedUpkeepBlockNumber;\\n emit UpkeepPerformed(startAwardCounter, startAwardCounter);\\n }\\n \\n }\\n\\n\\n /// @notice Updates the upkeepBatchSize which is set to prevent out of gas situations\\n /// @param _upkeepBatchSize Amount upkeepBatchSize will be set to\\n function updateUpkeepBatchSize(uint256 _upkeepBatchSize) external onlyOwner {\\n upkeepBatchSize = _upkeepBatchSize;\\n emit UpkeepBatchSizeUpdated(_upkeepBatchSize);\\n }\\n\\n\\n /// @notice Updates the prize pool registry\\n /// @param _prizePoolRegistry New registry address\\n function updatePrizePoolRegistry(AddressRegistry _prizePoolRegistry) external onlyOwner {\\n prizePoolRegistry = _prizePoolRegistry;\\n emit UpkeepPrizePoolRegistryUpdated(_prizePoolRegistry);\\n }\\n\\n\\n /// @notice Updates the upkeep minimum interval blocks\\n /// @param _upkeepMinimumBlockInterval New upkeepMinimumBlockInterval\\n function updateUpkeepMinimumBlockInterval(uint256 _upkeepMinimumBlockInterval) external onlyOwner {\\n upkeepMinimumBlockInterval = _upkeepMinimumBlockInterval;\\n emit UpkeepMinimumBlockIntervalUpdated(_upkeepMinimumBlockInterval);\\n }\\n\\n}\\n\\n\\n\",\"keccak256\":\"0x2043db1d5cc728495f96910bdb74d3bec06917c8c4edca6d4e34ee5a67245c13\",\"license\":\"MIT\"},\"contracts/interfaces/KeeperCompatibleInterface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.7.6;\\n\\ninterface KeeperCompatibleInterface {\\n\\n /**\\n * @notice method that is simulated by the keepers to see if any work actually\\n * needs to be performed. This method does does not actually need to be\\n * executable, and since it is only ever simulated it can consume lots of gas.\\n * @dev To ensure that it is never called, you may want to add the\\n * cannotExecute modifier from KeeperBase to your implementation of this\\n * method.\\n * @param checkData specified in the upkeep registration so it is always the\\n * same for a registered upkeep. This can easily be broken down into specific\\n * arguments using `abi.decode`, so multiple upkeeps can be registered on the\\n * same contract and easily differentiated by the contract.\\n * @return upkeepNeeded boolean to indicate whether the keeper should call\\n * performUpkeep or not.\\n * @return performData bytes that the keeper should call performUpkeep with, if\\n * upkeep is needed. If you would like to encode data to decode later, try\\n * `abi.encode`.\\n */\\n function checkUpkeep(\\n bytes calldata checkData\\n )\\n external\\n returns (\\n bool upkeepNeeded,\\n bytes memory performData\\n );\\n /**\\n * @notice method that is actually executed by the keepers, via the registry.\\n * The data returned by the checkUpkeep simulation will be passed into\\n * this method to actually be executed.\\n * @dev The input to this method should not be trusted, and the caller of the\\n * method should not even be restricted to any single registry. Anyone should\\n * be able call it, and the input should be validated, there is no guarantee\\n * that the data passed in is the performData returned from checkUpkeep. This\\n * could happen due to malicious keepers, racing keepers, or simply a state\\n * change while the performUpkeep transaction is waiting for confirmation.\\n * Always validate the data passed in.\\n * @param performData is the data which was passed back from the checkData\\n * simulation. If it is encoded, it can easily be decoded into other types by\\n * calling `abi.decode`. This data should not be trusted, and should be\\n * validated against the contract's current state.\\n */\\n function performUpkeep(\\n bytes calldata performData\\n ) external;\\n}\",\"keccak256\":\"0x5174919ce142bffa1517f63837e932ce18224d3b4cda828e0d88ff8a5b99d920\",\"license\":\"MIT\"},\"contracts/interfaces/PeriodicPrizeStrategyInterface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.7.6;\\n\\ninterface PeriodicPrizeStrategyInterface {\\n function startAward() external;\\n function completeAward() external;\\n function canStartAward() external view returns (bool);\\n function canCompleteAward() external view returns (bool);\\n}\",\"keccak256\":\"0x109f0a01f57f08936e7bb94fe357fa71e7237794f6f8576c37c773a80dcd155f\",\"license\":\"MIT\"},\"contracts/interfaces/PrizePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.7.6;\\n\\ninterface PrizePoolInterface {\\n function prizeStrategy() external view returns (address);\\n}\",\"keccak256\":\"0x25c3deefae7b4f2270303b5646e28f49922853ae946173ca2032173bd1844210\",\"license\":\"MIT\"},\"contracts/interfaces/PrizePoolRegistryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.7.6;\\n\\ninterface PrizePoolRegistryInterface {\\n function getPrizePools() external view returns(address[] memory);\\n}\",\"keccak256\":\"0x620c3e31149cdf62170e43f825aa8802a87ce7e677cd6c0c1c0722e45e6fe8ed\",\"license\":\"MIT\"},\"contracts/utils/SafeAwardable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.7.6;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../interfaces/PeriodicPrizeStrategyInterface.sol\\\";\\n\\n\\n///@notice Wrapper library for address that checks that the address supports canStartAward() and canCompleteAward() before calling\\nlibrary SafeAwardable{\\n\\n ///@return canCompleteAward returns true if the function is supported AND can be completed \\n function canCompleteAward(address self) internal view returns (bool canCompleteAward){\\n if(supportsFunction(self, PeriodicPrizeStrategyInterface.canCompleteAward.selector)){\\n return PeriodicPrizeStrategyInterface(self).canCompleteAward(); \\n }\\n return false;\\n }\\n\\n ///@return canStartAward returns true if the function is supported AND can be started, false otherwise\\n function canStartAward(address self) internal view returns (bool canStartAward){\\n if(supportsFunction(self, PeriodicPrizeStrategyInterface.canStartAward.selector)){\\n return PeriodicPrizeStrategyInterface(self).canStartAward();\\n }\\n return false;\\n }\\n \\n ///@param selector is the function selector to check against\\n ///@return success returns true if function is implemented, false otherwise\\n function supportsFunction(address self, bytes4 selector) internal view returns (bool success){\\n bytes memory encodedParams = abi.encodeWithSelector(selector);\\n (bool success, bytes memory result) = self.staticcall{ gas: 30000 }(encodedParams);\\n if (result.length < 32){\\n return (false);\\n }\\n if(!success && result.length > 0){\\n revert(string(result));\\n }\\n return (success);\\n }\\n}\",\"keccak256\":\"0xf5e2d50a8057812732975074254054c6b7717a97f34ec9be494a4c86663137e5\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b5060405161107b38038061107b83398101604081905261002f9161011e565b600061003961011a565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350600180546001600160a01b0319166001600160a01b0384161790556040517f3945779a0b94143e19ceb0254d7ff1fbe6c4265b6328031e7cc1274c2b8d77c7906100ce908490610156565b60405180910390a160028190556040517fb722c0a05d55d91208263d973f28b92fc9599d46d7c490ff2efae89d8f3ddfe89061010b90839061016a565b60405180910390a15050610173565b3390565b60008060408385031215610130578182fd5b82516001600160a01b0381168114610146578283fd5b6020939093015192949293505050565b6001600160a01b0391909116815260200190565b90815260200190565b610ef9806101826000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063715018a611610071578063715018a61461013b5780638da5cb5b14610143578063ad06337f14610158578063ba450a1a14610160578063f208517014610168578063f2fde38b1461017b576100b4565b80632dc41821146100b957806343d73f2d146100d75780634585e33b146100ec5780634fd47a76146100ff5780635fdc3b58146101075780636e04ff0d1461011a575b600080fd5b6100c161018e565b6040516100ce9190610e18565b60405180910390f35b6100ea6100e5366004610bed565b610194565b005b6100ea6100fa366004610d01565b61024c565b6100c16104e0565b6100ea610115366004610d6e565b6104e6565b61012d610128366004610d01565b61057d565b6040516100ce929190610de2565b6100ea61079e565b61014b61084a565b6040516100ce9190610dce565b61014b610859565b6100c1610868565b6100ea610176366004610d6e565b61086e565b6100ea610189366004610bed565b610905565b60025481565b61019c610a07565b6001600160a01b03166101ad61084a565b6001600160a01b0316146101f6576040805162461bcd60e51b81526020600482018190526024820152600080516020610ea4833981519152604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0383161790556040517f3945779a0b94143e19ceb0254d7ff1fbe6c4265b6328031e7cc1274c2b8d77c790610241908390610dce565b60405180910390a150565b6003546004548101431161025f57600080fd5b600154604080516351cfd60960e11b815290516000926001600160a01b03169163a39fac129160048083019286929190829003018186803b1580156102a357600080fd5b505afa1580156102b7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102df9190810190610c2c565b60025490915060008080805b6000851180156102fb5750855184105b1561048e57600086858151811061030e57fe5b60200260200101516001600160a01b03166398bf3eb66040518163ffffffff1660e01b815260040160206040518083038186803b15801561034e57600080fd5b505afa158015610362573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103869190610c10565b905061039a816001600160a01b0316610a0b565b1561040757806001600160a01b031663b9ee1e056040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156103da57600080fd5b505af11580156103ee573d6000803e3d6000fd5b5050600019909701965050600190930192439150610482565b610419816001600160a01b0316610aa4565b1561048257806001600160a01b031663dfb2f13b6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561045957600080fd5b505af115801561046d573d6000803e3d6000fd5b50506000199097019650506001909201914391505b506001909301926102eb565b8087146104d55760038190556040517f9a785b87d1714b9bc93929e1c937b56941763c25e63295fffaeff72a4947b288906104cc9085908190610e21565b60405180910390a15b505050505050505050565b60045481565b6104ee610a07565b6001600160a01b03166104ff61084a565b6001600160a01b031614610548576040805162461bcd60e51b81526020600482018190526024820152600080516020610ea4833981519152604482015290519081900360640190fd5b60028190556040517fb722c0a05d55d91208263d973f28b92fc9599d46d7c490ff2efae89d8f3ddfe890610241908390610e18565b600060606000600160009054906101000a90046001600160a01b03166001600160a01b031663a39fac126040518163ffffffff1660e01b815260040160006040518083038186803b1580156105d157600080fd5b505afa1580156105e5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261060d9190810190610c2c565b905060005b81518110156106cf57600082828151811061062957fe5b60200260200101516001600160a01b03166398bf3eb66040518163ffffffff1660e01b815260040160206040518083038186803b15801561066957600080fd5b505afa15801561067d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a19190610c10565b90506106b5816001600160a01b0316610a0b565b156106c65760019450505050610797565b50600101610612565b5060005b81518110156107905760008282815181106106ea57fe5b60200260200101516001600160a01b03166398bf3eb66040518163ffffffff1660e01b815260040160206040518083038186803b15801561072a57600080fd5b505afa15801561073e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107629190610c10565b9050610776816001600160a01b0316610aa4565b156107875760019450505050610797565b506001016106d3565b5060009250505b9250929050565b6107a6610a07565b6001600160a01b03166107b761084a565b6001600160a01b031614610800576040805162461bcd60e51b81526020600482018190526024820152600080516020610ea4833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b031690565b6001546001600160a01b031681565b60035481565b610876610a07565b6001600160a01b031661088761084a565b6001600160a01b0316146108d0576040805162461bcd60e51b81526020600482018190526024820152600080516020610ea4833981519152604482015290519081900360640190fd5b60048190556040517f7a5354403e343fa02d40d3906b696f894d8b73fb8a898b07d7414f29866ef5d390610241908390610e18565b61090d610a07565b6001600160a01b031661091e61084a565b6001600160a01b031614610967576040805162461bcd60e51b81526020600482018190526024820152600080516020610ea4833981519152604482015290519081900360640190fd5b6001600160a01b0381166109ac5760405162461bcd60e51b8152600401808060200182810382526026815260200180610e7e6026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b3390565b6000610a1e826343b7ae3f60e11b610af5565b15610a9b57816001600160a01b031663876f5c7e6040518163ffffffff1660e01b815260040160206040518083038186803b158015610a5c57600080fd5b505afa158015610a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a949190610ce1565b9050610a9f565b5060005b919050565b6000610ab782636a74f10760e01b610af5565b15610a9b57816001600160a01b0316636a74f1076040518163ffffffff1660e01b815260040160206040518083038186803b158015610a5c57600080fd5b60408051600481526024810182526020810180516001600160e01b03166001600160e01b03198516179052905160009190829081906001600160a01b0387169061753090610b44908690610db2565b6000604051808303818686fa925050503d8060008114610b80576040519150601f19603f3d011682016040523d82523d6000602084013e610b85565b606091505b5091509150602081511015610ba05760009350505050610bdc565b81158015610baf575060008151115b15610bd7578060405162461bcd60e51b8152600401610bce9190610e05565b60405180910390fd5b509150505b92915050565b8051610a9f81610e65565b600060208284031215610bfe578081fd5b8135610c0981610e65565b9392505050565b600060208284031215610c21578081fd5b8151610c0981610e65565b60006020808385031215610c3e578182fd5b825167ffffffffffffffff80821115610c55578384fd5b818501915085601f830112610c68578384fd5b815181811115610c7457fe5b83810260405185828201018181108582111715610c8d57fe5b604052828152858101935084860182860187018a1015610cab578788fd5b8795505b83861015610cd457610cc081610be2565b855260019590950194938601938601610caf565b5098975050505050505050565b600060208284031215610cf2578081fd5b81518015158114610c09578182fd5b60008060208385031215610d13578081fd5b823567ffffffffffffffff80821115610d2a578283fd5b818501915085601f830112610d3d578283fd5b813581811115610d4b578384fd5b866020828501011115610d5c578384fd5b60209290920196919550909350505050565b600060208284031215610d7f578081fd5b5035919050565b60008151808452610d9e816020860160208601610e35565b601f01601f19169290920160200192915050565b60008251610dc4818460208701610e35565b9190910192915050565b6001600160a01b0391909116815260200190565b6000831515825260406020830152610dfd6040830184610d86565b949350505050565b600060208252610c096020830184610d86565b90815260200190565b60ff92831681529116602082015260400190565b60005b83811015610e50578181015183820152602001610e38565b83811115610e5f576000848401525b50505050565b6001600160a01b0381168114610e7a57600080fd5b5056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a26469706673582212202b3a63fcbcc22d1ca1243c8c0ab65377117c08e98b3340f85e2672c572069b3764736f6c63430007060033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100b45760003560e01c8063715018a611610071578063715018a61461013b5780638da5cb5b14610143578063ad06337f14610158578063ba450a1a14610160578063f208517014610168578063f2fde38b1461017b576100b4565b80632dc41821146100b957806343d73f2d146100d75780634585e33b146100ec5780634fd47a76146100ff5780635fdc3b58146101075780636e04ff0d1461011a575b600080fd5b6100c161018e565b6040516100ce9190610e18565b60405180910390f35b6100ea6100e5366004610bed565b610194565b005b6100ea6100fa366004610d01565b61024c565b6100c16104e0565b6100ea610115366004610d6e565b6104e6565b61012d610128366004610d01565b61057d565b6040516100ce929190610de2565b6100ea61079e565b61014b61084a565b6040516100ce9190610dce565b61014b610859565b6100c1610868565b6100ea610176366004610d6e565b61086e565b6100ea610189366004610bed565b610905565b60025481565b61019c610a07565b6001600160a01b03166101ad61084a565b6001600160a01b0316146101f6576040805162461bcd60e51b81526020600482018190526024820152600080516020610ea4833981519152604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0383161790556040517f3945779a0b94143e19ceb0254d7ff1fbe6c4265b6328031e7cc1274c2b8d77c790610241908390610dce565b60405180910390a150565b6003546004548101431161025f57600080fd5b600154604080516351cfd60960e11b815290516000926001600160a01b03169163a39fac129160048083019286929190829003018186803b1580156102a357600080fd5b505afa1580156102b7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102df9190810190610c2c565b60025490915060008080805b6000851180156102fb5750855184105b1561048e57600086858151811061030e57fe5b60200260200101516001600160a01b03166398bf3eb66040518163ffffffff1660e01b815260040160206040518083038186803b15801561034e57600080fd5b505afa158015610362573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103869190610c10565b905061039a816001600160a01b0316610a0b565b1561040757806001600160a01b031663b9ee1e056040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156103da57600080fd5b505af11580156103ee573d6000803e3d6000fd5b5050600019909701965050600190930192439150610482565b610419816001600160a01b0316610aa4565b1561048257806001600160a01b031663dfb2f13b6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561045957600080fd5b505af115801561046d573d6000803e3d6000fd5b50506000199097019650506001909201914391505b506001909301926102eb565b8087146104d55760038190556040517f9a785b87d1714b9bc93929e1c937b56941763c25e63295fffaeff72a4947b288906104cc9085908190610e21565b60405180910390a15b505050505050505050565b60045481565b6104ee610a07565b6001600160a01b03166104ff61084a565b6001600160a01b031614610548576040805162461bcd60e51b81526020600482018190526024820152600080516020610ea4833981519152604482015290519081900360640190fd5b60028190556040517fb722c0a05d55d91208263d973f28b92fc9599d46d7c490ff2efae89d8f3ddfe890610241908390610e18565b600060606000600160009054906101000a90046001600160a01b03166001600160a01b031663a39fac126040518163ffffffff1660e01b815260040160006040518083038186803b1580156105d157600080fd5b505afa1580156105e5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261060d9190810190610c2c565b905060005b81518110156106cf57600082828151811061062957fe5b60200260200101516001600160a01b03166398bf3eb66040518163ffffffff1660e01b815260040160206040518083038186803b15801561066957600080fd5b505afa15801561067d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a19190610c10565b90506106b5816001600160a01b0316610a0b565b156106c65760019450505050610797565b50600101610612565b5060005b81518110156107905760008282815181106106ea57fe5b60200260200101516001600160a01b03166398bf3eb66040518163ffffffff1660e01b815260040160206040518083038186803b15801561072a57600080fd5b505afa15801561073e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107629190610c10565b9050610776816001600160a01b0316610aa4565b156107875760019450505050610797565b506001016106d3565b5060009250505b9250929050565b6107a6610a07565b6001600160a01b03166107b761084a565b6001600160a01b031614610800576040805162461bcd60e51b81526020600482018190526024820152600080516020610ea4833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b031690565b6001546001600160a01b031681565b60035481565b610876610a07565b6001600160a01b031661088761084a565b6001600160a01b0316146108d0576040805162461bcd60e51b81526020600482018190526024820152600080516020610ea4833981519152604482015290519081900360640190fd5b60048190556040517f7a5354403e343fa02d40d3906b696f894d8b73fb8a898b07d7414f29866ef5d390610241908390610e18565b61090d610a07565b6001600160a01b031661091e61084a565b6001600160a01b031614610967576040805162461bcd60e51b81526020600482018190526024820152600080516020610ea4833981519152604482015290519081900360640190fd5b6001600160a01b0381166109ac5760405162461bcd60e51b8152600401808060200182810382526026815260200180610e7e6026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b3390565b6000610a1e826343b7ae3f60e11b610af5565b15610a9b57816001600160a01b031663876f5c7e6040518163ffffffff1660e01b815260040160206040518083038186803b158015610a5c57600080fd5b505afa158015610a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a949190610ce1565b9050610a9f565b5060005b919050565b6000610ab782636a74f10760e01b610af5565b15610a9b57816001600160a01b0316636a74f1076040518163ffffffff1660e01b815260040160206040518083038186803b158015610a5c57600080fd5b60408051600481526024810182526020810180516001600160e01b03166001600160e01b03198516179052905160009190829081906001600160a01b0387169061753090610b44908690610db2565b6000604051808303818686fa925050503d8060008114610b80576040519150601f19603f3d011682016040523d82523d6000602084013e610b85565b606091505b5091509150602081511015610ba05760009350505050610bdc565b81158015610baf575060008151115b15610bd7578060405162461bcd60e51b8152600401610bce9190610e05565b60405180910390fd5b509150505b92915050565b8051610a9f81610e65565b600060208284031215610bfe578081fd5b8135610c0981610e65565b9392505050565b600060208284031215610c21578081fd5b8151610c0981610e65565b60006020808385031215610c3e578182fd5b825167ffffffffffffffff80821115610c55578384fd5b818501915085601f830112610c68578384fd5b815181811115610c7457fe5b83810260405185828201018181108582111715610c8d57fe5b604052828152858101935084860182860187018a1015610cab578788fd5b8795505b83861015610cd457610cc081610be2565b855260019590950194938601938601610caf565b5098975050505050505050565b600060208284031215610cf2578081fd5b81518015158114610c09578182fd5b60008060208385031215610d13578081fd5b823567ffffffffffffffff80821115610d2a578283fd5b818501915085601f830112610d3d578283fd5b813581811115610d4b578384fd5b866020828501011115610d5c578384fd5b60209290920196919550909350505050565b600060208284031215610d7f578081fd5b5035919050565b60008151808452610d9e816020860160208601610e35565b601f01601f19169290920160200192915050565b60008251610dc4818460208701610e35565b9190910192915050565b6001600160a01b0391909116815260200190565b6000831515825260406020830152610dfd6040830184610d86565b949350505050565b600060208252610c096020830184610d86565b90815260200190565b60ff92831681529116602082015260400190565b60005b83811015610e50578181015183820152602001610e38565b83811115610e5f576000848401525b50505050565b6001600160a01b0381168114610e7a57600080fd5b5056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a26469706673582212202b3a63fcbcc22d1ca1243c8c0ab65377117c08e98b3340f85e2672c572069b3764736f6c63430007060033", + "solcInputHash": "4d99ccacf7db9715d082cf53f38b8750", + "metadata": "{\"compiler\":{\"version\":\"0.7.6+commit.7338295f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract AddressRegistry\",\"name\":\"_prizePoolRegistry\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_upkeepBatchSize\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_upkeepMinimumBlockInterval\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"upkeepBatchSize\",\"type\":\"uint256\"}],\"name\":\"UpkeepBatchSizeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"upkeepMinimumBlockInterval\",\"type\":\"uint256\"}],\"name\":\"UpkeepMinimumBlockIntervalUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startAwardsPerformed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"completeAwardsPerformed\",\"type\":\"uint256\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract AddressRegistry\",\"name\":\"prizePoolRegistry\",\"type\":\"address\"}],\"name\":\"UpkeepPrizePoolRegistryUpdated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"prizePoolRegistry\",\"outputs\":[{\"internalType\":\"contract AddressRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract AddressRegistry\",\"name\":\"_prizePoolRegistry\",\"type\":\"address\"}],\"name\":\"updatePrizePoolRegistry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_upkeepBatchSize\",\"type\":\"uint256\"}],\"name\":\"updateUpkeepBatchSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_upkeepMinimumBlockInterval\",\"type\":\"uint256\"}],\"name\":\"updateUpkeepMinimumBlockInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepBatchSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepLastUpkeepBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepMinimumBlockInterval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"checkUpkeep(bytes)\":{\"params\":{\"checkData\":\"Not used in this implementation.\"},\"returns\":{\"upkeepNeeded\":\"as true if performUpkeep() needs to be called, false otherwise. performData returned empty. \"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"performUpkeep(bytes)\":{\"params\":{\"performData\":\"Not used in this implementation.\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updatePrizePoolRegistry(address)\":{\"params\":{\"_prizePoolRegistry\":\"New registry address\"}},\"updateUpkeepBatchSize(uint256)\":{\"params\":{\"_upkeepBatchSize\":\"Amount upkeepBatchSize will be set to\"}},\"updateUpkeepMinimumBlockInterval(uint256)\":{\"params\":{\"_upkeepMinimumBlockInterval\":\"New upkeepMinimumBlockInterval\"}}},\"stateVariables\":{\"upkeepBatchSize\":{\"details\":\"Set accordingly to prevent out-of-gas transactions during calls to performUpkeep\"}},\"version\":1},\"userdoc\":{\"events\":{\"UpkeepBatchSizeUpdated(uint256)\":{\"notice\":\"Emitted when the upkeepBatchSize has been changed\"},\"UpkeepMinimumBlockIntervalUpdated(uint256)\":{\"notice\":\"Emitted when the Upkeep Minimum Block interval is updated\"},\"UpkeepPerformed(uint256,uint256)\":{\"notice\":\"Emitted when the Upkeep has been performed\"},\"UpkeepPrizePoolRegistryUpdated(address)\":{\"notice\":\"Emitted when the prize pool registry has been changed\"}},\"kind\":\"user\",\"methods\":{\"checkUpkeep(bytes)\":{\"notice\":\"Checks if PrizePools require upkeep. Call in a static manner every block by the Chainlink Upkeep network.\"},\"performUpkeep(bytes)\":{\"notice\":\"Performs upkeep on the prize pools. \"},\"prizePoolRegistry()\":{\"notice\":\"Stores the maximum number of prize strategies to upkeep. \"},\"updatePrizePoolRegistry(address)\":{\"notice\":\"Updates the prize pool registry\"},\"updateUpkeepBatchSize(uint256)\":{\"notice\":\"Updates the upkeepBatchSize which is set to prevent out of gas situations\"},\"updateUpkeepMinimumBlockInterval(uint256)\":{\"notice\":\"Updates the upkeep minimum interval blocks\"},\"upkeepBatchSize()\":{\"notice\":\"Stores the maximum number of prize strategies to upkeep. \"},\"upkeepLastUpkeepBlockNumber()\":{\"notice\":\"Stores the last upkeep block number\"},\"upkeepMinimumBlockInterval()\":{\"notice\":\"Stores the minimum block interval between permitted performUpkeep() calls\"}},\"notice\":\"Contract implements Chainlink's Upkeep system interface, automating the upkeep of PrizePools in the associated registry. \",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PrizeStrategyUpkeep.sol\":\"PrizeStrategyUpkeep\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.6.0 <0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor () internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n emit OwnershipTransferred(_owner, address(0));\\n _owner = address(0);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x15e2d5bd4c28a88548074c54d220e8086f638a71ed07e6b3ba5a70066fcf458d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.6.0 <0.8.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x8d3cb350f04ff49cfb10aef08d87f19dcbaecc8027b0bed12f3275cd12f38cf0\",\"license\":\"MIT\"},\"@pooltogether/pooltogether-generic-registry/contracts/AddressRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity >=0.6.12 <=0.7.6;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\nimport \\\"./utils/MappedSinglyLinkedList.sol\\\";\\n\\n///@notice A registry to hold Contract addresses. Underlying data structure is a singly linked list. \\ncontract AddressRegistry is Ownable {\\n\\n using MappedSinglyLinkedList for MappedSinglyLinkedList.Mapping;\\n\\n MappedSinglyLinkedList.Mapping internal addressList;\\n\\n /// @notice Emmitted when a contract has been added to the registry\\n event AddressAdded(address indexed _address);\\n \\n /// @notice Emmitted when a contract has been removed to the registry\\n event AddressRemoved(address indexed _address);\\n\\n /// @notice Emitted when all the registry addresses are cleared\\n event AllAddressesCleared();\\n\\n /// @notice Storage field for what type of contract this Registry is storing \\n string public addressType; \\n\\n /// @notice Contract constructor sets addressType, intializes list and transfers ownership\\n /// @param _addressType The type of contracts stored in this registry \\n /// @param _owner The address to set as owner of the contract\\n constructor(string memory _addressType, address _owner) Ownable() {\\n addressType = _addressType;\\n addressList.initialize();\\n transferOwnership(_owner);\\n }\\n\\n /// @notice Returns an array of all contract addresses in the linked list\\n /// @return Array of contract addresses\\n function getAddresses() view external returns(address[] memory) {\\n return addressList.addressArray();\\n } \\n\\n /// @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.\\n /// @param _addresses Array of contract addresses to be added\\n function addAddresses(address[] calldata _addresses) public onlyOwner {\\n for(uint256 _address = 0; _address < _addresses.length; _address++ ){\\n addressList.addAddress(_addresses[_address]);\\n emit AddressAdded(_addresses[_address]);\\n }\\n }\\n\\n /// @notice Removes an address from the linked list. Can only be called by the Registry owner.\\n /// @param _previousContract The address positionally located before the address that will be deleted. This may be the SENTINEL address if the list contains one contract address\\n /// @param _address The address to remove from the linked list. \\n function removeAddress(address _previousContract, address _address) public onlyOwner {\\n addressList.removeAddress(_previousContract, _address); \\n emit AddressRemoved(_address);\\n } \\n\\n /// @notice Removes every address from the list\\n function clearAll() public onlyOwner {\\n addressList.clearAll();\\n emit AllAddressesCleared();\\n }\\n \\n /// @notice Determines whether the list contains the given address\\n /// @param _addr The address to check\\n /// @return True if the address is contained, false otherwise.\\n function contains(address _addr) public returns (bool) {\\n return addressList.contains(_addr);\\n }\\n\\n /// @notice Gives the address at the start of the list\\n /// @return The address at the start of the list\\n function start() public view returns (address) {\\n return addressList.start();\\n }\\n\\n /// @notice Exposes the internal next() iterator\\n /// @param current The current address\\n /// @return Returns the next address in the list\\n function next(address current) public view returns (address) {\\n return addressList.next(current);\\n }\\n \\n /// @notice Exposes the end of the list\\n /// @return The sentinel address\\n function end() public view returns (address) {\\n return addressList.end();\\n }\\n\\n}\",\"keccak256\":\"0xaf747d27e0da5eeeffd0496d32bd4e202f18253452d22bb816c541d4b09ea2f1\",\"license\":\"MIT\"},\"@pooltogether/pooltogether-generic-registry/contracts/utils/MappedSinglyLinkedList.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.7.6;\\n\\n/// @notice An efficient implementation of a singly linked list of addresses\\n/// @dev A mapping(address => address) tracks the 'next' pointer. A special address called the SENTINEL is used to denote the beginning and end of the list.\\nlibrary MappedSinglyLinkedList {\\n\\n /// @notice The special value address used to denote the end of the list\\n address public constant SENTINEL = address(0x1);\\n\\n /// @notice The data structure to use for the list.\\n struct Mapping {\\n uint256 count;\\n\\n mapping(address => address) addressMap;\\n }\\n\\n /// @notice Initializes the list.\\n /// @dev It is important that this is called so that the SENTINEL is correctly setup.\\n function initialize(Mapping storage self) internal {\\n require(self.count == 0, \\\"Already init\\\");\\n self.addressMap[SENTINEL] = SENTINEL;\\n }\\n\\n function start(Mapping storage self) internal view returns (address) {\\n return self.addressMap[SENTINEL];\\n }\\n\\n function next(Mapping storage self, address current) internal view returns (address) {\\n return self.addressMap[current];\\n }\\n\\n function end(Mapping storage) internal pure returns (address) {\\n return SENTINEL;\\n }\\n\\n function addAddresses(Mapping storage self, address[] memory addresses) internal {\\n for (uint256 i = 0; i < addresses.length; i++) {\\n addAddress(self, addresses[i]);\\n }\\n }\\n\\n /// @notice Adds an address to the front of the list.\\n /// @param self The Mapping struct that this function is attached to\\n /// @param newAddress The address to shift to the front of the list\\n function addAddress(Mapping storage self, address newAddress) internal {\\n require(newAddress != SENTINEL && newAddress != address(0), \\\"Invalid address\\\");\\n require(self.addressMap[newAddress] == address(0), \\\"Already added\\\");\\n self.addressMap[newAddress] = self.addressMap[SENTINEL];\\n self.addressMap[SENTINEL] = newAddress;\\n self.count = self.count + 1;\\n }\\n\\n /// @notice Removes an address from the list\\n /// @param self The Mapping struct that this function is attached to\\n /// @param prevAddress The address that precedes the address to be removed. This may be the SENTINEL if at the start.\\n /// @param addr The address to remove from the list.\\n function removeAddress(Mapping storage self, address prevAddress, address addr) internal {\\n require(addr != SENTINEL && addr != address(0), \\\"Invalid address\\\");\\n require(self.addressMap[prevAddress] == addr, \\\"Invalid prevAddress\\\");\\n self.addressMap[prevAddress] = self.addressMap[addr];\\n delete self.addressMap[addr];\\n self.count = self.count - 1;\\n }\\n\\n /// @notice Determines whether the list contains the given address\\n /// @param self The Mapping struct that this function is attached to\\n /// @param addr The address to check\\n /// @return True if the address is contained, false otherwise.\\n function contains(Mapping storage self, address addr) internal view returns (bool) {\\n return addr != SENTINEL && addr != address(0) && self.addressMap[addr] != address(0);\\n }\\n\\n /// @notice Returns an address array of all the addresses in this list\\n /// @dev Contains a for loop, so complexity is O(n) wrt the list size\\n /// @param self The Mapping struct that this function is attached to\\n /// @return An array of all the addresses\\n function addressArray(Mapping storage self) internal view returns (address[] memory) {\\n address[] memory array = new address[](self.count);\\n uint256 count;\\n address currentAddress = self.addressMap[SENTINEL];\\n while (currentAddress != address(0) && currentAddress != SENTINEL) {\\n array[count] = currentAddress;\\n currentAddress = self.addressMap[currentAddress];\\n count++;\\n }\\n return array;\\n }\\n\\n /// @notice Removes every address from the list\\n /// @param self The Mapping struct that this function is attached to\\n function clearAll(Mapping storage self) internal {\\n address currentAddress = self.addressMap[SENTINEL];\\n while (currentAddress != address(0) && currentAddress != SENTINEL) {\\n address nextAddress = self.addressMap[currentAddress];\\n delete self.addressMap[currentAddress];\\n currentAddress = nextAddress;\\n }\\n self.addressMap[SENTINEL] = SENTINEL;\\n self.count = 0;\\n }\\n}\\n\",\"keccak256\":\"0x14a99407202bafc5988b8ea002afabac73c13f88372083cf381d447ef30edc85\",\"license\":\"GPL-3.0\"},\"contracts/PrizeStrategyUpkeep.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.7.6;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./interfaces/KeeperCompatibleInterface.sol\\\";\\nimport \\\"./interfaces/PeriodicPrizeStrategyInterface.sol\\\";\\nimport \\\"./interfaces/PrizePoolRegistryInterface.sol\\\";\\nimport \\\"./interfaces/PrizePoolInterface.sol\\\";\\nimport \\\"./utils/SafeAwardable.sol\\\";\\n\\nimport \\\"@pooltogether/pooltogether-generic-registry/contracts/AddressRegistry.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n///@notice Contract implements Chainlink's Upkeep system interface, automating the upkeep of PrizePools in the associated registry. \\ncontract PrizeStrategyUpkeep is KeeperCompatibleInterface, Ownable {\\n\\n /// @notice Ensures the target address is a prize strategy (has both canStartAward and canCompleteAward)\\n using SafeAwardable for address;\\n\\n /// @notice Stores the maximum number of prize strategies to upkeep. \\n AddressRegistry public prizePoolRegistry;\\n\\n /// @notice Stores the maximum number of prize strategies to upkeep. \\n /// @dev Set accordingly to prevent out-of-gas transactions during calls to performUpkeep\\n uint256 public upkeepBatchSize;\\n\\n /// @notice Stores the last upkeep block number\\n uint256 public upkeepLastUpkeepBlockNumber;\\n\\n /// @notice Stores the minimum block interval between permitted performUpkeep() calls\\n uint256 public upkeepMinimumBlockInterval;\\n\\n /// @notice Emitted when the upkeepBatchSize has been changed\\n event UpkeepBatchSizeUpdated(uint256 upkeepBatchSize);\\n\\n /// @notice Emitted when the prize pool registry has been changed\\n event UpkeepPrizePoolRegistryUpdated(AddressRegistry prizePoolRegistry);\\n\\n /// @notice Emitted when the Upkeep Minimum Block interval is updated\\n event UpkeepMinimumBlockIntervalUpdated(uint256 upkeepMinimumBlockInterval);\\n\\n /// @notice Emitted when the Upkeep has been performed\\n event UpkeepPerformed(uint256 startAwardsPerformed, uint256 completeAwardsPerformed);\\n\\n\\n constructor(AddressRegistry _prizePoolRegistry, uint256 _upkeepBatchSize, uint256 _upkeepMinimumBlockInterval) public Ownable() {\\n prizePoolRegistry = _prizePoolRegistry;\\n emit UpkeepPrizePoolRegistryUpdated(_prizePoolRegistry);\\n\\n upkeepBatchSize = _upkeepBatchSize;\\n emit UpkeepBatchSizeUpdated(_upkeepBatchSize);\\n\\n upkeepMinimumBlockInterval = _upkeepMinimumBlockInterval;\\n emit UpkeepMinimumBlockIntervalUpdated(_upkeepMinimumBlockInterval);\\n }\\n\\n\\n /// @notice Checks if PrizePools require upkeep. Call in a static manner every block by the Chainlink Upkeep network.\\n /// @param checkData Not used in this implementation.\\n /// @return upkeepNeeded as true if performUpkeep() needs to be called, false otherwise. performData returned empty. \\n function checkUpkeep(bytes calldata checkData) view override external returns (bool upkeepNeeded, bytes memory performData) {\\n\\n address[] memory prizePools = prizePoolRegistry.getAddresses();\\n\\n // check if canStartAward()\\n for(uint256 pool = 0; pool < prizePools.length; pool++){\\n address prizeStrategy = PrizePoolInterface(prizePools[pool]).prizeStrategy();\\n if(prizeStrategy.canStartAward()){\\n return (true, performData);\\n } \\n }\\n // check if canCompleteAward()\\n for(uint256 pool = 0; pool < prizePools.length; pool++){\\n address prizeStrategy = PrizePoolInterface(prizePools[pool]).prizeStrategy();\\n if(prizeStrategy.canCompleteAward()){\\n return (true, performData);\\n } \\n }\\n return (false, performData);\\n }\\n \\n /// @notice Performs upkeep on the prize pools. \\n /// @param performData Not used in this implementation.\\n function performUpkeep(bytes calldata performData) override external {\\n\\n uint256 _upkeepLastUpkeepBlockNumber = upkeepLastUpkeepBlockNumber;\\n require(block.number > _upkeepLastUpkeepBlockNumber + upkeepMinimumBlockInterval, \\\"PrizeStrategyUpkeep::minimum block interval not reached\\\");\\n\\n address[] memory prizePools = prizePoolRegistry.getAddresses();\\n\\n \\n uint256 batchCounter = upkeepBatchSize; //counter for batch\\n\\n uint256 poolIndex = 0;\\n uint256 startAwardCounter = 0;\\n uint256 completeAwardCounter = 0;\\n\\n uint256 updatedUpkeepBlockNumber;\\n\\n while(batchCounter > 0 && poolIndex < prizePools.length){\\n \\n address prizeStrategy = PrizePoolInterface(prizePools[poolIndex]).prizeStrategy();\\n \\n if(prizeStrategy.canStartAward()){\\n PeriodicPrizeStrategyInterface(prizeStrategy).startAward();\\n startAwardCounter++;\\n batchCounter--;\\n }\\n else if(prizeStrategy.canCompleteAward()){\\n PeriodicPrizeStrategyInterface(prizeStrategy).completeAward(); \\n completeAwardCounter++;\\n batchCounter--;\\n }\\n poolIndex++; \\n }\\n \\n if(startAwardCounter > 0 || completeAwardCounter > 0){\\n updatedUpkeepBlockNumber = block.number;\\n }\\n\\n // SSTORE upkeepLastUpkeepBlockNumber once\\n if(_upkeepLastUpkeepBlockNumber != updatedUpkeepBlockNumber){\\n upkeepLastUpkeepBlockNumber = updatedUpkeepBlockNumber;\\n emit UpkeepPerformed(startAwardCounter, completeAwardCounter);\\n }\\n \\n }\\n\\n\\n /// @notice Updates the upkeepBatchSize which is set to prevent out of gas situations\\n /// @param _upkeepBatchSize Amount upkeepBatchSize will be set to\\n function updateUpkeepBatchSize(uint256 _upkeepBatchSize) external onlyOwner {\\n upkeepBatchSize = _upkeepBatchSize;\\n emit UpkeepBatchSizeUpdated(_upkeepBatchSize);\\n }\\n\\n\\n /// @notice Updates the prize pool registry\\n /// @param _prizePoolRegistry New registry address\\n function updatePrizePoolRegistry(AddressRegistry _prizePoolRegistry) external onlyOwner {\\n prizePoolRegistry = _prizePoolRegistry;\\n emit UpkeepPrizePoolRegistryUpdated(_prizePoolRegistry);\\n }\\n\\n\\n /// @notice Updates the upkeep minimum interval blocks\\n /// @param _upkeepMinimumBlockInterval New upkeepMinimumBlockInterval\\n function updateUpkeepMinimumBlockInterval(uint256 _upkeepMinimumBlockInterval) external onlyOwner {\\n upkeepMinimumBlockInterval = _upkeepMinimumBlockInterval;\\n emit UpkeepMinimumBlockIntervalUpdated(_upkeepMinimumBlockInterval);\\n }\\n\\n}\\n\\n\\n\",\"keccak256\":\"0xda8463e43291b15e0c638e2da72b4540ce6da42a020cd60f666732b2f240bcae\",\"license\":\"MIT\"},\"contracts/interfaces/KeeperCompatibleInterface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.7.6;\\n\\ninterface KeeperCompatibleInterface {\\n\\n /**\\n * @notice method that is simulated by the keepers to see if any work actually\\n * needs to be performed. This method does does not actually need to be\\n * executable, and since it is only ever simulated it can consume lots of gas.\\n * @dev To ensure that it is never called, you may want to add the\\n * cannotExecute modifier from KeeperBase to your implementation of this\\n * method.\\n * @param checkData specified in the upkeep registration so it is always the\\n * same for a registered upkeep. This can easily be broken down into specific\\n * arguments using `abi.decode`, so multiple upkeeps can be registered on the\\n * same contract and easily differentiated by the contract.\\n * @return upkeepNeeded boolean to indicate whether the keeper should call\\n * performUpkeep or not.\\n * @return performData bytes that the keeper should call performUpkeep with, if\\n * upkeep is needed. If you would like to encode data to decode later, try\\n * `abi.encode`.\\n */\\n function checkUpkeep(\\n bytes calldata checkData\\n )\\n external\\n returns (\\n bool upkeepNeeded,\\n bytes memory performData\\n );\\n /**\\n * @notice method that is actually executed by the keepers, via the registry.\\n * The data returned by the checkUpkeep simulation will be passed into\\n * this method to actually be executed.\\n * @dev The input to this method should not be trusted, and the caller of the\\n * method should not even be restricted to any single registry. Anyone should\\n * be able call it, and the input should be validated, there is no guarantee\\n * that the data passed in is the performData returned from checkUpkeep. This\\n * could happen due to malicious keepers, racing keepers, or simply a state\\n * change while the performUpkeep transaction is waiting for confirmation.\\n * Always validate the data passed in.\\n * @param performData is the data which was passed back from the checkData\\n * simulation. If it is encoded, it can easily be decoded into other types by\\n * calling `abi.decode`. This data should not be trusted, and should be\\n * validated against the contract's current state.\\n */\\n function performUpkeep(\\n bytes calldata performData\\n ) external;\\n}\",\"keccak256\":\"0x5174919ce142bffa1517f63837e932ce18224d3b4cda828e0d88ff8a5b99d920\",\"license\":\"MIT\"},\"contracts/interfaces/PeriodicPrizeStrategyInterface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.7.6;\\n\\ninterface PeriodicPrizeStrategyInterface {\\n function startAward() external;\\n function completeAward() external;\\n function canStartAward() external view returns (bool);\\n function canCompleteAward() external view returns (bool);\\n}\",\"keccak256\":\"0x109f0a01f57f08936e7bb94fe357fa71e7237794f6f8576c37c773a80dcd155f\",\"license\":\"MIT\"},\"contracts/interfaces/PrizePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.7.6;\\n\\ninterface PrizePoolInterface {\\n function prizeStrategy() external view returns (address);\\n}\",\"keccak256\":\"0x25c3deefae7b4f2270303b5646e28f49922853ae946173ca2032173bd1844210\",\"license\":\"MIT\"},\"contracts/interfaces/PrizePoolRegistryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.7.6;\\n\\ninterface PrizePoolRegistryInterface {\\n function getPrizePools() external view returns(address[] memory);\\n}\",\"keccak256\":\"0x620c3e31149cdf62170e43f825aa8802a87ce7e677cd6c0c1c0722e45e6fe8ed\",\"license\":\"MIT\"},\"contracts/utils/SafeAwardable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.7.6;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../interfaces/PeriodicPrizeStrategyInterface.sol\\\";\\n\\n\\n///@notice Wrapper library for address that checks that the address supports canStartAward() and canCompleteAward() before calling\\nlibrary SafeAwardable{\\n\\n ///@return canCompleteAward returns true if the function is supported AND can be completed \\n function canCompleteAward(address self) internal view returns (bool canCompleteAward){\\n if(supportsFunction(self, PeriodicPrizeStrategyInterface.canCompleteAward.selector)){\\n return PeriodicPrizeStrategyInterface(self).canCompleteAward(); \\n }\\n return false;\\n }\\n\\n ///@return canStartAward returns true if the function is supported AND can be started, false otherwise\\n function canStartAward(address self) internal view returns (bool canStartAward){\\n if(supportsFunction(self, PeriodicPrizeStrategyInterface.canStartAward.selector)){\\n return PeriodicPrizeStrategyInterface(self).canStartAward();\\n }\\n return false;\\n }\\n \\n ///@param selector is the function selector to check against\\n ///@return success returns true if function is implemented, false otherwise\\n function supportsFunction(address self, bytes4 selector) internal view returns (bool success){\\n bytes memory encodedParams = abi.encodeWithSelector(selector);\\n (bool success, bytes memory result) = self.staticcall{ gas: 30000 }(encodedParams);\\n if (result.length < 32){\\n return (false);\\n }\\n if(!success && result.length > 0){\\n revert(string(result));\\n }\\n return (success);\\n }\\n}\",\"keccak256\":\"0xf5e2d50a8057812732975074254054c6b7717a97f34ec9be494a4c86663137e5\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5060405161113d38038061113d83398101604081905261002f9161015c565b6000610039610158565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350600180546001600160a01b0319166001600160a01b0385161790556040517f3945779a0b94143e19ceb0254d7ff1fbe6c4265b6328031e7cc1274c2b8d77c7906100ce90859061019d565b60405180910390a160028290556040517fb722c0a05d55d91208263d973f28b92fc9599d46d7c490ff2efae89d8f3ddfe89061010b9084906101b1565b60405180910390a160048190556040517f7a5354403e343fa02d40d3906b696f894d8b73fb8a898b07d7414f29866ef5d3906101489083906101b1565b60405180910390a15050506101ba565b3390565b600080600060608486031215610170578283fd5b83516001600160a01b0381168114610186578384fd5b602085015160409095015190969495509392505050565b6001600160a01b0391909116815260200190565b90815260200190565b610f74806101c96000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063715018a611610071578063715018a61461013b5780638da5cb5b14610143578063ad06337f14610158578063ba450a1a14610160578063f208517014610168578063f2fde38b1461017b576100b4565b80632dc41821146100b957806343d73f2d146100d75780634585e33b146100ec5780634fd47a76146100ff5780635fdc3b58146101075780636e04ff0d1461011a575b600080fd5b6100c161018e565b6040516100ce9190610e99565b60405180910390f35b6100ea6100e5366004610c11565b610194565b005b6100ea6100fa366004610d25565b61024c565b6100c161050d565b6100ea610115366004610d92565b610513565b61012d610128366004610d25565b6105aa565b6040516100ce929190610e06565b6100ea6107cb565b61014b610877565b6040516100ce9190610df2565b61014b610886565b6100c1610895565b6100ea610176366004610d92565b61089b565b6100ea610189366004610c11565b610932565b60025481565b61019c610a34565b6001600160a01b03166101ad610877565b6001600160a01b0316146101f6576040805162461bcd60e51b81526020600482018190526024820152600080516020610f1f833981519152604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0383161790556040517f3945779a0b94143e19ceb0254d7ff1fbe6c4265b6328031e7cc1274c2b8d77c790610241908390610df2565b60405180910390a150565b6003546004548101431161027b5760405162461bcd60e51b815260040161027290610e3c565b60405180910390fd5b600154604080516351cfd60960e11b815290516000926001600160a01b03169163a39fac129160048083019286929190829003018186803b1580156102bf57600080fd5b505afa1580156102d3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102fb9190810190610c50565b60025490915060008080805b6000851180156103175750855184105b156104a457600086858151811061032a57fe5b60200260200101516001600160a01b03166398bf3eb66040518163ffffffff1660e01b815260040160206040518083038186803b15801561036a57600080fd5b505afa15801561037e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a29190610c34565b90506103b6816001600160a01b0316610a38565b1561042057806001600160a01b031663b9ee1e056040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156103f657600080fd5b505af115801561040a573d6000803e3d6000fd5b5050600019909701965050600190930192610498565b610432816001600160a01b0316610ad1565b1561049857806001600160a01b031663dfb2f13b6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561047257600080fd5b505af1158015610486573d6000803e3d6000fd5b50506000199097019650506001909201915b50600190930192610307565b60008311806104b35750600082115b156104bb5750435b8087146105025760038190556040517f9fbc2aeb5bf6200e5499d345acddf1dd462c37becb4673d661250b89ced7ff6a906104f99085908590610ea2565b60405180910390a15b505050505050505050565b60045481565b61051b610a34565b6001600160a01b031661052c610877565b6001600160a01b031614610575576040805162461bcd60e51b81526020600482018190526024820152600080516020610f1f833981519152604482015290519081900360640190fd5b60028190556040517fb722c0a05d55d91208263d973f28b92fc9599d46d7c490ff2efae89d8f3ddfe890610241908390610e99565b600060606000600160009054906101000a90046001600160a01b03166001600160a01b031663a39fac126040518163ffffffff1660e01b815260040160006040518083038186803b1580156105fe57600080fd5b505afa158015610612573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261063a9190810190610c50565b905060005b81518110156106fc57600082828151811061065657fe5b60200260200101516001600160a01b03166398bf3eb66040518163ffffffff1660e01b815260040160206040518083038186803b15801561069657600080fd5b505afa1580156106aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ce9190610c34565b90506106e2816001600160a01b0316610a38565b156106f357600194505050506107c4565b5060010161063f565b5060005b81518110156107bd57600082828151811061071757fe5b60200260200101516001600160a01b03166398bf3eb66040518163ffffffff1660e01b815260040160206040518083038186803b15801561075757600080fd5b505afa15801561076b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078f9190610c34565b90506107a3816001600160a01b0316610ad1565b156107b457600194505050506107c4565b50600101610700565b5060009250505b9250929050565b6107d3610a34565b6001600160a01b03166107e4610877565b6001600160a01b03161461082d576040805162461bcd60e51b81526020600482018190526024820152600080516020610f1f833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b031690565b6001546001600160a01b031681565b60035481565b6108a3610a34565b6001600160a01b03166108b4610877565b6001600160a01b0316146108fd576040805162461bcd60e51b81526020600482018190526024820152600080516020610f1f833981519152604482015290519081900360640190fd5b60048190556040517f7a5354403e343fa02d40d3906b696f894d8b73fb8a898b07d7414f29866ef5d390610241908390610e99565b61093a610a34565b6001600160a01b031661094b610877565b6001600160a01b031614610994576040805162461bcd60e51b81526020600482018190526024820152600080516020610f1f833981519152604482015290519081900360640190fd5b6001600160a01b0381166109d95760405162461bcd60e51b8152600401808060200182810382526026815260200180610ef96026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b3390565b6000610a4b826343b7ae3f60e11b610b22565b15610ac857816001600160a01b031663876f5c7e6040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8957600080fd5b505afa158015610a9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac19190610d05565b9050610acc565b5060005b919050565b6000610ae482636a74f10760e01b610b22565b15610ac857816001600160a01b0316636a74f1076040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8957600080fd5b60408051600481526024810182526020810180516001600160e01b03166001600160e01b03198516179052905160009190829081906001600160a01b0387169061753090610b71908690610dd6565b6000604051808303818686fa925050503d8060008114610bad576040519150601f19603f3d011682016040523d82523d6000602084013e610bb2565b606091505b5091509150602081511015610bcd5760009350505050610c00565b81158015610bdc575060008151115b15610bfb578060405162461bcd60e51b81526004016102729190610e29565b509150505b92915050565b8051610acc81610ee0565b600060208284031215610c22578081fd5b8135610c2d81610ee0565b9392505050565b600060208284031215610c45578081fd5b8151610c2d81610ee0565b60006020808385031215610c62578182fd5b825167ffffffffffffffff80821115610c79578384fd5b818501915085601f830112610c8c578384fd5b815181811115610c9857fe5b83810260405185828201018181108582111715610cb157fe5b604052828152858101935084860182860187018a1015610ccf578788fd5b8795505b83861015610cf857610ce481610c06565b855260019590950194938601938601610cd3565b5098975050505050505050565b600060208284031215610d16578081fd5b81518015158114610c2d578182fd5b60008060208385031215610d37578081fd5b823567ffffffffffffffff80821115610d4e578283fd5b818501915085601f830112610d61578283fd5b813581811115610d6f578384fd5b866020828501011115610d80578384fd5b60209290920196919550909350505050565b600060208284031215610da3578081fd5b5035919050565b60008151808452610dc2816020860160208601610eb0565b601f01601f19169290920160200192915050565b60008251610de8818460208701610eb0565b9190910192915050565b6001600160a01b0391909116815260200190565b6000831515825260406020830152610e216040830184610daa565b949350505050565b600060208252610c2d6020830184610daa565b60208082526037908201527f5072697a65537472617465677955706b6565703a3a6d696e696d756d20626c6f60408201527f636b20696e74657276616c206e6f742072656163686564000000000000000000606082015260800190565b90815260200190565b918252602082015260400190565b60005b83811015610ecb578181015183820152602001610eb3565b83811115610eda576000848401525b50505050565b6001600160a01b0381168114610ef557600080fd5b5056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a26469706673582212203c3bc5a14eef22b9e47120e14968b7423a8996ec8553bb4f7825e072047f0a9164736f6c63430007060033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100b45760003560e01c8063715018a611610071578063715018a61461013b5780638da5cb5b14610143578063ad06337f14610158578063ba450a1a14610160578063f208517014610168578063f2fde38b1461017b576100b4565b80632dc41821146100b957806343d73f2d146100d75780634585e33b146100ec5780634fd47a76146100ff5780635fdc3b58146101075780636e04ff0d1461011a575b600080fd5b6100c161018e565b6040516100ce9190610e99565b60405180910390f35b6100ea6100e5366004610c11565b610194565b005b6100ea6100fa366004610d25565b61024c565b6100c161050d565b6100ea610115366004610d92565b610513565b61012d610128366004610d25565b6105aa565b6040516100ce929190610e06565b6100ea6107cb565b61014b610877565b6040516100ce9190610df2565b61014b610886565b6100c1610895565b6100ea610176366004610d92565b61089b565b6100ea610189366004610c11565b610932565b60025481565b61019c610a34565b6001600160a01b03166101ad610877565b6001600160a01b0316146101f6576040805162461bcd60e51b81526020600482018190526024820152600080516020610f1f833981519152604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0383161790556040517f3945779a0b94143e19ceb0254d7ff1fbe6c4265b6328031e7cc1274c2b8d77c790610241908390610df2565b60405180910390a150565b6003546004548101431161027b5760405162461bcd60e51b815260040161027290610e3c565b60405180910390fd5b600154604080516351cfd60960e11b815290516000926001600160a01b03169163a39fac129160048083019286929190829003018186803b1580156102bf57600080fd5b505afa1580156102d3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102fb9190810190610c50565b60025490915060008080805b6000851180156103175750855184105b156104a457600086858151811061032a57fe5b60200260200101516001600160a01b03166398bf3eb66040518163ffffffff1660e01b815260040160206040518083038186803b15801561036a57600080fd5b505afa15801561037e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a29190610c34565b90506103b6816001600160a01b0316610a38565b1561042057806001600160a01b031663b9ee1e056040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156103f657600080fd5b505af115801561040a573d6000803e3d6000fd5b5050600019909701965050600190930192610498565b610432816001600160a01b0316610ad1565b1561049857806001600160a01b031663dfb2f13b6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561047257600080fd5b505af1158015610486573d6000803e3d6000fd5b50506000199097019650506001909201915b50600190930192610307565b60008311806104b35750600082115b156104bb5750435b8087146105025760038190556040517f9fbc2aeb5bf6200e5499d345acddf1dd462c37becb4673d661250b89ced7ff6a906104f99085908590610ea2565b60405180910390a15b505050505050505050565b60045481565b61051b610a34565b6001600160a01b031661052c610877565b6001600160a01b031614610575576040805162461bcd60e51b81526020600482018190526024820152600080516020610f1f833981519152604482015290519081900360640190fd5b60028190556040517fb722c0a05d55d91208263d973f28b92fc9599d46d7c490ff2efae89d8f3ddfe890610241908390610e99565b600060606000600160009054906101000a90046001600160a01b03166001600160a01b031663a39fac126040518163ffffffff1660e01b815260040160006040518083038186803b1580156105fe57600080fd5b505afa158015610612573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261063a9190810190610c50565b905060005b81518110156106fc57600082828151811061065657fe5b60200260200101516001600160a01b03166398bf3eb66040518163ffffffff1660e01b815260040160206040518083038186803b15801561069657600080fd5b505afa1580156106aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ce9190610c34565b90506106e2816001600160a01b0316610a38565b156106f357600194505050506107c4565b5060010161063f565b5060005b81518110156107bd57600082828151811061071757fe5b60200260200101516001600160a01b03166398bf3eb66040518163ffffffff1660e01b815260040160206040518083038186803b15801561075757600080fd5b505afa15801561076b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078f9190610c34565b90506107a3816001600160a01b0316610ad1565b156107b457600194505050506107c4565b50600101610700565b5060009250505b9250929050565b6107d3610a34565b6001600160a01b03166107e4610877565b6001600160a01b03161461082d576040805162461bcd60e51b81526020600482018190526024820152600080516020610f1f833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b031690565b6001546001600160a01b031681565b60035481565b6108a3610a34565b6001600160a01b03166108b4610877565b6001600160a01b0316146108fd576040805162461bcd60e51b81526020600482018190526024820152600080516020610f1f833981519152604482015290519081900360640190fd5b60048190556040517f7a5354403e343fa02d40d3906b696f894d8b73fb8a898b07d7414f29866ef5d390610241908390610e99565b61093a610a34565b6001600160a01b031661094b610877565b6001600160a01b031614610994576040805162461bcd60e51b81526020600482018190526024820152600080516020610f1f833981519152604482015290519081900360640190fd5b6001600160a01b0381166109d95760405162461bcd60e51b8152600401808060200182810382526026815260200180610ef96026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b3390565b6000610a4b826343b7ae3f60e11b610b22565b15610ac857816001600160a01b031663876f5c7e6040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8957600080fd5b505afa158015610a9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac19190610d05565b9050610acc565b5060005b919050565b6000610ae482636a74f10760e01b610b22565b15610ac857816001600160a01b0316636a74f1076040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8957600080fd5b60408051600481526024810182526020810180516001600160e01b03166001600160e01b03198516179052905160009190829081906001600160a01b0387169061753090610b71908690610dd6565b6000604051808303818686fa925050503d8060008114610bad576040519150601f19603f3d011682016040523d82523d6000602084013e610bb2565b606091505b5091509150602081511015610bcd5760009350505050610c00565b81158015610bdc575060008151115b15610bfb578060405162461bcd60e51b81526004016102729190610e29565b509150505b92915050565b8051610acc81610ee0565b600060208284031215610c22578081fd5b8135610c2d81610ee0565b9392505050565b600060208284031215610c45578081fd5b8151610c2d81610ee0565b60006020808385031215610c62578182fd5b825167ffffffffffffffff80821115610c79578384fd5b818501915085601f830112610c8c578384fd5b815181811115610c9857fe5b83810260405185828201018181108582111715610cb157fe5b604052828152858101935084860182860187018a1015610ccf578788fd5b8795505b83861015610cf857610ce481610c06565b855260019590950194938601938601610cd3565b5098975050505050505050565b600060208284031215610d16578081fd5b81518015158114610c2d578182fd5b60008060208385031215610d37578081fd5b823567ffffffffffffffff80821115610d4e578283fd5b818501915085601f830112610d61578283fd5b813581811115610d6f578384fd5b866020828501011115610d80578384fd5b60209290920196919550909350505050565b600060208284031215610da3578081fd5b5035919050565b60008151808452610dc2816020860160208601610eb0565b601f01601f19169290920160200192915050565b60008251610de8818460208701610eb0565b9190910192915050565b6001600160a01b0391909116815260200190565b6000831515825260406020830152610e216040830184610daa565b949350505050565b600060208252610c2d6020830184610daa565b60208082526037908201527f5072697a65537472617465677955706b6565703a3a6d696e696d756d20626c6f60408201527f636b20696e74657276616c206e6f742072656163686564000000000000000000606082015260800190565b90815260200190565b918252602082015260400190565b60005b83811015610ecb578181015183820152602001610eb3565b83811115610eda576000848401525b50505050565b6001600160a01b0381168114610ef557600080fd5b5056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a26469706673582212203c3bc5a14eef22b9e47120e14968b7423a8996ec8553bb4f7825e072047f0a9164736f6c63430007060033", "devdoc": { "kind": "dev", "methods": { @@ -375,7 +393,7 @@ "UpkeepMinimumBlockIntervalUpdated(uint256)": { "notice": "Emitted when the Upkeep Minimum Block interval is updated" }, - "UpkeepPerformed(uint8,uint8)": { + "UpkeepPerformed(uint256,uint256)": { "notice": "Emitted when the Upkeep has been performed" }, "UpkeepPrizePoolRegistryUpdated(address)": { @@ -409,7 +427,7 @@ "notice": "Stores the last upkeep block number" }, "upkeepMinimumBlockInterval()": { - "notice": "Stores the last upkeep block number" + "notice": "Stores the minimum block interval between permitted performUpkeep() calls" } }, "notice": "Contract implements Chainlink's Upkeep system interface, automating the upkeep of PrizePools in the associated registry. ", diff --git a/deployments/rinkeby/solcInputs/4d99ccacf7db9715d082cf53f38b8750.json b/deployments/rinkeby/solcInputs/4d99ccacf7db9715d082cf53f38b8750.json new file mode 100644 index 0000000..ecf6608 --- /dev/null +++ b/deployments/rinkeby/solcInputs/4d99ccacf7db9715d082cf53f38b8750.json @@ -0,0 +1,66 @@ +{ + "language": "Solidity", + "sources": { + "contracts/hardhat-dependency-compiler/@pooltogether/pooltogether-generic-registry/contracts/AddressRegistry.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >0.0.0;\nimport '@pooltogether/pooltogether-generic-registry/contracts/AddressRegistry.sol';\n" + }, + "@pooltogether/pooltogether-generic-registry/contracts/AddressRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.12 <=0.7.6;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\nimport \"./utils/MappedSinglyLinkedList.sol\";\n\n///@notice A registry to hold Contract addresses. Underlying data structure is a singly linked list. \ncontract AddressRegistry is Ownable {\n\n using MappedSinglyLinkedList for MappedSinglyLinkedList.Mapping;\n\n MappedSinglyLinkedList.Mapping internal addressList;\n\n /// @notice Emmitted when a contract has been added to the registry\n event AddressAdded(address indexed _address);\n \n /// @notice Emmitted when a contract has been removed to the registry\n event AddressRemoved(address indexed _address);\n\n /// @notice Emitted when all the registry addresses are cleared\n event AllAddressesCleared();\n\n /// @notice Storage field for what type of contract this Registry is storing \n string public addressType; \n\n /// @notice Contract constructor sets addressType, intializes list and transfers ownership\n /// @param _addressType The type of contracts stored in this registry \n /// @param _owner The address to set as owner of the contract\n constructor(string memory _addressType, address _owner) Ownable() {\n addressType = _addressType;\n addressList.initialize();\n transferOwnership(_owner);\n }\n\n /// @notice Returns an array of all contract addresses in the linked list\n /// @return Array of contract addresses\n function getAddresses() view external returns(address[] memory) {\n return addressList.addressArray();\n } \n\n /// @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.\n /// @param _addresses Array of contract addresses to be added\n function addAddresses(address[] calldata _addresses) public onlyOwner {\n for(uint256 _address = 0; _address < _addresses.length; _address++ ){\n addressList.addAddress(_addresses[_address]);\n emit AddressAdded(_addresses[_address]);\n }\n }\n\n /// @notice Removes an address from the linked list. Can only be called by the Registry owner.\n /// @param _previousContract The address positionally located before the address that will be deleted. This may be the SENTINEL address if the list contains one contract address\n /// @param _address The address to remove from the linked list. \n function removeAddress(address _previousContract, address _address) public onlyOwner {\n addressList.removeAddress(_previousContract, _address); \n emit AddressRemoved(_address);\n } \n\n /// @notice Removes every address from the list\n function clearAll() public onlyOwner {\n addressList.clearAll();\n emit AllAddressesCleared();\n }\n \n /// @notice Determines whether the list contains the given address\n /// @param _addr The address to check\n /// @return True if the address is contained, false otherwise.\n function contains(address _addr) public returns (bool) {\n return addressList.contains(_addr);\n }\n\n /// @notice Gives the address at the start of the list\n /// @return The address at the start of the list\n function start() public view returns (address) {\n return addressList.start();\n }\n\n /// @notice Exposes the internal next() iterator\n /// @param current The current address\n /// @return Returns the next address in the list\n function next(address current) public view returns (address) {\n return addressList.next(current);\n }\n \n /// @notice Exposes the end of the list\n /// @return The sentinel address\n function end() public view returns (address) {\n return addressList.end();\n }\n\n}" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.0 <0.8.0;\n\nimport \"../utils/Context.sol\";\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor () internal {\n address msgSender = _msgSender();\n _owner = msgSender;\n emit OwnershipTransferred(address(0), msgSender);\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n emit OwnershipTransferred(_owner, address(0));\n _owner = address(0);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n emit OwnershipTransferred(_owner, newOwner);\n _owner = newOwner;\n }\n}\n" + }, + "@pooltogether/pooltogether-generic-registry/contracts/utils/MappedSinglyLinkedList.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.7.6;\n\n/// @notice An efficient implementation of a singly linked list of addresses\n/// @dev A mapping(address => address) tracks the 'next' pointer. A special address called the SENTINEL is used to denote the beginning and end of the list.\nlibrary MappedSinglyLinkedList {\n\n /// @notice The special value address used to denote the end of the list\n address public constant SENTINEL = address(0x1);\n\n /// @notice The data structure to use for the list.\n struct Mapping {\n uint256 count;\n\n mapping(address => address) addressMap;\n }\n\n /// @notice Initializes the list.\n /// @dev It is important that this is called so that the SENTINEL is correctly setup.\n function initialize(Mapping storage self) internal {\n require(self.count == 0, \"Already init\");\n self.addressMap[SENTINEL] = SENTINEL;\n }\n\n function start(Mapping storage self) internal view returns (address) {\n return self.addressMap[SENTINEL];\n }\n\n function next(Mapping storage self, address current) internal view returns (address) {\n return self.addressMap[current];\n }\n\n function end(Mapping storage) internal pure returns (address) {\n return SENTINEL;\n }\n\n function addAddresses(Mapping storage self, address[] memory addresses) internal {\n for (uint256 i = 0; i < addresses.length; i++) {\n addAddress(self, addresses[i]);\n }\n }\n\n /// @notice Adds an address to the front of the list.\n /// @param self The Mapping struct that this function is attached to\n /// @param newAddress The address to shift to the front of the list\n function addAddress(Mapping storage self, address newAddress) internal {\n require(newAddress != SENTINEL && newAddress != address(0), \"Invalid address\");\n require(self.addressMap[newAddress] == address(0), \"Already added\");\n self.addressMap[newAddress] = self.addressMap[SENTINEL];\n self.addressMap[SENTINEL] = newAddress;\n self.count = self.count + 1;\n }\n\n /// @notice Removes an address from the list\n /// @param self The Mapping struct that this function is attached to\n /// @param prevAddress The address that precedes the address to be removed. This may be the SENTINEL if at the start.\n /// @param addr The address to remove from the list.\n function removeAddress(Mapping storage self, address prevAddress, address addr) internal {\n require(addr != SENTINEL && addr != address(0), \"Invalid address\");\n require(self.addressMap[prevAddress] == addr, \"Invalid prevAddress\");\n self.addressMap[prevAddress] = self.addressMap[addr];\n delete self.addressMap[addr];\n self.count = self.count - 1;\n }\n\n /// @notice Determines whether the list contains the given address\n /// @param self The Mapping struct that this function is attached to\n /// @param addr The address to check\n /// @return True if the address is contained, false otherwise.\n function contains(Mapping storage self, address addr) internal view returns (bool) {\n return addr != SENTINEL && addr != address(0) && self.addressMap[addr] != address(0);\n }\n\n /// @notice Returns an address array of all the addresses in this list\n /// @dev Contains a for loop, so complexity is O(n) wrt the list size\n /// @param self The Mapping struct that this function is attached to\n /// @return An array of all the addresses\n function addressArray(Mapping storage self) internal view returns (address[] memory) {\n address[] memory array = new address[](self.count);\n uint256 count;\n address currentAddress = self.addressMap[SENTINEL];\n while (currentAddress != address(0) && currentAddress != SENTINEL) {\n array[count] = currentAddress;\n currentAddress = self.addressMap[currentAddress];\n count++;\n }\n return array;\n }\n\n /// @notice Removes every address from the list\n /// @param self The Mapping struct that this function is attached to\n function clearAll(Mapping storage self) internal {\n address currentAddress = self.addressMap[SENTINEL];\n while (currentAddress != address(0) && currentAddress != SENTINEL) {\n address nextAddress = self.addressMap[currentAddress];\n delete self.addressMap[currentAddress];\n currentAddress = nextAddress;\n }\n self.addressMap[SENTINEL] = SENTINEL;\n self.count = 0;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.0 <0.8.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n" + }, + "contracts/PrizeStrategyUpkeep.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.6;\npragma experimental ABIEncoderV2;\n\nimport \"./interfaces/KeeperCompatibleInterface.sol\";\nimport \"./interfaces/PeriodicPrizeStrategyInterface.sol\";\nimport \"./interfaces/PrizePoolRegistryInterface.sol\";\nimport \"./interfaces/PrizePoolInterface.sol\";\nimport \"./utils/SafeAwardable.sol\";\n\nimport \"@pooltogether/pooltogether-generic-registry/contracts/AddressRegistry.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n///@notice Contract implements Chainlink's Upkeep system interface, automating the upkeep of PrizePools in the associated registry. \ncontract PrizeStrategyUpkeep is KeeperCompatibleInterface, Ownable {\n\n /// @notice Ensures the target address is a prize strategy (has both canStartAward and canCompleteAward)\n using SafeAwardable for address;\n\n /// @notice Stores the maximum number of prize strategies to upkeep. \n AddressRegistry public prizePoolRegistry;\n\n /// @notice Stores the maximum number of prize strategies to upkeep. \n /// @dev Set accordingly to prevent out-of-gas transactions during calls to performUpkeep\n uint256 public upkeepBatchSize;\n\n /// @notice Stores the last upkeep block number\n uint256 public upkeepLastUpkeepBlockNumber;\n\n /// @notice Stores the minimum block interval between permitted performUpkeep() calls\n uint256 public upkeepMinimumBlockInterval;\n\n /// @notice Emitted when the upkeepBatchSize has been changed\n event UpkeepBatchSizeUpdated(uint256 upkeepBatchSize);\n\n /// @notice Emitted when the prize pool registry has been changed\n event UpkeepPrizePoolRegistryUpdated(AddressRegistry prizePoolRegistry);\n\n /// @notice Emitted when the Upkeep Minimum Block interval is updated\n event UpkeepMinimumBlockIntervalUpdated(uint256 upkeepMinimumBlockInterval);\n\n /// @notice Emitted when the Upkeep has been performed\n event UpkeepPerformed(uint256 startAwardsPerformed, uint256 completeAwardsPerformed);\n\n\n constructor(AddressRegistry _prizePoolRegistry, uint256 _upkeepBatchSize, uint256 _upkeepMinimumBlockInterval) public Ownable() {\n prizePoolRegistry = _prizePoolRegistry;\n emit UpkeepPrizePoolRegistryUpdated(_prizePoolRegistry);\n\n upkeepBatchSize = _upkeepBatchSize;\n emit UpkeepBatchSizeUpdated(_upkeepBatchSize);\n\n upkeepMinimumBlockInterval = _upkeepMinimumBlockInterval;\n emit UpkeepMinimumBlockIntervalUpdated(_upkeepMinimumBlockInterval);\n }\n\n\n /// @notice Checks if PrizePools require upkeep. Call in a static manner every block by the Chainlink Upkeep network.\n /// @param checkData Not used in this implementation.\n /// @return upkeepNeeded as true if performUpkeep() needs to be called, false otherwise. performData returned empty. \n function checkUpkeep(bytes calldata checkData) view override external returns (bool upkeepNeeded, bytes memory performData) {\n\n address[] memory prizePools = prizePoolRegistry.getAddresses();\n\n // check if canStartAward()\n for(uint256 pool = 0; pool < prizePools.length; pool++){\n address prizeStrategy = PrizePoolInterface(prizePools[pool]).prizeStrategy();\n if(prizeStrategy.canStartAward()){\n return (true, performData);\n } \n }\n // check if canCompleteAward()\n for(uint256 pool = 0; pool < prizePools.length; pool++){\n address prizeStrategy = PrizePoolInterface(prizePools[pool]).prizeStrategy();\n if(prizeStrategy.canCompleteAward()){\n return (true, performData);\n } \n }\n return (false, performData);\n }\n \n /// @notice Performs upkeep on the prize pools. \n /// @param performData Not used in this implementation.\n function performUpkeep(bytes calldata performData) override external {\n\n uint256 _upkeepLastUpkeepBlockNumber = upkeepLastUpkeepBlockNumber;\n require(block.number > _upkeepLastUpkeepBlockNumber + upkeepMinimumBlockInterval, \"PrizeStrategyUpkeep::minimum block interval not reached\");\n\n address[] memory prizePools = prizePoolRegistry.getAddresses();\n\n \n uint256 batchCounter = upkeepBatchSize; //counter for batch\n\n uint256 poolIndex = 0;\n uint256 startAwardCounter = 0;\n uint256 completeAwardCounter = 0;\n\n uint256 updatedUpkeepBlockNumber;\n\n while(batchCounter > 0 && poolIndex < prizePools.length){\n \n address prizeStrategy = PrizePoolInterface(prizePools[poolIndex]).prizeStrategy();\n \n if(prizeStrategy.canStartAward()){\n PeriodicPrizeStrategyInterface(prizeStrategy).startAward();\n startAwardCounter++;\n batchCounter--;\n }\n else if(prizeStrategy.canCompleteAward()){\n PeriodicPrizeStrategyInterface(prizeStrategy).completeAward(); \n completeAwardCounter++;\n batchCounter--;\n }\n poolIndex++; \n }\n \n if(startAwardCounter > 0 || completeAwardCounter > 0){\n updatedUpkeepBlockNumber = block.number;\n }\n\n // SSTORE upkeepLastUpkeepBlockNumber once\n if(_upkeepLastUpkeepBlockNumber != updatedUpkeepBlockNumber){\n upkeepLastUpkeepBlockNumber = updatedUpkeepBlockNumber;\n emit UpkeepPerformed(startAwardCounter, completeAwardCounter);\n }\n \n }\n\n\n /// @notice Updates the upkeepBatchSize which is set to prevent out of gas situations\n /// @param _upkeepBatchSize Amount upkeepBatchSize will be set to\n function updateUpkeepBatchSize(uint256 _upkeepBatchSize) external onlyOwner {\n upkeepBatchSize = _upkeepBatchSize;\n emit UpkeepBatchSizeUpdated(_upkeepBatchSize);\n }\n\n\n /// @notice Updates the prize pool registry\n /// @param _prizePoolRegistry New registry address\n function updatePrizePoolRegistry(AddressRegistry _prizePoolRegistry) external onlyOwner {\n prizePoolRegistry = _prizePoolRegistry;\n emit UpkeepPrizePoolRegistryUpdated(_prizePoolRegistry);\n }\n\n\n /// @notice Updates the upkeep minimum interval blocks\n /// @param _upkeepMinimumBlockInterval New upkeepMinimumBlockInterval\n function updateUpkeepMinimumBlockInterval(uint256 _upkeepMinimumBlockInterval) external onlyOwner {\n upkeepMinimumBlockInterval = _upkeepMinimumBlockInterval;\n emit UpkeepMinimumBlockIntervalUpdated(_upkeepMinimumBlockInterval);\n }\n\n}\n\n\n" + }, + "contracts/interfaces/KeeperCompatibleInterface.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.7.6;\n\ninterface KeeperCompatibleInterface {\n\n /**\n * @notice method that is simulated by the keepers to see if any work actually\n * needs to be performed. This method does does not actually need to be\n * executable, and since it is only ever simulated it can consume lots of gas.\n * @dev To ensure that it is never called, you may want to add the\n * cannotExecute modifier from KeeperBase to your implementation of this\n * method.\n * @param checkData specified in the upkeep registration so it is always the\n * same for a registered upkeep. This can easily be broken down into specific\n * arguments using `abi.decode`, so multiple upkeeps can be registered on the\n * same contract and easily differentiated by the contract.\n * @return upkeepNeeded boolean to indicate whether the keeper should call\n * performUpkeep or not.\n * @return performData bytes that the keeper should call performUpkeep with, if\n * upkeep is needed. If you would like to encode data to decode later, try\n * `abi.encode`.\n */\n function checkUpkeep(\n bytes calldata checkData\n )\n external\n returns (\n bool upkeepNeeded,\n bytes memory performData\n );\n /**\n * @notice method that is actually executed by the keepers, via the registry.\n * The data returned by the checkUpkeep simulation will be passed into\n * this method to actually be executed.\n * @dev The input to this method should not be trusted, and the caller of the\n * method should not even be restricted to any single registry. Anyone should\n * be able call it, and the input should be validated, there is no guarantee\n * that the data passed in is the performData returned from checkUpkeep. This\n * could happen due to malicious keepers, racing keepers, or simply a state\n * change while the performUpkeep transaction is waiting for confirmation.\n * Always validate the data passed in.\n * @param performData is the data which was passed back from the checkData\n * simulation. If it is encoded, it can easily be decoded into other types by\n * calling `abi.decode`. This data should not be trusted, and should be\n * validated against the contract's current state.\n */\n function performUpkeep(\n bytes calldata performData\n ) external;\n}" + }, + "contracts/interfaces/PeriodicPrizeStrategyInterface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.7.6;\n\ninterface PeriodicPrizeStrategyInterface {\n function startAward() external;\n function completeAward() external;\n function canStartAward() external view returns (bool);\n function canCompleteAward() external view returns (bool);\n}" + }, + "contracts/interfaces/PrizePoolRegistryInterface.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.6;\n\ninterface PrizePoolRegistryInterface {\n function getPrizePools() external view returns(address[] memory);\n}" + }, + "contracts/interfaces/PrizePoolInterface.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.6;\n\ninterface PrizePoolInterface {\n function prizeStrategy() external view returns (address);\n}" + }, + "contracts/utils/SafeAwardable.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.6;\npragma experimental ABIEncoderV2;\n\nimport \"../interfaces/PeriodicPrizeStrategyInterface.sol\";\n\n\n///@notice Wrapper library for address that checks that the address supports canStartAward() and canCompleteAward() before calling\nlibrary SafeAwardable{\n\n ///@return canCompleteAward returns true if the function is supported AND can be completed \n function canCompleteAward(address self) internal view returns (bool canCompleteAward){\n if(supportsFunction(self, PeriodicPrizeStrategyInterface.canCompleteAward.selector)){\n return PeriodicPrizeStrategyInterface(self).canCompleteAward(); \n }\n return false;\n }\n\n ///@return canStartAward returns true if the function is supported AND can be started, false otherwise\n function canStartAward(address self) internal view returns (bool canStartAward){\n if(supportsFunction(self, PeriodicPrizeStrategyInterface.canStartAward.selector)){\n return PeriodicPrizeStrategyInterface(self).canStartAward();\n }\n return false;\n }\n \n ///@param selector is the function selector to check against\n ///@return success returns true if function is implemented, false otherwise\n function supportsFunction(address self, bytes4 selector) internal view returns (bool success){\n bytes memory encodedParams = abi.encodeWithSelector(selector);\n (bool success, bytes memory result) = self.staticcall{ gas: 30000 }(encodedParams);\n if (result.length < 32){\n return (false);\n }\n if(!success && result.length > 0){\n revert(string(result));\n }\n return (success);\n }\n}" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "evmVersion": "istanbul", + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index 06577ab..b17514b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pooltogether/pooltogether-prizestrategy-upkeep", - "version": "1.0.1", + "version": "1.0.2", "description": "Upkeep integration contracts for the PoolTogether protocol", "author": "Aodhgan Gleeson", "license": "MIT",