From c9e3be2297dcd6e82b493180031ac2c1981962ad Mon Sep 17 00:00:00 2001 From: Jason Efstathiou Date: Tue, 30 Jul 2024 10:47:00 +0200 Subject: [PATCH 1/3] fix broken avatar upload (#1152) --- .../components/custom-avatar-upload/custom-avatar-upload.svelte | 2 +- src/routes/api/custom-avatars/upload/+server.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/components/custom-avatar-upload/custom-avatar-upload.svelte b/src/lib/components/custom-avatar-upload/custom-avatar-upload.svelte index ff646acac..11fb30da5 100644 --- a/src/lib/components/custom-avatar-upload/custom-avatar-upload.svelte +++ b/src/lib/components/custom-avatar-upload/custom-avatar-upload.svelte @@ -160,7 +160,7 @@ {:else if error === 'too-large'} File exceeds 5MB {:else if error === 'upload-failed'} - Upload failed. Pleae try again later. + Upload failed. Please try again later. {:else if error === 'too-many-files'} Only drop a single file {/if} diff --git a/src/routes/api/custom-avatars/upload/+server.ts b/src/routes/api/custom-avatars/upload/+server.ts index f32f73015..8abe438e5 100644 --- a/src/routes/api/custom-avatars/upload/+server.ts +++ b/src/routes/api/custom-avatars/upload/+server.ts @@ -23,7 +23,7 @@ export const POST = async ({ request }) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (stream as any)['path'] = 'avatar.png'; - const pin = await pinata.pinFileToIPFS(stream); + const pin = await pinata.pinFileToIPFS(stream, { pinataMetadata: { name: 'avatar' } }); return new Response(JSON.stringify(pin)); }; From b56795acf1b368d6431e9e1360ce8ed82069d813 Mon Sep 17 00:00:00 2001 From: Jason Efstathiou Date: Tue, 30 Jul 2024 11:09:26 +0200 Subject: [PATCH 2/3] Revert "simplify ens store provider connection handling (#1148)" This reverts commit 6996c531a98cf4225c79ef6c942b086f22f326dd. --- .../drip-list-badge/drip-list-badge.svelte | 4 ++- .../identity-badge/identity-badge.svelte | 4 ++- src/lib/stores/ens/ens.store.ts | 28 +++++++++++++++---- src/lib/stores/ens/ens.store.unit.test.ts | 21 +++++--------- src/lib/utils/decode-universal-account-id.ts | 16 +++++++++++ .../[accountId]/tokens/[token]/+page.svelte | 1 + src/routes/app/+layout.svelte | 4 ++- 7 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/lib/components/drip-list-badge/drip-list-badge.svelte b/src/lib/components/drip-list-badge/drip-list-badge.svelte index 6551b0835..9c8cb72be 100644 --- a/src/lib/components/drip-list-badge/drip-list-badge.svelte +++ b/src/lib/components/drip-list-badge/drip-list-badge.svelte @@ -29,8 +29,10 @@ export let disabled = false; export let outline = false; + const ensConnected = ensStore.connected; + // lookup ens name if owner is provided - $: showOwner && dripList && ensStore.lookup(dripList.owner.address); + $: showOwner && dripList && $ensConnected && ensStore.lookup(dripList.owner.address); $: ens = showOwner && dripList ? $ensStore[dripList.owner.address] : {}; $: username = ens?.name ?? (dripList && showOwner && formatAddress(dripList.owner.address)) ?? undefined; diff --git a/src/lib/components/identity-badge/identity-badge.svelte b/src/lib/components/identity-badge/identity-badge.svelte index 5acb73847..c62c62c4c 100644 --- a/src/lib/components/identity-badge/identity-badge.svelte +++ b/src/lib/components/identity-badge/identity-badge.svelte @@ -22,7 +22,9 @@ export let isReverse = false; export let tag: string | undefined = undefined; - $: ensStore.lookup(address); + const ensConnected = ensStore.connected; + + $: $ensConnected && ensStore.lookup(address); $: ens = $ensStore[address]; $: blockyUrl = `/api/blockies/${address}`; diff --git a/src/lib/stores/ens/ens.store.ts b/src/lib/stores/ens/ens.store.ts index c6dc6ad50..3b6b2c714 100644 --- a/src/lib/stores/ens/ens.store.ts +++ b/src/lib/stores/ens/ens.store.ts @@ -1,5 +1,7 @@ +import type { BaseProvider } from '@ethersproject/providers'; +import type { ethers } from 'ethers'; import { get, writable } from 'svelte/store'; -import walletStore from '../wallet/wallet.store'; +import assert from '$lib/utils/assert'; export interface ResolvedRecord { name?: string; @@ -12,6 +14,19 @@ type State = { export default (() => { const state = writable({}); + const connected = writable(false); + + let provider: ethers.providers.BaseProvider | undefined; + + /** + * Connect the store to a provider, which is needed in order to resolve ENS + * records. + * @param toProvider The provider to connect to. + */ + function connect(toProvider: BaseProvider) { + provider = toProvider; + connected.set(true); + } /** * Perform an ENS lookup for the provided address, and append the result to the @@ -19,8 +34,6 @@ export default (() => { * @param address The address to attempt resolving. */ async function lookup(address: string): Promise { - const { provider } = get(walletStore); - const saved = get(state)[address]; if (saved) return; @@ -28,7 +41,7 @@ export default (() => { // for the same name state.update((s) => ({ ...s, [address]: {} })); - const lookups = [provider.lookupAddress(address), provider.getAvatar(address)]; + const lookups = [provider?.lookupAddress(address), provider?.getAvatar(address)]; const [name, avatarUrl] = await Promise.all(lookups); @@ -56,7 +69,10 @@ export default (() => { * name in the store state. */ async function reverseLookup(name: string): Promise { - const { provider } = get(walletStore); + assert( + provider, + 'You need to `connect` the store to a provider before being able to reverse lookup', + ); const saved = Object.entries(get(state)).find((entry) => entry[1].name === name); @@ -75,6 +91,8 @@ export default (() => { return { subscribe: state.subscribe, + connect, + connected: { subscribe: connected.subscribe }, lookup, reverseLookup, clear, diff --git a/src/lib/stores/ens/ens.store.unit.test.ts b/src/lib/stores/ens/ens.store.unit.test.ts index d72aeb54f..75644a0f5 100644 --- a/src/lib/stores/ens/ens.store.unit.test.ts +++ b/src/lib/stores/ens/ens.store.unit.test.ts @@ -1,7 +1,6 @@ import { MockProvider } from '@rsksmart/mock-web3-provider'; -import { get, readable } from 'svelte/store'; +import { get } from 'svelte/store'; import ens from '.'; -import walletStore from '../wallet/wallet.store'; vi.mock('@rsksmart/mock-web3-provider', () => ({ MockProvider: vi.fn().mockImplementation(() => ({ @@ -10,11 +9,7 @@ vi.mock('@rsksmart/mock-web3-provider', () => ({ })), })); -vi.mock('$lib/stores/wallet/wallet.store', () => ({ - default: readable({ - provider: new MockProvider(), - }), -})); +const provider = new MockProvider(); afterEach(() => { ens.clear(); @@ -22,6 +17,8 @@ afterEach(() => { describe('ens store', () => { it('resolves records', async () => { + ens.connect(provider); + await ens.lookup('0x1234'); const expectedResult = { @@ -33,18 +30,14 @@ describe('ens store', () => { }); it('deduplicates requests', async () => { - const mockProvider = get(walletStore).provider; - const lookupSpy = vi.spyOn(mockProvider, 'lookupAddress'); - const getAvatarSpy = vi.spyOn(mockProvider, 'getAvatar'); + ens.connect(provider); ens.lookup('0x1234'); ens.lookup('0x1234'); ens.lookup('0x1234'); ens.lookup('0x1234'); - ens.lookup('0x1235'); - ens.lookup('0x1235'); - expect(lookupSpy).toHaveBeenCalledTimes(2); - expect(getAvatarSpy).toHaveBeenCalledTimes(2); + expect(provider.lookupAddress).toHaveBeenCalledTimes(2); + expect(provider.getAvatar).toHaveBeenCalledTimes(2); }); }); diff --git a/src/lib/utils/decode-universal-account-id.ts b/src/lib/utils/decode-universal-account-id.ts index 0c36d374a..781d7570e 100644 --- a/src/lib/utils/decode-universal-account-id.ts +++ b/src/lib/utils/decode-universal-account-id.ts @@ -2,6 +2,7 @@ import ens from '$lib/stores/ens'; import { getAddressDriverClient } from '$lib/utils/get-drips-clients'; import { isAddress } from 'ethers/lib/utils'; import { AddressDriverClient, Utils } from 'radicle-drips'; +import { get } from 'svelte/store'; interface AddressDriverResult { driver: 'address'; @@ -40,6 +41,21 @@ export default async function ( dripsAccountId, }; } else if (universalAcccountIdentifier.endsWith('.eth')) { + // Subscribe to ens.connected store and wait until it's true + + const ensConnected = ens.connected; + + if (!get(ensConnected)) { + await new Promise((resolve) => { + const unsubscribe = ensConnected.subscribe((connected) => { + if (connected) { + unsubscribe(); + resolve(undefined); + } + }); + }); + } + const lookup = await ens.reverseLookup(universalAcccountIdentifier); if (lookup) { const dripsAccountId = await (await getAddressDriverClient()).getAccountIdByAddress(lookup); diff --git a/src/routes/app/(app)/[accountId]/tokens/[token]/+page.svelte b/src/routes/app/(app)/[accountId]/tokens/[token]/+page.svelte index 88ed0e16b..317026927 100644 --- a/src/routes/app/(app)/[accountId]/tokens/[token]/+page.svelte +++ b/src/routes/app/(app)/[accountId]/tokens/[token]/+page.svelte @@ -39,6 +39,7 @@ import checkIsUser from '$lib/utils/check-is-user'; import decodeAccountId from '$lib/utils/decode-universal-account-id'; import LargeEmptyState from '$lib/components/large-empty-state/large-empty-state.svelte'; + // import collectFlowSteps from '$lib/flows/collect-flow/collect-flow-steps'; import getWithdrawSteps from '$lib/flows/withdraw-flow/withdraw-flow-steps'; import topUpFlowSteps from '$lib/flows/top-up-flow/top-up-flow-steps'; import addCustomTokenFlowSteps from '$lib/flows/add-custom-token/add-custom-token-flow-steps'; diff --git a/src/routes/app/+layout.svelte b/src/routes/app/+layout.svelte index 4b41db95f..359fd6747 100644 --- a/src/routes/app/+layout.svelte +++ b/src/routes/app/+layout.svelte @@ -33,7 +33,9 @@ await wallet.initialize(); loaded = true; - const { connected, network, address, safe } = $wallet; + const { connected, network, provider, address, safe } = $wallet; + + ens.connect(provider); themeStore.subscribe((v) => { const onboardTheme = v.currentTheme === 'h4x0r' ? 'dark' : v.currentTheme; From 6477405b46c4b73dab724397bd0cc183c5634523 Mon Sep 17 00:00:00 2001 From: Jason Efstathiou Date: Tue, 30 Jul 2024 15:42:34 +0200 Subject: [PATCH 3/3] Revert "fix: #1145 (#1146)" This reverts commit b798901aae6795b867561948e245606cb2092673. --- src/lib/components/search-bar/search.ts | 4 ++-- .../steps/enter-git-url/enter-git-url.svelte | 4 ++-- src/lib/utils/build-repo-url.ts | 4 ++-- src/lib/utils/is-valid-git-url.ts | 10 ++++------ .../[githubRepoName]/+page.server.ts | 12 ++++++------ 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/lib/components/search-bar/search.ts b/src/lib/components/search-bar/search.ts index 71031f80a..501f69b43 100644 --- a/src/lib/components/search-bar/search.ts +++ b/src/lib/components/search-bar/search.ts @@ -4,7 +4,7 @@ import tokens from '$lib/stores/tokens'; import type { TokenInfoWrapper } from '$lib/stores/tokens/tokens.store'; import { get } from 'svelte/store'; import { isAddress } from 'ethers/lib/utils'; -import { isSupportedGitUrl } from '$lib/utils/is-valid-git-url'; +import { isValidGitUrl } from '$lib/utils/is-valid-git-url'; import GitProjectService from '$lib/utils/project/GitProjectService'; export enum SearchItemType { @@ -74,7 +74,7 @@ export function updateSearchItems(accountId: string | undefined) { export default function search(input: string | undefined) { if (!input) return []; - if (isSupportedGitUrl(input)) { + if (isValidGitUrl(input)) { const { username, repoName } = GitProjectService.deconstructUrl(input); searchItems.push({ diff --git a/src/lib/flows/claim-project-flow/steps/enter-git-url/enter-git-url.svelte b/src/lib/flows/claim-project-flow/steps/enter-git-url/enter-git-url.svelte index 1d30b5b61..9a3a62d4e 100644 --- a/src/lib/flows/claim-project-flow/steps/enter-git-url/enter-git-url.svelte +++ b/src/lib/flows/claim-project-flow/steps/enter-git-url/enter-git-url.svelte @@ -27,7 +27,7 @@ import UnclaimedProjectCard, { UNCLAIMED_PROJECT_CARD_FRAGMENT, } from '$lib/components/unclaimed-project-card/unclaimed-project-card.svelte'; - import { isSupportedGitUrl } from '$lib/utils/is-valid-git-url'; + import { isSupportedGitUrl, isValidGitUrl } from '$lib/utils/is-valid-git-url'; import seededRandomElement from '$lib/utils/seeded-random-element'; import { page } from '$app/stores'; import possibleRandomEmoji from '$lib/utils/project/possible-random-emoji'; @@ -155,7 +155,7 @@ function submitInput() { if (isSupportedGitUrl($context.gitUrl)) { fetchProject(); - } else { + } else if (isValidGitUrl($context.gitUrl) && !isSupportedGitUrl($context.gitUrl)) { validationState = { type: 'invalid', message: 'Unsupported URL' }; } } diff --git a/src/lib/utils/build-repo-url.ts b/src/lib/utils/build-repo-url.ts index 76b9e5cb2..e136a7872 100644 --- a/src/lib/utils/build-repo-url.ts +++ b/src/lib/utils/build-repo-url.ts @@ -1,5 +1,5 @@ import { BASE_URL } from './base-url'; -import { isSupportedGitUrl } from './is-valid-git-url'; +import { isValidGitUrl } from './is-valid-git-url'; export function isDripsProjectUrl(value: string): boolean { return value.includes(`${BASE_URL}/app/projects/`); @@ -24,7 +24,7 @@ export function buildRepositoryURL(url: string): string { if (forge === 'github') { const githubUrl = `https://github.com/${repoPath}`; - if (isSupportedGitUrl(githubUrl)) { + if (isValidGitUrl(githubUrl)) { return `https://github.com/${repoPath}`; } diff --git a/src/lib/utils/is-valid-git-url.ts b/src/lib/utils/is-valid-git-url.ts index c33492226..50f9c3a71 100644 --- a/src/lib/utils/is-valid-git-url.ts +++ b/src/lib/utils/is-valid-git-url.ts @@ -32,12 +32,10 @@ function validateUrl(url: string, allowedHosts: string[]): boolean { } } -export function isSupportedGitUrl(url: string): boolean { - const githubUrlRegex = /^https:\/\/github\.com\/[\w-]+\/[\w.-]+$/; - - if (!githubUrlRegex.test(url)) { - return false; - } +export function isValidGitUrl(url: string): boolean { + return validateUrl(url, ['github.com', 'gitlab.com']); +} +export function isSupportedGitUrl(url: string): boolean { return validateUrl(url, ['github.com']); } diff --git a/src/routes/app/(app)/projects/(forges)/github/[githubUsername]/[githubRepoName]/+page.server.ts b/src/routes/app/(app)/projects/(forges)/github/[githubUsername]/[githubRepoName]/+page.server.ts index 7a0c58652..2af68cc31 100644 --- a/src/routes/app/(app)/projects/(forges)/github/[githubUsername]/[githubRepoName]/+page.server.ts +++ b/src/routes/app/(app)/projects/(forges)/github/[githubUsername]/[githubRepoName]/+page.server.ts @@ -12,7 +12,6 @@ import { getRepoDriverClient } from '$lib/utils/get-drips-clients'; import { Forge } from 'radicle-drips'; import cached from '$lib/utils/cache/remote/cached'; import queryCacheKey from '$lib/utils/cache/remote/query-cache-key'; -import { isSupportedGitUrl } from '$lib/utils/is-valid-git-url'; async function fetchDripsProject(repoUrl: string) { const getProjectsQuery = gql` @@ -33,15 +32,18 @@ async function fetchDripsProject(repoUrl: string) { const cacheKey = queryCacheKey(getProjectsQuery, [repoUrl], `project-page:${accountId}`); - return await cached(redis, cacheKey, 172800, () => - query( + return await cached( + redis, + cacheKey, + 172800, + () => query( getProjectsQuery, { url: repoUrl, }, fetch, ), - ); + ) } export const load = (async ({ params, fetch, url }) => { @@ -66,8 +68,6 @@ export const load = (async ({ params, fetch, url }) => { const repoUrl = `https://github.com/${githubUsername}/${githubRepoName}`; - if (!isSupportedGitUrl(repoUrl)) throw error(404); - const [repoRes, projectRes] = await Promise.all([ fetch(`/api/github/${encodeURIComponent(repoUrl)}`), fetchDripsProject(repoUrl),