Skip to content
Open
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
47 changes: 1 addition & 46 deletions app/hooks/use-nostr-profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ const useNostrProfile = () => {
[
"wss://relay.damus.io",
"wss://relay.primal.net",
"wss://nos.lol",
"wss://relay.islandbitcoin.com",
],
0,
Expand Down Expand Up @@ -451,52 +452,6 @@ const useNostrProfile = () => {
throw new Error("Failed to publish profile to any relays")
}

console.log(`\n✨ Profile update completed with ${successCount} successful publishes`)

// Background retry for remaining failed relays
if (failedRelays.length > 0) {
console.log(
`⏰ Scheduling background retry for ${failedRelays.length} failed relays in 5 seconds...`,
)
setTimeout(() => {
console.log("🔄 Starting background retry for failed relays...")
retryFailedRelays(signedKind0Event, failedRelays)
}, 5000)
}

// Verify profile propagation after 3 seconds
if (successfulRelays.length > 0) {
setTimeout(async () => {
console.log("\n🔍 Starting profile propagation verification...")

// Use the new verification helper
const verifyRelays = [
"wss://relay.flashapp.me",
"wss://relay.islandbitcoin.com",
"wss://relay.damus.io",
"wss://relay.primal.net",
]

const verification = await verifyEventOnRelays(
pool,
signedKind0Event.id,
verifyRelays,
0, // kind-0 for profile
)

if (verification.found) {
console.log(
`✅ Profile verified on ${verification.foundOnRelays.length} critical relays`,
)
console.log("Profile available on:", verification.foundOnRelays.join(", "))
} else {
console.log(
"⚠️ WARNING: Profile verification failed - not found on any critical relay",
)
}
}, 3000)
}

return { successCount, totalRelays: publicRelays.length, successfulRelays }
}

Expand Down
22 changes: 7 additions & 15 deletions app/screens/authentication-screen/username-set.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { PrimaryBtn } from "@app/components/buttons"
import { Screen } from "@app/components/screen"

// hooks
import useNostrProfile from "@app/hooks/use-nostr-profile"
import { useI18nContext } from "@app/i18n/i18n-react"
import useLogout from "@app/hooks/use-logout"
import { useAppConfig } from "@app/hooks"
Expand Down Expand Up @@ -43,13 +42,12 @@ export const UsernameSet: React.FC<Props> = ({ navigation, route }) => {
const { LL } = useI18nContext()
const { colors } = useTheme().theme
const styles = useStyles()

const { updateNostrProfile } = useNostrProfile()
const { logout } = useLogout()
const { userProfileEvent } = useChatContext()

const [error, setError] = useState<SetAddressError | undefined>()
const [lnAddress, setLnAddress] = useState("")
const [isSubmitting, setIsSubmitting] = useState(false)

const [updateUsername, { loading }] = useUserUpdateUsernameMutation({
update: (cache, { data }) => {
Expand Down Expand Up @@ -78,6 +76,8 @@ export const UsernameSet: React.FC<Props> = ({ navigation, route }) => {
})

const onSetLightningAddress = async () => {
setIsSubmitting(true)
setError(undefined)
const validationResult = validateLightningAddress(lnAddress)
if (!validationResult.valid) {
setError(validationResult.error)
Expand All @@ -102,26 +102,16 @@ export const UsernameSet: React.FC<Props> = ({ navigation, route }) => {
console.log("No existing profile found or failed to parse")
}
}

// Merge with new username data
updateNostrProfile({
content: {
...existingProfile,
name: lnAddress,
username: lnAddress,
lud16: `${lnAddress}@${lnAddressHostname}`,
nip05: `${lnAddress}@${lnAddressHostname}`,
},
})
if ((data?.userUpdateUsername?.errors ?? []).length > 0) {
if (data?.userUpdateUsername?.errors[0]?.code === "USERNAME_ERROR") {
setError(SetAddressError.ADDRESS_UNAVAILABLE)
} else {
setError(SetAddressError.UNKNOWN_ERROR)
}
setIsSubmitting(false)
return
}

setIsSubmitting(false)
dispatch(updateUserData({ username: lnAddress }))
navigation.reset({
index: 0,
Expand Down Expand Up @@ -178,6 +168,7 @@ export const UsernameSet: React.FC<Props> = ({ navigation, route }) => {
</Text>
<TextInput
autoCorrect={false}
editable={!isSubmitting}
autoComplete="off"
autoCapitalize="none"
style={styles.textInputStyle}
Expand All @@ -190,6 +181,7 @@ export const UsernameSet: React.FC<Props> = ({ navigation, route }) => {
{errorMessage && <GaloyErrorBox errorMessage={errorMessage} />}
</View>
<PrimaryBtn
loading={isSubmitting}
label={LL.SetAddressModal.save()}
disabled={lnAddress.length < 3}
onPress={onSetLightningAddress}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,17 @@ export const NostrSettingsScreen = () => {
if (isGenerating) return
setIsGenerating(true)
setProgressMessage("Creating Nostr profile...")
let newSecret = await saveNewNostrKey((message) => {
setProgressMessage(message)
})
let newSecret = await saveNewNostrKey(
(message) => {
setProgressMessage(message)
},
{
name: dataAuthed?.me?.username,
username: dataAuthed?.me?.username,
lud16: `${dataAuthed?.me?.username}@${lnDomain}`,
nip05: `${dataAuthed?.me?.username}@${lnDomain}`,
},
)
setSecretKey(newSecret)
setIsGenerating(false)
setProgressMessage("")
Expand All @@ -151,7 +159,9 @@ export const NostrSettingsScreen = () => {
style={{ marginRight: 10, opacity: isGenerating ? 0.5 : 1 }}
/>
<Text style={{ color: colors.white, fontWeight: "bold" }}>
{isGenerating ? progressMessage || LL.Nostr.creatingProfile() : LL.Nostr.createNewProfile()}
{isGenerating
? progressMessage || LL.Nostr.creatingProfile()
: LL.Nostr.createNewProfile()}
</Text>
</Pressable>
</View>
Expand Down
37 changes: 17 additions & 20 deletions app/utils/nostr/publish-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export async function publishEventToRelays(
pool: SimplePool,
event: Event,
relays: string[],
eventLabel: string = "Event"
eventLabel: string = "Event",
): Promise<{
successCount: number
failedCount: number
Expand Down Expand Up @@ -117,27 +117,32 @@ export async function verifyEventOnRelays(
pool: SimplePool,
eventId: string,
relays: string[],
eventKind?: number
eventKind?: number,
): Promise<{
found: boolean
foundOnRelays: string[]
missingFromRelays: string[]
event: Event | null
}> {
console.log(`\n🔍 Verifying ${eventKind === 0 ? "profile" : "event"} ${eventId} on ${relays.length} relays...`)
console.log(
`\n🔍 Verifying ${eventKind === 0 ? "profile" : "event"} ${eventId} on ${
relays.length
} relays...`,
)

const foundOnRelays: string[] = []
const missingFromRelays: string[] = []

let event: Event | null = null
const verifyPromises = relays.map(async (relay) => {
try {
const filter: any = { ids: [eventId] }
if (eventKind !== undefined) {
filter.kinds = [eventKind]
}

const event = await pool.get([relay], filter)

if (event && event.id === eventId) {
const eventFound = await pool.get([relay], filter)
event = eventFound
if (eventFound && eventFound.id === eventId) {
console.log(` ✅ Found on ${relay}`)
foundOnRelays.push(relay)
} else {
Expand All @@ -156,6 +161,7 @@ export async function verifyEventOnRelays(
found: foundOnRelays.length > 0,
foundOnRelays,
missingFromRelays,
event,
}

console.log(`\n📊 Verification Summary:`)
Expand All @@ -171,26 +177,17 @@ export async function verifyEventOnRelays(
* Gets the best relays for publishing based on purpose
*/
export function getPublishingRelays(purpose: "profile" | "note" | "general"): string[] {
const coreRelays = [
"wss://relay.flashapp.me",
"wss://relay.islandbitcoin.com",
]
const coreRelays = ["wss://relay.flashapp.me", "wss://relay.islandbitcoin.com"]

const majorPublicRelays = [
"wss://relay.damus.io",
"wss://relay.primal.net",
"wss://relay.snort.social",
]

const profileRelays = [
"wss://purplepag.es",
"wss://relay.nostr.band",
]
const profileRelays = ["wss://purplepag.es", "wss://relay.nostr.band"]

const noteRelays = [
"wss://relay.current.fyi",
"wss://relay.nostrplebs.com",
]
const noteRelays = ["wss://relay.current.fyi", "wss://relay.nostrplebs.com"]

switch (purpose) {
case "profile":
Expand All @@ -201,4 +198,4 @@ export function getPublishingRelays(purpose: "profile" | "note" | "general"): st
default:
return [...coreRelays, ...majorPublicRelays]
}
}
}