diff --git a/.env b/.env index fa0709f..2698e33 100644 --- a/.env +++ b/.env @@ -1,22 +1,25 @@ SECRET_WORDS="test test test test test test test test test test test junk" PASSWORD=TestMetaMask NETWORK_NAME=MXC -GRAPH_URL=http://mxc-graph.mxc.com:8000/subgraphs/name/mnsdomains/mns +GRAPH_URL=http://mxc-graph-node.mxc.com:8000/subgraphs/name/mnsdomains/mns DATA_FOLDER=./data NEXT_PUBLIC_ALCHEMY_KEY=sSpYuHmhlpuU7RVXq-IIdCdz4IuKF-gM BLOCK_HEIGHT=17952336 -SUBGRAPH_ID=QmQ8PKwc5a4Zv86TPPLvN9n7y3VAASiH5ptkffJHZm2pU1 +SUBGRAPH_ID=QmXxAE7Urtv6TPa8o8XmPwLVQNbH6r35hRKHP63udTxTNa LOCAL_SUBGRAPH_ID=QmSUnR4AUTQ8CuGH2fK7tFTSSfYGe8BUz6EeBRNavXbE1H EPOCH_TIME=1660180306 -NETWORK=mxc -NEXT_PUBLIC_NETWORK_CHAINID=18686 +NETWORK=mxc_wannsee +NEXT_PUBLIC_NETWORK_CHAINID=5167003 ARCHIVE_URL=https://storage.googleapis.com/ens-manager-build-data TRANSACTION_WAIT_TIME=5000 STABLE_MODE=500 -NEXT_PUBLIC_PROVIDER=https://rpc.mxc.com -NEXT_PUBLIC_DEPLOYMENT_ADDRESSES={"ENSRegistry":"0xd241E9681B22Ae47e94c523d25CDdC1a4960cDC3","PublicResolver":"0x5325640Cc17A06a409d4f4b6af02A0120528c67E","BaseRegistrarImplementation":"0xCDFd5D9cEf780f751e5C653bFC9dFf0A4E55c39C","NameWrapper":"0xD1B70f92b310c3Fa95b83dB436E00a53e1f1f5d5","ETHRegistrarController":"0x8cFa2b92fcD0AEB6bD4EA056425C64f8638474d7","BulkRenewal":"0x032379fd3C71Fc100722CC98BC97803B7E01eAE6","DNSRegister":"0x74BF2E1290e24B99fCD244c34Da665Fd7FE17E08","ReverseRegistrar":"0x18c02bA5D8391b3CB49586C94454E44102252cFA","UniversalResolver":"0x7F0ca8F3bBC08eb712108Ae47D5A2c7D47075d6B","Multicall":"0xfA9eBcEd32BaB3EA062f9853ACA66cC9B666fBB9"} -NEXT_PUBLIC_GRAPH_URI=https://mxc-graph.mxc.com/subgraphs/name/mnsdomains/mns \ No newline at end of file +NEXT_PUBLIC_PROVIDER=https://wannsee-rpc.mxc.com +NEXT_PUBLIC_DEPLOYMENT_ADDRESSES={"ENSRegistry":"0x4E7984fF74569a270765EE67792386cBA77D1b01","PublicResolver":"0x438b261bEb8D3C500153DD17588E6feC36535312","BaseRegistrarImplementation":"0x39c47d083364b4A23d085c7945Fac9d42457d8C7","NameWrapper":"0x2246EdAd0bc9212Bae82D43974619480A9D1f387","ETHRegistrarController":"0xD9EeC15002fF7467a6841EDF6ea2D1048BaBc7c4","BulkRenewal":"0xD879004149706a6156De08e9a571Bfa5Ac6eDa84","DNSRegister":"0xaCFb160C4356a89c0096aAd292c7300D5949F384","ReverseRegistrar":"0x3453c56D41A18147dcb4a92b0B08210F90740a87","UniversalResolver":"0x4dc508720f701882c0bBB2fa67aA5c6bfBcC9c3e","Multicall":"0x98b114269C2635ff2cB03F0526feb246d1082B4C"} +NEXT_PUBLIC_GRAPH_URI=https://mxc-graph-node.mxc.com/subgraphs/name/mnsdomains/mns + +NEXT_PUBLIC_PINATA_SECRET_API_KEY = "e2888715c2e00be5b87664db8a797d11720db7f6014d51e15bfb6b62a922fe61" +NEXT_PUBLIC_PINATA_API_KEY = "52f5dffaa392c58db33d" \ No newline at end of file diff --git a/.env.mainnet b/.env.mainnet index fa0709f..bc4eadd 100644 --- a/.env.mainnet +++ b/.env.mainnet @@ -19,4 +19,7 @@ TRANSACTION_WAIT_TIME=5000 STABLE_MODE=500 NEXT_PUBLIC_PROVIDER=https://rpc.mxc.com NEXT_PUBLIC_DEPLOYMENT_ADDRESSES={"ENSRegistry":"0xd241E9681B22Ae47e94c523d25CDdC1a4960cDC3","PublicResolver":"0x5325640Cc17A06a409d4f4b6af02A0120528c67E","BaseRegistrarImplementation":"0xCDFd5D9cEf780f751e5C653bFC9dFf0A4E55c39C","NameWrapper":"0xD1B70f92b310c3Fa95b83dB436E00a53e1f1f5d5","ETHRegistrarController":"0x8cFa2b92fcD0AEB6bD4EA056425C64f8638474d7","BulkRenewal":"0x032379fd3C71Fc100722CC98BC97803B7E01eAE6","DNSRegister":"0x74BF2E1290e24B99fCD244c34Da665Fd7FE17E08","ReverseRegistrar":"0x18c02bA5D8391b3CB49586C94454E44102252cFA","UniversalResolver":"0x7F0ca8F3bBC08eb712108Ae47D5A2c7D47075d6B","Multicall":"0xfA9eBcEd32BaB3EA062f9853ACA66cC9B666fBB9"} -NEXT_PUBLIC_GRAPH_URI=https://mxc-graph.mxc.com/subgraphs/name/mnsdomains/mns \ No newline at end of file +NEXT_PUBLIC_GRAPH_URI=https://mxc-graph.mxc.com/subgraphs/name/mnsdomains/mns + +NEXT_PUBLIC_PINATA_SECRET_API_KEY = "e2888715c2e00be5b87664db8a797d11720db7f6014d51e15bfb6b62a922fe61" +NEXT_PUBLIC_PINATA_API_KEY = "52f5dffaa392c58db33d" \ No newline at end of file diff --git a/.env.testnet b/.env.testnet index 6876de5..2698e33 100644 --- a/.env.testnet +++ b/.env.testnet @@ -19,4 +19,7 @@ TRANSACTION_WAIT_TIME=5000 STABLE_MODE=500 NEXT_PUBLIC_PROVIDER=https://wannsee-rpc.mxc.com NEXT_PUBLIC_DEPLOYMENT_ADDRESSES={"ENSRegistry":"0x4E7984fF74569a270765EE67792386cBA77D1b01","PublicResolver":"0x438b261bEb8D3C500153DD17588E6feC36535312","BaseRegistrarImplementation":"0x39c47d083364b4A23d085c7945Fac9d42457d8C7","NameWrapper":"0x2246EdAd0bc9212Bae82D43974619480A9D1f387","ETHRegistrarController":"0xD9EeC15002fF7467a6841EDF6ea2D1048BaBc7c4","BulkRenewal":"0xD879004149706a6156De08e9a571Bfa5Ac6eDa84","DNSRegister":"0xaCFb160C4356a89c0096aAd292c7300D5949F384","ReverseRegistrar":"0x3453c56D41A18147dcb4a92b0B08210F90740a87","UniversalResolver":"0x4dc508720f701882c0bBB2fa67aA5c6bfBcC9c3e","Multicall":"0x98b114269C2635ff2cB03F0526feb246d1082B4C"} -NEXT_PUBLIC_GRAPH_URI=https://mxc-graph-node.mxc.com/subgraphs/name/mnsdomains/mns \ No newline at end of file +NEXT_PUBLIC_GRAPH_URI=https://mxc-graph-node.mxc.com/subgraphs/name/mnsdomains/mns + +NEXT_PUBLIC_PINATA_SECRET_API_KEY = "e2888715c2e00be5b87664db8a797d11720db7f6014d51e15bfb6b62a922fe61" +NEXT_PUBLIC_PINATA_API_KEY = "52f5dffaa392c58db33d" \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index b4ce847..ea2120c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,8 +8,8 @@ "typescript.enablePromptUseWorkspaceTsdk": true, "eslint.format.enable": true, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true, - "source.fixAll.stylelint": false + "source.fixAll.eslint": "explicit", + "source.fixAll.stylelint": "never" }, "stylelint.configFile": ".stylelintrc.json", "stylelint.validate": ["css", "typescriptreact"], @@ -18,5 +18,9 @@ "[svg]": { "editor.defaultFormatter": "jock.svg" }, - "jest.jestCommandLine": "pnpm run test" + "jest.jestCommandLine": "pnpm run test", + "i18n-ally.localesPaths": [ + "public/locales" + ], + "i18n-ally.keystyle": "nested" } diff --git a/src/components/@molecules/ProfileEditor/Avatar/AvatarButton.tsx b/src/components/@molecules/ProfileEditor/Avatar/AvatarButton.tsx index 343f57d..d6a6582 100755 --- a/src/components/@molecules/ProfileEditor/Avatar/AvatarButton.tsx +++ b/src/components/@molecules/ProfileEditor/Avatar/AvatarButton.tsx @@ -3,11 +3,13 @@ import { ComponentProps, useRef } from 'react' // import { useTranslation } from 'react-i18next' // import { DropdownItem } from '@ensdomains/thorin/dist/types/components/molecules/Dropdown/Dropdown' // import { LegacyDropdown } from '@app/omponents/@molecules/LegacyDropdown/LegacyDropdown' +import { showOpenImagePicker } from '@hairy/browser-utils' import styled, { css } from 'styled-components' import { Avatar, Dropdown } from '@ensdomains/thorin' import CameraIcon from '@app/assets/Camera.svg' +import func from 'deploy/00_deploy_bulk_renewal' const Container = styled.button<{ $error?: boolean; $validated?: boolean; $dirty?: boolean }>( ({ theme, $validated, $dirty, $error }) => css` @@ -128,16 +130,23 @@ Props) => { // const dropdownProps = setIsOpen // ? ({ isOpen, setIsOpen } as { isOpen: boolean; setIsOpen: Dispatch> }) // : ({} as { isOpen: never; setIsOpen: never }) - + async function onChange() { + const [file] = await showOpenImagePicker({multiple: false}) + onSelectOption?.('upload') + onAvatarFileChange?.(file) + } return ( - - {!validated && !error && ( - - - - )} - + + {!validated && !error && ( + + + + )} + + + {/* { onAvatarFileChange?.(e.target.files[0]) } }} - /> + /> */} // { const image = imageRef.current - if (canvasRef && !image.src) { + if (canvasRef && !image.src && avatar) { image.src = URL.createObjectURL(avatar) image.onload = handleImageLoad } diff --git a/src/components/@molecules/ProfileEditor/Avatar/AvatarUpload.tsx b/src/components/@molecules/ProfileEditor/Avatar/AvatarUpload.tsx index b673aaf..e32fadb 100755 --- a/src/components/@molecules/ProfileEditor/Avatar/AvatarUpload.tsx +++ b/src/components/@molecules/ProfileEditor/Avatar/AvatarUpload.tsx @@ -11,6 +11,7 @@ import { useChainName } from '@app/hooks/useChainName' import { useQueryKeys } from '../../../../utils/cacheKeyFactory' import { AvCancelButton, CropComponent } from './AvatarCrop' +import { helperPostPinFileToIPFS } from './helperPostPinFileToIPFS' const Container = styled.div(({ theme }) => [ css` @@ -78,31 +79,12 @@ const UploadComponent = ({ }) const { mutate: signAndUpload, isLoading } = useMutation(async () => { - let baseURL = process.env.NEXT_PUBLIC_AVUP_ENDPOINT || `https://ens.xyz` - if (network !== 'mainnet') { - baseURL = `${baseURL}/${network}` - } - const endpoint = `${baseURL}/${name}` - - const sig = await signTypedDataAsync() - const fetched = (await fetch(endpoint, { - method: 'PUT', - headers: { - // eslint-disable-next-line @typescript-eslint/naming-convention - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - expiry, - dataURL, - sig, - }), - }).then((res) => res.json())) as any - - if (fetched.message === 'uploaded') { - queryClient.invalidateQueries(queryKeys) - return handleSubmit('upload', endpoint, dataURL) - } - throw new Error(fetched.message) + + await signTypedDataAsync() + + const endpoint = await helperPostPinFileToIPFS({ file: base64ToFile(dataURL, name) }) + + handleSubmit('upload', endpoint, dataURL) }) return ( @@ -126,6 +108,18 @@ const UploadComponent = ({ ) } +function base64ToFile(base64: string, fileName: string) { + let arr = base64.split(","); + let mime = arr[0].match(/:(.\*?);/)?.[1]; + let bstr = window.atob(arr[1]); + let n = bstr.length; + let u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new File([u8arr], fileName, { type: mime }); +} + export const AvatarUpload = ({ avatar, handleCancel, diff --git a/src/components/@molecules/ProfileEditor/Avatar/helperPostPinFileToIPFS.ts b/src/components/@molecules/ProfileEditor/Avatar/helperPostPinFileToIPFS.ts new file mode 100644 index 0000000..a50e7aa --- /dev/null +++ b/src/components/@molecules/ProfileEditor/Avatar/helperPostPinFileToIPFS.ts @@ -0,0 +1,29 @@ +import { erc721ABI } from 'wagmi' + +export interface PostPinFileToIPFSData { + file: File + metadata?: Record +} + +const baseURL = 'https://api.pinata.cloud' +const headers = { + pinata_api_key: `${process.env.NEXT_PUBLIC_PINATA_API_KEY}`, + pinata_secret_api_key: `${process.env.NEXT_PUBLIC_PINATA_SECRET_API_KEY}`, +} + +export async function helperPostPinFileToIPFS(data: PostPinFileToIPFSData) { + const metadata = data.metadata || { name: data.file.name } + + const body = new FormData() + + body.append('pinataMetadata', JSON.stringify(metadata)) + body.append('file', data.file) + + const response = await fetch(`${baseURL}/pinning/pinFileToIPFS`, { + method: 'POST', + body, + headers, + }) + const result = await response.json() as any + return `https://gateway.pinata.cloud/ipfs/${result.IpfsHash}` +} diff --git a/src/hooks/useAvatar.ts b/src/hooks/useAvatar.ts index 5252846..f1e3488 100755 --- a/src/hooks/useAvatar.ts +++ b/src/hooks/useAvatar.ts @@ -5,6 +5,7 @@ import { useQueryKeys } from '@app/utils/cacheKeyFactory' import { ensNftImageUrl, imageUrlUnknownRecord } from '@app/utils/utils' import { useContractAddress } from './useContractAddress' +import { useProfile } from './useProfile' const fetchImg = async (url: string) => new Promise((resolve) => { @@ -34,18 +35,9 @@ const fetchImg = async (url: string) => }) export const useAvatar = (name: string | null | undefined, network: number, noCache?: boolean) => { - const { data, isLoading, status } = useQuery( - useQueryKeys().avatar.avatar(name), - () => fetchImg(imageUrlUnknownRecord(name!, network)), - { - enabled: !!name, - cacheTime: noCache ? 0 : 60000, - staleTime: 60000, - refetchOnMount: false, - }, - ) - - return { avatar: data, isLoading, status } + const {profile, loading, status} = useProfile(name!) + const avatar = profile?.records?.texts?.find(t => t.key === 'avatar')?.value + return { avatar: avatar, isLoading: loading, status } } export const useNFTImage = (name: string | undefined, network: number) => {