文件 1 的 4:ApeXPool3.sol
pragma solidity ^0.8.0;
import "./interfaces/IApeXPool3.sol";
import "../utils/Ownable.sol";
import "../libraries/TransferHelper.sol";
contract ApeXPool3 is IApeXPool3, Ownable {
address public override apeX;
address public override esApeX;
struct stakingInfo{
address lockToken;
address owner;
uint256 accountId;
uint256 amount;
uint256 lockPeriod;
uint256 lockStart;
bool unlocked;
}
mapping(uint256 => stakingInfo) public stakingAPEX;
mapping(uint256 => stakingInfo) public stakingEsAPEX;
uint256 public globalStakeId;
bool public override paused;
constructor(address _apeX, address _esApeX, address _owner) {
apeX = _apeX;
esApeX = _esApeX;
owner = _owner;
}
function setPaused(bool newState) external override onlyOwner {
require(paused != newState, "same state");
paused = newState;
emit PausedStateChanged(newState);
}
function setApex(address _newApex) external override onlyOwner {
require(_newApex != address(0));
apeX = _newApex;
emit ApexChanged(_newApex);
}
function setEsApex(address _newEsApex) external override onlyOwner {
require(_newEsApex != address(0));
esApeX = _newEsApex;
emit EsApexChanged(_newEsApex);
}
function stakeAPEX(uint256 accountId, uint256 amount,uint256 lockPeriod) external override {
require(!paused, "paused");
require(apeX != address(0));
TransferHelper.safeTransferFrom(apeX, msg.sender, address(this), amount);
globalStakeId++;
stakingAPEX[globalStakeId] = stakingInfo({
lockToken: apeX,
owner: msg.sender,
accountId: accountId,
amount: amount,
lockPeriod: lockPeriod,
lockStart: block.timestamp,
unlocked: false
});
emit Staked(apeX, msg.sender, globalStakeId, accountId, amount,lockPeriod);
}
function stakeEsAPEX(uint256 accountId, uint256 amount,uint256 lockPeriod) external override {
require(!paused, "paused");
require(esApeX != address(0));
TransferHelper.safeTransferFrom(esApeX, msg.sender, address(this), amount);
globalStakeId++;
stakingEsAPEX[globalStakeId] = stakingInfo({
lockToken: esApeX,
owner: msg.sender,
accountId: accountId,
amount: amount,
lockPeriod: lockPeriod,
lockStart: block.timestamp,
unlocked: false
});
emit Staked(esApeX, msg.sender, globalStakeId, accountId, amount,lockPeriod);
}
function unstakeAPEX(uint256 stakeId) external override {
_unstakeAPEX(stakeId);
}
function _unstakeAPEX(uint256 stakeId) private {
stakingInfo memory info = stakingAPEX[stakeId];
require(info.owner == msg.sender, "not allowed");
require(info.lockStart+info.lockPeriod <= block.timestamp,"in lock period");
require(info.lockToken == apeX, "apeX token mismatch");
require(!info.unlocked,"already unlocked");
TransferHelper.safeTransfer(apeX, info.owner, info.amount);
stakingAPEX[stakeId].unlocked = true;
emit Unstaked(stakeId);
}
function batchUnstakeAPEX(uint256[] calldata stakeIds) external {
for (uint i = 0; i < stakeIds.length; i++) {
_unstakeAPEX(stakeIds[i]);
}
}
function _unstakeEsAPEX(uint256 stakeId) private{
stakingInfo memory info = stakingEsAPEX[stakeId];
require(info.owner == msg.sender, "not allowed");
require(info.lockStart+info.lockPeriod <= block.timestamp,"in lock period");
require(info.lockToken == esApeX, "esApeX token mismatch");
require(!info.unlocked,"already unlocked");
TransferHelper.safeTransfer(esApeX, info.owner, info.amount);
stakingEsAPEX[stakeId].unlocked = true;
emit Unstaked(stakeId);
}
function unstakeEsAPEX(uint256 stakeId) external override {
_unstakeEsAPEX(stakeId);
}
function batchUnstakeEsAPEX(uint256[] calldata stakeIds) external {
for (uint i = 0; i < stakeIds.length; i++) {
_unstakeEsAPEX(stakeIds[i]);
}
}
}
文件 2 的 4:IApeXPool3.sol
pragma solidity ^0.8.0;
interface IApeXPool3 {
event ApexChanged(address newApex);
event EsApexChanged(address newEsApex);
event PausedStateChanged(bool newState);
event Staked(address indexed token, address indexed user, uint256 stakeId, uint256 accountId, uint256 amount, uint256 lockPeriod);
event Unstaked(uint256 stakeId);
function apeX() external view returns (address);
function esApeX() external view returns (address);
function paused() external view returns (bool);
function setPaused(bool newState) external;
function setApex(address newApex) external;
function setEsApex(address newEsApex) external;
function stakeAPEX(uint256 accountId, uint256 amount,uint256 lockPeriod) external;
function stakeEsAPEX(uint256 accountId, uint256 amount,uint256 lockPeriod) external;
function unstakeAPEX(uint256 stakeId) external;
function unstakeEsAPEX(uint256 stakeId) external;
}
文件 3 的 4:Ownable.sol
pragma solidity ^0.8.0;
abstract contract Ownable {
address public owner;
address public pendingOwner;
event NewOwner(address indexed oldOwner, address indexed newOwner);
event NewPendingOwner(address indexed oldPendingOwner, address indexed newPendingOwner);
modifier onlyOwner() {
require(msg.sender == owner, "Ownable: REQUIRE_OWNER");
_;
}
function setPendingOwner(address newPendingOwner) external onlyOwner {
require(pendingOwner != newPendingOwner, "Ownable: ALREADY_SET");
emit NewPendingOwner(pendingOwner, newPendingOwner);
pendingOwner = newPendingOwner;
}
function acceptOwner() external {
require(msg.sender == pendingOwner, "Ownable: REQUIRE_PENDING_OWNER");
address oldOwner = owner;
address oldPendingOwner = pendingOwner;
owner = pendingOwner;
pendingOwner = address(0);
emit NewOwner(oldOwner, owner);
emit NewPendingOwner(oldPendingOwner, pendingOwner);
}
}
文件 4 的 4:TransferHelper.sol
pragma solidity ^0.8.0;
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::safeApprove: approve failed"
);
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::safeTransfer: transfer failed"
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::transferFrom: transferFrom failed"
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, "TransferHelper::safeTransferETH: ETH transfer failed");
}
}
{
"compilationTarget": {
"contracts/stakingV2/ApeXPool3.sol": "ApeXPool3"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_apeX","type":"address"},{"internalType":"address","name":"_esApeX","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newApex","type":"address"}],"name":"ApexChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newEsApex","type":"address"}],"name":"EsApexChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldPendingOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newPendingOwner","type":"address"}],"name":"NewPendingOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"newState","type":"bool"}],"name":"PausedStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakeId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockPeriod","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"stakeId","type":"uint256"}],"name":"Unstaked","type":"event"},{"inputs":[],"name":"acceptOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"apeX","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"stakeIds","type":"uint256[]"}],"name":"batchUnstakeAPEX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"stakeIds","type":"uint256[]"}],"name":"batchUnstakeEsAPEX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"esApeX","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalStakeId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newApex","type":"address"}],"name":"setApex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newEsApex","type":"address"}],"name":"setEsApex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"newState","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPendingOwner","type":"address"}],"name":"setPendingOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"accountId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"lockPeriod","type":"uint256"}],"name":"stakeAPEX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"accountId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"lockPeriod","type":"uint256"}],"name":"stakeEsAPEX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakingAPEX","outputs":[{"internalType":"address","name":"lockToken","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"accountId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"lockPeriod","type":"uint256"},{"internalType":"uint256","name":"lockStart","type":"uint256"},{"internalType":"bool","name":"unlocked","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakingEsAPEX","outputs":[{"internalType":"address","name":"lockToken","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"accountId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"lockPeriod","type":"uint256"},{"internalType":"uint256","name":"lockStart","type":"uint256"},{"internalType":"bool","name":"unlocked","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakeId","type":"uint256"}],"name":"unstakeAPEX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakeId","type":"uint256"}],"name":"unstakeEsAPEX","outputs":[],"stateMutability":"nonpayable","type":"function"}]