From 9622bcf41f1fd673d3d725d62e477327f04ba238 Mon Sep 17 00:00:00 2001 From: Taraka Prabhu Date: Sat, 25 Jun 2022 21:03:02 +0400 Subject: [PATCH 01/34] NFTGame1 - Initial Commit --- .../.azure/.deployment | 2 + .../hyperverse-evm-nftgame1/.azure/deploy.sh | 122 ++++ packages/hyperverse-evm-nftgame1/.gitignore | 10 + .../.storybook/.babelrc | 4 + .../.storybook/main.js | 23 + .../.storybook/manager.js | 14 + .../.storybook/middleware.js | 46 ++ .../.storybook/preview.js | 14 + packages/hyperverse-evm-nftgame1/CHANGELOG.md | 83 +++ packages/hyperverse-evm-nftgame1/README.md | 33 + .../hyperverse-evm-nftgame1/contracts.json | 44 ++ .../contracts/NFTGame1.sol | 681 ++++++++++++++++++ .../contracts/NFTGame1Factory.sol | 94 +++ .../contracts/helper/ERC165.sol | 29 + .../contracts/helper/ReentrancyGuard.sol | 63 ++ .../contracts/hyperverse/CloneFactory.sol | 52 ++ .../hyperverse/IHyperverseModule.sol | 34 + .../contracts/hyperverse/Initializable.sol | 149 ++++ .../contracts/interface/IERC165.sol | 25 + .../contracts/interface/IERC20.sol | 82 +++ .../contracts/interface/IERC721.sol | 143 ++++ .../contracts/interface/IERC721Metadata.sol | 27 + .../contracts/interface/IERC721Receiver.sol | 27 + .../contracts/utils/Address.sol | 226 ++++++ .../contracts/utils/Context.sol | 24 + .../contracts/utils/Counters.sol | 42 ++ .../contracts/utils/SafeMath.sol | 227 ++++++ .../contracts/utils/Strings.sol | 75 ++ .../hyperverse-evm-nftgame1/docs/approve.md | 85 +++ .../hyperverse-evm-nftgame1/docs/approve.mdx | 4 + .../docs/getBalanceOf.md | 86 +++ .../docs/getBalanceOf.mdx | 4 + .../docs/getOwnerOf.md | 84 +++ .../docs/getOwnerOf.mdx | 4 + packages/hyperverse-evm-nftgame1/docs/mint.md | 84 +++ .../hyperverse-evm-nftgame1/docs/mint.mdx | 4 + .../docs/newInstance.md | 89 +++ .../docs/newInstance.mdx | 4 + .../docs/setApprovalForAll.md | 85 +++ .../docs/setApprovalForAll.mdx | 4 + .../docs/togglePublicMint.md | 81 +++ .../docs/togglePublicMint.mdx | 4 + .../hyperverse-evm-nftgame1/docs/transfer.md | 59 ++ .../hyperverse-evm-nftgame1/docs/transfer.mdx | 4 + .../hyperverse-evm-nftgame1/hardhat.config.js | 45 ++ packages/hyperverse-evm-nftgame1/index.ts | 2 + packages/hyperverse-evm-nftgame1/package.json | 86 +++ .../scripts/deploy-test.js | 24 + .../hyperverse-evm-nftgame1/scripts/deploy.js | 66 ++ .../scripts/sample-script.js | 42 ++ .../hyperverse-evm-nftgame1/scripts/test.js | 32 + .../source/Provider.tsx | 12 + .../source/environment.ts | 39 + .../hyperverse-evm-nftgame1/source/index.ts | 10 + .../source/nftGame1Library.ts | 212 ++++++ .../source/useERC721.ts | 41 ++ .../stories/Introduction.stories.mdx | 264 +++++++ .../stories/Stories.stories.mdx | 321 +++++++++ .../stories/approve.stories.tsx | 27 + .../stories/approve.tsx | 24 + .../stories/assets/code-brackets.svg | 1 + .../stories/assets/colors.svg | 1 + .../stories/assets/comments.svg | 1 + .../stories/assets/direction.svg | 1 + .../stories/assets/discord-logo.svg | 10 + .../stories/assets/flow.svg | 1 + .../stories/assets/github-logo.png | Bin 0 -> 4044 bytes .../stories/assets/hyperverse-logo.png | Bin 0 -> 56716 bytes .../stories/assets/plugin.svg | 1 + .../stories/assets/repo.svg | 1 + .../stories/assets/stackalt.svg | 1 + .../stories/assets/storybook-logo.svg | 1 + .../stories/getBalanceOf.stories.tsx | 26 + .../stories/getBalanceOf.tsx | 25 + .../stories/getOwnerOf.stories.tsx | 26 + .../stories/getOwnerOf.tsx | 25 + .../stories/header.css | 32 + .../stories/mint.stories.tsx | 26 + .../hyperverse-evm-nftgame1/stories/mint.tsx | 24 + .../stories/newInstance.stories.tsx | 24 + .../stories/newInstance.tsx | 24 + .../stories/setApprovalForAll.stories.tsx | 27 + .../stories/setApprovalForAll.tsx | 24 + .../hyperverse-evm-nftgame1/stories/style.css | 41 ++ .../stories/togglePublicMint.stories.tsx | 24 + .../stories/togglePublicMint.tsx | 24 + .../stories/transfer.stories.tsx | 28 + .../stories/transfer.tsx | 24 + .../stories/utils/Provider.tsx | 36 + .../stories/utils/ShowDocs.tsx | 104 +++ .../test/sample-test.js | 48 ++ .../hyperverse-evm-nftgame1/tsconfig.json | 9 + 92 files changed, 4967 insertions(+) create mode 100644 packages/hyperverse-evm-nftgame1/.azure/.deployment create mode 100644 packages/hyperverse-evm-nftgame1/.azure/deploy.sh create mode 100644 packages/hyperverse-evm-nftgame1/.gitignore create mode 100644 packages/hyperverse-evm-nftgame1/.storybook/.babelrc create mode 100644 packages/hyperverse-evm-nftgame1/.storybook/main.js create mode 100644 packages/hyperverse-evm-nftgame1/.storybook/manager.js create mode 100644 packages/hyperverse-evm-nftgame1/.storybook/middleware.js create mode 100644 packages/hyperverse-evm-nftgame1/.storybook/preview.js create mode 100644 packages/hyperverse-evm-nftgame1/CHANGELOG.md create mode 100644 packages/hyperverse-evm-nftgame1/README.md create mode 100644 packages/hyperverse-evm-nftgame1/contracts.json create mode 100644 packages/hyperverse-evm-nftgame1/contracts/NFTGame1.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/NFTGame1Factory.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/helper/ERC165.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/helper/ReentrancyGuard.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/hyperverse/CloneFactory.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/hyperverse/IHyperverseModule.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/hyperverse/Initializable.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/interface/IERC165.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/interface/IERC20.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/interface/IERC721.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/interface/IERC721Metadata.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/interface/IERC721Receiver.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/utils/Address.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/utils/Context.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/utils/Counters.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/utils/SafeMath.sol create mode 100644 packages/hyperverse-evm-nftgame1/contracts/utils/Strings.sol create mode 100644 packages/hyperverse-evm-nftgame1/docs/approve.md create mode 100644 packages/hyperverse-evm-nftgame1/docs/approve.mdx create mode 100644 packages/hyperverse-evm-nftgame1/docs/getBalanceOf.md create mode 100644 packages/hyperverse-evm-nftgame1/docs/getBalanceOf.mdx create mode 100644 packages/hyperverse-evm-nftgame1/docs/getOwnerOf.md create mode 100644 packages/hyperverse-evm-nftgame1/docs/getOwnerOf.mdx create mode 100644 packages/hyperverse-evm-nftgame1/docs/mint.md create mode 100644 packages/hyperverse-evm-nftgame1/docs/mint.mdx create mode 100644 packages/hyperverse-evm-nftgame1/docs/newInstance.md create mode 100644 packages/hyperverse-evm-nftgame1/docs/newInstance.mdx create mode 100644 packages/hyperverse-evm-nftgame1/docs/setApprovalForAll.md create mode 100644 packages/hyperverse-evm-nftgame1/docs/setApprovalForAll.mdx create mode 100644 packages/hyperverse-evm-nftgame1/docs/togglePublicMint.md create mode 100644 packages/hyperverse-evm-nftgame1/docs/togglePublicMint.mdx create mode 100644 packages/hyperverse-evm-nftgame1/docs/transfer.md create mode 100644 packages/hyperverse-evm-nftgame1/docs/transfer.mdx create mode 100644 packages/hyperverse-evm-nftgame1/hardhat.config.js create mode 100644 packages/hyperverse-evm-nftgame1/index.ts create mode 100644 packages/hyperverse-evm-nftgame1/package.json create mode 100644 packages/hyperverse-evm-nftgame1/scripts/deploy-test.js create mode 100644 packages/hyperverse-evm-nftgame1/scripts/deploy.js create mode 100644 packages/hyperverse-evm-nftgame1/scripts/sample-script.js create mode 100644 packages/hyperverse-evm-nftgame1/scripts/test.js create mode 100644 packages/hyperverse-evm-nftgame1/source/Provider.tsx create mode 100644 packages/hyperverse-evm-nftgame1/source/environment.ts create mode 100644 packages/hyperverse-evm-nftgame1/source/index.ts create mode 100644 packages/hyperverse-evm-nftgame1/source/nftGame1Library.ts create mode 100644 packages/hyperverse-evm-nftgame1/source/useERC721.ts create mode 100644 packages/hyperverse-evm-nftgame1/stories/Introduction.stories.mdx create mode 100644 packages/hyperverse-evm-nftgame1/stories/Stories.stories.mdx create mode 100644 packages/hyperverse-evm-nftgame1/stories/approve.stories.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/approve.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/assets/code-brackets.svg create mode 100644 packages/hyperverse-evm-nftgame1/stories/assets/colors.svg create mode 100644 packages/hyperverse-evm-nftgame1/stories/assets/comments.svg create mode 100644 packages/hyperverse-evm-nftgame1/stories/assets/direction.svg create mode 100644 packages/hyperverse-evm-nftgame1/stories/assets/discord-logo.svg create mode 100644 packages/hyperverse-evm-nftgame1/stories/assets/flow.svg create mode 100644 packages/hyperverse-evm-nftgame1/stories/assets/github-logo.png create mode 100644 packages/hyperverse-evm-nftgame1/stories/assets/hyperverse-logo.png create mode 100644 packages/hyperverse-evm-nftgame1/stories/assets/plugin.svg create mode 100644 packages/hyperverse-evm-nftgame1/stories/assets/repo.svg create mode 100644 packages/hyperverse-evm-nftgame1/stories/assets/stackalt.svg create mode 100644 packages/hyperverse-evm-nftgame1/stories/assets/storybook-logo.svg create mode 100644 packages/hyperverse-evm-nftgame1/stories/getBalanceOf.stories.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/getBalanceOf.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/getOwnerOf.stories.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/getOwnerOf.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/header.css create mode 100644 packages/hyperverse-evm-nftgame1/stories/mint.stories.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/mint.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/newInstance.stories.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/newInstance.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/setApprovalForAll.stories.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/setApprovalForAll.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/style.css create mode 100644 packages/hyperverse-evm-nftgame1/stories/togglePublicMint.stories.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/togglePublicMint.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/transfer.stories.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/transfer.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/utils/Provider.tsx create mode 100644 packages/hyperverse-evm-nftgame1/stories/utils/ShowDocs.tsx create mode 100644 packages/hyperverse-evm-nftgame1/test/sample-test.js create mode 100644 packages/hyperverse-evm-nftgame1/tsconfig.json diff --git a/packages/hyperverse-evm-nftgame1/.azure/.deployment b/packages/hyperverse-evm-nftgame1/.azure/.deployment new file mode 100644 index 00000000..1e42f16c --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/.azure/.deployment @@ -0,0 +1,2 @@ +[config] +command = bash deploy.sh \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/.azure/deploy.sh b/packages/hyperverse-evm-nftgame1/.azure/deploy.sh new file mode 100644 index 00000000..ae09a9a7 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/.azure/deploy.sh @@ -0,0 +1,122 @@ +#!/bin/bash + +# ---------------------- +# KUDU Deployment Script +# Version: 1.0.17 +# ---------------------- + +# Helpers +# ------- + +exitWithMessageOnError () { + if [ ! $? -eq 0 ]; then + echo "An error has occurred during web site deployment." + echo $1 + exit 1 + fi +} + +# Prerequisites +# ------------- + +# Verify node.js installed +hash node 2>/dev/null +exitWithMessageOnError "Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment." + +# Setup +# ----- + +SCRIPT_DIR="${BASH_SOURCE[0]%\\*}" +SCRIPT_DIR="${SCRIPT_DIR%/*}" +ARTIFACTS=$SCRIPT_DIR/../artifacts +KUDU_SYNC_CMD=${KUDU_SYNC_CMD//\"} +DEPLOYMENT_TARGET="d:\\home\\site\\wwwroot\\nftGame1-storybook" +if [[ ! -n "$DEPLOYMENT_SOURCE" ]]; then + DEPLOYMENT_SOURCE=$SCRIPT_DIR +fi + +if [[ ! -n "$NEXT_MANIFEST_PATH" ]]; then + NEXT_MANIFEST_PATH=$ARTIFACTS/manifest + + if [[ ! -n "$PREVIOUS_MANIFEST_PATH" ]]; then + PREVIOUS_MANIFEST_PATH=$NEXT_MANIFEST_PATH + fi +fi + +if [[ ! -n "$DEPLOYMENT_TARGET" ]]; then + DEPLOYMENT_TARGET=$ARTIFACTS/wwwroot +else + KUDU_SERVICE=true +fi + +if [[ ! -n "$KUDU_SYNC_CMD" ]]; then + # Install kudu sync + echo Installing Kudu Sync + npm install kudusync -g --silent + exitWithMessageOnError "npm failed" + + if [[ ! -n "$KUDU_SERVICE" ]]; then + # In case we are running locally this is the correct location of kuduSync + KUDU_SYNC_CMD=kuduSync + else + # In case we are running on kudu service this is the correct location of kuduSync + KUDU_SYNC_CMD=$APPDATA/npm/node_modules/kuduSync/bin/kuduSync + fi +fi + +# Node Helpers +# ------------ + +selectNodeVersion () { + if [[ -n "$KUDU_SELECT_NODE_VERSION_CMD" ]]; then + SELECT_NODE_VERSION="$KUDU_SELECT_NODE_VERSION_CMD \"$DEPLOYMENT_SOURCE\" \"$DEPLOYMENT_TARGET\" \"$DEPLOYMENT_TEMP\"" + eval $SELECT_NODE_VERSION + exitWithMessageOnError "select node version failed" + + if [[ -e "$DEPLOYMENT_TEMP/__nodeVersion.tmp" ]]; then + NODE_EXE=`cat "$DEPLOYMENT_TEMP/__nodeVersion.tmp"` + exitWithMessageOnError "getting node version failed" + fi + + if [[ -e "$DEPLOYMENT_TEMP/__npmVersion.tmp" ]]; then + NPM_JS_PATH=`cat "$DEPLOYMENT_TEMP/__npmVersion.tmp"` + exitWithMessageOnError "getting npm version failed" + fi + + if [[ ! -n "$NODE_EXE" ]]; then + NODE_EXE=node + fi + + NPM_CMD="\"$NODE_EXE\" \"$NPM_JS_PATH\"" + else + NPM_CMD=npm + NODE_EXE=node + fi +} + +################################################################################################################################## +# Deployment +# ---------- + +echo Handling node.js deployment. + +# 1. KuduSync +if [[ "$IN_PLACE_DEPLOYMENT" -ne "1" ]]; then + "$KUDU_SYNC_CMD" -v 50 -f "$DEPLOYMENT_SOURCE" -t "$DEPLOYMENT_TARGET" -n "$NEXT_MANIFEST_PATH" -p "$PREVIOUS_MANIFEST_PATH" -i ".git;.hg;.deployment;deploy.sh" + exitWithMessageOnError "Kudu Sync failed" +fi + +# 2. Select node version +selectNodeVersion + +# 3. Install npm packages +if [ -e "$DEPLOYMENT_TARGET/package.json" ]; then + cd "$DEPLOYMENT_TARGET" + echo "Running $NPM_CMD install --production" + eval $NPM_CMD install --production + exitWithMessageOnError "npm failed" + cd - > /dev/null +fi + +################################################################################################################################## +echo "Finished successfully." diff --git a/packages/hyperverse-evm-nftgame1/.gitignore b/packages/hyperverse-evm-nftgame1/.gitignore new file mode 100644 index 00000000..14ccdfb0 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/.gitignore @@ -0,0 +1,10 @@ +node_modules +.env +coverage +coverage.json +typechain +distribution + +#Hardhat files +cache +artifacts diff --git a/packages/hyperverse-evm-nftgame1/.storybook/.babelrc b/packages/hyperverse-evm-nftgame1/.storybook/.babelrc new file mode 100644 index 00000000..01cdf03a --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/.storybook/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["@babel/preset-typescript", "@babel/preset-react"], + "plugins": ["react-require"] +} diff --git a/packages/hyperverse-evm-nftgame1/.storybook/main.js b/packages/hyperverse-evm-nftgame1/.storybook/main.js new file mode 100644 index 00000000..9c4c0083 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/.storybook/main.js @@ -0,0 +1,23 @@ +module.exports = { + core: { + builder: 'webpack5' + }, + stories: [ + "../stories/**/*.stories.mdx", + '../stories/**/*.stories.@(js|jsx|ts|tsx)', + ], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-interactions', + ], + framework: '@storybook/react', + webpackFinal: async (config) => { + config.module.rules.push({ + test: /\.mjs$/, + include: /node_modules/, + type: 'javascript/auto', + }); + return config; + }, +}; diff --git a/packages/hyperverse-evm-nftgame1/.storybook/manager.js b/packages/hyperverse-evm-nftgame1/.storybook/manager.js new file mode 100644 index 00000000..087be719 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/.storybook/manager.js @@ -0,0 +1,14 @@ +import { addons } from '@storybook/addons'; +import { themes } from '@storybook/theming'; +import { create } from '@storybook/theming'; + +const theme = create({ + base: 'light', + brandTitle: 'Hyperverse-EVM-NFTGame1', + brandUrl: 'https://www.decentology.com', + brandImage: 'https://drive.google.com/uc?export=view&id=1gi_Ni_r1xQqrLRVlVVfXVvEEj-THLrq1', +}); + +addons.setConfig({ + theme, +}); diff --git a/packages/hyperverse-evm-nftgame1/.storybook/middleware.js b/packages/hyperverse-evm-nftgame1/.storybook/middleware.js new file mode 100644 index 00000000..108e7ec6 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/.storybook/middleware.js @@ -0,0 +1,46 @@ +const { createProxyMiddleware } = require('http-proxy-middleware'); +const hardhat = require('hardhat'); +const { join } = require('path'); +const waitOn = require('wait-on'); +const watch = require('node-watch'); +const path = require('path'); +const { spawn } = require('child_process'); +hardhat.hardhatArguments.network = 'localhost'; +const node = hardhat.run('node'); + +waitOn({ resources: [hardhat.config.networks['localhost'].url] }).then(deploy); +watch(path.join(__dirname, '../contracts'), { recursive: true }, deploy); + +function deploy() { + try { + const deployer = spawn( + 'hardhat', + ['run', join(__dirname, '../scripts/deploy.js'), '--network', 'localhost'], + { + shell: true, + env: { + ...process.env, + LOCALDEPLOY: true, + }, + stdio: 'inherit', + } + ); + deployer.stderr.on('data', (data) => { + console.error(data.toString()); + }); + deployer.stdio.on('data', (data) => { + console.log(data.toString()); + }); + } catch (error) {} +} + +module.exports = (router) => { + router.use( + '/hyperchain', + createProxyMiddleware({ + target: hardhat.config.networks['localhost'].url, + changeOrigin: true, + followRedirects: true, + }) + ); +}; diff --git a/packages/hyperverse-evm-nftgame1/.storybook/preview.js b/packages/hyperverse-evm-nftgame1/.storybook/preview.js new file mode 100644 index 00000000..c5a6f967 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/.storybook/preview.js @@ -0,0 +1,14 @@ +import { themes } from "@storybook/theming"; +import React from "react"; +global.React = React; + +export const parameters = { + actions: { argTypesRegex: "^on[A-Z].*" }, + layout: "centered", + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, +}; diff --git a/packages/hyperverse-evm-nftgame1/CHANGELOG.md b/packages/hyperverse-evm-nftgame1/CHANGELOG.md new file mode 100644 index 00000000..fd10fde1 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/CHANGELOG.md @@ -0,0 +1,83 @@ +# @decentology/hyperverse-ethereum-nftgame1 + +## 1.0.8 + +### Patch Changes + +- Update deployment for ESM modules. +- Updated dependencies + - @decentology/hyperverse@1.0.17 + - @decentology/hyperverse-evm@1.0.17 + +## 1.0.7 + +### Patch Changes + +- Milestone version +- Updated dependencies + - @decentology/hyperverse@1.0.15 + - @decentology/hyperverse-evm@1.0.15 + - @decentology/unstated-next@1.1.9 + +## 1.0.6 + +### Patch Changes + +- Updated dependencies + - @decentology/hyperverse@1.0.14 + - @decentology/hyperverse-evm@1.0.14 + - @decentology/hyperverse-storage-skynet@1.0.13 + - @decentology/unstated-next@1.1.8 + +## 1.0.5 + +### Patch Changes + +- Updated dependencies + - @decentology/hyperverse@1.0.13 + - @decentology/hyperverse-evm@1.0.13 + - @decentology/unstated-next@1.1.7 + - @decentology/hyperverse-storage-skynet@1.0.12 + +## 1.0.4 + +### Patch Changes + +- Updated dependencies + - @decentology/hyperverse@1.0.12 + - @decentology/hyperverse-evm@1.0.12 + - @decentology/unstated-next@1.1.6 + - @decentology/hyperverse-storage-skynet@1.0.11 + +## 1.0.3 + +### Patch Changes + +- milestone update +- Updated dependencies + - @decentology/hyperverse@1.0.11 + - @decentology/hyperverse-evm@1.0.11 + - @decentology/hyperverse-storage-skynet@1.0.10 + - @decentology/unstated-next@1.1.5 + +## 1.0.2 + +### Patch Changes + +- Milestone. Version bump +- Updated dependencies + - @decentology/hyperverse@1.0.10 + - @decentology/hyperverse-evm@1.0.10 + - @decentology/hyperverse-storage-skynet@1.0.9 + - @decentology/unstated-next@1.1.3 + +## 1.0.1 + +### Patch Changes + +- Milestone update. Added token and er721 modules +- Updated dependencies + - @decentology/unstated-next@1.1.1 + - @decentology/hyperverse@1.0.9 + - @decentology/hyperverse-ethereum@1.0.9 + - @decentology/hyperverse-storage-skynet@1.0.8 diff --git a/packages/hyperverse-evm-nftgame1/README.md b/packages/hyperverse-evm-nftgame1/README.md new file mode 100644 index 00000000..f3ae692b --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/README.md @@ -0,0 +1,33 @@ + +

+Hyperverse logo +

+ +# Hyperverse EVM Builderkit + +This is a initial scaffold project to assit with building a smart module for the Hypervers + +## How the project is setup + +1. `Contracts` - This is the first layer. Think of this as your database model and repository for how to fetch and store data +2. `Source` - Contains your javascript interface to your contracts. +3. `Stories` - This is your UI inteterface to your smart module that allows for documentating and testing the functionality of your smarat module + + +## Contracts +Modules are primarily written in `solidity`. They utilize the `hardat` framework to assit in the compilation and deploying of your contracts + +## Source +The javascript source connects to the smart module using `ethers` by default. The format of a Hyperverse smart module is broken down into further sub sections + +1. `Library` - Lib folder contains the detailed functions that read & write to the blockchain. +2. `useHook` - React hook that exposes your library to the react ecosystem. You'll want to rename this export to better help identify your module +3. `Provider` - Hyperverse modules use the React Context to expose state to child components +4. `Environment` - Simple component that will identify which blockchain and network your module is being used under. This allows EVM modules to easily work with any supported EVM module + + +# Documentation +For more information and learn about Hyperverse checkout the resources below + +- [Hyperverse Documentation](https://docs.hyperverse.dev/) +- [Decentology YouTube Channel](https://www.youtube.com/c/Decentology) diff --git a/packages/hyperverse-evm-nftgame1/contracts.json b/packages/hyperverse-evm-nftgame1/contracts.json new file mode 100644 index 00000000..dee11a26 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts.json @@ -0,0 +1,44 @@ +{ + "metis": { + "testnet": { + "contractAddress": "0x4Ad8135D5d1a94c8aA3EbF753b3014e8f9663290", + "factoryAddress": "0x7037E17e7D17980f20d7b88FdF241b4E78E7d50d" + }, + "mainnet": {} + }, + "avalanche": { + "testnet": { + "contractAddress": "0x296a744F4716f237F5aD92e1BFE709725C28337C", + "factoryAddress": "0xC0257126e148AE62E0D5Bd15553e720Ca7DE6dFf" + }, + "mainnet": {} + }, + "ethereum": { + "testnet": { + "contractAddress": "0xbda251C8be7AeF3846f44eBb6c28349FFaA77b07", + "factoryAddress": "0xdc27A92D7432a30CAb36903a74531E346BcC0b14" + }, + "mainnet": {} + }, + "polygon": { + "testnet": { + "contractAddress": "0xB872bba890D7D2F555f68b078CcbE9E40DA2b3cd", + "factoryAddress": "0x1F7c352ccF96974dC696b693b54E90248ce7A6D0" + }, + "mainnet": {} + }, + "localhost": { + "testnet": { + "contractAddress": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "factoryAddress": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" + }, + "mainnet": {} + }, + "hardhat": { + "testnet": { + "contractAddress": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "factoryAddress": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" + }, + "mainnet": {} + } +} diff --git a/packages/hyperverse-evm-nftgame1/contracts/NFTGame1.sol b/packages/hyperverse-evm-nftgame1/contracts/NFTGame1.sol new file mode 100644 index 00000000..cb0f47bc --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/NFTGame1.sol @@ -0,0 +1,681 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +pragma experimental ABIEncoderV2; + +import './hyperverse/IHyperverseModule.sol'; +import './hyperverse/Initializable.sol'; +import './utils/Counters.sol'; +import './utils/Strings.sol'; +import './utils/Address.sol'; +import './utils/Context.sol'; +import './helper/ERC165.sol'; +import './helper/ReentrancyGuard.sol'; + +import './interface/IERC721Metadata.sol'; +import './interface/IERC721.sol'; +import './interface/IERC721Receiver.sol'; +import './interface/IERC20.sol'; + +contract NFTGame1 is + Context, + ERC165, + IERC721, + IERC721Metadata, + ReentrancyGuard, + Initializable, + IHyperverseModule +{ + using Counters for Counters.Counter; + using Strings for uint256; + using Address for address; + + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ S T A T E @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + struct CollectionInfo { + uint256 price; + uint256 maxSupply; + uint256 maxPerUser; + bool isPublicSaleActive; + } + address public immutable contractOwner; + + address public _tenantOwner; + + Counters.Counter private tokenCounter; + + string private _name; + string private _symbol; + string private baseURI; + bool public isPublicSaleActive; + + bool private _isCollection; // true if contract is an NFT collection + CollectionInfo public _collectionInfo; + + mapping(uint256 => address) private _owners; + mapping(address => uint256) private _balances; + mapping(uint256 => address) private _tokenApprovals; + mapping(address => mapping(address => bool)) private _operatorApprovals; + + // Mapping for individual token URIs + mapping(uint256 => string) internal _tokenURIs; + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ E V E N T S @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + ///+events + + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ E R R O R S @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + error Unauthorized(); + error AlreadyInitialized(); + error ZeroAddress(); + error SameAddress(); + error InsufficientBalance(); + error InsufficientAllowance(); + error PublicMintInactive(); + error InvalidTokenId(); + error MissingERC721Receiver(); + error TokenAlreadyMinted(); + error IncorrectOwner(); + error SameOwnerAndOperator(); + error NotACollection(); + error MaxSupplyExceeded(); + error MaxPerUserExceeded(); + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ M O D I F I E R S @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + ///+modifiers + modifier isTenantOwner() { + if (msg.sender != _tenantOwner) { + revert Unauthorized(); + } + _; + } + + modifier canInitialize(address _tenant) { + if (_tenantOwner != address(0)) { + revert AlreadyInitialized(); + } + _; + } + + modifier mintCheck(uint256 _count) { + if (_isCollection == true) { + if (_collectionInfo.isPublicSaleActive == false) { + revert PublicMintInactive(); + } + + if ( + tokenCounter.current() > _collectionInfo.maxSupply || + tokenCounter.current() + _count > _collectionInfo.maxSupply + ) { + revert MaxSupplyExceeded(); + } + + if (msg.value * _count != _collectionInfo.price * _count) { + revert InsufficientBalance(); + } + + if (balanceOf(msg.sender) + _count > _collectionInfo.maxPerUser) { + revert MaxPerUserExceeded(); + } + } else { + if (isPublicSaleActive == false) { + revert PublicMintInactive(); + } + _; + } + _; + } + + /** + * @dev Checks functionlaities that are specific for ERC721 collections + */ + modifier isCollection() { + if (_isCollection == false) { + revert NotACollection(); + } + _; + } + + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ C O N S T R U C T O R @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + constructor(address _owner) { + metadata = ModuleMetadata( + 'NFTGame1', + Author(_owner, 'https://externallink.net'), + '0.0.1', + 3479831479814, + 'https://externalLink.net' + ); + contractOwner = _owner; + } + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + function initialize( + string memory name_, + string memory symbol_, + string memory instanceBaseURI_, + address tenant_ + ) external initializer canInitialize(tenant_) { + _name = name_; + _symbol = symbol_; + _tenantOwner = tenant_; + baseURI = instanceBaseURI_; + } + + /** + * @dev used for public minting of tokens for collection types. + */ + function mint(address _to) external payable nonReentrant mintCheck(1) returns (uint256) { + uint256 tokenId = nextTokenId(); + _safeMint(_to, tokenId); + return tokenId; + } + + function mintBatch(address _to, uint256 _count) + external + payable + nonReentrant + mintCheck(_count) + returns (uint256[] memory) + { + uint256[] memory tokenIds = new uint256[](_count); + for (uint256 i = 0; i < _count; i++) { + uint256 tokenId = nextTokenId(); + tokenIds[i] = tokenId; + _safeMint(_to, tokenId); + } + return tokenIds; + } + + function getBaseURI() public view returns (string memory) { + return bytes(baseURI).length > 0 ? baseURI : ""; + } + + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ T E N A N T F U N C T I O N S @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + function initializeCollection( + uint256 _price, + uint256 _maxSupply, + uint256 _maxPerUser + ) external isTenantOwner { + _collectionInfo.price = _price; + _collectionInfo.maxSupply = _maxSupply; + _collectionInfo.maxPerUser = _maxPerUser; + _isCollection = true; + } + + /** + * @dev tenant ownly minting function, used to mint a token with a tokenURI based on the baseURI and the tokenID + * use case: Collection Minting + */ + function tenantMint(address _reciever) external isTenantOwner isCollection returns (uint256) { + uint256 tokenId = nextTokenId(); + _safeMint(_reciever, tokenId); + return tokenId; + } + + /** + * @dev This minting function is used to mint a token with a the provided tokenURI + * use case: 1:1 NFTs + */ + function tenantMint(address _to, string calldata _uri) + external + isTenantOwner + returns (uint256) + { + uint256 tokenId = nextTokenId(); + _safeMint(_to, tokenId); + if (bytes(_uri).length > 0) { + _tokenURIs[tokenId] = _uri; + } + + return tokenId; + } + + // function setBaseURI(string memory baseURI_) external isTenantOwner { + // baseURI = baseURI_; + // } + + /** + * Can only set mint permissions if the contract is a collection + */ + function setMintPermissions(bool _isActive) external isTenantOwner { + if (_isCollection == true) { + _collectionInfo.isPublicSaleActive = _isActive; + } else { + isPublicSaleActive = _isActive; + } + } + + + function withdraw() public isTenantOwner { + uint256 balance = address(this).balance; + payable(msg.sender).transfer(balance); + } + + function withdrawTokens(IERC20 _token) public isTenantOwner { + uint256 balance = _token.balanceOf(address(this)); + _token.transfer(msg.sender, balance); + } + + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ H E L P E R F U N C T I O N S @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + function nextTokenId() private returns (uint256) { + tokenCounter.increment(); + return tokenCounter.current(); + } + + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ O V E R R I D E S @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 _tokenId) external view virtual override returns (string memory) { + _requireMinted(_tokenId); + + if (!_isCollection) { + return bytes(_tokenURIs[_tokenId]).length > 0 ? _tokenURIs[_tokenId] : ''; + } + + string memory baseURI_ = getBaseURI(); + return + bytes(baseURI_).length > 0 + ? string(abi.encodePacked(baseURI_, _tokenId.toString())) + : ''; + } + + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ E R C 7 2 1 M E T H O D S @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 _interfaceId) + public + view + virtual + override(ERC165, IERC165) + returns (bool) + { + return + _interfaceId == type(IERC721).interfaceId || + _interfaceId == type(IERC721Metadata).interfaceId || + super.supportsInterface(_interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address _owner) public view virtual override returns (uint256) { + if (_owner == address(0)) { + revert ZeroAddress(); + } + + return _balances[_owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 _tokenId) public view virtual override returns (address) { + address owner = _owners[_tokenId]; + if (owner == address(0)) { + revert InvalidTokenId(); + } + return owner; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ''; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address _to, uint256 _tokenId) public virtual override { + address owner = NFTGame1.ownerOf(_tokenId); + if (owner == _to) { + revert SameAddress(); + } + + if (_msgSender() != owner || !isApprovedForAll(owner, _msgSender())) { + revert Unauthorized(); + } + + _approve(_to, _tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 _tokenId) public view virtual override returns (address) { + _requireMinted(_tokenId); + + return _tokenApprovals[_tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address _operator, bool _approved) public virtual override { + _setApprovalForAll(_msgSender(), _operator, _approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address _owner, address _operator) + public + view + virtual + override + returns (bool) + { + return _operatorApprovals[_owner][_operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom( + address _from, + address _to, + uint256 _tokenId + ) public virtual override { + if (!(_isApprovedOrOwner(_msgSender(), _tokenId))) { + revert Unauthorized(); + } + + _transfer(_from, _to, _tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address _from, + address _to, + uint256 _tokenId + ) public virtual override { + safeTransferFrom(_from, _to, _tokenId, ''); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address _from, + address _to, + uint256 _tokenId, + bytes memory _data + ) public virtual override { + if (!(_isApprovedOrOwner(_msgSender(), _tokenId))) { + revert Unauthorized(); + } + + _safeTransfer(_from, _to, _tokenId, _data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + */ + function _safeTransfer( + address _from, + address _to, + uint256 _tokenId, + bytes memory _data + ) internal virtual { + _transfer(_from, _to, _tokenId); + + if (!_checkOnERC721Received(_from, _to, _tokenId, _data)) { + revert MissingERC721Receiver(); + } + } + + /** + * @dev Returns whether `tokenId` exists. + * + */ + function _exists(uint256 _tokenId) internal view virtual returns (bool) { + return _owners[_tokenId] != address(0); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + */ + function _isApprovedOrOwner(address _spender, uint256 _tokenId) + internal + view + virtual + returns (bool) + { + address owner = NFTGame1.ownerOf(_tokenId); + return (_spender == owner || + isApprovedForAll(owner, _spender) || + getApproved(_tokenId) == _spender); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + */ + function _safeMint(address _to, uint256 _tokenId) internal virtual { + _safeMint(_to, _tokenId, ''); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint( + address _to, + uint256 _tokenId, + bytes memory _data + ) internal virtual { + _mint(_to, _tokenId); + + if (!_checkOnERC721Received(address(0), _to, _tokenId, _data)) { + revert MissingERC721Receiver(); + } + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + */ + function _mint(address _to, uint256 _tokenId) internal virtual { + if (_to == address(0)) { + revert ZeroAddress(); + } + + if (_exists(_tokenId)) { + revert TokenAlreadyMinted(); + } + + _beforeTokenTransfer(address(0), _to, _tokenId); + + _balances[_to] += 1; + _owners[_tokenId] = _to; + + emit Transfer(address(0), _to, _tokenId); + + _afterTokenTransfer(address(0), _to, _tokenId); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + */ + function _burn(uint256 _tokenId) internal virtual { + address owner = NFTGame1.ownerOf(_tokenId); + + _beforeTokenTransfer(owner, address(0), _tokenId); + + // Clear approvals + _approve(address(0), _tokenId); + + _balances[owner] -= 1; + delete _owners[_tokenId]; + + emit Transfer(owner, address(0), _tokenId); + + _afterTokenTransfer(owner, address(0), _tokenId); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + */ + function _transfer( + address _from, + address _to, + uint256 _tokenId + ) internal virtual { + if (NFTGame1.ownerOf(_tokenId) != _from) { + revert IncorrectOwner(); + } + + if (_to == address(0)) { + revert ZeroAddress(); + } + _beforeTokenTransfer(_from, _to, _tokenId); + + // Clear approvals from the previous owner + _approve(address(0), _tokenId); + + _balances[_from] -= 1; + _balances[_to] += 1; + _owners[_tokenId] = _to; + + emit Transfer(_from, _to, _tokenId); + + _afterTokenTransfer(_from, _to, _tokenId); + } + + /** + * @dev Approve `to` to operate on `tokenId` + */ + function _approve(address _to, uint256 _tokenId) internal virtual { + _tokenApprovals[_tokenId] = _to; + emit Approval(NFTGame1.ownerOf(_tokenId), _to, _tokenId); + } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + */ + function _setApprovalForAll( + address _owner, + address _operator, + bool _approved + ) internal virtual { + if (_operator == address(0)) { + revert ZeroAddress(); + } + if (_owner == _operator) { + revert SameOwnerAndOperator(); + } + + _operatorApprovals[_owner][_operator] = _approved; + emit ApprovalForAll(_owner, _operator, _approved); + } + + /** + * @dev Reverts if the `tokenId` has not been minted yet. + */ + function _requireMinted(uint256 _tokenId) internal view virtual { + if (!_exists(_tokenId)) { + revert InvalidTokenId(); + } + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param _from address representing the previous owner of the given token ID + * @param _to target address that will receive the tokens + * @param _tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return _bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received( + address _from, + address _to, + uint256 _tokenId, + bytes memory _data + ) private returns (bool) { + if (_to.isContract()) { + try + IERC721Receiver(_to).onERC721Received(_msgSender(), _from, _tokenId, _data) + returns (bytes4 retval) { + return retval == IERC721Receiver.onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert MissingERC721Receiver(); + } else { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address _from, + address _to, + uint256 _tokenId + ) internal virtual {} + + /** + * @dev Hook that is called after any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer( + address _from, + address _to, + uint256 _tokenId + ) internal virtual {} +} diff --git a/packages/hyperverse-evm-nftgame1/contracts/NFTGame1Factory.sol b/packages/hyperverse-evm-nftgame1/contracts/NFTGame1Factory.sol new file mode 100644 index 00000000..a3a2e2c1 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/NFTGame1Factory.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +pragma experimental ABIEncoderV2; + +import './hyperverse/CloneFactory.sol'; +import './hyperverse/IHyperverseModule.sol'; +import './utils/Counters.sol'; +import './NFTGame1.sol'; + +/** + * @dev Clone Factory Implementation for ERC20 Token + */ + +contract NFTGame1Factory is CloneFactory { + using Counters for Counters.Counter; + + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ S T A T E @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + struct Tenant { + NFTGame1 nftGame1; + address owner; + } + + Counters.Counter public tenantCounter; + mapping(address => Tenant) public tenants; + mapping(address => bool) public instance; + + address public immutable owner; + address public immutable masterContract; + + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ E V E N T S @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + event TenantCreated(address _tenant, address _proxy); + + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ E R R O R S @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + error Unauthorized(); + error InstanceAlreadyInitialized(); + error InstanceDoesNotExist(); + error ZeroAddress(); + + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ M O D I F I E R S @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + modifier isAuthorized(address _tenant) { + if (_tenant == address(0)) { + revert ZeroAddress(); + } + if (!(msg.sender == _tenant || msg.sender == owner)) { + revert Unauthorized(); + } + _; + } + + modifier hasAnInstance(address _tenant) { + if (instance[_tenant]) { + revert InstanceAlreadyInitialized(); + } + _; + } + + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ C O N S T R U C T O R @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + constructor(address _masterContract, address _owner) { + masterContract = _masterContract; + owner = _owner; + } + + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ F U N C T I O N S @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + function createInstance( + address _tenant, + string memory _name, + string memory _symbol, + string memory _instanceBaseURI + ) external isAuthorized(_tenant) hasAnInstance(_tenant) { + NFTGame1 nftGame1 = NFTGame1(createClone(masterContract)); + + //initializing tenant state of clone + nftGame1.initialize(_name, _symbol, _instanceBaseURI, _tenant); + + //set Tenant data + Tenant storage newTenant = tenants[_tenant]; + newTenant.nftGame1 = nftGame1; + newTenant.owner = _tenant; + instance[_tenant] = true; + tenantCounter.increment(); + + emit TenantCreated(_tenant, address(nftGame1)); + } + + function getProxy(address _tenant) public view returns (NFTGame1) { + if (!instance[_tenant]) { + revert InstanceDoesNotExist(); + } + return tenants[_tenant].nftGame1; + } +} diff --git a/packages/hyperverse-evm-nftgame1/contracts/helper/ERC165.sol b/packages/hyperverse-evm-nftgame1/contracts/helper/ERC165.sol new file mode 100644 index 00000000..311d4466 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/helper/ERC165.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + +pragma solidity ^0.8.0; + +import "../interface/IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/helper/ReentrancyGuard.sol b/packages/hyperverse-evm-nftgame1/contracts/helper/ReentrancyGuard.sol new file mode 100644 index 00000000..9246a73d --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/helper/ReentrancyGuard.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor() { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and making it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/hyperverse/CloneFactory.sol b/packages/hyperverse-evm-nftgame1/contracts/hyperverse/CloneFactory.sol new file mode 100644 index 00000000..e925bce4 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/hyperverse/CloneFactory.sol @@ -0,0 +1,52 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/* +The MIT License (MIT) +Copyright (c) 2018 Murray Software, LLC. +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +//solhint-disable max-line-length +//solhint-disable no-inline-assembly + +contract CloneFactory { + function createClone(address target) internal returns (address result) { + bytes20 targetBytes = bytes20(target); + assembly { + let clone := mload(0x40) + mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) + mstore(add(clone, 0x14), targetBytes) + mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) + result := create(0, clone, 0x37) + } + } + + function isClone(address target, address query) internal view returns (bool result) { + bytes20 targetBytes = bytes20(target); + assembly { + let clone := mload(0x40) + mstore(clone, 0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000) + mstore(add(clone, 0xa), targetBytes) + mstore(add(clone, 0x1e), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) + + let other := add(clone, 0x40) + extcodecopy(query, other, 0, 0x2d) + result := and(eq(mload(clone), mload(other)), eq(mload(add(clone, 0xd)), mload(add(other, 0xd)))) + } + } +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/hyperverse/IHyperverseModule.sol b/packages/hyperverse-evm-nftgame1/contracts/hyperverse/IHyperverseModule.sol new file mode 100644 index 00000000..7dc01190 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/hyperverse/IHyperverseModule.sol @@ -0,0 +1,34 @@ +/** + +## The Decentology Smart Module standard on Ethereum + +## `IHyperverseModule` interface + +In essense, this contract serves the equivalent of two purposes +in respect to Cadence: +1) Enforces the `metadata` variable (same as IHyperverseModule.cdc) +2) Defines what a ModuleMetadata is (sam as HyperverseModule.cdc) + +*/ + +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +abstract contract IHyperverseModule { + ModuleMetadata public metadata; + address private owner; + + struct ModuleMetadata { + bytes title; + Author author; + bytes version; + uint64 publishedAt; + bytes externalLink; + } + + struct Author { + address authorAddress; + string externalLink; + } +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/hyperverse/Initializable.sol b/packages/hyperverse-evm-nftgame1/contracts/hyperverse/Initializable.sol new file mode 100644 index 00000000..432f0efc --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/hyperverse/Initializable.sol @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol) + +pragma solidity ^0.8.2; + +import "../utils/Address.sol"; + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * For example: + * + * [.hljs-theme-light.nopadding] + * ``` + * contract MyToken is ERC20Upgradeable { + * function initialize() initializer public { + * __ERC20_init("MyToken", "MTK"); + * } + * } + * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { + * function initializeV2() reinitializer(2) public { + * __ERC20Permit_init("MyToken"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable { + /** + * @dev Indicates that the contract has been initialized. + * @custom:oz-retyped-from bool + */ + uint8 private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint8 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`. + */ + modifier initializer() { + bool isTopLevelCall = _setInitializedVersion(1); + if (isTopLevelCall) { + _initializing = true; + } + _; + if (isTopLevelCall) { + _initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original + * initialization step. This is essential to configure modules that are added through upgrades and that require + * initialization. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + */ + modifier reinitializer(uint8 version) { + bool isTopLevelCall = _setInitializedVersion(version); + if (isTopLevelCall) { + _initializing = true; + } + _; + if (isTopLevelCall) { + _initializing = false; + emit Initialized(version); + } + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + require(_initializing, "Initializable: contract is not initializing"); + _; + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + */ + function _disableInitializers() internal virtual { + _setInitializedVersion(type(uint8).max); + } + + function _setInitializedVersion(uint8 version) private returns (bool) { + // If the contract is initializing we ignore whether _initialized is set in order to support multiple + // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level + // of initializers, because in other contexts the contract may have been reentered. + if (_initializing) { + require( + version == 1 && !Address.isContract(address(this)), + "Initializable: contract is already initialized" + ); + return false; + } else { + require(_initialized < version, "Initializable: contract is already initialized"); + _initialized = version; + return true; + } + } +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/interface/IERC165.sol b/packages/hyperverse-evm-nftgame1/contracts/interface/IERC165.sol new file mode 100644 index 00000000..5fa65516 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/interface/IERC165.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/interface/IERC20.sol b/packages/hyperverse-evm-nftgame1/contracts/interface/IERC20.sol new file mode 100644 index 00000000..829618d6 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/interface/IERC20.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 amount + ) external returns (bool); +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/interface/IERC721.sol b/packages/hyperverse-evm-nftgame1/contracts/interface/IERC721.sol new file mode 100644 index 00000000..2d65e567 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/interface/IERC721.sol @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721.sol) + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/interface/IERC721Metadata.sol b/packages/hyperverse-evm-nftgame1/contracts/interface/IERC721Metadata.sol new file mode 100644 index 00000000..4af79194 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/interface/IERC721Metadata.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) + +pragma solidity ^0.8.0; + +import "./IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/interface/IERC721Receiver.sol b/packages/hyperverse-evm-nftgame1/contracts/interface/IERC721Receiver.sol new file mode 100644 index 00000000..2ff3e0e8 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/interface/IERC721Receiver.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) + +pragma solidity ^0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/utils/Address.sol b/packages/hyperverse-evm-nftgame1/contracts/utils/Address.sol new file mode 100644 index 00000000..8cc9c049 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/utils/Address.sol @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Address.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + assembly { + size := extcodesize(account) + } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/utils/Context.sol b/packages/hyperverse-evm-nftgame1/contracts/utils/Context.sol new file mode 100644 index 00000000..253659a9 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/utils/Context.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/utils/Counters.sol b/packages/hyperverse-evm-nftgame1/contracts/utils/Counters.sol new file mode 100644 index 00000000..c526b712 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/utils/Counters.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @title Counters + * @author Matt Condon (@shrugs) + * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number + * of elements in a mapping, issuing ERC721 ids, or counting request ids. + * + * Include with `using Counters for Counters.Counter;` + */ +library Counters { + struct Counter { + // This variable should never be directly accessed by users of the library: interactions must be restricted to + // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add + // this feature: see https://github.com/ethereum/solidity/issues/4637 + uint256 _value; // default: 0 + } + + function current(Counter storage counter) internal view returns (uint256) { + return counter._value; + } + + function increment(Counter storage counter) internal { + unchecked { + counter._value += 1; + } + } + + function decrement(Counter storage counter) internal { + uint256 value = counter._value; + require(value > 0, "Counter: decrement overflow"); + unchecked { + counter._value = value - 1; + } + } + + function reset(Counter storage counter) internal { + counter._value = 0; + } +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/utils/SafeMath.sol b/packages/hyperverse-evm-nftgame1/contracts/utils/SafeMath.sol new file mode 100644 index 00000000..6569088a --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/utils/SafeMath.sol @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol) + +pragma solidity ^0.8.0; + +// CAUTION +// This version of SafeMath should only be used with Solidity 0.8 or later, +// because it relies on the compiler's built in overflow checks. + +/** + * @dev Wrappers over Solidity's arithmetic operations. + * + * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler + * now has built in overflow checking. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the subtraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b > a) return (false, 0); + return (true, a - b); + } + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a / b); + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a % b); + } + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + return a + b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + return a * b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub( + uint256 a, + uint256 b, + string memory errorMessage + ) internal pure returns (uint256) { + unchecked { + require(b <= a, errorMessage); + return a - b; + } + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div( + uint256 a, + uint256 b, + string memory errorMessage + ) internal pure returns (uint256) { + unchecked { + require(b > 0, errorMessage); + return a / b; + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod( + uint256 a, + uint256 b, + string memory errorMessage + ) internal pure returns (uint256) { + unchecked { + require(b > 0, errorMessage); + return a % b; + } + } +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/contracts/utils/Strings.sol b/packages/hyperverse-evm-nftgame1/contracts/utils/Strings.sol new file mode 100644 index 00000000..e30c4105 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/contracts/utils/Strings.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) + +pragma solidity ^0.8.0; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; + uint8 private constant _ADDRESS_LENGTH = 20; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + if (value == 0) { + return "0x00"; + } + uint256 temp = value; + uint256 length = 0; + while (temp != 0) { + length++; + temp >>= 8; + } + return toHexString(value, length); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _HEX_SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); + } +} \ No newline at end of file diff --git a/packages/hyperverse-evm-nftgame1/docs/approve.md b/packages/hyperverse-evm-nftgame1/docs/approve.md new file mode 100644 index 00000000..90ceff07 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/approve.md @@ -0,0 +1,85 @@ +# Approve + +

The `approve` function from `nftGame1Library` sets approves the transfer of a token to another address.

+ +--- + +
+ +### approve + +

The `approve` function takes in the target address and the token Id.

+ +```jsx + const approve = async ({ to, tokenId }: { to: string; tokenId: number }) => { + try { + const approveTxn = await base.proxyContract?.approve(to, tokenId); + return approveTxn.wait() as TransactionReceipt; + } catch (error) { + throw error; + } + } +``` + +### Stories + +```jsx +import { Approve } from './approve'; +import { HyperverseProvider } from './utils/Provider'; +import React from 'react'; +import Doc from '../docs/approve.mdx'; + +export default { + title: 'Components/Approve', + component: Approve, + parameters: { + docs: { + page: Doc, + }, + }, +}; + +const Template = (args) => ( + + + +); + +export const Demo = Template.bind({}); + +Demo.args = { + to: '0x976EA74026E726554dB657fA54763abd0C3a0aa9', + tokenId: 1, +}; +``` + +### Main UI Component + +```jsx +import { useNFTGame1 } from '../source'; +import { useEvm } from '@decentology/hyperverse-evm'; +import './style.css'; + +export const Approve = ({ ...props }: { to: string, tokenId: number }) => { + const { approve } = useNFTGame1(); + const { address, Connect } = useEvm(); + + return ( + <> + + + + ); +}; +``` + +For more information about our modules please visit: [**Hyperverse Docs**](docs.hyperverse.dev) diff --git a/packages/hyperverse-evm-nftgame1/docs/approve.mdx b/packages/hyperverse-evm-nftgame1/docs/approve.mdx new file mode 100644 index 00000000..db0327c0 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/approve.mdx @@ -0,0 +1,4 @@ +import { Description } from '@storybook/addon-docs'; +import readme from './approve.md'; + +export default ; diff --git a/packages/hyperverse-evm-nftgame1/docs/getBalanceOf.md b/packages/hyperverse-evm-nftgame1/docs/getBalanceOf.md new file mode 100644 index 00000000..2983750c --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/getBalanceOf.md @@ -0,0 +1,86 @@ +# Get Balance Of + +

The `getBalanceOf` function from `nftGame1Library` returns the current available balance of a provided address.

+ +--- + +
+ +### getBalanceOf + +

The `getBalanceOf` function takes in an account.

+ +```jsx + const getBalanceOf = async (account: string) => { + try { + const balance = await base.proxyContract?.balanceOf(account); + return BigNumber.from(balance) as BigNumber; + } catch (error) { + throw error; + } + }; +``` + +### Stories + +```jsx +import { GetBalanceOf } from './getBalanceOf'; +import { HyperverseProvider } from './utils/Provider'; +import React from 'react'; +import Doc from '../docs/getBalanceOf.mdx'; + +export default { + title: 'Components/GetBalanceOf', + component: GetBalanceOf, + parameters: { + docs: { + page: Doc, + }, + }, +}; + +const Template = (args) => ( + + + +); + +export const Demo = Template.bind({}); + +Demo.args = { + account: '0x976EA74026E726554dB657fA54763abd0C3a0aa9' +}; +``` + +### Main UI Component + +```jsx +import { useNFTGame1 } from '../source'; +import { useEvm } from '@decentology/hyperverse-evm'; +import { useEffect, useState } from 'react'; + +export const GetBalanceOf = ({ ...props }: { account: string }) => { + const nftGame1 = useNFTGame1(); + const { address } = useEvm(); + const [data, setData] = useState(null); + + useEffect(() => { + if (nftGame1.getBalanceOf) { + nftGame1.getBalanceOf(props.account).then(setData); + } + }, [nftGame1.getBalanceOf]); + + const balanceAvailable = () => { + return data ?

{JSON.stringify(data)}

:

Error.

; + }; + + return ( +
+ {' '} + Balance of: {props.account} {balanceAvailable()} +
+ ); +}; +``` + +For more information about our modules please visit: [**Hyperverse Docs**](docs.hyperverse.dev) diff --git a/packages/hyperverse-evm-nftgame1/docs/getBalanceOf.mdx b/packages/hyperverse-evm-nftgame1/docs/getBalanceOf.mdx new file mode 100644 index 00000000..3d8eecb1 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/getBalanceOf.mdx @@ -0,0 +1,4 @@ +import { Description } from '@storybook/addon-docs'; +import readme from './getBalanceOf.md'; + +export default ; diff --git a/packages/hyperverse-evm-nftgame1/docs/getOwnerOf.md b/packages/hyperverse-evm-nftgame1/docs/getOwnerOf.md new file mode 100644 index 00000000..a6851f12 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/getOwnerOf.md @@ -0,0 +1,84 @@ +# Get Owner Of + +

The `getOwnerOf` function from `nftGame1Library` returns the address of a token ID owner.

+ +--- + +
+ +### getOwnerOf + +

The `getOwnerOf` function takes in a token ID.

+ +```jsx + const getOwnerOf = async (tokenId: string) => { + try { + const owner = await base.proxyContract?.ownerOf(tokenId); + return owner; + } catch (error) { + throw error; + } + } +``` + +### Stories + +```jsx +import { GetOwnerOf } from './getOwnerOf'; +import { HyperverseProvider } from './utils/Provider'; +import React from 'react'; +import Doc from '../docs/getOwnerOf.mdx'; + +export default { + title: 'Components/GetOwnerOf', + component: GetOwnerOf, + parameters: { + docs: { + page: Doc, + }, + }, +}; + +const Template = (args) => ( + + + +); + +export const Demo = Template.bind({}); + +Demo.args = { + tokenId: 1 +}; +``` + +### Main UI Component + +```jsx +import { useNFTGame1 } from '../source'; +import { useEvm } from '@decentology/hyperverse-evm'; +import { useEffect, useState } from 'react'; + +export const GetOwnerOf = ({ ...props }: {tokenId: string}) => { + const nftGame1 = useNFTGame1(); + const { address } = useEvm(); + const [data, setData] = useState(null); + + useEffect(() => { + if (nftGame1.getOwnerOf) { + nftGame1.getOwnerOf(props.tokenId).then(setData); + } + }, [nftGame1.getOwnerOf]); + + const owner = () => { + return data ? ( +

{data}

+ ) : ( +

Error.

+ ); + }; + + return
Owner of {props.tokenId}: {owner()}
; +``` + +For more information about our modules please visit: [**Hyperverse Docs**](docs.hyperverse.dev) diff --git a/packages/hyperverse-evm-nftgame1/docs/getOwnerOf.mdx b/packages/hyperverse-evm-nftgame1/docs/getOwnerOf.mdx new file mode 100644 index 00000000..11d48a32 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/getOwnerOf.mdx @@ -0,0 +1,4 @@ +import { Description } from '@storybook/addon-docs'; +import readme from './getOwnerOf.md'; + +export default ; diff --git a/packages/hyperverse-evm-nftgame1/docs/mint.md b/packages/hyperverse-evm-nftgame1/docs/mint.md new file mode 100644 index 00000000..b5add9fc --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/mint.md @@ -0,0 +1,84 @@ +# Mint + +

The `mint` function from `nftGame1Library` allows a user to mint their own NFT.

+ +--- + +
+ +### mint + +

The `mint` function takes in a target address.

+ +```jsx + const mint = async(to: string) => { + try { + const mintTxn = await base.proxyContract?.mint(to); + return mintTxn.wait() as TransactionReceipt; + } catch (error) { + throw error; + } + } +``` + +### Stories + +```jsx +import { Mint } from './mint'; +import { HyperverseProvider } from './utils/Provider'; +import React from 'react'; +import Doc from '../docs/mint.mdx'; + +export default { + title: 'Components/Mint', + component: Mint, + parameters: { + docs: { + page: Doc, + }, + }, +}; + +const Template = (args) => ( + + + +); + +export const Demo = Template.bind({}); + +Demo.args = { + to: '0x976EA74026E726554dB657fA54763abd0C3a0aa9', +}; +``` + +### Main UI Component + +```jsx +import { useNFTGame1 } from '../source'; +import { useEvm } from '@decentology/hyperverse-evm'; +import './style.css'; + +export const Mint = ({ ...props }: { to: string }) => { + const { mint } = useNFTGame1(); + const { address, Connect } = useEvm(); + + return ( + <> + + + + ); +}; +``` + +For more information about our modules please visit: [**Hyperverse Docs**](docs.hyperverse.dev) diff --git a/packages/hyperverse-evm-nftgame1/docs/mint.mdx b/packages/hyperverse-evm-nftgame1/docs/mint.mdx new file mode 100644 index 00000000..fd69ed74 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/mint.mdx @@ -0,0 +1,4 @@ +import { Description } from '@storybook/addon-docs'; +import readme from './mint.md'; + +export default ; diff --git a/packages/hyperverse-evm-nftgame1/docs/newInstance.md b/packages/hyperverse-evm-nftgame1/docs/newInstance.md new file mode 100644 index 00000000..f546d0eb --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/newInstance.md @@ -0,0 +1,89 @@ +# Create Instance + +

The `createInstance` function from `evmBaseLibrary` allows a user to connect their wallet where they can create a new instance.

+ +--- + +
+ +### createInstance + +

The `createInstance` function takes in a name for their NFT and a symbol to represent it.

+ +```jsx + const createInstance = async ({ + account, + ...args + }: { + account: string; + [key: string]: any; + }) => { + try { + const createTxn = await factoryContract.createInstance(account, ...Object.values(args)); + return createTxn.wait(); + } catch (err) { + factoryErrors(err); + throw err; + } + }; +``` + +### Stories + +```jsx +import { NewInstance } from './newInstance'; +import { HyperverseProvider } from './utils/Provider'; +import { Story } from '@storybook/react'; +import { Doc } from '../docs/newInstance.mdx'; + +export default { + title: 'Components/NewInstance', + component: NewInstance, + parameters: { + docs: { + page: Doc, + }, + }, +}; + +const Template: Story = (args) => ( + + + +); + +export const Demo = Template.bind({}); + +Demo.args = {}; +``` + +### Main UI Component + +```jsx +import { useNFTGame1 } from '../source'; +import { useEvm } from '@decentology/hyperverse-evm'; +import './style.css'; + +export const NewInstance = ({ ...props }) => { + const { createInstance } = useNFTGame1(); + const { address, Connect } = useEvm(); + + return ( + <> + + + + ); +}; +``` + +For more information about our modules please visit: [**Hyperverse Docs**](docs.hyperverse.dev) diff --git a/packages/hyperverse-evm-nftgame1/docs/newInstance.mdx b/packages/hyperverse-evm-nftgame1/docs/newInstance.mdx new file mode 100644 index 00000000..bfe62769 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/newInstance.mdx @@ -0,0 +1,4 @@ +import { Description } from '@storybook/addon-docs'; +import readme from './newInstance.md'; + +export const Doc = () => ; diff --git a/packages/hyperverse-evm-nftgame1/docs/setApprovalForAll.md b/packages/hyperverse-evm-nftgame1/docs/setApprovalForAll.md new file mode 100644 index 00000000..b51f0b59 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/setApprovalForAll.md @@ -0,0 +1,85 @@ +# Set Approval for All + +

The `setApprovalForAll` function from `nftGame1Library` approves all transfers of tokens to other addresses.

+ +--- + +
+ +### setApprovalForAll + +

The `transfer` function takes in the target address and a value of true for approved.

+ +```jsx + const setApprovalForAll = async ({ to, approved }: { to: string; approved: boolean }) => { + try { + const setApprovalTxn = await base.proxyContract?.setApprovalForAll(to, approved); + return setApprovalTxn.wait() as TransactionReceipt; + } catch (error) { + throw error; + } + } +``` + +### Stories + +```jsx +import { ApproveAll } from './setApprovalForAll'; +import { HyperverseProvider } from './utils/Provider'; +import React from 'react'; +import Doc from '../docs/setApprovalForAll.mdx'; + +export default { + title: 'Components/ApproveAll', + component: ApproveAll, + parameters: { + docs: { + page: Doc, + }, + }, +}; + +const Template = (args) => ( + + + +); + +export const Demo = Template.bind({}); + +Demo.args = { + to: '0x976EA74026E726554dB657fA54763abd0C3a0aa9', + approved: true, +}; +``` + +### Main UI Component + +```jsx +import { useNFTGame1 } from '../source'; +import { useEvm } from '@decentology/hyperverse-evm'; +import './style.css'; + +export const ApproveAll = ({ ...props }: { to: string; approved: boolean }) => { + const { setApprovalForAll } = useNFTGame1(); + const { address, Connect } = useEvm(); + + return ( + <> + + + + ); +}; +``` + +For more information about our modules please visit: [**Hyperverse Docs**](docs.hyperverse.dev) diff --git a/packages/hyperverse-evm-nftgame1/docs/setApprovalForAll.mdx b/packages/hyperverse-evm-nftgame1/docs/setApprovalForAll.mdx new file mode 100644 index 00000000..69052090 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/setApprovalForAll.mdx @@ -0,0 +1,4 @@ +import { Description } from '@storybook/addon-docs'; +import readme from './setApprovalForAll.md'; + +export const Doc = () => ; diff --git a/packages/hyperverse-evm-nftgame1/docs/togglePublicMint.md b/packages/hyperverse-evm-nftgame1/docs/togglePublicMint.md new file mode 100644 index 00000000..fff8475d --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/togglePublicMint.md @@ -0,0 +1,81 @@ +# Toggle Public Mint + +

The `togglePublicMint` function from `nftGame1Library` toggles between allowing other users who +are not the tenant to mint and or not mint.

+ +--- + +
+ +### togglePublicMint + +```jsx + const togglePublicMint = async () => { + try { + const toggle = await base.proxyContract?.togglePublicMint(); + return toggle.wait() as TransactionReceipt; + } catch (error) { + throw error; + } + } +``` + +### Stories + +```jsx +import { TogglePublicMint } from './togglePublicMint'; +import { HyperverseProvider } from './utils/Provider'; +import React from 'react'; +import Doc from '../docs/togglePublicMint.mdx'; + +export default { + title: 'Components/TogglePublicMint', + component: TogglePublicMint, + parameters: { + docs: { + page: Doc, + }, + }, +}; + +const Template = (args) => ( + + + +); + +export const Demo = Template.bind({}); + +Demo.args = {}; +``` + +### Main UI Component + +```jsx +import { useNFTGame1 } from '../source'; +import { useEvm } from '@decentology/hyperverse-evm'; +import './style.css'; + +export const TogglePublicMint = ({ ...props }) => { + const { togglePublicMint } = useNFTGame1(); + const { Connect } = useEvm(); + + return ( + <> + + + + ); +}; +``` + +For more information about our modules please visit: [**Hyperverse Docs**](docs.hyperverse.dev) diff --git a/packages/hyperverse-evm-nftgame1/docs/togglePublicMint.mdx b/packages/hyperverse-evm-nftgame1/docs/togglePublicMint.mdx new file mode 100644 index 00000000..85a64bee --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/togglePublicMint.mdx @@ -0,0 +1,4 @@ +import { Description } from '@storybook/addon-docs'; +import readme from './togglePublicMint.md'; + +export const Doc = () => ; diff --git a/packages/hyperverse-evm-nftgame1/docs/transfer.md b/packages/hyperverse-evm-nftgame1/docs/transfer.md new file mode 100644 index 00000000..008d15f1 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/transfer.md @@ -0,0 +1,59 @@ +# Transfer + +

The `transfer` function from `nftGame1Library` allows the owner to transfer their NFT to another address.

+ +--- + +
+ +### transfer + +

The `transfer` function takes in the address of the sender, the address of the recipient, and the token ID of the NFT being transferred.

+ +```jsx + const transfer = async ({ from, to, tokenId }: { from: string, to: string; tokenId: number }) => { + try { + const transferTxn = await base.proxyContract?.safeTransferFrom(from, to, tokenId); + return transferTxn.wait() as TransactionReceipt; + } catch (error) { + throw error; + } + } +``` + +### Stories + +```jsx + +``` + +### Main UI Component + +```jsx +import { useNFTGame1 } from '../source'; +import { useEvm } from '@decentology/hyperverse-evm'; +import './style.css'; + +export const Transfer = ({ ...props }: { from: string; to: string; tokenId: number }) => { + const { transfer } = useNFTGame1(); + const { address, Connect } = useEvm(); + + return ( + <> + + + + ); +}; +``` + +For more information about our modules please visit: [**Hyperverse Docs**](docs.hyperverse.dev) diff --git a/packages/hyperverse-evm-nftgame1/docs/transfer.mdx b/packages/hyperverse-evm-nftgame1/docs/transfer.mdx new file mode 100644 index 00000000..5ba2ced9 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/docs/transfer.mdx @@ -0,0 +1,4 @@ +import { Description } from '@storybook/addon-docs'; +import readme from './transfer.md'; + +export default ; diff --git a/packages/hyperverse-evm-nftgame1/hardhat.config.js b/packages/hyperverse-evm-nftgame1/hardhat.config.js new file mode 100644 index 00000000..3151c2dd --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/hardhat.config.js @@ -0,0 +1,45 @@ +require('dotenv').config(); +require('@nomiclabs/hardhat-waffle'); + +// This is a sample Hardhat task. To learn how to create your own go to +// https://hardhat.org/guides/create-task.html +task('accounts', 'Prints the list of accounts', async (taskArgs, hre) => { + const accounts = await hre.ethers.getSigners(); + + for (const account of accounts) { + console.log(account.address); + } +}); + +// You need to export an object to set up your config +// Go to https://hardhat.org/config/ to learn more + +/** + * @type import('hardhat/config').HardhatUserConfig + */ + +const accounts = process.env.NEXT_PRIVATE_KEY !== undefined ? [process.env.NEXT_PRIVATE_KEY] : []; + +module.exports = { + solidity: '0.8.4', + defaultNetwork: 'hardhat', + networks: { + hardhat: {}, + ethereum: { + url: `https://rinkeby.infura.io/v3/${process.env.NEXT_PUBLIC_INFURA_API_KEY}`, + accounts, + }, + metis: { + url: 'https://stardust.metis.io/?owner=588', + accounts, + }, + avalanche: { + url: 'https://api.avax-test.network/ext/bc/C/rpc', + accounts, + }, + polygon: { + url: 'https://matic-mumbai.chainstacklabs.com/', + accounts, + }, + }, +}; diff --git a/packages/hyperverse-evm-nftgame1/index.ts b/packages/hyperverse-evm-nftgame1/index.ts new file mode 100644 index 00000000..87907b64 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/index.ts @@ -0,0 +1,2 @@ +export * from "./source"; +// export {main as deploy} from './scripts/deploy'; diff --git a/packages/hyperverse-evm-nftgame1/package.json b/packages/hyperverse-evm-nftgame1/package.json new file mode 100644 index 00000000..d4cc9176 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/package.json @@ -0,0 +1,86 @@ +{ + "name": "@decentology/hyperverse-evm-nftgame1", + "version": "1.0.10", + "source": "./source/index.ts", + "types": "./distribution/index.d.ts", + "main": "./distribution/index.mjs", + "license": "MIT", + "exports": { + ".": { + "import": "./source/index.ts" + } + }, + "scripts": { + "test": "hardhat test", + "build": "rollup --config node:@decentology/config/rollup.config.js", + "clean": "rimraf ./distribution", + "compile": "hardhat compile", + "deploy": "run-p deploy-ethereum deploy-metis deploy-avalanche deploy-polygon", + "deploy-ethereum": "hardhat run scripts/deploy.js --network ethereum ", + "deploy-metis": "hardhat run scripts/deploy.js --network metis", + "deploy-avalanche": "hardhat run scripts/deploy.js --network avalanche", + "deploy-polygon": "hardhat run scripts/deploy.js --network polygon", + "lint": "tsc --noEmit", + "storybook": "start-storybook -p 6006", + "preview": "STORYBOOK_NETWORK=rinkeby build-storybook && cd storybook-static && 7z a -mx=9 publish.zip . ../.azure/. && az webapp deployment source config-zip --resource-group samples --name dappstarter-samples --src publish.zip", + "build-storybook": "build-storybook" + }, + "publishConfig": { + "access": "public", + "exports": null + }, + "peerDependencies": { + "react": "^17.0.2", + "react-dom": "^17.0.2" + }, + "files": [ + "distribution", + "utils" + ], + "engines": { + "node": ">=12.0.0" + }, + "dependencies": { + "@decentology/hyperverse": "workspace:^", + "@decentology/hyperverse-evm": "workspace:^", + "@decentology/unstated-next": "workspace:^", + "@openzeppelin/contracts": "^4.6.0", + "react": "17.0.2", + "react-dom": "17.0.2", + "ethers": "^5.6.8", + "react-use": "^17.4.0", + "real-cancellable-promise": "^1.1.1" + }, + "devDependencies": { + "@babel/core": "^7.18.2", + "@decentology/config": "workspace:^", + "@ethersproject/abstract-provider": "^5.6.1", + "@nomiclabs/hardhat-ethers": "^2.0.6", + "@nomiclabs/hardhat-waffle": "^2.0.3", + "@storybook/addon-actions": "^6.5.6", + "@storybook/addon-console": "^1.2.3", + "@storybook/addon-docs": "^6.5.6", + "@storybook/addon-essentials": "^6.5.6", + "@storybook/addon-interactions": "^6.5.6", + "@storybook/addon-links": "^6.5.6", + "@storybook/addons": "^6.5.6", + "@storybook/builder-webpack5": "^6.5.6", + "@storybook/cli": "^6.5.6", + "@storybook/manager-webpack5": "^6.5.6", + "@storybook/react": "^6.5.6", + "@storybook/testing-library": "^0.0.11", + "@storybook/theming": "^6.5.6", + "@types/react": "17.0.2", + "babel-loader": "^8.2.5", + "babel-plugin-react-require": "^3.1.3", + "chai": "^4.3.6", + "ethereum-waffle": "^3.4.4", + "fs-extra": "^10.1.0", + "hardhat": "^2.9.7", + "http-proxy-middleware": "^2.0.6", + "node-watch": "^0.7.3", + "npm-run-all": "^4.1.5", + "rimraf": "^3.0.2", + "wait-on": "^6.0.1" + } +} diff --git a/packages/hyperverse-evm-nftgame1/scripts/deploy-test.js b/packages/hyperverse-evm-nftgame1/scripts/deploy-test.js new file mode 100644 index 00000000..ce420b59 --- /dev/null +++ b/packages/hyperverse-evm-nftgame1/scripts/deploy-test.js @@ -0,0 +1,24 @@ +// We require the Hardhat Runtime Environment explicitly here. This is optional +// but useful for running the script in a standalone fashion through `node