diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..22845b7 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,14 @@ +module.exports = { + env: { + browser: true, + commonjs: true, + es6: true, + }, + globals: { + Atomics: "readonly", + SharedArrayBuffer: "readonly", + }, + parserOptions: { + ecmaVersion: 2018, + }, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..73d8493 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +build/ +flattened/ +node_modules/ +.env* +*.DS_Store +data +package-lock.json +*.tar.gz +output.json +addr-to-claim.json diff --git a/README.md b/README.md index 78a91e0..938fcee 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # suchwowx-smart-contract + Smart contracts for SuchwowX interplanetary meme project. diff --git a/contracts/Migrations.sol b/contracts/Migrations.sol new file mode 100644 index 0000000..0cfdc23 --- /dev/null +++ b/contracts/Migrations.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract Migrations { + address public owner = msg.sender; + uint public last_completed_migration; + + modifier restricted() { + require( + msg.sender == owner, + "This function is restricted to the contract's owner" + ); + _; + } + + function setCompleted(uint completed) public restricted { + last_completed_migration = completed; + } +} diff --git a/contracts/SuchwowX.sol b/contracts/SuchwowX.sol new file mode 100644 index 0000000..7fc160e --- /dev/null +++ b/contracts/SuchwowX.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/utils/math/SafeMath.sol"; +import "@openzeppelin/contracts/utils/Counters.sol"; + + +contract SuchwowX is ERC721, ERC721URIStorage, Ownable { + using SafeMath for uint256; + using Counters for Counters.Counter; + Counters.Counter private _tokenSupply; + + // Data to maintain + mapping (uint256 => address) public tokenCreator; + mapping (uint256 => string) public tokenMetadata; + mapping (uint256 => uint256) public tokenTips; + mapping (address => uint256) public creatorTips; + mapping (address => uint256) public creatorTokensMinted; + mapping (address => uint256) public tipperTips; + + // Define starting contract state + string public baseURI = ""; + + constructor() ERC721("SuchwowX", "SWX") {} + + // Withdraw contract balance to creator (mnemonic seed address 0) + function withdraw() public onlyOwner { + uint256 balance = address(this).balance; + payable(msg.sender).transfer(balance); + } + + // Get total supply based upon counter + function totalSupply() public view returns (uint256) { + return _tokenSupply.current(); + } + + // Mint a new token with a specific metadata hash location + function mint(string memory metadataIPFSHash) external { + uint256 tokenId = totalSupply() + 1; // Start at 1 + _safeMint(msg.sender, tokenId); + _tokenSupply.increment(); + tokenCreator[tokenId] = msg.sender; + tokenMetadata[tokenId] = metadataIPFSHash; + creatorTokensMinted[msg.sender] = creatorTokensMinted[msg.sender].add(1); + } + + // Tip a token and it's creator + function tip(uint256 tokenId) public payable { + address creator = tokenCreator[tokenId]; + tokenTips[tokenId] = tokenTips[tokenId].add(msg.value); + creatorTips[creator] = creatorTips[creator].add(msg.value); + tipperTips[creator] = tipperTips[creator].add(msg.value); + payable(creator).transfer(msg.value); + } + + // Override the below functions from parent contracts + + function tokenURI(uint256 tokenId) + public + view + override(ERC721, ERC721URIStorage) + returns (string memory) + { + // Each token should return a unique IPFS hash + return string(abi.encodePacked("ipfs://", tokenMetadata[tokenId])); + } + + function _burn(uint256 tokenId) + internal + override(ERC721, ERC721URIStorage) + { + + } +} diff --git a/env-example b/env-example new file mode 100644 index 0000000..eddc588 --- /dev/null +++ b/env-example @@ -0,0 +1,2 @@ +INFURA_PID=xxxxxxxxxxxxxxxxxxxx +MNEMONIC=this should be your twelve word seed diff --git a/migrations/1_initial_migrations.js b/migrations/1_initial_migrations.js new file mode 100644 index 0000000..4344a21 --- /dev/null +++ b/migrations/1_initial_migrations.js @@ -0,0 +1,5 @@ +const Migrations = artifacts.require("./Migrations.sol") + +module.exports = function(deployer) { + deployer.deploy(Migrations) +} diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js new file mode 100644 index 0000000..dd6a1ab --- /dev/null +++ b/migrations/2_deploy_contracts.js @@ -0,0 +1,5 @@ +var SuchwowX = artifacts.require("SuchwowX"); + +module.exports = function(deployer) { + deployer.deploy(SuchwowX); +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..d527576 --- /dev/null +++ b/package.json @@ -0,0 +1,31 @@ +{ + "name": "suchwowx-smart-contract", + "version": "1.0.0", + "description": "Smart contract for the SuchwowX interplanetary meme project.", + "main": "index.js", + "scripts": { + "test": "truffle test" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/lalanza808/suchwowx-smart-contract.git" + }, + "author": "lza_menace@protonmail.com", + "license": "ISC", + "bugs": { + "url": "https://github.com/lalanza808/suchwowx-smart-contract/issues" + }, + "homepage": "https://github.com/lalanza808/suchwowx-smart-contract", + "dependencies": { + "@openzeppelin/contracts": "^4.3.3", + "dotenv": "^10.0.0", + "ganache-cli": "^6.12.2", + "truffle": "^5.4.19", + "truffle-hdwallet-provider": "^1.0.17", + "truffle-plugin-verify": "^0.5.18", + "web3": "^1.6.1" + }, + "engines": { + "node": "^12.18.x" + } +} diff --git a/truffle.js b/truffle.js new file mode 100644 index 0000000..ce35f33 --- /dev/null +++ b/truffle.js @@ -0,0 +1,53 @@ +require('dotenv').config(); +const HDWalletProvider = require('truffle-hdwallet-provider'); + +module.exports = { + networks: { + development: { + host: "127.0.0.1", + port: 8545, + network_id: "*", + }, + rinkeby: { + provider: () => new HDWalletProvider(process.env.MNEMONIC, "https://rinkeby.infura.io/v3/" + process.env.INFURA_PID), + network_id: 4, + confirmations: 1, + timeoutBlocks: 10, + skipDryRun: true, + production: false, + }, + mainnet: { + provider: () => new HDWalletProvider(process.env.MNEMONIC, "https://mainnet.infura.io/v3/" + process.env.INFURA_PID), + network_id: 1, + confirmations: 3, + timeoutBlocks: 30, + skipDryRun: false, + production: true, + gasPrice: 150000000000 // 150 gwei + }, + }, + mocha: { + reporter: "eth-gas-reporter", + reporterOptions: { + currency: "USD", + gasPrice: 2, + }, + }, + compilers: { + solc: { + version: "^0.8.0", + } + }, + solc: { + optimizer: { + enabled: true, + runs: 200 + } + }, + plugins: [ + 'truffle-plugin-verify' + ], + api_keys: { + 'etherscan': process.env.ETHERSCAN_API + } +};