Skip to content

Commit

Permalink
integrate alldomains to helium wallet: (#416)
Browse files Browse the repository at this point in the history
* add TldParser to retrieve domain owner
* add debounce to avoid unneccessary rpc calls
* add alias/nickname as the domain when applicable
  • Loading branch information
crypt0miester authored Aug 10, 2023
1 parent 83e9812 commit c53aee4
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 22 deletions.
21 changes: 11 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"@ledgerhq/react-native-hw-transport-ble": "6.27.2",
"@metaplex-foundation/js": "0.17.6",
"@metaplex-foundation/mpl-bubblegum": "0.6.0",
"@onsol/tldparser": "^0.5.3",
"@pythnetwork/client": "^2.17.0",
"@react-native-async-storage/async-storage": "1.18.1",
"@react-native-community/blur": "4.3.0",
Expand Down Expand Up @@ -291,29 +292,29 @@
"tls": false
},
"browser": {
"zlib": "browserify-zlib",
"_stream_duplex": "readable-stream/duplex",
"_stream_passthrough": "readable-stream/passthrough",
"_stream_readable": "readable-stream/readable",
"_stream_transform": "readable-stream/transform",
"_stream_writable": "readable-stream/writable",
"console": "console-browserify",
"constants": "constants-browserify",
"crypto": "react-native-crypto",
"dgram": "react-native-udp",
"dns": "dns.js",
"net": "react-native-tcp",
"domain": "domain-browser",
"fs": "react-native-level-fs",
"http": "@tradle/react-native-http",
"https": "https-browserify",
"net": "react-native-tcp",
"os": "react-native-os",
"path": "path-browserify",
"querystring": "querystring-es3",
"fs": "react-native-level-fs",
"_stream_transform": "readable-stream/transform",
"_stream_readable": "readable-stream/readable",
"_stream_writable": "readable-stream/writable",
"_stream_duplex": "readable-stream/duplex",
"_stream_passthrough": "readable-stream/passthrough",
"dgram": "react-native-udp",
"stream": "stream-browserify",
"timers": "timers-browserify",
"tls": false,
"tty": "tty-browserify",
"vm": "vm-browserify",
"tls": false
"zlib": "browserify-zlib"
}
}
30 changes: 30 additions & 0 deletions src/features/addressBook/ContactDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import useAlert from '@hooks/useAlert'
import CloseButton from '@components/CloseButton'
import { solAddressIsValid, accountNetType } from '@utils/accountUtils'
import { heliumAddressFromSolAddress } from '@helium/spl-utils'
import { useDebounce } from 'use-debounce'
import { fetchDomainOwner } from '@utils/getDomainOwner'
import { HomeNavigationProp } from '../home/homeTypes'
import { useAccountStorage } from '../../storage/AccountStorageProvider'
import {
Expand All @@ -37,6 +39,7 @@ import {
import { useAppStorage } from '../../storage/AppStorageProvider'
import AddressExtra from './AddressExtra'
import { CSAccount } from '../../storage/cloudStorage'
import { useSolana } from '../../solana/SolanaProvider'

const BUTTON_HEIGHT = 55

Expand All @@ -62,6 +65,9 @@ const ContactDetails = ({ action, contact }: Props) => {
const { scannedAddress, setScannedAddress } = useAppStorage()
const spacing = useSpacing()
const { showOKCancelAlert } = useAlert()
const { connection } = useSolana()
// debounce is needed to avoid unneccessary rpc calls
const [debouncedAddress] = useDebounce(address, 800)

useEffect(() => {
if (route.params?.address) {
Expand All @@ -71,6 +77,30 @@ const ContactDetails = ({ action, contact }: Props) => {
}
}, [contact, route])

const handleDomainAddress = useCallback(
async ({ domain }: { domain: string }) => {
if (!connection) return
return fetchDomainOwner(connection, domain)
},
[connection],
)

useEffect(() => {
// only parse addresses which include dots.
if (debouncedAddress.split('.').length === 2) {
handleDomainAddress({ domain: debouncedAddress }).then(
(resolvedAddress) => {
// owner was not found so we do not set the owner address
if (!resolvedAddress) return
setAddress(resolvedAddress)
// if nickname was previously set we ignore setting the domain as nickname
if (nickname) return
setNickname(debouncedAddress)
},
)
}
}, [debouncedAddress, handleDomainAddress, nickname])

const onRequestClose = useCallback(() => {
homeNav.goBack()
}, [homeNav])
Expand Down
15 changes: 7 additions & 8 deletions src/features/payment/PaymentItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
NativeSyntheticEvent,
TextInputEndEditingEventData,
} from 'react-native'
import { useDebouncedCallback } from 'use-debounce'
import { CSAccount } from '../../storage/cloudStorage'
import { useBalance } from '../../utils/Balance'
import { accountNetType, ellipsizeAddress } from '../../utils/accountUtils'
Expand Down Expand Up @@ -120,14 +121,12 @@ const PaymentItem = ({
onToggleMax({ address, index })
}, [address, index, onToggleMax])

const handleEditAddress = useCallback(
(text?: string) => {
onEditAddress({ address: text || '', index })
},
[index, onEditAddress],
)
// debounce is needed to avoid unneccessary rpc calls
const handleEditAddress = useDebouncedCallback((text?: string) => {
onEditAddress({ address: text || '', index })
}, 800)

const handleAddressBlur = useCallback(
const handleAddressBlur = useDebouncedCallback(
(event?: NativeSyntheticEvent<TextInputEndEditingEventData>) => {
const text = event?.nativeEvent.text
handleAddressError({
Expand All @@ -136,7 +135,7 @@ const PaymentItem = ({
isHotspotOrValidator: false,
})
},
[handleAddressError, index],
800,
)

const handleRemove = useCallback(() => {
Expand Down
32 changes: 28 additions & 4 deletions src/features/payment/PaymentScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import Toast from 'react-native-simple-toast'
import { useSelector } from 'react-redux'
import { fetchDomainOwner } from '@utils/getDomainOwner'
import useSubmitTxn from '../../hooks/useSubmitTxn'
import { RootNavigationProp } from '../../navigation/rootTypes'
import { useSolana } from '../../solana/SolanaProvider'
Expand Down Expand Up @@ -131,7 +132,7 @@ const PaymentScreen = () => {
return new BN(balanceBigint.toString())
}
}, [balanceBigint])
const { anchorProvider } = useSolana()
const { anchorProvider, connection } = useSolana()

const appDispatch = useAppDispatch()
const navigation = useNavigation<HomeNavigationProp>()
Expand Down Expand Up @@ -489,6 +490,14 @@ const PaymentScreen = () => {
[dispatch],
)

const handleDomainAddress = useCallback(
async ({ domain }: { domain: string }) => {
if (!connection) return
return fetchDomainOwner(connection, domain)
},
[connection],
)

const handleAddressError = useCallback(
({
index,
Expand All @@ -505,6 +514,12 @@ const PaymentScreen = () => {
}
let invalidAddress = false

// only handle address which include dots.
if (address.split('.').length === 2) {
// retrieve the address which has been set previously by handleEditAddress.
/* eslint-disable-next-line no-param-reassign */
address = paymentState.payments[index].address || ''
}
invalidAddress = !!address && !solAddressIsValid(address)

const wrongNetType =
Expand All @@ -513,20 +528,28 @@ const PaymentScreen = () => {
accountNetType(address) !== networkType
handleSetPaymentError(index, invalidAddress || wrongNetType)
},
[handleSetPaymentError, networkType],
[handleSetPaymentError, networkType, paymentState],
)

const handleEditAddress = useCallback(
async ({ index, address }: { index: number; address: string }) => {
if (index === undefined || !currentAccount || !anchorProvider) return

let domain = ''
if (address.split('.').length === 2) {
const resolvedAddress =
(await handleDomainAddress({ domain: address })) || ''
/* eslint-disable-next-line no-param-reassign */
address = resolvedAddress
// if the address is resolved then the domain could also be an alias/nickname of the address.
if (resolvedAddress) domain = address
}
const allAccounts = unionBy(
contacts,
Object.values(accounts || {}),
({ address: addr }) => addr,
)
let contact = allAccounts.find((c) => c.address === address)
if (!contact) contact = { address, netType: networkType, alias: '' }
if (!contact) contact = { address, netType: networkType, alias: domain }

const createTokenAccountFee =
await calcCreateAssociatedTokenAccountAccountFee(
Expand All @@ -551,6 +574,7 @@ const PaymentScreen = () => {
networkType,
anchorProvider,
mint,
handleDomainAddress,
],
)

Expand Down
16 changes: 16 additions & 0 deletions src/utils/getDomainOwner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TldParser } from '@onsol/tldparser'
import { Connection } from '@solana/web3.js'

// retrives AllDomain domain owner.
// the domain must include the dot
export async function fetchDomainOwner(connection: Connection, domain: string) {
try {
const parser = new TldParser(connection)
const owner = await parser.getOwnerFromDomainTld(domain)
if (!owner) return
return owner.toBase58()
} catch (e) {
// Handle the error here if needed
// console.error("Error fetching domain owner:", e);
}
}
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3320,6 +3320,14 @@
mkdirp "^1.0.4"
rimraf "^3.0.2"

"@onsol/tldparser@^0.5.3":
version "0.5.3"
resolved "https://registry.yarnpkg.com/@onsol/tldparser/-/tldparser-0.5.3.tgz#f5a0a06fa69af0e8a2783464bbd32b3e88ad0b1a"
integrity sha512-rICUDhYPwDuO81wo4HI7QSCf6kQiaM0mSv3HKBJPrRxliIvgwanAoU5H0p54HEdAKeS3pmeLi5wB6ROpGxTZ/A==
dependencies:
"@ethersproject/sha2" "^5.7.0"
"@metaplex-foundation/beet-solana" "^0.4.0"

"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
Expand Down

0 comments on commit c53aee4

Please sign in to comment.