@verified-network/verified-custody 0.1.9 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,334 @@
1
+ import {
2
+ contractAddress,
3
+ Custody,
4
+ Provider,
5
+ VerifiedWallet,
6
+ } from "@verified-network/verified-sdk";
7
+ import {
8
+ allGoogleFontUrls,
9
+ defaultChainId,
10
+ imageAssets,
11
+ TwiloBaseUrl,
12
+ } from "./constants";
13
+ import { ChainConfig, PaymasterConfig } from "./config";
14
+ import crypto from "crypto";
15
+ import crypt from "crypto-js";
16
+ import { toast } from "react-toastify";
17
+ import axios from "axios";
18
+ import { createSmartAccountClient } from "@biconomy/account";
19
+ import React from "react";
20
+
21
+ /**
22
+ *
23
+ * @param document Any web page loaded in the browser / Dom tree
24
+ */
25
+ export const loadAllGoogleFonts = (document: Document) => {
26
+ const apiExists = document.querySelector(
27
+ `link[href="https://fonts.googleapis.com"]`
28
+ );
29
+ if (!apiExists) {
30
+ const apiLink = document.createElement("link");
31
+ apiLink.rel = "preconnect";
32
+ apiLink.href = "https://fonts.googleapis.com";
33
+ document.head.appendChild(apiLink);
34
+ }
35
+ const staticExists = document.querySelector(
36
+ `link[href="https://fonts.gstatic.com"]`
37
+ );
38
+ if (!staticExists) {
39
+ const staticLink = document.createElement("link");
40
+ staticLink.rel = "preconnect";
41
+ staticLink.href = "https://fonts.gstatic.com";
42
+ document.head.appendChild(staticLink);
43
+ }
44
+ allGoogleFontUrls.map((fontUrl) => {
45
+ const fontExists = document.querySelector(`link[href="${fontUrl}"]`);
46
+ if (!fontExists) {
47
+ const fontLink = document.createElement("link");
48
+ fontLink.rel = "stylesheet";
49
+ fontLink.href = fontUrl;
50
+ document.head.appendChild(fontLink);
51
+ }
52
+ });
53
+
54
+ return true;
55
+ };
56
+
57
+ /**
58
+ * initialize user's wallet and vault contract using existing private key or create a new wallet for user
59
+ * unsupported/invalid chainId passed will automatically use default supported chainId
60
+ * @param chainId
61
+ * @param privateKey
62
+ *
63
+ */
64
+ export const initWalletAndContract = async (
65
+ chainId?: number,
66
+ privateKey?: string
67
+ ) => {
68
+ try {
69
+ let sender: VerifiedWallet;
70
+ //import existing wallet or create new one.
71
+ if (privateKey) {
72
+ sender = new VerifiedWallet(privateKey);
73
+ } else {
74
+ const mnemonics = VerifiedWallet.generateMnemonic();
75
+ sender = VerifiedWallet.importWallet(mnemonics);
76
+ }
77
+
78
+ //initialize provider, signer, privatekey and vault contract
79
+ const cntAddresses: any = contractAddress;
80
+ const _chainId =
81
+ chainId &&
82
+ cntAddresses[chainId]?.Custody &&
83
+ ChainConfig[chainId]?.rpcUrls?.length > 0
84
+ ? chainId
85
+ : defaultChainId;
86
+ const provider = ChainConfig[_chainId]?.rpcUrls[0];
87
+ const signer = sender.setProvider(new Provider(provider));
88
+ const pk = sender.privateKey;
89
+ const vaultContract = new Custody(signer, cntAddresses[_chainId]?.Custody);
90
+ const smartAccount = await createSmartAccountClient({
91
+ signer: signer,
92
+ bundlerUrl: `${PaymasterConfig.BUNDLER_URL_FIRST_SECTION}/${_chainId}/${PaymasterConfig[_chainId]["BUNDLER_API_KEY"]}`,
93
+ biconomyPaymasterApiKey: PaymasterConfig[_chainId]["PAYMASTER_API_KEY"],
94
+ });
95
+ const address = await smartAccount.getAccountAddress();
96
+
97
+ //valid return
98
+ return {
99
+ chainId: _chainId,
100
+ address,
101
+ pk,
102
+ signer,
103
+ provider,
104
+ vaultContract,
105
+ vaultData: null,
106
+ };
107
+ } catch (err) {
108
+ if (process.env.REACT_APP_NODE_ENV !== "production") {
109
+ console.error(
110
+ "Error while initializing user's wallet and contract: ",
111
+ err
112
+ );
113
+ }
114
+ //default return;
115
+ return {
116
+ chainId: null,
117
+ address: null,
118
+ pk: null,
119
+ signer: null,
120
+ provider: null,
121
+ vaultContract: null,
122
+ vaultData: null,
123
+ };
124
+ }
125
+ };
126
+
127
+ export const sendOTPVerification = async (
128
+ recipient: string,
129
+ channel: "sms" | "email"
130
+ ) => {
131
+ try {
132
+ const data = JSON.stringify({
133
+ to: recipient,
134
+ channel: channel,
135
+ });
136
+
137
+ const response = await fetch(`${TwiloBaseUrl}/start-verify`, {
138
+ method: "POST",
139
+ headers: {
140
+ "Content-Type": "application/json",
141
+ },
142
+ body: data,
143
+ });
144
+
145
+ const json = await response.json();
146
+ return json.success;
147
+ } catch (error) {
148
+ console.error(error);
149
+ return false;
150
+ }
151
+ };
152
+
153
+ export const checkOTPVerification = async (recipient: string, code: string) => {
154
+ try {
155
+ const data = JSON.stringify({
156
+ to: recipient,
157
+ code,
158
+ });
159
+
160
+ const response = await fetch(`${TwiloBaseUrl}/check-verify`, {
161
+ method: "POST",
162
+ headers: {
163
+ "Content-Type": "application/json",
164
+ },
165
+ body: data,
166
+ });
167
+
168
+ const json = await response.json();
169
+ return json.success;
170
+ } catch (error) {
171
+ console.error(error);
172
+ return false;
173
+ }
174
+ };
175
+
176
+ export const hashTheString = (text: string) => {
177
+ const hash = crypto.createHash("sha256").update(text).digest("hex");
178
+ return hash.slice(0, 30); // Truncate to 30 characters
179
+ };
180
+
181
+ export const encryptString = (text: string, secretKey: string) => {
182
+ const encryptedAES = crypt.AES.encrypt(text, secretKey);
183
+ return encryptedAES.toString();
184
+ };
185
+
186
+ export const decryptString = (encryptedText: string, secretKey: string) => {
187
+ var decryptedBytes = crypt.AES.decrypt(encryptedText, secretKey);
188
+ var decryptedText = decryptedBytes.toString(crypt.enc.Utf8);
189
+ return decryptedText;
190
+ };
191
+
192
+ export const customEncryptString = (inputString: string, password: string) => {
193
+ const salt = crypt.lib.WordArray.random(128 / 8);
194
+ const key = crypt.PBKDF2(password, salt, {
195
+ keySize: 256 / 32,
196
+ iterations: 1000,
197
+ });
198
+
199
+ const iv = crypt.lib.WordArray.random(128 / 8);
200
+
201
+ const encrypted = crypt.AES.encrypt(inputString, key, {
202
+ iv: iv,
203
+ padding: crypt.pad.Pkcs7,
204
+ mode: crypt.mode.CBC,
205
+ });
206
+
207
+ const result = salt.toString() + iv.toString() + encrypted.toString();
208
+ return result;
209
+ };
210
+
211
+ export const customDecryptString = (
212
+ encryptedString: string,
213
+ password: string
214
+ ) => {
215
+ const salt = crypt.enc.Hex.parse(encryptedString.substr(0, 32));
216
+ const iv = crypt.enc.Hex.parse(encryptedString.substr(32, 32));
217
+ const encrypted = encryptedString.substr(64);
218
+
219
+ const key = crypt.PBKDF2(password, salt, {
220
+ keySize: 256 / 32,
221
+ iterations: 1000,
222
+ });
223
+
224
+ const decrypted = crypt.AES.decrypt(encrypted, key, {
225
+ iv: iv,
226
+ padding: crypt.pad.Pkcs7,
227
+ mode: crypt.mode.CBC,
228
+ });
229
+
230
+ return decrypted.toString(crypt.enc.Utf8);
231
+ };
232
+
233
+ export const getErrorToastContent = (title: string, content: string) => {
234
+ return (
235
+ <div className="verified-custd-mdl-general-web-toast-error">
236
+ <img style={{ marginLeft: "5px" }} src={imageAssets.errorAlert} alt="" />
237
+ <div className="verified-custd-mdl-general-web-toast-error-container">
238
+ <p className="verified-custd-mdl-general-web-toast-error-title">
239
+ {title}
240
+ </p>
241
+ <p className="verified-custd-mdl-general-web-toast-error-label">
242
+ {content}
243
+ </p>
244
+ </div>
245
+ </div>
246
+ );
247
+ };
248
+
249
+ export const getSuccessToastContent = (
250
+ title: string,
251
+ content: string,
252
+ link: string
253
+ ) => {
254
+ return (
255
+ <div className="verified-custd-mdl-general-web-toast-success">
256
+ <div className="verified-custd-mdl-general-web-toast-success-cont">
257
+ <img
258
+ style={{ marginLeft: "5px" }}
259
+ src={imageAssets.successAlert}
260
+ alt=""
261
+ />
262
+ <div className="verified-custd-mdl-general-web-toast-success-container">
263
+ <p className="verified-custd-mdl-general-web-toast-error-title">
264
+ {title}
265
+ </p>
266
+ <p className="verified-custd-mdl-general-web-toast-error-label">
267
+ {content}
268
+ </p>
269
+ </div>
270
+ </div>
271
+ {link?.length > 0 && (
272
+ <div className="verified-custd-mdl-general-web-toast-success-link">
273
+ <a
274
+ className="verified-custd-mdl-general-web-toast-success-link-text"
275
+ href={link}
276
+ target="_blank"
277
+ rel="noreferrer"
278
+ >
279
+ Follow your transaction.
280
+ </a>
281
+ </div>
282
+ )}
283
+ </div>
284
+ );
285
+ };
286
+
287
+ export const errorToast = (title: string, content: string) => {
288
+ toast.dismiss();
289
+ return toast.error(getErrorToastContent(title, content), {
290
+ closeButton: false,
291
+ position: "top-center",
292
+ autoClose: 3000,
293
+ hideProgressBar: false,
294
+ pauseOnHover: false,
295
+ draggable: false,
296
+ closeOnClick: false,
297
+ style: {
298
+ background: "#fef2f2",
299
+ width: "600px",
300
+ height: "67px",
301
+ maxHeight: "67px",
302
+ position: "absolute",
303
+ top: "5px",
304
+ right: "5px",
305
+ borderRadius: "8px",
306
+ },
307
+ icon: false,
308
+ });
309
+ };
310
+
311
+ export const successToast = (title: string, content: string, link: string) => {
312
+ toast.dismiss();
313
+ return toast.success(getSuccessToastContent(title, content, link), {
314
+ closeButton: false,
315
+ position: "top-center",
316
+ autoClose: 3000,
317
+ hideProgressBar: false,
318
+ pauseOnHover: false,
319
+ draggable: false,
320
+ closeOnClick: false,
321
+ style: {
322
+ background: "var(--Success-50, #F1F8ED)",
323
+
324
+ width: "600px",
325
+ height: "67px",
326
+ maxHeight: "67px",
327
+ position: "absolute",
328
+ top: "5px",
329
+ right: "5px",
330
+ borderRadius: "8px",
331
+ },
332
+ icon: false,
333
+ });
334
+ };
@@ -0,0 +1,85 @@
1
+ export type VerifiedWalletAction =
2
+ | "connect_wallet"
3
+ | "getPk"
4
+ | "invitation"
5
+ | "signRecovery"
6
+ | "completeRecovery";
7
+
8
+ export type VerifiedWalletVault = {
9
+ vaultId: string;
10
+ hashedVaultId?: string;
11
+ hashedVaultPin?: string;
12
+ CoSignerId?: string;
13
+ vId?: string;
14
+ vPh?: string;
15
+ cId?: string;
16
+ address?: string;
17
+ channel?: "sms" | "email";
18
+ pk?: string;
19
+ };
20
+
21
+ export type VerifiedWalletTx = {
22
+ id: string;
23
+ };
24
+
25
+ export interface VerifiedCustodyProps {
26
+ action?: VerifiedWalletAction;
27
+ actionText?: string;
28
+ origin?: string;
29
+ title?: string;
30
+ chainId?: number;
31
+ vaultData?: VerifiedWalletVault;
32
+ txData?: VerifiedWalletTx;
33
+ reqVaultData?: VerifiedWalletVault;
34
+ delayPageElement?: React.JSX.Element;
35
+ delayPageStyle?: React.CSSProperties;
36
+ helperFunctions?: VerifiedCustodyHelpers;
37
+ }
38
+
39
+ export interface VerifiedCustodyHelpers {
40
+ sendCoSignerInvitation: (
41
+ channel: "sms" | "email",
42
+ cosigerId: string,
43
+ cretorId: string,
44
+ hashedCretorPin: string
45
+ ) => Promise<boolean>;
46
+
47
+ sendCreatorConfirmation: (
48
+ channel: "sms" | "email",
49
+ cretorId: string,
50
+ cosigersList: [],
51
+ requiredSigners: number
52
+ ) => Promise<boolean>;
53
+
54
+ sendCreatorInitiation: (
55
+ channel: "sms" | "email",
56
+ cretorId: string,
57
+ hashedCretorPin: string,
58
+ txId: number,
59
+ requiredSigners: number
60
+ ) => Promise<boolean>;
61
+
62
+ sendCreatorSigned: (
63
+ channel: "sms" | "email",
64
+ cretorId: string,
65
+ coSignerId: string
66
+ ) => Promise<boolean>;
67
+
68
+ sendCreatorCompleted: (
69
+ channel: "sms" | "email",
70
+ cretorId: string,
71
+ txId: number
72
+ ) => Promise<boolean>;
73
+
74
+ sendCreatorAcceptance: (
75
+ channel: "sms" | "email",
76
+ creatorId: string,
77
+ coSignerId: string
78
+ ) => Promise<boolean>;
79
+
80
+ sendCreatorRejection: (
81
+ channel: "sms" | "email",
82
+ creatorId: string,
83
+ coSignerId: string
84
+ ) => Promise<boolean>;
85
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "moduleResolution": "node",
4
+ "declaration": true,
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "esModuleInterop": true,
8
+ "allowSyntheticDefaultImports": true,
9
+ "strict": false,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "jsx": "react",
12
+ "outDir": "./dist"
13
+ },
14
+ "include": ["src/**/*.ts", "src/**/*.tsx", "src/customTypes.d.ts"],
15
+ "exclude": ["node_modules"]
16
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,36 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ const injectFunc = `
4
+ function injectStyle(css) {
5
+ if (!css || typeof document === 'undefined') return
6
+
7
+ const head = document.head || document.getElementsByTagName('head')[0]
8
+ const style = document.createElement('style')
9
+ style.type = 'text/css'
10
+
11
+ if(head.firstChild) {
12
+ head.insertBefore(style, head.firstChild)
13
+ } else {
14
+ head.appendChild(style)
15
+ }
16
+
17
+ if(style.styleSheet) {
18
+ style.styleSheet.cssText = css
19
+ } else {
20
+ style.appendChild(document.createTextNode(css))
21
+ }
22
+ }
23
+ `;
24
+
25
+ export default defineConfig({
26
+ entry: ["src/index.ts"],
27
+ format: ["esm", "cjs"],
28
+ dts: true,
29
+ sourcemap: true,
30
+ minify: true,
31
+ clean: true,
32
+ external: ["react", "react-dom", "react-native"],
33
+ injectStyle: (css) => {
34
+ return `${injectFunc}injectStyle(${css});`;
35
+ },
36
+ });
package/README.md DELETED
@@ -1,93 +0,0 @@
1
- # Verified Custody
2
-
3
- This react module allows users to create a vault using Mobile/ E-mail as their vault id and gives you a private Key which the users can use to sign all transactions further.
4
-
5
- ### Build:
6
- - All the components of the module is compiled and available under the dist/ directory.
7
-
8
-
9
- ### Install:
10
- ``` npm install @verified-network/verified-custody```
11
-
12
-
13
- The react module exports some constants and helper functions which will be useful when changing UI based on a user's state or any business logic
14
-
15
- **IS_CUSTODY_SET - (bool)** - Returns true when the user's pk is stored in the device and is validated by the users pin.
16
-
17
- **useCustody() - (hook)** - contains vaultInfo and IS_CUSTODY_SET.
18
-
19
- **initializeMessaging() - (void)** - Should be called to initialise the fcm which will get the device token. Should be called at the earliest.
20
-
21
- **getPermissionStatus - (bool** - Returns the status whether the user has allowed Push notification permissions.
22
-
23
- **getFcmToken - ( string)** - Returns the FCM token of the device.
24
-
25
-
26
-
27
-
28
-
29
- ****< StartCustody />**** component is the entry component, which starts from asking the user to enter their phone/email and follows.
30
-
31
- This **< StartCustody />** component, can be used for multiple use case like to Sign Transactions and Retrieve Private Key by passing props.
32
-
33
- - Create a new vault
34
- - To Accept and Decline Cosigner Request
35
- - To Sign Transactions
36
-
37
- **creator, txId, transactionType, user(id), etc.,** will be obtained from the notification params and as the query params.
38
-
39
- ## Usage:
40
-
41
- ### Creating a vault:
42
-
43
- return (
44
- <>
45
- { IS_CUSTODY_SET ? (
46
- <div>Welcome to dashboard</div>
47
- ) : permissionStatus === "granted" ? (
48
- <>
49
- { fcmToken ? (
50
- <StartCustody creatorInfo={{ fcmToken }} />
51
- ) : (
52
- <div>Retrieving fcm token...</div>
53
- ) }
54
- </>
55
- ) : permissionStatus === 'denied' ? (
56
- <p>
57
- Notifications are blocked. Please enable them from your browser
58
- settings.
59
- </p>
60
- ) : (
61
- <div>Requesting notification permissions...</div>
62
- )}
63
- </>
64
- )
65
-
66
-
67
- ### Handling cosigner requests:
68
-
69
- <StartCustody
70
- startPoint={{
71
- component: "StartCosigner", // currently supports all forms of signing
72
- args: { creator, txId, transactionType, id },
73
- }}
74
- />
75
-
76
- *transactionType* determines the type of signing request.
77
-
78
-
79
-
80
- ### Recovering a private key:
81
-
82
- This **< GetPrivateKey />** component, will let you to retreive the private key once all your cosigners signoff your recovery code request.
83
-
84
- return (
85
- <GetPrivateKey
86
- setupProps={{
87
- chainId: 84532,
88
- }}
89
- signingInfo={{ creator, txId, transactionType, user }}
90
- />
91
- )
92
-
93
-