文件 1 的 5:BaseShareField.sol
pragma solidity >=0.6.6;
import "../libraries/SafeMath.sol";
import "../libraries/TransferHelper.sol";
interface IERC20 {
function approve(address spender, uint256 value) external returns (bool);
function balanceOf(address owner) external view returns (uint256);
}
contract BaseShareField {
using SafeMath for uint256;
uint256 public totalProductivity;
uint256 public accAmountPerShare;
uint256 public totalShare;
uint256 public mintedShare;
uint256 public mintCumulation;
uint256 private unlocked = 1;
address public shareToken;
modifier lock() {
require(unlocked == 1, "Locked");
unlocked = 0;
_;
unlocked = 1;
}
struct UserInfo {
uint256 amount;
uint256 rewardDebt;
uint256 rewardEarn;
bool initialize;
}
mapping(address => UserInfo) public users;
function _setShareToken(address _shareToken) internal {
shareToken = _shareToken;
}
function _update() internal virtual {
if (totalProductivity == 0) {
totalShare = totalShare.add(_currentReward());
return;
}
uint256 reward = _currentReward();
accAmountPerShare = accAmountPerShare.add(reward.mul(1e12).div(totalProductivity));
totalShare += reward;
}
function _currentReward() internal view virtual returns (uint256) {
return mintedShare.add(IERC20(shareToken).balanceOf(address(this))).sub(totalShare);
}
function _audit(address user) internal virtual {
UserInfo storage userInfo = users[user];
if (userInfo.amount > 0) {
uint256 pending = userInfo.amount.mul(accAmountPerShare).div(1e12).sub(userInfo.rewardDebt);
userInfo.rewardEarn = userInfo.rewardEarn.add(pending);
mintCumulation = mintCumulation.add(pending);
userInfo.rewardDebt = userInfo.amount.mul(accAmountPerShare).div(1e12);
}
}
function _increaseProductivity(address user, uint256 value) internal virtual returns (bool) {
require(value > 0, "PRODUCTIVITY_VALUE_MUST_BE_GREATER_THAN_ZERO");
UserInfo storage userInfo = users[user];
_update();
_audit(user);
totalProductivity = totalProductivity.add(value);
userInfo.amount = userInfo.amount.add(value);
userInfo.rewardDebt = userInfo.amount.mul(accAmountPerShare).div(1e12);
return true;
}
function _decreaseProductivity(address user, uint256 value) internal virtual returns (bool) {
UserInfo storage userInfo = users[user];
require(value > 0 && userInfo.amount >= value, "INSUFFICIENT_PRODUCTIVITY");
_update();
_audit(user);
userInfo.amount = userInfo.amount.sub(value);
userInfo.rewardDebt = userInfo.amount.mul(accAmountPerShare).div(1e12);
totalProductivity = totalProductivity.sub(value);
return true;
}
function _transferTo(
address user,
address to,
uint256 value
) internal virtual returns (bool) {
UserInfo storage userInfo = users[user];
require(value > 0 && userInfo.amount >= value, "INSUFFICIENT_PRODUCTIVITY");
_update();
_audit(user);
uint256 transferAmount = value.mul(userInfo.rewardEarn).div(userInfo.amount);
userInfo.rewardEarn = userInfo.rewardEarn.sub(transferAmount);
users[to].rewardEarn = users[to].rewardEarn.add(transferAmount);
userInfo.amount = userInfo.amount.sub(value);
userInfo.rewardDebt = userInfo.amount.mul(accAmountPerShare).div(1e12);
totalProductivity = totalProductivity.sub(value);
return true;
}
function _takeWithAddress(address user) internal view returns (uint256) {
UserInfo storage userInfo = users[user];
uint256 _accAmountPerShare = accAmountPerShare;
if (totalProductivity != 0) {
uint256 reward = _currentReward();
_accAmountPerShare = _accAmountPerShare.add(reward.mul(1e12).div(totalProductivity));
}
return userInfo.amount.mul(_accAmountPerShare).div(1e12).add(userInfo.rewardEarn).sub(userInfo.rewardDebt);
}
function _mint(address user) internal virtual lock returns (uint256) {
_update();
_audit(user);
require(users[user].rewardEarn > 0, "NOTHING TO MINT SHARE");
uint256 amount = users[user].rewardEarn;
TransferHelper.safeTransfer(shareToken, user, amount);
users[user].rewardEarn = 0;
mintedShare += amount;
return amount;
}
function _mintTo(address user, address to) internal virtual lock returns (uint256) {
_update();
_audit(user);
uint256 amount = users[user].rewardEarn;
if (amount > 0) {
TransferHelper.safeTransfer(shareToken, to, amount);
}
users[user].rewardEarn = 0;
mintedShare += amount;
return amount;
}
function getProductivity(address user) public view virtual returns (uint256, uint256) {
return (users[user].amount, totalProductivity);
}
function interestsPerBlock() public view virtual returns (uint256) {
return accAmountPerShare;
}
}
文件 2 的 5:Initializable.sol
pragma solidity >=0.4.24 <0.8.0;
abstract contract Initializable {
bool private _initialized;
bool private _initializing;
modifier initializer() {
require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
function _isConstructor() private view returns (bool) {
address self = address(this);
uint256 cs;
assembly { cs := extcodesize(self) }
return cs == 0;
}
}
文件 3 的 5:ONXStrategy.sol
pragma solidity >=0.5.16;
import "./libraries/TransferHelper.sol";
import "./libraries/SafeMath.sol";
import "./modules/BaseShareField.sol";
import "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
interface IONXStrategy {
function invest(address user, uint256 amount) external;
function withdraw(address user, uint256 amount) external;
function liquidation(address user) external;
function claim(address user, uint256 amount, uint256 total) external;
function query() external view returns (uint256);
function mint() external;
function interestToken() external view returns (address);
function farmToken() external view returns (address);
}
interface IONXFarm {
function deposit(uint256 _pid, uint256 _amount) external;
function withdraw(uint256 _pid, uint256 _amount) external;
function pendingOnX(uint256 _pid, address _user) external view returns (uint256);
function poolInfo(uint _index) external view returns(address, uint256, uint256, uint256);
}
contract ONXStrategy is IONXStrategy, BaseShareField, Initializable {
event Mint(address indexed user, uint256 amount);
using SafeMath for uint256;
address public override interestToken;
address public override farmToken;
address public poolAddress;
address public onxFarm;
uint256 public lpPoolpid;
address public owner;
function initialize(
address _interestToken,
address _farmToken,
address _poolAddress,
address _onxFarm,
uint256 _lpPoolpid
) public initializer {
owner = msg.sender;
interestToken = _interestToken;
farmToken = _farmToken;
poolAddress = _poolAddress;
onxFarm = _onxFarm;
lpPoolpid = _lpPoolpid;
_setShareToken(_interestToken);
}
function invest(address user, uint256 amount) external override {
require(msg.sender == poolAddress, "INVALID CALLER");
TransferHelper.safeTransferFrom(farmToken, msg.sender, address(this), amount);
IERC20(farmToken).approve(onxFarm, amount);
IONXFarm(onxFarm).deposit(lpPoolpid, amount);
_increaseProductivity(user, amount);
}
function withdraw(address user, uint256 amount) external override {
require(msg.sender == poolAddress, "INVALID CALLER");
IONXFarm(onxFarm).withdraw(lpPoolpid, amount);
TransferHelper.safeTransfer(farmToken, msg.sender, amount);
_decreaseProductivity(user, amount);
}
function liquidation(address user) external override {
require(msg.sender == poolAddress, "INVALID CALLER");
uint256 amount = users[user].amount;
_decreaseProductivity(user, amount);
uint256 reward = users[user].rewardEarn;
users[msg.sender].rewardEarn = users[msg.sender].rewardEarn.add(reward);
users[user].rewardEarn = 0;
_increaseProductivity(msg.sender, amount);
}
function claim(
address user,
uint256 amount,
uint256 total
) external override {
require(msg.sender == poolAddress, "INVALID CALLER");
IONXFarm(onxFarm).withdraw(lpPoolpid, amount);
TransferHelper.safeTransfer(farmToken, msg.sender, amount);
_decreaseProductivity(msg.sender, amount);
uint256 claimAmount = users[msg.sender].rewardEarn.mul(amount).div(total);
users[user].rewardEarn = users[user].rewardEarn.add(claimAmount);
users[msg.sender].rewardEarn = users[msg.sender].rewardEarn.sub(claimAmount);
}
function _currentReward() internal view override returns (uint256) {
return
mintedShare
.add(IERC20(shareToken).balanceOf(address(this)))
.add(IONXFarm(onxFarm).pendingOnX(lpPoolpid, address(this)))
.sub(totalShare);
}
function query() external view override returns (uint256) {
return _takeWithAddress(msg.sender);
}
function mint() external override {
IONXFarm(onxFarm).deposit(lpPoolpid, 0);
uint256 amount = _mint(msg.sender);
emit Mint(msg.sender, amount);
}
}
文件 4 的 5:SafeMath.sol
pragma solidity >=0.6.0;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
文件 5 的 5:TransferHelper.sol
pragma solidity >=0.6.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: 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: 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: TRANSFER_FROM_FAILED");
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, "TransferHelper: ETH_TRANSFER_FAILED");
}
}
{
"compilationTarget": {
"contracts/ONXStrategy.sol": "ONXStrategy"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"inputs":[],"name":"accAmountPerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"farmToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getProductivity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_interestToken","type":"address"},{"internalType":"address","name":"_farmToken","type":"address"},{"internalType":"address","name":"_poolAddress","type":"address"},{"internalType":"address","name":"_onxFarm","type":"address"},{"internalType":"uint256","name":"_lpPoolpid","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestsPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"invest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"liquidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lpPoolpid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintCumulation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintedShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"onxFarm","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"query","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"shareToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalProductivity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"users","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"rewardDebt","type":"uint256"},{"internalType":"uint256","name":"rewardEarn","type":"uint256"},{"internalType":"bool","name":"initialize","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]