diff --git a/contracts/DODOFee/FeeRateDIP3Impl.sol b/contracts/DODOFee/FeeRateDIP3Impl.sol index f5dcb50..715419b 100644 --- a/contracts/DODOFee/FeeRateDIP3Impl.sol +++ b/contracts/DODOFee/FeeRateDIP3Impl.sol @@ -25,6 +25,10 @@ interface IQuota { function getUserQuota(address user) external view returns (int); } +interface IPoolHeartBeat { + function isPoolHeartBeatLive(address pool) external view returns(bool); +} + interface IPool { function version() external pure returns (string memory); function _LP_FEE_RATE_() external view returns (uint256); @@ -47,9 +51,10 @@ contract FeeRateDIP3Impl is InitializableOwnable { address quotaAddr; } - mapping(address => CPPoolInfo) cpPools; + mapping(address => CPPoolInfo) public cpPools; mapping(address => uint256) public specPoolList; mapping (address => bool) public isAdminListed; + address public poolHeartBeat; // ============ Events ============= event AddAdmin(address admin); @@ -92,6 +97,9 @@ contract FeeRateDIP3Impl is InitializableOwnable { function removeAdminList (address userAddr) external onlyOwner { isAdminListed[userAddr] = false; emit RemoveAdmin(userAddr); + + function setPoolHeartBeat (address newPoolHeartBeat) public onlyOwner { + poolHeartBeat = newPoolHeartBeat; } // ============ View Functions ============ @@ -106,6 +114,10 @@ contract FeeRateDIP3Impl is InitializableOwnable { require(!(k==0 && (baseReserve ==0 || quoteReserve == 0)), "KJUDGE_ERROR"); } + if (poolHeartBeat != address(0) && !IPoolHeartBeat(poolHeartBeat).isPoolHeartBeatLive(pool)) { + return 10**18 - IPool(pool)._LP_FEE_RATE_() - 1; + } + if(specPoolList[pool] != 0) { return specPoolList[pool]; } diff --git a/contracts/DODOFee/PoolHeartBeat.sol b/contracts/DODOFee/PoolHeartBeat.sol new file mode 100644 index 0000000..26a31c2 --- /dev/null +++ b/contracts/DODOFee/PoolHeartBeat.sol @@ -0,0 +1,46 @@ +/* + + Copyright 2022 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; + + +contract PoolHeartBeat is InitializableOwnable { + + struct heartBeat { + uint256 lastHeartBeat; + uint256 maxInterval; + } + + mapping(address => address) public poolHeartBeatManager; // pool => heartbeat manager + mapping(address => heartBeat) public beats; // heartbeat manager => heartbeat + + function isPoolHeartBeatLive(address pool) external view returns(bool) { + if(poolHeartBeatManager[pool]==address(0)) { + return true; + } + heartBeat memory beat = beats[poolHeartBeatManager[pool]]; + return block.timestamp - beat.lastHeartBeat < beat.maxInterval; + } + + function triggerBeat() external { + heartBeat storage beat = beats[msg.sender]; + beat.lastHeartBeat = block.timestamp; + } + + function setBeatInterval(uint256 interval) external { + heartBeat storage beat = beats[msg.sender]; + beat.maxInterval = interval; + } + + function bindPoolHeartBeat(address[] memory pools, address manager) external onlyOwner { + for(uint256 i=0; i