Skip to content

Commit 29d7b72

Browse files
authored
379 feat add methods to dappkit UI (#381)
1 parent eb3591b commit 29d7b72

File tree

22 files changed

+864
-251
lines changed

22 files changed

+864
-251
lines changed

.github/workflows/sonar-scan.yml

Lines changed: 0 additions & 27 deletions
This file was deleted.

examples/sample-angular-app/src/app/app.component.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,13 @@ <h2>Angular JS</h2>
1010
<button id="send-tx" (click)="sendTx()">Send TX</button>
1111
<div class="label">Typed Data</div>
1212
<button id="typed-data" (click)="signTypedData()">Sign Typed Data</button>
13-
</div>
13+
<button (click)="triggerNull()">
14+
Trigger connection with no signature
15+
</button>
16+
<button (click)="triggerSignTypedData()">
17+
Trigger connection with typed data
18+
</button>
19+
<button (click)="triggerCertificate()">
20+
Trigger connection with certificate
21+
</button>
22+
</div>

examples/sample-angular-app/src/app/app.component.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
// Angular modules
22
import { Component, CUSTOM_ELEMENTS_SCHEMA, type OnInit } from '@angular/core';
3-
import { DAppKitUI } from '@vechain/dapp-kit-ui';
3+
import { CertificateMessage, TypedDataMessage } from '@vechain/dapp-kit';
4+
import { DAppKitUI, DAppKitUIOptions } from '@vechain/dapp-kit-ui';
5+
6+
type OnConnectRequest = NonNullable<
7+
DAppKitUIOptions['v2Api']['onConnectRequest']
8+
>;
9+
type OnConnectResponse = NonNullable<
10+
DAppKitUIOptions['v2Api']['onConnectResponse']
11+
>;
412

513
@Component({
614
selector: 'app-root',
@@ -13,6 +21,9 @@ export class AppComponent implements OnInit {
1321
// NOTE Init ---------------------------------------------------------------------
1422
// -------------------------------------------------------------------------------
1523

24+
private onConnectRequest: OnConnectRequest = () => Promise.resolve(null);
25+
private onConnectResponse: OnConnectResponse = () => Promise.resolve();
26+
1627
public ngOnInit(): void {
1728
const walletConnectOptions = {
1829
projectId: 'a0b855ceaf109dbc8426479a4c3d38d8',
@@ -30,6 +41,8 @@ export class AppComponent implements OnInit {
3041
usePersistence: true,
3142
v2Api: {
3243
enabled: true,
44+
onConnectRequest: (...args) => this.onConnectRequest(...args),
45+
onConnectResponse: (...args) => this.onConnectResponse(...args),
3346
},
3447
});
3548

@@ -81,4 +94,42 @@ export class AppComponent implements OnInit {
8194
{ test: [{ name: 'test', type: 'address' }] },
8295
{ test: '0x435933c8064b4Ae76bE665428e0307eF2cCFBD68' },
8396
);
97+
98+
public triggerCertificate = () =>
99+
(this.onConnectRequest = () =>
100+
Promise.resolve({
101+
payload: {
102+
//<<veworld_address>> will be replaced by the user's wallet on VeWorld mobile
103+
content:
104+
'Test Message. Here is the user wallet: <<veworld_address>>',
105+
type: 'text',
106+
},
107+
purpose: 'identification',
108+
} satisfies CertificateMessage));
109+
110+
public triggerNull = () =>
111+
(this.onConnectRequest = () => Promise.resolve(null));
112+
public triggerSignTypedData = () =>
113+
(this.onConnectRequest = () =>
114+
Promise.resolve({
115+
domain: {
116+
name: 'Test Data',
117+
version: '1',
118+
chainId: 1,
119+
verifyingContract:
120+
'0x435933c8064b4Ae76bE665428e0307eF2cCFBD68',
121+
},
122+
types: {
123+
test: [
124+
{ name: 'test', type: 'address' },
125+
{ name: 'veworld_login_address', type: 'address' },
126+
],
127+
},
128+
value: {
129+
test: '0x435933c8064b4Ae76bE665428e0307eF2cCFBD68',
130+
//This will be replaced by the user's wallet on VeWorld mobile.
131+
veworld_login_address:
132+
'0x0000000000000000000000000000000000000000',
133+
},
134+
} satisfies TypedDataMessage));
84135
}

examples/sample-next-app/src/app/layout.tsx

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
'use client'; // This is a client component
22

3-
import type { WalletConnectOptions } from '@vechain/dapp-kit';
43
import dynamic from 'next/dynamic';
54
import { Inter } from 'next/font/google';
65
import './globals.css';
76

8-
const DAppKitProvider = dynamic(
7+
const Provider = dynamic(
98
async () => {
10-
const { DAppKitProvider: _DAppKitProvider } = await import(
11-
'@vechain/dapp-kit-react'
9+
const { Provider: _DAppKitProvider } = await import(
10+
'../providers/provider'
1211
);
1312
return _DAppKitProvider;
1413
},
@@ -19,20 +18,6 @@ const DAppKitProvider = dynamic(
1918

2019
const inter = Inter({ subsets: ['latin'] });
2120

22-
const walletConnectOptions: WalletConnectOptions = {
23-
projectId: 'a0b855ceaf109dbc8426479a4c3d38d8',
24-
metadata: {
25-
name: 'Sample VeChain dApp',
26-
description: 'A sample VeChain dApp',
27-
url: typeof window !== 'undefined' ? window.location.origin : '',
28-
icons: [
29-
typeof window !== 'undefined'
30-
? `${window.location.origin}/images/logo/my-dapp.png`
31-
: '',
32-
],
33-
},
34-
};
35-
3621
export default function RootLayout({
3722
children,
3823
}: {
@@ -44,15 +29,7 @@ export default function RootLayout({
4429
<title>Next JS</title>
4530
</head>
4631
<body className={inter.className}>
47-
<DAppKitProvider
48-
logLevel="DEBUG"
49-
node="https://testnet.vechain.org/"
50-
usePersistence
51-
walletConnectOptions={walletConnectOptions}
52-
v2Api={{ enabled: true }}
53-
>
54-
{children}
55-
</DAppKitProvider>
32+
<Provider>{children}</Provider>
5633
</body>
5734
</html>
5835
);

examples/sample-next-app/src/app/pages/homepage.tsx

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
'use client'; // This is a client component
2-
import { type ReactElement, useEffect, useState } from 'react';
2+
import { useDappKitFunctions } from '@/providers/provider';
3+
import { CertificateMessage, TypedDataMessage } from '@vechain/dapp-kit';
34
import {
45
useWallet,
56
useWalletModal,
67
WalletButton,
78
} from '@vechain/dapp-kit-react';
9+
import { type ReactElement, useEffect, useState } from 'react';
810

911
const Button = (): ReactElement => {
1012
const { account, signer } = useWallet();
1113
const { open, onConnectionStatusChange } = useWalletModal();
1214
const [buttonText, setButtonText] = useState('Connect Custom Button');
15+
const { onConnectRequest } = useDappKitFunctions();
1316

1417
const sendTx = () =>
1518
signer?.sendTransaction({
@@ -35,6 +38,48 @@ const Button = (): ReactElement => {
3538
{ test: '0x435933c8064b4Ae76bE665428e0307eF2cCFBD68' },
3639
);
3740

41+
const triggerCertificate = () => {
42+
onConnectRequest.current = () =>
43+
Promise.resolve({
44+
payload: {
45+
//<<veworld_address>> will be replaced by the user's wallet on VeWorld mobile
46+
content:
47+
'Test Message. Here is the user wallet: <<veworld_address>>',
48+
type: 'text',
49+
},
50+
purpose: 'identification',
51+
} satisfies CertificateMessage);
52+
};
53+
54+
const triggerNull = () => {
55+
onConnectRequest.current = () => Promise.resolve(null);
56+
};
57+
58+
const triggerSignTypedData = () => {
59+
onConnectRequest.current = () =>
60+
Promise.resolve({
61+
domain: {
62+
name: 'Test Data',
63+
version: '1',
64+
chainId: 1,
65+
verifyingContract:
66+
'0x435933c8064b4Ae76bE665428e0307eF2cCFBD68',
67+
},
68+
types: {
69+
test: [
70+
{ name: 'test', type: 'address' },
71+
{ name: 'veworld_login_address', type: 'address' },
72+
],
73+
},
74+
value: {
75+
test: '0x435933c8064b4Ae76bE665428e0307eF2cCFBD68',
76+
//This will be replaced by the user's wallet on VeWorld mobile.
77+
veworld_login_address:
78+
'0x0000000000000000000000000000000000000000',
79+
},
80+
} satisfies TypedDataMessage);
81+
};
82+
3883
useEffect(() => {
3984
const handleConnected = (address: string | null): void => {
4085
if (address) {
@@ -66,6 +111,19 @@ const Button = (): ReactElement => {
66111
<button onClick={sendTx}>Send TX</button>
67112
<div className="label">Typed Data</div>
68113
<button onClick={signTypedData}>Sign Typed Data</button>
114+
{!account && (
115+
<>
116+
<button onClick={triggerNull}>
117+
Trigger connection with no signature
118+
</button>
119+
<button onClick={triggerSignTypedData}>
120+
Trigger connection with typed data
121+
</button>
122+
<button onClick={triggerCertificate}>
123+
Trigger connection with certificate
124+
</button>
125+
</>
126+
)}
69127
</div>
70128
);
71129
};
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
'use client';
2+
import {
3+
DAppKitProvider,
4+
DAppKitUIOptions,
5+
WalletConnectOptions,
6+
} from '@vechain/dapp-kit-react';
7+
import {
8+
createContext,
9+
createRef,
10+
PropsWithChildren,
11+
RefObject,
12+
useCallback,
13+
useContext,
14+
useMemo,
15+
useRef,
16+
} from 'react';
17+
18+
const walletConnectOptions: WalletConnectOptions = {
19+
projectId: 'a0b855ceaf109dbc8426479a4c3d38d8',
20+
metadata: {
21+
name: 'Sample VeChain dApp',
22+
description: 'A sample VeChain dApp',
23+
url: typeof window !== 'undefined' ? window.location.origin : '',
24+
icons: [
25+
typeof window !== 'undefined'
26+
? `${window.location.origin}/images/logo/my-dapp.png`
27+
: '',
28+
],
29+
},
30+
};
31+
32+
type OnConnectRequest = NonNullable<
33+
DAppKitUIOptions['v2Api']['onConnectRequest']
34+
>;
35+
type OnConnectResponse = NonNullable<
36+
DAppKitUIOptions['v2Api']['onConnectResponse']
37+
>;
38+
39+
type ContextProps = {
40+
onConnectRequest: RefObject<OnConnectRequest | null>;
41+
onConnectResponse: RefObject<OnConnectResponse | null>;
42+
};
43+
44+
//This context has been created only for display purposes. It's not needed to created something like this
45+
const FunctionContext = createContext<ContextProps>({
46+
onConnectRequest: createRef(),
47+
onConnectResponse: createRef(),
48+
});
49+
50+
export const Provider = ({ children }: PropsWithChildren) => {
51+
const onConnectRequestRef = useRef<OnConnectRequest>(null);
52+
const onConnectResponseRef = useRef<OnConnectResponse>(null);
53+
54+
const ctxValue = useMemo(
55+
() => ({
56+
onConnectRequest: onConnectRequestRef,
57+
onConnectResponse: onConnectResponseRef,
58+
}),
59+
[],
60+
);
61+
62+
const onConnectRequest = useCallback<OnConnectRequest>((source) => {
63+
if (onConnectRequestRef.current)
64+
return onConnectRequestRef.current(source);
65+
return Promise.resolve(null);
66+
}, []);
67+
68+
const onConnectResponse = useCallback<OnConnectResponse>(
69+
(source, value) => {
70+
if (onConnectResponseRef.current)
71+
return onConnectResponseRef.current(source, value);
72+
alert(JSON.stringify(value));
73+
return Promise.resolve();
74+
},
75+
[],
76+
);
77+
78+
return (
79+
<FunctionContext.Provider value={ctxValue}>
80+
<DAppKitProvider
81+
node={'https://testnet.vechain.org'}
82+
usePersistence
83+
walletConnectOptions={walletConnectOptions}
84+
logLevel={'DEBUG'}
85+
v2Api={{ enabled: true, onConnectRequest, onConnectResponse }}
86+
>
87+
{children}
88+
</DAppKitProvider>
89+
</FunctionContext.Provider>
90+
);
91+
};
92+
93+
export const useDappKitFunctions = () => useContext(FunctionContext);

0 commit comments

Comments
 (0)