Contract Source Code:
<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: GPL-2.0-or-later
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]);
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: GPL-2.0-or-later
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;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: GPL-2.0-or-later
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);
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(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 {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(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 {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(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");
}
}