abstraction of CollaborationToken and BountyBank

This commit is contained in:
Ricardo Guilherme Schmidt
2017-03-24 03:34:31 +00:00
parent d895e9c17d
commit 1c408aefe9
10 changed files with 296 additions and 165 deletions
+13 -4
View File
@@ -3,8 +3,17 @@ pragma solidity ^0.4.9;
contract Bank {
event Withdrawn(address reciever, uint256 amount);
event Deposited(address sender,uint256 value);
//allow deposit and call event
function deposit() payable {
Deposited(msg.sender, msg.value);
}
//withdraw if locked and not paid, updates epoch
function withdrawal(address dest, uint amount)
internal {
if(!dest.send(amount)) throw;
Withdrawn(msg.sender, amount);
}
}
@@ -0,0 +1,98 @@
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 "./Bank.sol";
import "../management/EpochLocker.sol";
import "../token/LockerToken.sol";
contract CollaborationBank is Bank, EpochLocker {
LockableToken public token;
//used for calculating balance and for checking if account withdrawn
uint256 public currentPayEpoch;
//stores the balance from the lock time
uint256 public epochBalance;
//used for hecking if account withdrawn
mapping (address => uint) lastPaidOutEpoch;
//events
event Withdrawn(address tokenHolder, uint256 amountPaidOut);
event Deposited(address donator,uint256 value);
public CollaborationBank(LockableToken _token) EpochLockable(8 minutes,12 minutes){
token = _token;
}
//update the balance and payout epoch
modifier update_epoch {
if(currentPayEpoch < CURRENT_EPOCH) {
currentPayEpoch = _token.CURRENT_EPOCH();
epochBalance = this.balance;
}
_;
}
//checks if user already withdrawn
modifier not_paid {
if (lastPaidOutEpoch[msg.sender] == currentPayEpoch) throw;
_;
}
//check overflow in multiply
function safeMultiply(uint256 _a, uint256 _b) private {
if (!(_b == 0 || ((_a * _b) / _b) == _a)) throw;
_;
}
//allow deposit and call event
function ()
payable {
deposit();
}
function setLock(bool _lock){
token.setLock(_lock);
}
//withdraw if locked and not paid, updates epoch
function withdrawal()
external
check_lock(true)
update_epoch
not_paid {
uint256 _tokenBalance = token.balanceOf(msg.sender);
uint256 _tokenSupply = token.totalSupply();
safeMultiply(_tokenBalance, epochBalance);
lastPaidOutEpoch[msg.sender] = currentPayEpoch;
if (this.balance >= epochBalance || _tokenBalance == 0 || _tokenSupply == 0) throw;
super.withdrawal(msg.sender, (_tokenBalance * epochBalance) / _tokenSupply);
}
//if this coin owns tokens of other CollaborationBank, allow withdraw
function withdrawalFrom(CollaborationBank _otherCollaborationToken) {
_otherCollaborationToken.withdrawal();
}
//return expected payout in lock or estimated when not locked
function expectedPayout(address _tokenHolder)
external
constant
returns (uint256 payout) {
if (now < NEXT_LOCK) //unlocked, estimate
payout = (token.balanceOf(_tokenHolder) * this.balance) / token.totalSupply();
else
payout = (token.balanceOf(_tokenHolder) * epochBalance) / token.totalSupply();
}
}
@@ -0,0 +1,44 @@
pragma solidity ^0.4.8;
contract EpochLocker is Lockable {
uint256 public creationTime = now;
uint256 public unlockedTime = 25 days
uint256 public lockedTime = 5 days;
uint256 public constant EPOCH_LENGTH = unlockedTime + lockedTime;
//current epoch constant formula, recalculated in any contract call
uint256 public constant CURRENT_EPOCH = (now - creationTime) / EPOCH_LENGTH + 1;
//next lock constant formula, recalculated in any contract call
uint256 public constant NEXT_LOCK = (creationTime + CURRENT_EPOCH * unlockedTime) + (CURRENT_EPOCH - 1) * lockedTime;
function EpochLockable(uint256 _unlockedTime, uint256 _lockedTime){
unlockedTime = _unlockedTime;
lockedTime = _lockedTime;
}
//update lock value if needed or throw if unexpected lock
modifier check_lock(bool lockedOnly) {
if(lockedOnly){ //method allowed when locked
if (NEXT_LOCK < now) { //is locked!
if (!lock) setLock(true); //storage says other thing, update it.
}
else { //is not locked!
if (!lock) throw; //unlocked and storage already say so, throw to prevent event flood.
setLock(false); //update storage
return; //prevent method from running post states.
}
}else{ //method allowed when unlocked.
if (NEXT_LOCK < now) { //is locked!
if (lock) throw; //no need to update storage.
setLock(true);//update storage
return; //prevent method from running post states.
}
else { //is not locked!
if (lock) setLock(false); //storage says other thing, update it.
}
}
}
}
@@ -0,0 +1,14 @@
pragma solidity ^0.4.8;
import "./Owned.sol";
contract Lockable {
bool public lock = true;
event Locked(bool lock);
fuction setLock(bool _lock) internal {
Locked(_lock);
lock = _lock;
}
}
@@ -1,158 +0,0 @@
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 "./AbstractToken.sol";
contract CollaborationToken is AbstractToken {
//creation time, defined when contract is created
uint256 public creationTime = now;
//time constants, defines epoch size and periods
uint256 public constant UNLOCKED_TIME = 25 days;
uint256 public constant LOCKED_TIME = 5 days;
uint256 public constant EPOCH_LENGTH = UNLOCKED_TIME + LOCKED_TIME;
//current epoch constant formula, recalculated in any contract call
uint256 public constant CURRENT_EPOCH = (now - creationTime) / EPOCH_LENGTH + 1;
//next lock constant formula, recalculated in any contract call
uint256 public constant NEXT_LOCK = (creationTime + CURRENT_EPOCH * UNLOCKED_TIME) + (CURRENT_EPOCH - 1) * LOCKED_TIME;
//used for calculating balance and for checking if account withdrawn
uint256 public currentPayEpoch;
//stores the balance from the lock time
uint256 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, uint256 amountPaidOut);
event Deposited(address donator,uint256 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(uint256 _a, uint256 _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) {
uint256 _currentEpoch = CURRENT_EPOCH;
uint256 _tokenBalance = balanceOf(msg.sender);
uint256 _totalSupply = totalSupply;
if (this.balance == 0 || _tokenBalance == 0) throw;
lastPaidOutEpoch[msg.sender] = currentPayEpoch;
uint256 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(CollaborationToken _otherCollaborationToken) {
_otherCollaborationToken.withdrawal();
}
//return expected payout in lock or estimated when not locked
function expectedPayout(address _tokenHolder)
external
constant
returns (uint256 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);
}
}
@@ -0,0 +1,49 @@
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 "./AbstractToken.sol";
import "../management/Lockable.sol";
contract LockerToken is AbstractToken, Lockable, Owned {
Lockable public locker = this;
function unlinkLocker() only_owner {
locker = this;
}
function linkLocker(Lockable _locker) only_owner {
locker = _locker;
}
function lock(bool _lock) only_owner {
setLock(_lock);
}
modifier when_locked(bool value){
if (lock != value && locker.lock() != value) throw;
_;
}
//overwrite not allow transfer during lock
function transfer(address _to, uint256 _value) when_locked(true);
returns (bool ok) {
return super.transfer(_to,_value);
}
//overwrite not allow transfer during lock
function transferFrom(address _from, address _to, uint256 _value)
returns (bool ok) when_locked(true) {
return super.transferFrom(_from,_to,_value);
}
}
+63
View File
@@ -0,0 +1,63 @@
pragma solidity ^0.4.9;
import "lib/ethereans/management/Owned.sol"
contract BountyBank is Owned {
enum State {CLOSED, OPEN, CLAIMED};
struct Bounty {
State state;
uint closedAt;
mapping (address => int) deposits;
mapping (address => int) claimers;
uint balance;
uint points;
}
mapping (uint => Bounty) bounties;
uint count = 0;
function deposit(int num) payable {
if(bounties[num].state != OPEN || msg.value == 0) throw;
bounties[num].deposits[msg.sender] += msg.value;
bounties[num].balance += msg.value;
}
function withdraw(int num) {
uint value = bounties[num].deposits[msg.sender];
if(bounties[num].state != OPEN || value == 0) throw;
delete bounties[num].deposits[msg.sender];
if(!msg.sender.send(value)) throw;
}
function open(uint num) only_owner {
if(bounties[num].claimed == true) throw;
bounties[num].state = State.OPEN;
}
function setClaimer(uint num, address claimer, uint points) only_owner {
if(bounties[num].state == State.CLAIMED) throw;
bounties[num].claimers[claimer] += points;
bounties[num].points += points;
}
function close(uint num) only_owner {
if(bounties[num].state == State.CLAIMED) throw;
bounties[num].close = true;
bounties[num].closedAt = now;
}
function claim(uint num){
if (bounties[num].state == State.OPEN) throw;
uint totalPoints = bounties[num].points;
if(totalPoints == 0) throw;
uint points = bounties[num].claimers[msg.sender];
if (points == 0) throw;
delete bounties[num].claimers[msg.sender];
uint award = (bounties[num].balance / totalPoints)*points;
bounties[num].points -= points;
bounties[num].balance -= award;
if(!msg.sender.send(award)) throw;
}
}
@@ -15,6 +15,7 @@ pragma solidity ^0.4.8;
* Released under GPLv3 License
*/
import "lib/ethereans/bank/CollaborationBank.sol";
import "lib/ethereans/management/Owned.sol";
import "./GitRepositoryI.sol";
import "./GitRepositoryToken.sol";
@@ -25,6 +26,9 @@ contract GitRepository is GitRepositoryI, Owned {
//Address of the oracle, used for github login address lookup
GitRepositoryStorage public db;
GitRepositoryToken public token;
CollaborationBank public donationBank;
BountyBank
mapping (address=>uint) beers;
uint256 public subscribers;
uint256 public watchers;
@@ -37,9 +41,17 @@ contract GitRepository is GitRepositoryI, Owned {
_;
}
function () payable {
donationBank.deposit();
}
function GitRepository(uint256 _uid, string _name) {
db = new GitRepositoryStorage(_uid,_name);
token = new GitRepositoryToken(_name);
donationBank = new CollaborationBank(token);
token.linkLocker(donationBank);
}
//checks if a commit is already claimed
@@ -15,10 +15,10 @@ pragma solidity ^0.4.8;
* Released under GPLv3 License
*/
import "lib/ethereans/token/CollaborationToken.sol";
import "lib/ethereans/token/LockerToken.sol";
import "lib/ethereans/management/Owned.sol";
contract GitRepositoryToken is CollaborationToken, Owned {
contract GitRepositoryToken is LockerToken {
function GitRepositoryToken(string _repository) {
setAttribute("name", _repository);
@@ -27,7 +27,7 @@ contract GitRepositoryToken is CollaborationToken, Owned {
}
function mint(address _who, uint256 _value)
only_owner {
only_owner when_locked(false)) {
_mint(_who,_value);
}