commiteth issuebank

This commit is contained in:
Ricardo Guilherme Schmidt
2017-05-30 19:10:05 -03:00
parent cbc1bee917
commit b743861016
2 changed files with 376 additions and 0 deletions
+222
View File
@@ -0,0 +1,222 @@
import "../bank/TokenBank.sol";
import "../management/Controlled.sol";
pragma solidity ^0.4.11;
/**
* @title IssueBank
* @author Ricardo Guilherme Schmidt <3esmit>
* 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 {
deposit();
}
/**
* @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);
}
}
/**
* @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(uint depositNonce) returns (bool) {
if(state != State.REFUND) throw;
refundNonce++;
if(refundNonce == nonce) state = State.FINALIZED;
return super.refund(depositNonce);
}
/**
* @dev register the deposit to refundings
**/
function _deposited(address _tokenAddr, address _sender, uint _amount)
internal returns (uint receipt) {
if(state != State.OPEN) throw;
return super._deposited(_tokenAddr, _sender, _amount);
}
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);
}
reward = this.balance;
if (reward > 0) reward = (reward / points) * _reward_points;
if (reward > 0) withdraw(dest, reward);
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;
}
}
+154
View File
@@ -0,0 +1,154 @@
import "../token/ERC23.sol";
pragma solidity ^0.4.11;
/**
* @title TokenBank
* @author Ricardo Guilherme Schmidt <3esmit>
* Abstract contract for deposit and withdraw of ETH and ERC20/23 Tokens
**/
contract TokenBank is ERC23Receiver, ApproveAndCallFallBack {
event Withdrawn(address reciever, uint amount);
event Deposited(address sender, uint value);
event TokenWithdrawn(address token, address reciever, uint amount);
event TokenDeposited(address token, address sender, uint value);
mapping (uint => Deposit) public deposits;
mapping (address => uint) public tokenBalances;
address[] public tokens;
uint public nonce;
struct Deposit {
address sender;
address token;
uint amount;
}
/**
* @notice deposit ether in bank
* @return reciept that can be used for refund
**/
function deposit() payable returns (uint receipt) {
address sender = msg.sender;
uint amount = msg.value;
if(amount > 0){
return _deposited(0x0, sender, amount);
}
}
/**
* @notice deposit a ERC20 token. The amount of deposit is the allowance set to this contract.
* @param _tokenAddr the token contract address
* @return reciept that can be used for refund
**/
function tokenDeposit(address _tokenAddr) returns (uint reciept) {
address sender = msg.sender;
ERC20 token = ERC20(_tokenAddr);
uint amount = token.allowance(sender, this);
if(amount == 0) throw;
uint _nonce = nonce;
if(!token.transferFrom(sender, this, amount)) throw;
if(!token.approve(this, amount)) throw;
if(nonce == _nonce){
reciept = _deposited(_tokenAddr, sender, amount);
}else{
reciept = _nonce; //ERC23 executed _deposited tokenFallback by
}
}
/**
* @notice watches for balance in a token contract
* @param _tokenAddr the token contract address
**/
function watch(address _tokenAddr){
bool neverSeen = false;
if(tokenBalances[_tokenAddr] == 0) neverSeen = true;
uint amount = ERC20(_tokenAddr).balanceOf(this);
if(amount > 0){
if(!ERC20(_tokenAddr).approve(this, amount)) throw;
if(neverSeen) tokens.push(_tokenAddr);
tokenBalances[_tokenAddr] = amount;
}
}
/**
* @notice refunds a deposit.
* @param _nonce the reciept you want to refund
**/
function refund(uint _nonce) returns (bool) {
if(msg.sender != deposits[_nonce].sender) throw;
uint amount = deposits[_nonce].amount;
address token = deposits[_nonce].token;
delete deposits[_nonce];
if(token == 0x0){
withdraw(msg.sender,amount);
} else {
withdraw(ERC20(token), msg.sender, amount);
}
return true;
}
/**
* @notice ERC23 Token fallback
* @param _from address incoming token
* @param _amount incoming amount
**/
function tokenFallback(address _from, uint _amount, bytes) {
_deposited(msg.sender, _from, _amount);
}
/**
* @notice Called MiniMeToken approvesAndCall to this contract
* @param _from address incoming token
* @param _amount incoming amount
* @param _token the token contract address
*/
function receiveApproval(address _from, uint256 _amount, address _token, bytes){
_deposited(_token, _from, _amount);
}
/**
* @dev register the deposit to refundings
**/
function _deposited(address _tokenAddr, address _sender, uint _amount)
internal returns (uint receipt) {
if(_tokenAddr != 0x0){
TokenDeposited(_tokenAddr, _sender, _amount);
if(tokenBalances[_tokenAddr] == 0){
tokens.push(_tokenAddr);
tokenBalances[_tokenAddr] = ERC20(_tokenAddr).balanceOf(this);
}else{
tokenBalances[_tokenAddr] += _amount;
}
}else{
Deposited(_sender, _amount);
}
receipt = nonce;
nonce++;
deposits[receipt] = Deposit({sender: _sender, amount: _amount, token: _tokenAddr});
}
/**
* @dev withdraw amount wei to dest
**/
function withdraw(address _dest, uint _amount)
internal {
_dest.transfer(_amount);
Withdrawn(msg.sender, _amount);
}
/**
* @dev withdraw token amount to dest
**/
function withdraw(address _tokenAddr, address _dest, uint _amount)
internal {
if(!ERC20(_tokenAddr).transferFrom(this, _dest, _amount)) throw;
tokenBalances[_tokenAddr] -= _amount;
TokenWithdrawn(_tokenAddr, _dest, _amount);
}
}