diff --git a/components/Banner.tsx b/components/Banner.tsx index b03c5d87..e0206311 100644 --- a/components/Banner.tsx +++ b/components/Banner.tsx @@ -1,14 +1,13 @@ import { Cross1Icon } from "@radix-ui/react-icons"; -import { useContext } from "react"; -import { AppDispatchContext, AppStateContext } from "../context/state"; +import { useAppDispatch, useAppState } from "../context/state"; type props = { children: React.ReactNode; }; const Banner = ({ children }: props) => { - const state = useContext(AppStateContext)!; - const dispatch = useContext(AppDispatchContext)!; + const state = useAppState(); + const dispatch = useAppDispatch(); return state.hasBanner ? (
diff --git a/components/ContractExecution.tsx b/components/ContractExecution.tsx index d0364d7e..ff66f090 100644 --- a/components/ContractExecution.tsx +++ b/components/ContractExecution.tsx @@ -7,8 +7,9 @@ import { Formik, useFormikContext, } from "formik"; -import React, { useContext, useEffect } from "react"; -import { AppStateContext } from "../context/state"; +import React, { useEffect } from "react"; +import { useAppState } from "../context/state"; +import { useTezosToolkit } from "../context/tezos-toolkit"; import { parseContract, genLambda, @@ -485,10 +486,11 @@ function ExecuteForm( onShapeChange: (v: object) => void; }> ) { - const state = useContext(AppStateContext)!; + const state = useAppState(); + + const { tezos } = useTezosToolkit(); const address = props.address; - const conn = state.connection; const setLoading = props.setLoading; const loading = props.loading; @@ -497,7 +499,7 @@ function ExecuteForm( (async () => { try { setLoading(true); - const c = await conn.contract.at(address); + const c = await tezos.contract.at(address); const initTokenTable: Record = {}; const token: token = parseContract(c, initTokenTable); diff --git a/components/ExecuteContractForm.tsx b/components/ExecuteContractForm.tsx new file mode 100644 index 00000000..e0b660b1 --- /dev/null +++ b/components/ExecuteContractForm.tsx @@ -0,0 +1,129 @@ +import { Field, useFormikContext } from "formik"; +import React, { useCallback, useEffect, useRef, useState } from "react"; +import { useWallet } from "../context/wallet"; +import { tezToMutez } from "../utils/tez"; +import ExecuteForm from "./ContractExecution"; +import ContractLoader from "./contractLoader"; +import renderError from "./formUtils"; +import { state, Basic } from "./transferForm"; + +export function ExecuteContractForm( + props: React.PropsWithoutRef<{ + setField: (lambda: string, metadata: string) => void; + getFieldProps: (name: string) => { value: string }; + id: number; + defaultState?: state; + onReset: () => void; + onChange: (state: state) => void; + }> +) { + const { submitCount, setFieldValue } = useFormikContext(); + const submitCountRef = useRef(submitCount); + const { userAddress } = useWallet(); + + const [state, setState] = useState( + () => props.defaultState ?? { address: "", amount: 0, shape: {} } + ); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); + + const setLoader = useCallback((x: boolean) => setLoading(x), []); + + useEffect(() => { + props.onChange(state); + }, [state, props.onChange]); + + if (loading) { + return ( +
+ +
+ ); + } + + return ( +
+

+ + #{(props.id + 1).toString().padStart(2, "0")} + + Execute Contract +

+ setState({ ...x, shape: {} })} + onAmountChange={amount => { + setState({ ...state, amount: tezToMutez(Number(amount)) }); + setFieldValue(`transfers.${props.id}.amount`, amount); + }} + onAddressChange={address => { + setState({ ...state, address }); + }} + withContinue={!userAddress} + address={userAddress} + defaultValues={{ + amount: undefined, + address: undefined, + }} + /> + {!!userAddress && ( + { + setState(v => ({ + ...v, + shape: { ...v.shape, init: shape }, + })); + }} + setState={shape => { + setState(v => ({ ...v, shape })); + }} + reset={() => setState({ address: "", amount: 0, shape: {} })} + address={userAddress} + amount={state.amount} + setField={(lambda: string, metadata: string) => { + props.setField(lambda, metadata); + }} + onReset={() => { + setState({ address: "", amount: 0, shape: {} }); + props.onReset(); + }} + /> + )} + { + // This is a tricky way to detect when the submition happened + // We want this message to show only on submit, not on every change + if (!!v) { + submitCountRef.current = submitCount; + setError(""); + return; + } + + if (submitCountRef.current === submitCount - 1) { + setError("Please fill contract"); + submitCountRef.current += 1; + } + + // Returning a value to prevent submition + return true; + }} + /> + { + if (!!v) return; + + // Returning a value to prevent submition + return true; + }} + /> + {!!error && renderError(error)} +
+ ); +} diff --git a/components/FA1_2.tsx b/components/FA1_2.tsx index 5cc25c66..db73da2d 100644 --- a/components/FA1_2.tsx +++ b/components/FA1_2.tsx @@ -1,7 +1,7 @@ import { Field, useFormikContext } from "formik"; -import { useCallback, useContext, useEffect, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { TZKT_API_URL, THUMBNAIL_URL } from "../context/config"; -import { AppStateContext } from "../context/state"; +import { useAppState } from "../context/state"; import { debounce, promiseWithTimeout } from "../utils/timeout"; import { proposals } from "../versioned/interface"; import ErrorMessage from "./ErrorMessage"; @@ -75,7 +75,7 @@ const tokenToOption = (fa1_2Token: fa1_2Token) => { }; const FA1_2 = ({ index, remove, children }: props) => { - const state = useContext(AppStateContext)!; + const state = useAppState(); const { setFieldValue, getFieldProps } = useFormikContext(); const [isFetching, setIsFetching] = useState(true); diff --git a/components/FA2Transfer.tsx b/components/FA2Transfer.tsx index 1642d24e..4fcc1bd7 100644 --- a/components/FA2Transfer.tsx +++ b/components/FA2Transfer.tsx @@ -2,17 +2,10 @@ import { PlusIcon } from "@radix-ui/react-icons"; import { validateAddress, ValidationResult } from "@taquito/utils"; import BigNumber from "bignumber.js"; import { Field, FieldProps, useFormikContext } from "formik"; -import { - useCallback, - useContext, - useEffect, - useMemo, - useRef, - useState, -} from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { v4 as uuidV4 } from "uuid"; import { TZKT_API_URL, THUMBNAIL_URL } from "../context/config"; -import { AppStateContext } from "../context/state"; +import { useAppState } from "../context/state"; import { debounce } from "../utils/timeout"; import { proposals } from "../versioned/interface"; import ErrorMessage from "./ErrorMessage"; @@ -90,7 +83,7 @@ const FA2Transfer = ({ toExclude, autoSetField = true, }: fa2TransferProps) => { - const state = useContext(AppStateContext)!; + const state = useAppState(); const { getFieldProps, setFieldValue, errors } = useFormikContext(); diff --git a/components/Layout.tsx b/components/Layout.tsx new file mode 100644 index 00000000..9b42ab3b --- /dev/null +++ b/components/Layout.tsx @@ -0,0 +1,235 @@ +import { LocalStorage, NetworkType } from "@airgap/beacon-sdk"; +import { ArrowRightIcon } from "@radix-ui/react-icons"; +import { validateAddress, ValidationResult } from "@taquito/utils"; +import { AppProps } from "next/app"; +import { usePathname } from "next/navigation"; +import router, { useRouter } from "next/router"; +import { useEffect, useState } from "react"; +import P2PClient from "../context/P2PClient"; +import { PREFERED_NETWORK } from "../context/config"; +import { init, useAppDispatch, useAppState } from "../context/state"; +import { useTezosToolkit } from "../context/tezos-toolkit"; +import { useWallet } from "../context/wallet"; +import { contractStorage } from "../types/Proposal0_3_1"; +import { fetchContract } from "../utils/fetchContract"; +import Banner from "./Banner"; +import LoginModal from "./LoginModal"; +import PoeModal from "./PoeModal"; +import Sidebar from "./Sidebar"; +import Spinner from "./Spinner"; +import Footer from "./footer"; +import NavBar from "./navbar"; + +export default function Layout({ + Component, + pageProps, +}: Pick) { + const state = useAppState(); + const dispatch = useAppDispatch(); + const { tezos } = useTezosToolkit(); + const { wallet } = useWallet(); + + const [data, setData] = useState(); + const [hasSidebar, setHasSidebar] = useState(false); + const [isFetching, setIsFetching] = useState(true); + const router = useRouter(); + const path = usePathname(); + const isSidebarHidden = + Object.values(state.contracts).length === 0 && + (path === "/" || + path === "/new-wallet" || + path === "/import-wallet" || + path === "/address-book"); + + useEffect(() => { + if (!path) return; + + const queryParams = new URLSearchParams(window.location.search); + + const isPairing = queryParams.has("type") && queryParams.has("data"); + + if (isPairing) { + setData(queryParams.get("data")!); + } + + const contracts = Object.keys(state.contracts); + + if ((path === "/" || path === "") && contracts.length > 0) { + const contract = contracts[0]; + + router.replace(`/${contract}/dashboard`); + return; + } else if (path === "/" || path === "") { + // Get rid of query in case it comes from beacon + router.replace("/"); + } + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [state.currentContract, path, state.contracts]); + + useEffect(() => { + (async () => { + if ( + router.pathname.includes("[walletAddress]") && + !router.query.walletAddress + ) + return; + + if ( + !router.query.walletAddress || + Array.isArray(router.query.walletAddress) || + (router.query.walletAddress === state.currentContract && + !!state.currentStorage) + ) { + setIsFetching(false); + return; + } + + if (!!state.contracts[router.query.walletAddress]) { + dispatch({ + type: "setCurrentContract", + payload: router.query.walletAddress, + }); + setIsFetching(false); + } + + if ( + validateAddress(router.query.walletAddress) !== ValidationResult.VALID + ) { + setIsFetching(false); + router.replace( + `/invalid-contract?address=${router.query.walletAddress}` + ); + return; + } + + if (state.currentStorage?.address === router.query.walletAddress) { + setIsFetching(false); + return; + } + + try { + const storage = await fetchContract(tezos, router.query.walletAddress); + + if (!storage) { + setIsFetching(false); + router.replace( + `/invalid-contract?address=${router.query.walletAddress}` + ); + return; + } + + storage.address = router.query.walletAddress; + + dispatch({ + type: "setCurrentStorage", + payload: storage as contractStorage & { address: string }, + }); + + dispatch({ + type: "setCurrentContract", + payload: router.query.walletAddress, + }); + + setIsFetching(false); + } catch (e) { + setIsFetching(false); + + router.replace( + `/invalid-contract?address=${router.query.walletAddress}` + ); + } + })(); + }, [ + router.query.walletAddress, + state.currentContract, + dispatch, + router, + state.currentStorage, + tezos, + state.contracts, + ]); + useEffect(() => { + (async () => { + const p2pClient = new P2PClient({ + name: "TzSafe", + storage: new LocalStorage("P2P"), + }); + + await p2pClient.init(); + await p2pClient.connect(p2pClient.handleMessages); + + // Connect stored peers + Object.entries(state.connectedDapps).forEach(async ([address, dapps]) => { + Object.values(dapps).forEach(data => { + p2pClient + .addPeer(data) + .catch(_ => console.log("Failed to connect to peer", data)); + }); + }); + + dispatch!({ type: "p2pConnect", payload: p2pClient }); + })(); + }, [wallet]); + + useEffect(() => { + setHasSidebar(false); + }, [path]); + + return ( +
+ + ); +} diff --git a/components/LoginModal.tsx b/components/LoginModal.tsx index bef94a31..84878c04 100644 --- a/components/LoginModal.tsx +++ b/components/LoginModal.tsx @@ -1,8 +1,8 @@ -import { useContext, useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { Event } from "../context/P2PClient"; -import { AppDispatchContext, AppStateContext } from "../context/state"; +import { useAppDispatch, useAppState } from "../context/state"; +import { useWallet } from "../context/wallet"; import { decodeData } from "../pages/[walletAddress]/beacon"; -import { connectWallet } from "../utils/connectWallet"; import { signers } from "../versioned/apis"; import { p2pData } from "../versioned/interface"; import { hasTzip27Support } from "../versioned/util"; @@ -19,20 +19,21 @@ enum State { } const LoginModal = ({ data, onEnd }: { data: string; onEnd: () => void }) => { - const state = useContext(AppStateContext)!; - const dispatch = useContext(AppDispatchContext)!; + const state = useAppState(); + const dispatch = useAppDispatch(); const [parsedData, setParsedData] = useState(); const [error, setError] = useState(); + const { userAddress, wallet, connectWallet } = useWallet(); + const options = useMemo(() => { - if (!state.address) return []; + if (!userAddress) return []; return Object.keys(state.contracts).flatMap(address => { if (!hasTzip27Support(state.contracts[address].version)) return []; - if (!signers(state.contracts[address]).includes(state.address!)) - return []; + if (!signers(state.contracts[address]).includes(userAddress!)) return []; return [ { @@ -42,7 +43,7 @@ const LoginModal = ({ data, onEnd }: { data: string; onEnd: () => void }) => { }, ]; }); - }, [state.contracts, state.address]); + }, [state.contracts, userAddress]); const [selectedWallet, setSelectedWallet] = useState< { id: string; value: string; label: string } | undefined @@ -51,7 +52,7 @@ const LoginModal = ({ data, onEnd }: { data: string; onEnd: () => void }) => { const [currentState, setCurrentState] = useState(() => State.LOADING); useEffect(() => { - if (!state.p2pClient || !state.attemptedInitialLogin) return; + if (!state.p2pClient) return; try { const decoded = decodeData(data); @@ -59,7 +60,7 @@ const LoginModal = ({ data, onEnd }: { data: string; onEnd: () => void }) => { setParsedData(decoded); state.p2pClient!.on(Event.PERMISSION_REQUEST, () => { - if (state.attemptedInitialLogin && !state.address) { + if (!userAddress) { setCurrentState(State.LOGIN); } else if ( decoded.name.toLowerCase().includes("tzsafe") || @@ -77,13 +78,13 @@ const LoginModal = ({ data, onEnd }: { data: string; onEnd: () => void }) => { setError((e as Error).message); setCurrentState(State.ERROR); } - }, [data, state.p2pClient, state.attemptedInitialLogin]); + }, [data, state.p2pClient]); useEffect(() => { - if (currentState === State.LOGIN && !!state.address) { + if (currentState === State.LOGIN && !!userAddress) { setCurrentState(State.INITIAL); } - }, [state.address]); + }, [userAddress]); return (
@@ -254,14 +255,10 @@ const LoginModal = ({ data, onEnd }: { data: string; onEnd: () => void }) => { Cancel - {state?.address == null ? ( + {userAddress == null ? (
@@ -109,7 +109,7 @@ const NavBar = (_: React.PropsWithChildren) => { Open user menu
@@ -125,7 +125,7 @@ const NavBar = (_: React.PropsWithChildren) => {
diff --git a/components/transferForm.tsx b/components/transferForm.tsx index ffbf7135..742afd98 100644 --- a/components/transferForm.tsx +++ b/components/transferForm.tsx @@ -25,7 +25,9 @@ import React, { useState, } from "react"; import { MODAL_TIMEOUT, PREFERED_NETWORK } from "../context/config"; -import { AppStateContext, contractStorage } from "../context/state"; +import { contractStorage, useAppState } from "../context/state"; +import { TezosToolkitContext } from "../context/tezos-toolkit"; +import { useWallet } from "../context/wallet"; import { tezToMutez } from "../utils/tez"; import { VersionedApi } from "../versioned/apis"; import { Versioned, proposals, transfer } from "../versioned/interface"; @@ -45,7 +47,7 @@ import TextInputWithCompletion from "./textInputWithComplete"; type Nullable = T | null | undefined; -function Basic({ +export function Basic({ id, setFormState, defaultValues, @@ -69,7 +71,8 @@ function Basic({ { setTouched: setAddressTouched }, ] = useField(`transfers.${id}.walletAddress`); - const state = useContext(AppStateContext)!; + const { tezos } = useContext(TezosToolkitContext); + const [localFormState, setLocalFormState] = useState<{ amount: number | undefined; address: string; @@ -127,7 +130,7 @@ function Basic({ setContractLoading(true); const exists = await (async () => { try { - await state.connection.contract.at(address.trim()); + await tezos.contract.at(address.trim()); return true; } catch (e) { return false; @@ -216,7 +219,7 @@ function Basic({ ); } -type state = { +export type state = { address: string; amount: number; shape: object; @@ -233,6 +236,7 @@ function ExecuteContractForm( ) { const { submitCount, setFieldValue } = useFormikContext(); const submitCountRef = useRef(submitCount); + const { userAddress } = useWallet(); const [state, setState] = useState( () => props.defaultState ?? { address: "", amount: 0, shape: {} } @@ -272,14 +276,14 @@ function ExecuteContractForm( onAddressChange={address => { setState({ ...state, address }); }} - withContinue={!state.address} - address={state.address} + withContinue={!userAddress} + address={userAddress} defaultValues={{ amount: undefined, address: undefined, }} /> - {!!state.address && ( + {!!userAddress && ( ({ ...v, shape })); }} reset={() => setState({ address: "", amount: 0, shape: {} })} - address={state.address} + address={userAddress} amount={state.amount} setField={(lambda: string, metadata: string) => { props.setField(lambda, metadata); @@ -370,8 +374,10 @@ function TransferForm( contract: contractStorage; }> ) { - const state = useContext(AppStateContext)!; + const state = useAppState(); const router = useRouter(); + const { userAddress } = useWallet(); + const { tezos } = useContext(TezosToolkitContext); const portalIdx = useRef(0); const [isMenuOpen, setIsMenuOpen] = useState(true); @@ -381,7 +387,7 @@ function TransferForm( const [formState, setFormState] = useState(() => initialProps); const executeContractStateRef = useRef<{ [k: number]: state }>({}); - if (state?.address == null) { + if (userAddress == null) { return null; } @@ -508,14 +514,14 @@ function TransferForm( setFormState(values); setLoading(true); try { - const cc = await state.connection.wallet.at(props.address); + const cc = await tezos.wallet.at(props.address); const versioned = VersionedApi(props.contract.version, props.address); const proposals: proposals = { transfers: values.transfers }; setTimeoutAndHash( await versioned.submitTxProposals( cc, - state.connection, + tezos, proposals, undefined, undefined, diff --git a/context/aliases.tsx b/context/aliases.tsx index e5756e04..8907edd4 100644 --- a/context/aliases.tsx +++ b/context/aliases.tsx @@ -1,6 +1,7 @@ import React, { useRef } from "react"; import { createContext } from "react"; import { TZKT_API_URL } from "./config"; +import { useAppState } from "./state"; type AliasesContextType = { getAlias(address: string, defaultAlias: string): Promise; @@ -12,13 +13,13 @@ export const AliasesContext = createContext({ export const AliasesProvider = ({ children, - aliasesFromState, }: { children: React.ReactNode; - aliasesFromState: { [address: string]: string }; }) => { const aliases = useRef>>({}); + const aliasesFromState = useAppState().aliases; + const getTzktAlias = async (address: string) => { // address can be empty string... if (address === "") return undefined; diff --git a/context/state.ts b/context/state.tsx similarity index 68% rename from context/state.ts rename to context/state.tsx index c0616a5b..42a20e7e 100644 --- a/context/state.ts +++ b/context/state.tsx @@ -1,32 +1,23 @@ -import { AccountInfo, getSenderId } from "@airgap/beacon-sdk"; -import { BeaconWallet } from "@taquito/beacon-wallet"; -import { PollingSubscribeProvider, TezosToolkit } from "@taquito/taquito"; -import { Tzip12Module } from "@taquito/tzip12"; -import { - Handler, - IpfsHttpHandler, - MetadataProvider, - TezosStorageHandler, - Tzip16Module, -} from "@taquito/tzip16"; +import { getSenderId } from "@airgap/beacon-sdk"; import BigNumber from "bignumber.js"; -import { Context, createContext, Dispatch } from "react"; +import { + Context, + createContext, + Dispatch, + useContext, + useEffect, + useReducer, +} from "react"; import { contractStorage } from "../types/app"; import { Trie } from "../utils/radixTrie"; import { p2pData } from "../versioned/interface"; import P2PClient from "./P2PClient"; -import { IPFS_NODE, RPC_URL } from "./config"; -import { BeaconSigner } from "./signer"; +import { useWallet } from "./wallet"; type tezosState = { - connection: TezosToolkit; - beaconWallet: BeaconWallet | null; p2pClient: P2PClient | null; - address: string | null; - balance: string | null; currentContract: string | null; currentStorage: contractStorage | null; - accountInfo: AccountInfo | null; contracts: { [address: string]: contractStorage }; aliases: { [address: string]: string }; aliasTrie: Trie; @@ -39,7 +30,6 @@ type tezosState = { }; // Increasing this number will trigger a useEffect in the proposal page proposalRefresher: number; - attemptedInitialLogin: boolean; }; type storage = { contracts: { [address: string]: contractStorage }; @@ -47,54 +37,23 @@ type storage = { }; let emptyState = (): tezosState => { - const connection = new TezosToolkit(RPC_URL); - - const customHandler = new Map([ - ["ipfs", new IpfsHttpHandler(IPFS_NODE)], - ["tezos-storage", new TezosStorageHandler()], - ]); - - const customMetadataProvider = new MetadataProvider(customHandler); - connection.addExtension(new Tzip16Module(customMetadataProvider)); - connection.addExtension(new Tzip12Module()); - - connection.setStreamProvider( - connection.getFactory(PollingSubscribeProvider)({ - shouldObservableSubscriptionRetry: true, - pollingIntervalMilliseconds: 500, - }) - ); - return { - beaconWallet: null, p2pClient: null, contracts: {}, aliases: {}, - balance: null, - address: null, currentContract: null, currentStorage: null, - accountInfo: null, - connection, aliasTrie: new Trie(), hasBanner: true, delegatorAddresses: undefined, connectedDapps: {}, proposalRefresher: 0, - attemptedInitialLogin: false, }; }; type action = - | { type: "beaconConnect"; payload: BeaconWallet } | { type: "p2pConnect"; payload: P2PClient } | { type: "init"; payload: tezosState } - | { - type: "login"; - accountInfo: AccountInfo; - address: string; - balance: string; - } | { type: "addContract"; payload: { @@ -116,7 +75,6 @@ type action = payload: string; } | { type: "removeContract"; address: string } - | { type: "logout" } | { type: "loadStorage"; payload: storage } | { type: "writeStorage"; payload: storage } | { type: "setDelegatorAddresses"; payload: string[] } @@ -148,11 +106,14 @@ type action = | { type: "setAttemptedInitialLogin"; payload: boolean; + } + | { + type: "logout"; }; -const saveState = (state: tezosState) => { +const saveState = (state: tezosState, userAddress: string) => { localStorage.setItem( - `app_state:${state.address}`, + `app_state:${userAddress}`, JSON.stringify({ contracts: state.contracts, aliases: state.aliases, @@ -162,28 +123,28 @@ const saveState = (state: tezosState) => { ); }; -function reducer(state: tezosState, action: action): tezosState { +const loadState = (userAddress: string) => { + const rawStorage = localStorage.getItem(`app_state:${userAddress}`); + if (!rawStorage) return {}; + return JSON.parse(rawStorage); +}; + +function reducer( + state: tezosState, + action: action, + { userAddress }: { userAddress: string } +): tezosState { switch (action.type) { - case "beaconConnect": { - state.connection.setProvider({ - rpc: RPC_URL, - wallet: action.payload, - }); - state.connection.setSignerProvider(new BeaconSigner(action.payload)); - return { ...state, beaconWallet: action.payload }; - } case "p2pConnect": { return { ...state, p2pClient: action.payload }; } case "addDapp": { - if (!state.address) return state; - state.connectedDapps[action.payload.address] ??= {}; state.connectedDapps[action.payload.address][action.payload.data.appUrl] = action.payload.data; - saveState(state); + saveState(state, userAddress); return state; } @@ -198,7 +159,7 @@ function reducer(state: tezosState, action: action): tezosState { delete newState.connectedDapps[state.currentContract][action.payload]; - saveState(newState); + saveState(newState, userAddress); return newState; } @@ -219,7 +180,7 @@ function reducer(state: tezosState, action: action): tezosState { aliasTrie: Trie.fromAliases(Object.entries(aliases)), }; - saveState(newState); + saveState(newState, userAddress); return newState; } @@ -239,7 +200,7 @@ function reducer(state: tezosState, action: action): tezosState { aliasTrie: Trie.fromAliases(Object.entries(aliases)), }; - saveState(newState); + saveState(newState, userAddress); return newState; } @@ -253,7 +214,8 @@ function reducer(state: tezosState, action: action): tezosState { contracts, }; - if (state.contracts[action.payload.address]) saveState(newState); + if (state.contracts[action.payload.address]) + saveState(newState, userAddress); return newState; } @@ -263,7 +225,7 @@ function reducer(state: tezosState, action: action): tezosState { currentContract: action.payload, }; - saveState(newState); + saveState(newState, userAddress); return newState; case "setCurrentStorage": @@ -287,42 +249,13 @@ function reducer(state: tezosState, action: action): tezosState { return { ...action.payload, contracts, - attemptedInitialLogin: state.attemptedInitialLogin, currentContract: state.currentContract ?? action.payload.currentContract, currentStorage: state.currentStorage, aliasTrie: Trie.fromAliases(Object.entries(action.payload.aliases)), }; } - case "login": { - const rawStorage = window!.localStorage.getItem( - `app_state:${action.address}` - )!; - const storage: storage = JSON.parse(rawStorage); - return { - ...state, - ...storage, - balance: action.balance, - accountInfo: action.accountInfo, - address: action.address, - attemptedInitialLogin: true, - }; - } - case "logout": { - let { connection } = emptyState(); - - const newState: tezosState = { - ...state, - beaconWallet: null, - balance: null, - accountInfo: null, - address: null, - connection: connection, - p2pClient: null, - }; - return newState; - } case "removeContract": { const { [action.address]: _, ...contracts } = state.contracts; const { [action.address]: __, ...aliases } = state.aliases; @@ -352,7 +285,7 @@ function reducer(state: tezosState, action: action): tezosState { connectedDapps, }; - saveState(newState); + saveState(newState, userAddress); return newState; } @@ -365,8 +298,13 @@ function reducer(state: tezosState, action: action): tezosState { return { ...state, delegatorAddresses: action.payload }; case "refreshProposals": return { ...state, proposalRefresher: state.proposalRefresher + 1 }; - case "setAttemptedInitialLogin": - return { ...state, attemptedInitialLogin: action.payload }; + case "loadStorage": { + return { ...state, ...action.payload }; + } + case "logout": { + return { ...init() }; + } + default: { throw `notImplemented: ${action.type}`; } @@ -376,10 +314,38 @@ function init(): tezosState { return emptyState(); } -let AppStateContext: Context = - createContext(null); -let AppDispatchContext: Context | null> = +const AppStateContext = createContext<{ + state: tezosState; + dispatch: React.Dispatch; +}>({ state: emptyState(), dispatch: () => {} }); +const AppDispatchContext: Context | null> = createContext | null>(null); + +const AppStateProvider = ({ children }: { children: React.ReactNode }) => { + const { userAddress } = useWallet(); + + useEffect(() => { + // If we are in anonymous mode don't load the previous storage + if (userAddress) + dispatch({ type: "loadStorage", payload: loadState(userAddress) }); + }, [userAddress]); + + const [state, dispatch]: [tezosState, React.Dispatch] = useReducer( + (state: tezosState, action: action) => + reducer(state, action, { userAddress: userAddress || "" }), + emptyState() + ); + + return ( + + {children} + + ); +}; + +const useAppState = () => useContext(AppStateContext).state; +const useAppDispatch = () => useContext(AppStateContext).dispatch; + export { type tezosState, type action, @@ -389,4 +355,7 @@ export { AppDispatchContext, emptyState, reducer, + AppStateProvider, + useAppState, + useAppDispatch, }; diff --git a/context/tezos-toolkit.tsx b/context/tezos-toolkit.tsx new file mode 100644 index 00000000..47f98d61 --- /dev/null +++ b/context/tezos-toolkit.tsx @@ -0,0 +1,52 @@ +import { PollingSubscribeProvider, TezosToolkit } from "@taquito/taquito"; +import { Tzip12Module } from "@taquito/tzip12"; +import { + Handler, + IpfsHttpHandler, + MetadataProvider, + TezosStorageHandler, + Tzip16Module, +} from "@taquito/tzip16"; +import React, { createContext, useEffect, useState } from "react"; +import { IPFS_NODE, RPC_URL } from "./config"; + +type TzTkState = { + tezos: TezosToolkit; +}; + +const createTezosConnection = () => { + const connection = new TezosToolkit(RPC_URL); + const customHandler = new Map([ + ["ipfs", new IpfsHttpHandler(IPFS_NODE)], + ["tezos-storage", new TezosStorageHandler()], + ]); + const customMetadataProvider = new MetadataProvider(customHandler); + connection.addExtension(new Tzip16Module(customMetadataProvider)); + connection.addExtension(new Tzip12Module()); + connection.setStreamProvider( + connection.getFactory(PollingSubscribeProvider)({ + shouldObservableSubscriptionRetry: true, + pollingIntervalMilliseconds: 500, + }) + ); + return connection; +}; + +export const TezosToolkitContext = createContext({ + tezos: createTezosConnection(), +}); + +export const TezosToolkitProvider = ({ + children, +}: { + children: React.ReactNode; +}) => { + const context = React.useContext(TezosToolkitContext); + return ( + + {children} + + ); +}; + +export const useTezosToolkit = () => React.useContext(TezosToolkitContext); diff --git a/context/wallet.tsx b/context/wallet.tsx new file mode 100644 index 00000000..e9f0da37 --- /dev/null +++ b/context/wallet.tsx @@ -0,0 +1,157 @@ +import { AccountInfo, LocalStorage } from "@airgap/beacon-sdk"; +import { BeaconWallet } from "@taquito/beacon-wallet"; +import { TezosToolkit } from "@taquito/taquito"; +import React, { createContext, useEffect, useReducer } from "react"; +import { PREFERED_NETWORK } from "../context/config"; +import { RPC_URL } from "./config"; +import { BeaconSigner } from "./signer"; +import { useTezosToolkit } from "./tezos-toolkit"; + +type WalletState = { + wallet: BeaconWallet | undefined; + userAccount: AccountInfo | undefined; + userAddress: string | undefined; + userBalance: number | undefined; +}; + +type WalletContextType = { + connectWallet: () => void; + disconnectWallet: () => void; + wallet: BeaconWallet | undefined; + userAccount: AccountInfo | undefined; + userAddress: string | undefined; + userBalance: number | undefined; +}; + +const createWalletConnection = (tezos: TezosToolkit) => { + const wallet = new BeaconWallet({ + name: "TzSafe", + preferredNetwork: PREFERED_NETWORK, + storage: new LocalStorage("WALLET"), + }); + + tezos.setProvider({ + rpc: RPC_URL, + wallet, + }); + tezos.setSignerProvider(new BeaconSigner(wallet)); + + return wallet; +}; + +const initialState: WalletState = { + wallet: undefined, + userAccount: undefined, + userAddress: undefined, + userBalance: undefined, +}; + +export const WalletContext = createContext({ + wallet: undefined, + userAccount: undefined, + userAddress: undefined, + userBalance: undefined, + connectWallet: () => {}, + disconnectWallet: () => {}, +}); + +const connectWallet = async (tezos: TezosToolkit) => { + const wallet = createWalletConnection(tezos); + + await wallet.requestPermissions({ + network: { + // @ts-ignore + type: PREFERED_NETWORK, + rpcUrl: RPC_URL, + }, + }); + + return await wallet.client.getActiveAccount().then(async userAccount => { + const userAddress = await wallet.getPKH(); + const userBalance = (await tezos.tz.getBalance(userAddress)).toNumber(); + + return { wallet, userAddress, userAccount, userBalance }; + }); +}; + +const disconnectWallet = async (wallet?: BeaconWallet) => { + if (!wallet) return Promise.reject("Error: No wallet. Can't disconnected."); + + wallet.clearActiveAccount(); + + return Promise.resolve(); +}; + +const reducer = ( + state: WalletState, + action: + | { + type: "CONNECT_WALLET"; + payload: { + wallet: BeaconWallet; + userAddress: string; + userAccount: AccountInfo | undefined; + }; + } + | { + type: "DISCONNECT_WALLET"; + } + | { + type: "HYDRATE_WALLET"; + userAddress: string | undefined; + userAccount: AccountInfo | undefined; + wallet: BeaconWallet; + } +) => { + switch (action.type) { + case "CONNECT_WALLET": + return { ...state, ...action.payload }; + case "DISCONNECT_WALLET": + return { ...initialState, wallet: state.wallet }; + case "HYDRATE_WALLET": { + const { userAddress, userAccount, wallet } = action; + return { ...state, userAddress, userAccount, wallet }; + } + default: + return state; + } +}; + +export const WalletProvider = ({ children }: { children: React.ReactNode }) => { + const { tezos } = useTezosToolkit(); + + const [state, dispatch] = useReducer(reducer, initialState); + + useEffect(() => { + const wallet = createWalletConnection(tezos); + + wallet.client.getActiveAccount().then(userAccount => { + dispatch({ + type: "HYDRATE_WALLET", + userAddress: userAccount?.address, + userAccount, + wallet, + }); + }); + }, [tezos]); + + return ( + + connectWallet(tezos).then(payload => + dispatch({ type: "CONNECT_WALLET", payload }) + ), + disconnectWallet: () => + disconnectWallet(state.wallet).then(() => { + dispatch({ type: "DISCONNECT_WALLET" }); + }), + }} + > + {children} + + ); +}; + +export const useWallet = () => React.useContext(WalletContext); diff --git a/dapps/tezosDomains.tsx b/dapps/tezosDomains.tsx index 119d0e1a..ed32e129 100644 --- a/dapps/tezosDomains.tsx +++ b/dapps/tezosDomains.tsx @@ -1,7 +1,7 @@ import { Parser } from "@taquito/michel-codec"; import { MichelsonMap, Schema } from "@taquito/michelson-encoder"; import { TezosToolkit } from "@taquito/taquito"; -import { bytes2Char } from "@taquito/tzip16"; +import { bytesToString } from "@taquito/tzip16"; import BigNumber from "bignumber.js"; import React, { ReactNode, useEffect, useState } from "react"; import { contracts, CustomViewData, CustomView } from "."; @@ -377,7 +377,7 @@ export function tezosDomains( action: COMMIT_ADDRESS.name, description: (

- TzSafe doesn't support the entrypoint:{" "} + {"TzSafe doesn't support the entrypoint:"} {transaction.entrypoints}

), @@ -401,7 +401,7 @@ export function tezosDomains( action: BUY_ADDRESS.name, description: (

- TzSafe doesn't support the entrypoint:{" "} + {"TzSafe doesn't support the entrypoint:"} {transaction.entrypoints}

), @@ -410,7 +410,7 @@ export function tezosDomains( const data = buySchema.Execute(micheline); - const domain = `${bytes2Char(data.label)}${ + const domain = `${bytesToString(data.label)}${ transaction.addresses === tezosDomainsContracts.BUY_ADDRESS.mainnet ? ".tez" : ".gho" @@ -458,7 +458,7 @@ export function tezosDomains( action: CLAIM_REVERSE_RECORD.name, description: (

- TzSafe doesn't support the entrypoint:{" "} + {"TzSafe doesn't support the entrypoint:"} {transaction.entrypoints}

), @@ -467,7 +467,9 @@ export function tezosDomains( const data = claimReverseRecordSchema.Execute(micheline); - const domain = !!data.name ? bytes2Char(data.name.Some) : undefined; + const domain = !!data.name + ? bytesToString(data.name.Some) + : undefined; return [ { @@ -507,7 +509,7 @@ export function tezosDomains( action: UPDATE_REVERSE_RECORD.name, description: (

- TzSafe doesn't support the entrypoint:{" "} + {"TzSafe doesn't support the entrypoint:"} {transaction.entrypoints}

), @@ -516,7 +518,7 @@ export function tezosDomains( const data = updateReverseRecordSchema.Execute(micheline); - const domain = bytes2Char(data.name?.Some ?? ""); + const domain = bytesToString(data.name?.Some ?? ""); return [ { @@ -559,7 +561,7 @@ export function tezosDomains( action: UPDATE_RECORD.name, description: (

- TzSafe doesn't support the entrypoint:{" "} + {"TzSafe doesn't support the entrypoint:"} {transaction.entrypoints}

), @@ -568,11 +570,11 @@ export function tezosDomains( const data = updateRecordSchema.Execute(micheline); - const recordName = bytes2Char(data.name); + const recordName = bytesToString(data.name); const parsedData = Array.from( (data.data as MichelsonMap).entries() - ).map(([key, value]) => `${key}: ${bytes2Char(value)}`); + ).map(([key, value]) => `${key}: ${bytesToString(value)}`); return [ { @@ -617,7 +619,7 @@ export function tezosDomains( action: BID.name, description: (

- TzSafe doesn't support the entrypoint:{" "} + {"TzSafe doesn't support the entrypoint:"} {transaction.entrypoints}

), @@ -626,7 +628,7 @@ export function tezosDomains( const data = bidSchema.Execute(micheline); - const domain = `${bytes2Char(data.label)}${ + const domain = `${bytesToString(data.label)}${ transaction.addresses === BID.mainnet ? ".tez" : ".gho" }`; @@ -664,7 +666,7 @@ export function tezosDomains( action: SETTLE.name, description: (

- TzSafe doesn't support the entrypoint:{" "} + {"TzSafe doesn't support the entrypoint:"} {transaction.entrypoints}

), @@ -673,7 +675,7 @@ export function tezosDomains( const data = settleSchema.Execute(micheline); - const domain = `${bytes2Char(data.label)}${ + const domain = `${bytesToString(data.label)}${ transaction.addresses === SETTLE.mainnet ? ".tez" : ".gho" }`; @@ -718,7 +720,7 @@ export function tezosDomains( action: WITHDRAW.name, description: (

- TzSafe doesn't support the entrypoint:{" "} + {"TzSafe doesn't support the entrypoint:"} {transaction.entrypoints}

), @@ -749,7 +751,7 @@ export function tezosDomains( action: RENEW.name, description: (

- TzSafe doesn't support the entrypoint:{" "} + {"TzSafe doesn't support the entrypoint:"} {transaction.entrypoints}

), @@ -758,7 +760,7 @@ export function tezosDomains( const data = renewSchema.Execute(micheline); - const domain = `${bytes2Char(data.label)}${ + const domain = `${bytesToString(data.label)}${ transaction.addresses === RENEW.mainnet ? ".tez" : ".gho" }`; @@ -799,7 +801,7 @@ export function tezosDomains( action: SET_CHILD_RECORD.name, description: (

- TzSafe doesn't support the entrypoint:{" "} + {"TzSafe doesn't support the entrypoint:"} {transaction.entrypoints}

), @@ -808,7 +810,9 @@ export function tezosDomains( const data = setChildRecordSchema.Execute(micheline); - const domain = `${bytes2Char(data.label)}.${bytes2Char(data.parent)}`; + const domain = `${bytesToString(data.label)}.${bytesToString( + data.parent + )}`; return [ { action: SET_CHILD_RECORD.name, @@ -845,7 +849,7 @@ export function tezosDomains( action: CHECK_ADDRESS.name, description: (

- TzSafe doesn't support the entrypoint:{" "} + {"TzSafe doesn't support the entrypoint:"} {transaction.entrypoints}

), @@ -859,7 +863,7 @@ export function tezosDomains( action: CHECK_ADDRESS.name, description: (
    -
  • Name: {bytes2Char(data.name)}
  • +
  • Name: {bytesToString(data.name)}
  • Address: {" "}
  • @@ -957,7 +961,7 @@ export function tezosDomains( action: "Internal", description: (

    - TzSafe doesn't support the entrypoint:{" "} + {"TzSafe doesn't support the entrypoint:"} {transaction.entrypoints}

    ), @@ -1082,7 +1086,7 @@ export function tezosDomains( action: "Domain", description: (

    - TzSafe doesn't support the entrypoint:{" "} + {"TzSafe doesn't support the entrypoint:"} {transaction.entrypoints}

    ), diff --git a/package-lock.json b/package-lock.json index 844238d0..bf7468de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,18 +8,19 @@ "name": "multisig", "version": "0.1.0", "dependencies": { - "@airgap/beacon-sdk": "^4.1.3-beta.1", + "@airgap/beacon-sdk": "^4.2.1", "@ariakit/react": "^0.1.8", "@radix-ui/react-icons": "^1.1.1", "@radix-ui/react-select": "^1.2.0", "@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-tooltip": "^1.0.3", "@stablelib/blake2b": "^1.0.1", - "@taquito/beacon-wallet": "^17.2.0", - "@taquito/taquito": "^17.2.0", - "@taquito/tzip12": "^17.5.2", - "@taquito/tzip16": "^17.2.0", - "@taquito/utils": "^19.1.0", + "@taquito/beacon-wallet": "^19.2.0", + "@taquito/rpc": "^19.2.0", + "@taquito/taquito": "^19.2.0", + "@taquito/tzip12": "^19.2.0", + "@taquito/tzip16": "^19.2.0", + "@taquito/utils": "^19.2.0", "@types/node": "18.11.9", "@types/react": "18.0.25", "@types/react-dom": "18.0.9", @@ -82,30 +83,30 @@ "dev": true }, "node_modules/@airgap/beacon-blockchain-substrate": { - "version": "4.1.3-beta.1", - "resolved": "https://registry.npmjs.org/@airgap/beacon-blockchain-substrate/-/beacon-blockchain-substrate-4.1.3-beta.1.tgz", - "integrity": "sha512-gLmc/ZBJcQaKRQk2s8Ljy/n+bhHZOh7NYcQnHp0Mo+jwBCR1Lb4LmvlY6aG3hlhZkpOYlt69pvleOzRLNoVxsw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@airgap/beacon-blockchain-substrate/-/beacon-blockchain-substrate-4.2.1.tgz", + "integrity": "sha512-Zaggh3QdYYlXV8DsdbPcLuKCLCG9mqSBCQSrLZphaHi9phL16GuAcM7UnuQTnN9UbAS1gkLe3I1IIXZHNpMTig==", "dependencies": { - "@airgap/beacon-types": "4.1.3-beta.1", - "@airgap/beacon-ui": "4.1.3-beta.1" + "@airgap/beacon-types": "4.2.1", + "@airgap/beacon-ui": "4.2.1" } }, "node_modules/@airgap/beacon-blockchain-tezos": { - "version": "4.1.3-beta.1", - "resolved": "https://registry.npmjs.org/@airgap/beacon-blockchain-tezos/-/beacon-blockchain-tezos-4.1.3-beta.1.tgz", - "integrity": "sha512-IaxOwR6Hz2T0W/78atsY8fVsiP6ET1Ler6vWAXOxSu/74MCusIrouYwvzeavuVTBtwDoFVMhhdPGEOSg4+Hd7g==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@airgap/beacon-blockchain-tezos/-/beacon-blockchain-tezos-4.2.1.tgz", + "integrity": "sha512-vVwROjzt70MjiSDKbsUV2gHxFT8YMfCnn9t/FR04nn/DIxWrnxmRPoWh8lnqJOx2SHuqQgVDTE0i4kxBYuW94Q==", "dependencies": { - "@airgap/beacon-types": "4.1.3-beta.1", - "@airgap/beacon-ui": "4.1.3-beta.1" + "@airgap/beacon-types": "4.2.1", + "@airgap/beacon-ui": "4.2.1" } }, "node_modules/@airgap/beacon-core": { - "version": "4.1.3-beta.1", - "resolved": "https://registry.npmjs.org/@airgap/beacon-core/-/beacon-core-4.1.3-beta.1.tgz", - "integrity": "sha512-rQ16DFCxCGsrtRJZ1V2QZMlQ2QpBebSp4c/kzTBpU7TwZH9mx2u3cbpQZKB2kpV4+AjEyXG3GyY3Z5rU4lrcTA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@airgap/beacon-core/-/beacon-core-4.2.1.tgz", + "integrity": "sha512-rOfvmxTcfoPfC40G2RoPxp9HtQjeNZGuecvmsGAkbEcJHZpgNXoyp5zt8YeBBpxA8KsV156FcUDjyHadSFjaWw==", "dependencies": { - "@airgap/beacon-types": "4.1.3-beta.1", - "@airgap/beacon-utils": "4.1.3-beta.1", + "@airgap/beacon-types": "4.2.1", + "@airgap/beacon-utils": "4.2.1", "@stablelib/ed25519": "^1.0.3", "@stablelib/nacl": "^1.0.4", "@stablelib/utf8": "^1.0.1", @@ -140,62 +141,62 @@ } }, "node_modules/@airgap/beacon-dapp": { - "version": "4.1.3-beta.1", - "resolved": "https://registry.npmjs.org/@airgap/beacon-dapp/-/beacon-dapp-4.1.3-beta.1.tgz", - "integrity": "sha512-SWlDKdDtg+g2oXQiEfGk9b5EIr+T/OtxFUl8yEOkSIQs2Uz5TOMYZ6Esda2Wu3D+zsXLgf97PVSHbsYavTHLQA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@airgap/beacon-dapp/-/beacon-dapp-4.2.1.tgz", + "integrity": "sha512-lt1B8JL2yQkun0imhQv/Fz/LhHTrXo1xdBlYUopOGi6KHtXXyGZpMTrAqEUWn/nKYcygjx+zNI5NaMxDn2Ejlg==", "dependencies": { - "@airgap/beacon-core": "4.1.3-beta.1", - "@airgap/beacon-transport-matrix": "4.1.3-beta.1", - "@airgap/beacon-transport-postmessage": "4.1.3-beta.1", - "@airgap/beacon-transport-walletconnect": "4.1.3-beta.1", - "@airgap/beacon-ui": "4.1.3-beta.1" + "@airgap/beacon-core": "4.2.1", + "@airgap/beacon-transport-matrix": "4.2.1", + "@airgap/beacon-transport-postmessage": "4.2.1", + "@airgap/beacon-transport-walletconnect": "4.2.1", + "@airgap/beacon-ui": "4.2.1" } }, "node_modules/@airgap/beacon-sdk": { - "version": "4.1.3-beta.1", - "resolved": "https://registry.npmjs.org/@airgap/beacon-sdk/-/beacon-sdk-4.1.3-beta.1.tgz", - "integrity": "sha512-vulhBBtcgxEd5o5i51SmOjDNQGR/D445jnQBJx+hm0Pr3c54yY2DTyPCyXYz8wwZAud+YnmWdOzyJMGmmbvozA==", - "dependencies": { - "@airgap/beacon-blockchain-substrate": "4.1.3-beta.1", - "@airgap/beacon-blockchain-tezos": "4.1.3-beta.1", - "@airgap/beacon-core": "4.1.3-beta.1", - "@airgap/beacon-dapp": "4.1.3-beta.1", - "@airgap/beacon-transport-matrix": "4.1.3-beta.1", - "@airgap/beacon-transport-postmessage": "4.1.3-beta.1", - "@airgap/beacon-types": "4.1.3-beta.1", - "@airgap/beacon-ui": "4.1.3-beta.1", - "@airgap/beacon-utils": "4.1.3-beta.1", - "@airgap/beacon-wallet": "4.1.3-beta.1" + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@airgap/beacon-sdk/-/beacon-sdk-4.2.1.tgz", + "integrity": "sha512-/NhrQBETARyB3UT1c7/IEAItV1RmCpdGd2m32Dn8MsyAmHki+y+BuKBuWuywjKOZHqVntkeqIWvh9thmBnih/w==", + "dependencies": { + "@airgap/beacon-blockchain-substrate": "4.2.1", + "@airgap/beacon-blockchain-tezos": "4.2.1", + "@airgap/beacon-core": "4.2.1", + "@airgap/beacon-dapp": "4.2.1", + "@airgap/beacon-transport-matrix": "4.2.1", + "@airgap/beacon-transport-postmessage": "4.2.1", + "@airgap/beacon-types": "4.2.1", + "@airgap/beacon-ui": "4.2.1", + "@airgap/beacon-utils": "4.2.1", + "@airgap/beacon-wallet": "4.2.1" } }, "node_modules/@airgap/beacon-transport-matrix": { - "version": "4.1.3-beta.1", - "resolved": "https://registry.npmjs.org/@airgap/beacon-transport-matrix/-/beacon-transport-matrix-4.1.3-beta.1.tgz", - "integrity": "sha512-B2MlQDbef2v6ni/Tu7zNdYpKSVV/jMGdTB6mTWw9q94VP7cSbeS2wjaT+mUbTeR2Hpl+RK/PH6hGRsTEniNQ6Q==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@airgap/beacon-transport-matrix/-/beacon-transport-matrix-4.2.1.tgz", + "integrity": "sha512-ggvKQPreXVrm5t3kPV/RGBTIxo8ujSrE6tb6kpUAQyMC+mfMPY5WeP8qwqgMT+yzRMYUlkJa3u+hNxoSQIKK+A==", "dependencies": { - "@airgap/beacon-core": "4.1.3-beta.1", - "@airgap/beacon-utils": "4.1.3-beta.1", + "@airgap/beacon-core": "4.2.1", + "@airgap/beacon-utils": "4.2.1", "axios": "^1.6.2" } }, "node_modules/@airgap/beacon-transport-postmessage": { - "version": "4.1.3-beta.1", - "resolved": "https://registry.npmjs.org/@airgap/beacon-transport-postmessage/-/beacon-transport-postmessage-4.1.3-beta.1.tgz", - "integrity": "sha512-Q7I+yi2ZPsZXKofeOTCF6Bco9gYVOd769kdTq5SZlKH44hmb+qjKkC1a7sal2BoeJb4XMYnFRDeCDvGzIIX8HQ==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@airgap/beacon-transport-postmessage/-/beacon-transport-postmessage-4.2.1.tgz", + "integrity": "sha512-/sq2yz90scWNwb93nhe9hXQZpetXLuc/BRJcyg3W3Sv53wEQ5yPb9XmedFhuFo/Tc8nTt5kZgz5ORXgDnlATJg==", "dependencies": { - "@airgap/beacon-core": "4.1.3-beta.1", - "@airgap/beacon-types": "4.1.3-beta.1", - "@airgap/beacon-utils": "4.1.3-beta.1" + "@airgap/beacon-core": "4.2.1", + "@airgap/beacon-types": "4.2.1", + "@airgap/beacon-utils": "4.2.1" } }, "node_modules/@airgap/beacon-transport-walletconnect": { - "version": "4.1.3-beta.1", - "resolved": "https://registry.npmjs.org/@airgap/beacon-transport-walletconnect/-/beacon-transport-walletconnect-4.1.3-beta.1.tgz", - "integrity": "sha512-oK0P3KN7QQrVqRn5tbImOkl16d+VajR1HfjuvfE6MP9lEb4NXeFC/yzXqnYBG9Evn/R3NSeh+ktxuw6aPpPO6w==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@airgap/beacon-transport-walletconnect/-/beacon-transport-walletconnect-4.2.1.tgz", + "integrity": "sha512-HTjKXtXP3z/Xg2yViE2o4gi556ickOTHjFz7t9ftp75qARP+XOW0uWcwTTV8YVK4mW5fXe0lM2M5nGXWD6nE8g==", "dependencies": { - "@airgap/beacon-core": "4.1.3-beta.1", - "@airgap/beacon-types": "4.1.3-beta.1", - "@airgap/beacon-utils": "4.1.3-beta.1", + "@airgap/beacon-core": "4.2.1", + "@airgap/beacon-types": "4.2.1", + "@airgap/beacon-utils": "4.2.1", "@walletconnect/sign-client": "2.11.2" } }, @@ -291,22 +292,22 @@ } }, "node_modules/@airgap/beacon-types": { - "version": "4.1.3-beta.1", - "resolved": "https://registry.npmjs.org/@airgap/beacon-types/-/beacon-types-4.1.3-beta.1.tgz", - "integrity": "sha512-gnrbaPhIFlqAvP5RDGcCSsM56CclwiI7GjMNSwVl9LqjQJc98PbhtuTdr+rUNdhHzY91WE8h1Rnl/oFMp7J7Tg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@airgap/beacon-types/-/beacon-types-4.2.1.tgz", + "integrity": "sha512-6PBO/FCb2kDgfJdLVhImcK9oXq3Pa444/xOW3a5WEbVqq+q9qo5OjdscJFAviQgRMz8NJJvOn8/5RbRJBy2uWw==", "dependencies": { "@types/chrome": "0.0.246" } }, "node_modules/@airgap/beacon-ui": { - "version": "4.1.3-beta.1", - "resolved": "https://registry.npmjs.org/@airgap/beacon-ui/-/beacon-ui-4.1.3-beta.1.tgz", - "integrity": "sha512-GwtbuNHoHAMlvVasFN+sE+voq5w553x8bgfRR4dQ3lJKFil/X0Y/dZ224cPglSkzrO6DExbwsDVIvegkNQgmzg==", - "dependencies": { - "@airgap/beacon-core": "4.1.3-beta.1", - "@airgap/beacon-transport-postmessage": "4.1.3-beta.1", - "@airgap/beacon-types": "4.1.3-beta.1", - "@airgap/beacon-utils": "4.1.3-beta.1", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@airgap/beacon-ui/-/beacon-ui-4.2.1.tgz", + "integrity": "sha512-doCNbi9iaJQmNWKr54/i39VkgO/IFdxArdyxrUYAT2Z6bcLa+cJu3ttNjVQKoAhm8Z07QFWneMnS7RbYZRNbWg==", + "dependencies": { + "@airgap/beacon-core": "4.2.1", + "@airgap/beacon-transport-postmessage": "4.2.1", + "@airgap/beacon-types": "4.2.1", + "@airgap/beacon-utils": "4.2.1", "@walletconnect/utils": "2.11.2", "qrcode-svg": "^1.1.0", "solid-js": "^1.7.11" @@ -364,9 +365,9 @@ } }, "node_modules/@airgap/beacon-utils": { - "version": "4.1.3-beta.1", - "resolved": "https://registry.npmjs.org/@airgap/beacon-utils/-/beacon-utils-4.1.3-beta.1.tgz", - "integrity": "sha512-4rshFgmgbceCcmDh5zFLr9zopz770czBml4SGckH4RxTYQZgvMYvlzE0O0RvFeQmM2u8oQenozQHOXTf9Z6Kuw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@airgap/beacon-utils/-/beacon-utils-4.2.1.tgz", + "integrity": "sha512-Ob9OE1w9jnytC9s9UYuClBef1lmJnKFnB8NsqeLPur2AHC+9M2aeua92cS6KY8GkQo3EN4KzaCguC3QFo3nsVw==", "dependencies": { "@stablelib/ed25519": "^1.0.3", "@stablelib/nacl": "^1.0.4", @@ -402,13 +403,13 @@ } }, "node_modules/@airgap/beacon-wallet": { - "version": "4.1.3-beta.1", - "resolved": "https://registry.npmjs.org/@airgap/beacon-wallet/-/beacon-wallet-4.1.3-beta.1.tgz", - "integrity": "sha512-DLAm3kNd5BxFWsuDPB2jcQbpmc+hrvSLYsIkUUBhVPulzi28i4COPE079T6f8FyVmurinqC8Tx0nwI6dLZZFNg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@airgap/beacon-wallet/-/beacon-wallet-4.2.1.tgz", + "integrity": "sha512-YnEKbLVGlqZ2YwkD+bIKu6ZqMpIje2QtKccpnYbLsOSqZHY0+0n5iu63qkKw8Wy6PWDp1JN4CFVQVnGrRo7f9g==", "dependencies": { - "@airgap/beacon-core": "4.1.3-beta.1", - "@airgap/beacon-transport-matrix": "4.1.3-beta.1", - "@airgap/beacon-transport-postmessage": "4.1.3-beta.1" + "@airgap/beacon-core": "4.2.1", + "@airgap/beacon-transport-matrix": "4.2.1", + "@airgap/beacon-transport-postmessage": "4.2.1" } }, "node_modules/@alloc/quick-lru": { @@ -3117,141 +3118,34 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/@taquito/beacon-wallet": { - "version": "17.3.2", - "license": "Apache-2.0", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/beacon-wallet/-/beacon-wallet-19.2.0.tgz", + "integrity": "sha512-8gUlOEXZSbSaMEvhm1mHpWFj2TKe6KH1Fl+mT+NsG0RXPbben3O3d8iTwiFjZ2oT7ZLe8WbquQy7cE+kHmOuoQ==", "dependencies": { - "@airgap/beacon-dapp": "4.0.12", - "@taquito/core": "^17.3.2", - "@taquito/taquito": "^17.3.2" + "@airgap/beacon-dapp": "^4.2.1", + "@taquito/core": "^19.1.0", + "@taquito/taquito": "^19.2.0" }, "engines": { - "node": ">=16" - } - }, - "node_modules/@taquito/beacon-wallet/node_modules/@airgap/beacon-core": { - "version": "4.0.12", - "license": "ISC", - "dependencies": { - "@airgap/beacon-types": "4.0.12", - "@airgap/beacon-utils": "4.0.12", - "@stablelib/ed25519": "^1.0.3", - "@stablelib/nacl": "^1.0.4", - "@stablelib/utf8": "^1.0.1", - "@stablelib/x25519-session": "^1.0.4", - "bs58check": "2.1.2" - } - }, - "node_modules/@taquito/beacon-wallet/node_modules/@airgap/beacon-dapp": { - "version": "4.0.12", - "license": "ISC", - "dependencies": { - "@airgap/beacon-core": "4.0.12", - "@airgap/beacon-transport-matrix": "4.0.12", - "@airgap/beacon-transport-postmessage": "4.0.12", - "@airgap/beacon-transport-walletconnect": "4.0.12", - "@airgap/beacon-ui": "4.0.12" - } - }, - "node_modules/@taquito/beacon-wallet/node_modules/@airgap/beacon-transport-matrix": { - "version": "4.0.12", - "license": "ISC", - "dependencies": { - "@airgap/beacon-core": "4.0.12", - "@airgap/beacon-utils": "4.0.12", - "axios": "0.24.0" - } - }, - "node_modules/@taquito/beacon-wallet/node_modules/@airgap/beacon-transport-postmessage": { - "version": "4.0.12", - "license": "ISC", - "dependencies": { - "@airgap/beacon-core": "4.0.12", - "@airgap/beacon-types": "4.0.12", - "@airgap/beacon-utils": "4.0.12" - } - }, - "node_modules/@taquito/beacon-wallet/node_modules/@airgap/beacon-transport-walletconnect": { - "version": "4.0.12", - "license": "ISC", - "dependencies": { - "@airgap/beacon-core": "4.0.12", - "@airgap/beacon-types": "4.0.12", - "@airgap/beacon-utils": "4.0.12", - "@walletconnect/sign-client": "2.7.0" - } - }, - "node_modules/@taquito/beacon-wallet/node_modules/@airgap/beacon-types": { - "version": "4.0.12", - "license": "ISC", - "dependencies": { - "@types/chrome": "0.0.163" - } - }, - "node_modules/@taquito/beacon-wallet/node_modules/@airgap/beacon-ui": { - "version": "4.0.12", - "license": "ISC", - "dependencies": { - "@airgap/beacon-core": "4.0.12", - "@airgap/beacon-transport-postmessage": "4.0.12", - "@airgap/beacon-types": "4.0.12", - "@airgap/beacon-utils": "4.0.12", - "qrcode-svg": "^1.1.0", - "solid-js": "^1.6.6" - } - }, - "node_modules/@taquito/beacon-wallet/node_modules/@airgap/beacon-utils": { - "version": "4.0.12", - "license": "ISC", - "dependencies": { - "@stablelib/ed25519": "^1.0.3", - "@stablelib/nacl": "^1.0.3", - "@stablelib/random": "^1.0.2", - "@stablelib/utf8": "^1.0.1", - "bs58check": "2.1.2" - } - }, - "node_modules/@taquito/beacon-wallet/node_modules/@types/chrome": { - "version": "0.0.163", - "license": "MIT", - "dependencies": { - "@types/filesystem": "*", - "@types/har-format": "*" - } - }, - "node_modules/@taquito/beacon-wallet/node_modules/axios": { - "version": "0.24.0", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.14.4" - } - }, - "node_modules/@taquito/beacon-wallet/node_modules/base-x": { - "version": "3.0.9", - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/@taquito/beacon-wallet/node_modules/bs58": { - "version": "4.0.1", - "license": "MIT", - "dependencies": { - "base-x": "^3.0.2" + "node": ">=18" } }, - "node_modules/@taquito/beacon-wallet/node_modules/bs58check": { - "version": "2.1.2", - "license": "MIT", + "node_modules/@taquito/beacon-wallet/node_modules/@taquito/core": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@taquito/core/-/core-19.1.0.tgz", + "integrity": "sha512-gW7rQCXnznCsTaVNF04ilS6jgzxfJWRiDm7BDC0U5FrEHxIfiRXj6dDbVtOLvcai2xBmfCghFL79lCsToVYztQ==", "dependencies": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" + "json-stringify-safe": "^5.0.1" + }, + "engines": { + "node": ">=18" } }, "node_modules/@taquito/core": { "version": "17.5.2", "resolved": "https://registry.npmjs.org/@taquito/core/-/core-17.5.2.tgz", "integrity": "sha512-8MrQBg915r/GYSqAYIhx9b51vdrtW68S/5yMCdNvYc6xL5d92wIrXCy6gEkNkIS0kZyTQGfFgfWy6KyJZaIhNw==", + "dev": true, "dependencies": { "json-stringify-safe": "^5.0.1" }, @@ -3263,6 +3157,7 @@ "version": "17.5.2", "resolved": "https://registry.npmjs.org/@taquito/http-utils/-/http-utils-17.5.2.tgz", "integrity": "sha512-DQnjsHsgXELeUl59gdRTXy9U72RTWa27z7h2s4mRuQ5W4EYQRCWGbb5cOlUcZlEmNjcWCuVk+JBbULvgRk6N/g==", + "dev": true, "dependencies": { "@taquito/core": "^17.5.2", "node-fetch": "^2.7.0" @@ -3272,44 +3167,46 @@ } }, "node_modules/@taquito/local-forging": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@taquito/local-forging/-/local-forging-17.5.2.tgz", - "integrity": "sha512-QnywxtnQBRXrZDkNgIn7rSsExcPjCZx+uS0ojgiYGPI/NSUBUMDqvTy8vhuVJZVTw2CvjAFKrQpbjarF8jC5nw==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/local-forging/-/local-forging-19.2.0.tgz", + "integrity": "sha512-QqamfNVQOcoVXeWM92EnWo6wkpvXlBrgog8J70vv6PNtdU1geKQMmCIy7sz3qkKwCfPksUTgcROv3CS5fCUyFQ==", "dependencies": { - "@taquito/core": "^17.5.2", - "@taquito/utils": "^17.5.2", + "@taquito/core": "^19.1.0", + "@taquito/utils": "^19.2.0", "bignumber.js": "^9.1.2" }, "engines": { "node": ">=18" } }, - "node_modules/@taquito/local-forging/node_modules/@taquito/utils": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-17.5.2.tgz", - "integrity": "sha512-gtdQzInxbmylKHDAjUIW0npYWYUAyDwhPsFXdF/r7juM6g+qxB7WFbt7vZAYlA4gwwHxPSehehvBkHvEPQ3UWQ==", + "node_modules/@taquito/local-forging/node_modules/@taquito/core": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@taquito/core/-/core-19.1.0.tgz", + "integrity": "sha512-gW7rQCXnznCsTaVNF04ilS6jgzxfJWRiDm7BDC0U5FrEHxIfiRXj6dDbVtOLvcai2xBmfCghFL79lCsToVYztQ==", "dependencies": { - "@stablelib/blake2b": "^1.0.1", - "@stablelib/ed25519": "^1.0.3", - "@taquito/core": "^17.5.2", - "@types/bs58check": "^2.1.0", - "bignumber.js": "^9.1.2", - "blakejs": "^1.2.1", - "bs58check": "^3.0.1", - "buffer": "^6.0.3", - "elliptic": "^6.5.4", - "typedarray-to-buffer": "^4.0.0" + "json-stringify-safe": "^5.0.1" }, "engines": { "node": ">=18" } }, "node_modules/@taquito/michel-codec": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@taquito/michel-codec/-/michel-codec-17.5.2.tgz", - "integrity": "sha512-E3UgpipaiL+9dHuVpvXy6meRE0n1Nfk/W37gMFjgr4pRZefG7Bd3RtPdMr0tTGipxmAT6TT2r8lDqblW4GhufA==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/michel-codec/-/michel-codec-19.2.0.tgz", + "integrity": "sha512-vdbeUyQ4iDajYdnWxYYIJ9Q1ucg7Kz3okwMDG/A2TickX9i3jSBhGDkeu37FWPQrYZQG1kpJ25FobtFF1IGsJQ==", "dependencies": { - "@taquito/core": "^17.5.2" + "@taquito/core": "^19.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@taquito/michel-codec/node_modules/@taquito/core": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@taquito/core/-/core-19.1.0.tgz", + "integrity": "sha512-gW7rQCXnznCsTaVNF04ilS6jgzxfJWRiDm7BDC0U5FrEHxIfiRXj6dDbVtOLvcai2xBmfCghFL79lCsToVYztQ==", + "dependencies": { + "json-stringify-safe": "^5.0.1" }, "engines": { "node": ">=18" @@ -3319,6 +3216,7 @@ "version": "17.5.2", "resolved": "https://registry.npmjs.org/@taquito/michelson-encoder/-/michelson-encoder-17.5.2.tgz", "integrity": "sha512-GrQpAQHUdpYxcuIoDs6Er/UqAhPRu+KCnsCHkwLd/O5LUpQA/+AO+knnKIPvipAJ6ZJ/OP/eU+3fQWF0sQ2R0g==", + "dev": true, "dependencies": { "@taquito/core": "^17.5.2", "@taquito/rpc": "^17.5.2", @@ -3330,10 +3228,26 @@ "node": ">=18" } }, + "node_modules/@taquito/michelson-encoder/node_modules/@taquito/rpc": { + "version": "17.5.2", + "resolved": "https://registry.npmjs.org/@taquito/rpc/-/rpc-17.5.2.tgz", + "integrity": "sha512-fyS8s+Jj/jaYwGrx/BR7KZgVRPESpI8CdHXuxYJdk5wbMms3d2UmPDXFLyeo3eVXrX75U771qqbU3m+rNK5aBQ==", + "dev": true, + "dependencies": { + "@taquito/core": "^17.5.2", + "@taquito/http-utils": "^17.5.2", + "@taquito/utils": "^17.5.2", + "bignumber.js": "^9.1.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@taquito/michelson-encoder/node_modules/@taquito/utils": { "version": "17.5.2", "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-17.5.2.tgz", "integrity": "sha512-gtdQzInxbmylKHDAjUIW0npYWYUAyDwhPsFXdF/r7juM6g+qxB7WFbt7vZAYlA4gwwHxPSehehvBkHvEPQ3UWQ==", + "dev": true, "dependencies": { "@stablelib/blake2b": "^1.0.1", "@stablelib/ed25519": "^1.0.3", @@ -3351,34 +3265,37 @@ } }, "node_modules/@taquito/rpc": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@taquito/rpc/-/rpc-17.5.2.tgz", - "integrity": "sha512-fyS8s+Jj/jaYwGrx/BR7KZgVRPESpI8CdHXuxYJdk5wbMms3d2UmPDXFLyeo3eVXrX75U771qqbU3m+rNK5aBQ==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/rpc/-/rpc-19.2.0.tgz", + "integrity": "sha512-FvpsASz4mULSC6EWcTLPWQZhKP1x2szf0NUWx5pCqcxOmw1b1rZHzZ4oxG9MBSVmVrJR6Wq1HB1ZKrE3uIjarQ==", "dependencies": { - "@taquito/core": "^17.5.2", - "@taquito/http-utils": "^17.5.2", - "@taquito/utils": "^17.5.2", + "@taquito/core": "^19.1.0", + "@taquito/http-utils": "^19.2.0", + "@taquito/utils": "^19.2.0", "bignumber.js": "^9.1.2" }, "engines": { "node": ">=18" } }, - "node_modules/@taquito/rpc/node_modules/@taquito/utils": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-17.5.2.tgz", - "integrity": "sha512-gtdQzInxbmylKHDAjUIW0npYWYUAyDwhPsFXdF/r7juM6g+qxB7WFbt7vZAYlA4gwwHxPSehehvBkHvEPQ3UWQ==", + "node_modules/@taquito/rpc/node_modules/@taquito/core": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@taquito/core/-/core-19.1.0.tgz", + "integrity": "sha512-gW7rQCXnznCsTaVNF04ilS6jgzxfJWRiDm7BDC0U5FrEHxIfiRXj6dDbVtOLvcai2xBmfCghFL79lCsToVYztQ==", "dependencies": { - "@stablelib/blake2b": "^1.0.1", - "@stablelib/ed25519": "^1.0.3", - "@taquito/core": "^17.5.2", - "@types/bs58check": "^2.1.0", - "bignumber.js": "^9.1.2", - "blakejs": "^1.2.1", - "bs58check": "^3.0.1", - "buffer": "^6.0.3", - "elliptic": "^6.5.4", - "typedarray-to-buffer": "^4.0.0" + "json-stringify-safe": "^5.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@taquito/rpc/node_modules/@taquito/http-utils": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/http-utils/-/http-utils-19.2.0.tgz", + "integrity": "sha512-iju4dYCEVpJ7x6HyIDbH58VvpMTkLqmGMgSlmkjQSPblCO6cTRlubepe4QPJ/ZKyVo1+4KUa8CBqZ9CDMRXOIA==", + "dependencies": { + "@taquito/core": "^19.1.0", + "node-fetch": "^2.7.0" }, "engines": { "node": ">=18" @@ -3409,31 +3326,52 @@ "node": ">=18" } }, - "node_modules/@taquito/signer/node_modules/@taquito/utils": { + "node_modules/@taquito/signer/node_modules/@taquito/local-forging": { "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-17.5.2.tgz", - "integrity": "sha512-gtdQzInxbmylKHDAjUIW0npYWYUAyDwhPsFXdF/r7juM6g+qxB7WFbt7vZAYlA4gwwHxPSehehvBkHvEPQ3UWQ==", + "resolved": "https://registry.npmjs.org/@taquito/local-forging/-/local-forging-17.5.2.tgz", + "integrity": "sha512-QnywxtnQBRXrZDkNgIn7rSsExcPjCZx+uS0ojgiYGPI/NSUBUMDqvTy8vhuVJZVTw2CvjAFKrQpbjarF8jC5nw==", "dev": true, "dependencies": { - "@stablelib/blake2b": "^1.0.1", - "@stablelib/ed25519": "^1.0.3", "@taquito/core": "^17.5.2", - "@types/bs58check": "^2.1.0", - "bignumber.js": "^9.1.2", - "blakejs": "^1.2.1", - "bs58check": "^3.0.1", - "buffer": "^6.0.3", - "elliptic": "^6.5.4", - "typedarray-to-buffer": "^4.0.0" + "@taquito/utils": "^17.5.2", + "bignumber.js": "^9.1.2" }, "engines": { "node": ">=18" } }, - "node_modules/@taquito/taquito": { + "node_modules/@taquito/signer/node_modules/@taquito/michel-codec": { + "version": "17.5.2", + "resolved": "https://registry.npmjs.org/@taquito/michel-codec/-/michel-codec-17.5.2.tgz", + "integrity": "sha512-E3UgpipaiL+9dHuVpvXy6meRE0n1Nfk/W37gMFjgr4pRZefG7Bd3RtPdMr0tTGipxmAT6TT2r8lDqblW4GhufA==", + "dev": true, + "dependencies": { + "@taquito/core": "^17.5.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@taquito/signer/node_modules/@taquito/rpc": { + "version": "17.5.2", + "resolved": "https://registry.npmjs.org/@taquito/rpc/-/rpc-17.5.2.tgz", + "integrity": "sha512-fyS8s+Jj/jaYwGrx/BR7KZgVRPESpI8CdHXuxYJdk5wbMms3d2UmPDXFLyeo3eVXrX75U771qqbU3m+rNK5aBQ==", + "dev": true, + "dependencies": { + "@taquito/core": "^17.5.2", + "@taquito/http-utils": "^17.5.2", + "@taquito/utils": "^17.5.2", + "bignumber.js": "^9.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@taquito/signer/node_modules/@taquito/taquito": { "version": "17.5.2", "resolved": "https://registry.npmjs.org/@taquito/taquito/-/taquito-17.5.2.tgz", "integrity": "sha512-aYsyV482oQeiIz5z7mHPS5bnxMfZw3ju99EOvBZOlVxFjw5ZhuGTz1q+gjgdyUvOLAUM7890lTla41pi6Ehb9g==", + "dev": true, "hasInstallScript": true, "dependencies": { "@taquito/core": "^17.5.2", @@ -3450,10 +3388,11 @@ "node": ">=18" } }, - "node_modules/@taquito/taquito/node_modules/@taquito/utils": { + "node_modules/@taquito/signer/node_modules/@taquito/utils": { "version": "17.5.2", "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-17.5.2.tgz", "integrity": "sha512-gtdQzInxbmylKHDAjUIW0npYWYUAyDwhPsFXdF/r7juM6g+qxB7WFbt7vZAYlA4gwwHxPSehehvBkHvEPQ3UWQ==", + "dev": true, "dependencies": { "@stablelib/blake2b": "^1.0.1", "@stablelib/ed25519": "^1.0.3", @@ -3470,31 +3409,115 @@ "node": ">=18" } }, + "node_modules/@taquito/taquito": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/taquito/-/taquito-19.2.0.tgz", + "integrity": "sha512-Y6/lSgfkHDh1lQFKTxdakDPI8WZWDWL6GXkwwILXIUGYvG9ZNoFSJzqYK3BAxpuNg/7uupwR8gpAy7qj/bZjmA==", + "hasInstallScript": true, + "dependencies": { + "@taquito/core": "^19.1.0", + "@taquito/http-utils": "^19.2.0", + "@taquito/local-forging": "^19.2.0", + "@taquito/michel-codec": "^19.2.0", + "@taquito/michelson-encoder": "^19.2.0", + "@taquito/rpc": "^19.2.0", + "@taquito/utils": "^19.2.0", + "bignumber.js": "^9.1.2", + "rxjs": "^7.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@taquito/taquito/node_modules/@taquito/core": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@taquito/core/-/core-19.1.0.tgz", + "integrity": "sha512-gW7rQCXnznCsTaVNF04ilS6jgzxfJWRiDm7BDC0U5FrEHxIfiRXj6dDbVtOLvcai2xBmfCghFL79lCsToVYztQ==", + "dependencies": { + "json-stringify-safe": "^5.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@taquito/taquito/node_modules/@taquito/http-utils": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/http-utils/-/http-utils-19.2.0.tgz", + "integrity": "sha512-iju4dYCEVpJ7x6HyIDbH58VvpMTkLqmGMgSlmkjQSPblCO6cTRlubepe4QPJ/ZKyVo1+4KUa8CBqZ9CDMRXOIA==", + "dependencies": { + "@taquito/core": "^19.1.0", + "node-fetch": "^2.7.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@taquito/taquito/node_modules/@taquito/michelson-encoder": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/michelson-encoder/-/michelson-encoder-19.2.0.tgz", + "integrity": "sha512-yJZxc5H0WSI3rNQi1/GctfEKEUIGnIp67RJT63FYgxfAbBmhXdR6zsEUfAG8NUQ9BShMWY+uos0yHN3GKMRYFg==", + "dependencies": { + "@taquito/core": "^19.1.0", + "@taquito/rpc": "^19.2.0", + "@taquito/utils": "^19.2.0", + "bignumber.js": "^9.1.2", + "fast-json-stable-stringify": "^2.1.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@taquito/tzip12": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@taquito/tzip12/-/tzip12-17.5.2.tgz", - "integrity": "sha512-BFx8cwit0Z1K5JlBkbTo3Pud7k0WcFp94+lj6WVlrgNCIJVGOm+3IvwEh0u2T8TzXpBj0yLwiSGJgTfGLYRQ/Q==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/tzip12/-/tzip12-19.2.0.tgz", + "integrity": "sha512-CVVC4pCyF2vUeNq9484aF1SBVteaSCM8ThSVtfQSJq7Ddt+z/Phi4Ovygkj8wkkdPIigGiyHppO18mp7O/509Q==", "dependencies": { - "@taquito/core": "^17.5.2", - "@taquito/michelson-encoder": "^17.5.2", - "@taquito/taquito": "^17.5.2", - "@taquito/tzip16": "^17.5.2" + "@taquito/core": "^19.1.0", + "@taquito/michelson-encoder": "^19.2.0", + "@taquito/taquito": "^19.2.0", + "@taquito/tzip16": "^19.2.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@taquito/tzip12/node_modules/@taquito/core": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@taquito/core/-/core-19.1.0.tgz", + "integrity": "sha512-gW7rQCXnznCsTaVNF04ilS6jgzxfJWRiDm7BDC0U5FrEHxIfiRXj6dDbVtOLvcai2xBmfCghFL79lCsToVYztQ==", + "dependencies": { + "json-stringify-safe": "^5.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@taquito/tzip12/node_modules/@taquito/michelson-encoder": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/michelson-encoder/-/michelson-encoder-19.2.0.tgz", + "integrity": "sha512-yJZxc5H0WSI3rNQi1/GctfEKEUIGnIp67RJT63FYgxfAbBmhXdR6zsEUfAG8NUQ9BShMWY+uos0yHN3GKMRYFg==", + "dependencies": { + "@taquito/core": "^19.1.0", + "@taquito/rpc": "^19.2.0", + "@taquito/utils": "^19.2.0", + "bignumber.js": "^9.1.2", + "fast-json-stable-stringify": "^2.1.0" }, "engines": { "node": ">=18" } }, "node_modules/@taquito/tzip16": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@taquito/tzip16/-/tzip16-17.5.2.tgz", - "integrity": "sha512-wvut9DT1gxIIP3K1LUIPdncvqgVYovI9WZ06d22dyUyAONKNXPN4UFYeEOdgoH/gHliSZuk9hF8HXsk2zpfzMQ==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/tzip16/-/tzip16-19.2.0.tgz", + "integrity": "sha512-APmE4c5YB7bzJcpTSHv3LGrUAOJbLkt6GcsHSOYrwlkamryoqkfmKn4Fkup99syZTIyJdfYmwayKi4Yxb0ivew==", "dependencies": { - "@taquito/core": "^17.5.2", - "@taquito/http-utils": "^17.5.2", - "@taquito/michelson-encoder": "^17.5.2", - "@taquito/rpc": "^17.5.2", - "@taquito/taquito": "^17.5.2", - "@taquito/utils": "^17.5.2", + "@taquito/core": "^19.1.0", + "@taquito/http-utils": "^19.2.0", + "@taquito/michelson-encoder": "^19.2.0", + "@taquito/rpc": "^19.2.0", + "@taquito/taquito": "^19.2.0", + "@taquito/utils": "^19.2.0", "bignumber.js": "^9.1.2", "crypto-js": "^4.2.0" }, @@ -3502,30 +3525,48 @@ "node": ">=18" } }, - "node_modules/@taquito/tzip16/node_modules/@taquito/utils": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-17.5.2.tgz", - "integrity": "sha512-gtdQzInxbmylKHDAjUIW0npYWYUAyDwhPsFXdF/r7juM6g+qxB7WFbt7vZAYlA4gwwHxPSehehvBkHvEPQ3UWQ==", + "node_modules/@taquito/tzip16/node_modules/@taquito/core": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@taquito/core/-/core-19.1.0.tgz", + "integrity": "sha512-gW7rQCXnznCsTaVNF04ilS6jgzxfJWRiDm7BDC0U5FrEHxIfiRXj6dDbVtOLvcai2xBmfCghFL79lCsToVYztQ==", "dependencies": { - "@stablelib/blake2b": "^1.0.1", - "@stablelib/ed25519": "^1.0.3", - "@taquito/core": "^17.5.2", - "@types/bs58check": "^2.1.0", + "json-stringify-safe": "^5.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@taquito/tzip16/node_modules/@taquito/http-utils": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/http-utils/-/http-utils-19.2.0.tgz", + "integrity": "sha512-iju4dYCEVpJ7x6HyIDbH58VvpMTkLqmGMgSlmkjQSPblCO6cTRlubepe4QPJ/ZKyVo1+4KUa8CBqZ9CDMRXOIA==", + "dependencies": { + "@taquito/core": "^19.1.0", + "node-fetch": "^2.7.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@taquito/tzip16/node_modules/@taquito/michelson-encoder": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/michelson-encoder/-/michelson-encoder-19.2.0.tgz", + "integrity": "sha512-yJZxc5H0WSI3rNQi1/GctfEKEUIGnIp67RJT63FYgxfAbBmhXdR6zsEUfAG8NUQ9BShMWY+uos0yHN3GKMRYFg==", + "dependencies": { + "@taquito/core": "^19.1.0", + "@taquito/rpc": "^19.2.0", + "@taquito/utils": "^19.2.0", "bignumber.js": "^9.1.2", - "blakejs": "^1.2.1", - "bs58check": "^3.0.1", - "buffer": "^6.0.3", - "elliptic": "^6.5.4", - "typedarray-to-buffer": "^4.0.0" + "fast-json-stable-stringify": "^2.1.0" }, "engines": { "node": ">=18" } }, "node_modules/@taquito/utils": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-19.1.0.tgz", - "integrity": "sha512-vgEUWBb1n1PY8XpFqLJ2Axdlo/lNoIqNTeAyVHN7yxxqyVghSoMeWVsfbCJ661GJ32R1NNo4XAJrzwMR+B7soA==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-19.2.0.tgz", + "integrity": "sha512-7KfcCpkXmdaQs3A3ZuMfBTy8jrbExlil4zXeP5iKvJ2aKuW4/JfWYmVF72GwR68omr2YvD/qSrpu9D7bUB3joQ==", "dependencies": { "@stablelib/blake2b": "^1.0.1", "@stablelib/ed25519": "^1.0.3", @@ -4262,27 +4303,6 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, - "node_modules/@walletconnect/core": { - "version": "2.7.0", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/heartbeat": "1.2.1", - "@walletconnect/jsonrpc-provider": "^1.0.12", - "@walletconnect/jsonrpc-utils": "^1.0.7", - "@walletconnect/jsonrpc-ws-connection": "^1.0.11", - "@walletconnect/keyvaluestorage": "^1.0.2", - "@walletconnect/logger": "^2.0.1", - "@walletconnect/relay-api": "^1.0.9", - "@walletconnect/relay-auth": "^1.0.4", - "@walletconnect/safe-json": "^1.0.2", - "@walletconnect/time": "^1.0.2", - "@walletconnect/types": "2.7.0", - "@walletconnect/utils": "2.7.0", - "events": "^3.3.0", - "lodash.isequal": "4.5.0", - "uint8arrays": "^3.1.0" - } - }, "node_modules/@walletconnect/environment": { "version": "1.0.1", "license": "MIT", @@ -4397,21 +4417,6 @@ "tslib": "1.14.1" } }, - "node_modules/@walletconnect/sign-client": { - "version": "2.7.0", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/core": "2.7.0", - "@walletconnect/events": "^1.0.1", - "@walletconnect/heartbeat": "1.2.1", - "@walletconnect/jsonrpc-utils": "^1.0.7", - "@walletconnect/logger": "^2.0.1", - "@walletconnect/time": "^1.0.2", - "@walletconnect/types": "2.7.0", - "@walletconnect/utils": "2.7.0", - "events": "^3.3.0" - } - }, "node_modules/@walletconnect/time": { "version": "1.0.2", "license": "MIT", @@ -4419,39 +4424,6 @@ "tslib": "1.14.1" } }, - "node_modules/@walletconnect/types": { - "version": "2.7.0", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/events": "^1.0.1", - "@walletconnect/heartbeat": "1.2.1", - "@walletconnect/jsonrpc-types": "^1.0.2", - "@walletconnect/keyvaluestorage": "^1.0.2", - "@walletconnect/logger": "^2.0.1", - "events": "^3.3.0" - } - }, - "node_modules/@walletconnect/utils": { - "version": "2.7.0", - "license": "Apache-2.0", - "dependencies": { - "@stablelib/chacha20poly1305": "1.0.1", - "@stablelib/hkdf": "1.0.1", - "@stablelib/random": "^1.0.2", - "@stablelib/sha256": "1.0.1", - "@stablelib/x25519": "^1.0.3", - "@walletconnect/jsonrpc-utils": "^1.0.7", - "@walletconnect/relay-api": "^1.0.9", - "@walletconnect/safe-json": "^1.0.2", - "@walletconnect/time": "^1.0.2", - "@walletconnect/types": "2.7.0", - "@walletconnect/window-getters": "^1.0.1", - "@walletconnect/window-metadata": "^1.0.1", - "detect-browser": "5.3.0", - "query-string": "7.1.1", - "uint8arrays": "^3.1.0" - } - }, "node_modules/@walletconnect/window-getters": { "version": "1.0.1", "license": "MIT", @@ -5369,7 +5341,8 @@ }, "node_modules/crypto-js": { "version": "4.2.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" }, "node_modules/css.escape": { "version": "1.5.1", @@ -9170,22 +9143,6 @@ "qrcode-svg": "bin/qrcode-svg.js" } }, - "node_modules/query-string": { - "version": "7.1.1", - "license": "MIT", - "dependencies": { - "decode-uri-component": "^0.2.0", - "filter-obj": "^1.1.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", diff --git a/package.json b/package.json index 6da7fab6..9e5068e0 100644 --- a/package.json +++ b/package.json @@ -20,18 +20,19 @@ "**/*": "prettier --write --ignore-unknown pages/ components/ context/ types/ versioned/ utils/" }, "dependencies": { - "@airgap/beacon-sdk": "^4.1.3-beta.1", + "@airgap/beacon-sdk": "^4.2.1", "@ariakit/react": "^0.1.8", "@radix-ui/react-icons": "^1.1.1", "@radix-ui/react-select": "^1.2.0", "@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-tooltip": "^1.0.3", "@stablelib/blake2b": "^1.0.1", - "@taquito/beacon-wallet": "^17.2.0", - "@taquito/taquito": "^17.2.0", - "@taquito/tzip12": "^17.5.2", - "@taquito/tzip16": "^17.2.0", - "@taquito/utils": "^19.1.0", + "@taquito/beacon-wallet": "^19.2.0", + "@taquito/rpc": "^19.2.0", + "@taquito/taquito": "^19.2.0", + "@taquito/tzip12": "^19.2.0", + "@taquito/tzip16": "^19.2.0", + "@taquito/utils": "^19.2.0", "@types/node": "18.11.9", "@types/react": "18.0.25", "@types/react-dom": "18.0.9", diff --git a/pages/[walletAddress]/beacon.tsx b/pages/[walletAddress]/beacon.tsx index 42cad593..e56f2889 100644 --- a/pages/[walletAddress]/beacon.tsx +++ b/pages/[walletAddress]/beacon.tsx @@ -3,13 +3,13 @@ import { Cross1Icon } from "@radix-ui/react-icons"; import bs58check from "bs58check"; import { useSearchParams } from "next/navigation"; import { useRouter } from "next/router"; -import { useContext, useEffect, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import Spinner from "../../components/Spinner"; import renderError from "../../components/formUtils"; import Meta from "../../components/meta"; import { Event } from "../../context/P2PClient"; import { MODAL_TIMEOUT } from "../../context/config"; -import { AppDispatchContext, AppStateContext } from "../../context/state"; +import { useAppDispatch, useAppState } from "../../context/state"; import useIsOwner from "../../utils/useIsOwner"; import { p2pData } from "../../versioned/interface"; import { hasTzip27Support } from "../../versioned/util"; @@ -38,8 +38,8 @@ export function decodeData(data: string): p2pData { } const Beacon = () => { - const state = useContext(AppStateContext)!; - const dispatch = useContext(AppDispatchContext)!; + const state = useAppState(); + const dispatch = useAppDispatch(); const router = useRouter(); const isOwner = useIsOwner(); diff --git a/pages/[walletAddress]/dashboard.tsx b/pages/[walletAddress]/dashboard.tsx index 8b0ba3ad..dc4ebe38 100644 --- a/pages/[walletAddress]/dashboard.tsx +++ b/pages/[walletAddress]/dashboard.tsx @@ -1,7 +1,6 @@ -import { useContext } from "react"; import Dashboard from "../../components/dashboard"; import Meta from "../../components/meta"; -import { AppStateContext } from "../../context/state"; +import { useAppState } from "../../context/state"; import { useTzktBalance, useTzktDefiTokens, @@ -9,7 +8,7 @@ import { } from "../../utils/tzktHooks"; const DashboardPage = () => { - const state = useContext(AppStateContext)!; + const state = useAppState(); const address = state.currentContract; // Get balance diff --git a/pages/[walletAddress]/fund-wallet.tsx b/pages/[walletAddress]/fund-wallet.tsx index db4dbe4d..da973587 100644 --- a/pages/[walletAddress]/fund-wallet.tsx +++ b/pages/[walletAddress]/fund-wallet.tsx @@ -4,18 +4,22 @@ import { useRouter } from "next/router"; import { useContext, useEffect, useRef, useState } from "react"; import Alias from "../../components/Alias"; import Spinner from "../../components/Spinner"; -import renderError, { renderWarning } from "../../components/formUtils"; +import { renderWarning } from "../../components/formUtils"; import Meta from "../../components/meta"; import TopUp from "../../components/topUpForm"; -import { TZKT_API_URL, PREFERED_NETWORK } from "../../context/config"; -import { AppDispatchContext, AppStateContext } from "../../context/state"; +import { TZKT_API_URL } from "../../context/config"; +import { useAppDispatch, useAppState } from "../../context/state"; +import { TezosToolkitContext } from "../../context/tezos-toolkit"; +import { useWallet } from "../../context/wallet"; import { makeWertWidget } from "../../context/wert"; import { mutezToTez } from "../../utils/tez"; import { signers } from "../../versioned/apis"; const TopUpPage = () => { - const state = useContext(AppStateContext)!; - const disptach = useContext(AppDispatchContext)!; + const state = useAppState(); + const disptach = useAppDispatch(); + const { userAddress } = useWallet(); + const { tezos } = useContext(TezosToolkitContext); const router = useRouter(); const [error, setError] = useState(); const [isLoading, setIsLoading] = useState(false); @@ -43,7 +47,7 @@ const TopUpPage = () => { } try { - const sent = await state.connection.wallet + const sent = await tezos.wallet .transfer({ to: state.currentContract, amount }) .send(); @@ -68,16 +72,16 @@ const TopUpPage = () => { const wertWidgetRef = useRef( makeWertWidget({ - wallet: state.address ?? "", + wallet: userAddress ?? "", onSuccess, }) ); useEffect(() => { - if (!state.currentContract || !state.address) return; + if (!state.currentContract || !userAddress) return; wertWidgetRef.current = makeWertWidget({ - wallet: state.address ?? "", + wallet: userAddress ?? "", onSuccess, }); }, [state.currentContract]); @@ -86,8 +90,7 @@ const TopUpPage = () => { if ( !router.query.walletAddress || Array.isArray(router.query.walletAddress) || - !!state.address || - !state.attemptedInitialLogin + !!userAddress ) return; @@ -99,7 +102,7 @@ const TopUpPage = () => { } router.replace(`/${router.query.walletAddress}/proposals`); - }, [router.query.walletAddress, state.address, state.attemptedInitialLogin]); + }, [router.query.walletAddress, userAddress]); return (
    @@ -116,7 +119,7 @@ const TopUpPage = () => { {!signers( state.contracts[state.currentContract ?? ""] ?? state.currentStorage - ).includes(state.address ?? "") && + ).includes(userAddress ?? "") && renderWarning("You're not the owner of this wallet")}
@@ -156,7 +159,7 @@ const TopUpPage = () => { ) : isSuccess ? ( Transferred the funds from{" "} - to{" "} + to{" "} {" "} ) : null} @@ -169,7 +172,7 @@ const TopUpPage = () => { ) : ( <>

- Send from + Send from

(!!og.resolver ? og.resolver.timestamp : og.proposer.timestamp); const History = () => { - const globalState = useContext(AppStateContext)!; - const globalDispatch = useContext(AppDispatchContext)!; + const globalState = useAppState(); + const globalDispatch = useAppDispatch(); + const { tezos } = useContext(TezosToolkitContext); const walletTokens = useWalletTokens(); const [state, dispatch] = useReducer(reducer, { @@ -202,13 +204,8 @@ const History = () => { (async () => { if (!globalState.currentContract) return; - const c = await globalState.connection.wallet.at( - globalState.currentContract, - tzip16 - ); - const balance = await globalState.connection.tz.getBalance( - globalState.currentContract - ); + const c = await tezos.wallet.at(globalState.currentContract, tzip16); + const balance = await tezos.tz.getBalance(globalState.currentContract); const storage = (await c.storage()) as contractStorage; diff --git a/pages/[walletAddress]/new-proposal.tsx b/pages/[walletAddress]/new-proposal.tsx index 77b95b63..d9f1cdd9 100644 --- a/pages/[walletAddress]/new-proposal.tsx +++ b/pages/[walletAddress]/new-proposal.tsx @@ -1,12 +1,12 @@ import { useRouter } from "next/router"; -import { useContext, useEffect } from "react"; +import { useEffect } from "react"; import Meta from "../../components/meta"; import TransferForm from "../../components/transferForm"; -import { AppStateContext } from "../../context/state"; +import { useAppState } from "../../context/state"; import useIsOwner from "../../utils/useIsOwner"; const CreateProposal = () => { - const state = useContext(AppStateContext)!; + const state = useAppState(); const router = useRouter(); const isOwner = useIsOwner(); diff --git a/pages/[walletAddress]/proposals.tsx b/pages/[walletAddress]/proposals.tsx index 19920c41..6f0398f5 100644 --- a/pages/[walletAddress]/proposals.tsx +++ b/pages/[walletAddress]/proposals.tsx @@ -1,3 +1,4 @@ +import { TezosToolkit } from "@taquito/taquito"; import { tzip16 } from "@taquito/tzip16"; import { validateContractAddress, ValidationResult } from "@taquito/utils"; import { Dispatch, useContext, useEffect, useReducer, useRef } from "react"; @@ -7,13 +8,15 @@ import Meta from "../../components/meta"; import Modal from "../../components/modal"; import ProposalSignForm from "../../components/proposalSignForm"; import { - AppDispatchContext, - AppStateContext, tezosState, action as globalAction, contractStorage, + useAppDispatch, + useAppState, } from "../../context/state"; +import { TezosToolkitContext } from "../../context/tezos-toolkit"; import fetchVersion from "../../context/version"; +import { useWallet } from "../../context/wallet"; import { proposal, version } from "../../types/display"; import { canExecute, canReject } from "../../utils/proposals"; import useIsOwner from "../../utils/useIsOwner"; @@ -139,14 +142,12 @@ async function getProposals( globalState: tezosState, globalDispatch: Dispatch, dispatch: Dispatch, - state: state + state: state, + tezos: TezosToolkit ) { if (!globalState.currentContract) return; - const c = await globalState.connection.wallet.at( - globalState.currentContract, - tzip16 - ); + const c = await tezos.wallet.at(globalState.currentContract, tzip16); const storage: contractStorage = await c.storage(); @@ -175,9 +176,7 @@ async function getProposals( }); if (globalState.contracts[globalState.currentContract ?? ""]) { - const balance = await globalState.connection.tz.getBalance( - globalState.currentContract - ); + const balance = await tezos.tz.getBalance(globalState.currentContract); globalDispatch({ type: "updateContract", @@ -192,11 +191,15 @@ async function getProposals( } const Proposals = () => { - const globalState = useContext(AppStateContext)!; - const globalDispatch = useContext(AppDispatchContext)!; + const globalState = useAppState(); + const globalDispatch = useAppDispatch(); const isOwner = useIsOwner(); const walletTokens = useWalletTokens(); + const { userAddress } = useWallet(); + + const { tezos } = useContext(TezosToolkitContext); + const [state, dispatch] = useReducer(reducer, { isLoading: true, isInvalid: false, @@ -248,7 +251,8 @@ const Proposals = () => { globalState, globalDispatch, dispatch, - state + state, + tezos ); if (!proposals) return; @@ -283,7 +287,8 @@ const Proposals = () => { globalState, globalDispatch, dispatch, - state + state, + tezos ); if (!proposals) return; @@ -401,7 +406,7 @@ const Proposals = () => { hasDeadlinePassed || isExecutable || isRejectable; const hasSigned = !!signatures.find( - x => x.signer == globalState.address + x => x.signer == userAddress ); return ( @@ -441,7 +446,7 @@ const Proposals = () => { proposer={x[1].og.proposer} resolver={x[1].og.resolver} isSignable={ - !!globalState.address && + !!userAddress && !!globalState.currentContract && isOwner && (!hasSigned || shouldResolve) diff --git a/pages/[walletAddress]/settings.tsx b/pages/[walletAddress]/settings.tsx index 4fb96640..c726efd1 100644 --- a/pages/[walletAddress]/settings.tsx +++ b/pages/[walletAddress]/settings.tsx @@ -1,15 +1,13 @@ -import { getSenderId } from "@airgap/beacon-sdk"; -import { Cross1Icon } from "@radix-ui/react-icons"; import { useRouter } from "next/router"; -import { useContext, useEffect, useMemo, useState } from "react"; +import { useEffect, useState } from "react"; import Meta from "../../components/meta"; import SignersForm from "../../components/signersForm"; -import { AppDispatchContext, AppStateContext } from "../../context/state"; +import { useAppDispatch, useAppState } from "../../context/state"; import useIsOwner from "../../utils/useIsOwner"; const Settings = () => { - const state = useContext(AppStateContext)!; - const dispatch = useContext(AppDispatchContext)!; + const state = useAppState(); + const dispatch = useAppDispatch(); const router = useRouter(); const isOwner = useIsOwner(); diff --git a/pages/_app.tsx b/pages/_app.tsx index 326049fa..6f00edac 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,291 +1,21 @@ -import { LocalStorage, NetworkType } from "@airgap/beacon-sdk"; -import { ArrowRightIcon } from "@radix-ui/react-icons"; -import { BeaconWallet } from "@taquito/beacon-wallet"; -import { validateAddress, ValidationResult } from "@taquito/utils"; import type { AppProps } from "next/app"; -import { usePathname } from "next/navigation"; -import { useRouter } from "next/router"; -import { useReducer, useEffect, useState } from "react"; -import Banner from "../components/Banner"; -import LoginModal from "../components/LoginModal"; -import PoeModal from "../components/PoeModal"; -import Sidebar from "../components/Sidebar"; -import Spinner from "../components/Spinner"; -import Footer from "../components/footer"; -import NavBar from "../components/navbar"; -import P2PClient from "../context/P2PClient"; +import Layout from "../components/Layout"; import { AliasesProvider } from "../context/aliases"; -import { PREFERED_NETWORK } from "../context/config"; -import { - tezosState, - action, - reducer, - emptyState, - init, - AppStateContext, - AppDispatchContext, - contractStorage, -} from "../context/state"; +import { AppStateProvider } from "../context/state"; +import { TezosToolkitProvider } from "../context/tezos-toolkit"; +import { WalletProvider } from "../context/wallet"; import "../styles/globals.css"; -import { fetchContract } from "../utils/fetchContract"; export default function App({ Component, pageProps }: AppProps) { - const [state, dispatch]: [tezosState, React.Dispatch] = useReducer( - reducer, - emptyState() - ); - - const [isFetching, setIsFetching] = useState(true); - const [hasSidebar, setHasSidebar] = useState(false); - const [data, setData] = useState(); - const path = usePathname(); - const router = useRouter(); - useEffect(() => { - if (!path) return; - - const queryParams = new URLSearchParams(window.location.search); - - const isPairing = queryParams.has("type") && queryParams.has("data"); - - if (isPairing) { - setData(queryParams.get("data")!); - } - - const contracts = Object.keys(state.contracts); - - if ((path === "/" || path === "") && contracts.length > 0) { - const contract = contracts[0]; - - router.replace(`/${contract}/dashboard`); - return; - } else if (path === "/" || path === "") { - // Get rid of query in case it comes from beacon - router.replace("/"); - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - state.currentContract, - path, - state.attemptedInitialLogin, - state.contracts, - ]); - - useEffect(() => { - (async () => { - if ( - router.pathname.includes("[walletAddress]") && - !router.query.walletAddress - ) - return; - - if ( - !router.query.walletAddress || - Array.isArray(router.query.walletAddress) || - (router.query.walletAddress === state.currentContract && - !!state.currentStorage) - ) { - setIsFetching(false); - return; - } - - if (!!state.contracts[router.query.walletAddress]) { - dispatch({ - type: "setCurrentContract", - payload: router.query.walletAddress, - }); - setIsFetching(false); - return; - } - - if ( - validateAddress(router.query.walletAddress) !== ValidationResult.VALID - ) { - setIsFetching(false); - router.replace( - `/invalid-contract?address=${router.query.walletAddress}` - ); - return; - } - - if (state.currentStorage?.address === router.query.walletAddress) { - setIsFetching(false); - return; - } - - try { - const storage = await fetchContract( - state.connection, - router.query.walletAddress - ); - - if (!storage) { - setIsFetching(false); - router.replace( - `/invalid-contract?address=${router.query.walletAddress}` - ); - return; - } - - storage.address = router.query.walletAddress; - - dispatch({ - type: "setCurrentStorage", - payload: storage as contractStorage & { address: string }, - }); - - dispatch({ - type: "setCurrentContract", - payload: router.query.walletAddress, - }); - - setIsFetching(false); - } catch (e) { - setIsFetching(false); - - router.replace( - `/invalid-contract?address=${router.query.walletAddress}` - ); - } - })(); - }, [ - router.query.walletAddress, - state.currentContract, - dispatch, - router, - state.currentStorage, - state.connection, - state.contracts, - ]); - useEffect(() => { - (async () => { - if (state!.beaconWallet === null) { - let a = init(); - dispatch({ type: "init", payload: a }); - - const p2pClient = new P2PClient({ - name: "TzSafe", - storage: new LocalStorage("P2P"), - }); - - await p2pClient.init(); - await p2pClient.connect(p2pClient.handleMessages); - - // Connect stored peers - Object.entries(a.connectedDapps).forEach(async ([address, dapps]) => { - Object.values(dapps).forEach(data => { - p2pClient - .addPeer(data) - .catch(_ => console.log("Failed to connect to peer", data)); - }); - }); - - const wallet = new BeaconWallet({ - name: "TzSafe", - //@ts-expect-error NetworkType does not match with expected preferredNetwork type (types between Taquito and Beacon doesn't match) - preferredNetwork: PREFERED_NETWORK, - //@ts-expect-error Beacon beta and taquito's beacon are incompatible, but it's only a type error - storage: new LocalStorage("WALLET"), - }); - - dispatch!({ type: "beaconConnect", payload: wallet }); - dispatch!({ type: "p2pConnect", payload: p2pClient }); - - if (state.attemptedInitialLogin) return; - - const activeAccount = await wallet.client.getActiveAccount(); - if (activeAccount && state?.accountInfo == null) { - const userAddress = await wallet.getPKH(); - const balance = await state?.connection.tz.getBalance(userAddress); - dispatch({ - type: "login", - // TODO: FIX - //@ts-ignore - accountInfo: activeAccount!, - address: userAddress, - balance: balance!.toString(), - }); - } else { - dispatch({ - type: "setAttemptedInitialLogin", - payload: true, - }); - } - } - })(); - }, [state.beaconWallet]); - - useEffect(() => { - setHasSidebar(false); - }, [path]); - - const isSidebarHidden = - Object.values(state.contracts).length === 0 && - (path === "/" || - path === "/new-wallet" || - path === "/import-wallet" || - path === "/address-book"); - return ( - - - -
- - - - + + + + + + + + + ); } diff --git a/pages/address-book.tsx b/pages/address-book.tsx index a483f2b8..bf2c053f 100644 --- a/pages/address-book.tsx +++ b/pages/address-book.tsx @@ -10,7 +10,12 @@ import { import { useContext } from "react"; import renderError from "../components/formUtils"; import Meta from "../components/meta"; -import { AppDispatchContext, AppStateContext } from "../context/state"; +import { + AppDispatchContext, + AppStateContext, + useAppDispatch, + useAppState, +} from "../context/state"; function get( s: string | FormikErrors<{ name: string; address: string }> @@ -26,8 +31,8 @@ function get( } } function Home() { - const state = useContext(AppStateContext)!; - const dispatch = useContext(AppDispatchContext)!; + const state = useAppState(); + const dispatch = useAppDispatch(); const byName = Object.fromEntries( Object.entries(state.aliases).map(([k, v]) => [v, k]) diff --git a/pages/new-wallet.tsx b/pages/new-wallet.tsx index aaadc30f..f7e2235f 100644 --- a/pages/new-wallet.tsx +++ b/pages/new-wallet.tsx @@ -1,31 +1,29 @@ import { useRouter } from "next/navigation"; -import { useContext, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import Step from "../components/create/createStep"; import Meta from "../components/meta"; import Stepper from "../components/stepper"; import FormContext from "../context/formContext"; -import { AppDispatchContext, AppStateContext } from "../context/state"; -import { connectWallet } from "../utils/connectWallet"; +import { useWallet } from "../context/wallet"; function Create() { const [formState, setFormState] = useState(null); const [activeStepIndex, setActiveStepIndex] = useState(0); const [formStatus, setFormStatus] = useState(""); - const state = useContext(AppStateContext)!; - const dispatch = useContext(AppDispatchContext)!; - let router = useRouter(); + const router = useRouter(); + const { userAddress, wallet, connectWallet } = useWallet(); useEffect(() => { (async () => { - if (!state?.address && state?.beaconWallet) { + if (!userAddress && wallet) { try { - await connectWallet(state, dispatch); + await connectWallet(); } catch (e) { router.replace("/"); } } })(); - }, [router, dispatch, state]); + }, [router, connectWallet, userAddress, wallet]); return (
diff --git a/tests/e2eTest/v0.1.1.ts b/tests/e2eTest/v0.1.1.ts index 606039c2..da3abb43 100644 --- a/tests/e2eTest/v0.1.1.ts +++ b/tests/e2eTest/v0.1.1.ts @@ -1,5 +1,5 @@ import { MichelsonMap, TezosToolkit } from "@taquito/taquito"; -import { char2Bytes } from "@taquito/tzip16"; +import { stringToBytes } from "@taquito/tzip16"; import BigNumber from "bignumber.js"; import { describe, expect, it, beforeAll } from "vitest"; import { proposal } from "../../types/Proposal0_1_1"; @@ -39,7 +39,7 @@ const test_suit = (setTezosToolkit: (tezos: TezosToolkit) => TezosToolkit) => expect(storage.proposal_counter.isEqualTo(BigNumber(0))).toBe(true); expect(storage.owners).toEqual([owner]); storage.metadata.get("").then((value: string) => { - expect(value).toEqual(char2Bytes(ipfs_file)); + expect(value).toEqual(stringToBytes(ipfs_file)); }); }, { timeout: tenMins } diff --git a/tests/e2eTest/v0.3.3.ts b/tests/e2eTest/v0.3.3.ts index 99e4ce8f..73f5d7a2 100644 --- a/tests/e2eTest/v0.3.3.ts +++ b/tests/e2eTest/v0.3.3.ts @@ -1,5 +1,5 @@ import { MichelsonMap, TezosToolkit } from "@taquito/taquito"; -import { char2Bytes } from "@taquito/tzip16"; +import { stringToBytes } from "@taquito/tzip16"; import BigNumber from "bignumber.js"; import { describe, expect, it, beforeAll } from "vitest"; import { proposal } from "../../types/Proposal0_3_3"; @@ -39,7 +39,7 @@ const test_suit = (setTezosToolkit: (tezos: TezosToolkit) => TezosToolkit) => expect(storage.proposal_counter.isEqualTo(BigNumber(0))).toBe(true); expect(storage.owners).toEqual([owner]); storage.metadata.get("").then((value: string) => { - expect(value).toEqual(char2Bytes(ipfs_file)); + expect(value).toEqual(stringToBytes(ipfs_file)); }); }, { timeout: tenMins } diff --git a/tests/e2eTest/v0.3.4.ts b/tests/e2eTest/v0.3.4.ts index f29c8bcf..8b64d651 100644 --- a/tests/e2eTest/v0.3.4.ts +++ b/tests/e2eTest/v0.3.4.ts @@ -1,5 +1,5 @@ import { MichelsonMap, TezosToolkit } from "@taquito/taquito"; -import { char2Bytes } from "@taquito/tzip16"; +import { stringToBytes } from "@taquito/tzip16"; import BigNumber from "bignumber.js"; import { describe, expect, it, beforeAll } from "vitest"; import { proposal } from "../../types/Proposal0_3_4"; @@ -39,7 +39,7 @@ const test_suit = (setTezosToolkit: (tezos: TezosToolkit) => TezosToolkit) => expect(storage.proposal_counter.isEqualTo(BigNumber(0))).toBe(true); expect(storage.owners).toEqual([owner]); storage.metadata.get("").then((value: string) => { - expect(value).toEqual(char2Bytes(ipfs_file)); + expect(value).toEqual(stringToBytes(ipfs_file)); }); }, { timeout: tenMins } diff --git a/utils/connectWallet.ts b/utils/connectWallet.ts deleted file mode 100644 index c39e8116..00000000 --- a/utils/connectWallet.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Dispatch } from "react"; -import { PREFERED_NETWORK, RPC_URL } from "../context/config"; -import { action, tezosState } from "../context/state"; - -export const connectWallet = async ( - state: tezosState, - dispatch: Dispatch -): Promise => { - if (!state.beaconWallet) return; - - await state?.beaconWallet!.requestPermissions({ - network: { - //@ts-expect-error NetworkType does not match with expected preferredNetwork type (types between Taquito and Beacon doesn't match) - type: PREFERED_NETWORK, - rpcUrl: RPC_URL, - }, - }); - - const userAddress: string = await state?.beaconWallet!.getPKH()!; - const balance = await state?.connection.tz.getBalance(userAddress); - let s = await state?.beaconWallet!.client.getActiveAccount(); - dispatch!({ - type: "login", - // TODO: Fix - // @ts-ignore - accountInfo: s!, - address: userAddress, - balance: balance!.toString(), - }); -}; diff --git a/utils/useIsOwner.ts b/utils/useIsOwner.ts index 1e010398..333d801b 100644 --- a/utils/useIsOwner.ts +++ b/utils/useIsOwner.ts @@ -1,24 +1,21 @@ -import { useContext, useMemo } from "react"; -import { AppStateContext } from "../context/state"; +import { useMemo } from "react"; +import { useAppState } from "../context/state"; +import { useWallet } from "../context/wallet"; import { signers } from "../versioned/apis"; const useIsOwner = () => { - let state = useContext(AppStateContext)!; + let state = useAppState(); + const { userAddress } = useWallet(); const isOwner = useMemo( () => - !!state.address && + !!userAddress && (state.contracts[state.currentContract ?? ""]?.owners?.includes( - state.address + userAddress ) ?? (!!state.currentStorage && - signers(state.currentStorage).includes(state.address!))), - [ - state.currentContract, - state.address, - state.contracts, - state.currentStorage, - ] + signers(state.currentStorage).includes(userAddress!))), + [state.currentContract, userAddress, state.contracts, state.currentStorage] ); return isOwner; diff --git a/utils/useWalletTokens.ts b/utils/useWalletTokens.ts index 7325a3fc..231b5ffe 100644 --- a/utils/useWalletTokens.ts +++ b/utils/useWalletTokens.ts @@ -1,13 +1,13 @@ -import { useContext, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { fa1_2Token } from "../components/FA1_2"; import { fa2Token } from "../components/FA2Transfer"; import { TZKT_API_URL } from "../context/config"; -import { AppStateContext } from "../context/state"; +import { useAppState } from "../context/state"; export type walletToken = fa1_2Token | fa2Token; const useWalletTokens = () => { - const state = useContext(AppStateContext)!; + const state = useAppState(); const [tokens, setTokens] = useState(); useEffect(() => { diff --git a/versioned/version0_3_3.ts b/versioned/version0_3_3.ts index 1961f7d6..29af0889 100644 --- a/versioned/version0_3_3.ts +++ b/versioned/version0_3_3.ts @@ -6,7 +6,7 @@ import { WalletContract, WalletOperationBatch, } from "@taquito/taquito"; -import { char2Bytes, bytes2Char } from "@taquito/utils"; +import { stringToBytes, bytesToString } from "@taquito/utils"; import { BigNumber } from "bignumber.js"; import { fa1_2Token } from "../components/FA1_2"; import { fa2Token } from "../components/FA2Transfer"; @@ -210,7 +210,7 @@ class Version0_3_3 extends Versioned { const metadata = content.execute_lambda.metadata; const meta = !!metadata - ? bytes2Char(typeof metadata === "string" ? metadata : metadata.Some) + ? bytesToString(typeof metadata === "string" ? metadata : metadata.Some) : "No meta supplied"; const lambda = Array.isArray(contentLambda) @@ -295,7 +295,7 @@ class Version0_3_3 extends Versioned { transfer.values.lambda ); let meta = !!transfer.values.metadata - ? char2Bytes(transfer.values.metadata) + ? stringToBytes(transfer.values.metadata) : null; return { execute_lambda: { @@ -401,7 +401,7 @@ class Version0_3_3 extends Versioned { return { add_or_update_metadata: { key: "", - value: char2Bytes(transfer.values.tzip16_metadata), + value: stringToBytes(transfer.values.tzip16_metadata), }, }; } diff --git a/versioned/version0_3_4.ts b/versioned/version0_3_4.ts index 0f4de60a..1a75995f 100644 --- a/versioned/version0_3_4.ts +++ b/versioned/version0_3_4.ts @@ -21,7 +21,9 @@ class Version0_3_4 extends Version0_3_3 { const encodedPayload = stringToBytes(payload); const ops = [ - cc.methods.proof_of_event_challenge(encodedPayload).toTransferParams(), + cc.methodsObject + .proof_of_event_challenge(encodedPayload) + .toTransferParams(), cc.methodsObject .sign_proposal({ agreement: true,