diff options
Diffstat (limited to 'client/src/components')
-rw-r--r-- | client/src/components/ConnectWallet.tsx | 137 | ||||
-rw-r--r-- | client/src/components/DisconnectWallet.tsx | 50 | ||||
-rw-r--r-- | client/src/components/Records.tsx | 49 | ||||
-rw-r--r-- | client/src/components/Transfers.tsx | 70 |
4 files changed, 306 insertions, 0 deletions
diff --git a/client/src/components/ConnectWallet.tsx b/client/src/components/ConnectWallet.tsx new file mode 100644 index 0000000..3a293c0 --- /dev/null +++ b/client/src/components/ConnectWallet.tsx @@ -0,0 +1,137 @@ +import React, { Dispatch, SetStateAction, useState, useEffect } from "react"; +import { TezosToolkit } from "@taquito/taquito"; +import { BeaconWallet } from "@taquito/beacon-wallet"; +import { + NetworkType, + BeaconEvent, + defaultEventCallbacks +} from "@airgap/beacon-sdk"; +import TransportU2F from "@ledgerhq/hw-transport-u2f"; +import { LedgerSigner } from "@taquito/ledger-signer"; + +type ButtonProps = { + Tezos: TezosToolkit; + setContract: Dispatch<SetStateAction<any>>; + setWallet: Dispatch<SetStateAction<any>>; + setUserAddress: Dispatch<SetStateAction<string>>; + setUserBalance: Dispatch<SetStateAction<number>>; + setStorage: Dispatch<SetStateAction<number>>; + contractAddress: string; + setBeaconConnection: Dispatch<SetStateAction<boolean>>; + setPublicToken: Dispatch<SetStateAction<string | null>>; + wallet: BeaconWallet; +}; + +const ConnectButton = ({ + Tezos, + setContract, + setWallet, + setUserAddress, + setUserBalance, + setStorage, + contractAddress, + setBeaconConnection, + setPublicToken, + wallet +}: ButtonProps): JSX.Element => { + const [loadingNano, setLoadingNano] = useState<boolean>(false); + + const setup = async (userAddress: string): Promise<void> => { + setUserAddress(userAddress); + // updates balance + const balance = await Tezos.tz.getBalance(userAddress); + setUserBalance(balance.toNumber()); + // creates contract instance + const contract = await Tezos.wallet.at(contractAddress); + const storage: any = await contract.storage(); + setContract(contract); + setStorage(storage); + }; + + const connectWallet = async (): Promise<void> => { + try { + await wallet.requestPermissions({ + network: { + type: NetworkType.GRANADANET, + rpcUrl: "https://api.tez.ie/rpc/granadanet" + } + }); + // gets user's address + const userAddress = await wallet.getPKH(); + await setup(userAddress); + setBeaconConnection(true); + } catch (error) { + console.log(error); + } + }; + + const connectNano = async (): Promise<void> => { + try { + setLoadingNano(true); + const transport = await TransportU2F.create(); + const ledgerSigner = new LedgerSigner(transport, "44'/1729'/0'/0'", true); + + Tezos.setSignerProvider(ledgerSigner); + + //Get the public key and the public key hash from the Ledger + const userAddress = await Tezos.signer.publicKeyHash(); + await setup(userAddress); + } catch (error) { + console.log("Error!", error); + setLoadingNano(false); + } + }; + + useEffect(() => { + (async () => { + // creates a wallet instance + const wallet = new BeaconWallet({ + name: "Taquito Boilerplate", + preferredNetwork: NetworkType.GRANADANET, + disableDefaultEvents: true, // Disable all events / UI. This also disables the pairing alert. + eventHandlers: { + // To keep the pairing alert, we have to add the following default event handlers back + [BeaconEvent.PAIR_INIT]: { + handler: defaultEventCallbacks.PAIR_INIT + }, + [BeaconEvent.PAIR_SUCCESS]: { + handler: data => setPublicToken(data.publicKey) + } + } + }); + Tezos.setWalletProvider(wallet); + setWallet(wallet); + // checks if wallet was connected before + const activeAccount = await wallet.client.getActiveAccount(); + if (activeAccount) { + const userAddress = await wallet.getPKH(); + await setup(userAddress); + setBeaconConnection(true); + } + })(); + }, []); + + return ( + <div className="buttons"> + <button className="button" onClick={connectWallet}> + <span> + <i className="fas fa-wallet"></i> Connect with wallet + </span> + </button> + <button className="button" disabled={loadingNano} onClick={connectNano}> + {loadingNano ? ( + <span> + <i className="fas fa-spinner fa-spin"></i> Loading, please + wait + </span> + ) : ( + <span> + <i className="fab fa-usb"></i> Connect with Ledger Nano + </span> + )} + </button> + </div> + ); +}; + +export default ConnectButton; diff --git a/client/src/components/DisconnectWallet.tsx b/client/src/components/DisconnectWallet.tsx new file mode 100644 index 0000000..45e6643 --- /dev/null +++ b/client/src/components/DisconnectWallet.tsx @@ -0,0 +1,50 @@ +import React, { Dispatch, SetStateAction } from "react"; +import { BeaconWallet } from "@taquito/beacon-wallet"; +import { TezosToolkit } from "@taquito/taquito"; + +interface ButtonProps { + wallet: BeaconWallet | null; + setPublicToken: Dispatch<SetStateAction<string | null>>; + setUserAddress: Dispatch<SetStateAction<string>>; + setUserBalance: Dispatch<SetStateAction<number>>; + setWallet: Dispatch<SetStateAction<any>>; + setTezos: Dispatch<SetStateAction<TezosToolkit>>; + setBeaconConnection: Dispatch<SetStateAction<boolean>>; +} + +const DisconnectButton = ({ + wallet, + setPublicToken, + setUserAddress, + setUserBalance, + setWallet, + setTezos, + setBeaconConnection +}: ButtonProps): JSX.Element => { + const disconnectWallet = async (): Promise<void> => { + //window.localStorage.clear(); + setUserAddress(""); + setUserBalance(0); + setWallet(null); + const tezosTK = new TezosToolkit("https://api.tez.ie/rpc/granadanet"); + setTezos(tezosTK); + setBeaconConnection(false); + setPublicToken(null); + console.log("disconnecting wallet"); + if (wallet) { + await wallet.client.removeAllAccounts(); + await wallet.client.removeAllPeers(); + await wallet.client.destroy(); + } + }; + + return ( + <div className="buttons"> + <button className="button" onClick={disconnectWallet}> + <i className="fas fa-times"></i> Disconnect wallet + </button> + </div> + ); +}; + +export default DisconnectButton; diff --git a/client/src/components/Records.tsx b/client/src/components/Records.tsx new file mode 100644 index 0000000..eec867d --- /dev/null +++ b/client/src/components/Records.tsx @@ -0,0 +1,49 @@ +import React, { useState, Dispatch, SetStateAction } from "react"; +import { ContractMethod, TezosToolkit, WalletContract } from "@taquito/taquito"; + +interface RecordsProps { + contract: WalletContract | any; + setUserBalance: Dispatch<SetStateAction<any>>; + Tezos: TezosToolkit; + userAddress: string; + setStorage: Dispatch<SetStateAction<number>>; +} + +const Records = ({ contract, setUserBalance, Tezos, userAddress, setStorage }: RecordsProps) => { + const [loadingIncrement, setLoadingIncrement] = useState<boolean>(false); + const [loadingDecrement, setLoadingDecrement] = useState<boolean>(false); + + const addRecord = async (): Promise<void> => { + setLoadingIncrement(true); + try { + const op = await contract.methods.default("tesds").send(); + await op.confirmation(); + const newStorage: any = await contract.storage(); + if (newStorage) setStorage(newStorage); + setUserBalance(await Tezos.tz.getBalance(userAddress)); + } catch (error) { + console.log(error); + } finally { + setLoadingIncrement(false); + } + }; + + if (!contract && !userAddress) return <div> </div>; + return ( + <div className="buttons"> + <button className="button" disabled={loadingIncrement} onClick={addRecord}> + {loadingIncrement ? ( + <span> + <i className="fas fa-spinner fa-spin"></i> Please wait + </span> + ) : ( + <span> + <i className="fas fa-plus"></i> Add Record + </span> + )} + </button> + </div> + ); +}; + +export default Records; diff --git a/client/src/components/Transfers.tsx b/client/src/components/Transfers.tsx new file mode 100644 index 0000000..3bd1e65 --- /dev/null +++ b/client/src/components/Transfers.tsx @@ -0,0 +1,70 @@ +import React, { useState, Dispatch, SetStateAction } from "react"; +import { TezosToolkit } from "@taquito/taquito"; + +const Transfers = ({ + Tezos, + setUserBalance, + userAddress +}: { + Tezos: TezosToolkit; + setUserBalance: Dispatch<SetStateAction<number>>; + userAddress: string; +}): JSX.Element => { + const [recipient, setRecipient] = useState<string>(""); + const [amount, setAmount] = useState<string>(""); + const [loading, setLoading] = useState<boolean>(false); + + const sendTransfer = async (): Promise<void> => { + if (recipient && amount) { + setLoading(true); + try { + const op = await Tezos.wallet + .transfer({ to: recipient, amount: parseInt(amount) }) + .send(); + await op.confirmation(); + setRecipient(""); + setAmount(""); + const balance = await Tezos.tz.getBalance(userAddress); + setUserBalance(balance.toNumber()); + } catch (error) { + console.log(error); + } finally { + setLoading(false); + } + } + }; + + return ( + <div id="transfer-inputs"> + <input + type="text" + placeholder="Recipient" + value={recipient} + onChange={e => setRecipient(e.target.value)} + /> + <input + type="number" + placeholder="Amount" + value={amount} + onChange={e => setAmount(e.target.value)} + /> + <button + className="button" + disabled={!recipient && !amount} + onClick={sendTransfer} + > + {loading ? ( + <span> + <i className="fas fa-spinner fa-spin"></i> Please wait + </span> + ) : ( + <span> + <i className="far fa-paper-plane"></i> Send + </span> + )} + </button> + </div> + ); +}; + +export default Transfers; |