Skip to content

Commit daaa98c

Browse files
authored
KEEP-74 Add address book (#309)
1 parent 08c77bf commit daaa98c

File tree

114 files changed

+3938
-625
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

114 files changed

+3938
-625
lines changed

package-lock.json

Lines changed: 169 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"debounce": "^1.2.1",
5454
"debounce-stream": "^2.0.0",
5555
"dnode": "^1.2.2",
56+
"ethereumjs-util": "^7.1.5",
5657
"events": "^3.3.0",
5758
"highlight.js": "^11.3.1",
5859
"i18next": "^20.6.1",

scripts/webpack.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ module.exports = ({
7575
if (isProduction) {
7676
await zipFolder(
7777
platformFolder,
78-
path.join(DIST_FOLDER, `waves-keeper-${version}-${platformName}.zip`)
78+
path.join(DIST_FOLDER, `keeper-wallet-${version}-${platformName}.zip`)
7979
);
8080

8181
console.log(`Zipping ${platformName} is done`);

src/accounts/store.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
66

77
const reducer = combineReducers({
88
tab: reducers.tab,
9+
addresses: reducers.addresses,
910
accounts: reducers.accounts,
1011
currentLocale: reducers.currentLocale,
1112
state: reducers.state,

src/accounts/updateState.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ interface Account {
1616
}
1717

1818
interface UpdateStateInput {
19+
addresses: Record<string, string>;
1920
accounts?: Account[];
2021
currentLocale: string;
2122
currentNetwork?: string;
@@ -136,6 +137,14 @@ export function createUpdateState(store: AccountsStore) {
136137
});
137138
}
138139

140+
const addresses = getParam(state.addresses, {});
141+
if (addresses && !equals(addresses, currentState.addresses)) {
142+
store.dispatch({
143+
type: ACTION.UPDATE_ADDRESSES,
144+
payload: addresses,
145+
});
146+
}
147+
139148
actions.forEach(action => store.dispatch(action));
140149
};
141150
}

src/assets/selectModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import ColorHash from 'color-hash';
55
import * as React from 'react';
66
import { useTranslation } from 'react-i18next';
77
import { Button } from 'ui/components/ui/buttons/Button';
8-
import { Input } from 'ui/components/ui/input/index';
8+
import { Input } from 'ui/components/ui/input';
99
import { Tooltip } from 'ui/components/ui/tooltip';
1010
import { BalanceAssets } from 'ui/reducers/updateState';
1111
import { AssetDetail } from 'ui/services/Background';

src/background.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
UiStateController,
2727
WalletController,
2828
} from './controllers';
29+
import { AddressBookController } from './controllers/AddressBookController';
2930
import { SwapController } from './controllers/SwapController';
3031
import {
3132
getExtraFee,
@@ -366,6 +367,10 @@ class BackgroundService extends EventEmitter {
366367
getNode: this.networkController.getNode.bind(this.networkController),
367368
});
368369

370+
this.addressBookController = new AddressBookController({
371+
localStore: this.localStore,
372+
});
373+
369374
// Messages. Transaction message pipeline. Adds new tx, user approve/reject tx.
370375
// Delegates different signing to walletController, broadcast and getMatcherPublicKey to networkController,
371376
// assetInfo for assetInfoController
@@ -488,6 +493,8 @@ class BackgroundService extends EventEmitter {
488493
},
489494
newPassword: async (oldPassword, newPassword) =>
490495
this.walletController.newPassword(oldPassword, newPassword),
496+
checkPassword: async password =>
497+
this.walletController.checkPassword(password),
491498
getAccountSeed: async (address, network, password) =>
492499
this.walletController.getAccountSeed(address, network, password),
493500
getAccountEncodedSeed: async (address, network, password) =>
@@ -549,6 +556,13 @@ class BackgroundService extends EventEmitter {
549556
toggleAssetFavorite: this.assetInfoController.toggleAssetFavorite.bind(
550557
this.assetInfoController
551558
),
559+
// addresses
560+
setAddress: async (address, name) =>
561+
this.addressBookController.setAddress(address, name),
562+
setAddresses: async addresses =>
563+
this.addressBookController.setAddresses(addresses),
564+
removeAddress: async address =>
565+
this.addressBookController.removeAddress(address),
552566
// window control
553567
closeNotificationWindow: async () => this.emit('Close notification'),
554568
resizeNotificationWindow: async (width, height) =>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import * as ObservableStore from 'obs-store';
2+
import LocalStore from '../lib/localStore';
3+
4+
type AddressBookState = { addresses: Record<string, string> };
5+
6+
type Options = {
7+
localStore: LocalStore;
8+
};
9+
10+
export class AddressBookController {
11+
store: ObservableStore<AddressBookState>;
12+
13+
constructor({ localStore }: Options) {
14+
this.store = new ObservableStore(
15+
localStore.getInitState({ addresses: {} })
16+
);
17+
localStore.subscribe(this.store);
18+
}
19+
20+
setAddress(address: string, name: string) {
21+
const { addresses } = this.store.getState();
22+
this.store.updateState({ addresses: { ...addresses, [address]: name } });
23+
}
24+
25+
setAddresses(newAddresses: Record<string, string>) {
26+
const { addresses } = this.store.getState();
27+
this.store.updateState({ addresses: { ...newAddresses, ...addresses } });
28+
}
29+
30+
removeAddress(address: string) {
31+
const { addresses } = this.store.getState();
32+
delete addresses[address];
33+
this.store.updateState({ addresses });
34+
}
35+
}

src/controllers/WalletController.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ export class WalletController extends EventEmitter {
125125
this._saveWallets();
126126
}
127127

128+
checkPassword(password) {
129+
return password === this.password;
130+
}
131+
128132
getAccountSeed(address, network, password) {
129133
if (!password) throw new Error('Password is required');
130134
this._restoreWallets(password);

src/copied/_locales/en/extension.en.json

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,37 @@
2323
"activeAccountCard": {
2424
"swapButton": "Swap"
2525
},
26+
"spoiler": {
27+
"view": "View",
28+
"hide": "Hide"
29+
},
30+
"address": {
31+
"add": "New address",
32+
"addButton": "Add new",
33+
"addTooltip": "Add an address to your contacts",
34+
"added": "Address added",
35+
"addressAlreadyExist": "Address already exist",
36+
"addressInvalidError": "Address value is invalid",
37+
"cancel": "Cancel",
38+
"copied": "Copied!",
39+
"copyToClipboard": "Click to copy to clipboard",
40+
"delete": "Delete address",
41+
"deleteDescription": "Are you sure you want to delete this address from your contacts? This action is irreversible.",
42+
"edit": "Edit address",
43+
"edited": "Address edited",
44+
"emptyDescription": "Add the recipient's Name and Address for quick access to transfer and view in history",
45+
"emptyTitle": "No one here yet",
46+
"name": "Name",
47+
"nameAlreadyExist": "Name already exist",
48+
"nameInvalidError": "Name value is invalid",
49+
"save": "Save address",
50+
"saveChanges": "Save changes",
51+
"select": "Choose your address",
52+
"subtitle": "Address",
53+
"title": "Address book",
54+
"wallets": "My wallets",
55+
"warningAlias": "Be careful, the recipient has an Alias account, it is not a user from your contacts"
56+
},
2657
"assetAmountInput": {
2758
"balanceLabel": "Balance"
2859
},
@@ -132,12 +163,23 @@
132163
"delete": "Delete account",
133164
"warn": "Deleting an account will lead to its irretrievable loss!"
134165
},
166+
"exportAndImport": {
167+
"exportAccounts": "Export accounts",
168+
"importAccounts": "Import accounts",
169+
"exportAddressBook": "Export address book",
170+
"importAddressBook": "Import address book",
171+
"exportAll": "Export all"
172+
},
135173
"exportKeystore": {
136174
"cancelBtn": "Cancel",
137175
"chooseAccountsDesc": "Select which accounts you want to export. They will be encrypted and exported into a Keystore file",
176+
"chooseContactsDesc": "Select which address you want to export. They will be encrypted and exported into a Keystore file",
138177
"chooseAccountsExportBtn": "Export {{count}} account",
139178
"chooseAccountsExportBtn_plural": "Export {{count}} accounts",
179+
"chooseContactsExportBtn": "Continue",
140180
"chooseAccountsTitle": "Export to Keystore file",
181+
"chooseContactsTitle": "Export Contacts to file",
182+
"encrypt": "Encrypt the file",
141183
"exportNotSupported": "This account cannot be exported",
142184
"warningModalTitle": "Attention",
143185
"warningModalDesc": "Ledger and email accounts cannot be exported",
@@ -146,7 +188,7 @@
146188
"passwordLabel": "Password",
147189
"passwordVerifyDesc": "Please enter your Keeper password to confirm that it's really you",
148190
"passwordVerifyImportantNote": "<attention>Attention:</attention> this password will also be used to encrypt the resulting file. If you forget it, you won't be able to restore your accounts.",
149-
"verifyBtn": "Verify"
191+
"verifyBtn": "Enter"
150192
},
151193
"featureUpdateInfo": {
152194
"intro": "Keeper Wallet cares about safety of your funds and would like to remind you that losing the seed phrase means losing access to the account permanently.",
@@ -238,6 +280,8 @@
238280
"readyToUse": "Your account '{{ name }}' is ready to use",
239281
"readyToUseKeystore": "Your accounts are ready to use",
240282
"readyHelpText": "You can now close this tab and continue using the extension or add more accounts.",
283+
"readyToUseAddressBook": "Your Address Book is ready to use",
284+
"readyAddressBookText": "You can now close this tab and continue using the extension.",
241285
"viaKeystore": "Keystore File",
242286
"viaLedger": "Ledger",
243287
"viaSeed": "Seed Phrase or Private Key",
@@ -275,13 +319,16 @@
275319
"alreadyExists": "Account already exists"
276320
},
277321
"importKeystore": {
322+
"addressBookLabel": "Address Book file",
323+
"addressBookPasswordPlaceholder": "Password used to create file",
278324
"browse": "Browse...",
279-
"chooseAccountsTitle": "Choose accounts",
280325
"chooseAccountsDesc": "Select which accounts you want to import",
281326
"chooseAccountsExistingAccountNote": "Already exists in Keeper as {{existingName}}",
282327
"chooseAccountsImportBtn": "Import {{count}} account",
283328
"chooseAccountsImportBtn_plural": "Import {{count}} accounts",
284329
"chooseAccountsSkipBtn": "Skip",
330+
"chooseAccountsTitle": "Choose accounts",
331+
"chooseAddressBookFileTitle": "Import Address Book",
285332
"chooseFileSubmitBtn": "Continue",
286333
"chooseFileTitle": "Import Keystore File",
287334
"errorDecrypt": "Could not decrypt the Keystore file with the given password",
@@ -475,7 +522,7 @@
475522
"autoClickDisable": "Disabled",
476523
"autoClickEnable": "Enabled",
477524
"deleteAccounts": "Delete accounts",
478-
"export": "Export accounts",
525+
"exportAndImport": "Export and import",
479526
"langs": "Change language",
480527
"logOut": "Log out",
481528
"network": "Network",

0 commit comments

Comments
 (0)