From 1dd9e3191199e22de968f1643cb967fc8a7bfd4b Mon Sep 17 00:00:00 2001 From: HeesungB Date: Tue, 13 Dec 2022 21:21:16 +0900 Subject: [PATCH 1/8] Add all chains item, Fix checkbox logic --- components/chain-list/all-chains-item.tsx | 65 +++++++++++++++++++++ components/chain-list/chain-item.tsx | 48 +++++++++++----- components/chain-list/chain-list.tsx | 33 +++++++++-- next.config.js | 4 ++ pages/verification/index.tsx | 69 +++++++++++++++++++---- public/images/svg/all-chains-icon.svg | 33 +++++++++++ types/account-info.ts | 1 + 7 files changed, 224 insertions(+), 29 deletions(-) create mode 100644 components/chain-list/all-chains-item.tsx create mode 100644 public/images/svg/all-chains-icon.svg diff --git a/components/chain-list/all-chains-item.tsx b/components/chain-list/all-chains-item.tsx new file mode 100644 index 0000000..22d959d --- /dev/null +++ b/components/chain-list/all-chains-item.tsx @@ -0,0 +1,65 @@ +import { ChainItemType } from "../../types"; +import { + ChangeEvent, + Dispatch, + FunctionComponent, + SetStateAction, + useEffect, + useState, +} from "react"; +import { + ChainImageContainer, + ChainInfoContainer, + ChainItemContainer, +} from "./chain-list"; +import { ChainImage } from "./chain-image"; +import { Flex1 } from "../../styles/flex-1"; +import { ChainCheckBox, ChainName, WalletAddress } from "./chain-item"; +import color from "../../styles/color"; +import styled from "styled-components"; + +interface Props { + allChecked: boolean; + setAllChecked: Dispatch>; + chainItem: ChainItemType; +} + +export const AllChainsItem: FunctionComponent = (props) => { + const { allChecked, setAllChecked, chainItem } = props; + + const checkHandler = () => { + setAllChecked(!allChecked); + }; + + return ( + + + + + + + {`.${chainItem.prefix}`} + {chainItem.address} + + + + + + + + ); +}; + +const AllChainsContainer = styled.div` + width: 100%; + + background-color: ${color.grey["800"]}; +`; diff --git a/components/chain-list/chain-item.tsx b/components/chain-list/chain-item.tsx index 4492420..b1e0cd1 100644 --- a/components/chain-list/chain-item.tsx +++ b/components/chain-list/chain-item.tsx @@ -1,5 +1,12 @@ import { ChainItemType } from "../../types"; -import { ChangeEvent, FunctionComponent, useState } from "react"; +import { + ChangeEvent, + Dispatch, + FunctionComponent, + SetStateAction, + useEffect, + useState, +} from "react"; import { ChainImageContainer, ChainInfoContainer, @@ -14,18 +21,28 @@ import { ChainImage } from "./chain-image"; interface Props { chainItem: ChainItemType; checkedItemHandler: (chainItem: ChainItemType, isChecked: boolean) => void; + checkedItems: Set; } export const ChainItem: FunctionComponent = (props) => { - const { chainItem, checkedItemHandler } = props; + const { chainItem, checkedItemHandler, checkedItems } = props; const [checked, setChecked] = useState(false); - const checkHandler = (event: ChangeEvent) => { + const checkHandler = () => { setChecked(!checked); - checkedItemHandler(chainItem, event.target.checked); + checkedItemHandler(chainItem, !checked); }; + + useEffect(() => { + setChecked(checkedItems.has(chainItem)); + }, [checkedItems]); + return ( - + = (props) => { - checkHandler(event)} - /> + ); }; -const ChainName = styled.div` +export const ChainName = styled.div` font-weight: 600; font-size: 0.8rem; line-height: 1rem; - color: ${color.grey["100"]}; + color: ${color.white}; `; -const WalletAddress = styled.div` +export const WalletAddress = styled.div` font-weight: 500; font-size: 0.8rem; line-height: 1rem; + max-height: 2rem; + max-width: 27rem; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + color: ${color.grey["400"]}; `; -const ChainCheckBox = styled.input.attrs({ type: "checkbox" })` +export const ChainCheckBox = styled.input.attrs({ type: "checkbox" })` width: 1.5rem; height: 1.5rem; `; diff --git a/components/chain-list/chain-list.tsx b/components/chain-list/chain-list.tsx index fbdb442..ef0f80e 100644 --- a/components/chain-list/chain-list.tsx +++ b/components/chain-list/chain-list.tsx @@ -1,17 +1,25 @@ -import { FunctionComponent } from "react"; +import { Dispatch, FunctionComponent, SetStateAction, useEffect } from "react"; import { ChainItemType, WidthHeightProps } from "../../types"; import color from "../../styles/color"; import styled from "styled-components"; import { ChainItem } from "./chain-item"; interface Props { + allChecked: boolean; + setAllChecked: Dispatch>; chainList: ChainItemType[]; - checkedItems: any; - setCheckedItems: any; + checkedItems: Set; + setCheckedItems: Dispatch>>; } export const ChainList: FunctionComponent = (props) => { - const { chainList, checkedItems, setCheckedItems } = props; + const { + allChecked, + setAllChecked, + chainList, + checkedItems, + setCheckedItems, + } = props; const checkedItemHandler = (chainItem: ChainItemType, isChecked: boolean) => { const tempSet = new Set(checkedItems); @@ -25,6 +33,22 @@ export const ChainList: FunctionComponent = (props) => { setCheckedItems(tempSet); }; + useEffect(() => { + if (allChecked) { + setCheckedItems(new Set(chainList)); + } else if (chainList.length === checkedItems.size) { + setCheckedItems(new Set()); + } + }, [allChecked]); + + useEffect(() => { + if (chainList.length === checkedItems.size && checkedItems.size !== 0) { + setAllChecked(true); + } else { + setAllChecked(false); + } + }, [checkedItems]); + return ( {chainList.map((chainItem) => ( @@ -32,6 +56,7 @@ export const ChainList: FunctionComponent = (props) => { key={chainItem.address} chainItem={chainItem} checkedItemHandler={checkedItemHandler} + checkedItems={checkedItems} /> ))} diff --git a/next.config.js b/next.config.js index d3197ea..94c9229 100644 --- a/next.config.js +++ b/next.config.js @@ -15,6 +15,10 @@ const nextConfig = { protocol: "https", hostname: "raw.githubusercontent.com", }, + { + protocol: "https", + hostname: "abs.twimg.com", + }, ], }, }; diff --git a/pages/verification/index.tsx b/pages/verification/index.tsx index 431af3e..a5cc2b0 100644 --- a/pages/verification/index.tsx +++ b/pages/verification/index.tsx @@ -25,26 +25,33 @@ import { MainChainId } from "../../constants/wallet"; import { getKeplrFromWindow, KeplrWallet } from "../../wallets"; import { ChainIdHelper } from "@keplr-wallet/cosmos"; +import AllChainsIcon from "../../public/images/svg/all-chains-icon.svg"; +import { AllChainsItem } from "../../components/chain-list/all-chains-item"; + export default function VerificationPage() { const router = useRouter(); const [twitterAuthInfo, setTwitterAuthInfo] = useState(); - const [chainList, setChainList] = useState([]); const [isLoading, setIsLoading] = useState(true); + const [wallet, setWallet] = useState(); + const [allChains, setAllChains] = useState(); + const [chainList, setChainList] = useState([]); const [checkedItems, setCheckedItems] = useState(new Set()); + const [allChecked, setAllChecked] = useState(false); useEffect(() => { const handleVerification = async () => { if (window.location.search) { if (window.location.search.match("error")) { await router.push("/"); + return; } await fetchTwitterInfo(); - await fetchChainList(); + await initWallet(); setIsLoading(false); } @@ -66,11 +73,39 @@ export default function VerificationPage() { setTwitterAuthInfo(newTwitterAuthInfo); }; - const fetchChainList = async () => { + const initWallet = async () => { const keplr = await getKeplrFromWindow(); if (keplr) { - const wallet = new KeplrWallet(keplr); + const keplrWallet = new KeplrWallet(keplr); + setWallet(keplrWallet); + } + }; + + useEffect(() => { + if (wallet) { + fetchAllChains(); + fetchChainList(); + } + }, [wallet]); + + const fetchAllChains = async () => { + if (wallet) { + const chainNames = (await wallet.getChainInfosWithoutEndpoints()).map( + (chainInfo) => chainInfo.chainName, + ); + + setAllChains({ + chainId: "all chains", + prefix: `all chains(${chainNames.length})`, + address: chainNames.join(", "), + chainImageUrl: AllChainsIcon, + }); + } + }; + + const fetchChainList = async () => { + if (wallet) { const chainIds = (await wallet.getChainInfosWithoutEndpoints()).map( (c) => c.chainId, ); @@ -81,6 +116,7 @@ export default function VerificationPage() { const chainInfos = (await wallet.getChainInfosWithoutEndpoints()).map( (chainInfo) => { return { + chainId: chainInfo.chainId, prefix: chainInfo.bech32Config.bech32PrefixAccAddr, chainImageUrl: `https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/${ ChainIdHelper.parse(chainInfo.chainId).identifier @@ -98,19 +134,16 @@ export default function VerificationPage() { } // remove duplicated item - // const filteredChainList = chainArray.filter((chain, index, self) => { - // return index === self.findIndex((t) => chain.prefix === t.prefix); - // }); + const filteredChainList = chainArray.filter((chain, index, self) => { + return index === self.findIndex((t) => chain.prefix === t.prefix); + }); - setChainList(chainArray); + setChainList(filteredChainList); } }; const verifyTwitterAccount = async () => { - const keplr = await getKeplrFromWindow(); - - if (twitterAuthInfo && keplr) { - const wallet = new KeplrWallet(keplr); + if (twitterAuthInfo && wallet) { const key = await wallet.getKey(MainChainId); const icnsVerificationList = ( @@ -132,6 +165,8 @@ export default function VerificationPage() { const onClickRegistration = async () => { await verifyTwitterAccount(); + + await router.push("/complete"); }; return ( @@ -150,7 +185,17 @@ export default function VerificationPage() { Search + {allChains ? ( + + ) : null} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/types/account-info.ts b/types/account-info.ts index 8c73a23..0e1d315 100644 --- a/types/account-info.ts +++ b/types/account-info.ts @@ -1,4 +1,5 @@ export interface ChainItemType { + chainId: string; prefix: string; chainImageUrl: string; address: string; From 1602ef92c885c7d8ccbd786fd47ea7a5803021cd Mon Sep 17 00:00:00 2001 From: HeesungB Date: Tue, 13 Dec 2022 22:10:31 +0900 Subject: [PATCH 2/8] Add search input --- components/search-input/index.tsx | 83 +++++++++++++++++++++++++++++++ pages/verification/index.tsx | 28 +++++------ public/images/svg/search-icon.svg | 3 ++ 3 files changed, 99 insertions(+), 15 deletions(-) create mode 100644 components/search-input/index.tsx create mode 100644 public/images/svg/search-icon.svg diff --git a/components/search-input/index.tsx b/components/search-input/index.tsx new file mode 100644 index 0000000..f535cbb --- /dev/null +++ b/components/search-input/index.tsx @@ -0,0 +1,83 @@ +import { + Dispatch, + FunctionComponent, + SetStateAction, + useRef, + useState, +} from "react"; + +import Image from "next/image"; + +import styled from "styled-components"; +import color from "../../styles/color"; + +import SearchIcon from "../../public/images/svg/search-icon.svg"; + +interface Props { + searchValue: string; + setSearchValue: Dispatch>; +} + +export const SearchInput: FunctionComponent = (props) => { + const { searchValue, setSearchValue } = props; + + return ( + + + search icon + + + { + setSearchValue(event.target.value); + }} + /> + + ); +}; + +const SearchContainer = styled.div` + display: flex; + align-items: center; + gap: 0.625rem; + + min-width: 10rem; + height: 2rem; + + padding: 0.5rem 1.3rem; + + border-radius: 3rem; + background-color: ${color.grey["700"]}; +`; + +const SearchIconContainer = styled.div` + position: relative; + + width: 1.3rem; + height: 1.3rem; +`; + +const SearchText = styled.input` + border: none; + + color: ${color.white}; + background-color: ${color.grey["700"]}; + + font-family: "Inter", serif; + font-style: normal; + font-weight: 500; + font-size: 1rem; + line-height: 1.2rem; + + ::placeholder, + ::-webkit-input-placeholder { + color: ${color.grey["400"]}; + } + + &:focus { + outline: none; + } +`; diff --git a/pages/verification/index.tsx b/pages/verification/index.tsx index a5cc2b0..8e79ab8 100644 --- a/pages/verification/index.tsx +++ b/pages/verification/index.tsx @@ -27,6 +27,7 @@ import { ChainIdHelper } from "@keplr-wallet/cosmos"; import AllChainsIcon from "../../public/images/svg/all-chains-icon.svg"; import { AllChainsItem } from "../../components/chain-list/all-chains-item"; +import { SearchInput } from "../../components/search-input"; export default function VerificationPage() { const router = useRouter(); @@ -40,6 +41,7 @@ export default function VerificationPage() { const [chainList, setChainList] = useState([]); const [checkedItems, setCheckedItems] = useState(new Set()); const [allChecked, setAllChecked] = useState(false); + const [searchValue, setSearchValue] = useState(""); useEffect(() => { const handleVerification = async () => { @@ -182,10 +184,13 @@ export default function VerificationPage() { Chain List - Search + - {allChains ? ( + {allChains && !searchValue ? ( + chain.chainId.includes(searchValue) || + chain.address.includes(searchValue) || + chain.prefix.includes(searchValue), + )} checkedItems={checkedItems} setCheckedItems={setCheckedItems} /> @@ -264,15 +274,3 @@ const ChainListTitle = styled.div` color: ${color.white}; `; - -const SearchContainer = styled.div` - display: flex; - align-items: center; - - border-radius: 3rem; - - min-width: 10rem; - height: 2rem; - - background-color: ${color.grey["700"]}; -`; diff --git a/public/images/svg/search-icon.svg b/public/images/svg/search-icon.svg new file mode 100644 index 0000000..f1406e1 --- /dev/null +++ b/public/images/svg/search-icon.svg @@ -0,0 +1,3 @@ + + + From febde1e7c414e11f01182b444515e21a4c8321de Mon Sep 17 00:00:00 2001 From: HeesungB Date: Tue, 13 Dec 2022 22:11:28 +0900 Subject: [PATCH 3/8] Remove config.ts --- config.ts | 160 ------------------ types/{account-info.ts => chain-item-type.ts} | 0 types/index.ts | 2 +- 3 files changed, 1 insertion(+), 161 deletions(-) delete mode 100644 config.ts rename types/{account-info.ts => chain-item-type.ts} (100%) diff --git a/config.ts b/config.ts deleted file mode 100644 index 2b5e5b8..0000000 --- a/config.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { ChainItemType } from "./types"; - -export const AccountInfos: ChainItemType[] = [ - { - prefix: "cosmos", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/cosmoshub/chain.png", - }, - { - prefix: "osmo", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/osmosis/chain.png", - }, - { - prefix: "agoric", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/agoric/chain.png", - }, - { - prefix: "akash", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/akashnet/chain.png", - }, - { - prefix: "axelar", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/axelar-dojo/chain.png", - }, - { - prefix: "bostrom", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/bostrom/chain.png", - }, - { - prefix: "persistence", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/core/chain.png", - }, - { - prefix: "cro", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/crypto-org-chain-mainnet/chain.png", - }, - { - prefix: "emoney", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/emoney/chain.png", - }, - { - prefix: "evmos", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/evmos_9001/chain.png", - }, - { - prefix: "gravity", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/gravity-bridge/chain.png", - }, - { - prefix: "ixo", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/impacthub/chain.png", - }, - { - prefix: "star", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/iov-mainnet-ibc/chain.png", - }, - { - prefix: "iaa", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/irishub/chain.png", - }, - { - prefix: "juno", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/juno/chain.png", - }, - { - prefix: "kava", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/kava_2222/chain.png", - }, - { - prefix: "regen", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/regen/chain.png", - }, - { - prefix: "secret", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/secret/chain.png", - }, - { - prefix: "sent", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/sentinelhub/chain.png", - }, - { - prefix: "certik", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/shentu-2.2/chain.png", - }, - { - prefix: "sif", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/sifchain/chain.png", - }, - { - prefix: "somm", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/sommelier/chain.png", - }, - { - prefix: "stars", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/stargaze/chain.png", - }, - { - prefix: "stride", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/stride/chain.png", - }, - { - prefix: "tgrade", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/tgrade-mainnet/chain.png", - }, - { - prefix: "umee", - address: "cosmos14ky6udatsvdx859050mrnr7rvml0huue2wszvs", - chainImageUrl: - "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/umee/chain.png", - }, -]; diff --git a/types/account-info.ts b/types/chain-item-type.ts similarity index 100% rename from types/account-info.ts rename to types/chain-item-type.ts diff --git a/types/index.ts b/types/index.ts index 0dea015..6656919 100644 --- a/types/index.ts +++ b/types/index.ts @@ -1,4 +1,4 @@ export * from "./width-height-props"; export * from "./api-response"; -export * from "./account-info"; +export * from "./chain-item-type"; export * from "./msg"; From 8504c84d3c488e04a6eebe6bab59b9a84544fbca Mon Sep 17 00:00:00 2001 From: HeesungB Date: Tue, 13 Dec 2022 23:46:32 +0900 Subject: [PATCH 4/8] [WIP] Simulate --- components/chain-list/all-chains-item.tsx | 2 +- components/chain-list/chain-item.tsx | 3 +- components/chain-list/chain-list.tsx | 5 +- constants/icns.ts | 7 ++ pages/verification/index.tsx | 133 ++++++++++++++++++++-- 5 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 constants/icns.ts diff --git a/components/chain-list/all-chains-item.tsx b/components/chain-list/all-chains-item.tsx index 22d959d..06c7c0f 100644 --- a/components/chain-list/all-chains-item.tsx +++ b/components/chain-list/all-chains-item.tsx @@ -52,7 +52,7 @@ export const AllChainsItem: FunctionComponent = (props) => { - + ); diff --git a/components/chain-list/chain-item.tsx b/components/chain-list/chain-item.tsx index b1e0cd1..00a63a3 100644 --- a/components/chain-list/chain-item.tsx +++ b/components/chain-list/chain-item.tsx @@ -41,6 +41,7 @@ export const ChainItem: FunctionComponent = (props) => { @@ -57,7 +58,7 @@ export const ChainItem: FunctionComponent = (props) => { - + ); }; diff --git a/components/chain-list/chain-list.tsx b/components/chain-list/chain-list.tsx index ef0f80e..ab7ba36 100644 --- a/components/chain-list/chain-list.tsx +++ b/components/chain-list/chain-list.tsx @@ -73,7 +73,10 @@ export const ChainContainer = styled.div` background-color: ${(props) => props.color}; `; -export const ChainItemContainer = styled.div<{ isLoading: boolean }>` +export const ChainItemContainer = styled.div<{ + isLoading: boolean; + checked?: boolean; +}>` display: flex; flex-direction: row; align-items: center; diff --git a/constants/icns.ts b/constants/icns.ts new file mode 100644 index 0000000..b708260 --- /dev/null +++ b/constants/icns.ts @@ -0,0 +1,7 @@ +export const RPC_URL = ""; +export const REST_URL = "https://lcd.testnet.osmosis.zone"; + +export const REGISTRAR_ADDRESS = + "osmo1npn97g7hsgqlp70rw8nhd7c7vyvkukv9x0n25sn4fk5mgcjlz4gq9zlgf3"; +export const RESOLVER_ADDRESS = + "osmo1002awr7frr9wk44lc3vfzt0d2w6vz5z03ql6fszjsjy8vdcvk0sskruz3c"; diff --git a/pages/verification/index.tsx b/pages/verification/index.tsx index 8e79ab8..2ff09b3 100644 --- a/pages/verification/index.tsx +++ b/pages/verification/index.tsx @@ -22,12 +22,22 @@ import { TwitterProfile } from "../../components/twitter-profile"; import { ChainList } from "../../components/chain-list"; import { useRouter } from "next/router"; import { MainChainId } from "../../constants/wallet"; -import { getKeplrFromWindow, KeplrWallet } from "../../wallets"; +import { + getKeplrFromWindow, + KeplrWallet, + makeCosmwasmExecMsg, + simulateMsgs, +} from "../../wallets"; import { ChainIdHelper } from "@keplr-wallet/cosmos"; import AllChainsIcon from "../../public/images/svg/all-chains-icon.svg"; import { AllChainsItem } from "../../components/chain-list/all-chains-item"; import { SearchInput } from "../../components/search-input"; +import { + REGISTRAR_ADDRESS, + RESOLVER_ADDRESS, + REST_URL, +} from "../../constants/icns"; export default function VerificationPage() { const router = useRouter(); @@ -51,7 +61,8 @@ export default function VerificationPage() { return; } - await fetchTwitterInfo(); + const twitterInfo = await fetchTwitterInfo(); + setTwitterAuthInfo(twitterInfo); await initWallet(); @@ -62,7 +73,7 @@ export default function VerificationPage() { handleVerification(); }, []); - const fetchTwitterInfo = async () => { + const fetchTwitterInfo = async (): Promise => { const [, state, code] = window.location.search.match( /^(?=.*state=([^&]+)|)(?=.*code=([^&]+)|).+$/, @@ -72,7 +83,7 @@ export default function VerificationPage() { `/api/twitter-auth-info?state=${state}&code=${code}`, ); - setTwitterAuthInfo(newTwitterAuthInfo); + return newTwitterAuthInfo; }; const initWallet = async () => { @@ -144,8 +155,8 @@ export default function VerificationPage() { } }; - const verifyTwitterAccount = async () => { - if (twitterAuthInfo && wallet) { + const verifyTwitterAccount = async (accessToken: string) => { + if (wallet) { const key = await wallet.getKey(MainChainId); const icnsVerificationList = ( @@ -156,19 +167,121 @@ export default function VerificationPage() { }, body: JSON.stringify({ claimer: key.bech32Address, - authToken: twitterAuthInfo.accessToken, + authToken: accessToken, }), }) ).verificationList; - console.log(icnsVerificationList); + return icnsVerificationList; + } + }; + + const checkAdr36 = async () => { + if (twitterAuthInfo && wallet) { + const key = await wallet.getKey(MainChainId); + + const chainIds = Array.from(checkedItems).map( + (chain) => (chain as ChainItemType).chainId, + ); + + const adr36Infos = await wallet.signICNSAdr36( + MainChainId, + RESOLVER_ADDRESS, + key.bech32Address, + twitterAuthInfo.username, + chainIds, + ); + + return adr36Infos; } }; const onClickRegistration = async () => { - await verifyTwitterAccount(); + const adr36Infos = await checkAdr36(); - await router.push("/complete"); + const twitterInfo = await fetchTwitterInfo(); + + const icnsVerificationList = await verifyTwitterAccount( + twitterInfo.accessToken, + ); + + if (wallet && icnsVerificationList && adr36Infos) { + const key = await wallet.getKey(MainChainId); + + const registerMsg = makeCosmwasmExecMsg( + key.bech32Address, + REGISTRAR_ADDRESS, + { + claim: { + name: twitterInfo.username, + verifying_msg: + icnsVerificationList[0].status === "fulfilled" + ? icnsVerificationList[0].value.data.verifying_msg + : "", + verifications: icnsVerificationList.map((verification) => { + if (verification.status === "fulfilled") { + return { + public_key: verification.value.data.public_key, + signature: verification.value.data.signature, + }; + } + }), + }, + }, + [ + { + denom: "uosmo", + amount: "500000", + }, + ], + ); + + const addressMsgs = adr36Infos.map((adr36Info) => { + return makeCosmwasmExecMsg( + key.bech32Address, + RESOLVER_ADDRESS, + { + set_record: { + name: twitterInfo.username, + bech32_prefix: adr36Info.bech32Prefix, + adr36_info: { + signer_bech32_address: adr36Info.bech32Address, + address_hash: adr36Info.addressHash, + pub_key: Buffer.from(adr36Info.pubKey).toString("base64"), + signature: Buffer.from(adr36Info.signature).toString("base64"), + signature_salt: adr36Info.signatureSalt.toString(), + }, + }, + }, + [], + ); + }); + + const aminoMsgs = [registerMsg.amino]; + const protoMsgs = [registerMsg.proto]; + for (const addressMsg of addressMsgs) { + aminoMsgs.push(addressMsg.amino); + protoMsgs.push(addressMsg.proto); + } + + const chainInfo = { + chainId: MainChainId, + rest: REST_URL, + }; + + const simulated = await simulateMsgs( + chainInfo, + key.bech32Address, + { + proto: protoMsgs, + }, + { + amount: [], + }, + ); + + console.log("simulated", simulated); + } }; return ( From 01be54ee289a55de849df6caf121388ff732bc48 Mon Sep 17 00:00:00 2001 From: HeesungB Date: Wed, 14 Dec 2022 14:50:07 +0900 Subject: [PATCH 5/8] Change the order of Adr36 and twitter verifier --- pages/verification/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/verification/index.tsx b/pages/verification/index.tsx index 2ff09b3..8c510c0 100644 --- a/pages/verification/index.tsx +++ b/pages/verification/index.tsx @@ -197,10 +197,10 @@ export default function VerificationPage() { }; const onClickRegistration = async () => { - const adr36Infos = await checkAdr36(); - const twitterInfo = await fetchTwitterInfo(); + const adr36Infos = await checkAdr36(); + const icnsVerificationList = await verifyTwitterAccount( twitterInfo.accessToken, ); From 75d50bbe891129f676e1ed2692f23adf3c74ad88 Mon Sep 17 00:00:00 2001 From: HeesungB Date: Wed, 14 Dec 2022 16:52:05 +0900 Subject: [PATCH 6/8] Refactor repository --- .../connect-wallet-modal/wallet-item.tsx | 11 +- constants/icns.ts | 2 + constants/twitter.ts | 10 -- constants/wallet.ts | 8 +- pages/complete/index.tsx | 24 ++++ pages/verification/index.tsx | 124 +++++++++++------- repository/icns.ts | 0 repository/index.ts | 1 + repository/twitter.ts | 21 +++ 9 files changed, 136 insertions(+), 65 deletions(-) create mode 100644 repository/icns.ts create mode 100644 repository/index.ts create mode 100644 repository/twitter.ts diff --git a/components/connect-wallet-modal/wallet-item.tsx b/components/connect-wallet-modal/wallet-item.tsx index 13885b1..65f08bd 100644 --- a/components/connect-wallet-modal/wallet-item.tsx +++ b/components/connect-wallet-modal/wallet-item.tsx @@ -4,9 +4,13 @@ import color from "../../styles/color"; import { Flex1 } from "../../styles/flex-1"; import styled from "styled-components"; import Image from "next/image"; -import { SELECTED_WALLET_KEY, WalletType } from "../../constants/wallet"; +import { + SELECTED_WALLET_KEY, + WALLET_INSTALL_URL, + WalletType, +} from "../../constants/wallet"; import { getKeplrFromWindow, KeplrWallet } from "../../wallets"; -import { loginWithTwitter } from "../../constants/twitter"; +import { loginWithTwitter } from "../../repository"; interface Props { wallet: WalletType; @@ -32,8 +36,7 @@ export const WalletItem: FunctionComponent = (props: Props) => { const keplr = await getKeplrFromWindow(); if (keplr === undefined) { - window.location.href = - "https://chrome.google.com/webstore/detail/keplr/dmkamcknogkgcdfhhbddcghachkejeap"; + window.location.href = WALLET_INSTALL_URL; } if (keplr) { diff --git a/constants/icns.ts b/constants/icns.ts index b708260..7043738 100644 --- a/constants/icns.ts +++ b/constants/icns.ts @@ -1,3 +1,5 @@ +export const MainChainId = "osmo-test-4"; + export const RPC_URL = ""; export const REST_URL = "https://lcd.testnet.osmosis.zone"; diff --git a/constants/twitter.ts b/constants/twitter.ts index 0b4d16f..9f91183 100644 --- a/constants/twitter.ts +++ b/constants/twitter.ts @@ -1,5 +1,3 @@ -import { TwitterAuthUrlResponse } from "../types"; - export const twitterOAuthBaseUrl = "https://twitter.com/i/oauth2/authorize"; export const twitterOAuthScopes = [ @@ -9,11 +7,3 @@ export const twitterOAuthScopes = [ ]; export const twitterApiBaseUrl = "https://api.twitter.com/2"; - -export const loginWithTwitter = async () => { - const { authUrl }: TwitterAuthUrlResponse = await ( - await fetch("/api/twitter-auth-url") - ).json(); - - window.location.href = authUrl; -}; diff --git a/constants/wallet.ts b/constants/wallet.ts index ed04ff2..64822a8 100644 --- a/constants/wallet.ts +++ b/constants/wallet.ts @@ -3,8 +3,9 @@ import { StaticImageData } from "next/image"; import KeplrIcon from "../public/images/svg/keplr-icon.svg"; import CosmostationIcon from "../public/images/svg/cosmostation-icon.svg"; +export const WALLET_INSTALL_URL = + "https://chrome.google.com/webstore/detail/keplr/dmkamcknogkgcdfhhbddcghachkejeap"; export const SELECTED_WALLET_KEY = "SELECTED_WALLET_KEY"; -export const MainChainId = "osmo-test-4"; export type WalletName = "Keplr" | "Cosmostation"; export interface WalletType { @@ -25,3 +26,8 @@ export const WalletList: WalletType[] = [ isReady: false, }, ]; + +export const ContractFee = { + denom: "uosmo", + amount: "500000", +}; diff --git a/pages/complete/index.tsx b/pages/complete/index.tsx index d34c78c..6ebbc7f 100644 --- a/pages/complete/index.tsx +++ b/pages/complete/index.tsx @@ -8,8 +8,32 @@ import color from "../../styles/color"; import AlertCircleOutlineIcon from "../../public/images/svg/alert-circle-outline.svg"; import TwitterIcon from "../../public/images/svg/twitter-icon.svg"; +import { useRouter } from "next/router"; +import { useEffect } from "react"; +import { TendermintTxTracer } from "@keplr-wallet/cosmos"; export default function CompletePage() { + const router = useRouter(); + + useEffect(() => { + const { txHash } = router.query; + + if (txHash) { + traceTX(txHash as string); + } + }, []); + + const traceTX = async (txHash: string) => { + const txTracer = new TendermintTxTracer( + "https://rpc.testnet.osmosis.zone", + "/websocket", + ); + + const result = await txTracer.traceTx(Buffer.from(txHash, "hex")); + + console.log(result); + }; + return ( diff --git a/pages/verification/index.tsx b/pages/verification/index.tsx index 8c510c0..98988d3 100644 --- a/pages/verification/index.tsx +++ b/pages/verification/index.tsx @@ -21,11 +21,12 @@ import { PrimaryButton } from "../../components/primary-button"; import { TwitterProfile } from "../../components/twitter-profile"; import { ChainList } from "../../components/chain-list"; import { useRouter } from "next/router"; -import { MainChainId } from "../../constants/wallet"; +import { ContractFee } from "../../constants/wallet"; import { getKeplrFromWindow, KeplrWallet, makeCosmwasmExecMsg, + sendMsgs, simulateMsgs, } from "../../wallets"; import { ChainIdHelper } from "@keplr-wallet/cosmos"; @@ -34,11 +35,14 @@ import AllChainsIcon from "../../public/images/svg/all-chains-icon.svg"; import { AllChainsItem } from "../../components/chain-list/all-chains-item"; import { SearchInput } from "../../components/search-input"; import { + MainChainId, REGISTRAR_ADDRESS, RESOLVER_ADDRESS, REST_URL, } from "../../constants/icns"; +import { fetchTwitterInfo } from "../../repository"; + export default function VerificationPage() { const router = useRouter(); const [twitterAuthInfo, setTwitterAuthInfo] = @@ -53,39 +57,44 @@ export default function VerificationPage() { const [allChecked, setAllChecked] = useState(false); const [searchValue, setSearchValue] = useState(""); + const fetchUrlQueryParameter = (): { state: string; code: string } => { + // Twitter state, auth code check + const [, state, code] = + window.location.search.match( + /^(?=.*state=([^&]+)|)(?=.*code=([^&]+)|).+$/, + ) || []; + + return { + state, + code, + }; + }; + useEffect(() => { - const handleVerification = async () => { + const init = async () => { if (window.location.search) { + // Twitter Login Error Check if (window.location.search.match("error")) { await router.push("/"); return; } - const twitterInfo = await fetchTwitterInfo(); + const { state, code } = fetchUrlQueryParameter(); + + // Fetch Twitter Profile + const twitterInfo = await fetchTwitterInfo(state, code); setTwitterAuthInfo(twitterInfo); + // Initialize Wallet await initWallet(); setIsLoading(false); } }; - handleVerification(); + init(); }, []); - const fetchTwitterInfo = async (): Promise => { - const [, state, code] = - window.location.search.match( - /^(?=.*state=([^&]+)|)(?=.*code=([^&]+)|).+$/, - ) || []; - - const newTwitterAuthInfo = await request( - `/api/twitter-auth-info?state=${state}&code=${code}`, - ); - - return newTwitterAuthInfo; - }; - const initWallet = async () => { const keplr = await getKeplrFromWindow(); @@ -96,27 +105,12 @@ export default function VerificationPage() { }; useEffect(() => { + // After Wallet Initialize if (wallet) { - fetchAllChains(); fetchChainList(); } }, [wallet]); - const fetchAllChains = async () => { - if (wallet) { - const chainNames = (await wallet.getChainInfosWithoutEndpoints()).map( - (chainInfo) => chainInfo.chainName, - ); - - setAllChains({ - chainId: "all chains", - prefix: `all chains(${chainNames.length})`, - address: chainNames.join(", "), - chainImageUrl: AllChainsIcon, - }); - } - }; - const fetchChainList = async () => { if (wallet) { const chainIds = (await wallet.getChainInfosWithoutEndpoints()).map( @@ -130,6 +124,7 @@ export default function VerificationPage() { (chainInfo) => { return { chainId: chainInfo.chainId, + chainName: chainInfo.chainName, prefix: chainInfo.bech32Config.bech32PrefixAccAddr, chainImageUrl: `https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/${ ChainIdHelper.parse(chainInfo.chainId).identifier @@ -138,7 +133,7 @@ export default function VerificationPage() { }, ); - const chainArray: ChainItemType[] = []; + const chainArray = []; for (let i = 0; i < chainKeys.length; i++) { chainArray.push({ address: chainKeys[i].bech32Address, @@ -147,8 +142,28 @@ export default function VerificationPage() { } // remove duplicated item - const filteredChainList = chainArray.filter((chain, index, self) => { - return index === self.findIndex((t) => chain.prefix === t.prefix); + const filteredChainList = chainArray.filter((nextChain, index, self) => { + return ( + index === + self.findIndex((prevChain) => { + const isDuplicated = prevChain.prefix === nextChain.prefix; + + if (isDuplicated && prevChain.chainName !== nextChain.chainName) { + console.log( + `${nextChain.chainName} has been deleted due to a duplicate name with ${prevChain.chainName}`, + ); + } + + return isDuplicated; + }) + ); + }); + + setAllChains({ + chainId: "all chains", + prefix: `all chains(${filteredChainList.length})`, + address: chainInfos.map((chainInfo) => chainInfo.chainName).join(", "), + chainImageUrl: AllChainsIcon, }); setChainList(filteredChainList); @@ -159,7 +174,7 @@ export default function VerificationPage() { if (wallet) { const key = await wallet.getKey(MainChainId); - const icnsVerificationList = ( + return ( await request("/api/icns-verification", { method: "post", headers: { @@ -171,8 +186,6 @@ export default function VerificationPage() { }), }) ).verificationList; - - return icnsVerificationList; } }; @@ -184,20 +197,19 @@ export default function VerificationPage() { (chain) => (chain as ChainItemType).chainId, ); - const adr36Infos = await wallet.signICNSAdr36( + return await wallet.signICNSAdr36( MainChainId, RESOLVER_ADDRESS, key.bech32Address, twitterAuthInfo.username, chainIds, ); - - return adr36Infos; } }; const onClickRegistration = async () => { - const twitterInfo = await fetchTwitterInfo(); + const { state, code } = fetchUrlQueryParameter(); + const twitterInfo = await fetchTwitterInfo(state, code); const adr36Infos = await checkAdr36(); @@ -228,12 +240,7 @@ export default function VerificationPage() { }), }, }, - [ - { - denom: "uosmo", - amount: "500000", - }, - ], + [ContractFee], ); const addressMsgs = adr36Infos.map((adr36Info) => { @@ -280,7 +287,24 @@ export default function VerificationPage() { }, ); - console.log("simulated", simulated); + const txHash = await sendMsgs( + wallet, + chainInfo, + key.bech32Address, + { + amino: aminoMsgs, + proto: protoMsgs, + }, + { + amount: [], + gas: Math.floor(simulated.gasUsed * 1.5).toString(), + }, + ); + + router.push({ + pathname: "complete", + query: { txHash: Buffer.from(txHash).toString("hex") }, + }); } }; diff --git a/repository/icns.ts b/repository/icns.ts new file mode 100644 index 0000000..e69de29 diff --git a/repository/index.ts b/repository/index.ts new file mode 100644 index 0000000..5517f2d --- /dev/null +++ b/repository/index.ts @@ -0,0 +1 @@ +export * from "./twitter"; diff --git a/repository/twitter.ts b/repository/twitter.ts new file mode 100644 index 0000000..6c141a4 --- /dev/null +++ b/repository/twitter.ts @@ -0,0 +1,21 @@ +import { TwitterAuthInfoResponse, TwitterAuthUrlResponse } from "../types"; +import { request } from "../utils/url"; + +export const loginWithTwitter = async () => { + const { authUrl }: TwitterAuthUrlResponse = await ( + await fetch("/api/twitter-auth-url") + ).json(); + + window.location.href = authUrl; +}; + +export const fetchTwitterInfo = async ( + state: string, + code: string, +): Promise => { + const newTwitterAuthInfo = await request( + `/api/twitter-auth-info?state=${state}&code=${code}`, + ); + + return newTwitterAuthInfo; +}; From 2655c35c3231ec52eb7b10b7ec0531232bd88ce6 Mon Sep 17 00:00:00 2001 From: HeesungB Date: Wed, 14 Dec 2022 16:54:08 +0900 Subject: [PATCH 7/8] Remove unused file --- repository/icns.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 repository/icns.ts diff --git a/repository/icns.ts b/repository/icns.ts deleted file mode 100644 index e69de29..0000000 From 8897eac973968c26926c5f4f81480e96fa15c596 Mon Sep 17 00:00:00 2001 From: HeesungB Date: Wed, 14 Dec 2022 20:36:08 +0900 Subject: [PATCH 8/8] [WIP] : ICNS Query --- components/connect-wallet-modal/modal.tsx | 1 + constants/icns.ts | 2 +- pages/verification/index.tsx | 75 ++++++++++++++++++----- repository/icns.ts | 43 +++++++++++++ repository/index.ts | 1 + types/api-response.ts | 22 +++++++ types/index.ts | 1 + types/twitter.ts | 5 ++ 8 files changed, 135 insertions(+), 15 deletions(-) create mode 100644 repository/icns.ts create mode 100644 types/twitter.ts diff --git a/components/connect-wallet-modal/modal.tsx b/components/connect-wallet-modal/modal.tsx index 8797812..e346d65 100644 --- a/components/connect-wallet-modal/modal.tsx +++ b/components/connect-wallet-modal/modal.tsx @@ -17,6 +17,7 @@ export const ConnectWalletModal: FunctionComponent = (props) => { (); + const [twitterAuthInfo, setTwitterAuthInfo] = useState(); const [isLoading, setIsLoading] = useState(true); const [wallet, setWallet] = useState(); const [allChains, setAllChains] = useState(); const [chainList, setChainList] = useState([]); + const [registeredAddressList, setRegisteredAddressList] = useState( + [], + ); const [checkedItems, setCheckedItems] = useState(new Set()); const [allChecked, setAllChecked] = useState(false); const [searchValue, setSearchValue] = useState(""); @@ -81,14 +89,38 @@ export default function VerificationPage() { const { state, code } = fetchUrlQueryParameter(); - // Fetch Twitter Profile - const twitterInfo = await fetchTwitterInfo(state, code); - setTwitterAuthInfo(twitterInfo); + try { + // Initialize Wallet + await initWallet(); - // Initialize Wallet - await initWallet(); + // Fetch Twitter Profile + const twitterInfo = await fetchTwitterInfo(state, code); - setIsLoading(false); + const registeredQueryResponse = await queryRegisteredTwitterId( + twitterInfo.id, + ); + + setTwitterAuthInfo({ + ...twitterInfo, + isRegistered: "data" in registeredQueryResponse, + }); + + if ("data" in registeredQueryResponse) { + const addressesQueryResponse = await queryAddressesFromTwitterName( + registeredQueryResponse.data.name, + ); + + setRegisteredAddressList( + addressesQueryResponse.data.addresses.map( + (address) => address.address, + ), + ); + } + } catch (e) { + console.log(e); + } finally { + setIsLoading(false); + } } }; @@ -111,6 +143,14 @@ export default function VerificationPage() { } }, [wallet]); + useEffect(() => { + const filteredChainList = chainList.filter((chain) => { + return registeredAddressList.includes(chain.address); + }); + + setCheckedItems(new Set(filteredChainList)); + }, [registeredAddressList]); + const fetchChainList = async () => { if (wallet) { const chainIds = (await wallet.getChainInfosWithoutEndpoints()).map( @@ -193,9 +233,9 @@ export default function VerificationPage() { if (twitterAuthInfo && wallet) { const key = await wallet.getKey(MainChainId); - const chainIds = Array.from(checkedItems).map( - (chain) => (chain as ChainItemType).chainId, - ); + const chainIds = Array.from(checkedItems).map((chain) => { + return (chain as ChainItemType).chainId; + }); return await wallet.signICNSAdr36( MainChainId, @@ -264,13 +304,20 @@ export default function VerificationPage() { ); }); - const aminoMsgs = [registerMsg.amino]; - const protoMsgs = [registerMsg.proto]; + const aminoMsgs = twitterAuthInfo?.isRegistered + ? [] + : [registerMsg.amino]; + const protoMsgs = twitterAuthInfo?.isRegistered + ? [] + : [registerMsg.proto]; + for (const addressMsg of addressMsgs) { aminoMsgs.push(addressMsg.amino); protoMsgs.push(addressMsg.proto); } + console.log(aminoMsgs); + const chainInfo = { chainId: MainChainId, rest: REST_URL, diff --git a/repository/icns.ts b/repository/icns.ts new file mode 100644 index 0000000..cd51b39 --- /dev/null +++ b/repository/icns.ts @@ -0,0 +1,43 @@ +import { request } from "../utils/url"; +import { + REGISTRAR_ADDRESS, + RESOLVER_ADDRESS, + REST_URL, +} from "../constants/icns"; +import { Buffer } from "buffer/"; +import { + AddressesQueryResponse, + NameByTwitterIdQueryResponse, + QueryError, +} from "../types"; + +const getCosmwasmQueryUrl = (contractAddress: string, queryMsg: string) => + `${REST_URL}/cosmwasm/wasm/v1/contract/${contractAddress}/smart/${queryMsg}`; + +export const queryRegisteredTwitterId = async ( + twitterId: string, +): Promise => { + const msg = { + name_by_twitter_id: { twitter_id: twitterId }, + }; + return request( + getCosmwasmQueryUrl( + REGISTRAR_ADDRESS, + Buffer.from(JSON.stringify(msg)).toString("base64"), + ), + ); +}; + +export const queryAddressesFromTwitterName = async ( + twitterUsername: string, +): Promise => { + const msg = { + addresses: { name: twitterUsername }, + }; + return request( + getCosmwasmQueryUrl( + RESOLVER_ADDRESS, + Buffer.from(JSON.stringify(msg)).toString("base64"), + ), + ); +}; diff --git a/repository/index.ts b/repository/index.ts index 5517f2d..186b3f4 100644 --- a/repository/index.ts +++ b/repository/index.ts @@ -1 +1,2 @@ export * from "./twitter"; +export * from "./icns"; diff --git a/types/api-response.ts b/types/api-response.ts index 0be5888..19f9117 100644 --- a/types/api-response.ts +++ b/types/api-response.ts @@ -37,3 +37,25 @@ export interface IcnsVerificationResponse { } )[]; } + +export interface NameByTwitterIdQueryResponse { + data: { + name: string; + }; +} + +export interface AddressesQueryResponse { + data: { + addresses: RegisteredAddresses[]; + }; +} + +export interface RegisteredAddresses { + address: string; + bech32_prefix: string; +} + +export interface QueryError { + code: number; + message: string; +} diff --git a/types/index.ts b/types/index.ts index 6656919..7de37b7 100644 --- a/types/index.ts +++ b/types/index.ts @@ -2,3 +2,4 @@ export * from "./width-height-props"; export * from "./api-response"; export * from "./chain-item-type"; export * from "./msg"; +export * from "./twitter"; diff --git a/types/twitter.ts b/types/twitter.ts new file mode 100644 index 0000000..3241069 --- /dev/null +++ b/types/twitter.ts @@ -0,0 +1,5 @@ +import { TwitterAuthInfoResponse } from "./api-response"; + +export interface TwitterProfileType extends TwitterAuthInfoResponse { + isRegistered: boolean; +}