mirror of
https://github.com/status-im/github-oracle.git
synced 2026-08-27 09:51:10 +00:00
159 lines
4.7 KiB
Solidity
159 lines
4.7 KiB
Solidity
pragma solidity ^0.4.0;
|
|
|
|
/**
|
|
* Abstract contract used for recieving donations or profits
|
|
* Withdraw is divided by total tokens each account owns
|
|
* Unlock period allows transfers
|
|
* Lock period allow withdraws
|
|
* Child contract that implement minting should use modifier not_locked in minting function
|
|
* Inspired by ProfitContainer and Lockable by vDice
|
|
*
|
|
* By Ricardo Guilherme Schmidt
|
|
* Released under GPLv3 License
|
|
*/
|
|
|
|
import "AbstractCoin.sol";
|
|
|
|
contract LockableCoin is AbstractCoin {
|
|
//creation time, defined when contract is created
|
|
uint public creationTime = now;
|
|
//time constants, defines epoch size and periods
|
|
uint public constant UNLOCKED_TIME = 25 days;
|
|
uint public constant LOCKED_TIME = 5 days;
|
|
uint public constant EPOCH_LENGTH = UNLOCKED_TIME + LOCKED_TIME;
|
|
//current epoch constant formula, recalculated in any contract call
|
|
uint public constant CURRENT_EPOCH = (now - creationTime) / EPOCH_LENGTH + 1;
|
|
//next lock constant formula, recalculated in any contract call
|
|
uint public constant NEXT_LOCK = (creationTime + CURRENT_EPOCH * UNLOCKED_TIME) + (CURRENT_EPOCH - 1) * LOCKED_TIME;
|
|
//used for calculating balance and for checking if account withdrawn
|
|
uint public currentPayEpoch;
|
|
//stores the balance from the lock time
|
|
uint public epochBalance;
|
|
//stores lock state, used for events
|
|
bool public lock;
|
|
//used for hecking if account withdrawn
|
|
mapping (address => uint) lastPaidOutEpoch;
|
|
//events
|
|
event Withdrawn(address tokenHolder, uint amountPaidOut);
|
|
event Deposited(address donator,uint value);
|
|
event Locked();
|
|
event Unlocked();
|
|
|
|
//checks if not locked and call event on change
|
|
modifier not_locked {
|
|
if (NEXT_LOCK < now) {
|
|
if (lock) throw;
|
|
lock = true;
|
|
Locked();
|
|
return;
|
|
}
|
|
else {
|
|
if (lock) {
|
|
lock = false;
|
|
Unlocked();
|
|
}
|
|
}
|
|
_;
|
|
}
|
|
|
|
//checks if is locked and call event on change
|
|
modifier locked {
|
|
if (NEXT_LOCK < now) {
|
|
if (!lock){
|
|
lock = true;
|
|
Locked();
|
|
}
|
|
}
|
|
else {
|
|
if (!lock) throw;
|
|
lock = false;
|
|
Unlocked();
|
|
return;
|
|
}
|
|
_;
|
|
}
|
|
|
|
//update the balance and payout epoch
|
|
modifier update_epoch {
|
|
if(currentPayEpoch < CURRENT_EPOCH) {
|
|
currentPayEpoch = CURRENT_EPOCH;
|
|
epochBalance = this.balance;
|
|
}
|
|
_;
|
|
}
|
|
|
|
//checks if user already withdrawn
|
|
modifier not_paid {
|
|
if (lastPaidOutEpoch[msg.sender] == currentPayEpoch) throw;
|
|
_;
|
|
}
|
|
|
|
//check overflow in multiply
|
|
modifier safe_multiply(uint _a, uint _b) {
|
|
if (!(_b == 0 || ((_a * _b) / _b) == _a)) throw;
|
|
_;
|
|
}
|
|
|
|
//allow deposit and call event
|
|
function ()
|
|
payable {
|
|
Deposited(msg.sender, msg.value);
|
|
}
|
|
|
|
//withdraw if locked and not paid, updates epoch
|
|
function withdrawal()
|
|
external
|
|
locked
|
|
update_epoch
|
|
not_paid
|
|
safe_multiply(balanceOf(msg.sender), epochBalance) {
|
|
uint _currentEpoch = CURRENT_EPOCH;
|
|
uint _tokenBalance = balanceOf(msg.sender);
|
|
uint _totalSupply = totalSupply;
|
|
if (this.balance == 0 || _tokenBalance == 0) throw;
|
|
lastPaidOutEpoch[msg.sender] = currentPayEpoch;
|
|
uint amountToPayOut = (_tokenBalance * epochBalance) / _totalSupply;
|
|
if(!msg.sender.send(amountToPayOut)) {
|
|
throw;
|
|
}
|
|
Withdrawn(msg.sender, amountToPayOut);
|
|
}
|
|
|
|
//if this coin owns tokens of other lockablecoin, allow withdraw
|
|
function withdrawalFrom(LockableCoin _otherLockableCoin) {
|
|
_otherLockableCoin.withdrawal();
|
|
}
|
|
|
|
//return expected payout in lock or estimated when not locked
|
|
function expectedPayout(address _tokenHolder)
|
|
external
|
|
constant
|
|
returns (uint payout) {
|
|
if (now < NEXT_LOCK) //unlocked, estimate
|
|
payout = (balanceOf(_tokenHolder) * this.balance) / totalSupply;
|
|
else
|
|
payout = (balanceOf(_tokenHolder) * epochBalance) / totalSupply;
|
|
}
|
|
|
|
//overwrite not allow transfer during lock
|
|
function transfer(address _to, uint256 _value)
|
|
not_locked
|
|
returns (bool ok) {
|
|
return super.transfer(_to,_value);
|
|
}
|
|
|
|
//overwrite not allow transfer during lock
|
|
function transferFrom(address _from, address _to, uint256 _value)
|
|
not_locked
|
|
returns (bool ok) {
|
|
return super.transferFrom(_from,_to,_value);
|
|
}
|
|
|
|
//overwrite not allow transfer during lock
|
|
function approve(address _spender, uint256 _value)
|
|
returns (bool ok) {
|
|
return super.approve(_spender,_value);
|
|
}
|
|
|
|
}
|