{"action":"created","issue":{"url":"https://api.github.com/repos/BountyOneBounties/Issues/issues/13","repository_url":"https://api.github.com/repos/BountyOneBounties/Issues","labels_url":"https://api.github.com/repos/BountyOneBounties/Issues/issues/13/labels{/name}","comments_url":"https://api.github.com/repos/BountyOneBounties/Issues/issues/13/comments","events_url":"https://api.github.com/repos/BountyOneBounties/Issues/issues/13/events","html_url":"https://github.com/BountyOneBounties/Issues/issues/13","id":330438864,"node_id":"MDU6SXNzdWUzMzA0Mzg4NjQ=","number":13,"title":"Create JavaScript Frontend to Send any ERC20 Token to \"createBountyERC20\"","user":{"login":"thebkr7","id":11528441,"node_id":"MDQ6VXNlcjExNTI4NDQx","avatar_url":"https://avatars1.githubusercontent.com/u/11528441?v=4","gravatar_id":"","url":"https://api.github.com/users/thebkr7","html_url":"https://github.com/thebkr7","followers_url":"https://api.github.com/users/thebkr7/followers","following_url":"https://api.github.com/users/thebkr7/following{/other_user}","gists_url":"https://api.github.com/users/thebkr7/gists{/gist_id}","starred_url":"https://api.github.com/users/thebkr7/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thebkr7/subscriptions","organizations_url":"https://api.github.com/users/thebkr7/orgs","repos_url":"https://api.github.com/users/thebkr7/repos","events_url":"https://api.github.com/users/thebkr7/events{/privacy}","received_events_url":"https://api.github.com/users/thebkr7/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":6,"created_at":"2018-06-07T21:16:18Z","updated_at":"2018-06-14T17:29:49Z","closed_at":null,"author_association":"NONE","body":"Please create a Javascript frontend that will use Web3 to send any ERC20 token (any token address can be used as the example address for now) to the createBountyERC20 function in the below contract:\r\n\r\n`pragma solidity ^0.4.14;\r\n\r\ncontract BountyBG {\r\n\r\n    address public owner;\r\n\r\n    uint256 public bountyCount = 0;\r\n    // uint256 public minBounty = 10 finney;\r\n    // uint256 public bountyFee = 2 finney;\r\n    \r\n    uint256 public bountyFee = 2 finney;\r\n    uint256 public minBounty = 10 finney;\r\n    // my code: \r\n    // As the contract is supposed to support any ERC20 contract, the bountyFee and minBounty  \r\n    // parameter must be determined according to token introduced by bounty owner.\r\n    mapping (address => uint256) bountyFeeToken;\r\n    mapping (address => uint256) minBountyToken;\r\n\r\n    // my code: payment types are ether or erc20 type token\r\n    enum paymentType {ETHER, ERC20}\r\n\r\n    // uint256 public bountyFeeCount = 0;\r\n    // my code: bounty fees must be counted with respect to token payments\r\n    mapping (address => uint256) public bountyFeeCount;\r\n\r\n    uint256 public bountyBeneficiariesCount = 2;\r\n    uint256 public bountyDuration = 30 hours;\r\n    uint256 public bountyDurationPsterAllowed = 48 hours; // or whatever you need\r\n    \r\n\r\n    mapping(uint256 => Bounty) bountyAt;\r\n\r\n    event BountyStatus(string _msg, uint256 _id, address _from, uint256 _amount);\r\n    event RewardStatus(string _msg, uint256 _id, address _to, uint256 _amount);\r\n    event ErrorStatus(string _msg, uint256 _id, address _to, uint256 _amount);\r\n\r\n    struct Bounty {\r\n        uint256 id;\r\n        address owner;\r\n        uint256 bounty;\r\n        \r\n        // my code :\r\n        // ParameterType: {'ETHER': payment is done by ethereum, 'ERC20': payment is done by any ERC20 Token.}\r\n        // token Address: {if the payment is done by an ERC20 Token, here the token address must be registered,\r\n        // -------------:  else, you can put the contract address or leave it blank.}\r\n        paymentType payment;\r\n        address tokenAddress;\r\n\r\n        uint256 remainingBounty;\r\n        uint256 startTime;\r\n        uint256 endTime;\r\n        bool ended;\r\n        bool retracted;\r\n    }\r\n\r\n    constructor() public {\r\n        owner = msg.sender;\r\n    }\r\n\r\n    modifier onlyOwner() {\r\n        require(msg.sender == owner);\r\n        _;\r\n    }\r\n\r\n    modifier onlyPoster(uint _bountyId) {\r\n        require(msg.sender == bountyAt[_bountyId].owner);\r\n        _;\r\n    }\r\n\r\n    modifier allowedToReward(uint _bountyId) {\r\n        require((msg.sender == bountyAt[_bountyId].owner) ||\r\n                (msg.sender == owner &&\r\n                bountyAt[_bountyId].startTime + bountyDurationPsterAllowed > block.timestamp));\r\n        _;\r\n    }\r\n\r\n    // BLOCKGEEKS ACTIONS\r\n\r\n    function withdrawFee(uint256 _amount) external onlyOwner {\r\n        require(_amount <= bountyFeeCount[this]);\r\n        bountyFeeCount[this] -= _amount;\r\n        owner.transfer(_amount);\r\n    }\r\n\r\n    // my code: Now owner can also withdraw fees by other ERC20 tokens.\r\n    // @_tokenAddress: ERC20 token Address\r\n    function withdrawFeeToken(uint256 _amount, address _tokenAddress) external onlyOwner{\r\n        require(_amount <= bountyFeeCount[_tokenAddress]);\r\n        bountyFeeCount[_tokenAddress] -= _amount;\r\n        ERC20Interface token = ERC20Interface(_tokenAddress);\r\n        token.transfer(owner, _amount);\r\n    }\r\n\r\n    function setBountyDuration(uint256 _bountyDuration) external onlyOwner {\r\n        bountyDuration = _bountyDuration;\r\n    }\r\n\r\n    function setMinBounty(uint256 _minBounty) external onlyOwner {\r\n        minBounty = _minBounty;\r\n    }\r\n\r\n    // my code: Now for any ERC20 token owner can determine minimum bounty amount.\r\n    // @tokenAddress: the token contract address.\r\n    // @_minBounty: minimum bounty amount in token unit.\r\n    function setMinBountyToken(address _tokenAddress, uint256 _minBounty) external onlyOwner {\r\n        minBountyToken[_tokenAddress] = _minBounty;\r\n    }\r\n\r\n    // my code: Now for any ERC20 token owner can determine bounty fee amount.\r\n    // @tokenAddress: the token contract address.\r\n    // @_bountyFee: bounty Fee in token unit.\r\n    function setBountyFeeToken(address _tokenAddress, uint256 _bountyFee) external onlyOwner {\r\n        bountyFeeToken[_tokenAddress] = _bountyFee;\r\n    }\r\n\r\n    function setBountyBeneficiariesCount(uint256 _bountyBeneficiariesCount) external onlyOwner {\r\n        bountyBeneficiariesCount = _bountyBeneficiariesCount;\r\n    }\r\n\r\n    // code changed: rewardUsers now support payment in any ERC20 token.\r\n    function rewardUsers(uint256 _bountyId, address[] _users, uint256[] _rewards) external allowedToReward(_bountyId) {\r\n        Bounty storage bounty = bountyAt[_bountyId];\r\n        require(\r\n            !bounty.ended &&\r\n            !bounty.retracted &&\r\n            bounty.startTime + bountyDuration > block.timestamp &&\r\n            _users.length > 0 &&\r\n            _users.length <= bountyBeneficiariesCount &&\r\n            _users.length == _rewards.length\r\n        );\r\n\r\n        bounty.ended = true;\r\n        bounty.endTime = block.timestamp;\r\n        uint256 currentRewards = 0;\r\n        for (uint8 i = 0; i < _rewards.length; i++) {\r\n            currentRewards += _rewards[i];\r\n        }\r\n\r\n        require(bounty.bounty >= currentRewards);\r\n\r\n        if (bounty.payment == paymentType.ERC20) {\r\n            address tokenAddress = bounty.tokenAddress;\r\n            ERC20Interface token = ERC20Interface(tokenAddress);\r\n        }\r\n\r\n        for (i = 0; i < _users.length; i++) {\r\n            if (bounty.payment == paymentType.ETHER) {\r\n                _users[i].transfer(_rewards[i]);    \r\n            } else {\r\n                token.transfer(_users[i], _rewards[i]);\r\n            }\r\n            \r\n            emit RewardStatus(\"Reward sent\", bounty.id, _users[i], _rewards[i]);\r\n            /* if (_users[i].send(_rewards[i])) {\r\n                bounty.remainingBounty -= _rewards[i];\r\n                RewardStatus('Reward sent', bounty.id, _users[i], _rewards[i]);\r\n            } else {\r\n                ErrorStatus('Error in reward', bounty.id, _users[i], _rewards[i]);\r\n            } */\r\n        }\r\n    }\r\n\r\n    // code changed: rewardUser now support payment in any ERC20 token.\r\n    function rewardUser(uint256 _bountyId, address _user, uint256 _reward) external onlyPoster(_bountyId) {\r\n        Bounty storage bounty = bountyAt[_bountyId];\r\n        require(bounty.remainingBounty >= _reward);\r\n        \r\n        bounty.remainingBounty -= _reward;\r\n        bounty.ended = true;\r\n        bounty.endTime = block.timestamp;\r\n        \r\n        if (bounty.payment == paymentType.ETHER) {\r\n            _user.transfer(_reward);\r\n        } else {\r\n            address tokenAddress = bounty.tokenAddress;\r\n            ERC20Interface token = ERC20Interface(tokenAddress);\r\n            token.transfer(_user, _reward);\r\n        }\r\n\r\n        emit RewardStatus('Reward sent', bounty.id, _user, _reward);\r\n    }\r\n\r\n    // USER ACTIONS TRIGGERED BY METAMASK\r\n\r\n    function createBounty(uint256 _bountyId) external payable {\r\n        require(\r\n            msg.value >= minBounty + bountyFee\r\n        );\r\n        Bounty storage bounty = bountyAt[_bountyId];\r\n        require(bounty.id == 0);\r\n        bountyCount++;\r\n        bounty.id = _bountyId;\r\n        bounty.bounty = msg.value - bountyFee;\r\n        bounty.remainingBounty = bounty.bounty;\r\n        bounty.payment = paymentType.ETHER;\r\n        bounty.tokenAddress = this;\r\n        bountyFeeCount[this] += bountyFee;\r\n        bounty.startTime = block.timestamp;\r\n        bounty.owner = msg.sender;\r\n        emit BountyStatus('Bounty submitted', bounty.id, msg.sender, msg.value);\r\n    }\r\n\r\n    // my code: createBountyERC20 is added for when one can create a new bounty but to pay in an ERC20 token\r\n    // @_tokenAddress: ERC20 token address which by payment will be done.\r\n    function createBountyERC20(uint256 _bountyId, address _tokenAddress) external payable {\r\n        ERC20Interface token = ERC20Interface(_tokenAddress);\r\n        require(\r\n            minBountyToken[_tokenAddress] > 0 &&\r\n            bountyFeeToken[_tokenAddress] > 0 &&\r\n            token.allowance(msg.sender, this) >= minBountyToken[_tokenAddress] + bountyFeeToken[_tokenAddress]\r\n        );\r\n        uint256 bountyAmount = token.allowance(msg.sender, this);\r\n        token.transferFrom(msg.sender, this, bountyAmount);\r\n        Bounty storage bounty = bountyAt[_bountyId];\r\n        require(bounty.id == 0);\r\n        bountyCount++;\r\n        bounty.id = _bountyId;\r\n        bounty.bounty = bountyAmount - bountyFeeToken[_tokenAddress];\r\n        bounty.remainingBounty = bounty.bounty;\r\n        bounty.payment = paymentType.ERC20;\r\n        bounty.tokenAddress = _tokenAddress;\r\n        bountyFeeCount[bounty.tokenAddress] += bountyFeeToken[_tokenAddress];\r\n        bounty.startTime = block.timestamp;\r\n        bounty.owner = msg.sender;\r\n        emit BountyStatus('Bounty submitted with ERC20', bounty.id, msg.sender, bountyAmount);\r\n    }\r\n\r\n    // code changed: cancelBounty now support payments with any ERC20 token.\r\n    function cancelBounty(uint256 _bountyId) external {\r\n        Bounty storage bounty = bountyAt[_bountyId];\r\n        require(\r\n            msg.sender == bounty.owner &&\r\n            !bounty.ended &&\r\n            !bounty.retracted &&\r\n            bounty.owner == msg.sender &&\r\n            bounty.startTime + bountyDuration < block.timestamp\r\n        );\r\n        bounty.ended = true;\r\n        bounty.retracted = true;\r\n        if (bounty.payment == paymentType.ETHER) {\r\n            bounty.owner.transfer(bounty.bounty);\r\n        } else {\r\n            address tokenAddress = bounty.tokenAddress;\r\n            ERC20Interface token = ERC20Interface(tokenAddress);\r\n            token.approve(bounty.owner, bounty.bounty);\r\n        }\r\n        emit BountyStatus('Bounty was canceled', bounty.id, msg.sender, bounty.bounty);\r\n    }\r\n\r\n    // CUSTOM GETTERS\r\n\r\n    function getBalance() external view returns (uint256) {\r\n        return address(this).balance;\r\n    }\r\n\r\n    function getBounty(uint256 _bountyId) external view\r\n    returns (uint256, address, uint256, uint256, uint256, uint256, bool, bool) {\r\n        Bounty memory bounty = bountyAt[_bountyId];\r\n        return (\r\n            bounty.id,\r\n            bounty.owner,\r\n            bounty.bounty,\r\n            bounty.remainingBounty,\r\n            bounty.startTime,\r\n            bounty.endTime,\r\n            bounty.ended,\r\n            bounty.retracted\r\n        );\r\n    }\r\n\r\n}`"},"comment":{"url":"https://api.github.com/repos/BountyOneBounties/Issues/issues/comments/397375573","html_url":"https://github.com/BountyOneBounties/Issues/issues/13#issuecomment-397375573","issue_url":"https://api.github.com/repos/BountyOneBounties/Issues/issues/13","id":397375573,"node_id":"MDEyOklzc3VlQ29tbWVudDM5NzM3NTU3Mw==","user":{"login":"hnamzian","id":27501202,"node_id":"MDQ6VXNlcjI3NTAxMjAy","avatar_url":"https://avatars3.githubusercontent.com/u/27501202?v=4","gravatar_id":"","url":"https://api.github.com/users/hnamzian","html_url":"https://github.com/hnamzian","followers_url":"https://api.github.com/users/hnamzian/followers","following_url":"https://api.github.com/users/hnamzian/following{/other_user}","gists_url":"https://api.github.com/users/hnamzian/gists{/gist_id}","starred_url":"https://api.github.com/users/hnamzian/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hnamzian/subscriptions","organizations_url":"https://api.github.com/users/hnamzian/orgs","repos_url":"https://api.github.com/users/hnamzian/repos","events_url":"https://api.github.com/users/hnamzian/events{/privacy}","received_events_url":"https://api.github.com/users/hnamzian/received_events","type":"User","site_admin":false},"created_at":"2018-06-14T17:29:49Z","updated_at":"2018-06-14T17:29:49Z","author_association":"NONE","body":"this is the video\r\n\r\nhttps://drive.google.com/drive/u/0/folders/1QSfsH_Oxw0DfPQEIXK6ZWdHCuDE9y2kX"}}
{"actor":{"display_login":"hnamzian"}}