mirror of
https://github.com/status-im/gitpivot.git
synced 2026-08-27 16:41:08 +00:00
284 lines
8.1 KiB
Solidity
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;
|
|
}
|
|
|
|
|
|
} |