Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased (develop)

- added: Resolve and display ZcashNames (.zcash) in the Zcash send flow and transaction history.
- changed: Remove free FIO handle creation flows.

## 4.49.0 (staging)
Expand Down
7 changes: 2 additions & 5 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export default [
'src/components/layout/Peek.tsx',

'src/components/modals/AccelerateTxModal.tsx',
'src/components/modals/AddressModal.tsx',

'src/components/modals/AirshipFullScreenSpinner.tsx',
'src/components/modals/AutoLogoutModal.tsx',
'src/components/modals/BackupModal.tsx',
Expand Down Expand Up @@ -286,8 +286,6 @@ export default [
'src/components/scenes/SwapSettingsScene.tsx',
'src/components/scenes/SwapSuccessScene.tsx',

'src/components/scenes/TransactionDetailsScene.tsx',

'src/components/scenes/TransactionsExportScene.tsx',

'src/components/scenes/WalletRestoreScene.tsx',
Expand Down Expand Up @@ -358,7 +356,6 @@ export default [
'src/components/themed/Thermostat.tsx',
'src/components/themed/Title.tsx',
'src/components/themed/TransactionListComponents.tsx',
'src/components/themed/TransactionListRow.tsx',

'src/components/themed/VectorIcon.tsx',
'src/components/themed/WalletList.tsx',
Expand All @@ -372,7 +369,7 @@ export default [

'src/components/themed/WalletListSwipeableCurrencyRow.tsx',
'src/components/themed/WalletListSwipeableLoadingRow.tsx',
'src/components/tiles/AddressTile2.tsx',

'src/components/tiles/AprCard.tsx',
'src/components/tiles/CountdownTile.tsx',
'src/components/tiles/CryptoFiatAmountTile.tsx',
Expand Down
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ module.exports = {
preset: 'react-native',
setupFilesAfterEnv: ['./jestSetup.js'],
transformIgnorePatterns: [
'<rootDir>/node_modules/(?!(@react-native|react-native|@react-navigation))'
'<rootDir>/node_modules/(?!(@react-native|react-native|@react-navigation|zcashname-sdk|@noble/ed25519))'
]
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@
"url-parse": "^1.5.2",
"use-context-selector": "^2.0.0",
"yaob": "^0.3.12",
"yavent": "^0.1.5"
"yavent": "^0.1.5",
"zcashname-sdk": "^0.7.2"
},
"devDependencies": {
"@babel/core": "^7.25.2",
Expand Down
4 changes: 4 additions & 0 deletions src/actions/LoginActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { ConfirmContinueModal } from '../components/modals/ConfirmContinueModal'
import { SurveyModal } from '../components/modals/SurveyModal'
import { Airship, showError } from '../components/services/AirshipInstance'
import { getExperimentConfig } from '../experimentConfig'
import { clearZnsLookupCache } from '../hooks/useZnsName'
import { lstrings } from '../locales/strings'
import type { WalletCreateItem } from '../selectors/getCreateWalletList'
import { config } from '../theme/appConfig'
Expand All @@ -32,6 +33,7 @@ import { currencyCodesToEdgeAssets } from '../util/CurrencyInfoHelpers'
import { logActivity } from '../util/logger'
import { logEvent, trackError } from '../util/tracking'
import { runWithTimeout } from '../util/utils'
import { resetZnsClient } from '../util/zns'
import {
loadAccountReferral,
refreshAccountReferral
Expand Down Expand Up @@ -323,6 +325,8 @@ export function logoutRequest(
Keyboard.dismiss()
Airship.clear()
resetLocalAccountSettingsCache()
resetZnsClient()
clearZnsLookupCache()

dispatch({ type: 'LOGOUT' })
if (typeof account.logout === 'function') await account.logout()
Expand Down
29 changes: 29 additions & 0 deletions src/components/modals/AddressModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
getFioAddressCache
} from '../../util/FioAddressUtils'
import { resolveName } from '../../util/resolveName'
import { isZnsName, resolveZnsName } from '../../util/zns'
import { EdgeButton } from '../buttons/EdgeButton'
import { EdgeTouchableWithoutFeedback } from '../common/EdgeTouchableWithoutFeedback'
import { showDevError, showError } from '../services/AirshipInstance'
Expand Down Expand Up @@ -180,9 +181,14 @@ export class AddressModalComponent extends React.Component<Props, State> {
}

checkIfDomain = (domain: string): boolean => {
// ZNS only resolves on Zcash wallets — gating here so non-zcash wallets
// don't trip into the domain-resolution path on `.zcash` input and end
// up showing a spurious "unsupported domain" error.
const isZcash = this.props.coreWallet.currencyInfo.pluginId === 'zcash'
return (
this.checkIfUnstoppableDomain(domain) ||
this.checkIfEnsDomain(domain) ||
(isZcash && this.checkIfZnsName(domain)) ||
this.checkIfAlias(domain)
)
}
Expand All @@ -193,6 +199,8 @@ export class AddressModalComponent extends React.Component<Props, State> {
checkIfEnsDomain = (name: string): boolean =>
ENS_DOMAINS.some(domain => name.endsWith(domain))

checkIfZnsName = (name: string): boolean => isZnsName(name)

fetchUnstoppableDomainAddress = async (
resolver: Resolver,
domain: string,
Expand Down Expand Up @@ -232,6 +240,13 @@ export class AddressModalComponent extends React.Component<Props, State> {
return address
}

fetchZnsAddress = async (domain: string): Promise<string> => {
const address = await resolveZnsName(domain)
if (address == null)
throw new ResolutionError('UnregisteredDomain', { domain })
return address
}

resolveName = async (name: string, currencyTicker: string): Promise<void> => {
this.setState({ errorLabel: undefined })
if (name === '') return
Expand All @@ -255,6 +270,11 @@ export class AddressModalComponent extends React.Component<Props, State> {
)
} else if (this.checkIfEnsDomain(name)) {
address = await this.fetchEnsAddress(name)
} else if (
this.checkIfZnsName(name) &&
this.props.coreWallet.currencyInfo.pluginId === 'zcash'
) {
address = await this.fetchZnsAddress(name)
Comment thread
cursor[bot] marked this conversation as resolved.
}
if (address == null) {
throw new ResolutionError('UnsupportedDomain', { domain: name })
Expand Down Expand Up @@ -413,6 +433,15 @@ export class AddressModalComponent extends React.Component<Props, State> {
) {
submitData = uri
}
// Same idea for ZNS (.zcash) names on Zcash — return the original name so
// the caller can capture znsName and persist it in transaction metadata.
if (
coreWallet.currencyInfo.pluginId === 'zcash' &&
typeof uri === 'string' &&
isZnsName(uri)
) {
submitData = uri
}
if (errorLabel != null) return
this.props.bridge.resolve(submitData)
}
Expand Down
23 changes: 18 additions & 5 deletions src/components/scenes/SendScene2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ const SendComponent = (props: Props): React.ReactElement => {
const handleChangeAddress =
(spendTarget: EdgeSpendTarget) =>
async (changeAddressResult: ChangeAddressResult): Promise<void> => {
const { addressEntryMethod, parsedUri, fioAddress, alias } =
const { addressEntryMethod, parsedUri, fioAddress, alias, znsName } =
changeAddressResult

if (parsedUri != null) {
Expand Down Expand Up @@ -468,7 +468,8 @@ const SendComponent = (props: Props): React.ReactElement => {
}
spendTarget.otherParams = {
fioAddress,
zanoAlias: alias
zanoAlias: alias,
znsName
}

// We can assume the spendTarget object came from the Component spendInfo so simply resetting the spendInfo
Expand All @@ -495,10 +496,12 @@ const SendComponent = (props: Props): React.ReactElement => {
spendTarget: EdgeSpendTarget
): React.ReactElement => {
const { publicAddress, nativeAmount, otherParams = {} } = spendTarget
const { fioAddress } = otherParams
const { fioAddress, znsName } = otherParams
let title = ''
if (fioAddress != null) {
title = `Send To (${fioAddress}) ${publicAddress}`
} else if (znsName != null) {
title = `Send To (${znsName}) ${publicAddress}`
} else {
title = `Send To ${publicAddress}`
}
Expand Down Expand Up @@ -540,7 +543,8 @@ const SendComponent = (props: Props): React.ReactElement => {
if (coreWallet != null && hiddenFeaturesMap.address !== true) {
// TODO: Change API of AddressTile to access undefined recipientAddress
const { publicAddress = '', otherParams = {} } = spendTarget
const { fioAddress } = otherParams
const { fioAddress, zanoAlias, znsName } = otherParams
const recipientName = fioAddress ?? znsName ?? zanoAlias
const title =
lstrings.send_scene_send_to_address +
(spendInfo.spendTargets.length > 1 ? ` ${(index + 1).toString()}` : '')
Expand All @@ -559,7 +563,7 @@ const SendComponent = (props: Props): React.ReactElement => {
resetSendTransaction={handleResetSendTransaction(spendTarget)}
lockInputs={lockTilesMap.address}
isCameraOpen={doOpenCamera}
fioToAddress={fioAddress}
recipientName={recipientName}
navigation={navigation as NavigationBase}
/>
)
Expand Down Expand Up @@ -1320,6 +1324,15 @@ const SendComponent = (props: Props): React.ReactElement => {
payeeName = zanoAliases[0]
}
}
// Same idea for ZNS (.zec) names on Zcash
if (coreWallet.currencyInfo.pluginId === 'zcash') {
const znsNames = spendInfo.spendTargets
.map(t => t.otherParams?.znsName)
.filter((a): a is string => a != null && a.length > 0)
if (znsNames.length === 1) {
payeeName = znsNames[0]
}
}
for (const target of spendInfo.spendTargets) {
const { fioAddress } = target.otherParams ?? {}
if (fioAddress != null) {
Expand Down
13 changes: 12 additions & 1 deletion src/components/scenes/TransactionDetailsScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { useHandler } from '../../hooks/useHandler'
import { useHistoricalRate } from '../../hooks/useHistoricalRate'
import { useIconColor } from '../../hooks/useIconColor'
import { useWatch } from '../../hooks/useWatch'
import { useZnsName } from '../../hooks/useZnsName'
import { toPercentString } from '../../locales/intl'
import { lstrings } from '../../locales/strings'
import { getExchangeDenom } from '../../selectors/DenominationSelectors'
Expand Down Expand Up @@ -444,7 +445,17 @@ export const TransactionDetailsComponent: React.FC<Props> = props => {
direction === 'receive'
? lstrings.transaction_details_sender
: lstrings.transaction_details_recipient
const personName = localMetadata.name ?? personLabel
// Reverse-lookup only for outgoing txs — `spendTargets[0]` on a receive
// would be our own address.
const recipientAddress =
direction === 'send'
? transaction.spendTargets?.[0]?.publicAddress
: undefined
const znsName = useZnsName(wallet.currencyInfo.pluginId, recipientAddress)
const personName =
localMetadata.name != null && localMetadata.name !== ''
? localMetadata.name
: znsName ?? personLabel
Comment thread
j0ntz marked this conversation as resolved.
const personHeader = sprintf(
lstrings.transaction_details_person_name,
personLabel
Expand Down
40 changes: 27 additions & 13 deletions src/components/themed/TransactionListRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { useDisplayDenom } from '../../hooks/useDisplayDenom'
import { displayFiatAmount } from '../../hooks/useFiatText'
import { useHandler } from '../../hooks/useHandler'
import { useHistoricalRate } from '../../hooks/useHistoricalRate'
import { useZnsName } from '../../hooks/useZnsName'
import { formatNumber } from '../../locales/intl'
import { lstrings } from '../../locales/strings'
import { getExchangeDenom } from '../../selectors/DenominationSelectors'
Expand Down Expand Up @@ -57,15 +58,7 @@ interface TransactionViewInnerProps extends TransactionListRowProps {
isCard?: boolean
}

export const TransactionView = (props: TransactionListRowProps) => {
return <TransactionViewInner {...props} />
}

export const TransactionCard = (props: TransactionListRowProps) => {
return <TransactionViewInner {...props} isCard />
}

function TransactionViewInner(props: TransactionViewInnerProps) {
const TransactionViewInner: React.FC<TransactionViewInnerProps> = props => {
const theme = useTheme()
const styles = getStyles(theme)

Expand Down Expand Up @@ -109,7 +102,18 @@ function TransactionViewInner(props: TransactionViewInnerProps) {
account,
wallet
)
const { category, name } = mergedData
const { category, name: metadataName } = mergedData
// Reverse-lookup only for outgoing txs — `spendTargets[0]` on a receive
// would be our own address.
const recipientAddress =
direction === 'send'
? transaction.spendTargets?.[0]?.publicAddress
: undefined
const znsName = useZnsName(currencyInfo.pluginId, recipientAddress)
const name =
metadataName != null && metadataName !== ''
? metadataName
: znsName ?? metadataName
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.
const isSentTransaction = direction === 'send'

const cryptoAmount = div(
Expand All @@ -130,7 +134,9 @@ function TransactionViewInner(props: TransactionViewInnerProps) {
)

const cryptoAmountString = `${isSentTransaction ? '-' : '+'}${
denominationSymbol ? denominationSymbol + ' ' : ''
denominationSymbol != null && denominationSymbol !== ''
? denominationSymbol + ' '
: ''
}${cryptoAmountFormat}`

// Fiat Amount
Expand Down Expand Up @@ -249,13 +255,13 @@ function TransactionViewInner(props: TransactionViewInnerProps) {
failOnCancel: false,
url
}
Share.open(shareOptions).catch(e => {
Share.open(shareOptions).catch((e: unknown) => {
showError(e)
})
})

// HACK: Handle 100% of the margins because of SceneHeader usage on this scene
return isCard ? (
return isCard === true ? (
<EdgeCard icon={icon} onPress={handlePress} onLongPress={handleLongPress}>
<SectionView dividerMarginRem={[0.2, 0.5]} marginRem={0.25}>
<>
Expand Down Expand Up @@ -334,6 +340,14 @@ function TransactionViewInner(props: TransactionViewInnerProps) {
)
}

export const TransactionView: React.FC<TransactionListRowProps> = props => {
return <TransactionViewInner {...props} />
}

export const TransactionCard: React.FC<TransactionListRowProps> = props => {
return <TransactionViewInner {...props} isCard />
}

const getStyles = cacheStyles((theme: Theme) => ({
cardlessView: {
flexDirection: 'column',
Expand Down
Loading
Loading