diff --git a/.DS_Store b/.DS_Store index 508dd85e..cf394c26 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Server/constants/cdn.ts b/Server/constants/cdn.ts new file mode 100644 index 00000000..9a9ae56d --- /dev/null +++ b/Server/constants/cdn.ts @@ -0,0 +1,2 @@ +export const imagesCdnAddress = 'https://qwbufbmxkjfaikoloudl.supabase.co/storage/v1/object/public/images/' +export const generatorCdnInfo = 'https://github.com/Signal-K/client/commit/ab6b6db464602535a7ca9e471956e021ffbf3c95' \ No newline at end of file diff --git a/Server/constants/contractAddresses.ts b/Server/constants/contractAddresses.ts new file mode 100644 index 00000000..4add9e33 --- /dev/null +++ b/Server/constants/contractAddresses.ts @@ -0,0 +1,7 @@ +export const HELPER_ADDRESS = '0xcf05AB21cAa609c81D6DfF435F0F8808A05EA264'; // custom contract +// 0xcf05AB21cAa609c81D6DfF435F0F8808A05EA264 is deployed from the correct wallet, but has a problem - it points to the Planets contract as the multitools contract (i.e. the planets are both the required nft and the nft that is being staked. This could be implemented in future...but for now we need to fix this. So I've redeployed it on a new address (see above line) with the correct pointer). See https://skinetics.notion.site/Planet-Mining-multitool-8310fa1cd188440688bbcc19692b3b67. Derived from https://thirdweb.com/0xCdc5929e1158F7f0B320e3B942528E6998D8b25c/PlanetHelper/1.0.1?via=/goerli/0xcf05AB21cAa609c81D6DfF435F0F8808A05EA264 +export const MULTITOOLS_ADDRESS = '0xF846D262EeBAFbfA79017b43aBb0251F740a0619'; +export const PLANETS_ADDRESS = '0xdf35Bb26d9AAD05EeC5183c6288f13c0136A7b43'; // edition drop (erc1155) +export const MINERALS_ADDRESS = '0xE938775F4ee4913470905885c9744C7FAD482991'; + +// Note that this is on the Goerli test net \ No newline at end of file diff --git a/Server/constants/contractMappingResponse.ts b/Server/constants/contractMappingResponse.ts new file mode 100644 index 00000000..12dfbcc8 --- /dev/null +++ b/Server/constants/contractMappingResponse.ts @@ -0,0 +1,8 @@ +import { BigNumber } from "ethers"; + +type ContractMappingResponse = { + isData: boolean; + value: BigNumber; +}; + +export default ContractMappingResponse; \ No newline at end of file diff --git a/Server/constants/contracts.ts b/Server/constants/contracts.ts new file mode 100644 index 00000000..344d144c --- /dev/null +++ b/Server/constants/contracts.ts @@ -0,0 +1,1208 @@ +// 1. export the contract address +export const LENS_CONTRACT_ADDRESS = + "0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d"; + +// 2. export the contract abi +export const LENS_CONTRACT_ABI = [ + { + inputs: [ + { internalType: "address", name: "followNFTImpl", type: "address" }, + { internalType: "address", name: "collectNFTImpl", type: "address" }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { inputs: [], name: "CallerNotCollectNFT", type: "error" }, + { inputs: [], name: "CallerNotFollowNFT", type: "error" }, + { inputs: [], name: "CannotInitImplementation", type: "error" }, + { inputs: [], name: "EmergencyAdminCannotUnpause", type: "error" }, + { inputs: [], name: "InitParamsInvalid", type: "error" }, + { inputs: [], name: "Initialized", type: "error" }, + { inputs: [], name: "NotGovernance", type: "error" }, + { inputs: [], name: "NotGovernanceOrEmergencyAdmin", type: "error" }, + { inputs: [], name: "NotOwnerOrApproved", type: "error" }, + { inputs: [], name: "NotProfileOwner", type: "error" }, + { inputs: [], name: "NotProfileOwnerOrDispatcher", type: "error" }, + { inputs: [], name: "Paused", type: "error" }, + { inputs: [], name: "ProfileCreatorNotWhitelisted", type: "error" }, + { inputs: [], name: "ProfileImageURILengthInvalid", type: "error" }, + { inputs: [], name: "PublicationDoesNotExist", type: "error" }, + { inputs: [], name: "PublishingPaused", type: "error" }, + { inputs: [], name: "SignatureExpired", type: "error" }, + { inputs: [], name: "SignatureInvalid", type: "error" }, + { inputs: [], name: "ZeroSpender", type: "error" }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "approved", + type: "address", + }, + { + indexed: true, + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "operator", + type: "address", + }, + { indexed: false, internalType: "bool", name: "approved", type: "bool" }, + ], + name: "ApprovalForAll", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: true, + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + inputs: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "approve", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "owner", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "burn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "tokenId", type: "uint256" }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct DataTypes.EIP712Signature", + name: "sig", + type: "tuple", + }, + ], + name: "burnWithSig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "uint256", name: "pubId", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "collect", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "collector", type: "address" }, + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "uint256", name: "pubId", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct DataTypes.EIP712Signature", + name: "sig", + type: "tuple", + }, + ], + internalType: "struct DataTypes.CollectWithSigData", + name: "vars", + type: "tuple", + }, + ], + name: "collectWithSig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "string", name: "contentURI", type: "string" }, + { + internalType: "uint256", + name: "profileIdPointed", + type: "uint256", + }, + { internalType: "uint256", name: "pubIdPointed", type: "uint256" }, + { internalType: "bytes", name: "referenceModuleData", type: "bytes" }, + { internalType: "address", name: "collectModule", type: "address" }, + { + internalType: "bytes", + name: "collectModuleInitData", + type: "bytes", + }, + { internalType: "address", name: "referenceModule", type: "address" }, + { + internalType: "bytes", + name: "referenceModuleInitData", + type: "bytes", + }, + ], + internalType: "struct DataTypes.CommentData", + name: "vars", + type: "tuple", + }, + ], + name: "comment", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "string", name: "contentURI", type: "string" }, + { + internalType: "uint256", + name: "profileIdPointed", + type: "uint256", + }, + { internalType: "uint256", name: "pubIdPointed", type: "uint256" }, + { internalType: "bytes", name: "referenceModuleData", type: "bytes" }, + { internalType: "address", name: "collectModule", type: "address" }, + { + internalType: "bytes", + name: "collectModuleInitData", + type: "bytes", + }, + { internalType: "address", name: "referenceModule", type: "address" }, + { + internalType: "bytes", + name: "referenceModuleInitData", + type: "bytes", + }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct DataTypes.EIP712Signature", + name: "sig", + type: "tuple", + }, + ], + internalType: "struct DataTypes.CommentWithSigData", + name: "vars", + type: "tuple", + }, + ], + name: "commentWithSig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "string", name: "handle", type: "string" }, + { internalType: "string", name: "imageURI", type: "string" }, + { internalType: "address", name: "followModule", type: "address" }, + { + internalType: "bytes", + name: "followModuleInitData", + type: "bytes", + }, + { internalType: "string", name: "followNFTURI", type: "string" }, + ], + internalType: "struct DataTypes.CreateProfileData", + name: "vars", + type: "tuple", + }, + ], + name: "createProfile", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "wallet", type: "address" }], + name: "defaultProfile", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "uint256", name: "pubId", type: "uint256" }, + { internalType: "uint256", name: "collectNFTId", type: "uint256" }, + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + ], + name: "emitCollectNFTTransferEvent", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "uint256", name: "followNFTId", type: "uint256" }, + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + ], + name: "emitFollowNFTTransferEvent", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "exists", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256[]", name: "profileIds", type: "uint256[]" }, + { internalType: "bytes[]", name: "datas", type: "bytes[]" }, + ], + name: "follow", + outputs: [{ internalType: "uint256[]", name: "", type: "uint256[]" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "follower", type: "address" }, + { internalType: "uint256[]", name: "profileIds", type: "uint256[]" }, + { internalType: "bytes[]", name: "datas", type: "bytes[]" }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct DataTypes.EIP712Signature", + name: "sig", + type: "tuple", + }, + ], + internalType: "struct DataTypes.FollowWithSigData", + name: "vars", + type: "tuple", + }, + ], + name: "followWithSig", + outputs: [{ internalType: "uint256[]", name: "", type: "uint256[]" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "getApproved", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "uint256", name: "pubId", type: "uint256" }, + ], + name: "getCollectModule", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "uint256", name: "pubId", type: "uint256" }, + ], + name: "getCollectNFT", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getCollectNFTImpl", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "uint256", name: "pubId", type: "uint256" }, + ], + name: "getContentURI", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "profileId", type: "uint256" }], + name: "getDispatcher", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getDomainSeparator", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "profileId", type: "uint256" }], + name: "getFollowModule", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "profileId", type: "uint256" }], + name: "getFollowNFT", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getFollowNFTImpl", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "profileId", type: "uint256" }], + name: "getFollowNFTURI", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getGovernance", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "profileId", type: "uint256" }], + name: "getHandle", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "profileId", type: "uint256" }], + name: "getProfile", + outputs: [ + { + components: [ + { internalType: "uint256", name: "pubCount", type: "uint256" }, + { internalType: "address", name: "followModule", type: "address" }, + { internalType: "address", name: "followNFT", type: "address" }, + { internalType: "string", name: "handle", type: "string" }, + { internalType: "string", name: "imageURI", type: "string" }, + { internalType: "string", name: "followNFTURI", type: "string" }, + ], + internalType: "struct DataTypes.ProfileStruct", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "string", name: "handle", type: "string" }], + name: "getProfileIdByHandle", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "uint256", name: "pubId", type: "uint256" }, + ], + name: "getPub", + outputs: [ + { + components: [ + { + internalType: "uint256", + name: "profileIdPointed", + type: "uint256", + }, + { internalType: "uint256", name: "pubIdPointed", type: "uint256" }, + { internalType: "string", name: "contentURI", type: "string" }, + { internalType: "address", name: "referenceModule", type: "address" }, + { internalType: "address", name: "collectModule", type: "address" }, + { internalType: "address", name: "collectNFT", type: "address" }, + ], + internalType: "struct DataTypes.PublicationStruct", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "profileId", type: "uint256" }], + name: "getPubCount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "uint256", name: "pubId", type: "uint256" }, + ], + name: "getPubPointer", + outputs: [ + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "uint256", name: "", type: "uint256" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "uint256", name: "pubId", type: "uint256" }, + ], + name: "getPubType", + outputs: [ + { internalType: "enum DataTypes.PubType", name: "", type: "uint8" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "uint256", name: "pubId", type: "uint256" }, + ], + name: "getReferenceModule", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getState", + outputs: [ + { internalType: "enum DataTypes.ProtocolState", name: "", type: "uint8" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "string", name: "name", type: "string" }, + { internalType: "string", name: "symbol", type: "string" }, + { internalType: "address", name: "newGovernance", type: "address" }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "operator", type: "address" }, + ], + name: "isApprovedForAll", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "collectModule", type: "address" }, + ], + name: "isCollectModuleWhitelisted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "followModule", type: "address" }, + ], + name: "isFollowModuleWhitelisted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "profileCreator", type: "address" }, + ], + name: "isProfileCreatorWhitelisted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "referenceModule", type: "address" }, + ], + name: "isReferenceModuleWhitelisted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "mintTimestampOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { + internalType: "uint256", + name: "profileIdPointed", + type: "uint256", + }, + { internalType: "uint256", name: "pubIdPointed", type: "uint256" }, + { internalType: "bytes", name: "referenceModuleData", type: "bytes" }, + { internalType: "address", name: "referenceModule", type: "address" }, + { + internalType: "bytes", + name: "referenceModuleInitData", + type: "bytes", + }, + ], + internalType: "struct DataTypes.MirrorData", + name: "vars", + type: "tuple", + }, + ], + name: "mirror", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { + internalType: "uint256", + name: "profileIdPointed", + type: "uint256", + }, + { internalType: "uint256", name: "pubIdPointed", type: "uint256" }, + { internalType: "bytes", name: "referenceModuleData", type: "bytes" }, + { internalType: "address", name: "referenceModule", type: "address" }, + { + internalType: "bytes", + name: "referenceModuleInitData", + type: "bytes", + }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct DataTypes.EIP712Signature", + name: "sig", + type: "tuple", + }, + ], + internalType: "struct DataTypes.MirrorWithSigData", + name: "vars", + type: "tuple", + }, + ], + name: "mirrorWithSig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "ownerOf", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct DataTypes.EIP712Signature", + name: "sig", + type: "tuple", + }, + ], + name: "permit", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "operator", type: "address" }, + { internalType: "bool", name: "approved", type: "bool" }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct DataTypes.EIP712Signature", + name: "sig", + type: "tuple", + }, + ], + name: "permitForAll", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "string", name: "contentURI", type: "string" }, + { internalType: "address", name: "collectModule", type: "address" }, + { + internalType: "bytes", + name: "collectModuleInitData", + type: "bytes", + }, + { internalType: "address", name: "referenceModule", type: "address" }, + { + internalType: "bytes", + name: "referenceModuleInitData", + type: "bytes", + }, + ], + internalType: "struct DataTypes.PostData", + name: "vars", + type: "tuple", + }, + ], + name: "post", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "string", name: "contentURI", type: "string" }, + { internalType: "address", name: "collectModule", type: "address" }, + { + internalType: "bytes", + name: "collectModuleInitData", + type: "bytes", + }, + { internalType: "address", name: "referenceModule", type: "address" }, + { + internalType: "bytes", + name: "referenceModuleInitData", + type: "bytes", + }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct DataTypes.EIP712Signature", + name: "sig", + type: "tuple", + }, + ], + internalType: "struct DataTypes.PostWithSigData", + name: "vars", + type: "tuple", + }, + ], + name: "postWithSig", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "safeTransferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + { internalType: "bytes", name: "_data", type: "bytes" }, + ], + name: "safeTransferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "operator", type: "address" }, + { internalType: "bool", name: "approved", type: "bool" }, + ], + name: "setApprovalForAll", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "profileId", type: "uint256" }], + name: "setDefaultProfile", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "wallet", type: "address" }, + { internalType: "uint256", name: "profileId", type: "uint256" }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct DataTypes.EIP712Signature", + name: "sig", + type: "tuple", + }, + ], + internalType: "struct DataTypes.SetDefaultProfileWithSigData", + name: "vars", + type: "tuple", + }, + ], + name: "setDefaultProfileWithSig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "address", name: "dispatcher", type: "address" }, + ], + name: "setDispatcher", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "address", name: "dispatcher", type: "address" }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct DataTypes.EIP712Signature", + name: "sig", + type: "tuple", + }, + ], + internalType: "struct DataTypes.SetDispatcherWithSigData", + name: "vars", + type: "tuple", + }, + ], + name: "setDispatcherWithSig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "newEmergencyAdmin", type: "address" }, + ], + name: "setEmergencyAdmin", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "address", name: "followModule", type: "address" }, + { internalType: "bytes", name: "followModuleInitData", type: "bytes" }, + ], + name: "setFollowModule", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "address", name: "followModule", type: "address" }, + { + internalType: "bytes", + name: "followModuleInitData", + type: "bytes", + }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct DataTypes.EIP712Signature", + name: "sig", + type: "tuple", + }, + ], + internalType: "struct DataTypes.SetFollowModuleWithSigData", + name: "vars", + type: "tuple", + }, + ], + name: "setFollowModuleWithSig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "string", name: "followNFTURI", type: "string" }, + ], + name: "setFollowNFTURI", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "string", name: "followNFTURI", type: "string" }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct DataTypes.EIP712Signature", + name: "sig", + type: "tuple", + }, + ], + internalType: "struct DataTypes.SetFollowNFTURIWithSigData", + name: "vars", + type: "tuple", + }, + ], + name: "setFollowNFTURIWithSig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "newGovernance", type: "address" }, + ], + name: "setGovernance", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "string", name: "imageURI", type: "string" }, + ], + name: "setProfileImageURI", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "uint256", name: "profileId", type: "uint256" }, + { internalType: "string", name: "imageURI", type: "string" }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct DataTypes.EIP712Signature", + name: "sig", + type: "tuple", + }, + ], + internalType: "struct DataTypes.SetProfileImageURIWithSigData", + name: "vars", + type: "tuple", + }, + ], + name: "setProfileImageURIWithSig", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "enum DataTypes.ProtocolState", + name: "newState", + type: "uint8", + }, + ], + name: "setState", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "sigNonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "index", type: "uint256" }], + name: "tokenByIndex", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "tokenDataOf", + outputs: [ + { + components: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "uint96", name: "mintTimestamp", type: "uint96" }, + ], + internalType: "struct IERC721Time.TokenData", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "uint256", name: "index", type: "uint256" }, + ], + name: "tokenOfOwnerByIndex", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "tokenURI", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "transferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "collectModule", type: "address" }, + { internalType: "bool", name: "whitelist", type: "bool" }, + ], + name: "whitelistCollectModule", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "followModule", type: "address" }, + { internalType: "bool", name: "whitelist", type: "bool" }, + ], + name: "whitelistFollowModule", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "profileCreator", type: "address" }, + { internalType: "bool", name: "whitelist", type: "bool" }, + ], + name: "whitelistProfileCreator", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "referenceModule", type: "address" }, + { internalType: "bool", name: "whitelist", type: "bool" }, + ], + name: "whitelistReferenceModule", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +]; \ No newline at end of file diff --git a/Server/context/UserContext.js b/Server/context/UserContext.js new file mode 100644 index 00000000..b0370a51 --- /dev/null +++ b/Server/context/UserContext.js @@ -0,0 +1,27 @@ +import {createContext, useEffect, useState} from "react"; +import {useSession, useSupabaseClient} from "@supabase/auth-helpers-react"; + +export const UserContext = createContext({}); + +export function UserContextProvider({children}) { + const session = useSession(); + const supabase = useSupabaseClient(); + const [profile,setProfile] = useState(null); + useEffect(() => { + if (!session?.user?.id) { + return; + } + supabase.from('profiles') + .select() + .eq('id', session.user.id) + .then(result => { + setProfile(result.data?.[0]); + }); + }, [session?.user?.id]); + + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/Server/database/supabase/config.toml b/Server/database/supabase/config.toml new file mode 100644 index 00000000..b61f6a55 --- /dev/null +++ b/Server/database/supabase/config.toml @@ -0,0 +1,72 @@ +# A string used to distinguish different Supabase projects on the same host. Defaults to the working +# directory name when running `supabase init`. +project_id = "comments" + +[api] +# Port to use for the API URL. +port = 54321 +# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API +# endpoints. public and storage are always included. +schemas = ["public", "storage", "graphql_public"] +# Extra schemas to add to the search_path of every request. public is always included. +extra_search_path = ["public", "extensions"] +# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size +# for accidental or malicious requests. +max_rows = 1000 + +[db] +# Port to use for the local database URL. +port = 54322 +# The database major version to use. This has to be the same as your remote database's. Run `SHOW +# server_version;` on the remote database to check. +major_version = 15 + +[studio] +# Port to use for Supabase Studio. +port = 54323 + +# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they +# are monitored, and you can view the emails that would have been sent from the web interface. +[inbucket] +# Port to use for the email testing server web interface. +port = 54324 +smtp_port = 54325 +pop3_port = 54326 + +[storage] +# The maximum file size allowed (e.g. "5MB", "500KB"). +file_size_limit = "50MiB" + +[auth] +# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used +# in emails. +site_url = "http://localhost:3000" +# A list of *exact* URLs that auth providers are permitted to redirect to post authentication. +additional_redirect_urls = ["https://localhost:3000"] +# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 seconds (one +# week). +jwt_expiry = 3600 +# Allow/disallow new user signups to your project. +enable_signup = true + +[auth.email] +# Allow/disallow new user signups via email to your project. +enable_signup = true +# If enabled, a user will be required to confirm any email change on both the old, and new email +# addresses. If disabled, only the new email is required to confirm. +double_confirm_changes = false +# If enabled, users need to confirm their email address before signing in. +enable_confirmations = false + +# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, +# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin`, `notion`, `twitch`, +# `twitter`, `slack`, `spotify`, `workos`, `zoom`. +[auth.external.apple] +enabled = false +client_id = "" +secret = "" +# Overrides the default auth redirectUrl. +redirect_uri = "" +# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, +# or any other third-party OIDC providers. +url = "" diff --git a/Server/database/supabase/migrations/_original-ddl.sql b/Server/database/supabase/migrations/_original-ddl.sql new file mode 100644 index 00000000..9f9e32fd --- /dev/null +++ b/Server/database/supabase/migrations/_original-ddl.sql @@ -0,0 +1,246 @@ +create extension ltree; + +create table user_profiles ( + user_id uuid primary key references auth.users (id) not null, + username text unique not null + CONSTRAINT proper_username CHECK (username ~* '^[a-zA-Z0-9_]+$') + CONSTRAINT username_length CHECK (char_length(username) > 3 and char_length(username) < 15) +); + +create table posts ( + id uuid primary key default uuid_generate_v4() not null, + user_id uuid references auth.users (id) not null, + created_at timestamp with time zone default now() not null, + path ltree not null +); + +create table post_score ( + post_id uuid primary key references posts (id) not null, + score int not null +); + +create table post_contents ( + id uuid primary key default uuid_generate_v4() not null, + user_id uuid references auth.users (id) not null, + post_id uuid references posts (id) not null, + title text, + content text, + created_at timestamp with time zone default now() not null +); + +create table post_votes ( + id uuid primary key default uuid_generate_v4() not null, + post_id uuid references posts (id) not null, + user_id uuid references auth.users (id) not null, + vote_type text not null, + unique (post_id, user_id) +); + +create table comments ( + id uuid primary key default uuid_generate_v4() not null, + created_at timestamp with time zone default now() not null, + updated_at timestamp with time zone default now() not null, + username varchar not null, + payload text not null, + reply_of uuid not null, +) + +create function initialize_post_score() +returns trigger +language plpgsql +security definer +set search_path = public +as $initialize_post_score$ +begin + insert into post_score (post_id, score) + values (new.id, 0); + return new; +end;$initialize_post_score$; + +create trigger initialize_post_score + after insert + on posts + for each row execute procedure initialize_post_score(); + +create function update_post_score() +returns trigger +language plpgsql +security definer +set search_path = public +as $update_post_score$ +begin +update post_score + set score = ( + select sum(case when vote_type = 'up' then 1 else -1 end) + from post_votes + where post_id = new.post_id + ) + where post_id = new.post_id; + return new; +end;$update_post_score$; + +create trigger update_post_score + after insert or update + on post_votes + for each row execute procedure update_post_score(); + +create function get_posts(page_number int) +returns table ( + id uuid, + user_id uuid, + created_at timestamp with time zone, + title text, + score int, + username text +) +language plpgsql +as $$ +begin + return query + select posts.id, posts.user_id, posts.created_at, post_contents.title, post_score.score, user_profiles.username + from posts + join post_contents on posts.id = post_contents.post_id + join post_score on posts.id = post_score.post_id + join user_profiles on posts.user_id = user_profiles.user_id + where posts.path ~ 'root' + order by post_score.score desc, posts.created_at desc + limit 10 + offset (page_number - 1) * 10; +end;$$; + +create function get_single_post_with_comments(post_id uuid) +returns table ( + id uuid, + author_name text, + created_at timestamp with time zone, + title text, + content text, + score int, + path ltree +) +language plpgsql +as $$ +begin + return query + select + posts.id, + user_profiles.username, + posts.created_at, + post_contents.title, + post_contents.content, + post_score.score, + posts.path + from posts + join post_contents on posts.id = post_contents.post_id + join post_score on posts.id = post_score.post_id + join user_profiles on posts.user_id = user_profiles.user_id + where + posts.path <@ text2ltree(concat('root.', replace(concat($1, ''), '-', '_'))) + or + posts.id = $1; +end;$$; + +create function create_new_post("userId" uuid, "title" text, "content" text) +returns boolean +language plpgsql +as $$ +begin + with + "inserted_post" as ( + insert into "posts" ("user_id", "path") + values ($1, 'root') + returning "id" + ) + insert into "post_contents" ("post_id", "title", "content", "user_id") + values ((select "id" from "inserted_post"), $2, $3, $1); + return true; +end; $$; + +create function create_new_comment(user_id uuid, content text, path ltree) +returns boolean +language plpgsql +as $$ +begin + with + inserted_post as ( + insert into posts (user_id, path) + values ($1, $3) + returning id + ) + insert into post_contents (post_id, title, content, user_id) + values ((select id from inserted_post), '', $2, $1); + return true; +end; $$; + +alter table user_profiles enable row level security; +alter table posts enable row level security; +alter table post_contents enable row level security; +alter table post_score enable row level security; +alter table post_votes enable row level security; + +CREATE POLICY "all can see" ON "public"."user_profiles" +AS PERMISSIVE FOR SELECT +TO public +USING (true); + +CREATE POLICY "users can insert" ON "public"."user_profiles" +AS PERMISSIVE FOR INSERT +TO public +WITH CHECK (auth.uid() = user_id); + +CREATE POLICY "owners can update" ON "public"."user_profiles" +AS PERMISSIVE FOR UPDATE +TO public +USING (auth.uid()=user_id) +WITH CHECK (auth.uid()=user_id); + +CREATE POLICY "all can see" ON "public"."post_contents" +AS PERMISSIVE FOR SELECT +TO public +USING (true); + +CREATE POLICY "authors can create" ON "public"."post_contents" +AS PERMISSIVE FOR INSERT +TO public +WITH CHECK (auth.uid()=user_id); + +CREATE POLICY "all can see" ON "public"."post_score" +AS PERMISSIVE FOR SELECT +TO public +USING (true); + +CREATE POLICY "all can see" ON "public"."post_votes" +AS PERMISSIVE FOR SELECT +TO public +USING (true); + +CREATE POLICY "owners can insert" ON "public"."post_votes" +AS PERMISSIVE FOR INSERT +TO public +WITH CHECK (auth.uid()=user_id); + +CREATE POLICY "owners can update" ON "public"."post_votes" +AS PERMISSIVE FOR UPDATE +TO public +USING (auth.uid()=user_id) +WITH CHECK (auth.uid()=user_id); + +CREATE POLICY "all can see" ON "public"."posts" +AS PERMISSIVE FOR SELECT +TO public +USING (true); + +CREATE POLICY "owners can insert" ON "public"."posts" +AS PERMISSIVE FOR INSERT +TO public +WITH CHECK (auth.uid()=user_id); + +BEGIN; + +DROP PUBLICATION IF EXISTS supabase_realtime CASCADE; + +CREATE PUBLICATION supabase_realtime WITH ( publish = 'insert, update, delete' ); + +ALTER PUBLICATION supabase_realtime ADD TABLE post_score; + +COMMIT; \ No newline at end of file diff --git a/Server/database/supabase/rls/media.sql b/Server/database/supabase/rls/media.sql new file mode 100644 index 00000000..43f0a27f --- /dev/null +++ b/Server/database/supabase/rls/media.sql @@ -0,0 +1 @@ +CREATE POLICY "Logged in users can upload photos 1ps738_0" ON storage.objects FOR INSERT TO public WITH CHECK (bucket_id = 'media' && auth.uid() != null); /* Also applies to 'photos'/'media' bucket(s) */ \ No newline at end of file diff --git a/Server/database/supabase/rls/posts.sql b/Server/database/supabase/rls/posts.sql new file mode 100644 index 00000000..d5ed3581 --- /dev/null +++ b/Server/database/supabase/rls/posts.sql @@ -0,0 +1,10 @@ +CREATE POLICY "Any user can create posts" ON "public"."posts" +AS PERMISSIVE FOR INSERT +TO public + +WITH CHECK (author = auth.uid()) /* https://app.supabase.com/project/qwbufbmxkjfaikoloudl/auth/policies#27609 */ + +CREATE POLICY "Anyone can see all posts" ON "public"."posts" +AS PERMISSIVE FOR SELECT +TO public +USING (true) \ No newline at end of file diff --git a/hardhat 2.config.js b/hardhat 2.config.js new file mode 100644 index 00000000..75a72301 --- /dev/null +++ b/hardhat 2.config.js @@ -0,0 +1,12 @@ +/** @type import('hardhat/config').HardhatUserConfig */ +module.exports = { + solidity: { + version: '0.8.11', + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, +}; \ No newline at end of file diff --git a/hardhat.config.js b/hardhat.config.js new file mode 100644 index 00000000..75a72301 --- /dev/null +++ b/hardhat.config.js @@ -0,0 +1,12 @@ +/** @type import('hardhat/config').HardhatUserConfig */ +module.exports = { + solidity: { + version: '0.8.11', + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, +}; \ No newline at end of file diff --git a/postcss 2.config.js b/postcss 2.config.js new file mode 100644 index 00000000..33ad091d --- /dev/null +++ b/postcss 2.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000..33ad091d --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}