diff --git a/foundry-upgrades.json b/foundry-upgrades.json new file mode 100644 index 0000000..83cfefe --- /dev/null +++ b/foundry-upgrades.json @@ -0,0 +1,3 @@ +{ + "build-info-directory": "out/build-info-full" +} diff --git a/foundry.toml b/foundry.toml index e18a79e..32b27bf 100644 --- a/foundry.toml +++ b/foundry.toml @@ -36,3 +36,6 @@ solc_version = "0.8.26" #sepolia = "${SEPOLIA_RPC_URL}" #local = "${LOCAL_RPC_URL}" #polygon = "${POLYGON_RPC_URL}" + + + diff --git a/script/DeployerStakingManger.s.sol b/script/DeployerStakingManger.s.sol index 46e8824..6771d23 100644 --- a/script/DeployerStakingManger.s.sol +++ b/script/DeployerStakingManger.s.sol @@ -4,16 +4,20 @@ pragma solidity ^0.8.13; import "forge-std/Script.sol"; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; -import { StakingManager } from "../src/contracts/core/StakingManager.sol"; -import { IFishcakeEventManager } from "../src/contracts/interfaces/IFishcakeEventManager.sol"; -import { INftManager } from "../src/contracts/interfaces/INftManager.sol"; - +import {StakingManager} from "../src/contracts/core/StakingManager.sol"; +import {IFishcakeEventManager} from "../src/contracts/interfaces/IFishcakeEventManager.sol"; +import {INftManager} from "../src/contracts/interfaces/INftManager.sol"; contract DeployerStakingMangerScript is Script { + IFishcakeEventManager public constant PROXY_FISH_CAKE_EVENT_MANAGER = + IFishcakeEventManager( + address(0x2CAf752814f244b3778e30c27051cc6B45CB1fc9) + ); + INftManager public constant PROXY_NFT_MANAGER = + INftManager(address(0x2F2Cb24BaB1b6E2353EF6246a2Ea4ce50487008B)); - IFishcakeEventManager public constant PROXY_FISH_CAKE_EVENT_MANAGER = IFishcakeEventManager(address(0x2CAf752814f244b3778e30c27051cc6B45CB1fc9)); - INftManager public constant PROXY_NFT_MANAGER = INftManager(address(0x2F2Cb24BaB1b6E2353EF6246a2Ea4ce50487008B)); - + address public constant fccAddress = + address(0x84eBc138F4Ab844A3050a6059763D269dC9951c6); function run() public { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); @@ -24,14 +28,36 @@ contract DeployerStakingMangerScript is Script { StakingManager stakingManagerImplementation = new StakingManager(); - console.log("StakingManager address:", address(stakingManagerImplementation)); - - bytes memory data = abi.encodeCall(stakingManagerImplementation.initialize, (deployerAddress, PROXY_FISH_CAKE_EVENT_MANAGER, PROXY_NFT_MANAGER)); - - ERC1967Proxy proxyStakingManager = new ERC1967Proxy(address(stakingManagerImplementation), data); + console.log( + "=========== StakingManager Logic address: =============", + address(stakingManagerImplementation) + ); + + bytes memory data = abi.encodeCall( + stakingManagerImplementation.initialize, + ( + deployerAddress, // 升级权限和逻辑权限都在deployerAddress + fccAddress, + PROXY_FISH_CAKE_EVENT_MANAGER, + PROXY_NFT_MANAGER + ) + ); + + ERC1967Proxy proxyStakingManager = new ERC1967Proxy( + address(stakingManagerImplementation), + data + ); vm.stopBroadcast(); - console.log("UUPS Proxy Address:", address(proxyStakingManager)); + console.log( + "========UUPS Proxy StakingManager Address: =========", + address(proxyStakingManager) + ); + + console.log( + "========StakingManager Owner: =========", + StakingManager(payable(address(proxyStakingManager))).owner() + ); } } diff --git a/script/UpgradeDirectSalePoolV1.s.sol b/script/UpgradeDirectSalePoolV1.s.sol index d84b2f2..9495fb6 100644 --- a/script/UpgradeDirectSalePoolV1.s.sol +++ b/script/UpgradeDirectSalePoolV1.s.sol @@ -2,32 +2,75 @@ pragma solidity ^0.8.13; import "@openzeppelin-foundry-upgrades/Upgrades.sol"; -import "forge-std/Script.sol"; -import { DirectSalePoolV1 } from "../src/contracts/core/sale/DirectSalePoolV1.sol"; +import "forge-std/Script.sol"; +import {DirectSalePoolV1} from "../src/contracts/core/sale/DirectSalePoolV1.sol"; contract UpgradeDirectSalePoolV1Script is Script { - address public constant PROXY_DIRECT_SALE_POOL = address(0xF71C97C9C6B2133A0Cb5c3ED4CC6eFe5e1BC534C); + address public constant INITIAL_OWNER = + 0x7a129d41bb517aD9A6FA49afFAa92eBeea2DFe07; + address public constant FCC_ADDRESS = + 0x84eBc138F4Ab844A3050a6059763D269dC9951c6; + address public constant USDT_ADDRESS = + 0xc2132D05D31c914a87C6611C10748AEb04B58e8F; + address public constant REDEMPT_POOL = + 0x036423643CEB603B7aff40A05627F09C04b9897E; + + address public constant PROXY_DIRECT_SALE_POOL = + address(0xF71C97C9C6B2133A0Cb5c3ED4CC6eFe5e1BC534C); function run() public { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); address deployerAddress = vm.addr(deployerPrivateKey); console.log("deploy deployerAddress:", address(deployerAddress)); - console.log("address(this):", address(this)); + // console.log("address(this):", address(this)); vm.startBroadcast(deployerPrivateKey); DirectSalePoolV1 newImplementation = new DirectSalePoolV1(); - console.log("New DirectSalePoolV1 implementation deployed at:", address(newImplementation)); + console.log( + "New DirectSalePoolV1 implementation deployed at:", + address(newImplementation) + ); + + console.log( + "DirectSalePool Proxy Admin:", + Upgrades.getAdminAddress(PROXY_DIRECT_SALE_POOL) + ); + console.log( + "DirectSalePool upgraded before:", + Upgrades.getImplementationAddress(PROXY_DIRECT_SALE_POOL) + ); - console.log("DirectSalePool Proxy Admin:", Upgrades.getAdminAddress(PROXY_DIRECT_SALE_POOL)); - console.log("DirectSalePool upgraded before:", Upgrades.getImplementationAddress(PROXY_DIRECT_SALE_POOL)); + // // 加入初始化 data + // bytes memory data = abi.encodeCall( + // DirectSalePoolV1.initialize, + // (INITIAL_OWNER, FCC_ADDRESS, REDEMPT_POOL, USDT_ADDRESS) + // ); // 升级权限在 deployerAddress,逻辑权限在 INITIAL_OWNER - Upgrades.upgradeProxy(PROXY_DIRECT_SALE_POOL, "DirectSalePoolV1.sol:DirectSalePoolV1", "", deployerAddress); + Upgrades.upgradeProxy( + PROXY_DIRECT_SALE_POOL, + "DirectSalePoolV1.sol:DirectSalePoolV1", + "", + deployerAddress + ); console.log("DirectSalePoolV1 proxy upgraded successfully"); vm.stopBroadcast(); + console.log( + "=========DirectSalePool upgraded logic address after: ===========", + Upgrades.getImplementationAddress(PROXY_DIRECT_SALE_POOL) + ); + console.log( + "DirectSalePool Proxy Admin:", + Upgrades.getAdminAddress(PROXY_DIRECT_SALE_POOL) + ); + + DirectSalePoolV1 directSalePoolV1 = DirectSalePoolV1( + payable(PROXY_DIRECT_SALE_POOL) + ); + + console.log("========Proxy:==========", PROXY_DIRECT_SALE_POOL); - console.log("DirectSalePool upgraded after:", Upgrades.getImplementationAddress(PROXY_DIRECT_SALE_POOL)); - console.log("DirectSalePool Proxy Admin:", Upgrades.getAdminAddress(PROXY_DIRECT_SALE_POOL)); + console.log("========Owner:==========", directSalePoolV1.owner()); } } diff --git a/script/UpgradeFishcakeEventManagerV2.s.sol b/script/UpgradeFishcakeEventManagerV2.s.sol index 62c1abe..91cb328 100644 --- a/script/UpgradeFishcakeEventManagerV2.s.sol +++ b/script/UpgradeFishcakeEventManagerV2.s.sol @@ -2,31 +2,77 @@ pragma solidity ^0.8.13; import "@openzeppelin-foundry-upgrades/Upgrades.sol"; -import "forge-std/Script.sol"; +import "forge-std/Script.sol"; import {FishcakeEventManagerV2} from "../src/contracts/core/FishcakeEventManagerV2.sol"; contract FishcakeEventManagerV2Script is Script { - address public constant PROXY_FISH_CAKE_EVENT_MANAGER = address(0x2CAf752814f244b3778e30c27051cc6B45CB1fc9); + address public constant PROXY_FISH_CAKE_EVENT_MANAGER = + address(0x2CAf752814f244b3778e30c27051cc6B45CB1fc9); + + address public constant INITIAL_OWNER = + 0x7a129d41bb517aD9A6FA49afFAa92eBeea2DFe07; + address public constant FCC_ADDRESS = + 0x84eBc138F4Ab844A3050a6059763D269dC9951c6; + address public constant USDT_ADDRESS = + 0xc2132D05D31c914a87C6611C10748AEb04B58e8F; + address public constant NFT_MANAGER = + 0x2F2Cb24BaB1b6E2353EF6246a2Ea4ce50487008B; function run() public { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); address deployerAddress = vm.addr(deployerPrivateKey); console.log("deploy deployerAddress:", address(deployerAddress)); - console.log("address(this):", address(this)); + // console.log("address(this):", address(this)); vm.startBroadcast(deployerPrivateKey); FishcakeEventManagerV2 newImplementation = new FishcakeEventManagerV2(); - console.log("New FishcakeEventManagerV2 implementation deployed at:", address(newImplementation)); + console.log( + "New FishcakeEventManagerV2 implementation deployed at:", + address(newImplementation) + ); + + console.log( + "Proxy Admin:", + Upgrades.getAdminAddress(PROXY_FISH_CAKE_EVENT_MANAGER) + ); + console.log( + "upgraded before:", + Upgrades.getImplementationAddress(PROXY_FISH_CAKE_EVENT_MANAGER) + ); - console.log("Proxy Admin:", Upgrades.getAdminAddress(PROXY_FISH_CAKE_EVENT_MANAGER)); - console.log("upgraded before:", Upgrades.getImplementationAddress(PROXY_FISH_CAKE_EVENT_MANAGER)); + // // 加入初始化 data + // bytes memory data = abi.encodeCall( + // FishcakeEventManagerV2.initialize, + // (INITIAL_OWNER, FCC_ADDRESS, USDT_ADDRESS, NFT_MANAGER) + // ); // 升级权限在 deployerAddress,逻辑权限在 INITIAL_OWNER - Upgrades.upgradeProxy(PROXY_FISH_CAKE_EVENT_MANAGER, "FishcakeEventManagerV2.sol:FishcakeEventManagerV2", "", deployerAddress); + Upgrades.upgradeProxy( + PROXY_FISH_CAKE_EVENT_MANAGER, + "FishcakeEventManagerV2.sol:FishcakeEventManagerV2", + "", + deployerAddress + ); console.log("FishcakeEventManagerV2 proxy upgraded successfully"); - console.log("======================================================================="); + console.log( + "=======================================================================" + ); vm.stopBroadcast(); - console.log("upgraded after:", Upgrades.getImplementationAddress(PROXY_FISH_CAKE_EVENT_MANAGER)); - console.log("Proxy Admin:", Upgrades.getAdminAddress(PROXY_FISH_CAKE_EVENT_MANAGER)); + console.log( + "==========upgraded logic address after: ============", + Upgrades.getImplementationAddress(PROXY_FISH_CAKE_EVENT_MANAGER) + ); + console.log( + "Proxy Admin:", + Upgrades.getAdminAddress(PROXY_FISH_CAKE_EVENT_MANAGER) + ); + + FishcakeEventManagerV2 fishcakeEventManagerV2 = FishcakeEventManagerV2( + payable(PROXY_FISH_CAKE_EVENT_MANAGER) + ); + + console.log("========Proxy:==========", PROXY_FISH_CAKE_EVENT_MANAGER); + + console.log("========Owner:==========", fishcakeEventManagerV2.owner()); } } diff --git a/script/UpgradeInvestSalePoolV1.s.sol b/script/UpgradeInvestSalePoolV1.s.sol new file mode 100644 index 0000000..3e7761d --- /dev/null +++ b/script/UpgradeInvestSalePoolV1.s.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "@openzeppelin-foundry-upgrades/Upgrades.sol"; +import "forge-std/Script.sol"; +import {InvestorSalePool} from "../src/contracts/core/sale/InvestorSalePool.sol"; + +contract UpgradeInvestorSalePoolScript is Script { + address public constant INITIAL_OWNER = + 0x7a129d41bb517aD9A6FA49afFAa92eBeea2DFe07; + address public constant FCC_ADDRESS = + 0x84eBc138F4Ab844A3050a6059763D269dC9951c6; + address public constant USDT_ADDRESS = + 0xc2132D05D31c914a87C6611C10748AEb04B58e8F; + address public constant REDEMPT_POOL = + 0x036423643CEB603B7aff40A05627F09C04b9897E; + + address public constant PROXY_INVESTOR_SALE_POOL = + address(0x9dA9d48c3b1CB9B8c4AE3c195a6Bee5BAaa5314A); + + function run() public { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + address deployerAddress = vm.addr(deployerPrivateKey); + console.log("deploy deployerAddress:", address(deployerAddress)); + + // console.log("address(this):", address(this)); + + vm.startBroadcast(deployerPrivateKey); + InvestorSalePool newImplementation = new InvestorSalePool(); + console.log( + "New InvestorSalePool implementation deployed at:", + address(newImplementation) + ); + + console.log( + "DirectSalePool Proxy Admin:", + Upgrades.getAdminAddress(PROXY_INVESTOR_SALE_POOL) + ); + console.log( + "DirectSalePool upgraded before:", + Upgrades.getImplementationAddress(PROXY_INVESTOR_SALE_POOL) + ); + + // // 加入初始化 data + // bytes memory data = abi.encodeCall( + // InvestorSalePool.initialize, + // (INITIAL_OWNER, FCC_ADDRESS, REDEMPT_POOL, USDT_ADDRESS) + // ); // 升级权限在 deployerAddress,逻辑权限在 INITIAL_OWNER + + Upgrades.upgradeProxy( + PROXY_INVESTOR_SALE_POOL, + "InvestorSalePool.sol:InvestorSalePool", + "", + deployerAddress + ); + console.log("InvestorSalePool proxy upgraded successfully"); + vm.stopBroadcast(); + + console.log( + "======= InvestorSalePool logic address upgraded after:==========", + Upgrades.getImplementationAddress(PROXY_INVESTOR_SALE_POOL) + ); + console.log( + "InvestorSalePool Proxy Admin:", + Upgrades.getAdminAddress(PROXY_INVESTOR_SALE_POOL) + ); + + InvestorSalePool investorSalePool = InvestorSalePool( + payable(PROXY_INVESTOR_SALE_POOL) + ); + + console.log("========Proxy:==========", PROXY_INVESTOR_SALE_POOL); + + console.log("========Owner:==========", investorSalePool.owner()); + } +} diff --git a/script/UpgradeNftManagerV5DeployerScript.s.sol b/script/UpgradeNftManagerV5DeployerScript.s.sol index 94c9fcf..dda20d5 100644 --- a/script/UpgradeNftManagerV5DeployerScript.s.sol +++ b/script/UpgradeNftManagerV5DeployerScript.s.sol @@ -11,35 +11,91 @@ import "@openzeppelin-foundry-upgrades/Upgrades.sol"; import {NftManagerV5} from "../src/contracts/core/token/NftManagerV5.sol"; contract UpgradeNftManagerV5DeployerScript is Script { + address public constant INITIAL_OWNER = + 0x7a129d41bb517aD9A6FA49afFAa92eBeea2DFe07; + address public constant FCC_ADDRESS = + 0x84eBc138F4Ab844A3050a6059763D269dC9951c6; + address public constant USDT_ADDRESS = + 0xc2132D05D31c914a87C6611C10748AEb04B58e8F; + address public constant REDEMPT_POOL = + 0x036423643CEB603B7aff40A05627F09C04b9897E; + address public constant STAKING_MANAGER = + 0x19C6bf3Ae8DFf14967C1639b96887E8778738417; + // main network - address public constant PROXY_NFT_MANAGER = address(0x2F2Cb24BaB1b6E2353EF6246a2Ea4ce50487008B); + address public constant PROXY_NFT_MANAGER = + address(0x2F2Cb24BaB1b6E2353EF6246a2Ea4ce50487008B); function run() public { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); address deployerAddress = vm.addr(deployerPrivateKey); NftManagerV5 newImplementation = new NftManagerV5(); - console.log("New newNftManager implementation deployed at:", address(newImplementation)); + console.log( + "New newNftManager implementation deployed at:", + address(newImplementation) + ); vm.startBroadcast(deployerPrivateKey); - console.log("upgraded before:", Upgrades.getImplementationAddress(PROXY_NFT_MANAGER)); - Upgrades.upgradeProxy(PROXY_NFT_MANAGER, "NftManagerV5.sol:NftManagerV5", ""); + console.log( + "upgraded before:", + Upgrades.getImplementationAddress(PROXY_NFT_MANAGER) + ); + Upgrades.upgradeProxy( + PROXY_NFT_MANAGER, + "NftManagerV5.sol:NftManagerV5", + "" + ); + NftManagerV5 upgradedNftManager = NftManagerV5( + payable(PROXY_NFT_MANAGER) + ); + upgradedNftManager.initializeV5(STAKING_MANAGER); + vm.stopBroadcast(); - console.log("upgraded after:", Upgrades.getImplementationAddress(PROXY_NFT_MANAGER)); - console.log("Proxy Admin:", Upgrades.getAdminAddress(PROXY_NFT_MANAGER)); + + console.log( + "=========upgraded logic address after:=========", + Upgrades.getImplementationAddress(PROXY_NFT_MANAGER) + ); + console.log( + "New NftManagerV5 implementation:", + address(newImplementation) + ); + + console.log( + "Proxy Admin:", + Upgrades.getAdminAddress(PROXY_NFT_MANAGER) + ); console.log("NftManager proxy upgraded successfully"); - console.log("======================================================================="); - console.log("Owner:", deployerAddress); - console.log("New NftManagerV5 implementation:", address(newImplementation)); - console.log("NftManager proxy:", PROXY_NFT_MANAGER); + console.log( + "=======================================================================" + ); + + console.log("========Owner:==========", upgradedNftManager.owner()); + + console.log("=========NftManager proxy:==========", PROXY_NFT_MANAGER); + + console.log( + "========StakingManager:==========", + address(upgradedNftManager.stakingManagerAddress()) + ); // Verify upgraded state - NftManagerV5 upgradedNftManager = NftManagerV5(payable(PROXY_NFT_MANAGER)); + console.log("Verifying upgraded state..."); - console.log("fccTokenAddr:", address(upgradedNftManager.fccTokenAddr())); - console.log("tokenUsdtAddr:", address(upgradedNftManager.tokenUsdtAddr())); - console.log("redemptionPoolAddress:", address(upgradedNftManager.redemptionPoolAddress())); + console.log( + "fccTokenAddr:", + address(upgradedNftManager.fccTokenAddr()) + ); + console.log( + "tokenUsdtAddr:", + address(upgradedNftManager.tokenUsdtAddr()) + ); + console.log( + "redemptionPoolAddress:", + address(upgradedNftManager.redemptionPoolAddress()) + ); console.log("New name:", upgradedNftManager.name()); console.log("New symbol:", upgradedNftManager.symbol()); diff --git a/src/contracts/core/StakingManager.sol b/src/contracts/core/StakingManager.sol index ae5c164..570d969 100644 --- a/src/contracts/core/StakingManager.sol +++ b/src/contracts/core/StakingManager.sol @@ -10,11 +10,17 @@ import {StakingManagerStorage} from "./StakingManagerStorage.sol"; import "../interfaces/IFishcakeEventManager.sol"; import "../interfaces/INftManager.sol"; + +import "@openzeppelin-upgrades/contracts/proxy/utils/UUPSUpgradeable.sol"; + contract StakingManager is Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable, - StakingManagerStorage + + StakingManagerStorage, + UUPSUpgradeable + { using SafeERC20 for IERC20; @@ -43,12 +49,16 @@ contract StakingManager is __Ownable_init(_initialOwner); _transferOwnership(_initialOwner); __ReentrancyGuard_init(); + __UUPSUpgradeable_init(); messageNonce = 0; } function depositIntoStaking( uint256 amount, - uint8 stakingType + + uint8 stakingType, + bool isAutoRenew + ) external nonReentrant { require( amount >= minStakeAmount, @@ -70,6 +80,9 @@ contract StakingManager is msg.sender ); + uint256 nftApr = getNftApr(msg.sender, tokenId); + + stakeHolderStakingInfo memory ssInfo = stakeHolderStakingInfo({ startStakingTime: block.timestamp, amount: amount, @@ -77,7 +90,8 @@ contract StakingManager is endStakingTime: endTime, stakingStatus: 0, // under staking now stakingType: stakingType, - bindingNft: tokenId + bindingNft: tokenId, + isAutoRenew: isAutoRenew }); nftManagerAddress.inActiveMinerBoosterNft(msg.sender); @@ -86,7 +100,17 @@ contract StakingManager is totalStakingAmount += amount; - emit StakeHolderDepositStaking(msg.sender, amount, messageNonce); + emit StakeHolderDepositStaking( + msg.sender, + amount, + stakingType, + block.timestamp, + endTime, + tokenId, + nftApr, + isAutoRenew, + messageNonce + ); messageNonce++; } @@ -114,12 +138,13 @@ contract StakingManager is totalStakingAmount -= amount; stakingQueued[msg.sender][txMessageHash].stakingStatus = 1; //staking end - uint256 rewardAprFunding = calculateArpFunding( + uint256 rewardAprFunding = calculateAprFunding( msg.sender, stakingQueued[msg.sender][txMessageHash].amount, stakingQueued[msg.sender][txMessageHash].stakingType, stakingQueued[msg.sender][txMessageHash].startStakingTime, - stakingQueued[msg.sender][txMessageHash].bindingNft + stakingQueued[msg.sender][txMessageHash].bindingNft, + stakingQueued[msg.sender][txMessageHash].isAutoRenew ); IERC20(fccAddress).safeTransfer(msg.sender, amount); @@ -129,7 +154,10 @@ contract StakingManager is msg.sender, amount, messageNonce, - txMessageHash + + txMessageHash, + rewardAprFunding + ); } @@ -141,12 +169,13 @@ contract StakingManager is abi.encode(msg.sender, fccAddress, amount, messageNonce) ); - uint256 rewardAprFunding = calculateArpFunding( + uint256 rewardAprFunding = calculateAprFunding( msg.sender, stakingQueued[msg.sender][txMessageHash].amount, stakingQueued[msg.sender][txMessageHash].stakingType, stakingQueued[msg.sender][txMessageHash].startStakingTime, - stakingQueued[msg.sender][txMessageHash].bindingNft + stakingQueued[msg.sender][txMessageHash].bindingNft, + stakingQueued[msg.sender][txMessageHash].isAutoRenew ); return rewardAprFunding; } @@ -172,28 +201,57 @@ contract StakingManager is } //==========================internal function=============================== - function calculateArpFunding( + + function calculateAprFunding( + address miner, uint256 stakingAmount, uint8 stakingType, uint256 stakingTime, - uint256 tokenId + + uint256 tokenId, + bool isAutoRenew ) internal view returns (uint256) { - uint256 stakingArp = 0; - uint256 lockType = 0; + uint256 stakingApr = 0; + uint256 lockTime = 0; + uint256 nftApr = getNftApr(miner, tokenId); - (lockType, stakingArp) = getStakingPeriodAndApr(stakingType); - uint256 totalRewardApr = nftApr + stakingArp; + (lockTime, stakingApr) = getStakingPeriodAndApr(stakingType); + uint256 totalRewardApr = nftApr + stakingApr; uint256 actualStakingDuration = block.timestamp - stakingTime; + + // First calculate effective staking duration + if (actualStakingDuration <= lockTime || isAutoRenew) { + actualStakingDuration = actualStakingDuration; + } else { + actualStakingDuration = lockTime; + } + + // Then calculate reward: booster APR only counts for lock time, staking APR counts for all time + uint256 reward = 0; + if (actualStakingDuration < lockTime) { + reward = + (stakingAmount * totalRewardApr * actualStakingDuration) / + (100 * 365 days); + } else { + uint256 baseReward = (stakingAmount * totalRewardApr * lockTime) / + (100 * 365 days); + uint256 extraReward = (stakingAmount * + stakingApr * + (actualStakingDuration - lockTime)) / (100 * 365 days); + reward = baseReward + extraReward; + } + + // Halve the reward if past halfAprTimeStamp(2026/01/01) if (block.timestamp >= halfAprTimeStamp) { - uint256 reward = (stakingAmount * - totalRewardApr * - actualStakingDuration) / (100 * 365 days); + + return reward / 2; + } else { + return reward; } - return - (stakingAmount * totalRewardApr * actualStakingDuration) / - (100 * 365 days); + + } function getNftApr( @@ -213,7 +271,9 @@ contract StakingManager is } else if (nftType == 0) { return 0; } else { - return 1; + + return 0; + } } @@ -234,4 +294,10 @@ contract StakingManager is return (lockHalfYears, 15); } } + + /// @notice 授权升级逻辑合约的函数 + /// @dev 只允许合约owner执行 + function _authorizeUpgrade( + address newImplementation + ) internal override onlyOwner {} } diff --git a/src/contracts/core/StakingManagerStorage.sol b/src/contracts/core/StakingManagerStorage.sol index 0ad5d45..1b6fa6b 100644 --- a/src/contracts/core/StakingManagerStorage.sol +++ b/src/contracts/core/StakingManagerStorage.sol @@ -47,6 +47,7 @@ abstract contract StakingManagerStorage is IStakingManager { uint8 stakingStatus; uint8 stakingType; uint256 bindingNft; + bool isAutoRenew; } mapping(address => mapping(bytes32 => stakeHolderStakingInfo)) stakingQueued; diff --git a/src/contracts/core/sale/DirectSalePoolStorage.sol b/src/contracts/core/sale/DirectSalePoolStorage.sol index be1c5f8..d795d55 100644 --- a/src/contracts/core/sale/DirectSalePoolStorage.sol +++ b/src/contracts/core/sale/DirectSalePoolStorage.sol @@ -21,7 +21,9 @@ abstract contract DirectSalePoolStorage is IDirectSalePool, Initializable { address _fishCakeCoin, address _redemptionPool, address _tokenUsdtAddress - ) internal { + + ) internal onlyInitializing { + fishCakeCoin = IERC20(_fishCakeCoin); redemptionPool = IRedemptionPool(_redemptionPool); tokenUsdtAddress = IERC20(_tokenUsdtAddress); diff --git a/src/contracts/core/token/NftManagerStorage.sol b/src/contracts/core/token/NftManagerStorage.sol index 1cdfac3..12d7146 100644 --- a/src/contracts/core/token/NftManagerStorage.sol +++ b/src/contracts/core/token/NftManagerStorage.sol @@ -10,8 +10,6 @@ import "../../interfaces/IFishcakeEventManager.sol"; import "../../interfaces/INftManager.sol"; import "../../interfaces/IStakingManager.sol"; - - abstract contract NftManagerStorage is Initializable, INftManager { using Strings for uint256; using Strings for uint8; @@ -50,6 +48,11 @@ abstract contract NftManagerStorage is Initializable, INftManager { string public epicSalmonNftJson; string public legendaryTunaNftJson; + // string public uncommonFishcakeNftJson_Used; + // string public rareShrimpNftJson_Used; + // string public epicSalmonNftJson_Used; + // string public legendaryTunaNftJson_Used; + IFishcakeEventManager public feManagerAddress; mapping(address => uint256) public minerActiveNft; @@ -60,7 +63,11 @@ abstract contract NftManagerStorage is Initializable, INftManager { IStakingManager public stakingManagerAddress; - function __NftManagerStorage_init(address _fccTokenAddr, address _tokenUsdtAddr, address _redemptionPoolAddress) internal initializer { + function __NftManagerStorage_init( + address _fccTokenAddr, + address _tokenUsdtAddr, + address _redemptionPoolAddress + ) internal initializer { fccTokenAddr = IERC20(_fccTokenAddr); tokenUsdtAddr = IERC20(_tokenUsdtAddr); redemptionPoolAddress = IRedemptionPool(_redemptionPoolAddress); @@ -72,6 +79,5 @@ abstract contract NftManagerStorage is Initializable, INftManager { proNftJson = "https://www.fishcake.org/image/1.json"; basicNftJson = "https://www.fishcake.org/image/2.json"; - } } diff --git a/src/contracts/core/token/NftManagerV5.sol b/src/contracts/core/token/NftManagerV5.sol index bb9ba1e..c9617d7 100644 --- a/src/contracts/core/token/NftManagerV5.sol +++ b/src/contracts/core/token/NftManagerV5.sol @@ -105,6 +105,14 @@ contract NftManagerV5 is _tokenUsdtAddr, _redemptionPoolAddress ); + + } + + function initializeV5( + address _stakingManagerAddress + ) public reinitializer(5) { + stakingManagerAddress = IStakingManager(_stakingManagerAddress); + } receive() external payable { @@ -121,6 +129,11 @@ contract NftManagerV5 is epicSalmonNftJson = "https://www.fishcake.org/image/5.json"; legendaryTunaNftJson = "https://www.fishcake.org/image/6.json"; + // uncommonFishcakeNftJson_Used = "https://www.fishcake.org/image/3.json"; + // rareShrimpNftJson_Used = "https://www.fishcake.org/image/4.json"; + // epicSalmonNftJson_Used = "https://www.fishcake.org/image/5.json"; + // legendaryTunaNftJson_Used = "https://www.fishcake.org/image/6.json"; + feManagerAddress = IFishcakeEventManager(_feManagerAddress); stakingManagerAddress = IStakingManager(_stakingManagerAddress); boosterAddress = _boosterAddress; @@ -197,7 +210,9 @@ contract NftManagerV5 is ); tokenUsdtAddr.safeTransfer( address(redemptionPoolAddress), - (payUsdtAmount * 75) / 100 + + (payUsdtAmount * 25) / 100 + ); uint256 tokenId = _nextTokenId++; @@ -243,9 +258,20 @@ contract NftManagerV5 is return rareShrimpNftJson; } else if (nftType == 5) { return epicSalmonNftJson; - } else { + } else if (nftType == 6) { return legendaryTunaNftJson; + } else { + return ""; } + // } else if (nftType == 3 + 10) { + // return uncommonFishcakeNftJson_Used; + // } else if (nftType == 4 + 10) { + // return rareShrimpNftJson_Used; + // } else if (nftType == 5 + 10) { + // return epicSalmonNftJson_Used; + // } else if (nftType == 6 + 10) { + // return legendaryTunaNftJson_Used; + // } } function uri( @@ -327,7 +353,10 @@ contract NftManagerV5 is function inActiveMinerBoosterNft( address _miner ) external onlyStakingManager { - minerActiveNft[_miner] = 0; + + uint256 activeNftId = minerActiveNft[_miner]; + minerActiveNft[_miner] = activeNftId + 10; + } function getActiveMinerBoosterNft( diff --git a/src/contracts/interfaces/IFishcakeEventManager.sol b/src/contracts/interfaces/IFishcakeEventManager.sol index 50c66f9..7ada8be 100644 --- a/src/contracts/interfaces/IFishcakeEventManager.sol +++ b/src/contracts/interfaces/IFishcakeEventManager.sol @@ -52,8 +52,14 @@ interface IFishcakeEventManager { ) external returns (bool, uint256); function activityFinish(uint256 _activityId) external returns (bool); - function drop(uint256 _activityId, address _userAccount, uint256 _dropAmt) external returns (bool); + + function drop( + uint256 _activityId, + address _userAccount, + uint256 _dropAmt + ) external returns (bool); function getMinerMineAmount(address _miner) external view returns (uint256); + function deleteMinerMineAmount(address _miner) external; } diff --git a/src/contracts/interfaces/IStakingManager.sol b/src/contracts/interfaces/IStakingManager.sol index ba419ff..2db5adc 100644 --- a/src/contracts/interfaces/IStakingManager.sol +++ b/src/contracts/interfaces/IStakingManager.sol @@ -4,7 +4,13 @@ pragma solidity ^0.8.0; interface IStakingManager { event StakeHolderDepositStaking( address indexed staker, - uint256 stakingAmount, + uint256 amount, + uint8 stakingType, + uint256 startStakingTime, + uint256 endStakingTime, + uint256 bindingNft, + uint256 nftApr, + bool isAutoRenew, uint256 messageNonce ); @@ -12,7 +18,8 @@ interface IStakingManager { address indexed recipant, uint256 withdrawAmount, uint256 messageNonce, - bytes32 messageHash + bytes32 messageHash, + uint256 rewardAprFunding ); event Received(address indexed receiver, uint256 _value); @@ -20,7 +27,13 @@ interface IStakingManager { error FundingUnderStaking(uint256 amount, uint256 endTime); error NoFundingForStaking(); - function depositIntoStaking(uint256 amount, uint8 stakingType) external; + + function depositIntoStaking( + uint256 amount, + uint8 stakingType, + bool isAutonew + ) external; + function withdrawFromStakingWithAprIncome( uint256 amount,