Last active
June 15, 2022 09:43
-
-
Save naik899/59fd7e8653271a4df2d971223e6f98f8 to your computer and use it in GitHub Desktop.
Spock Proxy Contract
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// contracts/SpockProxy.sol | |
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | |
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; | |
import "@openzeppelin/contracts/utils/Counters.sol"; | |
contract SpockProxy { | |
address nftPool; | |
using Counters for Counters.Counter; | |
Counters.Counter private _tokenIds; | |
struct PlayerData { | |
uint256 tokenId; | |
address contractAddress; | |
string name; | |
string symbol; | |
uint256 initialPrice; | |
uint256 totalSupply; | |
} | |
PlayerData[] players; | |
// mapping(uint256 => address) playerNFTMap; | |
mapping(uint256 => address) playerTokenMap; | |
mapping(string => string) nftTokenMap; | |
address tokenPoolAddress; | |
address spockReservedPoolAddress; | |
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); | |
event SpockTransferred(address indexed to, uint256 amount); | |
event PlayerAdded(uint256 indexed tokenId, string name,string indexed symbol, uint256 indexed initialPrice); | |
event buy(address indexed receiver, uint256 indexed tokenId, uint256 indexed quantity); | |
event sell(address indexed sender, uint256 indexed tokenId, uint256 indexed quantity); | |
PlayerNFT newPlayerAddress; | |
ERC20 spockTokenAddress; | |
address owner; | |
constructor(address spockTokenInfo, address _tokenPoolAddress, address _spockReservedPoolAddress, address _nftPoolAddress) { | |
spockTokenAddress = ERC20(spockTokenInfo); | |
owner = msg.sender; | |
tokenPoolAddress = _tokenPoolAddress; | |
spockReservedPoolAddress = _spockReservedPoolAddress; | |
nftPool = _nftPoolAddress; | |
newPlayerAddress = new PlayerNFT("SPOCK-PLAYER", "SPKNFT"); | |
} | |
modifier onlyOwner() { | |
require(msg.sender == owner, "Only owner can call this function"); | |
_; | |
} | |
// change to grant and claim | |
function transferOwnership(address newOwner) public virtual onlyOwner { | |
require(newOwner != address(0), "Ownable: new owner is the zero address"); | |
emit OwnershipTransferred(owner, newOwner); | |
owner = newOwner; | |
} | |
function changeTokenPoolAddress(address newOwner) public virtual onlyOwner { | |
require(newOwner != address(0), "Ownable: new token pool address is the zero address"); | |
tokenPoolAddress = newOwner; | |
} | |
function changeSpockReservedPoolAddress(address newOwner) public virtual onlyOwner { | |
require(newOwner != address(0), "Ownable: new spock reserved pool address is the zero address"); | |
spockReservedPoolAddress = newOwner; | |
} | |
function changeNftPoolAddress(address newOwner) public virtual onlyOwner { | |
require(newOwner != address(0), "Ownable: new NFT pool address is the zero address"); | |
nftPool = newOwner; | |
} | |
function getNFTPlayerContract() public view returns (address){ | |
return address(newPlayerAddress); | |
} | |
function getSpockTokenAddress() public view returns (address){ | |
return address(spockTokenAddress); | |
} | |
function getTokenPoolAddress() public view returns (address){ | |
return tokenPoolAddress; | |
} | |
function getSpockReservedPoolAddress() public view returns (address){ | |
return spockReservedPoolAddress; | |
} | |
function getNftPoolAddress() public view returns (address){ | |
return nftPool; | |
} | |
function getPlayerContractAddressByTokenId(uint256 tokenId) public view returns (address){ | |
//to do require check tokenid exists | |
return playerTokenMap[tokenId]; | |
} | |
//add withdraw tokens only by owner to spockReservedPoolAddress | |
function withdrawSpock(address to) public onlyOwner{ | |
uint256 spockBalance = spockTokenAddress.balanceOf(address(this)); | |
require(spockBalance > 0, "Insufficient Spock balance"); | |
spockTokenAddress.transferFrom(address(this), to, spockBalance); | |
emit SpockTransferred(to, spockBalance); | |
} | |
//should be only owner | |
function addPlayer(string[] memory name, string[] memory symbol, uint256[] memory totalSupply, string[] memory tokenURI, uint256[] memory initialPrice) public onlyOwner { | |
//TODO: Add check for all array sizes | |
require(name.length >= 0, "Cannot add empty players"); | |
require(name.length == symbol.length, "Missing name or symbol information"); | |
require(name.length == totalSupply.length, "Missing name or Total Supply information"); | |
require(name.length == tokenURI.length, "Missing name or Token URI information"); | |
require(name.length == initialPrice.length, "Missing name or Initial price information"); | |
for(uint256 i =0; i < name.length; i++){ | |
require(bytes(nftTokenMap[symbol[i]]).length == 0, "Player Symbol is already taken"); | |
//TODO: Add necessary checks. | |
_tokenIds.increment(); | |
uint256 tokenId = _tokenIds.current(); | |
//Creating the NFT for the player | |
newPlayerAddress.mintNFT(nftPool, tokenId, tokenURI[i]); | |
// playerNFTMap[tokenId] = address(newPlayerAddress); | |
nftTokenMap[symbol[i]]= name[i]; | |
//Creating the fractions for the player as ERC20 msg.sender tokenPoolAddress | |
PlayerToken newPlayerToken = new PlayerToken(name[i], symbol[i], totalSupply[i], initialPrice[i], tokenPoolAddress); | |
players.push(PlayerData( | |
tokenId, | |
address(newPlayerToken), | |
name[i], | |
symbol[i], | |
initialPrice[i], | |
totalSupply[i] | |
)); | |
playerTokenMap[tokenId] = address(newPlayerToken); | |
emit PlayerAdded(tokenId, name[i], symbol[i], initialPrice[i]); | |
} | |
} | |
function depositToken(address sender, uint256 amount) public returns (bool) { | |
require(amount > 0, "You can't send 0 tokens"); | |
uint256 allowance = spockTokenAddress.allowance(sender, address(this)); | |
require(allowance >= amount, "Check the token allowance"); | |
spockTokenAddress.transferFrom(sender, spockReservedPoolAddress, amount); | |
return true; | |
} | |
function buyTokens(uint256 id, uint256 quantity) public { | |
require(playerTokenMap[id] != address(0), "Player does not exist"); | |
PlayerToken playerToken = PlayerToken(playerTokenMap[id]); | |
uint256 currentPrice = playerToken.getTokenPrice(); | |
uint256 currentSupply = playerToken.getCurrentSupply(); | |
require(currentSupply >= quantity, "Max supply exceeded"); | |
uint256 depositAmount = currentPrice * quantity; | |
require(depositToken(msg.sender, depositAmount)); | |
//token allowance should be checked and revert the spock transfer if below fails | |
playerToken.transferTokens(tokenPoolAddress, msg.sender, quantity * 1 ether); | |
emit buy(msg.sender, id, quantity); | |
playerToken.calculateTokenPrice(true); | |
//Send the msg.value amount to another address(think of it like our pool address) | |
//Calculate the new price of the token | |
} | |
function sellTokens(uint256 id, uint256 quantity) public { | |
require(playerTokenMap[id] != address(0), "Player does not exist"); | |
PlayerToken playerToken = PlayerToken(playerTokenMap[id]); | |
uint256 playerTokenBalance = playerToken.balanceOf(msg.sender); | |
require(playerTokenBalance >= quantity, "Insufficient funds"); | |
uint256 allowance = playerToken.allowance(msg.sender, address(this)); | |
require(allowance >= quantity, "Check the token allowance"); | |
uint256 currentPrice = playerToken.getTokenPrice(); | |
uint256 sellAmount = currentPrice * quantity; | |
playerToken.transferTokens(msg.sender, tokenPoolAddress, quantity * 1 ether); | |
emit sell(msg.sender, id, quantity); | |
spockTokenAddress.transferFrom(spockReservedPoolAddress, msg.sender, sellAmount); | |
playerToken.calculateTokenPrice(false); | |
} | |
function getPlayerData() public view returns(PlayerData[] memory) { | |
return players; | |
} | |
function withdraw(address _to) public onlyOwner { | |
payable(_to).transfer(address(this).balance); | |
} | |
} | |
/** | |
* @title SpockProxy | |
* @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator. | |
* Note they can later distribute these tokens as they wish using `transfer` and other | |
* `ERC20` functions. | |
* Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/examples/SimpleToken.sol | |
*/ | |
contract PlayerToken is ERC20 { | |
uint256 availableSupply; | |
uint256 totalFractions; | |
uint256 currentPrice; | |
address tokenPoolAddress; | |
address owner; | |
modifier onlyOwner() { | |
require(msg.sender == owner, "Only owner can call this function"); | |
_; | |
} | |
function transferOwnership(address newOwner) public virtual onlyOwner { | |
require(newOwner != address(0), "Ownable: new owner is the zero address"); | |
owner = newOwner; | |
} | |
/** | |
* @dev Constructor that gives msg.sender all of existing tokens. | |
*/ | |
constructor( | |
string memory name, | |
string memory symbol, | |
uint256 initialSupply, | |
uint256 initialPrice, | |
address tokenPool | |
) ERC20(name, symbol) { | |
totalFractions = initialSupply * (1 ether); | |
availableSupply = totalFractions; | |
currentPrice = initialPrice * (1 ether); | |
//Owner will be the proxy contract in this case | |
owner = msg.sender; | |
//Who should we mint to? A pool for ERC20 tokens. | |
_mint(tokenPool, totalFractions); | |
} | |
function getCurrentSupply() public view returns(uint256) { | |
return availableSupply; | |
} | |
//If action is buy - price will increase, if action is sell price decreases | |
function calculateTokenPrice(bool action) public returns(uint256) { | |
if(action){ | |
currentPrice = currentPrice + ((currentPrice)/availableSupply); | |
} | |
else { | |
currentPrice = currentPrice - ((125 * currentPrice)/(100*availableSupply)); | |
} | |
return currentPrice; | |
} | |
function transferTokens(address sender, | |
address recipient, | |
uint256 amount) external onlyOwner returns(bool) { | |
//TODO: Add required checks | |
if(sender != tokenPoolAddress){ | |
availableSupply = availableSupply - amount; | |
} | |
else if(sender == tokenPoolAddress) { | |
availableSupply = availableSupply + amount; | |
} | |
transferFrom(sender, recipient, amount); | |
return true; | |
} | |
function getTokenPrice() public view returns(uint256) { | |
return currentPrice; | |
} | |
} | |
contract PlayerNFT is ERC721URIStorage { | |
constructor(string memory name, string memory symbol) ERC721(name, symbol) { | |
} | |
function mintNFT(address to, uint256 tokenId, string memory tokenURI) public { | |
_safeMint(to, tokenId); | |
_setTokenURI(tokenId, tokenURI); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment