pragma solidity >= 0.5.3 < 0.6.0;
// ERC20 Interface
// - interface for ERC20 token functions for compatibility
interface ERC20Interface {
function balanceOf(address _who) external view returns (uint256);
function transfer(address _to, uint256 _value) external returns (bool);
function allowance(address _owner, address _spender) external view returns (uint256);
function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
function approve(address _spender, uint256 _value) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
pragma solidity >= 0.5.3 < 0.6.0;
import "./SafeMath.sol";
import "./TimestampMonthConv.sol";
import "./ERC20Interface.sol";
//import "./ERC223ReceivingContract.sol";
// Ownership contract
// - token contract ownership for owner & lockup addresses
contract Ownership {
address private _owner;
event OwnerOwnershipTransferred(address indexed prevOwner, address indexed newOwner);
// Returns contract owner address
function owner() public view returns (address){
return _owner;
}
// Check if caller is owner account
function isOwner() public view returns (bool){
return (msg.sender == _owner);
}
// Modifier for function restricted to owner only
modifier onlyOwner() {
require(isOwner(), "Ownership: the caller is not the owner address");
_;
}
// Transfer owner's ownership to new address
// # param newOwner: address of new owner to be transferred
function transferOwnerOwnership(address newOwner) public onlyOwner {
_transferOwnerOwnership(newOwner);
}
// ==== internal functions ====
function _transferOwnerOwnership(address newOwner) internal {
require (newOwner != address(0), "Ownable: new owner is zero address");
emit OwnerOwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
function _setupOwnership(address own) internal {
require (own != address(0), "Ownable: owner is zero address");
_owner = own;
emit OwnerOwnershipTransferred(address(0), own);
}
}
contract LockupCampaign is Ownership {
using SafeMath for uint256;
using TimestampMonthConv for uint;
enum LockStatus {NULL, LOCKED, UNLOCKED, RELEASED}
struct WowbitInfo {
uint256 totalLocked;
uint256 totalExtraGiven;
uint256 currentLocked;
uint256 incentive3;
uint256 incentive6;
uint256 incentive9;
}
struct ParticipatingUsers {
uint256 amountWWB;
uint256 month;
uint256 lockEnd;
bool incCalculated;
LockStatus status;
}
struct UsersExtraTokens {
address[] exTokenAddress;
uint8[] exTokenDecimals;
uint256[] exTokenAmount;
}
WowbitInfo public wwbInfo;
address public wwbAddress;
address[] public tokenAddresses;
uint8[] public tokenDecimals;
bool public firstSet = false;
mapping (address => ParticipatingUsers) internal userList;
mapping (address => UsersExtraTokens) internal extraList;
event PreRegister(address indexed _userAddress);
event ConfirmRegister(address indexed _userAddress, uint256 startLock, uint256 endLock);
event TokenLocked(address indexed _userAddress, uint256 amount);
event TokenUnlocked(address indexed _userAddress, uint256 timestamp);
event TokenReleased(address indexed _userAddress, uint256 amount);
event RegisterEtcToken(address indexed _token);
event RemoveEtcToken(address indexed _token);
event EtcTokenRequested(address indexed _userAddress, address indexed _tokenAddress);
event EtcTokenReleased(address indexed _userAddress, address indexed _tokenAddress, uint256 _amountIncentives);
constructor(address owner, address WwbTokenAddress) public{
_setupOwnership(owner);
wwbAddress = WwbTokenAddress;
}
// --------------- ERC223 token fallback function ---------------
// ERC223 supported tokenFallback: use erc223 transfer from token contract
function tokenFallback(address _from, uint _value, bytes memory _data) public {
string memory str = string(_data);
if(_from == owner()){
require((keccak256(abi.encodePacked((str))) == keccak256(abi.encodePacked(("supply")))),
"LockupCampaign: bytes command not authorized");
// balance can be require from wwbTokenBalance() / otherTokenBalance()
} else if(_from != owner()){
require(userList[_from].lockEnd == 0, "LockupCampaign: user not registered");
_confirmRegister(_from, _value);
emit TokenLocked(_from, _value);
} else {
revert("LockupCampaign: not authorized");
}
}
// --------------- ERC20 token deposit function ---------------
// ERC20 deposit function: owner needs to approve token using `approve()` function in respective participating ERC20 token contract
// before using this function (only owner function).
// # params erc20TokenAddress: address of the token to deposit
// # params amountToken: amount of token to deposit in contract
function depositApprovedERC20(address erc20TokenAddress, uint256 amountToken) public onlyOwner {
ERC20Interface(erc20TokenAddress).transferFrom(msg.sender, address(this), amountToken);
}
// --------------- WWB tokens functions ---------------
// Set the percentage interest rates (where 7% = 700) for respective months for WWB token (only owner function).
// # params rate_3month: percentage rate in 3 months
// # params rate_6month: percentage rate in 6 months
// # params rate_9month: percentage rate in 9 months
function setWwbRate(uint256 rate_3month, uint256 rate_6month, uint256 rate_9month) public onlyOwner {
_setWwbRate(rate_3month, rate_6month, rate_9month);
}
// Retrieve the balance of WWB tokens in this contract.
// * returns (uint256): the amount of token in the contract
function wwbTokenBalance() public view returns (uint256){
return ERC20Interface(wwbAddress).balanceOf(address(this));
}
// Returns all WWB tokens back to the owner (only owner function).
function returnAllWWBTokens() public onlyOwner {
ERC20Interface(wwbAddress).transfer(owner(), ERC20Interface(wwbAddress).balanceOf(address(this)));
}
// Returns WWB information (only owner function).
function getWwbInfo() public view onlyOwner returns (uint256, uint256, uint256, uint256, uint256, uint256){
return (wwbInfo.totalLocked, wwbInfo.totalExtraGiven, wwbInfo.currentLocked, wwbInfo.incentive3, wwbInfo.incentive6, wwbInfo.incentive9);
}
// --------------- participating tokens functions ---------------
// Retrieve if token address is a participating token in lockup campaign.
// # params tokenAddress: address of the participating token
// * returns (bool): indication of token participation
function isParticipatingTokens(address tokenAddress) public view returns(bool){
for(uint i = 0; i < tokenAddresses.length; i++){
if(tokenAddresses[i] == tokenAddress) {
return true;
}
}
}
// Retrieve the balance of participating tokens in this contract.
// # params tokenAddress: address of the participating token
// * returns (uint256): the amount of participating token in the contract
function participatingTokenBalance(address tokenAddress) public view returns (uint256){
return ERC20Interface(tokenAddress).balanceOf(address(this));
}
// Adds the participating tokens to be involved in lockup campaign
// # params tokenAddress: address of the participating token
// # params decimals: decimal of the participating token
function addParticipatingToken(address tokenAddress, uint8 decimals) public onlyOwner {
require(!isParticipatingTokens(tokenAddress), "LockupCampaign: token data exists");
require(tokenAddress != address(0), "LockupCampaign: token contract address is zero");
require(decimals != 0, "LockupCampaign: token contract decimals is zero");
require(decimals <= 18, "LockupCampaign: token contract decimals invalid");
tokenAddresses.push(tokenAddress);
tokenDecimals.push(decimals);
emit RegisterEtcToken(tokenAddress);
}
// Edit the registered participating tokens rates
// # params tokenAddress: address of the participating token
// # params incentive_6month: amount of token to be given for 6 month lock period
// # params incentive_9month: amount of token to be given for 9 month lock period
function removeParticipatingToken(address tokenAddress) public onlyOwner {
for (uint i = 0; i < tokenAddresses.length; i++){
if(tokenAddresses[i] == tokenAddress){
tokenAddresses[i] = tokenAddresses[i+1];
tokenDecimals[i] = tokenDecimals[i+1];
}
}
tokenAddresses.length--;
tokenDecimals.length--;
emit RemoveEtcToken(tokenAddress);
}
// Returns all participating tokens to owner
// # params tokenAddress: address of the participating token
function returnAllOtherTokens(address tokenAddress) public onlyOwner {
ERC20Interface(tokenAddress).transfer(owner(), ERC20Interface(tokenAddress).balanceOf(address(this)));
}
// --------------- register participants functions ---------------
// Checks whether the use have registered (pre-registered, not sent token to contract yet for lockup)
// # params userAddress: address of pre-registered user
// * returns (bool): indication whether user have pre-registered (true) or not registered (false)
function isPreParticipant(address userAddress) public view returns (bool) {
return (userList[userAddress].month != 0);
}
// Checks whether the use have registered (already sent token to contract for lockup)
// # params userAddress: address of registered user
// * returns (bool): indication whether user have pre-registered (true) or not registered (false)
function isRegisteredParticipant(address userAddress) public view returns (bool){
return (userList[userAddress].lockEnd != 0);
}
// Returns user's current lock amount
// # params userAddress: address of registered user
// * returns (uint256): amount of user's token locked in contract
function getParticipantLockAmount(address userAddress) public view returns (uint256){
return userList[userAddress].amountWWB;
}
// Returns the registered user's lock info
// # params userAddress: address of registered user
// * returns (uint256): amount of user's token locked in contract
// * returns (uint256): month of token lockup
// * returns (uint256): end date of token's lockup period (unix timestamp)
// * returns (bool): indication of user's locked token have been calculated or not
// * returns (uint256): indication whether token has been unlocked or not
function getParticipantInfo(address userAddress) public view returns (uint256, uint256, uint256, bool, bool){
return(userList[userAddress].amountWWB, userList[userAddress].month,
userList[userAddress].lockEnd, userList[userAddress].incCalculated,
_getLockStatus(userList[userAddress].status)
);
}
// Returns if user have applied for additional tokens
// # params userAddress: address of registered user
// * returns (bool): indication whether user have applied for additional token
function isParticipantExtraTokens(address user) public view returns (bool){
return (extraList[user].exTokenAddress.length != 0);
}
// Returns the data of additional token requested
// # params userAddress: address of registered user
// * returns (address[]): array of participating token contract address
// * returns (uint256[]): array of amount of respective participating tokens should be given out
function getParticipantExtraTokens(address user) public view returns (address[] memory, uint256[] memory){
return (extraList[user].exTokenAddress, extraList[user].exTokenAmount);
}
// Updates the user's info on current time
// # params userAddress: address of registered user
function updateParticipantInfo(address userAddress) public {
_incentiveTimeCheck(userAddress);
}
// Pre-register participants for lockup campaign, will be properly registered after user transfer tokens to contract
// # params userAddr: address of registered user
// # params wwbAmount: amount of token to lock (in wei)
// # params months: address of registered user
function preRegisterParticipant(address userAddr, uint256 months) public returns (bool) {
require(firstSet == true, "LockupCampaign: rates data for WWB token not yet set for first time");
require(userAddr != address(0), "LockupCampaign: user address is zero");
require(months > 0, "LockupCampaign: months to lock is zero");
_registParticipant(userAddr, months);
return true;
}
// Requests additional tokens for users locked more than 6 months
// # params user: address of registered user
// # params token: address of participating token to request
function requestExtraToken(address user, address token) public {
require(isRegisteredParticipant(user), "LockupCampaign: User not registered.");
require(tokenAddresses.length > 0, "LockupCampaign: no participating token data is entered yet");
require(userList[user].month >= 6, "LockupCampaign: user must lock more than 6 months to request extra token");
_requestExtraTokens(user, token);
}
// Releases the token and respective additional tokens to user after lock period passed
// # params user: address of registered user
function releaseParticipantTokens(address userAddr) public returns (bool){
require(isRegisteredParticipant(userAddr), "LockupCampaign: User not registered.");
require(_incentiveTimeCheck(userAddr));
require(userList[userAddr].status != LockStatus.LOCKED, "LockupCampaign: Token lock period still ongoing.");
require(userList[userAddr].status != LockStatus.RELEASED, "LockupCampaign: Token already released.");
_releaseWwbTokens(userAddr);
if(extraList[userAddr].exTokenAddress.length != 0){
_releaseOtherTokens(userAddr);
}
return true;
}
// --------------- extra functions ---------------
// Returns string converted bytes value
// # params str: a string value to convert
// * returns (bytes): converted string in bytes value
function convertStrToBytes(string memory str) public pure returns (bytes memory){
return bytes(str);
}
// --------------- internal functions ---------------
function _setWwbRate(uint256 i3, uint256 i6, uint256 i9) internal {
wwbInfo.incentive3 = i3;
wwbInfo.incentive6 = i6;
wwbInfo.incentive9 = i9;
firstSet = true;
}
function _registParticipant(address addr, uint256 month) internal {
ParticipatingUsers memory user = ParticipatingUsers(0, month, 0, false, LockStatus.NULL);
userList[addr] = user;
emit PreRegister(addr);
}
function _confirmRegister(address addr, uint256 val) internal {
uint256 finalDate = now.addMonths(userList[addr].month);
userList[addr].amountWWB = val;
userList[addr].lockEnd = finalDate;
userList[addr].status = LockStatus.LOCKED;
wwbInfo.totalLocked = wwbInfo.totalLocked.add(val);
wwbInfo.currentLocked = wwbInfo.currentLocked.add(val);
emit ConfirmRegister(addr, now, finalDate);
}
function _getLockStatus(LockStatus stat) internal pure returns (bool) {
if (stat == LockStatus.LOCKED || stat == LockStatus.NULL){
return false;
} else {
return true;
}
}
// Updates the status and send user incentives given to lockup
function _incentiveTimeCheck(address user) internal returns (bool) {
if (now >= userList[user].lockEnd){
if (userList[user].status == LockStatus.LOCKED && userList[user].incCalculated != true) {
uint256 val = _calcIncentives(user);
if (extraList[user].exTokenAddress.length != 0) { _calcExtra(user, val); }
userList[user].status = LockStatus.UNLOCKED;
userList[user].incCalculated = true;
emit TokenUnlocked(user, now);
}
}
return true;
}
// Incentives calculation
function _calcIncentives(address user) internal returns (uint256){
uint256 m = userList[user].month;
uint256 added;
if (m >= 3 && m < 6){
added = _calcAdd(userList[user].amountWWB, wwbInfo.incentive3);
} else if (m >= 6 && m < 12){
added = _calcAdd(userList[user].amountWWB, wwbInfo.incentive6);
} else if (m >= 12) {
added = _calcAdd(userList[user].amountWWB, wwbInfo.incentive9);
}
userList[user].amountWWB = userList[user].amountWWB.add(added);
wwbInfo.totalExtraGiven = wwbInfo.totalExtraGiven.add(added);
wwbInfo.currentLocked = wwbInfo.currentLocked.add(added);
return added;
}
function _calcExtra(address user, uint256 added) internal {
for (uint i = 0; i < extraList[user].exTokenAddress.length; i++){
uint8 dec = extraList[user].exTokenDecimals[i];
uint256 total;
if (dec > 6) { total = added.mul((10 ** uint256(dec - 6))); }
else if (dec < 6) { total = added.div((10 ** uint256(6 - dec))); }
extraList[user].exTokenAmount.push(total);
}
}
// rate calc
function _calcAdd(uint256 total, uint256 rate) internal pure returns (uint256){
uint256 r = total.mul(rate);
r = r.div(10000);
return r;
}
function _requestExtraTokens(address user, address token) internal {
require(isParticipatingTokens(token), "LockupCampaign: token address is not participating token");
//extraList[user].exTokenAddress.push(token);
for (uint i = 0; i < tokenAddresses.length; i++){
if(token == tokenAddresses[i]){
extraList[user].exTokenAddress.push(token);
extraList[user].exTokenDecimals.push(tokenDecimals[i]);
break;
}
}
emit EtcTokenRequested(user, token);
}
function _releaseWwbTokens(address user) internal {
uint256 amt = userList[user].amountWWB;
ERC20Interface(wwbAddress).transfer(user, amt);
wwbInfo.currentLocked = wwbInfo.currentLocked.sub(amt);
userList[user].status = LockStatus.RELEASED;
emit TokenReleased(user, amt);
}
function _releaseOtherTokens(address user) internal {
for (uint i = 0; i < extraList[user].exTokenAddress.length; i++){
address addr = extraList[user].exTokenAddress[i];
uint amt = extraList[user].exTokenAmount[i];
ERC20Interface(addr).transfer(user, amt);
emit EtcTokenReleased(user, addr, amt);
}
}
}
pragma solidity >= 0.5.3 < 0.6.0;
// SafeMath library
// - uint security overflow/underflow prevention
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) { return 0; }
uint256 c = a * b;
require(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0);
uint256 c = a / b;
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a);
uint256 c = a - b;
return c;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0);
return a % b;
}
}
pragma solidity >=0.5.3 < 0.6.0;
// Timestamp Month Conversion library
// - date and timestamp related conversion/operations for months
library TimestampMonthConv {
uint constant SECONDS_PER_DAY = 24 * 60 * 60;
uint constant SECONDS_PER_HOUR = 60 * 60;
uint constant SECONDS_PER_MINUTE = 60;
int constant OFFSET19700101 = 2440588;
function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) {
require(year >= 1970);
int _year = int(year);
int _month = int(month);
int _day = int(day);
int __days = _day
- 32075
+ 1461 * (_year + 4800 + (_month - 14) / 12) / 4
+ 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12
- 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4
- OFFSET19700101;
_days = uint(__days);
}
function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) {
int __days = int(_days);
int L = __days + 68569 + OFFSET19700101;
int N = 4 * L / 146097;
L = L - (146097 * N + 3) / 4;
int _year = 4000 * (L + 1) / 1461001;
L = L - 1461 * _year / 4 + 31;
int _month = 80 * L / 2447;
int _day = L - 2447 * _month / 80;
L = _month / 11;
_month = _month + 2 - 12 * L;
_year = 100 * (N - 49) + _year + L;
year = uint(_year);
month = uint(_month);
day = uint(_day);
}
function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) {
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
daysInMonth = 31;
} else if (month != 2) {
daysInMonth = 30;
} else {
daysInMonth = _isLeapYear(year) ? 29 : 28;
}
}
function _isLeapYear(uint year) internal pure returns (bool leapYear) {
leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) {
uint year;
uint month;
uint day;
(year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
month += _months;
year += (month - 1) / 12;
month = (month - 1) % 12 + 1;
uint daysInMonth = _getDaysInMonth(year, month);
if (day > daysInMonth) {
day = daysInMonth;
}
newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;
require(newTimestamp >= timestamp);
}
function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) {
require(fromTimestamp <= toTimestamp);
uint fromYear;
uint fromMonth;
uint fromDay;
uint toYear;
uint toMonth;
uint toDay;
(fromYear, fromMonth, fromDay) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);
(toYear, toMonth, toDay) = _daysToDate(toTimestamp / SECONDS_PER_DAY);
_months = toYear * 12 + toMonth - fromYear * 12 - fromMonth;
}
}
{
"compilationTarget": {
"LockupCampaign.sol": "LockupCampaign"
},
"evmVersion": "istanbul",
"libraries": {},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"WwbTokenAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_userAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"startLock","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endLock","type":"uint256"}],"name":"ConfirmRegister","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_userAddress","type":"address"},{"indexed":true,"internalType":"address","name":"_tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amountIncentives","type":"uint256"}],"name":"EtcTokenReleased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_userAddress","type":"address"},{"indexed":true,"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"EtcTokenRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"prevOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerOwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_userAddress","type":"address"}],"name":"PreRegister","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"}],"name":"RegisterEtcToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"}],"name":"RemoveEtcToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_userAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_userAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenReleased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_userAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"TokenUnlocked","type":"event"},{"constant":false,"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"addParticipatingToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"convertStrToBytes","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"erc20TokenAddress","type":"address"},{"internalType":"uint256","name":"amountToken","type":"uint256"}],"name":"depositApprovedERC20","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"firstSet","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getParticipantExtraTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"getParticipantInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"getParticipantLockAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getWwbInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"isParticipantExtraTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"isParticipatingTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"isPreParticipant","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"isRegisteredParticipant","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"participatingTokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"userAddr","type":"address"},{"internalType":"uint256","name":"months","type":"uint256"}],"name":"preRegisterParticipant","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"userAddr","type":"address"}],"name":"releaseParticipantTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"removeParticipatingToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"requestExtraToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"returnAllOtherTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"returnAllWWBTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"rate_3month","type":"uint256"},{"internalType":"uint256","name":"rate_6month","type":"uint256"},{"internalType":"uint256","name":"rate_9month","type":"uint256"}],"name":"setWwbRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"tokenFallback","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnerOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"updateParticipantInfo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"wwbAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"wwbInfo","outputs":[{"internalType":"uint256","name":"totalLocked","type":"uint256"},{"internalType":"uint256","name":"totalExtraGiven","type":"uint256"},{"internalType":"uint256","name":"currentLocked","type":"uint256"},{"internalType":"uint256","name":"incentive3","type":"uint256"},{"internalType":"uint256","name":"incentive6","type":"uint256"},{"internalType":"uint256","name":"incentive9","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"wwbTokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]