Files
gitpivot/contracts/bank/IssueBankModel.sol

284 lines
8.1 KiB
Solidity

pragma solidity ^0.4.11;
import "../token/TokenLedger.sol";
import "../common/Controlled.sol";
/**
* @title IssueBank
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
* @dev Model (library) contract to set agreement between a repository owner and GitPivot
* about the bounty winners.
**/
contract IssueBankModel is Controlled, TokenLedger {
address public owner; //repository owner
mapping (address => Reward) public rewards; //bounty winners candidates
uint public points; //remaining points to be claimed
State public state; //current issue state
enum State { OPEN, REFUND, REWARD, FINALIZED }
struct Reward {
bool active; // repository owner can activate
uint points;
}
modifier onlyOwner{
require (msg.sender == owner);
_;
}
/**
* @dev Model Constructor: Generates a locked state for model being unusable
**/
function IssueBankModel() public {
owner = 0x0;
}
/**
* @dev Instance Constructor: Actual agreement logic initialization.
* @param _owner Repository owner which will accept bounty winners and finalize issue.
**/
function IssueBank(address _owner) public {
require(controller == 0x0);
controller = msg.sender;
owner = _owner;
state = State.OPEN;
}
/**
* @notice deposit ether in bank
**/
function () payable {
deposits[msg.sender][0x0] += msg.value;
}
/**
* @notice claim all watched tokens based on user points;
*/
function reward() {
_reward(tokens);
}
/**
* @notice Useful if some token is throwing on transfer.
* @param _tokens the array of desired watched tokens. If token is not watched it will ignore..
*/
function rewardEthAnd(address[] _tokens) {
_reward(_tokens);
}
/**
* @notice Repository owner can replace his address
* @param _newOwner
**/
function updateOwner(address _newOwner) onlyOwner {
require(_newOwner != 0x0);
owner = _newOwner;
}
/**
* @notice only contoller may set reward to a single address.
* @param _claimer the beneficiary
* @param _points amount of points
**/
function setReward(address _claimer, uint _points) onlyController {
require(state == State.OPEN);
assert(!rewards[_claimer].active);
rewards[_claimer].points = _points;
}
/**
* @notice only contoller may set reward to an array of addresses.
* @param _claimers the array of beneficiaries
* @param _points the array of amount of points
**/
function setReward(address[] _claimers, uint[] _points) onlyController {
require(state == State.OPEN);
uint len = _claimers.length;
for (uint i = 0; i < len; i++) {
address _claimer = _claimers[i];
assert(!rewards[_claimer].active);
rewards[_claimer].points = _points[i];
}
}
/**
* @notice only the repo owner may confirm reward of addresses
* @param _claimers array of addresses that are eligible to reward
**/
function confirm(address[] _claimers) onlyOwner {
uint len = _claimers.length;
uint nPoints = 0;
for (uint i = 0; i < len; i++) {
address _claimer = _claimers[i];
require(!rewards[_claimer].active);
rewards[_claimer].active = true;
nPoints += rewards[_claimer].points;
}
points += nPoints;
}
/**
* @notice only the repo owner may confirm reward of single address
* @param _claimer the address that is eligible to reward
**/
function confirm(address _claimer) onlyOwner {
require(!rewards[_claimer].active);
rewards[_claimer].active = true;
points += rewards[_claimer].points;
}
/**
* @notice only repo owner can close deposits and start reward or refund
* If no points confirmed the system will start refund, otherwise reward
*/
function close() onlyOwner {
require(state == State.OPEN);
state = points > 0 ? State.REWARD : State.REFUND;
}
/**
* @notice Set a new list of tokens to be rewarded.
* User can still reward tokens not listed if he calls `rewardEthAnd(address[]`
* providing a list including unlisted tokens.
* To list a new token use `watch(address)` that will update the balance aswell
* @param _tokens the list of new tokens.
*
*/
function setTokenList(address[] _tokens) onlyController {
tokens = _tokens;
}
/**
* @notice withdraw remaining tokens and eth send them to repoOwner
* this might be a case when some tokens were 'forgotten'
* or simply sent after finalized.
* @param _tokens the list of tokens to withdraw.
**/
function withdraw(address[] _tokens) onlyController {
require(state == State.FINALIZED);
if (this.balance > 0) {
owner.send(this.balance);
}
uint len = _tokens.length;
uint amount;
for (uint i = 0; i < len; i++) {
address token = _tokens[i];
amount = updateInternalBalance(token);
if (amount > 0) {
withdraw(
token,
owner,
amount,
0x0
);
}
}
}
/**
* @notice withdraw ether and tokens sent by `msg.sender`
* @param _tokens the tokens to withdraw
**/
function refundEthAnd(address[] _tokens) {
require(state == State.REFUND);
uint v = deposits[0x0][msg.sender];
if (v > 0) {
delete deposits[0x0][msg.sender];
require(msg.sender.send(v));
}
uint len = _tokens.length;
for (uint i = 0; i < len; i++) {
address _token = _tokens[i];
require(
withdraw(
_token,
msg.sender,
deposits[_token][msg.sender],
msg.sender
)
);
}
}
/**
* @dev register the deposit to refundings
**/
function register(
address _token,
address _sender,
uint _amount,
bytes _data
)
internal
{
require(state == State.OPEN);
super.register(
_token,
_sender,
_amount,
_data
);
}
function _reward(address[] _tokens) internal {
require(state == State.REWARD);
address dest = msg.sender;
require(rewards[dest].active);
uint _rewardPoints = rewards[dest].points;
delete rewards[dest];
require(_rewardPoints > 0);
uint _outReward;
uint len = _tokens.length;
for (uint i = 0; i < len; i++) {
address tokenAddr = _tokens[i];
_outReward = tokenBalances[tokenAddr];
if (_outReward > 0) {
_outReward = calculeReward(_outReward, _rewardPoints);
}
if (_outReward > 0) {
withdraw(
tokenAddr,
dest,
_outReward,
0x0
);
}
}
_outReward = this.balance;
if (_outReward > 0) {
_outReward = (_outReward / points) * _rewardPoints;
}
if (_outReward > 0) {
withdraw(
0x0,
dest,
_outReward,
0x0
);
}
points -= _rewardPoints;
if (points == 0) {
state = State.FINALIZED;
}
}
/**
* @dev amplifies small token balances to divide points
**/
function calculeReward(uint _balance, uint _rewardPoints)
internal
constant
returns (uint _reward)
{
uint amplifier = 1;
while (_balance * amplifier < points) {
amplifier *= 10;
}
_reward = (((_balance*amplifier) / points) * _rewardPoints) / amplifier;
}
}