From b394c308625e349351800d45073e5e7ec847d2dd Mon Sep 17 00:00:00 2001 From: aeesh Date: Mon, 28 Mar 2022 10:05:01 +0100 Subject: [PATCH 01/21] Add NFT ui --- src/components/AddressBlock/index.tsx | 3 + src/components/InputAddress/index.tsx | 7 ++- src/contracts/NFT/components/NFTAdd/index.tsx | 32 ++++++++++ src/contracts/NFT/components/NFTAdd/style.ts | 56 +++++++++++++++++ .../NFT/components/NFTAddModal/index.tsx | 61 +++++++++++++++++++ .../NFT/components/NFTAddModal/style.ts | 30 +++++++++ .../NFT/components/NFTGallery/index.tsx | 2 + src/locales/en-US.json | 8 ++- 8 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 src/contracts/NFT/components/NFTAdd/index.tsx create mode 100644 src/contracts/NFT/components/NFTAdd/style.ts create mode 100644 src/contracts/NFT/components/NFTAddModal/index.tsx create mode 100644 src/contracts/NFT/components/NFTAddModal/style.ts diff --git a/src/components/AddressBlock/index.tsx b/src/components/AddressBlock/index.tsx index 0c282a36..5289b503 100644 --- a/src/components/AddressBlock/index.tsx +++ b/src/components/AddressBlock/index.tsx @@ -32,6 +32,7 @@ import BeaconPermission from '../../featureModals/Beacon/BeaconPermission'; import BeaconInfo from '../../featureModals/Beacon/BeaconInfo'; import BeaconDisabled from '../../featureModals/Beacon/BeaconDisabled'; import PlentyHarvestModal from '../../contracts/Plenty/components/HarvestModal'; +import NFTAddModal from '../../contracts/NFT/components/NFTAddModal'; import KolibriHarvestModal from '../../contracts/KolibriToken/components/HarvestModal'; import { setModalOpen, clearModal } from '../../reduxContent/modal/actions'; import { changeAccountThunk } from '../../reduxContent/app/thunks'; @@ -294,6 +295,7 @@ function AddressBlock(props: Props) { const isBeaconDisabledModalOpen = isModalOpen && activeModal === 'beaconDisable'; const isDelegateModalOpen = isModalOpen && activeModal === 'delegate_contract'; const isPlentyHarvestModalOpen = isModalOpen && activeModal === 'PlentyHarvest'; + const isNFTAddModalOpen = isModalOpen && activeModal === 'NFTAdd'; const isKolibriHarvestModalOpen = isModalOpen && activeModal === 'KolibriHarvest'; return ( @@ -483,6 +485,7 @@ function AddressBlock(props: Props) { )} {isPlentyHarvestModalOpen && setIsModalOpen(false, 'PlentyHarvest')} />} + {isNFTAddModalOpen && setIsModalOpen(false, 'NFTAdd')} />} {isKolibriHarvestModalOpen && setIsModalOpen(false, 'KolibriHarvest')} />} {isDelegateModalOpen && ( diff --git a/src/components/InputAddress/index.tsx b/src/components/InputAddress/index.tsx index 4bfabbda..e9a04166 100644 --- a/src/components/InputAddress/index.tsx +++ b/src/components/InputAddress/index.tsx @@ -59,7 +59,7 @@ interface Props { onChange: (val: string) => void; tooltip?: boolean; address?: string; - operationType: 'send' | 'delegate' | 'invoke' | 'send_babylon' | 'tz1'; // TODO: enum + operationType: 'send' | 'delegate' | 'invoke' | 'send_babylon' | 'tz1' | 'addNFT'; // TODO: enum onIssue?: (error: boolean) => void; onAddressType?: (type: AddressType) => void; } @@ -114,6 +114,9 @@ function InputAddress(props: Props) { } else if (operationType === 'tz1') { firstCharactersRegEx = /^(tz1|edpk)/; regErrorTxt = t('components.inputAddress.errors.verify_tz1'); + } else if (operationType === 'addNFT') { + firstCharactersRegEx = /^(KT1)/; + regErrorTxt = t('components.nftGallery.errors.invalid_address'); } return { firstCharactersRegEx, regErrorTxt }; @@ -147,7 +150,7 @@ function InputAddress(props: Props) { errorState = false; } else { addressType = getAddressType(addressText, account[0].script); - if (addressType === AddressType.Smart && operationType !== 'invoke') { + if (addressType === AddressType.Smart && operationType !== ('invoke' && 'addNFT')) { newError = t('components.inputAddress.errors.use_interact'); errorState = true; } diff --git a/src/contracts/NFT/components/NFTAdd/index.tsx b/src/contracts/NFT/components/NFTAdd/index.tsx new file mode 100644 index 00000000..7621a95d --- /dev/null +++ b/src/contracts/NFT/components/NFTAdd/index.tsx @@ -0,0 +1,32 @@ +import React, { useState } from 'react'; +import { useDispatch } from 'react-redux'; + +import SearchIcon from '@mui/icons-material/Search'; + +import { AddIcon, SearchForm, SearchInput, AddButton } from './style'; +import { RowContainer } from '../../../components/style'; +import { setModalOpen } from '../../../../reduxContent/modal/actions'; + +export const NFTAdd = () => { + const dispatch = useDispatch(); + + const [search, setSearch] = useState(''); + + return ( + + + } + // onChange={onSearchTokens} + // value={search} + /> + + } onClick={() => dispatch(setModalOpen(true, 'NFTAdd'))} disableRipple={true}> + Add NFT + + + ); +}; diff --git a/src/contracts/NFT/components/NFTAdd/style.ts b/src/contracts/NFT/components/NFTAdd/style.ts new file mode 100644 index 00000000..8eea8020 --- /dev/null +++ b/src/contracts/NFT/components/NFTAdd/style.ts @@ -0,0 +1,56 @@ +import styled, { css } from 'styled-components'; +import { styled as mStyled } from '@mui/system'; +import { withStyles } from '@mui/styles'; +import Button from '@mui/material/Button'; +import InputBase from '@mui/material/InputBase'; +import FormControl from '@mui/material/FormControl'; +import AddCircle from '@mui/icons-material/AddCircle'; + +import { ms } from '../../../../styles/helpers'; + +export const AddButton = styled(Button)` + align-self: center; + cursor: pointer; + color: ${({ theme: { colors } }) => colors.accent} !important; + margin: 35px 37px 44px 0 !important; + padding: 0 !important; + &:hover { + background: transparent !important; + } +`; + +export const SearchForm = mStyled(FormControl)({ + display: 'flex', + width: '383px', + margin: '27px 0 36px 43px', +}); + +export const SearchInput = withStyles((theme) => ({ + root: { + 'label + &': { + marginTop: theme.spacing(3), + }, + backgroundColor: '#F4F4F4', + borderRadius: '4px', + height: '32px', + maxWidth: '462px', + padding: '0px 12px', + }, + input: { + borderRadius: 4, + position: 'relative', + backgroundColor: '#F4F4F4', + fontSize: 14, + width: '100%', + padding: '0px 0px 0px 12px', + transition: theme.transitions.create(['border-color', 'box-shadow']), + }, +}))(InputBase); + +export const AddIcon = styled(AddCircle)` + &&& { + fill: ${({ theme: { colors } }) => colors.secondary}; + height: 16px; + width: 16px; + } +`; diff --git a/src/contracts/NFT/components/NFTAddModal/index.tsx b/src/contracts/NFT/components/NFTAddModal/index.tsx new file mode 100644 index 00000000..f56277cb --- /dev/null +++ b/src/contracts/NFT/components/NFTAddModal/index.tsx @@ -0,0 +1,61 @@ +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { useDispatch } from 'react-redux'; + +import Modal from '../../../../components/CustomModal'; + +import Loader from '../../../../components/Loader'; + +import InputAddress from '../../../../components/InputAddress'; +import TextField from '../../../../components/TextField'; +import { AddButton, AddNFTButtonContainer, InputAddressContainer, ModalHeader } from './style'; + +interface Props { + open: boolean; + onClose: () => void; +} + +const NFTAddModal = (props: Props) => { + const { t } = useTranslation(); + const dispatch = useDispatch(); + + const { open, onClose } = props; + + const [NFTContractAddress, setNFTContractAddress] = useState(''); + const [isNFTContractAddressIssue, setIsNFTContractAddressIssue] = useState(false); + const [isTokenDefinition, setIsTokenDefinition] = useState(false); + + const isDisabled = isNFTContractAddressIssue || !NFTContractAddress; + + return ( + + {t('components.nftGallery.add_nft_content')} + + { + setNFTContractAddress(val); + setIsTokenDefinition(false); + }} + onIssue={(flag) => setIsNFTContractAddressIssue(flag)} + /> + + + {isTokenDefinition && } + + + {isTokenDefinition && } + + + + (isTokenDefinition ? onClose() : setIsTokenDefinition(true))} disabled={isDisabled}> + {isTokenDefinition ? t('components.nftGallery.add_nft') : t('general.verbs.continue')} + + + + ); +}; + +export default NFTAddModal; diff --git a/src/contracts/NFT/components/NFTAddModal/style.ts b/src/contracts/NFT/components/NFTAddModal/style.ts new file mode 100644 index 00000000..260b9d13 --- /dev/null +++ b/src/contracts/NFT/components/NFTAddModal/style.ts @@ -0,0 +1,30 @@ +import styled from 'styled-components'; + +import Button from '../../../../components/Button'; + +export const InputAddressContainer = styled.div` + padding: 16px 76px; + height: 74px; + margin-bottom: 27px; +`; + +export const ModalHeader = styled.p` + padding: 0 76px; + color: ${({ theme: { colors } }) => colors.primary} !important; +`; + +export const AddNFTButtonContainer = styled.div` + display: flex; + justify-content: space-between; + align-items: flex-end; + margin-top: 42px; + padding: 29px 56px 47px 0; + background-color: ${({ theme: { colors } }) => colors.gray1}; + height: 124px; +`; + +export const AddButton = styled(Button)` + width: 194px; + height: 48px; + margin-left: auto; +`; diff --git a/src/contracts/NFT/components/NFTGallery/index.tsx b/src/contracts/NFT/components/NFTGallery/index.tsx index b8d10ade..eac2966c 100644 --- a/src/contracts/NFT/components/NFTGallery/index.tsx +++ b/src/contracts/NFT/components/NFTGallery/index.tsx @@ -19,6 +19,7 @@ import { tokensSupportURL } from '../../../../config.json'; import { NFTErrors } from '../NFTErrors'; import { NFTModal } from '../NFTModal'; +import { NFTAdd } from '../NFTAdd'; import { TokensDetailsModal } from '../../../../components/TokensDetailsModal'; const PER_PAGE = 2; @@ -96,6 +97,7 @@ export const NFTGallery: FunctionComponent = ({ const displayTokens = tab.value.toLowerCase() in collections ? collections[tab.value.toLowerCase()] : []; return ( + Date: Mon, 28 Mar 2022 22:30:13 +0100 Subject: [PATCH 02/21] parse Objkt Contract Address --- .../NFT/components/NFTAddModal/index.tsx | 39 ++++++++++++++++--- .../NFT/components/NFTAddModal/style.ts | 14 +++++++ 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/contracts/NFT/components/NFTAddModal/index.tsx b/src/contracts/NFT/components/NFTAddModal/index.tsx index f56277cb..cffbe5fd 100644 --- a/src/contracts/NFT/components/NFTAddModal/index.tsx +++ b/src/contracts/NFT/components/NFTAddModal/index.tsx @@ -1,7 +1,11 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useDispatch } from 'react-redux'; +import { useDispatch, useSelector, shallowEqual } from 'react-redux'; + +import { parseObjktContract } from '../../util'; +import { getMainNode } from '../../../../utils/settings'; +import { RootState } from '../../../../types/store'; import Modal from '../../../../components/CustomModal'; @@ -9,7 +13,7 @@ import Loader from '../../../../components/Loader'; import InputAddress from '../../../../components/InputAddress'; import TextField from '../../../../components/TextField'; -import { AddButton, AddNFTButtonContainer, InputAddressContainer, ModalHeader } from './style'; +import { AddButton, AddNFTButtonContainer, InputAddressContainer, ModalHeader, SuccessText } from './style'; interface Props { open: boolean; @@ -22,11 +26,32 @@ const NFTAddModal = (props: Props) => { const { open, onClose } = props; + const { selectedNode, nodesList } = useSelector((state: RootState) => state.settings, shallowEqual); + const mainNode = getMainNode(nodesList, selectedNode); + const { tezosUrl } = mainNode; + const [NFTContractAddress, setNFTContractAddress] = useState(''); const [isNFTContractAddressIssue, setIsNFTContractAddressIssue] = useState(false); - const [isTokenDefinition, setIsTokenDefinition] = useState(false); + const [isTokenDefinition, setIsTokenDefinition] = useState<{}>(); + const [isLoading, setIsLoading] = useState(false); + + const isDisabled = isNFTContractAddressIssue || !NFTContractAddress || isLoading; + + const parseContractAddress = async () => { + setIsLoading(true); + const tokenDefinition = await parseObjktContract(tezosUrl, NFTContractAddress); + setIsTokenDefinition(tokenDefinition); + console.log('tokenDefinition', tokenDefinition); + }; + + const addNFT = () => { + // TODO write NFT to file after confirmation. + onClose(); + }; - const isDisabled = isNFTContractAddressIssue || !NFTContractAddress; + useEffect(() => { + setIsLoading(false); + }, [isTokenDefinition]); return ( @@ -41,7 +66,9 @@ const NFTAddModal = (props: Props) => { }} onIssue={(flag) => setIsNFTContractAddressIssue(flag)} /> + {isTokenDefinition && NFT Contract found! } + {isLoading && } {isTokenDefinition && } @@ -50,7 +77,7 @@ const NFTAddModal = (props: Props) => { - (isTokenDefinition ? onClose() : setIsTokenDefinition(true))} disabled={isDisabled}> + (isTokenDefinition ? addNFT() : parseContractAddress())} disabled={isDisabled}> {isTokenDefinition ? t('components.nftGallery.add_nft') : t('general.verbs.continue')} diff --git a/src/contracts/NFT/components/NFTAddModal/style.ts b/src/contracts/NFT/components/NFTAddModal/style.ts index 260b9d13..587c2817 100644 --- a/src/contracts/NFT/components/NFTAddModal/style.ts +++ b/src/contracts/NFT/components/NFTAddModal/style.ts @@ -28,3 +28,17 @@ export const AddButton = styled(Button)` height: 48px; margin-left: auto; `; + +export const SuccessText = styled.p` + color: #259c90; + font-weight: 400; + font-size: 14px; + line-height: 22px; + margin-top: -42px; +`; + +export const LoaderWrapper = styled.div` + width: 100%; + padding: 80px 20px; + position: relative; +`; From 9080068656b7e096e2012c19fbd16ea17d2c2ae8 Mon Sep 17 00:00:00 2001 From: aeesh Date: Thu, 31 Mar 2022 00:24:21 +0100 Subject: [PATCH 03/21] Manage NFT Collections --- src/components/ManageNFTsModal/index.tsx | 29 ++++++++ src/components/ManageNFTsModal/style.ts | 67 +++++++++++++++++++ src/components/Table/index.tsx | 51 ++++++++++++++ src/components/Table/style.ts | 54 +++++++++++++++ .../NFT/components/NFTGallery/index.tsx | 4 +- src/locales/en-US.json | 5 +- 6 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 src/components/ManageNFTsModal/index.tsx create mode 100644 src/components/ManageNFTsModal/style.ts create mode 100644 src/components/Table/index.tsx create mode 100644 src/components/Table/style.ts diff --git a/src/components/ManageNFTsModal/index.tsx b/src/components/ManageNFTsModal/index.tsx new file mode 100644 index 00000000..a21a18a7 --- /dev/null +++ b/src/components/ManageNFTsModal/index.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +import CloseIcon from '@mui/icons-material/Close'; + +import { CloseButton, ModalHeader, StyledModalBox } from './style'; +import { ModalWrapper } from '../../contracts/components/style'; + +import TableComponent from '../Table'; + +import { StyledTable, StyledTableHead, StyledTableHeadCell, StyledTableRow, StyledTableCell, StyledTableBody } from '../Table/style'; +import { useSelector } from 'react-redux'; + +export const ManageNFTsModal = ({ open, onClose }) => { + const { t } = useTranslation(); + + return ( + + + {t('components.manageNFTsModal.modal_title')} + + + + + + + + ); +}; diff --git a/src/components/ManageNFTsModal/style.ts b/src/components/ManageNFTsModal/style.ts new file mode 100644 index 00000000..013c4add --- /dev/null +++ b/src/components/ManageNFTsModal/style.ts @@ -0,0 +1,67 @@ +import styled from 'styled-components'; +import IconButton from '@mui/material/IconButton'; +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; + +import { ModalBox } from '../../contracts/components/style'; + +export const styledTable = styled(Table)` + background: 'red; +`; + +export const StyledModalBox = styled(ModalBox)` + position: relative; + overflow: auto; + width: 570px; + min-height: 560px; + max-height: calc(100vh - 80px); + &::-webkit-scrollbar { + width: 6px; + } + &::-webkit-scrollbar-track { + background: ${({ theme: { colors } }) => colors.gray2}; + } + + &::-webkit-scrollbar-thumb { + background: ${({ theme: { colors } }) => colors.accent}; + border-radius: 4px; + } +`; + +export const ModalHeader = styled.h2` + background: ${({ theme: { colors } }) => colors.accent}; + font-size: 16px; + font-weight: 400; + color: ${({ theme: { colors } }) => colors.white}; + margin: 0; + padding: 15px 0 13px 16px; +`; + +export const CloseButton = styled(IconButton)` + &&& { + color: ${({ theme: { colors } }) => colors.white}; + position: absolute; + top: 5px; + right: 5px; + z-index: 1301; + cursor: pointer !important; + + span, + svg, + path { + cursor: pointer !important; + } + + :hover { + opacity: 0.7; + } + + @media all and (min-width: 768px) { + display: block; + } + } +`; diff --git a/src/components/Table/index.tsx b/src/components/Table/index.tsx new file mode 100644 index 00000000..c605bcb7 --- /dev/null +++ b/src/components/Table/index.tsx @@ -0,0 +1,51 @@ +import React from 'react'; + +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; + +import { StyledTableContainer, StyledTableHeadCell, StyledTableCell, StyledTableCellRight, StyledTableHeadCellRight, TokenTitle, TokenAddress } from './style'; +import { useSelector } from 'react-redux'; + +const TableComponent = (props) => { + const { headerOne, headerTwo, headerThree, tableData, icon } = props; + return ( + + + + + {headerOne} + {headerTwo} + {headerThree} + + + + {tableData && + tableData.map((data) => ( + + + User added collection 1 + KT5Qn6gt...VbJxtoH + + 4 OBKT + {icon && 'icon'} + + ))} + + + User added collection 1 + KT5Qn6gt...VbJxtoH + + 4 OBKT + {icon && 'icon'} + + +
+
+ ); +}; + +export default TableComponent; diff --git a/src/components/Table/style.ts b/src/components/Table/style.ts new file mode 100644 index 00000000..3a7c0fde --- /dev/null +++ b/src/components/Table/style.ts @@ -0,0 +1,54 @@ +import styled from 'styled-components'; + +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; + +export const StyledTableContainer = styled(TableContainer)` + margin-bottom: 40px; +`; +export const StyledTable = styled(Table)``; +export const StyledTableHead = styled(TableHead)``; +export const StyledTableBody = styled(TableBody)``; +export const StyledTableRow = styled(TableRow)``; +export const StyledTableHeadCell = styled(TableCell)` + height: 16px; + font-size: 16px; + font-weight: 400; + color: ${({ theme: { colors } }) => colors.gray3} !important; + border: 0 !important; + min-width: 148px; + padding: 0 16px !important; +`; +export const StyledTableHeadCellRight = styled(TableCell)` + height: 16px; + font-size: 16px; + font-weight: 400; + color: ${({ theme: { colors } }) => colors.gray3} !important; + border: 0 !important; + min-width: 148px; + padding: 0 16px !important; + text-align: right !important; +`; +export const StyledTableCell = styled(TableCell)` + border: 0 !important; +`; +export const StyledTableCellRight = styled(TableCell)` + border: 0 !important; + text-align: right !important; +`; + +export const TokenTitle = styled.p` + font-weight: 400; + font-size: 16px; + line-height: 16px; +`; + +export const TokenAddress = styled.p` + font-weight: 300; + font-size: 14px; + line-height: 16px; +`; diff --git a/src/contracts/NFT/components/NFTGallery/index.tsx b/src/contracts/NFT/components/NFTGallery/index.tsx index eac2966c..67c7c62d 100644 --- a/src/contracts/NFT/components/NFTGallery/index.tsx +++ b/src/contracts/NFT/components/NFTGallery/index.tsx @@ -21,6 +21,7 @@ import { NFTErrors } from '../NFTErrors'; import { NFTModal } from '../NFTModal'; import { NFTAdd } from '../NFTAdd'; import { TokensDetailsModal } from '../../../../components/TokensDetailsModal'; +import { ManageNFTsModal } from '../../../../components/ManageNFTsModal'; const PER_PAGE = 2; @@ -173,7 +174,8 @@ export const NFTGallery: FunctionComponent = ({ setCurrentNFTObject(null)} /> - setShowTokensDetailsModal(false)} /> + setShowTokensDetailsModal(false)} /> + {/* setShowTokensDetailsModal(false)} /> */} ); }; diff --git a/src/locales/en-US.json b/src/locales/en-US.json index 2079768f..18f92b55 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -38,7 +38,7 @@ "sell": "Sell", "add": "Add", "remove": "Remove", - "see_more": "View all supported NFTs" + "see_more": "Manage NFT Collections" }, "nouns": { "amount": "Amount", @@ -517,6 +517,9 @@ "logout": "LOG OUT", "help": "HELP" }, + "manageNFTsModal": { + "modal_title": "Manage NFT Collections" + }, "tokensDetailsModal": { "browse": "Browse objects", "modalTitle": "Tokens", From c0ba5bb8ac5c19cdd095bc0bbd02af74315c49b6 Mon Sep 17 00:00:00 2001 From: aeesh Date: Thu, 31 Mar 2022 03:55:47 +0100 Subject: [PATCH 04/21] modified parseObjktContract function --- src/contracts/NFT/util.ts | 177 +++++++++++++++++++++++++++++++++----- 1 file changed, 156 insertions(+), 21 deletions(-) diff --git a/src/contracts/NFT/util.ts b/src/contracts/NFT/util.ts index 3549eb60..c3822ed8 100644 --- a/src/contracts/NFT/util.ts +++ b/src/contracts/NFT/util.ts @@ -1,4 +1,13 @@ -import { ConseilQueryBuilder, ConseilOperator, KeyStore, MultiAssetTokenHelper, Signer, TezosConseilClient, TezosMessageUtils, TezosNodeReader } from 'conseiljs'; +import { + ConseilQueryBuilder, + ConseilOperator, + KeyStore, + MultiAssetTokenHelper, + Signer, + TezosConseilClient, + TezosMessageUtils, + TezosNodeReader, +} from 'conseiljs'; import { BigNumber } from 'bignumber.js'; import { JSONPath } from 'jsonpath-plus'; import { proxyFetch, ImageProxyServer, ImageProxyDataType } from 'nft-image-proxy'; @@ -25,7 +34,12 @@ function makeLastPriceQuery(operations) { lastPriceQuery = ConseilQueryBuilder.addPredicate(lastPriceQuery, 'kind', ConseilOperator.EQ, ['transaction']); lastPriceQuery = ConseilQueryBuilder.addPredicate(lastPriceQuery, 'status', ConseilOperator.EQ, ['applied']); lastPriceQuery = ConseilQueryBuilder.addPredicate(lastPriceQuery, 'internal', ConseilOperator.EQ, ['false']); - lastPriceQuery = ConseilQueryBuilder.addPredicate(lastPriceQuery, 'operation_group_hash', operations.length > 1 ? ConseilOperator.IN : ConseilOperator.EQ, operations); + lastPriceQuery = ConseilQueryBuilder.addPredicate( + lastPriceQuery, + 'operation_group_hash', + operations.length > 1 ? ConseilOperator.IN : ConseilOperator.EQ, + operations + ); lastPriceQuery = ConseilQueryBuilder.setLimit(lastPriceQuery, operations.length); return lastPriceQuery; @@ -162,7 +176,13 @@ export async function getKalamintNFTObjectDetails(tezosUrl: string, objectId: nu * @param {Node} node - the selected node. * @param {boolean} [skipDetails=false] - skip fetching the NFT object distance (expensive queries). */ -export async function getNFTCollections(tokens: ArtToken[], managerAddress: string, node: Node, skipDetails: boolean = false, dateBoundary?: Date): Promise { +export async function getNFTCollections( + tokens: ArtToken[], + managerAddress: string, + node: Node, + skipDetails: boolean = false, + dateBoundary?: Date +): Promise { const promises: Promise[] = []; tokens.map((token) => { switch (token.displayName.toLowerCase()) { @@ -181,7 +201,20 @@ export async function getNFTCollections(tokens: ArtToken[], managerAddress: stri default: try { - promises.push(getCollection(token.address, token.mapid, token.holderLocation || 'key', token.nftMetadataMap, token.provider || '', managerAddress, node, skipDetails, undefined, dateBoundary)); + promises.push( + getCollection( + token.address, + token.mapid, + token.holderLocation || 'key', + token.nftMetadataMap, + token.provider || '', + managerAddress, + node, + skipDetails, + undefined, + dateBoundary + ) + ); } catch (err) { console.log(`could not fetch collection for ${token.address}`); } @@ -218,7 +251,14 @@ export async function getNFTCollections(tokens: ArtToken[], managerAddress: stri * * @return {Promise} the list of NFT tokens grouped by type and the list of errors. */ -export async function getHicEtNuncCollection(tokenAddress: string, tokenMapId: number, managerAddress: string, node: Node, skipDetails: boolean = false, dateBoundary?: Date): Promise { +export async function getHicEtNuncCollection( + tokenAddress: string, + tokenMapId: number, + managerAddress: string, + node: Node, + skipDetails: boolean = false, + dateBoundary?: Date +): Promise { const { conseilUrl, apiKey, network } = node; const errors: NFTError[] = []; // Store errors to display to the user. @@ -226,7 +266,9 @@ export async function getHicEtNuncCollection(tokenAddress: string, tokenMapId: n let collectionQuery = ConseilQueryBuilder.blankQuery(); collectionQuery = ConseilQueryBuilder.addFields(collectionQuery, 'key', 'value', 'timestamp', 'operation_group_id'); collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'big_map_id', ConseilOperator.EQ, [tokenMapId]); - collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'key', ConseilOperator.STARTSWITH, [`Pair 0x${TezosMessageUtils.writeAddress(managerAddress)}`]); + collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'key', ConseilOperator.STARTSWITH, [ + `Pair 0x${TezosMessageUtils.writeAddress(managerAddress)}`, + ]); collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'value', ConseilOperator.EQ, [0], true); collectionQuery = ConseilQueryBuilder.setLimit(collectionQuery, 10_000); @@ -266,7 +308,14 @@ export async function getHicEtNuncCollection(tokenAddress: string, tokenMapId: n amount = Number(row.parameters.toString().replace(/^Pair ([0-9]+) [0-9]+/, '$1')); } else if (action === 'transfer') { action = 'collect'; - amount = Number(row.parameters.toString().replace(/[{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [(]Pair [0-9]+ [0-9]+[)] [}] [}]/, '$1')); + amount = Number( + row.parameters + .toString() + .replace( + /[{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [(]Pair [0-9]+ [0-9]+[)] [}] [}]/, + '$1' + ) + ); } else if (action === 'mint_OBJKT') { action = 'mint'; } else { @@ -390,7 +439,14 @@ export async function getHicEtNuncCollection(tokenAddress: string, tokenMapId: n * @param node * @param {boolean} [skipDetails=false] - skip fetching the NFT object distance (expensive queries). */ -export async function getKalamintCollection(tokenAddress: string, tokenMapId: number, managerAddress: string, node: Node, skipDetails: boolean = false, dateBoundary?: Date): Promise { +export async function getKalamintCollection( + tokenAddress: string, + tokenMapId: number, + managerAddress: string, + node: Node, + skipDetails: boolean = false, + dateBoundary?: Date +): Promise { const { conseilUrl, apiKey, network } = node; const errors: NFTError[] = []; // Store errors to display to the user. @@ -398,7 +454,9 @@ export async function getKalamintCollection(tokenAddress: string, tokenMapId: nu let collectionQuery = ConseilQueryBuilder.blankQuery(); collectionQuery = ConseilQueryBuilder.addFields(collectionQuery, 'key', 'value', 'timestamp', 'operation_group_id'); collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'big_map_id', ConseilOperator.EQ, [tokenMapId]); - collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'key', ConseilOperator.STARTSWITH, [`Pair 0x${TezosMessageUtils.writeAddress(managerAddress)}`]); + collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'key', ConseilOperator.STARTSWITH, [ + `Pair 0x${TezosMessageUtils.writeAddress(managerAddress)}`, + ]); collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'value', ConseilOperator.EQ, [0], true); collectionQuery = ConseilQueryBuilder.setLimit(collectionQuery, 10_000); @@ -427,7 +485,14 @@ export async function getKalamintCollection(tokenAddress: string, tokenMapId: nu amount = Number(row.parameters.toString().replace(/^Pair ([0-9]+) [0-9]+/, '$1')); } else if (action === 'transfer') { action = 'collect'; - amount = Number(row.parameters.toString().replace(/[{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [(]Pair [0-9]+ [0-9]+[)] [}] [}]/, '$1')); + amount = Number( + row.parameters + .toString() + .replace( + /[{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [(]Pair [0-9]+ [0-9]+[)] [}] [}]/, + '$1' + ) + ); } else if (action === 'mint') { action = 'mint'; } else { @@ -625,7 +690,14 @@ function makeUrl(source: string, type: string = '') { } } -export async function getPotusCollection(tokenAddress: string, tokenMapId: number, managerAddress: string, node: Node, skipDetails: boolean = false, dateBoundary?: Date): Promise { +export async function getPotusCollection( + tokenAddress: string, + tokenMapId: number, + managerAddress: string, + node: Node, + skipDetails: boolean = false, + dateBoundary?: Date +): Promise { const { conseilUrl, apiKey, network } = node; const errors: NFTError[] = []; // Store errors to display to the user. @@ -633,7 +705,9 @@ export async function getPotusCollection(tokenAddress: string, tokenMapId: numbe let collectionQuery = ConseilQueryBuilder.blankQuery(); collectionQuery = ConseilQueryBuilder.addFields(collectionQuery, 'key', 'value', 'timestamp', 'operation_group_id'); collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'big_map_id', ConseilOperator.EQ, [`${tokenMapId}`]); - collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'key', ConseilOperator.STARTSWITH, [`Pair 0x${TezosMessageUtils.writeAddress(managerAddress)}`]); + collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'key', ConseilOperator.STARTSWITH, [ + `Pair 0x${TezosMessageUtils.writeAddress(managerAddress)}`, + ]); collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'value', ConseilOperator.EQ, [0], true); collectionQuery = ConseilQueryBuilder.setLimit(collectionQuery, 10_000); @@ -745,7 +819,18 @@ export async function getPotusNFTObjectDetails(tezosUrl: string, objectId: numbe }; } -export async function getCollection(tokenAddress: string, tokenMapId: number, queryArg: 'key' | 'value', metadataMapId: number, provider: string, managerAddress: string, node: Node, skipDetails: boolean = false, urlPath?: string, dateBoundary?: Date): Promise { +export async function getCollection( + tokenAddress: string, + tokenMapId: number, + queryArg: 'key' | 'value', + metadataMapId: number, + provider: string, + managerAddress: string, + node: Node, + skipDetails: boolean = false, + urlPath?: string, + dateBoundary?: Date +): Promise { const { conseilUrl, apiKey, network } = node; const errors: NFTError[] = []; // Store errors to display to the user. @@ -753,10 +838,14 @@ export async function getCollection(tokenAddress: string, tokenMapId: number, qu collectionQuery = ConseilQueryBuilder.addFields(collectionQuery, 'key', 'value', 'timestamp', 'operation_group_id'); collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'big_map_id', ConseilOperator.EQ, [tokenMapId]); if (queryArg === 'key') { - collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'key', ConseilOperator.LIKE, [`0x${TezosMessageUtils.writeAddress(managerAddress)}`]); + collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'key', ConseilOperator.LIKE, [ + `0x${TezosMessageUtils.writeAddress(managerAddress)}`, + ]); collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'value', ConseilOperator.EQ, [0], true); } else if (queryArg === 'value') { - collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'value', ConseilOperator.EQ, [`0x${TezosMessageUtils.writeAddress(managerAddress)}`]); + collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'value', ConseilOperator.EQ, [ + `0x${TezosMessageUtils.writeAddress(managerAddress)}`, + ]); } else { throw new Error('invalid ledger query'); } @@ -789,7 +878,14 @@ export async function getCollection(tokenAddress: string, tokenMapId: number, qu amount = Number(row.parameters.toString().replace(/^Pair ([0-9]+) [0-9]+/, '$1')); } else if (action === 'transfer') { action = 'collect'; - amount = Number(row.parameters.toString().replace(/[{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [(]Pair [0-9]+ [0-9]+[)] [}] [}]/, '$1')); + amount = Number( + row.parameters + .toString() + .replace( + /[{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [(]Pair [0-9]+ [0-9]+[)] [}] [}]/, + '$1' + ) + ); } else if (action === 'mint' && tokenAddress === 'KT1KEa8z6vWXDJrVqtMrAeDVzsvxat3kHaCE') { // fxhash action = 'collect'; @@ -887,7 +983,14 @@ export async function getCollection(tokenAddress: string, tokenMapId: number, qu return { collection, errors }; } -export async function getHashThreeCollection(tokenAddress: string, tokenMapId: number, managerAddress: string, node: Node, skipDetails: boolean = false, dateBoundary?: Date): Promise { +export async function getHashThreeCollection( + tokenAddress: string, + tokenMapId: number, + managerAddress: string, + node: Node, + skipDetails: boolean = false, + dateBoundary?: Date +): Promise { const { conseilUrl, apiKey, network } = node; const errors: NFTError[] = []; // Store errors to display to the user. @@ -895,7 +998,9 @@ export async function getHashThreeCollection(tokenAddress: string, tokenMapId: n let collectionQuery = ConseilQueryBuilder.blankQuery(); collectionQuery = ConseilQueryBuilder.addFields(collectionQuery, 'key', 'value', 'timestamp', 'operation_group_id'); collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'big_map_id', ConseilOperator.EQ, [tokenMapId]); - collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'key', ConseilOperator.STARTSWITH, [`Pair 0x${TezosMessageUtils.writeAddress(managerAddress)}`]); + collectionQuery = ConseilQueryBuilder.addPredicate(collectionQuery, 'key', ConseilOperator.STARTSWITH, [ + `Pair 0x${TezosMessageUtils.writeAddress(managerAddress)}`, + ]); collectionQuery = ConseilQueryBuilder.setLimit(collectionQuery, 10_000); if (dateBoundary && dateBoundary.getTime() > GenesisBlockTime.getTime()) { @@ -925,7 +1030,14 @@ export async function getHashThreeCollection(tokenAddress: string, tokenMapId: n } else if (action === 'transfer') { // fa2 action = 'collect'; - amount = Number(row.parameters.toString().replace(/[{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [(]Pair [0-9]+ [0-9]+[)] [}] [}]/, '$1')); + amount = Number( + row.parameters + .toString() + .replace( + /[{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [{] Pair \"[1-9A-HJ-NP-Za-km-z]{36}\" [(]Pair [0-9]+ [0-9]+[)] [}] [}]/, + '$1' + ) + ); } else if (action === 'mint_OBJKT') { // hen action = 'mint'; @@ -1108,7 +1220,7 @@ export async function getCollectionSize(tokens: ArtToken[], managerAddress: stri return tokenCount; } -export async function parseObjktContract(tezosNode: string, contractAddress: string): Promise { +export async function parseObjktContract(tezosNode: string, contractAddress: string) { const tokenDefinition: ArtToken = { network: 'mainnet', symbol: '', @@ -1134,10 +1246,11 @@ export async function parseObjktContract(tezosNode: string, contractAddress: str const storageResult = await TezosNodeReader.getContractStorage(tezosNode, contractAddress); const ledgerMapId = Number(JSONPath({ path: '$.args[0].args[1].int', json: storageResult })[0]); + const metadataMapId = Number(JSONPath({ path: '$.args[0].args[2].int', json: storageResult })[0]); const contractMetadataMapId = Number(JSONPath({ path: '$.args[0].args[2].int', json: storageResult })[0]); const tokenMetadataMapId = Number(JSONPath({ path: '$.args[2].int', json: storageResult })[0]); - let contractMetadataJson: any = {}; + let contractMetadataJson = {}; try { const packedKey = TezosMessageUtils.encodeBigMapKey(Buffer.from(TezosMessageUtils.writePackedData('meta', 'string'), 'hex')); const contractMetadataResult = await TezosNodeReader.getValueForBigMapKey(tezosNode, contractMetadataMapId, packedKey); @@ -1154,6 +1267,28 @@ export async function parseObjktContract(tezosNode: string, contractAddress: str // } + try { + if (!tokenDefinition.displayName) { + const packedNftId = TezosMessageUtils.encodeBigMapKey(Buffer.from(TezosMessageUtils.writePackedData('', 'string'), 'hex')); + const nftInfo = await TezosNodeReader.getValueForBigMapKey(tezosNode, metadataMapId, packedNftId); + const ipfsUrlBytes = JSONPath({ path: '$.bytes', json: nftInfo })[0]; + const ipfsHash = Buffer.from(ipfsUrlBytes, 'hex').toString().slice(7); + + const nftDetails = await fetch(`https://cloudflare-ipfs.com/ipfs/${ipfsHash}`, { cache: 'no-store' }); + const nftDetailJson = await nftDetails.json(); + + if (nftDetailJson.homepage) { + tokenDefinition.displayHelpLink = nftDetailJson.homepage; + } + + if (nftDetailJson.name) { + tokenDefinition.displayName = nftDetailJson.name; + } + } + } catch { + // + } + tokenDefinition.mapid = ledgerMapId; tokenDefinition.nftMetadataMap = tokenMetadataMapId; From 5301398f3944215f62a9665438070978818345a5 Mon Sep 17 00:00:00 2001 From: aeesh Date: Thu, 31 Mar 2022 15:26:53 +0100 Subject: [PATCH 05/21] modified parseObjktContract function From bfd92861883e8c46e70e01403eb905e5709b50dc Mon Sep 17 00:00:00 2001 From: aeesh Date: Thu, 31 Mar 2022 15:30:13 +0100 Subject: [PATCH 06/21] search NFT --- src/contracts/NFT/components/NFTAdd/index.tsx | 32 ----------- src/contracts/NFT/components/NFTAdd/style.ts | 56 ------------------- .../NFT/components/NFTGallery/index.tsx | 43 ++++++++++++-- .../NFT/components/NFTGallery/style.ts | 54 +++++++++++++++++- 4 files changed, 91 insertions(+), 94 deletions(-) delete mode 100644 src/contracts/NFT/components/NFTAdd/index.tsx delete mode 100644 src/contracts/NFT/components/NFTAdd/style.ts diff --git a/src/contracts/NFT/components/NFTAdd/index.tsx b/src/contracts/NFT/components/NFTAdd/index.tsx deleted file mode 100644 index 7621a95d..00000000 --- a/src/contracts/NFT/components/NFTAdd/index.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, { useState } from 'react'; -import { useDispatch } from 'react-redux'; - -import SearchIcon from '@mui/icons-material/Search'; - -import { AddIcon, SearchForm, SearchInput, AddButton } from './style'; -import { RowContainer } from '../../../components/style'; -import { setModalOpen } from '../../../../reduxContent/modal/actions'; - -export const NFTAdd = () => { - const dispatch = useDispatch(); - - const [search, setSearch] = useState(''); - - return ( - - - } - // onChange={onSearchTokens} - // value={search} - /> - - } onClick={() => dispatch(setModalOpen(true, 'NFTAdd'))} disableRipple={true}> - Add NFT - - - ); -}; diff --git a/src/contracts/NFT/components/NFTAdd/style.ts b/src/contracts/NFT/components/NFTAdd/style.ts deleted file mode 100644 index 8eea8020..00000000 --- a/src/contracts/NFT/components/NFTAdd/style.ts +++ /dev/null @@ -1,56 +0,0 @@ -import styled, { css } from 'styled-components'; -import { styled as mStyled } from '@mui/system'; -import { withStyles } from '@mui/styles'; -import Button from '@mui/material/Button'; -import InputBase from '@mui/material/InputBase'; -import FormControl from '@mui/material/FormControl'; -import AddCircle from '@mui/icons-material/AddCircle'; - -import { ms } from '../../../../styles/helpers'; - -export const AddButton = styled(Button)` - align-self: center; - cursor: pointer; - color: ${({ theme: { colors } }) => colors.accent} !important; - margin: 35px 37px 44px 0 !important; - padding: 0 !important; - &:hover { - background: transparent !important; - } -`; - -export const SearchForm = mStyled(FormControl)({ - display: 'flex', - width: '383px', - margin: '27px 0 36px 43px', -}); - -export const SearchInput = withStyles((theme) => ({ - root: { - 'label + &': { - marginTop: theme.spacing(3), - }, - backgroundColor: '#F4F4F4', - borderRadius: '4px', - height: '32px', - maxWidth: '462px', - padding: '0px 12px', - }, - input: { - borderRadius: 4, - position: 'relative', - backgroundColor: '#F4F4F4', - fontSize: 14, - width: '100%', - padding: '0px 0px 0px 12px', - transition: theme.transitions.create(['border-color', 'box-shadow']), - }, -}))(InputBase); - -export const AddIcon = styled(AddCircle)` - &&& { - fill: ${({ theme: { colors } }) => colors.secondary}; - height: 16px; - width: 16px; - } -`; diff --git a/src/contracts/NFT/components/NFTGallery/index.tsx b/src/contracts/NFT/components/NFTGallery/index.tsx index 67c7c62d..281e3d30 100644 --- a/src/contracts/NFT/components/NFTGallery/index.tsx +++ b/src/contracts/NFT/components/NFTGallery/index.tsx @@ -1,4 +1,5 @@ import React, { FunctionComponent, ReactElement, useState } from 'react'; +import { useDispatch } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { NFT_PAGE_TABS, NFT_PROVIDERS } from '../../constants'; @@ -19,10 +20,15 @@ import { tokensSupportURL } from '../../../../config.json'; import { NFTErrors } from '../NFTErrors'; import { NFTModal } from '../NFTModal'; -import { NFTAdd } from '../NFTAdd'; import { TokensDetailsModal } from '../../../../components/TokensDetailsModal'; import { ManageNFTsModal } from '../../../../components/ManageNFTsModal'; +import SearchIcon from '@mui/icons-material/Search'; + +import { AddIcon, SearchForm, SearchInput, AddButton } from './style'; +import { RowContainer } from '../../../components/style'; +import { setModalOpen } from '../../../../reduxContent/modal/actions'; + const PER_PAGE = 2; /** @@ -73,7 +79,10 @@ export const NFTGallery: FunctionComponent = ({ clearErrors, }): ReactElement => { const { t } = useTranslation(); + const dispatch = useDispatch(); + const [showTokensDetailsModal, setShowTokensDetailsModal] = useState(false); + const [isSearch, setIsSearch] = useState(''); const onClickLink = (link: string) => openLink(link); @@ -96,9 +105,33 @@ export const NFTGallery: FunctionComponent = ({ return pageTabs.map((tab) => { const displayTokens = tab.value.toLowerCase() in collections ? collections[tab.value.toLowerCase()] : []; + const searchTokens = displayTokens.filter((token) => { + if (isSearch) { + const isToken = token.name.toLowerCase().includes(isSearch.toLowerCase()) || token.objectId.toString().includes(isSearch); + return isToken; + } else { + return token; + } + }); + return ( - + + + } + onChange={(e) => { + setIsSearch(e.target.value); + }} + value={isSearch} + /> + + } onClick={() => dispatch(setModalOpen(true, 'NFTAdd'))} disableRipple={true}> + Add NFT + + = ({ }} isEmpty={!displayTokens || displayTokens.length === 0} > - {displayTokens.map((token, index) => ( + {searchTokens.map((token, index) => ( setCurrentNFTObject(nftObj)} /> @@ -174,8 +207,8 @@ export const NFTGallery: FunctionComponent = ({ setCurrentNFTObject(null)} /> - setShowTokensDetailsModal(false)} /> - {/* setShowTokensDetailsModal(false)} /> */} + {/* setShowTokensDetailsModal(false)} /> */} + setShowTokensDetailsModal(false)} /> ); }; diff --git a/src/contracts/NFT/components/NFTGallery/style.ts b/src/contracts/NFT/components/NFTGallery/style.ts index bf9b90f8..5c2bb30f 100644 --- a/src/contracts/NFT/components/NFTGallery/style.ts +++ b/src/contracts/NFT/components/NFTGallery/style.ts @@ -1,4 +1,10 @@ -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; +import { styled as mStyled } from '@mui/system'; +import { withStyles } from '@mui/styles'; +import Button from '@mui/material/Button'; +import InputBase from '@mui/material/InputBase'; +import FormControl from '@mui/material/FormControl'; +import AddCircle from '@mui/icons-material/AddCircle'; /** * The wrapper positioning the loader on the center @@ -15,3 +21,49 @@ export const LoaderWrapper = styled.div` export const TokensCount = styled.span` margin-right: 4px; `; +export const AddButton = styled(Button)` + align-self: center; + cursor: pointer; + color: ${({ theme: { colors } }) => colors.accent} !important; + margin: 35px 37px 44px 0 !important; + padding: 0 !important; + &:hover { + background: transparent !important; + } +`; + +export const SearchForm = mStyled(FormControl)({ + display: 'flex', + width: '383px', + margin: '27px 0 36px 43px', +}); + +export const SearchInput = withStyles((theme) => ({ + root: { + 'label + &': { + marginTop: theme.spacing(3), + }, + backgroundColor: '#F4F4F4', + borderRadius: '4px', + height: '32px', + maxWidth: '462px', + padding: '0px 12px', + }, + input: { + borderRadius: 4, + position: 'relative', + backgroundColor: '#F4F4F4', + fontSize: 14, + width: '100%', + padding: '0px 0px 0px 12px', + transition: theme.transitions.create(['border-color', 'box-shadow']), + }, +}))(InputBase); + +export const AddIcon = styled(AddCircle)` + &&& { + fill: ${({ theme: { colors } }) => colors.secondary}; + height: 16px; + width: 16px; + } +`; From 979795e198c2414744c15926d74694f915fe14be Mon Sep 17 00:00:00 2001 From: aeesh Date: Thu, 31 Mar 2022 17:34:27 +0100 Subject: [PATCH 07/21] NFT collections --- src/components/ManageNFTsModal/index.tsx | 23 ++++++-- src/components/Table/index.tsx | 31 +++++----- src/components/Table/style.ts | 17 +----- .../NFT/components/NFTAddModal/index.tsx | 56 +++++++++++++++++-- .../NFT/components/NFTGallery/index.tsx | 5 +- 5 files changed, 86 insertions(+), 46 deletions(-) diff --git a/src/components/ManageNFTsModal/index.tsx b/src/components/ManageNFTsModal/index.tsx index a21a18a7..f6bda984 100644 --- a/src/components/ManageNFTsModal/index.tsx +++ b/src/components/ManageNFTsModal/index.tsx @@ -8,18 +8,33 @@ import { ModalWrapper } from '../../contracts/components/style'; import TableComponent from '../Table'; -import { StyledTable, StyledTableHead, StyledTableHeadCell, StyledTableRow, StyledTableCell, StyledTableBody } from '../Table/style'; import { useSelector } from 'react-redux'; +import { getLocalData } from '../../utils/localData'; -export const ManageNFTsModal = ({ open, onClose }) => { +export const ManageNFTsModal = ({ open, onClose, tokens }) => { const { t } = useTranslation(); + const localTokens = getLocalData('token'); + + const sortedTokens = tokens.sort((a, b) => b.balance - a.balance || a.displayName.localeCompare(b.displayName)); + const customSortedTokens = [localTokens].sort((a, b) => b.balance - a.balance || a.displayName.localeCompare(b.displayName)); + + const deleteToken = (item) => { + console.log('deleted', item); + }; return ( {t('components.manageNFTsModal.modal_title')} - - + deleteToken(token)} + /> + diff --git a/src/components/Table/index.tsx b/src/components/Table/index.tsx index c605bcb7..d7f98b64 100644 --- a/src/components/Table/index.tsx +++ b/src/components/Table/index.tsx @@ -2,16 +2,17 @@ import React from 'react'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; -import TableCell from '@mui/material/TableCell'; -import TableContainer from '@mui/material/TableContainer'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; -import { StyledTableContainer, StyledTableHeadCell, StyledTableCell, StyledTableCellRight, StyledTableHeadCellRight, TokenTitle, TokenAddress } from './style'; +import TezosAddress from '../TezosAddress'; + +import { StyledTableContainer, StyledTableHeadCell, StyledTableCell, StyledTableCellRight, StyledTableHeadCellRight, TokenTitle } from './style'; import { useSelector } from 'react-redux'; const TableComponent = (props) => { - const { headerOne, headerTwo, headerThree, tableData, icon } = props; + const { headerOne, headerTwo, headerThree, tableData, icon, deleteToken } = props; + return ( @@ -24,24 +25,18 @@ const TableComponent = (props) => { {tableData && - tableData.map((data) => ( - + tableData.map((data, index) => ( + - User added collection 1 - KT5Qn6gt...VbJxtoH + {data.displayName} + - 4 OBKT - {icon && 'icon'} + + deleteToken(data)}> + {icon && 'icon'} {/* TODO: Add delete Icon */} + ))} - - - User added collection 1 - KT5Qn6gt...VbJxtoH - - 4 OBKT - {icon && 'icon'} -
diff --git a/src/components/Table/style.ts b/src/components/Table/style.ts index 3a7c0fde..8f6fb7e2 100644 --- a/src/components/Table/style.ts +++ b/src/components/Table/style.ts @@ -1,26 +1,19 @@ import styled from 'styled-components'; -import Table from '@mui/material/Table'; -import TableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; import TableContainer from '@mui/material/TableContainer'; -import TableHead from '@mui/material/TableHead'; -import TableRow from '@mui/material/TableRow'; export const StyledTableContainer = styled(TableContainer)` margin-bottom: 40px; + padding-top: 27px; `; -export const StyledTable = styled(Table)``; -export const StyledTableHead = styled(TableHead)``; -export const StyledTableBody = styled(TableBody)``; -export const StyledTableRow = styled(TableRow)``; export const StyledTableHeadCell = styled(TableCell)` height: 16px; font-size: 16px; font-weight: 400; color: ${({ theme: { colors } }) => colors.gray3} !important; border: 0 !important; - min-width: 148px; + min-width: 230px; padding: 0 16px !important; `; export const StyledTableHeadCellRight = styled(TableCell)` @@ -46,9 +39,3 @@ export const TokenTitle = styled.p` font-size: 16px; line-height: 16px; `; - -export const TokenAddress = styled.p` - font-weight: 300; - font-size: 14px; - line-height: 16px; -`; diff --git a/src/contracts/NFT/components/NFTAddModal/index.tsx b/src/contracts/NFT/components/NFTAddModal/index.tsx index cffbe5fd..c04d908f 100644 --- a/src/contracts/NFT/components/NFTAddModal/index.tsx +++ b/src/contracts/NFT/components/NFTAddModal/index.tsx @@ -14,6 +14,9 @@ import Loader from '../../../../components/Loader'; import InputAddress from '../../../../components/InputAddress'; import TextField from '../../../../components/TextField'; import { AddButton, AddNFTButtonContainer, InputAddressContainer, ModalHeader, SuccessText } from './style'; +import { loadTokens } from '../../../../utils/wallet'; +import { updateTokensAction } from '../../../../reduxContent/wallet/actions'; +import { setLocalData } from '../../../../utils/localData'; interface Props { open: boolean; @@ -30,10 +33,15 @@ const NFTAddModal = (props: Props) => { const mainNode = getMainNode(nodesList, selectedNode); const { tezosUrl } = mainNode; + const tokens = useSelector((state: RootState) => state.wallet.tokens, shallowEqual); + // const tokens = loadTokens(mainNode.network); + const [NFTContractAddress, setNFTContractAddress] = useState(''); const [isNFTContractAddressIssue, setIsNFTContractAddressIssue] = useState(false); - const [isTokenDefinition, setIsTokenDefinition] = useState<{}>(); + const [isTokenDefinition, setIsTokenDefinition] = useState(); const [isLoading, setIsLoading] = useState(false); + const [helpLink, setHelpLink] = useState(''); + const [displayName, setDisplayName] = useState(''); const isDisabled = isNFTContractAddressIssue || !NFTContractAddress || isLoading; @@ -44,15 +52,34 @@ const NFTAddModal = (props: Props) => { console.log('tokenDefinition', tokenDefinition); }; - const addNFT = () => { + const addNFT = async () => { // TODO write NFT to file after confirmation. + tokens.push(isTokenDefinition); + setLocalData('token', isTokenDefinition); + dispatch(updateTokensAction([...tokens])); onClose(); + console.log('tokens', tokens); }; + useEffect(() => { + if (isTokenDefinition && !isTokenDefinition.displayHelpLink) { + isTokenDefinition.displayHelpLink = helpLink; + } + if (isTokenDefinition && !isTokenDefinition.displayName) { + isTokenDefinition.displayName = displayName; + } + return () => { + setHelpLink(''); + setDisplayName(''); + }; + }, [isTokenDefinition]); + useEffect(() => { setIsLoading(false); }, [isTokenDefinition]); + // KT1LjmAdYQCLBjwv4S2oFkEzyHVkomAf5MrW + return ( {t('components.nftGallery.add_nft_content')} @@ -66,16 +93,33 @@ const NFTAddModal = (props: Props) => { }} onIssue={(flag) => setIsNFTContractAddressIssue(flag)} /> - {isTokenDefinition && NFT Contract found! } + {isTokenDefinition && NFT Contract found!! } {isLoading && } - {isTokenDefinition && } + {isTokenDefinition && ( + { + setDisplayName(val); + }} + /> + )} - {isTokenDefinition && } + {isTokenDefinition && ( + { + setHelpLink(val); + }} + /> + )} - (isTokenDefinition ? addNFT() : parseContractAddress())} disabled={isDisabled}> {isTokenDefinition ? t('components.nftGallery.add_nft') : t('general.verbs.continue')} diff --git a/src/contracts/NFT/components/NFTGallery/index.tsx b/src/contracts/NFT/components/NFTGallery/index.tsx index 281e3d30..eeab01f4 100644 --- a/src/contracts/NFT/components/NFTGallery/index.tsx +++ b/src/contracts/NFT/components/NFTGallery/index.tsx @@ -20,7 +20,7 @@ import { tokensSupportURL } from '../../../../config.json'; import { NFTErrors } from '../NFTErrors'; import { NFTModal } from '../NFTModal'; -import { TokensDetailsModal } from '../../../../components/TokensDetailsModal'; +// import { TokensDetailsModal } from '../../../../components/TokensDetailsModal'; import { ManageNFTsModal } from '../../../../components/ManageNFTsModal'; import SearchIcon from '@mui/icons-material/Search'; @@ -207,8 +207,7 @@ export const NFTGallery: FunctionComponent = ({ setCurrentNFTObject(null)} /> - {/* setShowTokensDetailsModal(false)} /> */} - setShowTokensDetailsModal(false)} /> + setShowTokensDetailsModal(false)} /> ); }; From 47f8565037e2fe6cf9401529f69a55d7d582cb24 Mon Sep 17 00:00:00 2001 From: aeesh Date: Fri, 1 Apr 2022 18:39:51 +0100 Subject: [PATCH 08/21] add NFT --- src/components/ManageNFTsModal/index.tsx | 22 ++++- src/components/ManageNFTsModal/style.ts | 15 ++++ .../NFT/components/NFTAddModal/index.tsx | 6 -- .../NFT/components/NFTGallery/index.tsx | 9 +- .../NFT/components/NFTGallery/style.ts | 1 - src/reduxContent/wallet/thunks.ts | 90 ++++++++++++++++--- 6 files changed, 121 insertions(+), 22 deletions(-) diff --git a/src/components/ManageNFTsModal/index.tsx b/src/components/ManageNFTsModal/index.tsx index f6bda984..686d5672 100644 --- a/src/components/ManageNFTsModal/index.tsx +++ b/src/components/ManageNFTsModal/index.tsx @@ -1,18 +1,22 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; +import { useDispatch } from 'react-redux'; import CloseIcon from '@mui/icons-material/Close'; -import { CloseButton, ModalHeader, StyledModalBox } from './style'; +import { CloseButton, ModalHeader, StyledModalBox, StyledDivider, FooterCon, FooterText } from './style'; import { ModalWrapper } from '../../contracts/components/style'; import TableComponent from '../Table'; +import { AddButton, AddIcon } from '../../contracts/NFT/components/NFTGallery/style'; -import { useSelector } from 'react-redux'; import { getLocalData } from '../../utils/localData'; +import { setModalOpen } from '../../reduxContent/modal/actions'; export const ManageNFTsModal = ({ open, onClose, tokens }) => { const { t } = useTranslation(); + const dispatch = useDispatch(); + const localTokens = getLocalData('token'); const sortedTokens = tokens.sort((a, b) => b.balance - a.balance || a.displayName.localeCompare(b.displayName)); @@ -38,6 +42,20 @@ export const ManageNFTsModal = ({ open, onClose, tokens }) => { + + + Don’t see your NFTs? + } + onClick={() => { + onClose(); + dispatch(setModalOpen(true, 'NFTAdd')); + }} + disableRipple={true} + > + Add NFT + +
); diff --git a/src/components/ManageNFTsModal/style.ts b/src/components/ManageNFTsModal/style.ts index 013c4add..f8fc1dc7 100644 --- a/src/components/ManageNFTsModal/style.ts +++ b/src/components/ManageNFTsModal/style.ts @@ -6,6 +6,7 @@ import TableCell from '@mui/material/TableCell'; import TableContainer from '@mui/material/TableContainer'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; +import Divider from '@mui/material/Divider'; import { ModalBox } from '../../contracts/components/style'; @@ -65,3 +66,17 @@ export const CloseButton = styled(IconButton)` } } `; +export const StyledDivider = styled(Divider)` + border: 1px solid #e0e0e0; +`; +export const FooterCon = styled.div` + padding: 16px 0 16px 23px; +`; +export const FooterText = styled.p` + color: ${({ theme: { colors } }) => colors.gray3}; + margin: 0; + padding-bottom: 8px; + font-weight: 500; + font-size: 16px; + line-height: 16px; +`; diff --git a/src/contracts/NFT/components/NFTAddModal/index.tsx b/src/contracts/NFT/components/NFTAddModal/index.tsx index c04d908f..225a0f00 100644 --- a/src/contracts/NFT/components/NFTAddModal/index.tsx +++ b/src/contracts/NFT/components/NFTAddModal/index.tsx @@ -68,18 +68,12 @@ const NFTAddModal = (props: Props) => { if (isTokenDefinition && !isTokenDefinition.displayName) { isTokenDefinition.displayName = displayName; } - return () => { - setHelpLink(''); - setDisplayName(''); - }; }, [isTokenDefinition]); useEffect(() => { setIsLoading(false); }, [isTokenDefinition]); - // KT1LjmAdYQCLBjwv4S2oFkEzyHVkomAf5MrW - return ( {t('components.nftGallery.add_nft_content')} diff --git a/src/contracts/NFT/components/NFTGallery/index.tsx b/src/contracts/NFT/components/NFTGallery/index.tsx index eeab01f4..d911bfa9 100644 --- a/src/contracts/NFT/components/NFTGallery/index.tsx +++ b/src/contracts/NFT/components/NFTGallery/index.tsx @@ -106,7 +106,7 @@ export const NFTGallery: FunctionComponent = ({ return pageTabs.map((tab) => { const displayTokens = tab.value.toLowerCase() in collections ? collections[tab.value.toLowerCase()] : []; const searchTokens = displayTokens.filter((token) => { - if (isSearch) { + if (isSearch && token) { const isToken = token.name.toLowerCase().includes(isSearch.toLowerCase()) || token.objectId.toString().includes(isSearch); return isToken; } else { @@ -128,7 +128,12 @@ export const NFTGallery: FunctionComponent = ({ value={isSearch} /> - } onClick={() => dispatch(setModalOpen(true, 'NFTAdd'))} disableRipple={true}> + } + onClick={() => dispatch(setModalOpen(true, 'NFTAdd'))} + disableRipple={true} + style={{ margin: '35px 37px 44px 0' }} + > Add NFT diff --git a/src/contracts/NFT/components/NFTGallery/style.ts b/src/contracts/NFT/components/NFTGallery/style.ts index 5c2bb30f..886c67e1 100644 --- a/src/contracts/NFT/components/NFTGallery/style.ts +++ b/src/contracts/NFT/components/NFTGallery/style.ts @@ -25,7 +25,6 @@ export const AddButton = styled(Button)` align-self: center; cursor: pointer; color: ${({ theme: { colors } }) => colors.accent} !important; - margin: 35px 37px 44px 0 !important; padding: 0 !important; &:hover { background: transparent !important; diff --git a/src/reduxContent/wallet/thunks.ts b/src/reduxContent/wallet/thunks.ts index 8720285c..53d907a7 100644 --- a/src/reduxContent/wallet/thunks.ts +++ b/src/reduxContent/wallet/thunks.ts @@ -2,7 +2,22 @@ import path from 'path'; import { ipcRenderer } from 'electron'; import { push } from 'react-router-redux'; import TransportNodeHid from '@ledgerhq/hw-transport-node-hid'; -import { TezosNodeWriter, KeyStoreType, Tzip7ReferenceTokenHelper, MultiAssetTokenHelper, SingleAssetTokenHelper, TzbtcTokenHelper, WrappedTezosHelper, KolibriTokenHelper, ConseilServerInfo, TezosConseilClient, ConseilQueryBuilder, ConseilOperator, ConseilDataClient, TezosNodeReader } from 'conseiljs'; +import { + TezosNodeWriter, + KeyStoreType, + Tzip7ReferenceTokenHelper, + MultiAssetTokenHelper, + SingleAssetTokenHelper, + TzbtcTokenHelper, + WrappedTezosHelper, + KolibriTokenHelper, + ConseilServerInfo, + TezosConseilClient, + ConseilQueryBuilder, + ConseilOperator, + ConseilDataClient, + TezosNodeReader, +} from 'conseiljs'; import { KeyStoreUtils } from 'conseiljs-softsigner'; import { createMessageAction } from '../../reduxContent/message/actions'; import { CREATE, IMPORT } from '../../constants/CreationTypes'; @@ -25,7 +40,16 @@ import * as token2Util from '../../contracts/Token2Contract/util'; import { setWalletAction, setIdentitiesAction, addNewIdentityAction, updateIdentityAction, updateTokensAction } from './actions'; -import { logoutAction, setIsLoadingAction, setWalletIsSyncingAction, setNodesStatusAction, updateFetchedTimeAction, setLedgerAction, setIsLedgerConnectingAction, changeAccountAction } from '../app/actions'; +import { + logoutAction, + setIsLoadingAction, + setWalletIsSyncingAction, + setNodesStatusAction, + updateFetchedTimeAction, + setLedgerAction, + setIsLedgerConnectingAction, + changeAccountAction, +} from '../app/actions'; import { clearNFTCollectionsAction, endNFTSyncAction } from '../nft/actions'; @@ -303,7 +327,13 @@ export function syncTokenThunk(tokenAddress) { // ); } else if (tokens[tokenIndex].kind === TokenKind.tzip12) { if (tokens[tokenIndex].tokenIndex !== undefined) { - balanceAsync = MultiAssetTokenHelper.getAccountBalance(mainNode.tezosUrl, mapid, selectedParentHash, tokens[tokenIndex].tokenIndex || 0, tokens[tokenIndex].balancePath); + balanceAsync = MultiAssetTokenHelper.getAccountBalance( + mainNode.tezosUrl, + mapid, + selectedParentHash, + tokens[tokenIndex].tokenIndex || 0, + tokens[tokenIndex].balancePath + ); } else { balanceAsync = SingleAssetTokenHelper.getAccountBalance(mainNode.tezosUrl, mapid, selectedParentHash, tokens[tokenIndex].balancePath); } @@ -421,7 +451,9 @@ export function syncWalletThunk() { const keyCount = await TezosConseilClient.countKeysInMap(serverInfo, token.mapid); details = { ...details, holders: keyCount }; - const balance = await Tzip7ReferenceTokenHelper.getAccountBalance(mainNode.tezosUrl, mapid, selectedParentHash, token.balancePath).catch(() => 0); + const balance = await Tzip7ReferenceTokenHelper.getAccountBalance(mainNode.tezosUrl, mapid, selectedParentHash, token.balancePath).catch( + () => 0 + ); if (token.address === 'KT1JkoE42rrMBP9b2oDhbx6EUr26GcySZMUH' && details) { // TODO @@ -523,7 +555,12 @@ export function syncWalletThunk() { const keyCount = await TezosConseilClient.countKeysInMap(serverInfo, token.mapid); details = { ...details, holders: keyCount }; - const balance = await Tzip7ReferenceTokenHelper.getAccountBalance(mainNode.tezosUrl, token.mapid, selectedParentHash, token.balancePath).catch(() => 0); + const balance = await Tzip7ReferenceTokenHelper.getAccountBalance( + mainNode.tezosUrl, + token.mapid, + selectedParentHash, + token.balancePath + ).catch(() => 0); const transactions = []; // await tzip7Util.syncTokenTransactions(token.address, selectedParentHash, mainNode, token.transactions, token.kind); @@ -546,9 +583,17 @@ export function syncWalletThunk() { let balance = 0; if (token.tokenIndex !== undefined) { - balance = await MultiAssetTokenHelper.getAccountBalance(mainNode.tezosUrl, token.mapid, selectedParentHash, token.tokenIndex || 0, token.balancePath).catch(() => 0); + balance = await MultiAssetTokenHelper.getAccountBalance( + mainNode.tezosUrl, + token.mapid, + selectedParentHash, + token.tokenIndex || 0, + token.balancePath + ).catch(() => 0); } else { - balance = await SingleAssetTokenHelper.getAccountBalance(mainNode.tezosUrl, token.mapid, selectedParentHash, token.balancePath).catch(() => 0); + balance = await SingleAssetTokenHelper.getAccountBalance(mainNode.tezosUrl, token.mapid, selectedParentHash, token.balancePath).catch( + () => 0 + ); } const transactions = []; // await tzip12Util.syncTokenTransactions( @@ -580,7 +625,16 @@ export function syncAccountOrIdentityThunk(selectedAccountHash, selectedParentHa return async (dispatch) => { try { dispatch(setWalletIsSyncingAction(true)); - if (addressType === AddressType.Token || addressType === AddressType.Token2 || addressType === AddressType.TzBTC || addressType === AddressType.wXTZ || addressType === AddressType.kUSD || addressType === AddressType.BLND || addressType === AddressType.STKR || addressType === AddressType.plenty) { + if ( + addressType === AddressType.Token || + addressType === AddressType.Token2 || + addressType === AddressType.TzBTC || + addressType === AddressType.wXTZ || + addressType === AddressType.kUSD || + addressType === AddressType.BLND || + addressType === AddressType.STKR || + addressType === AddressType.plenty + ) { await dispatch(syncTokenThunk(selectedAccountHash)); } else if (selectedAccountHash === selectedParentHash) { await dispatch(syncIdentityThunk(selectedAccountHash)); @@ -601,6 +655,7 @@ function setTokensThunk() { const { selectedNode, nodesList } = state().settings; const mainNode = getMainNode(nodesList, selectedNode); const tokens = loadTokens(mainNode.network); + // add local storage data dispatch(updateTokensAction(tokens)); }; } @@ -634,11 +689,22 @@ export function importAddressThunk(activeTab, seed, pkh?, activationCode?, usern query = ConseilQueryBuilder.addPredicate(query, 'kind', ConseilOperator.EQ, ['activate_account'], false); query = ConseilQueryBuilder.setLimit(query, 1); - const account = await ConseilDataClient.executeEntityQuery({ url: conseilUrl, apiKey, network }, 'tezos', network, 'operations', query).catch(() => []); + const account = await ConseilDataClient.executeEntityQuery( + { url: conseilUrl, apiKey, network }, + 'tezos', + network, + 'operations', + query + ).catch(() => []); if (!account || account.length === 0) { const keyStore = getSelectedKeyStore([identity], identity.publicKeyHash, identity.publicKeyHash, false); const newKeyStore = { ...keyStore, storeType: KeyStoreType.Fundraiser }; - activating = await sendIdentityActivationOperation(tezosUrl, await cloneDecryptedSigner(state().app.signer, walletPassword), newKeyStore, activationCode).catch((err) => { + activating = await sendIdentityActivationOperation( + tezosUrl, + await cloneDecryptedSigner(state().app.signer, walletPassword), + newKeyStore, + activationCode + ).catch((err) => { throw new Error(`Count not activate account, due to – ${err.message}`); }); @@ -663,7 +729,9 @@ export function importAddressThunk(activeTab, seed, pkh?, activationCode?, usern }; identity.storeType = storeTypesMap[identity.storeType]; await dispatch(setSignerThunk(identity.secretKey, walletPassword)); - const account = await TezosConseilClient.getAccount({ url: conseilUrl, apiKey, network }, network, identity.publicKeyHash).catch(() => false); + const account = await TezosConseilClient.getAccount({ url: conseilUrl, apiKey, network }, network, identity.publicKeyHash).catch( + () => false + ); break; } From d23ab445e2891ef84d353446bb0729a93a4729bb Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Mon, 4 Apr 2022 21:13:26 -0400 Subject: [PATCH 09/21] - types --- src/contracts/NFT/util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contracts/NFT/util.ts b/src/contracts/NFT/util.ts index 6c4e9196..bf429234 100644 --- a/src/contracts/NFT/util.ts +++ b/src/contracts/NFT/util.ts @@ -1302,7 +1302,7 @@ export async function parseObjktContract(tezosNode: string, contractAddress: str const contractMetadataMapId = Number(JSONPath({ path: '$.args[0].args[2].int', json: storageResult })[0]); const tokenMetadataMapId = Number(JSONPath({ path: '$.args[2].int', json: storageResult })[0]); - let contractMetadataJson = {}; + let contractMetadataJson: any = {}; try { const packedKey = TezosMessageUtils.encodeBigMapKey(Buffer.from(TezosMessageUtils.writePackedData('meta', 'string'), 'hex')); const contractMetadataResult = await TezosNodeReader.getValueForBigMapKey(tezosNode, contractMetadataMapId, packedKey); From a3b8bf5ac49c0c07d1367da46e83186dccbc4401 Mon Sep 17 00:00:00 2001 From: aeesh Date: Wed, 6 Apr 2022 16:35:52 +0100 Subject: [PATCH 10/21] add nft to local storage --- package-lock.json | 2 +- .../NFT/components/NFTAddModal/index.tsx | 27 ++++++++++--------- src/package-lock.json | 24 ++++++++--------- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index cfa3f58e..a35fe782 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "tezori", - "version": "1.3.1-beta", + "version": "1.3.2-beta", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/contracts/NFT/components/NFTAddModal/index.tsx b/src/contracts/NFT/components/NFTAddModal/index.tsx index 225a0f00..17dae526 100644 --- a/src/contracts/NFT/components/NFTAddModal/index.tsx +++ b/src/contracts/NFT/components/NFTAddModal/index.tsx @@ -14,9 +14,8 @@ import Loader from '../../../../components/Loader'; import InputAddress from '../../../../components/InputAddress'; import TextField from '../../../../components/TextField'; import { AddButton, AddNFTButtonContainer, InputAddressContainer, ModalHeader, SuccessText } from './style'; -import { loadTokens } from '../../../../utils/wallet'; import { updateTokensAction } from '../../../../reduxContent/wallet/actions'; -import { setLocalData } from '../../../../utils/localData'; +import { setLocalData, getLocalData } from '../../../../utils/localData'; interface Props { open: boolean; @@ -34,7 +33,7 @@ const NFTAddModal = (props: Props) => { const { tezosUrl } = mainNode; const tokens = useSelector((state: RootState) => state.wallet.tokens, shallowEqual); - // const tokens = loadTokens(mainNode.network); + const customNftToken = getLocalData('token'); const [NFTContractAddress, setNFTContractAddress] = useState(''); const [isNFTContractAddressIssue, setIsNFTContractAddressIssue] = useState(false); @@ -53,22 +52,24 @@ const NFTAddModal = (props: Props) => { }; const addNFT = async () => { - // TODO write NFT to file after confirmation. - tokens.push(isTokenDefinition); - setLocalData('token', isTokenDefinition); - dispatch(updateTokensAction([...tokens])); - onClose(); - console.log('tokens', tokens); - }; - - useEffect(() => { if (isTokenDefinition && !isTokenDefinition.displayHelpLink) { isTokenDefinition.displayHelpLink = helpLink; } if (isTokenDefinition && !isTokenDefinition.displayName) { isTokenDefinition.displayName = displayName; } - }, [isTokenDefinition]); + tokens.push(isTokenDefinition); + if (customNftToken) { + setLocalData('token', [...customNftToken, isTokenDefinition]); + } else { + setLocalData('token', [isTokenDefinition]); + } + dispatch(updateTokensAction([...tokens])); + onClose(); + console.log('tokens', tokens); + }; + + console.log('customNftToken', customNftToken); useEffect(() => { setIsLoading(false); diff --git a/src/package-lock.json b/src/package-lock.json index 9bdfb4e4..92f3fc6b 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "tezori", - "version": "1.3.0-beta", + "version": "1.3.2-beta", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -104,9 +104,9 @@ "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==" }, "bignumber.js": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", - "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", + "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==" }, "bindings": { "version": "1.5.0", @@ -221,15 +221,15 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "conseiljs": { - "version": "5.0.9-5", - "resolved": "https://registry.npmjs.org/conseiljs/-/conseiljs-5.0.9-5.tgz", - "integrity": "sha512-Y20uj6/BHnnfz3hT1xG+sMhJ3RQK1lfPaOzXG6zfGsa/2MH0Oa826SaSopwHzgr5BZQ295GGwl3khxO5x+GFMg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/conseiljs/-/conseiljs-5.1.0.tgz", + "integrity": "sha512-8RnWAQNqk+0EKaCIcFQ8E0p45vVYLUiC0CUH3jf6rEEvxgZH7ZZFMDfExJa8lHmT4XXvRok324fWesasyI8nvw==", "requires": { "big-integer": "1.6.51", - "bignumber.js": "9.0.1", + "bignumber.js": "9.0.2", "blakejs": "1.1.0", "bs58check": "2.1.2", - "jsonpath-plus": "5.1.0", + "jsonpath-plus": "6.0.1", "moo": "0.5.0", "nearley": "2.19.1" }, @@ -240,9 +240,9 @@ "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==" }, "jsonpath-plus": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-5.1.0.tgz", - "integrity": "sha512-890w2Pjtj0iswAxalRlt2kHthi6HKrXEfZcn+ZNZptv7F3rUGIeDuZo+C+h4vXBHLEsVjJrHeCm35nYeZLzSBQ==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-6.0.1.tgz", + "integrity": "sha512-EvGovdvau6FyLexFH2OeXfIITlgIbgZoAZe3usiySeaIDm5QS+A10DKNpaPBBqqRSZr2HN6HVNXxtwUAr2apEw==" } } }, From 3dc70a39bb7e835adb47bb690662a5f50c0e6aeb Mon Sep 17 00:00:00 2001 From: aeesh Date: Wed, 6 Apr 2022 23:48:43 +0100 Subject: [PATCH 11/21] fetch token from storage --- .../NFT/components/NFTAddModal/index.tsx | 45 ++++++++++--------- src/reduxContent/wallet/thunks.ts | 5 ++- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/contracts/NFT/components/NFTAddModal/index.tsx b/src/contracts/NFT/components/NFTAddModal/index.tsx index 17dae526..ba71650d 100644 --- a/src/contracts/NFT/components/NFTAddModal/index.tsx +++ b/src/contracts/NFT/components/NFTAddModal/index.tsx @@ -37,7 +37,7 @@ const NFTAddModal = (props: Props) => { const [NFTContractAddress, setNFTContractAddress] = useState(''); const [isNFTContractAddressIssue, setIsNFTContractAddressIssue] = useState(false); - const [isTokenDefinition, setIsTokenDefinition] = useState(); + const [tokenDefinition, setTokenDefinition] = useState(); const [isLoading, setIsLoading] = useState(false); const [helpLink, setHelpLink] = useState(''); const [displayName, setDisplayName] = useState(''); @@ -46,23 +46,24 @@ const NFTAddModal = (props: Props) => { const parseContractAddress = async () => { setIsLoading(true); - const tokenDefinition = await parseObjktContract(tezosUrl, NFTContractAddress); - setIsTokenDefinition(tokenDefinition); - console.log('tokenDefinition', tokenDefinition); + const tokenDetails = await parseObjktContract(tezosUrl, NFTContractAddress); + tokenDetails.address = NFTContractAddress; + setTokenDefinition(tokenDetails); + console.log('tokenDetails', tokenDetails); }; const addNFT = async () => { - if (isTokenDefinition && !isTokenDefinition.displayHelpLink) { - isTokenDefinition.displayHelpLink = helpLink; + if (tokenDefinition && !tokenDefinition.displayHelpLink) { + tokenDefinition.displayHelpLink = helpLink; } - if (isTokenDefinition && !isTokenDefinition.displayName) { - isTokenDefinition.displayName = displayName; + if (tokenDefinition && !tokenDefinition.displayName) { + tokenDefinition.displayName = displayName; } - tokens.push(isTokenDefinition); + tokens.push(tokenDefinition); if (customNftToken) { - setLocalData('token', [...customNftToken, isTokenDefinition]); + setLocalData('token', [...customNftToken, tokenDefinition]); } else { - setLocalData('token', [isTokenDefinition]); + setLocalData('token', [tokenDefinition]); } dispatch(updateTokensAction([...tokens])); onClose(); @@ -73,7 +74,7 @@ const NFTAddModal = (props: Props) => { useEffect(() => { setIsLoading(false); - }, [isTokenDefinition]); + }, [tokenDefinition]); return ( @@ -84,19 +85,19 @@ const NFTAddModal = (props: Props) => { operationType="addNFT" onChange={(val) => { setNFTContractAddress(val); - setIsTokenDefinition(false); + setTokenDefinition(false); }} onIssue={(flag) => setIsNFTContractAddressIssue(flag)} /> - {isTokenDefinition && NFT Contract found!! } + {tokenDefinition && NFT Contract found!! } {isLoading && } - {isTokenDefinition && ( + {tokenDefinition && ( { setDisplayName(val); }} @@ -104,11 +105,11 @@ const NFTAddModal = (props: Props) => { )} - {isTokenDefinition && ( + {tokenDefinition && ( { setHelpLink(val); }} @@ -116,8 +117,8 @@ const NFTAddModal = (props: Props) => { )} - (isTokenDefinition ? addNFT() : parseContractAddress())} disabled={isDisabled}> - {isTokenDefinition ? t('components.nftGallery.add_nft') : t('general.verbs.continue')} + (tokenDefinition ? addNFT() : parseContractAddress())} disabled={isDisabled}> + {tokenDefinition ? t('components.nftGallery.add_nft') : t('general.verbs.continue')} diff --git a/src/reduxContent/wallet/thunks.ts b/src/reduxContent/wallet/thunks.ts index 53d907a7..affc0e3a 100644 --- a/src/reduxContent/wallet/thunks.ts +++ b/src/reduxContent/wallet/thunks.ts @@ -68,6 +68,7 @@ import * as tzip12Util from '../../contracts/Token2Contract/util'; import * as wxtzUtil from '../../contracts/WrappedTezos/util'; import * as plentyUtil from '../../contracts/Plenty/util'; import { JSONPath } from 'jsonpath-plus'; +import { getLocalData } from '../../utils/localData'; const { restoreIdentityFromFundraiser, restoreIdentityFromMnemonic, restoreIdentityFromSecretKey } = KeyStoreUtils; @@ -656,7 +657,9 @@ function setTokensThunk() { const mainNode = getMainNode(nodesList, selectedNode); const tokens = loadTokens(mainNode.network); // add local storage data - dispatch(updateTokensAction(tokens)); + const customTokens = getLocalData('token'); + dispatch(updateTokensAction(tokens.concat(customTokens || []))); + // dispatch(updateTokensAction(tokens)); }; } From 7579e63d3abf2766ebd46d2c10d3344ec12465cf Mon Sep 17 00:00:00 2001 From: aeesh Date: Fri, 8 Apr 2022 10:18:58 +0100 Subject: [PATCH 12/21] delete token --- resources/trash-can.svg | 3 +++ src/components/ManageNFTsModal/index.tsx | 19 ++++++++++++++++--- src/components/Table/index.tsx | 15 +++++++++++---- 3 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 resources/trash-can.svg diff --git a/resources/trash-can.svg b/resources/trash-can.svg new file mode 100644 index 00000000..744b10c0 --- /dev/null +++ b/resources/trash-can.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/ManageNFTsModal/index.tsx b/src/components/ManageNFTsModal/index.tsx index 686d5672..769914f8 100644 --- a/src/components/ManageNFTsModal/index.tsx +++ b/src/components/ManageNFTsModal/index.tsx @@ -10,7 +10,7 @@ import { ModalWrapper } from '../../contracts/components/style'; import TableComponent from '../Table'; import { AddButton, AddIcon } from '../../contracts/NFT/components/NFTGallery/style'; -import { getLocalData } from '../../utils/localData'; +import { getLocalData, setLocalData } from '../../utils/localData'; import { setModalOpen } from '../../reduxContent/modal/actions'; export const ManageNFTsModal = ({ open, onClose, tokens }) => { @@ -20,10 +20,23 @@ export const ManageNFTsModal = ({ open, onClose, tokens }) => { const localTokens = getLocalData('token'); const sortedTokens = tokens.sort((a, b) => b.balance - a.balance || a.displayName.localeCompare(b.displayName)); - const customSortedTokens = [localTokens].sort((a, b) => b.balance - a.balance || a.displayName.localeCompare(b.displayName)); + let customSortedTokens = []; + if (localTokens !== undefined) { + customSortedTokens = localTokens.sort((a, b) => b.balance - a.balance || a.displayName.localeCompare(b.displayName)); + } + function findIndexWithProps(array, attr, value) { + for (let i = 0; i < array.length; i += 1) { + if (array[i][attr] === value) { + return i; + } + } + return -1; + } const deleteToken = (item) => { - console.log('deleted', item); + const index = findIndexWithProps(localTokens, 'mapid', item.mapid); + localTokens.splice(index, 1); + setLocalData('token', localTokens); }; return ( diff --git a/src/components/Table/index.tsx b/src/components/Table/index.tsx index d7f98b64..966a6651 100644 --- a/src/components/Table/index.tsx +++ b/src/components/Table/index.tsx @@ -4,9 +4,12 @@ import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; +import Button from '@mui/material/Button'; import TezosAddress from '../TezosAddress'; +import trashCan from '../../../resources/trash-can.svg'; + import { StyledTableContainer, StyledTableHeadCell, StyledTableCell, StyledTableCellRight, StyledTableHeadCellRight, TokenTitle } from './style'; import { useSelector } from 'react-redux'; @@ -24,16 +27,20 @@ const TableComponent = (props) => { - {tableData && + {tableData !== undefined && tableData.map((data, index) => ( {data.displayName} - - deleteToken(data)}> - {icon && 'icon'} {/* TODO: Add delete Icon */} + + + {icon && ( + + )} ))} From f9b6e63ec602c3a8bde2e9aca03e6b0d61507686 Mon Sep 17 00:00:00 2001 From: aeesh Date: Mon, 11 Apr 2022 00:24:53 +0100 Subject: [PATCH 13/21] fix search error --- src/contracts/NFT/components/NFTGallery/index.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/contracts/NFT/components/NFTGallery/index.tsx b/src/contracts/NFT/components/NFTGallery/index.tsx index d911bfa9..24d54ae1 100644 --- a/src/contracts/NFT/components/NFTGallery/index.tsx +++ b/src/contracts/NFT/components/NFTGallery/index.tsx @@ -82,7 +82,7 @@ export const NFTGallery: FunctionComponent = ({ const dispatch = useDispatch(); const [showTokensDetailsModal, setShowTokensDetailsModal] = useState(false); - const [isSearch, setIsSearch] = useState(''); + const [search, setSearch] = useState(''); const onClickLink = (link: string) => openLink(link); @@ -106,9 +106,9 @@ export const NFTGallery: FunctionComponent = ({ return pageTabs.map((tab) => { const displayTokens = tab.value.toLowerCase() in collections ? collections[tab.value.toLowerCase()] : []; const searchTokens = displayTokens.filter((token) => { - if (isSearch && token) { - const isToken = token.name.toLowerCase().includes(isSearch.toLowerCase()) || token.objectId.toString().includes(isSearch); - return isToken; + if (search && token.name && token.objectId) { + const foundToken = token.name.toLowerCase().includes(search.toLowerCase()) || token.objectId.toString().includes(search); + return foundToken; } else { return token; } @@ -121,11 +121,11 @@ export const NFTGallery: FunctionComponent = ({ } + startAdornment={} onChange={(e) => { - setIsSearch(e.target.value); + setSearch(e.target.value); }} - value={isSearch} + value={search} /> Date: Mon, 11 Apr 2022 00:40:45 +0100 Subject: [PATCH 14/21] fix search error --- src/contracts/NFT/components/NFTGallery/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/contracts/NFT/components/NFTGallery/index.tsx b/src/contracts/NFT/components/NFTGallery/index.tsx index 24d54ae1..75e6b325 100644 --- a/src/contracts/NFT/components/NFTGallery/index.tsx +++ b/src/contracts/NFT/components/NFTGallery/index.tsx @@ -106,8 +106,8 @@ export const NFTGallery: FunctionComponent = ({ return pageTabs.map((tab) => { const displayTokens = tab.value.toLowerCase() in collections ? collections[tab.value.toLowerCase()] : []; const searchTokens = displayTokens.filter((token) => { - if (search && token.name && token.objectId) { - const foundToken = token.name.toLowerCase().includes(search.toLowerCase()) || token.objectId.toString().includes(search); + if (search) { + const foundToken = (token.name && token.name.toLowerCase().includes(search.toLowerCase())) || token.objectId.toString().includes(search); return foundToken; } else { return token; From 73032296c7c6e62902f0a81bb327ce703bebe985 Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Tue, 12 Apr 2022 17:28:49 -0400 Subject: [PATCH 15/21] - tezzards - batbits --- src/constants/Token.ts | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/constants/Token.ts b/src/constants/Token.ts index 48f76d94..8edffd27 100644 --- a/src/constants/Token.ts +++ b/src/constants/Token.ts @@ -886,6 +886,46 @@ export const knownTokenContracts: (Token | VaultToken | ArtToken)[] = [ displayHelpLink: 'flex.fashion', hideOnLanding: true, }, + { + network: 'mainnet', + address: 'KT1H436mFXZ1KqCVDUv2YQ23RnqMYKThhqah', + displayName: 'BatBits', + symbol: 'BB', + balance: 0, + transactions: [], + activeTab: COLLECTION, + kind: TokenKind.objkt, + scale: 0, + precision: 0, + round: 0, + mapid: 148210, + nftMetadataMap: 148212, + holderLocation: 'key', + provider: NFT_PROVIDERS.OBJKT_GENERIC, + helpLink: 'https://batbits.xyz', + displayHelpLink: 'batbits.xyz', + hideOnLanding: true, + }, + { + network: 'mainnet', + address: 'KT1LHHLso8zQWQWg1HUukajdxxbkGfNoHjh6', + displayName: 'Tezzardz', + symbol: 'FUKR', + balance: 0, + transactions: [], + activeTab: COLLECTION, + kind: TokenKind.objkt, + scale: 0, + precision: 0, + round: 0, + mapid: 12112, + nftMetadataMap: 12115, + holderLocation: 'key', + provider: NFT_PROVIDERS.OBJKT_GENERIC, + helpLink: 'https://tezzardz.xyz', + displayHelpLink: 'tezzardz.xyz', + hideOnLanding: true, + }, { network: 'mainnet', address: 'KT1XpYoPCxQnpgxLM22dkLDXBmTsDLc1S8nZ', @@ -1696,6 +1736,8 @@ export const knownContractNames = { KT1BvWGFENd4CXW5F3u4n31xKfJhmBGipoqF: '8bidou Market', KT1MxDwChiDwd6WBVs24g1NjERUoK622ZEFp: '8bidou NFT', + + KT1PHubm9HtyQEJ4BBpMTVomq6mhbfNZ9z5w: 'TEIA Market', }; export const knownMarketMetadata = [ From ff74f4f4e0498576663ec75aded5d86f80e7d268 Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Tue, 12 Apr 2022 17:30:15 -0400 Subject: [PATCH 16/21] - add new NFT contract cleanup --- src/contracts/NFT/components/NFTAddModal/index.tsx | 2 -- src/contracts/NFT/util.ts | 2 +- src/reduxContent/wallet/thunks.ts | 7 +++---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/contracts/NFT/components/NFTAddModal/index.tsx b/src/contracts/NFT/components/NFTAddModal/index.tsx index ba71650d..37704c88 100644 --- a/src/contracts/NFT/components/NFTAddModal/index.tsx +++ b/src/contracts/NFT/components/NFTAddModal/index.tsx @@ -47,9 +47,7 @@ const NFTAddModal = (props: Props) => { const parseContractAddress = async () => { setIsLoading(true); const tokenDetails = await parseObjktContract(tezosUrl, NFTContractAddress); - tokenDetails.address = NFTContractAddress; setTokenDefinition(tokenDetails); - console.log('tokenDetails', tokenDetails); }; const addNFT = async () => { diff --git a/src/contracts/NFT/util.ts b/src/contracts/NFT/util.ts index bf429234..2994e29b 100644 --- a/src/contracts/NFT/util.ts +++ b/src/contracts/NFT/util.ts @@ -1288,7 +1288,7 @@ export async function parseObjktContract(tezosNode: string, contractAddress: str hideOnLanding: true, marketAddress: '', - address: '', + address: contractAddress, displayName: '', mapid: -1, nftMetadataMap: -1, diff --git a/src/reduxContent/wallet/thunks.ts b/src/reduxContent/wallet/thunks.ts index affc0e3a..e7d183ea 100644 --- a/src/reduxContent/wallet/thunks.ts +++ b/src/reduxContent/wallet/thunks.ts @@ -656,10 +656,9 @@ function setTokensThunk() { const { selectedNode, nodesList } = state().settings; const mainNode = getMainNode(nodesList, selectedNode); const tokens = loadTokens(mainNode.network); - // add local storage data - const customTokens = getLocalData('token'); - dispatch(updateTokensAction(tokens.concat(customTokens || []))); - // dispatch(updateTokensAction(tokens)); + const builtinTokenAddresses = tokens.map((t) => t.address); + const customTokens = getLocalData('token') || []; + dispatch(updateTokensAction(tokens.concat(customTokens.filter((t) => !builtinTokenAddresses.includes(t.address))))); }; } From 42470c6e94cf51885fa3e506b06554d71d3633a0 Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Tue, 12 Apr 2022 17:30:25 -0400 Subject: [PATCH 17/21] - deps --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7f4d4dca..6348c402 100644 --- a/package.json +++ b/package.json @@ -218,7 +218,7 @@ "webpack-merge": "4.2.2" }, "dependencies": { - "@airgap/beacon-sdk": "2.3.10", + "@airgap/beacon-sdk": "2.3.12", "@emotion/react": "^11.4.1", "@emotion/styled": "^11.3.0", "@mui/icons-material": "^5.0.1", From 1c4a8ebfdf3aaa26e3803d50c3d8c4fdc9c9b87e Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Sun, 17 Apr 2022 11:21:29 -0400 Subject: [PATCH 18/21] - add NFT bugfix --- src/contracts/NFT/components/NFTAddModal/index.tsx | 8 ++++++-- src/contracts/NFT/util.ts | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/contracts/NFT/components/NFTAddModal/index.tsx b/src/contracts/NFT/components/NFTAddModal/index.tsx index 37704c88..40e05d8b 100644 --- a/src/contracts/NFT/components/NFTAddModal/index.tsx +++ b/src/contracts/NFT/components/NFTAddModal/index.tsx @@ -54,12 +54,16 @@ const NFTAddModal = (props: Props) => { if (tokenDefinition && !tokenDefinition.displayHelpLink) { tokenDefinition.displayHelpLink = helpLink; } + if (tokenDefinition && !tokenDefinition.displayName) { tokenDefinition.displayName = displayName; } - tokens.push(tokenDefinition); + if (customNftToken) { - setLocalData('token', [...customNftToken, tokenDefinition]); + const filteredTokens = customNftToken.filter((ct) => ct.address !== tokenDefinition.address); + filteredTokens.push(tokenDefinition); + + setLocalData('token', [...filteredTokens]); } else { setLocalData('token', [tokenDefinition]); } diff --git a/src/contracts/NFT/util.ts b/src/contracts/NFT/util.ts index 2994e29b..2082bf5b 100644 --- a/src/contracts/NFT/util.ts +++ b/src/contracts/NFT/util.ts @@ -1283,7 +1283,7 @@ export async function parseObjktContract(tezosNode: string, contractAddress: str scale: 0, precision: 0, round: 0, - holderLocation: 'value', + holderLocation: 'key', provider: 'OBJKT_GENERIC', hideOnLanding: true, marketAddress: '', From c5b62450e6eb589759ed04e8b417fab9a17ae157 Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Sun, 17 Apr 2022 11:23:53 -0400 Subject: [PATCH 19/21] - PXL token - PixelTACTICs NFT - Mooncakes NFT update - lending platform ithacanet test tokens --- resources/contracts/pxl-icon.png | Bin 0 -> 3978 bytes src/constants/Token.ts | 94 ++++++++- src/contracts/components/Swap/util.ts | 267 +++++++++++++++++++++++--- 3 files changed, 331 insertions(+), 30 deletions(-) create mode 100644 resources/contracts/pxl-icon.png diff --git a/resources/contracts/pxl-icon.png b/resources/contracts/pxl-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7b0ebae0b93738e6c2c63c21d5fac48d1cb499e8 GIT binary patch literal 3978 zcmd6q`8O2q7stmKV`wlajIA++EJK#Eqzp5%GbDS~nJihuhmd8AE&H0XXUR^;R`%>d zNXppvT~R}}ul|eg5BIs}-t+wMKJRm$`@C)>PDho2o|7H`05GVlVf8O^=f8k}FHXh4 zf|83w=cZ=j0RUWL`4?29(*Y*{0F#0`R>{C8V>?sNiMtElqezSl(b{gfa_`3q3;laY z%o8F$I6@-VoJ%cVnP>oHsts^h)5Mr2)MFXwb+vhwf4uC78Z+#`rCc}gGF{V4?~Ftj ze(Kf>A?Hjo5~W5a4a;mG`F~SQYG%@#GpDDf(=(6HuZxhUXLhzES~GXkUu8CLjTUGc zI5$Z)zQ@*n+@PWQYSV-p%r5&=nOy{Z^orZ)@J^(C`QmKhCwhRVT}H$Zi=HC$JMPm^ zn*jM@$sRF`k$^Xf*;(L?3$jUQB7}++j(BqoJI-3q@vd(qrSBc!PK5n)QCh(JUOl8d z?#9aTqAaDCu-3oSKr@NKmLjJm0G1u)U0Fp15n5ptTCpBMylMazQo$ti!(WfyL6Jg_ z>2@^#cmu401ywZl^mOzRpl@!;5_$P@sK~7E8xsv})F;LNBRtJuKVd}zwCDCtK38bD zs7@|`T;L1zQPrE0dOM8y5q*nYMVI`FaD(2or}_vu338ee%U)aNP&g4|(*NJ%8#RTm zHquiKtM6C=q>|X}9S;<=p=>C*LY>UYgZu`rx;tvTxuTc?q;!RSPOPd+{zQyOk&xfR zv`0al#AS}{=ixIOcQG}qD;-&fH-|lOSCrMmG_Y25F0(8c||M zDGTQCfs-twwO^ABo-WX5oEQ0LZcqd-!_%b+ zzv|lcIpO6hE&rH3)aDG`$k5-9SYhWeyvu1y9eVls^L zLLt4ZLnX1-svt}}Gia3a=OP$_xjR-{fA-I!QilLB!Ea+@jiK%2Bc@gVe8ZziEQoI_4$2ni| zF_3%f!Uu@7j&UvKALlO*`9Q$EK6~x=hML+Dt?4skwyLvif{EHVCPHntk+aQiQlEap z0ZkqAEUM!4WWnw+wgE)y)1L(%c6WrSMzW^9Zmuggd-u=XsfpXg7)PeNq3P#_c)BL6 z`CO~;uuIR61ct~bfOxjcokyX#J{P#gUvmP&2;lH$k$E{vW_4gga@{eXOiE+tvbF!`Sy^_o}4#Kx;!92G6{k6!7H;>`J9S2Ij>-Hf4B zRBjE9aOr0MnTqy!T*BH{bFT9x%7Be+Zut>LuWTa+<)5NGgG23< znEd(>R^&aPc|Qtm^E@w$Y+25AFh+EI(j7w_ec`K?(F`ZcycvaZsm$gH>hqHpy2y#` zGS4g~AaJ~!y>vq$ww1__4xq$)c?59cn$yJfo~3do+R0J-&5pk_j%@QzaWA!J$z|uQ z@H#9xoN2vRwr&~h+ABlX3rkE2@76cjxiLRsjr^+;QVPaH=;8zcHAS80!*1po=YteK zb}7r;sBh96&w%uzr^B?h_@Rt;j3NRPJve>J^ZKl>yciX@@-ncH(7Ee~OT?qoKtTXW z03rwqfFP&=z+S-rQ(4r>#C-L4=c@ft?m=qn&Z!B5Mgn&{-~CjE)+eXIo$e#&uy%p%X@UfajLTH$t==`$Zj=D)QjMEQcxIOgTYnIGW$n>BE zor{-s|I{a*3KZ6vHEed@MmO4I*uRFGMD#+xLbEX9H0HYC3c&Ke^W_uRfFc0b#) z(D_;A$CJc^)6`p^YpbPf%Rsj;^!%u^aK+173-`hSFfHdaVA`ClWF^IV-S! zv=eNQozBQ{joRqoWQT8f_^nQ+?t7RhP;xlGF7gm6=7WM2m*cWR7);64@fYu!Xm4E=kfURje5k>VJdxk;sm>NRYe|;ew#<9t@>h6zuk+zVtCFlw zr^mt1gO{0*P48)~`ZIs+xu>zMzj!mBFF*GUJZzl^oGNQt+{_&?q>FD?NmMo{RhfG+ zm=bqxar{}R^w)IrxuI!Ge;}b{UNIWQ(jFil0re*b3(nMD-}_58xt)rl6M_k-t0D2D zLedK_D8~%Xvr@+T*4YI#X3}|EtJeB07}-|8UtLa#T^8kvVwQ<-50MQWkx-p0J@sHZ z$y+Mf%{MQ2slE`Va(HZ887h3W{<{06;G4xzcaqjumS7A6SH-yNIpJge!v2#APj1P+ zx&AGh!0w(oe=JyYi60nlCqw@5BJ~!kAkOYyZoMT(eg9h6K=(XLxQ;sj?jNBa;aCUR zNy`!uGZOQrsb35l9PlD#IfPNqxvE%gg96KoxBEr zT>I{)Qp=iAGuDt(#xiYXDRy~3e0%GXw#DfY82ExOE<#7SS2+DqW3z8~>{+dqHn{d2 zZ{+$GYmu95x!IQea=_>fSkebZVf83Mfx_=81o4-~|HomVzO@UjY*1BW6aIO?RB5|s zOdGh<&08Kz9gWsh+xVha2UCw$l3o4nquqn(IdFJ^V6Icm-%fZ;@r0VGiKTnUhkZlv zEZ%x}ogNVqm7krPnhdL6hq-KNX!1sS;4;Rf8oc)C{fu=|)P2nB8dmt3@y1&3c?Ht& zm*zuJ#A)GP7Q2cO3!}#sBf8U1^Ox?n^iN%x%sR_O7N%Fpz-XxCLJ&m|1|#vPgTt?b zd=1s|t8~x!he~%Jtv526RI;e&FVLSZvdair&Od84J5P>!1X3Q@qp?o)IGT7gyXXAF zY`4!;ch`u&n62a4lptlWNULE{W8ElN?&p6!f2)h9{mm=pKB88|cBbwfd5B$oiK@Vx zbQ9|9$?wA>0v@{L4fXse_OSD_3Drof+T>)o>-8E;iA$bN4XnTTK<3tGjS&dbL!i_% zGDU8FwsifbP$W&u=t*>=Y2IUk+S7tNkOW3Y{V+$-BM9HY+ZBA#%8$1&WmiWHFb^A5 z80@dUl;m11=WWtR((8Do9>P2yDS$&fWN2752}ClV7)adx9mK2Q$;=+#(FlEtOSovP`dS4XRH~h6pEg~!Ml4$Mklsf zwMj_)9jS!mzBq((t;?XH|3}kq4tT>qJl;D|*kH3>ZqoX`_*KTj+L@I`SQ-C~fJ_+1 zUfy|XTNtyU-E=;ZX~^%%YGl9Ur4X>2+sS3~YJ0;gfI=yY+cFkt=MfRU{NgC-J_^!i z)Sb=XoLisuJiPFJYlB2)<IP9QZic+2Dk*@|wmnbZN0REhD<|RB6!F zOA7LpZR$j58~(mu%G;G30^sq!;VwL7pXN+twrn%_1Ctcb95N@Db+;aq!1mvwv1rS&46d%eJ{8W}`U0WB9 zr{bUvSEb4df7f#gzPR7!5f4AqpY5wk-9h5HN2?dL4WpqaUsX|4P3|FrOd^2-GK0*R5#gAlvJkEo!OH8XnYmK zJ9U6H0}ak$V6}-HydVo}Gb+JgEaD-&jBx4e+fTq8QZx6;;HOZHiZe+@cl*m&kbX)q zDyGc~UaA{zTZtat%;d(ZNUxkx-* literal 0 HcmV?d00001 diff --git a/src/constants/Token.ts b/src/constants/Token.ts index 8edffd27..762ec6cd 100644 --- a/src/constants/Token.ts +++ b/src/constants/Token.ts @@ -44,6 +44,7 @@ import ursaIcon from '../../resources/contracts/ursa-icon.png'; import materiaIcon from '../../resources/contracts/materia-icon.png'; import objktCreditIcon from '../../resources/contracts/objkt-credit-icon.svg'; import dogaIcon from '../../resources/contracts/doga-icon.png'; +import pxlIcon from '../../resources/contracts/pxl-icon.png'; export const knownTokenContracts: (Token | VaultToken | ArtToken)[] = [ { @@ -477,6 +478,41 @@ export const knownTokenContracts: (Token | VaultToken | ArtToken)[] = [ displayHelpLink: 'h3p.deconcept.com', hideOnLanding: true, }, + { + network: 'mainnet', + address: 'KT1F1mn2jbqQCJcsNgYKVAQjvenecNMY2oPK', + displayName: 'Pixel', + symbol: 'PXL', + balance: 0, + transactions: [], + activeTab: COLLECTION, + kind: TokenKind.tzip12, + icon: pxlIcon, + scale: 6, + precision: 6, + round: 2, + mapid: 21182, + helpLink: 'https://www.pixelpotus.com/', + displayHelpLink: 'pixelpotus.com', + }, + { + network: 'mainnet', + address: 'KT1VK8vevaKZNh68fonidY4792yLyrf5Ct3u', + displayName: 'PixelTACTICs', + symbol: 'TACTICs', + balance: 0, + transactions: [], + activeTab: COLLECTION, + kind: TokenKind.objkt, + scale: 0, + precision: 0, + round: 0, + mapid: 36518, + nftMetadataMap: 36521, + helpLink: 'https://www.pixeldebates.com/', + displayHelpLink: 'pixeldebates.com', + hideOnLanding: true, + }, { network: 'mainnet', address: 'KT1WGDVRnff4rmGzJUbdCRAJBmYt12BrPzdD', @@ -607,7 +643,7 @@ export const knownTokenContracts: (Token | VaultToken | ArtToken)[] = [ }, { network: 'mainnet', - address: 'KT1Qm7MHmbdiBzoRs7xqBiqoRxw7T2cxTTJN', + address: 'KT1CzVSa18hndYupV9NcXy3Qj7p8YFDZKVQv', displayName: 'Mooncakes', symbol: 'Mooncakes', balance: 0, @@ -617,8 +653,8 @@ export const knownTokenContracts: (Token | VaultToken | ArtToken)[] = [ scale: 0, precision: 0, round: 0, - mapid: 104507, - nftMetadataMap: 104513, + mapid: 127310, + nftMetadataMap: 127316, holderLocation: 'key', provider: NFT_PROVIDERS.OBJKT_GENERIC, helpLink: 'https://mooncakes.fun', @@ -1553,6 +1589,55 @@ export const knownTokenContracts: (Token | VaultToken | ArtToken)[] = [ balancePath: '$.args[0].int', helpLink: 'https://lugh.io', },*/ + { + network: 'ithacanet', + address: 'KT1XA22D7DazGGefGVGyWHH9Y2MTFmiPjxq3', + displayName: 'testUSDtez', + symbol: 'tUSDtz', + balance: 0, + transactions: [], + activeTab: TRANSACTIONS, + kind: TokenKind.usdtz, + icon: usdtzIcon, + scale: 6, + precision: 6, + round: 2, + mapid: 34654, + balancePath: '$.args[1].int', + }, + { + network: 'ithacanet', + address: 'KT1AAfsTHPnWT5cU77CUNQ2dcQNtAJ1jauPC', + displayName: 'testETHtez', + symbol: 'tETHtz', + balance: 0, + transactions: [], + activeTab: TRANSACTIONS, + kind: TokenKind.usdtz, + icon: ethtzIcon, + scale: 18, + precision: 18, + round: 2, + mapid: 34651, + balancePath: '$.args[1].int', + }, + { + network: 'ithacanet', + address: 'KT1D11fEJQuUGn4m161mHmZ7Lkayzq4Cv6xW', + displayName: 'testBTCtez', + symbol: 'tBTCtz', + balance: 0, + transactions: [], + activeTab: TRANSACTIONS, + kind: TokenKind.tzip12, + icon: btctzIcon, + scale: 8, + precision: 8, + round: 2, + mapid: 34646, + tokenIndex: 0, + balancePath: '$.int', + }, ]; export const knownTokenDescription = { @@ -1738,6 +1823,9 @@ export const knownContractNames = { KT1MxDwChiDwd6WBVs24g1NjERUoK622ZEFp: '8bidou NFT', KT1PHubm9HtyQEJ4BBpMTVomq6mhbfNZ9z5w: 'TEIA Market', + KT1Dq4XtyD83Bm7Nn4PMxj9MDp2n9HXijqkx: 'PixelDebates Tactics Claims', + KT1Qm7MHmbdiBzoRs7xqBiqoRxw7T2cxTTJN: 'Mooncakes', + KT1CzVSa18hndYupV9NcXy3Qj7p8YFDZKVQv: 'Mooncakes v2', }; export const knownMarketMetadata = [ diff --git a/src/contracts/components/Swap/util.ts b/src/contracts/components/Swap/util.ts index b03f79c1..03407bf2 100644 --- a/src/contracts/components/Swap/util.ts +++ b/src/contracts/components/Swap/util.ts @@ -118,6 +118,10 @@ export const tokenPoolMap = { quipuPool: '', vortexPool: 'KT1NoozaPXHKZHobxcheTWa1XLSTChUTgBg1', }, // doga + KT1F1mn2jbqQCJcsNgYKVAQjvenecNMY2oPK: { + dexterPool: '', + quipuPool: 'KT1UJ1hVTdiUen7H3zk1CXGC7PbANb57VkS4', + }, // pxl }; export function isTradeable(tokenAddress: string, tokenIndex?: number) { @@ -154,18 +158,43 @@ export function applyFees(amount: number, side: string, slippage: number = 0.01) return 0; } -export async function sendDexterBuy(tezosNode: string, keyStore: KeyStore, signer: Signer, tokenAddress: string, tokenIndex: number, poolAddress: string, notional: string, size: string): Promise { +export async function sendDexterBuy( + tezosNode: string, + keyStore: KeyStore, + signer: Signer, + tokenAddress: string, + tokenIndex: number, + poolAddress: string, + notional: string, + size: string +): Promise { const expiration = new Date(Date.now() + dexterExpirationPadding); let buyParams: string; if (tokenAddress === 'KT1PWx2mnDueood7fEmfbBDKx1D9BAnnXitn') { buyParams = `{"prim":"Pair","args":[{"string":"${keyStore.publicKeyHash}"},{"int":"${size}"},{"string":"${expiration.toISOString()}"}]}`; } else { - buyParams = `{ "prim": "Pair", "args": [ { "string": "${keyStore.publicKeyHash}" }, { "prim": "Pair", "args": [ { "int": "${size}" }, { "string":"${expiration.toISOString()}" } ] } ] }`; + buyParams = `{ "prim": "Pair", "args": [ { "string": "${ + keyStore.publicKeyHash + }" }, { "prim": "Pair", "args": [ { "int": "${size}" }, { "string":"${expiration.toISOString()}" } ] } ] }`; } try { - const r = await TezosNodeWriter.sendContractInvocationOperation(tezosNode, signer, keyStore, poolAddress, Number(notional), 0, 0, 0, 'xtzToToken', buyParams, TezosParameterFormat.Micheline, TezosConstants.HeadBranchOffset, true); + const r = await TezosNodeWriter.sendContractInvocationOperation( + tezosNode, + signer, + keyStore, + poolAddress, + Number(notional), + 0, + 0, + 0, + 'xtzToToken', + buyParams, + TezosParameterFormat.Micheline, + TezosConstants.HeadBranchOffset, + true + ); return r.operationGroupID.replace(/\\|"|\n|\r/g, ''); } catch (err) { @@ -173,23 +202,56 @@ export async function sendDexterBuy(tezosNode: string, keyStore: KeyStore, signe } } -export async function sendDexterSell(tezosNode: string, keyStore: KeyStore, signer: Signer, tokenAddress: string, tokenIndex: number, poolAddress: string, notional: string, size: string): Promise { +export async function sendDexterSell( + tezosNode: string, + keyStore: KeyStore, + signer: Signer, + tokenAddress: string, + tokenIndex: number, + poolAddress: string, + notional: string, + size: string +): Promise { const nextCounter = (await TezosNodeReader.getCounterForAccount(tezosNode, keyStore.publicKeyHash)) + 1; const approveParams = `{ "prim": "Pair", "args": [ { "string": "${poolAddress}" }, { "int": "${size}" } ] }`; - const approveOp = TezosNodeWriter.constructContractInvocationOperation(keyStore.publicKeyHash, nextCounter, tokenAddress, 0, 0, 0, 0, 'approve', approveParams); + const approveOp = TezosNodeWriter.constructContractInvocationOperation( + keyStore.publicKeyHash, + nextCounter, + tokenAddress, + 0, + 0, + 0, + 0, + 'approve', + approveParams + ); const expiration = new Date(Date.now() + dexterExpirationPadding); let sellParams: string; if (tokenAddress === 'KT1PWx2mnDueood7fEmfbBDKx1D9BAnnXitn') { // TODO - sellParams = `{"prim":"Pair","args":[{"string":"${keyStore.publicKeyHash}"},{"prim":"Pair","args":[{"int":"${size}"},{"prim":"Pair","args":[{"int":"${notional}"},{"string":"${expiration.toISOString()}"}]}]}]}`; + sellParams = `{"prim":"Pair","args":[{"string":"${ + keyStore.publicKeyHash + }"},{"prim":"Pair","args":[{"int":"${size}"},{"prim":"Pair","args":[{"int":"${notional}"},{"string":"${expiration.toISOString()}"}]}]}]}`; } else { - sellParams = `{ "prim": "Pair", "args": [ { "prim": "Pair", "args": [ { "string": "${keyStore.publicKeyHash}" }, { "string": "${keyStore.publicKeyHash}" } ] }, {"int": "${size}" }, { "int": "${notional}" }, { "string": "${expiration.toISOString()}" } ] }`; + sellParams = `{ "prim": "Pair", "args": [ { "prim": "Pair", "args": [ { "string": "${keyStore.publicKeyHash}" }, { "string": "${ + keyStore.publicKeyHash + }" } ] }, {"int": "${size}" }, { "int": "${notional}" }, { "string": "${expiration.toISOString()}" } ] }`; } - const sellOp = TezosNodeWriter.constructContractInvocationOperation(keyStore.publicKeyHash, nextCounter + 1, poolAddress, 0, 0, 0, 0, 'tokenToXtz', sellParams); + const sellOp = TezosNodeWriter.constructContractInvocationOperation( + keyStore.publicKeyHash, + nextCounter + 1, + poolAddress, + 0, + 0, + 0, + 0, + 'tokenToXtz', + sellParams + ); try { const opGroup = await TezosNodeWriter.prepareOperationGroup(tezosNode, keyStore, nextCounter - 1, [approveOp, sellOp], true); @@ -201,13 +263,38 @@ export async function sendDexterSell(tezosNode: string, keyStore: KeyStore, sign } } -export async function sendVortexBuy(tezosNode: string, keyStore: KeyStore, signer: Signer, tokenAddress: string, tokenIndex: number, poolAddress: string, notional: string, size: string): Promise { +export async function sendVortexBuy( + tezosNode: string, + keyStore: KeyStore, + signer: Signer, + tokenAddress: string, + tokenIndex: number, + poolAddress: string, + notional: string, + size: string +): Promise { const expiration = new Date(Date.now() + vortexExpirationPadding); - const buyParams = `{ "prim": "Pair", "args": [ { "string": "${keyStore.publicKeyHash}" }, { "int": "${size}" }, { "string":"${expiration.toISOString()}" } ] }`; + const buyParams = `{ "prim": "Pair", "args": [ { "string": "${ + keyStore.publicKeyHash + }" }, { "int": "${size}" }, { "string":"${expiration.toISOString()}" } ] }`; try { - const r = await TezosNodeWriter.sendContractInvocationOperation(tezosNode, signer, keyStore, poolAddress, Number(notional), 0, 0, 0, 'xtzToToken', buyParams, TezosParameterFormat.Micheline, TezosConstants.HeadBranchOffset, true); + const r = await TezosNodeWriter.sendContractInvocationOperation( + tezosNode, + signer, + keyStore, + poolAddress, + Number(notional), + 0, + 0, + 0, + 'xtzToToken', + buyParams, + TezosParameterFormat.Micheline, + TezosConstants.HeadBranchOffset, + true + ); return r.operationGroupID.replace(/\\|"|\n|\r/g, ''); } catch (err) { @@ -215,17 +302,48 @@ export async function sendVortexBuy(tezosNode: string, keyStore: KeyStore, signe } } -export async function sendVortexSell(tezosNode: string, keyStore: KeyStore, signer: Signer, tokenAddress: string, tokenIndex: number, poolAddress: string, notional: string, size: string): Promise { +export async function sendVortexSell( + tezosNode: string, + keyStore: KeyStore, + signer: Signer, + tokenAddress: string, + tokenIndex: number, + poolAddress: string, + notional: string, + size: string +): Promise { const nextCounter = (await TezosNodeReader.getCounterForAccount(tezosNode, keyStore.publicKeyHash)) + 1; const approveParams = `{ "prim": "Pair", "args": [ { "string": "${poolAddress}" }, { "int": "${size}" } ] }`; - const approveOp = TezosNodeWriter.constructContractInvocationOperation(keyStore.publicKeyHash, nextCounter, tokenAddress, 0, 0, 0, 0, 'approve', approveParams); + const approveOp = TezosNodeWriter.constructContractInvocationOperation( + keyStore.publicKeyHash, + nextCounter, + tokenAddress, + 0, + 0, + 0, + 0, + 'approve', + approveParams + ); const expiration = new Date(Date.now() + vortexExpirationPadding); - const sellParams = `{ "prim": "Pair","args": [ { "string": "${keyStore.publicKeyHash}" }, { "int": "${size}" }, { "int": "${notional}" }, { "string": "${expiration.toISOString()}" } ] }`; - - const sellOp = TezosNodeWriter.constructContractInvocationOperation(keyStore.publicKeyHash, nextCounter + 1, poolAddress, 0, 0, 0, 0, 'tokenToXtz', sellParams); + const sellParams = `{ "prim": "Pair","args": [ { "string": "${ + keyStore.publicKeyHash + }" }, { "int": "${size}" }, { "int": "${notional}" }, { "string": "${expiration.toISOString()}" } ] }`; + + const sellOp = TezosNodeWriter.constructContractInvocationOperation( + keyStore.publicKeyHash, + nextCounter + 1, + poolAddress, + 0, + 0, + 0, + 0, + 'tokenToXtz', + sellParams + ); try { const opGroup = await TezosNodeWriter.prepareOperationGroup(tezosNode, keyStore, nextCounter - 1, [approveOp, sellOp], true); @@ -237,11 +355,34 @@ export async function sendVortexSell(tezosNode: string, keyStore: KeyStore, sign } } -export async function sendQuipuBuy(tezosNode: string, keyStore: KeyStore, signer: Signer, tokenAddress: string, tokenIndex: number, poolAddress: string, notional: string, size: string): Promise { +export async function sendQuipuBuy( + tezosNode: string, + keyStore: KeyStore, + signer: Signer, + tokenAddress: string, + tokenIndex: number, + poolAddress: string, + notional: string, + size: string +): Promise { const params = `{ "prim": "Pair","args": [ { "int": "${size}" }, { "string": "${keyStore.publicKeyHash}" } ] }`; try { - const r = await TezosNodeWriter.sendContractInvocationOperation(tezosNode, signer, keyStore, poolAddress, Number(notional), 0, 0, 0, 'tezToTokenPayment', params, TezosParameterFormat.Micheline, TezosConstants.HeadBranchOffset, true); + const r = await TezosNodeWriter.sendContractInvocationOperation( + tezosNode, + signer, + keyStore, + poolAddress, + Number(notional), + 0, + 0, + 0, + 'tezToTokenPayment', + params, + TezosParameterFormat.Micheline, + TezosConstants.HeadBranchOffset, + true + ); return r.operationGroupID.replace(/\\|"|\n|\r/g, ''); } catch (err) { @@ -249,7 +390,16 @@ export async function sendQuipuBuy(tezosNode: string, keyStore: KeyStore, signer } } -export async function sendQuipuSell(tezosNode: string, keyStore: KeyStore, signer: Signer, tokenAddress: string, tokenIndex: number, poolAddress: string, notional: string, size: string): Promise { +export async function sendQuipuSell( + tezosNode: string, + keyStore: KeyStore, + signer: Signer, + tokenAddress: string, + tokenIndex: number, + poolAddress: string, + notional: string, + size: string +): Promise { let selectedToken: Token | VaultToken | ArtToken; if (tokenIndex > -1) { @@ -262,13 +412,30 @@ export async function sendQuipuSell(tezosNode: string, keyStore: KeyStore, signe let approveOp: Transaction; if (selectedToken.kind === TokenKind.tzip12 || selectedToken.kind === TokenKind.objkt) { - approveOp = constructFA2ApprovalOperation(keyStore.publicKeyHash, nextCounter, { fee: 0, gas: 0, storage: 0 }, tokenAddress, poolAddress, selectedToken.tokenIndex?.toString() || '0'); + approveOp = constructFA2ApprovalOperation( + keyStore.publicKeyHash, + nextCounter, + { fee: 0, gas: 0, storage: 0 }, + tokenAddress, + poolAddress, + selectedToken.tokenIndex?.toString() || '0' + ); } else { approveOp = constructFA1ApprovalOperation(keyStore.publicKeyHash, nextCounter, { fee: 0, gas: 0, storage: 0 }, tokenAddress, poolAddress, size); } const sellParams = `{ "prim": "Pair", "args": [ { "prim": "Pair", "args": [ { "int": "${size}" }, { "int": "${notional}" } ] }, { "string": "${keyStore.publicKeyHash}" } ] }`; - const sellOp = TezosNodeWriter.constructContractInvocationOperation(keyStore.publicKeyHash, nextCounter + 1, poolAddress, 0, 0, 0, 0, 'tokenToTezPayment', sellParams); + const sellOp = TezosNodeWriter.constructContractInvocationOperation( + keyStore.publicKeyHash, + nextCounter + 1, + poolAddress, + 0, + 0, + 0, + 0, + 'tokenToTezPayment', + sellParams + ); try { const opGroup = await TezosNodeWriter.prepareOperationGroup(tezosNode, keyStore, nextCounter - 1, [approveOp, sellOp], true); @@ -280,7 +447,13 @@ export async function sendQuipuSell(tezosNode: string, keyStore: KeyStore, signe } } -export function getTokenToCashExchangeRate(tokenAmount: string, tokenBalance: string, cashBalance: string, tokenDecimals: number = 6, exchangeMultiplier: number = 997) { +export function getTokenToCashExchangeRate( + tokenAmount: string, + tokenBalance: string, + cashBalance: string, + tokenDecimals: number = 6, + exchangeMultiplier: number = 997 +) { const n = bigInt(tokenAmount).multiply(bigInt(cashBalance)).multiply(bigInt(exchangeMultiplier)); const d = bigInt(tokenBalance) .multiply(bigInt(1000)) @@ -293,7 +466,13 @@ export function getTokenToCashExchangeRate(tokenAmount: string, tokenBalance: st return { cashAmount: cashAmount.toJSNumber(), rate: parseFloat(`${dm.quotient.toJSNumber()}.${f.toJSNumber()}`) }; } -export function getTokenToCashInverse(tokenAmount: string, tokenBalance: string, cashBalance: string, tokenDecimals: number = 6, exchangeMultiplier: number = 997) { +export function getTokenToCashInverse( + tokenAmount: string, + tokenBalance: string, + cashBalance: string, + tokenDecimals: number = 6, + exchangeMultiplier: number = 997 +) { const n = bigInt(tokenAmount).multiply(bigInt(cashBalance)).multiply(bigInt(1000)); const d = bigInt(tokenBalance) .multiply(bigInt(exchangeMultiplier)) @@ -339,14 +518,48 @@ export async function getPoolState(server: string, address: string, storageMap: }; } -export function constructFA1ApprovalOperation(sourceAddress: string, counter: number, fee: OperationFee, tokenAddress: string, destinationAddress: string, amount: string = '0') { +export function constructFA1ApprovalOperation( + sourceAddress: string, + counter: number, + fee: OperationFee, + tokenAddress: string, + destinationAddress: string, + amount: string = '0' +) { const params = `{ "prim": "Pair", "args": [ { "string": "${destinationAddress}" }, { "int": "${amount}" } ] }`; - return TezosNodeWriter.constructContractInvocationOperation(sourceAddress, counter, tokenAddress, 0, fee?.fee || 0, fee?.storage || 0, fee?.gas || 0, 'approve', params); + return TezosNodeWriter.constructContractInvocationOperation( + sourceAddress, + counter, + tokenAddress, + 0, + fee?.fee || 0, + fee?.storage || 0, + fee?.gas || 0, + 'approve', + params + ); } -export function constructFA2ApprovalOperation(sourceAddress: string, counter: number, fee: OperationFee, tokenAddress: string, destinationAddress: string, tokenIndex: string = '0') { +export function constructFA2ApprovalOperation( + sourceAddress: string, + counter: number, + fee: OperationFee, + tokenAddress: string, + destinationAddress: string, + tokenIndex: string = '0' +) { const params = `[{"prim":"Left","args":[{"prim":"Pair","args":[{"string":"${sourceAddress}"},{"prim":"Pair","args":[{"string":"${destinationAddress}"},{"int":"${tokenIndex}"}]}]}]}]`; - return TezosNodeWriter.constructContractInvocationOperation(sourceAddress, counter, tokenAddress, 0, fee?.fee || 0, fee?.storage || 0, fee?.gas || 0, 'update_operators', params); + return TezosNodeWriter.constructContractInvocationOperation( + sourceAddress, + counter, + tokenAddress, + 0, + fee?.fee || 0, + fee?.storage || 0, + fee?.gas || 0, + 'update_operators', + params + ); } From 531b217faa91febaf2ad792b169e99be9ccbd0fb Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Wed, 20 Apr 2022 12:12:46 -0400 Subject: [PATCH 20/21] - process operation groupid - reset NFT sync timestamp --- src/contracts/NFT/components/NFTAddModal/index.tsx | 5 +++-- src/utils/general.ts | 7 ++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/contracts/NFT/components/NFTAddModal/index.tsx b/src/contracts/NFT/components/NFTAddModal/index.tsx index 40e05d8b..93676b6b 100644 --- a/src/contracts/NFT/components/NFTAddModal/index.tsx +++ b/src/contracts/NFT/components/NFTAddModal/index.tsx @@ -15,6 +15,7 @@ import InputAddress from '../../../../components/InputAddress'; import TextField from '../../../../components/TextField'; import { AddButton, AddNFTButtonContainer, InputAddressContainer, ModalHeader, SuccessText } from './style'; import { updateTokensAction } from '../../../../reduxContent/wallet/actions'; +import { endNFTSyncAction } from '../../../../reduxContent/nft/actions'; import { setLocalData, getLocalData } from '../../../../utils/localData'; interface Props { @@ -68,8 +69,8 @@ const NFTAddModal = (props: Props) => { setLocalData('token', [tokenDefinition]); } dispatch(updateTokensAction([...tokens])); + dispatch(endNFTSyncAction(new Date(2018, 5, 30))); onClose(); - console.log('tokens', tokens); }; console.log('customNftToken', customNftToken); @@ -91,7 +92,7 @@ const NFTAddModal = (props: Props) => { }} onIssue={(flag) => setIsNFTContractAddressIssue(flag)} /> - {tokenDefinition && NFT Contract found!! } + {tokenDefinition && NFT Contract found! } {isLoading && } diff --git a/src/utils/general.ts b/src/utils/general.ts index f1ac44ec..23f0740f 100644 --- a/src/utils/general.ts +++ b/src/utils/general.ts @@ -139,11 +139,8 @@ export function openBlockExplorerForAccount(account: string, network: string = ' shell.openExternal(`${blockExplorerHost}/${network}/accounts/${account}`); } -export function clearOperationId(operationId) { - if (typeof operationId === 'string') { - return operationId.replace(/\\|"|\n|\r/g, ''); - } - return operationId; +export function clearOperationId(operationId: string) { + return operationId.replace(/\"/g, '').replace(/\n/, ''); } export const getDataFromApi = async (url: string) => { From 6602d144e0c994254555c51fb4da7610b0ecdf5c Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Wed, 20 Apr 2022 12:40:44 -0400 Subject: [PATCH 21/21] - reset NFT sync timestamp --- .../NFT/components/NFTAddModal/index.tsx | 6 ++++-- src/reduxContent/nft/actions.ts | 17 +++++++++++++++-- src/reduxContent/nft/types.ts | 10 ++++++++-- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/contracts/NFT/components/NFTAddModal/index.tsx b/src/contracts/NFT/components/NFTAddModal/index.tsx index 93676b6b..a22379a1 100644 --- a/src/contracts/NFT/components/NFTAddModal/index.tsx +++ b/src/contracts/NFT/components/NFTAddModal/index.tsx @@ -68,8 +68,10 @@ const NFTAddModal = (props: Props) => { } else { setLocalData('token', [tokenDefinition]); } - dispatch(updateTokensAction([...tokens])); - dispatch(endNFTSyncAction(new Date(2018, 5, 30))); + + dispatch(updateTokensAction([...tokens, tokenDefinition])); + dispatch(endNFTSyncAction(null)); + onClose(); }; diff --git a/src/reduxContent/nft/actions.ts b/src/reduxContent/nft/actions.ts index 5af8d0a9..5b4ed6f3 100644 --- a/src/reduxContent/nft/actions.ts +++ b/src/reduxContent/nft/actions.ts @@ -1,4 +1,17 @@ -import { CLEAR_NFT_GET_COLLECTIONS_ERRORS, ENABLE_NFT_SYNC, START_NFT_SYNC, END_NFT_SYNC, SET_NFT_COLLECTIONS, SET_NFT_COLLECTIONS_ARE_LOADING, StartNFTSyncAction, EndNFTSyncAction, EnableNFTSyncAction, ClearGetNFTCollectionsErrorsAction, SetNFTCollectionsAreLoadingAction, SetNFTCollectionsAction } from './types'; +import { + CLEAR_NFT_GET_COLLECTIONS_ERRORS, + ENABLE_NFT_SYNC, + START_NFT_SYNC, + END_NFT_SYNC, + SET_NFT_COLLECTIONS, + SET_NFT_COLLECTIONS_ARE_LOADING, + StartNFTSyncAction, + EndNFTSyncAction, + EnableNFTSyncAction, + ClearGetNFTCollectionsErrorsAction, + SetNFTCollectionsAreLoadingAction, + SetNFTCollectionsAction, +} from './types'; import { NFTCollections, NFTError } from '../../contracts/NFT/types'; @@ -14,7 +27,7 @@ export function startNFTSyncAction(): StartNFTSyncAction { /** * Mark that NFT sync has finished. */ -export function endNFTSyncAction(timestamp: Date): EndNFTSyncAction { +export function endNFTSyncAction(timestamp: Date | null): EndNFTSyncAction { return { type: END_NFT_SYNC, payload: { timestamp }, diff --git a/src/reduxContent/nft/types.ts b/src/reduxContent/nft/types.ts index 41a65886..e324f53d 100644 --- a/src/reduxContent/nft/types.ts +++ b/src/reduxContent/nft/types.ts @@ -18,7 +18,7 @@ export interface StartNFTSyncAction { export interface EndNFTSyncAction { type: typeof END_NFT_SYNC; payload: { - timestamp: Date; + timestamp: Date | null; }; } @@ -52,4 +52,10 @@ export interface GetNFTCollectionsDataSelector { isNFTSyncing: boolean; } -export type NFTActionTypes = ClearGetNFTCollectionsErrorsAction | EnableNFTSyncAction | StartNFTSyncAction | EndNFTSyncAction | SetNFTCollectionsAction | SetNFTCollectionsAreLoadingAction; +export type NFTActionTypes = + | ClearGetNFTCollectionsErrorsAction + | EnableNFTSyncAction + | StartNFTSyncAction + | EndNFTSyncAction + | SetNFTCollectionsAction + | SetNFTCollectionsAreLoadingAction;