-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- add wallet connect libraries - add wallet connect context provider - add new environment variables - integrate wallet connect with button - integrate wallet disconnet with button
- Loading branch information
Showing
15 changed files
with
582 additions
and
54 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. | ||
{ | ||
"pnpmShrinkwrapHash": "0ce1b55854da10cb6fa1b558bd64743d6c481cdc", | ||
"pnpmShrinkwrapHash": "48c1105dd2167eda84f82ddfcb54cf79f62d3577", | ||
"preferredVersionsHash": "bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletions
4
packages/apps/tools/src/components/Common/Layout/index.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
packages/apps/tools/src/components/Common/WalletConnectButton/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { Button } from '@kadena/react-ui'; | ||
|
||
import { useWalletConnectClient } from '@/context/connect-wallet-context'; | ||
import useTranslation from 'next-translate/useTranslation'; | ||
import React, { FC } from 'react'; | ||
|
||
const WalletConnectButton: FC = () => { | ||
const { connect, isInitializing, disconnect, session } = | ||
useWalletConnectClient(); | ||
const { t } = useTranslation(); | ||
|
||
const handleClick = async (): Promise<void> => { | ||
if (session) { | ||
await disconnect(); | ||
return; | ||
} | ||
|
||
await connect(); | ||
}; | ||
|
||
const buttonTitle = session | ||
? t('Disconnect your wallet') | ||
: t('Connect your wallet'); | ||
|
||
return ( | ||
<Button | ||
title={buttonTitle} | ||
color="positive" | ||
icon="Link" | ||
iconAlign="right" | ||
onClick={handleClick} | ||
disabled={isInitializing} | ||
loading={isInitializing} | ||
> | ||
{buttonTitle} | ||
</Button> | ||
); | ||
}; | ||
|
||
export default WalletConnectButton; |
18 changes: 0 additions & 18 deletions
18
packages/apps/tools/src/components/Global/WalletConnectButton/index.tsx
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
244 changes: 244 additions & 0 deletions
244
packages/apps/tools/src/context/connect-wallet-context.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,244 @@ | ||
import { env } from '@/utils/env'; | ||
import { WalletConnectModal } from '@walletconnect/modal'; | ||
import Client from '@walletconnect/sign-client'; | ||
import { PairingTypes, SessionTypes } from '@walletconnect/types'; | ||
import { getSdkError } from '@walletconnect/utils'; | ||
import React, { | ||
createContext, | ||
FC, | ||
ReactNode, | ||
useCallback, | ||
useContext, | ||
useEffect, | ||
useMemo, | ||
useState, | ||
} from 'react'; | ||
|
||
/** | ||
* Types | ||
*/ | ||
interface IWalletConnectClientContext { | ||
client: Client | undefined; | ||
session: SessionTypes.Struct | undefined; | ||
connect: (pairing?: { topic: string }) => Promise<void>; | ||
disconnect: () => Promise<void>; | ||
isInitializing: boolean; | ||
pairings: PairingTypes.Struct[]; | ||
accounts: string[] | undefined; | ||
} | ||
|
||
/** | ||
* Context | ||
*/ | ||
export const WalletConnectClientContext = | ||
createContext<IWalletConnectClientContext>({} as IWalletConnectClientContext); | ||
|
||
/** | ||
* walletConnectModal Config | ||
*/ | ||
// eslint-disable-next-line @kadena-dev/typedef-var | ||
const walletConnectModal = new WalletConnectModal({ | ||
projectId: env('WALLET_CONNECT_PROJECT_ID', ''), | ||
themeMode: 'light', | ||
}); | ||
|
||
interface IWalletConnectClientContextProviderProps { | ||
children: ReactNode; | ||
} | ||
/** | ||
* Provider | ||
*/ | ||
export const WalletConnectClientContextProvider: FC< | ||
IWalletConnectClientContextProviderProps | ||
> = ({ children }) => { | ||
const [client, setClient] = useState<Client>(); | ||
const [pairings, setPairings] = useState<PairingTypes.Struct[]>([]); | ||
const [session, setSession] = useState<SessionTypes.Struct>(); | ||
const [accounts, setAccounts] = useState<string[]>(); | ||
|
||
const [isInitializing, setIsInitializing] = useState(false); | ||
|
||
const reset = (): void => { | ||
setSession(undefined as unknown as SessionTypes.Struct); | ||
setAccounts(undefined as unknown as string[]); | ||
}; | ||
|
||
const onSessionConnected = useCallback( | ||
async (clientSession: SessionTypes.Struct) => { | ||
setSession(clientSession); | ||
setAccounts(clientSession?.namespaces?.kadena?.accounts); | ||
}, | ||
[], | ||
); | ||
|
||
const connect = useCallback( | ||
async (pairing?: { topic: string }) => { | ||
if (typeof client === 'undefined') { | ||
throw new Error('WalletConnect is not initialized'); | ||
} | ||
|
||
try { | ||
const { uri, approval } = await client.connect({ | ||
pairingTopic: pairing?.topic ?? '', | ||
|
||
requiredNamespaces: { | ||
kadena: { | ||
methods: [ | ||
'kadena_getAccounts_v1', | ||
'kadena_sign_v1', | ||
'kadena_quicksign_v1', | ||
], | ||
chains: [ | ||
'kadena:mainnet01', | ||
'kadena:testnet04', | ||
'kadena:development', | ||
], | ||
events: [], | ||
}, | ||
}, | ||
}); | ||
|
||
// Open QRCode modal if a URI was returned (i.e. we're not connecting an existing pairing). | ||
if (uri) { | ||
await walletConnectModal.openModal({ uri }); | ||
} | ||
|
||
const session = await approval(); | ||
await onSessionConnected(session); | ||
// Update known pairings after session is connected. | ||
setPairings(client.pairing.getAll({ active: true })); | ||
} catch (e) { | ||
console.error(e); | ||
// ignore rejection | ||
} finally { | ||
// close modal in case it was open | ||
walletConnectModal.closeModal(); | ||
} | ||
}, | ||
[client, onSessionConnected], | ||
); | ||
|
||
const disconnect = useCallback(async () => { | ||
if (typeof client === 'undefined') { | ||
throw new Error('WalletConnect is not initialized'); | ||
} | ||
if (typeof session === 'undefined') { | ||
throw new Error('Session is not connected'); | ||
} | ||
|
||
try { | ||
await client.disconnect({ | ||
topic: session.topic, | ||
reason: getSdkError('USER_DISCONNECTED'), | ||
}); | ||
} catch (error) { | ||
console.error('SignClient.disconnect failed:', error); | ||
} finally { | ||
// Reset app state after disconnect. | ||
reset(); | ||
} | ||
}, [client, session]); | ||
|
||
const subscribeToEvents = useCallback( | ||
async (signClient: Client) => { | ||
if (typeof signClient === 'undefined') { | ||
throw new Error('WalletConnect is not initialized'); | ||
} | ||
|
||
signClient.on('session_update', ({ topic, params }) => { | ||
const { namespaces } = params; | ||
const clientSession = signClient.session.get(topic); | ||
const updatedSession = { ...clientSession, namespaces }; | ||
onSessionConnected(updatedSession) | ||
.then(console.log) | ||
.catch(console.error); | ||
}); | ||
|
||
signClient.on('session_delete', () => { | ||
reset(); | ||
}); | ||
}, | ||
[onSessionConnected], | ||
); | ||
|
||
const checkPersistedState = useCallback( | ||
async (signClient: Client) => { | ||
if (typeof signClient === 'undefined') { | ||
throw new Error('WalletConnect is not initialized'); | ||
} | ||
// populates existing pairings to state | ||
setPairings(signClient.pairing.getAll({ active: true })); | ||
|
||
if (typeof session !== 'undefined') return; | ||
// populates (the last) existing session to state | ||
if (signClient.session.length) { | ||
const lastKeyIndex = signClient.session.keys.length - 1; | ||
const clientSession = signClient.session.get( | ||
signClient.session.keys[lastKeyIndex], | ||
); | ||
await onSessionConnected(clientSession); | ||
return clientSession; | ||
} | ||
}, | ||
[session, onSessionConnected], | ||
); | ||
|
||
const createClient = useCallback(async () => { | ||
try { | ||
setIsInitializing(true); | ||
|
||
const _client = await Client.init({ | ||
relayUrl: env('WALLET_CONNECT_RELAY_URL', ''), | ||
projectId: env('WALLET_CONNECT_PROJECT_ID', ''), | ||
}); | ||
|
||
setClient(_client); | ||
await subscribeToEvents(_client); | ||
await checkPersistedState(_client); | ||
// eslint-disable-next-line no-useless-catch | ||
} catch (err) { | ||
throw err; | ||
} finally { | ||
setIsInitializing(false); | ||
} | ||
}, [checkPersistedState, subscribeToEvents]); | ||
|
||
useEffect(() => { | ||
if (!client) { | ||
createClient().then(console.log).catch(console.error); | ||
} | ||
}, [client, createClient]); | ||
|
||
const value = useMemo( | ||
() => ({ | ||
pairings, | ||
isInitializing, | ||
accounts, | ||
client, | ||
session, | ||
connect, | ||
disconnect, | ||
}), | ||
[pairings, isInitializing, accounts, client, session, connect, disconnect], | ||
); | ||
|
||
return ( | ||
<WalletConnectClientContext.Provider | ||
value={{ | ||
...value, | ||
}} | ||
> | ||
{children} | ||
</WalletConnectClientContext.Provider> | ||
); | ||
}; | ||
|
||
export const useWalletConnectClient = (): IWalletConnectClientContext => { | ||
const context = useContext(WalletConnectClientContext); | ||
if (!context) { | ||
throw new Error( | ||
'useWalletConnectClient must be used within a WalletConnectClientContextProvider', | ||
); | ||
} | ||
return context; | ||
}; |
Oops, something went wrong.
e9ae531
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
tools – ./packages/apps/tools
tools.kadena.io
tools-kadena-js.vercel.app
kadena-js-transfer.vercel.app
tools-git-main-kadena-js.vercel.app