/ src / auth / hooks / useAuth.ts
useAuth.ts
  1  import { useCallback, useEffect, useState } from "react";
  2  import { Actor, ActorSubclass, HttpAgent, Identity } from "@dfinity/agent"
  3  import { AuthClient } from "@dfinity/auth-client";
  4  import { CkBTCMinterCanister } from "@dfinity/ckbtc";
  5  import { Principal } from "@dfinity/principal";
  6  import { IcrcLedgerCanister, IcrcTokenMetadataResponse } from "@dfinity/ledger-icrc";
  7  import {
  8      idlFactory as repositoryIdl
  9  } from "../../declarations/repository";
 10  import { _SERVICE as _REPOSITORY_SERVICE } from "@/declarations/repository/repository.did";
 11  
 12  
 13  interface AuthHooks {
 14    isAuthenticating: boolean;
 15    authClient: AuthClient | null;
 16    isAuthenticated: boolean;
 17    identity: Identity | Promise<Identity> | undefined;
 18    principal: string | undefined;
 19    agent: HttpAgent | undefined;
 20    hasLoggedIn: boolean;
 21    repositoryActor: ActorSubclass<_REPOSITORY_SERVICE | null>
 22    login: () => Promise<void>;
 23    logout: () => void;
 24    minterActor: CkBTCMinterCanister | undefined;
 25    btcAddress: string | undefined;
 26    ledgerActor: IcrcLedgerCanister | undefined;
 27    metadata: IcrcTokenMetadataResponse  | undefined;
 28    balance: bigint | null | undefined;
 29  }
 30      
 31  
 32  const useAuth = (): AuthHooks => {
 33    const [isAuthenticating, setIsAuthenticating] = useState<boolean>(false);
 34    const [authClient, setAuthClient] = useState<AuthClient | null>(null);
 35    const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
 36    const [identity, setIdentity] = useState<Identity | Promise<Identity> | undefined>();
 37    const [principal, setPrincipal] = useState<string | undefined>();
 38    const [hasLoggedIn, setHasLoggedIn] = useState<boolean>(false);
 39    const [repositoryActor, setRepositoryActor] = useState(null);
 40    const [walletPrincipal, setWalletPrincipal] = useState(null);
 41    const [walletCanister, setWalletCanister] = useState(null);
 42    const [minterActor, setMinterActor] = useState<CkBTCMinterCanister | undefined>();
 43    const [btcAddress, setBtcAddress] = useState<string | undefined>();
 44    const [ledgerActor, setLedgerActor] = useState<IcrcLedgerCanister | undefined>();
 45    const [metadata, setMetadata] = useState<IcrcTokenMetadataResponse  | undefined>();
 46    const [balance, setBalance] = useState<bigint | null | undefined>();
 47    const network = process.env.DFX_NETWORK || "local";
 48    const host = "https://icp0.io";
 49    const localhost = "http://localhost:4943";
 50    const repositoryCanisterId = process.env.CANISTER_ID_REPOSITORY;
 51    const minterCanisterId = process.env.MY_CKBTC_MINTER_CANISTER_ID;
 52    const ledgerCanisterId = process.env.MY_LEDGER_CANISTER_ID;
 53  
 54    const login = useCallback(async () => {
 55      const alreadyAuthenticated = await authClient?.isAuthenticated()
 56      console.log("alreadyAuthenticated: ", alreadyAuthenticated);
 57  
 58      if (alreadyAuthenticated) {
 59        setIsAuthenticated(true);
 60        setHasLoggedIn(true);
 61      } else {
 62        setIsAuthenticating(true)
 63  
 64        authClient?.login({
 65          identityProvider: process.env.DFX_NETWORK === "ic"
 66          ? "https://identity.ic0.app/#authorize"
 67          : "http://localhost:4943?canisterId=bkyz2-fmaaa-aaaaa-qaaaq-cai",
 68          onSuccess: async () => {
 69            setIsAuthenticating(false);
 70            setIsAuthenticated(true);
 71            setHasLoggedIn(true);
 72  
 73          }
 74        })
 75      }
 76  
 77    },[authClient]);
 78  
 79    const logout = () => {
 80      setIsAuthenticated(false);
 81  
 82      authClient?.logout({ returnTo: "/home_page" });
 83    };
 84  
 85   
 86    let agent: HttpAgent | undefined;
 87    const createAgent = () => {
 88      agent = new HttpAgent({
 89        host: network === "local" ? localhost : host,
 90        identity: identity,
 91      });
 92    
 93      console.log("Agent: ", agent);
 94    
 95      if (network === "local") {
 96          agent.fetchRootKey();
 97      }
 98    }
 99  
100    const createRepositoryActor = async () => {
101      console.log("Repository canister id: ", repositoryCanisterId);
102      const repositoryActor = Actor.createActor(repositoryIdl, {
103          agent,
104          canisterId: Principal.fromText(repositoryCanisterId),
105      });
106      console.log("Repository canister: ", repositoryActor);
107      setRepositoryActor(repositoryActor);
108    }
109  
110    const createMinterActor = async () => {
111      console.log("Minter canister Id: ", minterCanisterId);
112      if(!identity || !agent) return;
113      const minterActor = CkBTCMinterCanister.create({
114        agent,
115        canisterId: Principal.fromText(minterCanisterId),
116      });
117      console.log("Minter actor: ", minterActor);
118      setMinterActor(minterActor);
119      if(minterActor) {
120        getBtcAddress();
121      }
122    };
123  
124    const getBtcAddress = async () => {
125      if(!minterActor || !identity) return;
126      try {
127        const btcAddress = await minterActor?.getBtcAddress({});
128        setBtcAddress(btcAddress);
129        console.log("Send Btc to this address to get ckBtc: ", btcAddress);
130      } catch(error) {
131        console.log("There was an issue with fetching the Btc address: ", error);
132      }
133    };
134  
135    const createLedgerActor = async () => {
136      console.log("Ledger canister Id: ", ledgerCanisterId);
137      if(identity && agent ) {
138        const ledgerActor = IcrcLedgerCanister.create({
139          agent, 
140          canisterId: Principal.fromText(ledgerCanisterId),
141        })
142        console.log("Ledger actor: ", ledgerActor);
143        setLedgerActor(ledgerActor);
144        await getMetadata();
145        getBalance();
146      } else {
147        console.log("Idetity or agent not initialized");
148      }
149      
150    }
151  
152    const getMetadata = async ()=> {
153      if(ledgerActor) {
154        try {
155          const res = await ledgerActor?.metadata({ certified: false })
156          console.log("Meta data: ", res)
157          setMetadata(res);
158        } catch(error) {
159          console.log("There was an isue with fethcing the metadata: ", error);
160        }
161        
162      } else {
163        console.log("Ledger actor not initialized");
164      }
165    };
166  
167    const getBalance = async () => {
168      if(ledgerActor && principal ) {
169        const ownerPrincipal = Principal.fromText(principal);
170        console.log("Owner principal: ", ownerPrincipal);
171        try { 
172          const res = await ledgerActor?.balance({
173          owner: ownerPrincipal,
174          certified: false,
175        });
176        setBalance(res);
177        } catch(error) {
178          console.log("There was an issue fethcing the balance: ", error);
179        }
180      } else {
181        console.log("Make sure ledgerActor and principal are intitialized first");
182      }
183    }
184  
185    useEffect(() => {
186      if (authClient == null) {
187        setIsAuthenticating(true);
188  
189        AuthClient.create().then(async (client) => {
190          await client?.isAuthenticated();
191          setIsAuthenticating(false);
192          setAuthClient(client);
193        });
194      }
195    }, [authClient]);
196  
197    useEffect(() => {
198      if (authClient && login != null) {
199        (async () => {
200          const authenticated = await authClient?.isAuthenticated();
201          console.log("Authenticated: ", authenticated);
202          if (authenticated) {
203            setIsAuthenticated(true);
204          }
205        })();
206      }
207    }, [authClient]);
208  
209    useEffect(() => {
210      if (isAuthenticated) {
211        const identity = authClient.getIdentity();
212        setIdentity(identity);
213        const principal = identity.getPrincipal().toString();
214        setPrincipal(principal);
215  
216        console.log("Identity: ", identity);
217        console.log("Principal: ", principal);
218  
219        createAgent()
220        createRepositoryActor();
221        createMinterActor();
222        createLedgerActor();
223      }
224    }, [isAuthenticated]);
225  
226    return {
227      authClient,
228      isAuthenticated,
229      hasLoggedIn,
230      isAuthenticating,
231      login,
232      logout,
233      identity,
234      principal,
235      agent, 
236      repositoryActor, 
237      minterActor, 
238      btcAddress,
239      ledgerActor, 
240      metadata,
241      balance,
242    };
243  };
244  
245  export default useAuth;