├── .babelrc ├── .circleci └── config.yml ├── .eslintignore ├── .eslintrc ├── .flowconfig ├── .gitignore ├── .gitmodules ├── .nvmrc ├── LICENSE.md ├── README.md ├── app ├── App.js ├── Routes.js ├── ThemeManager.js ├── actions │ ├── ada │ │ ├── ada-redemption-actions.js │ │ ├── addresses-actions.js │ │ ├── daedalus-transfer-actions.js │ │ ├── index.js │ │ ├── node-update-actions.js │ │ ├── transactions-actions.js │ │ ├── wallet-settings-actions.js │ │ └── wallets-actions.js │ ├── dialogs-actions.js │ ├── index.js │ ├── lib │ │ └── Action.js │ ├── notifications-actions.js │ ├── profile-actions.js │ ├── router-actions.js │ ├── sidebar-actions.js │ └── wallet-backup-actions.js ├── api │ ├── ada │ │ ├── adaAccount.js │ │ ├── adaAddress.js │ │ ├── adaLocalStorage.js │ │ ├── adaTransactions │ │ │ ├── adaNewTransactions.js │ │ │ └── adaTransactionsHistory.js │ │ ├── adaTypes.js │ │ ├── adaWallet.js │ │ ├── daedalusTransfer.js │ │ ├── errors.js │ │ ├── index.js │ │ ├── lib │ │ │ ├── cardanoCrypto │ │ │ │ ├── cryptoErrors.js │ │ │ │ ├── cryptoToModel.js │ │ │ │ ├── cryptoUtils.js │ │ │ │ └── cryptoWallet.js │ │ │ ├── lovefieldDatabase.js │ │ │ ├── project-icarus-backend-api.js │ │ │ └── utils.js │ │ └── restoreAdaWallet.js │ ├── common.js │ ├── index.js │ └── localStorage │ │ └── index.js ├── assets │ ├── fonts │ │ ├── Electrolize-Regular.ttf │ │ ├── Montserrat-Medium.ttf │ │ ├── SFUIDisplay-Black.otf │ │ ├── SFUIDisplay-Bold.otf │ │ ├── SFUIDisplay-Heavy.otf │ │ ├── SFUIDisplay-Light.otf │ │ ├── SFUIDisplay-Medium.otf │ │ ├── SFUIDisplay-Regular.otf │ │ ├── SFUIDisplay-Semibold.otf │ │ ├── SFUIDisplay-Thin.otf │ │ └── SFUIDisplay-Ultralight.otf │ └── images │ │ ├── ada-logo.inline.svg │ │ ├── ada-symbol-big-dark.inline.svg │ │ ├── ada-symbol-smallest-dark.inline.svg │ │ ├── ada-symbol.inline.svg │ │ ├── arrow.inline.svg │ │ ├── attach-ic.inline.svg │ │ ├── attention-big-light.inline.svg │ │ ├── back-arrow-ic.inline.svg │ │ ├── card-payment-ic.svg │ │ ├── cardano-logo-white.inline.svg │ │ ├── cardano-logo.inline.svg │ │ ├── cert-bad-ic.inline.svg │ │ ├── cert-ic.inline.svg │ │ ├── cert-locked-ic.inline.svg │ │ ├── clipboard-ic.inline.svg │ │ ├── close-cross-white.inline.svg │ │ ├── close-cross.inline.svg │ │ ├── create-ic.inline.svg │ │ ├── daedalus-header-logo.svg │ │ ├── daedalus-logo-header-nologo.svg │ │ ├── daedalus-logo-header.svg │ │ ├── daedalus-logo-loading-grey.inline.svg │ │ ├── daedalus-logo-loading-white.inline.svg │ │ ├── danger.inline.svg │ │ ├── etc-logo.inline.svg │ │ ├── etc-symbol.inline.svg │ │ ├── exchange-ic.inline.svg │ │ ├── expand-arrow.svg │ │ ├── header-logo.svg │ │ ├── ic-check.svg │ │ ├── import-ic.inline.svg │ │ ├── join-shared-ic.inline.svg │ │ ├── mantis-logo.inline.svg │ │ ├── menu-ic.inline.svg │ │ ├── menu-opened-ic.inline.svg │ │ ├── paper-wallet.png │ │ ├── project-icarus-logo-shape-white.inline.svg │ │ ├── protected-off.inline.svg │ │ ├── receive-ic.svg │ │ ├── receive-white-ic.svg │ │ ├── restore-ic.inline.svg │ │ ├── search-ic-dark.svg │ │ ├── search-ic.svg │ │ ├── send-ic.svg │ │ ├── send-white-ic.svg │ │ ├── sidebar │ │ ├── ada-redemption-ic.inline.svg │ │ ├── add-wallet-ic.inline.svg │ │ ├── bug-report-ic.inline.svg │ │ ├── checked-light.svg │ │ ├── daedalus-transfer.inline.svg │ │ ├── settings-ic.inline.svg │ │ ├── spinner-light.svg │ │ ├── staking-ic.svg │ │ └── wallet-ic.inline.svg │ │ ├── spinner-dark.inline.svg │ │ ├── spinner-dark.svg │ │ ├── spinner-light.svg │ │ ├── success-big.inline.svg │ │ ├── success-small.inline.svg │ │ ├── themes │ │ ├── cardano.png │ │ ├── dark-blue.png │ │ └── light-blue.png │ │ ├── top-bar │ │ ├── node-sync-error.png │ │ ├── node-sync-spinner.png │ │ ├── node-sync-synced.png │ │ └── sticker.svg │ │ ├── transaction │ │ ├── deny-ic.inline.svg │ │ ├── receive-ic.inline.svg │ │ └── send-ic.inline.svg │ │ └── wallet-nav │ │ ├── deny-ic.inline.svg │ │ ├── receive-ic.inline.svg │ │ ├── send-ic.inline.svg │ │ ├── summary-ic.inline.svg │ │ ├── transactions-ic.inline.svg │ │ ├── wallet-settings-2-ic.inline.svg │ │ └── wallet-settings-ic.svg ├── components │ ├── daedalusTransfer │ │ ├── DaedalusTransferErrorPage.js │ │ ├── DaedalusTransferErrorPage.scss │ │ ├── DaedalusTransferFormPage.js │ │ ├── DaedalusTransferFormPage.scss │ │ ├── DaedalusTransferInstructionsPage.js │ │ ├── DaedalusTransferInstructionsPage.scss │ │ ├── DaedalusTransferSummaryPage.js │ │ ├── DaedalusTransferSummaryPage.scss │ │ ├── DaedalusTransferWaitingPage.js │ │ └── DaedalusTransferWaitingPage.scss │ ├── layout │ │ ├── CenteredLayout.js │ │ ├── CenteredLayout.scss │ │ ├── SidebarLayout.js │ │ ├── SidebarLayout.scss │ │ ├── TextOnlyTopbar.js │ │ ├── TextOnlyTopbar.scss │ │ ├── TopBar.js │ │ ├── TopBar.scss │ │ ├── TopBarCategory.js │ │ ├── TopBarCategory.scss │ │ ├── TopBarLayout.js │ │ ├── TopBarLayout.scss │ │ ├── VerticalFlexContainer.js │ │ └── VerticalFlexContainer.scss │ ├── loading │ │ ├── Loading.js │ │ └── Loading.scss │ ├── profile │ │ ├── language-selection │ │ │ ├── LanguageSelectionForm.js │ │ │ └── LanguageSelectionForm.scss │ │ └── terms-of-use │ │ │ ├── TermsOfUseForm.js │ │ │ ├── TermsOfUseForm.scss │ │ │ ├── TermsOfUseText.js │ │ │ └── TermsOfUseText.scss │ ├── settings │ │ ├── SettingsLayout.js │ │ ├── SettingsLayout.scss │ │ ├── _settingsConfig.scss │ │ ├── categories │ │ │ ├── GeneralSettings.js │ │ │ ├── GeneralSettings.scss │ │ │ ├── SupportSettings.js │ │ │ ├── SupportSettings.scss │ │ │ ├── TermsOfUseSettings.js │ │ │ └── TermsOfUseSettings.scss │ │ └── menu │ │ │ ├── SettingsMenu.js │ │ │ ├── SettingsMenu.scss │ │ │ ├── SettingsMenuItem.js │ │ │ └── SettingsMenuItem.scss │ ├── sidebar │ │ ├── Sidebar.js │ │ ├── Sidebar.scss │ │ ├── SidebarCategory.js │ │ ├── SidebarCategory.scss │ │ └── _sidebarConfig.scss │ ├── wallet │ │ ├── WalletAdd.js │ │ ├── WalletAdd.scss │ │ ├── WalletBackupDialog.js │ │ ├── WalletCreateDialog.js │ │ ├── WalletCreateDialog.scss │ │ ├── WalletReceive.js │ │ ├── WalletReceive.scss │ │ ├── WalletRestoreDialog.js │ │ ├── WalletRestoreDialog.scss │ │ ├── WalletSendConfirmationDialog.js │ │ ├── WalletSendConfirmationDialog.scss │ │ ├── WalletSendForm.js │ │ ├── WalletSendForm.scss │ │ ├── WalletSettings.js │ │ ├── WalletSettings.scss │ │ ├── backup-recovery │ │ │ ├── MnemonicWord.js │ │ │ ├── MnemonicWord.scss │ │ │ ├── WalletBackupPrivacyWarningDialog.js │ │ │ ├── WalletBackupPrivacyWarningDialog.scss │ │ │ ├── WalletRecoveryInstructions.js │ │ │ ├── WalletRecoveryInstructions.scss │ │ │ ├── WalletRecoveryPhraseDisplayDialog.js │ │ │ ├── WalletRecoveryPhraseDisplayDialog.scss │ │ │ ├── WalletRecoveryPhraseEntryDialog.js │ │ │ ├── WalletRecoveryPhraseEntryDialog.scss │ │ │ ├── WalletRecoveryPhraseMnemonic.js │ │ │ └── WalletRecoveryPhraseMnemonic.scss │ │ ├── layouts │ │ │ ├── WalletWithNavigation.js │ │ │ └── WalletWithNavigation.scss │ │ ├── navigation │ │ │ ├── WalletNavButton.js │ │ │ ├── WalletNavButton.scss │ │ │ ├── WalletNavigation.js │ │ │ └── WalletNavigation.scss │ │ ├── settings │ │ │ ├── ChangeWalletPasswordDialog.js │ │ │ └── ChangeWalletPasswordDialog.scss │ │ ├── skins │ │ │ ├── AmountInputSkin.js │ │ │ └── AmountInputSkin.scss │ │ ├── summary │ │ │ ├── WalletSummary.js │ │ │ └── WalletSummary.scss │ │ └── transactions │ │ │ ├── Transaction.js │ │ │ ├── Transaction.scss │ │ │ ├── TransactionTypeIcon.js │ │ │ ├── TransactionTypeIcon.scss │ │ │ ├── WalletNoTransactions.js │ │ │ ├── WalletNoTransactions.scss │ │ │ ├── WalletTransactionsList.js │ │ │ └── WalletTransactionsList.scss │ └── widgets │ │ ├── BigButtonForDialogs.js │ │ ├── BigButtonForDialogs.scss │ │ ├── BorderedBox.js │ │ ├── BorderedBox.scss │ │ ├── Dialog.js │ │ ├── Dialog.scss │ │ ├── DialogBackButton.js │ │ ├── DialogBackButton.scss │ │ ├── DialogCloseButton.js │ │ ├── DialogCloseButton.scss │ │ ├── LoadingSpinner.js │ │ ├── LoadingSpinner.scss │ │ ├── NotificationMessage.js │ │ ├── NotificationMessage.scss │ │ └── forms │ │ ├── InlineEditingInput.js │ │ ├── InlineEditingInput.scss │ │ ├── ReadOnlyInput.js │ │ └── ReadOnlyInput.scss ├── config.js ├── config │ ├── numbersConfig.js │ ├── sidebarConfig.js │ └── transactionAssuranceConfig.js ├── containers │ ├── LoadingPage.js │ ├── MainLayout.js │ ├── TopBarContainer.js │ ├── daedalusTransfer │ │ └── DaedalusTransferPage.js │ ├── profile │ │ ├── LanguageSelectionPage.js │ │ └── TermsOfUsePage.js │ ├── settings │ │ ├── Settings.js │ │ └── categories │ │ │ ├── GeneralSettingsPage.js │ │ │ ├── SupportSettingsPage.js │ │ │ ├── TermsOfUseSettingsPage.js │ │ │ └── WalletSettingsPage.js │ └── wallet │ │ ├── NoWalletsPage.js │ │ ├── Wallet.js │ │ ├── WalletAddPage.js │ │ ├── WalletReceivePage.js │ │ ├── WalletSendPage.js │ │ ├── WalletSummaryPage.js │ │ └── dialogs │ │ ├── ChangeWalletPasswordDialogContainer.js │ │ ├── WalletBackupDialogContainer.js │ │ ├── WalletCreateDialogContainer.js │ │ ├── WalletRestoreDialogContainer.js │ │ └── WalletSendConfirmationDialogContainer.js ├── domain │ ├── Wallet.js │ ├── WalletAddress.js │ └── WalletTransaction.js ├── environment.js ├── i18n │ ├── LocalizableError.js │ ├── global-messages.js │ ├── locales │ │ ├── de-DE.json │ │ ├── defaultMessages.json │ │ ├── en-US.json │ │ ├── hr-HR.json │ │ ├── ja-JP.json │ │ ├── ko-KR.json │ │ ├── terms-of-use │ │ │ └── ada │ │ │ │ ├── mainnet │ │ │ │ ├── en-US.md │ │ │ │ ├── ja-JP.md │ │ │ │ └── ko-KR.md │ │ │ │ └── other │ │ │ │ ├── en-US.md │ │ │ │ ├── ja-JP.md │ │ │ │ └── ko-KR.md │ │ ├── whitelist_de-DE.json │ │ ├── whitelist_en-US.json │ │ ├── whitelist_hr-HR.json │ │ ├── whitelist_ja-JP.json │ │ ├── whitelist_ko-KR.json │ │ ├── whitelist_zh-CN.json │ │ └── zh-CN.json │ └── translations.js ├── routes-config.js ├── scripts │ └── generateSTxs.js ├── stores │ ├── AppStore.js │ ├── LoadingStore.js │ ├── ProfileStore.js │ ├── SidebarStore.js │ ├── TransactionsStore.js │ ├── UiDialogsStore.js │ ├── UiNotificationsStore.js │ ├── WalletBackupStore.js │ ├── WalletSettingsStore.js │ ├── WalletStore.js │ ├── ada │ │ ├── AdaTransactionsStore.js │ │ ├── AdaWalletSettingsStore.js │ │ ├── AdaWalletsStore.js │ │ ├── AddressesStore.js │ │ ├── DaedalusTransferStore.js │ │ └── index.js │ ├── index.js │ └── lib │ │ ├── CachedRequest.js │ │ ├── LocalizedCachedRequest.js │ │ ├── LocalizedRequest.js │ │ ├── Reaction.js │ │ ├── Request.js │ │ └── Store.js ├── themes │ ├── daedalus.js │ ├── daedalus │ │ ├── cardano.js │ │ ├── dark-blue.js │ │ ├── light-blue.js │ │ └── project-icarus.js │ ├── index.global.scss │ ├── index.js │ ├── mixins │ │ ├── animations.scss │ │ ├── arrow.scss │ │ ├── buttons.scss │ │ ├── error-message.scss │ │ ├── forms.scss │ │ ├── loading-spinner.scss │ │ └── place-form-field-error-below-input.scss │ └── simple │ │ ├── SimpleAutocomplete.scss │ │ ├── SimpleBubble.scss │ │ ├── SimpleButton.scss │ │ ├── SimpleCheckbox.scss │ │ ├── SimpleFormField.scss │ │ ├── SimpleInput.scss │ │ ├── SimpleModal.scss │ │ ├── SimpleOptions.scss │ │ ├── SimpleSelect.scss │ │ ├── SimpleSwitch.scss │ │ ├── SimpleTextArea.scss │ │ └── _config.scss ├── types │ ├── daedalusTransferTypes.js │ ├── i18nTypes.js │ ├── injectedPropsType.js │ ├── notificationType.js │ ├── redemptionTypes.js │ ├── transactionAssuranceTypes.js │ └── unconfirmedAmountType.js └── utils │ ├── ReactToolboxMobxForm.js │ ├── formatters.js │ ├── imports.js │ ├── logging.js │ ├── passwordCipher.js │ ├── routing.js │ ├── strings.js │ └── validations.js ├── appveyor.yml ├── chrome ├── assets │ └── img │ │ ├── ada-logo.inline.svg │ │ ├── ada-symbol-smallest-dark.inline.svg │ │ ├── ada-symbol-smallest-white.inline.svg │ │ ├── ada-symbol.inline.svg │ │ ├── cardano-logo-white.inline.svg │ │ ├── icon-128.png │ │ ├── icon-16.png │ │ ├── icon-48.png │ │ ├── receive-ic.svg │ │ └── send-ic.svg ├── extension │ ├── background.js │ └── index.js ├── manifest.development.json ├── manifest.mainnet.json ├── manifest.staging.json ├── manifest.test.json ├── manifest.testnet.json └── views │ ├── background.pug │ └── main_window.pug ├── config ├── config-types.js ├── development.json ├── mainnet.json ├── staging.json ├── test.json └── testnet.json ├── dll ├── vendor-manifest.json └── vendor.js ├── e2etest-key.pem ├── features ├── accept-terms-of-use.feature ├── create-wallet.feature ├── daedalus-transfer.feature ├── generate-addresses.feature ├── get-balance.feature ├── navigate-general-settings-menu.feature ├── restore-wallet.feature ├── select-language.feature ├── send-tx.feature ├── step_definitions │ ├── accept-terms-of-use-steps.js │ ├── common-steps.js │ ├── create-wallet-steps.js │ ├── daedalus-transfer-steps.js │ ├── general-settings-steps.js │ ├── get-balance-steps.js │ ├── receive.js │ ├── restore-wallet-steps.js │ ├── select-language-steps.js │ ├── send-tx-steps.js │ ├── settings-steps.js │ ├── tx-history-steps.js │ └── wallet-steps.js ├── support │ ├── default-wallet.json │ ├── default-wallet.key │ ├── default-wallet.key.lock │ ├── helpers │ │ ├── i18n-helpers.js │ │ ├── language-selection-helpers.js │ │ ├── route-helpers.js │ │ └── terms-of-use-helpers.js │ ├── mockData.json │ ├── mockDataBuilder.js │ ├── mockServer.js │ ├── mockWebSocketServer.js │ └── webdriver.js ├── tx-history.feature └── wallet-settings.feature ├── flow ├── declarations │ ├── CardanoCrypto.js │ └── File.js └── mappers │ ├── CSSModule.js.flow │ ├── GeneralStub.js.flow │ └── WebpackAsset.js.flow ├── package-lock.json ├── package.json ├── scripts ├── .eslintrc ├── build.js ├── compress.js ├── start.js └── tasks.js ├── setup_cardano_crypto.sh ├── translations └── translation-runner.js └── webpack ├── .eslintrc ├── customPublicPath.js ├── development.config.js ├── dll.config.js ├── mainnet.config.js ├── replace ├── JsonpMainTemplate.runtime.js └── process-update.js ├── staging.config.js ├── test.config.js └── testnet.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "stage-0", 5 | "react" 6 | ], 7 | "plugins": [ 8 | ["transform-runtime", { 9 | "polyfill": false, 10 | "regenerator": true 11 | }], 12 | ["react-intl", { 13 | "messagesDir": "./translations/messages/", 14 | "enforceDescriptions": true, 15 | "extractSourceLocation": true 16 | }], 17 | "add-module-exports", 18 | "transform-decorators-legacy" 19 | ], 20 | "env": { 21 | "development": { 22 | "plugins": ["transform-runtime"] 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /js-cardano-wasm 2 | /dll -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/node_modules/fbjs/.* 3 | .*/node_modules/electron-packager/.* 4 | .*/node_modules/npm/.* 5 | .*/node_modules/oboe/.* 6 | .*/dist/.* 7 | .*/release/.* 8 | .*/.git/.* 9 | .*/.vscode/.* 10 | .*/.circleci/.* 11 | 12 | [include] 13 | 14 | [libs] 15 | flow/declarations/ 16 | node_modules/mobx/lib/mobx.js.flow 17 | 18 | [options] 19 | esproposal.class_static_fields=enable 20 | esproposal.class_instance_fields=enable 21 | esproposal.export_star_as=enable 22 | esproposal.decorators=ignore 23 | module.ignore_non_literal_requires=true 24 | module.name_mapper.extension='scss' -> '/flow/mappers/CSSModule.js.flow' 25 | module.name_mapper.extension='png' -> '/flow/mappers/WebpackAsset.js.flow' 26 | module.name_mapper.extension='jpg' -> '/flow/mappers/WebpackAsset.js.flow' 27 | module.name_mapper.extension='svg' -> '/flow/mappers/WebpackAsset.js.flow' 28 | module.name_mapper='\(react-dropzone\)' -> '/flow/mappers/GeneralStub.js.flow' 29 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe 30 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | 5 | build/ 6 | dev/ 7 | 8 | *.zip 9 | *.crx 10 | *.pem 11 | update.xml 12 | .vscode/ 13 | 14 | # Generated translation files 15 | translations/messages 16 | translations/reports -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "js-cardano-wasm"] 2 | path = js-cardano-wasm 3 | url = https://github.com/input-output-hk/js-cardano-wasm.git 4 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v8.9.4 2 | -------------------------------------------------------------------------------- /app/ThemeManager.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import _ from 'lodash'; 3 | 4 | export default class ThemeManager extends Component { 5 | componentDidMount() { 6 | this.updateCSSVariables(this.props.variables); 7 | } 8 | 9 | componentDidUpdate(prevProps) { 10 | if (this.props.variables !== prevProps.variables) { 11 | this.updateCSSVariables(this.props.variables); 12 | } 13 | } 14 | 15 | updateCSSVariables(variables) { 16 | _.map(variables, (value, prop) => { 17 | document.documentElement.style.setProperty(prop, value); 18 | }); 19 | } 20 | render() { 21 | return
{this.props.children}
; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/actions/ada/ada-redemption-actions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Action from '../lib/Action'; 3 | import type { RedemptionTypeChoices } from '../../types/redemptionTypes'; 4 | 5 | // ======= ADA REDEMPTION ACTIONS ======= 6 | 7 | export default class AdaRedemptionActions { 8 | chooseRedemptionType: Action<{ redemptionType: RedemptionTypeChoices }> = new Action(); 9 | setCertificate: Action<{ certificate: File }> = new Action(); 10 | removeCertificate: Action = new Action(); 11 | setPassPhrase: Action<{ passPhrase: string }> = new Action(); 12 | setRedemptionCode: Action<{ redemptionCode: string }> = new Action(); 13 | setEmail: Action<{ email: string }> = new Action(); 14 | setAdaPasscode: Action<{ adaPasscode: string }> = new Action(); 15 | setAdaAmount: Action<{ adaAmount: string }> = new Action(); 16 | redeemAda: Action<{ walletId: string, walletPassword: ?string }> = new Action(); 17 | // eslint-disable-next-line max-len 18 | redeemPaperVendedAda: Action<{ walletId: string, shieldedRedemptionKey: string, walletPassword: ?string }> = new Action(); 19 | adaSuccessfullyRedeemed: Action = new Action(); 20 | acceptRedemptionDisclaimer: Action = new Action(); 21 | // TODO: refactor dialog toggles to use dialog-actions instead 22 | closeAdaRedemptionSuccessOverlay: Action = new Action(); 23 | } 24 | -------------------------------------------------------------------------------- /app/actions/ada/addresses-actions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Action from '../lib/Action'; 3 | 4 | // ======= ADDRESSES ACTIONS ======= 5 | 6 | export default class AddressesActions { 7 | createAddress: Action = new Action(); 8 | resetErrors: Action = new Action(); 9 | } 10 | -------------------------------------------------------------------------------- /app/actions/ada/daedalus-transfer-actions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Action from '../lib/Action'; 3 | 4 | export default class DaedalusTranferActions { 5 | startTransferFunds: Action = new Action(); 6 | setupTransferFunds: Action = new Action(); 7 | backToUninitialized: Action = new Action(); 8 | transferFunds: Action = new Action(); 9 | cancelTransferFunds: Action = new Action(); 10 | } 11 | -------------------------------------------------------------------------------- /app/actions/ada/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import WalletsActions from './wallets-actions'; 3 | import AdaRedemptionActions from './ada-redemption-actions'; 4 | import TransactionsActions from './transactions-actions'; 5 | import NodeUpdateActions from './node-update-actions'; 6 | import WalletSettingsActions from './wallet-settings-actions'; 7 | import AddressesActions from './addresses-actions'; 8 | import DaedalusTransferActions from './daedalus-transfer-actions'; 9 | 10 | export type AdaActionsMap = { 11 | wallets: WalletsActions, 12 | adaRedemption: AdaRedemptionActions, 13 | transactions: TransactionsActions, 14 | nodeUpdate: NodeUpdateActions, 15 | walletSettings: WalletSettingsActions, 16 | addresses: AddressesActions, 17 | daedalusTransfer: DaedalusTransferActions, 18 | }; 19 | 20 | const adaActionsMap: AdaActionsMap = { 21 | wallets: new WalletsActions(), 22 | adaRedemption: new AdaRedemptionActions(), 23 | transactions: new TransactionsActions(), 24 | nodeUpdate: new NodeUpdateActions(), 25 | walletSettings: new WalletSettingsActions(), 26 | addresses: new AddressesActions(), 27 | daedalusTransfer: new DaedalusTransferActions() 28 | }; 29 | 30 | export default adaActionsMap; 31 | -------------------------------------------------------------------------------- /app/actions/ada/node-update-actions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Action from '../lib/Action'; 3 | 4 | // ======= NODE UPDATE ACTIONS ======= 5 | 6 | export default class NodeUpdateActions { 7 | acceptNodeUpdate: Action = new Action(); 8 | postponeNodeUpdate: Action = new Action(); 9 | toggleNodeUpdateNotificationExpanded: Action = new Action(); 10 | } 11 | -------------------------------------------------------------------------------- /app/actions/ada/transactions-actions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Action from '../lib/Action'; 3 | 4 | // ======= TRANSACTIONS ACTIONS ======= 5 | 6 | export default class TransactionsActions { 7 | loadMoreTransactions: Action = new Action(); 8 | } 9 | -------------------------------------------------------------------------------- /app/actions/ada/wallet-settings-actions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Action from '../lib/Action'; 3 | 4 | export type WalletExportToFileParams = { 5 | walletId: string, 6 | exportType: string, 7 | filePath: string, 8 | password: ?string 9 | }; 10 | 11 | export default class WalletSettingsActions { 12 | cancelEditingWalletField: Action = new Action(); 13 | startEditingWalletField: Action<{ field: string }> = new Action(); 14 | stopEditingWalletField: Action = new Action(); 15 | updateWalletField: Action<{ field: string, value: string }> = new Action(); 16 | // eslint-disable-next-line max-len 17 | updateWalletPassword: Action<{ walletId: string, oldPassword: ?string, newPassword: ?string }> = new Action(); 18 | exportToFile: Action = new Action(); 19 | } 20 | -------------------------------------------------------------------------------- /app/actions/ada/wallets-actions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import BigNumber from 'bignumber.js'; 3 | import Action from '../lib/Action'; 4 | 5 | export type WalletImportFromFileParams = { 6 | filePath: string, 7 | walletName: ?string, 8 | walletPassword: ?string, 9 | }; 10 | 11 | // ======= WALLET ACTIONS ======= 12 | 13 | export default class WalletsActions { 14 | createWallet: Action<{ name: string, password: string }> = new Action(); 15 | // eslint-disable-next-line max-len 16 | restoreWallet: Action<{recoveryPhrase: string, walletName: string, walletPassword: string }> = new Action(); 17 | importWalletFromFile: Action = new Action(); 18 | deleteWallet: Action<{ walletId: string }> = new Action(); 19 | sendMoney: Action<{ receiver: string, amount: string, password: ?string }> = new Action(); 20 | updateBalance: Action <{ amount: BigNumber }> = new Action(); 21 | } 22 | -------------------------------------------------------------------------------- /app/actions/dialogs-actions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Action from './lib/Action'; 3 | 4 | // ======= DIALOGS ACTIONS ======= 5 | 6 | export default class DialogsActions { 7 | open: Action<{ dialog: Function }> = new Action(); 8 | updateDataForActiveDialog: Action<{ data: Object }> = new Action(); 9 | closeActiveDialog: Action = new Action(); 10 | resetActiveDialog: Action = new Action(); 11 | } 12 | -------------------------------------------------------------------------------- /app/actions/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import RouterActions from './router-actions'; 3 | import SidebarActions from './sidebar-actions'; 4 | import WalletBackupActions from './wallet-backup-actions'; 5 | import ProfileActions from './profile-actions'; 6 | import DialogsActions from './dialogs-actions'; 7 | import NotificationsActions from './notifications-actions'; 8 | import adaActionsMap from './ada/index'; 9 | import type { AdaActionsMap } from './ada/index'; 10 | 11 | export type ActionsMap = { 12 | router: RouterActions, 13 | sidebar: SidebarActions, 14 | walletBackup: WalletBackupActions, 15 | profile: ProfileActions, 16 | dialogs: DialogsActions, 17 | notifications: NotificationsActions, 18 | ada: AdaActionsMap 19 | }; 20 | 21 | const actionsMap: ActionsMap = { 22 | router: new RouterActions(), 23 | sidebar: new SidebarActions(), 24 | walletBackup: new WalletBackupActions(), 25 | profile: new ProfileActions(), 26 | dialogs: new DialogsActions(), 27 | notifications: new NotificationsActions(), 28 | ada: adaActionsMap 29 | }; 30 | 31 | export default actionsMap; 32 | -------------------------------------------------------------------------------- /app/actions/lib/Action.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { bindAll } from 'lodash'; 3 | 4 | /** 5 | * Listener type as Function that takes specific params

6 | */ 7 | export type Listener

= (params: P) => any; 8 | 9 | /** 10 | * Action class with typed params 11 | */ 12 | export default class Action { 13 | 14 | /** 15 | * Array of all defined actions in the system 16 | * @type {[Action]} 17 | */ 18 | static actions: Action[] = []; 19 | 20 | static resetAllActions() { 21 | Action.actions.forEach(action => action.removeAll()); 22 | } 23 | 24 | listeners: Listener[] = []; 25 | 26 | constructor() { 27 | bindAll(this, ['trigger']); 28 | Action.actions.push(this); 29 | } 30 | 31 | listen(listener: Listener) { 32 | this.listeners.push(listener); 33 | } 34 | 35 | trigger(params: Params) { 36 | this.listeners.forEach(listener => listener(params)); 37 | } 38 | 39 | remove(listener: Listener) { 40 | this.listeners.splice(this.listeners.indexOf(listener), 1); 41 | } 42 | 43 | removeAll() { 44 | this.listeners = []; 45 | } 46 | 47 | once(listener: Listener) { 48 | this.listeners.push((...args) => { 49 | this.remove(listener); 50 | listener(...args); 51 | }); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/actions/notifications-actions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Action from './lib/Action'; 3 | 4 | // ======= NOTIFICATIONS ACTIONS ======= 5 | 6 | export default class NotificationsActions { 7 | open: Action<{ id: string, duration?: number }> = new Action(); 8 | updateDataForActiveNotification: Action<{ data: Object }> = new Action(); 9 | closeActiveNotification: Action<{ id: string }>= new Action(); 10 | resetActiveNotification: Action = new Action(); 11 | } 12 | -------------------------------------------------------------------------------- /app/actions/profile-actions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Action from './lib/Action'; 3 | 4 | // ======= PROFILE ACTIONS ======= 5 | 6 | export default class ProfileActions { 7 | acceptTermsOfUse: Action = new Action(); 8 | updateLocale: Action<{ locale: string }> = new Action(); 9 | } 10 | -------------------------------------------------------------------------------- /app/actions/router-actions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Action from './lib/Action'; 3 | 4 | // ======= ROUTER ACTIONS ======= 5 | 6 | export default class RouterActions { 7 | goToRoute: Action<{ route: string, params?: ?Object }> = new Action(); 8 | } 9 | -------------------------------------------------------------------------------- /app/actions/sidebar-actions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Action from './lib/Action'; 3 | 4 | // ======= SIDEBAR ACTIONS ======= 5 | 6 | export default class SidebarActions { 7 | toggleSubMenus: Action = new Action(); 8 | activateSidebarCategory: Action<{ category: string, showSubMenu?: boolean }> = new Action(); 9 | walletSelected: Action<{ walletId: string }> = new Action(); 10 | } 11 | -------------------------------------------------------------------------------- /app/actions/wallet-backup-actions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Action from './lib/Action'; 3 | 4 | // ======= WALLET BACKUP ACTIONS ======= 5 | 6 | export default class WalletBackupActions { 7 | startWalletBackup: Action = new Action(); 8 | initiateWalletBackup: Action<{ recoveryPhrase: string[] }> = new Action(); 9 | acceptPrivacyNoticeForWalletBackup: Action = new Action(); 10 | continueToRecoveryPhraseForWalletBackup: Action = new Action(); 11 | addWordToWalletBackupVerification: Action<{ word: string, index: number }> = new Action(); 12 | clearEnteredRecoveryPhrase: Action = new Action(); 13 | acceptWalletBackupTermDevice: Action = new Action(); 14 | acceptWalletBackupTermRecovery: Action = new Action(); 15 | restartWalletBackup: Action = new Action(); 16 | cancelWalletBackup: Action = new Action(); 17 | finishWalletBackup: Action = new Action(); 18 | } 19 | -------------------------------------------------------------------------------- /app/api/ada/adaAccount.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { Wallet } from 'rust-cardano-crypto'; 3 | import { getCryptoWalletFromMasterKey } from './lib/cardanoCrypto/cryptoWallet'; 4 | import { getResultOrFail } from './lib/cardanoCrypto/cryptoUtils'; 5 | import { saveCryptoAccount } from './adaLocalStorage'; 6 | 7 | const ACCOUNT_INDEX = 0; /* Currently we only provide a SINGLE account */ 8 | 9 | export function newCryptoAccount( 10 | masterKey: string, 11 | walletPassword: string 12 | ): CryptoAccount { 13 | const cryptoAccount = createCryptoAccount(masterKey, walletPassword); 14 | saveCryptoAccount(cryptoAccount); 15 | return cryptoAccount; 16 | } 17 | 18 | export function createCryptoAccount( 19 | masterKey: string, 20 | walletPassword: string, 21 | accountIndex: number = ACCOUNT_INDEX 22 | ): CryptoAccount { 23 | const cryptoWallet = getCryptoWalletFromMasterKey(masterKey, walletPassword); 24 | const result = getResultOrFail(Wallet.newAccount(cryptoWallet, accountIndex)); 25 | return Object.assign({ account: accountIndex }, result); 26 | } 27 | -------------------------------------------------------------------------------- /app/api/ada/adaLocalStorage.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { AdaWallet } from '../ada/adaTypes'; 3 | 4 | const storageKeys = { 5 | ACCOUNT_KEY: 'ACCOUNT', 6 | WALLET_KEY: 'WALLET', 7 | LAST_BLOCK_NUMBER_KEY: 'LAST_BLOCK_NUMBER' 8 | }; 9 | 10 | export function saveCryptoAccount( 11 | ca: CryptoAccount 12 | ): void { 13 | _saveInStorage(storageKeys.ACCOUNT_KEY, ca); 14 | } 15 | 16 | export function getSingleCryptoAccount(): CryptoAccount { 17 | return _getFromStorage(storageKeys.ACCOUNT_KEY); 18 | } 19 | 20 | export function saveAdaWallet( 21 | adaWallet: AdaWallet, 22 | masterKey: string 23 | ): void { 24 | _saveInStorage(storageKeys.WALLET_KEY, { adaWallet, masterKey }); 25 | } 26 | 27 | export function getAdaWallet(): ?AdaWallet { 28 | const stored = _getFromStorage(storageKeys.WALLET_KEY); 29 | return stored ? stored.adaWallet : null; 30 | } 31 | 32 | export function getWalletMasterKey(): string { 33 | const stored = _getFromStorage(storageKeys.WALLET_KEY); 34 | return stored.masterKey; 35 | } 36 | 37 | export function saveLastBlockNumber(blockNumber: number): void { 38 | _saveInStorage(storageKeys.LAST_BLOCK_NUMBER_KEY, blockNumber); 39 | } 40 | 41 | export function getLastBlockNumber() { 42 | return _getFromStorage(storageKeys.LAST_BLOCK_NUMBER_KEY); 43 | } 44 | 45 | function _saveInStorage(key: string, toSave: any): void { 46 | localStorage.setItem(key, JSON.stringify(toSave)); 47 | } 48 | 49 | function _getFromStorage(key: string): any { 50 | const result = localStorage.getItem(key); 51 | if (result) return JSON.parse(result); 52 | return undefined; 53 | } 54 | -------------------------------------------------------------------------------- /app/api/ada/lib/cardanoCrypto/cryptoErrors.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import ExtendableError from 'es6-error'; 3 | 4 | class CardanoCryptoError extends ExtendableError { 5 | constructor(message: ?string = 'Cardano crypto error') { 6 | super(message); 7 | } 8 | } 9 | 10 | export class WrongPassphraseError extends CardanoCryptoError { 11 | constructor(message: ?string = 'Passphrase doesn\'t match') { 12 | super(message); 13 | } 14 | } 15 | 16 | export default CardanoCryptoError; 17 | -------------------------------------------------------------------------------- /app/api/ada/lib/cardanoCrypto/cryptoToModel.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import moment from 'moment'; 3 | 4 | import type { 5 | AdaWallet, 6 | AdaAddress, 7 | AdaWalletInitData 8 | } from '../../adaTypes'; 9 | 10 | 11 | /* @note: Ada wallet is the abstraction for Daedalus */ 12 | export function toAdaWallet(walletInitData : AdaWalletInitData): AdaWallet { 13 | const { cwAssurance, cwName, cwUnit } = walletInitData.cwInitMeta; 14 | return { 15 | cwAccountsNumber: 1, 16 | cwAmount: { 17 | getCCoin: 0 18 | }, 19 | cwId: '1', 20 | cwMeta: { 21 | cwAssurance, 22 | cwName, 23 | cwUnit 24 | }, 25 | cwPassphraseLU: moment().format() 26 | }; 27 | } 28 | 29 | export function toAdaAddress( 30 | accountIndex: number, 31 | addressType: AddressType, 32 | addressIndex: number, 33 | addresHash: string 34 | ): AdaAddress { 35 | return { 36 | cadAmount: { 37 | getCCoin: 0 38 | }, 39 | cadId: addresHash, 40 | cadIsUsed: false, 41 | account: accountIndex, 42 | change: getAddressTypeIndex(addressType), 43 | index: addressIndex 44 | }; 45 | } 46 | 47 | export function getAddressTypeIndex(addressType: AddressType): number { 48 | if (addressType === 'External') return 0; 49 | return 1; // addressType === 'Internal; 50 | } 51 | -------------------------------------------------------------------------------- /app/api/ada/lib/cardanoCrypto/cryptoUtils.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import CardanoCryptoError from './cryptoErrors'; 3 | 4 | export function getResultOrFail( 5 | result: any 6 | ): any { 7 | if (result.failed) { 8 | throw new CardanoCryptoError(result.msg); 9 | } 10 | return result.result; 11 | } 12 | 13 | export function getOrFail( 14 | result: ?any 15 | ): any { 16 | if (!result) { 17 | throw new CardanoCryptoError('Result not defined'); 18 | } 19 | return result; 20 | } 21 | -------------------------------------------------------------------------------- /app/api/ada/lib/utils.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import bs58 from 'bs58'; 3 | import BigNumber from 'bignumber.js'; 4 | 5 | import type { 6 | AdaTransactionInputOutput, 7 | Transaction, 8 | AdaTransaction, 9 | AdaTransactionCondition 10 | } from '../adaTypes'; 11 | 12 | export const localeDateToUnixTimestamp = 13 | (localeDate: string) => new Date(localeDate).getTime(); 14 | 15 | export function mapToList(map: any): Array { 16 | return Object.values(map); 17 | } 18 | 19 | export function getAddressInHex(address: string): string { 20 | const bytes = bs58.decode(address); 21 | return bytes.toString('hex'); 22 | } 23 | 24 | export const toAdaTx = function ( 25 | amount: BigNumber, 26 | tx: Transaction, 27 | inputs: AdaTransactionInputOutput, 28 | isOutgoing: boolean, 29 | outputs: AdaTransactionInputOutput, 30 | time: string 31 | ) : AdaTransaction { 32 | return { 33 | ctAmount: { 34 | getCCoin: amount.toString() 35 | }, 36 | ctBlockNumber: Number(tx.block_num || ''), 37 | ctId: tx.hash, 38 | ctInputs: inputs, 39 | ctIsOutgoing: isOutgoing, 40 | ctMeta: { 41 | ctmDate: new Date(time), 42 | ctmDescription: undefined, 43 | ctmTitle: undefined, 44 | ctmUpdate: new Date(tx.last_update) 45 | }, 46 | ctOutputs: outputs, 47 | ctCondition: _getTxCondition(tx.tx_state) 48 | }; 49 | }; 50 | 51 | const _getTxCondition = (state: string): AdaTransactionCondition => { 52 | if (state === 'Successful') return 'CPtxInBlocks'; 53 | if (state === 'Pending') return 'CPtxApplying'; 54 | return 'CPtxWontApply'; 55 | }; 56 | -------------------------------------------------------------------------------- /app/api/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import AdaApi from './ada/index'; 3 | import LocalStorageApi from './localStorage/index'; 4 | 5 | export type Api = { 6 | ada: AdaApi, 7 | localStorage: LocalStorageApi, 8 | }; 9 | 10 | export const setupApi = (): Api => ({ 11 | ada: new AdaApi(), 12 | localStorage: new LocalStorageApi(), 13 | }); 14 | -------------------------------------------------------------------------------- /app/assets/fonts/Electrolize-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/fonts/Electrolize-Regular.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Montserrat-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/fonts/Montserrat-Medium.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SFUIDisplay-Black.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/fonts/SFUIDisplay-Black.otf -------------------------------------------------------------------------------- /app/assets/fonts/SFUIDisplay-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/fonts/SFUIDisplay-Bold.otf -------------------------------------------------------------------------------- /app/assets/fonts/SFUIDisplay-Heavy.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/fonts/SFUIDisplay-Heavy.otf -------------------------------------------------------------------------------- /app/assets/fonts/SFUIDisplay-Light.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/fonts/SFUIDisplay-Light.otf -------------------------------------------------------------------------------- /app/assets/fonts/SFUIDisplay-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/fonts/SFUIDisplay-Medium.otf -------------------------------------------------------------------------------- /app/assets/fonts/SFUIDisplay-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/fonts/SFUIDisplay-Regular.otf -------------------------------------------------------------------------------- /app/assets/fonts/SFUIDisplay-Semibold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/fonts/SFUIDisplay-Semibold.otf -------------------------------------------------------------------------------- /app/assets/fonts/SFUIDisplay-Thin.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/fonts/SFUIDisplay-Thin.otf -------------------------------------------------------------------------------- /app/assets/fonts/SFUIDisplay-Ultralight.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/fonts/SFUIDisplay-Ultralight.otf -------------------------------------------------------------------------------- /app/assets/images/ada-symbol-big-dark.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ada-symbol-big-dark 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/assets/images/ada-symbol-smallest-dark.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5B47861B-BE78-47A7-AF40-C1783A7FA64B 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/assets/images/arrow.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 260FEF0C-330C-4259-811C-D02213760D00 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/assets/images/attention-big-light.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/assets/images/back-arrow-ic.inline.svg: -------------------------------------------------------------------------------- 1 | D3D7852F-EF60-41C7-BDB2-B25B249B24F3 -------------------------------------------------------------------------------- /app/assets/images/cert-bad-ic.inline.svg: -------------------------------------------------------------------------------- 1 | C4367A61-39B1-47D8-B1AB-63977FD542A8 -------------------------------------------------------------------------------- /app/assets/images/cert-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 6CED6A1E-A8B5-43A5-BF8E-9E8A66DC6295 -------------------------------------------------------------------------------- /app/assets/images/cert-locked-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 23C984DC-966E-4307-A6AF-80B380D9FC04 -------------------------------------------------------------------------------- /app/assets/images/clipboard-ic.inline.svg: -------------------------------------------------------------------------------- 1 | DC594E36-C8C7-4564-9AE0-3B4043CB2E42 -------------------------------------------------------------------------------- /app/assets/images/close-cross-white.inline.svg: -------------------------------------------------------------------------------- 1 | B758FE3E-D295-4A3F-8562-ED9DDAA087A0 -------------------------------------------------------------------------------- /app/assets/images/close-cross.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | C2024DD0-6A17-4259-8D44-F164E18C7F49 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/assets/images/create-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9F4F6B6E-6C34-4DF2-8581-4440A408ED77 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/assets/images/etc-logo.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/assets/images/etc-symbol.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/assets/images/expand-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 97F2FF06-0F8D-457B-90CE-8A0315A90BB5 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/assets/images/ic-check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DCF9E9D1-CA61-4DEB-87F8-DE2E41F5025C 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/assets/images/mantis-logo.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/assets/images/menu-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/assets/images/menu-opened-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/assets/images/paper-wallet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/images/paper-wallet.png -------------------------------------------------------------------------------- /app/assets/images/project-icarus-logo-shape-white.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/assets/images/receive-ic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/assets/images/search-ic-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ED8BA164-C7D2-467D-9ED0-AB0171180C5E 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/assets/images/search-ic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 329ECE4E-0BC3-43E5-BFD7-3B7E0BB39673 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/assets/images/send-ic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/assets/images/sidebar/ada-redemption-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/assets/images/sidebar/add-wallet-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6EBC478C-D021-48B6-B539-2E335BBB3F0A 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/assets/images/sidebar/bug-report-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/assets/images/sidebar/checked-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3FB7C332-FC22-4CAD-97EF-91CF60A17EC7 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/assets/images/sidebar/settings-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/assets/images/sidebar/spinner-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 35953DBC-AB60-400C-80C8-6616B7A08FA5 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/assets/images/sidebar/staking-ic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A111D335-3708-4F91-AFAF-B993C725AA37 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/assets/images/sidebar/wallet-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/assets/images/spinner-dark.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 689D1EC6-CFD1-4DB8-8399-D10FD29322A1 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/assets/images/spinner-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 689D1EC6-CFD1-4DB8-8399-D10FD29322A1 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/assets/images/spinner-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ECCC5D4D-AB98-43EC-857B-4CE840C3CA29 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/assets/images/success-small.inline.svg: -------------------------------------------------------------------------------- 1 | C1A491E1-87A9-4229-AF18-5B141E6D99B6 -------------------------------------------------------------------------------- /app/assets/images/themes/cardano.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/images/themes/cardano.png -------------------------------------------------------------------------------- /app/assets/images/themes/dark-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/images/themes/dark-blue.png -------------------------------------------------------------------------------- /app/assets/images/themes/light-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/images/themes/light-blue.png -------------------------------------------------------------------------------- /app/assets/images/top-bar/node-sync-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/images/top-bar/node-sync-error.png -------------------------------------------------------------------------------- /app/assets/images/top-bar/node-sync-spinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/images/top-bar/node-sync-spinner.png -------------------------------------------------------------------------------- /app/assets/images/top-bar/node-sync-synced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/app/assets/images/top-bar/node-sync-synced.png -------------------------------------------------------------------------------- /app/assets/images/top-bar/sticker.svg: -------------------------------------------------------------------------------- 1 | 87680249-D419-40D4-8E7F-9E58B9D0C536 -------------------------------------------------------------------------------- /app/assets/images/transaction/deny-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/assets/images/transaction/receive-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/assets/images/transaction/send-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/assets/images/wallet-nav/deny-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/assets/images/wallet-nav/receive-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/assets/images/wallet-nav/send-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/assets/images/wallet-nav/summary-ic.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/components/daedalusTransfer/DaedalusTransferErrorPage.scss: -------------------------------------------------------------------------------- 1 | @import '../../themes/mixins/error-message'; 2 | 3 | .component { 4 | display: flex; 5 | height: 100%; 6 | align-items: center; 7 | justify-content: center; 8 | } 9 | 10 | .button { 11 | margin: 20px auto 0; 12 | } 13 | 14 | .body { 15 | color: var(--theme-bordered-box-text-color); 16 | font-family: var(--font-regular); 17 | font-size: 14px; 18 | line-height: 19px; 19 | 20 | .title { 21 | font-size: 19px; 22 | font-family: var(--font-medium); 23 | line-height: 23px; 24 | margin-bottom: 6px; 25 | word-break: break-all; 26 | text-align: center; 27 | } 28 | 29 | .error { 30 | @include error-message; 31 | font-size: 16px; 32 | line-height: 22px; 33 | margin-bottom: 12px; 34 | word-break: break-word; 35 | text-align: center; 36 | } 37 | 38 | .buttonsWrapper { 39 | display: flex; 40 | flex-direction: row; 41 | justify-content: center; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/components/daedalusTransfer/DaedalusTransferFormPage.scss: -------------------------------------------------------------------------------- 1 | @import '../../themes/mixins/loading-spinner'; 2 | 3 | .component { 4 | padding: 20px; 5 | } 6 | 7 | .button { 8 | display: block !important; 9 | margin: 20px auto 0; 10 | } 11 | 12 | .body { 13 | color: var(--theme-bordered-box-text-color); 14 | font-family: var(--font-regular); 15 | font-size: 14px; 16 | line-height: 19px; 17 | 18 | .title { 19 | font-size: 11px; 20 | font-family: var(--font-medium); 21 | font-weight: 600; 22 | line-height: 1.38; 23 | margin-bottom: 4px; 24 | padding-left: 10px; 25 | text-transform: uppercase; 26 | } 27 | 28 | .text { 29 | font-size: 15px; 30 | margin-bottom: 0.3%; 31 | word-break: break-word; 32 | } 33 | 34 | .instructionsList { 35 | list-style-type: disc; 36 | list-style-position: inside; 37 | margin-bottom: 20px; 38 | } 39 | 40 | .buttonsWrapper { 41 | display: flex; 42 | flex-direction: row-reverse; 43 | justify-content: center; 44 | } 45 | 46 | .submitWithPasswordButton { 47 | &.spinning { 48 | @include loading-spinner("../../assets/images/spinner-light.svg"); 49 | } 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /app/components/daedalusTransfer/DaedalusTransferWaitingPage.scss: -------------------------------------------------------------------------------- 1 | 2 | .component { 3 | display: flex; 4 | height: 100%; 5 | align-items: center; 6 | justify-content: center; 7 | } 8 | 9 | .body { 10 | color: var(--theme-bordered-box-text-color); 11 | font-family: var(--font-regular); 12 | font-size: 14px; 13 | line-height: 19px; 14 | 15 | .title { 16 | font-size: 19px; 17 | font-family: var(--font-medium); 18 | line-height: 23px; 19 | margin-bottom: 6px; 20 | word-break: break-all; 21 | text-align: center; 22 | text-transform: uppercase; 23 | } 24 | 25 | .progressInfo { 26 | font-size: 16px; 27 | line-height: 22px; 28 | margin-bottom: 12px; 29 | word-break: break-word; 30 | text-align: center; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/components/layout/CenteredLayout.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import type { Node } from 'react'; 4 | import { observer } from 'mobx-react'; 5 | import styles from './CenteredLayout.scss'; 6 | 7 | type Props = { 8 | children: Node, 9 | }; 10 | 11 | @observer 12 | export default class CenteredLayout extends Component { 13 | 14 | static defaultProps = { 15 | children: null 16 | }; 17 | 18 | render() { 19 | const { children } = this.props; 20 | return ( 21 |

22 | {children} 23 |
24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/components/layout/CenteredLayout.scss: -------------------------------------------------------------------------------- 1 | .component { 2 | align-items: center; 3 | background-color: var(--theme-loading-background-color); 4 | display: flex; 5 | height: 100%; 6 | justify-content: center; 7 | } 8 | -------------------------------------------------------------------------------- /app/components/layout/SidebarLayout.scss: -------------------------------------------------------------------------------- 1 | $topBarHeight: 64px; 2 | 3 | .component { 4 | background: var(--theme-main-body-background-color); 5 | height: 100%; 6 | display: flex; 7 | } 8 | 9 | .main { 10 | width: 100%; 11 | height: 100%; 12 | overflow: hidden; 13 | display: flex; 14 | flex-direction: column; 15 | position: relative; 16 | } 17 | 18 | .sidebar { 19 | flex: 0 0; 20 | overflow: visible; 21 | } 22 | 23 | .topbar { 24 | height: $topBarHeight; 25 | flex-shrink: 0; 26 | // Show elements that overflow the topbar above the content area 27 | z-index: 1; 28 | } 29 | 30 | .content { 31 | height: 100%; 32 | } 33 | 34 | .contentWrapper { 35 | height: 100%; 36 | overflow-x: hidden; 37 | overflow-y: overlay; 38 | position: relative; 39 | &::-webkit-scrollbar-button { 40 | height: 7px; 41 | display: block; 42 | } 43 | } 44 | 45 | .testnetWarning { 46 | font-family: var(--font-bold); 47 | text-align: center; 48 | color: white; 49 | background-color: #b54b4b; 50 | padding: 4px; 51 | text-transform: uppercase; 52 | } 53 | -------------------------------------------------------------------------------- /app/components/layout/TextOnlyTopbar.scss: -------------------------------------------------------------------------------- 1 | .topBar { 2 | align-items: center; 3 | background: var(--theme-topbar-background-color); 4 | display: flex; 5 | height: 64px; 6 | padding: 0 20px; 7 | position: relative; 8 | z-index: 100; 9 | 10 | .topbarTitleContainer { 11 | color: var(--theme-topbar-wallet-info-color); 12 | font-family: var(--font-regular); 13 | letter-spacing: 0.5px; 14 | line-height: 23px; 15 | text-align: center; 16 | text-transform: uppercase; 17 | 18 | .topbarTitleText { 19 | font-size: 17px; 20 | font-weight: 600; 21 | color: var(--theme-topbar-wallet-name-color); 22 | } 23 | 24 | } 25 | 26 | .topBarTitle { 27 | flex-grow: 1; 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /app/components/layout/TopBar.scss: -------------------------------------------------------------------------------- 1 | .topBar { 2 | align-items: center; 3 | background: var(--theme-topbar-background-color); 4 | display: flex; 5 | height: 64px; 6 | padding: 0; 7 | position: relative; 8 | z-index: 100; 9 | 10 | &.withoutWallet {} 11 | 12 | &.withWallet { 13 | .walletInfo { 14 | color: var(--theme-topbar-wallet-info-color); 15 | font-family: var(--font-regular); 16 | letter-spacing: 0.5px; 17 | line-height: 20px; 18 | text-align: center; 19 | text-transform: uppercase; 20 | 21 | .walletName { 22 | font-size: 17px; 23 | font-weight: 600; 24 | color: var(--theme-topbar-wallet-name-color); 25 | } 26 | 27 | .walletAmount { 28 | font-size: 14px; 29 | font-weight: 300; 30 | opacity: 0.7; 31 | word-break: break-all; 32 | } 33 | } 34 | } 35 | 36 | .leftIcon { 37 | align-items: center; 38 | cursor: pointer; 39 | display: flex; 40 | height: 50px; 41 | justify-content: center; 42 | width: 50px; 43 | 44 | .sidebarIcon { 45 | & > svg { 46 | height: 17px; 47 | } 48 | 49 | path:nth-child(2) { 50 | fill: var(--theme-icon-toggle-menu-color); 51 | } 52 | } 53 | } 54 | 55 | .topBarTitle { 56 | flex-grow: 1; 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /app/components/layout/TopBarCategory.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { uniq } from 'lodash'; 4 | import SvgInline from 'react-svg-inline'; 5 | import { observer } from 'mobx-react'; 6 | import classNames from 'classnames'; 7 | import styles from './TopBarCategory.scss'; 8 | 9 | type Props = { 10 | icon: string, 11 | active: boolean, 12 | onClick: Function, 13 | className: string, 14 | }; 15 | 16 | @observer 17 | export default class TopBarCategory extends Component { 18 | render() { 19 | const { icon, active, onClick, className } = this.props; 20 | const componentStyles = classNames([ 21 | styles.component, 22 | active ? styles.active : null, 23 | className === 'supportRequest' ? styles.supportRequest : className 24 | ]); 25 | 26 | const iconStyles = classNames(uniq([ 27 | className === 'wallets' ? styles.walletsIcon : styles.icon, 28 | className === 'supportRequest' ? styles.supportRequestIcon : styles.icon 29 | ])); 30 | 31 | return ( 32 | 35 | ); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/components/layout/TopBarLayout.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import type { Node } from 'react'; 4 | import { observer } from 'mobx-react'; 5 | import styles from './TopBarLayout.scss'; 6 | 7 | type Props = { 8 | topbar: Node, 9 | children?: ?Node, 10 | notification?: ?Node, 11 | }; 12 | 13 | @observer 14 | export default class TopBarLayout extends Component { 15 | 16 | render() { 17 | const { children, topbar, notification } = this.props; 18 | return ( 19 |
20 |
21 | {topbar} 22 |
23 | {notification} 24 |
25 | {children} 26 |
27 |
28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/components/layout/TopBarLayout.scss: -------------------------------------------------------------------------------- 1 | $topBarHeight: 64px; 2 | 3 | .component { 4 | background-color: var(--theme-topbar-layout-body-background-color); 5 | box-shadow: 0 0 70px 0 rgba(0,0,0,0.75); 6 | display: flex; 7 | flex-direction: column; 8 | height: 100%; 9 | overflow: hidden; 10 | width: 100%; 11 | } 12 | 13 | .topbar { 14 | flex-shrink: 0; 15 | height: $topBarHeight; 16 | } 17 | 18 | .content { 19 | height: calc(100% - #{$topBarHeight}); 20 | } 21 | -------------------------------------------------------------------------------- /app/components/layout/VerticalFlexContainer.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import type { Node } from 'react'; 4 | import { observer } from 'mobx-react'; 5 | import styles from './VerticalFlexContainer.scss'; 6 | 7 | type Props = { 8 | children?: ?Node, 9 | }; 10 | 11 | @observer 12 | export default class VerticalFlexContainer extends Component { 13 | render() { 14 | const { children } = this.props; 15 | return ( 16 |
17 | {children} 18 |
19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/components/layout/VerticalFlexContainer.scss: -------------------------------------------------------------------------------- 1 | .component { 2 | height: 100%; 3 | display: flex; 4 | flex-direction: column; 5 | overflow-y: overlay; 6 | position: relative; 7 | 8 | &::-webkit-scrollbar-button { 9 | height: 7px; 10 | display: block; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/components/profile/language-selection/LanguageSelectionForm.scss: -------------------------------------------------------------------------------- 1 | @import '../../../themes/mixins/loading-spinner'; 2 | @import '../../../themes/mixins/error-message'; 3 | 4 | .component { 5 | align-items: center; 6 | display: flex; 7 | height: 100%; 8 | justify-content: center; 9 | } 10 | 11 | .centeredBox { 12 | overflow: visible; 13 | width: 400px; 14 | } 15 | 16 | .languageSelect { 17 | margin-bottom: 20px; 18 | } 19 | 20 | .submitButton, 21 | .submitButtonSpinning { 22 | display: block !important; 23 | margin: 0 auto; 24 | width: 100% !important; 25 | } 26 | 27 | .submitButtonSpinning { 28 | @include loading-spinner("../../../assets/images/spinner-light.svg"); 29 | } 30 | 31 | .error { 32 | @include error-message; 33 | text-align: center; 34 | margin-bottom: 1rem; 35 | } 36 | -------------------------------------------------------------------------------- /app/components/profile/terms-of-use/TermsOfUseForm.scss: -------------------------------------------------------------------------------- 1 | @import '../../../themes/mixins/loading-spinner'; 2 | @import '../../../themes/mixins/error-message'; 3 | 4 | .component { 5 | padding: 20px; 6 | height: 100%; 7 | overflow-x: hidden; 8 | overflow-y: overlay; 9 | &::-webkit-scrollbar-button { 10 | height: 7px; 11 | display: block; 12 | } 13 | } 14 | 15 | .centeredBox { 16 | margin: 0 auto; 17 | width: 600px; 18 | } 19 | 20 | .submitButton, 21 | .submitButtonSpinning { 22 | display: block !important; 23 | margin: 0 auto; 24 | width: 100% !important; 25 | } 26 | 27 | .submitButtonSpinning { 28 | @include loading-spinner("../../../assets/images/spinner-light.svg"); 29 | } 30 | 31 | .error { 32 | @include error-message; 33 | text-align: center; 34 | margin-bottom: 1rem; 35 | } 36 | 37 | .checkbox { 38 | margin-bottom: 30px; 39 | padding-top: 10px; 40 | 41 | :global .SimpleCheckbox_label { 42 | font-family: var(--font-regular); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/components/profile/terms-of-use/TermsOfUseText.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { observer } from 'mobx-react'; 4 | import ReactMarkdown from 'react-markdown'; 5 | import styles from './TermsOfUseText.scss'; 6 | 7 | type Props = { 8 | localizedTermsOfUse: string, 9 | }; 10 | 11 | @observer 12 | export default class TermsOfUseText extends Component { 13 | render() { 14 | return ( 15 |
16 | 17 |
18 | ); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /app/components/profile/terms-of-use/TermsOfUseText.scss: -------------------------------------------------------------------------------- 1 | .terms { 2 | color: var(--theme-terms-of-use-text-color); 3 | text-align: justify; 4 | 5 | h1, h2 { 6 | font-family: var(--font-medium); 7 | font-size: 17px; 8 | margin-bottom: 11px; 9 | } 10 | 11 | h2 { 12 | margin-top: 22px; 13 | } 14 | 15 | ul { 16 | list-style: disc; 17 | margin-left: 20px; 18 | } 19 | 20 | p, li { 21 | font-family: var(--font-regular); 22 | font-size: 14px; 23 | letter-spacing: 0.5px; 24 | line-height: 1.38; 25 | margin-bottom: 11px; 26 | 27 | strong { 28 | font-weight: 500; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/components/settings/SettingsLayout.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import type { Node } from 'react'; 4 | import { observer } from 'mobx-react'; 5 | import styles from './SettingsLayout.scss'; 6 | 7 | type Props = { 8 | children: Node, 9 | menu: Node, 10 | }; 11 | 12 | @observer 13 | export default class SettingsLayout extends Component { 14 | render() { 15 | const { menu, children } = this.props; 16 | return ( 17 |
18 |
19 |
20 | {children} 21 |
22 |
23 | {menu} 24 |
25 | ); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/components/settings/SettingsLayout.scss: -------------------------------------------------------------------------------- 1 | @import "./settingsConfig"; 2 | 3 | .component { 4 | background-color: var(--theme-settings-body-background-color); 5 | display: flex; 6 | height: 100%; 7 | padding: 0 20px; 8 | } 9 | 10 | .settingsPaneWrapper { 11 | flex: 1; 12 | overflow-x: hidden; 13 | overflow-y: overlay; 14 | padding: 20px 20px 20px 0; 15 | &::-webkit-scrollbar-button { 16 | height: 7px; 17 | display: block; 18 | } 19 | } 20 | 21 | .settingsPane { 22 | background-color: var(--theme-settings-pane-background-color); 23 | border: var(--theme-settings-pane-border); 24 | padding: 20px 20px 10px 20px; 25 | overflow: visible; 26 | } 27 | -------------------------------------------------------------------------------- /app/components/settings/_settingsConfig.scss: -------------------------------------------------------------------------------- 1 | @mixin borderAndBackground { 2 | background-color: var(--theme-settings-body-background-color); 3 | border-radius: 4px; 4 | border: solid 1px var(--theme-settings-pane-background-color); 5 | } -------------------------------------------------------------------------------- /app/components/settings/categories/GeneralSettings.scss: -------------------------------------------------------------------------------- 1 | @import '../../../themes/mixins/error-message'; 2 | 3 | .component { 4 | margin-bottom: 20px; 5 | } 6 | 7 | .error { 8 | @include error-message; 9 | text-align: center; 10 | } 11 | -------------------------------------------------------------------------------- /app/components/settings/categories/SupportSettings.scss: -------------------------------------------------------------------------------- 1 | @import '../../../themes/mixins/error-message'; 2 | 3 | .component { 4 | padding-bottom: 10px; 5 | 6 | h1 { 7 | color: var(--theme-support-settings-text-color); 8 | font-family: var(--font-semibold); 9 | font-size: 16px; 10 | line-height: 1.38; 11 | margin-bottom: 10px; 12 | } 13 | 14 | h1:not(:first-child) { 15 | padding-top: 10px; 16 | } 17 | 18 | a, 19 | button, 20 | p { 21 | color: var(--theme-support-settings-text-color); 22 | font-family: var(--font-regular); 23 | font-size: 14px; 24 | line-height: 19px; 25 | } 26 | 27 | a, 28 | button { 29 | color: var(--theme-support-settings-link-color); 30 | text-decoration: underline; 31 | } 32 | 33 | button { 34 | cursor: pointer; 35 | letter-spacing: 1px; 36 | } 37 | 38 | p { 39 | margin-bottom: 10px; 40 | } 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/components/settings/categories/TermsOfUseSettings.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { observer } from 'mobx-react'; 4 | import TermsOfUseText from '../../profile/terms-of-use/TermsOfUseText'; 5 | import styles from './TermsOfUseSettings.scss'; 6 | 7 | type Props = { 8 | localizedTermsOfUse: string, 9 | }; 10 | 11 | @observer 12 | export default class TermsOfUseSettings extends Component { 13 | render() { 14 | const { localizedTermsOfUse } = this.props; 15 | return ( 16 |
17 | 18 |
19 | ); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/components/settings/categories/TermsOfUseSettings.scss: -------------------------------------------------------------------------------- 1 | .component {} 2 | -------------------------------------------------------------------------------- /app/components/settings/menu/SettingsMenu.scss: -------------------------------------------------------------------------------- 1 | @import "../settingsConfig"; 2 | 3 | .component { 4 | background-color: var(--theme-settings-menu-box-background-color); 5 | border: var(--theme-settings-menu-box-border); 6 | margin: 20px 0; 7 | padding: 16px 0; 8 | width: 200px; 9 | } 10 | -------------------------------------------------------------------------------- /app/components/settings/menu/SettingsMenuItem.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { observer } from 'mobx-react'; 4 | import classNames from 'classnames'; 5 | import styles from './SettingsMenuItem.scss'; 6 | 7 | type Props = { 8 | label: string, 9 | active: boolean, 10 | onClick: Function, 11 | className: string, 12 | disabled?: boolean, 13 | }; 14 | 15 | @observer 16 | export default class SettingsMenuItem extends Component { 17 | render() { 18 | const { label, active, disabled, onClick, className } = this.props; 19 | let state = styles.enabled; 20 | if (disabled) { 21 | state = styles.disabled; 22 | } else if (active) { 23 | state = styles.active; 24 | } 25 | const componentClasses = classNames([styles.component, state, className]); 26 | return ( 27 | 28 | ); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/components/settings/menu/SettingsMenuItem.scss: -------------------------------------------------------------------------------- 1 | .component { 2 | color: var(--theme-settings-menu-item-text-color); 3 | display: block; 4 | font-family: var(--font-regular); 5 | font-size: 14px; 6 | height: 40px; 7 | line-height: 1.38; 8 | padding: 10px 20px; 9 | text-align: left; 10 | width: 100%; 11 | } 12 | 13 | .active { 14 | color: var(--theme-settings-menu-item-text-color-active); 15 | background-color: var(--theme-settings-menu-item-background-color-active); 16 | border-left: 4px solid var(--theme-settings-menu-item-left-border-color-active); 17 | font-family: var(--font-bold); 18 | padding-left: 16px; 19 | } 20 | 21 | .enabled { 22 | &:hover { 23 | color: var(--theme-settings-menu-item-text-color-enabled-hover); 24 | cursor: pointer; 25 | } 26 | } 27 | 28 | .disabled { 29 | color: var(--theme-settings-menu-item-text-color-disabled); 30 | } 31 | -------------------------------------------------------------------------------- /app/components/sidebar/Sidebar.scss: -------------------------------------------------------------------------------- 1 | @import './sidebarConfig'; 2 | 3 | .component { 4 | background-color: var(--theme-sidebar-background-color); 5 | display: flex; 6 | height: 100%; 7 | overflow: hidden; 8 | transition: width 200ms ease; 9 | width: $sidebar-width; 10 | } 11 | 12 | .minimized { 13 | flex-shrink: 0; 14 | width: 64px; 15 | } 16 | -------------------------------------------------------------------------------- /app/components/sidebar/SidebarCategory.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { uniq } from 'lodash'; 4 | import SvgInline from 'react-svg-inline'; 5 | import { observer } from 'mobx-react'; 6 | import classNames from 'classnames'; 7 | import styles from './SidebarCategory.scss'; 8 | 9 | type Props = { 10 | icon: string, 11 | active: boolean, 12 | onClick: Function, 13 | className: string, 14 | }; 15 | 16 | @observer 17 | export default class SidebarCategory extends Component { 18 | render() { 19 | const { icon, active, onClick, className } = this.props; 20 | const componentStyles = classNames([ 21 | styles.component, 22 | active ? styles.active : null, 23 | className === 'supportRequest' ? styles.supportRequest : className 24 | ]); 25 | 26 | const iconStyles = classNames(uniq([ 27 | className === 'wallets' ? styles.walletsIcon : styles.icon, 28 | className === 'supportRequest' ? styles.supportRequestIcon : styles.icon 29 | ])); 30 | 31 | return ( 32 | 35 | ); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/components/sidebar/_sidebarConfig.scss: -------------------------------------------------------------------------------- 1 | // Sizes 2 | $sidebar-width: 280px; 3 | $sidebar-minimized-category-width: 64px; 4 | $sidebar-button-height: 64px; 5 | -------------------------------------------------------------------------------- /app/components/wallet/WalletAdd.scss: -------------------------------------------------------------------------------- 1 | 2 | .component { 3 | margin-top: 20%; 4 | 5 | .buttonsContainer { 6 | display: flex; 7 | flex: 1; 8 | flex-direction: column; 9 | align-items: center; 10 | 11 | button { 12 | & + button { 13 | margin-top: 20px; 14 | } 15 | } 16 | 17 | } 18 | } 19 | 20 | .notification { 21 | color: var(--theme-transactions-list-group-date-color); 22 | font-family: var(--font-regular); 23 | font-size: 16px; 24 | line-height: 1.38; 25 | margin-top: 10px; 26 | opacity: 0.6; 27 | text-align: center; 28 | } 29 | -------------------------------------------------------------------------------- /app/components/wallet/WalletCreateDialog.scss: -------------------------------------------------------------------------------- 1 | @import '../../themes/mixins/loading-spinner'; 2 | @import '../../themes/mixins/place-form-field-error-below-input'; 3 | 4 | .walletPassword { 5 | .walletPasswordSwitch { 6 | border-top: 1px solid var(--theme-separation-border-color); 7 | margin-top: 30px; 8 | padding-top: 20px; 9 | 10 | & > .passwordLabel { 11 | color: var(--theme-wallet-password-switch-label-color); 12 | font-family: var(--font-semibold); 13 | font-size: 16px; 14 | line-height: 1.38; 15 | margin-bottom: 10px; 16 | } 17 | 18 | :global { 19 | .SimpleSwitch_root { 20 | margin-bottom: 0; 21 | } 22 | } 23 | } 24 | 25 | .walletPasswordFields { 26 | display: flex; 27 | flex-wrap: wrap; 28 | justify-content: space-between; 29 | max-height: 0; 30 | opacity: 0; 31 | overflow: hidden; 32 | transition: all 400ms ease; 33 | 34 | &.show { 35 | max-height: 250px; 36 | opacity: 1; 37 | overflow: visible; 38 | } 39 | 40 | & > div { 41 | margin-top: 30px; 42 | width: 350px; 43 | } 44 | 45 | @include place-form-field-error-below-input; 46 | 47 | .passwordInstructions { 48 | color: var(--theme-instructions-text-color); 49 | font-family: var(--font-light); 50 | line-height: 1.38; 51 | margin-top: 16px; 52 | opacity: 0.5; 53 | } 54 | } 55 | } 56 | 57 | .isSubmitting { 58 | @include loading-spinner("../../assets/images/spinner-light.svg"); 59 | } 60 | -------------------------------------------------------------------------------- /app/components/wallet/WalletSendForm.scss: -------------------------------------------------------------------------------- 1 | @import '../../themes/mixins/loading-spinner'; 2 | @import '../../themes/mixins/error-message'; 3 | 4 | .component { 5 | padding: 20px; 6 | } 7 | 8 | .amountInput, 9 | .receiverInput { 10 | position: relative; 11 | margin-bottom: 20px; 12 | } 13 | 14 | .adaLabel { 15 | bottom: 16px; 16 | color: var(--theme-input-right-floating-text-color); 17 | font-family: var(--font-light); 18 | position: absolute; 19 | right: 20px; 20 | text-transform: uppercase; 21 | } 22 | 23 | .nextButton { 24 | display: block !important; 25 | margin: 30px auto 0; 26 | } 27 | 28 | .contentWarning{ 29 | display: flex; 30 | flex-flow: column; 31 | align-items: center; 32 | margin-bottom: 1em; 33 | } 34 | 35 | .icon { 36 | flex-shrink: 0; 37 | & > svg { 38 | width: 26px; 39 | height: 26px; 40 | } 41 | margin: 1em 0; 42 | } 43 | 44 | .warning { 45 | font-family: var(--font-light); 46 | text-transform: uppercase; 47 | font-size: 12px; 48 | font-weight: 600; 49 | margin-bottom: 0.5em; 50 | color: #daa49a; 51 | } -------------------------------------------------------------------------------- /app/components/wallet/backup-recovery/MnemonicWord.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { observer } from 'mobx-react'; 4 | import classnames from 'classnames'; 5 | import Button from 'react-polymorph/lib/components/Button'; 6 | import SimpleButtonSkin from 'react-polymorph/lib/skins/simple/raw/ButtonSkin'; 7 | import styles from './MnemonicWord.scss'; 8 | 9 | type Props = { 10 | word: string, 11 | index: number, 12 | isActive: boolean, 13 | onClick: Function, 14 | }; 15 | 16 | @observer 17 | export default class MnemonicWord extends Component { 18 | 19 | render() { 20 | const { word, index, isActive, onClick } = this.props; 21 | const componentClassNames = classnames([ 22 | 'flat', 23 | styles.component, 24 | isActive ? styles.active : styles.inactive 25 | ]); 26 | return ( 27 | 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/components/wallet/navigation/WalletNavigation.scss: -------------------------------------------------------------------------------- 1 | .component { 2 | display: flex; 3 | height: 100%; 4 | justify-content: space-between; 5 | } 6 | 7 | .navItem { 8 | height: 100%; 9 | width: percentage(1/3); // Update when adding new nav items! 10 | background-color: var(--theme-nav-item-background-color); 11 | } 12 | -------------------------------------------------------------------------------- /app/components/wallet/skins/AmountInputSkin.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { defineMessages, intlShape } from 'react-intl'; 3 | import BigNumber from 'bignumber.js'; 4 | import InputSkin from 'react-polymorph/lib/skins/simple/raw/InputSkin'; 5 | import styles from './AmountInputSkin.scss'; 6 | 7 | export const messages = defineMessages({ 8 | feesLabel: { 9 | id: 'wallet.amountInput.feesLabel', 10 | defaultMessage: '!!!+ {amount} of fees', 11 | description: 'Label for the "+ 12.042481 of fees" message above amount input field.' 12 | }, 13 | }); 14 | 15 | type Props = { 16 | currency: string, 17 | fees: BigNumber, 18 | total: BigNumber, 19 | error: boolean, 20 | }; 21 | 22 | export default class AmountInputSkin extends Component { 23 | 24 | static contextTypes = { 25 | intl: intlShape.isRequired, 26 | }; 27 | 28 | render() { 29 | const { error, fees, total, currency } = this.props; 30 | const { intl } = this.context; 31 | 32 | return ( 33 |
34 | 35 | {!error && ( 36 | 37 | {intl.formatMessage(messages.feesLabel, { amount: fees })} 38 | 39 | )} 40 | 41 | {!error && `= ${total} `}{currency} 42 | 43 |
44 | ); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /app/components/wallet/skins/AmountInputSkin.scss: -------------------------------------------------------------------------------- 1 | .root { 2 | position: relative; 3 | } 4 | 5 | .fees { 6 | position: absolute; 7 | bottom: 46px; 8 | right: 10px; 9 | color: var(--theme-input-right-floating-text-color); 10 | font-family: var(--font-regular); 11 | font-size: 11px; 12 | } 13 | 14 | .total { 15 | position: absolute; 16 | bottom: 12px; 17 | right: 10px; 18 | color: var(--theme-input-right-floating-text-color); 19 | font-family: var(--font-light); 20 | font-size: 15px; 21 | text-transform: uppercase; 22 | } 23 | -------------------------------------------------------------------------------- /app/components/wallet/transactions/TransactionTypeIcon.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import classNames from 'classnames'; 4 | import SvgInline from 'react-svg-inline'; 5 | import expendIcon from '../../../assets/images/transaction/send-ic.inline.svg'; 6 | import incomeIcon from '../../../assets/images/transaction/receive-ic.inline.svg'; 7 | import exchangeIcon from '../../../assets/images/exchange-ic.inline.svg'; 8 | import failedIcon from '../../../assets/images/transaction/deny-ic.inline.svg'; 9 | import styles from './TransactionTypeIcon.scss'; 10 | 11 | type Props = { 12 | iconType: string, 13 | }; 14 | 15 | export default class TransactionTypeIcon extends Component { 16 | 17 | render() { 18 | const { iconType } = this.props; 19 | 20 | const transactionTypeIconClasses = classNames([ 21 | styles.transactionTypeIconWrapper, 22 | styles[iconType], 23 | ]); 24 | 25 | let icon; 26 | switch (iconType) { 27 | case 'expend': 28 | icon = expendIcon; 29 | break; 30 | case 'income': 31 | icon = incomeIcon; 32 | break; 33 | case 'exchange': 34 | icon = exchangeIcon; 35 | break; 36 | case 'failed': 37 | icon = failedIcon; 38 | break; 39 | default: 40 | icon = ''; 41 | break; 42 | } 43 | 44 | return ( 45 |
46 | 47 |
48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/components/wallet/transactions/TransactionTypeIcon.scss: -------------------------------------------------------------------------------- 1 | .transactionTypeIconWrapper { 2 | align-items: center; 3 | display: flex; 4 | flex-direction: column; 5 | height: 44px; 6 | justify-content: center; 7 | width: 24px; 8 | 9 | &.expend { 10 | svg path { 11 | fill: var(--theme-transactions-icon-type-expend-background-color); 12 | } 13 | } 14 | 15 | &.income { 16 | svg path { 17 | fill: var(--theme-transactions-icon-type-income-background-color); 18 | } 19 | } 20 | 21 | &.exchange { 22 | svg path { 23 | fill: var(--theme-transactions-icon-type-exchange-background-color); 24 | } 25 | } 26 | 27 | &.failed { 28 | svg path { 29 | fill: var(--theme-transactions-icon-type-failed-background-color); 30 | } 31 | .transactionTypeIcon > svg { 32 | height: 16px; 33 | width: 22px; 34 | } 35 | } 36 | } 37 | 38 | .transactionTypeIcon { 39 | display: flex; 40 | 41 | & > svg { 42 | height: 19px; 43 | width: 23px; 44 | path { 45 | fill: var(--theme-icon-transaction-type-color); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/components/wallet/transactions/WalletNoTransactions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { observer } from 'mobx-react'; 4 | import styles from './WalletNoTransactions.scss'; 5 | 6 | type Props = { 7 | label: string, 8 | }; 9 | 10 | @observer 11 | export default class WalletNoTransactions extends Component { 12 | 13 | render() { 14 | return ( 15 |
16 |
{this.props.label}
17 |
18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/components/wallet/transactions/WalletNoTransactions.scss: -------------------------------------------------------------------------------- 1 | .component { 2 | height: 100%; 3 | display: flex; 4 | align-items: center; 5 | justify-content: center; 6 | } 7 | 8 | .label { 9 | opacity: 0.5; 10 | font-size: 15px; 11 | line-height: 1.38; 12 | font-family: var(--font-regular); 13 | color: var(--theme-main-body-messages-color); 14 | } 15 | -------------------------------------------------------------------------------- /app/components/wallet/transactions/WalletTransactionsList.scss: -------------------------------------------------------------------------------- 1 | .component { 2 | padding: 20px 20px 0; 3 | } 4 | 5 | .list { 6 | background-color: var(--theme-transactions-list-background-color); 7 | background-blend-mode: lighten; 8 | border: solid 1px var(--theme-transactions-list-border-color); 9 | margin-bottom: 20px; 10 | 11 | &:last-child { 12 | margin: 0; 13 | } 14 | } 15 | 16 | .group { 17 | margin-top: 20px; 18 | 19 | &:first-child { 20 | margin-top: 0; 21 | } 22 | 23 | &:last-child { 24 | margin-bottom: 20px; 25 | } 26 | } 27 | 28 | .groupDate { 29 | font-family: var(--font-regular); 30 | font-size: 12px; 31 | font-weight: 600; 32 | color: var(--theme-transactions-list-group-date-color); 33 | margin-bottom: 10px; 34 | text-align: center; 35 | text-transform: uppercase; 36 | } 37 | 38 | .showMoreTransactionsButton { 39 | display: block !important; 40 | margin: 30px auto; 41 | } 42 | -------------------------------------------------------------------------------- /app/components/widgets/BigButtonForDialogs.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import classnames from 'classnames'; 3 | import styles from './BigButtonForDialogs.scss'; 4 | 5 | type Props = { 6 | label: string, 7 | description: string, 8 | onClick: Function, 9 | isDisabled: boolean, 10 | className: string, 11 | }; 12 | 13 | export default class BigButtonForDialogs extends Component { 14 | 15 | render() { 16 | const { label, description, onClick, isDisabled = false, className } = this.props; 17 | const componentClasses = classnames([ 18 | className, 19 | styles.component, 20 | isDisabled ? styles.disabled : null 21 | ]); 22 | return ( 23 | 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/components/widgets/BigButtonForDialogs.scss: -------------------------------------------------------------------------------- 1 | .component { 2 | background-color: var(--theme-dialog-big-button-background-color); 3 | border: solid 4px var(--theme-dialog-big-button-border-color); 4 | display: flex; 5 | flex: 1; 6 | flex-direction: column; 7 | align-items: center; 8 | justify-content: center; 9 | cursor: pointer; 10 | margin: 10px; 11 | padding: 30px; 12 | } 13 | 14 | .disabled { 15 | opacity: 0.6; 16 | cursor: default; 17 | } 18 | 19 | .label { 20 | font-size: 19px; 21 | line-height: 1.37; 22 | color: var(--theme-dialog-big-button-label-color); 23 | font-family: var(--font-medium); 24 | } 25 | 26 | .description { 27 | font-family: var(--font-regular); 28 | height: 19px; 29 | font-size: 14px; 30 | line-height: 1.36; 31 | color: var(--theme-dialog-big-button-description-color); 32 | } 33 | -------------------------------------------------------------------------------- /app/components/widgets/BorderedBox.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import type { Node } from 'react'; 4 | import { observer } from 'mobx-react'; 5 | import styles from './BorderedBox.scss'; 6 | 7 | type Props = { 8 | children?: Node, 9 | }; 10 | 11 | @observer 12 | export default class BorderedBox extends Component { 13 | 14 | render() { 15 | const { children } = this.props; 16 | return ( 17 |
18 | {children} 19 |
20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/components/widgets/BorderedBox.scss: -------------------------------------------------------------------------------- 1 | .component { 2 | background: var(--theme-bordered-box-background-color); 3 | border: var(--theme-bordered-box-border); 4 | padding: 20px; 5 | } 6 | -------------------------------------------------------------------------------- /app/components/widgets/Dialog.scss: -------------------------------------------------------------------------------- 1 | .dialogWrapper { 2 | color: var(--theme-dialog-title-color); 3 | display: flex; 4 | flex: 1; 5 | flex-direction: column; 6 | position: relative; 7 | 8 | & > .title { 9 | font-family: var(--font-medium); 10 | font-size: 15px; 11 | line-height: 1.39; 12 | letter-spacing: 2px; 13 | margin-bottom: 20px; 14 | text-align: center; 15 | text-transform: uppercase; 16 | } 17 | 18 | & > .content { 19 | flex: 1; 20 | margin-right: -24px; 21 | overflow-x: hidden; 22 | overflow-y: overlay; 23 | padding-right: 24px; 24 | } 25 | 26 | & > .actions { 27 | display: flex; 28 | flex-shrink: 0; 29 | margin-top: 20px; 30 | 31 | button { 32 | width: 50%; 33 | 34 | &:only-child { 35 | margin: auto; 36 | width: 100%; 37 | } 38 | 39 | & + button { 40 | margin-left: 20px; 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/components/widgets/DialogBackButton.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import SvgInline from 'react-svg-inline'; 3 | import backArrow from '../../assets/images/back-arrow-ic.inline.svg'; 4 | import styles from './DialogBackButton.scss'; 5 | 6 | type Props = { 7 | onBack: Function 8 | }; 9 | 10 | export default class DialogBackButton extends Component { 11 | 12 | render() { 13 | const { onBack } = this.props; 14 | return ( 15 | 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/components/widgets/DialogBackButton.scss: -------------------------------------------------------------------------------- 1 | .component { 2 | position: absolute; 3 | top: 4px; 4 | left: 0; 5 | cursor: pointer; 6 | svg { 7 | width: 20px; 8 | height: 16px; 9 | path { 10 | fill: var(--theme-icon-back-button-color); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /app/components/widgets/DialogCloseButton.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import SvgInline from 'react-svg-inline'; 3 | import closeCross from '../../assets/images/close-cross.inline.svg'; 4 | import styles from './DialogCloseButton.scss'; 5 | 6 | type Props = { 7 | onClose: Function, 8 | icon?: string, 9 | }; 10 | 11 | export default class DialogCloseButton extends Component { 12 | 13 | render() { 14 | const { onClose, icon } = this.props; 15 | return ( 16 | 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/components/widgets/DialogCloseButton.scss: -------------------------------------------------------------------------------- 1 | .component { 2 | position: absolute; 3 | top: 4px; 4 | right: 0; 5 | cursor: pointer; 6 | svg { 7 | width: 11px; 8 | height: 11px; 9 | polygon { 10 | fill: var(--theme-icon-close-button-color); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/components/widgets/LoadingSpinner.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import styles from './LoadingSpinner.scss'; 4 | 5 | export default class LoadingSpinner extends Component { 6 | 7 | root: ?HTMLElement; 8 | 9 | render() { 10 | return
{ this.root = div; }} />; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/components/widgets/LoadingSpinner.scss: -------------------------------------------------------------------------------- 1 | .component { 2 | margin: 20px auto; 3 | width: 30px; 4 | height: 30px; 5 | background: url("../../assets/images/spinner-dark.svg") no-repeat center; 6 | background-size: 30px; 7 | :global { 8 | animation: loading-spin 1.5s linear; 9 | animation-iteration-count: infinite; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/components/widgets/NotificationMessage.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import type { Children } from 'react'; 3 | import SvgInline from 'react-svg-inline'; 4 | import classNames from 'classnames'; 5 | import styles from './NotificationMessage.scss'; 6 | 7 | type Props = { 8 | icon: string, 9 | show: boolean, 10 | children?: Children, 11 | }; 12 | 13 | export default class NotificationMessage extends Component { 14 | 15 | render() { 16 | const { icon, show, children } = this.props; 17 | 18 | const notificationMessageStyles = classNames([ 19 | styles.component, 20 | show ? styles.show : null, 21 | ]); 22 | 23 | return ( 24 |
25 | 26 | {icon && } 27 | 28 |
29 | {children} 30 |
31 | 32 |
33 | ); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/components/widgets/NotificationMessage.scss: -------------------------------------------------------------------------------- 1 | .component { 2 | background-color: var(--theme-notification-message-background-color); 3 | height: 0; 4 | overflow: hidden; 5 | position: absolute; 6 | text-align: center; 7 | transition: all 200ms linear; 8 | width: 100%; 9 | } 10 | 11 | .show { 12 | height: 40px; 13 | padding: 0; 14 | } 15 | 16 | .icon { 17 | display: inline-block; 18 | vertical-align: top; 19 | & > svg { 20 | height: 40px; 21 | width: 40px; 22 | } 23 | } 24 | 25 | .message { 26 | color: var(--theme-notification-message-text-color); 27 | display: inline-block; 28 | font-family: var(--font-regular); 29 | font-size: 14px; 30 | font-weight: 500; 31 | letter-spacing: normal; 32 | line-height: 40px; 33 | } 34 | -------------------------------------------------------------------------------- /app/components/widgets/forms/ReadOnlyInput.scss: -------------------------------------------------------------------------------- 1 | .component { 2 | margin-bottom: 32px; 3 | position: relative; 4 | 5 | :global { 6 | .SimpleFormField_root { 7 | .SimpleFormField_label { 8 | color: var(--theme-input-label-color); 9 | } 10 | } 11 | 12 | .SimpleInput_disabled { 13 | background: none; 14 | & .SimpleInput_input { 15 | background-color: var(--theme-input-background-color); 16 | border-color: var(--theme-input-border-color); 17 | color: var(--theme-input-text-color) !important; 18 | } 19 | } 20 | } 21 | 22 | .button { 23 | bottom: 10px; 24 | color: var(--theme-label-button-color); 25 | cursor: pointer; 26 | font-family: var(--font-light); 27 | font-size: 16px; 28 | line-height: 1.38; 29 | opacity: 0.5; 30 | position: absolute; 31 | right: 22px; 32 | text-transform: lowercase; 33 | &:hover { 34 | opacity: 1; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | wallets: { 3 | ADDRESS_COPY_NOTIFICATION_DURATION: 10, 4 | MAX_ALLOWED_UNUSED_ADDRESSES: 20, 5 | TRANSACTION_REQUEST_SIZE: 20 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /app/config/numbersConfig.js: -------------------------------------------------------------------------------- 1 | import BigNumber from 'bignumber.js'; 2 | 3 | export const LOVELACES_PER_ADA = 1000000; 4 | export const WEI_PER_ETC = 1000000000000000000; 5 | export const MAX_INTEGER_PLACES_IN_ADA = 11; 6 | export const DECIMAL_PLACES_IN_ADA = 6; 7 | export const DECIMAL_PLACES_IN_ETC = 18; 8 | export const ETC_DEFAULT_GAS_PRICE = new BigNumber(10).pow(10).times(2); 9 | -------------------------------------------------------------------------------- /app/config/sidebarConfig.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { ROUTES } from '../routes-config'; 3 | import walletsIcon from '../assets/images/project-icarus-logo-shape-white.inline.svg'; 4 | import settingsIcon from '../assets/images/sidebar/settings-ic.inline.svg'; 5 | import daedalusTransferIcon from '../assets/images/sidebar/daedalus-transfer.inline.svg'; 6 | 7 | export const CATEGORIES = [ 8 | { 9 | name: 'WALLETS', 10 | route: ROUTES.WALLETS.ROOT, 11 | icon: walletsIcon, 12 | }, 13 | { 14 | name: 'DAEDALUS_TRANSFER', 15 | route: ROUTES.DAEDALUS_TRANFER.ROOT, 16 | icon: daedalusTransferIcon, 17 | }, 18 | { 19 | name: 'SETTINGS', 20 | route: ROUTES.SETTINGS.ROOT, 21 | icon: settingsIcon, 22 | }, 23 | ]; 24 | -------------------------------------------------------------------------------- /app/config/transactionAssuranceConfig.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { 3 | AssuranceMode, AssuranceLevel, AssuranceModeOption, 4 | } from '../types/transactionAssuranceTypes'; 5 | 6 | export const assuranceModeOptions: { 7 | NORMAL: AssuranceModeOption, STRICT: AssuranceModeOption, 8 | } = { 9 | NORMAL: 'CWANormal', STRICT: 'CWAStrict', 10 | }; 11 | 12 | export const assuranceModes: { NORMAL: AssuranceMode, STRICT: AssuranceMode } = { 13 | NORMAL: { 14 | low: 3, 15 | medium: 9, 16 | }, 17 | STRICT: { 18 | low: 5, 19 | medium: 15, 20 | } 21 | }; 22 | 23 | export const assuranceLevels: { 24 | LOW: AssuranceLevel, MEDIUM: AssuranceLevel, HIGH: AssuranceLevel, 25 | } = { 26 | LOW: 'low', MEDIUM: 'medium', HIGH: 'high', 27 | }; 28 | -------------------------------------------------------------------------------- /app/containers/LoadingPage.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { inject, observer } from 'mobx-react'; 4 | import { defineMessages } from 'react-intl'; 5 | import CenteredLayout from '../components/layout/CenteredLayout'; 6 | import Loading from '../components/loading/Loading'; 7 | import adaLogo from '../assets/images/ada-logo.inline.svg'; 8 | import cardanoLogo from '../assets/images/cardano-logo.inline.svg'; 9 | import type { InjectedProps } from '../types/injectedPropsType'; 10 | 11 | export const messages = defineMessages({ 12 | loading: { 13 | id: 'loading.screen.loading', 14 | defaultMessage: '!!!loading components', 15 | description: 'Message "loading components" on the loading screen.' 16 | }, 17 | }); 18 | 19 | @inject('stores', 'actions') @observer 20 | export default class LoadingPage extends Component { 21 | 22 | render() { 23 | const { stores } = this.props; 24 | const { loading } = stores; 25 | const { hasLoadedCurrentLocale, hasLoadedCurrentTheme } = { 26 | hasLoadedCurrentLocale: true, 27 | hasLoadedCurrentTheme: true, 28 | }; 29 | return ( 30 | 31 | 40 | 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/containers/MainLayout.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { observer, inject } from 'mobx-react'; 4 | import type { Node } from 'react'; 5 | import TopBarContainer from './TopBarContainer'; 6 | import SidebarLayout from '../components/layout/SidebarLayout'; 7 | import type { StoresMap } from '../stores/index'; 8 | import type { ActionsMap } from '../actions/index'; 9 | 10 | export type MainLayoutProps = { 11 | stores: any | StoresMap, 12 | actions: any | ActionsMap, 13 | children: Node, 14 | topbar: ?any 15 | }; 16 | 17 | @inject('stores', 'actions') @observer 18 | export default class MainLayout extends Component { 19 | static defaultProps = { 20 | actions: null, 21 | stores: null, 22 | children: null, 23 | topbar: null, 24 | onClose: () => {} 25 | }; 26 | 27 | render() { 28 | const { actions, stores, topbar } = this.props; 29 | const topbarComponent = topbar || (); 30 | return ( 31 | } 34 | contentDialogs={[]} 35 | > 36 | {this.props.children} 37 | 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/containers/TopBarContainer.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { observer } from 'mobx-react'; 4 | import TopBar from '../components/layout/TopBar'; 5 | import type { InjectedProps } from '../types/injectedPropsType'; 6 | import environment from '../environment'; 7 | import resolver from '../utils/imports'; 8 | 9 | const { formattedWalletAmount } = resolver('utils/formatters'); 10 | 11 | type Props = InjectedProps; 12 | 13 | @observer 14 | export default class TopBarContainer extends Component { 15 | static defaultProps = { actions: null, stores: null }; 16 | 17 | render() { 18 | const { actions, stores } = this.props; 19 | const { app, sidebar } = stores; 20 | 21 | return ( 22 | { 28 | actions.sidebar.activateSidebarCategory.trigger({ category }); 29 | }} 30 | categories={sidebar.CATEGORIES} 31 | activeSidebarCategory={sidebar.activeSidebarCategory} 32 | /> 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/containers/settings/categories/GeneralSettingsPage.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { observer, inject } from 'mobx-react'; 4 | import GeneralSettings from '../../../components/settings/categories/GeneralSettings'; 5 | import type { InjectedProps } from '../../../types/injectedPropsType'; 6 | 7 | @inject('stores', 'actions') @observer 8 | export default class GeneralSettingsPage extends Component { 9 | 10 | static defaultProps = { actions: null, stores: null }; 11 | 12 | onSelectLanguage = (values: { locale: string }) => { 13 | this.props.actions.profile.updateLocale.trigger(values); 14 | }; 15 | 16 | render() { 17 | const { setProfileLocaleRequest, LANGUAGE_OPTIONS, currentLocale } = this.props.stores.profile; 18 | const isSubmitting = setProfileLocaleRequest.isExecuting; 19 | return ( 20 | 27 | ); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/containers/settings/categories/SupportSettingsPage.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { observer, inject } from 'mobx-react'; 4 | import { handleExternalLinkClick } from '../../../utils/routing'; 5 | import SupportSettings from '../../../components/settings/categories/SupportSettings'; 6 | import { downloadLogs } from '../../../../app/utils/logging'; 7 | import type { InjectedProps } from '../../../types/injectedPropsType'; 8 | 9 | @inject('stores', 'actions') @observer 10 | export default class SupportSettingsPage extends Component { 11 | 12 | static defaultProps = { actions: null, stores: null }; 13 | 14 | handleDownloadLogs = () => { 15 | downloadLogs(); 16 | }; 17 | 18 | render() { 19 | return ( 20 | 24 | ); 25 | } 26 | 27 | } 28 | 29 | -------------------------------------------------------------------------------- /app/containers/settings/categories/TermsOfUseSettingsPage.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { observer, inject } from 'mobx-react'; 4 | import TermsOfUseSettings from '../../../components/settings/categories/TermsOfUseSettings'; 5 | import type { InjectedProps } from '../../../types/injectedPropsType'; 6 | 7 | @inject('stores') @observer 8 | export default class TermsOfUseSettingsPage extends Component { 9 | 10 | static defaultProps = { actions: null, stores: null }; 11 | 12 | render() { 13 | const { termsOfUse } = this.props.stores.profile; 14 | return ( 15 | 16 | ); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/containers/wallet/NoWalletsPage.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { observer, inject } from 'mobx-react'; 4 | import resolver from '../../utils/imports'; 5 | 6 | const Layout = resolver('containers/MainLayout'); 7 | 8 | @inject('stores', 'actions') @observer 9 | export default class NoWalletsPage extends Component { 10 | 11 | render() { 12 | return ( 13 | 14 |
15 | 16 | ); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/containers/wallet/dialogs/WalletCreateDialogContainer.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { observer, inject } from 'mobx-react'; 4 | import WalletCreateDialog from '../../../components/wallet/WalletCreateDialog'; 5 | import type { InjectedDialogContainerProps } from '../../../types/injectedPropsType'; 6 | import environment from '../../../environment'; 7 | 8 | type Props = InjectedDialogContainerProps; 9 | 10 | @inject('stores', 'actions') @observer 11 | export default class WalletCreateDialogContainer extends Component { 12 | 13 | static defaultProps = { actions: null, stores: null, children: null, onClose: () => {} }; 14 | 15 | onSubmit = (values: { name: string, password: string }) => { 16 | this.props.actions[environment.API].wallets.createWallet.trigger(values); 17 | }; 18 | 19 | render() { 20 | return ( 21 | 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/domain/Wallet.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { observable, computed } from 'mobx'; 3 | import BigNumber from 'bignumber.js'; 4 | import type { AssuranceMode, AssuranceModeOption } from '../types/transactionAssuranceTypes'; 5 | import { assuranceModes, assuranceModeOptions } from '../config/transactionAssuranceConfig'; 6 | 7 | export default class Wallet { 8 | 9 | id: string = ''; 10 | address: string = 'current address'; 11 | @observable name: string = ''; 12 | @observable amount: BigNumber; 13 | @observable assurance: AssuranceModeOption; 14 | @observable passwordUpdateDate: ?Date; 15 | 16 | constructor(data: { 17 | id: string, 18 | name: string, 19 | amount: BigNumber, 20 | assurance: AssuranceModeOption, 21 | passwordUpdateDate: ?Date, 22 | }) { 23 | Object.assign(this, data); 24 | } 25 | 26 | updateAmount(amount: BigNumber): void { 27 | this.amount = amount; 28 | } 29 | 30 | @computed get assuranceMode(): AssuranceMode { 31 | switch (this.assurance) { 32 | case assuranceModeOptions.NORMAL: return assuranceModes.NORMAL; 33 | case assuranceModeOptions.STRICT: return assuranceModes.STRICT; 34 | default: return assuranceModes.NORMAL; 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/domain/WalletAddress.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { observable } from 'mobx'; 3 | import BigNumber from 'bignumber.js'; 4 | 5 | export default class WalletAddress { 6 | 7 | @observable id: string = ''; 8 | @observable amount: BigNumber; 9 | @observable isUsed: boolean = false; 10 | 11 | constructor(data: { 12 | id: string, 13 | amount: BigNumber, 14 | isUsed: boolean, 15 | }) { 16 | Object.assign(this, data); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/environment.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import os from 'os'; 3 | import type { ConfigType } from '../config/config-types'; 4 | 5 | declare var CONFIG: ConfigType; 6 | 7 | const environment = Object.assign({ 8 | DEVELOPMENT: 'development', 9 | TEST: 'test', 10 | PRODUCTION: 'production', 11 | NETWORK: CONFIG.network.name, 12 | API: process.env.API || 'ada', 13 | MOBX_DEV_TOOLS: process.env.MOBX_DEV_TOOLS, 14 | current: process.env.NODE_ENV, 15 | REPORT_URL: process.env.REPORT_URL || 'http://report-server.awstest.iohkdev.io:8080/', 16 | isDev: () => environment.current === environment.DEVELOPMENT, 17 | isTest: () => environment.current === environment.TEST, 18 | isMainnet: () => environment.NETWORK === 'mainnet', 19 | isAdaApi: () => environment.API === 'ada', 20 | isEtcApi: () => environment.API === 'etc', 21 | build: process.env.DAEDALUS_VERSION || 'dev', 22 | platform: os.platform(), 23 | walletRefreshInterval: CONFIG.app.walletRefreshInterval, 24 | }, process.env); 25 | 26 | export default environment; 27 | -------------------------------------------------------------------------------- /app/i18n/LocalizableError.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import ExtendableError from 'es6-error'; 3 | import { defineMessages } from 'react-intl'; 4 | 5 | const messages = defineMessages({ 6 | unknowError: { 7 | id: 'app.errors.unknowError', 8 | defaultMessage: '!!!Unknow error.', 9 | description: 'Unknow error message.' 10 | }, 11 | }); 12 | 13 | class LocalizableError extends ExtendableError { 14 | constructor( 15 | { id, defaultMessage, values = {} }: 16 | { id: string, defaultMessage: string, values?: Object} 17 | ) { 18 | if (!id) throw new Error('id:string is required.'); 19 | if (!defaultMessage) throw new Error('defaultMessage:string is required.'); 20 | super(`${id}: ${JSON.stringify(values)}`); 21 | this.id = id; 22 | this.defaultMessage = defaultMessage; 23 | this.values = values; 24 | } 25 | } 26 | 27 | class UnknowError extends LocalizableError { 28 | constructor() { 29 | super({ 30 | id: messages.unknowError.id, 31 | defaultMessage: messages.unknowError.defaultMessage, 32 | }); 33 | } 34 | } 35 | 36 | export function localizedError(error: any): LocalizableError { 37 | if (error instanceof LocalizableError) { 38 | return error; 39 | } 40 | return new UnknowError(); 41 | } 42 | 43 | export default LocalizableError; 44 | -------------------------------------------------------------------------------- /app/i18n/locales/terms-of-use/ada/mainnet/en-US.md: -------------------------------------------------------------------------------- 1 | # Terms of Service Agreement 2 | 3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam metus lectus, luctus ut porta sit amet, bibendum nec enim. Donec vel consequat diam. Aenean et ex laoreet, hendrerit metus luctus, pulvinar lectus. Ut posuere pretium erat, non malesuada sapien condimentum in. Duis quis lorem auctor, luctus dolor non, interdum quam. Cras vel enim varius, consequat quam at, blandit dolor. Phasellus lacinia enim volutpat libero vehicula, in malesuada erat vestibulum. In eu placerat nunc, eget rutrum orci. Quisque ut odio id erat iaculis gravida. 4 | 5 | Donec mauris purus, sagittis eget ipsum in, hendrerit auctor odio. Duis vestibulum blandit tellus eget convallis. Donec velit libero, mattis id lectus a, euismod facilisis dui. Nulla odio dui, euismod id turpis nec, interdum dignissim dui. Nunc non odio non nulla varius fermentum. Maecenas vulputate metus a metus sodales dapibus. Pellentesque gravida enim nunc. Pellentesque venenatis odio nec enim blandit, hendrerit fermentum urna ornare. Praesent accumsan id tortor ut maximus. Aliquam nulla tellus, scelerisque vel faucibus eu, dapibus vitae tellus. Nulla facilisi. 6 | -------------------------------------------------------------------------------- /app/i18n/locales/terms-of-use/ada/mainnet/ja-JP.md: -------------------------------------------------------------------------------- 1 | # サービス規約 2 | 3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam metus lectus, luctus ut porta sit amet, bibendum nec enim. Donec vel consequat diam. Aenean et ex laoreet, hendrerit metus luctus, pulvinar lectus. Ut posuere pretium erat, non malesuada sapien condimentum in. Duis quis lorem auctor, luctus dolor non, interdum quam. Cras vel enim varius, consequat quam at, blandit dolor. Phasellus lacinia enim volutpat libero vehicula, in malesuada erat vestibulum. In eu placerat nunc, eget rutrum orci. Quisque ut odio id erat iaculis gravida. 4 | 5 | Donec mauris purus, sagittis eget ipsum in, hendrerit auctor odio. Duis vestibulum blandit tellus eget convallis. Donec velit libero, mattis id lectus a, euismod facilisis dui. Nulla odio dui, euismod id turpis nec, interdum dignissim dui. Nunc non odio non nulla varius fermentum. Maecenas vulputate metus a metus sodales dapibus. Pellentesque gravida enim nunc. Pellentesque venenatis odio nec enim blandit, hendrerit fermentum urna ornare. Praesent accumsan id tortor ut maximus. Aliquam nulla tellus, scelerisque vel faucibus eu, dapibus vitae tellus. Nulla facilisi. 6 | -------------------------------------------------------------------------------- /app/i18n/locales/terms-of-use/ada/mainnet/ko-KR.md: -------------------------------------------------------------------------------- 1 | # 서비스 규약 2 | 3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam metus lectus, luctus ut porta sit amet, bibendum nec enim. Donec vel consequat diam. Aenean et ex laoreet, hendrerit metus luctus, pulvinar lectus. Ut posuere pretium erat, non malesuada sapien condimentum in. Duis quis lorem auctor, luctus dolor non, interdum quam. Cras vel enim varius, consequat quam at, blandit dolor. Phasellus lacinia enim volutpat libero vehicula, in malesuada erat vestibulum. In eu placerat nunc, eget rutrum orci. Quisque ut odio id erat iaculis gravida. 4 | 5 | Donec mauris purus, sagittis eget ipsum in, hendrerit auctor odio. Duis vestibulum blandit tellus eget convallis. Donec velit libero, mattis id lectus a, euismod facilisis dui. Nulla odio dui, euismod id turpis nec, interdum dignissim dui. Nunc non odio non nulla varius fermentum. Maecenas vulputate metus a metus sodales dapibus. Pellentesque gravida enim nunc. Pellentesque venenatis odio nec enim blandit, hendrerit fermentum urna ornare. Praesent accumsan id tortor ut maximus. Aliquam nulla tellus, scelerisque vel faucibus eu, dapibus vitae tellus. Nulla facilisi. 6 | -------------------------------------------------------------------------------- /app/i18n/locales/terms-of-use/ada/other/en-US.md: -------------------------------------------------------------------------------- 1 | # Terms of Service Agreement 2 | 3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam metus lectus, luctus ut porta sit amet, bibendum nec enim. Donec vel consequat diam. Aenean et ex laoreet, hendrerit metus luctus, pulvinar lectus. Ut posuere pretium erat, non malesuada sapien condimentum in. Duis quis lorem auctor, luctus dolor non, interdum quam. Cras vel enim varius, consequat quam at, blandit dolor. Phasellus lacinia enim volutpat libero vehicula, in malesuada erat vestibulum. In eu placerat nunc, eget rutrum orci. Quisque ut odio id erat iaculis gravida. 4 | 5 | Donec mauris purus, sagittis eget ipsum in, hendrerit auctor odio. Duis vestibulum blandit tellus eget convallis. Donec velit libero, mattis id lectus a, euismod facilisis dui. Nulla odio dui, euismod id turpis nec, interdum dignissim dui. Nunc non odio non nulla varius fermentum. Maecenas vulputate metus a metus sodales dapibus. Pellentesque gravida enim nunc. Pellentesque venenatis odio nec enim blandit, hendrerit fermentum urna ornare. Praesent accumsan id tortor ut maximus. Aliquam nulla tellus, scelerisque vel faucibus eu, dapibus vitae tellus. Nulla facilisi. 6 | -------------------------------------------------------------------------------- /app/i18n/locales/terms-of-use/ada/other/ja-JP.md: -------------------------------------------------------------------------------- 1 | # サービス規約 2 | 3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam metus lectus, luctus ut porta sit amet, bibendum nec enim. Donec vel consequat diam. Aenean et ex laoreet, hendrerit metus luctus, pulvinar lectus. Ut posuere pretium erat, non malesuada sapien condimentum in. Duis quis lorem auctor, luctus dolor non, interdum quam. Cras vel enim varius, consequat quam at, blandit dolor. Phasellus lacinia enim volutpat libero vehicula, in malesuada erat vestibulum. In eu placerat nunc, eget rutrum orci. Quisque ut odio id erat iaculis gravida. 4 | 5 | Donec mauris purus, sagittis eget ipsum in, hendrerit auctor odio. Duis vestibulum blandit tellus eget convallis. Donec velit libero, mattis id lectus a, euismod facilisis dui. Nulla odio dui, euismod id turpis nec, interdum dignissim dui. Nunc non odio non nulla varius fermentum. Maecenas vulputate metus a metus sodales dapibus. Pellentesque gravida enim nunc. Pellentesque venenatis odio nec enim blandit, hendrerit fermentum urna ornare. Praesent accumsan id tortor ut maximus. Aliquam nulla tellus, scelerisque vel faucibus eu, dapibus vitae tellus. Nulla facilisi. 6 | -------------------------------------------------------------------------------- /app/i18n/locales/terms-of-use/ada/other/ko-KR.md: -------------------------------------------------------------------------------- 1 | # 서비스 규약 2 | 3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam metus lectus, luctus ut porta sit amet, bibendum nec enim. Donec vel consequat diam. Aenean et ex laoreet, hendrerit metus luctus, pulvinar lectus. Ut posuere pretium erat, non malesuada sapien condimentum in. Duis quis lorem auctor, luctus dolor non, interdum quam. Cras vel enim varius, consequat quam at, blandit dolor. Phasellus lacinia enim volutpat libero vehicula, in malesuada erat vestibulum. In eu placerat nunc, eget rutrum orci. Quisque ut odio id erat iaculis gravida. 4 | 5 | Donec mauris purus, sagittis eget ipsum in, hendrerit auctor odio. Duis vestibulum blandit tellus eget convallis. Donec velit libero, mattis id lectus a, euismod facilisis dui. Nulla odio dui, euismod id turpis nec, interdum dignissim dui. Nunc non odio non nulla varius fermentum. Maecenas vulputate metus a metus sodales dapibus. Pellentesque gravida enim nunc. Pellentesque venenatis odio nec enim blandit, hendrerit fermentum urna ornare. Praesent accumsan id tortor ut maximus. Aliquam nulla tellus, scelerisque vel faucibus eu, dapibus vitae tellus. Nulla facilisi. 6 | -------------------------------------------------------------------------------- /app/i18n/locales/whitelist_de-DE.json: -------------------------------------------------------------------------------- 1 | [ 2 | ] -------------------------------------------------------------------------------- /app/i18n/locales/whitelist_en-US.json: -------------------------------------------------------------------------------- 1 | [ 2 | ] -------------------------------------------------------------------------------- /app/i18n/locales/whitelist_hr-HR.json: -------------------------------------------------------------------------------- 1 | [ 2 | ] -------------------------------------------------------------------------------- /app/i18n/locales/whitelist_ja-JP.json: -------------------------------------------------------------------------------- 1 | [ 2 | ] -------------------------------------------------------------------------------- /app/i18n/locales/whitelist_ko-KR.json: -------------------------------------------------------------------------------- 1 | [ 2 | ] -------------------------------------------------------------------------------- /app/i18n/locales/whitelist_zh-CN.json: -------------------------------------------------------------------------------- 1 | [ 2 | ] -------------------------------------------------------------------------------- /app/i18n/translations.js: -------------------------------------------------------------------------------- 1 | // This is essentially bulk require 2 | const req = require.context('./locales', true, /\.json.*$/); 3 | const translations = {}; 4 | 5 | req.keys().forEach((file) => { 6 | const locale = file.replace('./', '').replace('.json', ''); 7 | translations[locale] = req(file); 8 | }); 9 | 10 | module.exports = translations; 11 | -------------------------------------------------------------------------------- /app/routes-config.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export const ROUTES = { 3 | ROOT: '/', 4 | STAKING: '/staking', 5 | ADA_REDEMPTION: '/ada-redemption', 6 | NO_WALLETS: '/no-wallets', 7 | PROFILE: { 8 | LANGUAGE_SELECTION: '/profile/language-selection', 9 | TERMS_OF_USE: '/profile/terms-of-use', 10 | SEND_LOGS: '/profile/send-logs-choice', 11 | }, 12 | WALLETS: { 13 | ROOT: '/wallets', 14 | ADD: '/wallets/add', 15 | PAGE: '/wallets/:id/:page', 16 | TRANSACTIONS: '/wallets/:id/transactions', 17 | SEND: '/wallets/:id/send', 18 | RECEIVE: '/wallets/:id/receive', 19 | }, 20 | SETTINGS: { 21 | ROOT: '/settings', 22 | WALLET: '/settings/wallet', 23 | GENERAL: '/settings/general', 24 | TERMS_OF_USE: '/settings/terms-of-use', 25 | SUPPORT: '/settings/support', 26 | DISPLAY: '/settings/display', 27 | }, 28 | DAEDALUS_TRANFER: { 29 | ROOT: '/daedalus-transfer', 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /app/stores/AppStore.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { observable, computed } from 'mobx'; 3 | import Store from './lib/Store'; 4 | import LocalizableError from '../i18n/LocalizableError'; 5 | import { buildRoute } from '../utils/routing'; 6 | 7 | export default class AppStore extends Store { 8 | 9 | @observable error: ?LocalizableError = null; 10 | 11 | setup() { 12 | this.actions.router.goToRoute.listen(this._updateRouteLocation); 13 | } 14 | 15 | @computed get currentRoute(): string { 16 | return this.stores.router.location.pathname; 17 | } 18 | 19 | _updateRouteLocation = (options: { route: string, params: ?Object }) => { 20 | const routePath = buildRoute(options.route, options.params); 21 | const currentRoute = this.stores.router.location.pathname; 22 | if (currentRoute !== routePath) this.stores.router.push(routePath); 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /app/stores/WalletSettingsStore.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { observable, action } from 'mobx'; 3 | import Store from './lib/Store'; 4 | 5 | export default class WalletSettingsStore extends Store { 6 | 7 | @observable walletFieldBeingEdited = null; 8 | @observable lastUpdatedWalletField = null; 9 | 10 | @action _startEditingWalletField = ({ field }: { field: string }) => { 11 | this.walletFieldBeingEdited = field; 12 | }; 13 | 14 | @action _stopEditingWalletField = () => { 15 | if (this.walletFieldBeingEdited) { 16 | this.lastUpdatedWalletField = this.walletFieldBeingEdited; 17 | } 18 | this.walletFieldBeingEdited = null; 19 | }; 20 | 21 | @action _cancelEditingWalletField = () => { 22 | this.lastUpdatedWalletField = null; 23 | this.walletFieldBeingEdited = null; 24 | }; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/stores/ada/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { observable, action } from 'mobx'; 3 | import AdaWalletsStore from './AdaWalletsStore'; 4 | import TransactionsStore from './AdaTransactionsStore'; 5 | import AdaWalletSettingsStore from './AdaWalletSettingsStore'; 6 | import AddressesStore from './AddressesStore'; 7 | import DaedalusTransferStore from './DaedalusTransferStore'; 8 | 9 | export const adaStoreClasses = { 10 | wallets: AdaWalletsStore, 11 | transactions: TransactionsStore, 12 | walletSettings: AdaWalletSettingsStore, 13 | addresses: AddressesStore, 14 | daedalusTransfer: DaedalusTransferStore 15 | }; 16 | 17 | export type AdaStoresMap = { 18 | wallets: AdaWalletsStore, 19 | transactions: TransactionsStore, 20 | walletSettings: AdaWalletSettingsStore, 21 | addresses: AddressesStore, 22 | daedalusTransfer: DaedalusTransferStore 23 | }; 24 | 25 | const adaStores = observable({ 26 | wallets: null, 27 | transactions: null, 28 | walletSettings: null, 29 | addresses: null, 30 | daedalusTransfer: null 31 | }); 32 | 33 | // Set up and return the stores and reset all stores to defaults 34 | export default action((stores, api, actions): AdaStoresMap => { 35 | const storeNames = Object.keys(adaStoreClasses); 36 | storeNames.forEach(name => { if (adaStores[name]) adaStores[name].teardown(); }); 37 | storeNames.forEach(name => { 38 | adaStores[name] = new adaStoreClasses[name](stores, api, actions); 39 | }); 40 | storeNames.forEach(name => { if (adaStores[name]) adaStores[name].initialize(); }); 41 | return adaStores; 42 | }); 43 | -------------------------------------------------------------------------------- /app/stores/lib/LocalizedCachedRequest.js: -------------------------------------------------------------------------------- 1 | import CachedRequest from './CachedRequest'; 2 | import LocalizableError from '../../i18n/LocalizableError'; 3 | 4 | // eslint-disable-next-line 5 | export default class LocalizedCachedRequest extends CachedRequest {} 6 | -------------------------------------------------------------------------------- /app/stores/lib/LocalizedRequest.js: -------------------------------------------------------------------------------- 1 | import Request from './Request'; 2 | import LocalizableError from '../../i18n/LocalizableError'; 3 | 4 | export default class LocalizedRequest extends Request {} 5 | -------------------------------------------------------------------------------- /app/stores/lib/Reaction.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { autorun } from 'mobx'; 3 | 4 | export default class Reaction { 5 | 6 | reaction: () => void; 7 | hasBeenStarted: boolean; 8 | dispose: () => void; 9 | 10 | constructor(reaction: () => void) { 11 | this.reaction = reaction; 12 | this.hasBeenStarted = false; 13 | } 14 | 15 | start() { 16 | this.dispose = autorun(() => this.reaction()); 17 | this.hasBeenStarted = true; 18 | } 19 | 20 | stop() { 21 | if (this.hasBeenStarted) this.dispose(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/stores/lib/Store.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Reaction from './Reaction'; 3 | import type { ActionsMap } from '../../actions/index'; 4 | import type { StoresMap } from '../../stores/index'; 5 | import type { Api } from '../../api/index'; 6 | 7 | export default class Store { 8 | 9 | stores: StoresMap; 10 | api: Api; 11 | actions: ActionsMap; 12 | 13 | _reactions: Array = []; 14 | 15 | constructor(stores: StoresMap, api: Api, actions: ActionsMap) { 16 | this.stores = stores; 17 | this.api = api; 18 | this.actions = actions; 19 | } 20 | 21 | registerReactions(reactions: Array) { 22 | reactions.forEach(reaction => this._reactions.push(new Reaction(reaction))); 23 | } 24 | 25 | setup() {} 26 | 27 | initialize() { 28 | this.setup(); 29 | this._reactions.forEach(reaction => reaction.start()); 30 | } 31 | 32 | teardown() { 33 | this._reactions.forEach(reaction => reaction.stop()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/themes/daedalus.js: -------------------------------------------------------------------------------- 1 | import { 2 | SELECT, INPUT, FORM_FIELD, CHECKBOX, SWITCH, MODAL, 3 | BUTTON, TEXT_AREA, AUTOCOMPLETE, OPTIONS, BUBBLE 4 | } from 'react-polymorph/lib/skins/simple/identifiers'; 5 | 6 | // react-polymorph components 7 | import SimpleFormField from './simple/SimpleFormField.scss'; 8 | import SimpleInput from './simple/SimpleInput.scss'; 9 | import SimpleCheckbox from './simple/SimpleCheckbox.scss'; 10 | import SimpleSwitch from './simple/SimpleSwitch.scss'; 11 | import SimpleModal from './simple/SimpleModal.scss'; 12 | import SimpleButton from './simple/SimpleButton.scss'; 13 | import SimpleTextArea from './simple/SimpleTextArea.scss'; 14 | import SimpleAutocomplete from './simple/SimpleAutocomplete.scss'; 15 | import SimpleBubble from './simple/SimpleBubble.scss'; 16 | import SimpleOptions from './simple/SimpleOptions.scss'; 17 | import SimpleSelect from './simple/SimpleSelect.scss'; 18 | 19 | export const daedalusTheme = { 20 | [FORM_FIELD]: SimpleFormField, 21 | [INPUT]: SimpleInput, 22 | [CHECKBOX]: SimpleCheckbox, 23 | [SWITCH]: SimpleSwitch, 24 | [MODAL]: SimpleModal, 25 | [BUTTON]: SimpleButton, 26 | [TEXT_AREA]: SimpleTextArea, 27 | [BUBBLE]: SimpleBubble, 28 | [OPTIONS]: SimpleOptions, 29 | [SELECT]: SimpleSelect, 30 | [AUTOCOMPLETE]: SimpleAutocomplete, 31 | }; 32 | -------------------------------------------------------------------------------- /app/themes/index.js: -------------------------------------------------------------------------------- 1 | export const THEMES = { 2 | PROJECT_ICARUS: 'project-icarus', 3 | CARDANO: 'cardano', 4 | DARK_BLUE: 'dark-blue', 5 | LIGHT_BLUE: 'light-blue', 6 | }; 7 | -------------------------------------------------------------------------------- /app/themes/mixins/animations.scss: -------------------------------------------------------------------------------- 1 | @mixin animated-ellipsis($duration: 900, $width: 20px) { 2 | &:after { 3 | overflow: hidden; 4 | display: inline-block; 5 | vertical-align: bottom; 6 | animation: ellipsis steps(4,end) #{$duration}ms infinite; 7 | content: "\2026"; /* ascii code for the ellipsis character */ 8 | width: 0; 9 | margin-right: 0; 10 | text-align: left; 11 | } 12 | 13 | @keyframes ellipsis { 14 | to { 15 | width: $width; 16 | margin-right: -$width; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/themes/mixins/arrow.scss: -------------------------------------------------------------------------------- 1 | // CSS arrow box inspired from http://www.cssarrowplease.com/ 2 | @mixin arrow($direction, $bg-color, $border-color, $size) { 3 | &:after, &:before { 4 | @if $direction == down { top: 100%; } 5 | @if $direction == up { bottom: 100%; } 6 | left: 50%; 7 | border: solid transparent; 8 | content: " "; 9 | height: 0; 10 | width: 0; 11 | position: absolute; 12 | pointer-events: none; 13 | } 14 | 15 | &:after { 16 | border-color: rgba($bg-color, 0); 17 | @if $direction == down { border-top-color: $bg-color; } 18 | @if $direction == up { border-bottom-color: $bg-color; } 19 | border-width: $size; 20 | margin-left: -$size; 21 | } 22 | 23 | &:before { 24 | border-color: rgba($border-color, 0); 25 | @if $direction == down { border-top-color: $border-color; } 26 | @if $direction == up { border-bottom-color: $border-color; } 27 | border-width: $size; 28 | margin-left: -$size; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/themes/mixins/buttons.scss: -------------------------------------------------------------------------------- 1 | @mixin button { 2 | border: none; 3 | padding: 0; 4 | &:hover { 5 | cursor: pointer; 6 | } 7 | &:focus { 8 | outline: 0; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /app/themes/mixins/error-message.scss: -------------------------------------------------------------------------------- 1 | @mixin error-message { 2 | color: var(--theme-error-color); 3 | font-family: var(--font-regular); 4 | font-size: 14px; 5 | line-height: 1.5em; 6 | letter-spacing: 0.5px; 7 | } 8 | -------------------------------------------------------------------------------- /app/themes/mixins/forms.scss: -------------------------------------------------------------------------------- 1 | @mixin form-label { 2 | font-family: var(--font-medium); 3 | font-size: 16px; 4 | color: var(--theme-label-color); 5 | } 6 | -------------------------------------------------------------------------------- /app/themes/mixins/loading-spinner.scss: -------------------------------------------------------------------------------- 1 | @mixin loading-spinner($iconPath) { 2 | text-indent: -9999px; 3 | &:after { 4 | content: ''; 5 | width: 30px; 6 | height: 30px; 7 | position: absolute; 8 | top: calc(50% - 15px); 9 | left: calc(50% - 15px); 10 | background: url($iconPath) no-repeat center; 11 | background-size: 30px; 12 | :global { 13 | animation: loading-spin 1.5s linear; 14 | animation-iteration-count: infinite; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/themes/mixins/place-form-field-error-below-input.scss: -------------------------------------------------------------------------------- 1 | @mixin place-form-field-error-below-input { 2 | :global { 3 | .SimpleFormField_root { 4 | &.SimpleInput_errored { 5 | margin-bottom: 21px; 6 | 7 | .SimpleFormField_error { 8 | left: 0; 9 | margin: 4px 10px 0 0; 10 | overflow: hidden; 11 | position: absolute; 12 | right: 0; 13 | text-align: right; 14 | text-overflow: ellipsis; 15 | top: 100%; 16 | white-space: nowrap; 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/themes/simple/SimpleAutocomplete.scss: -------------------------------------------------------------------------------- 1 | @import "_config"; 2 | // Theme config overrides go here … 3 | @import "~react-polymorph/lib/themes/simple/SimpleAutocomplete"; 4 | // Css module overrides go here … 5 | 6 | .autocompleteWrapper { 7 | .autocompleteContent { 8 | min-height: 73px; 9 | padding: 0 10px; 10 | 11 | .selectedWords { 12 | input { 13 | font-size: 15px; 14 | margin: 5px 0; 15 | } 16 | 17 | .selectedWordBox { 18 | border-radius: 2px; 19 | margin: 5px 12px 0 -6px; 20 | padding: 3px 6px; 21 | 22 | .selectedWordValue { 23 | font-size: 15px; 24 | 25 | .selectedWordRemoveButton { 26 | margin-left: 4px; 27 | } 28 | } 29 | 30 | &:last-of-type { 31 | margin-right: 6px; 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/themes/simple/SimpleBubble.scss: -------------------------------------------------------------------------------- 1 | @import "_config"; 2 | // Theme config overrides go here … 3 | @import "~react-polymorph/lib/themes/simple/SimpleBubble"; 4 | // Css module overrides go here … 5 | -------------------------------------------------------------------------------- /app/themes/simple/SimpleCheckbox.scss: -------------------------------------------------------------------------------- 1 | @import "_config"; 2 | // Theme config overrides go here … 3 | @import "~react-polymorph/lib/themes/simple/SimpleCheckbox"; 4 | // Css module overrides go here … 5 | 6 | .root { 7 | .checked { 8 | background-color: var(--theme-checkbox-background-color-checked); 9 | } 10 | } 11 | 12 | .check { 13 | border: 1px solid var(--theme-checkbox-border-color); 14 | } 15 | 16 | .label { 17 | color: var(--theme-checkbox-label-color); 18 | font-size: 15px; 19 | 20 | strong { 21 | font-family: var(--font-medium); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/themes/simple/SimpleFormField.scss: -------------------------------------------------------------------------------- 1 | @import "_config"; 2 | // Theme config overrides go here … 3 | @import "~react-polymorph/lib/themes/simple/SimpleFormField"; 4 | // Css module overrides go here … 5 | 6 | .error { 7 | color: var(--theme-input-error-color); 8 | font-size: 11px; 9 | line-height: 1.38; 10 | margin: 0 10px 6px; 11 | opacity: 0.75; 12 | } 13 | 14 | .label { 15 | color: var(--theme-input-label-color); 16 | font-size: 11px; 17 | font-weight: 600; 18 | margin-bottom: 6px; 19 | padding-left: 10px; 20 | text-transform: uppercase; 21 | } 22 | -------------------------------------------------------------------------------- /app/themes/simple/SimpleInput.scss: -------------------------------------------------------------------------------- 1 | @import "_config"; 2 | // Theme config overrides go here … 3 | @import "~react-polymorph/lib/themes/simple/SimpleInput"; 4 | // Css module overrides go here … 5 | 6 | :global { 7 | .AmountInputSkin_total, .AmountInputSkin_fees { 8 | color: var(--theme-input-right-floating-text-color); 9 | } 10 | } 11 | 12 | .input { 13 | font-size: 15px; 14 | padding: 10px; 15 | } 16 | -------------------------------------------------------------------------------- /app/themes/simple/SimpleModal.scss: -------------------------------------------------------------------------------- 1 | @import "_config"; 2 | // Theme config overrides go here … 3 | @import "~react-polymorph/lib/themes/simple/SimpleModal"; 4 | // Css module overrides go here … 5 | 6 | .overlay { 7 | z-index: 100; 8 | } 9 | 10 | .modal { 11 | border-radius: 5px; 12 | display: flex; 13 | flex-direction: column; 14 | max-height: 90%; 15 | max-width: 785px; 16 | 17 | :global { 18 | .WalletExportDialogChoices_component { 19 | & > button { 20 | color: var(--theme-dialog-choice-tabs-text-color); 21 | } 22 | 23 | & > .WalletExportDialogChoices_activeButton { 24 | color: var(--theme-dialog-choice-tabs-text-color-active); 25 | border-bottom: 2px solid var(--theme-dialog-choice-tabs-bottom-border-color-active); 26 | } 27 | } 28 | 29 | .SimpleInput_input, 30 | .SimpleAutocomplete_autocompleteContent { 31 | background-color: transparent !important; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/themes/simple/SimpleOptions.scss: -------------------------------------------------------------------------------- 1 | @import "_config"; 2 | // Theme config overrides go here … 3 | @import "~react-polymorph/lib/themes/simple/SimpleOptions"; 4 | // Css module overrides go here … 5 | 6 | .options { 7 | :global { 8 | .SimpleBubble_bubble { 9 | margin-top: -11px !important; 10 | } 11 | } 12 | 13 | span[data-bubble-arrow] { 14 | display: none; 15 | } 16 | } 17 | 18 | .ul { 19 | font-size: 15px; 20 | } 21 | 22 | .option { 23 | padding: 10px; 24 | } 25 | -------------------------------------------------------------------------------- /app/themes/simple/SimpleSelect.scss: -------------------------------------------------------------------------------- 1 | @import "_config"; 2 | // Theme config overrides go here … 3 | @import "~react-polymorph/lib/themes/simple/SimpleSelect"; 4 | // Css module overrides go here … 5 | 6 | .selectInput { 7 | &::after { 8 | bottom: 16px; 9 | left: calc(100% - 22px); 10 | } 11 | 12 | input { 13 | background: none; 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /app/themes/simple/SimpleSwitch.scss: -------------------------------------------------------------------------------- 1 | @import "_config"; 2 | // Theme config overrides go here … 3 | @import "~react-polymorph/lib/themes/simple/SimpleSwitch"; 4 | // Css module overrides go here … 5 | 6 | .root { 7 | flex-direction: row-reverse; 8 | margin-bottom: 30px; 9 | &:not(.checked) { 10 | .switch { 11 | box-shadow: 0 2px 0 -1px transparent; // fix for cut-off bottom 12 | opacity: 0.3; 13 | } 14 | } 15 | } 16 | 17 | .label { 18 | margin: 0 30px 0 0 !important; 19 | opacity: 0.5; 20 | width: 100%; 21 | } 22 | -------------------------------------------------------------------------------- /app/themes/simple/SimpleTextArea.scss: -------------------------------------------------------------------------------- 1 | @import "_config"; 2 | // Theme config overrides go here … 3 | @import "~react-polymorph/lib/themes/simple/SimpleTextArea"; 4 | // Css module overrides go here … 5 | 6 | .textarea { 7 | border-radius: 2px; 8 | resize: none; 9 | } 10 | -------------------------------------------------------------------------------- /app/types/daedalusTransferTypes.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import BigNumber from 'bignumber.js'; 3 | 4 | export type TransferStatus = 5 | 'uninitialized' 6 | | 'gettingMnemonics' 7 | | 'restoringAddresses' 8 | | 'checkingAddresses' 9 | | 'generatingTx' 10 | | 'readyToTransfer' 11 | | 'error' 12 | 13 | export type TransferTx = { 14 | recoveredBalance: BigNumber, 15 | fee: BigNumber, 16 | cborEncodedTx: Array, 17 | senders: Array, 18 | receiver: string 19 | } 20 | -------------------------------------------------------------------------------- /app/types/i18nTypes.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export type ReactIntlMessage = { 3 | id: string, 4 | defaultMessage: string, 5 | description: string, 6 | }; 7 | -------------------------------------------------------------------------------- /app/types/injectedPropsType.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { Node } from 'react'; 3 | import type { StoresMap } from '../stores/index'; 4 | import type { ActionsMap } from '../actions/index'; 5 | 6 | export type InjectedProps = { 7 | stores: any | StoresMap, 8 | actions: any | ActionsMap, 9 | }; 10 | 11 | export type InjectedContainerProps = { 12 | stores: any | StoresMap, 13 | actions: any | ActionsMap, 14 | children: Node, 15 | }; 16 | 17 | export type InjectedDialogContainerProps = { 18 | stores: any | StoresMap, 19 | actions: any | ActionsMap, 20 | children: Node, 21 | onClose: Function, 22 | }; 23 | -------------------------------------------------------------------------------- /app/types/notificationType.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export type Notification = { 3 | id: string, 4 | duration: ?number, 5 | secondsTimerInterval: ?IntervalID, 6 | } 7 | -------------------------------------------------------------------------------- /app/types/redemptionTypes.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export type RedemptionTypeChoices = 'regular' | 'forceVended' | 'paperVended'; 3 | -------------------------------------------------------------------------------- /app/types/transactionAssuranceTypes.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export type AssuranceModeOption = 'CWANormal' | 'CWAStrict'; 3 | export type AssuranceMode = { low: number, medium: number }; 4 | export type AssuranceLevel = 'low' | 'medium' | 'high'; 5 | -------------------------------------------------------------------------------- /app/types/unconfirmedAmountType.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import BigNumber from 'bignumber.js'; 3 | 4 | export type UnconfirmedAmount = { 5 | total: BigNumber, 6 | incoming: BigNumber, 7 | outgoing: BigNumber, 8 | } 9 | -------------------------------------------------------------------------------- /app/utils/ReactToolboxMobxForm.js: -------------------------------------------------------------------------------- 1 | import MobxReactForm from 'mobx-react-form'; 2 | 3 | export default class ReactToolboxMobxForm extends MobxReactForm { 4 | 5 | bindings() { 6 | return { 7 | ReactToolbox: { 8 | id: 'id', 9 | name: 'name', 10 | type: 'type', 11 | value: 'value', 12 | label: 'label', 13 | placeholder: 'hint', 14 | disabled: 'disabled', 15 | error: 'error', 16 | onChange: 'onChange', 17 | onFocus: 'onFocus', 18 | onBlur: 'onBlur', 19 | }, 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/utils/formatters.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import BigNumber from 'bignumber.js'; 3 | 4 | export const formattedWalletAmount = (amount: BigNumber) => ( 5 | amount.toFormat(6) 6 | ); 7 | 8 | export const formattedAmountToBigNumber = (amount: string) => { 9 | const cleanedAmount = amount.replace(/,/g, ''); 10 | return new BigNumber(cleanedAmount !== '' ? cleanedAmount : 0); 11 | }; 12 | 13 | export const formattedAmountToNaturalUnits = (amount: string): string => { 14 | const cleanedAmount = amount.replace('.', '').replace(/,/g, '').replace(/^0+/, ''); 15 | return cleanedAmount === '' ? '0' : cleanedAmount; 16 | }; 17 | 18 | export const formattedAmountWithoutTrailingZeros = (amount: string): string => ( 19 | amount.replace(/0+$/, '').replace(/\.$/, '') 20 | ); 21 | -------------------------------------------------------------------------------- /app/utils/imports.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import environment from '../environment'; 3 | 4 | // resolver loads files relative to '/app/' directory 5 | const resolver = (path: string) => { 6 | const envPathSubdir = environment.API || ''; 7 | const envPathSegments = path.split('/'); 8 | envPathSegments.splice(-1, 0, envPathSubdir); 9 | const envPath = envPathSegments.join('/'); 10 | let file; 11 | try { 12 | file = require(`../${envPath}.js`); // eslint-disable-line 13 | } catch (e) { 14 | file = require(`../${path}.js`); // eslint-disable-line 15 | } 16 | return file.default || file; 17 | }; 18 | 19 | export default resolver; 20 | -------------------------------------------------------------------------------- /app/utils/logging.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import RingBuffer from 'ringbufferjs'; 3 | import moment from 'moment'; 4 | import FileSaver from 'file-saver'; 5 | 6 | import type { ConfigType } from '../../config/config-types'; 7 | 8 | const logger = console; 9 | declare var CONFIG: ConfigType; 10 | const { logsBufferSize, logsFileSuffix } = CONFIG.app; 11 | const logs = new RingBuffer(logsBufferSize); 12 | 13 | export const Logger = { 14 | 15 | debug: (data : string) => { 16 | logger.debug(data); 17 | }, 18 | 19 | info: (data : string) => { 20 | logger.info(data); 21 | }, 22 | 23 | error: (data : string) => { 24 | logger.error(data); 25 | logs.enq(`[${moment().format()}] ${data}\n`); 26 | }, 27 | 28 | warn: (data : string) => { 29 | logger.info(data); 30 | } 31 | }; 32 | 33 | export const downloadLogs = () => { 34 | const toDownload = logs.peekN(logs.size()); 35 | const blob = new Blob(toDownload, { type: 'text/plain;charset=utf-8' }); 36 | FileSaver.saveAs(blob, `${moment().format()}${logsFileSuffix}`); 37 | }; 38 | 39 | // ========== STRINGIFY ========= 40 | 41 | export const stringifyData = (data : any) => JSON.stringify(data, null, 2); 42 | 43 | export const stringifyError = (error : any) => ( 44 | JSON.stringify(error, Object.getOwnPropertyNames(error), 2) 45 | ); 46 | -------------------------------------------------------------------------------- /app/utils/passwordCipher.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { PasswordProtect } from 'rust-cardano-crypto'; 4 | import cryptoRandomString from 'crypto-random-string'; 5 | import { getOrFail } from '../api/ada/lib/cardanoCrypto/cryptoUtils'; 6 | import { WrongPassphraseError } from '../api/ada/lib/cardanoCrypto/cryptoErrors'; 7 | 8 | export function encryptWithPassword( 9 | password: string, 10 | bytes: Uint8Array 11 | ): string { 12 | const salt = new Buffer(cryptoRandomString(2 * 32), 'hex'); 13 | const nonce = new Buffer(cryptoRandomString(2 * 12), 'hex'); 14 | const formattedPassword: Uint8Array = new TextEncoder().encode(password); 15 | const encryptedBytes = getOrFail( 16 | PasswordProtect.encryptWithPassword(formattedPassword, salt, nonce, bytes)); 17 | const encryptedHex = Buffer.from(encryptedBytes).toString('hex'); 18 | return encryptedHex; 19 | } 20 | 21 | export function decryptWithPassword( 22 | password: string, 23 | encryptedHex: string 24 | ): Uint8Array { 25 | const encryptedBytes = new Buffer(encryptedHex, 'hex'); 26 | const formattedPassword: Uint8Array = new TextEncoder().encode(password); 27 | // FIXME: null or false is returned on invalid password 28 | const decryptedBytes: ?Uint8Array | false = 29 | PasswordProtect.decryptWithPassword(formattedPassword, encryptedBytes); 30 | if (!decryptedBytes) { 31 | throw new WrongPassphraseError(); 32 | } else { 33 | return decryptedBytes; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/utils/strings.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | export const ellipsis = (str:string, maxChars:number) => ( 4 | str.length > maxChars ? str.substr(0, maxChars) + '\u2026' : str 5 | ); 6 | -------------------------------------------------------------------------------- /app/utils/validations.js: -------------------------------------------------------------------------------- 1 | import BigNumber from 'bignumber.js'; 2 | import isInt from 'validator/lib/isInt'; 3 | 4 | export const isValidWalletName = (walletName) => { 5 | const nameLength = walletName.length; 6 | return nameLength >= 3 && nameLength <= 40; 7 | }; 8 | 9 | export const isValidWalletPassword = (walletPassword) => { 10 | // Validation rules: 11 | // - should contain at least one digit: (?=.*\d) 12 | // - should contain at least one lower case: (?=.*[a-z]) 13 | // - should contain at least one upper case: (?=.*[A-Z]) 14 | // - should contain at least 7 characters long: .{7,} 15 | const passwordRegex = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{7,}$/; 16 | return passwordRegex.test(walletPassword); 17 | }; 18 | 19 | // eslint-disable-next-line max-len 20 | export const isValidRepeatPassword = (walletPassword, repeatPassword) => walletPassword === repeatPassword; 21 | 22 | export const isNotEmptyString = (value) => value !== ''; 23 | 24 | export const isValidAmountInLovelaces = (value: string) => { 25 | const isNumeric = isInt(value, { allow_leading_zeroes: false }); 26 | if (!isNumeric) return false; 27 | const numericValue = new BigNumber(value); 28 | const minValue = new BigNumber(1); 29 | const maxValue = new BigNumber(45000000000000000); 30 | const isValid = numericValue.gte(minValue) && numericValue.lte(maxValue); 31 | return isValid; 32 | }; 33 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: '6' 4 | - nodejs_version: '7' 5 | 6 | cache: 7 | - "%LOCALAPPDATA%/Yarn" 8 | - node_modules 9 | 10 | install: 11 | - ps: Install-Product node $env:nodejs_version 12 | - yarn install 13 | 14 | test_script: 15 | - node --version 16 | - yarn --version 17 | - yarn run lint 18 | - yarn test 19 | - yarn run build 20 | 21 | build: off 22 | -------------------------------------------------------------------------------- /chrome/assets/img/ada-symbol-smallest-dark.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5B47861B-BE78-47A7-AF40-C1783A7FA64B 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /chrome/assets/img/ada-symbol-smallest-white.inline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /chrome/assets/img/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/chrome/assets/img/icon-128.png -------------------------------------------------------------------------------- /chrome/assets/img/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/chrome/assets/img/icon-16.png -------------------------------------------------------------------------------- /chrome/assets/img/icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/chrome/assets/img/icon-48.png -------------------------------------------------------------------------------- /chrome/assets/img/receive-ic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /chrome/assets/img/send-ic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /chrome/extension/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import { action, useStrict } from 'mobx'; 4 | import { RouterStore, syncHistoryWithStore } from 'mobx-react-router'; 5 | import { hashHistory } from 'react-router'; 6 | import { setupApi } from '../../app/api/index'; 7 | import createStores from '../../app/stores/index'; 8 | import translations from '../../app/i18n/translations'; 9 | import actions from '../../app/actions/index'; 10 | import Action from '../../app/actions/lib/Action'; 11 | import App from '../../app/App'; 12 | import '../../app/themes/index.global.scss'; 13 | 14 | // run MobX in strict mode 15 | useStrict(true); 16 | 17 | const initializeProjectIcarus = async () => { 18 | const api = setupApi(); 19 | const router = new RouterStore(); 20 | const history = syncHistoryWithStore(hashHistory, router); 21 | const stores = createStores(api, actions, router); 22 | 23 | window.projecticarus = { 24 | api, 25 | actions, 26 | translations, 27 | stores, 28 | reset: action(() => { 29 | Action.resetAllActions(); 30 | createStores(api, actions, router); 31 | }) 32 | }; 33 | 34 | render( 35 | , 36 | document.querySelector('#root') 37 | ); 38 | }; 39 | 40 | window.addEventListener('load', initializeProjectIcarus); 41 | -------------------------------------------------------------------------------- /chrome/manifest.development.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.0", 3 | "name": "project-icarus", 4 | "manifest_version": 2, 5 | "description": "[dev] Cardano ADA wallet", 6 | "browser_action": { 7 | "default_title": "[dev] Project Icarus" 8 | }, 9 | "icons": { 10 | "16": "img/icon-16.png", 11 | "48": "img/icon-48.png", 12 | "128": "img/icon-128.png" 13 | }, 14 | "background": { 15 | "page": "background.html" 16 | }, 17 | "permissions": [ 18 | "contextMenus", 19 | "management", 20 | "tabs", 21 | "storage" 22 | ], 23 | "content_security_policy": "default-src 'self' http://localhost:3000 https://localhost:3000; script-src 'self' http://localhost:3000 https://localhost:3000 'unsafe-eval'; connect-src http://localhost:3000 https://localhost:3000 http://localhost:8080 https://localhost:8080 https://18.206.30.1 ws://localhost:8080 wss://localhost:8080 wss://18.206.30.1 https://lld5qq5jl5.execute-api.us-east-1.amazonaws.com; style-src * 'unsafe-inline' 'self' blob:; img-src 'self' data:;", 24 | "key": "pojejnpjgcacmnpkdiklhlnlbkjechfh" 25 | } 26 | -------------------------------------------------------------------------------- /chrome/manifest.mainnet.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.0", 3 | "name": "project-icarus", 4 | "manifest_version": 2, 5 | "description": "Cardano ADA wallet", 6 | "browser_action": { 7 | "default_title": "Project Icarus" 8 | }, 9 | "icons": { 10 | "16": "img/icon-16.png", 11 | "48": "img/icon-48.png", 12 | "128": "img/icon-128.png" 13 | }, 14 | "background": { 15 | "page": "background.html" 16 | }, 17 | "permissions": [ 18 | "contextMenus", 19 | "management", 20 | "tabs", 21 | "storage" 22 | ], 23 | "content_security_policy": "default-src 'self'; script-src 'self' 'unsafe-eval'; connect-src https://DEFINE:443 wss://DEFINE:443; style-src * 'unsafe-inline' 'self' blob:; img-src 'self' data:;" 24 | } 25 | -------------------------------------------------------------------------------- /chrome/manifest.staging.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.13", 3 | "version_name": "st-0.0.13#68.0_GC-w7", 4 | "name": "project-icarus", 5 | "manifest_version": 2, 6 | "description": "[staging] Cardano ADA wallet", 7 | "browser_action": { 8 | "default_title": "[staging] Project Icarus" 9 | }, 10 | "icons": { 11 | "16": "img/icon-16.png", 12 | "48": "img/icon-48.png", 13 | "128": "img/icon-128.png" 14 | }, 15 | "background": { 16 | "page": "background.html" 17 | }, 18 | "permissions": [ 19 | "contextMenus", 20 | "management", 21 | "tabs", 22 | "storage" 23 | ], 24 | "content_security_policy": "default-src 'self'; script-src 'self' 'unsafe-eval'; connect-src https://lld5qq5jl5.execute-api.us-east-1.amazonaws.com wss://18.206.30.1; style-src * 'unsafe-inline' 'self' blob:; img-src 'self' data:;" 25 | } 26 | -------------------------------------------------------------------------------- /chrome/manifest.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.0", 3 | "name": "project-icarus", 4 | "manifest_version": 2, 5 | "description": "[test] Cardano ADA wallet", 6 | "browser_action": { 7 | "default_title": "[test] Project Icarus" 8 | }, 9 | "icons": { 10 | "16": "img/icon-16.png", 11 | "48": "img/icon-48.png", 12 | "128": "img/icon-128.png" 13 | }, 14 | "background": { 15 | "page": "background.html" 16 | }, 17 | "permissions": [ 18 | "contextMenus", 19 | "management", 20 | "tabs", 21 | "storage" 22 | ], 23 | "content_security_policy": "default-src 'self'; script-src 'self' 'unsafe-eval'; connect-src http://localhost:8080 https://localhost:8080 ws://localhost:8080 wss://localhost:8080; style-src * 'unsafe-inline' 'self' blob:; img-src 'self' data:;" 24 | } 25 | -------------------------------------------------------------------------------- /chrome/manifest.testnet.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.13", 3 | "version_name": "tn-0.0.13#68.0_GC-w7", 4 | "name": "project-icarus", 5 | "manifest_version": 2, 6 | "description": "[testnet] Cardano ADA wallet", 7 | "browser_action": { 8 | "default_title": "[testnet] Project Icarus" 9 | }, 10 | "icons": { 11 | "16": "img/icon-16.png", 12 | "48": "img/icon-48.png", 13 | "128": "img/icon-128.png" 14 | }, 15 | "background": { 16 | "page": "background.html" 17 | }, 18 | "permissions": [ 19 | "contextMenus", 20 | "management", 21 | "tabs", 22 | "storage" 23 | ], 24 | "content_security_policy": "default-src 'self'; script-src 'self' 'unsafe-eval'; connect-src https://18.207.22.26:8080 wss://18.207.22.26:8080; style-src * 'unsafe-inline' 'self' blob:; img-src 'self' data:;" 25 | } 26 | -------------------------------------------------------------------------------- /chrome/views/background.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | 3 | html 4 | head 5 | script(src='./js/vendor.js') 6 | script(src=env != 'development' ? '/js/background.bundle.js' : 'http://localhost:3000/js/background.bundle.js') -------------------------------------------------------------------------------- /chrome/views/main_window.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | 3 | html 4 | head 5 | meta(charset='UTF-8') 6 | title Project Icarus 7 | style. 8 | body { width: 500px; } 9 | 10 | body 11 | #root 12 | script(src='./js/vendor.js') 13 | script(src=env != 'development' ? '/js/projecticarus.bundle.js' : 'http://localhost:3000/js/projecticarus.bundle.js') -------------------------------------------------------------------------------- /config/config-types.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | export type ConfigType = { 4 | network: NetworkConfigType, 5 | app: AppConfigType, 6 | }; 7 | 8 | export type AppConfigType = { 9 | walletRefreshInterval: number, 10 | logsBufferSize: number, 11 | logsFileSuffix: string, 12 | addressScanSize: number, 13 | addressRequestSize: number 14 | } 15 | 16 | export type NetworkConfigType = { 17 | protocolMagic: 633343913 | 764824073, 18 | backendUrl: string, 19 | websocketUrl: string, 20 | name: string, 21 | }; 22 | -------------------------------------------------------------------------------- /config/development.json: -------------------------------------------------------------------------------- 1 | { 2 | "network": { 3 | "protocolMagic": 633343913, 4 | "backendUrl": "https://lld5qq5jl5.execute-api.us-east-1.amazonaws.com/latest", 5 | "websocketUrl": "wss://18.206.30.1:443", 6 | "name": "testnet" 7 | }, 8 | "app": { 9 | "walletRefreshInterval": 20000, 10 | "logsBufferSize": 500, 11 | "logsFileSuffix": "-project-icarus.log", 12 | "addressScanSize": 20, 13 | "addressRequestSize": 50 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /config/mainnet.json: -------------------------------------------------------------------------------- 1 | { 2 | "network": { 3 | "protocolMagic": 764824073, 4 | "backendUrl": "https://DEFINE:443", 5 | "websocketUrl": "wss://DEFINE:443", 6 | "name": "mainnet" 7 | }, 8 | "app": { 9 | "walletRefreshInterval": 20000, 10 | "logsBufferSize": 500, 11 | "logsFileSuffix": "-project-icarus.log", 12 | "addressScanSize": 20, 13 | "addressRequestSize": 50 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /config/staging.json: -------------------------------------------------------------------------------- 1 | { 2 | "network": { 3 | "protocolMagic": 633343913, 4 | "backendUrl": "https://lld5qq5jl5.execute-api.us-east-1.amazonaws.com/latest", 5 | "websocketUrl": "wss://18.206.30.1:443", 6 | "name": "staging" 7 | }, 8 | "app": { 9 | "walletRefreshInterval": 20000, 10 | "logsBufferSize": 500, 11 | "logsFileSuffix": "-project-icarus.log", 12 | "addressScanSize": 20, 13 | "addressRequestSize": 50 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /config/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "network": { 3 | "protocolMagic": 633343913, 4 | "backendUrl": "http://localhost:8080", 5 | "websocketUrl": "ws://localhost:8080" 6 | }, 7 | "app": { 8 | "walletRefreshInterval": 2000, 9 | "logsBufferSize": 500, 10 | "logsFileSuffix": "-project-icarus.log", 11 | "addressScanSize": 3, 12 | "addressRequestSize": 5 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /config/testnet.json: -------------------------------------------------------------------------------- 1 | { 2 | "network": { 3 | "protocolMagic": 1097911063, 4 | "backendUrl": "https://18.207.22.26:8080", 5 | "websocketUrl": "wss://18.207.22.26:8080", 6 | "name": "testnet" 7 | }, 8 | "app": { 9 | "walletRefreshInterval": 20000, 10 | "logsBufferSize": 500, 11 | "logsFileSuffix": "-project-icarus.log", 12 | "addressScanSize": 20, 13 | "addressRequestSize": 50 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /features/accept-terms-of-use.feature: -------------------------------------------------------------------------------- 1 | Feature: Accept "Terms of use" 2 | 3 | Background: 4 | Given I have opened the chrome extension 5 | And I have selected English language 6 | 7 | Scenario: User accepts "Terms of use" 8 | Given I am on the "Terms of use" screen 9 | And I click on "I agree with terms of use" checkbox 10 | When I submit the "Terms of use" form 11 | Then I should not see the "Terms of use" screen anymore 12 | And I should have "Terms of use" accepted 13 | -------------------------------------------------------------------------------- /features/create-wallet.feature: -------------------------------------------------------------------------------- 1 | Feature: Create wallet 2 | 3 | Background: 4 | Given I have opened the chrome extension 5 | And I have completed the basic setup 6 | And There is no wallet stored 7 | 8 | Scenario: Successfully creating a wallet 9 | When I click the create button 10 | And I enter the name "Created Wallet" 11 | And I enter the created wallet password: 12 | | password | repeatedPassword | 13 | | Secret_123 | Secret_123 | 14 | And I click the "Create personal wallet" button 15 | And I accept the creation terms 16 | And I copy and enter the displayed mnemonic phrase 17 | Then I should see the opened wallet with name "Created Wallet" 18 | 19 | Scenario: Fail to create due to incomplete fields 20 | When I click the create button 21 | And I enter the name "Created Wallet" 22 | And I enter the created wallet password: 23 | | password | repeatedPassword | 24 | | Secret_123 | Secret_123 | 25 | And I clear the name "Created Wallet" 26 | And I clear the created wallet password Secret_123 27 | And I click the "Create personal wallet" button 28 | Then I should stay in the create wallet dialog -------------------------------------------------------------------------------- /features/get-balance.feature: -------------------------------------------------------------------------------- 1 | Feature: Get balance 2 | 3 | Background: 4 | Given I have opened the chrome extension 5 | And I have completed the basic setup 6 | And I am testing "Get balance" 7 | 8 | Scenario: Get balance with 1 address 9 | Given There is a wallet stored named simple-wallet 10 | Then I should see the balance number "0.000000 ADA" 11 | 12 | Scenario: Get balance with 45 addresses 13 | Given There is a wallet stored named complex-wallet 14 | Then I should see the balance number "0.020295 ADA" 15 | 16 | Scenario: Get balance with a big amount 17 | Given There is a wallet stored named Test 18 | Then I should see the balance number "9,007,199,254.720698 ADA" 19 | -------------------------------------------------------------------------------- /features/navigate-general-settings-menu.feature: -------------------------------------------------------------------------------- 1 | Feature: General Settings 2 | 3 | Background: 4 | Given I have opened the chrome extension 5 | And I have completed the basic setup 6 | And I am testing "General Settings" 7 | 8 | Scenario: Change language in General Settings 9 | Given There is a wallet stored named Test 10 | When I navigate to the general settings screen 11 | And I open General Settings language selection dropdown 12 | And I select Japanese language 13 | Then I should see Japanese language as selected 14 | 15 | Scenario: Users should not be able to navigate wallet settings if there isn't any created 16 | Given There is no wallet stored 17 | When I navigate to the general settings screen 18 | Then I should see secondary menu "wallet" item disabled 19 | -------------------------------------------------------------------------------- /features/select-language.feature: -------------------------------------------------------------------------------- 1 | Feature: Select Language 2 | 3 | Scenario: User Selects Language 4 | Given I have opened the chrome extension 5 | And I am on the language selection screen 6 | And I open language selection dropdown 7 | And I select Japanese language 8 | When I submit the language selection form 9 | Then I should not see the language selection screen anymore 10 | And I should have Japanese language set 11 | -------------------------------------------------------------------------------- /features/step_definitions/accept-terms-of-use-steps.js: -------------------------------------------------------------------------------- 1 | import { Given, When, Then } from 'cucumber'; 2 | import { expect } from 'chai'; 3 | import termsOfUse from '../support/helpers/terms-of-use-helpers'; 4 | 5 | const TERMS_OF_USE_FORM = '.TermsOfUseForm_component'; 6 | 7 | Given(/^I have accepted "Terms of use"$/, async function () { 8 | await termsOfUse.acceptTerms(this.driver); 9 | }); 10 | 11 | Given(/^I am on the "Terms of use" screen$/, async function () { 12 | await this.waitForElement(TERMS_OF_USE_FORM); 13 | }); 14 | 15 | When(/^I click on "I agree with terms of use" checkbox$/, async function () { 16 | await this.click('.TermsOfUseForm_component .SimpleCheckbox_root'); 17 | }); 18 | 19 | When(/^I submit the "Terms of use" form$/, async function () { 20 | await this.click('.TermsOfUseForm_submitButton'); 21 | }); 22 | 23 | Then(/^I should not see the "Terms of use" screen anymore$/, async function () { 24 | await this.waitForElementNotPresent(TERMS_OF_USE_FORM); 25 | }); 26 | 27 | Then(/^I should have "Terms of use" accepted$/, async function () { 28 | const result = await this.driver.executeAsyncScript((done) => { 29 | window.projecticarus.stores.profile.getTermsOfUseAcceptanceRequest.execute() 30 | .then(done) 31 | .catch((error) => done(error)); 32 | }); 33 | expect(result).to.equal(true); 34 | }); 35 | -------------------------------------------------------------------------------- /features/step_definitions/get-balance-steps.js: -------------------------------------------------------------------------------- 1 | import { When, Then } from 'cucumber'; 2 | 3 | Then(/^I should see the balance number "([^"]*)"$/, async function (number) { 4 | await this.waitUntilText('.TopBar_walletAmount', number); 5 | }); 6 | -------------------------------------------------------------------------------- /features/step_definitions/select-language-steps.js: -------------------------------------------------------------------------------- 1 | import { Given, When, Then } from 'cucumber'; 2 | import { By } from 'selenium-webdriver'; 3 | import { expect } from 'chai'; 4 | import languageSelection from '../support/helpers/language-selection-helpers'; 5 | 6 | const LANGUAGE_SELECTION_FORM = '.LanguageSelectionForm_component'; 7 | 8 | Given(/^I have selected English language$/, async function () { 9 | await languageSelection.ensureLanguageIsSelected(this.driver, { language: 'en-US' }); 10 | }); 11 | 12 | When(/^I am on the language selection screen$/, async function () { 13 | await this.waitForElement(LANGUAGE_SELECTION_FORM); 14 | }); 15 | 16 | When(/^I open language selection dropdown$/, async function () { 17 | await this.click(`${LANGUAGE_SELECTION_FORM} .SimpleInput_input`); 18 | }); 19 | 20 | When(/^I select Japanese language$/, async function () { 21 | await this.click('//li[contains(text(), "日本語")]', By.xpath); 22 | }); 23 | 24 | When(/^I submit the language selection form$/, async function () { 25 | await this.click('.LanguageSelectionForm_submitButton'); 26 | }); 27 | 28 | Then(/^I should not see the language selection screen anymore$/, async function () { 29 | await this.waitForElementNotPresent(LANGUAGE_SELECTION_FORM); 30 | }); 31 | 32 | Then(/^I should have Japanese language set$/, async function () { 33 | const result = await this.driver.executeAsyncScript((done) => { 34 | window.projecticarus.stores.profile.getProfileLocaleRequest.execute() 35 | .then(done) 36 | .catch((error) => done(error)); 37 | }); 38 | expect(result).to.equal('ja-JP'); 39 | }); 40 | -------------------------------------------------------------------------------- /features/step_definitions/wallet-steps.js: -------------------------------------------------------------------------------- 1 | import { When, Then } from 'cucumber'; 2 | 3 | When(/^I enter the name "([^"]*)"$/, async function (walletName) { 4 | await this.input('#walletName--2', walletName); 5 | }); 6 | 7 | When(/^I clear the name "([^"]*)"$/, async function (walletName) { 8 | await this.clearInputUpdatingForm('#walletName--2', walletName.length); 9 | }); 10 | 11 | When(/^I navigate to wallet transactions screen$/, async function () { 12 | await this.click('.TopBarCategory_component.wallets'); 13 | await this.waitForElement('.WalletSummary_numberOfTransactions'); 14 | }); 15 | 16 | Then(/^I should see the opened wallet with name "([^"]*)"$/, async function (walletName) { 17 | const walletNameFormatted = walletName.toUpperCase(); 18 | await this.waitUntilText('.TopBar_walletName', walletNameFormatted); 19 | }); 20 | -------------------------------------------------------------------------------- /features/support/default-wallet.json: -------------------------------------------------------------------------------- 1 | {"wallet":{"accounts":[{"name":"Genesis account","index":2147483648}],"walletSecretKey":"WIAwbsQgbz9X0WhvOnVeH+yRs7Ri93ESTdMspBHzeLnPUR6hLZL/NazfB40z2x8FZhLwNIt83DCuMR1nGG+ZqvsD/ouyzg3ec729fnrqEMO4A+qPTJmpiRgQZfYO2KDJDRxLtMyofXl90VVZOEke/QddnZ8CGHoR/lCemJgZuvzBpw==","walletMeta":{"name":"Genesis wallet","assurance":"normal","unit":"ADA"},"passwordHash":"WGQxNHw4fDF8V0NERGRHY0JGcThzelVyeFdza00wM1VjYnloeVBBQXBvdWtwdWFsUTExNGVFdz09fFJXMk5kUmVJYmg2REtsa2lsWG8rQ1lvTStRZmJkMzRmRVd0MG4rSy82YUU9"},"fileType":"WALLETS_EXPORT","fileVersion":"1.0.0"} -------------------------------------------------------------------------------- /features/support/default-wallet.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/features/support/default-wallet.key -------------------------------------------------------------------------------- /features/support/default-wallet.key.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/project-icarus-chrome/62d01899b7c9e9d20a3fd4ad73afbcfcbe6b33ce/features/support/default-wallet.key.lock -------------------------------------------------------------------------------- /features/support/helpers/i18n-helpers.js: -------------------------------------------------------------------------------- 1 | import { IntlProvider } from 'react-intl'; 2 | 3 | const DEFAULT_LANGUAGE = 'en-US'; 4 | 5 | export default { 6 | setActiveLanguage: async (client, { language } = {}) => 7 | await client.executeScript(locale => { 8 | projecticarus.actions.profile.updateLocale.trigger({ locale }); 9 | }, language || DEFAULT_LANGUAGE), 10 | 11 | getActiveLanguage: async client => 12 | await client.executeScript(() => projecticarus.stores.profile.currentLocale), 13 | 14 | formatMessage: async (client, { id, values }) => { 15 | const [locale, messages] = await client.executeScript(() => 16 | [projecticarus.stores.profile.currentLocale, projecticarus.translations] 17 | ); 18 | const intlProvider = new IntlProvider({ locale, messages: messages[locale] }, {}); 19 | const translation = intlProvider.getChildContext() 20 | .intl.formatMessage({ id }, values || {}); 21 | return translation; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /features/support/helpers/language-selection-helpers.js: -------------------------------------------------------------------------------- 1 | import i18n from './i18n-helpers'; 2 | 3 | const LANGUAGE_SELECTION_FORM = '.LanguageSelectionForm_component'; 4 | 5 | const languageSelection = { 6 | waitForVisible: async (client, { isHidden } = {}) => { 7 | if (isHidden) { 8 | return client.waitForElementNotPresent(LANGUAGE_SELECTION_FORM); 9 | } 10 | return client.waitForElement(LANGUAGE_SELECTION_FORM); 11 | }, 12 | ensureLanguageIsSelected: async (client, { language } = {}) => { 13 | await languageSelection.waitForVisible(client); 14 | i18n.setActiveLanguage(client, { language }); 15 | await languageSelection.waitForVisible(client, { isHidden: true }); 16 | } 17 | }; 18 | 19 | export default languageSelection; 20 | -------------------------------------------------------------------------------- /features/support/helpers/route-helpers.js: -------------------------------------------------------------------------------- 1 | export const getCurrentAppRoute = async function () { 2 | const url = (await this.driver.getCurrentUrl()); 3 | return url.substring(url.indexOf('#/') + 1); // return without the hash 4 | }; 5 | 6 | export const waitUntilUrlEquals = function (expectedUrl) { 7 | const context = this; 8 | return context.driver.wait(async () => { 9 | const url = await getCurrentAppRoute.call(context); 10 | return url === expectedUrl; 11 | }); 12 | }; 13 | 14 | export const navigateTo = function (requestedRoute) { 15 | return this.driver.executeScript((route) => { 16 | window.projecticarus.actions.router.goToRoute.trigger({ route }); 17 | }, requestedRoute); 18 | }; 19 | -------------------------------------------------------------------------------- /features/support/helpers/terms-of-use-helpers.js: -------------------------------------------------------------------------------- 1 | const TERMS_OF_USE_FORM = '.TermsOfUseForm_component'; 2 | 3 | const termsOfUse = { 4 | waitForVisible: async (client, { isHidden } = {}) => ( 5 | client.waitForVisible(TERMS_OF_USE_FORM, null, isHidden) 6 | ), 7 | }; 8 | 9 | export default termsOfUse; 10 | -------------------------------------------------------------------------------- /features/support/mockWebSocketServer.js: -------------------------------------------------------------------------------- 1 | import WebSocket from 'ws'; 2 | 3 | const MSG_TYPE_RESTORE = 'RESTORE'; 4 | const fromMessage = JSON.parse; 5 | const toMessage = JSON.stringify; 6 | 7 | let wss = null; 8 | 9 | export function getMockWebSocketServer(server) { 10 | if (!wss) { 11 | wss = new WebSocket.Server({ server }); 12 | } 13 | return wss; 14 | } 15 | 16 | export function closeMockWebSocketServer() { 17 | wss = null; 18 | } 19 | 20 | export function mockRestoredDaedalusAddresses(addresses) { 21 | wss.on('connection', ws => { 22 | ws.on('message', (msg) => { 23 | const data = fromMessage(msg); 24 | switch (data.msg) { 25 | case MSG_TYPE_RESTORE: 26 | ws.send(toMessage({ 27 | msg: MSG_TYPE_RESTORE, 28 | addresses 29 | })); 30 | break; 31 | default: 32 | break; 33 | } 34 | }); 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /flow/declarations/File.js: -------------------------------------------------------------------------------- 1 | declare class File { 2 | name: string, 3 | path: string, 4 | } 5 | -------------------------------------------------------------------------------- /flow/mappers/CSSModule.js.flow: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare export default { [key: string]: string } 3 | -------------------------------------------------------------------------------- /flow/mappers/GeneralStub.js.flow: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /flow/mappers/WebpackAsset.js.flow: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare export default string 3 | -------------------------------------------------------------------------------- /scripts/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "shelljs": true 4 | }, 5 | "rules": { 6 | "no-console": 0, 7 | "import/no-extraneous-dependencies": ["error", { "devDependencies": true }] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | const tasks = require('./tasks'); 2 | const argv = require('minimist')(process.argv.slice(2)); 3 | 4 | process.env.NODE_ENV = argv.env; 5 | 6 | tasks.replaceWebpack(); 7 | console.log('[Copy assets]'); 8 | console.log('-'.repeat(80)); 9 | tasks.copyAssets('build', argv.env); 10 | 11 | console.log('[Webpack Build]'); 12 | console.log('-'.repeat(80)); 13 | 14 | exec(`./node_modules/.bin/webpack --config webpack/${argv.env}.config.js --progress --profile --colors`); 15 | -------------------------------------------------------------------------------- /scripts/compress.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const ChromeExtension = require('crx'); 4 | const argv = require('minimist')(process.argv.slice(2)); 5 | /* eslint import/no-unresolved: 0 */ 6 | const name = require('../build/manifest.json').name; 7 | 8 | const keyPath = argv.key; 9 | const existsKey = fs.existsSync(keyPath); 10 | const zipOnly = argv['zip-only']; 11 | const isCrx = !zipOnly; 12 | 13 | if (!argv.codebase || (isCrx && !existsKey)) { 14 | console.error('Missing input data.'); 15 | return; 16 | } 17 | 18 | const crx = new ChromeExtension({ 19 | appId: argv['app-id'], 20 | codebase: argv.codebase, 21 | privateKey: existsKey 22 | ? fs.readFileSync(keyPath) 23 | : null 24 | }); 25 | 26 | async function compress(isCrxBuild) { 27 | await crx.load(path.join(__dirname, '../build')); 28 | const archiveBuffer = await crx.loadContents(); 29 | fs.writeFileSync(`${name}.zip`, archiveBuffer); 30 | if (isCrxBuild) { 31 | const crxBuffer = await crx.pack(archiveBuffer); 32 | const updateXML = crx.generateUpdateXML(); 33 | fs.writeFileSync('update.xml', updateXML); 34 | fs.writeFileSync(`${name}-${argv.env}.crx`, crxBuffer); 35 | fs.unlinkSync(`${name}.zip`); 36 | } 37 | } 38 | 39 | compress(isCrx).catch(err => console.error(err)); 40 | -------------------------------------------------------------------------------- /scripts/start.js: -------------------------------------------------------------------------------- 1 | const tasks = require('./tasks'); 2 | 3 | const createWebpackServer = require('webpack-httpolyglot-server'); 4 | 5 | const argv = require('minimist')(process.argv.slice(2)); 6 | 7 | const config = require(`../webpack/${argv.env}.config`); 8 | 9 | tasks.replaceWebpack(); 10 | console.log('[Copy assets]'); 11 | console.log('-'.repeat(80)); 12 | tasks.copyAssets('dev', argv.env); 13 | 14 | console.log('[Webpack Dev]'); 15 | console.log('-'.repeat(80)); 16 | console.log('If you\'re developing Inject page,'); 17 | console.log('please allow `https://localhost:3000` connections in Google Chrome,'); 18 | console.log('and load unpacked extensions with `./dev` folder. (see https://developer.chrome.com/extensions/getstarted#unpacked)\n'); 19 | createWebpackServer(config, { 20 | host: 'localhost', 21 | port: 3000 22 | }); 23 | -------------------------------------------------------------------------------- /scripts/tasks.js: -------------------------------------------------------------------------------- 1 | require('shelljs/global'); 2 | 3 | exports.replaceWebpack = () => { 4 | const replaceTasks = [{ 5 | from: 'webpack/replace/JsonpMainTemplate.runtime.js', 6 | to: 'node_modules/webpack/lib/JsonpMainTemplate.runtime.js' 7 | }, { 8 | from: 'webpack/replace/process-update.js', 9 | to: 'node_modules/webpack-hot-middleware/process-update.js' 10 | }]; 11 | 12 | replaceTasks.forEach(task => cp(task.from, task.to)); 13 | }; 14 | 15 | exports.copyAssets = (type, env) => { 16 | rm('-rf', type); 17 | mkdir(type); 18 | mkdir(`${type}/js`); 19 | cp(`chrome/manifest.${env}.json`, `${type}/manifest.json`); 20 | cp('-R', 'chrome/assets/*', type); 21 | cp('-R', 'dll/*', `${type}/js/`); 22 | exec(`./node_modules/.bin/pug -O "{ env: '${env}' }" -o ${type} chrome/views/`); 23 | }; 24 | -------------------------------------------------------------------------------- /setup_cardano_crypto.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | git submodule update --init --recursive && \ 4 | cd js-cardano-wasm && \ 5 | npm install && \ 6 | ./build && \ 7 | npm link && \ 8 | cd .. && \ 9 | npm link rust-cardano-crypto 10 | -------------------------------------------------------------------------------- /translations/translation-runner.js: -------------------------------------------------------------------------------- 1 | const manageTranslations = require('react-intl-translations-manager').default; 2 | 3 | manageTranslations({ 4 | messagesDirectory: 'translations/messages', 5 | translationsDirectory: 'app/i18n/locales', 6 | singleMessagesFile: true, 7 | languages: ['en-US', 'hr-HR', 'de-DE', 'zh-CN', 'ko-KR', 'ja-JP'] 8 | }); 9 | -------------------------------------------------------------------------------- /webpack/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-extraneous-dependencies": ["error", { "devDependencies": true }] 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /webpack/customPublicPath.js: -------------------------------------------------------------------------------- 1 | /* global __webpack_public_path__ __HOST__ __PORT__ */ 2 | /* eslint no-global-assign: 0 camelcase: 0 */ 3 | 4 | if (process.env.NODE_ENV !== 'development') { 5 | __webpack_public_path__ = chrome.extension.getURL('/js/'); 6 | } else { 7 | // In development mode, 8 | // the iframe of injectpage cannot get correct path, 9 | // it need to get parent page protocol. 10 | const path = `//${__HOST__}:${__PORT__}/js/`; 11 | if (location.protocol === 'https:' || location.search.indexOf('protocol=https') !== -1) { 12 | __webpack_public_path__ = `https:${path}`; 13 | } else { 14 | __webpack_public_path__ = `http:${path}`; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /webpack/dll.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | 4 | const dependencies = Object.keys( 5 | require('../package.json').dependencies 6 | ).filter(dep => dep !== 'react-polymorph' && dep !== 'node-sass'); 7 | 8 | module.exports = { 9 | context: process.cwd(), 10 | resolve: { 11 | extensions: ['.js', '.jsx', '.json', '.less', '.css'], 12 | modules: [__dirname, 'node_modules'] 13 | }, 14 | 15 | entry: { 16 | vendor: dependencies 17 | }, 18 | output: { 19 | filename: '[name].js', 20 | path: path.resolve(__dirname, '../dll'), 21 | library: '[name]' 22 | }, 23 | 24 | plugins: [ 25 | new webpack.DllPlugin({ 26 | context: __dirname, 27 | name: '[name]', 28 | path: path.join(__dirname, '../dll/[name]-manifest.json') 29 | }) 30 | ] 31 | }; 32 | --------------------------------------------------------------------------------