) => void;
+ /**
+ * Function to handle the input click. When the user clicks on the input, the list of options will be displayed
+ */
handleInputClick: () => void;
};
const ComboboxInput = ({
open,
+ leftIcon,
handleInputChange,
handleInputClick,
}: ComboboxInputProps) => (
selectedValue.label}
onChange={handleInputChange}
onClick={handleInputClick}
/>
+
+
+
);
@@ -52,9 +73,13 @@ const ComboboxOption = ({ option }: ComboboxOptionProps) => (
>
{({ selected, active }) => (
-
+
{option.icon}
-
+
{option.label}
@@ -73,38 +98,97 @@ export const NoResults = ({ css }: { css?: string }) => (
);
export type ComboboxItem = {
+ /**
+ * The key of the item.
+ */
value: string;
+ /**
+ * The label to display of the item.
+ */
label: string;
+ /**
+ * Optional icon to display on the left of the item.
+ */
icon?: React.ReactNode;
};
export type ComboboxProps = {
+ /**
+ * List of items to be displayed in the combobox.
+ */
items: ComboboxItem[];
+ /**
+ * The selected value of the combobox.
+ */
selectedValue: ComboboxItem | undefined;
+ /**
+ * If true, the combobox will add the input if it doesn't exist in the list of items.
+ */
+ withAutocomplete?: boolean;
+ /**
+ * Name of the left icon to display in the input. Defualt is "search".
+ */
+ leftIcon?: IconName;
+ /**
+ * Callback when the selected value changes.
+ */
onChange(option: ComboboxItem): void;
};
export const Combobox: React.FC = ({
items,
selectedValue = { value: '', label: '' },
+ withAutocomplete = false,
+ leftIcon = 'search',
onChange,
}) => {
- const [query, setQuery] = useState('');
+ const [filteredItems, setFilteredItems] = useState([]);
+ const [autocompleteItems, setAutocompleteItems] = useState(
+ []
+ );
+
+ useEffect(() => {
+ // If the selected value doesn't exist in the list of items, we add it
+ if (
+ items.filter((item) => item === selectedValue).length === 0 &&
+ selectedValue.value !== undefined &&
+ autocompleteItems.length === 0 &&
+ withAutocomplete
+ ) {
+ setAutocompleteItems([selectedValue]);
+ }
+ }, [selectedValue]);
+
+ useEffect(() => {
+ setFilteredItems(items);
+ }, [items]);
const buttonRef = useRef(null);
- const filteredItems =
- query === ''
- ? items
- : items.filter((person) =>
- person.label
- .toLowerCase()
- .replace(/\s+/g, '')
- .includes(query.toLowerCase().replace(/\s+/g, ''))
- );
+ const handleSearch = useDebounce((searchValue: string) => {
+ if (searchValue === '') {
+ setFilteredItems(items);
+
+ if (withAutocomplete) {
+ setAutocompleteItems([]);
+ handleComboboxChange({} as ComboboxItem);
+ }
+ } else {
+ const filteredValues = items.filter((item) =>
+ cleanString(item.label).startsWith(cleanString(searchValue))
+ );
+
+ if (withAutocomplete && filteredValues.length === 0) {
+ // If the search value doesn't exist in the list of items, we add it
+ setAutocompleteItems([{ value: searchValue, label: searchValue }]);
+ }
+ setFilteredItems(filteredValues);
+ }
+ }, 200);
const handleInputChange = (event: React.ChangeEvent) => {
- setQuery(event.target.value);
+ event.stopPropagation();
+ handleSearch(event.target.value);
};
const handleInputClick = () => {
@@ -116,7 +200,11 @@ export const Combobox: React.FC = ({
};
const handleLeaveTransition = () => {
- setQuery('');
+ setFilteredItems(items);
+ if (selectedValue.value === undefined && withAutocomplete) {
+ setAutocompleteItems([]);
+ handleComboboxChange({} as ComboboxItem);
+ }
};
return (
@@ -131,6 +219,7 @@ export const Combobox: React.FC = ({
handleInputChange={handleInputChange}
handleInputClick={handleInputClick}
open={open}
+ leftIcon={leftIcon}
/>
@@ -144,12 +233,25 @@ export const Combobox: React.FC = ({
afterLeave={handleLeaveTransition}
>
- {filteredItems.length === 0 && query !== '' ? (
+ {[...autocompleteItems, ...filteredItems].length === 0 ||
+ filteredItems === undefined ? (
) : (
- filteredItems.map((option: ComboboxItem) => {
- return ;
- })
+ <>
+ {autocompleteItems.length > 0 && Create new}
+ {autocompleteItems.map((autocompleteOption: ComboboxItem) => (
+
+ ))}
+ {autocompleteItems.length > 0 && filteredItems.length > 0 && (
+
+ )}
+ {filteredItems.map((option: ComboboxItem) => (
+
+ ))}
+ >
)}
diff --git a/ui/src/components/core/combobox/combobox.utils.ts b/ui/src/components/core/combobox/combobox.utils.ts
new file mode 100644
index 0000000..2b4de14
--- /dev/null
+++ b/ui/src/components/core/combobox/combobox.utils.ts
@@ -0,0 +1,2 @@
+export const cleanString = (str: string) =>
+ str.toLowerCase().replace(/\s+/g, '');
diff --git a/ui/src/constants/env.ts b/ui/src/constants/env.ts
index a3a470d..12ba134 100644
--- a/ui/src/constants/env.ts
+++ b/ui/src/constants/env.ts
@@ -3,6 +3,10 @@ export const env = Object.freeze({
id: import.meta.env.VITE_ALCHEMY_API_KEY || '',
appName: import.meta.env.VITE_ALCHEMY_APP_NAME || '',
},
+ ens: {
+ contractAddress: import.meta.env.VITE_ENS_ADDRESS || '',
+ validationEnsURL: import.meta.env.VITE_ENS_VALIDATION_URL || '',
+ },
firebase: {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY || '',
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN || '',
diff --git a/ui/src/hooks/use-debounce.ts b/ui/src/hooks/use-debounce.ts
new file mode 100644
index 0000000..7528399
--- /dev/null
+++ b/ui/src/hooks/use-debounce.ts
@@ -0,0 +1,15 @@
+import { useRef } from 'react';
+
+export const useDebounce = void>(
+ f: F,
+ t = 500
+) => {
+ const timeOutRef = useRef();
+
+ return (...args: A) => {
+ timeOutRef.current && clearTimeout(timeOutRef.current);
+ timeOutRef.current = setTimeout(() => {
+ f(...args);
+ }, t);
+ };
+};
diff --git a/ui/src/integrations/ethereum/ethereum.ts b/ui/src/integrations/ethereum/ethereum.ts
index c61b16f..cb2ae65 100644
--- a/ui/src/integrations/ethereum/ethereum.ts
+++ b/ui/src/integrations/ethereum/ethereum.ts
@@ -1,8 +1,18 @@
import { JsonRpcProvider, Networkish } from '@ethersproject/providers';
import { ethers } from 'ethers';
import * as Contracts from './contracts';
+import { env } from '@/constants';
+import { Alchemy, Network } from 'alchemy-sdk';
+
+const config = {
+ apiKey: env.alchemy.id,
+ network: Network.ETH_MAINNET,
+};
+
+const alchemy = new Alchemy(config);
export const Ethereum: Ethereum.Core = {
+ //TODO remove
defaultNetwork: 'https://rpc-mumbai.maticvigil.com', // TODO: make it environment variable
provider: {
@@ -20,6 +30,23 @@ export const Ethereum: Ethereum.Core = {
return new ethers.Contract(contract.address, contract.abi, provider);
},
+
+ async getEnsName(address) {
+ const ensAddresses = await alchemy.nft.getNftsForOwner(address, {
+ contractAddresses: [env.ens.contractAddress],
+ });
+
+ return ensAddresses.ownedNfts.map((nft) => nft.title);
+ },
+
+ //TODO remove if we're not gonna validate ens on the client side
+ async validateEnsName(name) {
+ const provider = new ethers.providers.JsonRpcProvider(
+ env.ens.validationEnsURL
+ );
+
+ return Boolean(await provider.resolveName(name));
+ },
};
export namespace Ethereum {
@@ -36,5 +63,9 @@ export namespace Ethereum {
contractName: keyof typeof Contracts,
providerName?: Providers
) => ethers.Contract;
+
+ getEnsName: (address: string) => Promise;
+
+ validateEnsName: (name: string) => Promise;
};
}
diff --git a/ui/src/store/features/ens/async-thunk/fetch-ens-names.ts b/ui/src/store/features/ens/async-thunk/fetch-ens-names.ts
new file mode 100644
index 0000000..be87beb
--- /dev/null
+++ b/ui/src/store/features/ens/async-thunk/fetch-ens-names.ts
@@ -0,0 +1,24 @@
+import { Ethereum } from '@/integrations';
+import { RootState } from '@/store';
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { ensActions } from '../ens-slice';
+
+export const fetchEnsNamesThunk = createAsyncThunk(
+ 'ens/fetchEnsNames',
+ async (address, { dispatch, getState }) => {
+ const { state } = (getState() as RootState).ens;
+ if (state === 'loading') return;
+
+ try {
+ dispatch(ensActions.setState('loading'));
+
+ //fetch ens names for received addresses
+ const ensList = await Ethereum.getEnsName(address);
+
+ dispatch(ensActions.setEnsNames(ensList));
+ } catch (error) {
+ console.log(error);
+ dispatch(ensActions.setState('failed'));
+ }
+ }
+);
diff --git a/ui/src/store/features/ens/async-thunk/index.ts b/ui/src/store/features/ens/async-thunk/index.ts
new file mode 100644
index 0000000..e08e73a
--- /dev/null
+++ b/ui/src/store/features/ens/async-thunk/index.ts
@@ -0,0 +1 @@
+export * from './fetch-ens-names';
diff --git a/ui/src/store/features/ens/ens-slice.ts b/ui/src/store/features/ens/ens-slice.ts
new file mode 100644
index 0000000..0a9279d
--- /dev/null
+++ b/ui/src/store/features/ens/ens-slice.ts
@@ -0,0 +1,47 @@
+import { RootState, useAppSelector } from '@/store';
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+import * as asyncThunk from './async-thunk';
+
+export namespace EnsState {
+ export type State = 'idle' | 'loading' | 'success' | 'failed';
+
+ export type EnsNames = string[];
+}
+
+export interface EnsState {
+ state: EnsState.State;
+ ensNames: EnsState.EnsNames;
+}
+
+const initialState: EnsState = {
+ state: 'idle',
+ ensNames: [],
+};
+
+export const ensSlice = createSlice({
+ name: 'ens',
+ initialState,
+ reducers: {
+ setEnsNames: (state, action: PayloadAction) => {
+ state.ensNames = action.payload;
+ state.state = 'success';
+ },
+ setState: (
+ state,
+ action: PayloadAction>
+ ) => {
+ state.state = action.payload;
+ },
+ },
+});
+
+export const ensActions = {
+ ...ensSlice.actions,
+ ...asyncThunk,
+};
+
+const selectEnsState = (state: RootState): EnsState => state.ens;
+
+export const useEnsStore = (): EnsState => useAppSelector(selectEnsState);
+
+export default ensSlice.reducer;
diff --git a/ui/src/store/features/ens/index.ts b/ui/src/store/features/ens/index.ts
new file mode 100644
index 0000000..c58c438
--- /dev/null
+++ b/ui/src/store/features/ens/index.ts
@@ -0,0 +1 @@
+export * from './ens-slice';
diff --git a/ui/src/store/features/github/async-thunk/fetch-repositories.ts b/ui/src/store/features/github/async-thunk/fetch-repositories.ts
index 152b109..f153e36 100644
--- a/ui/src/store/features/github/async-thunk/fetch-repositories.ts
+++ b/ui/src/store/features/github/async-thunk/fetch-repositories.ts
@@ -16,8 +16,6 @@ export const fetchRepositoriesThunk = createAsyncThunk(
const repositories = await githubClient.fetchRepos(url);
- console.log(repositories);
-
dispatch(
githubActions.setRepositories(
repositories.map((repo: any) => ({
diff --git a/ui/src/store/features/index.ts b/ui/src/store/features/index.ts
index 8e3e83e..a587625 100644
--- a/ui/src/store/features/index.ts
+++ b/ui/src/store/features/index.ts
@@ -1 +1,2 @@
export * from './github';
+export * from './ens';
diff --git a/ui/src/store/store.ts b/ui/src/store/store.ts
index 0a9377f..f86bae7 100644
--- a/ui/src/store/store.ts
+++ b/ui/src/store/store.ts
@@ -1,9 +1,11 @@
import { configureStore } from '@reduxjs/toolkit';
import githubReducer from './features/github/github-slice';
+import ensReducer from './features/ens/ens-slice';
export const store = configureStore({
reducer: {
github: githubReducer,
+ ens: ensReducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
diff --git a/ui/src/views/components-test/components-test.tsx b/ui/src/views/components-test/components-test.tsx
new file mode 100644
index 0000000..a3871e1
--- /dev/null
+++ b/ui/src/views/components-test/components-test.tsx
@@ -0,0 +1,50 @@
+import { Combobox, ComboboxItem, Flex } from '@/components';
+import { useState } from 'react';
+
+const itemsCombobox = [
+ { label: 'Item 1', value: 'item-1' },
+ { label: 'Item 2', value: 'item-2' },
+ { label: 'Item 3', value: 'item-3' },
+];
+
+export const ComponentsTest = () => {
+ const [selectedValue, setSelectedValue] = useState({} as ComboboxItem);
+ const [selectedValueAutocomplete, setSelectedValueAutocomplete] = useState(
+ {} as ComboboxItem
+ );
+
+ const handleComboboxChange = (item: ComboboxItem) => {
+ setSelectedValue(item);
+ };
+
+ const handleComboboxChangeAutocomplete = (item: ComboboxItem) => {
+ setSelectedValueAutocomplete(item);
+ };
+
+ return (
+
+ Components Test
+
+
+
+
+
+ );
+};
diff --git a/ui/src/views/components-test/index.ts b/ui/src/views/components-test/index.ts
new file mode 100644
index 0000000..689ba78
--- /dev/null
+++ b/ui/src/views/components-test/index.ts
@@ -0,0 +1 @@
+export * from './components-test';
diff --git a/ui/src/views/index.ts b/ui/src/views/index.ts
index 75899f1..6319a92 100644
--- a/ui/src/views/index.ts
+++ b/ui/src/views/index.ts
@@ -1,3 +1,4 @@
export * from './home';
export * from './mint';
export * from './svg-test';
+export * from './components-test';
diff --git a/ui/src/views/mint/form-step/form.validations.ts b/ui/src/views/mint/form-step/form.validations.ts
new file mode 100644
index 0000000..9241fb7
--- /dev/null
+++ b/ui/src/views/mint/form-step/form.validations.ts
@@ -0,0 +1,12 @@
+import { Ethereum } from '@/integrations';
+
+//TODO remove if we're not gonna validate ens on the client side
+export const validateEnsField = async (
+ ensName: string,
+ setError: (message: string) => void
+) => {
+ const isValid = await Ethereum.validateEnsName(ensName);
+ if (!isValid) setError('Invalid ENS name');
+ else setError('');
+ return isValid;
+};
diff --git a/ui/src/views/mint/github-step/steps/github-connect/github-connect-step.tsx b/ui/src/views/mint/github-step/steps/github-connect/github-connect-step.tsx
index 9ccc425..c9c8ce5 100644
--- a/ui/src/views/mint/github-step/steps/github-connect/github-connect-step.tsx
+++ b/ui/src/views/mint/github-step/steps/github-connect/github-connect-step.tsx
@@ -1,30 +1,25 @@
-import { Card, Grid, Icon, IconButton } from '@/components';
+import { Card, Grid, Stepper } from '@/components';
+import { MintCardHeader } from '@/views/mint/mint-card';
import { GithubButton } from './github-button';
-export const GithubConnect: React.FC = () => (
-
- }
- />
- }
- />
-
-
-
-
-
- After connecting your GitHub, your repositories will show here.
-
-
-
-
-
-);
+export const GithubConnect: React.FC = () => {
+ const { prevStep } = Stepper.useContext();
+
+ return (
+
+
+
+
+
+
+
+ After connecting your GitHub, your repositories will show here.
+
+
+
+
+
+ );
+};
diff --git a/ui/src/views/mint/github-step/steps/github-repository-selection/github-repository-selection.tsx b/ui/src/views/mint/github-step/steps/github-repository-selection/github-repository-selection.tsx
index ce79f9d..7b906bd 100644
--- a/ui/src/views/mint/github-step/steps/github-repository-selection/github-repository-selection.tsx
+++ b/ui/src/views/mint/github-step/steps/github-repository-selection/github-repository-selection.tsx
@@ -1,9 +1,10 @@
import { Card, ComboboxItem, Flex, Grid, Icon, Spinner } from '@/components';
import { Input } from '@/components/core/input';
+import { useDebounce } from '@/hooks/use-debounce';
import { useGithubStore } from '@/store';
import { MintCardHeader } from '@/views/mint/mint-card';
import { Mint } from '@/views/mint/mint.context';
-import React, { forwardRef, useRef, useState } from 'react';
+import React, { forwardRef, useState } from 'react';
import { RepositoriesList } from './repositories-list';
import { UserOrgsCombobox } from './users-orgs-combobox';
@@ -46,14 +47,15 @@ export const GithubRepositoryConnection: React.FC = () => {
const { setGithubStep, setSelectedUserOrg } = Mint.useContext();
- const timeOutRef = useRef();
+ const setSearchValueDebounced = useDebounce(
+ (event: React.ChangeEvent) =>
+ setSearchValue(event.target.value),
+ 500
+ );
const handleSearchChange = (event: React.ChangeEvent) => {
event.stopPropagation();
- timeOutRef.current && clearTimeout(timeOutRef.current);
- timeOutRef.current = setTimeout(() => {
- setSearchValue(event.target.value);
- }, 500);
+ setSearchValueDebounced(event);
};
const handlePrevStepClick = () => {
@@ -73,7 +75,7 @@ export const GithubRepositoryConnection: React.FC = () => {
diff --git a/ui/src/views/mint/github-step/steps/github-repository-selection/users-orgs-combobox.tsx b/ui/src/views/mint/github-step/steps/github-repository-selection/users-orgs-combobox.tsx
index c5fb89b..8cd591d 100644
--- a/ui/src/views/mint/github-step/steps/github-repository-selection/users-orgs-combobox.tsx
+++ b/ui/src/views/mint/github-step/steps/github-repository-selection/users-orgs-combobox.tsx
@@ -43,6 +43,7 @@ export const UserOrgsCombobox = () => {
)}
selectedValue={selectedUserOrg}
onChange={handleUserOrgChange}
+ leftIcon="github"
/>
);
};
diff --git a/ui/src/views/mint/mint-stepper.tsx b/ui/src/views/mint/mint-stepper.tsx
index 1196781..454e0dc 100644
--- a/ui/src/views/mint/mint-stepper.tsx
+++ b/ui/src/views/mint/mint-stepper.tsx
@@ -10,14 +10,14 @@ export const MintStepper = () => {
-
-
+
+
-
-
+
+
diff --git a/ui/src/views/mint/mint.context.tsx b/ui/src/views/mint/mint.context.tsx
index fc2894e..07c57b8 100644
--- a/ui/src/views/mint/mint.context.tsx
+++ b/ui/src/views/mint/mint.context.tsx
@@ -15,9 +15,10 @@ export type MintContext = {
appDescription: string;
appLogo: string;
logoColor: string;
- ens: DropdownItem;
+ ens: ComboboxItem;
domain: string;
verifyNFA: boolean;
+ ensError: string;
setGithubStep: (step: number) => void;
setNfaStep: (step: number) => void;
setSelectedUserOrg: (userOrg: ComboboxItem) => void;
@@ -28,9 +29,10 @@ export type MintContext = {
setAppDescription: (description: string) => void;
setAppLogo: (logo: string) => void;
setLogoColor: (color: string) => void;
- setEns: (ens: DropdownItem) => void;
+ setEns: (ens: ComboboxItem) => void;
setDomain: (domain: string) => void;
setVerifyNFA: (verify: boolean) => void;
+ setEnsError: (error: string) => void;
};
const [MintProvider, useContext] = createContext({
@@ -62,10 +64,13 @@ export abstract class Mint {
const [appDescription, setAppDescription] = useState('');
const [appLogo, setAppLogo] = useState('');
const [logoColor, setLogoColor] = useState('');
- const [ens, setEns] = useState({} as DropdownItem);
+ const [ens, setEns] = useState({} as ComboboxItem);
const [domain, setDomain] = useState('');
const [verifyNFA, setVerifyNFA] = useState(true);
+ //Field validations
+ const [ensError, setEnsError] = useState('');
+
const setGithubStep = (step: number): void => {
if (step > 0 && step <= 3) {
setGithubStepContext(step);
@@ -88,6 +93,7 @@ export abstract class Mint {
ens,
domain,
verifyNFA,
+ ensError,
setSelectedUserOrg,
setGithubStep,
setNfaStep,
@@ -101,6 +107,7 @@ export abstract class Mint {
setEns,
setDomain,
setVerifyNFA,
+ setEnsError,
}}
>
{
- const { ens, setEns } = Mint.useContext();
+ const { ens, ensError, setEns } = Mint.useContext();
+ const { state, ensNames } = useEnsStore();
+ const dispatch = useAppDispatch();
+ const { address } = useAccount();
- const handleEnsChange = (item: DropdownItem) => {
+ if (state === 'idle' && address) {
+ dispatch(ensActions.fetchEnsNamesThunk(address));
+ }
+
+ const handleEnsChange = (item: ComboboxItem) => {
setEns(item);
};
return (
ENS
- ({
+ label: ens,
+ value: ens,
+ }))}
selectedValue={ens}
onChange={handleEnsChange}
+ withAutocomplete
/>
+ {ensError && {ensError}}
);
};
diff --git a/ui/src/views/mint/wallet-step/wallet-step.tsx b/ui/src/views/mint/wallet-step/wallet-step.tsx
index 5cf7cbd..c89df1b 100644
--- a/ui/src/views/mint/wallet-step/wallet-step.tsx
+++ b/ui/src/views/mint/wallet-step/wallet-step.tsx
@@ -1,12 +1,20 @@
-import { Button, Card, Grid, Icon, Stepper } from '@/components';
-import { MintCardHeader } from '../mint-card';
+import { Card, Grid, Icon, IconButton } from '@/components';
import { ConnectWalletButton } from './connect-wallet-button';
export const WalletStep = () => {
- const { prevStep } = Stepper.useContext();
return (
-
+ }
+ />
+ }
+ />
diff --git a/ui/tailwind.config.js b/ui/tailwind.config.js
index 0e6b121..bb7ae2b 100644
--- a/ui/tailwind.config.js
+++ b/ui/tailwind.config.js
@@ -18,6 +18,9 @@ module.exports = {
borderRadius: {
xhl: '1.25rem',
},
+ maxWidth: {
+ 70: '70%',
+ },
space: {
'1h': '0.375rem',
},
diff --git a/ui/yarn.lock b/ui/yarn.lock
index 4db5e04..f0623a1 100644
--- a/ui/yarn.lock
+++ b/ui/yarn.lock
@@ -1415,7 +1415,7 @@
dependencies:
"@ethersproject/bignumber" "^5.7.0"
-"@ethersproject/contracts@5.7.0":
+"@ethersproject/contracts@5.7.0", "@ethersproject/contracts@^5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e"
integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==
@@ -1518,7 +1518,7 @@
dependencies:
"@ethersproject/logger" "^5.7.0"
-"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.2":
+"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.0", "@ethersproject/providers@^5.7.2":
version "5.7.2"
resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb"
integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==
@@ -1617,7 +1617,7 @@
"@ethersproject/rlp" "^5.7.0"
"@ethersproject/signing-key" "^5.7.0"
-"@ethersproject/units@5.7.0":
+"@ethersproject/units@5.7.0", "@ethersproject/units@^5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1"
integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==
@@ -1626,7 +1626,7 @@
"@ethersproject/constants" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
-"@ethersproject/wallet@5.7.0":
+"@ethersproject/wallet@5.7.0", "@ethersproject/wallet@^5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d"
integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==
@@ -5373,6 +5373,26 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
+alchemy-sdk@^2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/alchemy-sdk/-/alchemy-sdk-2.5.0.tgz#20813b02eded16e9cbc56c5fc8259684dc324eb9"
+ integrity sha512-pgwyPiAmUp4uaBkkpdnlHxjB7yjeO88VhIIFo5aCiuPAxgpB5nKRqBQw2XXqiZEUF4xU1ybZ2s1ESQ6k/hc2MQ==
+ dependencies:
+ "@ethersproject/abi" "^5.7.0"
+ "@ethersproject/abstract-provider" "^5.7.0"
+ "@ethersproject/bignumber" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/contracts" "^5.7.0"
+ "@ethersproject/hash" "^5.7.0"
+ "@ethersproject/networks" "^5.7.0"
+ "@ethersproject/providers" "^5.7.0"
+ "@ethersproject/units" "^5.7.0"
+ "@ethersproject/wallet" "^5.7.0"
+ "@ethersproject/web" "^5.7.0"
+ axios "^0.26.1"
+ sturdy-websocket "^0.2.1"
+ websocket "^1.0.34"
+
ansi-align@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59"
@@ -5756,6 +5776,13 @@ axios@^0.21.0:
dependencies:
follow-redirects "^1.14.0"
+axios@^0.26.1:
+ version "0.26.1"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9"
+ integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==
+ dependencies:
+ follow-redirects "^1.14.8"
+
babel-loader@^8.0.0, babel-loader@^8.3.0:
version "8.3.0"
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.3.0.tgz#124936e841ba4fe8176786d6ff28add1f134d6a8"
@@ -7086,6 +7113,14 @@ cyclist@^1.0.1:
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
integrity sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==
+d@1, d@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
+ integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==
+ dependencies:
+ es5-ext "^0.10.50"
+ type "^1.0.1"
+
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@@ -7716,11 +7751,29 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
+es5-ext@^0.10.35, es5-ext@^0.10.50:
+ version "0.10.62"
+ resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5"
+ integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==
+ dependencies:
+ es6-iterator "^2.0.3"
+ es6-symbol "^3.1.3"
+ next-tick "^1.1.0"
+
es5-shim@^4.5.13:
version "4.6.7"
resolved "https://registry.yarnpkg.com/es5-shim/-/es5-shim-4.6.7.tgz#bc67ae0fc3dd520636e0a1601cc73b450ad3e955"
integrity sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==
+es6-iterator@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
+ integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==
+ dependencies:
+ d "1"
+ es5-ext "^0.10.35"
+ es6-symbol "^3.1.1"
+
es6-promise@^4.0.3:
version "4.2.8"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
@@ -7738,6 +7791,14 @@ es6-shim@^0.35.5:
resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.7.tgz#db00f1cbb7d4de70b50dcafa45b157e9ba28f5d2"
integrity sha512-baZkUfTDSx7X69+NA8imbvGrsPfqH0MX7ADdIDjqwsI8lkTgLIiD2QWrUCSGsUQ0YMnSCA/4pNgSyXdnLHWf3A==
+es6-symbol@^3.1.1, es6-symbol@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
+ integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
+ dependencies:
+ d "^1.0.1"
+ ext "^1.1.2"
+
esbuild-android-64@0.15.18:
version "0.15.18"
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz#20a7ae1416c8eaade917fb2453c1259302c637a5"
@@ -8347,6 +8408,13 @@ express@^4.17.1:
utils-merge "1.0.1"
vary "~1.1.2"
+ext@^1.1.2:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f"
+ integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==
+ dependencies:
+ type "^2.7.2"
+
extend-shallow@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
@@ -8667,7 +8735,7 @@ focus-lock@^0.8.0:
dependencies:
tslib "^1.9.3"
-follow-redirects@^1.14.0:
+follow-redirects@^1.14.0, follow-redirects@^1.14.8:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
@@ -11288,6 +11356,11 @@ nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0:
resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz#26c8a3cee6cc05fbcf1e333cd2fc3e003326c0b5"
integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==
+next-tick@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
+ integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
+
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
@@ -13951,6 +14024,11 @@ strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+sturdy-websocket@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/sturdy-websocket/-/sturdy-websocket-0.2.1.tgz#20a58fd53372ef96eaa08f3c61c91a10b07c7c05"
+ integrity sha512-NnzSOEKyv4I83qbuKw9ROtJrrT6Z/Xt7I0HiP/e6H6GnpeTDvzwGIGeJ8slai+VwODSHQDooW2CAilJwT9SpRg==
+
style-loader@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e"
@@ -14466,6 +14544,16 @@ type-is@~1.6.18:
media-typer "0.3.0"
mime-types "~2.1.24"
+type@^1.0.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
+ integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==
+
+type@^2.7.2:
+ version "2.7.2"
+ resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0"
+ integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==
+
typed-array-length@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb"
@@ -15111,6 +15199,18 @@ websocket-extensions@>=0.1.1:
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42"
integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==
+websocket@^1.0.34:
+ version "1.0.34"
+ resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111"
+ integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==
+ dependencies:
+ bufferutil "^4.0.1"
+ debug "^2.2.0"
+ es5-ext "^0.10.50"
+ typedarray-to-buffer "^3.1.5"
+ utf-8-validate "^5.0.2"
+ yaeti "^0.0.6"
+
whatwg-url@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
@@ -15303,6 +15403,11 @@ y18n@^5.0.5:
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+yaeti@^0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577"
+ integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==
+
yallist@^3.0.2:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"