Skip to content

Instantly share code, notes, and snippets.

@naik899
Last active June 15, 2022 09:43
Show Gist options
  • Save naik899/59fd7e8653271a4df2d971223e6f98f8 to your computer and use it in GitHub Desktop.
Save naik899/59fd7e8653271a4df2d971223e6f98f8 to your computer and use it in GitHub Desktop.
Spock Proxy Contract
// 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