mirror of
https://github.com/status-im/github-oracle.git
synced 2026-08-29 19:01:09 +00:00
220 lines
6.7 KiB
Solidity
220 lines
6.7 KiB
Solidity
pragma solidity ^0.4.11;
|
|
|
|
import "../bank/TokenBank.sol";
|
|
import "../management/Controlled.sol";
|
|
|
|
/**
|
|
* @title IssueBank
|
|
* @author Ricardo Guilherme Schmidt
|
|
* Enable deposits to be withdrawn by points recievers
|
|
**/
|
|
contract IssueBank is Controlled, TokenBank {
|
|
enum State {OPEN, REFUND, REWARD, FINALIZED }
|
|
State public state;
|
|
uint public points;
|
|
uint public refundNonce;
|
|
mapping (address => Reward) public rewards;
|
|
address public repoOwner;
|
|
|
|
struct Reward {
|
|
bool active;
|
|
uint points;
|
|
}
|
|
|
|
modifier onlyRepoOwner{
|
|
if (msg.sender != repoOwner) throw;
|
|
_;
|
|
}
|
|
|
|
function IssueBank(address _repoOwner) {
|
|
repoOwner = _repoOwner;
|
|
state = State.OPEN;
|
|
}
|
|
|
|
/**
|
|
* @notice deposit ether in bank
|
|
**/
|
|
function () payable {
|
|
depositEther(new bytes(0));
|
|
}
|
|
|
|
/**
|
|
* @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 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 {
|
|
if(state != State.OPEN) throw;
|
|
if(rewards[_claimer].active) throw;
|
|
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 {
|
|
if(state != State.OPEN) throw;
|
|
uint len = _claimers.length;
|
|
for (uint i = 0; i < len; i++){
|
|
address _claimer = _claimers[i];
|
|
if(rewards[_claimer].active) throw;
|
|
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) onlyRepoOwner {
|
|
uint len = _claimers.length;
|
|
uint nPoints = 0;
|
|
for (uint i = 0; i < len; i++){
|
|
address _claimer = _claimers[i];
|
|
if(rewards[_claimer].active) throw;
|
|
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) onlyRepoOwner {
|
|
if(rewards[_claimer].active) throw;
|
|
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() onlyRepoOwner {
|
|
if(state != State.OPEN) throw;
|
|
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 tokens
|
|
* only avaliable in REWARD state and all points claimed.
|
|
*
|
|
**/
|
|
function withdraw(address[] _tokens) onlyController {
|
|
if(state != State.FINALIZED) throw;
|
|
uint len = _tokens.length;
|
|
uint amount;
|
|
for (uint i = 0; i< len; i++){
|
|
ERC20 token = ERC20(_tokens[i]);
|
|
amount = token.balanceOf(this);
|
|
if(amount > 0) _withdraw(token, repoOwner, amount, 0x0);
|
|
}
|
|
}
|
|
/**
|
|
* @notice only controller may kill contract and send all remaining eth and tokens to repo owner
|
|
* This can only be done when all rewards are claimed.
|
|
**/
|
|
function kill() onlyController {
|
|
if(state != State.FINALIZED) throw;
|
|
withdraw(tokens);
|
|
selfdestruct(repoOwner);
|
|
}
|
|
/**
|
|
* @dev overwriten to only allow refund in correct state.
|
|
**/
|
|
function refund(address token) returns (bool) {
|
|
if(state != State.REFUND) throw;
|
|
return super.refund(token);
|
|
}
|
|
|
|
/**
|
|
* @dev register the deposit to refundings
|
|
**/
|
|
function _deposited(address _sender, uint _amount, address _tokenAddr, bytes _data)
|
|
internal {
|
|
if(state != State.OPEN) throw;
|
|
super._deposited(_sender, _amount, _tokenAddr, _data);
|
|
}
|
|
|
|
function _reward(address[] _tokens) internal {
|
|
if(state != State.REWARD) throw;
|
|
address dest = msg.sender;
|
|
if (!rewards[dest].active) throw;
|
|
uint _reward_points = rewards[dest].points;
|
|
delete rewards[dest];
|
|
if (_reward_points == 0) throw;
|
|
uint reward;
|
|
uint len = _tokens.length;
|
|
for (uint i = 0; i< len; i++){
|
|
address tokenAddr = _tokens[i];
|
|
reward = tokenBalances[tokenAddr];
|
|
if (reward > 0) reward = calculeReward(reward, _reward_points);
|
|
if (reward > 0) _withdraw(tokenAddr, dest, reward, 0x0);
|
|
}
|
|
reward = this.balance;
|
|
if (reward > 0) reward = (reward / points) * _reward_points;
|
|
if (reward > 0) _withdraw(0x0, dest, reward, 0x0);
|
|
points -= _reward_points;
|
|
if(points == 0) state = State.FINALIZED;
|
|
}
|
|
|
|
/**
|
|
* @dev amplifies small token balances to divide points
|
|
**/
|
|
function calculeReward(uint _balance, uint _reward_points) internal constant returns (uint reward) {
|
|
uint amplifier = 1;
|
|
while(_balance * amplifier < points){
|
|
amplifier *= 10;
|
|
}
|
|
reward = (((_balance*amplifier) / points) * _reward_points) / amplifier;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* @title IssueBankFactory
|
|
* @author Ricado Guilherme Schmidt <3esmit>
|
|
**/
|
|
contract IssueBankFactory {
|
|
|
|
/**
|
|
* @notice creates new IssueBank with repoOwner as moderator
|
|
**/
|
|
function create(address repoOwner) returns(IssueBank){
|
|
IssueBank bank = new IssueBank(repoOwner);
|
|
bank.changeController(msg.sender);
|
|
return bank;
|
|
}
|
|
|
|
} |