diff --git a/src/lib/components/input-address/input-address.svelte b/src/lib/components/input-address/input-stream-receiver.svelte
similarity index 50%
rename from src/lib/components/input-address/input-address.svelte
rename to src/lib/components/input-address/input-stream-receiver.svelte
index 4200123af..251c14cad 100644
--- a/src/lib/components/input-address/input-address.svelte
+++ b/src/lib/components/input-address/input-stream-receiver.svelte
@@ -4,6 +4,9 @@
import { ethers } from 'ethers';
import type { TextInputValidationState } from '$lib/components/text-input/text-input';
import { createEventDispatcher } from 'svelte';
+ import { BASE_URL } from '$lib/utils/base-url';
+ import assert from '$lib/utils/assert';
+ import { Utils } from 'radicle-drips';
export let value: string | undefined = undefined;
export let validatedValue: string | undefined = undefined;
@@ -17,18 +20,49 @@
const dispatch = createEventDispatcher();
- let addressValidationState: TextInputValidationState = { type: 'unvalidated' };
+ let inputValidationState: TextInputValidationState = { type: 'unvalidated' };
- async function validateAddress(input: string | undefined) {
+ async function validateInput(input: string | undefined) {
if (!input) {
- addressValidationState = { type: 'unvalidated' };
+ inputValidationState = { type: 'unvalidated' };
validatedValue = undefined;
return;
}
- if (input.endsWith('.eth')) {
+ if (input.includes(`${BASE_URL}/app/drip-lists/`)) {
+ inputValidationState = {
+ type: 'pending',
+ };
+
+ const dripListId = input.substring(input.lastIndexOf('/') + 1);
+ assert(dripListId);
+
+ if (Utils.AccountId.getDriver(dripListId) !== 'nft') {
+ inputValidationState = {
+ type: 'invalid',
+ message: 'Invalid Drip List URL',
+ };
+
+ throw new Error('Invalid Drip List URL');
+ }
+
+ if (dripListId) {
+ validatedValue = dripListId;
+ value = dripListId;
+
+ inputValidationState = {
+ type: 'valid',
+ };
+ } else {
+ validatedValue = undefined;
+ inputValidationState = {
+ type: 'invalid',
+ message: 'Unable to resolve Drip List URL',
+ };
+ }
+ } else if (input.endsWith('.eth')) {
// lookup ENS
- addressValidationState = {
+ inputValidationState = {
type: 'pending',
};
@@ -38,12 +72,12 @@
validatedValue = address;
value = address;
- addressValidationState = {
+ inputValidationState = {
type: 'valid',
};
} else {
validatedValue = undefined;
- addressValidationState = {
+ inputValidationState = {
type: 'invalid',
message: 'Unable to resolve ENS name',
};
@@ -58,33 +92,33 @@
if (exclusionMatch) {
// is excluded!
- addressValidationState = {
+ inputValidationState = {
type: 'invalid',
message: exclusionMatch.msg,
};
} else {
// valid
- addressValidationState = {
+ inputValidationState = {
type: 'valid',
};
}
} else {
// invalid
validatedValue = undefined;
- addressValidationState = {
+ inputValidationState = {
type: 'invalid',
- message: 'Enter a valid Ethereum address or ENS name.',
+ message: 'Enter a valid Ethereum address, ENS name, or Drip List URL.',
};
}
}
- // ensure initial value is validated since validateAddress() is async
+ // ensure initial value is validated since validateInput() is async
if (value?.length) {
- validateAddress(value).then(() => dispatch('validationChange', addressValidationState));
+ validateInput(value).then(() => dispatch('validationChange', inputValidationState));
}
- $: validateAddress(value);
- $: dispatch('validationChange', addressValidationState);
+ $: validateInput(value);
+ $: dispatch('validationChange', inputValidationState);
diff --git a/src/lib/flows/create-stream-flow/input-details.svelte b/src/lib/flows/create-stream-flow/input-details.svelte
index ee048c433..00b9ffdce 100644
--- a/src/lib/flows/create-stream-flow/input-details.svelte
+++ b/src/lib/flows/create-stream-flow/input-details.svelte
@@ -40,7 +40,6 @@
import Token from '$lib/components/token/token.svelte';
import type { Items } from '$lib/components/list-select/list-select.types';
import formatTokenAmount from '$lib/utils/format-token-amount';
- import InputAddress from '$lib/components/input-address/input-address.svelte';
import Toggleable from '$lib/components/toggleable/toggleable.svelte';
import createStream from './methods/create-stream';
import { get, type Writable } from 'svelte/store';
@@ -59,6 +58,8 @@
CreateStreamFlowAddressDriverAccountFragment,
CreateStreamFlowDetailsNftDriverAccountFragment,
} from './__generated__/gql.generated';
+ import InputStreamReceiver from '$lib/components/input-address/input-stream-receiver.svelte';
+ import { isAddress } from 'ethers/lib/utils';
const dispatch = createEventDispatcher();
@@ -246,11 +247,17 @@
to={receiver
? receiver
: recipientInputValidationState.type === 'valid' && recipientInputValue
- ? {
- __typename: 'AddressDriverAccount',
- driver: Driver.Address,
- address: recipientInputValue,
- }
+ ? isAddress(recipientInputValue) // TODO: Extract to function when project receiver is supported.
+ ? {
+ __typename: 'AddressDriverAccount',
+ driver: Driver.Address,
+ address: recipientInputValue,
+ }
+ : {
+ __typename: 'NftDriverAccount',
+ driver: Driver.Nft,
+ accountId: recipientInputValue,
+ }
: undefined}
amountPerSecond={amountValidationState?.type === 'valid' ? amountPerSecond : undefined}
/>
@@ -258,14 +265,12 @@
headline={receiver ? 'Start a Continuous Donation' : 'Create stream'}
description="Stream any ERC-20 token from your Drips account."
/>
- {#if !nameInputHidden}
-
-
-
- {/if}
+
+
+
{#if !receiver}
-
diff --git a/src/routes/app/(app)/[accountId]/tokens/[token]/streams/[dripId]/+page.svelte b/src/routes/app/(app)/[accountId]/tokens/[token]/streams/[dripId]/+page.svelte
index 869c8a66b..c60c7dd8c 100644
--- a/src/routes/app/(app)/[accountId]/tokens/[token]/streams/[dripId]/+page.svelte
+++ b/src/routes/app/(app)/[accountId]/tokens/[token]/streams/[dripId]/+page.svelte
@@ -74,7 +74,8 @@
$: {
if (stream) {
streamName =
- stream.receiver.driver === 'nft' ? 'Continuous donation' : stream.name ?? 'Unnamed stream';
+ stream.name ||
+ (stream.receiver.driver === 'nft' ? 'Continuous donation' : 'Unnamed stream');
}
}
diff --git a/src/routes/app/(app)/funds/sections/streams.section.svelte b/src/routes/app/(app)/funds/sections/streams.section.svelte
index 0f2e0cd0e..8f8facac0 100644
--- a/src/routes/app/(app)/funds/sections/streams.section.svelte
+++ b/src/routes/app/(app)/funds/sections/streams.section.svelte
@@ -94,7 +94,8 @@
// TODO: Donʼt presume that any stream to an NFT subaccount is going to a Drip List.
const streamName =
- stream.receiver.driver === 'nft' ? 'Continuous donation' : stream.name ?? 'Unnamed stream';
+ stream.name ||
+ (stream.receiver.driver === 'nft' ? 'Continuous donation' : 'Unnamed stream');
return {
streamId: stream.id,