diff --git a/.DS_Store b/.DS_Store index 171da95c..8eaee294 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/api b/api index 5433f38b..8f42351e 160000 --- a/api +++ b/api @@ -1 +1 @@ -Subproject commit 5433f38bd35c9fa3fab970a203015048886e9679 +Subproject commit 8f42351eb39dceb387a5aabb0fc942ee55d7975f diff --git a/components/Gameplay/Stake/ApproxRewards.tsx b/components/Gameplay/Stake/ApproxRewards.tsx index 31bd2d7b..29367a70 100644 --- a/components/Gameplay/Stake/ApproxRewards.tsx +++ b/components/Gameplay/Stake/ApproxRewards.tsx @@ -1,4 +1,10 @@ -import React, { useState, useEffect } from "react"; +export default function ApproxRewards () { + return ( + "This currently doesn't do anything due to compilation errors" + ) +} + +/*import React, { useState, useEffect } from "react"; import { useAddress } from "@thirdweb-dev/react"; import { SmartContract } from "@thirdweb-dev/sdk"; @@ -9,6 +15,7 @@ type Props = { helperContract: SmartContract; }; export default function ApproxRewards ({ helperContract }: Props ) { // Calls contract to estimate the rewards owed to the authenticated player/user const address = useAddress(); + const addressString = address const everyMillisecondAmount = parseInt( (10_000_000_000_000 / 2.1).toFixed(0) // Assumes each block (on EVM) takes ~2.1 seconds to be mined. Begins when component isMounted ); @@ -39,4 +46,4 @@ export default function ApproxRewards ({ helperContract }: Props ) { // Calls co

); -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/components/Gameplay/Stake/CurrentGear.tsx b/components/Gameplay/Stake/CurrentGear.tsx index a6983038..1da75f6f 100644 --- a/components/Gameplay/Stake/CurrentGear.tsx +++ b/components/Gameplay/Stake/CurrentGear.tsx @@ -21,7 +21,7 @@ export default function CurrentGear ({ // Shows the currently equipped planet ch const address = useAddress(); const { data: planetNft } = useNFT(planetContract, 0); // Maps the data to the first planet nft (as for this version of the demo, we're only interacting with WASP-48b aka token id 1) const [multitool, setMultitool] = useState(); // If user has any multitools staked onto the helper contract. Previously () - useEffect(() => { + /*useEffect(() => { (async () => { if (!address) return; const p = ( await helperContract.call( // Connect to the helper contract @@ -33,7 +33,7 @@ export default function CurrentGear ({ // Shows the currently equipped planet ch setMultitool(multitoolMetadata); } })(); - }, [address, helperContract, multitoolContract]); // Refresh this function if any of these values change. This component is reusable across multiple contracts (the contract addresses are defined in the page, not the component) + }, [address, helperContract, multitoolContract]); // Refresh this function if any of these values change. This component is reusable across multiple contracts (the contract addresses are defined in the page, not the component)*/ return (
diff --git a/components/Gameplay/Stake/OwnedGear.tsx b/components/Gameplay/Stake/OwnedGear.tsx index 9104f4e0..f8197036 100644 --- a/components/Gameplay/Stake/OwnedGear.tsx +++ b/components/Gameplay/Stake/OwnedGear.tsx @@ -1,4 +1,8 @@ -import React from "react"; +export default function OwnedGear () { + return "This export is a stub for the original ownedGear component" +} + +/*import React from "react"; import styles from '../../../styles/Staking-P2E/planetInteraction.module.css'; import { ThirdwebNftMedia, useAddress, useOwnedNFTs, Web3Button } from "@thirdweb-dev/react"; @@ -59,4 +63,4 @@ export default function OwnedGear ({ multitoolContract, helperContract }: Props)
); -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/components/Gameplay/Stake/Rewards.tsx b/components/Gameplay/Stake/Rewards.tsx index c5e2de03..14222d01 100644 --- a/components/Gameplay/Stake/Rewards.tsx +++ b/components/Gameplay/Stake/Rewards.tsx @@ -37,7 +37,8 @@ export default function Rewards({ helperContract, rewardsContract }: Props ) { / Unclaimed: {" "} {unclaimedAmount && ethers.utils.formatUnits(unclaimedAmount)}

- +

Approx rewards would go here

+ {/**/}
{ + getProfile(); + }, [session]); + + async function updateProfile({ + userAddress, + } : { + userAddress: Profiles['address'] + }) { + try { + setLoading(true); + if (!session?.user) throw new Error('No user authenticated'); + const updates = { + id: session?.user?.id, + address, + updated_at: new Date().toISOString(), + } + let { error } = await supabase.from('profiles').upsert(updates); + if (error) throw error; + alert('Off-chain PROFILE updated') + } catch (error) { + alert('Error updating your off-chain profile data'); + console.log(error); + } finally { + setLoading(false); + } + } + + if (loading) { + return ( + "Loading" + ); + } + + if (!userAddress) { + return ( + "Please authenticate via Metamask" + ) + } + + function updateProfileButton() { + updateProfile(userAddress); + } + + return ( +
+ +
+ ) +} \ No newline at end of file diff --git a/components/Lens/LensUser.tsx b/components/Lens/LensUser.tsx index 6e747a74..df292176 100644 --- a/components/Lens/LensUser.tsx +++ b/components/Lens/LensUser.tsx @@ -1,4 +1,10 @@ -// Base imports / next +type Props = {}; + +export default function LensProfilePage ( {}: Props ) { + return "Stub" +} + +/*/ Base imports / next import React from "react"; import { useRouter } from "next/router"; @@ -45,7 +51,7 @@ export default function LensProfilePage ( {}: Props ) { return ( - {/**/} + {/**/{/*
- {/* @ts-ignore */} + {/* @ts-ignore */}{/* {profileData?.profile?.coverPicture?.original?.url && ( )} - {/* @ts-ignore */} + {/* @ts-ignore */}{/* {profileData?.profile?.picture?.original?.url && (
- - ); -} \ No newline at end of file + */} + /*); +} +}*/ \ No newline at end of file diff --git a/contracts/extension 2/ContractMetadata.sol b/contracts/extension 2/ContractMetadata.sol new file mode 100644 index 00000000..c0d4825c --- /dev/null +++ b/contracts/extension 2/ContractMetadata.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.0; + +import "./interface/IContractMetadata.sol"; + +/** + * @title Contract Metadata + * @notice Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI + * for you contract. + * Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea. + */ + +abstract contract ContractMetadata is IContractMetadata { + /// @notice Returns the contract metadata URI. + string public override contractURI; + + /** + * @notice Lets a contract admin set the URI for contract-level metadata. + * @dev Caller should be authorized to setup contractURI, e.g. contract admin. + * See {_canSetContractURI}. + * Emits {ContractURIUpdated Event}. + * + * @param _uri keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE") + */ + function setContractURI(string memory _uri) external override { + if (!_canSetContractURI()) { + revert("Not authorized"); + } + + _setupContractURI(_uri); + } + + /// @dev Lets a contract admin set the URI for contract-level metadata. + function _setupContractURI(string memory _uri) internal { + string memory prevURI = contractURI; + contractURI = _uri; + + emit ContractURIUpdated(prevURI, _uri); + } + + /// @dev Returns whether contract metadata can be set in the given execution context. + function _canSetContractURI() internal view virtual returns (bool); +} \ No newline at end of file diff --git a/contracts/planetProposal.sol b/contracts/planetProposal.sol index dfc0b9d6..cf0f0a4a 100644 --- a/contracts/planetProposal.sol +++ b/contracts/planetProposal.sol @@ -38,4 +38,8 @@ contract PlanetProposal { proposals[_proposalIndex].noVotes ); } -} \ No newline at end of file +} + +/* +For use in testing voting on proposals from users on generated anomalies in play.skinetics.tech, working in the github/desci-md scripts +*/ \ No newline at end of file diff --git a/contracts/scripts/1_deploy_contract.js b/contracts/scripts/1_deploy_contract.js new file mode 100644 index 00000000..e901a512 --- /dev/null +++ b/contracts/scripts/1_deploy_contract.js @@ -0,0 +1,5 @@ +const Demo_Contract = artifacts.require("PlanetProposal"); + +module.exports = function(deployer) { + deployer.deploy(Demo_Contract); +}; \ No newline at end of file diff --git a/contracts/scripts/deploy.js b/contracts/scripts/deploy.js new file mode 100644 index 00000000..5810f5b3 --- /dev/null +++ b/contracts/scripts/deploy.js @@ -0,0 +1,19 @@ +async function main() { + const [deployer] = await ethers.getSigners(); + + console.log("Deploying contracts with the account:", deployer.address); + + console.log("Account balance:", (await deployer.getBalance()).toString()); + + const Token = await ethers.getContractFactory("Token"); + const token = await Token.deploy(); + + console.log("Token address:", token.address); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); +}); \ No newline at end of file diff --git a/contracts/scripts/deployToGoerli.js b/contracts/scripts/deployToGoerli.js new file mode 100644 index 00000000..74eaee4d --- /dev/null +++ b/contracts/scripts/deployToGoerli.js @@ -0,0 +1,14 @@ +async function main() { + const PlanetProposal = await ethers.getContractFactory("PlanetProposal"); + const gasPrice = await PlanetProposal.signer.getGasPrice(); + const estimatedGas = await PlanetProposal.signer.estimateGas( + PlanetProposal.getDeployTransaction() + ); + + const deploymentPrice = gasPrice.mul(estimatedGas); + const deployerBalance = await PlanetProposal.signer.getBalance(); + + if (Number(deployerBalance) < Number(deploymentPrice)) { + throw new Error("You don't have enough balance to deploy"); + } +} \ No newline at end of file diff --git a/contracts/scripts/deploy_voteContract.mjs b/contracts/scripts/deploy_voteContract.mjs new file mode 100644 index 00000000..ea5c54b0 --- /dev/null +++ b/contracts/scripts/deploy_voteContract.mjs @@ -0,0 +1,26 @@ +import { ThirdwebSDK } from "@thirdweb-dev/sdk"; +import "dotenv/config"; +import { MINERALS_ADDRESS } from "../../constants/contractAddresses"; + +const NETWORK = "goerli"; +const GOERLI_PRIVATE_KEY = process.env.PRIVATE_KEY; +const sdk = ThirdwebSDK.fromPrivateKey(GOERLI_PRIVATE_KEY, NETWORK); + +(async () => { + try { + const voteContractAddress = await sdk.deployer.deployVote({ + name: "Star Sailors Metadata DAO", + voting_token_address: MINERALS_ADDRESS, + voting_delay_in_blocks: 0, // A user can vote on a proposal immediately after it is created + voting_period_in_blocks: 6570, // Each proposal can be voted on for 1 day after it is created + voting_quorum_fraction: 0, + proposal_token_threshold: 0, + }); + + console.log('Successfully deployed vote contract, address: ', voteContractAddress); + } catch (err) { + console.error("Failed to deploy vote contract, ", err); + } +})(); + +// voting address: 0xEee8EB851e3d528ef3b5C98CD41cb6F25c929415 \ No newline at end of file diff --git a/contracts/scripts/proposals.mjs b/contracts/scripts/proposals.mjs new file mode 100644 index 00000000..46463403 --- /dev/null +++ b/contracts/scripts/proposals.mjs @@ -0,0 +1,39 @@ +import ethers from "hardhat"; +import { ThirdwebSDK } from "@thirdweb-dev/sdk"; +import "dotenv/config"; +//import { MINERALS_ADDRESS } from "../../constants/contractAddresses"; + +const MINERALS_ADDRESS = '0xE938775F4ee4913470905885c9744C7FAD482991'; +const NETWORK = "goerli"; +const GOERLI_PRIVATE_KEY = process.env.PRIVATE_KEY; +// const sdk = ThirdwebSDK.fromPrivateKey(GOERLI_PRIVATE_KEY, NETWORK); +const sdk = ThirdwebSDK.fromPrivateKey('71cc30029998f3282069d43e547efd1894f51269e15a833815e5ed5f418a38e7', NETWORK); + +(async () => { + try { + const vote = await sdk.getContract("0xd0F59Ed6EBf7f754fC3D5Fd7bb3181EBDeEd9E9d", "vote"); + const token = await sdk.getContract("0xa791a3e0F2D2300Ee85eC7105Eee9E9E8eb57908", "token"); + + // Create a proposal to mint 420,000 new minerals to the treasury + const amount = 420_000; + const description = "Should the DAO mint an additional " + amount + " tokens into the treasury?"; + const executions = [ + { + toAddress: token.getAddress(), + nativeTokenValue: 0, + transactionData: token.encoder.encode("mintTo", [ + vote.getAddress(), + ethers.utils.parseUnits(amount.toString(), 18), + ]), + }, + ]; + + await vote.propose(description, executions); + console.log("✅ Successfully created proposal to mint tokens"); + + } catch (error) { + console.error("failed to create first proposal", error); + process.exit(1); + }; + } +); \ No newline at end of file diff --git a/contracts/scripts/treasury.mjs b/contracts/scripts/treasury.mjs new file mode 100644 index 00000000..878bf6ef --- /dev/null +++ b/contracts/scripts/treasury.mjs @@ -0,0 +1,54 @@ +import { ThirdwebSDK } from "@thirdweb-dev/sdk"; +import "dotenv/config"; +//import { MINERALS_ADDRESS } from "../../constants/contractAddresses"; + +const MINERALS_ADDRESS = '0xE938775F4ee4913470905885c9744C7FAD482991'; +const NETWORK = "goerli"; +const GOERLI_PRIVATE_KEY = process.env.PRIVATE_KEY; +// const sdk = ThirdwebSDK.fromPrivateKey(GOERLI_PRIVATE_KEY, NETWORK); +const sdk = ThirdwebSDK.fromPrivateKey('71cc30029998f3282069d43e547efd1894f51269e15a833815e5ed5f418a38e7', NETWORK); + +(async () => { + try { + // This is our governance contract. + //const vote = await sdk.getContract("0xEee8EB851e3d528ef3b5C98CD41cb6F25c929415", "vote"); + const vote = await sdk.getContract("0xd0F59Ed6EBf7f754fC3D5Fd7bb3181EBDeEd9E9d", "vote"); + // This is our ERC-20 contract. + //const token = await sdk.getContract(MINERALS_ADDRESS, "token"); + const token = await sdk.getContract("0xa791a3e0F2D2300Ee85eC7105Eee9E9E8eb57908", "token"); + // Give our treasury the power to mint additional token if needed. + await token.roles.grant("minter", vote.getAddress()); + + console.log( + "Successfully gave vote contract permissions to act on token contract" + ); + } catch (error) { + console.error( + "failed to grant vote contract permissions on token contract", + error + ); + process.exit(1); + } + + try { + // This is our governance contract. + const vote = await sdk.getContract("0xd0F59Ed6EBf7f754fC3D5Fd7bb3181EBDeEd9E9d", "vote"); + // This is our ERC-20 contract. + const token = await sdk.getContract("0xa791a3e0F2D2300Ee85eC7105Eee9E9E8eb57908", "token"); + // Grab our wallet's token balance, remember -- we hold basically the entire supply right now! + const ownedTokenBalance = await token.balanceOf("0x8E818DF8441d4D13EA8fe8dd26967C061D956FE0"); + + // Grab 90% of the supply that we hold. + const ownedAmount = ownedTokenBalance.displayValue; + const percent90 = (Number(ownedAmount) / 100) * 90; + + // Transfer 90% of the supply to our voting contract. + await token.transfer(vote.getAddress(), percent90); + + console.log( + "✅ Successfully transferred " + percent90 + " tokens to vote contract" + ); + } catch (err) { + console.error("failed to transfer tokens to vote contract", err); + } +})(); \ No newline at end of file diff --git a/hardhat.config.js b/hardhat.config.js index 75a72301..9361476c 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -1,12 +1,19 @@ +//require("@nomicfoundation/hardhat-toolbox") +require(`@nomiclabs/hardhat-waffle`); + +const INFURA_API_KEY = process.env.WEB3_INFURA_PROJECT_ID; +const GOERLI_PRIVATE_KEY = process.env.PRIVATE_KEY; + /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: { - version: '0.8.11', - settings: { - optimizer: { - enabled: true, - runs: 200, - }, - }, + version: '0.8.0', + networks: { + goerli: { + url: `https://goerli.infura.io/v3/${INFURA_API_KEY}`, + accounts: [GOERLI_PRIVATE_KEY], + chainID: 5, + } + } }, }; \ No newline at end of file diff --git a/lib/useCreatePost.ts b/lib/useCreatePost.ts index a9acf07e..7b4d36c6 100644 --- a/lib/useCreatePost.ts +++ b/lib/useCreatePost.ts @@ -1,4 +1,8 @@ -import { useMutation } from "@tanstack/react-query"; +export function useCreatePost() { + return "Stub" +} + +/*import { useMutation } from "@tanstack/react-query"; import { useSDK, useStorageUpload } from "@thirdweb-dev/react"; import { PublicationMainFocus, useCreatePostTypedDataMutation } from "../graphql/generated"; import useLensUser from "./auth/useLensUser"; @@ -122,4 +126,4 @@ export function useCreatePost() { } return useMutation(createPost); -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/lib/useFollow.ts b/lib/useFollow.ts index 112579f7..d32bcb22 100644 --- a/lib/useFollow.ts +++ b/lib/useFollow.ts @@ -1,4 +1,8 @@ -// Web3 interaction & setup +export function useFollow () { + return "Stub" +} + +/*// Web3 interaction & setup import { useAddress, useSDK } from "@thirdweb-dev/react"; import { signTypedDataWithOmittedTypename, splitSignature } from "./helpers"; @@ -49,4 +53,4 @@ export function useFollow () { }; return useMutation(follow); -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/migrations/.gitkeep b/migrations/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/package.json b/package.json index 24965179..1de9e885 100644 --- a/package.json +++ b/package.json @@ -12,106 +12,125 @@ "test-api": "cd server && venv/bin/activate && flask test" }, "dependencies": { - "@chakra-ui/react": "^2.4.9", + "@3rdweb/hooks": "1.9.2", + "@3rdweb/sdk": "1.42.1", + "@chakra-ui/react": "2.4.9", "@emotion/react": "11.10.5", "@emotion/styled": "11.10.5", - "@ethersproject/solidity": "^5.7.0", - "@headlessui/react": "^1.7.12", - "@heroicons/react": "^2.0.16", - "@lens-protocol/react": "^0.3.0", + "@headlessui/react": "1.7.12", + "@heroicons/react": "2.0.16", + "@lens-protocol/react": "0.3.0", "@mui/icons-material": "5.11.9", "@mui/material": "5.11.9", - "@nextui-org/react": "^1.0.0-beta.12", - "@openzeppelin/contracts": "^4.8.2", + "@nextui-org/react": "1.0.0-beta.12", + "@nomicfoundation/hardhat-toolbox": "2.0.2", + "@nomiclabs/hardhat-waffle": "2.0.5", + "@openzeppelin/contracts": "4.8.2", "@primer/octicons-react": "9.1.1", - "@supabase/auth-helpers-nextjs": "^0.5.4", - "@supabase/auth-helpers-react": "^0.3.1", - "@supabase/auth-ui-react": "^0.2.6", - "@supabase/supabase-js": "^2.13.1", - "@supabase/ui": "^0.36.5", - "@tanstack/react-query": "^4.24.4", - "@thirdweb-dev/auth": "^3.0.11", - "@thirdweb-dev/react": "^3.9.0", - "@thirdweb-dev/sdk": "^3.9.0", - "@thirdweb-dev/storage": "^1.0.8", - "@types/rc-slider": "^9.3.1", - "@types/rc-tooltip": "^3.7.7", - "@types/react-color": "^3.0.6", - "@types/react-dom": "^18.0.10", - "alea": "^1.0.1", - "antd": "^5.3.3", - "autoprefixer": "^10.4.13", - "axios": "^1.3.4", - "bootstrap": "^5.2.3", - "daisyui": "^2.51.5", + "@supabase/auth-helpers-nextjs": "0.5.4", + "@supabase/auth-helpers-react": "0.3.1", + "@supabase/auth-ui-react": "0.2.6", + "@supabase/supabase-js": "2.13.1", + "@supabase/ui": "0.36.5", + "@tanstack/react-query": "4.24.4", + "@thirdweb-dev/auth": "3.0.11", + "@thirdweb-dev/react": "3.6.0", + "@thirdweb-dev/sdk": "3.10.7", + "@thirdweb-dev/storage": "1.0.8", + "@truffle/hdwallet-provider": "2.1.9", + "@types/rc-slider": "9.3.1", + "@types/rc-tooltip": "3.7.7", + "@types/react-color": "3.0.6", + "@types/react-dom": "18.0.10", + "alea": "1.0.1", + "antd": "5.3.3", + "autoprefixer": "10.4.13", + "axios": "1.3.4", + "bootstrap": "5.2.3", + "daisyui": "2.51.5", + "dotenv": "16.0.3", "eslint": "8.30.0", "eslint-config-next": "13.1.0", - "ether": "^0.0.9", + "ether": "0.0.9", "ethers": "5.7.2", - "extract-colors": "^2.0.5", - "framer-motion": "^9.0.2", - "fs": "^0.0.1-security", - "hardhat": "^2.13.0", - "html2canvas": "^1.4.1", - "javascript-time-ago": "^2.5.9", - "material-kit": "^2.0.4", + "extract-colors": "2.0.5", + "framer-motion": "9.0.2", + "fs": "0.0.1-security", + "hardhat": "2.13.0", + "html2canvas": "1.4.1", + "javascript-time-ago": "2.5.9", + "material-kit": "2.0.4", "next": "13.0.2", - "omit-deep": "^0.3.0", - "postcss": "^8.4.21", - "rc-slider": "^10.1.1", - "rc-tooltip": "^6.0.1", + "omit-deep": "0.3.0", + "postcss": "8.4.21", + "rc-slider": "10.1.1", + "rc-tooltip": "6.0.1", "react": "18.2.0", "react-bootstrap": "1.0.0-beta.12", - "react-clickout-handler": "^1.2.1", - "react-color": "^2.19.3", + "react-clickout-handler": "1.2.1", + "react-color": "2.19.3", "react-dom": "18.2.0", - "react-dropzone": "^14.2.3", - "react-icons": "^4.8.0", - "react-jupyter-notebook-viewer": "^1.1.13", - "react-query": "^3.39.3", - "react-spinners": "^0.13.8", - "react-time-ago": "^7.2.1", - "react-toastify": "^9.1.2", - "redux-typescript": "^1.2.1", - "sass": "^1.60.0", + "react-dropzone": "14.2.3", + "react-icons": "4.8.0", + "react-jupyter-notebook-viewer": "1.1.13", + "react-query": "3.39.3", + "react-spinners": "0.13.8", + "react-time-ago": "7.2.1", + "react-toastify": "9.1.2", + "redux-typescript": "1.2.1", + "sass": "1.60.0", "simplex-noise": "2.4.0", - "stellardream": "^0.1.5", - "supabase-comments-extension": "^0.0.2", - "tailwindcss": "^3.2.4", + "stellardream": "0.1.5", + "supabase-comments-extension": "0.0.2", + "tailwindcss": "3.2.4", "three": "0.108.0", - "use-react-screenshot": "^3.0.0", - "uuid": "^9.0.0", - "uuidv4": "^6.2.13", - "wagmi": "^0.12.8", - "wagmi-core": "^0.1.22" + "use-react-screenshot": "3.0.0", + "uuid": "9.0.0", + "uuidv4": "6.2.13", + "wagmi": "0.12.8", + "wagmi-core": "0.1.22" }, "devDependencies": { - "@babel/core": "^7.20.12", - "@graphql-codegen/cli": "^2.16.2", - "@graphql-codegen/fragment-matcher": "^3.3.3", - "@graphql-codegen/typescript": "^2.8.6", - "@graphql-codegen/typescript-operations": "^2.5.11", - "@graphql-codegen/typescript-react-query": "^4.0.6", - "@tailwindcss/forms": "^0.5.3", - "@tailwindcss/line-clamp": "^0.4.2", - "@tailwindcss/typography": "^0.5.9", - "@thirdweb-dev/contracts": "^3.3.0", - "@types/cookie": "^0.5.1", - "@types/node": "^18.14.0", - "@types/omit-deep": "^0.3.0", - "@types/react": "^18.0.28", - "@types/react-syntax-highlighter": "^15.5.5", - "@types/three": "^0.148.0", - "@types/unist": "^2.0.6", - "auto-prefixer": "^0.4.2", - "autoprefixer": "^10.4.13", - "babel-loader": "^9.1.2", + "@babel/core": "7.20.12", + "@graphql-codegen/cli": "2.16.2", + "@graphql-codegen/fragment-matcher": "3.3.3", + "@graphql-codegen/typescript": "2.8.6", + "@graphql-codegen/typescript-operations": "2.5.11", + "@graphql-codegen/typescript-react-query": "4.0.6", + "@nomicfoundation/hardhat-network-helpers": "1.0.8", + "@nomiclabs/hardhat-ethers": "2.2.2", + "@nomiclabs/hardhat-etherscan": "3.1.7", + "@tailwindcss/forms": "0.5.3", + "@tailwindcss/line-clamp": "0.4.2", + "@tailwindcss/typography": "0.5.9", + "@thirdweb-dev/contracts": "3.3.0", + "@thirdweb-dev/auth": "3.0.11", + "@thirdweb-dev/react": "3.6.0", + "@thirdweb-dev/sdk": "3.10.7", + "@thirdweb-dev/storage": "1.0.8", + "@typechain/ethers-v5": "10.2.0", + "@typechain/hardhat": "6.1.5", + "@types/chai": "4.3.4", + "@types/cookie": "0.5.1", + "@types/mocha": "10.0.1", + "@types/node": "18.14.0", + "@types/omit-deep": "0.3.0", + "@types/react": "18.0.28", + "@types/react-syntax-highlighter": "15.5.5", + "@types/three": "0.148.0", + "@types/unist": "2.0.6", + "auto-prefixer": "0.4.2", + "autoprefixer": "10.4.13", + "babel-loader": "9.1.2", "eslint": "8.30.0", "eslint-config-next": "13.1.0", - "gray-matter": "^4.0.3", - "postcss": "^8.4.21", - "stringify-object": "^4.0.1", - "tailwindcss": "^3.2.4", - "typescript": "^4.9.4" + "gray-matter": "4.0.3", + "hardhat-gas-reporter": "1.0.9", + "postcss": "8.4.21", + "solidity-coverage": "0.8.2", + "stringify-object": "4.0.1", + "tailwindcss": "3.2.4", + "typechain": "8.1.1", + "typescript": "4.9.4" } } diff --git a/pages/_app.tsx b/pages/_app.tsx index a9d63eae..ff1e0cee 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -35,7 +35,7 @@ function MyApp({ Component, pageProps }) { > write might require being set back to Polygon (with the Lens Mumbai/Polygon ABI & address) + desiredChainId={5} // Because our staking contracts are on Goerli, we'll need to move them onto Polygon/Mumbai so they work with the provider here. To-Do: Set to mumbai and confirm if Lens still works || Lens is using the contract ABI & Graphql -> write might require being set back to Polygon (with the Lens Mumbai/Polygon ABI & address) authConfig={{ domain: process.env.NEXT_PUBLIC_THIRDWEB_AUTH_DOMAIN, // originally set to sailors.skinetics.tech authUrl: "/api/auth", diff --git a/pages/gallery/.index.tsx.icloud b/pages/gallery/.index.tsx.icloud deleted file mode 100644 index d4a3f02a..00000000 Binary files a/pages/gallery/.index.tsx.icloud and /dev/null differ diff --git a/pages/gallery/index.tsx b/pages/gallery/index.tsx new file mode 100644 index 00000000..712a18d3 --- /dev/null +++ b/pages/gallery/index.tsx @@ -0,0 +1,152 @@ +import React, { useEffect, useState } from "react"; + +import Layout from "../../components/Layout"; +import Card from "../../components/Card"; +import PostCard from "../../components/PostCard"; + +import { v4 as uuidv4 } from 'uuid'; + +import { useSession, useSupabaseClient } from "@supabase/auth-helpers-react"; +import { UserContext } from "../../context/UserContext"; +import { Col, Container, Row, Form } from "react-bootstrap"; +import { imagesCdnAddress } from "../../constants/cdn"; + +export default function GalleryIndex () { + const supabase = useSupabaseClient(); + const session = useSession(); + + const [images, setImages] = useState([]); + const [loading, setLoading] = useState(false); + + async function getImages() { + const { data, error } = await supabase + .storage + .from('images') + .list(session?.user?.id + '/', { + limit: 100, + offset: 0, + sortBy: { + column: 'name', + order: 'asc', + } + }); + + if (data !== null) { + setImages(data); + } else { + alert('Error loading images'); + console.log(error); + } + } + + async function uploadImage(e) { + let file = e.target.files[0]; + const { data, error } = await supabase + .storage + .from('images') + .upload(session?.user?.id + '/' + uuidv4(), file); + // send request to Flask with url of (session?.user?.id + '/' + uuidv4(), file) + if (data) { + getImages(); + } else { + console.log(error); + } + } + + async function deleteImage ( imageName ) { + const { error } = await supabase + .storage + .from('images') + .remove([ session?.user?.id + '/' + imageName ]) + + if (error) { + alert (error); + } else { + getImages(); + } + } + + useEffect(() => { + if (session?.user) { + getImages(); + } + }, [session?.user]); + + /* PLANET manipulation + async function createPlanet({ // Maybe we should add a getPlanet (getUserPlanet) helper as well? + userId, temperature, radius, date, ticId + } : { + //id: Planets['id'] + userId: Planets['userId'] // Check to see if this page gets the userId as well, or just the username. Foreign key still works regardless + temperature: Planets['temperature'] + radius: Planets['radius'] + date: Planets['date'] + ticId: Planets['ticId'] + }) { + try { + setLoading(true); + // Is the planet ID going to be based on the user id (obviously not in production, but in this version?) + const newPlanetParams = { + id: user.id, // Generate a random id later + // .. other params from database types + } + } catch (error) { + console.log(error); + } finally { + setLoading(false); + } + } + + async function getUserPlanet() { + try { + setLoading(true); + if (!user) throw new Error('No user authenticated'); + let { data, error, status } = await supabase + .from('planets') + .select(`id, userId, temperature, radius, ticId`) + .eq('userId', username) + .single() + + if (error && status !== 406) { + throw error; + } + + if (data) { + setUserIdForPlanet(data.userId); + } + } catch (error) { + console.log(error); + } finally { + setLoading(false); + } + } */ + + return ( + + + + <> + {/* Add screenshot function for from `pages/planets/planet.tsx` */} +

Your images

{/* These images should be stored in an array based on which anomaly they're referring to if they're coming from posts -> e.g. 1 post can have 3 photos about "WASP-12b" */} + + {images.map((image) => { + return ( + + {/**/} + + ); + })} + +
+

Upload images of anomalies for analysis

+ + uploadImage(e)} /> + + +
+
+
+ ); +} + +// Original component demo here: https://github.com/Signal-K/client/blob/wb3-10-implement-off-chain-commenting-post/components/Data/OffchainAccount.tsx \ No newline at end of file diff --git a/pages/generator/account.tsx b/pages/generator/account.tsx index a74e136f..201a6452 100644 --- a/pages/generator/account.tsx +++ b/pages/generator/account.tsx @@ -12,18 +12,19 @@ import { useScreenshot } from 'use-react-screenshot'; import PlanetEditor from "./planet-editor"; -type Profiles = Database['public']['Tables']['profiles']['Row']; +//type Profiles = Database['public']['Tables']['profiles']['Row']; type Planets = Database['public']['Tables']['planets']['Row']; // See `wb3-10` at this point https://github.com/Signal-K/client/blob/wb3-10-implement-off-chain-commenting-post/components/Data/OffchainAccount.tsx / https://github.com/Signal-K/client/commit/17301ae88f3f8d1aa673ac968ceef360192fa3b1 -> Clone that branch and compare the behaviour and UI to what occurs here and in planet-editor export default function OffchainAccount({ session }: { session: Session}) { const supabase = useSupabaseClient(); const user = useUser(); const [loading, setLoading] = useState(true); - const [username, setUsername] = useState(null); - const [website, setWebsite] = useState(null); // I believe this is the email field - const [avatar_url, setAvatarUrl] = useState(null); - const [address, setAddress] = useState(null); // This should be set by the handler eventually (connected address). + const [username, setUsername] = useState(''); //useState(null); + const [website, setWebsite] = useState(''); //useState(null); // I believe this is the email field + const [avatar_url, setAvatarUrl] = useState(''); //useState(null); + const [address, setAddress] = useState(''); //useState(null); // This should be set by the handler eventually (connected address). const [images, setImages] = useState([]); + const [address2, setAddress2] = useState(''); // User planet const [userIdForPlanet, setUserIdForPlanet] = useState(null); @@ -37,7 +38,7 @@ export default function OffchainAccount({ session }: { session: Session}) { useEffect(() => { getProfile(); - console.log(user.id) + //console.log(user.id) }, [session]); async function getProfile () { @@ -46,7 +47,7 @@ export default function OffchainAccount({ session }: { session: Session}) { if (!user) throw new Error('No user authenticated'); let { data, error, status } = await supabase .from('profiles') - .select(`username, website, avatar_url, address`) + .select(`username, website, avatar_url, address, address2`) .eq('id', user.id) .single() @@ -59,6 +60,7 @@ export default function OffchainAccount({ session }: { session: Session}) { setWebsite(data.website); setAvatarUrl(data.avatar_url); setAddress(data.address); + setAddress2(data.address2); } } catch (error) { //alert('Error loading your user data'); @@ -74,21 +76,22 @@ export default function OffchainAccount({ session }: { session: Session}) { avatar_url, address, } : { - username: Profiles['username'] - website: Profiles['website'] - avatar_url: Profiles['avatar_url'] - address: Profiles['address'] + username: string //Profiles['username'] + website: string //Profiles['website'] + avatar_url: string //Profiles['avatar_url'] + address: string //Profiles['address'] }) { try { setLoading(true); if (!user) throw new Error('No user authenticated!'); const updates = { id: user.id, + updated_at: new Date().toISOString(), username, website, avatar_url, address, - updated_at: new Date().toISOString(), + address2, } let { error } = await supabase.from('profiles').upsert(updates); if (error) throw error; diff --git a/pages/governance/Authenticate.tsx b/pages/governance/Authenticate.tsx new file mode 100644 index 00000000..ba0adb32 --- /dev/null +++ b/pages/governance/Authenticate.tsx @@ -0,0 +1,95 @@ +import { useState, useEffect } from "react"; +import { useSession, useSupabaseClient } from "@supabase/auth-helpers-react"; +import { ConnectWallet, useAddress } from "@thirdweb-dev/react"; +import { Database } from "../../utils/database.types"; + +type Profiles = Database['public']['Tables']['profiles']['Row']; + +export default function AuthenticateWalletToDb () { + const session = useSession(); + const supabase = useSupabaseClient(); + const address = useAddress(); + + const [loading, setLoading] = useState(false); + const [userAddress, setUserAddress] = useState(); + const [username, setUsername] = useState(''); + const [updated_at, setUpdate_at] = useState(); + + async function getProfile () { + try { + setLoading(true); + if (!session) throw new Error('No user authenticated'); + let { data, error, status } = await supabase + .from('profiles') + .select(`username, website, avatar_url, address`) + .eq('id', session?.user?.id) + .single() + + if (error && status !== 406) { + throw error; + } + + if (data) { + setUsername(data.username); + setUserAddress(data.address); + } + } catch (error) { + //alert('Error loading your user data'); + console.log(error); + } finally { + setLoading(false); + } + } + + useEffect(() => { + getProfile(); + }, [session]); + + async function updateProfile({ + userAddress, + } : { + userAddress: Profiles['address'] + }) { + try { + setLoading(true); + if (!session?.user) throw new Error('No user authenticated'); + const updates = { + id: session?.user?.id, + address2: address, + updated_at: new Date().toISOString(), + } + let { error } = await supabase.from('profiles').upsert(updates); + if (error) throw error; + alert('Off-chain PROFILE updated') + } catch (error) { + alert('Error updating your off-chain profile data'); + console.log(error); + } finally { + setLoading(false); + } + } + + if (loading) { + return ( + "Loading" + ); + } + + if (!userAddress) { + return ( + "Please authenticate via Metamask" + ) + } + + function updateProfileButton() { + updateProfile(userAddress); + } + + return ( +
+ + {address} + +
+ ) +} \ No newline at end of file diff --git a/pages/governance/[id].tsx b/pages/governance/[id].tsx new file mode 100644 index 00000000..36ad3610 --- /dev/null +++ b/pages/governance/[id].tsx @@ -0,0 +1,5 @@ +import React from "react"; + +export default function VotePageForId () { + +} \ No newline at end of file diff --git a/pages/governance/index.tsx b/pages/governance/index.tsx index a7ef2562..78eb07f2 100644 --- a/pages/governance/index.tsx +++ b/pages/governance/index.tsx @@ -1,32 +1,58 @@ import React, { useEffect } from "react"; -import { Header } from "../../components/Governance/Header"; -import { Footer } from '../../components/Governance/Footer'; -import { Navbar } from "../../components/Governance/Navbar"; //import { useMetamaskState } from "../../components/Governance/Connections/ConnectWallet"; //import styles from '../../styles/governance/governance.module.css'; import styles from '../../styles/Staking-P2E/planetInteraction.module.css'; -import { NextPage } from "next"; -import { useAddress } from "@thirdweb-dev/react"; +import { ConnectWallet, useAddress, useContract, useContractRead, Web3Button } from "@thirdweb-dev/react"; +import CoreLayout from "../../components/Core/Layout"; -const GovernanceDAOIndex: NextPage = () => { +export default function GovernanceDAOIndex () { //const { isConnected, account, signer, connectToMetamask } = useMetamaskState(); const address = useAddress(); - const contractAddress = ''; // Set this to deployed "planetProposal.sol" contract + const contractAddress = '0xd606dead5014AfCc5678EeF3EB1C7bEc64718b34'; + const { contract } = useContract("0xd606dead5014AfCc5678EeF3EB1C7bEc64718b34"); + const { data, isLoading } = useContractRead(contract, "proposals"); + const { data: proposal, isLoading: proposalLoading } = useContractRead(contract, 'proposals', 0); // Set the index to the specific planet id, map the planet id to the dao id + const { data: hasVoted, isLoading: hasVotedLoading } = useContractRead(contract, 'hasVoted', 0, address); return ( - <> + <>
- + +

Proposal Voting

+
+ {address ? ( +
+ {proposalLoading ? ( +
+

{proposal/*[0]*/}

+ {/* contract.call("vote", 0, true)} + >Yes*/} +
+ {/* contract.call("vote", 0, false)} + >No*/} +
+ ) : ( +

Loading

+ )} +
+ ) : ( +
+

Connect your wallet to get started

+
+ )} +
{/*
-