@strkfarm/sdk 1.0.6

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,173 @@
1
+ import { IConfig, Network } from '@/interfaces/common';
2
+ import fs, { readFileSync, writeFileSync } from 'fs';
3
+ import { Account } from 'starknet';
4
+ import * as crypto from 'crypto';
5
+ import { PasswordJsonCryptoUtil } from './encrypt';
6
+ import { logger } from '..';
7
+ import { log } from 'winston';
8
+
9
+ /**
10
+ * @description Config to manage storage of files on disk
11
+ * @param SECRET_FILE_FOLDER - Folder to store secret files (default: ~/.starknet-store)
12
+ * @param NETWORK - Network to use
13
+ */
14
+ export interface StoreConfig {
15
+ SECRET_FILE_FOLDER?: string,
16
+ NETWORK: Network,
17
+ ACCOUNTS_FILE_NAME?: string,
18
+ PASSWORD: string
19
+ }
20
+
21
+ /**
22
+ * @description Info of a particular account
23
+ */
24
+ export interface AccountInfo {
25
+ address: string,
26
+ pk: string
27
+ }
28
+
29
+ /**
30
+ * @description map of accounts of a network
31
+ */
32
+ interface NetworkAccounts {
33
+ [accountKey: string]: AccountInfo
34
+ }
35
+
36
+ /**
37
+ * @description map of all accounts of all networks
38
+ */
39
+ export interface AllAccountsStore {
40
+ [networkKey: string]: NetworkAccounts
41
+ }
42
+
43
+ /**
44
+ * @description StoreConfig with optional fields marked required
45
+ */
46
+ export type RequiredStoreConfig = Required<StoreConfig>;
47
+
48
+ /**
49
+ * @description Get the default store config
50
+ * @param network
51
+ * @returns StoreConfig
52
+ */
53
+ export function getDefaultStoreConfig(network: Network): RequiredStoreConfig {
54
+ if (!process.env.HOME) {
55
+ throw new Error('StoreConfig: HOME environment variable not found');
56
+ }
57
+ return {
58
+ SECRET_FILE_FOLDER: `${process.env.HOME}/.starknet-store`,
59
+ NETWORK: network,
60
+ ACCOUNTS_FILE_NAME: 'accounts.json',
61
+ PASSWORD: crypto.randomBytes(16).toString('hex')
62
+ }
63
+ }
64
+
65
+ /**
66
+ * @description Store class to manage accounts
67
+ */
68
+ export class Store {
69
+ readonly config: IConfig;
70
+ readonly storeConfig: RequiredStoreConfig;
71
+
72
+ private encryptor = new PasswordJsonCryptoUtil();
73
+ constructor(config: IConfig, storeConfig: StoreConfig) {
74
+ this.config = config;
75
+
76
+ const defaultStoreConfig = getDefaultStoreConfig(config.network);
77
+
78
+ if (!storeConfig.PASSWORD) {
79
+ Store.logPassword(defaultStoreConfig.PASSWORD);
80
+ }
81
+
82
+ this.storeConfig = {
83
+ ...defaultStoreConfig,
84
+ ...storeConfig
85
+ };
86
+
87
+ // Ensure the store secret folder exists
88
+ Store.ensureFolder(this.storeConfig.SECRET_FILE_FOLDER);
89
+ }
90
+
91
+ static logPassword(password: string) {
92
+ logger.warn(`⚠️=========================================⚠️`);
93
+ logger.warn(`Generated a random password for store`);
94
+ logger.warn(`⚠️ Password: ${password}`);
95
+ logger.warn(`This not stored anywhere, please you backup this password for future use`);
96
+ logger.warn(`⚠️=========================================⚠️`);
97
+ }
98
+
99
+ getAccount(accountKey: string) {
100
+ const accounts = this.loadAccounts();
101
+ logger.verbose(`nAccounts loaded for network: ${Object.keys(accounts).length}`);
102
+ const data = accounts[accountKey];
103
+ if (!data) {
104
+ throw new Error(`Account not found: ${accountKey}`);
105
+ }
106
+ logger.verbose(`Account loaded: ${accountKey} from network: ${this.config.network}`);
107
+ logger.verbose(`Address: ${data.address}`);
108
+ return new Account(<any>this.config.provider, data.address, data.pk);
109
+ }
110
+
111
+ addAccount(accountKey: string, address: string, pk: string) {
112
+ const allAccounts = this.getAllAccounts();
113
+ if (!allAccounts[this.config.network]) {
114
+ allAccounts[this.config.network] = {};
115
+ }
116
+ allAccounts[this.config.network][accountKey] = {
117
+ address,
118
+ pk
119
+ };
120
+ const encryptedData = this.encryptor.encrypt(allAccounts, this.storeConfig.PASSWORD);
121
+ writeFileSync(this.getAccountFilePath(), encryptedData);
122
+ logger.verbose(`Account added: ${accountKey} to network: ${this.config.network}`);
123
+ }
124
+
125
+ private getAccountFilePath() {
126
+ const path = `${this.storeConfig.SECRET_FILE_FOLDER}/${this.storeConfig.ACCOUNTS_FILE_NAME}`;
127
+ logger.verbose(`Path: ${path}`);
128
+ return path
129
+ }
130
+
131
+ private getAllAccounts(): AllAccountsStore {
132
+ const PATH = this.getAccountFilePath();
133
+ if (!fs.existsSync(PATH)) {
134
+ logger.verbose(`Accounts: files doesnt exist`)
135
+ return {};
136
+ }
137
+ let encryptedData = readFileSync(PATH, {
138
+ encoding: 'utf-8'
139
+ });
140
+ let data = this.encryptor.decrypt(encryptedData, this.storeConfig.PASSWORD);
141
+ return data;
142
+ }
143
+
144
+ /**
145
+ * @description Load all accounts of the network
146
+ * @returns NetworkAccounts
147
+ */
148
+ loadAccounts(): NetworkAccounts {
149
+ const allData: AllAccountsStore = this.getAllAccounts();
150
+ logger.verbose(`Accounts loaded for network: ${this.config.network}`);
151
+ if (!allData[this.config.network]) {
152
+ allData[this.config.network] = {};
153
+ }
154
+ return allData[this.config.network];
155
+ }
156
+
157
+ /**
158
+ * @description List all accountKeys of the network
159
+ * @returns string[]
160
+ */
161
+ listAccounts(): string[] {
162
+ return Object.keys(this.loadAccounts());
163
+ }
164
+
165
+ static ensureFolder(folder: string) {
166
+ if (!fs.existsSync(folder)) {
167
+ fs.mkdirSync(folder, { recursive: true });
168
+ }
169
+ if (!fs.existsSync(`${folder}`)) {
170
+ throw new Error(`Store folder not found: ${folder}`);
171
+ }
172
+ }
173
+ }