From 654417985e16c30c1e9c56e915115f80f88f586b Mon Sep 17 00:00:00 2001 From: BkChoy Date: Tue, 29 Aug 2023 18:57:00 -0400 Subject: [PATCH] priority pool oracle contract --- contracts/core/interfaces/IPriorityPool.sol | 15 +++ .../core/priorityPool/DistributionOracle.sol | 97 +++++++++++++++++++ .../core/{ => priorityPool}/PriorityPool.sol | 4 +- package.json | 2 +- yarn.lock | 26 ++++- 5 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 contracts/core/interfaces/IPriorityPool.sol create mode 100644 contracts/core/priorityPool/DistributionOracle.sol rename contracts/core/{ => priorityPool}/PriorityPool.sol (99%) diff --git a/contracts/core/interfaces/IPriorityPool.sol b/contracts/core/interfaces/IPriorityPool.sol new file mode 100644 index 00000000..710e4b40 --- /dev/null +++ b/contracts/core/interfaces/IPriorityPool.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.15; + +interface IPriorityPool { + function paused() external view returns (bool); + + function pauseForUpdate() external; + + function updateDistribution( + bytes32 _merkleRoot, + bytes32 _ipfsHash, + uint256 _amountDistributed, + uint256 _sharesAmountDistributed + ) external; +} diff --git a/contracts/core/priorityPool/DistributionOracle.sol b/contracts/core/priorityPool/DistributionOracle.sol new file mode 100644 index 00000000..1de90da7 --- /dev/null +++ b/contracts/core/priorityPool/DistributionOracle.sol @@ -0,0 +1,97 @@ +//SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +import "../interfaces/IPriorityPool.sol"; + +contract DistributionOracle is ChainlinkClient, Ownable { + using Chainlink for Chainlink.Request; + + IPriorityPool public priorityPool; + + bytes32 public jobId; + uint256 public fee; + + uint256 public minBlockConfirmations; + uint256 public pausedAtBlockNumber; + + error NotPaused(); + error InsufficientBlockConfirmations(); + error InsufficientBalance(); + + /** + * @notice Initialize the contract + * @param _chainlinkToken address of LINK token + * @param _chainlinkOracle address of operator contract + * @param _jobId id of job + * @param _fee fee charged for each request paid in LINK + * @param _minBlockConfirmations min # of blocks to wait to request update after pausing priority pool + * @param _priorityPool address of priority pool + */ + constructor( + address _chainlinkToken, + address _chainlinkOracle, + bytes32 _jobId, + uint256 _fee, + uint256 _minBlockConfirmations, + address _priorityPool + ) { + setChainlinkToken(_chainlinkToken); + setChainlinkOracle(_chainlinkOracle); + jobId = _jobId; + fee = _fee; + minBlockConfirmations = _minBlockConfirmations; + priorityPool = IPriorityPool(_priorityPool); + } + + /** + * @notice Pauses the priority pool so a new merkle tree can be calculated + * @dev must always be called before requestUpdate() + */ + function pauseForUpdate() external onlyOwner { + priorityPool.pauseForUpdate(); + pausedAtBlockNumber = block.number; + } + + /** + * @notice Requests a new update which will calculate a new merkle tree, post the data to IPFS, and update + * the priority pool + * @dev pauseForUpdate() must be called before calling this function + */ + function requestUpdate() external onlyOwner { + if (!priorityPool.paused()) revert NotPaused(); + if (block.number < pausedAtBlockNumber + minBlockConfirmations) revert InsufficientBlockConfirmations(); + Chainlink.Request memory req = buildChainlinkRequest(jobId, address(this), this.fulfillRequest.selector); + req.addUint("blockNumber", pausedAtBlockNumber); + sendChainlinkRequest(req, fee); + } + + /** + * @notice Fulfills an update request + * @param _requestId id of the request to fulfill + * @param _merkleRoot new merkle root for the distribution tree + * @param _ipfsHash new ipfs hash for the distribution tree (CIDv0, no prefix - only hash) + * @param _amountDistributed amount of LSD tokens distributed in this distribution + * @param _sharesAmountDistributed amount of LSD shares distributed in this distribution + */ + function fulfillRequest( + bytes32 _requestId, + bytes32 _merkleRoot, + bytes32 _ipfsHash, + uint256 _amountDistributed, + uint256 _sharesAmountDistributed + ) public recordChainlinkFulfillment(_requestId) { + priorityPool.updateDistribution(_merkleRoot, _ipfsHash, _amountDistributed, _sharesAmountDistributed); + } + + /** + * @notice Withdraws LINK tokens + * @param _amount amount to withdraw + */ + function withdrawLink(uint256 _amount) public onlyOwner { + LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress()); + if (link.transfer(msg.sender, _amount) != true) revert InsufficientBalance(); + } +} diff --git a/contracts/core/PriorityPool.sol b/contracts/core/priorityPool/PriorityPool.sol similarity index 99% rename from contracts/core/PriorityPool.sol rename to contracts/core/priorityPool/PriorityPool.sol index 1b070cdc..90b6fd3c 100644 --- a/contracts/core/PriorityPool.sol +++ b/contracts/core/priorityPool/PriorityPool.sol @@ -9,8 +9,8 @@ import "@openzeppelin/contracts-upgradeable/utils/cryptography/MerkleProofUpgrad import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; -import "./interfaces/IStakingPool.sol"; -import "./interfaces/ISDLPool.sol"; +import "../interfaces/IStakingPool.sol"; +import "../interfaces/ISDLPool.sol"; /** * @title Priority Pool diff --git a/package.json b/package.json index 366c516d..4db90314 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "typescript": "^4.5.5" }, "dependencies": { - "@chainlink/contracts": "^0.4.2", + "@chainlink/contracts": "0.6.1", "@openzeppelin/contracts": "^4.7.0", "@openzeppelin/contracts-upgradeable": "^4.9.2", "@prb/math": "^2.5.0", diff --git a/yarn.lock b/yarn.lock index eacdc70d..f520e706 100644 --- a/yarn.lock +++ b/yarn.lock @@ -201,12 +201,15 @@ "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" -"@chainlink/contracts@^0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@chainlink/contracts/-/contracts-0.4.2.tgz#2928a35e8da94664b8ffeb8f5a54b1a3f14d5b3f" - integrity sha512-wVI/KZ9nIH0iqoebVxYrZfNVWO23vwds1UrHdbF+S0JwyixtT+54xYGlot723jCrAeBeQHsDRQXnEhhbUEHpgQ== +"@chainlink/contracts@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@chainlink/contracts/-/contracts-0.6.1.tgz#8842b57e755793cbdbcbc45277fb5d179c993e19" + integrity sha512-EuwijGexttw0UjfrW+HygwhQIrGAbqpf1ue28R55HhWMHBzphEH0PhWm8DQmFfj5OZNy8Io66N4L0nStkZ3QKQ== dependencies: "@eth-optimism/contracts" "^0.5.21" + "@openzeppelin/contracts" "~4.3.3" + "@openzeppelin/contracts-upgradeable" "^4.7.3" + "@openzeppelin/contracts-v0.7" "npm:@openzeppelin/contracts@v3.4.2" "@cspotcode/source-map-consumer@0.8.0": version "0.8.0" @@ -1513,16 +1516,31 @@ "@types/sinon-chai" "^3.2.3" "@types/web3" "1.0.19" +"@openzeppelin/contracts-upgradeable@^4.7.3": + version "4.9.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.3.tgz#ff17a80fb945f5102571f8efecb5ce5915cc4811" + integrity sha512-jjaHAVRMrE4UuZNfDwjlLGDxTHWIOwTJS2ldnc278a0gevfXfPr8hxKEVBGFBE96kl2G3VHDZhUimw/+G3TG2A== + "@openzeppelin/contracts-upgradeable@^4.9.2": version "4.9.2" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.2.tgz#a817c75688f8daede420052fbcb34e52482e769e" integrity sha512-siviV3PZV/fHfPaoIC51rf1Jb6iElkYWnNYZ0leO23/ukXuvOyoC/ahy8jqiV7g+++9Nuo3n/rk5ajSN/+d/Sg== +"@openzeppelin/contracts-v0.7@npm:@openzeppelin/contracts@v3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2.tgz#d81f786fda2871d1eb8a8c5a73e455753ba53527" + integrity sha512-z0zMCjyhhp4y7XKAcDAi3Vgms4T2PstwBdahiO0+9NaGICQKjynK3wduSRplTgk4LXmoO1yfDGO5RbjKYxtuxA== + "@openzeppelin/contracts@^4.7.0": version "4.7.0" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.7.0.tgz#3092d70ea60e3d1835466266b1d68ad47035a2d5" integrity sha512-52Qb+A1DdOss8QvJrijYYPSf32GUg2pGaG/yCxtaA3cu4jduouTdg4XZSMLW9op54m1jH7J8hoajhHKOPsoJFw== +"@openzeppelin/contracts@~4.3.3": + version "4.3.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.3.3.tgz#ff6ee919fc2a1abaf72b22814bfb72ed129ec137" + integrity sha512-tDBopO1c98Yk7Cv/PZlHqrvtVjlgK5R4J6jxLwoO7qxK4xqOiZG+zSkIvGFpPZ0ikc3QOED3plgdqjgNTnBc7g== + "@openzeppelin/defender-base-client@^1.46.0": version "1.46.0" resolved "https://registry.yarnpkg.com/@openzeppelin/defender-base-client/-/defender-base-client-1.46.0.tgz#aa5177f8fbad23fd03d78f3dbe06664bbe9333ff"