Skip to content

Instantly share code, notes, and snippets.

@nhphong
Last active August 11, 2019 08:09
Show Gist options
  • Save nhphong/00fc47e7d83505c6dae359c26dd264a7 to your computer and use it in GitHub Desktop.
Save nhphong/00fc47e7d83505c6dae359c26dd264a7 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.5.10+commit.5a6ea5b1.js&optimize=true&gist=
pragma solidity ^0.5.10;
import "github.com/OpenZeppelin/openzeppelin-solidity/contracts/ownership/Ownable.sol";
contract Authorizable is Ownable {
address[] private _authorized;
modifier onlyAuthorized() {
require(isAuthorized(), "Authorizable: caller is not authorized");
_;
}
event AuthorizationGranted(address indexed newAuthorized);
event AuthorizationRevoked(address indexed victim);
function isAuthorized() public view returns (bool) {
return isAuthorized(msg.sender);
}
function isAuthorized(address _address) public view returns (bool) {
if (_address == owner()) {
return true;
}
for (uint i = 0; i < _authorized.length; ++i) {
if (_authorized[i] == _address) {
return true;
}
}
return false;
}
function authorize(address _address) public onlyAuthorized {
require(_address != address(0));
require(!isAuthorized(_address), "Authorizable: target address is already authorized");
_authorized.push(_address);
emit AuthorizationGranted(_address);
}
function revokeAuthorization(address _address) public onlyAuthorized {
require(_address != address(0));
require(_address != owner(), "Authorizable: cannot revoke authorization of the contract creator.");
for (uint i = 0; i < _authorized.length; ++i) {
if (_authorized[i] == _address) {
_authorized[i] = _authorized[_authorized.length - 1];
delete _authorized[_authorized.length - 1];
_authorized.length--;
emit AuthorizationRevoked(_address);
break;
}
}
}
function authorized() public view returns (address[] memory) {
return _authorized;
}
function contractCreator() public view returns (address) {
return owner();
}
}
pragma solidity ^0.5.10;
import "./ERC721Priceable.sol";
import "./Authorizable.sol";
contract ERC20Token {
uint public decimals;
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}
contract BuyableReward is ERC721Priceable, Authorizable {
ERC20Token private _erc20Token;
uint private _erc20TokenDecimals;
event Erc20TokenAddressSet(address indexed tokenAddress, uint indexed tokenDecimals);
event Erc20PayingAttempt(address indexed buyer, address indexed rewardOwner, uint indexed amount);
constructor(string memory name, string memory symbol) public ERC721Priceable(name, symbol) {}
function setErc20TokenAddress(address _address) external onlyAuthorized {
_erc20Token = ERC20Token(_address);
_erc20TokenDecimals = _erc20Token.decimals();
require(_erc20TokenDecimals >= 2);
emit Erc20TokenAddressSet(_address, _erc20TokenDecimals);
}
function buyReward(uint _rewardId) external returns (bool) {
address rewardOwner = ownerOf(_rewardId);
address buyer = msg.sender;
require(_exists(_rewardId), "Reward doesn't exist");
require(buyer != rewardOwner, "Cannot buy the reward that you own.");
uint price;
uint decimals;
(price, decimals) = priceOf(_rewardId);
uint convertedPrice = price * (10 ** (_erc20TokenDecimals.sub(decimals)));
// Pay the reward owner
emit Erc20PayingAttempt(buyer, rewardOwner, convertedPrice);
_erc20Token.transferFrom(buyer, rewardOwner, convertedPrice);
// Transfer the ownership of the reward
BuyableReward(this).safeTransferFrom(rewardOwner, buyer, _rewardId);
// Re-allow the contract to transfer the reward on behalf of the new owner (buyer)
approve(address(this), _rewardId);
return true;
}
}
pragma solidity ^0.5.10;
import "github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC721/ERC721Full.sol";
contract ERC721Priceable is ERC721Full {
struct Price {
uint value;
uint decimals;
}
mapping(uint => Price) private _prices;
event PriceSet(uint indexed tokenId, uint indexed price, uint indexed decimals);
constructor(string memory name, string memory symbol) public ERC721Full(name, symbol) {}
function priceOf(uint _tokenId) public view returns (uint value, uint decimals) {
require(_exists(_tokenId), "ERC721Buyable: Price query for nonexistent token.");
Price storage price = _prices[_tokenId];
return (price.value, price.decimals);
}
function _setPrice(uint _tokenId, uint _price, uint _decimals) internal {
require(_exists(_tokenId), "ERC721Buyable: Price set of nonexistent token.");
require(_decimals <= 2, "ERC721Buyable: Price decimals cannot be bigger than 2.");
_prices[_tokenId] = Price(_price, _decimals);
emit PriceSet(_tokenId, _price, _decimals);
}
function _burn(address _owner, uint256 _tokenId) internal {
super._burn(_owner, _tokenId);
// Clear the price (if any)
Price memory price = _prices[_tokenId];
if (price.value != 0 || price.decimals != 0) {
delete _prices[_tokenId];
}
}
}
pragma solidity ^0.5.10;
import "github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20Capped.sol";
contract NimbleGold is ERC20Capped {
string public name = "Nimble Gold";
string public symbol = "NBG";
uint public decimals = 2;
uint private _maxSupply = 100000000;
constructor() ERC20Capped(_maxSupply * (10 ** decimals)) public {}
// Don't accept ETH
function () external payable {
revert();
}
}
pragma solidity ^0.5.10;
import "./BuyableReward.sol";
contract NimbleReward is BuyableReward {
constructor() public BuyableReward("NimbleReward", "NRW") {}
modifier onlyOwnerOf(uint _rewardId) {
require(msg.sender == ownerOf(_rewardId), "Caller is not the owner of the reward");
_;
}
function createReward(uint _price, uint _priceDecimals, string calldata _metadata) external onlyAuthorized {
uint rewardId = totalSupply();
// Mint the reward, and set the caller as its owner
_safeMint(msg.sender, rewardId);
// Set the reward price
_setPrice(rewardId, _price, _priceDecimals);
// Set metadata
_setTokenURI(rewardId, _metadata);
// Allow the contract to transfer this reward on the caller's behalf
approve(address(this), rewardId);
}
function deleteReward(uint _rewardId) external onlyAuthorized onlyOwnerOf(_rewardId) {
_burn(_rewardId);
}
function setRewardMetadata(uint _rewardId, string calldata _metadata) external onlyAuthorized onlyOwnerOf(_rewardId) {
_setTokenURI(_rewardId, _metadata);
}
function setRewardPrice(uint _rewardId, uint _price, uint _decimals) external onlyAuthorized onlyOwnerOf(_rewardId) {
_setPrice(_rewardId, _price, _decimals);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment