From e3ce6528b6d2236d1ce9c70bf5f8b8698b41fe6a Mon Sep 17 00:00:00 2001 From: "Eugene Sypachev (@Axblade)" Date: Tue, 4 Dec 2018 15:42:04 +0300 Subject: [PATCH] format code --- Makefile | 2 +- README.md | 2 +- package.json | 2 +- packages/insight-api/lib/addresses.js | 155 +- packages/insight-api/lib/blocks.js | 39 +- packages/insight-api/lib/common.js | 14 +- packages/insight-api/lib/currency.js | 15 +- packages/insight-api/lib/index.js | 87 +- packages/insight-api/lib/messages.js | 30 +- packages/insight-api/lib/ratelimiter.js | 19 +- packages/insight-api/lib/referrals.js | 3 +- packages/insight-api/lib/service.js | 2 - packages/insight-api/lib/status.js | 77 +- packages/insight-api/lib/transactions.js | 159 +- packages/insight-api/lib/utils.js | 38 +- packages/insight-api/lib/wallet.js | 8 +- packages/insight-api/test/addresses.js | 744 +- packages/insight-api/test/blocks.js | 200 +- packages/insight-api/test/currency.js | 52 +- packages/insight-api/test/index.js | 54 +- packages/insight-api/test/messages.js | 48 +- packages/insight-api/test/ratelimiter.js | 56 +- packages/insight-api/test/status.js | 51 +- packages/insight-api/test/transactions.js | 1038 +- packages/insight-api/test/utils.js | 24 +- packages/insight-ui/public/src/js/config.js | 65 +- .../public/src/js/controllers/address.js | 18 +- .../public/src/js/controllers/scanner.js | 274 +- .../insight-ui/public/src/js/translations.js | 403 +- .../common/common-directives.module.ts | 8 +- .../lightwallet/common/common-pipes.module.ts | 6 +- .../common/common-providers.module.ts | 4 +- .../lightwallet/common/const/wallet-colors.ts | 42 +- .../common/directives/gtag.directive.ts | 16 +- .../lightwallet/common/effects/app.effects.ts | 8 +- .../common/effects/goal.effects.ts | 56 +- .../effects/interface-preferences.effects.ts | 123 +- .../common/effects/notification.effects.ts | 41 +- .../common/effects/transaction.effects.ts | 40 +- .../common/effects/wallet.effects.ts | 108 +- .../environments/environment.example.ts | 4 +- .../common/environments/environment.prod.ts | 4 +- .../environments/environment.staging.ts | 4 +- .../common/merit-market-client/api.ts | 18 +- .../common/merit-wallet-client/index.ts | 7 +- .../common/merit-wallet-client/lib/api.ts | 983 +- .../lib/common/constants.ts | 12 +- .../lib/common/defaults.ts | 16 +- .../merit-wallet-client/lib/common/index.ts | 8 +- .../merit-wallet-client/lib/common/utils.ts | 102 +- .../merit-wallet-client/lib/credentials.ts | 127 +- .../merit-wallet-client/lib/errors/index.ts | 16 +- .../merit-wallet-client/lib/errors/spec.ts | 164 +- .../common/merit-wallet-client/lib/index.ts | 4 +- .../common/merit-wallet-client/lib/log.ts | 55 +- .../common/merit-wallet-client/lib/paypro.ts | 56 +- .../merit-wallet-client/lib/verifier.ts | 52 +- .../common/merit-wallet-client/test/client.js | 3888 +- .../merit-wallet-client/test/credentials.js | 225 +- .../test/legacyImportData.js | 66 +- .../common/merit-wallet-client/test/log.js | 11 +- .../common/merit-wallet-client/test/paypro.js | 161 +- .../merit-wallet-client/test/testdata.js | 259 +- .../common/merit-wallet-client/test/utils.js | 311 +- .../common/models/display-wallet.ts | 89 +- .../lightwallet/common/models/easy-receipt.ts | 9 +- .../lightwallet/common/models/easy-send.ts | 6 +- .../lightwallet/common/models/fiat-amount.ts | 10 +- .../common/models/merit-contact.ts | 15 +- .../lightwallet/common/models/send-method.ts | 4 +- .../common/models/sms-subscription.ts | 4 +- .../common/models/transaction-proposal.ts | 1 - .../lightwallet/common/models/transaction.ts | 8 +- packages/lightwallet/common/models/vault.ts | 6 +- .../pipes/address-error-message.pipe.ts | 14 +- .../common/pipes/address.pipe.spec.ts | 26 +- .../lightwallet/common/pipes/address.pipe.ts | 2 +- .../common/pipes/alias-error-message.pipe.ts | 14 +- .../lightwallet/common/pipes/chunks.pipe.ts | 5 +- .../lightwallet/common/pipes/to-fiat.pipe.ts | 6 +- .../common/pipes/to-mrt.pipe.spec.ts | 25 +- .../lightwallet/common/pipes/to-mrt.pipe.ts | 10 +- .../common/pipes/to-unit.pipe.spec.ts | 18 +- .../lightwallet/common/pipes/to-unit.pipe.ts | 3 +- .../common/pipes/unescape.pipe.spec.ts | 14 +- .../lightwallet/common/pipes/unescape.pipe.ts | 2 +- .../common/reducers/app.reducer.ts | 9 +- .../common/reducers/notifications.reducer.ts | 68 +- .../common/reducers/transactions.reducer.ts | 41 +- .../common/reducers/wallets.reducer.ts | 73 +- .../common/services/address.service.ts | 3 +- .../common/services/app-settings.service.ts | 10 +- .../common/services/config.service.ts | 56 +- .../common/services/contacts.service.ts | 74 +- .../common/services/easy-receive.service.ts | 46 +- .../common/services/easy-send.service.ts | 44 +- .../services/email-notification.service.ts | 21 +- .../common/services/fee.service.ts | 13 +- .../common/services/language.service.ts | 51 +- .../common/services/ledger.service.ts | 54 +- .../common/services/logger.service.ts | 10 +- .../common/services/mnemonic.service.ts | 12 +- .../mobile-push-notifications-service.ts | 48 +- .../common/services/mwc.service.ts | 7 +- .../common/services/persistence.service.ts | 5 +- .../common/services/persistence2.service.ts | 14 +- .../common/services/platform.service.ts | 3 +- .../services/polling-notification.service.ts | 31 +- .../common/services/profile.service.ts | 107 +- .../services/push-notification.service.ts | 22 +- .../common/services/rate.service.ts | 20 +- .../common/services/send.service.ts | 45 +- .../services/sms-notifications.service.ts | 22 +- .../common/services/tx-format.service.ts | 83 +- .../common/services/unlock-request.service.ts | 51 +- .../common/services/vaults.service.ts | 140 +- .../common/services/wallet.service.ts | 115 +- .../web-push-notifications.service.ts | 47 +- .../lightwallet/common/utils/constants.ts | 7 +- packages/lightwallet/common/utils/contacts.ts | 7 +- .../common/utils/derivation-path.ts | 16 +- .../common/utils/destination.spec.ts | 6 +- .../lightwallet/common/utils/destination.ts | 6 +- packages/lightwallet/common/utils/format.ts | 2 +- packages/lightwallet/common/utils/invites.ts | 2 +- .../lightwallet/common/utils/mnemonic.spec.ts | 6 +- packages/lightwallet/common/utils/mnemonic.ts | 10 +- .../common/utils/notification-settings.ts | 81 +- .../lightwallet/common/utils/observables.ts | 3 +- .../lightwallet/common/utils/transactions.ts | 245 +- packages/lightwallet/common/utils/url.ts | 14 +- .../common/utils/wordlists/english.ts | 2051 +- .../common/validators/address.validator.ts | 25 +- .../common/validators/email.validator.spec.ts | 4 +- .../common/validators/email.validator.ts | 19 +- .../common/validators/invite.validator.ts | 5 +- .../common/validators/mnemonic.validator.ts | 6 +- .../common/validators/password.validator.ts | 4 +- .../common/validators/send.validator.spec.ts | 16 +- .../common/validators/send.validator.ts | 21 +- .../lightwallet/desktop/e2e/app.e2e-spec.ts | 23 +- .../desktop/e2e/community.e2e-spec.ts | 3 +- .../desktop/e2e/dashboard.e2e-spec.ts | 5 - .../desktop/e2e/history.e2e-spec.ts | 2 - .../desktop/e2e/send-flow.e2e-spec.ts | 4 - .../desktop/e2e/wallet-details.e2e-spec.ts | 48 +- .../lightwallet/desktop/electron.bootstrap.js | 6 +- packages/lightwallet/desktop/electron.main.js | 46 +- .../lightwallet/desktop/electron.updater.js | 8 +- .../desktop/src/app/app-routing.module.ts | 37 +- .../desktop/src/app/app.component.ts | 14 +- .../lightwallet/desktop/src/app/app.module.ts | 2 +- .../components/backdrop/backdrop.component.ts | 2 +- .../confirm-dialog-controller.service.ts | 2 +- .../confirm-dialog.component.ts | 2 +- .../confirm-dialog/confirm-dialog.spec.ts | 12 +- .../src/app/components/dom.controller.ts | 6 +- .../globalsend-link-popup.component.ts | 4 +- .../sending-merit/sending-merit.component.ts | 2 +- .../thats-it/thats-it.component.ts | 4 +- .../worry-free/worry-free.component.ts | 2 +- .../your-way/your-way.component.ts | 2 +- .../loading-spinner-small.component.ts | 2 +- .../loading-spinner.component.ts | 2 +- .../lock-screen/lock-screen.component.ts | 4 +- .../merit-icon/merit-icon.component.ts | 7 +- .../message-box/message-box.component.ts | 2 +- .../password-prompt.component.ts | 8 +- .../password-prompt.controller.ts | 2 +- .../password-prompt/password-prompt.spec.ts | 15 +- .../components/shared-components.module.ts | 6 +- .../sms-notifications-prompt.component.ts | 16 +- .../toast-controller.service.ts | 6 +- .../toast-notification.component.ts | 4 +- .../toast-notification.spec.ts | 8 +- .../ui-checkbox/ui-checkbox.component.ts | 10 +- .../update-dialog/update-dialog.component.ts | 38 +- .../wallet-icon/wallet-icon.component.ts | 6 +- .../wallet-unlock-alert.component.ts | 5 +- .../src/app/core/backup/backup.view.ts | 2 +- .../backup/file-backup/file-backup.view.ts | 26 +- .../mnemonic-phrase/mnemonic-phrase.view.ts | 8 +- .../qr-code-backup/qr-code-backup.view.ts | 13 +- .../src/app/core/community/community.view.ts | 12 +- .../fee-selector/fee-selector.component.ts | 8 +- .../history-item/history-item.component.ts | 13 +- .../history-item/history-item.spec.ts | 23 +- .../history-list/history-list.component.ts | 33 +- .../notifications-history.component.ts | 13 +- .../notifications/notifications.component.ts | 10 +- .../community-rank.component.ts | 20 +- .../get-started-tips.component.ts | 9 +- .../profile-stats/profile-stats.component.ts | 13 +- .../components/select/select.component.ts | 15 +- .../send-method/send-method.component.ts | 8 +- .../share-box/share-box.component.ts | 57 +- .../components/toolbar/toolbar.component.ts | 14 +- .../vaults-list/vaults-list.component.ts | 8 +- .../wallets-list/wallets-list.component.ts | 15 +- .../desktop/src/app/core/core.component.ts | 36 +- .../desktop/src/app/core/core.module.ts | 2 +- .../src/app/core/dashboard/dashboard.view.ts | 2 +- .../backup-new-wallet.component.ts | 11 +- .../record-passphrase.component.ts | 8 +- .../task-confirm/task-confirm.component.ts | 18 +- .../welcome-to-setup-tracker.component.ts | 2 +- .../global-settings/global-settings.view.ts | 6 +- .../settings-preferences.view.ts | 39 +- .../settings-session-log.view.ts | 9 +- .../settings-terms-of-use.view.ts | 5 +- .../src/app/core/history/history.view.ts | 11 +- .../invites-history/invites-history.view.ts | 8 +- .../pending-invite-item.component.ts | 21 +- .../invites/send-invite/send-invite.view.ts | 94 +- .../src/app/core/receive/receive.view.ts | 57 +- .../send/send-tour/send-tour.component.ts | 6 +- .../desktop/src/app/core/send/send.view.ts | 235 +- .../task-preview/task-preview.component.ts | 11 +- .../wallet-setup-list.view.ts | 43 +- .../create-wallet/create-wallet.view.ts | 57 +- .../wallet-details-history.view.ts | 21 +- .../wallet-details/wallet-details.view.ts | 32 +- .../wallet-settings/wallet-settings.view.ts | 16 +- .../src/app/core/wallets/wallets.view.ts | 25 +- .../desktop/src/app/guards/dashboard.guard.ts | 25 +- .../src/app/guards/onboarding.guard.ts | 31 +- .../src/app/guards/wallet-password.guard.ts | 21 +- .../import-by-qr/import-by-qr.module.ts | 12 +- .../import/import-by-qr/import-by-qr.view.ts | 5 +- .../src/app/import/import-wallet.view.ts | 2 +- .../import-with-file.module.ts | 17 +- .../import-with-file/import-with-file.view.ts | 62 +- .../desktop/src/app/import/import.module.ts | 12 +- .../phrase-import/phrase-import.module.ts | 17 +- .../phrase-import/phrase-import.view.ts | 61 +- .../escrow-payment/escrow-payment.view.ts | 28 +- .../desktop/src/app/market/escrow.guard.ts | 10 +- .../market/market-login/market-login.view.ts | 9 +- .../desktop/src/app/market/market.module.ts | 11 +- .../app-start-up/app-start-up.component.ts | 4 +- .../guide-beginners-help.component.ts | 2 +- .../guide-went-from-desktop.component.ts | 9 +- .../invited-user/invited-user.component.ts | 9 +- .../sending-merit/sending-merit.component.ts | 9 +- .../thats-it/thats-it.component.ts | 9 +- .../worry-free/worry-free.component.ts | 9 +- .../your-way/your-way.component.ts | 9 +- .../app/onboarding/onboard/onboard.view.ts | 2 +- .../onboarding-root.component.ts | 11 +- .../slider-guide/slider-guide.component.ts | 9 +- .../src/app/onboarding/unlock/unlock.view.ts | 8 +- packages/lightwallet/desktop/src/doc/theme.md | 2 +- .../desktop/src/firebase-messaging-sw.js | 35 +- packages/lightwallet/desktop/src/main.ts | 3 +- .../src/services/desktop-alert.service.ts | 2 +- .../desktop/src/services/electron.service.ts | 2 +- .../lightwallet/desktop/webpack.config.js | 536 +- packages/lightwallet/jest-global-mocks.ts | 18 +- .../lightwallet/mobile/e2e/app.e2e-spec.ts | 22 +- .../mobile/e2e/community.e2e-spec.ts | 5 +- .../mobile/e2e/receive.e2e-spec.ts | 4 +- .../mobile/e2e/send-flow.e2e-spec.ts | 9 +- .../lightwallet/mobile/e2e/transact.po.ts | 6 +- .../mobile/e2e/wallet-details.e2e-spec.ts | 11 +- .../mobile/e2e/wallets.e2e-spec.ts | 1 - .../lightwallet/mobile/generator/README.md | 1 + packages/lightwallet/mobile/generator/run.js | 47 +- .../mobile/generator/templates/module.ts | 8 +- .../mobile/generator/templates/view.ts | 11 +- .../mobile/src/app/app.component.ts | 48 +- .../lightwallet/mobile/src/app/app.module.ts | 29 +- .../app/community/network/network.module.ts | 16 +- .../src/app/community/network/network.ts | 70 +- .../send-invite-amount.module.ts | 14 +- .../send-invite-amount/send-invite-amount.ts | 94 +- .../network/send-invite/send-invite.module.ts | 12 +- .../network/send-invite/send-invite.ts | 59 +- .../mobile/src/app/core/popup.service.ts | 31 +- .../src/app/onboard/alias/alias.module.ts | 12 +- .../mobile/src/app/onboard/alias/alias.ts | 50 +- .../src/app/onboard/backup/backup.module.ts | 14 +- .../mobile/src/app/onboard/backup/backup.ts | 31 +- .../onboard/no-session/no-session.module.ts | 11 +- .../src/app/onboard/no-session/no-session.ts | 8 +- .../src/app/onboard/onboarding.view.module.ts | 11 +- .../mobile/src/app/onboard/onboarding.view.ts | 5 +- .../src/app/onboard/tour/tour.module.ts | 11 +- .../mobile/src/app/onboard/tour/tour.ts | 16 +- .../src/app/onboard/unlock/unlock.module.ts | 13 +- .../mobile/src/app/onboard/unlock/unlock.ts | 42 +- .../verify-backup/verify-backup.module.ts | 12 +- .../onboard/verify-backup/verify-backup.ts | 52 +- .../notifications/notifications.module.ts | 12 +- .../settings/notifications/notifications.ts | 29 +- .../select-currency/select-currency.module.ts | 11 +- .../select-currency/select-currency.ts | 8 +- .../select-language/select-language.module.ts | 11 +- .../select-language/select-language.ts | 36 +- .../select-unit/select-unit.module.ts | 11 +- .../app/settings/select-unit/select-unit.ts | 3 +- .../session-log/session-log.module.ts | 15 +- .../app/settings/session-log/session-log.ts | 18 +- .../settings-about/settings-about.module.ts | 11 +- .../settings/settings-about/settings-about.ts | 53 +- .../src/app/settings/settings.module.ts | 11 +- .../mobile/src/app/settings/settings.ts | 149 +- .../app/terms-of-use/terms-of-use.module.ts | 11 +- .../src/app/terms-of-use/terms-of-use.ts | 3 +- .../app/transact/receive/receive.module.ts | 15 +- .../src/app/transact/receive/receive.ts | 89 +- .../select-wallet/select-wallet.module.ts | 13 +- .../transact/select-wallet/select-wallet.ts | 11 +- .../send/send-amount/send-amount.module.ts | 13 +- .../transact/send/send-amount/send-amount.ts | 135 +- .../send-confirmation.module.ts | 13 +- .../send-confirmation/send-confirmation.ts | 45 +- .../send-create-contact.module.ts | 12 +- .../send-create-contact.ts | 27 +- .../send-edit-contact.module.ts | 12 +- .../send-edit-contact/send-edit-contact.ts | 65 +- .../transact/send/send-fee/send-fee.module.ts | 11 +- .../app/transact/send/send-fee/send-fee.ts | 6 +- .../send-select-bind-contact.module.ts | 12 +- .../send-select-bind-contact.ts | 68 +- .../send-valid-till/send-valid-till.module.ts | 8 +- .../send/send-valid-till/send-valid-till.ts | 3 +- .../transact/send/send-via/send-via.module.ts | 11 +- .../app/transact/send/send-via/send-via.ts | 56 +- .../send/send-wallet/send-wallet.module.ts | 12 +- .../transact/send/send-wallet/send-wallet.ts | 7 +- .../src/app/transact/send/send.module.ts | 12 +- .../mobile/src/app/transact/send/send.ts | 120 +- .../src/app/transact/transact.module.ts | 11 +- .../mobile/src/app/transact/transact.ts | 129 +- .../import/address-scanner.service.ts | 17 +- .../import/import-scan/import-scan.module.ts | 11 +- .../import/import-scan/import-scan.ts | 5 +- .../src/app/utilities/import/import.module.ts | 12 +- .../mobile/src/app/utilities/import/import.ts | 24 +- .../create-wallet/create-wallet.module.ts | 12 +- .../wallets/create-wallet/create-wallet.ts | 114 +- .../wallets/edit-wallet/edit-wallet.module.ts | 12 +- .../app/wallets/edit-wallet/edit-wallet.ts | 84 +- .../export-wallet/export-wallet.module.ts | 16 +- .../wallets/export-wallet/export-wallet.ts | 198 +- .../incoming-request.module.ts | 13 +- .../incoming-request/incoming-request.ts | 41 +- .../select-color/select-color.module.ts | 11 +- .../app/wallets/select-color/select-color.ts | 9 +- .../set-wallet-password.module.ts | 12 +- .../set-wallet-password.ts | 28 +- .../wallets/tx-details/tx-details.module.ts | 15 +- .../src/app/wallets/tx-details/tx-details.ts | 19 +- .../wallet-details/wallet-details.module.ts | 12 +- .../wallets/wallet-details/wallet-details.ts | 47 +- .../mobile/src/app/wallets/wallets.module.ts | 13 +- .../mobile/src/app/wallets/wallets.ts | 41 +- .../src/components/components.module.ts | 18 +- .../contact-avatar/contact-avatar.ts | 6 +- .../components/slide-to-action/pan-gesture.ts | 23 +- .../slide-to-action/slide-to-action.ts | 46 +- .../transaction-history.ts | 20 +- .../custom-header-color.ts | 7 +- .../src/directives/directives.module.ts | 6 +- .../directives/enter-to-next/enter-to-next.ts | 14 +- .../sms-notifications.module.ts | 8 +- .../sms-notifications/sms-notifications.ts | 20 +- .../leaderboard/leaderboard.module.ts | 9 +- .../community/leaderboard/leaderboard.ts | 37 +- .../src/pages/community/tell-people.module.ts | 9 +- .../mobile/src/pages/community/tell-people.ts | 10 +- .../globalsend-receive.module.ts | 9 +- .../globalsend-receive/globalsend-receive.ts | 34 +- .../src/pages/history/history.module.ts | 9 +- .../mobile/src/pages/history/history.ts | 47 +- .../src/pages/pin-lock/pin-lock.module.ts | 8 +- .../mobile/src/pages/pin-lock/pin-lock.ts | 12 +- .../easy-send-share/easy-send-share.module.ts | 9 +- .../send/easy-send-share/easy-send-share.ts | 30 +- .../pin-settings/pin-settings.module.ts | 8 +- .../settings/pin-settings/pin-settings.ts | 21 +- .../unlock-requests/unlock-requests.module.ts | 12 +- .../pages/unlock-requests/unlock-requests.ts | 20 +- .../select-whitelist.module.ts | 11 +- .../select-whitelist/select-whitelist.ts | 8 +- .../vault-create-confirm.module.ts | 12 +- .../vault-create-confirm.ts | 38 +- .../vault/vault-create/vault-create.module.ts | 10 +- .../pages/vault/vault-create/vault-create.ts | 70 +- .../vault-deposit/vault-deposit.module.ts | 11 +- .../vault/vault-deposit/vault-deposit.ts | 20 +- .../vault/vault-edit/vault-edit.module.ts | 9 +- .../src/pages/vault/vault-edit/vault-edit.ts | 103 +- .../vault/vault-spend/vault-spend.module.ts | 11 +- .../pages/vault/vault-spend/vault-spend.ts | 41 +- .../mobile/src/pages/vault/vault.module.ts | 11 +- .../mobile/src/pages/vault/vault.ts | 28 +- .../lightwallet/mobile/src/service-worker.js | 21 +- .../mobile/src/services/contacts.service.ts | 52 +- .../src/services/mobile-alert.service.ts | 23 +- .../mobile-polling-notifications.service.ts | 17 +- .../mobile-toast-controller.service.ts | 12 +- .../mobile/src/services/touch-id.service.ts | 22 +- packages/lightwallet/mobile/webpack.config.js | 21 +- .../lightwallet/protractor.common.conf.js | 40 +- .../lightwallet/protractor.desktop.conf.js | 16 +- .../lightwallet/protractor.mobile.conf.js | 45 +- packages/merit-build/README.md | 8 +- packages/merit-build/index.js | 169 +- packages/merit-build/karma.conf.js | 9 +- packages/merit-node/README.md | 7 +- packages/merit-node/benchmarks/index.js | 201 +- packages/merit-node/docs/bus.md | 3 +- packages/merit-node/docs/development.md | 25 +- packages/merit-node/docs/index.md | 7 +- packages/merit-node/docs/node.md | 9 +- packages/merit-node/docs/scaffold.md | 7 + packages/merit-node/docs/services/bitcoind.md | 29 +- packages/merit-node/docs/services/web.md | 8 +- packages/merit-node/lib/bus.js | 6 +- packages/merit-node/lib/cli/daemon.js | 2 +- packages/merit-node/lib/cli/main.js | 28 +- packages/merit-node/lib/cli/merit-node.js | 54 +- packages/merit-node/lib/cli/merit-noded.js | 56 +- packages/merit-node/lib/cli/meritd.js | 56 +- packages/merit-node/lib/errors.js | 2 +- packages/merit-node/lib/node.js | 20 +- packages/merit-node/lib/scaffold/add.js | 21 +- .../merit-node/lib/scaffold/call-method.js | 29 +- packages/merit-node/lib/scaffold/create.js | 104 +- .../lib/scaffold/default-base-config.js | 10 +- .../merit-node/lib/scaffold/default-config.js | 11 +- .../merit-node/lib/scaffold/find-config.js | 2 +- packages/merit-node/lib/scaffold/remove.js | 19 +- packages/merit-node/lib/scaffold/start.js | 54 +- packages/merit-node/lib/services/meritd.js | 735 +- packages/merit-node/lib/services/web.js | 50 +- packages/merit-node/lib/utils.js | 8 +- packages/merit-node/regtest/cluster.js | 122 +- packages/merit-node/regtest/meritd.js | 97 +- packages/merit-node/regtest/node.js | 313 +- packages/merit-node/regtest/p2p.js | 105 +- packages/merit-node/test/bus.integration.js | 19 +- packages/merit-node/test/bus.unit.js | 52 +- packages/merit-node/test/logger.unit.js | 9 +- packages/merit-node/test/node.unit.js | 119 +- .../test/scaffold/add.integration.js | 123 +- .../test/scaffold/call-method.unit.js | 16 +- .../test/scaffold/create.integration.js | 154 +- .../default-base-config.integration.js | 4 +- .../scaffold/default-config.integration.js | 89 +- .../test/scaffold/find-config.integration.js | 32 +- .../test/scaffold/remove.integration.js | 139 +- .../test/scaffold/start.integration.js | 57 +- .../merit-node/test/scaffold/start.unit.js | 65 +- .../merit-node/test/services/meritd.unit.js | 1503 +- packages/merit-node/test/services/web.unit.js | 124 +- packages/merit-node/test/utils.unit.js | 18 +- packages/merit-p2p/README.md | 6 +- packages/merit-p2p/docs/index.md | 4 +- packages/merit-p2p/docs/messages.md | 17 +- packages/merit-p2p/docs/peer.md | 24 +- packages/merit-p2p/docs/pool.md | 22 +- packages/merit-p2p/gulpfile.js | 2 +- packages/merit-p2p/integration/bitcoind.js | 31 +- packages/merit-p2p/karma.conf.js | 19 +- packages/merit-p2p/lib/bloomfilter.js | 4 +- packages/merit-p2p/lib/buffers.js | 1 - packages/merit-p2p/lib/errors.js | 2 +- packages/merit-p2p/lib/index.js | 2 +- packages/merit-p2p/lib/inventory.js | 9 +- packages/merit-p2p/lib/messages/builder.js | 17 +- .../merit-p2p/lib/messages/commands/addr.js | 8 +- .../merit-p2p/lib/messages/commands/block.js | 5 +- .../lib/messages/commands/filteradd.js | 2 +- .../lib/messages/commands/filterload.js | 4 +- .../lib/messages/commands/getdata.js | 2 +- .../lib/messages/commands/headers.js | 2 +- .../merit-p2p/lib/messages/commands/inv.js | 2 +- .../lib/messages/commands/merkleblock.js | 2 +- .../lib/messages/commands/notfound.js | 2 +- .../merit-p2p/lib/messages/commands/ping.js | 2 +- .../merit-p2p/lib/messages/commands/pong.js | 2 +- .../merit-p2p/lib/messages/commands/reject.js | 2 +- .../merit-p2p/lib/messages/commands/tx.js | 2 +- .../lib/messages/commands/version.js | 6 +- packages/merit-p2p/lib/messages/index.js | 14 +- packages/merit-p2p/lib/messages/utils.js | 10 +- packages/merit-p2p/lib/peer.js | 26 +- packages/merit-p2p/lib/pool.js | 57 +- packages/merit-p2p/test/bloomfilter.js | 34 +- packages/merit-p2p/test/buffers.js | 2 - packages/merit-p2p/test/inventory.js | 15 +- packages/merit-p2p/test/messages/builder.js | 6 +- .../merit-p2p/test/messages/commands/index.js | 98 +- packages/merit-p2p/test/messages/index.js | 28 +- packages/merit-p2p/test/messages/message.js | 8 +- packages/merit-p2p/test/messages/util.js | 10 +- packages/merit-p2p/test/peer.js | 41 +- packages/merit-p2p/test/pool.js | 196 +- packages/merit-payment-protocol/README.md | 3 +- packages/merit-payment-protocol/docs/index.md | 17 +- .../merit-payment-protocol/lib/browser.js | 19 +- packages/merit-payment-protocol/lib/common.js | 163 +- packages/merit-payment-protocol/lib/errors.js | 2 +- packages/merit-payment-protocol/lib/index.js | 15 +- .../merit-payment-protocol/lib/rootcerts.js | 33 +- packages/merit-payment-protocol/test/index.js | 278 +- .../test/samplerequest.js | 903 +- .../update-rootcerts.js | 27 +- packages/merit-rpc/README.md | 9 +- packages/merit-rpc/lib/index.js | 61 +- packages/merit-rpc/test/index.js | 211 +- packages/merit-wallet-service/README.md | 17 +- packages/merit-wallet-service/config.js | 14 +- .../lib/blockchainexplorer.js | 15 +- .../lib/blockchainexplorers/insight.js | 122 +- .../lib/blockchainexplorers/localdaemon.js | 36 +- .../lib/blockchainexplorers/request-list.js | 10 +- .../lib/blockchainmonitor.js | 292 +- .../lib/common/constants.js | 2 +- .../lib/common/defaults.js | 60 +- .../merit-wallet-service/lib/common/utils.js | 26 +- .../merit-wallet-service/lib/emailservice.js | 418 +- .../lib/errors/clienterror.js | 2 +- .../lib/errors/errordefinitions.js | 16 +- .../merit-wallet-service/lib/expressapp.js | 300 +- .../lib/fiatrateproviders/bitpay.js | 16 +- .../lib/fiatrateproviders/bitstamp.js | 12 +- .../lib/fiatrateproviders/index.js | 2 +- .../lib/fiatrateservice.js | 134 +- .../merit-wallet-service/lib/locallock.js | 11 +- packages/merit-wallet-service/lib/lock.js | 2 +- .../merit-wallet-service/lib/messagebroker.js | 2 +- .../merit-wallet-service/lib/model/address.js | 15 +- .../lib/model/addressmanager.js | 11 +- .../merit-wallet-service/lib/model/copayer.js | 32 +- .../merit-wallet-service/lib/model/email.js | 3 +- .../lib/model/notification.js | 5 +- .../lib/model/preferences.js | 3 +- .../lib/model/pushnotificationsub.js | 3 +- .../lib/model/referraltxconfirmationsub.js | 6 +- .../merit-wallet-service/lib/model/session.js | 4 +- .../lib/model/txconfirmationsub.js | 3 +- .../merit-wallet-service/lib/model/txnote.js | 2 +- .../lib/model/txproposal.js | 52 +- .../lib/model/txproposalaction.js | 2 +- .../lib/model/vaulttxconfirmationsub.js | 6 +- .../merit-wallet-service/lib/model/wallet.js | 9 +- .../lib/notificationbroadcaster.js | 2 +- .../lib/pushnotificationsservice.js | 484 +- packages/merit-wallet-service/lib/server.js | 210 +- .../lib/sms-notification-service.js | 50 +- packages/merit-wallet-service/lib/stats.js | 144 +- packages/merit-wallet-service/lib/storage.js | 2158 +- .../merit-wallet-service/meritnode/index.js | 91 +- .../messagebroker/messagebroker.js | 2 +- packages/merit-wallet-service/mws.js | 25 +- .../scripts/level2mongo.js | 18 +- .../test/blockchainexplorer.js | 2 +- .../merit-wallet-service/test/expressapp.js | 54 +- .../test/integration/bcmonitor.js | 76 +- .../test/integration/emailnotifications.js | 696 +- .../test/integration/fiatrateservice.js | 515 +- .../test/integration/helpers.js | 325 +- .../test/integration/pushNotifications.js | 848 +- .../test/integration/server.js | 7586 +- .../merit-wallet-service/test/locallock.js | 6 +- .../merit-wallet-service/test/meritnode.js | 100 +- .../test/model/address.js | 65 +- .../test/model/addressmanager.js | 3 +- .../test/model/copayer.js | 119 +- .../test/model/txproposal.js | 135 +- .../merit-wallet-service/test/model/wallet.js | 135 +- .../merit-wallet-service/test/request-list.js | 303 +- packages/merit-wallet-service/test/storage.js | 42 +- .../merit-wallet-service/test/testdata.js | 585 +- packages/merit-wallet-service/test/utils.js | 190 +- packages/meritcore-lib/README.md | 4 +- packages/meritcore-lib/benchmark/script.js | 124 +- .../meritcore-lib/benchmark/serialization.js | 204 +- packages/meritcore-lib/bitcore-lib.js | 104059 ++++++++------- packages/meritcore-lib/docs/address.md | 1 + packages/meritcore-lib/docs/block.md | 2 + packages/meritcore-lib/docs/crypto.md | 6 + packages/meritcore-lib/docs/encoding.md | 3 + packages/meritcore-lib/docs/examples.md | 57 +- packages/meritcore-lib/docs/hierarchical.md | 11 +- packages/meritcore-lib/docs/index.md | 38 +- packages/meritcore-lib/docs/networks.md | 9 +- packages/meritcore-lib/docs/privatekey.md | 3 + packages/meritcore-lib/docs/publickey.md | 5 +- packages/meritcore-lib/docs/script.md | 36 +- packages/meritcore-lib/docs/transaction.md | 41 +- packages/meritcore-lib/docs/unit.md | 4 + packages/meritcore-lib/docs/unspentoutput.md | 24 +- packages/meritcore-lib/docs/uri.md | 8 +- packages/meritcore-lib/index.js | 5 +- packages/meritcore-lib/karma.conf.js | 19 +- packages/meritcore-lib/lib/address.js | 34 +- packages/meritcore-lib/lib/block/block.js | 6 +- .../meritcore-lib/lib/block/blockheader.js | 19 +- .../meritcore-lib/lib/block/merkleblock.js | 36 +- packages/meritcore-lib/lib/crypto/bn.js | 7 +- packages/meritcore-lib/lib/crypto/ecdsa.js | 72 +- packages/meritcore-lib/lib/crypto/hash.js | 20 +- packages/meritcore-lib/lib/crypto/point.js | 18 +- packages/meritcore-lib/lib/crypto/random.js | 21 +- .../meritcore-lib/lib/crypto/signature.js | 25 +- packages/meritcore-lib/lib/encoding/base58.js | 6 +- .../meritcore-lib/lib/encoding/base58check.js | 15 +- .../lib/encoding/bufferreader.js | 28 +- .../lib/encoding/bufferwriter.js | 13 +- packages/meritcore-lib/lib/encoding/varint.js | 13 +- packages/meritcore-lib/lib/errors/index.js | 6 +- packages/meritcore-lib/lib/errors/spec.js | 412 +- packages/meritcore-lib/lib/hdprivatekey.js | 69 +- packages/meritcore-lib/lib/hdpublickey.js | 78 +- packages/meritcore-lib/lib/message.js | 11 +- packages/meritcore-lib/lib/networks.js | 26 +- packages/meritcore-lib/lib/opcode.js | 11 +- packages/meritcore-lib/lib/privatekey.js | 56 +- packages/meritcore-lib/lib/publickey.js | 33 +- .../meritcore-lib/lib/referral/referral.js | 259 +- .../meritcore-lib/lib/script/interpreter.js | 134 +- packages/meritcore-lib/lib/script/script.js | 325 +- .../lib/transaction/input/input.js | 35 +- .../lib/transaction/input/multisig.js | 88 +- .../transaction/input/multisigscripthash.js | 86 +- .../lib/transaction/input/paytoscripthash.js | 24 +- .../lib/transaction/input/publickey.js | 23 +- .../lib/transaction/input/publickeyhash.js | 24 +- .../meritcore-lib/lib/transaction/output.js | 19 +- .../meritcore-lib/lib/transaction/sighash.js | 11 +- .../lib/transaction/signature.js | 24 +- .../lib/transaction/transaction.js | 182 +- .../lib/transaction/unspentoutput.js | 26 +- packages/meritcore-lib/lib/unit.js | 18 +- packages/meritcore-lib/lib/uri.js | 12 +- packages/meritcore-lib/lib/util/buffer.js | 4 +- packages/meritcore-lib/lib/util/js.js | 13 +- .../meritcore-lib/lib/util/preconditions.js | 2 +- packages/meritcore-lib/test/address.js | 100 +- packages/meritcore-lib/test/block/block.js | 118 +- .../meritcore-lib/test/block/blockheader.js | 93 +- .../meritcore-lib/test/block/merkleblock.js | 64 +- packages/meritcore-lib/test/crypto/bn.js | 54 +- packages/meritcore-lib/test/crypto/ecdsa.js | 125 +- packages/meritcore-lib/test/crypto/hash.js | 57 +- packages/meritcore-lib/test/crypto/point.js | 84 +- packages/meritcore-lib/test/crypto/random.js | 4 - .../meritcore-lib/test/crypto/signature.js | 162 +- .../test/data/blk86756-testnet.js | 6 +- .../meritcore-lib/test/data/merkleblocks.js | 943 +- packages/meritcore-lib/test/docs.js | 1 - .../meritcore-lib/test/encoding/base58.js | 50 +- .../test/encoding/base58check.js | 48 +- .../test/encoding/bufferreader.js | 168 +- .../test/encoding/bufferwriter.js | 91 +- .../meritcore-lib/test/encoding/varint.js | 66 +- packages/meritcore-lib/test/hdkeys.js | 191 +- packages/meritcore-lib/test/hdprivatekey.js | 99 +- packages/meritcore-lib/test/hdpublickey.js | 86 +- packages/meritcore-lib/test/index.js | 2 +- packages/meritcore-lib/test/networks.js | 23 +- packages/meritcore-lib/test/opcode.js | 57 +- packages/meritcore-lib/test/privatekey.js | 78 +- packages/meritcore-lib/test/publickey.js | 252 +- .../meritcore-lib/test/script/interpreter.js | 121 +- packages/meritcore-lib/test/script/script.js | 844 +- .../test/transaction/deserialize.js | 9 +- .../test/transaction/input/input.js | 21 +- .../test/transaction/input/multisig.js | 72 +- .../transaction/input/multisigscripthash.js | 32 +- .../test/transaction/input/publickey.js | 8 +- .../test/transaction/input/publickeyhash.js | 23 +- .../meritcore-lib/test/transaction/output.js | 65 +- .../meritcore-lib/test/transaction/sighash.js | 6 +- .../test/transaction/signature.js | 9 +- .../test/transaction/transaction.js | 468 +- .../test/transaction/unspentoutput.js | 40 +- packages/meritcore-lib/test/unit.js | 4 +- packages/meritcore-lib/test/uri.js | 103 +- packages/meritcore-lib/test/util/buffer.js | 11 +- packages/meritcore-lib/test/util/js.js | 5 - .../meritcore-lib/test/util/preconditions.js | 15 +- 686 files changed, 83111 insertions(+), 74129 deletions(-) diff --git a/Makefile b/Makefile index cdcb4326a1..db7794bd25 100644 --- a/Makefile +++ b/Makefile @@ -201,5 +201,5 @@ test-all: test-merit-rpc \ .PHONY: fmt fmt: node_modules/.bin/prettier --parser typescript --write "packages/**/*.{ts,js}" || true - node_modules/.bin/prettier --parser scss --write "packages/**/*.{scss,sass}" || true +# node_modules/.bin/prettier --parser scss --write "packages/**/*.{scss,sass}" || true node_modules/.bin/prettier --parser markdown --write "**/*.md" || true diff --git a/README.md b/README.md index f13c8809da..ce107d84e7 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ The lightwallet development environment consists of: Make sure the following conditions are met -- GNU/Linux x86_32/x86_64, or OSX 64bit _(for meritd distributed binaries)_ +- GNU/Linux x86*32/x86_64, or OSX 64bit *(for meritd distributed binaries)\_ - ZeroMQ _(libzmq3-dev for Ubuntu/Debian or zeromq on OSX)_ - GNU Make version 4.2.1 - The lightwallet-stack stably tested on Node.js >= v4.8.4 diff --git a/package.json b/package.json index 4236566ea6..a42b630ba8 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,6 @@ "dependencies": {}, "devDependencies": { "lerna": "^3.4.0", - "prettier": "^1.14.3" + "prettier": "^1.15.3" } } diff --git a/packages/insight-api/lib/addresses.js b/packages/insight-api/lib/addresses.js index ebfa8b840f..15180c9049 100644 --- a/packages/insight-api/lib/addresses.js +++ b/packages/insight-api/lib/addresses.js @@ -11,13 +11,13 @@ const COINBASE_MATURITY = meritcore.Block.COINBASE_MATURITY; function AddressController(node) { this.node = node; this.txController = new TxController(node); - this.common = new Common({log: this.node.log}); -}; + this.common = new Common({ log: this.node.log }); +} AddressController.prototype.show = function(req, res) { var self = this; var options = { - noTxList: parseInt(req.query.noTxList) + noTxList: parseInt(req.query.noTxList), }; if (req.query.from && req.query.to) { @@ -26,7 +26,7 @@ AddressController.prototype.show = function(req, res) { } this.getAddressSummary(req.addr, options, function(err, data) { - if(err) { + if (err) { return self.common.handleErrors(err, res); } @@ -53,7 +53,7 @@ AddressController.prototype.unconfirmedBalance = function(req, res) { AddressController.prototype.addressSummarySubQuery = function(req, res, param) { var self = this; this.getAddressSummary(req.addr, {}, function(err, data) { - if(err) { + if (err) { return self.common.handleErrors(err, res); } @@ -62,9 +62,8 @@ AddressController.prototype.addressSummarySubQuery = function(req, res, param) { }; AddressController.prototype.getAddressSummary = function(address, options, callback) { - this.node.getAddressSummary(address, options, function(err, summary) { - if(err) { + if (err) { return callback(err); } @@ -80,7 +79,7 @@ AddressController.prototype.getAddressSummary = function(address, options, callb unconfirmedBalanceMicros: summary.unconfirmedBalance, unconfirmedTxApperances: summary.unconfirmedAppearances, // misspelling - ew txApperances: summary.appearances, // yuck - transactions: summary.txids + transactions: summary.txids, }; callback(null, transformed); @@ -91,10 +90,13 @@ AddressController.prototype.checkAddr = function(req, res, next) { req.addr = req.params.addr; if (this.check(req, res, next, [req.addr])) { - return this.common.handleErrors({ - message: 'Must include address', - code: 1 - }, res); + return this.common.handleErrors( + { + message: 'Must include address', + code: 1, + }, + res, + ); } next(); @@ -103,27 +105,33 @@ AddressController.prototype.checkAddr = function(req, res, next) { AddressController.prototype.checkAddrOrAlias = function(req, res, next) { req.addr = req.params.addr; if (this.check(req, res, next, [req.addr] || !this.checkAlias(req, res, next, [req.addr]))) { - return this.common.handleErrors({ - message: 'Invalid address: ' + + req.addr, - code: 1 - }, res); + return this.common.handleErrors( + { + message: 'Invalid address: ' + +req.addr, + code: 1, + }, + res, + ); } next(); }; AddressController.prototype.checkAddrs = function(req, res, next) { - if(req.body.addrs) { + if (req.body.addrs) { req.addrs = req.body.addrs.split(','); } else { req.addrs = req.params.addrs.split(','); } if (this.check(req, res, next, req.addrs)) { - return this.common.handleErrors({ - message: 'Must include address', - code: 1 - }, res); + return this.common.handleErrors( + { + message: 'Must include address', + code: 1, + }, + res, + ); } next(); @@ -131,29 +139,35 @@ AddressController.prototype.checkAddrs = function(req, res, next) { AddressController.prototype.check = function(req, res, next, addresses) { if (!addresses.length || !addresses[0]) { - return this.common.handleErrors({ - message: 'Must include address', - code: 1 - }, res); + return this.common.handleErrors( + { + message: 'Must include address', + code: 1, + }, + res, + ); } addresses = _.reject(addresses, _.isEmpty); - for(var i = 0; i < addresses.length; i++) { + for (var i = 0; i < addresses.length; i++) { try { - new meritcore.Address(addresses[i]); - } catch(e) { + new meritcore.Address(addresses[i]); + } catch (e) { return false; } } }; AddressController.prototype.checkAlias = function(req, res, next, aliases) { - if(!aliases.length || !aliases[0]) { - return this.common.handleErrors({ - message: 'Must include alias', - code: 1 - }, res); + if (!aliases.length || !aliases[0]) { + return this.common.handleErrors( + { + message: 'Must include alias', + code: 1, + }, + res, + ); } aliases = _.reject(aliases, _.isEmpty); @@ -166,11 +180,14 @@ AddressController.prototype.validateAddress = function(req, res) { const address = req.addr; this.node.validateAddress(address, function(err, response) { - if (err || !response.result) { - return self.common.handleErrors({ - message: 'Invalid address: ' + err.message, - code: 1 - }, res); + if (err || !response.result) { + return self.common.handleErrors( + { + message: 'Invalid address: ' + err.message, + code: 1, + }, + res, + ); } const info = response.result; @@ -181,7 +198,7 @@ AddressController.prototype.validateAddress = function(req, res) { isValid: !!info.isvalid, isBeaconed: !!info.isbeaconed, isConfirmed: !!info.isconfirmed, - }); + }); }); }; @@ -189,7 +206,7 @@ AddressController.prototype.utxo = function(req, res) { var self = this; this.node.getAddressUnspentOutputs(req.addr, {}, function(err, utxos) { - if(err) { + if (err) { return self.common.handleErrors(err, res); } else if (!utxos.length) { return res.jsonp([]); @@ -200,9 +217,9 @@ AddressController.prototype.utxo = function(req, res) { AddressController.prototype.multiutxo = function(req, res) { this.node.getAddressUnspentOutputs(req.addrs, { invites: req.body.invites }, (err, utxos) => { - if(err && err.code === -5) { + if (err && err.code === -5) { return res.jsonp([]); - } else if(err) { + } else if (err) { return this.common.handleErrors(err, res); } @@ -241,45 +258,44 @@ AddressController.prototype._getTransformOptions = function(req) { return { noAsm: parseInt(req.query.noAsm) ? true : false, noScriptSig: parseInt(req.query.noScriptSig) ? true : false, - noSpent: parseInt(req.query.noSpent) ? true : false + noSpent: parseInt(req.query.noSpent) ? true : false, }; }; AddressController.prototype.referrals = function(req, res, next) { - var self = this; - - var options = { - from: parseInt(req.query.from) || parseInt(req.body.from) || 0 - }; + var self = this; - options.to = parseInt(req.query.to) || parseInt(req.body.to) || parseInt(options.from) + 10; + var options = { + from: parseInt(req.query.from) || parseInt(req.body.from) || 0, + }; - self.node.getAddressReferrals(req.addrs, options, function(err, result) { - if(err) { - return self.common.handleErrors(err, res); - } + options.to = parseInt(req.query.to) || parseInt(req.body.to) || parseInt(options.from) + 10; - return res.jsonp({ - totalItems: result.totalCount, - from: options.from, - to: Math.min(options.to, result.totalCount), - items: result.items - }); + self.node.getAddressReferrals(req.addrs, options, function(err, result) { + if (err) { + return self.common.handleErrors(err, res); + } + return res.jsonp({ + totalItems: result.totalCount, + from: options.from, + to: Math.min(options.to, result.totalCount), + items: result.items, }); + }); }; AddressController.prototype.multitxs = function(req, res, next) { var self = this; var options = { - from: parseInt(req.query.from) || parseInt(req.body.from) || 0 + from: parseInt(req.query.from) || parseInt(req.body.from) || 0, }; options.to = parseInt(req.query.to) || parseInt(req.body.to) || parseInt(options.from) + 10; self.node.getAddressHistory(req.addrs, options, function(err, result) { - if(err) { + if (err) { return self.common.handleErrors(err, res); } @@ -293,28 +309,29 @@ AddressController.prototype.multitxs = function(req, res, next) { totalItems: result.totalCount, from: options.from, to: Math.min(options.to, result.totalCount), - items: items + items: items, }); }); - }); }; AddressController.prototype.transformAddressHistoryForMultiTxs = function(txinfos, options, callback) { var self = this; - var items = txinfos.map(function(txinfo) { - return txinfo.tx; - }).filter(function(value, index, itemArr) { - return itemArr.indexOf(value) === index; - }); + var items = txinfos + .map(function(txinfo) { + return txinfo.tx; + }) + .filter(function(value, index, itemArr) { + return itemArr.indexOf(value) === index; + }); async.map( items, function(item, next) { self.txController.transformTransaction(item, options, next); }, - callback + callback, ); }; diff --git a/packages/insight-api/lib/blocks.js b/packages/insight-api/lib/blocks.js index c16fcfc18e..14e5ad7eca 100644 --- a/packages/insight-api/lib/blocks.js +++ b/packages/insight-api/lib/blocks.js @@ -21,12 +21,12 @@ function BlockController(options) { pool.searchStrings.forEach(function(s) { self.poolStrings[s] = { poolName: pool.poolName, - url: pool.url + url: pool.url, }; }); }); - this.common = new Common({log: this.node.log}); + this.common = new Common({ log: this.node.log }); } var BLOCK_LIMIT = 200; @@ -64,9 +64,9 @@ BlockController.prototype.block = function(req, res, next) { next(); } else { self.node.getBlock(hash, function(err, block) { - if((err && err.code === -5) || (err && err.code === -8)) { + if ((err && err.code === -5) || (err && err.code === -8)) { return self.common.handleErrors(null, res); - } else if(err) { + } else if (err) { return self.common.handleErrors(err, res); } @@ -104,7 +104,7 @@ BlockController.prototype.transformBlock = function(block, info) { const inviteIds = blockObj.invites.map(function(invite) { return invite.hash; }); - const referralIds = blockObj.referrals.map(function (ref) { + const referralIds = blockObj.referrals.map(function(ref) { return ref.hash; }); const result = { @@ -127,8 +127,8 @@ BlockController.prototype.transformBlock = function(block, info) { previousblockhash: this._normalizePrevHash(blockObj.header.prevHash), nextblockhash: info.nextblockhash, reward: this.getBlockReward(info.height) / 1e8, - isMainChain: (info.confirmations !== -1), - poolInfo: this.getPoolInfo(block) + isMainChain: info.confirmations !== -1, + poolInfo: this.getPoolInfo(block), }; return result; @@ -157,7 +157,7 @@ BlockController.prototype.blockIndex = function(req, res) { return self.common.handleErrors(err, res); } res.jsonp({ - blockHash: info.hash + blockHash: info.hash, }); }); }; @@ -207,7 +207,7 @@ BlockController.prototype._getBlockSummary = function(hash, moreTimestamp, next) hash: hash, time: header.time, txlength: txlength, - poolInfo: self.getPoolInfo(info) + poolInfo: self.getPoolInfo(info), }; var confirmations = self.node.services.meritd.height - height + 1; @@ -218,7 +218,6 @@ BlockController.prototype._getBlockSummary = function(hash, moreTimestamp, next) finish(summary); }); }); - } }; @@ -233,7 +232,7 @@ BlockController.prototype.list = function(req, res) { if (req.query.blockDate) { dateStr = req.query.blockDate; var datePattern = /\d{4}-\d{2}-\d{2}/; - if(!datePattern.test(dateStr)) { + if (!datePattern.test(dateStr)) { return self.common.handleErrors(new Error('Please use yyyy-mm-dd format'), res); } @@ -243,7 +242,7 @@ BlockController.prototype.list = function(req, res) { isToday = true; } - var gte = Math.round((new Date(dateStr)).getTime() / 1000); + var gte = Math.round(new Date(dateStr).getTime() / 1000); //pagination var lte = parseInt(req.query.startTimestamp) || gte + 86400; @@ -254,13 +253,13 @@ BlockController.prototype.list = function(req, res) { var moreTimestamp = lte; self.node.services.meritd.getBlockHashesByTimestamp(lte, gte, function(err, hashes) { - if(err) { + if (err) { return self.common.handleErrors(err, res); } hashes.reverse(); - if(hashes.length > limit) { + if (hashes.length > limit) { more = true; hashes = hashes.slice(0, limit); } @@ -271,7 +270,7 @@ BlockController.prototype.list = function(req, res) { self._getBlockSummary(hash, moreTimestamp, next); }, function(err, blocks) { - if(err) { + if (err) { return self.common.handleErrors(err, res); } @@ -288,16 +287,16 @@ BlockController.prototype.list = function(req, res) { currentTs: lte - 1, current: dateStr, isToday: isToday, - more: more - } + more: more, + }, }; - if(more) { + if (more) { data.pagination.moreTs = moreTimestamp; } res.jsonp(data); - } + }, ); }); }; @@ -306,7 +305,7 @@ BlockController.prototype.getPoolInfo = function(block) { if (block.transactions[0] && block.transactions[0].inputs && block.transactions[0].inputs[0]) { const coinbaseBuffer = block.transactions[0].inputs[0]._scriptBuffer; - for(let k in this.poolStrings) { + for (let k in this.poolStrings) { if (coinbaseBuffer.toString('utf-8').match(k)) { return this.poolStrings[k]; } diff --git a/packages/insight-api/lib/common.js b/packages/insight-api/lib/common.js index 3af54e0c0f..71cd94c177 100644 --- a/packages/insight-api/lib/common.js +++ b/packages/insight-api/lib/common.js @@ -4,20 +4,20 @@ function Common(options) { this.log = options.log; } -Common.prototype.notReady = function (err, res, p) { +Common.prototype.notReady = function(err, res, p) { res.status(503).send('Server not yet ready. Sync Percentage:' + p); }; -Common.prototype.handleErrors = function (err, res) { +Common.prototype.handleErrors = function(err, res) { if (err) { - if (err.code) { - this.log.warn("Insight Error: " + err.message + '. Code:' + err.code); - res.status(400).json({error: err.code, message: err.message}); + if (err.code) { + this.log.warn('Insight Error: ' + err.message + '. Code:' + err.code); + res.status(400).json({ error: err.code, message: err.message }); } else { - this.log.warn("Insight Error: "); + this.log.warn('Insight Error: '); this.log.warn(err.message); this.log.warn(err.stack); - res.status(503).json({error: 0, message: err.message}); + res.status(503).json({ error: 0, message: err.message }); } } else { res.status(404).send('Not found'); diff --git a/packages/insight-api/lib/currency.js b/packages/insight-api/lib/currency.js index 0c4a4e3196..16865d91c3 100644 --- a/packages/insight-api/lib/currency.js +++ b/packages/insight-api/lib/currency.js @@ -15,7 +15,7 @@ CurrencyController.DEFAULT_CURRENCY_DELAY = 10; CurrencyController.prototype.index = function(req, res) { var self = this; var currentTime = Date.now(); - if (self.bitstampRate === 0 || currentTime >= (self.timestamp + self.currencyDelay)) { + if (self.bitstampRate === 0 || currentTime >= self.timestamp + self.currencyDelay) { self.timestamp = currentTime; request('https://www.bitstamp.net/api/ticker/', function(err, response, body) { if (err) { @@ -26,20 +26,19 @@ CurrencyController.prototype.index = function(req, res) { } res.jsonp({ status: 200, - data: { - bitstamp: self.bitstampRate - } + data: { + bitstamp: self.bitstampRate, + }, }); }); } else { res.jsonp({ status: 200, - data: { - bitstamp: self.bitstampRate - } + data: { + bitstamp: self.bitstampRate, + }, }); } - }; module.exports = CurrencyController; diff --git a/packages/insight-api/lib/index.js b/packages/insight-api/lib/index.js index eb2d3ba698..69e273963f 100644 --- a/packages/insight-api/lib/index.js +++ b/packages/insight-api/lib/index.js @@ -39,7 +39,7 @@ var InsightAPI = function(options) { this.currencyRefresh = options.currencyRefresh || CurrencyController.DEFAULT_CURRENCY_DELAY; this.subscriptions = { - inv: [] + inv: [], }; if (!_.isUndefined(options.enableCache)) { @@ -107,7 +107,7 @@ InsightAPI.prototype.createLogInfoStream = function() { } inherits(Log, Writable); - Log.prototype._write = function (chunk, enc, callback) { + Log.prototype._write = function(chunk, enc, callback) { self.node.log.info(chunk.slice(0, chunk.length - 1)); // remove new line and pass to logger callback(); }; @@ -140,25 +140,27 @@ InsightAPI.prototype.setupRoutes = function(app) { } //Setup logging - morgan.token('remote-forward-addr', function(req){ + morgan.token('remote-forward-addr', function(req) { return self.getRemoteAddress(req); }); var logFormat = ':remote-forward-addr ":method :url" :status :res[content-length] :response-time ":user-agent" '; var logStream = this.createLogInfoStream(); - app.use(morgan(logFormat, {stream: logStream})); + app.use(morgan(logFormat, { stream: logStream })); //Enable compression app.use(compression()); //Enable urlencoded data - app.use(bodyParser.urlencoded({extended: true})); + app.use(bodyParser.urlencoded({ extended: true })); //Enable CORS app.use(function(req, res, next) { - res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, HEAD, PUT, POST, OPTIONS'); - res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Content-Length, Cache-Control, cf-connecting-ip'); + res.header( + 'Access-Control-Allow-Headers', + 'Origin, X-Requested-With, Content-Type, Accept, Content-Length, Cache-Control, cf-connecting-ip', + ); var method = req.method && req.method.toUpperCase && req.method.toUpperCase(); @@ -174,7 +176,7 @@ InsightAPI.prototype.setupRoutes = function(app) { var blockOptions = { node: this.node, blockSummaryCacheSize: this.blockSummaryCacheSize, - blockCacheSize: this.blockCacheSize + blockCacheSize: this.blockCacheSize, }; var blocks = new BlockController(blockOptions); app.get('/blocks', this.cacheShort(), blocks.list.bind(blocks)); @@ -202,18 +204,58 @@ InsightAPI.prototype.setupRoutes = function(app) { var addresses = new AddressController(this.node); app.get('/addr/:addr', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.show.bind(addresses)); app.get('/addr/:addr/utxo', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.utxo.bind(addresses)); - app.get('/addrs/:addrs/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses)); + app.get( + '/addrs/:addrs/utxo', + this.cacheShort(), + addresses.checkAddrs.bind(addresses), + addresses.multiutxo.bind(addresses), + ); app.post('/addrs/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses)); - app.get('/addrs/:addrs/txs', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multitxs.bind(addresses)); + app.get( + '/addrs/:addrs/txs', + this.cacheShort(), + addresses.checkAddrs.bind(addresses), + addresses.multitxs.bind(addresses), + ); app.post('/addrs/txs', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multitxs.bind(addresses)); - app.post('/addrs/referrals', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.referrals.bind(addresses)); + app.post( + '/addrs/referrals', + this.cacheShort(), + addresses.checkAddrs.bind(addresses), + addresses.referrals.bind(addresses), + ); // Address property routes - app.get('/addr/:addr/balance', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.balance.bind(addresses)); - app.get('/addr/:addr/totalReceived', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.totalReceived.bind(addresses)); - app.get('/addr/:addr/totalSent', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.totalSent.bind(addresses)); - app.get('/addr/:addr/unconfirmedBalance', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.unconfirmedBalance.bind(addresses)); - app.get('/addr/:addr/validate', this.cacheShort(), addresses.checkAddrOrAlias.bind(addresses), addresses.validateAddress.bind(addresses)); + app.get( + '/addr/:addr/balance', + this.cacheShort(), + addresses.checkAddr.bind(addresses), + addresses.balance.bind(addresses), + ); + app.get( + '/addr/:addr/totalReceived', + this.cacheShort(), + addresses.checkAddr.bind(addresses), + addresses.totalReceived.bind(addresses), + ); + app.get( + '/addr/:addr/totalSent', + this.cacheShort(), + addresses.checkAddr.bind(addresses), + addresses.totalSent.bind(addresses), + ); + app.get( + '/addr/:addr/unconfirmedBalance', + this.cacheShort(), + addresses.checkAddr.bind(addresses), + addresses.unconfirmedBalance.bind(addresses), + ); + app.get( + '/addr/:addr/validate', + this.cacheShort(), + addresses.checkAddrOrAlias.bind(addresses), + addresses.validateAddress.bind(addresses), + ); // Referral routes var referrals = new ReferralsController(this.node); @@ -239,7 +281,7 @@ InsightAPI.prototype.setupRoutes = function(app) { // Currency var currency = new CurrencyController({ node: this.node, - currencyRefresh: this.currencyRefresh + currencyRefresh: this.currencyRefresh, }); app.get('/currency', currency.index.bind(currency)); @@ -255,10 +297,9 @@ InsightAPI.prototype.setupRoutes = function(app) { res.status(404).jsonp({ status: 404, url: req.originalUrl, - error: 'Not found' + error: 'Not found', }); }); - }; InsightAPI.prototype.getPublishEvents = function() { @@ -268,8 +309,8 @@ InsightAPI.prototype.getPublishEvents = function() { scope: this, subscribe: this.subscribe.bind(this), unsubscribe: this.unsubscribe.bind(this), - extraEvents: ['tx', 'block', 'referral'] - } + extraEvents: ['tx', 'block', 'referral'], + }, ]; }; @@ -302,7 +343,7 @@ InsightAPI.prototype.subscribe = function(emitter) { var emitters = this.subscriptions.inv; var index = emitters.indexOf(emitter); - if(index === -1) { + if (index === -1) { emitters.push(emitter); } }; @@ -312,7 +353,7 @@ InsightAPI.prototype.unsubscribe = function(emitter) { var emitters = this.subscriptions.inv; var index = emitters.indexOf(emitter); - if(index > -1) { + if (index > -1) { emitters.splice(index, 1); } }; diff --git a/packages/insight-api/lib/messages.js b/packages/insight-api/lib/messages.js index 90ae549b78..ce3aa4dfbb 100644 --- a/packages/insight-api/lib/messages.js +++ b/packages/insight-api/lib/messages.js @@ -7,7 +7,7 @@ var Common = require('./common'); function MessagesController(node) { this.node = node; - this.common = new Common({log: this.node.log}); + this.common = new Common({ log: this.node.log }); } MessagesController.prototype.verify = function(req, res) { @@ -15,22 +15,28 @@ MessagesController.prototype.verify = function(req, res) { var address = req.body.address || req.query.address; var signature = req.body.signature || req.query.signature; var message = req.body.message || req.query.message; - if(_.isUndefined(address) || _.isUndefined(signature) || _.isUndefined(message)) { - return self.common.handleErrors({ - message: 'Missing parameters (expected "address", "signature" and "message")', - code: 1 - }, res); + if (_.isUndefined(address) || _.isUndefined(signature) || _.isUndefined(message)) { + return self.common.handleErrors( + { + message: 'Missing parameters (expected "address", "signature" and "message")', + code: 1, + }, + res, + ); } var valid; try { valid = new Message(message).verify(address, signature); - } catch(err) { - return self.common.handleErrors({ - message: 'Unexpected error: ' + err.message, - code: 1 - }, res); + } catch (err) { + return self.common.handleErrors( + { + message: 'Unexpected error: ' + err.message, + code: 1, + }, + res, + ); } - res.json({'result': valid}); + res.json({ result: valid }); }; module.exports = MessagesController; diff --git a/packages/insight-api/lib/ratelimiter.js b/packages/insight-api/lib/ratelimiter.js index 616d5b44e8..7471a807e5 100644 --- a/packages/insight-api/lib/ratelimiter.js +++ b/packages/insight-api/lib/ratelimiter.js @@ -21,7 +21,7 @@ function RateLimiter(options) { return new RateLimiter(options); } - if (!options){ + if (!options) { options = {}; } @@ -33,18 +33,17 @@ function RateLimiter(options) { this.config = { whitelist: { totalRequests: options.whitelistLimit || 3 * 60 * 60 * 10, // 108,000 - interval: options.whitelistInterval || THREE_HOURS + interval: options.whitelistInterval || THREE_HOURS, }, blacklist: { totalRequests: options.blacklistLimit || 0, - interval: options.blacklistInterval || THREE_HOURS + interval: options.blacklistInterval || THREE_HOURS, }, normal: { totalRequests: options.limit || 3 * 60 * 60, // 10,800 - interval: options.interval || THREE_HOURS - } + interval: options.interval || THREE_HOURS, + }, }; - } RateLimiter.prototype.middleware = function() { @@ -55,13 +54,12 @@ RateLimiter.prototype.middleware = function() { }; RateLimiter.prototype._middleware = function(req, res, next) { - var name = this.getClientName(req); var client = this.clients[name]; res.ratelimit = { clients: this.clients, - exceeded: false + exceeded: false, }; if (!client) { @@ -81,7 +79,7 @@ RateLimiter.prototype._middleware = function(req, res, next) { this.node.log.warn('Rate limited:', client); res.status(429).jsonp({ status: 429, - error: 'Rate limit exceeded' + error: 'Rate limit exceeded', }); } }; @@ -115,7 +113,7 @@ RateLimiter.prototype.addClient = function(name) { var client = { name: name, type: this.getClientType(name), - visits: 1 + visits: 1, }; var resetTime = this.config[client.type].interval; @@ -127,7 +125,6 @@ RateLimiter.prototype.addClient = function(name) { this.clients[name] = client; return client; - }; module.exports = RateLimiter; diff --git a/packages/insight-api/lib/referrals.js b/packages/insight-api/lib/referrals.js index cff64da09b..97240522c2 100644 --- a/packages/insight-api/lib/referrals.js +++ b/packages/insight-api/lib/referrals.js @@ -8,7 +8,6 @@ const async = require('async'); const MAXINT = 0xffffffff; // Math.pow(2, 32) - 1; - function ReferralsController(node) { this.node = node; this.common = new Common({ log: this.node.log }); @@ -29,7 +28,7 @@ ReferralsController.prototype.referral = function(req, res, next) { this.node.getReferral(refid, (err, referral) => { if (err && err.code === -5) { return this.common.handleErrors(null, res); - } else if(err) { + } else if (err) { return this.common.handleErrors(err, res); } diff --git a/packages/insight-api/lib/service.js b/packages/insight-api/lib/service.js index 2803479cd5..abf88df84c 100644 --- a/packages/insight-api/lib/service.js +++ b/packages/insight-api/lib/service.js @@ -86,6 +86,4 @@ Service.prototype.getRoutePrefix = function() { return this.name; }; - - module.exports = Service; diff --git a/packages/insight-api/lib/status.js b/packages/insight-api/lib/status.js index fe059a373b..cfba83d7d9 100644 --- a/packages/insight-api/lib/status.js +++ b/packages/insight-api/lib/status.js @@ -4,43 +4,43 @@ var Common = require('./common'); function StatusController(node) { this.node = node; - this.common = new Common({log: this.node.log}); + this.common = new Common({ log: this.node.log }); } StatusController.prototype.show = function(req, res) { var self = this; var option = req.query.q; - switch(option) { - case 'getDifficulty': - this.getDifficulty(function(err, result) { - if (err) { - return self.common.handleErrors(err, res); - } - res.jsonp(result); - }); - break; - case 'getLastBlockHash': - res.jsonp(this.getLastBlockHash()); - break; - case 'getBestBlockHash': - this.getBestBlockHash(function(err, result) { - if (err) { - return self.common.handleErrors(err, res); - } - res.jsonp(result); - }); - break; - case 'getInfo': - default: - this.getInfo(function(err, result) { - if (err) { - return self.common.handleErrors(err, res); - } - res.jsonp({ - info: result + switch (option) { + case 'getDifficulty': + this.getDifficulty(function(err, result) { + if (err) { + return self.common.handleErrors(err, res); + } + res.jsonp(result); + }); + break; + case 'getLastBlockHash': + res.jsonp(this.getLastBlockHash()); + break; + case 'getBestBlockHash': + this.getBestBlockHash(function(err, result) { + if (err) { + return self.common.handleErrors(err, res); + } + res.jsonp(result); + }); + break; + case 'getInfo': + default: + this.getInfo(function(err, result) { + if (err) { + return self.common.handleErrors(err, res); + } + res.jsonp({ + info: result, + }); }); - }); } }; @@ -60,7 +60,7 @@ StatusController.prototype.getInfo = function(callback) { testnet: result.testnet, relayfee: result.relayFee, errors: result.errors, - network: result.network + network: result.network, }; callback(null, info); }); @@ -70,7 +70,7 @@ StatusController.prototype.getLastBlockHash = function() { var hash = this.node.services.meritd.tiphash; return { syncTipHash: hash, - lastblockhash: hash + lastblockhash: hash, }; }; @@ -80,7 +80,7 @@ StatusController.prototype.getBestBlockHash = function(callback) { return callback(err); } callback(null, { - bestblockhash: hash + bestblockhash: hash, }); }); }; @@ -91,7 +91,7 @@ StatusController.prototype.getDifficulty = function(callback) { return callback(err); } callback(null, { - difficulty: info.difficulty + difficulty: info.difficulty, }); }); }; @@ -118,15 +118,12 @@ StatusController.prototype.sync = function(req, res) { syncPercentage: Math.round(percentage), height: self.node.services.meritd.height, error: null, - type: 'Merit Node' + type: 'Merit Node', }; res.jsonp(info); - }); - }); - }; // Hard coded to make insight ui happy, but not applicable @@ -134,14 +131,14 @@ StatusController.prototype.peer = function(req, res) { res.jsonp({ connected: true, host: '127.0.0.1', - port: null + port: null, }); }; StatusController.prototype.version = function(req, res) { var pjson = require('../package.json'); res.jsonp({ - version: pjson.version + version: pjson.version, }); }; diff --git a/packages/insight-api/lib/transactions.js b/packages/insight-api/lib/transactions.js index eb71c51f2f..80deab484c 100644 --- a/packages/insight-api/lib/transactions.js +++ b/packages/insight-api/lib/transactions.js @@ -10,10 +10,9 @@ const COINBASE_MATURITY = meritcore.Block.COINBASE_MATURITY; const MAXINT = 0xffffffff; // Math.pow(2, 32) - 1; - function TxController(node) { this.node = node; - this.common = new Common({log: this.node.log}); + this.common = new Common({ log: this.node.log }); } TxController.prototype.show = function(req, res) { @@ -32,7 +31,7 @@ TxController.prototype.transaction = function(req, res, next) { this.node.getDetailedTransaction(txid, function(err, transaction) { if (err && err.code === -5) { return self.common.handleErrors(null, res); - } else if(err) { + } else if (err) { return self.common.handleErrors(err, res); } @@ -43,7 +42,6 @@ TxController.prototype.transaction = function(req, res, next) { req.transaction = transformedTransaction; next(); }); - }); }; @@ -55,23 +53,23 @@ TxController.prototype.transformTransaction = function(transaction, options, cal $.checkArgument(_.isFunction(callback)); var confirmations = 0; - if(transaction.height >= 0) { + if (transaction.height >= 0) { confirmations = this.node.services.meritd.height - transaction.height + 1; } var transformed = { txid: transaction.hash, version: transaction.version, - locktime: transaction.locktime + locktime: transaction.locktime, }; - if(transaction.isCoinbase) { + if (transaction.isCoinbase) { transformed.vin = [ { coinbase: transaction.inputs[0].script, sequence: transaction.inputs[0].sequence, - n: 0 - } + n: 0, + }, ]; } else { transformed.vin = transaction.inputs.map(this.transformInput.bind(this, options)); @@ -117,12 +115,12 @@ TxController.prototype.transformInput = function(options, input, index) { txid: input.prevTxId, vout: input.outputIndex, sequence: input.sequence, - n: index + n: index, }; if (!options.noScriptSig) { transformed.scriptSig = { - hex: input.script + hex: input.script, }; if (!options.noAsm) { transformed.scriptSig.asm = input.scriptAsm; @@ -146,8 +144,8 @@ TxController.prototype.transformOutput = function(options, output, index) { value: (output.micros / 1e8).toFixed(8), n: index, scriptPubKey: { - hex: output.script - } + hex: output.script, + }, }; if (!options.noAsm) { @@ -174,37 +172,45 @@ TxController.prototype.transformInvTransaction = function(transaction) { let valueOut = 0; - const inputAddresses = _.reduce(transaction.inputs, function(acc, input) { - if (!input.script) { - return acc; - } + const inputAddresses = _.reduce( + transaction.inputs, + function(acc, input) { + if (!input.script) { + return acc; + } - const address = input.script.toAddress(self.node.network); - if (!address) { - return acc; - } + const address = input.script.toAddress(self.node.network); + if (!address) { + return acc; + } - return acc.add(address.toString()); - }, new Set()); + return acc.add(address.toString()); + }, + new Set(), + ); + + const vout = _.reduce( + transaction.outputs, + function(acc, output) { + valueOut += output.micros; + if (!output.script) { + return acc; + } - const vout = _.reduce(transaction.outputs, function(acc, output) { - valueOut += output.micros; - if (!output.script) { - return acc; - } + const address = output.script.toAddress(self.node.network); + if (!address) { + return acc; + } - const address = output.script.toAddress(self.node.network); - if (!address) { - return acc; - } - - const addresString = address.toString(); - const obj = { - [addresString]: output.micros, - isChangeOutput: inputAddresses.has(addresString), - }; - return acc.concat(obj); - }, []); + const addresString = address.toString(); + const obj = { + [addresString]: output.micros, + isChangeOutput: inputAddresses.has(addresString), + }; + return acc.concat(obj); + }, + [], + ); const isRBF = _.some(_.map(transaction.inputs, 'sequenceNumber'), function(seq) { return seq < MAXINT - 1; @@ -231,12 +237,12 @@ TxController.prototype.rawTransaction = function(req, res, next) { this.node.getTransaction(txid, function(err, transaction) { if (err && err.code === -5) { return self.common.handleErrors(null, res); - } else if(err) { + } else if (err) { return self.common.handleErrors(err, res); } req.rawTransaction = { - 'rawtx': transaction.toBuffer().toString('hex') + rawtx: transaction.toBuffer().toString('hex'), }; next(); @@ -258,18 +264,18 @@ TxController.prototype.list = function(req, res) { var pageLength = 10; var pagesTotal = 1; - if(blockHash) { + if (blockHash) { self.node.getBlockOverview(blockHash, function(err, block) { - if(err && err.code === -5) { + if (err && err.code === -5) { return self.common.handleErrors(null, res); - } else if(err) { + } else if (err) { return self.common.handleErrors(err, res); } var totalTxs = block.txids.length; var txids; - if(!_.isUndefined(page)) { + if (!_.isUndefined(page)) { var start = page * pageLength; txids = block.txids.slice(start, start + pageLength); pagesTotal = Math.ceil(totalTxs / pageLength); @@ -277,41 +283,46 @@ TxController.prototype.list = function(req, res) { txids = block.txids; } - async.mapSeries(txids, function(txid, next) { - self.node.getDetailedTransaction(txid, function(err, transaction) { + async.mapSeries( + txids, + function(txid, next) { + self.node.getDetailedTransaction(txid, function(err, transaction) { + if (err) { + return next(err); + } + self.transformTransaction(transaction, next); + }); + }, + function(err, transformed) { if (err) { - return next(err); + return self.common.handleErrors(err, res); } - self.transformTransaction(transaction, next); - }); - }, function(err, transformed) { - if(err) { - return self.common.handleErrors(err, res); - } - - res.jsonp({ - pagesTotal: pagesTotal, - txs: transformed - }); - }); + res.jsonp({ + pagesTotal: pagesTotal, + txs: transformed, + }); + }, + ); }); - } else if(address) { + } else if (address) { var options = { from: page * pageLength, - to: (page + 1) * pageLength + to: (page + 1) * pageLength, }; self.node.getAddressHistory(address, options, function(err, result) { - if(err) { + if (err) { return self.common.handleErrors(err, res); } - var txs = result.items.map(function(info) { - return info.tx; - }).filter(function(value, index, self) { - return self.indexOf(value) === index; - }); + var txs = result.items + .map(function(info) { + return info.tx; + }) + .filter(function(value, index, self) { + return self.indexOf(value) === index; + }); async.map( txs, @@ -324,9 +335,9 @@ TxController.prototype.list = function(req, res) { } res.jsonp({ pagesTotal: Math.ceil(result.totalCount / pageLength), - txs: transformed + txs: transformed, }); - } + }, ); }); } else { @@ -337,13 +348,13 @@ TxController.prototype.list = function(req, res) { TxController.prototype.send = function(req, res) { var self = this; this.node.sendTransaction(req.body.rawtx, function(err, txid) { - if(err) { + if (err) { // TODO handle specific errors - self.common.log.warn("Error when broadcasting rawTx: " + req.body.rawtx); + self.common.log.warn('Error when broadcasting rawTx: ' + req.body.rawtx); return self.common.handleErrors(err, res); } - res.json({'txid': txid}); + res.json({ txid: txid }); }); }; diff --git a/packages/insight-api/lib/utils.js b/packages/insight-api/lib/utils.js index 94415f2890..d6d3c3e123 100644 --- a/packages/insight-api/lib/utils.js +++ b/packages/insight-api/lib/utils.js @@ -6,32 +6,34 @@ var Common = require('./common'); function UtilsController(node) { this.node = node; - this.common = new Common({log: this.node.log}); + this.common = new Common({ log: this.node.log }); } -UtilsController.prototype.estimateSmartFee = function(req, res) { +UtilsController.prototype.estimateSmartFee = function(req, res) { var self = this; var args = req.query.nbBlocks || '2'; var nbBlocks = args.split(','); - async.map(nbBlocks, function(n, next) { - var num = parseInt(n); - // Insight and Merit JSON-RPC return merit for this value (instead of micros). - - self.node.services.meritd.estimateSmartFee(num, function(err, fee) { - + async.map( + nbBlocks, + function(n, next) { + var num = parseInt(n); + // Insight and Merit JSON-RPC return merit for this value (instead of micros). + + self.node.services.meritd.estimateSmartFee(num, function(err, fee) { + if (err) { + return next(err); + } + next(null, [num, fee]); + }); + }, + function(err, result) { if (err) { - return next(err); + return self.common.handleErrors(err, res); } - next(null, [num, fee]); - }); - }, function(err, result) { - if (err) { - return self.common.handleErrors(err, res); - } - res.jsonp(_.fromPairs(result)); - }); - + res.jsonp(_.fromPairs(result)); + }, + ); }; module.exports = UtilsController; diff --git a/packages/insight-api/lib/wallet.js b/packages/insight-api/lib/wallet.js index d8deeb39c0..7058741200 100644 --- a/packages/insight-api/lib/wallet.js +++ b/packages/insight-api/lib/wallet.js @@ -5,7 +5,7 @@ var _ = require('lodash'); function WalletController(node) { this.node = node; - this.common = new Common({log: this.node.log}); + this.common = new Common({ log: this.node.log }); } WalletController.prototype.getANV = function(req, res) { @@ -16,7 +16,7 @@ WalletController.prototype.getANV = function(req, res) { var addresses = req.body.addresses; self.node.services.meritd.getANV(addresses, function(err, result) { - if(err) { + if (err) { return self.common.handleErrors(err, res); } res.jsonp(result); @@ -39,12 +39,12 @@ WalletController.prototype.getCommunityInfo = function(req, res) { WalletController.prototype.getRewards = function(req, res) { var self = this; // If there are no keys passed in, the ANV is zero. - if (_.isEmpty(req.body.addresses)) return res.jsonp({amount: 0}); + if (_.isEmpty(req.body.addresses)) return res.jsonp({ amount: 0 }); var addresses = req.body.addresses; self.node.services.meritd.getRewards(addresses, function(err, result) { - if(err) { + if (err) { return self.common.handleErrors(err, res); } res.jsonp(result); diff --git a/packages/insight-api/test/addresses.js b/packages/insight-api/test/addresses.js index 254bb8de71..3e9addd77e 100644 --- a/packages/insight-api/test/addresses.js +++ b/packages/insight-api/test/addresses.js @@ -9,93 +9,94 @@ var txinfos = { totalCount: 2, items: [ { - 'address': 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', - 'micros': 2782729129, - 'height': 534105, - 'confirmations': 123, - 'timestamp': 1441068774, - 'fees': 35436, - 'outputIndexes': [ - 0 - ], - 'inputIndexes': [], - 'tx': { - 'hash': 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', - 'version': 1, - 'inputs': [ + address: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', + micros: 2782729129, + height: 534105, + confirmations: 123, + timestamp: 1441068774, + fees: 35436, + outputIndexes: [0], + inputIndexes: [], + tx: { + hash: 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + version: 1, + inputs: [ { - 'prevTxId': 'ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425', - 'outputIndex': 1, - 'sequenceNumber': 4294967294, - 'script': '483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', - 'scriptString': '72 0x3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 33 0x03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', - 'output': { - 'micros': 2796764565, - 'script': '76a91488b1fe8aec5ae4358a11447a2f22b2781faedb9b88ac' - } - } + prevTxId: 'ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425', + outputIndex: 1, + sequenceNumber: 4294967294, + script: + '483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', + scriptString: + '72 0x3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 33 0x03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', + output: { + micros: 2796764565, + script: '76a91488b1fe8aec5ae4358a11447a2f22b2781faedb9b88ac', + }, + }, ], - 'outputs': [ + outputs: [ { - 'micros': 2782729129, - 'script': '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac' + micros: 2782729129, + script: '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac', }, { - 'micros': 14000000, - 'script': '76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac' - } + micros: 14000000, + script: '76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac', + }, ], - 'nLockTime': 534089 - } + nLockTime: 534089, + }, }, { - 'address': 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', - 'micros': -2782729129, - 'height': 534110, - 'confirmations': 118, - 'timestamp': 1441072817, - 'fees': 35437, - 'outputIndexes': [], - 'inputIndexes': [ - '0' - ], - 'tx': { - 'hash': '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', - 'version': 1, - 'inputs': [ + address: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', + micros: -2782729129, + height: 534110, + confirmations: 118, + timestamp: 1441072817, + fees: 35437, + outputIndexes: [], + inputIndexes: ['0'], + tx: { + hash: '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', + version: 1, + inputs: [ { - 'prevTxId': 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', - 'outputIndex': 0, - 'sequenceNumber': 4294967294, - 'script': '47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', - 'scriptString': '71 0x304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 33 0x034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', - 'output': { - 'micros': 2782729129, - 'script': '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac' - } - } + prevTxId: 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + outputIndex: 0, + sequenceNumber: 4294967294, + script: + '47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', + scriptString: + '71 0x304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 33 0x034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', + output: { + micros: 2782729129, + script: '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac', + }, + }, ], - 'outputs': [ + outputs: [ { - 'micros': 2764693692, - 'script': '76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac' + micros: 2764693692, + script: '76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac', }, { - 'micros': 18000000, - 'script': '76a914011d2963b619186a318f768dddfd98cd553912a088ac' - } + micros: 18000000, + script: '76a914011d2963b619186a318f768dddfd98cd553912a088ac', + }, ], - 'nLockTime': 534099 - } - } - ] + nLockTime: 534099, + }, + }, + ], }; var tx = { height: 534181, blockTimestamp: 1441116143, blockHash: '0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013', - hex: '0100000002f379708395d0a0357514205a3758a0317926428356e54a09089852fc6f7297ea010000008a473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964dffffffffb758ffd4c31693d9620f326385404530a079d5e60a90b94e46d3c2dbc29c0a98020000008a473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2ffffffff03605b0300000000001976a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac40992d03000000001976a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac256c0400000000001976a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac00000000', + hex: + '0100000002f379708395d0a0357514205a3758a0317926428356e54a09089852fc6f7297ea010000008a473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964dffffffffb758ffd4c31693d9620f326385404530a079d5e60a90b94e46d3c2dbc29c0a98020000008a473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2ffffffff03605b0300000000001976a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac40992d03000000001976a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac256c0400000000001976a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac00000000', hash: '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', version: 1, inputMicros: 53839829, @@ -107,8 +108,10 @@ var tx = { prevTxId: 'ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3', outputIndex: 1, sequence: 4294967295, - script: '473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', - scriptAsm: '3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', + script: + '473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', + scriptAsm: + '3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', micros: 53540000, }, { @@ -116,64 +119,66 @@ var tx = { prevTxId: '980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7', outputIndex: 2, sequence: 4294967295, - script: '473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', - scriptAsm: '3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', + script: + '473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', + scriptAsm: + '3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', micros: 299829, - } + }, ], outputs: [ { micros: 220000, script: '76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac', scriptAsm: 'OP_DUP OP_HASH160 b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d OP_EQUALVERIFY OP_CHECKSIG', - address: 'mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp' + address: 'mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp', }, { micros: 53320000, address: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', script: '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', - scriptAsm: 'OP_DUP OP_HASH160 d2ec20bb8e5f25a52f730384b803d95683250e0b OP_EQUALVERIFY OP_CHECKSIG' + scriptAsm: 'OP_DUP OP_HASH160 d2ec20bb8e5f25a52f730384b803d95683250e0b OP_EQUALVERIFY OP_CHECKSIG', }, { address: 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', micros: 289829, script: '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', - scriptAsm: 'OP_DUP OP_HASH160 583df9fa56ad961051e00ca93e68dfaf1eab9ec5 OP_EQUALVERIFY OP_CHECKSIG' - } + scriptAsm: 'OP_DUP OP_HASH160 583df9fa56ad961051e00ca93e68dfaf1eab9ec5 OP_EQUALVERIFY OP_CHECKSIG', + }, ], - locktime: 0 + locktime: 0, }; var txinfos2 = { totalCount: 1, items: [ { - tx: tx - } - ] + tx: tx, + }, + ], }; var utxos = [ { - 'address': 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', - 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', - 'outputIndex': 1, - 'timestamp': 1441116143, - 'micros': 53320000, - 'script': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', - 'height': 534181, - 'confirmations': 50 + address: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', + txid: '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + outputIndex: 1, + timestamp: 1441116143, + micros: 53320000, + script: '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', + height: 534181, + confirmations: 50, }, { - 'address': 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', - 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', - 'outputIndex': 2, - 'timestamp': 1441116143, - 'micros': 289829, - 'script': '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', - 'height': 534181, - 'confirmations': 50 - } + address: 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', + txid: '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + outputIndex: 2, + timestamp: 1441116143, + micros: 289829, + script: '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', + height: 534181, + confirmations: 50, + }, ]; describe('Addresses', function() { @@ -186,44 +191,44 @@ describe('Addresses', function() { unconfirmedAppearances: 0, txids: [ 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', - '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3' - ] + '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', + ], }; describe('/addr/:addr', function() { var node = { - getAddressSummary: sinon.stub().callsArgWith(2, null, summary) + getAddressSummary: sinon.stub().callsArgWith(2, null, summary), }; var addresses = new AddressController(node); var req = { addr: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', - query: {} + query: {}, }; it('should have correct data', function(done) { var insight = { - 'addrStr': 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', - 'balance': 0, - 'balanceMicros': 0, - 'totalReceived': 27.82729129, - 'totalReceivedMicros': 2782729129, - 'totalSent': 27.82729129, - 'totalSentMicros': 2782729129, - 'unconfirmedBalance': 0, - 'unconfirmedBalanceMicros': 0, - 'unconfirmedTxApperances': 0, - 'txApperances': 2, - 'transactions': [ + addrStr: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', + balance: 0, + balanceMicros: 0, + totalReceived: 27.82729129, + totalReceivedMicros: 2782729129, + totalSent: 27.82729129, + totalSentMicros: 2782729129, + unconfirmedBalance: 0, + unconfirmedBalanceMicros: 0, + unconfirmedTxApperances: 0, + txApperances: 2, + transactions: [ 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', - '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3' - ] + '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', + ], }; var res = { jsonp: function(data) { should(data).eql(insight); done(); - } + }, }; addresses.show(req, res); }); @@ -236,14 +241,14 @@ describe('Addresses', function() { controller.getAddressSummary = sinon.stub().callsArgWith(2, new Error('test')); var req = { query: { - noTxList: 1 + noTxList: 1, }, - addr: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er' + addr: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', }; var send = sinon.stub(); - var status = sinon.stub().returns({send: send}); + var status = sinon.stub().returns({ send: send }); var res = { - status: status + status: status, }; controller.show(req, res); send.callCount.should.equal(1); @@ -259,7 +264,7 @@ describe('Addresses', function() { jsonp: function(data) { should(data).eql(insight); done(); - } + }, }; addresses.balance(req, res); }); @@ -271,7 +276,7 @@ describe('Addresses', function() { jsonp: function(data) { should(data).eql(insight); done(); - } + }, }; addresses.totalReceived(req, res); @@ -284,7 +289,7 @@ describe('Addresses', function() { jsonp: function(data) { should(data).eql(insight); done(); - } + }, }; addresses.totalSent(req, res); @@ -297,7 +302,7 @@ describe('Addresses', function() { jsonp: function(data) { should(data).eql(insight); done(); - } + }, }; addresses.unconfirmedBalance(req, res); @@ -308,38 +313,38 @@ describe('Addresses', function() { it('should have correct data', function(done) { var insight = [ { - 'address': 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', - 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', - 'vout': 1, - 'ts': 1441116143, - 'scriptPubKey': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', - 'amount': 0.5332, - 'confirmations': 50, - 'height': 534181, - 'micros': 53320000, - 'confirmationsFromCache': true - } + address: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', + txid: '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + vout: 1, + ts: 1441116143, + scriptPubKey: '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', + amount: 0.5332, + confirmations: 50, + height: 534181, + micros: 53320000, + confirmationsFromCache: true, + }, ]; var todos = [ { - confirmationsFromCache: true - } + confirmationsFromCache: true, + }, ]; var node = { services: { meritd: { - height: 534230 - } + height: 534230, + }, }, - getAddressUnspentOutputs: sinon.stub().callsArgWith(2, null, utxos.slice(0, 1)) + getAddressUnspentOutputs: sinon.stub().callsArgWith(2, null, utxos.slice(0, 1)), }; var addresses = new AddressController(node); var req = { - addr: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK' + addr: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', }; var res = { @@ -347,7 +352,7 @@ describe('Addresses', function() { var merged = _.merge(data, todos); should(merged).eql(insight); done(); - } + }, }; addresses.utxo(req, res); @@ -358,52 +363,53 @@ describe('Addresses', function() { it('should have the correct data', function(done) { var insight = [ { - 'address': 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', - 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', - 'vout': 1, - 'ts': 1441116143, - 'scriptPubKey': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', - 'amount': 0.5332, - 'height': 534181, - 'micros': 53320000, - 'confirmations': 50, - 'confirmationsFromCache': true + address: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', + txid: '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + vout: 1, + ts: 1441116143, + scriptPubKey: '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', + amount: 0.5332, + height: 534181, + micros: 53320000, + confirmations: 50, + confirmationsFromCache: true, }, { - 'address': 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', - 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', - 'vout': 2, - 'ts': 1441116143, - 'scriptPubKey': '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', - 'amount': 0.00289829, - 'height': 534181, - 'micros': 289829, - 'confirmations': 50, - 'confirmationsFromCache': true - } + address: 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', + txid: '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + vout: 2, + ts: 1441116143, + scriptPubKey: '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', + amount: 0.00289829, + height: 534181, + micros: 289829, + confirmations: 50, + confirmationsFromCache: true, + }, ]; var todos = [ { - confirmationsFromCache: true - }, { - confirmationsFromCache: true - } + confirmationsFromCache: true, + }, + { + confirmationsFromCache: true, + }, ]; var node = { services: { meritd: { - height: 534230 - } + height: 534230, + }, }, - getAddressUnspentOutputs: sinon.stub().callsArgWith(2, null, utxos) + getAddressUnspentOutputs: sinon.stub().callsArgWith(2, null, utxos), }; var addresses = new AddressController(node); var req = { - addrs: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK,moZY18rGNmh4YCPeugtGW46AkkWMQttBUD' + addrs: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK,moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', }; var res = { @@ -411,7 +417,7 @@ describe('Addresses', function() { var merged = _.merge(data, todos); should(merged).eql(insight); done(); - } + }, }; addresses.multiutxo(req, res); @@ -421,140 +427,138 @@ describe('Addresses', function() { describe('/addrs/:addrs/txs', function() { it('should have correct data', function(done) { var insight = { - 'totalItems': 1, - 'from': 0, - 'to': 1, - 'items': [ + totalItems: 1, + from: 0, + to: 1, + items: [ { - 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', - 'version': 1, - 'locktime': 0, - 'vin': [ + txid: '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + version: 1, + locktime: 0, + vin: [ { - 'txid': 'ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3', - 'vout': 1, - 'scriptSig': { - 'asm': '3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', - 'hex': '473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d' + txid: 'ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3', + vout: 1, + scriptSig: { + asm: + '3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', + hex: + '473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', }, - 'sequence': 4294967295, - 'n': 0, - 'addr': 'moFfnRwt77pApKnnU6m5uocFaa43aAYpt5', - 'valueMicros': 53540000, - 'value': 0.5354, - 'doubleSpentTxID': null + sequence: 4294967295, + n: 0, + addr: 'moFfnRwt77pApKnnU6m5uocFaa43aAYpt5', + valueMicros: 53540000, + value: 0.5354, + doubleSpentTxID: null, }, { - 'txid': '980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7', - 'vout': 2, - 'scriptSig': { - 'asm': '3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', - 'hex': '473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2' + txid: '980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7', + vout: 2, + scriptSig: { + asm: + '3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', + hex: + '473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', }, - 'sequence': 4294967295, - 'n': 1, - 'addr': 'n1XJBAyU4hNR4xRtY3UxnmAteoJX83p5qv', - 'valueMicros': 299829, - 'value': 0.00299829, - 'doubleSpentTxID': null - } + sequence: 4294967295, + n: 1, + addr: 'n1XJBAyU4hNR4xRtY3UxnmAteoJX83p5qv', + valueMicros: 299829, + value: 0.00299829, + doubleSpentTxID: null, + }, ], - 'vout': [ + vout: [ { - 'value': '0.00220000', - 'n': 0, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp' - ] + value: '0.00220000', + n: 0, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp'], }, - 'spentHeight': null, - 'spentIndex': null, - 'spentTxId': null + spentHeight: null, + spentIndex: null, + spentTxId: null, }, { - 'value': '0.53320000', - 'n': 1, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 d2ec20bb8e5f25a52f730384b803d95683250e0b OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK' - ], + value: '0.53320000', + n: 1, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 d2ec20bb8e5f25a52f730384b803d95683250e0b OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK'], }, - 'spentHeight': null, - 'spentIndex': null, - 'spentTxId': null + spentHeight: null, + spentIndex: null, + spentTxId: null, }, { - 'value': '0.00289829', - 'n': 2, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 583df9fa56ad961051e00ca93e68dfaf1eab9ec5 OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD' - ] + value: '0.00289829', + n: 2, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 583df9fa56ad961051e00ca93e68dfaf1eab9ec5 OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['moZY18rGNmh4YCPeugtGW46AkkWMQttBUD'], }, - 'spentHeight': null, - 'spentIndex': null, - 'spentTxId': null - } + spentHeight: null, + spentIndex: null, + spentTxId: null, + }, ], - 'blockhash': '0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013', - 'blockheight': 534181, - 'confirmations': 52, - 'time': 1441116143, - 'blocktime': 1441116143, - 'valueOut': 0.53829829, - 'valueIn': 0.53839829, - 'fees': 0.0001, - 'firstSeenTs': 1441108193 - } - ] + blockhash: '0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013', + blockheight: 534181, + confirmations: 52, + time: 1441116143, + blocktime: 1441116143, + valueOut: 0.53829829, + valueIn: 0.53839829, + fees: 0.0001, + firstSeenTs: 1441108193, + }, + ], }; var todos = { - 'items': [ + items: [ { - 'vout': [ + vout: [ { - 'scriptPubKey': { - 'reqSigs': 1, - } + scriptPubKey: { + reqSigs: 1, + }, }, { - 'scriptPubKey': { - 'reqSigs': 1, - } + scriptPubKey: { + reqSigs: 1, + }, }, { - 'scriptPubKey': { - 'reqSigs': 1, - } - } + scriptPubKey: { + reqSigs: 1, + }, + }, ], - 'firstSeenTs': 1441108193 - } - ] + firstSeenTs: 1441108193, + }, + ], }; var node = { getAddressHistory: sinon.stub().callsArgWith(2, null, txinfos2), services: { meritd: { - height: 534232 - } + height: 534232, + }, }, - network: 'testnet' + network: 'testnet', }; var addresses = new AddressController(node); @@ -562,7 +566,7 @@ describe('Addresses', function() { var req = { addrs: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK,moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', query: {}, - body: {} + body: {}, }; var res = { @@ -570,135 +574,129 @@ describe('Addresses', function() { var merged = _.merge(data, todos); should(merged).eql(insight); done(); - } + }, }; addresses.multitxs(req, res); }); it('should have trimmed data', function(done) { var insight = { - 'totalItems': 1, - 'from': 0, - 'to': 1, - 'items': [ + totalItems: 1, + from: 0, + to: 1, + items: [ { - 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', - 'version': 1, - 'locktime': 0, - 'vin': [ + txid: '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + version: 1, + locktime: 0, + vin: [ { - 'txid': 'ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3', - 'vout': 1, - 'sequence': 4294967295, - 'n': 0, - 'addr': 'moFfnRwt77pApKnnU6m5uocFaa43aAYpt5', - 'valueMicros': 53540000, - 'value': 0.5354, - 'doubleSpentTxID': null + txid: 'ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3', + vout: 1, + sequence: 4294967295, + n: 0, + addr: 'moFfnRwt77pApKnnU6m5uocFaa43aAYpt5', + valueMicros: 53540000, + value: 0.5354, + doubleSpentTxID: null, }, { - 'txid': '980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7', - 'vout': 2, - 'sequence': 4294967295, - 'n': 1, - 'addr': 'n1XJBAyU4hNR4xRtY3UxnmAteoJX83p5qv', - 'valueMicros': 299829, - 'value': 0.00299829, - 'doubleSpentTxID': null - } + txid: '980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7', + vout: 2, + sequence: 4294967295, + n: 1, + addr: 'n1XJBAyU4hNR4xRtY3UxnmAteoJX83p5qv', + valueMicros: 299829, + value: 0.00299829, + doubleSpentTxID: null, + }, ], - 'vout': [ + vout: [ { - 'value': '0.00220000', - 'n': 0, - 'scriptPubKey': { - 'hex': '76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp' - ] - } + value: '0.00220000', + n: 0, + scriptPubKey: { + hex: '76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp'], + }, }, { - 'value': '0.53320000', - 'n': 1, - 'scriptPubKey': { - 'hex': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK' - ], - } + value: '0.53320000', + n: 1, + scriptPubKey: { + hex: '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK'], + }, }, { - 'value': '0.00289829', - 'n': 2, - 'scriptPubKey': { - 'hex': '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD' - ] - } - } + value: '0.00289829', + n: 2, + scriptPubKey: { + hex: '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['moZY18rGNmh4YCPeugtGW46AkkWMQttBUD'], + }, + }, ], - 'blockhash': '0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013', - 'blockheight': 534181, - 'confirmations': 52, - 'time': 1441116143, - 'blocktime': 1441116143, - 'valueOut': 0.53829829, - 'valueIn': 0.53839829, - 'fees': 0.0001, - 'firstSeenTs': 1441108193 - } - ] + blockhash: '0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013', + blockheight: 534181, + confirmations: 52, + time: 1441116143, + blocktime: 1441116143, + valueOut: 0.53829829, + valueIn: 0.53839829, + fees: 0.0001, + firstSeenTs: 1441108193, + }, + ], }; var todos = { - 'items': [ + items: [ { - 'vout': [ + vout: [ { - 'scriptPubKey': { - 'reqSigs': 1, - } + scriptPubKey: { + reqSigs: 1, + }, }, { - 'scriptPubKey': { - 'reqSigs': 1, - } + scriptPubKey: { + reqSigs: 1, + }, }, { - 'scriptPubKey': { - 'reqSigs': 1, - } - } + scriptPubKey: { + reqSigs: 1, + }, + }, ], - 'firstSeenTs': 1441108193 - } - ] + firstSeenTs: 1441108193, + }, + ], }; var node = { getAddressHistory: sinon.stub().callsArgWith(2, null, txinfos2), services: { meritd: { - height: 534232 - } + height: 534232, + }, }, - network: 'testnet' + network: 'testnet', }; var addresses = new AddressController(node); var req = { addrs: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK,moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', - query: {noSpent: '1', noScriptSig: '1', noAsm: '1'}, - body: {} + query: { noSpent: '1', noScriptSig: '1', noAsm: '1' }, + body: {}, }; var res = { @@ -706,7 +704,7 @@ describe('Addresses', function() { var merged = _.merge(data, todos); should(merged).eql(insight); done(); - } + }, }; addresses.multitxs(req, res); @@ -720,14 +718,14 @@ describe('Addresses', function() { query: { noAsm: '0', noScriptSig: '0', - noSpent: '0' - } + noSpent: '0', + }, }; var options = addresses._getTransformOptions(req); options.should.eql({ noAsm: false, noScriptSig: false, - noSpent: false + noSpent: false, }); }); it('will return true with value of string "1"', function() { @@ -737,14 +735,14 @@ describe('Addresses', function() { query: { noAsm: '1', noScriptSig: '1', - noSpent: '1' - } + noSpent: '1', + }, }; var options = addresses._getTransformOptions(req); options.should.eql({ noAsm: true, noScriptSig: true, - noSpent: true + noSpent: true, }); }); it('will return true with value of number "1"', function() { @@ -754,14 +752,14 @@ describe('Addresses', function() { query: { noAsm: 1, noScriptSig: 1, - noSpent: 1 - } + noSpent: 1, + }, }; var options = addresses._getTransformOptions(req); options.should.eql({ noAsm: true, noScriptSig: true, - noSpent: true + noSpent: true, }); }); }); diff --git a/packages/insight-api/test/blocks.js b/packages/insight-api/test/blocks.js index 4eaa891f75..77ca4299e2 100644 --- a/packages/insight-api/test/blocks.js +++ b/packages/insight-api/test/blocks.js @@ -15,81 +15,85 @@ var blockIndexes = { prevHash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', nextHash: '000000000001e866a8057cde0c650796cb8a59e0e6038dc31c69d7ca6649627d', confirmations: 119, - height: 533974 + height: 533974, }, '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7': { hash: '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7', chainWork: '00000000000000000000000000000000000000000000000544ea52e1575ca753', prevHash: '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441', confirmations: 119, - height: 533951 + height: 533951, }, '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441': { hash: '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441', chainWork: '00000000000000000000000000000000000000000000000544ea52e0575ba752', prevHash: '000000000001b9c41e6c4a7b81a068b50cf3f522ee4ac1e942e75ec16e090547', - height: 533950 + height: 533950, }, '000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4': { hash: '000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4', prevHash: '00000000000000000a9d74a7b527f7b995fc21ceae5aa21087b443469351a362', - height: 375493 + height: 375493, }, 533974: { hash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', chainWork: '0000000000000000000000000000000000000000000000054626b1839ade284a', prevHash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', - height: 533974 - } + height: 533974, + }, }; describe('Blocks', function() { describe('/blocks/:blockHash route', function() { var insight = { - 'hash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', - 'confirmations': 119, - 'size': 1011, - 'height': 533974, - 'version': 536870919, - 'merkleroot': 'b06437355844b8178173f3e18ca141472e4b0861daa81ef0f701cf9e51f0283e', - 'tx': [ + hash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + confirmations: 119, + size: 1011, + height: 533974, + version: 536870919, + merkleroot: 'b06437355844b8178173f3e18ca141472e4b0861daa81ef0f701cf9e51f0283e', + tx: [ '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd', 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', - '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1' + '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1', ], - 'time': 1440987503, - 'nonce': 1868753784, - 'bits': '1a0cf267', - 'difficulty': 1295829.93087696, - 'chainwork': '0000000000000000000000000000000000000000000000054626b1839ade284a', - 'previousblockhash': '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', - 'nextblockhash': '000000000001e866a8057cde0c650796cb8a59e0e6038dc31c69d7ca6649627d', - 'reward': 12.5, - 'isMainChain': true, - 'poolInfo': {} + time: 1440987503, + nonce: 1868753784, + bits: '1a0cf267', + difficulty: 1295829.93087696, + chainwork: '0000000000000000000000000000000000000000000000054626b1839ade284a', + previousblockhash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', + nextblockhash: '000000000001e866a8057cde0c650796cb8a59e0e6038dc31c69d7ca6649627d', + reward: 12.5, + isMainChain: true, + poolInfo: {}, }; - var meritcoreBlock = meritcore.Block.fromBuffer(new Buffer(blocks['0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7'], 'hex')); + var meritcoreBlock = meritcore.Block.fromBuffer( + new Buffer(blocks['0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7'], 'hex'), + ); var node = { log: sinon.stub(), getBlock: sinon.stub().callsArgWith(1, null, meritcoreBlock), services: { meritd: { - getBlockHeader: sinon.stub().callsArgWith(1, null, blockIndexes['0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7']), + getBlockHeader: sinon + .stub() + .callsArgWith(1, null, blockIndexes['0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7']), isMainChain: sinon.stub().returns(true), - height: 534092 - } - } + height: 534092, + }, + }, }; it('block data should be correct', function(done) { - var controller = new BlockController({node: node}); + var controller = new BlockController({ node: node }); var hash = '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7'; var req = { params: { - blockHash: hash - } + blockHash: hash, + }, }; var res = {}; var next = function() { @@ -102,23 +106,27 @@ describe('Blocks', function() { }); it('block pool info should be correct', function(done) { - var block = meritcore.Block.fromString(blocks['000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4']); + var block = meritcore.Block.fromString( + blocks['000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4'], + ); var node = { log: sinon.stub(), getBlock: sinon.stub().callsArgWith(1, null, block), services: { meritd: { - getBlockHeader: sinon.stub().callsArgWith(1, null, blockIndexes['000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4']), + getBlockHeader: sinon + .stub() + .callsArgWith(1, null, blockIndexes['000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4']), isMainChain: sinon.stub().returns(true), - height: 534092 - } - } + height: 534092, + }, + }, }; - var controller = new BlockController({node: node}); + var controller = new BlockController({ node: node }); var req = { params: { - blockHash: hash - } + blockHash: hash, + }, }; var res = {}; var next = function() { @@ -133,54 +141,64 @@ describe('Blocks', function() { controller.block(req, res, next); }); - }); describe('/blocks route', function() { - var insight = { - 'blocks': [ + blocks: [ { - 'height': 533951, - 'size': 206, - 'hash': '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7', - 'time': 1440978683, - 'txlength': 1, - 'poolInfo': { - 'poolName': 'AntMiner', - 'url': 'https://bitmaintech.com/' - } + height: 533951, + size: 206, + hash: '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7', + time: 1440978683, + txlength: 1, + poolInfo: { + poolName: 'AntMiner', + url: 'https://bitmaintech.com/', + }, }, { - 'height': 533950, - 'size': 206, - 'hash': '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441', - 'time': 1440977479, - 'txlength': 1, - 'poolInfo': { - 'poolName': 'AntMiner', - 'url': 'https://bitmaintech.com/' - } - } + height: 533950, + size: 206, + hash: '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441', + time: 1440977479, + txlength: 1, + poolInfo: { + poolName: 'AntMiner', + url: 'https://bitmaintech.com/', + }, + }, ], - 'length': 2, - 'pagination': { - 'current': '2015-08-30', - 'currentTs': 1440979199, - 'isToday': false, - 'more': false, - 'next': '2015-08-31', - 'prev': '2015-08-29' - } + length: 2, + pagination: { + current: '2015-08-30', + currentTs: 1440979199, + isToday: false, + more: false, + next: '2015-08-31', + prev: '2015-08-29', + }, }; var stub = sinon.stub(); - stub.onFirstCall().callsArgWith(1, null, new Buffer(blocks['000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7'], 'hex')); - stub.onSecondCall().callsArgWith(1, null, new Buffer(blocks['00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441'], 'hex')); + stub + .onFirstCall() + .callsArgWith( + 1, + null, + new Buffer(blocks['000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7'], 'hex'), + ); + stub + .onSecondCall() + .callsArgWith( + 1, + null, + new Buffer(blocks['00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441'], 'hex'), + ); var hashes = [ '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441', - '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7' + '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7', ]; var node = { log: sinon.stub(), @@ -190,26 +208,26 @@ describe('Blocks', function() { getBlockHeader: function(hash, callback) { callback(null, blockIndexes[hash]); }, - getBlockHashesByTimestamp: sinon.stub().callsArgWith(2, null, hashes) - } - } + getBlockHashesByTimestamp: sinon.stub().callsArgWith(2, null, hashes), + }, + }, }; it('should have correct data', function(done) { - var blocks = new BlockController({node: node}); + var blocks = new BlockController({ node: node }); var req = { query: { limit: 2, - blockDate: '2015-08-30' - } + blockDate: '2015-08-30', + }, }; var res = { jsonp: function(data) { should(data).eql(insight); done(); - } + }, }; blocks.list(req, res); @@ -223,30 +241,30 @@ describe('Blocks', function() { meritd: { getBlockHeader: function(height, callback) { callback(null, blockIndexes[height]); - } - } - } + }, + }, + }, }; it('should have correct data', function(done) { - var blocks = new BlockController({node: node}); + var blocks = new BlockController({ node: node }); var insight = { - 'blockHash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7' + blockHash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', }; var height = 533974; var req = { params: { - height: height - } + height: height, + }, }; var res = { jsonp: function(data) { should(data).eql(insight); done(); - } + }, }; blocks.blockIndex(req, res); @@ -255,9 +273,9 @@ describe('Blocks', function() { describe('#getBlockReward', function() { var node = { - log: sinon.stub() + log: sinon.stub(), }; - var blocks = new BlockController({node: node}); + var blocks = new BlockController({ node: node }); it('should give a block reward of 50 * 1e8 for block before first halvening', function() { blocks.getBlockReward(100000).should.equal(50 * 1e8); diff --git a/packages/insight-api/test/currency.js b/packages/insight-api/test/currency.js index 6437e2cbff..a9b7c19649 100644 --- a/packages/insight-api/test/currency.js +++ b/packages/insight-api/test/currency.js @@ -6,16 +6,15 @@ var proxyquire = require('proxyquire'); var CurrencyController = require('../lib/currency'); describe('Currency', function() { - var bitstampData = { high: 239.44, - last: 237.90, + last: 237.9, timestamp: 1443798711, bid: 237.61, vwap: 237.88, volume: 21463.27736401, - low: 235.00, - ask: 237.90 + low: 235.0, + ask: 237.9, }; it.skip('will make live request to bitstamp', function(done) { @@ -27,56 +26,56 @@ describe('Currency', function() { should.exist(response.data.bitstamp); (typeof response.data.bitstamp).should.equal('number'); done(); - } + }, }; currency.index(req, res); }); it('will retrieve a fresh value', function(done) { var TestCurrencyController = proxyquire('../lib/currency', { - request: sinon.stub().callsArgWith(1, null, {statusCode: 200}, JSON.stringify(bitstampData)) + request: sinon.stub().callsArgWith(1, null, { statusCode: 200 }, JSON.stringify(bitstampData)), }); var node = { log: { - error: sinon.stub() - } + error: sinon.stub(), + }, }; - var currency = new TestCurrencyController({node: node}); - currency.bitstampRate = 220.20; + var currency = new TestCurrencyController({ node: node }); + currency.bitstampRate = 220.2; currency.timestamp = Date.now() - 61000 * CurrencyController.DEFAULT_CURRENCY_DELAY; var req = {}; var res = { jsonp: function(response) { response.status.should.equal(200); should.exist(response.data.bitstamp); - response.data.bitstamp.should.equal(237.90); + response.data.bitstamp.should.equal(237.9); done(); - } + }, }; currency.index(req, res); }); it('will log an error from request', function(done) { var TestCurrencyController = proxyquire('../lib/currency', { - request: sinon.stub().callsArgWith(1, new Error('test')) + request: sinon.stub().callsArgWith(1, new Error('test')), }); var node = { log: { - error: sinon.stub() - } + error: sinon.stub(), + }, }; - var currency = new TestCurrencyController({node: node}); - currency.bitstampRate = 237.90; + var currency = new TestCurrencyController({ node: node }); + currency.bitstampRate = 237.9; currency.timestamp = Date.now() - 65000 * CurrencyController.DEFAULT_CURRENCY_DELAY; var req = {}; var res = { jsonp: function(response) { response.status.should.equal(200); should.exist(response.data.bitstamp); - response.data.bitstamp.should.equal(237.90); + response.data.bitstamp.should.equal(237.9); node.log.error.callCount.should.equal(1); done(); - } + }, }; currency.index(req, res); }); @@ -84,27 +83,26 @@ describe('Currency', function() { it('will retrieve a cached value', function(done) { var request = sinon.stub(); var TestCurrencyController = proxyquire('../lib/currency', { - request: request + request: request, }); var node = { log: { - error: sinon.stub() - } + error: sinon.stub(), + }, }; - var currency = new TestCurrencyController({node: node}); - currency.bitstampRate = 237.90; + var currency = new TestCurrencyController({ node: node }); + currency.bitstampRate = 237.9; currency.timestamp = Date.now(); var req = {}; var res = { jsonp: function(response) { response.status.should.equal(200); should.exist(response.data.bitstamp); - response.data.bitstamp.should.equal(237.90); + response.data.bitstamp.should.equal(237.9); request.callCount.should.equal(0); done(); - } + }, }; currency.index(req, res); }); - }); diff --git a/packages/insight-api/test/index.js b/packages/insight-api/test/index.js index 964fe6e504..a3cd028f68 100644 --- a/packages/insight-api/test/index.js +++ b/packages/insight-api/test/index.js @@ -11,7 +11,7 @@ describe('Index', function() { var node = {}; var index = new InsightAPI({ rateLimiterOptions: options, - node: node + node: node, }); index.rateLimiterOptions.should.equal(options); }); @@ -19,7 +19,7 @@ describe('Index', function() { var node = {}; var index = new InsightAPI({ disableRateLimiter: true, - node: node + node: node, }); index.disableRateLimiter.should.equal(true); }); @@ -27,12 +27,12 @@ describe('Index', function() { describe('#_getRateLimiter', function() { it('will pass options to rate limiter', function() { var options = { - whitelist: ['127.0.0.1'] + whitelist: ['127.0.0.1'], }; var node = {}; var index = new InsightAPI({ rateLimiterOptions: options, - node: node + node: node, }); var limiter = index._getRateLimiter(); limiter.whitelist.should.eql(['127.0.0.1']); @@ -41,15 +41,15 @@ describe('Index', function() { describe('#cache', function() { it('will set cache control header', function(done) { var node = { - log: sinon.stub() + log: sinon.stub(), }; var index = new InsightAPI({ enableCache: true, - node: node + node: node, }); var req = {}; var res = { - header: sinon.stub() + header: sinon.stub(), }; var middle = index.cache(10); middle(req, res, function() { @@ -61,15 +61,15 @@ describe('Index', function() { }); it('will NOT set cache control header', function(done) { var node = { - log: sinon.stub() + log: sinon.stub(), }; var index = new InsightAPI({ enableCache: false, - node: node + node: node, }); var req = {}; var res = { - header: sinon.stub() + header: sinon.stub(), }; var middle = index.cache(10); middle(req, res, function() { @@ -81,16 +81,16 @@ describe('Index', function() { describe('#cacheShort', function() { it('will set SHORT cache control header', function(done) { var node = { - log: sinon.stub() + log: sinon.stub(), }; var index = new InsightAPI({ enableCache: true, cacheShortSeconds: 35, - node: node + node: node, }); var req = {}; var res = { - header: sinon.stub() + header: sinon.stub(), }; var middle = index.cacheShort(); middle(req, res, function() { @@ -102,15 +102,15 @@ describe('Index', function() { }); it('will set SHORT DEFAULT cache control header', function(done) { var node = { - log: sinon.stub() + log: sinon.stub(), }; var index = new InsightAPI({ enableCache: true, - node: node + node: node, }); var req = {}; var res = { - header: sinon.stub() + header: sinon.stub(), }; var middle = index.cacheShort(); middle(req, res, function() { @@ -124,16 +124,16 @@ describe('Index', function() { describe('#cacheLong', function() { it('will set LONG cache control header', function(done) { var node = { - log: sinon.stub() + log: sinon.stub(), }; var index = new InsightAPI({ enableCache: true, cacheLongSeconds: 86400000, - node: node + node: node, }); var req = {}; var res = { - header: sinon.stub() + header: sinon.stub(), }; var middle = index.cacheLong(); middle(req, res, function() { @@ -145,15 +145,15 @@ describe('Index', function() { }); it('will set LONG DEFAULT cache control header', function(done) { var node = { - log: sinon.stub() + log: sinon.stub(), }; var index = new InsightAPI({ enableCache: true, - node: node + node: node, }); var req = {}; var res = { - header: sinon.stub() + header: sinon.stub(), }; var middle = index.cacheLong(); middle(req, res, function() { @@ -168,12 +168,12 @@ describe('Index', function() { it('will use rate limiter by default', function() { var node = {}; var index = new InsightAPI({ - node: node + node: node, }); var middlewareFunc = sinon.stub(); var middleware = sinon.stub().returns(middlewareFunc); var limiter = { - middleware: middleware + middleware: middleware, }; index._getRateLimiter = sinon.stub().returns(limiter); var use = sinon.stub(); @@ -181,7 +181,7 @@ describe('Index', function() { use: use, get: sinon.stub(), param: sinon.stub(), - post: sinon.stub() + post: sinon.stub(), }; index.setupRoutes(app); use.callCount.should.be.above(0); @@ -192,7 +192,7 @@ describe('Index', function() { var node = {}; var index = new InsightAPI({ node: node, - disableRateLimiter: true + disableRateLimiter: true, }); index._getRateLimiter = sinon.stub(); var use = sinon.stub(); @@ -200,7 +200,7 @@ describe('Index', function() { use: use, get: sinon.stub(), param: sinon.stub(), - post: sinon.stub() + post: sinon.stub(), }; index.setupRoutes(app); index._getRateLimiter.callCount.should.equal(0); diff --git a/packages/insight-api/test/messages.js b/packages/insight-api/test/messages.js index 5334dc4147..f42fdec14c 100644 --- a/packages/insight-api/test/messages.js +++ b/packages/insight-api/test/messages.js @@ -7,7 +7,6 @@ var meritcore = require('meritcore-lib'); var _ = require('lodash'); describe('Messages', function() { - var privateKey = meritcore.PrivateKey.fromWIF('cQwApHAg8hw9AZuxiU4a7g9kFWdaemhPxVZXWiAKgJTx6dPP32fN'); var address = 'mswTKCE2tYSFvUNnNPBKZfeNmugYL1rZMx'; var badAddress = 'mswTKCE2tYSFvUNnNPBKZfeNmuhYL1rZMm'; @@ -15,61 +14,59 @@ describe('Messages', function() { var message = 'cellar door'; it('will verify a message (true)', function(done) { - - var controller = new MessagesController({node: {}}); + var controller = new MessagesController({ node: {} }); var req = { body: { - 'address': address, - 'signature': signature, - 'message': message + address: address, + signature: signature, + message: message, }, - query: {} + query: {}, }; var res = { json: function(data) { data.result.should.equal(true); done(); - } + }, }; controller.verify(req, res); }); it('will verify a message (false)', function(done) { - - var controller = new MessagesController({node: {}}); + var controller = new MessagesController({ node: {} }); var req = { body: { - 'address': address, - 'signature': signature, - 'message': 'wrong message' + address: address, + signature: signature, + message: 'wrong message', }, - query: {} + query: {}, }; var res = { json: function(data) { data.result.should.equal(false); done(); - } + }, }; controller.verify(req, res); }); it('handle an error from message verification', function(done) { - var controller = new MessagesController({node: {}}); + var controller = new MessagesController({ node: {} }); var req = { body: { - 'address': badAddress, - 'signature': signature, - 'message': message + address: badAddress, + signature: signature, + message: message, }, - query: {} + query: {}, }; var send = sinon.stub(); - var status = sinon.stub().returns({send: send}); + var status = sinon.stub().returns({ send: send }); var res = { status: status, }; @@ -80,20 +77,19 @@ describe('Messages', function() { }); it('handle error with missing parameters', function(done) { - var controller = new MessagesController({node: {}}); + var controller = new MessagesController({ node: {} }); var req = { body: {}, - query: {} + query: {}, }; var send = sinon.stub(); - var status = sinon.stub().returns({send: send}); + var status = sinon.stub().returns({ send: send }); var res = { - status: status + status: status, }; controller.verify(req, res); status.args[0][0].should.equal(400); send.args[0][0].should.match(/^Missing parameters/); done(); }); - }); diff --git a/packages/insight-api/test/ratelimiter.js b/packages/insight-api/test/ratelimiter.js index 5053b21213..5091c0de02 100644 --- a/packages/insight-api/test/ratelimiter.js +++ b/packages/insight-api/test/ratelimiter.js @@ -6,7 +6,6 @@ var sinon = require('sinon'); var RateLimiter = require('../lib/ratelimiter'); describe('RateLimiter', function() { - describe('@constructor', function() { it('will instantiate without options', function() { var limiter = new RateLimiter(); @@ -30,7 +29,7 @@ describe('RateLimiter', function() { whitelistLimit: 1, whitelistInterval: 1, blacklistLimit: 1, - blacklistInterval: 1 + blacklistInterval: 1, }); should.exist(limiter); should.exist(limiter.config); @@ -52,12 +51,12 @@ describe('RateLimiter', function() { var limiter = new RateLimiter(); var req = { headers: { - 'cf-connecting-ip': '127.0.0.1' - } + 'cf-connecting-ip': '127.0.0.1', + }, }; var setHeader = sinon.stub(); var res = { - setHeader: setHeader + setHeader: setHeader, }; limiter.middleware()(req, res, function() { setHeader.callCount.should.equal(2); @@ -71,23 +70,23 @@ describe('RateLimiter', function() { it('will give rate limit error', function() { var node = { log: { - warn: sinon.stub() - } + warn: sinon.stub(), + }, }; - var limiter = new RateLimiter({node: node}); + var limiter = new RateLimiter({ node: node }); limiter.exceeded = sinon.stub().returns(true); var req = { headers: { - 'cf-connecting-ip': '127.0.0.1' - } + 'cf-connecting-ip': '127.0.0.1', + }, }; var jsonp = sinon.stub(); var status = sinon.stub().returns({ - jsonp: jsonp + jsonp: jsonp, }); var res = { status: status, - setHeader: sinon.stub() + setHeader: sinon.stub(), }; limiter.middleware()(req, res); status.callCount.should.equal(1); @@ -95,7 +94,7 @@ describe('RateLimiter', function() { jsonp.callCount.should.equal(1); jsonp.args[0][0].should.eql({ status: 429, - error: 'Rate limit exceeded' + error: 'Rate limit exceeded', }); }); }); @@ -103,14 +102,14 @@ describe('RateLimiter', function() { describe('#exceeded', function() { it('should not be exceeded', function() { var node = {}; - var limiter = new RateLimiter({node: node}); + var limiter = new RateLimiter({ node: node }); var client = limiter.addClient('127.0.0.1'); var exceeded = limiter.exceeded(client); exceeded.should.equal(false); }); it('should be exceeded', function() { var node = {}; - var limiter = new RateLimiter({node: node}); + var limiter = new RateLimiter({ node: node }); var client = limiter.addClient('127.0.0.1'); client.visits = 3 * 60 * 60 + 1; var exceeded = limiter.exceeded(client); @@ -119,11 +118,9 @@ describe('RateLimiter', function() { it('should exclude whitelisted with no limit', function() { var node = {}; var limiter = new RateLimiter({ - whitelist: [ - '127.0.0.1' - ], + whitelist: ['127.0.0.1'], node: node, - whitelistLimit: -1 + whitelistLimit: -1, }); var client = limiter.addClient('127.0.0.1'); client.visits = Infinity; @@ -135,34 +132,34 @@ describe('RateLimiter', function() { describe('#getClientName', function() { it('should get client name from cloudflare header', function() { var node = {}; - var limiter = new RateLimiter({node: node}); + var limiter = new RateLimiter({ node: node }); var req = { headers: { - 'cf-connecting-ip': '127.0.0.1' - } + 'cf-connecting-ip': '127.0.0.1', + }, }; var name = limiter.getClientName(req); name.should.equal('127.0.0.1'); }); it('should get client name from x forwarded header', function() { var node = {}; - var limiter = new RateLimiter({node: node}); + var limiter = new RateLimiter({ node: node }); var req = { headers: { - 'x-forwarded-for': '127.0.0.1' - } + 'x-forwarded-for': '127.0.0.1', + }, }; var name = limiter.getClientName(req); name.should.equal('127.0.0.1'); }); it('should get client name from connection remote address', function() { var node = {}; - var limiter = new RateLimiter({node: node}); + var limiter = new RateLimiter({ node: node }); var req = { headers: {}, connection: { - remoteAddress: '127.0.0.1' - } + remoteAddress: '127.0.0.1', + }, }; var name = limiter.getClientName(req); name.should.equal('127.0.0.1'); @@ -178,12 +175,11 @@ describe('RateLimiter', function() { var THREE_HOURS_PLUS = 3 * 60 * 60 * 1000 + 1; var clock = sandbox.useFakeTimers(); var node = {}; - var limiter = new RateLimiter({node: node}); + var limiter = new RateLimiter({ node: node }); limiter.addClient('127.0.0.1'); should.exist(limiter.clients['127.0.0.1']); clock.tick(THREE_HOURS_PLUS); should.not.exist(limiter.clients['127.0.0.1']); }); }); - }); diff --git a/packages/insight-api/test/status.js b/packages/insight-api/test/status.js index bedba89340..7171ab52c6 100644 --- a/packages/insight-api/test/status.js +++ b/packages/insight-api/test/status.js @@ -15,7 +15,7 @@ describe('Status', function() { difficulty: 21546.906405522557, testnet: true, relayFee: 1000, - errors: '' + errors: '', }; var outSetInfo = { @@ -25,7 +25,7 @@ describe('Status', function() { txouts: 151, bytes_serialized: 10431, hash_serialized: 'c165d5dcb22a897745ee2ee274b47133b995bbcf8dd4a7572fedad87541c7df8', - total_amount: 750000000000 + total_amount: 750000000000, }; var node = { @@ -33,16 +33,16 @@ describe('Status', function() { meritd: { getInfo: sinon.stub().callsArgWith(0, null, info), getBestBlockHash: sinon.stub().callsArgWith(0, null, outSetInfo.bestblock), - tiphash: outSetInfo.bestblock - } - } + tiphash: outSetInfo.bestblock, + }, + }, }; var status = new StatusController(node); it('getInfo', function(done) { var req = { - query: {} + query: {}, }; var res = { jsonp: function(data) { @@ -55,7 +55,7 @@ describe('Status', function() { should.exist(data.info.testnet); should.exist(data.info.relayfee); done(); - } + }, }; status.show(req, res); @@ -64,14 +64,14 @@ describe('Status', function() { it('getDifficulty', function(done) { var req = { query: { - q: 'getDifficulty' - } + q: 'getDifficulty', + }, }; var res = { jsonp: function(data) { data.difficulty.should.equal(info.difficulty); done(); - } + }, }; status.show(req, res); @@ -80,14 +80,14 @@ describe('Status', function() { it('getBestBlockHash', function(done) { var req = { query: { - q: 'getBestBlockHash' - } + q: 'getBestBlockHash', + }, }; var res = { jsonp: function(data) { data.bestblockhash.should.equal(outSetInfo.bestblock); done(); - } + }, }; status.show(req, res); }); @@ -95,19 +95,18 @@ describe('Status', function() { it('getLastBlockHash', function(done) { var req = { query: { - q: 'getLastBlockHash' - } + q: 'getLastBlockHash', + }, }; var res = { jsonp: function(data) { data.syncTipHash.should.equal(outSetInfo.bestblock); data.lastblockhash.should.equal(outSetInfo.bestblock); done(); - } + }, }; status.show(req, res); }); - }); describe('/sync', function() { @@ -117,9 +116,9 @@ describe('Status', function() { meritd: { height: 500000, isSynced: sinon.stub().callsArgWith(0, null, true), - syncPercentage: sinon.stub().callsArgWith(0, null, 99.99) - } - } + syncPercentage: sinon.stub().callsArgWith(0, null, 99.99), + }, + }, }; var expected = { @@ -128,7 +127,7 @@ describe('Status', function() { syncPercentage: 100, height: 500000, error: null, - type: 'Merit Node' + type: 'Merit Node', }; var status = new StatusController(node); @@ -138,7 +137,7 @@ describe('Status', function() { jsonp: function(data) { should(data).eql(expected); done(); - } + }, }; status.sync(req, res); }); @@ -151,7 +150,7 @@ describe('Status', function() { var expected = { connected: true, host: '127.0.0.1', - port: null + port: null, }; var req = {}; @@ -159,7 +158,7 @@ describe('Status', function() { jsonp: function(data) { should(data).eql(expected); done(); - } + }, }; var status = new StatusController(node); @@ -172,7 +171,7 @@ describe('Status', function() { it('should have correct data', function(done) { var node = {}; var expected = { - version: require('../package.json').version + version: require('../package.json').version, }; var req = {}; @@ -180,7 +179,7 @@ describe('Status', function() { jsonp: function(data) { should(data).eql(expected); done(); - } + }, }; var status = new StatusController(node); diff --git a/packages/insight-api/test/transactions.js b/packages/insight-api/test/transactions.js index 2ab63d71ab..aece429286 100644 --- a/packages/insight-api/test/transactions.js +++ b/packages/insight-api/test/transactions.js @@ -9,94 +9,95 @@ describe('Transactions', function() { describe('/tx/:txid', function() { it('should have correct data', function(done) { var insight = { - 'txid': 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', - 'version': 1, - 'locktime': 0, - 'vin': [ + txid: 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', + version: 1, + locktime: 0, + vin: [ { - 'txid': '87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad', - 'vout': 0, - 'scriptSig': { - 'asm': '30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', - 'hex': '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307' + txid: '87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad', + vout: 0, + scriptSig: { + asm: + '30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + hex: + '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', }, - 'sequence': 4294967295, - 'n': 0, - 'addr': 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', - 'valueMicros': 18535505, - 'value': 0.18535505, - 'doubleSpentTxID': null, - 'isConfirmed': true, - 'confirmations': 242, - 'unconfirmedInput': false + sequence: 4294967295, + n: 0, + addr: 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + valueMicros: 18535505, + value: 0.18535505, + doubleSpentTxID: null, + isConfirmed: true, + confirmations: 242, + unconfirmedInput: false, }, { - 'txid': 'd8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196', - 'vout': 0, - 'scriptSig': { - 'asm': '30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', - 'hex': '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307' + txid: 'd8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196', + vout: 0, + scriptSig: { + asm: + '30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + hex: + '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', }, - 'sequence': 4294967295, - 'n': 1, - 'addr': 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', - 'valueMicros': 16419885, - 'value': 0.16419885, - 'doubleSpentTxID': null, - 'isConfirmed': true, - 'confirmations': 242, - 'unconfirmedInput': false - } + sequence: 4294967295, + n: 1, + addr: 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + valueMicros: 16419885, + value: 0.16419885, + doubleSpentTxID: null, + isConfirmed: true, + confirmations: 242, + unconfirmedInput: false, + }, ], - 'vout': [ + vout: [ { - 'value': '0.21247964', - 'n': 0, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a9144b7b335f978f130269fe661423258ae9642df8a188ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X' - ] + value: '0.21247964', + n: 0, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a9144b7b335f978f130269fe661423258ae9642df8a188ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X'], }, - 'spentTxId': null, - 'spentIndex': null, - 'spentHeight': null + spentTxId: null, + spentIndex: null, + spentHeight: null, }, { - 'value': '0.13677426', - 'n': 1, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f' - ] + value: '0.13677426', + n: 1, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f'], }, - 'spentTxId': '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec', - 'spentIndex': 1, - 'spentHeight': 10, - 'spentTs': 1440997099 - } + spentTxId: '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec', + spentIndex: 1, + spentHeight: 10, + spentTs: 1440997099, + }, ], - 'blockhash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', - 'blockheight': 533974, - 'confirmations': 230, - 'time': 1440987503, - 'blocktime': 1440987503, - 'valueOut': 0.3492539, - 'valueIn': 0.3495539, - 'fees': 0.0003 + blockhash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + blockheight: 533974, + confirmations: 230, + time: 1440987503, + blocktime: 1440987503, + valueOut: 0.3492539, + valueIn: 0.3495539, + fees: 0.0003, }; var spentTxId = '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec'; var spentIndex = 1; var detailedTransaction = { - hex: '7b5485d3628922f004f470f497f6a83f6df4df347e1bce15831a964623f8072b565f7c7bc5dcbc717c6e2a2301a2f6b4a19e65042ad88c9f5d037628de38603c4f137f625e135691e2bd0169cab74e1368abe858f3c3d116e9d13c4c85ead129d9edf0245a3fb1b35561bd230607dca0dcaf3cffc735a3982d8384a1ecc5d622a7bb4db8b5d47d061701978b1f45e2e39946d66c3394f8a20b8ac8c931a6786f761da2d0f3fa2c7c93edee9f2a94de7c47510498767c3d87afe68815bd6058710bf5d8c850a5d20fc217943d9c00da58a4908d92a0912578247746f2086e54cb7b81b6a9e3cc1741457e956d41bdeaae06c441db96ec39a2d17147dd8f468eeaeaaa78dc2e53d66188a791c46b2a4965639ad72a2b90ee52786e36db1a8cf924346b105a40b41a3027dae657782ef7e8b56d6da86062184cb5366d4886cd2ce27471d9d62d1df447f2e5a9641e1f8d1f2b628054d3bd915bf7932bcec6f2dd4965e2406b1dba445b5493ee475757de332618220318dd806b880a7364370c5c0c3b736a653f97b2901fdb5cf4b5b2230b09b2d7bd324a392633d51c598765f9bd286421239a1f25db34a9a61f645eb601e59f10fc1b', + hex: + '7b5485d3628922f004f470f497f6a83f6df4df347e1bce15831a964623f8072b565f7c7bc5dcbc717c6e2a2301a2f6b4a19e65042ad88c9f5d037628de38603c4f137f625e135691e2bd0169cab74e1368abe858f3c3d116e9d13c4c85ead129d9edf0245a3fb1b35561bd230607dca0dcaf3cffc735a3982d8384a1ecc5d622a7bb4db8b5d47d061701978b1f45e2e39946d66c3394f8a20b8ac8c931a6786f761da2d0f3fa2c7c93edee9f2a94de7c47510498767c3d87afe68815bd6058710bf5d8c850a5d20fc217943d9c00da58a4908d92a0912578247746f2086e54cb7b81b6a9e3cc1741457e956d41bdeaae06c441db96ec39a2d17147dd8f468eeaeaaa78dc2e53d66188a791c46b2a4965639ad72a2b90ee52786e36db1a8cf924346b105a40b41a3027dae657782ef7e8b56d6da86062184cb5366d4886cd2ce27471d9d62d1df447f2e5a9641e1f8d1f2b628054d3bd915bf7932bcec6f2dd4965e2406b1dba445b5493ee475757de332618220318dd806b880a7364370c5c0c3b736a653f97b2901fdb5cf4b5b2230b09b2d7bd324a392633d51c598765f9bd286421239a1f25db34a9a61f645eb601e59f10fc1b', hash: 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', version: 1, blockHash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', @@ -111,8 +112,10 @@ describe('Transactions', function() { prevTxId: '87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad', outputIndex: 0, sequence: 4294967295, - script: '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', - scriptAsm: '30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + script: + '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + scriptAsm: + '30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', micros: 18535505, }, { @@ -120,17 +123,19 @@ describe('Transactions', function() { prevTxId: 'd8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196', outputIndex: 0, sequence: 4294967295, - script: '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', - scriptAsm: '30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + script: + '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + scriptAsm: + '30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', micros: 16419885, - } + }, ], outputs: [ { micros: 21247964, script: '76a9144b7b335f978f130269fe661423258ae9642df8a188ac', scriptAsm: 'OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG', - address: 'mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X' + address: 'mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X', }, { address: 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', @@ -139,10 +144,10 @@ describe('Transactions', function() { script: '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac', spentTxId: spentTxId, spentIndex: spentIndex, - spentHeight: 10 - } + spentHeight: 10, + }, ], - locktime: 0 + locktime: 0, }; var todos = { @@ -150,45 +155,45 @@ describe('Transactions', function() { { isConfirmed: true, confirmations: 242, - unconfirmedInput: false + unconfirmedInput: false, }, { isConfirmed: true, confirmations: 242, - unconfirmedInput: false - } + unconfirmedInput: false, + }, ], vout: [ { scriptPubKey: { - reqSigs: 1 - } + reqSigs: 1, + }, }, { scriptPubKey: { - reqSigs: 1 + reqSigs: 1, }, - spentTs: 1440997099 - } - ] + spentTs: 1440997099, + }, + ], }; var node = { getDetailedTransaction: sinon.stub().callsArgWith(1, null, detailedTransaction), services: { meritd: { - height: 534203 + height: 534203, }, }, - network: 'testnet' + network: 'testnet', }; var transactions = new TxController(node); var txid = 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0'; var req = { params: { - txid: txid - } + txid: txid, + }, }; var res = {}; var next = function() { @@ -215,13 +220,14 @@ describe('Transactions', function() { txids: [ '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd', 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', - '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1' - ] + '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1', + ], }; var transactionDetails = { '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd': { - hex: '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2303d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000ffffffff01c018824a000000001976a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac00000000', + hex: + '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2303d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000ffffffff01c018824a000000001976a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac00000000', coinbase: true, version: 1, blockTimestamp: 1440987503, @@ -235,20 +241,21 @@ describe('Transactions', function() { inputs: [ { script: '03d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000', - sequence: 4294967295 - } + sequence: 4294967295, + }, ], outputs: [ { address: 'mq4oDPjmNWnBxbzx7qouzhpCSTMePUtYDF', script: '76a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac', scriptAsm: 'OP_DUP OP_HASH160 68bedce8982d25c3b6b03f6238cbad00378b8ead OP_EQUALVERIFY OP_CHECKSIG', - micros: 1250040000 - } - ] + micros: 1250040000, + }, + ], }, - 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0': { - hex: '0100000002ad5a14ae9d0f3221b790c4fc590fddceea1456e5692d8c4bf1ff7175f2b0c987000000008b4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff9621ac65bc22ea593ca9a61a8d63e461bf3d3f277989df5d3bd33ddfae0aa1d8000000008a4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff02dc374401000000001976a9144b7b335f978f130269fe661423258ae9642df8a188ac72b3d000000000001976a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac00000000', + b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0: { + hex: + '0100000002ad5a14ae9d0f3221b790c4fc590fddceea1456e5692d8c4bf1ff7175f2b0c987000000008b4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff9621ac65bc22ea593ca9a61a8d63e461bf3d3f277989df5d3bd33ddfae0aa1d8000000008a4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff02dc374401000000001976a9144b7b335f978f130269fe661423258ae9642df8a188ac72b3d000000000001976a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac00000000', inputMicros: 34955390, outputMicros: 34925390, feeMicros: 30000, @@ -262,28 +269,32 @@ describe('Transactions', function() { { micros: 18535505, address: 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', - script: '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', - scriptAsm: '30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + script: + '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + scriptAsm: + '30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', prevTxId: '87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad', outputIndex: 0, - sequence: 4294967295 + sequence: 4294967295, }, { address: 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', - script: '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', - scriptAsm: '30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + script: + '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + scriptAsm: + '30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', micros: 16419885, sequence: 4294967295, prevTxId: 'd8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196', - outputIndex: 0 - } + outputIndex: 0, + }, ], outputs: [ { address: 'mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X', script: '76a9144b7b335f978f130269fe661423258ae9642df8a188ac', scriptAsm: 'OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG', - micros: 21247964 + micros: 21247964, }, { script: '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac', @@ -292,12 +303,13 @@ describe('Transactions', function() { micros: 13677426, spentTxId: '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec', spentIndex: 1, - spentHeight: 200 - } - ] + spentHeight: 200, + }, + ], }, '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1': { - hex: '0100000002060d3cb6dfb7ffe85e2908010fea63190c9707e96fc7448128eb895b5e222771030000006b483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909dfeffffff7b2d8a8263cffbdb722e2a5c74166e6f2258634e277c0b08f51b578b667e2fba000000006a473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eeefeffffff02209a1d00000000001976a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac40420f00000000001976a914d0fce8f064cd1059a6a11501dd66fe42368572b088accb250800', + hex: + '0100000002060d3cb6dfb7ffe85e2908010fea63190c9707e96fc7448128eb895b5e222771030000006b483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909dfeffffff7b2d8a8263cffbdb722e2a5c74166e6f2258634e277c0b08f51b578b667e2fba000000006a473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eeefeffffff02209a1d00000000001976a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac40420f00000000001976a914d0fce8f064cd1059a6a11501dd66fe42368572b088accb250800', blockHash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', blockTimestamp: 1440987503, height: 533974, @@ -311,21 +323,25 @@ describe('Transactions', function() { { address: 'mgZK8zpudWoAaAwpLQSgc9t9PJJyEBpBdJ', micros: 990000, - script: '483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d', - scriptAsm: '3045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901 0346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d', + script: + '483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d', + scriptAsm: + '3045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901 0346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d', sequence: 4294967294, outputIndex: 3, - prevTxId: '7127225e5b89eb288144c76fe907970c1963ea0f0108295ee8ffb7dfb63c0d06' + prevTxId: '7127225e5b89eb288144c76fe907970c1963ea0f0108295ee8ffb7dfb63c0d06', }, { address: 'n4oM7bPuC4ZPdCEDvtw9xGYQC7jmi5S6F4', micros: 1960000, - script: '473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee', - scriptAsm: '3044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c01 03371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee', + script: + '473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee', + scriptAsm: + '3044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c01 03371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee', prevTxId: 'ba2f7e668b571bf5080b7c274e6358226f6e16745c2a2e72dbfbcf63828a2d7b', sequence: 4294967294, - outputIndex : 0 - } + outputIndex: 0, + }, ], outputs: [ { @@ -335,7 +351,7 @@ describe('Transactions', function() { micros: 1940000, script: '76a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac', scriptAsm: 'OP_DUP OP_HASH160 8e451eec7ca0a1764b4ab119274efdd2727b3c85 OP_EQUALVERIFY OP_CHECKSIG', - address: 'mtVD3tdifBNujYzZ5N7PgXfKk4Bc85tDKA' + address: 'mtVD3tdifBNujYzZ5N7PgXfKk4Bc85tDKA', }, { spentTxId: '418d3eb60275957b3456b96902e908abf962e71be4c4f09486564254664951bc', @@ -344,10 +360,10 @@ describe('Transactions', function() { script: '76a914d0fce8f064cd1059a6a11501dd66fe42368572b088ac', scriptAsm: 'OP_DUP OP_HASH160 d0fce8f064cd1059a6a11501dd66fe42368572b0 OP_EQUALVERIFY OP_CHECKSIG', address: 'mzZypShcs1B35udnkqeYeJy8rUdgHDDvKG', - micros: 1000000 - } - ] - } + micros: 1000000, + }, + ], + }, }; var node = { @@ -357,214 +373,212 @@ describe('Transactions', function() { }, services: { meritd: { - height: 534209 - } + height: 534209, + }, }, - network: 'testnet' + network: 'testnet', }; var transactions = new TxController(node); var insight = { - 'pagesTotal': 1, - 'txs': [ + pagesTotal: 1, + txs: [ { - 'txid': '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd', - 'version': 1, - 'locktime': 0, - 'vin': [ + txid: '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd', + version: 1, + locktime: 0, + vin: [ { - 'coinbase': '03d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000', - 'sequence': 4294967295, - 'n': 0 - } + coinbase: '03d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000', + sequence: 4294967295, + n: 0, + }, ], - 'vout': [ + vout: [ { - 'value': '12.50040000', - 'n': 0, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 68bedce8982d25c3b6b03f6238cbad00378b8ead OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'mq4oDPjmNWnBxbzx7qouzhpCSTMePUtYDF' - ] + value: '12.50040000', + n: 0, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 68bedce8982d25c3b6b03f6238cbad00378b8ead OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['mq4oDPjmNWnBxbzx7qouzhpCSTMePUtYDF'], }, - 'spentTxId': null, - 'spentIndex': null, - 'spentHeight': null - } + spentTxId: null, + spentIndex: null, + spentHeight: null, + }, ], - 'blockhash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', - 'blockheight': 533974, - 'confirmations': 236, - 'time': 1440987503, - 'blocktime': 1440987503, - 'isCoinBase': true, - 'valueOut': 12.5004, - 'fees': 0, - 'valueIn': 0, + blockhash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + blockheight: 533974, + confirmations: 236, + time: 1440987503, + blocktime: 1440987503, + isCoinBase: true, + valueOut: 12.5004, + fees: 0, + valueIn: 0, }, { - 'txid': 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', - 'version': 1, - 'locktime': 0, - 'vin': [ + txid: 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', + version: 1, + locktime: 0, + vin: [ { - 'txid': '87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad', - 'vout': 0, - 'scriptSig': { - 'asm': '30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', - 'hex': '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307' + txid: '87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad', + vout: 0, + scriptSig: { + asm: + '30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + hex: + '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', }, - 'sequence': 4294967295, - 'n': 0, - 'addr': 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', - 'valueMicros': 18535505, - 'value': 0.18535505, - 'doubleSpentTxID': null + sequence: 4294967295, + n: 0, + addr: 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + valueMicros: 18535505, + value: 0.18535505, + doubleSpentTxID: null, }, { - 'txid': 'd8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196', - 'vout': 0, - 'scriptSig': { - 'asm': '30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', - 'hex': '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307' + txid: 'd8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196', + vout: 0, + scriptSig: { + asm: + '30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + hex: + '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', }, - 'sequence': 4294967295, - 'n': 1, - 'addr': 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', - 'valueMicros': 16419885, - 'value': 0.16419885, - 'doubleSpentTxID': null - } + sequence: 4294967295, + n: 1, + addr: 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + valueMicros: 16419885, + value: 0.16419885, + doubleSpentTxID: null, + }, ], - 'vout': [ + vout: [ { - 'value': '0.21247964', - 'n': 0, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a9144b7b335f978f130269fe661423258ae9642df8a188ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X' - ] + value: '0.21247964', + n: 0, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a9144b7b335f978f130269fe661423258ae9642df8a188ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X'], }, - 'spentTxId': null, - 'spentIndex': null, - 'spentHeight': null + spentTxId: null, + spentIndex: null, + spentHeight: null, }, { - 'value': '0.13677426', - 'n': 1, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f' - ] + value: '0.13677426', + n: 1, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f'], }, - 'spentTxId': '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec', - 'spentIndex': 1, - 'spentHeight': 200, - 'spentTs': 1440997099 - } + spentTxId: '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec', + spentIndex: 1, + spentHeight: 200, + spentTs: 1440997099, + }, ], - 'blockhash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', - 'blockheight': 533974, - 'confirmations': 236, - 'time': 1440987503, - 'blocktime': 1440987503, - 'valueOut': 0.3492539, - 'valueIn': 0.3495539, - 'fees': 0.0003 + blockhash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + blockheight: 533974, + confirmations: 236, + time: 1440987503, + blocktime: 1440987503, + valueOut: 0.3492539, + valueIn: 0.3495539, + fees: 0.0003, }, { - 'txid': '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1', - 'version': 1, - 'locktime': 533963, - 'vin': [ + txid: '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1', + version: 1, + locktime: 533963, + vin: [ { - 'txid': '7127225e5b89eb288144c76fe907970c1963ea0f0108295ee8ffb7dfb63c0d06', - 'vout': 3, - 'scriptSig': { - 'asm': '3045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901 0346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d', - 'hex': '483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d' + txid: '7127225e5b89eb288144c76fe907970c1963ea0f0108295ee8ffb7dfb63c0d06', + vout: 3, + scriptSig: { + asm: + '3045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901 0346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d', + hex: + '483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d', }, - 'sequence': 4294967294, - 'n': 0, - 'addr': 'mgZK8zpudWoAaAwpLQSgc9t9PJJyEBpBdJ', - 'valueMicros': 990000, - 'value': 0.0099, - 'doubleSpentTxID': null + sequence: 4294967294, + n: 0, + addr: 'mgZK8zpudWoAaAwpLQSgc9t9PJJyEBpBdJ', + valueMicros: 990000, + value: 0.0099, + doubleSpentTxID: null, }, { - 'txid': 'ba2f7e668b571bf5080b7c274e6358226f6e16745c2a2e72dbfbcf63828a2d7b', - 'vout': 0, - 'scriptSig': { - 'asm': '3044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c01 03371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee', - 'hex': '473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee' + txid: 'ba2f7e668b571bf5080b7c274e6358226f6e16745c2a2e72dbfbcf63828a2d7b', + vout: 0, + scriptSig: { + asm: + '3044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c01 03371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee', + hex: + '473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee', }, - 'sequence': 4294967294, - 'n': 1, - 'addr': 'n4oM7bPuC4ZPdCEDvtw9xGYQC7jmi5S6F4', - 'valueMicros': 1960000, - 'value': 0.0196, - 'doubleSpentTxID': null - } + sequence: 4294967294, + n: 1, + addr: 'n4oM7bPuC4ZPdCEDvtw9xGYQC7jmi5S6F4', + valueMicros: 1960000, + value: 0.0196, + doubleSpentTxID: null, + }, ], - 'vout': [ + vout: [ { - 'value': '0.01940000', - 'n': 0, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 8e451eec7ca0a1764b4ab119274efdd2727b3c85 OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'mtVD3tdifBNujYzZ5N7PgXfKk4Bc85tDKA' - ] + value: '0.01940000', + n: 0, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 8e451eec7ca0a1764b4ab119274efdd2727b3c85 OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['mtVD3tdifBNujYzZ5N7PgXfKk4Bc85tDKA'], }, - 'spentTxId': '9a213b879da9073a9a30606f9046f35f36f268cbf03f6242993a97c4c07c00b9', - 'spentIndex': 1, - 'spentHeight': 200, - 'spentTs': 1440992946 + spentTxId: '9a213b879da9073a9a30606f9046f35f36f268cbf03f6242993a97c4c07c00b9', + spentIndex: 1, + spentHeight: 200, + spentTs: 1440992946, }, { - 'value': '0.01000000', - 'n': 1, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 d0fce8f064cd1059a6a11501dd66fe42368572b0 OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a914d0fce8f064cd1059a6a11501dd66fe42368572b088ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'mzZypShcs1B35udnkqeYeJy8rUdgHDDvKG' - ] + value: '0.01000000', + n: 1, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 d0fce8f064cd1059a6a11501dd66fe42368572b0 OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a914d0fce8f064cd1059a6a11501dd66fe42368572b088ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['mzZypShcs1B35udnkqeYeJy8rUdgHDDvKG'], }, - 'spentTxId': '418d3eb60275957b3456b96902e908abf962e71be4c4f09486564254664951bc', - 'spentIndex': 34, - 'spentHeight': 200, - 'spentTs': 1440999118 - } + spentTxId: '418d3eb60275957b3456b96902e908abf962e71be4c4f09486564254664951bc', + spentIndex: 34, + spentHeight: 200, + spentTs: 1440999118, + }, ], - 'blockhash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', - 'blockheight': 533974, - 'confirmations': 236, - 'time': 1440987503, - 'blocktime': 1440987503, - 'valueOut': 0.0294, - 'valueIn': 0.0295, - 'fees': 0.0001 - } - ] + blockhash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + blockheight: 533974, + confirmations: 236, + time: 1440987503, + blocktime: 1440987503, + valueOut: 0.0294, + valueIn: 0.0295, + fees: 0.0001, + }, + ], }; var todos = { @@ -573,53 +587,51 @@ describe('Transactions', function() { vout: [ { scriptPubKey: { - reqSigs: 1 - } - } - ] + reqSigs: 1, + }, + }, + ], }, { - vin: [ - ], + vin: [], vout: [ { scriptPubKey: { - reqSigs: 1 - } + reqSigs: 1, + }, }, { scriptPubKey: { - reqSigs: 1 + reqSigs: 1, }, - spentTs: 1440997099 - } - ] + spentTs: 1440997099, + }, + ], }, { - vin: [ - ], + vin: [], vout: [ { scriptPubKey: { - reqSigs: 1 + reqSigs: 1, }, - spentTs: 1440992946 + spentTs: 1440992946, }, { scriptPubKey: { - reqSigs: 1 + reqSigs: 1, }, - spentTs: 1440999118 - } - ] - } - ] + spentTs: 1440999118, + }, + ], + }, + ], }; var req = { query: { - block: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7' - } + block: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + }, }; var res = { @@ -627,17 +639,17 @@ describe('Transactions', function() { _.merge(data, todos); should(data).eql(insight); done(); - } + }, }; transactions.list(req, res); }); it('by address', function(done) { - var txinfos = [ { tx: { - hex: '010000000125c46caa6d839435b43c20d6d48978e677841244b37a09f6f6cd29bfaf5b5eea010000006b483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6feffffff02a913dda5000000001976a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac809fd500000000001976a9149713201957f42379e574d7c70d506ee49c2c8ad688ac49260800', + hex: + '010000000125c46caa6d839435b43c20d6d48978e677841244b37a09f6f6cd29bfaf5b5eea010000006b483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6feffffff02a913dda5000000001976a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac809fd500000000001976a9149713201957f42379e574d7c70d506ee49c2c8ad688ac49260800', hash: 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', version: 1, inputs: [ @@ -645,35 +657,38 @@ describe('Transactions', function() { prevTxId: 'ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425', outputIndex: 1, sequence: 4294967294, - script: '483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', - scriptAsm: '3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', + script: + '483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', + scriptAsm: + '3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', micros: 2796764565, - address: 'msyjRQQ88MabQmyafpKCjBHUwuJ49tVjcb' - } + address: 'msyjRQQ88MabQmyafpKCjBHUwuJ49tVjcb', + }, ], outputs: [ { micros: 2782729129, address: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', script: '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac', - scriptAsm: 'OP_DUP OP_HASH160 3583efb5e64a4668c6c54bb5fcc30af4417b4f2d OP_EQUALVERIFY OP_CHECKSIG' + scriptAsm: 'OP_DUP OP_HASH160 3583efb5e64a4668c6c54bb5fcc30af4417b4f2d OP_EQUALVERIFY OP_CHECKSIG', }, { micros: 14000000, address: 'muHmEsjhjmATf9i3T9gHyeQoce9LXe2dWz', script: '76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac', - scriptAsm: 'OP_DUP OP_HASH160 9713201957f42379e574d7c70d506ee49c2c8ad6 OP_EQUALVERIFY OP_CHECKSIG' - } + scriptAsm: 'OP_DUP OP_HASH160 9713201957f42379e574d7c70d506ee49c2c8ad6 OP_EQUALVERIFY OP_CHECKSIG', + }, ], inputMicros: 2796764565, outputMicros: 2796729129, feeMicros: 35436, - locktime: 534089 - } + locktime: 534089, + }, }, { tx: { - hex: '0100000001c7f1230d689647ccbff2aae4ddeeccf26aa8836fea709552c9fa0962b9c30ebb000000006a47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24feffffff02bce0c9a4000000001976a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac80a81201000000001976a914011d2963b619186a318f768dddfd98cd553912a088ac53260800', + hex: + '0100000001c7f1230d689647ccbff2aae4ddeeccf26aa8836fea709552c9fa0962b9c30ebb000000006a47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24feffffff02bce0c9a4000000001976a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac80a81201000000001976a914011d2963b619186a318f768dddfd98cd553912a088ac53260800', hash: '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', version: 1, inputs: [ @@ -681,38 +696,40 @@ describe('Transactions', function() { prevTxId: 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', outputIndex: 0, sequence: 4294967294, - script: '47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', - scriptAsm: '304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', + script: + '47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', + scriptAsm: + '304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', micros: 2782729129, - address: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er' - } + address: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', + }, ], outputs: [ { micros: 2764693692, address: 'moSPsU4p2C2gssiniJ1JNH4fB9xs633tLv', script: '76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac', - scriptAsm: 'OP_DUP OP_HASH160 56e446bc3489543d8324c6d0271524c0bd0506dd OP_EQUALVERIFY OP_CHECKSIG' + scriptAsm: 'OP_DUP OP_HASH160 56e446bc3489543d8324c6d0271524c0bd0506dd OP_EQUALVERIFY OP_CHECKSIG', }, { micros: 18000000, scriptAsm: 'OP_DUP OP_HASH160 011d2963b619186a318f768dddfd98cd553912a0 OP_EQUALVERIFY OP_CHECKSIG', script: '76a914011d2963b619186a318f768dddfd98cd553912a088ac', address: 'mfcquSAitCkUKXaYRZTRZQDfUegnL3kDew', - spentTxId: '71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed' - } + spentTxId: '71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed', + }, ], inputMicros: 2782729129, outputMicros: 2782693692, feeMicros: 35437, - locktime: 534099 - } - } + locktime: 534099, + }, + }, ]; var historyResult = { totalCount: txinfos.length, - items: txinfos + items: txinfos, }; txinfos[0].tx.blockHash = '00000000000001001aba15de213648f370607fb048288dd27b96f7e833a73520'; @@ -739,191 +756,185 @@ describe('Transactions', function() { getAddressHistory: sinon.stub().callsArgWith(2, null, historyResult), services: { meritd: { - height: 534223 - } + height: 534223, + }, }, - network: 'testnet' + network: 'testnet', }; var insight = { - 'pagesTotal': 1, - 'txs': [ + pagesTotal: 1, + txs: [ { - 'txid': 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', - 'version': 1, - 'locktime': 534089, - 'vin': [ + txid: 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + version: 1, + locktime: 534089, + vin: [ { - 'txid': 'ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425', - 'vout': 1, - 'scriptSig': { - 'asm': '3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', - 'hex': '483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6' + txid: 'ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425', + vout: 1, + scriptSig: { + asm: + '3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', + hex: + '483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', }, - 'sequence': 4294967294, - 'n': 0, - 'addr': 'msyjRQQ88MabQmyafpKCjBHUwuJ49tVjcb', - 'valueMicros': 2796764565, - 'value': 27.96764565, - 'doubleSpentTxID': null - } + sequence: 4294967294, + n: 0, + addr: 'msyjRQQ88MabQmyafpKCjBHUwuJ49tVjcb', + valueMicros: 2796764565, + value: 27.96764565, + doubleSpentTxID: null, + }, ], - 'vout': [ + vout: [ { - 'value': '27.82729129', - 'n': 0, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 3583efb5e64a4668c6c54bb5fcc30af4417b4f2d OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er' - ] + value: '27.82729129', + n: 0, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 3583efb5e64a4668c6c54bb5fcc30af4417b4f2d OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er'], }, - 'spentTxId': '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', - 'spentIndex': 0, - 'spentHeight': 199, - 'spentTs': 1441072817 + spentTxId: '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', + spentIndex: 0, + spentHeight: 199, + spentTs: 1441072817, }, { - 'value': '0.14000000', - 'n': 1, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 9713201957f42379e574d7c70d506ee49c2c8ad6 OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'muHmEsjhjmATf9i3T9gHyeQoce9LXe2dWz' - ] + value: '0.14000000', + n: 1, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 9713201957f42379e574d7c70d506ee49c2c8ad6 OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['muHmEsjhjmATf9i3T9gHyeQoce9LXe2dWz'], }, - 'spentTxId': null, - 'spentIndex': null, - 'spentHeight': null - } + spentTxId: null, + spentIndex: null, + spentHeight: null, + }, ], - 'blockhash': '00000000000001001aba15de213648f370607fb048288dd27b96f7e833a73520', - 'blockheight': 534105, - 'confirmations': 119, - 'time': 1441068774, - 'blocktime': 1441068774, - 'valueOut': 27.96729129, - 'valueIn': 27.96764565, - 'fees': 0.00035436 + blockhash: '00000000000001001aba15de213648f370607fb048288dd27b96f7e833a73520', + blockheight: 534105, + confirmations: 119, + time: 1441068774, + blocktime: 1441068774, + valueOut: 27.96729129, + valueIn: 27.96764565, + fees: 0.00035436, }, { - 'txid': '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', - 'version': 1, - 'locktime': 534099, - 'vin': [ + txid: '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', + version: 1, + locktime: 534099, + vin: [ { - 'txid': 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', - 'vout': 0, - 'scriptSig': { - 'asm': '304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', - 'hex': '47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24' + txid: 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + vout: 0, + scriptSig: { + asm: + '304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', + hex: + '47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', }, - 'sequence': 4294967294, - 'n': 0, - 'addr': 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', - 'valueMicros': 2782729129, - 'value': 27.82729129, - 'doubleSpentTxID': null - } + sequence: 4294967294, + n: 0, + addr: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', + valueMicros: 2782729129, + value: 27.82729129, + doubleSpentTxID: null, + }, ], - 'vout': [ + vout: [ { - 'value': '27.64693692', - 'n': 0, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 56e446bc3489543d8324c6d0271524c0bd0506dd OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'moSPsU4p2C2gssiniJ1JNH4fB9xs633tLv' - ] + value: '27.64693692', + n: 0, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 56e446bc3489543d8324c6d0271524c0bd0506dd OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['moSPsU4p2C2gssiniJ1JNH4fB9xs633tLv'], }, - 'spentTxId': '661194e5533a395ce9076f292b7e0fb28fe94cd8832a81b4aa0517ff58c1ddd2', - 'spentIndex': 0, - 'spentHeight': 134, - 'spentTs': 1441077236 + spentTxId: '661194e5533a395ce9076f292b7e0fb28fe94cd8832a81b4aa0517ff58c1ddd2', + spentIndex: 0, + spentHeight: 134, + spentTs: 1441077236, }, { - 'value': '0.18000000', - 'n': 1, - 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 011d2963b619186a318f768dddfd98cd553912a0 OP_EQUALVERIFY OP_CHECKSIG', - 'hex': '76a914011d2963b619186a318f768dddfd98cd553912a088ac', - 'reqSigs': 1, - 'type': 'pubkeyhash', - 'addresses': [ - 'mfcquSAitCkUKXaYRZTRZQDfUegnL3kDew' - ] + value: '0.18000000', + n: 1, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 011d2963b619186a318f768dddfd98cd553912a0 OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a914011d2963b619186a318f768dddfd98cd553912a088ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: ['mfcquSAitCkUKXaYRZTRZQDfUegnL3kDew'], }, - 'spentTxId': '71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed', - 'spentIndex': 0, - 'spentHeight': 112, - 'spentTs': 1441069523 - } + spentTxId: '71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed', + spentIndex: 0, + spentHeight: 112, + spentTs: 1441069523, + }, ], - 'blockhash': '0000000000000a3acc1f7fe72917eb48bb319ed96c125a6dfcc0ba6acab3c4d0', - 'blockheight': 534110, - 'confirmations': 114, - 'time': 1441072817, - 'blocktime': 1441072817, - 'valueOut': 27.82693692, - 'valueIn': 27.82729129, - 'fees': 0.00035437 - } - ] + blockhash: '0000000000000a3acc1f7fe72917eb48bb319ed96c125a6dfcc0ba6acab3c4d0', + blockheight: 534110, + confirmations: 114, + time: 1441072817, + blocktime: 1441072817, + valueOut: 27.82693692, + valueIn: 27.82729129, + fees: 0.00035437, + }, + ], }; var todos = { - 'txs': [ + txs: [ { - 'vin': [ - ], - 'vout': [ + vin: [], + vout: [ { - 'scriptPubKey': { - 'reqSigs': 1 + scriptPubKey: { + reqSigs: 1, }, - 'spentTs': 1441072817 + spentTs: 1441072817, }, { - 'scriptPubKey': { - 'reqSigs': 1 - } - } - ] + scriptPubKey: { + reqSigs: 1, + }, + }, + ], }, { - 'vin': [ - ], - 'vout': [ + vin: [], + vout: [ { - 'scriptPubKey': { - 'reqSigs': 1 + scriptPubKey: { + reqSigs: 1, }, - 'spentTs': 1441077236 + spentTs: 1441077236, }, { - 'scriptPubKey': { - 'reqSigs': 1 + scriptPubKey: { + reqSigs: 1, }, - 'spentTs': 1441069523 - } - ] - } - ] + spentTs: 1441069523, + }, + ], + }, + ], }; var req = { query: { - address: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er' - } + address: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', + }, }; var res = { @@ -931,7 +942,7 @@ describe('Transactions', function() { var merged = _.merge(data, todos); should(merged).eql(insight); done(); - } + }, }; var transactions = new TxController(node); @@ -941,10 +952,11 @@ describe('Transactions', function() { describe('/rawtx/:txid', function() { it('should give the correct data', function(done) { - var hex = '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2303d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000ffffffff01c018824a000000001976a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac00000000'; + var hex = + '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2303d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000ffffffff01c018824a000000001976a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac00000000'; var node = { - getTransaction: sinon.stub().callsArgWith(1, null, meritcore.Transaction().fromBuffer(new Buffer(hex, 'hex'))) + getTransaction: sinon.stub().callsArgWith(1, null, meritcore.Transaction().fromBuffer(new Buffer(hex, 'hex'))), }; var transactions = new TxController(node); @@ -952,8 +964,8 @@ describe('Transactions', function() { var res = {}; var req = { params: { - txid: txid - } + txid: txid, + }, }; var next = function() { should(req.rawTransaction.rawtx).eql(hex); @@ -967,24 +979,25 @@ describe('Transactions', function() { describe('#transformInvTransaction', function() { it('should give the correct data', function() { var insight = { - 'txid': 'a15a7c257af596704390d345ff3ea2eed4cd02ce8bfb8afb700bff82257e49fb', - 'valueOut': 0.02038504, - 'vout': [ + txid: 'a15a7c257af596704390d345ff3ea2eed4cd02ce8bfb8afb700bff82257e49fb', + valueOut: 0.02038504, + vout: [ { - '3DQYCLG6rZdtV2Xw8y4YtozZjNHYoKsLuo': 45000 + '3DQYCLG6rZdtV2Xw8y4YtozZjNHYoKsLuo': 45000, }, { - '12WvZmssxT85f81dD6wcmWznxbnFkEpNMS': 1993504 - } + '12WvZmssxT85f81dD6wcmWznxbnFkEpNMS': 1993504, + }, ], - 'isRBF': false + isRBF: false, }; - var rawTx = '01000000011760bc271a397bfb65b7506d430d96ebb1faff467ed957516238a9670e806a86010000006b483045022100f0056ae68a34cdb4194d424bd727c18f82653bca2a198e0d55ab6b4ee88bbdb902202a5745af4f72a5dbdca1e3d683af4667728a8b20e8001e0f8308a4d329ce3f96012102f3af6e66b61c9d99c74d9a9c3c1bec014a8c05d28bf339c8f5f395b5ce319e7dffffffff02c8af00000000000017a9148083b541ea15f1d18c5ca5e1fd47f9035cce24ed87206b1e00000000001976a91410a0e70cd91a45e0e6e409e227ab285bd61592b188ac00000000'; + var rawTx = + '01000000011760bc271a397bfb65b7506d430d96ebb1faff467ed957516238a9670e806a86010000006b483045022100f0056ae68a34cdb4194d424bd727c18f82653bca2a198e0d55ab6b4ee88bbdb902202a5745af4f72a5dbdca1e3d683af4667728a8b20e8001e0f8308a4d329ce3f96012102f3af6e66b61c9d99c74d9a9c3c1bec014a8c05d28bf339c8f5f395b5ce319e7dffffffff02c8af00000000000017a9148083b541ea15f1d18c5ca5e1fd47f9035cce24ed87206b1e00000000001976a91410a0e70cd91a45e0e6e409e227ab285bd61592b188ac00000000'; var tx = meritcore.Transaction().fromBuffer(new Buffer(rawTx, 'hex')); var node = { - network: meritcore.Networks.livenet + network: meritcore.Networks.livenet, }; var transactions = new TxController(node); @@ -994,21 +1007,22 @@ describe('Transactions', function() { }); it('will not include null values in vout array', function() { var insight = { - 'txid': '716d54157c31e52c820494c6c2b8af1b64352049f4dcc80632aa15742a7f82c4', - 'valueOut': 12.5002, - 'vout': [ + txid: '716d54157c31e52c820494c6c2b8af1b64352049f4dcc80632aa15742a7f82c4', + valueOut: 12.5002, + vout: [ { - 'n4eY3qiP9pi32MWC6FcJFHciSsfNiYFYgR': 12.5002 * 1e8 - } + n4eY3qiP9pi32MWC6FcJFHciSsfNiYFYgR: 12.5002 * 1e8, + }, ], - 'isRBF': false + isRBF: false, }; - var rawTx = '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0403ebc108ffffffff04a0ca814a000000001976a914fdb9fb622b0db8d9121475a983288a0876f4de4888ac0000000000000000226a200000000000000000000000000000000000000000000000000000ffff0000000000000000000000001b6a1976a914fdb9fb622b0db8d9121475a983288a0876f4de4888ac0000000000000000326a303a791c8e85200500d89769b4f958e4db6b3ec388ddaa30233c4517d942d440c24ae903bff40d97ca06465fcf2714000000000000'; + var rawTx = + '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0403ebc108ffffffff04a0ca814a000000001976a914fdb9fb622b0db8d9121475a983288a0876f4de4888ac0000000000000000226a200000000000000000000000000000000000000000000000000000ffff0000000000000000000000001b6a1976a914fdb9fb622b0db8d9121475a983288a0876f4de4888ac0000000000000000326a303a791c8e85200500d89769b4f958e4db6b3ec388ddaa30233c4517d942d440c24ae903bff40d97ca06465fcf2714000000000000'; var tx = meritcore.Transaction().fromBuffer(new Buffer(rawTx, 'hex')); var node = { - network: meritcore.Networks.testnet + network: meritcore.Networks.testnet, }; var transactions = new TxController(node); @@ -1019,16 +1033,19 @@ describe('Transactions', function() { it('should detect RBF txs', function() { var testCases = [ { - rawTx: '01000000017fa897c3556271c34cb28c03c196c2d912093264c9d293cb4980a2635474467d010000000f5355540b6f93598893578893588851ffffffff01501e0000000000001976a914aa2482ce71d219018ef334f6cc551ee88abd920888ac00000000', + rawTx: + '01000000017fa897c3556271c34cb28c03c196c2d912093264c9d293cb4980a2635474467d010000000f5355540b6f93598893578893588851ffffffff01501e0000000000001976a914aa2482ce71d219018ef334f6cc551ee88abd920888ac00000000', expected: false, - }, { - rawTx: '01000000017fa897c3556271c34cb28c03c196c2d912093264c9d293cb4980a2635474467d010000000f5355540b6f935988935788935888510000000001501e0000000000001976a914aa2482ce71d219018ef334f6cc551ee88abd920888ac00000000', + }, + { + rawTx: + '01000000017fa897c3556271c34cb28c03c196c2d912093264c9d293cb4980a2635474467d010000000f5355540b6f935988935788935888510000000001501e0000000000001976a914aa2482ce71d219018ef334f6cc551ee88abd920888ac00000000', expected: true, }, ]; var node = { - network: meritcore.Networks.livenet + network: meritcore.Networks.livenet, }; var transactions = new TxController(node); @@ -1040,6 +1057,5 @@ describe('Transactions', function() { result.isRBF.should.equal(tc.expected); }); }); - }); }); diff --git a/packages/insight-api/test/utils.js b/packages/insight-api/test/utils.js index 68eea413e5..8603ddc566 100644 --- a/packages/insight-api/test/utils.js +++ b/packages/insight-api/test/utils.js @@ -11,29 +11,29 @@ describe('Utils', function() { services: { meritd: { estimateFee: function(blocks, callback) { - switch(blocks) { - case 1: - return callback(null, 1000 / 1e8); - case 3: - return callback(null, 3000 / 1e8); + switch (blocks) { + case 1: + return callback(null, 1000 / 1e8); + case 3: + return callback(null, 3000 / 1e8); } - } - } - } + }, + }, + }, }; var utils = new UtilsController(node); var req = { query: { - nbBlocks: '1, 3' - } + nbBlocks: '1, 3', + }, }; var res = { jsonp: function(fees) { - should(fees).eql({1: 0.00001, 3: 0.00003}); + should(fees).eql({ 1: 0.00001, 3: 0.00003 }); done(); - } + }, }; utils.estimateFee(req, res); }); diff --git a/packages/insight-ui/public/src/js/config.js b/packages/insight-ui/public/src/js/config.js index a8629caa95..8d183c13a5 100644 --- a/packages/insight-ui/public/src/js/config.js +++ b/packages/insight-ui/public/src/js/config.js @@ -2,55 +2,56 @@ //Setting up route angular.module('insight').config(function($routeProvider) { - $routeProvider. - when('/block/:blockHash', { + $routeProvider + .when('/block/:blockHash', { templateUrl: 'views/block.html', - title: 'Merit Block ' - }). - when('/block-index/:blockHeight', { + title: 'Merit Block ', + }) + .when('/block-index/:blockHeight', { controller: 'BlocksController', - templateUrl: 'views/redirect.html' - }). - when('/tx/send', { + templateUrl: 'views/redirect.html', + }) + .when('/tx/send', { templateUrl: 'views/transaction_sendraw.html', - title: 'Broadcast Raw Transaction' - }). - when('/tx/:txId/:v_type?/:v_index?', { + title: 'Broadcast Raw Transaction', + }) + .when('/tx/:txId/:v_type?/:v_index?', { templateUrl: 'views/transaction.html', - title: 'Merit Transaction ' - }). - when('/', { + title: 'Merit Transaction ', + }) + .when('/', { templateUrl: 'views/index.html', - title: 'Home' - }). - when('/blocks', { + title: 'Home', + }) + .when('/blocks', { templateUrl: 'views/block_list.html', - title: 'Merit Blocks solved Today' - }). - when('/blocks-date/:blockDate/:startTimestamp?', { + title: 'Merit Blocks solved Today', + }) + .when('/blocks-date/:blockDate/:startTimestamp?', { templateUrl: 'views/block_list.html', - title: 'Merit Blocks solved ' - }). - when('/address/:addrStr', { + title: 'Merit Blocks solved ', + }) + .when('/address/:addrStr', { templateUrl: 'views/address.html', - title: 'Merit Address ' - }). - when('/status', { + title: 'Merit Address ', + }) + .when('/status', { templateUrl: 'views/status.html', - title: 'Status' - }). - when('/messages/verify', { + title: 'Status', + }) + .when('/messages/verify', { templateUrl: 'views/messages_verify.html', - title: 'Verify Message' + title: 'Verify Message', }) .otherwise({ templateUrl: 'views/404.html', - title: 'Error' + title: 'Error', }); }); //Setting HTML5 Location Mode -angular.module('insight') +angular + .module('insight') .config(function($locationProvider) { $locationProvider.html5Mode(true); $locationProvider.hashPrefix('!'); diff --git a/packages/insight-ui/public/src/js/controllers/address.js b/packages/insight-ui/public/src/js/controllers/address.js index 8ac054dead..2633f892d0 100644 --- a/packages/insight-ui/public/src/js/controllers/address.js +++ b/packages/insight-ui/public/src/js/controllers/address.js @@ -1,7 +1,8 @@ 'use strict'; -angular.module('insight.address').controller('AddressController', - function($scope, $rootScope, $routeParams, $location, Global, Address, getSocket) { +angular + .module('insight.address') + .controller('AddressController', function($scope, $rootScope, $routeParams, $location, Global, Address, getSocket) { $scope.global = Global; var socket = getSocket($scope); @@ -19,7 +20,7 @@ angular.module('insight.address').controller('AddressController', socket.emit('subscribe', 'meritd/addresstxid', [addrStr]); }; - var _stopSocket = function () { + var _stopSocket = function() { socket.emit('unsubscribe', 'meritd/addresstxid', [addrStr]); }; @@ -27,7 +28,7 @@ angular.module('insight.address').controller('AddressController', _startSocket(); }); - $scope.$on('$destroy', function(){ + $scope.$on('$destroy', function() { _stopSocket(); }); @@ -37,8 +38,9 @@ angular.module('insight.address').controller('AddressController', $rootScope.currentAddr = $routeParams.addrStr; _startSocket(); - Address.get({ - addrStr: $routeParams.addrStr + Address.get( + { + addrStr: $routeParams.addrStr, }, function(address) { $rootScope.titleDetail = address.addrStr.substring(0, 7) + '...'; @@ -54,7 +56,7 @@ angular.module('insight.address').controller('AddressController', $rootScope.flashMessage = 'Address Not Found'; } $location.path('/'); - }); + }, + ); }; - }); diff --git a/packages/insight-ui/public/src/js/controllers/scanner.js b/packages/insight-ui/public/src/js/controllers/scanner.js index c1f61d2d84..83872dc10f 100644 --- a/packages/insight-ui/public/src/js/controllers/scanner.js +++ b/packages/insight-ui/public/src/js/controllers/scanner.js @@ -1,149 +1,149 @@ 'use strict'; -angular.module('insight.system').controller('ScannerController', - function($scope, $rootScope, $modalInstance, Global) { - $scope.global = Global; - - // Detect mobile devices - var isMobile = { - Android: function() { - return navigator.userAgent.match(/Android/i); - }, - BlackBerry: function() { - return navigator.userAgent.match(/BlackBerry/i); - }, - iOS: function() { - return navigator.userAgent.match(/iPhone|iPad|iPod/i); - }, - Opera: function() { - return navigator.userAgent.match(/Opera Mini/i); - }, - Windows: function() { - return navigator.userAgent.match(/IEMobile/i); - }, - any: function() { - return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows()); +angular.module('insight.system').controller('ScannerController', function($scope, $rootScope, $modalInstance, Global) { + $scope.global = Global; + + // Detect mobile devices + var isMobile = { + Android: function() { + return navigator.userAgent.match(/Android/i); + }, + BlackBerry: function() { + return navigator.userAgent.match(/BlackBerry/i); + }, + iOS: function() { + return navigator.userAgent.match(/iPhone|iPad|iPod/i); + }, + Opera: function() { + return navigator.userAgent.match(/Opera Mini/i); + }, + Windows: function() { + return navigator.userAgent.match(/IEMobile/i); + }, + any: function() { + return isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows(); + }, + }; + + navigator.getUserMedia = + navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; + window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL; + + $scope.isMobile = isMobile.any(); + $scope.scannerLoading = false; + + var $searchInput = angular.element(document.getElementById('search')), + cameraInput, + video, + canvas, + $video, + context, + localMediaStream; + + var _scan = function(evt) { + if ($scope.isMobile) { + $scope.scannerLoading = true; + var files = evt.target.files; + + if (files.length === 1 && files[0].type.indexOf('image/') === 0) { + var file = files[0]; + + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(e) { + var mpImg = new MegaPixImage(file); + mpImg.render(canvas, { maxWidth: 200, maxHeight: 200, orientation: 6 }); + + setTimeout(function() { + qrcode.width = canvas.width; + qrcode.height = canvas.height; + qrcode.imagedata = context.getImageData(0, 0, qrcode.width, qrcode.height); + + try { + //alert(JSON.stringify(qrcode.process(context))); + qrcode.decode(); + } catch (e) { + alert(e); + } + }, 1500); + }; + })(file); + + // Read in the file as a data URL + reader.readAsDataURL(file); + } + } else { + if (localMediaStream) { + context.drawImage(video, 0, 0, 300, 225); + + try { + qrcode.decode(); + } catch (e) { + //qrcodeError(e); + } } - }; - navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; - window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL; + setTimeout(_scan, 500); + } + }; - $scope.isMobile = isMobile.any(); - $scope.scannerLoading = false; + var _successCallback = function(stream) { + video.src = (window.URL && window.URL.createObjectURL(stream)) || stream; + localMediaStream = stream; + video.play(); + setTimeout(_scan, 1000); + }; - var $searchInput = angular.element(document.getElementById('search')), - cameraInput, - video, - canvas, - $video, - context, - localMediaStream; + var _scanStop = function() { + $scope.scannerLoading = false; + $modalInstance.close(); + if (!$scope.isMobile) { + if (localMediaStream.stop) localMediaStream.stop(); + localMediaStream = null; + video.src = ''; + } + }; + + var _videoError = function(err) { + console.log('Video Error: ' + JSON.stringify(err)); + _scanStop(); + }; + + qrcode.callback = function(data) { + _scanStop(); + + var str = data.indexOf('merit:') === 0 ? data.substring(8) : data; + console.log('QR code detected: ' + str); + $searchInput + .val(str) + .triggerHandler('change') + .triggerHandler('submit'); + }; + + $scope.cancel = function() { + _scanStop(); + }; + + $modalInstance.opened.then(function() { + $rootScope.isCollapsed = true; + + // Start the scanner + setTimeout(function() { + canvas = document.getElementById('qr-canvas'); + context = canvas.getContext('2d'); - var _scan = function(evt) { if ($scope.isMobile) { - $scope.scannerLoading = true; - var files = evt.target.files; - - if (files.length === 1 && files[0].type.indexOf('image/') === 0) { - var file = files[0]; - - var reader = new FileReader(); - reader.onload = (function(theFile) { - return function(e) { - var mpImg = new MegaPixImage(file); - mpImg.render(canvas, { maxWidth: 200, maxHeight: 200, orientation: 6 }); - - setTimeout(function() { - qrcode.width = canvas.width; - qrcode.height = canvas.height; - qrcode.imagedata = context.getImageData(0, 0, qrcode.width, qrcode.height); - - try { - //alert(JSON.stringify(qrcode.process(context))); - qrcode.decode(); - } catch (e) { - alert(e); - } - }, 1500); - }; - })(file); - - // Read in the file as a data URL - reader.readAsDataURL(file); - } + cameraInput = document.getElementById('qrcode-camera'); + cameraInput.addEventListener('change', _scan, false); } else { - if (localMediaStream) { - context.drawImage(video, 0, 0, 300, 225); - - try { - qrcode.decode(); - } catch(e) { - //qrcodeError(e); - } - } + video = document.getElementById('qrcode-scanner-video'); + $video = angular.element(video); + canvas.width = 300; + canvas.height = 225; + context.clearRect(0, 0, 300, 225); - setTimeout(_scan, 500); + navigator.getUserMedia({ video: true }, _successCallback, _videoError); } - }; - - var _successCallback = function(stream) { - video.src = (window.URL && window.URL.createObjectURL(stream)) || stream; - localMediaStream = stream; - video.play(); - setTimeout(_scan, 1000); - }; - - var _scanStop = function() { - $scope.scannerLoading = false; - $modalInstance.close(); - if (!$scope.isMobile) { - if (localMediaStream.stop) localMediaStream.stop(); - localMediaStream = null; - video.src = ''; - } - }; - - var _videoError = function(err) { - console.log('Video Error: ' + JSON.stringify(err)); - _scanStop(); - }; - - qrcode.callback = function(data) { - _scanStop(); - - var str = (data.indexOf('merit:') === 0) ? data.substring(8) : data; - console.log('QR code detected: ' + str); - $searchInput - .val(str) - .triggerHandler('change') - .triggerHandler('submit'); - }; - - $scope.cancel = function() { - _scanStop(); - }; - - $modalInstance.opened.then(function() { - $rootScope.isCollapsed = true; - - // Start the scanner - setTimeout(function() { - canvas = document.getElementById('qr-canvas'); - context = canvas.getContext('2d'); - - if ($scope.isMobile) { - cameraInput = document.getElementById('qrcode-camera'); - cameraInput.addEventListener('change', _scan, false); - } else { - video = document.getElementById('qrcode-scanner-video'); - $video = angular.element(video); - canvas.width = 300; - canvas.height = 225; - context.clearRect(0, 0, 300, 225); - - navigator.getUserMedia({video: true}, _successCallback, _videoError); - } - }, 500); - }); + }, 500); + }); }); diff --git a/packages/insight-ui/public/src/js/translations.js b/packages/insight-ui/public/src/js/translations.js index 7a75852623..a7242659e1 100644 --- a/packages/insight-ui/public/src/js/translations.js +++ b/packages/insight-ui/public/src/js/translations.js @@ -1,7 +1,396 @@ -angular.module('insight').run(['gettextCatalog', function (gettextCatalog) { -/* jshint -W100 */ - gettextCatalog.setStrings('de_DE', {"(Input unconfirmed)":"(Eingabe unbestรคtigt)","404 Page not found :(":"404 Seite nicht gefunden :(","insight is an open-source Merit blockchain explorer with complete REST and websocket APIs that can be used for writing web wallets and other apps that need more advanced blockchain queries than provided by meritd RPC. Check out the source code.":"insight ist ein Open Source Merit Blockchain Explorer mit vollstรคndigen REST und Websocket APIs um eigene Wallets oder Applikationen zu implementieren. Hierbei werden fortschrittlichere Abfragen der Blockchain ermรถglicht, bei denen die RPC des Meritd nicht mehr ausreichen. Der aktuelle Quellcode ist auf Github zu finden.","insight is still in development, so be sure to report any bugs and provide feedback for improvement at our github issue tracker.":"insight befindet sich aktuell noch in der Entwicklung. Bitte sende alle gefundenen Fehler (Bugs) und Feedback zur weiteren Verbesserung an unseren Github Issue Tracker.","About":"รœber insight","Address":"Adresse","Age":"Alter","Application Status":"Programmstatus","Best Block":"Bester Block","Merit node information":"Merit-Node Info","Block":"Block","Block Reward":"Belohnung","Blocks":"Blรถcke","Bytes Serialized":"Serialisierte Bytes","Can't connect to meritd to get live updates from the p2p network. (Tried connecting to meritd at {{host}}:{{port}} and failed.)":"Es ist nicht mรถglich mit Meritd zu verbinden um live Aktualisierungen vom P2P Netzwerk zu erhalten. (Verbindungsversuch zu meritd an {{host}}:{{port}} ist fehlgeschlagen.)","Can't connect to insight server. Attempting to reconnect...":"Keine Verbindung zum insight-Server mรถglich. Es wird versucht die Verbindung neu aufzubauen...","Can't connect to internet. Please, check your connection.":"Keine Verbindung zum Internet mรถglich, bitte Zugangsdaten prรผfen.","Complete":"Vollstรคndig","Confirmations":"Bestรคtigungen","Conn":"Verbindungen","Connections to other nodes":"Verbindungen zu Nodes","Current Blockchain Tip (insight)":"Aktueller Blockchain Tip (insight)","Current Sync Status":"Aktueller Status","Details":"Details","Difficulty":"Schwierigkeit","Double spent attempt detected. From tx:":"Es wurde ein \"double Spend\" Versuch erkannt.Von tx:","Error!":"Fehler!","Fee":"Gebรผhr","Final Balance":"Schlussbilanz","Finish Date":"Fertigstellung","Go to home":"Zur Startseite","Hash Serialized":"Hash Serialisiert","Height":"Hรถhe","Included in Block":"Eingefรผgt in Block","Incoherence in levelDB detected:":"Es wurde eine Zusammenhangslosigkeit in der LevelDB festgestellt:","Info Errors":"Fehlerbeschreibung","Initial Block Chain Height":"Ursprรผngliche Blockchain Hรถhe","Input":"Eingรคnge","Last Block":"Letzter Block","Last Block Hash (Meritd)":"Letzter Hash (Meritd)","Latest Blocks":"Letzte Blรถcke","Latest Transactions":"Letzte Transaktionen","Loading Address Information":"Lade Adressinformationen","Loading Block Information":"Lade Blockinformation","Loading Selected Date...":"Lade gewรคhltes Datum...","Loading Transaction Details":"Lade Transaktionsdetails","Loading Transactions...":"Lade Transaktionen...","Loading...":"Lade...","Mined Time":"Block gefunden (Mining)","Mined by":"Gefunden von","Mining Difficulty":"Schwierigkeitgrad","Next Block":"Nรคchster Block","No Inputs (Newly Generated Coins)":"Keine Eingรคnge (Neu generierte Coins)","No blocks yet.":"Keine Blรถcke bisher.","No matching records found!":"Keine passenden Eintrรคge gefunden!","No. Transactions":"Anzahl Transaktionen","Number Of Transactions":"Anzahl der Transaktionen","Output":"Ausgรคnge","Powered by":"Powered by","Previous Block":"Letzter Block","Protocol version":"Protokollversion","Proxy setting":"Proxyeinstellung","Received Time":"Eingangszeitpunkt","Redirecting...":"Umleitung...","Search for block, transaction or address":"Suche Block, Transaktion oder Adresse","See all blocks":"Alle Blรถcke anzeigen","Show Transaction Output data":"Zeige Abgรคnge","Show all":"Zeige Alles","Show input":"Zeige Eingรคnge","Show less":"Weniger anzeigen","Show more":"Mehr anzeigen","Size":"GrรถรŸe","Size (bytes)":"GrรถรŸe (bytes)","Skipped Blocks (previously synced)":"Verworfene Blรถcke (bereits syncronisiert)","Start Date":"Startdatum","Status":"Status","Summary":"Zusammenfassung","Summary confirmed":"Zusammenfassung bestรคtigt","Sync Progress":"Fortschritt","Sync Status":"Syncronisation","Sync Type":"Art der Syncronisation","Synced Blocks":"Syncronisierte Blรถcke","Testnet":"Testnet aktiv","There are no transactions involving this address.":"Es gibt keine Transaktionen zu dieser Adressse","Time Offset":"Zeitoffset zu UTC","Timestamp":"Zeitstempel","Today":"Heute","Total Amount":"Gesamtsumme","Total Received":"Insgesamt empfangen","Total Sent":"Insgesamt gesendet","Transaction":"Transaktion","Transaction Output Set Information":"Transaktions Abgรคnge","Transaction Outputs":"Abgรคnge","Transactions":"Transaktionen","Type":"Typ","Unconfirmed":"Unbestรคtigt","Unconfirmed Transaction!":"Unbestรคtigte Transaktion!","Unconfirmed Txs Balance":"Unbestรคtigtes Guthaben","Value Out":"Wert","Version":"Version","Waiting for blocks...":"Warte auf Blรถcke...","Waiting for transactions...":"Warte auf Transaktionen...","by date.":"nach Datum.","first seen at":"zuerst gesehen am","mined":"gefunden","mined on:":"vom:","Waiting for blocks":"Warte auf Blรถcke"}); - gettextCatalog.setStrings('es', {"(Input unconfirmed)":"(Entrada sin confirmar)","404 Page not found :(":"404 Pรกgina no encontrada :(","insight is an open-source Merit blockchain explorer with complete REST and websocket APIs that can be used for writing web wallets and other apps that need more advanced blockchain queries than provided by meritd RPC. Check out the source code.":"insight es un explorador de bloques de Merit open-source con un completo conjunto de REST y APIs de websockets que pueden ser usadas para escribir monederos de Merits y otras aplicaciones que requieran consultar un explorador de bloques. Obtรฉn el cรณdigo en el repositorio abierto de Github.","insight is still in development, so be sure to report any bugs and provide feedback for improvement at our github issue tracker.":"insight esta en desarrollo aรบn, por ello agradecemos que nos reporten errores o sugerencias para mejorar el software. Github issue tracker.","About":"Acerca de","Address":"Direcciรณn","Age":"Edad","Application Status":"Estado de la Aplicaciรณn","Best Block":"Mejor Bloque","Merit node information":"Informaciรณn del nodo Merit","Block":"Bloque","Block Reward":"Bloque Recompensa","Blocks":"Bloques","Bytes Serialized":"Bytes Serializados","Can't connect to meritd to get live updates from the p2p network. (Tried connecting to meritd at {{host}}:{{port}} and failed.)":"No se pudo conectar a meritd para obtener actualizaciones en vivo de la red p2p. (Se intentรณ conectar a meritd de {{host}}:{{port}} y fallรณ.)","Can't connect to insight server. Attempting to reconnect...":"No se pudo conectar al servidor insight. Intentando re-conectar...","Can't connect to internet. Please, check your connection.":"No se pudo conectar a Internet. Por favor, verifique su conexiรณn.","Complete":"Completado","Confirmations":"Confirmaciones","Conn":"Con","Connections to other nodes":"Conexiones a otros nodos","Current Blockchain Tip (insight)":"Actual Blockchain Tip (insight)","Current Sync Status":"Actual Estado de Sincronizaciรณn","Details":"Detalles","Difficulty":"Dificultad","Double spent attempt detected. From tx:":"Intento de doble gasto detectado. De la transacciรณn:","Error!":"ยกError!","Fee":"Tasa","Final Balance":"Balance Final","Finish Date":"Fecha Final","Go to home":"Volver al Inicio","Hash Serialized":"Hash Serializado","Height":"Altura","Included in Block":"Incluido en el Bloque","Incoherence in levelDB detected:":"Detectada una incoherencia en levelDB:","Info Errors":"Errores de Informaciรณn","Initial Block Chain Height":"Altura de la Cadena en Bloque Inicial","Input":"Entrada","Last Block":"รšltimo Bloque","Last Block Hash (Meritd)":"รšltimo Bloque Hash (Meritd)","Latest Blocks":"รšltimos Bloques","Latest Transactions":"รšltimas Transacciones","Loading Address Information":"Cargando Informaciรณn de la Direcciรณn","Loading Block Information":"Cargando Informaciรณn del Bloque","Loading Selected Date...":"Cargando Fecha Seleccionada...","Loading Transaction Details":"Cargando Detalles de la Transacciรณn","Loading Transactions...":"Cargando Transacciones...","Loading...":"Cargando...","Mined Time":"Hora de Minado","Mined by":"Minado por","Mining Difficulty":"Dificultad de Minado","Next Block":"Prรณximo Bloque","No Inputs (Newly Generated Coins)":"Sin Entradas (Monedas Reciรฉn Generadas)","No blocks yet.":"No hay bloques aรบn.","No matching records found!":"ยกNo se encontraron registros coincidentes!","No. Transactions":"Nro. de Transacciones","Number Of Transactions":"Nรบmero de Transacciones","Output":"Salida","Powered by":"Funciona con","Previous Block":"Bloque Anterior","Protocol version":"Versiรณn del protocolo","Proxy setting":"Opciรณn de proxy","Received Time":"Hora de Recibido","Redirecting...":"Redireccionando...","Search for block, transaction or address":"Buscar bloques, transacciones o direcciones","See all blocks":"Ver todos los bloques","Show Transaction Output data":"Mostrar dato de Salida de la Transacciรณn","Show all":"Mostrar todos","Show input":"Mostrar entrada","Show less":"Ver menos","Show more":"Ver mรกs","Size":"Tamaรฑo","Size (bytes)":"Tamaรฑo (bytes)","Skipped Blocks (previously synced)":"Bloques Saltados (previamente sincronizado)","Start Date":"Fecha de Inicio","Status":"Estado","Summary":"Resumen","Summary confirmed":"Resumen confirmados","Sync Progress":"Proceso de Sincronizaciรณn","Sync Status":"Estado de Sincronizaciรณn","Sync Type":"Tipo de Sincronizaciรณn","Synced Blocks":"Bloques Sincornizados","Testnet":"Red de prueba","There are no transactions involving this address.":"No hay transacciones para esta direcciรณn","Time Offset":"Desplazamiento de hora","Timestamp":"Fecha y hora","Today":"Hoy","Total Amount":"Cantidad Total","Total Received":"Total Recibido","Total Sent":"Total Enviado","Transaction":"Transacciรณn","Transaction Output Set Information":"Informaciรณn del Conjunto de Salida de la Transacciรณn","Transaction Outputs":"Salidas de la Transacciรณn","Transactions":"Transacciones","Type":"Tipo","Unconfirmed":"Sin confirmar","Unconfirmed Transaction!":"ยกTransacciรณn sin confirmar!","Unconfirmed Txs Balance":"Balance sin confirmar","Value Out":"Valor de Salida","Version":"Versiรณn","Waiting for blocks...":"Esperando bloques...","Waiting for transactions...":"Esperando transacciones...","by date.":"por fecha.","first seen at":"Visto a","mined":"minado","mined on:":"minado el:","Waiting for blocks":"Esperando bloques"}); - gettextCatalog.setStrings('ja', {"(Input unconfirmed)":"(ๅ…ฅๅŠ›ใฏๆœชๆคœ่จผใงใ™)","404 Page not found :(":"404 ใƒšใƒผใ‚ธใŒใฟใคใ‹ใ‚Šใพใ›ใ‚“ (ยดใƒปฯ‰ใƒป`)","insight is an open-source Merit blockchain explorer with complete REST and websocket APIs that can be used for writing web wallets and other apps that need more advanced blockchain queries than provided by meritd RPC. Check out the source code.":"insightใฏใ€meritd RPCใฎๆไพ›ใ™ใ‚‹ใ‚‚ใฎใ‚ˆใ‚Šใ‚‚่ฉณ็ดฐใชใƒ–ใƒญใƒƒใ‚ฏใƒใ‚งใ‚คใƒณใธใฎๅ•ใ„ๅˆใ‚ใ›ใ‚’ๅฟ…่ฆใจใ™ใ‚‹ใ‚ฆใ‚งใƒ–ใ‚ฆใ‚ฉใƒฌใƒƒใƒˆใ‚„ใใฎไป–ใฎใ‚ขใƒ—ใƒชใ‚’ๆ›ธใใฎใซไฝฟใˆใ‚‹ใ€ๅฎŒๅ…จใชRESTใŠใ‚ˆใณwebsocket APIใ‚’ๅ‚™ใˆใŸใ‚ชใƒผใƒ—ใƒณใ‚ฝใƒผใ‚นใฎใƒ“ใƒƒใƒˆใ‚ณใ‚คใƒณใƒ–ใƒญใƒƒใ‚ฏใ‚จใ‚ฏใ‚นใƒ—ใƒญใƒผใƒฉใงใ™ใ€‚ใ‚ฝใƒผใ‚นใ‚ณใƒผใƒ‰ใ‚’็ขบ่ช","insight is still in development, so be sure to report any bugs and provide feedback for improvement at our github issue tracker.":"insightใฏ็พๅœจ้–‹็™บไธญใงใ™ใ€‚githubใฎissueใƒˆใƒฉใƒƒใ‚ซใซใฆใƒใ‚ฐใฎๅ ฑๅ‘Šใ‚„ๆ”นๅ–„ๆกˆใฎๆๆกˆใ‚’ใŠ้ก˜ใ„ใ—ใพใ™ใ€‚","About":"ใฏใ˜ใ‚ใซ","Address":"ใ‚ขใƒ‰ใƒฌใ‚น","Age":"็”ŸๆˆๅพŒ็ตŒ้Žๆ™‚้–“","An error occured in the verification process.":"ๆคœ่จผ้Ž็จ‹ใงใ‚จใƒฉใƒผใŒ็™บ็”Ÿใ—ใพใ—ใŸใ€‚","An error occured:
{{error}}":"ใ‚จใƒฉใƒผใŒ็™บ็”Ÿใ—ใพใ—ใŸ:
{{error}}","Application Status":"ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใฎ็Šถๆ…‹","Best Block":"ๆœ€่‰ฏใƒ–ใƒญใƒƒใ‚ฏ","Merit comes with a way of signing arbitrary messages.":"Meritใซใฏไปปๆ„ใฎใƒกใƒƒใ‚ปใƒผใ‚ธใ‚’็ฝฒๅใ™ใ‚‹ๆ˜จๆ—ฅใŒๅ‚™ใ‚ใฃใฆใ„ใพใ™ใ€‚","Merit node information":"MeritใƒŽใƒผใƒ‰ๆƒ…ๅ ฑ","Block":"ใƒ–ใƒญใƒƒใ‚ฏ","Block Reward":"ใƒ–ใƒญใƒƒใ‚ฏๅ ฑ้…ฌ","Blocks":"ใƒ–ใƒญใƒƒใ‚ฏ","Broadcast Raw Transaction":"็”Ÿใฎใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ‚’้…ไฟก","Bytes Serialized":"ใ‚ทใƒชใ‚ขใƒฉใ‚คใ‚บๅพŒใฎๅฎน้‡ (ใƒใ‚คใƒˆ)","Can't connect to meritd to get live updates from the p2p network. (Tried connecting to meritd at {{host}}:{{port}} and failed.)":"P2Pใƒใƒƒใƒˆใƒฏใƒผใ‚ฏใ‹ใ‚‰ใƒฉใ‚คใƒ–ๆƒ…ๅ ฑใ‚’ๅ–ๅพ—ใ™ใ‚‹ใŸใ‚ใซmeritdใธๆŽฅ็ถšใ™ใ‚‹ใ“ใจใŒใงใใพใ›ใ‚“ใงใ—ใŸใ€‚({{host}}:{{port}} ใธใฎๆŽฅ็ถšใ‚’่ฉฆใฟใพใ—ใŸใŒใ€ๅคฑๆ•—ใ—ใพใ—ใŸใ€‚)","Can't connect to insight server. Attempting to reconnect...":"insight ใ‚ตใƒผใƒใซๆŽฅ็ถšใงใใพใ›ใ‚“ใ€‚ๅ†ๆŽฅ็ถšใ—ใฆใ„ใพใ™...","Can't connect to internet. Please, check your connection.":"ใ‚คใƒณใ‚ฟใƒผใƒใƒƒใƒˆใซๆŽฅ็ถšใงใใพใ›ใ‚“ใ€‚ใ‚ณใƒใ‚ฏใ‚ทใƒงใƒณใ‚’็ขบ่ชใ—ใฆใใ ใ•ใ„ใ€‚","Complete":"ๅฎŒไบ†","Confirmations":"ๆคœ่จผๆ•ฐ","Conn":"ๆŽฅ็ถšๆ•ฐ","Connections to other nodes":"ไป–ใƒŽใƒผใƒ‰ใธใฎๆŽฅ็ถš","Current Blockchain Tip (insight)":"็พๅœจใฎใƒ–ใƒญใƒƒใ‚ฏใƒใ‚งใ‚คใƒณใฎTip (insight)","Current Sync Status":"็พๅœจใฎๅŒๆœŸ็Šถๆณ","Details":"่ฉณ็ดฐ","Difficulty":"้›ฃๆ˜“ๅบฆ","Double spent attempt detected. From tx:":"ไบŒ้‡ๆ”ฏๆ‰•ใ„ๆ”ปๆ’ƒใ‚’ใ“ใฎใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ‹ใ‚‰ๆคœ็Ÿฅใ—ใพใ—ใŸ๏ผš","Error message:":"ใ‚จใƒฉใƒผใƒกใƒƒใ‚ปใƒผใ‚ธ:","Error!":"ใ‚จใƒฉใƒผ๏ผ","Fee":"ๆ‰‹ๆ•ฐๆ–™","Final Balance":"ๆœ€็ต‚ๆฎ‹้ซ˜","Finish Date":"็ต‚ไบ†ๆ—ฅๆ™‚","Go to home":"ใƒ›ใƒผใƒ ใธ","Hash Serialized":"ใ‚ทใƒชใ‚ขใƒฉใ‚คใ‚บใƒ‡ใƒผใ‚ฟใฎใƒใƒƒใ‚ทใƒฅๅ€ค","Height":"ใƒ–ใƒญใƒƒใ‚ฏ้ซ˜","Included in Block":"ๅ–ใ‚Š่พผใพใ‚ŒใŸใƒ–ใƒญใƒƒใ‚ฏ","Incoherence in levelDB detected:":"levelDBใฎ็ ดๆใ‚’ๆคœ็Ÿฅใ—ใพใ—ใŸ:","Info Errors":"ใ‚จใƒฉใƒผๆƒ…ๅ ฑ","Initial Block Chain Height":"่ตทๅ‹•ๆ™‚ใฎใƒ–ใƒญใƒƒใ‚ฏ้ซ˜","Input":"ๅ…ฅๅŠ›","Last Block":"็›ดๅ‰ใฎใƒ–ใƒญใƒƒใ‚ฏ","Last Block Hash (Meritd)":"็›ดๅ‰ใฎใƒ–ใƒญใƒƒใ‚ฏใฎใƒใƒƒใ‚ทใƒฅๅ€ค (Meritd)","Latest Blocks":"ๆœ€ๆ–ฐใฎใƒ–ใƒญใƒƒใ‚ฏ","Latest Transactions":"ๆœ€ๆ–ฐใฎใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณ","Loading Address Information":"ใ‚ขใƒ‰ใƒฌใ‚นๆƒ…ๅ ฑใ‚’่ชญใฟ่พผใ‚“ใงใ„ใพใ™","Loading Block Information":"ใƒ–ใƒญใƒƒใ‚ฏๆƒ…ๅ ฑใ‚’่ชญใฟ่พผใ‚“ใงใ„ใพใ™","Loading Selected Date...":"้ธๆŠžใ•ใ‚ŒใŸใƒ‡ใƒผใ‚ฟใ‚’่ชญใฟ่พผใ‚“ใงใ„ใพใ™...","Loading Transaction Details":"ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎ่ฉณ็ดฐใ‚’่ชญใฟ่พผใ‚“ใงใ„ใพใ™","Loading Transactions...":"ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ‚’่ชญใฟ่พผใ‚“ใงใ„ใพใ™...","Loading...":"ใƒญใƒผใƒ‰ไธญ...","Message":"ใƒกใƒƒใ‚ปใƒผใ‚ธ","Mined Time":"ๆŽกๆŽ˜ๆ™‚ๅˆป","Mined by":"ๆŽกๆŽ˜่€…","Mining Difficulty":"ๆŽกๆŽ˜้›ฃๆ˜“ๅบฆ","Next Block":"ๆฌกใฎใƒ–ใƒญใƒƒใ‚ฏ","No Inputs (Newly Generated Coins)":"ๅ…ฅๅŠ›ใชใ— (ๆ–ฐใ—ใ็”Ÿๆˆใ•ใ‚ŒใŸใ‚ณใ‚คใƒณ)","No blocks yet.":"ใƒ–ใƒญใƒƒใ‚ฏใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚","No matching records found!":"ไธ€่‡ดใ™ใ‚‹ใƒฌใ‚ณใƒผใƒ‰ใฏใ‚ใ‚Šใพใ›ใ‚“๏ผ","No. Transactions":"ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณๆ•ฐ","Number Of Transactions":"ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณๆ•ฐ","Output":"ๅ‡บๅŠ›","Powered by":"Powered by","Previous Block":"ๅ‰ใฎใƒ–ใƒญใƒƒใ‚ฏ","Protocol version":"ใƒ—ใƒญใƒˆใ‚ณใƒซใƒใƒผใ‚ธใƒงใƒณ","Proxy setting":"ใƒ—ใƒญใ‚ญใ‚ท่จญๅฎš","Raw transaction data":"ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎ็”Ÿใƒ‡ใƒผใ‚ฟ","Raw transaction data must be a valid hexadecimal string.":"็”Ÿใฎใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใƒ‡ใƒผใ‚ฟใฏๆœ‰ๅŠนใช16้€ฒๆ•ฐใงใชใ‘ใ‚Œใฐใ„ใ‘ใพใ›ใ‚“ใ€‚","Received Time":"ๅ—ไฟกๆ™‚ๅˆป","Redirecting...":"ใƒชใƒ€ใ‚คใƒฌใ‚ฏใƒˆใ—ใฆใ„ใพใ™...","Search for block, transaction or address":"ใƒ–ใƒญใƒƒใ‚ฏใ€ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ€ใ‚ขใƒ‰ใƒฌใ‚นใ‚’ๆคœ็ดข","See all blocks":"ใ™ในใฆใฎใƒ–ใƒญใƒƒใ‚ฏใ‚’ใฟใ‚‹","Send transaction":"ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ‚’้€ไฟก","Show Transaction Output data":"ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎๅ‡บๅŠ›ใƒ‡ใƒผใ‚ฟใ‚’ใฟใ‚‹","Show all":"ใ™ในใฆ่กจ็คบ","Show input":"ๅ…ฅๅŠ›ใ‚’่กจ็คบ","Show less":"้š ใ™","Show more":"่กจ็คบใ™ใ‚‹","Signature":"็ฝฒๅ","Size":"ใ‚ตใ‚คใ‚บ","Size (bytes)":"ใ‚ตใ‚คใ‚บ (ใƒใ‚คใƒˆ)","Skipped Blocks (previously synced)":"ใ‚นใ‚ญใƒƒใƒ—ใ•ใ‚ŒใŸใƒ–ใƒญใƒƒใ‚ฏ (ๅŒๆœŸๆธˆใฟ)","Start Date":"้–‹ๅง‹ๆ—ฅๆ™‚","Status":"ใ‚นใƒ†ใƒผใ‚ฟใ‚น","Summary":"ๆฆ‚่ฆ","Summary confirmed":"ใ‚ตใƒžใƒช ๆคœ่จผๆธˆใฟ","Sync Progress":"ๅŒๆœŸใฎ้€ฒๆ—็Šถๆณ","Sync Status":"ๅŒๆœŸใ‚นใƒ†ใƒผใ‚ฟใ‚น","Sync Type":"ๅŒๆœŸใ‚ฟใ‚คใƒ—","Synced Blocks":"ๅŒๆœŸใ•ใ‚ŒใŸใƒ–ใƒญใƒƒใ‚ฏๆ•ฐ","Testnet":"ใƒ†ใ‚นใƒˆใƒใƒƒใƒˆ","The message failed to verify.":"ใƒกใƒƒใ‚ปใƒผใ‚ธใฎๆคœ่จผใซๅคฑๆ•—ใ—ใพใ—ใŸใ€‚","The message is verifiably from {{verification.address}}.":"ใƒกใƒƒใ‚ปใƒผใ‚ธใฏ{{verification.address}}ใซใ‚ˆใ‚Šๆคœ่จผใ•ใ‚Œใพใ—ใŸใ€‚","There are no transactions involving this address.":"ใ“ใฎใ‚ขใƒ‰ใƒฌใ‚นใซๅฏพใ™ใ‚‹ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚","This form can be used to broadcast a raw transaction in hex format over\n the Merit network.":"ใ“ใฎใƒ•ใ‚ฉใƒผใƒ ใงใฏใ€16้€ฒๆ•ฐใƒ•ใ‚ฉใƒผใƒžใƒƒใƒˆใฎ็”Ÿใฎใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ‚’Meritใƒใƒƒใƒˆใƒฏใƒผใ‚ฏไธŠใซ้…ไฟกใ™ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚","This form can be used to verify that a message comes from\n a specific Merit address.":"ใ“ใฎใƒ•ใ‚ฉใƒผใƒ ใงใฏใ€ใƒกใƒƒใ‚ปใƒผใ‚ธใŒ็‰นๅฎšใฎMeritใ‚ขใƒ‰ใƒฌใ‚นใ‹ใ‚‰ๆฅใŸใ‹ใฉใ†ใ‹ใ‚’ๆคœ่จผใ™ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚","Time Offset":"ๆ™‚้–“ใ‚ชใƒ•ใ‚ปใƒƒใƒˆ","Timestamp":"ใ‚ฟใ‚คใƒ ใ‚นใ‚ฟใƒณใƒ—","Today":"ไปŠๆ—ฅ","Total Amount":"Merit็ท้‡","Total Received":"็ทๅ…ฅ้‡‘้ก","Total Sent":"็ท้€้‡‘้ก","Transaction":"ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณ","Transaction Output Set Information":"ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎๅ‡บๅŠ›ใ‚ปใƒƒใƒˆๆƒ…ๅ ฑ","Transaction Outputs":"ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎๅ‡บๅŠ›","Transaction succesfully broadcast.
Transaction id: {{txid}}":"ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎ้…ไฟกใซๆˆๅŠŸใ—ใพใ—ใŸใ€‚
ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณID: {{txid}}","Transactions":"ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณ","Type":"ใ‚ฟใ‚คใƒ—","Unconfirmed":"ๆœชๆคœ่จผ","Unconfirmed Transaction!":"ๆœชๆคœ่จผใฎใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใงใ™๏ผ","Unconfirmed Txs Balance":"ๆœชๆคœ่จผใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎๆฎ‹้ซ˜","Value Out":"ๅ‡บๅŠ›ๅ€ค","Verify":"ๆคœ่จผ","Verify signed message":"็ฝฒๅๆธˆใฟใƒกใƒƒใ‚ปใƒผใ‚ธใ‚’ๆคœ่จผ","Version":"ใƒใƒผใ‚ธใƒงใƒณ","Waiting for blocks...":"ใƒ–ใƒญใƒƒใ‚ฏใ‚’ๅพ…ใฃใฆใ„ใพใ™...","Waiting for transactions...":"ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ‚’ๅพ…ใฃใฆใ„ใพใ™...","by date.":"ๆ—ฅๆฏŽใ€‚","first seen at":"ๆœ€ๅˆใซ็™บ่ฆ‹ใ•ใ‚ŒใŸๆ—ฅๆ™‚","mined":"ๆŽกๆŽ˜ใ•ใ‚ŒใŸ","mined on:":"ๆŽกๆŽ˜ๆ—ฅๆ™‚:","(Mainchain)":"(ใƒกใ‚คใƒณใƒใ‚งใƒผใƒณ)","(Orphaned)":"(ๅญค็ซ‹ใ—ใŸใƒ–ใƒญใƒƒใ‚ฏ)","Bits":"Bits","Block #{{block.height}}":"ใƒ–ใƒญใƒƒใ‚ฏ #{{block.height}}","BlockHash":"ใƒ–ใƒญใƒƒใ‚ฏใฎใƒใƒƒใ‚ทใƒฅๅ€ค","Blocks
mined on:":"ใƒ–ใƒญใƒƒใ‚ฏ
ๆŽกๆŽ˜ๆ—ฅ","Coinbase":"ใ‚ณใ‚คใƒณใƒ™ใƒผใ‚น","Hash":"ใƒใƒƒใ‚ทใƒฅๅ€ค","LockTime":"ใƒญใƒƒใ‚ฏๆ™‚้–“","Merkle Root":"Merkleใƒซใƒผใƒˆ","Nonce":"Nonce","Ooops!":"ใŠใ‰ใฃใจ๏ผ","Output is spent":"ๅ‡บๅŠ›ใฏไฝฟ็”จๆธˆใฟใงใ™","Output is unspent":"ๅ‡บๅŠ›ใฏๆœชไฝฟ็”จใงใ™","Scan":"ใ‚นใ‚ญใƒฃใƒณ","Show/Hide items details":"ใ‚ขใ‚คใƒ†ใƒ ใฎ่ฉณ็ดฐใ‚’่กจ็คบใพใŸใฏ้š ใ™","Waiting for blocks":"ใƒ–ใƒญใƒƒใ‚ฏใ‚’ๅพ…ใฃใฆใ„ใพใ™","by date. {{detail}} {{before}}":"ๆ—ฅๆ™‚้ † {{detail}} {{before}}","scriptSig":"scriptSig","{{tx.confirmations}} Confirmations":"{{tx.confirmations}} ๆคœ่จผ"," (Orphaned)":" (ๅญค็ซ‹ใ—ใŸใƒ–ใƒญใƒƒใ‚ฏ)"," Incoherence in levelDB detected: {{vin.dbError}}":" Incoherence in levelDB detected: {{vin.dbError}}","Waiting for blocks ":"ใƒ–ใƒญใƒƒใ‚ฏใ‚’ๅพ…ใฃใฆใ„ใพใ™ "}); -/* jshint +W100 */ -}]); +angular.module('insight').run([ + 'gettextCatalog', + function(gettextCatalog) { + /* jshint -W100 */ + gettextCatalog.setStrings('de_DE', { + '(Input unconfirmed)': '(Eingabe unbestรคtigt)', + '404 Page not found :(': '404 Seite nicht gefunden :(', + 'insight is an open-source Merit blockchain explorer with complete REST and websocket APIs that can be used for writing web wallets and other apps that need more advanced blockchain queries than provided by meritd RPC. Check out the source code.': + 'insight ist ein Open Source Merit Blockchain Explorer mit vollstรคndigen REST und Websocket APIs um eigene Wallets oder Applikationen zu implementieren. Hierbei werden fortschrittlichere Abfragen der Blockchain ermรถglicht, bei denen die RPC des Meritd nicht mehr ausreichen. Der aktuelle Quellcode ist auf Github zu finden.', + 'insight is still in development, so be sure to report any bugs and provide feedback for improvement at our github issue tracker.': + 'insight befindet sich aktuell noch in der Entwicklung. Bitte sende alle gefundenen Fehler (Bugs) und Feedback zur weiteren Verbesserung an unseren Github Issue Tracker.', + About: 'รœber insight', + Address: 'Adresse', + Age: 'Alter', + 'Application Status': 'Programmstatus', + 'Best Block': 'Bester Block', + 'Merit node information': 'Merit-Node Info', + Block: 'Block', + 'Block Reward': 'Belohnung', + Blocks: 'Blรถcke', + 'Bytes Serialized': 'Serialisierte Bytes', + "Can't connect to meritd to get live updates from the p2p network. (Tried connecting to meritd at {{host}}:{{port}} and failed.)": + 'Es ist nicht mรถglich mit Meritd zu verbinden um live Aktualisierungen vom P2P Netzwerk zu erhalten. (Verbindungsversuch zu meritd an {{host}}:{{port}} ist fehlgeschlagen.)', + "Can't connect to insight server. Attempting to reconnect...": + 'Keine Verbindung zum insight-Server mรถglich. Es wird versucht die Verbindung neu aufzubauen...', + "Can't connect to internet. Please, check your connection.": + 'Keine Verbindung zum Internet mรถglich, bitte Zugangsdaten prรผfen.', + Complete: 'Vollstรคndig', + Confirmations: 'Bestรคtigungen', + Conn: 'Verbindungen', + 'Connections to other nodes': 'Verbindungen zu Nodes', + 'Current Blockchain Tip (insight)': 'Aktueller Blockchain Tip (insight)', + 'Current Sync Status': 'Aktueller Status', + Details: 'Details', + Difficulty: 'Schwierigkeit', + 'Double spent attempt detected. From tx:': 'Es wurde ein "double Spend" Versuch erkannt.Von tx:', + 'Error!': 'Fehler!', + Fee: 'Gebรผhr', + 'Final Balance': 'Schlussbilanz', + 'Finish Date': 'Fertigstellung', + 'Go to home': 'Zur Startseite', + 'Hash Serialized': 'Hash Serialisiert', + Height: 'Hรถhe', + 'Included in Block': 'Eingefรผgt in Block', + 'Incoherence in levelDB detected:': 'Es wurde eine Zusammenhangslosigkeit in der LevelDB festgestellt:', + 'Info Errors': 'Fehlerbeschreibung', + 'Initial Block Chain Height': 'Ursprรผngliche Blockchain Hรถhe', + Input: 'Eingรคnge', + 'Last Block': 'Letzter Block', + 'Last Block Hash (Meritd)': 'Letzter Hash (Meritd)', + 'Latest Blocks': 'Letzte Blรถcke', + 'Latest Transactions': 'Letzte Transaktionen', + 'Loading Address Information': 'Lade Adressinformationen', + 'Loading Block Information': 'Lade Blockinformation', + 'Loading Selected Date...': 'Lade gewรคhltes Datum...', + 'Loading Transaction Details': 'Lade Transaktionsdetails', + 'Loading Transactions...': 'Lade Transaktionen...', + 'Loading...': 'Lade...', + 'Mined Time': 'Block gefunden (Mining)', + 'Mined by': 'Gefunden von', + 'Mining Difficulty': 'Schwierigkeitgrad', + 'Next Block': 'Nรคchster Block', + 'No Inputs (Newly Generated Coins)': 'Keine Eingรคnge (Neu generierte Coins)', + 'No blocks yet.': 'Keine Blรถcke bisher.', + 'No matching records found!': 'Keine passenden Eintrรคge gefunden!', + 'No. Transactions': 'Anzahl Transaktionen', + 'Number Of Transactions': 'Anzahl der Transaktionen', + Output: 'Ausgรคnge', + 'Powered by': 'Powered by', + 'Previous Block': 'Letzter Block', + 'Protocol version': 'Protokollversion', + 'Proxy setting': 'Proxyeinstellung', + 'Received Time': 'Eingangszeitpunkt', + 'Redirecting...': 'Umleitung...', + 'Search for block, transaction or address': 'Suche Block, Transaktion oder Adresse', + 'See all blocks': 'Alle Blรถcke anzeigen', + 'Show Transaction Output data': 'Zeige Abgรคnge', + 'Show all': 'Zeige Alles', + 'Show input': 'Zeige Eingรคnge', + 'Show less': 'Weniger anzeigen', + 'Show more': 'Mehr anzeigen', + Size: 'GrรถรŸe', + 'Size (bytes)': 'GrรถรŸe (bytes)', + 'Skipped Blocks (previously synced)': 'Verworfene Blรถcke (bereits syncronisiert)', + 'Start Date': 'Startdatum', + Status: 'Status', + Summary: 'Zusammenfassung', + 'Summary confirmed': 'Zusammenfassung bestรคtigt', + 'Sync Progress': 'Fortschritt', + 'Sync Status': 'Syncronisation', + 'Sync Type': 'Art der Syncronisation', + 'Synced Blocks': 'Syncronisierte Blรถcke', + Testnet: 'Testnet aktiv', + 'There are no transactions involving this address.': 'Es gibt keine Transaktionen zu dieser Adressse', + 'Time Offset': 'Zeitoffset zu UTC', + Timestamp: 'Zeitstempel', + Today: 'Heute', + 'Total Amount': 'Gesamtsumme', + 'Total Received': 'Insgesamt empfangen', + 'Total Sent': 'Insgesamt gesendet', + Transaction: 'Transaktion', + 'Transaction Output Set Information': 'Transaktions Abgรคnge', + 'Transaction Outputs': 'Abgรคnge', + Transactions: 'Transaktionen', + Type: 'Typ', + Unconfirmed: 'Unbestรคtigt', + 'Unconfirmed Transaction!': 'Unbestรคtigte Transaktion!', + 'Unconfirmed Txs Balance': 'Unbestรคtigtes Guthaben', + 'Value Out': 'Wert', + Version: 'Version', + 'Waiting for blocks...': 'Warte auf Blรถcke...', + 'Waiting for transactions...': 'Warte auf Transaktionen...', + 'by date.': 'nach Datum.', + 'first seen at': 'zuerst gesehen am', + mined: 'gefunden', + 'mined on:': 'vom:', + 'Waiting for blocks': 'Warte auf Blรถcke', + }); + gettextCatalog.setStrings('es', { + '(Input unconfirmed)': '(Entrada sin confirmar)', + '404 Page not found :(': '404 Pรกgina no encontrada :(', + 'insight is an open-source Merit blockchain explorer with complete REST and websocket APIs that can be used for writing web wallets and other apps that need more advanced blockchain queries than provided by meritd RPC. Check out the source code.': + 'insight es un explorador de bloques de Merit open-source con un completo conjunto de REST y APIs de websockets que pueden ser usadas para escribir monederos de Merits y otras aplicaciones que requieran consultar un explorador de bloques. Obtรฉn el cรณdigo en el repositorio abierto de Github.', + 'insight is still in development, so be sure to report any bugs and provide feedback for improvement at our github issue tracker.': + 'insight esta en desarrollo aรบn, por ello agradecemos que nos reporten errores o sugerencias para mejorar el software. Github issue tracker.', + About: 'Acerca de', + Address: 'Direcciรณn', + Age: 'Edad', + 'Application Status': 'Estado de la Aplicaciรณn', + 'Best Block': 'Mejor Bloque', + 'Merit node information': 'Informaciรณn del nodo Merit', + Block: 'Bloque', + 'Block Reward': 'Bloque Recompensa', + Blocks: 'Bloques', + 'Bytes Serialized': 'Bytes Serializados', + "Can't connect to meritd to get live updates from the p2p network. (Tried connecting to meritd at {{host}}:{{port}} and failed.)": + 'No se pudo conectar a meritd para obtener actualizaciones en vivo de la red p2p. (Se intentรณ conectar a meritd de {{host}}:{{port}} y fallรณ.)', + "Can't connect to insight server. Attempting to reconnect...": + 'No se pudo conectar al servidor insight. Intentando re-conectar...', + "Can't connect to internet. Please, check your connection.": + 'No se pudo conectar a Internet. Por favor, verifique su conexiรณn.', + Complete: 'Completado', + Confirmations: 'Confirmaciones', + Conn: 'Con', + 'Connections to other nodes': 'Conexiones a otros nodos', + 'Current Blockchain Tip (insight)': 'Actual Blockchain Tip (insight)', + 'Current Sync Status': 'Actual Estado de Sincronizaciรณn', + Details: 'Detalles', + Difficulty: 'Dificultad', + 'Double spent attempt detected. From tx:': 'Intento de doble gasto detectado. De la transacciรณn:', + 'Error!': 'ยกError!', + Fee: 'Tasa', + 'Final Balance': 'Balance Final', + 'Finish Date': 'Fecha Final', + 'Go to home': 'Volver al Inicio', + 'Hash Serialized': 'Hash Serializado', + Height: 'Altura', + 'Included in Block': 'Incluido en el Bloque', + 'Incoherence in levelDB detected:': 'Detectada una incoherencia en levelDB:', + 'Info Errors': 'Errores de Informaciรณn', + 'Initial Block Chain Height': 'Altura de la Cadena en Bloque Inicial', + Input: 'Entrada', + 'Last Block': 'รšltimo Bloque', + 'Last Block Hash (Meritd)': 'รšltimo Bloque Hash (Meritd)', + 'Latest Blocks': 'รšltimos Bloques', + 'Latest Transactions': 'รšltimas Transacciones', + 'Loading Address Information': 'Cargando Informaciรณn de la Direcciรณn', + 'Loading Block Information': 'Cargando Informaciรณn del Bloque', + 'Loading Selected Date...': 'Cargando Fecha Seleccionada...', + 'Loading Transaction Details': 'Cargando Detalles de la Transacciรณn', + 'Loading Transactions...': 'Cargando Transacciones...', + 'Loading...': 'Cargando...', + 'Mined Time': 'Hora de Minado', + 'Mined by': 'Minado por', + 'Mining Difficulty': 'Dificultad de Minado', + 'Next Block': 'Prรณximo Bloque', + 'No Inputs (Newly Generated Coins)': 'Sin Entradas (Monedas Reciรฉn Generadas)', + 'No blocks yet.': 'No hay bloques aรบn.', + 'No matching records found!': 'ยกNo se encontraron registros coincidentes!', + 'No. Transactions': 'Nro. de Transacciones', + 'Number Of Transactions': 'Nรบmero de Transacciones', + Output: 'Salida', + 'Powered by': 'Funciona con', + 'Previous Block': 'Bloque Anterior', + 'Protocol version': 'Versiรณn del protocolo', + 'Proxy setting': 'Opciรณn de proxy', + 'Received Time': 'Hora de Recibido', + 'Redirecting...': 'Redireccionando...', + 'Search for block, transaction or address': 'Buscar bloques, transacciones o direcciones', + 'See all blocks': 'Ver todos los bloques', + 'Show Transaction Output data': 'Mostrar dato de Salida de la Transacciรณn', + 'Show all': 'Mostrar todos', + 'Show input': 'Mostrar entrada', + 'Show less': 'Ver menos', + 'Show more': 'Ver mรกs', + Size: 'Tamaรฑo', + 'Size (bytes)': 'Tamaรฑo (bytes)', + 'Skipped Blocks (previously synced)': 'Bloques Saltados (previamente sincronizado)', + 'Start Date': 'Fecha de Inicio', + Status: 'Estado', + Summary: 'Resumen', + 'Summary confirmed': 'Resumen confirmados', + 'Sync Progress': 'Proceso de Sincronizaciรณn', + 'Sync Status': 'Estado de Sincronizaciรณn', + 'Sync Type': 'Tipo de Sincronizaciรณn', + 'Synced Blocks': 'Bloques Sincornizados', + Testnet: 'Red de prueba', + 'There are no transactions involving this address.': 'No hay transacciones para esta direcciรณn', + 'Time Offset': 'Desplazamiento de hora', + Timestamp: 'Fecha y hora', + Today: 'Hoy', + 'Total Amount': 'Cantidad Total', + 'Total Received': 'Total Recibido', + 'Total Sent': 'Total Enviado', + Transaction: 'Transacciรณn', + 'Transaction Output Set Information': 'Informaciรณn del Conjunto de Salida de la Transacciรณn', + 'Transaction Outputs': 'Salidas de la Transacciรณn', + Transactions: 'Transacciones', + Type: 'Tipo', + Unconfirmed: 'Sin confirmar', + 'Unconfirmed Transaction!': 'ยกTransacciรณn sin confirmar!', + 'Unconfirmed Txs Balance': 'Balance sin confirmar', + 'Value Out': 'Valor de Salida', + Version: 'Versiรณn', + 'Waiting for blocks...': 'Esperando bloques...', + 'Waiting for transactions...': 'Esperando transacciones...', + 'by date.': 'por fecha.', + 'first seen at': 'Visto a', + mined: 'minado', + 'mined on:': 'minado el:', + 'Waiting for blocks': 'Esperando bloques', + }); + gettextCatalog.setStrings('ja', { + '(Input unconfirmed)': '(ๅ…ฅๅŠ›ใฏๆœชๆคœ่จผใงใ™)', + '404 Page not found :(': '404 ใƒšใƒผใ‚ธใŒใฟใคใ‹ใ‚Šใพใ›ใ‚“ (ยดใƒปฯ‰ใƒป`)', + 'insight is an open-source Merit blockchain explorer with complete REST and websocket APIs that can be used for writing web wallets and other apps that need more advanced blockchain queries than provided by meritd RPC. Check out the source code.': + 'insightใฏใ€meritd RPCใฎๆไพ›ใ™ใ‚‹ใ‚‚ใฎใ‚ˆใ‚Šใ‚‚่ฉณ็ดฐใชใƒ–ใƒญใƒƒใ‚ฏใƒใ‚งใ‚คใƒณใธใฎๅ•ใ„ๅˆใ‚ใ›ใ‚’ๅฟ…่ฆใจใ™ใ‚‹ใ‚ฆใ‚งใƒ–ใ‚ฆใ‚ฉใƒฌใƒƒใƒˆใ‚„ใใฎไป–ใฎใ‚ขใƒ—ใƒชใ‚’ๆ›ธใใฎใซไฝฟใˆใ‚‹ใ€ๅฎŒๅ…จใชRESTใŠใ‚ˆใณwebsocket APIใ‚’ๅ‚™ใˆใŸใ‚ชใƒผใƒ—ใƒณใ‚ฝใƒผใ‚นใฎใƒ“ใƒƒใƒˆใ‚ณใ‚คใƒณใƒ–ใƒญใƒƒใ‚ฏใ‚จใ‚ฏใ‚นใƒ—ใƒญใƒผใƒฉใงใ™ใ€‚ใ‚ฝใƒผใ‚นใ‚ณใƒผใƒ‰ใ‚’็ขบ่ช', + 'insight is still in development, so be sure to report any bugs and provide feedback for improvement at our github issue tracker.': + 'insightใฏ็พๅœจ้–‹็™บไธญใงใ™ใ€‚githubใฎissueใƒˆใƒฉใƒƒใ‚ซใซใฆใƒใ‚ฐใฎๅ ฑๅ‘Šใ‚„ๆ”นๅ–„ๆกˆใฎๆๆกˆใ‚’ใŠ้ก˜ใ„ใ—ใพใ™ใ€‚', + About: 'ใฏใ˜ใ‚ใซ', + Address: 'ใ‚ขใƒ‰ใƒฌใ‚น', + Age: '็”ŸๆˆๅพŒ็ตŒ้Žๆ™‚้–“', + 'An error occured in the verification process.': 'ๆคœ่จผ้Ž็จ‹ใงใ‚จใƒฉใƒผใŒ็™บ็”Ÿใ—ใพใ—ใŸใ€‚', + 'An error occured:
{{error}}': 'ใ‚จใƒฉใƒผใŒ็™บ็”Ÿใ—ใพใ—ใŸ:
{{error}}', + 'Application Status': 'ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใฎ็Šถๆ…‹', + 'Best Block': 'ๆœ€่‰ฏใƒ–ใƒญใƒƒใ‚ฏ', + 'Merit comes with a way of signing arbitrary messages.': + 'Meritใซใฏไปปๆ„ใฎใƒกใƒƒใ‚ปใƒผใ‚ธใ‚’็ฝฒๅใ™ใ‚‹ๆ˜จๆ—ฅใŒๅ‚™ใ‚ใฃใฆใ„ใพใ™ใ€‚', + 'Merit node information': 'MeritใƒŽใƒผใƒ‰ๆƒ…ๅ ฑ', + Block: 'ใƒ–ใƒญใƒƒใ‚ฏ', + 'Block Reward': 'ใƒ–ใƒญใƒƒใ‚ฏๅ ฑ้…ฌ', + Blocks: 'ใƒ–ใƒญใƒƒใ‚ฏ', + 'Broadcast Raw Transaction': '็”Ÿใฎใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ‚’้…ไฟก', + 'Bytes Serialized': 'ใ‚ทใƒชใ‚ขใƒฉใ‚คใ‚บๅพŒใฎๅฎน้‡ (ใƒใ‚คใƒˆ)', + "Can't connect to meritd to get live updates from the p2p network. (Tried connecting to meritd at {{host}}:{{port}} and failed.)": + 'P2Pใƒใƒƒใƒˆใƒฏใƒผใ‚ฏใ‹ใ‚‰ใƒฉใ‚คใƒ–ๆƒ…ๅ ฑใ‚’ๅ–ๅพ—ใ™ใ‚‹ใŸใ‚ใซmeritdใธๆŽฅ็ถšใ™ใ‚‹ใ“ใจใŒใงใใพใ›ใ‚“ใงใ—ใŸใ€‚({{host}}:{{port}} ใธใฎๆŽฅ็ถšใ‚’่ฉฆใฟใพใ—ใŸใŒใ€ๅคฑๆ•—ใ—ใพใ—ใŸใ€‚)', + "Can't connect to insight server. Attempting to reconnect...": + 'insight ใ‚ตใƒผใƒใซๆŽฅ็ถšใงใใพใ›ใ‚“ใ€‚ๅ†ๆŽฅ็ถšใ—ใฆใ„ใพใ™...', + "Can't connect to internet. Please, check your connection.": + 'ใ‚คใƒณใ‚ฟใƒผใƒใƒƒใƒˆใซๆŽฅ็ถšใงใใพใ›ใ‚“ใ€‚ใ‚ณใƒใ‚ฏใ‚ทใƒงใƒณใ‚’็ขบ่ชใ—ใฆใใ ใ•ใ„ใ€‚', + Complete: 'ๅฎŒไบ†', + Confirmations: 'ๆคœ่จผๆ•ฐ', + Conn: 'ๆŽฅ็ถšๆ•ฐ', + 'Connections to other nodes': 'ไป–ใƒŽใƒผใƒ‰ใธใฎๆŽฅ็ถš', + 'Current Blockchain Tip (insight)': '็พๅœจใฎใƒ–ใƒญใƒƒใ‚ฏใƒใ‚งใ‚คใƒณใฎTip (insight)', + 'Current Sync Status': '็พๅœจใฎๅŒๆœŸ็Šถๆณ', + Details: '่ฉณ็ดฐ', + Difficulty: '้›ฃๆ˜“ๅบฆ', + 'Double spent attempt detected. From tx:': 'ไบŒ้‡ๆ”ฏๆ‰•ใ„ๆ”ปๆ’ƒใ‚’ใ“ใฎใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ‹ใ‚‰ๆคœ็Ÿฅใ—ใพใ—ใŸ๏ผš', + 'Error message:': 'ใ‚จใƒฉใƒผใƒกใƒƒใ‚ปใƒผใ‚ธ:', + 'Error!': 'ใ‚จใƒฉใƒผ๏ผ', + Fee: 'ๆ‰‹ๆ•ฐๆ–™', + 'Final Balance': 'ๆœ€็ต‚ๆฎ‹้ซ˜', + 'Finish Date': '็ต‚ไบ†ๆ—ฅๆ™‚', + 'Go to home': 'ใƒ›ใƒผใƒ ใธ', + 'Hash Serialized': 'ใ‚ทใƒชใ‚ขใƒฉใ‚คใ‚บใƒ‡ใƒผใ‚ฟใฎใƒใƒƒใ‚ทใƒฅๅ€ค', + Height: 'ใƒ–ใƒญใƒƒใ‚ฏ้ซ˜', + 'Included in Block': 'ๅ–ใ‚Š่พผใพใ‚ŒใŸใƒ–ใƒญใƒƒใ‚ฏ', + 'Incoherence in levelDB detected:': 'levelDBใฎ็ ดๆใ‚’ๆคœ็Ÿฅใ—ใพใ—ใŸ:', + 'Info Errors': 'ใ‚จใƒฉใƒผๆƒ…ๅ ฑ', + 'Initial Block Chain Height': '่ตทๅ‹•ๆ™‚ใฎใƒ–ใƒญใƒƒใ‚ฏ้ซ˜', + Input: 'ๅ…ฅๅŠ›', + 'Last Block': '็›ดๅ‰ใฎใƒ–ใƒญใƒƒใ‚ฏ', + 'Last Block Hash (Meritd)': '็›ดๅ‰ใฎใƒ–ใƒญใƒƒใ‚ฏใฎใƒใƒƒใ‚ทใƒฅๅ€ค (Meritd)', + 'Latest Blocks': 'ๆœ€ๆ–ฐใฎใƒ–ใƒญใƒƒใ‚ฏ', + 'Latest Transactions': 'ๆœ€ๆ–ฐใฎใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณ', + 'Loading Address Information': 'ใ‚ขใƒ‰ใƒฌใ‚นๆƒ…ๅ ฑใ‚’่ชญใฟ่พผใ‚“ใงใ„ใพใ™', + 'Loading Block Information': 'ใƒ–ใƒญใƒƒใ‚ฏๆƒ…ๅ ฑใ‚’่ชญใฟ่พผใ‚“ใงใ„ใพใ™', + 'Loading Selected Date...': '้ธๆŠžใ•ใ‚ŒใŸใƒ‡ใƒผใ‚ฟใ‚’่ชญใฟ่พผใ‚“ใงใ„ใพใ™...', + 'Loading Transaction Details': 'ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎ่ฉณ็ดฐใ‚’่ชญใฟ่พผใ‚“ใงใ„ใพใ™', + 'Loading Transactions...': 'ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ‚’่ชญใฟ่พผใ‚“ใงใ„ใพใ™...', + 'Loading...': 'ใƒญใƒผใƒ‰ไธญ...', + Message: 'ใƒกใƒƒใ‚ปใƒผใ‚ธ', + 'Mined Time': 'ๆŽกๆŽ˜ๆ™‚ๅˆป', + 'Mined by': 'ๆŽกๆŽ˜่€…', + 'Mining Difficulty': 'ๆŽกๆŽ˜้›ฃๆ˜“ๅบฆ', + 'Next Block': 'ๆฌกใฎใƒ–ใƒญใƒƒใ‚ฏ', + 'No Inputs (Newly Generated Coins)': 'ๅ…ฅๅŠ›ใชใ— (ๆ–ฐใ—ใ็”Ÿๆˆใ•ใ‚ŒใŸใ‚ณใ‚คใƒณ)', + 'No blocks yet.': 'ใƒ–ใƒญใƒƒใ‚ฏใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚', + 'No matching records found!': 'ไธ€่‡ดใ™ใ‚‹ใƒฌใ‚ณใƒผใƒ‰ใฏใ‚ใ‚Šใพใ›ใ‚“๏ผ', + 'No. Transactions': 'ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณๆ•ฐ', + 'Number Of Transactions': 'ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณๆ•ฐ', + Output: 'ๅ‡บๅŠ›', + 'Powered by': 'Powered by', + 'Previous Block': 'ๅ‰ใฎใƒ–ใƒญใƒƒใ‚ฏ', + 'Protocol version': 'ใƒ—ใƒญใƒˆใ‚ณใƒซใƒใƒผใ‚ธใƒงใƒณ', + 'Proxy setting': 'ใƒ—ใƒญใ‚ญใ‚ท่จญๅฎš', + 'Raw transaction data': 'ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎ็”Ÿใƒ‡ใƒผใ‚ฟ', + 'Raw transaction data must be a valid hexadecimal string.': + '็”Ÿใฎใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใƒ‡ใƒผใ‚ฟใฏๆœ‰ๅŠนใช16้€ฒๆ•ฐใงใชใ‘ใ‚Œใฐใ„ใ‘ใพใ›ใ‚“ใ€‚', + 'Received Time': 'ๅ—ไฟกๆ™‚ๅˆป', + 'Redirecting...': 'ใƒชใƒ€ใ‚คใƒฌใ‚ฏใƒˆใ—ใฆใ„ใพใ™...', + 'Search for block, transaction or address': 'ใƒ–ใƒญใƒƒใ‚ฏใ€ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ€ใ‚ขใƒ‰ใƒฌใ‚นใ‚’ๆคœ็ดข', + 'See all blocks': 'ใ™ในใฆใฎใƒ–ใƒญใƒƒใ‚ฏใ‚’ใฟใ‚‹', + 'Send transaction': 'ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ‚’้€ไฟก', + 'Show Transaction Output data': 'ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎๅ‡บๅŠ›ใƒ‡ใƒผใ‚ฟใ‚’ใฟใ‚‹', + 'Show all': 'ใ™ในใฆ่กจ็คบ', + 'Show input': 'ๅ…ฅๅŠ›ใ‚’่กจ็คบ', + 'Show less': '้š ใ™', + 'Show more': '่กจ็คบใ™ใ‚‹', + Signature: '็ฝฒๅ', + Size: 'ใ‚ตใ‚คใ‚บ', + 'Size (bytes)': 'ใ‚ตใ‚คใ‚บ (ใƒใ‚คใƒˆ)', + 'Skipped Blocks (previously synced)': 'ใ‚นใ‚ญใƒƒใƒ—ใ•ใ‚ŒใŸใƒ–ใƒญใƒƒใ‚ฏ (ๅŒๆœŸๆธˆใฟ)', + 'Start Date': '้–‹ๅง‹ๆ—ฅๆ™‚', + Status: 'ใ‚นใƒ†ใƒผใ‚ฟใ‚น', + Summary: 'ๆฆ‚่ฆ', + 'Summary confirmed': 'ใ‚ตใƒžใƒช ๆคœ่จผๆธˆใฟ', + 'Sync Progress': 'ๅŒๆœŸใฎ้€ฒๆ—็Šถๆณ', + 'Sync Status': 'ๅŒๆœŸใ‚นใƒ†ใƒผใ‚ฟใ‚น', + 'Sync Type': 'ๅŒๆœŸใ‚ฟใ‚คใƒ—', + 'Synced Blocks': 'ๅŒๆœŸใ•ใ‚ŒใŸใƒ–ใƒญใƒƒใ‚ฏๆ•ฐ', + Testnet: 'ใƒ†ใ‚นใƒˆใƒใƒƒใƒˆ', + 'The message failed to verify.': 'ใƒกใƒƒใ‚ปใƒผใ‚ธใฎๆคœ่จผใซๅคฑๆ•—ใ—ใพใ—ใŸใ€‚', + 'The message is verifiably from {{verification.address}}.': + 'ใƒกใƒƒใ‚ปใƒผใ‚ธใฏ{{verification.address}}ใซใ‚ˆใ‚Šๆคœ่จผใ•ใ‚Œใพใ—ใŸใ€‚', + 'There are no transactions involving this address.': 'ใ“ใฎใ‚ขใƒ‰ใƒฌใ‚นใซๅฏพใ™ใ‚‹ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚', + 'This form can be used to broadcast a raw transaction in hex format over\n the Merit network.': + 'ใ“ใฎใƒ•ใ‚ฉใƒผใƒ ใงใฏใ€16้€ฒๆ•ฐใƒ•ใ‚ฉใƒผใƒžใƒƒใƒˆใฎ็”Ÿใฎใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ‚’Meritใƒใƒƒใƒˆใƒฏใƒผใ‚ฏไธŠใซ้…ไฟกใ™ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚', + 'This form can be used to verify that a message comes from\n a specific Merit address.': + 'ใ“ใฎใƒ•ใ‚ฉใƒผใƒ ใงใฏใ€ใƒกใƒƒใ‚ปใƒผใ‚ธใŒ็‰นๅฎšใฎMeritใ‚ขใƒ‰ใƒฌใ‚นใ‹ใ‚‰ๆฅใŸใ‹ใฉใ†ใ‹ใ‚’ๆคœ่จผใ™ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚', + 'Time Offset': 'ๆ™‚้–“ใ‚ชใƒ•ใ‚ปใƒƒใƒˆ', + Timestamp: 'ใ‚ฟใ‚คใƒ ใ‚นใ‚ฟใƒณใƒ—', + Today: 'ไปŠๆ—ฅ', + 'Total Amount': 'Merit็ท้‡', + 'Total Received': '็ทๅ…ฅ้‡‘้ก', + 'Total Sent': '็ท้€้‡‘้ก', + Transaction: 'ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณ', + 'Transaction Output Set Information': 'ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎๅ‡บๅŠ›ใ‚ปใƒƒใƒˆๆƒ…ๅ ฑ', + 'Transaction Outputs': 'ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎๅ‡บๅŠ›', + 'Transaction succesfully broadcast.
Transaction id: {{txid}}': + 'ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎ้…ไฟกใซๆˆๅŠŸใ—ใพใ—ใŸใ€‚
ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณID: {{txid}}', + Transactions: 'ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณ', + Type: 'ใ‚ฟใ‚คใƒ—', + Unconfirmed: 'ๆœชๆคœ่จผ', + 'Unconfirmed Transaction!': 'ๆœชๆคœ่จผใฎใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใงใ™๏ผ', + 'Unconfirmed Txs Balance': 'ๆœชๆคœ่จผใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใฎๆฎ‹้ซ˜', + 'Value Out': 'ๅ‡บๅŠ›ๅ€ค', + Verify: 'ๆคœ่จผ', + 'Verify signed message': '็ฝฒๅๆธˆใฟใƒกใƒƒใ‚ปใƒผใ‚ธใ‚’ๆคœ่จผ', + Version: 'ใƒใƒผใ‚ธใƒงใƒณ', + 'Waiting for blocks...': 'ใƒ–ใƒญใƒƒใ‚ฏใ‚’ๅพ…ใฃใฆใ„ใพใ™...', + 'Waiting for transactions...': 'ใƒˆใƒฉใƒณใ‚ถใ‚ฏใ‚ทใƒงใƒณใ‚’ๅพ…ใฃใฆใ„ใพใ™...', + 'by date.': 'ๆ—ฅๆฏŽใ€‚', + 'first seen at': 'ๆœ€ๅˆใซ็™บ่ฆ‹ใ•ใ‚ŒใŸๆ—ฅๆ™‚', + mined: 'ๆŽกๆŽ˜ใ•ใ‚ŒใŸ', + 'mined on:': 'ๆŽกๆŽ˜ๆ—ฅๆ™‚:', + '(Mainchain)': '(ใƒกใ‚คใƒณใƒใ‚งใƒผใƒณ)', + '(Orphaned)': '(ๅญค็ซ‹ใ—ใŸใƒ–ใƒญใƒƒใ‚ฏ)', + Bits: 'Bits', + 'Block #{{block.height}}': 'ใƒ–ใƒญใƒƒใ‚ฏ #{{block.height}}', + BlockHash: 'ใƒ–ใƒญใƒƒใ‚ฏใฎใƒใƒƒใ‚ทใƒฅๅ€ค', + 'Blocks
mined on:': 'ใƒ–ใƒญใƒƒใ‚ฏ
ๆŽกๆŽ˜ๆ—ฅ', + Coinbase: 'ใ‚ณใ‚คใƒณใƒ™ใƒผใ‚น', + Hash: 'ใƒใƒƒใ‚ทใƒฅๅ€ค', + LockTime: 'ใƒญใƒƒใ‚ฏๆ™‚้–“', + 'Merkle Root': 'Merkleใƒซใƒผใƒˆ', + Nonce: 'Nonce', + 'Ooops!': 'ใŠใ‰ใฃใจ๏ผ', + 'Output is spent': 'ๅ‡บๅŠ›ใฏไฝฟ็”จๆธˆใฟใงใ™', + 'Output is unspent': 'ๅ‡บๅŠ›ใฏๆœชไฝฟ็”จใงใ™', + Scan: 'ใ‚นใ‚ญใƒฃใƒณ', + 'Show/Hide items details': 'ใ‚ขใ‚คใƒ†ใƒ ใฎ่ฉณ็ดฐใ‚’่กจ็คบใพใŸใฏ้š ใ™', + 'Waiting for blocks': 'ใƒ–ใƒญใƒƒใ‚ฏใ‚’ๅพ…ใฃใฆใ„ใพใ™', + 'by date. {{detail}} {{before}}': 'ๆ—ฅๆ™‚้ † {{detail}} {{before}}', + scriptSig: 'scriptSig', + '{{tx.confirmations}} Confirmations': '{{tx.confirmations}} ๆคœ่จผ', + ' (Orphaned)': + ' (ๅญค็ซ‹ใ—ใŸใƒ–ใƒญใƒƒใ‚ฏ)', + ' Incoherence in levelDB detected: {{vin.dbError}}': + ' Incoherence in levelDB detected: {{vin.dbError}}', + 'Waiting for blocks ': 'ใƒ–ใƒญใƒƒใ‚ฏใ‚’ๅพ…ใฃใฆใ„ใพใ™ ', + }); + /* jshint +W100 */ + }, +]); diff --git a/packages/lightwallet/common/common-directives.module.ts b/packages/lightwallet/common/common-directives.module.ts index 9cf41ce164..73d295e4f3 100644 --- a/packages/lightwallet/common/common-directives.module.ts +++ b/packages/lightwallet/common/common-directives.module.ts @@ -2,11 +2,7 @@ import { NgModule } from '@angular/core'; import { GtagDirective } from '@merit/common/directives/gtag.directive'; @NgModule({ - declarations: [ - GtagDirective - ], - exports: [ - GtagDirective - ] + declarations: [GtagDirective], + exports: [GtagDirective], }) export class CommonDirectivesModule {} diff --git a/packages/lightwallet/common/common-pipes.module.ts b/packages/lightwallet/common/common-pipes.module.ts index af49fbdc0e..88f33bb6a2 100644 --- a/packages/lightwallet/common/common-pipes.module.ts +++ b/packages/lightwallet/common/common-pipes.module.ts @@ -17,7 +17,7 @@ import { AddressPipe } from '@merit/common/pipes/address.pipe'; UnescapePipe, AddressPipe, AddressErrorMessagePipe, - AliasErrorMessagePipe + AliasErrorMessagePipe, ], exports: [ ChunksPipe, @@ -27,7 +27,7 @@ import { AddressPipe } from '@merit/common/pipes/address.pipe'; UnescapePipe, AddressPipe, AddressErrorMessagePipe, - AliasErrorMessagePipe - ] + AliasErrorMessagePipe, + ], }) export class CommonPipesModule {} diff --git a/packages/lightwallet/common/common-providers.module.ts b/packages/lightwallet/common/common-providers.module.ts index fdda2c6e77..4b547b985f 100644 --- a/packages/lightwallet/common/common-providers.module.ts +++ b/packages/lightwallet/common/common-providers.module.ts @@ -61,8 +61,8 @@ export class CommonProvidersModule { AlertService, GoalsService, SmsNotificationsService, - SocialSharing - ] + SocialSharing, + ], }; } } diff --git a/packages/lightwallet/common/const/wallet-colors.ts b/packages/lightwallet/common/const/wallet-colors.ts index 60e5ff63c7..f22ee76827 100644 --- a/packages/lightwallet/common/const/wallet-colors.ts +++ b/packages/lightwallet/common/const/wallet-colors.ts @@ -1,82 +1,82 @@ export const WalletSettingsColors = [ { name: 'Sunglo', - color: '#E57373' + color: '#E57373', }, { name: 'Carissma', - color: '#E985A7' + color: '#E985A7', }, { name: 'Light Wisteria', - color: '#ca85d6' + color: '#ca85d6', }, { name: 'Lilac Bush', - color: '#A185D4' + color: '#A185D4', }, { name: 'Merit blue', - color: '#00B0DD' + color: '#00B0DD', }, { name: 'Moody Blue', - color: '#7987d1' + color: '#7987d1', }, { name: 'Havelock Blue', - color: '#64aae3' + color: '#64aae3', }, { name: 'Picton Blue', - color: '#53b9e8' + color: '#53b9e8', }, { name: 'Viking', - color: '#4ccdde' + color: '#4ccdde', }, { name: 'Ocean Green', - color: '#48ae6c' + color: '#48ae6c', }, { name: 'Puerto Rico', - color: '#44baad' + color: '#44baad', }, { name: 'Wild Willow', - color: '#99c666' + color: '#99c666', }, { name: 'Turmeric', - color: '#bcc84c' + color: '#bcc84c', }, { name: 'Buttercup', - color: '#f5a623' + color: '#f5a623', }, { name: 'Supernova', - color: '#ffc30e' + color: '#ffc30e', }, { name: 'Yellow Orange', - color: '#ffaf37' + color: '#ffaf37', }, { name: 'Portage', - color: '#8997eb' + color: '#8997eb', }, { name: 'Gray', - color: '#808080' + color: '#808080', }, { name: 'Shuttle Gray', - color: '#5f6c82' + color: '#5f6c82', }, { name: 'Tuna', - color: '#383d43' - } + color: '#383d43', + }, ]; diff --git a/packages/lightwallet/common/directives/gtag.directive.ts b/packages/lightwallet/common/directives/gtag.directive.ts index 3b7f88888d..4aa588c8f0 100644 --- a/packages/lightwallet/common/directives/gtag.directive.ts +++ b/packages/lightwallet/common/directives/gtag.directive.ts @@ -3,13 +3,17 @@ import { Directive, HostListener, Input } from '@angular/core'; declare const gtag: any; @Directive({ - selector: '[gtag]' + selector: '[gtag]', }) export class GtagDirective { - @Input() gtagEvent: string; - @Input() gtagCategory: string; - @Input() gtagAction: string; - @Input() gtagLabel: string; + @Input() + gtagEvent: string; + @Input() + gtagCategory: string; + @Input() + gtagAction: string; + @Input() + gtagLabel: string; @HostListener('click') onClick() { @@ -17,7 +21,7 @@ export class GtagDirective { gtag('event', this.gtagEvent, { event_category: this.gtagCategory, event_action: this.gtagAction, - event_label: this.gtagLabel + event_label: this.gtagLabel, }); } } diff --git a/packages/lightwallet/common/effects/app.effects.ts b/packages/lightwallet/common/effects/app.effects.ts index 6d0e9c056a..b86642ba8f 100644 --- a/packages/lightwallet/common/effects/app.effects.ts +++ b/packages/lightwallet/common/effects/app.effects.ts @@ -9,7 +9,8 @@ import { getQueryParam } from '@merit/common/utils/url'; @Injectable() export class AppEffects { // Take the user to the onboarding page if they delete all wallets - @Effect({ dispatch: false }) update$ = this.actions$.pipe( + @Effect({ dispatch: false }) + update$ = this.actions$.pipe( ofType(AppReducerActionType.UPDATE), filter((action: UpdateAppAction) => !action.payload.authorized), tap(() => { @@ -26,9 +27,8 @@ export class AppEffects { } else if (window.location.pathname.indexOf('/onboarding') !== 0) { this.router.navigateByUrl('/onboarding'); } - }) + }), ); - constructor(private actions$: Actions, private router: Router, private persistence: PersistenceService2) { - } + constructor(private actions$: Actions, private router: Router, private persistence: PersistenceService2) {} } diff --git a/packages/lightwallet/common/effects/goal.effects.ts b/packages/lightwallet/common/effects/goal.effects.ts index 61ebde68b0..992d51a498 100644 --- a/packages/lightwallet/common/effects/goal.effects.ts +++ b/packages/lightwallet/common/effects/goal.effects.ts @@ -6,7 +6,7 @@ import { SaveGoalSettingsAction, SetTaskStatus, UpdateGoalSettingsAction, - UpdateGoalsProgressAction + UpdateGoalsProgressAction, } from '@merit/common/reducers/goals.reducer'; import { GoalsService } from '@merit/common/services/goals.service'; import { Actions, Effect, ofType } from '@ngrx/effects'; @@ -16,43 +16,35 @@ import { debounceTime, map, switchMap, tap } from 'rxjs/operators'; @Injectable() export class GoalEffects { - @Effect() - refreshProgress$: Observable = this.actions$ - .pipe( - ofType(GoalsActionType.RefreshProgress), - debounceTime(500), - switchMap(() => fromPromise(this.goalsService.getProgress())), - map((progress: IFullProgress) => - new UpdateGoalsProgressAction(progress, this.goalsService.statusByTask) - ) - ); + refreshProgress$: Observable = this.actions$.pipe( + ofType(GoalsActionType.RefreshProgress), + debounceTime(500), + switchMap(() => fromPromise(this.goalsService.getProgress())), + map((progress: IFullProgress) => new UpdateGoalsProgressAction(progress, this.goalsService.statusByTask)), + ); @Effect() - refreshSettings$: Observable = this.actions$ - .pipe( - ofType(GoalsActionType.RefreshSettings), - debounceTime(500), - switchMap(() => fromPromise(this.goalsService.getSettings())), - map((settings: IGoalSettings) => new UpdateGoalSettingsAction(settings)) - ); + refreshSettings$: Observable = this.actions$.pipe( + ofType(GoalsActionType.RefreshSettings), + debounceTime(500), + switchMap(() => fromPromise(this.goalsService.getSettings())), + map((settings: IGoalSettings) => new UpdateGoalSettingsAction(settings)), + ); @Effect() - saveSettings$: Observable = this.actions$ - .pipe( - ofType(GoalsActionType.SaveSettings), - switchMap((action: SaveGoalSettingsAction) => fromPromise(this.goalsService.setSettings(action.settings))), - map((settings: IGoalSettings) => new UpdateGoalSettingsAction(settings)) - ); + saveSettings$: Observable = this.actions$.pipe( + ofType(GoalsActionType.SaveSettings), + switchMap((action: SaveGoalSettingsAction) => fromPromise(this.goalsService.setSettings(action.settings))), + map((settings: IGoalSettings) => new UpdateGoalSettingsAction(settings)), + ); @Effect() - setTaskStatus$: Observable = this.actions$ - .pipe( - ofType(GoalsActionType.SetTaskStatus), - switchMap((action: SetTaskStatus) => fromPromise(this.goalsService.setTaskStatus(action.taskSlug, action.status))), - map(() => new RefreshGoalsProgressAction()) - ); + setTaskStatus$: Observable = this.actions$.pipe( + ofType(GoalsActionType.SetTaskStatus), + switchMap((action: SetTaskStatus) => fromPromise(this.goalsService.setTaskStatus(action.taskSlug, action.status))), + map(() => new RefreshGoalsProgressAction()), + ); - constructor(private actions$: Actions, - private goalsService: GoalsService) {} + constructor(private actions$: Actions, private goalsService: GoalsService) {} } diff --git a/packages/lightwallet/common/effects/interface-preferences.effects.ts b/packages/lightwallet/common/effects/interface-preferences.effects.ts index 48f9a58e09..194742c39f 100644 --- a/packages/lightwallet/common/effects/interface-preferences.effects.ts +++ b/packages/lightwallet/common/effects/interface-preferences.effects.ts @@ -4,7 +4,7 @@ import { IRootAppState } from '@merit/common/reducers'; import { InterfaceActionType, selectPrimaryWallet, - SetPrimaryWalletAction + SetPrimaryWalletAction, } from '@merit/common/reducers/interface-preferences.reducer'; import { selectWallets } from '@merit/common/reducers/wallets.reducer'; import { PersistenceService2, UserSettingsKey } from '@merit/common/services/persistence2.service'; @@ -18,78 +18,75 @@ import { of } from 'rxjs/observable/of'; @Injectable() export class InterfacePreferencesEffects { @Effect({ dispatch: false }) - setPrimaryWallet: Observable = this.actions$ - .pipe( - ofType(InterfaceActionType.SetPrimaryWallet), - skip(1), // the init function emits this action, we can skip the first one - switchMap((action: SetPrimaryWalletAction) => { - if (action.primaryWallet) { - return of(action.primaryWallet); - } + setPrimaryWallet: Observable = this.actions$.pipe( + ofType(InterfaceActionType.SetPrimaryWallet), + skip(1), // the init function emits this action, we can skip the first one + switchMap((action: SetPrimaryWalletAction) => { + if (action.primaryWallet) { + return of(action.primaryWallet); + } - return this.store.select(selectWallets) - .pipe( - take(1), - map((wallets: DisplayWallet[]) => - wallets[0] - ) - ); - }), - filter((wallet: DisplayWallet) => !!wallet), - tap((wallet: DisplayWallet) => this.persistenceService.setUserSettings(UserSettingsKey.primaryWalletID, wallet.id)) - ); + return this.store.select(selectWallets).pipe( + take(1), + map((wallets: DisplayWallet[]) => wallets[0]), + ); + }), + filter((wallet: DisplayWallet) => !!wallet), + tap((wallet: DisplayWallet) => this.persistenceService.setUserSettings(UserSettingsKey.primaryWalletID, wallet.id)), + ); @Effect() - refreshPrimaryWallet: Observable = this.actions$ - .pipe( - ofType(InterfaceActionType.RefreshPrimaryWallet), - withLatestFrom(this.store.select(selectPrimaryWallet), this.store.select(selectWallets).pipe(filter(wallets => wallets.length > 0))), - map(([_, primaryWallet, wallets]) => { - if (!primaryWallet) { - const confirmedWallet: DisplayWallet = wallets.find(wallet => wallet.confirmed); + refreshPrimaryWallet: Observable = this.actions$.pipe( + ofType(InterfaceActionType.RefreshPrimaryWallet), + withLatestFrom( + this.store.select(selectPrimaryWallet), + this.store.select(selectWallets).pipe(filter(wallets => wallets.length > 0)), + ), + map(([_, primaryWallet, wallets]) => { + if (!primaryWallet) { + const confirmedWallet: DisplayWallet = wallets.find(wallet => wallet.confirmed); - if (confirmedWallet) { - primaryWallet = confirmedWallet; - } else { - primaryWallet = wallets[0]; - } + if (confirmedWallet) { + primaryWallet = confirmedWallet; + } else { + primaryWallet = wallets[0]; } + } - return new SetPrimaryWalletAction(primaryWallet); - }) - ); + return new SetPrimaryWalletAction(primaryWallet); + }), + ); @Effect() - init$: Observable = fromPromise(this.persistenceService.getUserSettings(UserSettingsKey.primaryWalletID)) - .pipe( - switchMap((walletId: string) => { - return this.store.select(selectWallets) - .pipe( - filter(wallets => wallets.length > 0), - take(1), - map((wallets: DisplayWallet[]) => { - let wallet: DisplayWallet; + init$: Observable = fromPromise(this.persistenceService.getUserSettings(UserSettingsKey.primaryWalletID)).pipe( + switchMap((walletId: string) => { + return this.store.select(selectWallets).pipe( + filter(wallets => wallets.length > 0), + take(1), + map((wallets: DisplayWallet[]) => { + let wallet: DisplayWallet; - if (walletId) { - wallet = wallets.find(wallet => wallet.id === walletId); - } else { - wallet = wallets.find(wallet => wallet.confirmed); - } + if (walletId) { + wallet = wallets.find(wallet => wallet.id === walletId); + } else { + wallet = wallets.find(wallet => wallet.confirmed); + } - if (!wallet) { - wallet = wallets[0]; - } + if (!wallet) { + wallet = wallets[0]; + } - // return any wallet if we don't have a confirmed one - return wallet; - }) - ); - }), - map((wallet: DisplayWallet) => new SetPrimaryWalletAction(wallet)) - ); + // return any wallet if we don't have a confirmed one + return wallet; + }), + ); + }), + map((wallet: DisplayWallet) => new SetPrimaryWalletAction(wallet)), + ); - constructor(private actions$: Actions, - private persistenceService: PersistenceService2, - private store: Store) { - } + constructor( + private actions$: Actions, + private persistenceService: PersistenceService2, + private store: Store, + ) {} } diff --git a/packages/lightwallet/common/effects/notification.effects.ts b/packages/lightwallet/common/effects/notification.effects.ts index 16ce036b33..00f9151e0f 100644 --- a/packages/lightwallet/common/effects/notification.effects.ts +++ b/packages/lightwallet/common/effects/notification.effects.ts @@ -1,13 +1,15 @@ import { Injectable } from '@angular/core'; import { IRootAppState } from '@merit/common/reducers'; import { - AddNotificationAction, formatNotification, + AddNotificationAction, + formatNotification, INotification, - LoadNotificationsAction, MarkNotificationAsReadAction, + LoadNotificationsAction, + MarkNotificationAsReadAction, NotificationsActionType, SaveNotificationsAction, selectNotificationsState, - UpdateNotificationsAction + UpdateNotificationsAction, } from '@merit/common/reducers/notifications.reducer'; import { PersistenceService2 } from '@merit/common/services/persistence2.service'; import { Actions, Effect, ofType } from '@ngrx/effects'; @@ -28,22 +30,28 @@ export class NotificationEffects { */ @Effect() saveWhenNeeded$: Observable = this.actions$.pipe( - ofType(NotificationsActionType.Add, NotificationsActionType.Clear, NotificationsActionType.Delete, NotificationsActionType.MarkAsRead, NotificationsActionType.MarkAllAsRead), - map(() => new SaveNotificationsAction()) + ofType( + NotificationsActionType.Add, + NotificationsActionType.Clear, + NotificationsActionType.Delete, + NotificationsActionType.MarkAsRead, + NotificationsActionType.MarkAllAsRead, + ), + map(() => new SaveNotificationsAction()), ); @Effect() load$: Observable = this.actions$.pipe( ofType(NotificationsActionType.Load), switchMap(() => fromPromise(this.persistenceService.getNotifications())), - map((notifications: INotification[]) => new UpdateNotificationsAction(notifications)) + map((notifications: INotification[]) => new UpdateNotificationsAction(notifications)), ); @Effect({ dispatch: false }) save$ = this.actions$.pipe( ofType(NotificationsActionType.Save), withLatestFrom(this.store.select(selectNotificationsState)), - map(([action, notifications]) => this.persistenceService.setNotifications(notifications.notifications)) + map(([action, notifications]) => this.persistenceService.setNotifications(notifications.notifications)), ); @Effect({ dispatch: false }) @@ -66,17 +74,15 @@ export class NotificationEffects { const toast = this.toastCtrl.create({ title: notification.title, message: notification.message, - cssClass: 'success' + cssClass: 'success', }); toast.onDidDismiss = () => this.store.dispatch(new MarkNotificationAsReadAction(notification.id)); - }) + }), ); @Effect() - loadOnFocus$ = fromEvent(window, 'focus').pipe( - map(() => new LoadNotificationsAction()) - ); + loadOnFocus$ = fromEvent(window, 'focus').pipe(map(() => new LoadNotificationsAction())); /** * Load notifications from storage on startup @@ -85,9 +91,10 @@ export class NotificationEffects { @Effect() init$ = of(new LoadNotificationsAction()); - constructor(private actions$: Actions, - private store: Store, - private persistenceService: PersistenceService2, - private toastCtrl: ToastControllerService) { - } + constructor( + private actions$: Actions, + private store: Store, + private persistenceService: PersistenceService2, + private toastCtrl: ToastControllerService, + ) {} } diff --git a/packages/lightwallet/common/effects/transaction.effects.ts b/packages/lightwallet/common/effects/transaction.effects.ts index e908c6a04d..ad4894c18b 100644 --- a/packages/lightwallet/common/effects/transaction.effects.ts +++ b/packages/lightwallet/common/effects/transaction.effects.ts @@ -7,14 +7,14 @@ import { RefreshTransactionsAction, TransactionActionType, UpdateOneWalletTransactions, - UpdateTransactionsAction + UpdateTransactionsAction, } from '@merit/common/reducers/transactions.reducer'; import { AddWalletAction, selectWalletById, selectWallets, UpdateOneWalletAction, - WalletsActionType + WalletsActionType, } from '@merit/common/reducers/wallets.reducer'; import { PersistenceService2 } from '@merit/common/services/persistence2.service'; import { WalletService } from '@merit/common/services/wallet.service'; @@ -32,13 +32,13 @@ export class TransactionEffects { @Effect() refreshOnWalletRefresh$: Observable = this.actions$.pipe( ofType(WalletsActionType.Add), - map((action: AddWalletAction) => new RefreshOneWalletTransactions(action.wallet.id)) + map((action: AddWalletAction) => new RefreshOneWalletTransactions(action.wallet.id)), ); @Effect() refreshOnWalletsRefresh$: Observable = this.actions$.pipe( ofType(WalletsActionType.Update, WalletsActionType.DeleteWallet), - map(() => new RefreshTransactionsAction()) + map(() => new RefreshTransactionsAction()), ); @Effect() @@ -46,20 +46,19 @@ export class TransactionEffects { ofType(TransactionActionType.Refresh), withLatestFrom(this.store.select(selectWallets)), switchMap(([action, wallets]) => Observable.fromPromise(Promise.all(wallets.map(w => this.getWalletHistory(w))))), - map((transactionsList: IDisplayTransaction[][]) => new UpdateTransactionsAction(flatten(transactionsList))) + map((transactionsList: IDisplayTransaction[][]) => new UpdateTransactionsAction(flatten(transactionsList))), ); @Effect() refreshOne$: Observable = this.actions$.pipe( ofType(TransactionActionType.RefreshOne), switchMap((action: RefreshOneWalletTransactions) => - this.store.select(selectWalletById(action.walletId)) - .pipe( - take(1), - switchMap((wallet: DisplayWallet) => Observable.fromPromise(this.getWalletHistory(wallet))), - map((transactions: IDisplayTransaction[]) => new UpdateOneWalletTransactions(action.walletId, transactions)) - ) - ) + this.store.select(selectWalletById(action.walletId)).pipe( + take(1), + switchMap((wallet: DisplayWallet) => Observable.fromPromise(this.getWalletHistory(wallet))), + map((transactions: IDisplayTransaction[]) => new UpdateOneWalletTransactions(action.walletId, transactions)), + ), + ), ); @Effect() @@ -68,21 +67,20 @@ export class TransactionEffects { filter((action: UpdateOneWalletAction) => !action.opts.skipStatus), map((action: UpdateOneWalletAction) => action.wallet), distinctUntilKeyChanged('status'), - map((wallet: DisplayWallet) => new RefreshOneWalletTransactions(wallet.id)) + map((wallet: DisplayWallet) => new RefreshOneWalletTransactions(wallet.id)), ); - constructor(private actions$: Actions, - private walletService: WalletService, - private store: Store, - private persistenceService: PersistenceService2, - private feeService: FeeService - ) { - } + constructor( + private actions$: Actions, + private walletService: WalletService, + private store: Store, + private persistenceService: PersistenceService2, + private feeService: FeeService, + ) {} private async getWalletHistory(wallet: DisplayWallet): Promise { const walletHistory = await wallet.client.getTxHistory({ includeExtendedInfo: true }); // TODO (ibby: add this and do infinite loading --> { skip: 0, limit: 50, includeExtendedInfo: true } ) const easySends = await this.persistenceService.getEasySends(); return formatWalletHistory(walletHistory, wallet.client, easySends, this.feeService, null, this.persistenceService); } - } diff --git a/packages/lightwallet/common/effects/wallet.effects.ts b/packages/lightwallet/common/effects/wallet.effects.ts index 4da30fb1af..dcd40a18e5 100644 --- a/packages/lightwallet/common/effects/wallet.effects.ts +++ b/packages/lightwallet/common/effects/wallet.effects.ts @@ -47,11 +47,10 @@ export class WalletEffects { refreshOne$: Observable = this.actions$.pipe( ofType(WalletsActionType.RefreshOne), switchMap((action: RefreshOneWalletAction) => - this.store.select(selectWalletById(action.walletId)) - .pipe( - take(1), - switchMap((wallet: DisplayWallet) => fromPromise(updateDisplayWallet(wallet, action.opts))), - ), + this.store.select(selectWalletById(action.walletId)).pipe( + take(1), + switchMap((wallet: DisplayWallet) => fromPromise(updateDisplayWallet(wallet, action.opts))), + ), ), map((wallet: DisplayWallet) => new UpdateOneWalletAction(wallet)), ); @@ -59,20 +58,30 @@ export class WalletEffects { // TODO(ibby): update totals only if the numbers we depend on changed --> use distinct/distinctUntilChanged operators @Effect() updateTotals$: Observable = this.actions$.pipe( - ofType(WalletsActionType.Update, WalletsActionType.UpdateOne, WalletsActionType.Add, WalletsActionType.DeleteWallet), + ofType( + WalletsActionType.Update, + WalletsActionType.UpdateOne, + WalletsActionType.Add, + WalletsActionType.DeleteWallet, + ), withLatestFrom(this.store.select(selectWallets)), map(([action, wallets]) => new UpdateWalletTotalsAction(this.calculateTotals(wallets))), ); @Effect() updateInviteRequests$: Observable = this.actions$.pipe( - ofType(WalletsActionType.UpdateOne, WalletsActionType.Update, WalletsActionType.Add, WalletsActionType.DeleteWallet), + ofType( + WalletsActionType.UpdateOne, + WalletsActionType.Update, + WalletsActionType.Add, + WalletsActionType.DeleteWallet, + ), withLatestFrom(this.store.select(selectWallets)), map(([action, wallets]) => wallets.reduce((requests, wallet) => requests.concat(wallet.inviteRequests), [])), withLatestFrom(fromPromise(this.persistenceService.getHiddenUnlockRequestsAddresses())), map(([inviteRequests, hiddenAddresses]) => { const hiddenAddressesMap = {}; - hiddenAddresses.forEach(address => hiddenAddressesMap[address] = true); + hiddenAddresses.forEach(address => (hiddenAddressesMap[address] = true)); return inviteRequests.filter(request => !hiddenAddressesMap[request.address]); }), map((inviteRequests: any[]) => new UpdateInviteRequestsAction(inviteRequests)), @@ -86,9 +95,11 @@ export class WalletEffects { map((args: any[]) => args[1].map((wallet: DisplayWallet) => wallet.exportPreferences())), distinctUntilChanged(), skip(1), - switchMap((preferences: any[]) => fromPromise( - Promise.all(preferences.map(this.persistenceService2.saveWalletPreferences.bind(this.persistenceService2))), - )), + switchMap((preferences: any[]) => + fromPromise( + Promise.all(preferences.map(this.persistenceService2.saveWalletPreferences.bind(this.persistenceService2))), + ), + ), ); @Effect() @@ -96,24 +107,20 @@ export class WalletEffects { ofType(WalletsActionType.DeleteWallet), switchMap((action: DeleteWalletAction) => this.store.select(selectWalletById(action.walletId)).pipe(take(1))), switchMap((wallet: DisplayWallet) => - fromPromise( - this.profileService.deleteWallet(wallet.client) - .then(() => this.profileService.isAuthorized()), - ) - .pipe( - tap(async (authorized: boolean) => { - if (!authorized) { - await this.storage.clear(); - this.router.navigateByUrl('/onboarding'); - } else { - this.router.navigateByUrl('/wallets'); - } - }), - mergeMap((authorized: boolean) => [ - new UpdateAppAction({ authorized }), - new DeleteWalletCompletedAction(wallet.id), - ]), - ), + fromPromise(this.profileService.deleteWallet(wallet.client).then(() => this.profileService.isAuthorized())).pipe( + tap(async (authorized: boolean) => { + if (!authorized) { + await this.storage.clear(); + this.router.navigateByUrl('/onboarding'); + } else { + this.router.navigateByUrl('/wallets'); + } + }), + mergeMap((authorized: boolean) => [ + new UpdateAppAction({ authorized }), + new DeleteWalletCompletedAction(wallet.id), + ]), + ), ), ); @@ -121,34 +128,39 @@ export class WalletEffects { ignoreInviteRequest$: Observable = this.actions$.pipe( ofType(WalletsActionType.IgnoreInviteRequest), switchMap((action: IgnoreInviteRequestAction) => - fromPromise( - this.persistenceService.hideUnlockRequestAddress(action.address) - .then(() => action.address), - ), + fromPromise(this.persistenceService.hideUnlockRequestAddress(action.address).then(() => action.address)), ), withLatestFrom(this.store.select(selectInviteRequests)), - map(([address, inviteRequests]) => - new UpdateInviteRequestsAction(inviteRequests.filter(req => req.address !== address)), + map( + ([address, inviteRequests]) => + new UpdateInviteRequestsAction(inviteRequests.filter(req => req.address !== address)), ), ); - constructor(private actions$: Actions, - private walletService: WalletService, - private addressService: AddressService, - private profileService: ProfileService, - private txFormatService: TxFormatService, - private store: Store, - private persistenceService: PersistenceService, - private persistenceService2: PersistenceService2, - private storage: Storage, - private router: Router) { - } + constructor( + private actions$: Actions, + private walletService: WalletService, + private addressService: AddressService, + private profileService: ProfileService, + private txFormatService: TxFormatService, + private store: Store, + private persistenceService: PersistenceService, + private persistenceService2: PersistenceService2, + private storage: Storage, + private router: Router, + ) {} private async updateAllWallets(): Promise { const wallets = await this.profileService.getWallets(); return Promise.all( wallets.map(async w => { - const displayWallet = await createDisplayWallet(w, this.walletService, this.addressService, this.txFormatService, this.persistenceService2); + const displayWallet = await createDisplayWallet( + w, + this.walletService, + this.addressService, + this.txFormatService, + this.persistenceService2, + ); displayWallet.importPreferences(await this.persistenceService2.getWalletPreferences(displayWallet.id)); await this.updateVisitedInviteRequests(displayWallet.inviteRequests); return displayWallet; @@ -157,7 +169,7 @@ export class WalletEffects { } private async updateVisitedInviteRequests(inviteRequests: IUnlockRequest[]) { - const visitedInvites = await this.persistenceService2.getVisitedInvites() || []; + const visitedInvites = (await this.persistenceService2.getVisitedInvites()) || []; let updateVisitedInvites; inviteRequests.forEach(request => { diff --git a/packages/lightwallet/common/environments/environment.example.ts b/packages/lightwallet/common/environments/environment.example.ts index cc81995f14..d4aae357f6 100644 --- a/packages/lightwallet/common/environments/environment.example.ts +++ b/packages/lightwallet/common/environments/environment.example.ts @@ -13,6 +13,6 @@ export const ENV = { fbSDK: { appId: '2165982346808447', status: true, - version: 'v2.7' - } + version: 'v2.7', + }, }; diff --git a/packages/lightwallet/common/environments/environment.prod.ts b/packages/lightwallet/common/environments/environment.prod.ts index 6391358ee1..7998c00fa3 100644 --- a/packages/lightwallet/common/environments/environment.prod.ts +++ b/packages/lightwallet/common/environments/environment.prod.ts @@ -13,6 +13,6 @@ export const ENV = { fbSDK: { appId: '301300700672655', status: true, - version: 'v2.7' - } + version: 'v2.7', + }, }; diff --git a/packages/lightwallet/common/environments/environment.staging.ts b/packages/lightwallet/common/environments/environment.staging.ts index a9f8eda0a6..cd3a657b56 100644 --- a/packages/lightwallet/common/environments/environment.staging.ts +++ b/packages/lightwallet/common/environments/environment.staging.ts @@ -13,6 +13,6 @@ export const ENV = { fbSDK: { appId: '335944163815670', status: true, - version: 'v2.7' - } + version: 'v2.7', + }, }; diff --git a/packages/lightwallet/common/merit-market-client/api.ts b/packages/lightwallet/common/merit-market-client/api.ts index c7679fc55e..22b194aa0d 100644 --- a/packages/lightwallet/common/merit-market-client/api.ts +++ b/packages/lightwallet/common/merit-market-client/api.ts @@ -72,7 +72,7 @@ export class MeritMarketClient { */ isPrivKeyEncrypted(): any { return this.credentials && this.credentials.isPrivKeyEncrypted(); - }; + } /** * Returns unencrypted extended private key and mnemonics @@ -81,8 +81,7 @@ export class MeritMarketClient { */ getKeys(password: string): any { return this.credentials.getKeys(password); - }; - + } /** * Checks is password is valid @@ -99,7 +98,7 @@ export class MeritMarketClient { } catch (e) { return false; } - }; + } /** * Do a GET request @@ -109,8 +108,8 @@ export class MeritMarketClient { * @param {Callback} cb */ _doGetRequest(url: string): Promise { - return this._doRequest('get', url, {}).then((res) => res.body); - }; + return this._doRequest('get', url, {}).then(res => res.body); + } /** * Do a POST request @@ -122,7 +121,7 @@ export class MeritMarketClient { */ _doPostRequest(url: string, args: any = {}): Promise { return this._doRequest('post', url, args).then(res => res.body); - }; + } /** * Do an HTTP request @@ -137,10 +136,7 @@ export class MeritMarketClient { let headers = {}; if (this.credentials) { - const privkey = this.credentials - .getDerivedXPrivKey(args.password) - .deriveChild('m/0/0') - .privateKey; + const privkey = this.credentials.getDerivedXPrivKey(args.password).deriveChild('m/0/0').privateKey; const debug = !ENV.production; const [sig, ts] = this._signRequest(url, privkey, debug); diff --git a/packages/lightwallet/common/merit-wallet-client/index.ts b/packages/lightwallet/common/merit-wallet-client/index.ts index e122ee120e..fb62dd1f91 100644 --- a/packages/lightwallet/common/merit-wallet-client/index.ts +++ b/packages/lightwallet/common/merit-wallet-client/index.ts @@ -6,17 +6,16 @@ export class MeritWalletClient extends MeritClient { private static _instance: MeritWalletClient; public errors; - private constructor(opts:any = {}) { + private constructor(opts: any = {}) { super(opts); this.errors = BwcError; this.color = this.color || '#00B0DD'; this.name = this.name || 'Personal wallet'; } - public static getInstance(opts:any = {}): MeritWalletClient { - return (this._instance || new MeritWalletClient(opts)); + public static getInstance(opts: any = {}): MeritWalletClient { + return this._instance || new MeritWalletClient(opts); } } - // Errors thrown by the library diff --git a/packages/lightwallet/common/merit-wallet-client/lib/api.ts b/packages/lightwallet/common/merit-wallet-client/lib/api.ts index 5a9a442459..18502001ed 100644 --- a/packages/lightwallet/common/merit-wallet-client/lib/api.ts +++ b/packages/lightwallet/common/merit-wallet-client/lib/api.ts @@ -50,7 +50,7 @@ export interface InitOptions { export enum AddressType { PubKey = 1, Script, - ParameterizedScript + ParameterizedScript, } export interface ISendReferralOptions { @@ -71,7 +71,7 @@ export class API { public timeout: number; public logLevel: string; public privateKeyEncryptionOpts: any = { - iter: 10000 + iter: 10000, }; public credentials: Credentials; // TODO: Make public with getters/setters public notificationIncludeOwn: boolean; @@ -149,7 +149,6 @@ export class API { this.log.info('Hello Merit Wallet Client!'); } - // Do we need an initialize now? Constructor should be able to handle. initialize(notificationIncludeOwn?: boolean) { $.checkState(this.credentials); @@ -171,33 +170,29 @@ export class API { async _fetchLatestNotifications(interval: number): Promise { let opts: any = { lastNotificationId: this.lastNotificationId, - includeOwn: this.notificationIncludeOwn + includeOwn: this.notificationIncludeOwn, }; - if (!this.lastNotificationId) - opts.timeSpan = interval + 1; + if (!this.lastNotificationId) opts.timeSpan = interval + 1; const notifications = await this.getNotifications(opts); - if (notifications && notifications.length > 0) - this.lastNotificationId = notifications[notifications.length - 1].id; - + if (notifications && notifications.length > 0) this.lastNotificationId = notifications[notifications.length - 1].id; return notifications; } initNotifications(): Observable { - return interval(this.noticitationPollingInterval * 1000) - .pipe( - switchMap(() => fromPromise(this._fetchLatestNotifications(this.noticitationPollingInterval))), - retryWhen(err => - err.pipe( - map((err) => { - return !err || (err !== MWCErrors.NOT_FOUND && err !== MWCErrors.NOT_AUTHORIZED); - }) - ) - ) - ); + return interval(this.noticitationPollingInterval * 1000).pipe( + switchMap(() => fromPromise(this._fetchLatestNotifications(this.noticitationPollingInterval))), + retryWhen(err => + err.pipe( + map(err => { + return !err || (err !== MWCErrors.NOT_FOUND && err !== MWCErrors.NOT_AUTHORIZED); + }), + ), + ), + ); } /** @@ -233,7 +228,7 @@ export class API { _processTxNotes(notes): void { if (!notes) return; let encryptingKey = this.credentials.sharedEncryptingKey; - notes.forEach((note) => { + notes.forEach(note => { note.encryptedBody = note.body; note.body = this._decryptMessage(note.body, encryptingKey); note.encryptedEditedByName = note.editedByName; @@ -299,7 +294,7 @@ export class API { body = JSON.parse(body); } catch (e) { body = { - error: body + error: body, }; } } @@ -316,7 +311,7 @@ export class API { } this.log.error(ret); return ret; - } + }; /** * Sign an HTTP request @@ -328,11 +323,10 @@ export class API { * @param {Object} args - The arguments in case this is a POST/PUT request * @param {String} privKey - Private key to sign the request */ - private _signRequest = function (method, url, args, privKey) { + private _signRequest = function(method, url, args, privKey) { let message = [method.toLowerCase(), url, JSON.stringify(args)].join('|'); return Utils.signMessage(message, privKey); - } - + }; /** * Seed from random @@ -348,7 +342,6 @@ export class API { this.credentials = Credentials.create(opts.network || 'livenet'); } - /** * Seed from random * @@ -358,7 +351,6 @@ export class API { */ validateKeyDerivation(opts: any): Promise { return new Promise((resolve, reject) => { - let _deviceValidated: boolean; opts = opts || {}; @@ -367,7 +359,8 @@ export class API { function testMessageSigning(xpriv, xpub) { let nonHardenedPath = 'm/0/0'; - let message = 'Lorem ipsum dolor sit amet, ne amet urbanitas percipitur vim, libris disputando his ne, et facer suavitate qui. Ei quidam laoreet sea. Cu pro dico aliquip gubergren, in mundi postea usu. Ad labitur posidonium interesset duo, est et doctus molestie adipiscing.'; + let message = + 'Lorem ipsum dolor sit amet, ne amet urbanitas percipitur vim, libris disputando his ne, et facer suavitate qui. Ei quidam laoreet sea. Cu pro dico aliquip gubergren, in mundi postea usu. Ad labitur posidonium interesset duo, est et doctus molestie adipiscing.'; let priv = xpriv.deriveChild(nonHardenedPath).privateKey; let signature = Utils.signMessage(message, priv); let pub = xpub.deriveChild(nonHardenedPath).publicKey; @@ -378,12 +371,22 @@ export class API { let words = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; let xpriv = mnemonicToHDPrivateKey(words, '', c.network).toHDPrivateKey(); - if (xpriv.toString() != 'xprv9s21ZrQH143K2jHFB1HM4GNbVaBSSnjHDQP8uBtKKTvusxMirfmKEmaUS4fkwqeoLqVVT2ShayUSmnEZNV1AKqTSESqyAFCBW8nvEqKfvGy') return false; + if ( + xpriv.toString() != + 'xprv9s21ZrQH143K2jHFB1HM4GNbVaBSSnjHDQP8uBtKKTvusxMirfmKEmaUS4fkwqeoLqVVT2ShayUSmnEZNV1AKqTSESqyAFCBW8nvEqKfvGy' + ) + return false; - xpriv = xpriv.deriveChild('m/44\'/0\'/0\''); - if (xpriv.toString() != 'xprv9ynVfpDwjVTeyQALCLp4EVHwonHHoE37DoUkjsj6A5vxXK1Wh6YEQVPdgdGdtvqWttM4nqgxK8kgmmRD5yfKhWGbD75JGdsDb9yMtozdVc6') return false; + xpriv = xpriv.deriveChild("m/44'/0'/0'"); + if ( + xpriv.toString() != + 'xprv9ynVfpDwjVTeyQALCLp4EVHwonHHoE37DoUkjsj6A5vxXK1Wh6YEQVPdgdGdtvqWttM4nqgxK8kgmmRD5yfKhWGbD75JGdsDb9yMtozdVc6' + ) + return false; - let xpub = Meritcore.HDPublicKey.fromString('xpub6Cmr5KkqZs1xBtEoJNM4bdEgMp7nCgkxb2QMYG8hiRTwQ7LfEdrUxHi7XrjNxkeuRrNSqHLXHAuwZvqoeASrp5jxjnpMa4d8PFpA9TRxVCd'); + let xpub = Meritcore.HDPublicKey.fromString( + 'xpub6Cmr5KkqZs1xBtEoJNM4bdEgMp7nCgkxb2QMYG8hiRTwQ7LfEdrUxHi7XrjNxkeuRrNSqHLXHAuwZvqoeASrp5jxjnpMa4d8PFpA9TRxVCd', + ); return testMessageSigning(xpriv, xpub); } @@ -391,12 +394,11 @@ export class API { let words; try { words = c.getMnemonic(); - } catch (ex) { - } + } catch (ex) {} let xpriv; if (words && (!c.mnemonicHasPassphrase || opts.passphrase)) { - let m: string = generateMnemonic(); + let m: string = generateMnemonic(); xpriv = mnemonicToHDPrivateKey(m, opts.passphrase, c.network).toString(); } if (!xpriv) { @@ -414,13 +416,13 @@ export class API { _deviceValidated = true; } - let liveOk = (c.canSign() && !c.isPrivKeyEncrypted()) ? testLiveKeys() : true; + let liveOk = c.canSign() && !c.isPrivKeyEncrypted() ? testLiveKeys() : true; this.keyDerivationOk = hardcodedOk && liveOk; return resolve(this.keyDerivationOk); }); - }; + } /** * Seed from random with mnemonic @@ -435,8 +437,12 @@ export class API { $.checkArgument(arguments.length <= 1, 'DEPRECATED: only 1 argument accepted.'); $.checkArgument(_.isUndefined(opts) || _.isObject(opts), 'DEPRECATED: argument should be an options object.'); - this.credentials = Credentials.createWithMnemonic(opts.network || 'livenet', opts.passphrase, opts.language || 'en', opts.account || 0); - + this.credentials = Credentials.createWithMnemonic( + opts.network || 'livenet', + opts.passphrase, + opts.language || 'en', + opts.account || 0, + ); } getMnemonic(): any { @@ -447,7 +453,6 @@ export class API { return this.credentials.mnemonicHasPassphrase; } - clearMnemonic(): any { return this.credentials.clearMnemonic(); } @@ -462,7 +467,10 @@ export class API { getRootAddress() { if (this.rootAddress) return this.rootAddress; const xpub = new Meritcore.HDPublicKey(this.credentials.xPubKey); - return this.rootAddress = Meritcore.Address.fromPublicKey(xpub.deriveChild('m/0/0').publicKey, this.credentials.network); + return (this.rootAddress = Meritcore.Address.fromPublicKey( + xpub.deriveChild('m/0/0').publicKey, + this.credentials.network, + )); } getRootAddressPubkey() { @@ -484,7 +492,12 @@ export class API { * @param {String} opts.derivationStrategy - default 'BIP44' */ seedFromExtendedPrivateKey(xPrivKey: any, opts: any = {}): void { - this.credentials = Credentials.fromExtendedPrivateKey(xPrivKey, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44, opts); + this.credentials = Credentials.fromExtendedPrivateKey( + xPrivKey, + opts.account || 0, + opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44, + opts, + ); } /** @@ -499,7 +512,14 @@ export class API { * @param {String} opts.derivationStrategy - default 'BIP44' */ seedFromMnemonic(words: Array, opts: any = {}): any { - this.credentials = Credentials.fromMnemonic(opts.network || 'livenet', words, opts.passphrase, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44, opts); + this.credentials = Credentials.fromMnemonic( + opts.network || 'livenet', + words, + opts.passphrase, + opts.account || 0, + opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44, + opts, + ); } /** @@ -514,13 +534,19 @@ export class API { * @param {String} opts.derivationStrategy - default 'BIP44' */ seedFromExtendedPublicKey(xPubKey: any, source: any, entropySourceHex: any, opts: any = {}): any { - this.credentials = Credentials.fromExtendedPublicKey(xPubKey, source, entropySourceHex, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44); + this.credentials = Credentials.fromExtendedPublicKey( + xPubKey, + source, + entropySourceHex, + opts.account || 0, + opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44, + ); } static fromObj(obj) { let wallet = new this({ baseUrl: obj.baseUrl || ENV.mwsUrl, - timeout: 100000 + timeout: 100000, }); wallet.import(obj.credentials); @@ -542,7 +568,6 @@ export class API { } toObj() { - return { credentials: this.export(), name: this.name, @@ -567,9 +592,9 @@ export class API { coins: v.coins, masterPubKey: v.masterPubKey, status: v.status, - whitelist: v.whitelist + whitelist: v.whitelist, }; - }) + }), }; } @@ -615,17 +640,14 @@ export class API { } async _import(): Promise { - $.checkState(this.credentials); try { return await this.openWallet(); } catch (e) { - if (e.code != 'NOT_AUTHORIZED') { throw e; } else { - const walletPrivKey = new Meritcore.PrivateKey(void 0, this.credentials.network); const pubkey = walletPrivKey.toPublicKey(); this.credentials.addWalletPrivateKey(walletPrivKey.toString()); @@ -635,7 +657,7 @@ export class API { m: 1, n: 1, walletName: 'Personal Wallet', - copayerName: 'me' + copayerName: 'me', }; //call 'recreate wallet' method to create wallet instance with exision @@ -647,7 +669,7 @@ export class API { pubKey: pubkey.toString(), rootAddress: rootAddress.toString(), network: this.credentials.network, - singleAddress: true //daedalus wallets are single-addressed + singleAddress: true, //daedalus wallets are single-addressed }; let res = await this._doPostRequest('/v1/recreate_wallet/', args); @@ -655,9 +677,23 @@ export class API { if (res) { let walletId = res.walletId; let parentAddress = res.parentAddress; - this.credentials.addWalletInfo(walletId, defaultOpts.walletName, defaultOpts.m, defaultOpts.n, defaultOpts.copayerName, parentAddress); - - return this.doJoinWallet(walletId, walletPrivKey, this.credentials.xPubKey, this.credentials.requestPubKey, defaultOpts.copayerName, {}); + this.credentials.addWalletInfo( + walletId, + defaultOpts.walletName, + defaultOpts.m, + defaultOpts.n, + defaultOpts.copayerName, + parentAddress, + ); + + return this.doJoinWallet( + walletId, + walletPrivKey, + this.credentials.xPubKey, + this.credentials.requestPubKey, + defaultOpts.copayerName, + {}, + ); } else { throw new Error('failed to recreate wallet'); } @@ -682,10 +718,17 @@ export class API { this.log.debug('Importing from 12 Words'); function derive(nonCompliantDerivation) { - return Credentials.fromMnemonic(opts.network || 'livenet', words, opts.passphrase, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44, { - nonCompliantDerivation: nonCompliantDerivation, - entropySourcePath: opts.entropySourcePath - }); + return Credentials.fromMnemonic( + opts.network || 'livenet', + words, + opts.passphrase, + opts.account || 0, + opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44, + { + nonCompliantDerivation: nonCompliantDerivation, + entropySourcePath: opts.entropySourcePath, + }, + ); } try { @@ -698,7 +741,6 @@ export class API { return this._import().catch(err => { if (err == MWCErrors.INVALID_BACKUP) return Promise.reject(err); if (err == MWCErrors.NOT_AUTHORIZED || err == MWCErrors.WALLET_DOES_NOT_EXIST) { - let altCredentials = derive(true); if (altCredentials.xPubKey.toString() == this.credentials.xPubKey.toString()) return Promise.reject(err); this.credentials = altCredentials; @@ -706,7 +748,6 @@ export class API { } return Promise.reject(err); }); - } /* @@ -721,7 +762,11 @@ export class API { this.log.debug('Importing from Extended Private Key'); try { - this.credentials = Credentials.fromExtendedPrivateKey(xPrivKey, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44); + this.credentials = Credentials.fromExtendedPrivateKey( + xPrivKey, + opts.account || 0, + opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44, + ); } catch (e) { this.log.info('xPriv error:', e); return new Promise((resolve, reject) => { @@ -748,7 +793,13 @@ export class API { this.log.debug('Importing from Extended Private Key'); try { - this.credentials = Credentials.fromExtendedPublicKey(xPubKey, source, entropySourceHex, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44); + this.credentials = Credentials.fromExtendedPublicKey( + xPubKey, + source, + entropySourceHex, + opts.account || 0, + opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44, + ); } catch (e) { this.log.info('xPriv error:', e); return new Promise((resolve, reject) => { @@ -757,11 +808,10 @@ export class API { } return this._import(); - }; + } decryptBIP38PrivateKey(encryptedPrivateKeyBase58: any, passphrase: string, opts: any = {}): Promise { return new Promise((resolve, reject) => { - let bip38 = new Bip38(); let privateKeyWif; @@ -774,29 +824,30 @@ export class API { let privateKey = new Meritcore.PrivateKey(privateKeyWif, 'livenet'); let address = privateKey.publicKey.toAddress().toString(); let addrBuff = new Buffer(address, 'ascii'); - let actualChecksum = Meritcore.crypto.Hash.sha256sha256(addrBuff).toString('hex').substring(0, 8); - let expectedChecksum = Meritcore.encoding.Base58Check.decode(encryptedPrivateKeyBase58).toString('hex').substring(6, 14); + let actualChecksum = Meritcore.crypto.Hash.sha256sha256(addrBuff) + .toString('hex') + .substring(0, 8); + let expectedChecksum = Meritcore.encoding.Base58Check.decode(encryptedPrivateKeyBase58) + .toString('hex') + .substring(6, 14); - if (actualChecksum != expectedChecksum) - return reject(new Error('Incorrect passphrase')); + if (actualChecksum != expectedChecksum) return reject(new Error('Incorrect passphrase')); return resolve(privateKeyWif); }); - }; - + } getBalanceFromPrivateKey(_privateKey: string): Promise { return new Promise((resolve, reject) => { - let privateKey = new Meritcore.PrivateKey(_privateKey); let address = privateKey.publicKey.toAddress(); return this.getUtxos({ - addresses: address.toString() - }).then((utxos) => { + addresses: address.toString(), + }).then(utxos => { return resolve(_.sumBy(utxos, 'micros')); }); }); - }; + } buildTxFromPrivateKey(_privateKey: any, destinationAddress: any, opts: any = {}): Promise { return new Promise((resolve, reject) => { @@ -804,8 +855,8 @@ export class API { let address = privateKey.publicKey.toAddress(); return this.getUtxos({ - addresses: address.toString() - }).then((utxos) => { + addresses: address.toString(), + }).then(utxos => { if (!_.isArray(utxos) || utxos.length == 0) return reject(new Error('No utxos found')); let fee = opts.fee || DEFAULT_FEE; @@ -824,7 +875,6 @@ export class API { // Make sure the tx can be serialized tx.serialize(); - } catch (ex) { this.log.error('Could not build transaction from private key', ex); return reject(MWCErrors.COULD_NOT_BUILD_TRANSACTION); @@ -832,8 +882,7 @@ export class API { return resolve(tx); }); }); - }; - + } /** * Open a wallet and try to complete the public key ring. @@ -845,55 +894,53 @@ export class API { openWallet(): Promise { this.log.warn('Opening wallet'); return new Promise((resolve, reject) => { - $.checkState(this.credentials); if (this.credentials.isComplete() && this.credentials.hasWalletInfo()) { this.log.warn('WALLET OPEN'); return resolve(true); // wallet is already open } - return this._doGetRequest('/v1/wallets/?includeExtendedInfo=1').then((ret) => { - let wallet = ret.wallet; + return this._doGetRequest('/v1/wallets/?includeExtendedInfo=1') + .then(ret => { + let wallet = ret.wallet; - return this._processStatus(ret).then(() => { - - if (!this.credentials.hasWalletInfo()) { - let me: any = _.find(wallet.copayers, { - id: this.credentials.copayerId - }); - this.credentials.addWalletInfo(wallet.id, wallet.name, wallet.m, wallet.n, me.name, wallet.parentAddress); - } + return this._processStatus(ret).then(() => { + if (!this.credentials.hasWalletInfo()) { + let me: any = _.find(wallet.copayers, { + id: this.credentials.copayerId, + }); + this.credentials.addWalletInfo(wallet.id, wallet.name, wallet.m, wallet.n, me.name, wallet.parentAddress); + } - if (wallet.status != 'complete') - return resolve(); + if (wallet.status != 'complete') return resolve(); - if (this.credentials.walletPrivKey) { - if (!Verifier.checkCopayers(this.credentials, wallet.copayers)) { - return reject(MWCErrors.SERVER_COMPROMISED); + if (this.credentials.walletPrivKey) { + if (!Verifier.checkCopayers(this.credentials, wallet.copayers)) { + return reject(MWCErrors.SERVER_COMPROMISED); + } + } else { + // this should only happen in AIR-GAPPED flows + this.log.warn('Could not verify copayers key (missing wallet Private Key)'); } - } else { - // this should only happen in AIR-GAPPED flows - this.log.warn('Could not verify copayers key (missing wallet Private Key)'); - } - this.credentials.addPublicKeyRing(this._extractPublicKeyRing(wallet.copayers)); + this.credentials.addPublicKeyRing(this._extractPublicKeyRing(wallet.copayers)); - this.eventEmitter.emit('walletCompleted', wallet.id); + this.eventEmitter.emit('walletCompleted', wallet.id); - return resolve(ret); + return resolve(ret); + }); + }) + .catch(err => { + return reject(err); }); - }).catch(err => { - return reject(err); - }); }); - }; + } _getHeaders() { return { - 'x-client-version': 'MWC-' + Package.version + 'x-client-version': 'MWC-' + Package.version, }; - }; - + } /** * Do an HTTP request @@ -903,9 +950,14 @@ export class API { * @param {String} url * @param {Object} args */ - protected _doRequest(method: string, url: string, args: any, useSession: boolean, secondRun = false): Promise<{ body: any, header: any }> { + protected _doRequest( + method: string, + url: string, + args: any, + useSession: boolean, + secondRun = false, + ): Promise<{ body: any; header: any }> { return new Promise((resolve, reject) => { - let headers = this._getHeaders(); if (this.credentials) { @@ -928,14 +980,13 @@ export class API { r.accept('json'); - _.each(headers, function (v, k) { + _.each(headers, function(v, k) { if (v) r.set(k, v); }); if (args) { if (method == 'post' || method == 'put') { r.send(args); - } else { r.query(args); } @@ -944,96 +995,100 @@ export class API { r.timeout(this.timeout); r.ok(res => res.status < 500); // dont reject on failed status - return Promise.resolve(r).then((res) => { - - /** - * Universal MWC Logger. It will log all output returned from MWS - * if the private static DEBUG_MODE is set to true above. - */ - if (res.body && this.DEBUG_MODE) { - this.log.info('MWS Response: '); - this.log.info(util.inspect(res.body, { - depth: 10 - })); - } - - if (res.status !== 200) { - if (res.status === 404) - return reject(MWCErrors.NOT_FOUND); - - if (res.code == MWCErrors.AUTHENTICATION_ERROR.code) { - if (this.onAuthenticationError) this.onAuthenticationError(); - return reject(MWCErrors.AUTHENTICATION_ERROR); + return Promise.resolve(r) + .then(res => { + /** + * Universal MWC Logger. It will log all output returned from MWS + * if the private static DEBUG_MODE is set to true above. + */ + if (res.body && this.DEBUG_MODE) { + this.log.info('MWS Response: '); + this.log.info( + util.inspect(res.body, { + depth: 10, + }), + ); } - if (!res.status) { - return reject(MWCErrors.CONNECTION_ERROR); - } + if (res.status !== 200) { + if (res.status === 404) return reject(MWCErrors.NOT_FOUND); - this.log.error('HTTP Error:' + res.status); + if (res.code == MWCErrors.AUTHENTICATION_ERROR.code) { + if (this.onAuthenticationError) this.onAuthenticationError(); + return reject(MWCErrors.AUTHENTICATION_ERROR); + } - if (!res.body) return reject(new Error(res.status.toString())); + if (!res.status) { + return reject(MWCErrors.CONNECTION_ERROR); + } - return reject(this._parseError(res.body)); - } + this.log.error('HTTP Error:' + res.status); - if (res.body === '{"error":"read ECONNRESET"}') { - return reject(MWCErrors.ECONNRESET_ERROR); - } + if (!res.body) return reject(new Error(res.status.toString())); - if (this.onConnectionRestored) { - this.onConnectionRestored(); - } + return reject(this._parseError(res.body)); + } - return resolve(res); - }).catch((err) => { + if (res.body === '{"error":"read ECONNRESET"}') { + return reject(MWCErrors.ECONNRESET_ERROR); + } - if (!err.status) { - return reject(MWCErrors.CONNECTION_ERROR); - } else if (err.status == 502 || err.status == 504) { - return reject(MWCErrors.SERVER_UNAVAILABLE); - } + if (this.onConnectionRestored) { + this.onConnectionRestored(); + } - if (!err.response || !err.response.text) { - return reject(err); - } + return resolve(res); + }) + .catch(err => { + if (!err.status) { + return reject(MWCErrors.CONNECTION_ERROR); + } else if (err.status == 502 || err.status == 504) { + return reject(MWCErrors.SERVER_UNAVAILABLE); + } - let errObj; // not an instance of Error - try { - errObj = JSON.parse(err.response.text); - } catch (e) { - return reject(err); - } + if (!err.response || !err.response.text) { + return reject(err); + } - if (errObj.code == MWCErrors.AUTHENTICATION_ERROR.code) { - if (!secondRun) { //trying to restore session one time - return this._doRequest('post', '/v1/login', {}, null, true).then(() => { - return this._doRequest(method, url, args, useSession, true); - }).catch(() => { + let errObj; // not an instance of Error + try { + errObj = JSON.parse(err.response.text); + } catch (e) { + return reject(err); + } + + if (errObj.code == MWCErrors.AUTHENTICATION_ERROR.code) { + if (!secondRun) { + //trying to restore session one time + return this._doRequest('post', '/v1/login', {}, null, true) + .then(() => { + return this._doRequest(method, url, args, useSession, true); + }) + .catch(() => { + if (this.onAuthenticationError) { + return Promise.resolve(this.onAuthenticationError()); + } + }); + } else { if (this.onAuthenticationError) { return Promise.resolve(this.onAuthenticationError()); } - }); - } else { - if (this.onAuthenticationError) { - return Promise.resolve(this.onAuthenticationError()); } } - } - if (errObj.code && MWCErrors[errObj.code]) return reject(MWCErrors[errObj.code]); - return reject(err); - }); + if (errObj.code && MWCErrors[errObj.code]) return reject(MWCErrors[errObj.code]); + return reject(err); + }); }); - }; + } private _login(): Promise { return this._doPostRequest('/v1/login', {}); - }; + } private _logout(): Promise { return this._doPostRequest('/v1/logout', {}); - }; + } /** * Do an HTTP request @@ -1044,16 +1099,17 @@ export class API { * @param {Object} args */ private _doRequestWithLogin(method: string, url: string, args: any): Promise { - let doLogin = (): Promise => { return new Promise((resolve, reject) => { - return this._login().then((s) => { - if (!s) return reject(MWCErrors.NOT_AUTHORIZED); - this.session = s; - return resolve(); - }).catch((err) => { - return reject(err); - }); + return this._login() + .then(s => { + if (!s) return reject(MWCErrors.NOT_AUTHORIZED); + this.session = s; + return resolve(); + }) + .catch(err => { + return reject(err); + }); }); }; @@ -1066,13 +1122,14 @@ export class API { }); }; - - return loginIfNeeded().then(() => { - return this._doRequest(method, url, args, true); - }).then((res) => { - return res.body; - }); - }; + return loginIfNeeded() + .then(() => { + return this._doRequest(method, url, args, true); + }) + .then(res => { + return res.body; + }); + } /** * Do a POST request @@ -1084,15 +1141,14 @@ export class API { */ _doPostRequest(url: string, args?: any): Promise { args = args || {}; - return this._doRequest('post', url, args, false) - .then(res => res.body); - }; + return this._doRequest('post', url, args, false).then(res => res.body); + } _doPutRequest(url: string, args: any): Promise { - return this._doRequest('put', url, args, false).then((res) => { + return this._doRequest('put', url, args, false).then(res => { return res.body; }); - }; + } /** * Do a GET request @@ -1104,18 +1160,18 @@ export class API { _doGetRequest(url: string): Promise { url += url.indexOf('?') > 0 ? '&' : '?'; url += 'r=' + _.random(10000, 99999); - return this._doRequest('get', url, {}, false).then((res) => { + return this._doRequest('get', url, {}, false).then(res => { return res.body; }); - }; + } _doGetRequestWithLogin(url: string): Promise { url += url.indexOf('?') > 0 ? '&' : '?'; url += 'r=' + _.random(10000, 99999); - return this._doRequestWithLogin('get', url, {}).catch((err) => { + return this._doRequestWithLogin('get', url, {}).catch(err => { this.log.warn('Were not able to complete getRequest: ', err); }); - }; + } /** * Do a DELETE request @@ -1125,12 +1181,12 @@ export class API { * @param {Callback} cb */ private _doDeleteRequest(url: string): Promise { - return this._doRequest('delete', url, {}, false).then((res) => { + return this._doRequest('delete', url, {}, false).then(res => { return res.body; }); - }; + } - private _buildSecret = function (walletId, walletPrivKey, network) { + private _buildSecret = function(walletId, walletPrivKey, network) { if (_.isString(walletPrivKey)) { walletPrivKey = Meritcore.PrivateKey.fromString(walletPrivKey); } @@ -1150,9 +1206,8 @@ export class API { parts.push(str.substring(i == 0 ? 0 : indexes[i - 1], indexes[i])); i++; } - ; return parts; - }; + } try { let secretSplit = split(secret, [22, 74]); @@ -1166,12 +1221,12 @@ export class API { return { walletId: walletId, walletPrivKey: walletPrivKey, - network: networkChar == 'T' ? 'testnet' : 'livenet' + network: networkChar == 'T' ? 'testnet' : 'livenet', }; } catch (ex) { throw new Error('Invalid secret'); } - }; + } buildTx(txp: any): any { return Utils.buildTx(txp); @@ -1181,7 +1236,7 @@ export class API { let t = Utils.buildTx(txp); return t.uncheckedSerialize(); - }; + } signTxp(txp: any, derivedXPrivKey): any { //Derive proper key to sign, for each input @@ -1190,7 +1245,7 @@ export class API { let xpriv = new Meritcore.HDPrivateKey(derivedXPrivKey); - _.each(txp.inputs, function (i) { + _.each(txp.inputs, function(i) { $.checkState(i.path, 'Input derivation path not available (signing transaction)'); if (!derived[i.path]) { derived[i.path] = xpriv.deriveChild(i.path).privateKey; @@ -1200,43 +1255,42 @@ export class API { let t = Utils.buildTx(txp); - let signatures = _.map(privs, function (priv, i) { + let signatures = _.map(privs, function(priv, i) { return t.getSignatures(priv); }); - signatures = _.map(_.sortBy(_.flatten(signatures), 'inputIndex'), function (s) { + signatures = _.map(_.sortBy(_.flatten(signatures), 'inputIndex'), function(s) { return s.signature.toDER().toString('hex'); }); return signatures; - }; + } private _signTxp(txp, password): any { let derived = this.credentials.getDerivedXPrivKey(password); return this.signTxp(txp, derived); - }; + } _getCurrentSignatures(txp: any): any { let acceptedActions = _.filter(txp.actions, { - type: 'accept' + type: 'accept', }); - return _.map(acceptedActions, function (x: any) { + return _.map(acceptedActions, function(x: any) { return { signatures: x.signatures, - xpub: x.xpub + xpub: x.xpub, }; }); - }; + } _addSignaturesToMeritcoreTx(txp: any, t: any, signatures: any, xpub: any): any { - if (signatures.length != txp.inputs.length) - throw new Error('Number of signatures does not match number of inputs'); + if (signatures.length != txp.inputs.length) throw new Error('Number of signatures does not match number of inputs'); let i = 0, x = new Meritcore.HDPublicKey(xpub); - _.each(signatures, function (signatureHex) { + _.each(signatures, function(signatureHex) { let input = txp.inputs[i]; try { let signature = Meritcore.crypto.Signature.fromString(signatureHex); @@ -1245,29 +1299,24 @@ export class API { inputIndex: i, signature: signature, sigtype: Meritcore.crypto.Signature.SIGHASH_ALL, - publicKey: pub + publicKey: pub, }; t.inputs[i].addSignature(t, s); i++; - } catch (e) { - } - ; + } catch (e) {} }); - if (i != txp.inputs.length) - throw new Error('Wrong signatures'); - }; - + if (i != txp.inputs.length) throw new Error('Wrong signatures'); + } _applyAllSignatures(txp: any, t: any): any { - $.checkState(txp.status == 'accepted'); let sigs = this._getCurrentSignatures(txp); - _.each(sigs, function (x) { + _.each(sigs, function(x) { this._addSignaturesToMeritcoreTx(txp, t, x.signatures, x.xpub); }); - }; + } /** * Join @@ -1282,9 +1331,15 @@ export class API { * @param {String} opts.customData * @param {Callback} cb */ - public doJoinWallet(walletId: any, walletPrivKey: any, xPubKey: any, requestPubKey: any, copayerName: string, opts: any = {}): Promise { + public doJoinWallet( + walletId: any, + walletPrivKey: any, + xPubKey: any, + requestPubKey: any, + copayerName: string, + opts: any = {}, + ): Promise { return new Promise((resolve, reject) => { - // Adds encrypted walletPrivateKey to CustomData opts.customData = opts.customData || {}; opts.customData.walletPrivKey = walletPrivKey.toString(); @@ -1296,33 +1351,34 @@ export class API { name: encCopayerName, xPubKey: xPubKey, requestPubKey: requestPubKey, - customData: encCustomData + customData: encCustomData, }; if (opts.dryRun) args.dryRun = true; - if (_.isBoolean(opts.supportBIP44AndP2PKH)) - args.supportBIP44AndP2PKH = opts.supportBIP44AndP2PKH; + if (_.isBoolean(opts.supportBIP44AndP2PKH)) args.supportBIP44AndP2PKH = opts.supportBIP44AndP2PKH; let hash = Utils.getCopayerHash(args.name, args.xPubKey, args.requestPubKey); args.copayerSignature = Utils.signMessage(hash, walletPrivKey); let url = '/v1/wallets/' + walletId + '/copayers'; - return this._doPostRequest(url, args).then((body) => { - return this._processWallet(body.wallet).then(() => { - return resolve(body.wallet); + return this._doPostRequest(url, args) + .then(body => { + return this._processWallet(body.wallet).then(() => { + return resolve(body.wallet); + }); + }) + .catch(err => { + return reject(err); }); - }).catch((err) => { - return reject(err); - }); }); - }; + } /** * Return if wallet is complete */ isComplete(): any { return this.credentials && this.credentials.isComplete(); - }; + } /** * Is private key currently encrypted? @@ -1331,7 +1387,7 @@ export class API { */ isPrivKeyEncrypted(): any { return this.credentials && this.credentials.isPrivKeyEncrypted(); - }; + } /** * Is private key external? @@ -1340,7 +1396,7 @@ export class API { */ isPrivKeyExternal(): any { return this.credentials && this.credentials.hasExternalSource(); - }; + } /** * Get external wallet source name @@ -1349,7 +1405,7 @@ export class API { */ getPrivKeyExternalSourceName(): any { return this.credentials ? this.credentials.getExternalSourceName() : null; - }; + } /** * Returns unencrypted extended private key and mnemonics @@ -1358,8 +1414,7 @@ export class API { */ getKeys(password: string): any { return this.credentials.getKeys(password); - }; - + } /** * Checks is password is valid @@ -1376,9 +1431,7 @@ export class API { } catch (e) { return false; } - ; - }; - + } /** * Can this credentials sign a transaction? @@ -1388,11 +1441,10 @@ export class API { */ canSign(): any { return this.credentials && this.credentials.canSign(); - }; - + } - private _extractPublicKeyRing = function (copayers) { - return _.map(copayers, function (copayer: any) { + private _extractPublicKeyRing = function(copayers) { + return _.map(copayers, function(copayer: any) { let pkr: any = _.pick(copayer, ['xPubKey', 'requestPubKey']); pkr.copayerName = copayer.name; return pkr; @@ -1408,7 +1460,7 @@ export class API { */ encryptPrivateKey(password: string, opts?: any): any { this.credentials.encryptPrivateKey(password, opts || this.privateKeyEncryptionOpts); - }; + } /** * disables encryption for private key. @@ -1417,7 +1469,7 @@ export class API { */ decryptPrivateKey(password: string): any { return this.credentials.decryptPrivateKey(password); - }; + } /** * Get current fee levels for the specified network @@ -1426,10 +1478,10 @@ export class API { * @returns {Callback} cb - Returns error or an object with status information */ getFeeLevels(network: string = this.network): Promise { - (!$.checkArgument(network || _.includes(['livenet', 'testnet'], network))); + !$.checkArgument(network || _.includes(['livenet', 'testnet'], network)); return this._doGetRequest('/v1/feelevels/?network=' + (network || ENV.network)); - }; + } /** * Get fee for easy receive @@ -1437,7 +1489,7 @@ export class API { */ getEasyReceiveFee(): Promise { return this._doGetRequest('/v1/easy_fee/'); - }; + } /** * Get service version @@ -1446,15 +1498,15 @@ export class API { */ getVersion(): any { this._doGetRequest('/v1/version/'); - }; + } _checkKeyDerivation(): any { - let isInvalid = (this.keyDerivationOk === false); + let isInvalid = this.keyDerivationOk === false; if (isInvalid) { this.log.error('Key derivation for this device is not working as expected'); } return !isInvalid; - }; + } /** * @@ -1473,7 +1525,6 @@ export class API { */ createWallet(walletName: string, copayerName: string, m: number, n: number, opts: any = {}): Promise { return new Promise((resolve, reject) => { - if (!this._checkKeyDerivation()) return reject(new Error('Cannot create new wallet')); if (opts) $.shouldBeObject(opts); @@ -1484,7 +1535,7 @@ export class API { if (!this.credentials) { this.log.info('Generating new keys'); this.seedFromRandom({ - network: network + network: network, }); } else { this.log.info('Using existing keys'); @@ -1506,47 +1557,48 @@ export class API { addressType: Meritcore.Address.PayToPublicKeyHashType, signPrivKey: walletPrivKey, network: network, - alias: opts.alias + alias: opts.alias, }; // Create wallet - return this.sendReferral(referralOpts).then(refid => { - - let c = this.credentials; - let encWalletName = Utils.encryptMessage(walletName, c.sharedEncryptingKey); - - let args = { - name: encWalletName, - m: m, - n: n, - pubKey: pubkey.toString(), - network: network, - singleAddress: true, //daedalus wallets are single-addressed - id: opts.id, - parentAddress: opts.parentAddress, - referralId: refid - }; - - return this._doPostRequest('/v1/wallets/', args).then(res => { - if (res) { - let walletId = res.walletId; - c.addWalletInfo(walletId, walletName, m, n, copayerName, opts.parentAddress); - this.name = walletName; - - let secret = this._buildSecret(c.walletId, c.walletPrivKey, c.network); - - return this.doJoinWallet(walletId, walletPrivKey, c.xPubKey, c.requestPubKey, copayerName, {}).then( - wallet => { - return resolve(n > 1 ? secret : null); - } - ); - } else { - return reject(Error(res)); - } - }); - }).catch(reject); + return this.sendReferral(referralOpts) + .then(refid => { + let c = this.credentials; + let encWalletName = Utils.encryptMessage(walletName, c.sharedEncryptingKey); + + let args = { + name: encWalletName, + m: m, + n: n, + pubKey: pubkey.toString(), + network: network, + singleAddress: true, //daedalus wallets are single-addressed + id: opts.id, + parentAddress: opts.parentAddress, + referralId: refid, + }; + + return this._doPostRequest('/v1/wallets/', args).then(res => { + if (res) { + let walletId = res.walletId; + c.addWalletInfo(walletId, walletName, m, n, copayerName, opts.parentAddress); + this.name = walletName; + + let secret = this._buildSecret(c.walletId, c.walletPrivKey, c.network); + + return this.doJoinWallet(walletId, walletPrivKey, c.xPubKey, c.requestPubKey, copayerName, {}).then( + wallet => { + return resolve(n > 1 ? secret : null); + }, + ); + } else { + return reject(Error(res)); + } + }); + }) + .catch(reject); }); - }; + } /** * Broadcast raw referral to network @@ -1573,7 +1625,7 @@ export class API { if (!this.credentials) { this.log.info('Generating new keys'); this.seedFromRandom({ - network: opts.network + network: opts.network, }); } else { this.log.info('Using existing keys'); @@ -1595,26 +1647,31 @@ export class API { parentAddress = parentReferral.address; } - const hash = Meritcore.crypto.Hash.sha256sha256(Buffer.concat([ - Meritcore.Address.fromString(parentAddress, opts.network).toBufferLean(), - Meritcore.Address.fromString(opts.address, opts.network).toBufferLean() - ])); + const hash = Meritcore.crypto.Hash.sha256sha256( + Buffer.concat([ + Meritcore.Address.fromString(parentAddress, opts.network).toBufferLean(), + Meritcore.Address.fromString(opts.address, opts.network).toBufferLean(), + ]), + ); const signature = Meritcore.crypto.ECDSA.sign(hash, opts.signPrivKey, 'big').toString('hex'); // The referral constructor requires that the parentAddress is in // full address form (ripe160); it should not be an alias here. - const referral = new Meritcore.Referral({ - parentAddress, - address: opts.address, - addressType: opts.addressType, - pubkey: opts.pubkey, - signature: signature.toString('hex'), - alias: opts.alias - }, opts.network); + const referral = new Meritcore.Referral( + { + parentAddress, + address: opts.address, + addressType: opts.addressType, + pubkey: opts.pubkey, + signature: signature.toString('hex'), + alias: opts.alias, + }, + opts.network, + ); return this._doPostRequest('/v1/referral/', { referral: referral.serialize() }); - }; + } /** * Join an existing wallet @@ -1627,22 +1684,28 @@ export class API { */ async joinWallet(secret: string, copayerName: string, opts: any = {}): Promise { - if (!this._checkKeyDerivation()) - throw new Error('Cannot join wallet'); + if (!this._checkKeyDerivation()) throw new Error('Cannot join wallet'); let secretData = this.parseSecret(secret); if (!this.credentials) { this.seedFromRandom({ - network: secretData.network + network: secretData.network, }); } this.credentials.addWalletPrivateKey(secretData.walletPrivKey.toString()); - const wallet = await this.doJoinWallet(secretData.walletId, secretData.walletPrivKey, this.credentials.xPubKey, this.credentials.requestPubKey, copayerName, { - dryRun: !!opts.dryRun - }); + const wallet = await this.doJoinWallet( + secretData.walletId, + secretData.walletPrivKey, + this.credentials.xPubKey, + this.credentials.requestPubKey, + copayerName, + { + dryRun: !!opts.dryRun, + }, + ); if (!opts.dryRun) { this.credentials.addWalletInfo(wallet.id, wallet.name, wallet.m, wallet.n, copayerName, wallet.parentAddress); @@ -1662,7 +1725,7 @@ export class API { // First: Try to get the wallet with current credentials await this.getStatus({ - includeExtendedInfo: true + includeExtendedInfo: true, }); let c = this.credentials; @@ -1679,7 +1742,7 @@ export class API { network: c.network, id: walletId, supportBIP44AndP2PKH, - beacon: c.beacon + beacon: c.beacon, }; const body = await this._doPostRequest('/v1/wallets/', args); @@ -1693,13 +1756,15 @@ export class API { let i = 1; - return Promise.all(this.credentials.publicKeyRing.map((item: any) => { - let name = item.copayerName || ('copayer ' + i++); - return this.doJoinWallet(walletId, walletPrivKey, item.xPubKey, item.requestPubKey, name, { - supportBIP44AndP2PKH - }); - })); - }; + return Promise.all( + this.credentials.publicKeyRing.map((item: any) => { + let name = item.copayerName || 'copayer ' + i++; + return this.doJoinWallet(walletId, walletPrivKey, item.xPubKey, item.requestPubKey, name, { + supportBIP44AndP2PKH, + }); + }), + ); + } private async _processWallet(wallet): Promise { let encryptingKey = this.credentials.sharedEncryptingKey; @@ -1728,7 +1793,7 @@ export class API { access.name = name; }); }); - }; + } private async _processStatus(status) { this.id = status.wallet.id; @@ -1736,17 +1801,19 @@ export class API { this.balance = status.balance || {}; this.invitesBalance = status.invitesBalance || {}; - this.confirmed = (status.invitesBalance && status.invitesBalance.totalAmount > 0); + this.confirmed = status.invitesBalance && status.invitesBalance.totalAmount > 0; if (this.confirmed) { this.availableInvites = Math.max(0, status.invitesBalance.availableConfirmedAmount - 1); this.pendingInvites = status.invitesBalance.availableAmount - status.invitesBalance.availableConfirmedAmount; - if (status.invitesBalance.availableConfirmedAmount == 0) this.pendingInvites = Math.max(0, this.pendingInvites - 1); + if (status.invitesBalance.availableConfirmedAmount == 0) + this.pendingInvites = Math.max(0, this.pendingInvites - 1); this.sendableInvites = Math.max(0, status.invitesBalance.availableAmount - 1); } //todo check if we use 'spendunconfirmed' options - this.balance.spendableAmount = status.balance.totalAmount - status.balance.lockedAmount - status.balance.totalPendingCoinbaseAmount; + this.balance.spendableAmount = + status.balance.totalAmount - status.balance.lockedAmount - status.balance.totalPendingCoinbaseAmount; - const processCustomData = async (data) => { + const processCustomData = async data => { let copayers = data.wallet.copayers; if (!copayers) return; @@ -1770,7 +1837,7 @@ export class API { } // Add it to result - return data.customData = customData; + return (data.customData = customData); }; const validateAddress = async () => { @@ -1785,7 +1852,7 @@ export class API { processCustomData(status), this._processWallet(status.wallet), this._processTxps(status.pendingTxps), - validateAddress() + validateAddress(), ]); return status; @@ -1802,7 +1869,6 @@ export class API { */ // TODO: Make this return a promise of []Notifications getNotifications(opts: any = {}): Promise { - $.checkState(this.credentials); let url = '/v1/notifications/'; @@ -1813,7 +1879,7 @@ export class API { } return this._doGetRequest(url); - }; + } /** * Get status of the wallet @@ -1836,7 +1902,7 @@ export class API { } return this._processStatus(result); - }; + } getANV(addr: any): Promise { $.checkState(this.credentials); @@ -1870,7 +1936,7 @@ export class API { $.checkState(this.credentials); return this._doGetRequest('/v1/preferences/'); - }; + } /** * Save copayer preferences @@ -1881,8 +1947,7 @@ export class API { $.checkState(this.credentials); return this._doPutRequest('/v1/preferences/', preferences); - }; - + } /** * fetchPayPro @@ -1896,14 +1961,13 @@ export class API { */ // TODO: Promisify (if we keep PayPro functionality.) fetchPayPro(opts: any): Promise { - $.checkArgument(opts) - .checkArgument(opts.payProUrl); + $.checkArgument(opts).checkArgument(opts.payProUrl); return PayPro.get({ url: opts.payProUrl, - http: this.payProHttp + http: this.payProHttp, }); - }; + } /** * Gets list of utxos @@ -1917,24 +1981,26 @@ export class API { let url = '/v1/utxos/'; if (opts.addresses) { - url += '?' + querystring.stringify({ - addresses: [].concat(opts.addresses).join(','), - invites: opts.invites - }); + url += + '?' + + querystring.stringify({ + addresses: [].concat(opts.addresses).join(','), + invites: opts.invites, + }); } return this._doGetRequest(url); - }; + } _getCreateTxProposalArgs(opts: any): any { let args = _.cloneDeep(opts); args.message = this._encryptMessage(opts.message, this.credentials.sharedEncryptingKey) || null; args.payProUrl = opts.payProUrl || null; - _.each(args.outputs, (o) => { + _.each(args.outputs, o => { o.message = this._encryptMessage(o.message, this.credentials.sharedEncryptingKey) || null; }); return args; - }; + } /** * Create a transaction proposal @@ -1990,7 +2056,7 @@ export class API { } return txp; - }; + } /** * Publish a transaction proposal @@ -2006,7 +2072,7 @@ export class API { const hash = Utils.buildTx(opts.txp).uncheckedSerialize(); const args = { - proposalSignature: Utils.signMessage(hash, this.credentials.requestPrivKey) + proposalSignature: Utils.signMessage(hash, this.credentials.requestPrivKey), }; try { @@ -2014,7 +2080,7 @@ export class API { } catch (err) { throw new Error('error in post /v1/txproposals/' + err); } - }; + } /** * Send signed referral to beacon address and unlock in MWS @@ -2022,10 +2088,14 @@ export class API { */ async signAddressAndUnlock(opts: any = {}): Promise { const refid: string = await this.sendReferral(opts); - await this._doPostRequest('/v1/addresses/unlock/', { address: opts.address, parentAddress: opts.parentAddress, refid }); + await this._doPostRequest('/v1/addresses/unlock/', { + address: opts.address, + parentAddress: opts.parentAddress, + refid, + }); return refid; - }; + } /** * Sign and unlock address with root wallet address if it's not beaconed yet @@ -2045,12 +2115,15 @@ export class API { const unlockOpts = { // privKey.toPublicKey().toAddress() and privKey.toAddress() gives two different strings, but daemon treats them // as same string ??? - parentAddress: Meritcore.PrivateKey(this.credentials.walletPrivKey, this.credentials.network).toPublicKey().toAddress().toString(), + parentAddress: Meritcore.PrivateKey(this.credentials.walletPrivKey, this.credentials.network) + .toPublicKey() + .toAddress() + .toString(), address: address.address, pubkey: address.publicKeys[0], addressType: 1, signPrivKey, - network: address.network + network: address.network, }; return this.signAddressAndUnlock(unlockOpts); @@ -2065,8 +2138,7 @@ export class API { async createAddress(opts: any = {}): Promise { $.checkState(this.credentials && this.credentials.isComplete()); - if (!this._checkKeyDerivation()) - throw new Error('Cannot create new address for this wallet'); + if (!this._checkKeyDerivation()) throw new Error('Cannot create new address for this wallet'); opts.ignoreMaxGap = true; @@ -2081,7 +2153,7 @@ export class API { } return address; - }; + } /** * Adds access to the current copayer @@ -2100,8 +2172,9 @@ export class API { let reqPrivKey = new Meritcore.PrivateKey(opts.generateNewKey ? null : this.credentials.requestPrivKey); let requestPubKey = reqPrivKey.toPublicKey().toString(); - let xPriv = new Meritcore.HDPrivateKey(this.credentials.xPrivKey) - .deriveChild(this.credentials.getBaseAddressDerivationPath()); + let xPriv = new Meritcore.HDPrivateKey(this.credentials.xPrivKey).deriveChild( + this.credentials.getBaseAddressDerivationPath(), + ); let sig = Utils.signRequestPubKey(requestPubKey, xPriv); let copayerId = this.credentials.copayerId; @@ -2112,18 +2185,17 @@ export class API { requestPubKey: requestPubKey, signature: sig, name: encCopayerName, - restrictions: opts.restrictions + restrictions: opts.restrictions, }; return this._doPutRequest('/v1/copayers/' + copayerId + '/', opts); - }; + } // Ensure that an address is in a valid format, and that it has been beaconed on the blockchain. validateAddress(address: string): Promise { const url = `/v1/addresses/${address}/validate/`; return this._doGetRequest(url); - }; - + } /** * Get your main addresses @@ -2155,7 +2227,7 @@ export class API { } return addresses; - }; + } /** * Update wallet balance @@ -2168,7 +2240,7 @@ export class API { if (opts.twoStep) url += '?twoStep=1'; return this._doGetRequest(url).then(balance => balance.availableAmount); - }; + } /** * Update wallet invites balance @@ -2178,7 +2250,7 @@ export class API { let url = '/v1/invites/'; return this._doGetRequest(url); - }; + } /** * Get list of transactions proposals @@ -2196,49 +2268,55 @@ export class API { await this._processTxps(txps); - await Promise.all(txps.map(async (txp) => { - if (!opts.doNotVerify) { - // TODO: Find a way to run this check in parallel. - const paypro = await this.getPayPro(txp); + await Promise.all( + txps.map(async txp => { + if (!opts.doNotVerify) { + // TODO: Find a way to run this check in parallel. + const paypro = await this.getPayPro(txp); - if (!Verifier.checkTxProposal(this.credentials, txp, { paypro })) { - throw MWCErrors.SERVER_COMPROMISED; - } + if (!Verifier.checkTxProposal(this.credentials, txp, { paypro })) { + throw MWCErrors.SERVER_COMPROMISED; + } - return paypro; - } - })); + return paypro; + } + }), + ); let result: any; if (opts.forAirGapped) { result = { txps: JSON.parse(JSON.stringify(txps)), - encryptedPkr: opts.doNotEncryptPkr ? null : Utils.encryptMessage(JSON.stringify(this.credentials.publicKeyRing), this.credentials.personalEncryptingKey), + encryptedPkr: opts.doNotEncryptPkr + ? null + : Utils.encryptMessage( + JSON.stringify(this.credentials.publicKeyRing), + this.credentials.personalEncryptingKey, + ), unencryptedPkr: opts.doNotEncryptPkr ? JSON.stringify(this.credentials.publicKeyRing) : null, m: this.credentials.m, - n: this.credentials.n + n: this.credentials.n, }; } else { result = txps; } return result; - }; + } //TODO: Refactor Paypro module to be Promisified. private async getPayPro(txp): Promise { - if (!txp.payProUrl || this.doNotVerifyPayPro) - return; + if (!txp.payProUrl || this.doNotVerifyPayPro) return; const paypro = await PayPro.get({ url: txp.payProUrl, - http: this.payProHttp + http: this.payProHttp, }); if (!paypro) { throw new Error('Cannot check paypro transaction now.'); } return paypro; - }; + } /** * Sign a transaction proposal @@ -2250,19 +2328,16 @@ export class API { $.checkArgument(txp.creatorId); if (!txp.signatures) { - if (!this.canSign()) - throw MWCErrors.MISSING_PRIVATE_KEY; + if (!this.canSign()) throw MWCErrors.MISSING_PRIVATE_KEY; - if (this.isPrivKeyEncrypted() && !password) - throw MWCErrors.ENCRYPTED_PRIVATE_KEY; + if (this.isPrivKeyEncrypted() && !password) throw MWCErrors.ENCRYPTED_PRIVATE_KEY; } const paypro = await this.getPayPro(txp); let isLegit = Verifier.checkTxProposal(this.credentials, txp, { paypro }); - if (!isLegit) - throw MWCErrors.SERVER_COMPROMISED; + if (!isLegit) throw MWCErrors.SERVER_COMPROMISED; let signatures = txp.signatures; @@ -2272,7 +2347,7 @@ export class API { const url = '/v1/txproposals/' + txp.id + '/signatures/'; const args = { - signatures + signatures, }; txp = await this._doPostRequest(url, args); @@ -2292,11 +2367,9 @@ export class API { */ signTxProposalFromAirGapped(txp: any, encryptedPkr: string, m: number, n: number, password: string): Promise { $.checkState(this.credentials); - if (!this.canSign()) - throw MWCErrors.MISSING_PRIVATE_KEY; + if (!this.canSign()) throw MWCErrors.MISSING_PRIVATE_KEY; - if (this.isPrivKeyEncrypted() && !password) - throw MWCErrors.ENCRYPTED_PRIVATE_KEY; + if (this.isPrivKeyEncrypted() && !password) throw MWCErrors.ENCRYPTED_PRIVATE_KEY; let publicKeyRing; try { @@ -2314,12 +2387,10 @@ export class API { this.credentials.addressType = txp.addressType; this.credentials.addPublicKeyRing(publicKeyRing); - if (!Verifier.checkTxProposalSignature(this.credentials, txp)) - throw new Error('Fake transaction proposal'); + if (!Verifier.checkTxProposalSignature(this.credentials, txp)) throw new Error('Fake transaction proposal'); return this._signTxp(txp, password); - }; - + } /** * Reject a transaction proposal @@ -2332,7 +2403,7 @@ export class API { const url = '/v1/txproposals/' + txp.id + '/rejections/'; const args = { - reason: this._encryptMessage(reason, this.credentials.sharedEncryptingKey) || '' + reason: this._encryptMessage(reason, this.credentials.sharedEncryptingKey) || '', }; txp = await this._doPostRequest(url, args); @@ -2356,7 +2427,7 @@ export class API { const url = '/v1/broadcast_raw/'; return this._doPostRequest(url, opts); - }; + } private async _doBroadcast(txp: any): Promise { const url = '/v1/txproposals/' + txp.id + '/broadcast/'; @@ -2364,7 +2435,7 @@ export class API { await this._processTxps(txp); return txp; - }; + } /** * Broadcast a transaction proposal @@ -2375,8 +2446,7 @@ export class API { this.log.warn('Inside broadCastTxProposal'); $.checkState(this.credentials && this.credentials.isComplete()); - if (_.isArray(txp)) - txp = txp[0]; + if (_.isArray(txp)) txp = txp[0]; await this.signAddressAndUnlockWithRoot(txp.changeAddress); const paypro = await this.getPayPro(txp); @@ -2395,13 +2465,13 @@ export class API { rawTx: t.serialize({ disableSmallFees: true, disableLargeFees: true, - disableDustOutputs: true - }) + disableDustOutputs: true, + }), }); } return this._doBroadcast(txp); - }; + } /** * Remove a transaction proposal @@ -2410,7 +2480,7 @@ export class API { removeTxProposal(txp: any): Promise { $.checkState(this.credentials && this.credentials.isComplete()); return this._doDeleteRequest('/v1/txproposals/' + txp.id); - }; + } /** * Get transaction history @@ -2460,7 +2530,7 @@ export class API { await this._processTxps(txp); return txp; - }; + } /** * Start an address scanning process. @@ -2474,10 +2544,10 @@ export class API { opts = opts || {}; $.checkState(this.credentials && this.credentials.isComplete()); const args = { - includeCopayerBranches: opts.includeCopayerBranches + includeCopayerBranches: opts.includeCopayerBranches, }; return this._doPostRequest('/v1/addresses/scan', args); - }; + } /** * Get a note associated with the specified txid @@ -2504,7 +2574,7 @@ export class API { const note = await this._doPutRequest('/v1/txnotes/' + opts.txid + '/', opts); return this._processTxNotes(note); - }; + } /** * Get all notes edited after the specified date @@ -2552,7 +2622,7 @@ export class API { * Get all rates * @returns {Promise} */ - getRates():Promise { + getRates(): Promise { return this._doGetRequest('/v1/rates'); } @@ -2566,7 +2636,7 @@ export class API { pushNotificationsSubscribe(opts: any): Promise { const url = '/v1/pushnotifications/subscriptions/'; return this._doPostRequest(url, opts); - }; + } /** * Unsubscribe from push notifications. @@ -2576,14 +2646,14 @@ export class API { pushNotificationsUnsubscribe(token: string): Promise { const url = '/v1/pushnotifications/subscriptions/' + token; return this._doDeleteRequest(url); - }; + } smsNotificationsSubscribe(phoneNumber: string, platform: string, settings: ISmsNotificationSettings) { return this._doPostRequest('/v1/sms-notifications', { phoneNumber, platform, walletId: this.id, - settings + settings, }); } @@ -2604,7 +2674,7 @@ export class API { txConfirmationSubscribe(opts: any): Promise { const url = '/v1/txconfirmations/'; return this._doPostRequest(url, opts); - }; + } /** * Stop listening for a tx confirmation. @@ -2613,7 +2683,7 @@ export class API { txConfirmationUnsubscribe(txid: string): Promise { const url = '/v1/txconfirmations/' + txid; return this._doDeleteRequest(url); - }; + } /** * Returns send max information. @@ -2632,12 +2702,11 @@ export class API { if (opts.excludeUnconfirmedUtxos) args.push('excludeUnconfirmedUtxos=1'); if (opts.returnInputs) args.push('returnInputs=1'); let qs = ''; - if (args.length > 0) - qs = '?' + args.join('&'); + if (args.length > 0) qs = '?' + args.join('&'); const url = '/v1/sendmaxinfo/' + qs; return this._doGetRequest(url); - }; + } /** * Get wallet status based on a string identifier (one of: walletId, address, txid) @@ -2654,8 +2723,7 @@ export class API { const result = await this._doGetRequest('/v1/wallets/' + opts.identifier + '?' + qs.join('&')); - if (!result || !result.wallet) - throw new Error('Could not get status by identifier.'); + if (!result || !result.wallet) throw new Error('Could not get status by identifier.'); if (result.wallet.status == 'pending') { const { walletId, walletPrivKey, network } = this.credentials; @@ -2665,12 +2733,12 @@ export class API { await this._processStatus(result); return result; - }; + } referralTxConfirmationSubscribe(opts): Promise { const url = '/v1/referraltxconfirmations/'; return this._doPostRequest(url, opts); - }; + } referralTxConfirmationUnsubscribe(codeHash): Promise { const url = '/v1/referraltxconfirmations/' + codeHash; @@ -2688,7 +2756,7 @@ export class API { let url = '/v1/easyreceive/validate/' + scriptId; return this._doGetRequest(url); - }; + } /** * Vaulting @@ -2696,11 +2764,11 @@ export class API { getVaults() { $.checkState(this.credentials); return this._doGetRequest('/v1/vaults/'); - }; + } getVault(vaultId) { $.checkState(this.credentials); - return this._doGetRequest(`/v1/vaults/${ vaultId }`); + return this._doGetRequest(`/v1/vaults/${vaultId}`); } /** @@ -2716,18 +2784,18 @@ export class API { $.checkState(this.credentials); return this._doPostRequest('/v1/vaults/', vault); - }; + } renewVault(vault: any) { $.checkState(this.credentials); delete vault.walletClient; return this._doPostRequest(`/v1/vaults/${vault._id}`, vault); - }; + } getVaultTxHistory(vaultId: string, network: string): Promise> { $.checkState(this.credentials); return this._doGetRequest(`/v1/vaults/${vaultId}/txhistory?network=${network}`); - }; + } getDefaultFee() { return DEFAULT_FEE; @@ -2735,12 +2803,19 @@ export class API { deliverGlobalSend(globalSend: EasySend, type: ISendMethod) { return this._doPostRequest('/v1/globalsend', { - globalSend: _.pick(globalSend, ['secret', 'senderPubKey', 'senderName', 'blockTimeout', 'parentAddress', 'inviteOnly']), + globalSend: _.pick(globalSend, [ + 'secret', + 'senderPubKey', + 'senderName', + 'blockTimeout', + 'parentAddress', + 'inviteOnly', + ]), type: { method: type.destination, destination: type.value, - message: type.message - } + message: type.message, + }, }); } @@ -2749,7 +2824,10 @@ export class API { */ registerGlobalSend(easySend: EasySend) { $.checkState(this.credentials); - return this._doPostRequest(`/v1/globalsend/register`, {scriptAddress: easySend.scriptAddress, globalsend: this.encryptGlobalSend(easySend)}); + return this._doPostRequest(`/v1/globalsend/register`, { + scriptAddress: easySend.scriptAddress, + globalsend: this.encryptGlobalSend(easySend), + }); } /** @@ -2770,7 +2848,7 @@ export class API { let globalSend = JSON.parse(this.decryptGlobalSend(g.globalsend)); globalSend.cancelled = g.cancelled; return globalSend; - } ); + }); } async getCommunityRank() { @@ -2780,12 +2858,12 @@ export class API { async getCommunityRanks(addresses) { $.checkState(this.credentials); - return this._doPostRequest(`/v1/community/ranks`, {addresses: addresses}); + return this._doPostRequest(`/v1/community/ranks`, { addresses: addresses }); } async getCommunityLeaderboard(limit: number) { $.checkState(this.credentials); - return this._doGetRequest(`/v1/community/leaderboard?limit=`+limit); + return this._doGetRequest(`/v1/community/leaderboard?limit=` + limit); } private encryptGlobalSend(easySend: EasySend) { @@ -2795,7 +2873,4 @@ export class API { private decryptGlobalSend(data) { return this._decryptMessage(data, this.credentials.personalEncryptingKey); } - - - } diff --git a/packages/lightwallet/common/merit-wallet-client/lib/common/constants.ts b/packages/lightwallet/common/merit-wallet-client/lib/common/constants.ts index 46152676eb..f541f62022 100644 --- a/packages/lightwallet/common/merit-wallet-client/lib/common/constants.ts +++ b/packages/lightwallet/common/merit-wallet-client/lib/common/constants.ts @@ -1,5 +1,4 @@ -export module Constants { - +export namespace Constants { export const DEFAULT_NET = 'testnet'; export const SCRIPT_TYPES = { @@ -17,7 +16,7 @@ export module Constants { export const PATHS = { REQUEST_KEY: "m/1'/0", TXPROPOSAL_KEY: "m/1'/1", - REQUEST_KEY_AUTH: "m/2", // relative to BASE + REQUEST_KEY_AUTH: 'm/2', // relative to BASE }; export const BIP45_SHARED_INDEX = 0x80000000 - 1; @@ -32,7 +31,7 @@ export module Constants { short: { maxDecimals: 6, minDecimals: 2, - } + }, }, bit: { toMicros: 100, @@ -43,12 +42,11 @@ export module Constants { short: { maxDecimals: 0, minDecimals: 0, - } + }, }, }; // value here is NOT limited to max merit supply as in meritd // as it overflows BN max supported value (Number.MAX_SAFE_INTEGER) export const VAULT_SPEND_LIMIT = 10000000; - -}; +} diff --git a/packages/lightwallet/common/merit-wallet-client/lib/common/defaults.ts b/packages/lightwallet/common/merit-wallet-client/lib/common/defaults.ts index 220b19a413..f3f286e947 100644 --- a/packages/lightwallet/common/merit-wallet-client/lib/common/defaults.ts +++ b/packages/lightwallet/common/merit-wallet-client/lib/common/defaults.ts @@ -1,14 +1,12 @@ -export module Defaults { - - export const DEFAULT_FEE_PER_KB:number = 10000; - export const MIN_FEE_PER_KB:number = 0; - export const MAX_FEE_PER_KB:number = 1000000; - export const MAX_TX_FEE:number = 1 * 1e8; +export namespace Defaults { + export const DEFAULT_FEE_PER_KB: number = 10000; + export const MIN_FEE_PER_KB: number = 0; + export const MAX_FEE_PER_KB: number = 1000000; + export const MAX_TX_FEE: number = 1 * 1e8; export const MAX_TX_FEE_PERCENT = 0.00001; export const adjustableMaxFee = function(value: number): number { const percents = value * Defaults.MAX_TX_FEE_PERCENT; return percents > Defaults.MAX_TX_FEE ? percents : Defaults.MAX_TX_FEE; - } - -}; + }; +} diff --git a/packages/lightwallet/common/merit-wallet-client/lib/common/index.ts b/packages/lightwallet/common/merit-wallet-client/lib/common/index.ts index 794260cf2b..61ba64a304 100644 --- a/packages/lightwallet/common/merit-wallet-client/lib/common/index.ts +++ b/packages/lightwallet/common/merit-wallet-client/lib/common/index.ts @@ -4,8 +4,8 @@ import { Utils as _Utils } from './utils'; // TODO: Investigate a way to import/expert with one line in modules. // Adil mentioned that there was a way to do. -export module Common { - export const Constants = _Constants; - export const Defaults = _Defaults; - export const Utils = _Utils; +export namespace Common { + export const Constants = _Constants; + export const Defaults = _Defaults; + export const Utils = _Utils; } diff --git a/packages/lightwallet/common/merit-wallet-client/lib/common/utils.ts b/packages/lightwallet/common/merit-wallet-client/lib/common/utils.ts index 00a303a453..d6dd548829 100644 --- a/packages/lightwallet/common/merit-wallet-client/lib/common/utils.ts +++ b/packages/lightwallet/common/merit-wallet-client/lib/common/utils.ts @@ -5,27 +5,40 @@ import * as preconditions from 'preconditions'; const $ = preconditions.singleton(); import * as sjcl from 'sjcl'; import * as Stringify from 'json-stable-stringify'; -import { Transaction, HDPublicKey, HDPrivateKey, Address, PrivateKey, PublicKey, crypto, encoding } from 'meritcore-lib'; +import { + Transaction, + HDPublicKey, + HDPrivateKey, + Address, + PrivateKey, + PublicKey, + crypto, + encoding, +} from 'meritcore-lib'; import { Constants } from './constants'; import { Defaults } from './defaults'; import { formatAmount as meritCoreFormatAmount } from '@merit/common/utils/format'; - - -export module Utils { - - let SJCL:any = {}; +export namespace Utils { + let SJCL: any = {}; export const encryptMessage = function(message, encryptingKey) { let key = sjcl.codec.base64.toBits(encryptingKey); - return sjcl.encrypt(key, message, _.defaults({ - ks: 128, - iter: 1, - }, this.SJCL)); + return sjcl.encrypt( + key, + message, + _.defaults( + { + ks: 128, + iter: 1, + }, + this.SJCL, + ), + ); }; - export const decryptMessage = function(cyphertextJson, encryptingKey) { + export const decryptMessage = function(cyphertextJson, encryptingKey) { try { let key = sjcl.codec.base64.toBits(encryptingKey); return sjcl.decrypt(key, cyphertextJson); @@ -36,7 +49,7 @@ export module Utils { /* TODO: It would be nice to be compatible with meritd signmessage. How * the hash is calculated there? */ - export const hashMessage = function(text) { + export const hashMessage = function(text) { $.checkArgument(text); let buf = new Buffer(text); let ret = crypto.Hash.sha256sha256(buf); @@ -44,21 +57,18 @@ export module Utils { return ret; }; - - export const signMessage = function(text, privKey) { + export const signMessage = function(text, privKey) { $.checkArgument(text); let priv = new PrivateKey(privKey); let hash = this.hashMessage(text); return crypto.ECDSA.sign(hash, priv, 'little').toString(); }; - - export const verifyMessage = function(text, signature, pubKey) { + export const verifyMessage = function(text, signature, pubKey) { $.checkArgument(text); $.checkArgument(pubKey); - if (!signature) - return false; + if (!signature) return false; let pub = new PublicKey(pubKey); let hash = this.hashMessage(text); @@ -71,21 +81,23 @@ export module Utils { } }; - export const privateKeyToAESKey = function(privKey) { + export const privateKeyToAESKey = function(privKey) { $.checkArgument(privKey && _.isString(privKey)); $.checkArgument(PrivateKey.isValid(privKey), 'The private key received is invalid'); let pk = PrivateKey.fromString(privKey); - return crypto.Hash.sha256(pk.toBuffer()).slice(0, 16).toString('base64'); + return crypto.Hash.sha256(pk.toBuffer()) + .slice(0, 16) + .toString('base64'); }; - export const getCopayerHash = function(name, xPubKey, requestPubKey) { + export const getCopayerHash = function(name, xPubKey, requestPubKey) { return [name, xPubKey, requestPubKey].join('|'); }; - export const getProposalHash = function(proposalHeader) { + export const getProposalHash = function(proposalHeader) { function getOldHash(toAddress, amount, message, payProUrl) { - return [toAddress, amount, (message || ''), (payProUrl || '')].join('|'); - }; + return [toAddress, amount, message || '', payProUrl || ''].join('|'); + } // For backwards compatibility if (arguments.length > 1) { @@ -95,7 +107,7 @@ export module Utils { return Stringify(proposalHeader); }; - export const deriveAddress = function(scriptType, publicKeyRing, path, m, network) { + export const deriveAddress = function(scriptType, publicKeyRing, path, m, network) { $.checkArgument(_.includes(_.values(Constants.SCRIPT_TYPES), scriptType)); let publicKeys = _.map(publicKeyRing, function(item: any) { @@ -125,23 +137,23 @@ export module Utils { }; }; - export const xPubToCopayerId = function(xpub) { + export const xPubToCopayerId = function(xpub) { let hash = sjcl.hash.sha256.hash(xpub); return sjcl.codec.hex.fromBits(hash); }; - export const signRequestPubKey = function(requestPubKey, xPrivKey) { + export const signRequestPubKey = function(requestPubKey, xPrivKey) { let priv = new HDPrivateKey(xPrivKey).deriveChild(Constants.PATHS.REQUEST_KEY_AUTH).privateKey; return this.signMessage(requestPubKey, priv); }; - export const verifyRequestPubKey = function(requestPubKey, signature, xPubKey) { - let pub = (new HDPublicKey(xPubKey)).deriveChild(Constants.PATHS.REQUEST_KEY_AUTH).publicKey; + export const verifyRequestPubKey = function(requestPubKey, signature, xPubKey) { + let pub = new HDPublicKey(xPubKey).deriveChild(Constants.PATHS.REQUEST_KEY_AUTH).publicKey; return this.verifyMessage(requestPubKey, signature, pub.toString()); }; // Beginning the process of refactoring common methods into a unified merit core location. - export const formatAmount = function(micros: number, unit: string, opts: any) { + export const formatAmount = function(micros: number, unit: string, opts: any) { $.checkArgument(_.includes(_.keys(Constants.UNITS), unit)); return meritCoreFormatAmount(micros, unit, opts); @@ -172,10 +184,12 @@ export module Utils { $.checkState(o.script || o.toAddress, 'Output should have either toAddress or script specified'); if (o.script) { $.checkState(!isNaN(o.amount) || !isNaN(o.micros), 'Output should have either amount or micros specified'); - t.addOutput(new Transaction.Output({ - script: o.script, - micros: !isNaN(o.amount) ? o.amount : o.micros, - })); + t.addOutput( + new Transaction.Output({ + script: o.script, + micros: !isNaN(o.amount) ? o.amount : o.micros, + }), + ); } else { t.to(o.toAddress, o.amount); } @@ -199,12 +213,20 @@ export module Utils { } // Validate inputs vs outputs independently of meritcore - let totalInputs = _.reduce(txp.inputs, function(memo: any, i: any) { - return +i.micros + memo; - }, 0); - let totalOutputs = _.reduce(t.outputs, function(memo: any, o: any) { - return +o.micros + memo; - }, 0); + let totalInputs = _.reduce( + txp.inputs, + function(memo: any, i: any) { + return +i.micros + memo; + }, + 0, + ); + let totalOutputs = _.reduce( + t.outputs, + function(memo: any, o: any) { + return +o.micros + memo; + }, + 0, + ); $.checkState(totalInputs - totalOutputs >= 0); $.checkState(totalInputs - totalOutputs <= Defaults.adjustableMaxFee(totalOutputs)); diff --git a/packages/lightwallet/common/merit-wallet-client/lib/credentials.ts b/packages/lightwallet/common/merit-wallet-client/lib/credentials.ts index 920213f8d0..4eeed92a1d 100644 --- a/packages/lightwallet/common/merit-wallet-client/lib/credentials.ts +++ b/packages/lightwallet/common/merit-wallet-client/lib/credentials.ts @@ -47,10 +47,9 @@ const FIELDS = [ function _checkNetwork(network: string): void { if (!_.includes(['livenet', 'testnet'], network)) throw new Error('Invalid network'); -}; +} export class Credentials { - public network: string; public xPrivKey: any; public xPubKey: string; @@ -81,17 +80,13 @@ export class Credentials { public parentAddress: string; public hwInfo: string; - - - - public static create = function(network): Credentials { _checkNetwork(network); let x = new Credentials(); x.network = network; - x.xPrivKey = (new Meritcore.HDPrivateKey(network)).toString(); + x.xPrivKey = new Meritcore.HDPrivateKey(network).toString(); x.compliantDerivation = true; x._expand(); return x; @@ -106,22 +101,21 @@ export class Credentials { private static createMnemonicWithRetries(m?: string, tries?: number) { m = m || generateMnemonic(); tries = tries || 5; - if(!validateImportMnemonic(m)){ + if (!validateImportMnemonic(m)) { if (--tries > 0) { - this.createMnemonicWithRetries(m, tries) + this.createMnemonicWithRetries(m, tries); } else { - throw new Error("Error generating valid mnemonic") + throw new Error('Error generating valid mnemonic'); } } return m; } - public static createWithMnemonic = function(network, passphrase, language, account, opts: any = {}): Credentials { _checkNetwork(network); $.shouldBeNumber(account); - let m: string = this.createMnemonicWithRetries(null, 5); + let m: string = this.createMnemonicWithRetries(null, 5); let x = new Credentials(); x.network = network; x.account = account; @@ -147,7 +141,14 @@ export class Credentials { return x; }; - public static fromMnemonic = function(network, words, passphrase, account, derivationStrategy, opts: any = {}): Credentials { + public static fromMnemonic = function( + network, + words, + passphrase, + account, + derivationStrategy, + opts: any = {}, + ): Credentials { _checkNetwork(network); $.shouldBeNumber(account); $.checkArgument(_.includes(_.values(Constants.DERIVATION_STRATEGIES), derivationStrategy)); @@ -165,14 +166,21 @@ export class Credentials { return x; }; - public static fromExtendedPublicKey = function(xPubKey, source, entropySourceHex, account, derivationStrategy, opts: any = {}): Credentials { + public static fromExtendedPublicKey = function( + xPubKey, + source, + entropySourceHex, + account, + derivationStrategy, + opts: any = {}, + ): Credentials { $.checkArgument(entropySourceHex); $.shouldBeNumber(account); $.checkArgument(_.includes(_.values(Constants.DERIVATION_STRATEGIES), derivationStrategy)); let entropyBuffer = new Buffer(entropySourceHex, 'hex'); //require at least 112 bits of entropy - $.checkArgument(entropyBuffer.length >= 14, 'At least 112 bits of entropy are needed') + $.checkArgument(entropyBuffer.length >= 14, 'At least 112 bits of entropy are needed'); let x = new Credentials(); x.xPubKey = xPubKey; @@ -201,7 +209,7 @@ export class Credentials { x.addressType = x.addressType || Constants.SCRIPT_TYPES.P2SH; x.account = x.account || 0; - $.checkState(x.xPrivKey || x.xPubKey || x.xPrivKeyEncrypted, "invalid input"); + $.checkState(x.xPrivKey || x.xPubKey || x.xPrivKeyEncrypted, 'invalid input'); return x; }; @@ -212,14 +220,14 @@ export class Credentials { constructor() { this.network = ENV.network; - this.xPrivKey = (new Meritcore.HDPrivateKey(ENV.network)).toString(); + this.xPrivKey = new Meritcore.HDPrivateKey(ENV.network).toString(); this.compliantDerivation = true; this.version = '1.0.0'; this.derivationStrategy = Constants.DERIVATION_STRATEGIES.BIP44; this.account = 0; } - public Mnemonic = function(network, passphrase, language, account, opts): Credentials { + public Mnemonic = function(network, passphrase, language, account, opts): Credentials { $.shouldBeNumber(account); opts = opts || {}; @@ -281,14 +289,21 @@ export class Credentials { * entropySource should be a HEX string containing pseudo-random data, that can * be deterministically derived from the xPrivKey, and should not be derived from xPubKey */ - public edPublicKey = function(xPubKey, source, entropySourceHex, account, derivationStrategy, opts: any = {}): Credentials { + public edPublicKey = function( + xPubKey, + source, + entropySourceHex, + account, + derivationStrategy, + opts: any = {}, + ): Credentials { $.checkArgument(entropySourceHex); $.shouldBeNumber(account); $.checkArgument(_.includes(_.values(Constants.DERIVATION_STRATEGIES), derivationStrategy)); let entropyBuffer = new Buffer(entropySourceHex, 'hex'); //require at least 112 bits of entropy - $.checkArgument(entropyBuffer.length >= 14, 'At least 112 bits of entropy are needed') + $.checkArgument(entropyBuffer.length >= 14, 'At least 112 bits of entropy are needed'); let x = new Credentials(); x.xPubKey = xPubKey; @@ -319,7 +334,6 @@ export class Credentials { return b2.slice(0, length); }; - public _expand = function(): void { $.checkState(this.xPrivKey || (this.xPubKey && this.entropySource)); @@ -334,7 +348,9 @@ export class Credentials { if (this.xPrivKey) { let xPrivKey = new Meritcore.HDPrivateKey.fromString(this.xPrivKey); - deriveFn = this.compliantDerivation ? _.bind(xPrivKey.deriveChild, xPrivKey) : _.bind(xPrivKey.deriveNonCompliantChild, xPrivKey); + deriveFn = this.compliantDerivation + ? _.bind(xPrivKey.deriveChild, xPrivKey) + : _.bind(xPrivKey.deriveNonCompliantChild, xPrivKey); const derivedXPrivKey: any = deriveFn(this.getBaseAddressDerivationPath()); @@ -371,10 +387,12 @@ export class Credentials { this.personalEncryptingKey = this._hashFromEntropy('personalKey', 16).toString('base64'); this.copayerId = Credentials._xPubToCopayerId(this.xPubKey); - this.publicKeyRing = [{ - xPubKey: this.xPubKey, - requestPubKey: this.requestPubKey, - }]; + this.publicKeyRing = [ + { + xPubKey: this.xPubKey, + requestPubKey: this.requestPubKey, + }, + ]; }; public fromObj = function(obj): Credentials { @@ -388,7 +406,7 @@ export class Credentials { x.addressType = x.addressType || Constants.SCRIPT_TYPES.P2SH; x.account = x.account || 0; - $.checkState(x.xPrivKey || x.xPubKey || x.xPrivKeyEncrypted, "invalid input"); + $.checkState(x.xPrivKey || x.xPubKey || x.xPrivKeyEncrypted, 'invalid input'); return x; }; @@ -417,14 +435,16 @@ export class Credentials { throw new Error('Credentials#getBaseAddressDerivationPath: derivation strategy is not set.'); } - let coin = (this.network == 'livenet' ? "0" : "1"); - return "m/" + purpose + "'/" + coin + "'/" + this.account + "'"; + let coin = this.network == 'livenet' ? '0' : '1'; + return 'm/' + purpose + "'/" + coin + "'/" + this.account + "'"; }; public getDerivedXPrivKey = function(password) { let path = this.getBaseAddressDerivationPath(); let xPrivKey = new Meritcore.HDPrivateKey(this.getKeys(password).xPrivKey, this.network); - let deriveFn = !!this.compliantDerivation ? _.bind(xPrivKey.deriveChild, xPrivKey) : _.bind(xPrivKey.deriveNonCompliantChild, xPrivKey); + let deriveFn = !!this.compliantDerivation + ? _.bind(xPrivKey.deriveChild, xPrivKey) + : _.bind(xPrivKey.deriveNonCompliantChild, xPrivKey); return deriveFn(path); }; @@ -434,7 +454,7 @@ export class Credentials { }; // TODO: figure out if we need to store refid in credentials - public addWalletInfo = function(walletId, walletName, m, n, copayerName, parentAddress): void { + public addWalletInfo = function(walletId, walletName, m, n, copayerName, parentAddress): void { this.walletId = walletId; this.walletName = walletName; this.m = m; @@ -443,13 +463,10 @@ export class Credentials { this.parentAddress = parentAddress; this.unlocked = true; - if (copayerName) - this.copayerName = copayerName; + if (copayerName) this.copayerName = copayerName; - if (this.derivationStrategy == 'BIP44' && n == 1) - this.addressType = Constants.SCRIPT_TYPES.P2PKH; - else - this.addressType = Constants.SCRIPT_TYPES.P2SH; + if (this.derivationStrategy == 'BIP44' && n == 1) this.addressType = Constants.SCRIPT_TYPES.P2PKH; + else this.addressType = Constants.SCRIPT_TYPES.P2SH; // Use m/48' for multisig hardware wallets if (!this.xPrivKey && this.externalSource && n > 1) { @@ -457,10 +474,12 @@ export class Credentials { } if (n == 1) { - this.addPublicKeyRing([{ - xPubKey: this.xPubKey, - requestPubKey: this.requestPubKey, - }]); + this.addPublicKeyRing([ + { + xPubKey: this.xPubKey, + requestPubKey: this.requestPubKey, + }, + ]); } }; @@ -469,31 +488,25 @@ export class Credentials { }; public isPrivKeyEncrypted = function() { - return (!!this.xPrivKeyEncrypted) && !this.xPrivKey; + return !!this.xPrivKeyEncrypted && !this.xPrivKey; }; public encryptPrivateKey = function(password, opts): void { - if (this.xPrivKeyEncrypted) - throw new Error('Private key already encrypted'); - - if (!this.xPrivKey) - throw new Error('No private key to encrypt'); + if (this.xPrivKeyEncrypted) throw new Error('Private key already encrypted'); + if (!this.xPrivKey) throw new Error('No private key to encrypt'); this.xPrivKeyEncrypted = sjcl.encrypt(password, this.xPrivKey, opts); - if (!this.xPrivKeyEncrypted) - throw new Error('Could not encrypt'); + if (!this.xPrivKeyEncrypted) throw new Error('Could not encrypt'); - if (this.mnemonic) - this.mnemonicEncrypted = sjcl.encrypt(password, this.mnemonic, opts); + if (this.mnemonic) this.mnemonicEncrypted = sjcl.encrypt(password, this.mnemonic, opts); delete this.xPrivKey; delete this.mnemonic; }; public decryptPrivateKey = function(password): void { - if (!this.xPrivKeyEncrypted) - throw new Error('Private key is not encrypted'); + if (!this.xPrivKeyEncrypted) throw new Error('Private key is not encrypted'); try { this.xPrivKey = sjcl.decrypt(password, this.xPrivKeyEncrypted); @@ -508,8 +521,8 @@ export class Credentials { } }; - public getKeys = function(password):any { - let keys:any = {}; + public getKeys = function(password): any { + let keys: any = {}; if (this.isPrivKeyEncrypted()) { $.checkArgument(password, 'Private keys are encrypted, a password is needed'); @@ -534,7 +547,7 @@ export class Credentials { }; public canSign = function(): boolean { - return (!!this.xPrivKey || !!this.xPrivKeyEncrypted); + return !!this.xPrivKey || !!this.xPrivKeyEncrypted; }; public setNoSign = function(): void { @@ -551,7 +564,7 @@ export class Credentials { }; public hasExternalSource = function(): boolean { - return (typeof this.externalSource == "string"); + return typeof this.externalSource == 'string'; }; public getExternalSourceName = function() { diff --git a/packages/lightwallet/common/merit-wallet-client/lib/errors/index.ts b/packages/lightwallet/common/merit-wallet-client/lib/errors/index.ts index 4ca563dc5d..cd29e9404f 100644 --- a/packages/lightwallet/common/merit-wallet-client/lib/errors/index.ts +++ b/packages/lightwallet/common/merit-wallet-client/lib/errors/index.ts @@ -4,14 +4,19 @@ export class MwcError extends Error { } } - export class MWCErrors { public static INVALID_BACKUP = new MwcError('INVALID_BACKUP', 'Invalid backup'); public static WALLET_DOES_NOT_EXIST = new MwcError('WALLET_DOES_NOT_EXIST', 'Wallet does not exist'); public static MISSING_PRIVATE_KEY = new MwcError('MISSING_PRIVATE_KEY', 'Missing private keys to sign'); - public static ENCRYPTED_PRIVATE_KEY = new MwcError('ENCRYPTED_PRIVATE_KEY', 'Private key is encrypted, cannot sign transaction'); + public static ENCRYPTED_PRIVATE_KEY = new MwcError( + 'ENCRYPTED_PRIVATE_KEY', + 'Private key is encrypted, cannot sign transaction', + ); public static SERVER_COMPROMISED = new MwcError('SERVER_COMPROMISED', 'Server response could not be verified'); - public static COULD_NOT_BUILD_TRANSACTION = new MwcError('COULD_NOT_BUILD_TRANSACTION', 'Could not build the transaction'); + public static COULD_NOT_BUILD_TRANSACTION = new MwcError( + 'COULD_NOT_BUILD_TRANSACTION', + 'Could not build the transaction', + ); public static INSUFFICIENT_FUNDS = new MwcError('INSUFFICIENT_FUNDS', 'Insufficient funds'); public static CONNECTION_ERROR = new MwcError('CONNECTION_ERROR', 'Connection error'); public static NOT_FOUND = new MwcError('NOT_FOUND', 'Not found'); @@ -30,7 +35,10 @@ export class MWCErrors { public static TX_NOT_FOUND = new MwcError('TX_NOT_FOUND', 'Transaction proposal not found'); public static INVALID_REFERRAL = new MwcError('INVALID_REFERRAL', 'Invalid referral'); public static REFERRER_INVALID = new MwcError('REFERRER_INVALID', 'Invalid referrer address'); - public static MAIN_ADDRESS_GAP_REACHED = new MwcError('MAIN_ADDRESS_GAP_REACHED', 'Maximum number of consecutive addresses without activity reached'); + public static MAIN_ADDRESS_GAP_REACHED = new MwcError( + 'MAIN_ADDRESS_GAP_REACHED', + 'Maximum number of consecutive addresses without activity reached', + ); public static SERVER_UNAVAILABLE = new MwcError('SERVER_UNAVAILABLE', 'Could not reach the server'); public static TX_MAX_SIZE_EXCEEDED = new MwcError('TX_MAX_SIZE_EXCEEDED', 'Maximum size of transaction exceeded'); } diff --git a/packages/lightwallet/common/merit-wallet-client/lib/errors/spec.ts b/packages/lightwallet/common/merit-wallet-client/lib/errors/spec.ts index a7065eabef..7fe75228a3 100644 --- a/packages/lightwallet/common/merit-wallet-client/lib/errors/spec.ts +++ b/packages/lightwallet/common/merit-wallet-client/lib/errors/spec.ts @@ -1,72 +1,96 @@ -export const errorSpec = [{ - name: 'INVALID_BACKUP', - message: 'Invalid Backup.' -}, { - name: 'WALLET_DOES_NOT_EXIST', - message: 'Wallet does not exist.' -}, { - name: 'MISSING_PRIVATE_KEY', - message: 'Missing private keys to sign.' -}, { - name: 'ENCRYPTED_PRIVATE_KEY', - message: 'Private key is encrypted, cannot sign transaction.' -}, { - name: 'SERVER_COMPROMISED', - message: 'Server response could not be verified.' -}, { - name: 'COULD_NOT_BUILD_TRANSACTION', - message: 'Could not build the transaction.' -}, { - name: 'INSUFFICIENT_FUNDS', - message: 'Insufficient funds.' -}, { - name: 'CONNECTION_ERROR', - message: 'Wallet service connection error.' -}, { - name: 'NOT_FOUND', - message: 'Wallet service not found.' -}, { - name: 'ECONNRESET_ERROR', - message: 'ECONNRESET, body: {0}' -}, { - name: 'WALLET_ALREADY_EXISTS', - message: 'Wallet already exists.' -}, { - name: 'COPAYER_IN_WALLET', - message: 'Copayer in wallet.' -}, { - name: 'WALLET_FULL', - message: 'Wallet is full.' -}, { - name: 'WALLET_NOT_FOUND', - message: 'Wallet not found.' -}, { - name: 'INSUFFICIENT_FUNDS_FOR_FEE', - message: 'Insufficient funds for fee.' -}, { - name: 'LOCKED_FUNDS', - message: 'Locked funds.' -}, { - name: 'DUST_AMOUNT', - message: 'Amount below dust threshold.' -}, { - name: 'COPAYER_VOTED', - message: 'Copayer already voted on this transaction proposal.' -}, { - name: 'NOT_AUTHORIZED', - message: 'Not authorized.' -}, { - name: 'UNAVAILABLE_UTXOS', - message: 'Unavailable unspent outputs.' -}, { - name: 'TX_NOT_FOUND', - message: 'Transaction proposal not found.' -}, { - name: 'UNLOCK_CODE_INVALID', - message: 'Invalid unlock code.' -}, { - name: 'MAIN_ADDRESS_GAP_REACHED', - message: 'Maximum number of consecutive addresses without activity reached.' -}]; +export const errorSpec = [ + { + name: 'INVALID_BACKUP', + message: 'Invalid Backup.', + }, + { + name: 'WALLET_DOES_NOT_EXIST', + message: 'Wallet does not exist.', + }, + { + name: 'MISSING_PRIVATE_KEY', + message: 'Missing private keys to sign.', + }, + { + name: 'ENCRYPTED_PRIVATE_KEY', + message: 'Private key is encrypted, cannot sign transaction.', + }, + { + name: 'SERVER_COMPROMISED', + message: 'Server response could not be verified.', + }, + { + name: 'COULD_NOT_BUILD_TRANSACTION', + message: 'Could not build the transaction.', + }, + { + name: 'INSUFFICIENT_FUNDS', + message: 'Insufficient funds.', + }, + { + name: 'CONNECTION_ERROR', + message: 'Wallet service connection error.', + }, + { + name: 'NOT_FOUND', + message: 'Wallet service not found.', + }, + { + name: 'ECONNRESET_ERROR', + message: 'ECONNRESET, body: {0}', + }, + { + name: 'WALLET_ALREADY_EXISTS', + message: 'Wallet already exists.', + }, + { + name: 'COPAYER_IN_WALLET', + message: 'Copayer in wallet.', + }, + { + name: 'WALLET_FULL', + message: 'Wallet is full.', + }, + { + name: 'WALLET_NOT_FOUND', + message: 'Wallet not found.', + }, + { + name: 'INSUFFICIENT_FUNDS_FOR_FEE', + message: 'Insufficient funds for fee.', + }, + { + name: 'LOCKED_FUNDS', + message: 'Locked funds.', + }, + { + name: 'DUST_AMOUNT', + message: 'Amount below dust threshold.', + }, + { + name: 'COPAYER_VOTED', + message: 'Copayer already voted on this transaction proposal.', + }, + { + name: 'NOT_AUTHORIZED', + message: 'Not authorized.', + }, + { + name: 'UNAVAILABLE_UTXOS', + message: 'Unavailable unspent outputs.', + }, + { + name: 'TX_NOT_FOUND', + message: 'Transaction proposal not found.', + }, + { + name: 'UNLOCK_CODE_INVALID', + message: 'Invalid unlock code.', + }, + { + name: 'MAIN_ADDRESS_GAP_REACHED', + message: 'Maximum number of consecutive addresses without activity reached.', + }, +]; module.exports = errorSpec; diff --git a/packages/lightwallet/common/merit-wallet-client/lib/index.ts b/packages/lightwallet/common/merit-wallet-client/lib/index.ts index 1eeee2e55f..9d0e7c6a4d 100644 --- a/packages/lightwallet/common/merit-wallet-client/lib/index.ts +++ b/packages/lightwallet/common/merit-wallet-client/lib/index.ts @@ -22,9 +22,9 @@ export class MeritClient extends Client { public Utils: any = Utils; public sjcl: any = sjcl; public Meritcore: Meritcore = Meritcore; - public sdsa:any; + public sdsa: any; - constructor(opts:any = {}) { + constructor(opts: any = {}) { super(opts); } } diff --git a/packages/lightwallet/common/merit-wallet-client/lib/log.ts b/packages/lightwallet/common/merit-wallet-client/lib/log.ts index ed166e053c..79232676f8 100644 --- a/packages/lightwallet/common/merit-wallet-client/lib/log.ts +++ b/packages/lightwallet/common/merit-wallet-client/lib/log.ts @@ -26,7 +26,7 @@ export interface LoggerWithLevels { warn(message: string, ...supportingDetails: any[]): void; error(message: string, ...supportingDetails: any[]): void; fatal(message: string, ...supportingDetails: any[]): void; - } +} export class Logger implements LoggerWithLevels { private static _instance: Logger; @@ -37,19 +37,18 @@ export class Logger implements LoggerWithLevels { return this.levels; }; - private levels = { - 'silent': -1, - 'debug': 0, - 'info': 1, - 'log': 2, - 'warn': 3, - 'error': 4, - 'fatal': 5 + silent: -1, + debug: 0, + info: 1, + log: 2, + warn: 3, + error: 4, + fatal: 5, }; public silent(message: string, ...supportingDetails: any[]): void { - this.logMessage('silent', message) + this.logMessage('silent', message); } /** @@ -59,17 +58,17 @@ export class Logger implements LoggerWithLevels { * @param {*} args - the arguments to be logged. */ public debug(message: string, ...supportingDetails: any[]): void { - this.logMessage('debug', message) + this.logMessage('debug', message); } - /** + /** * @class Logger * @method log * @desc Log messages at an intermediary level called 'log'. * @param {*} args - the arguments to be logged. */ public log(message: string, ...supportingDetails: any[]): void { - this.logMessage('log', message) + this.logMessage('log', message); } /** @@ -79,7 +78,7 @@ export class Logger implements LoggerWithLevels { * @param {*} args - the arguments to be logged. */ public info(message: string, ...supportingDetails: any[]): void { - this.logMessage('info', message) + this.logMessage('info', message); } /** @@ -89,7 +88,7 @@ export class Logger implements LoggerWithLevels { * @param {*} args - the arguments to be logged. */ public warn(message: string, ...supportingDetails: any[]): void { - this.logMessage('warn', message) + this.logMessage('warn', message); } /** @@ -99,7 +98,7 @@ export class Logger implements LoggerWithLevels { * @param {*} args - the arguments to be logged. */ public error(message: string, ...supportingDetails: any[]): void { - this.logMessage('error', message) + this.logMessage('error', message); } /** @@ -109,22 +108,21 @@ export class Logger implements LoggerWithLevels { * @param {*} args - the arguments to be logged. */ public fatal(message: string, ...supportingDetails: any[]): void { - this.logMessage('fatal', message) + this.logMessage('fatal', message); } private constructor() { - this.name = "Merit Log"; + this.name = 'Merit Log'; this.level = DEFAULT_LOG_LEVEL; - _.each(this.levels, function(level, levelName: string) { - - }); + _.each(this.levels, function(level, levelName: string) {}); } private logMessage(levelName: string, message: string, supportingDetails?: any[]) { - let level:number = this.levels[levelName] || -1; + let level: number = this.levels[levelName] || -1; - if (levelName === 'silent') { // dont create a log.silent() method + if (levelName === 'silent') { + // dont create a log.silent() method return; } if (level >= this.levels[this.level]) { @@ -142,7 +140,7 @@ export class Logger implements LoggerWithLevels { Error.stackTraceLimit = old; let str = '[' + levelName + (caller || '') + '] ' + arguments[0], - extraArgs = [].slice.call(arguments, 1); + extraArgs = [].slice.call(arguments, 1); if (console[levelName]) { extraArgs.unshift(str); console[levelName].apply(console, extraArgs); @@ -153,7 +151,7 @@ export class Logger implements LoggerWithLevels { console.log(str); } } - }; + } } /** @@ -168,14 +166,13 @@ export class Logger implements LoggerWithLevels { this.level = level; }; - /** + /** * @desc * Return singleton * * @param {string} level - the name of the logging level */ public static getInstance() { - return (this._instance || new Logger()); - }; - + return this._instance || new Logger(); + } } diff --git a/packages/lightwallet/common/merit-wallet-client/lib/paypro.ts b/packages/lightwallet/common/merit-wallet-client/lib/paypro.ts index e135e6fa89..2112e13a35 100644 --- a/packages/lightwallet/common/merit-wallet-client/lib/paypro.ts +++ b/packages/lightwallet/common/merit-wallet-client/lib/paypro.ts @@ -1,21 +1,21 @@ import * as request from 'superagent'; import * as _ from 'lodash'; -import { Logger } from "./log"; +import { Logger } from './log'; import * as preconditions from 'preconditions'; import * as Meritcore from 'meritcore-lib'; import * as MeritcorePayPro from 'merit-payment-protocol'; const $ = preconditions.singleton(); -export module PayPro { +export namespace PayPro { const logger = Logger.getInstance(); logger.setLevel('debug'); const TIMEOUT = 5000; - let _request = (opts:any): Promise => { + let _request = (opts: any): Promise => { return new Promise((resolve, reject) => { let fn = opts.method == 'POST' ? 'post' : 'get'; if (!opts.url) { - return reject(new Error("No URL for PayPro request.")); + return reject(new Error('No URL for PayPro request.')); } let reqUrl = opts.url; @@ -25,35 +25,34 @@ export module PayPro { let headers = opts.headers || {}; //req.body = req.body || req.data || ''; _.each(headers, (v, k) => { - if (v) r.set(k,v); + if (v) r.set(k, v); }); r.timeout(TIMEOUT); - return r.then((res) => { + return r.then(res => { if (!res) { - return reject(new Error("No reply from PayPro")); + return reject(new Error('No reply from PayPro')); } return resolve(res); }); }); - - } + }; export let get = (opts): Promise => { $.checkArgument(opts && opts.url); opts.headers = opts.headers || { - 'Accept': MeritcorePayPro.PAYMENT_REQUEST_CONTENT_TYPE, + Accept: MeritcorePayPro.PAYMENT_REQUEST_CONTENT_TYPE, 'Content-Type': 'application/octet-stream', }; - return _request(opts).then((res) => { + return _request(opts).then(res => { let request, verified, signature, serializedDetails; try { let body = MeritcorePayPro.PaymentRequest.decode(res.body); - request = (new MeritcorePayPro()).makePaymentRequest(body); + request = new MeritcorePayPro().makePaymentRequest(body); signature = request.get('signature'); serializedDetails = request.get('serialized_payment_details'); // Verify the signature @@ -69,7 +68,9 @@ export module PayPro { let outputs = pd.get('outputs'); if (outputs.length > 1) - return Promise.reject(new Error('Payment Protocol Error: Requests with more that one output are not supported')) + return Promise.reject( + new Error('Payment Protocol Error: Requests with more that one output are not supported'), + ); let output = outputs[0]; @@ -117,7 +118,6 @@ export module PayPro { }); }; - let _getPayProRefundOutputs = (addrStr, amount) => { amount = amount.toString(10); @@ -139,7 +139,6 @@ export module PayPro { return [output]; }; - let _createPayment = (merchant_data, rawTx, refundAddr, amountMicros) => { let pay = new MeritcorePayPro(); pay = pay.makePayment(); @@ -153,8 +152,7 @@ export module PayPro { pay.set('transactions', [txBuf]); let refund_outputs = _getPayProRefundOutputs(refundAddr, amountMicros); - if (refund_outputs) - pay.set('refund_to', refund_outputs); + if (refund_outputs) pay.set('refund_to', refund_outputs); // Unused for now // options.memo = ''; @@ -182,24 +180,24 @@ export module PayPro { opts.method = 'POST'; opts.headers = opts.headers || { - 'Accept': MeritcorePayPro.PAYMENT_ACK_CONTENT_TYPE, + Accept: MeritcorePayPro.PAYMENT_ACK_CONTENT_TYPE, 'Content-Type': MeritcorePayPro.PAYMENT_CONTENT_TYPE, // 'Content-Type': 'application/octet-stream', }; opts.body = payment; - return _request(opts).then((rawData) => { - if (!rawData) return reject(new Error("No RawData from PayPro sending event.")); + return _request(opts).then(rawData => { + if (!rawData) return reject(new Error('No RawData from PayPro sending event.')); let memo; - try { - let data = MeritcorePayPro.PaymentACK.decode(rawData); - let pp = new MeritcorePayPro(); - let ack = pp.makePaymentACK(data); - memo = ack.get('memo'); - } catch (e) { - logger.info("Error in PayPro Payment Ack: " + e); - }; - return resolve({rawData, memo}); + try { + let data = MeritcorePayPro.PaymentACK.decode(rawData); + let pp = new MeritcorePayPro(); + let ack = pp.makePaymentACK(data); + memo = ack.get('memo'); + } catch (e) { + logger.info('Error in PayPro Payment Ack: ' + e); + } + return resolve({ rawData, memo }); }); }); }; diff --git a/packages/lightwallet/common/merit-wallet-client/lib/verifier.ts b/packages/lightwallet/common/merit-wallet-client/lib/verifier.ts index 32e8f84e1d..0450e25bda 100644 --- a/packages/lightwallet/common/merit-wallet-client/lib/verifier.ts +++ b/packages/lightwallet/common/merit-wallet-client/lib/verifier.ts @@ -4,18 +4,15 @@ const $ = preconditions.singleton(); import * as Meritcore from 'meritcore-lib'; import { Common } from './common'; let Utils = Common.Utils; -import { Logger } from "./log"; +import { Logger } from './log'; const log = Logger.getInstance(); - /** * @desc Verifier constructor. Checks data given by the server * * @constructor */ -export module Verifier { - - +export namespace Verifier { /** * Check address * @@ -27,9 +24,15 @@ export module Verifier { if (!address) return false; $.checkState(credentials.isComplete()); - var local = Utils.deriveAddress(address.type || credentials.addressType, credentials.publicKeyRing, address.path, credentials.m, credentials.network); + var local = Utils.deriveAddress( + address.type || credentials.addressType, + credentials.publicKeyRing, + address.path, + credentials.m, + credentials.network, + ); - return (local.address == address.address && _.difference(local.publicKeys, address.publicKeys).length === 0); + return local.address == address.address && _.difference(local.publicKeys, address.publicKeys).length === 0; }; /** @@ -41,7 +44,9 @@ export module Verifier { */ export let checkCopayers = function(credentials, copayers): boolean { $.checkState(credentials.walletPrivKey); - var walletPubKey = Meritcore.PrivateKey.fromString(credentials.walletPrivKey).toPublicKey().toString(); + var walletPubKey = Meritcore.PrivateKey.fromString(credentials.walletPrivKey) + .toPublicKey() + .toString(); if (copayers.length != credentials.n) { log.error('Missing public keys in server response'); @@ -60,7 +65,12 @@ export module Verifier { } // Not signed pub keys - if (!(copayer.encryptedName || copayer.name) || !copayer.xPubKey || !copayer.requestPubKey || !copayer.signature) { + if ( + !(copayer.encryptedName || copayer.name) || + !copayer.xPubKey || + !copayer.requestPubKey || + !copayer.signature + ) { log.error('Missing copayer fields in server response'); error = true; } else { @@ -75,7 +85,7 @@ export module Verifier { if (error) return false; if (!_.includes(_.map(copayers, 'xPubKey'), credentials.xPubKey)) { - log.error('Server response does not contains our let keys') + log.error('Server response does not contains our let keys'); return false; } return true; @@ -83,7 +93,7 @@ export module Verifier { export let checkProposalCreation = function(args, txp, encryptingKey, sendMax?): boolean { function strEqual(str1, str2) { - return ((!str1 && !str2) || (str1 === str2)); + return (!str1 && !str2) || str1 === str2; } if (txp.outputs.length != args.outputs.length) return false; @@ -111,7 +121,7 @@ export module Verifier { } if (args.changeAddress && !strEqual(changeAddress, args.changeAddress)) return false; - if (_.isNumber(args.feePerKb) && (txp.feePerKb != args.feePerKb)) return false; + if (_.isNumber(args.feePerKb) && txp.feePerKb != args.feePerKb) return false; if (!strEqual(txp.payProUrl, args.payProUrl)) return false; let decryptedMessage = null; @@ -139,7 +149,6 @@ export module Verifier { // If the txp using a selfsigned pub key? if (txp.proposalSignaturePubKey) { - // Verify it... if (!Utils.verifyRequestPubKey(txp.proposalSignaturePubKey, txp.proposalSignaturePubKeySig, creatorKeys.xPubKey)) return false; @@ -159,16 +168,13 @@ export module Verifier { } log.debug('Regenerating & verifying tx proposal hash -> Hash: ', hash, ' Signature: ', txp.proposalSignature); - if (!Utils.verifyMessage(hash, txp.proposalSignature, creatorSigningPubKey)) - return false; + if (!Utils.verifyMessage(hash, txp.proposalSignature, creatorSigningPubKey)) return false; - if (!this.checkAddress(credentials, txp.changeAddress)) - return false; + if (!this.checkAddress(credentials, txp.changeAddress)) return false; return true; }; - export let checkPaypro = function(txp, payproOpts): boolean { var toAddress, amount; @@ -180,10 +186,9 @@ export module Verifier { amount = txp.amount; } - return (toAddress == payproOpts.toAddress && amount == payproOpts.amount); + return toAddress == payproOpts.toAddress && amount == payproOpts.amount; }; - /** * Check transaction proposal * @@ -195,13 +200,10 @@ export module Verifier { export let checkTxProposal = function(credentials, txp, opts): boolean { opts = opts || {}; - if (!this.checkTxProposalSignature(credentials, txp)) - return false; + if (!this.checkTxProposalSignature(credentials, txp)) return false; - if (opts.paypro && !this.checkPaypro(txp, opts.paypro)) - return false; + if (opts.paypro && !this.checkPaypro(txp, opts.paypro)) return false; return true; }; - } diff --git a/packages/lightwallet/common/merit-wallet-client/test/client.js b/packages/lightwallet/common/merit-wallet-client/test/client.js index d5852a80ff..d9b562e4de 100644 --- a/packages/lightwallet/common/merit-wallet-client/test/client.js +++ b/packages/lightwallet/common/merit-wallet-client/test/client.js @@ -10,7 +10,7 @@ var async = require('async'); var request = require('supertest'); var Uuid = require('uuid'); var tingodb = require('tingodb')({ - memStore: true + memStore: true, }); var log = require('../lib/log'); @@ -57,17 +57,20 @@ helpers.stubRequest = function(err, res) { timeout: sinon.stub(), end: sinon.stub().yields(err, res), }; - var reqFactory = _.reduce(['get', 'post', 'put', 'delete'], function(mem, verb) { - mem[verb] = function(url) { - return request; - }; - return mem; - }, {}); + var reqFactory = _.reduce( + ['get', 'post', 'put', 'delete'], + function(mem, verb) { + mem[verb] = function(url) { + return request; + }; + return mem; + }, + {}, + ); return reqFactory; }; - helpers.newDb = function() { this.dbCounter = (this.dbCounter || 0) + 1; return new tingodb.Db('./db/test' + this.dbCounter, {}); @@ -76,7 +79,6 @@ helpers.newDb = function() { helpers.generateUtxos = function(scriptType, publicKeyRing, path, requiredSignatures, amounts) { var amounts = [].concat(amounts); var utxos = _.map(amounts, function(amount, i) { - var address = Utils.deriveAddress(scriptType, publicKeyRing, path, requiredSignatures, 'testnet'); var scriptPubKey; @@ -113,44 +115,60 @@ helpers.createAndJoinWallet = function(clients, m, n, opts, cb) { opts = opts || {}; clients[0].seedFromRandomWithMnemonic({ - network: 'testnet' - }); - clients[0].createWallet('mywallet', 'creator', m, n, { network: 'testnet', - beacon: 'code', - singleAddress: !!opts.singleAddress, - }, function(err, secret) { - should.not.exist(err); - - if (n > 1) { - should.exist(secret); - } - - async.series([ + }); + clients[0].createWallet( + 'mywallet', + 'creator', + m, + n, + { + network: 'testnet', + beacon: 'code', + singleAddress: !!opts.singleAddress, + }, + function(err, secret) { + should.not.exist(err); + + if (n > 1) { + should.exist(secret); + } - function(next) { - async.each(_.range(1, n), function(i, cb) { - clients[i].seedFromRandomWithMnemonic({ - network: 'testnet' - }); - clients[i].joinWallet(secret, 'copayer ' + i, {}, cb); - }, next); - }, - function(next) { - async.each(_.range(n), function(i, cb) { - clients[i].openWallet(cb); - }, next); + async.series( + [ + function(next) { + async.each( + _.range(1, n), + function(i, cb) { + clients[i].seedFromRandomWithMnemonic({ + network: 'testnet', + }); + clients[i].joinWallet(secret, 'copayer ' + i, {}, cb); + }, + next, + ); + }, + function(next) { + async.each( + _.range(n), + function(i, cb) { + clients[i].openWallet(cb); + }, + next, + ); + }, + ], + function(err) { + should.not.exist(err); + return cb({ + m: m, + n: n, + secret: secret, + }); }, - ], - function(err) { - should.not.exist(err); - return cb({ - m: m, - n: n, - secret: secret, - }); - }); - }); + ); + }, + ); }; helpers.tamperResponse = function(clients, method, url, args, tamper, cb) { @@ -161,7 +179,10 @@ helpers.tamperResponse = function(clients, method, url, args, tamper, cb) { tamper(result); // Return tampered data for every client in the list _.each(clients, function(client) { - client._doRequest = sinon.stub().withArgs(method, url).yields(null, result); + client._doRequest = sinon + .stub() + .withArgs(method, url) + .yields(null, result); }); return cb(); }); @@ -169,16 +190,21 @@ helpers.tamperResponse = function(clients, method, url, args, tamper, cb) { helpers.createAndPublishTxProposal = function(client, opts, cb) { if (!opts.outputs) { - opts.outputs = [{ - toAddress: opts.toAddress, - amount: opts.amount, - }]; + opts.outputs = [ + { + toAddress: opts.toAddress, + amount: opts.amount, + }, + ]; } client.createTxProposal(opts, function(err, txp) { if (err) return cb(err); - client.publishTxProposal({ - txp: txp - }, cb); + client.publishTxProposal( + { + txp: txp, + }, + cb, + ); }); }; @@ -195,7 +221,9 @@ blockchainExplorerMock.setUtxo = function(address, amount, m, confirmations) { var scriptPubKey; switch (address.type) { case Constants.SCRIPT_TYPES.P2SH: - scriptPubKey = address.publicKeys ? Meritcore.Script.buildMultisigOut(address.publicKeys, m).toScriptHashOut() : ''; + scriptPubKey = address.publicKeys + ? Meritcore.Script.buildMultisigOut(address.publicKeys, m).toScriptHashOut() + : ''; break; case Constants.SCRIPT_TYPES.P2PKH: scriptPubKey = Meritcore.Script.buildPublicKeyHashOut(address.address); @@ -204,17 +232,17 @@ blockchainExplorerMock.setUtxo = function(address, amount, m, confirmations) { should.exist(scriptPubKey); blockchainExplorerMock.utxos.push({ txid: Meritcore.crypto.Hash.sha256(new Buffer(Math.random() * 100000)).toString('hex'), - vout: Math.floor((Math.random() * 10) + 1), + vout: Math.floor(Math.random() * 10 + 1), amount: amount, address: address.address, scriptPubKey: scriptPubKey.toBuffer().toString('hex'), - confirmations: _.isUndefined(confirmations) ? Math.floor((Math.random() * 100) + 1) : +confirmations, + confirmations: _.isUndefined(confirmations) ? Math.floor(Math.random() * 100 + 1) : +confirmations, }); }; blockchainExplorerMock.broadcast = function(raw, cb) { blockchainExplorerMock.lastBroadcasted = raw; - return cb(null, (new Meritcore.Transaction(raw)).id); + return cb(null, new Meritcore.Transaction(raw).id); }; blockchainExplorerMock.setHistory = function(txs) { @@ -264,7 +292,8 @@ describe('client API', function() { db: helpers.newDb(), }); var expressApp = new ExpressApp(); - expressApp.start({ + expressApp.start( + { ignoreRateLimiter: true, storage: storage, blockchainExplorer: blockchainExplorerMock, @@ -286,7 +315,8 @@ describe('client API', function() { sandbox.stub(log, 'error'); } done(); - }); + }, + ); }); afterEach(function(done) { sandbox.restore(); @@ -298,13 +328,13 @@ describe('client API', function() { var originalLogLevel = log.level; var client = new Client({ - logLevel: 'info' + logLevel: 'info', }); client.logLevel.should.equal('info'); log.level.should.equal('info'); var client = new Client({ - logLevel: 'debug' + logLevel: 'debug', }); client.logLevel.should.equal('debug'); log.level.should.equal('debug'); @@ -315,7 +345,7 @@ describe('client API', function() { it('should use silent for the log level if no logLevel is specified', function() { var originalLogLevel = log.level; - log.level = 'foo;' + log.level = 'foo;'; var client = new Client(); client.logLevel.should.equal('silent'); @@ -348,88 +378,115 @@ describe('client API', function() { s.storeWallet = sinon.stub().yields('bigerror'); s.fetchWallet = sinon.stub().yields(null); var expressApp = new ExpressApp(); - expressApp.start({ - storage: s, - blockchainExplorer: blockchainExplorerMock, - disableLogs: true, - }, function() { - var s2 = sinon.stub(); - s2.load = sinon.stub().yields(null); - var client = helpers.newClient(app); - client.storage = s2; - client.createWallet('1', '2', 1, 1, { - network: 'testnet', - beacon: 'beacon', - }, - function(err) { - err.should.be.an.instanceOf(Error); - err.message.should.equal('bigerror'); - done(); - }); - }); + expressApp.start( + { + storage: s, + blockchainExplorer: blockchainExplorerMock, + disableLogs: true, + }, + function() { + var s2 = sinon.stub(); + s2.load = sinon.stub().yields(null); + var client = helpers.newClient(app); + client.storage = s2; + client.createWallet( + '1', + '2', + 1, + 1, + { + network: 'testnet', + beacon: 'beacon', + }, + function(err) { + err.should.be.an.instanceOf(Error); + err.message.should.equal('bigerror'); + done(); + }, + ); + }, + ); }); it('should handle critical errors (Case2)', function(done) { var s = sinon.stub(); s.storeWallet = sinon.stub().yields({ code: 501, - message: 'wow' + message: 'wow', }); s.fetchWallet = sinon.stub().yields(null); var expressApp = new ExpressApp(); - expressApp.start({ - storage: s, - blockchainExplorer: blockchainExplorerMock, - disableLogs: true, - }, function() { - var s2 = sinon.stub(); - s2.load = sinon.stub().yields(null); - var client = helpers.newClient(app); - client.storage = s2; - client.createWallet('1', '2', 1, 1, { - network: 'testnet', - beacon: 'beacon', - }, - function(err) { - err.should.be.an.instanceOf(Error); - err.message.should.equal('wow'); - done(); - }); - }); + expressApp.start( + { + storage: s, + blockchainExplorer: blockchainExplorerMock, + disableLogs: true, + }, + function() { + var s2 = sinon.stub(); + s2.load = sinon.stub().yields(null); + var client = helpers.newClient(app); + client.storage = s2; + client.createWallet( + '1', + '2', + 1, + 1, + { + network: 'testnet', + beacon: 'beacon', + }, + function(err) { + err.should.be.an.instanceOf(Error); + err.message.should.equal('wow'); + done(); + }, + ); + }, + ); }); it('should handle critical errors (Case3)', function(done) { var s = sinon.stub(); s.storeWallet = sinon.stub().yields({ code: 404, - message: 'wow' + message: 'wow', }); s.fetchWallet = sinon.stub().yields(null); var expressApp = new ExpressApp(); - expressApp.start({ - storage: s, - blockchainExplorer: blockchainExplorerMock, - disableLogs: true, - }, function() { - var s2 = sinon.stub(); - s2.load = sinon.stub().yields(null); - var client = helpers.newClient(app); - client.storage = s2; - client.createWallet('1', '2', 1, 1, { - network: 'testnet', - beacon: 'beacon', - }, - function(err) { - err.should.be.an.instanceOf(Errors.NOT_FOUND); - done(); - }); - }); + expressApp.start( + { + storage: s, + blockchainExplorer: blockchainExplorerMock, + disableLogs: true, + }, + function() { + var s2 = sinon.stub(); + s2.load = sinon.stub().yields(null); + var client = helpers.newClient(app); + client.storage = s2; + client.createWallet( + '1', + '2', + 1, + 1, + { + network: 'testnet', + beacon: 'beacon', + }, + function(err) { + err.should.be.an.instanceOf(Errors.NOT_FOUND); + done(); + }, + ); + }, + ); }); it('should handle critical errors (Case4)', function(done) { var body = { code: 999, - message: 'unexpected body' + message: 'unexpected body', }; var ret = Client._parseError(body); ret.should.be.an.instanceOf(Error); @@ -439,14 +496,21 @@ describe('client API', function() { it('should handle critical errors (Case5)', function(done) { clients[0].request = helpers.stubRequest('some error'); - clients[0].createWallet('mywallet', 'creator', 1, 2, { - network: 'testnet', - beacon: 'beacon', - }, function(err, secret) { - should.exist(err); - err.should.be.an.instanceOf(Errors.CONNECTION_ERROR); - done(); - }); + clients[0].createWallet( + 'mywallet', + 'creator', + 1, + 2, + { + network: 'testnet', + beacon: 'beacon', + }, + function(err, secret) { + should.exist(err); + err.should.be.an.instanceOf(Errors.CONNECTION_ERROR); + done(); + }, + ); }); it('should correctly use remote message', function(done) { var body = { @@ -476,11 +540,12 @@ describe('client API', function() { }); describe('Build & sign txs', function() { - var masterPrivateKey = 'tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k'; + var masterPrivateKey = + 'tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k'; var derivedPrivateKey = { - 'BIP44': new Meritcore.HDPrivateKey(masterPrivateKey).deriveChild("m/44'/1'/0'").toString(), - 'BIP45': new Meritcore.HDPrivateKey(masterPrivateKey).deriveChild("m/45'").toString(), - 'BIP48': new Meritcore.HDPrivateKey(masterPrivateKey).deriveChild("m/48'/1'/0'").toString(), + BIP44: new Meritcore.HDPrivateKey(masterPrivateKey).deriveChild("m/44'/1'/0'").toString(), + BIP45: new Meritcore.HDPrivateKey(masterPrivateKey).deriveChild("m/45'").toString(), + BIP48: new Meritcore.HDPrivateKey(masterPrivateKey).deriveChild("m/48'/1'/0'").toString(), }; describe('#buildTx', function() { @@ -488,9 +553,11 @@ describe('client API', function() { var toAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; var changeAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; - var publicKeyRing = [{ - xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), - }]; + var publicKeyRing = [ + { + xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), + }, + ]; var utxos = helpers.generateUtxos('P2PKH', publicKeyRing, 'm/1/0', 1, [1000, 2000]); var txp = { @@ -499,7 +566,7 @@ describe('client API', function() { toAddress: toAddress, amount: 1200, changeAddress: { - address: changeAddress + address: changeAddress, }, requiredSignatures: 1, outputOrder: [0, 1], @@ -521,9 +588,11 @@ describe('client API', function() { var toAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; var changeAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; - var publicKeyRing = [{ - xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), - }]; + var publicKeyRing = [ + { + xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), + }, + ]; var utxos = helpers.generateUtxos('P2PKH', publicKeyRing, 'm/1/0', 1, [1000, 2000]); var txp = { @@ -532,7 +601,7 @@ describe('client API', function() { toAddress: toAddress, amount: 1200, changeAddress: { - address: changeAddress + address: changeAddress, }, requiredSignatures: 1, outputOrder: [0, 1], @@ -554,9 +623,11 @@ describe('client API', function() { var toAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; var changeAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; - var publicKeyRing = [{ - xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP48']), - }]; + var publicKeyRing = [ + { + xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP48']), + }, + ]; var utxos = helpers.generateUtxos('P2PKH', publicKeyRing, 'm/1/0', 1, [1000, 2000]); var txp = { @@ -565,7 +636,7 @@ describe('client API', function() { toAddress: toAddress, amount: 1200, changeAddress: { - address: changeAddress + address: changeAddress, }, requiredSignatures: 1, outputOrder: [0, 1], @@ -587,9 +658,11 @@ describe('client API', function() { var toAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; var changeAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; - var publicKeyRing = [{ - xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), - }]; + var publicKeyRing = [ + { + xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), + }, + ]; var utxos = helpers.generateUtxos('P2PKH', publicKeyRing, 'm/1/0', 1, [1, 2]); var txp = { @@ -597,7 +670,7 @@ describe('client API', function() { toAddress: toAddress, amount: 1.5e8, changeAddress: { - address: changeAddress + address: changeAddress, }, requiredSignatures: 1, outputOrder: [0, 1], @@ -613,16 +686,18 @@ describe('client API', function() { from: sinon.stub(), to: sinon.stub(), change: sinon.stub(), - outputs: [{ - micros: 1000, - }], + outputs: [ + { + micros: 1000, + }, + ], fee: sinon.stub(), - } + }; }; (function() { var t = Utils.buildTx(txp); - }).should.throw('Illegal State'); + }.should.throw('Illegal State')); Utils.newMeritcoreTransaction = x; }); @@ -630,24 +705,29 @@ describe('client API', function() { var toAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; var changeAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; - var publicKeyRing = [{ - xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), - }]; + var publicKeyRing = [ + { + xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), + }, + ]; var utxos = helpers.generateUtxos('P2PKH', publicKeyRing, 'm/1/0', 1, [1000, 2000]); var txp = { inputs: utxos, - outputs: [{ - toAddress: toAddress, - amount: 800, - message: 'first output' - }, { - toAddress: toAddress, - amount: 900, - message: 'second output' - }], + outputs: [ + { + toAddress: toAddress, + amount: 800, + message: 'first output', + }, + { + toAddress: toAddress, + amount: 900, + message: 'second output', + }, + ], changeAddress: { - address: changeAddress + address: changeAddress, }, requiredSignatures: 1, outputOrder: [0, 1, 2], @@ -665,27 +745,34 @@ describe('client API', function() { var toAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; var changeAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; - var publicKeyRing = [{ - xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), - }]; + var publicKeyRing = [ + { + xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), + }, + ]; var utxos = helpers.generateUtxos('P2PKH', publicKeyRing, 'm/1/0', 1, [0.001]); var txp = { inputs: utxos, type: 'external', - outputs: [{ - "toAddress": "18433T2TSgajt9jWhcTBw4GoNREA6LpX3E", - "amount": 700, - "script": "512103ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff210314a96cd6f5a20826070173fe5b7e9797f21fc8ca4a55bcb2d2bde99f55dd352352ae" - }, { - "amount": 600, - "script": "76a9144d5bd54809f846dc6b1a14cbdd0ac87a3c66f76688ac" - }, { - "amount": 0, - "script": "6a1e43430102fa9213bc243af03857d0f9165e971153586d3915201201201210" - }], + outputs: [ + { + toAddress: '18433T2TSgajt9jWhcTBw4GoNREA6LpX3E', + amount: 700, + script: + '512103ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff210314a96cd6f5a20826070173fe5b7e9797f21fc8ca4a55bcb2d2bde99f55dd352352ae', + }, + { + amount: 600, + script: '76a9144d5bd54809f846dc6b1a14cbdd0ac87a3c66f76688ac', + }, + { + amount: 0, + script: '6a1e43430102fa9213bc243af03857d0f9165e971153586d3915201201201210', + }, + ], changeAddress: { - address: changeAddress + address: changeAddress, }, requiredSignatures: 1, outputOrder: [0, 1, 2, 3], @@ -712,25 +799,31 @@ describe('client API', function() { var toAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; var changeAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; - var publicKeyRing = [{ - xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), - }]; + var publicKeyRing = [ + { + xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), + }, + ]; var utxos = helpers.generateUtxos('P2PKH', publicKeyRing, 'm/1/0', 1, [0.001]); var txp = { inputs: utxos, type: 'external', - outputs: [{ - "amount": 700, - }, { - "amount": 600, - "script": "76a9144d5bd54809f846dc6b1a14cbdd0ac87a3c66f76688ac" - }, { - "amount": 0, - "script": "6a1e43430102fa9213bc243af03857d0f9165e971153586d3915201201201210" - }], + outputs: [ + { + amount: 700, + }, + { + amount: 600, + script: '76a9144d5bd54809f846dc6b1a14cbdd0ac87a3c66f76688ac', + }, + { + amount: 0, + script: '6a1e43430102fa9213bc243af03857d0f9165e971153586d3915201201201210', + }, + ], changeAddress: { - address: changeAddress + address: changeAddress, }, requiredSignatures: 1, outputOrder: [0, 1, 2, 3], @@ -740,9 +833,9 @@ describe('client API', function() { }; (function() { var t = Utils.buildTx(txp); - }).should.throw('Output should have either toAddress or script specified'); + }.should.throw('Output should have either toAddress or script specified')); - txp.outputs[0].toAddress = "18433T2TSgajt9jWhcTBw4GoNREA6LpX3E"; + txp.outputs[0].toAddress = '18433T2TSgajt9jWhcTBw4GoNREA6LpX3E'; var t = Utils.buildTx(txp); var bitcoreError = t.getSerializationError({ disableIsFullySigned: true, @@ -750,7 +843,8 @@ describe('client API', function() { should.not.exist(bitcoreError); delete txp.outputs[0].toAddress; - txp.outputs[0].script = "512103ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff210314a96cd6f5a20826070173fe5b7e9797f21fc8ca4a55bcb2d2bde99f55dd352352ae"; + txp.outputs[0].script = + '512103ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff210314a96cd6f5a20826070173fe5b7e9797f21fc8ca4a55bcb2d2bde99f55dd352352ae'; t = Utils.buildTx(txp); var bitcoreError = t.getSerializationError({ disableIsFullySigned: true, @@ -761,25 +855,30 @@ describe('client API', function() { var toAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; var changeAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; - var publicKeyRing = [{ - xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), - }]; + var publicKeyRing = [ + { + xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), + }, + ]; var utxos = helpers.generateUtxos('P2PKH', publicKeyRing, 'm/1/0', 1, [1000, 2000]); var txp = { version: 3, inputs: utxos, - outputs: [{ - toAddress: toAddress, - amount: 800, - message: 'first output' - }, { - toAddress: toAddress, - amount: 900, - message: 'second output' - }], + outputs: [ + { + toAddress: toAddress, + amount: 800, + message: 'first output', + }, + { + toAddress: toAddress, + amount: 900, + message: 'second output', + }, + ], changeAddress: { - address: changeAddress + address: changeAddress, }, requiredSignatures: 1, outputOrder: [0, 1, 2], @@ -800,9 +899,11 @@ describe('client API', function() { var toAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; var changeAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; - var publicKeyRing = [{ - xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP45']), - }]; + var publicKeyRing = [ + { + xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP45']), + }, + ]; var utxos = helpers.generateUtxos('P2SH', publicKeyRing, 'm/2147483647/0/0', 1, [1000, 2000]); var txp = { @@ -810,7 +911,7 @@ describe('client API', function() { toAddress: toAddress, amount: 1200, changeAddress: { - address: changeAddress + address: changeAddress, }, requiredSignatures: 1, outputOrder: [0, 1], @@ -825,9 +926,11 @@ describe('client API', function() { var toAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; var changeAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; - var publicKeyRing = [{ - xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), - }]; + var publicKeyRing = [ + { + xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), + }, + ]; var utxos = helpers.generateUtxos('P2PKH', publicKeyRing, 'm/1/0', 1, [1000, 2000]); var txp = { @@ -835,7 +938,7 @@ describe('client API', function() { toAddress: toAddress, amount: 1200, changeAddress: { - address: changeAddress + address: changeAddress, }, requiredSignatures: 1, outputOrder: [0, 1], @@ -850,24 +953,29 @@ describe('client API', function() { var toAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; var changeAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; - var publicKeyRing = [{ - xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), - }]; + var publicKeyRing = [ + { + xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), + }, + ]; var utxos = helpers.generateUtxos('P2PKH', publicKeyRing, 'm/1/0', 1, [1000, 2000]); var txp = { inputs: utxos, - outputs: [{ - toAddress: toAddress, - amount: 800, - message: 'first output' - }, { - toAddress: toAddress, - amount: 900, - message: 'second output' - }], + outputs: [ + { + toAddress: toAddress, + amount: 800, + message: 'first output', + }, + { + toAddress: toAddress, + amount: 900, + message: 'second output', + }, + ], changeAddress: { - address: changeAddress + address: changeAddress, }, requiredSignatures: 1, outputOrder: [0, 1, 2], @@ -882,26 +990,33 @@ describe('client API', function() { var toAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; var changeAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; - var publicKeyRing = [{ - xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), - }]; + var publicKeyRing = [ + { + xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), + }, + ]; var utxos = helpers.generateUtxos('P2PKH', publicKeyRing, 'm/1/0', 1, [0.001]); var txp = { inputs: utxos, type: 'external', - outputs: [{ - "amount": 700, - "script": "512103ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff210314a96cd6f5a20826070173fe5b7e9797f21fc8ca4a55bcb2d2bde99f55dd352352ae" - }, { - "amount": 600, - "script": "76a9144d5bd54809f846dc6b1a14cbdd0ac87a3c66f76688ac" - }, { - "amount": 0, - "script": "6a1e43430102fa9213bc243af03857d0f9165e971153586d3915201201201210" - }], + outputs: [ + { + amount: 700, + script: + '512103ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff210314a96cd6f5a20826070173fe5b7e9797f21fc8ca4a55bcb2d2bde99f55dd352352ae', + }, + { + amount: 600, + script: '76a9144d5bd54809f846dc6b1a14cbdd0ac87a3c66f76688ac', + }, + { + amount: 0, + script: '6a1e43430102fa9213bc243af03857d0f9165e971153586d3915201201201210', + }, + ], changeAddress: { - address: changeAddress + address: changeAddress, }, requiredSignatures: 1, outputOrder: [0, 1, 2, 3], @@ -916,25 +1031,30 @@ describe('client API', function() { var toAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; var changeAddress = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; - var publicKeyRing = [{ - xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), - }]; + var publicKeyRing = [ + { + xPubKey: new Meritcore.HDPublicKey(derivedPrivateKey['BIP44']), + }, + ]; var utxos = helpers.generateUtxos('P2PKH', publicKeyRing, 'm/1/0', 1, [1000, 2000]); var txp = { version: 3, inputs: utxos, - outputs: [{ - toAddress: toAddress, - amount: 800, - message: 'first output' - }, { - toAddress: toAddress, - amount: 900, - message: 'second output' - }], + outputs: [ + { + toAddress: toAddress, + amount: 800, + message: 'first output', + }, + { + toAddress: toAddress, + amount: 900, + message: 'second output', + }, + ], changeAddress: { - address: changeAddress + address: changeAddress, }, requiredSignatures: 1, outputOrder: [0, 1, 2], @@ -960,12 +1080,12 @@ describe('client API', function() { result.walletId.should.equal(walletId); result.walletPrivKey.toString().should.equal(walletPrivKey.toString()); result.network.should.equal(network); - }; + } }); it('should fail on invalid secret', function() { (function() { Client.parseSecret('invalidSecret'); - }).should.throw('Invalid secret'); + }.should.throw('Invalid secret')); }); it('should create secret and parse secret from string ', function() { @@ -1050,7 +1170,7 @@ describe('client API', function() { should.not.exist(err); status.wallet.name.should.equal('mywallet'); done(); - }) + }); }); }); it('should encrypt copayer name in wallet creation', function(done) { @@ -1066,7 +1186,7 @@ describe('client API', function() { should.not.exist(err); status.wallet.copayers[0].name.should.equal('pepe'); done(); - }) + }); }); }); it('should be able to access wallet name in non-encrypted wallet (legacy)', function(done) { @@ -1090,9 +1210,12 @@ describe('client API', function() { name: 'pepe', xPubKey: c.xPubKey, requestPubKey: c.requestPubKey, - customData: Utils.encryptMessage(JSON.stringify({ - walletPrivKey: wpk.toString(), - }), c.personalEncryptingKey), + customData: Utils.encryptMessage( + JSON.stringify({ + walletPrivKey: wpk.toString(), + }), + c.personalEncryptingKey, + ), }; var hash = Utils.getCopayerHash(args.name, args.xPubKey, args.requestPubKey); args.copayerSignature = Utils.signMessage(hash, wpk); @@ -1121,7 +1244,7 @@ describe('client API', function() { balance.availableAmount.should.equal(0); balance.lockedAmount.should.equal(0); done(); - }) + }); }); }); it('should be able to complete wallet in copayer that joined later', function(done) { @@ -1133,9 +1256,9 @@ describe('client API', function() { clients[2].getBalance({}, function(err, x) { should.not.exist(err); done(); - }) - }) - }) + }); + }); + }); }); }); it('should fire event when wallet is complete', function(done) { @@ -1147,24 +1270,31 @@ describe('client API', function() { clients[0].credentials.isComplete().should.equal(true); if (++checks == 2) done(); }); - clients[0].createWallet('mywallet', 'creator', 2, 2, { - network: 'testnet', - beacon: 'code' - }, function(err, secret) { - should.not.exist(err); - clients[0].isComplete().should.equal(false); - clients[0].credentials.isComplete().should.equal(false); - clients[1].joinWallet(secret, 'guest', {}, function(err, wallet) { + clients[0].createWallet( + 'mywallet', + 'creator', + 2, + 2, + { + network: 'testnet', + beacon: 'code', + }, + function(err, secret) { should.not.exist(err); - wallet.name.should.equal('mywallet'); - clients[0].openWallet(function(err, walletStatus) { + clients[0].isComplete().should.equal(false); + clients[0].credentials.isComplete().should.equal(false); + clients[1].joinWallet(secret, 'guest', {}, function(err, wallet) { should.not.exist(err); - should.exist(walletStatus); - _.difference(_.map(walletStatus.copayers, 'name'), ['creator', 'guest']).length.should.equal(0); - if (++checks == 2) done(); + wallet.name.should.equal('mywallet'); + clients[0].openWallet(function(err, walletStatus) { + should.not.exist(err); + should.exist(walletStatus); + _.difference(_.map(walletStatus.copayers, 'name'), ['creator', 'guest']).length.should.equal(0); + if (++checks == 2) done(); + }); }); - }); - }); + }, + ); }); it('should fill wallet info in an incomplete wallet', function(done) { @@ -1183,33 +1313,47 @@ describe('client API', function() { }); it('should return wallet on successful join', function(done) { - clients[0].createWallet('mywallet', 'creator', 2, 2, { - network: 'testnet', - beacon: 'code' - }, function(err, secret) { - should.not.exist(err); - clients[1].joinWallet(secret, 'guest', {}, function(err, wallet) { + clients[0].createWallet( + 'mywallet', + 'creator', + 2, + 2, + { + network: 'testnet', + beacon: 'code', + }, + function(err, secret) { should.not.exist(err); - wallet.name.should.equal('mywallet'); - wallet.copayers[0].name.should.equal('creator'); - wallet.copayers[1].name.should.equal('guest'); - done(); - }); - }); + clients[1].joinWallet(secret, 'guest', {}, function(err, wallet) { + should.not.exist(err); + wallet.name.should.equal('mywallet'); + wallet.copayers[0].name.should.equal('creator'); + wallet.copayers[1].name.should.equal('guest'); + done(); + }); + }, + ); }); it('should not allow to join wallet on bogus device', function(done) { - clients[0].createWallet('mywallet', 'creator', 2, 2, { - network: 'testnet', - beacon: 'code' - }, function(err, secret) { - should.not.exist(err); - clients[1].keyDerivationOk = false; - clients[1].joinWallet(secret, 'guest', {}, function(err, wallet) { - should.exist(err); - done(); - }); - }); + clients[0].createWallet( + 'mywallet', + 'creator', + 2, + 2, + { + network: 'testnet', + beacon: 'code', + }, + function(err, secret) { + should.not.exist(err); + clients[1].keyDerivationOk = false; + clients[1].joinWallet(secret, 'guest', {}, function(err, wallet) { + should.exist(err); + done(); + }); + }, + ); }); it('should not allow to join a full wallet ', function(done) { @@ -1226,10 +1370,15 @@ describe('client API', function() { clients[0].joinWallet('dummy', 'copayer', {}, function(err, result) { err.message.should.contain('Invalid secret'); // Right length, invalid char for base 58 - clients[0].joinWallet('DsZbqNQQ9LrTKU8EknR7gFKyCQMPg2UUHNPZ1BzM5EbJwjRZaUNBfNtdWLluuFc0f7f7sTCkh7T', 'copayer', {}, function(err, result) { - err.message.should.contain('Invalid secret'); - done(); - }); + clients[0].joinWallet( + 'DsZbqNQQ9LrTKU8EknR7gFKyCQMPg2UUHNPZ1BzM5EbJwjRZaUNBfNtdWLluuFc0f7f7sTCkh7T', + 'copayer', + {}, + function(err, result) { + err.message.should.contain('Invalid secret'); + done(); + }, + ); }); }); it('should fail with an unknown secret', function(done) { @@ -1246,15 +1395,22 @@ describe('client API', function() { var openWalletStub = sinon.stub(clients[1], 'openWallet').yields(); helpers.createAndJoinWallet(clients, 2, 3, function() { - helpers.tamperResponse([clients[0], clients[1]], 'get', '/v1/wallets/', {}, function(status) { - status.wallet.copayers[0].xPubKey = status.wallet.copayers[1].xPubKey; - }, function() { - openWalletStub.restore(); - clients[1].openWallet(function(err, x) { - err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); - done(); - }); - }); + helpers.tamperResponse( + [clients[0], clients[1]], + 'get', + '/v1/wallets/', + {}, + function(status) { + status.wallet.copayers[0].xPubKey = status.wallet.copayers[1].xPubKey; + }, + function() { + openWalletStub.restore(); + clients[1].openWallet(function(err, x) { + err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); + done(); + }); + }, + ); }); }); @@ -1263,15 +1419,22 @@ describe('client API', function() { var openWalletStub = sinon.stub(clients[1], 'openWallet').yields(); helpers.createAndJoinWallet(clients, 2, 3, function() { - helpers.tamperResponse([clients[0], clients[1]], 'get', '/v1/wallets/', {}, function(status) { - delete status.wallet.copayers[1].xPubKey; - }, function() { - openWalletStub.restore(); - clients[1].openWallet(function(err, x) { - err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); - done(); - }); - }); + helpers.tamperResponse( + [clients[0], clients[1]], + 'get', + '/v1/wallets/', + {}, + function(status) { + delete status.wallet.copayers[1].xPubKey; + }, + function() { + openWalletStub.restore(); + clients[1].openWallet(function(err, x) { + err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); + done(); + }); + }, + ); }); }); @@ -1280,141 +1443,202 @@ describe('client API', function() { var openWalletStub = sinon.stub(clients[1], 'openWallet').yields(); helpers.createAndJoinWallet(clients, 2, 3, function() { - helpers.tamperResponse([clients[0], clients[1]], 'get', '/v1/wallets/', {}, function(status) { - // Replace caller's pubkey - status.wallet.copayers[1].xPubKey = (new Meritcore.HDPrivateKey()).publicKey; - // Add a correct signature - status.wallet.copayers[1].xPubKeySignature = Utils.signMessage( - status.wallet.copayers[1].xPubKey.toString(), - clients[0].credentials.walletPrivKey - ); - }, function() { - openWalletStub.restore(); - clients[1].openWallet(function(err, x) { - err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); - done(); - }); - }); + helpers.tamperResponse( + [clients[0], clients[1]], + 'get', + '/v1/wallets/', + {}, + function(status) { + // Replace caller's pubkey + status.wallet.copayers[1].xPubKey = new Meritcore.HDPrivateKey().publicKey; + // Add a correct signature + status.wallet.copayers[1].xPubKeySignature = Utils.signMessage( + status.wallet.copayers[1].xPubKey.toString(), + clients[0].credentials.walletPrivKey, + ); + }, + function() { + openWalletStub.restore(); + clients[1].openWallet(function(err, x) { + err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); + done(); + }); + }, + ); }); }); it('should perform a dry join without actually joining', function(done) { clients[0].createWallet('mywallet', 'creator', 1, 2, { beacon: 'code' }, function(err, secret) { should.not.exist(err); should.exist(secret); - clients[1].joinWallet(secret, 'dummy', { - dryRun: true - }, function(err, wallet) { - should.not.exist(err); - should.exist(wallet); - wallet.status.should.equal('pending'); - wallet.copayers.length.should.equal(1); - done(); - }); + clients[1].joinWallet( + secret, + 'dummy', + { + dryRun: true, + }, + function(err, wallet) { + should.not.exist(err); + should.exist(wallet); + wallet.status.should.equal('pending'); + wallet.copayers.length.should.equal(1); + done(); + }, + ); }); }); it('should return wallet status even if wallet is not yet complete', function(done) { - clients[0].createWallet('mywallet', 'creator', 1, 2, { - network: 'testnet', - beacon: 'code' - }, function(err, secret) { - should.not.exist(err); - should.exist(secret); - - clients[0].getStatus({}, function(err, status) { + clients[0].createWallet( + 'mywallet', + 'creator', + 1, + 2, + { + network: 'testnet', + beacon: 'code', + }, + function(err, secret) { should.not.exist(err); - should.exist(status); - status.wallet.status.should.equal('pending'); - should.exist(status.wallet.secret); - status.wallet.secret.should.equal(secret); - done(); - }); - }); - }); - it('should return status using v2 version', function(done) { - clients[0].createWallet('mywallet', 'creator', 1, 1, { - network: 'testnet', - beacon: 'code' - }, function(err, secret) { - should.not.exist(err); - clients[0].getStatus({}, function(err, status) { + should.exist(secret); + + clients[0].getStatus({}, function(err, status) { + should.not.exist(err); + should.exist(status); + status.wallet.status.should.equal('pending'); + should.exist(status.wallet.secret); + status.wallet.secret.should.equal(secret); + done(); + }); + }, + ); + }); + it('should return status using v2 version', function(done) { + clients[0].createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'testnet', + beacon: 'code', + }, + function(err, secret) { should.not.exist(err); - should.not.exist(status.wallet.publicKeyRing); - status.wallet.status.should.equal('complete'); - done(); - }); - }); + clients[0].getStatus({}, function(err, status) { + should.not.exist(err); + should.not.exist(status.wallet.publicKeyRing); + status.wallet.status.should.equal('complete'); + done(); + }); + }, + ); }); it('should return extended status using v2 version', function(done) { - clients[0].createWallet('mywallet', 'creator', 1, 1, { - network: 'testnet', - beacon: 'code' - }, function(err, secret) { - should.not.exist(err); - clients[0].getStatus({ - includeExtendedInfo: true - }, function(err, status) { + clients[0].createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'testnet', + beacon: 'code', + }, + function(err, secret) { should.not.exist(err); - status.wallet.publicKeyRing.length.should.equal(1); - status.wallet.status.should.equal('complete'); - done(); - }); - }); + clients[0].getStatus( + { + includeExtendedInfo: true, + }, + function(err, status) { + should.not.exist(err); + status.wallet.publicKeyRing.length.should.equal(1); + status.wallet.status.should.equal('complete'); + done(); + }, + ); + }, + ); }); it('should store walletPrivKey', function(done) { - clients[0].createWallet('mywallet', 'creator', 1, 1, { - network: 'testnet', - beacon: 'code' - }, function(err) { - - var key = clients[0].credentials.walletPrivKey; - should.not.exist(err); - clients[0].getStatus({ - includeExtendedInfo: true - }, function(err, status) { + clients[0].createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'testnet', + beacon: 'code', + }, + function(err) { + var key = clients[0].credentials.walletPrivKey; should.not.exist(err); - status.wallet.publicKeyRing.length.should.equal(1); - status.wallet.status.should.equal('complete'); - var key2 = status.customData.walletPrivKey; - key2.should.be.equal(key2); - done(); - }); - }); + clients[0].getStatus( + { + includeExtendedInfo: true, + }, + function(err, status) { + should.not.exist(err); + status.wallet.publicKeyRing.length.should.equal(1); + status.wallet.status.should.equal('complete'); + var key2 = status.customData.walletPrivKey; + key2.should.be.equal(key2); + done(); + }, + ); + }, + ); }); it('should set walletPrivKey from MWS', function(done) { - clients[0].createWallet('mywallet', 'creator', 1, 1, { - network: 'testnet', - beacon: 'code' - }, function(err) { - - var wkey = clients[0].credentials.walletPrivKey; - var skey = clients[0].credentials.sharedEncryptingKey; - delete clients[0].credentials.walletPrivKey; - delete clients[0].credentials.sharedEncryptingKey; - should.not.exist(err); - clients[0].getStatus({ - includeExtendedInfo: true - }, function(err, status) { + clients[0].createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'testnet', + beacon: 'code', + }, + function(err) { + var wkey = clients[0].credentials.walletPrivKey; + var skey = clients[0].credentials.sharedEncryptingKey; + delete clients[0].credentials.walletPrivKey; + delete clients[0].credentials.sharedEncryptingKey; should.not.exist(err); - clients[0].credentials.walletPrivKey.should.equal(wkey); - clients[0].credentials.sharedEncryptingKey.should.equal(skey); - done(); - }); - }); + clients[0].getStatus( + { + includeExtendedInfo: true, + }, + function(err, status) { + should.not.exist(err); + clients[0].credentials.walletPrivKey.should.equal(wkey); + clients[0].credentials.sharedEncryptingKey.should.equal(skey); + done(); + }, + ); + }, + ); }); it('should prepare wallet with external xpubkey', function(done) { var client = helpers.newClient(app); - client.seedFromExtendedPublicKey('xpub661MyMwAqRbcGVyYUcHbZi9KNhN9Tdj8qHi9ZdoUXP1VeKiXDGGrE9tSoJKYhGFE2rimteYdwvoP6e87zS5LsgcEvsvdrpPBEmeWz9EeAUq', 'ledger', '1a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f00', { - account: 1, - derivationStrategy: 'BIP48', - }); + client.seedFromExtendedPublicKey( + 'xpub661MyMwAqRbcGVyYUcHbZi9KNhN9Tdj8qHi9ZdoUXP1VeKiXDGGrE9tSoJKYhGFE2rimteYdwvoP6e87zS5LsgcEvsvdrpPBEmeWz9EeAUq', + 'ledger', + '1a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f00', + { + account: 1, + derivationStrategy: 'BIP48', + }, + ); client.isPrivKeyExternal().should.equal(true); client.credentials.account.should.equal(1); client.credentials.derivationStrategy.should.equal('BIP48'); - client.credentials.requestPrivKey.should.equal('36a4504f0c6651db30484c2c128304a7ea548ef5935f19ed6af99db8000c75a4'); + client.credentials.requestPrivKey.should.equal( + '36a4504f0c6651db30484c2c128304a7ea548ef5935f19ed6af99db8000c75a4', + ); client.credentials.personalEncryptingKey.should.equal('wYI1597BfOv06NI6Uye3tA=='); client.getPrivKeyExternalSourceName().should.equal('ledger'); done(); @@ -1422,9 +1646,14 @@ describe('client API', function() { it('should create a 1-1 wallet with random mnemonic', function(done) { clients[0].seedFromRandomWithMnemonic(); - clients[0].createWallet('mywallet', 'creator', 1, 1, { + clients[0].createWallet( + 'mywallet', + 'creator', + 1, + 1, + { network: 'livenet', - beacon: 'code' + beacon: 'code', }, function(err) { should.not.exist(err); @@ -1432,19 +1661,28 @@ describe('client API', function() { should.not.exist(err); should.not.exist(err); clients[0].credentials.network.should.equal('livenet'); - clients[0].getMnemonic().split(' ').length.should.equal(12); + clients[0] + .getMnemonic() + .split(' ') + .length.should.equal(12); done(); }); - }); + }, + ); }); it('should create a 1-1 wallet with given mnemonic', function(done) { var words = 'forget announce travel fury farm alpha chaos choice talent sting eagle supreme'; clients[0].seedFromMnemonic(words); - clients[0].createWallet('mywallet', 'creator', 1, 1, { + clients[0].createWallet( + 'mywallet', + 'creator', + 1, + 1, + { network: 'livenet', derivationStrategy: 'BIP48', - beacon: 'code' + beacon: 'code', }, function(err) { should.not.exist(err); @@ -1452,18 +1690,26 @@ describe('client API', function() { should.not.exist(err); should.exist(clients[0].getMnemonic()); words.should.be.equal(clients[0].getMnemonic()); - clients[0].credentials.xPrivKey.should.equal('xprv9s21ZrQH143K4X2frJxRmGsmef9UfXhmfL4hdTGLm5ruSX46gekuSTspJX63d5nEi9q2wqUgg4KZ4yhSPy13CzVezAH6t6gCox1DN2hXV3L') + clients[0].credentials.xPrivKey.should.equal( + 'xprv9s21ZrQH143K4X2frJxRmGsmef9UfXhmfL4hdTGLm5ruSX46gekuSTspJX63d5nEi9q2wqUgg4KZ4yhSPy13CzVezAH6t6gCox1DN2hXV3L', + ); done(); }); - }); + }, + ); }); it('should create a 2-3 wallet with given mnemonic', function(done) { var words = 'forget announce travel fury farm alpha chaos choice talent sting eagle supreme'; clients[0].seedFromMnemonic(words); - clients[0].createWallet('mywallet', 'creator', 2, 3, { + clients[0].createWallet( + 'mywallet', + 'creator', + 2, + 3, + { network: 'livenet', - beacon: 'code' + beacon: 'code', }, function(err, secret) { should.not.exist(err); @@ -1472,10 +1718,13 @@ describe('client API', function() { should.not.exist(err); should.exist(clients[0].getMnemonic()); words.should.be.equal(clients[0].getMnemonic()); - clients[0].credentials.xPrivKey.should.equal('xprv9s21ZrQH143K4X2frJxRmGsmef9UfXhmfL4hdTGLm5ruSX46gekuSTspJX63d5nEi9q2wqUgg4KZ4yhSPy13CzVezAH6t6gCox1DN2hXV3L') + clients[0].credentials.xPrivKey.should.equal( + 'xprv9s21ZrQH143K4X2frJxRmGsmef9UfXhmfL4hdTGLm5ruSX46gekuSTspJX63d5nEi9q2wqUgg4KZ4yhSPy13CzVezAH6t6gCox1DN2hXV3L', + ); done(); }); - }); + }, + ); }); }); @@ -1493,14 +1742,17 @@ describe('client API', function() { }); }); it('Should return all main addresses', function(done) { - clients[0].getMainAddresses({ - doNotVerify: true - }, function(err, addr) { - should.not.exist(err); - // addr.length.should.equal(2); - addr.length.should.equal(1); // for singleAddress = true - done(); - }); + clients[0].getMainAddresses( + { + doNotVerify: true, + }, + function(err, addr) { + should.not.exist(err); + // addr.length.should.equal(2); + addr.length.should.equal(1); // for singleAddress = true + done(); + }, + ); }); it('Should return only main addresses when change addresses exist', function(done) { var opts = { @@ -1543,25 +1795,29 @@ describe('client API', function() { }); }); it('Should return UTXOs for specific addresses', function(done) { - async.map(_.range(3), function(i, next) { - clients[0].createAddress(function(err, x) { - should.not.exist(err); - should.exist(x.address); - blockchainExplorerMock.setUtxo(x, 1, 1); - next(null, x.address); - }); - }, function(err, addresses) { - var opts = { - addresses: _.take(addresses, 2), - }; - clients[0].getUtxos(opts, function(err, utxos) { - should.not.exist(err); - // utxos.length.should.equal(2); - utxos.length.should.equal(3); // for singleAddress = true - _.sumBy(utxos, 'micros').should.equal(3 * 1e8); // for singleAddress = true - done(); - }); - }); + async.map( + _.range(3), + function(i, next) { + clients[0].createAddress(function(err, x) { + should.not.exist(err); + should.exist(x.address); + blockchainExplorerMock.setUtxo(x, 1, 1); + next(null, x.address); + }); + }, + function(err, addresses) { + var opts = { + addresses: _.take(addresses, 2), + }; + clients[0].getUtxos(opts, function(err, utxos) { + should.not.exist(err); + // utxos.length.should.equal(2); + utxos.length.should.equal(3); // for singleAddress = true + _.sumBy(utxos, 'micros').should.equal(3 * 1e8); // for singleAddress = true + done(); + }); + }, + ); }); }); @@ -1606,17 +1862,20 @@ describe('client API', function() { clients[0].getPreferences(function(err, preferences) { should.not.exist(err); preferences.should.be.empty; - clients[0].savePreferences({ - email: 'dummy@dummy.com' - }, function(err) { - should.not.exist(err); - clients[0].getPreferences(function(err, preferences) { + clients[0].savePreferences( + { + email: 'dummy@dummy.com', + }, + function(err) { should.not.exist(err); - should.exist(preferences); - preferences.email.should.equal('dummy@dummy.com'); - done(); - }); - }); + clients[0].getPreferences(function(err, preferences) { + should.not.exist(err); + should.exist(preferences); + preferences.email.should.equal('dummy@dummy.com'); + done(); + }); + }, + ); }); }); }); @@ -1626,16 +1885,19 @@ describe('client API', function() { it('should get fiat exchange rate', function(done) { var now = Date.now(); helpers.createAndJoinWallet(clients, 1, 1, function() { - clients[0].getFiatRate({ - code: 'USD', - ts: now, - }, function(err, res) { - should.not.exist(err); - should.exist(res); - res.ts.should.equal(now); - should.not.exist(res.rate); - done(); - }); + clients[0].getFiatRate( + { + code: 'USD', + ts: now, + }, + function(err, res) { + should.not.exist(err); + should.exist(res); + res.ts.should.equal(now); + should.not.exist(res.rate); + done(); + }, + ); }); }); }); @@ -1672,14 +1934,17 @@ describe('client API', function() { clients[0]._doRequest = sinon.stub().yields(null, { statusCode: 200, }); - clients[0].txConfirmationSubscribe({ - txid: '123' - }, function(err, res) { - should.not.exist(err); - should.exist(res); - res.statusCode.should.be.equal(200); - done(); - }); + clients[0].txConfirmationSubscribe( + { + txid: '123', + }, + function(err, res) { + should.not.exist(err); + should.exist(res); + res.statusCode.should.be.equal(200); + done(); + }, + ); }); }); @@ -1718,7 +1983,7 @@ describe('client API', function() { var opts = { feeLevel: 'priority', excludeUnconfirmedUtxos: false, - returnInputs: true + returnInputs: true, }; clients[0].getSendMaxInfo(opts, function(err, result) { should.not.exist(err); @@ -1736,7 +2001,7 @@ describe('client API', function() { var opts = { feePerKb: 200, excludeUnconfirmedUtxos: true, - returnInputs: true + returnInputs: true, }; clients[0].getSendMaxInfo(opts, function(err, result) { should.not.exist(err); @@ -1748,7 +2013,7 @@ describe('client API', function() { var opts = { feePerKb: 200, excludeUnconfirmedUtxos: false, - returnInputs: true + returnInputs: true, }; clients[0].getSendMaxInfo(opts, function(err, result) { should.not.exist(err); @@ -1760,7 +2025,7 @@ describe('client API', function() { var opts = { feePerKb: 200, excludeUnconfirmedUtxos: true, - returnInputs: false + returnInputs: false, }; clients[0].getSendMaxInfo(opts, function(err, result) { should.not.exist(err); @@ -1772,7 +2037,7 @@ describe('client API', function() { var opts = { feePerKb: 200, excludeUnconfirmedUtxos: true, - returnInputs: true + returnInputs: true, }; clients[0].getSendMaxInfo(opts, function(err, result) { should.not.exist(err); @@ -1851,29 +2116,43 @@ describe('client API', function() { }); it('should detect fake addresses', function(done) { helpers.createAndJoinWallet(clients, 1, 1, function() { - helpers.tamperResponse(clients[0], 'post', '/v3/addresses/', {}, function(address) { - address.address = '2N86pNEpREGpwZyHVC5vrNUCbF9nM1Geh4K'; - }, function() { - clients[0].createAddress(function(err, x0) { - err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); - done(); - }); - }); + helpers.tamperResponse( + clients[0], + 'post', + '/v3/addresses/', + {}, + function(address) { + address.address = '2N86pNEpREGpwZyHVC5vrNUCbF9nM1Geh4K'; + }, + function() { + clients[0].createAddress(function(err, x0) { + err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); + done(); + }); + }, + ); }); }); it('should detect fake public keys', function(done) { helpers.createAndJoinWallet(clients, 1, 1, function() { - helpers.tamperResponse(clients[0], 'post', '/v3/addresses/', {}, function(address) { - address.publicKeys = [ - '0322defe0c3eb9fcd8bc01878e6dbca7a6846880908d214b50a752445040cc5c54', - '02bf3aadc17131ca8144829fa1883c1ac0a8839067af4bca47a90ccae63d0d8037' - ]; - }, function() { - clients[0].createAddress(function(err, x0) { - err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); - done(); - }); - }); + helpers.tamperResponse( + clients[0], + 'post', + '/v3/addresses/', + {}, + function(address) { + address.publicKeys = [ + '0322defe0c3eb9fcd8bc01878e6dbca7a6846880908d214b50a752445040cc5c54', + '02bf3aadc17131ca8144829fa1883c1ac0a8839067af4bca47a90ccae63d0d8037', + ]; + }, + function() { + clients[0].createAddress(function(err, x0) { + err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); + done(); + }); + }, + ); }); }); it('should be able to derive 25 addresses', function(done) { @@ -1881,13 +2160,16 @@ describe('client API', function() { var num = 25; helpers.createAndJoinWallet(clients, 1, 1, function() { function create(callback) { - clients[0].createAddress({ - ignoreMaxGap: true - }, function(err, x) { - should.not.exist(err); - should.exist(x.address); - callback(err, x); - }); + clients[0].createAddress( + { + ignoreMaxGap: true, + }, + function(err, x) { + should.not.exist(err); + should.exist(x.address); + callback(err, x); + }, + ); } var tasks = []; @@ -1931,13 +2213,16 @@ describe('client API', function() { notifications.length.should.equal(2); // for singleAddress = true // _.map(notifications, 'type').should.deep.equal(['NewCopayer', 'WalletComplete', 'NewAddress']); _.map(notifications, 'type').should.deep.equal(['NewCopayer', 'WalletComplete']); // for singleAddress = true - clients[0].getNotifications({ - lastNotificationId: _.last(notifications).id - }, function(err, notifications) { - should.not.exist(err); - notifications.length.should.equal(0, 'should only return unread notifications'); - done(); - }); + clients[0].getNotifications( + { + lastNotificationId: _.last(notifications).id, + }, + function(err, notifications) { + should.not.exist(err); + notifications.length.should.equal(0, 'should only return unread notifications'); + done(); + }, + ); }); }); it('should not receive old notifications', function(done) { @@ -1955,16 +2240,24 @@ describe('client API', function() { notifications.length.should.equal(2); // for singleAddress = true // _.map(notifications, 'type').should.deep.equal(['NewCopayer', 'WalletComplete', 'NewAddress']); _.map(notifications, 'type').should.deep.equal(['NewCopayer', 'WalletComplete']); // for singleAddress = true - clients[0].getNotifications({ - includeOwn: true, - }, function(err, notifications) { - should.not.exist(err); - // notifications.length.should.equal(5); - notifications.length.should.equal(4); - // _.map(notifications, 'type').should.deep.equal(['NewCopayer', 'NewCopayer', 'WalletComplete', 'NewAddress', 'NewAddress']); - _.map(notifications, 'type').should.deep.equal(['NewCopayer', 'NewCopayer', 'WalletComplete', 'NewAddress']); - done(); - }); + clients[0].getNotifications( + { + includeOwn: true, + }, + function(err, notifications) { + should.not.exist(err); + // notifications.length.should.equal(5); + notifications.length.should.equal(4); + // _.map(notifications, 'type').should.deep.equal(['NewCopayer', 'NewCopayer', 'WalletComplete', 'NewAddress', 'NewAddress']); + _.map(notifications, 'type').should.deep.equal([ + 'NewCopayer', + 'NewCopayer', + 'WalletComplete', + 'NewAddress', + ]); + done(); + }, + ); }); }); }); @@ -1990,21 +2283,24 @@ describe('client API', function() { }); var toAddress = 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5'; var opts = { - outputs: [{ - amount: 1e8, - toAddress: toAddress, - message: 'world', - }, { - amount: 2e8, - toAddress: toAddress, - }], + outputs: [ + { + amount: 1e8, + toAddress: toAddress, + message: 'world', + }, + { + amount: 2e8, + toAddress: toAddress, + }, + ], message: 'hello', customData: { someObj: { - x: 1 + x: 1, }, - someStr: "str" - } + someStr: 'str', + }, }; clients[0].createTxProposal(opts, function(err, txp) { should.not.exist(err); @@ -2028,29 +2324,32 @@ describe('client API', function() { should.not.exist(err); txps.should.be.empty; - clients[0].publishTxProposal({ - txp: txp, - }, function(err, publishedTxp) { - should.not.exist(err); - should.exist(publishedTxp); - publishedTxp.status.should.equal('pending'); - clients[0].getTxProposals({}, function(err, txps) { + clients[0].publishTxProposal( + { + txp: txp, + }, + function(err, publishedTxp) { should.not.exist(err); - txps.length.should.equal(1); - var x = txps[0]; - x.id.should.equal(txp.id); - should.exist(x.proposalSignature); - should.not.exist(x.proposalSignaturePubKey); - should.not.exist(x.proposalSignaturePubKeySig); - // Should be visible for other copayers as well - clients[1].getTxProposals({}, function(err, txps) { + should.exist(publishedTxp); + publishedTxp.status.should.equal('pending'); + clients[0].getTxProposals({}, function(err, txps) { should.not.exist(err); txps.length.should.equal(1); - txps[0].id.should.equal(txp.id); - done(); + var x = txps[0]; + x.id.should.equal(txp.id); + should.exist(x.proposalSignature); + should.not.exist(x.proposalSignaturePubKey); + should.not.exist(x.proposalSignaturePubKeySig); + // Should be visible for other copayers as well + clients[1].getTxProposals({}, function(err, txps) { + should.not.exist(err); + txps.length.should.equal(1); + txps[0].id.should.equal(txp.id); + done(); + }); }); - }); - }); + }, + ); }); }); }); @@ -2063,22 +2362,25 @@ describe('client API', function() { var toAddress = 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5'; var opts = { txProposalId: '1234', - outputs: [{ - amount: 1e8, - toAddress: toAddress, - message: 'world', - }, { - amount: 2e8, - toAddress: toAddress, - }], + outputs: [ + { + amount: 1e8, + toAddress: toAddress, + message: 'world', + }, + { + amount: 2e8, + toAddress: toAddress, + }, + ], message: 'hello', feeLevel: 'economy', customData: { someObj: { - x: 1 + x: 1, }, - someStr: "str" - } + someStr: 'str', + }, }; clients[0].createTxProposal(opts, function(err, txp) { should.not.exist(err); @@ -2086,50 +2388,58 @@ describe('client API', function() { txp.status.should.equal('temporary'); txp.feeLevel.should.equal('economy'); txp.feePerKb.should.equal(123e2); - clients[0].publishTxProposal({ - txp: txp, - }, function(err, publishedTxp) { - should.not.exist(err); - should.exist(publishedTxp); - publishedTxp.status.should.equal('pending'); - clients[0].getTxProposals({}, function(err, txps) { + clients[0].publishTxProposal( + { + txp: txp, + }, + function(err, publishedTxp) { should.not.exist(err); - txps.length.should.equal(1); - // Try to republish from copayer 1 - clients[1].createTxProposal(opts, function(err, txp) { + should.exist(publishedTxp); + publishedTxp.status.should.equal('pending'); + clients[0].getTxProposals({}, function(err, txps) { should.not.exist(err); - should.exist(txp); - txp.status.should.equal('pending'); - clients[1].publishTxProposal({ - txp: txp - }, function(err, publishedTxp) { + txps.length.should.equal(1); + // Try to republish from copayer 1 + clients[1].createTxProposal(opts, function(err, txp) { should.not.exist(err); - should.exist(publishedTxp); - publishedTxp.status.should.equal('pending'); - done(); + should.exist(txp); + txp.status.should.equal('pending'); + clients[1].publishTxProposal( + { + txp: txp, + }, + function(err, publishedTxp) { + should.not.exist(err); + should.exist(publishedTxp); + publishedTxp.status.should.equal('pending'); + done(); + }, + ); }); }); - }); - }); + }, + ); }); }); it('Should protect against tampering at proposal creation', function(done) { var opts = { - outputs: [{ - amount: 1e8, - toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', - message: 'world' - }, { - amount: 2e8, - toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', - }], - feePerKb: 123e2, - // changeAddress: myAddress, // for singleAddress = true - message: 'hello', + outputs: [ + { + amount: 1e8, + toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', + message: 'world', + }, + { + amount: 2e8, + toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', + }, + ], + feePerKb: 123e2, + // changeAddress: myAddress, // for singleAddress = true + message: 'hello', }; var tamperings = [ - function(txp) { txp.feePerKb = 45600; }, @@ -2170,106 +2480,128 @@ describe('client API', function() { clients[0]._getCreateTxProposalArgs = function(opts) { return args; }; - async.each(tamperings, function(tamperFn, next) { - helpers.tamperResponse(clients[0], 'post', '/v2/txproposals/', args, tamperFn, function() { - clients[0].createTxProposal(opts, function(err, txp) { - should.exist(err, tamperFn); - err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); - next(); + async.each( + tamperings, + function(tamperFn, next) { + helpers.tamperResponse(clients[0], 'post', '/v2/txproposals/', args, tamperFn, function() { + clients[0].createTxProposal(opts, function(err, txp) { + should.exist(err, tamperFn); + err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); + next(); + }); }); - }); - }, function(err) { - should.not.exist(err); - clients[0]._getCreateTxProposalArgs = tmp; - done(); - }); + }, + function(err) { + should.not.exist(err); + clients[0]._getCreateTxProposalArgs = tmp; + done(); + }, + ); }); it('Should fail to publish when not enough available UTXOs', function(done) { var opts = { - outputs: [{ - amount: 3e8, - toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', - }], + outputs: [ + { + amount: 3e8, + toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', + }, + ], feePerKb: 100e2, }; var txp1, txp2; - async.series([ - - function(next) { - clients[0].createTxProposal(opts, function(err, txp) { - txp1 = txp; - next(err); - }); - }, - function(next) { - clients[0].createTxProposal(opts, function(err, txp) { - txp2 = txp; - next(err); - }); - - }, - function(next) { - clients[0].publishTxProposal({ - txp: txp1 - }, next); - }, - function(next) { - clients[0].publishTxProposal({ - txp: txp2 - }, function(err) { - should.exist(err); - err.should.be.an.instanceOf(Errors.UNAVAILABLE_UTXOS); - next(); - }); - }, - function(next) { - clients[1].rejectTxProposal(txp1, 'Free locked UTXOs', next); - }, - function(next) { - clients[2].rejectTxProposal(txp1, 'Free locked UTXOs', next); - }, - function(next) { - clients[0].publishTxProposal({ - txp: txp2 - }, next); + async.series( + [ + function(next) { + clients[0].createTxProposal(opts, function(err, txp) { + txp1 = txp; + next(err); + }); + }, + function(next) { + clients[0].createTxProposal(opts, function(err, txp) { + txp2 = txp; + next(err); + }); + }, + function(next) { + clients[0].publishTxProposal( + { + txp: txp1, + }, + next, + ); + }, + function(next) { + clients[0].publishTxProposal( + { + txp: txp2, + }, + function(err) { + should.exist(err); + err.should.be.an.instanceOf(Errors.UNAVAILABLE_UTXOS); + next(); + }, + ); + }, + function(next) { + clients[1].rejectTxProposal(txp1, 'Free locked UTXOs', next); + }, + function(next) { + clients[2].rejectTxProposal(txp1, 'Free locked UTXOs', next); + }, + function(next) { + clients[0].publishTxProposal( + { + txp: txp2, + }, + next, + ); + }, + ], + function(err) { + should.not.exist(err); + done(); }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); }); it('Should sign proposal', function(done) { var toAddress = 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5'; var opts = { - outputs: [{ - amount: 1e8, - toAddress: toAddress, - }, { - amount: 2e8, - toAddress: toAddress, - }], + outputs: [ + { + amount: 1e8, + toAddress: toAddress, + }, + { + amount: 2e8, + toAddress: toAddress, + }, + ], feePerKb: 100e2, message: 'just some message', }; clients[0].createTxProposal(opts, function(err, txp) { should.not.exist(err); should.exist(txp); - clients[0].publishTxProposal({ - txp: txp, - }, function(err, publishedTxp) { - should.not.exist(err); - should.exist(publishedTxp); - publishedTxp.status.should.equal('pending'); - clients[0].signTxProposal(publishedTxp, function(err, txp) { + clients[0].publishTxProposal( + { + txp: txp, + }, + function(err, publishedTxp) { should.not.exist(err); - clients[1].signTxProposal(publishedTxp, function(err, txp) { + should.exist(publishedTxp); + publishedTxp.status.should.equal('pending'); + clients[0].signTxProposal(publishedTxp, function(err, txp) { should.not.exist(err); - txp.status.should.equal('accepted'); - done(); + clients[1].signTxProposal(publishedTxp, function(err, txp) { + should.not.exist(err); + txp.status.should.equal('accepted'); + done(); + }); }); - }); - }); + }, + ); }); }); it('Should create proposal with unconfirmed inputs', function(done) { @@ -2399,10 +2731,12 @@ describe('client API', function() { }); it('Should encrypt proposal message', function(done) { var opts = { - outputs: [{ - amount: 1000e2, - toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', - }], + outputs: [ + { + amount: 1000e2, + toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', + }, + ], message: 'some message', feePerKb: 100e2, }; @@ -2444,15 +2778,23 @@ describe('client API', function() { helpers.createAndPublishTxProposal(clients[0], opts, function(err, x) { should.not.exist(err); - helpers.tamperResponse(clients[0], 'get', '/v1/txproposals/', {}, function(txps) { - txps[0].proposalSignature = '304402206e4a1db06e00068582d3be41cfc795dcf702451c132581e661e7241ef34ca19202203e17598b4764913309897d56446b51bc1dcd41a25d90fdb5f87a6b58fe3a6920'; - }, function() { - clients[0].getTxProposals({}, function(err, txps) { - should.exist(err); - err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); - done(); - }); - }); + helpers.tamperResponse( + clients[0], + 'get', + '/v1/txproposals/', + {}, + function(txps) { + txps[0].proposalSignature = + '304402206e4a1db06e00068582d3be41cfc795dcf702451c132581e661e7241ef34ca19202203e17598b4764913309897d56446b51bc1dcd41a25d90fdb5f87a6b58fe3a6920'; + }, + function() { + clients[0].getTxProposals({}, function(err, txps) { + should.exist(err); + err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); + done(); + }); + }, + ); }); }); }); @@ -2466,15 +2808,22 @@ describe('client API', function() { helpers.createAndPublishTxProposal(clients[0], opts, function(err, x) { should.not.exist(err); - helpers.tamperResponse(clients[0], 'get', '/v1/txproposals/', {}, function(txps) { - txps[0].outputs[0].amount = 1e8; - }, function() { - clients[0].getTxProposals({}, function(err, txps) { - should.exist(err); - err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); - done(); - }); - }); + helpers.tamperResponse( + clients[0], + 'get', + '/v1/txproposals/', + {}, + function(txps) { + txps[0].outputs[0].amount = 1e8; + }, + function() { + clients[0].getTxProposals({}, function(err, txps) { + should.exist(err); + err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); + done(); + }); + }, + ); }); }); it('should detect change address not it wallet', function(done) { @@ -2486,15 +2835,22 @@ describe('client API', function() { helpers.createAndPublishTxProposal(clients[0], opts, function(err, x) { should.not.exist(err); - helpers.tamperResponse(clients[0], 'get', '/v1/txproposals/', {}, function(txps) { - txps[0].changeAddress.address = 'mnA11ZwktRp4sZJbS8MbXmmFPZAgriuwhh'; - }, function() { - clients[0].getTxProposals({}, function(err, txps) { - should.exist(err); - err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); - done(); - }); - }); + helpers.tamperResponse( + clients[0], + 'get', + '/v1/txproposals/', + {}, + function(txps) { + txps[0].changeAddress.address = 'mnA11ZwktRp4sZJbS8MbXmmFPZAgriuwhh'; + }, + function() { + clients[0].getTxProposals({}, function(err, txps) { + should.exist(err); + err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); + done(); + }); + }, + ); }); }); }); @@ -2502,10 +2858,12 @@ describe('client API', function() { it('Should sign proposal with no change', function(done) { var toAddress = 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5'; var opts = { - outputs: [{ - amount: 4e8 - 100, - toAddress: toAddress, - }], + outputs: [ + { + amount: 4e8 - 100, + toAddress: toAddress, + }, + ], excludeUnconfirmedUtxos: true, feePerKb: 1, }; @@ -2514,64 +2872,75 @@ describe('client API', function() { should.exist(txp); var t = Utils.buildTx(txp); should.not.exist(t.getChangeOutput()); - clients[0].publishTxProposal({ - txp: txp, - }, function(err, publishedTxp) { - should.not.exist(err); - should.exist(publishedTxp); - publishedTxp.status.should.equal('pending'); - clients[0].signTxProposal(publishedTxp, function(err, txp) { + clients[0].publishTxProposal( + { + txp: txp, + }, + function(err, publishedTxp) { should.not.exist(err); - clients[1].signTxProposal(publishedTxp, function(err, txp) { + should.exist(publishedTxp); + publishedTxp.status.should.equal('pending'); + clients[0].signTxProposal(publishedTxp, function(err, txp) { should.not.exist(err); - txp.status.should.equal('accepted'); - done(); + clients[1].signTxProposal(publishedTxp, function(err, txp) { + should.not.exist(err); + txp.status.should.equal('accepted'); + done(); + }); }); - }); - }); + }, + ); }); }); it('Should sign proposal created with send max settings', function(done) { var toAddress = 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5'; - clients[0].getSendMaxInfo({ - feePerKb: 100e2, - returnInputs: true - }, function(err, info) { - should.not.exist(err); - var opts = { - outputs: [{ - amount: info.amount, - toAddress: toAddress, - }], - inputs: info.inputs, - fee: info.fee, - }; - clients[0].createTxProposal(opts, function(err, txp) { + clients[0].getSendMaxInfo( + { + feePerKb: 100e2, + returnInputs: true, + }, + function(err, info) { should.not.exist(err); - should.exist(txp); - var t = Utils.buildTx(txp); - should.not.exist(t.getChangeOutput()); - clients[0].publishTxProposal({ - txp: txp, - }, function(err, publishedTxp) { + var opts = { + outputs: [ + { + amount: info.amount, + toAddress: toAddress, + }, + ], + inputs: info.inputs, + fee: info.fee, + }; + clients[0].createTxProposal(opts, function(err, txp) { should.not.exist(err); - should.exist(publishedTxp); - publishedTxp.status.should.equal('pending'); - clients[0].signTxProposal(publishedTxp, function(err, txp) { - should.not.exist(err); - clients[1].signTxProposal(publishedTxp, function(err, txp) { + should.exist(txp); + var t = Utils.buildTx(txp); + should.not.exist(t.getChangeOutput()); + clients[0].publishTxProposal( + { + txp: txp, + }, + function(err, publishedTxp) { should.not.exist(err); - txp.status.should.equal('accepted'); - clients[0].getBalance({}, function(err, balance) { + should.exist(publishedTxp); + publishedTxp.status.should.equal('pending'); + clients[0].signTxProposal(publishedTxp, function(err, txp) { should.not.exist(err); - balance.lockedAmount.should.equal(5e8); - done(); + clients[1].signTxProposal(publishedTxp, function(err, txp) { + should.not.exist(err); + txp.status.should.equal('accepted'); + clients[0].getBalance({}, function(err, balance) { + should.not.exist(err); + balance.lockedAmount.should.equal(5e8); + done(); + }); + }); }); - }); - }); + }, + ); }); - }); - }); + }, + ); }); }); @@ -2594,15 +2963,19 @@ describe('client API', function() { clients[0].payProHttp = clients[1].payProHttp = http; clients[0].fetchPayPro(opts, function(err, paypro) { - helpers.createAndPublishTxProposal(clients[0], { - toAddress: paypro.toAddress, - amount: paypro.amount, - message: paypro.memo, - payProUrl: opts.payProUrl, - }, function(err, x) { - should.not.exist(err); - done(); - }); + helpers.createAndPublishTxProposal( + clients[0], + { + toAddress: paypro.toAddress, + amount: paypro.amount, + message: paypro.memo, + payProUrl: opts.payProUrl, + }, + function(err, x) { + should.not.exist(err); + done(); + }, + ); }); }); }); @@ -2677,8 +3050,12 @@ describe('client API', function() { var args = http.lastCall.args[0]; args.method.should.equal('POST'); args.body.length.should.be.within(440, 460); - memo.should.equal('Transaction received by BitPay. Invoice will be marked as paid if the transaction is confirmed.'); - zz.message.should.equal('Payment request for BitPay invoice CibEJJtG1t9H77KmM61E2t for merchant testCopay'); + memo.should.equal( + 'Transaction received by BitPay. Invoice will be marked as paid if the transaction is confirmed.', + ); + zz.message.should.equal( + 'Payment request for BitPay invoice CibEJJtG1t9H77KmM61E2t for merchant testCopay', + ); done(); }); }); @@ -2708,7 +3085,7 @@ describe('client API', function() { refund_to = refund_to[0]; - var amount = refund_to.get('amount') + var amount = refund_to.get('amount'); amount.low.should.equal(404500); amount.high.should.equal(0); var s = refund_to.get('script'); @@ -2734,7 +3111,6 @@ describe('client API', function() { http.onCall(5).yields(null, TestData.payProAckBuf); clients[1].broadcastTxProposal(yy, function(err, zz, memo) { - should.not.exist(err); var args = http.lastCall.args[0]; var data = MeritcorePayPro.Payment.decode(args.body); @@ -2768,15 +3144,19 @@ describe('client API', function() { clients[0].payProHttp = clients[1].payProHttp = http; clients[0].fetchPayPro(opts, function(err, paypro) { - helpers.createAndPublishTxProposal(clients[0], { - toAddress: paypro.toAddress, - amount: paypro.amount, - message: paypro.memo, - payProUrl: opts.payProUrl, - }, function(err, x) { - should.not.exist(err); - done(); - }); + helpers.createAndPublishTxProposal( + clients[0], + { + toAddress: paypro.toAddress, + amount: paypro.amount, + message: paypro.memo, + payProUrl: opts.payProUrl, + }, + function(err, x) { + should.not.exist(err); + done(); + }, + ); }); }); }); @@ -2802,7 +3182,7 @@ describe('client API', function() { refund_to = refund_to[0]; - var amount = refund_to.get('amount') + var amount = refund_to.get('amount'); amount.low.should.equal(404500); amount.high.should.equal(0); var s = refund_to.get('script'); @@ -2842,7 +3222,6 @@ describe('client API', function() { }); describe('New proposal flow', function() { - beforeEach(function(done) { http = sinon.stub(); http.yields(null, TestData.payProBuf); @@ -2858,23 +3237,31 @@ describe('client API', function() { clients[0].payProHttp = clients[1].payProHttp = http; clients[0].fetchPayPro(opts, function(err, paypro) { - clients[0].createTxProposal({ - outputs: [{ - toAddress: paypro.toAddress, - amount: paypro.amount, - }], - message: paypro.memo, - payProUrl: opts.payProUrl, - feePerKb: 100e2, - }, function(err, txp) { - should.not.exist(err); - clients[0].publishTxProposal({ - txp: txp - }, function(err) { + clients[0].createTxProposal( + { + outputs: [ + { + toAddress: paypro.toAddress, + amount: paypro.amount, + }, + ], + message: paypro.memo, + payProUrl: opts.payProUrl, + feePerKb: 100e2, + }, + function(err, txp) { should.not.exist(err); - done(); - }); - }); + clients[0].publishTxProposal( + { + txp: txp, + }, + function(err) { + should.not.exist(err); + done(); + }, + ); + }, + ); }); }); }); @@ -2905,31 +3292,36 @@ describe('client API', function() { blockchainExplorerMock.setUtxo(x0, 1, 2); var toAddress = 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5'; var opts = { - outputs: [{ - amount: 40000, - toAddress: toAddress, - }], + outputs: [ + { + amount: 40000, + toAddress: toAddress, + }, + ], feePerKb: 100e2, txProposalId: id, }; clients[0].createTxProposal(opts, function(err, txp) { should.not.exist(err); should.exist(txp); - clients[0].publishTxProposal({ - txp: txp, - }, function(err, publishedTxp) { - should.not.exist(err); - publishedTxp.id.should.equal(id); - clients[0].removeTxProposal(publishedTxp, function(err) { - opts.txProposalId = null; - clients[0].createTxProposal(opts, function(err, txp) { - should.not.exist(err); - should.exist(txp); - txp.id.should.not.equal(id); - done(); + clients[0].publishTxProposal( + { + txp: txp, + }, + function(err, publishedTxp) { + should.not.exist(err); + publishedTxp.id.should.equal(id); + clients[0].removeTxProposal(publishedTxp, function(err) { + opts.txProposalId = null; + clients[0].createTxProposal(opts, function(err, txp) { + should.not.exist(err); + should.exist(txp); + txp.id.should.not.equal(id); + done(); + }); }); - }); - }); + }, + ); }); }); }); @@ -2940,11 +3332,13 @@ describe('client API', function() { var toAddress = 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5'; var opts = { message: 'hello', - outputs: [{ - amount: 10000, - toAddress: toAddress, - message: 'world', - }], + outputs: [ + { + amount: 10000, + toAddress: toAddress, + message: 'world', + }, + ], feePerKb: 100e2, }; @@ -2980,7 +3374,7 @@ describe('client API', function() { clients[0].broadcastTxProposal(txp, function(err, txp) { should.not.exist(err); txp.status.should.equal('broadcasted'); - txp.txid.should.equal((new Meritcore.Transaction(blockchainExplorerMock.lastBroadcasted)).id); + txp.txid.should.equal(new Meritcore.Transaction(blockchainExplorerMock.lastBroadcasted).id); done(); }); } else { @@ -2989,7 +3383,7 @@ describe('client API', function() { }); }); }); - }; + } it('should create, get, sign, and broadcast proposal with no payProUrl', function(done) { delete opts.payProUrl; doit(opts, false, true, done); @@ -3022,11 +3416,13 @@ describe('client API', function() { should.exist(x0.address); blockchainExplorerMock.setUtxo(x0, 1, 1); var opts = { - outputs: [{ - amount: 10000000, - toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', - message: 'output 0', - }], + outputs: [ + { + amount: 10000000, + toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', + message: 'output 0', + }, + ], message: 'hello', feePerKb: 100e2, }; @@ -3046,7 +3442,7 @@ describe('client API', function() { clients[0].broadcastTxProposal(txp, function(err, txp) { should.not.exist(err); txp.status.should.equal('broadcasted'); - txp.txid.should.equal((new Meritcore.Transaction(blockchainExplorerMock.lastBroadcasted)).id); + txp.txid.should.equal(new Meritcore.Transaction(blockchainExplorerMock.lastBroadcasted).id); txp.outputs[0].message.should.equal('output 0'); txp.message.should.equal('hello'); done(); @@ -3119,7 +3515,7 @@ describe('client API', function() { txp.status.should.equal('accepted'); clients[1].broadcastTxProposal(txp, function(err, txp) { txp.status.should.equal('broadcasted'); - txp.txid.should.equal((new Meritcore.Transaction(blockchainExplorerMock.lastBroadcasted)).id); + txp.txid.should.equal(new Meritcore.Transaction(blockchainExplorerMock.lastBroadcasted).id); done(); }); }); @@ -3154,8 +3550,6 @@ describe('client API', function() { }); }); - - it('Send, reject, 2 signs and broadcast in 2-3 wallet', function(done) { helpers.createAndJoinWallet(clients, 2, 3, function(w) { clients[0].createAddress(function(err, x0) { @@ -3182,7 +3576,7 @@ describe('client API', function() { txp.status.should.equal('accepted'); clients[2].broadcastTxProposal(txp, function(err, txp) { txp.status.should.equal('broadcasted'); - txp.txid.should.equal((new Meritcore.Transaction(blockchainExplorerMock.lastBroadcasted)).id); + txp.txid.should.equal(new Meritcore.Transaction(blockchainExplorerMock.lastBroadcasted).id); done(); }); }); @@ -3271,7 +3665,8 @@ describe('client API', function() { helpers.createAndJoinWallet(clients, 1, 1, function(w) { var opts = { network: 'testnet', - rawTx: '0100000001b1b1b1b0d9786e237ec6a4b80049df9e926563fee7bdbc1ac3c4efc3d0af9a1c010000006a47304402207c612d36d0132ed463526a4b2370de60b0aa08e76b6f370067e7915c2c74179b02206ae8e3c6c84cee0bca8521704eddb40afe4590f14fd5d6434da980787ba3d5110121031be732b984b0f1f404840f2479bcc81f90187298efecc67dd83e1f93d9b2860dfeffffff0200ab9041000000001976a91403383bd4cff200de3690db1ed17d0b1a228ea43f88ac25ad6ed6190000001976a9147ccbaf7bcc1e323548bd1d57d7db03f6e6daf76a88acaec70700', + rawTx: + '0100000001b1b1b1b0d9786e237ec6a4b80049df9e926563fee7bdbc1ac3c4efc3d0af9a1c010000006a47304402207c612d36d0132ed463526a4b2370de60b0aa08e76b6f370067e7915c2c74179b02206ae8e3c6c84cee0bca8521704eddb40afe4590f14fd5d6434da980787ba3d5110121031be732b984b0f1f404840f2479bcc81f90187298efecc67dd83e1f93d9b2860dfeffffff0200ab9041000000001976a91403383bd4cff200de3690db1ed17d0b1a228ea43f88ac25ad6ed6190000001976a9147ccbaf7bcc1e323548bd1d57d7db03f6e6daf76a88acaec70700', }; clients[0].broadcastRawTx(opts, function(err, txid) { should.not.exist(err); @@ -3310,128 +3705,143 @@ describe('client API', function() { }); }); it('should get transaction history decorated with proposal & notes', function(done) { - async.waterfall([ - - function(next) { - helpers.createAndJoinWallet(clients, 2, 3, function(w) { - clients[0].createAddress(function(err, address) { - should.not.exist(err); - should.exist(address); - next(null, address); + async.waterfall( + [ + function(next) { + helpers.createAndJoinWallet(clients, 2, 3, function(w) { + clients[0].createAddress(function(err, address) { + should.not.exist(err); + should.exist(address); + next(null, address); + }); }); - }); - }, - function(address, next) { - blockchainExplorerMock.setUtxo(address, 10, 2); - var opts = { - amount: 10000, - toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', - message: 'some message', - }; - helpers.createAndPublishTxProposal(clients[0], opts, function(err, txp) { - should.not.exist(err); - clients[1].rejectTxProposal(txp, 'some reason', function(err, txp) { + }, + function(address, next) { + blockchainExplorerMock.setUtxo(address, 10, 2); + var opts = { + amount: 10000, + toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', + message: 'some message', + }; + helpers.createAndPublishTxProposal(clients[0], opts, function(err, txp) { should.not.exist(err); - clients[2].signTxProposal(txp, function(err, txp) { + clients[1].rejectTxProposal(txp, 'some reason', function(err, txp) { should.not.exist(err); - clients[0].signTxProposal(txp, function(err, txp) { + clients[2].signTxProposal(txp, function(err, txp) { should.not.exist(err); - txp.status.should.equal('accepted'); - clients[0].broadcastTxProposal(txp, function(err, txp) { + clients[0].signTxProposal(txp, function(err, txp) { should.not.exist(err); - txp.status.should.equal('broadcasted'); - next(null, txp); + txp.status.should.equal('accepted'); + clients[0].broadcastTxProposal(txp, function(err, txp) { + should.not.exist(err); + txp.status.should.equal('broadcasted'); + next(null, txp); + }); }); }); }); }); - }); - }, - function(txp, next) { - clients[1].editTxNote({ - txid: txp.txid, - body: 'just a note' - }, function(err) { - return next(err, txp); - }); - }, - function(txp, next) { - var history = _.cloneDeep(TestData.history); - history[0].txid = txp.txid; - _.each(history, function(h) { - h.blocktime = Math.floor(Date.now() / 1000); - }); - blockchainExplorerMock.setHistory(history); - clients[0].getTxHistory({}, function(err, txs) { - should.not.exist(err); - should.exist(txs); - txs.length.should.equal(2); - var decorated = _.find(txs, { - txid: txp.txid + }, + function(txp, next) { + clients[1].editTxNote( + { + txid: txp.txid, + body: 'just a note', + }, + function(err) { + return next(err, txp); + }, + ); + }, + function(txp, next) { + var history = _.cloneDeep(TestData.history); + history[0].txid = txp.txid; + _.each(history, function(h) { + h.blocktime = Math.floor(Date.now() / 1000); }); - should.exist(decorated); - decorated.proposalId.should.equal(txp.id); - decorated.message.should.equal('some message'); - decorated.actions.length.should.equal(3); - var rejection = _.find(decorated.actions, { - type: 'reject' + blockchainExplorerMock.setHistory(history); + clients[0].getTxHistory({}, function(err, txs) { + should.not.exist(err); + should.exist(txs); + txs.length.should.equal(2); + var decorated = _.find(txs, { + txid: txp.txid, + }); + should.exist(decorated); + decorated.proposalId.should.equal(txp.id); + decorated.message.should.equal('some message'); + decorated.actions.length.should.equal(3); + var rejection = _.find(decorated.actions, { + type: 'reject', + }); + should.exist(rejection); + rejection.comment.should.equal('some reason'); + + var note = decorated.note; + should.exist(note); + note.body.should.equal('just a note'); + note.editedByName.should.equal('copayer 1'); + next(); }); - should.exist(rejection); - rejection.comment.should.equal('some reason'); - - var note = decorated.note; - should.exist(note); - note.body.should.equal('just a note'); - note.editedByName.should.equal('copayer 1'); - next(); - }); - } - ], function(err) { - should.not.exist(err); - done(); - }); + }, + ], + function(err) { + should.not.exist(err); + done(); + }, + ); }); it('should get paginated transaction history', function(done) { - var testCases = [{ - opts: {}, - expected: [20, 10] - }, { - opts: { - skip: 1, + var testCases = [ + { + opts: {}, + expected: [20, 10], + }, + { + opts: { + skip: 1, + }, + expected: [10], }, - expected: [10] - }, { - opts: { - limit: 1, + { + opts: { + limit: 1, + }, + expected: [20], }, - expected: [20] - }, { - opts: { - skip: 3, + { + opts: { + skip: 3, + }, + expected: [], }, - expected: [] - }, { - opts: { - skip: 1, - limit: 10, + { + opts: { + skip: 1, + limit: 10, + }, + expected: [10], }, - expected: [10] - }, ]; + ]; blockchainExplorerMock.setHistory(TestData.history); helpers.createAndJoinWallet(clients, 1, 1, function(w) { clients[0].createAddress(function(err, x0) { should.not.exist(err); should.exist(x0.address); - async.each(testCases, function(testCase, next) { - clients[0].getTxHistory(testCase.opts, function(err, txs) { - should.not.exist(err); - should.exist(txs); - var times = _.map(txs, 'time'); - times.should.deep.equal(testCase.expected); - next(); - }); - }, done); + async.each( + testCases, + function(testCase, next) { + clients[0].getTxHistory(testCase.opts, function(err, txs) { + should.not.exist(err); + should.exist(txs); + var times = _.map(txs, 'time'); + times.should.deep.equal(testCase.expected); + next(); + }); + }, + done, + ); }); }); }); @@ -3445,153 +3855,194 @@ describe('client API', function() { }); it('should edit a note for an arbitrary txid', function(done) { - clients[0].editTxNote({ - txid: '123', - body: 'note body' - }, function(err, note) { - should.not.exist(err); - should.exist(note); - note.body.should.equal('note body'); - clients[0].getTxNote({ + clients[0].editTxNote( + { txid: '123', - }, function(err, note) { + body: 'note body', + }, + function(err, note) { should.not.exist(err); should.exist(note); - note.txid.should.equal('123'); - note.walletId.should.equal(clients[0].credentials.walletId); note.body.should.equal('note body'); - note.editedBy.should.equal(clients[0].credentials.copayerId); - note.editedByName.should.equal(clients[0].credentials.copayerName); - note.createdOn.should.equal(note.editedOn); - done(); - }); - }); + clients[0].getTxNote( + { + txid: '123', + }, + function(err, note) { + should.not.exist(err); + should.exist(note); + note.txid.should.equal('123'); + note.walletId.should.equal(clients[0].credentials.walletId); + note.body.should.equal('note body'); + note.editedBy.should.equal(clients[0].credentials.copayerId); + note.editedByName.should.equal(clients[0].credentials.copayerName); + note.createdOn.should.equal(note.editedOn); + done(); + }, + ); + }, + ); }); it('should not send note body in clear text', function(done) { var spy = sinon.spy(clients[0], '_doPutRequest'); - clients[0].editTxNote({ - txid: '123', - body: 'a random note' - }, function(err) { - should.not.exist(err); - var url = spy.getCall(0).args[0]; - var body = JSON.stringify(spy.getCall(0).args[1]); - url.should.contain('/txnotes'); - body.should.contain('123'); - body.should.not.contain('a random note'); - done(); - }); + clients[0].editTxNote( + { + txid: '123', + body: 'a random note', + }, + function(err) { + should.not.exist(err); + var url = spy.getCall(0).args[0]; + var body = JSON.stringify(spy.getCall(0).args[1]); + url.should.contain('/txnotes'); + body.should.contain('123'); + body.should.not.contain('a random note'); + done(); + }, + ); }); it('should share notes between copayers', function(done) { - clients[0].editTxNote({ - txid: '123', - body: 'note body' - }, function(err) { - should.not.exist(err); - clients[0].getTxNote({ + clients[0].editTxNote( + { txid: '123', - }, function(err, note) { + body: 'note body', + }, + function(err) { should.not.exist(err); - should.exist(note); - note.editedBy.should.equal(clients[0].credentials.copayerId); - var creator = note.editedBy; - clients[1].getTxNote({ - txid: '123', - }, function(err, note) { - should.not.exist(err); - should.exist(note); - note.body.should.equal('note body'); - note.editedBy.should.equal(creator); - done(); - }); - }); - }); + clients[0].getTxNote( + { + txid: '123', + }, + function(err, note) { + should.not.exist(err); + should.exist(note); + note.editedBy.should.equal(clients[0].credentials.copayerId); + var creator = note.editedBy; + clients[1].getTxNote( + { + txid: '123', + }, + function(err, note) { + should.not.exist(err); + should.exist(note); + note.body.should.equal('note body'); + note.editedBy.should.equal(creator); + done(); + }, + ); + }, + ); + }, + ); }); it('should get all notes edited past a given date', function(done) { var clock = sinon.useFakeTimers('Date'); - async.series([ - - function(next) { - clients[0].getTxNotes({}, function(err, notes) { - should.not.exist(err); - notes.should.be.empty; - next(); - }); - }, - function(next) { - clients[0].editTxNote({ - txid: '123', - body: 'note body' - }, next); - }, - function(next) { - clients[0].getTxNotes({ - minTs: 0, - }, function(err, notes) { - should.not.exist(err); - notes.length.should.equal(1); - notes[0].txid.should.equal('123'); - next(); - }); - }, - function(next) { - clock.tick(60 * 1000); - clients[0].editTxNote({ - txid: '456', - body: 'another note' - }, next); - }, - function(next) { - clients[0].getTxNotes({ - minTs: 0, - }, function(err, notes) { - should.not.exist(err); - notes.length.should.equal(2); - _.difference(_.map(notes, 'txid'), ['123', '456']).should.be.empty; - next(); - }); - }, - function(next) { - clients[0].getTxNotes({ - minTs: 50, - }, function(err, notes) { - should.not.exist(err); - notes.length.should.equal(1); - notes[0].txid.should.equal('456'); - next(); - }); - }, - function(next) { - clock.tick(60 * 1000); - clients[0].editTxNote({ - txid: '123', - body: 'an edit' - }, next); - }, - function(next) { - clients[0].getTxNotes({ - minTs: 100, - }, function(err, notes) { - should.not.exist(err); - notes.length.should.equal(1); - notes[0].txid.should.equal('123'); - notes[0].body.should.equal('an edit'); - next(); - }); - }, - function(next) { - clients[0].getTxNotes({}, function(err, notes) { - should.not.exist(err); - notes.length.should.equal(2); - next(); - }); + async.series( + [ + function(next) { + clients[0].getTxNotes({}, function(err, notes) { + should.not.exist(err); + notes.should.be.empty; + next(); + }); + }, + function(next) { + clients[0].editTxNote( + { + txid: '123', + body: 'note body', + }, + next, + ); + }, + function(next) { + clients[0].getTxNotes( + { + minTs: 0, + }, + function(err, notes) { + should.not.exist(err); + notes.length.should.equal(1); + notes[0].txid.should.equal('123'); + next(); + }, + ); + }, + function(next) { + clock.tick(60 * 1000); + clients[0].editTxNote( + { + txid: '456', + body: 'another note', + }, + next, + ); + }, + function(next) { + clients[0].getTxNotes( + { + minTs: 0, + }, + function(err, notes) { + should.not.exist(err); + notes.length.should.equal(2); + _.difference(_.map(notes, 'txid'), ['123', '456']).should.be.empty; + next(); + }, + ); + }, + function(next) { + clients[0].getTxNotes( + { + minTs: 50, + }, + function(err, notes) { + should.not.exist(err); + notes.length.should.equal(1); + notes[0].txid.should.equal('456'); + next(); + }, + ); + }, + function(next) { + clock.tick(60 * 1000); + clients[0].editTxNote( + { + txid: '123', + body: 'an edit', + }, + next, + ); + }, + function(next) { + clients[0].getTxNotes( + { + minTs: 100, + }, + function(err, notes) { + should.not.exist(err); + notes.length.should.equal(1); + notes[0].txid.should.equal('123'); + notes[0].body.should.equal('an edit'); + next(); + }, + ); + }, + function(next) { + clients[0].getTxNotes({}, function(err, notes) { + should.not.exist(err); + notes.length.should.equal(2); + next(); + }); + }, + ], + function(err) { + should.not.exist(err); + clock.restore(); + done(); }, - ], function(err) { - should.not.exist(err); - clock.restore(); - done(); - }); + ); }); }); @@ -3654,7 +4105,7 @@ describe('client API', function() { clients[0].encryptPrivateKey('password'); var exported = clients[0].export({ - password: 'password' + password: 'password', }); importedClient = helpers.newClient(app); @@ -3670,13 +4121,13 @@ describe('client API', function() { clients[0].encryptPrivateKey('password'); var exported = clients[0].export({ - password: 'password' + password: 'password', }); var err; try { var exported = clients[0].export({ - password: 'wrong' + password: 'wrong', }); } catch (ex) { err = ex; @@ -3693,17 +4144,21 @@ describe('client API', function() { var exported = clients[0].getMnemonic(); importedClient = helpers.newClient(app); - importedClient.importFromMnemonic(exported, { - network: c.network, - }, function(err) { - var c2 = importedClient.credentials; - c2.xPrivKey.should.equal(key); - should.not.exist(err); - c2.walletId.should.equal(walletId); - c2.walletName.should.equal(walletName); - c2.copayerName.should.equal(copayerName); - done(); - }); + importedClient.importFromMnemonic( + exported, + { + network: c.network, + }, + function(err) { + var c2 = importedClient.credentials; + c2.xPrivKey.should.equal(key); + should.not.exist(err); + c2.walletId.should.equal(walletId); + c2.walletName.should.equal(walletName); + c2.copayerName.should.equal(copayerName); + done(); + }, + ); }); it('should export & import with xprivkey + MWSs', function(done) { @@ -3730,18 +4185,25 @@ describe('client API', function() { describe('Non-compliant derivation', function() { function setup(done) { - clients[0].createWallet('mywallet', 'creator', 1, 1, { - network: 'livenet', - beacon: 'code' - }, function(err) { - should.not.exist(err); - clients[0].createAddress(function(err, addr) { + clients[0].createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'livenet', + beacon: 'code', + }, + function(err) { should.not.exist(err); - address = addr.address; - done(); - }); - }); - }; + clients[0].createAddress(function(err, addr) { + should.not.exist(err); + address = addr.address; + done(); + }); + }, + ); + } beforeEach(function() { importedClient = null; @@ -3761,18 +4223,30 @@ describe('client API', function() { network: 'livenet', nonCompliantDerivation: true, }); - clients[0].credentials.xPrivKey.toString().should.equal('xprv9s21ZrQH143K3E71Wm5nrxuMdqCTMG6AM5Xyp4dJ3ZkUj2gEpfifT5Hc1cfqnycKooRpzoH4gjmAKDmGGaH2k2cSe29EcQSarveq6STBZZW'); - clients[0].credentials.xPubKey.toString().should.equal('xpub6CLj2x8T5zwngq3Uq42PbXbAXnyaUtsANEZaBjAPNBn5PbhSJM29DM5nhrdJDNpEy9X3n5sQhk6CNA7PKTp48Xvq3QFdiYAXAcaWEJ6Xmug'); + clients[0].credentials.xPrivKey + .toString() + .should.equal( + 'xprv9s21ZrQH143K3E71Wm5nrxuMdqCTMG6AM5Xyp4dJ3ZkUj2gEpfifT5Hc1cfqnycKooRpzoH4gjmAKDmGGaH2k2cSe29EcQSarveq6STBZZW', + ); + clients[0].credentials.xPubKey + .toString() + .should.equal( + 'xpub6CLj2x8T5zwngq3Uq42PbXbAXnyaUtsANEZaBjAPNBn5PbhSJM29DM5nhrdJDNpEy9X3n5sQhk6CNA7PKTp48Xvq3QFdiYAXAcaWEJ6Xmug', + ); setup(function() { importedClient = helpers.newClient(app); var spy = sinon.spy(importedClient, 'openWallet'); - importedClient.importFromMnemonic(clients[0].getMnemonic(), { - network: 'livenet', - }, function(err) { - should.not.exist(err); - spy.getCalls().length.should.equal(2); - done(); - }); + importedClient.importFromMnemonic( + clients[0].getMnemonic(), + { + network: 'livenet', + }, + function(err) { + should.not.exist(err); + spy.getCalls().length.should.equal(2); + done(); + }, + ); }); }); @@ -3782,15 +4256,19 @@ describe('client API', function() { }); importedClient = helpers.newClient(app); var spy = sinon.spy(importedClient, 'openWallet'); - importedClient.importFromMnemonic(clients[0].getMnemonic(), { - network: 'livenet', - }, function(err) { - should.exist(err); - err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); - spy.getCalls().length.should.equal(1); - importedClient = null; - done(); - }); + importedClient.importFromMnemonic( + clients[0].getMnemonic(), + { + network: 'livenet', + }, + function(err) { + should.exist(err); + err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); + spy.getCalls().length.should.equal(1); + importedClient = null; + done(); + }, + ); }); it('should export & import with xprivkey + MWS', function(done) { clients[0].seedFromMnemonic('relax about label gentle insect cross summer helmet come price elephant seek', { @@ -3798,17 +4276,20 @@ describe('client API', function() { }); importedClient = helpers.newClient(app); var spy = sinon.spy(importedClient, 'openWallet'); - importedClient.importFromExtendedPrivateKey(clients[0].getKeys().xPrivKey, { - network: 'livenet', - }, function(err) { - should.exist(err); - err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); - spy.getCalls().length.should.equal(1); - importedClient = null; - done(); - }); + importedClient.importFromExtendedPrivateKey( + clients[0].getKeys().xPrivKey, + { + network: 'livenet', + }, + function(err) { + should.exist(err); + err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); + spy.getCalls().length.should.equal(1); + importedClient = null; + done(); + }, + ); }); - }); }); @@ -3827,7 +4308,8 @@ describe('client API', function() { var exported = JSON.parse(clients[0].export()); // Tamper export with a wrong xpub - exported.xPubKey = 'tpubD6NzVbkrYhZ4XJEQQWBgysPKJcBv8zLhHpfhcw4RyhakMxmffNRRRFDUe1Zh7fxvjt1FdNJcaxHgqxyKLL8XiZug7C8KJFLFtGfPVBcY6Nb'; + exported.xPubKey = + 'tpubD6NzVbkrYhZ4XJEQQWBgysPKJcBv8zLhHpfhcw4RyhakMxmffNRRRFDUe1Zh7fxvjt1FdNJcaxHgqxyKLL8XiZug7C8KJFLFtGfPVBcY6Nb'; var importedClient = helpers.newClient(app); should.not.exist(importedClient.keyDerivationOk); @@ -3850,51 +4332,70 @@ describe('client API', function() { var client = helpers.newClient(app); client.seedFromRandomWithMnemonic(); var exported = client.getMnemonic(); - client.createWallet('mywallet', 'creator', 1, 1, { - network: 'livenet', - beacon: 'code' - }, function(err) { - should.not.exist(err); - var c = client.credentials; - importedClient = helpers.newClient(app); - importedClient.importFromMnemonic(exported, {}, function(err) { + client.createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'livenet', + beacon: 'code', + }, + function(err) { should.not.exist(err); - var c2 = importedClient.credentials; - c2.network.should.equal('livenet'); - c2.xPubKey.should.equal(client.credentials.xPubKey); - c2.personalEncryptingKey.should.equal(c.personalEncryptingKey); - c2.walletId.should.equal(c.walletId); - c2.walletName.should.equal(c.walletName); - c2.copayerName.should.equal(c.copayerName); - done(); - }); - }); + var c = client.credentials; + importedClient = helpers.newClient(app); + importedClient.importFromMnemonic(exported, {}, function(err) { + should.not.exist(err); + var c2 = importedClient.credentials; + c2.network.should.equal('livenet'); + c2.xPubKey.should.equal(client.credentials.xPubKey); + c2.personalEncryptingKey.should.equal(c.personalEncryptingKey); + c2.walletId.should.equal(c.walletId); + c2.walletName.should.equal(c.walletName); + c2.copayerName.should.equal(c.copayerName); + done(); + }); + }, + ); }); // Generated with https://dcpos.github.io/bip39/ it('should fail to import from words if not at MWS', function(done) { var exported = 'bounce tonight little spy earn void nominee ankle walk ten type update'; importedClient = helpers.newClient(app); - importedClient.importFromMnemonic(exported, { - network: 'testnet', - }, function(err) { - err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); - importedClient.mnemonicHasPassphrase().should.equal(false); - importedClient.credentials.xPrivKey.should.equal('tprv8ZgxMBicQKsPdTYGTn3cPvTJJuuKHCYbfH1fbu4ceZ5tzYrcjYMKY1JfZiEFDDpEXWquSpX6jRsEoVPoaSw82tQ1Wn1U3K1bQDZBj3UGuEG'); - done(); - }); + importedClient.importFromMnemonic( + exported, + { + network: 'testnet', + }, + function(err) { + err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); + importedClient.mnemonicHasPassphrase().should.equal(false); + importedClient.credentials.xPrivKey.should.equal( + 'tprv8ZgxMBicQKsPdTYGTn3cPvTJJuuKHCYbfH1fbu4ceZ5tzYrcjYMKY1JfZiEFDDpEXWquSpX6jRsEoVPoaSw82tQ1Wn1U3K1bQDZBj3UGuEG', + ); + done(); + }, + ); }); it('should fail to import from words if not at MWS, with passphrase', function(done) { var exported = 'bounce tonight little spy earn void nominee ankle walk ten type update'; importedClient = helpers.newClient(app); - importedClient.importFromMnemonic(exported, { - network: 'testnet', - passphrase: 'hola', - }, function(err) { - err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); - importedClient.mnemonicHasPassphrase().should.equal(true); - importedClient.credentials.xPrivKey.should.equal('tprv8ZgxMBicQKsPdVijVxEu7gVDi86PUZqbCe7xTGLwVXwZpsG3HuxLDjXL3DXRSaaNymMD7gRpXimxnUDYa5N7pLTKLQymdSotrb4co7Nwrs7'); - done(); - }); + importedClient.importFromMnemonic( + exported, + { + network: 'testnet', + passphrase: 'hola', + }, + function(err) { + err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); + importedClient.mnemonicHasPassphrase().should.equal(true); + importedClient.credentials.xPrivKey.should.equal( + 'tprv8ZgxMBicQKsPdVijVxEu7gVDi86PUZqbCe7xTGLwVXwZpsG3HuxLDjXL3DXRSaaNymMD7gRpXimxnUDYa5N7pLTKLQymdSotrb4co7Nwrs7', + ); + done(); + }, + ); }); }); @@ -3969,56 +4470,61 @@ describe('client API', function() { var newApp; var expressApp = new ExpressApp(); - expressApp.start({ - storage: storage, - blockchainExplorer: blockchainExplorerMock, - disableLogs: true, - }, function() { - newApp = expressApp.app; + expressApp.start( + { + storage: storage, + blockchainExplorer: blockchainExplorerMock, + disableLogs: true, + }, + function() { + newApp = expressApp.app; - var oldPKR = _.clone(clients[0].credentials.publicKeyRing); - var recoveryClient = helpers.newClient(newApp); - recoveryClient.import(clients[0].export()); + var oldPKR = _.clone(clients[0].credentials.publicKeyRing); + var recoveryClient = helpers.newClient(newApp); + recoveryClient.import(clients[0].export()); - recoveryClient.getStatus({}, function(err, status) { - should.exist(err); - err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); - var spy = sinon.spy(recoveryClient, '_doPostRequest'); - recoveryClient.recreateWallet(function(err) { - should.not.exist(err); + recoveryClient.getStatus({}, function(err, status) { + should.exist(err); + err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); + var spy = sinon.spy(recoveryClient, '_doPostRequest'); + recoveryClient.recreateWallet(function(err) { + should.not.exist(err); - // Do not send wallet name and copayer names in clear text - var url = spy.getCall(0).args[0]; - var body = JSON.stringify(spy.getCall(0).args[1]); - url.should.contain('/wallets'); - body.should.not.contain('mywallet'); - var url = spy.getCall(1).args[0]; - var body = JSON.stringify(spy.getCall(1).args[1]); - url.should.contain('/copayers'); - body.should.not.contain('creator'); - body.should.not.contain('copayer 1'); + // Do not send wallet name and copayer names in clear text + var url = spy.getCall(0).args[0]; + var body = JSON.stringify(spy.getCall(0).args[1]); + url.should.contain('/wallets'); + body.should.not.contain('mywallet'); + var url = spy.getCall(1).args[0]; + var body = JSON.stringify(spy.getCall(1).args[1]); + url.should.contain('/copayers'); + body.should.not.contain('creator'); + body.should.not.contain('copayer 1'); - recoveryClient.getStatus({}, function(err, status) { - should.not.exist(err); - status.wallet.name.should.equal('mywallet'); - _.difference(_.map(status.wallet.copayers, 'name'), ['creator', 'copayer 1']).length.should.equal(0); - recoveryClient.createAddress(function(err, addr2) { + recoveryClient.getStatus({}, function(err, status) { should.not.exist(err); - should.exist(addr2); - addr2.address.should.equal(addr.address); - addr2.path.should.equal(addr.path); - - var recoveryClient2 = helpers.newClient(newApp); - recoveryClient2.import(clients[1].export()); - recoveryClient2.getStatus({}, function(err, status) { + status.wallet.name.should.equal('mywallet'); + _.difference(_.map(status.wallet.copayers, 'name'), ['creator', 'copayer 1']).length.should.equal( + 0, + ); + recoveryClient.createAddress(function(err, addr2) { should.not.exist(err); - done(); + should.exist(addr2); + addr2.address.should.equal(addr.address); + addr2.path.should.equal(addr.path); + + var recoveryClient2 = helpers.newClient(newApp); + recoveryClient2.import(clients[1].export()); + recoveryClient2.getStatus({}, function(err, status) { + should.not.exist(err); + done(); + }); }); }); }); }); - }); - }); + }, + ); }); }); }); @@ -4036,7 +4542,8 @@ describe('client API', function() { }); var newApp; var expressApp = new ExpressApp(); - expressApp.start({ + expressApp.start( + { storage: storage, blockchainExplorer: blockchainExplorerMock, disableLogs: true, @@ -4057,25 +4564,30 @@ describe('client API', function() { recoveryClient.startScan({}, function(err) { should.not.exist(err); var balance = 0; - async.whilst(function() { - return balance == 0; - }, function(next) { - setTimeout(function() { - recoveryClient.getBalance({}, function(err, b) { - balance = b.totalAmount; - next(err); - }); - }, 200); - }, function(err) { - should.not.exist(err); - balance.should.equal(1e8); - done(); - }); + async.whilst( + function() { + return balance == 0; + }, + function(next) { + setTimeout(function() { + recoveryClient.getBalance({}, function(err, b) { + balance = b.totalAmount; + next(err); + }); + }, 200); + }, + function(err) { + should.not.exist(err); + balance.should.equal(1e8); + done(); + }, + ); }); }); }); }); - }); + }, + ); }); }); }); @@ -4091,7 +4603,8 @@ describe('client API', function() { }); var newApp; var expressApp = new ExpressApp(); - expressApp.start({ + expressApp.start( + { storage: storage, blockchainExplorer: blockchainExplorerMock, disableLogs: true, @@ -4112,7 +4625,10 @@ describe('client API', function() { should.not.exist(err); recoveryClient.getStatus({}, function(err, status) { should.not.exist(err); - _.difference(_.map(status.wallet.copayers, 'name'), ['creator', 'copayer 1']).length.should.equal(0); + _.difference(_.map(status.wallet.copayers, 'name'), [ + 'creator', + 'copayer 1', + ]).length.should.equal(0); recoveryClient.createAddress(function(err, addr2) { should.not.exist(err); should.exist(addr2); @@ -4130,64 +4646,80 @@ describe('client API', function() { }); }); }); - }); + }, + ); }); }); }); it('should be able to recreate 1-of-1 wallet with external key (m/48) account 2', function(done) { - clients[0].seedFromExtendedPublicKey('tprv8ZgxMBicQKsPdeZR4tV14PAJmzrWGsmafRVaHXUVYezrSbtnFM1CnqdbQuXfmSLxwr71axKewd3LTRDcQmtttUnZe27TQoGmGMeddv1H9JQ', 'ledger', 'b0937662dddea83b0ce037ff3991dd', { - account: 2, - derivationStrategy: 'BIP48', - }); - clients[0].createWallet('mywallet', 'creator', 1, 1, { - network: 'testnet', - beacon: 'code' - }, function(err, secret) { - should.not.exist(err); - - clients[0].createAddress(function(err, addr) { + clients[0].seedFromExtendedPublicKey( + 'tprv8ZgxMBicQKsPdeZR4tV14PAJmzrWGsmafRVaHXUVYezrSbtnFM1CnqdbQuXfmSLxwr71axKewd3LTRDcQmtttUnZe27TQoGmGMeddv1H9JQ', + 'ledger', + 'b0937662dddea83b0ce037ff3991dd', + { + account: 2, + derivationStrategy: 'BIP48', + }, + ); + clients[0].createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'testnet', + beacon: 'code', + }, + function(err, secret) { should.not.exist(err); - should.exist(addr); - var storage = new Storage({ - db: helpers.newDb(), - }); + clients[0].createAddress(function(err, addr) { + should.not.exist(err); + should.exist(addr); - var newApp; - var expressApp = new ExpressApp(); - expressApp.start({ - storage: storage, - blockchainExplorer: blockchainExplorerMock, - disableLogs: true, - }, function() { - newApp = expressApp.app; + var storage = new Storage({ + db: helpers.newDb(), + }); - var oldPKR = _.clone(clients[0].credentials.publicKeyRing); - var recoveryClient = helpers.newClient(newApp); - recoveryClient.import(clients[0].export()); - recoveryClient.credentials.derivationStrategy.should.equal('BIP48'); - recoveryClient.credentials.account.should.equal(2); - recoveryClient.getStatus({}, function(err, status) { - should.exist(err); - err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); - recoveryClient.recreateWallet(function(err) { - should.not.exist(err); + var newApp; + var expressApp = new ExpressApp(); + expressApp.start( + { + storage: storage, + blockchainExplorer: blockchainExplorerMock, + disableLogs: true, + }, + function() { + newApp = expressApp.app; + + var oldPKR = _.clone(clients[0].credentials.publicKeyRing); + var recoveryClient = helpers.newClient(newApp); + recoveryClient.import(clients[0].export()); + recoveryClient.credentials.derivationStrategy.should.equal('BIP48'); + recoveryClient.credentials.account.should.equal(2); recoveryClient.getStatus({}, function(err, status) { - should.not.exist(err); - recoveryClient.createAddress(function(err, addr2) { + should.exist(err); + err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); + recoveryClient.recreateWallet(function(err) { should.not.exist(err); - should.exist(addr2); - addr2.address.should.equal(addr.address); - addr2.path.should.equal(addr.path); - done(); + recoveryClient.getStatus({}, function(err, status) { + should.not.exist(err); + recoveryClient.createAddress(function(err, addr2) { + should.not.exist(err); + should.exist(addr2); + addr2.address.should.equal(addr.address); + addr2.path.should.equal(addr.path); + done(); + }); + }); }); }); - }); - }); + }, + ); }); - }); - }); + }, + ); }); }); }); @@ -4196,10 +4728,10 @@ describe('client API', function() { it('should create wallet in proxy from airgapped', function(done) { var airgapped = new Client(); airgapped.seedFromRandom({ - network: 'testnet' + network: 'testnet', }); var exported = airgapped.export({ - noSign: true + noSign: true, }); var proxy = helpers.newClient(app); @@ -4207,26 +4739,33 @@ describe('client API', function() { should.not.exist(proxy.credentials.xPrivKey); var seedSpy = sinon.spy(proxy, 'seedFromRandom'); - proxy.createWallet('mywallet', 'creator', 1, 1, { - network: 'testnet', - beacon: 'code' - }, function(err) { - should.not.exist(err); - seedSpy.called.should.be.false; - proxy.getStatus({}, function(err, status) { + proxy.createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'testnet', + beacon: 'code', + }, + function(err) { should.not.exist(err); - status.wallet.name.should.equal('mywallet'); - done(); - }); - }); + seedSpy.called.should.be.false; + proxy.getStatus({}, function(err, status) { + should.not.exist(err); + status.wallet.name.should.equal('mywallet'); + done(); + }); + }, + ); }); it('should fail to create wallet in proxy from airgapped when networks do not match', function(done) { var airgapped = new Client(); airgapped.seedFromRandom({ - network: 'testnet' + network: 'testnet', }); var exported = airgapped.export({ - noSign: true + noSign: true, }); var proxy = helpers.newClient(app); @@ -4235,47 +4774,61 @@ describe('client API', function() { var seedSpy = sinon.spy(proxy, 'seedFromRandom'); should.not.exist(proxy.credentials.xPrivKey); - proxy.createWallet('mywallet', 'creator', 1, 1, { - network: 'livenet' - }, function(err) { - should.exist(err); - err.message.should.equal('Existing keys were created for a different network'); - done(); - }); + proxy.createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'livenet', + }, + function(err) { + should.exist(err); + err.message.should.equal('Existing keys were created for a different network'); + done(); + }, + ); }); it('should be able to sign from airgapped client and broadcast from proxy', function(done) { var airgapped = new Client(); airgapped.seedFromRandom({ - network: 'testnet' + network: 'testnet', }); var exported = airgapped.export({ - noSign: true + noSign: true, }); var proxy = helpers.newClient(app); proxy.import(exported); should.not.exist(proxy.credentials.xPrivKey); - async.waterfall([ - - function(next) { - proxy.createWallet('mywallet', 'creator', 1, 1, { - network: 'testnet', - beacon: 'code' - }, function(err) { - should.not.exist(err); - proxy.createAddress(function(err, address) { + async.waterfall( + [ + function(next) { + proxy.createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'testnet', + beacon: 'code', + }, + function(err) { should.not.exist(err); - should.exist(address.address); - blockchainExplorerMock.setUtxo(address, 1, 1); - var opts = { - amount: 1200000, - toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', - message: 'hello 1-1', - }; - helpers.createAndPublishTxProposal(proxy, opts, next); - }); - }); + proxy.createAddress(function(err, address) { + should.not.exist(err); + should.exist(address.address); + blockchainExplorerMock.setUtxo(address, 1, 1); + var opts = { + amount: 1200000, + toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', + message: 'hello 1-1', + }; + helpers.createAndPublishTxProposal(proxy, opts, next); + }); + }, + ); }, function(txp, next) { should.exist(txp); @@ -4287,12 +4840,20 @@ describe('client API', function() { }); }, function(txp, next) { - proxy.getTxProposals({ - forAirGapped: true - }, next); + proxy.getTxProposals( + { + forAirGapped: true, + }, + next, + ); }, function(bundle, next) { - var signatures = airgapped.signTxProposalFromAirGapped(bundle.txps[0], bundle.encryptedPkr, bundle.m, bundle.n); + var signatures = airgapped.signTxProposalFromAirGapped( + bundle.txps[0], + bundle.encryptedPkr, + bundle.m, + bundle.n, + ); next(null, signatures); }, function(signatures, next) { @@ -4300,26 +4861,30 @@ describe('client API', function() { should.not.exist(err); var txp = txps[0]; txp.signatures = signatures; - async.each(txps, function(txp, cb) { - proxy.signTxProposal(txp, function(err, txp) { - should.not.exist(err); - proxy.broadcastTxProposal(txp, function(err, txp) { + async.each( + txps, + function(txp, cb) { + proxy.signTxProposal(txp, function(err, txp) { should.not.exist(err); - txp.status.should.equal('broadcasted'); - should.exist(txp.txid); - cb(); + proxy.broadcastTxProposal(txp, function(err, txp) { + should.not.exist(err); + txp.status.should.equal('broadcasted'); + should.exist(txp.txid); + cb(); + }); }); - }); - }, function(err) { - next(err); - }); + }, + function(err) { + next(err); + }, + ); }); }, ], function(err) { should.not.exist(err); done(); - } + }, ); }); it('should be able to sign from airgapped client with mnemonics (with unencrypted xpubkey ring)', function(done) { @@ -4333,40 +4898,57 @@ describe('client API', function() { client.encryptPrivateKey('password'); client.isPrivKeyEncrypted().should.be.true; - async.waterfall([ - + async.waterfall( + [ function(next) { - client.createWallet('mywallet', 'creator', 1, 1, { - network: 'testnet', - beacon: 'code' - }, function(err) { - should.not.exist(err); - client.createAddress(function(err, address) { + client.createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'testnet', + beacon: 'code', + }, + function(err) { should.not.exist(err); - should.exist(address.address); - blockchainExplorerMock.setUtxo(address, 1, 1); - var opts = { - amount: 1200000, - toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', - message: 'hello 1-1', - }; - helpers.createAndPublishTxProposal(client, opts, next); - }); - }); + client.createAddress(function(err, address) { + should.not.exist(err); + should.exist(address.address); + blockchainExplorerMock.setUtxo(address, 1, 1); + var opts = { + amount: 1200000, + toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', + message: 'hello 1-1', + }; + helpers.createAndPublishTxProposal(client, opts, next); + }); + }, + ); }, function(txp, next) { should.exist(txp); - client.getTxProposals({ - forAirGapped: true, - doNotEncryptPkr: true, - }, next); + client.getTxProposals( + { + forAirGapped: true, + doNotEncryptPkr: true, + }, + next, + ); }, function(bundle, next) { - var signatures = Client.signTxProposalFromAirGapped(mnemonic, bundle.txps[0], bundle.unencryptedPkr, bundle.m, bundle.n, { - passphrase: 'passphrase', - account: 0, - derivationStrategy: 'BIP44' - }); + var signatures = Client.signTxProposalFromAirGapped( + mnemonic, + bundle.txps[0], + bundle.unencryptedPkr, + bundle.m, + bundle.n, + { + passphrase: 'passphrase', + account: 0, + derivationStrategy: 'BIP44', + }, + ); next(null, signatures); }, function(signatures, next) { @@ -4374,26 +4956,30 @@ describe('client API', function() { should.not.exist(err); var txp = txps[0]; txp.signatures = signatures; - async.each(txps, function(txp, cb) { - client.signTxProposal(txp, function(err, txp) { - should.not.exist(err); - client.broadcastTxProposal(txp, function(err, txp) { + async.each( + txps, + function(txp, cb) { + client.signTxProposal(txp, function(err, txp) { should.not.exist(err); - txp.status.should.equal('broadcasted'); - should.exist(txp.txid); - cb(); + client.broadcastTxProposal(txp, function(err, txp) { + should.not.exist(err); + txp.status.should.equal('broadcasted'); + should.exist(txp.txid); + cb(); + }); }); - }); - }, function(err) { - next(err); - }); + }, + function(err) { + next(err); + }, + ); }); }, ], function(err) { should.not.exist(err); done(); - } + }, ); }); describe('Failure and tampering', function() { @@ -4402,85 +4988,95 @@ describe('client API', function() { beforeEach(function(done) { airgapped = new Client(); airgapped.seedFromRandom({ - network: 'testnet' + network: 'testnet', }); var exported = airgapped.export({ - noSign: true + noSign: true, }); proxy = helpers.newClient(app); proxy.import(exported); should.not.exist(proxy.credentials.xPrivKey); - async.waterfall([ - + async.waterfall( + [ function(next) { - proxy.createWallet('mywallet', 'creator', 1, 1, { - network: 'testnet', - beacon: 'address' - }, function(err) { - should.not.exist(err); - proxy.createAddress(function(err, address) { + proxy.createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'testnet', + beacon: 'address', + }, + function(err) { should.not.exist(err); - should.exist(address.address); - blockchainExplorerMock.setUtxo(address, 1, 1); - var opts = { - amount: 1200000, - toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', - message: 'hello 1-1', - }; - helpers.createAndPublishTxProposal(proxy, opts, next); - }); - }); + proxy.createAddress(function(err, address) { + should.not.exist(err); + should.exist(address.address); + blockchainExplorerMock.setUtxo(address, 1, 1); + var opts = { + amount: 1200000, + toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', + message: 'hello 1-1', + }; + helpers.createAndPublishTxProposal(proxy, opts, next); + }); + }, + ); }, function(txp, next) { - proxy.getTxProposals({ - forAirGapped: true - }, function(err, result) { - should.not.exist(err); - bundle = result; - next(); - }); + proxy.getTxProposals( + { + forAirGapped: true, + }, + function(err, result) { + should.not.exist(err); + bundle = result; + next(); + }, + ); }, ], function(err) { should.not.exist(err); done(); - } + }, ); }); it('should fail to sign from airgapped client when there is no extended private key', function(done) { delete airgapped.credentials.xPrivKey; (function() { airgapped.signTxProposalFromAirGapped(bundle.txps[0], bundle.encryptedPkr, bundle.m, bundle.n); - }).should.throw('Missing private keys'); + }.should.throw('Missing private keys')); done(); }); it('should fail gracefully when PKR cannot be decrypted in airgapped client', function(done) { bundle.encryptedPkr = 'dummy'; (function() { airgapped.signTxProposalFromAirGapped(bundle.txps[0], bundle.encryptedPkr, bundle.m, bundle.n); - }).should.throw('Could not decrypt public key ring'); + }.should.throw('Could not decrypt public key ring')); done(); }); it('should be able to detect invalid or tampered PKR when signing on airgapped client', function(done) { (function() { airgapped.signTxProposalFromAirGapped(bundle.txps[0], bundle.encryptedPkr, bundle.m, 2); - }).should.throw('Invalid public key ring'); + }.should.throw('Invalid public key ring')); done(); }); it.skip('should be able to detect tampered proposal when signing on airgapped client', function(done) { bundle.txps[0].encryptedMessage = 'tampered message'; (function() { airgapped.signTxProposalFromAirGapped(bundle.txps[0], bundle.encryptedPkr, bundle.m, bundle.n); - }).should.throw('Fake transaction proposal'); + }.should.throw('Fake transaction proposal')); done(); }); it('should be able to detect tampered change address when signing on airgapped client', function(done) { bundle.txps[0].changeAddress.address = 'mqNkvNuhzZKeXYNRZ1bdj55smmW3acr6K7'; (function() { airgapped.signTxProposalFromAirGapped(bundle.txps[0], bundle.encryptedPkr, bundle.m, bundle.n); - }).should.throw('Fake transaction proposal'); + }.should.throw('Fake transaction proposal')); done(); }); }); @@ -4701,21 +5297,28 @@ describe('client API', function() { beforeEach(function(done) { c1 = clients[1]; clients[1].seedFromRandomWithMnemonic({ - network: 'testnet' - }); - clients[1].createWallet('mywallet', 'creator', 1, 1, { network: 'testnet', - beacon: 'address' - }, function() { - clients[1].encryptPrivateKey(password); - done(); }); + clients[1].createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'testnet', + beacon: 'address', + }, + function() { + clients[1].encryptPrivateKey(password); + done(); + }, + ); }); it('should fail to decrypt if not encrypted', function(done) { helpers.createAndJoinWallet(clients, 1, 1, function() { (function() { clients[0].decryptPrivateKey('wrong'); - }).should.throw('encrypted'); + }.should.throw('encrypted')); done(); }); }); @@ -4731,26 +5334,26 @@ describe('client API', function() { it('should prevent to reencrypt the priv key', function() { (function() { c1.encryptPrivateKey('pepe'); - }).should.throw('Private key already encrypted'); + }.should.throw('Private key already encrypted')); }); it('should allow to decrypt', function() { c1.decryptPrivateKey(password); c1.isPrivKeyEncrypted().should.be.false; }); - it('should prevent to encrypt airgapped\'s proxy credentials', function() { + it("should prevent to encrypt airgapped's proxy credentials", function() { var airgapped = new Client(); airgapped.seedFromRandom({ - network: 'testnet' + network: 'testnet', }); var exported = airgapped.export({ - noSign: true + noSign: true, }); var proxy = helpers.newClient(app); proxy.import(exported); should.not.exist(proxy.credentials.xPrivKey); (function() { proxy.encryptPrivateKey('pepe'); - }).should.throw('No private key'); + }.should.throw('No private key')); }); it('should not contain unencrypted fields when encrypted', function() { var keys = c1.getKeys(password); @@ -4763,15 +5366,15 @@ describe('client API', function() { var keys = c1.getKeys(password); (function() { c1.getMnemonic(); - }).should.throw('encrypted'); + }.should.throw('encrypted')); c1.decryptPrivateKey(password); c1.credentials.xPrivKey.should.equal(keys.xPrivKey); c1.getMnemonic().should.equal(keys.mnemonic); }); it('should fail to decrypt with wrong password', function() { (function() { - c1.decryptPrivateKey('wrong') - }).should.throw('Could not decrypt'); + c1.decryptPrivateKey('wrong'); + }.should.throw('Could not decrypt')); }); it('should export & import encrypted', function(done) { var walletId = c1.credentials.walletId; @@ -4901,61 +5504,70 @@ describe('client API', function() { it('should add access with copayer name', function(done) { var spy = sinon.spy(clients[0], '_doPutRequest'); - clients[0].addAccess({ - name: 'pepe', - }, function(err, x, key) { - should.not.exist(err); - var url = spy.getCall(0).args[0]; - var body = JSON.stringify(spy.getCall(0).args[1]); - url.should.contain('/copayers'); - body.should.not.contain('pepe'); - - var k = new Meritcore.PrivateKey(key); - var c = clients[0].credentials; - c.requestPrivKey = k.toString(); - c.requestPubKey = k.toPublicKey().toString(); - - clients[0].getStatus({}, function(err, status) { + clients[0].addAccess( + { + name: 'pepe', + }, + function(err, x, key) { should.not.exist(err); - var keys = status.wallet.copayers[0].requestPubKeys; - keys.length.should.equal(2); - _.filter(keys, { - name: 'pepe' - }).length.should.equal(1); + var url = spy.getCall(0).args[0]; + var body = JSON.stringify(spy.getCall(0).args[1]); + url.should.contain('/copayers'); + body.should.not.contain('pepe'); - helpers.createAndPublishTxProposal(clients[0], opts, function(err, x) { + var k = new Meritcore.PrivateKey(key); + var c = clients[0].credentials; + c.requestPrivKey = k.toString(); + c.requestPubKey = k.toPublicKey().toString(); + + clients[0].getStatus({}, function(err, status) { should.not.exist(err); - // TODO: verify tx's creator is 'pepe' - done(); + var keys = status.wallet.copayers[0].requestPubKeys; + keys.length.should.equal(2); + _.filter(keys, { + name: 'pepe', + }).length.should.equal(1); + + helpers.createAndPublishTxProposal(clients[0], opts, function(err, x) { + should.not.exist(err); + // TODO: verify tx's creator is 'pepe' + done(); + }); }); - }); - }); + }, + ); }); it('should grant access with *new* keys then deny access with old keys', function(done) { - clients[0].addAccess({ - generateNewKey: true - }, function(err, x) { - helpers.createAndPublishTxProposal(clients[0], opts, function(err, x) { - err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); - done(); - }); - }); + clients[0].addAccess( + { + generateNewKey: true, + }, + function(err, x) { + helpers.createAndPublishTxProposal(clients[0], opts, function(err, x) { + err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); + done(); + }); + }, + ); }); it('should grant access with new keys', function(done) { - clients[0].addAccess({ - generateNewKey: true - }, function(err, x, key) { - var k = new Meritcore.PrivateKey(key); - var c = clients[0].credentials; - c.requestPrivKey = k.toString(); - c.requestPubKey = k.toPublicKey().toString(); - helpers.createAndPublishTxProposal(clients[0], opts, function(err, x) { - should.not.exist(err); - done(); - }); - }); + clients[0].addAccess( + { + generateNewKey: true, + }, + function(err, x, key) { + var k = new Meritcore.PrivateKey(key); + var c = clients[0].credentials; + c.requestPrivKey = k.toString(); + c.requestPubKey = k.toPublicKey().toString(); + helpers.createAndPublishTxProposal(clients[0], opts, function(err, x) { + should.not.exist(err); + done(); + }); + }, + ); }); it('should verify tx proposals of added access', function(done) { @@ -4970,19 +5582,26 @@ describe('client API', function() { }); }); - it('should detect tampered tx proposals of added access (case 1)', function(done) { clients[0].addAccess({}, function(err, x) { helpers.createAndPublishTxProposal(clients[0], opts, function(err, x) { should.not.exist(err); - helpers.tamperResponse(clients[0], 'get', '/v1/txproposals/', {}, function(txps) { - txps[0].proposalSignature = '304402206e4a1db06e00068582d3be41cfc795dcf702451c132581e661e7241ef34ca19202203e17598b4764913309897d56446b51bc1dcd41a25d90fdb5f87a6b58fe3a6920'; - }, function() { - clients[0].getTxProposals({}, function(err, txps) { - err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); - done(); - }); - }); + helpers.tamperResponse( + clients[0], + 'get', + '/v1/txproposals/', + {}, + function(txps) { + txps[0].proposalSignature = + '304402206e4a1db06e00068582d3be41cfc795dcf702451c132581e661e7241ef34ca19202203e17598b4764913309897d56446b51bc1dcd41a25d90fdb5f87a6b58fe3a6920'; + }, + function() { + clients[0].getTxProposals({}, function(err, txps) { + err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); + done(); + }); + }, + ); }); }); }); @@ -4991,31 +5610,45 @@ describe('client API', function() { clients[0].addAccess({}, function(err, x) { helpers.createAndPublishTxProposal(clients[0], opts, function(err, x) { should.not.exist(err); - helpers.tamperResponse(clients[0], 'get', '/v1/txproposals/', {}, function(txps) { - txps[0].proposalSignaturePubKey = '02d368d7f03a57b2ad3ad9c2766739da83b85ab9c3718fb02ad36574f9391d6bf6'; - }, function() { - clients[0].getTxProposals({}, function(err, txps) { - err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); - done(); - }); - }); + helpers.tamperResponse( + clients[0], + 'get', + '/v1/txproposals/', + {}, + function(txps) { + txps[0].proposalSignaturePubKey = '02d368d7f03a57b2ad3ad9c2766739da83b85ab9c3718fb02ad36574f9391d6bf6'; + }, + function() { + clients[0].getTxProposals({}, function(err, txps) { + err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); + done(); + }); + }, + ); }); }); }); - it('should detect tampered tx proposals of added access (case 3)', function(done) { clients[0].addAccess({}, function(err, x) { helpers.createAndPublishTxProposal(clients[0], opts, function(err, x) { should.not.exist(err); - helpers.tamperResponse(clients[0], 'get', '/v1/txproposals/', {}, function(txps) { - txps[0].proposalSignaturePubKeySig = '304402201528748eafc5083fe67c84cbf0eb996eba9a65584a73d8c07ed6e0dc490c195802204f340488266c804cf1033f8b852efd1d4e05d862707c119002dc3fbe7a805c35'; - }, function() { - clients[0].getTxProposals({}, function(err, txps) { - err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); - done(); - }); - }); + helpers.tamperResponse( + clients[0], + 'get', + '/v1/txproposals/', + {}, + function(txps) { + txps[0].proposalSignaturePubKeySig = + '304402201528748eafc5083fe67c84cbf0eb996eba9a65584a73d8c07ed6e0dc490c195802204f340488266c804cf1033f8b852efd1d4e05d862707c119002dc3fbe7a805c35'; + }, + function() { + clients[0].getTxProposals({}, function(err, txps) { + err.should.be.an.instanceOf(Errors.SERVER_COMPROMISED); + done(); + }); + }, + ); }); }); }); @@ -5025,19 +5658,29 @@ describe('client API', function() { describe('Sweep paper wallet', function() { it.skip('should decrypt bip38 encrypted private key', function(done) { this.timeout(60000); - clients[0].decryptBIP38PrivateKey('6PfRh9ZnWtiHrGoPPSzXe6iafTXc6FSXDhSBuDvvDmGd1kpX2Gvy1CfTcA', 'passphrase', {}, function(err, result) { - should.not.exist(err); - result.should.equal('5KjBgBiadWGhjWmLN1v4kcEZqWSZFqzgv7cSUuZNJg4tD82c4xp'); - done(); - }); + clients[0].decryptBIP38PrivateKey( + '6PfRh9ZnWtiHrGoPPSzXe6iafTXc6FSXDhSBuDvvDmGd1kpX2Gvy1CfTcA', + 'passphrase', + {}, + function(err, result) { + should.not.exist(err); + result.should.equal('5KjBgBiadWGhjWmLN1v4kcEZqWSZFqzgv7cSUuZNJg4tD82c4xp'); + done(); + }, + ); }); it.skip('should fail to decrypt bip38 encrypted private key with incorrect passphrase', function(done) { this.timeout(60000); - clients[0].decryptBIP38PrivateKey('6PfRh9ZnWtiHrGoPPSzXe6iafTXc6FSXDhSBuDvvDmGd1kpX2Gvy1CfTcA', 'incorrect passphrase', {}, function(err, result) { - should.exist(err); - err.message.should.contain('passphrase'); - done(); - }); + clients[0].decryptBIP38PrivateKey( + '6PfRh9ZnWtiHrGoPPSzXe6iafTXc6FSXDhSBuDvvDmGd1kpX2Gvy1CfTcA', + 'incorrect passphrase', + {}, + function(err, result) { + should.exist(err); + err.message.should.contain('passphrase'); + done(); + }, + ); }); it('should get balance from single private key', function(done) { var address = { @@ -5046,7 +5689,10 @@ describe('client API', function() { }; helpers.createAndJoinWallet(clients, 1, 1, function() { blockchainExplorerMock.setUtxo(address, 123, 1); - clients[0].getBalanceFromPrivateKey('5KjBgBiadWGhjWmLN1v4kcEZqWSZFqzgv7cSUuZNJg4tD82c4xp', function(err, balance) { + clients[0].getBalanceFromPrivateKey('5KjBgBiadWGhjWmLN1v4kcEZqWSZFqzgv7cSUuZNJg4tD82c4xp', function( + err, + balance, + ) { should.not.exist(err); balance.should.equal(123 * 1e8); done(); @@ -5060,16 +5706,23 @@ describe('client API', function() { }; helpers.createAndJoinWallet(clients, 1, 1, function() { blockchainExplorerMock.setUtxo(address, 123, 1); - clients[0].buildTxFromPrivateKey('5KjBgBiadWGhjWmLN1v4kcEZqWSZFqzgv7cSUuZNJg4tD82c4xp', '1GG3JQikGC7wxstyavUBDoCJ66bWLLENZC', {}, function(err, tx) { - should.not.exist(err); - should.exist(tx); - tx.outputs.length.should.equal(1); - var output = tx.outputs[0]; - output.micros.should.equal(123 * 1e8 - 10000); - var script = new Meritcore.Script.buildPublicKeyHashOut(Meritcore.Address.fromString('1GG3JQikGC7wxstyavUBDoCJ66bWLLENZC')); - output.script.toString('hex').should.equal(script.toString('hex')); - done(); - }); + clients[0].buildTxFromPrivateKey( + '5KjBgBiadWGhjWmLN1v4kcEZqWSZFqzgv7cSUuZNJg4tD82c4xp', + '1GG3JQikGC7wxstyavUBDoCJ66bWLLENZC', + {}, + function(err, tx) { + should.not.exist(err); + should.exist(tx); + tx.outputs.length.should.equal(1); + var output = tx.outputs[0]; + output.micros.should.equal(123 * 1e8 - 10000); + var script = new Meritcore.Script.buildPublicKeyHashOut( + Meritcore.Address.fromString('1GG3JQikGC7wxstyavUBDoCJ66bWLLENZC'), + ); + output.script.toString('hex').should.equal(script.toString('hex')); + done(); + }, + ); }); }); @@ -5086,13 +5739,18 @@ describe('client API', function() { }; helpers.createAndJoinWallet(clients, 1, 1, function() { blockchainExplorerMock.setUtxo(address, 123, 1); - clients[0].buildTxFromPrivateKey('5KjBgBiadWGhjWmLN1v4kcEZqWSZFqzgv7cSUuZNJg4tD82c4xp', '1GG3JQikGC7wxstyavUBDoCJ66bWLLENZC', {}, function(err, tx) { - should.exist(err); - should.not.exist(tx); - err.should.be.an.instanceOf(Errors.COULD_NOT_BUILD_TRANSACTION); - sandbox.restore(); - done(); - }); + clients[0].buildTxFromPrivateKey( + '5KjBgBiadWGhjWmLN1v4kcEZqWSZFqzgv7cSUuZNJg4tD82c4xp', + '1GG3JQikGC7wxstyavUBDoCJ66bWLLENZC', + {}, + function(err, tx) { + should.exist(err); + should.not.exist(tx); + err.should.be.an.instanceOf(Errors.COULD_NOT_BUILD_TRANSACTION); + sandbox.restore(); + done(); + }, + ); }); }); @@ -5103,42 +5761,65 @@ describe('client API', function() { }; helpers.createAndJoinWallet(clients, 1, 1, function() { blockchainExplorerMock.setUtxo(address, 123 / 1e8, 1); - clients[0].buildTxFromPrivateKey('5KjBgBiadWGhjWmLN1v4kcEZqWSZFqzgv7cSUuZNJg4tD82c4xp', '1GG3JQikGC7wxstyavUBDoCJ66bWLLENZC', { - fee: 500 - }, function(err, tx) { - should.exist(err); - err.should.be.an.instanceOf(Errors.INSUFFICIENT_FUNDS); - done(); - }); + clients[0].buildTxFromPrivateKey( + '5KjBgBiadWGhjWmLN1v4kcEZqWSZFqzgv7cSUuZNJg4tD82c4xp', + '1GG3JQikGC7wxstyavUBDoCJ66bWLLENZC', + { + fee: 500, + }, + function(err, tx) { + should.exist(err); + err.should.be.an.instanceOf(Errors.INSUFFICIENT_FUNDS); + done(); + }, + ); }); }); }); describe('#formatAmount', function() { it('should successfully format amount', function() { - var cases = [{ - args: [1, 'bit'], - expected: '0', - }, { - args: [1, 'bit', { - fullPrecision: true - }], - expected: '0.01', - }, { - args: [1, 'mrt'], - expected: '0.00', - }, { - args: [1, 'mrt', { - fullPrecision: true - }], - expected: '0.00000001', - }, { - args: [1234567899999, 'mrt', { - thousandsSeparator: ' ', - decimalSeparator: ',' - }], - expected: '12 345,678999', - }, ]; + var cases = [ + { + args: [1, 'bit'], + expected: '0', + }, + { + args: [ + 1, + 'bit', + { + fullPrecision: true, + }, + ], + expected: '0.01', + }, + { + args: [1, 'mrt'], + expected: '0.00', + }, + { + args: [ + 1, + 'mrt', + { + fullPrecision: true, + }, + ], + expected: '0.00000001', + }, + { + args: [ + 1234567899999, + 'mrt', + { + thousandsSeparator: ' ', + decimalSeparator: ',', + }, + ], + expected: '12 345,678999', + }, + ]; _.each(cases, function(testCase) { Utils.formatAmount.apply(this, testCase.args).should.equal(testCase.expected); @@ -5154,11 +5835,11 @@ describe('client API', function() { var client = new Client(); var _f = sandbox.stub(client, '_fetchLatestNotifications', function(interval, cb) { - cb(new Errors.NOT_FOUND); + cb(new Errors.NOT_FOUND()); }); client._initNotifications({ - notificationIntervalSeconds: 1 + notificationIntervalSeconds: 1, }); should.exist(client.notificationsIntervalId); clock.tick(1000); @@ -5174,11 +5855,11 @@ describe('client API', function() { var client = new Client(); var _f = sandbox.stub(client, '_fetchLatestNotifications', function(interval, cb) { - cb(new Errors.NOT_AUTHORIZED); + cb(new Errors.NOT_AUTHORIZED()); }); client._initNotifications({ - notificationIntervalSeconds: 1 + notificationIntervalSeconds: 1, }); should.exist(client.notificationsIntervalId); clock.tick(1000); @@ -5189,14 +5870,13 @@ describe('client API', function() { }); describe('Import', function() { - describe('#import', function(done) { it('should handle import with invalid JSON', function(done) { var importString = 'this is not valid JSON'; var client = new Client(); (function() { client.import(importString); - }).should.throw(Errors.INVALID_BACKUP); + }.should.throw(Errors.INVALID_BACKUP)); done(); }); }); @@ -5266,35 +5946,55 @@ describe('client API', function() { it('should import with external priv key', function(done) { var client = helpers.newClient(app); - client.seedFromExtendedPublicKey('xpub661MyMwAqRbcGVyYUcHbZi9KNhN9Tdj8qHi9ZdoUXP1VeKiXDGGrE9tSoJKYhGFE2rimteYdwvoP6e87zS5LsgcEvsvdrpPBEmeWz9EeAUq', 'ledger', '1a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f00'); - client.createWallet('mywallet', 'creator', 1, 1, { - network: 'livenet', - beacon: 'address' - }, function(err) { - should.not.exist(err); - var c = client.credentials; - var importedClient = helpers.newClient(app); - importedClient.importFromExtendedPublicKey('xpub661MyMwAqRbcGVyYUcHbZi9KNhN9Tdj8qHi9ZdoUXP1VeKiXDGGrE9tSoJKYhGFE2rimteYdwvoP6e87zS5LsgcEvsvdrpPBEmeWz9EeAUq', 'ledger', '1a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f00', {}, function(err) { + client.seedFromExtendedPublicKey( + 'xpub661MyMwAqRbcGVyYUcHbZi9KNhN9Tdj8qHi9ZdoUXP1VeKiXDGGrE9tSoJKYhGFE2rimteYdwvoP6e87zS5LsgcEvsvdrpPBEmeWz9EeAUq', + 'ledger', + '1a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f00', + ); + client.createWallet( + 'mywallet', + 'creator', + 1, + 1, + { + network: 'livenet', + beacon: 'address', + }, + function(err) { should.not.exist(err); - var c2 = importedClient.credentials; - c2.account.should.equal(0); - c2.xPubKey.should.equal(client.credentials.xPubKey); - c2.personalEncryptingKey.should.equal(c.personalEncryptingKey); - c2.walletId.should.equal(c.walletId); - c2.walletName.should.equal(c.walletName); - c2.copayerName.should.equal(c.copayerName); - done(); - }); - }); + var c = client.credentials; + var importedClient = helpers.newClient(app); + importedClient.importFromExtendedPublicKey( + 'xpub661MyMwAqRbcGVyYUcHbZi9KNhN9Tdj8qHi9ZdoUXP1VeKiXDGGrE9tSoJKYhGFE2rimteYdwvoP6e87zS5LsgcEvsvdrpPBEmeWz9EeAUq', + 'ledger', + '1a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f001a1f00', + {}, + function(err) { + should.not.exist(err); + var c2 = importedClient.credentials; + c2.account.should.equal(0); + c2.xPubKey.should.equal(client.credentials.xPubKey); + c2.personalEncryptingKey.should.equal(c.personalEncryptingKey); + c2.walletId.should.equal(c.walletId); + c2.walletName.should.equal(c.walletName); + c2.copayerName.should.equal(c.copayerName); + done(); + }, + ); + }, + ); }); it('should fail to import with external priv key when not enought entropy', function() { var client = helpers.newClient(app); (function() { - client.seedFromExtendedPublicKey('xpub661MyMwAqRbcGVyYUcHbZi9KNhN9Tdj8qHi9ZdoUXP1VeKiXDGGrE9tSoJKYhGFE2rimteYdwvoP6e87zS5LsgcEvsvdrpPBEmeWz9EeAUq', 'ledger', '1a1f00'); - }).should.throw('entropy'); + client.seedFromExtendedPublicKey( + 'xpub661MyMwAqRbcGVyYUcHbZi9KNhN9Tdj8qHi9ZdoUXP1VeKiXDGGrE9tSoJKYhGFE2rimteYdwvoP6e87zS5LsgcEvsvdrpPBEmeWz9EeAUq', + 'ledger', + '1a1f00', + ); + }.should.throw('entropy')); }); - }); describe('_doRequest', function() { @@ -5330,11 +6030,17 @@ describe('client API', function() { describe('Single-address wallets', function() { beforeEach(function(done) { - helpers.createAndJoinWallet(clients, 1, 2, { - singleAddress: true - }, function(wallet) { - done(); - }); + helpers.createAndJoinWallet( + clients, + 1, + 2, + { + singleAddress: true, + }, + function(wallet) { + done(); + }, + ); }); it('should always return same address', function(done) { clients[0].createAddress(function(err, x) { @@ -5368,10 +6074,12 @@ describe('client API', function() { var toAddress = 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5'; var opts = { - outputs: [{ - amount: 1e8, - toAddress: toAddress, - }], + outputs: [ + { + amount: 1e8, + toAddress: toAddress, + }, + ], feePerKb: 100e2, }; clients[0].createTxProposal(opts, function(err, txp) { diff --git a/packages/lightwallet/common/merit-wallet-client/test/credentials.js b/packages/lightwallet/common/merit-wallet-client/test/credentials.js index dc5b59d449..2e3ab4e7b0 100644 --- a/packages/lightwallet/common/merit-wallet-client/test/credentials.js +++ b/packages/lightwallet/common/merit-wallet-client/test/credentials.js @@ -10,7 +10,6 @@ var Credentials = require('../lib/credentials'); var TestData = require('./testdata'); describe('Credentials', function() { - describe('#create', function() { it('Should create', function() { var c = Credentials.create('livenet'); @@ -51,166 +50,274 @@ describe('Credentials', function() { describe('#getDerivedXPrivKey', function() { it('should derive extended private key from master livenet', function() { - var c = Credentials.fromExtendedPrivateKey('xprv9s21ZrQH143K3zLpjtB4J4yrRfDTEfbrMa9vLZaTAv5BzASwBmA16mdBmZKpMLssw1AzTnm31HAD2pk2bsnZ9dccxaLD48mRdhtw82XoiBi', 0, 'BIP44'); + var c = Credentials.fromExtendedPrivateKey( + 'xprv9s21ZrQH143K3zLpjtB4J4yrRfDTEfbrMa9vLZaTAv5BzASwBmA16mdBmZKpMLssw1AzTnm31HAD2pk2bsnZ9dccxaLD48mRdhtw82XoiBi', + 0, + 'BIP44', + ); var xpk = c.getDerivedXPrivKey().toString(); - xpk.should.equal('xprv9xud2WztGSSBPDPDL9RQ3rG3vucRA4BmEnfAdP76bTqtkGCK8VzWjevLw9LsdqwH1PEWiwcjymf1T2FLp12XjwjuCRvcSBJvxDgv1BDTbWY'); + xpk.should.equal( + 'xprv9xud2WztGSSBPDPDL9RQ3rG3vucRA4BmEnfAdP76bTqtkGCK8VzWjevLw9LsdqwH1PEWiwcjymf1T2FLp12XjwjuCRvcSBJvxDgv1BDTbWY', + ); }); it('should derive extended private key from master testnet', function() { - var c = Credentials.fromExtendedPrivateKey('tprv8ZgxMBicQKsPfPX8avSJXY1tZYJJESNg8vR88i8rJFkQJm6HgPPtDEmD36NLVSJWV5ieejVCK62NdggXmfMEHog598PxvXuLEsWgE6tKdwz', 0, 'BIP44'); + var c = Credentials.fromExtendedPrivateKey( + 'tprv8ZgxMBicQKsPfPX8avSJXY1tZYJJESNg8vR88i8rJFkQJm6HgPPtDEmD36NLVSJWV5ieejVCK62NdggXmfMEHog598PxvXuLEsWgE6tKdwz', + 0, + 'BIP44', + ); var xpk = c.getDerivedXPrivKey().toString(); - xpk.should.equal('tprv8gBu8N7JbHZs7MsW4kgE8LAYMhGJES9JP6DHsj2gw9Tc5PrF5Grr9ynAZkH1LyWsxjaAyCuEMFKTKhzdSaykpqzUnmEhpLsxfujWHA66N93'); + xpk.should.equal( + 'tprv8gBu8N7JbHZs7MsW4kgE8LAYMhGJES9JP6DHsj2gw9Tc5PrF5Grr9ynAZkH1LyWsxjaAyCuEMFKTKhzdSaykpqzUnmEhpLsxfujWHA66N93', + ); }); it('should derive extended private key from master BIP48 livenet', function() { - var c = Credentials.fromExtendedPrivateKey('xprv9s21ZrQH143K3zLpjtB4J4yrRfDTEfbrMa9vLZaTAv5BzASwBmA16mdBmZKpMLssw1AzTnm31HAD2pk2bsnZ9dccxaLD48mRdhtw82XoiBi', 0, 'BIP48'); + var c = Credentials.fromExtendedPrivateKey( + 'xprv9s21ZrQH143K3zLpjtB4J4yrRfDTEfbrMa9vLZaTAv5BzASwBmA16mdBmZKpMLssw1AzTnm31HAD2pk2bsnZ9dccxaLD48mRdhtw82XoiBi', + 0, + 'BIP48', + ); var xpk = c.getDerivedXPrivKey().toString(); - xpk.should.equal('xprv9yaGCLKPS2ovEGw987MZr4DCkfZHGh518ndVk3Jb6eiUdPwCQu7nYru59WoNkTEQvmhnv5sPbYxeuee5k8QASWRnGV2iFX4RmKXEQse8KnQ'); + xpk.should.equal( + 'xprv9yaGCLKPS2ovEGw987MZr4DCkfZHGh518ndVk3Jb6eiUdPwCQu7nYru59WoNkTEQvmhnv5sPbYxeuee5k8QASWRnGV2iFX4RmKXEQse8KnQ', + ); }); it('should derive extended private key from master livenet (BIP45)', function() { - var c = Credentials.fromExtendedPrivateKey('xprv9s21ZrQH143K3zLpjtB4J4yrRfDTEfbrMa9vLZaTAv5BzASwBmA16mdBmZKpMLssw1AzTnm31HAD2pk2bsnZ9dccxaLD48mRdhtw82XoiBi', 0, 'BIP45'); + var c = Credentials.fromExtendedPrivateKey( + 'xprv9s21ZrQH143K3zLpjtB4J4yrRfDTEfbrMa9vLZaTAv5BzASwBmA16mdBmZKpMLssw1AzTnm31HAD2pk2bsnZ9dccxaLD48mRdhtw82XoiBi', + 0, + 'BIP45', + ); var xpk = c.getDerivedXPrivKey().toString(); - xpk.should.equal('xprv9vDaAbbvT8LHKr8v5A2JeFJrnbQk6ZrMDGWuiv2vZgSyugeV4RE7Z9QjBNYsdafdhwEGb6Y48DRrXFVKvYRAub9ExzcmJHt6Js6ybJCSssm'); + xpk.should.equal( + 'xprv9vDaAbbvT8LHKr8v5A2JeFJrnbQk6ZrMDGWuiv2vZgSyugeV4RE7Z9QjBNYsdafdhwEGb6Y48DRrXFVKvYRAub9ExzcmJHt6Js6ybJCSssm', + ); }); it('should set addressType & BIP45', function() { - var c = Credentials.fromExtendedPrivateKey('xprv9s21ZrQH143K3zLpjtB4J4yrRfDTEfbrMa9vLZaTAv5BzASwBmA16mdBmZKpMLssw1AzTnm31HAD2pk2bsnZ9dccxaLD48mRdhtw82XoiBi', 8, 'BIP45'); + var c = Credentials.fromExtendedPrivateKey( + 'xprv9s21ZrQH143K3zLpjtB4J4yrRfDTEfbrMa9vLZaTAv5BzASwBmA16mdBmZKpMLssw1AzTnm31HAD2pk2bsnZ9dccxaLD48mRdhtw82XoiBi', + 8, + 'BIP45', + ); c.addWalletInfo(1, 'name', 1, 1, 'juan'); c.account.should.equal(8); }); it('should derive compliant child', function() { - var c = Credentials.fromExtendedPrivateKey('tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k', 0, 'BIP44'); + var c = Credentials.fromExtendedPrivateKey( + 'tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k', + 0, + 'BIP44', + ); c.compliantDerivation.should.be.true; var xpk = c.getDerivedXPrivKey().toString(); - xpk.should.equal('tprv8gXvQvjGt7oYCTRD3d4oeQr9B7JLuC2B6S854F4XWCQ4pr9NcjokH9kouWMAp1MJKy4Y8QLBgbmPtk3i7RegVzaWhWsnVPi4ZmykJXt4HeV'); + xpk.should.equal( + 'tprv8gXvQvjGt7oYCTRD3d4oeQr9B7JLuC2B6S854F4XWCQ4pr9NcjokH9kouWMAp1MJKy4Y8QLBgbmPtk3i7RegVzaWhWsnVPi4ZmykJXt4HeV', + ); }); it('should derive non-compliant child', function() { - var c = Credentials.fromExtendedPrivateKey('tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k', 0, 'BIP44', { - nonCompliantDerivation: true - }); + var c = Credentials.fromExtendedPrivateKey( + 'tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k', + 0, + 'BIP44', + { + nonCompliantDerivation: true, + }, + ); c.compliantDerivation.should.be.false; var xpk = c.getDerivedXPrivKey().toString(); - xpk.should.equal('tprv8gSy16H5hQ1MKNHzZDzsktr4aaGQSHg4XYVEbfsEiGSBcgw4J8dEm8uf19FH4L9h6W47VBKtc3bbYyjb6HAm6QdyRLpB6fsA7bW19RZnby2'); + xpk.should.equal( + 'tprv8gSy16H5hQ1MKNHzZDzsktr4aaGQSHg4XYVEbfsEiGSBcgw4J8dEm8uf19FH4L9h6W47VBKtc3bbYyjb6HAm6QdyRLpB6fsA7bW19RZnby2', + ); }); }); describe('#fromExtendedPrivateKey', function() { it('Should create credentials from seed', function() { - var xPriv = 'xprv9s21ZrQH143K2TjT3rF4m5AJcMvCetfQbVjFEx1Rped8qzcMJwbqxv21k3ftL69z7n3gqvvHthkdzbW14gxEFDYQdrRQMub3XdkJyt3GGGc'; + var xPriv = + 'xprv9s21ZrQH143K2TjT3rF4m5AJcMvCetfQbVjFEx1Rped8qzcMJwbqxv21k3ftL69z7n3gqvvHthkdzbW14gxEFDYQdrRQMub3XdkJyt3GGGc'; var c = Credentials.fromExtendedPrivateKey(xPriv, 0, 'BIP44'); - c.xPrivKey.should.equal('xprv9s21ZrQH143K2TjT3rF4m5AJcMvCetfQbVjFEx1Rped8qzcMJwbqxv21k3ftL69z7n3gqvvHthkdzbW14gxEFDYQdrRQMub3XdkJyt3GGGc'); - c.xPubKey.should.equal('xpub6DUean44k773kxbUq8QpSmAPFaNCpk5AzrxbFRAMsNCZBGD15XQVnRJCgNd8GtJVmDyDZh89NPZz1XPQeX5w6bAdLGfSTUuPDEQwBgKxfh1'); + c.xPrivKey.should.equal( + 'xprv9s21ZrQH143K2TjT3rF4m5AJcMvCetfQbVjFEx1Rped8qzcMJwbqxv21k3ftL69z7n3gqvvHthkdzbW14gxEFDYQdrRQMub3XdkJyt3GGGc', + ); + c.xPubKey.should.equal( + 'xpub6DUean44k773kxbUq8QpSmAPFaNCpk5AzrxbFRAMsNCZBGD15XQVnRJCgNd8GtJVmDyDZh89NPZz1XPQeX5w6bAdLGfSTUuPDEQwBgKxfh1', + ); c.copayerId.should.equal('bad66ef88ad8dec08e36d576c29b4f091d30197f04e166871e64bf969d08a958'); c.network.should.equal('livenet'); c.personalEncryptingKey.should.equal('M4MTmfRZaTtX6izAAxTpJg=='); }); describe('Compliant derivation', function() { it('Should create compliant base address derivation key', function() { - var xPriv = 'xprv9s21ZrQH143K4HHBKb6APEoa5i58fxeFWP1x5AGMfr6zXB3A6Hjt7f9LrPXp9P7CiTCA3Hk66cS4g8enUHWpYHpNhtufxSrSpcbaQyVX163'; + var xPriv = + 'xprv9s21ZrQH143K4HHBKb6APEoa5i58fxeFWP1x5AGMfr6zXB3A6Hjt7f9LrPXp9P7CiTCA3Hk66cS4g8enUHWpYHpNhtufxSrSpcbaQyVX163'; var c = Credentials.fromExtendedPrivateKey(xPriv, 0, 'BIP44'); - c.xPubKey.should.equal('xpub6CUtFEwZKBEyX6xF4ECdJdfRBBo69ufVgmRpy7oqzWJBSadSZ3vaqvCPNFsarga4UWcgTuoDQL7ZnpgWkUVUAX3oc7ej8qfLEuhMALGvFwX'); + c.xPubKey.should.equal( + 'xpub6CUtFEwZKBEyX6xF4ECdJdfRBBo69ufVgmRpy7oqzWJBSadSZ3vaqvCPNFsarga4UWcgTuoDQL7ZnpgWkUVUAX3oc7ej8qfLEuhMALGvFwX', + ); }); it('Should create compliant request key', function() { - var xPriv = 'xprv9s21ZrQH143K3xMCR1BNaUrTuh1XJnsj8KjEL5VpQty3NY8ufgbR8SjZS8B4offHq6Jj5WhgFpM2dcYxeqLLCuj1wgMnSfmZuPUtGk8rWT7'; + var xPriv = + 'xprv9s21ZrQH143K3xMCR1BNaUrTuh1XJnsj8KjEL5VpQty3NY8ufgbR8SjZS8B4offHq6Jj5WhgFpM2dcYxeqLLCuj1wgMnSfmZuPUtGk8rWT7'; var c = Credentials.fromExtendedPrivateKey(xPriv, 0, 'BIP44'); c.requestPrivKey.should.equal('559371263eb0b2fd9cd2aa773ca5fea69ed1f9d9bdb8a094db321f02e9d53cec'); }); it('should accept non-compliant derivation as a parameter when importing', function() { - var c = Credentials.fromExtendedPrivateKey('tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k', 0, 'BIP44', { - nonCompliantDerivation: true - }); - c.xPrivKey.should.equal('tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k'); + var c = Credentials.fromExtendedPrivateKey( + 'tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k', + 0, + 'BIP44', + { + nonCompliantDerivation: true, + }, + ); + c.xPrivKey.should.equal( + 'tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k', + ); c.compliantDerivation.should.be.false; - c.xPubKey.should.equal('tpubDD919WKKqmh2CqKnSsfUAJWB9bnLbcry6r61tBuY8YEaTBBpvXSpwdXXBGAB1n4JRFDC7ebo7if3psUAMpvQJUBe3LcjuMNA6Y4nP8U9SNg'); - c.getDerivedXPrivKey().toString().should.equal("tprv8gSy16H5hQ1MKNHzZDzsktr4aaGQSHg4XYVEbfsEiGSBcgw4J8dEm8uf19FH4L9h6W47VBKtc3bbYyjb6HAm6QdyRLpB6fsA7bW19RZnby2"); + c.xPubKey.should.equal( + 'tpubDD919WKKqmh2CqKnSsfUAJWB9bnLbcry6r61tBuY8YEaTBBpvXSpwdXXBGAB1n4JRFDC7ebo7if3psUAMpvQJUBe3LcjuMNA6Y4nP8U9SNg', + ); + c.getDerivedXPrivKey() + .toString() + .should.equal( + 'tprv8gSy16H5hQ1MKNHzZDzsktr4aaGQSHg4XYVEbfsEiGSBcgw4J8dEm8uf19FH4L9h6W47VBKtc3bbYyjb6HAm6QdyRLpB6fsA7bW19RZnby2', + ); }); }); }); describe('#fromMnemonic', function() { it('Should create credentials from mnemonic BIP44', function() { - var words = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; + var words = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; var c = Credentials.fromMnemonic('livenet', words, '', 0, 'BIP44'); - c.xPrivKey.should.equal('xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu'); + c.xPrivKey.should.equal( + 'xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu', + ); c.network.should.equal('livenet'); c.account.should.equal(0); c.derivationStrategy.should.equal('BIP44'); - c.xPubKey.should.equal('xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj'); + c.xPubKey.should.equal( + 'xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj', + ); c.getBaseAddressDerivationPath().should.equal("m/44'/0'/0'"); }); it('Should create credentials from mnemonic BIP48', function() { - var words = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; + var words = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; var c = Credentials.fromMnemonic('livenet', words, '', 0, 'BIP48'); - c.xPrivKey.should.equal('xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu'); + c.xPrivKey.should.equal( + 'xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu', + ); c.network.should.equal('livenet'); c.account.should.equal(0); c.derivationStrategy.should.equal('BIP48'); - c.xPubKey.should.equal('xpub6CKZtUaK1YHpQbg6CLaGRmsMKLQB1iKzsvmxtyHD6X7gzLqCB2VNZYd1XCxrccQnE8hhDxtYbR1Sakkvisy2J4CcTxWeeGjmkasCoNS9vZm'); + c.xPubKey.should.equal( + 'xpub6CKZtUaK1YHpQbg6CLaGRmsMKLQB1iKzsvmxtyHD6X7gzLqCB2VNZYd1XCxrccQnE8hhDxtYbR1Sakkvisy2J4CcTxWeeGjmkasCoNS9vZm', + ); c.getBaseAddressDerivationPath().should.equal("m/48'/0'/0'"); }); it('Should create credentials from mnemonic account 1', function() { - var words = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; + var words = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; var c = Credentials.fromMnemonic('livenet', words, '', 1, 'BIP44'); - c.xPrivKey.should.equal('xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu'); + c.xPrivKey.should.equal( + 'xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu', + ); c.account.should.equal(1); - c.xPubKey.should.equal('xpub6BosfCnifzxcJJ1wYuntGJfF2zPJkDeG9ELNHcKNjezuea4tumswN9sH1psMdSVqCMoJC21Bv8usSeqSP4Sp1tLzW7aY59fGn9GCYzx5UTo'); + c.xPubKey.should.equal( + 'xpub6BosfCnifzxcJJ1wYuntGJfF2zPJkDeG9ELNHcKNjezuea4tumswN9sH1psMdSVqCMoJC21Bv8usSeqSP4Sp1tLzW7aY59fGn9GCYzx5UTo', + ); c.getBaseAddressDerivationPath().should.equal("m/44'/0'/1'"); }); it('Should create credentials from mnemonic with undefined/null passphrase', function() { - var words = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; + var words = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; var c = Credentials.fromMnemonic('livenet', words, undefined, 0, 'BIP44'); - c.xPrivKey.should.equal('xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu'); + c.xPrivKey.should.equal( + 'xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu', + ); c = Credentials.fromMnemonic('livenet', words, null, 0, 'BIP44'); - c.xPrivKey.should.equal('xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu'); + c.xPrivKey.should.equal( + 'xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu', + ); }); it('Should create credentials from mnemonic and passphrase', function() { - var words = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; + var words = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; var c = Credentials.fromMnemonic('livenet', words, 'hรบngaro', 0, 'BIP44'); - c.xPrivKey.should.equal('xprv9s21ZrQH143K2LkGEPHqW8w5vMJ3giizin94rFpSM5Ys5KhDaP7Hde3rEuzC7VpZDtNX643bJdvhHnkbhKMNmLx3Yi6H8WEsHBBox3qbpqq'); + c.xPrivKey.should.equal( + 'xprv9s21ZrQH143K2LkGEPHqW8w5vMJ3giizin94rFpSM5Ys5KhDaP7Hde3rEuzC7VpZDtNX643bJdvhHnkbhKMNmLx3Yi6H8WEsHBBox3qbpqq', + ); }); it('Should create credentials from mnemonic and passphrase for testnet account 2', function() { - var words = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; + var words = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; var c = Credentials.fromMnemonic('testnet', words, 'hรบngaro', 2, 'BIP44'); - c.xPrivKey.should.equal('tprv8ZgxMBicQKsPd9yntx9LfnZ5EUiFvEm14L4BigEtq43LrvSJZkT39PRJA69r7sCsbKuJ69fMTzWVkeJLpXhKaQDe5MJanrxvCGwEPnNxN85'); + c.xPrivKey.should.equal( + 'tprv8ZgxMBicQKsPd9yntx9LfnZ5EUiFvEm14L4BigEtq43LrvSJZkT39PRJA69r7sCsbKuJ69fMTzWVkeJLpXhKaQDe5MJanrxvCGwEPnNxN85', + ); c.network.should.equal('testnet'); - c.xPubKey.should.equal('tpubDCoAP4Ut9MXK5CakPFPudKAP4yCw6Xr7uzV2129v2LTa3eBoPoUGMqi2y3kmh83oRGX93m7EehB6LWan5GTSVD8yUnV5Jc7Kjzfa3Zsf8nE'); + c.xPubKey.should.equal( + 'tpubDCoAP4Ut9MXK5CakPFPudKAP4yCw6Xr7uzV2129v2LTa3eBoPoUGMqi2y3kmh83oRGX93m7EehB6LWan5GTSVD8yUnV5Jc7Kjzfa3Zsf8nE', + ); c.getBaseAddressDerivationPath().should.equal("m/44'/1'/2'"); }); it('Should create credentials from mnemonic (ES)', function() { var words = 'afirmar diseรฑo hielo fideo etapa ogro cambio fideo toalla pomelo nรบmero buscar'; var c = Credentials.fromMnemonic('livenet', words, '', 0, 'BIP44'); - c.xPrivKey.should.equal('xprv9s21ZrQH143K3H3WtXCn9nHtpi7Fz1ZE9VJErWErhrGL4hV1cApFVo3t4aANoPF7ufcLLWqN168izu3xGQdLaGxXG2qYZF8wWQGNWnuSSon'); + c.xPrivKey.should.equal( + 'xprv9s21ZrQH143K3H3WtXCn9nHtpi7Fz1ZE9VJErWErhrGL4hV1cApFVo3t4aANoPF7ufcLLWqN168izu3xGQdLaGxXG2qYZF8wWQGNWnuSSon', + ); c.network.should.equal('livenet'); }); describe('Compliant derivation', function() { it('Should create compliant base address derivation key from mnemonic', function() { - var words = "shoulder sphere pull seven top much black copy labor dress depth unit"; + var words = 'shoulder sphere pull seven top much black copy labor dress depth unit'; var c = Credentials.fromMnemonic('livenet', words, '', 0, 'BIP44'); - c.xPrivKey.should.equal('xprv9s21ZrQH143K3WoNK8dVjQJpcXhqfwyuBTpuZdc1ZVa9yWW2i7TmM4TLyfPrSKXctQuLgbg3U1WJmodK9yWM26JWeuh2vhT6bmsPPie688n'); - c.xPubKey.should.equal('xpub6DVMaW3r1CcZcsUazSHspjRfZZJzZG3N7GRL4DciY54Z8M4KmRSDrq2hd75VzxKZDXPu4EKiAwCGwiXMxec2pq6oVgtZYxQHSrgtxksWehx'); + c.xPrivKey.should.equal( + 'xprv9s21ZrQH143K3WoNK8dVjQJpcXhqfwyuBTpuZdc1ZVa9yWW2i7TmM4TLyfPrSKXctQuLgbg3U1WJmodK9yWM26JWeuh2vhT6bmsPPie688n', + ); + c.xPubKey.should.equal( + 'xpub6DVMaW3r1CcZcsUazSHspjRfZZJzZG3N7GRL4DciY54Z8M4KmRSDrq2hd75VzxKZDXPu4EKiAwCGwiXMxec2pq6oVgtZYxQHSrgtxksWehx', + ); }); it('Should create compliant request key from mnemonic', function() { - var words = "pool stomach bridge series powder mammal betray slogan pass roast neglect reunion"; + var words = 'pool stomach bridge series powder mammal betray slogan pass roast neglect reunion'; var c = Credentials.fromMnemonic('livenet', words, '', 0, 'BIP44'); - c.xPrivKey.should.equal('xprv9s21ZrQH143K3ZMudFRXpEwftifDuJkjLKnCtk26pXhxQuK8bCnytJuUTGkfvaibnCxPQQ9xToUtDAZkJqjm3W62GBXXr7JwhiAz1XWgTUJ'); + c.xPrivKey.should.equal( + 'xprv9s21ZrQH143K3ZMudFRXpEwftifDuJkjLKnCtk26pXhxQuK8bCnytJuUTGkfvaibnCxPQQ9xToUtDAZkJqjm3W62GBXXr7JwhiAz1XWgTUJ', + ); c.requestPrivKey.should.equal('7582efa9b71aefa831823592d753704cba9648b810b14b77ee078dfe8b730157'); }); it('should accept non-compliant derivation as a parameter when importing', function() { - var c = Credentials.fromMnemonic('testnet', 'level unusual burger hole call main basic flee drama diary argue legal', '', 0, 'BIP44', { - nonCompliantDerivation: true - }); - c.xPrivKey.should.equal('tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k'); + var c = Credentials.fromMnemonic( + 'testnet', + 'level unusual burger hole call main basic flee drama diary argue legal', + '', + 0, + 'BIP44', + { + nonCompliantDerivation: true, + }, + ); + c.xPrivKey.should.equal( + 'tprv8ZgxMBicQKsPd8U9aBBJ5J2v8XMwKwZvf8qcu2gLK5FRrsrPeSgkEcNHqKx4zwv6cP536m68q2UD7wVM24zdSCpaJRmpowaeJTeVMXL5v5k', + ); c.compliantDerivation.should.be.false; - c.xPubKey.should.equal('tpubDD919WKKqmh2CqKnSsfUAJWB9bnLbcry6r61tBuY8YEaTBBpvXSpwdXXBGAB1n4JRFDC7ebo7if3psUAMpvQJUBe3LcjuMNA6Y4nP8U9SNg'); - c.getDerivedXPrivKey().toString().should.equal("tprv8gSy16H5hQ1MKNHzZDzsktr4aaGQSHg4XYVEbfsEiGSBcgw4J8dEm8uf19FH4L9h6W47VBKtc3bbYyjb6HAm6QdyRLpB6fsA7bW19RZnby2"); + c.xPubKey.should.equal( + 'tpubDD919WKKqmh2CqKnSsfUAJWB9bnLbcry6r61tBuY8YEaTBBpvXSpwdXXBGAB1n4JRFDC7ebo7if3psUAMpvQJUBe3LcjuMNA6Y4nP8U9SNg', + ); + c.getDerivedXPrivKey() + .toString() + .should.equal( + 'tprv8gSy16H5hQ1MKNHzZDzsktr4aaGQSHg4XYVEbfsEiGSBcgw4J8dEm8uf19FH4L9h6W47VBKtc3bbYyjb6HAm6QdyRLpB6fsA7bW19RZnby2', + ); }); }); }); @@ -241,7 +348,9 @@ describe('Credentials', function() { it('Should return and clear mnemonic', function() { var c = Credentials.createWithMnemonic('testnet', '', 'en', 0); should.exist(c.mnemonic); - c.getMnemonic().split(' ').length.should.equal(12); + c.getMnemonic() + .split(' ') + .length.should.equal(12); c.clearMnemonic(); should.not.exist(c.getMnemonic()); }); diff --git a/packages/lightwallet/common/merit-wallet-client/test/legacyImportData.js b/packages/lightwallet/common/merit-wallet-client/test/legacyImportData.js index 17a801bbb3..e228616d12 100644 --- a/packages/lightwallet/common/merit-wallet-client/test/legacyImportData.js +++ b/packages/lightwallet/common/merit-wallet-client/test/legacyImportData.js @@ -1,29 +1,43 @@ -var copayers = [{ - username: '123', - password: '123qweasdZXC.', - ls: { - 'profile::4872dd8b2ceaa54f922e8e6ba6a8eaa77b488721': '{"iv":"b1Nsi+8CC9y8yuyMDo8ptw==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"cxWEUayLM5gKDjxdIeYwc1WFfm8CQn606QAof41LkW9fy1w+VwuN2QyQ8WKSk7HFnCVGsKqMlW3bzUUlzTAcB9uz/6V1y/HLyY8v7zjVFk67QFLHt5gDxnwUZTMPVsLjVd4ORhCBstekd5b6OL4jN/YPzCo4U2zjt2UdciKzARWUWjnPUj03qaKnvOnabtGcSDDdlsMi+qHNfsttJxjKhtu+Vw2S9Sl48BaGzE5dtn6uxABXYR0LVyfW9o0LSE4HlXzE+Pxs3CXc0hJfKsth5QLvh8XsvqHwIlp0kMsuRUcZ86jQ+b1+kdBkv911ppbdV2eFB2IPw2p9OY+GC/s3zCzaJ0ov/qarvJ4rq2yFfg05akptBcC7BE0+SpKRoQuwNpKUJRhdcjqzMW/8bEbhrZ/5Ucy1/9ijhedWHplKQvdbVd+TXtqhCqMjx/CvaGP33l+EMyQcDKpUFglQpw=="}', - 'wallet::4d32f0737a05f072': '{"iv":"zooCmnqINutmJ2HAOj4SqQ==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"lUZqnsKuOgPXd/9a6m5i7wZL+rBJmubhgVDUqwbFeJqBTYq7pT2Mq2nZHFyblSs3P/nqcnUG8w3OXqU1XsMRTpgFtiKtvVc5cjIru1oyJE2MNf73gIk401q3ekT51nJ5QSSCf4y83JxYj77zLmFFOkxAy/nAlOKlI16OeQ6PawiihsYn5h+hnNLJfhTdBepAO+PD89hkdXgTwPdhnBzZRpG1Hthe6Y1R3T3X6mjxYaF+HYe8ZtgcJWiLhL4o5LUESnGcgtpTmLk0L986Wj0n231Co3y05F+ustSI3yV4viB2y+HGgHO2o7eyidtNq/BAKSJQ9GI0QBssPfpgj/DIzQlBNfuS4+QxldXyglE5Joyhpv6TG9deiI0uE1Lq6IHmuhg13zov02viRcQjt+JvUxkSx9P7A3OPot9zdzxXZHcSLgvzb9W6PlRyhGLBDjCbGwpafsW8JQ48ZxJ8rg31Nc90kGQWC3j7D8dtOyGdDKTImeAzEAycSePU1DzElGKwIgV24joZaxLJO7wsQbZidEpHndBBy2EAVLEYUQPYlo2HRqDYBycK2pEXerel0K9eAWOcwv+AprOCM0rip1aYISBJBY+C6+/M9a4evzwSyCtzLp2Tsp/kFosVlae2uhftsMqa5jRh8kSjd+O/oXs28LBvW37e1PUbthxQ+kpWkwyWLFIIH2gaey5LKGvNB+pzzfTqEEV0aLxnc8rYH8fQvApmVgtRDm9f9YCIcyRuPiNEAFO4q/dAjjm5+cbRUVOUt08M+Uwmp2ItoWSPeuPfUFHT2ThdAG1z62zRsFXbxq+5DNQHbBHMA58JeMvBiy4jQYPS6/FvrUNUx54jHajH3FfCzf8jxRqZXvHJjse6sg7grkxhObxzj8pTUhBJUUHIiEixFAp6KZpJNqNXuuNGOsXxtADACi2Ig7v5dtIhOZLilI/45hLvWm48YJWzqcgEW/yjDlU2d5oTFTXar6f0rbe4a5M8fcr00F+GYZn4xd+Br/Aj4buRhNdQFgfTY5SIf1DwavJeotYJRwaqLG5wpJCa2nx7PubsSc6UpHvW54kmHSoq88CF6OGvafD0VrVB8tYkJoWUpsqK/uQmWuskHaNgaPj+u1xGQfb893QDBtZWhdDE5eJWkfe+UGv0wMfKQLdBrSDVBjZsQ/8Qbica+zVWwL/z3uuMMr8a7YahPaqyn1BxpQdHpeFNrpdc9aC68n/2Os6RnhzSofrGy6mIl4ck/IXemf/Ir5W9N6nxs5BRW3qsL+1l2xxSbqHKiFjkyJQZA6aGBB8iJQ2H2KH+hcQZy1hidvNHEniusVGdIOzS+TrKsceVs5DIhr+OIao2vrSnHtB4yytZTfbvpbt3iuyIsSGJvXRvtNTOmZCBBi1byR5MC4vpdQ8BLulFtl2bm6CLvvCCTJA8v6oeXFSFJ44cKFtjiYvvykwNqYM6GxWFsr+6Tk//F7E0n/Kji21YS1MU7kU8wGEX3Q1u0UUzGqN9AyZu583UVAoevmqDw7iYRXZDu4GvvJUoWqUsb2WueEa83LjVc6sz07OB+6ntlYvI4WCwKrCzp1RBuT0qn5Mc2w7igiPVnVAot8X7iseeqjGyHml6kZ+M+ZWaWK1RZLWeGuBOIUKI2X6Y18QgELzyHFYfxDs3cOYNCNa64BzAQlEalp/oupZlUtWCEBpP/4KOeBWOL4ywY/geJDlNlDJfYW5lU/ze+h67gPWRM5O9S1HgVUXX/ZhlpGCndTphs+8ABGR7vY035JFlRhsbZREb31V6Cu5GDH6PPdwvX1pg6flzqf5kQYLgsS5zgV/G6Un9OIoUYRvSpeBJceP2cq5AX33E+kdNAQsACaIR1gfGknb+ZlQRgwhaaeOq7YRKVCTuJWm7hJ82i1DnAWTj0bY4Uqs+OV9XbopSpz9/Att7xJRIoFXAcICpgB2ekDwH65S/NKLSxWJOhHDXlDiE5aE5ERmamaGqVHejWCwrj+GQrg4YEybKfH3DhOqSBLDJEuIxtJOXneIyYyHZw/EZV8xVorE24d8pCDvmmQHvYPgeydE0fAbKqk6LdOIaA3Au2oELBpbGzYR7rXhZXROOsXV2c7g7wpwONekmjdShuBiI0L3KblRGt6uyc5iEPAxOXsECPJK6QWEoqUC3fJpJcP+iMZah+xeZsYMZRkucehP4rmJlKb3imrKTMbR5W2hRUR5mpfmJovU4k15r00hW2QufCbQBmTy3/9vohiX2+9pKSgqZWRvnfpq9SWLW1i8P4EmOr/PamKCp8w0e3PjX0wNu4E+bPbvUq/b8CQvaw3XZ06IGgQF5jKYCrAbtAIqzrJ8mwE/FWB1B0MwxIA/HSzIslKq+g+oa2lCv+2do+NCf+PnZH77S50/y9p6Ugr7zeuRgZuAjGJerPv1bBEm+EX0nUIq3tkAALJr7mckyq2xAkZHX4tm+SZ9Bz0ioVYmppGeuSDCtGNk3XCLFcDFy1BzPwRW0+/c0gLy28Wd6AeWTTAdX80vhRtt2Qk1zG8I7S+a9RJbaOEZrCZKcq75rDi6AtaJhrD1+p6Fv0v2xFPuUWgIhJ0Pu99RJzi9fovtYCu7TO4hsDJRw1zIMesVZ9cBVHVe/azoAqpCCJ8X/lkoAWmoSPnMdwnIdn7ygpm2rdUdRtzQZyUEj85hg3X/hJDSfkTcDfRpHTyIwPf9iIBxjyXuT2QQVJIHZVRUp2LxVu5r/6g17Dw/O9YeXaNu4wuJ49NnMUtZg2dxbU4TbZq5tvLLvsfS6F4pKO+KomkKuBbGZ5OqXlvYaO39Yn5CWEBBKZ0BwCq0iAEKCaV0xgvjHrGt7zIKD01g+/CdgAdIQGdoUpDVOgAXfBH52B8vcQdaUFQZRFejbhjAZYHfRYOdfgWepQuVabMG+AHjceVl/gA4+aPaw9rWcKhIPXLjf5s2iiIEoLqFKFde/bF0rJXGbTryonNyMR9lI6lEdRQRfeOnhLi3mvkflqny3rm9Aj39zrob8a+P6gf5rCdZ8NQzrKajhbbqqSvJhHGesUPOw4EhL7U5WvlTBOyoI6bxV52zwaakQkVxS8+anouFnCToJIgCptDQPhNj5BaGqVuVEemittwCWLf0OIGHllAFZDdwFZxKYp/UtySJ4Dt8uitRgWnDsSzfT7gd06aKcUKtF1Ebme0+lRTu2jywNI3iwXL0ttmBncg73PaZDJbjdJt0ihKcym9y7hkfC+aT+k/NodfF75YWH2UXjuq2pDdR5hX1eOE+u+Qs96lxlgkNiR00kFbJ6qAANlDsDRxq5O/KU/SP4ioJaSEzUYR/Dbr/WXHTCsYREsfaczBzdW5zlb5Th6JcNBzt8WBQbkAMW4ky236UzgpmPr14zrmDIOK5vwMVdjTmdn9XKYdg4TV1yZk6Fiy0c4KgJBuOTqFFa6weBY7dK8cohjNArF0tjgLhrqBetJZ76IQHgNlXKxpGR8t54Cr98R8kV1rcaKoz1OvJHsZj6G9WXe2tzg2fJ9oDxROpD64pEPFXbWZwYLMIl8+DBPHeyjLdqmqKoa1PYnAWOl8OeCLyaa0GdH3VizotzMapvkcwhJv4tUfaViWLRGmXJob8/bdxJiKNnong7VnJJ3czAxKHBK4GrsduVaEx4KsOpgnCG7Ttw0YbuIIvXEM0x1IJm4oyW+36p/oXi+Hm1b66en0dUrqlfXCtxVvqaxbXsB99poQQhhu70crQKeg85p0pkhiRSFsKb2e2249Ep3pY+9bLhfYdT88zL5fljFUZavoau13WMNHB7dNPew42QdwfdLyKZIhSQYvmOVIYBkcpRpU2SdVzBXdWQ32d2tFA9AIGnvII0QxLrUlJ1bRibJxUudeEuQzv0CAOPIjGpjHJsKGwz8MrQEKjqeEUCeYxmn2UVrPIpbwRnaQqDQwOwcv17359jwj6db5rbeDIK4S5QW6LisOFR5G4g7E0+8XV6SfUvbw1s2XApogF3ty08Jg56aq733ysWfcxolMpUzAKanztbeN39QjND58T6Q0aM3AN8MS0EsPmyoVSDD1oauZNQbtZGuBk+PyrM9T0fsNaBsdzo4FmYiI4x9I/UacCFQcVNvveGUhiChOw2Dw2tbIJhoQRV4tLeyfKMBu66VW//n58xhIlQvDhbTr2GpKfKG7pH4bY+HHnfDchYYHixSim5vWb08vnQo0P1Bd9en7WiS+8qxdgt0v+UoXQfUXyazgZcIXk3OKxbCzAknlu0w2dy/EDLNyxpYwEP1xpqgGEAiUWcc/ux/E/SasA1NYQ8Eb1R3jT0qgMVcy8UkKlhZ25dobgyDIvINN5T9buBkta3FU5bQ+UDNzBIthjozcOHiltZ3plyFl3TuZ4Ia7CV1GP09MaBeMPhgTFV0Wu7jbRd//5aGYjxfgX4/c+je0/hZV3NxFhvdQkQ5euRZYCF4vXTc80RgeIJnb0staQjAs8X4mrTjjhnts7tR/+MB7lnQNy1fzvpio6St66wZcmuLSXE+jixhp+ynqHxBw1/LyGSvZ2Tic1CcotFbK9BDYWxstIObJ130BgQQDNxF4AmOoSn9/tSsJ0qjbhgm85/r8E4hUm5kHq0VM3NIpe/TaHEmPWP0JfYL94UsoffDYuCiGt6JIYSAQ280v8095vGxv6uyyGBcB3Pq3MLA3XRgdj3drFymMQ45ICdDsvTMpw3dQ/IOfbX08Kk9kmv+ZFCsxwzMuuiKypOHoBz6ZND6ZoKvsLZzGu5rXDK3thS+0qeB6edpml9Xwi3VbUfHujaTwEcw0tY6CjkzpxNMoL569MYHmwu+xajmBqgD4zYJqtb4TKk9zWoaBOrPmdbOe3P/1lrFayD+m5d7vCrihxxQhdlIgmEs+oGSi9ng4txNKTK7JplGvK7U+pihJSG2Exc8DbTh0VmCsX7nGhEIp4gz1xLiaKngYQekSnilmACDZmlNxO/sJgrstVXPHBcYvdxwtXJg7L4qd1uHI5ZIOHrAiAps12HgF9dQ3f1lynX+7UbJR/aI24iJgiRkEeUW8Iv+peK70DIXqbY7XMljyKnJFx8Npbd2VGYrdrF3dydPNtLKcK0pPp06C5wgKC0Pg94y/UWSMaaAzjdYlQIs6s1RiQ1XWZD0kCIZAkf61gmZo4f0S9BTNZdRg5y9Ka6LluD7psQFVDQUImuRT+25Wn0XVmctrHW0OUjH+QM7vmsfkoqVD532M76J0ABeIbHxJfzomfe0i8OibR9yK5l+HO2++EAoMjOxT6PglwiTQBMgkjF6Bx/6ONPPCNHwS9jLqI6qwkuUYCCi1cBNGEfOkfTUrjFxJy1PUie0o4IM6Fj1440lt0Zx9o3lKUZ85ICuJ5h5LQ1qTeSnHN7/xHcLpOsW5wIP4JgVsYxFe67Un22uUyn6Zf6CF88apem/5y6EsdcQ1Ik0ZUclLm59jdT10FSLfsPc0IFDHR1MyYPfRUnMGXnlnQGp+Ot2ilHdFSU+9dRpO3wixPi9iryvOm/dn43btvjfB81WdzmHGJSEfXILIq8zEVynln9gP4dCDbLLIUxRlZX1HY5Fqde/wrw6GtI7uRrfp1KnSUOMasCecI+lNdh/ztsGQsS5qfNkPme4jqGlHgv2FT5R5Brt7o8fnstXjrj7YVxBHyyupqh+fj18phYaWlAhTTSHqP6Whk6S8sv/HoeVl0O1Iia9CoHgUGT1OWopwHC2Rh2FMm2gSKvq9nkhTyRygBeuAam92u7X8TpMICLj/ernMpIQTw789zew9AKY4fugos1O1g58gojXC134/jfjKlibVjnHZxb9sR0892uLWeBs33RWayMSydI22DS/1Kh10FGcm1buGrZHdoc7PYUbUWMhlYQbDH2a3mDK9IKxeU/j2/nnSjjs0ryVaQpoicvhu8LBISLpkclS/SMiNj6Yj+c2rkXohHRu39CvwgMMcijg1bymitQmvs5iXZzD03iu3pJj8DZwA8CRPRjXzfysQp+5lcKd90bVodhD468clywnvNI/ruEsPzymGZdwb4IvxU1MLaA6fXBSNtz6hp1OouZhSB1wOYsSvzbmaKWHWp1hShnlvK4gJVugQdOTNwsuuqVYM1WGFHsV3YjDa0z+kGuBe8egsyVQcY4rNNDzfetr+Lo79b+3izUGjmOEWI3uRE3NQbGROMgHOPfnmU3yUKF5if7Y5rEZKc1Hdlm4cY0TgrUkobTwuI5/SJr2+E3t4KXmI4Wdv13U3gJSks257X7IfHT5+ooRaE2oHD5Qi0LbiKYtEjnnPOVo26Rl9hHXoM4EJfLvoXFLS0tJgwpl3US4hss8hy7IuUPvT9HeEJXgdqX4YnrzEL871JDMrOe+51hEmY3M56X1CRHzhd5fOKXQR4QOQE163TKmdf69WlZNfx/TP2/yMbDTxp1txG8RN2aRzj8BCsf/vMg2zKfYAIijoNmcnRbegEW96lhAOTt5aBE2XvBsuWoPgf9s69yjsy5RpYZFCPpUbLKxNjO3tB28CE+9chZnOLS5CQCrhG2gl56xVs5pgoKfnFwU7rT5nv8KP4YCN9hmJeo6h7F+HumSy1Sa1Hy88D+cXvsjKzjhwxmk0vuguTlGYiK4p8z0r395iOPBn9jlyRwLr8UJyXAYSLpqgSxxU9HuTS8WWKPbiRFJFYjy6gsVCaSuiGgntikx/XxcP4T5Uk+VDQ1JRuFLuRBn6b9FC76zEkegHKqNqZQvNPGzArWBOhLbrkN7v8FCOWlkbLDhzqkVCSns+FLec48DbMHyhkUeIP9dc18yDHMVHRAMEjsrRYoiaJ4rAWXe+/2P8N1Z599RKcKQqIOaJjZi1oUuFBIa6UCD0q5cOu2F0+XulPSVFwyW61m28SIEzoNeAPIWv8bXMroonTUbesSRpqRZbSUwlWqz1eADpKo6bjBlD3dtdphyAOGr9BA3uMd8snRiWFXUC6bqOb5LF30zD7vY9/uuH0ARG4nexMi+yB+NqgCKUxZyGhUSH9utZuHs+qLnEVkPeQxof8pSo1mmviE6oOdi513LFhe0RzPLoRutvizLmN9HNfNsFPpJ5Fy66CsI2qEI79KKRkNXHEvB9LJCJvWKN8AUNhXLQBsXkfbkAUUxXvVI7oAhlTVbfNJpe1qC2rBFWbBVA/p2lKghoaudkSXl4IYuaBKIpdA644+VHbV5A1bjogJIfeVIdVXNeJ1ijjq0ntErqRfu4RrI32FHk/FWn3/LdDz3G5jQLRfzxr38ZMj9CKQw1eN83MVGnZjNXf5MKmTpDqSIA5mWsFX/2yfuzbUft3gMG0iCtosabkz8IuH4Ima4PSGIBglaWiKr04l3j+LfMts9oVlMItQSMH3v7QSzD3SXQNc6cRNOTiSquc8DBdHZlGmvFJClp+kY9xj5azcHPeXUEABrAmwyXOtdKLb9CtlN3GttmbY47jrBh/aI0Wdtd0Jyo1swlDQwpooBxO7rDSnj8vMGRvG3DlzKb4pN0hc0XWu19i89oa8QGkvm6/6mgCFR4dq1qazr5KZaM9/JLALbV3+zaAhToPKEDaiqihggMRdzbixV7FnGiBji9GPF3CytNUhXZUyzZPvGWkgF9SPW4keX7dtzdqHFRza1XFpRTtpq7idRiyF7UuivoRVbXhw5jCIjiZAXYzn0ZnOfzF5v4E/ERvEsxR4IHBy9Q5Iyn7YIzlHQfVEYZNhixBtzJQxRtfz31AnRVVcjSubpC+hL1HQdvWrPRovlt914OwE00mIZ+UX2Tm4CtKMZoWH1ApQ/ROsXdBV27sSv8XZ3D250A2Ylrs1H6lgCxVtdsDo/udL+s/9QRf1W3aupvM8+c6qx4EGClr2nsRHahQ6xUYcbVAkkIf7+FnGXUhAXRrOfWZBSCkqY+5/TxVbVZ1+S743gkxmWxBae7HktSyyMir2tk9QCZ5dRdxMp6ZgMiTRbMh2TgepACwMb896SzTngT8vhNXA/A24qDWYkEXNmasbmQqLzU5DlnGnmnS4mbK5WSiCA5s9U8ssx7c3eVTVHnYFo08ozmqshnqDB65wisLQ/KdvKtskMk5E7Ci3/vFaK2ByYRDq2MAmAwWHykDjdGKeoDAFpiwQz7O4PAHF6/awIRkkD2CPW8MQDvlsuzMmKuywdmGmIg2Ihrv8hyBLsIoN//84InWr/uN+mRLawYbT3JIjSF6S/nns4HePqnTrItHxhcZ84iG9xIYuDb160/kCuZ747r1iCXdc0C0peMnpp9aMC31gVYxxLjfmrA/60SM2g2Kt7iwwoo39Ul8YPx1OxwYXtanob/Ooy0vNJddHPrcNjoiTmUqEzpDk62ywWLEbB1YnMDZ+QOChz52Z0q6xcuegVC/uYzUrk7oaHUmptqgHvXphHD5CQRcWtvGB6dIHsN2gScnFm+QNO2F5S/p6bM9dYvtSQFsdkur3nFFrSka8M9F1BQmvDOEIk38lHLuGo0qAhNwaJGK15F6eIVXkhyp0A1zfMfjaKmkA6BTb2sPLimwI+GwsESO9xPVcGa3ewvxo8u9vhm66ciNm58QQ+goO5SjzlskGFM/hxYZ5p+3tEzl71rUDFZK0UaSzAtYR+vEuceQKke3rT3Qor9Dm7HFbS7F9kNQ6nRfcb3KGq32iJC3nSfq23z310xSfn8ObGS1PPbAHpjkuuC0Q8blK6wnur4U3TLUMsRglHCBOSWu/MHN4bQvG6rB98NFVLnF1tk16iwbmulReV9Ma+kQXuYQRjw9dq4jS4iz4b4lbO7H199/t54LfCdahBnZmG2euHmGPNiiEGVxeH6IUV0hbZdAwZRPmTwXjEPrfGa3LTAjKk0/ZFjfrTIlNoEJ+BoxdhcMiNB+54fuCT9i0brEw/kmUB1lfqXse8MMtlPLMfiTx4mKzmyKZOsUBJoCnCKMS0k6cAfbrznGQZkDth0BqbCFcj94gjyPtoZyhmv8n8xY64X40hCyk7DMm4Q4SUpYmLW1IHTnHWe0zn845y3G+t8QzX4+xtuk0a6DH6y9iPtyyJZzoAGPMkkO3kMaupHtGkFmyip1rXgezFkgUy70x+rBDgxp8jde5KmXsV/9d+X8Y9bMHeIDHxxQuhGaQn/zxge+mvA4k5BTlFG2kIz+foD5yEw4oeLpv3H2RRGFB8F6ehQgUEkAx5si3VsOjrXyVVxAmVgD6r44Zp0wJdA4PVkNfUOSoq3M83W2FTpud8ERiA9v9MmT1HP2YNASXyJEyqk0e55w1xbkJwYtd4qIk8dOIlKUl4JweNT7qlbFhGOajAfX3td/NzijLNwJ0h/o77niS1UF1nZTu5l/Q12H9q++UXsxNrNP5zG7W+S1FbSZyQijTj9E8Oo8kR/EdfNkY9xuMu7wG+/B2mvAwhEEqzK4UCyKi14WhDsXA+MA36ufumkqFCR6poM0HNs35q5x4sBLZjecZkBvNTIXVmcSWtQWjFbDok+bxPyW6KVcZkhNErbY8VlAqW2keBDw5AezER1hpTmyHbkJs2u/OkZjsJWYriVea80PTECpigiWt3RgsRH8J0a5pEzUnZR26VloeYB0ctve6rDtZ/H1aDdFOteb+O7qEHmC5YdSu5b50Ts4+8hrrhHu9BY73pEhpB6hEkCX6DfCGBBmFgzwUqLnVtJhdee12xK7AXjfRDHD74iyKSAZmeDSZiZ5Tn99hZUCrzLMuSPpuEm4ArvkS0dOYmOj1ed1ISRpkngMNhQBnejcKlPJJyREUU07KgiHEb41brTeGujA5eg5a229WSkqxiGdvNjqctLWurhZiVGgZL7QFaenorCYa+cWRdd817mm0AmvZoasNkxJjidD73umMd8ZdgBH6rvo2XxQGVrHLIy7F2Hf4CF6ImsBE/BM3QTiZwYSEjmc7T/37QeK8SSmns7BBzYq/yFtzny9qMYy5xudwGgGOSUnOUouGJZzZ0Zya8sDUzfhLfgmqg6mbBIN0CE5gwW4lakADENplTlVX19VA0H8yBZ4J2PPSVzUlqfrmIun8g1o87EudzNUWS1+REJ6tLdxzceHSTd4YjRtoQZ6TAPROGSpLZfBq4bVadBcqJOzSsk4XmPTbdo+rpkXhmyRVylYM7U6UCuXNdFMLroOVgeVFL9vfNtnSqT9V81tlygAP+W1qp8y0kb4aD+gy2OsZejOKVHqU7GGQ/jLYKTrO3ahBhA1Cqec005Hy5kNpgv8c6Y2i0qFg7CiBVp2XNQncty56O9ftPoDEGtoqqghBesSILhIu4HkF5pR+rubyO1Wk3UYDAryfgtAtPEtONy6rZoFoZ92pH+FI3L32vHiOv1tNDnf2OWln35bFVTJ96HyLx2KdgcyIbpD99SHt0ODCJr9u/lnxPYfC7LoOHR/J+NP+NBUKxqd4xrBxbvQP/qm5g29xyY/8Olec4+dWv2PwqKyKktGmF/zbxdrkqOK9Eld0DXUx1bPNVkUXauq9LZcacr+5+mihDXdPOJuZkf01MogxqAwEupDW5ccwsNEpi9sdNeCIy7CTSvj/Llqcaou1Bu9xv7Gay8HI7rmbzZNVFA+RUDTtTcPdmRwfGRO4gR8KgoMZT9HtX/oh2+sXBWgLNq55QOLjm43Uow0CPnZQzVKULpiRKUuXVu3aKsBooDVDmGuAxrG/Fv8jgrXbg2SFYRWZRQdC/xOPjsKahzlEt8rmF5wgiNvoR6QCcEA5e1JG+3WeMHzeF1GHiZMk9QfwpiPWoaGCbsFzt4sKYcvKsk+ImZT1aLp1zkrcGVP5ozNvWSxFAnR5Ras7kMrDjzbVPmcuhq/3gRMn9Q9Ip2zVmkFSGfifbr1UzOt7BU10JWIx7kwTcwtKoxGAdEIguZi4hWSN627CsV8sF4ymSEkUjZeMpZ2JkixWNjwtmHmc+YqV0lSVyudIjt9h+K46KYXi6uXYoOU5Ku9XFJ0Y9z59+SW0G3g1Z7VFU3Ea26JIao5L4+idHWjllyGUzMkdPe8ZH3ZlzKBbwXtz083W+fMNa0awVNtpT3kgcc1J1pqkqkK2/F+fqxLy5i8kG9Efyq6XMNm6GyaSXaFitHkFsQl9pXXTLl3hwzUcqO5VgKZOJsDZb1eLZl34dGzUoaPoPqiKXHyGKV9htClCQdD6swOavCYwNIy3QFtIvNUTUkbMywnfYT5GLELDJfywgBCT1TIXyzdplT5iw7F1WOB4E+HLHdekjBtW7kBrR9ll9ujk0Z++aBBQFeas9ptCsNfKGS97dXeh2fYHnB2w9wNWoF8TKnUC7PmRIe0ajVBR2gs6EAga8xd+mZkqmzqCwdvU3LGpeJ0lmnvQ6/PIlBel75zhK6ib0n6PAUdCziVJGIkDn5dTkbbsEDSCVpk98e7ufipRGUlmmMh83R0qJpHO4UyG6+yi2vy+HPbhHMoHusMNlqq2V9AlbqEa+wHo2x8ePhf54v40TAQgx+MnAtKkc4/d9TA0nR1lav5LuO50ns9CzWK1ULwSUscsXXgnXbyOfjf4UajfsCj18GowvQAY3V1zpJm6TiDNXs7Jgbof1c5hV/f3z5hePDGmPp/jG4fvjfhG4myBXfYRHO2o56QLMInZLsrE6fViZz0IC+XJ0sC2KILh9HtoIu40LzkDVgifpU0llqPwBlAoYtJBV+rI+ieGVak87v209svifc3De7Aso0DEkAxNYT1oL+DRaPEnEuheHfX5fIE0P6pZnJdPzMsyvAHOzN6ykNqjw9ENl9DcnEWOGAAC8THGRjsbmERGELu+2XzuoHd2Mmr92uqnCmyj5HsGj+3XOnKj9/77K+l7orRzo3RYJEQvyIXEBwG/p8SQEIadRR2aoxWdYWNJXnRhWcbHWbqH76YBqqWg0lQVAVOwYkV8R8+Oenrb6wwu7QNAKn/XrpdTmw2/taakAPkg/dGzqb1Iik9CNI8n4+VqusQay3fc9zlWNt4FLvqEB6ISULluQpFm8sFvR/uet5n1JPdWAj5VmrGGynavSk11jv6p3yWkbtTX6VE4LtErNDgktUkJ+l6kjDySADKBsE6qfOGPnqRJwhEeEi4ulZ9+U40EvtvO6iL8+V6r5LLgclz/Fc9AqRicVRGenOq028LVI784BWOvFYiW8Kwy46nwZ4NMACSNEQshRubXuT0LEmUQWdyPlssKs7ioxZLLz5si0rVUJJ7vUfba+QYFcAWDYfAxF9zXROIJx1sTIR1q+oRTF5kSoBtPHrO2bNG6k6DkJOlTF8MAs82LUtmfqp4EZiaL1v+ETYDTFvfFxI5BFP+Tpyco+JX8P8rHNU4nsIBL/fbGHOPusQsjG4PO0XMI6YmgqNe3XNcgzWpLnOQp5uZ9po9qbHYJwo/a/kWshsqgscxhp3tce95owI8NBbIuRYevy8gcPYzS9Ka+8Fgm02TXxBBCWDk8WKrQgGHu+npgowoKGSBFKBrSR9/CpcwYAHVyi1J2Myj7L7myBu9sVQISazh9ADQcEAxpbZUipEX6TBuv62CPHkxh/Ye/bycDpN2t/PwoxTh91w7Rhq+1io4IGSywr94Gs66+rhsuSRVGYeH/T7k5Bp5yt3F/+R4Pg75MarXU/yR1S5560hjRYgiNJ1UPfIMlyt8IekaaoYAzF3ooC5sYzwTmT89cTH22gkH4hFq/WYZVvSUm/1jgScoIlf5sSDs4Pn7vK9BgXyD2AqCddyeC4ss6RXO+VpjJe6rfsS32jd4V4LE7ohZA6bgTxsfech2WTnXH0YjUlo423AzBMAvSNJ0djeULxt1F4XcNw5s87X9Ps+G1t0r6smgFIhvndq//uqutHlNiJZBOaLJBK/HJ5X7D9diDb69UE+msE1HGfKHBCGO4qcT89cCwAX3vFdsCZom/PLG3hJ7YJT+NxKV6g4UyJjXdRKPMVYbYHRYIiCZQDi2buCh1oanhp4f9gzscoYKINeUG/4E8w7NKARYDuGL5v1abzuvyGm6aQVkpskbLygI1s1izFSVUkL61KY+AALWF6bu5ReiuQ9OnXJPmiplj+O3Oez4KeCqVDIFYapzFdBZ4jGejyZNJPWdqHZmJbE8diQfvMZ3KnpGLoNeuuwusvOp4AkvDKzOXwJofSH44d/lrYRGdWJXp+Si/4iHBMFkJdM663ULSJvizzjAHZXfMKrYVUtTEYWYJyzPSJc4t4dyz8k7S5lFE8LwKX8fQMYAiLBcu+d0b3x1+AarR81SdTkk0wmeHVbcQUwut8YwhjfNDmojJ4JXUNbwL1VKdEYuKW+ZoNqpB2OfXufj1fSJZ8kymDudyoEpvyI4L86152inC7S0V8u+q1S6NLFoTokj5UKl93hACL3z5dg9u/IMPZbD7Oa+xqp0UcfJzBNzmQ5Y0nuS30xNJz/UKH7alwOlkB/B99ibJD1Sxa35DuUUObD5p6J+TShvN9NGPVKYxrcXscDZAeqVJrAEBJXDJ3sGhEfR2hMKVi1AhXfGwv386jKM8203eKWZdcsBXfRjhaFZOeesTdk+mAyTrjUCpBBrIDL040nnJ++zP88YbYWVo/oFPrf9rG3VIIOPIopoRMl/PJwx6SW+YiwSkB9sYJEqGyO80IQ5R21oQNBn14mPnemz1Pvb2PFy2iogrweupsbH5xhrRiFvRpSt3I4id8k8JKUK40JQwGvDhbyG2HMgZb9uo6U2tvtwOGSZaMv5WGpZwGNKFoTiiseagYSjTLG4TQQ7rNLdbKlIcgHiXy+bBaLr8ZIdR+10RuevP86YpZ9Dy5vQI+swoKVBnDdMzZiAvBdssVvTltqMYWelp7tvzCoJ6NK/eKdI="}', - 'wallet::7065a73486c8cb5d': '{"iv":"T3mXsRTEfMmDO7yvooHuSQ==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"FuVCpCX/iTzaiybPgx1FNPgpZn8w/QDupofYJaYvH229izUpR8s7pjGU1QSBrWqOtuDhA6fofjEAmdRliMv0ckRF28YGllXpK7Wvt3H6TENz++to1sUfNtPq4dl7jXsEFz+8Y08KzkirL+kAnsmIyYL3Jhi8opKOWLwX6S1yf1ZMZYt1P5XgcPF474MXvKLptuDWrX/e9aOkUXhneAK+1X26ghcDVgbmMWxUxbYJk/QcQC2fHAFV75G2hMzRXjFuBT8zPeMJ37yVLBdnbG375YHPInKOf5Pun1xMwcKTrpNW1pLsNU6zePvaTNMRMnjOaqEBEeey6tFO3tvA3V3AAGfPowKzN86QmjWA7Tkvy/mBa0ZDd13LvFKVeWZlFEkTkk1FoyFiSSgHC3Iodk8Bopyh6EYJNs17f8cwzpEWtg43ekLK5v95Lj1QXaEepOFNGCyPpr0nasoXo50J5hu3Ksnzk6XW2gIskcwjfwbVogLc6UEojx0puDRCrlHtQRmWGqcI14S6Srcc3aasCHqlmJ8nODvBOQ+Jsj8BkZgWgtLcJlzkr4p3X4oOgh2VJL7HpjIOtUZXdAmMdYStf4WEqZnfuP7UtPHmjaNEnOY7y7e2NqfX06iibUbZMnik3b7aXxGSFbY4623iVLHLzu2RmZZLOKzrbGPkBhCAq/M8oduxr91GbSuNK/NcNo+DDtBXsc7b3hNaS8sRf37kx/DbvY7TtGpBcRn/qXlc97zfkEZRQ7dGKAf3vyZuH3EThXdP6qc+hNzbY4HkCFt41wu9qX4B0CQDonSGrTBQdXYbyQRT7/QEtul+L+wGkX3UR0JCXxXiGd/RyTj8PFGOx9E2emrIr34prZVI7eD8fHxRER2c7vhF8ZRsZ6GHyN2zzRSNmc6Jxi5Vq5Sk3hFREmu2Y/dsbgyfxHEZ8/ZA+lG7DmbHtbWecjlPyGHG1DFFpPWSuFmlYJVZ+Q5LzwKAHZWT1/QTp/xWcjvYHWtNLuv+wFm4Mi2goeXs0lN62LDCtD3kmWcwP9n36EDNy+qJjh95SESw5GNtJrZHupilbATW9kEI9RmdZf/vi6qfJrTry46MreFI7rjRquVlMW2BRSc2ZS3yMyPPVWzOsPNIozXOb30PXM2Sqs32hsjQiVCaloY3iXHmTTFfaKggPCm5rMkLUfZ3E26J3Kl0AFhqScc/K+FFJZ5RyoiFp/0p1nUFIu0+M+5ZDYTNKI9SvctAyX9N6VJeq1SwXvL8lnlYRzcRf95ZVgz7KuzTezhoSNVzrlW9PJ4puOSNdaqJdh2H+hiVdCW2gxIgK4d8AiZ3yr/iPnZc1n76NvynNnHl9F+FFqiMofP1B5vtzI9QsYTA0mMJZeiZW9FcWFnjv95va4vPzQheY8Np2G0O/ADwh2oMXwDkgKbfiWYG6Vu5ydLD0/8IoLYyqO6Usn0k2xLyauX7zW2VoW8ltxRM0hDAqT1tglTZeafoN847tSgYpbcRpktR+hW5QN/Lbw+LWp0iI/3w4c75gtgIADLf3ii6zfHgSqpdtLPwARn8ThyguPWUw4TjOMYExrIR4YwPiQ4LhbAKfhY7ciFLn2YlRc3dmvpqHtdx9asIg8nK0TfMTZUAIK2BCPcVjNcLUagY6KzcA9udaptv6RkzVwlk1SuQJRsKOec2IQRlTczj71i6VUkGI3PdCt/Zcwgd86DFskJa62k2yY7qYY1kwZ83rQM/j+kzvPy+Avep0pb169ZTYE+G8E3BVJMGKlCRqm30B0507rM/tih01Ht0SFhzMH675pB791VYNqOkAPuVg8VVQO3oUgKuHbedZgdvv0xXTtpSzQawmKsEQ2Vk2cNi138p4WrcSTg9sWMDzVazZ9PISUl4zHaDhe5I023c3koVH0FBSCw97FhdflDRNnSSZoETOD7vEEOW1zUM6lrpQKBdQweqweWb+kbAZC+W4Nyxxuk1xMZwo0yf8BxB7RzoFsDDqqfPpiPRE+VLgIJQNAnaN0G+AKAd0B3tmkcNTfjYn7UXl7DlSxit4MoWL/MUbY8+Hxe63q4MlhDHmKR/BqqgGhgnhng0NVm1khvLU45fLXIXjXG5AeH5c7zIxnFlIJhC+7urPd1dJyOCHSVWsRCm/VG3kMyMi20bL7HjHCgQ+H8k5dnb8995ODBk+feg8RFGxqSiH141gcnqJTZxnwUNKfQ+9rK6hLnVBvwUFgmWfUgFtdw1ZQKE31O+JosC5MhEAV0CamMHH4Aa1YbcdIOfNCN+/Chb1h68mkkS8fsuYjyHznZLc55uAWq5pbbgIHIqzyGKEr0FX67q0Ax+NVnt8g2esqmqWFOXuWmIVaaG2KmwwB9rdgauFpBvcb2m4ExA97GYLJ/QkiAqlTuCiz8PGYjmqRk+EqSQkmRnEhX8wyTr2XNA/ml5S5/mqNvvM8N0gryyUEwUqH0Lg7I1lb6modmfL+z72cbDyg4swXQUT4fK/iXlIU2CAsspgUR4XzQSGEw8NV9dSZX9Y9ADT3XVVF6E2JQgEixMsfrPlXiFLHMnlZmLuMNSAKhuLSk7CHvrI1OY2fjTddXJhaiarT8Lsfbx8YLTau+TYb26JI5OaGH1z/WgH2gss8J7W5C5k1nft+K9R81csJg+35wm0BQC/hylhVJqkbfgL8g/A/axALyL31SaNhIZ1xfhHiw8MO/U0caWTEXH0vASZTi5Q+R27JqqwW6frAdrObTD7kuch+HU22brc4zu1yvqY5B8Rm4c2MhpivnU2oLL8rcVVAlErMpbLfJb1XItrgdYvlTYKGP0DXVJjOUA70OV1fqUWhNWuGTVoYGoscTKMBmoWpN3eivrNm04QhAnm3EDT9glq2uDL3te7Vaw41m8XsUsJdhkYG1jBvb10igHLLb8Cw58eK3XG2xrg49+u+VBjjV2uPZ6l/gd5JSjJZgiV+RkJUMed+3WnA6c73E3zlbwegxVF/cPd6hqjwZYrpzbe4B5kYEzC6/0fazeOXtaORB5xTXWqBr6+HFzV8T/6G3I7sdVWyXgsJCNtYajcmN63xFIijVOSZ56qNEaIbnse2Owll2xS0iB9nHKML3hyT7YvPWuIOXE1qGk9ayKpDlnCR0DWzFAN/W8PhTE1oIEHPWPrypS6Vp9HGe6cwIaewKRoFvLRzlkq345Cx/ahFRBGYUQcLmApdmBcZ2pwW2VhRgplFUdsREycAaRdYxJepYI/jnnH3upbjo7Wy8N846Jm0FFU6jrapCp84bRRmHAXKTFvyZAAKLhiKULJ9rUh/Gu6xBV+plla7KSKz+3u54Sjam0drlXb4cp89wRS+P6nRJiFvI5SnKMOhXLowXtdJxAGQtZIrPxpO/TQ4+kAQS1/7deN8x+6sZEJBfRzCxSAMhTEKNxvooJ5r3USMEmmGN9tUVdHkF2scaRgKVujfT6vFMrdfWatYxeRgbk5cQAEQ05/uwsOCtzLVDZevvCTZOL84IePvEsnpZBYN/SobwmvDCarpl+lEEhMFYPJMQQEHW4zPZ/XQR3YyUIJV+6s6kaV4a22vBwFMfW2ZloBOsxZxqMGY5MhPO1j+jJcyAaQonhGliUnScSRQrVZDCKyEOnq80d68jSZ65JFD+07OxQqwUuzLi1Mw0wmM4dVwtUavI/x0WpCGUU++Lh5fcpqU6fCUrEJzK/ca9Kbd/fyKTdReVP0sj9282CKLi6pZRQwYQgMuhd9OjaZ5+ZEwX0vQIDH82vMcjR9bu4OksXsVaKk+A3f1W1dOXwiZYt4cusupD/9wYqCFBLlzb0f6I0r2zAYvJz6ko43evE7JwlzrcVKapkZ6zszWDIlNgsq629jiDkuzx94fXBhtuCH18Qx1bxrt77UgcnteRHzS6sIDQF03pdZEfuOL2OQnOzU8dlOCfMZZVDAOeNIW6pckzEeOAdWhK7oY1YQqMV2oKc8DDLmjzoT9+S6s2B3FAUNplxBufMA4zF0Cc817Tr7gjNSY953ru4q6WEiiUFwj7AtCPRE6GCZaoGtlMWh4RUTUdlla/HZeJu+SBds2ecvdbkuBtarBfk3NVVLlgpBVd0wGEs6PdMQU+Liaq3SIwEdqeFPoxRzVSv400BGtUgEV36/fsKvMT9iHF4RCVb9w4rwJe/OjXZexfMEBc9/kTUYOnU2KCkbfOz92ZxTEo0gAAJbszY3lI/N9dpon+n5uEvUlR9tkAquX1jKeN+Fav9bXF7BFJ3F1saHJ2EVXtdKUt4aa56JlUTlSBRTJCoJXx558eGoRqgOCQOp6k7+TIqDTM65OuwQuBKaZNFOCU8RGzot796ans9lCO0XVbymMKfqMFkMbrCrQ+qLe81lAIEq3HUXCAuRfeq8/GANDNygbPkHFZZO6pDXCneCMUJmZlU0ehJfPdVkH0owHO2XcdjwRWRNQqwXfyOT5fQb7Zu9+qJMLPlrYTtRKC6Q8lMxW+IwJ2lBPU7xdVDW72Z0EqMQb7KX/ExO7SXQfzbnQP6FfY5KlcPpmOkwhP/1EI+fah5nUgwTJ/PxU8H9+qo6U6KSXG3POPKw8FdyJFKE3hEbhO2iUcCCc0V9uR+zwL0eVnarukaT9tbnwDaRizWvD2O098nDWKpsyXl6ZANac1s5a6GOiZVB3H4tlO4tonU2jA0RQmPKQQuZve4fPtzyr7thDToINRlVMzHDLB39IhNnO64taVs46F+adHhsRVmx815uUOpBPiZq2CB4k2W5qAFncnOImUhdY8gK4DrdMIwo8s06AKLm1SZriKlOwN5RH6H61kwGoBCSGqHCDvW0Ik+BCkqTehhjv7VovzSyr90bhn1ghRV/74yA3u+niMbbmeuP4oPjPwXJ/ryzdp55eeG14KZ5xj2Z6/z+L3Pld1CxANnbKX9fM7/UvNAEgNieCYSkoTS4MAKKllKbzoTpDiSmq23hErw9uFuAcaWPm4IMmmfvVfyCm4PpnhaWAOIDwFBrvUtl0PfqfQ9YzzKUGRnrbuSpbd9mU3zDczSzX9IcJDhnz8vs73g7ueR8KZRaLA67Gcn4X6/XzwsJzn3I2UWeBtRDbEgySpfAXLtxTjk2gY7rM/Ws8PyhLcLOt/PoagoSQswpSa8C8TZScySBx9QE00607HwbL0Vgw5pzaJNadsfGyTewwPcj+xz1V3ZOBdbmCeYsmZgdpExYd7nMt/2/1gVTg/2/a7vhdd21uvDo09AgvcXake/gFz+mCQnKBm3tpXORU+6GY78kPykbSrIN44p+5Sw34Gsfc4mt5xmp1XLouiqBuWoj/sVKimnwkg5wgK0QeWBbD4y4Yx7L9b7OCzShmAEs09xcpL0pTFceCme0vXdpe5wU5THkh0Ks0diH2Ug2tssd/0pDfJmzw0yfKNxw6oM4TRyQFmVr3mxrDXy2+IaYVKNzVBBN21OS1OaJ4Llo6K/BTNWu6lxGKO9D+I+jREvs2SykoA4aNJB2AHiqTq/h52BV3HAAudjFsmsLQ/aFFBCjH8R9Lfuewq1s7vuGMaPdFAgb/q9aDEwZ/Ovl3vhTLtMc7WoLMFQ8yv4jX1//zC9/WQUGjINBE0ow5htKpx4OmaxUuYgd6iOwtTJkN5wbmKwgO8zoCbRaZjHfSGUjI4qR7r3c9jw3bITvhOp97E9nAv1oUvXwFLT+UwmpWokSr+4p/7APE6drPIIYEm9In9siGHyqFCy4n5HynKYLqv8oyyeKzOmyr7QmMtilD/OO6+Z5NGlQmhFxxR2uOC2Fiez4Ze/5xqunQqIyP4j7QjIrXxu4NgyrRlmkD71pyA3cpfo2UHFOkA3pmLy8Ctryz8xqt/2wYqzeXi8gPd4abK8L6GiMJV/xvomAWy0HAn/FdHZMcwd3Yja4xZjhxNc3sHZMM9BoifkZy/UfliwgTcnvxsf3lO34Y9JZu2Y0dxaVUoMaL/xySD2tRrGNUPvhZIkR/v9P6gs2zTPvoWC4bt1e3VoSRWx/gC5g/N4ORftOgMby6WKoqTz7wCeMNy83sARTlsuFkT7ipzswk/oaqlbSqBRfkX/fbyXUWp6o50k3ci7ulcslwoRIvssw6GDlW8fnrcnLCu6fcdQ7vyiMZytI6qWqDIY4K65hSdhcPSMyYbBwtZlPy92iL9NlzSlmGsTZj/OW1J992u4J49bXG4NUCZ3y8HIz45miJAiOJ73xYio49yaNOgzK1TUUg2Fm+Z+UKeb0Tw7ARgVnC64cMoAiE2b7bPhGeSRzPpgzxqzASEiPEP5y9uoCEhbtwE4KOdDUYGZlFt5AhQTRkvjN8Z3FCZYLGV6VRePlZlIu5pta7y6QmlGefwWds5PtZYuVUV3QZWr00fjYIMHwZ3Su0ofpQXJPduuIqmQIX75YCmzIo5RL4t/YOD/a+98Ga0e04lmo5ywHnVD7Xt+0Kc4ZOUg5OcL1bYIq1HCvvnochlwkYb06c42HGQUlXDZW+P1Y2jV/1n+U9qvIugYE69CU61t/oAlUABCc/FAuMuTZ/DFvWqXa2uZGhMfN/FGFzCEYtGJ0FVRpOfyrpDQpuqn/57Q29lELhivlql9XVz8VS8fb/bie0fz9B6najk2AgveRIZGWNFRvTidxbD6iVQ5BU2zBvec8zeGHtwQX1ZP0OFQpKDOLLAuDE/hl4dgRnn9J8UboTjITklgOIsVN8VUrXhvFs3C3fLnq+ohcXtk+RYfb21hTvQFMFL5fneESeAyYgMmpfMqlnmDMOtfENwzYJqWEl33XPYWxFFDjV/gRt9zAqGF2X2lgpp3ZUzz0bdtv+7bVW1hjhjYJYGU4iX55PqEv3+foSjrCyfDrSNcIF03uBWrpzbL4yxQlaTjRiY2z+ApQu+BpF7EMlBkPBFTq1OtzfrsJfMnU80Z0N0U1JUUweXaoYU8mT7NtrFr+KAbLVsPPrTmQnrz7ZPNfW0nw3Ei/L2x7vViIYftR+1jrtu2hmQgNJ2DoHquGzYOA3wdzfg5JH9d1yjr+fNSlnG9Jqy6LGHPIfK+yMxZG8NTJSPd7MfwGsOjgN78cMB9Hi9sm7xwFmdX+1IV99FQbgQuZ54cCk+ubqOxIOZzxgecvJH7IMGACFQ51Gneog5YLEQNj4VCv2el+LQUD46dCKha58r9YVEApjLpUErj7EWfYmmL2LTF4seIjYjgNYEXi8f9Xbmwnvw0DVBj68jrAsMxRwEaJs5T7J/oTyF1T7amoqirg253Fg54XO7Rt3qb1cG9RNXas/sm09VQOesUIDe01MIVBxNzCVu5OsS3gIpsGotgD/XCq0OrUQXN51XCdYiW4/lTxC8tUJCyMwvNSRX3f6pQK7ubNSBP72u9fVUld9zuJo1vfmrZtub4XYUT7SWpf+YUknVOSRJme9rOhCf03Iopi0uFge1o7GueBWOsWDaJCctimtLkPsYt38hb1spMIUpRQffbCY/T1eR+I9NztqRDllUYzOm7/KfBsFfMzaCxr9UGDUmHVHr1N3QZyonT75FrAfHGQal6hgLA6P3kAZcoC6Ba+DMD9+TIquuxZz60ojJfhjGOu+pPJmGt13pHGSRWKPvQVybopy2+/4jp4S0FhzWW+7Fd6sVwKqU3hQtov4vXlt6DMK/fVw/iPqbbxEf2Bkpg08TaJ2pX+wP+BN+174Fx8gzBj5dDkgn//0OnvnDj1T09JU6cxeLzfd1rPByO7/D5MUEyE0plX3GlPDDLt3WLZs0F4zpJO6Gr06Z8C1HvZvAKwRcZGyGEqbNSgqECZ3oZTyqF8fcrYpd4jTrPxnlk/0b36Mja0wuccSdvN2xV/XCY8OKoU66jaZLeDszE6FxJgcGoJ8NqebuACbzLMUkkXZu2ST6w8eGnp9v/jnXNKdA32IMwk2XSwhVf8E7ioLBFrrQY7i5oxU5T/KDsdQkGsTIqY7VrE+zsfPXMQF1DEUJMsHFdBn/umVqygncktdQV7I4rWYlgqGHwmRkI3n4xdDWzEQiufNwO0C2R0qpiIXWMGy4xomJRqHgjzBp/XqLflKrZ/B5oY4g+cADrv35pL5DW9wFHTdIIDtHneR0riSt1kXx4/2ZxAYNEORRgxH+qihmeygtpflouS6HKJ0A9Lg9jn+Hi8pwT48VOX7Lc0YRz3WAR3Gn40tMEh7wViZKAjRyJqxmy1r62LTMrTUo1d0gBETHoSEeSn2uD/aR5dSduSYaOj84AsbWmxMmsCji3IxUOwwV+iPItYRsAA9tvgKtbg/Jcqa7iA8SFVuY47A+r/d2L+pFueCifrIeq/M61zxDfSoWTq/dyeFbDb9ClmwnpcUmTwl/Dj8J7lQ668D1HCoTXfMxSyrDSsjKpMyTNWgU8wRRbEnM9NXutc6gIJjBJSdwDhkf/F3XnTOzpGMCxW6RVF8EU8rzB28Biy9YmyjRfCjlEdMvo+cy4wM0j4ar3Nmr8QhNrB45lXigKKn4urneJjMS6AVEGAgJhLEojBwJIt7KjVqMDSENIdp6n6SnnECVuqri2L6vI87l1/UeIsUcHlVtcwlbH39WCw+GBVC7vvCQw1esV0Vo/OStMETqa4miKSr7PvCB25HZTgquVCWxg9B82bSf1lgwG0T0Z+Wp6zu2djdXrARVMu3WMghD75+s8pwfWjAs7m0TVPu1DAy4naFcjBWvjL/j2MWUsLyxszrssk8sLKg5AIfs+ZlCdJqIt3k1q8qzPqSmSCRZbARxmzAxiSUZ5Owfyp02m/rkRdFPw/grao+kLWkNi6ZR+hBI0E8tLWexp+RzSeDioErCKZdjkYwGL0W6yEvHjq9wNZqsYJvoDUksz7ZL8Pd2fGRrCCzt/HtcdhChblFG6Z93kigUih0aKVDH3WpLxnJ002d4V9OI/hGCQnrtb07oX+N8Tsh6+HRhd0oXKW2H8rceqxd8VyuGBy3BlhSfY3BckeVFIk16tkGzWmrV5E4nCFUMZB8RpQdpo7qT7tUY+ym14HyTj7EY8IW3Kuro00Nk0JttSBYm8OuumVvgGCC3eGAAgkAj1yiSBmivtwoi/ewl6cVPOjnIdAfYGHaizjmXRGLlsBiALyXRWMvICtvO6kvNKtLT0z0FXw+DlPMaIfSBTBNE1jfv+QJmLSeh+HDJXD6wfDBbiTw7WgDIBoPqFjkQSqR7IPmPotpD3i40JZCyviQAWdA7znEKafefGQ7uVfCOdUAhTCx69OtUdrtZffkvow39y4CMTLfz4+1iFlRSzDJv/Jz2oVIgVh49sRVDnvhYRse0hfJH7baOXNuH2bj4P0Y5jIAAbI0Yf6YscGjAhUp/tX/ETJHBFajiIDMPouWKphasgxMlcIoCjPFI8egG9fyVZx6q0LCXo6/xDLqWZkn45gD7TmRe3aNqatP3e6UOLnkipNblj21+s8/FL8bYk0wg+VJmIe1fT8GZ1ycncFC01Yc1shP7KNiLv92ZmZ5Yl0on1ld7uloZUZgIkeBfiKgkBU0B1ya66nrKQhzTJPxFQWFOuBPZzO7QHkbHFzo81JzmV+g8q2PqzVOxuPRcCnHm0FPs3XdB+5x3oU0+og7EKCMevK1VUmx3A6BZ9I2t7MCCoJcbtqBAZ9aVVpziNk/XxqgZ1C3ueZO7DKJEgmg22tEuHaHhK/jKZxxIENi68Tbj7WVijdspQ9bvRnESnUjA+FEw9owSj5Fiw0TQAy9pxlEvQWkb2RPjEDgLXlttsBbBuVbc0T0nzpEaqWzk2tmK55hmvjYOkbmBLeLr/8baRrMFrtPZSy1ai+0oCkQAwUjRlS1GJvObnr6jk6G4Jzt3swph2STiTl/+Y51HmsXf+cQ69aBEje+o+nA0DQOvyNyG5+RfkBMZXbbHCxp2IKymfSLXp82AFSaRkfgPVn7cydKQZRHlMOc93+Io/RzxJU1OgWUAgq3G6KrtqD+GYvk1RRc6zWXrmEsIB6uCmEVVvJcS2bRkhCg8Vrd7PUi9FLTf5xRsZ8jQUg94crKScEXk84jM40wrF5LSSIngM0aqHeM7zXPGLKJn6LrzTe+UYZzRVPgBDD6NsK+zqX8TGkWcnpaWDAHGAs/ECErPSt51a8s//bPXf+obnIViTcwL9FRTBfmR7yXV3NEfXnI0gwK/PQLjeV2v98JUL50RM4k0+F/9eIj706b5LRnJ8FVOJpL/9XOqc3BknvSmMq+fMw6ADO4wXvxRIso0I7U0CjtNSkKnkatSMjuGuTNwrSz7N8NEUn2unDR+mgACIqSfnnobmOL0zMLeDR38MFQuObSU5i1+ux4fzrxi91aN1FeJIKqrCxxIiKYZ+DwTS/plgvbXsgnGcndt0002ANl7H1btkp8BmZM5In5IHW8YC5FxDPrbd8A6SB7MPaN+nak5Z2qBDWMDHqmlxOJKWUiWNLV9e36o6ZZjExr1PpA+2mItksINLh9vgiZnPLkhDY43dr2OInYiXIMAdZOTTSG3vf9XR6S5VFEHelCE/09a5lPOHE7cvL57x8+CsKNAVI3zkrm9Q8JURHssEXBoLpa7jYZQji+kga690WaWjzYB/kjrwimlWndys+KHrKSadYHTQ/skMr+Ez6k7KmzpqFTtg1/29mMTkysbrwsUTS0ypSTnzd8DO1ds86lQx7Rk+x3IIxMZFDD5HCclZ/jLFJMSLIn+qD5AyUJ9FGmi4l94kSs1XwesIsf5m/GAAxOTzDx2hoaSa/2x75ZAtml4nIHVnKAw+z3wH7PnJ58WHpgaV6/FxaF9BAAKVeudJvNlVcudbgsp7XtBuMmYR7Qjo9H+NByo0pGPETSBiCOtrzCuyaSNHxjK8b1SvVRNcWZf4+2XkLVpZlNvB5lBvc+By23ogubjpToOguNw6S0GFUEEc4HAS+4xaAmzQtZYOlJqamgn/be8xYCeZ41gwwlZi6K9WsTsVHaBcfiYsjWVLR/v6+gD+T2zlgdBKTTznaKvRpxryTwEseTsTQiaQ51Ta69HOg0pT5RhHnUzmsiVmgpMu7alCTOCqBVpOA6/pJbldBTBa6hI/D5Jdo//Ki8PNodSPfx9rpG+EPchUHgabv7QGv7iW2Jmbq5qNL9Osa4Kz7sYkR/RNsVFLDXdBkRn/8YoXuKKBozzwQ93k2J0BnbFiQJJnL8PduSzu2cKFFS6NyaSHKIyijdpztJwEGmiw3wXmCsdMSO3PsYoj8Hk3Er1uga0+OupIgNhF3Tc7wAaKbb5R+aW344G18APLx1unGbPG1P+3Xdlhmcl+svjqktcC0Aw97qZzs+73uom6ZMJSLiWeFj2MsuILlTCfoZdi0qDC3sU3sehz6LdgsLBC54Mfp+xCEuPgVmV2pI1OynTs0L1IhSnNWzzCdn0LtRClSWJfc17exEMHPfnS2C4EoqkdGRIUsremZPdTSM4TQx0rFVv2pg=="}', - 'wallet::8f197244e661f4d0': '{"iv":"ey0b5/szn+jBexTsZokzMQ==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"9Rn+6r8b4DwdA/jFGNmfI6GVCwTlAMCa5YTa+fWZuO2M2gSkA1MNCEGPvy65d74xEGX7aybF3E9KPL4rNxUoAV5hCkndkbA20Cwp06k/5HS9oPdnCMNPdzH8skrPvXZLCTzcXsJZsA8F4TVYiOLGycBEdGA63Ki2CVjbG+xZZvvAI3WCQY3PErZetISX8ciU8AuzUiiYkfn9w+bKu2XP4T8JzVP+yf74JwZY8OJAeEIgPCbBR/HN6JNDpUBi5bC9dFmGNI+oreUBTUle0g6WYBfgd9YAMPf9IySRhIaTuj3vJU+ROTleFiMtoa40BxMhtJgIItCvqahiszGcIg+a+mFDvZEd9FP2ZhhGSzMmsScL4tsqES1CvnmLl0Vg+SHAZkbdyajpE6MTjEI8SV2NWqrpbziZhNJdIGaS/GzpzzKEwejrCmUK6jww+UT5it51ltI7+OEmhLUzgz7eLZ7yrRL+c6F9V8ndwkenOe7plXew4NKQT1s655FltVwr/UNjemwSPmx133lqajilL6emafMTbO5njrFmvaE4LCS54nXqCRuCXzQKnpulDWxWkXr61qzeAhsKTaChO/WTBtoV7V3g8wyEuWTKJJg/DeRN4JUjM6RxU+lcVa5WamOYCmWIWIAwKihsKK9xxbiQsDDI1uw/tdzIXwBhs0SYjK4J+HvpSznT0mbaCKv7ldDkngNlMxjAOYlzMbnwtAa7/HzkfW5Q20NO1jUuv3zJO9fjnDT71OLRMI193RXHYNdCOXj017Kduq2bFhJNnC9kID7cyU7SVpT6lUZEeq+mtMokHy+tzcF7kIkhavs6pyF5D89O7HUX3JF+1kL6Wp9J9U/wmCZCSuFvspgG2aRH3ZbGwQ4F+qNXyfDsHDgEf9Z88vWSeYRhZb3rHkrPp+WasSQRqi8wZmxyHKtzeKSL7bM05MVRdWZfnIFu9gn+vo6QbmvJNlFHnY3hWGuCYfj949iwprW4df1fzW9z1dPwil9E7UP5tdkUZb6wKAeQvgBBNw29eRrMw4pv1ngwQxOUGgUQAEKANu+SFVbHqRwWu1CI3b+n5lnJWmGNw44o9PRRqzgBmiV4G+unbmUsYh9JwYI3MJhqev0i9fNtEKdoeGetBlMVUmDanil0Uo9ealPJfzKt4YyWgw3gB+vTXzLGipXchG84sH4OrJH/oZ67xLCffzsmK2PiaPAnVYWIOOj/MUYeAPJB+SqPzz+FOoc9WlF+xOGIHYwr62I4A3KPROENQdt3QdZo3ckzvAxXRnvg08WQZ5KCdV24Rnz8v4/V5RgLYbhJDKmAwwv8hSnOwThdoYCuxzhCkH+bO/+BuwEdPd0asHxtoVTtRMMGkgNZOmcb76/R8MoV4uNjX4RQC3NFXrVaqDug3dpL+81muc28oVU7Cq7bcwZo2gXgtU2myaikfXrxFpv4art5Qi/Pc8P2G76xD5r8o+jdriRAZhf792eOb2uluUOZfvsgZrhjg0vGo7u2bV/kCi1PZFOAbdbqWfm+L9WMw9qraW+TJqzLPyl5+2bxP/tIzxanhXYsNR/mzV2PYp/XEiEUC7TFC4gWFEKJif3kFdoPWt8YL2BBeirl8du3OwqMNdn8+aRXF9qHyiEasOVUDYjo5rhxur53Wafl/jGfjuLU7AZojD0AfLodaeQgYWwDbmZWZFKl9uyxpiuhgr7bGCoSy8C5ie4O5ss9KsvdGGAx+IVYWzCVk89bBtlU/4uxNKAkDdMMSkRr7SJORjrtIB1b77DNLD8n2KHoPsDDTj5LMsUhy0s54Ror84wYLnNkmXtNDD0jM3iyGMY45/RgWGbWVaU9ZIDN"}', - 'wallet::e2c2d72024979ded': '{"iv":"SE2jsjnmAd27S8dyvM+/AA==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"IvVGj5uxHgOUBz3th5P23R7/GVNIMA+aBhrJXBlfS1gDJx6ekdyGJejq5Q4gmhX+M7WnnJlJpCtWeLcD9ymV5KxnkWlfwbNbI+wwdcMwiU+RDQR3YN4d6W/7Rxi++7VWho59MOipS+s72k2DY45ZGTQRyYZlzn4a3FfAJe6AIS92MsgkfPkjPxIrYz/eg0pS5k1aV5+EuNvCKCBd0dH7tHMlTDfo92+YHIO//tJ0JVMOj3Fk5xeYXUnBUeWO4VsPR2aRaa34h+Tv/pSUfHad8YJHUzhOw2w2tF9b59AWhjJ74BD0VM/MnPLOIYxqwkZP+nzEujkuDVl1RQ+zZYYmCSBYar8oA1m5qlRKPJJFuiXAA3xW6xUOM8A5zSSSv21jE5fqmCEfhg+HX5ePvi5APW+Y8x5H5XCX0sewY3jCBux+LWBpFssxhWX0yE6ytwyWYD5l6Uce9ARTnnPpOwwWImLRFFPzTdFyoNRvv73dSmU5F8oZXqC3kOqLtXFMNIFRBsTiwAFoplj4EQzMUOs/hZFzpIDq/bBlYKIuk+p54mggzigsRlypnPPGvXmgw0SZ93a8JXLmBETii4RifG/iR6LwTtjxRj8MdCeEjALk7Q+p7jzQwkMUtRQTQdFG8YpaqZUhnY9n7IUhLpGB+621m7lxgrPGCz7WLKy9uEq+la6hbKlyZtkibGGpN7098HFSZQxrj3RXc+BeEj8uc/BemWlARtgUF+0w3HNRnm1He5+GmFqD2/bwqEsTmqRrjDpWBarJGVFWN4+eJX2ZIx5p7a3toikvYcWAz+U0oaJuP9QdLHk3DVViCgNz1q/xW9Jx91YgjeWAmlN3C9ZeDW2jS+SKulv+59oOaILJvfFpECU0NYZ5ljA5n3XwIzJTBMLwEftpYgRaT2xLeP0qExXiHXMtXvff2pTOFBRERtfrDac1sTspUB81ogoQ9tMmPJMVYyNiB3x40znc/t/+e1zKIxkfrC6Mkv7JE/NjOaXxGKpg+zuMMmMMK+zMqOIg/6qEbIcNA5bsx+G7wEthJeQvgaR0uN/XFKd/GlnrsuO+OuWyEUQBs5PsrQwpDDTIuXWJpBKZqFtk2fcRqMNYyUTtJYgqOE5Qkscj4Ze8mlJjEfwMmyOgenW+7AHIf4bQUm2TD6wkK/WxLPllB/LNoj0mB2PgKCnrn5VoL3KMPMwnUrIzBSyCVIgXr4UkWztxHmCK0AU+IUDoyYdvOFslqE4HR97zEGpq5aZLc+f3tQ/xoiKcVylJW7D67R5gmwOM1ZYFhvX1G11f+Qbm4j8MBoBxbSlkdfGBOPYbOFRCm20L7GImG//k7pYkLB9bn3miEPKljjiT4QUkgu6hnS6//o6iJmtuVMF+jW22La+NI1nm29am+b8LNjyWbTttmd8jPrHlRMsyg+NT/CMyJm8wNB6c4fhcBOf8d3zxGZm6C4MKzOpdkmAr8FS1sPdrvQz7KMH4D026M3Eouw0ETKDc/rbkJH5VksqM3mMVNcM7En7qb1m4YOCLg6SFTstW3LZm4qnLwssf0LpVO2lHSXQS/2CEMTYg9HBlDji99oaMG0GAQTO3VmcGx90zp8VCRL97iOVIk78UUEZIS/bsDW5DBwuW2hngY4g3Yej5+GMAREo3PwsnGo+AE+B8QuUwc+KA2NeTWWZGBJ86SfXPCHRS9KLfmfW6r5pfKD9qy3loUMgzsSy71fS/Sl/p1ONAsJB5yNP33ZPloeT1J/CkM8sOX0o1BKyIyhV4RrfkjQSXSzuOAo7awbaOv8iAEy1R6fiYVtZfClNoJrCPg0dXDlFZ5g7db5C/W1V0H52+d7obi3+CWziMFXZErASVzAnsyKep70bb48zC9pERLSjK39GbByQAq6M+JjvCsygtWdmqBkbOwcjLIjXM6j44SIId2ZmjdrivDZt/copyiHG7es5q+W2F5V09sCJURBmj/5EgTn7cXZBPndutfxokYd6gTvIqZkeuZQ12skbQpwy9NKc81G2rklZx5iQVj7hp1RcDP1xIGYf01jdgiHWTZVBcnI8vqNZry8+UPNAwWtoRlrnBKkm4Oy9uaWtB6XuSruoZ9c8HNT/Gpmhq23CBAdP29moXIjzyY/kjrcYGH17nEXBqt1dfTk+SJPIGS2UaQ9FRb9EAEHV9gEJYGVJCPX/ofX9H66a8w82MQhcR1y6rD4sC0FunFA3qOnz1+4QIndma8nST11dOjvDAQg3rV3kIs95H3zadM+M+Clxk0XCUKgzxWqm56zoJ2EJ1udM6VFO1WetGVGlcZf/iU7Jl75I7ds9VRtBMa7qREpjmtCW/5eDjGzkzP7TVXxVK/ALEFKXMwJ4wXQUNdsXuPCi4OvUb70JmouPDUQONuItXELRfNuMScxSxP8SE/U8H7aRHbgg+uvvb2vXP2te6yJA/ZxVY4fw0mQvs96ez4bpRg3BClD+0ZNTNTENPNl7qx2YPs+utcJSvfYvXEEsMrVotXRdj8znHtFAJ1YagzRtj+NX36CtGNaYEGd8t7QM4XRR9PHalUdt1ArE+tMY5Do9Yx/jcDRp4n1h6qGKIETgLn4VUy8VWl84v/tswZh9OLV3qOaF43ZfW49eY8NevgED74jF/3et/hSk5P/S9SNnnwbe9dQs/toLZIZ7Ez3epMbH8YDCM1esrHDgCL1yjBq24vGQo7e/TKYmp+LRodo05NTSVtiB8QSiXjb5TWvIb4QKBMA67gksQDbYal9Cb78T3oebJ4daQ4Eu/dsN5H8setRWNGnzkS3yUYCrUpQhd7bdjUqnbVRKP2a3DPs7wNvNQmr6FLw0+AfkZumqbCzwKaPZ72Tp7b/dUd+OwlvlKeVbemHV/g8EGL1Pc1bF2QewYTHnLwCJzuie7+CdTRHXwbK1sMIw4vVutTDABh2BF9fWt90J9NM/Yzu5futgR9mle6DrAvahnhA0+8UPWKay10ODZcwg492wvHhorRSNBNjoPgCSVuWJ2LPSkGziax3pcx8uEUDE1IaaButpM5ny3bZV6LUIgy/Ah35TBuWpFJAeWcBGaf2+VnA3sqWXz+I1AdNdMrVWBbUkP6aJebmLN4sbcM4D8BpMr0HO3wCovguAeYAB8JaKYJCX43l8hmjHqozI+AZl72+9GsqioXsvXGGRpnfsnQSBncF+2hUXqXTLfr+BrZfNrxF+iiDF0gnbcPRnsnKMsyDo6x+DrcM1YWO/KJNCi/DbAX7TNrUuU+g/EsgYCGebsYIVn13iLrXZsLpm/9KJO7q98t+LSPKB3o+9mcMcUm1y3NuDSLNJQqgGhS6cU5G2YrIrhz+I16dA8K4etTjQa6IvJ9/FiwLRwvHq41DjP1zTvVxdqTaBujkh8sY2Jj6toJldGwep1pDn+/DKxZrRxwMG6EJup2h4zX/uXcP6yPuGc6eOQZJ5xW/LBLkHxSlxBaRKJYM7eFydcu0bFCvVdnVDivwiETlOLgxbw2pbIbs7oH9nykqKE4FyqKE/LK8eLUHhLpMOhLJx+4cCZB6E1TUlEaqrJuUC/W0SscCpLPH+FYFAJT7Y4Y40gW1ChNFd6GA5MofRjHp3ja/uC2kcyzUdo+DqjQyj6UH34VhtFlVyAdEooS60CbFpZFs13crHWe/N12/Q/4xQcTfRJPpyNAtOD/LuzedCdH0ZBLOTwf0WbLQl2VRjQCxSlgPj5LMkFdf5GNiPtDgikwtp8Ma3nqbDLpgjWCiWjEDqFzyxnAyqJB8sKnpPbXPFC7o2GnsrMwYPeUK618+eJHfTx5cPrlzE2Tyg35CpuC11/eh/DDv/27tTDclNAGhtjWRfn5jBNOiBur2NirdSl+AkSeGQjnTujyd3Qy+UOJfubHc8v1/P1QlEb03+wEDbzZRmVE1akuecLu+grBJtbugLx9/crhp+K0JBskwTO9ALHM85KtlkvMnnOO7zRwxowfLangHkj+o3DDeVpdRB0Kad6WQRhlQwAt3hr9UBlW8LVBF7FR4DYBX/QQk9qiSb98cCiIedr7Sgl1aiAVwGl6VJWkFBaC2ai0qmKryLcQDV8ss0zSTONDSncTKK6fyJ9BX5zAEDxUZCUJuF1LQQgURNPdpJpKhHU/rcI0PNuizoUJwcnPeGT9LrAvZpFX33EUnk6Ca7uwjOw207FfwaYQOTTSm0MoGaA981we3kTq1LEdqBb4/e+Ez7ZWFYBNDM7Id/1A/aW385JIgii8DHHrM7UA0IfzjV8hOouURviPedCVIPLv+nNXBw1t9148aJ3xAhrnhCYi+Dc9VMA2kRO8gwgWKtVvGObUAMlr+3mT28sIlk87u4+hBaJdyEua0oFfyL9qma4+ihpHvlp8r6ORPcJVsn+ekQmOSzyuGfJzx6VC06q93rFBF4/jgM22jyjMPKwUMVQ2Oxj8k63z1lz+F1N5W7FLc5CPxKXOC4gLorEyjanDjEFYdFlH/vO6NQkVQqJ927fstAUxYMIObDxZQsEZSGfZGusvNWErZnVuyaMBK/o5jjSR13tg6agFBZKzbNFe+W9psKv159ssf6q8JGsvl5oaSrB5rXFXD5wwlJeiScS4zIkDsd4XCJyKi6kPAzf1riqwrj33R8xf2gIueRIPMg/njj0AQPNQ4PgTFnrCuUG1K/4a67lICGkWx4KiM/XuIE57linTWH/H0e2+Hi/ZM96LeEmXUalJg+9yw4G/9omxNdlkOUG/TsmvQZBcmSUXWFB+cCLLRhqe7KOiBqPEh232lg1W8N627bpR8PHSXF6IiFuGEMwNeXl9bHe0uR2lrc1Ux8cWiIMwhoubNkev1PDS5UNXk/y12VYNg8AZl/fjum4n0tr/vvBXDXgvTI0Z+AVs2jA7TQreix7wXHXqwcXzazguJjYAkZBRtFfe+udFDOhmjrN2QWh7Mvu67rwUnjbcu6a2ryrkyh2tVaEXkcwmO52eXL39EHWc0S+9PJZqa323ORGyaddhnOB+WWIarRCT+C1lQOZpCPo+Z5yjgXgjbyiD3kHW4nAUeSjC2aQLkvxzs8qDkEU5O2A83t4rIvKqlrDI2Mp1teo4oTH2MSwP++iTfbDqCJLEyWHE8XuYc8oz3pW07EOkiAiaAmcu7RC1w71IIRVaOkHELHtqNKOrS0XBlG6mmjE4xv6eSFmTtNLVza5XFIdMI6Mob5++BDcYR/ShDsVNINf4Cc2r2o8lNqinh+oAbIyvMjgqQ5sWCBiPa/2XSVna+dAB7hsmQJ0ZxAWTujhDhSnzstwsvjp+mUX4/etCknS/J84NEZPBhd6nJyRLAG7pbpBfTpX+GEZXNSwI1BxK9mCG5MptL+69fSB4tke8CwNclwq5+yk2XrKmKv8nTFqa2KfLhvHAXCrdaX9DQRL2ND9Ce4akkOFKl4nSkiVfelhxrM0eZlG1fa5YIfik9xJO+vPJs+h7b9aI9WZYroqM7+rZgdtOGfNyQJK95u/gpIxqiDWBFEPY1PSLGRaji4OzbPRgrQQTNcC1nCPGu5e2RtAaCm+VKXWbZUT1TaWRGBwXdexLLDgm19tTyCGgPx6fm2Af/gwH+u45TwplYUroYwpWUD8Y25LxQ0Q031nibgZdPDZaNFYXQg24n3WUmd376ywKPCMlMznkYP6AJv0XRaDuKw+IcgeXPu/8cFcbFPlk7WxJKFmVyT5dumYXDRNe7Xj/UdUcneItqYZVdO6MsTgvJJKoWLGRcfqJ2UPRObKTM7TVJ8oza7cwNPapnM4l961//s0gk/3gqTeFjJetWx6Yv1BE3cSY1heF61eGHKuxA0oPp2oUCgsPSBwfCTBvMGz4yRXDpDN8thGia2TcV3bqRKHZyB25d1+UJXmuLKiTNUKGfbSWyUaWMJYXBlIpeFg60Mr/1xGuUYN0a2pHmURMIhmBn7mBneuy8oCfTNr8gLDSe6NlEO2hn+JKqZAZwB99EmPe85bH1vG8qgU2yUCrtHI98QwjCyWtmWk5m/DJx9G39Jc6tQLf3iocxksWmSU+WCwy/BEZ+um+yOXLqDQPOaKmgKAQMZ6CPnb+9nEkUk6cT56o4e0nLzlBR0NlJ3kKCuL6QDk61Lp05mo4yOS+lu4W1Eg5Q4LVPee1v3npFAWv16oaDE8w+c2Bx9POUF3u+NNAGLYcG6ZIP249jEsqHrGBOzkiiBeo0fvSoWdK+ol3G5BuLBZBAIMmm7hN5VGjUm1oy1K8GXWECLkAZwwsSmCZsJrGw3LEDat6mHuR6YFbROYGKSKlbswaZrXm4Y/nO4IcuqzOtF+s1sXHI0JPbQqPQaZylco8WRz72xtzxMAnY9YZEFMM1gbq9n5ntKcpHE7Q0gNKJSz5AaPHZIUoJ+4TxBw0X5MPx/+9A1TVOJI82bwptWId46W+wQ8xYjG2678c4EkN6xhcKX5fjKOwsFKYu2BPJuVqmaAP0WKgbWPw/ySauI5oGNZpAibLTtVeyFzCXRkIjR8mPWsNnQUD+aiXHYGH+buniC+mS04vj6amCw8PIr153MaWc7Dmkj01TBShH4BhYqF6+HJdv6dJWmsiQcHhe/fkeA+odBly16izpRiTt534ZA1Q93cQLy3qWxQvn9jGnjVFhyl+VkPLadBpAnelHSNdN5B02DNBx7/d90mg9P3VbDDyJgD4Ad6ILuKh+DZm9SHY8Ne+1NCKCaoybAYgEnM9ZK8Ys12RnyRBP3plen4GUraizdJoB5VZ+i2V4eX4sbMp/mal9HWfkWvvJMvI/PSqdxKK3gjVDzTpy+5SC4="}', +var copayers = [ + { + username: '123', + password: '123qweasdZXC.', + ls: { + 'profile::4872dd8b2ceaa54f922e8e6ba6a8eaa77b488721': + '{"iv":"b1Nsi+8CC9y8yuyMDo8ptw==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"cxWEUayLM5gKDjxdIeYwc1WFfm8CQn606QAof41LkW9fy1w+VwuN2QyQ8WKSk7HFnCVGsKqMlW3bzUUlzTAcB9uz/6V1y/HLyY8v7zjVFk67QFLHt5gDxnwUZTMPVsLjVd4ORhCBstekd5b6OL4jN/YPzCo4U2zjt2UdciKzARWUWjnPUj03qaKnvOnabtGcSDDdlsMi+qHNfsttJxjKhtu+Vw2S9Sl48BaGzE5dtn6uxABXYR0LVyfW9o0LSE4HlXzE+Pxs3CXc0hJfKsth5QLvh8XsvqHwIlp0kMsuRUcZ86jQ+b1+kdBkv911ppbdV2eFB2IPw2p9OY+GC/s3zCzaJ0ov/qarvJ4rq2yFfg05akptBcC7BE0+SpKRoQuwNpKUJRhdcjqzMW/8bEbhrZ/5Ucy1/9ijhedWHplKQvdbVd+TXtqhCqMjx/CvaGP33l+EMyQcDKpUFglQpw=="}', + 'wallet::4d32f0737a05f072': + '{"iv":"zooCmnqINutmJ2HAOj4SqQ==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"lUZqnsKuOgPXd/9a6m5i7wZL+rBJmubhgVDUqwbFeJqBTYq7pT2Mq2nZHFyblSs3P/nqcnUG8w3OXqU1XsMRTpgFtiKtvVc5cjIru1oyJE2MNf73gIk401q3ekT51nJ5QSSCf4y83JxYj77zLmFFOkxAy/nAlOKlI16OeQ6PawiihsYn5h+hnNLJfhTdBepAO+PD89hkdXgTwPdhnBzZRpG1Hthe6Y1R3T3X6mjxYaF+HYe8ZtgcJWiLhL4o5LUESnGcgtpTmLk0L986Wj0n231Co3y05F+ustSI3yV4viB2y+HGgHO2o7eyidtNq/BAKSJQ9GI0QBssPfpgj/DIzQlBNfuS4+QxldXyglE5Joyhpv6TG9deiI0uE1Lq6IHmuhg13zov02viRcQjt+JvUxkSx9P7A3OPot9zdzxXZHcSLgvzb9W6PlRyhGLBDjCbGwpafsW8JQ48ZxJ8rg31Nc90kGQWC3j7D8dtOyGdDKTImeAzEAycSePU1DzElGKwIgV24joZaxLJO7wsQbZidEpHndBBy2EAVLEYUQPYlo2HRqDYBycK2pEXerel0K9eAWOcwv+AprOCM0rip1aYISBJBY+C6+/M9a4evzwSyCtzLp2Tsp/kFosVlae2uhftsMqa5jRh8kSjd+O/oXs28LBvW37e1PUbthxQ+kpWkwyWLFIIH2gaey5LKGvNB+pzzfTqEEV0aLxnc8rYH8fQvApmVgtRDm9f9YCIcyRuPiNEAFO4q/dAjjm5+cbRUVOUt08M+Uwmp2ItoWSPeuPfUFHT2ThdAG1z62zRsFXbxq+5DNQHbBHMA58JeMvBiy4jQYPS6/FvrUNUx54jHajH3FfCzf8jxRqZXvHJjse6sg7grkxhObxzj8pTUhBJUUHIiEixFAp6KZpJNqNXuuNGOsXxtADACi2Ig7v5dtIhOZLilI/45hLvWm48YJWzqcgEW/yjDlU2d5oTFTXar6f0rbe4a5M8fcr00F+GYZn4xd+Br/Aj4buRhNdQFgfTY5SIf1DwavJeotYJRwaqLG5wpJCa2nx7PubsSc6UpHvW54kmHSoq88CF6OGvafD0VrVB8tYkJoWUpsqK/uQmWuskHaNgaPj+u1xGQfb893QDBtZWhdDE5eJWkfe+UGv0wMfKQLdBrSDVBjZsQ/8Qbica+zVWwL/z3uuMMr8a7YahPaqyn1BxpQdHpeFNrpdc9aC68n/2Os6RnhzSofrGy6mIl4ck/IXemf/Ir5W9N6nxs5BRW3qsL+1l2xxSbqHKiFjkyJQZA6aGBB8iJQ2H2KH+hcQZy1hidvNHEniusVGdIOzS+TrKsceVs5DIhr+OIao2vrSnHtB4yytZTfbvpbt3iuyIsSGJvXRvtNTOmZCBBi1byR5MC4vpdQ8BLulFtl2bm6CLvvCCTJA8v6oeXFSFJ44cKFtjiYvvykwNqYM6GxWFsr+6Tk//F7E0n/Kji21YS1MU7kU8wGEX3Q1u0UUzGqN9AyZu583UVAoevmqDw7iYRXZDu4GvvJUoWqUsb2WueEa83LjVc6sz07OB+6ntlYvI4WCwKrCzp1RBuT0qn5Mc2w7igiPVnVAot8X7iseeqjGyHml6kZ+M+ZWaWK1RZLWeGuBOIUKI2X6Y18QgELzyHFYfxDs3cOYNCNa64BzAQlEalp/oupZlUtWCEBpP/4KOeBWOL4ywY/geJDlNlDJfYW5lU/ze+h67gPWRM5O9S1HgVUXX/ZhlpGCndTphs+8ABGR7vY035JFlRhsbZREb31V6Cu5GDH6PPdwvX1pg6flzqf5kQYLgsS5zgV/G6Un9OIoUYRvSpeBJceP2cq5AX33E+kdNAQsACaIR1gfGknb+ZlQRgwhaaeOq7YRKVCTuJWm7hJ82i1DnAWTj0bY4Uqs+OV9XbopSpz9/Att7xJRIoFXAcICpgB2ekDwH65S/NKLSxWJOhHDXlDiE5aE5ERmamaGqVHejWCwrj+GQrg4YEybKfH3DhOqSBLDJEuIxtJOXneIyYyHZw/EZV8xVorE24d8pCDvmmQHvYPgeydE0fAbKqk6LdOIaA3Au2oELBpbGzYR7rXhZXROOsXV2c7g7wpwONekmjdShuBiI0L3KblRGt6uyc5iEPAxOXsECPJK6QWEoqUC3fJpJcP+iMZah+xeZsYMZRkucehP4rmJlKb3imrKTMbR5W2hRUR5mpfmJovU4k15r00hW2QufCbQBmTy3/9vohiX2+9pKSgqZWRvnfpq9SWLW1i8P4EmOr/PamKCp8w0e3PjX0wNu4E+bPbvUq/b8CQvaw3XZ06IGgQF5jKYCrAbtAIqzrJ8mwE/FWB1B0MwxIA/HSzIslKq+g+oa2lCv+2do+NCf+PnZH77S50/y9p6Ugr7zeuRgZuAjGJerPv1bBEm+EX0nUIq3tkAALJr7mckyq2xAkZHX4tm+SZ9Bz0ioVYmppGeuSDCtGNk3XCLFcDFy1BzPwRW0+/c0gLy28Wd6AeWTTAdX80vhRtt2Qk1zG8I7S+a9RJbaOEZrCZKcq75rDi6AtaJhrD1+p6Fv0v2xFPuUWgIhJ0Pu99RJzi9fovtYCu7TO4hsDJRw1zIMesVZ9cBVHVe/azoAqpCCJ8X/lkoAWmoSPnMdwnIdn7ygpm2rdUdRtzQZyUEj85hg3X/hJDSfkTcDfRpHTyIwPf9iIBxjyXuT2QQVJIHZVRUp2LxVu5r/6g17Dw/O9YeXaNu4wuJ49NnMUtZg2dxbU4TbZq5tvLLvsfS6F4pKO+KomkKuBbGZ5OqXlvYaO39Yn5CWEBBKZ0BwCq0iAEKCaV0xgvjHrGt7zIKD01g+/CdgAdIQGdoUpDVOgAXfBH52B8vcQdaUFQZRFejbhjAZYHfRYOdfgWepQuVabMG+AHjceVl/gA4+aPaw9rWcKhIPXLjf5s2iiIEoLqFKFde/bF0rJXGbTryonNyMR9lI6lEdRQRfeOnhLi3mvkflqny3rm9Aj39zrob8a+P6gf5rCdZ8NQzrKajhbbqqSvJhHGesUPOw4EhL7U5WvlTBOyoI6bxV52zwaakQkVxS8+anouFnCToJIgCptDQPhNj5BaGqVuVEemittwCWLf0OIGHllAFZDdwFZxKYp/UtySJ4Dt8uitRgWnDsSzfT7gd06aKcUKtF1Ebme0+lRTu2jywNI3iwXL0ttmBncg73PaZDJbjdJt0ihKcym9y7hkfC+aT+k/NodfF75YWH2UXjuq2pDdR5hX1eOE+u+Qs96lxlgkNiR00kFbJ6qAANlDsDRxq5O/KU/SP4ioJaSEzUYR/Dbr/WXHTCsYREsfaczBzdW5zlb5Th6JcNBzt8WBQbkAMW4ky236UzgpmPr14zrmDIOK5vwMVdjTmdn9XKYdg4TV1yZk6Fiy0c4KgJBuOTqFFa6weBY7dK8cohjNArF0tjgLhrqBetJZ76IQHgNlXKxpGR8t54Cr98R8kV1rcaKoz1OvJHsZj6G9WXe2tzg2fJ9oDxROpD64pEPFXbWZwYLMIl8+DBPHeyjLdqmqKoa1PYnAWOl8OeCLyaa0GdH3VizotzMapvkcwhJv4tUfaViWLRGmXJob8/bdxJiKNnong7VnJJ3czAxKHBK4GrsduVaEx4KsOpgnCG7Ttw0YbuIIvXEM0x1IJm4oyW+36p/oXi+Hm1b66en0dUrqlfXCtxVvqaxbXsB99poQQhhu70crQKeg85p0pkhiRSFsKb2e2249Ep3pY+9bLhfYdT88zL5fljFUZavoau13WMNHB7dNPew42QdwfdLyKZIhSQYvmOVIYBkcpRpU2SdVzBXdWQ32d2tFA9AIGnvII0QxLrUlJ1bRibJxUudeEuQzv0CAOPIjGpjHJsKGwz8MrQEKjqeEUCeYxmn2UVrPIpbwRnaQqDQwOwcv17359jwj6db5rbeDIK4S5QW6LisOFR5G4g7E0+8XV6SfUvbw1s2XApogF3ty08Jg56aq733ysWfcxolMpUzAKanztbeN39QjND58T6Q0aM3AN8MS0EsPmyoVSDD1oauZNQbtZGuBk+PyrM9T0fsNaBsdzo4FmYiI4x9I/UacCFQcVNvveGUhiChOw2Dw2tbIJhoQRV4tLeyfKMBu66VW//n58xhIlQvDhbTr2GpKfKG7pH4bY+HHnfDchYYHixSim5vWb08vnQo0P1Bd9en7WiS+8qxdgt0v+UoXQfUXyazgZcIXk3OKxbCzAknlu0w2dy/EDLNyxpYwEP1xpqgGEAiUWcc/ux/E/SasA1NYQ8Eb1R3jT0qgMVcy8UkKlhZ25dobgyDIvINN5T9buBkta3FU5bQ+UDNzBIthjozcOHiltZ3plyFl3TuZ4Ia7CV1GP09MaBeMPhgTFV0Wu7jbRd//5aGYjxfgX4/c+je0/hZV3NxFhvdQkQ5euRZYCF4vXTc80RgeIJnb0staQjAs8X4mrTjjhnts7tR/+MB7lnQNy1fzvpio6St66wZcmuLSXE+jixhp+ynqHxBw1/LyGSvZ2Tic1CcotFbK9BDYWxstIObJ130BgQQDNxF4AmOoSn9/tSsJ0qjbhgm85/r8E4hUm5kHq0VM3NIpe/TaHEmPWP0JfYL94UsoffDYuCiGt6JIYSAQ280v8095vGxv6uyyGBcB3Pq3MLA3XRgdj3drFymMQ45ICdDsvTMpw3dQ/IOfbX08Kk9kmv+ZFCsxwzMuuiKypOHoBz6ZND6ZoKvsLZzGu5rXDK3thS+0qeB6edpml9Xwi3VbUfHujaTwEcw0tY6CjkzpxNMoL569MYHmwu+xajmBqgD4zYJqtb4TKk9zWoaBOrPmdbOe3P/1lrFayD+m5d7vCrihxxQhdlIgmEs+oGSi9ng4txNKTK7JplGvK7U+pihJSG2Exc8DbTh0VmCsX7nGhEIp4gz1xLiaKngYQekSnilmACDZmlNxO/sJgrstVXPHBcYvdxwtXJg7L4qd1uHI5ZIOHrAiAps12HgF9dQ3f1lynX+7UbJR/aI24iJgiRkEeUW8Iv+peK70DIXqbY7XMljyKnJFx8Npbd2VGYrdrF3dydPNtLKcK0pPp06C5wgKC0Pg94y/UWSMaaAzjdYlQIs6s1RiQ1XWZD0kCIZAkf61gmZo4f0S9BTNZdRg5y9Ka6LluD7psQFVDQUImuRT+25Wn0XVmctrHW0OUjH+QM7vmsfkoqVD532M76J0ABeIbHxJfzomfe0i8OibR9yK5l+HO2++EAoMjOxT6PglwiTQBMgkjF6Bx/6ONPPCNHwS9jLqI6qwkuUYCCi1cBNGEfOkfTUrjFxJy1PUie0o4IM6Fj1440lt0Zx9o3lKUZ85ICuJ5h5LQ1qTeSnHN7/xHcLpOsW5wIP4JgVsYxFe67Un22uUyn6Zf6CF88apem/5y6EsdcQ1Ik0ZUclLm59jdT10FSLfsPc0IFDHR1MyYPfRUnMGXnlnQGp+Ot2ilHdFSU+9dRpO3wixPi9iryvOm/dn43btvjfB81WdzmHGJSEfXILIq8zEVynln9gP4dCDbLLIUxRlZX1HY5Fqde/wrw6GtI7uRrfp1KnSUOMasCecI+lNdh/ztsGQsS5qfNkPme4jqGlHgv2FT5R5Brt7o8fnstXjrj7YVxBHyyupqh+fj18phYaWlAhTTSHqP6Whk6S8sv/HoeVl0O1Iia9CoHgUGT1OWopwHC2Rh2FMm2gSKvq9nkhTyRygBeuAam92u7X8TpMICLj/ernMpIQTw789zew9AKY4fugos1O1g58gojXC134/jfjKlibVjnHZxb9sR0892uLWeBs33RWayMSydI22DS/1Kh10FGcm1buGrZHdoc7PYUbUWMhlYQbDH2a3mDK9IKxeU/j2/nnSjjs0ryVaQpoicvhu8LBISLpkclS/SMiNj6Yj+c2rkXohHRu39CvwgMMcijg1bymitQmvs5iXZzD03iu3pJj8DZwA8CRPRjXzfysQp+5lcKd90bVodhD468clywnvNI/ruEsPzymGZdwb4IvxU1MLaA6fXBSNtz6hp1OouZhSB1wOYsSvzbmaKWHWp1hShnlvK4gJVugQdOTNwsuuqVYM1WGFHsV3YjDa0z+kGuBe8egsyVQcY4rNNDzfetr+Lo79b+3izUGjmOEWI3uRE3NQbGROMgHOPfnmU3yUKF5if7Y5rEZKc1Hdlm4cY0TgrUkobTwuI5/SJr2+E3t4KXmI4Wdv13U3gJSks257X7IfHT5+ooRaE2oHD5Qi0LbiKYtEjnnPOVo26Rl9hHXoM4EJfLvoXFLS0tJgwpl3US4hss8hy7IuUPvT9HeEJXgdqX4YnrzEL871JDMrOe+51hEmY3M56X1CRHzhd5fOKXQR4QOQE163TKmdf69WlZNfx/TP2/yMbDTxp1txG8RN2aRzj8BCsf/vMg2zKfYAIijoNmcnRbegEW96lhAOTt5aBE2XvBsuWoPgf9s69yjsy5RpYZFCPpUbLKxNjO3tB28CE+9chZnOLS5CQCrhG2gl56xVs5pgoKfnFwU7rT5nv8KP4YCN9hmJeo6h7F+HumSy1Sa1Hy88D+cXvsjKzjhwxmk0vuguTlGYiK4p8z0r395iOPBn9jlyRwLr8UJyXAYSLpqgSxxU9HuTS8WWKPbiRFJFYjy6gsVCaSuiGgntikx/XxcP4T5Uk+VDQ1JRuFLuRBn6b9FC76zEkegHKqNqZQvNPGzArWBOhLbrkN7v8FCOWlkbLDhzqkVCSns+FLec48DbMHyhkUeIP9dc18yDHMVHRAMEjsrRYoiaJ4rAWXe+/2P8N1Z599RKcKQqIOaJjZi1oUuFBIa6UCD0q5cOu2F0+XulPSVFwyW61m28SIEzoNeAPIWv8bXMroonTUbesSRpqRZbSUwlWqz1eADpKo6bjBlD3dtdphyAOGr9BA3uMd8snRiWFXUC6bqOb5LF30zD7vY9/uuH0ARG4nexMi+yB+NqgCKUxZyGhUSH9utZuHs+qLnEVkPeQxof8pSo1mmviE6oOdi513LFhe0RzPLoRutvizLmN9HNfNsFPpJ5Fy66CsI2qEI79KKRkNXHEvB9LJCJvWKN8AUNhXLQBsXkfbkAUUxXvVI7oAhlTVbfNJpe1qC2rBFWbBVA/p2lKghoaudkSXl4IYuaBKIpdA644+VHbV5A1bjogJIfeVIdVXNeJ1ijjq0ntErqRfu4RrI32FHk/FWn3/LdDz3G5jQLRfzxr38ZMj9CKQw1eN83MVGnZjNXf5MKmTpDqSIA5mWsFX/2yfuzbUft3gMG0iCtosabkz8IuH4Ima4PSGIBglaWiKr04l3j+LfMts9oVlMItQSMH3v7QSzD3SXQNc6cRNOTiSquc8DBdHZlGmvFJClp+kY9xj5azcHPeXUEABrAmwyXOtdKLb9CtlN3GttmbY47jrBh/aI0Wdtd0Jyo1swlDQwpooBxO7rDSnj8vMGRvG3DlzKb4pN0hc0XWu19i89oa8QGkvm6/6mgCFR4dq1qazr5KZaM9/JLALbV3+zaAhToPKEDaiqihggMRdzbixV7FnGiBji9GPF3CytNUhXZUyzZPvGWkgF9SPW4keX7dtzdqHFRza1XFpRTtpq7idRiyF7UuivoRVbXhw5jCIjiZAXYzn0ZnOfzF5v4E/ERvEsxR4IHBy9Q5Iyn7YIzlHQfVEYZNhixBtzJQxRtfz31AnRVVcjSubpC+hL1HQdvWrPRovlt914OwE00mIZ+UX2Tm4CtKMZoWH1ApQ/ROsXdBV27sSv8XZ3D250A2Ylrs1H6lgCxVtdsDo/udL+s/9QRf1W3aupvM8+c6qx4EGClr2nsRHahQ6xUYcbVAkkIf7+FnGXUhAXRrOfWZBSCkqY+5/TxVbVZ1+S743gkxmWxBae7HktSyyMir2tk9QCZ5dRdxMp6ZgMiTRbMh2TgepACwMb896SzTngT8vhNXA/A24qDWYkEXNmasbmQqLzU5DlnGnmnS4mbK5WSiCA5s9U8ssx7c3eVTVHnYFo08ozmqshnqDB65wisLQ/KdvKtskMk5E7Ci3/vFaK2ByYRDq2MAmAwWHykDjdGKeoDAFpiwQz7O4PAHF6/awIRkkD2CPW8MQDvlsuzMmKuywdmGmIg2Ihrv8hyBLsIoN//84InWr/uN+mRLawYbT3JIjSF6S/nns4HePqnTrItHxhcZ84iG9xIYuDb160/kCuZ747r1iCXdc0C0peMnpp9aMC31gVYxxLjfmrA/60SM2g2Kt7iwwoo39Ul8YPx1OxwYXtanob/Ooy0vNJddHPrcNjoiTmUqEzpDk62ywWLEbB1YnMDZ+QOChz52Z0q6xcuegVC/uYzUrk7oaHUmptqgHvXphHD5CQRcWtvGB6dIHsN2gScnFm+QNO2F5S/p6bM9dYvtSQFsdkur3nFFrSka8M9F1BQmvDOEIk38lHLuGo0qAhNwaJGK15F6eIVXkhyp0A1zfMfjaKmkA6BTb2sPLimwI+GwsESO9xPVcGa3ewvxo8u9vhm66ciNm58QQ+goO5SjzlskGFM/hxYZ5p+3tEzl71rUDFZK0UaSzAtYR+vEuceQKke3rT3Qor9Dm7HFbS7F9kNQ6nRfcb3KGq32iJC3nSfq23z310xSfn8ObGS1PPbAHpjkuuC0Q8blK6wnur4U3TLUMsRglHCBOSWu/MHN4bQvG6rB98NFVLnF1tk16iwbmulReV9Ma+kQXuYQRjw9dq4jS4iz4b4lbO7H199/t54LfCdahBnZmG2euHmGPNiiEGVxeH6IUV0hbZdAwZRPmTwXjEPrfGa3LTAjKk0/ZFjfrTIlNoEJ+BoxdhcMiNB+54fuCT9i0brEw/kmUB1lfqXse8MMtlPLMfiTx4mKzmyKZOsUBJoCnCKMS0k6cAfbrznGQZkDth0BqbCFcj94gjyPtoZyhmv8n8xY64X40hCyk7DMm4Q4SUpYmLW1IHTnHWe0zn845y3G+t8QzX4+xtuk0a6DH6y9iPtyyJZzoAGPMkkO3kMaupHtGkFmyip1rXgezFkgUy70x+rBDgxp8jde5KmXsV/9d+X8Y9bMHeIDHxxQuhGaQn/zxge+mvA4k5BTlFG2kIz+foD5yEw4oeLpv3H2RRGFB8F6ehQgUEkAx5si3VsOjrXyVVxAmVgD6r44Zp0wJdA4PVkNfUOSoq3M83W2FTpud8ERiA9v9MmT1HP2YNASXyJEyqk0e55w1xbkJwYtd4qIk8dOIlKUl4JweNT7qlbFhGOajAfX3td/NzijLNwJ0h/o77niS1UF1nZTu5l/Q12H9q++UXsxNrNP5zG7W+S1FbSZyQijTj9E8Oo8kR/EdfNkY9xuMu7wG+/B2mvAwhEEqzK4UCyKi14WhDsXA+MA36ufumkqFCR6poM0HNs35q5x4sBLZjecZkBvNTIXVmcSWtQWjFbDok+bxPyW6KVcZkhNErbY8VlAqW2keBDw5AezER1hpTmyHbkJs2u/OkZjsJWYriVea80PTECpigiWt3RgsRH8J0a5pEzUnZR26VloeYB0ctve6rDtZ/H1aDdFOteb+O7qEHmC5YdSu5b50Ts4+8hrrhHu9BY73pEhpB6hEkCX6DfCGBBmFgzwUqLnVtJhdee12xK7AXjfRDHD74iyKSAZmeDSZiZ5Tn99hZUCrzLMuSPpuEm4ArvkS0dOYmOj1ed1ISRpkngMNhQBnejcKlPJJyREUU07KgiHEb41brTeGujA5eg5a229WSkqxiGdvNjqctLWurhZiVGgZL7QFaenorCYa+cWRdd817mm0AmvZoasNkxJjidD73umMd8ZdgBH6rvo2XxQGVrHLIy7F2Hf4CF6ImsBE/BM3QTiZwYSEjmc7T/37QeK8SSmns7BBzYq/yFtzny9qMYy5xudwGgGOSUnOUouGJZzZ0Zya8sDUzfhLfgmqg6mbBIN0CE5gwW4lakADENplTlVX19VA0H8yBZ4J2PPSVzUlqfrmIun8g1o87EudzNUWS1+REJ6tLdxzceHSTd4YjRtoQZ6TAPROGSpLZfBq4bVadBcqJOzSsk4XmPTbdo+rpkXhmyRVylYM7U6UCuXNdFMLroOVgeVFL9vfNtnSqT9V81tlygAP+W1qp8y0kb4aD+gy2OsZejOKVHqU7GGQ/jLYKTrO3ahBhA1Cqec005Hy5kNpgv8c6Y2i0qFg7CiBVp2XNQncty56O9ftPoDEGtoqqghBesSILhIu4HkF5pR+rubyO1Wk3UYDAryfgtAtPEtONy6rZoFoZ92pH+FI3L32vHiOv1tNDnf2OWln35bFVTJ96HyLx2KdgcyIbpD99SHt0ODCJr9u/lnxPYfC7LoOHR/J+NP+NBUKxqd4xrBxbvQP/qm5g29xyY/8Olec4+dWv2PwqKyKktGmF/zbxdrkqOK9Eld0DXUx1bPNVkUXauq9LZcacr+5+mihDXdPOJuZkf01MogxqAwEupDW5ccwsNEpi9sdNeCIy7CTSvj/Llqcaou1Bu9xv7Gay8HI7rmbzZNVFA+RUDTtTcPdmRwfGRO4gR8KgoMZT9HtX/oh2+sXBWgLNq55QOLjm43Uow0CPnZQzVKULpiRKUuXVu3aKsBooDVDmGuAxrG/Fv8jgrXbg2SFYRWZRQdC/xOPjsKahzlEt8rmF5wgiNvoR6QCcEA5e1JG+3WeMHzeF1GHiZMk9QfwpiPWoaGCbsFzt4sKYcvKsk+ImZT1aLp1zkrcGVP5ozNvWSxFAnR5Ras7kMrDjzbVPmcuhq/3gRMn9Q9Ip2zVmkFSGfifbr1UzOt7BU10JWIx7kwTcwtKoxGAdEIguZi4hWSN627CsV8sF4ymSEkUjZeMpZ2JkixWNjwtmHmc+YqV0lSVyudIjt9h+K46KYXi6uXYoOU5Ku9XFJ0Y9z59+SW0G3g1Z7VFU3Ea26JIao5L4+idHWjllyGUzMkdPe8ZH3ZlzKBbwXtz083W+fMNa0awVNtpT3kgcc1J1pqkqkK2/F+fqxLy5i8kG9Efyq6XMNm6GyaSXaFitHkFsQl9pXXTLl3hwzUcqO5VgKZOJsDZb1eLZl34dGzUoaPoPqiKXHyGKV9htClCQdD6swOavCYwNIy3QFtIvNUTUkbMywnfYT5GLELDJfywgBCT1TIXyzdplT5iw7F1WOB4E+HLHdekjBtW7kBrR9ll9ujk0Z++aBBQFeas9ptCsNfKGS97dXeh2fYHnB2w9wNWoF8TKnUC7PmRIe0ajVBR2gs6EAga8xd+mZkqmzqCwdvU3LGpeJ0lmnvQ6/PIlBel75zhK6ib0n6PAUdCziVJGIkDn5dTkbbsEDSCVpk98e7ufipRGUlmmMh83R0qJpHO4UyG6+yi2vy+HPbhHMoHusMNlqq2V9AlbqEa+wHo2x8ePhf54v40TAQgx+MnAtKkc4/d9TA0nR1lav5LuO50ns9CzWK1ULwSUscsXXgnXbyOfjf4UajfsCj18GowvQAY3V1zpJm6TiDNXs7Jgbof1c5hV/f3z5hePDGmPp/jG4fvjfhG4myBXfYRHO2o56QLMInZLsrE6fViZz0IC+XJ0sC2KILh9HtoIu40LzkDVgifpU0llqPwBlAoYtJBV+rI+ieGVak87v209svifc3De7Aso0DEkAxNYT1oL+DRaPEnEuheHfX5fIE0P6pZnJdPzMsyvAHOzN6ykNqjw9ENl9DcnEWOGAAC8THGRjsbmERGELu+2XzuoHd2Mmr92uqnCmyj5HsGj+3XOnKj9/77K+l7orRzo3RYJEQvyIXEBwG/p8SQEIadRR2aoxWdYWNJXnRhWcbHWbqH76YBqqWg0lQVAVOwYkV8R8+Oenrb6wwu7QNAKn/XrpdTmw2/taakAPkg/dGzqb1Iik9CNI8n4+VqusQay3fc9zlWNt4FLvqEB6ISULluQpFm8sFvR/uet5n1JPdWAj5VmrGGynavSk11jv6p3yWkbtTX6VE4LtErNDgktUkJ+l6kjDySADKBsE6qfOGPnqRJwhEeEi4ulZ9+U40EvtvO6iL8+V6r5LLgclz/Fc9AqRicVRGenOq028LVI784BWOvFYiW8Kwy46nwZ4NMACSNEQshRubXuT0LEmUQWdyPlssKs7ioxZLLz5si0rVUJJ7vUfba+QYFcAWDYfAxF9zXROIJx1sTIR1q+oRTF5kSoBtPHrO2bNG6k6DkJOlTF8MAs82LUtmfqp4EZiaL1v+ETYDTFvfFxI5BFP+Tpyco+JX8P8rHNU4nsIBL/fbGHOPusQsjG4PO0XMI6YmgqNe3XNcgzWpLnOQp5uZ9po9qbHYJwo/a/kWshsqgscxhp3tce95owI8NBbIuRYevy8gcPYzS9Ka+8Fgm02TXxBBCWDk8WKrQgGHu+npgowoKGSBFKBrSR9/CpcwYAHVyi1J2Myj7L7myBu9sVQISazh9ADQcEAxpbZUipEX6TBuv62CPHkxh/Ye/bycDpN2t/PwoxTh91w7Rhq+1io4IGSywr94Gs66+rhsuSRVGYeH/T7k5Bp5yt3F/+R4Pg75MarXU/yR1S5560hjRYgiNJ1UPfIMlyt8IekaaoYAzF3ooC5sYzwTmT89cTH22gkH4hFq/WYZVvSUm/1jgScoIlf5sSDs4Pn7vK9BgXyD2AqCddyeC4ss6RXO+VpjJe6rfsS32jd4V4LE7ohZA6bgTxsfech2WTnXH0YjUlo423AzBMAvSNJ0djeULxt1F4XcNw5s87X9Ps+G1t0r6smgFIhvndq//uqutHlNiJZBOaLJBK/HJ5X7D9diDb69UE+msE1HGfKHBCGO4qcT89cCwAX3vFdsCZom/PLG3hJ7YJT+NxKV6g4UyJjXdRKPMVYbYHRYIiCZQDi2buCh1oanhp4f9gzscoYKINeUG/4E8w7NKARYDuGL5v1abzuvyGm6aQVkpskbLygI1s1izFSVUkL61KY+AALWF6bu5ReiuQ9OnXJPmiplj+O3Oez4KeCqVDIFYapzFdBZ4jGejyZNJPWdqHZmJbE8diQfvMZ3KnpGLoNeuuwusvOp4AkvDKzOXwJofSH44d/lrYRGdWJXp+Si/4iHBMFkJdM663ULSJvizzjAHZXfMKrYVUtTEYWYJyzPSJc4t4dyz8k7S5lFE8LwKX8fQMYAiLBcu+d0b3x1+AarR81SdTkk0wmeHVbcQUwut8YwhjfNDmojJ4JXUNbwL1VKdEYuKW+ZoNqpB2OfXufj1fSJZ8kymDudyoEpvyI4L86152inC7S0V8u+q1S6NLFoTokj5UKl93hACL3z5dg9u/IMPZbD7Oa+xqp0UcfJzBNzmQ5Y0nuS30xNJz/UKH7alwOlkB/B99ibJD1Sxa35DuUUObD5p6J+TShvN9NGPVKYxrcXscDZAeqVJrAEBJXDJ3sGhEfR2hMKVi1AhXfGwv386jKM8203eKWZdcsBXfRjhaFZOeesTdk+mAyTrjUCpBBrIDL040nnJ++zP88YbYWVo/oFPrf9rG3VIIOPIopoRMl/PJwx6SW+YiwSkB9sYJEqGyO80IQ5R21oQNBn14mPnemz1Pvb2PFy2iogrweupsbH5xhrRiFvRpSt3I4id8k8JKUK40JQwGvDhbyG2HMgZb9uo6U2tvtwOGSZaMv5WGpZwGNKFoTiiseagYSjTLG4TQQ7rNLdbKlIcgHiXy+bBaLr8ZIdR+10RuevP86YpZ9Dy5vQI+swoKVBnDdMzZiAvBdssVvTltqMYWelp7tvzCoJ6NK/eKdI="}', + 'wallet::7065a73486c8cb5d': + '{"iv":"T3mXsRTEfMmDO7yvooHuSQ==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"FuVCpCX/iTzaiybPgx1FNPgpZn8w/QDupofYJaYvH229izUpR8s7pjGU1QSBrWqOtuDhA6fofjEAmdRliMv0ckRF28YGllXpK7Wvt3H6TENz++to1sUfNtPq4dl7jXsEFz+8Y08KzkirL+kAnsmIyYL3Jhi8opKOWLwX6S1yf1ZMZYt1P5XgcPF474MXvKLptuDWrX/e9aOkUXhneAK+1X26ghcDVgbmMWxUxbYJk/QcQC2fHAFV75G2hMzRXjFuBT8zPeMJ37yVLBdnbG375YHPInKOf5Pun1xMwcKTrpNW1pLsNU6zePvaTNMRMnjOaqEBEeey6tFO3tvA3V3AAGfPowKzN86QmjWA7Tkvy/mBa0ZDd13LvFKVeWZlFEkTkk1FoyFiSSgHC3Iodk8Bopyh6EYJNs17f8cwzpEWtg43ekLK5v95Lj1QXaEepOFNGCyPpr0nasoXo50J5hu3Ksnzk6XW2gIskcwjfwbVogLc6UEojx0puDRCrlHtQRmWGqcI14S6Srcc3aasCHqlmJ8nODvBOQ+Jsj8BkZgWgtLcJlzkr4p3X4oOgh2VJL7HpjIOtUZXdAmMdYStf4WEqZnfuP7UtPHmjaNEnOY7y7e2NqfX06iibUbZMnik3b7aXxGSFbY4623iVLHLzu2RmZZLOKzrbGPkBhCAq/M8oduxr91GbSuNK/NcNo+DDtBXsc7b3hNaS8sRf37kx/DbvY7TtGpBcRn/qXlc97zfkEZRQ7dGKAf3vyZuH3EThXdP6qc+hNzbY4HkCFt41wu9qX4B0CQDonSGrTBQdXYbyQRT7/QEtul+L+wGkX3UR0JCXxXiGd/RyTj8PFGOx9E2emrIr34prZVI7eD8fHxRER2c7vhF8ZRsZ6GHyN2zzRSNmc6Jxi5Vq5Sk3hFREmu2Y/dsbgyfxHEZ8/ZA+lG7DmbHtbWecjlPyGHG1DFFpPWSuFmlYJVZ+Q5LzwKAHZWT1/QTp/xWcjvYHWtNLuv+wFm4Mi2goeXs0lN62LDCtD3kmWcwP9n36EDNy+qJjh95SESw5GNtJrZHupilbATW9kEI9RmdZf/vi6qfJrTry46MreFI7rjRquVlMW2BRSc2ZS3yMyPPVWzOsPNIozXOb30PXM2Sqs32hsjQiVCaloY3iXHmTTFfaKggPCm5rMkLUfZ3E26J3Kl0AFhqScc/K+FFJZ5RyoiFp/0p1nUFIu0+M+5ZDYTNKI9SvctAyX9N6VJeq1SwXvL8lnlYRzcRf95ZVgz7KuzTezhoSNVzrlW9PJ4puOSNdaqJdh2H+hiVdCW2gxIgK4d8AiZ3yr/iPnZc1n76NvynNnHl9F+FFqiMofP1B5vtzI9QsYTA0mMJZeiZW9FcWFnjv95va4vPzQheY8Np2G0O/ADwh2oMXwDkgKbfiWYG6Vu5ydLD0/8IoLYyqO6Usn0k2xLyauX7zW2VoW8ltxRM0hDAqT1tglTZeafoN847tSgYpbcRpktR+hW5QN/Lbw+LWp0iI/3w4c75gtgIADLf3ii6zfHgSqpdtLPwARn8ThyguPWUw4TjOMYExrIR4YwPiQ4LhbAKfhY7ciFLn2YlRc3dmvpqHtdx9asIg8nK0TfMTZUAIK2BCPcVjNcLUagY6KzcA9udaptv6RkzVwlk1SuQJRsKOec2IQRlTczj71i6VUkGI3PdCt/Zcwgd86DFskJa62k2yY7qYY1kwZ83rQM/j+kzvPy+Avep0pb169ZTYE+G8E3BVJMGKlCRqm30B0507rM/tih01Ht0SFhzMH675pB791VYNqOkAPuVg8VVQO3oUgKuHbedZgdvv0xXTtpSzQawmKsEQ2Vk2cNi138p4WrcSTg9sWMDzVazZ9PISUl4zHaDhe5I023c3koVH0FBSCw97FhdflDRNnSSZoETOD7vEEOW1zUM6lrpQKBdQweqweWb+kbAZC+W4Nyxxuk1xMZwo0yf8BxB7RzoFsDDqqfPpiPRE+VLgIJQNAnaN0G+AKAd0B3tmkcNTfjYn7UXl7DlSxit4MoWL/MUbY8+Hxe63q4MlhDHmKR/BqqgGhgnhng0NVm1khvLU45fLXIXjXG5AeH5c7zIxnFlIJhC+7urPd1dJyOCHSVWsRCm/VG3kMyMi20bL7HjHCgQ+H8k5dnb8995ODBk+feg8RFGxqSiH141gcnqJTZxnwUNKfQ+9rK6hLnVBvwUFgmWfUgFtdw1ZQKE31O+JosC5MhEAV0CamMHH4Aa1YbcdIOfNCN+/Chb1h68mkkS8fsuYjyHznZLc55uAWq5pbbgIHIqzyGKEr0FX67q0Ax+NVnt8g2esqmqWFOXuWmIVaaG2KmwwB9rdgauFpBvcb2m4ExA97GYLJ/QkiAqlTuCiz8PGYjmqRk+EqSQkmRnEhX8wyTr2XNA/ml5S5/mqNvvM8N0gryyUEwUqH0Lg7I1lb6modmfL+z72cbDyg4swXQUT4fK/iXlIU2CAsspgUR4XzQSGEw8NV9dSZX9Y9ADT3XVVF6E2JQgEixMsfrPlXiFLHMnlZmLuMNSAKhuLSk7CHvrI1OY2fjTddXJhaiarT8Lsfbx8YLTau+TYb26JI5OaGH1z/WgH2gss8J7W5C5k1nft+K9R81csJg+35wm0BQC/hylhVJqkbfgL8g/A/axALyL31SaNhIZ1xfhHiw8MO/U0caWTEXH0vASZTi5Q+R27JqqwW6frAdrObTD7kuch+HU22brc4zu1yvqY5B8Rm4c2MhpivnU2oLL8rcVVAlErMpbLfJb1XItrgdYvlTYKGP0DXVJjOUA70OV1fqUWhNWuGTVoYGoscTKMBmoWpN3eivrNm04QhAnm3EDT9glq2uDL3te7Vaw41m8XsUsJdhkYG1jBvb10igHLLb8Cw58eK3XG2xrg49+u+VBjjV2uPZ6l/gd5JSjJZgiV+RkJUMed+3WnA6c73E3zlbwegxVF/cPd6hqjwZYrpzbe4B5kYEzC6/0fazeOXtaORB5xTXWqBr6+HFzV8T/6G3I7sdVWyXgsJCNtYajcmN63xFIijVOSZ56qNEaIbnse2Owll2xS0iB9nHKML3hyT7YvPWuIOXE1qGk9ayKpDlnCR0DWzFAN/W8PhTE1oIEHPWPrypS6Vp9HGe6cwIaewKRoFvLRzlkq345Cx/ahFRBGYUQcLmApdmBcZ2pwW2VhRgplFUdsREycAaRdYxJepYI/jnnH3upbjo7Wy8N846Jm0FFU6jrapCp84bRRmHAXKTFvyZAAKLhiKULJ9rUh/Gu6xBV+plla7KSKz+3u54Sjam0drlXb4cp89wRS+P6nRJiFvI5SnKMOhXLowXtdJxAGQtZIrPxpO/TQ4+kAQS1/7deN8x+6sZEJBfRzCxSAMhTEKNxvooJ5r3USMEmmGN9tUVdHkF2scaRgKVujfT6vFMrdfWatYxeRgbk5cQAEQ05/uwsOCtzLVDZevvCTZOL84IePvEsnpZBYN/SobwmvDCarpl+lEEhMFYPJMQQEHW4zPZ/XQR3YyUIJV+6s6kaV4a22vBwFMfW2ZloBOsxZxqMGY5MhPO1j+jJcyAaQonhGliUnScSRQrVZDCKyEOnq80d68jSZ65JFD+07OxQqwUuzLi1Mw0wmM4dVwtUavI/x0WpCGUU++Lh5fcpqU6fCUrEJzK/ca9Kbd/fyKTdReVP0sj9282CKLi6pZRQwYQgMuhd9OjaZ5+ZEwX0vQIDH82vMcjR9bu4OksXsVaKk+A3f1W1dOXwiZYt4cusupD/9wYqCFBLlzb0f6I0r2zAYvJz6ko43evE7JwlzrcVKapkZ6zszWDIlNgsq629jiDkuzx94fXBhtuCH18Qx1bxrt77UgcnteRHzS6sIDQF03pdZEfuOL2OQnOzU8dlOCfMZZVDAOeNIW6pckzEeOAdWhK7oY1YQqMV2oKc8DDLmjzoT9+S6s2B3FAUNplxBufMA4zF0Cc817Tr7gjNSY953ru4q6WEiiUFwj7AtCPRE6GCZaoGtlMWh4RUTUdlla/HZeJu+SBds2ecvdbkuBtarBfk3NVVLlgpBVd0wGEs6PdMQU+Liaq3SIwEdqeFPoxRzVSv400BGtUgEV36/fsKvMT9iHF4RCVb9w4rwJe/OjXZexfMEBc9/kTUYOnU2KCkbfOz92ZxTEo0gAAJbszY3lI/N9dpon+n5uEvUlR9tkAquX1jKeN+Fav9bXF7BFJ3F1saHJ2EVXtdKUt4aa56JlUTlSBRTJCoJXx558eGoRqgOCQOp6k7+TIqDTM65OuwQuBKaZNFOCU8RGzot796ans9lCO0XVbymMKfqMFkMbrCrQ+qLe81lAIEq3HUXCAuRfeq8/GANDNygbPkHFZZO6pDXCneCMUJmZlU0ehJfPdVkH0owHO2XcdjwRWRNQqwXfyOT5fQb7Zu9+qJMLPlrYTtRKC6Q8lMxW+IwJ2lBPU7xdVDW72Z0EqMQb7KX/ExO7SXQfzbnQP6FfY5KlcPpmOkwhP/1EI+fah5nUgwTJ/PxU8H9+qo6U6KSXG3POPKw8FdyJFKE3hEbhO2iUcCCc0V9uR+zwL0eVnarukaT9tbnwDaRizWvD2O098nDWKpsyXl6ZANac1s5a6GOiZVB3H4tlO4tonU2jA0RQmPKQQuZve4fPtzyr7thDToINRlVMzHDLB39IhNnO64taVs46F+adHhsRVmx815uUOpBPiZq2CB4k2W5qAFncnOImUhdY8gK4DrdMIwo8s06AKLm1SZriKlOwN5RH6H61kwGoBCSGqHCDvW0Ik+BCkqTehhjv7VovzSyr90bhn1ghRV/74yA3u+niMbbmeuP4oPjPwXJ/ryzdp55eeG14KZ5xj2Z6/z+L3Pld1CxANnbKX9fM7/UvNAEgNieCYSkoTS4MAKKllKbzoTpDiSmq23hErw9uFuAcaWPm4IMmmfvVfyCm4PpnhaWAOIDwFBrvUtl0PfqfQ9YzzKUGRnrbuSpbd9mU3zDczSzX9IcJDhnz8vs73g7ueR8KZRaLA67Gcn4X6/XzwsJzn3I2UWeBtRDbEgySpfAXLtxTjk2gY7rM/Ws8PyhLcLOt/PoagoSQswpSa8C8TZScySBx9QE00607HwbL0Vgw5pzaJNadsfGyTewwPcj+xz1V3ZOBdbmCeYsmZgdpExYd7nMt/2/1gVTg/2/a7vhdd21uvDo09AgvcXake/gFz+mCQnKBm3tpXORU+6GY78kPykbSrIN44p+5Sw34Gsfc4mt5xmp1XLouiqBuWoj/sVKimnwkg5wgK0QeWBbD4y4Yx7L9b7OCzShmAEs09xcpL0pTFceCme0vXdpe5wU5THkh0Ks0diH2Ug2tssd/0pDfJmzw0yfKNxw6oM4TRyQFmVr3mxrDXy2+IaYVKNzVBBN21OS1OaJ4Llo6K/BTNWu6lxGKO9D+I+jREvs2SykoA4aNJB2AHiqTq/h52BV3HAAudjFsmsLQ/aFFBCjH8R9Lfuewq1s7vuGMaPdFAgb/q9aDEwZ/Ovl3vhTLtMc7WoLMFQ8yv4jX1//zC9/WQUGjINBE0ow5htKpx4OmaxUuYgd6iOwtTJkN5wbmKwgO8zoCbRaZjHfSGUjI4qR7r3c9jw3bITvhOp97E9nAv1oUvXwFLT+UwmpWokSr+4p/7APE6drPIIYEm9In9siGHyqFCy4n5HynKYLqv8oyyeKzOmyr7QmMtilD/OO6+Z5NGlQmhFxxR2uOC2Fiez4Ze/5xqunQqIyP4j7QjIrXxu4NgyrRlmkD71pyA3cpfo2UHFOkA3pmLy8Ctryz8xqt/2wYqzeXi8gPd4abK8L6GiMJV/xvomAWy0HAn/FdHZMcwd3Yja4xZjhxNc3sHZMM9BoifkZy/UfliwgTcnvxsf3lO34Y9JZu2Y0dxaVUoMaL/xySD2tRrGNUPvhZIkR/v9P6gs2zTPvoWC4bt1e3VoSRWx/gC5g/N4ORftOgMby6WKoqTz7wCeMNy83sARTlsuFkT7ipzswk/oaqlbSqBRfkX/fbyXUWp6o50k3ci7ulcslwoRIvssw6GDlW8fnrcnLCu6fcdQ7vyiMZytI6qWqDIY4K65hSdhcPSMyYbBwtZlPy92iL9NlzSlmGsTZj/OW1J992u4J49bXG4NUCZ3y8HIz45miJAiOJ73xYio49yaNOgzK1TUUg2Fm+Z+UKeb0Tw7ARgVnC64cMoAiE2b7bPhGeSRzPpgzxqzASEiPEP5y9uoCEhbtwE4KOdDUYGZlFt5AhQTRkvjN8Z3FCZYLGV6VRePlZlIu5pta7y6QmlGefwWds5PtZYuVUV3QZWr00fjYIMHwZ3Su0ofpQXJPduuIqmQIX75YCmzIo5RL4t/YOD/a+98Ga0e04lmo5ywHnVD7Xt+0Kc4ZOUg5OcL1bYIq1HCvvnochlwkYb06c42HGQUlXDZW+P1Y2jV/1n+U9qvIugYE69CU61t/oAlUABCc/FAuMuTZ/DFvWqXa2uZGhMfN/FGFzCEYtGJ0FVRpOfyrpDQpuqn/57Q29lELhivlql9XVz8VS8fb/bie0fz9B6najk2AgveRIZGWNFRvTidxbD6iVQ5BU2zBvec8zeGHtwQX1ZP0OFQpKDOLLAuDE/hl4dgRnn9J8UboTjITklgOIsVN8VUrXhvFs3C3fLnq+ohcXtk+RYfb21hTvQFMFL5fneESeAyYgMmpfMqlnmDMOtfENwzYJqWEl33XPYWxFFDjV/gRt9zAqGF2X2lgpp3ZUzz0bdtv+7bVW1hjhjYJYGU4iX55PqEv3+foSjrCyfDrSNcIF03uBWrpzbL4yxQlaTjRiY2z+ApQu+BpF7EMlBkPBFTq1OtzfrsJfMnU80Z0N0U1JUUweXaoYU8mT7NtrFr+KAbLVsPPrTmQnrz7ZPNfW0nw3Ei/L2x7vViIYftR+1jrtu2hmQgNJ2DoHquGzYOA3wdzfg5JH9d1yjr+fNSlnG9Jqy6LGHPIfK+yMxZG8NTJSPd7MfwGsOjgN78cMB9Hi9sm7xwFmdX+1IV99FQbgQuZ54cCk+ubqOxIOZzxgecvJH7IMGACFQ51Gneog5YLEQNj4VCv2el+LQUD46dCKha58r9YVEApjLpUErj7EWfYmmL2LTF4seIjYjgNYEXi8f9Xbmwnvw0DVBj68jrAsMxRwEaJs5T7J/oTyF1T7amoqirg253Fg54XO7Rt3qb1cG9RNXas/sm09VQOesUIDe01MIVBxNzCVu5OsS3gIpsGotgD/XCq0OrUQXN51XCdYiW4/lTxC8tUJCyMwvNSRX3f6pQK7ubNSBP72u9fVUld9zuJo1vfmrZtub4XYUT7SWpf+YUknVOSRJme9rOhCf03Iopi0uFge1o7GueBWOsWDaJCctimtLkPsYt38hb1spMIUpRQffbCY/T1eR+I9NztqRDllUYzOm7/KfBsFfMzaCxr9UGDUmHVHr1N3QZyonT75FrAfHGQal6hgLA6P3kAZcoC6Ba+DMD9+TIquuxZz60ojJfhjGOu+pPJmGt13pHGSRWKPvQVybopy2+/4jp4S0FhzWW+7Fd6sVwKqU3hQtov4vXlt6DMK/fVw/iPqbbxEf2Bkpg08TaJ2pX+wP+BN+174Fx8gzBj5dDkgn//0OnvnDj1T09JU6cxeLzfd1rPByO7/D5MUEyE0plX3GlPDDLt3WLZs0F4zpJO6Gr06Z8C1HvZvAKwRcZGyGEqbNSgqECZ3oZTyqF8fcrYpd4jTrPxnlk/0b36Mja0wuccSdvN2xV/XCY8OKoU66jaZLeDszE6FxJgcGoJ8NqebuACbzLMUkkXZu2ST6w8eGnp9v/jnXNKdA32IMwk2XSwhVf8E7ioLBFrrQY7i5oxU5T/KDsdQkGsTIqY7VrE+zsfPXMQF1DEUJMsHFdBn/umVqygncktdQV7I4rWYlgqGHwmRkI3n4xdDWzEQiufNwO0C2R0qpiIXWMGy4xomJRqHgjzBp/XqLflKrZ/B5oY4g+cADrv35pL5DW9wFHTdIIDtHneR0riSt1kXx4/2ZxAYNEORRgxH+qihmeygtpflouS6HKJ0A9Lg9jn+Hi8pwT48VOX7Lc0YRz3WAR3Gn40tMEh7wViZKAjRyJqxmy1r62LTMrTUo1d0gBETHoSEeSn2uD/aR5dSduSYaOj84AsbWmxMmsCji3IxUOwwV+iPItYRsAA9tvgKtbg/Jcqa7iA8SFVuY47A+r/d2L+pFueCifrIeq/M61zxDfSoWTq/dyeFbDb9ClmwnpcUmTwl/Dj8J7lQ668D1HCoTXfMxSyrDSsjKpMyTNWgU8wRRbEnM9NXutc6gIJjBJSdwDhkf/F3XnTOzpGMCxW6RVF8EU8rzB28Biy9YmyjRfCjlEdMvo+cy4wM0j4ar3Nmr8QhNrB45lXigKKn4urneJjMS6AVEGAgJhLEojBwJIt7KjVqMDSENIdp6n6SnnECVuqri2L6vI87l1/UeIsUcHlVtcwlbH39WCw+GBVC7vvCQw1esV0Vo/OStMETqa4miKSr7PvCB25HZTgquVCWxg9B82bSf1lgwG0T0Z+Wp6zu2djdXrARVMu3WMghD75+s8pwfWjAs7m0TVPu1DAy4naFcjBWvjL/j2MWUsLyxszrssk8sLKg5AIfs+ZlCdJqIt3k1q8qzPqSmSCRZbARxmzAxiSUZ5Owfyp02m/rkRdFPw/grao+kLWkNi6ZR+hBI0E8tLWexp+RzSeDioErCKZdjkYwGL0W6yEvHjq9wNZqsYJvoDUksz7ZL8Pd2fGRrCCzt/HtcdhChblFG6Z93kigUih0aKVDH3WpLxnJ002d4V9OI/hGCQnrtb07oX+N8Tsh6+HRhd0oXKW2H8rceqxd8VyuGBy3BlhSfY3BckeVFIk16tkGzWmrV5E4nCFUMZB8RpQdpo7qT7tUY+ym14HyTj7EY8IW3Kuro00Nk0JttSBYm8OuumVvgGCC3eGAAgkAj1yiSBmivtwoi/ewl6cVPOjnIdAfYGHaizjmXRGLlsBiALyXRWMvICtvO6kvNKtLT0z0FXw+DlPMaIfSBTBNE1jfv+QJmLSeh+HDJXD6wfDBbiTw7WgDIBoPqFjkQSqR7IPmPotpD3i40JZCyviQAWdA7znEKafefGQ7uVfCOdUAhTCx69OtUdrtZffkvow39y4CMTLfz4+1iFlRSzDJv/Jz2oVIgVh49sRVDnvhYRse0hfJH7baOXNuH2bj4P0Y5jIAAbI0Yf6YscGjAhUp/tX/ETJHBFajiIDMPouWKphasgxMlcIoCjPFI8egG9fyVZx6q0LCXo6/xDLqWZkn45gD7TmRe3aNqatP3e6UOLnkipNblj21+s8/FL8bYk0wg+VJmIe1fT8GZ1ycncFC01Yc1shP7KNiLv92ZmZ5Yl0on1ld7uloZUZgIkeBfiKgkBU0B1ya66nrKQhzTJPxFQWFOuBPZzO7QHkbHFzo81JzmV+g8q2PqzVOxuPRcCnHm0FPs3XdB+5x3oU0+og7EKCMevK1VUmx3A6BZ9I2t7MCCoJcbtqBAZ9aVVpziNk/XxqgZ1C3ueZO7DKJEgmg22tEuHaHhK/jKZxxIENi68Tbj7WVijdspQ9bvRnESnUjA+FEw9owSj5Fiw0TQAy9pxlEvQWkb2RPjEDgLXlttsBbBuVbc0T0nzpEaqWzk2tmK55hmvjYOkbmBLeLr/8baRrMFrtPZSy1ai+0oCkQAwUjRlS1GJvObnr6jk6G4Jzt3swph2STiTl/+Y51HmsXf+cQ69aBEje+o+nA0DQOvyNyG5+RfkBMZXbbHCxp2IKymfSLXp82AFSaRkfgPVn7cydKQZRHlMOc93+Io/RzxJU1OgWUAgq3G6KrtqD+GYvk1RRc6zWXrmEsIB6uCmEVVvJcS2bRkhCg8Vrd7PUi9FLTf5xRsZ8jQUg94crKScEXk84jM40wrF5LSSIngM0aqHeM7zXPGLKJn6LrzTe+UYZzRVPgBDD6NsK+zqX8TGkWcnpaWDAHGAs/ECErPSt51a8s//bPXf+obnIViTcwL9FRTBfmR7yXV3NEfXnI0gwK/PQLjeV2v98JUL50RM4k0+F/9eIj706b5LRnJ8FVOJpL/9XOqc3BknvSmMq+fMw6ADO4wXvxRIso0I7U0CjtNSkKnkatSMjuGuTNwrSz7N8NEUn2unDR+mgACIqSfnnobmOL0zMLeDR38MFQuObSU5i1+ux4fzrxi91aN1FeJIKqrCxxIiKYZ+DwTS/plgvbXsgnGcndt0002ANl7H1btkp8BmZM5In5IHW8YC5FxDPrbd8A6SB7MPaN+nak5Z2qBDWMDHqmlxOJKWUiWNLV9e36o6ZZjExr1PpA+2mItksINLh9vgiZnPLkhDY43dr2OInYiXIMAdZOTTSG3vf9XR6S5VFEHelCE/09a5lPOHE7cvL57x8+CsKNAVI3zkrm9Q8JURHssEXBoLpa7jYZQji+kga690WaWjzYB/kjrwimlWndys+KHrKSadYHTQ/skMr+Ez6k7KmzpqFTtg1/29mMTkysbrwsUTS0ypSTnzd8DO1ds86lQx7Rk+x3IIxMZFDD5HCclZ/jLFJMSLIn+qD5AyUJ9FGmi4l94kSs1XwesIsf5m/GAAxOTzDx2hoaSa/2x75ZAtml4nIHVnKAw+z3wH7PnJ58WHpgaV6/FxaF9BAAKVeudJvNlVcudbgsp7XtBuMmYR7Qjo9H+NByo0pGPETSBiCOtrzCuyaSNHxjK8b1SvVRNcWZf4+2XkLVpZlNvB5lBvc+By23ogubjpToOguNw6S0GFUEEc4HAS+4xaAmzQtZYOlJqamgn/be8xYCeZ41gwwlZi6K9WsTsVHaBcfiYsjWVLR/v6+gD+T2zlgdBKTTznaKvRpxryTwEseTsTQiaQ51Ta69HOg0pT5RhHnUzmsiVmgpMu7alCTOCqBVpOA6/pJbldBTBa6hI/D5Jdo//Ki8PNodSPfx9rpG+EPchUHgabv7QGv7iW2Jmbq5qNL9Osa4Kz7sYkR/RNsVFLDXdBkRn/8YoXuKKBozzwQ93k2J0BnbFiQJJnL8PduSzu2cKFFS6NyaSHKIyijdpztJwEGmiw3wXmCsdMSO3PsYoj8Hk3Er1uga0+OupIgNhF3Tc7wAaKbb5R+aW344G18APLx1unGbPG1P+3Xdlhmcl+svjqktcC0Aw97qZzs+73uom6ZMJSLiWeFj2MsuILlTCfoZdi0qDC3sU3sehz6LdgsLBC54Mfp+xCEuPgVmV2pI1OynTs0L1IhSnNWzzCdn0LtRClSWJfc17exEMHPfnS2C4EoqkdGRIUsremZPdTSM4TQx0rFVv2pg=="}', + 'wallet::8f197244e661f4d0': + '{"iv":"ey0b5/szn+jBexTsZokzMQ==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"9Rn+6r8b4DwdA/jFGNmfI6GVCwTlAMCa5YTa+fWZuO2M2gSkA1MNCEGPvy65d74xEGX7aybF3E9KPL4rNxUoAV5hCkndkbA20Cwp06k/5HS9oPdnCMNPdzH8skrPvXZLCTzcXsJZsA8F4TVYiOLGycBEdGA63Ki2CVjbG+xZZvvAI3WCQY3PErZetISX8ciU8AuzUiiYkfn9w+bKu2XP4T8JzVP+yf74JwZY8OJAeEIgPCbBR/HN6JNDpUBi5bC9dFmGNI+oreUBTUle0g6WYBfgd9YAMPf9IySRhIaTuj3vJU+ROTleFiMtoa40BxMhtJgIItCvqahiszGcIg+a+mFDvZEd9FP2ZhhGSzMmsScL4tsqES1CvnmLl0Vg+SHAZkbdyajpE6MTjEI8SV2NWqrpbziZhNJdIGaS/GzpzzKEwejrCmUK6jww+UT5it51ltI7+OEmhLUzgz7eLZ7yrRL+c6F9V8ndwkenOe7plXew4NKQT1s655FltVwr/UNjemwSPmx133lqajilL6emafMTbO5njrFmvaE4LCS54nXqCRuCXzQKnpulDWxWkXr61qzeAhsKTaChO/WTBtoV7V3g8wyEuWTKJJg/DeRN4JUjM6RxU+lcVa5WamOYCmWIWIAwKihsKK9xxbiQsDDI1uw/tdzIXwBhs0SYjK4J+HvpSznT0mbaCKv7ldDkngNlMxjAOYlzMbnwtAa7/HzkfW5Q20NO1jUuv3zJO9fjnDT71OLRMI193RXHYNdCOXj017Kduq2bFhJNnC9kID7cyU7SVpT6lUZEeq+mtMokHy+tzcF7kIkhavs6pyF5D89O7HUX3JF+1kL6Wp9J9U/wmCZCSuFvspgG2aRH3ZbGwQ4F+qNXyfDsHDgEf9Z88vWSeYRhZb3rHkrPp+WasSQRqi8wZmxyHKtzeKSL7bM05MVRdWZfnIFu9gn+vo6QbmvJNlFHnY3hWGuCYfj949iwprW4df1fzW9z1dPwil9E7UP5tdkUZb6wKAeQvgBBNw29eRrMw4pv1ngwQxOUGgUQAEKANu+SFVbHqRwWu1CI3b+n5lnJWmGNw44o9PRRqzgBmiV4G+unbmUsYh9JwYI3MJhqev0i9fNtEKdoeGetBlMVUmDanil0Uo9ealPJfzKt4YyWgw3gB+vTXzLGipXchG84sH4OrJH/oZ67xLCffzsmK2PiaPAnVYWIOOj/MUYeAPJB+SqPzz+FOoc9WlF+xOGIHYwr62I4A3KPROENQdt3QdZo3ckzvAxXRnvg08WQZ5KCdV24Rnz8v4/V5RgLYbhJDKmAwwv8hSnOwThdoYCuxzhCkH+bO/+BuwEdPd0asHxtoVTtRMMGkgNZOmcb76/R8MoV4uNjX4RQC3NFXrVaqDug3dpL+81muc28oVU7Cq7bcwZo2gXgtU2myaikfXrxFpv4art5Qi/Pc8P2G76xD5r8o+jdriRAZhf792eOb2uluUOZfvsgZrhjg0vGo7u2bV/kCi1PZFOAbdbqWfm+L9WMw9qraW+TJqzLPyl5+2bxP/tIzxanhXYsNR/mzV2PYp/XEiEUC7TFC4gWFEKJif3kFdoPWt8YL2BBeirl8du3OwqMNdn8+aRXF9qHyiEasOVUDYjo5rhxur53Wafl/jGfjuLU7AZojD0AfLodaeQgYWwDbmZWZFKl9uyxpiuhgr7bGCoSy8C5ie4O5ss9KsvdGGAx+IVYWzCVk89bBtlU/4uxNKAkDdMMSkRr7SJORjrtIB1b77DNLD8n2KHoPsDDTj5LMsUhy0s54Ror84wYLnNkmXtNDD0jM3iyGMY45/RgWGbWVaU9ZIDN"}', + 'wallet::e2c2d72024979ded': + '{"iv":"SE2jsjnmAd27S8dyvM+/AA==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"IvVGj5uxHgOUBz3th5P23R7/GVNIMA+aBhrJXBlfS1gDJx6ekdyGJejq5Q4gmhX+M7WnnJlJpCtWeLcD9ymV5KxnkWlfwbNbI+wwdcMwiU+RDQR3YN4d6W/7Rxi++7VWho59MOipS+s72k2DY45ZGTQRyYZlzn4a3FfAJe6AIS92MsgkfPkjPxIrYz/eg0pS5k1aV5+EuNvCKCBd0dH7tHMlTDfo92+YHIO//tJ0JVMOj3Fk5xeYXUnBUeWO4VsPR2aRaa34h+Tv/pSUfHad8YJHUzhOw2w2tF9b59AWhjJ74BD0VM/MnPLOIYxqwkZP+nzEujkuDVl1RQ+zZYYmCSBYar8oA1m5qlRKPJJFuiXAA3xW6xUOM8A5zSSSv21jE5fqmCEfhg+HX5ePvi5APW+Y8x5H5XCX0sewY3jCBux+LWBpFssxhWX0yE6ytwyWYD5l6Uce9ARTnnPpOwwWImLRFFPzTdFyoNRvv73dSmU5F8oZXqC3kOqLtXFMNIFRBsTiwAFoplj4EQzMUOs/hZFzpIDq/bBlYKIuk+p54mggzigsRlypnPPGvXmgw0SZ93a8JXLmBETii4RifG/iR6LwTtjxRj8MdCeEjALk7Q+p7jzQwkMUtRQTQdFG8YpaqZUhnY9n7IUhLpGB+621m7lxgrPGCz7WLKy9uEq+la6hbKlyZtkibGGpN7098HFSZQxrj3RXc+BeEj8uc/BemWlARtgUF+0w3HNRnm1He5+GmFqD2/bwqEsTmqRrjDpWBarJGVFWN4+eJX2ZIx5p7a3toikvYcWAz+U0oaJuP9QdLHk3DVViCgNz1q/xW9Jx91YgjeWAmlN3C9ZeDW2jS+SKulv+59oOaILJvfFpECU0NYZ5ljA5n3XwIzJTBMLwEftpYgRaT2xLeP0qExXiHXMtXvff2pTOFBRERtfrDac1sTspUB81ogoQ9tMmPJMVYyNiB3x40znc/t/+e1zKIxkfrC6Mkv7JE/NjOaXxGKpg+zuMMmMMK+zMqOIg/6qEbIcNA5bsx+G7wEthJeQvgaR0uN/XFKd/GlnrsuO+OuWyEUQBs5PsrQwpDDTIuXWJpBKZqFtk2fcRqMNYyUTtJYgqOE5Qkscj4Ze8mlJjEfwMmyOgenW+7AHIf4bQUm2TD6wkK/WxLPllB/LNoj0mB2PgKCnrn5VoL3KMPMwnUrIzBSyCVIgXr4UkWztxHmCK0AU+IUDoyYdvOFslqE4HR97zEGpq5aZLc+f3tQ/xoiKcVylJW7D67R5gmwOM1ZYFhvX1G11f+Qbm4j8MBoBxbSlkdfGBOPYbOFRCm20L7GImG//k7pYkLB9bn3miEPKljjiT4QUkgu6hnS6//o6iJmtuVMF+jW22La+NI1nm29am+b8LNjyWbTttmd8jPrHlRMsyg+NT/CMyJm8wNB6c4fhcBOf8d3zxGZm6C4MKzOpdkmAr8FS1sPdrvQz7KMH4D026M3Eouw0ETKDc/rbkJH5VksqM3mMVNcM7En7qb1m4YOCLg6SFTstW3LZm4qnLwssf0LpVO2lHSXQS/2CEMTYg9HBlDji99oaMG0GAQTO3VmcGx90zp8VCRL97iOVIk78UUEZIS/bsDW5DBwuW2hngY4g3Yej5+GMAREo3PwsnGo+AE+B8QuUwc+KA2NeTWWZGBJ86SfXPCHRS9KLfmfW6r5pfKD9qy3loUMgzsSy71fS/Sl/p1ONAsJB5yNP33ZPloeT1J/CkM8sOX0o1BKyIyhV4RrfkjQSXSzuOAo7awbaOv8iAEy1R6fiYVtZfClNoJrCPg0dXDlFZ5g7db5C/W1V0H52+d7obi3+CWziMFXZErASVzAnsyKep70bb48zC9pERLSjK39GbByQAq6M+JjvCsygtWdmqBkbOwcjLIjXM6j44SIId2ZmjdrivDZt/copyiHG7es5q+W2F5V09sCJURBmj/5EgTn7cXZBPndutfxokYd6gTvIqZkeuZQ12skbQpwy9NKc81G2rklZx5iQVj7hp1RcDP1xIGYf01jdgiHWTZVBcnI8vqNZry8+UPNAwWtoRlrnBKkm4Oy9uaWtB6XuSruoZ9c8HNT/Gpmhq23CBAdP29moXIjzyY/kjrcYGH17nEXBqt1dfTk+SJPIGS2UaQ9FRb9EAEHV9gEJYGVJCPX/ofX9H66a8w82MQhcR1y6rD4sC0FunFA3qOnz1+4QIndma8nST11dOjvDAQg3rV3kIs95H3zadM+M+Clxk0XCUKgzxWqm56zoJ2EJ1udM6VFO1WetGVGlcZf/iU7Jl75I7ds9VRtBMa7qREpjmtCW/5eDjGzkzP7TVXxVK/ALEFKXMwJ4wXQUNdsXuPCi4OvUb70JmouPDUQONuItXELRfNuMScxSxP8SE/U8H7aRHbgg+uvvb2vXP2te6yJA/ZxVY4fw0mQvs96ez4bpRg3BClD+0ZNTNTENPNl7qx2YPs+utcJSvfYvXEEsMrVotXRdj8znHtFAJ1YagzRtj+NX36CtGNaYEGd8t7QM4XRR9PHalUdt1ArE+tMY5Do9Yx/jcDRp4n1h6qGKIETgLn4VUy8VWl84v/tswZh9OLV3qOaF43ZfW49eY8NevgED74jF/3et/hSk5P/S9SNnnwbe9dQs/toLZIZ7Ez3epMbH8YDCM1esrHDgCL1yjBq24vGQo7e/TKYmp+LRodo05NTSVtiB8QSiXjb5TWvIb4QKBMA67gksQDbYal9Cb78T3oebJ4daQ4Eu/dsN5H8setRWNGnzkS3yUYCrUpQhd7bdjUqnbVRKP2a3DPs7wNvNQmr6FLw0+AfkZumqbCzwKaPZ72Tp7b/dUd+OwlvlKeVbemHV/g8EGL1Pc1bF2QewYTHnLwCJzuie7+CdTRHXwbK1sMIw4vVutTDABh2BF9fWt90J9NM/Yzu5futgR9mle6DrAvahnhA0+8UPWKay10ODZcwg492wvHhorRSNBNjoPgCSVuWJ2LPSkGziax3pcx8uEUDE1IaaButpM5ny3bZV6LUIgy/Ah35TBuWpFJAeWcBGaf2+VnA3sqWXz+I1AdNdMrVWBbUkP6aJebmLN4sbcM4D8BpMr0HO3wCovguAeYAB8JaKYJCX43l8hmjHqozI+AZl72+9GsqioXsvXGGRpnfsnQSBncF+2hUXqXTLfr+BrZfNrxF+iiDF0gnbcPRnsnKMsyDo6x+DrcM1YWO/KJNCi/DbAX7TNrUuU+g/EsgYCGebsYIVn13iLrXZsLpm/9KJO7q98t+LSPKB3o+9mcMcUm1y3NuDSLNJQqgGhS6cU5G2YrIrhz+I16dA8K4etTjQa6IvJ9/FiwLRwvHq41DjP1zTvVxdqTaBujkh8sY2Jj6toJldGwep1pDn+/DKxZrRxwMG6EJup2h4zX/uXcP6yPuGc6eOQZJ5xW/LBLkHxSlxBaRKJYM7eFydcu0bFCvVdnVDivwiETlOLgxbw2pbIbs7oH9nykqKE4FyqKE/LK8eLUHhLpMOhLJx+4cCZB6E1TUlEaqrJuUC/W0SscCpLPH+FYFAJT7Y4Y40gW1ChNFd6GA5MofRjHp3ja/uC2kcyzUdo+DqjQyj6UH34VhtFlVyAdEooS60CbFpZFs13crHWe/N12/Q/4xQcTfRJPpyNAtOD/LuzedCdH0ZBLOTwf0WbLQl2VRjQCxSlgPj5LMkFdf5GNiPtDgikwtp8Ma3nqbDLpgjWCiWjEDqFzyxnAyqJB8sKnpPbXPFC7o2GnsrMwYPeUK618+eJHfTx5cPrlzE2Tyg35CpuC11/eh/DDv/27tTDclNAGhtjWRfn5jBNOiBur2NirdSl+AkSeGQjnTujyd3Qy+UOJfubHc8v1/P1QlEb03+wEDbzZRmVE1akuecLu+grBJtbugLx9/crhp+K0JBskwTO9ALHM85KtlkvMnnOO7zRwxowfLangHkj+o3DDeVpdRB0Kad6WQRhlQwAt3hr9UBlW8LVBF7FR4DYBX/QQk9qiSb98cCiIedr7Sgl1aiAVwGl6VJWkFBaC2ai0qmKryLcQDV8ss0zSTONDSncTKK6fyJ9BX5zAEDxUZCUJuF1LQQgURNPdpJpKhHU/rcI0PNuizoUJwcnPeGT9LrAvZpFX33EUnk6Ca7uwjOw207FfwaYQOTTSm0MoGaA981we3kTq1LEdqBb4/e+Ez7ZWFYBNDM7Id/1A/aW385JIgii8DHHrM7UA0IfzjV8hOouURviPedCVIPLv+nNXBw1t9148aJ3xAhrnhCYi+Dc9VMA2kRO8gwgWKtVvGObUAMlr+3mT28sIlk87u4+hBaJdyEua0oFfyL9qma4+ihpHvlp8r6ORPcJVsn+ekQmOSzyuGfJzx6VC06q93rFBF4/jgM22jyjMPKwUMVQ2Oxj8k63z1lz+F1N5W7FLc5CPxKXOC4gLorEyjanDjEFYdFlH/vO6NQkVQqJ927fstAUxYMIObDxZQsEZSGfZGusvNWErZnVuyaMBK/o5jjSR13tg6agFBZKzbNFe+W9psKv159ssf6q8JGsvl5oaSrB5rXFXD5wwlJeiScS4zIkDsd4XCJyKi6kPAzf1riqwrj33R8xf2gIueRIPMg/njj0AQPNQ4PgTFnrCuUG1K/4a67lICGkWx4KiM/XuIE57linTWH/H0e2+Hi/ZM96LeEmXUalJg+9yw4G/9omxNdlkOUG/TsmvQZBcmSUXWFB+cCLLRhqe7KOiBqPEh232lg1W8N627bpR8PHSXF6IiFuGEMwNeXl9bHe0uR2lrc1Ux8cWiIMwhoubNkev1PDS5UNXk/y12VYNg8AZl/fjum4n0tr/vvBXDXgvTI0Z+AVs2jA7TQreix7wXHXqwcXzazguJjYAkZBRtFfe+udFDOhmjrN2QWh7Mvu67rwUnjbcu6a2ryrkyh2tVaEXkcwmO52eXL39EHWc0S+9PJZqa323ORGyaddhnOB+WWIarRCT+C1lQOZpCPo+Z5yjgXgjbyiD3kHW4nAUeSjC2aQLkvxzs8qDkEU5O2A83t4rIvKqlrDI2Mp1teo4oTH2MSwP++iTfbDqCJLEyWHE8XuYc8oz3pW07EOkiAiaAmcu7RC1w71IIRVaOkHELHtqNKOrS0XBlG6mmjE4xv6eSFmTtNLVza5XFIdMI6Mob5++BDcYR/ShDsVNINf4Cc2r2o8lNqinh+oAbIyvMjgqQ5sWCBiPa/2XSVna+dAB7hsmQJ0ZxAWTujhDhSnzstwsvjp+mUX4/etCknS/J84NEZPBhd6nJyRLAG7pbpBfTpX+GEZXNSwI1BxK9mCG5MptL+69fSB4tke8CwNclwq5+yk2XrKmKv8nTFqa2KfLhvHAXCrdaX9DQRL2ND9Ce4akkOFKl4nSkiVfelhxrM0eZlG1fa5YIfik9xJO+vPJs+h7b9aI9WZYroqM7+rZgdtOGfNyQJK95u/gpIxqiDWBFEPY1PSLGRaji4OzbPRgrQQTNcC1nCPGu5e2RtAaCm+VKXWbZUT1TaWRGBwXdexLLDgm19tTyCGgPx6fm2Af/gwH+u45TwplYUroYwpWUD8Y25LxQ0Q031nibgZdPDZaNFYXQg24n3WUmd376ywKPCMlMznkYP6AJv0XRaDuKw+IcgeXPu/8cFcbFPlk7WxJKFmVyT5dumYXDRNe7Xj/UdUcneItqYZVdO6MsTgvJJKoWLGRcfqJ2UPRObKTM7TVJ8oza7cwNPapnM4l961//s0gk/3gqTeFjJetWx6Yv1BE3cSY1heF61eGHKuxA0oPp2oUCgsPSBwfCTBvMGz4yRXDpDN8thGia2TcV3bqRKHZyB25d1+UJXmuLKiTNUKGfbSWyUaWMJYXBlIpeFg60Mr/1xGuUYN0a2pHmURMIhmBn7mBneuy8oCfTNr8gLDSe6NlEO2hn+JKqZAZwB99EmPe85bH1vG8qgU2yUCrtHI98QwjCyWtmWk5m/DJx9G39Jc6tQLf3iocxksWmSU+WCwy/BEZ+um+yOXLqDQPOaKmgKAQMZ6CPnb+9nEkUk6cT56o4e0nLzlBR0NlJ3kKCuL6QDk61Lp05mo4yOS+lu4W1Eg5Q4LVPee1v3npFAWv16oaDE8w+c2Bx9POUF3u+NNAGLYcG6ZIP249jEsqHrGBOzkiiBeo0fvSoWdK+ol3G5BuLBZBAIMmm7hN5VGjUm1oy1K8GXWECLkAZwwsSmCZsJrGw3LEDat6mHuR6YFbROYGKSKlbswaZrXm4Y/nO4IcuqzOtF+s1sXHI0JPbQqPQaZylco8WRz72xtzxMAnY9YZEFMM1gbq9n5ntKcpHE7Q0gNKJSz5AaPHZIUoJ+4TxBw0X5MPx/+9A1TVOJI82bwptWId46W+wQ8xYjG2678c4EkN6xhcKX5fjKOwsFKYu2BPJuVqmaAP0WKgbWPw/ySauI5oGNZpAibLTtVeyFzCXRkIjR8mPWsNnQUD+aiXHYGH+buniC+mS04vj6amCw8PIr153MaWc7Dmkj01TBShH4BhYqF6+HJdv6dJWmsiQcHhe/fkeA+odBly16izpRiTt534ZA1Q93cQLy3qWxQvn9jGnjVFhyl+VkPLadBpAnelHSNdN5B02DNBx7/d90mg9P3VbDDyJgD4Ad6ILuKh+DZm9SHY8Ne+1NCKCaoybAYgEnM9ZK8Ys12RnyRBP3plen4GUraizdJoB5VZ+i2V4eX4sbMp/mal9HWfkWvvJMvI/PSqdxKK3gjVDzTpy+5SC4="}', + }, }, - -}, { - username: '234', - password: '123qweasdZXC.', - ls: { - 'profile::19510bad7f0638eb36548f9ad54f76fdfe2254f8': '{"iv":"ldPQwfVgrbBbxqyD0t/fCw==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"XYUELIWyxxAmuRrot6wXAG7f9ccAaatuI4Cuy6eVIjyYXCuR7F52DlG/cr2OdkiR+t63jLeGexOmyD/eq2cU8AYAK8giA8D3O+ogZrciyHGio1JQt+3iaJ8rj+4g/YlXC9Zx2gWPD8cToy+W3aMjBD1QCTsw27B6Lr6cp3/21Ireu3c60YVYRUH3cUF55tlH2ky50BftqANgCUjPUyb0LUoMaw99du0rgzat7RDbEWVUeQFvSN5UIUssVxOyO437bdsXWE7Ba9SQPsTHGToP+6MRh42m319SVzblZjCHyLwo6NAfDypRl5mVcAmCv2RLTYeQS+Ro4Ie57HRt3Ngh2DNBAm0TOGoLLr6rhMl1Ac1A1BGRMFDq3LEEJARzq0+dsz5WcX8t4lQ/"}', - 'wallet::4d32f0737a05f072': '{"iv":"JyZc5viMPjPPz11HcchsGg==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"+E7nNVViL/NvOXaHvPo1iKVvGRo2RKnhG1LM48SF2OBbd4TIGtvB/V7YQOvvZkVGop5GgfqG7HJ0fx19TFHEaYvMCF6Q0nzmoVkwZlDfkzhzS5iu7USs6I8RV+fis/gg/sELXXEBrwE+bnkaj91UEo94uM4svF65QthYx+RMR1SlWsTJNrCf9I+RUZJLzuo/41dgf+rZ5TIyuSqqMUjUtFE1Bpoe1qbp2tcROGGovwDPqs3P8p9ucIJdH0vmiFIV/rqg1Mfr+m/m20j3gg/ac2pWZgKS3PJ7ZsnHct2Wam4yKSrgtZQFFoA0xeFhF4D7ZcTFJgsgHNAKrl0o+u72D5aBBaA4waybP3ZpGYiy4Pzkz5I/BoXurvXHkR9bdZ83bG3/Jg4gJ/zcSLTUjLK3YfVWfJeY1RMBiX6a8i+59V0I4MPl9pVI0CFSEjMOjZ8lbUk7l6wxyvkvGQgDzhxuidWjDQyY7N+BkPHjNXQwyyJdLP9VkLDvgP0HL0vhWV6O5WehfnICr+e6x9LuBKQmZnXpbEkqI/LeM9Qp+JWwC0Gr11ngjaCUSibSYaqeJWtbgmP6bVP9x1oZ2FRnAPEqjFK63vC+WhtB3nitcL1eK+LOPzjL5/98ghdPecdyQpEdABtPNd4jt+igJALA/v7TitUHScHq3B1VTO5T5YFREp8WYSg0TqTQz78BBuqXDJ0Yh6REXeetLq8/oWEkxpQVWkMrCQOZBHgFYv2D8NJU0r/C1SCKHFkCen7hL4vuRzG1QQNd37haTKxBsFfooBgjnUBIzZC6hVgAcQdiBFS4tu4HxJ9tDr57AoSIcnT7O4RdXqeWBxeq0MRz5nyvbOR8hQqk7xP7yrEcICRSIujksAhvIVoMLx0XqWEI2iaeW6IDbh+CYZF6Cd6z388fyplZKyfe3z+V/L6klozx2IZuL60ayQo/uvXhMsmoAcKMXsHt2MGDVgHnFlcTO6lG3irVd4rOtaxQi/5f9cg4+KU2QWUAs8iJnCP07wRG9PLF5EKklXO3cHdThjcKHgTrBicPrrYWft0/oQzDeP+oaV0qqCV1OsnMfjZlQXMHFD6Wc7CEi9CImrNfzJBQBXORhi4PPLrabpU8Ad8t+YLoYCgJcCdE4sG6R/GfksNoH0hksIvKwoQEUpRc1SnpxISlA0BIntZEbbm2Vz/soaz9u5e7v9RgLtKl4yTbEEiLXn/XE+RLYc7pPZzYAmr0E8w/anPuugI2mToOaZVKv3bMX6K7pyOB7t4TasG6GOqQf4kev/LybJ7I574qKOahOUTWSEvriht4bzHXKCyKMasCawpfg6QoiM2I+w94j9YCnGB1OUd77qq8WX+Y8OSCZkpx1FpOCy4qGnIa4Rw8BQRA3BzRcJd8WaXfiRIMbwXL7xMv55YV35qHMDwdWYw+64jDHxcQmNm7zdeN6c2TZglJ3ryn+OoudEL+u5IraawUJd7idyKSNjr1n7muLp1vNODTmOlzVlenJrBr0D1sj+tuh5zCxbmGoVyr7wtwhQnLq+18X8EGS2JzHfyG4PnXDqKVGZRb+CmfTSKvfIhFr+ay+Gi2GwB54eMHtFPUlWOFGcFxJgRCJbsUvcLODC0MF6WuiGzQITV+5pwRWLZ01ZWbZSEzOgYv1xn99nthWfE3ri0YvxzU9CCagd9yBKUeRhfpGjAWzdHiEwTARHpMG1YQkXUQI3YDTLfEpEkKBSgFLr+kieeM7/rYLV840kd4RzxV82IGSU3i/FE7xmo0R9GNbBo4hFCJl0sG1oP82C1XoRVGLnBUKNWIz1LSonNNFMRthnaEn/x1VZoASYTWvqwlB3SkIdIOs2DnsFq/EkRvW5BaowazypJ/asfv2wk4OEtKm+iHgkGIJYr4Yma4pOdQ+VBa8Lr7VIrJcLvyho8mDRzLllGtN7E9vurIJxazWHpwG/XDF58trPZwCqCYF8lIj6r4GHX0Ikizi+1ciyNb8rgFTAZVmJ61beL9C2MjFfR2llNqswJbD+SlNxspFo+KEeCB6XJi+d5GhmGppBQFHz2VKvheMO5CKPADWXmWWiOZOhLvUGjIZDyjsPTeaPovevdUwuiGsgrekHvhLh/+x/uocUcrjp6fg0K+g1CfS2jxx1vclZM2c+PSWiWdnRh79GcssrASnIxoPaAlEmw6F3aQXKXImT0EEubWg+/gioGaQUJrY/Knvef3sOn4B8BwI9ym/o1iL3vumiqu3wopD5dQamknG+luZFSGsQ9jms6lshbOM913pA401d1AA21AOyW0YelqnnXwyr9i6HgCkHdSKtP/01vS6qorA/Ye5WfJXVmrRsFdz+eSUNMTWQec24B/f3bMXGUJ+mH/7jS1sjEj3QTiQaXpyboDQvBD7agRhZp+oTzIVEKl6bKx6yRlqlIp9C5V0kDTtU/J+q/FmRKUfBwAFab9katVs/hoOzB5s1O81CUn0psYphwSIaWjRNYRjg5l/gRsDT2wt57rUtBC09Sxq94YRsShrTdQLvH3eJdRZFcPnTFYifXafRKcZLVn33EN/g9hP2fSd0F1AlNYuiTO0GDjK9/Ss8YjUPkLEIzGHwjJ/hrwApRia3mJmH8LkSukFzdX3QM+gtMQYk1KPepCYJkb6giAe23th4om6aXtt80va5obdoPGshDpWcmcBjvHcEdhe7r582Hp0N8O0qZrpMF0Vlu+JiCfrW6xZvOM6xyOM5m9sKvSMJuBzEykKAlenfjKA15UZFy71VCEVU+PTkHU8tKOj8ManP5nLtPUsm+3EwkRumoYaNE8RdNoWCnJVEJ2wicZYfvoi6KHB/IYIGoXx3RLiy2GgWRZnc5sMeZAHhg767YVxLvXd97VKlhWdIXGVyweRxtA8AY5aMfLDktSvwu4/pEQCDHAchpHbGRrBexZK/6yVKdb5UsQ3WZlrvlHMTso9HB53uSl3YRO2hBgbH9kodv55khH5H5uNR8mzHFZ7N38PnUG0cUaO9pZ6OsEbtjiSNdlnMnegojWqN7jYjfD0nXDY+5dK86jZaSlE4wAkeQ6dcZadPLklxcQVGYjgmn21hPREaPCY0Y9OeEF3n+HPYCqLRdSRB12/BHYEg0J1voW7UCq/rWzIKOGO1dGOWZjA2fQpdicxBfGkvjdVt+Pu84noNIYxuEv6Wsy02f4tEEnN/Ncos7ibIuCeqLqL8Tfh3nF0ZPu4PsDjN3VkZw2TC6ASVxHCo2spJD/haDMWe4A5WnjHUpvZm6nvS16WX0q22fSv432sE24hMuRv1i/Ym6C2qcl6n2TiMHLyCHpOwrODJkElu9sHkJsVdOybYgs6Lu/zn38sZsyGE64ip8AnihCBmQ/8ymAg2z0UAwyVmTzy1Io1BDYJZhngaR/RD9j3xgZsa8Pqw0OYp/qYKlY1PiXah+gWn1Z08sRa8dCGgzftJ+5zbyzyy2m/jafv7P180fQPabEOwvrWX12a7UFIPy78Q/KZUXra592cs7g3C1pP+DTr1ODxZVGPffQoUiPhGoaJrJxDlZBJZs+Ffg0s38ZAo5MmBRdtFP6UakVQBJmvqLXqWw/e8CIK6SBRpccrHVt1+eKZPlFdrR/iBJmvDvUqLu1mmD3lODE87mK8F/QgrVtdEkVxBQNOARxiUIA/I1prmEVNl8kHH0HM5epa2czBqTMgn+fT5GVxA7cT95NJhOCHhIVAKmT1ACHlwshjccLyn9o+zO1LR3uOCnotypHZrWddenNJoKfrB50J4E6/gs0F4ylKH70tEZ0RNh3njWI5bX8MFn4dD9dBZTYJU2IuvX3zuDL4cYnpOl9VekOjSLjg6Murt7Zr3yTzTkcG3OJe33BdOcPmzWGHJHBXc4g9W8zLDDhxUUpIXjdGm2oCASHwNf0TRjLmu4tTLpOzdvuxMV0F1eViRIAXoC/07gNkkF2KMldc33QgST/Eb5gjerSksZ1XERINoQml3h1TM+64myi4hf79E/CDOs2Estcqox3BDc1aZxIWFaeL1luZoBWKSwnh5IVVLuHrHrfzd7MwK2TwVU+bCLuIudEz9riIXfSPqRpaNj8H/f51Bh2MNX08M/wlgRWPn8upl43kbGqjQMmHWW81+F6iRNYp7woG+DsrOYUmUiJTR5InglYcbOVWDBGvzS7YQZjUBbUSLCxYyAahLyT6ZrZs/RRklwixVrt1r41c93FvuWhbtoVSZyFYUcvQvnpKpz0Ntps9TKblHnvohvSBVNI8O76iinkMrFC/oCO5Dc+tR31n1hLTyTZ3JLN0XaY3CS4KvcVVPMaM0s1KsufUo5wIjFZjXRYJ/POuhhFlQIybG0tZgNdRObghpp8fIrpkNKP/eJCGGbaZMBQ2/astPMHbKOr07LXDjIv+FRFpbXZsGwq98iHaUCVB+l2gSn9yGPFZo3W6bUA2suaSoV6Yi2hN/SEjt4h1Uz6N560uKbiHvT5BFEJEqz1fP6m+ab48Ap43ECrY1cMBufswHhcSVxEfLZqu0Qgdnq0ABQOqnFT6SVgW4KU0QbCbGa23XftkHLLIdqldb19NxRqe5cbDPKZ9OCVdgvatkmpXzQc/t8Uko0uPMm5pxzlw+tZIfl0Zfj6afdlnEwg3u+EkepEOPVP09rUBif7Np9v8vndBOL6m8ZBdLXDqQjTaQ4gXAYj5N0fZB41xjp/21LFSXLaTJD1xOY63O7DS+cfQnUccnC7mtN6Qp5PqZ7RXbYrubTBRttpIpxyGJcgHly0G5qOqxd4qiyT7jbv+j2VkfBvroP2kZJTupnSfGPW7QfMltVcPjVdI4MU9/scNp8XnWoUBHJZ6jNdjL69P+CjlyG9qaFNySVkeWiADGSBL9iGbEG5nh65DpWinhHic0QUC8BVtVO8qEWGt+gf+6npnzyCKulfPQxb5ySYVPifgGAPdaaOtNkEX7AKQQNpqcFD9RzQEOBCK5+AaxLE+FwWP5wJvIVoO7ZWEvGsZy069QEanQarifzw0Yr/WHFIf9oW++6C2bpCPNurwxZwGElniACZctIuQMOQ5ykkWz5yH8dXCkOhJYe86wgTMM3jTRtZ3sgQ9L8wGfUpL7328RNbhuRAMifmli1tcvH+L55ESX31eAwNQaqVdfgpDOdvFFc9yDStrfwmFx/VjfbpmilNjZPJor3+nsZnz44Bh330pqiGQ3AhBR8o2ttWRiWNMXLj/4wZs7s8NvhPiS1D4LkRXHn13W6z8Cl9XMN1REvf42qwglL3467I6fVUImPwMF1cB5giu96Z9k02nxUlu4Xz28MxLusrfPZ2sKu+4npz+t8aEFNJ/8xUDPflyGnPd9XfFSJml7k5zv+M+2TnHWaQcvi1eimRSOmAoUX9ytkgoDiue6Ik124Mm+M8woDO8pqixUcg7/bLdMx8msDbecxTCA5744jH/2U3BzQbUBcCVmpsD1yLmeUn4iDOydED3IdBtsicIBjbctOw2Q6bXwo/KBJ/N0FhCZBxaC5FqbYyHEZvF6DdB19/mzySgYAl04gQqf0emJUfbMAtnTXqmZPt6zIec0ACD9RSomjO0LJz0nxHL2F+60bB2POa7SOGVubIqEaBZDGOwKSZxOst8wM1QIhEWyUEx+6ZG+0a5QI8Y4iPyidorEUqoxeW45WqnFiadciJhXYL4uGk9jq6iDX997LSQzpETDIoYp1CBwla71z5Lx4uFLXBiCOptWqe35y6THii4nHBcdb0kuz1CEuBgFE6hhO3ww+syWQHs9RgSoKkEYAriFeVnhF/cNNrgxTW0hlwfDJMV6qdQks7W1EKHEvwPs+NPSveA1yxR2r5fv9El+QiCixs3HFKjEq2wXdFxZdoAhnOhIlgv84QFsG021jERupkEwfCAvLhpcvbOiyZJNktG2ho/RgHku78UcEfC+VuKIGS4kGxIuEIXi82o2ldv21qKXbSyi1maT3/jhE+Oayp0kGS/Q3bFk75fXsFcE3jkEDd9WRJQsTTBUKzffoU8CJJnSGUlLZtUL4P5TqYDPZP0kzE9laUsolX813mkmVPG8TAyVCa6UIMAXcSr1BKv2FMpLiJSsvQEKHDgTJU1qiRB78z+VykR73IcV6yl7Ssz9g2gq4nnxmiWk/tI8LA1Dv3CdDCfufVNJCMVjlTmfVxKV0bkZsndFA1W4EN1STeLC1ke1yXXwkUNhb4lRLY9h//f2cUofkjqkHG35jXcfeYtzWSXUXBSra4Vol3RzpzNwwPPYCGaxgZjl6qRYxsJ5skSvBRjjFBUQN3ktWm1HGjQxE5YoeRew/PgtG9/j5Fv5yzWDvIVqOpgdq2vxAxsa+EP2qw6tbd+TyyNG1ayYiUWRc/TcwMEkkOnHVVGAkbSBiPpFAhTnRLlDjjVNsf4L+uPDGvbTN2TvUrIAijvM4k6v4eEROuARjuJnjhBxnv6V+K4QuN102K5wErKRxHq3s/lwxlaQegklSbUOUtHRWuXGS9PlAp28DCNO+GSnXUdXYyuGRvt0shdJkksCtgVoN+TEAXJKi0hr69aNM2x5vqbhy0pdF2gkoO2oPJouSgy1axu1oduMGcoBHAK244gJfcNZOUmPZ/5k9UyhW0OFX9doeYTe5uKC6+xXdOoxPQkvmz30puNcFYHLUUbQ/9BMWzOWiXfs//W/swhfR45qCUb7ZVvEbFHQidW3YYjOr11rNimfNT8cbHrvrcJnEK0PWTJTbenqq7Txt4cXFdSR4YzX8FqdC0WQRBiQehbGVlKhdAcQ7yUKhnWTmscHj4hteHtIXeSFS8WSaLz1UYRXHQgVJk1H9Ahi03IXL9sDiOrwbKjFrvpizRC5uUS1NtUBbdoTFs63JDEtKLq3iVoryH7yNgD2vx0lDx05F/XRBcmrRgcFlXxhvARoXDU3kzMR4HPeSYoAz3rNA3Fl7GmpV+IVxnZH/ZE3LVzug/LviqtrI9nD2glucPsunH+62erhZnSqpCBCAKwfCfw/sv0YqDxynhujkuksXGFLGwc4Ud+OZWilVJCZiupxydYbRAwzMFs+Q5DBPe4iEzFt1LoqlYdJVC6FYd1rZG3zp5Ba/15MMhzPuOjhFYU/hUY6ZBYBJRIUMYRaNurug93Ko4cXKFshYsntZoAz0Mhw3yrMtiK6m9YYsqbq11trbuK4Q9cMdXX1vbYlqffbj/NEey0Z2nm0YChqOqXzNaY9AewPEQkkj+cs/Pc+C954OoTXsSY+WRASiBYZLjWlagbQEPo3sijuIgo/kbsviZv/PbnxYX270t9N69KH72WCjZICcW/ifjOXxRxZnskxtEW36pIYOZlWR5p3Ua8SMqMHiG6zyrjdyvrRRjVNpYfLIn7+HzLfCRImP/SjArt5KxoV9OY52CBCWFr8bJ+XZE8vTS+gEMx93PCZs/iKYU3GznHeKCu/3kTKwp4Orx0J3BxdQnURGCrepmwhLBqrXP0BENYNhQcB7pAW/Ow1g/flH5vXqGGVn9lf9+M0RSEQFOFYW242ojfGsU0eQCQi0RkHeGhZ5gAT3+ZGpgm0Gt+c7QM4bdYPQDKoEp1Bx0tdza2eKkE32t8a3MnPzXrKDNQyJW4YWUEDPdsQHtiHxHTv/OQT/2i3OCG8RF18zQuiqXX9S5YH6FogCzkHr3oGhEYIRicnoZ3Hr+p5enuoBrZ8LhoDU6qW89gD+T09XvRocT5jZFUTbrkMYkB0Av/iktZ3kjOXiwoGmpZyOPEMJmUkUek502mUEKtMpDxBzkYhvxT2MyNUGaLkivVt4t7taG5peagtdCIoToUCc8Q4EmJ2XJm3r7fy/qiNq3fxF9LIC6PvshxHVp7ljKwhf/kdDYDw+l9ibFl6HmyJYLsssEt0SMps45++WpbtEvRE2kiIuAaZVo5iIEhAP01bGbHqIP8yhs1JO/HRM7nLaiJMF2vRmfKmyL2l8Y/vFRTfambwcN3ti28OCRUM2RrFw4Dm1Y5GuRuap6YJxGn3Fo2TJ24yFWHObV1ipIRGDJe22CWxsixxvniI24Qn7ySKxtQdchiXbFyWuJfTwj7DAKuhT1QHVI1qG8amZiNSBJaHz5/YWWsQQ4keANQagyZe+l0QqcS9XISiD651LWykE4oZLsOWQh/rnQrqsiWgNqIDARMDsDj0n3y1HzV2B3+PKdashkjIeulGO3ebgzGklJZ7W6LqTIY3S7bMEJxvMwKyVZ+WoOYnhcY+Ie9Jkrt4Cicb/accdWrn5HDbxWWRNifpwRz12OCJTwyw3yZzxTMpUU25F57fPkymF/71mS9OEVqIsps/M2J96c1q8QO6spA6w77QVpohR3gbwKMaDGSQvwoVYy1N1h8vNQymJaJ6kJZ6xi1QhUxdZrh2SvvXvKzNFaZAOmzVln+QUX/hfsYr5Etq+qYWZ/lbAW0W+7zo0/JFi46W3gEGuCouoyU4HCYCmRLFPpL9VdR57XOAIlpoDO8Bdxxt9F8q+oWhWh855wtdjlxCV4YzOO84XgIXOXfz5YYMrnsdHC593UQcjrV2RXD5JlMF0eyv4jaGlsqjfhteTkHJ0JrqMCIYbpeIN4LbReAuKTi2esBPk+T6hompIMPFGRara3X4quVnDaoC0AccRjCRmGet+sxIO9wTN4LgCy+zediE2fvdnpU1nRuJBFA5YgjO68FlM+oqQMWt77etBPc7jcaQfa8OR4IA/XELZOoAnA81Ht2FdT0e7bn/l5KbCn4J8gkmskc4kchaRWcxeXYhY0kw8R07HE7u0OZvwtzSk9iHle2/s2Ov3RzthuQQBJxsguGmzW8q1NYhtnaE0pwqzb1SVsHgpzvPAlIY0c/Ze1j/YmqCodNaJ9si1aX13yxY7vF6Xb73tpIkq8Z49Fsa0bOw1J+pW+EQecQ2yejT80Wt0sF7azdUAQFYcmuZkOIT3c2nIlDpfJ2qVIiCpTa3/RFv2bMhFwyEgDt8wSvP9nNHddOTwTjG0c5xDF6Ezcn0FNNCB4z4zo6GQknmqMPnGkfABEymIPCnSt8pGdQHGscxrA/lY58iDJNkQdlrWej0uoU9azGtOF1hbCbJY/m10cgAhEogMbuHRSngkaXMv1X/pbM816XQdKvDFcEndOY9OcvNO02BMpBwV0S08uIqxKNJtSTdlFRVCESYjaSJuhvGRISKDtgojdOVvPBPT73cy4gpa6TB5Krd7keWr2Muh5x/Gx+p1yMuGgxScay42/Sv9Phy2r2w6TFUVEIeL2zNabOiPLEgabsuL8CSx21kLw0gRS3iDmpydWcPToV0OkkIstQ9jOWLl1Efhi4DzPSZlV5NkAECUjhcmcJ4/Rs9ErdqwzAWdNjM6l14fXn5zbiBXNuEQsVnwaxVjhIIezAe7S3Ydk4MslNh2ACoZr8FSnTvgxiltM7hzu0Ji9KbS0qzVy6gQNPAf0KgZnnf2oIALU6ZQcrPo125pZ0OApmfp1U7VPmI4KSlPP19wjKwCGE39tCtngrq3Tc3EABDnOF8q8JWTWg161QwR7Dks9FarSpPaKOZkDc3UdxeNRWYSJRU87CpO2heeLRII8jl6jxS4Km+7DFCncKWykhUC8JivZhoOGEgkNm5cVoEY2XecF7nlbDNY+lYvs/o8606DhD8bX5vLmwnvABLZ5ruPXewkTqsPlT7GAz8032y4qEBryrf4NgVzb5C1Bs3R8SlUoL6vWjHOIl+mr59ZZkfnpOJBM7RB0ozaHK4poFnlomb/2E8N9y/psffmES22+7jtiwILN63ojEYBtNkszEfLul9pPwemt6iAt/jI43/WjDBYAwEhgbBMATNlvL1doUN6atLU2q3eUAC1Z1Uuv/2nAhuMYjLV0uBy/bG58RLb6eiflP1krw01obpCFp07s1/fOExG9pZyRe8NPeNILFBAsPqOTtaUL+g12mfLfM/YMKIhfPZaYeyJ74G6XsCM5XGDGVa4cGzvOj34K/GO/94FIkhXZLQgSU/JvhseM88wuqh3rBtKcSq7g5ThcxuhejY1uY0z4hc4hScvHLU80dpaAXAp0WPjbLLoF2+lNeI0ttX8Ru51lnvfuiDxOTKMM3tcU3R5ppcVEtUITwC4cewUDJ/3STHyTaV030/GJRwj07laBGwIWw8RQf9rJ69bjZIF0mLUHt0gSNFZqgkOtlGx3DK4hEuS4qWqm7yp5sK9mnxg1veUstIj87Ijjk0tehScYmM3gPMBtviZ9raZkfgf/0P9hop1d59XfZtZrCr7KgL8XYCZWIto/s1u9HAMXqkYNm9hU4hI64lxg4WFDn7QClDRayNAQF+yE3hB1grQF8sL0UdDelv7WMYbL5olAm9u6qeZ18m9XOY7uJ/eW11pLHs94BwnfLqq6+2bDc2mL6eOPNKDtfoH5ogc5l8s6sMMMEtv+frb+BSg8iPGHXkoXpxM2xwdM4niq8G/J2b3OeZICfz64pgvUpKxx8aGjrdzluThxKga6GR4k+ODYpaHrzLgHuU+ZhklfZ2F/kSC0bAR3qmo/a4vG/jz+GpzeY/3jAy1FQj6mII2b1iMAfkouczTmtRVSkdyh+3Ce4J9E21IdbkKB2xAWjXAXOXzX3j0aAY0SxTHytZ51H0vRiawrwsDHQCpVsxY15kety8l2Juk9FGqbzdSlrgT8NOhCzsfYvQxAUum1+E9cjn+8qC2nZv/z/8751rJHM6rnWOqhTFrB9PWIuq3NWuzRDWdPFP9lh0KXiSRPK0rd3rGFd84DEvpbCNenH40n9wi3q3jGPvjQDzvSkpguwPGWDywNiAYJCTGFtU2y9vf4QzN2vqsjEob0arjXy8UfSgILE9kIrPp9bwwnn0lOJcYcboP5et8WD4DAa+90sOaXlkc7OulUee4qDA4h4ORCF3yl7AqcP+C5dx7FBxknrGhBViUjzfjxdoXRlvnst9INIORv6sWZbCAgD6/q7+3HMCMny9Ci67ThM4J6Xhm2rpa4VV0XLH3u1Z+g5XVC1DqEaHL4vp6AEQUfpxO/aMBBCwdqd0eCz97AQg1V04GB6JYfSBf+3Y1HdCYwOBgoICFAyiD2lbstYHh3h+UrE39vqeAO8r08AT+SrEb5PHPnmdMg0t2paS8d330lgm/GXfhgQ07+X7HrKcqZ8Hl4KibbZ0lXwZXTom4ymBoPj72xRZz0rcfZbNsp+jCGfQRflatlfOQ6nCIpXG9FJGenQFMe4hh41imPMZua6GdZJ7TMg0NYLMyIvammW4wEJpj5kOWnBm5gdlbSwVQw1+NfuI8wnt39NipYtgkxyPl0Fd3KJofm95oGZMS2+AYzT862Outmiw0jRFZFHWt2rx5loHWsLIt/NSy4v+nv+Xf9X8zd8sQPbiGppG9xQjrQS8Ns7GF4kOrOGbnL5I3/fb9wXt4F1VsjVDcaT8+23LcMJY9svizIwz9vKwvOtoCxyrKlZyc+Z/aiLeVozKG4A54aUqupF83iZBLaAxxKrXtydltPLSdfAHI1/SveDnTCEvKnea3A0OWWO/0WRMfouCQbexsyj+BUCMg05d3I6WkWKI8j9nu7usPLWy1dMXXEJT7CysYqNqBS4XdDQ26o1E1LC49nmTdVG5RI+hL4uymUA3o1b62sr5psKKDIMlOlEKVIrWam8bK4JTe8eFa9JFeHVg/ZXzGtEXbHDRg2Uj3pnYzaBTAh8cRz+5FWAHdnFt7mM38yRst3oMa2HdalurcuY0os3iwiIISo3OKuk4iVr/l+rdPkZ4r1Kd01OJxqrmYKIFX0IHyJ+qhni2Zn7Ddsosgr+j1ovVKS9XPcnndKcb/KPIyRmqM8s8s4gn2YjXHVVN1KbdbRqMzlju7VY9K5QvmLl/1UrIyfuY543A15T6XNFm/BzFzJW/T9gSQXF/iq2Iv1kfcWnm8QdW+Ey8fU+hSD8/wpok1RCH3yVDSvy51aEWGCf/oWej3seSdnmYfdYAmPJ9TyRkdF7hOq9oSHMzoBb6wTsGD/Vur2R83/xwGWgr99bIe5JuYU1XNUweSP9k7RBggOpuHNOA2mQ8stOm9f34+c9xdoMhrg3xqf50IAtKQIefldAAZo29yO2sul7iwQO0uk53jj5WasW4SzgrCFlzfdErHht/ddve0PwVREMncSMHBKEwHLctsdA65O3JRZp5eCkchn8xjZHtMF3g02iH0FBDrp4AIf2Mdlb+pK0O04taCM/c305MtFMQqNt/nniOBnhraA+FPTff6un1bsp3WNdIAwU8sm9QWYHBWRwt58OvLk4WHNTZBIz2afz/mHTBDHhPilV54tl1A+bs2bg0Ck2oR1I/9y+u3HGqFJxY64E2H6MppGCFQJ4HSehDRuT/mkbpilFfXiRYBj+Z+Sb5GiK6Xew8NTFwdEJ2VCTBMRauM7sEiYyLvAk/goiEBQm5HtmPVWTkJPZLq8wOsxOPabHCwj9wRqL69ek36s6u7XQa4ExUBNyAm9drvhkVx1GFjawrrOm5gvV2fCJIhIODz5i03viZlhNZDy5l5/ZE9PFzCetG5Pi5QvThHLNHiF9zZ3plAflFiZvcs4PvkcQMQ42t1iKPPl5TMuA+V7DEQYzw9wLxPVLu5jKmlLM7s3hVGizAj/Gw/Z/oruY7r2O3LPMvNMMWnYHngfS6TSvY4+4p/CWk+GXGu+gQEOvN9CSDKqKcVHM8ay/NOje8IGrQP0xITzwDw1iOA86yiofdqF8V8Wny4MmMiXhLX+kPdp39GmGLXpqhSmi+4CUvWUr/SIWB0hEtFs52tXglPYZPw0zVio8GnjKNxRksTD64Q97iRmyaAFi/2EbXWcun8Z024Hkq8NS6d+eHGPz/2fagFopcrgHtxsz6jdoGMEubwPSOJDhm3gJAS4AD056NKCn4HPxQc3HA9aoaW2HHh0BDGBVvLiV+g9jnIfS+DBQzrspYSu89moXLY8Hi2E7XTPsWeobJh3gbfQHkqfHp5yRIqHV5WXjGULMllU27J9+FviyZZmSIWabLCgafNwcdqzUlNX3PCNOIWAiXgtCBpbGpzglSyV+DffKOTlORUU4FJPszO8PWMkfUTcUWLSs/RzP6r0oZYtU/Qr5bISeDctIha4MKN8aBit+rmPsjKcVoQ9b8gGitRXKwrhG0GeC5PilYySXmIQ2w4nGBqWbCpsPoUkb99SC+3VhfWP1ZiYD6uOhok5o66WOfmK2awzf2jSsj2hNtEYQayfDKmxPZdRyFnfo5vTTz6LwAr66TyCX6+7GHT0yQdZQ97f3+GPBKs4xGaAOmXl4/Yk5yn3c8dyPMfAQe9xkiuTp4lOuhmzxzvzF3uNT1NgXxn63jajPYATtpBcxjzIAV+ARtK/a5pLVtr3BOcAcwOXFzAq5ZTb/pE+pPOxfiBv1ugBDo61dnnVmV3S/WlgHRjKRflAsnQr94PxQ+1bBaWn3+jcdD/fELRcBMmXKCSkLAw8vw1J8QmFA+Z6mzARkWhdq4LCriBWXdjZFFBIWVgBFESPcNhm/nAAjxnCEO9mzrZqahD8aDdIR9NQYpyFskfc63QdhZbvLjK/ITHEDqM1tQ1ABZ4kR417+pXogrg6jnOzgt9pWRWUVBZ7kX/q10UResFXPVXurOMNHY+eVfCfFCbKHb6KFjfvQ+Sh+7VMReS2HuwylHZgCno6N6VEPtyLVHIX96eqff7fvjHL9pbfYjb615giXxy8yVKBOQNOAkqkz1wlOthgnSST77ERCdcuimfL7E8AuvFtQ6uZIbR7BIGpZKzYkr990cbMQw06BagmlYABKg=="}', - 'wallet::7065a73486c8cb5d': '{"iv":"7j5Z78zSgRk6+5nxkVtq0Q==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"dCifjzWmsHqBx0y2NKYxvWbp5QuwhxZgnsWLUoJezcdaqY6RWfIXpRDxaggETwS8KtnAywV9bL8SDzkowQnKzs/xdkvqInjRTgvdDF2lxwoUhUbmT8AhFio+XMssQxXRcc82NMI3+YlPTuO/HmDUeniLmp5iHLc48o5VT1SeWV557Wh+MyIg86+Zvw0/BZTYl7JrTZtur425j62jY9zVkaB8mdQR1QYdTqJ3Utwozute8NROIs4p4aZAU/rSkr4knylSZKOwX0//pCw0Y4glPQeRKm7EFwfG+UZIQH248pNG9lmzRbUAxN020cgHHiQ0PJYUd8WfjpLrM8Vuyfqrr/ZY+ZteQXnsVOODPcwXXGEeHrLcfKWxsy5n/nrmMjN/auLmMPJY4furl3UG7fcCV4W+RbuJrA6I7Ld3XtSMLLwVwxSq0tGRELhuuzM01ZLV7KJA6McgJPPetNTLE6LBt9LUtUCUE+tc5OmqSKsxG7UWbDdh59kP5om2g3wn9lZh8z8+KGjKOWkeaYxVNNHSmR1oE6/4qouLqjhlaF0gERRGu0GwHUG2ytgil6tTYzWjpFQpa3RsR7TnJqHMkS66h4Kw5ausWHYECoNntujyriNzgn4w4vtTC1Wm4OjQwN136ywbXJ6GMbfbYNX9XERv3VKLngzAPTbJpPbbbVs9AECx+kZiSp3FU58DLXqQyg41KeGfqFjPjrB3g1HTi7Fj326UR7ofAGyXkiygnT/13zNVoX++wrAEcImJvBcH7zwnuA+xNwFrKJLKeTEptYcnMLHqYp8kges57CaAkICD/0Lp+RclFe3xKsDtqXRLPKE3ALlBSIDhLDA2V5fDN8vR1f4Ks9EHRh3FBrfoSI2UqTnDeA0uASIk28DtaDPLeHZreGNmAaF4oV8k/UJd1fLQLaogzRU9L2HTQSe9zowLbqZ2grpvqm6dDIVPNzkGTJgWeduilA/lVKitUoGm3unSG8PcJb6MnqVhAkvrQvizM6GpkxlMpRW8ZKUVbVY+3MUZSvmDTCilPmOm70rfToacxDC/RvbKMiqyKMCJQNEyTMm/eUw+fYQyb7WouGzC4CrahaH/kEyYPmUSubVw+kGoXbX/mjyPOGGDjvn8qspKpSqJ/okqRMrISrKZ5G0UAjkaMa4tWUzJXMx3dtF6tPuNzJ17s4Irr0SNtkJJL+fMn4MCARfhPJmzU6XPzFkb3B0eOrPtMnRoko9NdVJwsOSibSs2Fj/1/ryCF0SCQDQAaWfGhIDey1xh8QlQGchXOxkQa0RSKPOtRk803b8WfZTOGYjRr0P1ZdkQxSl2m6E+mdQ+dlKGhoGVu7COJ1+7mO9I02m8VHh0ZUnW8HOKts0JKaVV+u+NbYHEXXWegcCnVB7lkbVZHCmptl9j+Z8aVwHjn0/wUt3qRo/2FNUZhq83J5wEKjqUr5o/A2wkwquKY8FMHp/6vM8NO7/HAT/9N1ggecRR8GGIYEnsJXFqsqGuROzRWLruX43cWO7tZ90wlbWNHeTeJfKckMVd8jEZexlfJEipN5PUPbZCShUsnK6RAxPgU0U+bNks4YaalpeLsbeDtnbyIXskyOH4gc4U02g9pC6xL3SvuJbDhfSoMffzPWePHVAACQYYhvf8LMdR5oTiOsq7xXKDFHnep6C5DrugYm63ppOeCPd0H5cJUhSTDEXXta8Ba0nksQYP0lkGZ4+eP5qPpZddQrLFWzHBzb+cguAGH6keeL3F4x8n5xVOhEGRGcfzcC8FJrcQ0tKQ9NRByFNcSM8uHwj7osCXahv+lIdKZnCgxrwvWyB+Ku+UyrJrK3ZSk5kCRXpB6ErgCJeRFy5liEyPvaa6H38i0Z1mjEwzdAVdMPDzFwgZilW+r8wdUXpe9/DQ0E6WQCslh5FUoS0nhUkQcxCObuDq/HFabLhtiVQRiYwZz2moLst2AZUnZQkuND/fh8Hjv2932huGJai5v5WFwUlyfCD4RqXREGuOaKjqjuui0xcM6GOdqIzhMERU18vyF7J700IlcdRHkpxbDYTYf0x7uDRh7+Ws7ovMxbsEIGdbBjVe52QidSfpGWBE7i4g4+wzbBl/U2NcxhudHTsUVvdT/bkUNbYApfcF+lrj32JVaubaM53UNQrLPUViJZuWvENgbd/94Zuz67szhiiDNLYcASvSaILET+CSkn4WYinafhMvRFzIpapX08Qa45UZ3WYMoPGaCkV4ymRTXRxn3OedJY69Q6R/yqmNNJgUQ2FM2dpvnpwmGZzOLszLyhzXTfbdwpogB+bm2DN027qMJVBqsNOtBoOQrZbKHhrZBwJyE6AOj1UQlVRFTKHu8yqYcFKnHV+n5gZ4OERPLifXMkoYysnTNnWdYaSJgKbsk4hw0mhjs5xGzeZbeoKH55O8VYozyWiRTUF/bIajpGy6ZM5+YGFL+1v/sHKCRixNOxPMXr8coGlvFuyC12CWV/Ab9EvAT5DIcDQFmbBFX/3qo1eEBToUbGDzJOCp41+iQ69RosoNwKkrfoktAPZ0zG9OSLpBgkdNv62jIwL7eth1tN5lQHbTnsKjFlS1jDW2HbL74ynYImEOWXM1nwkPHHaE/BnY9dODK0b7xugAXmGbiw3enmZ5r4hLqd5pGv87GZqonpoi1kvpsr2PnEOq2v4Y/rfxekXxPva9iyCDxIGx7z6OBbuVkNfIU0Vs10Llx5PWQ7Pn21Tf1TlZE21zG3r4qQraL62X6g1KTza3S9rkWCDO3EvF34hlFRpuG/exO4Pa9lLIOPxpU0nEJxDw10imV95UVuI94U87yvySU06OA3HbktUoPv39v4GyT8z7iq1qZ5qoqdsGT3Adn7eNsIVPAPmtJ6cqx6JQPfMZir5SAabD40EQZTyG4Mz1XTJ7Ltz/IB0GPXRLqD2t7NO0J3JA8f9isa7Yt+UL5TB96tYI9waxhNV131K/VqtiPrsJ4YwS07bMwXEyuMEeL/7zJB3msfR1u0ZOaCL0yogdh/Zx/k9Xg5JbywrfbACoPX0PRxzcPe0csUlMLfQffYeX4+W4UhdUyJ4+d5F2aHaK+Iihk+Nbdgryqi4BDbgNtS/sOr7skqV+YUBbJ+WcFuUJ7Zp3kSh+SDSObWkLazfS+7xogvOI1O9p2pg2BLxRWPmOcOCoAvRCDb3TQOg/RhCGw9w7coCVq7WEkE1iQwZk3hwNpTbP6jX2rHM2okjIw8KW8oxyQYoy03MdQthSMNtoqyg0VpjsCg7zvlBKNPg4vdNtEii0Q6rOyKC8L/8yWwituzrc/5K90hlk8V5G+197/av5oYdZjzsi+kLk3QjAUEMREkmL7sXjAT3f2iMcnexOz6cgIiNQ7YsLwXhPosopUCLdPXyUV+y4mW1rp0AD3unTzM9I8/kfYZprIYt0qXZVsnT0xYfxqWQo5Xtl+EOUUtVedIYqFTJa5NkT2kE6NDKMeKTA7lCqXoE7+Ft26JpKkYBGIgr9PpIifQF5DC+j4IrZMOdQIQj8VOX7OAO8Fo2mNNe4tJbt+NHrKuz2LJF9Ptd0O3lLsuZ++Gvp/cLsGXk7aJf2j4LYTiwJPXz0dwrqF953o1ynAk7UdyQcI9Bc4MbVraHgLjEnxUFGABZfNMPuH4Gxqah6h+HPHlTP41SMiCoXFyjvikenpbQxQySyWscfKt7Ekp4S8IHbflQ7XcHYR4DgoqCUu6yTnDNZ3tQOl7UvUOpU++zYNmrCIgw6WGGretq/RkrcdgaYO0xrfUeXKXn9VZ7DE9OzJ3wWrZh+oWMPnwSPcMJwsO6c/Ca+IBNz5Cgro9uYxbA2f7Im3Wj8gfx+tJUhwdQ5v+AYaXwJw4BNfwe7Kg9mLU5y5M474Ae+1rlFSE+bx1gT5yiKexLS8qYFGMxA+x2NvWrBHxHL1L8AvvMfxy0k45bL7ELGwIkg8YOO1deSDoY76KpMt4LYdYmDIHdIVyoVcPtRRD5xHbjU1xfB6Y23Xj1MkUFNxauYk3fbSsL9oUwXFU/zM6Ygac29GNmVxs/dhHpdUH7tIRMIzDkawxP9W8fwP5ahWGfK0FCXa4L5zKu02XJqTi97bOjNZ/zTkWI9seKmmChp2p0WAnpnU/8ngbygkVQBBaWpcPKZB8R7pf0OvOxyNI0FTbLHr+o1fDeFgC13og46aINhy/mo/xFbvGloQMFFMxd+X39JL9RprMIQJJUSgrpXv+oisvD/xAYEA2l9pTBsMzu3ud1q446jpmRmSGbTVoHc+0fYO0XS7Np3mX0g9j24JHaKHjTd9WhZO+G2ChX1kdHJjji9DGrBUqvxCRyDzzu3CCUzozxZPa2rBYZDwoySEek+mnnu/5zdJfYk8yRrnqzebb6Alpw5r8y3LiDh824UacOQVcBMToXGgJ7qHZQGZN4pEpnpXElB0YojHGV1lgcubQ/uRTq7r47ngOJgLU6NH84NqmYquJmpi5wZhXBV4ospJZrAQ1jQed+5uMZtf3iFPOG7gdul1FvmguUQfbuAApmenEMBJjPiitZHiMQaLx2sNizIVk6inwEOKf9YTcZL2am49s330WvNji0qX9Ux3XLyJXzlVHlNEHc7UrQteIrWIApetz9CJzuDrg1WrrU3rF/k537XEeF2y1S3uIKmKqbbO5x/7GZllMVAlt+yVEZCBP6Pm6NdRligwz+qXrBPWtKxxTOk22GN6uwmOvTd0ocTMRZgqOu1Jx8nZf871LB99SqbZ/3ZnzjWLxzKWk3T84CZ24f0g0GwBRRpWHqnL6ivO9qeze/eLmEnOavrt+oh1dOuaBdP89NTnN97ix7BnSppWVl5XfYloy5A36nRSGgLykbtSrK4i30MO6ifpiXrsyArBB+FzylUaKp+cSy5jjCe72y5tPxbMN/dhTkQZCNcq4vjGbNM5vu5J97hiCzFM6naiBvPEdd2nwSfHRFpQhNB+A44EYOFubSDFi/auUz920m+Ff6ZmY1hEq6EOLR+LKnycfIEJ2iTa9EWAI4p0fpzQwOUH0ziSMnWIulJ0yosIYolt//8Usj55d/G9KFiJErfCmI+YL0rXLjqxgj9ecWIr3c9qCYBw4erUTQA5UFjgvIBMUSIV0q4ZiARYZBLGJwdT0+O8wHCPLhw0koCO2Bxsk1cmyY8eSdBQNRa+R9jR4LoV2ORxNdTGvSFVmuOvOkuEGYXowkJi+7n4ZWXtmQEx/C4f6JMYt0HoXnbShZW6/GmLtgsAVbLRjmPYljQj7QsdxsV60659KdqhHNZp5tmaz7emFq/ROFTBLqTXinHM828HJFcb9aSwAkKCGnpQwF0qRnR1oOoLmJgILpaRrOTEqIHyiytxrFyJ07794lWBpsruki/GSaAOLGaRZfHZFTHRSmt/XdXkY/8cgiwFIM8e3Tg2aPu2yMpLZ9dV/eqOjEG6FASvals6S8dR1EUHhp58PX3JQ9BqS0KlhN1oraUcF6XpgVNRPWkfCwpE2HPhh77vEB7NrOhdUiQvOIjIu4/+WrL66KpaiRxZqbCQhMhlWXUBIfobEI7wdboIuiTM4Ny8eStq37yj5ZdOY1dnl5E47xPxNr1tidD21F4H2QA6GCDHWHdh7/u2iANnBj5sB8ZgiH3pSbb0VmjcR10gnMrG4P7t38AwRBZXBmZRWSbkoHxIv9ldEMHNhLcGk0GfdlFtCLG8p8TwVAf4PyooChru/6M9jMwnLm7mnOfHsWYTsxLKqBiK4zNzX6qag4EwyKtm3cju7ViP11gRd/WwFf8F42Lf14q83cKkW0ZU95bzOh5mGw/rk8+iPRV3T0YgpGGlvtaliGk+GqZxExwb7UYMYA2WzynufAyIcTJflxfvfA7z1AoZaoS8qtQz809eDKIOr63W4Wk3yA6NXw9wjtaO/ng7q47tgLQ3zr6YCfYIsHC6yk3+A/cFK1Vgd1fIr7asiRHeafVpReSRy0nkg2W/9K34ApZTt/mCEKnwVi7DKLp6CqRbb0B1iL18zSfJ7VmJ2rt1mMzHz0EUATRvuS8Fb6cpplVVwRhcOV7E+fiM2YypwSgzzeil4wL5wuArCPg4OH8gPtmofw5CgEabwfqB8eDvksE+1ENBwVvHFo4BB4A09m9PLxoyviVMSdxe31i2ZGGbF1U1v8iBT219YQpVJtKMMoK47lV9F326cALt8GY1s5urlk//KJqNZ58hfR9E/xA4EK4orsWyFgOlQ+Cg2jsOtUSseRC9BL03+hixkeAbizwBjVsBOm8/T7aSCa9Uub1oQLFmGkta+1fWQdJSMdBUFIHr+QaIMEQSORzCNoEg/OWLOiYt4lybTM48CihYWSFd1XlMRw09tMefPZdCn8fHEzLylyqxfeyLhvTk7i6vjvsZDQEUaqXoVzPp5loNyUYXJ1cKd8pzDpeqqobePleBmdhyEJr3Qf8LSHtVnX+oc6XRiQQ9qOqPeS2uXMAUot/wJgV45k5USZMMwBAfuwZEB/ePMJP5Wy51B+EyR8OgrK0g2w4qkLdrGSU/HWrQuLjnHWY80BrNjeDzmWdUVnN4FvN3epaW8nLovoRCOab/RtwCcBzX+dZYjmlsRmLtIbC7F5Ttjs2qzvuXi74H8z5sfdv72Av47o1ttSttH/H5gPcbxAYkgcPIcNd6v3oc7vq3Nn+gLisoH1fgIrg6dkWN203S83Vnod0RwA1SxMBIk8sAjDiDWuGX8qsEdqlNNNOTrbMkLKcJTDMd0SdJ46s/U7wldsIh5Zo0rcU+kpUXfuvaR7NWPUbEWwcdG2DbInHjJ9CNRNDbEduD6YQbfRciCwda6MqHnB4UYSn00wFXWZa6PmoTrWMTvFonSp5bccuh/vqhIiYipqiVv6NqYzYsHzLXYG3DBLBn7GAccKjS6IChIHbI5899c7yvQ78Bgq/eSBg3EO+V4SJopz310478bjt/QEuN2Nh/8E+XHGUtx6tjccQixuRmwQHA4qKObHQ1RZ+onPV93EMHvALUjwATbWq5bAmQzDhUPsW5oH6PRUMjjOZDotp/vshjCY1IeTWgi08NvMiRp5tyWXmUFMz2/dexC0NQPCG6t+cLEpO9zNTmeW7DwbLXlmBWx+HnNlPvUKV/4UPdXW0j9NEykVzq5wfVXektbdBS8ipOqx+nAlfNW04CXlj8U8C3l8aJ4P4Uxy9hI7WnnyPyC+OqTEZD5VmAPMlyuLbWMnEcTfv4jQxZM6WOxv83XTBIDuzB9arMWwdSPv7qyAsO3OOVpnxVcvjNJJHZ1SRLIaV9IG5oSIPSfjaoZFI+ohTDxTUT7E1+FVQ3zJrXFrOtIyUsb/7nRi0RUue7DE+0Lgfl/t+MS2Wlpgp8t3yc16ogkobXZf0EmeYQiQ8J+awWKZcaC6RDxo4/rEaKQCNd3ae46Np/579wQxdmm6bFUU1Vpuw5cY5TutNAznttryOP7/6/cz6jsqMwXV9nzVKJyKPexxfIKdNXlcxB2PqslMsLj7PMYCc+8TjGMeyyXLDz7NvRsI2CwrWOAd44RniGvvQ41y3cSwVVaLqL168b6wMtUAjk4Z7ix+LiIJqKVnvBQwHvyPELvuWDu8ypbGhv4KV1mo0B82tXbMh0E8Wer+QGdd419AT9kDlGf7dv886jiy9x8nYPWeSj5/Fw4Eqh8aHOKoBrjUTxVN51rQN6NfK23LNxMk9F8KvSz40wpjF6pyY3iy/7OjSi0yP+NreioO2fc0wkA8hPQHl//zf/GuLnm8m0Uq7xgECD3YxL0n/PBtg1rtowGr/KyXyOqm9qCQoYsJyPvjBnN63yMob1E65ig2xGD/F/kYqbgdoAcRc4/MmY7LWhBtRQScMjfsL0rDlD2cUWCX4K/QsQsuiOfTQ+FssGnzk23R3OC3U20+TVGyndRp5cOmRGLfdT1MoOF2aM6QvVYrUKvQ7By76hdBouoQazOM2TXXPY5mIuFJueKNwvVfzXd5UvKBpQ15qpLrOW57p3QSj0Kb1Hm6CoxaoLxAFuF9xd0Ci3uw8p+X4nJgWnstx2qALmc4blsDzJd3pYesip96uS7kv/T9n8kEK6IaJ6L26iWTqIszGBmqrgYcyOcUgHPZ4+upaJd8JpeFq5+SFzI/ScBpSeS0PpVGEYBFZ9iSPiCi6WYoQsl7RIigXI783TbOjTyVzugBYRGdC/UyFn24SfnGvWQn6dWAx0zaeOwpBDPRZDCh4nYqeocpCd62qbSHq8kQrYfbhI+BAfdIdpCJyCQYTrCtL3FpJhXzWZtwzxsEFkFVCT/2rR62x6dIpkzfWmqtZ18hUMQ0viXztbBG27AaIwfBXFkynfSWihMzrOrs8X17yFYoi9zDwmS6QXLuGsyVsDvJdim9O/Jk+9von2YG8cr/WE9N7orHmC+ywlMLnnLGKk4ozmigW3Q31jR5qeF+UdyKO5Ter+zpMtWYJQQH8lqS+wvIE00/zRhg51ALMs4sMVI538+ABn+pT7rjyRr/7Er5tppvu28NZpYmhMUXiEoH+/JIRWONqNzjEeM0NhwxKSYFoUXjGytfouuAk8q+akJ5S544SJLBubPd7KL52MxrbOKeIjFlvng1YfniEYWDE9DfBS7AznsJFsO1bEP9XHVxMqLTm9xzFD7e+URFCtcBH0HO6vVcXwBI55BR0q+PxnfOJxeORGc/ljIi91+RPjz9W+7T83nlqbuhQoemo/srnpxZqfiqEdorMQTuhuViAkoM0lrz7sKiDpUErUs4QCu6SMSlIQCClTqPGUR1pHaiF6hFE8erjy+948f0sVkmu2Jw+eyU/skJIDcRYaqkq+cBJINebCJUKVYZl7oywAv/FYnru5WWssw2bc1l5YFpYENNkHQndX+tTviOaADWGsZgY+b5/odHDjKL6uy4JwSD5mlBJOg5OgW98YlX9eVKNmg4SYnyzS/FOjzFEe6TPicvjip0eKqy8OImgrkoJI5nyeljOKfpQx1p/sc75k1Yl98yXRH12m0ZympSPgt93H1wTtv5BSFKPXtoGkPh+VnkU8pAeGBHUgz30QUT/QnKY5iYkcAgm0/1eneCt9y4c9LboTOV7lUlTaUG4FA7ysJjMHbNmbG6f0uiT0xgP+w2nuEgr+2FY0qMZt8EX7RSlynY1ZNCzArdyVYzpRGa8ILaf9videPY4EveQVUnNysaU1oCCfST5Z+gF3lyRKs5BqhrjaJmbSApL0kNrRU+LG40FRR4aH0/0JiiqJvUd6JC3Vhmh8jpWwwK5ikzaiA9j3nZyHBXMhXXSNFET38tYfOB4GUAVxTIqP1q+fLqk8fv8LgYZ+LIWegjop3v9QmgDfxEM/1BDvMeL2P3VxkrzwAraIMzOGXp7O2LHZ9ElvGK6QIqY4yXe18tnTT2WdkftyxnbF8NOOubyDa9CGUbIdtn0JLyjdYRklGDufSy2EbjVHJUl+MUecJe+XFxcl5YBFfLBxnAlbFyZn6VsfjwLJ3+JCYI6py7o5NCVgU9Hhava2BP7ZwnmM9h1H/46vbeGi2N+69H4bX8Nxf2BmI2dzyeWeF4Tsrr5v7m85fU34xN7ujCn8QC8EZZh+eJBENVxViDc/ZISzqqTFhKvbw8/8zMhlS960KyCZQWGeqFHF4Bq4BPk0Ig1BgxKX0TfGdF7x6GXVE1bEsvtMRBM1Uo1e4Rd96VtNYZ1booUg+/MXzFjFviDGN0QgZ/8lOChJ5FlRvMP5ax7BlFtVeq18lf0TaNxa5Oyz7ae59CHEfHmh1h4Jh+693tC45ANtqsUMAS1vFludrxpKFAOijkKupvELj0MqmmFKke1gk8WOYCpSN/4Rd7L1smAPRch4VwkyRMqPy3NrpnTq0GVRhBi+B2YewwhiwEYA5tKO/3v4n3uSiM0XGIACq0d9KcRiRwRd9JZECEOi4yYMPbrsw7Zt9t53Wlv9NFfrWutK2eedhsRn036XCd+Sb26VjZsvmeR1a6p/kQoK4XZHoXHXTGAgnGmkIqnhu1AF6pSHw9d7+7b+4d/x4PHPIqWd0s56BI0a06iZwrciGOUwbY6/buso231i6WWSccE7Plvfyzi45TxLUymcAO0TSB6fzjPDQdWAsg82I6NZWIF2Rrr/q7wyF4bjueaTxbj4s72swMuL3howPt6Q3XAuIz374ho0BFKi9g56Wa110E/wbe53zh416yvhPQ+56fQ0Ficbb8kSy0AUZ3lod4TVf7xZEpzZqmFybfLDBn+HUXn64Q39XjmZTxtwhH/v9jaXYUHLwGERJm9YrskkqQLpH4HInozUIspmQVLms96fUt1kQaeQnL6az5NCH3JxavtuSkB94K89N9d7WOahsn/IS3DRE5N8n2hBHgVst+VTXcLfc3K2EMFtNvibDIAm/UnQ+jPFnbgINBDaPMN2psQiKiZ45mGLu+8tp7zdWCVymEIolZflbKTcfHX7PJ/Yw/EryBj5P3Ghyltc1tpNS1whUwLum3qfwVmu87R4E4Vm2dHHm3F68BlRLQe2Mx831IYUUAKiTgkvN/Fo3zj1PqTrH6+IENOZYppzgFWAP5w7sOZbZmZSkRjqqNkmaGuZYkIYVohkdxUysMJsnjQPAVaXHjd82f1WcKY8M/n"}', - 'wallet::871b9de859991023': '{"iv":"E6C+AsQMfwtTv/31l7Yxrw==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"mmFYrdsJ6J4BV6fpRkR7JwQ4xTp/pkiMRt4Q+yxIw3m5soQmIEAt4NkIl+cEtNZZ+J8tMkYYhobHkOeT+jMJjS/QQfxpEqmYEWz2Tq8I1zIg76KuaUcKEXq78pONcPFctCkUZgA5p5QtuGlt0vzJTcTI4Mo0jJixgHis9EEhXa43ay6E0LZYdjQZEoNn14ZH+o0hr/pK4X8Muf6JQaXAXZ6ialyisf54fiYWb+TOuGaCjw1k/a3sSdUVxKdLLt8mOjlTlRqlI7+1VuyxlSRCUuwqb/rboEC7qLfxU/Dy2tYOzUJGDwD0k/CHF14DiZxHOW2qAKbL35y69K2s44clRGV7JtapfRlO7h6fssFh9qbOYoRO6ode6h8mD7PqnmAct77vP57vvC2az5v3vMmydy1+Hwc6zknvLJF55AXhg1yZzT3fa8DGC+ISmyOxvbGX4bxKObKaeoZAy6dMFwzKywGvtvN5cV1epFVTJs9+pNHazba40HiwNIV45jC2QeeJErWcH7ODJqvx0ckGdijfQ41VUZ5kNC3uroEPFazHeIL7NgK6i9LGCVMQB6jFhTD7kr5Wc3m7H9MVCg+s5eW3bbJ7elFuzdluCrgt9ntijhTzRtxVzDoYLKbq0bkaXQQtXwiDpENIYWRJ/Nttlz98KC+aHcfSrq3B/ZvtbsVw4ua84sXMPvCM6LQF61nhDxbBo7SVxWRA/TGpZ+GYX/O8ABkRP/L1ed2EXdTkGjKyEDy5sbMPEiIxYZCrfJ0DMvp7/kS00cLxxRi5gWzZ9rtAqrXDZTeTvDs/PjJNnsOH5qWSkrvIxJerBF5fOexv175jl3sYSl1Sym0IHPd+T4CT7h3N0UHuqp7QugeOS7I8HhFOWgHHjGmUmGm/IOE0MRRPdMrwLy+WPxzkcZH3Ywy7OuVcRWEaV1QApAz0jLZN129EZN7QAbP7r5M2+6wKcZvlJjdk9MIOBZQqkFTaNvnkNAyvzlbq6VpQnClyhZ+NAH3kzJedZdmqjrUSDErATSEaPjeWNzygy1+YDA0O78yyCpAMe7xf2/HnY3jKzVioahJ7VBJnrEsiGO7Q5FUpr4qbDx/xL4HkQ5G2XedIHvOdhzHvMFAgKzDZpAkspH0MmIBnjbZ2xnOYB8rTRtOaZ5f4aUU487qeQ0jKaP/saAx+f/ox88zplhSsAyzaH9OI03/k593LhSsMoZit4XqjtoD/Z0oyYukj8SzYbTl8yJrCEePIIYkyB07qbPYPDGbZCauSlILL0aYcxkFDd6cP07gKVcZcKRWaPBXF0gQEq16sgyuAxoOyBpHx+VMeNq0qGyrEBQ9bQBVBM9tcrirWf6Yh9+TzqnclG99Mk0poQ3PcqDZ7KBN8WTCNRYiVuQRssGIdLHS3bVl4eCaxJu+GLRqJbCC+SS4zTbVkTxExnx8AXUEX7SrrmLwLp+tzYfx7hg9Tgc8S3kMVCvmxiepdFPUfG+24hj+mnz8f3TjYZnlDacyhi6F5hhamItct37DLmhX+An6lkKrqjw3yqCiUlr+2P/mH88eK3tG8wxyJ8qGEtIumK6xW5bbeFmipi7w5N/qvNi+vij2uTuDTTK3Ys7G/Npit3/9gF9qkwdH72EwJSgwpil1P"}', - } -}, { - username: '345', - password: '123qweasdZXC.', - ls: { - 'profile::2cf943e7720652c2924a0737761377ccc679ab57': '{"iv":"zY72H76ShUA8cajds69DMQ==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"iaDWQDC6KM7VJZImT2jSRtbjnlYuUXUNofCMb4LkYmocwXWK9TpD4XC2/tSsZcXpBFzeK063xB+fk1OuPDrm1lX+VkO2RvxaOz0a5mv5526PQkCwYzddF1uZxVJY7dDeuwoxsqukx48FP9/zF//62rgdbv2QuaudUonbLb0XUcqn+dheH+E4US46dhJE+iJGUBiVbop0xV2uZWwAUeRzsaWFrw99WBw//zNx/HsPz277ZvtOfo0KkyIIoGFLuNJ30XB2Vh43+6rrsO9v2vnAtA+PIcMNRuUJ+Xsu+EtMYMxhszMyeg=="}', - 'wallet::7065a73486c8cb5d':'{"iv":"6Ut9/VXCezlzBX/zZSD15A==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"WFJaxxf808JpVADOT8EFEh2r7QC2X9+3z9nxRd2TFtVmfe+umzQ6zi+xBrjyg7ddDTRt5Gtu7jUADi9pLCAUCsm1zgQ85Oi05QyDCk8fBRNaNimZgP/g75JOVNJ4opnB5rXBq0wsUz838nBMyYISnhC3RGTo4Gwnd8hyiaUhD9LRb05IZ9fhqh5Lxpc88rmze7xjkrWWTPf3znqcCDviNVi7RdygIv+PJxmOChwHq2jRtY6TsxsjQXi9dpChQHIwtdcZAUSDXQ6nhvrFF8qHt1dc+ldhddr26krccOnwopynz1V6W4lBNUb9vD0vZV5Vh30TYqZwAvuuOS1uhzAm1qWufGnoz6/BF+0KblEYmXySCqvASnW61V1SrteyGeAm2/a8MxA595Bsmd3HkGpiRkz6UCeaIS0MrUvfzqwpi91pcitmcx//HxuKIHF+FHMsxa3RLfA3touI10z50jnFkhNbr/6vz6n1OnL65nZH/ZzgK4Y/CiPsoHAk3D8xbFVJ0Y/p+VFSR4fVUMvycEazvVIpTrpHv2P3/vP8zA/dsyvS3iKQKB2lnOZ225VoMHpc30JdWkXtcLT582OSkZfAUfdIcHOwZbZQseARt6QZrJ+paAHld8ozFnNAtvXdqOEIsFhvd3hBz5mobAibFGrFKl8otOdlioM2ate7Ek2oXt+jkSKBJYaxCsNgCV3rFtNU2O3EYn24pRBQ4B4Mwenai5cVUwHy8CoJ5i/UoThLEART5vMgVBxU7G+YnKKv7jloDn9E9x+7p2zrieXfU06yJJc0l7M7Y90hXAZWuHja2WPnNyFmqB7y1df8K2pAX2Q2vVZLKrvAt0/12PF6I5280yoXiAyyOFOyfpNwdaark1+3QgMLX0WsEvzvO2dGlAFWwwRiY/UzkyZ1qk5EhCryzIV+BYaoSr5XujrFOhNMeGe2CgGqgT3eP+ij2sNPKWX+WnUXYTF8ijysUBCBcVUbGm1sU34CVq/2Fu2uUsCKVHMzLupuOFzUJDuAOHOeJqAJiUU19MjSLKa/IisI8KDIYImI8OrWBuwpbD5b0cA7V+Dq7tfZiTs2tMuM3K8nYnp0kVtsYs/beKiA7UE/6NAyUR/5W0s+pRiv26G9WicQkNy9SKqHgSnf7xEVgmAy3IhtXqb9Tbo1pBN32AK3Le+IW3o2lbSG3dNU/3ATPFyWRpTfQWeuIPm84mNHOCjMrMEtFWdHiZF2rLSvDLBMS7xdqi10X9RKyD3hNjSpW8KbPVhQj9CdMOJCSn771Umm48Paf4llwOH8lfzqCrKLVXifMcVgkltKJV29itc+bm3BZ03gzF501krpg4XW9c64UKmmzFgcTGoyoeMYAMxzM9yOyrMOiEBADo/8xj/fp6ht5NcyVfCqwhrbSzcqBCVcXXpL1qxZvy7TRAVNfao7+tJ+o5v3POH7Klszgfdy4nH9uWnj4mxy/I4jGqM+hmbo8w8iLIQWyOzVGV/L07TKozA77Nlja0LBkvtenU+QEhWKzUom3z9epqJozH6N6qHWsVWsIO/GgFKwrxIx0uxCqIgDsamvZSDKsn63UPD38ZxQj1M7PHbzPDGRZ66AF2zuC9wEzRyN1c2HvaYB4o9mGdkNMWN1FuPgaDmVE8daF3+BrJqchDLgKG5I6j/1fLGmQl/cGj1IO2pC6VU6Q9bwnhJyusARBSvKajYyLlB6LDwMgXXiV4Nb473rm5QgJstcjoNZt6F6G+aMlgwsuoo/p3TIh+jmxfJsvbldjQFHA7WNDID1Ruk480JcC1aS9aQiWidAB8Kj1j189oA0KB4Vzk0hXse5S+DcTCrEQ6qRiMeJBwf9oS/a9uEEkFlUWj6iGVmSBR/svU2/PG+8R/+o8Gbv8CdF7jvdVpUjayMcdw2BHjPI+TZOrjcU8UggGE2YwioKPGUj6PpK+Isd5Ves4GVTRr1W9wMrOG6+MQxlRboIwyd8odCBrmUYOhc+E6u/hndJoHdZ4/Dm5tTF/nz7XdsKWKkbMurNrB4OHb9CoflVAfBkLy6EwjDS8yxhjTU5jLxuYNTD/NYFSWs9jjFsVeZIwulQ7V3ptpE2iBLGcP5I2LiH69XH68e7lQwRMMWixL3qhXo0bL4o0raV8yE9OnrTBbpgbJJZLcEmxfZdy9Q0Jr9VYVuTFIu4wlsxGUQlmB26V+o2NSAZsbyBdItuEUbJnJEG4A5Lc/0Bwd/oOVDT31BqvkhCwRpuC4/BH30l4rCqvDufEhabYK4Ho6goJfuVSw4NVSUT49o2jvnkQV+0oZ+cOTLmHM6E4kfyHI5jK2AIhsmVxmt/b0qa8cWor6SUPzdxBa7Sn/fdALSMKI3pvOfUm9jZDqI9yPVCbrNF6wRIKF/ZLdONhAkhM1q1a5hu0QBcnX05vFZAUQy+Xq49aA8XLVahfXJv2kROzSHli81eYhURZdfrLgE/bnGxexX8L0f4SBFhYC+9QxI2wwPAxGE/Js2RjISGnDm2Ozpq8GVIz8YQHujZ9ElHHqlfvffeDTvRNgd9n2TOwEnqFlh+149NGwxM5qrkDCkW4UgAtpfX/hXnrsDtYjlava1qpJFu2b9/QeC9esJnlZru7KOwj7xUFoPFRdnPK5EnvRjFMRtwDnNrdsJqC5eSntZJadwwBxjKNq1GnYq8Q28wHLlGp7YidJaPmLpDLXAtFLQPZZ4qZOHBssttoDvCy3Joq4A9rIhYAf8yHpJFun7xnqetiErXNLiTQhVl1MUvUHLzDIzHkv0Afnhj+XmVg8HKmkFKDikn+qEi9XGSu/Oz0wzC1Iww/5SJ/yGVoH3rytD2Xl1V+WsBcoAz2ipkqK2SaR4zfYCpmrUiWbhQghWRGUgrHLFvpHvBu9foLoxErYU6sDhdl1dem45mICOeCFBYYVQCpxx7QP02ASzyvqqhHa/6PdYVDhJgfNtHER3oFbhlN17+c+8SIg1FYg1lAT34MF8GgGPFmzTx0ylRJrEY/eDAKBdXjTSukoHegG/tpLVb7irkvgvrd8obkxiTGNUqmLXWZPOMEoyc8zArP+uJF+VY9zCyHQWXytf2cpkIEWCeEJNFWIXzq7Rke4GceNfM8SuxzI/n+vxFUqx48NllHRUsn4++93NcDONqvTHY1VXUOkt0b6sm7XVr0wa3SsIZcro1eX1LB1iVVfwD8+BTHUCjo2qFdm+krrMBRgwDhoe85JYqVwnBfnYm9OfrDdasfXjyy43HNGElfyG8yRBbZ52pEoep6LCMBCj9mDi6VPBe72a/2tiYr45j2j4Y1hpV3Zwgw67Ev8C4+PCRMily/ikwAfA/JJbsBeutQfh+6xXIieCId6ZIBDr7TN1SdSVWLPIelAFtoJi0xWhj/UW14w3ZR6BZOzMcfSpvLWPH21cbYov9rJLNH4fjbRew7wURNqpNH+Qu4hp83+MxVzY54N8gYppXG2LbXKLGzbkEiHLa4mcB0uY9ElzLI2elhL8hQN41HDKhlfAh/k0+3LNmpeNusF78hR2oHf+vAug77iZxGlHlrY9X0/eIHPMCjP2WSnFKt29PiAgg0omkxUBDttam/SDgEYG79jqg26T+QwkarrGPY7Wb4rvjOXAGwFrK3rgCOUDXsiU4hCvY4YdLitsyTxIc43+91vWDi4havivgYwClbPhGVCoO3gQUB/Elggv34P5LWPyWt+lRLxk/hDCkVQhLBAKpmI8tqBjLItluefbuy016jmHHdZOYsoSpkD0nzBJuAIxJ2BiaHWoRJTJNju1oaEac+bRe2y7uT7JaMtPNmwQ7NYCKSxVHXz6MoQE+ptgIZ/W1ZBdEABEEGoFJfR/YBngOAJSeuHyIherzbfZXfvwtq7TdXz0Gmnt5VYDLWBn5yymIhSl4JG5PwKWAuVHi/uZr+3UQWx7XD8kuEZPgJ/6v2yHsDIOIQYBNR2D3EDj9X0yHCD6TDkm3lz/IWjpOxrP2VbD/C1EMHOYjrrMRP0jyASM5On8kUFn9ZwuOTQn6R75Hc8Jw2DIChxTQ4AncvK5DVTYf/q6YXk8XeCQofcmat/UvpWo/Hx9tGt/BPQj7SX/FmoHpUGqAo+58IJ+5vjzInUs2FP3z7TYAIM9x9QzMwoENcyKkbo6+x+P5dRgHkuztdTKam62VGawgVixScsn0y8nfNNZTplHMHdH39A44UUd9aB/8SPLaL6yOBHU+y713uKGFUv7wPlFnlTQMszKhZLryCWcEHQ3Wjy9Ik5+W9f6PjDJXNYpZh1MPkasHzLw0W8I6Z4RKRGA9KAkXczY0miCOdf+9NqpGv1kqfRWPCT32K2qb1b6P3z+Ed/5XzqH44JL4zVTjYFplWd1+G2Coe+VygXyqKx3X5w3s6BPkjwcKsSN6hetOodlxDpWIJDPqTlYxHHGhYMLN89rqrfPGqGjnDa/ym+UFoqbVhip9zMBkYcL7ZxoOw2LPnhjQPnFpq+VHkKtzwCkc7MyvI+E6mQTlXLSILjvHPzAUuKkdwIWFHigESmnjC7gFhXMgprgcwRPTuMjxdJtfwED5EmZlRhQgTvj1a/lJtNNO63z30WYL5afDxcVlUC/fmkOkKJL88qXLCG9hRAe9sw+FV+ClWsE6d8LoprBKM2U/reWy8gitQ/cQRutO+86aNxE53K6K5fZS9sNYlljLFA0GBDsTBedBnhPeDKynQrlYHM5uNL1DD/k/ZOeHRMhe7wnHcdQg7Dkv0qewfFlAMGO9dpEjzNzNUPlw2s5EO/IPYdDERnzDKrtrYCmhXdFusmUeFXc+QrLi52nB+9xpSZOJO5PdUdayuqBSgmV4OcgNeF/MD0uPTYeeEP18jNE+gSYOeDfmczV5BIqjD5P5TZHaOA8Y+TcIaXLu1jJxepWIrlzcCcoM16F8Us9nmpkZulItt0F15kJI9XwrsX0gG56RU9+u0I6aOwBKM/I4/q4S9glUpApCmrRPYcBkZt0AIgypDj97H+KyeTqq1kO3Gm1JEybMQ5oxV/tqExP5SRK7J0I4rgMYO99y3cRYwvwcklkHFAwyCJdZtzWDGtHI3L77ofYhSfirl4plwKrwJ+nQNojpkf4x2QcmPPxFfu8jJrYFGuwQvkSk0izfl7zHmL/DHQlhXf52hGxVCPNysU8d0VkTOTW0EOIgCPgeMfcZ9w5dLiOymJyJfok3OMbS6F2a/roiWu5MI7TCChMArtqaK3R+8AUmHbLNeINDSKOVP79DlLSCgnF5PPninwLk16gkPqd2mK/3EPKiPam7dV/R3f/utRBqlp8C7sYOUZTIdb+M/dibhRuBtc968imh8bLu2LGN6xF8cR8rXDKzS4st3Fsk3uyEHuIqjsH/+GgMJqpVI31w5k80NixzCk/g9ThcMZWg9LGJbT+9KMIUItir8R0psqwulfK/k2PUue5cDJcyvtvJLo1NOaQo4dCyopNS00Xb7OKUeIZlOCCSQj4MLmEqeawssyoHpEpyz2VKade0M+kCmp3f8vOlmL9lVVt+tNNxB4QQuAuU2nV2cDi42OQHHFfpu5ND1zwL1F61a2+TLR/dkHLpOVXbz2PemO4JEcWrQAB0D/hRnRWB7PjAm0NSWLd5mcZJ4SeOCjiyMeVJTpFyYvotSw7EnTcBkF79nsli+0BhQOM72ykq5JDFQLwe1JStJ26R+0JoWIAcxu2sGgPzc6/TVi4v8TvvF5NfLjXZ7B29iLQQDAYX1XSJNtMJv598ziNmLAISCFjOzLOLpAZTSqJ+uDF4DYV4abR+XjE6zYwgtSfQ3+/lMXPkTrJ/HhTCV1uNcZ/0m/6gd5+JAwjlzOFmxnBtcatR1eGTYkFHqNCpZB4QNQ9fGPHPTsEICq9bsj20fmeq0s9CpIgyny3QS5dzJgmgzdBdPXOFIrp0SiLl3OofnEQNR03+ja/cO/5ad6PbbKhg5MSjYZDjk+i3J71/VLihe0SH5MQZ0RTvT7edWHUeyL/DAqR/soyLO2/Gz3tXzhWVN1zb5PuJyhAVa/zS3RSSk67CbiN/5jjJ90TvFKNbG3L86+x758vtUvSMicGputhrN4G0wDxWBIRwDwu/Mux9X5LAwpRq7VthOxJFNzK2td2Ym6C0fF/dEUpEwXjmxaDzb7RNy6Dw38eQNpDiPlOUo31zpVtPKmKCppHHyN4/QkxXv6ZZ+VHrIUvdkU3MVsnZMnnfrQje7DgH3k7dnqnS8GWbxOv/FQCoL88aBDspThpPY/N2LxTRA3UpbOcWbdzuE+SaQu0U9i/Bvmx8yOHE6H75vnFRxUUAJj4YNW2FEmIzTZkKfI4ss6QuxIEHgfWzGBszzl9H+QLBMT9e5VZTSbNmufiFsObgtLNaBoF8Jtza1Bzhzbeb3Rv7X4LAeDqaCvs/gjPVUxzmbCLofg6r3SaayMycGCY34CWL28grFCynUFHiIluiHaFPg7QKPimf5NW3fiYqKNsBAlcJNIYQAFMLpQ1jMAhLki7VDRCBekqyKBzAAhkm4rg4LlE3VqUJJ3ARp9YU+dn4xpPrSeyD4roWdRuA+0YE5W104bv2ziAgOORT/0E1paHZU2yzWSqnNEy1qWBgZ4wkaUVEXwkgDuhvgQXuFta50iayl/oNTfpnKRl4oTLCGBBnzvpajaffB7NsVIfp3Ci25r6guEeJV/bn3QriK95ZDs9Jd9vKghmg/yb1QLV2G/9pA4381gU73u0LgwRWwGBbf4dlOdLxvJ0Tvo9AURPyn9jYyqsVZkoVukJtFCI0pRDPxuah7HLpdg04NnJtUo3vbIR54pfK/cnQqB+glQEhB7tqSCB6g1HxTbBRPSNeqS03paylcQer8xh8AlVRAOOrozGY3araWNNfgNKSIi+fU0kBXwB+KQMm/rCvXnKbTndtoQQa+E4F845UT2YogbaRDusK0ZO+K4FcfOGt9y6jccjxiZ97Q5Cvv8f3NG5C/5J8oQSuBpIU9ji6c/e6JIu66g6YpdgXMxZ0MniNv8ErRRU+SdF/blZbEWbc6+bbj1sgXGap5o4NhO6RiFBZFK5iDwmFv2NIbzAvj3lkSBJ7uysorqMrBOQhO/PEE8Em+dj0Zxaen5iQp/S9ep1DVRV8cF25YqphId9rjP3cuAHTHt8Eey8AsxwwatzazFPBWFHrJ5j2hluBFm5u8Nljx04Gr4Q+r+4VeG8T0wDE669rQA8LNdSyYkrbNCogML48nTS0uU4CiYvyGrTa2zv4iKTqi+lhygbirPRQSua5aBF+3Je6/9ErNlblXW3CJT4yKSXmmDvgxHU/en+qnjRbE3Nq0o1+M1F7fayzFrDuX86FACacib6nvZUM/KNmyKITIAiBnZ5tsqve0oRv7q8umM1kB6SfDdYVAvPg+fjdGzayRJGevpq9kDL+oxiylH7ytDoWDQsmcvSw8v61sv09WIc00UHBI54eMprDtvuhrMduF/xx23iYZCKf6tM35DawNxqF12x1aWswkspI9zqmHzybcNz+/Wk5AfUMJZV5i8ep1xCoOtBSce+NjE/fldncNBiQTPVgfM3L4o1mnPK48M3ktqt6vozH4J6ch186iCAWsZqTnpya8ZLeBhDXqzXdAphZTRuTfkNoEtE0I5HXMLw6f71jbCyD9NHXfTGHZOemTZBIn/g4H+vONtqUqeaGLrVtpyQ9R2sYHACJ07VENIoDG1pP6+gxbI5pk1OL38osVCtl7IxIhwdF9qgWsdDiz7T6S35G4NpRuzpZRFaeeM7h28J1YAo0/+aha/uYb8iECcFtaocoE4NsUhLNWOqQhjJJoUUmgCrqM9/xchi/MoJNtFAHmNuMmduGIK8LK1f7sHlRD18ghI22hWFWOMWaaK4zdOYUk5YZiG4H7t9IuMl3qND3PrNq+jdeJlHKu0H4WRV28rLSd3py+kxZiL4fOhALJ6rfCzOem8Xwy61wqVfAfZw+tNs47ZohnR6kdYI03pozR/KGk3BkKrfDrz4hYPdNlUxBqSanwfwrdoU7DJ00FxvxpzmBIjllIxbg9ahS43+UmrOVQS7cEr8TyhkqhV3EE37scP2aOt8DgqBC2TxrMid4LFCf7UCLuqDCWS/Nck1hQt+cIjyxZbpeQVeR1Bg5M0Ut73rIT6VmuoZ3LBx+7/d07z1EDiwA/Va2OKPk6IzmuxPGb5mTCTpd9MK84TgdlPdQyQorCzko83h+hOkoZ0UDQ7CvAbGlPZn1lmPIciufCSMkmWJWy0ZQbP31auPSqTBHzemze8IH+r71mXIRucbqT9L52g1S8bTiS3uUHu6b/bv1Jlhe1hMETth69mw2Wx9uFhy5cdoSMGVl5N1d1w6Y/kvzX62uc8H75Pk2xxxIa6hXMTYn9cstsHAbhJLlfAPcKGZoRv4hIWy9Pmc1bE19lBufdfKbX+I+ZzpR3srW4h4m9T3wLSth45mMojowjnDeHcAVJNz+w3HnWYUkl05UGjPMOC00syIYXvyTwFBHHaaMEXAroljNvbSKyhEaJmbI47YfAZ9WhHdt/tPoVLyQApr7Th8cYU5fLNDHiBnyqjPsTCzQB6H/RphOIowEU6UB1OcPDXT67kUrLnb1d5u0KMkluaA+8O9biXCUhSgVYaOsorxYVdDPf4NYstrBIB0wTW6+FE6ynVCw7BUyv1LHx1yA82OcMv48ysDredg5NYHbvTtdr9xpUkynXJyJ4p1xTaz/TY0hqgXNq9kS7eOahVa7QYWyH+rkifOb5Qxx9sqp/ehKlYFkZ188k73Hzt306XuF1Ku2i5P/PDGSnuB7ZHEu1j4NhAnC4PxufSrNiuCxv3kVlb1aofWdXS3tPWYJnFH84bgkigDXRO4blQIdXTKaI4hQnNf9n38/BL3B/x6CFHO54AyJ8JArc10A7L4ndCyYP/Oe6gjQf5jvzVLruWG3Va74s47Qm572koAZ9gRA+6eDEFi3VD0L6Ir9Pm7sPx1FsTkclPhSRO1PQpi3OI5vsTgEWEP9voaVUrZyfe6Q/IY0HnbrYW0NaBSusR/9z6XjxVbE7AKYGIlw5TA6juotL2mqES88qZ7GF0SHQjh+gMGVzAG7MTiixQ5/F/+d+g1z1Q+7+srLu8yfssggiS0bEJ3eXHpgSR7KF9/9GcXhJiof2KyvoL3rzBa838icKtsv6vMeM7QozDNjbPmDS0NLkJi8j4vNgOTTbAMkMYJnqO/QGC1PMaWUDzEkuIZZGWhAYCMEquK3vo/Ce3Ds9OKe7K5/QiGPBA1Be2bqprWXp5nMBqoVsA9aWxHqdMe+PN7csBeSeAcnmoNBGh/NRYJHx0liR2fybXuIQEY1/zRrTd8AoEqyiz0t3OBy3TxeesTBn1bDRYLlIAskH8OOCBN3Knfhp9TN3kg7xu1mjyx7XlKPVySUizFcbBVPxO7DMadALpbkHWAtNkV2qUf+66sRD+QQo80FIw0GVPPbzcXYJd/TjDXqynBIw0eOVvhmmWZddiFaxwtKG32nc9IzAyGr0yjPK0m9k9QklgdB204MtVt58P0GpvmH4V4RbdRkReB60ptox92dXIbZM2uD3TWr4uR4aCATQ7zmk/xUFB62WAoIEQSvMhe/k7t6O8BAasBEH6Jhzz+IqmezpJ17weqEZMaZOaJPpqN96bykWEN5WW+aYoaWJNR4Buh3qg9VK/o0u9iMOmGBrErpo9C97UKVYDjyZsf3elLG8lxYH0a4OrLKizSdiOIE3ydFQPmHPgA/i2kKXCjQBfcPEOD+nd5oUQmdMfcYyJsuPKs0EqZu3cGeJ6naBqquymFxeiWiXD/qrL1110kXBehakWZ/3kIT6VwMRwQCRsrvunpC/uEDGo93bK0peirjXE2OHnRh+faGsR4kAIH+BZhVEn8NhSL9441mF2RhfDUmX3m4C+dj1TdMPcik4nCqzY0kV0DuzQZgxfy6PlUiMVGWFKh7V/5+z5wq5wL8qo0LX+xhygVhGFnbfIp9VFnDGmcpbKvCXCfijHz/cPR8WvFqV+TRMpReqNamLqqgQP+RE5Rw0T8bb1E2jTvUElobxKNX3UjlWhj/S5KZiaCZ7u5fp4fZ5aceTffyyanHE2851d90JdqgadOMEfdeJHJo0GR4x6OagjRXyMHwu2nLWuxdxckYoGbaA8sInc5RFJqpezLYPhuCMyNTLy1HIesQRGmuFrm9NeG74KxgHTdbDCl5NwVbYoxzmGG8bbzH05MpUVMmQpmEtIlAHwxuMpfh7DUA2JrUzpFO7P/kH865OQmds1KsifCm0HgjCLQdcmY5l6iMfMI/CW34O11xMoT0ZyP3LWBY0KCfJbGygPjfmRJR7KQac5XRh9LEyKBwMRrfvITodV/dXZcH+t6Czdctfme9NLiGnxPFXI5DnwohBg72fJLokzJWUHtzPjV9ERI9ipuFsnRp6mu/9nvGyEhvXpUFsTCRBKwq+JQFC6AQGzoVpLIHI+S3V4ppA9PziZ7k+0/eF5q2whNBdyFpOWl4XQedY32PKBr/Jk+9mpbd1Ii0b5kwH87BYkcjOl1+MQ=="}', + { + username: '234', + password: '123qweasdZXC.', + ls: { + 'profile::19510bad7f0638eb36548f9ad54f76fdfe2254f8': + '{"iv":"ldPQwfVgrbBbxqyD0t/fCw==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"XYUELIWyxxAmuRrot6wXAG7f9ccAaatuI4Cuy6eVIjyYXCuR7F52DlG/cr2OdkiR+t63jLeGexOmyD/eq2cU8AYAK8giA8D3O+ogZrciyHGio1JQt+3iaJ8rj+4g/YlXC9Zx2gWPD8cToy+W3aMjBD1QCTsw27B6Lr6cp3/21Ireu3c60YVYRUH3cUF55tlH2ky50BftqANgCUjPUyb0LUoMaw99du0rgzat7RDbEWVUeQFvSN5UIUssVxOyO437bdsXWE7Ba9SQPsTHGToP+6MRh42m319SVzblZjCHyLwo6NAfDypRl5mVcAmCv2RLTYeQS+Ro4Ie57HRt3Ngh2DNBAm0TOGoLLr6rhMl1Ac1A1BGRMFDq3LEEJARzq0+dsz5WcX8t4lQ/"}', + 'wallet::4d32f0737a05f072': + '{"iv":"JyZc5viMPjPPz11HcchsGg==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"+E7nNVViL/NvOXaHvPo1iKVvGRo2RKnhG1LM48SF2OBbd4TIGtvB/V7YQOvvZkVGop5GgfqG7HJ0fx19TFHEaYvMCF6Q0nzmoVkwZlDfkzhzS5iu7USs6I8RV+fis/gg/sELXXEBrwE+bnkaj91UEo94uM4svF65QthYx+RMR1SlWsTJNrCf9I+RUZJLzuo/41dgf+rZ5TIyuSqqMUjUtFE1Bpoe1qbp2tcROGGovwDPqs3P8p9ucIJdH0vmiFIV/rqg1Mfr+m/m20j3gg/ac2pWZgKS3PJ7ZsnHct2Wam4yKSrgtZQFFoA0xeFhF4D7ZcTFJgsgHNAKrl0o+u72D5aBBaA4waybP3ZpGYiy4Pzkz5I/BoXurvXHkR9bdZ83bG3/Jg4gJ/zcSLTUjLK3YfVWfJeY1RMBiX6a8i+59V0I4MPl9pVI0CFSEjMOjZ8lbUk7l6wxyvkvGQgDzhxuidWjDQyY7N+BkPHjNXQwyyJdLP9VkLDvgP0HL0vhWV6O5WehfnICr+e6x9LuBKQmZnXpbEkqI/LeM9Qp+JWwC0Gr11ngjaCUSibSYaqeJWtbgmP6bVP9x1oZ2FRnAPEqjFK63vC+WhtB3nitcL1eK+LOPzjL5/98ghdPecdyQpEdABtPNd4jt+igJALA/v7TitUHScHq3B1VTO5T5YFREp8WYSg0TqTQz78BBuqXDJ0Yh6REXeetLq8/oWEkxpQVWkMrCQOZBHgFYv2D8NJU0r/C1SCKHFkCen7hL4vuRzG1QQNd37haTKxBsFfooBgjnUBIzZC6hVgAcQdiBFS4tu4HxJ9tDr57AoSIcnT7O4RdXqeWBxeq0MRz5nyvbOR8hQqk7xP7yrEcICRSIujksAhvIVoMLx0XqWEI2iaeW6IDbh+CYZF6Cd6z388fyplZKyfe3z+V/L6klozx2IZuL60ayQo/uvXhMsmoAcKMXsHt2MGDVgHnFlcTO6lG3irVd4rOtaxQi/5f9cg4+KU2QWUAs8iJnCP07wRG9PLF5EKklXO3cHdThjcKHgTrBicPrrYWft0/oQzDeP+oaV0qqCV1OsnMfjZlQXMHFD6Wc7CEi9CImrNfzJBQBXORhi4PPLrabpU8Ad8t+YLoYCgJcCdE4sG6R/GfksNoH0hksIvKwoQEUpRc1SnpxISlA0BIntZEbbm2Vz/soaz9u5e7v9RgLtKl4yTbEEiLXn/XE+RLYc7pPZzYAmr0E8w/anPuugI2mToOaZVKv3bMX6K7pyOB7t4TasG6GOqQf4kev/LybJ7I574qKOahOUTWSEvriht4bzHXKCyKMasCawpfg6QoiM2I+w94j9YCnGB1OUd77qq8WX+Y8OSCZkpx1FpOCy4qGnIa4Rw8BQRA3BzRcJd8WaXfiRIMbwXL7xMv55YV35qHMDwdWYw+64jDHxcQmNm7zdeN6c2TZglJ3ryn+OoudEL+u5IraawUJd7idyKSNjr1n7muLp1vNODTmOlzVlenJrBr0D1sj+tuh5zCxbmGoVyr7wtwhQnLq+18X8EGS2JzHfyG4PnXDqKVGZRb+CmfTSKvfIhFr+ay+Gi2GwB54eMHtFPUlWOFGcFxJgRCJbsUvcLODC0MF6WuiGzQITV+5pwRWLZ01ZWbZSEzOgYv1xn99nthWfE3ri0YvxzU9CCagd9yBKUeRhfpGjAWzdHiEwTARHpMG1YQkXUQI3YDTLfEpEkKBSgFLr+kieeM7/rYLV840kd4RzxV82IGSU3i/FE7xmo0R9GNbBo4hFCJl0sG1oP82C1XoRVGLnBUKNWIz1LSonNNFMRthnaEn/x1VZoASYTWvqwlB3SkIdIOs2DnsFq/EkRvW5BaowazypJ/asfv2wk4OEtKm+iHgkGIJYr4Yma4pOdQ+VBa8Lr7VIrJcLvyho8mDRzLllGtN7E9vurIJxazWHpwG/XDF58trPZwCqCYF8lIj6r4GHX0Ikizi+1ciyNb8rgFTAZVmJ61beL9C2MjFfR2llNqswJbD+SlNxspFo+KEeCB6XJi+d5GhmGppBQFHz2VKvheMO5CKPADWXmWWiOZOhLvUGjIZDyjsPTeaPovevdUwuiGsgrekHvhLh/+x/uocUcrjp6fg0K+g1CfS2jxx1vclZM2c+PSWiWdnRh79GcssrASnIxoPaAlEmw6F3aQXKXImT0EEubWg+/gioGaQUJrY/Knvef3sOn4B8BwI9ym/o1iL3vumiqu3wopD5dQamknG+luZFSGsQ9jms6lshbOM913pA401d1AA21AOyW0YelqnnXwyr9i6HgCkHdSKtP/01vS6qorA/Ye5WfJXVmrRsFdz+eSUNMTWQec24B/f3bMXGUJ+mH/7jS1sjEj3QTiQaXpyboDQvBD7agRhZp+oTzIVEKl6bKx6yRlqlIp9C5V0kDTtU/J+q/FmRKUfBwAFab9katVs/hoOzB5s1O81CUn0psYphwSIaWjRNYRjg5l/gRsDT2wt57rUtBC09Sxq94YRsShrTdQLvH3eJdRZFcPnTFYifXafRKcZLVn33EN/g9hP2fSd0F1AlNYuiTO0GDjK9/Ss8YjUPkLEIzGHwjJ/hrwApRia3mJmH8LkSukFzdX3QM+gtMQYk1KPepCYJkb6giAe23th4om6aXtt80va5obdoPGshDpWcmcBjvHcEdhe7r582Hp0N8O0qZrpMF0Vlu+JiCfrW6xZvOM6xyOM5m9sKvSMJuBzEykKAlenfjKA15UZFy71VCEVU+PTkHU8tKOj8ManP5nLtPUsm+3EwkRumoYaNE8RdNoWCnJVEJ2wicZYfvoi6KHB/IYIGoXx3RLiy2GgWRZnc5sMeZAHhg767YVxLvXd97VKlhWdIXGVyweRxtA8AY5aMfLDktSvwu4/pEQCDHAchpHbGRrBexZK/6yVKdb5UsQ3WZlrvlHMTso9HB53uSl3YRO2hBgbH9kodv55khH5H5uNR8mzHFZ7N38PnUG0cUaO9pZ6OsEbtjiSNdlnMnegojWqN7jYjfD0nXDY+5dK86jZaSlE4wAkeQ6dcZadPLklxcQVGYjgmn21hPREaPCY0Y9OeEF3n+HPYCqLRdSRB12/BHYEg0J1voW7UCq/rWzIKOGO1dGOWZjA2fQpdicxBfGkvjdVt+Pu84noNIYxuEv6Wsy02f4tEEnN/Ncos7ibIuCeqLqL8Tfh3nF0ZPu4PsDjN3VkZw2TC6ASVxHCo2spJD/haDMWe4A5WnjHUpvZm6nvS16WX0q22fSv432sE24hMuRv1i/Ym6C2qcl6n2TiMHLyCHpOwrODJkElu9sHkJsVdOybYgs6Lu/zn38sZsyGE64ip8AnihCBmQ/8ymAg2z0UAwyVmTzy1Io1BDYJZhngaR/RD9j3xgZsa8Pqw0OYp/qYKlY1PiXah+gWn1Z08sRa8dCGgzftJ+5zbyzyy2m/jafv7P180fQPabEOwvrWX12a7UFIPy78Q/KZUXra592cs7g3C1pP+DTr1ODxZVGPffQoUiPhGoaJrJxDlZBJZs+Ffg0s38ZAo5MmBRdtFP6UakVQBJmvqLXqWw/e8CIK6SBRpccrHVt1+eKZPlFdrR/iBJmvDvUqLu1mmD3lODE87mK8F/QgrVtdEkVxBQNOARxiUIA/I1prmEVNl8kHH0HM5epa2czBqTMgn+fT5GVxA7cT95NJhOCHhIVAKmT1ACHlwshjccLyn9o+zO1LR3uOCnotypHZrWddenNJoKfrB50J4E6/gs0F4ylKH70tEZ0RNh3njWI5bX8MFn4dD9dBZTYJU2IuvX3zuDL4cYnpOl9VekOjSLjg6Murt7Zr3yTzTkcG3OJe33BdOcPmzWGHJHBXc4g9W8zLDDhxUUpIXjdGm2oCASHwNf0TRjLmu4tTLpOzdvuxMV0F1eViRIAXoC/07gNkkF2KMldc33QgST/Eb5gjerSksZ1XERINoQml3h1TM+64myi4hf79E/CDOs2Estcqox3BDc1aZxIWFaeL1luZoBWKSwnh5IVVLuHrHrfzd7MwK2TwVU+bCLuIudEz9riIXfSPqRpaNj8H/f51Bh2MNX08M/wlgRWPn8upl43kbGqjQMmHWW81+F6iRNYp7woG+DsrOYUmUiJTR5InglYcbOVWDBGvzS7YQZjUBbUSLCxYyAahLyT6ZrZs/RRklwixVrt1r41c93FvuWhbtoVSZyFYUcvQvnpKpz0Ntps9TKblHnvohvSBVNI8O76iinkMrFC/oCO5Dc+tR31n1hLTyTZ3JLN0XaY3CS4KvcVVPMaM0s1KsufUo5wIjFZjXRYJ/POuhhFlQIybG0tZgNdRObghpp8fIrpkNKP/eJCGGbaZMBQ2/astPMHbKOr07LXDjIv+FRFpbXZsGwq98iHaUCVB+l2gSn9yGPFZo3W6bUA2suaSoV6Yi2hN/SEjt4h1Uz6N560uKbiHvT5BFEJEqz1fP6m+ab48Ap43ECrY1cMBufswHhcSVxEfLZqu0Qgdnq0ABQOqnFT6SVgW4KU0QbCbGa23XftkHLLIdqldb19NxRqe5cbDPKZ9OCVdgvatkmpXzQc/t8Uko0uPMm5pxzlw+tZIfl0Zfj6afdlnEwg3u+EkepEOPVP09rUBif7Np9v8vndBOL6m8ZBdLXDqQjTaQ4gXAYj5N0fZB41xjp/21LFSXLaTJD1xOY63O7DS+cfQnUccnC7mtN6Qp5PqZ7RXbYrubTBRttpIpxyGJcgHly0G5qOqxd4qiyT7jbv+j2VkfBvroP2kZJTupnSfGPW7QfMltVcPjVdI4MU9/scNp8XnWoUBHJZ6jNdjL69P+CjlyG9qaFNySVkeWiADGSBL9iGbEG5nh65DpWinhHic0QUC8BVtVO8qEWGt+gf+6npnzyCKulfPQxb5ySYVPifgGAPdaaOtNkEX7AKQQNpqcFD9RzQEOBCK5+AaxLE+FwWP5wJvIVoO7ZWEvGsZy069QEanQarifzw0Yr/WHFIf9oW++6C2bpCPNurwxZwGElniACZctIuQMOQ5ykkWz5yH8dXCkOhJYe86wgTMM3jTRtZ3sgQ9L8wGfUpL7328RNbhuRAMifmli1tcvH+L55ESX31eAwNQaqVdfgpDOdvFFc9yDStrfwmFx/VjfbpmilNjZPJor3+nsZnz44Bh330pqiGQ3AhBR8o2ttWRiWNMXLj/4wZs7s8NvhPiS1D4LkRXHn13W6z8Cl9XMN1REvf42qwglL3467I6fVUImPwMF1cB5giu96Z9k02nxUlu4Xz28MxLusrfPZ2sKu+4npz+t8aEFNJ/8xUDPflyGnPd9XfFSJml7k5zv+M+2TnHWaQcvi1eimRSOmAoUX9ytkgoDiue6Ik124Mm+M8woDO8pqixUcg7/bLdMx8msDbecxTCA5744jH/2U3BzQbUBcCVmpsD1yLmeUn4iDOydED3IdBtsicIBjbctOw2Q6bXwo/KBJ/N0FhCZBxaC5FqbYyHEZvF6DdB19/mzySgYAl04gQqf0emJUfbMAtnTXqmZPt6zIec0ACD9RSomjO0LJz0nxHL2F+60bB2POa7SOGVubIqEaBZDGOwKSZxOst8wM1QIhEWyUEx+6ZG+0a5QI8Y4iPyidorEUqoxeW45WqnFiadciJhXYL4uGk9jq6iDX997LSQzpETDIoYp1CBwla71z5Lx4uFLXBiCOptWqe35y6THii4nHBcdb0kuz1CEuBgFE6hhO3ww+syWQHs9RgSoKkEYAriFeVnhF/cNNrgxTW0hlwfDJMV6qdQks7W1EKHEvwPs+NPSveA1yxR2r5fv9El+QiCixs3HFKjEq2wXdFxZdoAhnOhIlgv84QFsG021jERupkEwfCAvLhpcvbOiyZJNktG2ho/RgHku78UcEfC+VuKIGS4kGxIuEIXi82o2ldv21qKXbSyi1maT3/jhE+Oayp0kGS/Q3bFk75fXsFcE3jkEDd9WRJQsTTBUKzffoU8CJJnSGUlLZtUL4P5TqYDPZP0kzE9laUsolX813mkmVPG8TAyVCa6UIMAXcSr1BKv2FMpLiJSsvQEKHDgTJU1qiRB78z+VykR73IcV6yl7Ssz9g2gq4nnxmiWk/tI8LA1Dv3CdDCfufVNJCMVjlTmfVxKV0bkZsndFA1W4EN1STeLC1ke1yXXwkUNhb4lRLY9h//f2cUofkjqkHG35jXcfeYtzWSXUXBSra4Vol3RzpzNwwPPYCGaxgZjl6qRYxsJ5skSvBRjjFBUQN3ktWm1HGjQxE5YoeRew/PgtG9/j5Fv5yzWDvIVqOpgdq2vxAxsa+EP2qw6tbd+TyyNG1ayYiUWRc/TcwMEkkOnHVVGAkbSBiPpFAhTnRLlDjjVNsf4L+uPDGvbTN2TvUrIAijvM4k6v4eEROuARjuJnjhBxnv6V+K4QuN102K5wErKRxHq3s/lwxlaQegklSbUOUtHRWuXGS9PlAp28DCNO+GSnXUdXYyuGRvt0shdJkksCtgVoN+TEAXJKi0hr69aNM2x5vqbhy0pdF2gkoO2oPJouSgy1axu1oduMGcoBHAK244gJfcNZOUmPZ/5k9UyhW0OFX9doeYTe5uKC6+xXdOoxPQkvmz30puNcFYHLUUbQ/9BMWzOWiXfs//W/swhfR45qCUb7ZVvEbFHQidW3YYjOr11rNimfNT8cbHrvrcJnEK0PWTJTbenqq7Txt4cXFdSR4YzX8FqdC0WQRBiQehbGVlKhdAcQ7yUKhnWTmscHj4hteHtIXeSFS8WSaLz1UYRXHQgVJk1H9Ahi03IXL9sDiOrwbKjFrvpizRC5uUS1NtUBbdoTFs63JDEtKLq3iVoryH7yNgD2vx0lDx05F/XRBcmrRgcFlXxhvARoXDU3kzMR4HPeSYoAz3rNA3Fl7GmpV+IVxnZH/ZE3LVzug/LviqtrI9nD2glucPsunH+62erhZnSqpCBCAKwfCfw/sv0YqDxynhujkuksXGFLGwc4Ud+OZWilVJCZiupxydYbRAwzMFs+Q5DBPe4iEzFt1LoqlYdJVC6FYd1rZG3zp5Ba/15MMhzPuOjhFYU/hUY6ZBYBJRIUMYRaNurug93Ko4cXKFshYsntZoAz0Mhw3yrMtiK6m9YYsqbq11trbuK4Q9cMdXX1vbYlqffbj/NEey0Z2nm0YChqOqXzNaY9AewPEQkkj+cs/Pc+C954OoTXsSY+WRASiBYZLjWlagbQEPo3sijuIgo/kbsviZv/PbnxYX270t9N69KH72WCjZICcW/ifjOXxRxZnskxtEW36pIYOZlWR5p3Ua8SMqMHiG6zyrjdyvrRRjVNpYfLIn7+HzLfCRImP/SjArt5KxoV9OY52CBCWFr8bJ+XZE8vTS+gEMx93PCZs/iKYU3GznHeKCu/3kTKwp4Orx0J3BxdQnURGCrepmwhLBqrXP0BENYNhQcB7pAW/Ow1g/flH5vXqGGVn9lf9+M0RSEQFOFYW242ojfGsU0eQCQi0RkHeGhZ5gAT3+ZGpgm0Gt+c7QM4bdYPQDKoEp1Bx0tdza2eKkE32t8a3MnPzXrKDNQyJW4YWUEDPdsQHtiHxHTv/OQT/2i3OCG8RF18zQuiqXX9S5YH6FogCzkHr3oGhEYIRicnoZ3Hr+p5enuoBrZ8LhoDU6qW89gD+T09XvRocT5jZFUTbrkMYkB0Av/iktZ3kjOXiwoGmpZyOPEMJmUkUek502mUEKtMpDxBzkYhvxT2MyNUGaLkivVt4t7taG5peagtdCIoToUCc8Q4EmJ2XJm3r7fy/qiNq3fxF9LIC6PvshxHVp7ljKwhf/kdDYDw+l9ibFl6HmyJYLsssEt0SMps45++WpbtEvRE2kiIuAaZVo5iIEhAP01bGbHqIP8yhs1JO/HRM7nLaiJMF2vRmfKmyL2l8Y/vFRTfambwcN3ti28OCRUM2RrFw4Dm1Y5GuRuap6YJxGn3Fo2TJ24yFWHObV1ipIRGDJe22CWxsixxvniI24Qn7ySKxtQdchiXbFyWuJfTwj7DAKuhT1QHVI1qG8amZiNSBJaHz5/YWWsQQ4keANQagyZe+l0QqcS9XISiD651LWykE4oZLsOWQh/rnQrqsiWgNqIDARMDsDj0n3y1HzV2B3+PKdashkjIeulGO3ebgzGklJZ7W6LqTIY3S7bMEJxvMwKyVZ+WoOYnhcY+Ie9Jkrt4Cicb/accdWrn5HDbxWWRNifpwRz12OCJTwyw3yZzxTMpUU25F57fPkymF/71mS9OEVqIsps/M2J96c1q8QO6spA6w77QVpohR3gbwKMaDGSQvwoVYy1N1h8vNQymJaJ6kJZ6xi1QhUxdZrh2SvvXvKzNFaZAOmzVln+QUX/hfsYr5Etq+qYWZ/lbAW0W+7zo0/JFi46W3gEGuCouoyU4HCYCmRLFPpL9VdR57XOAIlpoDO8Bdxxt9F8q+oWhWh855wtdjlxCV4YzOO84XgIXOXfz5YYMrnsdHC593UQcjrV2RXD5JlMF0eyv4jaGlsqjfhteTkHJ0JrqMCIYbpeIN4LbReAuKTi2esBPk+T6hompIMPFGRara3X4quVnDaoC0AccRjCRmGet+sxIO9wTN4LgCy+zediE2fvdnpU1nRuJBFA5YgjO68FlM+oqQMWt77etBPc7jcaQfa8OR4IA/XELZOoAnA81Ht2FdT0e7bn/l5KbCn4J8gkmskc4kchaRWcxeXYhY0kw8R07HE7u0OZvwtzSk9iHle2/s2Ov3RzthuQQBJxsguGmzW8q1NYhtnaE0pwqzb1SVsHgpzvPAlIY0c/Ze1j/YmqCodNaJ9si1aX13yxY7vF6Xb73tpIkq8Z49Fsa0bOw1J+pW+EQecQ2yejT80Wt0sF7azdUAQFYcmuZkOIT3c2nIlDpfJ2qVIiCpTa3/RFv2bMhFwyEgDt8wSvP9nNHddOTwTjG0c5xDF6Ezcn0FNNCB4z4zo6GQknmqMPnGkfABEymIPCnSt8pGdQHGscxrA/lY58iDJNkQdlrWej0uoU9azGtOF1hbCbJY/m10cgAhEogMbuHRSngkaXMv1X/pbM816XQdKvDFcEndOY9OcvNO02BMpBwV0S08uIqxKNJtSTdlFRVCESYjaSJuhvGRISKDtgojdOVvPBPT73cy4gpa6TB5Krd7keWr2Muh5x/Gx+p1yMuGgxScay42/Sv9Phy2r2w6TFUVEIeL2zNabOiPLEgabsuL8CSx21kLw0gRS3iDmpydWcPToV0OkkIstQ9jOWLl1Efhi4DzPSZlV5NkAECUjhcmcJ4/Rs9ErdqwzAWdNjM6l14fXn5zbiBXNuEQsVnwaxVjhIIezAe7S3Ydk4MslNh2ACoZr8FSnTvgxiltM7hzu0Ji9KbS0qzVy6gQNPAf0KgZnnf2oIALU6ZQcrPo125pZ0OApmfp1U7VPmI4KSlPP19wjKwCGE39tCtngrq3Tc3EABDnOF8q8JWTWg161QwR7Dks9FarSpPaKOZkDc3UdxeNRWYSJRU87CpO2heeLRII8jl6jxS4Km+7DFCncKWykhUC8JivZhoOGEgkNm5cVoEY2XecF7nlbDNY+lYvs/o8606DhD8bX5vLmwnvABLZ5ruPXewkTqsPlT7GAz8032y4qEBryrf4NgVzb5C1Bs3R8SlUoL6vWjHOIl+mr59ZZkfnpOJBM7RB0ozaHK4poFnlomb/2E8N9y/psffmES22+7jtiwILN63ojEYBtNkszEfLul9pPwemt6iAt/jI43/WjDBYAwEhgbBMATNlvL1doUN6atLU2q3eUAC1Z1Uuv/2nAhuMYjLV0uBy/bG58RLb6eiflP1krw01obpCFp07s1/fOExG9pZyRe8NPeNILFBAsPqOTtaUL+g12mfLfM/YMKIhfPZaYeyJ74G6XsCM5XGDGVa4cGzvOj34K/GO/94FIkhXZLQgSU/JvhseM88wuqh3rBtKcSq7g5ThcxuhejY1uY0z4hc4hScvHLU80dpaAXAp0WPjbLLoF2+lNeI0ttX8Ru51lnvfuiDxOTKMM3tcU3R5ppcVEtUITwC4cewUDJ/3STHyTaV030/GJRwj07laBGwIWw8RQf9rJ69bjZIF0mLUHt0gSNFZqgkOtlGx3DK4hEuS4qWqm7yp5sK9mnxg1veUstIj87Ijjk0tehScYmM3gPMBtviZ9raZkfgf/0P9hop1d59XfZtZrCr7KgL8XYCZWIto/s1u9HAMXqkYNm9hU4hI64lxg4WFDn7QClDRayNAQF+yE3hB1grQF8sL0UdDelv7WMYbL5olAm9u6qeZ18m9XOY7uJ/eW11pLHs94BwnfLqq6+2bDc2mL6eOPNKDtfoH5ogc5l8s6sMMMEtv+frb+BSg8iPGHXkoXpxM2xwdM4niq8G/J2b3OeZICfz64pgvUpKxx8aGjrdzluThxKga6GR4k+ODYpaHrzLgHuU+ZhklfZ2F/kSC0bAR3qmo/a4vG/jz+GpzeY/3jAy1FQj6mII2b1iMAfkouczTmtRVSkdyh+3Ce4J9E21IdbkKB2xAWjXAXOXzX3j0aAY0SxTHytZ51H0vRiawrwsDHQCpVsxY15kety8l2Juk9FGqbzdSlrgT8NOhCzsfYvQxAUum1+E9cjn+8qC2nZv/z/8751rJHM6rnWOqhTFrB9PWIuq3NWuzRDWdPFP9lh0KXiSRPK0rd3rGFd84DEvpbCNenH40n9wi3q3jGPvjQDzvSkpguwPGWDywNiAYJCTGFtU2y9vf4QzN2vqsjEob0arjXy8UfSgILE9kIrPp9bwwnn0lOJcYcboP5et8WD4DAa+90sOaXlkc7OulUee4qDA4h4ORCF3yl7AqcP+C5dx7FBxknrGhBViUjzfjxdoXRlvnst9INIORv6sWZbCAgD6/q7+3HMCMny9Ci67ThM4J6Xhm2rpa4VV0XLH3u1Z+g5XVC1DqEaHL4vp6AEQUfpxO/aMBBCwdqd0eCz97AQg1V04GB6JYfSBf+3Y1HdCYwOBgoICFAyiD2lbstYHh3h+UrE39vqeAO8r08AT+SrEb5PHPnmdMg0t2paS8d330lgm/GXfhgQ07+X7HrKcqZ8Hl4KibbZ0lXwZXTom4ymBoPj72xRZz0rcfZbNsp+jCGfQRflatlfOQ6nCIpXG9FJGenQFMe4hh41imPMZua6GdZJ7TMg0NYLMyIvammW4wEJpj5kOWnBm5gdlbSwVQw1+NfuI8wnt39NipYtgkxyPl0Fd3KJofm95oGZMS2+AYzT862Outmiw0jRFZFHWt2rx5loHWsLIt/NSy4v+nv+Xf9X8zd8sQPbiGppG9xQjrQS8Ns7GF4kOrOGbnL5I3/fb9wXt4F1VsjVDcaT8+23LcMJY9svizIwz9vKwvOtoCxyrKlZyc+Z/aiLeVozKG4A54aUqupF83iZBLaAxxKrXtydltPLSdfAHI1/SveDnTCEvKnea3A0OWWO/0WRMfouCQbexsyj+BUCMg05d3I6WkWKI8j9nu7usPLWy1dMXXEJT7CysYqNqBS4XdDQ26o1E1LC49nmTdVG5RI+hL4uymUA3o1b62sr5psKKDIMlOlEKVIrWam8bK4JTe8eFa9JFeHVg/ZXzGtEXbHDRg2Uj3pnYzaBTAh8cRz+5FWAHdnFt7mM38yRst3oMa2HdalurcuY0os3iwiIISo3OKuk4iVr/l+rdPkZ4r1Kd01OJxqrmYKIFX0IHyJ+qhni2Zn7Ddsosgr+j1ovVKS9XPcnndKcb/KPIyRmqM8s8s4gn2YjXHVVN1KbdbRqMzlju7VY9K5QvmLl/1UrIyfuY543A15T6XNFm/BzFzJW/T9gSQXF/iq2Iv1kfcWnm8QdW+Ey8fU+hSD8/wpok1RCH3yVDSvy51aEWGCf/oWej3seSdnmYfdYAmPJ9TyRkdF7hOq9oSHMzoBb6wTsGD/Vur2R83/xwGWgr99bIe5JuYU1XNUweSP9k7RBggOpuHNOA2mQ8stOm9f34+c9xdoMhrg3xqf50IAtKQIefldAAZo29yO2sul7iwQO0uk53jj5WasW4SzgrCFlzfdErHht/ddve0PwVREMncSMHBKEwHLctsdA65O3JRZp5eCkchn8xjZHtMF3g02iH0FBDrp4AIf2Mdlb+pK0O04taCM/c305MtFMQqNt/nniOBnhraA+FPTff6un1bsp3WNdIAwU8sm9QWYHBWRwt58OvLk4WHNTZBIz2afz/mHTBDHhPilV54tl1A+bs2bg0Ck2oR1I/9y+u3HGqFJxY64E2H6MppGCFQJ4HSehDRuT/mkbpilFfXiRYBj+Z+Sb5GiK6Xew8NTFwdEJ2VCTBMRauM7sEiYyLvAk/goiEBQm5HtmPVWTkJPZLq8wOsxOPabHCwj9wRqL69ek36s6u7XQa4ExUBNyAm9drvhkVx1GFjawrrOm5gvV2fCJIhIODz5i03viZlhNZDy5l5/ZE9PFzCetG5Pi5QvThHLNHiF9zZ3plAflFiZvcs4PvkcQMQ42t1iKPPl5TMuA+V7DEQYzw9wLxPVLu5jKmlLM7s3hVGizAj/Gw/Z/oruY7r2O3LPMvNMMWnYHngfS6TSvY4+4p/CWk+GXGu+gQEOvN9CSDKqKcVHM8ay/NOje8IGrQP0xITzwDw1iOA86yiofdqF8V8Wny4MmMiXhLX+kPdp39GmGLXpqhSmi+4CUvWUr/SIWB0hEtFs52tXglPYZPw0zVio8GnjKNxRksTD64Q97iRmyaAFi/2EbXWcun8Z024Hkq8NS6d+eHGPz/2fagFopcrgHtxsz6jdoGMEubwPSOJDhm3gJAS4AD056NKCn4HPxQc3HA9aoaW2HHh0BDGBVvLiV+g9jnIfS+DBQzrspYSu89moXLY8Hi2E7XTPsWeobJh3gbfQHkqfHp5yRIqHV5WXjGULMllU27J9+FviyZZmSIWabLCgafNwcdqzUlNX3PCNOIWAiXgtCBpbGpzglSyV+DffKOTlORUU4FJPszO8PWMkfUTcUWLSs/RzP6r0oZYtU/Qr5bISeDctIha4MKN8aBit+rmPsjKcVoQ9b8gGitRXKwrhG0GeC5PilYySXmIQ2w4nGBqWbCpsPoUkb99SC+3VhfWP1ZiYD6uOhok5o66WOfmK2awzf2jSsj2hNtEYQayfDKmxPZdRyFnfo5vTTz6LwAr66TyCX6+7GHT0yQdZQ97f3+GPBKs4xGaAOmXl4/Yk5yn3c8dyPMfAQe9xkiuTp4lOuhmzxzvzF3uNT1NgXxn63jajPYATtpBcxjzIAV+ARtK/a5pLVtr3BOcAcwOXFzAq5ZTb/pE+pPOxfiBv1ugBDo61dnnVmV3S/WlgHRjKRflAsnQr94PxQ+1bBaWn3+jcdD/fELRcBMmXKCSkLAw8vw1J8QmFA+Z6mzARkWhdq4LCriBWXdjZFFBIWVgBFESPcNhm/nAAjxnCEO9mzrZqahD8aDdIR9NQYpyFskfc63QdhZbvLjK/ITHEDqM1tQ1ABZ4kR417+pXogrg6jnOzgt9pWRWUVBZ7kX/q10UResFXPVXurOMNHY+eVfCfFCbKHb6KFjfvQ+Sh+7VMReS2HuwylHZgCno6N6VEPtyLVHIX96eqff7fvjHL9pbfYjb615giXxy8yVKBOQNOAkqkz1wlOthgnSST77ERCdcuimfL7E8AuvFtQ6uZIbR7BIGpZKzYkr990cbMQw06BagmlYABKg=="}', + 'wallet::7065a73486c8cb5d': + '{"iv":"7j5Z78zSgRk6+5nxkVtq0Q==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"dCifjzWmsHqBx0y2NKYxvWbp5QuwhxZgnsWLUoJezcdaqY6RWfIXpRDxaggETwS8KtnAywV9bL8SDzkowQnKzs/xdkvqInjRTgvdDF2lxwoUhUbmT8AhFio+XMssQxXRcc82NMI3+YlPTuO/HmDUeniLmp5iHLc48o5VT1SeWV557Wh+MyIg86+Zvw0/BZTYl7JrTZtur425j62jY9zVkaB8mdQR1QYdTqJ3Utwozute8NROIs4p4aZAU/rSkr4knylSZKOwX0//pCw0Y4glPQeRKm7EFwfG+UZIQH248pNG9lmzRbUAxN020cgHHiQ0PJYUd8WfjpLrM8Vuyfqrr/ZY+ZteQXnsVOODPcwXXGEeHrLcfKWxsy5n/nrmMjN/auLmMPJY4furl3UG7fcCV4W+RbuJrA6I7Ld3XtSMLLwVwxSq0tGRELhuuzM01ZLV7KJA6McgJPPetNTLE6LBt9LUtUCUE+tc5OmqSKsxG7UWbDdh59kP5om2g3wn9lZh8z8+KGjKOWkeaYxVNNHSmR1oE6/4qouLqjhlaF0gERRGu0GwHUG2ytgil6tTYzWjpFQpa3RsR7TnJqHMkS66h4Kw5ausWHYECoNntujyriNzgn4w4vtTC1Wm4OjQwN136ywbXJ6GMbfbYNX9XERv3VKLngzAPTbJpPbbbVs9AECx+kZiSp3FU58DLXqQyg41KeGfqFjPjrB3g1HTi7Fj326UR7ofAGyXkiygnT/13zNVoX++wrAEcImJvBcH7zwnuA+xNwFrKJLKeTEptYcnMLHqYp8kges57CaAkICD/0Lp+RclFe3xKsDtqXRLPKE3ALlBSIDhLDA2V5fDN8vR1f4Ks9EHRh3FBrfoSI2UqTnDeA0uASIk28DtaDPLeHZreGNmAaF4oV8k/UJd1fLQLaogzRU9L2HTQSe9zowLbqZ2grpvqm6dDIVPNzkGTJgWeduilA/lVKitUoGm3unSG8PcJb6MnqVhAkvrQvizM6GpkxlMpRW8ZKUVbVY+3MUZSvmDTCilPmOm70rfToacxDC/RvbKMiqyKMCJQNEyTMm/eUw+fYQyb7WouGzC4CrahaH/kEyYPmUSubVw+kGoXbX/mjyPOGGDjvn8qspKpSqJ/okqRMrISrKZ5G0UAjkaMa4tWUzJXMx3dtF6tPuNzJ17s4Irr0SNtkJJL+fMn4MCARfhPJmzU6XPzFkb3B0eOrPtMnRoko9NdVJwsOSibSs2Fj/1/ryCF0SCQDQAaWfGhIDey1xh8QlQGchXOxkQa0RSKPOtRk803b8WfZTOGYjRr0P1ZdkQxSl2m6E+mdQ+dlKGhoGVu7COJ1+7mO9I02m8VHh0ZUnW8HOKts0JKaVV+u+NbYHEXXWegcCnVB7lkbVZHCmptl9j+Z8aVwHjn0/wUt3qRo/2FNUZhq83J5wEKjqUr5o/A2wkwquKY8FMHp/6vM8NO7/HAT/9N1ggecRR8GGIYEnsJXFqsqGuROzRWLruX43cWO7tZ90wlbWNHeTeJfKckMVd8jEZexlfJEipN5PUPbZCShUsnK6RAxPgU0U+bNks4YaalpeLsbeDtnbyIXskyOH4gc4U02g9pC6xL3SvuJbDhfSoMffzPWePHVAACQYYhvf8LMdR5oTiOsq7xXKDFHnep6C5DrugYm63ppOeCPd0H5cJUhSTDEXXta8Ba0nksQYP0lkGZ4+eP5qPpZddQrLFWzHBzb+cguAGH6keeL3F4x8n5xVOhEGRGcfzcC8FJrcQ0tKQ9NRByFNcSM8uHwj7osCXahv+lIdKZnCgxrwvWyB+Ku+UyrJrK3ZSk5kCRXpB6ErgCJeRFy5liEyPvaa6H38i0Z1mjEwzdAVdMPDzFwgZilW+r8wdUXpe9/DQ0E6WQCslh5FUoS0nhUkQcxCObuDq/HFabLhtiVQRiYwZz2moLst2AZUnZQkuND/fh8Hjv2932huGJai5v5WFwUlyfCD4RqXREGuOaKjqjuui0xcM6GOdqIzhMERU18vyF7J700IlcdRHkpxbDYTYf0x7uDRh7+Ws7ovMxbsEIGdbBjVe52QidSfpGWBE7i4g4+wzbBl/U2NcxhudHTsUVvdT/bkUNbYApfcF+lrj32JVaubaM53UNQrLPUViJZuWvENgbd/94Zuz67szhiiDNLYcASvSaILET+CSkn4WYinafhMvRFzIpapX08Qa45UZ3WYMoPGaCkV4ymRTXRxn3OedJY69Q6R/yqmNNJgUQ2FM2dpvnpwmGZzOLszLyhzXTfbdwpogB+bm2DN027qMJVBqsNOtBoOQrZbKHhrZBwJyE6AOj1UQlVRFTKHu8yqYcFKnHV+n5gZ4OERPLifXMkoYysnTNnWdYaSJgKbsk4hw0mhjs5xGzeZbeoKH55O8VYozyWiRTUF/bIajpGy6ZM5+YGFL+1v/sHKCRixNOxPMXr8coGlvFuyC12CWV/Ab9EvAT5DIcDQFmbBFX/3qo1eEBToUbGDzJOCp41+iQ69RosoNwKkrfoktAPZ0zG9OSLpBgkdNv62jIwL7eth1tN5lQHbTnsKjFlS1jDW2HbL74ynYImEOWXM1nwkPHHaE/BnY9dODK0b7xugAXmGbiw3enmZ5r4hLqd5pGv87GZqonpoi1kvpsr2PnEOq2v4Y/rfxekXxPva9iyCDxIGx7z6OBbuVkNfIU0Vs10Llx5PWQ7Pn21Tf1TlZE21zG3r4qQraL62X6g1KTza3S9rkWCDO3EvF34hlFRpuG/exO4Pa9lLIOPxpU0nEJxDw10imV95UVuI94U87yvySU06OA3HbktUoPv39v4GyT8z7iq1qZ5qoqdsGT3Adn7eNsIVPAPmtJ6cqx6JQPfMZir5SAabD40EQZTyG4Mz1XTJ7Ltz/IB0GPXRLqD2t7NO0J3JA8f9isa7Yt+UL5TB96tYI9waxhNV131K/VqtiPrsJ4YwS07bMwXEyuMEeL/7zJB3msfR1u0ZOaCL0yogdh/Zx/k9Xg5JbywrfbACoPX0PRxzcPe0csUlMLfQffYeX4+W4UhdUyJ4+d5F2aHaK+Iihk+Nbdgryqi4BDbgNtS/sOr7skqV+YUBbJ+WcFuUJ7Zp3kSh+SDSObWkLazfS+7xogvOI1O9p2pg2BLxRWPmOcOCoAvRCDb3TQOg/RhCGw9w7coCVq7WEkE1iQwZk3hwNpTbP6jX2rHM2okjIw8KW8oxyQYoy03MdQthSMNtoqyg0VpjsCg7zvlBKNPg4vdNtEii0Q6rOyKC8L/8yWwituzrc/5K90hlk8V5G+197/av5oYdZjzsi+kLk3QjAUEMREkmL7sXjAT3f2iMcnexOz6cgIiNQ7YsLwXhPosopUCLdPXyUV+y4mW1rp0AD3unTzM9I8/kfYZprIYt0qXZVsnT0xYfxqWQo5Xtl+EOUUtVedIYqFTJa5NkT2kE6NDKMeKTA7lCqXoE7+Ft26JpKkYBGIgr9PpIifQF5DC+j4IrZMOdQIQj8VOX7OAO8Fo2mNNe4tJbt+NHrKuz2LJF9Ptd0O3lLsuZ++Gvp/cLsGXk7aJf2j4LYTiwJPXz0dwrqF953o1ynAk7UdyQcI9Bc4MbVraHgLjEnxUFGABZfNMPuH4Gxqah6h+HPHlTP41SMiCoXFyjvikenpbQxQySyWscfKt7Ekp4S8IHbflQ7XcHYR4DgoqCUu6yTnDNZ3tQOl7UvUOpU++zYNmrCIgw6WGGretq/RkrcdgaYO0xrfUeXKXn9VZ7DE9OzJ3wWrZh+oWMPnwSPcMJwsO6c/Ca+IBNz5Cgro9uYxbA2f7Im3Wj8gfx+tJUhwdQ5v+AYaXwJw4BNfwe7Kg9mLU5y5M474Ae+1rlFSE+bx1gT5yiKexLS8qYFGMxA+x2NvWrBHxHL1L8AvvMfxy0k45bL7ELGwIkg8YOO1deSDoY76KpMt4LYdYmDIHdIVyoVcPtRRD5xHbjU1xfB6Y23Xj1MkUFNxauYk3fbSsL9oUwXFU/zM6Ygac29GNmVxs/dhHpdUH7tIRMIzDkawxP9W8fwP5ahWGfK0FCXa4L5zKu02XJqTi97bOjNZ/zTkWI9seKmmChp2p0WAnpnU/8ngbygkVQBBaWpcPKZB8R7pf0OvOxyNI0FTbLHr+o1fDeFgC13og46aINhy/mo/xFbvGloQMFFMxd+X39JL9RprMIQJJUSgrpXv+oisvD/xAYEA2l9pTBsMzu3ud1q446jpmRmSGbTVoHc+0fYO0XS7Np3mX0g9j24JHaKHjTd9WhZO+G2ChX1kdHJjji9DGrBUqvxCRyDzzu3CCUzozxZPa2rBYZDwoySEek+mnnu/5zdJfYk8yRrnqzebb6Alpw5r8y3LiDh824UacOQVcBMToXGgJ7qHZQGZN4pEpnpXElB0YojHGV1lgcubQ/uRTq7r47ngOJgLU6NH84NqmYquJmpi5wZhXBV4ospJZrAQ1jQed+5uMZtf3iFPOG7gdul1FvmguUQfbuAApmenEMBJjPiitZHiMQaLx2sNizIVk6inwEOKf9YTcZL2am49s330WvNji0qX9Ux3XLyJXzlVHlNEHc7UrQteIrWIApetz9CJzuDrg1WrrU3rF/k537XEeF2y1S3uIKmKqbbO5x/7GZllMVAlt+yVEZCBP6Pm6NdRligwz+qXrBPWtKxxTOk22GN6uwmOvTd0ocTMRZgqOu1Jx8nZf871LB99SqbZ/3ZnzjWLxzKWk3T84CZ24f0g0GwBRRpWHqnL6ivO9qeze/eLmEnOavrt+oh1dOuaBdP89NTnN97ix7BnSppWVl5XfYloy5A36nRSGgLykbtSrK4i30MO6ifpiXrsyArBB+FzylUaKp+cSy5jjCe72y5tPxbMN/dhTkQZCNcq4vjGbNM5vu5J97hiCzFM6naiBvPEdd2nwSfHRFpQhNB+A44EYOFubSDFi/auUz920m+Ff6ZmY1hEq6EOLR+LKnycfIEJ2iTa9EWAI4p0fpzQwOUH0ziSMnWIulJ0yosIYolt//8Usj55d/G9KFiJErfCmI+YL0rXLjqxgj9ecWIr3c9qCYBw4erUTQA5UFjgvIBMUSIV0q4ZiARYZBLGJwdT0+O8wHCPLhw0koCO2Bxsk1cmyY8eSdBQNRa+R9jR4LoV2ORxNdTGvSFVmuOvOkuEGYXowkJi+7n4ZWXtmQEx/C4f6JMYt0HoXnbShZW6/GmLtgsAVbLRjmPYljQj7QsdxsV60659KdqhHNZp5tmaz7emFq/ROFTBLqTXinHM828HJFcb9aSwAkKCGnpQwF0qRnR1oOoLmJgILpaRrOTEqIHyiytxrFyJ07794lWBpsruki/GSaAOLGaRZfHZFTHRSmt/XdXkY/8cgiwFIM8e3Tg2aPu2yMpLZ9dV/eqOjEG6FASvals6S8dR1EUHhp58PX3JQ9BqS0KlhN1oraUcF6XpgVNRPWkfCwpE2HPhh77vEB7NrOhdUiQvOIjIu4/+WrL66KpaiRxZqbCQhMhlWXUBIfobEI7wdboIuiTM4Ny8eStq37yj5ZdOY1dnl5E47xPxNr1tidD21F4H2QA6GCDHWHdh7/u2iANnBj5sB8ZgiH3pSbb0VmjcR10gnMrG4P7t38AwRBZXBmZRWSbkoHxIv9ldEMHNhLcGk0GfdlFtCLG8p8TwVAf4PyooChru/6M9jMwnLm7mnOfHsWYTsxLKqBiK4zNzX6qag4EwyKtm3cju7ViP11gRd/WwFf8F42Lf14q83cKkW0ZU95bzOh5mGw/rk8+iPRV3T0YgpGGlvtaliGk+GqZxExwb7UYMYA2WzynufAyIcTJflxfvfA7z1AoZaoS8qtQz809eDKIOr63W4Wk3yA6NXw9wjtaO/ng7q47tgLQ3zr6YCfYIsHC6yk3+A/cFK1Vgd1fIr7asiRHeafVpReSRy0nkg2W/9K34ApZTt/mCEKnwVi7DKLp6CqRbb0B1iL18zSfJ7VmJ2rt1mMzHz0EUATRvuS8Fb6cpplVVwRhcOV7E+fiM2YypwSgzzeil4wL5wuArCPg4OH8gPtmofw5CgEabwfqB8eDvksE+1ENBwVvHFo4BB4A09m9PLxoyviVMSdxe31i2ZGGbF1U1v8iBT219YQpVJtKMMoK47lV9F326cALt8GY1s5urlk//KJqNZ58hfR9E/xA4EK4orsWyFgOlQ+Cg2jsOtUSseRC9BL03+hixkeAbizwBjVsBOm8/T7aSCa9Uub1oQLFmGkta+1fWQdJSMdBUFIHr+QaIMEQSORzCNoEg/OWLOiYt4lybTM48CihYWSFd1XlMRw09tMefPZdCn8fHEzLylyqxfeyLhvTk7i6vjvsZDQEUaqXoVzPp5loNyUYXJ1cKd8pzDpeqqobePleBmdhyEJr3Qf8LSHtVnX+oc6XRiQQ9qOqPeS2uXMAUot/wJgV45k5USZMMwBAfuwZEB/ePMJP5Wy51B+EyR8OgrK0g2w4qkLdrGSU/HWrQuLjnHWY80BrNjeDzmWdUVnN4FvN3epaW8nLovoRCOab/RtwCcBzX+dZYjmlsRmLtIbC7F5Ttjs2qzvuXi74H8z5sfdv72Av47o1ttSttH/H5gPcbxAYkgcPIcNd6v3oc7vq3Nn+gLisoH1fgIrg6dkWN203S83Vnod0RwA1SxMBIk8sAjDiDWuGX8qsEdqlNNNOTrbMkLKcJTDMd0SdJ46s/U7wldsIh5Zo0rcU+kpUXfuvaR7NWPUbEWwcdG2DbInHjJ9CNRNDbEduD6YQbfRciCwda6MqHnB4UYSn00wFXWZa6PmoTrWMTvFonSp5bccuh/vqhIiYipqiVv6NqYzYsHzLXYG3DBLBn7GAccKjS6IChIHbI5899c7yvQ78Bgq/eSBg3EO+V4SJopz310478bjt/QEuN2Nh/8E+XHGUtx6tjccQixuRmwQHA4qKObHQ1RZ+onPV93EMHvALUjwATbWq5bAmQzDhUPsW5oH6PRUMjjOZDotp/vshjCY1IeTWgi08NvMiRp5tyWXmUFMz2/dexC0NQPCG6t+cLEpO9zNTmeW7DwbLXlmBWx+HnNlPvUKV/4UPdXW0j9NEykVzq5wfVXektbdBS8ipOqx+nAlfNW04CXlj8U8C3l8aJ4P4Uxy9hI7WnnyPyC+OqTEZD5VmAPMlyuLbWMnEcTfv4jQxZM6WOxv83XTBIDuzB9arMWwdSPv7qyAsO3OOVpnxVcvjNJJHZ1SRLIaV9IG5oSIPSfjaoZFI+ohTDxTUT7E1+FVQ3zJrXFrOtIyUsb/7nRi0RUue7DE+0Lgfl/t+MS2Wlpgp8t3yc16ogkobXZf0EmeYQiQ8J+awWKZcaC6RDxo4/rEaKQCNd3ae46Np/579wQxdmm6bFUU1Vpuw5cY5TutNAznttryOP7/6/cz6jsqMwXV9nzVKJyKPexxfIKdNXlcxB2PqslMsLj7PMYCc+8TjGMeyyXLDz7NvRsI2CwrWOAd44RniGvvQ41y3cSwVVaLqL168b6wMtUAjk4Z7ix+LiIJqKVnvBQwHvyPELvuWDu8ypbGhv4KV1mo0B82tXbMh0E8Wer+QGdd419AT9kDlGf7dv886jiy9x8nYPWeSj5/Fw4Eqh8aHOKoBrjUTxVN51rQN6NfK23LNxMk9F8KvSz40wpjF6pyY3iy/7OjSi0yP+NreioO2fc0wkA8hPQHl//zf/GuLnm8m0Uq7xgECD3YxL0n/PBtg1rtowGr/KyXyOqm9qCQoYsJyPvjBnN63yMob1E65ig2xGD/F/kYqbgdoAcRc4/MmY7LWhBtRQScMjfsL0rDlD2cUWCX4K/QsQsuiOfTQ+FssGnzk23R3OC3U20+TVGyndRp5cOmRGLfdT1MoOF2aM6QvVYrUKvQ7By76hdBouoQazOM2TXXPY5mIuFJueKNwvVfzXd5UvKBpQ15qpLrOW57p3QSj0Kb1Hm6CoxaoLxAFuF9xd0Ci3uw8p+X4nJgWnstx2qALmc4blsDzJd3pYesip96uS7kv/T9n8kEK6IaJ6L26iWTqIszGBmqrgYcyOcUgHPZ4+upaJd8JpeFq5+SFzI/ScBpSeS0PpVGEYBFZ9iSPiCi6WYoQsl7RIigXI783TbOjTyVzugBYRGdC/UyFn24SfnGvWQn6dWAx0zaeOwpBDPRZDCh4nYqeocpCd62qbSHq8kQrYfbhI+BAfdIdpCJyCQYTrCtL3FpJhXzWZtwzxsEFkFVCT/2rR62x6dIpkzfWmqtZ18hUMQ0viXztbBG27AaIwfBXFkynfSWihMzrOrs8X17yFYoi9zDwmS6QXLuGsyVsDvJdim9O/Jk+9von2YG8cr/WE9N7orHmC+ywlMLnnLGKk4ozmigW3Q31jR5qeF+UdyKO5Ter+zpMtWYJQQH8lqS+wvIE00/zRhg51ALMs4sMVI538+ABn+pT7rjyRr/7Er5tppvu28NZpYmhMUXiEoH+/JIRWONqNzjEeM0NhwxKSYFoUXjGytfouuAk8q+akJ5S544SJLBubPd7KL52MxrbOKeIjFlvng1YfniEYWDE9DfBS7AznsJFsO1bEP9XHVxMqLTm9xzFD7e+URFCtcBH0HO6vVcXwBI55BR0q+PxnfOJxeORGc/ljIi91+RPjz9W+7T83nlqbuhQoemo/srnpxZqfiqEdorMQTuhuViAkoM0lrz7sKiDpUErUs4QCu6SMSlIQCClTqPGUR1pHaiF6hFE8erjy+948f0sVkmu2Jw+eyU/skJIDcRYaqkq+cBJINebCJUKVYZl7oywAv/FYnru5WWssw2bc1l5YFpYENNkHQndX+tTviOaADWGsZgY+b5/odHDjKL6uy4JwSD5mlBJOg5OgW98YlX9eVKNmg4SYnyzS/FOjzFEe6TPicvjip0eKqy8OImgrkoJI5nyeljOKfpQx1p/sc75k1Yl98yXRH12m0ZympSPgt93H1wTtv5BSFKPXtoGkPh+VnkU8pAeGBHUgz30QUT/QnKY5iYkcAgm0/1eneCt9y4c9LboTOV7lUlTaUG4FA7ysJjMHbNmbG6f0uiT0xgP+w2nuEgr+2FY0qMZt8EX7RSlynY1ZNCzArdyVYzpRGa8ILaf9videPY4EveQVUnNysaU1oCCfST5Z+gF3lyRKs5BqhrjaJmbSApL0kNrRU+LG40FRR4aH0/0JiiqJvUd6JC3Vhmh8jpWwwK5ikzaiA9j3nZyHBXMhXXSNFET38tYfOB4GUAVxTIqP1q+fLqk8fv8LgYZ+LIWegjop3v9QmgDfxEM/1BDvMeL2P3VxkrzwAraIMzOGXp7O2LHZ9ElvGK6QIqY4yXe18tnTT2WdkftyxnbF8NOOubyDa9CGUbIdtn0JLyjdYRklGDufSy2EbjVHJUl+MUecJe+XFxcl5YBFfLBxnAlbFyZn6VsfjwLJ3+JCYI6py7o5NCVgU9Hhava2BP7ZwnmM9h1H/46vbeGi2N+69H4bX8Nxf2BmI2dzyeWeF4Tsrr5v7m85fU34xN7ujCn8QC8EZZh+eJBENVxViDc/ZISzqqTFhKvbw8/8zMhlS960KyCZQWGeqFHF4Bq4BPk0Ig1BgxKX0TfGdF7x6GXVE1bEsvtMRBM1Uo1e4Rd96VtNYZ1booUg+/MXzFjFviDGN0QgZ/8lOChJ5FlRvMP5ax7BlFtVeq18lf0TaNxa5Oyz7ae59CHEfHmh1h4Jh+693tC45ANtqsUMAS1vFludrxpKFAOijkKupvELj0MqmmFKke1gk8WOYCpSN/4Rd7L1smAPRch4VwkyRMqPy3NrpnTq0GVRhBi+B2YewwhiwEYA5tKO/3v4n3uSiM0XGIACq0d9KcRiRwRd9JZECEOi4yYMPbrsw7Zt9t53Wlv9NFfrWutK2eedhsRn036XCd+Sb26VjZsvmeR1a6p/kQoK4XZHoXHXTGAgnGmkIqnhu1AF6pSHw9d7+7b+4d/x4PHPIqWd0s56BI0a06iZwrciGOUwbY6/buso231i6WWSccE7Plvfyzi45TxLUymcAO0TSB6fzjPDQdWAsg82I6NZWIF2Rrr/q7wyF4bjueaTxbj4s72swMuL3howPt6Q3XAuIz374ho0BFKi9g56Wa110E/wbe53zh416yvhPQ+56fQ0Ficbb8kSy0AUZ3lod4TVf7xZEpzZqmFybfLDBn+HUXn64Q39XjmZTxtwhH/v9jaXYUHLwGERJm9YrskkqQLpH4HInozUIspmQVLms96fUt1kQaeQnL6az5NCH3JxavtuSkB94K89N9d7WOahsn/IS3DRE5N8n2hBHgVst+VTXcLfc3K2EMFtNvibDIAm/UnQ+jPFnbgINBDaPMN2psQiKiZ45mGLu+8tp7zdWCVymEIolZflbKTcfHX7PJ/Yw/EryBj5P3Ghyltc1tpNS1whUwLum3qfwVmu87R4E4Vm2dHHm3F68BlRLQe2Mx831IYUUAKiTgkvN/Fo3zj1PqTrH6+IENOZYppzgFWAP5w7sOZbZmZSkRjqqNkmaGuZYkIYVohkdxUysMJsnjQPAVaXHjd82f1WcKY8M/n"}', + 'wallet::871b9de859991023': + '{"iv":"E6C+AsQMfwtTv/31l7Yxrw==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"mmFYrdsJ6J4BV6fpRkR7JwQ4xTp/pkiMRt4Q+yxIw3m5soQmIEAt4NkIl+cEtNZZ+J8tMkYYhobHkOeT+jMJjS/QQfxpEqmYEWz2Tq8I1zIg76KuaUcKEXq78pONcPFctCkUZgA5p5QtuGlt0vzJTcTI4Mo0jJixgHis9EEhXa43ay6E0LZYdjQZEoNn14ZH+o0hr/pK4X8Muf6JQaXAXZ6ialyisf54fiYWb+TOuGaCjw1k/a3sSdUVxKdLLt8mOjlTlRqlI7+1VuyxlSRCUuwqb/rboEC7qLfxU/Dy2tYOzUJGDwD0k/CHF14DiZxHOW2qAKbL35y69K2s44clRGV7JtapfRlO7h6fssFh9qbOYoRO6ode6h8mD7PqnmAct77vP57vvC2az5v3vMmydy1+Hwc6zknvLJF55AXhg1yZzT3fa8DGC+ISmyOxvbGX4bxKObKaeoZAy6dMFwzKywGvtvN5cV1epFVTJs9+pNHazba40HiwNIV45jC2QeeJErWcH7ODJqvx0ckGdijfQ41VUZ5kNC3uroEPFazHeIL7NgK6i9LGCVMQB6jFhTD7kr5Wc3m7H9MVCg+s5eW3bbJ7elFuzdluCrgt9ntijhTzRtxVzDoYLKbq0bkaXQQtXwiDpENIYWRJ/Nttlz98KC+aHcfSrq3B/ZvtbsVw4ua84sXMPvCM6LQF61nhDxbBo7SVxWRA/TGpZ+GYX/O8ABkRP/L1ed2EXdTkGjKyEDy5sbMPEiIxYZCrfJ0DMvp7/kS00cLxxRi5gWzZ9rtAqrXDZTeTvDs/PjJNnsOH5qWSkrvIxJerBF5fOexv175jl3sYSl1Sym0IHPd+T4CT7h3N0UHuqp7QugeOS7I8HhFOWgHHjGmUmGm/IOE0MRRPdMrwLy+WPxzkcZH3Ywy7OuVcRWEaV1QApAz0jLZN129EZN7QAbP7r5M2+6wKcZvlJjdk9MIOBZQqkFTaNvnkNAyvzlbq6VpQnClyhZ+NAH3kzJedZdmqjrUSDErATSEaPjeWNzygy1+YDA0O78yyCpAMe7xf2/HnY3jKzVioahJ7VBJnrEsiGO7Q5FUpr4qbDx/xL4HkQ5G2XedIHvOdhzHvMFAgKzDZpAkspH0MmIBnjbZ2xnOYB8rTRtOaZ5f4aUU487qeQ0jKaP/saAx+f/ox88zplhSsAyzaH9OI03/k593LhSsMoZit4XqjtoD/Z0oyYukj8SzYbTl8yJrCEePIIYkyB07qbPYPDGbZCauSlILL0aYcxkFDd6cP07gKVcZcKRWaPBXF0gQEq16sgyuAxoOyBpHx+VMeNq0qGyrEBQ9bQBVBM9tcrirWf6Yh9+TzqnclG99Mk0poQ3PcqDZ7KBN8WTCNRYiVuQRssGIdLHS3bVl4eCaxJu+GLRqJbCC+SS4zTbVkTxExnx8AXUEX7SrrmLwLp+tzYfx7hg9Tgc8S3kMVCvmxiepdFPUfG+24hj+mnz8f3TjYZnlDacyhi6F5hhamItct37DLmhX+An6lkKrqjw3yqCiUlr+2P/mH88eK3tG8wxyJ8qGEtIumK6xW5bbeFmipi7w5N/qvNi+vij2uTuDTTK3Ys7G/Npit3/9gF9qkwdH72EwJSgwpil1P"}', + }, }, -}, ]; + { + username: '345', + password: '123qweasdZXC.', + ls: { + 'profile::2cf943e7720652c2924a0737761377ccc679ab57': + '{"iv":"zY72H76ShUA8cajds69DMQ==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"iaDWQDC6KM7VJZImT2jSRtbjnlYuUXUNofCMb4LkYmocwXWK9TpD4XC2/tSsZcXpBFzeK063xB+fk1OuPDrm1lX+VkO2RvxaOz0a5mv5526PQkCwYzddF1uZxVJY7dDeuwoxsqukx48FP9/zF//62rgdbv2QuaudUonbLb0XUcqn+dheH+E4US46dhJE+iJGUBiVbop0xV2uZWwAUeRzsaWFrw99WBw//zNx/HsPz277ZvtOfo0KkyIIoGFLuNJ30XB2Vh43+6rrsO9v2vnAtA+PIcMNRuUJ+Xsu+EtMYMxhszMyeg=="}', + 'wallet::7065a73486c8cb5d': + '{"iv":"6Ut9/VXCezlzBX/zZSD15A==","v":1,"iter":5000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"mjuBtGybi/4=","ct":"WFJaxxf808JpVADOT8EFEh2r7QC2X9+3z9nxRd2TFtVmfe+umzQ6zi+xBrjyg7ddDTRt5Gtu7jUADi9pLCAUCsm1zgQ85Oi05QyDCk8fBRNaNimZgP/g75JOVNJ4opnB5rXBq0wsUz838nBMyYISnhC3RGTo4Gwnd8hyiaUhD9LRb05IZ9fhqh5Lxpc88rmze7xjkrWWTPf3znqcCDviNVi7RdygIv+PJxmOChwHq2jRtY6TsxsjQXi9dpChQHIwtdcZAUSDXQ6nhvrFF8qHt1dc+ldhddr26krccOnwopynz1V6W4lBNUb9vD0vZV5Vh30TYqZwAvuuOS1uhzAm1qWufGnoz6/BF+0KblEYmXySCqvASnW61V1SrteyGeAm2/a8MxA595Bsmd3HkGpiRkz6UCeaIS0MrUvfzqwpi91pcitmcx//HxuKIHF+FHMsxa3RLfA3touI10z50jnFkhNbr/6vz6n1OnL65nZH/ZzgK4Y/CiPsoHAk3D8xbFVJ0Y/p+VFSR4fVUMvycEazvVIpTrpHv2P3/vP8zA/dsyvS3iKQKB2lnOZ225VoMHpc30JdWkXtcLT582OSkZfAUfdIcHOwZbZQseARt6QZrJ+paAHld8ozFnNAtvXdqOEIsFhvd3hBz5mobAibFGrFKl8otOdlioM2ate7Ek2oXt+jkSKBJYaxCsNgCV3rFtNU2O3EYn24pRBQ4B4Mwenai5cVUwHy8CoJ5i/UoThLEART5vMgVBxU7G+YnKKv7jloDn9E9x+7p2zrieXfU06yJJc0l7M7Y90hXAZWuHja2WPnNyFmqB7y1df8K2pAX2Q2vVZLKrvAt0/12PF6I5280yoXiAyyOFOyfpNwdaark1+3QgMLX0WsEvzvO2dGlAFWwwRiY/UzkyZ1qk5EhCryzIV+BYaoSr5XujrFOhNMeGe2CgGqgT3eP+ij2sNPKWX+WnUXYTF8ijysUBCBcVUbGm1sU34CVq/2Fu2uUsCKVHMzLupuOFzUJDuAOHOeJqAJiUU19MjSLKa/IisI8KDIYImI8OrWBuwpbD5b0cA7V+Dq7tfZiTs2tMuM3K8nYnp0kVtsYs/beKiA7UE/6NAyUR/5W0s+pRiv26G9WicQkNy9SKqHgSnf7xEVgmAy3IhtXqb9Tbo1pBN32AK3Le+IW3o2lbSG3dNU/3ATPFyWRpTfQWeuIPm84mNHOCjMrMEtFWdHiZF2rLSvDLBMS7xdqi10X9RKyD3hNjSpW8KbPVhQj9CdMOJCSn771Umm48Paf4llwOH8lfzqCrKLVXifMcVgkltKJV29itc+bm3BZ03gzF501krpg4XW9c64UKmmzFgcTGoyoeMYAMxzM9yOyrMOiEBADo/8xj/fp6ht5NcyVfCqwhrbSzcqBCVcXXpL1qxZvy7TRAVNfao7+tJ+o5v3POH7Klszgfdy4nH9uWnj4mxy/I4jGqM+hmbo8w8iLIQWyOzVGV/L07TKozA77Nlja0LBkvtenU+QEhWKzUom3z9epqJozH6N6qHWsVWsIO/GgFKwrxIx0uxCqIgDsamvZSDKsn63UPD38ZxQj1M7PHbzPDGRZ66AF2zuC9wEzRyN1c2HvaYB4o9mGdkNMWN1FuPgaDmVE8daF3+BrJqchDLgKG5I6j/1fLGmQl/cGj1IO2pC6VU6Q9bwnhJyusARBSvKajYyLlB6LDwMgXXiV4Nb473rm5QgJstcjoNZt6F6G+aMlgwsuoo/p3TIh+jmxfJsvbldjQFHA7WNDID1Ruk480JcC1aS9aQiWidAB8Kj1j189oA0KB4Vzk0hXse5S+DcTCrEQ6qRiMeJBwf9oS/a9uEEkFlUWj6iGVmSBR/svU2/PG+8R/+o8Gbv8CdF7jvdVpUjayMcdw2BHjPI+TZOrjcU8UggGE2YwioKPGUj6PpK+Isd5Ves4GVTRr1W9wMrOG6+MQxlRboIwyd8odCBrmUYOhc+E6u/hndJoHdZ4/Dm5tTF/nz7XdsKWKkbMurNrB4OHb9CoflVAfBkLy6EwjDS8yxhjTU5jLxuYNTD/NYFSWs9jjFsVeZIwulQ7V3ptpE2iBLGcP5I2LiH69XH68e7lQwRMMWixL3qhXo0bL4o0raV8yE9OnrTBbpgbJJZLcEmxfZdy9Q0Jr9VYVuTFIu4wlsxGUQlmB26V+o2NSAZsbyBdItuEUbJnJEG4A5Lc/0Bwd/oOVDT31BqvkhCwRpuC4/BH30l4rCqvDufEhabYK4Ho6goJfuVSw4NVSUT49o2jvnkQV+0oZ+cOTLmHM6E4kfyHI5jK2AIhsmVxmt/b0qa8cWor6SUPzdxBa7Sn/fdALSMKI3pvOfUm9jZDqI9yPVCbrNF6wRIKF/ZLdONhAkhM1q1a5hu0QBcnX05vFZAUQy+Xq49aA8XLVahfXJv2kROzSHli81eYhURZdfrLgE/bnGxexX8L0f4SBFhYC+9QxI2wwPAxGE/Js2RjISGnDm2Ozpq8GVIz8YQHujZ9ElHHqlfvffeDTvRNgd9n2TOwEnqFlh+149NGwxM5qrkDCkW4UgAtpfX/hXnrsDtYjlava1qpJFu2b9/QeC9esJnlZru7KOwj7xUFoPFRdnPK5EnvRjFMRtwDnNrdsJqC5eSntZJadwwBxjKNq1GnYq8Q28wHLlGp7YidJaPmLpDLXAtFLQPZZ4qZOHBssttoDvCy3Joq4A9rIhYAf8yHpJFun7xnqetiErXNLiTQhVl1MUvUHLzDIzHkv0Afnhj+XmVg8HKmkFKDikn+qEi9XGSu/Oz0wzC1Iww/5SJ/yGVoH3rytD2Xl1V+WsBcoAz2ipkqK2SaR4zfYCpmrUiWbhQghWRGUgrHLFvpHvBu9foLoxErYU6sDhdl1dem45mICOeCFBYYVQCpxx7QP02ASzyvqqhHa/6PdYVDhJgfNtHER3oFbhlN17+c+8SIg1FYg1lAT34MF8GgGPFmzTx0ylRJrEY/eDAKBdXjTSukoHegG/tpLVb7irkvgvrd8obkxiTGNUqmLXWZPOMEoyc8zArP+uJF+VY9zCyHQWXytf2cpkIEWCeEJNFWIXzq7Rke4GceNfM8SuxzI/n+vxFUqx48NllHRUsn4++93NcDONqvTHY1VXUOkt0b6sm7XVr0wa3SsIZcro1eX1LB1iVVfwD8+BTHUCjo2qFdm+krrMBRgwDhoe85JYqVwnBfnYm9OfrDdasfXjyy43HNGElfyG8yRBbZ52pEoep6LCMBCj9mDi6VPBe72a/2tiYr45j2j4Y1hpV3Zwgw67Ev8C4+PCRMily/ikwAfA/JJbsBeutQfh+6xXIieCId6ZIBDr7TN1SdSVWLPIelAFtoJi0xWhj/UW14w3ZR6BZOzMcfSpvLWPH21cbYov9rJLNH4fjbRew7wURNqpNH+Qu4hp83+MxVzY54N8gYppXG2LbXKLGzbkEiHLa4mcB0uY9ElzLI2elhL8hQN41HDKhlfAh/k0+3LNmpeNusF78hR2oHf+vAug77iZxGlHlrY9X0/eIHPMCjP2WSnFKt29PiAgg0omkxUBDttam/SDgEYG79jqg26T+QwkarrGPY7Wb4rvjOXAGwFrK3rgCOUDXsiU4hCvY4YdLitsyTxIc43+91vWDi4havivgYwClbPhGVCoO3gQUB/Elggv34P5LWPyWt+lRLxk/hDCkVQhLBAKpmI8tqBjLItluefbuy016jmHHdZOYsoSpkD0nzBJuAIxJ2BiaHWoRJTJNju1oaEac+bRe2y7uT7JaMtPNmwQ7NYCKSxVHXz6MoQE+ptgIZ/W1ZBdEABEEGoFJfR/YBngOAJSeuHyIherzbfZXfvwtq7TdXz0Gmnt5VYDLWBn5yymIhSl4JG5PwKWAuVHi/uZr+3UQWx7XD8kuEZPgJ/6v2yHsDIOIQYBNR2D3EDj9X0yHCD6TDkm3lz/IWjpOxrP2VbD/C1EMHOYjrrMRP0jyASM5On8kUFn9ZwuOTQn6R75Hc8Jw2DIChxTQ4AncvK5DVTYf/q6YXk8XeCQofcmat/UvpWo/Hx9tGt/BPQj7SX/FmoHpUGqAo+58IJ+5vjzInUs2FP3z7TYAIM9x9QzMwoENcyKkbo6+x+P5dRgHkuztdTKam62VGawgVixScsn0y8nfNNZTplHMHdH39A44UUd9aB/8SPLaL6yOBHU+y713uKGFUv7wPlFnlTQMszKhZLryCWcEHQ3Wjy9Ik5+W9f6PjDJXNYpZh1MPkasHzLw0W8I6Z4RKRGA9KAkXczY0miCOdf+9NqpGv1kqfRWPCT32K2qb1b6P3z+Ed/5XzqH44JL4zVTjYFplWd1+G2Coe+VygXyqKx3X5w3s6BPkjwcKsSN6hetOodlxDpWIJDPqTlYxHHGhYMLN89rqrfPGqGjnDa/ym+UFoqbVhip9zMBkYcL7ZxoOw2LPnhjQPnFpq+VHkKtzwCkc7MyvI+E6mQTlXLSILjvHPzAUuKkdwIWFHigESmnjC7gFhXMgprgcwRPTuMjxdJtfwED5EmZlRhQgTvj1a/lJtNNO63z30WYL5afDxcVlUC/fmkOkKJL88qXLCG9hRAe9sw+FV+ClWsE6d8LoprBKM2U/reWy8gitQ/cQRutO+86aNxE53K6K5fZS9sNYlljLFA0GBDsTBedBnhPeDKynQrlYHM5uNL1DD/k/ZOeHRMhe7wnHcdQg7Dkv0qewfFlAMGO9dpEjzNzNUPlw2s5EO/IPYdDERnzDKrtrYCmhXdFusmUeFXc+QrLi52nB+9xpSZOJO5PdUdayuqBSgmV4OcgNeF/MD0uPTYeeEP18jNE+gSYOeDfmczV5BIqjD5P5TZHaOA8Y+TcIaXLu1jJxepWIrlzcCcoM16F8Us9nmpkZulItt0F15kJI9XwrsX0gG56RU9+u0I6aOwBKM/I4/q4S9glUpApCmrRPYcBkZt0AIgypDj97H+KyeTqq1kO3Gm1JEybMQ5oxV/tqExP5SRK7J0I4rgMYO99y3cRYwvwcklkHFAwyCJdZtzWDGtHI3L77ofYhSfirl4plwKrwJ+nQNojpkf4x2QcmPPxFfu8jJrYFGuwQvkSk0izfl7zHmL/DHQlhXf52hGxVCPNysU8d0VkTOTW0EOIgCPgeMfcZ9w5dLiOymJyJfok3OMbS6F2a/roiWu5MI7TCChMArtqaK3R+8AUmHbLNeINDSKOVP79DlLSCgnF5PPninwLk16gkPqd2mK/3EPKiPam7dV/R3f/utRBqlp8C7sYOUZTIdb+M/dibhRuBtc968imh8bLu2LGN6xF8cR8rXDKzS4st3Fsk3uyEHuIqjsH/+GgMJqpVI31w5k80NixzCk/g9ThcMZWg9LGJbT+9KMIUItir8R0psqwulfK/k2PUue5cDJcyvtvJLo1NOaQo4dCyopNS00Xb7OKUeIZlOCCSQj4MLmEqeawssyoHpEpyz2VKade0M+kCmp3f8vOlmL9lVVt+tNNxB4QQuAuU2nV2cDi42OQHHFfpu5ND1zwL1F61a2+TLR/dkHLpOVXbz2PemO4JEcWrQAB0D/hRnRWB7PjAm0NSWLd5mcZJ4SeOCjiyMeVJTpFyYvotSw7EnTcBkF79nsli+0BhQOM72ykq5JDFQLwe1JStJ26R+0JoWIAcxu2sGgPzc6/TVi4v8TvvF5NfLjXZ7B29iLQQDAYX1XSJNtMJv598ziNmLAISCFjOzLOLpAZTSqJ+uDF4DYV4abR+XjE6zYwgtSfQ3+/lMXPkTrJ/HhTCV1uNcZ/0m/6gd5+JAwjlzOFmxnBtcatR1eGTYkFHqNCpZB4QNQ9fGPHPTsEICq9bsj20fmeq0s9CpIgyny3QS5dzJgmgzdBdPXOFIrp0SiLl3OofnEQNR03+ja/cO/5ad6PbbKhg5MSjYZDjk+i3J71/VLihe0SH5MQZ0RTvT7edWHUeyL/DAqR/soyLO2/Gz3tXzhWVN1zb5PuJyhAVa/zS3RSSk67CbiN/5jjJ90TvFKNbG3L86+x758vtUvSMicGputhrN4G0wDxWBIRwDwu/Mux9X5LAwpRq7VthOxJFNzK2td2Ym6C0fF/dEUpEwXjmxaDzb7RNy6Dw38eQNpDiPlOUo31zpVtPKmKCppHHyN4/QkxXv6ZZ+VHrIUvdkU3MVsnZMnnfrQje7DgH3k7dnqnS8GWbxOv/FQCoL88aBDspThpPY/N2LxTRA3UpbOcWbdzuE+SaQu0U9i/Bvmx8yOHE6H75vnFRxUUAJj4YNW2FEmIzTZkKfI4ss6QuxIEHgfWzGBszzl9H+QLBMT9e5VZTSbNmufiFsObgtLNaBoF8Jtza1Bzhzbeb3Rv7X4LAeDqaCvs/gjPVUxzmbCLofg6r3SaayMycGCY34CWL28grFCynUFHiIluiHaFPg7QKPimf5NW3fiYqKNsBAlcJNIYQAFMLpQ1jMAhLki7VDRCBekqyKBzAAhkm4rg4LlE3VqUJJ3ARp9YU+dn4xpPrSeyD4roWdRuA+0YE5W104bv2ziAgOORT/0E1paHZU2yzWSqnNEy1qWBgZ4wkaUVEXwkgDuhvgQXuFta50iayl/oNTfpnKRl4oTLCGBBnzvpajaffB7NsVIfp3Ci25r6guEeJV/bn3QriK95ZDs9Jd9vKghmg/yb1QLV2G/9pA4381gU73u0LgwRWwGBbf4dlOdLxvJ0Tvo9AURPyn9jYyqsVZkoVukJtFCI0pRDPxuah7HLpdg04NnJtUo3vbIR54pfK/cnQqB+glQEhB7tqSCB6g1HxTbBRPSNeqS03paylcQer8xh8AlVRAOOrozGY3araWNNfgNKSIi+fU0kBXwB+KQMm/rCvXnKbTndtoQQa+E4F845UT2YogbaRDusK0ZO+K4FcfOGt9y6jccjxiZ97Q5Cvv8f3NG5C/5J8oQSuBpIU9ji6c/e6JIu66g6YpdgXMxZ0MniNv8ErRRU+SdF/blZbEWbc6+bbj1sgXGap5o4NhO6RiFBZFK5iDwmFv2NIbzAvj3lkSBJ7uysorqMrBOQhO/PEE8Em+dj0Zxaen5iQp/S9ep1DVRV8cF25YqphId9rjP3cuAHTHt8Eey8AsxwwatzazFPBWFHrJ5j2hluBFm5u8Nljx04Gr4Q+r+4VeG8T0wDE669rQA8LNdSyYkrbNCogML48nTS0uU4CiYvyGrTa2zv4iKTqi+lhygbirPRQSua5aBF+3Je6/9ErNlblXW3CJT4yKSXmmDvgxHU/en+qnjRbE3Nq0o1+M1F7fayzFrDuX86FACacib6nvZUM/KNmyKITIAiBnZ5tsqve0oRv7q8umM1kB6SfDdYVAvPg+fjdGzayRJGevpq9kDL+oxiylH7ytDoWDQsmcvSw8v61sv09WIc00UHBI54eMprDtvuhrMduF/xx23iYZCKf6tM35DawNxqF12x1aWswkspI9zqmHzybcNz+/Wk5AfUMJZV5i8ep1xCoOtBSce+NjE/fldncNBiQTPVgfM3L4o1mnPK48M3ktqt6vozH4J6ch186iCAWsZqTnpya8ZLeBhDXqzXdAphZTRuTfkNoEtE0I5HXMLw6f71jbCyD9NHXfTGHZOemTZBIn/g4H+vONtqUqeaGLrVtpyQ9R2sYHACJ07VENIoDG1pP6+gxbI5pk1OL38osVCtl7IxIhwdF9qgWsdDiz7T6S35G4NpRuzpZRFaeeM7h28J1YAo0/+aha/uYb8iECcFtaocoE4NsUhLNWOqQhjJJoUUmgCrqM9/xchi/MoJNtFAHmNuMmduGIK8LK1f7sHlRD18ghI22hWFWOMWaaK4zdOYUk5YZiG4H7t9IuMl3qND3PrNq+jdeJlHKu0H4WRV28rLSd3py+kxZiL4fOhALJ6rfCzOem8Xwy61wqVfAfZw+tNs47ZohnR6kdYI03pozR/KGk3BkKrfDrz4hYPdNlUxBqSanwfwrdoU7DJ00FxvxpzmBIjllIxbg9ahS43+UmrOVQS7cEr8TyhkqhV3EE37scP2aOt8DgqBC2TxrMid4LFCf7UCLuqDCWS/Nck1hQt+cIjyxZbpeQVeR1Bg5M0Ut73rIT6VmuoZ3LBx+7/d07z1EDiwA/Va2OKPk6IzmuxPGb5mTCTpd9MK84TgdlPdQyQorCzko83h+hOkoZ0UDQ7CvAbGlPZn1lmPIciufCSMkmWJWy0ZQbP31auPSqTBHzemze8IH+r71mXIRucbqT9L52g1S8bTiS3uUHu6b/bv1Jlhe1hMETth69mw2Wx9uFhy5cdoSMGVl5N1d1w6Y/kvzX62uc8H75Pk2xxxIa6hXMTYn9cstsHAbhJLlfAPcKGZoRv4hIWy9Pmc1bE19lBufdfKbX+I+ZzpR3srW4h4m9T3wLSth45mMojowjnDeHcAVJNz+w3HnWYUkl05UGjPMOC00syIYXvyTwFBHHaaMEXAroljNvbSKyhEaJmbI47YfAZ9WhHdt/tPoVLyQApr7Th8cYU5fLNDHiBnyqjPsTCzQB6H/RphOIowEU6UB1OcPDXT67kUrLnb1d5u0KMkluaA+8O9biXCUhSgVYaOsorxYVdDPf4NYstrBIB0wTW6+FE6ynVCw7BUyv1LHx1yA82OcMv48ysDredg5NYHbvTtdr9xpUkynXJyJ4p1xTaz/TY0hqgXNq9kS7eOahVa7QYWyH+rkifOb5Qxx9sqp/ehKlYFkZ188k73Hzt306XuF1Ku2i5P/PDGSnuB7ZHEu1j4NhAnC4PxufSrNiuCxv3kVlb1aofWdXS3tPWYJnFH84bgkigDXRO4blQIdXTKaI4hQnNf9n38/BL3B/x6CFHO54AyJ8JArc10A7L4ndCyYP/Oe6gjQf5jvzVLruWG3Va74s47Qm572koAZ9gRA+6eDEFi3VD0L6Ir9Pm7sPx1FsTkclPhSRO1PQpi3OI5vsTgEWEP9voaVUrZyfe6Q/IY0HnbrYW0NaBSusR/9z6XjxVbE7AKYGIlw5TA6juotL2mqES88qZ7GF0SHQjh+gMGVzAG7MTiixQ5/F/+d+g1z1Q+7+srLu8yfssggiS0bEJ3eXHpgSR7KF9/9GcXhJiof2KyvoL3rzBa838icKtsv6vMeM7QozDNjbPmDS0NLkJi8j4vNgOTTbAMkMYJnqO/QGC1PMaWUDzEkuIZZGWhAYCMEquK3vo/Ce3Ds9OKe7K5/QiGPBA1Be2bqprWXp5nMBqoVsA9aWxHqdMe+PN7csBeSeAcnmoNBGh/NRYJHx0liR2fybXuIQEY1/zRrTd8AoEqyiz0t3OBy3TxeesTBn1bDRYLlIAskH8OOCBN3Knfhp9TN3kg7xu1mjyx7XlKPVySUizFcbBVPxO7DMadALpbkHWAtNkV2qUf+66sRD+QQo80FIw0GVPPbzcXYJd/TjDXqynBIw0eOVvhmmWZddiFaxwtKG32nc9IzAyGr0yjPK0m9k9QklgdB204MtVt58P0GpvmH4V4RbdRkReB60ptox92dXIbZM2uD3TWr4uR4aCATQ7zmk/xUFB62WAoIEQSvMhe/k7t6O8BAasBEH6Jhzz+IqmezpJ17weqEZMaZOaJPpqN96bykWEN5WW+aYoaWJNR4Buh3qg9VK/o0u9iMOmGBrErpo9C97UKVYDjyZsf3elLG8lxYH0a4OrLKizSdiOIE3ydFQPmHPgA/i2kKXCjQBfcPEOD+nd5oUQmdMfcYyJsuPKs0EqZu3cGeJ6naBqquymFxeiWiXD/qrL1110kXBehakWZ/3kIT6VwMRwQCRsrvunpC/uEDGo93bK0peirjXE2OHnRh+faGsR4kAIH+BZhVEn8NhSL9441mF2RhfDUmX3m4C+dj1TdMPcik4nCqzY0kV0DuzQZgxfy6PlUiMVGWFKh7V/5+z5wq5wL8qo0LX+xhygVhGFnbfIp9VFnDGmcpbKvCXCfijHz/cPR8WvFqV+TRMpReqNamLqqgQP+RE5Rw0T8bb1E2jTvUElobxKNX3UjlWhj/S5KZiaCZ7u5fp4fZ5aceTffyyanHE2851d90JdqgadOMEfdeJHJo0GR4x6OagjRXyMHwu2nLWuxdxckYoGbaA8sInc5RFJqpezLYPhuCMyNTLy1HIesQRGmuFrm9NeG74KxgHTdbDCl5NwVbYoxzmGG8bbzH05MpUVMmQpmEtIlAHwxuMpfh7DUA2JrUzpFO7P/kH865OQmds1KsifCm0HgjCLQdcmY5l6iMfMI/CW34O11xMoT0ZyP3LWBY0KCfJbGygPjfmRJR7KQac5XRh9LEyKBwMRrfvITodV/dXZcH+t6Czdctfme9NLiGnxPFXI5DnwohBg72fJLokzJWUHtzPjV9ERI9ipuFsnRp6mu/9nvGyEhvXpUFsTCRBKwq+JQFC6AQGzoVpLIHI+S3V4ppA9PziZ7k+0/eF5q2whNBdyFpOWl4XQedY32PKBr/Jk+9mpbd1Ii0b5kwH87BYkcjOl1+MQ=="}', + }, + }, +]; module.exports.copayers = copayers; diff --git a/packages/lightwallet/common/merit-wallet-client/test/log.js b/packages/lightwallet/common/merit-wallet-client/test/log.js index b5b812a958..806a8007be 100644 --- a/packages/lightwallet/common/merit-wallet-client/test/log.js +++ b/packages/lightwallet/common/merit-wallet-client/test/log.js @@ -12,8 +12,7 @@ describe('log utils', function() { }); it('should log .warn', function() { - if (console.warn.restore) - console.warn.restore(); + if (console.warn.restore) console.warn.restore(); sinon.stub(console, 'warn'); @@ -26,15 +25,13 @@ describe('log utils', function() { console.warn.restore(); }); - it('should log .fatal', function() { - if (console.log.restore) - console.log.restore(); + if (console.log.restore) console.log.restore(); sinon.stub(console, 'log'); log.setLevel('debug'); - log.fatal('hola', "que", 'tal'); + log.fatal('hola', 'que', 'tal'); var arg = console.log.getCall(0).args[0]; //arg.should.contain('util.log.js'); /* Firefox does not include the stack track */ @@ -42,7 +39,6 @@ describe('log utils', function() { console.log.restore(); }); - it('should not log debug', function() { sinon.stub(console, 'log'); log.setLevel('info'); @@ -75,5 +71,4 @@ describe('log utils', function() { it('should not create a log.silent() method', function() { should.not.exist(log.silent); }); - }); diff --git a/packages/lightwallet/common/merit-wallet-client/test/paypro.js b/packages/lightwallet/common/merit-wallet-client/test/paypro.js index 419407b25b..afb43739d4 100644 --- a/packages/lightwallet/common/merit-wallet-client/test/paypro.js +++ b/packages/lightwallet/common/merit-wallet-client/test/paypro.js @@ -7,7 +7,6 @@ var should = chai.should(); var PayPro = require('../lib/paypro'); var TestData = require('./testdata'); - describe('paypro', function() { var xhr, httpNode, clock; before(function() { @@ -31,10 +30,8 @@ describe('paypro', function() { var res = {}; res.statusCode = httpNode.error || 200; res.on = function(e, cb) { - if (e == 'data') - return cb(TestData.payProBuf); - if (e == 'end') - return cb(); + if (e == 'data') return cb(TestData.payProBuf); + if (e == 'end') return cb(); }; return cb(res); }; @@ -42,10 +39,8 @@ describe('paypro', function() { var res = {}; res.statusCode = httpNode.error || 200; res.on = function(e, cb) { - if (e == 'data') - return cb(new Buffer('id')); - if (e == 'end') - return cb(); + if (e == 'data') return cb(new Buffer('id')); + if (e == 'end') return cb(); }; return cb(res); @@ -56,51 +51,57 @@ describe('paypro', function() { }); it('Make a PP request with browser', function(done) { - PayPro.get({ - url: 'http://an.url.com/paypro', - xhr: xhr, - env: 'browser', - }, function(err, res) { - should.not.exist(err); - res.should.deep.equal(TestData.payProData); - done(); - }); + PayPro.get( + { + url: 'http://an.url.com/paypro', + xhr: xhr, + env: 'browser', + }, + function(err, res) { + should.not.exist(err); + res.should.deep.equal(TestData.payProData); + done(); + }, + ); }); it('Make a PP request with browser with headers', function(done) { - PayPro.get({ - url: 'http://an.url.com/paypro', - xhr: xhr, - env: 'browser', - headers: { - 'Accept': 'xx/xxx', - 'Content-Type': 'application/octet-stream', - 'Content-Length': 0, - 'Content-Transfer-Encoding': 'xxx', - } - - }, function(err, res) { - should.not.exist(err); - res.should.deep.equal(TestData.payProData); - done(); - }); + PayPro.get( + { + url: 'http://an.url.com/paypro', + xhr: xhr, + env: 'browser', + headers: { + Accept: 'xx/xxx', + 'Content-Type': 'application/octet-stream', + 'Content-Length': 0, + 'Content-Transfer-Encoding': 'xxx', + }, + }, + function(err, res) { + should.not.exist(err); + res.should.deep.equal(TestData.payProData); + done(); + }, + ); }); - - it('make a pp request with browser, with http error', function(done) { xhr.send = function() { xhr.onerror(); }; - PayPro.get({ - url: 'http://an.url.com/paypro', - xhr: xhr, - env: 'browser', - }, function(err, res) { - err.should.be.an.instanceOf(Error); - err.message.should.equal('HTTP Request Error'); - done(); - }); + PayPro.get( + { + url: 'http://an.url.com/paypro', + xhr: xhr, + env: 'browser', + }, + function(err, res) { + err.should.be.an.instanceOf(Error); + err.message.should.equal('HTTP Request Error'); + done(); + }, + ); }); it('Make a PP request with browser, with http given error', function(done) { @@ -108,48 +109,55 @@ describe('paypro', function() { xhr.onerror(); }; xhr.statusText = 'myerror'; - PayPro.get({ - url: 'http://an.url.com/paypro', - xhr: xhr, - env: 'browser', - }, function(err, res) { - err.should.be.an.instanceOf(Error); - err.message.should.equal('myerror'); - done(); - }); + PayPro.get( + { + url: 'http://an.url.com/paypro', + xhr: xhr, + env: 'browser', + }, + function(err, res) { + err.should.be.an.instanceOf(Error); + err.message.should.equal('myerror'); + done(); + }, + ); }); - it('Make a PP request with node', function(done) { xhr.send = function() { xhr.response = 'id'; xhr.onload(); }; - xhr.statusText = null; - PayPro.get({ - url: 'http://an.url.com/paypro', - httpNode: httpNode, - env: 'node', - }, function(err, res) { - should.not.exist(err); - res.should.deep.equal(TestData.payProData); - done(); - }); + PayPro.get( + { + url: 'http://an.url.com/paypro', + httpNode: httpNode, + env: 'node', + }, + function(err, res) { + should.not.exist(err); + res.should.deep.equal(TestData.payProData); + done(); + }, + ); }); it('Make a PP request with node with HTTP error', function(done) { httpNode.error = 404; - PayPro.get({ - url: 'http://an.url.com/paypro', - httpNode: httpNode, - env: 'node', - }, function(err, res) { - err.should.be.an.instanceOf(Error); - err.message.should.equal('HTTP Request Error'); - done(); - }); + PayPro.get( + { + url: 'http://an.url.com/paypro', + httpNode: httpNode, + env: 'node', + }, + function(err, res) { + err.should.be.an.instanceOf(Error); + err.message.should.equal('HTTP Request Error'); + done(); + }, + ); }); it('Create a PP payment', function() { @@ -159,7 +167,9 @@ describe('paypro', function() { for (var i = 0; i < payment.length; i++) { s += payment[i].toString(16); } - s.should.equal('a4c7b22696e766f6963654964223a22436962454a4a74473174394837374b6d4d3631453274222c226d65726368616e744964223a22444766754344656f66556e576a446d5537454c634568227d12412ab12341a1d864121976a914ae6eeec7e05624db748f9c16cce6fb53696ab3988ac'); + s.should.equal( + 'a4c7b22696e766f6963654964223a22436962454a4a74473174394837374b6d4d3631453274222c226d65726368616e744964223a22444766754344656f66556e576a446d5537454c634568227d12412ab12341a1d864121976a914ae6eeec7e05624db748f9c16cce6fb53696ab3988ac', + ); }); it('Send a PP payment (browser)', function(done) { @@ -196,5 +206,4 @@ describe('paypro', function() { done(); }); }); - }); diff --git a/packages/lightwallet/common/merit-wallet-client/test/testdata.js b/packages/lightwallet/common/merit-wallet-client/test/testdata.js index 7b47aed827..541c21cd58 100644 --- a/packages/lightwallet/common/merit-wallet-client/test/testdata.js +++ b/packages/lightwallet/common/merit-wallet-client/test/testdata.js @@ -1,79 +1,86 @@ -var history = [{ - txid: "0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04", - vin: [{ - txid: "c8e221141e8bb60977896561b77fa59d6dacfcc10db82bf6f5f923048b11c70d", - vout: 0, - n: 0, - addr: "2N6Zutg26LEC4iYVxi7SHhopVLP1iZPU1rZ", - valueMicros: 485645, - value: 0.00485645, - }, { - txid: "6e599eea3e2898b91087eb87e041c5d8dec5362447a8efba185ed593f6dc64c0", - vout: 1, - n: 1, - addr: "2MyqmcWjmVxW8i39wdk1CVPdEqKyFSY9H1S", - valueMicros: 885590, - value: 0.0088559, - }], - vout: [{ - value: "0.00045753", - n: 0, - scriptPubKey: { - addresses: [ - "2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V" - ] - }, - }, { - value: "0.01300000", - n: 1, - scriptPubKey: { - addresses: [ - "mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE" - ] - } - }], - confirmations: 2, - time: 1424471041, - blocktime: 20, - valueOut: 0.01345753, - valueIn: 0.01371235, - fees: 0.00025482 -}, { - txid: "fad88682ccd2ff34cac6f7355fe9ecd8addd9ef167e3788455972010e0d9d0de", - vin: [{ - txid: "0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04", - vout: 0, - n: 0, - addr: "2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V", - valueMicros: 45753, - value: 0.00045753, - }], - vout: [{ - value: "0.00011454", - n: 0, - scriptPubKey: { - addresses: [ - "2N7GT7XaN637eBFMmeczton2aZz5rfRdZso" - ] - } - }, { - value: "0.00020000", - n: 1, - scriptPubKey: { - addresses: [ - "mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE" - ] - } - }], - confirmations: 1, - firstSeenTs: 1424472242, - blocktime: 10, - valueOut: 0.00031454, - valueIn: 0.00045753, - fees: 0.00014299 -}]; +var history = [ + { + txid: '0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04', + vin: [ + { + txid: 'c8e221141e8bb60977896561b77fa59d6dacfcc10db82bf6f5f923048b11c70d', + vout: 0, + n: 0, + addr: '2N6Zutg26LEC4iYVxi7SHhopVLP1iZPU1rZ', + valueMicros: 485645, + value: 0.00485645, + }, + { + txid: '6e599eea3e2898b91087eb87e041c5d8dec5362447a8efba185ed593f6dc64c0', + vout: 1, + n: 1, + addr: '2MyqmcWjmVxW8i39wdk1CVPdEqKyFSY9H1S', + valueMicros: 885590, + value: 0.0088559, + }, + ], + vout: [ + { + value: '0.00045753', + n: 0, + scriptPubKey: { + addresses: ['2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V'], + }, + }, + { + value: '0.01300000', + n: 1, + scriptPubKey: { + addresses: ['mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE'], + }, + }, + ], + confirmations: 2, + time: 1424471041, + blocktime: 20, + valueOut: 0.01345753, + valueIn: 0.01371235, + fees: 0.00025482, + }, + { + txid: 'fad88682ccd2ff34cac6f7355fe9ecd8addd9ef167e3788455972010e0d9d0de', + vin: [ + { + txid: '0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04', + vout: 0, + n: 0, + addr: '2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V', + valueMicros: 45753, + value: 0.00045753, + }, + ], + vout: [ + { + value: '0.00011454', + n: 0, + scriptPubKey: { + addresses: ['2N7GT7XaN637eBFMmeczton2aZz5rfRdZso'], + }, + }, + { + value: '0.00020000', + n: 1, + scriptPubKey: { + addresses: ['mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE'], + }, + }, + ], + confirmations: 1, + firstSeenTs: 1424472242, + blocktime: 10, + valueOut: 0.00031454, + valueIn: 0.00045753, + fees: 0.00014299, + }, +]; -var payproHex = '0801120b783530392b7368613235361a89250aa40a3082052030820408a003020102020727a49d05046d62300d06092a864886f70d01010b05003081b4310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e312d302b060355040b1324687474703a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f313330310603550403132a476f2044616464792053656375726520436572746966696361746520417574686f72697479202d204732301e170d3134303432363132333532365a170d3136303432363132333532365a303a3121301f060355040b1318446f6d61696e20436f6e74726f6c2056616c6964617465643115301306035504030c0c2a2e6269747061792e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100e2a5dd4aea959c1d0fb016e6e05bb7011e741cdc61918c61f9625a2f682f485f0e862ea63db61cc9161753127504de800604df36b10f46cb17ab6cb99dba8aa45a36adfb901a2fc380c89e234bce18de6639b883e9339801673efaee1f2df77eeb82f7c39c96a2f8ef4572b634c203d9be8fd1e0036d32fb38b6b9b5ecd5a0684345c7e9ffc5d26bc6fd69aa6619f77badaa4bfb989478fb2f41aa92782e40b34ba9ac4549a4e6fda76b5fc4a581853bd0de5fb5a2c6dfdc12cdfadb54e9636a6d1223705924b8be566b81ac7921078cf590a146ae397a84908ef4fc83ff5715a44ab59e9258674d90113bb607b8d81eb268e4c6ce849497c76521795b0873950203010001a38201ae308201aa300f0603551d130101ff04053003010100301d0603551d250416301406082b0601050507030106082b06010505070302300e0603551d0f0101ff0404030205a030360603551d1f042f302d302ba029a0278625687474703a2f2f63726c2e676f64616464792e636f6d2f676469673273312d34392e63726c30530603551d20044c304a3048060b6086480186fd6d010717013039303706082b06010505070201162b687474703a2f2f6365727469666963617465732e676f64616464792e636f6d2f7265706f7369746f72792f307606082b06010505070101046a3068302406082b060105050730018618687474703a2f2f6f6373702e676f64616464792e636f6d2f304006082b060105050730028634687474703a2f2f6365727469666963617465732e676f64616464792e636f6d2f7265706f7369746f72792f67646967322e637274301f0603551d2304183016801440c2bd278ecc348330a233d7fb6cb3f0b42c80ce30230603551d11041c301a820c2a2e6269747061792e636f6d820a6269747061792e636f6d301d0603551d0e0416041485454e3b4072e2f58e377438988b5229387e967a300d06092a864886f70d01010b050003820101002d0a7ef97f988905ebbbad4e9ffb690352535211d6792516119838b55f24ff9fa4e93b6187b8517cbb0477457d3378078ef66057abe41bcafeb142ec52443a94b88114fa069f725c6198581d97af16352727f4f35e7f2110faa41a0511bcfdf8e3f4a3a310278c150b10f32a962c81e8f3d5374d9cb56d893027ff4fa4e3c3e6384c1f1557ceea6fca9cbc0c110748c08b82d8f0ed9a579637ee43a2d8fec3b5b04d1f3c8f1a3e2088da2274b6bc60948bbe744a7f8b942b41f0ae9b4afaeefbb7e0f04a0587b52efb6ebfa2d970b9de56a068575e4bf0cf824618dc17bbeaa2cdd25d65970a9f1a06fc9fffb466a10c9568cd651795bc2c7996975027bdbaba0ad409308204d0308203b8a003020102020107300d06092a864886f70d01010b0500308183310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e3131302f06035504031328476f20446164647920526f6f7420436572746966696361746520417574686f72697479202d204732301e170d3131303530333037303030305a170d3331303530333037303030305a3081b4310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e312d302b060355040b1324687474703a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f313330310603550403132a476f2044616464792053656375726520436572746966696361746520417574686f72697479202d20473230820122300d06092a864886f70d01010105000382010f003082010a0282010100b9e0cb10d4af76bdd49362eb3064b881086cc304d962178e2fff3e65cf8fce62e63c521cda16454b55ab786b63836290ce0f696c99c81a148b4ccc4533ea88dc9ea3af2bfe80619d7957c4cf2ef43f303c5d47fc9a16bcc3379641518e114b54f828bed08cbef030381ef3b026f86647636dde7126478f384753d1461db4e3dc00ea45acbdbc71d9aa6f00dbdbcd303a794f5f4c47f81def5bc2c49d603bb1b24391d8a4334eeab3d6274fad258aa5c6f4d5d0a6ae7405645788b54455d42d2a3a3ef8b8bde9320a029464c4163a50f14aaee77933af0c20077fe8df0439c269026c6352fa77c11bc87487c8b993185054354b694ebc3bd3492e1fdcc1d252fb0203010001a382011a30820116300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106301d0603551d0e0416041440c2bd278ecc348330a233d7fb6cb3f0b42c80ce301f0603551d230418301680143a9a8507106728b6eff6bd05416e20c194da0fde303406082b0601050507010104283026302406082b060105050730018618687474703a2f2f6f6373702e676f64616464792e636f6d2f30350603551d1f042e302c302aa028a0268624687474703a2f2f63726c2e676f64616464792e636f6d2f6764726f6f742d67322e63726c30460603551d20043f303d303b0604551d20003033303106082b06010505070201162568747470733a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f300d06092a864886f70d01010b05000382010100087e6c9310c838b896a9904bffa15f4f04ef6c3e9c8806c9508fa673f757311bbebce42fdbf8bad35be0b4e7e679620e0ca2d76a637331b5f5a848a43b082da25d90d7b47c254f115630c4b6449d7b2c9de55ee6ef0c61aabfe42a1bee849eb8837dc143ce44a713700d911ff4c813ad8360d9d872a873241eb5ac220eca17896258441bab892501000fcdc41b62db51b4d30f512a9bf4bc73fc76ce36a4cdd9d82ceaae9bf52ab290d14d75188a3f8a4190237d5b4bfea403589b46b2c3606083f87d5041cec2a190c3bbef022fd21554ee4415d90aaea78a33edb12d763626dc04eb9ff7611f15dc876fee469628ada1267d0a09a72e04a38dbcf8bc0430010a81093082047d30820365a00302010202031be715300d06092a864886f70d01010b05003063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f72697479301e170d3134303130313037303030305a170d3331303533303037303030305a308183310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e3131302f06035504031328476f20446164647920526f6f7420436572746966696361746520417574686f72697479202d20473230820122300d06092a864886f70d01010105000382010f003082010a0282010100bf716208f1fa5934f71bc918a3f7804958e9228313a6c52043013b84f1e685499f27eaf6841b4ea0b4db7098c73201b1053e074eeef4fa4f2f593022e7ab19566be28007fcf316758039517be5f935b6744ea98d8213e4b63fa90383faa2be8a156a7fde0bc3b6191405caeac3a804943b467c320df3006622c88d696d368c1118b7d3b21c60b438fa028cced3dd4607de0a3eeb5d7cc87cfbb02b53a4926269512505611a44818c2ca9439623dfac3a819a0e29c51ca9e95d1eb69e9e300a39cef18880fb4b5dcc32ec85624325340256270191b43b702a3f6eb1e89c88017d9fd4f9db536d609dbf2ce758abb85f46fccec41b033c09eb49315c6946b3e0470203010001a382011730820113300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106301d0603551d0e041604143a9a8507106728b6eff6bd05416e20c194da0fde301f0603551d23041830168014d2c4b0d291d44c1171b361cb3da1fedda86ad4e3303406082b0601050507010104283026302406082b060105050730018618687474703a2f2f6f6373702e676f64616464792e636f6d2f30320603551d1f042b30293027a025a0238621687474703a2f2f63726c2e676f64616464792e636f6d2f6764726f6f742e63726c30460603551d20043f303d303b0604551d20003033303106082b06010505070201162568747470733a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f300d06092a864886f70d01010b05000382010100590b53bd928611a7247bed5b31cf1d1f6c70c5b86ebe4ebbf6be9750e1307fba285c6294c2e37e33f7fb427685db951c8c225875090c886567390a1609c5a03897a4c523933fb418a601064491e3a76927b45a257f3ab732cddd84ff2a382933a4dd67b285fea188201c5089c8dc2af64203374ce688dfd5af24f2b1c3dfccb5ece0995eb74954203c94180cc71c521849a46de1b3580bc9d8ecd9ae1c328e28700de2fea6179e840fbd5770b35ae91fa08653bbef7cff690be048c3b7930bc80a54c4ac5d1467376ccaa52f310837aa6e6f8cbc9be2575d2481af97979c84ad6cac374c66f361911120e4be309f7aa42909b0e1345f6477184051df8c30a6af0a840830820400308202e8a003020102020100300d06092a864886f70d01010505003063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f72697479301e170d3034303632393137303632305a170d3334303632393137303632305a3063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f7269747930820120300d06092a864886f70d01010105000382010d00308201080282010100de9dd7ea571849a15bebd75f4886eabeddffe4ef671cf46568b35771a05e77bbed9b49e970803d561863086fdaf2ccd03f7f0254225410d8b281d4c0753d4b7fc777c33e78ab1a03b5206b2f6a2bb1c5887ec4bb1eb0c1d845276faa3758f78726d7d82df6a917b71f72364ea6173f659892db2a6e5da2fe88e00bde7fe58d15e1ebcb3ad5e212a2132dd88eaf5f123da0080508b65ca565380445991ea3606074c541a572621b62c51f6f5f1a42be025165a8ae23186afc7803a94d7f80c3faab5afca140a4ca1916feb2c8ef5e730dee77bd9af67998bcb10767a2150ddda058c6447b0a3e62285fba41075358cf117e3874c5f8ffb569908f8474ea971baf020103a381c03081bd301d0603551d0e04160414d2c4b0d291d44c1171b361cb3da1fedda86ad4e330818d0603551d230481853081828014d2c4b0d291d44c1171b361cb3da1fedda86ad4e3a167a4653063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f72697479820100300c0603551d13040530030101ff300d06092a864886f70d01010505000382010100324bf3b2ca3e91fc12c6a1078c8e77a03306145c901e18f708a63d0a19f98780116e69e4961730ff3491637238eecc1c01a31d9428a431f67ac454d7f6e5315803a2ccce62db944573b5bf45c924b5d58202ad2379698db8b64dcecf4cca3323e81c88aa9d8b416e16c920e5899ecd3bda70f77e992620145425ab6e7385e69b219d0a6c820ea8f8c20cfa101e6c96ef870dc40f618badee832b95f88e92847239eb20ea83ed83cd976e08bceb4e26b6732be4d3f64cfe2671e26111744aff571a870f75482ecf516917a002126195d5d140b2104ceec4ac1043a6a59e0ad595629a0dcf8882c5320ce42b9f45e60d9f289cb1b92a5a57ad370faf1d7fdbbd9f2285020a0474657374121f0894d818121976a9142d89a9720d0aca9beaae478994a06b1ab178186788ac18f3f2caa80520f7f9caa8052a505061796d656e74207265717565737420666f722042697450617920696e766f69636520436962454a4a74473174394837374b6d4d363145327420666f72206d65726368616e742074657374436f706179323068747470733a2f2f746573742e6269747061792e636f6d2f692f436962454a4a74473174394837374b6d4d36314532743a4c7b22696e766f6963654964223a22436962454a4a74473174394837374b6d4d3631453274222c226d65726368616e744964223a22444766754344656f66556e576a446d5537454c634568227d2a8002c7146109dfd2584b905627f13e79fe96cc390de6d9729f1263be9ded44f907cc185a1968b71d1b99f073671e288ff51be93493dc2b0cbd7a9de761692bbb143c117aa24961c64e3add6a35b67b48da73c6c740024665494c28cd80d6bbf99ab98d9cee87a6bf826666990d51791d87978cbefd132679851c19962c0ba364913786ec6c9706989c0b4e257d1313cd635822569babff5e58e41f4f94add69efc5ed2850fc1c87cac0487ef3678d02b92459e04666f0e2d3e530502c0623768cd741262fcdf696817ffecb93917152a16a701d21f0a257302d2596f3c86b3fa296450662a11fdd857c40e6bb50cfad4e65cf647eb65541a617661c69da903c54bf6'; +var payproHex = + '0801120b783530392b7368613235361a89250aa40a3082052030820408a003020102020727a49d05046d62300d06092a864886f70d01010b05003081b4310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e312d302b060355040b1324687474703a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f313330310603550403132a476f2044616464792053656375726520436572746966696361746520417574686f72697479202d204732301e170d3134303432363132333532365a170d3136303432363132333532365a303a3121301f060355040b1318446f6d61696e20436f6e74726f6c2056616c6964617465643115301306035504030c0c2a2e6269747061792e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100e2a5dd4aea959c1d0fb016e6e05bb7011e741cdc61918c61f9625a2f682f485f0e862ea63db61cc9161753127504de800604df36b10f46cb17ab6cb99dba8aa45a36adfb901a2fc380c89e234bce18de6639b883e9339801673efaee1f2df77eeb82f7c39c96a2f8ef4572b634c203d9be8fd1e0036d32fb38b6b9b5ecd5a0684345c7e9ffc5d26bc6fd69aa6619f77badaa4bfb989478fb2f41aa92782e40b34ba9ac4549a4e6fda76b5fc4a581853bd0de5fb5a2c6dfdc12cdfadb54e9636a6d1223705924b8be566b81ac7921078cf590a146ae397a84908ef4fc83ff5715a44ab59e9258674d90113bb607b8d81eb268e4c6ce849497c76521795b0873950203010001a38201ae308201aa300f0603551d130101ff04053003010100301d0603551d250416301406082b0601050507030106082b06010505070302300e0603551d0f0101ff0404030205a030360603551d1f042f302d302ba029a0278625687474703a2f2f63726c2e676f64616464792e636f6d2f676469673273312d34392e63726c30530603551d20044c304a3048060b6086480186fd6d010717013039303706082b06010505070201162b687474703a2f2f6365727469666963617465732e676f64616464792e636f6d2f7265706f7369746f72792f307606082b06010505070101046a3068302406082b060105050730018618687474703a2f2f6f6373702e676f64616464792e636f6d2f304006082b060105050730028634687474703a2f2f6365727469666963617465732e676f64616464792e636f6d2f7265706f7369746f72792f67646967322e637274301f0603551d2304183016801440c2bd278ecc348330a233d7fb6cb3f0b42c80ce30230603551d11041c301a820c2a2e6269747061792e636f6d820a6269747061792e636f6d301d0603551d0e0416041485454e3b4072e2f58e377438988b5229387e967a300d06092a864886f70d01010b050003820101002d0a7ef97f988905ebbbad4e9ffb690352535211d6792516119838b55f24ff9fa4e93b6187b8517cbb0477457d3378078ef66057abe41bcafeb142ec52443a94b88114fa069f725c6198581d97af16352727f4f35e7f2110faa41a0511bcfdf8e3f4a3a310278c150b10f32a962c81e8f3d5374d9cb56d893027ff4fa4e3c3e6384c1f1557ceea6fca9cbc0c110748c08b82d8f0ed9a579637ee43a2d8fec3b5b04d1f3c8f1a3e2088da2274b6bc60948bbe744a7f8b942b41f0ae9b4afaeefbb7e0f04a0587b52efb6ebfa2d970b9de56a068575e4bf0cf824618dc17bbeaa2cdd25d65970a9f1a06fc9fffb466a10c9568cd651795bc2c7996975027bdbaba0ad409308204d0308203b8a003020102020107300d06092a864886f70d01010b0500308183310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e3131302f06035504031328476f20446164647920526f6f7420436572746966696361746520417574686f72697479202d204732301e170d3131303530333037303030305a170d3331303530333037303030305a3081b4310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e312d302b060355040b1324687474703a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f313330310603550403132a476f2044616464792053656375726520436572746966696361746520417574686f72697479202d20473230820122300d06092a864886f70d01010105000382010f003082010a0282010100b9e0cb10d4af76bdd49362eb3064b881086cc304d962178e2fff3e65cf8fce62e63c521cda16454b55ab786b63836290ce0f696c99c81a148b4ccc4533ea88dc9ea3af2bfe80619d7957c4cf2ef43f303c5d47fc9a16bcc3379641518e114b54f828bed08cbef030381ef3b026f86647636dde7126478f384753d1461db4e3dc00ea45acbdbc71d9aa6f00dbdbcd303a794f5f4c47f81def5bc2c49d603bb1b24391d8a4334eeab3d6274fad258aa5c6f4d5d0a6ae7405645788b54455d42d2a3a3ef8b8bde9320a029464c4163a50f14aaee77933af0c20077fe8df0439c269026c6352fa77c11bc87487c8b993185054354b694ebc3bd3492e1fdcc1d252fb0203010001a382011a30820116300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106301d0603551d0e0416041440c2bd278ecc348330a233d7fb6cb3f0b42c80ce301f0603551d230418301680143a9a8507106728b6eff6bd05416e20c194da0fde303406082b0601050507010104283026302406082b060105050730018618687474703a2f2f6f6373702e676f64616464792e636f6d2f30350603551d1f042e302c302aa028a0268624687474703a2f2f63726c2e676f64616464792e636f6d2f6764726f6f742d67322e63726c30460603551d20043f303d303b0604551d20003033303106082b06010505070201162568747470733a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f300d06092a864886f70d01010b05000382010100087e6c9310c838b896a9904bffa15f4f04ef6c3e9c8806c9508fa673f757311bbebce42fdbf8bad35be0b4e7e679620e0ca2d76a637331b5f5a848a43b082da25d90d7b47c254f115630c4b6449d7b2c9de55ee6ef0c61aabfe42a1bee849eb8837dc143ce44a713700d911ff4c813ad8360d9d872a873241eb5ac220eca17896258441bab892501000fcdc41b62db51b4d30f512a9bf4bc73fc76ce36a4cdd9d82ceaae9bf52ab290d14d75188a3f8a4190237d5b4bfea403589b46b2c3606083f87d5041cec2a190c3bbef022fd21554ee4415d90aaea78a33edb12d763626dc04eb9ff7611f15dc876fee469628ada1267d0a09a72e04a38dbcf8bc0430010a81093082047d30820365a00302010202031be715300d06092a864886f70d01010b05003063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f72697479301e170d3134303130313037303030305a170d3331303533303037303030305a308183310b30090603550406130255533110300e060355040813074172697a6f6e61311330110603550407130a53636f74747364616c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e3131302f06035504031328476f20446164647920526f6f7420436572746966696361746520417574686f72697479202d20473230820122300d06092a864886f70d01010105000382010f003082010a0282010100bf716208f1fa5934f71bc918a3f7804958e9228313a6c52043013b84f1e685499f27eaf6841b4ea0b4db7098c73201b1053e074eeef4fa4f2f593022e7ab19566be28007fcf316758039517be5f935b6744ea98d8213e4b63fa90383faa2be8a156a7fde0bc3b6191405caeac3a804943b467c320df3006622c88d696d368c1118b7d3b21c60b438fa028cced3dd4607de0a3eeb5d7cc87cfbb02b53a4926269512505611a44818c2ca9439623dfac3a819a0e29c51ca9e95d1eb69e9e300a39cef18880fb4b5dcc32ec85624325340256270191b43b702a3f6eb1e89c88017d9fd4f9db536d609dbf2ce758abb85f46fccec41b033c09eb49315c6946b3e0470203010001a382011730820113300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106301d0603551d0e041604143a9a8507106728b6eff6bd05416e20c194da0fde301f0603551d23041830168014d2c4b0d291d44c1171b361cb3da1fedda86ad4e3303406082b0601050507010104283026302406082b060105050730018618687474703a2f2f6f6373702e676f64616464792e636f6d2f30320603551d1f042b30293027a025a0238621687474703a2f2f63726c2e676f64616464792e636f6d2f6764726f6f742e63726c30460603551d20043f303d303b0604551d20003033303106082b06010505070201162568747470733a2f2f63657274732e676f64616464792e636f6d2f7265706f7369746f72792f300d06092a864886f70d01010b05000382010100590b53bd928611a7247bed5b31cf1d1f6c70c5b86ebe4ebbf6be9750e1307fba285c6294c2e37e33f7fb427685db951c8c225875090c886567390a1609c5a03897a4c523933fb418a601064491e3a76927b45a257f3ab732cddd84ff2a382933a4dd67b285fea188201c5089c8dc2af64203374ce688dfd5af24f2b1c3dfccb5ece0995eb74954203c94180cc71c521849a46de1b3580bc9d8ecd9ae1c328e28700de2fea6179e840fbd5770b35ae91fa08653bbef7cff690be048c3b7930bc80a54c4ac5d1467376ccaa52f310837aa6e6f8cbc9be2575d2481af97979c84ad6cac374c66f361911120e4be309f7aa42909b0e1345f6477184051df8c30a6af0a840830820400308202e8a003020102020100300d06092a864886f70d01010505003063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f72697479301e170d3034303632393137303632305a170d3334303632393137303632305a3063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f7269747930820120300d06092a864886f70d01010105000382010d00308201080282010100de9dd7ea571849a15bebd75f4886eabeddffe4ef671cf46568b35771a05e77bbed9b49e970803d561863086fdaf2ccd03f7f0254225410d8b281d4c0753d4b7fc777c33e78ab1a03b5206b2f6a2bb1c5887ec4bb1eb0c1d845276faa3758f78726d7d82df6a917b71f72364ea6173f659892db2a6e5da2fe88e00bde7fe58d15e1ebcb3ad5e212a2132dd88eaf5f123da0080508b65ca565380445991ea3606074c541a572621b62c51f6f5f1a42be025165a8ae23186afc7803a94d7f80c3faab5afca140a4ca1916feb2c8ef5e730dee77bd9af67998bcb10767a2150ddda058c6447b0a3e62285fba41075358cf117e3874c5f8ffb569908f8474ea971baf020103a381c03081bd301d0603551d0e04160414d2c4b0d291d44c1171b361cb3da1fedda86ad4e330818d0603551d230481853081828014d2c4b0d291d44c1171b361cb3da1fedda86ad4e3a167a4653063310b30090603550406130255533121301f060355040a131854686520476f2044616464792047726f75702c20496e632e3131302f060355040b1328476f20446164647920436c61737320322043657274696669636174696f6e20417574686f72697479820100300c0603551d13040530030101ff300d06092a864886f70d01010505000382010100324bf3b2ca3e91fc12c6a1078c8e77a03306145c901e18f708a63d0a19f98780116e69e4961730ff3491637238eecc1c01a31d9428a431f67ac454d7f6e5315803a2ccce62db944573b5bf45c924b5d58202ad2379698db8b64dcecf4cca3323e81c88aa9d8b416e16c920e5899ecd3bda70f77e992620145425ab6e7385e69b219d0a6c820ea8f8c20cfa101e6c96ef870dc40f618badee832b95f88e92847239eb20ea83ed83cd976e08bceb4e26b6732be4d3f64cfe2671e26111744aff571a870f75482ecf516917a002126195d5d140b2104ceec4ac1043a6a59e0ad595629a0dcf8882c5320ce42b9f45e60d9f289cb1b92a5a57ad370faf1d7fdbbd9f2285020a0474657374121f0894d818121976a9142d89a9720d0aca9beaae478994a06b1ab178186788ac18f3f2caa80520f7f9caa8052a505061796d656e74207265717565737420666f722042697450617920696e766f69636520436962454a4a74473174394837374b6d4d363145327420666f72206d65726368616e742074657374436f706179323068747470733a2f2f746573742e6269747061792e636f6d2f692f436962454a4a74473174394837374b6d4d36314532743a4c7b22696e766f6963654964223a22436962454a4a74473174394837374b6d4d3631453274222c226d65726368616e744964223a22444766754344656f66556e576a446d5537454c634568227d2a8002c7146109dfd2584b905627f13e79fe96cc390de6d9729f1263be9ded44f907cc185a1968b71d1b99f073671e288ff51be93493dc2b0cbd7a9de761692bbb143c117aa24961c64e3add6a35b67b48da73c6c740024665494c28cd80d6bbf99ab98d9cee87a6bf826666990d51791d87978cbefd132679851c19962c0ba364913786ec6c9706989c0b4e257d1313cd635822569babff5e58e41f4f94add69efc5ed2850fc1c87cac0487ef3678d02b92459e04666f0e2d3e530502c0623768cd741262fcdf696817ffecb93917152a16a701d21f0a257302d2596f3c86b3fa296450662a11fdd857c40e6bb50cfad4e65cf647eb65541a617661c69da903c54bf6'; var payProData = { verified: true, @@ -91,7 +98,107 @@ var payProData = { merchant_data: '{"invoiceId":"CibEJJtG1t9H77KmM61E2t","merchantId":"DGfuCDeofUnWjDmU7ELcEh"}', }; -var payAck = [10, 0, 18, 95, 84, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 32, 114, 101, 99, 101, 105, 118, 101, 100, 32, 98, 121, 32, 66, 105, 116, 80, 97, 121, 46, 32, 73, 110, 118, 111, 105, 99, 101, 32, 119, 105, 108, 108, 32, 98, 101, 32, 109, 97, 114, 107, 101, 100, 32, 97, 115, 32, 112, 97, 105, 100, 32, 105, 102, 32, 116, 104, 101, 32, 116, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 32, 105, 115, 32, 99, 111, 110, 102, 105, 114, 109, 101, 100, 46]; +var payAck = [ + 10, + 0, + 18, + 95, + 84, + 114, + 97, + 110, + 115, + 97, + 99, + 116, + 105, + 111, + 110, + 32, + 114, + 101, + 99, + 101, + 105, + 118, + 101, + 100, + 32, + 98, + 121, + 32, + 66, + 105, + 116, + 80, + 97, + 121, + 46, + 32, + 73, + 110, + 118, + 111, + 105, + 99, + 101, + 32, + 119, + 105, + 108, + 108, + 32, + 98, + 101, + 32, + 109, + 97, + 114, + 107, + 101, + 100, + 32, + 97, + 115, + 32, + 112, + 97, + 105, + 100, + 32, + 105, + 102, + 32, + 116, + 104, + 101, + 32, + 116, + 114, + 97, + 110, + 115, + 97, + 99, + 116, + 105, + 111, + 110, + 32, + 105, + 115, + 32, + 99, + 111, + 110, + 102, + 105, + 114, + 109, + 101, + 100, + 46, +]; module.exports.history = history; module.exports.payProBuf = new Buffer(payproHex, 'hex'); diff --git a/packages/lightwallet/common/merit-wallet-client/test/utils.js b/packages/lightwallet/common/merit-wallet-client/test/utils.js index 6355dc5329..3e81610809 100644 --- a/packages/lightwallet/common/merit-wallet-client/test/utils.js +++ b/packages/lightwallet/common/merit-wallet-client/test/utils.js @@ -20,18 +20,24 @@ describe('Utils', function() { it('should sign a message', function() { var sig = Utils.signMessage('hola', '09458c090a69a38368975fb68115df2f4b0ab7d1bc463fc60c67aa1730641d6c'); should.exist(sig); - sig.should.equal('3045022100f2e3369dd4813d4d42aa2ed74b5cf8e364a8fa13d43ec541e4bc29525e0564c302205b37a7d1ca73f684f91256806cdad4b320b4ed3000bee2e388bcec106e0280e0'); + sig.should.equal( + '3045022100f2e3369dd4813d4d42aa2ed74b5cf8e364a8fa13d43ec541e4bc29525e0564c302205b37a7d1ca73f684f91256806cdad4b320b4ed3000bee2e388bcec106e0280e0', + ); }); it('should fail to sign with wrong args', function() { (function() { Utils.signMessage('hola', '03bec86ad4a8a91fe7c11ec06af27246ec55094db3d86098b7d8b2f12afe47627f'); - }).should.throw('Number'); + }.should.throw('Number')); }); }); describe('#verifyMessage', function() { it('should fail to verify a malformed signature', function() { - var res = Utils.verifyMessage('hola', 'badsignature', '02555a2d45e309c00cc8c5090b6ec533c6880ab2d3bc970b3943def989b3373f16'); + var res = Utils.verifyMessage( + 'hola', + 'badsignature', + '02555a2d45e309c00cc8c5090b6ec533c6880ab2d3bc970b3943def989b3373f16', + ); should.exist(res); res.should.equal(false); }); @@ -41,12 +47,20 @@ describe('Utils', function() { res.should.equal(false); }); it('should fail to verify with wrong pubkey', function() { - var res = Utils.verifyMessage('hola', '3045022100d6186930e4cd9984e3168e15535e2297988555838ad10126d6c20d4ac0e74eb502201095a6319ea0a0de1f1e5fb50f7bf10b8069de10e0083e23dbbf8de9b8e02785', '02555a2d45e309c00cc8c5090b6ec533c6880ab2d3bc970b3943def989b3373f16'); + var res = Utils.verifyMessage( + 'hola', + '3045022100d6186930e4cd9984e3168e15535e2297988555838ad10126d6c20d4ac0e74eb502201095a6319ea0a0de1f1e5fb50f7bf10b8069de10e0083e23dbbf8de9b8e02785', + '02555a2d45e309c00cc8c5090b6ec533c6880ab2d3bc970b3943def989b3373f16', + ); should.exist(res); res.should.equal(false); }); it('should verify', function() { - var res = Utils.verifyMessage('hola', '3045022100d6186930e4cd9984e3168e15535e2297988555838ad10126d6c20d4ac0e74eb502201095a6319ea0a0de1f1e5fb50f7bf10b8069de10e0083e23dbbf8de9b8e02785', '03bec86ad4a8a91fe7c11ec06af27246ec55094db3d86098b7d8b2f12afe47627f'); + var res = Utils.verifyMessage( + 'hola', + '3045022100d6186930e4cd9984e3168e15535e2297988555838ad10126d6c20d4ac0e74eb502201095a6319ea0a0de1f1e5fb50f7bf10b8069de10e0083e23dbbf8de9b8e02785', + '03bec86ad4a8a91fe7c11ec06af27246ec55094db3d86098b7d8b2f12afe47627f', + ); should.exist(res); res.should.equal(true); }); @@ -54,115 +68,170 @@ describe('Utils', function() { describe('#formatAmount', function() { it('should successfully format short amount', function() { - var cases = [{ - args: [1, 'bit'], - expected: '0', - }, { - args: [1, 'mrt'], - expected: '0.00', - }, { - args: [400050000, 'mrt'], - expected: '4.0005', - }, { - args: [400000000, 'mrt'], - expected: '4.00', - }, { - args: [49999, 'mrt'], - expected: '0.000499', - }, { - args: [100000000, 'mrt'], - expected: '1.00', - }, { - args: [0, 'bit'], - expected: '0', - }, { - args: [12345678, 'bit'], - expected: '123,456', - }, { - args: [12345678, 'mrt'], - expected: '0.123456', - }, { - args: [12345611, 'mrt'], - expected: '0.123456', - }, { - args: [1234, 'mrt'], - expected: '0.000012', - }, { - args: [1299, 'mrt'], - expected: '0.000012', - }, { - args: [1234567899999, 'mrt'], - expected: '12,345.678999', - }, { - args: [12345678, 'bit', { - thousandsSeparator: '.' - }], - expected: '123.456', - }, { - args: [12345678, 'mrt', { - decimalSeparator: ',' - }], - expected: '0,123456', - }, { - args: [1234567899999, 'mrt', { - thousandsSeparator: ' ', - decimalSeparator: ',' - }], - expected: '12 345,678999', - }, ]; + var cases = [ + { + args: [1, 'bit'], + expected: '0', + }, + { + args: [1, 'mrt'], + expected: '0.00', + }, + { + args: [400050000, 'mrt'], + expected: '4.0005', + }, + { + args: [400000000, 'mrt'], + expected: '4.00', + }, + { + args: [49999, 'mrt'], + expected: '0.000499', + }, + { + args: [100000000, 'mrt'], + expected: '1.00', + }, + { + args: [0, 'bit'], + expected: '0', + }, + { + args: [12345678, 'bit'], + expected: '123,456', + }, + { + args: [12345678, 'mrt'], + expected: '0.123456', + }, + { + args: [12345611, 'mrt'], + expected: '0.123456', + }, + { + args: [1234, 'mrt'], + expected: '0.000012', + }, + { + args: [1299, 'mrt'], + expected: '0.000012', + }, + { + args: [1234567899999, 'mrt'], + expected: '12,345.678999', + }, + { + args: [ + 12345678, + 'bit', + { + thousandsSeparator: '.', + }, + ], + expected: '123.456', + }, + { + args: [ + 12345678, + 'mrt', + { + decimalSeparator: ',', + }, + ], + expected: '0,123456', + }, + { + args: [ + 1234567899999, + 'mrt', + { + thousandsSeparator: ' ', + decimalSeparator: ',', + }, + ], + expected: '12 345,678999', + }, + ]; _.each(cases, function(testCase) { Utils.formatAmount.apply(this, testCase.args).should.equal(testCase.expected); }); }); it('should successfully format full amount', function() { - var cases = [{ - args: [1, 'bit'], - expected: '0.01', - }, { - args: [1, 'mrt'], - expected: '0.00000001', - }, { - args: [0, 'bit'], - expected: '0.00', - }, { - args: [12345678, 'bit'], - expected: '123,456.78', - }, { - args: [12345678, 'mrt'], - expected: '0.12345678', - }, { - args: [1234567, 'mrt'], - expected: '0.01234567', - }, { - args: [12345611, 'mrt'], - expected: '0.12345611', - }, { - args: [1234, 'mrt'], - expected: '0.00001234', - }, { - args: [1299, 'mrt'], - expected: '0.00001299', - }, { - args: [1234567899999, 'mrt'], - expected: '12,345.67899999', - }, { - args: [12345678, 'bit', { - thousandsSeparator: "'" - }], - expected: "123'456.78", - }, { - args: [12345678, 'mrt', { - decimalSeparator: ',' - }], - expected: '0,12345678', - }, { - args: [1234567899999, 'mrt', { - thousandsSeparator: ' ', - decimalSeparator: ',' - }], - expected: '12 345,67899999', - }, ]; + var cases = [ + { + args: [1, 'bit'], + expected: '0.01', + }, + { + args: [1, 'mrt'], + expected: '0.00000001', + }, + { + args: [0, 'bit'], + expected: '0.00', + }, + { + args: [12345678, 'bit'], + expected: '123,456.78', + }, + { + args: [12345678, 'mrt'], + expected: '0.12345678', + }, + { + args: [1234567, 'mrt'], + expected: '0.01234567', + }, + { + args: [12345611, 'mrt'], + expected: '0.12345611', + }, + { + args: [1234, 'mrt'], + expected: '0.00001234', + }, + { + args: [1299, 'mrt'], + expected: '0.00001299', + }, + { + args: [1234567899999, 'mrt'], + expected: '12,345.67899999', + }, + { + args: [ + 12345678, + 'bit', + { + thousandsSeparator: "'", + }, + ], + expected: "123'456.78", + }, + { + args: [ + 12345678, + 'mrt', + { + decimalSeparator: ',', + }, + ], + expected: '0,12345678', + }, + { + args: [ + 1234567899999, + 'mrt', + { + thousandsSeparator: ' ', + decimalSeparator: ',', + }, + ], + expected: '12 345,67899999', + }, + ]; _.each(cases, function(testCase) { testCase.args[2] = testCase.args[2] || {}; @@ -174,15 +243,18 @@ describe('Utils', function() { describe('#signMessage #verifyMessage round trip', function() { it('should sign and verify', function() { - var msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + var msg = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; var sig = Utils.signMessage(msg, '09458c090a69a38368975fb68115df2f4b0ab7d1bc463fc60c67aa1730641d6c'); - Utils.verifyMessage(msg, sig, '03bec86ad4a8a91fe7c11ec06af27246ec55094db3d86098b7d8b2f12afe47627f').should.equal(true); + Utils.verifyMessage(msg, sig, '03bec86ad4a8a91fe7c11ec06af27246ec55094db3d86098b7d8b2f12afe47627f').should.equal( + true, + ); }); }); describe('#encryptMessage #decryptMessage round trip', function() { it('should encrypt and decrypt', function() { - var pwd = "ezDRS2NRchMJLf1IWtjL5A=="; + var pwd = 'ezDRS2NRchMJLf1IWtjL5A=='; var ct = Utils.encryptMessage('hello world', pwd); var msg = Utils.decryptMessage(ct, pwd); msg.should.equal('hello world'); @@ -202,7 +274,7 @@ describe('Utils', function() { amount: 1234, message: { one: 'one', - two: 'two' + two: 'two', }, }; @@ -212,7 +284,7 @@ describe('Utils', function() { version: '1.0', message: { two: 'two', - one: 'one' + one: 'one', }, amount: 1234, }; @@ -226,15 +298,13 @@ describe('Utils', function() { describe('#privateKeyToAESKey', function() { it('should be ok', function() { - var privKey = new Meritcore.PrivateKey('09458c090a69a38368975fb68115df2f4b0ab7d1bc463fc60c67aa1730641d6c').toString(); + var privKey = new Meritcore.PrivateKey( + '09458c090a69a38368975fb68115df2f4b0ab7d1bc463fc60c67aa1730641d6c', + ).toString(); Utils.privateKeyToAESKey(privKey).should.be.equal('2HvmUYBSD0gXLea6z0n7EQ=='); }); it('should fail if pk has invalid values', function() { - var values = [ - null, - 123, - '123', - ]; + var values = [null, 123, '123']; _.each(values, function(value) { var valid = true; try { @@ -249,11 +319,10 @@ describe('Utils', function() { describe('#verifyRequestPubKey', function() { it('should generate and check request pub key', function() { - var reqPubKey = (new Meritcore.PrivateKey).toPublicKey(); + var reqPubKey = new Meritcore.PrivateKey().toPublicKey(); var xPrivKey = new Meritcore.HDPrivateKey(); var xPubKey = new Meritcore.HDPublicKey(xPrivKey); - var sig = Utils.signRequestPubKey(reqPubKey.toString(), xPrivKey); var valid = Utils.verifyRequestPubKey(reqPubKey.toString(), sig, xPubKey); valid.should.be.equal(true); diff --git a/packages/lightwallet/common/models/display-wallet.ts b/packages/lightwallet/common/models/display-wallet.ts index 73ff210d34..96a179da34 100644 --- a/packages/lightwallet/common/models/display-wallet.ts +++ b/packages/lightwallet/common/models/display-wallet.ts @@ -19,32 +19,46 @@ export interface IDisplayWalletOptions { export function ClientProperty(target: DisplayWallet, key: keyof MeritWalletClient) { Object.defineProperty(target, key, { enumerable: true, - get: function () { + get: function() { return this.client[key]; }, - set: function (value: any) { + set: function(value: any) { this.client[key] = value; - } + }, }); } const MINIMAL_STAKE = 2000000000; export class DisplayWallet { - @ClientProperty readonly id: string; - @ClientProperty readonly locked: boolean; - @ClientProperty name: string; - @ClientProperty color: string; - @ClientProperty totalNetworkValue: number; - @ClientProperty credentials: any; - @ClientProperty network: string; - @ClientProperty status: any; - @ClientProperty balanceHidden: boolean; - @ClientProperty balance: any; - @ClientProperty availableInvites: number; - @ClientProperty pendingInvites: number; - @ClientProperty sendableInvites: number; - @ClientProperty confirmed: boolean; + @ClientProperty + readonly id: string; + @ClientProperty + readonly locked: boolean; + @ClientProperty + name: string; + @ClientProperty + color: string; + @ClientProperty + totalNetworkValue: number; + @ClientProperty + credentials: any; + @ClientProperty + network: string; + @ClientProperty + status: any; + @ClientProperty + balanceHidden: boolean; + @ClientProperty + balance: any; + @ClientProperty + availableInvites: number; + @ClientProperty + pendingInvites: number; + @ClientProperty + sendableInvites: number; + @ClientProperty + confirmed: boolean; referrerAddress: string; alias: string; @@ -72,11 +86,13 @@ export class DisplayWallet { communitySize: number = 0; - constructor(public client: MeritWalletClient, + constructor( + public client: MeritWalletClient, private walletService: WalletService, private addressService: AddressService, private txFormatService?: TxFormatService, - private persistenceService2?: PersistenceService2) { + private persistenceService2?: PersistenceService2, + ) { this.client = client; this.walletService = walletService; this.txFormatService = txFormatService; @@ -94,7 +110,7 @@ export class DisplayWallet { id: this.id, name: this.name, color: this.color, - balanceHidden: this.balanceHidden + balanceHidden: this.balanceHidden, }; } @@ -124,11 +140,10 @@ export class DisplayWallet { async updateStatus() { this.client.status = await this.client.getStatus(); - let visitedInvites = await this.persistenceService2.getVisitedInvites() || []; + let visitedInvites = (await this.persistenceService2.getVisitedInvites()) || []; this.inviteRequests = (await this.client.getUnlockRequests()) .filter((request: IUnlockRequest) => !request.isConfirmed) .map((request: IUnlockRequest) => { - request.walletClient = this.client; request.isNew = visitedInvites.findIndex(rId => rId === request.rId) === -1; @@ -156,8 +171,13 @@ export class DisplayWallet { private formatNetworkInfo() { if (!isNil(this.totalNetworkValueMicro)) { - this.totalNetworkValueMerit = this.txFormatService.parseAmount(this.totalNetworkValueMicro, 'micros').amountUnitStr; - this.totalNetworkValueFiat = new FiatAmount(+this.txFormatService.formatToUSD(this.totalNetworkValueMicro)).amountStr; + this.totalNetworkValueMerit = this.txFormatService.parseAmount( + this.totalNetworkValueMicro, + 'micros', + ).amountUnitStr; + this.totalNetworkValueFiat = new FiatAmount( + +this.txFormatService.formatToUSD(this.totalNetworkValueMicro), + ).amountStr; } if (!isNil(this.miningRewardsMicro)) { @@ -172,23 +192,26 @@ export class DisplayWallet { } } -export async function createDisplayWallet(wallet: MeritWalletClient, walletService: WalletService, addressService?: AddressService, txFormatService?: TxFormatService, persistenceService2?: PersistenceService2, options: IDisplayWalletOptions = {}): Promise { +export async function createDisplayWallet( + wallet: MeritWalletClient, + walletService: WalletService, + addressService?: AddressService, + txFormatService?: TxFormatService, + persistenceService2?: PersistenceService2, + options: IDisplayWalletOptions = {}, +): Promise { const displayWallet = new DisplayWallet(wallet, walletService, addressService, txFormatService, persistenceService2); return updateDisplayWallet(displayWallet, options); } export async function updateDisplayWallet(displayWallet: DisplayWallet, options: IDisplayWalletOptions) { - if (!options.skipAlias) - await displayWallet.updateAlias(); + if (!options.skipAlias) await displayWallet.updateAlias(); - if (!options.skipStatus) - await displayWallet.updateStatus(); + if (!options.skipStatus) await displayWallet.updateStatus(); - if (!options.skipRewards) - await displayWallet.updateRewards(); + if (!options.skipRewards) await displayWallet.updateRewards(); - if (!options.skipShareCode) - await displayWallet.updateShareCode(); + if (!options.skipShareCode) await displayWallet.updateShareCode(); return displayWallet; } diff --git a/packages/lightwallet/common/models/easy-receipt.ts b/packages/lightwallet/common/models/easy-receipt.ts index 383d511f64..265afd5890 100644 --- a/packages/lightwallet/common/models/easy-receipt.ts +++ b/packages/lightwallet/common/models/easy-receipt.ts @@ -16,19 +16,14 @@ export class EasyReceipt { // TODO: Actually validate that the sizes/shapes of the parameters are correct. isValid() { - return ( - this.parentAddress - && this.senderPublicKey - && this.secret - && this.blockTimeout - ); + return this.parentAddress && this.senderPublicKey && this.secret && this.blockTimeout; } } export interface EasyReceiptTxData { found: true; txid: string; - index: number + index: number; amount: number; spending: boolean; spent: boolean; diff --git a/packages/lightwallet/common/models/easy-send.ts b/packages/lightwallet/common/models/easy-send.ts index 77aca4e6bd..8e00ef54ff 100644 --- a/packages/lightwallet/common/models/easy-send.ts +++ b/packages/lightwallet/common/models/easy-send.ts @@ -16,10 +16,12 @@ export interface EasySend { } export const getEasySendURL = (es: EasySend): string => { - return ENV.easyUrl + + return ( + ENV.easyUrl + `?se=${es.secret}` + `&sk=${es.senderPubKey}` + `&sn=${es.senderName}` + `&bt=${es.blockTimeout}` + - `&pa=${es.parentAddress}`; + `&pa=${es.parentAddress}` + ); }; diff --git a/packages/lightwallet/common/models/fiat-amount.ts b/packages/lightwallet/common/models/fiat-amount.ts index d3ebd33417..c209de5826 100644 --- a/packages/lightwallet/common/models/fiat-amount.ts +++ b/packages/lightwallet/common/models/fiat-amount.ts @@ -1,11 +1,10 @@ import * as _ from 'lodash'; export class FiatAmount { - formats: { - CURRENCY_SYM: string, - DECIMAL_SEP: string, - GROUP_SEP: string + CURRENCY_SYM: string; + DECIMAL_SEP: string; + GROUP_SEP: string; }; amount: number; amountStr: string; @@ -14,7 +13,7 @@ export class FiatAmount { this.formats = { CURRENCY_SYM: '$', DECIMAL_SEP: '.', - GROUP_SEP: ',' + GROUP_SEP: ',', }; this.amount = this.formatFiatAmount(amount); this.amountStr = this.formatAmountStr(amount); @@ -65,5 +64,4 @@ export class FiatAmount { return formatter.format(this.formatFiatAmount(amount)); } - } diff --git a/packages/lightwallet/common/models/merit-contact.ts b/packages/lightwallet/common/models/merit-contact.ts index f657e29696..390f5f0b91 100644 --- a/packages/lightwallet/common/models/merit-contact.ts +++ b/packages/lightwallet/common/models/merit-contact.ts @@ -6,13 +6,12 @@ export interface IAddressBook { } export interface IMeritAddress { - network: string, - address: string, - alias?: string + network: string; + address: string; + alias?: string; } export class MeritContact implements IContactProperties { - id: string; name: IContactName = { formatted: '' }; phoneNumbers: IContactField[] = []; @@ -25,7 +24,7 @@ export class MeritContact implements IContactProperties { if (!this.name) return false; if (!this.meritAddresses.length) return false; let isValid = true; - this.meritAddresses.forEach((address) => { + this.meritAddresses.forEach(address => { if (!address.network) { isValid = false; } else { @@ -36,13 +35,11 @@ export class MeritContact implements IContactProperties { } formatAddress() { - this.meritAddresses.forEach((val) => { + this.meritAddresses.forEach(val => { if (val.address.indexOf('merit:') == 0) val.address = val.address.split(':')[1]; try { val.network = Address.fromString(val.address).network.name; - } catch (e) { - } + } catch (e) {} }); } - } diff --git a/packages/lightwallet/common/models/send-method.ts b/packages/lightwallet/common/models/send-method.ts index 3819d88c73..56400b14ed 100644 --- a/packages/lightwallet/common/models/send-method.ts +++ b/packages/lightwallet/common/models/send-method.ts @@ -1,12 +1,12 @@ export enum SendMethodType { Easy = 'easy', - Classic = 'classic' + Classic = 'classic', } export enum SendMethodDestination { Sms = 'sms', Email = 'email', - Address = 'address' + Address = 'address', } export interface ISendMethod { diff --git a/packages/lightwallet/common/models/sms-subscription.ts b/packages/lightwallet/common/models/sms-subscription.ts index 0478746156..2d2bc7de91 100644 --- a/packages/lightwallet/common/models/sms-subscription.ts +++ b/packages/lightwallet/common/models/sms-subscription.ts @@ -6,9 +6,7 @@ export interface ISmsNotificationStatus { settings?: ISmsNotificationSettings; } -export type ISmsNotificationSettings = { - [k in keyof typeof SmsNotificationSetting]?: boolean; -}; +export type ISmsNotificationSettings = { [k in keyof typeof SmsNotificationSetting]?: boolean }; export enum SmsNotificationSetting { IncomingTx = 'IncomingTx', diff --git a/packages/lightwallet/common/models/transaction-proposal.ts b/packages/lightwallet/common/models/transaction-proposal.ts index 8a0cef685f..134c8a23c7 100644 --- a/packages/lightwallet/common/models/transaction-proposal.ts +++ b/packages/lightwallet/common/models/transaction-proposal.ts @@ -24,4 +24,3 @@ export interface TransactionProposal { toColor?: string; usingCustomFee?: boolean; } - diff --git a/packages/lightwallet/common/models/transaction.ts b/packages/lightwallet/common/models/transaction.ts index fa52296d60..9431753719 100644 --- a/packages/lightwallet/common/models/transaction.ts +++ b/packages/lightwallet/common/models/transaction.ts @@ -1,7 +1,7 @@ import { EasySend } from '@merit/common/models/easy-send'; import { MeritContact } from './merit-contact'; import { DisplayWallet } from './display-wallet'; -import { MeritWalletClient } from "@merit/common/merit-wallet-client/index"; +import { MeritWalletClient } from '@merit/common/merit-wallet-client/index'; export enum TransactionAction { RECEIVED = 'received', @@ -18,7 +18,7 @@ export enum TransactionAction { export enum UnlockRequestStatus { ACCEPTED = 'accepted', DECLINED = 'declined', - PENDING = 'pending' + PENDING = 'pending', } export interface ITransactionIO { @@ -65,8 +65,8 @@ export interface IDisplayTransaction extends ITransaction { safeConfirmed?: string; contact?: MeritContact; feeStr: string; - to: { alias: string; address: string; }; - from: { alias: string; address: string; }; + to: { alias: string; address: string }; + from: { alias: string; address: string }; displayWallet?: DisplayWallet; wallet: MeritWalletClient; isMiningReward: boolean; diff --git a/packages/lightwallet/common/models/vault.ts b/packages/lightwallet/common/models/vault.ts index 4cf2a203a8..98ef0600cb 100644 --- a/packages/lightwallet/common/models/vault.ts +++ b/packages/lightwallet/common/models/vault.ts @@ -1,15 +1,13 @@ import { MeritWalletClient } from '@merit/common/merit-wallet-client'; export interface IVault { - _id: string; - name: string; + name: string; amount: number; address: string; coins: Array; masterPubKey: any; status: string; - whitelist: Array<{address: string, alias: string}>; + whitelist: Array<{ address: string; alias: string }>; walletClient: MeritWalletClient; - } diff --git a/packages/lightwallet/common/pipes/address-error-message.pipe.ts b/packages/lightwallet/common/pipes/address-error-message.pipe.ts index 8062bedcbb..ce83c08902 100644 --- a/packages/lightwallet/common/pipes/address-error-message.pipe.ts +++ b/packages/lightwallet/common/pipes/address-error-message.pipe.ts @@ -1,23 +1,19 @@ import { Pipe } from '@angular/core'; @Pipe({ - name: 'addressErrorMessage' + name: 'addressErrorMessage', }) export class AddressErrorMessagePipe { transform(value: any) { if (!value) return; - if (value.required) - return 'Address or alias is required'; + if (value.required) return 'Address or alias is required'; - if (value.minlength) - return 'Address or alias must be at least 3 characters long'; + if (value.minlength) return 'Address or alias must be at least 3 characters long'; - if (value.InvalidFormat) - return 'Invalid address format'; + if (value.InvalidFormat) return 'Invalid address format'; - if (value.AddressNotFound) - return 'Address or alias not found'; + if (value.AddressNotFound) return 'Address or alias not found'; console.error('Unhandled address error: ', value); return 'Unknown error'; diff --git a/packages/lightwallet/common/pipes/address.pipe.spec.ts b/packages/lightwallet/common/pipes/address.pipe.spec.ts index 18376cab6e..867ab29fe2 100644 --- a/packages/lightwallet/common/pipes/address.pipe.spec.ts +++ b/packages/lightwallet/common/pipes/address.pipe.spec.ts @@ -12,27 +12,27 @@ const ALIAS = 'ibby-demo-mac';
{{ 'mNAxzEYp7HcQCdMqstzftS548SSYx5PvWd' | address:5:true }}
{{ 'ibby-demo-mac' | address }}
{{ '@ibby-demo-mac' | address }}
- ` + `, }) class TestComponent { - @ViewChild('test1') test1: ElementRef; - @ViewChild('test2') test2: ElementRef; - @ViewChild('test3') test3: ElementRef; - @ViewChild('test4') test4: ElementRef; - @ViewChild('test5') test5: ElementRef; + @ViewChild('test1') + test1: ElementRef; + @ViewChild('test2') + test2: ElementRef; + @ViewChild('test3') + test3: ElementRef; + @ViewChild('test4') + test4: ElementRef; + @ViewChild('test5') + test5: ElementRef; } describe('Pipes.Address', () => { - - let comp: TestComponent, - instance: ComponentFixture; + let comp: TestComponent, instance: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - AddressPipe, - TestComponent - ] + declarations: [AddressPipe, TestComponent], }).compileComponents(); instance = TestBed.createComponent(TestComponent); comp = instance.componentInstance; diff --git a/packages/lightwallet/common/pipes/address.pipe.ts b/packages/lightwallet/common/pipes/address.pipe.ts index 8d2c48ff0f..c50232d6c7 100644 --- a/packages/lightwallet/common/pipes/address.pipe.ts +++ b/packages/lightwallet/common/pipes/address.pipe.ts @@ -2,7 +2,7 @@ import { Pipe } from '@angular/core'; import { cleanAddress, isAddress, isAlias } from '@merit/common/utils/addresses'; @Pipe({ - name: 'address' + name: 'address', }) export class AddressPipe { transform(value: string, maxAddressLength?: number, showEllipsis?: boolean) { diff --git a/packages/lightwallet/common/pipes/alias-error-message.pipe.ts b/packages/lightwallet/common/pipes/alias-error-message.pipe.ts index ff7a8d76c6..8cfbcfeb1b 100644 --- a/packages/lightwallet/common/pipes/alias-error-message.pipe.ts +++ b/packages/lightwallet/common/pipes/alias-error-message.pipe.ts @@ -1,23 +1,19 @@ import { Pipe } from '@angular/core'; @Pipe({ - name: 'aliasErrorMessage' + name: 'aliasErrorMessage', }) export class AliasErrorMessagePipe { transform(value: any) { if (!value) return; - if (value.required) - return 'Alias is required'; + if (value.required) return 'Alias is required'; - if (value.minlength) - return 'Alias must be at least 3 characters long'; + if (value.minlength) return 'Alias must be at least 3 characters long'; - if (value.InvalidFormat) - return 'Invalid alias format'; + if (value.InvalidFormat) return 'Invalid alias format'; - if (value.AliasInUse) - return 'Alias is already in use'; + if (value.AliasInUse) return 'Alias is already in use'; console.error('Unhandled alias error: ', value); return 'Unknown error'; diff --git a/packages/lightwallet/common/pipes/chunks.pipe.ts b/packages/lightwallet/common/pipes/chunks.pipe.ts index 884ce9a04a..55fe4b9451 100644 --- a/packages/lightwallet/common/pipes/chunks.pipe.ts +++ b/packages/lightwallet/common/pipes/chunks.pipe.ts @@ -3,6 +3,9 @@ import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'chunks' }) export class ChunksPipe implements PipeTransform { transform(arr: any, chunkSize: number) { - return arr.reduce((prev, cur, index) => (index % chunkSize) ? prev : prev.concat([arr.slice(index, index + chunkSize)]), []); + return arr.reduce( + (prev, cur, index) => (index % chunkSize ? prev : prev.concat([arr.slice(index, index + chunkSize)])), + [], + ); } } diff --git a/packages/lightwallet/common/pipes/to-fiat.pipe.ts b/packages/lightwallet/common/pipes/to-fiat.pipe.ts index 707ceb63bf..9b51ebbbd6 100644 --- a/packages/lightwallet/common/pipes/to-fiat.pipe.ts +++ b/packages/lightwallet/common/pipes/to-fiat.pipe.ts @@ -3,11 +3,7 @@ import { TxFormatService } from '@merit/common/services/tx-format.service'; @Pipe({ name: 'toFiat' }) export class ToFiatPipe implements PipeTransform { - - constructor( - private txFormatProvider: TxFormatService - ) { - } + constructor(private txFormatProvider: TxFormatService) {} transform(value: string, micros: number): string { return this.txFormatProvider.formatAlternativeStr(micros); diff --git a/packages/lightwallet/common/pipes/to-mrt.pipe.spec.ts b/packages/lightwallet/common/pipes/to-mrt.pipe.spec.ts index 053478cace..5ce50f1292 100644 --- a/packages/lightwallet/common/pipes/to-mrt.pipe.spec.ts +++ b/packages/lightwallet/common/pipes/to-mrt.pipe.spec.ts @@ -9,27 +9,26 @@ import { RateService } from '@merit/common/services/rate.service';
{{ 123e6 | toMRT:null:true }}
{{ 123e6 | toMRT:1 }}
{{ 123e6 | toMRT:2 }}
- ` + `, }) class TestComponent { - @ViewChild('test1') test1: ElementRef; - @ViewChild('test2') test2: ElementRef; - @ViewChild('test3') test3: ElementRef; - @ViewChild('test4') test4: ElementRef; + @ViewChild('test1') + test1: ElementRef; + @ViewChild('test2') + test2: ElementRef; + @ViewChild('test3') + test3: ElementRef; + @ViewChild('test4') + test4: ElementRef; } describe('Pipes.ToMRT', () => { - - let comp: TestComponent, - instance: ComponentFixture; + let comp: TestComponent, instance: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - ToMrtPipe, - TestComponent - ], - providers: [RateService] + declarations: [ToMrtPipe, TestComponent], + providers: [RateService], }).compileComponents(); instance = TestBed.createComponent(TestComponent); comp = instance.componentInstance; diff --git a/packages/lightwallet/common/pipes/to-mrt.pipe.ts b/packages/lightwallet/common/pipes/to-mrt.pipe.ts index 31e75f5a99..0886335956 100644 --- a/packages/lightwallet/common/pipes/to-mrt.pipe.ts +++ b/packages/lightwallet/common/pipes/to-mrt.pipe.ts @@ -6,17 +6,15 @@ export class ToMrtPipe implements PipeTransform { constructor(private rateService: RateService) {} transform(micros: number, digitsLimit?: number, hideUnit?: boolean): string { - - const unitStr = (hideUnit? '' : ' MRT'); + const unitStr = hideUnit ? '' : ' MRT'; let mrt = this.rateService.microsToMrt(micros) || 0; - if (!digitsLimit) return mrt+unitStr; + if (!digitsLimit) return mrt + unitStr; const intLength = mrt.toFixed(0).length; - let floatLength = (digitsLimit - intLength) >= 0 ? (digitsLimit - intLength) : 0; - - return Number(mrt.toFixed(floatLength))+unitStr; + let floatLength = digitsLimit - intLength >= 0 ? digitsLimit - intLength : 0; + return Number(mrt.toFixed(floatLength)) + unitStr; } } diff --git a/packages/lightwallet/common/pipes/to-unit.pipe.spec.ts b/packages/lightwallet/common/pipes/to-unit.pipe.spec.ts index b28149f9a0..2e7fcbec5e 100644 --- a/packages/lightwallet/common/pipes/to-unit.pipe.spec.ts +++ b/packages/lightwallet/common/pipes/to-unit.pipe.spec.ts @@ -9,28 +9,24 @@ import { EventsMock, StorageMock } from 'ionic-mocks-jest'; @Component({ template: `
{{ 1e8 | toUnit }}
- ` + `, }) class TestComponent { - @ViewChild('test1') test1: ElementRef; + @ViewChild('test1') + test1: ElementRef; } describe('Pipes.ToUnit', () => { - - let comp: TestComponent, - instance: ComponentFixture; + let comp: TestComponent, instance: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - ToUnitPipe, - TestComponent - ], + declarations: [ToUnitPipe, TestComponent], imports: [CommonProvidersModule.forRoot()], providers: [ { provide: Storage, useFactory: () => StorageMock.instance() }, - { provide: Events, useFactory: () => EventsMock.instance() } - ] + { provide: Events, useFactory: () => EventsMock.instance() }, + ], }).compileComponents(); instance = TestBed.createComponent(TestComponent); comp = instance.componentInstance; diff --git a/packages/lightwallet/common/pipes/to-unit.pipe.ts b/packages/lightwallet/common/pipes/to-unit.pipe.ts index f3a13ae7ea..1f4efe2157 100644 --- a/packages/lightwallet/common/pipes/to-unit.pipe.ts +++ b/packages/lightwallet/common/pipes/to-unit.pipe.ts @@ -6,8 +6,7 @@ import { TxFormatService } from '@merit/common/services/tx-format.service'; export class ToUnitPipe implements PipeTransform { private unitCode: string; - constructor(private configProvider: ConfigService, - private txFormatProvider: TxFormatService) { + constructor(private configProvider: ConfigService, private txFormatProvider: TxFormatService) { this.unitCode = this.configProvider.get().wallet.settings.unitCode; } diff --git a/packages/lightwallet/common/pipes/unescape.pipe.spec.ts b/packages/lightwallet/common/pipes/unescape.pipe.spec.ts index cbbe7e3863..4712e192c9 100644 --- a/packages/lightwallet/common/pipes/unescape.pipe.spec.ts +++ b/packages/lightwallet/common/pipes/unescape.pipe.spec.ts @@ -5,23 +5,19 @@ import { UnescapePipe } from '@merit/common/pipes/unescape.pipe'; @Component({ template: `
{{ '%40' | unescape }}
- ` + `, }) class TestComponent { - @ViewChild('test1') test1: ElementRef; + @ViewChild('test1') + test1: ElementRef; } describe('Pipes.Unescape', () => { - - let comp: TestComponent, - instance: ComponentFixture; + let comp: TestComponent, instance: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - UnescapePipe, - TestComponent - ] + declarations: [UnescapePipe, TestComponent], }).compileComponents(); instance = TestBed.createComponent(TestComponent); comp = instance.componentInstance; diff --git a/packages/lightwallet/common/pipes/unescape.pipe.ts b/packages/lightwallet/common/pipes/unescape.pipe.ts index dbb3409790..681e51bc93 100644 --- a/packages/lightwallet/common/pipes/unescape.pipe.ts +++ b/packages/lightwallet/common/pipes/unescape.pipe.ts @@ -4,7 +4,7 @@ import { Pipe, PipeTransform } from '@angular/core'; export class UnescapePipe implements PipeTransform { transform(value: any, args?: any): any { const unescapedStr = decodeURIComponent(value); //Belt-and-suspenders check for an "@" at the beginning of the alias - if (unescapedStr.length > 0 && unescapedStr.charAt(0) != ('@')) { + if (unescapedStr.length > 0 && unescapedStr.charAt(0) != '@') { return '@'.concat(unescapedStr); } return unescapedStr; diff --git a/packages/lightwallet/common/reducers/app.reducer.ts b/packages/lightwallet/common/reducers/app.reducer.ts index c2ffe781d1..9c42ca84ad 100644 --- a/packages/lightwallet/common/reducers/app.reducer.ts +++ b/packages/lightwallet/common/reducers/app.reducer.ts @@ -8,11 +8,11 @@ export interface IAppState { const INITIAL_STATE: IAppState = { loading: true, - authorized: false + authorized: false, }; export enum AppReducerActionType { - UPDATE = '[App] Update' + UPDATE = '[App] Update', } export class UpdateAppAction implements Action { @@ -27,10 +27,11 @@ export function appReducer(state: IAppState = INITIAL_STATE, action: AppReducerA case AppReducerActionType.UPDATE: return { ...state, - ...action.payload + ...action.payload, }; - default: return state; + default: + return state; } } diff --git a/packages/lightwallet/common/reducers/notifications.reducer.ts b/packages/lightwallet/common/reducers/notifications.reducer.ts index a80a8c1680..45720f3e8e 100644 --- a/packages/lightwallet/common/reducers/notifications.reducer.ts +++ b/packages/lightwallet/common/reducers/notifications.reducer.ts @@ -31,7 +31,7 @@ export enum NotificationsActionType { Clear = '[Notifications] Clear', Load = '[Notifications] Load', Save = '[Notifications] Save', - MarkAllAsRead = '[Notifications] Mark all as read' + MarkAllAsRead = '[Notifications] Mark all as read', } export class LoadNotificationsAction implements Action { @@ -51,8 +51,7 @@ export class SaveNotificationsAction implements Action { export class UpdateNotificationsAction implements Action { type = NotificationsActionType.Update; - constructor(public notifications: INotification[]) { - } + constructor(public notifications: INotification[]) {} } /** @@ -74,8 +73,7 @@ export class AddNotificationAction implements Action { export class MarkNotificationAsReadAction implements Action { type = NotificationsActionType.MarkAsRead; - constructor(public notificationId: string) { - } + constructor(public notificationId: string) {} } /** @@ -84,8 +82,7 @@ export class MarkNotificationAsReadAction implements Action { export class DeleteNotificationAction implements Action { type = NotificationsActionType.Delete; - constructor(public notificationId: string) { - } + constructor(public notificationId: string) {} } /** @@ -99,26 +96,18 @@ export class MarkAllNotificationsAsReadAction implements Action { type = NotificationsActionType.MarkAllAsRead; } -export type NotificationAction = - UpdateNotificationsAction - & AddNotificationAction - & MarkNotificationAsReadAction - & DeleteNotificationAction - & ClearNotificationsAction; +export type NotificationAction = UpdateNotificationsAction & + AddNotificationAction & + MarkNotificationAsReadAction & + DeleteNotificationAction & + ClearNotificationsAction; export function calculateUnreadNotifications(notifications: INotification[]): number { return notifications.reduce((total: number, notification: INotification) => total + Number(!notification.read), 0); } export function processNotifications(notifications: INotification[]): INotification[] { - return sortBy( - uniq( - compact( - notifications.map(formatNotification) - ) - ), - 'timestamp' - ).reverse(); + return sortBy(uniq(compact(notifications.map(formatNotification))), 'timestamp').reverse(); } export function formatNotification(notification: INotification): INotification { @@ -126,7 +115,10 @@ export function formatNotification(notification: INotification): INotification { switch (notification.type) { case 'IncomingTx': notification.title = 'New payment received'; - notification.message = `A payment of ${ formatAmount(notification.amount, 'mrt') }MRT has been received into your wallet.`; + notification.message = `A payment of ${formatAmount( + notification.amount, + 'mrt', + )}MRT has been received into your wallet.`; break; case 'IncomingInvite': @@ -141,7 +133,10 @@ export function formatNotification(notification: INotification): INotification { case 'IncomingCoinbase': notification.title = 'Mining reward received'; - notification.message = `Congratulations! You received a mining reward of ${ formatAmount(notification.amount, 'mrt') }MRT.`; + notification.message = `Congratulations! You received a mining reward of ${formatAmount( + notification.amount, + 'mrt', + )}MRT.`; break; case 'IncomingInviteRequest': @@ -164,29 +159,32 @@ export function formatNotification(notification: INotification): INotification { return notification; } -export function notificationsReducer(state: INotificationsState = { - notifications: [], - totalUnread: 0 -}, action: NotificationAction): INotificationsState { +export function notificationsReducer( + state: INotificationsState = { + notifications: [], + totalUnread: 0, + }, + action: NotificationAction, +): INotificationsState { switch (action.type) { case NotificationsActionType.Update: return { notifications: processNotifications(action.notifications), - totalUnread: calculateUnreadNotifications(action.notifications) + totalUnread: calculateUnreadNotifications(action.notifications), }; case NotificationsActionType.Add: state.notifications.push(action.notification); return { notifications: processNotifications(state.notifications), - totalUnread: state.totalUnread + Number(!action.notification.read) + totalUnread: state.totalUnread + Number(!action.notification.read), }; case NotificationsActionType.MarkAsRead: state.notifications.find((notification: INotification) => notification.id === action.notificationId).read = true; return { notifications: state.notifications, - totalUnread: state.totalUnread - 1 + totalUnread: state.totalUnread - 1, }; case NotificationsActionType.MarkAllAsRead: @@ -195,20 +193,22 @@ export function notificationsReducer(state: INotificationsState = { notification.read = true; return notification; }), - totalUnread: 0 + totalUnread: 0, }; case NotificationsActionType.Delete: - state.notifications = state.notifications.filter((notification: INotification) => notification.id !== action.notificationId); + state.notifications = state.notifications.filter( + (notification: INotification) => notification.id !== action.notificationId, + ); return { notifications: state.notifications, - totalUnread: calculateUnreadNotifications(state.notifications) + totalUnread: calculateUnreadNotifications(state.notifications), }; case NotificationsActionType.Clear: return { notifications: [], - totalUnread: 0 + totalUnread: 0, }; default: diff --git a/packages/lightwallet/common/reducers/transactions.reducer.ts b/packages/lightwallet/common/reducers/transactions.reducer.ts index 64ac4f7d32..ddb5b855c9 100644 --- a/packages/lightwallet/common/reducers/transactions.reducer.ts +++ b/packages/lightwallet/common/reducers/transactions.reducer.ts @@ -11,7 +11,7 @@ export enum TransactionActionType { Update = '[Transactions] Update', UpdateOne = '[Transactions] Update one', Refresh = '[Transactions] Refresh', - RefreshOne = '[Transactions] Refresh one' + RefreshOne = '[Transactions] Refresh one', } export class RefreshTransactionsAction implements Action { @@ -30,8 +30,7 @@ export class UpdateTransactionsAction implements Action { this.transactions.forEach((transaction: IDisplayTransaction) => { walletId = transaction.wallet.id; - if (!this.transactionsByWallet[walletId]) - this.transactionsByWallet[walletId] = []; + if (!this.transactionsByWallet[walletId]) this.transactionsByWallet[walletId] = []; this.transactionsByWallet[walletId].push(transaction); }); @@ -41,56 +40,58 @@ export class UpdateTransactionsAction implements Action { export class UpdateOneWalletTransactions implements Action { type = TransactionActionType.UpdateOne; - constructor(public walletId: string, public transactions: IDisplayTransaction[]) { } + constructor(public walletId: string, public transactions: IDisplayTransaction[]) {} } export class RefreshOneWalletTransactions implements Action { type = TransactionActionType.RefreshOne; - constructor(public walletId: string) { - } + constructor(public walletId: string) {} } -export type TransactionsReducerAction = - RefreshTransactionsAction - & UpdateTransactionsAction - & UpdateOneWalletTransactions - & RefreshOneWalletTransactions; +export type TransactionsReducerAction = RefreshTransactionsAction & + UpdateTransactionsAction & + UpdateOneWalletTransactions & + RefreshOneWalletTransactions; const DEFAULT_STATE: ITransactionsState = { transactions: [], - loading: true + loading: true, }; -export function transactionsReducer(state: ITransactionsState = DEFAULT_STATE, action: TransactionsReducerAction): ITransactionsState { +export function transactionsReducer( + state: ITransactionsState = DEFAULT_STATE, + action: TransactionsReducerAction, +): ITransactionsState { switch (action.type) { case TransactionActionType.Refresh: return { ...state, - loading: true + loading: true, }; case TransactionActionType.Update: return { transactions: action.transactions, - loading: false + loading: false, }; case TransactionActionType.UpdateOne: return { transactions: sortBy(uniqBy(action.transactions.concat(state.transactions), 'txid'), 'time').reverse(), - loading: false + loading: false, }; default: return state; } - - } export const selectTransactionsState = createFeatureSelector('transactions'); export const selectTransactionsLoading = createSelector(selectTransactionsState, state => state.loading); export const selectTransactions = createSelector(selectTransactionsState, state => state.transactions); -export const selectSentInvites = createSelector(selectTransactions, (transactions: IDisplayTransaction[]) => transactions.filter(transaction => transaction.action === TransactionAction.SENT && transaction.isInvite)); -export const selectTransactionsByWalletId = (id: string) => createSelector(selectTransactionsState, state => state.transactions.filter(tx => tx.walletId === id)); +export const selectSentInvites = createSelector(selectTransactions, (transactions: IDisplayTransaction[]) => + transactions.filter(transaction => transaction.action === TransactionAction.SENT && transaction.isInvite), +); +export const selectTransactionsByWalletId = (id: string) => + createSelector(selectTransactionsState, state => state.transactions.filter(tx => tx.walletId === id)); diff --git a/packages/lightwallet/common/reducers/wallets.reducer.ts b/packages/lightwallet/common/reducers/wallets.reducer.ts index ef6fec5606..5b88f5c0de 100644 --- a/packages/lightwallet/common/reducers/wallets.reducer.ts +++ b/packages/lightwallet/common/reducers/wallets.reducer.ts @@ -4,7 +4,7 @@ import { Action, createFeatureSelector, createSelector } from '@ngrx/store'; export interface IWalletsState { wallets: DisplayWallet[]; - walletsMap: { [walletId: string]: DisplayWallet; }; + walletsMap: { [walletId: string]: DisplayWallet }; loading: boolean; totals: IWalletTotals; totalsLoading: boolean; @@ -33,11 +33,11 @@ const DEFAULT_STATE: IWalletsState = { totalWalletsBalanceFiat: '0.00', allBalancesHidden: false, totalCommunitySize: 0, - invites: 0 + invites: 0, }, loading: true, totalsLoading: true, - inviteRequests: [] + inviteRequests: [], }; export enum WalletsActionType { @@ -51,14 +51,13 @@ export enum WalletsActionType { UpdateInviteRequests = '[Wallets] Update Invite Wait List', DeleteWallet = '[Wallets] Delete wallet', DeleteWalletCompleted = '[Wallets] Delete wallet completed', - IgnoreInviteRequest = '[Wallets] Ignore invite request' + IgnoreInviteRequest = '[Wallets] Ignore invite request', } export class AddWalletAction implements Action { type = WalletsActionType.Add; - constructor(public wallet: DisplayWallet) { - } + constructor(public wallet: DisplayWallet) {} } export class UpdateWalletsAction implements Action { @@ -67,7 +66,7 @@ export class UpdateWalletsAction implements Action { walletsMap: any = {}; constructor(public payload: DisplayWallet[]) { - payload.forEach(w => this.walletsMap[w.id] = w); + payload.forEach(w => (this.walletsMap[w.id] = w)); } } @@ -114,17 +113,16 @@ export class IgnoreInviteRequestAction implements Action { constructor(public address: string) {} } -export type WalletsAction = - AddWalletAction - & UpdateWalletsAction - & RefreshWalletsAction - & UpdateOneWalletAction - & RefreshOneWalletAction - & UpdateWalletTotalsAction - & UpdateInviteRequestsAction - & DeleteWalletAction - & DeleteWalletCompletedAction - & IgnoreInviteRequestAction; +export type WalletsAction = AddWalletAction & + UpdateWalletsAction & + RefreshWalletsAction & + UpdateOneWalletAction & + RefreshOneWalletAction & + UpdateWalletTotalsAction & + UpdateInviteRequestsAction & + DeleteWalletAction & + DeleteWalletCompletedAction & + IgnoreInviteRequestAction; export function walletsReducer(state: IWalletsState = DEFAULT_STATE, action: WalletsAction) { switch (action.type) { @@ -135,19 +133,16 @@ export function walletsReducer(state: IWalletsState = DEFAULT_STATE, action: Wal loading: false, walletsMap: { ...state.walletsMap, - [newWallet.id]: newWallet + [newWallet.id]: newWallet, }, - wallets: [ - ...state.wallets, - newWallet - ], - totalsLoading: true + wallets: [...state.wallets, newWallet], + totalsLoading: true, }; case WalletsActionType.Refresh: return { ...state, - loading: true + loading: true, }; case WalletsActionType.Update: @@ -155,7 +150,7 @@ export function walletsReducer(state: IWalletsState = DEFAULT_STATE, action: Wal ...state, loading: false, wallets: action.payload, - walletsMap: action.walletsMap + walletsMap: action.walletsMap, }; case WalletsActionType.UpdateOne: @@ -163,33 +158,31 @@ export function walletsReducer(state: IWalletsState = DEFAULT_STATE, action: Wal state.wallets[index] = action.wallet; return { ...state, - wallets: [ - ...state.wallets - ], + wallets: [...state.wallets], loading: false, walletsMap: { ...state.walletsMap, - [action.wallet.id]: action.wallet - } + [action.wallet.id]: action.wallet, + }, }; case WalletsActionType.RefreshTotals: return { ...state, - totalsLoading: true + totalsLoading: true, }; case WalletsActionType.UpdateTotals: return { ...state, totalsLoading: false, - totals: action.totals + totals: action.totals, }; case WalletsActionType.UpdateInviteRequests: return { ...state, - inviteRequests: action.inviteRequests + inviteRequests: action.inviteRequests, }; case WalletsActionType.DeleteWalletCompleted: @@ -198,8 +191,8 @@ export function walletsReducer(state: IWalletsState = DEFAULT_STATE, action: Wal wallets: state.wallets.filter(wallet => wallet.id !== action.walletId), walletsMap: { ...state.walletsMap, - [action.walletId]: undefined - } + [action.walletId]: undefined, + }, }; default: @@ -210,11 +203,15 @@ export function walletsReducer(state: IWalletsState = DEFAULT_STATE, action: Wal export const selectWalletsState = createFeatureSelector('wallets'); export const selectWalletsLoading = createSelector(selectWalletsState, state => state.loading); export const selectWallets = createSelector(selectWalletsState, state => state.wallets); -export const selectConfirmedWallets = createSelector(selectWallets, wallets => wallets.filter((w: DisplayWallet) => w.client.confirmed)); +export const selectConfirmedWallets = createSelector(selectWallets, wallets => + wallets.filter((w: DisplayWallet) => w.client.confirmed), +); export const selectWalletTotals = createSelector(selectWalletsState, state => state.totals); export const selectWalletTotalsLoading = createSelector(selectWalletsState, state => state.totalsLoading); export const selectWalletById = (id: string) => createSelector(selectWalletsState, state => state.walletsMap[id]); -export const selectWalletsWithInvites = createSelector(selectWallets, (wallets: DisplayWallet[]) => wallets.filter(wallet => wallet.availableInvites > 0)); +export const selectWalletsWithInvites = createSelector(selectWallets, (wallets: DisplayWallet[]) => + wallets.filter(wallet => wallet.availableInvites > 0), +); export const selectInvites = createSelector(selectWalletTotals, totals => totals.invites); export const selectInviteRequests = createSelector(selectWalletsState, state => state.inviteRequests); export const selectNumberOfInviteRequests = createSelector(selectInviteRequests, inviteRequests => { diff --git a/packages/lightwallet/common/services/address.service.ts b/packages/lightwallet/common/services/address.service.ts index e3c988eb7a..55762a0acc 100644 --- a/packages/lightwallet/common/services/address.service.ts +++ b/packages/lightwallet/common/services/address.service.ts @@ -19,7 +19,7 @@ export class AddressService { private config: ConfigService, private persistenceService: PersistenceService, private logger: LoggerService, - mwcService: MWCService + mwcService: MWCService, ) { this.client = mwcService.getClient(null); } @@ -60,7 +60,6 @@ export class AddressService { const info = await this.getAddressInfo(addr); return info.isValid && info.isBeaconed; - } async getValidAddress(input: string): Promise { diff --git a/packages/lightwallet/common/services/app-settings.service.ts b/packages/lightwallet/common/services/app-settings.service.ts index d7f484e807..4ca9dcce45 100644 --- a/packages/lightwallet/common/services/app-settings.service.ts +++ b/packages/lightwallet/common/services/app-settings.service.ts @@ -43,10 +43,12 @@ export class AppSettingsService { public info: AppSettings; private jsonPath: string = 'assets/appConfig.json'; - constructor(public http: HttpClient, - private logger: LoggerService, - private language: LanguageService, - private config: ConfigService) { + constructor( + public http: HttpClient, + private logger: LoggerService, + private language: LanguageService, + private config: ConfigService, + ) { this.logger.info('AppService initialized.'); } diff --git a/packages/lightwallet/common/services/config.service.ts b/packages/lightwallet/common/services/config.service.ts index 5e54178e1a..ec03c3858f 100644 --- a/packages/lightwallet/common/services/config.service.ts +++ b/packages/lightwallet/common/services/config.service.ts @@ -34,7 +34,7 @@ export interface IAppConfig { }; copay: { url: string; - } + }; }; rateApp: { @@ -45,7 +45,6 @@ export interface IAppConfig { }; }; - recentTransactions: { enabled: boolean; }; @@ -63,8 +62,8 @@ export interface IAppConfig { }; help: { - url: string - }, + url: string; + }; pushNotificationsEnabled: boolean; @@ -84,14 +83,13 @@ export interface IAppConfig { // Custom Aliases // Stored like: aliasFor[WalletId] = "Full Wallet" aliasFor?: object; - } const configDefault: IAppConfig = { // wallet limits limits: { totalCopayers: 6, - mPlusN: 100 + mPlusN: 100, }, // wallet default config @@ -109,83 +107,82 @@ const configDefault: IAppConfig = { alternativeName: 'US Dollar', alternativeIsoCode: 'USD', defaultLanguage: '', - feeLevel: 'normal' - } + feeLevel: 'normal', + }, }, download: { bitpay: { - url: 'https://merit.me/wallet' + url: 'https://merit.me/wallet', }, copay: { - url: 'https://merit.me/#download' - } + url: 'https://merit.me/#download', + }, }, rateApp: { lightwallet: { ios: 'http://coming.soon', android: 'http://coming.soon', - wp: '' - } + wp: '', + }, }, // External services recentTransactions: { - enabled: true + enabled: true, }, hideNextSteps: { - enabled: false + enabled: false, }, rates: { - url: 'https://insight.merit.me:443/api/rates' + url: 'https://insight.merit.me:443/api/rates', }, release: { - url: 'https://api.github.com/repos/meritlabs/lightwallet-stack/releases/latest' + url: 'https://api.github.com/repos/meritlabs/lightwallet-stack/releases/latest', }, help: { - url: 'https://help.merit.me' + url: 'https://help.merit.me', }, pushNotificationsEnabled: true, confirmedTxsNotifications: { - enabled: true + enabled: true, }, emailNotifications: { enabled: false, - emailAddress: '' + emailAddress: '', }, log: { - filter: 'debug' - } - + filter: 'debug', + }, }; @Injectable() export class ConfigService { private configCache: IAppConfig = _.clone(configDefault); - constructor(private logger: LoggerService, - private persistence: PersistenceService) { + constructor(private logger: LoggerService, private persistence: PersistenceService) { this.load() .then(() => { this.logger.debug('ConfigService initialized.'); - }).catch(err => { - this.logger.warn('ConfigService could not load default config'); - }); + }) + .catch(err => { + this.logger.warn('ConfigService could not load default config'); + }); } async load(): Promise { try { const config: any = await this.persistence.getConfig(); - this.configCache = _.clone(_.isEmpty(config)? configDefault : config); + this.configCache = _.clone(_.isEmpty(config) ? configDefault : config); } catch (err) { this.logger.error(err); throw err; @@ -215,5 +212,4 @@ export class ConfigService { getDefaults(): IAppConfig { return configDefault; } - } diff --git a/packages/lightwallet/common/services/contacts.service.ts b/packages/lightwallet/common/services/contacts.service.ts index 25606ad8d6..87c0920cad 100644 --- a/packages/lightwallet/common/services/contacts.service.ts +++ b/packages/lightwallet/common/services/contacts.service.ts @@ -8,7 +8,6 @@ import { createMeritContact } from '@merit/common/utils/contacts'; @Injectable() export class ContactsService { - // TODO cache contacts & re-use instead of retrieving them again protected contacts: MeritContact[]; protected addressBook: IAddressBook; @@ -29,7 +28,7 @@ export class ContactsService { contact.meritAddresses.forEach(({ address, alias }) => { if (address) this.addressBook[address] = contact; if (alias) this.addressBook[alias] = contact; - }) + }), ); await this.persistenceService.setAddressbook(ENV.network, this.addressBook); @@ -37,17 +36,16 @@ export class ContactsService { } list(network: string = ENV.network): Promise { - return this.getAddressbook(network) - .catch((err) => { - return Promise.reject(new Error('Error listing addressBook: ' + err)); - }); - }; + return this.getAddressbook(network).catch(err => { + return Promise.reject(new Error('Error listing addressBook: ' + err)); + }); + } async add(entry: MeritContact, address: string, network: string = ENV.network): Promise { this.addressBook[address] = entry; await this.persistenceService.setAddressbook(network, this.addressBook); return this.addressBook; - }; + } async bindAddressToContact(contact: MeritContact, address: string, alias?: string) { const addressBook: IAddressBook = await this.getAddressbook(ENV.network); @@ -60,7 +58,7 @@ export class ContactsService { }); } if (existingContact) { - existingContact.meritAddresses.push({ address: address, alias: alias, network: ENV.network }); + existingContact.meritAddresses.push({ address: address, alias: alias, network: ENV.network }); } else { contact.meritAddresses.push({ address: address, network: ENV.network }); addressBook[address] = contact; @@ -78,17 +76,17 @@ export class ContactsService { } catch (err) { throw new Error('Contact with address ' + addr + ' not found'); } - }; + } searchContacts(contacts: MeritContact[], searchQuery: string = ''): MeritContact[] { searchQuery = searchQuery.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); const exp = new RegExp(searchQuery, 'ig'); return contacts.filter((contact: MeritContact) => { if (contact.name.formatted && contact.name.formatted.match(exp)) return true; - if (_.some(contact.emails, (email) => email.value.match(exp))) return true; - if (_.some(contact.phoneNumbers, (phoneNumber) => phoneNumber.value.match(exp))) return true; - if (_.some(contact.meritAddresses, (address) => address.address.match(exp))) return true; - if (_.some(contact.meritAddresses, (address) => address.alias && address.alias.match(exp))) return true; + if (_.some(contact.emails, email => email.value.match(exp))) return true; + if (_.some(contact.phoneNumbers, phoneNumber => phoneNumber.value.match(exp))) return true; + if (_.some(contact.meritAddresses, address => address.address.match(exp))) return true; + if (_.some(contact.meritAddresses, address => address.alias && address.alias.match(exp))) return true; return false; }); } @@ -97,35 +95,42 @@ export class ContactsService { const localContacts: IAddressBook = await this.getAddressbook(); const contacts: MeritContact[] = deviceContacts - .filter((contact: Contact) => !_.isEmpty(contact.displayName) && !_.isEmpty(contact.phoneNumbers) || !_.isEmpty(contact.emails)) + .filter( + (contact: Contact) => + (!_.isEmpty(contact.displayName) && !_.isEmpty(contact.phoneNumbers)) || !_.isEmpty(contact.emails), + ) .map((contact: Contact) => createMeritContact(contact)); let localContact: MeritContact, deviceContact: MeritContact; - Object.keys(localContacts) - .forEach((key: string) => { - localContact = localContacts[key]; + Object.keys(localContacts).forEach((key: string) => { + localContact = localContacts[key]; - if (localContact.id || localContact.phoneNumbers.length || localContact.emails.length) { - deviceContact = contacts.find((c: MeritContact) => + if (localContact.id || localContact.phoneNumbers.length || localContact.emails.length) { + deviceContact = contacts.find( + (c: MeritContact) => // find by ID - (localContact.id === c.id) || + localContact.id === c.id || // find by phone number - (localContact.phoneNumbers.some((p: IContactField) => Boolean(c.phoneNumbers.find(_p => _p.value == p.value)))) || + localContact.phoneNumbers.some((p: IContactField) => + Boolean(c.phoneNumbers.find(_p => _p.value == p.value)), + ) || // compare emails - (localContact.emails.some((e: IContactField) => Boolean(c.emails.find(_e => _e.value == e.value)))) - ); + localContact.emails.some((e: IContactField) => Boolean(c.emails.find(_e => _e.value == e.value))), + ); - if (deviceContact) { - // merge addresses - deviceContact.meritAddresses = _.uniq(Array.prototype.concat((deviceContact.meritAddresses || []), (localContact.meritAddresses || []))); - deviceContact = void 0; - return; - } + if (deviceContact) { + // merge addresses + deviceContact.meritAddresses = _.uniq( + Array.prototype.concat(deviceContact.meritAddresses || [], localContact.meritAddresses || []), + ); + deviceContact = void 0; + return; } + } - contacts.push(localContact); - }); + contacts.push(localContact); + }); localContact = void 0; @@ -136,7 +141,7 @@ export class ContactsService { delete this.addressBook[addr]; await this.persistenceService.setAddressbook(network, this.addressBook); return this.addressBook; - }; + } deleteAddressBook() { return this.persistenceService.setAddressbook(ENV.network, {}); @@ -146,7 +151,4 @@ export class ContactsService { const addressBook = await this.persistenceService.getAddressbook(network); return _.isEmpty(addressBook) ? {} : addressBook; } - - - } diff --git a/packages/lightwallet/common/services/easy-receive.service.ts b/packages/lightwallet/common/services/easy-receive.service.ts index c6b2c0ec2b..6fa4b3d084 100644 --- a/packages/lightwallet/common/services/easy-receive.service.ts +++ b/packages/lightwallet/common/services/easy-receive.service.ts @@ -12,7 +12,7 @@ import { RateService } from '@merit/common/services/rate.service'; import { accessWallet, WalletService } from '@merit/common/services/wallet.service'; import { Address, crypto, HDPrivateKey, HDPublicKey, PrivateKey, PublicKey, Script, Transaction } from 'meritcore-lib'; import { Subject } from 'rxjs/Subject'; -import { AlertService } from "@merit/common/services/alert.service"; +import { AlertService } from '@merit/common/services/alert.service'; @Injectable() export class EasyReceiveService { @@ -25,9 +25,8 @@ export class EasyReceiveService { private ledger: LedgerService, private rateService: RateService, private walletService: WalletService, - private alertCtrl: AlertService - ) { - } + private alertCtrl: AlertService, + ) {} private cancelEasySendSource = new Subject(); private cancelledEasySendSource = new Subject(); @@ -57,7 +56,7 @@ export class EasyReceiveService { senderName: params.sn, senderPublicKey: params.sk, blockTimeout: params.bt, - deepLinkURL: params['~referring_link'] + deepLinkURL: params['~referring_link'], }); } @@ -87,7 +86,8 @@ export class EasyReceiveService { wallet: MeritWalletClient, receipt: EasyReceipt, input: any, - destinationAddress: any): Promise { + destinationAddress: any, + ): Promise { return this.spendEasyReceipt(receipt, wallet, input, destinationAddress); } @@ -122,12 +122,10 @@ export class EasyReceiveService { return tx ? tx.amount : 0; } - isInviteOnly(txs: Array) { return !txs.some(tx => !tx.invite); } - async validateEasyReceiptOnBlockchain(receipt: EasyReceipt, password = ''): Promise { const walletClient = this.mwcService.getClient(null, {}); @@ -143,7 +141,7 @@ export class EasyReceiveService { privateKey: scriptData.privateKey, publicKey: scriptData.publicKey, script: scriptData.script, - scriptId: scriptAddress + scriptId: scriptAddress, }; } catch (err) { this.logger.error('Could not validate easyScript on the blockchain.', err); @@ -151,7 +149,12 @@ export class EasyReceiveService { } } - private async spendEasyReceipt(receipt: EasyReceipt, wallet: MeritWalletClient, input: any, destinationAddress: any): Promise { + private async spendEasyReceipt( + receipt: EasyReceipt, + wallet: MeritWalletClient, + input: any, + destinationAddress: any, + ): Promise { // Claim invites await Promise.all(input.txs.map(tx => tx.invite && this.sendEasyReceiveTx(input, tx, destinationAddress, wallet))); @@ -167,7 +170,7 @@ export class EasyReceiveService { const txp = await this.buildEasySendRedeemTransaction(input, tx, destinationAddress, fee); return this.walletService.broadcastRawTx(wallet, { rawTx: txp.serialize({ disableSmallFees: tx.invite }), - network: ENV.network + network: ENV.network, }); } @@ -183,7 +186,7 @@ export class EasyReceiveService { privateKey: receivePrv, publicKey: receivePub, script: script, - scriptPubKey: script.toMixedScriptHashOut(senderPubKey) + scriptPubKey: script.toMixedScriptHashOut(senderPubKey), }; } @@ -208,7 +211,6 @@ export class EasyReceiveService { * @param {toAddress} Address to put the funds into. */ buildEasySendRedeemTransaction(input: any, txn: any, toAddress: string, fee = FeeService.DEFAULT_FEE): Promise { - const totalAmount = txn.amount; const amount = txn.invite ? txn.amount : totalAmount - fee; @@ -225,7 +227,7 @@ export class EasyReceiveService { output: Transaction.Output.fromObject({ script: p2shScript, micros: totalAmount }), prevTxId: txn.txid, outputIndex: txn.index, - script: input.script + script: input.script, }; tx.addInput(new Transaction.Input.PayToScriptHashInput(p2shInput, input.script, p2shScript)); @@ -243,7 +245,6 @@ export class EasyReceiveService { return tx; } - cancelEasySend(url: string) { let params = this.parseEasySendUrl(url); let receipt = this.paramsToReceipt(params); @@ -260,8 +261,8 @@ export class EasyReceiveService { wallet: MeritWalletClient, receipt: EasyReceipt, password: string, - walletPassword: string) { - + walletPassword: string, + ) { //figure out wallet info const signingKey = wallet.getRootPrivateKey(walletPassword); const pubKey = wallet.getRootAddressPubkey(); @@ -280,18 +281,16 @@ export class EasyReceiveService { const input = { script: redeemScript, privateKey: signingKey, - senderPublicKey: pubKey.toString() + senderPublicKey: pubKey.toString(), }; //get the invite back const invite = txs.find(tx => tx.invite); - if (invite) - await this.sendEasyReceiveTx(input, invite, destAddress, wallet); + if (invite) await this.sendEasyReceiveTx(input, invite, destAddress, wallet); //get the merit back const transact = txs.find(tx => !tx.invite); - if (transact) - await this.sendEasyReceiveTx(input, transact, destAddress, wallet); + if (transact) await this.sendEasyReceiveTx(input, transact, destAddress, wallet); await wallet.cancelGlobalSend(scriptAddress.toString()); @@ -299,8 +298,7 @@ export class EasyReceiveService { return { invite: invite, - tx: transact + tx: transact, }; } - } diff --git a/packages/lightwallet/common/services/easy-send.service.ts b/packages/lightwallet/common/services/easy-send.service.ts index 2489fc564e..107c065723 100644 --- a/packages/lightwallet/common/services/easy-send.service.ts +++ b/packages/lightwallet/common/services/easy-send.service.ts @@ -12,7 +12,6 @@ import { AlertService } from '@merit/common/services/alert.service'; @Injectable() export class EasySendService { - private readonly DEFAULT_TIMEOUT = 10080; // 7 days * 24 hours * 60 minutes constructor( @@ -20,7 +19,8 @@ export class EasySendService { private persistenceService: PersistenceService, @Optional() private socialSharing: SocialSharing, private addressService: AddressService, - private alertCtrl: AlertService) {} + private alertCtrl: AlertService, + ) {} @accessWallet async createEasySendScriptHash(wallet: MeritWalletClient, password?: string): Promise { @@ -37,7 +37,7 @@ export class EasySendService { signPrivKey, address: easySendAddress, addressType: Address.PayToScriptHashType, // script address - network: ENV.network + network: ENV.network, }; // easy send address is a mix of script_id pubkey_id @@ -58,7 +58,6 @@ export class EasySendService { // HACK: msg = msg2; - } try { @@ -86,11 +85,13 @@ export class EasySendService { async updatePendingEasySends(wallet: MeritWalletClient) { let easySends: EasySend[] = (await this.persistenceService.getPendingEasySends(wallet.id)) || []; - easySends = await Promise.all(easySends.map(async (easySend: EasySend) => { - if (!easySend.scriptAddress) return null; - const txs = await wallet.validateEasyScript(easySend.scriptAddress.toString()); - return txs.result.every(tx => !tx.spent) ? easySend : null; - })); + easySends = await Promise.all( + easySends.map(async (easySend: EasySend) => { + if (!easySend.scriptAddress) return null; + const txs = await wallet.validateEasyScript(easySend.scriptAddress.toString()); + return txs.result.every(tx => !tx.spent) ? easySend : null; + }), + ); easySends = easySends.filter((easySend: EasySend) => easySend !== null); await this.persistenceService.setPendingEasySends(wallet.id, easySends); @@ -98,7 +99,7 @@ export class EasySendService { } async storeEasySend(walletId: string, easySend: EasySend): Promise { - const history: EasySend[] = await this.persistenceService.getPendingEasySends(walletId) || []; + const history: EasySend[] = (await this.persistenceService.getPendingEasySends(walletId)) || []; history.push(easySend); return this.persistenceService.setPendingEasySends(walletId, history); } @@ -107,16 +108,18 @@ export class EasySendService { if (amount > Number.MAX_SAFE_INTEGER) throw new Error('The amount is too big'); const txp: any = { - outputs: [{ - 'script': easySend.script.toHex(), - 'toAddress': easySend.scriptAddress, - 'amount': amount - }], + outputs: [ + { + script: easySend.script.toHex(), + toAddress: easySend.scriptAddress, + amount: amount, + }, + ], inputs: [], // will be defined on MWS side feeLevel: this.feeService.getCurrentFeeLevel(), excludeUnconfirmedUtxos: false, dryRun: true, - addressType: 'P2SH' + addressType: 'P2SH', }; if (amount == wallet.balance.spendableAmount) { @@ -125,7 +128,6 @@ export class EasySendService { } return wallet.createTxProposal(txp); - } /** @@ -135,10 +137,7 @@ export class EasySendService { passphrase = passphrase || ''; const pubKey = wallet.getRootAddressPubkey(); const rcvPair = PrivateKey.forNewEasySend(passphrase, ENV.network); - const pubKeys = [ - rcvPair.key.publicKey.toBuffer(), - pubKey.toBuffer() - ]; + const pubKeys = [rcvPair.key.publicKey.toBuffer(), pubKey.toBuffer()]; const script = Script.buildEasySendOut(pubKeys, timeout, ENV.network); const addressInfo = await this.addressService.getAddressInfo(wallet.getRootAddress().toString()); @@ -154,8 +153,7 @@ export class EasySendService { scriptAddress: '', scriptReferralOpts: {}, cancelled: false, - inviteOnly: false + inviteOnly: false, }; } - } diff --git a/packages/lightwallet/common/services/email-notification.service.ts b/packages/lightwallet/common/services/email-notification.service.ts index 4ce9133006..b4951db232 100644 --- a/packages/lightwallet/common/services/email-notification.service.ts +++ b/packages/lightwallet/common/services/email-notification.service.ts @@ -6,10 +6,11 @@ import { WalletService } from '@merit/common/services/wallet.service'; @Injectable() export class EmailNotificationsService { - - constructor(private configService: ConfigService, - private profileService: ProfileService, - private walletService: WalletService) {} + constructor( + private configService: ConfigService, + private profileService: ProfileService, + private walletService: WalletService, + ) {} async updateEmail(opts: any) { opts = opts || {}; @@ -21,12 +22,12 @@ export class EmailNotificationsService { emailFor: null, // Backward compatibility emailNotifications: { enabled: opts.enabled, - email: opts.enabled ? opts.email : null - } + email: opts.enabled ? opts.email : null, + }, }); return this.walletService.updateRemotePreferences(wallets); - }; + } getEmailIfEnabled(config) { config = config || this.configService.get(); @@ -34,8 +35,7 @@ export class EmailNotificationsService { if (config.emailNotifications) { if (!config.emailNotifications.enabled) return; - if (config.emailNotifications.email) - return config.emailNotifications.email; + if (config.emailNotifications.email) return config.emailNotifications.email; } if (_.isEmpty(config.emailFor)) return; @@ -57,9 +57,8 @@ export class EmailNotificationsService { let currentEmail = emailNotifications.emailAddress; return this.updateEmail({ enabled: currentEmail ? true : false, - email: currentEmail + email: currentEmail, }); } } - } diff --git a/packages/lightwallet/common/services/fee.service.ts b/packages/lightwallet/common/services/fee.service.ts index 1037955b17..fc316bc2ce 100644 --- a/packages/lightwallet/common/services/fee.service.ts +++ b/packages/lightwallet/common/services/fee.service.ts @@ -12,20 +12,16 @@ export class FeeLevels { static SUPER_ECONOMY = 'superEconomy'; } - @Injectable() export class FeeService { - public mwClient: MeritWalletClient; public static DEFAULT_FEE = 10000; private readonly CACHE_TIME = 120000; //2min - private cache = {updatedTs: 0, levels: []}; + private cache = { updatedTs: 0, levels: [] }; - constructor( - mwcService: MWCService - ) { + constructor(mwcService: MWCService) { this.mwClient = mwcService.getClient(null); } @@ -35,7 +31,7 @@ export class FeeService { public async getFeeRate(levelName) { if (this.cache.updatedTs + this.CACHE_TIME < Date.now()) { const levels = await this.mwClient.getFeeLevels(ENV.network); - this.cache = {updatedTs: Date.now(), levels}; + this.cache = { updatedTs: Date.now(), levels }; } return this.cache.levels.find(l => l.level == levelName).feePerKb; @@ -46,7 +42,7 @@ export class FeeService { */ public async getTxpFee(txp) { const feePerKB = await this.getFeeRate(ENV.feeLevel); - const fee = Math.round(feePerKB * txp.serialize().length / 1024); + const fee = Math.round((feePerKB * txp.serialize().length) / 1024); return fee; } @@ -64,5 +60,4 @@ export class FeeService { public getCurrentFeeLevel() { return ENV.feeLevel; } - } diff --git a/packages/lightwallet/common/services/language.service.ts b/packages/lightwallet/common/services/language.service.ts index d2e7939152..d04241ffbc 100644 --- a/packages/lightwallet/common/services/language.service.ts +++ b/packages/lightwallet/common/services/language.service.ts @@ -11,45 +11,52 @@ export class LanguageService { private languages: Array = [ { name: 'English', - isoCode: 'en' - }, { + isoCode: 'en', + }, + { name: 'Espaรฑol', - isoCode: 'es' - }, { + isoCode: 'es', + }, + { name: 'Franรงais', isoCode: 'fr', - }, { + }, + { name: 'Italiano', isoCode: 'it', - }, { + }, + { name: 'Polski', isoCode: 'pl', - }, { + }, + { name: 'Deutsch', isoCode: 'de', - }, { + }, + { name: 'ๆ—ฅๆœฌ่ชž', isoCode: 'ja', useIdeograms: true, - }, { + }, + { name: 'ไธญๆ–‡๏ผˆ็ฎ€ไฝ“๏ผ‰', isoCode: 'zh', useIdeograms: true, - }, { + }, + { name: 'Pัƒััะบะธะน', isoCode: 'ru', - }, { + }, + { name: 'Portuguรชs', isoCode: 'pt', - } + }, ]; private current: string; - constructor(private logger: LoggerService, - private translate: TranslateService, - private config: ConfigService) { + constructor(private logger: LoggerService, private translate: TranslateService, private config: ConfigService) { this.logger.info('LanguageService initialized.'); - this.translate.onLangChange.subscribe((event) => { + this.translate.onLangChange.subscribe(event => { this.logger.info('Settings language changed to: ' + event.lang); }); } @@ -74,9 +81,12 @@ export class LanguageService { } getName(lang: string) { - return _.result(_.find(this.languages, { - 'isoCode': lang - }), 'name'); + return _.result( + _.find(this.languages, { + isoCode: lang, + }), + 'name', + ); } getDefault() { @@ -93,12 +103,11 @@ export class LanguageService { getCurrentInfo() { return _.find(this.languages, { - 'isoCode': this.current + isoCode: this.current, }); } getAvailables() { return this.languages; } - } diff --git a/packages/lightwallet/common/services/ledger.service.ts b/packages/lightwallet/common/services/ledger.service.ts index 5a37c2664e..c5facc7fdb 100644 --- a/packages/lightwallet/common/services/ledger.service.ts +++ b/packages/lightwallet/common/services/ledger.service.ts @@ -2,13 +2,12 @@ import { Injectable } from '@angular/core'; @Injectable() export class LedgerService { - static description = { id: 'ledger', name: 'Ledger', longName: 'Ledger Hardware Wallet', isEmbeddedHardware: false, - supportsTestnet: false + supportsTestnet: false, }; private static LEDGER_CHROME_ID = 'kkdpmhnladdopljabkgpacgpliggeeaf'; @@ -17,10 +16,9 @@ export class LedgerService { let bstr = new ByteString(s, GP.HEX).toBuffer(); let a = new Uint8Array(bstr.length); - Array.prototype.forEach.call(bstr, - (ch, i) => { - a[i] = (ch + '').charCodeAt(0); - }); + Array.prototype.forEach.call(bstr, (ch, i) => { + a[i] = (ch + '').charCodeAt(0); + }); return a; } @@ -28,12 +26,9 @@ export class LedgerService { public hexToString(s) { return new ByteString(s, GP.HEX).toBuffer(); } - } - class Convert { - /** * Convert a binary string to his hexadecimal representation * @param {String} src binary string @@ -47,7 +42,7 @@ class Convert { r += hexes[src.charCodeAt(i) >> 4] + hexes[src.charCodeAt(i) & 0xf]; } return r; - }; + } /** * Convert an hexadecimal string to its binary representation @@ -59,7 +54,7 @@ class Convert { static hexToBin(src) { var result = ''; var digits = '0123456789ABCDEF'; - if ((src.length % 2) != 0) { + if (src.length % 2 != 0) { throw 'Invalid string: ' + src; } src = src.toUpperCase(); @@ -84,12 +79,15 @@ class Convert { * @param {Number} offset offset to the digit (default is 0) * @returns {Number} converted digit */ - public static readHexDigit = function (data, offset) { + public static readHexDigit = function(data, offset) { var digits = '0123456789ABCDEF'; if (typeof offset == 'undefined') { offset = 0; } - return (digits.indexOf(data.substring(offset, offset + 1).toUpperCase()) << 4) + (digits.indexOf(data.substring(offset + 1, offset + 2).toUpperCase())); + return ( + (digits.indexOf(data.substring(offset, offset + 1).toUpperCase()) << 4) + + digits.indexOf(data.substring(offset + 1, offset + 2).toUpperCase()) + ); }; /** @@ -98,9 +96,9 @@ class Convert { * @param {Number} number number to convert * @returns {String} converted number */ - public static toHexDigit = function (number) { + public static toHexDigit = function(number) { var digits = '0123456789abcdef'; - return digits.charAt(number >> 4) + digits.charAt(number & 0x0F); + return digits.charAt(number >> 4) + digits.charAt(number & 0x0f); }; /** @@ -109,7 +107,7 @@ class Convert { * @param {Number} number number to convert * @returns {String} converted number */ - public static toHexByte = function (number) { + public static toHexByte = function(number) { return this.toHexDigit(number); }; @@ -119,19 +117,18 @@ class Convert { * @param {Number} number number to convert * @returns {String} converted number */ - public static toHexByteBCD = function (numberBCD) { - var number = ((numberBCD / 10) * 16) + (numberBCD % 10); + public static toHexByteBCD = function(numberBCD) { + var number = (numberBCD / 10) * 16 + (numberBCD % 10); return this.toHexDigit(number); }; - /** * Convert a number to an hexadecimal short number * @static * @param {Number} number number to convert * @returns {String} converted number */ - public static toHexShort = function (number) { + public static toHexShort = function(number) { return this.toHexDigit((number >> 8) & 0xff) + this.toHexDigit(number & 0xff); }; @@ -141,9 +138,13 @@ class Convert { * @param {Number} number number to convert * @returns {String} converted number */ - public static toHexInt = function (number) { - return this.toHexDigit((number >> 24) & 0xff) + this.toHexDigit((number >> 16) & 0xff) + - this.toHexDigit((number >> 8) & 0xff) + this.toHexDigit(number & 0xff); + public static toHexInt = function(number) { + return ( + this.toHexDigit((number >> 24) & 0xff) + + this.toHexDigit((number >> 16) & 0xff) + + this.toHexDigit((number >> 8) & 0xff) + + this.toHexDigit(number & 0xff) + ); }; } @@ -159,8 +160,7 @@ GP.HEX = 5; * @constructs */ class ByteString { - - public toBuffer = function () { + public toBuffer = function() { return this.value; }; private hasBuffer: boolean; @@ -168,10 +168,10 @@ class ByteString { private length: any; constructor(value, private encoding) { - this.hasBuffer = (typeof Buffer != 'undefined'); + this.hasBuffer = typeof Buffer != 'undefined'; this.hasBuffer = false; - if (this.hasBuffer && (value instanceof Buffer)) { + if (this.hasBuffer && value instanceof Buffer) { this.value = value; this.encoding = GP.HEX; } else { diff --git a/packages/lightwallet/common/services/logger.service.ts b/packages/lightwallet/common/services/logger.service.ts index c598605d71..feabc2dbb5 100644 --- a/packages/lightwallet/common/services/logger.service.ts +++ b/packages/lightwallet/common/services/logger.service.ts @@ -7,14 +7,13 @@ export enum LogLevel { ERROR = 0, WARN, INFO, - DEBUG + DEBUG, } declare const process: any; @Injectable() export class LoggerService { - private logs = []; getLogs(level = LogLevel.INFO) { @@ -25,16 +24,14 @@ export class LoggerService { this.logs.push({ level: LogLevel.ERROR, timestamp: Date.now(), arguments: messages }); if (!LOGGING_ENABLED) return; console.error.apply(console, messages); - if (TRACE_ENABLED) - console.trace(); + if (TRACE_ENABLED) console.trace(); } warn(...messages) { this.logs.unshift({ level: LogLevel.WARN, timestamp: Date.now(), arguments: messages }); if (!LOGGING_ENABLED) return; console.warn.apply(console, messages); - if (TRACE_ENABLED) - console.trace(); + if (TRACE_ENABLED) console.trace(); } info(...messages) { @@ -54,4 +51,3 @@ export class LoggerService { this.info(messages); } } - diff --git a/packages/lightwallet/common/services/mnemonic.service.ts b/packages/lightwallet/common/services/mnemonic.service.ts index c3758875c8..b545e601c3 100644 --- a/packages/lightwallet/common/services/mnemonic.service.ts +++ b/packages/lightwallet/common/services/mnemonic.service.ts @@ -7,11 +7,7 @@ import { MeritWalletClient } from '@merit/common/merit-wallet-client'; @Injectable() export class MnemonicService { - - constructor(private logger: LoggerService, - private profileService: ProfileService, - private mwcService: MWCService) { - } + constructor(private logger: LoggerService, private profileService: ProfileService, private mwcService: MWCService) {} async importMnemonic(words: string, opts: any): Promise { const walletClient = this.mwcService.getClient(null, opts); @@ -24,7 +20,7 @@ export class MnemonicService { passphrase: opts.passphrase, entropySourcePath: opts.entropySourcePath, derivationStrategy: opts.derivationStrategy || 'BIP44', - account: opts.account || 0 + account: opts.account || 0, }); return this.profileService.addWallet(walletClient); @@ -40,7 +36,7 @@ export class MnemonicService { network: opts.networkName || ENV.network, passphrase: opts.passphrase, account: opts.account || 0, - derivationStrategy: opts.derivationStrategy || 'BIP44' + derivationStrategy: opts.derivationStrategy || 'BIP44', }); return walletClient; @@ -56,5 +52,5 @@ export class MnemonicService { let wordList = words.split(/[\u3000\s]+/); return wordList.join(isJA ? '\u3000' : ' '); - }; + } } diff --git a/packages/lightwallet/common/services/mobile-push-notifications-service.ts b/packages/lightwallet/common/services/mobile-push-notifications-service.ts index ec53e02922..3a730dfd75 100644 --- a/packages/lightwallet/common/services/mobile-push-notifications-service.ts +++ b/packages/lightwallet/common/services/mobile-push-notifications-service.ts @@ -24,18 +24,20 @@ export class MobilePushNotificationsService extends PushNotificationsService { return this.configService.get().pushNotificationsEnabled; } - constructor(http: HttpClient, - public profileService: ProfileService, - public platformService: PlatformService, - public configService: ConfigService, - logger: LoggerService, - public appService: AppSettingsService, - private app: App, - private mwcService: MWCService, - platform: Platform, - private FCM: FCM, - private ngZone: NgZone, - private pollingNotifications: PollingNotificationsService) { + constructor( + http: HttpClient, + public profileService: ProfileService, + public platformService: PlatformService, + public configService: ConfigService, + logger: LoggerService, + public appService: AppSettingsService, + private app: App, + private mwcService: MWCService, + platform: Platform, + private FCM: FCM, + private ngZone: NgZone, + private pollingNotifications: PollingNotificationsService, + ) { super(http, logger); this.logger.info('Hello PushNotificationsService Service'); this.isIOS = this.platformService.isIOS; @@ -114,11 +116,14 @@ export class MobilePushNotificationsService extends PushNotificationsService { const wallet = (await this.profileService.getWallets()).find(w => w.id == data.walletId); if (!_.isEmpty(wallet)) { // Let's re-shape the event to match the notificatons stored in MWS - this.profileService.propogateBwsEvent({ - data: _.pick(data, ['amount', 'address', 'txid']), - type: data.type, - walletId: data.walletId - }, wallet); + this.profileService.propogateBwsEvent( + { + data: _.pick(data, ['amount', 'address', 'txid']), + type: data.type, + walletId: data.walletId, + }, + wallet, + ); } } } @@ -138,14 +143,13 @@ export class MobilePushNotificationsService extends PushNotificationsService { this.subscribe(walletClient); } - enable() { if (!this.token) { this.logger.warn('No token available for this device. Cannot set push notifications. Needs registration.'); return; } return super.enable(); - }; + } async disable() { if (!this.usePushNotifications) { @@ -183,7 +187,11 @@ export class MobilePushNotificationsService extends PushNotificationsService { } if (!this.token && this.retriesRemaining > 0) { this.retriesRemaining--; - this.logger.warn(`Attempted to subscribe without an available token; attempting to acquire. ${this.retriesRemaining} attempts remaining.`); + this.logger.warn( + `Attempted to subscribe without an available token; attempting to acquire. ${ + this.retriesRemaining + } attempts remaining.`, + ); await this.getToken(); return super.subscribe(walletClient); } diff --git a/packages/lightwallet/common/services/mwc.service.ts b/packages/lightwallet/common/services/mwc.service.ts index 22ba7c8803..36c2183d12 100644 --- a/packages/lightwallet/common/services/mwc.service.ts +++ b/packages/lightwallet/common/services/mwc.service.ts @@ -5,7 +5,7 @@ import { ENV } from '@app/env'; export enum MWCErrors { AUTHENTICATION = 'MWC_AUTH_ERROR', - CONNECTION = 'MWC_CONNECTION_ERROR' + CONNECTION = 'MWC_CONNECTION_ERROR', } @Injectable() @@ -14,8 +14,7 @@ export class MWCService { buildTx: Function = this.MWC.buildTx; parseSecret: Function = this.MWC.parseSecret; - constructor(private events: Events) { - } + constructor(private events: Events) {} public getMeritcore() { return this.MWC.Meritcore; @@ -33,7 +32,7 @@ export class MWCService { return this.MWC.Utils; } - public getClient(walletData?, opts?: { bwsurl?: string; verbose?: boolean; }): MeritWalletClient { + public getClient(walletData?, opts?: { bwsurl?: string; verbose?: boolean }): MeritWalletClient { if (!walletData && !opts && this.MWC) return this.MWC; opts = opts || {}; diff --git a/packages/lightwallet/common/services/persistence.service.ts b/packages/lightwallet/common/services/persistence.service.ts index a7900d9897..47b9ca11d0 100644 --- a/packages/lightwallet/common/services/persistence.service.ts +++ b/packages/lightwallet/common/services/persistence.service.ts @@ -408,10 +408,7 @@ export class PersistenceService { async hideUnlockRequestAddress(address: string) { const addresses = await this.getHiddenUnlockRequestsAddresses(); - return this.setHiddenUnlockRequestsAddresses([ - ...addresses, - address - ]); + return this.setHiddenUnlockRequestsAddresses([...addresses, address]); } async getActiveRequestsNumber() { diff --git a/packages/lightwallet/common/services/persistence2.service.ts b/packages/lightwallet/common/services/persistence2.service.ts index 93cac7c38b..d7de64480c 100644 --- a/packages/lightwallet/common/services/persistence2.service.ts +++ b/packages/lightwallet/common/services/persistence2.service.ts @@ -21,7 +21,7 @@ export enum UserSettingsKey { GetStartedTips = 'get_started_tips', recordPassphrase = 'record_passphrase', primaryWalletID = 'primary_wallet_id', - SmsNotificationsPrompt = 'sms_notifications_prompt' + SmsNotificationsPrompt = 'sms_notifications_prompt', } export interface INotificationSettings { @@ -37,7 +37,7 @@ const DEFAULT_NOTIFICATION_SETTINGS: INotificationSettings = { emailNotifications: false, pushNotifications: true, smsNotifications: false, - phoneNumber: '' + phoneNumber: '', }; /** @@ -45,7 +45,7 @@ const DEFAULT_NOTIFICATION_SETTINGS: INotificationSettings = { */ @Injectable() export class PersistenceService2 { - constructor(private storage: Storage) { } + constructor(private storage: Storage) {} /** * Use this method to set a generic value that doesn't require it's own function @@ -76,8 +76,8 @@ export class PersistenceService2 { async setNotificationSettings(settings: Partial) { return this.storage.set(StorageKey.NotificationSettings, { - ...await this.getNotificationSettings(), - ...settings + ...(await this.getNotificationSettings()), + ...settings, }); } @@ -85,7 +85,7 @@ export class PersistenceService2 { const settings = (await this.storage.get(StorageKey.NotificationSettings)) || {}; return { ...DEFAULT_NOTIFICATION_SETTINGS, - ...settings + ...settings, }; } @@ -113,7 +113,7 @@ export class PersistenceService2 { await this.setEasySends(easySends); return true; } else { - console.error('Couldn\'t find EasySend to cancel', scriptAddress); + console.error("Couldn't find EasySend to cancel", scriptAddress); return false; } } diff --git a/packages/lightwallet/common/services/platform.service.ts b/packages/lightwallet/common/services/platform.service.ts index 16e45799b2..68c74aa767 100644 --- a/packages/lightwallet/common/services/platform.service.ts +++ b/packages/lightwallet/common/services/platform.service.ts @@ -15,8 +15,7 @@ export class PlatformService { isDevel: boolean; supportsLedger: boolean; - constructor(private platform: Platform, - private log: LoggerService) { + constructor(private platform: Platform, private log: LoggerService) { let ua = navigator ? navigator.userAgent : null; if (!ua) { diff --git a/packages/lightwallet/common/services/polling-notification.service.ts b/packages/lightwallet/common/services/polling-notification.service.ts index a25fa0dd26..c92f3aeccc 100644 --- a/packages/lightwallet/common/services/polling-notification.service.ts +++ b/packages/lightwallet/common/services/polling-notification.service.ts @@ -16,10 +16,12 @@ import { ElectronService } from '../../desktop/src/services/electron.service'; export class PollingNotificationsService { private pollingNotificationsSubscriptions: { [walletId: string]: Subscription } = {}; - constructor(protected profileService: ProfileService, - protected logger: LoggerService, - @Optional() private store: Store, - @Optional() private persistenceService: PersistenceService2) { + constructor( + protected profileService: ProfileService, + protected logger: LoggerService, + @Optional() private store: Store, + @Optional() private persistenceService: PersistenceService2, + ) { this.logger.info('Hello PollingNotification Service'); } @@ -30,7 +32,7 @@ export class PollingNotificationsService { } (await this.profileService.getWallets()).forEach(w => this.enablePolling(w)); - }; + } disable() { let walletId: string; @@ -46,11 +48,12 @@ export class PollingNotificationsService { if (this.pollingNotificationsSubscriptions[walletClient.id]) { this.logger.warn('Attempting to enable polling for wallet that already has polling enabled: ', walletClient.id); } else { - this.pollingNotificationsSubscriptions[walletClient.id] = walletClient.initNotifications() + this.pollingNotificationsSubscriptions[walletClient.id] = walletClient + .initNotifications() .pipe( filter((notifications: any[]) => !!notifications), map((notifications: any[]) => uniqBy(notifications, 'walletId')), - debounceTime(500) + debounceTime(500), ) .subscribe(this.onFetch.bind(this)); } @@ -64,12 +67,12 @@ export class PollingNotificationsService { } protected onFetch(notifications: any[]) { - notifications.forEach((notification) => { + notifications.forEach(notification => { if (notification) { notification = { ...notification, ...notification.data, - read: false + read: false, }; delete notification.data; @@ -77,10 +80,12 @@ export class PollingNotificationsService { this.store.dispatch(new AddNotificationAction(notification)); if (notification.walletId) { - this.store.dispatch(new RefreshOneWalletAction(notification.walletId, { - skipAlias: true, - skipShareCode: true - })); + this.store.dispatch( + new RefreshOneWalletAction(notification.walletId, { + skipAlias: true, + skipShareCode: true, + }), + ); } } }); diff --git a/packages/lightwallet/common/services/profile.service.ts b/packages/lightwallet/common/services/profile.service.ts index 62ac5da450..fc78d1ab6e 100644 --- a/packages/lightwallet/common/services/profile.service.ts +++ b/packages/lightwallet/common/services/profile.service.ts @@ -3,7 +3,7 @@ import { Events } from 'ionic-angular/util/events'; import { ENV } from '@app/env'; import { MeritWalletClient } from '@merit/common/merit-wallet-client'; import { PersistenceService } from '@merit/common/services/persistence.service'; -import { IVault } from "@merit/common/models/vault"; +import { IVault } from '@merit/common/models/vault'; import { LoggerService } from '@merit/common/services/logger.service'; import { MWCService } from '@merit/common/services/mwc.service'; @@ -12,23 +12,22 @@ import { MWCService } from '@merit/common/services/mwc.service'; */ @Injectable() export class ProfileService { - public wallets: Array; public communityInfo: { - communitySize: number, - networkValue: number, - miningRewards: number, - growthRewards: number, + communitySize: number; + networkValue: number; + miningRewards: number; + growthRewards: number; wallets: Array<{ - name: string, - alias: string, - referralAddress: string, - confirmed: boolean, - communitySize: number, - miningRewards: number, - growthRewards: number, - color: string + name: string; + alias: string; + referralAddress: string; + confirmed: boolean; + communitySize: number; + miningRewards: number; + growthRewards: number; + color: string; }>; }; @@ -36,8 +35,8 @@ export class ProfileService { private persistenceService: PersistenceService, private logger: LoggerService, private events: Events, - private mwcService: MWCService - ){ + private mwcService: MWCService, + ) { this.loadProfile(); } @@ -74,7 +73,6 @@ export class ProfileService { this.events.publish(eventName, wallet.id, n.type, n); } - async loadProfile() { const profile = await this.persistenceService.getProfile(); @@ -83,9 +81,7 @@ export class ProfileService { if (profile.wallets) { wallets = profile.wallets.map(w => MeritWalletClient.fromObj(w)); } else if (profile.credentials) { - wallets = profile.credentials.map(c => - this.mwcService.getClient(JSON.stringify(c)) - ) + wallets = profile.credentials.map(c => this.mwcService.getClient(JSON.stringify(c))); } } this.wallets = wallets; @@ -96,7 +92,7 @@ export class ProfileService { async isAuthorized() { if (this.wallets == undefined) await this.loadProfile(); - return (this.wallets.length > 0); + return this.wallets.length > 0; } async getWallets() { @@ -122,23 +118,24 @@ export class ProfileService { } async refreshData() { - let updateWallets = () => this.wallets.map(async (w) => { - status = await w.getStatus(); - }); + let updateWallets = () => + this.wallets.map(async w => { + status = await w.getStatus(); + }); - let updateVaults = () => this.wallets.map(async (w) => { - w.vaults = await w.getVaults(); - w.vaults.forEach(v => { - v.walletClient = w; - }) - }); + let updateVaults = () => + this.wallets.map(async w => { + w.vaults = await w.getVaults(); + w.vaults.forEach(v => { + v.walletClient = w; + }); + }); await Promise.all(updateWallets().concat(updateVaults())); this.storeProfile(); } async addWallet(wallet: MeritWalletClient) { - if (this.wallets.find(w => w.id == wallet.credentials.walletId)) throw new Error('Wallet already added'); wallet.initialize(true); @@ -153,7 +150,6 @@ export class ProfileService { } async updateWallet(wallet: MeritWalletClient) { - this.wallets = this.wallets.filter(w => w.id != wallet.id); this.wallets.push(wallet); @@ -162,16 +158,14 @@ export class ProfileService { } async deleteWallet(wallet: MeritWalletClient) { - wallet.eventEmitter.removeAllListeners(); - this.wallets = this.wallets.filter(w => (w.id != wallet.id)); + this.wallets = this.wallets.filter(w => w.id != wallet.id); return this.storeProfile(); } async addVault(vault: IVault) { - this.wallets.some(w => { if (w.id == vault.walletClient.id) { if (!w.vaults) w.vaults = []; @@ -184,10 +178,9 @@ export class ProfileService { } async updateVault(vault: IVault) { - this.wallets.some(w => { if (w.id == vault.walletClient.id) { - w.vaults = w.vaults.filter(v => (v._id != vault._id)); + w.vaults = w.vaults.filter(v => v._id != vault._id); w.vaults.push(vault); return true; } @@ -197,7 +190,6 @@ export class ProfileService { } storeProfile() { - if (this.wallets == undefined) return; /** do not save profile if we have wallet in temporary mode */ @@ -206,7 +198,7 @@ export class ProfileService { let profile = { version: '2.0.0', wallets: this.wallets.map(w => w.toObj()), - credentials: this.wallets.map(w => w.export()) + credentials: this.wallets.map(w => w.export()), }; this.persistenceService.storeProfile(profile); @@ -229,28 +221,30 @@ export class ProfileService { networkValue: 0, miningRewards: 0, growthRewards: 0, - wallets: wallets.map(w => { return { - name: w.name, - alias: w.rootAlias, - referralAddress: w.rootAddress.toString(), - confirmed: w.confirmed, - communitySize: 0, - miningRewards: 0, - growthRewards: 0, - color: w.color - }}) + wallets: wallets.map(w => { + return { + name: w.name, + alias: w.rootAlias, + referralAddress: w.rootAddress.toString(), + confirmed: w.confirmed, + communitySize: 0, + miningRewards: 0, + growthRewards: 0, + color: w.color, + }; + }), }; const addresses = network.wallets.map(w => w.referralAddress); if (addresses.length) { - - const getCommunitySizes = () => addresses.map(async (a) => { - const { referralcount } = await wallets[0].getCommunityInfo(a); - let w = network.wallets.find(w => w.referralAddress == a); - w.communitySize = referralcount; - network.communitySize += referralcount; - }); + const getCommunitySizes = () => + addresses.map(async a => { + const { referralcount } = await wallets[0].getCommunityInfo(a); + let w = network.wallets.find(w => w.referralAddress == a); + w.communitySize = referralcount; + network.communitySize += referralcount; + }); const getRewards = async () => { const rewards = await this.wallets[0].getRewards(addresses); @@ -278,5 +272,4 @@ export class ProfileService { } return this.communityInfo; } - } diff --git a/packages/lightwallet/common/services/push-notification.service.ts b/packages/lightwallet/common/services/push-notification.service.ts index fd1c52e4db..ceb3bf2c5f 100644 --- a/packages/lightwallet/common/services/push-notification.service.ts +++ b/packages/lightwallet/common/services/push-notification.service.ts @@ -9,9 +9,7 @@ export class PushNotificationsService { protected platform: string; protected packageName: string; - constructor( - protected http: HttpClient, - protected logger: LoggerService) {} + constructor(protected http: HttpClient, protected logger: LoggerService) {} protected get pushNotificationsEnabled(): boolean { return false; @@ -22,15 +20,23 @@ export class PushNotificationsService { } // abstract methods - init(): Promise { return; } + init(): Promise { + return; + } - protected requestPermission(): Promise { return; } + protected requestPermission(): Promise { + return; + } - protected getToken(): Promise { return; } + protected getToken(): Promise { + return; + } protected subscribeToEvents() {} - protected getWallets(): Promise { return; } + protected getWallets(): Promise { + return; + } protected enablePolling() {} @@ -59,7 +65,7 @@ export class PushNotificationsService { await walletClient.pushNotificationsSubscribe({ token: this.token, platform: this.platform, - packageName: this.packageName + packageName: this.packageName, }); } catch (err) { if (err) { diff --git a/packages/lightwallet/common/services/rate.service.ts b/packages/lightwallet/common/services/rate.service.ts index c5be7653c1..c0edcdfb90 100644 --- a/packages/lightwallet/common/services/rate.service.ts +++ b/packages/lightwallet/common/services/rate.service.ts @@ -1,18 +1,17 @@ import { MeritWalletClient } from '@merit/common/merit-wallet-client'; export class RateService { - private readonly CACHE_TIME = 120000; //2min public mwClient: MeritWalletClient; private MRT_TO_MIC = 1e8; private cache: { - updatedTs: number, + updatedTs: number; rates: Array<{ - code: string, - name: string, - rate: number - }> + code: string; + name: string; + rate: number; + }>; }; /** @@ -73,12 +72,11 @@ export class RateService { return this.microsToMrt(micros) * rate; } - async fiatToMicros(amount: number, code: string): Promise { + async fiatToMicros(amount: number, code: string): Promise { const rate = await this.getRate(code); - return Math.ceil(amount / rate * this.MRT_TO_MIC); + return Math.ceil((amount / rate) * this.MRT_TO_MIC); } - /** * @OBSOLETE Remove this after removing usages of this method * @@ -100,8 +98,6 @@ export class RateService { */ fromFiatToMicros(amount: number, code: string) { const r = this.cache.rates.find(l => l.code == code) || { rate: 0 }; - return Math.ceil(amount / r.rate * this.MRT_TO_MIC); + return Math.ceil((amount / r.rate) * this.MRT_TO_MIC); } - } - diff --git a/packages/lightwallet/common/services/send.service.ts b/packages/lightwallet/common/services/send.service.ts index 4289be3ef5..1774e2f0d2 100644 --- a/packages/lightwallet/common/services/send.service.ts +++ b/packages/lightwallet/common/services/send.service.ts @@ -12,23 +12,25 @@ import { isAddress } from '@merit/common/utils/addresses'; import { clone } from 'lodash'; import { EasySendService } from '@merit/common/services/easy-send.service'; import { Address } from 'meritcore-lib'; -import { accessWallet } from "./wallet.service"; +import { accessWallet } from './wallet.service'; import { getEasySendURL } from '@merit/common/models/easy-send'; -import { AlertService } from "@merit/common/services/alert.service"; +import { AlertService } from '@merit/common/services/alert.service'; export interface ISendTxData { amount?: number; // micros totalAmount?: number; // micros fee?: number; // micros feeIncluded?: boolean; - easyFee?: number, + easyFee?: number; password?: string; - recipient?: { - label?: string; - name?: string; - emails?: Array<{ value: string }>; - phoneNumbers?: Array<{ value: string }>; - } | MeritContact; + recipient?: + | { + label?: string; + name?: string; + emails?: Array<{ value: string }>; + phoneNumbers?: Array<{ value: string }>; + } + | MeritContact; sendMethod?: ISendMethod; txp?: any; easySend?: EasySend; @@ -41,12 +43,14 @@ export interface ISendTxData { @Injectable() export class SendService { - constructor(private feeService: FeeService, - private walletService: WalletService, - private loggerService: LoggerService, - private easySendService: EasySendService, - private addressService: AddressService, - private alertCtrl: AlertService) {} + constructor( + private feeService: FeeService, + private walletService: WalletService, + private loggerService: LoggerService, + private easySendService: EasySendService, + private addressService: AddressService, + private alertCtrl: AlertService, + ) {} async prepareTxp(wallet: MeritWalletClient, amount: number, toAddress: string) { if (!isAddress(toAddress)) { @@ -61,7 +65,7 @@ export class SendService { inputs: [], // will be defined on MWS side feeLevel: this.feeService.getCurrentFeeLevel(), excludeUnconfirmedUtxos: false, - dryRun: true + dryRun: true, }; if (amount == wallet.balance.spendableAmount) { @@ -81,7 +85,7 @@ export class SendService { fee: preparedTxp.fee, excludeUnconfirmedUtxos: false, dryRun: false, - addressType: preparedTxp.addressType + addressType: preparedTxp.addressType, }; if (preparedTxp.sendMax || !feeIncluded) { @@ -95,10 +99,9 @@ export class SendService { @accessWallet async send(wallet: MeritWalletClient, txData: ISendTxData) { - - if (txData.sendMethod.type == SendMethodType.Easy) { + if (txData.sendMethod.type == SendMethodType.Easy) { const easySend = await this.easySendService.createEasySendScriptHash(wallet, txData.password); - const amount = txData.feeIncluded ? txData.amount : (txData.amount + await this.feeService.getEasyReceiveFee()); + const amount = txData.feeIncluded ? txData.amount : txData.amount + (await this.feeService.getEasyReceiveFee()); txData.easySend = easySend; txData.txp = await this.easySendService.prepareTxp(wallet, amount, easySend); @@ -134,7 +137,6 @@ export class SendService { } } - async estimateFee(wallet: MeritWalletClient, amount: number, isEasySend: boolean, toAddress?: string) { if (isEasySend) { const easySend = await this.easySendService.bulidScript(wallet); @@ -148,5 +150,4 @@ export class SendService { return txp.fee; } } - } diff --git a/packages/lightwallet/common/services/sms-notifications.service.ts b/packages/lightwallet/common/services/sms-notifications.service.ts index af2de8f4b9..55f886ce3d 100644 --- a/packages/lightwallet/common/services/sms-notifications.service.ts +++ b/packages/lightwallet/common/services/sms-notifications.service.ts @@ -7,8 +7,7 @@ import { ISmsNotificationSettings, ISmsNotificationStatus } from '@merit/common/ export class SmsNotificationsService { status: ISmsNotificationStatus; - constructor(private profileService: ProfileService, - private persistenceService: PersistenceService2) {} + constructor(private profileService: ProfileService, private persistenceService: PersistenceService2) {} async getSmsSubscriptionStatus(): Promise { if (this.status) { @@ -22,7 +21,6 @@ export class SmsNotificationsService { if (!wallets || !wallets.length) { status = { enabled: false }; } else { - try { status = await wallets[0].getSmsNotificationSubscription(); } catch (err) {} @@ -36,17 +34,21 @@ export class SmsNotificationsService { await this.persistenceService.setNotificationSettings({ smsNotifications: status.enabled, - phoneNumber: status.phoneNumber || '' + phoneNumber: status.phoneNumber || '', }); - return this.status = status; + return (this.status = status); } - async setSmsSubscription(enabled: boolean, phoneNumber?: string, platform?: string, settings?: ISmsNotificationSettings) { + async setSmsSubscription( + enabled: boolean, + phoneNumber?: string, + platform?: string, + settings?: ISmsNotificationSettings, + ) { await this.persistenceService.setNotificationSettings({ smsNotifications: enabled, phoneNumber }); - if (enabled && !phoneNumber) - return; + if (enabled && !phoneNumber) return; const wallets = await this.profileService.getWallets(); let promises; @@ -56,13 +58,13 @@ export class SmsNotificationsService { enabled, phoneNumber, platform, - settings + settings, }; promises = wallets.map(wallet => wallet.smsNotificationsSubscribe(phoneNumber, platform, settings)); } else { this.status = { - enabled + enabled, }; promises = wallets.map(wallet => wallet.smsNotificationsUnsubscribe()); diff --git a/packages/lightwallet/common/services/tx-format.service.ts b/packages/lightwallet/common/services/tx-format.service.ts index c5047ed289..3eea521811 100644 --- a/packages/lightwallet/common/services/tx-format.service.ts +++ b/packages/lightwallet/common/services/tx-format.service.ts @@ -9,14 +9,15 @@ import { FiatAmount } from '@merit/common/models/fiat-amount'; @Injectable() export class TxFormatService { - // TODO: implement configService pendingTxProposalsCountForUs: number; - constructor(private mwcService: MWCService, - private rate: RateService, - private config: ConfigService, - private logger: LoggerService) { + constructor( + private mwcService: MWCService, + private rate: RateService, + private config: ConfigService, + private logger: LoggerService, + ) { this.logger.info('Hello TxFormatService Service'); } @@ -27,7 +28,7 @@ export class TxFormatService { //TODO : now only works for english, specify opts to change thousand separator and decimal separator let opts = { - fullPrecision: !!fullPrecision + fullPrecision: !!fullPrecision, }; return this.mwcService.getUtils().formatAmount(micros, settings.unitCode, opts); } @@ -46,7 +47,7 @@ export class TxFormatService { } toFiatStr(micros: number, code: string): Promise { - return this.toFiat(micros, code).then((fiatAmount) => { + return this.toFiat(micros, code).then(fiatAmount => { return new FiatAmount(parseFloat(fiatAmount)).amountStr; }); } @@ -62,7 +63,7 @@ export class TxFormatService { if (isNaN(micros)) return; let settings = this.config.get().wallet.settings; - let v1 = parseFloat((this.rate.fromMicrosToFiat(micros, settings.alternativeIsoCode)).toFixed(2)); + let v1 = parseFloat(this.rate.fromMicrosToFiat(micros, settings.alternativeIsoCode).toFixed(2)); if (!v1) return null; let v1FormatFiat = new FiatAmount(v1); if (!v1FormatFiat) return null; @@ -94,12 +95,10 @@ export class TxFormatService { } async processTx(tx: any): Promise { - if (!tx || tx.action == 'invalid') - return tx; + if (!tx || tx.action == 'invalid') return tx; // New transaction output format if (tx.outputs && tx.outputs.length) { - let outputsNr = tx.outputs.length; if (tx.action != 'received') { @@ -127,44 +126,42 @@ export class TxFormatService { this.pendingTxProposalsCountForUs = 0; let now = Math.floor(Date.now() / 1000); - const pTxps = await Promise.all(txps.map(async (tx: any) => { - // no future transactions... - if (tx.createdOn > now) - tx.createdOn = now; - + const pTxps = await Promise.all( + txps.map(async (tx: any) => { + // no future transactions... + if (tx.createdOn > now) tx.createdOn = now; - // TODO: We should not call any services here. Data should be passed in. - tx.wallet = { copayerId: 'yepNope' }; + // TODO: We should not call any services here. Data should be passed in. + tx.wallet = { copayerId: 'yepNope' }; + if (!tx.wallet) { + this.logger.info('no wallet at txp?'); + return; + } - if (!tx.wallet) { - this.logger.info('no wallet at txp?'); - return; - } - - const pTx = await this.processTx(tx); + const pTx = await this.processTx(tx); - let action: any = _.find(pTx.actions, { - copayerId: pTx.wallet.copayerId - }); + let action: any = _.find(pTx.actions, { + copayerId: pTx.wallet.copayerId, + }); - if (!action && pTx.status == 'pending') { - pTx.pendingForUs = true; - } + if (!action && pTx.status == 'pending') { + pTx.pendingForUs = true; + } - if (action && action.type == 'accept') { - pTx.statusForUs = 'accepted'; - } else if (action && action.type == 'reject') { - pTx.statusForUs = 'rejected'; - } else { - pTx.statusForUs = 'pending'; - } + if (action && action.type == 'accept') { + pTx.statusForUs = 'accepted'; + } else if (action && action.type == 'reject') { + pTx.statusForUs = 'rejected'; + } else { + pTx.statusForUs = 'pending'; + } - if (!pTx.deleteLockTime) - pTx.canBeRemoved = true; + if (!pTx.deleteLockTime) pTx.canBeRemoved = true; - return pTx; - })); + return pTx; + }), + ); this.logger.warn('What are the TXPs after promise all?'); this.logger.warn(pTxps); @@ -203,9 +200,8 @@ export class TxFormatService { currency: currency, alternativeIsoCode: alternativeIsoCode, amountMicros: amountMicros, - amountUnitStr: amountUnitStr + amountUnitStr: amountUnitStr, }; - } satToUnit(amount: any) { @@ -216,5 +212,4 @@ export class TxFormatService { let unitDecimals = settings.unitDecimals; return parseFloat((amount * satToUnit).toFixed(unitDecimals)); } - } diff --git a/packages/lightwallet/common/services/unlock-request.service.ts b/packages/lightwallet/common/services/unlock-request.service.ts index adc51fc48f..f18e6c0f4e 100644 --- a/packages/lightwallet/common/services/unlock-request.service.ts +++ b/packages/lightwallet/common/services/unlock-request.service.ts @@ -23,18 +23,18 @@ export interface IUnlockRequest { @Injectable() export class UnlockRequestService { - hiddenAddresses: Array; activeRequestsNumber: number; hiddenRequests: Array = []; confirmedRequests: Array = []; activeRequests: Array = []; - constructor(private profileService: ProfileService, - private persistenseService: PersistenceService, - private walletService: WalletService, - private contactsService: ContactsService) { - } + constructor( + private profileService: ProfileService, + private persistenseService: PersistenceService, + private walletService: WalletService, + private contactsService: ContactsService, + ) {} //todo subscribe to new block event, then update info async loadRequestsData() { @@ -46,26 +46,27 @@ export class UnlockRequestService { let requests = { hidden: [], active: [], confirmed: [] }; const wallets = await this.profileService.getWallets(); - const updateWallets = (requests) => wallets.map(async (w) => { - const rqs = await w.getUnlockRequests(); - rqs.forEach(request => { - request.walletClient = w; - if (request.isConfirmed) { - request.status = 'accepted'; - const foundContacts = this.contactsService.searchContacts(knownContacts, request.address); - if (foundContacts.length) { - request.contact = foundContacts[0]; + const updateWallets = requests => + wallets.map(async w => { + const rqs = await w.getUnlockRequests(); + rqs.forEach(request => { + request.walletClient = w; + if (request.isConfirmed) { + request.status = 'accepted'; + const foundContacts = this.contactsService.searchContacts(knownContacts, request.address); + if (foundContacts.length) { + request.contact = foundContacts[0]; + } + requests.confirmed.push(request); + } else if (this.hiddenAddresses.indexOf(request.address) != -1) { + request.status = 'hidden'; + requests.hidden.push(request); + } else { + request.status = 'pending'; + requests.active.push(request); } - requests.confirmed.push(request); - } else if (this.hiddenAddresses.indexOf(request.address) != -1) { - request.status = 'hidden'; - requests.hidden.push(request); - } else { - request.status = 'pending'; - requests.active.push(request); - } - }) - }); + }); + }); await Promise.all(updateWallets(requests)); diff --git a/packages/lightwallet/common/services/vaults.service.ts b/packages/lightwallet/common/services/vaults.service.ts index 89a26b7834..1de224fa9a 100644 --- a/packages/lightwallet/common/services/vaults.service.ts +++ b/packages/lightwallet/common/services/vaults.service.ts @@ -1,10 +1,10 @@ import { Injectable } from '@angular/core'; import { LoggerService } from '@merit/common/services/logger.service'; -import { IVault } from "@merit/common/models/vault"; +import { IVault } from '@merit/common/models/vault'; import { WalletService } from '@merit/common/services/wallet.service'; import { ProfileService } from '@merit/common/services/profile.service'; -import { RateService } from "@merit/common/services/rate.service"; +import { RateService } from '@merit/common/services/rate.service'; import { MeritWalletClient } from '@merit/common/merit-wallet-client'; import { Constants } from '@merit/common/merit-wallet-client/lib/common/constants'; import { FeeService } from '@merit/common/services/fee.service'; @@ -12,24 +12,22 @@ import { ENV } from '@app/env'; import { HDPrivateKey, Address, Script, Transaction, PublicKey, Opcode, crypto } from 'meritcore-lib'; export interface IVaultCreateData { - vaultName: string, - whiteList: Array, - wallet: MeritWalletClient, - amount: number, - masterKey: {key: any, phrase: string} + vaultName: string; + whiteList: Array; + wallet: MeritWalletClient; + amount: number; + masterKey: { key: any; phrase: string }; } @Injectable() export class VaultsService { - constructor( private logger: LoggerService, private walletService: WalletService, private profileService: ProfileService, private rateService: RateService, - private feeService: FeeService - ) { - } + private feeService: FeeService, + ) {} /** * Receiving fresh data from MWS db, does not look into blockchain @@ -49,7 +47,7 @@ export class VaultsService { * Changing only name in MWS, no transactions created */ async editVaultName(vault: IVault, newName: string) { - return vault.walletClient.updateVaultInfo({_id: vault._id, name: newName}); + return vault.walletClient.updateVaultInfo({ _id: vault._id, name: newName }); } /** @@ -62,7 +60,7 @@ export class VaultsService { const fee = await this.feeService.getTxpFee(txp); const tx = await this.getSendTxp(vault, amount, toAddress, fee); await vault.walletClient.broadcastRawTx({ rawTx: tx.serialize(), network: ENV.network }); - await vault.walletClient.updateVaultInfo({_id: vault._id}); + await vault.walletClient.updateVaultInfo({ _id: vault._id }); vault = await this.getVaultInfo(vault); await this.profileService.updateVault(vault); @@ -70,9 +68,9 @@ export class VaultsService { } /** - * renewing vault means changing whitelist. Address and redeem script stays the same, but scriptPubKey changes - * so we take all utxos and send them to the same address but differrent scriptPubkey - */ + * renewing vault means changing whitelist. Address and redeem script stays the same, but scriptPubKey changes + * so we take all utxos and send them to the same address but differrent scriptPubkey + */ async renewVaultWhitelist(vault: IVault, newWhitelist: Array, masterKey) { vault = await this.getVaultInfo(vault); @@ -87,18 +85,18 @@ export class VaultsService { _id: vault._id, status: 'renewing', whitelist: newWhitelist, - initialTxId: txid + initialTxId: txid, }; return vault.walletClient.updateVaultInfo(infoToUpdate); } /** - * create and deposit new vault - */ + * create and deposit new vault + */ async createVault(data: IVaultCreateData) { await this.checkCreateData(data); - const vault:any = this.prepareVault(0, { + const vault: any = this.prepareVault(0, { whitelist: data.whiteList.map(w => w.rootAddress.toBuffer()), masterPubKey: data.masterKey.key.publicKey, spendPubKey: HDPrivateKey.fromString(data.wallet.credentials.xPrivKey).publicKey, @@ -110,7 +108,7 @@ export class VaultsService { signPrivKey: data.masterKey.key.privateKey, address: vault.address.toString(), addressType: Address.ParameterizedPayToScriptHashType, // pubkey address - network: data.wallet.credentials.network + network: data.wallet.credentials.network, }; //todo use wallet decrypt-encrypt decorator @@ -119,7 +117,7 @@ export class VaultsService { await this.walletService.sendInvite(data.wallet, scriptReferralOpts.address, 1, vault.scriptPubKey.toHex()); vault.scriptPubKey = vault.scriptPubKey.toBuffer().toString('hex'); - const depositData = {amount: data.amount, address: vault.address, scriptPubKey: vault.scriptPubKey}; + const depositData = { amount: data.amount, address: vault.address, scriptPubKey: vault.scriptPubKey }; const txp = await this.getDepositTxp(depositData, data.wallet); const pubTxp = await this.walletService.publishTx(data.wallet, txp); //todo wallet should be decrypted by the moment @@ -135,32 +133,36 @@ export class VaultsService { } /** - * sending money to existing vault - */ + * sending money to existing vault + */ async depositVault(vault, amount) { vault = await this.getVaultInfo(vault); const address = Address(vault.address); - const scriptPubKey = Script(vault.scriptPubKey).toBuffer().toString('hex'); - const txp = await this.getDepositTxp({address, scriptPubKey, amount}, vault.walletClient); + const scriptPubKey = Script(vault.scriptPubKey) + .toBuffer() + .toString('hex'); + const txp = await this.getDepositTxp({ address, scriptPubKey, amount }, vault.walletClient); await this.walletService.publishAndSign(vault.walletClient, txp); - await vault.walletClient.updateVaultInfo({_id: vault._id, name: vault.name}); + await vault.walletClient.updateVaultInfo({ _id: vault._id, name: vault.name }); vault = await this.getVaultInfo(vault); await this.profileService.updateVault(vault); return vault; } /** - * check if we can create vault - */ + * check if we can create vault + */ private async checkCreateData(data) { if ( - !data.vaultName - || !data.wallet - || !data.whiteList - || !data.whiteList.length - || !data.amount - || !data.masterKey || !data.masterKey.key || !data.masterKey.phrase + !data.vaultName || + !data.wallet || + !data.whiteList || + !data.whiteList.length || + !data.amount || + !data.masterKey || + !data.masterKey.key || + !data.masterKey.phrase ) { this.logger.warn('Incorrect data', data); throw new Error('Incorrect data'); @@ -172,16 +174,16 @@ export class VaultsService { throw new Error("You don't have any active invites that you can use to create a vault"); } if (data.amount > data.wallet.balance.spendableAmount) { - throw new Error("Wallet balance is less than vault balance"); + throw new Error('Wallet balance is less than vault balance'); } return true; } /** - * renewing vault means changing whitelist. Address and redeem script stays the same, but scriptPubKey changes - * so we take all utxos and send them to the same address but differrent scriptPubkey - */ + * renewing vault means changing whitelist. Address and redeem script stays the same, but scriptPubKey changes + * so we take all utxos and send them to the same address but differrent scriptPubkey + */ private getRenewTxp(vault, newWhitelist, masterKey, fee = FeeService.DEFAULT_FEE) { const amount = vault.amount - fee; @@ -191,7 +193,7 @@ export class VaultsService { let params = [ new PublicKey(vault.spendPubKey, { network: ENV.network }).toBuffer(), - new PublicKey(vault.masterPubKey, { network: ENV.network }).toBuffer() + new PublicKey(vault.masterPubKey, { network: ENV.network }).toBuffer(), ]; const whitelist = newWhitelist.map(w => Address(w).hashBuffer); @@ -227,10 +229,9 @@ export class VaultsService { } /** - * creating transaction to transfer money from vault to one of whitelisted addresses - */ + * creating transaction to transfer money from vault to one of whitelisted addresses + */ private getSendTxp(vault, amount, address, fee = FeeService.DEFAULT_FEE) { - if (vault.type != 0) throw new Error('Vault type is not supported'); //todo why are we using wallet private key here??? @@ -238,13 +239,13 @@ export class VaultsService { let selectedCoins = []; let selectedAmount = 0; - for(let c = 0; c < vault.coins.length && selectedAmount < amount; c++) { + for (let c = 0; c < vault.coins.length && selectedAmount < amount; c++) { let coin = vault.coins[c]; selectedAmount += coin.micros; selectedCoins.push(coin); } - if(selectedAmount < amount) throw new Error('Insufficient funds'); + if (selectedAmount < amount) throw new Error('Insufficient funds'); const change = selectedAmount - amount; @@ -268,10 +269,12 @@ export class VaultsService { let scriptPubKey = Script.buildMixedParameterizedP2SH(redeemScript, params, vault.masterPubKey); - tx.addOutput(Transaction.Output({ - script: scriptPubKey, - micros: change - })); + tx.addOutput( + Transaction.Output({ + script: scriptPubKey, + micros: change, + }), + ); tx.fee(fee); @@ -290,29 +293,30 @@ export class VaultsService { }); return tx; - } /** - * transfer money to vault - */ + * transfer money to vault + */ private async getDepositTxp(vault: any, wallet: MeritWalletClient): Promise { let feeLevel = this.feeService.getCurrentFeeLevel(); - if (vault.amount > Number.MAX_SAFE_INTEGER) throw new Error('The amount is too big'); // Because Javascript + if (vault.amount > Number.MAX_SAFE_INTEGER) throw new Error('The amount is too big'); // Because Javascript - let txp:any = { - outputs: [{ - 'toAddress': vault.address.toString(), - 'script': vault.scriptPubKey, - 'amount': vault.amount - }], + let txp: any = { + outputs: [ + { + toAddress: vault.address.toString(), + script: vault.scriptPubKey, + amount: vault.amount, + }, + ], addressType: 'PP2SH', inputs: null, //Let Merit wallet service figure out the inputs based - //on the selected wallet. + //on the selected wallet. feeLevel: feeLevel, excludeUnconfirmedUtxos: true, - dryRun: true + dryRun: true, }; if (vault.amount == wallet.balance.totalConfirmedAmount) { delete txp.outputs[0].amount; @@ -331,21 +335,16 @@ export class VaultsService { } /** - * create vautl object before transfering Merit - */ + * create vautl object before transfering Merit + */ private prepareVault(type: number, opts: any = {}) { - if (type != 0) throw new Error('Vault type is not supported'); let tag = opts.masterPubKey.toAddress().hashBuffer; let whitelist = opts.whitelist.map(w => Address(w).hashBuffer); - let params = [ - opts.spendPubKey.toBuffer(), - opts.masterPubKey.toBuffer(), - ]; - + let params = [opts.spendPubKey.toBuffer(), opts.masterPubKey.toBuffer()]; const spendLimit = this.rateService.mrtToMicro(Constants.VAULT_SPEND_LIMIT); params.push(crypto.BN.fromNumber(spendLimit).toScriptNumBuffer()); @@ -365,10 +364,9 @@ export class VaultsService { masterPubKey: opts.masterPubKey, redeemScript: redeemScript, scriptPubKey: scriptPubKey, - address: Address(scriptPubKey.getAddressInfo()) + address: Address(scriptPubKey.getAddressInfo()), }; return vault; } - } diff --git a/packages/lightwallet/common/services/wallet.service.ts b/packages/lightwallet/common/services/wallet.service.ts index b411505d86..202bd4140a 100644 --- a/packages/lightwallet/common/services/wallet.service.ts +++ b/packages/lightwallet/common/services/wallet.service.ts @@ -11,13 +11,11 @@ import { PersistenceService } from '@merit/common/services/persistence.service'; import { ProfileService } from '@merit/common/services/profile.service'; import { Events } from 'ionic-angular/util/events'; import * as _ from 'lodash'; -import { AlertService } from "@merit/common/services/alert.service"; - +import { AlertService } from '@merit/common/services/alert.service'; export function accessWallet(target, key: string, descriptor: any) { - return { - value: async function (...args:any[]) { + value: async function(...args: any[]) { const wallet: MeritWalletClient = args[0]; if (!wallet || !wallet.credentials) { @@ -49,26 +47,23 @@ export function accessWallet(target, key: string, descriptor: any) { } } return result; - } - + }, }; } @Injectable() export class WalletService { - - - constructor(private logger: LoggerService, - private mwcService: MWCService, - private configService: ConfigService, - private profileService: ProfileService, - private persistenceService: PersistenceService, - private mnemonicService: MnemonicService, - private easySendService: EasySendService, - private events: Events, - private alertCtrl: AlertService - ) { - } + constructor( + private logger: LoggerService, + private mwcService: MWCService, + private configService: ConfigService, + private profileService: ProfileService, + private persistenceService: PersistenceService, + private mnemonicService: MnemonicService, + private easySendService: EasySendService, + private events: Events, + private alertCtrl: AlertService, + ) {} isWalletEncrypted(wallet: MeritWalletClient) { return wallet.isPrivKeyEncrypted(); @@ -77,7 +72,7 @@ export class WalletService { encryptWallet(wallet: MeritWalletClient, password: string): Promise { wallet.encryptPrivateKey(password, {}); return this.profileService.updateWallet(wallet); - }; + } decryptWallet(wallet: MeritWalletClient, password: string) { return wallet.decryptPrivateKey(password); @@ -106,8 +101,7 @@ export class WalletService { @accessWallet broadcastTx(wallet: MeritWalletClient, txp: any): Promise { - if (txp.status != 'accepted') - throw new Error('TX_NOT_ACCEPTED'); + if (txp.status != 'accepted') throw new Error('TX_NOT_ACCEPTED'); return wallet.broadcastTxProposal(txp); } @@ -135,7 +129,6 @@ export class WalletService { @accessWallet async publishAndSign(wallet: MeritWalletClient, txp: any): Promise { - if (txp.status != 'pending') { txp = await this.publishTx(wallet, txp); } @@ -168,16 +161,24 @@ export class WalletService { * */ @accessWallet - async sendInvite(wallet: MeritWalletClient, toAddress: string, amount: number = 1, script = null, message: string = ''): Promise { + async sendInvite( + wallet: MeritWalletClient, + toAddress: string, + amount: number = 1, + script = null, + message: string = '', + ): Promise { amount = parseInt(amount as any); const opts = { invite: true, - outputs: [_.pickBy({ - amount, - toAddress, - message, - script - })] + outputs: [ + _.pickBy({ + amount, + toAddress, + message, + script, + }), + ], }; let txp = await wallet.createTxProposal(opts); @@ -207,7 +208,6 @@ export class WalletService { return easySend; } - /** =================== CREATE WALLET METHODS ================ */ createDefaultWallet(parentAddress: string, alias: string) { @@ -233,7 +233,7 @@ export class WalletService { singleAddress: opts.singleAddress, walletPrivKey: opts.walletPrivKey, parentAddress: opts.parentAddress, - alias: opts.alias + alias: opts.alias, }); await this.profileService.addWallet(wallet); @@ -243,7 +243,6 @@ export class WalletService { // TODO: Rename this. private async seedWallet(opts: any): Promise { - let walletClient = this.mwcService.getClient(null, opts); if (opts.mnemonic) { @@ -256,9 +255,9 @@ export class WalletService { } else if (opts.extendedPrivateKey) { try { walletClient.seedFromExtendedPrivateKey(opts.extendedPrivateKey, { - network: ENV.network, + network: ENV.network, account: opts.account || 0, - derivationStrategy: opts.derivationStrategy || 'BIP44' + derivationStrategy: opts.derivationStrategy || 'BIP44', }); } catch (ex) { this.logger.warn(ex); @@ -268,7 +267,7 @@ export class WalletService { try { walletClient.seedFromExtendedPublicKey(opts.extendedPublicKey, opts.externalSource, opts.entropySource, { account: opts.account || 0, - derivationStrategy: opts.derivationStrategy || 'BIP44' + derivationStrategy: opts.derivationStrategy || 'BIP44', }); walletClient.credentials.hwInfo = opts.hwInfo; } catch (ex) { @@ -276,11 +275,11 @@ export class WalletService { throw new Error('Could not create using the specified extended key'); // TODO GetTextCatalog } } else { - walletClient.seedFromRandomWithMnemonic({ - network: ENV.network, - passphrase: opts.passphrase, - account: 0 - }); + walletClient.seedFromRandomWithMnemonic({ + network: ENV.network, + passphrase: opts.passphrase, + account: 0, + }); } return walletClient; } @@ -290,7 +289,7 @@ export class WalletService { const encodingType = { mnemonic: 1, xpriv: 2, - xpub: 3 + xpub: 3, }; let info: any = {}; @@ -302,41 +301,47 @@ export class WalletService { if (keys.mnemonic) { info = { type: encodingType.mnemonic, - data: keys.mnemonic + data: keys.mnemonic, }; } else { info = { type: encodingType.xpriv, - data: keys.xPrivKey + data: keys.xPrivKey, }; } - return info.type + '|' + info.data + '|' + wallet.credentials.network.toLowerCase() + '|' + derivationPath + '|' + (wallet.credentials.mnemonicHasPassphrase); + return ( + info.type + + '|' + + info.data + + '|' + + wallet.credentials.network.toLowerCase() + + '|' + + derivationPath + + '|' + + wallet.credentials.mnemonicHasPassphrase + ); } - /** ================ PREFERENCES METHODS ======================== **/ async setHiddenBalanceOption(walletId: string, hideBalance: boolean): Promise { - await this.persistenceService.setHideBalanceFlag(walletId, String(hideBalance)); + await this.persistenceService.setHideBalanceFlag(walletId, String(hideBalance)); } private updateRemotePreferencesFor(clients: any[], prefs: any): Promise { - return Promise.all(clients.map((wallet: any) => - wallet.savePreferences(prefs) - )); + return Promise.all(clients.map((wallet: any) => wallet.savePreferences(prefs))); } async updateRemotePreferences(clients: any[], prefs: any = {}): Promise { - if (!_.isArray(clients)) - clients = [clients]; + if (!_.isArray(clients)) clients = [clients]; // Update this JIC. let config: any = this.configService.get(); prefs.email = config.emailNotifications.email; prefs.language = 'en'; - Promise.all(clients.map(async (w) => w.savePreferences(prefs) )); + Promise.all(clients.map(async w => w.savePreferences(prefs))); clients.forEach(c => { c.preferences = _.assign(prefs, c.preferences); @@ -351,7 +356,7 @@ export class WalletService { try { await walletClient.importFromExtendedPublicKey(opts.extendedPublicKey, opts.externalSource, opts.entropySource, { account: opts.account || 0, - derivationStrategy: opts.derivationStrategy || 'BIP44' + derivationStrategy: opts.derivationStrategy || 'BIP44', }); return this.profileService.addWallet(walletClient); @@ -362,7 +367,6 @@ export class WalletService { } async importExtendedPrivateKey(xPrivKey: string, opts: any): Promise { - const walletClient = this.mwcService.getClient(null, opts); this.logger.debug('Importing Wallet xPrivKey'); @@ -398,5 +402,4 @@ export class WalletService { throw new Error('Could not import. Check input file and spending password'); // TODO getTextCatalog } } - } diff --git a/packages/lightwallet/common/services/web-push-notifications.service.ts b/packages/lightwallet/common/services/web-push-notifications.service.ts index 439ec882a2..7a6461cbcf 100644 --- a/packages/lightwallet/common/services/web-push-notifications.service.ts +++ b/packages/lightwallet/common/services/web-push-notifications.service.ts @@ -17,13 +17,11 @@ import { filter, map, take } from 'rxjs/operators'; const FirebaseAppConfig = { apiKey: 'APIKEY', projectId: 'prime-service-181121', - messagingSenderId: '1091326413792' + messagingSenderId: '1091326413792', }; - @Injectable() export class WebPushNotificationsService extends PushNotificationsService { - protected get pushNotificationsEnabled(): boolean { return this._pushNotificationsEnabled; } @@ -37,11 +35,13 @@ export class WebPushNotificationsService extends PushNotificationsService { private firebaseApp; private firebaseMessaging; - constructor(http: HttpClient, - logger: LoggerService, - private pollingNotificationService: PollingNotificationsService, - private persistenceService: PersistenceService2, - private store: Store) { + constructor( + http: HttpClient, + logger: LoggerService, + private pollingNotificationService: PollingNotificationsService, + private persistenceService: PersistenceService2, + private store: Store, + ) { super(http, logger); this.logger.info('Web PushNotifications service is alive!'); this.platform = 'web'; @@ -49,11 +49,12 @@ export class WebPushNotificationsService extends PushNotificationsService { } getWallets() { - return this.store.select(selectWallets) + return this.store + .select(selectWallets) .pipe( filter((wallets: DisplayWallet[]) => wallets && wallets.length > 0), take(1), - map((wallets: DisplayWallet[]) => wallets.map(wallet => wallet.client)) + map((wallets: DisplayWallet[]) => wallets.map(wallet => wallet.client)), ) .toPromise(); } @@ -82,7 +83,7 @@ export class WebPushNotificationsService extends PushNotificationsService { if (this.pushNotificationsEnabled) { if (!this.token) { - this.firebaseApp = firebase.apps.length? firebase.app() : firebase.initializeApp(FirebaseAppConfig); + this.firebaseApp = firebase.apps.length ? firebase.app() : firebase.initializeApp(FirebaseAppConfig); this.firebaseMessaging = firebase.messaging(this.firebaseApp); await this.registerSW(); try { @@ -94,7 +95,7 @@ export class WebPushNotificationsService extends PushNotificationsService { this._hasPermission = false; await this.persistenceService.setNotificationSettings({ ...settings, - pushNotifications: false + pushNotifications: false, }); this.enablePolling(); return; @@ -125,17 +126,21 @@ export class WebPushNotificationsService extends PushNotificationsService { async subscribeToEvents() { this.firebaseMessaging.onMessage((data: NotificationData) => { if (data.data) { - this.store.dispatch(new AddNotificationAction({ - ...data.data, - timestamp: Date.now(), - read: false - })); + this.store.dispatch( + new AddNotificationAction({ + ...data.data, + timestamp: Date.now(), + read: false, + }), + ); if (data.data.walletId) { - this.store.dispatch(new RefreshOneWalletAction(data.data.walletId, { - skipAlias: true, - skipShareCode: true - })); + this.store.dispatch( + new RefreshOneWalletAction(data.data.walletId, { + skipAlias: true, + skipShareCode: true, + }), + ); } } }); diff --git a/packages/lightwallet/common/utils/constants.ts b/packages/lightwallet/common/utils/constants.ts index f6bae6e21a..539768ee6b 100644 --- a/packages/lightwallet/common/utils/constants.ts +++ b/packages/lightwallet/common/utils/constants.ts @@ -1,11 +1,10 @@ import { ModalOptions } from 'ionic-angular'; import { ENV } from '@app/env'; - export const MERIT_MODAL_OPTS: ModalOptions = { leaveAnimation: 'modal-slide-out', enterAnimation: 'modal-slide-in', - cssClass: 'merit-modal' + cssClass: 'merit-modal', }; export const COINBASE_CONFIRMATION_THRESHOLD = ENV.network == 'testnet' ? 6 : 100; @@ -22,7 +21,7 @@ export const UNITS = { short: { maxDecimals: 6, minDecimals: 2, - } + }, }, bit: { toMicros: 100, @@ -33,6 +32,6 @@ export const UNITS = { short: { maxDecimals: 0, minDecimals: 0, - } + }, }, }; diff --git a/packages/lightwallet/common/utils/contacts.ts b/packages/lightwallet/common/utils/contacts.ts index a48afcc2f7..aa99630360 100644 --- a/packages/lightwallet/common/utils/contacts.ts +++ b/packages/lightwallet/common/utils/contacts.ts @@ -4,7 +4,10 @@ import { clone, isEmpty } from 'lodash'; export function getContactInitials(contact: IContactProperties) { if (!contact.name || !contact.name.formatted) return ''; - const nameParts = contact.name.formatted.toUpperCase().replace(/\s\s+/g, ' ').split(' '); + const nameParts = contact.name.formatted + .toUpperCase() + .replace(/\s\s+/g, ' ') + .split(' '); let name = nameParts[0].charAt(0); if (nameParts[1]) name += '' + nameParts[1].charAt(0); return name; @@ -18,7 +21,7 @@ export function createMeritContact(contact: Partial): MeritC meritContact.phoneNumbers = clone(contact.phoneNumbers) || []; meritContact.emails = clone(contact.emails) || []; meritContact.photos = clone(contact.photos) || []; - meritContact.meritAddresses = isEmpty(contact['meritAddresses'])? [] : clone(contact['meritAddresses']); + meritContact.meritAddresses = isEmpty(contact['meritAddresses']) ? [] : clone(contact['meritAddresses']); return meritContact; } diff --git a/packages/lightwallet/common/utils/derivation-path.ts b/packages/lightwallet/common/utils/derivation-path.ts index 8e38770c58..fa3f233b97 100644 --- a/packages/lightwallet/common/utils/derivation-path.ts +++ b/packages/lightwallet/common/utils/derivation-path.ts @@ -12,20 +12,19 @@ export class DerivationPath { let ret: any = {}; - if (arr[0] != 'm') - return false; + if (arr[0] != 'm') return false; switch (arr[1]) { - case '44\'': + case "44'": ret.derivationStrategy = 'BIP44'; break; - case '45\'': + case "45'": return { derivationStrategy: 'BIP45', networkName: 'livenet', account: 0, }; - case '48\'': + case "48'": ret.derivationStrategy = 'BIP48'; break; default: @@ -33,10 +32,10 @@ export class DerivationPath { } switch (arr[2]) { - case '0\'': + case "0'": ret.networkName = 'livenet'; break; - case '1\'': + case "1'": ret.networkName = 'testnet'; break; default: @@ -44,8 +43,7 @@ export class DerivationPath { } let match = arr[3].match(/(\d+)'/); - if (!match) - return false; + if (!match) return false; ret.account = +match[1]; return ret; diff --git a/packages/lightwallet/common/utils/destination.spec.ts b/packages/lightwallet/common/utils/destination.spec.ts index bf88a61733..368469131e 100644 --- a/packages/lightwallet/common/utils/destination.spec.ts +++ b/packages/lightwallet/common/utils/destination.spec.ts @@ -2,12 +2,11 @@ import { SendMethodDestination } from '@merit/common/models/send-method'; import { getSendMethodDestinationType, validateEmail, validatePhoneNumber } from '@merit/common/utils/destination'; describe('[Validators] Destination', () => { - it('should validate email', () => { expect(validateEmail('hello@merit.me')).toBeTruthy(); }); - it('should return type as email', () =>{ + it('should return type as email', () => { expect(getSendMethodDestinationType('hello@merit.me')).toBe(SendMethodDestination.Email); }); @@ -19,8 +18,7 @@ describe('[Validators] Destination', () => { expect(getSendMethodDestinationType('8444169972')).toBe(SendMethodDestination.Sms); }); - it('should return type as null if it\'s not a phone number or email', () => { + it("should return type as null if it's not a phone number or email", () => { expect(getSendMethodDestinationType('definitely nothing valid')).toBeFalsy(); }); - }); diff --git a/packages/lightwallet/common/utils/destination.ts b/packages/lightwallet/common/utils/destination.ts index af58d23967..903367acbc 100644 --- a/packages/lightwallet/common/utils/destination.ts +++ b/packages/lightwallet/common/utils/destination.ts @@ -4,7 +4,11 @@ const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+" export function validateEmail(email: string) { email = email || ''; - return EMAIL_REGEX.test(String(email).trim().toLowerCase()); + return EMAIL_REGEX.test( + String(email) + .trim() + .toLowerCase(), + ); } export function validatePhoneNumber(phoneNumber: string) { diff --git a/packages/lightwallet/common/utils/format.ts b/packages/lightwallet/common/utils/format.ts index 596789a643..b3e42465f1 100644 --- a/packages/lightwallet/common/utils/format.ts +++ b/packages/lightwallet/common/utils/format.ts @@ -26,6 +26,6 @@ export const formatAmount = (micros: number, unit: string, opts: any = {}): stri if (!u) throw new Error('Invalid unit'); const precision: string = opts.fullPrecision ? 'full' : 'short', - amount: string = clipDecimals((micros / u.toMicros), u[precision].maxDecimals).toFixed(u[precision].maxDecimals); + amount: string = clipDecimals(micros / u.toMicros, u[precision].maxDecimals).toFixed(u[precision].maxDecimals); return addSeparators(amount, opts.thousandsSeparator || ',', opts.decimalSeparator || '.', u[precision].minDecimals); }; diff --git a/packages/lightwallet/common/utils/invites.ts b/packages/lightwallet/common/utils/invites.ts index 295d55bd11..f3e38a1ae8 100644 --- a/packages/lightwallet/common/utils/invites.ts +++ b/packages/lightwallet/common/utils/invites.ts @@ -1,5 +1,5 @@ import { MWCService } from '@merit/common/services/mwc.service'; export function getSendableInvites(mwcService: MWCService) { - return mwcService.getClient().invitesBalance.availableAmount -1; + return mwcService.getClient().invitesBalance.availableAmount - 1; } diff --git a/packages/lightwallet/common/utils/mnemonic.spec.ts b/packages/lightwallet/common/utils/mnemonic.spec.ts index 19ff77b443..42293f69f7 100644 --- a/packages/lightwallet/common/utils/mnemonic.spec.ts +++ b/packages/lightwallet/common/utils/mnemonic.spec.ts @@ -1,7 +1,6 @@ import { hasValidEntropy, hasValidWords, isValidSize } from './mnemonic'; describe('Utils.Mnemonic', () => { - it('12 words mnemonic should be valid size', () => { expect(isValidSize('chair sing cool west birth stock disease sniff bulb surround absorb design')).toBeTruthy(); }); @@ -11,11 +10,12 @@ describe('Utils.Mnemonic', () => { }); it('mnemonic should be valid', () => { - expect(hasValidEntropy('miracle tilt alone fresh sustain course awesome holiday fix tuna vital ginger')).toBeTruthy(); + expect( + hasValidEntropy('miracle tilt alone fresh sustain course awesome holiday fix tuna vital ginger'), + ).toBeTruthy(); }); it('mnemonic should be invalid', () => { expect(hasValidEntropy('chair sing cool west birth stock disease sniff bulb surround absorb design')).toBeFalsy(); }); - }); diff --git a/packages/lightwallet/common/utils/mnemonic.ts b/packages/lightwallet/common/utils/mnemonic.ts index 5d3301f40b..a0aac30ab1 100644 --- a/packages/lightwallet/common/utils/mnemonic.ts +++ b/packages/lightwallet/common/utils/mnemonic.ts @@ -34,15 +34,15 @@ export function isValidSize(mnemonic: string) { } export function hasValidWords(mnemonic: string, wordlist: string[] = EnglishWordlist) { - return !mnemonic.split(' ') - .some((word: string) => wordlist.indexOf(word) === -1); + return !mnemonic.split(' ').some((word: string) => wordlist.indexOf(word) === -1); } export function hasValidEntropy(mnemonic: string, wordlist: string[] = EnglishWordlist) { const words = mnemonic.split(' '); let bin = ''; - let i = 0, ind; + let i = 0, + ind; for (i; i < words.length; i++) { ind = wordlist.indexOf(words[i]); @@ -69,7 +69,9 @@ export function mnemonicToHDPrivateKey(mnemonic, passphrase, network) { } function entropyChecksum(entropy: Buffer): string { - const hash = createHash('sha256').update(entropy).digest(), + const hash = createHash('sha256') + .update(entropy) + .digest(), bits = entropy.length * 8, cs = bits / 32; diff --git a/packages/lightwallet/common/utils/notification-settings.ts b/packages/lightwallet/common/utils/notification-settings.ts index a387252a5c..d0a1005b53 100644 --- a/packages/lightwallet/common/utils/notification-settings.ts +++ b/packages/lightwallet/common/utils/notification-settings.ts @@ -14,9 +14,7 @@ import { Subscription } from 'rxjs/Subscription'; import { SmsNotificationSetting } from '@merit/common/models/sms-subscription'; export type SavingStatus = 'saving' | 'saved' | 'none'; -export type SmsNotificationSettingsText = { - [k in keyof typeof SmsNotificationSetting]: string; -} +export type SmsNotificationSettingsText = { [k in keyof typeof SmsNotificationSetting]: string }; const smsNotificationSettingsText: SmsNotificationSettingsText = { IncomingInvite: 'Incoming invites', @@ -35,7 +33,7 @@ export class NotificationSettingsController { emailNotifications: [false, [Validators.required]], email: [''], smsNotifications: [false], - phoneNumber: ['', [Validators.required, Validators.pattern(/\d{10,}/)]] + phoneNumber: ['', [Validators.required, Validators.pattern(/\d{10,}/)]], }); private subs: Subscription[] = []; private emailStatus: Subject = new Subject(); @@ -69,13 +67,15 @@ export class NotificationSettingsController { return this.formData.get('phoneNumber'); } - constructor(private persistenceService: PersistenceService2, - private pushNotificationsService: PushNotificationsService, - private emailNotificationsService: EmailNotificationsService, - private smsNotificationsService: SmsNotificationsService, - private formBuilder: FormBuilder, - private toastCtrl: ToastControllerService, - private platform: 'ios' | 'android' | 'desktop') {} + constructor( + private persistenceService: PersistenceService2, + private pushNotificationsService: PushNotificationsService, + private emailNotificationsService: EmailNotificationsService, + private smsNotificationsService: SmsNotificationsService, + private formBuilder: FormBuilder, + private toastCtrl: ToastControllerService, + private platform: 'ios' | 'android' | 'desktop', + ) {} async init() { const settings = await this.persistenceService.getNotificationSettings(); @@ -84,15 +84,17 @@ export class NotificationSettingsController { const smsNotificationSettings = []; - Object.keys(SmsNotificationSetting) - .forEach((key: keyof SmsNotificationSetting) => { - this.formData.addControl(SmsNotificationSetting[key], new FormControl(status && status.settings && status.settings[key])); + Object.keys(SmsNotificationSetting).forEach((key: keyof SmsNotificationSetting) => { + this.formData.addControl( + SmsNotificationSetting[key], + new FormControl(status && status.settings && status.settings[key]), + ); - smsNotificationSettings.push({ - name: SmsNotificationSetting[key], - label: smsNotificationSettingsText[key] - }); + smsNotificationSettings.push({ + name: SmsNotificationSetting[key], + label: smsNotificationSettingsText[key], }); + }); if (!isEmpty(settings)) { this.formData.patchValue(settings, { emitEvent: false }); @@ -109,9 +111,9 @@ export class NotificationSettingsController { this.formData.valueChanges .pipe( filter(() => this.formData.valid), - tap((newValue: any) => this.persistenceService.setNotificationSettings(newValue)) + tap((newValue: any) => this.persistenceService.setNotificationSettings(newValue)), ) - .subscribe() + .subscribe(), ); this.subs.push( @@ -125,9 +127,9 @@ export class NotificationSettingsController { } else { this.pushNotificationsService.disable(); } - }) + }), ) - .subscribe() + .subscribe(), ); this.subs.push( @@ -141,9 +143,9 @@ export class NotificationSettingsController { fromPromise( this.emailNotificationsService.updateEmail({ enabled: this.emailNotificationsEnabled, - email: this.email.value - }) - ) + email: this.email.value, + }), + ), ), tap(() => { this.emailStatus.next('saved'); @@ -151,22 +153,21 @@ export class NotificationSettingsController { this.toastCtrl.success('You are now subscribed to Email notifications!'); } this.updateStorage(); - }) + }), ) - .subscribe() + .subscribe(), ); const smsObservables = [ this.formData.get('smsNotifications').valueChanges, - this.formData.get('phoneNumber').valueChanges + this.formData.get('phoneNumber').valueChanges, ]; - this.smsNotificationSettings.forEach(({ name }) => - smsObservables.push(this.formData.get(name).valueChanges) - ); + this.smsNotificationSettings.forEach(({ name }) => smsObservables.push(this.formData.get(name).valueChanges)); this.subs.push( - merge.apply(merge, smsObservables) + merge + .apply(merge, smsObservables) .pipe( tap(() => this.smsStatus.next('none')), filter(() => this.smsNotifications.value == false || this.phoneNumber.valid), @@ -174,17 +175,22 @@ export class NotificationSettingsController { debounceTime(750), switchMap(() => fromPromise( - this.smsNotificationsService.setSmsSubscription(this.smsNotificationsEnabled, this.formData.get('phoneNumber').value, this.platform, this.getSmsNotificationSettings()) - ) + this.smsNotificationsService.setSmsSubscription( + this.smsNotificationsEnabled, + this.formData.get('phoneNumber').value, + this.platform, + this.getSmsNotificationSettings(), + ), + ), ), tap(() => { this.smsStatus.next('saved'); if (this.smsNotificationsEnabled && this.phoneNumber.valid) { this.toastCtrl.success('You are now subscribed to SMS notifications!'); } - }) + }), ) - .subscribe() + .subscribe(), ); } @@ -192,8 +198,7 @@ export class NotificationSettingsController { this.subs.forEach(sub => { try { sub.unsubscribe(); - } catch (e) { - } + } catch (e) {} }); } diff --git a/packages/lightwallet/common/utils/observables.ts b/packages/lightwallet/common/utils/observables.ts index 20b057107f..5ae56735b5 100644 --- a/packages/lightwallet/common/utils/observables.ts +++ b/packages/lightwallet/common/utils/observables.ts @@ -14,4 +14,5 @@ export const getLatestValue = (obs: Observable, filterFn?: (val: any) => bo return obs.pipe.apply(obs, args).toPromise(); }; -export const getLatestDefinedValue = (obs: Observable) => getLatestValue(obs, val => typeof val !== 'undefined' && val !== null); +export const getLatestDefinedValue = (obs: Observable) => + getLatestValue(obs, val => typeof val !== 'undefined' && val !== null); diff --git a/packages/lightwallet/common/utils/transactions.ts b/packages/lightwallet/common/utils/transactions.ts index 1400aa00b5..f4a2cc62ad 100644 --- a/packages/lightwallet/common/utils/transactions.ts +++ b/packages/lightwallet/common/utils/transactions.ts @@ -4,14 +4,21 @@ import { IDisplayTransaction, ITransactionIO, IVisitedTransaction, - TransactionAction + TransactionAction, } from '@merit/common/models/transaction'; import { ContactsService } from '@merit/common/services/contacts.service'; -import { MeritWalletClient } from "@merit/common/merit-wallet-client"; -import { FeeService } from "@merit/common/services/fee.service"; +import { MeritWalletClient } from '@merit/common/merit-wallet-client'; +import { FeeService } from '@merit/common/services/fee.service'; import { PersistenceService2 } from '@merit/common/services/persistence2.service'; -export async function formatWalletHistory(walletHistory: IDisplayTransaction[], wallet: MeritWalletClient, easySends: EasySend[] = [], feeService: FeeService, contactsProvider?: ContactsService, persistenceService?: PersistenceService2): Promise { +export async function formatWalletHistory( + walletHistory: IDisplayTransaction[], + wallet: MeritWalletClient, + easySends: EasySend[] = [], + feeService: FeeService, + contactsProvider?: ContactsService, + persistenceService?: PersistenceService2, +): Promise { if (_.isEmpty(walletHistory)) return []; const easyReceiveFee = await feeService.getEasyReceiveFee(); @@ -32,142 +39,161 @@ export async function formatWalletHistory(walletHistory: IDisplayTransaction[], let visitedTxs: IVisitedTransaction[]; if (persistenceService) { - visitedTxs = await persistenceService.getVisitedTransactions() || []; + visitedTxs = (await persistenceService.getVisitedTransactions()) || []; } - walletHistory = await Promise.all(walletHistory.map(async (tx: IDisplayTransaction, i: number) => { - if (!_.isNil(tx) && !_.isNil(tx.action)) { - pendingString = tx.isPendingEasySend ? '(pending) ' : ''; + walletHistory = await Promise.all( + walletHistory.map(async (tx: IDisplayTransaction, i: number) => { + if (!_.isNil(tx) && !_.isNil(tx.action)) { + pendingString = tx.isPendingEasySend ? '(pending) ' : ''; - let received: boolean = false, - isEasySend: boolean; + let received: boolean = false, + isEasySend: boolean; - switch (tx.action) { - case TransactionAction.SENT: - tx.type = 'debit'; - isEasySend = true; - break; - - case TransactionAction.RECEIVED: - tx.type = 'credit'; - - if (tx.isInvite) { - if (i === 0) { - tx.isWalletUnlock = true; - tx.name = 'Wallet Unlocked'; - } - } else { + switch (tx.action) { + case TransactionAction.SENT: + tx.type = 'debit'; isEasySend = true; - } + break; + + case TransactionAction.RECEIVED: + tx.type = 'credit'; + + if (tx.isInvite) { + if (i === 0) { + tx.isWalletUnlock = true; + tx.name = 'Wallet Unlocked'; + } + } else { + isEasySend = true; + } - received = true; - break; + received = true; + break; - case TransactionAction.MOVED: - tx.name = tx.actionStr = tx.isInvite ? 'Moved Invite' : 'Moved Merit'; - break; - } + case TransactionAction.MOVED: + tx.name = tx.actionStr = tx.isInvite ? 'Moved Invite' : 'Moved Merit'; + break; + } - const { alias: inputAlias, address: inputAddress } = tx.inputs.find((input: ITransactionIO) => input.isMine === !received) || {}; - const { alias: outputAlias, address: outputAddress } = tx.outputs.find((output: ITransactionIO) => output.isMine === received) || {}; + const { alias: inputAlias, address: inputAddress } = + tx.inputs.find((input: ITransactionIO) => input.isMine === !received) || {}; + const { alias: outputAlias, address: outputAddress } = + tx.outputs.find((output: ITransactionIO) => output.isMine === received) || {}; - tx.input = inputAlias ? '@' + inputAlias : 'Anonymous'; - tx.output = outputAlias ? '@' + outputAlias : 'Anonymous'; + tx.input = inputAlias ? '@' + inputAlias : 'Anonymous'; + tx.output = outputAlias ? '@' + outputAlias : 'Anonymous'; - tx.name = tx.name || (received ? tx.input : tx.output); + tx.name = tx.name || (received ? tx.input : tx.output); - tx.addressFrom = inputAlias || inputAddress; - tx.addressTo = outputAlias || outputAddress; + tx.addressFrom = inputAlias || inputAddress; + tx.addressTo = outputAlias || outputAddress; - tx.from = { - alias: inputAlias, - address: inputAddress - }; + tx.from = { + alias: inputAlias, + address: inputAddress, + }; - tx.to = { - alias: outputAlias, - address: outputAddress - }; + tx.to = { + alias: outputAlias, + address: outputAddress, + }; - if (!tx.isCoinbase && !tx.isWalletUnlock && contactsProvider) { - const contactAddress = received ? inputAddress || inputAlias : outputAddress || outputAlias; + if (!tx.isCoinbase && !tx.isWalletUnlock && contactsProvider) { + const contactAddress = received ? inputAddress || inputAlias : outputAddress || outputAlias; - try { - tx.contact = contactsProvider.get(contactAddress); - tx.name = tx.contact ? tx.contact.name.formatted : tx.name; - } catch (e) { + try { + tx.contact = contactsProvider.get(contactAddress); + tx.name = tx.contact ? tx.contact.name.formatted : tx.name; + } catch (e) {} } - } - tx.actionStr = pendingString + tx.actionStr; + tx.actionStr = pendingString + tx.actionStr; - if (wallet && !tx.walletId) { - tx.walletId = wallet.id; - tx.wallet = wallet; - } - - if (tx.isCoinbase) { - if (tx.isInvite) { - tx.name = 'Mined Invite'; - tx.action = TransactionAction.INVITE; - tx.type = 'credit'; - } else { - const output = tx.outputs.find(o => o.isMine); + if (wallet && !tx.walletId) { + tx.walletId = wallet.id; + tx.wallet = wallet; + } - if (output && output.index !== 0) { - // Ambassador reward - tx.name = 'Growth Reward'; - tx.action = TransactionAction.AMBASSADOR_REWARD; - tx.isGrowthReward = true; + if (tx.isCoinbase) { + if (tx.isInvite) { + tx.name = 'Mined Invite'; + tx.action = TransactionAction.INVITE; + tx.type = 'credit'; } else { - tx.name = 'Mining Reward'; - tx.action = TransactionAction.MINING_REWARD; - tx.isMiningReward = true; + const output = tx.outputs.find(o => o.isMine); + + if (output && output.index !== 0) { + // Ambassador reward + tx.name = 'Growth Reward'; + tx.action = TransactionAction.AMBASSADOR_REWARD; + tx.isGrowthReward = true; + } else { + tx.name = 'Mining Reward'; + tx.action = TransactionAction.MINING_REWARD; + tx.isMiningReward = true; + } } - } - } else { - if (tx.outputs.some(o => o.amount == 0 && _.get(o, 'data', '').toLowerCase().indexOf('pool') > -1)) { - tx.name = 'Pool Reward'; - tx.action = TransactionAction.POOL_REWARD; - tx.isPoolReward = true; } else { - if (tx.outputs.some(o => o.amount == 0 && _.get(o, 'data', '').toLowerCase().indexOf('market') > -1)) { - tx.name = 'Market Escrow'; - tx.isMarketPayment = true; + if ( + tx.outputs.some( + o => + o.amount == 0 && + _.get(o, 'data', '') + .toLowerCase() + .indexOf('pool') > -1, + ) + ) { + tx.name = 'Pool Reward'; + tx.action = TransactionAction.POOL_REWARD; + tx.isPoolReward = true; + } else { + if ( + tx.outputs.some( + o => + o.amount == 0 && + _.get(o, 'data', '') + .toLowerCase() + .indexOf('market') > -1, + ) + ) { + tx.name = 'Market Escrow'; + tx.isMarketPayment = true; + } } } } - } - if (easySendsByAddress[tx.addressTo]) { - const easySend = easySendsByAddress[tx.addressTo]; - tx.name = tx.isInvite ? 'MeritInvite' : 'MeritMoney'; - tx.type = tx.name.toLowerCase(); - tx.easySend = easySend; - tx.easySendUrl = getEasySendURL(easySend); - tx.cancelled = easySend.cancelled; - if (tx.type === 'meritmoney') { - meritMoneyAddresses.push(tx.addressTo); - tx.fees += easyReceiveFee; - tx.amount -= easyReceiveFee; + if (easySendsByAddress[tx.addressTo]) { + const easySend = easySendsByAddress[tx.addressTo]; + tx.name = tx.isInvite ? 'MeritInvite' : 'MeritMoney'; + tx.type = tx.name.toLowerCase(); + tx.easySend = easySend; + tx.easySendUrl = getEasySendURL(easySend); + tx.cancelled = easySend.cancelled; + if (tx.type === 'meritmoney') { + meritMoneyAddresses.push(tx.addressTo); + tx.fees += easyReceiveFee; + tx.amount -= easyReceiveFee; + } } - } - tx.isNew = false; + tx.isNew = false; - if (persistenceService) { - if (!visitedTxs.find(visTx => visTx.txid === tx.txid)) { - tx.isNew = true; - // add new one in visited - visitedTxs.push({ - txid: tx.txid, - counter: 1 - }); + if (persistenceService) { + if (!visitedTxs.find(visTx => visTx.txid === tx.txid)) { + tx.isNew = true; + // add new one in visited + visitedTxs.push({ + txid: tx.txid, + counter: 1, + }); + } } - } - return tx; - })); + return tx; + }), + ); if (persistenceService) { //save to storage @@ -177,7 +203,6 @@ export async function formatWalletHistory(walletHistory: IDisplayTransaction[], // remove meritmoney invites so we have only one tx for meritmoney return walletHistory .filter(t => { - if (meritMoneyAddresses.indexOf(t.addressFrom) !== -1) { //filtering out txs from cancelled MeritMoney/MeritInvite return false; diff --git a/packages/lightwallet/common/utils/url.ts b/packages/lightwallet/common/utils/url.ts index 3019362fb0..0141ab002d 100644 --- a/packages/lightwallet/common/utils/url.ts +++ b/packages/lightwallet/common/utils/url.ts @@ -3,12 +3,10 @@ import { ENV } from '@app/env'; export function parseQuery(query: string): object { query = query.substr(query.indexOf('?') + 1); - return query - .split('&') - .reduce((res, pair) => { - const q = pair.split('='); - return { ...res, [q[0]]: q[1] }; - }, {}); + return query.split('&').reduce((res, pair) => { + const q = pair.split('='); + return { ...res, [q[0]]: q[1] }; + }, {}); } export function getQueryParam(key: string, query: string = window.location.search): string { @@ -16,9 +14,9 @@ export function getQueryParam(key: string, query: string = window.location.searc } export function getWalletUrl() { - return ENV.network === 'testnet'? 'https://testnet.wallet.merit.me/' : 'https://wallet.merit.me/'; + return ENV.network === 'testnet' ? 'https://testnet.wallet.merit.me/' : 'https://wallet.merit.me/'; } export function getShareLink(aliasOrAddress: string) { - return `${ getWalletUrl() }?invite=${aliasOrAddress}` + return `${getWalletUrl()}?invite=${aliasOrAddress}`; } diff --git a/packages/lightwallet/common/utils/wordlists/english.ts b/packages/lightwallet/common/utils/wordlists/english.ts index f3705878dc..51dbbdf50c 100644 --- a/packages/lightwallet/common/utils/wordlists/english.ts +++ b/packages/lightwallet/common/utils/wordlists/english.ts @@ -1 +1,2050 @@ -export default ['abandon', 'ability', 'able', 'about', 'above', 'absent', 'absorb', 'abstract', 'absurd', 'abuse', 'access', 'accident', 'account', 'accuse', 'achieve', 'acid', 'acoustic', 'acquire', 'across', 'act', 'action', 'actor', 'actress', 'actual', 'adapt', 'add', 'addict', 'address', 'adjust', 'admit', 'adult', 'advance', 'advice', 'aerobic', 'affair', 'afford', 'afraid', 'again', 'age', 'agent', 'agree', 'ahead', 'aim', 'air', 'airport', 'aisle', 'alarm', 'album', 'alcohol', 'alert', 'alien', 'all', 'alley', 'allow', 'almost', 'alone', 'alpha', 'already', 'also', 'alter', 'always', 'amateur', 'amazing', 'among', 'amount', 'amused', 'analyst', 'anchor', 'ancient', 'anger', 'angle', 'angry', 'animal', 'ankle', 'announce', 'annual', 'another', 'answer', 'antenna', 'antique', 'anxiety', 'any', 'apart', 'apology', 'appear', 'apple', 'approve', 'april', 'arch', 'arctic', 'area', 'arena', 'argue', 'arm', 'armed', 'armor', 'army', 'around', 'arrange', 'arrest', 'arrive', 'arrow', 'art', 'artefact', 'artist', 'artwork', 'ask', 'aspect', 'assault', 'asset', 'assist', 'assume', 'asthma', 'athlete', 'atom', 'attack', 'attend', 'attitude', 'attract', 'auction', 'audit', 'august', 'aunt', 'author', 'auto', 'autumn', 'average', 'avocado', 'avoid', 'awake', 'aware', 'away', 'awesome', 'awful', 'awkward', 'axis', 'baby', 'bachelor', 'bacon', 'badge', 'bag', 'balance', 'balcony', 'ball', 'bamboo', 'banana', 'banner', 'bar', 'barely', 'bargain', 'barrel', 'base', 'basic', 'basket', 'battle', 'beach', 'bean', 'beauty', 'because', 'become', 'beef', 'before', 'begin', 'behave', 'behind', 'believe', 'below', 'belt', 'bench', 'benefit', 'best', 'betray', 'better', 'between', 'beyond', 'bicycle', 'bid', 'bike', 'bind', 'biology', 'bird', 'birth', 'bitter', 'black', 'blade', 'blame', 'blanket', 'blast', 'bleak', 'bless', 'blind', 'blood', 'blossom', 'blouse', 'blue', 'blur', 'blush', 'board', 'boat', 'body', 'boil', 'bomb', 'bone', 'bonus', 'book', 'boost', 'border', 'boring', 'borrow', 'boss', 'bottom', 'bounce', 'box', 'boy', 'bracket', 'brain', 'brand', 'brass', 'brave', 'bread', 'breeze', 'brick', 'bridge', 'brief', 'bright', 'bring', 'brisk', 'broccoli', 'broken', 'bronze', 'broom', 'brother', 'brown', 'brush', 'bubble', 'buddy', 'budget', 'buffalo', 'build', 'bulb', 'bulk', 'bullet', 'bundle', 'bunker', 'burden', 'burger', 'burst', 'bus', 'business', 'busy', 'butter', 'buyer', 'buzz', 'cabbage', 'cabin', 'cable', 'cactus', 'cage', 'cake', 'call', 'calm', 'camera', 'camp', 'can', 'canal', 'cancel', 'candy', 'cannon', 'canoe', 'canvas', 'canyon', 'capable', 'capital', 'captain', 'car', 'carbon', 'card', 'cargo', 'carpet', 'carry', 'cart', 'case', 'cash', 'casino', 'castle', 'casual', 'cat', 'catalog', 'catch', 'category', 'cattle', 'caught', 'cause', 'caution', 'cave', 'ceiling', 'celery', 'cement', 'census', 'century', 'cereal', 'certain', 'chair', 'chalk', 'champion', 'change', 'chaos', 'chapter', 'charge', 'chase', 'chat', 'cheap', 'check', 'cheese', 'chef', 'cherry', 'chest', 'chicken', 'chief', 'child', 'chimney', 'choice', 'choose', 'chronic', 'chuckle', 'chunk', 'churn', 'cigar', 'cinnamon', 'circle', 'citizen', 'city', 'civil', 'claim', 'clap', 'clarify', 'claw', 'clay', 'clean', 'clerk', 'clever', 'click', 'client', 'cliff', 'climb', 'clinic', 'clip', 'clock', 'clog', 'close', 'cloth', 'cloud', 'clown', 'club', 'clump', 'cluster', 'clutch', 'coach', 'coast', 'coconut', 'code', 'coffee', 'coil', 'coin', 'collect', 'color', 'column', 'combine', 'come', 'comfort', 'comic', 'common', 'company', 'concert', 'conduct', 'confirm', 'congress', 'connect', 'consider', 'control', 'convince', 'cook', 'cool', 'copper', 'copy', 'coral', 'core', 'corn', 'correct', 'cost', 'cotton', 'couch', 'country', 'couple', 'course', 'cousin', 'cover', 'coyote', 'crack', 'cradle', 'craft', 'cram', 'crane', 'crash', 'crater', 'crawl', 'crazy', 'cream', 'credit', 'creek', 'crew', 'cricket', 'crime', 'crisp', 'critic', 'crop', 'cross', 'crouch', 'crowd', 'crucial', 'cruel', 'cruise', 'crumble', 'crunch', 'crush', 'cry', 'crystal', 'cube', 'culture', 'cup', 'cupboard', 'curious', 'current', 'curtain', 'curve', 'cushion', 'custom', 'cute', 'cycle', 'dad', 'damage', 'damp', 'dance', 'danger', 'daring', 'dash', 'daughter', 'dawn', 'day', 'deal', 'debate', 'debris', 'decade', 'december', 'decide', 'decline', 'decorate', 'decrease', 'deer', 'defense', 'define', 'defy', 'degree', 'delay', 'deliver', 'demand', 'demise', 'denial', 'dentist', 'deny', 'depart', 'depend', 'deposit', 'depth', 'deputy', 'derive', 'describe', 'desert', 'design', 'desk', 'despair', 'destroy', 'detail', 'detect', 'develop', 'device', 'devote', 'diagram', 'dial', 'diamond', 'diary', 'dice', 'diesel', 'diet', 'differ', 'digital', 'dignity', 'dilemma', 'dinner', 'dinosaur', 'direct', 'dirt', 'disagree', 'discover', 'disease', 'dish', 'dismiss', 'disorder', 'display', 'distance', 'divert', 'divide', 'divorce', 'dizzy', 'doctor', 'document', 'dog', 'doll', 'dolphin', 'domain', 'donate', 'donkey', 'donor', 'door', 'dose', 'double', 'dove', 'draft', 'dragon', 'drama', 'drastic', 'draw', 'dream', 'dress', 'drift', 'drill', 'drink', 'drip', 'drive', 'drop', 'drum', 'dry', 'duck', 'dumb', 'dune', 'during', 'dust', 'dutch', 'duty', 'dwarf', 'dynamic', 'eager', 'eagle', 'early', 'earn', 'earth', 'easily', 'east', 'easy', 'echo', 'ecology', 'economy', 'edge', 'edit', 'educate', 'effort', 'egg', 'eight', 'either', 'elbow', 'elder', 'electric', 'elegant', 'element', 'elephant', 'elevator', 'elite', 'else', 'embark', 'embody', 'embrace', 'emerge', 'emotion', 'employ', 'empower', 'empty', 'enable', 'enact', 'end', 'endless', 'endorse', 'enemy', 'energy', 'enforce', 'engage', 'engine', 'enhance', 'enjoy', 'enlist', 'enough', 'enrich', 'enroll', 'ensure', 'enter', 'entire', 'entry', 'envelope', 'episode', 'equal', 'equip', 'era', 'erase', 'erode', 'erosion', 'error', 'erupt', 'escape', 'essay', 'essence', 'estate', 'eternal', 'ethics', 'evidence', 'evil', 'evoke', 'evolve', 'exact', 'example', 'excess', 'exchange', 'excite', 'exclude', 'excuse', 'execute', 'exercise', 'exhaust', 'exhibit', 'exile', 'exist', 'exit', 'exotic', 'expand', 'expect', 'expire', 'explain', 'expose', 'express', 'extend', 'extra', 'eye', 'eyebrow', 'fabric', 'face', 'faculty', 'fade', 'faint', 'faith', 'fall', 'false', 'fame', 'family', 'famous', 'fan', 'fancy', 'fantasy', 'farm', 'fashion', 'fat', 'fatal', 'father', 'fatigue', 'fault', 'favorite', 'feature', 'february', 'federal', 'fee', 'feed', 'feel', 'female', 'fence', 'festival', 'fetch', 'fever', 'few', 'fiber', 'fiction', 'field', 'figure', 'file', 'film', 'filter', 'final', 'find', 'fine', 'finger', 'finish', 'fire', 'firm', 'first', 'fiscal', 'fish', 'fit', 'fitness', 'fix', 'flag', 'flame', 'flash', 'flat', 'flavor', 'flee', 'flight', 'flip', 'float', 'flock', 'floor', 'flower', 'fluid', 'flush', 'fly', 'foam', 'focus', 'fog', 'foil', 'fold', 'follow', 'food', 'foot', 'force', 'forest', 'forget', 'fork', 'fortune', 'forum', 'forward', 'fossil', 'foster', 'found', 'fox', 'fragile', 'frame', 'frequent', 'fresh', 'friend', 'fringe', 'frog', 'front', 'frost', 'frown', 'frozen', 'fruit', 'fuel', 'fun', 'funny', 'furnace', 'fury', 'future', 'gadget', 'gain', 'galaxy', 'gallery', 'game', 'gap', 'garage', 'garbage', 'garden', 'garlic', 'garment', 'gas', 'gasp', 'gate', 'gather', 'gauge', 'gaze', 'general', 'genius', 'genre', 'gentle', 'genuine', 'gesture', 'ghost', 'giant', 'gift', 'giggle', 'ginger', 'giraffe', 'girl', 'give', 'glad', 'glance', 'glare', 'glass', 'glide', 'glimpse', 'globe', 'gloom', 'glory', 'glove', 'glow', 'glue', 'goat', 'goddess', 'gold', 'good', 'goose', 'gorilla', 'gospel', 'gossip', 'govern', 'gown', 'grab', 'grace', 'grain', 'grant', 'grape', 'grass', 'gravity', 'great', 'green', 'grid', 'grief', 'grit', 'grocery', 'group', 'grow', 'grunt', 'guard', 'guess', 'guide', 'guilt', 'guitar', 'gun', 'gym', 'habit', 'hair', 'half', 'hammer', 'hamster', 'hand', 'happy', 'harbor', 'hard', 'harsh', 'harvest', 'hat', 'have', 'hawk', 'hazard', 'head', 'health', 'heart', 'heavy', 'hedgehog', 'height', 'hello', 'helmet', 'help', 'hen', 'hero', 'hidden', 'high', 'hill', 'hint', 'hip', 'hire', 'history', 'hobby', 'hockey', 'hold', 'hole', 'holiday', 'hollow', 'home', 'honey', 'hood', 'hope', 'horn', 'horror', 'horse', 'hospital', 'host', 'hotel', 'hour', 'hover', 'hub', 'huge', 'human', 'humble', 'humor', 'hundred', 'hungry', 'hunt', 'hurdle', 'hurry', 'hurt', 'husband', 'hybrid', 'ice', 'icon', 'idea', 'identify', 'idle', 'ignore', 'ill', 'illegal', 'illness', 'image', 'imitate', 'immense', 'immune', 'impact', 'impose', 'improve', 'impulse', 'inch', 'include', 'income', 'increase', 'index', 'indicate', 'indoor', 'industry', 'infant', 'inflict', 'inform', 'inhale', 'inherit', 'initial', 'inject', 'injury', 'inmate', 'inner', 'innocent', 'input', 'inquiry', 'insane', 'insect', 'inside', 'inspire', 'install', 'intact', 'interest', 'into', 'invest', 'invite', 'involve', 'iron', 'island', 'isolate', 'issue', 'item', 'ivory', 'jacket', 'jaguar', 'jar', 'jazz', 'jealous', 'jeans', 'jelly', 'jewel', 'job', 'join', 'joke', 'journey', 'joy', 'judge', 'juice', 'jump', 'jungle', 'junior', 'junk', 'just', 'kangaroo', 'keen', 'keep', 'ketchup', 'key', 'kick', 'kid', 'kidney', 'kind', 'kingdom', 'kiss', 'kit', 'kitchen', 'kite', 'kitten', 'kiwi', 'knee', 'knife', 'knock', 'know', 'lab', 'label', 'labor', 'ladder', 'lady', 'lake', 'lamp', 'language', 'laptop', 'large', 'later', 'latin', 'laugh', 'laundry', 'lava', 'law', 'lawn', 'lawsuit', 'layer', 'lazy', 'leader', 'leaf', 'learn', 'leave', 'lecture', 'left', 'leg', 'legal', 'legend', 'leisure', 'lemon', 'lend', 'length', 'lens', 'leopard', 'lesson', 'letter', 'level', 'liar', 'liberty', 'library', 'license', 'life', 'lift', 'light', 'like', 'limb', 'limit', 'link', 'lion', 'liquid', 'list', 'little', 'live', 'lizard', 'load', 'loan', 'lobster', 'local', 'lock', 'logic', 'lonely', 'long', 'loop', 'lottery', 'loud', 'lounge', 'love', 'loyal', 'lucky', 'luggage', 'lumber', 'lunar', 'lunch', 'luxury', 'lyrics', 'machine', 'mad', 'magic', 'magnet', 'maid', 'mail', 'main', 'major', 'make', 'mammal', 'man', 'manage', 'mandate', 'mango', 'mansion', 'manual', 'maple', 'marble', 'march', 'margin', 'marine', 'market', 'marriage', 'mask', 'mass', 'master', 'match', 'material', 'math', 'matrix', 'matter', 'maximum', 'maze', 'meadow', 'mean', 'measure', 'meat', 'mechanic', 'medal', 'media', 'melody', 'melt', 'member', 'memory', 'mention', 'menu', 'mercy', 'merge', 'merit', 'merry', 'mesh', 'message', 'metal', 'method', 'middle', 'midnight', 'milk', 'million', 'mimic', 'mind', 'minimum', 'minor', 'minute', 'miracle', 'mirror', 'misery', 'miss', 'mistake', 'mix', 'mixed', 'mixture', 'mobile', 'model', 'modify', 'mom', 'moment', 'monitor', 'monkey', 'monster', 'month', 'moon', 'moral', 'more', 'morning', 'mosquito', 'mother', 'motion', 'motor', 'mountain', 'mouse', 'move', 'movie', 'much', 'muffin', 'mule', 'multiply', 'muscle', 'museum', 'mushroom', 'music', 'must', 'mutual', 'myself', 'mystery', 'myth', 'naive', 'name', 'napkin', 'narrow', 'nasty', 'nation', 'nature', 'near', 'neck', 'need', 'negative', 'neglect', 'neither', 'nephew', 'nerve', 'nest', 'net', 'network', 'neutral', 'never', 'news', 'next', 'nice', 'night', 'noble', 'noise', 'nominee', 'noodle', 'normal', 'north', 'nose', 'notable', 'note', 'nothing', 'notice', 'novel', 'now', 'nuclear', 'number', 'nurse', 'nut', 'oak', 'obey', 'object', 'oblige', 'obscure', 'observe', 'obtain', 'obvious', 'occur', 'ocean', 'october', 'odor', 'off', 'offer', 'office', 'often', 'oil', 'okay', 'old', 'olive', 'olympic', 'omit', 'once', 'one', 'onion', 'online', 'only', 'open', 'opera', 'opinion', 'oppose', 'option', 'orange', 'orbit', 'orchard', 'order', 'ordinary', 'organ', 'orient', 'original', 'orphan', 'ostrich', 'other', 'outdoor', 'outer', 'output', 'outside', 'oval', 'oven', 'over', 'own', 'owner', 'oxygen', 'oyster', 'ozone', 'pact', 'paddle', 'page', 'pair', 'palace', 'palm', 'panda', 'panel', 'panic', 'panther', 'paper', 'parade', 'parent', 'park', 'parrot', 'party', 'pass', 'patch', 'path', 'patient', 'patrol', 'pattern', 'pause', 'pave', 'payment', 'peace', 'peanut', 'pear', 'peasant', 'pelican', 'pen', 'penalty', 'pencil', 'people', 'pepper', 'perfect', 'permit', 'person', 'pet', 'phone', 'photo', 'phrase', 'physical', 'piano', 'picnic', 'picture', 'piece', 'pig', 'pigeon', 'pill', 'pilot', 'pink', 'pioneer', 'pipe', 'pistol', 'pitch', 'pizza', 'place', 'planet', 'plastic', 'plate', 'play', 'please', 'pledge', 'pluck', 'plug', 'plunge', 'poem', 'poet', 'point', 'polar', 'pole', 'police', 'pond', 'pony', 'pool', 'popular', 'portion', 'position', 'possible', 'post', 'potato', 'pottery', 'poverty', 'powder', 'power', 'practice', 'praise', 'predict', 'prefer', 'prepare', 'present', 'pretty', 'prevent', 'price', 'pride', 'primary', 'print', 'priority', 'prison', 'private', 'prize', 'problem', 'process', 'produce', 'profit', 'program', 'project', 'promote', 'proof', 'property', 'prosper', 'protect', 'proud', 'provide', 'public', 'pudding', 'pull', 'pulp', 'pulse', 'pumpkin', 'punch', 'pupil', 'puppy', 'purchase', 'purity', 'purpose', 'purse', 'push', 'put', 'puzzle', 'pyramid', 'quality', 'quantum', 'quarter', 'question', 'quick', 'quit', 'quiz', 'quote', 'rabbit', 'raccoon', 'race', 'rack', 'radar', 'radio', 'rail', 'rain', 'raise', 'rally', 'ramp', 'ranch', 'random', 'range', 'rapid', 'rare', 'rate', 'rather', 'raven', 'raw', 'razor', 'ready', 'real', 'reason', 'rebel', 'rebuild', 'recall', 'receive', 'recipe', 'record', 'recycle', 'reduce', 'reflect', 'reform', 'refuse', 'region', 'regret', 'regular', 'reject', 'relax', 'release', 'relief', 'rely', 'remain', 'remember', 'remind', 'remove', 'render', 'renew', 'rent', 'reopen', 'repair', 'repeat', 'replace', 'report', 'require', 'rescue', 'resemble', 'resist', 'resource', 'response', 'result', 'retire', 'retreat', 'return', 'reunion', 'reveal', 'review', 'reward', 'rhythm', 'rib', 'ribbon', 'rice', 'rich', 'ride', 'ridge', 'rifle', 'right', 'rigid', 'ring', 'riot', 'ripple', 'risk', 'ritual', 'rival', 'river', 'road', 'roast', 'robot', 'robust', 'rocket', 'romance', 'roof', 'rookie', 'room', 'rose', 'rotate', 'rough', 'round', 'route', 'royal', 'rubber', 'rude', 'rug', 'rule', 'run', 'runway', 'rural', 'sad', 'saddle', 'sadness', 'safe', 'sail', 'salad', 'salmon', 'salon', 'salt', 'salute', 'same', 'sample', 'sand', 'satisfy', 'satoshi', 'sauce', 'sausage', 'save', 'say', 'scale', 'scan', 'scare', 'scatter', 'scene', 'scheme', 'school', 'science', 'scissors', 'scorpion', 'scout', 'scrap', 'screen', 'script', 'scrub', 'sea', 'search', 'season', 'seat', 'second', 'secret', 'section', 'security', 'seed', 'seek', 'segment', 'select', 'sell', 'seminar', 'senior', 'sense', 'sentence', 'series', 'service', 'session', 'settle', 'setup', 'seven', 'shadow', 'shaft', 'shallow', 'share', 'shed', 'shell', 'sheriff', 'shield', 'shift', 'shine', 'ship', 'shiver', 'shock', 'shoe', 'shoot', 'shop', 'short', 'shoulder', 'shove', 'shrimp', 'shrug', 'shuffle', 'shy', 'sibling', 'sick', 'side', 'siege', 'sight', 'sign', 'silent', 'silk', 'silly', 'silver', 'similar', 'simple', 'since', 'sing', 'siren', 'sister', 'situate', 'six', 'size', 'skate', 'sketch', 'ski', 'skill', 'skin', 'skirt', 'skull', 'slab', 'slam', 'sleep', 'slender', 'slice', 'slide', 'slight', 'slim', 'slogan', 'slot', 'slow', 'slush', 'small', 'smart', 'smile', 'smoke', 'smooth', 'snack', 'snake', 'snap', 'sniff', 'snow', 'soap', 'soccer', 'social', 'sock', 'soda', 'soft', 'solar', 'soldier', 'solid', 'solution', 'solve', 'someone', 'song', 'soon', 'sorry', 'sort', 'soul', 'sound', 'soup', 'source', 'south', 'space', 'spare', 'spatial', 'spawn', 'speak', 'special', 'speed', 'spell', 'spend', 'sphere', 'spice', 'spider', 'spike', 'spin', 'spirit', 'split', 'spoil', 'sponsor', 'spoon', 'sport', 'spot', 'spray', 'spread', 'spring', 'spy', 'square', 'squeeze', 'squirrel', 'stable', 'stadium', 'staff', 'stage', 'stairs', 'stamp', 'stand', 'start', 'state', 'stay', 'steak', 'steel', 'stem', 'step', 'stereo', 'stick', 'still', 'sting', 'stock', 'stomach', 'stone', 'stool', 'story', 'stove', 'strategy', 'street', 'strike', 'strong', 'struggle', 'student', 'stuff', 'stumble', 'style', 'subject', 'submit', 'subway', 'success', 'such', 'sudden', 'suffer', 'sugar', 'suggest', 'suit', 'summer', 'sun', 'sunny', 'sunset', 'super', 'supply', 'supreme', 'sure', 'surface', 'surge', 'surprise', 'surround', 'survey', 'suspect', 'sustain', 'swallow', 'swamp', 'swap', 'swarm', 'swear', 'sweet', 'swift', 'swim', 'swing', 'switch', 'sword', 'symbol', 'symptom', 'syrup', 'system', 'table', 'tackle', 'tag', 'tail', 'talent', 'talk', 'tank', 'tape', 'target', 'task', 'taste', 'tattoo', 'taxi', 'teach', 'team', 'tell', 'ten', 'tenant', 'tennis', 'tent', 'term', 'test', 'text', 'thank', 'that', 'theme', 'then', 'theory', 'there', 'they', 'thing', 'this', 'thought', 'three', 'thrive', 'throw', 'thumb', 'thunder', 'ticket', 'tide', 'tiger', 'tilt', 'timber', 'time', 'tiny', 'tip', 'tired', 'tissue', 'title', 'toast', 'tobacco', 'today', 'toddler', 'toe', 'together', 'toilet', 'token', 'tomato', 'tomorrow', 'tone', 'tongue', 'tonight', 'tool', 'tooth', 'top', 'topic', 'topple', 'torch', 'tornado', 'tortoise', 'toss', 'total', 'tourist', 'toward', 'tower', 'town', 'toy', 'track', 'trade', 'traffic', 'tragic', 'train', 'transfer', 'trap', 'trash', 'travel', 'tray', 'treat', 'tree', 'trend', 'trial', 'tribe', 'trick', 'trigger', 'trim', 'trip', 'trophy', 'trouble', 'truck', 'true', 'truly', 'trumpet', 'trust', 'truth', 'try', 'tube', 'tuition', 'tumble', 'tuna', 'tunnel', 'turkey', 'turn', 'turtle', 'twelve', 'twenty', 'twice', 'twin', 'twist', 'two', 'type', 'typical', 'ugly', 'umbrella', 'unable', 'unaware', 'uncle', 'uncover', 'under', 'undo', 'unfair', 'unfold', 'unhappy', 'uniform', 'unique', 'unit', 'universe', 'unknown', 'unlock', 'until', 'unusual', 'unveil', 'update', 'upgrade', 'uphold', 'upon', 'upper', 'upset', 'urban', 'urge', 'usage', 'use', 'used', 'useful', 'useless', 'usual', 'utility', 'vacant', 'vacuum', 'vague', 'valid', 'valley', 'valve', 'van', 'vanish', 'vapor', 'various', 'vast', 'vault', 'vehicle', 'velvet', 'vendor', 'venture', 'venue', 'verb', 'verify', 'version', 'very', 'vessel', 'veteran', 'viable', 'vibrant', 'vicious', 'victory', 'video', 'view', 'village', 'vintage', 'violin', 'virtual', 'virus', 'visa', 'visit', 'visual', 'vital', 'vivid', 'vocal', 'voice', 'void', 'volcano', 'volume', 'vote', 'voyage', 'wage', 'wagon', 'wait', 'walk', 'wall', 'walnut', 'want', 'warfare', 'warm', 'warrior', 'wash', 'wasp', 'waste', 'water', 'wave', 'way', 'wealth', 'weapon', 'wear', 'weasel', 'weather', 'web', 'wedding', 'weekend', 'weird', 'welcome', 'west', 'wet', 'whale', 'what', 'wheat', 'wheel', 'when', 'where', 'whip', 'whisper', 'wide', 'width', 'wife', 'wild', 'will', 'win', 'window', 'wine', 'wing', 'wink', 'winner', 'winter', 'wire', 'wisdom', 'wise', 'wish', 'witness', 'wolf', 'woman', 'wonder', 'wood', 'wool', 'word', 'work', 'world', 'worry', 'worth', 'wrap', 'wreck', 'wrestle', 'wrist', 'write', 'wrong', 'yard', 'year', 'yellow', 'you', 'young', 'youth', 'zebra', 'zero', 'zone', 'zoo']; +export default [ + 'abandon', + 'ability', + 'able', + 'about', + 'above', + 'absent', + 'absorb', + 'abstract', + 'absurd', + 'abuse', + 'access', + 'accident', + 'account', + 'accuse', + 'achieve', + 'acid', + 'acoustic', + 'acquire', + 'across', + 'act', + 'action', + 'actor', + 'actress', + 'actual', + 'adapt', + 'add', + 'addict', + 'address', + 'adjust', + 'admit', + 'adult', + 'advance', + 'advice', + 'aerobic', + 'affair', + 'afford', + 'afraid', + 'again', + 'age', + 'agent', + 'agree', + 'ahead', + 'aim', + 'air', + 'airport', + 'aisle', + 'alarm', + 'album', + 'alcohol', + 'alert', + 'alien', + 'all', + 'alley', + 'allow', + 'almost', + 'alone', + 'alpha', + 'already', + 'also', + 'alter', + 'always', + 'amateur', + 'amazing', + 'among', + 'amount', + 'amused', + 'analyst', + 'anchor', + 'ancient', + 'anger', + 'angle', + 'angry', + 'animal', + 'ankle', + 'announce', + 'annual', + 'another', + 'answer', + 'antenna', + 'antique', + 'anxiety', + 'any', + 'apart', + 'apology', + 'appear', + 'apple', + 'approve', + 'april', + 'arch', + 'arctic', + 'area', + 'arena', + 'argue', + 'arm', + 'armed', + 'armor', + 'army', + 'around', + 'arrange', + 'arrest', + 'arrive', + 'arrow', + 'art', + 'artefact', + 'artist', + 'artwork', + 'ask', + 'aspect', + 'assault', + 'asset', + 'assist', + 'assume', + 'asthma', + 'athlete', + 'atom', + 'attack', + 'attend', + 'attitude', + 'attract', + 'auction', + 'audit', + 'august', + 'aunt', + 'author', + 'auto', + 'autumn', + 'average', + 'avocado', + 'avoid', + 'awake', + 'aware', + 'away', + 'awesome', + 'awful', + 'awkward', + 'axis', + 'baby', + 'bachelor', + 'bacon', + 'badge', + 'bag', + 'balance', + 'balcony', + 'ball', + 'bamboo', + 'banana', + 'banner', + 'bar', + 'barely', + 'bargain', + 'barrel', + 'base', + 'basic', + 'basket', + 'battle', + 'beach', + 'bean', + 'beauty', + 'because', + 'become', + 'beef', + 'before', + 'begin', + 'behave', + 'behind', + 'believe', + 'below', + 'belt', + 'bench', + 'benefit', + 'best', + 'betray', + 'better', + 'between', + 'beyond', + 'bicycle', + 'bid', + 'bike', + 'bind', + 'biology', + 'bird', + 'birth', + 'bitter', + 'black', + 'blade', + 'blame', + 'blanket', + 'blast', + 'bleak', + 'bless', + 'blind', + 'blood', + 'blossom', + 'blouse', + 'blue', + 'blur', + 'blush', + 'board', + 'boat', + 'body', + 'boil', + 'bomb', + 'bone', + 'bonus', + 'book', + 'boost', + 'border', + 'boring', + 'borrow', + 'boss', + 'bottom', + 'bounce', + 'box', + 'boy', + 'bracket', + 'brain', + 'brand', + 'brass', + 'brave', + 'bread', + 'breeze', + 'brick', + 'bridge', + 'brief', + 'bright', + 'bring', + 'brisk', + 'broccoli', + 'broken', + 'bronze', + 'broom', + 'brother', + 'brown', + 'brush', + 'bubble', + 'buddy', + 'budget', + 'buffalo', + 'build', + 'bulb', + 'bulk', + 'bullet', + 'bundle', + 'bunker', + 'burden', + 'burger', + 'burst', + 'bus', + 'business', + 'busy', + 'butter', + 'buyer', + 'buzz', + 'cabbage', + 'cabin', + 'cable', + 'cactus', + 'cage', + 'cake', + 'call', + 'calm', + 'camera', + 'camp', + 'can', + 'canal', + 'cancel', + 'candy', + 'cannon', + 'canoe', + 'canvas', + 'canyon', + 'capable', + 'capital', + 'captain', + 'car', + 'carbon', + 'card', + 'cargo', + 'carpet', + 'carry', + 'cart', + 'case', + 'cash', + 'casino', + 'castle', + 'casual', + 'cat', + 'catalog', + 'catch', + 'category', + 'cattle', + 'caught', + 'cause', + 'caution', + 'cave', + 'ceiling', + 'celery', + 'cement', + 'census', + 'century', + 'cereal', + 'certain', + 'chair', + 'chalk', + 'champion', + 'change', + 'chaos', + 'chapter', + 'charge', + 'chase', + 'chat', + 'cheap', + 'check', + 'cheese', + 'chef', + 'cherry', + 'chest', + 'chicken', + 'chief', + 'child', + 'chimney', + 'choice', + 'choose', + 'chronic', + 'chuckle', + 'chunk', + 'churn', + 'cigar', + 'cinnamon', + 'circle', + 'citizen', + 'city', + 'civil', + 'claim', + 'clap', + 'clarify', + 'claw', + 'clay', + 'clean', + 'clerk', + 'clever', + 'click', + 'client', + 'cliff', + 'climb', + 'clinic', + 'clip', + 'clock', + 'clog', + 'close', + 'cloth', + 'cloud', + 'clown', + 'club', + 'clump', + 'cluster', + 'clutch', + 'coach', + 'coast', + 'coconut', + 'code', + 'coffee', + 'coil', + 'coin', + 'collect', + 'color', + 'column', + 'combine', + 'come', + 'comfort', + 'comic', + 'common', + 'company', + 'concert', + 'conduct', + 'confirm', + 'congress', + 'connect', + 'consider', + 'control', + 'convince', + 'cook', + 'cool', + 'copper', + 'copy', + 'coral', + 'core', + 'corn', + 'correct', + 'cost', + 'cotton', + 'couch', + 'country', + 'couple', + 'course', + 'cousin', + 'cover', + 'coyote', + 'crack', + 'cradle', + 'craft', + 'cram', + 'crane', + 'crash', + 'crater', + 'crawl', + 'crazy', + 'cream', + 'credit', + 'creek', + 'crew', + 'cricket', + 'crime', + 'crisp', + 'critic', + 'crop', + 'cross', + 'crouch', + 'crowd', + 'crucial', + 'cruel', + 'cruise', + 'crumble', + 'crunch', + 'crush', + 'cry', + 'crystal', + 'cube', + 'culture', + 'cup', + 'cupboard', + 'curious', + 'current', + 'curtain', + 'curve', + 'cushion', + 'custom', + 'cute', + 'cycle', + 'dad', + 'damage', + 'damp', + 'dance', + 'danger', + 'daring', + 'dash', + 'daughter', + 'dawn', + 'day', + 'deal', + 'debate', + 'debris', + 'decade', + 'december', + 'decide', + 'decline', + 'decorate', + 'decrease', + 'deer', + 'defense', + 'define', + 'defy', + 'degree', + 'delay', + 'deliver', + 'demand', + 'demise', + 'denial', + 'dentist', + 'deny', + 'depart', + 'depend', + 'deposit', + 'depth', + 'deputy', + 'derive', + 'describe', + 'desert', + 'design', + 'desk', + 'despair', + 'destroy', + 'detail', + 'detect', + 'develop', + 'device', + 'devote', + 'diagram', + 'dial', + 'diamond', + 'diary', + 'dice', + 'diesel', + 'diet', + 'differ', + 'digital', + 'dignity', + 'dilemma', + 'dinner', + 'dinosaur', + 'direct', + 'dirt', + 'disagree', + 'discover', + 'disease', + 'dish', + 'dismiss', + 'disorder', + 'display', + 'distance', + 'divert', + 'divide', + 'divorce', + 'dizzy', + 'doctor', + 'document', + 'dog', + 'doll', + 'dolphin', + 'domain', + 'donate', + 'donkey', + 'donor', + 'door', + 'dose', + 'double', + 'dove', + 'draft', + 'dragon', + 'drama', + 'drastic', + 'draw', + 'dream', + 'dress', + 'drift', + 'drill', + 'drink', + 'drip', + 'drive', + 'drop', + 'drum', + 'dry', + 'duck', + 'dumb', + 'dune', + 'during', + 'dust', + 'dutch', + 'duty', + 'dwarf', + 'dynamic', + 'eager', + 'eagle', + 'early', + 'earn', + 'earth', + 'easily', + 'east', + 'easy', + 'echo', + 'ecology', + 'economy', + 'edge', + 'edit', + 'educate', + 'effort', + 'egg', + 'eight', + 'either', + 'elbow', + 'elder', + 'electric', + 'elegant', + 'element', + 'elephant', + 'elevator', + 'elite', + 'else', + 'embark', + 'embody', + 'embrace', + 'emerge', + 'emotion', + 'employ', + 'empower', + 'empty', + 'enable', + 'enact', + 'end', + 'endless', + 'endorse', + 'enemy', + 'energy', + 'enforce', + 'engage', + 'engine', + 'enhance', + 'enjoy', + 'enlist', + 'enough', + 'enrich', + 'enroll', + 'ensure', + 'enter', + 'entire', + 'entry', + 'envelope', + 'episode', + 'equal', + 'equip', + 'era', + 'erase', + 'erode', + 'erosion', + 'error', + 'erupt', + 'escape', + 'essay', + 'essence', + 'estate', + 'eternal', + 'ethics', + 'evidence', + 'evil', + 'evoke', + 'evolve', + 'exact', + 'example', + 'excess', + 'exchange', + 'excite', + 'exclude', + 'excuse', + 'execute', + 'exercise', + 'exhaust', + 'exhibit', + 'exile', + 'exist', + 'exit', + 'exotic', + 'expand', + 'expect', + 'expire', + 'explain', + 'expose', + 'express', + 'extend', + 'extra', + 'eye', + 'eyebrow', + 'fabric', + 'face', + 'faculty', + 'fade', + 'faint', + 'faith', + 'fall', + 'false', + 'fame', + 'family', + 'famous', + 'fan', + 'fancy', + 'fantasy', + 'farm', + 'fashion', + 'fat', + 'fatal', + 'father', + 'fatigue', + 'fault', + 'favorite', + 'feature', + 'february', + 'federal', + 'fee', + 'feed', + 'feel', + 'female', + 'fence', + 'festival', + 'fetch', + 'fever', + 'few', + 'fiber', + 'fiction', + 'field', + 'figure', + 'file', + 'film', + 'filter', + 'final', + 'find', + 'fine', + 'finger', + 'finish', + 'fire', + 'firm', + 'first', + 'fiscal', + 'fish', + 'fit', + 'fitness', + 'fix', + 'flag', + 'flame', + 'flash', + 'flat', + 'flavor', + 'flee', + 'flight', + 'flip', + 'float', + 'flock', + 'floor', + 'flower', + 'fluid', + 'flush', + 'fly', + 'foam', + 'focus', + 'fog', + 'foil', + 'fold', + 'follow', + 'food', + 'foot', + 'force', + 'forest', + 'forget', + 'fork', + 'fortune', + 'forum', + 'forward', + 'fossil', + 'foster', + 'found', + 'fox', + 'fragile', + 'frame', + 'frequent', + 'fresh', + 'friend', + 'fringe', + 'frog', + 'front', + 'frost', + 'frown', + 'frozen', + 'fruit', + 'fuel', + 'fun', + 'funny', + 'furnace', + 'fury', + 'future', + 'gadget', + 'gain', + 'galaxy', + 'gallery', + 'game', + 'gap', + 'garage', + 'garbage', + 'garden', + 'garlic', + 'garment', + 'gas', + 'gasp', + 'gate', + 'gather', + 'gauge', + 'gaze', + 'general', + 'genius', + 'genre', + 'gentle', + 'genuine', + 'gesture', + 'ghost', + 'giant', + 'gift', + 'giggle', + 'ginger', + 'giraffe', + 'girl', + 'give', + 'glad', + 'glance', + 'glare', + 'glass', + 'glide', + 'glimpse', + 'globe', + 'gloom', + 'glory', + 'glove', + 'glow', + 'glue', + 'goat', + 'goddess', + 'gold', + 'good', + 'goose', + 'gorilla', + 'gospel', + 'gossip', + 'govern', + 'gown', + 'grab', + 'grace', + 'grain', + 'grant', + 'grape', + 'grass', + 'gravity', + 'great', + 'green', + 'grid', + 'grief', + 'grit', + 'grocery', + 'group', + 'grow', + 'grunt', + 'guard', + 'guess', + 'guide', + 'guilt', + 'guitar', + 'gun', + 'gym', + 'habit', + 'hair', + 'half', + 'hammer', + 'hamster', + 'hand', + 'happy', + 'harbor', + 'hard', + 'harsh', + 'harvest', + 'hat', + 'have', + 'hawk', + 'hazard', + 'head', + 'health', + 'heart', + 'heavy', + 'hedgehog', + 'height', + 'hello', + 'helmet', + 'help', + 'hen', + 'hero', + 'hidden', + 'high', + 'hill', + 'hint', + 'hip', + 'hire', + 'history', + 'hobby', + 'hockey', + 'hold', + 'hole', + 'holiday', + 'hollow', + 'home', + 'honey', + 'hood', + 'hope', + 'horn', + 'horror', + 'horse', + 'hospital', + 'host', + 'hotel', + 'hour', + 'hover', + 'hub', + 'huge', + 'human', + 'humble', + 'humor', + 'hundred', + 'hungry', + 'hunt', + 'hurdle', + 'hurry', + 'hurt', + 'husband', + 'hybrid', + 'ice', + 'icon', + 'idea', + 'identify', + 'idle', + 'ignore', + 'ill', + 'illegal', + 'illness', + 'image', + 'imitate', + 'immense', + 'immune', + 'impact', + 'impose', + 'improve', + 'impulse', + 'inch', + 'include', + 'income', + 'increase', + 'index', + 'indicate', + 'indoor', + 'industry', + 'infant', + 'inflict', + 'inform', + 'inhale', + 'inherit', + 'initial', + 'inject', + 'injury', + 'inmate', + 'inner', + 'innocent', + 'input', + 'inquiry', + 'insane', + 'insect', + 'inside', + 'inspire', + 'install', + 'intact', + 'interest', + 'into', + 'invest', + 'invite', + 'involve', + 'iron', + 'island', + 'isolate', + 'issue', + 'item', + 'ivory', + 'jacket', + 'jaguar', + 'jar', + 'jazz', + 'jealous', + 'jeans', + 'jelly', + 'jewel', + 'job', + 'join', + 'joke', + 'journey', + 'joy', + 'judge', + 'juice', + 'jump', + 'jungle', + 'junior', + 'junk', + 'just', + 'kangaroo', + 'keen', + 'keep', + 'ketchup', + 'key', + 'kick', + 'kid', + 'kidney', + 'kind', + 'kingdom', + 'kiss', + 'kit', + 'kitchen', + 'kite', + 'kitten', + 'kiwi', + 'knee', + 'knife', + 'knock', + 'know', + 'lab', + 'label', + 'labor', + 'ladder', + 'lady', + 'lake', + 'lamp', + 'language', + 'laptop', + 'large', + 'later', + 'latin', + 'laugh', + 'laundry', + 'lava', + 'law', + 'lawn', + 'lawsuit', + 'layer', + 'lazy', + 'leader', + 'leaf', + 'learn', + 'leave', + 'lecture', + 'left', + 'leg', + 'legal', + 'legend', + 'leisure', + 'lemon', + 'lend', + 'length', + 'lens', + 'leopard', + 'lesson', + 'letter', + 'level', + 'liar', + 'liberty', + 'library', + 'license', + 'life', + 'lift', + 'light', + 'like', + 'limb', + 'limit', + 'link', + 'lion', + 'liquid', + 'list', + 'little', + 'live', + 'lizard', + 'load', + 'loan', + 'lobster', + 'local', + 'lock', + 'logic', + 'lonely', + 'long', + 'loop', + 'lottery', + 'loud', + 'lounge', + 'love', + 'loyal', + 'lucky', + 'luggage', + 'lumber', + 'lunar', + 'lunch', + 'luxury', + 'lyrics', + 'machine', + 'mad', + 'magic', + 'magnet', + 'maid', + 'mail', + 'main', + 'major', + 'make', + 'mammal', + 'man', + 'manage', + 'mandate', + 'mango', + 'mansion', + 'manual', + 'maple', + 'marble', + 'march', + 'margin', + 'marine', + 'market', + 'marriage', + 'mask', + 'mass', + 'master', + 'match', + 'material', + 'math', + 'matrix', + 'matter', + 'maximum', + 'maze', + 'meadow', + 'mean', + 'measure', + 'meat', + 'mechanic', + 'medal', + 'media', + 'melody', + 'melt', + 'member', + 'memory', + 'mention', + 'menu', + 'mercy', + 'merge', + 'merit', + 'merry', + 'mesh', + 'message', + 'metal', + 'method', + 'middle', + 'midnight', + 'milk', + 'million', + 'mimic', + 'mind', + 'minimum', + 'minor', + 'minute', + 'miracle', + 'mirror', + 'misery', + 'miss', + 'mistake', + 'mix', + 'mixed', + 'mixture', + 'mobile', + 'model', + 'modify', + 'mom', + 'moment', + 'monitor', + 'monkey', + 'monster', + 'month', + 'moon', + 'moral', + 'more', + 'morning', + 'mosquito', + 'mother', + 'motion', + 'motor', + 'mountain', + 'mouse', + 'move', + 'movie', + 'much', + 'muffin', + 'mule', + 'multiply', + 'muscle', + 'museum', + 'mushroom', + 'music', + 'must', + 'mutual', + 'myself', + 'mystery', + 'myth', + 'naive', + 'name', + 'napkin', + 'narrow', + 'nasty', + 'nation', + 'nature', + 'near', + 'neck', + 'need', + 'negative', + 'neglect', + 'neither', + 'nephew', + 'nerve', + 'nest', + 'net', + 'network', + 'neutral', + 'never', + 'news', + 'next', + 'nice', + 'night', + 'noble', + 'noise', + 'nominee', + 'noodle', + 'normal', + 'north', + 'nose', + 'notable', + 'note', + 'nothing', + 'notice', + 'novel', + 'now', + 'nuclear', + 'number', + 'nurse', + 'nut', + 'oak', + 'obey', + 'object', + 'oblige', + 'obscure', + 'observe', + 'obtain', + 'obvious', + 'occur', + 'ocean', + 'october', + 'odor', + 'off', + 'offer', + 'office', + 'often', + 'oil', + 'okay', + 'old', + 'olive', + 'olympic', + 'omit', + 'once', + 'one', + 'onion', + 'online', + 'only', + 'open', + 'opera', + 'opinion', + 'oppose', + 'option', + 'orange', + 'orbit', + 'orchard', + 'order', + 'ordinary', + 'organ', + 'orient', + 'original', + 'orphan', + 'ostrich', + 'other', + 'outdoor', + 'outer', + 'output', + 'outside', + 'oval', + 'oven', + 'over', + 'own', + 'owner', + 'oxygen', + 'oyster', + 'ozone', + 'pact', + 'paddle', + 'page', + 'pair', + 'palace', + 'palm', + 'panda', + 'panel', + 'panic', + 'panther', + 'paper', + 'parade', + 'parent', + 'park', + 'parrot', + 'party', + 'pass', + 'patch', + 'path', + 'patient', + 'patrol', + 'pattern', + 'pause', + 'pave', + 'payment', + 'peace', + 'peanut', + 'pear', + 'peasant', + 'pelican', + 'pen', + 'penalty', + 'pencil', + 'people', + 'pepper', + 'perfect', + 'permit', + 'person', + 'pet', + 'phone', + 'photo', + 'phrase', + 'physical', + 'piano', + 'picnic', + 'picture', + 'piece', + 'pig', + 'pigeon', + 'pill', + 'pilot', + 'pink', + 'pioneer', + 'pipe', + 'pistol', + 'pitch', + 'pizza', + 'place', + 'planet', + 'plastic', + 'plate', + 'play', + 'please', + 'pledge', + 'pluck', + 'plug', + 'plunge', + 'poem', + 'poet', + 'point', + 'polar', + 'pole', + 'police', + 'pond', + 'pony', + 'pool', + 'popular', + 'portion', + 'position', + 'possible', + 'post', + 'potato', + 'pottery', + 'poverty', + 'powder', + 'power', + 'practice', + 'praise', + 'predict', + 'prefer', + 'prepare', + 'present', + 'pretty', + 'prevent', + 'price', + 'pride', + 'primary', + 'print', + 'priority', + 'prison', + 'private', + 'prize', + 'problem', + 'process', + 'produce', + 'profit', + 'program', + 'project', + 'promote', + 'proof', + 'property', + 'prosper', + 'protect', + 'proud', + 'provide', + 'public', + 'pudding', + 'pull', + 'pulp', + 'pulse', + 'pumpkin', + 'punch', + 'pupil', + 'puppy', + 'purchase', + 'purity', + 'purpose', + 'purse', + 'push', + 'put', + 'puzzle', + 'pyramid', + 'quality', + 'quantum', + 'quarter', + 'question', + 'quick', + 'quit', + 'quiz', + 'quote', + 'rabbit', + 'raccoon', + 'race', + 'rack', + 'radar', + 'radio', + 'rail', + 'rain', + 'raise', + 'rally', + 'ramp', + 'ranch', + 'random', + 'range', + 'rapid', + 'rare', + 'rate', + 'rather', + 'raven', + 'raw', + 'razor', + 'ready', + 'real', + 'reason', + 'rebel', + 'rebuild', + 'recall', + 'receive', + 'recipe', + 'record', + 'recycle', + 'reduce', + 'reflect', + 'reform', + 'refuse', + 'region', + 'regret', + 'regular', + 'reject', + 'relax', + 'release', + 'relief', + 'rely', + 'remain', + 'remember', + 'remind', + 'remove', + 'render', + 'renew', + 'rent', + 'reopen', + 'repair', + 'repeat', + 'replace', + 'report', + 'require', + 'rescue', + 'resemble', + 'resist', + 'resource', + 'response', + 'result', + 'retire', + 'retreat', + 'return', + 'reunion', + 'reveal', + 'review', + 'reward', + 'rhythm', + 'rib', + 'ribbon', + 'rice', + 'rich', + 'ride', + 'ridge', + 'rifle', + 'right', + 'rigid', + 'ring', + 'riot', + 'ripple', + 'risk', + 'ritual', + 'rival', + 'river', + 'road', + 'roast', + 'robot', + 'robust', + 'rocket', + 'romance', + 'roof', + 'rookie', + 'room', + 'rose', + 'rotate', + 'rough', + 'round', + 'route', + 'royal', + 'rubber', + 'rude', + 'rug', + 'rule', + 'run', + 'runway', + 'rural', + 'sad', + 'saddle', + 'sadness', + 'safe', + 'sail', + 'salad', + 'salmon', + 'salon', + 'salt', + 'salute', + 'same', + 'sample', + 'sand', + 'satisfy', + 'satoshi', + 'sauce', + 'sausage', + 'save', + 'say', + 'scale', + 'scan', + 'scare', + 'scatter', + 'scene', + 'scheme', + 'school', + 'science', + 'scissors', + 'scorpion', + 'scout', + 'scrap', + 'screen', + 'script', + 'scrub', + 'sea', + 'search', + 'season', + 'seat', + 'second', + 'secret', + 'section', + 'security', + 'seed', + 'seek', + 'segment', + 'select', + 'sell', + 'seminar', + 'senior', + 'sense', + 'sentence', + 'series', + 'service', + 'session', + 'settle', + 'setup', + 'seven', + 'shadow', + 'shaft', + 'shallow', + 'share', + 'shed', + 'shell', + 'sheriff', + 'shield', + 'shift', + 'shine', + 'ship', + 'shiver', + 'shock', + 'shoe', + 'shoot', + 'shop', + 'short', + 'shoulder', + 'shove', + 'shrimp', + 'shrug', + 'shuffle', + 'shy', + 'sibling', + 'sick', + 'side', + 'siege', + 'sight', + 'sign', + 'silent', + 'silk', + 'silly', + 'silver', + 'similar', + 'simple', + 'since', + 'sing', + 'siren', + 'sister', + 'situate', + 'six', + 'size', + 'skate', + 'sketch', + 'ski', + 'skill', + 'skin', + 'skirt', + 'skull', + 'slab', + 'slam', + 'sleep', + 'slender', + 'slice', + 'slide', + 'slight', + 'slim', + 'slogan', + 'slot', + 'slow', + 'slush', + 'small', + 'smart', + 'smile', + 'smoke', + 'smooth', + 'snack', + 'snake', + 'snap', + 'sniff', + 'snow', + 'soap', + 'soccer', + 'social', + 'sock', + 'soda', + 'soft', + 'solar', + 'soldier', + 'solid', + 'solution', + 'solve', + 'someone', + 'song', + 'soon', + 'sorry', + 'sort', + 'soul', + 'sound', + 'soup', + 'source', + 'south', + 'space', + 'spare', + 'spatial', + 'spawn', + 'speak', + 'special', + 'speed', + 'spell', + 'spend', + 'sphere', + 'spice', + 'spider', + 'spike', + 'spin', + 'spirit', + 'split', + 'spoil', + 'sponsor', + 'spoon', + 'sport', + 'spot', + 'spray', + 'spread', + 'spring', + 'spy', + 'square', + 'squeeze', + 'squirrel', + 'stable', + 'stadium', + 'staff', + 'stage', + 'stairs', + 'stamp', + 'stand', + 'start', + 'state', + 'stay', + 'steak', + 'steel', + 'stem', + 'step', + 'stereo', + 'stick', + 'still', + 'sting', + 'stock', + 'stomach', + 'stone', + 'stool', + 'story', + 'stove', + 'strategy', + 'street', + 'strike', + 'strong', + 'struggle', + 'student', + 'stuff', + 'stumble', + 'style', + 'subject', + 'submit', + 'subway', + 'success', + 'such', + 'sudden', + 'suffer', + 'sugar', + 'suggest', + 'suit', + 'summer', + 'sun', + 'sunny', + 'sunset', + 'super', + 'supply', + 'supreme', + 'sure', + 'surface', + 'surge', + 'surprise', + 'surround', + 'survey', + 'suspect', + 'sustain', + 'swallow', + 'swamp', + 'swap', + 'swarm', + 'swear', + 'sweet', + 'swift', + 'swim', + 'swing', + 'switch', + 'sword', + 'symbol', + 'symptom', + 'syrup', + 'system', + 'table', + 'tackle', + 'tag', + 'tail', + 'talent', + 'talk', + 'tank', + 'tape', + 'target', + 'task', + 'taste', + 'tattoo', + 'taxi', + 'teach', + 'team', + 'tell', + 'ten', + 'tenant', + 'tennis', + 'tent', + 'term', + 'test', + 'text', + 'thank', + 'that', + 'theme', + 'then', + 'theory', + 'there', + 'they', + 'thing', + 'this', + 'thought', + 'three', + 'thrive', + 'throw', + 'thumb', + 'thunder', + 'ticket', + 'tide', + 'tiger', + 'tilt', + 'timber', + 'time', + 'tiny', + 'tip', + 'tired', + 'tissue', + 'title', + 'toast', + 'tobacco', + 'today', + 'toddler', + 'toe', + 'together', + 'toilet', + 'token', + 'tomato', + 'tomorrow', + 'tone', + 'tongue', + 'tonight', + 'tool', + 'tooth', + 'top', + 'topic', + 'topple', + 'torch', + 'tornado', + 'tortoise', + 'toss', + 'total', + 'tourist', + 'toward', + 'tower', + 'town', + 'toy', + 'track', + 'trade', + 'traffic', + 'tragic', + 'train', + 'transfer', + 'trap', + 'trash', + 'travel', + 'tray', + 'treat', + 'tree', + 'trend', + 'trial', + 'tribe', + 'trick', + 'trigger', + 'trim', + 'trip', + 'trophy', + 'trouble', + 'truck', + 'true', + 'truly', + 'trumpet', + 'trust', + 'truth', + 'try', + 'tube', + 'tuition', + 'tumble', + 'tuna', + 'tunnel', + 'turkey', + 'turn', + 'turtle', + 'twelve', + 'twenty', + 'twice', + 'twin', + 'twist', + 'two', + 'type', + 'typical', + 'ugly', + 'umbrella', + 'unable', + 'unaware', + 'uncle', + 'uncover', + 'under', + 'undo', + 'unfair', + 'unfold', + 'unhappy', + 'uniform', + 'unique', + 'unit', + 'universe', + 'unknown', + 'unlock', + 'until', + 'unusual', + 'unveil', + 'update', + 'upgrade', + 'uphold', + 'upon', + 'upper', + 'upset', + 'urban', + 'urge', + 'usage', + 'use', + 'used', + 'useful', + 'useless', + 'usual', + 'utility', + 'vacant', + 'vacuum', + 'vague', + 'valid', + 'valley', + 'valve', + 'van', + 'vanish', + 'vapor', + 'various', + 'vast', + 'vault', + 'vehicle', + 'velvet', + 'vendor', + 'venture', + 'venue', + 'verb', + 'verify', + 'version', + 'very', + 'vessel', + 'veteran', + 'viable', + 'vibrant', + 'vicious', + 'victory', + 'video', + 'view', + 'village', + 'vintage', + 'violin', + 'virtual', + 'virus', + 'visa', + 'visit', + 'visual', + 'vital', + 'vivid', + 'vocal', + 'voice', + 'void', + 'volcano', + 'volume', + 'vote', + 'voyage', + 'wage', + 'wagon', + 'wait', + 'walk', + 'wall', + 'walnut', + 'want', + 'warfare', + 'warm', + 'warrior', + 'wash', + 'wasp', + 'waste', + 'water', + 'wave', + 'way', + 'wealth', + 'weapon', + 'wear', + 'weasel', + 'weather', + 'web', + 'wedding', + 'weekend', + 'weird', + 'welcome', + 'west', + 'wet', + 'whale', + 'what', + 'wheat', + 'wheel', + 'when', + 'where', + 'whip', + 'whisper', + 'wide', + 'width', + 'wife', + 'wild', + 'will', + 'win', + 'window', + 'wine', + 'wing', + 'wink', + 'winner', + 'winter', + 'wire', + 'wisdom', + 'wise', + 'wish', + 'witness', + 'wolf', + 'woman', + 'wonder', + 'wood', + 'wool', + 'word', + 'work', + 'world', + 'worry', + 'worth', + 'wrap', + 'wreck', + 'wrestle', + 'wrist', + 'write', + 'wrong', + 'yard', + 'year', + 'yellow', + 'you', + 'young', + 'youth', + 'zebra', + 'zero', + 'zone', + 'zoo', +]; diff --git a/packages/lightwallet/common/validators/address.validator.ts b/packages/lightwallet/common/validators/address.validator.ts index 459dad5302..c9639492b3 100644 --- a/packages/lightwallet/common/validators/address.validator.ts +++ b/packages/lightwallet/common/validators/address.validator.ts @@ -7,20 +7,22 @@ export class AddressValidator { return async (abstractCtrl: AbstractControl) => { let { value } = abstractCtrl; - if (!value) - return { required: true }; + if (!value) return { required: true }; value = cleanAddress(value); - if (value.length < 3) - return { minlength: true }; + if (value.length < 3) return { minlength: true }; - if (!isAddress(value) && !couldBeAlias(value)) - return { InvalidFormat: true }; + if (!isAddress(value) && !couldBeAlias(value)) return { InvalidFormat: true }; const addressInfo = await getAddressInfo(value, mwcService); - if (!addressInfo || !addressInfo.isValid || !addressInfo.isBeaconed || (!allowUnconfirmed && !addressInfo.isConfirmed)) + if ( + !addressInfo || + !addressInfo.isValid || + !addressInfo.isBeaconed || + (!allowUnconfirmed && !addressInfo.isConfirmed) + ) return { AddressNotFound: true }; }; } @@ -29,18 +31,15 @@ export class AddressValidator { return async (abstractCtrl: AbstractControl) => { let { value } = abstractCtrl; - if (!value) - return null; + if (!value) return null; value = cleanAddress(value); - if (!couldBeAlias(value)) - return { InvalidFormat: true }; + if (!couldBeAlias(value)) return { InvalidFormat: true }; const addressInfo = await getAddressInfo(value, mwcService); - if (addressInfo && addressInfo.isConfirmed) - return { AliasInUse: true }; + if (addressInfo && addressInfo.isConfirmed) return { AliasInUse: true }; }; } } diff --git a/packages/lightwallet/common/validators/email.validator.spec.ts b/packages/lightwallet/common/validators/email.validator.spec.ts index 99f7d8858d..2249a4bf3d 100644 --- a/packages/lightwallet/common/validators/email.validator.spec.ts +++ b/packages/lightwallet/common/validators/email.validator.spec.ts @@ -4,6 +4,8 @@ import { EmailValidator } from './email.validator'; describe('Validators.Email', () => { it('should validate email', () => { expect(EmailValidator.isValidEmail({ value: 'valid@email.com' } as AbstractControl)).toBe(null); - expect(EmailValidator.isValidEmail({ value: 'definitelyNotAValidEmail' } as AbstractControl)).toHaveProperty('InvalidEmail'); + expect(EmailValidator.isValidEmail({ value: 'definitelyNotAValidEmail' } as AbstractControl)).toHaveProperty( + 'InvalidEmail', + ); }); }); diff --git a/packages/lightwallet/common/validators/email.validator.ts b/packages/lightwallet/common/validators/email.validator.ts index abf57bc535..a3f8c7970f 100644 --- a/packages/lightwallet/common/validators/email.validator.ts +++ b/packages/lightwallet/common/validators/email.validator.ts @@ -2,34 +2,35 @@ import { AbstractControl, ValidationErrors } from '@angular/forms'; import { ConfigService } from '@merit/common/services/config.service'; import { EmailNotificationsService } from '@merit/common/services/email-notification.service'; - export class EmailValidator { - static isValidEmail(control: AbstractControl) { - const validEmail = (/^[a-zA-Z0-9.!#$%&*+=?^_{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/).test(control.value); + const validEmail = /^[a-zA-Z0-9.!#$%&*+=?^_{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(control.value); if (!validEmail) { return { - InvalidEmail: true + InvalidEmail: true, }; } return null; } - static isValid(cnf: ConfigService, eml: EmailNotificationsService): (control: AbstractControl) => ValidationErrors | null { - return function (control: AbstractControl): ValidationErrors | null { + static isValid( + cnf: ConfigService, + eml: EmailNotificationsService, + ): (control: AbstractControl) => ValidationErrors | null { + return function(control: AbstractControl): ValidationErrors | null { const config = cnf.get(); const latestEmail = eml.getEmailIfEnabled(config); - const validEmail = (/^[a-zA-Z0-9.!#$%&*+=?^_{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/).test(control.value); + const validEmail = /^[a-zA-Z0-9.!#$%&*+=?^_{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(control.value); if (validEmail && control.value != latestEmail) { return null; } return { - 'Invalid Email': true + 'Invalid Email': true, }; - } + }; } } diff --git a/packages/lightwallet/common/validators/invite.validator.ts b/packages/lightwallet/common/validators/invite.validator.ts index 78e6fad140..146283afc2 100644 --- a/packages/lightwallet/common/validators/invite.validator.ts +++ b/packages/lightwallet/common/validators/invite.validator.ts @@ -2,12 +2,11 @@ import { AbstractControl } from '@angular/forms'; import { DisplayWallet } from '@merit/common/models/display-wallet'; export class InviteValidator { - static InviteQuantityValidator(control: AbstractControl) { try { - const wallet:DisplayWallet = control.parent.get("wallet").value; + const wallet: DisplayWallet = control.parent.get('wallet').value; if (control.value > wallet.sendableInvites) { - return { NotEnoughInvites: true } + return { NotEnoughInvites: true }; } } catch (e) { return null; diff --git a/packages/lightwallet/common/validators/mnemonic.validator.ts b/packages/lightwallet/common/validators/mnemonic.validator.ts index d9525f2b71..498c2c292b 100644 --- a/packages/lightwallet/common/validators/mnemonic.validator.ts +++ b/packages/lightwallet/common/validators/mnemonic.validator.ts @@ -7,12 +7,12 @@ export class MnemonicValidator { if (!isValidSize(words)) return { - InvalidSize: true + InvalidSize: true, }; if (!hasValidWords(words)) return { - InvalidWords: true + InvalidWords: true, }; return null; @@ -23,7 +23,7 @@ export class MnemonicValidator { if (!hasValidEntropy(words)) return { - InvalidEntropy: true + InvalidEntropy: true, }; return null; diff --git a/packages/lightwallet/common/validators/password.validator.ts b/packages/lightwallet/common/validators/password.validator.ts index c6a81ebb11..8f03672d0d 100644 --- a/packages/lightwallet/common/validators/password.validator.ts +++ b/packages/lightwallet/common/validators/password.validator.ts @@ -16,7 +16,7 @@ export class PasswordValidator { } static VerifyWalletPassword(wallet: MeritWalletClient): ValidatorFn { - return (control: AbstractControl) => wallet.checkPassword(control.value) ? null : { IncorrectPassword: true }; + return (control: AbstractControl) => (wallet.checkPassword(control.value) ? null : { IncorrectPassword: true }); } static ValidateEasyReceivePassword(receipt: EasyReceipt, easyReceiveService: EasyReceiveService): AsyncValidatorFn { @@ -24,7 +24,7 @@ export class PasswordValidator { const { txs } = await easyReceiveService.validateEasyReceiptOnBlockchain(receipt, control.value); if (!txs || !txs.length) { return { - IncorrectPassword: true + IncorrectPassword: true, }; } }; diff --git a/packages/lightwallet/common/validators/send.validator.spec.ts b/packages/lightwallet/common/validators/send.validator.spec.ts index 65ecaac77f..a9cfd5a9f1 100644 --- a/packages/lightwallet/common/validators/send.validator.spec.ts +++ b/packages/lightwallet/common/validators/send.validator.spec.ts @@ -4,25 +4,27 @@ import { SendValidator } from '@merit/common/validators/send.validator'; const mockObj: any = {}; describe('Validators.Send', () => { - describe('validateWallet', () => { it('should detect a valid wallet', () => { const result = SendValidator.validateWallet({ - value: new DisplayWallet({ - getRootAddress: () => 0, - } as any, mockObj, mockObj) + value: new DisplayWallet( + { + getRootAddress: () => 0, + } as any, + mockObj, + mockObj, + ), }); expect(result).toBe(null); }); it('should detect an invalid wallet', () => { - const result = SendValidator.validateWallet( { - value: {} + const result = SendValidator.validateWallet({ + value: {}, }); expect(result.InvalidWallet).toBeTruthy(); }); }); - }); diff --git a/packages/lightwallet/common/validators/send.validator.ts b/packages/lightwallet/common/validators/send.validator.ts index c78e819b13..4375a9217b 100644 --- a/packages/lightwallet/common/validators/send.validator.ts +++ b/packages/lightwallet/common/validators/send.validator.ts @@ -8,7 +8,7 @@ export class SendValidator { static validateWallet(control: AbstractControl) { if (!control.value || !(control.value instanceof DisplayWallet)) { return { - InvalidWallet: true + InvalidWallet: true, }; } @@ -32,30 +32,27 @@ export class SendValidator { } static validateMaximumAvailable(control: AbstractControl) { - const wallet:DisplayWallet = control.parent.get("wallet").value; + const wallet: DisplayWallet = control.parent.get('wallet').value; try { if (control.value > wallet.balance.spendableAmount) { - return { NotEnoughMRT: true } - } + return { NotEnoughMRT: true }; + } } catch (e) { return null; } } - static validateGlobalSendDestination(control: AbstractControl) { const { value } = control; - if (control.parent && control.parent.get('type').value === 'classic') - return null; + if (control.parent && control.parent.get('type').value === 'classic') return null; - if (!value || value.trim() == '') - return null; + if (!value || value.trim() == '') return null; if (!validatePhoneNumber(value) && !validateEmail(value)) return { - InvalidDestination: true + InvalidDestination: true, }; // validate email / phone number @@ -63,7 +60,7 @@ export class SendValidator { return null; } - static isEmail(value) { - return validateEmail(value); + static isEmail(value) { + return validateEmail(value); } } diff --git a/packages/lightwallet/desktop/e2e/app.e2e-spec.ts b/packages/lightwallet/desktop/e2e/app.e2e-spec.ts index 3e669f6537..f2e3f84832 100644 --- a/packages/lightwallet/desktop/e2e/app.e2e-spec.ts +++ b/packages/lightwallet/desktop/e2e/app.e2e-spec.ts @@ -12,7 +12,10 @@ export async function isBrowser(browser: string) { describe('[Desktop] Onboarding', () => { beforeAll(() => { // maximize window - browser.driver.manage().window().maximize(); + browser.driver + .manage() + .window() + .maximize(); browser.get('/'); @@ -29,7 +32,7 @@ describe('[Desktop] Onboarding', () => { expect(browser.getCurrentUrl()).toContain('onboarding'); }); - it('shouldn\'t let the user go to dashboard', async () => { + it("shouldn't let the user go to dashboard", async () => { await browser.get('/dashboard'); expect(browser.getCurrentUrl()).toContain('onboarding'); }); @@ -67,7 +70,6 @@ describe('[Desktop] Onboarding', () => { }); describe('> QT Wallet unboarding', () => { - beforeEach(() => { browser.get('/onboarding'); const el = element(by.css('[routerlink=tour-desktop]')); @@ -135,13 +137,10 @@ describe('[Desktop] Onboarding', () => { expect(browser.getCurrentUrl()).not.toContain('tour-desktop'); expect(browser.getCurrentUrl()).toContain('import'); }); - }); - }); describe('> Unlock view', () => { - let el; beforeAll(() => { @@ -184,13 +183,10 @@ describe('[Desktop] Onboarding', () => { browser.wait(EC.not(EC.urlContains('unlock'))); expect(browser.getCurrentUrl()).not.toContain('unlock'); }); - }); describe('> Import wallet', () => { - describe('> Main import view', () => { - beforeAll(() => { browser.get('/'); const el = element(by.css('[routerLink="import"]')); @@ -207,14 +203,10 @@ describe('[Desktop] Onboarding', () => { expect(mnemonicButton.isDisplayed()).toBeTruthy(); }); - it('should have a file backup option', async () => { - - }); - + it('should have a file backup option', async () => {}); }); describe('> Mnemonic phrase', () => { - let mnemonicButton, mnemonicInput, submitButton; beforeAll(() => { @@ -247,13 +239,10 @@ describe('[Desktop] Onboarding', () => { browser.wait(EC.urlContains('wallets')); expect(browser.getCurrentUrl()).toContain('wallets'); }); - }); // describe('File backup', () => { // // }); - }); - }); diff --git a/packages/lightwallet/desktop/e2e/community.e2e-spec.ts b/packages/lightwallet/desktop/e2e/community.e2e-spec.ts index dda236023f..657b55a523 100644 --- a/packages/lightwallet/desktop/e2e/community.e2e-spec.ts +++ b/packages/lightwallet/desktop/e2e/community.e2e-spec.ts @@ -80,7 +80,8 @@ describe('[Desktop] Community', () => { }); it('should show "Copy to clipboard" when user hovers over invite code', async () => { - browser.actions() + browser + .actions() .mouseMove(inviteCodeEl) .perform(); diff --git a/packages/lightwallet/desktop/e2e/dashboard.e2e-spec.ts b/packages/lightwallet/desktop/e2e/dashboard.e2e-spec.ts index 5d80096d60..419f317bed 100644 --- a/packages/lightwallet/desktop/e2e/dashboard.e2e-spec.ts +++ b/packages/lightwallet/desktop/e2e/dashboard.e2e-spec.ts @@ -2,7 +2,6 @@ import { browser, by, element } from 'protractor'; import { TEST_WALLET_MNEMONIC, EC } from './app.e2e-spec'; describe('[Desktop] Dashboard view', () => { - beforeAll(() => { const link = element(by.css('[ng-reflect-router-link="/dashboard"]')); browser.wait(EC.visibilityOf(link), 5000); @@ -19,7 +18,6 @@ describe('[Desktop] Dashboard view', () => { }); describe('> Welcome guide', () => { - let rootEl; beforeEach(() => { @@ -67,8 +65,5 @@ describe('[Desktop] Dashboard view', () => { browser.sleep(200); expect(rootEl.isPresent()).toBeFalsy('Guide is still visible'); }); - }); - - }); diff --git a/packages/lightwallet/desktop/e2e/history.e2e-spec.ts b/packages/lightwallet/desktop/e2e/history.e2e-spec.ts index 07a2fd6540..9c75f6fb19 100644 --- a/packages/lightwallet/desktop/e2e/history.e2e-spec.ts +++ b/packages/lightwallet/desktop/e2e/history.e2e-spec.ts @@ -2,7 +2,6 @@ import { browser, by, element } from 'protractor'; import { EC } from './app.e2e-spec'; describe('[Desktop] History', () => { - beforeAll(() => { const link = element(by.css('[ng-reflect-router-link="/history"]')); browser.wait(EC.visibilityOf(link), 5000); @@ -23,5 +22,4 @@ describe('[Desktop] History', () => { it('should have a list of history items', () => { expect(element(by.css('history-list history-item')).isDisplayed()).toBeTruthy(); }); - }); diff --git a/packages/lightwallet/desktop/e2e/send-flow.e2e-spec.ts b/packages/lightwallet/desktop/e2e/send-flow.e2e-spec.ts index a23c231ca3..4056326ade 100644 --- a/packages/lightwallet/desktop/e2e/send-flow.e2e-spec.ts +++ b/packages/lightwallet/desktop/e2e/send-flow.e2e-spec.ts @@ -2,7 +2,6 @@ import { browser, by, element } from 'protractor'; import { EC, TEST_WALLET_ALIAS } from './app.e2e-spec'; describe('[Desktop] Sending Merit', () => { - beforeAll(() => { const link = element(by.css('[ng-reflect-router-link="/send"]')); browser.wait(EC.visibilityOf(link), 5000); @@ -84,7 +83,6 @@ describe('[Desktop] Sending Merit', () => { }); describe('> Sending', () => { - const amountInputEl = element(by.css('[formcontrolname=amountMrt]')), selectBoxEl = element(by.css('.ui-input.ui-input--select.ui-input--form.selectbox__selected')), selectMethodEl = element(by.css('.select-method')), @@ -251,7 +249,5 @@ describe('[Desktop] Sending Merit', () => { }); }); }); - }); - }); diff --git a/packages/lightwallet/desktop/e2e/wallet-details.e2e-spec.ts b/packages/lightwallet/desktop/e2e/wallet-details.e2e-spec.ts index eb04f1accb..aaa9528812 100644 --- a/packages/lightwallet/desktop/e2e/wallet-details.e2e-spec.ts +++ b/packages/lightwallet/desktop/e2e/wallet-details.e2e-spec.ts @@ -2,21 +2,23 @@ import { browser, by, element, protractor } from 'protractor'; import { EC, TEST_WALLET_ALIAS, TEST_WALLET_MNEMONIC, TEST_WALLET_NAME } from './app.e2e-spec'; describe('[Desktop] Wallet details view', () => { - let header, walletId; beforeAll(async () => { const link = element(by.css('[ng-reflect-router-link="/dashboard"]')); - browser.wait(EC.visibilityOf(link), 5000, 'Dashboard menu link isn\'t visible'); + browser.wait(EC.visibilityOf(link), 5000, "Dashboard menu link isn't visible"); link.click(); - browser.wait(EC.urlContains('dashboard'), 5000, 'URL doesn\'t contain dashboard'); + browser.wait(EC.urlContains('dashboard'), 5000, "URL doesn't contain dashboard"); const el = element(by.css('wallets-list .wallets__group__wallet')); browser.wait(EC.visibilityOf(el), 8000, 'Wallet list item is not visible'); await el.click(); - browser.wait(EC.urlContains('wallets'), 5000, 'URL doesn\'t contain wallets'); + browser.wait(EC.urlContains('wallets'), 5000, "URL doesn't contain wallets"); header = element(by.css('.wallet-details__header')); browser.wait(EC.visibilityOf(header), 5000); - walletId = (await browser.getCurrentUrl()).replace('/history', '').split('/').pop(); + walletId = (await browser.getCurrentUrl()) + .replace('/history', '') + .split('/') + .pop(); }); it('should go to wallet details view', async () => { @@ -53,7 +55,6 @@ describe('[Desktop] Wallet details view', () => { }); describe('> History tab', () => { - it('url should have /history', () => { expect(EC.urlContains('/history')).toBeTruthy(); }); @@ -62,14 +63,10 @@ describe('[Desktop] Wallet details view', () => { // it('should have wallet unlocked transaction', async () => { // expect(await element(by.css('history-item:last-child')).getText()).toContain('Wallet Unlocked'); // }); - }); describe('> Preferences tab', () => { - - let header, - initialHeaderColor: string, - initialToolbarBalance: string; + let header, initialHeaderColor: string, initialToolbarBalance: string; beforeAll(async () => { element(by.css('a[href*="settings"]')).click(); @@ -90,7 +87,7 @@ describe('[Desktop] Wallet details view', () => { expect(await element(by.css('app-select')).getText()).toContain('Merit blue'); }); - it('header color should change when we change the wallet\'s color', () => { + it("header color should change when we change the wallet's color", () => { element(by.css('app-select .selectbox > button')).click(); element(by.css('app-select .selectbox__dropdown button:first-child')).click(); expect(element(by.css('.wallet-details__header')).getAttribute('style')).not.toEqual(initialHeaderColor); @@ -112,7 +109,10 @@ describe('[Desktop] Wallet details view', () => { }); it('should hide balance in app toolbar', () => { - expect(element(by.css('app-toolbar .amount-merit')).getText()).not.toEqual(initialToolbarBalance, 'Toolbar balance didn\'t change'); + expect(element(by.css('app-toolbar .amount-merit')).getText()).not.toEqual( + initialToolbarBalance, + "Toolbar balance didn't change", + ); }); it('should make balance visible', async () => { @@ -120,11 +120,9 @@ describe('[Desktop] Wallet details view', () => { browser.wait(EC.not(EC.textToBePresentInElement(header, '[Balance hidden]'))); expect(header.getText()).not.toContain('[Balance hidden]', 'Unable to un-hide balance'); }); - }); describe('> Backup tab', () => { - beforeAll(async () => { element(by.css('a[href*="export"]')).click(); }); @@ -152,7 +150,6 @@ describe('[Desktop] Wallet details view', () => { }); describe('> QR Code backup', () => { - beforeAll(() => { element(by.css('div[routerLink=qr-code]')).click(); browser.wait(EC.urlContains('qr-code')); @@ -165,7 +162,7 @@ describe('[Desktop] Wallet details view', () => { it('should have QR Code Backup title', () => { const el = element(by.css('.page-title h3')); expect(el.isDisplayed()).toBeTruthy('Title is not visible'); - expect(el.getText()).toContain('QR Code backup', 'Doesn\'t have the right title'); + expect(el.getText()).toContain('QR Code backup', "Doesn't have the right title"); }); it('should have a QR code image', () => { @@ -176,7 +173,7 @@ describe('[Desktop] Wallet details view', () => { it('should have a back button', () => { backButton = element(by.css('[routerlink="../"]')); - expect(backButton.isDisplayed()).toBeTruthy('Back button doesn\'t exist'); + expect(backButton.isDisplayed()).toBeTruthy("Back button doesn't exist"); }); it('should take us back to root export page when clicking on back button', () => { @@ -184,11 +181,9 @@ describe('[Desktop] Wallet details view', () => { browser.wait(EC.not(EC.urlContains('qr-code'))); expect(browser.getCurrentUrl()).not.toContain('qr-code'); }); - }); describe('> Mnemonic phrase backup', () => { - beforeAll(() => { element(by.css('div[routerLink=mnemonic]')).click(); browser.wait(EC.urlContains('mnemonic')); @@ -201,20 +196,20 @@ describe('[Desktop] Wallet details view', () => { it('should have a Mnemonic Phrase title', () => { const el = element(by.css('.page-title h3')); expect(el.isDisplayed()).toBeTruthy('Title is not visible'); - expect(el.getText()).toContain('Mnemonic Phrase', 'Doesn\'t have the right title'); + expect(el.getText()).toContain('Mnemonic Phrase', "Doesn't have the right title"); }); it('should display mnemonic phrase', () => { const el = element(by.css('.mnemonic-container')); expect(el.isDisplayed()).toBeTruthy('Mnemonic container not visible'); - expect(el.getText()).toContain(TEST_WALLET_MNEMONIC, 'Doesn\'t show mnemonic'); + expect(el.getText()).toContain(TEST_WALLET_MNEMONIC, "Doesn't show mnemonic"); }); let backButton; it('should have a back button', () => { backButton = element(by.css('[routerlink="../"]')); - expect(backButton.isDisplayed()).toBeTruthy('Back button doesn\'t exist'); + expect(backButton.isDisplayed()).toBeTruthy("Back button doesn't exist"); }); it('should take us back to root export page when clicking on back button', () => { @@ -222,11 +217,9 @@ describe('[Desktop] Wallet details view', () => { browser.wait(EC.not(EC.urlContains('mnemonic'))); expect(browser.getCurrentUrl()).not.toContain('mnemonic'); }); - }); describe('> Backup file export', () => { - beforeAll(() => { element(by.css('div[routerLink=file]')).click(); browser.wait(EC.urlContains('file')); @@ -239,7 +232,7 @@ describe('[Desktop] Wallet details view', () => { it('should have a File backup title', () => { const el = element(by.css('.page-title h3')); expect(el.isDisplayed()).toBeTruthy('Title is not visible'); - expect(el.getText()).toContain('File backup', 'Doesn\'t have the right title'); + expect(el.getText()).toContain('File backup', "Doesn't have the right title"); }); let passwordEl, repeatPasswordEl, submitButtonEl; @@ -282,9 +275,6 @@ describe('[Desktop] Wallet details view', () => { it('download file button should be enabled', () => { expect(submitButtonEl.isEnabled()).toBeTruthy(); }); - }); - }); - }); diff --git a/packages/lightwallet/desktop/electron.bootstrap.js b/packages/lightwallet/desktop/electron.bootstrap.js index ed74bcc180..321073a8c9 100644 --- a/packages/lightwallet/desktop/electron.bootstrap.js +++ b/packages/lightwallet/desktop/electron.bootstrap.js @@ -19,7 +19,7 @@ const showWindowsNotification = (title, message = ' ') => { icon, appId: 'wallet.merit.me', wait: true, - sound: true + sound: true, }); }; @@ -28,8 +28,8 @@ nn.on('click', () => { }); window['electron'] = { - showNotification: isWin? showWindowsNotification : showNotification, + showNotification: isWin ? showWindowsNotification : showNotification, checkForUpdates: updater.checkForUpdates, downloadUpdate: updater.downloadUpdate, - installUpdate: updater.installUpdate + installUpdate: updater.installUpdate, }; diff --git a/packages/lightwallet/desktop/electron.main.js b/packages/lightwallet/desktop/electron.main.js index c643feb36a..077d6b66ae 100644 --- a/packages/lightwallet/desktop/electron.main.js +++ b/packages/lightwallet/desktop/electron.main.js @@ -31,8 +31,8 @@ function buildMenuTemplate() { { role: 'paste' }, { role: 'pasteandmatchstyle' }, { role: 'delete' }, - { role: 'selectall' } - ] + { role: 'selectall' }, + ], }, { label: 'View', @@ -43,26 +43,24 @@ function buildMenuTemplate() { { role: 'resetzoom' }, { role: 'zoomin' }, { role: 'zoomout' }, - { type: 'separator' } - ] + { type: 'separator' }, + ], }, { role: 'window', - submenu: [ - { role: 'minimize' }, - { role: 'close' }, - { role: 'toggledevtools' } - ] + submenu: [{ role: 'minimize' }, { role: 'close' }, { role: 'toggledevtools' }], }, { role: 'help', submenu: [ { label: 'Learn More', - click() { shell.openExternal('https://www.merit.me'); } - } - ] - } + click() { + shell.openExternal('https://www.merit.me'); + }, + }, + ], + }, ]; if (process.platform === 'darwin') { @@ -77,8 +75,8 @@ function buildMenuTemplate() { { role: 'hideothers' }, { role: 'unhide' }, { type: 'separator' }, - { role: 'quit', label: `Quit ${appName}` } - ] + { role: 'quit', label: `Quit ${appName}` }, + ], }); } @@ -93,10 +91,8 @@ function createWindow() { let after; - if (dir.includes('assets')) - after = path.resolve(__dirname, 'dist', 'assets', dir.split(/assets\/?/).pop(), base); - else - after = path.resolve(__dirname, 'dist', base); + if (dir.includes('assets')) after = path.resolve(__dirname, 'dist', 'assets', dir.split(/assets\/?/).pop(), base); + else after = path.resolve(__dirname, 'dist', base); cb(after); }); @@ -106,20 +102,20 @@ function createWindow() { height: 720, autoHideMenuBar: true, webPreferences: { - devTools: true - } + devTools: true, + }, }); const URL = url.format({ pathname: path.resolve(__dirname, './dist/index.html'), protocol: 'file:', - slashes: true + slashes: true, }); mainWindow.loadURL(URL); mainWindow.maximize(); - mainWindow.on('closed', function () { + mainWindow.on('closed', function() { mainWindow = null; }); @@ -139,7 +135,7 @@ ipcMain.on('notificationClick', () => { app.on('ready', createWindow); // Quit when all windows are closed. -app.on('window-all-closed', function () { +app.on('window-all-closed', function() { // On OS X it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q if (process.platform !== 'darwin') { @@ -147,7 +143,7 @@ app.on('window-all-closed', function () { } }); -app.on('activate', function () { +app.on('activate', function() { log.verbose('App activated'); // On OS X it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. diff --git a/packages/lightwallet/desktop/electron.updater.js b/packages/lightwallet/desktop/electron.updater.js index 64ffec57ea..8d434fd48e 100644 --- a/packages/lightwallet/desktop/electron.updater.js +++ b/packages/lightwallet/desktop/electron.updater.js @@ -24,10 +24,10 @@ const checkForUpdates = async () => { const file = res.updateInfo.files[0]; return { - size: file.size? (Math.round(file.size / 1024 / 1024 * 100) / 100) + 'MB' : 'Unknown', + size: file.size ? Math.round((file.size / 1024 / 1024) * 100) / 100 + 'MB' : 'Unknown', releaseDate: res.updateInfo.releaseDate, releaseNotes: res.updateInfo.releaseNotes, - version: res.updateInfo.version + version: res.updateInfo.version, }; } } catch (err) { @@ -38,7 +38,7 @@ const checkForUpdates = async () => { const downloadUpdate = async progressCallback => { autoUpdater.on('download-progress', progressCallback); try { - await autoUpdater.downloadUpdate() + await autoUpdater.downloadUpdate(); } catch (err) { log.error('Error downloading update', err); } @@ -49,5 +49,5 @@ const installUpdate = () => autoUpdater.quitAndInstall(false, true); module.exports = { checkForUpdates, downloadUpdate, - installUpdate + installUpdate, }; diff --git a/packages/lightwallet/desktop/src/app/app-routing.module.ts b/packages/lightwallet/desktop/src/app/app-routing.module.ts index 3696d567e2..b86208e9fd 100644 --- a/packages/lightwallet/desktop/src/app/app-routing.module.ts +++ b/packages/lightwallet/desktop/src/app/app-routing.module.ts @@ -14,7 +14,12 @@ import { RateService } from '@merit/common/services/rate.service'; @Injectable() export class CoreModuleResolver implements Resolve { - constructor(private appService: AppSettingsService, private ratesService: RateService, private profileService: ProfileService, private store: Store) {} + constructor( + private appService: AppSettingsService, + private ratesService: RateService, + private profileService: ProfileService, + private store: Store, + ) {} // resolver here is a hack for lazy loaded CoreModule route // TODO: figure out if there is a better place to hook in in module initialization process @@ -22,24 +27,34 @@ export class CoreModuleResolver implements Resolve { await this.appService.getInfo(); await this.ratesService.loadRates(); - this.store.select(selectAppState).pipe( - filter((state: IAppState) => state.authorized), - tap((state: IAppState) => this.store.dispatch(new RefreshWalletsAction())) - ).subscribe(); + this.store + .select(selectAppState) + .pipe( + filter((state: IAppState) => state.authorized), + tap((state: IAppState) => this.store.dispatch(new RefreshWalletsAction())), + ) + .subscribe(); } } const routes: Routes = [ - { path: 'onboarding', loadChildren: './onboarding/onboarding.module#OnboardingModule', canActivate: [OnboardingGuard] }, + { + path: 'onboarding', + loadChildren: './onboarding/onboarding.module#OnboardingModule', + canActivate: [OnboardingGuard], + }, { path: 'market', loadChildren: './market/market.module#MarketModule', canActivate: [DashboardGuard] }, - { path: '', loadChildren: './core/core.module#CoreModule', canActivate: [DashboardGuard], resolve: { init: CoreModuleResolver } } + { + path: '', + loadChildren: './core/core.module#CoreModule', + canActivate: [DashboardGuard], + resolve: { init: CoreModuleResolver }, + }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], - providers: [ - CoreModuleResolver, - ] + providers: [CoreModuleResolver], }) -export class AppRoutingModule { } +export class AppRoutingModule {} diff --git a/packages/lightwallet/desktop/src/app/app.component.ts b/packages/lightwallet/desktop/src/app/app.component.ts index 1266882084..cce79489c4 100644 --- a/packages/lightwallet/desktop/src/app/app.component.ts +++ b/packages/lightwallet/desktop/src/app/app.component.ts @@ -10,14 +10,16 @@ import { ElectronService, IUpdateInfo } from '@merit/desktop/services/electron.s selector: 'merit-lw', templateUrl: './app.component.html', styleUrls: ['./app.component.sass'], - encapsulation: ViewEncapsulation.None + encapsulation: ViewEncapsulation.None, }) export class AppComponent { - constructor(private domCtrl: DOMController, - private renderer2: Renderer2, - private easyReceiveService: EasyReceiveService, - private updateDialogCtrl: UpdateDialogController, - private perstitenceService: PersistenceService2) { + constructor( + private domCtrl: DOMController, + private renderer2: Renderer2, + private easyReceiveService: EasyReceiveService, + private updateDialogCtrl: UpdateDialogController, + private perstitenceService: PersistenceService2, + ) { // Services can't inject Renderer, so this is a workaround. domCtrl.rnd = renderer2; } diff --git a/packages/lightwallet/desktop/src/app/app.module.ts b/packages/lightwallet/desktop/src/app/app.module.ts index ec256a0184..4599ade547 100644 --- a/packages/lightwallet/desktop/src/app/app.module.ts +++ b/packages/lightwallet/desktop/src/app/app.module.ts @@ -49,7 +49,7 @@ export function loadConfigs(profileService: ProfileService, store: Store { - let instance: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ConfirmDialogComponent, BackdropComponent] + declarations: [ConfirmDialogComponent, BackdropComponent], }).compileComponents(); instance = TestBed.createComponent(ConfirmDialogComponent); @@ -18,12 +17,12 @@ describe('Confirm Dialog', () => { buttons: [ { text: 'Ok', - class: 'primary' + class: 'primary', }, { - text: 'Cancel' - } - ] + text: 'Cancel', + }, + ], }); instance.detectChanges(); }); @@ -69,5 +68,4 @@ describe('Confirm Dialog', () => { instance.detectChanges(); expect(spy).toHaveBeenCalledWith(); }); - }); diff --git a/packages/lightwallet/desktop/src/app/components/dom.controller.ts b/packages/lightwallet/desktop/src/app/components/dom.controller.ts index 033cd1639e..22d74fc8b9 100644 --- a/packages/lightwallet/desktop/src/app/components/dom.controller.ts +++ b/packages/lightwallet/desktop/src/app/components/dom.controller.ts @@ -5,7 +5,7 @@ import { Injectable, Injector, Renderer2, - Type + Type, } from '@angular/core'; export interface IDynamicComponent { @@ -30,9 +30,7 @@ export interface IDynamicComponent { export class DOMController { rnd: Renderer2; - constructor(private appRef: ApplicationRef, - private cfr: ComponentFactoryResolver, - private injector: Injector) {} + constructor(private appRef: ApplicationRef, private cfr: ComponentFactoryResolver, private injector: Injector) {} create(component: Type, config: any, parentElement?: HTMLElement) { const componentRef = this.cfr.resolveComponentFactory(component).create(this.injector); diff --git a/packages/lightwallet/desktop/src/app/components/globalsend-link-popup/globalsend-link-popup.component.ts b/packages/lightwallet/desktop/src/app/components/globalsend-link-popup/globalsend-link-popup.component.ts index c8d44fc8bf..6a2712fcb2 100644 --- a/packages/lightwallet/desktop/src/app/components/globalsend-link-popup/globalsend-link-popup.component.ts +++ b/packages/lightwallet/desktop/src/app/components/globalsend-link-popup/globalsend-link-popup.component.ts @@ -20,7 +20,7 @@ import { ToastControllerService } from '../toast-notification/toast-controller.s - ` + `, }) export class GlobalsendLinkPopupComponent implements IDynamicComponent { destroy: Function; @@ -35,7 +35,7 @@ export class GlobalsendLinkPopupComponent implements IDynamicComponent { } onCopy() { - this.toastCtrl.success((this.isInvite? 'MeritInvite' : 'MeritMoney') + ' link copied!'); + this.toastCtrl.success((this.isInvite ? 'MeritInvite' : 'MeritMoney') + ' link copied!'); } dismiss() { diff --git a/packages/lightwallet/desktop/src/app/components/illustations/sending-merit/sending-merit.component.ts b/packages/lightwallet/desktop/src/app/components/illustations/sending-merit/sending-merit.component.ts index 9326f3adb2..58489b68ff 100644 --- a/packages/lightwallet/desktop/src/app/components/illustations/sending-merit/sending-merit.component.ts +++ b/packages/lightwallet/desktop/src/app/components/illustations/sending-merit/sending-merit.component.ts @@ -3,6 +3,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'illustations-sending-merit', templateUrl: './sending-merit.component.html', - styleUrls: ['./sending-merit.component.sass'] + styleUrls: ['./sending-merit.component.sass'], }) export class IllustationsSendingMeritComponent {} diff --git a/packages/lightwallet/desktop/src/app/components/illustations/thats-it/thats-it.component.ts b/packages/lightwallet/desktop/src/app/components/illustations/thats-it/thats-it.component.ts index db2ed69056..b8471e59bb 100644 --- a/packages/lightwallet/desktop/src/app/components/illustations/thats-it/thats-it.component.ts +++ b/packages/lightwallet/desktop/src/app/components/illustations/thats-it/thats-it.component.ts @@ -1,8 +1,8 @@ -import { Component} from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'illustations-thats-it', templateUrl: './thats-it.component.html', - styleUrls: ['./thats-it.component.sass'] + styleUrls: ['./thats-it.component.sass'], }) export class IllustationsThatsItComponent {} diff --git a/packages/lightwallet/desktop/src/app/components/illustations/worry-free/worry-free.component.ts b/packages/lightwallet/desktop/src/app/components/illustations/worry-free/worry-free.component.ts index bfdf87ab03..e4226b9a9a 100644 --- a/packages/lightwallet/desktop/src/app/components/illustations/worry-free/worry-free.component.ts +++ b/packages/lightwallet/desktop/src/app/components/illustations/worry-free/worry-free.component.ts @@ -3,6 +3,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'illustations-worry-free', templateUrl: './worry-free.component.html', - styleUrls: ['./worry-free.component.sass'] + styleUrls: ['./worry-free.component.sass'], }) export class IllustationsWorryFreeComponent {} diff --git a/packages/lightwallet/desktop/src/app/components/illustations/your-way/your-way.component.ts b/packages/lightwallet/desktop/src/app/components/illustations/your-way/your-way.component.ts index c7defd6c3d..4587dda5f6 100644 --- a/packages/lightwallet/desktop/src/app/components/illustations/your-way/your-way.component.ts +++ b/packages/lightwallet/desktop/src/app/components/illustations/your-way/your-way.component.ts @@ -3,6 +3,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'illustations-your-way', templateUrl: './your-way.component.html', - styleUrls: ['./your-way.component.sass'] + styleUrls: ['./your-way.component.sass'], }) export class IllustationsYourWayComponent {} diff --git a/packages/lightwallet/desktop/src/app/components/loading-spinner-small/loading-spinner-small.component.ts b/packages/lightwallet/desktop/src/app/components/loading-spinner-small/loading-spinner-small.component.ts index 8653b7c34e..fd94d80e06 100644 --- a/packages/lightwallet/desktop/src/app/components/loading-spinner-small/loading-spinner-small.component.ts +++ b/packages/lightwallet/desktop/src/app/components/loading-spinner-small/loading-spinner-small.component.ts @@ -3,6 +3,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'loading-spinner-small', templateUrl: './loading-spinner-small.component.html', - styleUrls: ['./loading-spinner-small.component.sass'] + styleUrls: ['./loading-spinner-small.component.sass'], }) export class LoadingSpinnerSmallComponent {} diff --git a/packages/lightwallet/desktop/src/app/components/loading-spinner/loading-spinner.component.ts b/packages/lightwallet/desktop/src/app/components/loading-spinner/loading-spinner.component.ts index f2b2eaa057..a3c1bc5217 100644 --- a/packages/lightwallet/desktop/src/app/components/loading-spinner/loading-spinner.component.ts +++ b/packages/lightwallet/desktop/src/app/components/loading-spinner/loading-spinner.component.ts @@ -3,6 +3,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'loading-spinner', templateUrl: './loading-spinner.component.html', - styleUrls: ['./loading-spinner.component.sass'] + styleUrls: ['./loading-spinner.component.sass'], }) export class LoadingSpinnerComponent {} diff --git a/packages/lightwallet/desktop/src/app/components/lock-screen/lock-screen.component.ts b/packages/lightwallet/desktop/src/app/components/lock-screen/lock-screen.component.ts index a4671428bd..a82e3cec84 100644 --- a/packages/lightwallet/desktop/src/app/components/lock-screen/lock-screen.component.ts +++ b/packages/lightwallet/desktop/src/app/components/lock-screen/lock-screen.component.ts @@ -3,14 +3,14 @@ import { Component, Input } from '@angular/core'; @Component({ selector: 'app-lock-screen', templateUrl: './lock-screen.component.html', - styleUrls: ['./lock-screen.component.sass'] + styleUrls: ['./lock-screen.component.sass'], }) export class LockScreenComponent { private _fullScreen: boolean; @Input() set fullScreen(val: any) { - this._fullScreen = val? Boolean(val) : true; + this._fullScreen = val ? Boolean(val) : true; } get fullScreen() { diff --git a/packages/lightwallet/desktop/src/app/components/merit-icon/merit-icon.component.ts b/packages/lightwallet/desktop/src/app/components/merit-icon/merit-icon.component.ts index a829374b92..92ecad1c00 100644 --- a/packages/lightwallet/desktop/src/app/components/merit-icon/merit-icon.component.ts +++ b/packages/lightwallet/desktop/src/app/components/merit-icon/merit-icon.component.ts @@ -5,9 +5,10 @@ import { Component, Input } from '@angular/core'; template: '', styleUrls: ['./merit-icon.component.sass'], host: { - '[class]': 'name' - } + '[class]': 'name', + }, }) export class MeritIconComponent { - @Input() name: string; + @Input() + name: string; } diff --git a/packages/lightwallet/desktop/src/app/components/message-box/message-box.component.ts b/packages/lightwallet/desktop/src/app/components/message-box/message-box.component.ts index 6aabd3f048..1f398e1971 100644 --- a/packages/lightwallet/desktop/src/app/components/message-box/message-box.component.ts +++ b/packages/lightwallet/desktop/src/app/components/message-box/message-box.component.ts @@ -3,6 +3,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'message-box', templateUrl: './message-box.component.html', - styleUrls: ['./message-box.component.sass'] + styleUrls: ['./message-box.component.sass'], }) export class MessageBoxComponent {} diff --git a/packages/lightwallet/desktop/src/app/components/password-prompt/password-prompt.component.ts b/packages/lightwallet/desktop/src/app/components/password-prompt/password-prompt.component.ts index ec12613998..9e638ec612 100644 --- a/packages/lightwallet/desktop/src/app/components/password-prompt/password-prompt.component.ts +++ b/packages/lightwallet/desktop/src/app/components/password-prompt/password-prompt.component.ts @@ -13,7 +13,7 @@ export interface IPasswordPromptConfig { @Component({ selector: 'password-prompt', templateUrl: './password-prompt.component.html', - styleUrls: ['./password-prompt.component.sass'] + styleUrls: ['./password-prompt.component.sass'], }) export class PasswordPromptComponent implements IDynamicComponent { destroy: Function; @@ -22,7 +22,9 @@ export class PasswordPromptComponent implements IDynamicComponent { ready: boolean; title: string; - get password(): AbstractControl { return this.formData.get('password'); } + get password(): AbstractControl { + return this.formData.get('password'); + } constructor(private formBuilder: FormBuilder) {} @@ -30,7 +32,7 @@ export class PasswordPromptComponent implements IDynamicComponent { this.title = config.title; this.formData = this.formBuilder.group({ - password: ['', config.validators, config.asyncValidators] + password: ['', config.validators, config.asyncValidators], }); this.ready = true; diff --git a/packages/lightwallet/desktop/src/app/components/password-prompt/password-prompt.controller.ts b/packages/lightwallet/desktop/src/app/components/password-prompt/password-prompt.controller.ts index 77f353f716..cf541e83ca 100644 --- a/packages/lightwallet/desktop/src/app/components/password-prompt/password-prompt.controller.ts +++ b/packages/lightwallet/desktop/src/app/components/password-prompt/password-prompt.controller.ts @@ -16,7 +16,7 @@ export class PasswordPromptController { createForWallet(wallet: DisplayWallet | MeritWalletClient) { const validators: ValidatorFn[] = [Validators.required]; - validators.push(PasswordValidator.VerifyWalletPassword(wallet instanceof DisplayWallet? wallet.client : wallet)); + validators.push(PasswordValidator.VerifyWalletPassword(wallet instanceof DisplayWallet ? wallet.client : wallet)); return this.create('Enter password for wallet: ' + wallet.name, validators); } } diff --git a/packages/lightwallet/desktop/src/app/components/password-prompt/password-prompt.spec.ts b/packages/lightwallet/desktop/src/app/components/password-prompt/password-prompt.spec.ts index bca85e3616..5e17c1bf40 100644 --- a/packages/lightwallet/desktop/src/app/components/password-prompt/password-prompt.spec.ts +++ b/packages/lightwallet/desktop/src/app/components/password-prompt/password-prompt.spec.ts @@ -5,17 +5,12 @@ import { BackdropComponent } from '../backdrop/backdrop.component'; import { PasswordPromptComponent } from './password-prompt.component'; describe('Password Prompt', () => { - let instance: ComponentFixture, - de: DebugElement, - comp: PasswordPromptComponent; + let instance: ComponentFixture, de: DebugElement, comp: PasswordPromptComponent; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [PasswordPromptComponent, BackdropComponent], - imports: [ - FormsModule, - ReactiveFormsModule - ] + imports: [FormsModule, ReactiveFormsModule], }).compileComponents(); instance = TestBed.createComponent(PasswordPromptComponent); @@ -23,7 +18,7 @@ describe('Password Prompt', () => { comp.init({ title: 'Enter password', validators: [Validators.required], - asyncValidators: [] + asyncValidators: [], }); instance.detectChanges(); de = instance.debugElement; @@ -34,11 +29,11 @@ describe('Password Prompt', () => { }); it('should display a title', () => { - expect(de.nativeElement.querySelector('h2.title').innerHTML).toContain('Enter password'); + expect(de.nativeElement.querySelector('h2.title').innerHTML).toContain('Enter password'); }); it('should display a password input', () => { - expect(de.nativeElement.querySelector('input[type=password]')).toBeDefined(); + expect(de.nativeElement.querySelector('input[type=password]')).toBeDefined(); }); it('should validate password input', () => { diff --git a/packages/lightwallet/desktop/src/app/components/shared-components.module.ts b/packages/lightwallet/desktop/src/app/components/shared-components.module.ts index 018ce4aa2d..91446d690f 100644 --- a/packages/lightwallet/desktop/src/app/components/shared-components.module.ts +++ b/packages/lightwallet/desktop/src/app/components/shared-components.module.ts @@ -51,7 +51,7 @@ export function getComponents() { UICheckboxComponent, WalletUnlockAlertComponent, SmsNotificationsPromptComponent, - UpdateDialogComponent + UpdateDialogComponent, ]; } @@ -62,7 +62,7 @@ export function getComponents() { ConfirmDialogComponent, GlobalsendLinkPopupComponent, SmsNotificationsPromptComponent, - UpdateDialogComponent + UpdateDialogComponent, ], imports: [CommonModule, FormsModule, ReactiveFormsModule, ClipModule, CommonDirectivesModule, MomentModule], declarations: getComponents(), @@ -79,7 +79,7 @@ export class SharedComponentsModule { ConfirmDialogControllerService, GlobalsendLinkPopupController, SmsNotificationsPromptController, - UpdateDialogController + UpdateDialogController, ], }; } diff --git a/packages/lightwallet/desktop/src/app/components/sms-notifications-prompt/sms-notifications-prompt.component.ts b/packages/lightwallet/desktop/src/app/components/sms-notifications-prompt/sms-notifications-prompt.component.ts index 19ffd69860..e58ac22d78 100644 --- a/packages/lightwallet/desktop/src/app/components/sms-notifications-prompt/sms-notifications-prompt.component.ts +++ b/packages/lightwallet/desktop/src/app/components/sms-notifications-prompt/sms-notifications-prompt.component.ts @@ -9,20 +9,22 @@ import { Ng4LoadingSpinnerService } from 'ng4-loading-spinner'; @Component({ selector: 'sms-notifications-prompt', templateUrl: './sms-notifications-prompt.component.html', - styleUrls: ['./sms-notifications-prompt.component.sass'] + styleUrls: ['./sms-notifications-prompt.component.sass'], }) export class SmsNotificationsPromptComponent implements IDynamicComponent { formData: FormGroup = this.formBuilder.group({ - phoneNumber: ['', [Validators.required, Validators.pattern(/\d{10,}/)]] + phoneNumber: ['', [Validators.required, Validators.pattern(/\d{10,}/)]], }); destroy: Function; - constructor(private smsNotificationsService: SmsNotificationsService, - private toastCtrl: ToastControllerService, - private formBuilder: FormBuilder, - private loadingCtrl: Ng4LoadingSpinnerService, - private persistenceService: PersistenceService2) {} + constructor( + private smsNotificationsService: SmsNotificationsService, + private toastCtrl: ToastControllerService, + private formBuilder: FormBuilder, + private loadingCtrl: Ng4LoadingSpinnerService, + private persistenceService: PersistenceService2, + ) {} init() {} diff --git a/packages/lightwallet/desktop/src/app/components/toast-notification/toast-controller.service.ts b/packages/lightwallet/desktop/src/app/components/toast-notification/toast-controller.service.ts index 362bf998fb..a494a15dcb 100644 --- a/packages/lightwallet/desktop/src/app/components/toast-notification/toast-controller.service.ts +++ b/packages/lightwallet/desktop/src/app/components/toast-notification/toast-controller.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { IMeritToastConfig, - ToastControllerService as ToastControllerServiceBase + ToastControllerService as ToastControllerServiceBase, } from '@merit/common/services/toast-controller.service'; import { DOMController } from '../dom.controller'; import { ToastNotificationComponent } from './toast-notification.component'; @@ -20,7 +20,7 @@ export class ToastControllerService extends ToastControllerServiceBase { return this.create({ cssClass: 'error', title: 'Error', - message + message, }); } @@ -28,7 +28,7 @@ export class ToastControllerService extends ToastControllerServiceBase { return this.create({ cssClass: 'success', title: 'Success', - message + message, }); } } diff --git a/packages/lightwallet/desktop/src/app/components/toast-notification/toast-notification.component.ts b/packages/lightwallet/desktop/src/app/components/toast-notification/toast-notification.component.ts index f1d0e936fe..abb32760f0 100644 --- a/packages/lightwallet/desktop/src/app/components/toast-notification/toast-notification.component.ts +++ b/packages/lightwallet/desktop/src/app/components/toast-notification/toast-notification.component.ts @@ -8,8 +8,8 @@ import { IDynamicComponent } from '@merit/desktop/app/components/dom.controller' styleUrls: ['./toast-notification.component.sass'], host: { '[class]': 'config.cssClass', - '[hidden]': '!show' - } + '[hidden]': '!show', + }, }) export class ToastNotificationComponent implements IDynamicComponent, OnDestroy { config: IMeritToastConfig; diff --git a/packages/lightwallet/desktop/src/app/components/toast-notification/toast-notification.spec.ts b/packages/lightwallet/desktop/src/app/components/toast-notification/toast-notification.spec.ts index 6ac815bd62..5b45ee9d3a 100644 --- a/packages/lightwallet/desktop/src/app/components/toast-notification/toast-notification.spec.ts +++ b/packages/lightwallet/desktop/src/app/components/toast-notification/toast-notification.spec.ts @@ -3,20 +3,18 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ToastNotificationComponent } from './toast-notification.component'; describe('Toast notification', () => { - let instance: ComponentFixture, - de: DebugElement, - comp: ToastNotificationComponent; + let instance: ComponentFixture, de: DebugElement, comp: ToastNotificationComponent; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ToastNotificationComponent] + declarations: [ToastNotificationComponent], }).compileComponents(); instance = TestBed.createComponent(ToastNotificationComponent); comp = instance.componentInstance; comp.init({ title: 'Test title', - message: 'Test message' + message: 'Test message', }); instance.detectChanges(); de = instance.debugElement; diff --git a/packages/lightwallet/desktop/src/app/components/ui-checkbox/ui-checkbox.component.ts b/packages/lightwallet/desktop/src/app/components/ui-checkbox/ui-checkbox.component.ts index d6ff1bc72c..4a60ada1df 100644 --- a/packages/lightwallet/desktop/src/app/components/ui-checkbox/ui-checkbox.component.ts +++ b/packages/lightwallet/desktop/src/app/components/ui-checkbox/ui-checkbox.component.ts @@ -9,15 +9,15 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; styleUrls: ['./ui-checkbox.component.sass'], host: { '(click)': 'onClick()', - '[class.checked]': 'value' + '[class.checked]': 'value', }, providers: [ { provide: NG_VALUE_ACCESSOR, multi: true, - useExisting: forwardRef(() => UICheckboxComponent) - } - ] + useExisting: forwardRef(() => UICheckboxComponent), + }, + ], }) export class UICheckboxComponent implements ControlValueAccessor { value: boolean; @@ -25,7 +25,7 @@ export class UICheckboxComponent implements ControlValueAccessor { onTouched: Function = () => {}; writeValue(val: boolean) { - this.onChange(this.value = Boolean(val)); + this.onChange((this.value = Boolean(val))); } registerOnChange(fn: Function) { diff --git a/packages/lightwallet/desktop/src/app/components/update-dialog/update-dialog.component.ts b/packages/lightwallet/desktop/src/app/components/update-dialog/update-dialog.component.ts index 8839af1b03..f6ee73cc75 100644 --- a/packages/lightwallet/desktop/src/app/components/update-dialog/update-dialog.component.ts +++ b/packages/lightwallet/desktop/src/app/components/update-dialog/update-dialog.component.ts @@ -6,7 +6,7 @@ import { ElectronService, IUpdateInfo, IUpdateProgress } from '@merit/desktop/se @Component({ selector: 'update-dialog', templateUrl: './update-dialog.component.html', - styleUrls: ['./update-dialog.component.sass'] + styleUrls: ['./update-dialog.component.sass'], }) export class UpdateDialogComponent implements IDynamicComponent { destroy: Function; @@ -15,8 +15,7 @@ export class UpdateDialogComponent implements IDynamicComponent { updateInfo: IUpdateInfo; - constructor(private persistenceService: PersistenceService2, - private ngZone: NgZone) {} + constructor(private persistenceService: PersistenceService2, private ngZone: NgZone) {} init(updateInfo: IUpdateInfo) { this.updateInfo = updateInfo; @@ -24,23 +23,22 @@ export class UpdateDialogComponent implements IDynamicComponent { downloadUpdate() { this.step = 'downloading'; - ElectronService.downloadUpdate() - .subscribe({ - next: (val: IUpdateProgress) => { - this.ngZone.run(() => { - val.timeRemaining = Math.ceil((val.total - val.transferred) / val.bytesPerSecond); - val.transferred = Math.round(val.transferred / 1024 / 1024 * 100) / 100; - val.total = Math.round(val.total / 1024 / 1024 * 100) / 100; - val.percent = Math.round(val.percent); - this.downloadProgress = val; - }); - }, - complete: () => { - this.ngZone.run(() => { - this.step = 'downloaded' - }); - } - }); + ElectronService.downloadUpdate().subscribe({ + next: (val: IUpdateProgress) => { + this.ngZone.run(() => { + val.timeRemaining = Math.ceil((val.total - val.transferred) / val.bytesPerSecond); + val.transferred = Math.round((val.transferred / 1024 / 1024) * 100) / 100; + val.total = Math.round((val.total / 1024 / 1024) * 100) / 100; + val.percent = Math.round(val.percent); + this.downloadProgress = val; + }); + }, + complete: () => { + this.ngZone.run(() => { + this.step = 'downloaded'; + }); + }, + }); } installUpdate() { diff --git a/packages/lightwallet/desktop/src/app/components/wallet-icon/wallet-icon.component.ts b/packages/lightwallet/desktop/src/app/components/wallet-icon/wallet-icon.component.ts index 9878de5645..0dd60a60f0 100644 --- a/packages/lightwallet/desktop/src/app/components/wallet-icon/wallet-icon.component.ts +++ b/packages/lightwallet/desktop/src/app/components/wallet-icon/wallet-icon.component.ts @@ -3,9 +3,9 @@ import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'wallet-icon', templateUrl: './wallet-icon.component.html', - styleUrls: ['./wallet-icon.component.scss'] + styleUrls: ['./wallet-icon.component.scss'], }) - export class WalletIconComponent { - @Input() strokeColor: string; + @Input() + strokeColor: string; } diff --git a/packages/lightwallet/desktop/src/app/components/wallet-unlock-alert/wallet-unlock-alert.component.ts b/packages/lightwallet/desktop/src/app/components/wallet-unlock-alert/wallet-unlock-alert.component.ts index 7eb7566acc..db67bbc4ec 100644 --- a/packages/lightwallet/desktop/src/app/components/wallet-unlock-alert/wallet-unlock-alert.component.ts +++ b/packages/lightwallet/desktop/src/app/components/wallet-unlock-alert/wallet-unlock-alert.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { DisplayWallet } from "@merit/common/models/display-wallet"; +import { DisplayWallet } from '@merit/common/models/display-wallet'; @Component({ selector: 'app-wallet-unlock-alert', @@ -7,5 +7,6 @@ import { DisplayWallet } from "@merit/common/models/display-wallet"; styleUrls: ['./wallet-unlock-alert.component.sass'], }) export class WalletUnlockAlertComponent { - @Input() wallets: DisplayWallet[]; + @Input() + wallets: DisplayWallet[]; } diff --git a/packages/lightwallet/desktop/src/app/core/backup/backup.view.ts b/packages/lightwallet/desktop/src/app/core/backup/backup.view.ts index 00ee6ee7c5..58a619afe4 100644 --- a/packages/lightwallet/desktop/src/app/core/backup/backup.view.ts +++ b/packages/lightwallet/desktop/src/app/core/backup/backup.view.ts @@ -3,6 +3,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'app-backup', templateUrl: './backup.view.html', - styleUrls: ['./backup.view.sass'] + styleUrls: ['./backup.view.sass'], }) export class BackupView {} diff --git a/packages/lightwallet/desktop/src/app/core/backup/file-backup/file-backup.view.ts b/packages/lightwallet/desktop/src/app/core/backup/file-backup/file-backup.view.ts index 3225d47f11..4a877ade8a 100644 --- a/packages/lightwallet/desktop/src/app/core/backup/file-backup/file-backup.view.ts +++ b/packages/lightwallet/desktop/src/app/core/backup/file-backup/file-backup.view.ts @@ -11,18 +11,17 @@ import { PasswordValidator } from '@merit/common/validators/password.validator'; import { MWCService } from '@merit/common/services/mwc.service'; import { AppSettingsService } from '@merit/common/services/app-settings.service'; import * as FileSaver from 'file-saver'; -import 'rxjs/add/operator/toPromise' -import 'rxjs/add/operator/take' +import 'rxjs/add/operator/toPromise'; +import 'rxjs/add/operator/take'; @Component({ selector: 'view-file-backup', - templateUrl: './file-backup.view.html' + templateUrl: './file-backup.view.html', }) export class FileBackupView { - formData = this.formBuilder.group({ password: ['', [Validators.required, Validators.minLength(1)]], - repeatPassword: ['', [Validators.required, PasswordValidator.MatchPassword]] + repeatPassword: ['', [Validators.required, PasswordValidator.MatchPassword]], }); get password() { @@ -34,15 +33,16 @@ export class FileBackupView { } wallet$: Observable = this.route.parent.params.pipe( - switchMap((params: any) => this.store.select(selectWalletById(params.id))) + switchMap((params: any) => this.store.select(selectWalletById(params.id))), ); - constructor(private route: ActivatedRoute, - private store: Store, - private formBuilder: FormBuilder, - private mwcService: MWCService, - private appSettingsService: AppSettingsService) { - } + constructor( + private route: ActivatedRoute, + private store: Store, + private formBuilder: FormBuilder, + private mwcService: MWCService, + private appSettingsService: AppSettingsService, + ) {} async downloadFileBackup() { const wallet = await this.wallet$.take(1).toPromise(); @@ -50,7 +50,7 @@ export class FileBackupView { const encryptedData = this.mwcService.getSJCL().encrypt(this.password.value, exportData, { iter: 10000 }); const walletName = wallet.name; const info = await this.appSettingsService.getInfo(); - const fileName = `${ walletName }-${ info.nameCase || '' }.backup.aes.json`; + const fileName = `${walletName}-${info.nameCase || ''}.backup.aes.json`; const blob = new Blob([encryptedData], { type: 'text/plain;charset=utf-8' }); FileSaver.saveAs(blob, fileName); diff --git a/packages/lightwallet/desktop/src/app/core/backup/mnemonic-phrase/mnemonic-phrase.view.ts b/packages/lightwallet/desktop/src/app/core/backup/mnemonic-phrase/mnemonic-phrase.view.ts index 090862d304..902112c38f 100644 --- a/packages/lightwallet/desktop/src/app/core/backup/mnemonic-phrase/mnemonic-phrase.view.ts +++ b/packages/lightwallet/desktop/src/app/core/backup/mnemonic-phrase/mnemonic-phrase.view.ts @@ -10,15 +10,13 @@ import { Store } from '@ngrx/store'; @Component({ selector: 'app-mnemonic-phrase', templateUrl: './mnemonic-phrase.view.html', - styleUrls: ['./mnemonic-phrase.view.sass'] + styleUrls: ['./mnemonic-phrase.view.sass'], }) export class MnemonicPhraseView { mnemonic$: Observable = this.route.parent.params.pipe( switchMap((params: any) => this.store.select(selectWalletById(params.id))), - map((wallet: DisplayWallet) => wallet.client.getMnemonic()) + map((wallet: DisplayWallet) => wallet.client.getMnemonic()), ); - constructor(private route: ActivatedRoute, - private store: Store) { - } + constructor(private route: ActivatedRoute, private store: Store) {} } diff --git a/packages/lightwallet/desktop/src/app/core/backup/qr-code-backup/qr-code-backup.view.ts b/packages/lightwallet/desktop/src/app/core/backup/qr-code-backup/qr-code-backup.view.ts index 7d561f6c6c..b23972b328 100644 --- a/packages/lightwallet/desktop/src/app/core/backup/qr-code-backup/qr-code-backup.view.ts +++ b/packages/lightwallet/desktop/src/app/core/backup/qr-code-backup/qr-code-backup.view.ts @@ -12,16 +12,17 @@ import { Store } from '@ngrx/store'; @Component({ selector: 'view-qr-code-backup', templateUrl: './qr-code-backup.view.html', - styleUrls: ['./qr-code-backup.view.sass'] + styleUrls: ['./qr-code-backup.view.sass'], }) export class QrCodeBackupView { mnemonic$: Observable = this.route.parent.params.pipe( switchMap((params: any) => this.store.select(selectWalletById(params.id)).pipe(take(1))), - switchMap((wallet: DisplayWallet) => fromPromise(this.walletService.getEncodedWalletInfo(wallet.client, null))) + switchMap((wallet: DisplayWallet) => fromPromise(this.walletService.getEncodedWalletInfo(wallet.client, null))), ); - constructor(private route: ActivatedRoute, - private store: Store, - private walletService: WalletService) { - } + constructor( + private route: ActivatedRoute, + private store: Store, + private walletService: WalletService, + ) {} } diff --git a/packages/lightwallet/desktop/src/app/core/community/community.view.ts b/packages/lightwallet/desktop/src/app/core/community/community.view.ts index 62ebda1652..d108dbe873 100644 --- a/packages/lightwallet/desktop/src/app/core/community/community.view.ts +++ b/packages/lightwallet/desktop/src/app/core/community/community.view.ts @@ -4,22 +4,22 @@ import { Observable } from 'rxjs/Observable'; import { Store } from '@ngrx/store'; import { selectInviteRequests, - selectInvites, selectWallets, selectWalletsLoading, - selectWalletTotals + selectInvites, + selectWallets, + selectWalletsLoading, + selectWalletTotals, } from '@merit/common/reducers/wallets.reducer'; import { IRootAppState } from '@merit/common/reducers'; @Component({ selector: 'view-network', templateUrl: './community.view.html', - styleUrls: ['./community.view.sass'] + styleUrls: ['./community.view.sass'], }) export class CommunityView { wallets$: Observable = this.store.select(selectWallets); walletsLoading$: Observable = this.store.select(selectWalletsLoading); totals$: Observable = this.store.select(selectWalletTotals); - constructor(private store: Store) { - } - + constructor(private store: Store) {} } diff --git a/packages/lightwallet/desktop/src/app/core/components/fee-selector/fee-selector.component.ts b/packages/lightwallet/desktop/src/app/core/components/fee-selector/fee-selector.component.ts index f52585df8f..17abcafa0a 100644 --- a/packages/lightwallet/desktop/src/app/core/components/fee-selector/fee-selector.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/fee-selector/fee-selector.component.ts @@ -9,9 +9,9 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; { provide: NG_VALUE_ACCESSOR, multi: true, - useExisting: forwardRef(() => FeeSelectorComponent) - } - ] + useExisting: forwardRef(() => FeeSelectorComponent), + }, + ], }) export class FeeSelectorComponent implements ControlValueAccessor { value: boolean; @@ -19,7 +19,7 @@ export class FeeSelectorComponent implements ControlValueAccessor { onTouched: Function = () => {}; writeValue(val: boolean) { - this.onChange(this.value = Boolean(val)); + this.onChange((this.value = Boolean(val))); } registerOnChange(fn: Function) { diff --git a/packages/lightwallet/desktop/src/app/core/components/history-item/history-item.component.ts b/packages/lightwallet/desktop/src/app/core/components/history-item/history-item.component.ts index 6e9fa3048f..53442ddc52 100644 --- a/packages/lightwallet/desktop/src/app/core/components/history-item/history-item.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/history-item/history-item.component.ts @@ -8,10 +8,11 @@ import { GlobalsendLinkPopupController } from '@merit/desktop/app/components/glo selector: 'history-item', templateUrl: './history-item.component.html', styleUrls: ['./history-item.component.sass'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, }) export class HistoryItemComponent implements OnInit { - @Input() tx: IDisplayTransaction; + @Input() + tx: IDisplayTransaction; confirmationsExplanation: string; isUnlockRequest: boolean; @@ -30,10 +31,7 @@ export class HistoryItemComponent implements OnInit { } } - constructor( - private globalSendLinkCtrl: GlobalsendLinkPopupController, - private easyReceive: EasyReceiveService - ) {} + constructor(private globalSendLinkCtrl: GlobalsendLinkPopupController, private easyReceive: EasyReceiveService) {} ngOnInit() { const { tx } = this; @@ -45,7 +43,8 @@ export class HistoryItemComponent implements OnInit { this.isMiningReward = this.isReward && tx.outputs[0].index === 0; this.isEasySend = !this.isInvite && !this.isReward; if (tx.isCoinbase && !tx.isMature) { - this.confirmationsExplanation = String(this.tx.confirmations) + ' block(s) confirmed from ' + COINBASE_CONFIRMATION_THRESHOLD; + this.confirmationsExplanation = + String(this.tx.confirmations) + ' block(s) confirmed from ' + COINBASE_CONFIRMATION_THRESHOLD; } if (tx.isGrowthReward) this.image = 'growth'; diff --git a/packages/lightwallet/desktop/src/app/core/components/history-item/history-item.spec.ts b/packages/lightwallet/desktop/src/app/core/components/history-item/history-item.spec.ts index 41b9cbc92b..14bb3ed5b5 100644 --- a/packages/lightwallet/desktop/src/app/core/components/history-item/history-item.spec.ts +++ b/packages/lightwallet/desktop/src/app/core/components/history-item/history-item.spec.ts @@ -9,15 +9,14 @@ import { ClipModule } from 'ng2-clip'; import { MomentModule } from 'ngx-moment'; import { HistoryItemComponent } from './history-item.component'; - const BASE_TRANSACTION: Partial = { isConfirmed: true, isInvite: false, isCoinbase: false, wallet: { - name: 'Personal wallet' + name: 'Personal wallet', }, - time: Date.now() / 1000 + time: Date.now() / 1000, }; @Injectable() @@ -35,25 +34,17 @@ class MockMeritMoneyLinkPopupController { class MockEasyReceiveService {} describe('History item component', () => { - - let instance: ComponentFixture, - de: DebugElement, - comp: HistoryItemComponent; + let instance: ComponentFixture, de: DebugElement, comp: HistoryItemComponent; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - HistoryItemComponent - ], + declarations: [HistoryItemComponent], providers: [ { provide: GlobalsendLinkPopupController, useClass: MockMeritMoneyLinkPopupController }, { provide: ToastControllerService, useClass: MockToastController }, { provide: EasyReceiveService, useClass: MockEasyReceiveService }, ], - imports: [ - ClipModule, - MomentModule - ] + imports: [ClipModule, MomentModule], }).compileComponents(); instance = TestBed.createComponent(HistoryItemComponent); @@ -73,7 +64,7 @@ describe('History item component', () => { action: TransactionAction.RECEIVED, name, amountStr, - alternativeAmountStr + alternativeAmountStr, }; instance.detectChanges(); }); @@ -91,7 +82,5 @@ describe('History item component', () => { expect(innerHTML).toContain('Received to'); expect(innerHTML).toContain('Personal wallet'); }); - }); - }); diff --git a/packages/lightwallet/desktop/src/app/core/components/history-list/history-list.component.ts b/packages/lightwallet/desktop/src/app/core/components/history-list/history-list.component.ts index 19af2a8613..d93da4be77 100644 --- a/packages/lightwallet/desktop/src/app/core/components/history-list/history-list.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/history-list/history-list.component.ts @@ -14,7 +14,7 @@ import { DisplayWallet } from '@merit/common/models/display-wallet'; selector: 'history-list', templateUrl: './history-list.component.html', styleUrls: ['./history-list.component.sass'], - encapsulation: ViewEncapsulation.None + encapsulation: ViewEncapsulation.None, }) export class HistoryListComponent { private _transactions: IDisplayTransaction[]; @@ -29,20 +29,20 @@ export class HistoryListComponent { return this._transactions; } - @Input() loading: boolean; - @Input() widget: boolean; + @Input() + loading: boolean; + @Input() + widget: boolean; viewPortItems: IDisplayTransaction[]; mineInviteTaskSlug: TaskSlug = TaskSlug.MineInvite; unlockTaskSlug: TaskSlug = TaskSlug.UnlockWallet; - isInviteMined$: Observable = this.store.select(selectStatusForTask(this.mineInviteTaskSlug)) - .pipe( - map((status: ProgressStatus) => status !== ProgressStatus.Incomplete) - ); - isWalletUnlocked$: Observable = this.store.select(selectPrimaryWallet) - .pipe( - map((wallet: DisplayWallet) => wallet && wallet.confirmed) - ); + isInviteMined$: Observable = this.store + .select(selectStatusForTask(this.mineInviteTaskSlug)) + .pipe(map((status: ProgressStatus) => status !== ProgressStatus.Incomplete)); + isWalletUnlocked$: Observable = this.store + .select(selectPrimaryWallet) + .pipe(map((wallet: DisplayWallet) => wallet && wallet.confirmed)); constructor(private store: Store) {} @@ -53,11 +53,12 @@ export class HistoryListComponent { const primaryWallet = await getLatestDefinedValue(this.store.select(selectPrimaryWallet)); - if (this.transactions.some((tx: IDisplayTransaction) => - tx.action === TransactionAction.INVITE && - !tx.isWalletUnlock && - tx.walletId === primaryWallet.id - )) { + if ( + this.transactions.some( + (tx: IDisplayTransaction) => + tx.action === TransactionAction.INVITE && !tx.isWalletUnlock && tx.walletId === primaryWallet.id, + ) + ) { this.store.dispatch(new SetTaskStatus(this.mineInviteTaskSlug, ProgressStatus.Complete)); } } diff --git a/packages/lightwallet/desktop/src/app/core/components/notifications-history/notifications-history.component.ts b/packages/lightwallet/desktop/src/app/core/components/notifications-history/notifications-history.component.ts index 23d4719ccf..eeb67ae714 100644 --- a/packages/lightwallet/desktop/src/app/core/components/notifications-history/notifications-history.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/notifications-history/notifications-history.component.ts @@ -6,14 +6,17 @@ import { INotification } from '@merit/common/reducers/notifications.reducer'; templateUrl: './notifications-history.component.html', styleUrls: ['./notifications-history.component.sass'], host: { - '[class.show]': 'showHistory' + '[class.show]': 'showHistory', }, - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, }) export class NotificationsHistoryComponent { - @Input() notifications: INotification[]; - @Input() showHistory: boolean; - @Output() onClear: EventEmitter = new EventEmitter(); + @Input() + notifications: INotification[]; + @Input() + showHistory: boolean; + @Output() + onClear: EventEmitter = new EventEmitter(); clearAll() { this.onClear.emit(); diff --git a/packages/lightwallet/desktop/src/app/core/components/notifications/notifications.component.ts b/packages/lightwallet/desktop/src/app/core/components/notifications/notifications.component.ts index fac248eee2..5a73f9bb6a 100644 --- a/packages/lightwallet/desktop/src/app/core/components/notifications/notifications.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/notifications/notifications.component.ts @@ -3,19 +3,21 @@ import { IRootAppState } from '@merit/common/reducers'; import { ClearNotificationsAction, INotification, - MarkAllNotificationsAsReadAction + MarkAllNotificationsAsReadAction, } from '@merit/common/reducers/notifications.reducer'; import { Store } from '@ngrx/store'; @Component({ selector: 'app-notifications', templateUrl: './notifications.component.html', - styleUrls: ['./notifications.component.sass'] + styleUrls: ['./notifications.component.sass'], }) export class NotificationsComponent { showHistory: boolean; - @Input() notifications: INotification[]; - @Input() hasNewNotifications: boolean; + @Input() + notifications: INotification[]; + @Input() + hasNewNotifications: boolean; constructor(private store: Store) {} diff --git a/packages/lightwallet/desktop/src/app/core/components/profile-stats/community-rank/community-rank.component.ts b/packages/lightwallet/desktop/src/app/core/components/profile-stats/community-rank/community-rank.component.ts index 2691e1bd94..629e0965b8 100644 --- a/packages/lightwallet/desktop/src/app/core/components/profile-stats/community-rank/community-rank.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/profile-stats/community-rank/community-rank.component.ts @@ -20,13 +20,19 @@ export class CommunityRankComponent { private _wallets: any[]; private _ranks: any; - @Output() close: EventEmitter = new EventEmitter(); + @Output() + close: EventEmitter = new EventEmitter(); - @Input() onMoreSecurityRewards: Function; - @Input() onMoreCommunity: Function; - @Input() active: boolean; - @Input() leaderboard: any[]; - @Input() rankData: any; + @Input() + onMoreSecurityRewards: Function; + @Input() + onMoreCommunity: Function; + @Input() + active: boolean; + @Input() + leaderboard: any[]; + @Input() + rankData: any; @Input() set ranks(val: any[]) { this._ranks = val; @@ -55,7 +61,7 @@ export class CommunityRankComponent { private assignRanks() { if (!this._ranks || !this._wallets) return; - this._wallets.map((w) => { + this._wallets.map(w => { w.rank = this.ranks.find(r => r.address == w.referrerAddress); }); } diff --git a/packages/lightwallet/desktop/src/app/core/components/profile-stats/get-started-tips/get-started-tips.component.ts b/packages/lightwallet/desktop/src/app/core/components/profile-stats/get-started-tips/get-started-tips.component.ts index 9782493d8f..c0e2ac6f6b 100644 --- a/packages/lightwallet/desktop/src/app/core/components/profile-stats/get-started-tips/get-started-tips.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/profile-stats/get-started-tips/get-started-tips.component.ts @@ -21,13 +21,12 @@ declare global { trigger('showTips', [ state('true', style({ maxHeight: '1000px', padding: '60px 20px 30px' })), state('false', style({})), - transition('* => *', animate('100ms cubic-bezier(0.445, 0.05, 0.55, 0.95)')) - ]) - ] + transition('* => *', animate('100ms cubic-bezier(0.445, 0.05, 0.55, 0.95)')), + ]), + ], }) export class GetStartedTipsComponent implements OnInit { - constructor(private persistenceService: PersistenceService2, private store: Store) { - } + constructor(private persistenceService: PersistenceService2, private store: Store) {} active: boolean; getArticle: boolean; diff --git a/packages/lightwallet/desktop/src/app/core/components/profile-stats/profile-stats.component.ts b/packages/lightwallet/desktop/src/app/core/components/profile-stats/profile-stats.component.ts index a609b641d4..0467e6adc0 100644 --- a/packages/lightwallet/desktop/src/app/core/components/profile-stats/profile-stats.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/profile-stats/profile-stats.component.ts @@ -29,8 +29,10 @@ interface IRankInfo { export class ProfileStatsComponent { private _wallets: DisplayWallet[]; - @Input() totals: any; - @Input() loading: boolean; + @Input() + totals: any; + @Input() + loading: boolean; @Input() set wallets(val: DisplayWallet[]) { @@ -81,7 +83,9 @@ export class ProfileStatsComponent { } }); - const topRankWallet: DisplayWallet = this.wallets.find((wallet: DisplayWallet) => wallet.referrerAddress === topRank.address); + const topRankWallet: DisplayWallet = this.wallets.find( + (wallet: DisplayWallet) => wallet.referrerAddress === topRank.address, + ); this.rankData = { unlocked: true, @@ -95,12 +99,11 @@ export class ProfileStatsComponent { this.displayLeaderboard = this.leaderboard.slice(this.offset, this.LIMIT); } - // TODO: move this function to a utils file private getPercentileStr(rankData: IRankInfo) { const percentile = Number(rankData.percentile); - return (percentile > 20) + return percentile > 20 ? 'Top ' + Math.max(Math.round(100 - percentile), 1) + '%' : 'Bottom ' + Math.max(Math.round(percentile), 1) + '%'; } diff --git a/packages/lightwallet/desktop/src/app/core/components/select/select.component.ts b/packages/lightwallet/desktop/src/app/core/components/select/select.component.ts index f48e079740..e924503318 100644 --- a/packages/lightwallet/desktop/src/app/core/components/select/select.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/select/select.component.ts @@ -3,14 +3,17 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; @Component({ selector: 'app-select', templateUrl: './select.component.html', - styleUrls: ['./select.component.sass'] + styleUrls: ['./select.component.sass'], }) export class SelectComponent { - - @Output() selectionEvent = new EventEmitter(); - @Input() selected: any; - @Input() input: any; - @Input() cssClass: any; + @Output() + selectionEvent = new EventEmitter(); + @Input() + selected: any; + @Input() + input: any; + @Input() + cssClass: any; show: boolean = false; select(item) { diff --git a/packages/lightwallet/desktop/src/app/core/components/send-method/send-method.component.ts b/packages/lightwallet/desktop/src/app/core/components/send-method/send-method.component.ts index fcf00e56df..44725a9c6f 100644 --- a/packages/lightwallet/desktop/src/app/core/components/send-method/send-method.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/send-method/send-method.component.ts @@ -10,9 +10,9 @@ import { SendMethodType } from '@merit/common/models/send-method'; { provide: NG_VALUE_ACCESSOR, multi: true, - useExisting: forwardRef(() => SendMethodComponent) - } - ] + useExisting: forwardRef(() => SendMethodComponent), + }, + ], }) export class SendMethodComponent implements ControlValueAccessor { value: SendMethodType; @@ -23,7 +23,7 @@ export class SendMethodComponent implements ControlValueAccessor { invite: boolean; writeValue(val: SendMethodType) { - this.onChange(this.value = val); + this.onChange((this.value = val)); } registerOnChange(fn: Function) { diff --git a/packages/lightwallet/desktop/src/app/core/components/share-box/share-box.component.ts b/packages/lightwallet/desktop/src/app/core/components/share-box/share-box.component.ts index 0f5382b7a0..83631d8ebd 100644 --- a/packages/lightwallet/desktop/src/app/core/components/share-box/share-box.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/share-box/share-box.component.ts @@ -19,7 +19,11 @@ import { ElectronService } from '@merit/desktop/services/electron.service'; styleUrls: ['./share-box.component.sass'], }) export class ShareBoxComponent implements OnInit { - constructor(private store: Store, private toastCtrl: ToastControllerService, private socialSharing: SocialSharing) {} + constructor( + private store: Store, + private toastCtrl: ToastControllerService, + private socialSharing: SocialSharing, + ) {} wallets$: Observable = this.store.select(selectWallets); selectedWallet = { @@ -35,18 +39,22 @@ export class ShareBoxComponent implements OnInit { shareTitle: string = 'Merit - digital currency for humans.'; shareText: string = `Merit aims to be the worldโ€™s friendliest digital currency, making it dead simple to pay friends, buy goods, and manage your wealth.\n Get wallet now, your activation: `; - @Output() dismiss: EventEmitter = new EventEmitter(); + @Output() + dismiss: EventEmitter = new EventEmitter(); async ngOnInit() { const wallets: DisplayWallet[] = await this.wallets$ - .pipe(filter((wallets: DisplayWallet[]) => wallets.length > 0), take(1)) + .pipe( + filter((wallets: DisplayWallet[]) => wallets.length > 0), + take(1), + ) .toPromise(); if (wallets.length > 0) { this.selectedWallet = wallets[0]; this.selectWallet(wallets[0]); } - this.FB = await this.socialSharing.authorizeFBSDK(); + this.FB = await this.socialSharing.authorizeFBSDK(); } get isElectron(): boolean { @@ -69,31 +77,34 @@ export class ShareBoxComponent implements OnInit { } shareFacebook() { - this.FB.ui({ - method: 'share_open_graph', - action_type: 'og.shares', - action_properties: JSON.stringify({ - object : { - 'og:url': `${this.shareLink}`, - 'og:title': `${this.shareTitle}`, - 'og:site_name':'MeritLightWallet', - 'og:description': `${this.shareText} ${this.shareLink}`, - 'og:image': 'https://www.merit.me/uploads/2018/02/17/shareImage.png', - 'og:image:width':'250', - 'og:image:height':'257' - } - }) - }, function(response){ - console.debug(response); - }); + this.FB.ui( + { + method: 'share_open_graph', + action_type: 'og.shares', + action_properties: JSON.stringify({ + object: { + 'og:url': `${this.shareLink}`, + 'og:title': `${this.shareTitle}`, + 'og:site_name': 'MeritLightWallet', + 'og:description': `${this.shareText} ${this.shareLink}`, + 'og:image': 'https://www.merit.me/uploads/2018/02/17/shareImage.png', + 'og:image:width': '250', + 'og:image:height': '257', + }, + }), + }, + function(response) { + console.debug(response); + }, + ); } shareTweeter() { - this._newWindow(`https://twitter.com/intent/tweet?text=${this.shareText} ${this.shareLink}`); + this._newWindow(`https://twitter.com/intent/tweet?text=${this.shareText} ${this.shareLink}`); } mailTo() { - window.location.href = (`mailto:?subject=${this.shareTitle}&body=${this.shareText} ${this.shareLink}`); + window.location.href = `mailto:?subject=${this.shareTitle}&body=${this.shareText} ${this.shareLink}`; } private _newWindow(url) { diff --git a/packages/lightwallet/desktop/src/app/core/components/toolbar/toolbar.component.ts b/packages/lightwallet/desktop/src/app/core/components/toolbar/toolbar.component.ts index 28ec1907e8..546196ee99 100644 --- a/packages/lightwallet/desktop/src/app/core/components/toolbar/toolbar.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/toolbar/toolbar.component.ts @@ -3,13 +3,13 @@ import { IRootAppState } from '@merit/common/reducers'; import { INotification, selectNotifications, - selectTotalUnreadNotifications + selectTotalUnreadNotifications, } from '@merit/common/reducers/notifications.reducer'; import { RefreshWalletsAction, selectWalletsLoading, selectWalletTotals, - selectWalletTotalsLoading + selectWalletTotalsLoading, } from '@merit/common/reducers/wallets.reducer'; import { Store } from '@ngrx/store'; import { Observable } from 'rxjs/Observable'; @@ -18,7 +18,7 @@ import { SetShareDialogAction } from '@merit/common/reducers/interface-preferenc @Component({ selector: 'app-toolbar', templateUrl: './toolbar.component.html', - styleUrls: ['./toolbar.component.sass'] + styleUrls: ['./toolbar.component.sass'], }) export class ToolbarComponent { showMenu: boolean; @@ -26,7 +26,7 @@ export class ToolbarComponent { selectedCurrency: any = { name: 'USD', symbol: '$', - value: '1' + value: '1', }; totals$: Observable = this.store.select(selectWalletTotals); @@ -37,12 +37,12 @@ export class ToolbarComponent { walletsLoading$: Observable = this.store.select(selectWalletsLoading); - @Output() shareActivate: EventEmitter = new EventEmitter(); + @Output() + shareActivate: EventEmitter = new EventEmitter(); showAdvTb: boolean; - constructor(private store: Store) { - } + constructor(private store: Store) {} receiveSelection($event) { this.selectedCurrency = $event; diff --git a/packages/lightwallet/desktop/src/app/core/components/vaults-list/vaults-list.component.ts b/packages/lightwallet/desktop/src/app/core/components/vaults-list/vaults-list.component.ts index 4a56d604d2..5e43d2a8f6 100644 --- a/packages/lightwallet/desktop/src/app/core/components/vaults-list/vaults-list.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/vaults-list/vaults-list.component.ts @@ -4,9 +4,11 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; selector: 'vaults-list', templateUrl: './vaults-list.component.html', styleUrls: ['./vaults-list.component.sass'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, }) export class VaultsListComponent { - @Input() showButton: boolean = true; - @Input() vaults: any[]; + @Input() + showButton: boolean = true; + @Input() + vaults: any[]; } diff --git a/packages/lightwallet/desktop/src/app/core/components/wallets-list/wallets-list.component.ts b/packages/lightwallet/desktop/src/app/core/components/wallets-list/wallets-list.component.ts index 328ca9a097..2cd6f02b16 100644 --- a/packages/lightwallet/desktop/src/app/core/components/wallets-list/wallets-list.component.ts +++ b/packages/lightwallet/desktop/src/app/core/components/wallets-list/wallets-list.component.ts @@ -7,18 +7,21 @@ import { DisplayWallet } from '@merit/common/models/display-wallet'; styleUrls: ['./wallets-list.component.sass'], }) export class WalletsListComponent { - @Input() wallets: DisplayWallet[]; - @Input() loading: boolean; - @Input() limit: number; + @Input() + wallets: DisplayWallet[]; + @Input() + loading: boolean; + @Input() + limit: number; trackByFn(wallet: DisplayWallet) { return wallet.id; } - isShowMore() { - if(this.limit > 1 && this.limit < this.wallets.length) { + isShowMore() { + if (this.limit > 1 && this.limit < this.wallets.length) { return true; - }else { + } else { this.limit = this.wallets.length; return false; } diff --git a/packages/lightwallet/desktop/src/app/core/core.component.ts b/packages/lightwallet/desktop/src/app/core/core.component.ts index d8b132678d..006a146ea9 100644 --- a/packages/lightwallet/desktop/src/app/core/core.component.ts +++ b/packages/lightwallet/desktop/src/app/core/core.component.ts @@ -87,7 +87,7 @@ export class CoreView implements OnInit, AfterViewInit { { name: 'Market Beta', icon: '/assets/v1/icons/ui/aside-navigation/market.svg', - link: '/market/gate' + link: '/market/gate', }, { name: 'Help & Support', @@ -102,14 +102,12 @@ export class CoreView implements OnInit, AfterViewInit { recordPassphrase: boolean = true; lockedWallets$: Observable = this.wallets$.pipe( map((wallets: DisplayWallet[]) => wallets.filter((wallet: DisplayWallet) => !wallet.confirmed)), - map((wallets: DisplayWallet[]) => (wallets && wallets.length ? wallets : null)) + map((wallets: DisplayWallet[]) => (wallets && wallets.length ? wallets : null)), + ); + isWelcomeDialogEnabled$: Observable = this.store.select(selectGoalSettings).pipe( + filter((goalSettings: IGoalSettings) => !!goalSettings), + map((goalSettings: IGoalSettings) => goalSettings.isWelcomeDialogEnabled), ); - isWelcomeDialogEnabled$: Observable = this.store - .select(selectGoalSettings) - .pipe( - filter((goalSettings: IGoalSettings) => !!goalSettings), - map((goalSettings: IGoalSettings) => goalSettings.isWelcomeDialogEnabled) - ); showShare$: Observable = this.store.select(selectShareDialogState); constructor( @@ -125,7 +123,7 @@ export class CoreView implements OnInit, AfterViewInit { private domSanitizer: DomSanitizer, private smsNotificationsService: SmsNotificationsService, private smsNotificationsPromptCtrl: SmsNotificationsPromptController, - private goalsService: GoalsService + private goalsService: GoalsService, ) {} async ngOnInit() { @@ -145,7 +143,7 @@ export class CoreView implements OnInit, AfterViewInit { if (smsNotificationStatus.enabled) return; - if(this.recordPassphrase) { + if (this.recordPassphrase) { this.smsNotificationsPromptCtrl.create(); } } @@ -156,7 +154,7 @@ export class CoreView implements OnInit, AfterViewInit { getIconStyle(icon: string) { return this.domSanitizer.bypassSecurityTrustStyle( - `mask-image: url('${icon}'); -webkit-mask-image: url('${icon}');` + `mask-image: url('${icon}'); -webkit-mask-image: url('${icon}');`, ); } @@ -174,7 +172,7 @@ export class CoreView implements OnInit, AfterViewInit { const passwordPrompt = this.passwordPromptCtrl.create( message, [Validators.required], - [PasswordValidator.ValidateEasyReceivePassword(receipt, this.easyReceiveService)] + [PasswordValidator.ValidateEasyReceivePassword(receipt, this.easyReceiveService)], ); passwordPrompt.onDidDismiss((password: any) => { if (password) { @@ -188,7 +186,7 @@ export class CoreView implements OnInit, AfterViewInit { receipt: EasyReceipt, data: any, wallet?: MeritWalletClient, - inviteOnly?: boolean + inviteOnly?: boolean, ) { const amount = await this.easyReceiveService.getReceiverAmount(data.txs); @@ -234,7 +232,7 @@ export class CoreView implements OnInit, AfterViewInit { data: any, wallet?: MeritWalletClient, cancelling?: boolean, - inviteOnly?: boolean + inviteOnly?: boolean, ) { const amount = await this.easyReceiveService.getReceiverAmount(data.txs); @@ -261,7 +259,7 @@ export class CoreView implements OnInit, AfterViewInit { text: "Don't Cancel", value: 'no', }, - ] + ], ); confirmDialog.onDidDismiss((val: string) => { @@ -290,7 +288,7 @@ export class CoreView implements OnInit, AfterViewInit { skipShareCode: true, skipRewards: true, skipAlias: true, - }) + }), ); } catch (err) { console.error(err); @@ -312,7 +310,7 @@ export class CoreView implements OnInit, AfterViewInit { skipShareCode: true, skipRewards: true, skipAlias: true, - }) + }), ); } catch (err) { console.error(err); @@ -330,7 +328,7 @@ export class CoreView implements OnInit, AfterViewInit { this.confirmDialogCtrl.create( 'Transaction expired', 'The Merit from this link has not been lost! You can ask the sender to make a new transaction.', - [{ text: 'Ok' }] + [{ text: 'Ok' }], ); } @@ -348,7 +346,7 @@ export class CoreView implements OnInit, AfterViewInit { password?: string, processAll: boolean = true, wallet?: MeritWalletClient, - cancelling?: boolean + cancelling?: boolean, ): Promise { password = password || ''; const data = await this.easyReceiveService.validateEasyReceiptOnBlockchain(receipt, password); diff --git a/packages/lightwallet/desktop/src/app/core/core.module.ts b/packages/lightwallet/desktop/src/app/core/core.module.ts index 692baf3709..c388fb1554 100644 --- a/packages/lightwallet/desktop/src/app/core/core.module.ts +++ b/packages/lightwallet/desktop/src/app/core/core.module.ts @@ -72,7 +72,7 @@ export function getPages() { SendInviteView, WalletSetupView, WalletSetupListView, - BackupNewWallet + BackupNewWallet, ]; } diff --git a/packages/lightwallet/desktop/src/app/core/dashboard/dashboard.view.ts b/packages/lightwallet/desktop/src/app/core/dashboard/dashboard.view.ts index fd6e4a0dd8..1f297ae31a 100644 --- a/packages/lightwallet/desktop/src/app/core/dashboard/dashboard.view.ts +++ b/packages/lightwallet/desktop/src/app/core/dashboard/dashboard.view.ts @@ -28,7 +28,7 @@ export class DashboardView { .pipe(map((transactions: IDisplayTransaction[]) => (isArray(transactions) ? transactions.slice(0, 5) : []))); transactionsLoading$: Observable = this.store.select(selectTransactionsLoading); - constructor(private store: Store, private sanitizer: DomSanitizer) { } + constructor(private store: Store, private sanitizer: DomSanitizer) {} getHistoryStyle(length: number) { return this.sanitizer.bypassSecurityTrustStyle('height: ' + length * 110 + 'px'); diff --git a/packages/lightwallet/desktop/src/app/core/dialog/backup-new-wallet/backup-new-wallet.component.ts b/packages/lightwallet/desktop/src/app/core/dialog/backup-new-wallet/backup-new-wallet.component.ts index 07b2190bf3..2cf8e993f1 100644 --- a/packages/lightwallet/desktop/src/app/core/dialog/backup-new-wallet/backup-new-wallet.component.ts +++ b/packages/lightwallet/desktop/src/app/core/dialog/backup-new-wallet/backup-new-wallet.component.ts @@ -3,12 +3,13 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; @Component({ selector: 'backup-new-wallet', templateUrl: './backup-new-wallet.component.html', - styleUrls: ['./backup-new-wallet.component.sass'] + styleUrls: ['./backup-new-wallet.component.sass'], }) - export class BackupNewWallet { - @Input() wallet; - @Output() dismiss: EventEmitter = new EventEmitter(); + @Input() + wallet; + @Output() + dismiss: EventEmitter = new EventEmitter(); copy: string = 'COPY'; showPhrase: boolean = false; @@ -20,6 +21,6 @@ export class BackupNewWallet { setTimeout(() => { this.copy = 'COPY'; }, 1000); - this.showNextBtn=true; + this.showNextBtn = true; } } diff --git a/packages/lightwallet/desktop/src/app/core/dialog/record-passphrase/record-passphrase.component.ts b/packages/lightwallet/desktop/src/app/core/dialog/record-passphrase/record-passphrase.component.ts index b074d62618..d23a0eae7f 100644 --- a/packages/lightwallet/desktop/src/app/core/dialog/record-passphrase/record-passphrase.component.ts +++ b/packages/lightwallet/desktop/src/app/core/dialog/record-passphrase/record-passphrase.component.ts @@ -9,8 +9,10 @@ import { DisplayWallet } from '@merit/common/models/display-wallet'; export class RecordPassphraseComponent { constructor() {} - @Input() wallets: DisplayWallet[]; - @Output() dismiss: EventEmitter = new EventEmitter(); + @Input() + wallets: DisplayWallet[]; + @Output() + dismiss: EventEmitter = new EventEmitter(); copy: string = 'COPY'; showPhrase: boolean = false; showNextBtn: boolean = false; @@ -20,6 +22,6 @@ export class RecordPassphraseComponent { setTimeout(() => { this.copy = 'COPY'; }, 1000); - this.showNextBtn=true; + this.showNextBtn = true; } } diff --git a/packages/lightwallet/desktop/src/app/core/dialog/task-confirm/task-confirm.component.ts b/packages/lightwallet/desktop/src/app/core/dialog/task-confirm/task-confirm.component.ts index 24d43d21d2..d16ca1646b 100644 --- a/packages/lightwallet/desktop/src/app/core/dialog/task-confirm/task-confirm.component.ts +++ b/packages/lightwallet/desktop/src/app/core/dialog/task-confirm/task-confirm.component.ts @@ -10,7 +10,7 @@ import { filter, map } from 'rxjs/operators'; @Component({ selector: 'task-confirm', templateUrl: './task-confirm.component.html', - styleUrls: ['./task-confirm.component.sass'] + styleUrls: ['./task-confirm.component.sass'], }) export class TaskConfirmComponent implements OnInit { @Input() @@ -34,22 +34,18 @@ export class TaskConfirmComponent implements OnInit { @Input() arrow: string; - trackerEnabled$: Observable = this.store.select(selectGoalSettings) - .pipe( - filter(settings => !!settings), - map(settings => settings.isSetupTrackerEnabled) - ); + trackerEnabled$: Observable = this.store.select(selectGoalSettings).pipe( + filter(settings => !!settings), + map(settings => settings.isSetupTrackerEnabled), + ); goal: IFullGoal; task: IFullTask; - constructor(private store: Store, - private goalsService: GoalsService) {} + constructor(private store: Store, private goalsService: GoalsService) {} ngOnInit() { - this.goal = this.goalsService.getGoal( - this.goalsService.getGoalForTask(this.taskSlug) - ); + this.goal = this.goalsService.getGoal(this.goalsService.getGoalForTask(this.taskSlug)); this.task = this.goalsService.getFullTask(this.taskSlug); } diff --git a/packages/lightwallet/desktop/src/app/core/dialog/welcome-to-setup-tracker/welcome-to-setup-tracker.component.ts b/packages/lightwallet/desktop/src/app/core/dialog/welcome-to-setup-tracker/welcome-to-setup-tracker.component.ts index d9e31ec492..9fe0c0a2ca 100644 --- a/packages/lightwallet/desktop/src/app/core/dialog/welcome-to-setup-tracker/welcome-to-setup-tracker.component.ts +++ b/packages/lightwallet/desktop/src/app/core/dialog/welcome-to-setup-tracker/welcome-to-setup-tracker.component.ts @@ -22,7 +22,7 @@ export class WelcomeToSetupTrackerComponent { private formBuilder: FormBuilder, private store: Store, private router: Router, - private goalsService: GoalsService + private goalsService: GoalsService, ) {} closeAndSave() { diff --git a/packages/lightwallet/desktop/src/app/core/global-settings/global-settings.view.ts b/packages/lightwallet/desktop/src/app/core/global-settings/global-settings.view.ts index 196f1f7bcb..7346dee165 100644 --- a/packages/lightwallet/desktop/src/app/core/global-settings/global-settings.view.ts +++ b/packages/lightwallet/desktop/src/app/core/global-settings/global-settings.view.ts @@ -3,8 +3,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'view-global-settings', templateUrl: './global-settings.view.html', - styleUrls: ['./global-settings.view.sass'] + styleUrls: ['./global-settings.view.sass'], }) -export class GlobalSettingsView { - -} +export class GlobalSettingsView {} diff --git a/packages/lightwallet/desktop/src/app/core/global-settings/settings-preferences/settings-preferences.view.ts b/packages/lightwallet/desktop/src/app/core/global-settings/settings-preferences/settings-preferences.view.ts index f37ea7457a..f43066eed3 100644 --- a/packages/lightwallet/desktop/src/app/core/global-settings/settings-preferences/settings-preferences.view.ts +++ b/packages/lightwallet/desktop/src/app/core/global-settings/settings-preferences/settings-preferences.view.ts @@ -24,10 +24,9 @@ declare const WEBPACK_CONFIG: any; @Component({ selector: 'view-settings-preferences', templateUrl: './settings-preferences.view.html', - styleUrls: ['./settings-preferences.view.sass'] + styleUrls: ['./settings-preferences.view.sass'], }) export class SettingsPreferencesView implements OnInit, OnDestroy { - get isElectron(): boolean { return ElectronService.isElectronAvailable; } @@ -42,20 +41,22 @@ export class SettingsPreferencesView implements OnInit, OnDestroy { this.smsNotificationsService, this.formBuilder, this.toastCtrl, - 'desktop' + 'desktop', ); - constructor(private formBuilder: FormBuilder, - private state: State, - private persistenceService: PersistenceService2, - private emailNotificationsService: EmailNotificationsService, - private pushNotificationsService: PushNotificationsService, - private toastCtrl: ToastControllerService, - private confirmDialogCtrl: ConfirmDialogControllerService, - private passwordPromptCtrl: PasswordPromptController, - private profileService: ProfileService, - private store: Store, - private smsNotificationsService: SmsNotificationsService) { + constructor( + private formBuilder: FormBuilder, + private state: State, + private persistenceService: PersistenceService2, + private emailNotificationsService: EmailNotificationsService, + private pushNotificationsService: PushNotificationsService, + private toastCtrl: ToastControllerService, + private confirmDialogCtrl: ConfirmDialogControllerService, + private passwordPromptCtrl: PasswordPromptController, + private profileService: ProfileService, + private store: Store, + private smsNotificationsService: SmsNotificationsService, + ) { if (typeof WEBPACK_CONFIG !== 'undefined') { this.commitHash = WEBPACK_CONFIG.COMMIT_HASH; this.version = WEBPACK_CONFIG.VERSION; @@ -80,12 +81,12 @@ export class SettingsPreferencesView implements OnInit, OnDestroy { { text: 'Delete', value: 'delete', - class: 'primary danger' + class: 'primary danger', }, { - text: 'Cancel' - } - ] + text: 'Cancel', + }, + ], ); dialog.onDidDismiss(async (value: string) => { @@ -111,7 +112,7 @@ export class SettingsPreferencesView implements OnInit, OnDestroy { await this.persistenceService.resetUserSettings(); this.store.dispatch(new SetPrimaryWalletAction(null)); this.store.dispatch(new DeleteWalletAction(wallet.id)); - }) + }), ); this.toastCtrl.success('All wallets are now deleted!'); diff --git a/packages/lightwallet/desktop/src/app/core/global-settings/settings-session-log/settings-session-log.view.ts b/packages/lightwallet/desktop/src/app/core/global-settings/settings-session-log/settings-session-log.view.ts index 0c232b669d..3a54bdfc40 100644 --- a/packages/lightwallet/desktop/src/app/core/global-settings/settings-session-log/settings-session-log.view.ts +++ b/packages/lightwallet/desktop/src/app/core/global-settings/settings-session-log/settings-session-log.view.ts @@ -4,7 +4,7 @@ import { LoggerService } from '@merit/common/services/logger.service'; @Component({ selector: 'view-settings-session-log', templateUrl: './settings-session-log.view.html', - styleUrls: ['./settings-session-log.view.sass'] + styleUrls: ['./settings-session-log.view.sass'], }) export class SettingsSessionLogView { logLevel: number = 4; @@ -29,8 +29,11 @@ export class SettingsSessionLogView { let logsString = ''; - this.filteredLogs.forEach(log => - logsString += `${(new Date(log.timestamp)).toString()}: ${this.getLogLevelName(log.level)} ${log.arguments.join('\n')}` + this.filteredLogs.forEach( + log => + (logsString += `${new Date(log.timestamp).toString()}: ${this.getLogLevelName(log.level)} ${log.arguments.join( + '\n', + )}`), ); this.logsString = logsString; diff --git a/packages/lightwallet/desktop/src/app/core/global-settings/settings-terms-of-use/settings-terms-of-use.view.ts b/packages/lightwallet/desktop/src/app/core/global-settings/settings-terms-of-use/settings-terms-of-use.view.ts index 50d11860a1..961a1d08c9 100644 --- a/packages/lightwallet/desktop/src/app/core/global-settings/settings-terms-of-use/settings-terms-of-use.view.ts +++ b/packages/lightwallet/desktop/src/app/core/global-settings/settings-terms-of-use/settings-terms-of-use.view.ts @@ -3,7 +3,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'view-settings-terms-of-use', templateUrl: './settings-terms-of-use.view.html', - styleUrls: ['./settings-terms-of-use.view.sass'] + styleUrls: ['./settings-terms-of-use.view.sass'], }) -export class SettingsTermsOfUseView { -} +export class SettingsTermsOfUseView {} diff --git a/packages/lightwallet/desktop/src/app/core/history/history.view.ts b/packages/lightwallet/desktop/src/app/core/history/history.view.ts index adc9b10ce1..678b47d335 100644 --- a/packages/lightwallet/desktop/src/app/core/history/history.view.ts +++ b/packages/lightwallet/desktop/src/app/core/history/history.view.ts @@ -2,23 +2,18 @@ import { Component, ViewEncapsulation } from '@angular/core'; import { IRootAppState } from '@merit/common/reducers'; import { Store } from '@ngrx/store'; import { Observable } from 'rxjs/Observable'; -import { - selectTransactions, - selectTransactionsLoading -} from '@merit/common/reducers/transactions.reducer'; +import { selectTransactions, selectTransactionsLoading } from '@merit/common/reducers/transactions.reducer'; import { IDisplayTransaction } from '@merit/common/models/transaction'; @Component({ selector: 'view-history', templateUrl: './history.view.html', styleUrls: ['./history.view.sass'], - encapsulation: ViewEncapsulation.None + encapsulation: ViewEncapsulation.None, }) export class HistoryView { loading$: Observable = this.store.select(selectTransactionsLoading); transactions$: Observable = this.store.select(selectTransactions); - constructor(private store: Store) { - - } + constructor(private store: Store) {} } diff --git a/packages/lightwallet/desktop/src/app/core/invites/invites-history/invites-history.view.ts b/packages/lightwallet/desktop/src/app/core/invites/invites-history/invites-history.view.ts index c7eca492ea..eaf326e5e3 100644 --- a/packages/lightwallet/desktop/src/app/core/invites/invites-history/invites-history.view.ts +++ b/packages/lightwallet/desktop/src/app/core/invites/invites-history/invites-history.view.ts @@ -1,10 +1,7 @@ import { Component } from '@angular/core'; import { IDisplayTransaction } from '@merit/common/models/transaction'; import { IRootAppState } from '@merit/common/reducers'; -import { - selectSentInvites, - selectTransactionsLoading -} from '@merit/common/reducers/transactions.reducer'; +import { selectSentInvites, selectTransactionsLoading } from '@merit/common/reducers/transactions.reducer'; import { Store } from '@ngrx/store'; import { Observable } from 'rxjs/Observable'; @@ -17,6 +14,5 @@ export class InvitesHistoryView { historyLoading$: Observable = this.store.select(selectTransactionsLoading); history$: Observable = this.store.select(selectSentInvites); - constructor(private store: Store) { - } + constructor(private store: Store) {} } diff --git a/packages/lightwallet/desktop/src/app/core/invites/pending-invite-item/pending-invite-item.component.ts b/packages/lightwallet/desktop/src/app/core/invites/pending-invite-item/pending-invite-item.component.ts index 5bd368b9a4..620017af03 100644 --- a/packages/lightwallet/desktop/src/app/core/invites/pending-invite-item/pending-invite-item.component.ts +++ b/packages/lightwallet/desktop/src/app/core/invites/pending-invite-item/pending-invite-item.component.ts @@ -22,15 +22,20 @@ export class PendingInviteItemComponent { private confirmDialogCtrl: ConfirmDialogControllerService, private logger: LoggerService, private toastCtrl: ToastControllerService, - private walletService: WalletService + private walletService: WalletService, ) {} - @Input() request; - @Input() availableInvites; - @Input() inviteRequests; - @Input() wallets; + @Input() + request; + @Input() + availableInvites; + @Input() + inviteRequests; + @Input() + wallets; - @Output() approveInviteRequest: EventEmitter = new EventEmitter(); + @Output() + approveInviteRequest: EventEmitter = new EventEmitter(); sending: { [referralId: string]: boolean } = {}; @@ -54,7 +59,7 @@ export class PendingInviteItemComponent { { text: 'No', }, - ] + ], ); dialog.onDidDismiss(async (value: string) => { @@ -105,7 +110,7 @@ export class PendingInviteItemComponent { { text: 'No', }, - ] + ], ); dialog.onDidDismiss(async (value: string) => { diff --git a/packages/lightwallet/desktop/src/app/core/invites/send-invite/send-invite.view.ts b/packages/lightwallet/desktop/src/app/core/invites/send-invite/send-invite.view.ts index 6ea9f78015..ff4aba2fb7 100644 --- a/packages/lightwallet/desktop/src/app/core/invites/send-invite/send-invite.view.ts +++ b/packages/lightwallet/desktop/src/app/core/invites/send-invite/send-invite.view.ts @@ -9,7 +9,7 @@ import { RefreshOneWalletTransactions } from '@merit/common/reducers/transaction import { RefreshOneWalletAction, selectInvites, - selectWalletsWithInvites + selectWalletsWithInvites, } from '@merit/common/reducers/wallets.reducer'; import { AddressService } from '@merit/common/services/address.service'; import { AlertService } from '@merit/common/services/alert.service'; @@ -32,7 +32,7 @@ import { filter, take, tap } from 'rxjs/operators'; @Component({ selector: 'view-send-invite', templateUrl: './send-invite.view.html', - styleUrls: ['./send-invite.view.sass'] + styleUrls: ['./send-invite.view.sass'], }) export class SendInviteView { availableInvites$: Observable = this.store.select(selectInvites); @@ -58,40 +58,63 @@ export class SendInviteView { easySendUrl: string; easySendDelivered: boolean; - get address() { return this.formData.get('address'); } - get type() { return this.formData.get('type'); } - get destination() { return this.formData.get('destination'); } - get amount() { return this.formData.get('amount'); } - get message() { return this.formData.get('message'); } - - constructor(private store: Store, - private formBuilder: FormBuilder, - private mwcService: MWCService, - private walletService: WalletService, - private toastCtrl: ToastControllerService, - private addressService: AddressService, - private loader: Ng4LoadingSpinnerService, - private easySendService: EasySendService, - private logger: LoggerService, - private alertCtrl: AlertService) {} + get address() { + return this.formData.get('address'); + } + get type() { + return this.formData.get('type'); + } + get destination() { + return this.formData.get('destination'); + } + get amount() { + return this.formData.get('amount'); + } + get message() { + return this.formData.get('message'); + } - async ngOnInit() { - const wallets: DisplayWallet[] = await this.wallets$.pipe(filter((wallets: DisplayWallet[]) => wallets.length > 0), take(1)).toPromise(); + constructor( + private store: Store, + private formBuilder: FormBuilder, + private mwcService: MWCService, + private walletService: WalletService, + private toastCtrl: ToastControllerService, + private addressService: AddressService, + private loader: Ng4LoadingSpinnerService, + private easySendService: EasySendService, + private logger: LoggerService, + private alertCtrl: AlertService, + ) {} - if (this.hasAWalletWithInvites = wallets.length > 0) { + async ngOnInit() { + const wallets: DisplayWallet[] = await this.wallets$ + .pipe( + filter((wallets: DisplayWallet[]) => wallets.length > 0), + take(1), + ) + .toPromise(); + + if ((this.hasAWalletWithInvites = wallets.length > 0)) { this.selectWallet(wallets[0]); - this.formData.get("wallet").setValue(this.selectedWallet); + this.formData.get('wallet').setValue(this.selectedWallet); const code = this.selectedWallet.alias || this.selectedWallet.referrerAddress; this.emailSubject = `Merit invite from ${code}`; - this.emailBody = `${ code } invites you to Merit Community. Create your wallet now - ${ getShareLink(code) }`; + this.emailBody = `${code} invites you to Merit Community. Create your wallet now - ${getShareLink(code)}`; } // this.formData.valueChanges.subscribe(val => (this.showEmailMessage = validateEmail(val.address))); - this.type.valueChanges.pipe( - filter((value: string) => (value === 'easy' && this.address.invalid) || (value === 'classic' && this.address.valid && !this.address.value)), - tap(() => this.address.updateValueAndValidity({ onlySelf: false })) - ).subscribe(); + this.type.valueChanges + .pipe( + filter( + (value: string) => + (value === 'easy' && this.address.invalid) || + (value === 'classic' && this.address.valid && !this.address.value), + ), + tap(() => this.address.updateValueAndValidity({ onlySelf: false })), + ) + .subscribe(); } @accessWallet @@ -114,7 +137,7 @@ export class SendInviteView { type: SendMethodType.Easy, destination: destinationType, message: message, - value: destination + value: destination, }); this.easySendDelivered = true; @@ -123,7 +146,6 @@ export class SendInviteView { this.easySendDelivered = false; } } - } else { address = cleanAddress(address); address = await this.addressService.getAddressInfo(address); @@ -133,12 +155,14 @@ export class SendInviteView { this.success = true; - this.store.dispatch(new RefreshOneWalletAction(this.selectedWallet.id, { - skipRewards: true, - skipAnv: true, - skipAlias: true, - skipShareCode: true - })); + this.store.dispatch( + new RefreshOneWalletAction(this.selectedWallet.id, { + skipRewards: true, + skipAnv: true, + skipAlias: true, + skipShareCode: true, + }), + ); this.store.dispatch(new RefreshOneWalletTransactions(this.selectedWallet.id)); this.address.reset(); diff --git a/packages/lightwallet/desktop/src/app/core/receive/receive.view.ts b/packages/lightwallet/desktop/src/app/core/receive/receive.view.ts index fac611363a..91a6ed2046 100644 --- a/packages/lightwallet/desktop/src/app/core/receive/receive.view.ts +++ b/packages/lightwallet/desktop/src/app/core/receive/receive.view.ts @@ -15,7 +15,7 @@ import { Observable } from 'rxjs/Observable'; selector: 'view-receive', templateUrl: './receive.view.html', styleUrls: ['./receive.view.sass'], - encapsulation: ViewEncapsulation.None + encapsulation: ViewEncapsulation.None, }) export class ReceiveView implements OnInit { wallets$: Observable = this.store.select(selectConfirmedWallets); @@ -35,25 +35,25 @@ export class ReceiveView implements OnInit { availableCurrencies: any = [ { - 'name': 'USD', - 'symbol': '$', - 'value': 10 + name: 'USD', + symbol: '$', + value: 10, }, { - 'name': 'RUB', - 'symbol': 'โ‚ฝ', - 'value': 0.1 + name: 'RUB', + symbol: 'โ‚ฝ', + value: 0.1, }, { - 'name': 'CAD', - 'symbol': 'C$', - 'value': 2 + name: 'CAD', + symbol: 'C$', + value: 2, }, { - 'name': 'EUR', - 'symbol': 'โ‚ฌ', - 'value': 3 - } + name: 'EUR', + symbol: 'โ‚ฌ', + value: 3, + }, ]; // For now, the first wallet in the list of wallets is the default. @@ -61,21 +61,23 @@ export class ReceiveView implements OnInit { selectedWallet: DisplayWallet; selectedCurrency: any = { - 'name': 'USD', - 'symbol': '$', - 'value': 10 + name: 'USD', + symbol: '$', + value: 10, }; - constructor(private configService: ConfigService, - private store: Store, - private walletService: WalletService, - private addressService: AddressService, - private rateService: RateService, - private toastCtrl: ToastControllerService) { + constructor( + private configService: ConfigService, + private store: Store, + private walletService: WalletService, + private addressService: AddressService, + private rateService: RateService, + private toastCtrl: ToastControllerService, + ) { try { this.availableUnits = [ this.configService.get().wallet.settings.unitCode.toUpperCase(), - this.configService.get().wallet.settings.alternativeIsoCode.toUpperCase() + this.configService.get().wallet.settings.alternativeIsoCode.toUpperCase(), ]; } catch (err) { console.error('Error reading the config service.'); @@ -89,8 +91,7 @@ export class ReceiveView implements OnInit { this.hasUnlockedWallet = wallets.length > 0; this.selectWallet(wallets[0]); } catch (err) { - if (err.text) - console.error('Could not initialize: ', err.text); + if (err.text) console.error('Could not initialize: ', err.text); } } @@ -123,6 +124,8 @@ export class ReceiveView implements OnInit { } private formatAddress() { - this.qrAddress = `${ this.protocolHandler }:${ this.address }${ this.amountMicros ? '?micros=' + this.amountMicros : '' }`; + this.qrAddress = `${this.protocolHandler}:${this.address}${ + this.amountMicros ? '?micros=' + this.amountMicros : '' + }`; } } diff --git a/packages/lightwallet/desktop/src/app/core/send/send-tour/send-tour.component.ts b/packages/lightwallet/desktop/src/app/core/send/send-tour/send-tour.component.ts index 87399d1941..01a4a1be49 100644 --- a/packages/lightwallet/desktop/src/app/core/send/send-tour/send-tour.component.ts +++ b/packages/lightwallet/desktop/src/app/core/send/send-tour/send-tour.component.ts @@ -3,11 +3,11 @@ import { Component, EventEmitter, Output } from '@angular/core'; @Component({ selector: 'send-tour', templateUrl: './send-tour.component.html', - styleUrls: ['./send-tour.component.sass'] + styleUrls: ['./send-tour.component.sass'], }) export class SendTourComponent { - - @Output() hideTour = new EventEmitter(); + @Output() + hideTour = new EventEmitter(); step: number = 0; stepGoTo(i?: number) { diff --git a/packages/lightwallet/desktop/src/app/core/send/send.view.ts b/packages/lightwallet/desktop/src/app/core/send/send.view.ts index 3956547a04..df213870f2 100644 --- a/packages/lightwallet/desktop/src/app/core/send/send.view.ts +++ b/packages/lightwallet/desktop/src/app/core/send/send.view.ts @@ -59,13 +59,12 @@ interface Receipt { styleUrls: ['./send.view.sass'], }) export class SendView implements OnInit, AfterViewInit { - wallets$: Observable = this.store.select(selectConfirmedWallets); hasUnlockedWallet: boolean; hasAvailableInvites: boolean; - availableCurrencies: Array<{ code: string; name: string; rate: number; }>; + availableCurrencies: Array<{ code: string; name: string; rate: number }>; easySendUrl: string; easySendDelivered: boolean; @@ -136,7 +135,7 @@ export class SendView implements OnInit, AfterViewInit { this.overMaximumAmount = false; }), filter(() => this.formData.dirty), - switchMap((formData) => { + switchMap(formData => { if (this.formData.pending) { // wait till form is validated return this.formData.statusChanges.pipe( @@ -147,17 +146,16 @@ export class SendView implements OnInit, AfterViewInit { } return of(formData); }), - switchMap((formData) => { + switchMap(formData => { if (this.formData.valid) { this.receiptLoading = true; - return fromPromise(this.createTx(formData)) - .pipe( - catchError((err: any) => { - console.error(err); - this.error = err.message || 'Unknown error'; - return of({} as ISendTxData); - }), - ); + return fromPromise(this.createTx(formData)).pipe( + catchError((err: any) => { + console.error(err); + this.error = err.message || 'Unknown error'; + return of({} as ISendTxData); + }), + ); } return of({} as ISendTxData); @@ -169,102 +167,94 @@ export class SendView implements OnInit, AfterViewInit { ); submit: Subject = new Subject(); - onSubmit$: Observable = this.submit.asObservable() - .pipe( - withLatestFrom(this.txData$), - tap(() => { - this.sending = true; - this.loadingCtrl.show(); - this.error = this.easySendUrl = this.easySendDelivered = null; - }), - switchMap(([_, txData]) => - fromPromise(this.send(txData)) - .pipe( - catchError(err => { - this.error = err.message; - return of(false); - }), - ), + onSubmit$: Observable = this.submit.asObservable().pipe( + withLatestFrom(this.txData$), + tap(() => { + this.sending = true; + this.loadingCtrl.show(); + this.error = this.easySendUrl = this.easySendDelivered = null; + }), + switchMap(([_, txData]) => + fromPromise(this.send(txData)).pipe( + catchError(err => { + this.error = err.message; + return of(false); + }), ), - tap((success: boolean) => { - this.sending = false; - this.loadingCtrl.hide(); - this.success = success; - - if (success) { - this.resetFormData(); - } - }), - startWith(false), - share(), - ); + ), + tap((success: boolean) => { + this.sending = false; + this.loadingCtrl.hide(); + this.success = success; + if (success) { + this.resetFormData(); + } + }), + startWith(false), + share(), + ); receiptLoading: boolean; - receipt$: Observable = combineLatest(this.txData$, this.onSubmit$) - .pipe( - map(([txData, submitSuccess]) => { - const { feeIncluded, wallet } = this.formData.value; - const { spendableAmount } = wallet ? wallet.balance : 0; - - if (!txData || this.success) { - return { - amount: 0, - fee: 0, - total: 0, - inWallet: spendableAmount, - remaining: spendableAmount, - }; - } - - this.receiptLoading = true; + receipt$: Observable = combineLatest(this.txData$, this.onSubmit$).pipe( + map(([txData, submitSuccess]) => { + const { feeIncluded, wallet } = this.formData.value; + const { spendableAmount } = wallet ? wallet.balance : 0; - const receipt: Receipt = { - amount: txData.amount, - fee: txData.fee, - total: feeIncluded ? txData.amount : txData.amount + txData.fee, + if (!txData || this.success) { + return { + amount: 0, + fee: 0, + total: 0, inWallet: spendableAmount, - remaining: 0, + remaining: spendableAmount, }; + } - receipt.remaining = receipt.inWallet - receipt.total; + this.receiptLoading = true; - return receipt; - }), - tap(() => this.receiptLoading = false), - startWith({} as Receipt), - ); + const receipt: Receipt = { + amount: txData.amount, + fee: txData.fee, + total: feeIncluded ? txData.amount : txData.amount + txData.fee, + inWallet: spendableAmount, + remaining: 0, + }; + + receipt.remaining = receipt.inWallet - receipt.total; + + return receipt; + }), + tap(() => (this.receiptLoading = false)), + startWith({} as Receipt), + ); amountFiat$: Observable = this.amountMrt.valueChanges.pipe( withLatestFrom(this.selectedCurrency.valueChanges), switchMap(([amountMrt, selectedCurrency]) => - fromPromise( - this.rateService.microsToFiat( - this.rateService.mrtToMicro(amountMrt), - selectedCurrency.code, - ), - ), + fromPromise(this.rateService.microsToFiat(this.rateService.mrtToMicro(amountMrt), selectedCurrency.code)), ), ); - constructor(private route: ActivatedRoute, - private store: Store, - private formBuilder: FormBuilder, - private logger: LoggerService, - private rateService: RateService, - private configService: ConfigService, - private walletService: WalletService, - private passwordPromptCtrl: PasswordPromptController, - private addressService: AddressService, - private easySendService: EasySendService, - private sendService: SendService, - private feeService: FeeService, - private persistenceService: PersistenceService2, - private mwcService: MWCService, - private toastCtrl: ToastControllerService, - private loadingCtrl: Ng4LoadingSpinnerService) { - } + constructor( + private route: ActivatedRoute, + private store: Store, + private formBuilder: FormBuilder, + private logger: LoggerService, + private rateService: RateService, + private configService: ConfigService, + private walletService: WalletService, + private passwordPromptCtrl: PasswordPromptController, + private addressService: AddressService, + private easySendService: EasySendService, + private sendService: SendService, + private feeService: FeeService, + private persistenceService: PersistenceService2, + private mwcService: MWCService, + private toastCtrl: ToastControllerService, + private loadingCtrl: Ng4LoadingSpinnerService, + ) {} async ngOnInit() { this.availableCurrencies = await this.rateService.getAvailableFiats(); @@ -280,21 +270,20 @@ export class SendView implements OnInit, AfterViewInit { this.amountMrt.markAsDirty(); } - this.type.valueChanges.pipe( - distinctUntilChanged() - ) - .subscribe((value: SendMethodType) => { - if ((value === SendMethodType.Easy && this.address.invalid) - || (value === SendMethodType.Classic && this.address.valid)) { - // Re-validate address field to make sure it's marked as valid when necessary - this.address.updateValueAndValidity({ onlySelf: false }); - } + this.type.valueChanges.pipe(distinctUntilChanged()).subscribe((value: SendMethodType) => { + if ( + (value === SendMethodType.Easy && this.address.invalid) || + (value === SendMethodType.Classic && this.address.valid) + ) { + // Re-validate address field to make sure it's marked as valid when necessary + this.address.updateValueAndValidity({ onlySelf: false }); + } - if (value === SendMethodType.Classic && this.destination.invalid) { - this.destination.setValue(''); - this.destination.markAsPristine(); - } - }); + if (value === SendMethodType.Classic && this.destination.invalid) { + this.destination.setValue(''); + this.destination.markAsPristine(); + } + }); this.onSubmit$.subscribe(); @@ -302,11 +291,10 @@ export class SendView implements OnInit, AfterViewInit { .pipe( filter(() => this.formData.pristine), switchMap(() => - this.formData.statusChanges - .pipe( - filter(() => !this.formData.pristine), - take(1) - ) + this.formData.statusChanges.pipe( + filter(() => !this.formData.pristine), + take(1), + ), ), ) .subscribe(() => { @@ -335,10 +323,12 @@ export class SendView implements OnInit, AfterViewInit { private async resetFormData() { this.formData.reset({ emitEvent: false }); - const wallets = await this.wallets$.pipe( - skipWhile(wallets => !wallets || !wallets.length), - take(1), - ).toPromise(); + const wallets = await this.wallets$ + .pipe( + skipWhile(wallets => !wallets || !wallets.length), + take(1), + ) + .toPromise(); this.hasUnlockedWallet = wallets.length > 0; this.hasAvailableInvites = wallets.some(w => w.availableInvites > 0); @@ -346,7 +336,7 @@ export class SendView implements OnInit, AfterViewInit { if (wallets && wallets[0]) { this.wallet.setValue(wallets[0], { emitEvent: false }); if (wallets[0].balance.spendableAmount <= 0) { - wallets.some((wallet) => { + wallets.some(wallet => { if (wallet.balance.spendableAmount > 0) { this.wallet.setValue(wallet, { emitEvent: false }); return true; @@ -366,8 +356,7 @@ export class SendView implements OnInit, AfterViewInit { selectWallet(wallet) { const { value } = this.wallet; - if (!value || value.id !== wallet.id) - this.wallet.setValue(wallet); + if (!value || value.id !== wallet.id) this.wallet.setValue(wallet); } private async createTx(formValue: any): Promise { @@ -433,11 +422,13 @@ export class SendView implements OnInit, AfterViewInit { } setTimeout(() => { - this.store.dispatch(new RefreshOneWalletAction(wallet.id, { - skipRewards: true, - skipAlias: true, - skipShareCode: true, - })); + this.store.dispatch( + new RefreshOneWalletAction(wallet.id, { + skipRewards: true, + skipAlias: true, + skipShareCode: true, + }), + ); }, 1750); return true; diff --git a/packages/lightwallet/desktop/src/app/core/wallet-setup/task-preview/task-preview.component.ts b/packages/lightwallet/desktop/src/app/core/wallet-setup/task-preview/task-preview.component.ts index d6c4bd2ec6..cb301fc76b 100644 --- a/packages/lightwallet/desktop/src/app/core/wallet-setup/task-preview/task-preview.component.ts +++ b/packages/lightwallet/desktop/src/app/core/wallet-setup/task-preview/task-preview.component.ts @@ -14,9 +14,12 @@ import { TaskSlug, ProgressStatus, IFullGoal, GoalSlug } from '@merit/common/mod export class TaskPreviewComponent implements OnInit { constructor(private router: Router, private store: Store, private goalService: GoalsService) {} - @Input() goal: IFullGoal; - @Input() isComplete: boolean; - @Input() isConfirmed: boolean; + @Input() + goal: IFullGoal; + @Input() + isComplete: boolean; + @Input() + isConfirmed: boolean; route: string; readinessBackground: string; @@ -29,7 +32,7 @@ export class TaskPreviewComponent implements OnInit { const toDo = this.goal.tasks.filter((item: any) => item.status === ProgressStatus.Incomplete), complete = this.goal.tasks.length - toDo.length, total = this.goal.tasks.length, - readiness = complete / total * 100; + readiness = (complete / total) * 100; this.readinessBackground = `linear-gradient(to right, #74cd4f ${readiness}%, #555b7033 ${readiness}%)`; } diff --git a/packages/lightwallet/desktop/src/app/core/wallet-setup/wallet-setup-list/wallet-setup-list.view.ts b/packages/lightwallet/desktop/src/app/core/wallet-setup/wallet-setup-list/wallet-setup-list.view.ts index d5475fe64e..4079a55101 100644 --- a/packages/lightwallet/desktop/src/app/core/wallet-setup/wallet-setup-list/wallet-setup-list.view.ts +++ b/packages/lightwallet/desktop/src/app/core/wallet-setup/wallet-setup-list/wallet-setup-list.view.ts @@ -18,57 +18,52 @@ import { filter, map, tap } from 'rxjs/operators'; @Component({ selector: 'app-wallet-setup-list', templateUrl: './wallet-setup-list.view.html', - styleUrls: ['./wallet-setup-list.view.sass'] + styleUrls: ['./wallet-setup-list.view.sass'], }) export class WalletSetupListView implements OnInit { constructor( private store: Store, private formBuilder: FormBuilder, - private persistenceService2: PersistenceService2 + private persistenceService2: PersistenceService2, ) {} - progress$: Observable = this.store.select(selectGoalsProgress) - .pipe( - filter(progress => !!progress && progress.goals && progress.goals.length > 0) - ); + progress$: Observable = this.store + .select(selectGoalsProgress) + .pipe(filter(progress => !!progress && progress.goals && progress.goals.length > 0)); private trackerSettings: any; toDo$: Observable = this.progress$.pipe( - map(progress => - progress.goals.filter(goal => goal.status === ProgressStatus.Incomplete) - ) + map(progress => progress.goals.filter(goal => goal.status === ProgressStatus.Incomplete)), ); done$: Observable = this.progress$.pipe( - map(progress => - progress.goals.filter(goal => goal.status === ProgressStatus.Complete) - ) + map(progress => progress.goals.filter(goal => goal.status === ProgressStatus.Complete)), ); formData: FormGroup = this.formBuilder.group({ - isSetupTrackerEnabled: false + isSetupTrackerEnabled: false, }); wallets$: Observable = this.store.select(selectWallets); selectedWallet$: Observable = this.store.select(selectPrimaryWallet); - isConfirmed$: Observable = this.selectedWallet$ - .pipe( - filter(wallet => !!wallet), - map((wallet: DisplayWallet) => wallet.confirmed) - ); + isConfirmed$: Observable = this.selectedWallet$.pipe( + filter(wallet => !!wallet), + map((wallet: DisplayWallet) => wallet.confirmed), + ); async ngOnInit() { this.trackerSettings = await getLatestValue(this.store.select(selectGoalSettings), settings => !!settings); - this.formData.get('isSetupTrackerEnabled').setValue(this.trackerSettings.isSetupTrackerEnabled, { emitEvent: false }); + this.formData + .get('isSetupTrackerEnabled') + .setValue(this.trackerSettings.isSetupTrackerEnabled, { emitEvent: false }); - this.formData.valueChanges - .subscribe(({ isSetupTrackerEnabled }) => { - this.trackerSettings.isSetupTrackerEnabled = isSetupTrackerEnabled; - this.store.dispatch(new SaveGoalSettingsAction(this.trackerSettings)); - }); + this.formData.valueChanges.subscribe(({ isSetupTrackerEnabled }) => { + this.trackerSettings.isSetupTrackerEnabled = isSetupTrackerEnabled; + this.store.dispatch(new SaveGoalSettingsAction(this.trackerSettings)); + }); } async selectWallet(wallet: DisplayWallet) { diff --git a/packages/lightwallet/desktop/src/app/core/wallets/create-wallet/create-wallet.view.ts b/packages/lightwallet/desktop/src/app/core/wallets/create-wallet/create-wallet.view.ts index 3fb086d404..37041c92f4 100644 --- a/packages/lightwallet/desktop/src/app/core/wallets/create-wallet/create-wallet.view.ts +++ b/packages/lightwallet/desktop/src/app/core/wallets/create-wallet/create-wallet.view.ts @@ -25,10 +25,9 @@ import 'rxjs/add/operator/toPromise'; @Component({ selector: 'view-create-wallet', templateUrl: './create-wallet.view.html', - styleUrls: ['./create-wallet.view.sass'] + styleUrls: ['./create-wallet.view.sass'], }) export class CreateWalletView { - formData: FormGroup = this.formBuilder.group({ walletName: ['Personal wallet', Validators.required], parentAddress: ['', Validators.required, AddressValidator.validateAddress(this.mwcService)], @@ -38,33 +37,37 @@ export class CreateWalletView { password: '', repeatPassword: ['', PasswordValidator.MatchPassword], color: ['#00B0DD'], - hideBalance: false + hideBalance: false, }); selectedColor = { name: 'Merit blue', - color: '#00B0DD' + color: '#00B0DD', }; availableColors: any = WalletSettingsColors; backUpWallet: boolean; createdWallet; - constructor(private formBuilder: FormBuilder, - private walletService: WalletService, - private config: ConfigService, - private logger: LoggerService, - private router: Router, - private store: Store, - private addressService: AddressService, - private txFormatService: TxFormatService, - private loader: Ng4LoadingSpinnerService, - private mwcService: MWCService, - private persistenceService2: PersistenceService2) { - } + constructor( + private formBuilder: FormBuilder, + private walletService: WalletService, + private config: ConfigService, + private logger: LoggerService, + private router: Router, + private store: Store, + private addressService: AddressService, + private txFormatService: TxFormatService, + private loader: Ng4LoadingSpinnerService, + private mwcService: MWCService, + private persistenceService2: PersistenceService2, + ) {} async ngOnInit() { - const wallets = await this.store.select(selectWallets).pipe(take(1)).toPromise(); + const wallets = await this.store + .select(selectWallets) + .pipe(take(1)) + .toPromise(); let wallet = wallets.find(w => w.availableInvites > 0); wallet = wallet || wallets[0]; @@ -86,7 +89,7 @@ export class CreateWalletView { recoveryPhrase: mnemonic, hideBalance, password, - color + color, } = this.formData.getRawValue(); parentAddress = cleanAddress(parentAddress); @@ -100,7 +103,7 @@ export class CreateWalletView { mnemonic, networkName: ENV.network, m: 1, //todo temp! - n: 1 //todo temp! + n: 1, //todo temp! }; try { @@ -127,8 +130,8 @@ export class CreateWalletView { // TODO(ibby): fix this implementation here & in mobile version const colorOpts = { colorFor: { - [wallet.id]: color - } + [wallet.id]: color, + }, }; promises.push(this.config.set(colorOpts)); } @@ -139,8 +142,14 @@ export class CreateWalletView { this.logger.error(e); } - const displayWallet = await createDisplayWallet(wallet, this.walletService, this.addressService, this.txFormatService, this.persistenceService2); - this.store.dispatch(new AddWalletAction(displayWallet)); + const displayWallet = await createDisplayWallet( + wallet, + this.walletService, + this.addressService, + this.txFormatService, + this.persistenceService2, + ); + this.store.dispatch(new AddWalletAction(displayWallet)); this.backUpWallet = true; this.createdWallet = displayWallet; } catch (err) { @@ -151,7 +160,7 @@ export class CreateWalletView { } } - proceedToWallet() { + proceedToWallet() { this.router.navigateByUrl(`/wallets/${this.createdWallet.client.id}/settings`); } diff --git a/packages/lightwallet/desktop/src/app/core/wallets/wallet-details/wallet-details-history/wallet-details-history.view.ts b/packages/lightwallet/desktop/src/app/core/wallets/wallet-details/wallet-details-history/wallet-details-history.view.ts index 5b8eebf74c..23fde39c97 100644 --- a/packages/lightwallet/desktop/src/app/core/wallets/wallet-details/wallet-details-history/wallet-details-history.view.ts +++ b/packages/lightwallet/desktop/src/app/core/wallets/wallet-details/wallet-details-history/wallet-details-history.view.ts @@ -2,10 +2,7 @@ import { Component, ViewEncapsulation } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { IDisplayTransaction } from '@merit/common/models/transaction'; import { IRootAppState } from '@merit/common/reducers'; -import { - selectTransactionsByWalletId, - selectTransactionsLoading -} from '@merit/common/reducers/transactions.reducer'; +import { selectTransactionsByWalletId, selectTransactionsLoading } from '@merit/common/reducers/transactions.reducer'; import { getLatestValue } from '@merit/common/utils/observables'; import { Store } from '@ngrx/store'; import { Observable } from 'rxjs/Observable'; @@ -15,24 +12,18 @@ import { switchMap, map } from 'rxjs/operators'; selector: 'view-wallet-details-history', templateUrl: './wallet-details-history.view.html', styleUrls: ['./wallet-details-history.view.sass'], - encapsulation: ViewEncapsulation.None + encapsulation: ViewEncapsulation.None, }) export class WalletDetailHistoryView { - walletId$: Observable = this.route.parent.params - .pipe( - map(params => params.id) - ); + walletId$: Observable = this.route.parent.params.pipe(map(params => params.id)); transactions$: Observable = this.walletId$.pipe( - switchMap(walletId => this.store.select(selectTransactionsByWalletId(walletId))) + switchMap(walletId => this.store.select(selectTransactionsByWalletId(walletId))), ); loading$: Observable = this.store.select(selectTransactionsLoading); - constructor(private store: Store, - private route: ActivatedRoute) {} + constructor(private store: Store, private route: ActivatedRoute) {} - async ngOnInit() { - - } + async ngOnInit() {} } diff --git a/packages/lightwallet/desktop/src/app/core/wallets/wallet-details/wallet-details.view.ts b/packages/lightwallet/desktop/src/app/core/wallets/wallet-details/wallet-details.view.ts index 5b32487be0..0a74e18839 100644 --- a/packages/lightwallet/desktop/src/app/core/wallets/wallet-details/wallet-details.view.ts +++ b/packages/lightwallet/desktop/src/app/core/wallets/wallet-details/wallet-details.view.ts @@ -12,32 +12,28 @@ import { ToastControllerService } from '@merit/common/services/toast-controller. @Component({ selector: 'view-wallet-details', templateUrl: './wallet-details.view.html', - styleUrls: ['./wallet-details.view.sass'] + styleUrls: ['./wallet-details.view.sass'], }) export class WalletDetailView { - singleWallet$: Observable = this.store.select(selectNumberOfWallets).pipe( - map((numOfWallets: number) => numOfWallets === 1) - ); + singleWallet$: Observable = this.store + .select(selectNumberOfWallets) + .pipe(map((numOfWallets: number) => numOfWallets === 1)); - wallet$: Observable = this.route.params - .pipe( - filter(({ id }) => !!id), - switchMap(({ id }) => - this.store.select(selectWalletById(id)) - ) - ); + wallet$: Observable = this.route.params.pipe( + filter(({ id }) => !!id), + switchMap(({ id }) => this.store.select(selectWalletById(id))), + ); shareLink$: Observable = this.wallet$.pipe( filter(wallet => !!wallet), - map(wallet => - getShareLink(wallet.alias || wallet.referrerAddress) - ) + map(wallet => getShareLink(wallet.alias || wallet.referrerAddress)), ); - constructor(private store: Store, - private route: ActivatedRoute, - private toastCtrl: ToastControllerService) { - } + constructor( + private store: Store, + private route: ActivatedRoute, + private toastCtrl: ToastControllerService, + ) {} onCopy() { this.toastCtrl.success('Share link copied to clipboard!'); diff --git a/packages/lightwallet/desktop/src/app/core/wallets/wallet-details/wallet-settings/wallet-settings.view.ts b/packages/lightwallet/desktop/src/app/core/wallets/wallet-details/wallet-settings/wallet-settings.view.ts index 918897ca2e..62d2989e4d 100644 --- a/packages/lightwallet/desktop/src/app/core/wallets/wallet-details/wallet-settings/wallet-settings.view.ts +++ b/packages/lightwallet/desktop/src/app/core/wallets/wallet-details/wallet-settings/wallet-settings.view.ts @@ -22,7 +22,6 @@ import { WalletSettingsColors } from '@merit/common/const/wallet-colors'; styleUrls: ['./wallet-settings.view.sass'], }) export class WalletSettingsView implements OnInit, OnDestroy { - availableColors: any = WalletSettingsColors; selectedColor: any; @@ -63,7 +62,7 @@ export class WalletSettingsView implements OnInit, OnDestroy { private passwordPromptCtrl: PasswordPromptController, private confirmDialogCtrl: ConfirmDialogControllerService, private router: Router, - private toastCtrl: ToastControllerService + private toastCtrl: ToastControllerService, ) {} ngOnInit() { @@ -88,14 +87,17 @@ export class WalletSettingsView implements OnInit, OnDestroy { this.subs.push( this.settingsForm.valueChanges - .pipe(debounceTime(100), filter(() => this.settingsForm.valid)) + .pipe( + debounceTime(100), + filter(() => this.settingsForm.valid), + ) .subscribe(({ name, balanceHidden }) => { this.wallet.name = name; this.wallet.balanceHidden = balanceHidden; this.store.dispatch(new UpdateOneWalletAction(this.wallet)); - }) + }), ); - }) + }), ); } @@ -103,7 +105,7 @@ export class WalletSettingsView implements OnInit, OnDestroy { // wallet is encrypted and we need a password to decrypt before setting a new password this.passwordChangeForm.addControl( 'currentPassword', - this.formBuilder.control('', [Validators.required, PasswordValidator.VerifyWalletPassword(this.wallet.client)]) + this.formBuilder.control('', [Validators.required, PasswordValidator.VerifyWalletPassword(this.wallet.client)]), ); this.isWalletEncrypted = true; } @@ -152,7 +154,7 @@ export class WalletSettingsView implements OnInit, OnDestroy { text: 'No', value: 'no', }, - ] + ], ); confirmDialog.onDidDismiss(async (value: string) => { diff --git a/packages/lightwallet/desktop/src/app/core/wallets/wallets.view.ts b/packages/lightwallet/desktop/src/app/core/wallets/wallets.view.ts index 858b49a189..c8f16cf460 100644 --- a/packages/lightwallet/desktop/src/app/core/wallets/wallets.view.ts +++ b/packages/lightwallet/desktop/src/app/core/wallets/wallets.view.ts @@ -12,23 +12,24 @@ import 'rxjs/add/operator/toPromise'; selector: 'view-wallets', templateUrl: './wallets.view.html', styleUrls: ['./wallets.view.sass'], - encapsulation: ViewEncapsulation.None + encapsulation: ViewEncapsulation.None, }) export class WalletsView { wallets$: Observable = this.store.select(selectWallets); walletsLoading$: Observable = this.store.select(selectWalletsLoading); - constructor(private store: Store, - private router: Router) {} + constructor(private store: Store, private router: Router) {} - ngOnInit() { - return this.wallets$.pipe( - take(1), - tap((wallets) => { - if(wallets.length === 1) { - this.router.navigate(['/wallets/', wallets[0].id]); - } - }) - ).toPromise(); + ngOnInit() { + return this.wallets$ + .pipe( + take(1), + tap(wallets => { + if (wallets.length === 1) { + this.router.navigate(['/wallets/', wallets[0].id]); + } + }), + ) + .toPromise(); } } diff --git a/packages/lightwallet/desktop/src/app/guards/dashboard.guard.ts b/packages/lightwallet/desktop/src/app/guards/dashboard.guard.ts index 7fe0c6193b..a029e2defc 100644 --- a/packages/lightwallet/desktop/src/app/guards/dashboard.guard.ts +++ b/packages/lightwallet/desktop/src/app/guards/dashboard.guard.ts @@ -9,21 +9,18 @@ import { map } from 'rxjs/operators'; @Injectable() export class DashboardGuard implements CanActivate { - constructor(private profileService: ProfileService, - private router: Router, - private store: Store) {} + constructor(private profileService: ProfileService, private router: Router, private store: Store) {} canActivate(): Observable | Promise | boolean { - return this.store.select(selectAppState) - .pipe( - map((state: IAppState) => { - if (state.authorized) { - return true; - } else { - this.router.navigateByUrl('/onboarding/unlock'); - return false; - } - }) - ); + return this.store.select(selectAppState).pipe( + map((state: IAppState) => { + if (state.authorized) { + return true; + } else { + this.router.navigateByUrl('/onboarding/unlock'); + return false; + } + }), + ); } } diff --git a/packages/lightwallet/desktop/src/app/guards/onboarding.guard.ts b/packages/lightwallet/desktop/src/app/guards/onboarding.guard.ts index d707be685c..db3d2f9a51 100644 --- a/packages/lightwallet/desktop/src/app/guards/onboarding.guard.ts +++ b/packages/lightwallet/desktop/src/app/guards/onboarding.guard.ts @@ -9,22 +9,21 @@ import { map } from 'rxjs/operators'; @Injectable() export class OnboardingGuard implements CanActivate { - constructor(private profileService: ProfileService, - private router: Router, - private store: Store) {} + constructor(private profileService: ProfileService, private router: Router, private store: Store) {} - canActivate(next: ActivatedRouteSnapshot, - state: RouterStateSnapshot): Observable | Promise | boolean { - return this.store.select(selectAppState) - .pipe( - map((state: IAppState) => { - if (!state.authorized) { - return true; - } else { - this.router.navigateByUrl('/dashboard'); - return false; - } - }) - ); + canActivate( + next: ActivatedRouteSnapshot, + state: RouterStateSnapshot, + ): Observable | Promise | boolean { + return this.store.select(selectAppState).pipe( + map((state: IAppState) => { + if (!state.authorized) { + return true; + } else { + this.router.navigateByUrl('/dashboard'); + return false; + } + }), + ); } } diff --git a/packages/lightwallet/desktop/src/app/guards/wallet-password.guard.ts b/packages/lightwallet/desktop/src/app/guards/wallet-password.guard.ts index 5e7fe6d076..6c14406c3e 100644 --- a/packages/lightwallet/desktop/src/app/guards/wallet-password.guard.ts +++ b/packages/lightwallet/desktop/src/app/guards/wallet-password.guard.ts @@ -16,21 +16,22 @@ import { switchMap } from 'rxjs/operators'; @Injectable() export class WalletPasswordGuard implements CanActivate { wallet$: Observable = this.route.params.pipe( - switchMap((params: any) => - this.store.select(selectWalletById(params.id)) - ) + switchMap((params: any) => this.store.select(selectWalletById(params.id))), ); - constructor(private route: ActivatedRoute, - private walletService: WalletService, - private store: Store, - private passwordPromptCtrl: PasswordPromptController) { - console.log('WalletPasswordGuard'); - } + constructor( + private route: ActivatedRoute, + private walletService: WalletService, + private store: Store, + private passwordPromptCtrl: PasswordPromptController, + ) { + console.log('WalletPasswordGuard'); + } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { return new Promise(async resolve => { - const wallet = await this.store.select(selectWalletById(route.parent.params.id)) + const wallet = await this.store + .select(selectWalletById(route.parent.params.id)) .take(1) .toPromise(); diff --git a/packages/lightwallet/desktop/src/app/import/import-by-qr/import-by-qr.module.ts b/packages/lightwallet/desktop/src/app/import/import-by-qr/import-by-qr.module.ts index 08239b3125..8552dd59b5 100644 --- a/packages/lightwallet/desktop/src/app/import/import-by-qr/import-by-qr.module.ts +++ b/packages/lightwallet/desktop/src/app/import/import-by-qr/import-by-qr.module.ts @@ -7,19 +7,17 @@ import { ImportByQrView } from '@merit/desktop/app/import/import-by-qr/import-by RouterModule.forChild([ { path: '', - component: ImportByQrView - } - ]) + component: ImportByQrView, + }, + ]), ], - exports: [ - RouterModule - ] + exports: [RouterModule], }) export class ImportByQrRoutingModule {} @NgModule({ entryComponents: [ImportByQrView], declarations: [ImportByQrView], - imports: [ImportByQrRoutingModule] + imports: [ImportByQrRoutingModule], }) export class ImportByQrModule {} diff --git a/packages/lightwallet/desktop/src/app/import/import-by-qr/import-by-qr.view.ts b/packages/lightwallet/desktop/src/app/import/import-by-qr/import-by-qr.view.ts index 690e43cdd1..f2af7cd201 100644 --- a/packages/lightwallet/desktop/src/app/import/import-by-qr/import-by-qr.view.ts +++ b/packages/lightwallet/desktop/src/app/import/import-by-qr/import-by-qr.view.ts @@ -3,7 +3,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'view-import-by-qr', templateUrl: './import-by-qr.view.html', - styleUrls: ['./import-by-qr.view.scss'] + styleUrls: ['./import-by-qr.view.scss'], }) -export class ImportByQrView { -} +export class ImportByQrView {} diff --git a/packages/lightwallet/desktop/src/app/import/import-wallet.view.ts b/packages/lightwallet/desktop/src/app/import/import-wallet.view.ts index 918be30155..2488cd5624 100644 --- a/packages/lightwallet/desktop/src/app/import/import-wallet.view.ts +++ b/packages/lightwallet/desktop/src/app/import/import-wallet.view.ts @@ -3,6 +3,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'view-import-wallet', templateUrl: './import-wallet.view.html', - styleUrls: ['./import-wallet.view.sass'] + styleUrls: ['./import-wallet.view.sass'], }) export class ImportWalletView {} diff --git a/packages/lightwallet/desktop/src/app/import/import-with-file/import-with-file.module.ts b/packages/lightwallet/desktop/src/app/import/import-with-file/import-with-file.module.ts index 5b9cfb6e19..844f535f56 100644 --- a/packages/lightwallet/desktop/src/app/import/import-with-file/import-with-file.module.ts +++ b/packages/lightwallet/desktop/src/app/import/import-with-file/import-with-file.module.ts @@ -9,24 +9,17 @@ import { Ng4LoadingSpinnerModule } from 'ng4-loading-spinner'; RouterModule.forChild([ { path: '', - component: ImportWithFileView - } - ]) + component: ImportWithFileView, + }, + ]), ], - exports: [ - RouterModule - ] + exports: [RouterModule], }) export class ImportWithFileRoutingModule {} @NgModule({ entryComponents: [ImportWithFileView], declarations: [ImportWithFileView], - imports: [ - ImportWithFileRoutingModule, - FormsModule, - ReactiveFormsModule, - Ng4LoadingSpinnerModule - ] + imports: [ImportWithFileRoutingModule, FormsModule, ReactiveFormsModule, Ng4LoadingSpinnerModule], }) export class ImportWithFileModule {} diff --git a/packages/lightwallet/desktop/src/app/import/import-with-file/import-with-file.view.ts b/packages/lightwallet/desktop/src/app/import/import-with-file/import-with-file.view.ts index 22f24b6e06..45adf69463 100644 --- a/packages/lightwallet/desktop/src/app/import/import-with-file/import-with-file.view.ts +++ b/packages/lightwallet/desktop/src/app/import/import-with-file/import-with-file.view.ts @@ -21,15 +21,14 @@ import { Ng4LoadingSpinnerService } from 'ng4-loading-spinner'; @Component({ selector: 'view-import-with-file', templateUrl: './import-with-file.view.html', - styleUrls: ['./import-with-file.view.scss'] + styleUrls: ['./import-with-file.view.scss'], }) export class ImportWithFileView { - formData = { backupFile: null, backupFileBlob: null, filePassword: '', - mwsUrl: ENV.mwsUrl + mwsUrl: ENV.mwsUrl, }; showPass: boolean; @@ -40,26 +39,28 @@ export class ImportWithFileView { private sjcl = this.mwcService.getSJCL(); - constructor(private mwcService: MWCService, - private store: Store, - private logger: LoggerService, - private profileService: ProfileService, - private walletService: WalletService, - private addressService: AddressService, - private txFormatService: TxFormatService, - private router: Router, - private toastCtrl: ToastControllerService, - private pushNotificationsService: PushNotificationsService, - private loadingCtrl: Ng4LoadingSpinnerService, - private persistenceService2: PersistenceService2) { - } + constructor( + private mwcService: MWCService, + private store: Store, + private logger: LoggerService, + private profileService: ProfileService, + private walletService: WalletService, + private addressService: AddressService, + private txFormatService: TxFormatService, + private router: Router, + private toastCtrl: ToastControllerService, + private pushNotificationsService: PushNotificationsService, + private loadingCtrl: Ng4LoadingSpinnerService, + private persistenceService2: PersistenceService2, + ) {} fileChangeListener($event) { this.formData.backupFile = $event.target.files[0]; const reader = new FileReader(); reader.onloadend = (loadEvent: any) => { - if (loadEvent.target.readyState == 2) { //DONE == 2 + if (loadEvent.target.readyState == 2) { + //DONE == 2 this.formData.backupFileBlob = loadEvent.target.result; } }; @@ -74,7 +75,6 @@ export class ImportWithFileView { try { decrypted = this.sjcl.decrypt(this.formData.filePassword, this.formData.backupFileBlob); } catch (e) { - this.logger.warn(e); this.loadingCtrl.hide(); return this.toastCtrl.error('Could not decrypt file, check your password.'); @@ -84,23 +84,32 @@ export class ImportWithFileView { // loader.present(); try { - const wallet: MeritWalletClient = await this.walletService.importWallet(decrypted, { bwsurl: this.formData.mwsUrl }); + const wallet: MeritWalletClient = await this.walletService.importWallet(decrypted, { + bwsurl: this.formData.mwsUrl, + }); this.pushNotificationsService.subscribe(wallet); this.store.dispatch( new AddWalletAction( - await createDisplayWallet(wallet, this.walletService, this.addressService, this.txFormatService, this.persistenceService2) - ) + await createDisplayWallet( + wallet, + this.walletService, + this.addressService, + this.txFormatService, + this.persistenceService2, + ), + ), ); // update state so we're allowed to access the dashboard, in case this is done via onboarding import - this.store.dispatch(new UpdateAppAction({ - loading: false, - authorized: true - })); + this.store.dispatch( + new UpdateAppAction({ + loading: false, + authorized: true, + }), + ); return this.router.navigateByUrl('/wallets'); - } catch (err) { // loader.dismiss(); this.logger.warn(err); @@ -108,5 +117,4 @@ export class ImportWithFileView { return this.toastCtrl.error(err); } } - } diff --git a/packages/lightwallet/desktop/src/app/import/import.module.ts b/packages/lightwallet/desktop/src/app/import/import.module.ts index c0101607f7..67d9d21990 100644 --- a/packages/lightwallet/desktop/src/app/import/import.module.ts +++ b/packages/lightwallet/desktop/src/app/import/import.module.ts @@ -7,19 +7,17 @@ import { ImportWalletView } from '@merit/desktop/app/import/import-wallet.view'; RouterModule.forChild([ { path: '', - component: ImportWalletView - } - ]) + component: ImportWalletView, + }, + ]), ], - exports: [RouterModule] + exports: [RouterModule], }) export class ImportRoutingModule {} @NgModule({ entryComponents: [ImportWalletView], declarations: [ImportWalletView], - imports: [ - ImportRoutingModule - ] + imports: [ImportRoutingModule], }) export class ImportModule {} diff --git a/packages/lightwallet/desktop/src/app/import/phrase-import/phrase-import.module.ts b/packages/lightwallet/desktop/src/app/import/phrase-import/phrase-import.module.ts index b66a8bbbcc..cbc639a122 100644 --- a/packages/lightwallet/desktop/src/app/import/phrase-import/phrase-import.module.ts +++ b/packages/lightwallet/desktop/src/app/import/phrase-import/phrase-import.module.ts @@ -9,24 +9,17 @@ import { Ng4LoadingSpinnerModule } from 'ng4-loading-spinner'; RouterModule.forChild([ { path: '', - component: PhraseImportView - } - ]) + component: PhraseImportView, + }, + ]), ], - exports: [ - RouterModule - ] + exports: [RouterModule], }) export class PhraseImportRoutingModule {} @NgModule({ entryComponents: [PhraseImportView], declarations: [PhraseImportView], - imports: [ - PhraseImportRoutingModule, - FormsModule, - ReactiveFormsModule, - Ng4LoadingSpinnerModule - ] + imports: [PhraseImportRoutingModule, FormsModule, ReactiveFormsModule, Ng4LoadingSpinnerModule], }) export class PhraseImportModule {} diff --git a/packages/lightwallet/desktop/src/app/import/phrase-import/phrase-import.view.ts b/packages/lightwallet/desktop/src/app/import/phrase-import/phrase-import.view.ts index 03bbb7de5b..34e6981e55 100644 --- a/packages/lightwallet/desktop/src/app/import/phrase-import/phrase-import.view.ts +++ b/packages/lightwallet/desktop/src/app/import/phrase-import/phrase-import.view.ts @@ -23,33 +23,31 @@ import { Ng4LoadingSpinnerService } from 'ng4-loading-spinner'; @Component({ selector: 'view-phrase-import', templateUrl: './phrase-import.view.html', - styleUrls: ['./phrase-import.view.scss'] + styleUrls: ['./phrase-import.view.scss'], }) export class PhraseImportView { - formData: FormGroup = this.formBuilder.group({ - words: ['', [Validators.required, MnemonicValidator.validateMnemonicImport]] + words: ['', [Validators.required, MnemonicValidator.validateMnemonicImport]], }); showPass: boolean; - private derivationPath = ENV.network == 'livenet' ? - DerivationPath.getDefault() : - DerivationPath.getDefaultTestnet(); - - constructor(private formBuilder: FormBuilder, - private profileService: ProfileService, - private mnemonicService: MnemonicService, - private store: Store, - private walletService: WalletService, - private addressService: AddressService, - private txFormatService: TxFormatService, - private router: Router, - private pushNotificationsService: PushNotificationsService, - private toastCtrl: ToastControllerService, - private loadingCtrl: Ng4LoadingSpinnerService, - private persistenceService2:PersistenceService2 ) {} - + private derivationPath = ENV.network == 'livenet' ? DerivationPath.getDefault() : DerivationPath.getDefaultTestnet(); + + constructor( + private formBuilder: FormBuilder, + private profileService: ProfileService, + private mnemonicService: MnemonicService, + private store: Store, + private walletService: WalletService, + private addressService: AddressService, + private txFormatService: TxFormatService, + private router: Router, + private pushNotificationsService: PushNotificationsService, + private toastCtrl: ToastControllerService, + private loadingCtrl: Ng4LoadingSpinnerService, + private persistenceService2: PersistenceService2, + ) {} async importMnemonic() { this.loadingCtrl.show(); @@ -66,7 +64,7 @@ export class PhraseImportView { const opts: any = { account: pathData.account, networkName: pathData.networkName, - derivationStrategy: pathData.derivationStrategy + derivationStrategy: pathData.derivationStrategy, }; let wallet; @@ -85,15 +83,23 @@ export class PhraseImportView { this.store.dispatch( new AddWalletAction( - await createDisplayWallet(wallet, this.walletService, this.addressService, this.txFormatService, this.persistenceService2) - ) + await createDisplayWallet( + wallet, + this.walletService, + this.addressService, + this.txFormatService, + this.persistenceService2, + ), + ), ); // update state so we're allowed to access the dashboard, in case this is done via onboarding import - this.store.dispatch(new UpdateAppAction({ - loading: false, - authorized: true - })); + this.store.dispatch( + new UpdateAppAction({ + loading: false, + authorized: true, + }), + ); this.loadingCtrl.hide(); this.persistenceService2.setUserSettings(UserSettingsKey.recordPassphrase, true); @@ -130,5 +136,4 @@ export class PhraseImportView { return !(words.split(/[\u3000\s]+/).length % 3); } } - } diff --git a/packages/lightwallet/desktop/src/app/market/escrow-payment/escrow-payment.view.ts b/packages/lightwallet/desktop/src/app/market/escrow-payment/escrow-payment.view.ts index f00b123107..f2bacfb603 100644 --- a/packages/lightwallet/desktop/src/app/market/escrow-payment/escrow-payment.view.ts +++ b/packages/lightwallet/desktop/src/app/market/escrow-payment/escrow-payment.view.ts @@ -11,7 +11,7 @@ import { PasswordPromptController } from '@merit/desktop/app/components/password @Component({ selector: 'view-escrow-payment', templateUrl: './escrow-payment.view.html', - styleUrls: ['./escrow-payment.view.sass'] + styleUrls: ['./escrow-payment.view.sass'], }) export class EscrowPaymentView implements OnInit { error: string; @@ -52,14 +52,16 @@ export class EscrowPaymentView implements OnInit { this.feeCalculated = false; const opts = { - outputs: [{ - amount: this.amount, - toAddress: this.sendTo, - }, - { - script: Script.buildDataOut(`MeritMarket:${this.entitiesType}:${this.entitiesIds}`).toHex(), - amount: 0 - }], + outputs: [ + { + amount: this.amount, + toAddress: this.sendTo, + }, + { + script: Script.buildDataOut(`MeritMarket:${this.entitiesType}:${this.entitiesIds}`).toHex(), + amount: 0, + }, + ], validateOutputs: false, }; @@ -112,8 +114,8 @@ export class EscrowPaymentView implements OnInit { this.success = true; const message = JSON.stringify({ - message: "Lightwallet.Market.SendToEscrow", - data: { ok: true, txid: this.txp.txid } + message: 'Lightwallet.Market.SendToEscrow', + data: { ok: true, txid: this.txp.txid }, }); window.opener.postMessage(message, ENV.marketUrl); } catch (e) { @@ -123,8 +125,8 @@ export class EscrowPaymentView implements OnInit { cancel() { const message = JSON.stringify({ - message: "Lightwallet.Market.SendToEscrow", - data: { ok: false } + message: 'Lightwallet.Market.SendToEscrow', + data: { ok: false }, }); window.opener.postMessage(message, ENV.marketUrl); } diff --git a/packages/lightwallet/desktop/src/app/market/escrow.guard.ts b/packages/lightwallet/desktop/src/app/market/escrow.guard.ts index 3997d79c63..2d2a8e567c 100644 --- a/packages/lightwallet/desktop/src/app/market/escrow.guard.ts +++ b/packages/lightwallet/desktop/src/app/market/escrow.guard.ts @@ -8,7 +8,15 @@ export class EscrowGuard implements CanActivate { constructor(private router: Router) {} canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): any { - if (/*!window.opener ||*/ !(getQueryParam('a') && getQueryParam('pa') && getQueryParam('ea') && getQueryParam('t') && getQueryParam('ids'))) { + if ( + /*!window.opener ||*/ !( + getQueryParam('a') && + getQueryParam('pa') && + getQueryParam('ea') && + getQueryParam('t') && + getQueryParam('ids') + ) + ) { this.router.navigate(['/']); return false; } diff --git a/packages/lightwallet/desktop/src/app/market/market-login/market-login.view.ts b/packages/lightwallet/desktop/src/app/market/market-login/market-login.view.ts index c4a47f2b3a..c48b7f818b 100644 --- a/packages/lightwallet/desktop/src/app/market/market-login/market-login.view.ts +++ b/packages/lightwallet/desktop/src/app/market/market-login/market-login.view.ts @@ -17,10 +17,7 @@ export class MarketLoginView implements OnInit { selectedWalletIndex = -1; profile; - constructor( - private persistenceService: PersistenceService, - private passwordPromptCtrl: PasswordPromptController, - ) {} + constructor(private persistenceService: PersistenceService, private passwordPromptCtrl: PasswordPromptController) {} async ngOnInit() { this.loadingWallets = true; @@ -62,8 +59,8 @@ export class MarketLoginView implements OnInit { if (authData.token) { const message = JSON.stringify({ - message: "Lightwallet.Market.Auth", - data: { token: authData.token } + message: 'Lightwallet.Market.Auth', + data: { token: authData.token }, }); window.opener.postMessage(message, ENV.marketUrl); } diff --git a/packages/lightwallet/desktop/src/app/market/market.module.ts b/packages/lightwallet/desktop/src/app/market/market.module.ts index b80d9614cd..1c8ea023dd 100644 --- a/packages/lightwallet/desktop/src/app/market/market.module.ts +++ b/packages/lightwallet/desktop/src/app/market/market.module.ts @@ -19,14 +19,7 @@ import { CommonPipesModule } from '@merit/common/common-pipes.module'; SharedComponentsModule.forRoot(), CommonPipesModule, ], - declarations: [ - MarketLoginView, - EscrowPaymentView, - ], - providers: [ - EscrowGuard, - WalletService, - SendService, - ] + declarations: [MarketLoginView, EscrowPaymentView], + providers: [EscrowGuard, WalletService, SendService], }) export class MarketModule {} diff --git a/packages/lightwallet/desktop/src/app/onboarding/app-start-up/app-start-up.component.ts b/packages/lightwallet/desktop/src/app/onboarding/app-start-up/app-start-up.component.ts index f23311f1d3..d7dfb9775f 100644 --- a/packages/lightwallet/desktop/src/app/onboarding/app-start-up/app-start-up.component.ts +++ b/packages/lightwallet/desktop/src/app/onboarding/app-start-up/app-start-up.component.ts @@ -3,10 +3,9 @@ import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-app-start-up', templateUrl: './app-start-up.component.html', - styleUrls: ['./app-start-up.component.sass'] + styleUrls: ['./app-start-up.component.sass'], }) export class AppStartUpComponent implements OnInit { - showWelcomeAnimation: Boolean = true; ngOnInit() { @@ -19,5 +18,4 @@ export class AppStartUpComponent implements OnInit { } this.showWelcomeAnimation = showWelcomeAnimation; } - } diff --git a/packages/lightwallet/desktop/src/app/onboarding/app-start-up/guide-beginners-help/guide-beginners-help.component.ts b/packages/lightwallet/desktop/src/app/onboarding/app-start-up/guide-beginners-help/guide-beginners-help.component.ts index 5b055a3336..4db072da3a 100644 --- a/packages/lightwallet/desktop/src/app/onboarding/app-start-up/guide-beginners-help/guide-beginners-help.component.ts +++ b/packages/lightwallet/desktop/src/app/onboarding/app-start-up/guide-beginners-help/guide-beginners-help.component.ts @@ -3,7 +3,7 @@ import { Component } from '@angular/core'; @Component({ selector: 'app-guide-beginners-help', templateUrl: './guide-beginners-help.component.html', - styleUrls: ['./guide-beginners-help.component.sass'] + styleUrls: ['./guide-beginners-help.component.sass'], }) export class GuideBeginnersHelpComponent { showGuide: boolean = !('showGuide' in localStorage && localStorage.getItem('showGuide') === 'false'); diff --git a/packages/lightwallet/desktop/src/app/onboarding/app-start-up/guide-went-from-desktop/guide-went-from-desktop.component.ts b/packages/lightwallet/desktop/src/app/onboarding/app-start-up/guide-went-from-desktop/guide-went-from-desktop.component.ts index 57524151a3..912e12954d 100644 --- a/packages/lightwallet/desktop/src/app/onboarding/app-start-up/guide-went-from-desktop/guide-went-from-desktop.component.ts +++ b/packages/lightwallet/desktop/src/app/onboarding/app-start-up/guide-went-from-desktop/guide-went-from-desktop.component.ts @@ -3,13 +3,10 @@ import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-guide-went-from-desktop', templateUrl: './guide-went-from-desktop.component.html', - styleUrls: ['./guide-went-from-desktop.component.sass'] + styleUrls: ['./guide-went-from-desktop.component.sass'], }) export class GuideWentFromDesktopComponent implements OnInit { + constructor() {} - constructor() { } - - ngOnInit() { - } - + ngOnInit() {} } diff --git a/packages/lightwallet/desktop/src/app/onboarding/app-start-up/invited-user/invited-user.component.ts b/packages/lightwallet/desktop/src/app/onboarding/app-start-up/invited-user/invited-user.component.ts index f8ca9277a5..178019eb92 100644 --- a/packages/lightwallet/desktop/src/app/onboarding/app-start-up/invited-user/invited-user.component.ts +++ b/packages/lightwallet/desktop/src/app/onboarding/app-start-up/invited-user/invited-user.component.ts @@ -3,13 +3,10 @@ import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-invited-user', templateUrl: './invited-user.component.html', - styleUrls: ['./invited-user.component.sass'] + styleUrls: ['./invited-user.component.sass'], }) export class InvitedUserComponent implements OnInit { + constructor() {} - constructor() { } - - ngOnInit() { - } - + ngOnInit() {} } diff --git a/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/sending-merit/sending-merit.component.ts b/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/sending-merit/sending-merit.component.ts index 6add20be4b..14dadd4127 100644 --- a/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/sending-merit/sending-merit.component.ts +++ b/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/sending-merit/sending-merit.component.ts @@ -3,13 +3,10 @@ import { Component, OnInit } from '@angular/core'; @Component({ selector: 'illustration-sending-merit', templateUrl: './sending-merit.component.html', - styleUrls: ['./sending-merit.component.sass'] + styleUrls: ['./sending-merit.component.sass'], }) export class SendingMeritComponent implements OnInit { + constructor() {} - constructor() { } - - ngOnInit() { - } - + ngOnInit() {} } diff --git a/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/thats-it/thats-it.component.ts b/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/thats-it/thats-it.component.ts index b9b91dc90f..0b56b51576 100644 --- a/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/thats-it/thats-it.component.ts +++ b/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/thats-it/thats-it.component.ts @@ -3,13 +3,10 @@ import { Component, OnInit } from '@angular/core'; @Component({ selector: 'illustration-thats-it', templateUrl: './thats-it.component.html', - styleUrls: ['./thats-it.component.sass'] + styleUrls: ['./thats-it.component.sass'], }) export class ThatsItComponent implements OnInit { + constructor() {} - constructor() { } - - ngOnInit() { - } - + ngOnInit() {} } diff --git a/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/worry-free/worry-free.component.ts b/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/worry-free/worry-free.component.ts index 72b3b99e2a..f82fb4b67e 100644 --- a/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/worry-free/worry-free.component.ts +++ b/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/worry-free/worry-free.component.ts @@ -3,13 +3,10 @@ import { Component, OnInit } from '@angular/core'; @Component({ selector: 'illustration-worry-free', templateUrl: './worry-free.component.html', - styleUrls: ['./worry-free.component.sass'] + styleUrls: ['./worry-free.component.sass'], }) export class WorryFreeComponent implements OnInit { + constructor() {} - constructor() { } - - ngOnInit() { - } - + ngOnInit() {} } diff --git a/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/your-way/your-way.component.ts b/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/your-way/your-way.component.ts index 9daa5cbcbc..22e2fd59ac 100644 --- a/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/your-way/your-way.component.ts +++ b/packages/lightwallet/desktop/src/app/onboarding/onboard/illustations/your-way/your-way.component.ts @@ -3,13 +3,10 @@ import { Component, OnInit } from '@angular/core'; @Component({ selector: 'illustration-your-way', templateUrl: './your-way.component.html', - styleUrls: ['./your-way.component.sass'] + styleUrls: ['./your-way.component.sass'], }) export class YourWayComponent implements OnInit { + constructor() {} - constructor() { } - - ngOnInit() { - } - + ngOnInit() {} } diff --git a/packages/lightwallet/desktop/src/app/onboarding/onboard/onboard.view.ts b/packages/lightwallet/desktop/src/app/onboarding/onboard/onboard.view.ts index 1c63de83c3..9d0e1f32d9 100644 --- a/packages/lightwallet/desktop/src/app/onboarding/onboard/onboard.view.ts +++ b/packages/lightwallet/desktop/src/app/onboarding/onboard/onboard.view.ts @@ -3,6 +3,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'view-onboard', templateUrl: './onboard.view.html', - styleUrls: ['./onboard.view.sass'] + styleUrls: ['./onboard.view.sass'], }) export class OnboardView {} diff --git a/packages/lightwallet/desktop/src/app/onboarding/onboarding-root/onboarding-root.component.ts b/packages/lightwallet/desktop/src/app/onboarding/onboarding-root/onboarding-root.component.ts index 06f4bbbc2a..3d5ac32266 100644 --- a/packages/lightwallet/desktop/src/app/onboarding/onboarding-root/onboarding-root.component.ts +++ b/packages/lightwallet/desktop/src/app/onboarding/onboarding-root/onboarding-root.component.ts @@ -7,14 +7,10 @@ import { getQueryParam } from '@merit/common/utils/url'; selector: 'view-onboarding-root', templateUrl: './onboarding-root.component.html', styleUrls: ['./onboarding-root.component.sass'], - encapsulation: ViewEncapsulation.None + encapsulation: ViewEncapsulation.None, }) export class OnboardingRootComponent implements OnInit { - constructor( - private router: Router, - private easyReceiveService: EasyReceiveService - ) { - } + constructor(private router: Router, private easyReceiveService: EasyReceiveService) {} async ngOnInit() { const receipts = await this.easyReceiveService.getPendingReceipts(); @@ -25,7 +21,6 @@ export class OnboardingRootComponent implements OnInit { query = '?source=' + source; } this.router.navigateByUrl(`onboarding/unlock${query}`); - } + } } - } diff --git a/packages/lightwallet/desktop/src/app/onboarding/slider-guide/slider-guide.component.ts b/packages/lightwallet/desktop/src/app/onboarding/slider-guide/slider-guide.component.ts index 3320adce33..f7ec2c4b9a 100644 --- a/packages/lightwallet/desktop/src/app/onboarding/slider-guide/slider-guide.component.ts +++ b/packages/lightwallet/desktop/src/app/onboarding/slider-guide/slider-guide.component.ts @@ -20,9 +20,12 @@ export class SliderGuideComponent { loop: false, }; - @Output() hideGuide = new EventEmitter(); - @Input() skipButton: string = 'Skip tutorial'; - @Input() primaryButton: string = 'Get started'; + @Output() + hideGuide = new EventEmitter(); + @Input() + skipButton: string = 'Skip tutorial'; + @Input() + primaryButton: string = 'Get started'; skipIntro() { this.hideGuide.emit(false); diff --git a/packages/lightwallet/desktop/src/app/onboarding/unlock/unlock.view.ts b/packages/lightwallet/desktop/src/app/onboarding/unlock/unlock.view.ts index c48c1899fd..a0e342869a 100644 --- a/packages/lightwallet/desktop/src/app/onboarding/unlock/unlock.view.ts +++ b/packages/lightwallet/desktop/src/app/onboarding/unlock/unlock.view.ts @@ -73,20 +73,20 @@ export class UnlockComponent { private addressService: AddressService, private persistence: PersistenceService2, private loadingCtrl: Ng4LoadingSpinnerService, - private toastCtrl: ToastControllerService + private toastCtrl: ToastControllerService, ) {} async ngOnInit() { const receipts = await this.easyReceiveService.getPendingReceipts(); this.easyReceipt = receipts.pop(); - let inviteCode; + let inviteCode; this.gbsUnlock = (await this.persistence.getSource()) === 'gbs'; if (this.easyReceipt) { inviteCode = this.easyReceipt.parentAddress; - } else { + } else { inviteCode = cleanAddress(getQueryParam('invite')); this.invite = this.addressService.couldBeAlias(inviteCode) ? `@${inviteCode}` : inviteCode; } @@ -135,7 +135,7 @@ export class UnlockComponent { new UpdateAppAction({ loading: false, authorized: true, - }) + }), ); if (this.gbsUnlock && !!win) { diff --git a/packages/lightwallet/desktop/src/doc/theme.md b/packages/lightwallet/desktop/src/doc/theme.md index 98a72e11c8..6bee148a3e 100644 --- a/packages/lightwallet/desktop/src/doc/theme.md +++ b/packages/lightwallet/desktop/src/doc/theme.md @@ -2,6 +2,6 @@ ## Theme preferences: -All available for quick edit preferences placed: +All available for quick edit preferences placed: `/styles/v1/common/_variables.sass` diff --git a/packages/lightwallet/desktop/src/firebase-messaging-sw.js b/packages/lightwallet/desktop/src/firebase-messaging-sw.js index 0e8707c2fd..cf15794ab3 100644 --- a/packages/lightwallet/desktop/src/firebase-messaging-sw.js +++ b/packages/lightwallet/desktop/src/firebase-messaging-sw.js @@ -12,7 +12,7 @@ idb.onsuccess = () => { // Initialize the Firebase app in the service worker by passing in the // messagingSenderId. firebase.initializeApp({ - messagingSenderId: '1091326413792' + messagingSenderId: '1091326413792', }); // Retrieve an instance of Firebase Messaging so that it can handle background @@ -26,35 +26,34 @@ idb.onsuccess = () => { // so when we click on a notification, we always open any window // that we have open, instead of opening a new one. self.clients.matchAll = () => - originalMatchAllClients.apply(self.clients, [{ type: 'window', includeUncontrolled: true }]) - .then((clients) => { - if (clients && clients.length) { - clients = clients.map(client => { - Object.defineProperty(client, 'url', { - get: () => location.origin, - enumerable: true, - configurable: true - }); - return client; + originalMatchAllClients.apply(self.clients, [{ type: 'window', includeUncontrolled: true }]).then(clients => { + if (clients && clients.length) { + clients = clients.map(client => { + Object.defineProperty(client, 'url', { + get: () => location.origin, + enumerable: true, + configurable: true, }); - } - return clients; - }); + return client; + }); + } + return clients; + }); - const onBackgroundNotification = (data) => { + const onBackgroundNotification = data => { if (!data) return; console.log('[firebase-messaging-sw.js] Received background message ', data); const tx = db.transaction('_ionickv', 'readwrite'); const store = tx.objectStore('_ionickv'); - store.get('notifications').onsuccess = (({ target: { result: doc } }) => { + store.get('notifications').onsuccess = ({ target: { result: doc } }) => { doc = doc || []; doc.push({ ...data, timestamp: Date.now(), - read: false + read: false, }); store.put(doc, 'notifications'); - }); + }; }; // Firebase calls this method instead of the background message handler, so we need to intercept it to catch the date~ diff --git a/packages/lightwallet/desktop/src/main.ts b/packages/lightwallet/desktop/src/main.ts index c2c888b9f3..b06d9c54ce 100644 --- a/packages/lightwallet/desktop/src/main.ts +++ b/packages/lightwallet/desktop/src/main.ts @@ -7,5 +7,6 @@ if (ENV.production) { enableProdMode(); } -platformBrowserDynamic().bootstrapModule(AppModule) +platformBrowserDynamic() + .bootstrapModule(AppModule) .catch(err => console.error(err)); diff --git a/packages/lightwallet/desktop/src/services/desktop-alert.service.ts b/packages/lightwallet/desktop/src/services/desktop-alert.service.ts index 157ab8ca0a..a9966fa373 100644 --- a/packages/lightwallet/desktop/src/services/desktop-alert.service.ts +++ b/packages/lightwallet/desktop/src/services/desktop-alert.service.ts @@ -6,7 +6,7 @@ import { PasswordPromptController } from '@merit/desktop/app/components/password @Injectable() export class DesktopAlertService extends AlertService { constructor(private passwordPromptCtrl: PasswordPromptController) { - super() + super(); } promptForWalletPassword(wallet: MeritWalletClient) { diff --git a/packages/lightwallet/desktop/src/services/electron.service.ts b/packages/lightwallet/desktop/src/services/electron.service.ts index 584985be54..ca1c1f9225 100644 --- a/packages/lightwallet/desktop/src/services/electron.service.ts +++ b/packages/lightwallet/desktop/src/services/electron.service.ts @@ -57,7 +57,7 @@ export class ElectronService { total: 0, transferred: 0, percent: 0, - bytesPerSecond: 0 + bytesPerSecond: 0, }); this.electron.downloadUpdate((progress: IUpdateProgress) => { diff --git a/packages/lightwallet/desktop/webpack.config.js b/packages/lightwallet/desktop/webpack.config.js index c489a62363..363494343a 100644 --- a/packages/lightwallet/desktop/webpack.config.js +++ b/packages/lightwallet/desktop/webpack.config.js @@ -12,13 +12,29 @@ const postcssUrl = require('postcss-url'); const postcssImports = require('postcss-import'); const { execSync } = require('child_process'); -const { NoEmitOnErrorsPlugin, SourceMapDevToolPlugin, NamedModulesPlugin, DefinePlugin, EnvironmentPlugin, HashedModuleIdsPlugin } = require('webpack'); -const { NamedLazyChunksWebpackPlugin, SuppressExtractedTextChunksWebpackPlugin, CleanCssWebpackPlugin, BundleBudgetPlugin, BaseHrefWebpackPlugin, PostcssCliResources } = require('@angular/cli/plugins/webpack'); +const { + NoEmitOnErrorsPlugin, + SourceMapDevToolPlugin, + NamedModulesPlugin, + DefinePlugin, + EnvironmentPlugin, + HashedModuleIdsPlugin, +} = require('webpack'); +const { + NamedLazyChunksWebpackPlugin, + SuppressExtractedTextChunksWebpackPlugin, + CleanCssWebpackPlugin, + BundleBudgetPlugin, + BaseHrefWebpackPlugin, + PostcssCliResources, +} = require('@angular/cli/plugins/webpack'); const { CommonsChunkPlugin, ModuleConcatenationPlugin } = require('webpack').optimize; const { LicenseWebpackPlugin } = require('license-webpack-plugin'); const { PurifyPlugin } = require('@angular-devkit/build-optimizer'); const { AngularCompilerPlugin } = require('@ngtools/webpack'); -const { compilerOptions: { paths } } = require('./tsconfig'); +const { + compilerOptions: { paths }, +} = require('./tsconfig'); const nodeModules = path.join(process.cwd(), 'node_modules'); const realNodeModules = fs.realpathSync(nodeModules); @@ -30,8 +46,8 @@ const projectRoot = process.cwd(); const maximumInlineSize = 10; const staging = process.env.LW_STAGING; -const postcssPlugins = (isProduction) => { - return function (loader) { +const postcssPlugins = isProduction => { + return function(loader) { return [ postcssImports({ resolve: (url, context) => { @@ -50,19 +66,17 @@ const postcssPlugins = (isProduction) => { loader.resolve(context, url, (err, result) => { if (err) { reject(err); - } - else { + } else { resolve(result); } }); - } - else { + } else { resolve(result); } }); }); }, - load: (filename) => { + load: filename => { return new Promise((resolve, reject) => { loader.fs.readFile(filename, (err, data) => { if (err) { @@ -73,14 +87,14 @@ const postcssPlugins = (isProduction) => { resolve(content); }); }); - } + }, }), postcssUrl({ filter: ({ url }) => url.startsWith('~'), url: ({ url }) => { const fullPath = path.join(projectRoot, 'node_modules', url.substr(1)); return path.relative(loader.context, fullPath).replace(/\\/g, '/'); - } + }, }), postcssUrl([ { @@ -90,62 +104,58 @@ const postcssPlugins = (isProduction) => { if (deployUrl.match(/:\/\//) || deployUrl.startsWith('/')) { // If deployUrl is absolute or root relative, ignore baseHref & use deployUrl as is. return `${deployUrl.replace(/\/$/, '')}${url}`; - } - else if (baseHref.match(/:\/\//)) { + } else if (baseHref.match(/:\/\//)) { // If baseHref contains a scheme, include it as is. - return baseHref.replace(/\/$/, '') + - `/${deployUrl}/${url}`.replace(/\/\/+/g, '/'); - } - else { + return baseHref.replace(/\/$/, '') + `/${deployUrl}/${url}`.replace(/\/\/+/g, '/'); + } else { // Join together base-href, deploy-url and the original URL. // Also dedupe multiple slashes into single ones. return `/${baseHref}/${deployUrl}/${url}`.replace(/\/\/+/g, '/'); } - } + }, }, { // TODO: inline .cur if not supporting IE (use browserslist to check) - filter: (asset) => { + filter: asset => { return maximumInlineSize > 0 && !asset.hash && !asset.absolutePath.endsWith('.cur'); }, url: 'inline', // NOTE: maxSize is in KB maxSize: maximumInlineSize, - fallback: 'rebase' + fallback: 'rebase', }, - { url: 'rebase' } + { url: 'rebase' }, ]), PostcssCliResources({ deployUrl: loader.loaders[loader.loaderIndex].options.ident == 'extracted' ? '' : deployUrl, loader, - filename: `[name]${getHashFormat(isProduction).file}.[ext]` + filename: `[name]${getHashFormat(isProduction).file}.[ext]`, }), - autoprefixer({ grid: true }) + autoprefixer({ grid: true }), ]; - } + }; }; function getEnvPath(production) { - let env = staging ? 'staging' : (production ? 'prod' : 'dev'); + let env = staging ? 'staging' : production ? 'prod' : 'dev'; return '../common/environments/environment.' + env + '.ts'; } function getAliases(production) { return { - '@app/env': path.resolve(__dirname, getEnvPath(production)) + '@app/env': path.resolve(__dirname, getEnvPath(production)), }; } function getHashFormat(production) { - return production ? - { - 'chunk': '.[chunkhash:20]', - 'extract': '.[contenthash:20]', - 'file': '.[hash:20]', - 'script': '.[hash:20]' - } - : - { chunk: '', extract: '', file: '.[hash:20]', script: '' }; + return production + ? { + chunk: '.[chunkhash:20]', + extract: '.[contenthash:20]', + file: '.[hash:20]', + script: '.[hash:20]', + } + : { chunk: '', extract: '', file: '.[hash:20]', script: '' }; } function isProduction(config) { @@ -156,122 +166,114 @@ function getDevRules() { return [ { test: /\.html$/, - loader: 'raw-loader' + loader: 'raw-loader', }, { test: /\.(eot|svg|cur)$/, loader: 'file-loader', options: { name: '[name].[hash:20].[ext]', - limit: 10000 - } + limit: 10000, + }, }, { test: /\.(jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/, loader: 'url-loader', options: { name: '[name].[hash:20].[ext]', - limit: 10000 - } + limit: 10000, + }, }, { - exclude: [ - path.join(process.cwd(), 'src/styles.sass') - ], + exclude: [path.join(process.cwd(), 'src/styles.sass')], test: /\.css$/, use: [ { - loader: 'raw-loader' + loader: 'raw-loader', }, { loader: 'postcss-loader', options: { ident: 'embedded', plugins: postcssPlugins(false), - sourceMap: true - } - } - ] + sourceMap: true, + }, + }, + ], }, { - exclude: [ - path.join(process.cwd(), 'src/styles.sass') - ], + exclude: [path.join(process.cwd(), 'src/styles.sass')], test: /\.scss$|\.sass$/, use: [ { - loader: 'raw-loader' + loader: 'raw-loader', }, { loader: 'postcss-loader', options: { ident: 'embedded', plugins: postcssPlugins(false), - sourceMap: true - } + sourceMap: true, + }, }, { loader: 'sass-loader', options: { sourceMap: true, precision: 8, - includePaths: [] - } - } - ] + includePaths: [], + }, + }, + ], }, { - include: [ - path.join(process.cwd(), 'src/styles.sass') - ], + include: [path.join(process.cwd(), 'src/styles.sass')], test: /\.css$/, use: [ 'style-loader', { - loader: 'raw-loader' + loader: 'raw-loader', }, { loader: 'postcss-loader', options: { ident: 'embedded', plugins: postcssPlugins(false), - sourceMap: true - } - } - ] + sourceMap: true, + }, + }, + ], }, { - include: [ - path.join(process.cwd(), 'src/styles.sass') - ], + include: [path.join(process.cwd(), 'src/styles.sass')], test: /\.scss$|\.sass$/, use: [ 'style-loader', { - loader: 'raw-loader' + loader: 'raw-loader', }, { loader: 'postcss-loader', options: { ident: 'embedded', plugins: postcssPlugins(false), - sourceMap: true - } + sourceMap: true, + }, }, { loader: 'sass-loader', options: { sourceMap: true, precision: 8, - includePaths: [] - } - } - ] + includePaths: [], + }, + }, + ], }, { test: /\.ts$/, - loader: '@ngtools/webpack' - } + loader: '@ngtools/webpack', + }, ]; } @@ -279,23 +281,23 @@ function getProdRules() { return [ { test: /\.html$/, - loader: 'raw-loader' + loader: 'raw-loader', }, { test: /\.(eot|svg|cur)$/, loader: 'file-loader', options: { name: '[name].[hash:20].[ext]', - limit: 10000 - } + limit: 10000, + }, }, { test: /\.(jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/, loader: 'url-loader', options: { name: '[name].[hash:20].[ext]', - limit: 10000 - } + limit: 10000, + }, }, { test: /\.js$/, @@ -303,92 +305,86 @@ function getProdRules() { { loader: 'cache-loader', options: { - cacheDirectory: path.join(process.cwd(), '/node_modules/@angular-devkit/build-optimizer/src/.cache') - } + cacheDirectory: path.join(process.cwd(), '/node_modules/@angular-devkit/build-optimizer/src/.cache'), + }, }, { loader: '@angular-devkit/build-optimizer/webpack-loader', options: { - sourceMap: false - } - } - ] + sourceMap: false, + }, + }, + ], }, { - exclude: [ - path.join(process.cwd(), 'src/styles.sass') - ], + exclude: [path.join(process.cwd(), 'src/styles.sass')], test: /\.css$/, use: [ { - loader: 'raw-loader' + loader: 'raw-loader', }, { loader: 'postcss-loader', options: { ident: 'embedded', plugins: postcssPlugins(true), - sourceMap: false - } - } - ] + sourceMap: false, + }, + }, + ], }, { - exclude: [ - path.join(process.cwd(), 'src/styles.sass') - ], + exclude: [path.join(process.cwd(), 'src/styles.sass')], test: /\.scss$|\.sass$/, use: [ { - loader: 'raw-loader' + loader: 'raw-loader', }, { loader: 'postcss-loader', options: { ident: 'embedded', plugins: postcssPlugins(true), - sourceMap: false - } + sourceMap: false, + }, }, { loader: 'sass-loader', options: { sourceMap: false, precision: 8, - includePaths: [] - } - } - ] + includePaths: [], + }, + }, + ], }, { - include: [ - path.join(process.cwd(), 'src/styles.sass') - ], + include: [path.join(process.cwd(), 'src/styles.sass')], test: /\.scss$|\.sass$/, loaders: ExtractTextPlugin.extract({ use: [ { - loader: 'raw-loader' + loader: 'raw-loader', }, { loader: 'postcss-loader', options: { ident: 'extracted', plugins: postcssPlugins(true), - sourceMap: false - } + sourceMap: false, + }, }, { loader: 'sass-loader', options: { sourceMap: false, precision: 8, - includePaths: [] - } - } + includePaths: [], + }, + }, ], - publicPath: '' - }) + publicPath: '', + }), }, { test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/, @@ -396,115 +392,100 @@ function getProdRules() { { loader: '@angular-devkit/build-optimizer/webpack-loader', options: { - sourceMap: false - } + sourceMap: false, + }, }, - '@ngtools/webpack' - ] - } + '@ngtools/webpack', + ], + }, ]; } module.exports = (_, config) => { const newConfig = { resolve: { - extensions: [ - '.ts', - '.js' - ], + extensions: ['.ts', '.js'], symlinks: true, - modules: [ - './src', - './node_modules' - ], + modules: ['./src', './node_modules'], alias: { ...rxPaths(), - ...getAliases(isProduction(config)) + ...getAliases(isProduction(config)), }, - mainFields: [ - 'browser', - 'module', - 'main' - ] + mainFields: ['browser', 'module', 'main'], }, resolveLoader: { - modules: [ - './node_modules' - ], + modules: ['./node_modules'], alias: { ...rxPaths(), - ...getAliases(isProduction(config)) - } + ...getAliases(isProduction(config)), + }, }, entry: { - main: [ - './src/main.ts' - ], - polyfills: [ - './src/polyfills.ts' - ], - styles: [ - './src/styles.sass' - ] + main: ['./src/main.ts'], + polyfills: ['./src/polyfills.ts'], + styles: ['./src/styles.sass'], }, output: { path: path.join(process.cwd(), 'dist'), filename: '[name]' + (isProduction(config) ? '.[chunkhash:20]' : '') + '.bundle.js', chunkFilename: '[id]' + (isProduction(config) ? '.[chunkhash:20]' : '') + '.chunk.js', - crossOriginLoading: false + crossOriginLoading: false, }, module: { - rules: isProduction(config) ? getProdRules() : getDevRules() + rules: isProduction(config) ? getProdRules() : getDevRules(), }, plugins: [ new DefinePlugin({ WEBPACK_CONFIG: { - COMMIT_HASH: JSON.stringify(execSync('git rev-parse --short HEAD').toString().trim()), - VERSION: JSON.stringify(require('./package.json').version) - } + COMMIT_HASH: JSON.stringify( + execSync('git rev-parse --short HEAD') + .toString() + .trim(), + ), + VERSION: JSON.stringify(require('./package.json').version), + }, }), new NoEmitOnErrorsPlugin(), - new CopyWebpackPlugin([ - { - context: 'src', - to: '', - from: { - glob: 'assets/**/*', - dot: true - } - }, - { - context: 'src', - to: '', - from: { - glob: 'favicon.ico', - dot: true - } - }, + new CopyWebpackPlugin( + [ + { + context: 'src', + to: '', + from: { + glob: 'assets/**/*', + dot: true, + }, + }, + { + context: 'src', + to: '', + from: { + glob: 'favicon.ico', + dot: true, + }, + }, + { + context: 'src', + to: '', + from: { + glob: 'firebase-messaging-sw.js', + dot: true, + }, + }, + { + context: 'src', + to: '', + from: { + glob: 'manifest.json', + dot: true, + }, + }, + ], { - context: 'src', - to: '', - from: { - glob: 'firebase-messaging-sw.js', - dot: true - } + ignore: ['.gitkeep', '**/.DS_Store', '**/Thumbs.db'], + debug: 'warning', }, - { - context: 'src', - to: '', - from: { - glob: 'manifest.json', - dot: true - } - } - ], { - ignore: [ - '.gitkeep', - '**/.DS_Store', - '**/Thumbs.db' - ], - debug: 'warning' - }), + ), new ProgressPlugin(), // new CircularDependencyPlugin({ // exclude: /(\\|\/)node_modules(\\|\/)/, @@ -520,11 +501,13 @@ module.exports = (_, config) => { inject: true, compile: true, favicon: false, - minify: isProduction(config) ? { - caseSensitive: true, - collapseWhitespace: true, - keepClosingSlash: true - } : false, + minify: isProduction(config) + ? { + caseSensitive: true, + collapseWhitespace: true, + keepClosingSlash: true, + } + : false, cache: true, showErrors: true, chunks: 'all', @@ -536,42 +519,34 @@ module.exports = (_, config) => { let rightIndex = entryPoints.indexOf(right.names[0]); if (leftIndex > rightIndex) { return 1; - } - else if (leftIndex < rightIndex) { + } else if (leftIndex < rightIndex) { return -1; - } - else { + } else { return 0; } - } + }, }), new BaseHrefWebpackPlugin({}), new CommonsChunkPlugin({ - name: [ - 'inline' - ], - minChunks: null + name: ['inline'], + minChunks: null, }), new CommonsChunkPlugin({ - name: [ - 'vendor' - ], - minChunks: (module) => { - return module.resource - && (module.resource.startsWith(nodeModules) - || module.resource.startsWith(genDirNodeModules) - || module.resource.startsWith(realNodeModules)); + name: ['vendor'], + minChunks: module => { + return ( + module.resource && + (module.resource.startsWith(nodeModules) || + module.resource.startsWith(genDirNodeModules) || + module.resource.startsWith(realNodeModules)) + ); }, - chunks: [ - 'main' - ] + chunks: ['main'], }), new CommonsChunkPlugin({ - name: [ - 'main' - ], + name: ['main'], minChunks: 2, - async: 'common' + async: 'common', }), new NamedModulesPlugin({}), new AngularCompilerPlugin({ @@ -583,11 +558,11 @@ module.exports = (_, config) => { compilerOptions: { paths: { ...paths, - '@app/env': [getEnvPath(isProduction(config))] + '@app/env': [getEnvPath(isProduction(config))], }, - sourceMap: !isProduction(config) - } - }) + sourceMap: !isProduction(config), + }, + }), ], node: { fs: 'empty', @@ -595,82 +570,73 @@ module.exports = (_, config) => { crypto: true, tls: 'empty', net: 'empty', - process: true + process: true, }, devServer: { - historyApiFallback: true - } + historyApiFallback: true, + }, }; if (isProduction(config)) { newConfig.plugins.push( new ExtractTextPlugin({ - 'filename': '[name].[contenthash:20].bundle.css' + filename: '[name].[contenthash:20].bundle.css', }), new SuppressExtractedTextChunksWebpackPlugin(), new CleanCssWebpackPlugin(), new EnvironmentPlugin({ - 'NODE_ENV': 'production' + NODE_ENV: 'production', }), new HashedModuleIdsPlugin({ - 'hashFunction': 'md5', - 'hashDigest': 'base64', - 'hashDigestLength': 4 + hashFunction: 'md5', + hashDigest: 'base64', + hashDigestLength: 4, }), new ModuleConcatenationPlugin({}), new BundleBudgetPlugin({}), new LicenseWebpackPlugin({ - 'licenseFilenames': [ - 'LICENSE', - 'LICENSE.md', - 'LICENSE.txt', - 'license', - 'license.md', - 'license.txt' - ], - 'perChunkOutput': false, - 'outputTemplate': path.join(process.cwd(), 'node_modules/license-webpack-plugin/output.template.ejs'), - 'outputFilename': '3rdpartylicenses.txt', - 'suppressErrors': true, - 'includePackagesWithoutLicense': false, - 'abortOnUnacceptableLicense': false, - 'addBanner': false, - 'bannerTemplate': '/*! 3rd party license information is available at <%- filename %> */', - 'includedChunks': [], - 'excludedChunks': [], - 'additionalPackages': [], - 'modulesDirectories': [ - 'node_modules' - ], - 'pattern': /^(MIT|ISC|BSD.*)$/ + licenseFilenames: ['LICENSE', 'LICENSE.md', 'LICENSE.txt', 'license', 'license.md', 'license.txt'], + perChunkOutput: false, + outputTemplate: path.join(process.cwd(), 'node_modules/license-webpack-plugin/output.template.ejs'), + outputFilename: '3rdpartylicenses.txt', + suppressErrors: true, + includePackagesWithoutLicense: false, + abortOnUnacceptableLicense: false, + addBanner: false, + bannerTemplate: '/*! 3rd party license information is available at <%- filename %> */', + includedChunks: [], + excludedChunks: [], + additionalPackages: [], + modulesDirectories: ['node_modules'], + pattern: /^(MIT|ISC|BSD.*)$/, }), new PurifyPlugin(), new UglifyJsPlugin({ - 'test': /\.js(\?.*)?$/i, - 'extractComments': false, - 'sourceMap': false, - 'cache': true, - 'parallel': true, - 'uglifyOptions': { - 'output': { - 'ascii_only': true, - 'comments': false, - 'webkit': true + test: /\.js(\?.*)?$/i, + extractComments: false, + sourceMap: false, + cache: true, + parallel: true, + uglifyOptions: { + output: { + ascii_only: true, + comments: false, + webkit: true, }, - 'ecma': 5, - 'warnings': false, - 'ie8': false, - 'mangle': { - 'safari10': true + ecma: 5, + warnings: false, + ie8: false, + mangle: { + safari10: true, }, - 'compress': { - 'typeofs': false, - 'inline': 3, - 'pure_getters': true, - 'passes': 3 - } - } - }) + compress: { + typeofs: false, + inline: 3, + pure_getters: true, + passes: 3, + }, + }, + }), ); } else { newConfig.plugins.push( @@ -678,8 +644,8 @@ module.exports = (_, config) => { filename: '[file].map[query]', moduleFilenameTemplate: '[resource-path]', fallbackModuleFilenameTemplate: '[resource-path]?[hash]', - sourceRoot: 'webpack:///' - }) + sourceRoot: 'webpack:///', + }), ); } diff --git a/packages/lightwallet/jest-global-mocks.ts b/packages/lightwallet/jest-global-mocks.ts index cc18e0fe12..17b4b734c2 100644 --- a/packages/lightwallet/jest-global-mocks.ts +++ b/packages/lightwallet/jest-global-mocks.ts @@ -6,32 +6,32 @@ nock(ENV.mwsUrl) .filteringPath(/\?r=[0-9]+/g, '') .persist() .get('/v1/rates') - .reply(200, [{ 'code': 'USD', 'name': 'US Dollar', 'rate': 1 }]); + .reply(200, [{ code: 'USD', name: 'US Dollar', rate: 1 }]); global['CSS'] = null; const mock = () => { let storage = {}; return { - getItem: key => key in storage ? storage[key] : null, - setItem: (key, value) => storage[key] = value || '', + getItem: key => (key in storage ? storage[key] : null), + setItem: (key, value) => (storage[key] = value || ''), removeItem: key => delete storage[key], - clear: () => storage = {} + clear: () => (storage = {}), }; }; Object.defineProperty(window, 'localStorage', { value: mock() }); Object.defineProperty(window, 'sessionStorage', { value: mock() }); Object.defineProperty(document, 'doctype', { - value: '' + value: '', }); Object.defineProperty(window, 'getComputedStyle', { value: () => { return { display: 'none', - appearance: ['-webkit-appearance'] + appearance: ['-webkit-appearance'], }; - } + }, }); /** * ISSUE: https://github.com/angular/material2/issues/7101 @@ -41,7 +41,7 @@ Object.defineProperty(document.body.style, 'transform', { value: () => { return { enumerable: true, - configurable: true + configurable: true, }; - } + }, }); diff --git a/packages/lightwallet/mobile/e2e/app.e2e-spec.ts b/packages/lightwallet/mobile/e2e/app.e2e-spec.ts index 6056bc9aad..45f8432b18 100644 --- a/packages/lightwallet/mobile/e2e/app.e2e-spec.ts +++ b/packages/lightwallet/mobile/e2e/app.e2e-spec.ts @@ -5,12 +5,13 @@ export const TEST_WALLET_ALIAS = '@ibby-demo-mac'; export const TEST_WALLET_NAME = 'Personal wallet'; export const EC: ProtractorExpectedConditions = new ProtractorExpectedConditions(browser); - describe('[Mobile] Onboarding', () => { - beforeAll(() => { browser.get('/'); - browser.driver.manage().window().maximize(); + browser.driver + .manage() + .window() + .maximize(); // Clickblock prevents us from making certain click actions, so let's get rid of it browser.executeScript(`document.querySelector('.click-block').remove()`); @@ -65,7 +66,6 @@ describe('[Mobile] Onboarding', () => { }); describe('> Tour', () => { - let nextButtonEl; it('get started button should go to tour page', async () => { @@ -80,7 +80,7 @@ describe('[Mobile] Onboarding', () => { it('should have a link to the import page', async () => { const buttonEl = element(by.css('view-tour ion-header button[navpush=ImportView]')); - expect((await buttonEl.getText()).toLowerCase()).toContain('restore'); + expect((await buttonEl.getText()).toLowerCase()).toContain('restore'); expect(buttonEl.isDisplayed()).toBeTruthy(); expect(buttonEl.isEnabled()).toBeTruthy(); }); @@ -123,11 +123,9 @@ describe('[Mobile] Onboarding', () => { browser.wait(EC.urlContains('unlock')); expect(browser.getCurrentUrl()).toContain('unlock'); }); - }); describe('> Unlock view', () => { - let rootEl; let inviteInputEl, nextButtonEl, backButtonEl, errorEl; @@ -180,11 +178,9 @@ describe('[Mobile] Onboarding', () => { expect(browser.getCurrentUrl()).not.toContain('unlock'); expect(browser.getCurrentUrl()).toContain('tour'); }); - }); describe('> Import view', () => { - beforeAll(() => { const restoreButtonEl = element(by.css('view-tour ion-header button[navpush=ImportView]')); restoreButtonEl.click(); @@ -201,7 +197,7 @@ describe('[Mobile] Onboarding', () => { }); it('should show the file tab when clicking on segment button', () => { - expect(element(by.css('view-import .file')).isDisplayed()).toBeTruthy(); + expect(element(by.css('view-import .file')).isDisplayed()).toBeTruthy(); }); }); @@ -230,8 +226,8 @@ describe('[Mobile] Onboarding', () => { }); it('should have a mnemonic textarea', () => { - mnemonicEl = rootEl.element(by.css('.mnemonic-input textarea')); - expect(mnemonicEl.isDisplayed()).toBeTruthy(); + mnemonicEl = rootEl.element(by.css('.mnemonic-input textarea')); + expect(mnemonicEl.isDisplayed()).toBeTruthy(); }); it('should detect invalid mnemonic', () => { @@ -252,7 +248,5 @@ describe('[Mobile] Onboarding', () => { expect(rootEl.isPresent()).toBeFalsy(); }); }); - }); - }); diff --git a/packages/lightwallet/mobile/e2e/community.e2e-spec.ts b/packages/lightwallet/mobile/e2e/community.e2e-spec.ts index 5fbbb73d5e..4871875a90 100644 --- a/packages/lightwallet/mobile/e2e/community.e2e-spec.ts +++ b/packages/lightwallet/mobile/e2e/community.e2e-spec.ts @@ -3,10 +3,7 @@ import { browser, by, ElementFinder } from 'protractor'; import { EC } from './app.e2e-spec'; describe('[Mobile] Community', () => { - - let transact: Transact, - communityViewEl: ElementFinder, - headerEl: ElementFinder; + let transact: Transact, communityViewEl: ElementFinder, headerEl: ElementFinder; beforeAll(async () => { transact = new Transact(); diff --git a/packages/lightwallet/mobile/e2e/receive.e2e-spec.ts b/packages/lightwallet/mobile/e2e/receive.e2e-spec.ts index d70131de6e..a4522633cf 100644 --- a/packages/lightwallet/mobile/e2e/receive.e2e-spec.ts +++ b/packages/lightwallet/mobile/e2e/receive.e2e-spec.ts @@ -3,9 +3,7 @@ import { browser, by, ElementFinder } from 'protractor'; import { EC, TEST_WALLET_ALIAS } from './app.e2e-spec'; describe('[Mobile] Receive', () => { - let transact: Transact, - receiveViewEl: ElementFinder, - qrCodeEl: ElementFinder; + let transact: Transact, receiveViewEl: ElementFinder, qrCodeEl: ElementFinder; beforeAll(async () => { transact = new Transact(); diff --git a/packages/lightwallet/mobile/e2e/send-flow.e2e-spec.ts b/packages/lightwallet/mobile/e2e/send-flow.e2e-spec.ts index 1f17a0d4f2..73026a7ee5 100644 --- a/packages/lightwallet/mobile/e2e/send-flow.e2e-spec.ts +++ b/packages/lightwallet/mobile/e2e/send-flow.e2e-spec.ts @@ -3,8 +3,7 @@ import { EC } from './app.e2e-spec'; import { Transact } from './transact.po'; describe('[Mobile] Send flow', () => { - let transact: Transact, - sendViewEl; + let transact: Transact, sendViewEl; beforeAll(async () => { transact = new Transact(); @@ -81,9 +80,5 @@ describe('[Mobile] Send flow', () => { }); }); - describe('> Classic send', () => { - - }); - - + describe('> Classic send', () => {}); }); diff --git a/packages/lightwallet/mobile/e2e/transact.po.ts b/packages/lightwallet/mobile/e2e/transact.po.ts index 4e2470bbe0..26bf915f88 100644 --- a/packages/lightwallet/mobile/e2e/transact.po.ts +++ b/packages/lightwallet/mobile/e2e/transact.po.ts @@ -2,7 +2,6 @@ import { browser, protractor, element, by } from 'protractor'; import { EC } from './app.e2e-spec'; export class Transact { - getRootEl() { return element(by.css('view-transact')); } @@ -20,9 +19,9 @@ export class Transact { } selectTab(index: number) { - const el = this.getTabButtonsEl().element(by.css(`.tab-button:nth-child(${ ++index })`)); + const el = this.getTabButtonsEl().element(by.css(`.tab-button:nth-child(${++index})`)); browser.wait(EC.visibilityOf(el), 3000, 'Cant click on tab button'); - return el.click(); + return el.click(); } getSendView() { @@ -36,5 +35,4 @@ export class Transact { getCommunityView() { return this.getRootEl().element(by.css('view-network')); } - } diff --git a/packages/lightwallet/mobile/e2e/wallet-details.e2e-spec.ts b/packages/lightwallet/mobile/e2e/wallet-details.e2e-spec.ts index c4145e1d29..79d43bf021 100644 --- a/packages/lightwallet/mobile/e2e/wallet-details.e2e-spec.ts +++ b/packages/lightwallet/mobile/e2e/wallet-details.e2e-spec.ts @@ -3,15 +3,16 @@ import { EC, TEST_WALLET_ALIAS, TEST_WALLET_NAME } from './app.e2e-spec'; import { Transact } from './transact.po'; describe('[Mobile] Wallet details', () => { - - let transact: Transact, - rootEl; + let transact: Transact, rootEl; beforeAll(async () => { transact = new Transact(); transact.selectTab(0); browser.wait(EC.visibilityOf(transact.getRootEl())); - await transact.getRootEl().element(by.css('ion-list.wallets button[ion-item]')).click(); + await transact + .getRootEl() + .element(by.css('ion-list.wallets button[ion-item]')) + .click(); rootEl = element(by.css('wallet-details-view')); browser.wait(EC.visibilityOf(rootEl), 3000, 'Element was not visible in 3s'); }); @@ -59,6 +60,4 @@ describe('[Mobile] Wallet details', () => { expect(el.isEnabled()).toBeTruthy(); }); }); - - }); diff --git a/packages/lightwallet/mobile/e2e/wallets.e2e-spec.ts b/packages/lightwallet/mobile/e2e/wallets.e2e-spec.ts index 0ed3aac3b0..75fbf26080 100644 --- a/packages/lightwallet/mobile/e2e/wallets.e2e-spec.ts +++ b/packages/lightwallet/mobile/e2e/wallets.e2e-spec.ts @@ -68,5 +68,4 @@ describe('[Mobile] Wallets view', () => { expect(walletItemLabelEl.getText()).toContain(TEST_WALLET_ALIAS); }); }); - }); diff --git a/packages/lightwallet/mobile/generator/README.md b/packages/lightwallet/mobile/generator/README.md index 5718ffd5d9..d5e9ac87e9 100644 --- a/packages/lightwallet/mobile/generator/README.md +++ b/packages/lightwallet/mobile/generator/README.md @@ -6,6 +6,7 @@ Expample: `node run.js /some/awesome-stuff` will create following structure: + ``` src/ app/ diff --git a/packages/lightwallet/mobile/generator/run.js b/packages/lightwallet/mobile/generator/run.js index 3435b12e0c..2df7162fce 100644 --- a/packages/lightwallet/mobile/generator/run.js +++ b/packages/lightwallet/mobile/generator/run.js @@ -1,47 +1,50 @@ -var fs = require('fs'); +var fs = require('fs'); var path = require('path'); var mkdirp = require('mkdirp'); var dirName = process.argv[2]; if (!dirName) { - throw('ERROR: no module name provided') + throw 'ERROR: no module name provided'; } -var dirPath = path.normalize(__dirname+'/../src/pages/'+dirName); +var dirPath = path.normalize(__dirname + '/../src/pages/' + dirName); if (fs.existsSync(dirPath)) { - throw('ERROR: module exists!'); + throw 'ERROR: module exists!'; } moduleName = ''; -var fileName = dirName.split('/').pop().toLowerCase(); +var fileName = dirName + .split('/') + .pop() + .toLowerCase(); fileName.split('-').forEach(function(word) { - moduleName += word.charAt(0).toUpperCase() + word.slice(1); + moduleName += word.charAt(0).toUpperCase() + word.slice(1); }); -var componentName = moduleName+'View'; +var componentName = moduleName + 'View'; var interpolate = function(content) { - content = content.replace(/\$\$componentName\$\$/gi, componentName); - content = content.replace(/\$\$moduleName\$\$/gi, moduleName); - content = content.replace(/\$\$fileName\$\$/gi, fileName); - return content; + content = content.replace(/\$\$componentName\$\$/gi, componentName); + content = content.replace(/\$\$moduleName\$\$/gi, moduleName); + content = content.replace(/\$\$fileName\$\$/gi, fileName); + return content; }; -console.log("generating module '"+moduleName+"' in "+dirPath); +console.log("generating module '" + moduleName + "' in " + dirPath); mkdirp(dirPath, function(err) { - if (err) throw err; + if (err) throw err; - var content = fs.readFileSync(__dirname+'/templates/view.html', 'utf8'); - fs.writeFileSync(dirPath+'/'+fileName+'.html', interpolate(content)); + var content = fs.readFileSync(__dirname + '/templates/view.html', 'utf8'); + fs.writeFileSync(dirPath + '/' + fileName + '.html', interpolate(content)); - var content = fs.readFileSync(__dirname+'/templates/module.ts', 'utf8'); - fs.writeFileSync(dirPath+'/'+fileName+'.module.ts', interpolate(content)); + var content = fs.readFileSync(__dirname + '/templates/module.ts', 'utf8'); + fs.writeFileSync(dirPath + '/' + fileName + '.module.ts', interpolate(content)); - var content = fs.readFileSync(__dirname+'/templates/view.ts', 'utf8'); - fs.writeFileSync(dirPath+'/'+fileName+'.ts', interpolate(content)); + var content = fs.readFileSync(__dirname + '/templates/view.ts', 'utf8'); + fs.writeFileSync(dirPath + '/' + fileName + '.ts', interpolate(content)); - var content = fs.readFileSync(__dirname+'/templates/style.scss', 'utf8'); - fs.writeFileSync(dirPath+'/'+fileName+'.scss', interpolate(content)); + var content = fs.readFileSync(__dirname + '/templates/style.scss', 'utf8'); + fs.writeFileSync(dirPath + '/' + fileName + '.scss', interpolate(content)); - console.log('success'); + console.log('success'); }); diff --git a/packages/lightwallet/mobile/generator/templates/module.ts b/packages/lightwallet/mobile/generator/templates/module.ts index 5f0bc94ece..10c97ef063 100644 --- a/packages/lightwallet/mobile/generator/templates/module.ts +++ b/packages/lightwallet/mobile/generator/templates/module.ts @@ -3,11 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { $$componentName$$ } from './$$fileName$$'; @NgModule({ - declarations: [ - $$componentName$$, - ], - imports: [ - IonicPageModule.forChild($$componentName$$), - ], + declarations: [$$componentName$$], + imports: [IonicPageModule.forChild($$componentName$$)], }) export class $$moduleName$$Module {} diff --git a/packages/lightwallet/mobile/generator/templates/view.ts b/packages/lightwallet/mobile/generator/templates/view.ts index 576e0c273d..5994a56c63 100644 --- a/packages/lightwallet/mobile/generator/templates/view.ts +++ b/packages/lightwallet/mobile/generator/templates/view.ts @@ -1,24 +1,15 @@ import { Component } from '@angular/core'; import { IonicPage, NavController, NavParams } from 'ionic-angular'; - @IonicPage() @Component({ selector: 'view-$$fileName$$', templateUrl: '$$fileName$$.html', }) export class $$componentName$$ { - - - constructor( - private navCtrl: NavController, - private navParams: NavParams - ) { - - } + constructor(private navCtrl: NavController, private navParams: NavParams) {} ionViewDidLoad() { //do something here } - } diff --git a/packages/lightwallet/mobile/src/app/app.component.ts b/packages/lightwallet/mobile/src/app/app.component.ts index 2a5a68ad7c..b121321ee3 100644 --- a/packages/lightwallet/mobile/src/app/app.component.ts +++ b/packages/lightwallet/mobile/src/app/app.component.ts @@ -19,31 +19,30 @@ import { Events, ModalController, Nav, Platform } from 'ionic-angular'; import { getQueryParam } from '@merit/common/utils/url'; @Component({ - templateUrl: 'app.html' + templateUrl: 'app.html', }) export class MeritLightWallet { - - @ViewChild(Nav) nav: Nav; + @ViewChild(Nav) + nav: Nav; private authorized: boolean; - constructor(private platform: Platform, - private statusBar: StatusBar, - private splashScreen: SplashScreen, - private profileService: ProfileService, - private logger: LoggerService, - private modalCtrl: ModalController, - private appService: AppSettingsService, - private persistenceService: PersistenceService, - private deepLinkService: DeepLinkService, - private easyReceiveService: EasyReceiveService, - private events: Events, - private keyboard: Keyboard, - private addressService: AddressService, - ) { - } + constructor( + private platform: Platform, + private statusBar: StatusBar, + private splashScreen: SplashScreen, + private profileService: ProfileService, + private logger: LoggerService, + private modalCtrl: ModalController, + private appService: AppSettingsService, + private persistenceService: PersistenceService, + private deepLinkService: DeepLinkService, + private easyReceiveService: EasyReceiveService, + private events: Events, + private keyboard: Keyboard, + private addressService: AddressService, + ) {} async ngOnInit() { - if (await this.persistenceService.isPinEnabled()) { this.modalCtrl.create('PinLockView').present(); } @@ -54,8 +53,8 @@ export class MeritLightWallet { }); this.platform.resume.subscribe(() => { - if (Date.now() - pausedAt > 1*60*1000) { - this.persistenceService.isPinEnabled().then((isEnabled) => { + if (Date.now() - pausedAt > 1 * 60 * 1000) { + this.persistenceService.isPinEnabled().then(isEnabled => { if (isEnabled) this.modalCtrl.create('PinLockView').present(); }); } @@ -69,7 +68,7 @@ export class MeritLightWallet { const appInfo: any = await this.appService.getInfo(); this.logger.info(` - platform ready (${ readySource }): -v ${ appInfo.version } # ${ appInfo.commitHash } + platform ready (${readySource}): -v ${appInfo.version} # ${appInfo.commitHash} `); this.registerMwcErrorHandler(); @@ -123,7 +122,6 @@ export class MeritLightWallet { } } - /** * Get Easy send params eiter from url or from branch */ @@ -159,11 +157,10 @@ export class MeritLightWallet { const invitation = this.parseInviteParams(); if (invitation && !this.authorized) { - await this.nav.setRoot('UnlockView', { ...invitation }); } else { const receipt = await this.loadEasySend(); - if (receipt && !this.authorized) { + if (receipt && !this.authorized) { await this.nav.setRoot('UnlockView', { gbs: getQueryParam('source', search).toLowerCase() === 'gbs' }); } else { await this.nav.setRoot(this.authorized ? 'TransactView' : 'OnboardingView'); @@ -179,5 +176,4 @@ export class MeritLightWallet { this.nav.setRoot('NoSessionView'); }); } - } diff --git a/packages/lightwallet/mobile/src/app/app.module.ts b/packages/lightwallet/mobile/src/app/app.module.ts index 9c2794199b..59af4533db 100644 --- a/packages/lightwallet/mobile/src/app/app.module.ts +++ b/packages/lightwallet/mobile/src/app/app.module.ts @@ -56,7 +56,7 @@ export function getProviders() { EmailNotificationsService, AddressService, TouchIdService, - VaultsService + VaultsService, ]; } @@ -75,7 +75,7 @@ export function getIonicNativePlugins() { SocialSharing, SplashScreen, StatusBar, - TouchID + TouchID, ]; } @@ -88,9 +88,7 @@ export function loadConfigs(appService) { } @NgModule({ - declarations: [ - MeritLightWallet - ], + declarations: [MeritLightWallet], imports: [ BrowserModule, MomentModule, @@ -101,22 +99,20 @@ export function loadConfigs(appService) { preloadModules: true, tabsHideOnSubPages: true, backButtonText: '', - autocomplete: 'off' + autocomplete: 'off', }), TranslateModule.forRoot({ loader: { provide: TranslateLoader, useFactory: createTranslateLoader, - deps: [HttpClient] - } + deps: [HttpClient], + }, }), IonicStorageModule.forRoot(), - CommonProvidersModule.forRoot() + CommonProvidersModule.forRoot(), ], bootstrap: [IonicApp], - entryComponents: [ - MeritLightWallet - ], + entryComponents: [MeritLightWallet], providers: [ ...getProviders(), ...getIonicNativePlugins(), @@ -125,9 +121,8 @@ export function loadConfigs(appService) { provide: APP_INITIALIZER, useFactory: loadConfigs, deps: [AppSettingsService], - multi: true - } - ] + multi: true, + }, + ], }) -export class AppModule { -} +export class AppModule {} diff --git a/packages/lightwallet/mobile/src/app/community/network/network.module.ts b/packages/lightwallet/mobile/src/app/community/network/network.module.ts index 758d5ba52f..22a17d4a10 100644 --- a/packages/lightwallet/mobile/src/app/community/network/network.module.ts +++ b/packages/lightwallet/mobile/src/app/community/network/network.module.ts @@ -2,19 +2,11 @@ import { NgModule } from '@angular/core'; import { MomentModule } from 'ngx-moment'; import { IonicPageModule } from 'ionic-angular'; import { NetworkView } from '@merit/mobile/app/community/network/network'; -import { ClipModule } from 'ng2-clip' +import { ClipModule } from 'ng2-clip'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; @NgModule({ - declarations: [ - NetworkView, - ], - imports: [ - MomentModule, - ClipModule, - CommonPipesModule, - IonicPageModule.forChild(NetworkView), - ] + declarations: [NetworkView], + imports: [MomentModule, ClipModule, CommonPipesModule, IonicPageModule.forChild(NetworkView)], }) -export class NetworkViewModule { -} +export class NetworkViewModule {} diff --git a/packages/lightwallet/mobile/src/app/community/network/network.ts b/packages/lightwallet/mobile/src/app/community/network/network.ts index efe9dafb2e..f00ef753c7 100644 --- a/packages/lightwallet/mobile/src/app/community/network/network.ts +++ b/packages/lightwallet/mobile/src/app/community/network/network.ts @@ -14,47 +14,46 @@ import { ToastControllerService, IMeritToastConfig } from '@merit/common/service templateUrl: 'network.html', }) export class NetworkView { - loading: boolean; refreshing: boolean; wallets: MeritWalletClient[]; - network:{ - communitySize: number, - miningRewards: number, - growthRewards: number + network: { + communitySize: number; + miningRewards: number; + growthRewards: number; wallets: Array<{ - name: string, - referralAddress: string, - alias: string, - confirmed: boolean, - communitySize: number - miningRewards: number, - growthRewards: number, - color: string - }> + name: string; + referralAddress: string; + alias: string; + confirmed: boolean; + communitySize: number; + miningRewards: number; + growthRewards: number; + color: string; + }>; } = { communitySize: 0, miningRewards: 0, growthRewards: 0, - wallets: [] + wallets: [], }; rankData: { - totalAnv: number, - totalProbability: number, - bestRank: number, - bestPercentile: number, - percentileStr: string, - estimateStr: string + totalAnv: number; + totalProbability: number; + bestRank: number; + bestPercentile: number; + percentileStr: string; + estimateStr: string; } = { totalAnv: 0, totalProbability: 0, bestRank: 0, bestPercentile: 0, percentileStr: '', - estimateStr: '' + estimateStr: '', }; activeUnlockRequests: number; @@ -71,7 +70,7 @@ export class NetworkView { private unlockRequestService: UnlockRequestService, private logger: LoggerService, private events: Events, - platformService: PlatformService + platformService: PlatformService, ) { this.shareButtonAvailable = platformService.isCordova; } @@ -98,7 +97,6 @@ export class NetworkView { refresher.complete(); } - private async refreshData() { this.refreshing = true; const refreshCommunity = async () => { @@ -133,7 +131,7 @@ export class NetworkView { bestRank: 0, bestPercentile: 0, percentileStr: '', - estimateStr: '' + estimateStr: '', }; const addresses = this.wallets.filter(w => w.confirmed).map(w => w.getRootAddress().toString()); if (addresses.length) { @@ -142,21 +140,23 @@ export class NetworkView { rankData.totalAnv += walletRank.anv; rankData.totalProbability += walletRank.anvpercent; if (!rankData.bestRank || rankData.bestRank > walletRank.rank) rankData.bestRank = walletRank.rank; - if (!rankData.bestPercentile || rankData.bestPercentile < walletRank.percentile) rankData.bestPercentile = walletRank.percentile; + if (!rankData.bestPercentile || rankData.bestPercentile < walletRank.percentile) + rankData.bestPercentile = walletRank.percentile; }); - rankData.percentileStr = (rankData.bestPercentile > 20) - ? 'top '+Math.max(Math.round(100 - rankData.bestPercentile), 1)+'%' - : 'bottom '+Math.max(Math.round(rankData.bestPercentile),1)+'%'; + rankData.percentileStr = + rankData.bestPercentile > 20 + ? 'top ' + Math.max(Math.round(100 - rankData.bestPercentile), 1) + '%' + : 'bottom ' + Math.max(Math.round(rankData.bestPercentile), 1) + '%'; - const estimateMinutesPerReward = 1/(rankData.totalProbability*this.REWARDS_PER_BLOCK); + const estimateMinutesPerReward = 1 / (rankData.totalProbability * this.REWARDS_PER_BLOCK); if (estimateMinutesPerReward < 120) { - rankData.estimateStr = `Every ${Math.ceil(estimateMinutesPerReward)}min` + rankData.estimateStr = `Every ${Math.ceil(estimateMinutesPerReward)}min`; } else if (estimateMinutesPerReward < 2880) { - rankData.estimateStr = `Every ${ Math.ceil(estimateMinutesPerReward/60)}hrs` + rankData.estimateStr = `Every ${Math.ceil(estimateMinutesPerReward / 60)}hrs`; } else { - rankData.estimateStr = `Every ${ Math.ceil(estimateMinutesPerReward/1440)}days` + rankData.estimateStr = `Every ${Math.ceil(estimateMinutesPerReward / 1440)}days`; } } @@ -164,7 +164,6 @@ export class NetworkView { } private async loadCommunityInfo() { - try { this.wallets = await this.profileService.getWallets(); @@ -180,7 +179,6 @@ export class NetworkView { this.logger.warn(err); this.toastCtrl.error(err.text || 'Unknown error'); } - } private async loadRequestsInfo() { @@ -192,6 +190,4 @@ export class NetworkView { this.toastCtrl.error(err.text || 'Unknown error'); } } - } - diff --git a/packages/lightwallet/mobile/src/app/community/network/send-invite-amount/send-invite-amount.module.ts b/packages/lightwallet/mobile/src/app/community/network/send-invite-amount/send-invite-amount.module.ts index e42e2b0f51..ee5b6c3cd9 100644 --- a/packages/lightwallet/mobile/src/app/community/network/send-invite-amount/send-invite-amount.module.ts +++ b/packages/lightwallet/mobile/src/app/community/network/send-invite-amount/send-invite-amount.module.ts @@ -1,17 +1,11 @@ import { NgModule } from '@angular/core'; -import { IonicPageModule} from 'ionic-angular'; +import { IonicPageModule } from 'ionic-angular'; import { SendInviteAmountView } from '@merit/mobile/app/community/network/send-invite-amount/send-invite-amount'; import { ComponentsModule } from '@merit/mobile/components/components.module'; import { ClipModule } from 'ng2-clip'; @NgModule({ - declarations: [ - SendInviteAmountView, - ], - imports: [ - IonicPageModule.forChild(SendInviteAmountView), - ComponentsModule, - ClipModule - ] + declarations: [SendInviteAmountView], + imports: [IonicPageModule.forChild(SendInviteAmountView), ComponentsModule, ClipModule], }) -export class SendInviteAmountViewModule { } +export class SendInviteAmountViewModule {} diff --git a/packages/lightwallet/mobile/src/app/community/network/send-invite-amount/send-invite-amount.ts b/packages/lightwallet/mobile/src/app/community/network/send-invite-amount/send-invite-amount.ts index 3e706b030f..dedbed1389 100644 --- a/packages/lightwallet/mobile/src/app/community/network/send-invite-amount/send-invite-amount.ts +++ b/packages/lightwallet/mobile/src/app/community/network/send-invite-amount/send-invite-amount.ts @@ -17,21 +17,20 @@ import { ModalController, NavController, NavParams, - Platform + Platform, } from 'ionic-angular'; @IonicPage() @Component({ selector: 'view-send-invite-amount', - templateUrl: 'send-invite-amount.html' + templateUrl: 'send-invite-amount.html', }) export class SendInviteAmountView { - wallets: Array; wallet: MeritWalletClient; formData = { amount: null, - destination: '' + destination: '', }; address; error: string; @@ -41,20 +40,22 @@ export class SendInviteAmountView { amountFocused: boolean; easySendDelivered: boolean; - @ViewChild('amount') amountInput: ElementRef; - - constructor(private navCtrl: NavController, - private navParams: NavParams, - private profileService: ProfileService, - private toastCtrl: ToastControllerService, - private loadCtrl: LoadingController, - private modalCtrl: ModalController, - private alertCtrl: AlertController, - private socialSharing: SocialSharing, - private platform: Platform, - private easySendService: EasySendService, - private logger: LoggerService, - private walletService: WalletService + @ViewChild('amount') + amountInput: ElementRef; + + constructor( + private navCtrl: NavController, + private navParams: NavParams, + private profileService: ProfileService, + private toastCtrl: ToastControllerService, + private loadCtrl: LoadingController, + private modalCtrl: ModalController, + private alertCtrl: AlertController, + private socialSharing: SocialSharing, + private platform: Platform, + private easySendService: EasySendService, + private logger: LoggerService, + private walletService: WalletService, ) { this.address = this.navParams.get('address'); this.showShareButton = this.platform.is('cordova') && SocialSharing.installed(); @@ -74,14 +75,14 @@ export class SendInviteAmountView { async send() { if (!this.wallet) { - this.wallet = this.wallets.find(w => (w.availableInvites > 0)); + this.wallet = this.wallets.find(w => w.availableInvites > 0); } if (!this.wallet || !this.wallet.availableInvites) { return this.toastCtrl.error('You have no active invites'); } if (this.wallet.availableInvites < this.formData.amount) { - return this.toastCtrl.error('You don\'t have enough invites in your wallet for this transaction.'); + return this.toastCtrl.error("You don't have enough invites in your wallet for this transaction."); } const loader = this.loadCtrl.create({ content: 'Creating MeritInvite link...' }); @@ -97,7 +98,7 @@ export class SendInviteAmountView { await this.wallet.deliverGlobalSend(easySend, { type: SendMethodType.Easy, destination, - value: this.formData.destination + value: this.formData.destination, }); this.easySendDelivered = true; } catch (err) { @@ -108,7 +109,6 @@ export class SendInviteAmountView { this.link = getEasySendURL(easySend); this.wallet.availableInvites -= this.formData.amount; - } catch (e) { console.error(e); this.toastCtrl.error('Failed to send invite'); @@ -118,12 +118,16 @@ export class SendInviteAmountView { } selectWallet() { - const modal = this.modalCtrl.create('SelectWalletModal', { - selectedWallet: this.wallet, - showInvites: true, - availableWallets: this.wallets.filter(wallet => wallet.availableInvites > 0) - }, MERIT_MODAL_OPTS); - modal.onDidDismiss((wallet) => { + const modal = this.modalCtrl.create( + 'SelectWalletModal', + { + selectedWallet: this.wallet, + showInvites: true, + availableWallets: this.wallets.filter(wallet => wallet.availableInvites > 0), + }, + MERIT_MODAL_OPTS, + ); + modal.onDidDismiss(wallet => { if (wallet) { this.wallet = wallet; this.processAmount(this.formData.amount); @@ -147,36 +151,34 @@ export class SendInviteAmountView { this.amountInput['_native']['nativeElement'].focus(); } - copyToClipboard() { this.copied = true; this.toastCtrl.success('Copied to clipboard'); } - async toWallets() { if (this.copied) { this.navCtrl.pop(); } else { - this.alertCtrl.create({ - title: 'Have you copied/shared your link?', - message: 'Do not forget to copy or share your link, or you can lose invite', - buttons: [ - { text: 'Cancel', role: 'cancel' }, - { - text: 'Ok', handler: () => { - this.navCtrl.pop(); - } - } - ] - }).present(); + this.alertCtrl + .create({ + title: 'Have you copied/shared your link?', + message: 'Do not forget to copy or share your link, or you can lose invite', + buttons: [ + { text: 'Cancel', role: 'cancel' }, + { + text: 'Ok', + handler: () => { + this.navCtrl.pop(); + }, + }, + ], + }) + .present(); } } isSendAllowed() { - return ( - !this.error && this.formData.amount - ); + return !this.error && this.formData.amount; } - } diff --git a/packages/lightwallet/mobile/src/app/community/network/send-invite/send-invite.module.ts b/packages/lightwallet/mobile/src/app/community/network/send-invite/send-invite.module.ts index f1c0c41b7e..422b1d53e8 100644 --- a/packages/lightwallet/mobile/src/app/community/network/send-invite/send-invite.module.ts +++ b/packages/lightwallet/mobile/src/app/community/network/send-invite/send-invite.module.ts @@ -4,13 +4,7 @@ import { SendInviteView } from '@merit/mobile/app/community/network/send-invite/ import { ComponentsModule } from '@merit/mobile/components/components.module'; @NgModule({ - declarations: [ - SendInviteView, - ], - imports: [ - IonicPageModule.forChild(SendInviteView), - ComponentsModule - ] + declarations: [SendInviteView], + imports: [IonicPageModule.forChild(SendInviteView), ComponentsModule], }) -export class SendInviteViewModule { -} +export class SendInviteViewModule {} diff --git a/packages/lightwallet/mobile/src/app/community/network/send-invite/send-invite.ts b/packages/lightwallet/mobile/src/app/community/network/send-invite/send-invite.ts index d539ca225c..84e393e43d 100644 --- a/packages/lightwallet/mobile/src/app/community/network/send-invite/send-invite.ts +++ b/packages/lightwallet/mobile/src/app/community/network/send-invite/send-invite.ts @@ -17,7 +17,7 @@ const ERROR_ALIAS_NOT_FOUND = 'ALIAS_NOT_FOUND'; @IonicPage() @Component({ selector: 'view-send-invite', - templateUrl: 'send-invite.html' + templateUrl: 'send-invite.html', }) export class SendInviteView { searchQuery: string = ''; @@ -26,19 +26,18 @@ export class SendInviteView { searchInProgress: boolean; searchResult: { - withMerit: Array, - toNewEntity: { destination: string, contact: MeritContact }, - error: string + withMerit: Array; + toNewEntity: { destination: string; contact: MeritContact }; + error: string; } = { withMerit: [], toNewEntity: null, error: null }; - - constructor(private navCtrl: NavController, - private contactsService: ContactsService, - private addressService: AddressService, - private modalCtrl: ModalController, - private addressScanner: AddressScannerService - ) { - } + constructor( + private navCtrl: NavController, + private contactsService: ContactsService, + private addressService: AddressService, + private modalCtrl: ModalController, + private addressScanner: AddressScannerService, + ) {} async ionViewWillEnter() { this.loadingContacts = true; @@ -55,7 +54,7 @@ export class SendInviteView { this.clearSearch(); this.debounceSearch.cancel(); result.withMerit = this.contacts; - return this.searchResult = result; + return (this.searchResult = result); this.searchInProgress = false; } @@ -68,7 +67,6 @@ export class SendInviteView { private debounceSearch = debounce(() => this.search(), 500); private async search() { - let result = { withMerit: [], toNewEntity: null, error: null }; const input = cleanAddress(this.searchQuery.split('?')[0]); @@ -87,15 +85,18 @@ export class SendInviteView { if (addressInfo && addressInfo.isConfirmed) { result.toNewEntity = { destination: SendMethodDestination.Address, contact: new MeritContact() }; - result.toNewEntity.contact.meritAddresses.push({ alias: input, address: addressInfo.address, network: ENV.network }); + result.toNewEntity.contact.meritAddresses.push({ + alias: input, + address: addressInfo.address, + network: ENV.network, + }); } } - this.contactsService.searchContacts(this.contacts, input) - .forEach((contact: MeritContact) => { - if (contact.meritAddresses && contact.meritAddresses.length) { - result.withMerit.push(contact); - } + this.contactsService.searchContacts(this.contacts, input).forEach((contact: MeritContact) => { + if (contact.meritAddresses && contact.meritAddresses.length) { + result.withMerit.push(contact); + } }); this.searchResult = result; @@ -112,7 +113,7 @@ export class SendInviteView { createContact() { const address = this.searchResult.toNewEntity.contact.meritAddresses[0]; const modal = this.modalCtrl.create('SendCreateContactView', { address }); - modal.onDidDismiss((contact) => { + modal.onDidDismiss(contact => { if (contact) { return this.sendInvite(this.searchResult.toNewEntity.contact); } @@ -123,7 +124,7 @@ export class SendInviteView { bindAddressToContact() { const address = this.searchResult.toNewEntity.contact.meritAddresses[0]; const modal = this.modalCtrl.create('SendSelectBindContactView', { contacts: this.contacts, address }); - modal.onDidDismiss((contact) => { + modal.onDidDismiss(contact => { if (contact) { return this.sendInvite(this.searchResult.toNewEntity.contact); } @@ -141,26 +142,26 @@ export class SendInviteView { } async sendInvite(contact) { - if (contact.meritAddresses.length == 1) { this.toSendAmount(contact.meritAddresses[0].address); } else { - let modal = this.modalCtrl.create('SendViaView', { - contact: contact - }, MERIT_MODAL_OPTS + let modal = this.modalCtrl.create( + 'SendViaView', + { + contact: contact, + }, + MERIT_MODAL_OPTS, ); - modal.onDidDismiss((params) => { + modal.onDidDismiss(params => { if (params) { this.toSendAmount(params.suggestedMethod.value); } }); modal.present(); } - } private toSendAmount(address) { this.navCtrl.push('SendInviteAmountView', { address: address }); } - } diff --git a/packages/lightwallet/mobile/src/app/core/popup.service.ts b/packages/lightwallet/mobile/src/app/core/popup.service.ts index 3e41c8fdf8..95216fe1f0 100644 --- a/packages/lightwallet/mobile/src/app/core/popup.service.ts +++ b/packages/lightwallet/mobile/src/app/core/popup.service.ts @@ -5,8 +5,7 @@ import { PopupService as BasePopupService } from '@merit/common/services/popup.s @Injectable() export class PopupService extends BasePopupService { - constructor(public alertCtrl: AlertController, - private log: LoggerService) { + constructor(public alertCtrl: AlertController, private log: LoggerService) { super(); } @@ -21,13 +20,13 @@ export class PopupService extends BasePopupService { handler: () => { this.log.info('Ok clicked'); return resolve(); - } - } - ] + }, + }, + ], }); alert.present(); }); - }; + } confirm(title, message, okText, cancelText): Promise { return new Promise((resolve, reject) => { @@ -40,20 +39,20 @@ export class PopupService extends BasePopupService { handler: () => { this.log.info('Disagree clicked'); return resolve(false); - } + }, }, { text: okText, handler: () => { this.log.info('Agree clicked'); return resolve(true); - } - } - ] + }, + }, + ], }); return confirm.present(); }); - }; + } prompt(title: string, message: string, opts: any, okText?: string, cancelText?: string): Promise { return new Promise((resolve, reject) => { @@ -63,7 +62,7 @@ export class PopupService extends BasePopupService { inputs: [ { value: opts.defaultText, - placeholder: opts.placeholder + placeholder: opts.placeholder, }, ], buttons: [ @@ -72,16 +71,16 @@ export class PopupService extends BasePopupService { handler: data => { this.log.info('Cancel clicked'); return resolve(null); - } + }, }, { text: okText ? okText : 'OK', handler: data => { this.log.info('Saved clicked'); return resolve(data[0]); - } - } - ] + }, + }, + ], }); prompt.present(); }); diff --git a/packages/lightwallet/mobile/src/app/onboard/alias/alias.module.ts b/packages/lightwallet/mobile/src/app/onboard/alias/alias.module.ts index 24652eb0b2..23cba9e334 100644 --- a/packages/lightwallet/mobile/src/app/onboard/alias/alias.module.ts +++ b/packages/lightwallet/mobile/src/app/onboard/alias/alias.module.ts @@ -4,13 +4,7 @@ import { AliasView } from '@merit/mobile/app/onboard/alias/alias'; import { DirectivesModule } from '@merit/mobile/directives/directives.module'; @NgModule({ - declarations: [ - AliasView, - ], - imports: [ - IonicPageModule.forChild(AliasView), - DirectivesModule - ], + declarations: [AliasView], + imports: [IonicPageModule.forChild(AliasView), DirectivesModule], }) -export class AliasViewModule { -} +export class AliasViewModule {} diff --git a/packages/lightwallet/mobile/src/app/onboard/alias/alias.ts b/packages/lightwallet/mobile/src/app/onboard/alias/alias.ts index ca1278f5ad..c750d8f912 100644 --- a/packages/lightwallet/mobile/src/app/onboard/alias/alias.ts +++ b/packages/lightwallet/mobile/src/app/onboard/alias/alias.ts @@ -17,7 +17,7 @@ import { InAppBrowser } from '@ionic-native/in-app-browser'; @IonicPage({ segment: 'alias/:parentAddress', - defaultHistory: ['OnboardingView'] + defaultHistory: ['OnboardingView'], }) @Component({ selector: 'view-alias', @@ -28,31 +28,32 @@ export class AliasView { formData = { alias: '', aliasValidationError: '', - aliasCheckInProgress: false + aliasCheckInProgress: false, }; - @ViewChild(Content) content: Content; + @ViewChild(Content) + content: Content; private parentAddress: string; - constructor(private walletService: WalletService, - private toastCtrl: ToastControllerService, - private loaderCtrl: LoadingController, - private navCtrl: NavController, - private navParams: NavParams, - private logger: LoggerService, - private config: ConfigService, - private pushNotificationService: PushNotificationsService, - private pollingNotificationService: PollingNotificationsService, - private emailNotificationService: EmailNotificationsService, - private addressService: AddressService, - private inAppBrowser: InAppBrowser ) { - } + constructor( + private walletService: WalletService, + private toastCtrl: ToastControllerService, + private loaderCtrl: LoadingController, + private navCtrl: NavController, + private navParams: NavParams, + private logger: LoggerService, + private config: ConfigService, + private pushNotificationService: PushNotificationsService, + private pollingNotificationService: PollingNotificationsService, + private emailNotificationService: EmailNotificationsService, + private addressService: AddressService, + private inAppBrowser: InAppBrowser, + ) {} async ionViewDidLoad() { // An unlock code from a friend sharing the link. this.parentAddress = this.navParams.get('parentAddress'); - } checkAlias() { @@ -65,31 +66,30 @@ export class AliasView { }, 750); private async validateAlias() { - this.formData.alias = cleanAddress(this.formData.alias); - const input = (this.formData.alias && isAlias(this.formData.alias)) ? this.formData.alias.slice(1) : this.formData.alias; + const input = + this.formData.alias && isAlias(this.formData.alias) ? this.formData.alias.slice(1) : this.formData.alias; if (!input) { this.validateAliasDebounce.cancel(); this.formData.aliasCheckInProgress = false; - return this.formData.aliasValidationError = null; + return (this.formData.aliasValidationError = null); } if (input.length < 3) { this.validateAliasDebounce.cancel(); this.formData.aliasCheckInProgress = false; - return this.formData.aliasValidationError = 'Alias should contain at least 3 symbols'; + return (this.formData.aliasValidationError = 'Alias should contain at least 3 symbols'); } if (!this.addressService.couldBeAlias(input)) { this.validateAliasDebounce.cancel(); this.formData.aliasCheckInProgress = false; - return this.formData.aliasValidationError = 'Incorrect alias format'; + return (this.formData.aliasValidationError = 'Incorrect alias format'); } this.formData.aliasValidationError = null; - let addressExists = await this.addressService.getValidAddress(input); if (addressExists) { @@ -108,7 +108,7 @@ export class AliasView { let { alias } = this.formData; - alias = (alias && isAlias(alias))? alias.slice(1) : alias; + alias = alias && isAlias(alias) ? alias.slice(1) : alias; const loader = this.loaderCtrl.create({ content: 'Creating wallet...' }); await loader.present(); @@ -124,7 +124,7 @@ export class AliasView { this.logger.info('Subscribing to long polling for default wallet'); await this.emailNotificationService.init(); this.pollingNotificationService.enablePolling(wallet); - } + } let unlockUrl: string; diff --git a/packages/lightwallet/mobile/src/app/onboard/backup/backup.module.ts b/packages/lightwallet/mobile/src/app/onboard/backup/backup.module.ts index fafa174f87..6b30e0b873 100644 --- a/packages/lightwallet/mobile/src/app/onboard/backup/backup.module.ts +++ b/packages/lightwallet/mobile/src/app/onboard/backup/backup.module.ts @@ -1,16 +1,10 @@ import { NgModule } from '@angular/core'; import { IonicPageModule } from 'ionic-angular'; import { BackupView } from '@merit/mobile/app/onboard/backup/backup'; -import { ClipModule } from 'ng2-clip' +import { ClipModule } from 'ng2-clip'; @NgModule({ - declarations: [ - BackupView, - ], - imports: [ - IonicPageModule.forChild(BackupView), - ClipModule - ], + declarations: [BackupView], + imports: [IonicPageModule.forChild(BackupView), ClipModule], }) -export class BackupModule { -} +export class BackupModule {} diff --git a/packages/lightwallet/mobile/src/app/onboard/backup/backup.ts b/packages/lightwallet/mobile/src/app/onboard/backup/backup.ts index d843f8cf62..7b87ca63ea 100644 --- a/packages/lightwallet/mobile/src/app/onboard/backup/backup.ts +++ b/packages/lightwallet/mobile/src/app/onboard/backup/backup.ts @@ -10,10 +10,11 @@ export class BackupView { public mnemonic: string; public copied: boolean; - constructor(public alertController: AlertController, - private navCtrl: NavController, - private navParams: NavParams, - private toastCtrl: ToastControllerService + constructor( + public alertController: AlertController, + private navCtrl: NavController, + private navParams: NavParams, + private toastCtrl: ToastControllerService, ) { this.mnemonic = this.navParams.get('mnemonic'); } @@ -22,25 +23,23 @@ export class BackupView { // Now that we are unlocked, we no longer need these other views in the stack, // so we shall destroy them. - await this.navCtrl.setRoot('TransactView', { unlockUrl: this.navParams.get('unlockUrl') }); return this.navCtrl.popToRoot(); } - public skipBackupPrompt(){ + public skipBackupPrompt() { if (!this.copied) { - this.alertController.create({ - title: 'No backup, no Merit', - message: "Have you written your phrase down? You can do it later on wallet export page, but we strongly recommend to do it now so you won't loose access to your Merit", - buttons: [ - { text: 'Cancel', role: 'cancel' }, - { text: 'Ok', handler: this.toTransactView.bind(this) } - ] - }).present(); + this.alertController + .create({ + title: 'No backup, no Merit', + message: + "Have you written your phrase down? You can do it later on wallet export page, but we strongly recommend to do it now so you won't loose access to your Merit", + buttons: [{ text: 'Cancel', role: 'cancel' }, { text: 'Ok', handler: this.toTransactView.bind(this) }], + }) + .present(); } else { - this.toTransactView(); + this.toTransactView(); } - } public markCopied() { diff --git a/packages/lightwallet/mobile/src/app/onboard/no-session/no-session.module.ts b/packages/lightwallet/mobile/src/app/onboard/no-session/no-session.module.ts index 4b03ad41ff..985a07c7b1 100644 --- a/packages/lightwallet/mobile/src/app/onboard/no-session/no-session.module.ts +++ b/packages/lightwallet/mobile/src/app/onboard/no-session/no-session.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { NoSessionView } from './no-session'; @NgModule({ - declarations: [ - NoSessionView, - ], - imports: [ - IonicPageModule.forChild(NoSessionView), - ], + declarations: [NoSessionView], + imports: [IonicPageModule.forChild(NoSessionView)], }) -export class NoSessionModule { -} +export class NoSessionModule {} diff --git a/packages/lightwallet/mobile/src/app/onboard/no-session/no-session.ts b/packages/lightwallet/mobile/src/app/onboard/no-session/no-session.ts index 6c0e964a60..d00d0d753a 100644 --- a/packages/lightwallet/mobile/src/app/onboard/no-session/no-session.ts +++ b/packages/lightwallet/mobile/src/app/onboard/no-session/no-session.ts @@ -1,18 +1,13 @@ import { Component } from '@angular/core'; import { IonicPage, NavController, NavParams } from 'ionic-angular'; - @IonicPage() @Component({ selector: 'view-no-session', templateUrl: 'no-session.html', }) export class NoSessionView { - - constructor(private navCtrl: NavController, - private navParams: NavParams) { - - } + constructor(private navCtrl: NavController, private navParams: NavParams) {} ionViewDidLoad() { //do something here @@ -25,5 +20,4 @@ export class NoSessionView { toImportView() { this.navCtrl.push('ImportView'); } - } diff --git a/packages/lightwallet/mobile/src/app/onboard/onboarding.view.module.ts b/packages/lightwallet/mobile/src/app/onboard/onboarding.view.module.ts index e4f3cbe5c4..f9249577d8 100644 --- a/packages/lightwallet/mobile/src/app/onboard/onboarding.view.module.ts +++ b/packages/lightwallet/mobile/src/app/onboard/onboarding.view.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { OnboardingView } from './onboarding.view'; @NgModule({ - declarations: [ - OnboardingView, - ], - imports: [ - IonicPageModule.forChild(OnboardingView), - ], + declarations: [OnboardingView], + imports: [IonicPageModule.forChild(OnboardingView)], }) -export class OnboardingViewModule { -} +export class OnboardingViewModule {} diff --git a/packages/lightwallet/mobile/src/app/onboard/onboarding.view.ts b/packages/lightwallet/mobile/src/app/onboard/onboarding.view.ts index 852d7363f9..e1f72b7759 100644 --- a/packages/lightwallet/mobile/src/app/onboard/onboarding.view.ts +++ b/packages/lightwallet/mobile/src/app/onboard/onboarding.view.ts @@ -2,11 +2,10 @@ import { Component } from '@angular/core'; import { IonicPage } from 'ionic-angular'; @IonicPage({ - segment: 'onboarding' + segment: 'onboarding', }) @Component({ selector: 'view-onboarding', templateUrl: 'onboarding.html', }) -export class OnboardingView { -} +export class OnboardingView {} diff --git a/packages/lightwallet/mobile/src/app/onboard/tour/tour.module.ts b/packages/lightwallet/mobile/src/app/onboard/tour/tour.module.ts index 9c116c30a3..c32dff36c6 100644 --- a/packages/lightwallet/mobile/src/app/onboard/tour/tour.module.ts +++ b/packages/lightwallet/mobile/src/app/onboard/tour/tour.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { TourView } from '@merit/mobile/app/onboard/tour/tour'; @NgModule({ - declarations: [ - TourView, - ], - imports: [ - IonicPageModule.forChild(TourView), - ], + declarations: [TourView], + imports: [IonicPageModule.forChild(TourView)], }) -export class TourModule { -} +export class TourModule {} diff --git a/packages/lightwallet/mobile/src/app/onboard/tour/tour.ts b/packages/lightwallet/mobile/src/app/onboard/tour/tour.ts index 1798f058f8..b1b856b7a0 100644 --- a/packages/lightwallet/mobile/src/app/onboard/tour/tour.ts +++ b/packages/lightwallet/mobile/src/app/onboard/tour/tour.ts @@ -3,27 +3,22 @@ import { IonicPage, NavController, NavParams, Slides } from 'ionic-angular'; import { RateService } from '@merit/common/services/rate.service'; @IonicPage({ - defaultHistory: ['OnboardingView'] + defaultHistory: ['OnboardingView'], }) @Component({ selector: 'view-tour', templateUrl: 'tour.html', }) export class TourView { - - @ViewChild(Slides) slides: Slides; + @ViewChild(Slides) + slides: Slides; rateData: any = {}; - constructor(public navCtrl: NavController, - public navParams: NavParams, - private rateService: RateService) { - } + constructor(public navCtrl: NavController, public navParams: NavParams, private rateService: RateService) {} async ionViewDidLoad() { - this.rateData.usdPerMerit = this.rateService.microsToMrt( - await this.rateService.fiatToMicros(1e8, 'USD') - ); + this.rateData.usdPerMerit = this.rateService.microsToMrt(await this.rateService.fiatToMicros(1e8, 'USD')); } ionViewDidEnter() { @@ -57,5 +52,4 @@ export class TourView { slides.lockSwipeToPrev(false); } } - } diff --git a/packages/lightwallet/mobile/src/app/onboard/unlock/unlock.module.ts b/packages/lightwallet/mobile/src/app/onboard/unlock/unlock.module.ts index b82494983e..87f9ed7966 100644 --- a/packages/lightwallet/mobile/src/app/onboard/unlock/unlock.module.ts +++ b/packages/lightwallet/mobile/src/app/onboard/unlock/unlock.module.ts @@ -5,14 +5,7 @@ import { CommonPipesModule } from '@merit/common/common-pipes.module'; import { DirectivesModule } from '@merit/mobile/directives/directives.module'; @NgModule({ - declarations: [ - UnlockView, - ], - imports: [ - IonicPageModule.forChild(UnlockView), - CommonPipesModule, - DirectivesModule - ], + declarations: [UnlockView], + imports: [IonicPageModule.forChild(UnlockView), CommonPipesModule, DirectivesModule], }) -export class UnlockViewModule { -} +export class UnlockViewModule {} diff --git a/packages/lightwallet/mobile/src/app/onboard/unlock/unlock.ts b/packages/lightwallet/mobile/src/app/onboard/unlock/unlock.ts index 50527bac95..cd7a293729 100644 --- a/packages/lightwallet/mobile/src/app/onboard/unlock/unlock.ts +++ b/packages/lightwallet/mobile/src/app/onboard/unlock/unlock.ts @@ -8,7 +8,7 @@ import { cleanAddress, isAlias } from '@merit/common/utils/addresses'; import { AddressService } from '@merit/common/services/address.service'; @IonicPage({ - defaultHistory: ['OnboardingView'] + defaultHistory: ['OnboardingView'], }) @Component({ selector: 'view-unlock', @@ -19,29 +19,33 @@ export class UnlockView { formData = { parentAddress: '', addressCheckError: '', - addressCheckInProgress: false + addressCheckInProgress: false, }; easyReceipt: EasyReceipt; parsedAddress: ''; - invitation: {address: string, alias: string}; + invitation: { address: string; alias: string }; get canContinue(): boolean { return Boolean(this.parsedAddress) && !this.formData.addressCheckInProgress && !this.formData.addressCheckError; } get shouldShowQRButton(): boolean { - return !Boolean(this.formData.parentAddress) && !this.formData.addressCheckInProgress && !this.formData.addressCheckError; + return ( + !Boolean(this.formData.parentAddress) && !this.formData.addressCheckInProgress && !this.formData.addressCheckError + ); } - @ViewChild(Content) content: Content; + @ViewChild(Content) + content: Content; - constructor(private navCtrl: NavController, - private navParams: NavParams, - private easyReceiveService: EasyReceiveService, - private addressService: AddressService, - private addressScanner: AddressScannerService) { - } + constructor( + private navCtrl: NavController, + private navParams: NavParams, + private easyReceiveService: EasyReceiveService, + private addressService: AddressService, + private addressScanner: AddressScannerService, + ) {} // TODO use ngOnInit or ionViewWillLoad async ionViewDidLoad() { @@ -68,7 +72,7 @@ export class UnlockView { this.validateAddressDebounce(); } - toAliasView() { + toAliasView() { if (this.formData.parentAddress && !this.formData.addressCheckInProgress && !this.formData.addressCheckError) { const inv = this.navParams.get('invitation'); const gbs = !!this.navParams.get('gbs'); @@ -93,24 +97,26 @@ export class UnlockView { private async validateAddress() { this.formData.parentAddress = cleanAddress(this.formData.parentAddress); - let input = (this.formData.parentAddress && isAlias(this.formData.parentAddress)) ? this.formData.parentAddress.slice(1) : this.formData.parentAddress; + let input = + this.formData.parentAddress && isAlias(this.formData.parentAddress) + ? this.formData.parentAddress.slice(1) + : this.formData.parentAddress; if (!input) { this.formData.addressCheckInProgress = false; - return this.formData.addressCheckError = 'Address cannot be empty'; + return (this.formData.addressCheckError = 'Address cannot be empty'); } else if (!this.addressService.isAddress(input) && !this.addressService.couldBeAlias(input)) { this.formData.addressCheckInProgress = false; - return this.formData.addressCheckError = 'Incorrect address or alias format'; + return (this.formData.addressCheckError = 'Incorrect address or alias format'); } else { let addressInfo = await this.addressService.getAddressInfo(input); if (!addressInfo || !addressInfo.isValid || !addressInfo.isBeaconed || !addressInfo.isConfirmed) { this.formData.addressCheckInProgress = false; - return this.formData.addressCheckError = 'Address not found'; + return (this.formData.addressCheckError = 'Address not found'); } else { this.formData.addressCheckError = null; this.formData.addressCheckInProgress = false; - return this.parsedAddress = addressInfo.address; + return (this.parsedAddress = addressInfo.address); } } } - } diff --git a/packages/lightwallet/mobile/src/app/onboard/verify-backup/verify-backup.module.ts b/packages/lightwallet/mobile/src/app/onboard/verify-backup/verify-backup.module.ts index ea9d3e606f..c9bdf2fcf2 100644 --- a/packages/lightwallet/mobile/src/app/onboard/verify-backup/verify-backup.module.ts +++ b/packages/lightwallet/mobile/src/app/onboard/verify-backup/verify-backup.module.ts @@ -4,13 +4,7 @@ import { VerifyBackupView } from '@merit/mobile/app/onboard/verify-backup/verify import { CommonPipesModule } from '@merit/common/common-pipes.module'; @NgModule({ - declarations: [ - VerifyBackupView - ], - imports: [ - IonicPageModule.forChild(VerifyBackupView), - CommonPipesModule - ], + declarations: [VerifyBackupView], + imports: [IonicPageModule.forChild(VerifyBackupView), CommonPipesModule], }) -export class VerifyBackupModule { -} +export class VerifyBackupModule {} diff --git a/packages/lightwallet/mobile/src/app/onboard/verify-backup/verify-backup.ts b/packages/lightwallet/mobile/src/app/onboard/verify-backup/verify-backup.ts index f65bdd97c9..622e207b49 100644 --- a/packages/lightwallet/mobile/src/app/onboard/verify-backup/verify-backup.ts +++ b/packages/lightwallet/mobile/src/app/onboard/verify-backup/verify-backup.ts @@ -4,7 +4,7 @@ import * as _ from 'lodash'; import { LoggerService } from '@merit/common/services/logger.service'; @IonicPage({ - defaultHistory: ['OnboardingView'] + defaultHistory: ['OnboardingView'], }) @Component({ selector: 'view-verify-backup', @@ -13,21 +13,24 @@ import { LoggerService } from '@merit/common/services/logger.service'; export class VerifyBackupView { mnemonic: string; enteredPhrase: string[] = []; - wordList: { word: string, selected: boolean }[] = []; + wordList: { word: string; selected: boolean }[] = []; - constructor(private alertController: AlertController, - private navCtrl: NavController, - private navParams: NavParams, - private logger: LoggerService) { - } + constructor( + private alertController: AlertController, + private navCtrl: NavController, + private navParams: NavParams, + private logger: LoggerService, + ) {} ionViewDidLoad() { this.mnemonic = this.navParams.get('mnemonic'); if (this.mnemonic) { - this.wordList = _.shuffle(_.map(this.mnemonic.split(' '), (word) => ({ - word: word, - selected: false - }))); + this.wordList = _.shuffle( + _.map(this.mnemonic.split(' '), word => ({ + word: word, + selected: false, + })), + ); } else { this.navCtrl.pop(); } @@ -37,7 +40,7 @@ export class VerifyBackupView { return _.every(this.wordList, 'selected'); } - toggleWord(wordObj: { word: string, selected: boolean }): void { + toggleWord(wordObj: { word: string; selected: boolean }): void { wordObj.selected = !wordObj.selected; if (wordObj.selected) { this.enteredPhrase.push(wordObj.word); @@ -47,7 +50,7 @@ export class VerifyBackupView { } resetWords(): void { - _.each(this.wordList, (word) => { + _.each(this.wordList, word => { word.selected = false; }); this.enteredPhrase = []; @@ -69,14 +72,19 @@ export class VerifyBackupView { } private failedAlert(): void { - this.alertController.create({ - title: 'Oops...', - message: 'The phrase you entered didn\'t match your backup phrase! ' + - 'If you lose your wallet without a backup, it is lost for good!', - buttons: [{ - text: 'Try Again', - handler: this.resetWords - }] - }).present(); + this.alertController + .create({ + title: 'Oops...', + message: + "The phrase you entered didn't match your backup phrase! " + + 'If you lose your wallet without a backup, it is lost for good!', + buttons: [ + { + text: 'Try Again', + handler: this.resetWords, + }, + ], + }) + .present(); } } diff --git a/packages/lightwallet/mobile/src/app/settings/notifications/notifications.module.ts b/packages/lightwallet/mobile/src/app/settings/notifications/notifications.module.ts index b564d7ff3a..024a206deb 100644 --- a/packages/lightwallet/mobile/src/app/settings/notifications/notifications.module.ts +++ b/packages/lightwallet/mobile/src/app/settings/notifications/notifications.module.ts @@ -4,13 +4,7 @@ import { NotificationsView } from '@merit/mobile/app/settings/notifications/noti import { TranslateModule } from '@ngx-translate/core'; @NgModule({ - declarations: [ - NotificationsView - ], - imports: [ - IonicPageModule.forChild(NotificationsView), - TranslateModule - ] + declarations: [NotificationsView], + imports: [IonicPageModule.forChild(NotificationsView), TranslateModule], }) -export class NotificationsViewModule { -} +export class NotificationsViewModule {} diff --git a/packages/lightwallet/mobile/src/app/settings/notifications/notifications.ts b/packages/lightwallet/mobile/src/app/settings/notifications/notifications.ts index 024d36c616..ea37f0f58b 100644 --- a/packages/lightwallet/mobile/src/app/settings/notifications/notifications.ts +++ b/packages/lightwallet/mobile/src/app/settings/notifications/notifications.ts @@ -15,7 +15,7 @@ import { NotificationSettingsController } from '@merit/common/utils/notification @IonicPage() @Component({ selector: 'notifications-view', - templateUrl: 'notifications.html' + templateUrl: 'notifications.html', }) export class NotificationsView { usePushNotifications: boolean = this.platformService.isCordova; @@ -27,21 +27,22 @@ export class NotificationsView { this.smsNotificationsService, this.formBuilder, this.toastCtrl, - this.platformService.isIOS ? 'ios' : 'android' + this.platformService.isIOS ? 'ios' : 'android', ); - constructor(public navCtrl: NavController, - public navParams: NavParams, - public formBuilder: FormBuilder, - private configService: ConfigService, - private appService: AppSettingsService, - private platformService: PlatformService, - private pushNotificationsService: PushNotificationsService, - private emailNotificationsService: EmailNotificationsService, - private loadingCtrl: LoadingController, - private smsNotificationsService: SmsNotificationsService, - private persistenceService: PersistenceService2, - private toastCtrl: ToastControllerService + constructor( + public navCtrl: NavController, + public navParams: NavParams, + public formBuilder: FormBuilder, + private configService: ConfigService, + private appService: AppSettingsService, + private platformService: PlatformService, + private pushNotificationsService: PushNotificationsService, + private emailNotificationsService: EmailNotificationsService, + private loadingCtrl: LoadingController, + private smsNotificationsService: SmsNotificationsService, + private persistenceService: PersistenceService2, + private toastCtrl: ToastControllerService, ) {} ngOnInit() { diff --git a/packages/lightwallet/mobile/src/app/settings/select-currency/select-currency.module.ts b/packages/lightwallet/mobile/src/app/settings/select-currency/select-currency.module.ts index d2331acd70..feccb64f2a 100644 --- a/packages/lightwallet/mobile/src/app/settings/select-currency/select-currency.module.ts +++ b/packages/lightwallet/mobile/src/app/settings/select-currency/select-currency.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { SelectCurrencyModal } from '@merit/mobile/app/settings/select-currency/select-currency'; @NgModule({ - declarations: [ - SelectCurrencyModal, - ], - imports: [ - IonicPageModule.forChild(SelectCurrencyModal), - ], + declarations: [SelectCurrencyModal], + imports: [IonicPageModule.forChild(SelectCurrencyModal)], }) -export class SelectCurrencyComponentModule { -} +export class SelectCurrencyComponentModule {} diff --git a/packages/lightwallet/mobile/src/app/settings/select-currency/select-currency.ts b/packages/lightwallet/mobile/src/app/settings/select-currency/select-currency.ts index 277bb81db6..77d17de8f0 100644 --- a/packages/lightwallet/mobile/src/app/settings/select-currency/select-currency.ts +++ b/packages/lightwallet/mobile/src/app/settings/select-currency/select-currency.ts @@ -7,7 +7,6 @@ import { IonicPage, NavController, NavParams, ViewController } from 'ionic-angul templateUrl: 'select-currency.html', }) export class SelectCurrencyModal { - public currentCurrency; public availableCurrencies; @@ -15,9 +14,7 @@ export class SelectCurrencyModal { foundCurrencies = []; - constructor(public navCtrl: NavController, - public navParams: NavParams, - private viewCtrl: ViewController) { + constructor(public navCtrl: NavController, public navParams: NavParams, private viewCtrl: ViewController) { this.currentCurrency = this.navParams.get('currentCurrency'); this.availableCurrencies = this.navParams.get('availableCurrencies'); @@ -29,7 +26,7 @@ export class SelectCurrencyModal { this.foundCurrencies = this.availableCurrencies; } else { this.foundCurrencies = this.availableCurrencies.filter((c: string) => { - return (c.toLowerCase().indexOf(this.searchQuery.toLowerCase()) != -1); + return c.toLowerCase().indexOf(this.searchQuery.toLowerCase()) != -1; }); } } @@ -41,5 +38,4 @@ export class SelectCurrencyModal { select(currency) { this.viewCtrl.dismiss(currency); } - } diff --git a/packages/lightwallet/mobile/src/app/settings/select-language/select-language.module.ts b/packages/lightwallet/mobile/src/app/settings/select-language/select-language.module.ts index b36c00e873..c3601934c6 100644 --- a/packages/lightwallet/mobile/src/app/settings/select-language/select-language.module.ts +++ b/packages/lightwallet/mobile/src/app/settings/select-language/select-language.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { SelectLanguageModal } from '@merit/mobile/app/settings/select-language/select-language'; @NgModule({ - declarations: [ - SelectLanguageModal, - ], - imports: [ - IonicPageModule.forChild(SelectLanguageModal), - ], + declarations: [SelectLanguageModal], + imports: [IonicPageModule.forChild(SelectLanguageModal)], }) -export class SelectLanguageComponentModule { -} +export class SelectLanguageComponentModule {} diff --git a/packages/lightwallet/mobile/src/app/settings/select-language/select-language.ts b/packages/lightwallet/mobile/src/app/settings/select-language/select-language.ts index 36e9c323db..a860a9d1fa 100644 --- a/packages/lightwallet/mobile/src/app/settings/select-language/select-language.ts +++ b/packages/lightwallet/mobile/src/app/settings/select-language/select-language.ts @@ -2,22 +2,22 @@ import { Component } from '@angular/core'; import { InAppBrowser } from '@ionic-native/in-app-browser'; import { AlertController, IonicPage, NavController, NavParams, ViewController } from 'ionic-angular'; - @IonicPage() @Component({ selector: 'view-select-language', templateUrl: 'select-language.html', }) export class SelectLanguageModal { - currentLanguage; availableLanguages; - constructor(public navCtrl: NavController, - public navParams: NavParams, - private alertCtrl: AlertController, - private viewCtrl: ViewController, - private iap: InAppBrowser) { + constructor( + public navCtrl: NavController, + public navParams: NavParams, + private alertCtrl: AlertController, + private viewCtrl: ViewController, + private iap: InAppBrowser, + ) { this.currentLanguage = this.navParams.get('currentLanguage'); this.availableLanguages = this.navParams.get('availableLanguages'); } @@ -32,19 +32,22 @@ export class SelectLanguageModal { const confirm = this.alertCtrl.create({ title: 'External link', - message: 'You can see the latest developments and contribute to this open source app by visiting our project on GitHub', + message: + 'You can see the latest developments and contribute to this open source app by visiting our project on GitHub', buttons: [ { - text: 'Cancel', role: 'cancel', handler: () => { - } + text: 'Cancel', + role: 'cancel', + handler: () => {}, }, { - text: 'Open GitHub', handler: () => { - // TODO use an IAP service w/ chrome/safari - this.iap.create(url); - } - } - ] + text: 'Open GitHub', + handler: () => { + // TODO use an IAP service w/ chrome/safari + this.iap.create(url); + }, + }, + ], }); confirm.present(); @@ -57,5 +60,4 @@ export class SelectLanguageModal { select(language) { this.viewCtrl.dismiss(language); } - } diff --git a/packages/lightwallet/mobile/src/app/settings/select-unit/select-unit.module.ts b/packages/lightwallet/mobile/src/app/settings/select-unit/select-unit.module.ts index 40906aa8e0..c1e2964e3e 100644 --- a/packages/lightwallet/mobile/src/app/settings/select-unit/select-unit.module.ts +++ b/packages/lightwallet/mobile/src/app/settings/select-unit/select-unit.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { SelectUnitModal } from '@merit/mobile/app/settings/select-unit/select-unit'; @NgModule({ - declarations: [ - SelectUnitModal, - ], - imports: [ - IonicPageModule.forChild(SelectUnitModal), - ], + declarations: [SelectUnitModal], + imports: [IonicPageModule.forChild(SelectUnitModal)], }) -export class SelectUnitComponentModule { -} +export class SelectUnitComponentModule {} diff --git a/packages/lightwallet/mobile/src/app/settings/select-unit/select-unit.ts b/packages/lightwallet/mobile/src/app/settings/select-unit/select-unit.ts index 135ae91679..23f279c6cd 100644 --- a/packages/lightwallet/mobile/src/app/settings/select-unit/select-unit.ts +++ b/packages/lightwallet/mobile/src/app/settings/select-unit/select-unit.ts @@ -10,8 +10,7 @@ export class SelectUnitModal { currentUnit; availableUnits; - constructor(private navParams: NavParams, - private viewCtrl: ViewController) { + constructor(private navParams: NavParams, private viewCtrl: ViewController) { this.currentUnit = this.navParams.get('currentUnit'); this.availableUnits = this.navParams.get('availableUnits'); } diff --git a/packages/lightwallet/mobile/src/app/settings/session-log/session-log.module.ts b/packages/lightwallet/mobile/src/app/settings/session-log/session-log.module.ts index 5f9340c20b..911f1df1a6 100644 --- a/packages/lightwallet/mobile/src/app/settings/session-log/session-log.module.ts +++ b/packages/lightwallet/mobile/src/app/settings/session-log/session-log.module.ts @@ -1,18 +1,11 @@ import { NgModule } from '@angular/core'; import { MomentModule } from 'ngx-moment'; import { IonicPageModule } from 'ionic-angular'; -import { ClipModule } from 'ng2-clip' +import { ClipModule } from 'ng2-clip'; import { SessionLogView } from '@merit/mobile/app/settings/session-log/session-log'; @NgModule({ - declarations: [ - SessionLogView, - ], - imports: [ - MomentModule, - ClipModule, - IonicPageModule.forChild(SessionLogView), - ], + declarations: [SessionLogView], + imports: [MomentModule, ClipModule, IonicPageModule.forChild(SessionLogView)], }) -export class SessionLogComponentModule { -} +export class SessionLogComponentModule {} diff --git a/packages/lightwallet/mobile/src/app/settings/session-log/session-log.ts b/packages/lightwallet/mobile/src/app/settings/session-log/session-log.ts index 7c9b69746d..90c5a69b90 100644 --- a/packages/lightwallet/mobile/src/app/settings/session-log/session-log.ts +++ b/packages/lightwallet/mobile/src/app/settings/session-log/session-log.ts @@ -13,11 +13,12 @@ export class SessionLogView { filteredLogs = []; logsString = ''; - constructor(public navCtrl: NavController, - public navParams: NavParams, - private logger: LoggerService, - private toastCtrl: ToastControllerService) { - } + constructor( + public navCtrl: NavController, + public navParams: NavParams, + private logger: LoggerService, + private toastCtrl: ToastControllerService, + ) {} ionViewDidLoad() { this.filterLogs(); @@ -32,8 +33,11 @@ export class SessionLogView { let logsString = ''; - this.filteredLogs.forEach(log => - logsString += `${(new Date(log.timestamp)).toString()}: ${this.getLogLevelName(log.level)} ${log.arguments.join('\n')}` + this.filteredLogs.forEach( + log => + (logsString += `${new Date(log.timestamp).toString()}: ${this.getLogLevelName(log.level)} ${log.arguments.join( + '\n', + )}`), ); this.logsString = logsString; diff --git a/packages/lightwallet/mobile/src/app/settings/settings-about/settings-about.module.ts b/packages/lightwallet/mobile/src/app/settings/settings-about/settings-about.module.ts index 853a35d09d..1b08010d4b 100644 --- a/packages/lightwallet/mobile/src/app/settings/settings-about/settings-about.module.ts +++ b/packages/lightwallet/mobile/src/app/settings/settings-about/settings-about.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { SettingsAboutView } from '@merit/mobile/app/settings/settings-about/settings-about'; @NgModule({ - declarations: [ - SettingsAboutView, - ], - imports: [ - IonicPageModule.forChild(SettingsAboutView), - ], + declarations: [SettingsAboutView], + imports: [IonicPageModule.forChild(SettingsAboutView)], }) -export class SettingsAboutViewModule { -} +export class SettingsAboutViewModule {} diff --git a/packages/lightwallet/mobile/src/app/settings/settings-about/settings-about.ts b/packages/lightwallet/mobile/src/app/settings/settings-about/settings-about.ts index 24f23af52d..186045a54f 100644 --- a/packages/lightwallet/mobile/src/app/settings/settings-about/settings-about.ts +++ b/packages/lightwallet/mobile/src/app/settings/settings-about/settings-about.ts @@ -16,38 +16,41 @@ export class SettingsAboutView { commitHash: string; repoUrl: string = this.appSettingsService.info.gitHubRepoUrl; - constructor(private alertCtrl: AlertController, - private inAppBrowser: InAppBrowser, - private appSettingsService: AppSettingsService, - private appVersion: AppVersion, - private plt: Platform) { + constructor( + private alertCtrl: AlertController, + private inAppBrowser: InAppBrowser, + private appSettingsService: AppSettingsService, + private appVersion: AppVersion, + private plt: Platform, + ) { if (typeof WEBPACK_CONFIG !== 'undefined') { this.commitHash = WEBPACK_CONFIG.COMMIT_HASH; this.version = WEBPACK_CONFIG.VERSION; } } - async ngOnInit() { - } + async ngOnInit() {} toGithub() { - this.alertCtrl.create({ - title: 'External link', - message: 'You can see the latest developments and contribute to this open source app by visiting our project on GitHub', - buttons: [ - { - text: 'Cancel', - role: 'cancel', - handler: () => { - } - }, - { - text: 'Open GitHub', - handler: () => { - this.inAppBrowser.create(this.repoUrl + '/commit/' + this.commitHash, '_system'); - } - } - ] - }).present(); + this.alertCtrl + .create({ + title: 'External link', + message: + 'You can see the latest developments and contribute to this open source app by visiting our project on GitHub', + buttons: [ + { + text: 'Cancel', + role: 'cancel', + handler: () => {}, + }, + { + text: 'Open GitHub', + handler: () => { + this.inAppBrowser.create(this.repoUrl + '/commit/' + this.commitHash, '_system'); + }, + }, + ], + }) + .present(); } } diff --git a/packages/lightwallet/mobile/src/app/settings/settings.module.ts b/packages/lightwallet/mobile/src/app/settings/settings.module.ts index 25de4e7941..d41dd69ef5 100644 --- a/packages/lightwallet/mobile/src/app/settings/settings.module.ts +++ b/packages/lightwallet/mobile/src/app/settings/settings.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { SettingsView } from '@merit/mobile/app/settings/settings'; @NgModule({ - declarations: [ - SettingsView, - ], - imports: [ - IonicPageModule.forChild(SettingsView) - ], + declarations: [SettingsView], + imports: [IonicPageModule.forChild(SettingsView)], }) -export class SettingsComponentModule { -} +export class SettingsComponentModule {} diff --git a/packages/lightwallet/mobile/src/app/settings/settings.ts b/packages/lightwallet/mobile/src/app/settings/settings.ts index f6f39affb0..1f3887e434 100644 --- a/packages/lightwallet/mobile/src/app/settings/settings.ts +++ b/packages/lightwallet/mobile/src/app/settings/settings.ts @@ -14,7 +14,6 @@ import { PersistenceService } from '@merit/common/services/persistence.service'; templateUrl: 'settings.html', }) export class SettingsView { - currentLanguageName; availableLanguages = []; currentUnitName; @@ -25,17 +24,18 @@ export class SettingsView { wallets: Array; - constructor(private navCtrl: NavController, - private navParams: NavParams, - private app: App, - private alertCtrl: AlertController, - private inAppBrowser: InAppBrowser, - private modalCtrl: ModalController, - private configService: ConfigService, - private logger: LoggerService, - private profileService: ProfileService, - private contactsService: ContactsService, - private persistenceService: PersistenceService + constructor( + private navCtrl: NavController, + private navParams: NavParams, + private app: App, + private alertCtrl: AlertController, + private inAppBrowser: InAppBrowser, + private modalCtrl: ModalController, + private configService: ConfigService, + private logger: LoggerService, + private profileService: ProfileService, + private contactsService: ContactsService, + private persistenceService: PersistenceService, ) { let config = this.configService.get(); this.currentUnitName = config.wallet.settings.unitName; @@ -45,49 +45,56 @@ export class SettingsView { } async logout() { - - this.alertCtrl.create({ - title: 'Have you backed up your wallets?', - message: 'This action will delete all Merit data on your device, so if you have no backup, you will lose your wallets for good', - buttons: [ - { text: 'Cancel', role: 'cancel' }, - { text: 'Logout', handler: () => { - - const logout = () => { - const deleteAllData = () => this.wallets.map( w => this.profileService.deleteWallet(w)).concat(this.contactsService.deleteAddressBook()); - Promise.all(deleteAllData()).then(() => { - this.app.getRootNavs()[0].setRoot('OnboardingView'); - }); - }; - - this.persistenceService.isPinEnabled().then(pinEnabled => { - if (pinEnabled) { - const modal = this.modalCtrl.create('PinLockView', {showCancelButton: true}); - modal.onDidDismiss(async (success) => { - if (success) { - await this.persistenceService.setPin(null); - logout(); - } + this.alertCtrl + .create({ + title: 'Have you backed up your wallets?', + message: + 'This action will delete all Merit data on your device, so if you have no backup, you will lose your wallets for good', + buttons: [ + { text: 'Cancel', role: 'cancel' }, + { + text: 'Logout', + handler: () => { + const logout = () => { + const deleteAllData = () => + this.wallets + .map(w => this.profileService.deleteWallet(w)) + .concat(this.contactsService.deleteAddressBook()); + Promise.all(deleteAllData()).then(() => { + this.app.getRootNavs()[0].setRoot('OnboardingView'); }); - modal.present(); - } else { - logout(); - } - }); - } - } - ] - }).present(); + }; + this.persistenceService.isPinEnabled().then(pinEnabled => { + if (pinEnabled) { + const modal = this.modalCtrl.create('PinLockView', { showCancelButton: true }); + modal.onDidDismiss(async success => { + if (success) { + await this.persistenceService.setPin(null); + logout(); + } + }); + modal.present(); + } else { + logout(); + } + }); + }, + }, + ], + }) + .present(); } toLanguageSelect() { const modal = this.modalCtrl.create('SelectLanguageModal', { currentLanguage: this.currentLanguageName, - availableLanguages: [/* */] + availableLanguages: [ + /* */ + ], }); modal.present(); - modal.onDidDismiss((language) => { + modal.onDidDismiss(language => { if (language) this.currentLanguageName = language; }); } @@ -96,10 +103,12 @@ export class SettingsView { //@todo get from service const modal = this.modalCtrl.create('SelectUnitModal', { currentUnit: this.currentUnitName, - availableUnits: [/* available units */] + availableUnits: [ + /* available units */ + ], }); modal.present(); - modal.onDidDismiss((unit) => { + modal.onDidDismiss(unit => { this.logger.info(unit); if (unit) this.currentUnitName = unit; }); @@ -109,33 +118,35 @@ export class SettingsView { //@todo get from service const modal = this.modalCtrl.create('SelectCurrencyModal', { currentCurrency: this.currentAlternativeName, - availableCurrencies: [/* available currencies */] + availableCurrencies: [ + /* available currencies */ + ], }); modal.present(); - modal.onDidDismiss((unit) => { + modal.onDidDismiss(unit => { if (unit) this.currentUnitName = unit; }); } help() { - this.alertCtrl.create({ - title: 'External link', - message: 'Help and support information is available at the website', - buttons: [ - { - text: 'Cancel', - role: 'cancel', - handler: () => { - } - }, - { - text: 'Open', - handler: () => { - this.inAppBrowser.create(this.configService.get().help.url); - } - } - ] - }).present(); + this.alertCtrl + .create({ + title: 'External link', + message: 'Help and support information is available at the website', + buttons: [ + { + text: 'Cancel', + role: 'cancel', + handler: () => {}, + }, + { + text: 'Open', + handler: () => { + this.inAppBrowser.create(this.configService.get().help.url); + }, + }, + ], + }) + .present(); } - } diff --git a/packages/lightwallet/mobile/src/app/terms-of-use/terms-of-use.module.ts b/packages/lightwallet/mobile/src/app/terms-of-use/terms-of-use.module.ts index 25cb5065a3..517d0cd020 100644 --- a/packages/lightwallet/mobile/src/app/terms-of-use/terms-of-use.module.ts +++ b/packages/lightwallet/mobile/src/app/terms-of-use/terms-of-use.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { TermsOfUseView } from '@merit/mobile/app/terms-of-use/terms-of-use'; @NgModule({ - declarations: [ - TermsOfUseView, - ], - imports: [ - IonicPageModule.forChild(TermsOfUseView), - ], + declarations: [TermsOfUseView], + imports: [IonicPageModule.forChild(TermsOfUseView)], }) -export class TermsOfUseComponentModule { -} +export class TermsOfUseComponentModule {} diff --git a/packages/lightwallet/mobile/src/app/terms-of-use/terms-of-use.ts b/packages/lightwallet/mobile/src/app/terms-of-use/terms-of-use.ts index 14bbda0950..d10698c3d6 100644 --- a/packages/lightwallet/mobile/src/app/terms-of-use/terms-of-use.ts +++ b/packages/lightwallet/mobile/src/app/terms-of-use/terms-of-use.ts @@ -6,5 +6,4 @@ import { IonicPage } from 'ionic-angular'; selector: 'view-terms-of-use', templateUrl: 'terms-of-use.html', }) -export class TermsOfUseView { -} +export class TermsOfUseView {} diff --git a/packages/lightwallet/mobile/src/app/transact/receive/receive.module.ts b/packages/lightwallet/mobile/src/app/transact/receive/receive.module.ts index 437c504b9b..178f6b989e 100644 --- a/packages/lightwallet/mobile/src/app/transact/receive/receive.module.ts +++ b/packages/lightwallet/mobile/src/app/transact/receive/receive.module.ts @@ -5,17 +5,8 @@ import { ReceiveView } from '@merit/mobile/app/transact/receive/receive'; import { ClipModule } from 'ng2-clip'; import { DirectivesModule } from '@merit/mobile/directives/directives.module'; - @NgModule({ - declarations: [ - ReceiveView - ], - imports: [ - QRCodeModule, - ClipModule, - IonicPageModule.forChild(ReceiveView), - DirectivesModule - ], + declarations: [ReceiveView], + imports: [QRCodeModule, ClipModule, IonicPageModule.forChild(ReceiveView), DirectivesModule], }) -export class ReceiveComponentModule { -} +export class ReceiveComponentModule {} diff --git a/packages/lightwallet/mobile/src/app/transact/receive/receive.ts b/packages/lightwallet/mobile/src/app/transact/receive/receive.ts index e8e6ad376e..4fd6d0b68b 100644 --- a/packages/lightwallet/mobile/src/app/transact/receive/receive.ts +++ b/packages/lightwallet/mobile/src/app/transact/receive/receive.ts @@ -39,33 +39,37 @@ export class ReceiveView { hasUnlockedWallets: boolean; loading: boolean; - @ViewChild('amountInput') amountInput: TextInput; - @ViewChild(Footer) footer: Footer; + @ViewChild('amountInput') + amountInput: TextInput; + @ViewChild(Footer) + footer: Footer; private footerHeight: number; private toggleButtonHeight: number; private footerBottom: number; isFooterCollapsed: boolean; - constructor(private navCtrl: NavController, - private modalCtrl: ModalController, - private profileService: ProfileService, - private walletService: WalletService, - private toastCtrl: ToastControllerService, - private logger: LoggerService, - private socialSharing: SocialSharing, - private clipboard: Clipboard, - private rateService: RateService, - private configService: ConfigService, - private events: Events, - private addressService: AddressService, - private platformService: PlatformService, - private navParams: NavParams, - private rnd: Renderer2) { + constructor( + private navCtrl: NavController, + private modalCtrl: ModalController, + private profileService: ProfileService, + private walletService: WalletService, + private toastCtrl: ToastControllerService, + private logger: LoggerService, + private socialSharing: SocialSharing, + private clipboard: Clipboard, + private rateService: RateService, + private configService: ConfigService, + private events: Events, + private addressService: AddressService, + private platformService: PlatformService, + private navParams: NavParams, + private rnd: Renderer2, + ) { this.protocolHandler = 'merit'; this.availableUnits = [ this.configService.get().wallet.settings.unitCode.toUpperCase(), - this.configService.get().wallet.settings.alternativeIsoCode.toUpperCase() + this.configService.get().wallet.settings.alternativeIsoCode.toUpperCase(), ]; this.amountCurrency = this.availableUnits[0]; } @@ -87,12 +91,9 @@ export class ReceiveView { toggleFooter() { const el: HTMLElement = this.footer.getNativeElement(); - if (!this.footerHeight) - this.footerHeight = el.offsetHeight; - - if (!this.footerBottom) - this.footerBottom = parseInt(el.style.bottom.replace(/\D+/g, '')); + if (!this.footerHeight) this.footerHeight = el.offsetHeight; + if (!this.footerBottom) this.footerBottom = parseInt(el.style.bottom.replace(/\D+/g, '')); if (this.isFooterCollapsed) { this.isFooterCollapsed = false; @@ -125,7 +126,7 @@ export class ReceiveView { this.wallet = wallet; } - if (this.wallet) this.generateAddress(); + if (this.wallet) this.generateAddress(); this.loading = false; } @@ -147,8 +148,7 @@ export class ReceiveView { } else { this.addressGenerationInProgress = false; - if (err.text) - this.error = err.text; + if (err.text) this.error = err.text; return this.toastCtrl.error(err.text || 'Failed to generate new address'); } @@ -156,11 +156,15 @@ export class ReceiveView { } selectWallet() { - const modal = this.modalCtrl.create('SelectWalletModal', { - selectedWallet: this.wallet, - availableWallets: this.wallets - }, MERIT_MODAL_OPTS); - modal.onDidDismiss((wallet) => { + const modal = this.modalCtrl.create( + 'SelectWalletModal', + { + selectedWallet: this.wallet, + availableWallets: this.wallets, + }, + MERIT_MODAL_OPTS, + ); + modal.onDidDismiss(wallet => { if (wallet) { this.wallet = wallet; this.generateAddress(); @@ -171,17 +175,16 @@ export class ReceiveView { showShareButton() { return ( - this.platformService.isCordova - && this.wallet - && this.wallet.isComplete() - && this.qrAddress - && !this.addressGenerationInProgress + this.platformService.isCordova && + this.wallet && + this.wallet.isComplete() && + this.qrAddress && + !this.addressGenerationInProgress ); } share() { - if (SocialSharing.installed()) - return this.socialSharing.share(this.qrAddress); + if (SocialSharing.installed()) return this.socialSharing.share(this.qrAddress); } copyToClipboard(addressString: string) { @@ -189,8 +192,7 @@ export class ReceiveView { const address = addressString.split(':')[1] || addressString; - if (Clipboard.installed()) - this.clipboard.copy(address); + if (Clipboard.installed()) this.clipboard.copy(address); this.toastCtrl.message('Address copied to clipboard'); } @@ -198,7 +200,8 @@ export class ReceiveView { async toggleCurrency() { const rate = await this.rateService.getRate(this.availableUnits[1]); if (rate > 0) { - this.amountCurrency = this.amountCurrency == this.availableUnits[0] ? this.availableUnits[1] : this.availableUnits[0]; + this.amountCurrency = + this.amountCurrency == this.availableUnits[0] ? this.availableUnits[1] : this.availableUnits[0]; this.changeAmount(); } } @@ -213,6 +216,8 @@ export class ReceiveView { } private formatAddress() { - this.qrAddress = `${ this.protocolHandler }:${ this.address }${ this.amountMicros ? '?micros=' + this.amountMicros : '' }`; + this.qrAddress = `${this.protocolHandler}:${this.address}${ + this.amountMicros ? '?micros=' + this.amountMicros : '' + }`; } } diff --git a/packages/lightwallet/mobile/src/app/transact/select-wallet/select-wallet.module.ts b/packages/lightwallet/mobile/src/app/transact/select-wallet/select-wallet.module.ts index 5ea7f26493..52fde23b55 100644 --- a/packages/lightwallet/mobile/src/app/transact/select-wallet/select-wallet.module.ts +++ b/packages/lightwallet/mobile/src/app/transact/select-wallet/select-wallet.module.ts @@ -5,14 +5,7 @@ import { SelectWalletModal } from '@merit/mobile/app/transact/select-wallet/sele import { CommonPipesModule } from '@merit/common/common-pipes.module'; @NgModule({ - declarations: [ - SelectWalletModal, - ], - imports: [ - MomentModule, - CommonPipesModule, - IonicPageModule.forChild(SelectWalletModal), - ], + declarations: [SelectWalletModal], + imports: [MomentModule, CommonPipesModule, IonicPageModule.forChild(SelectWalletModal)], }) -export class SelectWalletComponentModule { -} +export class SelectWalletComponentModule {} diff --git a/packages/lightwallet/mobile/src/app/transact/select-wallet/select-wallet.ts b/packages/lightwallet/mobile/src/app/transact/select-wallet/select-wallet.ts index 98dd41deee..61fcc40b46 100644 --- a/packages/lightwallet/mobile/src/app/transact/select-wallet/select-wallet.ts +++ b/packages/lightwallet/mobile/src/app/transact/select-wallet/select-wallet.ts @@ -14,15 +14,12 @@ export class SelectWalletModal { showInvites: boolean; - constructor(private navParams: NavParams, - private viewCtrl: ViewController, - private profileService: ProfileService) { - } + constructor(private navParams: NavParams, private viewCtrl: ViewController, private profileService: ProfileService) {} async ngOnInit() { - this.wallets = this.navParams.get('availableWallets') || await this.profileService.getWallets(); + this.wallets = this.navParams.get('availableWallets') || (await this.profileService.getWallets()); this.selectedWallet = this.navParams.get('selectedWallet'); - this.showInvites = this.navParams.get('showInvites'); + this.showInvites = this.navParams.get('showInvites'); } cancel() { @@ -30,6 +27,6 @@ export class SelectWalletModal { } select(wallet) { - this.viewCtrl.dismiss(wallet); + this.viewCtrl.dismiss(wallet); } } diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-amount/send-amount.module.ts b/packages/lightwallet/mobile/src/app/transact/send/send-amount/send-amount.module.ts index 82344245bc..667eebf365 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-amount/send-amount.module.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-amount/send-amount.module.ts @@ -5,14 +5,7 @@ import { SendAmountView } from './send-amount'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; @NgModule({ - declarations: [ - SendAmountView, - ], - imports: [ - IonicPageModule.forChild(SendAmountView), - CommonPipesModule, - DirectivesModule - ], + declarations: [SendAmountView], + imports: [IonicPageModule.forChild(SendAmountView), CommonPipesModule, DirectivesModule], }) -export class SendAmountModule { -} +export class SendAmountModule {} diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-amount/send-amount.ts b/packages/lightwallet/mobile/src/app/transact/send/send-amount/send-amount.ts index ede92a7cc7..f7d9e4e034 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-amount/send-amount.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-amount/send-amount.ts @@ -18,21 +18,21 @@ import { LoadingController, ModalController, NavController, - NavParams + NavParams, } from 'ionic-angular'; import { getSendMethodDestinationType } from '@merit/common/utils/destination'; @IonicPage() @Component({ selector: 'view-send-amount', - templateUrl: 'send-amount.html' + templateUrl: 'send-amount.html', }) export class SendAmountView { public recipient: MeritContact; public sendMethod: ISendMethod; - public availableUnits: Array<{ type: string, name: string }>; - public selectedCurrency: { type: string, name: string }; + public availableUnits: Array<{ type: string; name: string }>; + public selectedCurrency: { type: string; name: string }; public txData: ISendTxData; public feeCalcError: string; @@ -44,7 +44,7 @@ export class SendAmountView { confirmPassword: '', nbBlocks: 10080, validTill: '', - destination: '' + destination: '', }; public readonly CURRENCY_TYPE_MRT = 'mrt'; @@ -62,20 +62,23 @@ export class SendAmountView { private loading: boolean = true; - @ViewChild('amount') amountInput: ElementRef; - @ViewChild('confirmInput') confirmInput: ElementRef; - - constructor(private navCtrl: NavController, - private navParams: NavParams, - private configService: ConfigService, - private rateService: RateService, - private profileService: ProfileService, - private modalCtrl: ModalController, - private alertCtrl: AlertController, - private loadingCtrl: LoadingController, - private sendService: SendService, - private events: Events, - private logger: LoggerService + @ViewChild('amount') + amountInput: ElementRef; + @ViewChild('confirmInput') + confirmInput: ElementRef; + + constructor( + private navCtrl: NavController, + private navParams: NavParams, + private configService: ConfigService, + private rateService: RateService, + private profileService: ProfileService, + private modalCtrl: ModalController, + private alertCtrl: AlertController, + private loadingCtrl: LoadingController, + private sendService: SendService, + private events: Events, + private logger: LoggerService, ) { this.recipient = this.navParams.get('contact'); this.sendMethod = this.navParams.get('suggestedMethod'); @@ -87,13 +90,13 @@ export class SendAmountView { await this.updateTxData(); this.availableUnits = [ - { type: this.CURRENCY_TYPE_MRT, name: this.configService.get().wallet.settings.unitCode.toUpperCase() } + { type: this.CURRENCY_TYPE_MRT, name: this.configService.get().wallet.settings.unitCode.toUpperCase() }, ]; const rate = await this.rateService.getRate(this.configService.get().wallet.settings.alternativeIsoCode); if (rate > 0) { this.availableUnits.push({ type: this.CURRENCY_TYPE_FIAT, - name: this.configService.get().wallet.settings.alternativeIsoCode.toUpperCase() + name: this.configService.get().wallet.settings.alternativeIsoCode.toUpperCase(), }); } this.selectedCurrency = this.availableUnits[0]; @@ -127,23 +130,30 @@ export class SendAmountView { this.selectedWallet = this.wallets.find(w => w.confirmed); const passedAmount = this.navParams.get('amount') || 0; this.selectedWallet = this.wallets.find(w => { - return (w.balance.spendableAmount > 0) && (w.balance.spendableAmount >= passedAmount) && (this.sendMethod.type != SendMethodType.Easy || w.availableInvites) + return ( + w.balance.spendableAmount > 0 && + w.balance.spendableAmount >= passedAmount && + (this.sendMethod.type != SendMethodType.Easy || w.availableInvites) + ); }); } } } selectWallet() { - const modal = this.modalCtrl.create('SelectWalletModal', + const modal = this.modalCtrl.create( + 'SelectWalletModal', { selectedWallet: this.selectedWallet, showInvites: this.sendMethod.type == SendMethodType.Easy, availableWallets: this.wallets.filter(w => { return w.balance.spendableAmount && (this.sendMethod.type != SendMethodType.Easy || w.availableInvites); - }) - }, MERIT_MODAL_OPTS); + }), + }, + MERIT_MODAL_OPTS, + ); - modal.onDidDismiss(async (wallet) => { + modal.onDidDismiss(async wallet => { if (wallet) { this.selectedWallet = wallet; this.updateTxData(); @@ -153,13 +163,15 @@ export class SendAmountView { modal.present(); } - showFeeIncludedTooltip() { - this.alertCtrl.create({ - title: 'Include fee', - message: 'If you choose this option, amount size that recipient receives will be reduced by fee size. Otherwise fee will be charged from your balance', - buttons: ['Got it'] - }).present(); + this.alertCtrl + .create({ + title: 'Include fee', + message: + 'If you choose this option, amount size that recipient receives will be reduced by fee size. Otherwise fee will be charged from your balance', + buttons: ['Got it'], + }) + .present(); } async selectCurrency(currency) { @@ -235,7 +247,7 @@ export class SendAmountView { this.amount.fiat = parseFloat(this.formData.amount) || 0; this.amount.micros = await this.rateService.fiatToMicros(this.amount.fiat, this.availableUnits[1].name); this.amount.mrt = this.rateService.microsToMrt( - await this.rateService.fiatToMicros(this.amount.fiat, this.availableUnits[1].name) + await this.rateService.fiatToMicros(this.amount.fiat, this.availableUnits[1].name), ); } @@ -253,10 +265,10 @@ export class SendAmountView { public isSendAllowed() { return ( - this.amount.micros > 0 - && this.selectedWallet - && !this.feeCalcError - && (!this.formData.password || this.formData.password === this.formData.confirmPassword) + this.amount.micros > 0 && + this.selectedWallet && + !this.feeCalcError && + (!this.formData.password || this.formData.password === this.formData.confirmPassword) ); } @@ -269,10 +281,9 @@ export class SendAmountView { } public async toConfirm() { - const loader = this.loadingCtrl.create({ content: 'Calculating fee...', - dismissOnPageChange: true + dismissOnPageChange: true, }); loader.present(); @@ -287,46 +298,50 @@ export class SendAmountView { } try { - const fee = await this.sendService.estimateFee(this.selectedWallet, this.amount .micros, ( this.sendMethod.type == SendMethodType.Easy), this.sendMethod.value); - if (this.formData.password && (this.formData.password !=this.formData.confirmPassword)) { this.feeCalcError = 'Passwords do not match'; + const fee = await this.sendService.estimateFee( + this.selectedWallet, + this.amount.micros, + this.sendMethod.type == SendMethodType.Easy, + this.sendMethod.value, + ); + if (this.formData.password && this.formData.password != this.formData.confirmPassword) { + this.feeCalcError = 'Passwords do not match'; } - this.navCtrl.push('SendConfirmationView', { txData: { - amount:this.amount.micros, - password: this.formData.password, - fee: fee, - wallet: this.selectedWallet, - feeIncluded: this.feeIncluded, - sendMethod: this.sendMethod, - toAddress: this.sendMethod.value || 'MeritMoney link', - recipient: this.recipient }}); + this.navCtrl.push('SendConfirmationView', { + txData: { + amount: this.amount.micros, + password: this.formData.password, + fee: fee, + wallet: this.selectedWallet, + feeIncluded: this.feeIncluded, + sendMethod: this.sendMethod, + toAddress: this.sendMethod.value || 'MeritMoney link', + recipient: this.recipient, + }, + }); } catch (e) { this.logger.warn(e); - return this.feeCalcError = e.message; + return (this.feeCalcError = e.message); } finally { loader.dismiss(); } - } - public async updateTxData() { - //this.feeLoading = true; this.feeCalcError = null; this.feePercent = null; if (!this.selectedWallet) { - return this.feeCalcError = 'No wallet selected'; + return (this.feeCalcError = 'No wallet selected'); } if (this.amount.micros > this.selectedWallet.balance.spendableAmount) { - return this.feeCalcError = 'Amount is too big'; + return (this.feeCalcError = 'Amount is too big'); } - if (this.formData.password && (this.formData.password != this.formData.confirmPassword)) { - return this.feeCalcError = 'Passwords do not match'; + if (this.formData.password && this.formData.password != this.formData.confirmPassword) { + return (this.feeCalcError = 'Passwords do not match'); } } - - } diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-confirmation/send-confirmation.module.ts b/packages/lightwallet/mobile/src/app/transact/send/send-confirmation/send-confirmation.module.ts index 8964223dba..161e2ac22a 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-confirmation/send-confirmation.module.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-confirmation/send-confirmation.module.ts @@ -5,14 +5,7 @@ import { ComponentsModule } from '../../../../components/components.module'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; @NgModule({ - declarations: [ - SendConfirmationView, - ], - imports: [ - IonicPageModule.forChild(SendConfirmationView), - ComponentsModule, - CommonPipesModule - ], + declarations: [SendConfirmationView], + imports: [IonicPageModule.forChild(SendConfirmationView), ComponentsModule, CommonPipesModule], }) -export class SendConfirmationModule { -} +export class SendConfirmationModule {} diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-confirmation/send-confirmation.ts b/packages/lightwallet/mobile/src/app/transact/send/send-confirmation/send-confirmation.ts index c41d4c7130..9a8863dad0 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-confirmation/send-confirmation.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-confirmation/send-confirmation.ts @@ -11,26 +11,25 @@ import { WalletService } from '@merit/common/services/wallet.service'; import { TouchIdService } from '@merit/mobile/services/touch-id.service'; import { AlertController, IonicPage, LoadingController, NavController, NavParams } from 'ionic-angular'; - @IonicPage() @Component({ selector: 'view-send-confirmation', - templateUrl: 'send-confirmation.html' + templateUrl: 'send-confirmation.html', }) export class SendConfirmationView { - txData: ISendTxData; viewData: any; unlockValue: number = 0; - constructor(private navParams: NavParams, - private navCtrl: NavController, - private toastCtrl: ToastControllerService, - private alertController: AlertController, - private loadingCtrl: LoadingController, - private rateService: RateService, - private logger: LoggerService, - private sendService: SendService + constructor( + private navParams: NavParams, + private navCtrl: NavController, + private toastCtrl: ToastControllerService, + private alertController: AlertController, + private loadingCtrl: LoadingController, + private rateService: RateService, + private logger: LoggerService, + private sendService: SendService, ) { this.txData = navParams.get('txData'); } @@ -44,7 +43,6 @@ export class SendConfirmationView { } async ngOnInit() { - const viewData: any = { recipient: this.txData.recipient, amount: this.txData.amount, @@ -57,7 +55,7 @@ export class SendConfirmationView { feeIncluded: this.txData.feeIncluded, methodName: this.txData.sendMethod.type == SendMethodType.Easy ? 'MeritMoney Link' : 'Classic Send', destination: this.txData.sendMethod.alias ? '@' + this.txData.sendMethod.alias : this.txData.sendMethod.value, - easySendDelivered: this.navParams.get('easySendDelivered') + easySendDelivered: this.navParams.get('easySendDelivered'), }; viewData.walletRemainingBalance = this.txData.wallet.balance.totalAmount - viewData.totalAmount; @@ -78,23 +76,28 @@ export class SendConfirmationView { } async send() { - const loadingSpinner = this.loadingCtrl.create({ content: 'Sending transaction...', - dismissOnPageChange: true + dismissOnPageChange: true, }); loadingSpinner.present(); try { - await this.sendService.send(this.txData.wallet, this.txData); if (this.txData.sendMethod.type === SendMethodType.Easy) { let easySendDelivered; - if (this.txData.sendMethod.destination === SendMethodDestination.Email || this.txData.sendMethod.destination === SendMethodDestination.Sms) { + if ( + this.txData.sendMethod.destination === SendMethodDestination.Email || + this.txData.sendMethod.destination === SendMethodDestination.Sms + ) { try { - await this.txData.wallet.deliverGlobalSend(this.txData.easySend, { type: SendMethodType.Easy, destination: this.txData.sendMethod.destination, value: this.txData.sendMethod.value }); + await this.txData.wallet.deliverGlobalSend(this.txData.easySend, { + type: SendMethodType.Easy, + destination: this.txData.sendMethod.destination, + value: this.txData.sendMethod.value, + }); easySendDelivered = true; } catch (err) { this.logger.error('Unable to deliver GlobalSend', err); @@ -118,10 +121,12 @@ export class SendConfirmationView { getContactInitials(contact) { if (!contact.name || !contact.name.formatted) return ''; - let nameParts = contact.name.formatted.toUpperCase().replace(/\s\s+/g, ' ').split(' '); + let nameParts = contact.name.formatted + .toUpperCase() + .replace(/\s\s+/g, ' ') + .split(' '); let name = nameParts[0].charAt(0); if (nameParts[1]) name += ' ' + nameParts[1].charAt(0); return name; } - } diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-create-contact/send-create-contact.module.ts b/packages/lightwallet/mobile/src/app/transact/send/send-create-contact/send-create-contact.module.ts index 1c970ba4d3..19a39cf62f 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-create-contact/send-create-contact.module.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-create-contact/send-create-contact.module.ts @@ -4,13 +4,7 @@ import { DirectivesModule } from '@merit/mobile/directives/directives.module'; import { SendCreateContactView } from './send-create-contact'; @NgModule({ - declarations: [ - SendCreateContactView, - ], - imports: [ - IonicPageModule.forChild(SendCreateContactView), - DirectivesModule - ], + declarations: [SendCreateContactView], + imports: [IonicPageModule.forChild(SendCreateContactView), DirectivesModule], }) -export class SendCreateContactModule { -} +export class SendCreateContactModule {} diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-create-contact/send-create-contact.ts b/packages/lightwallet/mobile/src/app/transact/send/send-create-contact/send-create-contact.ts index 4cb28e02ee..d61638b863 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-create-contact/send-create-contact.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-create-contact/send-create-contact.ts @@ -13,25 +13,25 @@ import { ToastControllerService, IMeritToastConfig } from '@merit/common/service templateUrl: 'send-create-contact.html', }) export class SendCreateContactView { - contact: MeritContact; amount: number; newAddress: string; - constructor(navParams: NavParams, - private contactsService: ContactsService, - private addressService: AddressService, - private toastController: ToastControllerService, - private viewCtrl: ViewController) { + constructor( + navParams: NavParams, + private contactsService: ContactsService, + private addressService: AddressService, + private toastController: ToastControllerService, + private viewCtrl: ViewController, + ) { this.contact = new MeritContact(); this.contact.meritAddresses.push(navParams.get('address')); } save() { - return this.contactsService.add(this.contact, this.contact.meritAddresses[0].address, ENV.network) - .then(() => { - this.viewCtrl.dismiss(this.contact); - }); + return this.contactsService.add(this.contact, this.contact.meritAddresses[0].address, ENV.network).then(() => { + this.viewCtrl.dismiss(this.contact); + }); } cancel() { @@ -54,7 +54,7 @@ export class SendCreateContactView { const meritAddress: IMeritAddress = { network: ENV.network, address: info.address, - alias: info.alias + alias: info.alias, }; this.contact.meritAddresses.push(meritAddress); @@ -62,11 +62,12 @@ export class SendCreateContactView { } removeAddress(meritAddress) { - this.contact.meritAddresses = this.contact.meritAddresses.filter(mAddress => mAddress.address != meritAddress.address); + this.contact.meritAddresses = this.contact.meritAddresses.filter( + mAddress => mAddress.address != meritAddress.address, + ); } isSaveAvailable() { return this.contact.name.formatted && this.contact.meritAddresses.length; } - } diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-edit-contact/send-edit-contact.module.ts b/packages/lightwallet/mobile/src/app/transact/send/send-edit-contact/send-edit-contact.module.ts index b61640a990..0de236e79f 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-edit-contact/send-edit-contact.module.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-edit-contact/send-edit-contact.module.ts @@ -4,13 +4,7 @@ import { DirectivesModule } from '@merit/mobile/directives/directives.module'; import { SendEditContactView } from './send-edit-contact'; @NgModule({ - declarations: [ - SendEditContactView, - ], - imports: [ - IonicPageModule.forChild(SendEditContactView), - DirectivesModule - ], + declarations: [SendEditContactView], + imports: [IonicPageModule.forChild(SendEditContactView), DirectivesModule], }) -export class SendEditContactModule { -} +export class SendEditContactModule {} diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-edit-contact/send-edit-contact.ts b/packages/lightwallet/mobile/src/app/transact/send/send-edit-contact/send-edit-contact.ts index 3a0e4f9c2a..a623741ca2 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-edit-contact/send-edit-contact.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-edit-contact/send-edit-contact.ts @@ -17,27 +17,30 @@ export class SendEditContactView { contact: MeritContact; newAddress: string = ''; - private actions: Array<{ type: string, mAddress: IMeritAddress }> = []; //logging all actions to properly modify addressbook + private actions: Array<{ type: string; mAddress: IMeritAddress }> = []; //logging all actions to properly modify addressbook private readonly TYPE_REMOVE = 'remove'; private readonly TYPE_ADD = 'add'; - constructor(private navCtrl: NavController, - private navParams: NavParams, - private contactsService: ContactsService, - private toastController: ToastControllerService, - private addressService: AddressService, - private alertCtrl: AlertController) { + constructor( + private navCtrl: NavController, + private navParams: NavParams, + private contactsService: ContactsService, + private toastController: ToastControllerService, + private addressService: AddressService, + private alertCtrl: AlertController, + ) { this.contact = this.navParams.get('contact'); } removeAddress(meritAddress) { this.actions.push({ type: this.TYPE_REMOVE, mAddress: meritAddress }); - this.actions = this.actions.filter((action) => { //removing fresh added address - return (action.type != this.TYPE_ADD || action.mAddress.address != meritAddress.address); + this.actions = this.actions.filter(action => { + //removing fresh added address + return action.type != this.TYPE_ADD || action.mAddress.address != meritAddress.address; }); this.contact.meritAddresses = this.contact.meritAddresses.filter(mAddress => { - return (mAddress.address != meritAddress.address); + return mAddress.address != meritAddress.address; }); } @@ -57,7 +60,7 @@ export class SendEditContactView { const meritAddress: IMeritAddress = { network: ENV.network, address: info.address, - alias: info.alias + alias: info.alias, }; this.actions.push({ type: this.TYPE_ADD, mAddress: meritAddress }); @@ -67,14 +70,14 @@ export class SendEditContactView { async save() { const removalPromises = []; - this.actions.forEach((action) => { + this.actions.forEach(action => { if (action.type == this.TYPE_REMOVE) { removalPromises.push(this.contactsService.remove(action.mAddress.address, action.mAddress.network)); } }); //removing all entities with existing addresses key - this.contact.meritAddresses.forEach((mAddress) => { + this.contact.meritAddresses.forEach(mAddress => { removalPromises.push(this.contactsService.remove(mAddress.address, mAddress.network)); }); @@ -91,7 +94,7 @@ export class SendEditContactView { // we are able to delete merit contacts and edit name property, instead of contacts in device address book isMeritContact() { - return (!this.contact.phoneNumbers.length && !this.contact.emails.length); + return !this.contact.phoneNumbers.length && !this.contact.emails.length; } isSaveAvailable() { @@ -100,25 +103,29 @@ export class SendEditContactView { deleteContact() { let remove = () => { - this.contact.meritAddresses.forEach((m) => { + this.contact.meritAddresses.forEach(m => { this.removeAddress(m); }); return this.save(); }; - this.alertCtrl.create({ - title: `Are you sure want to delete this contact?`, - buttons: [ - { - text: 'Cancel', role: 'cancel', handler: () => { - } - }, - { - text: 'Delete', handler: () => { - remove(); - } - } - ] - }).present(); + this.alertCtrl + .create({ + title: `Are you sure want to delete this contact?`, + buttons: [ + { + text: 'Cancel', + role: 'cancel', + handler: () => {}, + }, + { + text: 'Delete', + handler: () => { + remove(); + }, + }, + ], + }) + .present(); } } diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-fee/send-fee.module.ts b/packages/lightwallet/mobile/src/app/transact/send/send-fee/send-fee.module.ts index a0f1f34e92..bf38b4f870 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-fee/send-fee.module.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-fee/send-fee.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { SendFeeView } from './send-fee'; @NgModule({ - declarations: [ - SendFeeView, - ], - imports: [ - IonicPageModule.forChild(SendFeeView), - ], + declarations: [SendFeeView], + imports: [IonicPageModule.forChild(SendFeeView)], }) -export class SendFeeModule { -} +export class SendFeeModule {} diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-fee/send-fee.ts b/packages/lightwallet/mobile/src/app/transact/send/send-fee/send-fee.ts index b45191b072..20dbec6050 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-fee/send-fee.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-fee/send-fee.ts @@ -7,12 +7,10 @@ import { IonicPage, NavParams, ViewController } from 'ionic-angular'; templateUrl: 'send-fee.html', }) export class SendFeeView { - - feeLevels: Array<{ name: string, amount: number, nbBlocks: number }>; + feeLevels: Array<{ name: string; amount: number; nbBlocks: number }>; selectedLevelName: string; - constructor(private navParams: NavParams, - private viewCtrl: ViewController) { + constructor(private navParams: NavParams, private viewCtrl: ViewController) { this.feeLevels = this.navParams.get('feeLevels'); this.selectedLevelName = this.navParams.get('selectedLevelName'); } diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-select-bind-contact/send-select-bind-contact.module.ts b/packages/lightwallet/mobile/src/app/transact/send/send-select-bind-contact/send-select-bind-contact.module.ts index 35a012cf64..742a233824 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-select-bind-contact/send-select-bind-contact.module.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-select-bind-contact/send-select-bind-contact.module.ts @@ -4,13 +4,7 @@ import { SendSelectBindContactView } from './send-select-bind-contact'; import { ComponentsModule } from '../../../../components/components.module'; @NgModule({ - declarations: [ - SendSelectBindContactView, - ], - imports: [ - IonicPageModule.forChild(SendSelectBindContactView), - ComponentsModule - ], + declarations: [SendSelectBindContactView], + imports: [IonicPageModule.forChild(SendSelectBindContactView), ComponentsModule], }) -export class SendSelectBindContactModule { -} +export class SendSelectBindContactModule {} diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-select-bind-contact/send-select-bind-contact.ts b/packages/lightwallet/mobile/src/app/transact/send/send-select-bind-contact/send-select-bind-contact.ts index 6b36e36b36..cbd604eba8 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-select-bind-contact/send-select-bind-contact.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-select-bind-contact/send-select-bind-contact.ts @@ -9,16 +9,17 @@ import { ContactsService } from '@merit/common/services/contacts.service'; templateUrl: 'send-select-bind-contact.html', }) export class SendSelectBindContactView { - public contacts: Array; public foundContacts: Array = []; public searchQuery: string = ''; - public meritAddress: { address: string, network: string, alias: string }; + public meritAddress: { address: string; network: string; alias: string }; - constructor(private navParams: NavParams, - private viewCtrl: ViewController, - private contactsService: ContactsService, - private alertCtrl: AlertController) { + constructor( + private navParams: NavParams, + private viewCtrl: ViewController, + private contactsService: ContactsService, + private alertCtrl: AlertController, + ) { this.contacts = this.navParams.get('contacts'); this.meritAddress = this.navParams.get('address'); } @@ -32,28 +33,36 @@ export class SendSelectBindContactView { } select(contact) { - this.alertCtrl.create({ - title: `Bind this address to contact '${contact.name.formatted}'?`, - buttons: [ - { - text: 'Cancel', role: 'cancel', handler: () => { - } - }, - { - text: 'Bind', handler: () => { - this.contactsService.bindAddressToContact(contact, this.meritAddress.address, this.meritAddress.alias) - .then((contact) => { - this.viewCtrl.dismiss(contact); - }); - } - } - ] - }).present(); + this.alertCtrl + .create({ + title: `Bind this address to contact '${contact.name.formatted}'?`, + buttons: [ + { + text: 'Cancel', + role: 'cancel', + handler: () => {}, + }, + { + text: 'Bind', + handler: () => { + this.contactsService + .bindAddressToContact(contact, this.meritAddress.address, this.meritAddress.alias) + .then(contact => { + this.viewCtrl.dismiss(contact); + }); + }, + }, + ], + }) + .present(); } getContactInitials(contact) { if (!contact.name || !contact.name.formatted) return ''; - let nameParts = contact.name.formatted.toUpperCase().replace(/\s\s+/g, ' ').split(' '); + let nameParts = contact.name.formatted + .toUpperCase() + .replace(/\s\s+/g, ' ') + .split(' '); let name = nameParts[0].charAt(0); if (nameParts[1]) name += ' ' + nameParts[1].charAt(0); return name; @@ -66,12 +75,15 @@ export class SendSelectBindContactView { parseSearch() { if (!this.searchQuery) { - return this.foundContacts = this.contacts; + return (this.foundContacts = this.contacts); } - this.foundContacts = this.contacts.filter((contact) => { - return (!!contact.name && !!contact.name.formatted && contact.name.formatted.toLowerCase().match(this.searchQuery.toLowerCase())); + this.foundContacts = this.contacts.filter(contact => { + return ( + !!contact.name && + !!contact.name.formatted && + contact.name.formatted.toLowerCase().match(this.searchQuery.toLowerCase()) + ); }); } - } diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-valid-till/send-valid-till.module.ts b/packages/lightwallet/mobile/src/app/transact/send/send-valid-till/send-valid-till.module.ts index 2b49a486cd..e0083ec905 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-valid-till/send-valid-till.module.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-valid-till/send-valid-till.module.ts @@ -3,11 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { SendValidTillView } from './send-valid-till'; @NgModule({ - declarations: [ - SendValidTillView, - ], - imports: [ - IonicPageModule.forChild(SendValidTillView), - ], + declarations: [SendValidTillView], + imports: [IonicPageModule.forChild(SendValidTillView)], }) export class SendValidTillModule {} diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-valid-till/send-valid-till.ts b/packages/lightwallet/mobile/src/app/transact/send/send-valid-till/send-valid-till.ts index 64f56e7f04..c5ada73196 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-valid-till/send-valid-till.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-valid-till/send-valid-till.ts @@ -6,5 +6,4 @@ import { IonicPage } from 'ionic-angular'; selector: 'view-send-valid-till', templateUrl: 'send-valid-till.html', }) -export class SendValidTillView { -} +export class SendValidTillView {} diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-via/send-via.module.ts b/packages/lightwallet/mobile/src/app/transact/send/send-via/send-via.module.ts index 3dc4e93526..82a00fa716 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-via/send-via.module.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-via/send-via.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { SendViaView } from './send-via'; @NgModule({ - declarations: [ - SendViaView, - ], - imports: [ - IonicPageModule.forChild(SendViaView), - ], + declarations: [SendViaView], + imports: [IonicPageModule.forChild(SendViaView)], }) -export class SendViaModule { -} +export class SendViaModule {} diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-via/send-via.ts b/packages/lightwallet/mobile/src/app/transact/send/send-via/send-via.ts index a8bc7e945e..e137d90bdd 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-via/send-via.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-via/send-via.ts @@ -23,7 +23,6 @@ const searchIn = (method: ISendMethod) => { templateUrl: 'send-via.html', }) export class SendViaView { - public contact: MeritContact; public amount: number; public highlightedMethod: ISendMethod; @@ -31,10 +30,12 @@ export class SendViaView { public easySendEnabled: boolean; - constructor(private viewCtrl: ViewController, - private navParams: NavParams, - private alertCtrl: AlertController, - private addressService: AddressService) { + constructor( + private viewCtrl: ViewController, + private navParams: NavParams, + private alertCtrl: AlertController, + private addressService: AddressService, + ) { this.contact = this.navParams.get('contact'); this.amount = this.navParams.get('amount'); this.suggestedMethod = this.navParams.get('suggestedMethod'); @@ -50,19 +51,16 @@ export class SendViaView { } if (!this.highlightedMethod) { - this.addressService.getSendHistory().then((sendHistory) => { - sendHistory - .sort((a, b) => b.timestamp - a.timestamp) - .some((record) => { - const entities: any[] = this.contact[searchIn(this.suggestedMethod)]; - if (entities.some(entity => entity.value == record.method.value)) { - this.highlightedMethod = record; - return true; - } - }); + this.addressService.getSendHistory().then(sendHistory => { + sendHistory.sort((a, b) => b.timestamp - a.timestamp).some(record => { + const entities: any[] = this.contact[searchIn(this.suggestedMethod)]; + if (entities.some(entity => entity.value == record.method.value)) { + this.highlightedMethod = record; + return true; + } + }); }); } - } } @@ -78,28 +76,34 @@ export class SendViaView { return this.viewCtrl.dismiss({ contact: this.contact, amount: this.amount, - suggestedMethod: { type, destination, value, alias } + suggestedMethod: { type, destination, value, alias }, }); } showClassicTooltip() { - return this.showTooltip('Classic Send', - 'ClassicSend transactions do not have power of EasySend, but fee size is lower.'); + return this.showTooltip( + 'Classic Send', + 'ClassicSend transactions do not have power of EasySend, but fee size is lower.', + ); } showEasyTooltip() { - return this.showTooltip('Easy Send', - 'EasySend transactions could be returned, password protected and limited by expiration time. You can send Merit either to existing merit address or share a link via sms/email'); + return this.showTooltip( + 'Easy Send', + 'EasySend transactions could be returned, password protected and limited by expiration time. You can send Merit either to existing merit address or share a link via sms/email', + ); } cancel() { this.viewCtrl.dismiss(); } private showTooltip(title, message) { - return this.alertCtrl.create({ - title, message, - buttons: ['Got it'] - }).present(); + return this.alertCtrl + .create({ + title, + message, + buttons: ['Got it'], + }) + .present(); } - } diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-wallet/send-wallet.module.ts b/packages/lightwallet/mobile/src/app/transact/send/send-wallet/send-wallet.module.ts index 2c0182437a..bc6a7e12c5 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-wallet/send-wallet.module.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-wallet/send-wallet.module.ts @@ -4,13 +4,7 @@ import { SendWalletView } from './send-wallet'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; @NgModule({ - declarations: [ - SendWalletView, - ], - imports: [ - CommonPipesModule, - IonicPageModule.forChild(SendWalletView), - ], + declarations: [SendWalletView], + imports: [CommonPipesModule, IonicPageModule.forChild(SendWalletView)], }) -export class SensWalletModule { -} +export class SensWalletModule {} diff --git a/packages/lightwallet/mobile/src/app/transact/send/send-wallet/send-wallet.ts b/packages/lightwallet/mobile/src/app/transact/send/send-wallet/send-wallet.ts index 5c4917fd6e..085c4dca33 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send-wallet/send-wallet.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send-wallet/send-wallet.ts @@ -1,20 +1,16 @@ import { Component } from '@angular/core'; import { IonicPage, NavParams, ViewController } from 'ionic-angular'; - @IonicPage() @Component({ selector: 'view-send-wallet', templateUrl: 'send-wallet.html', }) export class SendWalletView { - wallets; selectedWallet; - constructor(private navParams: NavParams, - private viewCtrl: ViewController) { - } + constructor(private navParams: NavParams, private viewCtrl: ViewController) {} async ionViewDidLoad() { this.selectedWallet = this.navParams.get('selectedWallet'); @@ -28,5 +24,4 @@ export class SendWalletView { select(wallet) { this.viewCtrl.dismiss(wallet); } - } diff --git a/packages/lightwallet/mobile/src/app/transact/send/send.module.ts b/packages/lightwallet/mobile/src/app/transact/send/send.module.ts index eb7d254fe4..24e7971870 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send.module.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send.module.ts @@ -4,13 +4,7 @@ import { SendView } from '@merit/mobile/app/transact/send/send'; import { ComponentsModule } from '../../../components/components.module'; @NgModule({ - declarations: [ - SendView, - ], - imports: [ - IonicPageModule.forChild(SendView), - ComponentsModule - ] + declarations: [SendView], + imports: [IonicPageModule.forChild(SendView), ComponentsModule], }) -export class SendViewModule { -} +export class SendViewModule {} diff --git a/packages/lightwallet/mobile/src/app/transact/send/send.ts b/packages/lightwallet/mobile/src/app/transact/send/send.ts index 5064ad48dc..c57a70f64f 100644 --- a/packages/lightwallet/mobile/src/app/transact/send/send.ts +++ b/packages/lightwallet/mobile/src/app/transact/send/send.ts @@ -20,11 +20,11 @@ const ERROR_ALIAS_NOT_FOUND = 'ALIAS_NOT_FOUND'; @IonicPage() @Component({ selector: 'view-send', - templateUrl: 'send.html' + templateUrl: 'send.html', }) export class SendView { - - @ViewChild(Slides) slides: Slides; + @ViewChild(Slides) + slides: Slides; get sliderIsFinished(): boolean { return this.slides.isEnd(); @@ -37,9 +37,9 @@ export class SendView { contacts: Array = []; amount: number; searchResult: { - contacts: Array, - toNewEntity: { destination: string, contact: MeritContact }, - error: string + contacts: Array; + toNewEntity: { destination: string; contact: MeritContact }; + error: string; } = { contacts: [], toNewEntity: null, error: null }; hasUnlockedWallets: boolean; @@ -50,20 +50,19 @@ export class SendView { searchInProgress: boolean; - constructor(private navCtrl: NavController, - private navParams: NavParams, - private contactsService: ContactsService, - private profileService: ProfileService, - private addressService: AddressService, - private modalCtrl: ModalController, - private addressScanner: AddressScannerService, - private persistenceService: PersistenceService, - private events: Events, - private toastCtrl: ToastController, - private rateService: RateService - ) { - - } + constructor( + private navCtrl: NavController, + private navParams: NavParams, + private contactsService: ContactsService, + private profileService: ProfileService, + private addressService: AddressService, + private modalCtrl: ModalController, + private addressScanner: AddressScannerService, + private persistenceService: PersistenceService, + private events: Events, + private toastCtrl: ToastController, + private rateService: RateService, + ) {} private async updateHasUnlocked() { const wallets = await this.profileService.getWallets(); @@ -71,7 +70,7 @@ export class SendView { this.hasActiveInvites = wallets.some(w => w.availableInvites > 0); let pagesVisited = await this.persistenceService.getPagesVisited(); - this.showSlider = (pagesVisited.indexOf('send') == -1); + this.showSlider = pagesVisited.indexOf('send') == -1; this.showSlider = false; // temporary disabled } @@ -90,7 +89,7 @@ export class SendView { this.contacts = await this.contactsService.getAllMeritContacts(); this.loadingContacts = false; await this.updateRecentContacts(); - await this.parseSearch(); + await this.parseSearch(); this.events.subscribe('Remote:IncomingTx', () => { this.updateHasUnlocked(); @@ -103,20 +102,18 @@ export class SendView { let results, contact; - sendHistory - .sort((a, b) => b.timestamp - a.timestamp) - .forEach((record) => { - results = this.contactsService.searchContacts(this.contacts, record.method.value); - if (results && results.length) { - recentContacts.push(results[0]); - results = void 0; - } else { - contact = new MeritContact(); - contact.name.formatted = record.method.alias ? '@' + record.method.alias : record.method.value; - recentContacts.push(contact); - contact = void 0; - } - }); + sendHistory.sort((a, b) => b.timestamp - a.timestamp).forEach(record => { + results = this.contactsService.searchContacts(this.contacts, record.method.value); + if (results && results.length) { + recentContacts.push(results[0]); + results = void 0; + } else { + contact = new MeritContact(); + contact.name.formatted = record.method.alias ? '@' + record.method.alias : record.method.value; + recentContacts.push(contact); + contact = void 0; + } + }); this.recentContacts = _.uniqBy(recentContacts, 'name.formatted'); } @@ -130,7 +127,7 @@ export class SendView { this.debounceSearch.cancel(); this.searchInProgress = false; result.contacts = this.contacts; - return this.searchResult = result; + return (this.searchResult = result); } if (this.searchQuery.length > 6 && this.searchQuery.indexOf('merit:') == 0) { @@ -150,13 +147,11 @@ export class SendView { private debounceSearch = _.debounce(() => this.search(), 500); - /** * Search users based on searchQuery * Looks both for contact list and for address/alias */ private async search() { - const result = { contacts: [], toNewEntity: null, error: null }; let input = cleanAddress(this.searchQuery.split('?')[0]); @@ -168,16 +163,16 @@ export class SendView { result.toNewEntity.contact.meritAddresses.push({ address: addressInfo.address, alias: addressInfo.alias, - network: ENV.network + network: ENV.network, }); } } result.contacts = this.contacts.filter(contact => - _.some(contact.meritAddresses, (meritAddress) => { + _.some(contact.meritAddresses, meritAddress => { if (meritAddress.address == input) return true; - return (meritAddress.alias && meritAddress.alias.match(input)); - }) + return meritAddress.alias && meritAddress.alias.match(input); + }), ); this.searchResult = result; @@ -204,10 +199,10 @@ export class SendView { addContact() { let meritAddress = { address: null, - network: null + network: null, }; let modal = this.modalCtrl.create('SendCreateContactView'); - modal.onDidDismiss((contact) => { + modal.onDidDismiss(contact => { this.navCtrl.pop(); }); modal.present(); @@ -216,7 +211,7 @@ export class SendView { createContact() { let meritAddress = this.searchResult.toNewEntity.contact.meritAddresses[0]; let modal = this.modalCtrl.create('SendCreateContactView', { address: meritAddress }); - modal.onDidDismiss((contact) => { + modal.onDidDismiss(contact => { if (contact) { this.navCtrl.push('SendAmountView', { contact: contact, @@ -227,8 +222,8 @@ export class SendView { type: SendMethodType.Classic, destination: SendMethodDestination.Address, value: meritAddress.address, - alias: meritAddress.alias - } + alias: meritAddress.alias, + }, }); } }); @@ -238,7 +233,7 @@ export class SendView { bindAddressToContact() { let meritAddress = this.searchResult.toNewEntity.contact.meritAddresses[0]; let modal = this.modalCtrl.create('SendSelectBindContactView', { contacts: this.contacts, address: meritAddress }); - modal.onDidDismiss((contact) => { + modal.onDidDismiss(contact => { if (contact) { this.navCtrl.push('SendViaView', { contact: contact, @@ -249,8 +244,8 @@ export class SendView { type: SendMethodType.Classic, destination: SendMethodDestination.Address, value: meritAddress.address, - alias: meritAddress.alias - } + alias: meritAddress.alias, + }, }); } }); @@ -267,17 +262,20 @@ export class SendView { type: SendMethodType.Classic, destination: SendMethodDestination.Address, value: contact.meritAddresses[0].address, - alias: contact.meritAddresses[0].alias - } + alias: contact.meritAddresses[0].alias, + }, }); } else { - let modal = this.modalCtrl.create('SendViaView', { + let modal = this.modalCtrl.create( + 'SendViaView', + { contact: contact, - amount: this.amount - }, MERIT_MODAL_OPTS + amount: this.amount, + }, + MERIT_MODAL_OPTS, ); - modal.onDidDismiss((params) => { + modal.onDidDismiss(params => { if (params) { params.amount = this.amount; params.wallet = this.wallet; @@ -303,8 +301,8 @@ export class SendView { type: SendMethodType.Classic, destination: SendMethodDestination.Address, value: entity.contact.meritAddresses[0].address, - alias: entity.contact.meritAddresses[0].alias - } + alias: entity.contact.meritAddresses[0].alias, + }, }); } @@ -318,13 +316,13 @@ export class SendView { this.toastCtrl.create({ message: 'You do not have any available invites to use MeritMoney', duration: 4000, - showCloseButton: true + showCloseButton: true, }); return; } this.navCtrl.push('SendAmountView', { - suggestedMethod: { type: SendMethodType.Easy, wallet: this.wallet } + suggestedMethod: { type: SendMethodType.Easy, wallet: this.wallet }, }); } diff --git a/packages/lightwallet/mobile/src/app/transact/transact.module.ts b/packages/lightwallet/mobile/src/app/transact/transact.module.ts index 657c41c581..6367f3afc7 100644 --- a/packages/lightwallet/mobile/src/app/transact/transact.module.ts +++ b/packages/lightwallet/mobile/src/app/transact/transact.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { TransactView } from '@merit/mobile/app/transact/transact'; @NgModule({ - declarations: [ - TransactView, - ], - imports: [ - IonicPageModule.forChild(TransactView), - ] + declarations: [TransactView], + imports: [IonicPageModule.forChild(TransactView)], }) -export class TransactModule { -} +export class TransactModule {} diff --git a/packages/lightwallet/mobile/src/app/transact/transact.ts b/packages/lightwallet/mobile/src/app/transact/transact.ts index a918b31623..a49b1b08c7 100644 --- a/packages/lightwallet/mobile/src/app/transact/transact.ts +++ b/packages/lightwallet/mobile/src/app/transact/transact.ts @@ -5,53 +5,45 @@ import { EasyReceiveService } from '@merit/common/services/easy-receive.service' import { LoggerService } from '@merit/common/services/logger.service'; import { ProfileService } from '@merit/common/services/profile.service'; import { UnlockRequestService } from '@merit/common/services/unlock-request.service'; -import { - AlertController, - IonicPage, - ModalController, - NavController, - NavParams, - Platform, - Tabs -} from 'ionic-angular'; +import { AlertController, IonicPage, ModalController, NavController, NavParams, Platform, Tabs } from 'ionic-angular'; import { debounceTime, startWith, tap } from 'rxjs/operators'; import { Subscription } from 'rxjs/Subscription'; import { PersistenceService2, UserSettingsKey } from '@merit/common/services/persistence2.service'; import { SmsNotificationsService } from '@merit/common/services/sms-notifications.service'; - @IonicPage({ - segment: 'transact' + segment: 'transact', }) @Component({ selector: 'view-transact', templateUrl: 'transact.html', host: { - '[class.keyboard-visible]': 'keyboardVisible' - } + '[class.keyboard-visible]': 'keyboardVisible', + }, }) export class TransactView { - @ViewChild('tabs') tabs: Tabs; + @ViewChild('tabs') + tabs: Tabs; private subs: Subscription[] = []; keyboardVisible: boolean = false; - constructor(public navCtrl: NavController, - public navParams: NavParams, - private logger: LoggerService, - private profileService: ProfileService, - private plt: Platform, - private keyboard: Keyboard, - private unlockRequestService: UnlockRequestService, - private easyReceiveService: EasyReceiveService, - private alertCtrl: AlertController, - private modalCtrl: ModalController, - private persistenceService2: PersistenceService2, - private smsNotificationsService: SmsNotificationsService) { - } + constructor( + public navCtrl: NavController, + public navParams: NavParams, + private logger: LoggerService, + private profileService: ProfileService, + private plt: Platform, + private keyboard: Keyboard, + private unlockRequestService: UnlockRequestService, + private easyReceiveService: EasyReceiveService, + private alertCtrl: AlertController, + private modalCtrl: ModalController, + private persistenceService2: PersistenceService2, + private smsNotificationsService: SmsNotificationsService, + ) {} async ngOnInit() { - if (this.navParams.get('unlockUrl')) { window.location.href = this.navParams.get('unlockUrl'); } @@ -63,26 +55,22 @@ export class TransactView { debounceTime(500), tap(() => { this.processPendingEasyReceipts(); - }) + }), ) .subscribe(), - this.easyReceiveService.cancelEasySendObservable$.subscribe( - receipt => { - this.processEasyReceipt(receipt, false, '', false); - } - ) + this.easyReceiveService.cancelEasySendObservable$.subscribe(receipt => { + this.processEasyReceipt(receipt, false, '', false); + }), ); if (this.plt.is('android') && Keyboard.installed()) { this.subs.push( - this.keyboard.onKeyboardShow() - .subscribe(() => { - this.keyboardVisible = true; - }), - this.keyboard.onKeyboardHide() - .subscribe(() => { - this.keyboardVisible = false; - }) + this.keyboard.onKeyboardShow().subscribe(() => { + this.keyboardVisible = true; + }), + this.keyboard.onKeyboardHide().subscribe(() => { + this.keyboardVisible = false; + }), ); } @@ -90,13 +78,11 @@ export class TransactView { const smsPromptSetting = await this.persistenceService2.getUserSettings(UserSettingsKey.SmsNotificationsPrompt); - if (smsPromptSetting == true) - return; + if (smsPromptSetting == true) return; const smsNotificationStatus = await this.smsNotificationsService.getSmsSubscriptionStatus(); - if (smsNotificationStatus.enabled) - return; + if (smsNotificationStatus.enabled) return; const modal = this.modalCtrl.create('SmsNotificationsModal'); modal.present(); @@ -112,7 +98,7 @@ export class TransactView { } async ionViewCanEnter() { - const wallets = await this.profileService.wallets || []; + const wallets = (await this.profileService.wallets) || []; return wallets.length > 0; } @@ -133,7 +119,12 @@ export class TransactView { * @returns {Promise} * @memberof WalletsView */ - private async processEasyReceipt(receipt: EasyReceipt, isRetry: boolean, password: string = '', processAll: boolean = true) { + private async processEasyReceipt( + receipt: EasyReceipt, + isRetry: boolean, + password: string = '', + processAll: boolean = true, + ) { const data = await this.easyReceiveService.validateEasyReceiptOnBlockchain(receipt, password); let txs = data.txs; @@ -143,8 +134,7 @@ export class TransactView { txs = [txs]; } - if (!txs.length) return this.showPasswordEasyReceivePrompt(receipt, data); - + if (!txs.length) return this.showPasswordEasyReceivePrompt(receipt, data); if (txs.some(tx => tx.spent)) { await this.easyReceiveService.deletePendingReceipt(receipt); @@ -152,7 +142,7 @@ export class TransactView { return await this.processPendingEasyReceipts(); } - if (txs.some(tx => (tx.confirmations === undefined))) { + if (txs.some(tx => tx.confirmations === undefined)) { this.logger.warn('Got easyReceipt with unknown depth. It might be expired!'); return this.showEasyReceivePrompt(receipt, data); } @@ -170,8 +160,8 @@ export class TransactView { /** * Shows easy receive popup with password input. */ - private showPasswordEasyReceivePrompt(receipt: EasyReceipt,data) { - const modal = this.modalCtrl.create('GlobalsendReceiveView', {mode: 'validate', receipt, data}); + private showPasswordEasyReceivePrompt(receipt: EasyReceipt, data) { + const modal = this.modalCtrl.create('GlobalsendReceiveView', { mode: 'validate', receipt, data }); modal.onDidDismiss(() => { this.processPendingEasyReceipts(); }); @@ -182,7 +172,7 @@ export class TransactView { * @param receipt */ private showEasyReceivePrompt(receipt: EasyReceipt, data) { - const modal = this.modalCtrl.create('GlobalsendReceiveView', {mode: 'receive', receipt, data}); + const modal = this.modalCtrl.create('GlobalsendReceiveView', { mode: 'receive', receipt, data }); modal.onDidDismiss(() => { this.processPendingEasyReceipts(); }); @@ -190,25 +180,24 @@ export class TransactView { } private showSpentEasyReceiptAlert() { - this.alertCtrl.create({ - title: 'Uh oh', - message: 'It seems that the MeritLink has already been redeemed!', - buttons: [ - 'Ok' - ] - }).present(); + this.alertCtrl + .create({ + title: 'Uh oh', + message: 'It seems that the MeritLink has already been redeemed!', + buttons: ['Ok'], + }) + .present(); } private showExpiredEasyReceiptAlert() { - this.alertCtrl.create({ - title: 'Uh oh', - subTitle: 'It seems that this transaction has expired. ', - message: 'Transaction was returned to sender! ' + - 'You can ask the sender to make a new transaction.', - buttons: [ - 'Ok' - ] - }).present(); + this.alertCtrl + .create({ + title: 'Uh oh', + subTitle: 'It seems that this transaction has expired. ', + message: 'Transaction was returned to sender! ' + 'You can ask the sender to make a new transaction.', + buttons: ['Ok'], + }) + .present(); } countUnlockRequests() { diff --git a/packages/lightwallet/mobile/src/app/utilities/import/address-scanner.service.ts b/packages/lightwallet/mobile/src/app/utilities/import/address-scanner.service.ts index ef817b9f06..799833a2b8 100644 --- a/packages/lightwallet/mobile/src/app/utilities/import/address-scanner.service.ts +++ b/packages/lightwallet/mobile/src/app/utilities/import/address-scanner.service.ts @@ -9,10 +9,11 @@ export class AddressScannerService { _hasCameraPermissions: boolean; _deviceHasCamera: boolean; - constructor(private modalCtrl: ModalController, - private barcodeScanner: BarcodeScanner, - private diagnostic: Diagnostic) { - } + constructor( + private modalCtrl: ModalController, + private barcodeScanner: BarcodeScanner, + private diagnostic: Diagnostic, + ) {} async scanAddress() { let error; @@ -24,7 +25,7 @@ export class AddressScannerService { return code; } } catch (e) { - error = e == 'cordova_not_available'? 'This feature is available in native applications only.' : e; + error = e == 'cordova_not_available' ? 'This feature is available in native applications only.' : e; } } else { error = 'This feature is available in native applications only.'; @@ -49,12 +50,14 @@ export class AddressScannerService { if (typeof this._hasCameraPermissions !== 'boolean') { // we didn't check/request permissions yet.. lets do that - this._hasCameraPermissions = (await this.diagnostic.getCameraAuthorizationStatus(false)) === this.diagnostic.permissionStatus.GRANTED; + this._hasCameraPermissions = + (await this.diagnostic.getCameraAuthorizationStatus(false)) === this.diagnostic.permissionStatus.GRANTED; } if (this._hasCameraPermissions === true) return true; - this._hasCameraPermissions = (await this.diagnostic.requestCameraAuthorization(false)) === this.diagnostic.permissionStatus.GRANTED; + this._hasCameraPermissions = + (await this.diagnostic.requestCameraAuthorization(false)) === this.diagnostic.permissionStatus.GRANTED; return this._hasCameraPermissions; } diff --git a/packages/lightwallet/mobile/src/app/utilities/import/import-scan/import-scan.module.ts b/packages/lightwallet/mobile/src/app/utilities/import/import-scan/import-scan.module.ts index c4c53d6ec2..ade995dd7c 100644 --- a/packages/lightwallet/mobile/src/app/utilities/import/import-scan/import-scan.module.ts +++ b/packages/lightwallet/mobile/src/app/utilities/import/import-scan/import-scan.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { ImportScanView } from '@merit/mobile/app/utilities/import/import-scan/import-scan'; @NgModule({ - declarations: [ - ImportScanView, - ], - imports: [ - IonicPageModule.forChild(ImportScanView), - ], + declarations: [ImportScanView], + imports: [IonicPageModule.forChild(ImportScanView)], }) -export class ImportScanComponentModule { -} +export class ImportScanComponentModule {} diff --git a/packages/lightwallet/mobile/src/app/utilities/import/import-scan/import-scan.ts b/packages/lightwallet/mobile/src/app/utilities/import/import-scan/import-scan.ts index 83905b9111..fe578f91fb 100644 --- a/packages/lightwallet/mobile/src/app/utilities/import/import-scan/import-scan.ts +++ b/packages/lightwallet/mobile/src/app/utilities/import/import-scan/import-scan.ts @@ -9,11 +9,9 @@ import { IonicPage, NavParams, ViewController } from 'ionic-angular'; templateUrl: 'import-scan.html', }) export class ImportScanView { - err; - constructor(private viewCtrl: ViewController, - private navParams: NavParams) { + constructor(private viewCtrl: ViewController, private navParams: NavParams) { this.err = navParams.get('error'); if (!this.err) { this.close(); @@ -23,5 +21,4 @@ export class ImportScanView { close() { this.viewCtrl.dismiss(); } - } diff --git a/packages/lightwallet/mobile/src/app/utilities/import/import.module.ts b/packages/lightwallet/mobile/src/app/utilities/import/import.module.ts index 1964959ffa..a18d5d6e24 100644 --- a/packages/lightwallet/mobile/src/app/utilities/import/import.module.ts +++ b/packages/lightwallet/mobile/src/app/utilities/import/import.module.ts @@ -4,13 +4,7 @@ import { ImportView } from '@merit/mobile/app/utilities/import/import'; import { DirectivesModule } from '@merit/mobile/directives/directives.module'; @NgModule({ - declarations: [ - ImportView - ], - imports: [ - IonicPageModule.forChild(ImportView), - DirectivesModule - ] + declarations: [ImportView], + imports: [IonicPageModule.forChild(ImportView), DirectivesModule], }) -export class ImportViewModule { -} +export class ImportViewModule {} diff --git a/packages/lightwallet/mobile/src/app/utilities/import/import.ts b/packages/lightwallet/mobile/src/app/utilities/import/import.ts index 8f66385b14..5c8d7b5044 100644 --- a/packages/lightwallet/mobile/src/app/utilities/import/import.ts +++ b/packages/lightwallet/mobile/src/app/utilities/import/import.ts @@ -13,14 +13,15 @@ import { AddressScannerService } from '@merit/mobile/app/utilities/import/addres import { PushNotificationsService } from '@merit/common/services/push-notification.service'; @IonicPage({ - defaultHistory: ['OnboardingView'] + defaultHistory: ['OnboardingView'], }) @Component({ selector: 'view-import', templateUrl: 'import.html', }) export class ImportView { - @ViewChild('fileInput') input: ElementRef; + @ViewChild('fileInput') + input: ElementRef; segment = 'phrase'; formData = { @@ -32,7 +33,7 @@ export class ImportView { backupFileBlob: '', filePassword: '', network: '', - hasPassphrase: false + hasPassphrase: false, }; loadFileInProgress = false; @@ -47,13 +48,11 @@ export class ImportView { private mnemonicService: MnemonicService, private addressScanner: AddressScannerService, private pushNotificationsService: PushNotificationsService, - private walletService: WalletService + private walletService: WalletService, ) { this.formData.network = ENV.network; this.formData.derivationPath = - this.formData.network == 'livenet' ? - DerivationPath.getDefault() : - DerivationPath.getDefaultTestnet(); + this.formData.network == 'livenet' ? DerivationPath.getDefault() : DerivationPath.getDefaultTestnet(); this.sjcl = this.mwcService.getSJCL(); } @@ -80,7 +79,8 @@ export class ImportView { const reader: any = new FileReader(); this.loadFileInProgress = true; reader.onloadend = (loadEvent: any) => { - if (loadEvent.target.readyState == 2) { //DONE == 2 + if (loadEvent.target.readyState == 2) { + //DONE == 2 this.loadFileInProgress = false; this.formData.backupFileBlob = loadEvent.target.result; } @@ -89,7 +89,6 @@ export class ImportView { reader.readAsText($event.target.files[0]); } - async importMnemonic() { const loader = this.loadingCtrl.create({ content: 'Importing wallet' }); loader.present(); @@ -103,7 +102,7 @@ export class ImportView { const opts: any = { account: pathData.account, networkName: pathData.networkName, - derivationStrategy: pathData.derivationStrategy + derivationStrategy: pathData.derivationStrategy, }; let wallet; @@ -142,7 +141,6 @@ export class ImportView { try { decrypted = this.sjcl.decrypt(this.formData.filePassword, this.formData.backupFileBlob); } catch (e) { - this.logger.warn(e); return this.toastCtrl.error('Could not decrypt file, check your password'); } @@ -173,9 +171,7 @@ export class ImportView { } fileImportAllowed() { - return ( - !this.loadFileInProgress && this.formData.backupFileBlob && this.formData.filePassword - ); + return !this.loadFileInProgress && this.formData.backupFileBlob && this.formData.filePassword; } private async processCreatedWallet(wallet: MeritWalletClient, loader?: Loading) { diff --git a/packages/lightwallet/mobile/src/app/wallets/create-wallet/create-wallet.module.ts b/packages/lightwallet/mobile/src/app/wallets/create-wallet/create-wallet.module.ts index 0a009cd733..28e91cb1a1 100644 --- a/packages/lightwallet/mobile/src/app/wallets/create-wallet/create-wallet.module.ts +++ b/packages/lightwallet/mobile/src/app/wallets/create-wallet/create-wallet.module.ts @@ -4,13 +4,7 @@ import { CreateWalletView } from '@merit/mobile/app/wallets/create-wallet/create import { DirectivesModule } from '@merit/mobile/directives/directives.module'; @NgModule({ - declarations: [ - CreateWalletView, - ], - imports: [ - IonicPageModule.forChild(CreateWalletView), - DirectivesModule - ], + declarations: [CreateWalletView], + imports: [IonicPageModule.forChild(CreateWalletView), DirectivesModule], }) -export class CreateWalletComponentModule { -} +export class CreateWalletComponentModule {} diff --git a/packages/lightwallet/mobile/src/app/wallets/create-wallet/create-wallet.ts b/packages/lightwallet/mobile/src/app/wallets/create-wallet/create-wallet.ts index df385c6304..f444bc5d3e 100644 --- a/packages/lightwallet/mobile/src/app/wallets/create-wallet/create-wallet.ts +++ b/packages/lightwallet/mobile/src/app/wallets/create-wallet/create-wallet.ts @@ -5,7 +5,7 @@ import { LoadingController, ModalController, NavController, - NavParams + NavParams, } from 'ionic-angular'; import { ENV } from '@app/env'; import * as _ from 'lodash'; @@ -19,14 +19,13 @@ import { PollingNotificationsService } from '@merit/common/services/polling-noti import { PushNotificationsService } from '@merit/common/services/push-notification.service'; @IonicPage({ - defaultHistory: ['WalletsView'] + defaultHistory: ['WalletsView'], }) @Component({ selector: 'view-create-wallet', templateUrl: 'create-wallet.html', }) export class CreateWalletView { - formData = { walletName: '', parentAddress: '', @@ -40,25 +39,26 @@ export class CreateWalletView { password: '', repeatPassword: '', color: '', - hideBalance: false + hideBalance: false, }; parsedAddress: string; defaultBwsUrl: string = ENV.mwsUrl; - constructor(private navCtrl: NavController, - private navParams: NavParams, - private config: ConfigService, - private walletService: WalletService, - private loadCtrl: LoadingController, - private toastCtrl: ToastControllerService, - private modalCtrl: ModalController, - private logger: LoggerService, - private pushNotificationService: PushNotificationsService, - private pollingNotificationService: PollingNotificationsService, - private alertCtrl: AlertController, - private addressService: AddressService) { - } + constructor( + private navCtrl: NavController, + private navParams: NavParams, + private config: ConfigService, + private walletService: WalletService, + private loadCtrl: LoadingController, + private toastCtrl: ToastControllerService, + private modalCtrl: ModalController, + private logger: LoggerService, + private pushNotificationService: PushNotificationsService, + private pollingNotificationService: PollingNotificationsService, + private alertCtrl: AlertController, + private addressService: AddressService, + ) {} ionViewDidEnter() { let parentAddress = this.navParams.get('parentAddress'); @@ -70,18 +70,18 @@ export class CreateWalletView { isCreationEnabled() { return ( - this.formData.parentAddress - && this.formData.walletName - && !this.formData.aliasCheckInProgress - && !this.formData.aliasValidationError - && !this.formData.addressCheckInProgress - && !this.formData.addressCheckError + this.formData.parentAddress && + this.formData.walletName && + !this.formData.aliasCheckInProgress && + !this.formData.aliasValidationError && + !this.formData.addressCheckInProgress && + !this.formData.addressCheckError ); } selectColor() { let modal = this.modalCtrl.create('SelectColorView', { color: this.formData.color }); - modal.onDidDismiss((color) => { + modal.onDidDismiss(color => { if (color) { this.formData.color = color; } @@ -90,15 +90,20 @@ export class CreateWalletView { } showAliasTooltip() { - return this.showTooltip('Add an alias', - 'Add alias to your address, so people can recognize you and type something like "@merituser" instead of address.'); + return this.showTooltip( + 'Add an alias', + 'Add alias to your address, so people can recognize you and type something like "@merituser" instead of address.', + ); } private showTooltip(title, message) { - return this.alertCtrl.create({ - title, message, - buttons: ['Got it'] - }).present(); + return this.alertCtrl + .create({ + title, + message, + buttons: ['Got it'], + }) + .present(); } checkAlias() { @@ -120,85 +125,84 @@ export class CreateWalletView { private async validateParentAddress() { this.formData.parentAddress = cleanAddress(this.formData.parentAddress); - let input = (this.formData.parentAddress && isAlias(this.formData.parentAddress)) ? this.formData.parentAddress.slice(1) : this.formData.parentAddress; + let input = + this.formData.parentAddress && isAlias(this.formData.parentAddress) + ? this.formData.parentAddress.slice(1) + : this.formData.parentAddress; if (!input) { this.formData.addressCheckInProgress = false; - return this.formData.addressCheckError = 'Address cannot be empty'; + return (this.formData.addressCheckError = 'Address cannot be empty'); } else if (!this.addressService.isAddress(input)) { if (!this.addressService.couldBeAlias(input)) { this.formData.addressCheckInProgress = false; - return this.formData.addressCheckError = 'Incorrect address or alias format'; + return (this.formData.addressCheckError = 'Incorrect address or alias format'); } else { let aliasInfo = await this.addressService.getAddressInfo(input); if (!aliasInfo || !aliasInfo.isValid || !aliasInfo.isBeaconed || !aliasInfo.isConfirmed) { this.formData.addressCheckInProgress = false; - return this.formData.addressCheckError = 'Alias not found'; + return (this.formData.addressCheckError = 'Alias not found'); } else { this.formData.addressCheckError = null; this.formData.addressCheckInProgress = false; - return this.parsedAddress = aliasInfo.address; + return (this.parsedAddress = aliasInfo.address); } } } else { let addressInfo = await this.addressService.getAddressInfo(input); if (!addressInfo || !addressInfo.isValid || !addressInfo.isBeaconed || !addressInfo.isConfirmed) { this.formData.addressCheckInProgress = false; - return this.formData.addressCheckError = 'Address not found'; + return (this.formData.addressCheckError = 'Address not found'); } else { this.formData.addressCheckError = null; this.formData.addressCheckInProgress = false; - return this.parsedAddress = addressInfo.address; + return (this.parsedAddress = addressInfo.address); } } - - } private async validateAlias() { this.formData.alias = cleanAddress(this.formData.alias); - let input = (this.formData.alias && isAlias(this.formData.alias)) ? this.formData.alias.slice(1) : this.formData.alias; + let input = + this.formData.alias && isAlias(this.formData.alias) ? this.formData.alias.slice(1) : this.formData.alias; if (!input) { this.validateAliasDebounce.cancel(); this.formData.aliasCheckInProgress = false; - return this.formData.aliasValidationError = null; + return (this.formData.aliasValidationError = null); } if (input.length < 4) { this.validateAliasDebounce.cancel(); this.formData.aliasCheckInProgress = false; - return this.formData.aliasValidationError = 'Alias should contain at least 4 symbols'; + return (this.formData.aliasValidationError = 'Alias should contain at least 4 symbols'); } if (!this.addressService.couldBeAlias(input)) { this.validateAliasDebounce.cancel(); this.formData.aliasCheckInProgress = false; - return this.formData.aliasValidationError = 'Incorrect alias format'; + return (this.formData.aliasValidationError = 'Incorrect alias format'); } - let addressExists = await this.addressService.getValidAddress(input); if (addressExists) { this.formData.aliasCheckInProgress = false; - return this.formData.aliasValidationError = 'Alias already in use'; + return (this.formData.aliasValidationError = 'Alias already in use'); } else { this.formData.aliasValidationError = null; - return this.formData.aliasCheckInProgress = false; + return (this.formData.aliasCheckInProgress = false); } - - } async createWallet() { - if (this.formData.password != this.formData.repeatPassword) { return this.toastCtrl.error(`Passwords don't match`); } - let alias = (this.formData.alias && isAlias(this.formData.alias)) ? this.formData.alias.slice(1) : this.formData.alias; + let alias = + this.formData.alias && isAlias(this.formData.alias) ? this.formData.alias.slice(1) : this.formData.alias; const opts = { name: this.formData.walletName, @@ -208,11 +212,11 @@ export class CreateWalletView { mnemonic: this.formData.recoveryPhrase, networkName: ENV.network, m: 1, //todo temp! - n: 1 //todo temp! + n: 1, //todo temp! }; let loader = this.loadCtrl.create({ - content: 'Creating wallet' + content: 'Creating wallet', }); await loader.present(); @@ -233,7 +237,7 @@ export class CreateWalletView { let promises: Promise[] = []; if (this.formData.hideBalance) { - wallet.balanceHidden = this.formData.hideBalance; + wallet.balanceHidden = this.formData.hideBalance; promises.push(this.walletService.setHiddenBalanceOption(walletId, this.formData.hideBalance)); } @@ -245,8 +249,8 @@ export class CreateWalletView { wallet.color = this.formData.color; const colorOpts = { colorFor: { - [walletId]: this.formData.color - } + [walletId]: this.formData.color, + }, }; promises.push(this.config.set(colorOpts)); } diff --git a/packages/lightwallet/mobile/src/app/wallets/edit-wallet/edit-wallet.module.ts b/packages/lightwallet/mobile/src/app/wallets/edit-wallet/edit-wallet.module.ts index 2a33026b80..480dbbdf22 100644 --- a/packages/lightwallet/mobile/src/app/wallets/edit-wallet/edit-wallet.module.ts +++ b/packages/lightwallet/mobile/src/app/wallets/edit-wallet/edit-wallet.module.ts @@ -4,13 +4,7 @@ import { DirectivesModule } from '@merit/mobile/directives/directives.module'; import { EditWalletView } from './edit-wallet'; @NgModule({ - declarations: [ - EditWalletView, - ], - imports: [ - IonicPageModule.forChild(EditWalletView), - DirectivesModule - ], + declarations: [EditWalletView], + imports: [IonicPageModule.forChild(EditWalletView), DirectivesModule], }) -export class EditWalletModule { -} +export class EditWalletModule {} diff --git a/packages/lightwallet/mobile/src/app/wallets/edit-wallet/edit-wallet.ts b/packages/lightwallet/mobile/src/app/wallets/edit-wallet/edit-wallet.ts index 0021b6fc78..3d6f841449 100644 --- a/packages/lightwallet/mobile/src/app/wallets/edit-wallet/edit-wallet.ts +++ b/packages/lightwallet/mobile/src/app/wallets/edit-wallet/edit-wallet.ts @@ -27,7 +27,7 @@ export class EditWalletView { private toastCtrl: ToastControllerService, private configService: ConfigService, private walletService: WalletService, - private logger: LoggerService + private logger: LoggerService, ) { this.wallet = this.navParams.get('wallet'); this.logger.info(this.wallet); @@ -55,7 +55,7 @@ export class EditWalletView { changeColor() { let modal = this.modalCtrl.create('SelectColorView', { color: this.wallet.color }); - modal.onDidDismiss((color) => { + modal.onDidDismiss(color => { if (color) { this.wallet.color = color; let colorOpts = { colorFor: {} }; @@ -76,29 +76,29 @@ export class EditWalletView { } deleteWallet() { - - this.alertCtrl.create({ - title: 'WARNING!', - message: 'This action will permanently delete this wallet. IT CANNOT BE REVERSED!', - buttons: [ - { - text: 'Cancel', - role: 'cancel', - handler: () => { - } - }, - { - text: 'Delete', - handler: () => { - if (!this.walletService.isWalletEncrypted(this.wallet)) { - this.doDeleteWallet(); - } else { - this.showPasswordPrompt(); - } - } - } - ] - }).present(); + this.alertCtrl + .create({ + title: 'WARNING!', + message: 'This action will permanently delete this wallet. IT CANNOT BE REVERSED!', + buttons: [ + { + text: 'Cancel', + role: 'cancel', + handler: () => {}, + }, + { + text: 'Delete', + handler: () => { + if (!this.walletService.isWalletEncrypted(this.wallet)) { + this.doDeleteWallet(); + } else { + this.showPasswordPrompt(); + } + }, + }, + ], + }) + .present(); } private showPasswordPrompt(highlightInvalid = false) { @@ -106,8 +106,10 @@ export class EditWalletView { .create({ title: 'Enter wallet password', cssClass: highlightInvalid ? 'invalid-input-prompt' : '', - inputs: [ { name: 'password', placeholder: 'Password', type: 'password'} ], - buttons: [ { text: 'Cancel',role: 'cancel', },{ + inputs: [{ name: 'password', placeholder: 'Password', type: 'password' }], + buttons: [ + { text: 'Cancel', role: 'cancel' }, + { text: 'Ok', handler: data => { if (!data.password) { @@ -128,19 +130,21 @@ export class EditWalletView { } private doDeleteWallet() { - - this.profileService.deleteWallet(this.wallet).then(() => { - this.profileService.isAuthorized().then((authorized) => { - if (authorized) { - this.navCtrl.popToRoot(); - } else { - const nav = this.app.getRootNavs()[0]; - nav.setRoot('OnboardingView'); - nav.popToRoot(); - } + this.profileService + .deleteWallet(this.wallet) + .then(() => { + this.profileService.isAuthorized().then(authorized => { + if (authorized) { + this.navCtrl.popToRoot(); + } else { + const nav = this.app.getRootNavs()[0]; + nav.setRoot('OnboardingView'); + nav.popToRoot(); + } + }); }) - }).catch((err) => { - this.toastCtrl.error(JSON.stringify(err)); - }); + .catch(err => { + this.toastCtrl.error(JSON.stringify(err)); + }); } } diff --git a/packages/lightwallet/mobile/src/app/wallets/export-wallet/export-wallet.module.ts b/packages/lightwallet/mobile/src/app/wallets/export-wallet/export-wallet.module.ts index 0ca3923120..23977f29ae 100644 --- a/packages/lightwallet/mobile/src/app/wallets/export-wallet/export-wallet.module.ts +++ b/packages/lightwallet/mobile/src/app/wallets/export-wallet/export-wallet.module.ts @@ -3,18 +3,10 @@ import { QRCodeModule } from 'angular2-qrcode'; import { IonicPageModule } from 'ionic-angular'; import { DirectivesModule } from '@merit/mobile/directives/directives.module'; import { ExportWalletView } from './export-wallet'; -import { ClipModule } from 'ng2-clip' +import { ClipModule } from 'ng2-clip'; @NgModule({ - declarations: [ - ExportWalletView, - ], - imports: [ - QRCodeModule, - IonicPageModule.forChild(ExportWalletView), - DirectivesModule, - ClipModule - ] + declarations: [ExportWalletView], + imports: [QRCodeModule, IonicPageModule.forChild(ExportWalletView), DirectivesModule, ClipModule], }) -export class ExportWalletModule { -} +export class ExportWalletModule {} diff --git a/packages/lightwallet/mobile/src/app/wallets/export-wallet/export-wallet.ts b/packages/lightwallet/mobile/src/app/wallets/export-wallet/export-wallet.ts index ded4edd718..30a76de9ca 100644 --- a/packages/lightwallet/mobile/src/app/wallets/export-wallet/export-wallet.ts +++ b/packages/lightwallet/mobile/src/app/wallets/export-wallet/export-wallet.ts @@ -16,78 +16,85 @@ import { ToastControllerService, IMeritToastConfig } from '@merit/common/service templateUrl: 'export-wallet.html', }) export class ExportWalletView { - wallet: MeritWalletClient; segment = 'mnemonic'; accessGranted: boolean; formData = { password: '', - repeatPassword: '' + repeatPassword: '', }; mnemonic: string; qrcode: string; private sjcl; - constructor(private navCtrl: NavController, - private navParams: NavParams, - private walletsService: WalletService, - private alertController: AlertController, - private persistenceService: PersistenceService, - private appService: AppSettingsService, - private bwcService: MWCService, - private toastCtrl: ToastControllerService, - private file: File, - private platform: Platform, - private logger: LoggerService) { + constructor( + private navCtrl: NavController, + private navParams: NavParams, + private walletsService: WalletService, + private alertController: AlertController, + private persistenceService: PersistenceService, + private appService: AppSettingsService, + private bwcService: MWCService, + private toastCtrl: ToastControllerService, + private file: File, + private platform: Platform, + private logger: LoggerService, + ) { this.wallet = this.navParams.get('wallet'); this.sjcl = this.bwcService.getSJCL(); } ionViewDidLoad() { - - let setQrInfo = (password) => { - this.walletsService.getEncodedWalletInfo(this.wallet, password).then((info) => { + let setQrInfo = password => { + this.walletsService.getEncodedWalletInfo(this.wallet, password).then(info => { this.qrcode = info; }); }; if (this.walletsService.isWalletEncrypted(this.wallet)) { - let showPrompt = (highlightInvalid = false) => { - this.alertController.create({ - title: 'Enter spending password', - message: 'Spending password required to export this wallet. This is not the password you will use to protect exported file.', - cssClass: highlightInvalid ? 'invalid-input-prompt' : '', - inputs: [{ - name: 'password', - placeholder: 'Password', - type: 'password' - }], - buttons: [ - { - text: 'Cancel', role: 'cancel', handler: () => { - this.navCtrl.pop(); - } - }, - { - text: 'Ok', handler: (data) => { - if (!data.password) { - showPrompt(true); - } else { - try { - this.walletsService.decryptWallet(this.wallet, data.password); - this.mnemonic = this.wallet.getMnemonic(); - setQrInfo(data.password); - this.walletsService.encryptWallet(this.wallet, data.password); - this.accessGranted = true; - } catch (err) { - showPrompt(); - } - } - } - } - ] - }).present(); + this.alertController + .create({ + title: 'Enter spending password', + message: + 'Spending password required to export this wallet. This is not the password you will use to protect exported file.', + cssClass: highlightInvalid ? 'invalid-input-prompt' : '', + inputs: [ + { + name: 'password', + placeholder: 'Password', + type: 'password', + }, + ], + buttons: [ + { + text: 'Cancel', + role: 'cancel', + handler: () => { + this.navCtrl.pop(); + }, + }, + { + text: 'Ok', + handler: data => { + if (!data.password) { + showPrompt(true); + } else { + try { + this.walletsService.decryptWallet(this.wallet, data.password); + this.mnemonic = this.wallet.getMnemonic(); + setQrInfo(data.password); + this.walletsService.encryptWallet(this.wallet, data.password); + this.accessGranted = true; + } catch (err) { + showPrompt(); + } + } + }, + }, + ], + }) + .present(); }; showPrompt(); } else { @@ -98,14 +105,10 @@ export class ExportWalletView { } saveEnabled() { - return ( - this.formData.password - && this.formData.password == this.formData.repeatPassword - ); + return this.formData.password && this.formData.password == this.formData.repeatPassword; } async download() { - const addressBook = await this.persistenceService.getAddressbook(this.wallet.credentials.network); const exportData = this.wallet.export({ addressBook: addressBook }); const encryptedData = this.sjcl.encrypt(this.formData.password, exportData, { iter: 10000 }); @@ -114,61 +117,60 @@ export class ExportWalletView { const defaultFileName = `${walletName}-${info.nameCase || ''}.backup.aes.json`; const blob = new Blob([encryptedData], { type: 'text/plain;charset=utf-8' }); - const done = (fileName: string = defaultFileName) => this.toastCtrl.success(`Wallet exported to ${ fileName }`); + const done = (fileName: string = defaultFileName) => this.toastCtrl.success(`Wallet exported to ${fileName}`); if (this.platform.is('cordova')) { const root = this.platform.is('ios') ? this.file.documentsDirectory : this.file.externalRootDirectory; - return this.alertController.create({ - title: 'Set file name', - message: 'Enter a name for the file to export your wallet', - inputs: [ - { - name: 'name', - placeholder: 'File name', - value: defaultFileName - } - ], - buttons: [ - 'Cancel', - { - text: 'Export', - handler: (data) => { - if (data.name && data.name.length) { - (async () => { - - try { - await this.file.checkFile(root, data.name); - // file exists - return this.toastCtrl.error('There is already a file with the name you specified. Please pick another name.'); - } catch (e) { - // file doesn't exist + return this.alertController + .create({ + title: 'Set file name', + message: 'Enter a name for the file to export your wallet', + inputs: [ + { + name: 'name', + placeholder: 'File name', + value: defaultFileName, + }, + ], + buttons: [ + 'Cancel', + { + text: 'Export', + handler: data => { + if (data.name && data.name.length) { + (async () => { try { - await this.file.writeFile(root, data.name, blob); - return done(); + await this.file.checkFile(root, data.name); + // file exists + return this.toastCtrl.error( + 'There is already a file with the name you specified. Please pick another name.', + ); } catch (e) { - this.logger.error('Error export wallet to file', e); - return this.toastCtrl.error('An error occurred while exporting your wallet.'); + // file doesn't exist + try { + await this.file.writeFile(root, data.name, blob); + return done(); + } catch (e) { + this.logger.error('Error export wallet to file', e); + return this.toastCtrl.error('An error occurred while exporting your wallet.'); + } } - } - - })(); - } else { - return false; - } - } - } - ] - }).present(); - + })(); + } else { + return false; + } + }, + }, + ], + }) + .present(); } else { await FileSaver.saveAs(blob, defaultFileName); return done(); } } - public notifyCopied() { this.toastCtrl.success('Copied to clipboard'); } - } diff --git a/packages/lightwallet/mobile/src/app/wallets/incoming-request/incoming-request.module.ts b/packages/lightwallet/mobile/src/app/wallets/incoming-request/incoming-request.module.ts index c26fa4f5f2..9854841d78 100644 --- a/packages/lightwallet/mobile/src/app/wallets/incoming-request/incoming-request.module.ts +++ b/packages/lightwallet/mobile/src/app/wallets/incoming-request/incoming-request.module.ts @@ -3,15 +3,8 @@ import { IonicPageModule } from 'ionic-angular'; import { IncomingRequestModal } from './incoming-request'; import { MomentModule } from 'ngx-moment'; - @NgModule({ - declarations: [ - IncomingRequestModal, - ], - imports: [ - MomentModule, - IonicPageModule.forChild(IncomingRequestModal), - ], + declarations: [IncomingRequestModal], + imports: [MomentModule, IonicPageModule.forChild(IncomingRequestModal)], }) -export class IncomingRequestModule { -} +export class IncomingRequestModule {} diff --git a/packages/lightwallet/mobile/src/app/wallets/incoming-request/incoming-request.ts b/packages/lightwallet/mobile/src/app/wallets/incoming-request/incoming-request.ts index aa937bddba..81607c91fd 100644 --- a/packages/lightwallet/mobile/src/app/wallets/incoming-request/incoming-request.ts +++ b/packages/lightwallet/mobile/src/app/wallets/incoming-request/incoming-request.ts @@ -11,22 +11,23 @@ import { IonicPage, LoadingController, ModalController, NavController, NavParams @IonicPage() @Component({ selector: 'view-incoming-request', - templateUrl: 'incoming-request.html' + templateUrl: 'incoming-request.html', }) export class IncomingRequestModal { - public unlockRequest: any; public contacts: Array = []; public wallets: Array = []; - constructor(private navCtrl: NavController, - private navParams: NavParams, - private modalCtrl: ModalController, - private contactsService: ContactsService, - private addressService: AddressService, - private toastCtrl: ToastControllerService, - private unlockService: UnlockRequestService, - private loadingCtrl: LoadingController) { + constructor( + private navCtrl: NavController, + private navParams: NavParams, + private modalCtrl: ModalController, + private contactsService: ContactsService, + private addressService: AddressService, + private toastCtrl: ToastControllerService, + private unlockService: UnlockRequestService, + private loadingCtrl: LoadingController, + ) { this.unlockRequest = this.navParams.get('request'); this.wallets = this.navParams.get('wallets'); } @@ -56,7 +57,7 @@ export class IncomingRequestModal { const meritAddress = { address: this.unlockRequest.address, alias: this.unlockRequest.alias, - network: this.addressService.getAddressNetwork(this.unlockRequest.address).name + network: this.addressService.getAddressNetwork(this.unlockRequest.address).name, }; const modal = this.modalCtrl.create('SendCreateContactView', { address: meritAddress }); modal.onDidDismiss(() => { @@ -69,7 +70,7 @@ export class IncomingRequestModal { let meritAddress = { address: this.unlockRequest.address, alias: this.unlockRequest.alias, - network: this.addressService.getAddressNetwork(this.unlockRequest.address).name + network: this.addressService.getAddressNetwork(this.unlockRequest.address).name, }; let modal = this.modalCtrl.create('SendSelectBindContactView', { contacts: this.contacts, address: meritAddress }); modal.onDidDismiss(() => { @@ -84,12 +85,16 @@ export class IncomingRequestModal { } selectWallet() { - const modal = this.modalCtrl.create('SelectWalletModal', { - showInvites: true, - selectedWallet: this.unlockRequest.walletClient, - availableWallets: this.wallets.filter((wallet) => wallet.availableInvites > 0) - }, MERIT_MODAL_OPTS); - modal.onDidDismiss((wallet) => { + const modal = this.modalCtrl.create( + 'SelectWalletModal', + { + showInvites: true, + selectedWallet: this.unlockRequest.walletClient, + availableWallets: this.wallets.filter(wallet => wallet.availableInvites > 0), + }, + MERIT_MODAL_OPTS, + ); + modal.onDidDismiss(wallet => { if (wallet) { this.unlockRequest.walletClient = wallet; } diff --git a/packages/lightwallet/mobile/src/app/wallets/select-color/select-color.module.ts b/packages/lightwallet/mobile/src/app/wallets/select-color/select-color.module.ts index 6c3aa11a89..c056810ccc 100644 --- a/packages/lightwallet/mobile/src/app/wallets/select-color/select-color.module.ts +++ b/packages/lightwallet/mobile/src/app/wallets/select-color/select-color.module.ts @@ -3,12 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { SelectColorView } from './select-color'; @NgModule({ - declarations: [ - SelectColorView, - ], - imports: [ - IonicPageModule.forChild(SelectColorView), - ], + declarations: [SelectColorView], + imports: [IonicPageModule.forChild(SelectColorView)], }) -export class SelectColorModule { -} +export class SelectColorModule {} diff --git a/packages/lightwallet/mobile/src/app/wallets/select-color/select-color.ts b/packages/lightwallet/mobile/src/app/wallets/select-color/select-color.ts index 163eaba188..ae441c0a2c 100644 --- a/packages/lightwallet/mobile/src/app/wallets/select-color/select-color.ts +++ b/packages/lightwallet/mobile/src/app/wallets/select-color/select-color.ts @@ -7,7 +7,6 @@ import { IonicPage, NavController, NavParams, ViewController } from 'ionic-angul templateUrl: 'select-color.html', }) export class SelectColorView { - availableColors = [ '#e57373', '#e985a7', @@ -27,15 +26,12 @@ export class SelectColorView { '#8997eb', '#808080', '#5f6c82', - '#383d43' + '#383d43', ]; selectedColor: string; - constructor(public navCtrl: NavController, - public navParams: NavParams, - private viewCtrl: ViewController) { - } + constructor(public navCtrl: NavController, public navParams: NavParams, private viewCtrl: ViewController) {} cancel() { this.viewCtrl.dismiss(); @@ -44,5 +40,4 @@ export class SelectColorView { select(color) { this.viewCtrl.dismiss(color); } - } diff --git a/packages/lightwallet/mobile/src/app/wallets/set-wallet-password/set-wallet-password.module.ts b/packages/lightwallet/mobile/src/app/wallets/set-wallet-password/set-wallet-password.module.ts index 224b6d4fde..3b3925dad5 100644 --- a/packages/lightwallet/mobile/src/app/wallets/set-wallet-password/set-wallet-password.module.ts +++ b/packages/lightwallet/mobile/src/app/wallets/set-wallet-password/set-wallet-password.module.ts @@ -4,13 +4,7 @@ import { DirectivesModule } from '@merit/mobile/directives/directives.module'; import { SetWalletPasswordView } from './set-wallet-password'; @NgModule({ - declarations: [ - SetWalletPasswordView, - ], - imports: [ - IonicPageModule.forChild(SetWalletPasswordView), - DirectivesModule - ], + declarations: [SetWalletPasswordView], + imports: [IonicPageModule.forChild(SetWalletPasswordView), DirectivesModule], }) -export class SetWalletPasswordModule { -} +export class SetWalletPasswordModule {} diff --git a/packages/lightwallet/mobile/src/app/wallets/set-wallet-password/set-wallet-password.ts b/packages/lightwallet/mobile/src/app/wallets/set-wallet-password/set-wallet-password.ts index d4dbf8dbe8..737af32bf1 100644 --- a/packages/lightwallet/mobile/src/app/wallets/set-wallet-password/set-wallet-password.ts +++ b/packages/lightwallet/mobile/src/app/wallets/set-wallet-password/set-wallet-password.ts @@ -9,7 +9,6 @@ import { ToastControllerService, IMeritToastConfig } from '@merit/common/service templateUrl: 'set-wallet-password.html', }) export class SetWalletPasswordView { - wallet: any; isWalletEncrypted: boolean; @@ -17,35 +16,33 @@ export class SetWalletPasswordView { formData = { password: '', repeatPassword: '', - currentPassword: '' + currentPassword: '', }; - constructor(private navCtrl: NavController, - private navParams: NavParams, - private toastCtrl: ToastControllerService, - private walletService: WalletService) { + constructor( + private navCtrl: NavController, + private navParams: NavParams, + private toastCtrl: ToastControllerService, + private walletService: WalletService, + ) { this.wallet = navParams.get('wallet'); this.isWalletEncrypted = this.walletService.isWalletEncrypted(this.wallet); } async removePassword() { - try { await this.walletService.decryptWallet(this.wallet, this.formData.currentPassword); this.navCtrl.pop(); } catch (err) { return this.toastCtrl.error('Incorrect current password'); } - } async setPassword() { - if (this.formData.password != this.formData.repeatPassword) { - return this.toastCtrl.error('Passwords don\'t match'); + return this.toastCtrl.error("Passwords don't match"); } - const encrypt = async () => { try { await this.walletService.encryptWallet(this.wallet, this.formData.password); @@ -55,7 +52,6 @@ export class SetWalletPasswordView { } }; - if (this.isWalletEncrypted) { try { await this.walletService.decryptWallet(this.wallet, this.formData.currentPassword); @@ -66,15 +62,9 @@ export class SetWalletPasswordView { } else { return encrypt(); } - } saveEnabled() { - return ( - this.formData.password - && (this.isWalletEncrypted ? this.formData.currentPassword : true) - ); + return this.formData.password && (this.isWalletEncrypted ? this.formData.currentPassword : true); } - - } diff --git a/packages/lightwallet/mobile/src/app/wallets/tx-details/tx-details.module.ts b/packages/lightwallet/mobile/src/app/wallets/tx-details/tx-details.module.ts index e18e595ebd..f2fd5bbba9 100644 --- a/packages/lightwallet/mobile/src/app/wallets/tx-details/tx-details.module.ts +++ b/packages/lightwallet/mobile/src/app/wallets/tx-details/tx-details.module.ts @@ -7,16 +7,7 @@ import { ComponentsModule } from '../../../components/components.module'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; @NgModule({ - declarations: [ - TxDetailsView - ], - imports: [ - IonicPageModule.forChild(TxDetailsView), - MomentModule, - ComponentsModule, - CommonPipesModule, - ClipModule - ] + declarations: [TxDetailsView], + imports: [IonicPageModule.forChild(TxDetailsView), MomentModule, ComponentsModule, CommonPipesModule, ClipModule], }) -export class TxDetailsViewModule { -} +export class TxDetailsViewModule {} diff --git a/packages/lightwallet/mobile/src/app/wallets/tx-details/tx-details.ts b/packages/lightwallet/mobile/src/app/wallets/tx-details/tx-details.ts index f4538ca3be..4838b88794 100644 --- a/packages/lightwallet/mobile/src/app/wallets/tx-details/tx-details.ts +++ b/packages/lightwallet/mobile/src/app/wallets/tx-details/tx-details.ts @@ -6,14 +6,13 @@ import { IonicPage, NavParams, ViewController } from 'ionic-angular'; import { EasyReceiveService } from '../../../../../common/services/easy-receive.service'; @IonicPage({ - defaultHistory: ['WalletsView'] + defaultHistory: ['WalletsView'], }) @Component({ selector: 'tx-details-view', - templateUrl: 'tx-details.html' + templateUrl: 'tx-details.html', }) export class TxDetailsView { - tx: IDisplayTransaction; confirmationsExplanation: string; isUnlockRequest: boolean; @@ -33,11 +32,12 @@ export class TxDetailsView { } } - constructor(private navParams: NavParams, - private viewCtrl: ViewController, - private toastCtrl: ToastControllerService, - private easyReceive: EasyReceiveService) { - } + constructor( + private navParams: NavParams, + private viewCtrl: ViewController, + private toastCtrl: ToastControllerService, + private easyReceive: EasyReceiveService, + ) {} dismiss() { return this.viewCtrl.dismiss(); @@ -65,7 +65,8 @@ export class TxDetailsView { this.isEasySend = !this.isInvite && !this.isReward; this.isCancelled = tx.cancelled; if (!tx.isConfirmed) { - this.confirmationsExplanation = String(tx.confirmations) + ' block(s) confirmed from ' + COINBASE_CONFIRMATION_THRESHOLD; + this.confirmationsExplanation = + String(tx.confirmations) + ' block(s) confirmed from ' + COINBASE_CONFIRMATION_THRESHOLD; } if (tx.isGrowthReward) this.image = 'growth'; diff --git a/packages/lightwallet/mobile/src/app/wallets/wallet-details/wallet-details.module.ts b/packages/lightwallet/mobile/src/app/wallets/wallet-details/wallet-details.module.ts index 33aa5d9589..2c31babbb1 100644 --- a/packages/lightwallet/mobile/src/app/wallets/wallet-details/wallet-details.module.ts +++ b/packages/lightwallet/mobile/src/app/wallets/wallet-details/wallet-details.module.ts @@ -6,18 +6,14 @@ import { ComponentsModule } from '../../../components/components.module'; import { DirectivesModule } from '@merit/mobile/directives/directives.module'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; - @NgModule({ - declarations: [ - WalletDetailsView - ], + declarations: [WalletDetailsView], imports: [ IonicPageModule.forChild(WalletDetailsView), MomentModule, ComponentsModule, DirectivesModule, - CommonPipesModule - ] + CommonPipesModule, + ], }) -export class WalletDetailsModule { -} +export class WalletDetailsModule {} diff --git a/packages/lightwallet/mobile/src/app/wallets/wallet-details/wallet-details.ts b/packages/lightwallet/mobile/src/app/wallets/wallet-details/wallet-details.ts index affc7e6638..d2de752aea 100644 --- a/packages/lightwallet/mobile/src/app/wallets/wallet-details/wallet-details.ts +++ b/packages/lightwallet/mobile/src/app/wallets/wallet-details/wallet-details.ts @@ -8,18 +8,17 @@ import { PersistenceService2 } from '@merit/common/services/persistence2.service import { WalletService } from '@merit/common/services/wallet.service'; import { formatWalletHistory } from '@merit/common/utils/transactions'; import { App, Events, IonicPage, NavController, NavParams, Tab, Tabs } from 'ionic-angular'; -import { FeeService } from "@merit/common/services/fee.service"; +import { FeeService } from '@merit/common/services/fee.service'; @IonicPage({ segment: 'wallet/:walletId', - defaultHistory: ['WalletsView'] + defaultHistory: ['WalletsView'], }) @Component({ selector: 'wallet-details-view', - templateUrl: 'wallet-details.html' + templateUrl: 'wallet-details.html', }) export class WalletDetailsView { - wallet: MeritWalletClient; loading: boolean; refreshing: boolean; @@ -29,17 +28,18 @@ export class WalletDetailsView { txs: Array = []; - constructor(private navCtrl: NavController, - private app: App, - private navParams: NavParams, - private walletService: WalletService, - private logger: LoggerService, - private tabsCtrl: Tabs, - private events: Events, - private contactsService: ContactsService, - private persistenceService: PersistenceService2, - private easyReceiveService: EasyReceiveService, - private feeService: FeeService + constructor( + private navCtrl: NavController, + private app: App, + private navParams: NavParams, + private walletService: WalletService, + private logger: LoggerService, + private tabsCtrl: Tabs, + private events: Events, + private contactsService: ContactsService, + private persistenceService: PersistenceService2, + private easyReceiveService: EasyReceiveService, + private feeService: FeeService, ) { // We can assume that the wallet data has already been fetched and // passed in from the wallets (list) view. This enables us to keep @@ -59,10 +59,9 @@ export class WalletDetailsView { this.getCommunityInfo(); }); - this.easyReceiveService.cancelledEasySend$ - .subscribe(() => { - this.getWalletHistory(); - }); + this.easyReceiveService.cancelledEasySend$.subscribe(() => { + this.getWalletHistory(); + }); } async deposit() { @@ -98,7 +97,6 @@ export class WalletDetailsView { refresher.complete(); } - private async getCommunityInfo() { const addressesRewards = await this.wallet.getRewards([this.wallet.getRootAddress()]); this.wallet.miningRewards = addressesRewards[0].rewards.mining; @@ -116,7 +114,13 @@ export class WalletDetailsView { private async formatHistory() { const easySends = await this.wallet.getGlobalSendHistory(); - this.wallet.completeHistory = await formatWalletHistory(this.txs, this.wallet, easySends, this.feeService, this.contactsService); + this.wallet.completeHistory = await formatWalletHistory( + this.txs, + this.wallet, + easySends, + this.feeService, + this.contactsService, + ); } async loadMoreHistory(infiniter) { @@ -130,5 +134,4 @@ export class WalletDetailsView { } infiniter.complete(); } - } diff --git a/packages/lightwallet/mobile/src/app/wallets/wallets.module.ts b/packages/lightwallet/mobile/src/app/wallets/wallets.module.ts index 79e868aa99..ac10b0f401 100644 --- a/packages/lightwallet/mobile/src/app/wallets/wallets.module.ts +++ b/packages/lightwallet/mobile/src/app/wallets/wallets.module.ts @@ -5,14 +5,7 @@ import { WalletsView } from '@merit/mobile/app/wallets/wallets'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; @NgModule({ - declarations: [ - WalletsView - ], - imports: [ - MomentModule, - CommonPipesModule, - IonicPageModule.forChild(WalletsView) - ], + declarations: [WalletsView], + imports: [MomentModule, CommonPipesModule, IonicPageModule.forChild(WalletsView)], }) -export class WalletsModule { -} +export class WalletsModule {} diff --git a/packages/lightwallet/mobile/src/app/wallets/wallets.ts b/packages/lightwallet/mobile/src/app/wallets/wallets.ts index c281b07649..f1d15a8fb3 100644 --- a/packages/lightwallet/mobile/src/app/wallets/wallets.ts +++ b/packages/lightwallet/mobile/src/app/wallets/wallets.ts @@ -11,10 +11,9 @@ import { Events, IonicPage, NavController, Platform } from 'ionic-angular'; @IonicPage() @Component({ selector: 'view-wallets', - templateUrl: 'wallets.html' + templateUrl: 'wallets.html', }) export class WalletsView { - totalInvites: number; totalAmount: number; @@ -27,12 +26,13 @@ export class WalletsView { showCommunityPopup: boolean; communitySize: number; - constructor(private navCtrl: NavController, - private logger: LoggerService, - private toastCtrl: ToastControllerService, - private profileService: ProfileService, - private platform: Platform, - private events: Events + constructor( + private navCtrl: NavController, + private logger: LoggerService, + private toastCtrl: ToastControllerService, + private profileService: ProfileService, + private platform: Platform, + private events: Events, ) { this.logger.debug('WalletsView constructor!'); } @@ -44,13 +44,13 @@ export class WalletsView { this.logger.info('WalletView is going to refresh data on resume.'); if (this.isActivePage) { this.refreshing = true; - this.updateAllInfo().then(() => this.refreshing = false); + this.updateAllInfo().then(() => (this.refreshing = false)); } }); this.events.subscribe('Remote:IncomingTx', () => { this.refreshing = true; - this.updateAllInfo().then(() => this.refreshing = false); + this.updateAllInfo().then(() => (this.refreshing = false)); }); } @@ -71,7 +71,8 @@ export class WalletsView { this.loading = false; this.refreshing = true; await this.updateAllInfo(); - } catch (e) {} finally { + } catch (e) { + } finally { this.loading = false; this.refreshing = true; } @@ -93,21 +94,20 @@ export class WalletsView { } async loadCommunitySize() { - let communitySize = 0; - const getCommunitySizes = () => this.wallets.map(async (w) => { - let { referralcount } = await w.getCommunityInfo(w.rootAddress.toString()); - return w.communitySize = referralcount; - }); + const getCommunitySizes = () => + this.wallets.map(async w => { + let { referralcount } = await w.getCommunityInfo(w.rootAddress.toString()); + return (w.communitySize = referralcount); + }); await Promise.all(getCommunitySizes()); this.communitySize = communitySize; - } toAddWallet() { let referralAddress = ''; this.wallets.some(w => { - if (w.availableInvites) return referralAddress = w.rootAddress; + if (w.availableInvites) return (referralAddress = w.rootAddress); }); return this.navCtrl.push('CreateWalletView', { parentAddress: referralAddress }); } @@ -139,7 +139,7 @@ export class WalletsView { this.totalAmount = totalAmount; this.communitySize = this.wallets.reduce((size, w) => { - return size + w.communitySize + return size + w.communitySize; }, 0); } @@ -147,7 +147,4 @@ export class WalletsView { this.showCommunityPopup = false; this.profileService.closeCommunityPopup(); } - - } - diff --git a/packages/lightwallet/mobile/src/components/components.module.ts b/packages/lightwallet/mobile/src/components/components.module.ts index 07fecef7aa..e50921dace 100644 --- a/packages/lightwallet/mobile/src/components/components.module.ts +++ b/packages/lightwallet/mobile/src/components/components.module.ts @@ -7,20 +7,8 @@ import { ContactAvatarComponent } from './contact-avatar/contact-avatar'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; @NgModule({ - declarations: [ - TransactionHistoryComponent, - SlideToActionComponent, - ContactAvatarComponent - ], - imports: [ - MomentModule, - CommonPipesModule, - IonicModule - ], - exports: [ - TransactionHistoryComponent, - SlideToActionComponent, - ContactAvatarComponent - ] + declarations: [TransactionHistoryComponent, SlideToActionComponent, ContactAvatarComponent], + imports: [MomentModule, CommonPipesModule, IonicModule], + exports: [TransactionHistoryComponent, SlideToActionComponent, ContactAvatarComponent], }) export class ComponentsModule {} diff --git a/packages/lightwallet/mobile/src/components/contact-avatar/contact-avatar.ts b/packages/lightwallet/mobile/src/components/contact-avatar/contact-avatar.ts index 72be745cf4..f84284dc55 100644 --- a/packages/lightwallet/mobile/src/components/contact-avatar/contact-avatar.ts +++ b/packages/lightwallet/mobile/src/components/contact-avatar/contact-avatar.ts @@ -12,10 +12,9 @@ import { getContactInitials } from '@merit/common/utils/contacts'; {{ contactInitials }} `, - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, }) export class ContactAvatarComponent { - @Input() set contact(contact: MeritContact) { if (!contact) return; @@ -32,6 +31,5 @@ export class ContactAvatarComponent { imageSrc: any; contactInitials: string; - constructor(private _sanitizer: DomSanitizer) { - } + constructor(private _sanitizer: DomSanitizer) {} } diff --git a/packages/lightwallet/mobile/src/components/slide-to-action/pan-gesture.ts b/packages/lightwallet/mobile/src/components/slide-to-action/pan-gesture.ts index 0283438f81..0de4473e63 100644 --- a/packages/lightwallet/mobile/src/components/slide-to-action/pan-gesture.ts +++ b/packages/lightwallet/mobile/src/components/slide-to-action/pan-gesture.ts @@ -6,7 +6,6 @@ const MAX_DRAG_ANGLE = 40; const DRAG_THRESHOLD = 20; export class PanGesture { - onMove: (delta: number) => void; onEnd: () => void; @@ -25,18 +24,14 @@ export class PanGesture { private listeners: Function[] = []; - constructor( - private plt: Platform, - private el: HTMLElement, - private rnd: Renderer2 - ) { + constructor(private plt: Platform, private el: HTMLElement, private rnd: Renderer2) { this.listeners.push( rnd.listen(el, 'mousedown', this._onStart.bind(this)), rnd.listen(el, 'touchstart', this._onStart.bind(this)), rnd.listen(el, 'touchmove', this._onMove.bind(this)), rnd.listen(el, 'mousemove', this._onMove.bind(this)), rnd.listen(el, 'touchend', this._onEnd.bind(this)), - rnd.listen(el, 'mouseup', this._onEnd.bind(this)) + rnd.listen(el, 'mouseup', this._onEnd.bind(this)), ); } @@ -60,7 +55,6 @@ export class PanGesture { this.initialCoords = coords; this.lastPosX = coords.x; - } private _onMove(ev: TouchEvent | MouseEvent) { @@ -70,18 +64,14 @@ export class PanGesture { if (!this.initialCoords) return; if (!this.isDragging) { - if (typeof this.shouldCapture !== 'boolean') - // we haven't decided yet if we want to capture this gesture + // we haven't decided yet if we want to capture this gesture this.checkGesture(coords); - if (this.shouldCapture === true) - // gesture is good, let's capture all next onTouchMove events + // gesture is good, let's capture all next onTouchMove events this.isDragging = true; - else - return; - + else return; } // stop anything else from capturing these events, to make sure the content doesn't slide @@ -96,7 +86,6 @@ export class PanGesture { // update last X value this.lastPosX = coords.x; - } private _onEnd(ev: TouchEvent | MouseEvent) { @@ -109,7 +98,6 @@ export class PanGesture { this.isDragging = false; this.shouldCapture = undefined; - } private checkGesture(newCoords: PointerCoordinates) { @@ -128,5 +116,4 @@ export class PanGesture { this.shouldCapture = Math.abs(cosine) > maxCosine; } } - } diff --git a/packages/lightwallet/mobile/src/components/slide-to-action/slide-to-action.ts b/packages/lightwallet/mobile/src/components/slide-to-action/slide-to-action.ts index cb753cc3ac..e3add2d991 100644 --- a/packages/lightwallet/mobile/src/components/slide-to-action/slide-to-action.ts +++ b/packages/lightwallet/mobile/src/components/slide-to-action/slide-to-action.ts @@ -1,6 +1,14 @@ import { - AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, OnDestroy, Output, Renderer2, - ViewChild + AfterViewInit, + ChangeDetectionStrategy, + Component, + ElementRef, + EventEmitter, + Input, + OnDestroy, + Output, + Renderer2, + ViewChild, } from '@angular/core'; import { Platform } from 'ionic-angular'; import { PanGesture } from './pan-gesture'; @@ -8,25 +16,28 @@ import { PanGesture } from './pan-gesture'; @Component({ selector: 'slide-to-action', templateUrl: 'slide-to-action.html', - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, }) export class SlideToActionComponent implements AfterViewInit, OnDestroy { - private _gesture: PanGesture; private _sliderPosition: number = 0; - @ViewChild('slider') _sliderElement: ElementRef; + @ViewChild('slider') + _sliderElement: ElementRef; _sliderNativeElement: HTMLElement; - @ViewChild('container') _containerElement: ElementRef; + @ViewChild('container') + _containerElement: ElementRef; - @Input() text: string = 'Slide to confirm'; - @Input() disabled: boolean; + @Input() + text: string = 'Slide to confirm'; + @Input() + disabled: boolean; - @Output() confirm: EventEmitter = new EventEmitter(); + @Output() + confirm: EventEmitter = new EventEmitter(); - constructor(private _plt: Platform, - private _rnd: Renderer2){} + constructor(private _plt: Platform, private _rnd: Renderer2) {} ngAfterViewInit() { this._sliderNativeElement = this._sliderElement.nativeElement; @@ -42,7 +53,7 @@ export class SlideToActionComponent implements AfterViewInit, OnDestroy { const newPos = Math.min(Math.max(0, -1 * delta + this._sliderPosition), maxPosition); if (newPos !== this._sliderPosition) { // if (newPos === maxPosition) { - // TODO use haptic/taptic feedback + // TODO use haptic/taptic feedback // } this._sliderPosition = newPos; this.moveSlider(0); @@ -52,7 +63,8 @@ export class SlideToActionComponent implements AfterViewInit, OnDestroy { this._gesture.onEnd = () => { if (this.disabled) return; switch (this._sliderPosition) { - case 0: return; + case 0: + return; case maxPosition: this.confirm.emit(); break; @@ -71,12 +83,16 @@ export class SlideToActionComponent implements AfterViewInit, OnDestroy { if (this.disabled) return; this._plt.raf(() => { if (duration) { - this._rnd.setStyle(this._sliderNativeElement, this._plt.Css.transition, `all ${ duration }ms ease-out`); + this._rnd.setStyle(this._sliderNativeElement, this._plt.Css.transition, `all ${duration}ms ease-out`); this._plt.timeout(() => { this._rnd.setStyle(this._sliderNativeElement, this._plt.Css.transition, ''); }, duration); } - this._rnd.setStyle(this._sliderNativeElement, this._plt.Css.transform, `translate3d(${ this._sliderPosition }px, 0, 0)`); + this._rnd.setStyle( + this._sliderNativeElement, + this._plt.Css.transform, + `translate3d(${this._sliderPosition}px, 0, 0)`, + ); }); } } diff --git a/packages/lightwallet/mobile/src/components/transaction-history/transaction-history.ts b/packages/lightwallet/mobile/src/components/transaction-history/transaction-history.ts index 9a27e3f378..f0e2e3f6f6 100644 --- a/packages/lightwallet/mobile/src/components/transaction-history/transaction-history.ts +++ b/packages/lightwallet/mobile/src/components/transaction-history/transaction-history.ts @@ -6,14 +6,13 @@ import { IDisplayTransaction, TransactionAction } from '@merit/common/models/tra @Component({ selector: 'transaction-history', templateUrl: 'transaction-history.html', - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, }) export class TransactionHistoryComponent { @Input() transactions: IDisplayTransaction[]; - constructor(private modalCtrl: ModalController) { - } + constructor(private modalCtrl: ModalController) {} viewTxDetails(tx: IDisplayTransaction) { return this.modalCtrl.create('TxDetailsView', { tx }, MERIT_MODAL_OPTS).present(); @@ -52,12 +51,23 @@ export class TransactionHistoryComponent { } isRegularTx(transaction: IDisplayTransaction) { - return !transaction.isGrowthReward && !transaction.easySendUrl && !transaction.isPoolReward && !transaction.isInvite && !transaction.isCoinbase; + return ( + !transaction.isGrowthReward && + !transaction.easySendUrl && + !transaction.isPoolReward && + !transaction.isInvite && + !transaction.isCoinbase + ); } private isReward(transaction: IDisplayTransaction) { try { - return Boolean(transaction.isCoinbase) && transaction.outputs[0] && !isNaN(transaction.outputs[0].index) && !transaction.isInvite; + return ( + Boolean(transaction.isCoinbase) && + transaction.outputs[0] && + !isNaN(transaction.outputs[0].index) && + !transaction.isInvite + ); } catch (e) { return false; } diff --git a/packages/lightwallet/mobile/src/directives/custom-header-color/custom-header-color.ts b/packages/lightwallet/mobile/src/directives/custom-header-color/custom-header-color.ts index fa5b996f7e..fb29da457e 100644 --- a/packages/lightwallet/mobile/src/directives/custom-header-color/custom-header-color.ts +++ b/packages/lightwallet/mobile/src/directives/custom-header-color/custom-header-color.ts @@ -1,10 +1,9 @@ import { AfterViewInit, Directive, ElementRef, Input, Renderer2 } from '@angular/core'; @Directive({ - selector: '[custom-header-color]' + selector: '[custom-header-color]', }) export class CustomHeaderColorDirective implements AfterViewInit { - private toolbarBackgroundNativeElement: HTMLElement; _color: string; @@ -21,8 +20,7 @@ export class CustomHeaderColorDirective implements AfterViewInit { return this._color; } - constructor(private rnd: Renderer2, - private el: ElementRef) {} + constructor(private rnd: Renderer2, private el: ElementRef) {} ngAfterViewInit() { this.toolbarBackgroundNativeElement = this.el.nativeElement.querySelector('.toolbar-background'); @@ -34,5 +32,4 @@ export class CustomHeaderColorDirective implements AfterViewInit { this.rnd.setStyle(this.toolbarBackgroundNativeElement, 'background', this.color); } } - } diff --git a/packages/lightwallet/mobile/src/directives/directives.module.ts b/packages/lightwallet/mobile/src/directives/directives.module.ts index 053a11a3b5..41a03ff9e2 100644 --- a/packages/lightwallet/mobile/src/directives/directives.module.ts +++ b/packages/lightwallet/mobile/src/directives/directives.module.ts @@ -2,8 +2,8 @@ import { NgModule } from '@angular/core'; import { CustomHeaderColorDirective } from './custom-header-color/custom-header-color'; import { EnterToNextDirective } from './enter-to-next/enter-to-next'; @NgModule({ - declarations: [CustomHeaderColorDirective, EnterToNextDirective], - imports: [], - exports: [CustomHeaderColorDirective, EnterToNextDirective] + declarations: [CustomHeaderColorDirective, EnterToNextDirective], + imports: [], + exports: [CustomHeaderColorDirective, EnterToNextDirective], }) export class DirectivesModule {} diff --git a/packages/lightwallet/mobile/src/directives/enter-to-next/enter-to-next.ts b/packages/lightwallet/mobile/src/directives/enter-to-next/enter-to-next.ts index 2f59d6c831..c5acbfb453 100644 --- a/packages/lightwallet/mobile/src/directives/enter-to-next/enter-to-next.ts +++ b/packages/lightwallet/mobile/src/directives/enter-to-next/enter-to-next.ts @@ -2,19 +2,17 @@ import { AfterViewInit, Directive, ElementRef } from '@angular/core'; import { Platform } from 'ionic-angular'; @Directive({ - selector: '[enter-to-next]' + selector: '[enter-to-next]', }) export class EnterToNextDirective implements AfterViewInit { - constructor(private plt: Platform, - private el: ElementRef) {} + constructor(private plt: Platform, private el: ElementRef) {} ngAfterViewInit() { const inputNodes: NodeListOf = this.el.nativeElement.querySelectorAll('input,textarea'); const inputs = []; let i = 0; - for (i; i < inputNodes.length; i++) - inputs.push(inputNodes[i]); + for (i; i < inputNodes.length; i++) inputs.push(inputNodes[i]); (this.el.nativeElement as HTMLElement).onkeyup = (event: KeyboardEvent) => { const { keyCode, target } = event; @@ -28,10 +26,8 @@ export class EnterToNextDirective implements AfterViewInit { }); if (input) { - if (index !== inputs.length - 1) - inputs[index + 1].focus(); - else - input.blur(); + if (index !== inputs.length - 1) inputs[index + 1].focus(); + else input.blur(); } } }; diff --git a/packages/lightwallet/mobile/src/modals/sms-notifications/sms-notifications.module.ts b/packages/lightwallet/mobile/src/modals/sms-notifications/sms-notifications.module.ts index d388de2379..5a88eb0120 100644 --- a/packages/lightwallet/mobile/src/modals/sms-notifications/sms-notifications.module.ts +++ b/packages/lightwallet/mobile/src/modals/sms-notifications/sms-notifications.module.ts @@ -3,11 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { SmsNotificationsModal } from './sms-notifications'; @NgModule({ - declarations: [ - SmsNotificationsModal - ], - imports: [ - IonicPageModule.forChild(SmsNotificationsModal) - ] + declarations: [SmsNotificationsModal], + imports: [IonicPageModule.forChild(SmsNotificationsModal)], }) export class SmsNotificationsModule {} diff --git a/packages/lightwallet/mobile/src/modals/sms-notifications/sms-notifications.ts b/packages/lightwallet/mobile/src/modals/sms-notifications/sms-notifications.ts index 51f01c5969..c0ba76adac 100644 --- a/packages/lightwallet/mobile/src/modals/sms-notifications/sms-notifications.ts +++ b/packages/lightwallet/mobile/src/modals/sms-notifications/sms-notifications.ts @@ -7,19 +7,21 @@ import { ToastControllerService } from '@merit/common/services/toast-controller. @IonicPage() @Component({ selector: 'modal-sms-notifications', - templateUrl: 'sms-notifications.html' + templateUrl: 'sms-notifications.html', }) export class SmsNotificationsModal { formData: FormGroup = this.formBuilder.group({ - phoneNumber: ['', [Validators.required, Validators.pattern(/\d{10,}/)]] + phoneNumber: ['', [Validators.required, Validators.pattern(/\d{10,}/)]], }); - constructor(private smsNotificationsService: SmsNotificationsService, - private viewCtrl: ViewController, - private toastCtrl: ToastControllerService, - private formBuilder: FormBuilder, - private plt: Platform, - private loadingCtrl: LoadingController) {} + constructor( + private smsNotificationsService: SmsNotificationsService, + private viewCtrl: ViewController, + private toastCtrl: ToastControllerService, + private formBuilder: FormBuilder, + private plt: Platform, + private loadingCtrl: LoadingController, + ) {} async save() { const loader = this.loadingCtrl.create({ content: 'Saving settings...' }); @@ -28,7 +30,7 @@ export class SmsNotificationsModal { const { value } = this.formData.get('phoneNumber'); try { - await this.smsNotificationsService.setSmsSubscription(true, value, this.plt.is('ios')? 'ios' : 'android'); + await this.smsNotificationsService.setSmsSubscription(true, value, this.plt.is('ios') ? 'ios' : 'android'); this.toastCtrl.success('You are now subscribed to SMS notifications'); this.dismiss(); } catch (err) { diff --git a/packages/lightwallet/mobile/src/pages/community/leaderboard/leaderboard.module.ts b/packages/lightwallet/mobile/src/pages/community/leaderboard/leaderboard.module.ts index afb3b3c39b..502667fcb4 100644 --- a/packages/lightwallet/mobile/src/pages/community/leaderboard/leaderboard.module.ts +++ b/packages/lightwallet/mobile/src/pages/community/leaderboard/leaderboard.module.ts @@ -4,12 +4,7 @@ import { LeaderboardView } from './leaderboard'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; @NgModule({ - declarations: [ - LeaderboardView - ], - imports: [ - IonicPageModule.forChild(LeaderboardView), - CommonPipesModule - ], + declarations: [LeaderboardView], + imports: [IonicPageModule.forChild(LeaderboardView), CommonPipesModule], }) export class LeaderboardModule {} diff --git a/packages/lightwallet/mobile/src/pages/community/leaderboard/leaderboard.ts b/packages/lightwallet/mobile/src/pages/community/leaderboard/leaderboard.ts index 4276bcdd46..008df333bb 100644 --- a/packages/lightwallet/mobile/src/pages/community/leaderboard/leaderboard.ts +++ b/packages/lightwallet/mobile/src/pages/community/leaderboard/leaderboard.ts @@ -4,27 +4,24 @@ import { SocialSharing } from '@ionic-native/social-sharing'; import { ProfileService } from '@merit/common/services/profile.service'; import { MeritWalletClient } from '@merit/common/merit-wallet-client'; - - @IonicPage() @Component({ selector: 'view-leaderboard', templateUrl: 'leaderboard.html', }) export class LeaderboardView { - wallets: Array; leaderboard: Array<{ - rank: number, - alias?: string, - address?: string, - anv: number + rank: number; + alias?: string; + address?: string; + anv: number; }>; displayLeaderboard: Array<{ - rank: number, - alias?: string, - address?: string, - anv: number + rank: number; + alias?: string; + address?: string; + anv: number; }>; ranks: Array; @@ -36,12 +33,7 @@ export class LeaderboardView { loading: boolean = true; - constructor( - private navCtrl: NavController, - private navParams: NavParams, - private profileService: ProfileService - ) { - } + constructor(private navCtrl: NavController, private navParams: NavParams, private profileService: ProfileService) {} async ionViewWillEnter() { this.wallets = await this.profileService.getConfimedWallets(); @@ -68,10 +60,12 @@ export class LeaderboardView { async getRankInfo() { const ranks = []; - await Promise.all(this.wallets.map(async (w) => { - const rankInfo = (await w.getCommunityRank()).ranks[0]; - ranks.push(rankInfo); - })); + await Promise.all( + this.wallets.map(async w => { + const rankInfo = (await w.getCommunityRank()).ranks[0]; + ranks.push(rankInfo); + }), + ); this.ranks = ranks; } @@ -84,5 +78,4 @@ export class LeaderboardView { isOwnWallet(r) { return !!this.ranks.some(w => w.address == r.address); } - } diff --git a/packages/lightwallet/mobile/src/pages/community/tell-people.module.ts b/packages/lightwallet/mobile/src/pages/community/tell-people.module.ts index 3dc24be23a..898ad42383 100644 --- a/packages/lightwallet/mobile/src/pages/community/tell-people.module.ts +++ b/packages/lightwallet/mobile/src/pages/community/tell-people.module.ts @@ -4,12 +4,7 @@ import { TellPeopleView } from './tell-people'; import { ClipModule } from 'ng2-clip'; @NgModule({ - declarations: [ - TellPeopleView - ], - imports: [ - IonicPageModule.forChild(TellPeopleView), - ClipModule - ], + declarations: [TellPeopleView], + imports: [IonicPageModule.forChild(TellPeopleView), ClipModule], }) export class TellPeopleModule {} diff --git a/packages/lightwallet/mobile/src/pages/community/tell-people.ts b/packages/lightwallet/mobile/src/pages/community/tell-people.ts index 2135a30c7e..eb1beeecd0 100644 --- a/packages/lightwallet/mobile/src/pages/community/tell-people.ts +++ b/packages/lightwallet/mobile/src/pages/community/tell-people.ts @@ -4,14 +4,12 @@ import { SocialSharing } from '@ionic-native/social-sharing'; import { ProfileService } from '@merit/common/services/profile.service'; import { ToastControllerService, IMeritToastConfig } from '@merit/common/services/toast-controller.service'; - @IonicPage() @Component({ selector: 'view-tell-people', templateUrl: 'tell-people.html', }) export class TellPeopleView { - inviteLink: string; inviteText: string; showShareButton: boolean = true; @@ -23,7 +21,7 @@ export class TellPeopleView { private toastCtrl: ToastControllerService, private socialSharing: SocialSharing, private platform: Platform, - private profileService: ProfileService + private profileService: ProfileService, ) { this.showShareButton = this.platform.is('cordova') && SocialSharing.installed(); } @@ -32,12 +30,11 @@ export class TellPeopleView { const wallets = await this.profileService.getWallets(); let wallet = wallets.find(w => w.confirmed); if (!wallet) wallet = wallets[0]; - const code = wallet.confirmed ? (wallet.rootAlias || wallet.rootAddress) : wallet.rootAlias; - this.inviteLink = 'https://wallet.merit.me?invite='+code; + const code = wallet.confirmed ? wallet.rootAlias || wallet.rootAddress : wallet.rootAlias; + this.inviteLink = 'https://wallet.merit.me?invite=' + code; this.inviteText = `Hey, let's use Merit, a digital currency for humans! ${this.inviteLink}`; } - copyToClipboard() { this.copied = true; this.toastCtrl.success('Copied to clipboard'); @@ -47,5 +44,4 @@ export class TellPeopleView { this.copied = true; if (SocialSharing.installed()) return this.socialSharing.share(this.inviteText); } - } diff --git a/packages/lightwallet/mobile/src/pages/globalsend-receive/globalsend-receive.module.ts b/packages/lightwallet/mobile/src/pages/globalsend-receive/globalsend-receive.module.ts index dfc0e72afb..b61ad48202 100644 --- a/packages/lightwallet/mobile/src/pages/globalsend-receive/globalsend-receive.module.ts +++ b/packages/lightwallet/mobile/src/pages/globalsend-receive/globalsend-receive.module.ts @@ -4,12 +4,7 @@ import { GlobalsendReceiveView } from './globalsend-receive'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; @NgModule({ - declarations: [ - GlobalsendReceiveView, - ], - imports: [ - IonicPageModule.forChild(GlobalsendReceiveView), - CommonPipesModule - ], + declarations: [GlobalsendReceiveView], + imports: [IonicPageModule.forChild(GlobalsendReceiveView), CommonPipesModule], }) export class GlobalsendReceiveModule {} diff --git a/packages/lightwallet/mobile/src/pages/globalsend-receive/globalsend-receive.ts b/packages/lightwallet/mobile/src/pages/globalsend-receive/globalsend-receive.ts index 1f67343d01..b4fd59c8bf 100644 --- a/packages/lightwallet/mobile/src/pages/globalsend-receive/globalsend-receive.ts +++ b/packages/lightwallet/mobile/src/pages/globalsend-receive/globalsend-receive.ts @@ -6,7 +6,7 @@ import { ModalController, NavController, NavParams, - ViewController + ViewController, } from 'ionic-angular'; import { EasyReceiveService } from '@merit/common/services/easy-receive.service'; import { ToastControllerService } from '@merit/common/services/toast-controller.service'; @@ -21,7 +21,6 @@ import { MERIT_MODAL_OPTS } from '@merit/common/utils/constants'; templateUrl: 'globalsend-receive.html', }) export class GlobalsendReceiveView { - receipt: EasyReceipt; data; @@ -46,7 +45,7 @@ export class GlobalsendReceiveView { private toastCtrl: ToastControllerService, private profileService: ProfileService, private modalCtrl: ModalController, - private events: Events + private events: Events, ) { this.receipt = this.navParams.get('receipt'); this.data = this.navParams.get('data'); @@ -60,16 +59,15 @@ export class GlobalsendReceiveView { if (await this.easyReceiveService.isInviteOnly(this.data.txs)) { const invitesAmount = await this.easyReceiveService.getInvitesAmount(this.data.txs); - this.amountStr = (invitesAmount == 1) ? 'Invite Token' : invitesAmount + ' Invite tokens'; + this.amountStr = invitesAmount == 1 ? 'Invite Token' : invitesAmount + ' Invite tokens'; this.type = 'MeritInvite'; } else { this.type = 'MeritMoney'; - this.amountStr = await this.easyReceiveService.getReceiverAmount(this.data.txs) + ' MRT'; + this.amountStr = (await this.easyReceiveService.getReceiverAmount(this.data.txs)) + ' MRT'; } this.loading = false; } - async accept() { let loader = this.loadingCtrl.create({ content: 'Accepting payment...' }); loader.present(); @@ -99,7 +97,6 @@ export class GlobalsendReceiveView { } async ignore() { - let loader = this.loadingCtrl.create({ content: 'Ignoring...' }); loader.present(); try { @@ -118,7 +115,6 @@ export class GlobalsendReceiveView { loader.present(); this.validationError = false; try { - let data = await this.easyReceiveService.validateEasyReceiptOnBlockchain(this.receipt, this.password); let txs = data.txs; @@ -133,15 +129,12 @@ export class GlobalsendReceiveView { this.data = data; this.mode = 'receive'; } - } catch (e) { console.warn(e); this.toastCtrl.error('Unexpected error occurred'); } loader.dismiss(); - - } private async acceptEasyReceipt(receipt: EasyReceipt, data: any): Promise { @@ -154,13 +147,17 @@ export class GlobalsendReceiveView { } selectWallet() { - const modal = this.modalCtrl.create('SelectWalletModal', { - selectedWallet: this.wallet, - showInvites: true, - availableWallets: this.wallets - }, MERIT_MODAL_OPTS); - - modal.onDidDismiss(async (wallet) => { + const modal = this.modalCtrl.create( + 'SelectWalletModal', + { + selectedWallet: this.wallet, + showInvites: true, + availableWallets: this.wallets, + }, + MERIT_MODAL_OPTS, + ); + + modal.onDidDismiss(async wallet => { if (wallet) { this.wallet = wallet; } @@ -168,5 +165,4 @@ export class GlobalsendReceiveView { modal.present(); } - } diff --git a/packages/lightwallet/mobile/src/pages/history/history.module.ts b/packages/lightwallet/mobile/src/pages/history/history.module.ts index c11b0d00b3..fed10a4fd2 100644 --- a/packages/lightwallet/mobile/src/pages/history/history.module.ts +++ b/packages/lightwallet/mobile/src/pages/history/history.module.ts @@ -4,12 +4,7 @@ import { HistoryView } from './history'; import { ComponentsModule } from '../../components/components.module'; @NgModule({ - declarations: [ - HistoryView, - ], - imports: [ - IonicPageModule.forChild(HistoryView), - ComponentsModule - ], + declarations: [HistoryView], + imports: [IonicPageModule.forChild(HistoryView), ComponentsModule], }) export class HistoryPageModule {} diff --git a/packages/lightwallet/mobile/src/pages/history/history.ts b/packages/lightwallet/mobile/src/pages/history/history.ts index a4f8048888..47d8caec91 100644 --- a/packages/lightwallet/mobile/src/pages/history/history.ts +++ b/packages/lightwallet/mobile/src/pages/history/history.ts @@ -15,7 +15,7 @@ import { IonicPage, ModalController } from 'ionic-angular'; @IonicPage() @Component({ selector: 'view-history', - templateUrl: 'history.html' + templateUrl: 'history.html', }) export class HistoryView { transactions: Array = []; @@ -29,13 +29,13 @@ export class HistoryView { offset: number = 0; limit: number = 10; - constructor(private profileService: ProfileService, - private contactsService: ContactsService, - private modalCtrl: ModalController, - private easyReceiveService: EasyReceiveService, - private feeService: FeeService - ) { - } + constructor( + private profileService: ProfileService, + private contactsService: ContactsService, + private modalCtrl: ModalController, + private easyReceiveService: EasyReceiveService, + private feeService: FeeService, + ) {} async ionViewDidLoad() { this.loading = true; @@ -43,10 +43,9 @@ export class HistoryView { this.selectDefaultWallet(); await this.loadHistory(); - this.easyReceiveService.cancelledEasySend$ - .subscribe(() => { - this.refreshHistory(); - }); + this.easyReceiveService.cancelledEasySend$.subscribe(() => { + this.refreshHistory(); + }); } async ionViewWillEnter() { @@ -83,7 +82,6 @@ export class HistoryView { } async loadMoreHistory(infiniter) { - this.offset += this.limit; try { const txs = await this.wallet.getTxHistory({ skip: this.offset, limit: this.limit, includeExtendedInfo: true }); @@ -97,16 +95,26 @@ export class HistoryView { private async formatHistory() { const easySends = await this.wallet.getGlobalSendHistory(); - this.transactions = await formatWalletHistory(this.txs, this.wallet, easySends, this.feeService, this.contactsService); + this.transactions = await formatWalletHistory( + this.txs, + this.wallet, + easySends, + this.feeService, + this.contactsService, + ); } selectWallet() { if (this.wallets.length == 1) return; - const modal = this.modalCtrl.create('SelectWalletModal', { - selectedWallet: this.wallet, - availableWallets: this.wallets.filter(w => w.confirmed) - }, MERIT_MODAL_OPTS); - modal.onDidDismiss((wallet) => { + const modal = this.modalCtrl.create( + 'SelectWalletModal', + { + selectedWallet: this.wallet, + availableWallets: this.wallets.filter(w => w.confirmed), + }, + MERIT_MODAL_OPTS, + ); + modal.onDidDismiss(wallet => { if (wallet) { this.wallet = wallet; this.loadHistory(); @@ -114,5 +122,4 @@ export class HistoryView { }); return modal.present(); } - } diff --git a/packages/lightwallet/mobile/src/pages/pin-lock/pin-lock.module.ts b/packages/lightwallet/mobile/src/pages/pin-lock/pin-lock.module.ts index 5e133f2bd0..7ebaf69387 100644 --- a/packages/lightwallet/mobile/src/pages/pin-lock/pin-lock.module.ts +++ b/packages/lightwallet/mobile/src/pages/pin-lock/pin-lock.module.ts @@ -3,11 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { PinLockView } from './pin-lock'; @NgModule({ - declarations: [ - PinLockView, - ], - imports: [ - IonicPageModule.forChild(PinLockView), - ], + declarations: [PinLockView], + imports: [IonicPageModule.forChild(PinLockView)], }) export class PinLockModule {} diff --git a/packages/lightwallet/mobile/src/pages/pin-lock/pin-lock.ts b/packages/lightwallet/mobile/src/pages/pin-lock/pin-lock.ts index d9539c2ece..842446de3a 100644 --- a/packages/lightwallet/mobile/src/pages/pin-lock/pin-lock.ts +++ b/packages/lightwallet/mobile/src/pages/pin-lock/pin-lock.ts @@ -9,10 +9,9 @@ import { TouchIdService } from '@merit/mobile/services/touch-id.service'; templateUrl: 'pin-lock.html', }) export class PinLockView { - pin: string = ''; - error:boolean; + error: boolean; isTouchIdAvailable: boolean; pinBlockedUntil: number; @@ -35,7 +34,7 @@ export class PinLockView { private platform: Platform, private viewCtrl: ViewController, private touchIdService: TouchIdService, - private navParams: NavParams + private navParams: NavParams, ) { if (this.navParams.get('newPinMode')) { this.mode = 'new'; @@ -70,9 +69,9 @@ export class PinLockView { this.blocked = false; this.blockedText = null; } else { - const minutes = Math.ceil(diff/60000); + const minutes = Math.ceil(diff / 60000); this.blocked = true; - this.blockedText = `You can try again in ${minutes > 1 ? minutes+' minutes' : 'one minute'}`; + this.blockedText = `You can try again in ${minutes > 1 ? minutes + ' minutes' : 'one minute'}`; } } @@ -105,7 +104,7 @@ export class PinLockView { if (this.attempts >= this.MAX_ATTEMPTS) { this.blocked = true; this.checkIsBlocked(); - this.pinBlockedUntil = Date.now()+1000*60*this.BLOCK_FOR_MINUTES; + this.pinBlockedUntil = Date.now() + 1000 * 60 * this.BLOCK_FOR_MINUTES; this.persistenceService.blockPin(this.pinBlockedUntil); this.attempts = 0; } @@ -137,5 +136,4 @@ export class PinLockView { close() { this.viewCtrl.dismiss(false); } - } diff --git a/packages/lightwallet/mobile/src/pages/send/easy-send-share/easy-send-share.module.ts b/packages/lightwallet/mobile/src/pages/send/easy-send-share/easy-send-share.module.ts index 9a47030e15..ffac47fa0c 100644 --- a/packages/lightwallet/mobile/src/pages/send/easy-send-share/easy-send-share.module.ts +++ b/packages/lightwallet/mobile/src/pages/send/easy-send-share/easy-send-share.module.ts @@ -4,12 +4,7 @@ import { EasySendShareView } from './easy-send-share'; import { ClipModule } from 'ng2-clip'; @NgModule({ - declarations: [ - EasySendShareView - ], - imports: [ - IonicPageModule.forChild(EasySendShareView), - ClipModule - ], + declarations: [EasySendShareView], + imports: [IonicPageModule.forChild(EasySendShareView), ClipModule], }) export class EasySendShareModule {} diff --git a/packages/lightwallet/mobile/src/pages/send/easy-send-share/easy-send-share.ts b/packages/lightwallet/mobile/src/pages/send/easy-send-share/easy-send-share.ts index b67241b26f..6d4d799c47 100644 --- a/packages/lightwallet/mobile/src/pages/send/easy-send-share/easy-send-share.ts +++ b/packages/lightwallet/mobile/src/pages/send/easy-send-share/easy-send-share.ts @@ -10,7 +10,6 @@ import { PlatformService } from '@merit/common/services/platform.service'; templateUrl: 'easy-send-share.html', }) export class EasySendShareView { - txData: any; easySendDelivered: boolean; @@ -27,7 +26,7 @@ export class EasySendShareView { private tabs: Tabs, private viewCtrl: ViewController, private platform: Platform, - private alertController: AlertController + private alertController: AlertController, ) { this.txData = this.navParams.get('txData'); this.easySendDelivered = this.navParams.get('easySendDelivered'); @@ -71,18 +70,23 @@ export class EasySendShareView { async toWallets() { if (this.copied) { - this.goToWallets(); + this.goToWallets(); } else { - this.alertController.create({ - title: 'Have you copied/shared your link?', - message: "Do not forget to copy or share your link, or you can loose money", - buttons: [ - { text: 'Cancel', role: 'cancel' }, - { text: 'Ok', handler: () => { - this.goToWallets(); - } } - ] - }).present(); + this.alertController + .create({ + title: 'Have you copied/shared your link?', + message: 'Do not forget to copy or share your link, or you can loose money', + buttons: [ + { text: 'Cancel', role: 'cancel' }, + { + text: 'Ok', + handler: () => { + this.goToWallets(); + }, + }, + ], + }) + .present(); } } diff --git a/packages/lightwallet/mobile/src/pages/settings/pin-settings/pin-settings.module.ts b/packages/lightwallet/mobile/src/pages/settings/pin-settings/pin-settings.module.ts index 90433ca34c..2f6da4bcd4 100644 --- a/packages/lightwallet/mobile/src/pages/settings/pin-settings/pin-settings.module.ts +++ b/packages/lightwallet/mobile/src/pages/settings/pin-settings/pin-settings.module.ts @@ -3,11 +3,7 @@ import { IonicPageModule } from 'ionic-angular'; import { PinSettingsView } from './pin-settings'; @NgModule({ - declarations: [ - PinSettingsView, - ], - imports: [ - IonicPageModule.forChild(PinSettingsView), - ], + declarations: [PinSettingsView], + imports: [IonicPageModule.forChild(PinSettingsView)], }) export class PinSettingsModule {} diff --git a/packages/lightwallet/mobile/src/pages/settings/pin-settings/pin-settings.ts b/packages/lightwallet/mobile/src/pages/settings/pin-settings/pin-settings.ts index 3f04faba25..ea5f384b37 100644 --- a/packages/lightwallet/mobile/src/pages/settings/pin-settings/pin-settings.ts +++ b/packages/lightwallet/mobile/src/pages/settings/pin-settings/pin-settings.ts @@ -2,21 +2,15 @@ import { Component } from '@angular/core'; import { IonicPage, ModalController } from 'ionic-angular'; import { PersistenceService } from '@merit/common/services/persistence.service'; - @IonicPage() @Component({ selector: 'view-pin-settings', templateUrl: 'pin-settings.html', }) export class PinSettingsView { - enabled: boolean; - constructor( - private modalCtrl: ModalController, - private persistenceService: PersistenceService - ) { - } + constructor(private modalCtrl: ModalController, private persistenceService: PersistenceService) {} async ionViewWillEnter() { this.enabled = await this.persistenceService.isPinEnabled(); @@ -24,17 +18,14 @@ export class PinSettingsView { async togglePin(enable) { if (enable) { - - const modal = this.modalCtrl.create('PinLockView', {newPinMode: true}); - modal.onDidDismiss(async (success) => { + const modal = this.modalCtrl.create('PinLockView', { newPinMode: true }); + modal.onDidDismiss(async success => { if (!success) this.enabled = false; }); modal.present(); - } else { - - const modal = this.modalCtrl.create('PinLockView', {showCancelButton: true}); - modal.onDidDismiss(async (success) => { + const modal = this.modalCtrl.create('PinLockView', { showCancelButton: true }); + modal.onDidDismiss(async success => { if (success) { await this.persistenceService.setPin(null); } else { @@ -42,8 +33,6 @@ export class PinSettingsView { } }); modal.present(); - } } - } diff --git a/packages/lightwallet/mobile/src/pages/unlock-requests/unlock-requests.module.ts b/packages/lightwallet/mobile/src/pages/unlock-requests/unlock-requests.module.ts index d59aee9172..0b6d8dc735 100644 --- a/packages/lightwallet/mobile/src/pages/unlock-requests/unlock-requests.module.ts +++ b/packages/lightwallet/mobile/src/pages/unlock-requests/unlock-requests.module.ts @@ -4,13 +4,7 @@ import { UnlockRequestsView } from './unlock-requests'; import { ComponentsModule } from '@merit/mobile/components/components.module'; @NgModule({ - declarations: [ - UnlockRequestsView, - ], - imports: [ - IonicPageModule.forChild(UnlockRequestsView), - ComponentsModule - ], + declarations: [UnlockRequestsView], + imports: [IonicPageModule.forChild(UnlockRequestsView), ComponentsModule], }) -export class UnlockRequestsModule { -} +export class UnlockRequestsModule {} diff --git a/packages/lightwallet/mobile/src/pages/unlock-requests/unlock-requests.ts b/packages/lightwallet/mobile/src/pages/unlock-requests/unlock-requests.ts index a0efff2b7a..6383fbf3fc 100644 --- a/packages/lightwallet/mobile/src/pages/unlock-requests/unlock-requests.ts +++ b/packages/lightwallet/mobile/src/pages/unlock-requests/unlock-requests.ts @@ -8,10 +8,9 @@ import { IonicPage, NavController, NavParams } from 'ionic-angular'; @IonicPage() @Component({ selector: 'view-unlock-requests', - templateUrl: 'unlock-requests.html' + templateUrl: 'unlock-requests.html', }) export class UnlockRequestsView { - hiddenRequests: IUnlockRequest[] = []; confirmedRequests: IUnlockRequest[] = []; activeRequests: IUnlockRequest[] = []; @@ -23,12 +22,13 @@ export class UnlockRequestsView { showHiddenRequests: boolean; - constructor(private navCtrl: NavController, - private navParams: NavParams, - private toastCtrl: ToastControllerService, - private unlockRequestService: UnlockRequestService, - private profileService: ProfileService) { - } + constructor( + private navCtrl: NavController, + private navParams: NavParams, + private toastCtrl: ToastControllerService, + private unlockRequestService: UnlockRequestService, + private profileService: ProfileService, + ) {} async ionViewWillEnter() { let vaults = await this.profileService.getVaults(); @@ -62,12 +62,12 @@ export class UnlockRequestsView { processRequest(request: IUnlockRequest) { if (!this.totalInvites) { - return this.toastCtrl.error('You don\'t have any invites you can spend now'); + return this.toastCtrl.error("You don't have any invites you can spend now"); } this.navCtrl.push('IncomingRequestModal', { request, - wallets: this.wallets + wallets: this.wallets, }); } diff --git a/packages/lightwallet/mobile/src/pages/vault/select-whitelist/select-whitelist.module.ts b/packages/lightwallet/mobile/src/pages/vault/select-whitelist/select-whitelist.module.ts index ff3c7e06f3..54b3032dbb 100644 --- a/packages/lightwallet/mobile/src/pages/vault/select-whitelist/select-whitelist.module.ts +++ b/packages/lightwallet/mobile/src/pages/vault/select-whitelist/select-whitelist.module.ts @@ -4,15 +4,8 @@ import { IonicPageModule } from 'ionic-angular'; import { SelectWhitelistModal } from './select-whitelist'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; - @NgModule({ - declarations: [ - SelectWhitelistModal, - ], - imports: [ - MomentModule, - CommonPipesModule, - IonicPageModule.forChild(SelectWhitelistModal), - ], + declarations: [SelectWhitelistModal], + imports: [MomentModule, CommonPipesModule, IonicPageModule.forChild(SelectWhitelistModal)], }) export class SelectWhitelistComponentModule {} diff --git a/packages/lightwallet/mobile/src/pages/vault/select-whitelist/select-whitelist.ts b/packages/lightwallet/mobile/src/pages/vault/select-whitelist/select-whitelist.ts index 69c72951d4..4d074eaaf7 100644 --- a/packages/lightwallet/mobile/src/pages/vault/select-whitelist/select-whitelist.ts +++ b/packages/lightwallet/mobile/src/pages/vault/select-whitelist/select-whitelist.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { IonicPage, NavController, NavParams, ViewController } from 'ionic-angular'; -import { DisplayWallet } from "@merit/common/models/display-wallet"; +import { DisplayWallet } from '@merit/common/models/display-wallet'; export interface IWhitelistWallet extends DisplayWallet { selected: boolean; @@ -12,13 +12,9 @@ export interface IWhitelistWallet extends DisplayWallet { templateUrl: 'select-whitelist.html', }) export class SelectWhitelistModal { - wallets: Array; - constructor( - public navParams: NavParams, - private viewCtrl: ViewController - ) { + constructor(public navParams: NavParams, private viewCtrl: ViewController) { this.wallets = this.navParams.get('availableWallets'); } diff --git a/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create-confirm/vault-create-confirm.module.ts b/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create-confirm/vault-create-confirm.module.ts index 71d8c1d1fe..1fe14ea083 100644 --- a/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create-confirm/vault-create-confirm.module.ts +++ b/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create-confirm/vault-create-confirm.module.ts @@ -2,16 +2,10 @@ import { NgModule } from '@angular/core'; import { IonicPageModule } from 'ionic-angular'; import { VaultCreateConfirmView } from './vault-create-confirm'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; -import { ClipModule } from 'ng2-clip' +import { ClipModule } from 'ng2-clip'; @NgModule({ - declarations: [ - VaultCreateConfirmView, - ], - imports: [ - IonicPageModule.forChild(VaultCreateConfirmView), - CommonPipesModule, - ClipModule - ], + declarations: [VaultCreateConfirmView], + imports: [IonicPageModule.forChild(VaultCreateConfirmView), CommonPipesModule, ClipModule], }) export class VaultCreateConfirmModule {} diff --git a/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create-confirm/vault-create-confirm.ts b/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create-confirm/vault-create-confirm.ts index 7d9e023f96..42e069e0ef 100644 --- a/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create-confirm/vault-create-confirm.ts +++ b/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create-confirm/vault-create-confirm.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { IonicPage, NavController, NavParams, AlertController, LoadingController } from 'ionic-angular'; -import { RateService } from "@merit/common/services/rate.service"; -import { IVaultCreateData, VaultsService } from "@merit/common/services/vaults.service"; +import { RateService } from '@merit/common/services/rate.service'; +import { IVaultCreateData, VaultsService } from '@merit/common/services/vaults.service'; import { ToastControllerService, IMeritToastConfig } from '@merit/common/services/toast-controller.service'; @IonicPage() @@ -10,10 +10,9 @@ import { ToastControllerService, IMeritToastConfig } from '@merit/common/service templateUrl: 'vault-create-confirm.html', }) export class VaultCreateConfirmView { - private vaultData: IVaultCreateData; - public copied:boolean; + public copied: boolean; constructor( private navCtrl: NavController, @@ -21,29 +20,34 @@ export class VaultCreateConfirmView { private alertCtrl: AlertController, private toastCtrl: ToastControllerService, private vaultsService: VaultsService, - private loadingCtrl: LoadingController + private loadingCtrl: LoadingController, ) { this.vaultData = this.navParams.get('vaultData'); } create() { if (!this.copied) { - this.alertCtrl.create({ - title: 'Did you write your master key phrase down?', - message: 'It is necessary to keep your money safe.', - buttons: [ - { text: 'Cancel', role: 'cancel' }, - { text: 'Yes', handler: () => { this.createVault(); }} - ] - }).present(); + this.alertCtrl + .create({ + title: 'Did you write your master key phrase down?', + message: 'It is necessary to keep your money safe.', + buttons: [ + { text: 'Cancel', role: 'cancel' }, + { + text: 'Yes', + handler: () => { + this.createVault(); + }, + }, + ], + }) + .present(); } else { this.createVault(); } - } private async createVault() { - const loader = this.loadingCtrl.create({ content: 'Creating vault' }); loader.present(); try { @@ -52,15 +56,13 @@ export class VaultCreateConfirmView { } catch (e) { console.error(e); this.toastCtrl.error(e.message || 'Failed to create vault'); - } finally { + } finally { loader.dismiss(); } - } public markCopied() { this.copied = true; this.toastCtrl.success('Copied to clipboard'); } - } diff --git a/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create.module.ts b/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create.module.ts index 509d4d352e..6f1c936645 100644 --- a/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create.module.ts +++ b/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create.module.ts @@ -5,13 +5,7 @@ import { VaultCreateView } from './vault-create'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; @NgModule({ - declarations: [ - VaultCreateView, - ], - imports: [ - IonicPageModule.forChild(VaultCreateView), - CommonPipesModule, - DirectivesModule - ] + declarations: [VaultCreateView], + imports: [IonicPageModule.forChild(VaultCreateView), CommonPipesModule, DirectivesModule], }) export class VaultCreateModule {} diff --git a/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create.ts b/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create.ts index 5d0fc01b2f..3f26c32b7c 100644 --- a/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create.ts +++ b/packages/lightwallet/mobile/src/pages/vault/vault-create/vault-create.ts @@ -1,21 +1,19 @@ import { Component } from '@angular/core'; import { IonicPage, NavParams, NavController, ModalController } from 'ionic-angular'; -import { RateService } from "@merit/common/services/rate.service"; +import { RateService } from '@merit/common/services/rate.service'; import { MERIT_MODAL_OPTS } from '@merit/common/utils/constants'; import { MeritWalletClient } from '@merit/common/merit-wallet-client'; import { mnemonicToHDPrivateKey } from '@merit/common/utils/mnemonic'; import { ENV } from '@app/env'; - @IonicPage({ - defaultHistory: ['WalletsView'] + defaultHistory: ['WalletsView'], }) @Component({ selector: 'view-vault-create', templateUrl: 'vault-create.html', }) export class VaultCreateView { - public vaultName: string; public wallets: Array; public wallet: MeritWalletClient; @@ -25,22 +23,20 @@ export class VaultCreateView { private navCtrl: NavController, private navParams: NavParams, private rateService: RateService, - private modalCtrl: ModalController + private modalCtrl: ModalController, ) { - this.wallets = this.navParams.get('wallets') - .filter(w => w.confirmed); + this.wallets = this.navParams.get('wallets').filter(w => w.confirmed); this.wallet = this.wallets[0]; } get isNextStepAvailable() { - return ( - this.vaultName - && this.amount - && this.amount > 0 - && this.rateService.mrtToMicro(this.amount) <= this.wallet.balance.totalConfirmedAmount - && this.wallets.filter(w => w.selected).length - ) + this.vaultName && + this.amount && + this.amount > 0 && + this.rateService.mrtToMicro(this.amount) <= this.wallet.balance.totalConfirmedAmount && + this.wallets.filter(w => w.selected).length + ); } get whiteList() { @@ -50,24 +46,31 @@ export class VaultCreateView { hasInsufficientConfirmedFunds() { if (!this.wallet) return false; const micros = this.rateService.mrtToMicro(this.amount); - return (this.wallet.balance.totalConfirmedAmount < micros) && (micros <= this.wallet.balance.spendableAmount); + return this.wallet.balance.totalConfirmedAmount < micros && micros <= this.wallet.balance.spendableAmount; } selectWhitelist() { - - let modal = this.modalCtrl.create('SelectWhitelistModal', { - selectedWallet: this.wallet, - availableWallets: this.wallets - }, MERIT_MODAL_OPTS); + let modal = this.modalCtrl.create( + 'SelectWhitelistModal', + { + selectedWallet: this.wallet, + availableWallets: this.wallets, + }, + MERIT_MODAL_OPTS, + ); modal.present(); } selectWallet() { - const modal = this.modalCtrl.create('SelectWalletModal', { - selectedWallet: this.wallet, - availableWallets: this.wallets - }, MERIT_MODAL_OPTS); - modal.onDidDismiss((wallet) => { + const modal = this.modalCtrl.create( + 'SelectWalletModal', + { + selectedWallet: this.wallet, + availableWallets: this.wallets, + }, + MERIT_MODAL_OPTS, + ); + modal.onDidDismiss(wallet => { if (wallet) { this.wallet = wallet; } @@ -81,13 +84,14 @@ export class VaultCreateView { let phrase = this.wallet.getNewMnemonic(null); let key = mnemonicToHDPrivateKey(phrase, '', network); - this.navCtrl.push('VaultCreateConfirmView', {vaultData: { - vaultName: this.vaultName, - whiteList: this.whiteList, - wallet: this.wallet, - amount: this.rateService.mrtToMicro(this.amount), - masterKey: {key, phrase} - }}); + this.navCtrl.push('VaultCreateConfirmView', { + vaultData: { + vaultName: this.vaultName, + whiteList: this.whiteList, + wallet: this.wallet, + amount: this.rateService.mrtToMicro(this.amount), + masterKey: { key, phrase }, + }, + }); } - } diff --git a/packages/lightwallet/mobile/src/pages/vault/vault-deposit/vault-deposit.module.ts b/packages/lightwallet/mobile/src/pages/vault/vault-deposit/vault-deposit.module.ts index dc918ddae1..d989436247 100644 --- a/packages/lightwallet/mobile/src/pages/vault/vault-deposit/vault-deposit.module.ts +++ b/packages/lightwallet/mobile/src/pages/vault/vault-deposit/vault-deposit.module.ts @@ -6,14 +6,7 @@ import { CommonPipesModule } from '@merit/common/common-pipes.module'; import { ComponentsModule } from '@merit/mobile/components/components.module'; @NgModule({ - declarations: [ - VaultDepositView, - ], - imports: [ - IonicPageModule.forChild(VaultDepositView), - CommonPipesModule, - ComponentsModule, - DirectivesModule - ], + declarations: [VaultDepositView], + imports: [IonicPageModule.forChild(VaultDepositView), CommonPipesModule, ComponentsModule, DirectivesModule], }) export class VaultDepositModule {} diff --git a/packages/lightwallet/mobile/src/pages/vault/vault-deposit/vault-deposit.ts b/packages/lightwallet/mobile/src/pages/vault/vault-deposit/vault-deposit.ts index eaff914417..7658befee7 100644 --- a/packages/lightwallet/mobile/src/pages/vault/vault-deposit/vault-deposit.ts +++ b/packages/lightwallet/mobile/src/pages/vault/vault-deposit/vault-deposit.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { IonicPage, NavController, NavParams, LoadingController } from 'ionic-angular'; -import { IVault } from "@merit/common/models/vault"; -import { RateService } from "@merit/common/services/rate.service"; +import { IVault } from '@merit/common/models/vault'; +import { RateService } from '@merit/common/services/rate.service'; import { VaultsService } from '@merit/common/services/vaults.service'; import { ToastControllerService, IMeritToastConfig } from '@merit/common/services/toast-controller.service'; @@ -11,7 +11,6 @@ import { ToastControllerService, IMeritToastConfig } from '@merit/common/service templateUrl: 'vault-deposit.html', }) export class VaultDepositView { - public vault: IVault; public amount; @@ -21,21 +20,21 @@ export class VaultDepositView { private rateService: RateService, private vaultsService: VaultsService, private loadingCtrl: LoadingController, - private toastCtrl: ToastControllerService + private toastCtrl: ToastControllerService, ) { this.vault = this.navParams.get('vault'); } get isSendingAvailable() { - return ( - this.amount - && this.amount > 0 - && this.rateService.mrtToMicro(this.amount) <= this.vault.walletClient.balance.totalConfirmedAmount - ) + return ( + this.amount && + this.amount > 0 && + this.rateService.mrtToMicro(this.amount) <= this.vault.walletClient.balance.totalConfirmedAmount + ); } async send() { - const loader = this.loadingCtrl.create({ content: 'Sending transaction...'}); + const loader = this.loadingCtrl.create({ content: 'Sending transaction...' }); loader.present(); try { await this.vaultsService.depositVault(this.vault, this.rateService.mrtToMicro(this.amount)); @@ -45,5 +44,4 @@ export class VaultDepositView { } loader.dismiss(); } - } diff --git a/packages/lightwallet/mobile/src/pages/vault/vault-edit/vault-edit.module.ts b/packages/lightwallet/mobile/src/pages/vault/vault-edit/vault-edit.module.ts index 1b7f2ab619..3267cc4db5 100644 --- a/packages/lightwallet/mobile/src/pages/vault/vault-edit/vault-edit.module.ts +++ b/packages/lightwallet/mobile/src/pages/vault/vault-edit/vault-edit.module.ts @@ -4,12 +4,7 @@ import { DirectivesModule } from '@merit/mobile/directives/directives.module'; import { VaultEditView } from './vault-edit'; @NgModule({ - declarations: [ - VaultEditView, - ], - imports: [ - IonicPageModule.forChild(VaultEditView), - DirectivesModule - ], + declarations: [VaultEditView], + imports: [IonicPageModule.forChild(VaultEditView), DirectivesModule], }) export class VaultEditModule {} diff --git a/packages/lightwallet/mobile/src/pages/vault/vault-edit/vault-edit.ts b/packages/lightwallet/mobile/src/pages/vault/vault-edit/vault-edit.ts index e7c498a642..ee451d3fc2 100644 --- a/packages/lightwallet/mobile/src/pages/vault/vault-edit/vault-edit.ts +++ b/packages/lightwallet/mobile/src/pages/vault/vault-edit/vault-edit.ts @@ -1,21 +1,26 @@ import { Component } from '@angular/core'; -import { IonicPage, NavController, NavParams, AlertController, ModalController, LoadingController } from 'ionic-angular'; -import { IWhitelistWallet } from "@merit/mobile/pages/vault/select-whitelist/select-whitelist"; -import { VaultsService } from "@merit/common/services/vaults.service"; +import { + IonicPage, + NavController, + NavParams, + AlertController, + ModalController, + LoadingController, +} from 'ionic-angular'; +import { IWhitelistWallet } from '@merit/mobile/pages/vault/select-whitelist/select-whitelist'; +import { VaultsService } from '@merit/common/services/vaults.service'; import { MERIT_MODAL_OPTS } from '@merit/common/utils/constants'; import { ToastControllerService, IMeritToastConfig } from '@merit/common/services/toast-controller.service'; import { MeritWalletClient } from '@merit/common/merit-wallet-client'; import { ENV } from '@app/env'; import { mnemonicToHDPrivateKey } from '@merit/common/utils/mnemonic'; - @IonicPage() @Component({ selector: 'view-vault-edit', templateUrl: 'vault-edit.html', }) export class VaultEditView { - public vault; public vaultName: string; @@ -34,7 +39,7 @@ export class VaultEditView { private vaultsService: VaultsService, private modalCtrl: ModalController, private loadingCtrl: LoadingController, - private toastCtrl: ToastControllerService + private toastCtrl: ToastControllerService, ) { this.vault = this.navParams.get('vault'); this.vaultName = this.vault.name; @@ -48,34 +53,40 @@ export class VaultEditView { }); this.whitelist = this.wallets.filter(w => w.selected); - this.previous = { + this.previous = { name: this.vault.name, whitelist: this.vault.whitelist.reduce((str, addr) => { - return str + addr.toString() - }, '') - } + return str + addr.toString(); + }, ''), + }; } - async edit(highlightInvalidInput = false, previousValue = '') { - if (this.whitelistChanged) { - - this.alertCtrl.create({ - title: 'Renew Vault?', - message: 'Changing the whitelist will cancel all pending transactions and charge a fee. Enter master key (phrase) to continue', - cssClass: highlightInvalidInput ? 'invalid-input-prompt' : '', - inputs: [{ - value: previousValue, - name: 'phrase', - placeholder: 'Master Phrase' - }], - buttons: [ - { text: 'Cancel', role: 'cancel', handler: () => {} }, - { text: 'Yes', handler: (value) => { this.renew(value.phrase); }} - ] - }).present(); - + this.alertCtrl + .create({ + title: 'Renew Vault?', + message: + 'Changing the whitelist will cancel all pending transactions and charge a fee. Enter master key (phrase) to continue', + cssClass: highlightInvalidInput ? 'invalid-input-prompt' : '', + inputs: [ + { + value: previousValue, + name: 'phrase', + placeholder: 'Master Phrase', + }, + ], + buttons: [ + { text: 'Cancel', role: 'cancel', handler: () => {} }, + { + text: 'Yes', + handler: value => { + this.renew(value.phrase); + }, + }, + ], + }) + .present(); } else { if (this.vaultName != this.previous.name) await this.editName(); this.navCtrl.pop(); @@ -83,11 +94,13 @@ export class VaultEditView { } private async renew(phrase) { - let xMasterKey; try { - const words = phrase.replace(/\s\s+/g, ' ').trim().toLowerCase(); - xMasterKey = mnemonicToHDPrivateKey(words, '', ENV.network); + const words = phrase + .replace(/\s\s+/g, ' ') + .trim() + .toLowerCase(); + xMasterKey = mnemonicToHDPrivateKey(words, '', ENV.network); } catch (ex) { console.warn(ex); return this.edit(true, phrase); @@ -103,10 +116,9 @@ export class VaultEditView { } catch (e) { console.warn(e); this.toastCtrl.error(e.message || 'Failed to renew vault'); - } finally { + } finally { loader.dismiss(); } - } private async editName() { @@ -114,12 +126,15 @@ export class VaultEditView { this.vault.name = this.vaultName; } - selectWhitelist() { - let modal = this.modalCtrl.create('SelectWhitelistModal', { - selectedWallet: this.wallet, - availableWallets: this.wallets - }, MERIT_MODAL_OPTS); + let modal = this.modalCtrl.create( + 'SelectWhitelistModal', + { + selectedWallet: this.wallet, + availableWallets: this.wallets, + }, + MERIT_MODAL_OPTS, + ); modal.onDidDismiss(() => { this.whitelist = this.wallets.filter(w => w.selected); this.checkWhitelistChange(); @@ -129,18 +144,12 @@ export class VaultEditView { private checkWhitelistChange() { const newWl = this.whitelist.reduce((str, w) => { - return str + w.rootAddress.toString() + return str + w.rootAddress.toString(); }, ''); - this.whitelistChanged = (this.previous.whitelist != newWl); + this.whitelistChanged = this.previous.whitelist != newWl; } get isEditAvailable() { - return ( - this.vaultName - && this.whitelist.length - && ((this.vaultName != this.previous.name) || this.whitelistChanged) - ) + return this.vaultName && this.whitelist.length && (this.vaultName != this.previous.name || this.whitelistChanged); } - - } diff --git a/packages/lightwallet/mobile/src/pages/vault/vault-spend/vault-spend.module.ts b/packages/lightwallet/mobile/src/pages/vault/vault-spend/vault-spend.module.ts index 8aed24e595..5169dbd755 100644 --- a/packages/lightwallet/mobile/src/pages/vault/vault-spend/vault-spend.module.ts +++ b/packages/lightwallet/mobile/src/pages/vault/vault-spend/vault-spend.module.ts @@ -6,14 +6,7 @@ import { ComponentsModule } from '@merit/mobile/components/components.module'; import { CommonPipesModule } from '@merit/common/common-pipes.module'; @NgModule({ - declarations: [ - VaultSpendView, - ], - imports: [ - IonicPageModule.forChild(VaultSpendView), - CommonPipesModule, - ComponentsModule, - DirectivesModule - ], + declarations: [VaultSpendView], + imports: [IonicPageModule.forChild(VaultSpendView), CommonPipesModule, ComponentsModule, DirectivesModule], }) export class VaultSpendModule {} diff --git a/packages/lightwallet/mobile/src/pages/vault/vault-spend/vault-spend.ts b/packages/lightwallet/mobile/src/pages/vault/vault-spend/vault-spend.ts index 58e85ecf57..642dc89788 100644 --- a/packages/lightwallet/mobile/src/pages/vault/vault-spend/vault-spend.ts +++ b/packages/lightwallet/mobile/src/pages/vault/vault-spend/vault-spend.ts @@ -4,9 +4,14 @@ import { IVault } from '@merit/common/models/vault'; import { VaultsService } from '@merit/common/services/vaults.service'; import { ToastControllerService, IMeritToastConfig } from '@merit/common/services/toast-controller.service'; import { MERIT_MODAL_OPTS } from '@merit/common/utils/constants'; -import { RateService } from "@merit/common/services/rate.service"; +import { RateService } from '@merit/common/services/rate.service'; -interface IWhiteListRecord {name: string, confirmed: boolean, address: string, alias: string} +interface IWhiteListRecord { + name: string; + confirmed: boolean; + address: string; + alias: string; +} @IonicPage() @Component({ @@ -14,7 +19,6 @@ interface IWhiteListRecord {name: string, confirmed: boolean, address: string, a templateUrl: 'vault-spend.html', }) export class VaultSpendView { - public amount: number; public vault: IVault; public whitelist: Array; @@ -28,26 +32,25 @@ export class VaultSpendView { private loadingCtrl: LoadingController, private toastCtrl: ToastControllerService, private modalCtrl: ModalController, - private rateService: RateService + private rateService: RateService, ) { this.whitelist = this.navParams.get('whitelist').map(w => { return { name: w.label, confirmed: true, address: w.address, - alias: w.alias - } + alias: w.alias, + }; }); this.recipient = this.whitelist[0]; this.vault = this.navParams.get('vault'); } async send() { - const loader = this.loadingCtrl.create({ content: 'Creating transaction' }); loader.present(); try { - const amount = this.rateService.mrtToMicro(this.amount); + const amount = this.rateService.mrtToMicro(this.amount); const address = this.recipient.address; await this.vaultsService.sendFromVault(this.vault, amount, address); this.navCtrl.pop(); @@ -60,23 +63,23 @@ export class VaultSpendView { } selectWallet() { - const modal = this.modalCtrl.create('SelectWalletModal', { - selectedWallet: this.recipient, - availableWallets: this.whitelist - }, MERIT_MODAL_OPTS); - modal.onDidDismiss((wallet) => { + const modal = this.modalCtrl.create( + 'SelectWalletModal', + { + selectedWallet: this.recipient, + availableWallets: this.whitelist, + }, + MERIT_MODAL_OPTS, + ); + modal.onDidDismiss(wallet => { if (wallet) { - this.recipient = wallet + this.recipient = wallet; } }); return modal.present(); } get isSendingAvailable() { - return ( - this.amount - && this.rateService.mrtToMicro(this.amount) <= this.vault.amount - ) + return this.amount && this.rateService.mrtToMicro(this.amount) <= this.vault.amount; } - } diff --git a/packages/lightwallet/mobile/src/pages/vault/vault.module.ts b/packages/lightwallet/mobile/src/pages/vault/vault.module.ts index 391ec4102f..41032d3b06 100644 --- a/packages/lightwallet/mobile/src/pages/vault/vault.module.ts +++ b/packages/lightwallet/mobile/src/pages/vault/vault.module.ts @@ -6,14 +6,7 @@ import { ComponentsModule } from '@merit/mobile/components/components.module'; import { MomentModule } from 'ngx-moment'; @NgModule({ - declarations: [ - VaultView, - ], - imports: [ - IonicPageModule.forChild(VaultView), - CommonPipesModule, - ComponentsModule, - MomentModule - ] + declarations: [VaultView], + imports: [IonicPageModule.forChild(VaultView), CommonPipesModule, ComponentsModule, MomentModule], }) export class VaultModule {} diff --git a/packages/lightwallet/mobile/src/pages/vault/vault.ts b/packages/lightwallet/mobile/src/pages/vault/vault.ts index 5b8cf7272a..f95483b679 100644 --- a/packages/lightwallet/mobile/src/pages/vault/vault.ts +++ b/packages/lightwallet/mobile/src/pages/vault/vault.ts @@ -1,33 +1,31 @@ import { Component } from '@angular/core'; -import { IonicPage, NavParams } from 'ionic-angular'; +import { IonicPage, NavParams } from 'ionic-angular'; import { IVault } from '@merit/common/models/vault'; -import { VaultsService }from '@merit/common/services/vaults.service'; -import { AddressService } from "@merit/common/services/address.service"; +import { VaultsService } from '@merit/common/services/vaults.service'; +import { AddressService } from '@merit/common/services/address.service'; import { ModalController } from 'ionic-angular'; import { MERIT_MODAL_OPTS } from '@merit/common/utils/constants'; import { MeritWalletClient } from '@merit/common/merit-wallet-client'; - @IonicPage() @Component({ selector: 'view-vault', templateUrl: 'vault.html', }) export class VaultView { - public vault: IVault; public vaultId: string; public wallets: Array; public transactions: Array; public indexedWallets: { [rootAddress: string]: MeritWalletClient }; - public whitelist: Array<{label: string, address: string, alias: string}>; + public whitelist: Array<{ label: string; address: string; alias: string }>; constructor( private navParams: NavParams, private vaultsService: VaultsService, private addressService: AddressService, - private modalCtrl: ModalController + private modalCtrl: ModalController, ) { this.vault = this.navParams.get('vault'); this.vaultId = this.navParams.get('vaultId'); @@ -39,34 +37,29 @@ export class VaultView { } async ionViewWillEnter() { - this.whitelist = await this.formatWhiteList(this.vault.whitelist); const transactions = await this.vaultsService.getTxHistory(this.vault); - this.transactions = transactions.map((tx:any) => { + this.transactions = transactions.map((tx: any) => { if (tx.type == 'renewal') { tx.label = 'renewed'; - } else if (tx.type == 'stored') { + } else if (tx.type == 'stored') { tx.label = 'Stored'; } else { - tx.label = this.indexedWallets[tx.address] - ? this.indexedWallets[tx.address].name - : (tx.alias || tx.address); + tx.label = this.indexedWallets[tx.address] ? this.indexedWallets[tx.address].name : tx.alias || tx.address; tx.amount += tx.fee; //showing full spent amount when sending from vault } return tx; }); - } - private async formatWhiteList(whitelist) { const formattedWhitelist = []; for (let address of whitelist) { const addressInfo = await this.addressService.getAddressInfo(address); if (addressInfo.isConfirmed) { const wallet = this.indexedWallets[addressInfo.address]; - const label = (wallet && wallet.name) ? wallet.name : (addressInfo.alias || addressInfo.address); - formattedWhitelist.push({label, address: addressInfo.address, alias: addressInfo.alias}); + const label = wallet && wallet.name ? wallet.name : addressInfo.alias || addressInfo.address; + formattedWhitelist.push({ label, address: addressInfo.address, alias: addressInfo.alias }); } } return formattedWhitelist; @@ -75,5 +68,4 @@ export class VaultView { viewTxDetails(tx) { return this.modalCtrl.create('TxDetailsView', { tx }, MERIT_MODAL_OPTS).present(); } - } diff --git a/packages/lightwallet/mobile/src/service-worker.js b/packages/lightwallet/mobile/src/service-worker.js index ffbbb068f3..0d81ca0f72 100644 --- a/packages/lightwallet/mobile/src/service-worker.js +++ b/packages/lightwallet/mobile/src/service-worker.js @@ -3,25 +3,22 @@ * more info on how to use sw-toolbox to custom configure your service worker. */ - 'use strict'; importScripts('./build/sw-toolbox.js'); self.toolbox.options.cache = { - name: 'ionic-cache' + name: 'ionic-cache', }; // pre-cache our key assets -self.toolbox.precache( - [ - './build/main.js', - './build/vendor.js', - './build/main.css', - './build/polyfills.js', - 'index.html', - 'manifest.json' - ] -); +self.toolbox.precache([ + './build/main.js', + './build/vendor.js', + './build/main.css', + './build/polyfills.js', + 'index.html', + 'manifest.json', +]); // dynamically cache any other local assets self.toolbox.router.any('/*', self.toolbox.fastest); diff --git a/packages/lightwallet/mobile/src/services/contacts.service.ts b/packages/lightwallet/mobile/src/services/contacts.service.ts index 7414430f1f..c120ddbab8 100644 --- a/packages/lightwallet/mobile/src/services/contacts.service.ts +++ b/packages/lightwallet/mobile/src/services/contacts.service.ts @@ -4,23 +4,18 @@ import { Diagnostic } from '@ionic-native/diagnostic'; import { Contacts } from '@ionic-native/contacts'; import { PersistenceService } from '@merit/common/services/persistence.service'; -const DESIRED_FIELDS = [ - 'displayName', - 'emails', - 'name', - 'phoneNumbers', - 'photos' -]; +const DESIRED_FIELDS = ['displayName', 'emails', 'name', 'phoneNumbers', 'photos']; @Injectable() export class ContactsService extends OriginalContactsProvider { - private devicePermissionGranted: boolean; private devicePermissionStatus: string; - constructor(private deviceContactsProvider: Contacts, - private deviceDiagnosticProvider: Diagnostic, - persistenceService: PersistenceService) { + constructor( + private deviceContactsProvider: Contacts, + private deviceDiagnosticProvider: Diagnostic, + persistenceService: PersistenceService, + ) { super(persistenceService); } @@ -33,31 +28,33 @@ export class ContactsService extends OriginalContactsProvider { } async requestDevicePermission() { - if (!Diagnostic.installed()) - return false; + if (!Diagnostic.installed()) return false; // we have permission, no need to request it again - if (await this.hasDevicePermission()) - return true; + if (await this.hasDevicePermission()) return true; // we do not have permission - const status: string = this.devicePermissionStatus = await this.deviceDiagnosticProvider.requestContactsAuthorization(); + const status: string = (this.devicePermissionStatus = await this.deviceDiagnosticProvider.requestContactsAuthorization()); // permission was granted - if ([this.deviceDiagnosticProvider.permissionStatus.GRANTED, this.deviceDiagnosticProvider.permissionStatus.GRANTED_WHEN_IN_USE].indexOf(status) > -1) - return this.devicePermissionGranted = true; + if ( + [ + this.deviceDiagnosticProvider.permissionStatus.GRANTED, + this.deviceDiagnosticProvider.permissionStatus.GRANTED_WHEN_IN_USE, + ].indexOf(status) > -1 + ) + return (this.devicePermissionGranted = true); // permission wasn't granted return false; } async getDeviceContacts() { - if (!await this.hasDevicePermission()) - return []; + if (!(await this.hasDevicePermission())) return []; return this.deviceContactsProvider.find(['emails', 'phoneNumbers'], { desiredFields: DESIRED_FIELDS, - multiple: true + multiple: true, }); } @@ -65,7 +62,12 @@ export class ContactsService extends OriginalContactsProvider { await this.init; if (this.devicePermissionGranted === true) return true; - return [this.deviceDiagnosticProvider.permissionStatus.DENIED, this.deviceDiagnosticProvider.permissionStatus.DENIED_ALWAYS].indexOf(this.devicePermissionStatus) > -1; + return ( + [ + this.deviceDiagnosticProvider.permissionStatus.DENIED, + this.deviceDiagnosticProvider.permissionStatus.DENIED_ALWAYS, + ].indexOf(this.devicePermissionStatus) > -1 + ); } async getAllMeritContacts() { @@ -74,7 +76,9 @@ export class ContactsService extends OriginalContactsProvider { private async hasDevicePermission() { if (!Diagnostic.installed()) return false; - return (await this.deviceDiagnosticProvider.getContactsAuthorizationStatus()) === this.deviceDiagnosticProvider.permissionStatus.GRANTED; + return ( + (await this.deviceDiagnosticProvider.getContactsAuthorizationStatus()) === + this.deviceDiagnosticProvider.permissionStatus.GRANTED + ); } - } diff --git a/packages/lightwallet/mobile/src/services/mobile-alert.service.ts b/packages/lightwallet/mobile/src/services/mobile-alert.service.ts index a2a7057ec9..c3f663a3bc 100644 --- a/packages/lightwallet/mobile/src/services/mobile-alert.service.ts +++ b/packages/lightwallet/mobile/src/services/mobile-alert.service.ts @@ -16,10 +16,18 @@ export class MobileAlertService extends AlertService { .create({ title: 'Enter wallet password', cssClass: highlightInvalid ? 'invalid-input-prompt password-prompt' : 'password-prompt', - inputs: [ { name: 'password', placeholder: 'Password', type: 'text' } ], + inputs: [{ name: 'password', placeholder: 'Password', type: 'text' }], buttons: [ - {text: 'Cancel', role: 'cancel', handler: () => { reject(); }}, - { text: 'Ok', handler: data => { + { + text: 'Cancel', + role: 'cancel', + handler: () => { + reject(); + }, + }, + { + text: 'Ok', + handler: data => { if (!data.password) { showPassPrompt(true); } else { @@ -31,10 +39,11 @@ export class MobileAlertService extends AlertService { showPassPrompt(true); } } - } - } - ] - }).present(); + }, + }, + ], + }) + .present(); }; showPassPrompt(); diff --git a/packages/lightwallet/mobile/src/services/mobile-polling-notifications.service.ts b/packages/lightwallet/mobile/src/services/mobile-polling-notifications.service.ts index ef991812be..ab1fed8309 100644 --- a/packages/lightwallet/mobile/src/services/mobile-polling-notifications.service.ts +++ b/packages/lightwallet/mobile/src/services/mobile-polling-notifications.service.ts @@ -7,9 +7,7 @@ import { pick } from 'lodash'; @Injectable() export class MobilePollingNotificationsService extends PollingNotificationsService { - constructor(profileService: ProfileService, - logger: LoggerService, - private configService: ConfigService) { + constructor(profileService: ProfileService, logger: LoggerService, private configService: ConfigService) { super(profileService, logger, null, null); } @@ -24,11 +22,14 @@ export class MobilePollingNotificationsService extends PollingNotificationsServi const wallet = (await this.profileService.getWallets()).find(w => w.id == notification.walletId); if (wallet) { - this.profileService.propogateBwsEvent({ - data: pick(notification, 'amount', 'address', 'txid'), - type: notification.type, - walletId: notification.walletId - }, wallet); + this.profileService.propogateBwsEvent( + { + data: pick(notification, 'amount', 'address', 'txid'), + type: notification.type, + walletId: notification.walletId, + }, + wallet, + ); } } }); diff --git a/packages/lightwallet/mobile/src/services/mobile-toast-controller.service.ts b/packages/lightwallet/mobile/src/services/mobile-toast-controller.service.ts index ff8796873c..68129cc8ab 100644 --- a/packages/lightwallet/mobile/src/services/mobile-toast-controller.service.ts +++ b/packages/lightwallet/mobile/src/services/mobile-toast-controller.service.ts @@ -8,7 +8,7 @@ export const DefaultToastConfig: Partial = { duration: 3000, position: 'top', cssClass: 'toast-message', - showCloseButton: true + showCloseButton: true, }; @Injectable() @@ -18,14 +18,14 @@ export class MobileToastControllerService implements ToastControllerService { create(opts?: IMeritToastConfig): Toast { return this.toastCtrl.create({ ...DefaultToastConfig, - ...(opts || {}) + ...(opts || {}), } as ToastOptions); } createSticky(opts?: IMeritToastConfig): Toast { opts = { - ...DefaultToastConfig as IMeritToastConfig, - ...(opts || {}) + ...(DefaultToastConfig as IMeritToastConfig), + ...(opts || {}), }; delete opts.duration; @@ -36,7 +36,7 @@ export class MobileToastControllerService implements ToastControllerService { success(message: string) { return this.create({ message, - cssClass: 'toast-success' + cssClass: 'toast-success', }).present(); } @@ -47,7 +47,7 @@ export class MobileToastControllerService implements ToastControllerService { error(message: string) { return this.create({ message, - cssClass: 'toast-error' + cssClass: 'toast-error', }).present(); } } diff --git a/packages/lightwallet/mobile/src/services/touch-id.service.ts b/packages/lightwallet/mobile/src/services/touch-id.service.ts index e7405af182..bdc8627b8d 100644 --- a/packages/lightwallet/mobile/src/services/touch-id.service.ts +++ b/packages/lightwallet/mobile/src/services/touch-id.service.ts @@ -7,15 +7,15 @@ import { LoggerService } from '@merit/common/services/logger.service'; @Injectable() export class TouchIdService { - private _isAvailable: boolean; - constructor(private touchId: TouchID, - private androidFingerprintAuth: AndroidFingerprintAuth, - private platform: PlatformService, - private config: ConfigService, - private log: LoggerService) { - } + constructor( + private touchId: TouchID, + private androidFingerprintAuth: AndroidFingerprintAuth, + private platform: PlatformService, + private config: ConfigService, + private log: LoggerService, + ) {} async checkIOS() { try { @@ -51,8 +51,7 @@ export class TouchIdService { return; } - this.log.info('Didn\'t authenticate!'); - + this.log.info("Didn't authenticate!"); } catch (error) { if (error === this.androidFingerprintAuth.ERRORS.FINGERPRINT_CANCELLED) { this.log.warn('Fingerprint authentication cancelled'); @@ -66,12 +65,11 @@ export class TouchIdService { async isAvailable() { if (this._isAvailable == undefined) { - await this.platform.ready(); if (this.platform.isAndroid) { this._isAvailable = await this.checkAndroid(); - } else if (this.platform.isIOS) { - this._isAvailable = await this.checkIOS(); + } else if (this.platform.isIOS) { + this._isAvailable = await this.checkIOS(); } else { this._isAvailable = false; } diff --git a/packages/lightwallet/mobile/webpack.config.js b/packages/lightwallet/mobile/webpack.config.js index 8e569f5387..7fe199b03a 100644 --- a/packages/lightwallet/mobile/webpack.config.js +++ b/packages/lightwallet/mobile/webpack.config.js @@ -13,26 +13,25 @@ if (env !== 'prod' && env !== 'dev') { webpackConfig[env] = webpackConfig.dev; } - if (env === 'prod') { webpackConfig.prod.resolve = { alias: { '@app/env': path.resolve(environmentPath('prod')), '@merit/mobile': path.resolve(__dirname, './src'), - '@merit/common': path.resolve(__dirname, '../common') + '@merit/common': path.resolve(__dirname, '../common'), }, extensions: ['.ts', '.js', '.json'], - modules: [path.resolve('node_modules')] + modules: [path.resolve('node_modules')], }; } else { webpackConfig.dev.resolve = { alias: { '@app/env': path.resolve(environmentPath('dev')), '@merit/mobile': path.resolve(__dirname, './src'), - '@merit/common': path.resolve(__dirname, '../common') + '@merit/common': path.resolve(__dirname, '../common'), }, extensions: ['.ts', '.js', '.json'], - modules: [path.resolve('node_modules')] + modules: [path.resolve('node_modules')], }; } @@ -50,14 +49,18 @@ function environmentPath(env) { const DEFINE_PLUGIN = new webpack.DefinePlugin({ WEBPACK_CONFIG: { - COMMIT_HASH: JSON.stringify(execSync('git rev-parse --short HEAD').toString().trim()), - VERSION: JSON.stringify(require('./package.json').version) - } + COMMIT_HASH: JSON.stringify( + execSync('git rev-parse --short HEAD') + .toString() + .trim(), + ), + VERSION: JSON.stringify(require('./package.json').version), + }, }); webpackConfig.dev.plugins.push(DEFINE_PLUGIN); webpackConfig.prod.plugins.push(DEFINE_PLUGIN); -module.exports = function () { +module.exports = function() { return webpackConfig; }; diff --git a/packages/lightwallet/protractor.common.conf.js b/packages/lightwallet/protractor.common.conf.js index 56cab1ddf2..88d31c0300 100644 --- a/packages/lightwallet/protractor.common.conf.js +++ b/packages/lightwallet/protractor.common.conf.js @@ -1,7 +1,7 @@ const { SpecReporter } = require('jasmine-spec-reporter'); const IS_CI = process.env.CIRCLECI || process.env.JENKINS_URL; const COMMIT = process.env.CIRCLE_SHA1 || process.env.GIT_COMMIT || 'LOCAL'; -const BS_IDENTIFIER = `${ process.env.CIRCLE_BUILD_NUM }-${ process.env.CIRCLE_JOB }`; +const BS_IDENTIFIER = `${process.env.CIRCLE_BUILD_NUM}-${process.env.CIRCLE_JOB}`; const config = { allScriptsTimeout: 11000, @@ -11,14 +11,14 @@ const config = { jasmineNodeOpts: { showColors: true, defaultTimeoutInterval: 100000, - print: function() {} + print: function() {}, }, onPrepare() { require('ts-node').register({ - project: 'tsconfig.e2e.json' + project: 'tsconfig.e2e.json', }); jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); - } + }, }; if (IS_CI) { @@ -26,23 +26,27 @@ if (IS_CI) { config.seleniumAddress = 'http://hub-cloud.browserstack.com/wd/hub'; config.beforeLaunch = () => { - console.log("Connecting local"); - return new Promise(function(resolve, reject){ + console.log('Connecting local'); + return new Promise(function(resolve, reject) { exports.bs_local = new browserstack.Local(); - exports.bs_local.start({ - key: process.env.BROWSERSTACK_KEY, - localIdentifier: BS_IDENTIFIER - }, function(error) { - if (error) return reject(error); - console.log('Connected. Now testing...'); - resolve(); - }); + exports.bs_local.start( + { + key: process.env.BROWSERSTACK_KEY, + localIdentifier: BS_IDENTIFIER, + }, + function(error) { + if (error) return reject(error); + console.log('Connected. Now testing...'); + resolve(); + }, + ); }); }; - config.afterLaunch = () => new Promise(resolve => { - exports.bs_local.stop(resolve); - }); + config.afterLaunch = () => + new Promise(resolve => { + exports.bs_local.stop(resolve); + }); config.directConnect = false; } @@ -53,7 +57,7 @@ exports.browserStackCommon = { 'browserstack.local': true, 'browserstack.localIdentifier': BS_IDENTIFIER, resolution: '1920x1080', - name: 'LightwalletStack-' + COMMIT + name: 'LightwalletStack-' + COMMIT, }; exports.config = config; diff --git a/packages/lightwallet/protractor.desktop.conf.js b/packages/lightwallet/protractor.desktop.conf.js index 9182559fcb..6e8712414a 100644 --- a/packages/lightwallet/protractor.desktop.conf.js +++ b/packages/lightwallet/protractor.desktop.conf.js @@ -2,29 +2,25 @@ const { config, browserStackCommon } = require('./protractor.common.conf'); const IS_CI = process.env.CIRCLECI || process.env.JENKINS_URL; config.baseUrl = 'http://localhost:8888/'; -config.specs = [ - './desktop/e2e/app.e2e-spec.ts', - './desktop/e2e/**/*.e2e-spec.ts' -]; +config.specs = ['./desktop/e2e/app.e2e-spec.ts', './desktop/e2e/**/*.e2e-spec.ts']; if (IS_CI) { config.multiCapabilities.push( { ...browserStackCommon, - browserName: 'Chrome' + browserName: 'Chrome', }, { ...browserStackCommon, browserName: 'Safari', browser_version: '11.0', os: 'OS X', - os_version: 'High Sierra' - } - , + os_version: 'High Sierra', + }, { ...browserStackCommon, - browserName: 'Firefox' - } + browserName: 'Firefox', + }, ); } else { config.multiCapabilities.push({ browserName: 'chrome' }); diff --git a/packages/lightwallet/protractor.mobile.conf.js b/packages/lightwallet/protractor.mobile.conf.js index a452a9fbbf..345efde1f7 100644 --- a/packages/lightwallet/protractor.mobile.conf.js +++ b/packages/lightwallet/protractor.mobile.conf.js @@ -2,35 +2,28 @@ const { config, browserStackCommon } = require('./protractor.common.conf'); const IS_CI = process.env.CIRCLECI || process.env.JENKINS_URL; config.baseUrl = 'http://localhost:8100/'; -config.specs = [ - './mobile/e2e/app.e2e-spec.ts', - './mobile/e2e/**/*.e2e-spec.ts' -]; +config.specs = ['./mobile/e2e/app.e2e-spec.ts', './mobile/e2e/**/*.e2e-spec.ts']; if (IS_CI) { - config.multiCapabilities.push( - { - ...browserStackCommon, - browserName: 'Chrome', - chromeOptions: { - mobileEmulation: { - deviceName: 'Pixel 2' - } - } - } - ); + config.multiCapabilities.push({ + ...browserStackCommon, + browserName: 'Chrome', + chromeOptions: { + mobileEmulation: { + deviceName: 'Pixel 2', + }, + }, + }); } else { - config.multiCapabilities.push( - { - browserName: 'chrome', - chromeOptions: { - mobileEmulation: { - deviceName: 'Pixel 2' - }, - args: ['--touch-events=enabled'] - } - } - ); + config.multiCapabilities.push({ + browserName: 'chrome', + chromeOptions: { + mobileEmulation: { + deviceName: 'Pixel 2', + }, + args: ['--touch-events=enabled'], + }, + }); } exports.config = config; diff --git a/packages/merit-build/README.md b/packages/merit-build/README.md index 9f7ee25487..db72d9b7ed 100644 --- a/packages/merit-build/README.md +++ b/packages/merit-build/README.md @@ -22,11 +22,12 @@ gulp.task('default', ['lint', 'test', 'browser', 'coverage']); ### Notes -* There's no default task to allow for each submodule to set up their own configuration -* If the module is node-only, avoid adding the browser tasks with: +- There's no default task to allow for each submodule to set up their own configuration +- If the module is node-only, avoid adding the browser tasks with: + ```javascript var meritTasks = require('merit-build'); -meritTasks('submodule', {skipBrowsers: true}); +meritTasks('submodule', { skipBrowsers: true }); ``` ## Contributing @@ -38,4 +39,3 @@ See [CONTRIBUTING.md](https://github.com/bitpay/merit) on the main merit repo fo Code released under [the MIT license](https://github.com/bitpay/merit/blob/master/LICENSE). Copyright 2015 BitPay, Inc. Bitcore is a trademark maintained by BitPay, Inc. - diff --git a/packages/merit-build/index.js b/packages/merit-build/index.js index f057acceb1..b4fca6f1b6 100644 --- a/packages/merit-build/index.js +++ b/packages/merit-build/index.js @@ -48,7 +48,6 @@ function ignoreerror() { } function startGulp(name, opts) { - opts = opts || {}; var browser = !opts.skipBrowser; var fullname = name ? 'bitcore-' + name : 'bitcore'; @@ -91,14 +90,14 @@ function startGulp(name, opts) { * testing */ var testmocha = function() { - return gulp.src(tests).pipe(mocha({ - reporter: 'spec' - })); + return gulp.src(tests).pipe( + mocha({ + reporter: 'spec', + }), + ); }; - var testkarma = shell.task([ - karmaPath + ' start ' + buildPath + 'karma.conf.js' - ]); + var testkarma = shell.task([karmaPath + ' start ' + buildPath + 'karma.conf.js']); gulp.task('test:node', testmocha); @@ -122,33 +121,35 @@ function startGulp(name, opts) { * file generation */ if (browser) { - var browserifyCommand; if (name !== 'lib') { - browserifyCommand = browserifyPath + ' --require ./index.js:' + fullname + ' --external bitcore-lib -o ' + fullname + '.js'; + browserifyCommand = + browserifyPath + ' --require ./index.js:' + fullname + ' --external bitcore-lib -o ' + fullname + '.js'; } else { browserifyCommand = browserifyPath + ' --require ./index.js:bitcore-lib -o bitcore-lib.js'; } - gulp.task('browser:uncompressed', shell.task([ - browserifyCommand - ])); + gulp.task('browser:uncompressed', shell.task([browserifyCommand])); gulp.task('browser:compressed', ['browser:uncompressed'], function() { - return gulp.src(fullname + '.js') - .pipe(uglify({ - mangle: true, - compress: true - })) + return gulp + .src(fullname + '.js') + .pipe( + uglify({ + mangle: true, + compress: true, + }), + ) .pipe(rename(fullname + '.min.js')) .pipe(gulp.dest('.')) .on('error', log.error); }); - gulp.task('browser:maketests', shell.task([ - 'find test/ -type f -name "*.js" | xargs ' + browserifyPath + ' -t brfs -o tests.js' - ])); + gulp.task( + 'browser:maketests', + shell.task(['find test/ -type f -name "*.js" | xargs ' + browserifyPath + ' -t brfs -o tests.js']), + ); gulp.task('browser', function(callback) { runsequence(['browser:compressed'], callback); @@ -160,7 +161,8 @@ function startGulp(name, opts) { */ gulp.task('lint', function() { - return gulp.src(alljs) + return gulp + .src(alljs) .pipe(jshint()) .pipe(jshint.reporter('default')); }); @@ -208,9 +210,7 @@ function startGulp(name, opts) { */ gulp.task('release:install', function() { - return shell.task([ - 'npm install', - ]); + return shell.task(['npm install']); }); var releaseFiles = ['./package.json']; @@ -219,40 +219,62 @@ function startGulp(name, opts) { } var bump_version = function(importance) { - return gulp.src(releaseFiles) - .pipe(bump({ - type: importance - })) + return gulp + .src(releaseFiles) + .pipe( + bump({ + type: importance, + }), + ) .pipe(gulp.dest('./')); }; var tempBranch = 'releases/' + new Date().getTime() + '-build'; gulp.task('release:checkout-releases', function(cb) { - git.branch(tempBranch, { - args: '' - }, function() { - git.checkout(tempBranch, { - args: '' - }, cb); - }); + git.branch( + tempBranch, + { + args: '', + }, + function() { + git.checkout( + tempBranch, + { + args: '', + }, + cb, + ); + }, + ); }); gulp.task('release:cleanup', function(cb) { - git.branch(tempBranch, { - args: '-D' - }, cb); + git.branch( + tempBranch, + { + args: '-D', + }, + cb, + ); }); gulp.task('release:checkout-master', function(cb) { - git.checkout('master', { - args: '' - }, cb); + git.checkout( + 'master', + { + args: '', + }, + cb, + ); }); - gulp.task('release:sign-built-files', shell.task([ - 'gpg --yes --out ' + fullname + '.js.sig --detach-sig ' + fullname + '.js', - 'gpg --yes --out ' + fullname + '.min.js.sig --detach-sig ' + fullname + '.min.js' - ])); + gulp.task( + 'release:sign-built-files', + shell.task([ + 'gpg --yes --out ' + fullname + '.js.sig --detach-sig ' + fullname + '.js', + 'gpg --yes --out ' + fullname + '.min.js.sig --detach-sig ' + fullname + '.min.js', + ]), + ); var buildFiles = ['./package.json']; var signatureFiles = []; @@ -269,45 +291,49 @@ function startGulp(name, opts) { } var addFiles = function() { var pjson = require('../../package.json'); - return gulp.src(buildFiles) - .pipe(git.add({ - args: '-f' - })); + return gulp.src(buildFiles).pipe( + git.add({ + args: '-f', + }), + ); }; var buildCommit = function() { var pjson = require('../../package.json'); - return gulp.src(buildFiles) - .pipe(git.commit('Build: ' + pjson.version, { - args: '' - })); + return gulp.src(buildFiles).pipe( + git.commit('Build: ' + pjson.version, { + args: '', + }), + ); }; gulp.task('release:add-signed-files', ['release:sign-built-files'], addFiles); gulp.task('release:add-built-files', addFiles); if (browser) { - gulp.task('release:build-commit', [ - 'release:add-signed-files' - ], buildCommit); + gulp.task('release:build-commit', ['release:add-signed-files'], buildCommit); } else { - gulp.task('release:build-commit', [ - 'release:add-built-files' - ], buildCommit); + gulp.task('release:build-commit', ['release:add-built-files'], buildCommit); } gulp.task('release:version-commit', function() { var pjson = require('../../package.json'); - return gulp.src(releaseFiles) - .pipe(git.commit('Bump package version to ' + pjson.version, { - args: '' - })); + return gulp.src(releaseFiles).pipe( + git.commit('Bump package version to ' + pjson.version, { + args: '', + }), + ); }); gulp.task('release:push', function(cb) { - git.push('bitpay', 'master', { - args: '' - }, cb); + git.push( + 'bitpay', + 'master', + { + args: '', + }, + cb, + ); }); gulp.task('release:push-tag', function(cb) { @@ -318,10 +344,7 @@ function startGulp(name, opts) { }); }); - gulp.task('release:publish', shell.task([ - 'npm publish' - ])); - + gulp.task('release:publish', shell.task(['npm publish'])); // requires https://hub.github.com/ var release = function(importance, cb) { @@ -353,7 +376,8 @@ function startGulp(name, opts) { 'release:push', // remove release branch 'release:cleanup', - cb); + cb, + ); }; ['patch', 'minor', 'major'].forEach(function(importance) { @@ -365,9 +389,6 @@ function startGulp(name, opts) { }); }); gulp.task('release', ['release:patch']); - - - } module.exports = startGulp; diff --git a/packages/merit-build/karma.conf.js b/packages/merit-build/karma.conf.js index 0b34df4bdf..3d952636dc 100644 --- a/packages/merit-build/karma.conf.js +++ b/packages/merit-build/karma.conf.js @@ -2,18 +2,13 @@ // karma.conf.js module.exports = function(config) { - config.set({ browsers: ['PhantomJS'], frameworks: ['mocha'], singleRun: true, files: [ - './../../tests.js' // project root + './../../tests.js', // project root ], - plugins: [ - 'karma-mocha', - 'karma-phantomjs-launcher' - ] + plugins: ['karma-mocha', 'karma-phantomjs-launcher'], }); - }; diff --git a/packages/merit-node/README.md b/packages/merit-node/README.md index abe36e5149..c42d042480 100644 --- a/packages/merit-node/README.md +++ b/packages/merit-node/README.md @@ -1,5 +1,4 @@ -Merit Node -============ +# Merit Node A Merit full node for building applications and services with Node.js. A node is extensible and can be configured to run additional services. At the minimum a node has an interface to Merit Core with additional indexing for more advanced address queries. Additional services can be enabled to make a node more useful such as exposing new APIs, running a block explorer and wallet service. @@ -9,9 +8,9 @@ Merit Node is a part of Merit Lightwallet Stack and is distributed as a source c ## Prerequisites -- GNU/Linux x86_32/x86_64, or OSX 64bit *(for bitcoind distributed binaries)* +- GNU/Linux x86_32/x86_64, or OSX 64bit _(for bitcoind distributed binaries)_ - Node.js v0.10, v0.12 or v4 -- ZeroMQ *(libzmq3-dev for Ubuntu/Debian or zeromq on OSX)* +- ZeroMQ _(libzmq3-dev for Ubuntu/Debian or zeromq on OSX)_ - ~200GB of disk storage - ~8GB of RAM diff --git a/packages/merit-node/benchmarks/index.js b/packages/merit-node/benchmarks/index.js index 490374bc98..ac2f3ff56e 100644 --- a/packages/merit-node/benchmarks/index.js +++ b/packages/merit-node/benchmarks/index.js @@ -16,23 +16,23 @@ var fixtureData = { '00000000fa7a4acea40e5d0591d64faf48fd862fa3561d111d967fc3a6a94177', '000000000017e9e0afc4bc55339f60ffffb9cbe883f7348a9fbc198a486d5488', '000000000019ddb889b534c5d85fca2c91a73feef6fd775cd228dea45353bae1', - '0000000000977ac3d9f5261efc88a3c2d25af92a91350750d00ad67744fa8d03' + '0000000000977ac3d9f5261efc88a3c2d25af92a91350750d00ad67744fa8d03', ], txHashes: [ '5523b432c1bd6c101bee704ad6c560fd09aefc483f8a4998df6741feaa74e6eb', 'ff48393e7731507c789cfa9cbfae045b10e023ce34ace699a63cdad88c8b43f8', '5d35c5eebf704877badd0a131b0a86588041997d40dbee8ccff21ca5b7e5e333', '88842f2cf9d8659c3434f6bc0c515e22d87f33e864e504d2d7117163a572a3aa', - ] + ], }; var meritd = require('../').services.Merit({ node: { datadir: process.env.HOME + '/.merit', network: { - name: 'testnet' - } - } + name: 'testnet', + }, + }, }); meritd.on('error', function(err) { @@ -47,123 +47,124 @@ meritd.start(function(err) { }); meritd.on('ready', function() { - console.log('Merit Core ready'); var client = new merit.Client({ host: 'localhost', port: 18445, user: 'merit', - pass: 'local321' + pass: 'local321', }); - async.series([ - function(next) { - - var c = 0; - var hashesLength = fixtureData.blockHashes.length; - var txLength = fixtureData.txHashes.length; + async.series( + [ + function(next) { + var c = 0; + var hashesLength = fixtureData.blockHashes.length; + var txLength = fixtureData.txHashes.length; - function meritdGetBlockNative(deffered) { - if (c >= hashesLength) { - c = 0; - } - var hash = fixtureData.blockHashes[c]; - meritd.getBlock(hash, function(err, block) { - if (err) { - throw err; + function meritdGetBlockNative(deffered) { + if (c >= hashesLength) { + c = 0; } - deffered.resolve(); - }); - c++; - } - - function meritdGetBlockJsonRpc(deffered) { - if (c >= hashesLength) { - c = 0; + var hash = fixtureData.blockHashes[c]; + meritd.getBlock(hash, function(err, block) { + if (err) { + throw err; + } + deffered.resolve(); + }); + c++; } - var hash = fixtureData.blockHashes[c]; - client.getBlock(hash, false, function(err, block) { - if (err) { - throw err; - } - deffered.resolve(); - }); - c++; - } - function meritGetTransactionNative(deffered) { - if (c >= txLength) { - c = 0; - } - var hash = fixtureData.txHashes[c]; - meritd.getTransaction(hash, true, function(err, tx) { - if (err) { - throw err; + function meritdGetBlockJsonRpc(deffered) { + if (c >= hashesLength) { + c = 0; } - deffered.resolve(); - }); - c++; - } + var hash = fixtureData.blockHashes[c]; + client.getBlock(hash, false, function(err, block) { + if (err) { + throw err; + } + deffered.resolve(); + }); + c++; + } - function meritGetTransactionJsonRpc(deffered) { - if (c >= txLength) { - c = 0; + function meritGetTransactionNative(deffered) { + if (c >= txLength) { + c = 0; + } + var hash = fixtureData.txHashes[c]; + meritd.getTransaction(hash, true, function(err, tx) { + if (err) { + throw err; + } + deffered.resolve(); + }); + c++; } - var hash = fixtureData.txHashes[c]; - client.getRawTransaction(hash, function(err, tx) { - if (err) { - throw err; + + function meritGetTransactionJsonRpc(deffered) { + if (c >= txLength) { + c = 0; } - deffered.resolve(); - }); - c++; - } + var hash = fixtureData.txHashes[c]; + client.getRawTransaction(hash, function(err, tx) { + if (err) { + throw err; + } + deffered.resolve(); + }); + c++; + } - var suite = new benchmark.Suite(); + var suite = new benchmark.Suite(); - suite.add('meritd getblock (native)', meritdGetBlockNative, { - defer: true, - maxTime: maxTime - }); + suite.add('meritd getblock (native)', meritdGetBlockNative, { + defer: true, + maxTime: maxTime, + }); - suite.add('meritd getblock (json rpc)', meritdGetBlockJsonRpc, { - defer: true, - maxTime: maxTime - }); + suite.add('meritd getblock (json rpc)', meritdGetBlockJsonRpc, { + defer: true, + maxTime: maxTime, + }); - suite.add('meritd gettransaction (native)', meritGetTransactionNative, { - defer: true, - maxTime: maxTime - }); + suite.add('meritd gettransaction (native)', meritGetTransactionNative, { + defer: true, + maxTime: maxTime, + }); - suite.add('meritd gettransaction (json rpc)', meritGetTransactionJsonRpc, { - defer: true, - maxTime: maxTime - }); + suite.add('meritd gettransaction (json rpc)', meritGetTransactionJsonRpc, { + defer: true, + maxTime: maxTime, + }); - suite - .on('cycle', function(event) { - console.log(String(event.target)); - }) - .on('complete', function() { - console.log('Fastest is ' + this.filter('fastest').map('name')); - console.log('----------------------------------------------------------------------'); - next(); - }) - .run(); - } - ], function(err) { - if (err) { - throw err; - } - console.log('Finished'); - meritd.stop(function(err) { + suite + .on('cycle', function(event) { + console.log(String(event.target)); + }) + .on('complete', function() { + console.log('Fastest is ' + this.filter('fastest').map('name')); + console.log('----------------------------------------------------------------------'); + next(); + }) + .run(); + }, + ], + function(err) { if (err) { - console.error('Fail to stop services: ' + err); - process.exit(1); + throw err; } - process.exit(0); - }); - }); + console.log('Finished'); + meritd.stop(function(err) { + if (err) { + console.error('Fail to stop services: ' + err); + process.exit(1); + } + process.exit(0); + }); + }, + ); }); diff --git a/packages/merit-node/docs/bus.md b/packages/merit-node/docs/bus.md index 6a14517a00..efd3223fc8 100644 --- a/packages/merit-node/docs/bus.md +++ b/packages/merit-node/docs/bus.md @@ -1,10 +1,10 @@ # Bus + The bus provides a way to subscribe to events from any of the services running. It's implemented abstract from transport specific implementation. The primary use of the bus in Merit Node is for subscribing to events via a web socket. ## Opening/Closing ```javascript - // a node is needed to be able to open a bus var node = new Node(configuration); @@ -18,7 +18,6 @@ bus.close(); ## Subscribing/Unsubscribing ```javascript - // subscribe to all transaction events bus.subscribe('meritd/rawtransaction'); diff --git a/packages/merit-node/docs/development.md b/packages/merit-node/docs/development.md index fb600fbfa5..c4252ec94e 100644 --- a/packages/merit-node/docs/development.md +++ b/packages/merit-node/docs/development.md @@ -25,20 +25,22 @@ git clone git@github.com:/bitcoin.git git fetch origin : git checkout ``` -**Note**: See bitcoin documentation for building bitcoin on your platform. +**Note**: See bitcoin documentation for building bitcoin on your platform. ## Install Development Dependencies For Ubuntu: + ```bash sudo apt-get install libzmq3-dev sudo apt-get install build-essential ``` -**Note**: Make sure that libzmq-dev is not installed, it should be removed when installing libzmq3-dev. +**Note**: Make sure that libzmq-dev is not installed, it should be removed when installing libzmq3-dev. For Mac OS X: + ```bash brew install zeromq ``` @@ -51,10 +53,11 @@ npm install cd ../merit-node npm install ``` + **Note**: If you get a message about not being able to download bitcoin distribution, you'll need to compile bitcoind from source, and setup your configuration to use that version. +We now will setup symlinks in `merit-node` _(repeat this for any other modules you're planning on developing)_: -We now will setup symlinks in `merit-node` *(repeat this for any other modules you're planning on developing)*: ```bash cd node_modules rm -rf meritcore-lib @@ -64,6 +67,7 @@ ln -s ~/bitcoind-rpc ``` And if you're compiling or developing bitcoin: + ```bash cd ../bin ln -sf ~/bitcoin/src/bitcoind @@ -72,11 +76,13 @@ ln -sf ~/bitcoin/src/bitcoind ## Run Tests If you do not already have mocha installed: + ```bash npm install mocha -g ``` To run all test suites: + ```bash cd merit-node npm run regtest @@ -84,11 +90,13 @@ npm run test ``` To run a specific unit test in watch mode: + ```bash mocha -w -R spec test/services/bitcoind.unit.js ``` To run a specific regtest: + ```bash mocha -R spec regtest/bitcoind.js ``` @@ -107,17 +115,12 @@ touch package.json ``` Edit `merit-node.json` with something similar to: + ```json { "network": "livenet", "port": 3001, - "services": [ - "bitcoind", - "web", - "insight-api", - "insight-ui", - "" - ], + "services": ["bitcoind", "web", "insight-api", "insight-ui", ""], "servicesConfig": { "bitcoind": { "spawn": { @@ -142,6 +145,7 @@ ln -s ~/insight-ui ``` Make sure that the `/bitcoin.conf` has the necessary settings, for example: + ``` server=1 whitelist=127.0.0.1 @@ -157,6 +161,7 @@ rpcpassword=local321 ``` From within the `devnode` directory with the configuration file, start the node: + ```bash ../merit-node/bin/merit-node start ``` diff --git a/packages/merit-node/docs/index.md b/packages/merit-node/docs/index.md index abe36e5149..c42d042480 100755 --- a/packages/merit-node/docs/index.md +++ b/packages/merit-node/docs/index.md @@ -1,5 +1,4 @@ -Merit Node -============ +# Merit Node A Merit full node for building applications and services with Node.js. A node is extensible and can be configured to run additional services. At the minimum a node has an interface to Merit Core with additional indexing for more advanced address queries. Additional services can be enabled to make a node more useful such as exposing new APIs, running a block explorer and wallet service. @@ -9,9 +8,9 @@ Merit Node is a part of Merit Lightwallet Stack and is distributed as a source c ## Prerequisites -- GNU/Linux x86_32/x86_64, or OSX 64bit *(for bitcoind distributed binaries)* +- GNU/Linux x86_32/x86_64, or OSX 64bit _(for bitcoind distributed binaries)_ - Node.js v0.10, v0.12 or v4 -- ZeroMQ *(libzmq3-dev for Ubuntu/Debian or zeromq on OSX)* +- ZeroMQ _(libzmq3-dev for Ubuntu/Debian or zeromq on OSX)_ - ~200GB of disk storage - ~8GB of RAM diff --git a/packages/merit-node/docs/node.md b/packages/merit-node/docs/node.md index f7eb4ccd82..4f5dafb35e 100644 --- a/packages/merit-node/docs/node.md +++ b/packages/merit-node/docs/node.md @@ -1,7 +1,9 @@ # Node + A node represents a collection of services that are loaded together. For more information about services, please see the [Services Documentation](services.md). ## API Documentation + - `start()` - Will start the node's services in the correct order based on the dependencies of a service. - `stop()` - Will stop the node's services. - `openBus()` - Will create a new event bus to subscribe to events. @@ -13,7 +15,6 @@ A node represents a collection of services that are loaded together. For more in ## Example Usage ```js - var index = require('merit-node'); var Merit = index.services.Merit; var Node = index.Node; @@ -25,9 +26,9 @@ var configuration = { { name: 'meritd', module: Merit, - config: {} - } - ] + config: {}, + }, + ], }; var node = new Node(configuration); diff --git a/packages/merit-node/docs/scaffold.md b/packages/merit-node/docs/scaffold.md index dc8157bc67..d5e00d0bb1 100644 --- a/packages/merit-node/docs/scaffold.md +++ b/packages/merit-node/docs/scaffold.md @@ -1,20 +1,27 @@ # Scaffold + A collection of functions for creating, managing, starting, stopping and interacting with a Merit node. ## Install + This function will add a service to a node by installing the necessary dependencies and modifying the `merit-node.json` configuration. ## Start + This function will load a configuration file `merit-node.json` and instantiate and start a node based on the configuration. ## Find Config + This function will recursively find a configuration `merit-node.json` file in parent directories and return the result. ## Default Config + This function will return a default configuration with the default services based on environment variables, and will default to using the standard `/home/user/.merit` data directory. ## Uninstall + This function will remove a service from a node by uninstalling the necessary dependencies and modifying the `merit-node.json` configuration. ## Call Method + This function will call an API method on a node via the JSON-RPC interface. diff --git a/packages/merit-node/docs/services/bitcoind.md b/packages/merit-node/docs/services/bitcoind.md index e743a6ff40..549e59c352 100644 --- a/packages/merit-node/docs/services/bitcoind.md +++ b/packages/merit-node/docs/services/bitcoind.md @@ -51,8 +51,8 @@ It's also possible to connect to separately managed `bitcoind` processes with ro **Note**: For detailed example configuration see [`regtest/cluster.js`](regtest/cluster.js) - ## API Documentation + Methods are available by directly interfacing with the service: ```js @@ -74,7 +74,7 @@ node.services.bitcoind.getBlockHashesByTimestamp(high, low, function(err, blockH // get the current tip of the chain node.services.bitcoind.getBestBlockHash(function(err, blockHash) { //... -}) +}); ``` **Getting Synchronization and Node Status** @@ -83,7 +83,7 @@ node.services.bitcoind.getBestBlockHash(function(err, blockHash) { // gives a boolean if the daemon is fully synced (not the initial block download) node.services.bitcoind.isSynced(function(err, synced) { //... -}) +}); // gives the current estimate of blockchain download as a percentage node.services.bitcoind.syncPercentage(function(err, percent) { @@ -199,9 +199,9 @@ The `unspentOutputs` will have the format: height: 150, micros: 1000000000, script: '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac', - confirmations: 3 - } -] + confirmations: 3, + }, +]; ``` **View Balances** @@ -219,14 +219,14 @@ This method will give history of an address limited by a range of block heights If "queryMempool" is set as true (it is true by default), it will show unconfirmed transactions from the bitcoin mempool. However, if you specify "start" and "end", "queryMempool" is ignored and is always false. -If "queryMempoolOnly" is set as true (it is false by default), it will show *only* unconfirmed transactions from mempool. +If "queryMempoolOnly" is set as true (it is false by default), it will show _only_ unconfirmed transactions from mempool. ```js var addresses = ['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW']; var options = { start: 345000, end: 344000, - queryMempool: true // since we presented range, queryMempool will be ignored + queryMempool: true, // since we presented range, queryMempool will be ignored }; node.services.bitcoind.getAddressHistory(addresses, options, function(err, history) { // see below @@ -258,7 +258,7 @@ The history format will be: ```js var address = 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'; var options = { - noTxList: false + noTxList: false, }; node.services.bitcoind.getAddressSummary(address, options, function(err, summary) { @@ -281,15 +281,17 @@ The `summary` will have the format (values are in micros): ] } ``` + **Notes**: -- `totalReceived` does not exclude change *(the amount of micros originating from the same address)* -- `unconfirmedBalance` is the delta that the unconfirmed transactions have on the total balance *(can be both positive and negative)* + +- `totalReceived` does not exclude change _(the amount of micros originating from the same address)_ +- `unconfirmedBalance` is the delta that the unconfirmed transactions have on the total balance _(can be both positive and negative)_ - `unconfirmedAppearances` is the total number of unconfirmed transactions - `appearances` is the total confirmed transactions -- `txids` Are sorted in block order with the most recent at the beginning. A maximum of 1000 *(default)* will be returned, the `from` and `to` options can be used to get further values. - +- `txids` Are sorted in block order with the most recent at the beginning. A maximum of 1000 _(default)_ will be returned, the `from` and `to` options can be used to get further values. ## Events + The Bitcoin Service exposes two events via the Bus, and there are a few events that can be directly registered: ```js @@ -307,6 +309,7 @@ node.services.bitcoind.on('block', function(blockHash) { ``` For details on instantiating a bus for a node, see the [Bus Documentation](../bus.md). + - Name: `bitcoind/rawtransaction` - Name: `bitcoind/hashblock` - Name: `bitcoind/addresstxid`, Arguments: [address, address...] diff --git a/packages/merit-node/docs/services/web.md b/packages/merit-node/docs/services/web.md index a067cbc711..187510b2ff 100644 --- a/packages/merit-node/docs/services/web.md +++ b/packages/merit-node/docs/services/web.md @@ -1,4 +1,5 @@ # Web Service + The web service creates an express app which can be used by services for setting up web routes for API's, static content, web applications, etc. This allows users to interact with various Merit Node services over one http or https port. In order for your service to add routes, it must implement the `setupRoutes()` and `getRoutePrefix()` methods. @@ -17,11 +18,12 @@ MyService.prototype.setupRoutes = function(app, express) { }; MyService.prototype.getRoutePrefix = function() { - return 'my-service' + return 'my-service'; }; ``` ## Configuring Web Service for HTTPS + You can run the web service over https by editing your Merit Node config, setting https to true and adding httpsOptions: ```json @@ -32,8 +34,6 @@ You can run the web service over https by editing your Merit Node config, settin "key": "path-to-private-key", "cert": "path-to-certificate" }, - "services": [ - "web" - ] + "services": ["web"] } ``` diff --git a/packages/merit-node/lib/bus.js b/packages/merit-node/lib/bus.js index d4f3bdd5f0..f2d1b4e902 100644 --- a/packages/merit-node/lib/bus.js +++ b/packages/merit-node/lib/bus.js @@ -27,7 +27,7 @@ util.inherits(Bus, events.EventEmitter); Bus.prototype.subscribe = function(name) { var events = []; - for(var i in this.node.services) { + for (var i in this.node.services) { var service = this.node.services[i]; events = events.concat(service.getPublishEvents()); } @@ -49,7 +49,7 @@ Bus.prototype.subscribe = function(name) { Bus.prototype.unsubscribe = function(name) { var events = []; - for(var i in this.node.services) { + for (var i in this.node.services) { var service = this.node.services[i]; events = events.concat(service.getPublishEvents()); } @@ -70,7 +70,7 @@ Bus.prototype.unsubscribe = function(name) { Bus.prototype.close = function() { var events = []; - for(var i in this.node.services) { + for (var i in this.node.services) { var service = this.node.services[i]; events = events.concat(service.getPublishEvents()); } diff --git a/packages/merit-node/lib/cli/daemon.js b/packages/merit-node/lib/cli/daemon.js index f0a33e9a47..604a7cf7c5 100644 --- a/packages/merit-node/lib/cli/daemon.js +++ b/packages/merit-node/lib/cli/daemon.js @@ -25,7 +25,7 @@ function main(servicesPath, additionalServices) { var configInfo = findConfig(program.config || process.cwd()); if (!configInfo) { configInfo = defaultConfig({ - additionalServices: additionalServices + additionalServices: additionalServices, }); } if (servicesPath) { diff --git a/packages/merit-node/lib/cli/main.js b/packages/merit-node/lib/cli/main.js index 41dd5b714d..cbbf6905cb 100644 --- a/packages/merit-node/lib/cli/main.js +++ b/packages/merit-node/lib/cli/main.js @@ -17,15 +17,14 @@ function main(servicesPath, additionalServices) { var findConfig = meritcorenode.scaffold.findConfig; var defaultConfig = meritcorenode.scaffold.defaultConfig; - program - .version(version); + program.version(version); program .command('create ') .description('Create a new node') .option('-d, --datadir ', 'Specify the Merit database directory') .option('-t, --testnet', 'Enable testnet as the network') - .action(function(dirname, cmd){ + .action(function(dirname, cmd) { if (cmd.datadir) { cmd.datadir = path.resolve(process.cwd(), cmd.datadir); } @@ -33,7 +32,7 @@ function main(servicesPath, additionalServices) { cwd: process.cwd(), dirname: dirname, datadir: cmd.datadir || './data', - isGlobal: false + isGlobal: false, }; if (cmd.testnet) { opts.network = 'testnet'; @@ -50,14 +49,14 @@ function main(servicesPath, additionalServices) { .command('start') .description('Start the current node') .option('-c, --config ', 'Specify the directory with Merit Node configuration') - .action(function(cmd){ + .action(function(cmd) { if (cmd.config) { cmd.config = path.resolve(process.cwd(), cmd.config); } var configInfo = findConfig(cmd.config || process.cwd()); if (!configInfo) { configInfo = defaultConfig({ - additionalServices: additionalServices + additionalServices: additionalServices, }); } if (servicesPath) { @@ -69,14 +68,14 @@ function main(servicesPath, additionalServices) { program .command('install ') .description('Install a service for the current node') - .action(function(services){ + .action(function(services) { var configInfo = findConfig(process.cwd()); if (!configInfo) { throw new Error('Could not find configuration, see `merit-node create --help`'); } var opts = { path: configInfo.path, - services: services + services: services, }; add(opts, function(err) { if (err) { @@ -84,7 +83,8 @@ function main(servicesPath, additionalServices) { } console.log('Successfully added services(s):', services.join(', ')); }); - }).on('--help', function() { + }) + .on('--help', function() { console.log(' Examples:'); console.log(); console.log(' $ merit-node add wallet-service'); @@ -95,14 +95,14 @@ function main(servicesPath, additionalServices) { program .command('uninstall ') .description('Uninstall a service for the current node') - .action(function(services){ + .action(function(services) { var configInfo = findConfig(process.cwd()); if (!configInfo) { throw new Error('Could not find configuration, see `merit-node create --help`'); } var opts = { path: configInfo.path, - services: services + services: services, }; remove(opts, function(err) { if (err) { @@ -110,7 +110,8 @@ function main(servicesPath, additionalServices) { } console.log('Successfully removed services(s):', services.join(', ')); }); - }).on('--help', function() { + }) + .on('--help', function() { console.log(' Examples:'); console.log(); console.log(' $ merit-node remove wallet-service'); @@ -130,7 +131,7 @@ function main(servicesPath, additionalServices) { var options = { protocol: 'http', host: 'localhost', - port: configInfo.config.port + port: configInfo.config.port, }; callMethod(options, method, params, function(err, data) { if (err) { @@ -145,7 +146,6 @@ function main(servicesPath, additionalServices) { if (process.argv.length === 2) { program.help(); } - } module.exports = main; diff --git a/packages/merit-node/lib/cli/merit-node.js b/packages/merit-node/lib/cli/merit-node.js index 43239504b2..c3e03ac5b4 100644 --- a/packages/merit-node/lib/cli/merit-node.js +++ b/packages/merit-node/lib/cli/merit-node.js @@ -3,36 +3,38 @@ var Liftoff = require('liftoff'); function main(parentServicesPath, additionalServices) { - var liftoff = new Liftoff({ name: 'merit-core', moduleName: 'merit-node', configName: 'merit-node', - processTitle: 'merit-core' - }).on('require', function (name) { - console.log('Loading:', name); - }).on('requireFail', function (name, err) { - console.log('Unable to load:', name, err); - }).on('respawn', function (flags, child) { - console.log('Detected node flags:', flags); - console.log('Respawned to PID:', child.pid); - }); - - liftoff.launch({ - cwd: process.cwd() - }, function(env){ - - var node; - if (env.configPath && env.modulePath) { - node = require(env.modulePath); - node.cli.main(); - } else { - node = require('../../'); - node.cli.main(parentServicesPath, additionalServices); - } - - }); - + processTitle: 'merit-core', + }) + .on('require', function(name) { + console.log('Loading:', name); + }) + .on('requireFail', function(name, err) { + console.log('Unable to load:', name, err); + }) + .on('respawn', function(flags, child) { + console.log('Detected node flags:', flags); + console.log('Respawned to PID:', child.pid); + }); + + liftoff.launch( + { + cwd: process.cwd(), + }, + function(env) { + var node; + if (env.configPath && env.modulePath) { + node = require(env.modulePath); + node.cli.main(); + } else { + node = require('../../'); + node.cli.main(parentServicesPath, additionalServices); + } + }, + ); } module.exports = main; diff --git a/packages/merit-node/lib/cli/merit-noded.js b/packages/merit-node/lib/cli/merit-noded.js index 5f0b9050a9..5cf7875fab 100644 --- a/packages/merit-node/lib/cli/merit-noded.js +++ b/packages/merit-node/lib/cli/merit-noded.js @@ -3,37 +3,39 @@ var Liftoff = require('liftoff'); function main(parentServicesPath, additionalServices) { - var liftoff = new Liftoff({ name: 'merit-noded', moduleName: 'merit-node', configName: 'merit-node', - processTitle: 'merit-noded' - }).on('require', function (name) { - console.log('Loading:', name); - }).on('requireFail', function (name, err) { - console.log('Unable to load:', name, err); - }).on('respawn', function (flags, child) { - console.log('Detected node flags:', flags); - console.log('Respawned to PID:', child.pid); - }); - - liftoff.launch({ - cwd: process.cwd() - }, function(env){ - - var node; - - if (env.configPath && env.modulePath) { - node = require(env.modulePath); - node.cli.daemon(); - } else { - node = require('../../'); - node.cli.daemon(parentServicesPath, additionalServices); - } - - }); - + processTitle: 'merit-noded', + }) + .on('require', function(name) { + console.log('Loading:', name); + }) + .on('requireFail', function(name, err) { + console.log('Unable to load:', name, err); + }) + .on('respawn', function(flags, child) { + console.log('Detected node flags:', flags); + console.log('Respawned to PID:', child.pid); + }); + + liftoff.launch( + { + cwd: process.cwd(), + }, + function(env) { + var node; + + if (env.configPath && env.modulePath) { + node = require(env.modulePath); + node.cli.daemon(); + } else { + node = require('../../'); + node.cli.daemon(parentServicesPath, additionalServices); + } + }, + ); } module.exports = main; diff --git a/packages/merit-node/lib/cli/meritd.js b/packages/merit-node/lib/cli/meritd.js index 48293e3978..a7757c896b 100644 --- a/packages/merit-node/lib/cli/meritd.js +++ b/packages/merit-node/lib/cli/meritd.js @@ -3,37 +3,39 @@ var Liftoff = require('liftoff'); function main(parentServicesPath, additionalServices) { - var liftoff = new Liftoff({ name: 'merit-cored', moduleName: 'merit-node', configName: 'merit-node', - processTitle: 'merit-cored' - }).on('require', function (name) { - console.log('Loading:', name); - }).on('requireFail', function (name, err) { - console.log('Unable to load:', name, err); - }).on('respawn', function (flags, child) { - console.log('Detected node flags:', flags); - console.log('Respawned to PID:', child.pid); - }); - - liftoff.launch({ - cwd: process.cwd() - }, function(env){ - - var node; - - if (env.configPath && env.modulePath) { - node = require(env.modulePath); - node.cli.daemon(); - } else { - node = require('../../'); - node.cli.daemon(parentServicesPath, additionalServices); - } - - }); - + processTitle: 'merit-cored', + }) + .on('require', function(name) { + console.log('Loading:', name); + }) + .on('requireFail', function(name, err) { + console.log('Unable to load:', name, err); + }) + .on('respawn', function(flags, child) { + console.log('Detected node flags:', flags); + console.log('Respawned to PID:', child.pid); + }); + + liftoff.launch( + { + cwd: process.cwd(), + }, + function(env) { + var node; + + if (env.configPath && env.modulePath) { + node = require(env.modulePath); + node.cli.daemon(); + } else { + node = require('../../'); + node.cli.daemon(parentServicesPath, additionalServices); + } + }, + ); } module.exports = main; diff --git a/packages/merit-node/lib/errors.js b/packages/merit-node/lib/errors.js index a455cfd011..e62dd62686 100644 --- a/packages/merit-node/lib/errors.js +++ b/packages/merit-node/lib/errors.js @@ -8,5 +8,5 @@ var RPCError = createError('RPCError', MeritcoreNodeError); module.exports = { Error: MeritcoreNodeError, - RPCError: RPCError + RPCError: RPCError, }; diff --git a/packages/merit-node/lib/node.js b/packages/merit-node/lib/node.js index 636f20b21e..ff73cbf690 100644 --- a/packages/merit-node/lib/node.js +++ b/packages/merit-node/lib/node.js @@ -38,7 +38,7 @@ var errors = require('./errors'); */ function Node(config) { /* jshint maxstatements: 20 */ - if(!(this instanceof Node)) { + if (!(this instanceof Node)) { return new Node(config); } this.configPath = config.path; @@ -93,7 +93,7 @@ Node.prototype.openBus = function(options) { if (!options) { options = {}; } - return new Bus({node: this, remoteAddress: options.remoteAddress}); + return new Bus({ node: this, remoteAddress: options.remoteAddress }); }; /** @@ -102,7 +102,7 @@ Node.prototype.openBus = function(options) { */ Node.prototype.getAllAPIMethods = function() { var methods = []; - for(var i in this.services) { + for (var i in this.services) { var mod = this.services[i]; if (mod.getAPIMethods) { methods = methods.concat(mod.getAPIMethods()); @@ -132,7 +132,6 @@ Node.prototype.getAllPublishEvents = function() { * @returns {Array} */ Node.prototype.getServiceOrder = function() { - var services = this._unloadedServices; // organize data for sorting @@ -148,8 +147,7 @@ Node.prototype.getServiceOrder = function() { var stack = []; function addToStack(names) { - for(var i = 0; i < names.length; i++) { - + for (var i = 0; i < names.length; i++) { var name = names[i]; var service = servicesByName[name]; $.checkState(service, 'Required dependency "' + name + '" not available.'); @@ -158,11 +156,10 @@ Node.prototype.getServiceOrder = function() { addToStack(service.module.dependencies); // add to the stack if it hasn't been added - if(!stackNames[name]) { + if (!stackNames[name]) { stack.push(service); stackNames[name] = true; } - } } @@ -233,9 +230,7 @@ Node.prototype._startService = function(serviceInfo, callback) { } callback(); - }); - }; Node.prototype._logTitle = function() { @@ -245,7 +240,6 @@ Node.prototype._logTitle = function() { } }; - /** * Will start all running services in the order based on the dependency chain. * @param {Function} callback - Called when all services are started @@ -267,7 +261,7 @@ Node.prototype.start = function(callback) { } self.emit('ready'); callback(); - } + }, ); }; @@ -303,7 +297,7 @@ Node.prototype.stop = function(callback) { setImmediate(next); } }, - callback + callback, ); }; diff --git a/packages/merit-node/lib/scaffold/add.js b/packages/merit-node/lib/scaffold/add.js index fd8f7f533f..8363214401 100644 --- a/packages/merit-node/lib/scaffold/add.js +++ b/packages/merit-node/lib/scaffold/add.js @@ -21,10 +21,7 @@ function addConfig(configFilePath, service, done) { return done(err); } var config = JSON.parse(data); - $.checkState( - Array.isArray(config.services), - 'Configuration file is expected to have a services array.' - ); + $.checkState(Array.isArray(config.services), 'Configuration file is expected to have a services array.'); config.services.push(service); config.services = _.uniq(config.services); config.services.sort(function(a, b) { @@ -41,7 +38,7 @@ function addConfig(configFilePath, service, done) { */ function addService(configDir, service, done) { $.checkState(utils.isAbsolutePath(configDir), 'An absolute path is expected'); - var npm = spawn('npm', ['install', service, '--save'], {cwd: configDir}); + var npm = spawn('npm', ['install', service, '--save'], { cwd: configDir }); npm.stdout.on('data', function(data) { process.stdout.write(data); @@ -69,10 +66,7 @@ function addService(configDir, service, done) { function add(options, done) { $.checkArgument(_.isObject(options)); $.checkArgument(_.isFunction(done)); - $.checkArgument( - _.isString(options.path) && utils.isAbsolutePath(options.path), - 'An absolute path is expected' - ); + $.checkArgument(_.isString(options.path) && utils.isAbsolutePath(options.path), 'An absolute path is expected'); $.checkArgument(Array.isArray(options.services)); var configPath = options.path; @@ -82,9 +76,7 @@ function add(options, done) { var packagePath = path.resolve(configPath, 'package.json'); if (!fs.existsSync(meritcoreConfigPath) || !fs.existsSync(packagePath)) { - return done( - new Error('Directory does not have a merit-node.json and/or package.json file.') - ); + return done(new Error('Directory does not have a merit-node.json and/or package.json file.')); } var oldPackage = JSON.parse(fs.readFileSync(packagePath)); @@ -102,7 +94,7 @@ function add(options, done) { var updatedPackage = JSON.parse(fs.readFileSync(packagePath)); var newDependencies = _.difference( Object.keys(updatedPackage.dependencies), - Object.keys(oldPackage.dependencies) + Object.keys(oldPackage.dependencies), ); $.checkState(newDependencies.length === 1); oldPackage = updatedPackage; @@ -111,7 +103,8 @@ function add(options, done) { // add service to merit-node.json addConfig(meritcoreConfigPath, serviceName, next); }); - }, done + }, + done, ); } diff --git a/packages/merit-node/lib/scaffold/call-method.js b/packages/merit-node/lib/scaffold/call-method.js index b5ca9ad660..436dbd1be7 100644 --- a/packages/merit-node/lib/scaffold/call-method.js +++ b/packages/merit-node/lib/scaffold/call-method.js @@ -10,34 +10,35 @@ var socketClient = require('socket.io-client'); * @param {Function} done - The callback function */ function callMethod(options, method, params, done) { - var host = options.host; var protocol = options.protocol; var port = options.port; var url = protocol + '://' + host + ':' + port; var socketOptions = { reconnection: false, - connect_timeout: 5000 + connect_timeout: 5000, }; var socket = socketClient(url, socketOptions); - socket.on('connect', function(){ - socket.send({ - method: method, - params: params, - }, function(response) { - if (response.error) { - return done(new Error(response.error.message)); - } - socket.close(); - done(null, response.result); - }); + socket.on('connect', function() { + socket.send( + { + method: method, + params: params, + }, + function(response) { + if (response.error) { + return done(new Error(response.error.message)); + } + socket.close(); + done(null, response.result); + }, + ); }); socket.on('connect_error', done); return socket; - } module.exports = callMethod; diff --git a/packages/merit-node/lib/scaffold/create.js b/packages/merit-node/lib/scaffold/create.js index 74f293b1a4..560d30adfe 100644 --- a/packages/merit-node/lib/scaffold/create.js +++ b/packages/merit-node/lib/scaffold/create.js @@ -20,8 +20,8 @@ var BASE_PACKAGE = { readme: 'README.md', dependencies: { 'meritcore-lib': '^' + meritcore.version, - 'merit-node': version - } + 'merit-node': version, + }, }; /** @@ -65,11 +65,10 @@ function createConfigDirectory(options, configDir, isGlobal, done) { if (!isGlobal) { fs.writeFileSync(configDir + '/package.json', packageJSON); } - } catch(e) { + } catch (e) { done(e); } done(); - }); } @@ -101,54 +100,55 @@ function create(options, done) { var absConfigDir = path.resolve(cwd, dirname); var absDataDir = path.resolve(absConfigDir, datadir); - async.series([ - function(next) { - // Setup the the merit-node directory and configuration - if (!fs.existsSync(absConfigDir)) { - var createOptions = { - network: options.network, - datadir: datadir - }; - createConfigDirectory(createOptions, absConfigDir, isGlobal, next); - } else { - next(new Error('Directory "' + absConfigDir+ '" already exists.')); - } - }, - function(next) { - // Setup the Merit directory and configuration - if (!fs.existsSync(absDataDir)) { - createMeritDirectory(absDataDir, next); - } else { - next(); - } - }, - function(next) { - // Install all of the necessary dependencies - if (!isGlobal) { - var npm = spawn('npm', ['install'], {cwd: absConfigDir}); - - npm.stdout.on('data', function (data) { - process.stdout.write(data); - }); - - npm.stderr.on('data', function (data) { - process.stderr.write(data); - }); - - npm.on('close', function (code) { - if (code !== 0) { - return next(new Error('There was an error installing dependencies.')); - } else { - return next(); - } - }); - - } else { - next(); - } - } - ], done); - + async.series( + [ + function(next) { + // Setup the the merit-node directory and configuration + if (!fs.existsSync(absConfigDir)) { + var createOptions = { + network: options.network, + datadir: datadir, + }; + createConfigDirectory(createOptions, absConfigDir, isGlobal, next); + } else { + next(new Error('Directory "' + absConfigDir + '" already exists.')); + } + }, + function(next) { + // Setup the Merit directory and configuration + if (!fs.existsSync(absDataDir)) { + createMeritDirectory(absDataDir, next); + } else { + next(); + } + }, + function(next) { + // Install all of the necessary dependencies + if (!isGlobal) { + var npm = spawn('npm', ['install'], { cwd: absConfigDir }); + + npm.stdout.on('data', function(data) { + process.stdout.write(data); + }); + + npm.stderr.on('data', function(data) { + process.stderr.write(data); + }); + + npm.on('close', function(code) { + if (code !== 0) { + return next(new Error('There was an error installing dependencies.')); + } else { + return next(); + } + }); + } else { + next(); + } + }, + ], + done, + ); } module.exports = create; diff --git a/packages/merit-node/lib/scaffold/default-base-config.js b/packages/merit-node/lib/scaffold/default-base-config.js index 2a7af12557..e6a2ce7745 100644 --- a/packages/merit-node/lib/scaffold/default-base-config.js +++ b/packages/merit-node/lib/scaffold/default-base-config.js @@ -23,11 +23,11 @@ function getDefaultBaseConfig(options) { meritd: { spawn: { datadir: options.datadir || path.resolve(process.env.HOME, '.merit'), - exec: path.resolve(__dirname, '../../bin/meritd') - } - } - } - } + exec: path.resolve(__dirname, '../../bin/meritd'), + }, + }, + }, + }, }; } diff --git a/packages/merit-node/lib/scaffold/default-config.js b/packages/merit-node/lib/scaffold/default-config.js index 9ce9d50d04..3cbb5ccbd9 100644 --- a/packages/merit-node/lib/scaffold/default-config.js +++ b/packages/merit-node/lib/scaffold/default-config.js @@ -38,10 +38,10 @@ function getDefaultConfig(options) { meritd: { spawn: { datadir: path.resolve(defaultPath, './data'), - exec: path.resolve(__dirname, '../../bin/meritd') - } - } - } + exec: path.resolve(__dirname, '../../bin/meritd'), + }, + }, + }, }; fs.writeFileSync(defaultConfigFile, JSON.stringify(defaultConfig, null, 2)); } @@ -56,9 +56,8 @@ function getDefaultConfig(options) { return { path: defaultPath, - config: config + config: config, }; - } module.exports = getDefaultConfig; diff --git a/packages/merit-node/lib/scaffold/find-config.js b/packages/merit-node/lib/scaffold/find-config.js index 57a01a2ae9..c59369239a 100644 --- a/packages/merit-node/lib/scaffold/find-config.js +++ b/packages/merit-node/lib/scaffold/find-config.js @@ -24,7 +24,7 @@ function findConfig(cwd) { console.log(directory); return { path: directory, - config: require(path.resolve(directory, 'merit-node.json')) + config: require(path.resolve(directory, 'merit-node.json')), }; } diff --git a/packages/merit-node/lib/scaffold/remove.js b/packages/merit-node/lib/scaffold/remove.js index 0b7c101e35..32efec5139 100644 --- a/packages/merit-node/lib/scaffold/remove.js +++ b/packages/merit-node/lib/scaffold/remove.js @@ -22,10 +22,7 @@ function removeConfig(configFilePath, service, done) { return done(err); } var config = JSON.parse(data); - $.checkState( - Array.isArray(config.services), - 'Configuration file is expected to have a services array.' - ); + $.checkState(Array.isArray(config.services), 'Configuration file is expected to have a services array.'); // remove the service from the configuration for (var i = 0; i < config.services.length; i++) { if (config.services[i] === service) { @@ -50,7 +47,7 @@ function uninstallService(configDir, service, done) { $.checkArgument(utils.isAbsolutePath(configDir), 'An absolute path is expected'); $.checkArgument(_.isString(service), 'A string is expected for the service argument'); - var child = spawn('npm', ['uninstall', service, '--save'], {cwd: configDir}); + var child = spawn('npm', ['uninstall', service, '--save'], { cwd: configDir }); child.stdout.on('data', function(data) { process.stdout.write(data); @@ -91,10 +88,7 @@ function removeService(configDir, service, done) { function remove(options, done) { $.checkArgument(_.isObject(options)); $.checkArgument(_.isFunction(done)); - $.checkArgument( - _.isString(options.path) && utils.isAbsolutePath(options.path), - 'An absolute path is expected' - ); + $.checkArgument(_.isString(options.path) && utils.isAbsolutePath(options.path), 'An absolute path is expected'); $.checkArgument(Array.isArray(options.services)); var configPath = options.path; @@ -104,9 +98,7 @@ function remove(options, done) { var packagePath = path.resolve(configPath, 'package.json'); if (!fs.existsSync(meritcoreConfigPath) || !fs.existsSync(packagePath)) { - return done( - new Error('Directory does not have a merit-node.json and/or package.json file.') - ); + return done(new Error('Directory does not have a merit-node.json and/or package.json file.')); } async.eachSeries( @@ -120,7 +112,8 @@ function remove(options, done) { // remove service to merit-node.json removeConfig(meritcoreConfigPath, service, next); }); - }, done + }, + done, ); } diff --git a/packages/merit-node/lib/scaffold/start.js b/packages/merit-node/lib/scaffold/start.js index b71a2482aa..55798a925d 100644 --- a/packages/merit-node/lib/scaffold/start.js +++ b/packages/merit-node/lib/scaffold/start.js @@ -16,15 +16,16 @@ log.debug = function() {}; */ function checkConfigVersion2(fullConfig) { var datadirUndefined = _.isUndefined(fullConfig.datadir); - var addressDefined = (fullConfig.services.indexOf('address') >= 0); - var dbDefined = (fullConfig.services.indexOf('db') >= 0); + var addressDefined = fullConfig.services.indexOf('address') >= 0; + var dbDefined = fullConfig.services.indexOf('db') >= 0; if (!datadirUndefined || addressDefined || dbDefined) { - - console.warn('\nConfiguration file is not compatible with this version. \n' + - 'A reindex for meritd is necessary for this upgrade with the "reindex=1" merit.conf option. \n' + - 'There are changes necessary in both merit.conf and merit-node.json. \n\n' + - 'To upgrade please see the details below and documentation at: \n'); + console.warn( + '\nConfiguration file is not compatible with this version. \n' + + 'A reindex for meritd is necessary for this upgrade with the "reindex=1" merit.conf option. \n' + + 'There are changes necessary in both merit.conf and merit-node.json. \n\n' + + 'To upgrade please see the details below and documentation at: \n', + ); if (!datadirUndefined) { console.warn('Please remove "datadir" and add it to the config at ' + fullConfig.path + ' with:'); @@ -33,10 +34,10 @@ function checkConfigVersion2(fullConfig) { meritd: { spawn: { datadir: fullConfig.datadir, - exec: path.resolve(__dirname, '../../bin/meritd') - } - } - } + exec: path.resolve(__dirname, '../../bin/meritd'), + }, + }, + }, }; console.warn(JSON.stringify(missingConfig, null, 2) + '\n'); } @@ -97,7 +98,7 @@ function start(options) { }); node.start(function(err) { - if(err) { + if (err) { log.error('Failed to start services'); if (err.stack) { log.error(err.stack); @@ -107,7 +108,6 @@ function start(options) { }); return node; - } /** @@ -116,12 +116,14 @@ function start(options) { */ function checkService(service) { // check that the service supports expected methods - if (!service.module.prototype || - !service.module.dependencies || - !service.module.prototype.start || - !service.module.prototype.stop) { + if ( + !service.module.prototype || + !service.module.dependencies || + !service.module.prototype.start || + !service.module.prototype.stop + ) { throw new Error( - 'Could not load service "' + service.name + '" as it does not support necessary methods and properties.' + 'Could not load service "' + service.name + '" as it does not support necessary methods and properties.', ); } } @@ -136,8 +138,7 @@ function loadModule(req, service) { try { // first try in the built-in merit-node services directory service.module = req(path.resolve(__dirname, '../services/' + service.name)); - } catch(e) { - + } catch (e) { // check if the package.json specifies a specific file to use var servicePackage = req(service.name + '/package.json'); var serviceModule = service.name; @@ -165,7 +166,6 @@ function loadModule(req, service) { * @returns {Array} */ function setupServices(req, servicesPath, config) { - module.paths.push(path.resolve(servicesPath, './packages')); var services = []; @@ -193,7 +193,7 @@ function setupServices(req, servicesPath, config) { */ function cleanShutdown(_process, node) { node.stop(function(err) { - if(err) { + if (err) { log.error('Failed to stop services: ' + err); return _process.exit(1); } @@ -210,15 +210,15 @@ function cleanShutdown(_process, node) { * @param {Object} _process - The Node.js process * @param {Node} node * @param {Error} error -*/ + */ function exitHandler(options, _process, node, err) { if (err) { log.error('uncaught exception:', err); - if(err.stack) { + if (err.stack) { log.error(err.stack); } node.stop(function(err) { - if(err) { + if (err) { log.error('Failed to stop services: ' + err); } _process.exit(-1); @@ -240,10 +240,10 @@ function exitHandler(options, _process, node, err) { */ function registerExitHandlers(_process, node) { //catches uncaught exceptions - _process.on('uncaughtException', exitHandler.bind(null, {exit:true}, _process, node)); + _process.on('uncaughtException', exitHandler.bind(null, { exit: true }, _process, node)); //catches ctrl+c event - _process.on('SIGINT', exitHandler.bind(null, {sigint:true}, _process, node)); + _process.on('SIGINT', exitHandler.bind(null, { sigint: true }, _process, node)); } module.exports = start; diff --git a/packages/merit-node/lib/services/meritd.js b/packages/merit-node/lib/services/meritd.js index 53aa73bbd3..2a5a326545 100644 --- a/packages/merit-node/lib/services/meritd.js +++ b/packages/merit-node/lib/services/meritd.js @@ -11,7 +11,7 @@ var async = require('async'); var LRU = require('lru-cache'); var MeritRPC = require('meritd-rpc'); var $ = meritcore.util.preconditions; -var _ = meritcore.deps._; +var _ = meritcore.deps._; var Transaction = meritcore.Transaction; var Referral = meritcore.Referral; @@ -93,7 +93,7 @@ Merit.DEFAULT_CONFIG_SETTINGS = { rpcallowip: '127.0.0.1', rpcuser: 'merit', rpcpassword: 'local321', - uacomment: 'meritcore' + uacomment: 'meritcore', }; Merit.prototype._initDefaults = function(options) { @@ -134,8 +134,6 @@ Merit.prototype._initCaches = function() { this.anvCache = LRU(50000); this.rewardsCache = LRU(50000); - - // caches valid indefinitely this.transactionCache = LRU(100000); this.rawTransactionCache = LRU(50000); @@ -161,7 +159,7 @@ Merit.prototype._initClients = function() { return client; }, enumerable: true, - configurable: false + configurable: false, }); }; @@ -196,8 +194,8 @@ Merit.prototype.getAPIMethods = function() { // Merit Specific RPC ['getInputForEasySend', this, this.getInputForEasySend, 1], - ['getanv', this, this.getANV, 1], - ['getrewards', this, this.getRewards, 1], + ['getanv', this, this.getANV, 1], + ['getrewards', this, this.getRewards, 1], ['sendReferral', this, this.sendReferral, 1], ['getReferral', this, this.getReferral, 1], ['getAddressReferrals', this, this.getAddressReferrals, 1], @@ -221,34 +219,32 @@ Merit.prototype.getPublishEvents = function() { name: 'meritd/rawtransaction', scope: this, subscribe: this.subscribe.bind(this, 'rawtransaction'), - unsubscribe: this.unsubscribe.bind(this, 'rawtransaction') + unsubscribe: this.unsubscribe.bind(this, 'rawtransaction'), }, { name: 'meritd/hashblock', scope: this, subscribe: this.subscribe.bind(this, 'hashblock'), - unsubscribe: this.unsubscribe.bind(this, 'hashblock') + unsubscribe: this.unsubscribe.bind(this, 'hashblock'), }, { name: 'meritd/addresstxid', scope: this, subscribe: this.subscribeAddress.bind(this), - unsubscribe: this.unsubscribeAddress.bind(this) + unsubscribe: this.unsubscribeAddress.bind(this), }, { name: 'meritd/rawreferraltx', - - scope: this, subscribe: this.subscribe.bind(this, 'rawreferraltx'), - unsubscribe: this.unsubscribe.bind(this, 'rawreferraltx') + unsubscribe: this.unsubscribe.bind(this, 'rawreferraltx'), }, { name: 'meritd/hashreferraltx', scope: this, subscribe: this.subscribe.bind(this, 'hashreferraltx'), - unsubscribe: this.unsubscribe.bind(this, 'hashreferraltx') + unsubscribe: this.unsubscribe.bind(this, 'hashreferraltx'), }, ]; }; @@ -270,7 +266,7 @@ Merit.prototype.subscribeAddress = function(emitter, addresses) { var self = this; function addAddress(addressStr) { - if(self.subscriptions.address[addressStr]) { + if (self.subscriptions.address[addressStr]) { var emitters = self.subscriptions.address[addressStr]; var index = emitters.indexOf(emitter); if (index === -1) { @@ -281,7 +277,7 @@ Merit.prototype.subscribeAddress = function(emitter, addresses) { } } - for(var i = 0; i < addresses.length; i++) { + for (var i = 0; i < addresses.length; i++) { if (meritcore.Address.isValid(addresses[i], this.node.network)) { addAddress(addresses[i]); } @@ -292,14 +288,14 @@ Merit.prototype.subscribeAddress = function(emitter, addresses) { Merit.prototype.unsubscribeAddress = function(emitter, addresses) { var self = this; - if(!addresses) { + if (!addresses) { return this.unsubscribeAddressAll(emitter); } function removeAddress(addressStr) { var emitters = self.subscriptions.address[addressStr]; var index = emitters.indexOf(emitter); - if(index > -1) { + if (index > -1) { emitters.splice(index, 1); if (emitters.length === 0) { delete self.subscriptions.address[addressStr]; @@ -307,8 +303,8 @@ Merit.prototype.unsubscribeAddress = function(emitter, addresses) { } } - for(var i = 0; i < addresses.length; i++) { - if(this.subscriptions.address[addresses[i]]) { + for (var i = 0; i < addresses.length; i++) { + if (this.subscriptions.address[addresses[i]]) { removeAddress(addresses[i]); } } @@ -322,10 +318,10 @@ Merit.prototype.unsubscribeAddress = function(emitter, addresses) { * @param {EventEmitter} emitter - An instance of an event emitter */ Merit.prototype.unsubscribeAddressAll = function(emitter) { - for(var hashHex in this.subscriptions.address) { + for (var hashHex in this.subscriptions.address) { var emitters = this.subscriptions.address[hashHex]; var index = emitters.indexOf(emitter); - if(index > -1) { + if (index > -1) { emitters.splice(index, 1); } if (emitters.length === 0) { @@ -338,7 +334,7 @@ Merit.prototype.unsubscribeAddressAll = function(emitter) { Merit.prototype._getDefaultConfig = function() { var config = ''; var defaults = Merit.DEFAULT_CONFIG_SETTINGS; - for(var key in defaults) { + for (var key in defaults) { config += key + '=' + defaults[key] + '\n'; } return config; @@ -348,7 +344,7 @@ Merit.prototype._parseMeritConf = function(configPath) { var options = {}; var file = fs.readFileSync(configPath); var unparsed = file.toString().split('\n'); - for(var i = 0; i < unparsed.length; i++) { + for (var i = 0; i < unparsed.length; i++) { var line = unparsed[i]; if (!line.match(/^\#/) && line.match(/\=/)) { var option = line.split('='); @@ -412,7 +408,6 @@ Merit.prototype._loadSpawnConfiguration = function(node) { var spawnConfig = this.spawn.config; this._checkConfigIndexes(spawnConfig, node); - }; Merit.prototype._checkConfigIndexes = function(spawnConfig, node) { @@ -420,58 +415,60 @@ Merit.prototype._checkConfigIndexes = function(spawnConfig, node) { spawnConfig.txindex && spawnConfig.txindex === 1, '"txindex" option is required in order to use transaction query features of merit-node. ' + 'Please add "txindex=1" to your configuration and reindex an existing database if ' + - 'necessary with reindex=1' + 'necessary with reindex=1', ); $.checkState( spawnConfig.addressindex && spawnConfig.addressindex === 1, '"addressindex" option is required in order to use address query features of merit-node. ' + 'Please add "addressindex=1" to your configuration and reindex an existing database if ' + - 'necessary with reindex=1' + 'necessary with reindex=1', ); $.checkState( spawnConfig.spentindex && spawnConfig.spentindex === 1, '"spentindex" option is required in order to use spent info query features of merit-node. ' + 'Please add "spentindex=1" to your configuration and reindex an existing database if ' + - 'necessary with reindex=1' + 'necessary with reindex=1', ); $.checkState( spawnConfig.server && spawnConfig.server === 1, '"server" option is required to communicate to meritd from meritcore. ' + - 'Please add "server=1" to your configuration and restart' + 'Please add "server=1" to your configuration and restart', ); $.checkState( spawnConfig.zmqpubrawtx, '"zmqpubrawtx" option is required to get event updates from meritd. ' + - 'Please add "zmqpubrawtx=tcp://127.0.0.1:" to your configuration and restart' + 'Please add "zmqpubrawtx=tcp://127.0.0.1:" to your configuration and restart', ); $.checkState( spawnConfig.zmqpubhashblock, '"zmqpubhashblock" option is required to get event updates from meritd. ' + - 'Please add "zmqpubhashblock=tcp://127.0.0.1:" to your configuration and restart' + 'Please add "zmqpubhashblock=tcp://127.0.0.1:" to your configuration and restart', ); $.checkState( spawnConfig.zmqpubrawreferraltx, '"zmqpubrawreferraltx" option is required to get event updates from meritd. ' + - 'Please add "zmqpubrawreferraltx=tcp://127.0.0.1:" to your configuration and restart' + 'Please add "zmqpubrawreferraltx=tcp://127.0.0.1:" to your configuration and restart', ); $.checkState( - (spawnConfig.zmqpubhashblock === spawnConfig.zmqpubrawtx && - spawnConfig.zmqpubrawtx === spawnConfig.zmqpubrawreferraltx), - '"zmqpubrawtx", "zmqpubhashblock", "zmqpubrawreferraltx" are expected to the same host and port in merit.conf' + spawnConfig.zmqpubhashblock === spawnConfig.zmqpubrawtx && + spawnConfig.zmqpubrawtx === spawnConfig.zmqpubrawreferraltx, + '"zmqpubrawtx", "zmqpubhashblock", "zmqpubrawreferraltx" are expected to the same host and port in merit.conf', ); if (spawnConfig.reindex && spawnConfig.reindex === 1) { - log.warn('Reindex option is currently enabled. This means that meritd is undergoing a reindex. ' + - 'The reindex flag will start the index from beginning every time the node is started, so it ' + - 'should be removed after the reindex has been initiated. Once the reindex is complete, the rest ' + - 'of merit-node services will start.'); + log.warn( + 'Reindex option is currently enabled. This means that meritd is undergoing a reindex. ' + + 'The reindex flag will start the index from beginning every time the node is started, so it ' + + 'should be removed after the reindex has been initiated. Once the reindex is complete, the rest ' + + 'of merit-node services will start.', + ); node._reindex = true; } }; @@ -496,7 +493,7 @@ Merit.prototype._tryAllClients = function(func, callback) { nodesIndex = (nodesIndex + 1) % self.nodes.length; func(client, done); }; - async.retry({times: this.nodes.length, interval: this.tryAllInterval || 1000}, retry, callback); + async.retry({ times: this.nodes.length, interval: this.tryAllInterval || 1000 }, retry, callback); }; Merit.prototype._wrapRPCError = function(errObj) { @@ -535,7 +532,6 @@ Merit.prototype._initChain = function(callback) { callback(); }); }); - }); }); }; @@ -588,7 +584,6 @@ Merit.prototype._zmqBlockHandler = function(node, message) { this.subscriptions.hashblock[i].emit('meritd/hashblock', message.toString('hex')); } } - }; Merit.prototype._rapidProtectedUpdateTip = function(node, message) { @@ -607,8 +602,7 @@ Merit.prototype._rapidProtectedUpdateTip = function(node, message) { }; Merit.prototype._updateTip = function(node, message) { - - console.log("\nUPDATE TIP\n", message); + console.log('\nUPDATE TIP\n', message); var self = this; @@ -630,7 +624,7 @@ Merit.prototype._updateTip = function(node, message) { } }); - if(!self.node.stopping) { + if (!self.node.stopping) { self.syncPercentage(function(err, percentage) { if (err) { self.emit('error', err); @@ -675,12 +669,12 @@ Merit.prototype._notifyAddressTxidSubscribers = function(txid, transaction) { var addresses = this._getAddressesFromTransaction(transaction); for (var i = 0; i < addresses.length; i++) { var address = addresses[i]; - if(this.subscriptions.address[address]) { + if (this.subscriptions.address[address]) { var emitters = this.subscriptions.address[address]; - for(var j = 0; j < emitters.length; j++) { + for (var j = 0; j < emitters.length; j++) { emitters[j].emit('meritd/addresstxid', { address: address, - txid: txid + txid: txid, }); } } @@ -704,7 +698,6 @@ Merit.prototype._zmqTransactionHandler = function(node, message) { tx.fromString(message); var txid = meritcore.util.buffer.reverse(hash).toString('hex'); self._notifyAddressTxidSubscribers(txid, tx); - } }; @@ -791,7 +784,6 @@ Merit.prototype._checkSyncedAndSubscribeZmqEvents = function(node) { }, node._tipUpdateInterval || Merit.DEFAULT_TIP_UPDATE_INTERVAL); } }); - }; Merit.prototype._subscribeZmqEvents = function(node) { @@ -804,23 +796,23 @@ Merit.prototype._subscribeZmqEvents = function(node) { node.zmqSubSocket.on('message', function(topic, message) { const topicString = topic.toString('utf8'); log.info(`message received in topic: ${topicString}`); - switch(topicString) { - case 'rawtx': - self._zmqTransactionHandler(node, message); - break; - case 'hashblock': - self._zmqBlockHandler(node, message); - break; - case 'rawreferraltx': - self._zmqRawReferralsHandler(node, message); - break; - case 'hashreferraltx': - self._zmqHashReferralsHandler(node, message); - break; - default: - log.error('Error in ZMQ message parsing: cannot determine topic.') - break; - }; + switch (topicString) { + case 'rawtx': + self._zmqTransactionHandler(node, message); + break; + case 'hashblock': + self._zmqBlockHandler(node, message); + break; + case 'rawreferraltx': + self._zmqRawReferralsHandler(node, message); + break; + case 'hashreferraltx': + self._zmqHashReferralsHandler(node, message); + break; + default: + log.error('Error in ZMQ message parsing: cannot determine topic.'); + break; + } }); }; @@ -920,11 +912,11 @@ Merit.prototype._stopSpawnedMerit = function(callback) { try { log.warn('Stopping existing spawned Merit process with pid: ' + pid); self._process.kill(pid, 'SIGINT'); - } catch(err) { + } catch (err) { if (err && err.code === 'ESRCH') { log.warn('Unclean Merit process shutdown, process not found with pid: ' + pid); return callback(null); - } else if(err) { + } else if (err) { return callback(err); } } @@ -934,7 +926,7 @@ Merit.prototype._stopSpawnedMerit = function(callback) { }); } - if(spawnOptions.exec) { + if (spawnOptions.exec) { stopProcess(); } else { callback(null); @@ -950,14 +942,11 @@ Merit.prototype._spawnChildProcess = function(callback) { try { self._loadSpawnConfiguration(node); - } catch(e) { + } catch (e) { return callback(e); } - var options = [ - '--conf=' + this.spawn.configPath, - '--datadir=' + this.spawn.datadir, - ]; + var options = ['--conf=' + this.spawn.configPath, '--datadir=' + this.spawn.datadir]; if (self._getNetworkOption()) { options.push(self._getNetworkOption()); @@ -969,8 +958,8 @@ Merit.prototype._spawnChildProcess = function(callback) { } log.info('Starting Meritd process'); - if(self.spawn.exec) { - self.spawn.process = spawn(self.spawn.exec, options, {stdio: 'inherit'}); + if (self.spawn.exec) { + self.spawn.process = spawn(self.spawn.exec, options, { stdio: 'inherit' }); self.spawn.process.on('error', function(err) { self.emit('error', err); @@ -994,45 +983,45 @@ Merit.prototype._spawnChildProcess = function(callback) { var exitShutdown = false; - async.retry({times: 60, interval: self.startRetryInterval}, function(done) { - if (self.node.stopping) { - exitShutdown = true; - return done(); - } - - node.client = new MeritRPC({ - protocol: 'http', - host: '127.0.0.1', - port: self.spawn.config.rpcport, - user: self.spawn.config.rpcuser, - pass: self.spawn.config.rpcpassword, - queue: self.spawn.config.rpcqueue, - }); - - self._loadTipFromNode(node, done); - - }, function(err) { - if (err) { - return callback(err); - } - if (exitShutdown) { - return callback(new Error('Stopping while trying to spawn meritd.')); - } + async.retry( + { times: 60, interval: self.startRetryInterval }, + function(done) { + if (self.node.stopping) { + exitShutdown = true; + return done(); + } - self._initZmqSubSocket(node, self.spawn.config.zmqpubrawtx); + node.client = new MeritRPC({ + protocol: 'http', + host: '127.0.0.1', + port: self.spawn.config.rpcport, + user: self.spawn.config.rpcuser, + pass: self.spawn.config.rpcpassword, + queue: self.spawn.config.rpcqueue, + }); - self._checkReindex(node, function(err) { + self._loadTipFromNode(node, done); + }, + function(err) { if (err) { return callback(err); } - self._checkSyncedAndSubscribeZmqEvents(node); - callback(null, node); - }); + if (exitShutdown) { + return callback(new Error('Stopping while trying to spawn meritd.')); + } - }); + self._initZmqSubSocket(node, self.spawn.config.zmqpubrawtx); + self._checkReindex(node, function(err) { + if (err) { + return callback(err); + } + self._checkSyncedAndSubscribeZmqEvents(node); + callback(null, node); + }); + }, + ); }); - }; Merit.prototype._connectProcess = function(config, callback) { @@ -1040,37 +1029,40 @@ Merit.prototype._connectProcess = function(config, callback) { var node = {}; var exitShutdown = false; - async.retry({times: 60, interval: self.startRetryInterval}, function(done) { - if (self.node.stopping) { - exitShutdown = true; - return done(); - } - - node.client = new MeritRPC({ - protocol: config.rpcprotocol || 'http', - host: config.rpchost || '127.0.0.1', - port: config.rpcport, - user: config.rpcuser, - pass: config.rpcpassword, - rejectUnauthorized: _.isUndefined(config.rpcstrict) ? true : config.rpcstrict, - queue: config.rpcqueue, - }); + async.retry( + { times: 60, interval: self.startRetryInterval }, + function(done) { + if (self.node.stopping) { + exitShutdown = true; + return done(); + } - self._loadTipFromNode(node, done); + node.client = new MeritRPC({ + protocol: config.rpcprotocol || 'http', + host: config.rpchost || '127.0.0.1', + port: config.rpcport, + user: config.rpcuser, + pass: config.rpcpassword, + rejectUnauthorized: _.isUndefined(config.rpcstrict) ? true : config.rpcstrict, + queue: config.rpcqueue, + }); - }, function(err) { - if (err) { - return callback(err); - } - if (exitShutdown) { - return callback(new Error('Stopping while trying to connect to meritd.')); - } + self._loadTipFromNode(node, done); + }, + function(err) { + if (err) { + return callback(err); + } + if (exitShutdown) { + return callback(new Error('Stopping while trying to connect to meritd.')); + } - self._initZmqSubSocket(node, config.zmqpubrawtx); - self._subscribeZmqEvents(node); + self._initZmqSubSocket(node, config.zmqpubrawtx); + self._subscribeZmqEvents(node); - callback(null, node); - }); + callback(null, node); + }, + ); }; /** @@ -1080,45 +1072,47 @@ Merit.prototype._connectProcess = function(config, callback) { Merit.prototype.start = function(callback) { var self = this; - async.series([ - function(next) { - if (self.options.spawn) { - self._spawnChildProcess(function(err, node) { - if (err) { - return next(err); - } - self.nodes.push(node); + async.series( + [ + function(next) { + if (self.options.spawn) { + self._spawnChildProcess(function(err, node) { + if (err) { + return next(err); + } + self.nodes.push(node); + next(); + }); + } else { next(); - }); - } else { - next(); - } - }, - function(next) { - if (self.options.connect) { - async.map(self.options.connect, self._connectProcess.bind(self), function(err, nodes) { - if (err) { - return callback(err); - } - for(var i = 0; i < nodes.length; i++) { - self.nodes.push(nodes[i]); - } + } + }, + function(next) { + if (self.options.connect) { + async.map(self.options.connect, self._connectProcess.bind(self), function(err, nodes) { + if (err) { + return callback(err); + } + for (var i = 0; i < nodes.length; i++) { + self.nodes.push(nodes[i]); + } + next(); + }); + } else { next(); - }); - } else { - next(); + } + }, + ], + function(err) { + if (err) { + return callback(err); } - } - ], function(err) { - if (err) { - return callback(err); - } - if (self.nodes.length === 0) { - return callback(new Error('Merit configuration options "spawn" or "connect" are expected')); - } - self._initChain(callback); - }); - + if (self.nodes.length === 0) { + return callback(new Error('Merit configuration options "spawn" or "connect" are expected')); + } + self._initChain(callback); + }, + ); }; /** @@ -1173,20 +1167,20 @@ Merit.prototype.getAddressBalance = function(addressArg, options, callback) { var self = this; var addresses = self._normalizeAddressArg(addressArg); var cacheKeySuffix = addresses.join(''); - var cacheKey = options.invites ? 'i' + cacheKeySuffix: cacheKeySuffix; + var cacheKey = options.invites ? 'i' + cacheKeySuffix : cacheKeySuffix; var balance = self.balanceCache.get(cacheKey); if (balance) { return setImmediate(function() { callback(null, balance); }); } else { - let req = {addresses, invites: options.invites, detailed: options.detailed}; + let req = { addresses, invites: options.invites, detailed: options.detailed }; this.client.getAddressBalance(req, function(err, response) { if (err) { return callback(self._wrapRPCError(err)); } - self.balanceCache.set(cacheKey, {result: response.result}); - callback(null, {result: response.result}); + self.balanceCache.set(cacheKey, { result: response.result }); + callback(null, { result: response.result }); }); } }; @@ -1235,7 +1229,7 @@ Merit.prototype.getAddressUnspentOutputs = function(addressArg, options, callbac if (!spentOutputs[utxo.txid]) { return true; } else { - return (spentOutputs[utxo.txid].indexOf(utxo.outputIndex) === -1); + return spentOutputs[utxo.txid].indexOf(utxo.outputIndex) === -1; } }); } @@ -1273,7 +1267,6 @@ Merit.prototype.getAddressUnspentOutputs = function(addressArg, options, callbac } else { finish(); } - }; Merit.prototype._getBalanceFromMempool = function(deltas) { @@ -1326,7 +1319,7 @@ Merit.prototype.getAddressTxids = function(addressArg, options, callback) { var rangeQuery = false; try { rangeQuery = self._getHeightRangeQuery(options); - } catch(err) { + } catch (err) { return callback(err); } if (rangeQuery) { @@ -1354,7 +1347,7 @@ Merit.prototype.getAddressTxids = function(addressArg, options, callback) { }); } else { var txidOpts = { - addresses: addresses + addresses: addresses, }; if (rangeQuery) { self._getHeightRangeQuery(options, txidOpts); @@ -1374,7 +1367,7 @@ Merit.prototype.getAddressTxids = function(addressArg, options, callback) { } if (queryMempool) { - self.client.getAddressMempool({addresses: addresses}, function(err, response) { + self.client.getAddressMempool({ addresses: addresses }, function(err, response) { if (err) { return callback(self._wrapRPCError(err)); } @@ -1384,7 +1377,6 @@ Merit.prototype.getAddressTxids = function(addressArg, options, callback) { } else { finish(); } - }; Merit.prototype._getConfirmationsDetail = function(transaction) { @@ -1408,7 +1400,7 @@ Merit.prototype._getAddressDetailsForInput = function(input, inputIndex, result, if (!result.addresses[address]) { result.addresses[address] = { inputIndexes: [inputIndex], - outputIndexes: [] + outputIndexes: [], }; } else { result.addresses[address].inputIndexes.push(inputIndex); @@ -1426,7 +1418,7 @@ Merit.prototype._getAddressDetailsForOutput = function(output, outputIndex, resu if (!result.addresses[address]) { result.addresses[address] = { inputIndexes: [], - outputIndexes: [outputIndex] + outputIndexes: [outputIndex], }; } else { result.addresses[address].outputIndexes.push(outputIndex); @@ -1438,7 +1430,7 @@ Merit.prototype._getAddressDetailsForOutput = function(output, outputIndex, resu Merit.prototype._getAddressDetailsForTransaction = function(transaction, addressStrings) { var result = { addresses: {}, - micros: 0 + micros: 0, }; for (var inputIndex = 0; inputIndex < transaction.inputs.length; inputIndex++) { @@ -1464,23 +1456,20 @@ Merit.prototype._getAddressDetailsForTransaction = function(transaction, address Merit.prototype._getAddressDetailedTransaction = function(txid, options, next) { var self = this; - self.getDetailedTransaction( - txid, - function(err, transaction) { - if (err) { - return next(err); - } - var addressDetails = self._getAddressDetailsForTransaction(transaction, options.addressStrings); - - var details = { - addresses: addressDetails.addresses, - micros: addressDetails.micros, - confirmations: self._getConfirmationsDetail(transaction), - tx: transaction - }; - next(null, details); + self.getDetailedTransaction(txid, function(err, transaction) { + if (err) { + return next(err); } - ); + var addressDetails = self._getAddressDetailsForTransaction(transaction, options.addressStrings); + + var details = { + addresses: addressDetails.addresses, + micros: addressDetails.micros, + confirmations: self._getConfirmationsDetail(transaction), + tx: transaction, + }; + next(null, details); + }); }; Merit.prototype._getAddressStrings = function(addresses) { @@ -1526,11 +1515,17 @@ Merit.prototype.getAddressHistory = function(addressArg, options, callback) { var fromArg = parseInt(options.from || 0); var toArg = parseInt(options.to || self.maxTransactionHistory); - if ((toArg - fromArg) > self.maxTransactionHistory) { - return callback(new Error( - '"from" (' + options.from + ') and "to" (' + options.to + ') range should be less than or equal to ' + - self.maxTransactionHistory - )); + if (toArg - fromArg > self.maxTransactionHistory) { + return callback( + new Error( + '"from" (' + + options.from + + ') and "to" (' + + options.to + + ') range should be less than or equal to ' + + self.maxTransactionHistory, + ), + ); } self.getAddressTxids(addresses, options, function(err, txids) { @@ -1541,7 +1536,7 @@ Merit.prototype.getAddressHistory = function(addressArg, options, callback) { var totalCount = txids.length; try { txids = self._paginateTxids(txids, fromArg, toArg); - } catch(e) { + } catch (e) { return callback(e); } @@ -1549,10 +1544,14 @@ Merit.prototype.getAddressHistory = function(addressArg, options, callback) { txids, self.transactionConcurrency, function(txid, next) { - self._getAddressDetailedTransaction(txid, { - queryMempool: queryMempool, - addressStrings: addressStrings - }, next); + self._getAddressDetailedTransaction( + txid, + { + queryMempool: queryMempool, + addressStrings: addressStrings, + }, + next, + ); }, function(err, transactions) { if (err) { @@ -1560,9 +1559,9 @@ Merit.prototype.getAddressHistory = function(addressArg, options, callback) { } callback(null, { totalCount: totalCount, - items: transactions + items: transactions, }); - } + }, ); }); }; @@ -1573,25 +1572,24 @@ Merit.prototype.getAddressHistory = function(addressArg, options, callback) { * @param {Function} callback */ Merit.prototype.getReferral = function(refid, callback) { - var self = this; - var referral = self.referralCache.get(refid); - if (referral) { - return setImmediate(function() { - callback(null, referral); - }); - } else { - self._tryAllClients(function(client, done) { - client.getRawReferral(refid, function(err, response) { - - if (err) { - return done(self._wrapRPCError(err)); - } - var referral = Referral(response.result, self.node.getNetworkName()); - self.referralCache.set(refid, referral); - done(null, referral); - }); - }, callback); - } + var self = this; + var referral = self.referralCache.get(refid); + if (referral) { + return setImmediate(function() { + callback(null, referral); + }); + } else { + self._tryAllClients(function(client, done) { + client.getRawReferral(refid, function(err, response) { + if (err) { + return done(self._wrapRPCError(err)); + } + var referral = Referral(response.result, self.node.getNetworkName()); + self.referralCache.set(refid, referral); + done(null, referral); + }); + }, callback); + } }; /** @@ -1601,69 +1599,70 @@ Merit.prototype.getReferral = function(refid, callback) { * @param {Function} callback */ Merit.prototype.getAddressReferrals = function(addressArg, options, callback) { - var self = this; + var self = this; - var addresses = self._normalizeAddressArg(addressArg); - if (addresses.length > this.maxAddressesQuery) { - return callback(new TypeError('Maximum number of addresses (' + this.maxAddressesQuery + ') exceeded')); - } + var addresses = self._normalizeAddressArg(addressArg); + if (addresses.length > this.maxAddressesQuery) { + return callback(new TypeError('Maximum number of addresses (' + this.maxAddressesQuery + ') exceeded')); + } - var cacheKey = addresses.join(''); + var cacheKey = addresses.join(''); - function loadFromMempool(cb) { - return self.client.getaddressmempoolreferrals({addresses: addresses}, function (err, response) { - if (err) { - return cb(self._wrapRPCError(err)); - } + function loadFromMempool(cb) { + return self.client.getaddressmempoolreferrals({ addresses: addresses }, function(err, response) { + if (err) { + return cb(self._wrapRPCError(err)); + } - console.log('mempool', response.result); - return cb(null, response.result); - }); - } + console.log('mempool', response.result); + return cb(null, response.result); + }); + } - function loadFromBc(cb) { - return self.client.getaddressreferrals({addresses: addresses}, function (err, response) { - if (err) { - return cb(self._wrapRPCError(err)); - } + function loadFromBc(cb) { + return self.client.getaddressreferrals({ addresses: addresses }, function(err, response) { + if (err) { + return cb(self._wrapRPCError(err)); + } - return cb(null, response.result); - }); - } + return cb(null, response.result); + }); + } - function finish(referrals) { - return callback(null, { - totalCount: referrals.length, - items: referrals - }); - } + function finish(referrals) { + return callback(null, { + totalCount: referrals.length, + items: referrals, + }); + } - return loadFromMempool(function(err, mempoolReferrals) { - mempoolReferrals = mempoolReferrals || []; - var cachedReferrals = self.referralsCache.get(cacheKey); - if (cachedReferrals) { - var referrals = mempoolReferrals.concat(cachedReferrals); - console.log(cachedReferrals.length+' referrals read from cache + '+mempoolReferrals.length+' from mempool'); - finish(referrals); + return loadFromMempool(function(err, mempoolReferrals) { + mempoolReferrals = mempoolReferrals || []; + var cachedReferrals = self.referralsCache.get(cacheKey); + if (cachedReferrals) { + var referrals = mempoolReferrals.concat(cachedReferrals); + console.log( + cachedReferrals.length + ' referrals read from cache + ' + mempoolReferrals.length + ' from mempool', + ); + finish(referrals); + } else { + loadFromBc(function(err, bcReferrals) { + var referrals = []; + if (!err) { + self.referralsCache.set(cacheKey, bcReferrals); + referrals = mempoolReferrals.concat(bcReferrals); + log.info(bcReferrals.length + ' referrals read from bc + '); + log.info(mempoolReferrals.length + ' from mempool'); } else { - loadFromBc(function(err, bcReferrals) { - var referrals = []; - if (!err) { - self.referralsCache.set(cacheKey, bcReferrals); - referrals = mempoolReferrals.concat(bcReferrals); - log.info(bcReferrals.length +' referrals read from bc + '); - log.info(mempoolReferrals.length + ' from mempool'); - } else { - log.info('error in loadFromBc: ', err); - } - referrals = _.uniqBy(referrals, 'refid'); - finish(referrals); - }); + log.info('error in loadFromBc: ', err); } - }); + referrals = _.uniqBy(referrals, 'refid'); + finish(referrals); + }); + } + }); }; - /** * Will get the summary including txids and balance for an address or multiple addresses * @param {String|Address|Array} addressArg - An address string, Merit address, or array of addresses @@ -1685,16 +1684,17 @@ Merit.prototype.getAddressSummary = function(addressArg, options, callback) { var fromArg = parseInt(options.from || 0); var toArg = parseInt(options.to || self.maxTxids); - if ((toArg - fromArg) > self.maxTxids) { - return callback(new Error( - '"from" (' + fromArg + ') and "to" (' + toArg + ') range should be less than or equal to ' + - self.maxTxids - )); + if (toArg - fromArg > self.maxTxids) { + return callback( + new Error( + '"from" (' + fromArg + ') and "to" (' + toArg + ') range should be less than or equal to ' + self.maxTxids, + ), + ); } var paginatedTxids; try { paginatedTxids = self._paginateTxids(allTxids, fromArg, toArg); - } catch(e) { + } catch (e) { return callback(e); } @@ -1707,49 +1707,52 @@ Merit.prototype.getAddressSummary = function(addressArg, options, callback) { } function querySummary() { - async.parallel([ - function getTxList(done) { - self.getAddressTxids(addresses, {queryMempool: false}, function(err, txids) { - if (err) { - return done(err); - } - summaryTxids = txids; - summary.appearances = txids.length; - done(); - }); - }, - function getBalance(done) { - self.getAddressBalance(addresses, options, function(err, data) { - if (err) { - return done(err); + async.parallel( + [ + function getTxList(done) { + self.getAddressTxids(addresses, { queryMempool: false }, function(err, txids) { + if (err) { + return done(err); + } + summaryTxids = txids; + summary.appearances = txids.length; + done(); + }); + }, + function getBalance(done) { + self.getAddressBalance(addresses, options, function(err, data) { + if (err) { + return done(err); + } + summary.totalReceived = data.received; + summary.totalSpent = data.received - data.balance; + summary.balance = data.balance; + done(); + }); + }, + function getMempool(done) { + if (!queryMempool) { + return done(); } - summary.totalReceived = data.received; - summary.totalSpent = data.received - data.balance; - summary.balance = data.balance; - done(); - }); - }, - function getMempool(done) { - if (!queryMempool) { - return done(); + self.client.getAddressMempool({ addresses: addresses }, function(err, response) { + if (err) { + return done(self._wrapRPCError(err)); + } + mempoolTxids = self._getTxidsFromMempool(response.result); + summary.unconfirmedAppearances = mempoolTxids.length; + summary.unconfirmedBalance = self._getBalanceFromMempool(response.result); + done(); + }); + }, + ], + function(err) { + if (err) { + return callback(err); } - self.client.getAddressMempool({'addresses': addresses}, function(err, response) { - if (err) { - return done(self._wrapRPCError(err)); - } - mempoolTxids = self._getTxidsFromMempool(response.result); - summary.unconfirmedAppearances = mempoolTxids.length; - summary.unconfirmedBalance = self._getBalanceFromMempool(response.result); - done(); - }); + self.summaryCache.set(cacheKey, summary); + finishWithTxids(); }, - ], function(err) { - if (err) { - return callback(err); - } - self.summaryCache.set(cacheKey, summary); - finishWithTxids(); - }); + ); } if (options.noTxList) { @@ -1762,7 +1765,6 @@ Merit.prototype.getAddressSummary = function(addressArg, options, callback) { } else { querySummary(); } - }; Merit.prototype._maybeGetBlockHash = function(blockArg, callback) { @@ -1890,7 +1892,7 @@ Merit.prototype.getBlockOverview = function(blockArg, callback) { nonce: result.nonce, bits: result.bits, difficulty: result.difficulty, - txids: result.tx + txids: result.tx, }; self.blockOverviewCache.set(blockhash, blockOverview); done(null, blockOverview); @@ -1968,7 +1970,7 @@ Merit.prototype.getBlockHeader = function(blockArg, callback) { medianTime: result.mediantime, nonce: result.nonce, bits: result.bits, - difficulty: result.difficulty + difficulty: result.difficulty, }; done(null, header); }); @@ -1978,7 +1980,6 @@ Merit.prototype.getBlockHeader = function(blockArg, callback) { self._maybeGetBlockHash(blockArg, queryHeader); }; - /** * Will estimate the fee per kilobyte. * @param {Number} blocks - The number of blocks for the transaction to be confirmed. @@ -2016,7 +2017,6 @@ Merit.prototype.sendTransaction = function(tx, options, callback) { } callback(null, response.result); }); - }; /** @@ -2119,7 +2119,7 @@ Merit.prototype.getDetailedTransaction = function(txid, callback) { var self = this; var tx = self.transactionDetailedCache.get(txid); - function getMicros (input, isInvite) { + function getMicros(input, isInvite) { if (input.valueSat) { return input.valueSat; } @@ -2135,7 +2135,7 @@ Merit.prototype.getDetailedTransaction = function(txid, callback) { function addInputsToTx(tx, result) { tx.inputs = []; tx.inputMicros = 0; - for(var inputIndex = 0; inputIndex < result.vin.length; inputIndex++) { + for (var inputIndex = 0; inputIndex < result.vin.length; inputIndex++) { var input = result.vin[inputIndex]; if (!tx.isCoinbase && input.valueSat) { tx.inputMicros += input.valueSat; // TODO: rename sat @@ -2167,7 +2167,7 @@ Merit.prototype.getDetailedTransaction = function(txid, callback) { function addOutputsToTx(tx, result) { tx.outputs = []; tx.outputMicros = 0; - for(var outputIndex = 0; outputIndex < result.vout.length; outputIndex++) { + for (var outputIndex = 0; outputIndex < result.vout.length; outputIndex++) { var out = result.vout[outputIndex]; tx.outputMicros += !tx.isInvite ? out.valueSat : out.value; // TODO: rename sat var address = null; @@ -2184,7 +2184,7 @@ Merit.prototype.getDetailedTransaction = function(txid, callback) { spentIndex: out.spentIndex, spentHeight: out.spentHeight, address, - alias + alias, }); } } @@ -2296,7 +2296,7 @@ Merit.prototype.getInfo = function(callback) { testnet: result.testnet, relayFee: result.relayfee, errors: result.errors, - network: self.node.getNetworkName() + network: self.node.getNetworkName(), }; callback(null, info); }); @@ -2335,10 +2335,10 @@ Merit.prototype.validateAddress = function(address, callback) { * Checks if an easyScript is on the blockChain. * @param {String} easyScript - The full easyScript value. */ - Merit.prototype.getInputForEasySend = function(easyScript, callback) { - log.info('ValidateEasyScript RPC called: ', easyScript); +Merit.prototype.getInputForEasySend = function(easyScript, callback) { + log.info('ValidateEasyScript RPC called: ', easyScript); - const self = this; + const self = this; if (typeof easyScript == 'string' || easyScript instanceof String) { self.client.getInputForEasySend(easyScript, function(err, response) { @@ -2348,12 +2348,12 @@ Merit.prototype.validateAddress = function(address, callback) { callback(null, response); } }); - } else { - var err = new errors.RPCError('EasyScript was missing or incorrect'); - err.code = -8; - return callback(self._wrapRPCError(err)); - } - }; + } else { + var err = new errors.RPCError('EasyScript was missing or incorrect'); + err.code = -8; + return callback(self._wrapRPCError(err)); + } +}; /** * Get ANV for array of keys @@ -2380,7 +2380,7 @@ Merit.prototype.getANV = function(addressArg, callback) { self.anvCache.set(cacheKey, response.result); callback(null, response.result); }); -} +}; Merit.prototype.getCommunityInfo = function(addressArg, callback) { const address = this._normalizeAddressArg(addressArg); @@ -2405,7 +2405,6 @@ Merit.prototype.getRewards = function(addressArg, callback) { var cacheKey = addresses.join(''); var rewards = self.rewardsCache.get(cacheKey); - if (rewards) { return setImmediate(function() { callback(null, rewards); @@ -2420,7 +2419,7 @@ Merit.prototype.getRewards = function(addressArg, callback) { self.rewardsCache.set(cacheKey, response.result); callback(null, response.result); }); -} +}; /** * Send raw referral to nodes @@ -2436,8 +2435,7 @@ Merit.prototype.sendReferral = function(referral, callback) { } callback(null, response.result); }); - -} +}; /** * Called by Node to stop the service. @@ -2472,34 +2470,35 @@ Merit.prototype.stop = function(callback) { const { promisify } = require('util'); Merit.prototype.getMempoolReferrals = async function(addresses) { - const {err, result} = await promisify(this.client.getaddressmempoolreferrals.bind(this.client))({addresses: addresses}); - if (err) throw err; - return result; + const { err, result } = await promisify(this.client.getaddressmempoolreferrals.bind(this.client))({ + addresses: addresses, + }); + if (err) throw err; + return result; }; Merit.prototype.getBlockchainReferrals = async function(addresses) { - const {err, result} = await promisify(this.client.getaddressreferrals.bind(this.client))({addresses: addresses}); - if (err) throw err; - return result; + const { err, result } = await promisify(this.client.getaddressreferrals.bind(this.client))({ addresses: addresses }); + if (err) throw err; + return result; }; Merit.prototype.getAddressMempool = async function(addresses) { - const {err, result} = await promisify(this.client.getAddressMempool.bind(this.client))({addresses: addresses}); - if (err) throw err; - return result; + const { err, result } = await promisify(this.client.getAddressMempool.bind(this.client))({ addresses: addresses }); + if (err) throw err; + return result; }; Merit.prototype.getCommunityRank = async function(addresses) { - const {err, result} = await promisify(this.client.getaddressrank.bind(this.client))({addresses: addresses}); - if (err) throw err; - return result; + const { err, result } = await promisify(this.client.getaddressrank.bind(this.client))({ addresses: addresses }); + if (err) throw err; + return result; }; Merit.prototype.getCommunityLeaderboard = async function(limit) { - const {err, result} = await promisify(this.client.getaddressleaderboard.bind(this.client))(limit); - if (err) throw err; - return result; + const { err, result } = await promisify(this.client.getaddressleaderboard.bind(this.client))(limit); + if (err) throw err; + return result; }; - module.exports = Merit; diff --git a/packages/merit-node/lib/services/web.js b/packages/merit-node/lib/services/web.js index 160ae938cd..5aa7718f79 100644 --- a/packages/merit-node/lib/services/web.js +++ b/packages/merit-node/lib/services/web.js @@ -14,7 +14,6 @@ var _ = meritcore.deps._; var index = require('../'); var log = index.log; - /** * This service represents a hub for combining several services over a single HTTP port. Services * can extend routes by implementing the methods `getRoutePrefix` and `setupRoutes`. Additionally @@ -41,8 +40,9 @@ var WebService = function(options) { // see: https://github.com/expressjs/body-parser#limit this.jsonRequestLimit = options.jsonRequestLimit || '10mb'; - this.enableSocketRPC = _.isUndefined(options.enableSocketRPC) ? - WebService.DEFAULT_SOCKET_RPC : options.enableSocketRPC; + this.enableSocketRPC = _.isUndefined(options.enableSocketRPC) + ? WebService.DEFAULT_SOCKET_RPC + : options.enableSocketRPC; this.node.on('ready', function() { self.eventNames = self.getEventNames(); @@ -63,9 +63,9 @@ WebService.DEFAULT_SOCKET_RPC = true; */ WebService.prototype.start = function(callback) { this.app = express(); - this.app.use(bodyParser.json({limit: this.jsonRequestLimit})); + this.app.use(bodyParser.json({ limit: this.jsonRequestLimit })); - if(this.https) { + if (this.https) { this.transformHttpsOptions(); this.server = https.createServer(this.httpsOptions, this.app); } else { @@ -86,7 +86,7 @@ WebService.prototype.stop = function(callback) { var self = this; setImmediate(function() { - if(self.server) { + if (self.server) { self.server.close(); } callback(); @@ -98,11 +98,11 @@ WebService.prototype.stop = function(callback) { * all of the exposed HTTP routes. */ WebService.prototype.setupAllRoutes = function() { - for(var key in this.node.services) { + for (var key in this.node.services) { var subApp = new express(); var service = this.node.services[key]; - if(service.getRoutePrefix && service.setupRoutes) { + if (service.getRoutePrefix && service.setupRoutes) { this.app.use('/' + this.node.services[key].getRoutePrefix(), subApp); this.node.services[key].setupRoutes(subApp, express); } else { @@ -129,7 +129,7 @@ WebService.prototype.createMethodsMap = function() { fn: function() { return method.apply(instance, arguments); }, - args: args + args: args, }; }); }; @@ -143,7 +143,7 @@ WebService.prototype.getEventNames = function() { var eventNames = []; function addEventName(name) { - if(eventNames.indexOf(name) > -1) { + if (eventNames.indexOf(name) > -1) { throw new Error('Duplicate event ' + name); } eventNames.push(name); @@ -152,7 +152,7 @@ WebService.prototype.getEventNames = function() { events.forEach(function(event) { addEventName(event.name); - if(event.extraEvents) { + if (event.extraEvents) { event.extraEvents.forEach(function(name) { addEventName(name); }); @@ -174,7 +174,7 @@ WebService.prototype._getRemoteAddress = function(socket) { WebService.prototype.socketHandler = function(socket) { var self = this; var remoteAddress = self._getRemoteAddress(socket); - var bus = this.node.openBus({remoteAddress: remoteAddress}); + var bus = this.node.openBus({ remoteAddress: remoteAddress }); if (this.enableSocketRPC) { socket.on('message', this.socketMessageHandler.bind(this)); @@ -192,10 +192,10 @@ WebService.prototype.socketHandler = function(socket) { this.eventNames.forEach(function(eventName) { bus.on(eventName, function() { - if(socket.connected) { + if (socket.connected) { var results = []; - for(var i = 0; i < arguments.length; i++) { + for (var i = 0; i < arguments.length; i++) { results.push(arguments[i]); } @@ -221,27 +221,27 @@ WebService.prototype.socketMessageHandler = function(message, socketCallback) { if (this.methodsMap[message.method]) { var params = message.params; - if(!params || !params.length) { + if (!params || !params.length) { params = []; } - if(params.length !== this.methodsMap[message.method].args) { + if (params.length !== this.methodsMap[message.method].args) { return socketCallback({ error: { - message: 'Expected ' + this.methodsMap[message.method].args + ' parameter(s)' - } + message: 'Expected ' + this.methodsMap[message.method].args + ' parameter(s)', + }, }); } var callback = function(err, result) { var response = {}; - if(err) { + if (err) { response.error = { - message: err.toString() + message: err.toString(), }; } - if(result) { + if (result) { response.result = result; } @@ -253,8 +253,8 @@ WebService.prototype.socketMessageHandler = function(message, socketCallback) { } else { socketCallback({ error: { - message: 'Method Not Found' - } + message: 'Method Not Found', + }, }); } }; @@ -264,13 +264,13 @@ WebService.prototype.socketMessageHandler = function(message, socketCallback) { * replace the options with the files. */ WebService.prototype.transformHttpsOptions = function() { - if(!this.httpsOptions || !this.httpsOptions.key || !this.httpsOptions.cert) { + if (!this.httpsOptions || !this.httpsOptions.key || !this.httpsOptions.cert) { throw new Error('Missing https options'); } this.httpsOptions = { key: fs.readFileSync(this.httpsOptions.key), - cert: fs.readFileSync(this.httpsOptions.cert) + cert: fs.readFileSync(this.httpsOptions.cert), }; }; diff --git a/packages/merit-node/lib/utils.js b/packages/merit-node/lib/utils.js index b4b3af7a03..f12076a75f 100644 --- a/packages/merit-node/lib/utils.js +++ b/packages/merit-node/lib/utils.js @@ -8,11 +8,13 @@ utils.isHash = function isHash(value) { }; utils.isSafeNatural = function isSafeNatural(value) { - return typeof value === 'number' && + return ( + typeof value === 'number' && isFinite(value) && Math.floor(value) === value && value >= 0 && - value <= MAX_SAFE_INTEGER; + value <= MAX_SAFE_INTEGER + ); }; utils.startAtZero = function startAtZero(obj, key) { @@ -31,7 +33,7 @@ utils.parseParamsWithJSON = function parseParamsWithJSON(paramsArg) { var param; try { param = JSON.parse(paramArg); - } catch(err) { + } catch (err) { param = paramArg; } return param; diff --git a/packages/merit-node/regtest/cluster.js b/packages/merit-node/regtest/cluster.js index 5047f5a13e..420c50aa23 100644 --- a/packages/merit-node/regtest/cluster.js +++ b/packages/merit-node/regtest/cluster.js @@ -28,7 +28,7 @@ describe('Merit Cluster', function() { rpcpassword: 'local321', rpcport: 30521, zmqpubrawtx: 'tcp://127.0.0.1:30611', - zmqpubhashblock: 'tcp://127.0.0.1:30611' + zmqpubhashblock: 'tcp://127.0.0.1:30611', }, { datadir: path.resolve(__dirname, './data/node2'), @@ -37,7 +37,7 @@ describe('Merit Cluster', function() { rpcpassword: 'local321', rpcport: 30522, zmqpubrawtx: 'tcp://127.0.0.1:30622', - zmqpubhashblock: 'tcp://127.0.0.1:30622' + zmqpubhashblock: 'tcp://127.0.0.1:30622', }, { datadir: path.resolve(__dirname, './data/node3'), @@ -46,53 +46,59 @@ describe('Merit Cluster', function() { rpcpassword: 'local321', rpcport: 30523, zmqpubrawtx: 'tcp://127.0.0.1:30633', - zmqpubhashblock: 'tcp://127.0.0.1:30633' - } + zmqpubhashblock: 'tcp://127.0.0.1:30633', + }, ]; before(function(done) { log.info('Starting 3 meritd daemons'); this.timeout(60000); - async.each(nodesConf, function(nodeConf, next) { - var opts = [ - '--regtest', - '--datadir=' + nodeConf.datadir, - '--conf=' + nodeConf.conf - ]; - - rimraf(path.resolve(nodeConf.datadir, './regtest'), function(err) { - if (err) { - return done(err); - } - - var process = spawn(execPath, opts, {stdio: 'inherit'}); - - var client = new MeritRPC({ - protocol: 'http', - host: '127.0.0.1', - port: nodeConf.rpcport, - user: nodeConf.rpcuser, - pass: nodeConf.rpcpassword - }); - - daemons.push(process); - - async.retry({times: 10, interval: 5000}, function(ready) { - client.getInfo(ready); - }, next); - - }); + async.each( + nodesConf, + function(nodeConf, next) { + var opts = ['--regtest', '--datadir=' + nodeConf.datadir, '--conf=' + nodeConf.conf]; + + rimraf(path.resolve(nodeConf.datadir, './regtest'), function(err) { + if (err) { + return done(err); + } - }, done); + var process = spawn(execPath, opts, { stdio: 'inherit' }); + + var client = new MeritRPC({ + protocol: 'http', + host: '127.0.0.1', + port: nodeConf.rpcport, + user: nodeConf.rpcuser, + pass: nodeConf.rpcpassword, + }); + + daemons.push(process); + + async.retry( + { times: 10, interval: 5000 }, + function(ready) { + client.getInfo(ready); + }, + next, + ); + }); + }, + done, + ); }); after(function(done) { this.timeout(10000); setTimeout(function() { - async.each(daemons, function(process, next) { - process.once('exit', next); - process.kill('SIGINT'); - }, done); + async.each( + daemons, + function(process, next) { + process.once('exit', next); + process.kill('SIGINT'); + }, + done, + ); }, 1000); }); @@ -111,26 +117,26 @@ describe('Merit Cluster', function() { rpcport: 30521, rpcuser: 'merit', rpcpassword: 'local321', - zmqpubrawtx: 'tcp://127.0.0.1:30611' + zmqpubrawtx: 'tcp://127.0.0.1:30611', }, { rpchost: '127.0.0.1', rpcport: 30522, rpcuser: 'merit', rpcpassword: 'local321', - zmqpubrawtx: 'tcp://127.0.0.1:30622' + zmqpubrawtx: 'tcp://127.0.0.1:30622', }, { rpchost: '127.0.0.1', rpcport: 30523, rpcuser: 'merit', rpcpassword: 'local321', - zmqpubrawtx: 'tcp://127.0.0.1:30633' - } - ] - } - } - ] + zmqpubrawtx: 'tcp://127.0.0.1:30633', + }, + ], + }, + }, + ], }; var regtest = meritcore.Networks.get('regtest'); @@ -151,7 +157,6 @@ describe('Merit Cluster', function() { return done(err); } }); - }); it('step 2: receive block events', function(done) { @@ -169,15 +174,18 @@ describe('Merit Cluster', function() { }); it('step 3: get blocks', function(done) { - async.times(3, function(n, next) { - node.getBlock(1, function(err, block) { - if (err) { - return next(err); - } - should.exist(block); - next(); - }); - }, done); + async.times( + 3, + function(n, next) { + node.getBlock(1, function(err, block) { + if (err) { + return next(err); + } + should.exist(block); + next(); + }); + }, + done, + ); }); - }); diff --git a/packages/merit-node/regtest/meritd.js b/packages/merit-node/regtest/meritd.js index 485e567094..19a6eb0e56 100644 --- a/packages/merit-node/regtest/meritd.js +++ b/packages/merit-node/regtest/meritd.js @@ -27,7 +27,6 @@ var privateKey = meritcore.PrivateKey(); var destKey = meritcore.PrivateKey(); describe('Meritd Functionality', function() { - before(function(done) { this.timeout(60000); @@ -38,7 +37,6 @@ describe('Meritd Functionality', function() { var datadir = __dirname + '/data'; rimraf(datadir + '/regtest', function(err) { - if (err) { throw err; } @@ -46,14 +44,14 @@ describe('Meritd Functionality', function() { meritd = require('../').services.Merit({ spawn: { datadir: datadir, - exec: path.resolve(__dirname, '../bin/meritd') + exec: path.resolve(__dirname, '../bin/meritd'), }, node: { network: regtestNetwork, getNetworkName: function() { return 'regtest'; - } - } + }, + }, }); meritd.on('error', function(err) { @@ -71,7 +69,7 @@ describe('Meritd Functionality', function() { port: 30331, user: 'merit', pass: 'local321', - rejectUnauthorized: false + rejectUnauthorized: false, }); log.info('Generating 100 blocks...'); @@ -92,36 +90,43 @@ describe('Meritd Functionality', function() { client.listUnspent(0, 150, function(err, response) { utxos = response.result; - async.mapSeries(utxos, function(utxo, next) { - async.series([ - function(finished) { - // Load all of the transactions for later testing - client.getTransaction(utxo.txid, function(err, txresponse) { - if (err) { - throw err; - } - // add to the list of transactions for testing later - transactionData.push(txresponse.result.hex); - finished(); - }); - }, - function(finished) { - // Get the private key for each utxo - client.dumpPrivKey(utxo.address, function(err, privresponse) { - if (err) { - throw err; - } - utxo.privateKeyWIF = privresponse.result; - finished(); - }); + async.mapSeries( + utxos, + function(utxo, next) { + async.series( + [ + function(finished) { + // Load all of the transactions for later testing + client.getTransaction(utxo.txid, function(err, txresponse) { + if (err) { + throw err; + } + // add to the list of transactions for testing later + transactionData.push(txresponse.result.hex); + finished(); + }); + }, + function(finished) { + // Get the private key for each utxo + client.dumpPrivKey(utxo.address, function(err, privresponse) { + if (err) { + throw err; + } + utxo.privateKeyWIF = privresponse.result; + finished(); + }); + }, + ], + next, + ); + }, + function(err) { + if (err) { + throw err; } - ], next); - }, function(err) { - if (err) { - throw err; - } - done(); - }); + done(); + }, + ); }); }); }); @@ -138,8 +143,7 @@ describe('Meritd Functionality', function() { }); describe('get blocks by hash', function() { - - [0,1,2,3,5,6,7,8,9].forEach(function(i) { + [0, 1, 2, 3, 5, 6, 7, 8, 9].forEach(function(i) { it('generated block ' + i, function(done) { meritd.getBlock(blockHashes[i], function(err, block) { if (err) { @@ -154,7 +158,7 @@ describe('Meritd Functionality', function() { }); describe('get blocks as buffers', function() { - [0,1,2,3,5,6,7,8,9].forEach(function(i) { + [0, 1, 2, 3, 5, 6, 7, 8, 9].forEach(function(i) { it('generated block ' + i, function(done) { meritd.getRawBlock(blockHashes[i], function(err, block) { if (err) { @@ -182,8 +186,7 @@ describe('Meritd Functionality', function() { }); describe('get blocks by height', function() { - - [0,1,2,3,4,5,6,7,8,9].forEach(function(i) { + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(function(i) { it('generated block ' + i, function(done) { // add the genesis block var height = i + 1; @@ -205,11 +208,10 @@ describe('Meritd Functionality', function() { done(); }); }); - }); describe('get transactions by hash', function() { - [0,1,2,3,4,5,6,7,8,9].forEach(function(i) { + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(function(i) { it('for tx ' + i, function(done) { var txhex = transactionData[i]; var tx = new meritcore.Transaction(); @@ -234,7 +236,7 @@ describe('Meritd Functionality', function() { }); describe('get transactions as buffers', function() { - [0,1,2,3,4,5,6,7,8,9].forEach(function(i) { + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(function(i) { it('for tx ' + i, function(done) { var txhex = transactionData[i]; var tx = new meritcore.Transaction(); @@ -261,7 +263,7 @@ describe('Meritd Functionality', function() { describe('get block header', function() { var expectedWork = new BN(6); - [1,2,3,4,5,6,7,8,9].forEach(function(i) { + [1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(function(i) { it('generate block ' + i, function(done) { meritd.getBlockHeader(blockHashes[i], function(err, blockIndex) { if (err) { @@ -300,7 +302,7 @@ describe('Meritd Functionality', function() { describe('get block index by height', function() { var expectedWork = new BN(6); - [2,3,4,5,6,7,8,9].forEach(function(i) { + [2, 3, 4, 5, 6, 7, 8, 9].forEach(function(i) { it('generate block ' + i, function() { meritd.getBlockHeader(i, function(err, header) { should.exist(header); @@ -324,9 +326,7 @@ describe('Meritd Functionality', function() { }); describe('send transaction functionality', function() { - it('will not error and return the transaction hash', function(done) { - // create and sign the transaction var tx = meritcore.Transaction(); tx.from(utxos[0]); @@ -342,7 +342,6 @@ describe('Meritd Functionality', function() { hash.should.equal(tx.hash); done(); }); - }); it('will throw an error if an unsigned transaction is sent', function(done) { @@ -393,7 +392,6 @@ describe('Meritd Functionality', function() { should.exist(hash); }); }); - }); describe('fee estimation', function() { @@ -481,5 +479,4 @@ describe('Meritd Functionality', function() { }); }); }); - }); diff --git a/packages/merit-node/regtest/node.js b/packages/merit-node/regtest/node.js index 645f921ec2..97f5b9a0e7 100644 --- a/packages/merit-node/regtest/node.js +++ b/packages/merit-node/regtest/node.js @@ -28,7 +28,6 @@ var outputForIsSpentTest1; var unspentOutputSpentTxId; describe('Node Functionality', function() { - var regtest; before(function(done) { @@ -39,7 +38,6 @@ describe('Node Functionality', function() { testKey = meritcore.PrivateKey(testWIF); rimraf(datadir + '/regtest', function(err) { - if (err) { throw err; } @@ -53,11 +51,11 @@ describe('Node Functionality', function() { config: { spawn: { datadir: datadir, - exec: path.resolve(__dirname, '../bin/meritd') - } - } - } - ] + exec: path.resolve(__dirname, '../bin/meritd'), + }, + }, + }, + ], }; node = new meritcoreNode(configuration); @@ -80,7 +78,7 @@ describe('Node Functionality', function() { port: 30331, user: 'merit', pass: 'local321', - rejectUnauthorized: false + rejectUnauthorized: false, }); var syncedHandler = function() { @@ -97,17 +95,14 @@ describe('Node Functionality', function() { throw err; } }); - }); - - }); }); after(function(done) { this.timeout(20000); node.stop(function(err, result) { - if(err) { + if (err) { throw err; } done(); @@ -189,7 +184,7 @@ describe('Node Functionality', function() { var options = { from: 0, to: 10, - queryMempool: false + queryMempool: false, }; node.getAddressHistory(address, options, function(err, results) { if (err) { @@ -211,7 +206,7 @@ describe('Node Functionality', function() { }); it('correctly give the summary for the address', function(done) { var options = { - queryMempool: false + queryMempool: false, }; node.getAddressSummary(address, options, function(err, results) { if (err) { @@ -228,7 +223,6 @@ describe('Node Functionality', function() { }); }); describe('History', function() { - this.timeout(20000); var testKey2; @@ -310,81 +304,78 @@ describe('Node Functionality', function() { } results.length.should.equal(5); - async.series([ - function(next) { - var tx2 = new Transaction(); - tx2Amount = results[0].micros - 10000; - tx2.from(results[0]); - tx2.to(address2, tx2Amount); - tx2.change(address); - tx2.sign(testKey); - tx2Hash = tx2.hash; - node.sendTransaction(tx2.serialize(), function(err) { - if (err) { - return next(err); - } - mineBlock(next); - }); - }, function(next) { - var tx3 = new Transaction(); - tx3.from(results[1]); - tx3.to(address3, results[1].micros - 10000); - tx3.change(address); - tx3.sign(testKey); - node.sendTransaction(tx3.serialize(), function(err) { - if (err) { - return next(err); - } - mineBlock(next); - }); - }, function(next) { - var tx4 = new Transaction(); - tx4.from(results[2]); - tx4.to(address4, results[2].micros - 10000); - tx4.change(address); - tx4.sign(testKey); - node.sendTransaction(tx4.serialize(), function(err) { - if (err) { - return next(err); - } - mineBlock(next); - }); - }, function(next) { - var tx5 = new Transaction(); - tx5.from(results[3]); - tx5.from(results[4]); - tx5.to(address5, results[3].micros - 10000); - tx5.to(address6, results[4].micros - 10000); - tx5.change(address); - tx5.sign(testKey); - node.sendTransaction(tx5.serialize(), function(err) { - if (err) { - return next(err); - } - mineBlock(next); - }); - } - ], function(err) { - if (err) { - throw err; - } - }); + async.series( + [ + function(next) { + var tx2 = new Transaction(); + tx2Amount = results[0].micros - 10000; + tx2.from(results[0]); + tx2.to(address2, tx2Amount); + tx2.change(address); + tx2.sign(testKey); + tx2Hash = tx2.hash; + node.sendTransaction(tx2.serialize(), function(err) { + if (err) { + return next(err); + } + mineBlock(next); + }); + }, + function(next) { + var tx3 = new Transaction(); + tx3.from(results[1]); + tx3.to(address3, results[1].micros - 10000); + tx3.change(address); + tx3.sign(testKey); + node.sendTransaction(tx3.serialize(), function(err) { + if (err) { + return next(err); + } + mineBlock(next); + }); + }, + function(next) { + var tx4 = new Transaction(); + tx4.from(results[2]); + tx4.to(address4, results[2].micros - 10000); + tx4.change(address); + tx4.sign(testKey); + node.sendTransaction(tx4.serialize(), function(err) { + if (err) { + return next(err); + } + mineBlock(next); + }); + }, + function(next) { + var tx5 = new Transaction(); + tx5.from(results[3]); + tx5.from(results[4]); + tx5.to(address5, results[3].micros - 10000); + tx5.to(address6, results[4].micros - 10000); + tx5.change(address); + tx5.sign(testKey); + node.sendTransaction(tx5.serialize(), function(err) { + if (err) { + return next(err); + } + mineBlock(next); + }); + }, + ], + function(err) { + if (err) { + throw err; + } + }, + ); }); - }); - }); - }); it('five addresses', function(done) { - var addresses = [ - address2, - address3, - address4, - address5, - address6 - ]; + var addresses = [address2, address3, address4, address5, address6]; var options = {}; node.getAddressHistory(addresses, options, function(err, results) { if (err) { @@ -409,16 +400,10 @@ describe('Node Functionality', function() { }); it('five addresses (limited by height)', function(done) { - var addresses = [ - address2, - address3, - address4, - address5, - address6 - ]; + var addresses = [address2, address3, address4, address5, address6]; var options = { start: 158, - end: 157 + end: 157, }; node.getAddressHistory(addresses, options, function(err, results) { if (err) { @@ -436,16 +421,10 @@ describe('Node Functionality', function() { }); it('five addresses (limited by height 155 to 154)', function(done) { - var addresses = [ - address2, - address3, - address4, - address5, - address6 - ]; + var addresses = [address2, address3, address4, address5, address6]; var options = { start: 157, - end: 156 + end: 156, }; node.getAddressHistory(addresses, options, function(err, results) { if (err) { @@ -461,16 +440,10 @@ describe('Node Functionality', function() { }); it('five addresses (paginated by index)', function(done) { - var addresses = [ - address2, - address3, - address4, - address5, - address6 - ]; + var addresses = [address2, address3, address4, address5, address6]; var options = { from: 0, - to: 3 + to: 3, }; node.getAddressHistory(addresses, options, function(err, results) { if (err) { @@ -488,9 +461,7 @@ describe('Node Functionality', function() { }); it('one address with sending and receiving', function(done) { - var addresses = [ - address - ]; + var addresses = [address]; var options = {}; node.getAddressHistory(addresses, options, function(err, results) { if (err) { @@ -532,11 +503,8 @@ describe('Node Functionality', function() { }); }); - it('total transaction count (sending and receiving)', function(done) { - var addresses = [ - address - ]; + var addresses = [address]; var options = {}; node.getAddressHistory(addresses, options, function(err, results) { if (err) { @@ -551,7 +519,7 @@ describe('Node Functionality', function() { it('from 0 to 1', function(done) { var options = { from: 0, - to: 1 + to: 1, }; node.getAddressHistory(address, options, function(err, results) { if (err) { @@ -566,7 +534,7 @@ describe('Node Functionality', function() { it('from 1 to 2', function(done) { var options = { from: 1, - to: 2 + to: 2, }; node.getAddressHistory(address, options, function(err, results) { if (err) { @@ -581,7 +549,7 @@ describe('Node Functionality', function() { it('from 2 to 3', function(done) { var options = { from: 2, - to: 3 + to: 3, }; node.getAddressHistory(address, options, function(err, results) { if (err) { @@ -596,7 +564,7 @@ describe('Node Functionality', function() { it('from 3 to 4', function(done) { var options = { from: 3, - to: 4 + to: 4, }; node.getAddressHistory(address, options, function(err, results) { if (err) { @@ -611,7 +579,7 @@ describe('Node Functionality', function() { it('from 4 to 5', function(done) { var options = { from: 4, - to: 5 + to: 5, }; node.getAddressHistory(address, options, function(err, results) { if (err) { @@ -629,7 +597,7 @@ describe('Node Functionality', function() { it('from 5 to 6', function(done) { var options = { from: 5, - to: 6 + to: 6, }; node.getAddressHistory(address, options, function(err, results) { if (err) { @@ -642,7 +610,6 @@ describe('Node Functionality', function() { done(); }); }); - }); }); @@ -660,7 +627,10 @@ describe('Node Functionality', function() { }); it('will update the mempool index after new tx', function(done) { - var memAddress = meritcore.PrivateKey().toAddress(node.network).toString(); + var memAddress = meritcore + .PrivateKey() + .toAddress(node.network) + .toString(); var tx = new Transaction(); tx.from(unspentOutput); tx.to(memAddress, unspentOutput.micros - 1000); @@ -678,9 +648,7 @@ describe('Node Functionality', function() { }); }); }); - }); - }); describe('Orphaned Transactions', function() { @@ -691,52 +659,55 @@ describe('Node Functionality', function() { var count; var invalidatedBlockHash; - async.series([ - function(next) { - client.sendToAddress(testKey.toAddress(regtest).toString(), 10, function(err) { - if (err) { - return next(err); - } - client.generate(1, next); - }); - }, - function(next) { - client.getBlockCount(function(err, response) { - if (err) { - return next(err); - } - count = response.result; - next(); - }); - }, - function(next) { - client.getBlockHash(count, function(err, response) { - if (err) { - return next(err); - } - invalidatedBlockHash = response.result; - next(); - }); - }, - function(next) { - client.getBlock(invalidatedBlockHash, function(err, response) { - if (err) { - return next(err); - } - orphanedTransaction = response.result.tx[1]; - should.exist(orphanedTransaction); - next(); - }); + async.series( + [ + function(next) { + client.sendToAddress(testKey.toAddress(regtest).toString(), 10, function(err) { + if (err) { + return next(err); + } + client.generate(1, next); + }); + }, + function(next) { + client.getBlockCount(function(err, response) { + if (err) { + return next(err); + } + count = response.result; + next(); + }); + }, + function(next) { + client.getBlockHash(count, function(err, response) { + if (err) { + return next(err); + } + invalidatedBlockHash = response.result; + next(); + }); + }, + function(next) { + client.getBlock(invalidatedBlockHash, function(err, response) { + if (err) { + return next(err); + } + orphanedTransaction = response.result.tx[1]; + should.exist(orphanedTransaction); + next(); + }); + }, + function(next) { + client.invalidateBlock(invalidatedBlockHash, next); + }, + ], + function(err) { + if (err) { + throw err; + } + done(); }, - function(next) { - client.invalidateBlock(invalidatedBlockHash, next); - } - ], function(err) { - if (err) { - throw err; - } - done(); - }); + ); }); it('will not show confirmation count for orphaned transaction', function(done) { @@ -752,7 +723,5 @@ describe('Node Functionality', function() { done(); }); }); - }); - }); diff --git a/packages/merit-node/regtest/p2p.js b/packages/merit-node/regtest/p2p.js index 043dbe5deb..a32fdf83fa 100644 --- a/packages/merit-node/regtest/p2p.js +++ b/packages/merit-node/regtest/p2p.js @@ -35,7 +35,6 @@ var BufferUtil = meritcore.util.buffer; var blocks; describe('P2P Functionality', function() { - before(function(done) { this.timeout(100000); @@ -52,11 +51,11 @@ describe('P2P Functionality', function() { meritd = require('../').services.Merit({ spawn: { datadir: datadir, - exec: path.resolve(__dirname, '../bin/meritd') + exec: path.resolve(__dirname, '../bin/meritd'), }, node: { - network: meritcore.Networks.testnet - } + network: meritcore.Networks.testnet, + }, }); meritd.on('error', function(err) { @@ -77,17 +76,17 @@ describe('P2P Functionality', function() { port: 30331, user: 'merit', pass: 'local321', - rejectUnauthorized: false + rejectUnauthorized: false, }); peer = new Peer({ host: '127.0.0.1', port: '18444', - network: regtestNetwork + network: regtestNetwork, }); messages = new Messages({ - network: regtestNetwork + network: regtestNetwork, }); blocks = 500; @@ -110,53 +109,59 @@ describe('P2P Functionality', function() { client.listUnspent(0, blocks, function(err, response) { var utxos = response.result; - async.mapSeries(utxos, function(utxo, next) { - async.series([ - function(finished) { - // Load all of the transactions for later testing - client.getTransaction(utxo.txid, function(err, txresponse) { - if (err) { - throw err; - } - // add to the list of transactions for testing later - transactionData.push(txresponse.result.hex); - finished(); - }); - }, - function(finished) { - // Get the private key for each utxo - client.dumpPrivKey(utxo.address, function(err, privresponse) { - if (err) { - throw err; - } - utxo.privateKeyWIF = privresponse.result; - var tx = meritcore.Transaction(); - tx.from(utxo); - tx.change(privateKey.toAddress()); - tx.to(destKey.toAddress(), utxo.amount * 1e8 - 1000); - tx.sign(meritcore.PrivateKey.fromWIF(utxo.privateKeyWIF)); - txs.push(tx); - finished(); - }); + async.mapSeries( + utxos, + function(utxo, next) { + async.series( + [ + function(finished) { + // Load all of the transactions for later testing + client.getTransaction(utxo.txid, function(err, txresponse) { + if (err) { + throw err; + } + // add to the list of transactions for testing later + transactionData.push(txresponse.result.hex); + finished(); + }); + }, + function(finished) { + // Get the private key for each utxo + client.dumpPrivKey(utxo.address, function(err, privresponse) { + if (err) { + throw err; + } + utxo.privateKeyWIF = privresponse.result; + var tx = meritcore.Transaction(); + tx.from(utxo); + tx.change(privateKey.toAddress()); + tx.to(destKey.toAddress(), utxo.amount * 1e8 - 1000); + tx.sign(meritcore.PrivateKey.fromWIF(utxo.privateKeyWIF)); + txs.push(tx); + finished(); + }); + }, + ], + next, + ); + }, + function(err) { + if (err) { + throw err; } - ], next); - }, function(err) { - if (err) { - throw err; - } - peer.on('ready', function() { - log.info('Peer ready'); - done(); - }); - log.info('Connecting to peer'); - peer.connect(); - }); + peer.on('ready', function() { + log.info('Peer ready'); + done(); + }); + log.info('Connecting to peer'); + peer.connect(); + }, + ); }); }); }); }); }); - }); after(function(done) { @@ -211,7 +216,7 @@ describe('P2P Functionality', function() { if (err) { throw err; } - }); + }, + ); }); - }); diff --git a/packages/merit-node/test/bus.integration.js b/packages/merit-node/test/bus.integration.js index a482afe005..50d676f373 100644 --- a/packages/merit-node/test/bus.integration.js +++ b/packages/merit-node/test/bus.integration.js @@ -29,8 +29,8 @@ TestService.prototype.getPublishEvents = function() { name: 'test/testEvent', scope: this, subscribe: this.subscribe.bind(this, 'test/testEvent'), - unsubscribe: this.unsubscribe.bind(this, 'test/testEvent') - } + unsubscribe: this.unsubscribe.bind(this, 'test/testEvent'), + }, ]; }; @@ -42,7 +42,6 @@ TestService.prototype.unsubscribe = function(name, emitter) { emitter.emit('unsubscribe'); }; - describe('Bus Functionality', function() { var sandbox = sinon.sandbox.create(); beforeEach(function() { @@ -61,9 +60,9 @@ describe('Bus Functionality', function() { { name: 'testService', config: {}, - module: TestService - } - ] + module: TestService, + }, + ], }); node.start(function() { var bus = node.openBus(); @@ -85,9 +84,9 @@ describe('Bus Functionality', function() { { name: 'testService', config: {}, - module: TestService - } - ] + module: TestService, + }, + ], }); node.start(function() { var bus = node.openBus(); @@ -97,8 +96,6 @@ describe('Bus Functionality', function() { }); bus.subscribe('test/testEvent'); bus.unsubscribe('test/testEvent'); - }); - }); }); diff --git a/packages/merit-node/test/bus.unit.js b/packages/merit-node/test/bus.unit.js index 0b2bf298d6..7e74cd5b33 100644 --- a/packages/merit-node/test/bus.unit.js +++ b/packages/merit-node/test/bus.unit.js @@ -5,7 +5,6 @@ var sinon = require('sinon'); var Bus = require('../lib/bus'); describe('Bus', function() { - describe('#subscribe', function() { it('will call db and services subscribe function with the correct arguments', function() { var subscribeDb = sinon.spy(); @@ -17,9 +16,9 @@ describe('Bus', function() { { name: 'dbtest', scope: this, - subscribe: subscribeDb - } - ]) + subscribe: subscribeDb, + }, + ]), }, service1: { getPublishEvents: sinon.stub().returns([ @@ -27,12 +26,12 @@ describe('Bus', function() { name: 'test', scope: this, subscribe: subscribeService, - } - ]) - } - } + }, + ]), + }, + }, }; - var bus = new Bus({node: node}); + var bus = new Bus({ node: node }); bus.subscribe('dbtest', 'a', 'b', 'c'); bus.subscribe('test', 'a', 'b', 'c'); subscribeService.callCount.should.equal(1); @@ -59,9 +58,9 @@ describe('Bus', function() { { name: 'dbtest', scope: this, - unsubscribe: unsubscribeDb - } - ]) + unsubscribe: unsubscribeDb, + }, + ]), }, service1: { getPublishEvents: sinon.stub().returns([ @@ -69,12 +68,12 @@ describe('Bus', function() { name: 'test', scope: this, unsubscribe: unsubscribeService, - } - ]) - } - } + }, + ]), + }, + }, }; - var bus = new Bus({node: node}); + var bus = new Bus({ node: node }); bus.unsubscribe('dbtest', 'a', 'b', 'c'); bus.unsubscribe('test', 'a', 'b', 'c'); unsubscribeService.callCount.should.equal(1); @@ -101,22 +100,22 @@ describe('Bus', function() { { name: 'dbtest', scope: this, - unsubscribe: unsubscribeDb - } - ]) + unsubscribe: unsubscribeDb, + }, + ]), }, service1: { getPublishEvents: sinon.stub().returns([ { name: 'test', scope: this, - unsubscribe: unsubscribeService - } - ]) - } - } + unsubscribe: unsubscribeService, + }, + ]), + }, + }, }; - var bus = new Bus({node: node}); + var bus = new Bus({ node: node }); bus.close(); unsubscribeDb.callCount.should.equal(1); @@ -127,5 +126,4 @@ describe('Bus', function() { unsubscribeService.args[0][0].should.equal(bus); }); }); - }); diff --git a/packages/merit-node/test/logger.unit.js b/packages/merit-node/test/logger.unit.js index 755228145f..e68ee31769 100644 --- a/packages/merit-node/test/logger.unit.js +++ b/packages/merit-node/test/logger.unit.js @@ -19,17 +19,17 @@ describe('Logger', function() { it('will instatiate with formatting option', function() { var logger = new Logger({ - formatting: false + formatting: false, }); logger.formatting.should.equal(false); var logger2 = new Logger({ - formatting: true + formatting: true, }); logger2.formatting.should.equal(true); }); it('will log with formatting', function() { - var logger = new Logger({formatting: true}); + var logger = new Logger({ formatting: true }); sandbox.stub(console, 'info'); logger.info('Test info log'); @@ -53,7 +53,7 @@ describe('Logger', function() { }); it('will log without formatting', function() { - var logger = new Logger({formatting: false}); + var logger = new Logger({ formatting: false }); sandbox.stub(console, 'info'); logger.info('Test info log'); @@ -79,5 +79,4 @@ describe('Logger', function() { should.equal(console.warn.args[0][0].match(/^\[/), null); console.warn.restore(); }); - }); diff --git a/packages/merit-node/test/node.unit.js b/packages/merit-node/test/node.unit.js index f0835b78b4..718bdbf862 100644 --- a/packages/merit-node/test/node.unit.js +++ b/packages/merit-node/test/node.unit.js @@ -11,7 +11,6 @@ var index = require('../lib'); var log = index.log; describe('Merit Node', function() { - var baseConfig = {}; var Node; @@ -37,8 +36,8 @@ describe('Merit Node', function() { services: [ { name: 'test1', - module: TestService - } + module: TestService, + }, ], }; var TestNode = proxyquire('../lib/node', {}); @@ -60,8 +59,8 @@ describe('Merit Node', function() { services: [ { name: 'test1', - module: TestService - } + module: TestService, + }, ], }; var TestNode = proxyquire('../lib/node', {}); @@ -75,8 +74,8 @@ describe('Merit Node', function() { services: [ { name: 'test1', - module: TestService - } + module: TestService, + }, ], }; var TestNode = proxyquire('../lib/node', {}); @@ -92,10 +91,10 @@ describe('Merit Node', function() { services: [ { name: 'test1', - module: TestService - } + module: TestService, + }, ], - formatLogs: false + formatLogs: false, }; var TestNode = proxyquire('../lib/node', {}); var node = new TestNode(config); @@ -116,7 +115,7 @@ describe('Merit Node', function() { }); it('will use remoteAddress config option', function() { var node = new Node(baseConfig); - var bus = node.openBus({remoteAddress: '127.0.0.1'}); + var bus = node.openBus({ remoteAddress: '127.0.0.1' }); bus.remoteAddress.should.equal('127.0.0.1'); }); }); @@ -129,11 +128,11 @@ describe('Merit Node', function() { getAPIMethods: sinon.stub().returns(['db1', 'db2']), }, service1: { - getAPIMethods: sinon.stub().returns(['mda1', 'mda2']) + getAPIMethods: sinon.stub().returns(['mda1', 'mda2']), }, service2: { - getAPIMethods: sinon.stub().returns(['mdb1', 'mdb2']) - } + getAPIMethods: sinon.stub().returns(['mdb1', 'mdb2']), + }, }; var methods = node.getAllAPIMethods(); @@ -147,8 +146,8 @@ describe('Merit Node', function() { }, service1: {}, service2: { - getAPIMethods: sinon.stub().returns(['mdb1', 'mdb2']) - } + getAPIMethods: sinon.stub().returns(['mdb1', 'mdb2']), + }, }; var methods = node.getAllAPIMethods(); @@ -164,11 +163,11 @@ describe('Merit Node', function() { getPublishEvents: sinon.stub().returns(['db1', 'db2']), }, service1: { - getPublishEvents: sinon.stub().returns(['mda1', 'mda2']) + getPublishEvents: sinon.stub().returns(['mda1', 'mda2']), }, service2: { - getPublishEvents: sinon.stub().returns(['mdb1', 'mdb2']) - } + getPublishEvents: sinon.stub().returns(['mdb1', 'mdb2']), + }, }; var events = node.getAllPublishEvents(); events.should.deep.equal(['db1', 'db2', 'mda1', 'mda2', 'mdb1', 'mdb2']); @@ -181,8 +180,8 @@ describe('Merit Node', function() { }, service1: {}, service2: { - getPublishEvents: sinon.stub().returns(['mdb1', 'mdb2']) - } + getPublishEvents: sinon.stub().returns(['mdb1', 'mdb2']), + }, }; var events = node.getAllPublishEvents(); events.should.deep.equal(['db1', 'db2', 'mdb1', 'mdb2']); @@ -196,27 +195,27 @@ describe('Merit Node', function() { { name: 'chain', module: { - dependencies: ['db'] - } + dependencies: ['db'], + }, }, { name: 'db', module: { - dependencies: ['daemon', 'p2p'] - } + dependencies: ['daemon', 'p2p'], + }, }, { - name:'daemon', + name: 'daemon', module: { - dependencies: [] - } + dependencies: [], + }, }, { name: 'p2p', module: { - dependencies: [] - } - } + dependencies: [], + }, + }, ]; var order = node.getServiceOrder(); order[0].name.should.equal('daemon'); @@ -242,14 +241,12 @@ describe('Merit Node', function() { var getData = sinon.stub(); TestService.prototype.getData = getData; TestService.prototype.getAPIMethods = function() { - return [ - ['getData', this, this.getData, 1] - ]; + return [['getData', this, this.getData, 1]]; }; var service = { name: 'testservice', module: TestService, - config: {} + config: {}, }; node._startService(service, function(err) { if (err) { @@ -270,9 +267,7 @@ describe('Merit Node', function() { var getData = sinon.stub(); TestService.prototype.getData = getData; TestService.prototype.getAPIMethods = function() { - return [ - ['getData', this, this.getData, 1] - ]; + return [['getData', this, this.getData, 1]]; }; var service = { name: 'testservice', @@ -297,7 +292,7 @@ describe('Merit Node', function() { var service = { name: 'testservice', module: TestService, - config: {} + config: {}, }; node._startService(service, function(err) { err.message.should.equal('test'); @@ -321,9 +316,7 @@ describe('Merit Node', function() { TestService.prototype.start = sinon.stub().callsArg(0); TestService.prototype.getData = function() {}; TestService.prototype.getAPIMethods = function() { - return [ - ['getData', this, this.getData, 1] - ]; + return [['getData', this, this.getData, 1]]; }; function TestService2() {} @@ -331,22 +324,20 @@ describe('Merit Node', function() { TestService2.prototype.start = sinon.stub().callsArg(0); TestService2.prototype.getData2 = function() {}; TestService2.prototype.getAPIMethods = function() { - return [ - ['getData2', this, this.getData2, 1] - ]; + return [['getData2', this, this.getData2, 1]]; }; node.getServiceOrder = sinon.stub().returns([ { name: 'test1', module: TestService, - config: {} + config: {}, }, { name: 'test2', module: TestService2, - config: {} - } + config: {}, + }, ]); node.start(function() { TestService2.prototype.start.callCount.should.equal(1); @@ -364,9 +355,7 @@ describe('Merit Node', function() { TestService.prototype.start = sinon.stub().callsArg(0); TestService.prototype.getData = function() {}; TestService.prototype.getAPIMethods = function() { - return [ - ['getData', this, this.getData, 1] - ]; + return [['getData', this, this.getData, 1]]; }; function ConflictService() {} @@ -374,22 +363,20 @@ describe('Merit Node', function() { ConflictService.prototype.start = sinon.stub().callsArg(0); ConflictService.prototype.getData = function() {}; ConflictService.prototype.getAPIMethods = function() { - return [ - ['getData', this, this.getData, 1] - ]; + return [['getData', this, this.getData, 1]]; }; node.getServiceOrder = sinon.stub().returns([ { name: 'test', module: TestService, - config: {} + config: {}, }, { name: 'conflict', module: ConflictService, - config: {} - } + config: {}, + }, ]); node.start(function(err) { @@ -397,7 +384,6 @@ describe('Merit Node', function() { err.message.should.match(/^Existing API method\(s\) exists\:/); done(); }); - }); it('will handle service with getAPIMethods undefined', function(done) { var node = new Node(baseConfig); @@ -411,7 +397,7 @@ describe('Merit Node', function() { { name: 'test', module: TestService, - config: {} + config: {}, }, ]); @@ -419,7 +405,6 @@ describe('Merit Node', function() { TestService.prototype.start.callCount.should.equal(1); done(); }); - }); }); @@ -433,14 +418,14 @@ describe('Merit Node', function() { }); it('it will return the network name for testnet', function() { var baseConfig = { - network: 'testnet' + network: 'testnet', }; var node = new Node(baseConfig); node.getNetworkName().should.equal('testnet'); }); it('it will return the network for regtest', function() { var baseConfig = { - network: 'regtest' + network: 'regtest', }; var node = new Node(baseConfig); node.getNetworkName().should.equal('regtest'); @@ -462,20 +447,18 @@ describe('Merit Node', function() { TestService.prototype.stop = sinon.stub().callsArg(0); TestService.prototype.getData = function() {}; TestService.prototype.getAPIMethods = function() { - return [ - ['getData', this, this.getData, 1] - ]; + return [['getData', this, this.getData, 1]]; }; node.services = { - 'test1': new TestService({node: node}) + test1: new TestService({ node: node }), }; node.test2 = {}; node.test2.stop = sinon.stub().callsArg(0); node.getServiceOrder = sinon.stub().returns([ { name: 'test1', - module: TestService - } + module: TestService, + }, ]); node.stop(function() { TestService.prototype.stop.callCount.should.equal(1); diff --git a/packages/merit-node/test/scaffold/add.integration.js b/packages/merit-node/test/scaffold/add.integration.js index dc609deee2..7b674bb04d 100644 --- a/packages/merit-node/test/scaffold/add.integration.js +++ b/packages/merit-node/test/scaffold/add.integration.js @@ -10,12 +10,11 @@ var rimraf = require('rimraf'); var add = require('../../lib/scaffold/add'); describe('#add', function() { - var basePath = path.resolve(__dirname, '..'); var testDir = path.resolve(basePath, 'temporary-test-data'); var startConfig = { name: 'My Node', - services: [] + services: [], }; var startPackage = {}; @@ -24,20 +23,12 @@ describe('#add', function() { if (err) { throw err; } - fs.writeFile( - testDir + '/s0/s1/merit-node.json', - JSON.stringify(startConfig), - function(err) { - if (err) { - throw err; - } - fs.writeFile( - testDir + '/s0/s1/package.json', - JSON.stringify(startPackage), - done - ); + fs.writeFile(testDir + '/s0/s1/merit-node.json', JSON.stringify(startConfig), function(err) { + if (err) { + throw err; } - ); + fs.writeFile(testDir + '/s0/s1/package.json', JSON.stringify(startPackage), done); + }); }); }); @@ -52,42 +43,47 @@ describe('#add', function() { }); describe('will modify scaffold files', function() { - it('will give an error if expected files do not exist', function(done) { - add({ - path: path.resolve(testDir, 's0'), - services: ['a', 'b', 'c'] - }, function(err) { - should.exist(err); - err.message.match(/^Invalid state/); - done(); - }); + add( + { + path: path.resolve(testDir, 's0'), + services: ['a', 'b', 'c'], + }, + function(err) { + should.exist(err); + err.message.match(/^Invalid state/); + done(); + }, + ); }); it('will receive error from `npm install`', function(done) { var spawn = sinon.stub().returns({ stdout: { - on: sinon.stub() + on: sinon.stub(), }, stderr: { - on: sinon.stub() + on: sinon.stub(), }, - on: sinon.stub().callsArgWith(1, 1) + on: sinon.stub().callsArgWith(1, 1), }); var addtest = proxyquire('../../lib/scaffold/add', { - 'child_process': { - spawn: spawn - } + child_process: { + spawn: spawn, + }, }); - addtest({ - path: path.resolve(testDir, 's0/s1/'), - services: ['a', 'b', 'c'] - }, function(err) { - should.exist(err); - err.message.should.equal('There was an error installing service: a'); - done(); - }); + addtest( + { + path: path.resolve(testDir, 's0/s1/'), + services: ['a', 'b', 'c'], + }, + function(err) { + should.exist(err); + err.message.should.equal('There was an error installing service: a'); + done(); + }, + ); }); it('will update merit-node.json services', function(done) { @@ -95,48 +91,49 @@ describe('#add', function() { var oldPackage = { dependencies: { 'meritcore-lib': '^v0.13.7', - 'merit-node': '^v0.2.0' - } + 'merit-node': '^v0.2.0', + }, }; var spawn = sinon.stub().returns({ stdout: { - on: sinon.stub() + on: sinon.stub(), }, stderr: { - on: sinon.stub() + on: sinon.stub(), }, - on: sinon.stub().callsArgWith(1, 0) + on: sinon.stub().callsArgWith(1, 0), }); var addtest = proxyquire('../../lib/scaffold/add', { - 'child_process': { - spawn: spawn + child_process: { + spawn: spawn, }, - 'fs': { + fs: { readFileSync: function() { - if (callCount === 1){ + if (callCount === 1) { oldPackage.dependencies.a = '^v0.1'; - } else if (callCount === 2){ + } else if (callCount === 2) { oldPackage.dependencies.b = '^v0.1'; - } else if (callCount === 3){ + } else if (callCount === 3) { oldPackage.dependencies.c = '^v0.1'; } callCount++; return JSON.stringify(oldPackage); - } - } - }); - addtest({ - path: path.resolve(testDir, 's0/s1/'), - services: ['a', 'b', 'c'] - }, function(err) { - should.not.exist(err); - var configPath = path.resolve(testDir, 's0/s1/merit-node.json'); - var config = JSON.parse(fs.readFileSync(configPath)); - config.services.should.deep.equal(['a','b','c']); - done(); + }, + }, }); + addtest( + { + path: path.resolve(testDir, 's0/s1/'), + services: ['a', 'b', 'c'], + }, + function(err) { + should.not.exist(err); + var configPath = path.resolve(testDir, 's0/s1/merit-node.json'); + var config = JSON.parse(fs.readFileSync(configPath)); + config.services.should.deep.equal(['a', 'b', 'c']); + done(); + }, + ); }); - }); - }); diff --git a/packages/merit-node/test/scaffold/call-method.unit.js b/packages/merit-node/test/scaffold/call-method.unit.js index cf2291bea3..51c0fd82e9 100644 --- a/packages/merit-node/test/scaffold/call-method.unit.js +++ b/packages/merit-node/test/scaffold/call-method.unit.js @@ -6,17 +6,16 @@ var proxyquire = require('proxyquire'); var EventEmitter = require('events').EventEmitter; describe('#callMethod', function() { - var expectedUrl = 'http://localhost:3001'; var expectedOptions = { reconnection: false, - connect_timeout: 5000 + connect_timeout: 5000, }; var callOptions = { host: 'localhost', port: 3001, - protocol: 'http' + protocol: 'http', }; var callMethod; @@ -27,7 +26,7 @@ describe('#callMethod', function() { url.should.equal(expectedUrl); options.should.deep.equal(expectedOptions); return new EventEmitter(); - } + }, }); }); @@ -51,8 +50,8 @@ describe('#callMethod', function() { should.equal(opts.params, null); var response = { error: { - message: 'response' - } + message: 'response', + }, }; callback(response); }; @@ -69,7 +68,7 @@ describe('#callMethod', function() { difficulty: 112628548.66634709, testnet: false, relayfee: 1000, - errors: '' + errors: '', }; var socket = callMethod(callOptions, 'getInfo', null, function(err, data) { should.not.exist(err); @@ -83,11 +82,10 @@ describe('#callMethod', function() { should.equal(opts.params, null); var response = { error: null, - result: expectedData + result: expectedData, }; callback(response); }; socket.emit('connect'); }); - }); diff --git a/packages/merit-node/test/scaffold/create.integration.js b/packages/merit-node/test/scaffold/create.integration.js index c4ec60e2aa..87edce5c4b 100644 --- a/packages/merit-node/test/scaffold/create.integration.js +++ b/packages/merit-node/test/scaffold/create.integration.js @@ -4,26 +4,25 @@ var should = require('chai').should(); var proxyquire = require('proxyquire'); var sinon = require('sinon'); var create = proxyquire('../../lib/scaffold/create', { - 'child_process': { + child_process: { spawn: sinon.stub().returns({ stdout: { - on: sinon.stub() + on: sinon.stub(), }, stderr: { - on: sinon.stub() + on: sinon.stub(), }, on: function(event, cb) { cb(0); - } - }) - } + }, + }), + }, }); var fs = require('fs'); var mkdirp = require('mkdirp'); var rimraf = require('rimraf'); describe('#create', function() { - var basePath = __dirname + '/../'; var testDir = basePath + 'temporary-test-data'; @@ -53,98 +52,101 @@ describe('#create', function() { }); it('will create scaffold files', function() { - create({ - cwd: testDir, - dirname: 'mynode', - name: 'My Node 1', - isGlobal: false, - datadir: './data' - }, function(err) { - if (err) { - throw err; - } - - var configPath = testDir + '/mynode/merit-node.json'; - var packagePath = testDir + '/mynode/package.json'; - - should.equal(fs.existsSync(configPath), true); - should.equal(fs.existsSync(packagePath), true); + create( + { + cwd: testDir, + dirname: 'mynode', + name: 'My Node 1', + isGlobal: false, + datadir: './data', + }, + function(err) { + if (err) { + throw err; + } - var config = JSON.parse(fs.readFileSync(configPath)); - config.services.should.deep.equal(['meritd', 'db', 'address', 'web']); - config.datadir.should.equal('./data'); - config.network.should.equal('livenet'); + var configPath = testDir + '/mynode/merit-node.json'; + var packagePath = testDir + '/mynode/package.json'; - var pack = JSON.parse(fs.readFileSync(packagePath)); - should.exist(pack.dependencies); + should.equal(fs.existsSync(configPath), true); + should.equal(fs.existsSync(packagePath), true); - }); + var config = JSON.parse(fs.readFileSync(configPath)); + config.services.should.deep.equal(['meritd', 'db', 'address', 'web']); + config.datadir.should.equal('./data'); + config.network.should.equal('livenet'); + var pack = JSON.parse(fs.readFileSync(packagePath)); + should.exist(pack.dependencies); + }, + ); }); it('will error if directory already exists', function() { - - create({ - cwd: testDir, - dirname: 'mynode', - name: 'My Node 2', - isGlobal: false, - datadir: './data' - }, function(err) { - should.exist(err); - err.message.should.match(/^Directory/); - }); - + create( + { + cwd: testDir, + dirname: 'mynode', + name: 'My Node 2', + isGlobal: false, + datadir: './data', + }, + function(err) { + should.exist(err); + err.message.should.match(/^Directory/); + }, + ); }); it('will not create a package.json if globally installed', function() { + create( + { + cwd: testDir, + dirname: 'mynode3', + name: 'My Node 3', + isGlobal: true, + datadir: '../.merit', + }, + function(err) { + if (err) { + throw err; + } - create({ - cwd: testDir, - dirname: 'mynode3', - name: 'My Node 3', - isGlobal: true, - datadir: '../.merit' - }, function(err) { - if (err) { - throw err; - } - - var packagePath = testDir + '/mynode3/package.json'; - should.equal(fs.existsSync(packagePath), false); - - }); - + var packagePath = testDir + '/mynode3/package.json'; + should.equal(fs.existsSync(packagePath), false); + }, + ); }); it('will receieve an error from npm', function() { var createtest = proxyquire('../../lib/scaffold/create', { - 'child_process': { + child_process: { spawn: sinon.stub().returns({ stdout: { - on: sinon.stub() + on: sinon.stub(), }, stderr: { - on: sinon.stub() + on: sinon.stub(), }, on: function(event, cb) { cb(1); - } - }) - } - }); - - createtest({ - cwd: testDir, - dirname: 'mynode4', - name: 'My Node 4', - isGlobal: false, - datadir: '../.merit' - }, function(err) { - should.exist(err); - err.message.should.equal('There was an error installing dependencies.'); + }, + }), + }, }); + createtest( + { + cwd: testDir, + dirname: 'mynode4', + name: 'My Node 4', + isGlobal: false, + datadir: '../.merit', + }, + function(err) { + should.exist(err); + err.message.should.equal('There was an error installing dependencies.'); + }, + ); }); - }); diff --git a/packages/merit-node/test/scaffold/default-base-config.integration.js b/packages/merit-node/test/scaffold/default-base-config.integration.js index 3439a3d65f..5a336456d3 100644 --- a/packages/merit-node/test/scaffold/default-base-config.integration.js +++ b/packages/merit-node/test/scaffold/default-base-config.integration.js @@ -18,11 +18,11 @@ describe('#defaultBaseConfig', function() { meritd.spawn.exec.should.equal(path.resolve(__dirname, '../../bin/meritd')); }); it('be able to specify a network', function() { - var info = defaultBaseConfig({network: 'testnet'}); + var info = defaultBaseConfig({ network: 'testnet' }); info.config.network.should.equal('testnet'); }); it('be able to specify a datadir', function() { - var info = defaultBaseConfig({datadir: './data2', network: 'testnet'}); + var info = defaultBaseConfig({ datadir: './data2', network: 'testnet' }); info.config.servicesConfig.meritd.spawn.datadir.should.equal('./data2'); }); }); diff --git a/packages/merit-node/test/scaffold/default-config.integration.js b/packages/merit-node/test/scaffold/default-config.integration.js index a751ff96e8..2bb2c02124 100644 --- a/packages/merit-node/test/scaffold/default-config.integration.js +++ b/packages/merit-node/test/scaffold/default-config.integration.js @@ -9,22 +9,23 @@ describe('#defaultConfig', function() { var expectedExecPath = path.resolve(__dirname, '../../bin/meritd'); it('will return expected configuration', function() { - var config = JSON.stringify({ - network: 'livenet', - port: 3001, - services: [ - 'meritd', - 'web' - ], - servicesConfig: { - meritd: { - spawn: { - datadir: process.env.HOME + '/.meritcore/data', - exec: expectedExecPath - } - } - } - }, null, 2); + var config = JSON.stringify( + { + network: 'livenet', + port: 3001, + services: ['meritd', 'web'], + servicesConfig: { + meritd: { + spawn: { + datadir: process.env.HOME + '/.meritcore/data', + exec: expectedExecPath, + }, + }, + }, + }, + null, + 2, + ); var defaultConfig = proxyquire('../../lib/scaffold/default-config', { fs: { existsSync: sinon.stub().returns(false), @@ -34,11 +35,11 @@ describe('#defaultConfig', function() { }, readFileSync: function() { return config; - } + }, }, mkdirp: { - sync: sinon.stub() - } + sync: sinon.stub(), + }, }); var home = process.env.HOME; var info = defaultConfig(); @@ -52,24 +53,23 @@ describe('#defaultConfig', function() { meritd.spawn.exec.should.equal(expectedExecPath); }); it('will include additional services', function() { - var config = JSON.stringify({ - network: 'livenet', - port: 3001, - services: [ - 'meritd', - 'web', - 'insight-api', - 'insight-ui' - ], - servicesConfig: { - meritd: { - spawn: { - datadir: process.env.HOME + '/.meritcore/data', - exec: expectedExecPath - } - } - } - }, null, 2); + var config = JSON.stringify( + { + network: 'livenet', + port: 3001, + services: ['meritd', 'web', 'insight-api', 'insight-ui'], + servicesConfig: { + meritd: { + spawn: { + datadir: process.env.HOME + '/.meritcore/data', + exec: expectedExecPath, + }, + }, + }, + }, + null, + 2, + ); var defaultConfig = proxyquire('../../lib/scaffold/default-config', { fs: { existsSync: sinon.stub().returns(false), @@ -79,25 +79,20 @@ describe('#defaultConfig', function() { }, readFileSync: function() { return config; - } + }, }, mkdirp: { - sync: sinon.stub() - } + sync: sinon.stub(), + }, }); var home = process.env.HOME; var info = defaultConfig({ - additionalServices: ['insight-api', 'insight-ui'] + additionalServices: ['insight-api', 'insight-ui'], }); info.path.should.equal(home + '/.meritcore'); info.config.network.should.equal('livenet'); info.config.port.should.equal(3001); - info.config.services.should.deep.equal([ - 'meritd', - 'web', - 'insight-api', - 'insight-ui' - ]); + info.config.services.should.deep.equal(['meritd', 'web', 'insight-api', 'insight-ui']); var meritd = info.config.servicesConfig.meritd; should.exist(meritd); meritd.spawn.datadir.should.equal(home + '/.meritcore/data'); diff --git a/packages/merit-node/test/scaffold/find-config.integration.js b/packages/merit-node/test/scaffold/find-config.integration.js index 6dd1d17115..7ca7b71151 100644 --- a/packages/merit-node/test/scaffold/find-config.integration.js +++ b/packages/merit-node/test/scaffold/find-config.integration.js @@ -10,10 +10,9 @@ var rimraf = require('rimraf'); var findConfig = require('../../lib/scaffold/find-config'); describe('#findConfig', function() { - var testDir = path.resolve(__dirname, '../temporary-test-data'); var expectedConfig = { - name: 'My Node' + name: 'My Node', }; before(function(done) { @@ -22,20 +21,15 @@ describe('#findConfig', function() { if (err) { throw err; } - fs.writeFile( - testDir + '/p2/merit-node.json', - JSON.stringify(expectedConfig), - function() { - mkdirp(testDir + '/e0', function(err) { - if (err) { - throw err; - } - done(); - }); - } - ); + fs.writeFile(testDir + '/p2/merit-node.json', JSON.stringify(expectedConfig), function() { + mkdirp(testDir + '/e0', function(err) { + if (err) { + throw err; + } + done(); + }); + }); }); - }); after(function(done) { @@ -48,9 +42,7 @@ describe('#findConfig', function() { }); }); - describe('will find a configuration file', function() { - it('in the current directory', function() { var config = findConfig(path.resolve(testDir, 'p2')); config.path.should.equal(path.resolve(testDir, 'p2')); @@ -58,17 +50,16 @@ describe('#findConfig', function() { }); it('in a parent directory', function() { - var config = findConfig(path.resolve(testDir, 'p2/p1')); + var config = findConfig(path.resolve(testDir, 'p2/p1')); config.path.should.equal(path.resolve(testDir, 'p2')); config.config.should.deep.equal(expectedConfig); }); it('recursively find in parent directories', function() { - var config = findConfig(path.resolve(testDir, 'p2/p1/p0')); + var config = findConfig(path.resolve(testDir, 'p2/p1/p0')); config.path.should.equal(path.resolve(testDir, 'p2')); config.config.should.deep.equal(expectedConfig); }); - }); // skip this one as we have merit-node.json in project root @@ -76,5 +67,4 @@ describe('#findConfig', function() { // var config = findConfig(path.resolve(testDir, 'e0')); // config.should.equal(false); // }); - }); diff --git a/packages/merit-node/test/scaffold/remove.integration.js b/packages/merit-node/test/scaffold/remove.integration.js index 46125ee8df..ada9485f6b 100644 --- a/packages/merit-node/test/scaffold/remove.integration.js +++ b/packages/merit-node/test/scaffold/remove.integration.js @@ -10,12 +10,11 @@ var rimraf = require('rimraf'); var remove = require('../../lib/scaffold/remove'); describe('#remove', function() { - var basePath = path.resolve(__dirname, '..'); var testDir = path.resolve(basePath, 'temporary-test-data'); var startConfig = { name: 'My Node', - services: ['a', 'b', 'c'] + services: ['a', 'b', 'c'], }; var startPackage = {}; @@ -24,20 +23,12 @@ describe('#remove', function() { if (err) { throw err; } - fs.writeFile( - testDir + '/s0/s1/merit-node.json', - JSON.stringify(startConfig), - function(err) { - if (err) { - throw err; - } - fs.writeFile( - testDir + '/s0/s1/package.json', - JSON.stringify(startPackage), - done - ); + fs.writeFile(testDir + '/s0/s1/merit-node.json', JSON.stringify(startConfig), function(err) { + if (err) { + throw err; } - ); + fs.writeFile(testDir + '/s0/s1/package.json', JSON.stringify(startPackage), done); + }); }); }); @@ -52,87 +43,103 @@ describe('#remove', function() { }); describe('will modify scaffold files', function() { - it('will give an error if expected files do not exist', function(done) { - remove({ - path: path.resolve(testDir, 's0'), - services: ['b'] - }, function(err) { - should.exist(err); - err.message.match(/^Invalid state/); - done(); - }); + remove( + { + path: path.resolve(testDir, 's0'), + services: ['b'], + }, + function(err) { + should.exist(err); + err.message.match(/^Invalid state/); + done(); + }, + ); }); it('will update merit-node.json services', function(done) { var spawn = sinon.stub().returns({ stdout: { - on: sinon.stub() + on: sinon.stub(), }, stderr: { - on: sinon.stub() + on: sinon.stub(), }, - on: sinon.stub().callsArgWith(1, 0) + on: sinon.stub().callsArgWith(1, 0), }); var removetest = proxyquire('../../lib/scaffold/remove', { - 'child_process': { - spawn: spawn + child_process: { + spawn: spawn, }, - 'npm': { + npm: { load: sinon.stub().callsArg(0), commands: { - ls: sinon.stub().callsArgWith(2, null, {}, { - dependencies: {} - }) - } - } - }); - removetest({ - path: path.resolve(testDir, 's0/s1/'), - services: ['b'] - }, function(err) { - should.not.exist(err); - var configPath = path.resolve(testDir, 's0/s1/merit-node.json'); - var config = JSON.parse(fs.readFileSync(configPath)); - config.services.should.deep.equal(['a', 'c']); - done(); + ls: sinon.stub().callsArgWith( + 2, + null, + {}, + { + dependencies: {}, + }, + ), + }, + }, }); + removetest( + { + path: path.resolve(testDir, 's0/s1/'), + services: ['b'], + }, + function(err) { + should.not.exist(err); + var configPath = path.resolve(testDir, 's0/s1/merit-node.json'); + var config = JSON.parse(fs.readFileSync(configPath)); + config.services.should.deep.equal(['a', 'c']); + done(); + }, + ); }); it('will receive error from `npm uninstall`', function(done) { var spawn = sinon.stub().returns({ stdout: { - on: sinon.stub() + on: sinon.stub(), }, stderr: { - on: sinon.stub() + on: sinon.stub(), }, - on: sinon.stub().callsArgWith(1, 1) + on: sinon.stub().callsArgWith(1, 1), }); var removetest = proxyquire('../../lib/scaffold/remove', { - 'child_process': { - spawn: spawn + child_process: { + spawn: spawn, }, - 'npm': { + npm: { load: sinon.stub().callsArg(0), commands: { - ls: sinon.stub().callsArgWith(2, null, {}, { - dependencies: {} - }) - } - } + ls: sinon.stub().callsArgWith( + 2, + null, + {}, + { + dependencies: {}, + }, + ), + }, + }, }); - removetest({ - path: path.resolve(testDir, 's0/s1/'), - services: ['b'] - }, function(err) { - should.exist(err); - err.message.should.equal('There was an error uninstalling service(s): b'); - done(); - }); + removetest( + { + path: path.resolve(testDir, 's0/s1/'), + services: ['b'], + }, + function(err) { + should.exist(err); + err.message.should.equal('There was an error uninstalling service(s): b'); + done(); + }, + ); }); - }); - }); diff --git a/packages/merit-node/test/scaffold/start.integration.js b/packages/merit-node/test/scaffold/start.integration.js index f1ebe3dc51..95a1966bfa 100644 --- a/packages/merit-node/test/scaffold/start.integration.js +++ b/packages/merit-node/test/scaffold/start.integration.js @@ -8,7 +8,6 @@ var index = require('../../lib'); var log = index.log; describe('#start', function() { - var sandbox = sinon.sandbox.create(); beforeEach(function() { sandbox.stub(log, 'error'); @@ -18,7 +17,6 @@ describe('#start', function() { }); describe('will dynamically create a node from a configuration', function() { - it('require each merit-node service with default config', function(done) { var node; var TestNode = function(options) { @@ -27,19 +25,19 @@ describe('#start', function() { module: MeritService, config: { spawn: { - datadir: './data' - } - } + datadir: './data', + }, + }, }); }; TestNode.prototype.start = sinon.stub().callsArg(0); TestNode.prototype.on = sinon.stub(); TestNode.prototype.chain = { - on: sinon.stub() + on: sinon.stub(), }; var starttest = proxyquire('../../lib/scaffold/start', { - '../node': TestNode + '../node': TestNode, }); starttest.registerExitHandlers = sinon.stub(); @@ -47,17 +45,15 @@ describe('#start', function() { node = starttest({ path: __dirname, config: { - services: [ - 'meritd' - ], + services: ['meritd'], servicesConfig: { meritd: { spawn: { - datadir: './data' - } - } - } - } + datadir: './data', + }, + }, + }, + }, }); node.should.be.instanceof(TestNode); done(); @@ -70,7 +66,7 @@ describe('#start', function() { }); }; var starttest = proxyquire('../../lib/scaffold/start', { - '../node': TestNode + '../node': TestNode, }); starttest.cleanShutdown = sinon.stub(); starttest.registerExitHandlers = sinon.stub(); @@ -79,8 +75,8 @@ describe('#start', function() { path: __dirname, config: { services: [], - servicesConfig: {} - } + servicesConfig: {}, + }, }); setImmediate(function() { starttest.cleanShutdown.callCount.should.equal(1); @@ -96,38 +92,35 @@ describe('#start', function() { config: { param: 'test', spawn: { - datadir: './data' - } - } + datadir: './data', + }, + }, }); }; TestNode.prototype.start = sinon.stub().callsArg(0); TestNode.prototype.on = sinon.stub(); TestNode.prototype.chain = { - on: sinon.stub() + on: sinon.stub(), }; var starttest = proxyquire('../../lib/scaffold/start', { - '../node': TestNode + '../node': TestNode, }); starttest.registerExitHandlers = sinon.stub(); node = starttest({ path: __dirname, config: { - services: [ - 'meritd' - ], + services: ['meritd'], servicesConfig: { - 'meritd': { + meritd: { param: 'test', spawn: { - datadir: './data' - } - } + datadir: './data', + }, + }, }, - - } + }, }); node.should.be.instanceof(TestNode); done(); diff --git a/packages/merit-node/test/scaffold/start.unit.js b/packages/merit-node/test/scaffold/start.unit.js index 6e9064e3ed..c71cdbc963 100644 --- a/packages/merit-node/test/scaffold/start.unit.js +++ b/packages/merit-node/test/scaffold/start.unit.js @@ -18,22 +18,22 @@ describe('#start', function() { }); it('will give true with "datadir" at root', function() { var checkConfigVersion2 = proxyquire('../../lib/scaffold/start', {}).checkConfigVersion2; - var v2 = checkConfigVersion2({datadir: '/home/user/.meritcore/data', services: []}); + var v2 = checkConfigVersion2({ datadir: '/home/user/.meritcore/data', services: [] }); v2.should.equal(true); }); it('will give true with "address" service enabled', function() { var checkConfigVersion2 = proxyquire('../../lib/scaffold/start', {}).checkConfigVersion2; - var v2 = checkConfigVersion2({services: ['address']}); + var v2 = checkConfigVersion2({ services: ['address'] }); v2.should.equal(true); }); it('will give true with "db" service enabled', function() { var checkConfigVersion2 = proxyquire('../../lib/scaffold/start', {}).checkConfigVersion2; - var v2 = checkConfigVersion2({services: ['db']}); + var v2 = checkConfigVersion2({ services: ['db'] }); v2.should.equal(true); }); it('will give false without "datadir" at root and "address", "db" services disabled', function() { var checkConfigVersion2 = proxyquire('../../lib/scaffold/start', {}).checkConfigVersion2; - var v2 = checkConfigVersion2({services: []}); + var v2 = checkConfigVersion2({ services: [] }); v2.should.equal(false); }); }); @@ -54,13 +54,13 @@ describe('#start', function() { services: ['internal'], servicesConfig: { internal: { - param: 'value' - } - } + param: 'value', + }, + }, }; var services = setupServices(testRequire, cwd, config); services[0].name.should.equal('internal'); - services[0].config.should.deep.equal({param: 'value'}); + services[0].config.should.deep.equal({ param: 'value' }); services[0].module.should.equal(InternalService); }); it('will require a local module', function() { @@ -76,12 +76,12 @@ describe('#start', function() { return LocalService; } else if (p === 'local/package.json') { return { - name: 'local' + name: 'local', }; } }; var config = { - services: ['local'] + services: ['local'], }; var services = setupServices(testRequire, cwd, config); services[0].name.should.equal('local'); @@ -99,14 +99,14 @@ describe('#start', function() { } else if (p === 'local/package.json') { return { name: 'local', - meritcoreNode: 'lib/meritcoreNode.js' + meritcoreNode: 'lib/meritcoreNode.js', }; } else if (p === 'local/lib/meritcoreNode.js') { return LocalService; } }; var config = { - services: ['local'] + services: ['local'], }; var services = setupServices(testRequire, cwd, config); services[0].name.should.equal('local'); @@ -118,29 +118,29 @@ describe('#start', function() { return internal; }; var config = { - services: ['meritd'] + services: ['meritd'], }; (function() { setupServices(testRequire, cwd, config); - }).should.throw('Could not load service'); + }.should.throw('Could not load service')); }); }); describe('#cleanShutdown', function() { it('will call node stop and process exit', function() { var log = { info: sinon.stub(), - error: sinon.stub() + error: sinon.stub(), }; var cleanShutdown = proxyquire('../../lib/scaffold/start', { '../': { - log: log - } + log: log, + }, }).cleanShutdown; var node = { - stop: sinon.stub().callsArg(0) + stop: sinon.stub().callsArg(0), }; var _process = { - exit: sinon.stub() + exit: sinon.stub(), }; cleanShutdown(_process, node); setImmediate(function() { @@ -152,18 +152,18 @@ describe('#start', function() { it('will log error during shutdown and exit with status 1', function() { var log = { info: sinon.stub(), - error: sinon.stub() + error: sinon.stub(), }; var cleanShutdown = proxyquire('../../lib/scaffold/start', { '../': { - log: log - } + log: log, + }, }).cleanShutdown; var node = { - stop: sinon.stub().callsArgWith(0, new Error('test')) + stop: sinon.stub().callsArgWith(0, new Error('test')), }; var _process = { - exit: sinon.stub() + exit: sinon.stub(), }; cleanShutdown(_process, node); setImmediate(function() { @@ -177,18 +177,18 @@ describe('#start', function() { describe('#registerExitHandlers', function() { var log = { info: sinon.stub(), - error: sinon.stub() + error: sinon.stub(), }; var registerExitHandlers = proxyquire('../../lib/scaffold/start', { '../': { - log: log - } + log: log, + }, }).registerExitHandlers; it('log, stop and exit with an `uncaughtException`', function(done) { var proc = new EventEmitter(); proc.exit = sinon.stub(); var node = { - stop: sinon.stub().callsArg(0) + stop: sinon.stub().callsArg(0), }; registerExitHandlers(proc, node); proc.emit('uncaughtException', new Error('test')); @@ -202,7 +202,7 @@ describe('#start', function() { var proc = new EventEmitter(); proc.exit = sinon.stub(); var node = { - stop: sinon.stub().callsArg(0) + stop: sinon.stub().callsArg(0), }; registerExitHandlers(proc, node); proc.emit('SIGINT'); @@ -250,7 +250,7 @@ describe('#start', function() { }); it('should replace the listener for SIGINT after the first SIGINT is handled', function() { - var options = { sigint: true }; + var options = { sigint: true }; var node = {}; exitHandler(options, process, node); cleanShutdown.callCount.should.equal(1); @@ -259,16 +259,15 @@ describe('#start', function() { }); it('should log all errors and stops the services nonetheless', function() { - var options = { sigint: true }; + var options = { sigint: true }; var stop = sinon.stub(); var node = { - stop: stop + stop: stop, }; exitHandler(options, process, node, new Error('some error')); logStub.callCount.should.equal(2); stop.callCount.should.equal(1); }); - }); }); }); diff --git a/packages/merit-node/test/services/meritd.unit.js b/packages/merit-node/test/services/meritd.unit.js index 35dbdc8a44..ccf577d75b 100644 --- a/packages/merit-node/test/services/meritd.unit.js +++ b/packages/merit-node/test/services/meritd.unit.js @@ -21,22 +21,23 @@ var Transaction = meritcore.Transaction; var readFileSync = sinon.stub().returns(fs.readFileSync(path.resolve(__dirname, '../data/merit.conf'))); var MeritService = proxyquire('../../lib/services/meritd', { fs: { - readFileSync: readFileSync - } + readFileSync: readFileSync, + }, }); var defaultMeritConf = fs.readFileSync(path.resolve(__dirname, '../data/default.merit.conf'), 'utf8'); describe('Merit Service', function() { - var txhex = '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000'; + var txhex = + '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000'; var baseConfig = { node: { - network: meritcore.Networks.testnet + network: meritcore.Networks.testnet, }, spawn: { datadir: 'testdir', - exec: 'testpath' - } + exec: 'testpath', + }, }; describe('@constructor', function() { @@ -70,7 +71,7 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); meritd.nodes.should.deep.equal([]); meritd.nodesIndex.should.equal(0); - meritd.nodes.push({client: sinon.stub()}); + meritd.nodes.push({ client: sinon.stub() }); should.exist(meritd.client); }); it('will set subscriptions', function() { @@ -79,7 +80,7 @@ describe('Merit Service', function() { address: {}, rawtransaction: [], hashblock: [], - rawreferraltx: [] + rawreferraltx: [], }); }); }); @@ -87,7 +88,7 @@ describe('Merit Service', function() { describe('#_initDefaults', function() { it('will set transaction concurrency', function() { var meritd = new MeritService(baseConfig); - meritd._initDefaults({transactionConcurrency: 10}); + meritd._initDefaults({ transactionConcurrency: 10 }); meritd.transactionConcurrency.should.equal(10); meritd._initDefaults({}); meritd.transactionConcurrency.should.equal(5); @@ -205,7 +206,7 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); var emitter1 = {}; var emitter3 = {}; - meritd.subscriptions.hashblock= [emitter1]; + meritd.subscriptions.hashblock = [emitter1]; meritd.unsubscribe('hashblock', emitter3); meritd.subscriptions.hashblock.length.should.equal(1); meritd.subscriptions.hashblock[0].should.equal(emitter1); @@ -363,11 +364,11 @@ describe('Merit Service', function() { fs: { readFileSync: readFileSync, existsSync: sinon.stub().returns(true), - writeFileSync: sinon.stub() + writeFileSync: sinon.stub(), }, mkdirp: { - sync: sinon.stub() - } + sync: sinon.stub(), + }, }); var meritd = new TestMerit(baseConfig); meritd.options.spawn.datadir = '/tmp/.merit'; @@ -400,21 +401,21 @@ describe('Merit Service', function() { fs: { readFileSync: readFileSync, existsSync: sinon.stub().returns(true), - writeFileSync: sinon.stub() + writeFileSync: sinon.stub(), }, mkdirp: { - sync: sinon.stub() - } + sync: sinon.stub(), + }, }); var config = { node: { network: meritcore.Networks.testnet, - configPath: '/tmp/.meritcore/merit-node.json' + configPath: '/tmp/.meritcore/merit-node.json', }, spawn: { datadir: './data', - exec: 'testpath' - } + exec: 'testpath', + }, }; var meritd = new TestMerit(config); meritd.options.spawn.datadir = './data'; @@ -422,20 +423,20 @@ describe('Merit Service', function() { meritd._loadSpawnConfiguration(node); meritd.options.spawn.datadir.should.equal('/tmp/.meritcore/data'); }); - it('should throw an exception if txindex isn\'t enabled in the configuration', function() { + it("should throw an exception if txindex isn't enabled in the configuration", function() { var TestMerit = proxyquire('../../lib/services/meritd', { fs: { readFileSync: sinon.stub().returns(fs.readFileSync(__dirname + '/../data/badmerit.conf')), existsSync: sinon.stub().returns(true), }, mkdirp: { - sync: sinon.stub() - } + sync: sinon.stub(), + }, }); var meritd = new TestMerit(baseConfig); (function() { - meritd._loadSpawnConfiguration({datadir: './test'}); - }).should.throw(meritcore.errors.InvalidState); + meritd._loadSpawnConfiguration({ datadir: './test' }); + }.should.throw(meritcore.errors.InvalidState)); }); it('should NOT set https options if node https options are set', function() { var writeFileSync = function(path, config) { @@ -445,27 +446,27 @@ describe('Merit Service', function() { fs: { writeFileSync: writeFileSync, readFileSync: readFileSync, - existsSync: sinon.stub().returns(false) + existsSync: sinon.stub().returns(false), }, mkdirp: { - sync: sinon.stub() - } + sync: sinon.stub(), + }, }); var config = { node: { network: { - name: 'regtest' + name: 'regtest', }, https: true, httpsOptions: { key: 'key.pem', - cert: 'cert.pem' - } + cert: 'cert.pem', + }, }, spawn: { datadir: 'testdir', - exec: 'testexec' - } + exec: 'testexec', + }, }; var meritd = new TestMerit(config); meritd.options.spawn.datadir = '/tmp/.merit'; @@ -492,7 +493,7 @@ describe('Merit Service', function() { zmqpubrawtx: 1, zmqpubhashblock: 1, zmqpubrawreferraltx: 1, - reindex: 1 + reindex: 1, }; var node = {}; meritd._checkConfigIndexes(config, node); @@ -509,12 +510,12 @@ describe('Merit Service', function() { zmqpubrawtx: 'tcp://127.0.0.1:28332', zmqpubhashblock: 'tcp://127.0.0.1:28331', zmqpubrawreferraltx: 'tcp://127.0.0.1:28331', - reindex: 1 + reindex: 1, }; var node = {}; (function() { meritd._checkConfigIndexes(config, node); - }).should.throw('"zmqpubrawtx", "zmqpubhashblock"'); + }.should.throw('"zmqpubrawtx", "zmqpubhashblock"')); }); }); @@ -545,95 +546,104 @@ describe('Merit Service', function() { meritd.tryAllInterval = 1; meritd.nodes.push({ client: { - getInfo: sinon.stub().callsArgWith(0, new Error('test')) - } + getInfo: sinon.stub().callsArgWith(0, new Error('test')), + }, }); meritd.nodes.push({ client: { - getInfo: sinon.stub().callsArgWith(0, new Error('test')) - } + getInfo: sinon.stub().callsArgWith(0, new Error('test')), + }, }); meritd.nodes.push({ client: { - getInfo: sinon.stub().callsArg(0) - } - }); - meritd._tryAllClients(function(client, next) { - client.getInfo(next); - }, function(err) { - if (err) { - return done(err); - } - meritd.nodes[0].client.getInfo.callCount.should.equal(1); - meritd.nodes[1].client.getInfo.callCount.should.equal(1); - meritd.nodes[2].client.getInfo.callCount.should.equal(1); - done(); + getInfo: sinon.stub().callsArg(0), + }, }); + meritd._tryAllClients( + function(client, next) { + client.getInfo(next); + }, + function(err) { + if (err) { + return done(err); + } + meritd.nodes[0].client.getInfo.callCount.should.equal(1); + meritd.nodes[1].client.getInfo.callCount.should.equal(1); + meritd.nodes[2].client.getInfo.callCount.should.equal(1); + done(); + }, + ); }); it('will start using the current node index (round-robin)', function(done) { var meritd = new MeritService(baseConfig); meritd.tryAllInterval = 1; meritd.nodes.push({ client: { - getInfo: sinon.stub().callsArgWith(0, new Error('2')) - } + getInfo: sinon.stub().callsArgWith(0, new Error('2')), + }, }); meritd.nodes.push({ client: { - getInfo: sinon.stub().callsArgWith(0, new Error('3')) - } + getInfo: sinon.stub().callsArgWith(0, new Error('3')), + }, }); meritd.nodes.push({ client: { - getInfo: sinon.stub().callsArgWith(0, new Error('1')) - } + getInfo: sinon.stub().callsArgWith(0, new Error('1')), + }, }); meritd.nodesIndex = 2; - meritd._tryAllClients(function(client, next) { - client.getInfo(next); - }, function(err) { - err.should.be.instanceOf(Error); - err.message.should.equal('3'); - meritd.nodes[0].client.getInfo.callCount.should.equal(1); - meritd.nodes[1].client.getInfo.callCount.should.equal(1); - meritd.nodes[2].client.getInfo.callCount.should.equal(1); - meritd.nodesIndex.should.equal(2); - done(); - }); + meritd._tryAllClients( + function(client, next) { + client.getInfo(next); + }, + function(err) { + err.should.be.instanceOf(Error); + err.message.should.equal('3'); + meritd.nodes[0].client.getInfo.callCount.should.equal(1); + meritd.nodes[1].client.getInfo.callCount.should.equal(1); + meritd.nodes[2].client.getInfo.callCount.should.equal(1); + meritd.nodesIndex.should.equal(2); + done(); + }, + ); }); it('will get error if all clients fail', function(done) { var meritd = new MeritService(baseConfig); meritd.tryAllInterval = 1; meritd.nodes.push({ client: { - getInfo: sinon.stub().callsArgWith(0, new Error('test')) - } + getInfo: sinon.stub().callsArgWith(0, new Error('test')), + }, }); meritd.nodes.push({ client: { - getInfo: sinon.stub().callsArgWith(0, new Error('test')) - } + getInfo: sinon.stub().callsArgWith(0, new Error('test')), + }, }); meritd.nodes.push({ client: { - getInfo: sinon.stub().callsArgWith(0, new Error('test')) - } - }); - meritd._tryAllClients(function(client, next) { - client.getInfo(next); - }, function(err) { - should.exist(err); - err.should.be.instanceOf(Error); - err.message.should.equal('test'); - done(); + getInfo: sinon.stub().callsArgWith(0, new Error('test')), + }, }); + meritd._tryAllClients( + function(client, next) { + client.getInfo(next); + }, + function(err) { + should.exist(err); + err.should.be.instanceOf(Error); + err.message.should.equal('test'); + done(); + }, + ); }); }); describe('#_wrapRPCError', function() { it('will convert meritd-rpc error object into JavaScript error', function() { var meritd = new MeritService(baseConfig); - var error = meritd._wrapRPCError({message: 'Test error', code: -1}); + var error = meritd._wrapRPCError({ message: 'Test error', code: -1 }); error.should.be.an.instanceof(errors.RPCError); error.code.should.equal(-1); error.message.should.equal('Test error'); @@ -656,24 +666,24 @@ describe('Merit Service', function() { client: { getBestBlockHash: function(callback) { callback(null, { - result: 'bestblockhash' + result: 'bestblockhash', }); }, getBlock: function(hash, callback) { if (hash === 'bestblockhash') { callback(null, { result: { - height: 5000 - } + height: 5000, + }, }); } }, getBlockHash: function(num, callback) { callback(null, { - result: 'genesishash' + result: 'genesishash', }); - } - } + }, + }, }); meritd._initChain(function() { log.info.callCount.should.equal(1); @@ -686,11 +696,11 @@ describe('Merit Service', function() { }); it('it will handle error from getBestBlockHash', function(done) { var meritd = new MeritService(baseConfig); - var getBestBlockHash = sinon.stub().callsArgWith(0, {code: -1, message: 'error'}); + var getBestBlockHash = sinon.stub().callsArgWith(0, { code: -1, message: 'error' }); meritd.nodes.push({ client: { - getBestBlockHash: getBestBlockHash - } + getBestBlockHash: getBestBlockHash, + }, }); meritd._initChain(function(err) { err.should.be.instanceOf(Error); @@ -700,12 +710,12 @@ describe('Merit Service', function() { it('it will handle error from getBlock', function(done) { var meritd = new MeritService(baseConfig); var getBestBlockHash = sinon.stub().callsArgWith(0, null, {}); - var getBlock = sinon.stub().callsArgWith(1, {code: -1, message: 'error'}); + var getBlock = sinon.stub().callsArgWith(1, { code: -1, message: 'error' }); meritd.nodes.push({ client: { getBestBlockHash: getBestBlockHash, - getBlock: getBlock - } + getBlock: getBlock, + }, }); meritd._initChain(function(err) { err.should.be.instanceOf(Error); @@ -717,16 +727,16 @@ describe('Merit Service', function() { var getBestBlockHash = sinon.stub().callsArgWith(0, null, {}); var getBlock = sinon.stub().callsArgWith(1, null, { result: { - height: 10 - } + height: 10, + }, }); - var getBlockHash = sinon.stub().callsArgWith(1, {code: -1, message: 'error'}); + var getBlockHash = sinon.stub().callsArgWith(1, { code: -1, message: 'error' }); meritd.nodes.push({ client: { getBestBlockHash: getBestBlockHash, getBlock: getBlock, - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd._initChain(function(err) { err.should.be.instanceOf(Error); @@ -738,16 +748,16 @@ describe('Merit Service', function() { var getBestBlockHash = sinon.stub().callsArgWith(0, null, {}); var getBlock = sinon.stub().callsArgWith(1, null, { result: { - height: 10 - } + height: 10, + }, }); var getBlockHash = sinon.stub().callsArgWith(1, null, {}); meritd.nodes.push({ client: { getBestBlockHash: getBestBlockHash, getBlock: getBlock, - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd.getRawBlock = sinon.stub().callsArgWith(1, new Error('test')); meritd._initChain(function(err) { @@ -765,12 +775,12 @@ describe('Merit Service', function() { it('will get default rpc port for livenet', function() { var config = { node: { - network: meritcore.Networks.livenet + network: meritcore.Networks.livenet, }, spawn: { datadir: 'testdir', - exec: 'testpath' - } + exec: 'testpath', + }, }; var meritd = new MeritService(config); meritd._getDefaultConf().rpcport.should.equal(8445); @@ -778,12 +788,12 @@ describe('Merit Service', function() { it('will get default rpc port for testnet', function() { var config = { node: { - network: meritcore.Networks.testnet + network: meritcore.Networks.testnet, }, spawn: { datadir: 'testdir', - exec: 'testpath' - } + exec: 'testpath', + }, }; var meritd = new MeritService(config); meritd._getDefaultConf().rpcport.should.equal(18445); @@ -792,12 +802,12 @@ describe('Merit Service', function() { meritcore.Networks.enableRegtest(); var config = { node: { - network: meritcore.Networks.testnet + network: meritcore.Networks.testnet, }, spawn: { datadir: 'testdir', - exec: 'testpath' - } + exec: 'testpath', + }, }; var meritd = new MeritService(config); meritd._getDefaultConf().rpcport.should.equal(18445); @@ -812,12 +822,12 @@ describe('Merit Service', function() { it('will get default config path for livenet', function() { var config = { node: { - network: meritcore.Networks.livenet + network: meritcore.Networks.livenet, }, spawn: { datadir: 'testdir', - exec: 'testpath' - } + exec: 'testpath', + }, }; var meritd = new MeritService(config); should.equal(meritd._getNetworkConfigPath(), undefined); @@ -825,12 +835,12 @@ describe('Merit Service', function() { it('will get default rpc port for testnet', function() { var config = { node: { - network: meritcore.Networks.testnet + network: meritcore.Networks.testnet, }, spawn: { datadir: 'testdir', - exec: 'testpath' - } + exec: 'testpath', + }, }; var meritd = new MeritService(config); meritd._getNetworkConfigPath().should.equal('testnet3/merit.com'); @@ -839,12 +849,12 @@ describe('Merit Service', function() { meritcore.Networks.enableRegtest(); var config = { node: { - network: meritcore.Networks.testnet + network: meritcore.Networks.testnet, }, spawn: { datadir: 'testdir', - exec: 'testpath' - } + exec: 'testpath', + }, }; var meritd = new MeritService(config); meritd._getNetworkConfigPath().should.equal('regtest/merit.com'); @@ -970,8 +980,8 @@ describe('Merit Service', function() { }); var node = { client: { - getBlock: sinon.stub().callsArgWith(1, {message: 'Test error', code: -1}) - } + getBlock: sinon.stub().callsArgWith(1, { message: 'Test error', code: -1 }), + }, }; meritd._updateTip(node, message); }); @@ -983,8 +993,8 @@ describe('Merit Service', function() { }); var node = { client: { - getBlock: sinon.stub() - } + getBlock: sinon.stub(), + }, }; meritd._updateTip(node, message); }); @@ -996,8 +1006,8 @@ describe('Merit Service', function() { }); var node = { client: { - getBlock: sinon.stub() - } + getBlock: sinon.stub(), + }, }; meritd._updateTip(node, message); log.info.callCount.should.equal(1); @@ -1013,8 +1023,8 @@ describe('Merit Service', function() { }); var node = { client: { - getBlock: sinon.stub() - } + getBlock: sinon.stub(), + }, }; meritd._updateTip(node, message); }); @@ -1032,10 +1042,10 @@ describe('Merit Service', function() { client: { getBlock: sinon.stub().callsArgWith(1, null, { result: { - height: 10 - } - }) - } + height: 10, + }, + }), + }, }; meritd._updateTip(node, message); }); @@ -1050,10 +1060,10 @@ describe('Merit Service', function() { client: { getBlock: sinon.stub().callsArgWith(1, null, { result: { - height: 10 - } - }) - } + height: 10, + }, + }), + }, }; meritd._updateTip(node, message); meritd._updateTip(node, message); @@ -1061,12 +1071,12 @@ describe('Merit Service', function() { it('will not call syncPercentage if node is stopping', function(done) { var config = { node: { - network: meritcore.Networks.testnet + network: meritcore.Networks.testnet, }, spawn: { datadir: 'testdir', - exec: 'testpath' - } + exec: 'testpath', + }, }; var meritd = new MeritService(config); meritd.syncPercentage = sinon.stub(); @@ -1076,10 +1086,10 @@ describe('Merit Service', function() { client: { getBlock: sinon.stub().callsArgWith(1, null, { result: { - height: 10 - } - }) - } + height: 10, + }, + }), + }, }; meritd.on('tip', function() { meritd.syncPercentage.callCount.should.equal(0); @@ -1102,7 +1112,7 @@ describe('Merit Service', function() { outputIndex: 0, script: meritcore.Script(inputAddress), address: inputAddress.toString(), - micros: 5000000000 + micros: 5000000000, }); tx.to(outputAddress, 5000000000); tx.sign(privkey); @@ -1114,29 +1124,35 @@ describe('Merit Service', function() { it('will handle non-standard script types', function() { var meritd = new MeritService(baseConfig); var tx = meritcore.Transaction(); - tx.addInput(meritcore.Transaction.Input({ - prevTxId: '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b', - script: meritcore.Script('OP_TRUE'), - outputIndex: 1, - output: { + tx.addInput( + meritcore.Transaction.Input({ + prevTxId: '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b', script: meritcore.Script('OP_TRUE'), - micros: 5000000000 - } - })); - tx.addOutput(meritcore.Transaction.Output({ - script: meritcore.Script('OP_TRUE'), - micros: 5000000000 - })); + outputIndex: 1, + output: { + script: meritcore.Script('OP_TRUE'), + micros: 5000000000, + }, + }), + ); + tx.addOutput( + meritcore.Transaction.Output({ + script: meritcore.Script('OP_TRUE'), + micros: 5000000000, + }), + ); var addresses = meritd._getAddressesFromTransaction(tx); addresses.length.should.equal(0); }); it('will handle unparsable script types or missing input script', function() { var meritd = new MeritService(baseConfig); var tx = meritcore.Transaction(); - tx.addOutput(meritcore.Transaction.Output({ - script: new Buffer('4c', 'hex'), - micros: 5000000000 - })); + tx.addOutput( + meritcore.Transaction.Output({ + script: new Buffer('4c', 'hex'), + micros: 5000000000, + }), + ); var addresses = meritd._getAddressesFromTransaction(tx); addresses.length.should.equal(0); }); @@ -1144,14 +1160,18 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); var tx = meritcore.Transaction(); var address = meritcore.Address('2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br'); - tx.addOutput(meritcore.Transaction.Output({ - script: meritcore.Script(address), - micros: 5000000000 - })); - tx.addOutput(meritcore.Transaction.Output({ - script: meritcore.Script(address), - micros: 5000000000 - })); + tx.addOutput( + meritcore.Transaction.Output({ + script: meritcore.Script(address), + micros: 5000000000, + }), + ); + tx.addOutput( + meritcore.Transaction.Output({ + script: meritcore.Script(address), + micros: 5000000000, + }), + ); var addresses = meritd._getAddressesFromTransaction(tx); addresses.length.should.equal(1); }); @@ -1254,10 +1274,10 @@ describe('Merit Service', function() { blockEvents++; }); var getBestBlockHash = sinon.stub().callsArgWith(0, null, { - result: '00000000000000001bb82a7f5973618cfd3185ba1ded04dd852a653f92a27c45' + result: '00000000000000001bb82a7f5973618cfd3185ba1ded04dd852a653f92a27c45', }); - getBestBlockHash.onCall(0).callsArgWith(0, {code: -1 , message: 'Test error'}); - var progress = 0.90; + getBestBlockHash.onCall(0).callsArgWith(0, { code: -1, message: 'Test error' }); + var progress = 0.9; function getProgress() { progress = progress + 0.01; return progress; @@ -1266,20 +1286,20 @@ describe('Merit Service', function() { Object.defineProperty(info, 'result', { get: function() { return { - verificationprogress: getProgress() + verificationprogress: getProgress(), }; - } + }, }); var getBlockchainInfo = sinon.stub().callsArgWith(0, null, info); - getBlockchainInfo.onCall(0).callsArgWith(0, {code: -1, message: 'Test error'}); + getBlockchainInfo.onCall(0).callsArgWith(0, { code: -1, message: 'Test error' }); var node = { _reindex: true, _reindexWait: 1, _tipUpdateInterval: 1, client: { getBestBlockHash: getBestBlockHash, - getBlockchainInfo: getBlockchainInfo - } + getBlockchainInfo: getBlockchainInfo, + }, }; meritd._checkSyncedAndSubscribeZmqEvents(node); setTimeout(function() { @@ -1293,20 +1313,20 @@ describe('Merit Service', function() { it('it will clear interval if node is stopping', function(done) { var config = { node: { - network: meritcore.Networks.testnet + network: meritcore.Networks.testnet, }, spawn: { datadir: 'testdir', - exec: 'testpath' - } + exec: 'testpath', + }, }; var meritd = new MeritService(config); - var getBestBlockHash = sinon.stub().callsArgWith(0, {code: -1, message: 'error'}); + var getBestBlockHash = sinon.stub().callsArgWith(0, { code: -1, message: 'error' }); var node = { _tipUpdateInterval: 1, client: { - getBestBlockHash: getBestBlockHash - } + getBestBlockHash: getBestBlockHash, + }, }; meritd._checkSyncedAndSubscribeZmqEvents(node); setTimeout(function() { @@ -1323,20 +1343,20 @@ describe('Merit Service', function() { meritd._updateTip = sinon.stub(); meritd._subscribeZmqEvents = sinon.stub(); var getBestBlockHash = sinon.stub().callsArgWith(0, null, { - result: '00000000000000001bb82a7f5973618cfd3185ba1ded04dd852a653f92a27c45' + result: '00000000000000001bb82a7f5973618cfd3185ba1ded04dd852a653f92a27c45', }); var info = { result: { - verificationprogress: 1.00 - } + verificationprogress: 1.0, + }, }; var getBlockchainInfo = sinon.stub().callsArgWith(0, null, info); var node = { _tipUpdateInterval: 1, client: { getBestBlockHash: getBestBlockHash, - getBlockchainInfo: getBlockchainInfo - } + getBlockchainInfo: getBlockchainInfo, + }, }; meritd._checkSyncedAndSubscribeZmqEvents(node); setTimeout(function() { @@ -1353,8 +1373,8 @@ describe('Merit Service', function() { var node = { zmqSubSocket: { subscribe: sinon.stub(), - on: sinon.stub() - } + on: sinon.stub(), + }, }; meritd._subscribeZmqEvents(node); node.zmqSubSocket.subscribe.callCount.should.equal(4); @@ -1365,7 +1385,7 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); meritd._zmqTransactionHandler = sinon.stub(); var node = { - zmqSubSocket: new EventEmitter() + zmqSubSocket: new EventEmitter(), }; node.zmqSubSocket.subscribe = sinon.stub(); meritd._subscribeZmqEvents(node); @@ -1381,7 +1401,7 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); meritd._zmqBlockHandler = sinon.stub(); var node = { - zmqSubSocket: new EventEmitter() + zmqSubSocket: new EventEmitter(), }; node.zmqSubSocket.subscribe = sinon.stub(); meritd._subscribeZmqEvents(node); @@ -1398,7 +1418,7 @@ describe('Merit Service', function() { meritd._zmqBlockHandler = sinon.stub(); meritd._zmqTransactionHandler = sinon.stub(); var node = { - zmqSubSocket: new EventEmitter() + zmqSubSocket: new EventEmitter(), }; node.zmqSubSocket.subscribe = sinon.stub(); meritd._subscribeZmqEvents(node); @@ -1423,8 +1443,8 @@ describe('Merit Service', function() { }; var MeritService = proxyquire('../../lib/services/meritd', { zmq: { - socket: socketFunc - } + socket: socketFunc, + }, }); var meritd = new MeritService(baseConfig); var node = {}; @@ -1452,8 +1472,8 @@ describe('Merit Service', function() { _reindex: true, _reindexWait: 1, client: { - getBlockchainInfo: sinon.stub().callsArgWith(0, {code: -1 , message: 'Test error'}) - } + getBlockchainInfo: sinon.stub().callsArgWith(0, { code: -1, message: 'Test error' }), + }, }; meritd._checkReindex(node, function(err) { should.exist(err); @@ -1472,11 +1492,11 @@ describe('Merit Service', function() { percent += 0.01; callback(null, { result: { - verificationprogress: percent - } + verificationprogress: percent, + }, }); - } - } + }, + }, }; meritd._checkReindex(node, function() { node._reindex.should.equal(false); @@ -1487,7 +1507,7 @@ describe('Merit Service', function() { it('will call callback if reindex is not enabled', function(done) { var meritd = new MeritService(baseConfig); var node = { - _reindex: false + _reindex: false, }; meritd._checkReindex(node, function() { node._reindex.should.equal(false); @@ -1506,11 +1526,11 @@ describe('Merit Service', function() { }); it('will give rpc from client getbestblockhash', function(done) { var meritd = new MeritService(baseConfig); - var getBestBlockHash = sinon.stub().callsArgWith(0, {code: -1, message: 'Test error'}); + var getBestBlockHash = sinon.stub().callsArgWith(0, { code: -1, message: 'Test error' }); var node = { client: { - getBestBlockHash: getBestBlockHash - } + getBestBlockHash: getBestBlockHash, + }, }; meritd._loadTipFromNode(node, function(err) { err.should.be.instanceof(Error); @@ -1521,14 +1541,14 @@ describe('Merit Service', function() { it('will give rpc from client getblock', function(done) { var meritd = new MeritService(baseConfig); var getBestBlockHash = sinon.stub().callsArgWith(0, null, { - result: '00000000000000001bb82a7f5973618cfd3185ba1ded04dd852a653f92a27c45' + result: '00000000000000001bb82a7f5973618cfd3185ba1ded04dd852a653f92a27c45', }); var getBlock = sinon.stub().callsArgWith(1, new Error('Test error')); var node = { client: { getBestBlockHash: getBestBlockHash, - getBlock: getBlock - } + getBlock: getBlock, + }, }; meritd._loadTipFromNode(node, function(err) { getBlock.args[0][0].should.equal('00000000000000001bb82a7f5973618cfd3185ba1ded04dd852a653f92a27c45'); @@ -1539,11 +1559,11 @@ describe('Merit Service', function() { }); it('will log when error is RPC_IN_WARMUP', function(done) { var meritd = new MeritService(baseConfig); - var getBestBlockHash = sinon.stub().callsArgWith(0, {code: -28, message: 'Verifying blocks...'}); + var getBestBlockHash = sinon.stub().callsArgWith(0, { code: -28, message: 'Verifying blocks...' }); var node = { client: { - getBestBlockHash: getBestBlockHash - } + getBestBlockHash: getBestBlockHash, + }, }; meritd._loadTipFromNode(node, function(err) { err.should.be.instanceof(Error); @@ -1554,18 +1574,18 @@ describe('Merit Service', function() { it('will set height and emit tip', function(done) { var meritd = new MeritService(baseConfig); var getBestBlockHash = sinon.stub().callsArgWith(0, null, { - result: '00000000000000001bb82a7f5973618cfd3185ba1ded04dd852a653f92a27c45' + result: '00000000000000001bb82a7f5973618cfd3185ba1ded04dd852a653f92a27c45', }); var getBlock = sinon.stub().callsArgWith(1, null, { result: { - height: 100 - } + height: 100, + }, }); var node = { client: { getBestBlockHash: getBestBlockHash, - getBlock: getBlock - } + getBlock: getBlock, + }, }; meritd.on('tip', function(height) { height.should.equal(100); @@ -1596,8 +1616,8 @@ describe('Merit Service', function() { readFile.onCall(1).callsArgWith(2, error); var TestMeritService = proxyquire('../../lib/services/meritd', { fs: { - readFile: readFile - } + readFile: readFile, + }, }); var meritd = new TestMeritService(baseConfig); meritd.spawnStopTime = 1; @@ -1620,8 +1640,8 @@ describe('Merit Service', function() { readFile.onCall(1).callsArgWith(2, error); var TestMeritService = proxyquire('../../lib/services/meritd', { fs: { - readFile: readFile - } + readFile: readFile, + }, }); var meritd = new TestMeritService(baseConfig); meritd.spawnStopTime = 1; @@ -1643,8 +1663,8 @@ describe('Merit Service', function() { readFile.onCall(0).callsArgWith(2, null, ' '); var TestMeritService = proxyquire('../../lib/services/meritd', { fs: { - readFile: readFile - } + readFile: readFile, + }, }); var meritd = new TestMeritService(baseConfig); meritd.spawnStopTime = 1; @@ -1662,8 +1682,8 @@ describe('Merit Service', function() { readFile.onCall(0).callsArgWith(2, null, ''); var TestMeritService = proxyquire('../../lib/services/meritd', { fs: { - readFile: readFile - } + readFile: readFile, + }, }); var meritd = new TestMeritService(baseConfig); meritd.spawnStopTime = 1; @@ -1710,22 +1730,22 @@ describe('Merit Service', function() { it('will exit spawn if shutdown', function() { var config = { node: { - network: meritcore.Networks.testnet + network: meritcore.Networks.testnet, }, spawn: { datadir: 'testdir', - exec: 'testpath' - } + exec: 'testpath', + }, }; var process = new EventEmitter(); var spawn = sinon.stub().returns(process); var TestMeritService = proxyquire('../../lib/services/meritd', { fs: { - readFileSync: readFileSync + readFileSync: readFileSync, }, child_process: { - spawn: spawn - } + spawn: spawn, + }, }); var meritd = new TestMeritService(config); meritd.spawn = {}; @@ -1742,11 +1762,11 @@ describe('Merit Service', function() { var spawn = sinon.stub().returns(process); var TestMeritService = proxyquire('../../lib/services/meritd', { fs: { - readFileSync: readFileSync + readFileSync: readFileSync, }, child_process: { - spawn: spawn - } + spawn: spawn, + }, }); var meritd = new TestMeritService(baseConfig); @@ -1769,13 +1789,9 @@ describe('Merit Service', function() { should.not.exist(err); spawn.callCount.should.equal(1); spawn.args[0][0].should.equal('testexec'); - spawn.args[0][1].should.deep.equal([ - '--conf=testdir/merit.com', - '--datadir=testdir', - '--testnet' - ]); + spawn.args[0][1].should.deep.equal(['--conf=testdir/merit.com', '--datadir=testdir', '--testnet']); spawn.args[0][2].should.deep.equal({ - stdio: 'inherit' + stdio: 'inherit', }); meritd._loadTipFromNode.callCount.should.equal(1); meritd._initZmqSubSocket.callCount.should.equal(1); @@ -1793,11 +1809,11 @@ describe('Merit Service', function() { var spawn = sinon.stub().returns(process); var TestMeritService = proxyquire('../../lib/services/meritd', { fs: { - readFileSync: readFileSync + readFileSync: readFileSync, }, child_process: { - spawn: spawn - } + spawn: spawn, + }, }); var meritd = new TestMeritService(baseConfig); meritd._loadSpawnConfiguration = sinon.stub(); @@ -1831,11 +1847,11 @@ describe('Merit Service', function() { var spawn = sinon.stub().returns(process); var TestMeritService = proxyquire('../../lib/services/meritd', { fs: { - readFileSync: readFileSync + readFileSync: readFileSync, }, child_process: { - spawn: spawn - } + spawn: spawn, + }, }); var meritd = new TestMeritService(baseConfig); meritd._loadSpawnConfiguration = sinon.stub(); @@ -1869,20 +1885,20 @@ describe('Merit Service', function() { var spawn = sinon.stub().returns(process); var TestMeritService = proxyquire('../../lib/services/meritd', { fs: { - readFileSync: readFileSync + readFileSync: readFileSync, }, child_process: { - spawn: spawn - } + spawn: spawn, + }, }); var config = { node: { - network: meritcore.Networks.testnet + network: meritcore.Networks.testnet, }, spawn: { datadir: 'testdir', - exec: 'testpath' - } + exec: 'testpath', + }, }; var meritd = new TestMeritService(config); meritd._loadSpawnConfiguration = sinon.stub(); @@ -1917,11 +1933,11 @@ describe('Merit Service', function() { var spawn = sinon.stub().returns(process); var TestMeritService = proxyquire('../../lib/services/meritd', { fs: { - readFileSync: readFileSync + readFileSync: readFileSync, }, child_process: { - spawn: spawn - } + spawn: spawn, + }, }); var meritd = new TestMeritService(baseConfig); meritd.startRetryInterval = 1; @@ -1947,11 +1963,11 @@ describe('Merit Service', function() { var spawn = sinon.stub().returns(process); var TestMeritService = proxyquire('../../lib/services/meritd', { fs: { - readFileSync: readFileSync + readFileSync: readFileSync, }, child_process: { - spawn: spawn - } + spawn: spawn, + }, }); var meritd = new TestMeritService(baseConfig); @@ -1982,12 +1998,12 @@ describe('Merit Service', function() { it('will give error if connecting while shutting down', function(done) { var config = { node: { - network: meritcore.Networks.testnet + network: meritcore.Networks.testnet, }, spawn: { datadir: 'testdir', - exec: 'testpath' - } + exec: 'testpath', + }, }; var meritd = new MeritService(config); meritd.node.stopping = true; @@ -2050,7 +2066,7 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); meritd._spawnChildProcess = sinon.stub().callsArgWith(0, new Error('test')); meritd.options = { - spawn: {} + spawn: {}, }; meritd.start(function(err) { err.should.be.instanceof(Error); @@ -2062,9 +2078,7 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); meritd._connectProcess = sinon.stub().callsArgWith(1, new Error('test')); meritd.options = { - connect: [ - {} - ] + connect: [{}], }; meritd.start(function(err) { meritd._connectProcess.callCount.should.equal(1); @@ -2079,7 +2093,7 @@ describe('Merit Service', function() { meritd._initChain = sinon.stub().callsArg(0); meritd._spawnChildProcess = sinon.stub().callsArgWith(0, null, node); meritd.options = { - spawn: {} + spawn: {}, }; meritd.start(function(err) { should.not.exist(err); @@ -2093,9 +2107,7 @@ describe('Merit Service', function() { var nodes = [{}]; meritd._connectProcess = sinon.stub().callsArgWith(1, null, nodes); meritd.options = { - connect: [ - {} - ] + connect: [{}], }; meritd.start(function(err) { should.not.exist(err); @@ -2118,7 +2130,7 @@ describe('Merit Service', function() { }); it('will give "true" if percentage is 100.00', function(done) { var meritd = new MeritService(baseConfig); - meritd.syncPercentage = sinon.stub().callsArgWith(0, null, 100.00); + meritd.syncPercentage = sinon.stub().callsArgWith(0, null, 100.0); meritd.isSynced(function(err, synced) { if (err) { return done(err); @@ -2165,11 +2177,11 @@ describe('Merit Service', function() { describe('#syncPercentage', function() { it('will give rpc error', function(done) { var meritd = new MeritService(baseConfig); - var getBlockchainInfo = sinon.stub().callsArgWith(0, {message: 'error', code: -1}); + var getBlockchainInfo = sinon.stub().callsArgWith(0, { message: 'error', code: -1 }); meritd.nodes.push({ client: { - getBlockchainInfo: getBlockchainInfo - } + getBlockchainInfo: getBlockchainInfo, + }, }); meritd.syncPercentage(function(err) { should.exist(err); @@ -2181,13 +2193,13 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); var getBlockchainInfo = sinon.stub().callsArgWith(0, null, { result: { - verificationprogress: '0.983821387' - } + verificationprogress: '0.983821387', + }, }); meritd.nodes.push({ client: { - getBlockchainInfo: getBlockchainInfo - } + getBlockchainInfo: getBlockchainInfo, + }, }); meritd.syncPercentage(function(err, percentage) { if (err) { @@ -2217,8 +2229,8 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); meritd.nodes.push({ client: { - getAddressBalance: sinon.stub().callsArgWith(1, {code: -1, message: 'Test error'}) - } + getAddressBalance: sinon.stub().callsArgWith(1, { code: -1, message: 'Test error' }), + }, }); var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; var options = {}; @@ -2232,13 +2244,13 @@ describe('Merit Service', function() { var getAddressBalance = sinon.stub().callsArgWith(1, null, { result: { received: 100000, - balance: 10000 - } + balance: 10000, + }, }); meritd.nodes.push({ client: { - getAddressBalance: getAddressBalance - } + getAddressBalance: getAddressBalance, + }, }); var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; var options = {}; @@ -2266,11 +2278,11 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); meritd.nodes.push({ client: { - getAddressUtxos: sinon.stub().callsArgWith(1, {code: -1, message: 'Test error'}) - } + getAddressUtxos: sinon.stub().callsArgWith(1, { code: -1, message: 'Test error' }), + }, }); var options = { - queryMempool: false + queryMempool: false, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressUnspentOutputs(address, options, function(err) { @@ -2288,18 +2300,18 @@ describe('Merit Service', function() { outputIndex: 1, script: '76a914f399b4b8894f1153b96fce29f05e6e116eb4c21788ac', micros: 7679241, - height: 207111 - } + height: 207111, + }, ]; meritd.nodes.push({ client: { getAddressUtxos: sinon.stub().callsArgWith(1, null, { - result: expectedUtxos - }) - } + result: expectedUtxos, + }), + }, }); var options = { - queryMempool: false + queryMempool: false, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressUnspentOutputs(address, options, function(err, utxos) { @@ -2320,19 +2332,19 @@ describe('Merit Service', function() { outputIndex: 1, script: '76a914f399b4b8894f1153b96fce29f05e6e116eb4c21788ac', micros: 7679241, - height: 207111 - } + height: 207111, + }, ]; var getAddressUtxos = sinon.stub().callsArgWith(1, null, { - result: expectedUtxos + result: expectedUtxos, }); meritd.nodes.push({ client: { - getAddressUtxos: getAddressUtxos - } + getAddressUtxos: getAddressUtxos, + }, }); var options = { - queryMempool: false + queryMempool: false, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressUnspentOutputs(address, options, function(err, utxos) { @@ -2362,22 +2374,22 @@ describe('Merit Service', function() { index: 0, timestamp: 1461342707725, prevtxid: '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0', - prevout: 1 + prevout: 1, }, { txid: 'f637384e9f81f18767ea50e00bce58fc9848b6588a1130529eebba22a410155f', micros: 100000, address: '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo', index: 0, - timestamp: 1461342833133 + timestamp: 1461342833133, }, { txid: 'f71bccef3a8f5609c7f016154922adbfe0194a96fb17a798c24077c18d0a9345', micros: 400000, address: '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo', index: 1, - timestamp: 1461342954813 - } + timestamp: 1461342954813, + }, ]; var meritd = new MeritService(baseConfig); var confirmedUtxos = [ @@ -2387,8 +2399,8 @@ describe('Merit Service', function() { outputIndex: 1, script: '76a914f399b4b8894f1153b96fce29f05e6e116eb4c21788ac', micros: 7679241, - height: 207111 - } + height: 207111, + }, ]; var expectedUtxos = [ { @@ -2397,7 +2409,7 @@ describe('Merit Service', function() { micros: 400000, script: '76a914809dc14496f99b6deb722cf46d89d22f4beb8efd88ac', timestamp: 1461342954813, - txid: 'f71bccef3a8f5609c7f016154922adbfe0194a96fb17a798c24077c18d0a9345' + txid: 'f71bccef3a8f5609c7f016154922adbfe0194a96fb17a798c24077c18d0a9345', }, { address: '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo', @@ -2405,21 +2417,21 @@ describe('Merit Service', function() { micros: 100000, script: '76a914809dc14496f99b6deb722cf46d89d22f4beb8efd88ac', timestamp: 1461342833133, - txid: 'f637384e9f81f18767ea50e00bce58fc9848b6588a1130529eebba22a410155f' - } + txid: 'f637384e9f81f18767ea50e00bce58fc9848b6588a1130529eebba22a410155f', + }, ]; meritd.nodes.push({ client: { getAddressUtxos: sinon.stub().callsArgWith(1, null, { - result: confirmedUtxos + result: confirmedUtxos, }), getAddressMempool: sinon.stub().callsArgWith(1, null, { - result: deltas - }) - } + result: deltas, + }), + }, }); var options = { - queryMempool: true + queryMempool: true, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressUnspentOutputs(address, options, function(err, utxos) { @@ -2440,7 +2452,7 @@ describe('Merit Service', function() { index: 0, timestamp: 1461342707725, prevtxid: '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0', - prevout: 1 + prevout: 1, }, { txid: 'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce', @@ -2449,8 +2461,8 @@ describe('Merit Service', function() { index: 1, timestamp: 1461342707725, prevtxid: '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0', - prevout: 2 - } + prevout: 2, + }, ]; var meritd = new MeritService(baseConfig); var confirmedUtxos = [ @@ -2460,7 +2472,7 @@ describe('Merit Service', function() { outputIndex: 1, script: '76a914f399b4b8894f1153b96fce29f05e6e116eb4c21788ac', micros: 7679241, - height: 207111 + height: 207111, }, { address: '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo', @@ -2468,21 +2480,21 @@ describe('Merit Service', function() { outputIndex: 2, script: '76a914f399b4b8894f1153b96fce29f05e6e116eb4c21788ac', micros: 7679241, - height: 207111 - } + height: 207111, + }, ]; meritd.nodes.push({ client: { getAddressUtxos: sinon.stub().callsArgWith(1, null, { - result: confirmedUtxos + result: confirmedUtxos, }), getAddressMempool: sinon.stub().callsArgWith(1, null, { - result: deltas - }) - } + result: deltas, + }), + }, }); var options = { - queryMempool: true + queryMempool: true, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressUnspentOutputs(address, options, function(err, utxos) { @@ -2502,7 +2514,7 @@ describe('Merit Service', function() { index: 0, timestamp: 1461342707725, prevtxid: '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0', - prevout: 0 + prevout: 0, }, { txid: 'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce', @@ -2511,7 +2523,7 @@ describe('Merit Service', function() { index: 0, timestamp: 1461342707725, prevtxid: '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0', - prevout: 1 + prevout: 1, }, { txid: 'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce', @@ -2520,7 +2532,7 @@ describe('Merit Service', function() { index: 1, timestamp: 1461342707725, prevtxid: '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0', - prevout: 2 + prevout: 2, }, { txid: 'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce', @@ -2528,8 +2540,8 @@ describe('Merit Service', function() { address: '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo', index: 1, script: '76a914809dc14496f99b6deb722cf46d89d22f4beb8efd88ac', - timestamp: 1461342833133 - } + timestamp: 1461342833133, + }, ]; var meritd = new MeritService(baseConfig); var confirmedUtxos = [ @@ -2539,7 +2551,7 @@ describe('Merit Service', function() { outputIndex: 0, script: '76a914f399b4b8894f1153b96fce29f05e6e116eb4c21788ac', micros: 7679241, - height: 207111 + height: 207111, }, { address: '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo', @@ -2547,7 +2559,7 @@ describe('Merit Service', function() { outputIndex: 1, script: '76a914f399b4b8894f1153b96fce29f05e6e116eb4c21788ac', micros: 7679241, - height: 207111 + height: 207111, }, { address: '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo', @@ -2555,21 +2567,21 @@ describe('Merit Service', function() { outputIndex: 2, script: '76a914f399b4b8894f1153b96fce29f05e6e116eb4c21788ac', micros: 7679241, - height: 207111 - } + height: 207111, + }, ]; meritd.nodes.push({ client: { getAddressUtxos: sinon.stub().callsArgWith(1, null, { - result: confirmedUtxos + result: confirmedUtxos, }), getAddressMempool: sinon.stub().callsArgWith(1, null, { - result: deltas - }) - } + result: deltas, + }), + }, }); var options = { - queryMempool: true + queryMempool: true, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressUnspentOutputs(address, options, function(err, utxos) { @@ -2587,14 +2599,14 @@ describe('Merit Service', function() { micros: 7679241, address: '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo', index: 0, - timestamp: 1461342707724 + timestamp: 1461342707724, }, { txid: '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0', micros: 7679241, address: '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo', index: 1, - timestamp: 1461342707724 + timestamp: 1461342707724, }, { txid: '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0', @@ -2610,7 +2622,7 @@ describe('Merit Service', function() { index: 0, timestamp: 1461342707725, prevtxid: '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0', - prevout: 0 + prevout: 0, }, { txid: 'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce', @@ -2619,7 +2631,7 @@ describe('Merit Service', function() { index: 0, timestamp: 1461342707725, prevtxid: '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0', - prevout: 1 + prevout: 1, }, { txid: 'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce', @@ -2628,30 +2640,30 @@ describe('Merit Service', function() { index: 1, timestamp: 1461342707725, prevtxid: '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0', - prevout: 2 + prevout: 2, }, { txid: 'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce', micros: 100000, address: '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo', index: 1, - timestamp: 1461342833133 - } + timestamp: 1461342833133, + }, ]; var meritd = new MeritService(baseConfig); var confirmedUtxos = []; meritd.nodes.push({ client: { getAddressUtxos: sinon.stub().callsArgWith(1, null, { - result: confirmedUtxos + result: confirmedUtxos, }), getAddressMempool: sinon.stub().callsArgWith(1, null, { - result: deltas - }) - } + result: deltas, + }), + }, }); var options = { - queryMempool: true + queryMempool: true, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressUnspentOutputs(address, options, function(err, utxos) { @@ -2676,8 +2688,8 @@ describe('Merit Service', function() { index: 0, timestamp: 1461342707725, prevtxid: '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0', - prevout: 1 - } + prevout: 1, + }, ]; var meritd = new MeritService(baseConfig); var confirmedUtxos = [ @@ -2687,21 +2699,21 @@ describe('Merit Service', function() { outputIndex: 1, script: '76a914f399b4b8894f1153b96fce29f05e6e116eb4c21788ac', micros: 0, - height: 207111 - } + height: 207111, + }, ]; meritd.nodes.push({ client: { getAddressUtxos: sinon.stub().callsArgWith(1, null, { - result: confirmedUtxos + result: confirmedUtxos, }), getAddressMempool: sinon.stub().callsArgWith(1, null, { - result: deltas - }) - } + result: deltas, + }), + }, }); var options = { - queryMempool: true + queryMempool: true, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressUnspentOutputs(address, options, function(err, utxos) { @@ -2719,8 +2731,8 @@ describe('Merit Service', function() { micros: 10000, address: '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo', index: 0, - timestamp: 1461342707725 - } + timestamp: 1461342707725, + }, ]; var meritd = new MeritService(baseConfig); var confirmedUtxos = [ @@ -2730,21 +2742,21 @@ describe('Merit Service', function() { outputIndex: 1, script: '76a914f399b4b8894f1153b96fce29f05e6e116eb4c21788ac', micros: 0, - height: 207111 - } + height: 207111, + }, ]; meritd.nodes.push({ client: { getAddressUtxos: sinon.stub().callsArgWith(1, null, { - result: confirmedUtxos + result: confirmedUtxos, }), getAddressMempool: sinon.stub().callsArgWith(1, null, { - result: deltas - }) - } + result: deltas, + }), + }, }); var options = { - queryMempool: true + queryMempool: true, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressUnspentOutputs(address, options, function(err, utxos) { @@ -2759,11 +2771,11 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); meritd.nodes.push({ client: { - getAddressMempool: sinon.stub().callsArgWith(1, {code: -1, message: 'test'}) - } + getAddressMempool: sinon.stub().callsArgWith(1, { code: -1, message: 'test' }), + }, }); var options = { - queryMempool: true + queryMempool: true, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressUnspentOutputs(address, options, function(err) { @@ -2773,11 +2785,11 @@ describe('Merit Service', function() { }); it('should set query mempool if undefined', function(done) { var meritd = new MeritService(baseConfig); - var getAddressMempool = sinon.stub().callsArgWith(1, {code: -1, message: 'test'}); + var getAddressMempool = sinon.stub().callsArgWith(1, { code: -1, message: 'test' }); meritd.nodes.push({ client: { - getAddressMempool: getAddressMempool - } + getAddressMempool: getAddressMempool, + }, }); var options = {}; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; @@ -2800,7 +2812,7 @@ describe('Merit Service', function() { }, { micros: -10, - } + }, ]; var sum = meritd._getBalanceFromMempool(deltas); sum.should.equal(990); @@ -2819,7 +2831,7 @@ describe('Merit Service', function() { }, { txid: 'txid2', - } + }, ]; var txids = meritd._getTxidsFromMempool(deltas); txids.length.should.equal(3); @@ -2838,7 +2850,7 @@ describe('Merit Service', function() { }, { txid: 'txid1', - } + }, ]; var txids = meritd._getTxidsFromMempool(deltas); txids.length.should.equal(2); @@ -2852,7 +2864,7 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); var options = { start: 20, - end: 0 + end: 0, }; var rangeQuery = meritd._getHeightRangeQuery(options); rangeQuery.should.equal(true); @@ -2861,7 +2873,7 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); var options = { start: 20, - end: 0 + end: 0, }; var clone = {}; meritd._getHeightRangeQuery(options, clone); @@ -2872,11 +2884,11 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); var options = { start: 0, - end: 20 + end: 20, }; (function() { meritd._getHeightRangeQuery(options); - }).should.throw('"end" is expected'); + }.should.throw('"end" is expected')); }); }); @@ -2894,8 +2906,8 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); meritd.nodes.push({ client: { - getAddressMempool: sinon.stub().callsArgWith(1, {code: -1, message: 'Test error'}) - } + getAddressMempool: sinon.stub().callsArgWith(1, { code: -1, message: 'Test error' }), + }, }); var options = {}; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; @@ -2908,11 +2920,11 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); meritd.nodes.push({ client: { - getAddressTxids: sinon.stub().callsArgWith(1, {code: -1, message: 'Test error'}) - } + getAddressTxids: sinon.stub().callsArgWith(1, { code: -1, message: 'Test error' }), + }, }); var options = { - queryMempool: false + queryMempool: false, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressTxids(address, options, function(err) { @@ -2931,18 +2943,18 @@ describe('Merit Service', function() { 'f35e7e2a2334e845946f3eaca76890d9a68f4393ccc9fe37a0c2fb035f66d2e9', 'edc080f2084eed362aa488ccc873a24c378dc0979aa29b05767517b70569414a', 'ed11a08e3102f9610bda44c80c46781d97936a4290691d87244b1b345b39a693', - 'ec94d845c603f292a93b7c829811ac624b76e52b351617ca5a758e9d61a11681' + 'ec94d845c603f292a93b7c829811ac624b76e52b351617ca5a758e9d61a11681', ]; var meritd = new MeritService(baseConfig); meritd.nodes.push({ client: { getAddressTxids: sinon.stub().callsArgWith(1, null, { - result: expectedTxids.reverse() - }) - } + result: expectedTxids.reverse(), + }), + }, }); var options = { - queryMempool: false + queryMempool: false, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressTxids(address, options, function(err, txids) { @@ -2955,20 +2967,18 @@ describe('Merit Service', function() { }); }); it('will get txid results from cache', function(done) { - var expectedTxids = [ - 'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce' - ]; + var expectedTxids = ['e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce']; var meritd = new MeritService(baseConfig); var getAddressTxids = sinon.stub().callsArgWith(1, null, { - result: expectedTxids.reverse() + result: expectedTxids.reverse(), }); meritd.nodes.push({ client: { - getAddressTxids: getAddressTxids - } + getAddressTxids: getAddressTxids, + }, }); var options = { - queryMempool: false + queryMempool: false, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressTxids(address, options, function(err, txids) { @@ -2989,24 +2999,22 @@ describe('Merit Service', function() { }); }); it('will get txid results WITHOUT cache if rangeQuery and exclude mempool', function(done) { - var expectedTxids = [ - 'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce' - ]; + var expectedTxids = ['e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce']; var meritd = new MeritService(baseConfig); var getAddressMempool = sinon.stub(); var getAddressTxids = sinon.stub().callsArgWith(1, null, { - result: expectedTxids.reverse() + result: expectedTxids.reverse(), }); meritd.nodes.push({ client: { getAddressTxids: getAddressTxids, - getAddressMempool: getAddressMempool - } + getAddressMempool: getAddressMempool, + }, }); var options = { queryMempool: true, // start and end will exclude mempool start: 4, - end: 2 + end: 2, }; var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; meritd.getAddressTxids(address, options, function(err, txids) { @@ -3029,41 +3037,39 @@ describe('Merit Service', function() { }); }); it('will get txid results from cache and live mempool', function(done) { - var expectedTxids = [ - 'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce' - ]; + var expectedTxids = ['e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce']; var meritd = new MeritService(baseConfig); var getAddressTxids = sinon.stub().callsArgWith(1, null, { - result: expectedTxids.reverse() + result: expectedTxids.reverse(), }); var getAddressMempool = sinon.stub().callsArgWith(1, null, { result: [ { - txid: 'bc992ad772eb02864db07ef248d31fb3c6826d25f1153ebf8c79df9b7f70fcf2' + txid: 'bc992ad772eb02864db07ef248d31fb3c6826d25f1153ebf8c79df9b7f70fcf2', }, { - txid: 'f71bccef3a8f5609c7f016154922adbfe0194a96fb17a798c24077c18d0a9345' + txid: 'f71bccef3a8f5609c7f016154922adbfe0194a96fb17a798c24077c18d0a9345', }, { - txid: 'f35e7e2a2334e845946f3eaca76890d9a68f4393ccc9fe37a0c2fb035f66d2e9' - } - ] + txid: 'f35e7e2a2334e845946f3eaca76890d9a68f4393ccc9fe37a0c2fb035f66d2e9', + }, + ], }); meritd.nodes.push({ client: { getAddressTxids: getAddressTxids, - getAddressMempool: getAddressMempool - } + getAddressMempool: getAddressMempool, + }, }); var address = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo'; - meritd.getAddressTxids(address, {queryMempool: false}, function(err, txids) { + meritd.getAddressTxids(address, { queryMempool: false }, function(err, txids) { if (err) { return done(err); } getAddressTxids.callCount.should.equal(1); txids.should.deep.equal(expectedTxids); - meritd.getAddressTxids(address, {queryMempool: true}, function(err, txids) { + meritd.getAddressTxids(address, { queryMempool: true }, function(err, txids) { if (err) { return done(err); } @@ -3072,10 +3078,10 @@ describe('Merit Service', function() { 'f35e7e2a2334e845946f3eaca76890d9a68f4393ccc9fe37a0c2fb035f66d2e9', // mempool 'f71bccef3a8f5609c7f016154922adbfe0194a96fb17a798c24077c18d0a9345', // mempool 'bc992ad772eb02864db07ef248d31fb3c6826d25f1153ebf8c79df9b7f70fcf2', // mempool - 'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce' // confirmed + 'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce', // confirmed ]); - meritd.getAddressTxids(address, {queryMempoolOnly: true}, function(err, txids) { + meritd.getAddressTxids(address, { queryMempoolOnly: true }, function(err, txids) { if (err) { return done(err); } @@ -3154,20 +3160,30 @@ describe('Merit Service', function() { it('will only add address if it matches', function() { var meritd = new MeritService(baseConfig); var result = {}; - meritd._getAddressDetailsForInput({ - address: 'address1' - }, 0, result, ['address2']); + meritd._getAddressDetailsForInput( + { + address: 'address1', + }, + 0, + result, + ['address2'], + ); should.not.exist(result.addresses); should.not.exist(result.micros); }); it('will instantiate if outputIndexes not defined', function() { var meritd = new MeritService(baseConfig); var result = { - addresses: {} + addresses: {}, }; - meritd._getAddressDetailsForInput({ - address: 'address1' - }, 0, result, ['address1']); + meritd._getAddressDetailsForInput( + { + address: 'address1', + }, + 0, + result, + ['address1'], + ); should.exist(result.addresses); result.addresses['address1'].inputIndexes.should.deep.equal([0]); result.addresses['address1'].outputIndexes.should.deep.equal([]); @@ -3176,14 +3192,19 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); var result = { addresses: { - 'address1': { - inputIndexes: [1] - } - } + address1: { + inputIndexes: [1], + }, + }, }; - meritd._getAddressDetailsForInput({ - address: 'address1' - }, 2, result, ['address1']); + meritd._getAddressDetailsForInput( + { + address: 'address1', + }, + 2, + result, + ['address1'], + ); should.exist(result.addresses); result.addresses['address1'].inputIndexes.should.deep.equal([1, 2]); }); @@ -3200,20 +3221,30 @@ describe('Merit Service', function() { it('will only add address if it matches', function() { var meritd = new MeritService(baseConfig); var result = {}; - meritd._getAddressDetailsForOutput({ - address: 'address1' - }, 0, result, ['address2']); + meritd._getAddressDetailsForOutput( + { + address: 'address1', + }, + 0, + result, + ['address2'], + ); should.not.exist(result.addresses); should.not.exist(result.micros); }); it('will instantiate if outputIndexes not defined', function() { var meritd = new MeritService(baseConfig); var result = { - addresses: {} + addresses: {}, }; - meritd._getAddressDetailsForOutput({ - address: 'address1' - }, 0, result, ['address1']); + meritd._getAddressDetailsForOutput( + { + address: 'address1', + }, + 0, + result, + ['address1'], + ); should.exist(result.addresses); result.addresses['address1'].inputIndexes.should.deep.equal([]); result.addresses['address1'].outputIndexes.should.deep.equal([0]); @@ -3222,14 +3253,19 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); var result = { addresses: { - 'address1': { - outputIndexes: [0] - } - } + address1: { + outputIndexes: [0], + }, + }, }; - meritd._getAddressDetailsForOutput({ - address: 'address1' - }, 1, result, ['address1']); + meritd._getAddressDetailsForOutput( + { + address: 'address1', + }, + 1, + result, + ['address1'], + ); should.exist(result.addresses); result.addresses['address1'].outputIndexes.should.deep.equal([0, 1]); }); @@ -3242,41 +3278,39 @@ describe('Merit Service', function() { inputs: [ { micros: 1000000000, - address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW' - } + address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW', + }, ], outputs: [ { micros: 100000000, - address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW' + address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW', }, { micros: 200000000, - address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW' + address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW', }, { micros: 50000000, - address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW' + address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW', }, { micros: 300000000, - address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW' + address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW', }, { micros: 349990000, - address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW' - } + address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW', + }, ], - locktime: 0 + locktime: 0, }; var meritd = new MeritService(baseConfig); var addresses = ['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW']; var details = meritd._getAddressDetailsForTransaction(tx, addresses); should.exist(details.addresses['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW']); details.addresses['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'].inputIndexes.should.deep.equal([0]); - details.addresses['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'].outputIndexes.should.deep.equal([ - 0, 1, 2, 3, 4 - ]); + details.addresses['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'].outputIndexes.should.deep.equal([0, 1, 2, 3, 4]); details.micros.should.equal(-10000); done(); }); @@ -3330,34 +3364,25 @@ describe('Merit Service', function() { strings[1].should.equal('3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou'); }); it('will get address strings from strings', function() { - var addresses = [ - '1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i', - '3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou', - ]; + var addresses = ['1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i', '3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou']; var meritd = new MeritService(baseConfig); var strings = meritd._getAddressStrings(addresses); strings[0].should.equal('1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i'); strings[1].should.equal('3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou'); }); it('will get address strings from mixture of types', function() { - var addresses = [ - meritcore.Address('1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i'), - '3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou', - ]; + var addresses = [meritcore.Address('1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i'), '3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou']; var meritd = new MeritService(baseConfig); var strings = meritd._getAddressStrings(addresses); strings[0].should.equal('1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i'); strings[1].should.equal('3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou'); }); it('will give error with unknown', function() { - var addresses = [ - meritcore.Address('1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i'), - 0, - ]; + var addresses = [meritcore.Address('1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i'), 0]; var meritd = new MeritService(baseConfig); (function() { meritd._getAddressStrings(addresses); - }).should.throw(TypeError); + }.should.throw(TypeError)); }); }); @@ -3385,7 +3410,7 @@ describe('Merit Service', function() { var txids = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; (function() { meritd._paginateTxids(txids, 1, 0); - }).should.throw('"from" (1) is expected to be less than "to"'); + }.should.throw('"from" (1) is expected to be less than "to"')); }); it('will handle string numbers', function() { var meritd = new MeritService(baseConfig); @@ -3399,7 +3424,7 @@ describe('Merit Service', function() { var address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX'; it('will give error with "from" and "to" range that exceeds max size', function(done) { var meritd = new MeritService(baseConfig); - meritd.getAddressHistory(address, {from: 0, to: 51}, function(err) { + meritd.getAddressHistory(address, { from: 0, to: 51 }, function(err) { should.exist(err); err.message.match(/^\"from/); done(); @@ -3408,7 +3433,7 @@ describe('Merit Service', function() { it('will give error with "from" and "to" order is reversed', function(done) { var meritd = new MeritService(baseConfig); meritd.getAddressTxids = sinon.stub().callsArgWith(2, null, []); - meritd.getAddressHistory(address, {from: 51, to: 0}, function(err) { + meritd.getAddressHistory(address, { from: 51, to: 0 }, function(err) { should.exist(err); err.message.match(/^\"from/); done(); @@ -3454,7 +3479,7 @@ describe('Merit Service', function() { }; var txids = ['one', 'two', 'three', 'four']; meritd.getAddressTxids = sinon.stub().callsArgWith(2, null, txids); - meritd.getAddressHistory('address', {from: 1, to: 3}, function(err, data) { + meritd.getAddressHistory('address', { from: 1, to: 3 }, function(err, data) { if (err) { return done(err); } @@ -3479,10 +3504,10 @@ describe('Merit Service', function() { result: [ { txid: '70d9d441d7409aace8e0ffe24ff0190407b2fcb405799a266e0327017288d1f8', - } - ] - }) - } + }, + ], + }), + }, }); meritd.getAddressTxids = sinon.stub().callsArgWith(2, new Error('test')); meritd.getAddressBalance = sinon.stub().callsArgWith(2, null, {}); @@ -3503,10 +3528,10 @@ describe('Merit Service', function() { result: [ { txid: '70d9d441d7409aace8e0ffe24ff0190407b2fcb405799a266e0327017288d1f8', - } - ] - }) - } + }, + ], + }), + }, }); meritd.getAddressTxids = sinon.stub().callsArgWith(2, null, {}); meritd.getAddressBalance = sinon.stub().callsArgWith(2, new Error('test'), {}); @@ -3523,8 +3548,8 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); meritd.nodes.push({ client: { - getAddressMempool: sinon.stub().callsArgWith(1, {code: -1, message: 'Test error'}) - } + getAddressMempool: sinon.stub().callsArgWith(1, { code: -1, message: 'Test error' }), + }, }); meritd.getAddressTxids = sinon.stub().callsArgWith(2, null, {}); meritd.getAddressBalance = sinon.stub().callsArgWith(2, null, {}); @@ -3545,21 +3570,21 @@ describe('Merit Service', function() { result: [ { txid: memtxid1, - micros: -1000000 + micros: -1000000, }, { txid: memtxid2, - micros: 99999 - } - ] - }) - } + micros: 99999, + }, + ], + }), + }, }); sinon.spy(meritd, '_paginateTxids'); meritd.getAddressTxids = sinon.stub().callsArgWith(2, null, [txid1, txid2, txid3]); meritd.getAddressBalance = sinon.stub().callsArgWith(2, null, { received: 30 * 1e8, - balance: 20 * 1e8 + balance: 20 * 1e8, }); var address = '3NbU8XzUgKyuCgYgZEKsBtUvkTm2r7Xgwj'; var options = {}; @@ -3578,7 +3603,7 @@ describe('Merit Service', function() { 'b1bfa8dbbde790cb46b9763ef3407c1a21c8264b67bfe224f462ec0e1f569e92', '70d9d441d7409aace8e0ffe24ff0190407b2fcb405799a266e0327017288d1f8', '35fafaf572341798b2ce2858755afa7c8800bb6b1e885d3e030b81255b5e172d', - '57b7842afc97a2b46575b490839df46e9273524c6ea59ba62e1e86477cf25247' + '57b7842afc97a2b46575b490839df46e9273524c6ea59ba62e1e86477cf25247', ]); done(); }); @@ -3591,25 +3616,25 @@ describe('Merit Service', function() { result: [ { txid: memtxid1, - micros: -1000000 + micros: -1000000, }, { txid: memtxid2, - micros: 99999 - } - ] - }) - } + micros: 99999, + }, + ], + }), + }, }); meritd.getAddressTxids = sinon.stub().callsArgWith(2, null, [txid1, txid2, txid3]); meritd.getAddressBalance = sinon.stub().callsArgWith(2, null, { received: 30 * 1e8, - balance: 20 * 1e8 + balance: 20 * 1e8, }); var address = '3NbU8XzUgKyuCgYgZEKsBtUvkTm2r7Xgwj'; var options = { from: 0, - to: 1001 + to: 1001, }; meritd.getAddressSummary(address, options, function(err) { should.exist(err); @@ -3625,24 +3650,24 @@ describe('Merit Service', function() { result: [ { txid: memtxid1, - micros: -1000000 + micros: -1000000, }, { txid: memtxid2, - micros: 99999 - } - ] - }) - } + micros: 99999, + }, + ], + }), + }, }); meritd.getAddressTxids = sinon.stub().callsArgWith(2, null, [txid1, txid2, txid3]); meritd.getAddressBalance = sinon.stub().callsArgWith(2, null, { received: 30 * 1e8, - balance: 20 * 1e8 + balance: 20 * 1e8, }); var address = '3NbU8XzUgKyuCgYgZEKsBtUvkTm2r7Xgwj'; var options = { - noTxList: true + noTxList: true, }; function checkSummary(summary) { summary.appearances.should.equal(3); @@ -3670,18 +3695,18 @@ describe('Merit Service', function() { var getAddressMempool = sinon.stub(); meritd.nodes.push({ client: { - getAddressMempool: getAddressMempool - } + getAddressMempool: getAddressMempool, + }, }); sinon.spy(meritd, '_paginateTxids'); meritd.getAddressTxids = sinon.stub().callsArgWith(2, null, [txid1, txid2, txid3]); meritd.getAddressBalance = sinon.stub().callsArgWith(2, null, { received: 30 * 1e8, - balance: 20 * 1e8 + balance: 20 * 1e8, }); var address = '3NbU8XzUgKyuCgYgZEKsBtUvkTm2r7Xgwj'; var options = { - queryMempool: false + queryMempool: false, }; meritd.getAddressSummary(address, options, function() { getAddressMempool.callCount.should.equal(0); @@ -3693,19 +3718,19 @@ describe('Merit Service', function() { var getAddressMempool = sinon.stub(); meritd.nodes.push({ client: { - getAddressMempool: getAddressMempool - } + getAddressMempool: getAddressMempool, + }, }); sinon.spy(meritd, '_paginateTxids'); meritd.getAddressTxids = sinon.stub().callsArgWith(2, null, [txid1, txid2, txid3]); meritd.getAddressBalance = sinon.stub().callsArgWith(2, null, { received: 30 * 1e8, - balance: 20 * 1e8 + balance: 20 * 1e8, }); meritd._paginateTxids = sinon.stub().throws(new Error('test')); var address = '3NbU8XzUgKyuCgYgZEKsBtUvkTm2r7Xgwj'; var options = { - queryMempool: false + queryMempool: false, }; meritd.getAddressSummary(address, options, function(err) { err.should.be.instanceOf(Error); @@ -3717,13 +3742,14 @@ describe('Merit Service', function() { describe('#getRawBlock', function() { var blockhash = '00000000050a6d07f583beba2d803296eb1e9d4980c4a20f206c584e89a4f02b'; - var blockhex = '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; + var blockhex = + '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; it('will give rcp error from client getblockhash', function(done) { var meritd = new MeritService(baseConfig); meritd.nodes.push({ client: { - getBlockHash: sinon.stub().callsArgWith(1, {code: -1, message: 'Test error'}) - } + getBlockHash: sinon.stub().callsArgWith(1, { code: -1, message: 'Test error' }), + }, }); meritd.getRawBlock(10, function(err) { should.exist(err); @@ -3735,8 +3761,8 @@ describe('Merit Service', function() { var meritd = new MeritService(baseConfig); meritd.nodes.push({ client: { - getBlock: sinon.stub().callsArgWith(2, {code: -1, message: 'Test error'}) - } + getBlock: sinon.stub().callsArgWith(2, { code: -1, message: 'Test error' }), + }, }); meritd.getRawBlock(blockhash, function(err) { should.exist(err); @@ -3746,24 +3772,24 @@ describe('Merit Service', function() { }); it('will try all nodes for getblock', function(done) { var meritd = new MeritService(baseConfig); - var getBlockWithError = sinon.stub().callsArgWith(2, {code: -1, message: 'Test error'}); + var getBlockWithError = sinon.stub().callsArgWith(2, { code: -1, message: 'Test error' }); meritd.tryAllInterval = 1; meritd.nodes.push({ client: { - getBlock: getBlockWithError - } + getBlock: getBlockWithError, + }, }); meritd.nodes.push({ client: { - getBlock: getBlockWithError - } + getBlock: getBlockWithError, + }, }); meritd.nodes.push({ client: { getBlock: sinon.stub().callsArgWith(2, null, { - result: blockhex - }) - } + result: blockhex, + }), + }, }); meritd.getRawBlock(blockhash, function(err, buffer) { if (err) { @@ -3777,12 +3803,12 @@ describe('Merit Service', function() { it('will get block from cache', function(done) { var meritd = new MeritService(baseConfig); var getBlock = sinon.stub().callsArgWith(2, null, { - result: blockhex + result: blockhex, }); meritd.nodes.push({ client: { - getBlock: getBlock - } + getBlock: getBlock, + }, }); meritd.getRawBlock(blockhash, function(err, buffer) { if (err) { @@ -3803,16 +3829,16 @@ describe('Merit Service', function() { it('will get block by height', function(done) { var meritd = new MeritService(baseConfig); var getBlock = sinon.stub().callsArgWith(2, null, { - result: blockhex + result: blockhex, }); var getBlockHash = sinon.stub().callsArgWith(1, null, { - result: '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f' + result: '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f', }); meritd.nodes.push({ client: { getBlock: getBlock, - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd.getRawBlock(0, function(err, buffer) { if (err) { @@ -3827,16 +3853,17 @@ describe('Merit Service', function() { }); describe('#getBlock', function() { - var blockhex = '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; + var blockhex = + '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; it('will give an rpc error from client getblock', function(done) { var meritd = new MeritService(baseConfig); - var getBlock = sinon.stub().callsArgWith(2, {code: -1, message: 'Test error'}); + var getBlock = sinon.stub().callsArgWith(2, { code: -1, message: 'Test error' }); var getBlockHash = sinon.stub().callsArgWith(1, null, {}); meritd.nodes.push({ client: { getBlock: getBlock, - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd.getBlock(0, function(err) { err.should.be.instanceof(Error); @@ -3845,11 +3872,11 @@ describe('Merit Service', function() { }); it('will give an rpc error from client getblockhash', function(done) { var meritd = new MeritService(baseConfig); - var getBlockHash = sinon.stub().callsArgWith(1, {code: -1, message: 'Test error'}); + var getBlockHash = sinon.stub().callsArgWith(1, { code: -1, message: 'Test error' }); meritd.nodes.push({ client: { - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd.getBlock(0, function(err) { err.should.be.instanceof(Error); @@ -3859,16 +3886,16 @@ describe('Merit Service', function() { it('will getblock as meritcore object from height', function(done) { var meritd = new MeritService(baseConfig); var getBlock = sinon.stub().callsArgWith(2, null, { - result: blockhex + result: blockhex, }); var getBlockHash = sinon.stub().callsArgWith(1, null, { - result: '00000000050a6d07f583beba2d803296eb1e9d4980c4a20f206c584e89a4f02b' + result: '00000000050a6d07f583beba2d803296eb1e9d4980c4a20f206c584e89a4f02b', }); meritd.nodes.push({ client: { getBlock: getBlock, - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd.getBlock(0, function(err, block) { should.not.exist(err); @@ -3881,14 +3908,14 @@ describe('Merit Service', function() { it('will getblock as meritcore object', function(done) { var meritd = new MeritService(baseConfig); var getBlock = sinon.stub().callsArgWith(2, null, { - result: blockhex + result: blockhex, }); var getBlockHash = sinon.stub(); meritd.nodes.push({ client: { getBlock: getBlock, - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd.getBlock('00000000050a6d07f583beba2d803296eb1e9d4980c4a20f206c584e89a4f02b', function(err, block) { should.not.exist(err); @@ -3903,14 +3930,14 @@ describe('Merit Service', function() { it('will get block from cache', function(done) { var meritd = new MeritService(baseConfig); var getBlock = sinon.stub().callsArgWith(2, null, { - result: blockhex + result: blockhex, }); var getBlockHash = sinon.stub(); meritd.nodes.push({ client: { getBlock: getBlock, - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); var hash = '00000000050a6d07f583beba2d803296eb1e9d4980c4a20f206c584e89a4f02b'; meritd.getBlock(hash, function(err, block) { @@ -3930,16 +3957,16 @@ describe('Merit Service', function() { it('will get block from cache with height (but not height)', function(done) { var meritd = new MeritService(baseConfig); var getBlock = sinon.stub().callsArgWith(2, null, { - result: blockhex + result: blockhex, }); var getBlockHash = sinon.stub().callsArgWith(1, null, { - result: '00000000050a6d07f583beba2d803296eb1e9d4980c4a20f206c584e89a4f02b' + result: '00000000050a6d07f583beba2d803296eb1e9d4980c4a20f206c584e89a4f02b', }); meritd.nodes.push({ client: { getBlock: getBlock, - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd.getBlock(0, function(err, block) { should.not.exist(err); @@ -3960,11 +3987,11 @@ describe('Merit Service', function() { describe('#getBlockHashesByTimestamp', function() { it('should give an rpc error', function(done) { var meritd = new MeritService(baseConfig); - var getBlockHashes = sinon.stub().callsArgWith(3, {message: 'error', code: -1}); + var getBlockHashes = sinon.stub().callsArgWith(3, { message: 'error', code: -1 }); meritd.nodes.push({ client: { - getBlockHashes: getBlockHashes - } + getBlockHashes: getBlockHashes, + }, }); meritd.getBlockHashesByTimestamp(1441911000, 1441914000, function(err, hashes) { should.exist(err); @@ -3977,12 +4004,12 @@ describe('Merit Service', function() { var block1 = '00000000050a6d07f583beba2d803296eb1e9d4980c4a20f206c584e89a4f02b'; var block2 = '000000000383752a55a0b2891ce018fd0fdc0b6352502772b034ec282b4a1bf6'; var getBlockHashes = sinon.stub().callsArgWith(3, null, { - result: [block2, block1] + result: [block2, block1], }); meritd.nodes.push({ client: { - getBlockHashes: getBlockHashes - } + getBlockHashes: getBlockHashes, + }, }); meritd.getBlockHashesByTimestamp(1441914000, 1441911000, function(err, hashes) { should.not.exist(err); @@ -3996,11 +4023,11 @@ describe('Merit Service', function() { var blockhash = '00000000050a6d07f583beba2d803296eb1e9d4980c4a20f206c584e89a4f02b'; it('will give error from getBlockHash', function() { var meritd = new MeritService(baseConfig); - var getBlockHash = sinon.stub().callsArgWith(1, {code: -1, message: 'Test error'}); + var getBlockHash = sinon.stub().callsArgWith(1, { code: -1, message: 'Test error' }); meritd.nodes.push({ client: { - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd.getBlockHeader(10, function(err) { err.should.be.instanceof(Error); @@ -4008,11 +4035,11 @@ describe('Merit Service', function() { }); it('it will give rpc error from client getblockheader', function() { var meritd = new MeritService(baseConfig); - var getBlockHeader = sinon.stub().callsArgWith(1, {code: -1, message: 'Test error'}); + var getBlockHeader = sinon.stub().callsArgWith(1, { code: -1, message: 'Test error' }); meritd.nodes.push({ client: { - getBlockHeader: getBlockHeader - } + getBlockHeader: getBlockHeader, + }, }); meritd.getBlockHeader(blockhash, function(err) { err.should.be.instanceof(Error); @@ -4021,12 +4048,12 @@ describe('Merit Service', function() { it('it will give rpc error from client getblockhash', function() { var meritd = new MeritService(baseConfig); var getBlockHeader = sinon.stub(); - var getBlockHash = sinon.stub().callsArgWith(1, {code: -1, message: 'Test error'}); + var getBlockHash = sinon.stub().callsArgWith(1, { code: -1, message: 'Test error' }); meritd.nodes.push({ client: { getBlockHeader: getBlockHeader, - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd.getBlockHeader(0, function(err) { err.should.be.instanceof(Error); @@ -4047,7 +4074,7 @@ describe('Merit Service', function() { medianTime: 1462976771, nonce: 2981820714, bits: '1a13ca10', - difficulty: 847779.0710240941 + difficulty: 847779.0710240941, }; var getBlockHeader = sinon.stub().callsArgWith(1, null, { result: { @@ -4063,17 +4090,17 @@ describe('Merit Service', function() { mediantime: 1462976771, nonce: 2981820714, bits: '1a13ca10', - difficulty: 847779.0710240941 - } + difficulty: 847779.0710240941, + }, }); var getBlockHash = sinon.stub().callsArgWith(1, null, { - result: blockhash + result: blockhash, }); meritd.nodes.push({ client: { getBlockHeader: getBlockHeader, - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd.getBlockHeader(0, function(err, blockHeader) { should.not.exist(err); @@ -4096,7 +4123,7 @@ describe('Merit Service', function() { medianTime: 1462976771, nonce: 2981820714, bits: '1a13ca10', - difficulty: 847779.0710240941 + difficulty: 847779.0710240941, }; var getBlockHeader = sinon.stub().callsArgWith(1, null, { result: { @@ -4112,15 +4139,15 @@ describe('Merit Service', function() { mediantime: 1462976771, nonce: 2981820714, bits: '1a13ca10', - difficulty: 847779.0710240941 - } + difficulty: 847779.0710240941, + }, }); var getBlockHash = sinon.stub(); meritd.nodes.push({ client: { getBlockHeader: getBlockHeader, - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd.getBlockHeader(blockhash, function(err, blockHeader) { should.not.exist(err); @@ -4136,8 +4163,8 @@ describe('Merit Service', function() { var getBlockHash = sinon.stub(); meritd.nodes.push({ client: { - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd._maybeGetBlockHash('2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br', function(err, hash) { if (err) { @@ -4153,8 +4180,8 @@ describe('Merit Service', function() { var getBlockHash = sinon.stub(); meritd.nodes.push({ client: { - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd._maybeGetBlockHash('109a', function(err, hash) { if (err) { @@ -4168,12 +4195,12 @@ describe('Merit Service', function() { it('will get the block hash if argument is a number', function(done) { var meritd = new MeritService(baseConfig); var getBlockHash = sinon.stub().callsArgWith(1, null, { - result: 'blockhash' + result: 'blockhash', }); meritd.nodes.push({ client: { - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd._maybeGetBlockHash(10, function(err, hash) { if (err) { @@ -4187,12 +4214,12 @@ describe('Merit Service', function() { it('will get the block hash if argument is a number (as string)', function(done) { var meritd = new MeritService(baseConfig); var getBlockHash = sinon.stub().callsArgWith(1, null, { - result: 'blockhash' + result: 'blockhash', }); meritd.nodes.push({ client: { - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd._maybeGetBlockHash('10', function(err, hash) { if (err) { @@ -4206,19 +4233,19 @@ describe('Merit Service', function() { it('will try multiple nodes if one fails', function(done) { var meritd = new MeritService(baseConfig); var getBlockHash = sinon.stub().callsArgWith(1, null, { - result: 'blockhash' + result: 'blockhash', }); - getBlockHash.onCall(0).callsArgWith(1, {code: -1, message: 'test'}); + getBlockHash.onCall(0).callsArgWith(1, { code: -1, message: 'test' }); meritd.tryAllInterval = 1; meritd.nodes.push({ client: { - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd.nodes.push({ client: { - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd._maybeGetBlockHash(10, function(err, hash) { if (err) { @@ -4231,17 +4258,17 @@ describe('Merit Service', function() { }); it('will give error from getBlockHash', function(done) { var meritd = new MeritService(baseConfig); - var getBlockHash = sinon.stub().callsArgWith(1, {code: -1, message: 'test'}); + var getBlockHash = sinon.stub().callsArgWith(1, { code: -1, message: 'test' }); meritd.tryAllInterval = 1; meritd.nodes.push({ client: { - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd.nodes.push({ client: { - getBlockHash: getBlockHash - } + getBlockHash: getBlockHash, + }, }); meritd._maybeGetBlockHash(10, function(err, hash) { getBlockHash.callCount.should.equal(2); @@ -4265,11 +4292,11 @@ describe('Merit Service', function() { }); it('will give error from client.getBlock', function(done) { var meritd = new MeritService(baseConfig); - var getBlock = sinon.stub().callsArgWith(2, {code: -1, message: 'test'}); + var getBlock = sinon.stub().callsArgWith(2, { code: -1, message: 'test' }); meritd.nodes.push({ client: { - getBlock: getBlock - } + getBlock: getBlock, + }, }); meritd.getBlockOverview(blockhash, function(err) { err.should.be.instanceOf(Error); @@ -4292,15 +4319,15 @@ describe('Merit Service', function() { mediantime: 1462976771, nonce: 2981820714, bits: '1a13ca10', - difficulty: 847779.0710240941 + difficulty: 847779.0710240941, }; var getBlock = sinon.stub().callsArgWith(2, null, { - result: blockResult + result: blockResult, }); meritd.nodes.push({ client: { - getBlock: getBlock - } + getBlock: getBlock, + }, }); function checkBlock(blockOverview) { blockOverview.hash.should.equal('00000000050a6d07f583beba2d803296eb1e9d4980c4a20f206c584e89a4f02b'); @@ -4334,11 +4361,11 @@ describe('Merit Service', function() { describe('#estimateFee', function() { it('will give rpc error', function(done) { var meritd = new MeritService(baseConfig); - var estimateFee = sinon.stub().callsArgWith(1, {message: 'error', code: -1}); + var estimateFee = sinon.stub().callsArgWith(1, { message: 'error', code: -1 }); meritd.nodes.push({ client: { - estimateFee: estimateFee - } + estimateFee: estimateFee, + }, }); meritd.estimateFee(1, function(err) { should.exist(err); @@ -4349,12 +4376,12 @@ describe('Merit Service', function() { it('will call client estimateFee and give result', function(done) { var meritd = new MeritService(baseConfig); var estimateFee = sinon.stub().callsArgWith(1, null, { - result: -1 + result: -1, }); meritd.nodes.push({ client: { - estimateFee: estimateFee - } + estimateFee: estimateFee, + }, }); meritd.estimateFee(1, function(err, feesPerKb) { if (err) { @@ -4370,11 +4397,11 @@ describe('Merit Service', function() { var tx = meritcore.Transaction(txhex); it('will give rpc error', function() { var meritd = new MeritService(baseConfig); - var sendRawTransaction = sinon.stub().callsArgWith(2, {message: 'error', code: -1}); + var sendRawTransaction = sinon.stub().callsArgWith(2, { message: 'error', code: -1 }); meritd.nodes.push({ client: { - sendRawTransaction: sendRawTransaction - } + sendRawTransaction: sendRawTransaction, + }, }); meritd.sendTransaction(txhex, function(err) { should.exist(err); @@ -4384,12 +4411,12 @@ describe('Merit Service', function() { it('will send to client and get hash', function() { var meritd = new MeritService(baseConfig); var sendRawTransaction = sinon.stub().callsArgWith(2, null, { - result: tx.hash + result: tx.hash, }); meritd.nodes.push({ client: { - sendRawTransaction: sendRawTransaction - } + sendRawTransaction: sendRawTransaction, + }, }); meritd.sendTransaction(txhex, function(err, hash) { if (err) { @@ -4401,14 +4428,14 @@ describe('Merit Service', function() { it('will send to client with absurd fees and get hash', function() { var meritd = new MeritService(baseConfig); var sendRawTransaction = sinon.stub().callsArgWith(2, null, { - result: tx.hash + result: tx.hash, }); meritd.nodes.push({ client: { - sendRawTransaction: sendRawTransaction - } + sendRawTransaction: sendRawTransaction, + }, }); - meritd.sendTransaction(txhex, {allowAbsurdFees: true}, function(err, hash) { + meritd.sendTransaction(txhex, { allowAbsurdFees: true }, function(err, hash) { if (err) { return done(err); } @@ -4418,28 +4445,28 @@ describe('Merit Service', function() { it('missing callback will throw error', function() { var meritd = new MeritService(baseConfig); var sendRawTransaction = sinon.stub().callsArgWith(2, null, { - result: tx.hash + result: tx.hash, }); meritd.nodes.push({ client: { - sendRawTransaction: sendRawTransaction - } + sendRawTransaction: sendRawTransaction, + }, }); var transaction = meritcore.Transaction(); (function() { meritd.sendTransaction(transaction); - }).should.throw(Error); + }.should.throw(Error)); }); }); describe('#getRawTransaction', function() { it('will give rpc error', function(done) { var meritd = new MeritService(baseConfig); - var getRawTransaction = sinon.stub().callsArgWith(1, {message: 'error', code: -1}); + var getRawTransaction = sinon.stub().callsArgWith(1, { message: 'error', code: -1 }); meritd.nodes.push({ client: { - getRawTransaction: getRawTransaction - } + getRawTransaction: getRawTransaction, + }, }); meritd.getRawTransaction('txid', function(err) { should.exist(err); @@ -4450,24 +4477,24 @@ describe('Merit Service', function() { it('will try all nodes', function(done) { var meritd = new MeritService(baseConfig); meritd.tryAllInterval = 1; - var getRawTransactionWithError = sinon.stub().callsArgWith(1, {message: 'error', code: -1}); + var getRawTransactionWithError = sinon.stub().callsArgWith(1, { message: 'error', code: -1 }); var getRawTransaction = sinon.stub().callsArgWith(1, null, { - result: txhex + result: txhex, }); meritd.nodes.push({ client: { - getRawTransaction: getRawTransactionWithError - } + getRawTransaction: getRawTransactionWithError, + }, }); meritd.nodes.push({ client: { - getRawTransaction: getRawTransactionWithError - } + getRawTransaction: getRawTransactionWithError, + }, }); meritd.nodes.push({ client: { - getRawTransaction: getRawTransaction - } + getRawTransaction: getRawTransaction, + }, }); meritd.getRawTransaction('txid', function(err, tx) { if (err) { @@ -4481,12 +4508,12 @@ describe('Merit Service', function() { it('will get from cache', function(done) { var meritd = new MeritService(baseConfig); var getRawTransaction = sinon.stub().callsArgWith(1, null, { - result: txhex + result: txhex, }); meritd.nodes.push({ client: { - getRawTransaction: getRawTransaction - } + getRawTransaction: getRawTransaction, + }, }); meritd.getRawTransaction('txid', function(err, tx) { if (err) { @@ -4508,11 +4535,11 @@ describe('Merit Service', function() { describe('#getTransaction', function() { it('will give rpc error', function(done) { var meritd = new MeritService(baseConfig); - var getRawTransaction = sinon.stub().callsArgWith(1, {message: 'error', code: -1}); + var getRawTransaction = sinon.stub().callsArgWith(1, { message: 'error', code: -1 }); meritd.nodes.push({ client: { - getRawTransaction: getRawTransaction - } + getRawTransaction: getRawTransaction, + }, }); meritd.getTransaction('txid', function(err) { should.exist(err); @@ -4523,24 +4550,24 @@ describe('Merit Service', function() { it('will try all nodes', function(done) { var meritd = new MeritService(baseConfig); meritd.tryAllInterval = 1; - var getRawTransactionWithError = sinon.stub().callsArgWith(1, {message: 'error', code: -1}); + var getRawTransactionWithError = sinon.stub().callsArgWith(1, { message: 'error', code: -1 }); var getRawTransaction = sinon.stub().callsArgWith(1, null, { - result: txhex + result: txhex, }); meritd.nodes.push({ client: { - getRawTransaction: getRawTransactionWithError - } + getRawTransaction: getRawTransactionWithError, + }, }); meritd.nodes.push({ client: { - getRawTransaction: getRawTransactionWithError - } + getRawTransaction: getRawTransactionWithError, + }, }); meritd.nodes.push({ client: { - getRawTransaction: getRawTransaction - } + getRawTransaction: getRawTransaction, + }, }); meritd.getTransaction('txid', function(err, tx) { if (err) { @@ -4554,12 +4581,12 @@ describe('Merit Service', function() { it('will get from cache', function(done) { var meritd = new MeritService(baseConfig); var getRawTransaction = sinon.stub().callsArgWith(1, null, { - result: txhex + result: txhex, }); meritd.nodes.push({ client: { - getRawTransaction: getRawTransaction - } + getRawTransaction: getRawTransaction, + }, }); meritd.getTransaction('txid', function(err, tx) { if (err) { @@ -4574,18 +4601,20 @@ describe('Merit Service', function() { getRawTransaction.callCount.should.equal(1); done(); }); - }); }); }); describe('#getDetailedTransaction', function() { - var txBuffer = new Buffer('01000000016f95980911e01c2c664b3e78299527a47933aac61a515930a8fe0213d1ac9abe01000000da0047304402200e71cda1f71e087c018759ba3427eb968a9ea0b1decd24147f91544629b17b4f0220555ee111ed0fc0f751ffebf097bdf40da0154466eb044e72b6b3dcd5f06807fa01483045022100c86d6c8b417bff6cc3bbf4854c16bba0aaca957e8f73e19f37216e2b06bb7bf802205a37be2f57a83a1b5a8cc511dc61466c11e9ba053c363302e7b99674be6a49fc0147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a9148a31d53a448c18996e81ce67811e5fb7da21e4468738c9d6f90000000017a9148ce5408cfeaddb7ccb2545ded41ef478109454848700000000', 'hex'); + var txBuffer = new Buffer( + '01000000016f95980911e01c2c664b3e78299527a47933aac61a515930a8fe0213d1ac9abe01000000da0047304402200e71cda1f71e087c018759ba3427eb968a9ea0b1decd24147f91544629b17b4f0220555ee111ed0fc0f751ffebf097bdf40da0154466eb044e72b6b3dcd5f06807fa01483045022100c86d6c8b417bff6cc3bbf4854c16bba0aaca957e8f73e19f37216e2b06bb7bf802205a37be2f57a83a1b5a8cc511dc61466c11e9ba053c363302e7b99674be6a49fc0147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a9148a31d53a448c18996e81ce67811e5fb7da21e4468738c9d6f90000000017a9148ce5408cfeaddb7ccb2545ded41ef478109454848700000000', + 'hex', + ); var info = { blockHash: '00000000000ec715852ea2ecae4dc8563f62d603c820f81ac284cd5be0a944d6', height: 530482, timestamp: 1439559434000, - buffer: txBuffer + buffer: txBuffer, }; var rpcRawTransaction = { hex: txBuffer.toString('hex'), @@ -4599,13 +4628,13 @@ describe('Merit Service', function() { valueMicros: 110, address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW', txid: '3d003413c13eec3fa8ea1fe8bbff6f40718c66facffe2544d7516c9e2900cac2', - sequence: 0xFFFFFFFF, + sequence: 0xffffffff, vout: 0, scriptSig: { hex: 'scriptSigHex', - asm: 'scriptSigAsm' - } - } + asm: 'scriptSigAsm', + }, + }, ], vout: [ { @@ -4616,17 +4645,17 @@ describe('Merit Service', function() { scriptPubKey: { hex: '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac', asm: 'OP_DUP OP_HASH160 0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc OP_EQUALVERIFY OP_CHECKSIG', - addresses: ['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'] - } - } - ] + addresses: ['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'], + }, + }, + ], }; it('should give a transaction with height and timestamp', function(done) { var meritd = new MeritService(baseConfig); meritd.nodes.push({ client: { - getRawTransaction: sinon.stub().callsArgWith(2, {code: -1, message: 'Test error'}) - } + getRawTransaction: sinon.stub().callsArgWith(2, { code: -1, message: 'Test error' }), + }, }); var txid = '2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f'; meritd.getDetailedTransaction(txid, function(err) { @@ -4638,12 +4667,12 @@ describe('Merit Service', function() { it('should give a transaction with all properties', function(done) { var meritd = new MeritService(baseConfig); var getRawTransaction = sinon.stub().callsArgWith(2, null, { - result: rpcRawTransaction + result: rpcRawTransaction, }); meritd.nodes.push({ client: { - getRawTransaction: getRawTransaction - } + getRawTransaction: getRawTransaction, + }, }); var txid = '2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f'; function checkTx(tx) { @@ -4663,14 +4692,17 @@ describe('Merit Service', function() { should.equal(input.prevTxId, '3d003413c13eec3fa8ea1fe8bbff6f40718c66facffe2544d7516c9e2900cac2'); should.equal(input.outputIndex, 0); should.equal(input.micros, 110); - should.equal(input.sequence, 0xFFFFFFFF); + should.equal(input.sequence, 0xffffffff); should.equal(input.script, 'scriptSigHex'); should.equal(input.scriptAsm, 'scriptSigAsm'); should.equal(input.address, 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'); var output = tx.outputs[0]; should.equal(output.micros, 100); should.equal(output.script, '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'); - should.equal(output.scriptAsm, 'OP_DUP OP_HASH160 0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc OP_EQUALVERIFY OP_CHECKSIG'); + should.equal( + output.scriptAsm, + 'OP_DUP OP_HASH160 0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc OP_EQUALVERIFY OP_CHECKSIG', + ); should.equal(output.address, 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'); should.equal(output.spentTxId, '4316b98e7504073acd19308b4b8c9f4eeb5e811455c54c0ebfe276c0b1eb6315'); should.equal(output.spentIndex, 2); @@ -4693,19 +4725,19 @@ describe('Merit Service', function() { }); it('should set coinbase to true', function(done) { var meritd = new MeritService(baseConfig); - var rawTransaction = JSON.parse((JSON.stringify(rpcRawTransaction))); + var rawTransaction = JSON.parse(JSON.stringify(rpcRawTransaction)); delete rawTransaction.vin[0]; rawTransaction.vin = [ { - coinbase: 'abcdef' - } + coinbase: 'abcdef', + }, ]; meritd.nodes.push({ client: { getRawTransaction: sinon.stub().callsArgWith(2, null, { - result: rawTransaction - }) - } + result: rawTransaction, + }), + }, }); var txid = '2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f'; meritd.getDetailedTransaction(txid, function(err, tx) { @@ -4716,14 +4748,14 @@ describe('Merit Service', function() { }); it('will not include address if address length is zero', function(done) { var meritd = new MeritService(baseConfig); - var rawTransaction = JSON.parse((JSON.stringify(rpcRawTransaction))); + var rawTransaction = JSON.parse(JSON.stringify(rpcRawTransaction)); rawTransaction.vout[0].scriptPubKey.addresses = []; meritd.nodes.push({ client: { getRawTransaction: sinon.stub().callsArgWith(2, null, { - result: rawTransaction - }) - } + result: rawTransaction, + }), + }, }); var txid = '2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f'; meritd.getDetailedTransaction(txid, function(err, tx) { @@ -4734,14 +4766,14 @@ describe('Merit Service', function() { }); it('will not include address if address length is greater than 1', function(done) { var meritd = new MeritService(baseConfig); - var rawTransaction = JSON.parse((JSON.stringify(rpcRawTransaction))); + var rawTransaction = JSON.parse(JSON.stringify(rpcRawTransaction)); rawTransaction.vout[0].scriptPubKey.addresses = ['one', 'two']; meritd.nodes.push({ client: { getRawTransaction: sinon.stub().callsArgWith(2, null, { - result: rawTransaction - }) - } + result: rawTransaction, + }), + }, }); var txid = '2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f'; meritd.getDetailedTransaction(txid, function(err, tx) { @@ -4752,14 +4784,14 @@ describe('Merit Service', function() { }); it('will handle scriptPubKey.addresses not being set', function(done) { var meritd = new MeritService(baseConfig); - var rawTransaction = JSON.parse((JSON.stringify(rpcRawTransaction))); + var rawTransaction = JSON.parse(JSON.stringify(rpcRawTransaction)); delete rawTransaction.vout[0].scriptPubKey['addresses']; meritd.nodes.push({ client: { getRawTransaction: sinon.stub().callsArgWith(2, null, { - result: rawTransaction - }) - } + result: rawTransaction, + }), + }, }); var txid = '2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f'; meritd.getDetailedTransaction(txid, function(err, tx) { @@ -4770,15 +4802,15 @@ describe('Merit Service', function() { }); it('will not include script if input missing scriptSig or coinbase', function(done) { var meritd = new MeritService(baseConfig); - var rawTransaction = JSON.parse((JSON.stringify(rpcRawTransaction))); + var rawTransaction = JSON.parse(JSON.stringify(rpcRawTransaction)); delete rawTransaction.vin[0].scriptSig; delete rawTransaction.vin[0].coinbase; meritd.nodes.push({ client: { getRawTransaction: sinon.stub().callsArgWith(2, null, { - result: rawTransaction - }) - } + result: rawTransaction, + }), + }, }); var txid = '2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f'; meritd.getDetailedTransaction(txid, function(err, tx) { @@ -4789,14 +4821,14 @@ describe('Merit Service', function() { }); it('will set height to -1 if missing height', function(done) { var meritd = new MeritService(baseConfig); - var rawTransaction = JSON.parse((JSON.stringify(rpcRawTransaction))); + var rawTransaction = JSON.parse(JSON.stringify(rpcRawTransaction)); delete rawTransaction.height; meritd.nodes.push({ client: { getRawTransaction: sinon.stub().callsArgWith(2, null, { - result: rawTransaction - }) - } + result: rawTransaction, + }), + }, }); var txid = '2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f'; meritd.getDetailedTransaction(txid, function(err, tx) { @@ -4810,11 +4842,11 @@ describe('Merit Service', function() { describe('#getBestBlockHash', function() { it('will give rpc error', function(done) { var meritd = new MeritService(baseConfig); - var getBestBlockHash = sinon.stub().callsArgWith(0, {message: 'error', code: -1}); + var getBestBlockHash = sinon.stub().callsArgWith(0, { message: 'error', code: -1 }); meritd.nodes.push({ client: { - getBestBlockHash: getBestBlockHash - } + getBestBlockHash: getBestBlockHash, + }, }); meritd.getBestBlockHash(function(err) { should.exist(err); @@ -4825,12 +4857,12 @@ describe('Merit Service', function() { it('will call client getInfo and give result', function(done) { var meritd = new MeritService(baseConfig); var getBestBlockHash = sinon.stub().callsArgWith(0, null, { - result: 'besthash' + result: 'besthash', }); meritd.nodes.push({ client: { - getBestBlockHash: getBestBlockHash - } + getBestBlockHash: getBestBlockHash, + }, }); meritd.getBestBlockHash(function(err, hash) { if (err) { @@ -4846,11 +4878,11 @@ describe('Merit Service', function() { describe('#getSpentInfo', function() { it('will give rpc error', function(done) { var meritd = new MeritService(baseConfig); - var getSpentInfo = sinon.stub().callsArgWith(1, {message: 'error', code: -1}); + var getSpentInfo = sinon.stub().callsArgWith(1, { message: 'error', code: -1 }); meritd.nodes.push({ client: { - getSpentInfo: getSpentInfo - } + getSpentInfo: getSpentInfo, + }, }); meritd.getSpentInfo({}, function(err) { should.exist(err); @@ -4860,11 +4892,11 @@ describe('Merit Service', function() { }); it('will empty object when not found', function(done) { var meritd = new MeritService(baseConfig); - var getSpentInfo = sinon.stub().callsArgWith(1, {message: 'test', code: -5}); + var getSpentInfo = sinon.stub().callsArgWith(1, { message: 'test', code: -5 }); meritd.nodes.push({ client: { - getSpentInfo: getSpentInfo - } + getSpentInfo: getSpentInfo, + }, }); meritd.getSpentInfo({}, function(err, info) { should.not.exist(err); @@ -4878,13 +4910,13 @@ describe('Merit Service', function() { result: { txid: 'txid', index: 10, - height: 101 - } + height: 101, + }, }); meritd.nodes.push({ client: { - getSpentInfo: getSpentInfo - } + getSpentInfo: getSpentInfo, + }, }); meritd.getSpentInfo({}, function(err, info) { if (err) { @@ -4901,11 +4933,11 @@ describe('Merit Service', function() { describe('#getInfo', function() { it('will give rpc error', function(done) { var meritd = new MeritService(baseConfig); - var getInfo = sinon.stub().callsArgWith(0, {message: 'error', code: -1}); + var getInfo = sinon.stub().callsArgWith(0, { message: 'error', code: -1 }); meritd.nodes.push({ client: { - getInfo: getInfo - } + getInfo: getInfo, + }, }); meritd.getInfo(function(err) { should.exist(err); @@ -4927,13 +4959,13 @@ describe('Merit Service', function() { difficulty: 1, testnet: true, relayfee: 10, - errors: '' - } + errors: '', + }, }); meritd.nodes.push({ client: { - getInfo: getInfo - } + getInfo: getInfo, + }, }); meritd.getInfo(function(err, info) { if (err) { @@ -4959,11 +4991,11 @@ describe('Merit Service', function() { describe('#generateBlock', function() { it('will give rpc error', function(done) { var meritd = new MeritService(baseConfig); - var generate = sinon.stub().callsArgWith(1, {message: 'error', code: -1}); + var generate = sinon.stub().callsArgWith(1, { message: 'error', code: -1 }); meritd.nodes.push({ client: { - generate: generate - } + generate: generate, + }, }); meritd.generateBlock(10, function(err) { should.exist(err); @@ -4974,12 +5006,12 @@ describe('Merit Service', function() { it('will call client generate and give result', function(done) { var meritd = new MeritService(baseConfig); var generate = sinon.stub().callsArgWith(1, null, { - result: ['hash'] + result: ['hash'], }); meritd.nodes.push({ client: { - generate: generate - } + generate: generate, + }, }); meritd.generateBlock(10, function(err, hashes) { if (err) { @@ -5035,5 +5067,4 @@ describe('Merit Service', function() { meritd.spawn.process.kill.args[0][0].should.equal('SIGINT'); }); }); - }); diff --git a/packages/merit-node/test/services/web.unit.js b/packages/merit-node/test/services/web.unit.js index b57d07b4b8..41f71860a1 100644 --- a/packages/merit-node/test/services/web.unit.js +++ b/packages/merit-node/test/services/web.unit.js @@ -9,15 +9,15 @@ var index = require('../../lib'); var log = index.log; var httpStub = { - createServer: sinon.spy() + createServer: sinon.spy(), }; var httpsStub = { - createServer: sinon.spy() + createServer: sinon.spy(), }; var fsStub = { readFileSync: function(arg1) { return arg1 + '-buffer'; - } + }, }; var fakeSocketListener = new EventEmitter(); @@ -30,24 +30,24 @@ fakeSocket.on('test/event1', function(data) { fakeSocketListener.emit('connection', fakeSocket); fakeSocket.emit('subscribe', 'test/event1'); -var WebService = proxyquire('../../lib/services/web', {http: httpStub, https: httpsStub, fs: fsStub}); +var WebService = proxyquire('../../lib/services/web', { http: httpStub, https: httpsStub, fs: fsStub }); describe('WebService', function() { var defaultNode = new EventEmitter(); describe('@constructor', function() { it('will set socket rpc settings', function() { - var web = new WebService({node: defaultNode, enableSocketRPC: false}); + var web = new WebService({ node: defaultNode, enableSocketRPC: false }); web.enableSocketRPC.should.equal(false); - var web2 = new WebService({node: defaultNode, enableSocketRPC: true}); + var web2 = new WebService({ node: defaultNode, enableSocketRPC: true }); web2.enableSocketRPC.should.equal(true); - var web3 = new WebService({node: defaultNode}); + var web3 = new WebService({ node: defaultNode }); web3.enableSocketRPC.should.equal(WebService.DEFAULT_SOCKET_RPC); }); it('will set configuration options for max payload', function() { - var web = new WebService({node: defaultNode, jsonRequestLimit: '200kb'}); + var web = new WebService({ node: defaultNode, jsonRequestLimit: '200kb' }); web.jsonRequestLimit.should.equal('200kb'); }); }); @@ -58,7 +58,7 @@ describe('WebService', function() { httpsStub.createServer.reset(); }); it('should create an http server if no options are specified and node is not configured for https', function(done) { - var web = new WebService({node: defaultNode}); + var web = new WebService({ node: defaultNode }); web.deriveHttpsOptions = sinon.spy(); web.start(function(err) { should.not.exist(err); @@ -71,7 +71,7 @@ describe('WebService', function() { var node = new EventEmitter(); node.https = true; - var web = new WebService({node: node}); + var web = new WebService({ node: node }); web.transformHttpsOptions = sinon.spy(); web.start(function(err) { should.not.exist(err); @@ -84,25 +84,25 @@ describe('WebService', function() { var jsonStub = sinon.stub(); var TestWebService = proxyquire('../../lib/services/web', { http: { - createServer: sinon.stub() + createServer: sinon.stub(), }, https: { - createServer: sinon.stub() + createServer: sinon.stub(), }, fs: fsStub, express: sinon.stub().returns({ - use: sinon.stub() + use: sinon.stub(), }), 'body-parser': { - json: jsonStub + json: jsonStub, }, 'socket.io': { listen: sinon.stub().returns({ - on: sinon.stub() - }) - } + on: sinon.stub(), + }), + }, }); - var web = new TestWebService({node: node}); + var web = new TestWebService({ node: node }); web.start(function(err) { if (err) { return done(err); @@ -116,9 +116,9 @@ describe('WebService', function() { describe('#stop', function() { it('should close the server if it exists', function(done) { - var web = new WebService({node: defaultNode}); + var web = new WebService({ node: defaultNode }); web.server = { - close: sinon.spy() + close: sinon.spy(), }; web.stop(function(err) { @@ -136,18 +136,18 @@ describe('WebService', function() { services: { one: { setupRoutes: sinon.spy(), - getRoutePrefix: sinon.stub().returns('one') + getRoutePrefix: sinon.stub().returns('one'), }, two: { setupRoutes: sinon.spy(), - getRoutePrefix: sinon.stub().returns('two') - } - } + getRoutePrefix: sinon.stub().returns('two'), + }, + }, }; - var web = new WebService({node: node}); + var web = new WebService({ node: node }); web.app = { - use: sinon.spy() + use: sinon.spy(), }; web.setupAllRoutes(); @@ -164,10 +164,7 @@ describe('WebService', function() { it('should create the methodsMap correctly', function(done) { var Module1 = function() {}; Module1.prototype.getAPIMethods = function() { - return [ - ['one', this, this.one, 1], - ['two', this, this.two, 2] - ]; + return [['one', this, this.one, 1], ['two', this, this.two, 2]]; }; Module1.prototype.one = function(param1, callback) { callback(null, param1); @@ -180,10 +177,10 @@ describe('WebService', function() { var node = { on: sinon.spy(), - getAllAPIMethods: sinon.stub().returns(module1.getAPIMethods()) + getAllAPIMethods: sinon.stub().returns(module1.getAPIMethods()), }; - var web = new WebService({node: node}); + var web = new WebService({ node: node }); web.createMethodsMap(); Object.keys(web.methodsMap).length.should.equal(2); @@ -209,18 +206,18 @@ describe('WebService', function() { return [ { name: 'event1', - extraEvents: ['event2'] - } + extraEvents: ['event2'], + }, ]; }; var module1 = new Module1(); var node = { on: sinon.spy(), - getAllPublishEvents: sinon.stub().returns(module1.getPublishEvents()) + getAllPublishEvents: sinon.stub().returns(module1.getPublishEvents()), }; - var web = new WebService({node: node}); + var web = new WebService({ node: node }); var events = web.getEventNames(); events.should.deep.equal(['event1', 'event2']); @@ -232,39 +229,39 @@ describe('WebService', function() { return [ { name: 'event1', - extraEvents: ['event1'] - } + extraEvents: ['event1'], + }, ]; }; var module1 = new Module1(); var node = { on: sinon.spy(), - getAllPublishEvents: sinon.stub().returns(module1.getPublishEvents()) + getAllPublishEvents: sinon.stub().returns(module1.getPublishEvents()), }; - var web = new WebService({node: node}); + var web = new WebService({ node: node }); (function() { var events = web.getEventNames(); - }).should.throw('Duplicate event event1'); + }.should.throw('Duplicate event event1')); }); }); describe('#_getRemoteAddress', function() { it('will get remote address from cloudflare header', function() { - var web = new WebService({node: defaultNode}); + var web = new WebService({ node: defaultNode }); var socket = {}; socket.conn = {}; socket.client = {}; socket.client.request = {}; socket.client.request.headers = { - 'cf-connecting-ip': '127.0.0.1' + 'cf-connecting-ip': '127.0.0.1', }; var remoteAddress = web._getRemoteAddress(socket); remoteAddress.should.equal('127.0.0.1'); }); it('will get remote address from connection', function() { - var web = new WebService({node: defaultNode}); + var web = new WebService({ node: defaultNode }); var socket = {}; socket.conn = {}; socket.conn.remoteAddress = '127.0.0.1'; @@ -293,8 +290,8 @@ describe('WebService', function() { return [ { name: 'event1', - extraEvents: ['event2'] - } + extraEvents: ['event2'], + }, ]; }; @@ -302,14 +299,14 @@ describe('WebService', function() { var node = { on: sinon.spy(), openBus: sinon.stub().returns(bus), - getAllPublishEvents: sinon.stub().returns(module1.getPublishEvents()) + getAllPublishEvents: sinon.stub().returns(module1.getPublishEvents()), }; var web; var socket; it('on message should call socketMessageHandler', function(done) { - web = new WebService({node: node}); + web = new WebService({ node: node }); web.eventNames = web.getEventNames(); web.socketMessageHandler = function(param1) { param1.should.equal('data'); @@ -326,7 +323,7 @@ describe('WebService', function() { }); it('on message should NOT call socketMessageHandler if not enabled', function(done) { - web = new WebService({node: node, enableSocketRPC: false}); + web = new WebService({ node: node, enableSocketRPC: false }); web.eventNames = web.getEventNames(); web.socketMessageHandler = sinon.stub(); socket = new EventEmitter(); @@ -382,28 +379,28 @@ describe('WebService', function() { describe('#socketMessageHandler', function() { var node = { - on: sinon.spy() + on: sinon.spy(), }; - var web = new WebService({node: node}); + var web = new WebService({ node: node }); web.methodsMap = { one: { fn: function(param1, param2, callback) { var result = param1 + param2; - if(result > 0) { + if (result > 0) { return callback(null, result); } else { return callback(new Error('error')); } }, - args: 2 - } + args: 2, + }, }; it('should give a Method Not Found error if method does not exist', function(done) { var message = { method: 'two', - params: [1, 2] + params: [1, 2], }; web.socketMessageHandler(message, function(response) { should.exist(response.error); @@ -415,7 +412,7 @@ describe('WebService', function() { it('should call the method and return the result', function(done) { var message = { method: 'one', - params: [1, 2] + params: [1, 2], }; web.socketMessageHandler(message, function(response) { should.not.exist(response.error); @@ -427,7 +424,7 @@ describe('WebService', function() { it('should give an error if there is a param count mismatch', function(done) { var message = { method: 'one', - params: [1] + params: [1], }; web.socketMessageHandler(message, function(response) { should.exist(response.error); @@ -439,7 +436,7 @@ describe('WebService', function() { it('should give an error if the method gave an error', function(done) { var message = { method: 'one', - params: [-1, -2] + params: [-1, -2], }; web.socketMessageHandler(message, function(response) { should.exist(response.error); @@ -456,8 +453,8 @@ describe('WebService', function() { https: true, httpsOptions: { key: 'key', - cert: 'cert' - } + cert: 'cert', + }, }); web.transformHttpsOptions(); @@ -469,14 +466,13 @@ describe('WebService', function() { node: defaultNode, https: true, httpsOptions: { - key: 'key' - } + key: 'key', + }, }); (function() { web.transformHttpsOptions(); - }).should.throw('Missing https options'); + }.should.throw('Missing https options')); }); }); - }); diff --git a/packages/merit-node/test/utils.unit.js b/packages/merit-node/test/utils.unit.js index ff166b8304..76c8cc64c2 100644 --- a/packages/merit-node/test/utils.unit.js +++ b/packages/merit-node/test/utils.unit.js @@ -4,9 +4,7 @@ var should = require('chai').should(); var utils = require('../lib/utils'); describe('Utils', function() { - describe('#isHash', function() { - it('false for short string', function() { var a = utils.isHash('ashortstring'); a.should.equal(false); @@ -36,11 +34,9 @@ describe('Utils', function() { var a = utils.isHash('fc63629e2106c3440d7e56751adc8cfa5266a5920c1b54b81565af25aec1998b'); a.should.equal(true); }); - }); describe('#isSafeNatural', function() { - it('false for float', function() { var a = utils.isSafeNatural(0.1); a.should.equal(false); @@ -85,11 +81,9 @@ describe('Utils', function() { var a = utils.isSafeNatural(1000); a.should.equal(true); }); - }); describe('#startAtZero', function() { - it('will set key to zero if not set', function() { var obj = {}; utils.startAtZero(obj, 'key'); @@ -98,7 +92,7 @@ describe('Utils', function() { it('not if already set', function() { var obj = { - key: 10 + key: 10, }; utils.startAtZero(obj, 'key'); obj.key.should.equal(10); @@ -106,7 +100,7 @@ describe('Utils', function() { it('not if set to false', function() { var obj = { - key: false + key: false, }; utils.startAtZero(obj, 'key'); obj.key.should.equal(false); @@ -114,7 +108,7 @@ describe('Utils', function() { it('not if set to undefined', function() { var obj = { - key: undefined + key: undefined, }; utils.startAtZero(obj, 'key'); should.equal(obj.key, undefined); @@ -122,19 +116,18 @@ describe('Utils', function() { it('not if set to null', function() { var obj = { - key: null + key: null, }; utils.startAtZero(obj, 'key'); should.equal(obj.key, null); }); - }); describe('#parseParamsWithJSON', function() { it('will parse object', function() { var paramsArg = ['3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou', '{"start": 100, "end": 1}']; var params = utils.parseParamsWithJSON(paramsArg); - params.should.deep.equal(['3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou', {start: 100, end: 1}]); + params.should.deep.equal(['3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou', { start: 100, end: 1 }]); }); it('will parse array', function() { var paramsArg = ['3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou', '[0, 1]']; @@ -147,5 +140,4 @@ describe('Utils', function() { params.should.deep.equal([3, 0, 'b', 0, 0x12, 0.0001]); }); }); - }); diff --git a/packages/merit-p2p/README.md b/packages/merit-p2p/README.md index 6d6e6c5762..972a495b5d 100644 --- a/packages/merit-p2p/README.md +++ b/packages/merit-p2p/README.md @@ -1,5 +1,4 @@ -Meritcore P2P -======= +# Meritcore P2P Merit P2P prottocol library. @@ -8,12 +7,13 @@ Merit P2P prottocol library. ```sh npm install merit-p2p ``` + In order to connect to the Merit network, you'll need to know the IP address of at least one node of the network, or use pool to discover peers using a DNS seed. ```javascript var Peer = require('merit-p2p').Peer; -var peer = new Peer({host: '127.0.0.1'}); +var peer = new Peer({ host: '127.0.0.1' }); peer.on('ready', function() { // peer info diff --git a/packages/merit-p2p/docs/index.md b/packages/merit-p2p/docs/index.md index 5357795f1e..c7250afd34 100644 --- a/packages/merit-p2p/docs/index.md +++ b/packages/merit-p2p/docs/index.md @@ -1,7 +1,9 @@ # Peer-to-Peer + The `merit-p2p` module provides peer-to-peer networking capabilities for LWS, and includes [Peer](peer.md) and [Pool](pool.md) classes. A [Message](messages.md) class is also exposed, in addition to [several types of messages](messages.md). Pool will maintain connection to several peers, Peers represents a node in the Merit network, and Message represents data sent to and from a Peer. For detailed technical information about the Merit protocol. ## Installation + Peer-to-peer is implemented as a separate module, that is shipped with Merit Lightwallet Stack. For node projects: @@ -14,7 +16,7 @@ npm install merit-p2p --save ```javascript var Peer = require('merit-p2p').Peer; -var peer = new Peer({host: '5.9.85.34'}); +var peer = new Peer({ host: '5.9.85.34' }); // handle events peer.on('inv', function(message) { diff --git a/packages/merit-p2p/docs/messages.md b/packages/merit-p2p/docs/messages.md index 14e924b88c..614c3bd3d7 100644 --- a/packages/merit-p2p/docs/messages.md +++ b/packages/merit-p2p/docs/messages.md @@ -29,52 +29,65 @@ Note: A list of further messages is available below. For advanced usage, you can also customize which constructor is used for Block and Transaction messages by passing it as an argument to Messages, for example: ```javascript -var messages = new Messages({Block: MyBlock, Transaction: MyTransaction}); +var messages = new Messages({ Block: MyBlock, Transaction: MyTransaction }); ``` And additionally a custom network: ```javascript -var messages = new Messages({network: Networks.testnet}); +var messages = new Messages({ network: Networks.testnet }); ``` ## List of Messages + ### Version + The version message (`ver`) is used on connection creation, to advertise the type of node. The remote node will respond with its version, and no communication is possible until both peers have exchanged their versions. ### VerAck + Finishes the connection handshake started by the `ver` message. ### Inventory + From the Merit protocol spec: "Allows a node to advertise its knowledge of one or more objects. It can be received unsolicited, or in reply to getblocks.". ### GetData + From the Merit protocol spec: `getdata` is used in response to `inv`, to retrieve the content of a specific object, and is usually sent after receiving an `inv` packet, after filtering known elements. It can be used to retrieve transactions, but only if they are in the memory pool or relay set - arbitrary access to transactions in the chain is not allowed to avoid having clients start to depend on nodes having full transaction indexes (which modern nodes do not). GetData inherits from Inventory, as they both have the same structure. ### NotFound + notfound is a response to a getdata, sent if any requested data items could not be relayed, for example, because the requested transaction was not in the memory pool or relay set. Contains inventory information specifying which items were not found. ### Ping + Sent to another peer mainly to check the connection is still alive. ### Pong + Sent in response to a `ping` message. ### Address and GetAddresses + Provides information on known nodes of the network. `GetAddresses` is used to query another peer for known addresses. ### GetHeaders and Headers + `getheaders` allows a peer to query another about blockheaders. `headers` is sent in response to a `getheaders` message, containing information about block headers. ### GetBlocks and Block + Same as `getheaders` and `headers`, but the response comes one block at the time. ### Transaction + Message that contains a transaction. ## Custom Messages + It is possible to extend the default peer to peer messages and add custom ones. First you will need to create a message which resembles the default messages in `lib/messages/commands`. Then to add the custom message: diff --git a/packages/merit-p2p/docs/peer.md b/packages/merit-p2p/docs/peer.md index a61974c39d..e297b80a3a 100644 --- a/packages/merit-p2p/docs/peer.md +++ b/packages/merit-p2p/docs/peer.md @@ -1,26 +1,30 @@ # Peer + Represents a node from the p2p Merit network. The Peer class supports connecting directly to other nodes or through a socks5 proxy like Tor. ## Creating a peer + The code to create a new peer looks like this: ```javascript var Peer = require('merit-p2p').Peer; // default port -var livenetPeer = new Peer({host: '5.9.85.34'}); -var testnetPeer = new Peer({host: '5.9.85.34', network: Networks.testnet}); +var livenetPeer = new Peer({ host: '5.9.85.34' }); +var testnetPeer = new Peer({ host: '5.9.85.34', network: Networks.testnet }); // custom port -var livenetPeer = new Peer({host: '5.9.85.34', port: 8334}); -var testnetPeer = new Peer({host: '5.9.85.34', port: 18334, network: Networks.testnet}); +var livenetPeer = new Peer({ host: '5.9.85.34', port: 8334 }); +var testnetPeer = new Peer({ host: '5.9.85.34', port: 18334, network: Networks.testnet }); // use sock5 proxy (Tor) -var peer = new Peer({host: '5.9.85.34'}).setProxy('localhost', 9050); +var peer = new Peer({ host: '5.9.85.34' }).setProxy('localhost', 9050); ``` ## States + A peer instance is always in one of the following states: + - `disconnected`: No connection with the remote node. - `connecting`: While establishing the connection. - `connected`: Exchanging version packages. @@ -31,7 +35,7 @@ You can subscribe to the change of those states as follows: ```javascript var Peer = require('merit-p2p').Peer; -var peer = new Peer({host: '5.9.85.34'}); +var peer = new Peer({ host: '5.9.85.34' }); peer.on('ready', function() { // peer info @@ -46,11 +50,12 @@ peer.connect(); ``` ## Handle messages + Once connected, a peer instance can send and receive messages. Every time a message arrives it's emitted as a new event. Let's see an example of this: ```javascript var Peer = require('merit-p2p').Peer; -var peer = new Peer({host: '5.9.85.34'}); +var peer = new Peer({ host: '5.9.85.34' }); // handle events peer.on('inv', function(message) { @@ -69,15 +74,16 @@ peer.connect(); ``` ## Sending messages + In order to send messages the Peer class offers the `sendMessage(message)` method, which receives an instance of a message. All supported messages can be found in the `Messages` module. For more information about messages refer to the [protocol specification](https://en.bitcoin.it/wiki/Protocol_specification). An example for requesting other connected nodes to a peers looks like this: ```javascript -var p2p = require('merit-p2p') +var p2p = require('merit-p2p'); var Peer = p2p.Peer; var Messages = p2p.Messages; -var peer = new Peer({host: '5.9.85.34'}); +var peer = new Peer({ host: '5.9.85.34' }); peer.on('ready', function() { var message = new Messages.GetAddresses(); diff --git a/packages/merit-p2p/docs/pool.md b/packages/merit-p2p/docs/pool.md index 5c9685f57e..8f921e7ba3 100644 --- a/packages/merit-p2p/docs/pool.md +++ b/packages/merit-p2p/docs/pool.md @@ -1,14 +1,14 @@ # Pool + A pool maintains a connection of [Peers](peer.md). A pool will discover peers via DNS seeds, as well as when peer addresses are announced through the network. The quickest way to get connected is to run the following: ```javascript - var Pool = require('merit-p2p').Pool; var Networks = require('meritcore-lib').Networks; -var pool = new Pool({network: Networks.livenet}); +var pool = new Pool({ network: Networks.livenet }); // connect to the network pool.connect(); @@ -19,37 +19,39 @@ pool.on('peerinv', function(peer, message) { }); // will disconnect all peers -pool.disconnect() +pool.disconnect(); ``` For more information about Peer events please read the [Peer](peer.md) documentation. Peer events are relayed to the pool, a peer event `inv` in the pool would be `peerinv`. When a peer is disconnected the pool will try to connect to the list of known addresses to maintain connection. ## Trusted Peers + By default, peers will be added via DNS discovery and as peers are announced in the network. Configuration options can be included to connect only to specific trusted peers: ```javascript - var pool = new Pool({ network: Networks.livenet, // the network object dnsSeed: false, // prevent seeding with DNS discovered known peers upon connecting listenAddr: false, // prevent new peers being added from addr messages - addrs: [ // initial peers to connect to + addrs: [ + // initial peers to connect to { ip: { - v4: '127.0.0.1' - } - } - ] + v4: '127.0.0.1', + }, + }, + ], }); pool.connect(); ``` ## Listening for Peers + It's also possible to listen to incoming socket connections to add peers to the pool. To enable this capability, you can do the following: ```javascript -var pool = new Pool({network: Networks.livenet}); +var pool = new Pool({ network: Networks.livenet }); pool.listen(); ``` diff --git a/packages/merit-p2p/gulpfile.js b/packages/merit-p2p/gulpfile.js index dfccc70e31..982cd0eaaa 100644 --- a/packages/merit-p2p/gulpfile.js +++ b/packages/merit-p2p/gulpfile.js @@ -3,6 +3,6 @@ var gulp = require('gulp'); var meritTasks = require('merit-build'); -meritTasks('p2p', {skipBrowser: true}); +meritTasks('p2p', { skipBrowser: true }); gulp.task('default', ['lint', 'coverage']); diff --git a/packages/merit-p2p/integration/bitcoind.js b/packages/merit-p2p/integration/bitcoind.js index 2016790a32..2a5684c92d 100644 --- a/packages/merit-p2p/integration/bitcoind.js +++ b/packages/merit-p2p/integration/bitcoind.js @@ -23,28 +23,27 @@ var Transaction = meritcore.Transaction; // config var network = process.env.NETWORK === 'testnet' ? Networks.testnet : Networks.livenet; var messages = new Messages({ - network: network + network: network, }); var blockHash = { - 'livenet': '000000000000000013413cf2536b491bf0988f52e90c476ffeb701c8bfdb1db9', - 'testnet': '0000000058cc069d964711cd25083c0a709f4df2b34c8ff9302ce71fe5b45786' + livenet: '000000000000000013413cf2536b491bf0988f52e90c476ffeb701c8bfdb1db9', + testnet: '0000000058cc069d964711cd25083c0a709f4df2b34c8ff9302ce71fe5b45786', }; var stopBlock = { - 'livenet': '00000000000000000b539ef570128acb953af3dbcfc19dd8e6066949672311a1', - 'testnet': '00000000d0bc4271bcefaa7eb25000e345910ba16b91eb375cd944b68624de9f' + livenet: '00000000000000000b539ef570128acb953af3dbcfc19dd8e6066949672311a1', + testnet: '00000000d0bc4271bcefaa7eb25000e345910ba16b91eb375cd944b68624de9f', }; var txHash = { - 'livenet': '22231e8219a0617a0ded618b5dc713fdf9b0db8ebd5bb3322d3011a703119d3b', - 'testnet': '22231e8219a0617a0ded618b5dc713fdf9b0db8ebd5bb3322d3011a703119d3b' + livenet: '22231e8219a0617a0ded618b5dc713fdf9b0db8ebd5bb3322d3011a703119d3b', + testnet: '22231e8219a0617a0ded618b5dc713fdf9b0db8ebd5bb3322d3011a703119d3b', }; // These tests require a running meritd instance describe(`Integration with ${network.name} meritd`, function() { - this.timeout(15000); var opts = { host: 'localhost', - network: network.name + network: network.name, }; it('handshakes', function(cb) { var peer = new Peer(opts); @@ -123,10 +122,12 @@ describe(`Integration with ${network.name} meritd`, function() { it('sends tx inv and receives getdata for that tx', function(cb) { connect(function(peer) { var type = Inventory.TYPE.TX; - var inv = [{ - type: type, - hash: new Buffer(Random.getRandomBuffer(32)) // needs to be random for repeatability - }]; + var inv = [ + { + type: type, + hash: new Buffer(Random.getRandomBuffer(32)), // needs to be random for repeatability + }, + ]; peer.once('getdata', function(message) { message.inventory[0].should.deep.equal(inv[0]); cb(); @@ -172,7 +173,7 @@ describe(`Integration with ${network.name} meritd`, function() { }); var message = messages.GetHeaders({ starts: from, - stop: stop + stop: stop, }); peer.sendMessage(message); }); @@ -189,7 +190,7 @@ describe(`Integration with ${network.name} meritd`, function() { }); var message = messages.GetBlocks({ starts: from, - stop: stop + stop: stop, }); peer.sendMessage(message); }); diff --git a/packages/merit-p2p/karma.conf.js b/packages/merit-p2p/karma.conf.js index dc5d5970ef..dfe1002c72 100644 --- a/packages/merit-p2p/karma.conf.js +++ b/packages/merit-p2p/karma.conf.js @@ -2,7 +2,6 @@ // karma.conf.js module.exports = function(config) { - config.set({ browsers: ['Firefox'], frameworks: ['mocha', 'detectBrowsers'], @@ -13,24 +12,16 @@ module.exports = function(config) { // modify to enable additional browsers if available var runBrowsers = ['Firefox', 'Chrome']; var browsers = []; - for(var i = 0; i < runBrowsers.length; i++) { - if(~availableBrowser.indexOf(runBrowsers[i])) { + for (var i = 0; i < runBrowsers.length; i++) { + if (~availableBrowser.indexOf(runBrowsers[i])) { browsers.push(runBrowsers[i]); } } return browsers; - } + }, }, singleRun: true, - files: [ - 'tests.js' - ], - plugins: [ - 'karma-mocha', - 'karma-chrome-launcher', - 'karma-firefox-launcher', - 'karma-detect-browsers' - ] + files: ['tests.js'], + plugins: ['karma-mocha', 'karma-chrome-launcher', 'karma-firefox-launcher', 'karma-detect-browsers'], }); - }; diff --git a/packages/merit-p2p/lib/bloomfilter.js b/packages/merit-p2p/lib/bloomfilter.js index 59ad45a3f1..83a7ded344 100644 --- a/packages/merit-p2p/lib/bloomfilter.js +++ b/packages/merit-p2p/lib/bloomfilter.js @@ -15,7 +15,7 @@ BloomFilter.fromBuffer = function fromBuffer(payload) { var parser = new BufferReader(payload); var length = parser.readVarintNum(); obj.vData = []; - for(var i = 0; i < length; i++) { + for (var i = 0; i < length; i++) { obj.vData.push(parser.readUInt8()); } obj.nHashFuncs = parser.readUInt32LE(); @@ -30,7 +30,7 @@ BloomFilter.fromBuffer = function fromBuffer(payload) { BloomFilter.prototype.toBuffer = function toBuffer() { var bw = new BufferWriter(); bw.writeVarintNum(this.vData.length); - for(var i = 0; i < this.vData.length; i++) { + for (var i = 0; i < this.vData.length; i++) { bw.writeUInt8(this.vData[i]); } bw.writeUInt32LE(this.nHashFuncs); diff --git a/packages/merit-p2p/lib/buffers.js b/packages/merit-p2p/lib/buffers.js index f96333639e..d8c17b663d 100644 --- a/packages/merit-p2p/lib/buffers.js +++ b/packages/merit-p2p/lib/buffers.js @@ -20,4 +20,3 @@ Buffers.prototype.skip = function(i) { }; module.exports = Buffers; - diff --git a/packages/merit-p2p/lib/errors.js b/packages/merit-p2p/lib/errors.js index dcfa9da513..8b9ced558a 100644 --- a/packages/merit-p2p/lib/errors.js +++ b/packages/merit-p2p/lib/errors.js @@ -2,7 +2,7 @@ var spec = { name: 'P2P', - message: 'Internal Error on merit-p2p Module {0}' + message: 'Internal Error on merit-p2p Module {0}', }; module.exports = require('meritcore-lib').errors.extend(spec); diff --git a/packages/merit-p2p/lib/index.js b/packages/merit-p2p/lib/index.js index f4f5552efb..e2c7936cdf 100644 --- a/packages/merit-p2p/lib/index.js +++ b/packages/merit-p2p/lib/index.js @@ -7,5 +7,5 @@ module.exports = { BloomFilter: require('./bloomfilter'), Messages: require('./messages'), Peer: require('./peer'), - Pool: require('./pool') + Pool: require('./pool'), }; diff --git a/packages/merit-p2p/lib/inventory.js b/packages/merit-p2p/lib/inventory.js index 552ae70f4f..229e8e34c6 100644 --- a/packages/merit-p2p/lib/inventory.js +++ b/packages/merit-p2p/lib/inventory.js @@ -35,7 +35,7 @@ Inventory.forItem = function(type, hash) { hash = new Buffer(hash, 'hex'); hash = BufferUtil.reverse(hash); } - return new Inventory({type: type, hash: hash}); + return new Inventory({ type: type, hash: hash }); }; /** @@ -111,11 +111,6 @@ Inventory.TYPE.ERROR = 0; Inventory.TYPE.TX = 1; Inventory.TYPE.BLOCK = 2; Inventory.TYPE.FILTERED_BLOCK = 3; -Inventory.TYPE_NAME = [ - 'ERROR', - 'TX', - 'BLOCK', - 'FILTERED_BLOCK' -]; +Inventory.TYPE_NAME = ['ERROR', 'TX', 'BLOCK', 'FILTERED_BLOCK']; module.exports = Inventory; diff --git a/packages/merit-p2p/lib/messages/builder.js b/packages/merit-p2p/lib/messages/builder.js index ea6d69cbcd..f396225e87 100644 --- a/packages/merit-p2p/lib/messages/builder.js +++ b/packages/merit-p2p/lib/messages/builder.js @@ -26,17 +26,13 @@ function builder(options) { Block: options.Block, BlockHeader: options.BlockHeader, Transaction: options.Transaction, - MerkleBlock: options.MerkleBlock + MerkleBlock: options.MerkleBlock, }, defaults: { protocolVersion: options.protocolVersion, - network: options.network + network: options.network, }, - inventoryCommands: [ - 'getdata', - 'inv', - 'notfound' - ], + inventoryCommands: ['getdata', 'inv', 'notfound'], commandsMap: { version: 'Version', verack: 'VerAck', @@ -58,9 +54,9 @@ function builder(options) { getblocks: 'GetBlocks', getheaders: 'GetHeaders', mempool: 'MemPool', - getaddr: 'GetAddr' + getaddr: 'GetAddr', }, - commands: {} + commands: {}, }; exported.add = function(key, Command) { @@ -82,7 +78,6 @@ function builder(options) { }); exported.inventoryCommands.forEach(function(command) { - // add forTransaction methods exported.commands[command].forTransaction = function forTransaction(hash) { return new exported.commands[command]([Inventory.forTransaction(hash)]); @@ -97,11 +92,9 @@ function builder(options) { exported.commands[command].forFilteredBlock = function forFilteredBlock(hash) { return new exported.commands[command]([Inventory.forFilteredBlock(hash)]); }; - }); return exported; - } module.exports = builder; diff --git a/packages/merit-p2p/lib/messages/commands/addr.js b/packages/merit-p2p/lib/messages/commands/addr.js index a371e0ebd9..60907822db 100644 --- a/packages/merit-p2p/lib/messages/commands/addr.js +++ b/packages/merit-p2p/lib/messages/commands/addr.js @@ -21,10 +21,10 @@ function AddrMessage(arg, options) { $.checkArgument( _.isUndefined(arg) || (Array.isArray(arg) && - !_.isUndefined(arg[0].services) && - !_.isUndefined(arg[0].ip) && - !_.isUndefined(arg[0].port)), - 'First argument is expected to be an array of addrs' + !_.isUndefined(arg[0].services) && + !_.isUndefined(arg[0].ip) && + !_.isUndefined(arg[0].port)), + 'First argument is expected to be an array of addrs', ); this.addresses = arg; } diff --git a/packages/merit-p2p/lib/messages/commands/block.js b/packages/merit-p2p/lib/messages/commands/block.js index e957743c36..61de570e23 100644 --- a/packages/merit-p2p/lib/messages/commands/block.js +++ b/packages/merit-p2p/lib/messages/commands/block.js @@ -17,10 +17,7 @@ function BlockMessage(arg, options) { Message.call(this, options); this.Block = options.Block; this.command = 'block'; - $.checkArgument( - _.isUndefined(arg) || arg instanceof this.Block, - 'An instance of Block or undefined is expected' - ); + $.checkArgument(_.isUndefined(arg) || arg instanceof this.Block, 'An instance of Block or undefined is expected'); this.block = arg; } inherits(BlockMessage, Message); diff --git a/packages/merit-p2p/lib/messages/commands/filteradd.js b/packages/merit-p2p/lib/messages/commands/filteradd.js index 0209ed681e..2fcead8a4d 100644 --- a/packages/merit-p2p/lib/messages/commands/filteradd.js +++ b/packages/merit-p2p/lib/messages/commands/filteradd.js @@ -22,7 +22,7 @@ function FilteraddMessage(arg, options) { this.command = 'filteradd'; $.checkArgument( _.isUndefined(arg) || BufferUtil.isBuffer(arg), - 'First argument is expected to be a Buffer or undefined' + 'First argument is expected to be a Buffer or undefined', ); this.data = arg || BufferUtil.EMPTY_BUFFER; } diff --git a/packages/merit-p2p/lib/messages/commands/filterload.js b/packages/merit-p2p/lib/messages/commands/filterload.js index 24654b5b74..53dbbe6f66 100644 --- a/packages/merit-p2p/lib/messages/commands/filterload.js +++ b/packages/merit-p2p/lib/messages/commands/filterload.js @@ -20,7 +20,7 @@ function FilterloadMessage(arg, options) { this.command = 'filterload'; $.checkArgument( _.isUndefined(arg) || arg instanceof BloomFilter, - 'An instance of BloomFilter or undefined is expected' + 'An instance of BloomFilter or undefined is expected', ); this.filter = arg; } @@ -31,7 +31,7 @@ FilterloadMessage.prototype.setPayload = function(payload) { }; FilterloadMessage.prototype.getPayload = function() { - if(this.filter) { + if (this.filter) { return this.filter.toBuffer(); } else { return BufferUtil.EMPTY_BUFFER; diff --git a/packages/merit-p2p/lib/messages/commands/getdata.js b/packages/merit-p2p/lib/messages/commands/getdata.js index ce98bf886e..b4fd83b73e 100644 --- a/packages/merit-p2p/lib/messages/commands/getdata.js +++ b/packages/merit-p2p/lib/messages/commands/getdata.js @@ -30,7 +30,7 @@ GetdataMessage.prototype.setPayload = function(payload) { for (var i = 0; i < count; i++) { var type = parser.readUInt32LE(); var hash = parser.read(32); - this.inventory.push({type: type, hash: hash}); + this.inventory.push({ type: type, hash: hash }); } utils.checkFinished(parser); diff --git a/packages/merit-p2p/lib/messages/commands/headers.js b/packages/merit-p2p/lib/messages/commands/headers.js index b3c048614b..7742bbc497 100644 --- a/packages/merit-p2p/lib/messages/commands/headers.js +++ b/packages/merit-p2p/lib/messages/commands/headers.js @@ -25,7 +25,7 @@ function HeadersMessage(arg, options) { this.command = 'headers'; $.checkArgument( _.isUndefined(arg) || (Array.isArray(arg) && arg[0] instanceof this.BlockHeader), - 'First argument is expected to be an array of BlockHeader instances' + 'First argument is expected to be an array of BlockHeader instances', ); this.headers = arg; } diff --git a/packages/merit-p2p/lib/messages/commands/inv.js b/packages/merit-p2p/lib/messages/commands/inv.js index 25f19a0253..dc159faf04 100644 --- a/packages/merit-p2p/lib/messages/commands/inv.js +++ b/packages/merit-p2p/lib/messages/commands/inv.js @@ -31,7 +31,7 @@ InvMessage.prototype.setPayload = function(payload) { for (var i = 0; i < count; i++) { var type = parser.readUInt32LE(); var hash = parser.read(32); - this.inventory.push({type: type, hash: hash}); + this.inventory.push({ type: type, hash: hash }); } utils.checkFinished(parser); diff --git a/packages/merit-p2p/lib/messages/commands/merkleblock.js b/packages/merit-p2p/lib/messages/commands/merkleblock.js index 638c9ac40e..c9876c6c7c 100644 --- a/packages/merit-p2p/lib/messages/commands/merkleblock.js +++ b/packages/merit-p2p/lib/messages/commands/merkleblock.js @@ -22,7 +22,7 @@ function MerkleblockMessage(arg, options) { this.command = 'merkleblock'; $.checkArgument( _.isUndefined(arg) || arg instanceof this.MerkleBlock, - 'An instance of MerkleBlock or undefined is expected' + 'An instance of MerkleBlock or undefined is expected', ); this.merkleBlock = arg; } diff --git a/packages/merit-p2p/lib/messages/commands/notfound.js b/packages/merit-p2p/lib/messages/commands/notfound.js index a533754fd7..8f8e9221d1 100644 --- a/packages/merit-p2p/lib/messages/commands/notfound.js +++ b/packages/merit-p2p/lib/messages/commands/notfound.js @@ -31,7 +31,7 @@ NotfoundMessage.prototype.setPayload = function(payload) { for (var i = 0; i < count; i++) { var type = parser.readUInt32LE(); var hash = parser.read(32); - this.inventory.push({type: type, hash: hash}); + this.inventory.push({ type: type, hash: hash }); } utils.checkFinished(parser); diff --git a/packages/merit-p2p/lib/messages/commands/ping.js b/packages/merit-p2p/lib/messages/commands/ping.js index 630a6d02a6..fc9990edd7 100644 --- a/packages/merit-p2p/lib/messages/commands/ping.js +++ b/packages/merit-p2p/lib/messages/commands/ping.js @@ -21,7 +21,7 @@ function PingMessage(arg, options) { this.command = 'ping'; $.checkArgument( _.isUndefined(arg) || (BufferUtil.isBuffer(arg) && arg.length === 8), - 'First argument is expected to be an 8 byte buffer' + 'First argument is expected to be an 8 byte buffer', ); this.nonce = arg || utils.getNonce(); } diff --git a/packages/merit-p2p/lib/messages/commands/pong.js b/packages/merit-p2p/lib/messages/commands/pong.js index 9c211a89ce..3f71beb9e0 100644 --- a/packages/merit-p2p/lib/messages/commands/pong.js +++ b/packages/merit-p2p/lib/messages/commands/pong.js @@ -21,7 +21,7 @@ function PongMessage(arg, options) { this.command = 'pong'; $.checkArgument( _.isUndefined(arg) || (BufferUtil.isBuffer(arg) && arg.length === 8), - 'First argument is expected to be an 8 byte buffer' + 'First argument is expected to be an 8 byte buffer', ); this.nonce = arg || utils.getNonce(); } diff --git a/packages/merit-p2p/lib/messages/commands/reject.js b/packages/merit-p2p/lib/messages/commands/reject.js index ecc7888db4..a442a1afb0 100644 --- a/packages/merit-p2p/lib/messages/commands/reject.js +++ b/packages/merit-p2p/lib/messages/commands/reject.js @@ -41,7 +41,7 @@ RejectMessage.CCODE = { REJECT_NONSTANDARD: 0x40, REJECT_DUST: 0x41, REJECT_INSUFFICIENTFEE: 0x42, - REJECT_CHECKPOINT: 0x43 + REJECT_CHECKPOINT: 0x43, }; RejectMessage.prototype.setPayload = function(payload) { diff --git a/packages/merit-p2p/lib/messages/commands/tx.js b/packages/merit-p2p/lib/messages/commands/tx.js index c8bf93e702..a7642c6832 100644 --- a/packages/merit-p2p/lib/messages/commands/tx.js +++ b/packages/merit-p2p/lib/messages/commands/tx.js @@ -18,7 +18,7 @@ function TransactionMessage(arg, options) { this.Transaction = options.Transaction; $.checkArgument( _.isUndefined(arg) || arg instanceof this.Transaction, - 'An instance of Transaction or undefined is expected' + 'An instance of Transaction or undefined is expected', ); this.transaction = arg; if (!this.transaction) { diff --git a/packages/merit-p2p/lib/messages/commands/version.js b/packages/merit-p2p/lib/messages/commands/version.js index 36c4752e16..868f949572 100644 --- a/packages/merit-p2p/lib/messages/commands/version.js +++ b/packages/merit-p2p/lib/messages/commands/version.js @@ -52,18 +52,18 @@ VersionMessage.prototype.setPayload = function(payload) { this.addrMe = { services: parser.readUInt64LEBN(), ip: utils.parseIP(parser), - port: parser.readUInt16BE() + port: parser.readUInt16BE(), }; this.addrYou = { services: parser.readUInt64LEBN(), ip: utils.parseIP(parser), - port: parser.readUInt16BE() + port: parser.readUInt16BE(), }; this.nonce = parser.read(8); this.subversion = parser.readVarLengthBuffer().toString(); this.startHeight = parser.readUInt32LE(); - if(parser.finished()) { + if (parser.finished()) { this.relay = true; } else { this.relay = !!parser.readUInt8(); diff --git a/packages/merit-p2p/lib/messages/index.js b/packages/merit-p2p/lib/messages/index.js index ada812e886..fc7e35ff5f 100644 --- a/packages/merit-p2p/lib/messages/index.js +++ b/packages/merit-p2p/lib/messages/index.js @@ -1,4 +1,4 @@ - 'use strict'; +'use strict'; var meritcore = require('meritcore-lib'); var BufferUtil = meritcore.util.buffer; @@ -19,7 +19,7 @@ function Messages(options) { this.builder = Messages.builder(options); // map message constructors by name - for(var key in this.builder.commandsMap) { + for (var key in this.builder.commandsMap) { var name = this.builder.commandsMap[key]; this[name] = this.builder.commands[key]; } @@ -49,7 +49,8 @@ Messages.prototype.parseBuffer = function(dataBuffer) { return; } - var payloadLen = (dataBuffer.get(Messages.PAYLOAD_START)) + + var payloadLen = + dataBuffer.get(Messages.PAYLOAD_START) + (dataBuffer.get(Messages.PAYLOAD_START + 1) << 8) + (dataBuffer.get(Messages.PAYLOAD_START + 2) << 16) + (dataBuffer.get(Messages.PAYLOAD_START + 3) << 24); @@ -59,7 +60,10 @@ Messages.prototype.parseBuffer = function(dataBuffer) { return; } - var command = dataBuffer.slice(4, 16).toString('ascii').replace(/\0+$/, ''); + var command = dataBuffer + .slice(4, 16) + .toString('ascii') + .replace(/\0+$/, ''); var payload = dataBuffer.slice(24, messageLength); var checksum = dataBuffer.slice(20, 24); @@ -87,7 +91,7 @@ Messages.prototype._discardUntilNextMessage = function(dataBuffer) { } // did we reach the end of the buffer? - if (i > (dataBuffer.length - 4)) { + if (i > dataBuffer.length - 4) { dataBuffer.skip(i); return false; } diff --git a/packages/merit-p2p/lib/messages/utils.js b/packages/merit-p2p/lib/messages/utils.js index d3e3e238a2..1db741ec13 100644 --- a/packages/merit-p2p/lib/messages/utils.js +++ b/packages/merit-p2p/lib/messages/utils.js @@ -12,11 +12,11 @@ module.exports = utils = { _.isUndefined(arg) || (Array.isArray(arg) && arg.length === 0) || (Array.isArray(arg) && !_.isUndefined(arg[0].type) && !_.isUndefined(arg[0].hash)), - 'Argument is expected to be an array of inventory objects' + 'Argument is expected to be an array of inventory objects', ); }, checkFinished: function checkFinished(parser) { - if(!parser.finished()) { + if (!parser.finished()) { throw new Error('Data still available after parsing'); } }, @@ -65,7 +65,7 @@ module.exports = utils = { ipv4 = ipv4.join('.'); return { v6: ipv6, - v4: ipv4 + v4: ipv4, }; }, parseAddr: function parseAddr(parser) { @@ -75,7 +75,7 @@ module.exports = utils = { return { services: services, ip: ip, - port: port + port: port, }; }, sanitizeStartStop: function sanitizeStartStop(obj) { @@ -113,5 +113,5 @@ module.exports = utils = { obj.stop = stop; return obj; - } + }, }; diff --git a/packages/merit-p2p/lib/peer.js b/packages/merit-p2p/lib/peer.js index 961834620d..3b7a143ee7 100644 --- a/packages/merit-p2p/lib/peer.js +++ b/packages/merit-p2p/lib/peer.js @@ -63,11 +63,13 @@ function Peer(options) { this.port = this.network.port; } - this.messages = options.messages || new Messages({ - network: this.network, - Block: meritcore.Block, - Transaction: meritcore.Transaction - }); + this.messages = + options.messages || + new Messages({ + network: this.network, + Block: meritcore.Block, + Transaction: meritcore.Transaction, + }); this.dataBuffer = new Buffers(); @@ -93,7 +95,7 @@ function Peer(options) { var verackResponse = self.messages.VerAck(); self.sendMessage(verackResponse); - if(!self.versionSent) { + if (!self.versionSent) { self._sendVersion(); } }); @@ -103,7 +105,6 @@ function Peer(options) { }); return this; - } util.inherits(Peer, EventEmitter); @@ -112,7 +113,7 @@ Peer.STATUS = { DISCONNECTED: 'disconnected', CONNECTING: 'connecting', CONNECTED: 'connected', - READY: 'ready' + READY: 'ready', }; /** @@ -126,7 +127,7 @@ Peer.prototype.setProxy = function(host, port) { this.proxy = { host: host, - port: port + port: port, }; return this; }; @@ -147,7 +148,10 @@ Peer.prototype.connect = function() { }); this._addSocketEventHandlers(); - this.socket.connect(this.port, this.host); + this.socket.connect( + this.port, + this.host, + ); return this; }; @@ -199,7 +203,7 @@ Peer.prototype.sendMessage = function(message) { */ Peer.prototype._sendVersion = function() { // todo: include sending local ip address - var message = this.messages.Version({relay: this.relay}); + var message = this.messages.Version({ relay: this.relay }); this.versionSent = true; this.sendMessage(message); }; diff --git a/packages/merit-p2p/lib/pool.js b/packages/merit-p2p/lib/pool.js index 8ab52f3bb5..824e913613 100644 --- a/packages/merit-p2p/lib/pool.js +++ b/packages/merit-p2p/lib/pool.js @@ -58,7 +58,7 @@ function Pool(options) { this.relay = options.relay === false ? false : true; if (options.addrs) { - for(var i = 0; i < options.addrs.length; i++) { + for (var i = 0; i < options.addrs.length; i++) { this._addAddr(options.addrs[i]); } } @@ -69,7 +69,7 @@ function Pool(options) { var length = addrs.length; for (var i = 0; i < length; i++) { var addr = addrs[i]; - var future = new Date().getTime() + (10 * 60 * 1000); + var future = new Date().getTime() + 10 * 60 * 1000; if (addr.time.getTime() <= 100000000000 || addr.time.getTime() > future) { // In case of an invalid time, assume "5 days ago" var past = new Date(new Date().getTime() - 5 * 24 * 60 * 60 * 1000); @@ -84,8 +84,8 @@ function Pool(options) { ips.forEach(function(ip) { self._addAddr({ ip: { - v4: ip - } + v4: ip, + }, }); }); if (self.keepalive) { @@ -102,17 +102,33 @@ function Pool(options) { }); return this; - } util.inherits(Pool, EventEmitter); Pool.MaxConnectedPeers = 8; Pool.RetrySeconds = 30; -Pool.PeerEvents = ['version', 'inv', 'getdata', 'ping', 'pong', 'addr', - 'getaddr', 'verack', 'reject', 'alert', 'headers', 'block', 'merkleblock', - 'tx', 'getblocks', 'getheaders', 'error', 'filterload', 'filteradd', - 'filterclear' +Pool.PeerEvents = [ + 'version', + 'inv', + 'getdata', + 'ping', + 'pong', + 'addr', + 'getaddr', + 'verack', + 'reject', + 'alert', + 'headers', + 'block', + 'merkleblock', + 'tx', + 'getblocks', + 'getheaders', + 'error', + 'filterload', + 'filteradd', + 'filterclear', ]; /** @@ -194,7 +210,7 @@ Pool.prototype._connectPeer = function _connectPeer(addr) { port: port, messages: self.messages, network: this.network, - relay: self.relay + relay: self.relay, }); peer.on('connect', function peerConnect() { @@ -222,7 +238,7 @@ Pool.prototype._addConnectedPeer = function _addConnectedPeer(socket, addr) { var peer = new Peer({ socket: socket, network: this.network, - messages: self.messages + messages: self.messages, }); self._addPeerEventHandlers(peer, addr); @@ -335,10 +351,15 @@ Pool.prototype._addAddrsFromSeeds = function _addAddrsFromSeeds() { * @returns {String} A string formatted for the console */ Pool.prototype.inspect = function inspect() { - return ''; + return ( + '' + ); }; /** @@ -347,7 +368,7 @@ Pool.prototype.inspect = function inspect() { */ Pool.prototype.sendMessage = function(message) { // broadcast to peers - for(var key in this._connectedPeers) { + for (var key in this._connectedPeers) { var peer = this._connectedPeers[key]; peer.sendMessage(message); } @@ -363,9 +384,9 @@ Pool.prototype.listen = function() { // Create server this.server = net.createServer(function(socket) { var addr = { - ip: {} + ip: {}, }; - if(net.isIPv6(socket.remoteAddress)) { + if (net.isIPv6(socket.remoteAddress)) { addr.ip.v6 = socket.remoteAddress; } else { addr.ip.v4 = socket.remoteAddress; diff --git a/packages/merit-p2p/test/bloomfilter.js b/packages/merit-p2p/test/bloomfilter.js index 59b4b28f0b..ea50175746 100644 --- a/packages/merit-p2p/test/bloomfilter.js +++ b/packages/merit-p2p/test/bloomfilter.js @@ -25,7 +25,6 @@ function ParseHex(str) { } describe('BloomFilter', function() { - it('#fromBuffer and #toBuffer round trip', function() { var testPayloadBuffer = getPayloadBuffer(Data.filterload.message); var filter = new BloomFilter.fromBuffer(testPayloadBuffer); @@ -35,7 +34,6 @@ describe('BloomFilter', function() { // test data from: https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp it('serialize filter with public keys added', function() { - var privateKey = meritcore.PrivateKey.fromWIF('5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C'); var publicKey = privateKey.toPublicKey(); @@ -46,11 +44,9 @@ describe('BloomFilter', function() { var expectedFilter = BloomFilter.fromBuffer(ParseHex('038fc16b080000000000000001')); filter.toBuffer().should.deep.equal(expectedFilter.toBuffer()); - }); it('serialize to a buffer', function() { - var filter = BloomFilter.create(3, 0.01, 0, BloomFilter.BLOOM_UPDATE_ALL); filter.insert(ParseHex('99108ad8ed9bb6274d3980bab5a85c048f0950c8')); @@ -58,7 +54,7 @@ describe('BloomFilter', function() { // one bit different in first byte assert(!filter.contains(ParseHex('19108ad8ed9bb6274d3980bab5a85c048f0950c8'))); filter.insert(ParseHex('b5a2c786d9ef4658287ced5914b37a1b4aa32eee')); - assert(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee"))); + assert(filter.contains(ParseHex('b5a2c786d9ef4658287ced5914b37a1b4aa32eee'))); filter.insert(ParseHex('b9300670b4c5366e95b2699e8b18bc75e5f729c5')); assert(filter.contains(ParseHex('b9300670b4c5366e95b2699e8b18bc75e5f729c5'))); @@ -68,21 +64,19 @@ describe('BloomFilter', function() { actual.should.deep.equal(expected); }); - it('deserialize a buffer', function() { - - var buffer = new Buffer('03614e9b050000000000000001', 'hex'); - var filter = BloomFilter.fromBuffer(buffer); - - assert(filter.contains(ParseHex('99108ad8ed9bb6274d3980bab5a85c048f0950c8'))); - assert(!filter.contains(ParseHex('19108ad8ed9bb6274d3980bab5a85c048f0950c8'))); - assert(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee"))); - assert(filter.contains(ParseHex('b9300670b4c5366e95b2699e8b18bc75e5f729c5'))); - }); + it('deserialize a buffer', function() { + var buffer = new Buffer('03614e9b050000000000000001', 'hex'); + var filter = BloomFilter.fromBuffer(buffer); - it('#toBuffer and #fromBuffer round trip, with a large filter', function() { - var filter = BloomFilter.create(10000, 0.001); - var buffer = filter.toBuffer(); - new BloomFilter.fromBuffer(buffer).should.deep.equal(filter); - }); + assert(filter.contains(ParseHex('99108ad8ed9bb6274d3980bab5a85c048f0950c8'))); + assert(!filter.contains(ParseHex('19108ad8ed9bb6274d3980bab5a85c048f0950c8'))); + assert(filter.contains(ParseHex('b5a2c786d9ef4658287ced5914b37a1b4aa32eee'))); + assert(filter.contains(ParseHex('b9300670b4c5366e95b2699e8b18bc75e5f729c5'))); + }); + it('#toBuffer and #fromBuffer round trip, with a large filter', function() { + var filter = BloomFilter.create(10000, 0.001); + var buffer = filter.toBuffer(); + new BloomFilter.fromBuffer(buffer).should.deep.equal(filter); + }); }); diff --git a/packages/merit-p2p/test/buffers.js b/packages/merit-p2p/test/buffers.js index 0dc7c2be94..5e60a3ee0f 100644 --- a/packages/merit-p2p/test/buffers.js +++ b/packages/merit-p2p/test/buffers.js @@ -5,7 +5,6 @@ var should = chai.should(); var Buffers = require('../lib/buffers'); describe('Buffers', function() { - var buffs = function buffs() { var b = new Buffers(); b.push(new Buffer('0123', 'hex')); @@ -59,5 +58,4 @@ describe('Buffers', function() { b.length.should.equal(1); b.buffers[0].should.deep.equal(new Buffer('ef', 'hex')); }); - }); diff --git a/packages/merit-p2p/test/inventory.js b/packages/merit-p2p/test/inventory.js index 5272406ca1..c012da80ca 100644 --- a/packages/merit-p2p/test/inventory.js +++ b/packages/merit-p2p/test/inventory.js @@ -12,27 +12,22 @@ var BufferWriter = meritcore.encoding.BufferWriter; var BufferReader = meritcore.encoding.BufferReader; describe('Inventory', function() { - var hash = new Buffer('eb951630aba498b9a0d10f72b5ea9e39d5ff04b03dc2231e662f52057f948aa1', 'hex'); var hashedStr = BufferUtils.reverse(new Buffer(hash, 'hex')).toString('hex'); - var inventoryBuffer = new Buffer( - '01000000eb951630aba498b9a0d10f72b5ea9e39d5ff04b03dc2231e662f52057f948aa1', - 'hex' - ); + var inventoryBuffer = new Buffer('01000000eb951630aba498b9a0d10f72b5ea9e39d5ff04b03dc2231e662f52057f948aa1', 'hex'); describe('@constructor', function() { it('create inventory', function() { - var inventory = new Inventory({type: Inventory.TYPE.TX, hash: hash}); + var inventory = new Inventory({ type: Inventory.TYPE.TX, hash: hash }); should.exist(inventory); }); it('error with string hash', function() { (function() { - var inventory = new Inventory({type: Inventory.TYPE.TX, hash: hashedStr}); + var inventory = new Inventory({ type: Inventory.TYPE.TX, hash: hashedStr }); should.not.exist(inventory); - }).should.throw('Unexpected hash'); + }.should.throw('Unexpected hash')); }); - }); describe('#forItem', function() { @@ -41,7 +36,6 @@ describe('Inventory', function() { should.exist(inventory); inventory.hash.should.deep.equal(new Buffer(hash, 'hex')); }); - }); describe('#forBlock', function() { @@ -103,5 +97,4 @@ describe('Inventory', function() { inventory.hash.should.deep.equal(hash); }); }); - }); diff --git a/packages/merit-p2p/test/messages/builder.js b/packages/merit-p2p/test/messages/builder.js index b95856ce9e..89e5a1175a 100644 --- a/packages/merit-p2p/test/messages/builder.js +++ b/packages/merit-p2p/test/messages/builder.js @@ -6,9 +6,7 @@ var builder = P2P.Messages.builder; var meritcore = require('meritcore-lib'); describe('Messages Builder', function() { - describe('@constructor', function() { - it('should return commands based on default', function() { // instantiate var b = builder(); @@ -20,11 +18,9 @@ describe('Messages Builder', function() { var b = builder({ network: meritcore.Networks.testnet, Block: meritcore.Block, - Transaction: meritcore.Transaction + Transaction: meritcore.Transaction, }); should.exist(b); }); - }); - }); diff --git a/packages/merit-p2p/test/messages/commands/index.js b/packages/merit-p2p/test/messages/commands/index.js index 536738da80..d7fef903bc 100644 --- a/packages/merit-p2p/test/messages/commands/index.js +++ b/packages/merit-p2p/test/messages/commands/index.js @@ -8,43 +8,40 @@ var sinon = require('sinon'); var meritcore = require('meritcore-lib'); describe('Command Messages', function() { - var messages = new Messages(); describe('Addr', function() { - it('should error if arg is not an array of addrs', function() { (function() { var message = messages.Addresses(['not an addr']); - }).should.throw('First argument is expected to be an array of addrs'); + }.should.throw('First argument is expected to be an array of addrs')); }); it('should instantiate with an array of addrs', function() { - var message = messages.Addresses([{ - ip: { - v4: 'localhost' + var message = messages.Addresses([ + { + ip: { + v4: 'localhost', + }, + services: 1, + port: 1234, }, - services: 1, - port: 1234 - }]); + ]); }); }); describe('Alert', function() { - it('should accept a transaction instance as an argument', function() { var message = messages.Alert({ payload: new Buffer('abcdef', 'hex'), - signature: new Buffer('123456', 'hex') + signature: new Buffer('123456', 'hex'), }); message.payload.should.deep.equal(new Buffer('abcdef', 'hex')); message.signature.should.deep.equal(new Buffer('123456', 'hex')); }); - }); describe('Transaction', function() { - it('should accept a transaction instance as an argument', function() { var tx = new meritcore.Transaction(); var message = messages.Transaction(tx); @@ -62,34 +59,30 @@ describe('Command Messages', function() { var message = messages.Transaction(tx); message.transaction.version.should.equal(version); }); - }); describe('Block', function() { - it('should accept a block instance as an argument', function() { var block = new meritcore.Block({ header: {}, - transactions: [] + transactions: [], }); var message = messages.Block(block); message.block.should.be.instanceof(meritcore.Block); }); - }); describe('Pong', function() { - it('should error if nonce is not a buffer', function() { (function() { var message = messages.Pong('not a buffer'); - }).should.throw('First argument is expected to be an 8 byte buffer'); + }.should.throw('First argument is expected to be an 8 byte buffer')); }); it('should error if nonce buffer has invalid length', function() { (function() { var message = messages.Pong(new Buffer(Array(9))); - }).should.throw('First argument is expected to be an 8 byte buffer'); + }.should.throw('First argument is expected to be an 8 byte buffer')); }); it('should set a nonce if not included', function() { @@ -97,21 +90,19 @@ describe('Command Messages', function() { should.exist(message.nonce); message.nonce.length.should.equal(8); }); - }); describe('Ping', function() { - it('should error if nonce is not a buffer', function() { (function() { var message = messages.Ping('not a buffer'); - }).should.throw('First argument is expected to be an 8 byte buffer'); + }.should.throw('First argument is expected to be an 8 byte buffer')); }); it('should error if nonce buffer has invalid length', function() { (function() { var message = messages.Ping(new Buffer(Array(9))); - }).should.throw('First argument is expected to be an 8 byte buffer'); + }.should.throw('First argument is expected to be an 8 byte buffer')); }); it('should set a nonce if not included', function() { @@ -119,21 +110,17 @@ describe('Command Messages', function() { should.exist(message.nonce); message.nonce.length.should.equal(8); }); - }); describe('FilterAdd', function() { - it('should error if arg is not a buffer', function() { (function() { var message = messages.FilterAdd('not a buffer'); - }).should.throw('First argument is expected to be a Buffer or undefined'); + }.should.throw('First argument is expected to be a Buffer or undefined')); }); - }); describe('FilterLoad', function() { - it('should return a null payload', function() { var message = messages.FilterLoad(); var payload = message.getPayload(); @@ -143,17 +130,16 @@ describe('Command Messages', function() { it('should error if filter is not a bloom filter', function() { (function() { - var message = messages.FilterLoad({filter: 'not a bloom filter'}); - }).should.throw('An instance of BloomFilter'); + var message = messages.FilterLoad({ filter: 'not a bloom filter' }); + }.should.throw('An instance of BloomFilter')); }); - }); describe('Inventory', function() { it('should error if arg is not an array', function() { (function() { var message = messages.Inventory({}); - }).should.throw('Argument is expected to be an array of inventory objects'); + }.should.throw('Argument is expected to be an array of inventory objects')); }); it('should not error if arg is an empty array', function() { var message = messages.Inventory([]); @@ -161,18 +147,17 @@ describe('Command Messages', function() { it('should error if arg is not an array of inventory objects', function() { (function() { var message = messages.Inventory([Number(0)]); - }).should.throw('Argument is expected to be an array of inventory objects'); + }.should.throw('Argument is expected to be an array of inventory objects')); }); }); describe('Transaction', function() { - it('should be able to pass a custom Transaction', function(done) { - var Transaction = function(){}; + var Transaction = function() {}; Transaction.prototype.fromBuffer = function() { done(); }; - var messagesCustom = new Messages({Transaction: Transaction}); + var messagesCustom = new Messages({ Transaction: Transaction }); var message = messagesCustom.Transaction.fromBuffer(); should.exist(message); }); @@ -182,75 +167,67 @@ describe('Command Messages', function() { Transaction.fromBuffer = function() { done(); }; - var messagesCustom = new Messages({Transaction: Transaction}); + var messagesCustom = new Messages({ Transaction: Transaction }); var message = messagesCustom.Transaction.fromBuffer(); should.exist(message); }); - }); describe('Block', function() { - it('should be able to pass a custom Block', function(done) { var Block = sinon.stub(); Block.fromBuffer = function() { done(); }; - var messagesCustom = new Messages({Block: Block}); + var messagesCustom = new Messages({ Block: Block }); var message = messagesCustom.Block.fromBuffer(); should.exist(message); }); - }); describe('GetBlocks', function() { - it('should error with invalid stop', function() { var invalidStop = '000000'; var starts = ['000000000000000013413cf2536b491bf0988f52e90c476ffeb701c8bfdb1db9']; (function() { - var message = messages.GetBlocks({starts: starts, stop: invalidStop}); + var message = messages.GetBlocks({ starts: starts, stop: invalidStop }); var buffer = message.toBuffer(); should.not.exist(buffer); - }).should.throw('Invalid hash length'); + }.should.throw('Invalid hash length')); }); - }); describe('GetHeaders', function() { - it('should error with invalid stop', function() { var invalidStop = '000000'; var starts = ['000000000000000013413cf2536b491bf0988f52e90c476ffeb701c8bfdb1db9']; (function() { - var message = messages.GetHeaders({starts: starts, stop: invalidStop}); + var message = messages.GetHeaders({ starts: starts, stop: invalidStop }); var buffer = message.toBuffer(); should.not.exist(buffer); - }).should.throw('Invalid hash length'); + }.should.throw('Invalid hash length')); }); - }); describe('Headers', function() { it('should error if arg is not an array', function() { (function() { var message = messages.Headers({}); - }).should.throw('First argument is expected to be an array'); + }.should.throw('First argument is expected to be an array')); }); it('should error if arg is an empty array', function() { (function() { var message = messages.Headers([]); - }).should.throw('First argument is expected to be an array'); + }.should.throw('First argument is expected to be an array')); }); it('should error if arg is not an array of BlockHeaders', function() { (function() { var message = messages.Headers([Number(0)]); - }).should.throw('First argument is expected to be an array'); + }.should.throw('First argument is expected to be an array')); }); }); describe('MerkleBlock', function() { - it('should return null buffer for payload', function() { var message = messages.MerkleBlock(); var payload = message.getPayload(); @@ -259,8 +236,8 @@ describe('Command Messages', function() { it('should error if merkleBlock is not a MerkleBlock', function() { (function() { - var message = messages.MerkleBlock({merkleBlock: 'not a merkle block'}); - }).should.throw('An instance of MerkleBlock'); + var message = messages.MerkleBlock({ merkleBlock: 'not a merkle block' }); + }.should.throw('An instance of MerkleBlock')); }); }); @@ -270,7 +247,7 @@ describe('Command Messages', function() { message: 'tx', ccode: 0x01, reason: 'transaction is malformed', - data: new Buffer('12345678901234567890123456789012', 'hex') + data: new Buffer('12345678901234567890123456789012', 'hex'), }); message.message.should.equal('tx'); message.ccode.should.equal(0x01); @@ -289,7 +266,7 @@ describe('Command Messages', function() { message: 'tx', ccode: 0x01, reason: 'transaction is malformed', - data: new Buffer('12345678901234567890123456789012', 'hex') + data: new Buffer('12345678901234567890123456789012', 'hex'), }); var payload = message.getPayload(); message = messages.Reject(); @@ -308,15 +285,14 @@ describe('Command Messages', function() { message.relay.should.equal(true); }); it('should set the relay as false', function() { - var message = messages.Version({relay: false}); + var message = messages.Version({ relay: false }); should.exist(message.relay); message.relay.should.equal(false); }); it('should set the relay as true', function() { - var message = messages.Version({relay: true}); + var message = messages.Version({ relay: true }); should.exist(message.relay); message.relay.should.equal(true); }); }); - }); diff --git a/packages/merit-p2p/test/messages/index.js b/packages/merit-p2p/test/messages/index.js index 09beac3335..af3662a1a7 100644 --- a/packages/merit-p2p/test/messages/index.js +++ b/packages/merit-p2p/test/messages/index.js @@ -16,7 +16,6 @@ function getPayloadBuffer(messageBuffer) { } describe('Messages', function() { - var buildMessage = function(hex) { var m = Buffers(); m.push(new Buffer(hex, 'hex')); @@ -29,7 +28,7 @@ describe('Messages', function() { var messages = new Messages({ network: network, Block: bitcore.Block, - Transaction: bitcore.Transaction + Transaction: bitcore.Transaction, }); should.exist(messages.builder.commands); should.exist(messages.builder.constructors); @@ -39,10 +38,10 @@ describe('Messages', function() { }); it('network should be unique for each set of messages', function() { var messages = new Messages({ - network: bitcore.Networks.livenet + network: bitcore.Networks.livenet, }); var messages2 = new Messages({ - network: bitcore.Networks.testnet + network: bitcore.Networks.testnet, }); messages.network.should.deep.equal(bitcore.Networks.livenet); messages2.network.should.deep.equal(bitcore.Networks.testnet); @@ -94,7 +93,6 @@ describe('Messages', function() { message.network.should.deep.equal(bitcore.Networks.defaultNetwork); }); }); - }); describe('messages.Version', function() { @@ -108,7 +106,7 @@ describe('Messages', function() { it('#relay setting works', function() { [true, false].forEach(function(relay) { var message = messages.Version({ - relay: relay + relay: relay, }); message.relay.should.equal(relay); var messageBuf = message.getPayload(); @@ -119,7 +117,6 @@ describe('Messages', function() { }); describe('Inventory Helpers', function() { - var messages = new Messages(); var constructors = messages.builder.inventoryCommands; @@ -158,12 +155,12 @@ describe('Messages', function() { }); }); }); - }); describe('#parseBuffer', function() { it('fails with invalid command', function() { - var invalidCommand = 'f9beb4d96d616c6963696f757300000025000000bd5e830c' + + var invalidCommand = + 'f9beb4d96d616c6963696f757300000025000000bd5e830c' + '0102000000ec3995c1bf7269ff728818a65e53af00cbbee6b6eca8ac9ce7bc79d87' + '7041ed8'; var fails = function() { @@ -174,14 +171,17 @@ describe('Messages', function() { }); it('ignores malformed messages', function() { - var malformed1 = 'd8c4c3d976657273696f6e000000000065000000fc970f1772110' + + var malformed1 = + 'd8c4c3d976657273696f6e000000000065000000fc970f1772110' + '1000100000000000000ba6288540000000001000000000000000000000000000000' + '0000ffffba8886dceab0010000000000000000000000000000000000ffff0509552' + '2208de7e1c1ef80a1cea70f2f5361746f7368693a302e392e312fa317050001'; - var malformed2 = 'f9beb4d967657464617461000000000089000000d88134740102' + + var malformed2 = + 'f9beb4d967657464617461000000000089000000d88134740102' + '0000006308e4a380c949dbad182747b0f7b6a89e874328ca41f37287f74a81b8f84' + '86d'; - var malformed3 = 'f9beb4d967657464617461000000000025000000616263640102' + + var malformed3 = + 'f9beb4d967657464617461000000000025000000616263640102' + '00000069ebcbc34a4f9890da9aea0f773beba883a9afb1ab9ad7647dd4a1cd346c3' + '728'; [malformed1, malformed2, malformed3].forEach(function(malformed) { @@ -189,7 +189,6 @@ describe('Messages', function() { should.not.exist(ret); }); }); - }); describe('#add', function() { @@ -198,7 +197,7 @@ describe('Messages', function() { var messages = new Messages({ network: network, Block: bitcore.Block, - Transaction: bitcore.Transaction + Transaction: bitcore.Transaction, }); var CustomMessage = function(arg, options) { @@ -212,5 +211,4 @@ describe('Messages', function() { message.arg.should.equal('hello'); }); }); - }); diff --git a/packages/merit-p2p/test/messages/message.js b/packages/merit-p2p/test/messages/message.js index ff74ffae12..43ba6e5a30 100644 --- a/packages/merit-p2p/test/messages/message.js +++ b/packages/merit-p2p/test/messages/message.js @@ -6,14 +6,13 @@ var Message = P2P.Messages.Message; var Networks = require('meritcore-lib').Networks; describe('Message', function() { - describe('@constructor', function() { it('construct with magic number and command', function() { var message = new Message({ network: { - networkMagic: 0xd9b4bef9 + networkMagic: 0xd9b4bef9, }, - command: 'command' + command: 'command', }); should.exist(message); message.command.should.equal('command'); @@ -25,7 +24,7 @@ describe('Message', function() { it('serialize to a buffer', function() { var message = new Message({ command: 'command', - network: Networks.defaultNetwork + network: Networks.defaultNetwork, }); message.getPayload = function() { return new Buffer(0); @@ -35,5 +34,4 @@ describe('Message', function() { buffer.should.deep.equal(expectedBuffer); }); }); - }); diff --git a/packages/merit-p2p/test/messages/util.js b/packages/merit-p2p/test/messages/util.js index cd7a5de094..cfbbbf4762 100644 --- a/packages/merit-p2p/test/messages/util.js +++ b/packages/merit-p2p/test/messages/util.js @@ -8,7 +8,6 @@ var meritcore = require('meritcore-lib'); var BufferReader = meritcore.encoding.BufferReader; describe('Message Utils', function() { - describe('checkFinished', function() { it('should throw an error if buffer reader is not finished', function() { /*jshint immed: false */ @@ -16,7 +15,7 @@ describe('Message Utils', function() { var br = new BufferReader(buffer); (function() { utils.checkFinished(br); - }).should.throw('Data still available after parsing'); + }.should.throw('Data still available after parsing')); }); }); @@ -25,15 +24,14 @@ describe('Message Utils', function() { /*jshint immed: false */ var stop = '000000000000000013413cf2536b491bf0988f52e90c476ffeb701c8bfdb1db9'; (function() { - utils.sanitizeStartStop({starts: ['0000'], stop: stop}); - }).should.throw('Invalid hash'); + utils.sanitizeStartStop({ starts: ['0000'], stop: stop }); + }.should.throw('Invalid hash')); }); it('should keep buffers as buffers', function() { /*jshint immed: false */ var starts = [new Buffer(Array(32))]; - var obj = utils.sanitizeStartStop({starts: starts}); + var obj = utils.sanitizeStartStop({ starts: starts }); obj.starts[0].should.deep.equal(starts[0]); }); }); - }); diff --git a/packages/merit-p2p/test/peer.js b/packages/merit-p2p/test/peer.js index b4049f1f83..e2da9940a4 100644 --- a/packages/merit-p2p/test/peer.js +++ b/packages/merit-p2p/test/peer.js @@ -20,7 +20,6 @@ var messages = new Messages(); var Networks = meritcore.Networks; describe('Peer', function() { - describe('Integration test', function() { it('parses this stream of data from a connection', function(callback) { var peer = new Peer(''); @@ -31,13 +30,13 @@ describe('Peer', function() { version: 1, verack: 1, inv: 18, - addr: 4 + addr: 4, }; var received = { version: 0, verack: 0, inv: 0, - addr: 0 + addr: 0, }; stub.on = function() { if (arguments[0] === 'data') { @@ -79,28 +78,28 @@ describe('Peer', function() { }); it('create instance setting a port', function() { - var peer = new Peer({host: 'localhost', port: 8111}); + var peer = new Peer({ host: 'localhost', port: 8111 }); peer.host.should.equal('localhost'); peer.network.should.equal(Networks.livenet); peer.port.should.equal(8111); }); it('create instance setting a network', function() { - var peer = new Peer({host: 'localhost', network: Networks.testnet}); + var peer = new Peer({ host: 'localhost', network: Networks.testnet }); peer.host.should.equal('localhost'); peer.network.should.equal(Networks.testnet); peer.port.should.equal(Networks.testnet.port); }); it('create instance setting port and network', function() { - var peer = new Peer({host: 'localhost', port: 8111, network: Networks.testnet}); + var peer = new Peer({ host: 'localhost', port: 8111, network: Networks.testnet }); peer.host.should.equal('localhost'); peer.network.should.equal(Networks.testnet); peer.port.should.equal(8111); }); it('create instance without new', function() { - var peer = Peer({host: 'localhost', port: 8111, network: Networks.testnet}); + var peer = Peer({ host: 'localhost', port: 8111, network: Networks.testnet }); peer.host.should.equal('localhost'); peer.network.should.equal(Networks.testnet); peer.port.should.equal(8111); @@ -124,7 +123,7 @@ describe('Peer', function() { }); it('send pong on ping', function(done) { - var peer = new Peer({host: 'localhost'}); + var peer = new Peer({ host: 'localhost' }); var pingMessage = messages.Ping(); peer.sendMessage = function(message) { message.command.should.equal('pong'); @@ -135,7 +134,7 @@ describe('Peer', function() { }); it('relay error from socket', function(done) { - var peer = new Peer({host: 'localhost'}); + var peer = new Peer({ host: 'localhost' }); var socket = new EventEmitter(); socket.connect = sinon.spy(); socket.destroy = sinon.spy(); @@ -152,7 +151,7 @@ describe('Peer', function() { }); it('will not disconnect twice on disconnect and error', function(done) { - var peer = new Peer({host: 'localhost'}); + var peer = new Peer({ host: 'localhost' }); var socket = new EventEmitter(); socket.connect = sinon.stub(); socket.destroy = sinon.stub(); @@ -172,7 +171,7 @@ describe('Peer', function() { }); it('disconnect with max buffer length', function(done) { - var peer = new Peer({host: 'localhost'}); + var peer = new Peer({ host: 'localhost' }); var socket = new EventEmitter(); socket.connect = sinon.spy(); peer._getSocket = function() { @@ -184,11 +183,10 @@ describe('Peer', function() { peer.connect(); var buffer = new Buffer(Array(Peer.MAX_RECEIVE_BUFFER + 1)); peer.socket.emit('data', buffer); - }); it('should send version on version if not already sent', function(done) { - var peer = new Peer({host:'localhost'}); + var peer = new Peer({ host: 'localhost' }); var commands = {}; peer.sendMessage = function(message) { commands[message.command] = true; @@ -200,12 +198,12 @@ describe('Peer', function() { peer.emit('version', { version: 'version', subversion: 'subversion', - startHeight: 'startHeight' + startHeight: 'startHeight', }); }); it('should not send version on version if already sent', function(done) { - var peer = new Peer({host:'localhost'}); + var peer = new Peer({ host: 'localhost' }); peer.versionSent = true; var commands = {}; peer.sendMessage = function(message) { @@ -216,22 +214,22 @@ describe('Peer', function() { peer.emit('version', { version: 'version', subversion: 'subversion', - startHeight: 'startHeight' + startHeight: 'startHeight', }); }); it('relay set properly', function() { - var peer = new Peer({host: 'localhost'}); + var peer = new Peer({ host: 'localhost' }); peer.relay.should.equal(true); - var peer2 = new Peer({host: 'localhost', relay: false}); + var peer2 = new Peer({ host: 'localhost', relay: false }); peer2.relay.should.equal(false); - var peer3 = new Peer({host: 'localhost', relay: true}); + var peer3 = new Peer({ host: 'localhost', relay: true }); peer3.relay.should.equal(true); }); it('relay setting respected', function() { - [true,false].forEach(function(relay) { - var peer = new Peer({host: 'localhost', relay: relay}); + [true, false].forEach(function(relay) { + var peer = new Peer({ host: 'localhost', relay: relay }); var peerSendMessageStub = sinon.stub(Peer.prototype, 'sendMessage', function(message) { message.relay.should.equal(relay); }); @@ -239,5 +237,4 @@ describe('Peer', function() { peerSendMessageStub.restore(); }); }); - }); diff --git a/packages/merit-p2p/test/pool.js b/packages/merit-p2p/test/pool.js index 3bff5a6c7d..9ef93f3456 100644 --- a/packages/merit-p2p/test/pool.js +++ b/packages/merit-p2p/test/pool.js @@ -24,7 +24,6 @@ function getPayloadBuffer(messageBuffer) { } describe('Pool', function() { - it('create instance', function() { var pool = new Pool(); should.exist(pool.network); @@ -34,7 +33,7 @@ describe('Pool', function() { }); it('create instance setting the network', function() { - var pool = new Pool({network: Networks.testnet}); + var pool = new Pool({ network: Networks.testnet }); pool.network.should.equal(Networks.testnet); }); @@ -42,7 +41,7 @@ describe('Pool', function() { var stub = sinon.stub(dns, 'resolve', function(seed, callback) { callback(null, ['10.10.10.1', '10.10.10.2', '10.10.10.3']); }); - var pool = new Pool({network: Networks.livenet}); + var pool = new Pool({ network: Networks.livenet }); pool.connect(); pool.disconnect(); pool._addrs.length.should.equal(3); @@ -52,7 +51,7 @@ describe('Pool', function() { it('optionally connect without dns seeds', function() { sinon.stub(Peer.prototype, 'connect', function() { this.socket = { - destroy: sinon.stub() + destroy: sinon.stub(), }; }); var stub = sinon.stub(dns, 'resolve', function(seed, callback) { @@ -65,15 +64,15 @@ describe('Pool', function() { addrs: [ { ip: { - v4: 'localhost' - } + v4: 'localhost', + }, }, { ip: { - v4: 'localhost2' - } - } - ] + v4: 'localhost2', + }, + }, + ], }; var pool = new Pool(options); pool.connect(); @@ -90,17 +89,16 @@ describe('Pool', function() { addrs: [ { ip: { - v4: 'localhost' - } - } - ] + v4: 'localhost', + }, + }, + ], }; var pool = new Pool(options); pool._addrs.length.should.equal(1); }); it('add new addrs as they are announced over the network', function(done) { - // only emit an event, no need to connect var peerConnectStub = sinon.stub(Peer.prototype, 'connect', function() { this._readMessage(); @@ -120,10 +118,10 @@ describe('Pool', function() { addrs: [ { ip: { - v4: 'localhost' - } - } - ] + v4: 'localhost', + }, + }, + ], }; var pool = new Pool(options); @@ -147,11 +145,9 @@ describe('Pool', function() { }); pool.connect(); - }); it('can optionally not listen to new addrs messages', function(done) { - // only emit an event, no need to connect var peerConnectStub = sinon.stub(Peer.prototype, 'connect', function() { this._readMessage(); @@ -172,10 +168,10 @@ describe('Pool', function() { addrs: [ { ip: { - v4: 'localhost' - } - } - ] + v4: 'localhost', + }, + }, + ], }; var pool = new Pool(options); @@ -199,7 +195,6 @@ describe('Pool', function() { }); pool.connect(); - }); it('propagate connect, ready, and disconnect peer events', function(done) { @@ -217,10 +212,10 @@ describe('Pool', function() { addrs: [ { ip: { - v4: 'localhost' - } - } - ] + v4: 'localhost', + }, + }, + ], }); var poolDisconnectStub; @@ -253,12 +248,12 @@ describe('Pool', function() { this.emit('connect', this, {}); }); [true, false].forEach(function(relay) { - var pool = new Pool({relay: relay, dnsSeed: false}); + var pool = new Pool({ relay: relay, dnsSeed: false }); pool._addAddr({ ip: { v4: 'localhost' } }); pool.on('peerconnect', function(peer, addr) { peer.relay.should.equal(relay); pool.disconnect(); - if(++count == 2) { + if (++count == 2) { done(); } }); @@ -276,7 +271,7 @@ describe('Pool', function() { var dnsStub = sinon.stub(dns, 'resolve', function(seed, callback) { callback(new Error('A DNS error')); }); - var pool = new Pool({network: Networks.livenet, maxSize: 1}); + var pool = new Pool({ network: Networks.livenet, maxSize: 1 }); pool.once('seederror', function(error) { should.exist(error); pool.disconnect(); @@ -290,7 +285,7 @@ describe('Pool', function() { var dnsStub = sinon.stub(dns, 'resolve', function(seed, callback) { callback(null, []); }); - var pool = new Pool({network: Networks.livenet, maxSize: 1}); + var pool = new Pool({ network: Networks.livenet, maxSize: 1 }); pool.once('seederror', function(error) { should.exist(error); pool.disconnect(); @@ -304,7 +299,7 @@ describe('Pool', function() { var message = 'message'; sinon.stub(Peer.prototype, 'connect', function() { this.socket = { - destroy: sinon.stub() + destroy: sinon.stub(), }; var self = this; process.nextTick(function() { @@ -324,11 +319,11 @@ describe('Pool', function() { dnsSeed: false, addrs: [ { - ip:{ - v4: 'localhost' - } - } - ] + ip: { + v4: 'localhost', + }, + }, + ], }); pool.on('peerready', function() { pool.sendMessage(message); @@ -337,7 +332,7 @@ describe('Pool', function() { }); it('not call _fillConnections if keepalive is false on seed', function(done) { - var pool = new Pool({network: Networks.livenet, maxSize: 1}); + var pool = new Pool({ network: Networks.livenet, maxSize: 1 }); pool._fillConnections = sinon.stub(); pool.keepalive = false; pool.on('seed', function() { @@ -350,23 +345,27 @@ describe('Pool', function() { }); it('keep original time for handling peeraddr messages', function(done) { - var pool = new Pool({network: Networks.livenet, maxSize: 1}); + var pool = new Pool({ network: Networks.livenet, maxSize: 1 }); var now = new Date(); pool._addAddr = function(addr) { addr.time.should.equal(now); done(); }; - pool.emit('peeraddr', {}, { - addresses: [ - { - time: now - } - ] - }); + pool.emit( + 'peeraddr', + {}, + { + addresses: [ + { + time: now, + }, + ], + }, + ); }); it('replace time if time is invalid on peeraddr messages', function(done) { - var pool = new Pool({network: Networks.livenet, maxSize: 1}); + var pool = new Pool({ network: Networks.livenet, maxSize: 1 }); var future = new Date(new Date().getTime() + 10 * 70 * 1000); var past = new Date(new Date().getTime() - 4 * 24 * 60 * 60 * 1000); // 4 days ago pool._addAddr = function(addr) { @@ -374,27 +373,31 @@ describe('Pool', function() { addr.time.getTime().should.be.below(past.getTime()); done(); }; - pool.emit('peeraddr', {}, { - addresses: [ - { - time: future - } - ] - }); + pool.emit( + 'peeraddr', + {}, + { + addresses: [ + { + time: future, + }, + ], + }, + ); }); describe('#_removeConnectedPeer', function() { it('disconnect peer if peer status is not disconnected', function(done) { - var pool = new Pool({network: Networks.livenet, maxSize: 1}); + var pool = new Pool({ network: Networks.livenet, maxSize: 1 }); /* jshint sub: true */ pool._connectedPeers['hash'] = { status: Peer.STATUS.CONNECTED, disconnect: function() { done(); - } + }, }; pool._removeConnectedPeer({ - hash: 'hash' + hash: 'hash', }); }); }); @@ -402,14 +405,14 @@ describe('Pool', function() { describe('#_connectPeer', function() { it('connect ipv6 peer', function() { var connectStub = sinon.stub(Peer.prototype, 'connect'); - var pool = new Pool({network: Networks.livenet, maxSize: 1}); + var pool = new Pool({ network: Networks.livenet, maxSize: 1 }); var ipv6 = '2001:0db8:85a3:0042:1000:8a2e:0370:7334'; pool._addPeerEventHandlers = sinon.stub(); pool._connectPeer({ ip: { - v6: ipv6 + v6: ipv6, }, - hash: 'hash' + hash: 'hash', }); /* jshint sub: true */ should.exist(pool._connectedPeers['hash']); @@ -420,14 +423,14 @@ describe('Pool', function() { it('will pass network to peer', function() { var connectStub = sinon.stub(Peer.prototype, 'connect'); - var pool = new Pool({network: Networks.testnet, maxSize: 1}); + var pool = new Pool({ network: Networks.testnet, maxSize: 1 }); var ipv6 = '2001:0db8:85a3:0042:1000:8a2e:0370:7334'; pool._addPeerEventHandlers = sinon.stub(); pool._connectPeer({ ip: { - v6: ipv6 + v6: ipv6, }, - hash: 'hash' + hash: 'hash', }); /* jshint sub: true */ pool._connectedPeers['hash'].network.should.equal(pool.network); @@ -436,54 +439,60 @@ describe('Pool', function() { }); describe('#_addConnectedPeer', function() { - it('should add a peer', function() { /* jshint sub: true */ - var pool = new Pool({network: Networks.livenet, maxSize: 1}); + var pool = new Pool({ network: Networks.livenet, maxSize: 1 }); pool._addPeerEventHandlers = sinon.stub(); - pool._addConnectedPeer({ - on: sinon.stub() - }, {hash: 'hash'}); + pool._addConnectedPeer( + { + on: sinon.stub(), + }, + { hash: 'hash' }, + ); should.exist(pool._connectedPeers['hash']); pool._addPeerEventHandlers.calledOnce.should.equal(true); }); it('should not already added peer', function() { /* jshint sub: true */ - var pool = new Pool({network: Networks.livenet, maxSize: 1}); + var pool = new Pool({ network: Networks.livenet, maxSize: 1 }); pool._addPeerEventHandlers = sinon.stub(); pool._connectedPeers['hash'] = {}; - pool._addConnectedPeer({ - on: sinon.stub() - }, {hash: 'hash'}); + pool._addConnectedPeer( + { + on: sinon.stub(), + }, + { hash: 'hash' }, + ); should.exist(pool._connectedPeers['hash']); pool._addPeerEventHandlers.calledOnce.should.equal(false); }); it('will pass network to peer', function() { /* jshint sub: true */ - var pool = new Pool({network: Networks.testnet, maxSize: 1}); - pool._addConnectedPeer({ - on: sinon.stub() - }, {hash: 'hash'}); + var pool = new Pool({ network: Networks.testnet, maxSize: 1 }); + pool._addConnectedPeer( + { + on: sinon.stub(), + }, + { hash: 'hash' }, + ); should.exist(pool._connectedPeers['hash']); pool._connectedPeers['hash'].network.should.equal(pool.network); }); - }); describe('#listen', function() { - it('create a server', function(done) { var netStub = sinon.stub(net, 'createServer', function() { return { listen: function() { netStub.restore(); done(); - } + }, }; }); - var pool = new Pool({network: Networks.livenet, maxSize: 1}); + var pool = new Pool({ network: Networks.livenet, maxSize: 1 }); pool.listen(); }); @@ -491,16 +500,16 @@ describe('Pool', function() { var ipv6 = '2001:0db8:85a3:0042:1000:8a2e:0370:7334'; sinon.stub(net, 'createServer', function(callback) { callback({ - remoteAddress: ipv6 + remoteAddress: ipv6, }); return { - listen: sinon.stub() + listen: sinon.stub(), }; }); sinon.stub(net, 'isIPv6', function() { return true; }); - var pool = new Pool({network: Networks.livenet, maxSize: 1}); + var pool = new Pool({ network: Networks.livenet, maxSize: 1 }); pool._addAddr = function(addr) { should.exist(addr.ip.v6); addr.ip.v6.should.equal(ipv6); @@ -517,13 +526,13 @@ describe('Pool', function() { sinon.stub(net, 'createServer', function(callback) { callback({ remoteAddress: '127.0.0.1', - remotePort: port + remotePort: port, }); return { - listen: sinon.stub() + listen: sinon.stub(), }; }); - var pool = new Pool({network: Networks.livenet, maxSize: 1}); + var pool = new Pool({ network: Networks.livenet, maxSize: 1 }); pool._addAddr = function(addr) { should.exist(addr.port); addr.port.should.equal(port); @@ -538,16 +547,16 @@ describe('Pool', function() { var ipv4 = '127.0.0.1'; sinon.stub(net, 'createServer', function(callback) { callback({ - remoteAddress: ipv4 + remoteAddress: ipv4, }); return { - listen: sinon.stub() + listen: sinon.stub(), }; }); sinon.stub(net, 'isIPv6', function() { return false; }); - var pool = new Pool({network: Networks.livenet, maxSize: 1}); + var pool = new Pool({ network: Networks.livenet, maxSize: 1 }); pool._addAddr = function(addr) { should.exist(addr.ip.v4); addr.ip.v4.should.equal(ipv4); @@ -558,8 +567,5 @@ describe('Pool', function() { pool._addConnectedPeer = sinon.stub(); pool.listen(); }); - }); - - }); diff --git a/packages/merit-payment-protocol/README.md b/packages/merit-payment-protocol/README.md index 91b7dca970..2351d55fdc 100644 --- a/packages/merit-payment-protocol/README.md +++ b/packages/merit-payment-protocol/README.md @@ -1,5 +1,4 @@ -Merit Payment Protocol -======= +# Merit Payment Protocol A module for [Merit LWS](https://github.com/meritlabs/lightwallet-stack) that implements [Payment Protocol](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki) and other related BIPs. diff --git a/packages/merit-payment-protocol/docs/index.md b/packages/merit-payment-protocol/docs/index.md index 4b2f8ad1cc..265ffffd05 100644 --- a/packages/merit-payment-protocol/docs/index.md +++ b/packages/merit-payment-protocol/docs/index.md @@ -1,7 +1,9 @@ # Payment Protocol + `PaymentProtocol` and associated functions and methods will serialize, deserialize, sign and verify payment protocol messages both in Node.js and web browsers. Both X.509 and Merit identity protocol are supported. For detailed technical information, please view [BIP70](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki). ## Installation + Payment protocol is implemented as a separate module and you must add it to your dependencies: For node projects: @@ -12,11 +14,12 @@ npm install merit-payment-protocol --save ``` ## Make Payment Details + Here the merchant's server will construct the payment details message: ```javascript var PaymentProtocol = require('merit-payment-protocol'); -var now = Date.now() / 1000 | 0; +var now = (Date.now() / 1000) | 0; // construct the payment details var details = new PaymentProtocol().makePaymentDetails(); @@ -26,12 +29,13 @@ details.set('time', now); details.set('expires', now + 60 * 60 * 24); details.set('memo', 'A payment request from the merchant.'); details.set('payment_url', 'https://localhost/-/pay'); -details.set('merchant_data', new Buffer({size: 7})); // identify the request +details.set('merchant_data', new Buffer({ size: 7 })); // identify the request ``` For more information about these fields please visit [BIP70](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#paymentdetailspaymentrequest) ## Sign a Payment Request + The merchant's server will then construct a payment request and send it to the customer: ```javascript @@ -57,10 +61,10 @@ var rawbody = request.serialize(); ``` ## Verify a Payment Request + The customers wallet would then verify the payment request as follows (after asking for the payment request message): ```javascript - // Example HTTP Request Headers: // Method: GET // Accept: PaymentProtocol.PAYMENT_REQUEST_CONTENT_TYPE, PaymentProtocol.PAYMENT_ACK_CONTENT_TYPE @@ -92,10 +96,10 @@ var merchant_data = details.get('merchant_data'); ``` ## Send a Payment + After the request is verified a payment can be sent to the merchant from the customer's wallet: ```javascript - // send the payment transaction var payment = new PaymentProtocol().makePayment(); payment.set('merchant_data', merchant_data); @@ -123,10 +127,10 @@ var rawbody = pay.serialize(); ``` ## Receive a Payment + The merchant would then receive the payment as follows: ```javascript - var body = PaymentProtocol.Payment.decode(rawbody); var payment = new PaymentProtocol().makePayment(body); var merchant_data = payment.get('merchant_data'); @@ -138,10 +142,10 @@ var memo = payment.get('memo'); ``` ## Send a Payment Acknowledgement + After the payment has been broadcasted, a payment acknowledgement can be sent in response: ```javascript - // make a payment acknowledgement var ack = new PaymentProtocol().makePaymentACK(); ack.set('payment', payment.message); @@ -155,6 +159,7 @@ var rawbody = ack.serialize(); ``` ## Receive an Acknowledgement + The customer's wallet can then receive an acknowledgement of payment as follows: ```javascript diff --git a/packages/merit-payment-protocol/lib/browser.js b/packages/merit-payment-protocol/lib/browser.js index f610096383..2092903fb6 100644 --- a/packages/merit-payment-protocol/lib/browser.js +++ b/packages/merit-payment-protocol/lib/browser.js @@ -26,7 +26,7 @@ PaymentProtocol.prototype.x509Sign = function(key, returnTrust) { if (type !== 'none') { var jsrsaSig = new KJUR.crypto.Signature({ alg: type + 'withRSA', - prov: 'cryptojs/jsrsa' + prov: 'cryptojs/jsrsa', }); jsrsaSig.init(key); @@ -52,7 +52,7 @@ PaymentProtocol.prototype.x509Sign = function(key, returnTrust) { isChain: pki_data.length > 1, signature: sig, caTrusted: !!caName, - caName: caName || null + caName: caName || null, }; } @@ -75,7 +75,7 @@ PaymentProtocol.prototype.x509Verify = function(returnTrust) { if (type !== 'none') { var jsrsaSig = new KJUR.crypto.Signature({ alg: type + 'withRSA', - prov: 'cryptojs/jsrsa' + prov: 'cryptojs/jsrsa', }); var signedCert = pki_data[0]; der = signedCert.toString('hex'); @@ -96,8 +96,7 @@ PaymentProtocol.prototype.x509Verify = function(returnTrust) { pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(der, 'CERTIFICATE'); var caName = RootCerts.getTrusted(pem); - if (!caName) - caName = PaymentProtocol.completeChainAndGetCA(chain); + if (!caName) caName = PaymentProtocol.completeChainAndGetCA(chain); if (chain.length === 1 && !caName) { if (returnTrust) { @@ -107,7 +106,7 @@ PaymentProtocol.prototype.x509Verify = function(returnTrust) { verified: verified, caTrusted: false, caName: null, - chainVerified: false + chainVerified: false, }; } return verified; @@ -123,7 +122,7 @@ PaymentProtocol.prototype.x509Verify = function(returnTrust) { verified: verified, caTrusted: false, caName: null, - chainVerified: false + chainVerified: false, }; } return verified; @@ -138,7 +137,7 @@ PaymentProtocol.prototype.x509Verify = function(returnTrust) { verified: verified, caTrusted: !!caName, caName: caName || null, - chainVerified: chainVerified + chainVerified: chainVerified, }; } @@ -175,7 +174,7 @@ PaymentProtocol.verifyCertChain = function(chain, sigHashAlg) { if (sigHashAlg !== 'none') { var js = new KJUR.crypto.Signature({ alg: sigHashAlg + 'withRSA', - prov: 'cryptojs/jsrsa' + prov: 'cryptojs/jsrsa', }); js.initVerifyByCertificatePEM(npem); npubKey = js.pubKey; @@ -198,7 +197,7 @@ PaymentProtocol.verifyCertChain = function(chain, sigHashAlg) { if (sigHashAlg !== 'none') { var jsrsaSig = new KJUR.crypto.Signature({ alg: sigHashAlg + 'withRSA', - prov: 'cryptojs/jsrsa' + prov: 'cryptojs/jsrsa', }); jsrsaSig.initVerifyByPublicKey(npubKey); diff --git a/packages/merit-payment-protocol/lib/common.js b/packages/merit-payment-protocol/lib/common.js index 94c16c5ef9..0a23349269 100644 --- a/packages/merit-payment-protocol/lib/common.js +++ b/packages/merit-payment-protocol/lib/common.js @@ -38,7 +38,7 @@ PaymentProtocol.X509_ALGORITHM = { '1.2.840.10045.4.3.2': 'ECDSA_SHA256', '1.2.840.10045.4.3.3': 'ECDSA_SHA384', - '1.2.840.10045.4.3.4': 'ECDSA_SHA512' + '1.2.840.10045.4.3.4': 'ECDSA_SHA512', }; PaymentProtocol.getAlgorithm = function(value, index) { @@ -46,12 +46,12 @@ PaymentProtocol.getAlgorithm = function(value, index) { value = value.join('.'); } value = PaymentProtocol.X509_ALGORITHM[value]; - if (typeof(index) !== 'undefined') { + if (typeof index !== 'undefined') { value = value.split('_'); if (index === true) { return { cipher: value[0], - hash: value[1] + hash: value[1], }; } return value[index]; @@ -122,20 +122,22 @@ PaymentProtocol.validateCertTime = function(c, nc) { PaymentProtocol.validateCertIssuer = function(c, nc) { var issuer = c.tbsCertificate.issuer; var subject = nc.tbsCertificate.subject; - var issuerVerified = issuer.type === subject.type && issuer.value.every(function(issuerArray, i) { - var subjectArray = subject.value[i]; - return issuerArray.every(function(issuerObject, i) { - var subjectObject = subjectArray[i]; + var issuerVerified = + issuer.type === subject.type && + issuer.value.every(function(issuerArray, i) { + var subjectArray = subject.value[i]; + return issuerArray.every(function(issuerObject, i) { + var subjectObject = subjectArray[i]; - var issuerObjectType = issuerObject.type.join('.'); - var subjectObjectType = subjectObject.type.join('.'); + var issuerObjectType = issuerObject.type.join('.'); + var subjectObjectType = subjectObject.type.join('.'); - var issuerObjectValue = issuerObject.value.toString('hex'); - var subjectObjectValue = subjectObject.value.toString('hex'); + var issuerObjectValue = issuerObject.value.toString('hex'); + var subjectObjectValue = subjectObject.value.toString('hex'); - return issuerObjectType === subjectObjectType && issuerObjectValue === subjectObjectValue; + return issuerObjectType === subjectObjectType && issuerObjectValue === subjectObjectValue; + }); }); - }); return issuerVerified; }; @@ -143,13 +145,15 @@ PaymentProtocol.RootCerts = RootCerts; PaymentProtocol.proto = {}; -PaymentProtocol.proto.Output = 'message Output {\ +PaymentProtocol.proto.Output = + 'message Output {\ optional uint64 amount = 1 [default = 0];\ optional bytes script = 2;\ }\n'; -PaymentProtocol.proto.PaymentDetails = 'message PaymentDetails {\ - optional string network = 1 [default = \"main\"];\ +PaymentProtocol.proto.PaymentDetails = + 'message PaymentDetails {\ + optional string network = 1 [default = "main"];\ repeated Output outputs = 2;\ required uint64 time = 3;\ optional uint64 expires = 4;\ @@ -158,22 +162,25 @@ PaymentProtocol.proto.PaymentDetails = 'message PaymentDetails {\ optional bytes merchant_data = 7;\ }\n'; -PaymentProtocol.proto.PaymentRequest = 'message PaymentRequest {\ +PaymentProtocol.proto.PaymentRequest = + 'message PaymentRequest {\ optional uint32 payment_details_version = 1 [default = 1];\ - optional string pki_type = 2 [default = \"none\"];\ + optional string pki_type = 2 [default = "none"];\ optional bytes pki_data = 3;\ required bytes serialized_payment_details = 4;\ optional bytes signature = 5;\ }\n'; -PaymentProtocol.proto.Payment = 'message Payment {\ +PaymentProtocol.proto.Payment = + 'message Payment {\ optional bytes merchant_data = 1;\ repeated bytes transactions = 2;\ repeated Output refund_to = 3;\ optional string memo = 4;\ }\n'; -PaymentProtocol.proto.PaymentACK = 'message PaymentACK {\ +PaymentProtocol.proto.PaymentACK = + 'message PaymentACK {\ required Payment payment = 1;\ optional string memo = 2;\ }\n'; @@ -323,7 +330,7 @@ PaymentProtocol.prototype.serialize = function() { //protobufjs returns either a Buffer or an ArrayBuffer //but we always want a Buffer (which browserify understands, browser or no) var maybebuf = this.message.toBuffer(); - var buf = (Buffer.isBuffer(maybebuf)) ? maybebuf : new Buffer(new Uint8Array(maybebuf)); + var buf = Buffer.isBuffer(maybebuf) ? maybebuf : new Buffer(new Uint8Array(maybebuf)); return buf; }; @@ -413,21 +420,20 @@ PaymentProtocol.prototype.sinVerify = function() { }; // Helpers -PaymentProtocol.PEMtoDER = - PaymentProtocol.prototype._PEMtoDER = function(pem) { - return this.PEMtoDERParam(pem, 'CERTIFICATE'); - }; - -PaymentProtocol.PEMtoDERParam = - PaymentProtocol.prototype._PEMtoDERParam = function(pem, param) { - if (Buffer.isBuffer(pem)) { - pem = pem.toString(); - } - var start = new RegExp('(?=-----BEGIN ' + (param || '[^-]+') + '-----)', 'i'); - var end = new RegExp('^-----END ' + (param || '[^-]+') + '-----$', 'gmi'); - pem = pem.replace(end, ''); - var parts = pem.split(start); - return parts.map(function(part) { +PaymentProtocol.PEMtoDER = PaymentProtocol.prototype._PEMtoDER = function(pem) { + return this.PEMtoDERParam(pem, 'CERTIFICATE'); +}; + +PaymentProtocol.PEMtoDERParam = PaymentProtocol.prototype._PEMtoDERParam = function(pem, param) { + if (Buffer.isBuffer(pem)) { + pem = pem.toString(); + } + var start = new RegExp('(?=-----BEGIN ' + (param || '[^-]+') + '-----)', 'i'); + var end = new RegExp('^-----END ' + (param || '[^-]+') + '-----$', 'gmi'); + pem = pem.replace(end, ''); + var parts = pem.split(start); + return parts + .map(function(part) { var type = /-----BEGIN ([^-]+)-----/.exec(part)[1]; part = part.replace(/-----BEGIN ([^-]+)-----/g, ''); part = part.replace(/\s+/g, ''); @@ -435,54 +441,47 @@ PaymentProtocol.PEMtoDERParam = return; } return new Buffer(part, 'base64'); - }).filter(Boolean); - }; + }) + .filter(Boolean); +}; -PaymentProtocol.DERtoPEM = - PaymentProtocol.prototype._DERtoPEM = function(der, type) { - if (typeof der === 'string') { - der = new Buffer(der, 'hex'); - } - type = type || 'PRIVACY-ENHANCED MESSAGE'; - der = der.toString('base64'); - der = der.replace(/(.{64})/g, '$1\r\n'); - der = der.replace(/\r\n$/, ''); - return '' + - '-----BEGIN ' + type + '-----\r\n' + - der + - '\r\n-----END ' + type + '-----\r\n'; - }; - - -PaymentProtocol.completeChainAndGetCA = - PaymentProtocol.prototype._completeChainAndGetCA = function(chain) { - var caName, pem, der; - var issuer = chain[chain.length - 1]; - var nder = issuer.toString('hex'); - var ndata = new Buffer(nder, 'hex'); - var nc = rfc5280.Certificate.decode(ndata, 'der'); - var values = nc.tbsCertificate.issuer.value; - var l = values.length, - i = 0; - while (i++ < l && !caName) { - var v = values[i]; - if (!v) continue; - var name = v[0].value.toString().substr(2); - - pem = RootCerts.getCert(name); - if (!pem) - pem = RootCerts.getCert(name.replace('Certification Authority', 'CA')); - - // Root Cert found - if (pem) { - caName = name; - der = PaymentProtocol.PEMtoDER(pem)[0]; - chain.push(der); - } - } - return caName; - }; +PaymentProtocol.DERtoPEM = PaymentProtocol.prototype._DERtoPEM = function(der, type) { + if (typeof der === 'string') { + der = new Buffer(der, 'hex'); + } + type = type || 'PRIVACY-ENHANCED MESSAGE'; + der = der.toString('base64'); + der = der.replace(/(.{64})/g, '$1\r\n'); + der = der.replace(/\r\n$/, ''); + return '' + '-----BEGIN ' + type + '-----\r\n' + der + '\r\n-----END ' + type + '-----\r\n'; +}; +PaymentProtocol.completeChainAndGetCA = PaymentProtocol.prototype._completeChainAndGetCA = function(chain) { + var caName, pem, der; + var issuer = chain[chain.length - 1]; + var nder = issuer.toString('hex'); + var ndata = new Buffer(nder, 'hex'); + var nc = rfc5280.Certificate.decode(ndata, 'der'); + var values = nc.tbsCertificate.issuer.value; + var l = values.length, + i = 0; + while (i++ < l && !caName) { + var v = values[i]; + if (!v) continue; + var name = v[0].value.toString().substr(2); + + pem = RootCerts.getCert(name); + if (!pem) pem = RootCerts.getCert(name.replace('Certification Authority', 'CA')); + + // Root Cert found + if (pem) { + caName = name; + der = PaymentProtocol.PEMtoDER(pem)[0]; + chain.push(der); + } + } + return caName; +}; // Expose RootCerts PaymentProtocol.getTrusted = RootCerts.getTrusted; diff --git a/packages/merit-payment-protocol/lib/errors.js b/packages/merit-payment-protocol/lib/errors.js index 2fb95e33ef..0a16c7672f 100644 --- a/packages/merit-payment-protocol/lib/errors.js +++ b/packages/merit-payment-protocol/lib/errors.js @@ -2,7 +2,7 @@ var spec = { name: 'PaymentProtocol', - message: 'Internal Error on merit-payment-protocol Module: {0}' + message: 'Internal Error on merit-payment-protocol Module: {0}', }; module.exports = require('meritcore-lib').errors.extend(spec); diff --git a/packages/merit-payment-protocol/lib/index.js b/packages/merit-payment-protocol/lib/index.js index 9b91611422..6ddd2dc0da 100644 --- a/packages/merit-payment-protocol/lib/index.js +++ b/packages/merit-payment-protocol/lib/index.js @@ -36,7 +36,7 @@ PaymentProtocol.prototype.x509Sign = function(key, returnTrust) { isChain: pki_data.length > 1, signature: sig, caTrusted: !!caName, - caName: caName || null + caName: caName || null, }; } @@ -75,9 +75,7 @@ PaymentProtocol.prototype.x509Verify = function(returnTrust) { pem = PaymentProtocol.DERtoPEM(der, 'CERTIFICATE'); var caName = RootCerts.getTrusted(pem); - if (!caName) - caName = PaymentProtocol.completeChainAndGetCA(chain); - + if (!caName) caName = PaymentProtocol.completeChainAndGetCA(chain); if (chain.length === 1 && !caName) { if (returnTrust) { @@ -87,7 +85,7 @@ PaymentProtocol.prototype.x509Verify = function(returnTrust) { verified: verified, caTrusted: false, caName: null, - chainVerified: false + chainVerified: false, }; } return verified; @@ -103,7 +101,7 @@ PaymentProtocol.prototype.x509Verify = function(returnTrust) { verified: verified, caTrusted: false, caName: null, - chainVerified: false + chainVerified: false, }; } return verified; @@ -118,7 +116,7 @@ PaymentProtocol.prototype.x509Verify = function(returnTrust) { verified: verified, caTrusted: !!caName, caName: caName || null, - chainVerified: chainVerified + chainVerified: chainVerified, }; } @@ -149,8 +147,7 @@ PaymentProtocol.verifyCertChain = function(chain, sigHashAlg) { // Get Public Key from next certificate: var ndata = new Buffer(nder, 'hex'); var nc = rfc5280.Certificate.decode(ndata, 'der'); - var npubKeyAlg = PaymentProtocol.getAlgorithm( - nc.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm); + var npubKeyAlg = PaymentProtocol.getAlgorithm(nc.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm); var npubKey = nc.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; npubKey = PaymentProtocol.DERtoPEM(npubKey, npubKeyAlg + ' PUBLIC KEY'); diff --git a/packages/merit-payment-protocol/lib/rootcerts.js b/packages/merit-payment-protocol/lib/rootcerts.js index 855a1880c0..7a77d74313 100644 --- a/packages/merit-payment-protocol/lib/rootcerts.js +++ b/packages/merit-payment-protocol/lib/rootcerts.js @@ -51,24 +51,29 @@ RootCerts.parsePEM = function(pem) { var parts = pem.trim().split(/(?:\r?\n){2,}/); var headers = {}; if (parts.length > 1) { - headers = parts[0].trim().split(/[\r\n]/).reduce(function(out, line) { - var parts = line.split(/:[ \t]+/); - var key = parts[0].trim().toLowerCase(); - var value = (parts.slice(1).join('') || '').trim(); - out[key] = value; - return out; - }, {}); + headers = parts[0] + .trim() + .split(/[\r\n]/) + .reduce(function(out, line) { + var parts = line.split(/:[ \t]+/); + var key = parts[0].trim().toLowerCase(); + var value = (parts.slice(1).join('') || '').trim(); + out[key] = value; + return out; + }, {}); pem = parts.slice(1).join(''); } pem = pem.replace(/\s+/g, ''); var der = pem ? new Buffer(pem, 'base64') : null; - return [{ - type: type, - headers: headers, - pem: pem, - der: der, - body: der || new Buffer([0]) - }]; + return [ + { + type: type, + headers: headers, + pem: pem, + der: der, + body: der || new Buffer([0]), + }, + ]; }; RootCerts.certs = certs; diff --git a/packages/merit-payment-protocol/test/index.js b/packages/merit-payment-protocol/test/index.js index b297732400..6b4d685475 100644 --- a/packages/merit-payment-protocol/test/index.js +++ b/packages/merit-payment-protocol/test/index.js @@ -11,88 +11,92 @@ var PublicKey = meritcore.PublicKey; var is_browser = process.browser; var PaymentProtocol = require('../'); -var SampleRequest = require('./samplerequest'); +var SampleRequest = require('./samplerequest'); var x509 = { - priv: '' - + 'LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBeFRKdUsyYUdM' - + 'bjFkWEpLRGg0TXdQTFVrbDNISTVwR25HNWFjNGwvMGlobXE4Y3dDCitGVlBnWk1TNTlheWtpc0Ir' - + 'ekM3dnR2a0prL2J2K0JTT1g3b3hkSXN1TDNkS1FGcHVYWFZmcmRiOTV3WW40TSsKL25qRWhYTWxo' - + 'Vk1IL09DaUFnOUpLaFRLV0w2R1JXWkFBaEE3bEJSaGdTTkRUaVRDNTFDYmlLN3hBNnBONCt0UQpI' - + 'eG9tSlBYclpSa2JCMmtsT2ZXd2J2OTNZM0oxS0ZEK2kwUE1RSEx3N3JoRXVteEM5MytISFVWWVZI' - + 'N0gxVFBaCkgxYmRVSkowMmdRZXlsSnNzWUNKeWRaUHpOVC96dXRzL0tKV2RSdjVseHdHOXU5dE1O' - + 'TWdoSmJtQWFNa01HaSsKbzdQTkV5UDNxSEZyWXBZaHM1cHFMSE1STkI3OFFNOUllTmpMRndJREFR' - + 'QUJBb0lCQVFERVJyalBiQUdjbmwxaAorZGIrOTczNGZ0aElBUkpWSko1dTRFK1JKcThSRWhGTEVL' - + 'UFlKNW0yUC94dVZBMXpYV2xnYXhaRUZ6d1VRaUpZCjdsOEpLVjlwSHhReVlaQ1M4dndYZzhpWGtz' - + 'dndQaWRvQmN1YW4vd0RWQ1FCZXk2VkxjVXpSYUd1Ui9sTHNYK1YKN2Z0QjBvUnFsSXFrYmNQZE1N' - + 'dnFUeG93UnVoUG11Q3JWVGpPNHBiTnFuU09OUExPaUovRkFYYjJwZnpGZnBCUgpHeCtFTW16d2Ur' - + 'SEZuSkJHRGhIWjk5bm4vVEJmYUp6TlZDcURZLzNid3o1WDdIUU5ZN1QrSnlUVUZzZVE5NHhzCnpy' - + 'a2lidGRmVGNUanB1K1VoWm80c1p6Q3IrZkhHWm9FOUdEUHF0ZDRnQ3ByazRFS0pzbXFCRVN4QlhT' - + 'RGhZZ04KOXBVRDM4c1pBb0dCQU9yZkRqdDZaL0ZDamFuVThXek5GaWYrOVQxQTJ4b013RDVWU2xN' - + 'dVJyWW1HbGZyMEM5TQpmMUVvZ2l2dVRrYnA3cmtnZFRhWVRTYndmTnFaQkt4Y3R5YzdCaGRwWnhE' - + 'RVdKa2Z5cThxVngvem1Cek1JK1ZzCjJLYi9hcHZXcmJlb3NET0NyeUg1YzhKc1VUOXhUWDNYYnhF' - + 'anlPSlFCU1lHRE1qUHlKNkU5czZMQW9HQkFOYnYKd2d0S2Nra0tLbDJhNXZzaGR2RENnNnFLL1Fn' - + 'T20vNktUSlVKRVNqaHoydFIrZlBWUjcwVEg5UmhoVFJscERXQgpCd3oyU2NCc1RRNDIvTGsxRnky' - + 'MFQvck12S3VmSEw1VE1BNGZ6NWRxMUxIbmN6ejZVazVnWEtBT09rUjlVdVhpClR0eTNoREcyQkM4' - + 'Nk1LTVJ4SjUxRWJxam94d0VSMTAwU2FuTVBmTWxBb0dBSUhLY1pyOHNhUHBHMC9XbFBPREEKZE5v' - + 'V1MxWVFidkxnQkR5SVBpR2doejJRV2lFcjY3em53ZkNVdXpqNiszVUtFKzFXQkNyYVRjemZrdHVj' - + 'OTZyLwphcDRPNDJFZWFnU1dNT0ZoZ1AyYWQ4R1JmRGovcEl4N0NlY3pkVUFkVThnc1A1R0lYR3M0' - + 'QU40eUEwL0Y0dUxHCloxbklRT3ZKS2syZnFvWjZNdHd2dEswQ2dZRUFnSjdGTGVDRTkzUmYyZGdD' - + 'ZFRHWGJZZlpKc3M1bEFLNkV0NUwKNmJ1ZFN5dWw1Z0VPWkgyekNsQlJjZFJSMUFNbSt1V1ZoSW8x' - + 'cERLckFlQ2g1MnIvemRmakxLQXNIejkrQWQ3aQpHUEdzVmw0Vm5jaDFTMzQ0bHJKUGUzQklLZ2dj' - + 'L1hncDNTYnNzcHJMY2orT0wyZElrOUpXbzZ1Y3hmMUJmMkwwCjJlbGhBUWtDZ1lCWHN5elZWL1pK' - + 'cVhOcFdDZzU1TDNVRm9UTHlLU3FsVktNM1dpRzVCS240QWF6VkNITCtHUVUKeHd4U2dSOWZRNElu' - + 'dStyUHJOM0lteWswbEtQR0Y5U3pDUlJUaUpGUjcyc05xbE82bDBWOENXUkFQVFBKY2dxVgoxVThO' - + 'SEs4YjNaaUlvR0orbXNOenBkeHJqNjJIM0E2K1krQXNOWTRTbVVUWEg5eWpnK251a2c9PQotLS0t' - + 'LUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=', - pub: '' - + 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FR' - + 'OEFNSUlCQ2dLQ0FRRUF4VEp1SzJhR0xuMWRYSktEaDRNdwpQTFVrbDNISTVwR25HNWFjNGwvMGlo' - + 'bXE4Y3dDK0ZWUGdaTVM1OWF5a2lzQit6Qzd2dHZrSmsvYnYrQlNPWDdvCnhkSXN1TDNkS1FGcHVY' - + 'WFZmcmRiOTV3WW40TSsvbmpFaFhNbGhWTUgvT0NpQWc5SktoVEtXTDZHUldaQUFoQTcKbEJSaGdT' - + 'TkRUaVRDNTFDYmlLN3hBNnBONCt0UUh4b21KUFhyWlJrYkIya2xPZld3YnY5M1kzSjFLRkQraTBQ' - + 'TQpRSEx3N3JoRXVteEM5MytISFVWWVZIN0gxVFBaSDFiZFVKSjAyZ1FleWxKc3NZQ0p5ZFpQek5U' - + 'L3p1dHMvS0pXCmRSdjVseHdHOXU5dE1OTWdoSmJtQWFNa01HaStvN1BORXlQM3FIRnJZcFloczVw' - + 'cUxITVJOQjc4UU05SWVOakwKRndJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==', - der: '' - + 'MIIDBjCCAe4CCQDI2qWdA3/VpDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTETMBEGA1UE' - + 'CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE0MDcx' - + 'NjAxMzM1MVoXDTE1MDcxNjAxMzM1MVowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3Rh' - + 'dGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQAD' - + 'ggEPADCCAQoCggEBAMUybitmhi59XVySg4eDMDy1JJdxyOaRpxuWnOJf9IoZqvHMAvhVT4GTEufW' - + 'spIrAfswu77b5CZP27/gUjl+6MXSLLi93SkBabl11X63W/ecGJ+DPv54xIVzJYVTB/zgogIPSSoU' - + 'yli+hkVmQAIQO5QUYYEjQ04kwudQm4iu8QOqTePrUB8aJiT162UZGwdpJTn1sG7/d2NydShQ/otD' - + 'zEBy8O64RLpsQvd/hx1FWFR+x9Uz2R9W3VCSdNoEHspSbLGAicnWT8zU/87rbPyiVnUb+ZccBvbv' - + 'bTDTIISW5gGjJDBovqOzzRMj96hxa2KWIbOaaixzETQe/EDPSHjYyxcCAwEAATANBgkqhkiG9w0B' - + 'AQUFAAOCAQEAL6AMMfC3TlRcmsIgHxjVD4XYtISlldnrn2X9zvFbJKCpNy8XQQosQxrhyfzPHQKj' - + 'lS2L/KCGMnjx9QkYD2Hlp1MJ1uVv9888th/gcZOv3Or3hQyi5K1Sh5xCG+69lUOqUEGu9B4irsqo' - + 'FomQVbQolSy+t4apdJi7kuEDwFDk4gZiVEfsuX+naN5a6pCnWnhX1Vf4fKwfkLobKKXm2zQVsjxl' - + 'wBAqOEmJGDLoRMXH56qJnEZ/dqsczaJOHQSi9mFEHL0r5rsEDTT5AVxdnBfNnyGaCH7/zANEko+F' - + 'GBj1JdJaJgFTXdbxDoyoPTPD+LJqSK5XYToo46y/T0u9CLveNA==', - pem: '' - + 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCakNDQWU0Q0NRREkycVdkQTMvVnBEQU5C' - + 'Z2txaGtpRzl3MEJBUVVGQURCRk1Rc3dDUVlEVlFRR0V3SkIKVlRFVE1CRUdBMVVFQ0F3S1UyOXRa' - + 'UzFUZEdGMFpURWhNQjhHQTFVRUNnd1lTVzUwWlhKdVpYUWdWMmxrWjJsMApjeUJRZEhrZ1RIUmtN' - + 'QjRYRFRFME1EY3hOakF4TXpNMU1Wb1hEVEUxTURjeE5qQXhNek0xTVZvd1JURUxNQWtHCkExVUVC' - + 'aE1DUVZVeEV6QVJCZ05WQkFnTUNsTnZiV1V0VTNSaGRHVXhJVEFmQmdOVkJBb01HRWx1ZEdWeWJt' - + 'VjAKSUZkcFpHZHBkSE1nVUhSNUlFeDBaRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFE' - + 'Q0NBUW9DZ2dFQgpBTVV5Yml0bWhpNTlYVnlTZzRlRE1EeTFKSmR4eU9hUnB4dVduT0pmOUlvWnF2' - + 'SE1BdmhWVDRHVEV1ZldzcElyCkFmc3d1NzdiNUNaUDI3L2dVamwrNk1YU0xMaTkzU2tCYWJsMTFY' - + 'NjNXL2VjR0orRFB2NTR4SVZ6SllWVEIvemcKb2dJUFNTb1V5bGkraGtWbVFBSVFPNVFVWVlFalEw' - + 'NGt3dWRRbTRpdThRT3FUZVByVUI4YUppVDE2MlVaR3dkcApKVG4xc0c3L2QyTnlkU2hRL290RHpF' - + 'Qnk4TzY0Ukxwc1F2ZC9oeDFGV0ZSK3g5VXoyUjlXM1ZDU2ROb0VIc3BTCmJMR0FpY25XVDh6VS84' - + 'N3JiUHlpVm5VYitaY2NCdmJ2YlREVElJU1c1Z0dqSkRCb3ZxT3p6Uk1qOTZoeGEyS1cKSWJPYWFp' - + 'eHpFVFFlL0VEUFNIall5eGNDQXdFQUFUQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFMNkFNTWZD' - + 'MwpUbFJjbXNJZ0h4alZENFhZdElTbGxkbnJuMlg5enZGYkpLQ3BOeThYUVFvc1F4cmh5ZnpQSFFL' - + 'amxTMkwvS0NHCk1uang5UWtZRDJIbHAxTUoxdVZ2OTg4OHRoL2djWk92M09yM2hReWk1SzFTaDV4' - + 'Q0crNjlsVU9xVUVHdTlCNGkKcnNxb0ZvbVFWYlFvbFN5K3Q0YXBkSmk3a3VFRHdGRGs0Z1ppVkVm' - + 'c3VYK25hTjVhNnBDblduaFgxVmY0Zkt3ZgprTG9iS0tYbTJ6UVZzanhsd0JBcU9FbUpHRExvUk1Y' - + 'SDU2cUpuRVovZHFzY3phSk9IUVNpOW1GRUhMMHI1cnNFCkRUVDVBVnhkbkJmTm55R2FDSDcvekFO' - + 'RWtvK0ZHQmoxSmRKYUpnRlRYZGJ4RG95b1BUUEQrTEpxU0s1WFlUb28KNDZ5L1QwdTlDTHZlTkE9' - + 'PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==', + priv: + '' + + 'LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBeFRKdUsyYUdM' + + 'bjFkWEpLRGg0TXdQTFVrbDNISTVwR25HNWFjNGwvMGlobXE4Y3dDCitGVlBnWk1TNTlheWtpc0Ir' + + 'ekM3dnR2a0prL2J2K0JTT1g3b3hkSXN1TDNkS1FGcHVYWFZmcmRiOTV3WW40TSsKL25qRWhYTWxo' + + 'Vk1IL09DaUFnOUpLaFRLV0w2R1JXWkFBaEE3bEJSaGdTTkRUaVRDNTFDYmlLN3hBNnBONCt0UQpI' + + 'eG9tSlBYclpSa2JCMmtsT2ZXd2J2OTNZM0oxS0ZEK2kwUE1RSEx3N3JoRXVteEM5MytISFVWWVZI' + + 'N0gxVFBaCkgxYmRVSkowMmdRZXlsSnNzWUNKeWRaUHpOVC96dXRzL0tKV2RSdjVseHdHOXU5dE1O' + + 'TWdoSmJtQWFNa01HaSsKbzdQTkV5UDNxSEZyWXBZaHM1cHFMSE1STkI3OFFNOUllTmpMRndJREFR' + + 'QUJBb0lCQVFERVJyalBiQUdjbmwxaAorZGIrOTczNGZ0aElBUkpWSko1dTRFK1JKcThSRWhGTEVL' + + 'UFlKNW0yUC94dVZBMXpYV2xnYXhaRUZ6d1VRaUpZCjdsOEpLVjlwSHhReVlaQ1M4dndYZzhpWGtz' + + 'dndQaWRvQmN1YW4vd0RWQ1FCZXk2VkxjVXpSYUd1Ui9sTHNYK1YKN2Z0QjBvUnFsSXFrYmNQZE1N' + + 'dnFUeG93UnVoUG11Q3JWVGpPNHBiTnFuU09OUExPaUovRkFYYjJwZnpGZnBCUgpHeCtFTW16d2Ur' + + 'SEZuSkJHRGhIWjk5bm4vVEJmYUp6TlZDcURZLzNid3o1WDdIUU5ZN1QrSnlUVUZzZVE5NHhzCnpy' + + 'a2lidGRmVGNUanB1K1VoWm80c1p6Q3IrZkhHWm9FOUdEUHF0ZDRnQ3ByazRFS0pzbXFCRVN4QlhT' + + 'RGhZZ04KOXBVRDM4c1pBb0dCQU9yZkRqdDZaL0ZDamFuVThXek5GaWYrOVQxQTJ4b013RDVWU2xN' + + 'dVJyWW1HbGZyMEM5TQpmMUVvZ2l2dVRrYnA3cmtnZFRhWVRTYndmTnFaQkt4Y3R5YzdCaGRwWnhE' + + 'RVdKa2Z5cThxVngvem1Cek1JK1ZzCjJLYi9hcHZXcmJlb3NET0NyeUg1YzhKc1VUOXhUWDNYYnhF' + + 'anlPSlFCU1lHRE1qUHlKNkU5czZMQW9HQkFOYnYKd2d0S2Nra0tLbDJhNXZzaGR2RENnNnFLL1Fn' + + 'T20vNktUSlVKRVNqaHoydFIrZlBWUjcwVEg5UmhoVFJscERXQgpCd3oyU2NCc1RRNDIvTGsxRnky' + + 'MFQvck12S3VmSEw1VE1BNGZ6NWRxMUxIbmN6ejZVazVnWEtBT09rUjlVdVhpClR0eTNoREcyQkM4' + + 'Nk1LTVJ4SjUxRWJxam94d0VSMTAwU2FuTVBmTWxBb0dBSUhLY1pyOHNhUHBHMC9XbFBPREEKZE5v' + + 'V1MxWVFidkxnQkR5SVBpR2doejJRV2lFcjY3em53ZkNVdXpqNiszVUtFKzFXQkNyYVRjemZrdHVj' + + 'OTZyLwphcDRPNDJFZWFnU1dNT0ZoZ1AyYWQ4R1JmRGovcEl4N0NlY3pkVUFkVThnc1A1R0lYR3M0' + + 'QU40eUEwL0Y0dUxHCloxbklRT3ZKS2syZnFvWjZNdHd2dEswQ2dZRUFnSjdGTGVDRTkzUmYyZGdD' + + 'ZFRHWGJZZlpKc3M1bEFLNkV0NUwKNmJ1ZFN5dWw1Z0VPWkgyekNsQlJjZFJSMUFNbSt1V1ZoSW8x' + + 'cERLckFlQ2g1MnIvemRmakxLQXNIejkrQWQ3aQpHUEdzVmw0Vm5jaDFTMzQ0bHJKUGUzQklLZ2dj' + + 'L1hncDNTYnNzcHJMY2orT0wyZElrOUpXbzZ1Y3hmMUJmMkwwCjJlbGhBUWtDZ1lCWHN5elZWL1pK' + + 'cVhOcFdDZzU1TDNVRm9UTHlLU3FsVktNM1dpRzVCS240QWF6VkNITCtHUVUKeHd4U2dSOWZRNElu' + + 'dStyUHJOM0lteWswbEtQR0Y5U3pDUlJUaUpGUjcyc05xbE82bDBWOENXUkFQVFBKY2dxVgoxVThO' + + 'SEs4YjNaaUlvR0orbXNOenBkeHJqNjJIM0E2K1krQXNOWTRTbVVUWEg5eWpnK251a2c9PQotLS0t' + + 'LUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=', + pub: + '' + + 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FR' + + 'OEFNSUlCQ2dLQ0FRRUF4VEp1SzJhR0xuMWRYSktEaDRNdwpQTFVrbDNISTVwR25HNWFjNGwvMGlo' + + 'bXE4Y3dDK0ZWUGdaTVM1OWF5a2lzQit6Qzd2dHZrSmsvYnYrQlNPWDdvCnhkSXN1TDNkS1FGcHVY' + + 'WFZmcmRiOTV3WW40TSsvbmpFaFhNbGhWTUgvT0NpQWc5SktoVEtXTDZHUldaQUFoQTcKbEJSaGdT' + + 'TkRUaVRDNTFDYmlLN3hBNnBONCt0UUh4b21KUFhyWlJrYkIya2xPZld3YnY5M1kzSjFLRkQraTBQ' + + 'TQpRSEx3N3JoRXVteEM5MytISFVWWVZIN0gxVFBaSDFiZFVKSjAyZ1FleWxKc3NZQ0p5ZFpQek5U' + + 'L3p1dHMvS0pXCmRSdjVseHdHOXU5dE1OTWdoSmJtQWFNa01HaStvN1BORXlQM3FIRnJZcFloczVw' + + 'cUxITVJOQjc4UU05SWVOakwKRndJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==', + der: + '' + + 'MIIDBjCCAe4CCQDI2qWdA3/VpDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTETMBEGA1UE' + + 'CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE0MDcx' + + 'NjAxMzM1MVoXDTE1MDcxNjAxMzM1MVowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3Rh' + + 'dGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQAD' + + 'ggEPADCCAQoCggEBAMUybitmhi59XVySg4eDMDy1JJdxyOaRpxuWnOJf9IoZqvHMAvhVT4GTEufW' + + 'spIrAfswu77b5CZP27/gUjl+6MXSLLi93SkBabl11X63W/ecGJ+DPv54xIVzJYVTB/zgogIPSSoU' + + 'yli+hkVmQAIQO5QUYYEjQ04kwudQm4iu8QOqTePrUB8aJiT162UZGwdpJTn1sG7/d2NydShQ/otD' + + 'zEBy8O64RLpsQvd/hx1FWFR+x9Uz2R9W3VCSdNoEHspSbLGAicnWT8zU/87rbPyiVnUb+ZccBvbv' + + 'bTDTIISW5gGjJDBovqOzzRMj96hxa2KWIbOaaixzETQe/EDPSHjYyxcCAwEAATANBgkqhkiG9w0B' + + 'AQUFAAOCAQEAL6AMMfC3TlRcmsIgHxjVD4XYtISlldnrn2X9zvFbJKCpNy8XQQosQxrhyfzPHQKj' + + 'lS2L/KCGMnjx9QkYD2Hlp1MJ1uVv9888th/gcZOv3Or3hQyi5K1Sh5xCG+69lUOqUEGu9B4irsqo' + + 'FomQVbQolSy+t4apdJi7kuEDwFDk4gZiVEfsuX+naN5a6pCnWnhX1Vf4fKwfkLobKKXm2zQVsjxl' + + 'wBAqOEmJGDLoRMXH56qJnEZ/dqsczaJOHQSi9mFEHL0r5rsEDTT5AVxdnBfNnyGaCH7/zANEko+F' + + 'GBj1JdJaJgFTXdbxDoyoPTPD+LJqSK5XYToo46y/T0u9CLveNA==', + pem: + '' + + 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCakNDQWU0Q0NRREkycVdkQTMvVnBEQU5C' + + 'Z2txaGtpRzl3MEJBUVVGQURCRk1Rc3dDUVlEVlFRR0V3SkIKVlRFVE1CRUdBMVVFQ0F3S1UyOXRa' + + 'UzFUZEdGMFpURWhNQjhHQTFVRUNnd1lTVzUwWlhKdVpYUWdWMmxrWjJsMApjeUJRZEhrZ1RIUmtN' + + 'QjRYRFRFME1EY3hOakF4TXpNMU1Wb1hEVEUxTURjeE5qQXhNek0xTVZvd1JURUxNQWtHCkExVUVC' + + 'aE1DUVZVeEV6QVJCZ05WQkFnTUNsTnZiV1V0VTNSaGRHVXhJVEFmQmdOVkJBb01HRWx1ZEdWeWJt' + + 'VjAKSUZkcFpHZHBkSE1nVUhSNUlFeDBaRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFE' + + 'Q0NBUW9DZ2dFQgpBTVV5Yml0bWhpNTlYVnlTZzRlRE1EeTFKSmR4eU9hUnB4dVduT0pmOUlvWnF2' + + 'SE1BdmhWVDRHVEV1ZldzcElyCkFmc3d1NzdiNUNaUDI3L2dVamwrNk1YU0xMaTkzU2tCYWJsMTFY' + + 'NjNXL2VjR0orRFB2NTR4SVZ6SllWVEIvemcKb2dJUFNTb1V5bGkraGtWbVFBSVFPNVFVWVlFalEw' + + 'NGt3dWRRbTRpdThRT3FUZVByVUI4YUppVDE2MlVaR3dkcApKVG4xc0c3L2QyTnlkU2hRL290RHpF' + + 'Qnk4TzY0Ukxwc1F2ZC9oeDFGV0ZSK3g5VXoyUjlXM1ZDU2ROb0VIc3BTCmJMR0FpY25XVDh6VS84' + + 'N3JiUHlpVm5VYitaY2NCdmJ2YlREVElJU1c1Z0dqSkRCb3ZxT3p6Uk1qOTZoeGEyS1cKSWJPYWFp' + + 'eHpFVFFlL0VEUFNIall5eGNDQXdFQUFUQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFMNkFNTWZD' + + 'MwpUbFJjbXNJZ0h4alZENFhZdElTbGxkbnJuMlg5enZGYkpLQ3BOeThYUVFvc1F4cmh5ZnpQSFFL' + + 'amxTMkwvS0NHCk1uang5UWtZRDJIbHAxTUoxdVZ2OTg4OHRoL2djWk92M09yM2hReWk1SzFTaDV4' + + 'Q0crNjlsVU9xVUVHdTlCNGkKcnNxb0ZvbVFWYlFvbFN5K3Q0YXBkSmk3a3VFRHdGRGs0Z1ppVkVm' + + 'c3VYK25hTjVhNnBDblduaFgxVmY0Zkt3ZgprTG9iS0tYbTJ6UVZzanhsd0JBcU9FbUpHRExvUk1Y' + + 'SDU2cUpuRVovZHFzY3phSk9IUVNpOW1GRUhMMHI1cnNFCkRUVDVBVnhkbkJmTm55R2FDSDcvekFO' + + 'RWtvK0ZHQmoxSmRKYUpnRlRYZGJ4RG95b1BUUEQrTEpxU0s1WFlUb28KNDZ5L1QwdTlDTHZlTkE9' + + 'PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==', sig1: new Buffer(0), sig2: new Buffer(0), - sig3: new Buffer(0) + sig3: new Buffer(0), }; x509.priv = new Buffer(x509.priv, 'base64'); @@ -101,7 +105,6 @@ x509.der = new Buffer(x509.der, 'base64'); x509.pem = new Buffer(x509.pem, 'base64'); describe('PaymentProtocol', function() { - this.timeout(15000); it('should be able to create class', function() { @@ -109,7 +112,6 @@ describe('PaymentProtocol', function() { }); describe('#Output', function() { - it('should not fail', function() { var obj = {}; var output = new PaymentProtocol.Output(); @@ -119,19 +121,23 @@ describe('PaymentProtocol', function() { it('should be able to set the amount of an output', function() { var output = new PaymentProtocol.Output(); output.set('amount', 20); - output.get('amount').toInt().should.equal(20); + output + .get('amount') + .toInt() + .should.equal(20); }); it('should be able to make output using "makeOutput"', function() { var output = new PaymentProtocol().makeOutput(); output.message.set('amount', 20); - output.message.get('amount').toInt().should.equal(20); + output.message + .get('amount') + .toInt() + .should.equal(20); }); - }); describe('#PaymentDetails', function() { - it('should not fail', function() { var obj = {}; var pd = new PaymentProtocol.PaymentDetails(); @@ -152,11 +158,9 @@ describe('PaymentProtocol', function() { var hex = pd.toHex(); hex.length.should.be.greaterThan(0); }); - }); describe('#PaymentRequest', function() { - it('should not fail', function() { var obj = {}; var pd = new PaymentProtocol.PaymentRequest(); @@ -172,11 +176,9 @@ describe('PaymentProtocol', function() { var prhex = pr.toHex(); prhex.length.should.be.greaterThan(0); }); - }); describe('#Payment', function() { - it('should not fail', function() { var obj = {}; var pd = new PaymentProtocol.Payment(); @@ -190,11 +192,9 @@ describe('PaymentProtocol', function() { var phex = p.toHex(); phex.length.should.be.greaterThan(0); }); - }); describe('#PaymentACK', function() { - it('should not fail', function() { var obj = {}; var pd = new PaymentProtocol.PaymentACK(); @@ -228,11 +228,9 @@ describe('PaymentProtocol', function() { var serialized2 = ack2.serialize(); serialized.should.deep.equal(serialized2); }); - }); describe('#X509Certificates', function() { - it('should not fail', function() { var obj = {}; var pd = new PaymentProtocol.X509Certificates(); @@ -246,26 +244,22 @@ describe('PaymentProtocol', function() { var xhex = x.toHex(); xhex.length.should.be.greaterThan(0); }); - }); describe('#isValidSize', function() { - it('should return true for validly sized payment', function() { var paypro = new PaymentProtocol(); paypro.makePayment(); paypro.set('memo', 'test memo'); paypro.isValidSize().should.equal(true); }); - }); describe('#getContentType', function() { - it('should error without a known message type', function() { var paypro = new PaymentProtocol(); paypro.messageType = 'unknown'; - expect(function(){ + expect(function() { paypro.getContentType(); }).to.throw(Error); }); @@ -276,11 +270,9 @@ describe('PaymentProtocol', function() { paypro.set('memo', 'test memo'); paypro.getContentType().should.equal('application/merit-payment'); }); - }); describe('#set', function() { - it('should set a field', function() { var obj = {}; var paypro = new PaymentProtocol(); @@ -288,11 +280,9 @@ describe('PaymentProtocol', function() { paypro.set('memo', 'test memo'); paypro.get('memo').should.equal('test memo'); }); - }); describe('#get', function() { - it('should get a field', function() { var obj = {}; var paypro = new PaymentProtocol(); @@ -300,30 +290,26 @@ describe('PaymentProtocol', function() { paypro.set('memo', 'test memo'); paypro.get('memo').should.equal('test memo'); }); - }); describe('#setObj', function() { - it('should set properties of paymentdetails', function() { var pd = new PaymentProtocol.PaymentDetails(); var paypro = new PaymentProtocol(); - paypro.messageType = "PaymentDetails"; + paypro.messageType = 'PaymentDetails'; paypro.message = pd; paypro.setObj({ - time: 0 + time: 0, }); paypro.get('time').should.equal(0); }); - }); describe('#serializeForSig', function() { - it('should error when not a payment request', function() { var paypro = new PaymentProtocol(); paypro.messageType = 'unknown'; - expect(function(){ + expect(function() { paypro.serializeForSig(); }).to.throw(Error); }); @@ -343,11 +329,9 @@ describe('PaymentProtocol', function() { valid.should.equal(true); buf.length.should.be.greaterThan(0); }); - }); describe('#serialize', function() { - it('should serialize', function() { var obj = {}; var paypro = new PaymentProtocol(); @@ -358,15 +342,13 @@ describe('PaymentProtocol', function() { buf.length.should.be.greaterThan(0); Buffer.isBuffer(buf).should.equal(true); }); - }); describe('#deserialize', function() { - it('should error without a message type', function() { var paypro = new PaymentProtocol(); - expect(function(){ - paypro.deserialize(new Buffer({size: 12})); + expect(function() { + paypro.deserialize(new Buffer({ size: 12 })); }).to.throw(Error); }); @@ -382,14 +364,12 @@ describe('PaymentProtocol', function() { paypro2.get('memo').should.equal('test memo'); paypro2.get('time').should.equal(0); }); - }); describe('#sign', function() { - it('should error when not a payment request', function() { var paypro = new PaymentProtocol(); - expect(function(){ + expect(function() { paypro.sign(); }).to.throw(Error); }); @@ -405,7 +385,7 @@ describe('PaymentProtocol', function() { it('should error if unkown pki_type', function() { var paypro = new PaymentProtocol().makePaymentRequest(); paypro.set('pki_type', 'x508'); //typo - expect(function(){ + expect(function() { paypro.sign(); }).to.throw(Error); }); @@ -443,14 +423,12 @@ describe('PaymentProtocol', function() { x509.sig1 = paypro.get('signature'); x509.sig1.length.should.be.greaterThan(0); }); - }); describe('#verify', function() { - it('should error if not a payment request', function() { var paypro = new PaymentProtocol(); - expect(function(){ + expect(function() { paypro.verify(); }).to.throw(Error); }); @@ -465,7 +443,7 @@ describe('PaymentProtocol', function() { it('should error if unsupported pki_type', function() { var paypro = new PaymentProtocol().makePaymentRequest(); paypro.set('pki_type', 'x508'); // typo - expect(function(){ + expect(function() { paypro.verify(); }).to.throw(Error); }); @@ -511,14 +489,12 @@ describe('PaymentProtocol', function() { should.equal(null, trust.caName); trust.chainVerified.should.equal(false); }); - }); describe('#sinSign', function() { - it('should error if not sent an instance of PrivateKey', function() { var paypro = new PaymentProtocol(); - expect(function(){ + expect(function() { paypro.sinSign(Number(7)); // not a private key }).to.throw(TypeError); }); @@ -535,11 +511,9 @@ describe('PaymentProtocol', function() { var sig = paypro.sinSign(key); sig.length.should.be.greaterThan(0); }); - }); describe('#sinVerify', function() { - it('should verify assuming pki_type is SIN', function() { var pd = new PaymentProtocol.PaymentDetails(); pd.set('time', 0); @@ -553,7 +527,6 @@ describe('PaymentProtocol', function() { var verify = paypro.sinVerify(); verify.should.equal(true); }); - }); describe('#x509+sha256Sign', function() { @@ -709,18 +682,22 @@ describe('PaymentProtocol', function() { ver.should.equal(1); pki_type.should.equal('x509+sha256'); pki_data.length.should.equal(4); - sig.toString('hex').should.equal('' - + '1566366ab78842a514c056ca7ecb76481262cac74cc4c4ccdc' - + '82c4980bc3300de67836d61d3e06dc8c90798a7774c21c7ad4' - + 'fe634b85faa8719d6402411bb720396ae03cbb4e14f06f7894' - + 'a66b208b99f727fab35d32f4f2148294d24bea1b3f240c159d' - + '0fd3ee4a32e5f926bf7c05eb7a3f75e01d9af81254cfbb6160' - + '6467750ea7e0a1536728358e0898d06f57235e4096d2caf647' - + 'ae58dff645be80c9b3555fa96c81efa07d421977d26214ad4f' - + '1ff642a93d0925656aeab454fa0b60fcbb6c1bc570eb6e43e7' - + '613392f37900748635ae381534bfaa558792bc46028b9efce3' - + '91423a9c1201f76292614b30a14272e837f3813045b035f3d4' - + '2f4f76f48acd'); + sig + .toString('hex') + .should.equal( + '' + + '1566366ab78842a514c056ca7ecb76481262cac74cc4c4ccdc' + + '82c4980bc3300de67836d61d3e06dc8c90798a7774c21c7ad4' + + 'fe634b85faa8719d6402411bb720396ae03cbb4e14f06f7894' + + 'a66b208b99f727fab35d32f4f2148294d24bea1b3f240c159d' + + '0fd3ee4a32e5f926bf7c05eb7a3f75e01d9af81254cfbb6160' + + '6467750ea7e0a1536728358e0898d06f57235e4096d2caf647' + + 'ae58dff645be80c9b3555fa96c81efa07d421977d26214ad4f' + + '1ff642a93d0925656aeab454fa0b60fcbb6c1bc570eb6e43e7' + + '613392f37900748635ae381534bfaa558792bc46028b9efce3' + + '91423a9c1201f76292614b30a14272e837f3813045b035f3d4' + + '2f4f76f48acd', + ); if (is_browser) { var type = 'SHA256'; @@ -728,7 +705,7 @@ describe('PaymentProtocol', function() { var buf = pr.serializeForSig(); var jsrsaSig = new KJUR.crypto.Signature({ alg: type + 'withRSA', - prov: 'cryptojs/jsrsa' + prov: 'cryptojs/jsrsa', }); var signedCert = pki_data[0]; var der = signedCert.toString('hex'); @@ -817,7 +794,7 @@ describe('PaymentProtocol', function() { var buf = pr.serializeForSig(); var jsrsaSig = new KJUR.crypto.Signature({ alg: type + 'withRSA', - prov: 'cryptojs/jsrsa' + prov: 'cryptojs/jsrsa', }); var signedCert = pki_data[0]; var der = signedCert.toString('hex'); @@ -869,7 +846,10 @@ describe('PaymentProtocol', function() { memo.should.equal('Payment request for BitPay invoice PAQtNxX7KL8BtJBnfXyTaH for merchant BitGive Foundation'); payment_url.should.equal('https://bitpay.com/i/PAQtNxX7KL8BtJBnfXyTaH'); var merchant_data = pd.get('merchant_data'); - should.equal('{"invoiceId":"PAQtNxX7KL8BtJBnfXyTaH","merchantId":"TxZ5RyChmZw2isKjJWGhBc"}', merchant_data.toString()); + should.equal( + '{"invoiceId":"PAQtNxX7KL8BtJBnfXyTaH","merchantId":"TxZ5RyChmZw2isKjJWGhBc"}', + merchant_data.toString(), + ); }); it.skip('should verify a real PaymentRequest without Root Cert (case 2: Coinbase)', function() { @@ -892,14 +872,13 @@ describe('PaymentProtocol', function() { pki_data.length.should.equal(2); - if (is_browser) { var type = 'SHA256'; var pem = PaymentProtocol.prototype._DERtoPEM(pki_data[0], 'CERTIFICATE'); var buf = pr.serializeForSig(); var jsrsaSig = new KJUR.crypto.Signature({ alg: type + 'withRSA', - prov: 'cryptojs/jsrsa' + prov: 'cryptojs/jsrsa', }); var signedCert = pki_data[0]; var der = signedCert.toString('hex'); @@ -951,10 +930,11 @@ describe('PaymentProtocol', function() { memo.should.equal('Payment request for BitPay invoice PAQtNxX7KL8BtJBnfXyTaH for merchant BitGive Foundation'); payment_url.should.equal('https://bitpay.com/i/PAQtNxX7KL8BtJBnfXyTaH'); var merchant_data = pd.get('merchant_data'); - should.equal('{"invoiceId":"PAQtNxX7KL8BtJBnfXyTaH","merchantId":"TxZ5RyChmZw2isKjJWGhBc"}', merchant_data.toString()); + should.equal( + '{"invoiceId":"PAQtNxX7KL8BtJBnfXyTaH","merchantId":"TxZ5RyChmZw2isKjJWGhBc"}', + merchant_data.toString(), + ); }); - - }); describe('#PEMtoDER', function() { @@ -981,6 +961,4 @@ describe('PaymentProtocol', function() { pem1.should.equal(pem2); }); }); - - }); diff --git a/packages/merit-payment-protocol/test/samplerequest.js b/packages/merit-payment-protocol/test/samplerequest.js index a17fefb90e..2b8d1ebcef 100644 --- a/packages/merit-payment-protocol/test/samplerequest.js +++ b/packages/merit-payment-protocol/test/samplerequest.js @@ -2,458 +2,461 @@ // A test PaymentRequest (with a full cert chain) from test.bitpay.com: var SampleRequest = {}; -SampleRequest.bitpay = new Buffer('' - + '0801120b783530392b7368613235361a89250aa40a3082052030820408a0' - + '03020102020727a49d05046d62300d06092a864886f70d01010b05003081' - + 'b4310b30090603550406130255533110300e060355040813074172697a6f' - + '6e61311330110603550407130a53636f74747364616c65311a3018060355' - + '040a1311476f44616464792e636f6d2c20496e632e312d302b060355040b' - + '1324687474703a2f2f63657274732e676f64616464792e636f6d2f726570' - + '6f7369746f72792f313330310603550403132a476f204461646479205365' - + '6375726520436572746966696361746520417574686f72697479202d2047' - + '32301e170d3134303432363132333532365a170d31363034323631323335' - + '32365a303a3121301f060355040b1318446f6d61696e20436f6e74726f6c' - + '2056616c6964617465643115301306035504030c0c2a2e6269747061792e' - + '636f6d30820122300d06092a864886f70d01010105000382010f00308201' - + '0a0282010100e2a5dd4aea959c1d0fb016e6e05bb7011e741cdc61918c61' - + 'f9625a2f682f485f0e862ea63db61cc9161753127504de800604df36b10f' - + '46cb17ab6cb99dba8aa45a36adfb901a2fc380c89e234bce18de6639b883' - + 'e9339801673efaee1f2df77eeb82f7c39c96a2f8ef4572b634c203d9be8f' - + 'd1e0036d32fb38b6b9b5ecd5a0684345c7e9ffc5d26bc6fd69aa6619f77b' - + 'adaa4bfb989478fb2f41aa92782e40b34ba9ac4549a4e6fda76b5fc4a581' - + '853bd0de5fb5a2c6dfdc12cdfadb54e9636a6d1223705924b8be566b81ac' - + '7921078cf590a146ae397a84908ef4fc83ff5715a44ab59e9258674d9011' - + '3bb607b8d81eb268e4c6ce849497c76521795b0873950203010001a38201' - + 'ae308201aa300f0603551d130101ff04053003010100301d0603551d2504' - + '16301406082b0601050507030106082b06010505070302300e0603551d0f' - + '0101ff0404030205a030360603551d1f042f302d302ba029a02786256874' - + '74703a2f2f63726c2e676f64616464792e636f6d2f676469673273312d34' - + '392e63726c30530603551d20044c304a3048060b6086480186fd6d010717' - + '013039303706082b06010505070201162b687474703a2f2f636572746966' - + '6963617465732e676f64616464792e636f6d2f7265706f7369746f72792f' - + '307606082b06010505070101046a3068302406082b060105050730018618' - + '687474703a2f2f6f6373702e676f64616464792e636f6d2f304006082b06' - + '0105050730028634687474703a2f2f6365727469666963617465732e676f' - + '64616464792e636f6d2f7265706f7369746f72792f67646967322e637274' - + '301f0603551d2304183016801440c2bd278ecc348330a233d7fb6cb3f0b4' - + '2c80ce30230603551d11041c301a820c2a2e6269747061792e636f6d820a' - + '6269747061792e636f6d301d0603551d0e0416041485454e3b4072e2f58e' - + '377438988b5229387e967a300d06092a864886f70d01010b050003820101' - + '002d0a7ef97f988905ebbbad4e9ffb690352535211d6792516119838b55f' - + '24ff9fa4e93b6187b8517cbb0477457d3378078ef66057abe41bcafeb142' - + 'ec52443a94b88114fa069f725c6198581d97af16352727f4f35e7f2110fa' - + 'a41a0511bcfdf8e3f4a3a310278c150b10f32a962c81e8f3d5374d9cb56d' - + '893027ff4fa4e3c3e6384c1f1557ceea6fca9cbc0c110748c08b82d8f0ed' - + '9a579637ee43a2d8fec3b5b04d1f3c8f1a3e2088da2274b6bc60948bbe74' - + '4a7f8b942b41f0ae9b4afaeefbb7e0f04a0587b52efb6ebfa2d970b9de56' - + 'a068575e4bf0cf824618dc17bbeaa2cdd25d65970a9f1a06fc9fffb466a1' - + '0c9568cd651795bc2c7996975027bdbaba0ad409308204d0308203b8a003' - + '020102020107300d06092a864886f70d01010b0500308183310b30090603' - + '550406130255533110300e060355040813074172697a6f6e613113301106' - + '03550407130a53636f74747364616c65311a3018060355040a1311476f44' - + '616464792e636f6d2c20496e632e3131302f06035504031328476f204461' - + '64647920526f6f7420436572746966696361746520417574686f72697479' - + '202d204732301e170d3131303530333037303030305a170d333130353033' - + '3037303030305a3081b4310b30090603550406130255533110300e060355' - + '040813074172697a6f6e61311330110603550407130a53636f7474736461' - + '6c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e' - + '312d302b060355040b1324687474703a2f2f63657274732e676f64616464' - + '792e636f6d2f7265706f7369746f72792f313330310603550403132a476f' - + '204461646479205365637572652043657274696669636174652041757468' - + '6f72697479202d20473230820122300d06092a864886f70d010101050003' - + '82010f003082010a0282010100b9e0cb10d4af76bdd49362eb3064b88108' - + '6cc304d962178e2fff3e65cf8fce62e63c521cda16454b55ab786b638362' - + '90ce0f696c99c81a148b4ccc4533ea88dc9ea3af2bfe80619d7957c4cf2e' - + 'f43f303c5d47fc9a16bcc3379641518e114b54f828bed08cbef030381ef3' - + 'b026f86647636dde7126478f384753d1461db4e3dc00ea45acbdbc71d9aa' - + '6f00dbdbcd303a794f5f4c47f81def5bc2c49d603bb1b24391d8a4334eea' - + 'b3d6274fad258aa5c6f4d5d0a6ae7405645788b54455d42d2a3a3ef8b8bd' - + 'e9320a029464c4163a50f14aaee77933af0c20077fe8df0439c269026c63' - + '52fa77c11bc87487c8b993185054354b694ebc3bd3492e1fdcc1d252fb02' - + '03010001a382011a30820116300f0603551d130101ff040530030101ff30' - + '0e0603551d0f0101ff040403020106301d0603551d0e0416041440c2bd27' - + '8ecc348330a233d7fb6cb3f0b42c80ce301f0603551d230418301680143a' - + '9a8507106728b6eff6bd05416e20c194da0fde303406082b060105050701' - + '0104283026302406082b060105050730018618687474703a2f2f6f637370' - + '2e676f64616464792e636f6d2f30350603551d1f042e302c302aa028a026' - + '8624687474703a2f2f63726c2e676f64616464792e636f6d2f6764726f6f' - + '742d67322e63726c30460603551d20043f303d303b0604551d2000303330' - + '3106082b06010505070201162568747470733a2f2f63657274732e676f64' - + '616464792e636f6d2f7265706f7369746f72792f300d06092a864886f70d' - + '01010b05000382010100087e6c9310c838b896a9904bffa15f4f04ef6c3e' - + '9c8806c9508fa673f757311bbebce42fdbf8bad35be0b4e7e679620e0ca2' - + 'd76a637331b5f5a848a43b082da25d90d7b47c254f115630c4b6449d7b2c' - + '9de55ee6ef0c61aabfe42a1bee849eb8837dc143ce44a713700d911ff4c8' - + '13ad8360d9d872a873241eb5ac220eca17896258441bab892501000fcdc4' - + '1b62db51b4d30f512a9bf4bc73fc76ce36a4cdd9d82ceaae9bf52ab290d1' - + '4d75188a3f8a4190237d5b4bfea403589b46b2c3606083f87d5041cec2a1' - + '90c3bbef022fd21554ee4415d90aaea78a33edb12d763626dc04eb9ff761' - + '1f15dc876fee469628ada1267d0a09a72e04a38dbcf8bc0430010a810930' - + '82047d30820365a00302010202031be715300d06092a864886f70d01010b' - + '05003063310b30090603550406130255533121301f060355040a13185468' - + '6520476f2044616464792047726f75702c20496e632e3131302f06035504' - + '0b1328476f20446164647920436c61737320322043657274696669636174' - + '696f6e20417574686f72697479301e170d3134303130313037303030305a' - + '170d3331303533303037303030305a308183310b30090603550406130255' - + '533110300e060355040813074172697a6f6e61311330110603550407130a' - + '53636f74747364616c65311a3018060355040a1311476f44616464792e63' - + '6f6d2c20496e632e3131302f06035504031328476f20446164647920526f' - + '6f7420436572746966696361746520417574686f72697479202d20473230' - + '820122300d06092a864886f70d01010105000382010f003082010a028201' - + '0100bf716208f1fa5934f71bc918a3f7804958e9228313a6c52043013b84' - + 'f1e685499f27eaf6841b4ea0b4db7098c73201b1053e074eeef4fa4f2f59' - + '3022e7ab19566be28007fcf316758039517be5f935b6744ea98d8213e4b6' - + '3fa90383faa2be8a156a7fde0bc3b6191405caeac3a804943b467c320df3' - + '006622c88d696d368c1118b7d3b21c60b438fa028cced3dd4607de0a3eeb' - + '5d7cc87cfbb02b53a4926269512505611a44818c2ca9439623dfac3a819a' - + '0e29c51ca9e95d1eb69e9e300a39cef18880fb4b5dcc32ec856243253402' - + '56270191b43b702a3f6eb1e89c88017d9fd4f9db536d609dbf2ce758abb8' - + '5f46fccec41b033c09eb49315c6946b3e0470203010001a3820117308201' - + '13300f0603551d130101ff040530030101ff300e0603551d0f0101ff0404' - + '03020106301d0603551d0e041604143a9a8507106728b6eff6bd05416e20' - + 'c194da0fde301f0603551d23041830168014d2c4b0d291d44c1171b361cb' - + '3da1fedda86ad4e3303406082b0601050507010104283026302406082b06' - + '0105050730018618687474703a2f2f6f6373702e676f64616464792e636f' - + '6d2f30320603551d1f042b30293027a025a0238621687474703a2f2f6372' - + '6c2e676f64616464792e636f6d2f6764726f6f742e63726c30460603551d' - + '20043f303d303b0604551d20003033303106082b06010505070201162568' - + '747470733a2f2f63657274732e676f64616464792e636f6d2f7265706f73' - + '69746f72792f300d06092a864886f70d01010b05000382010100590b53bd' - + '928611a7247bed5b31cf1d1f6c70c5b86ebe4ebbf6be9750e1307fba285c' - + '6294c2e37e33f7fb427685db951c8c225875090c886567390a1609c5a038' - + '97a4c523933fb418a601064491e3a76927b45a257f3ab732cddd84ff2a38' - + '2933a4dd67b285fea188201c5089c8dc2af64203374ce688dfd5af24f2b1' - + 'c3dfccb5ece0995eb74954203c94180cc71c521849a46de1b3580bc9d8ec' - + 'd9ae1c328e28700de2fea6179e840fbd5770b35ae91fa08653bbef7cff69' - + '0be048c3b7930bc80a54c4ac5d1467376ccaa52f310837aa6e6f8cbc9be2' - + '575d2481af97979c84ad6cac374c66f361911120e4be309f7aa42909b0e1' - + '345f6477184051df8c30a6af0a840830820400308202e8a0030201020201' - + '00300d06092a864886f70d01010505003063310b30090603550406130255' - + '533121301f060355040a131854686520476f2044616464792047726f7570' - + '2c20496e632e3131302f060355040b1328476f20446164647920436c6173' - + '7320322043657274696669636174696f6e20417574686f72697479301e17' - + '0d3034303632393137303632305a170d3334303632393137303632305a30' - + '63310b30090603550406130255533121301f060355040a13185468652047' - + '6f2044616464792047726f75702c20496e632e3131302f060355040b1328' - + '476f20446164647920436c61737320322043657274696669636174696f6e' - + '20417574686f7269747930820120300d06092a864886f70d010101050003' - + '82010d00308201080282010100de9dd7ea571849a15bebd75f4886eabedd' - + 'ffe4ef671cf46568b35771a05e77bbed9b49e970803d561863086fdaf2cc' - + 'd03f7f0254225410d8b281d4c0753d4b7fc777c33e78ab1a03b5206b2f6a' - + '2bb1c5887ec4bb1eb0c1d845276faa3758f78726d7d82df6a917b71f7236' - + '4ea6173f659892db2a6e5da2fe88e00bde7fe58d15e1ebcb3ad5e212a213' - + '2dd88eaf5f123da0080508b65ca565380445991ea3606074c541a572621b' - + '62c51f6f5f1a42be025165a8ae23186afc7803a94d7f80c3faab5afca140' - + 'a4ca1916feb2c8ef5e730dee77bd9af67998bcb10767a2150ddda058c644' - + '7b0a3e62285fba41075358cf117e3874c5f8ffb569908f8474ea971baf02' - + '0103a381c03081bd301d0603551d0e04160414d2c4b0d291d44c1171b361' - + 'cb3da1fedda86ad4e330818d0603551d230481853081828014d2c4b0d291' - + 'd44c1171b361cb3da1fedda86ad4e3a167a4653063310b30090603550406' - + '130255533121301f060355040a131854686520476f204461646479204772' - + '6f75702c20496e632e3131302f060355040b1328476f2044616464792043' - + '6c61737320322043657274696669636174696f6e20417574686f72697479' - + '820100300c0603551d13040530030101ff300d06092a864886f70d010105' - + '05000382010100324bf3b2ca3e91fc12c6a1078c8e77a03306145c901e18' - + 'f708a63d0a19f98780116e69e4961730ff3491637238eecc1c01a31d9428' - + 'a431f67ac454d7f6e5315803a2ccce62db944573b5bf45c924b5d58202ad' - + '2379698db8b64dcecf4cca3323e81c88aa9d8b416e16c920e5899ecd3bda' - + '70f77e992620145425ab6e7385e69b219d0a6c820ea8f8c20cfa101e6c96' - + 'ef870dc40f618badee832b95f88e92847239eb20ea83ed83cd976e08bceb' - + '4e26b6732be4d3f64cfe2671e26111744aff571a870f75482ecf516917a0' - + '02126195d5d140b2104ceec4ac1043a6a59e0ad595629a0dcf8882c5320c' - + 'e42b9f45e60d9f289cb1b92a5a57ad370faf1d7fdbbd9f22a1010a047465' - + '7374122008c0c9e714121976a914176d7c5d60da6f8c82de86671a1fb776' - + '028538ca88ac18c6f5d89f0520cafcd89f052a395061796d656e74207265' - + '717565737420666f722042697450617920696e766f69636520434d577075' - + '46736a676d51325a4c6979476663463157323068747470733a2f2f746573' - + '742e6269747061792e636f6d2f692f434d57707546736a676d51325a4c69' - + '794766634631572a80021566366ab78842a514c056ca7ecb76481262cac7' - + '4cc4c4ccdc82c4980bc3300de67836d61d3e06dc8c90798a7774c21c7ad4' - + 'fe634b85faa8719d6402411bb720396ae03cbb4e14f06f7894a66b208b99' - + 'f727fab35d32f4f2148294d24bea1b3f240c159d0fd3ee4a32e5f926bf7c' - + '05eb7a3f75e01d9af81254cfbb61606467750ea7e0a1536728358e0898d0' - + '6f57235e4096d2caf647ae58dff645be80c9b3555fa96c81efa07d421977' - + 'd26214ad4f1ff642a93d0925656aeab454fa0b60fcbb6c1bc570eb6e43e7' - + '613392f37900748635ae381534bfaa558792bc46028b9efce391423a9c12' - + '01f76292614b30a14272e837f3813045b035f3d42f4f76f48acd', - 'hex'); - +SampleRequest.bitpay = new Buffer( + '' + + '0801120b783530392b7368613235361a89250aa40a3082052030820408a0' + + '03020102020727a49d05046d62300d06092a864886f70d01010b05003081' + + 'b4310b30090603550406130255533110300e060355040813074172697a6f' + + '6e61311330110603550407130a53636f74747364616c65311a3018060355' + + '040a1311476f44616464792e636f6d2c20496e632e312d302b060355040b' + + '1324687474703a2f2f63657274732e676f64616464792e636f6d2f726570' + + '6f7369746f72792f313330310603550403132a476f204461646479205365' + + '6375726520436572746966696361746520417574686f72697479202d2047' + + '32301e170d3134303432363132333532365a170d31363034323631323335' + + '32365a303a3121301f060355040b1318446f6d61696e20436f6e74726f6c' + + '2056616c6964617465643115301306035504030c0c2a2e6269747061792e' + + '636f6d30820122300d06092a864886f70d01010105000382010f00308201' + + '0a0282010100e2a5dd4aea959c1d0fb016e6e05bb7011e741cdc61918c61' + + 'f9625a2f682f485f0e862ea63db61cc9161753127504de800604df36b10f' + + '46cb17ab6cb99dba8aa45a36adfb901a2fc380c89e234bce18de6639b883' + + 'e9339801673efaee1f2df77eeb82f7c39c96a2f8ef4572b634c203d9be8f' + + 'd1e0036d32fb38b6b9b5ecd5a0684345c7e9ffc5d26bc6fd69aa6619f77b' + + 'adaa4bfb989478fb2f41aa92782e40b34ba9ac4549a4e6fda76b5fc4a581' + + '853bd0de5fb5a2c6dfdc12cdfadb54e9636a6d1223705924b8be566b81ac' + + '7921078cf590a146ae397a84908ef4fc83ff5715a44ab59e9258674d9011' + + '3bb607b8d81eb268e4c6ce849497c76521795b0873950203010001a38201' + + 'ae308201aa300f0603551d130101ff04053003010100301d0603551d2504' + + '16301406082b0601050507030106082b06010505070302300e0603551d0f' + + '0101ff0404030205a030360603551d1f042f302d302ba029a02786256874' + + '74703a2f2f63726c2e676f64616464792e636f6d2f676469673273312d34' + + '392e63726c30530603551d20044c304a3048060b6086480186fd6d010717' + + '013039303706082b06010505070201162b687474703a2f2f636572746966' + + '6963617465732e676f64616464792e636f6d2f7265706f7369746f72792f' + + '307606082b06010505070101046a3068302406082b060105050730018618' + + '687474703a2f2f6f6373702e676f64616464792e636f6d2f304006082b06' + + '0105050730028634687474703a2f2f6365727469666963617465732e676f' + + '64616464792e636f6d2f7265706f7369746f72792f67646967322e637274' + + '301f0603551d2304183016801440c2bd278ecc348330a233d7fb6cb3f0b4' + + '2c80ce30230603551d11041c301a820c2a2e6269747061792e636f6d820a' + + '6269747061792e636f6d301d0603551d0e0416041485454e3b4072e2f58e' + + '377438988b5229387e967a300d06092a864886f70d01010b050003820101' + + '002d0a7ef97f988905ebbbad4e9ffb690352535211d6792516119838b55f' + + '24ff9fa4e93b6187b8517cbb0477457d3378078ef66057abe41bcafeb142' + + 'ec52443a94b88114fa069f725c6198581d97af16352727f4f35e7f2110fa' + + 'a41a0511bcfdf8e3f4a3a310278c150b10f32a962c81e8f3d5374d9cb56d' + + '893027ff4fa4e3c3e6384c1f1557ceea6fca9cbc0c110748c08b82d8f0ed' + + '9a579637ee43a2d8fec3b5b04d1f3c8f1a3e2088da2274b6bc60948bbe74' + + '4a7f8b942b41f0ae9b4afaeefbb7e0f04a0587b52efb6ebfa2d970b9de56' + + 'a068575e4bf0cf824618dc17bbeaa2cdd25d65970a9f1a06fc9fffb466a1' + + '0c9568cd651795bc2c7996975027bdbaba0ad409308204d0308203b8a003' + + '020102020107300d06092a864886f70d01010b0500308183310b30090603' + + '550406130255533110300e060355040813074172697a6f6e613113301106' + + '03550407130a53636f74747364616c65311a3018060355040a1311476f44' + + '616464792e636f6d2c20496e632e3131302f06035504031328476f204461' + + '64647920526f6f7420436572746966696361746520417574686f72697479' + + '202d204732301e170d3131303530333037303030305a170d333130353033' + + '3037303030305a3081b4310b30090603550406130255533110300e060355' + + '040813074172697a6f6e61311330110603550407130a53636f7474736461' + + '6c65311a3018060355040a1311476f44616464792e636f6d2c20496e632e' + + '312d302b060355040b1324687474703a2f2f63657274732e676f64616464' + + '792e636f6d2f7265706f7369746f72792f313330310603550403132a476f' + + '204461646479205365637572652043657274696669636174652041757468' + + '6f72697479202d20473230820122300d06092a864886f70d010101050003' + + '82010f003082010a0282010100b9e0cb10d4af76bdd49362eb3064b88108' + + '6cc304d962178e2fff3e65cf8fce62e63c521cda16454b55ab786b638362' + + '90ce0f696c99c81a148b4ccc4533ea88dc9ea3af2bfe80619d7957c4cf2e' + + 'f43f303c5d47fc9a16bcc3379641518e114b54f828bed08cbef030381ef3' + + 'b026f86647636dde7126478f384753d1461db4e3dc00ea45acbdbc71d9aa' + + '6f00dbdbcd303a794f5f4c47f81def5bc2c49d603bb1b24391d8a4334eea' + + 'b3d6274fad258aa5c6f4d5d0a6ae7405645788b54455d42d2a3a3ef8b8bd' + + 'e9320a029464c4163a50f14aaee77933af0c20077fe8df0439c269026c63' + + '52fa77c11bc87487c8b993185054354b694ebc3bd3492e1fdcc1d252fb02' + + '03010001a382011a30820116300f0603551d130101ff040530030101ff30' + + '0e0603551d0f0101ff040403020106301d0603551d0e0416041440c2bd27' + + '8ecc348330a233d7fb6cb3f0b42c80ce301f0603551d230418301680143a' + + '9a8507106728b6eff6bd05416e20c194da0fde303406082b060105050701' + + '0104283026302406082b060105050730018618687474703a2f2f6f637370' + + '2e676f64616464792e636f6d2f30350603551d1f042e302c302aa028a026' + + '8624687474703a2f2f63726c2e676f64616464792e636f6d2f6764726f6f' + + '742d67322e63726c30460603551d20043f303d303b0604551d2000303330' + + '3106082b06010505070201162568747470733a2f2f63657274732e676f64' + + '616464792e636f6d2f7265706f7369746f72792f300d06092a864886f70d' + + '01010b05000382010100087e6c9310c838b896a9904bffa15f4f04ef6c3e' + + '9c8806c9508fa673f757311bbebce42fdbf8bad35be0b4e7e679620e0ca2' + + 'd76a637331b5f5a848a43b082da25d90d7b47c254f115630c4b6449d7b2c' + + '9de55ee6ef0c61aabfe42a1bee849eb8837dc143ce44a713700d911ff4c8' + + '13ad8360d9d872a873241eb5ac220eca17896258441bab892501000fcdc4' + + '1b62db51b4d30f512a9bf4bc73fc76ce36a4cdd9d82ceaae9bf52ab290d1' + + '4d75188a3f8a4190237d5b4bfea403589b46b2c3606083f87d5041cec2a1' + + '90c3bbef022fd21554ee4415d90aaea78a33edb12d763626dc04eb9ff761' + + '1f15dc876fee469628ada1267d0a09a72e04a38dbcf8bc0430010a810930' + + '82047d30820365a00302010202031be715300d06092a864886f70d01010b' + + '05003063310b30090603550406130255533121301f060355040a13185468' + + '6520476f2044616464792047726f75702c20496e632e3131302f06035504' + + '0b1328476f20446164647920436c61737320322043657274696669636174' + + '696f6e20417574686f72697479301e170d3134303130313037303030305a' + + '170d3331303533303037303030305a308183310b30090603550406130255' + + '533110300e060355040813074172697a6f6e61311330110603550407130a' + + '53636f74747364616c65311a3018060355040a1311476f44616464792e63' + + '6f6d2c20496e632e3131302f06035504031328476f20446164647920526f' + + '6f7420436572746966696361746520417574686f72697479202d20473230' + + '820122300d06092a864886f70d01010105000382010f003082010a028201' + + '0100bf716208f1fa5934f71bc918a3f7804958e9228313a6c52043013b84' + + 'f1e685499f27eaf6841b4ea0b4db7098c73201b1053e074eeef4fa4f2f59' + + '3022e7ab19566be28007fcf316758039517be5f935b6744ea98d8213e4b6' + + '3fa90383faa2be8a156a7fde0bc3b6191405caeac3a804943b467c320df3' + + '006622c88d696d368c1118b7d3b21c60b438fa028cced3dd4607de0a3eeb' + + '5d7cc87cfbb02b53a4926269512505611a44818c2ca9439623dfac3a819a' + + '0e29c51ca9e95d1eb69e9e300a39cef18880fb4b5dcc32ec856243253402' + + '56270191b43b702a3f6eb1e89c88017d9fd4f9db536d609dbf2ce758abb8' + + '5f46fccec41b033c09eb49315c6946b3e0470203010001a3820117308201' + + '13300f0603551d130101ff040530030101ff300e0603551d0f0101ff0404' + + '03020106301d0603551d0e041604143a9a8507106728b6eff6bd05416e20' + + 'c194da0fde301f0603551d23041830168014d2c4b0d291d44c1171b361cb' + + '3da1fedda86ad4e3303406082b0601050507010104283026302406082b06' + + '0105050730018618687474703a2f2f6f6373702e676f64616464792e636f' + + '6d2f30320603551d1f042b30293027a025a0238621687474703a2f2f6372' + + '6c2e676f64616464792e636f6d2f6764726f6f742e63726c30460603551d' + + '20043f303d303b0604551d20003033303106082b06010505070201162568' + + '747470733a2f2f63657274732e676f64616464792e636f6d2f7265706f73' + + '69746f72792f300d06092a864886f70d01010b05000382010100590b53bd' + + '928611a7247bed5b31cf1d1f6c70c5b86ebe4ebbf6be9750e1307fba285c' + + '6294c2e37e33f7fb427685db951c8c225875090c886567390a1609c5a038' + + '97a4c523933fb418a601064491e3a76927b45a257f3ab732cddd84ff2a38' + + '2933a4dd67b285fea188201c5089c8dc2af64203374ce688dfd5af24f2b1' + + 'c3dfccb5ece0995eb74954203c94180cc71c521849a46de1b3580bc9d8ec' + + 'd9ae1c328e28700de2fea6179e840fbd5770b35ae91fa08653bbef7cff69' + + '0be048c3b7930bc80a54c4ac5d1467376ccaa52f310837aa6e6f8cbc9be2' + + '575d2481af97979c84ad6cac374c66f361911120e4be309f7aa42909b0e1' + + '345f6477184051df8c30a6af0a840830820400308202e8a0030201020201' + + '00300d06092a864886f70d01010505003063310b30090603550406130255' + + '533121301f060355040a131854686520476f2044616464792047726f7570' + + '2c20496e632e3131302f060355040b1328476f20446164647920436c6173' + + '7320322043657274696669636174696f6e20417574686f72697479301e17' + + '0d3034303632393137303632305a170d3334303632393137303632305a30' + + '63310b30090603550406130255533121301f060355040a13185468652047' + + '6f2044616464792047726f75702c20496e632e3131302f060355040b1328' + + '476f20446164647920436c61737320322043657274696669636174696f6e' + + '20417574686f7269747930820120300d06092a864886f70d010101050003' + + '82010d00308201080282010100de9dd7ea571849a15bebd75f4886eabedd' + + 'ffe4ef671cf46568b35771a05e77bbed9b49e970803d561863086fdaf2cc' + + 'd03f7f0254225410d8b281d4c0753d4b7fc777c33e78ab1a03b5206b2f6a' + + '2bb1c5887ec4bb1eb0c1d845276faa3758f78726d7d82df6a917b71f7236' + + '4ea6173f659892db2a6e5da2fe88e00bde7fe58d15e1ebcb3ad5e212a213' + + '2dd88eaf5f123da0080508b65ca565380445991ea3606074c541a572621b' + + '62c51f6f5f1a42be025165a8ae23186afc7803a94d7f80c3faab5afca140' + + 'a4ca1916feb2c8ef5e730dee77bd9af67998bcb10767a2150ddda058c644' + + '7b0a3e62285fba41075358cf117e3874c5f8ffb569908f8474ea971baf02' + + '0103a381c03081bd301d0603551d0e04160414d2c4b0d291d44c1171b361' + + 'cb3da1fedda86ad4e330818d0603551d230481853081828014d2c4b0d291' + + 'd44c1171b361cb3da1fedda86ad4e3a167a4653063310b30090603550406' + + '130255533121301f060355040a131854686520476f204461646479204772' + + '6f75702c20496e632e3131302f060355040b1328476f2044616464792043' + + '6c61737320322043657274696669636174696f6e20417574686f72697479' + + '820100300c0603551d13040530030101ff300d06092a864886f70d010105' + + '05000382010100324bf3b2ca3e91fc12c6a1078c8e77a03306145c901e18' + + 'f708a63d0a19f98780116e69e4961730ff3491637238eecc1c01a31d9428' + + 'a431f67ac454d7f6e5315803a2ccce62db944573b5bf45c924b5d58202ad' + + '2379698db8b64dcecf4cca3323e81c88aa9d8b416e16c920e5899ecd3bda' + + '70f77e992620145425ab6e7385e69b219d0a6c820ea8f8c20cfa101e6c96' + + 'ef870dc40f618badee832b95f88e92847239eb20ea83ed83cd976e08bceb' + + '4e26b6732be4d3f64cfe2671e26111744aff571a870f75482ecf516917a0' + + '02126195d5d140b2104ceec4ac1043a6a59e0ad595629a0dcf8882c5320c' + + 'e42b9f45e60d9f289cb1b92a5a57ad370faf1d7fdbbd9f22a1010a047465' + + '7374122008c0c9e714121976a914176d7c5d60da6f8c82de86671a1fb776' + + '028538ca88ac18c6f5d89f0520cafcd89f052a395061796d656e74207265' + + '717565737420666f722042697450617920696e766f69636520434d577075' + + '46736a676d51325a4c6979476663463157323068747470733a2f2f746573' + + '742e6269747061792e636f6d2f692f434d57707546736a676d51325a4c69' + + '794766634631572a80021566366ab78842a514c056ca7ecb76481262cac7' + + '4cc4c4ccdc82c4980bc3300de67836d61d3e06dc8c90798a7774c21c7ad4' + + 'fe634b85faa8719d6402411bb720396ae03cbb4e14f06f7894a66b208b99' + + 'f727fab35d32f4f2148294d24bea1b3f240c159d0fd3ee4a32e5f926bf7c' + + '05eb7a3f75e01d9af81254cfbb61606467750ea7e0a1536728358e0898d0' + + '6f57235e4096d2caf647ae58dff645be80c9b3555fa96c81efa07d421977' + + 'd26214ad4f1ff642a93d0925656aeab454fa0b60fcbb6c1bc570eb6e43e7' + + '613392f37900748635ae381534bfaa558792bc46028b9efce391423a9c12' + + '01f76292614b30a14272e837f3813045b035f3d42f4f76f48acd', + 'hex', +); // Livenet, with root cert missing -SampleRequest.bitpay2 = new Buffer('' -+ '0801120b783530392b7368613235361a88210aaa0e308207263082060ea0' -+ '03020102020900ba55847ce9a10f59300d06092a864886f70d01010b0500' -+ '3081b4310b30090603550406130255533110300e06035504081307417269' -+ '7a6f6e61311330110603550407130a53636f74747364616c65311a301806' -+ '0355040a1311476f44616464792e636f6d2c20496e632e312d302b060355' -+ '040b1324687474703a2f2f63657274732e676f64616464792e636f6d2f72' -+ '65706f7369746f72792f313330310603550403132a476f20446164647920' -+ '53656375726520436572746966696361746520417574686f72697479202d' -+ '204732301e170d3135303432303231323134365a170d3137303432353139' -+ '313130305a3081be31133011060b2b0601040182373c0201031302555331' -+ '193017060b2b0601040182373c020102130844656c6177617265311d301b' -+ '060355040f131450726976617465204f7267616e697a6174696f6e311030' -+ '0e0603550405130735313633393636310b30090603550406130255533110' -+ '300e0603550408130747656f726769613110300e0603550407130741746c' -+ '616e746131153013060355040a130c4269745061792c20496e632e311330' -+ '110603550403130a6269747061792e636f6d30820122300d06092a864886' -+ 'f70d01010105000382010f003082010a0282010100e42025369a803c1b44' -+ '234a279d123b610ec1178452fc7c57f2576492e1123166bed5eec11d12a8' -+ 'b824904f77aa6166ce6e111538204121069b5ecff81fd1ab27b1b9475c49' -+ 'd7680ef5f406f57a1871b77392a7b5c4370f504ba175617f78fe24c9ed76' -+ '154b46aa677cf6463a202909711b34ceecbe0ee7b9766cfd7018886b67e5' -+ '18f1ac39a3715152d62e59547f34d440ed3dfa01a92a42ed0b221c093144' -+ 'ed63f86c2300b8cf192b75929732af63c41526e4fd69735f0062c61c2dbc' -+ 'b56f6439ff9bbe62507da52752c1d99f24afbb3a6b5c98989d2196fb6bd9' -+ 'cc83a5ab21f060e955e7f45a01c9efe782f15cd48ab824d6272db2b71c89' -+ '88d02071e805df0203010001a382032d30820329300c0603551d130101ff' -+ '04023000301d0603551d250416301406082b0601050507030106082b0601' -+ '0505070302300e0603551d0f0101ff0404030205a030350603551d1f042e' -+ '302c302aa028a0268624687474703a2f2f63726c2e676f64616464792e63' -+ '6f6d2f676469673273332d312e63726c30530603551d20044c304a304806' -+ '0b6086480186fd6d010717033039303706082b06010505070201162b6874' -+ '74703a2f2f6365727469666963617465732e676f64616464792e636f6d2f' -+ '7265706f7369746f72792f307606082b06010505070101046a3068302406' -+ '082b060105050730018618687474703a2f2f6f6373702e676f6461646479' -+ '2e636f6d2f304006082b060105050730028634687474703a2f2f63657274' -+ '69666963617465732e676f64616464792e636f6d2f7265706f7369746f72' -+ '792f67646967322e637274301f0603551d2304183016801440c2bd278ecc' -+ '348330a233d7fb6cb3f0b42c80ce30250603551d11041e301c820a626974' -+ '7061792e636f6d820e7777772e6269747061792e636f6d301d0603551d0e' -+ '04160414a5698a70daa1405dbcdd1a02e95db8a51aaadd7f3082017d060a' -+ '2b06010401d6790204020482016d0482016901670076005614069a2fd7c2' -+ 'ecd3f5e1bd44b23ec74676b9bc99115cc0ef949855d689d0dd0000014cd8' -+ 'b6d73a000004030047304502210095e5768670ea27ed35075e484b7c42cd' -+ '20176c7263b4e879deb418639144079d02204911ae1cf0fcda5a2b6b3cec' -+ '528ccd689e7371a34c99460c2ca063b44ba6fbca00750068f698f81f6482' -+ 'be3a8ceeb9281d4cfc71515d6793d444d10a67acbb4f4ffbc40000014cd8' -+ 'b6d93e0000040300463044022030c89215d7081b372a1b033eb77ff5abbe' -+ '9c6822b38c9a0f5e4b166c7532fabf02200a481b330414d0076aa0d925dc' -+ '84096b8cb7585fc0b1ff28c744cfa85e17ab8e007600a4b90990b4185814' -+ '87bb13a2cc67700a3c359804f91bdfb8e377cd0ec80ddc100000014cd8b6' -+ 'dc34000004030047304502201f085d25b292b34185a182e314a3c64c9b51' -+ '62526c90cfc3ff7136b137bc98ee022100b28a7fbaa53c2fff07bdf23300' -+ '551e0b52ff1d823bb89df9eeb9079327adfe2c300d06092a864886f70d01' -+ '010b0500038201010013eeaf33325800bb0f252a091b1a9cdf2e10de3abf' -+ 'b9f566b94a60e63401598f68c4086cf170881f1b856e51dc45edce992f58' -+ '9a7c4acbfb7c28a10c28c1ce4d1425c5b795b764367f0446dde5bb5710e5' -+ 'a1994a02f0b02334458e4950a876e48363aee4a32d1904d6d9c6af2906f4' -+ 'e4e03122e35bf943cf17b0e05a8ebaa5154a86f40676e779bb1dcd2672d7' -+ '5887e1bcb51186596d749bc6c1ecfedcf60b24eb503ac9460dc3682fe74e' -+ '7acf16e9ab0014f6719322de534e14e90e7638e854546087c6a33d7743f5' -+ '8ee3b589dbd8fa5800af9b0ecdef0c041a2bf2126b908e3bf84881c1a323' -+ '929bca34f0830373a8b28f62b2133880ff6f20ffb19c38a7280ad4093082' -+ '04d0308203b8a003020102020107300d06092a864886f70d01010b050030' -+ '8183310b30090603550406130255533110300e060355040813074172697a' -+ '6f6e61311330110603550407130a53636f74747364616c65311a30180603' -+ '55040a1311476f44616464792e636f6d2c20496e632e3131302f06035504' -+ '031328476f20446164647920526f6f742043657274696669636174652041' -+ '7574686f72697479202d204732301e170d3131303530333037303030305a' -+ '170d3331303530333037303030305a3081b4310b30090603550406130255' -+ '533110300e060355040813074172697a6f6e61311330110603550407130a' -+ '53636f74747364616c65311a3018060355040a1311476f44616464792e63' -+ '6f6d2c20496e632e312d302b060355040b1324687474703a2f2f63657274' -+ '732e676f64616464792e636f6d2f7265706f7369746f72792f3133303106' -+ '03550403132a476f20446164647920536563757265204365727469666963' -+ '61746520417574686f72697479202d20473230820122300d06092a864886' -+ 'f70d01010105000382010f003082010a0282010100b9e0cb10d4af76bdd4' -+ '9362eb3064b881086cc304d962178e2fff3e65cf8fce62e63c521cda1645' -+ '4b55ab786b63836290ce0f696c99c81a148b4ccc4533ea88dc9ea3af2bfe' -+ '80619d7957c4cf2ef43f303c5d47fc9a16bcc3379641518e114b54f828be' -+ 'd08cbef030381ef3b026f86647636dde7126478f384753d1461db4e3dc00' -+ 'ea45acbdbc71d9aa6f00dbdbcd303a794f5f4c47f81def5bc2c49d603bb1' -+ 'b24391d8a4334eeab3d6274fad258aa5c6f4d5d0a6ae7405645788b54455' -+ 'd42d2a3a3ef8b8bde9320a029464c4163a50f14aaee77933af0c20077fe8' -+ 'df0439c269026c6352fa77c11bc87487c8b993185054354b694ebc3bd349' -+ '2e1fdcc1d252fb0203010001a382011a30820116300f0603551d130101ff' -+ '040530030101ff300e0603551d0f0101ff040403020106301d0603551d0e' -+ '0416041440c2bd278ecc348330a233d7fb6cb3f0b42c80ce301f0603551d' -+ '230418301680143a9a8507106728b6eff6bd05416e20c194da0fde303406' -+ '082b0601050507010104283026302406082b060105050730018618687474' -+ '703a2f2f6f6373702e676f64616464792e636f6d2f30350603551d1f042e' -+ '302c302aa028a0268624687474703a2f2f63726c2e676f64616464792e63' -+ '6f6d2f6764726f6f742d67322e63726c30460603551d20043f303d303b06' -+ '04551d20003033303106082b06010505070201162568747470733a2f2f63' -+ '657274732e676f64616464792e636f6d2f7265706f7369746f72792f300d' -+ '06092a864886f70d01010b05000382010100087e6c9310c838b896a9904b' -+ 'ffa15f4f04ef6c3e9c8806c9508fa673f757311bbebce42fdbf8bad35be0' -+ 'b4e7e679620e0ca2d76a637331b5f5a848a43b082da25d90d7b47c254f11' -+ '5630c4b6449d7b2c9de55ee6ef0c61aabfe42a1bee849eb8837dc143ce44' -+ 'a713700d911ff4c813ad8360d9d872a873241eb5ac220eca17896258441b' -+ 'ab892501000fcdc41b62db51b4d30f512a9bf4bc73fc76ce36a4cdd9d82c' -+ 'eaae9bf52ab290d14d75188a3f8a4190237d5b4bfea403589b46b2c36060' -+ '83f87d5041cec2a190c3bbef022fd21554ee4415d90aaea78a33edb12d76' -+ '3626dc04eb9ff7611f15dc876fee469628ada1267d0a09a72e04a38dbcf8' -+ 'bc0430010a81093082047d30820365a00302010202031be715300d06092a' -+ '864886f70d01010b05003063310b30090603550406130255533121301f06' -+ '0355040a131854686520476f2044616464792047726f75702c20496e632e' -+ '3131302f060355040b1328476f20446164647920436c6173732032204365' -+ '7274696669636174696f6e20417574686f72697479301e170d3134303130' -+ '313037303030305a170d3331303533303037303030305a308183310b3009' -+ '0603550406130255533110300e060355040813074172697a6f6e61311330' -+ '110603550407130a53636f74747364616c65311a3018060355040a131147' -+ '6f44616464792e636f6d2c20496e632e3131302f06035504031328476f20' -+ '446164647920526f6f7420436572746966696361746520417574686f7269' -+ '7479202d20473230820122300d06092a864886f70d01010105000382010f' -+ '003082010a0282010100bf716208f1fa5934f71bc918a3f7804958e92283' -+ '13a6c52043013b84f1e685499f27eaf6841b4ea0b4db7098c73201b1053e' -+ '074eeef4fa4f2f593022e7ab19566be28007fcf316758039517be5f935b6' -+ '744ea98d8213e4b63fa90383faa2be8a156a7fde0bc3b6191405caeac3a8' -+ '04943b467c320df3006622c88d696d368c1118b7d3b21c60b438fa028cce' -+ 'd3dd4607de0a3eeb5d7cc87cfbb02b53a4926269512505611a44818c2ca9' -+ '439623dfac3a819a0e29c51ca9e95d1eb69e9e300a39cef18880fb4b5dcc' -+ '32ec85624325340256270191b43b702a3f6eb1e89c88017d9fd4f9db536d' -+ '609dbf2ce758abb85f46fccec41b033c09eb49315c6946b3e04702030100' -+ '01a382011730820113300f0603551d130101ff040530030101ff300e0603' -+ '551d0f0101ff040403020106301d0603551d0e041604143a9a8507106728' -+ 'b6eff6bd05416e20c194da0fde301f0603551d23041830168014d2c4b0d2' -+ '91d44c1171b361cb3da1fedda86ad4e3303406082b060105050701010428' -+ '3026302406082b060105050730018618687474703a2f2f6f6373702e676f' -+ '64616464792e636f6d2f30320603551d1f042b30293027a025a023862168' -+ '7474703a2f2f63726c2e676f64616464792e636f6d2f6764726f6f742e63' -+ '726c30460603551d20043f303d303b0604551d20003033303106082b0601' -+ '0505070201162568747470733a2f2f63657274732e676f64616464792e63' -+ '6f6d2f7265706f7369746f72792f300d06092a864886f70d01010b050003' -+ '82010100590b53bd928611a7247bed5b31cf1d1f6c70c5b86ebe4ebbf6be' -+ '9750e1307fba285c6294c2e37e33f7fb427685db951c8c225875090c8865' -+ '67390a1609c5a03897a4c523933fb418a601064491e3a76927b45a257f3a' -+ 'b732cddd84ff2a382933a4dd67b285fea188201c5089c8dc2af64203374c' -+ 'e688dfd5af24f2b1c3dfccb5ece0995eb74954203c94180cc71c521849a4' -+ '6de1b3580bc9d8ecd9ae1c328e28700de2fea6179e840fbd5770b35ae91f' -+ 'a08653bbef7cff690be048c3b7930bc80a54c4ac5d1467376ccaa52f3108' -+ '37aa6e6f8cbc9be2575d2481af97979c84ad6cac374c66f361911120e4be' -+ '309f7aa42909b0e1345f6477184051df8c30a6af2289020a046d61696e12' -+ '1f08c0843d121976a914e4ea045fc0f08208d452187ad401ab2a874d0b6d' -+ '88ac1896d6e5af05209adde5af052a595061796d656e7420726571756573' -+ '7420666f722042697450617920696e766f69636520504151744e7858374b' -+ '4c3842744a426e66587954614820666f72206d65726368616e7420426974' -+ '4769766520466f756e646174696f6e322b68747470733a2f2f6269747061' -+ '792e636f6d2f692f504151744e7858374b4c3842744a426e665879546148' -+ '3a4c7b22696e766f6963654964223a22504151744e7858374b4c3842744a' -+ '426e665879546148222c226d65726368616e744964223a2254785a355279' -+ '43686d5a773269734b6a4a5747684263227d2a8002dca72518e1951edeb8' -+ '32ad680b5b99f29e0d5d9b9bf4c6d3a6e327436a8c9e44328b9c4738703b' -+ '3407033f13cfc90ac7201dbbb612ee00f81a94169b4f4994b310c1779488' -+ '77e440d1347a64aa55c351fd08a3ce9af7598b8d103b24a0928a23cba006' -+ '7d35aa86de6fc664c017233cd22db0ec204cacb00c87dd58abfdeae7c2fc' -+ '61e5666a41c1be2f633d925f97a088b1fabc0b6634fff7f0034437a8d4cf' -+ '52d94d739dc67327a1b3757358f2799bda1e0af4e897a8fae0ec77f2baa8' -+ 'fb6a9b315bf1a19e09dc806d3269e5544c98da2a3bfd1fcc70389539b1c9' -+ 'ad0c16cd34f62cd1533e3b491115814746c47914bd2c45cf947ac239b1e1' -+ '251907cfd99036', -'hex'); - - -SampleRequest.coinbase = new Buffer('' -+ "120b783530392b7368613235361abe150afe0b308205fa308204e2a00302" -+ "01020210090b35ca5c5bf1b98b3d8f9f4a7755d6300d06092a864886f70d" -+ "01010b05003075310b300906035504061302555331153013060355040a13" -+ "0c446967694365727420496e6331193017060355040b13107777772e6469" -+ "6769636572742e636f6d313430320603550403132b446967694365727420" -+ "5348413220457874656e6465642056616c69646174696f6e205365727665" -+ "72204341301e170d3134303530393030303030305a170d31363035313331" -+ "32303030305a30820105311d301b060355040f0c1450726976617465204f" -+ "7267616e697a6174696f6e31133011060b2b0601040182373c0201031302" -+ "555331193017060b2b0601040182373c020102130844656c617761726531" -+ "10300e0603550405130735313534333137310f300d06035504090c062332" -+ "33303038311730150603550409130e353438204d61726b65742053742e31" -+ "0e300c060355041113053934313034310b30090603550406130255533113" -+ "30110603550408130a43616c69666f726e6961311630140603550407130d" -+ "53616e204672616e636973636f31173015060355040a130e436f696e6261" -+ "73652c20496e632e311530130603550403130c636f696e626173652e636f" -+ "6d30820122300d06092a864886f70d01010105000382010f003082010a02" -+ "82010100b45e3ff380667aa14d5a12fc2fc983fc6618b55499933c3bde15" -+ "c01d838846b4caf9848e7c40e5fa7c67ef9b5b1efe26ee5571c5fa2eff75" -+ "9052454701ad8931557d697b139e5d19abb3e439675f31db7f2ef1a5d97d" -+ "b07c1f6966266380eb4fcfa8e1471a6ecc2fbebf3e67b3eaa84d0fbe063e" -+ "60380dcdb7a20203d29a94059ef7f20d472cc25783ab2a1db6a394ecc07b" -+ "4024974100bcfd470f59ef3b572365213209609fad229994b4923c1df3a1" -+ "8c41e3e7bc1f192ba6e7e5c32ae155107e21903eff7bce9fc594b49d9f6a" -+ "e7901fa191fcbae8a2cf09c3bfc24377d717b6010080c5681a7dbc6e1d52" -+ "987b7ebbe95e7af4202da436e67a88472aacedc90203010001a38201f230" -+ "8201ee301f0603551d230418301680143dd350a5d6a0adeef34a600a65d3" -+ "21d4f8f8d60f301d0603551d0e041604146d33b9743a61b7499423d1a89d" -+ "085d0148680bba30290603551d1104223020820c636f696e626173652e63" -+ "6f6d82107777772e636f696e626173652e636f6d300e0603551d0f0101ff" -+ "0404030205a0301d0603551d250416301406082b0601050507030106082b" -+ "0601050507030230750603551d1f046e306c3034a032a030862e68747470" -+ "3a2f2f63726c332e64696769636572742e636f6d2f736861322d65762d73" -+ "65727665722d67312e63726c3034a032a030862e687474703a2f2f63726c" -+ "342e64696769636572742e636f6d2f736861322d65762d7365727665722d" -+ "67312e63726c30420603551d20043b3039303706096086480186fd6c0201" -+ "302a302806082b06010505070201161c68747470733a2f2f7777772e6469" -+ "6769636572742e636f6d2f43505330818806082b06010505070101047c30" -+ "7a302406082b060105050730018618687474703a2f2f6f6373702e646967" -+ "69636572742e636f6d305206082b060105050730028646687474703a2f2f" -+ "636163657274732e64696769636572742e636f6d2f446967694365727453" -+ "484132457874656e64656456616c69646174696f6e53657276657243412e" -+ "637274300c0603551d130101ff04023000300d06092a864886f70d01010b" -+ "05000382010100aadfcf94050ed938e3114a640af3d9b04276da00f5215d" -+ "7148f9f16d4cac0c77bd5349ec2f47299d03c900f70146752da72829290a" -+ "c50a77992f01537ab2689392ce0bfeb7efa49f4c4fe4e1e43ca1fcfb1626" -+ "ce554da4f6e7fa34a597e401f215c43afd0ba777ad587eb0afacd71f7a6a" -+ "f7752814f7ab4c202ed76d33defd1289d541803fed01ac80a3cacfdaae29" -+ "279e5de14d460475f4baf27eab693379d39120e7477bf3ec719664c7b6cb" -+ "5e557556e5bbddd9c9d1ebc9f835e9da5b3dbb72fe8d94ac05eab3c47998" -+ "7520ade3a1d275e1e2fe725698d2f7cb1390a9d40ea6cbf21a73bddccd1a" -+ "d61aa249ce8e2885a3730b7d53bd075f55099d2960f3cc0aba09308204b6" -+ "3082039ea00302010202100c79a944b08c11952092615fe26b1d83300d06" -+ "092a864886f70d01010b0500306c310b3009060355040613025553311530" -+ "13060355040a130c446967694365727420496e6331193017060355040b13" -+ "107777772e64696769636572742e636f6d312b3029060355040313224469" -+ "6769436572742048696768204173737572616e636520455620526f6f7420" -+ "4341301e170d3133313032323132303030305a170d323831303232313230" -+ "3030305a3075310b300906035504061302555331153013060355040a130c" -+ "446967694365727420496e6331193017060355040b13107777772e646967" -+ "69636572742e636f6d313430320603550403132b44696769436572742053" -+ "48413220457874656e6465642056616c69646174696f6e20536572766572" -+ "20434130820122300d06092a864886f70d01010105000382010f00308201" -+ "0a0282010100d753a40451f899a616484b6727aa9349d039ed0cb0b00087" -+ "f1672886858c8e63dabcb14038e2d3f5eca50518b83d3ec5991732ec188c" -+ "faf10ca6642185cb071034b052882b1f689bd2b18f12b0b3d2e7881f1fef" -+ "387754535f80793f2e1aaaa81e4b2b0dabb763b935b77d14bc594bdf514a" -+ "d2a1e20ce29082876aaeead764d69855e8fdaf1a506c54bc11f2fd4af29d" -+ "bb7f0ef4d5be8e16891255d8c07134eef6dc2decc48725868dd821e4b04d" -+ "0c89dc392617ddf6d79485d80421709d6f6fff5cba19e145cb5657287e1c" -+ "0d4157aab7b827bbb1e4fa2aef2123751aad2d9b86358c9c77b573add894" -+ "2de4f30c9deec14e627e17c0719e2cdef1f9102819330203010001a38201" -+ "493082014530120603551d130101ff040830060101ff020100300e060355" -+ "1d0f0101ff040403020186301d0603551d250416301406082b0601050507" -+ "030106082b06010505070302303406082b06010505070101042830263024" -+ "06082b060105050730018618687474703a2f2f6f6373702e646967696365" -+ "72742e636f6d304b0603551d1f044430423040a03ea03c863a687474703a" -+ "2f2f63726c342e64696769636572742e636f6d2f44696769436572744869" -+ "67684173737572616e63654556526f6f7443412e63726c303d0603551d20" -+ "0436303430320604551d2000302a302806082b06010505070201161c6874" -+ "7470733a2f2f7777772e64696769636572742e636f6d2f435053301d0603" -+ "551d0e041604143dd350a5d6a0adeef34a600a65d321d4f8f8d60f301f06" -+ "03551d23041830168014b13ec36903f8bf4701d498261a0802ef63642bc3" -+ "300d06092a864886f70d01010b050003820101009db6d09086e18602edc5" -+ "a0f0341c74c18d76cc860aa8f04a8a42d63fc8a94dad7c08ade6b650b8a2" -+ "1a4d8807b12921dce7dac63c21e0e3114970ac7a1d01a4ca113a57ab7d57" -+ "2a4074fdd31d851850df574775a17d55202e473750728c7f821bd2628f2d" -+ "035adac3c8a1ce2c52a20063eb73ba71c84927239764859e380ead63683c" -+ "ba52815879a32c0cdfde6deb31f2baa07c6cf12cd4e1bd77843703ce32b5" -+ "c89a811a4a924e3b469a85fe83a2f99e8ca3cc0d5eb33dcf04788f14147b" -+ "329cc700a65cc4b5a1558d5a5668a42270aa3c8171d99da8453bf4e5f6a2" -+ "51ddc77b62e86f0c74ebb8daf8bf870d795091909b183b915927f1352813" -+ "ab267ed5f77a22b801121f08d8e51a121976a914f5fa7bb3c2245e646925" -+ "4c074c062af292ce008c88ac189295e7af0520f49be7af052a315061796d" -+ "656e74207265717565737420666f7220436f696e62617365206f72646572" -+ "20636f64653a205738375858335753323468747470733a2f2f7777772e63" -+ "6f696e626173652e636f6d2f72702f353566396361373033643564383030" -+ "3038633030303166343a2062623739623666323331306533323162643362" -+ "316439323965646265623335382a8002b45d9b5d48d566d577ec4973b4b5" -+ "7a4930f173be6545d9fc367f9b55f90a669504085db971107a09c25d1e30" -+ "dcaf54ce86f177685751feebd5c66c40d7d9daad08129fe10450518d48e4" -+ "9ae4e03a8c4939010f9f222de60b9e5df210e066115cbc2ad92f51fcdc35" -+ "eaa3ee2430687ff46053e460b6f93deede2ee09a8841eec11b6f5d1bbcf2" -+ "6708e5c12d427959569d9af629f8940736ac3941f78eafb2c2e400dfcc76" -+ "e729d13c4a9d0ec834515cf7287188589e5e0e505a7a7daab1fa8ac4f674" -+ "5a0eae2daa61d73a7e3fc56ca94457e2aa164a959b05bb91b797828cb7c4" -+ "d8b05395840a40ef51a0a0f93d13dce15e5f5f9ede08b3510701a1cac6a9" -+ "9c06" - ,'hex'); +SampleRequest.bitpay2 = new Buffer( + '' + + '0801120b783530392b7368613235361a88210aaa0e308207263082060ea0' + + '03020102020900ba55847ce9a10f59300d06092a864886f70d01010b0500' + + '3081b4310b30090603550406130255533110300e06035504081307417269' + + '7a6f6e61311330110603550407130a53636f74747364616c65311a301806' + + '0355040a1311476f44616464792e636f6d2c20496e632e312d302b060355' + + '040b1324687474703a2f2f63657274732e676f64616464792e636f6d2f72' + + '65706f7369746f72792f313330310603550403132a476f20446164647920' + + '53656375726520436572746966696361746520417574686f72697479202d' + + '204732301e170d3135303432303231323134365a170d3137303432353139' + + '313130305a3081be31133011060b2b0601040182373c0201031302555331' + + '193017060b2b0601040182373c020102130844656c6177617265311d301b' + + '060355040f131450726976617465204f7267616e697a6174696f6e311030' + + '0e0603550405130735313633393636310b30090603550406130255533110' + + '300e0603550408130747656f726769613110300e0603550407130741746c' + + '616e746131153013060355040a130c4269745061792c20496e632e311330' + + '110603550403130a6269747061792e636f6d30820122300d06092a864886' + + 'f70d01010105000382010f003082010a0282010100e42025369a803c1b44' + + '234a279d123b610ec1178452fc7c57f2576492e1123166bed5eec11d12a8' + + 'b824904f77aa6166ce6e111538204121069b5ecff81fd1ab27b1b9475c49' + + 'd7680ef5f406f57a1871b77392a7b5c4370f504ba175617f78fe24c9ed76' + + '154b46aa677cf6463a202909711b34ceecbe0ee7b9766cfd7018886b67e5' + + '18f1ac39a3715152d62e59547f34d440ed3dfa01a92a42ed0b221c093144' + + 'ed63f86c2300b8cf192b75929732af63c41526e4fd69735f0062c61c2dbc' + + 'b56f6439ff9bbe62507da52752c1d99f24afbb3a6b5c98989d2196fb6bd9' + + 'cc83a5ab21f060e955e7f45a01c9efe782f15cd48ab824d6272db2b71c89' + + '88d02071e805df0203010001a382032d30820329300c0603551d130101ff' + + '04023000301d0603551d250416301406082b0601050507030106082b0601' + + '0505070302300e0603551d0f0101ff0404030205a030350603551d1f042e' + + '302c302aa028a0268624687474703a2f2f63726c2e676f64616464792e63' + + '6f6d2f676469673273332d312e63726c30530603551d20044c304a304806' + + '0b6086480186fd6d010717033039303706082b06010505070201162b6874' + + '74703a2f2f6365727469666963617465732e676f64616464792e636f6d2f' + + '7265706f7369746f72792f307606082b06010505070101046a3068302406' + + '082b060105050730018618687474703a2f2f6f6373702e676f6461646479' + + '2e636f6d2f304006082b060105050730028634687474703a2f2f63657274' + + '69666963617465732e676f64616464792e636f6d2f7265706f7369746f72' + + '792f67646967322e637274301f0603551d2304183016801440c2bd278ecc' + + '348330a233d7fb6cb3f0b42c80ce30250603551d11041e301c820a626974' + + '7061792e636f6d820e7777772e6269747061792e636f6d301d0603551d0e' + + '04160414a5698a70daa1405dbcdd1a02e95db8a51aaadd7f3082017d060a' + + '2b06010401d6790204020482016d0482016901670076005614069a2fd7c2' + + 'ecd3f5e1bd44b23ec74676b9bc99115cc0ef949855d689d0dd0000014cd8' + + 'b6d73a000004030047304502210095e5768670ea27ed35075e484b7c42cd' + + '20176c7263b4e879deb418639144079d02204911ae1cf0fcda5a2b6b3cec' + + '528ccd689e7371a34c99460c2ca063b44ba6fbca00750068f698f81f6482' + + 'be3a8ceeb9281d4cfc71515d6793d444d10a67acbb4f4ffbc40000014cd8' + + 'b6d93e0000040300463044022030c89215d7081b372a1b033eb77ff5abbe' + + '9c6822b38c9a0f5e4b166c7532fabf02200a481b330414d0076aa0d925dc' + + '84096b8cb7585fc0b1ff28c744cfa85e17ab8e007600a4b90990b4185814' + + '87bb13a2cc67700a3c359804f91bdfb8e377cd0ec80ddc100000014cd8b6' + + 'dc34000004030047304502201f085d25b292b34185a182e314a3c64c9b51' + + '62526c90cfc3ff7136b137bc98ee022100b28a7fbaa53c2fff07bdf23300' + + '551e0b52ff1d823bb89df9eeb9079327adfe2c300d06092a864886f70d01' + + '010b0500038201010013eeaf33325800bb0f252a091b1a9cdf2e10de3abf' + + 'b9f566b94a60e63401598f68c4086cf170881f1b856e51dc45edce992f58' + + '9a7c4acbfb7c28a10c28c1ce4d1425c5b795b764367f0446dde5bb5710e5' + + 'a1994a02f0b02334458e4950a876e48363aee4a32d1904d6d9c6af2906f4' + + 'e4e03122e35bf943cf17b0e05a8ebaa5154a86f40676e779bb1dcd2672d7' + + '5887e1bcb51186596d749bc6c1ecfedcf60b24eb503ac9460dc3682fe74e' + + '7acf16e9ab0014f6719322de534e14e90e7638e854546087c6a33d7743f5' + + '8ee3b589dbd8fa5800af9b0ecdef0c041a2bf2126b908e3bf84881c1a323' + + '929bca34f0830373a8b28f62b2133880ff6f20ffb19c38a7280ad4093082' + + '04d0308203b8a003020102020107300d06092a864886f70d01010b050030' + + '8183310b30090603550406130255533110300e060355040813074172697a' + + '6f6e61311330110603550407130a53636f74747364616c65311a30180603' + + '55040a1311476f44616464792e636f6d2c20496e632e3131302f06035504' + + '031328476f20446164647920526f6f742043657274696669636174652041' + + '7574686f72697479202d204732301e170d3131303530333037303030305a' + + '170d3331303530333037303030305a3081b4310b30090603550406130255' + + '533110300e060355040813074172697a6f6e61311330110603550407130a' + + '53636f74747364616c65311a3018060355040a1311476f44616464792e63' + + '6f6d2c20496e632e312d302b060355040b1324687474703a2f2f63657274' + + '732e676f64616464792e636f6d2f7265706f7369746f72792f3133303106' + + '03550403132a476f20446164647920536563757265204365727469666963' + + '61746520417574686f72697479202d20473230820122300d06092a864886' + + 'f70d01010105000382010f003082010a0282010100b9e0cb10d4af76bdd4' + + '9362eb3064b881086cc304d962178e2fff3e65cf8fce62e63c521cda1645' + + '4b55ab786b63836290ce0f696c99c81a148b4ccc4533ea88dc9ea3af2bfe' + + '80619d7957c4cf2ef43f303c5d47fc9a16bcc3379641518e114b54f828be' + + 'd08cbef030381ef3b026f86647636dde7126478f384753d1461db4e3dc00' + + 'ea45acbdbc71d9aa6f00dbdbcd303a794f5f4c47f81def5bc2c49d603bb1' + + 'b24391d8a4334eeab3d6274fad258aa5c6f4d5d0a6ae7405645788b54455' + + 'd42d2a3a3ef8b8bde9320a029464c4163a50f14aaee77933af0c20077fe8' + + 'df0439c269026c6352fa77c11bc87487c8b993185054354b694ebc3bd349' + + '2e1fdcc1d252fb0203010001a382011a30820116300f0603551d130101ff' + + '040530030101ff300e0603551d0f0101ff040403020106301d0603551d0e' + + '0416041440c2bd278ecc348330a233d7fb6cb3f0b42c80ce301f0603551d' + + '230418301680143a9a8507106728b6eff6bd05416e20c194da0fde303406' + + '082b0601050507010104283026302406082b060105050730018618687474' + + '703a2f2f6f6373702e676f64616464792e636f6d2f30350603551d1f042e' + + '302c302aa028a0268624687474703a2f2f63726c2e676f64616464792e63' + + '6f6d2f6764726f6f742d67322e63726c30460603551d20043f303d303b06' + + '04551d20003033303106082b06010505070201162568747470733a2f2f63' + + '657274732e676f64616464792e636f6d2f7265706f7369746f72792f300d' + + '06092a864886f70d01010b05000382010100087e6c9310c838b896a9904b' + + 'ffa15f4f04ef6c3e9c8806c9508fa673f757311bbebce42fdbf8bad35be0' + + 'b4e7e679620e0ca2d76a637331b5f5a848a43b082da25d90d7b47c254f11' + + '5630c4b6449d7b2c9de55ee6ef0c61aabfe42a1bee849eb8837dc143ce44' + + 'a713700d911ff4c813ad8360d9d872a873241eb5ac220eca17896258441b' + + 'ab892501000fcdc41b62db51b4d30f512a9bf4bc73fc76ce36a4cdd9d82c' + + 'eaae9bf52ab290d14d75188a3f8a4190237d5b4bfea403589b46b2c36060' + + '83f87d5041cec2a190c3bbef022fd21554ee4415d90aaea78a33edb12d76' + + '3626dc04eb9ff7611f15dc876fee469628ada1267d0a09a72e04a38dbcf8' + + 'bc0430010a81093082047d30820365a00302010202031be715300d06092a' + + '864886f70d01010b05003063310b30090603550406130255533121301f06' + + '0355040a131854686520476f2044616464792047726f75702c20496e632e' + + '3131302f060355040b1328476f20446164647920436c6173732032204365' + + '7274696669636174696f6e20417574686f72697479301e170d3134303130' + + '313037303030305a170d3331303533303037303030305a308183310b3009' + + '0603550406130255533110300e060355040813074172697a6f6e61311330' + + '110603550407130a53636f74747364616c65311a3018060355040a131147' + + '6f44616464792e636f6d2c20496e632e3131302f06035504031328476f20' + + '446164647920526f6f7420436572746966696361746520417574686f7269' + + '7479202d20473230820122300d06092a864886f70d01010105000382010f' + + '003082010a0282010100bf716208f1fa5934f71bc918a3f7804958e92283' + + '13a6c52043013b84f1e685499f27eaf6841b4ea0b4db7098c73201b1053e' + + '074eeef4fa4f2f593022e7ab19566be28007fcf316758039517be5f935b6' + + '744ea98d8213e4b63fa90383faa2be8a156a7fde0bc3b6191405caeac3a8' + + '04943b467c320df3006622c88d696d368c1118b7d3b21c60b438fa028cce' + + 'd3dd4607de0a3eeb5d7cc87cfbb02b53a4926269512505611a44818c2ca9' + + '439623dfac3a819a0e29c51ca9e95d1eb69e9e300a39cef18880fb4b5dcc' + + '32ec85624325340256270191b43b702a3f6eb1e89c88017d9fd4f9db536d' + + '609dbf2ce758abb85f46fccec41b033c09eb49315c6946b3e04702030100' + + '01a382011730820113300f0603551d130101ff040530030101ff300e0603' + + '551d0f0101ff040403020106301d0603551d0e041604143a9a8507106728' + + 'b6eff6bd05416e20c194da0fde301f0603551d23041830168014d2c4b0d2' + + '91d44c1171b361cb3da1fedda86ad4e3303406082b060105050701010428' + + '3026302406082b060105050730018618687474703a2f2f6f6373702e676f' + + '64616464792e636f6d2f30320603551d1f042b30293027a025a023862168' + + '7474703a2f2f63726c2e676f64616464792e636f6d2f6764726f6f742e63' + + '726c30460603551d20043f303d303b0604551d20003033303106082b0601' + + '0505070201162568747470733a2f2f63657274732e676f64616464792e63' + + '6f6d2f7265706f7369746f72792f300d06092a864886f70d01010b050003' + + '82010100590b53bd928611a7247bed5b31cf1d1f6c70c5b86ebe4ebbf6be' + + '9750e1307fba285c6294c2e37e33f7fb427685db951c8c225875090c8865' + + '67390a1609c5a03897a4c523933fb418a601064491e3a76927b45a257f3a' + + 'b732cddd84ff2a382933a4dd67b285fea188201c5089c8dc2af64203374c' + + 'e688dfd5af24f2b1c3dfccb5ece0995eb74954203c94180cc71c521849a4' + + '6de1b3580bc9d8ecd9ae1c328e28700de2fea6179e840fbd5770b35ae91f' + + 'a08653bbef7cff690be048c3b7930bc80a54c4ac5d1467376ccaa52f3108' + + '37aa6e6f8cbc9be2575d2481af97979c84ad6cac374c66f361911120e4be' + + '309f7aa42909b0e1345f6477184051df8c30a6af2289020a046d61696e12' + + '1f08c0843d121976a914e4ea045fc0f08208d452187ad401ab2a874d0b6d' + + '88ac1896d6e5af05209adde5af052a595061796d656e7420726571756573' + + '7420666f722042697450617920696e766f69636520504151744e7858374b' + + '4c3842744a426e66587954614820666f72206d65726368616e7420426974' + + '4769766520466f756e646174696f6e322b68747470733a2f2f6269747061' + + '792e636f6d2f692f504151744e7858374b4c3842744a426e665879546148' + + '3a4c7b22696e766f6963654964223a22504151744e7858374b4c3842744a' + + '426e665879546148222c226d65726368616e744964223a2254785a355279' + + '43686d5a773269734b6a4a5747684263227d2a8002dca72518e1951edeb8' + + '32ad680b5b99f29e0d5d9b9bf4c6d3a6e327436a8c9e44328b9c4738703b' + + '3407033f13cfc90ac7201dbbb612ee00f81a94169b4f4994b310c1779488' + + '77e440d1347a64aa55c351fd08a3ce9af7598b8d103b24a0928a23cba006' + + '7d35aa86de6fc664c017233cd22db0ec204cacb00c87dd58abfdeae7c2fc' + + '61e5666a41c1be2f633d925f97a088b1fabc0b6634fff7f0034437a8d4cf' + + '52d94d739dc67327a1b3757358f2799bda1e0af4e897a8fae0ec77f2baa8' + + 'fb6a9b315bf1a19e09dc806d3269e5544c98da2a3bfd1fcc70389539b1c9' + + 'ad0c16cd34f62cd1533e3b491115814746c47914bd2c45cf947ac239b1e1' + + '251907cfd99036', + 'hex', +); +SampleRequest.coinbase = new Buffer( + '' + + '120b783530392b7368613235361abe150afe0b308205fa308204e2a00302' + + '01020210090b35ca5c5bf1b98b3d8f9f4a7755d6300d06092a864886f70d' + + '01010b05003075310b300906035504061302555331153013060355040a13' + + '0c446967694365727420496e6331193017060355040b13107777772e6469' + + '6769636572742e636f6d313430320603550403132b446967694365727420' + + '5348413220457874656e6465642056616c69646174696f6e205365727665' + + '72204341301e170d3134303530393030303030305a170d31363035313331' + + '32303030305a30820105311d301b060355040f0c1450726976617465204f' + + '7267616e697a6174696f6e31133011060b2b0601040182373c0201031302' + + '555331193017060b2b0601040182373c020102130844656c617761726531' + + '10300e0603550405130735313534333137310f300d06035504090c062332' + + '33303038311730150603550409130e353438204d61726b65742053742e31' + + '0e300c060355041113053934313034310b30090603550406130255533113' + + '30110603550408130a43616c69666f726e6961311630140603550407130d' + + '53616e204672616e636973636f31173015060355040a130e436f696e6261' + + '73652c20496e632e311530130603550403130c636f696e626173652e636f' + + '6d30820122300d06092a864886f70d01010105000382010f003082010a02' + + '82010100b45e3ff380667aa14d5a12fc2fc983fc6618b55499933c3bde15' + + 'c01d838846b4caf9848e7c40e5fa7c67ef9b5b1efe26ee5571c5fa2eff75' + + '9052454701ad8931557d697b139e5d19abb3e439675f31db7f2ef1a5d97d' + + 'b07c1f6966266380eb4fcfa8e1471a6ecc2fbebf3e67b3eaa84d0fbe063e' + + '60380dcdb7a20203d29a94059ef7f20d472cc25783ab2a1db6a394ecc07b' + + '4024974100bcfd470f59ef3b572365213209609fad229994b4923c1df3a1' + + '8c41e3e7bc1f192ba6e7e5c32ae155107e21903eff7bce9fc594b49d9f6a' + + 'e7901fa191fcbae8a2cf09c3bfc24377d717b6010080c5681a7dbc6e1d52' + + '987b7ebbe95e7af4202da436e67a88472aacedc90203010001a38201f230' + + '8201ee301f0603551d230418301680143dd350a5d6a0adeef34a600a65d3' + + '21d4f8f8d60f301d0603551d0e041604146d33b9743a61b7499423d1a89d' + + '085d0148680bba30290603551d1104223020820c636f696e626173652e63' + + '6f6d82107777772e636f696e626173652e636f6d300e0603551d0f0101ff' + + '0404030205a0301d0603551d250416301406082b0601050507030106082b' + + '0601050507030230750603551d1f046e306c3034a032a030862e68747470' + + '3a2f2f63726c332e64696769636572742e636f6d2f736861322d65762d73' + + '65727665722d67312e63726c3034a032a030862e687474703a2f2f63726c' + + '342e64696769636572742e636f6d2f736861322d65762d7365727665722d' + + '67312e63726c30420603551d20043b3039303706096086480186fd6c0201' + + '302a302806082b06010505070201161c68747470733a2f2f7777772e6469' + + '6769636572742e636f6d2f43505330818806082b06010505070101047c30' + + '7a302406082b060105050730018618687474703a2f2f6f6373702e646967' + + '69636572742e636f6d305206082b060105050730028646687474703a2f2f' + + '636163657274732e64696769636572742e636f6d2f446967694365727453' + + '484132457874656e64656456616c69646174696f6e53657276657243412e' + + '637274300c0603551d130101ff04023000300d06092a864886f70d01010b' + + '05000382010100aadfcf94050ed938e3114a640af3d9b04276da00f5215d' + + '7148f9f16d4cac0c77bd5349ec2f47299d03c900f70146752da72829290a' + + 'c50a77992f01537ab2689392ce0bfeb7efa49f4c4fe4e1e43ca1fcfb1626' + + 'ce554da4f6e7fa34a597e401f215c43afd0ba777ad587eb0afacd71f7a6a' + + 'f7752814f7ab4c202ed76d33defd1289d541803fed01ac80a3cacfdaae29' + + '279e5de14d460475f4baf27eab693379d39120e7477bf3ec719664c7b6cb' + + '5e557556e5bbddd9c9d1ebc9f835e9da5b3dbb72fe8d94ac05eab3c47998' + + '7520ade3a1d275e1e2fe725698d2f7cb1390a9d40ea6cbf21a73bddccd1a' + + 'd61aa249ce8e2885a3730b7d53bd075f55099d2960f3cc0aba09308204b6' + + '3082039ea00302010202100c79a944b08c11952092615fe26b1d83300d06' + + '092a864886f70d01010b0500306c310b3009060355040613025553311530' + + '13060355040a130c446967694365727420496e6331193017060355040b13' + + '107777772e64696769636572742e636f6d312b3029060355040313224469' + + '6769436572742048696768204173737572616e636520455620526f6f7420' + + '4341301e170d3133313032323132303030305a170d323831303232313230' + + '3030305a3075310b300906035504061302555331153013060355040a130c' + + '446967694365727420496e6331193017060355040b13107777772e646967' + + '69636572742e636f6d313430320603550403132b44696769436572742053' + + '48413220457874656e6465642056616c69646174696f6e20536572766572' + + '20434130820122300d06092a864886f70d01010105000382010f00308201' + + '0a0282010100d753a40451f899a616484b6727aa9349d039ed0cb0b00087' + + 'f1672886858c8e63dabcb14038e2d3f5eca50518b83d3ec5991732ec188c' + + 'faf10ca6642185cb071034b052882b1f689bd2b18f12b0b3d2e7881f1fef' + + '387754535f80793f2e1aaaa81e4b2b0dabb763b935b77d14bc594bdf514a' + + 'd2a1e20ce29082876aaeead764d69855e8fdaf1a506c54bc11f2fd4af29d' + + 'bb7f0ef4d5be8e16891255d8c07134eef6dc2decc48725868dd821e4b04d' + + '0c89dc392617ddf6d79485d80421709d6f6fff5cba19e145cb5657287e1c' + + '0d4157aab7b827bbb1e4fa2aef2123751aad2d9b86358c9c77b573add894' + + '2de4f30c9deec14e627e17c0719e2cdef1f9102819330203010001a38201' + + '493082014530120603551d130101ff040830060101ff020100300e060355' + + '1d0f0101ff040403020186301d0603551d250416301406082b0601050507' + + '030106082b06010505070302303406082b06010505070101042830263024' + + '06082b060105050730018618687474703a2f2f6f6373702e646967696365' + + '72742e636f6d304b0603551d1f044430423040a03ea03c863a687474703a' + + '2f2f63726c342e64696769636572742e636f6d2f44696769436572744869' + + '67684173737572616e63654556526f6f7443412e63726c303d0603551d20' + + '0436303430320604551d2000302a302806082b06010505070201161c6874' + + '7470733a2f2f7777772e64696769636572742e636f6d2f435053301d0603' + + '551d0e041604143dd350a5d6a0adeef34a600a65d321d4f8f8d60f301f06' + + '03551d23041830168014b13ec36903f8bf4701d498261a0802ef63642bc3' + + '300d06092a864886f70d01010b050003820101009db6d09086e18602edc5' + + 'a0f0341c74c18d76cc860aa8f04a8a42d63fc8a94dad7c08ade6b650b8a2' + + '1a4d8807b12921dce7dac63c21e0e3114970ac7a1d01a4ca113a57ab7d57' + + '2a4074fdd31d851850df574775a17d55202e473750728c7f821bd2628f2d' + + '035adac3c8a1ce2c52a20063eb73ba71c84927239764859e380ead63683c' + + 'ba52815879a32c0cdfde6deb31f2baa07c6cf12cd4e1bd77843703ce32b5' + + 'c89a811a4a924e3b469a85fe83a2f99e8ca3cc0d5eb33dcf04788f14147b' + + '329cc700a65cc4b5a1558d5a5668a42270aa3c8171d99da8453bf4e5f6a2' + + '51ddc77b62e86f0c74ebb8daf8bf870d795091909b183b915927f1352813' + + 'ab267ed5f77a22b801121f08d8e51a121976a914f5fa7bb3c2245e646925' + + '4c074c062af292ce008c88ac189295e7af0520f49be7af052a315061796d' + + '656e74207265717565737420666f7220436f696e62617365206f72646572' + + '20636f64653a205738375858335753323468747470733a2f2f7777772e63' + + '6f696e626173652e636f6d2f72702f353566396361373033643564383030' + + '3038633030303166343a2062623739623666323331306533323162643362' + + '316439323965646265623335382a8002b45d9b5d48d566d577ec4973b4b5' + + '7a4930f173be6545d9fc367f9b55f90a669504085db971107a09c25d1e30' + + 'dcaf54ce86f177685751feebd5c66c40d7d9daad08129fe10450518d48e4' + + '9ae4e03a8c4939010f9f222de60b9e5df210e066115cbc2ad92f51fcdc35' + + 'eaa3ee2430687ff46053e460b6f93deede2ee09a8841eec11b6f5d1bbcf2' + + '6708e5c12d427959569d9af629f8940736ac3941f78eafb2c2e400dfcc76' + + 'e729d13c4a9d0ec834515cf7287188589e5e0e505a7a7daab1fa8ac4f674' + + '5a0eae2daa61d73a7e3fc56ca94457e2aa164a959b05bb91b797828cb7c4' + + 'd8b05395840a40ef51a0a0f93d13dce15e5f5f9ede08b3510701a1cac6a9' + + '9c06', + 'hex', +); module.exports = SampleRequest; diff --git a/packages/merit-payment-protocol/update-rootcerts.js b/packages/merit-payment-protocol/update-rootcerts.js index f759e3918a..9ebab29ebb 100644 --- a/packages/merit-payment-protocol/update-rootcerts.js +++ b/packages/merit-payment-protocol/update-rootcerts.js @@ -60,10 +60,8 @@ function request(options, callback) { options = { uri: options }; } - var uri = options.uri || options.url - , body = options.json - ? JSON.stringify(options.json) - : options.body || ''; + var uri = options.uri || options.url, + body = options.json ? JSON.stringify(options.json) : options.body || ''; if (typeof uri !== 'object') { uri = url.parse(uri); @@ -77,9 +75,7 @@ function request(options, callback) { uri.path = uri.pathname + '?' + qs.stringify(query); } - var protocol = uri.protocol === 'https:' - ? require('https') - : http; + var protocol = uri.protocol === 'https:' ? require('https') : http; options.method = options.method || (body ? 'POST' : 'GET'); options.method = options.method.toUpperCase(); @@ -102,12 +98,11 @@ function request(options, callback) { port: uri.port || (protocol === http ? 80 : 443), path: uri.path, method: options.method, - headers: options.headers + headers: options.headers, }; - - var req = protocol.request(opt) - , response = new Stream; + var req = protocol.request(opt), + response = new Stream(); req.on('error', function(err) { if (callback) { @@ -118,9 +113,9 @@ function request(options, callback) { }); req.on('response', function(res) { - var decoder = new StringDecoder('utf8') - , done = false - , body = ''; + var decoder = new StringDecoder('utf8'), + done = false, + body = ''; function end() { if (done) return; @@ -130,9 +125,7 @@ function request(options, callback) { if (options.json) { try { body = JSON.parse(body); - } catch (e) { - ; - } + } catch (e) {} } callback(null, res, body); } else { diff --git a/packages/merit-rpc/README.md b/packages/merit-rpc/README.md index e051a339a4..020b66aa33 100644 --- a/packages/merit-rpc/README.md +++ b/packages/merit-rpc/README.md @@ -1,5 +1,4 @@ -meritd-rpc.js -=============== +# meritd-rpc.js A client library to connect to Merit Core RPC in JavaScript. @@ -27,14 +26,14 @@ var run = function() { var txids = []; function showNewTransactions() { - rpc.getRawMemPool(function (err, ret) { + rpc.getRawMemPool(function(err, ret) { if (err) { console.error(err); return setTimeout(showNewTransactions, 10000); } function batchCall() { - ret.result.forEach(function (txid) { + ret.result.forEach(function(txid) { if (txids.indexOf(txid) === -1) { rpc.getRawTransaction(txid); } @@ -47,7 +46,7 @@ var run = function() { return setTimeout(showNewTransactions, 10000); } - rawtxs.map(function (rawtx) { + rawtxs.map(function(rawtx) { var tx = new meritcore.Transaction(rawtx.result); console.log('\n\n\n' + tx.id + ':', tx.toObject()); }); diff --git a/packages/merit-rpc/lib/index.js b/packages/merit-rpc/lib/index.js index bde1616a3b..e7bbd7d64d 100644 --- a/packages/merit-rpc/lib/index.js +++ b/packages/merit-rpc/lib/index.js @@ -12,13 +12,13 @@ function RpcClient(opts) { this.pass = opts.pass || 'pass'; this.protocol = opts.protocol === 'http' ? http : https; this.batchedCalls = null; - this.disableAgent = opts.disableAgent || false; + this.disableAgent = opts.disableAgent || false; var queueSize = opts.queue || 16; var isRejectUnauthorized = typeof opts.rejectUnauthorized !== 'undefined'; this.rejectUnauthorized = isRejectUnauthorized ? opts.rejectUnauthorized : true; - if(RpcClient.config.log) { + if (RpcClient.config.log) { this.log = RpcClient.config.log; } else { this.log = RpcClient.loggers[RpcClient.config.logger || 'normal']; @@ -34,13 +34,13 @@ var cl = console.log.bind(console); var noop = function() {}; RpcClient.loggers = { - none: {info: noop, warn: noop, err: noop, debug: noop}, - normal: {info: cl, warn: cl, err: cl, debug: noop}, - debug: {info: cl, warn: cl, err: cl, debug: cl} + none: { info: noop, warn: noop, err: noop, debug: noop }, + normal: { info: cl, warn: cl, err: cl, debug: noop }, + debug: { info: cl, warn: cl, err: cl, debug: cl }, }; RpcClient.config = { - logger: 'normal' // none, normal, debug + logger: 'normal', // none, normal, debug }; function rpc(request, callback) { @@ -68,7 +68,7 @@ function innerRpc(request, callback) { method: 'POST', port: self.port, rejectUnauthorized: self.rejectUnauthorized, - agent: self.disableAgent ? false : undefined + agent: self.disableAgent ? false : undefined, }; if (self.httpOptions) { @@ -82,14 +82,12 @@ function innerRpc(request, callback) { var errorMessage = 'Merit JSON-RPC: '; var req = this.protocol.request(options, function(res) { - var buf = ''; res.on('data', function(data) { buf += data; }); res.on('end', function() { - if (called) { return; } @@ -113,7 +111,7 @@ function innerRpc(request, callback) { var parsedBuf; try { parsedBuf = JSON.parse(buf); - } catch(e) { + } catch (e) { self.log.err(e.stack); self.log.err(buf); self.log.err('HTTP Status code:' + res.statusCode); @@ -123,7 +121,6 @@ function innerRpc(request, callback) { } callback(parsedBuf.error, parsedBuf); - }); }); @@ -220,7 +217,7 @@ RpcClient.callspec = { move: 'str str float int str', prioritiseTransaction: 'str float int', sendFrom: 'str str float int str str', - sendMany: 'str obj int str', //not sure this is will work + sendMany: 'str obj int str', //not sure this is will work sendRawTransaction: 'str', sendToAddress: 'str float str str', setAccount: '', @@ -245,10 +242,10 @@ RpcClient.callspec = { getaddressanv: 'obj', sendRawReferral: 'str', getRawReferral: 'str int', - getaddressmempoolreferrals: "obj", - getaddressreferrals: "obj", + getaddressmempoolreferrals: 'obj', + getaddressreferrals: 'obj', getaddressrank: 'obj', - getaddressleaderboard: 'obj' + getaddressleaderboard: 'obj', }; var slice = function(arr, start, end) { @@ -256,10 +253,8 @@ var slice = function(arr, start, end) { }; function generateRPCMethods(constructor, apiCalls, rpc) { - function createRPCMethod(methodName, argMap) { return function() { - var limit = arguments.length - 1; if (this.batchedCalls) { @@ -267,7 +262,7 @@ function generateRPCMethods(constructor, apiCalls, rpc) { } for (var i = 0; i < limit; i++) { - if(argMap[i]) { + if (argMap[i]) { arguments[i] = argMap[i](arguments[i]); } } @@ -277,18 +272,21 @@ function generateRPCMethods(constructor, apiCalls, rpc) { jsonrpc: '2.0', method: methodName, params: slice(arguments), - id: getRandomId() + id: getRandomId(), }); } else { - rpc.call(this, { - method: methodName, - params: slice(arguments, 0, arguments.length - 1), - id: getRandomId() - }, arguments[arguments.length - 1]); + rpc.call( + this, + { + method: methodName, + params: slice(arguments, 0, arguments.length - 1), + id: getRandomId(), + }, + arguments[arguments.length - 1], + ); } - }; - }; + } var types = { str: function(arg) { @@ -301,20 +299,20 @@ function generateRPCMethods(constructor, apiCalls, rpc) { return parseFloat(arg); }, bool: function(arg) { - return (arg === true || arg == '1' || arg == 'true' || arg.toString().toLowerCase() == 'true'); + return arg === true || arg == '1' || arg == 'true' || arg.toString().toLowerCase() == 'true'; }, obj: function(arg) { - if(typeof arg === 'string') { + if (typeof arg === 'string') { return JSON.parse(arg); } return arg; - } + }, }; - for(var k in apiCalls) { + for (var k in apiCalls) { var spec = apiCalls[k].split(' '); for (var i = 0; i < spec.length; i++) { - if(types[spec[i]]) { + if (types[spec[i]]) { spec[i] = types[spec[i]]; } else { spec[i] = types.str; @@ -324,7 +322,6 @@ function generateRPCMethods(constructor, apiCalls, rpc) { constructor.prototype[k] = createRPCMethod(methodName, spec); constructor.prototype[methodName] = constructor.prototype[k]; } - } function getRandomId() { diff --git a/packages/merit-rpc/test/index.js b/packages/merit-rpc/test/index.js index 5318df7536..ecb4b988f0 100644 --- a/packages/merit-rpc/test/index.js +++ b/packages/merit-rpc/test/index.js @@ -10,10 +10,9 @@ var http = require('http'); var https = require('https'); var async = require('async'); -if(!setImmediate) setImmediate = setTimeout; +if (!setImmediate) setImmediate = setTimeout; describe('RpcClient', function() { - it('should initialize the main object', function() { should.exist(RpcClient); }); @@ -31,10 +30,10 @@ describe('RpcClient', function() { it('should be able to define a custom logger', function() { var customLogger = { - info: function(){}, - warn: function(){}, - err: function(){}, - debug: function(){} + info: function() {}, + warn: function() {}, + err: function() {}, + debug: function() {}, }; RpcClient.config.log = customLogger; var s = new RpcClient(); @@ -54,12 +53,12 @@ describe('RpcClient', function() { s.log.should.equal(RpcClient.loggers.none); }); - function FakeResponse(){ + function FakeResponse() { EventEmitter.call(this); } util.inherits(FakeResponse, EventEmitter); - function FakeRequest(){ + function FakeRequest() { EventEmitter.call(this); return this; } @@ -71,44 +70,39 @@ describe('RpcClient', function() { FakeRequest.prototype.end = function() {}; it('should use https', function() { - var client = new RpcClient({ user: 'user', pass: 'pass', port: 8445, }); client.protocol.should.equal(https); - }); it('should use http', function() { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, - protocol: 'http' + protocol: 'http', }); client.protocol.should.equal(http); - }); it('should call a method and receive response', function(done) { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, rejectUnauthorized: true, - disableAgent: true + disableAgent: true, }); - var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ + var requestStub = sinon.stub(client.protocol, 'request', function(options, callback) { var res = new FakeResponse(); - var req = new FakeRequest(); - setImmediate(function(){ + var req = new FakeRequest(); + setImmediate(function() { res.emit('data', '{}'); res.emit('end'); }); @@ -122,24 +116,22 @@ describe('RpcClient', function() { should.exist(parsedBuf); done(); }); - }); it('accept many values for bool', function(done) { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, rejectUnauthorized: true, - disableAgent: false + disableAgent: false, }); - var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ + var requestStub = sinon.stub(client.protocol, 'request', function(options, callback) { var res = new FakeResponse(); var req = new FakeRequest(); - setImmediate(function(){ + setImmediate(function() { res.emit('data', req.data); res.emit('end'); }); @@ -147,35 +139,37 @@ describe('RpcClient', function() { return req; }); - async.eachSeries([true, 'true', 1, '1', 'True'], function(i, next) { - client.importAddress('n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X', '', i, function(error, parsedBuf) { - should.not.exist(error); - should.exist(parsedBuf); - parsedBuf.params[2].should.equal(true); - next(); - }); - }, function(err) { - requestStub.restore(); - done(); - }); - + async.eachSeries( + [true, 'true', 1, '1', 'True'], + function(i, next) { + client.importAddress('n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X', '', i, function(error, parsedBuf) { + should.not.exist(error); + should.exist(parsedBuf); + parsedBuf.params[2].should.equal(true); + next(); + }); + }, + function(err) { + requestStub.restore(); + done(); + }, + ); }); it('should process object arguments', function(done) { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, rejectUnauthorized: true, - disableAgent: false + disableAgent: false, }); - var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ + var requestStub = sinon.stub(client.protocol, 'request', function(options, callback) { var res = new FakeResponse(); var req = new FakeRequest(); - setImmediate(function(){ + setImmediate(function() { res.emit('data', req.data); res.emit('end'); }); @@ -183,35 +177,37 @@ describe('RpcClient', function() { return req; }); - var obj = {'n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X': 1}; - async.eachSeries([obj, JSON.stringify(obj)], function(i, next) { - client.sendMany('account', i, function(error, parsedBuf) { - should.not.exist(error); - should.exist(parsedBuf); - parsedBuf.params[1].should.have.property('n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X', 1); - next(); - }); - }, function(err) { - requestStub.restore(); - done(); - }); - + var obj = { n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X: 1 }; + async.eachSeries( + [obj, JSON.stringify(obj)], + function(i, next) { + client.sendMany('account', i, function(error, parsedBuf) { + should.not.exist(error); + should.exist(parsedBuf); + parsedBuf.params[1].should.have.property('n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X', 1); + next(); + }); + }, + function(err) { + requestStub.restore(); + done(); + }, + ); }); it('should batch calls for a method and receive a response', function(done) { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, rejectUnauthorized: true, - disableAgent: false + disableAgent: false, }); - var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ + var requestStub = sinon.stub(client.protocol, 'request', function(options, callback) { var res = new FakeResponse(); - setImmediate(function(){ + setImmediate(function() { res.emit('data', '[{}, {}, {}]'); res.emit('end'); }); @@ -224,34 +220,35 @@ describe('RpcClient', function() { client.listReceivedByAccount(2, true); client.listReceivedByAccount(3, true); client.batchedCalls.length.should.equal(3); - client.batch(function(){ - // batch started - }, function(error, result){ - // batch ended - requestStub.restore(); - should.not.exist(error); - should.exist(result); - result.length.should.equal(3); - done(); - }); - + client.batch( + function() { + // batch started + }, + function(error, result) { + // batch ended + requestStub.restore(); + should.not.exist(error); + should.exist(result); + result.length.should.equal(3); + done(); + }, + ); }); it('should handle connection rejected 401 unauthorized', function(done) { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, rejectUnauthorized: true, - disableAgent: true + disableAgent: true, }); - var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ + var requestStub = sinon.stub(client.protocol, 'request', function(options, callback) { var res = new FakeResponse(); res.statusCode = 401; - setImmediate(function(){ + setImmediate(function() { res.emit('end'); }); callback(res); @@ -264,24 +261,22 @@ describe('RpcClient', function() { error.message.should.equal('Merit JSON-RPC: Connection Rejected: 401 Unnauthorized'); done(); }); - }); it('should handle connection rejected 401 forbidden', function(done) { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, rejectUnauthorized: true, - disableAgent: true + disableAgent: true, }); - var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ + var requestStub = sinon.stub(client.protocol, 'request', function(options, callback) { var res = new FakeResponse(); res.statusCode = 403; - setImmediate(function(){ + setImmediate(function() { res.emit('end'); }); callback(res); @@ -294,24 +289,22 @@ describe('RpcClient', function() { error.message.should.equal('Merit JSON-RPC: Connection Rejected: 403 Forbidden'); done(); }); - }); it('should handle 500 work limit exceeded error', function(done) { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, rejectUnauthorized: true, - disableAgent: true + disableAgent: true, }); - var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ + var requestStub = sinon.stub(client.protocol, 'request', function(options, callback) { var res = new FakeResponse(); res.statusCode = 500; - setImmediate(function(){ + setImmediate(function() { res.emit('data', 'Work queue depth exceeded'); res.emit('end'); }); @@ -325,27 +318,25 @@ describe('RpcClient', function() { error.message.should.equal('Merit JSON-RPC: Work queue depth exceeded'); done(); }); - }); it('should handle EPIPE error case 1', function(done) { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, rejectUnauthorized: true, - disableAgent: true + disableAgent: true, }); - var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ + var requestStub = sinon.stub(client.protocol, 'request', function(options, callback) { var req = new FakeRequest(); - setImmediate(function(){ + setImmediate(function() { req.emit('error', new Error('write EPIPE')); }); var res = new FakeResponse(); - setImmediate(function(){ + setImmediate(function() { res.emit('data', '{}'); res.emit('end'); }); @@ -359,28 +350,26 @@ describe('RpcClient', function() { error.message.should.equal('Merit JSON-RPC: Request Error: write EPIPE'); done(); }); - }); it('should handle EPIPE error case 2', function(done) { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, rejectUnauthorized: true, - disableAgent: true + disableAgent: true, }); - var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ + var requestStub = sinon.stub(client.protocol, 'request', function(options, callback) { var res = new FakeResponse(); - setImmediate(function(){ + setImmediate(function() { res.emit('data', '{}'); res.emit('end'); }); var req = new FakeRequest(); - setImmediate(function(){ + setImmediate(function() { req.emit('error', new Error('write EPIPE')); }); callback(res); @@ -392,24 +381,22 @@ describe('RpcClient', function() { }); client.getDifficulty(function(error, parsedBuf) {}); - }); it('should handle ECONNREFUSED error', function(done) { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, rejectUnauthorized: true, - disableAgent: true + disableAgent: true, }); - var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ + var requestStub = sinon.stub(client.protocol, 'request', function(options, callback) { var res = new FakeResponse(); var req = new FakeRequest(); - setImmediate(function(){ + setImmediate(function() { req.emit('error', new Error('connect ECONNREFUSED')); }); callback(res); @@ -422,23 +409,21 @@ describe('RpcClient', function() { error.message.should.equal('Merit JSON-RPC: Request Error: connect ECONNREFUSED'); done(); }); - }); it('should callback with error if invalid json', function(done) { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, rejectUnauthorized: true, - disableAgent: true + disableAgent: true, }); - var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ + var requestStub = sinon.stub(client.protocol, 'request', function(options, callback) { var res = new FakeResponse(); - setImmediate(function(){ + setImmediate(function() { res.emit('data', 'not a json string'); res.emit('end'); }); @@ -453,23 +438,21 @@ describe('RpcClient', function() { error.message.should.contain('Merit JSON-RPC: Error Parsing JSON: Unexpected token o'); done(); }); - }); it('should callback with error if blank response', function(done) { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, rejectUnauthorized: true, - disableAgent: true + disableAgent: true, }); - var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ + var requestStub = sinon.stub(client.protocol, 'request', function(options, callback) { var res = new FakeResponse(); - setImmediate(function(){ + setImmediate(function() { res.emit('data', ''); res.emit('end'); }); @@ -484,30 +467,28 @@ describe('RpcClient', function() { error.message.should.equal('Merit JSON-RPC: Error Parsing JSON: Unexpected end of JSON input'); done(); }); - }); it('should add additional http options', function(done) { - var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8445, rejectUnauthorized: true, - disableAgent: true + disableAgent: true, }); client.httpOptions = { - port: 20001 + port: 20001, }; var calledPort = false; - var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ + var requestStub = sinon.stub(client.protocol, 'request', function(options, callback) { calledPort = options.port; var res = new FakeResponse(); - setImmediate(function(){ + setImmediate(function() { res.emit('data', '{}'); res.emit('end'); }); @@ -523,7 +504,5 @@ describe('RpcClient', function() { requestStub.restore(); done(); }); - }); - }); diff --git a/packages/merit-wallet-service/README.md b/packages/merit-wallet-service/README.md index 2fc731c9c9..d9e7350e70 100644 --- a/packages/merit-wallet-service/README.md +++ b/packages/merit-wallet-service/README.md @@ -1,4 +1,3 @@ - # merit-wallet-service A Multisig HD Merit Wallet Service. @@ -10,6 +9,7 @@ Merit Wallet Service facilitates multisig HD wallets creation and operation thro BWS can usually be installed within minutes and accommodates all the needed infrastructure for peers in a multisig wallet to communicate and operate โ€“ with minimum server trust. # Getting Started + ``` git clone https://github.com/meritlabs/lightwallet-stack.git make start-stack @@ -22,13 +22,14 @@ BWS needs mongoDB. You can configure the connection at `config.js` BWS uses by default a Request Rate Limitation to CreateWallet endpoint. If you need to modify it, check defaults.js' `Defaults.RateLimit` # Security Considerations - * Private keys are never sent to BWS. Copayers store them locally. - * Extended public keys are stored on BWS. This allows BWS to easily check wallet balance, send offline notifications to copayers, etc. - * During wallet creation, the initial copayer creates a wallet secret that contains a private key. All copayers need to prove they have the secret by signing their information with this private key when joining the wallet. The secret should be shared using secured channels. - * A user could join the wallet more than once, and there is no mechanism to prevent this. . - * All MWS responses are verified: - * Addresses and change addresses are derived independently and locally by the copayers from their local data. - * TX Proposals templates are signed by copayers and verified by others, so the BWS cannot create or tamper with them. + +- Private keys are never sent to BWS. Copayers store them locally. +- Extended public keys are stored on BWS. This allows BWS to easily check wallet balance, send offline notifications to copayers, etc. +- During wallet creation, the initial copayer creates a wallet secret that contains a private key. All copayers need to prove they have the secret by signing their information with this private key when joining the wallet. The secret should be shared using secured channels. +- A user could join the wallet more than once, and there is no mechanism to prevent this. . +- All MWS responses are verified: +- Addresses and change addresses are derived independently and locally by the copayers from their local data. +- TX Proposals templates are signed by copayers and verified by others, so the BWS cannot create or tamper with them. ## Contributing diff --git a/packages/merit-wallet-service/config.js b/packages/merit-wallet-service/config.js index bf6e89e845..ba34109cf0 100644 --- a/packages/merit-wallet-service/config.js +++ b/packages/merit-wallet-service/config.js @@ -81,9 +81,11 @@ var config = { // testnet: 'https://test-insight.bitpay.com/tx/{{txid}}', // }, //}, - mailer: sgTransport({ auth: { - api_key: '', - }}), + mailer: sgTransport({ + auth: { + api_key: '', + }, + }), emailOpts: { subjectPrefix: '[Merit]', from: 'support@merit.me', @@ -92,11 +94,11 @@ var config = { publicTxUrlTemplate: { livenet: 'https://insight.bitpay.com/tx/{{txid}}', testnet: 'https://test-insight.bitpay.com/tx/{{txid}}', - } + }, }, meritMessagingUrl: process.env.MERIT_MESSAGING_URL || 'http://localhost:8300', smsOpts: { - enabled: process.env.SMS_ENABLED - } + enabled: process.env.SMS_ENABLED, + }, }; module.exports = config; diff --git a/packages/merit-wallet-service/lib/blockchainexplorer.js b/packages/merit-wallet-service/lib/blockchainexplorer.js index e61bf6a41f..ae27fce1d1 100644 --- a/packages/merit-wallet-service/lib/blockchainexplorer.js +++ b/packages/merit-wallet-service/lib/blockchainexplorer.js @@ -8,9 +8,9 @@ log.debug = log.verbose; var Insight = require('./blockchainexplorers/insight'); var PROVIDERS = { - 'insight': { + insight: { //'livenet': 'http://127.0.0.1:3131', //Does not exist for now. - 'testnet': 'http://127.0.0.1:3001', + testnet: 'http://127.0.0.1:3001', }, }; @@ -22,7 +22,10 @@ function BlockChainExplorer(opts) { var log = opts.log || log; //If we don't have a unified logger, use npmlog. $.checkState(PROVIDERS[provider], 'Provider ' + provider + ' not supported'); - $.checkState(_.includes(_.keys(PROVIDERS[provider]), network), 'Network ' + network + ' not supported by this provider'); + $.checkState( + _.includes(_.keys(PROVIDERS[provider]), network), + 'Network ' + network + ' not supported by this provider', + ); var url = opts.url || PROVIDERS[provider][network]; @@ -33,11 +36,11 @@ function BlockChainExplorer(opts) { url: url, apiPrefix: opts.apiPrefix, userAgent: opts.userAgent, - log: opts.log + log: opts.log, }); default: throw new Error('Provider ' + provider + ' not supported.'); - }; -}; + } +} module.exports = BlockChainExplorer; diff --git a/packages/merit-wallet-service/lib/blockchainexplorers/insight.js b/packages/merit-wallet-service/lib/blockchainexplorers/insight.js index 2eeb8a9b62..dfd0c21b61 100644 --- a/packages/merit-wallet-service/lib/blockchainexplorers/insight.js +++ b/packages/merit-wallet-service/lib/blockchainexplorers/insight.js @@ -16,8 +16,7 @@ function Insight(opts) { this.hosts = opts.url; this.userAgent = opts.userAgent || 'bws'; log = opts.log || require('npmlog'); -}; - +} var _parseErr = function(err, res) { // The 'err' can be misleading because it's not really the error returned from insight. @@ -25,11 +24,13 @@ var _parseErr = function(err, res) { const errMessage = res.body; if (err) { log.warn('Network error connecting to blockchain explorer: ', err); - return { localMessage: "Error connecting to the blockchain explorer.", ...errMessage }; + return { localMessage: 'Error connecting to the blockchain explorer.', ...errMessage }; } - log.warn("Insight " + res.request.href + " Returned Status: " + res.statusCode + ". Error message: " + errMessage.message); + log.warn( + 'Insight ' + res.request.href + ' Returned Status: ' + res.statusCode + '. Error message: ' + errMessage.message, + ); - return { localMessage: "Error querying the blockchain", ...errMessage }; + return { localMessage: 'Error querying the blockchain', ...errMessage }; }; Insight.prototype._doRequest = function(args, cb) { @@ -37,7 +38,7 @@ Insight.prototype._doRequest = function(args, cb) { hosts: this.hosts, headers: { 'User-Agent': this.userAgent, - } + }, }; requestList(_.defaults(args, opts), cb); }; @@ -74,7 +75,7 @@ Insight.prototype.broadcast = function(rawTx, cb) { method: 'POST', path: this.apiPrefix + '/tx/send', json: { - rawtx: rawTx + rawtx: rawTx, }, }; @@ -93,8 +94,7 @@ Insight.prototype.getTransaction = function(txid, cb) { this._doRequest(args, function(err, res, tx) { if (res && res.statusCode == 404) return cb(); - if (err || res.statusCode !== 200) - return cb(_parseErr(err, res)); + if (err || res.statusCode !== 200) return cb(_parseErr(err, res)); return cb(null, tx); }); @@ -109,40 +109,37 @@ Insight.prototype.getReferral = function(refid, cb) { this._doRequest(args, function(err, res, tx) { if (res && res.statusCode == 404) return cb(); - if (err || res.statusCode !== 200) - return cb(_parseErr(err, res)); + if (err || res.statusCode !== 200) return cb(_parseErr(err, res)); return cb(null, tx); }); }; Insight.prototype.getAddressReferrals = function(addresses, cb) { + var args = { + method: 'POST', + path: this.apiPrefix + '/addrs/referrals', + json: { + addrs: [].concat(addresses).join(','), + }, + timeout: 120000, + }; - var args = { - method: 'POST', - path: this.apiPrefix + '/addrs/referrals', - json: { - addrs: [].concat(addresses).join(',') - }, - timeout: 120000 - }; - - this._doRequest(args, function(err, res, referrals) { - if (err || res.statusCode !== 200) return cb(_parseErr(err, res)); + this._doRequest(args, function(err, res, referrals) { + if (err || res.statusCode !== 200) return cb(_parseErr(err, res)); - if (_.isObject(referrals)) { - if (referrals.totalItems) - var total = referrals.totalItems; + if (_.isObject(referrals)) { + if (referrals.totalItems) var total = referrals.totalItems; - if (referrals.items) - referrals = referrals.items; - } + if (referrals.items) referrals = referrals.items; + } - // NOTE: Whenever Insight breaks communication with meritd, it returns invalid data but no error code. - if (!_.isArray(referrals) || (referrals.length != _.compact(referrals).length)) return cb(new Error('Could not retrieve referrals from blockchain. Request was:' + JSON.stringify(args))); + // NOTE: Whenever Insight breaks communication with meritd, it returns invalid data but no error code. + if (!_.isArray(referrals) || referrals.length != _.compact(referrals).length) + return cb(new Error('Could not retrieve referrals from blockchain. Request was:' + JSON.stringify(args))); - return cb(null, referrals, total); - }); + return cb(null, referrals, total); + }); }; Insight.prototype.getTransactions = function(addresses, from, to, cb) { @@ -160,7 +157,7 @@ Insight.prototype.getTransactions = function(addresses, from, to, cb) { method: 'POST', path: this.apiPrefix + '/addrs/txs' + (qs.length > 0 ? '?' + qs.join('&') : ''), json: { - addrs: [].concat(addresses).join(',') + addrs: [].concat(addresses).join(','), }, timeout: 120000, }; @@ -169,15 +166,14 @@ Insight.prototype.getTransactions = function(addresses, from, to, cb) { if (err || res.statusCode !== 200) return cb(_parseErr(err, res)); if (_.isObject(txs)) { - if (txs.totalItems) - total = txs.totalItems; + if (txs.totalItems) total = txs.totalItems; - if (txs.items) - txs = txs.items; + if (txs.items) txs = txs.items; } // NOTE: Whenever Insight breaks communication with meritd, it returns invalid data but no error code. - if (!_.isArray(txs) || (txs.length != _.compact(txs).length)) return cb(new Error('Could not retrieve transactions from blockchain. Request was:' + JSON.stringify(args))); + if (!_.isArray(txs) || txs.length != _.compact(txs).length) + return cb(new Error('Could not retrieve transactions from blockchain. Request was:' + JSON.stringify(args))); return cb(null, txs, total); }); @@ -194,8 +190,7 @@ Insight.prototype.getAddressActivity = function(address, cb) { this._doRequest(args, function(err, res, result) { if (res && res.statusCode == 404) return cb(); - if (err || res.statusCode !== 200) - return cb(_parseErr(err, res)); + if (err || res.statusCode !== 200) return cb(_parseErr(err, res)); var nbTxs = result.unconfirmedTxApperances + result.txApperances; return cb(null, nbTxs > 0); @@ -249,14 +244,17 @@ Insight.prototype.getBlock = function(blockHash, cb) { console.log('insight block received. Referrals: ', body.referrals); return cb(null, body); }); -} +}; Insight.prototype.initSocket = function() { console.log('Insight hosts:', this.hosts); // sockets always use the first server on the pull - var socket = io.connect(_.head([].concat(this.hosts)), { - 'reconnection': true, - }); + var socket = io.connect( + _.head([].concat(this.hosts)), + { + reconnection: true, + }, + ); return socket; }; @@ -282,8 +280,8 @@ Insight.prototype.getANV = function(addresses, cb) { method: 'GET', path: `${this.apiPrefix}/anv`, json: { - addresses: addresses - } + addresses: addresses, + }, }; this._doRequest(args, function(err, res, body) { @@ -297,7 +295,7 @@ Insight.prototype.getANV = function(addresses, cb) { Insight.prototype.getCommunityInfo = function(address, cb) { const args = { method: 'GET', - path: `${this.apiPrefix}/communityinfo/${address}` + path: `${this.apiPrefix}/communityinfo/${address}`, }; this._doRequest(args, (err, res, body) => { @@ -311,20 +309,20 @@ Insight.prototype.getCommunityInfo = function(address, cb) { Insight.prototype.getRewards = function(addresses, cb) { var self = this; - var args = { - method: 'GET', - path: `${this.apiPrefix}/rewards`, - json: { - addresses: addresses - } - }; - - this._doRequest(args, function(err, res, body) { - if (err || res.statusCode !== 200) { - return cb(_parseErr(err, res)); - } - return cb(null, body); - }); -} + var args = { + method: 'GET', + path: `${this.apiPrefix}/rewards`, + json: { + addresses: addresses, + }, + }; + + this._doRequest(args, function(err, res, body) { + if (err || res.statusCode !== 200) { + return cb(_parseErr(err, res)); + } + return cb(null, body); + }); +}; module.exports = Insight; diff --git a/packages/merit-wallet-service/lib/blockchainexplorers/localdaemon.js b/packages/merit-wallet-service/lib/blockchainexplorers/localdaemon.js index c639ac0e62..78aaeaaedf 100644 --- a/packages/merit-wallet-service/lib/blockchainexplorers/localdaemon.js +++ b/packages/merit-wallet-service/lib/blockchainexplorers/localdaemon.js @@ -67,14 +67,12 @@ LocalDaemon.prototype.sendReferral = function(rawReferral, cb) { }); }; - - -LocalDaemon.prototype.getMempoolReferrals = function(addresses) { - return this.node.getMempoolReferrals(addresses); +LocalDaemon.prototype.getMempoolReferrals = function(addresses) { + return this.node.getMempoolReferrals(addresses); }; LocalDaemon.prototype.getBlockchainReferrals = function(addresses) { - return this.node.getBlockchainReferrals(addresses); + return this.node.getBlockchainReferrals(addresses); }; /** @@ -83,34 +81,32 @@ LocalDaemon.prototype.getBlockchainReferrals = function(addresses) { * @return Array of addresses that were accepted */ LocalDaemon.prototype.getMempoolAcceptedAddresses = async function(addresses) { - let acceptedAddresses = []; + let acceptedAddresses = []; - const txs = (await this.node.getAddressMempool(addresses)) - .filter(t => t.isInvite && t.satoshis < 0); //is invite tx and sent FROM given address + const txs = (await this.node.getAddressMempool(addresses)).filter(t => t.isInvite && t.satoshis < 0); //is invite tx and sent FROM given address - await Promise.all(_.map(txs, async (t) => { - let res = await promisify(this.node.getDetailedTransaction)(t.txid); - acceptedAddresses.push(res.outputs[0].address); - })); + await Promise.all( + _.map(txs, async t => { + let res = await promisify(this.node.getDetailedTransaction)(t.txid); + acceptedAddresses.push(res.outputs[0].address); + }), + ); - return acceptedAddresses; + return acceptedAddresses; }; LocalDaemon.prototype.getCommunityRank = function(addresses) { - return this.node.getCommunityRank(addresses); + return this.node.getCommunityRank(addresses); }; - LocalDaemon.prototype.getCommunityLeaderboard = function(limit) { - return this.node.getCommunityLeaderboard(limit); + return this.node.getCommunityLeaderboard(limit); }; LocalDaemon.prototype.getAddressBalance = async function(addresses, options) { - const {err, result} = await promisify(this.node.getAddressBalance.bind(this.node))(addresses, options); - if(err) throw err; + const { err, result } = await promisify(this.node.getAddressBalance.bind(this.node))(addresses, options); + if (err) throw err; return result; }; - - module.exports = LocalDaemon; diff --git a/packages/merit-wallet-service/lib/blockchainexplorers/request-list.js b/packages/merit-wallet-service/lib/blockchainexplorers/request-list.js index cf93a9eabc..4cd171905b 100644 --- a/packages/merit-wallet-service/lib/blockchainexplorers/request-list.js +++ b/packages/merit-wallet-service/lib/blockchainexplorers/request-list.js @@ -5,8 +5,7 @@ var $ = require('preconditions').singleton(); var log = require('npmlog'); log.debug = log.verbose; - -var DEFAULT_TIMEOUT= 60000; // 60 s +var DEFAULT_TIMEOUT = 60000; // 60 s /** * Query a server, using one of the given options * @@ -18,14 +17,13 @@ var requestList = function(args, cb) { $.checkArgument(args.hosts); request = args.request || require('request'); - if (!_.isArray(args.hosts)) - args.hosts = [args.hosts]; + if (!_.isArray(args.hosts)) args.hosts = [args.hosts]; args.timeout = args.timeout || DEFAULT_TIMEOUT; // This allows us to round-robin requests across hosts until we get one that is responsive. var urls = _.map(args.hosts, function(x) { - return (x + args.path); + return x + args.path; }); var nextUrl, result, success; @@ -55,7 +53,7 @@ var requestList = function(args, cb) { function(err) { if (err) return cb(err); return cb(result[0], result[1], result[2]); - } + }, ); }; diff --git a/packages/merit-wallet-service/lib/blockchainmonitor.js b/packages/merit-wallet-service/lib/blockchainmonitor.js index 192be9df88..4703476636 100644 --- a/packages/merit-wallet-service/lib/blockchainmonitor.js +++ b/packages/merit-wallet-service/lib/blockchainmonitor.js @@ -18,7 +18,7 @@ var WalletService = require('./server'); function BlockchainMonitor() {} -BlockchainMonitor.prototype.start = function (opts, cb) { +BlockchainMonitor.prototype.start = function(opts, cb) { console.warn('**** Starting Blockchain Monitor'); opts = opts || {}; @@ -30,9 +30,9 @@ BlockchainMonitor.prototype.start = function (opts, cb) { async.parallel( [ - function (done) { + function(done) { self.explorers = {}; - _.map(['testnet'], function (network) { + _.map(['testnet'], function(network) { var explorer; if (opts.blockchainExplorers) { explorer = opts.blockchainExplorers[network]; @@ -54,25 +54,28 @@ BlockchainMonitor.prototype.start = function (opts, cb) { }); done(); }, - function (done) { + function(done) { if (opts.storage) { self.storage = opts.storage; done(); } else { self.storage = new Storage(); - self.storage.connect(opts.storageOpts, done); + self.storage.connect( + opts.storageOpts, + done, + ); } }, - function (done) { + function(done) { self.messageBroker = opts.messageBroker || new MessageBroker(opts.messageBrokerOpts); done(); }, - function (done) { + function(done) { self.lock = opts.lock || new Lock(opts.lockOpts); done(); }, ], - function (err) { + function(err) { if (err) { log.error(err); } @@ -81,16 +84,16 @@ BlockchainMonitor.prototype.start = function (opts, cb) { ); }; -BlockchainMonitor.prototype._initExplorer = function (network, explorer) { +BlockchainMonitor.prototype._initExplorer = function(network, explorer) { var self = this; var socket = explorer.initSocket(); - socket.on('connect', function () { + socket.on('connect', function() { log.info('Connected to ' + explorer.getConnectionInfo()); socket.emit('subscribe', 'inv'); }); - socket.on('connect_error', function () { + socket.on('connect_error', function() { log.error('Error connecting to ' + explorer.getConnectionInfo()); }); @@ -99,7 +102,7 @@ BlockchainMonitor.prototype._initExplorer = function (network, explorer) { socket.on('referral', _.bind(self._handleIncomingReferral, self)); }; -BlockchainMonitor.prototype._handleIncomingTx = function (network, data) { +BlockchainMonitor.prototype._handleIncomingTx = function(network, data) { const self = this; const identity = { @@ -107,20 +110,20 @@ BlockchainMonitor.prototype._handleIncomingTx = function (network, data) { txid: data.txid, blockHash: null, }; - self._uniqueMessageProcessing(identity, function () { + self._uniqueMessageProcessing(identity, function() { self._handleThirdPartyBroadcasts(data); self._handleIncomingPayments(data, network); }); }; -BlockchainMonitor.prototype._handleNewBlock = function (network, hash) { +BlockchainMonitor.prototype._handleNewBlock = function(network, hash) { const self = this; const identity = { type: 'NEW_BLOCK', blockHash: hash, txid: null, }; - self._uniqueMessageProcessing(identity, function () { + self._uniqueMessageProcessing(identity, function() { self._notifyNewBlock(network, hash); const explorer = self.explorers[network]; @@ -160,7 +163,7 @@ BlockchainMonitor.prototype._handleMinedInvites = function(network, invites) { return; } - invites.forEach((inviteTxId) => { + invites.forEach(inviteTxId => { explorer.getTransaction(inviteTxId, (err, tx) => { if (err || !tx) { console.log('Unable to fetch invite transaction: ', inviteTxId); @@ -173,7 +176,7 @@ BlockchainMonitor.prototype._handleMinedInvites = function(network, invites) { }); }; -BlockchainMonitor.prototype._handleIncomingReferral = function (data) { +BlockchainMonitor.prototype._handleIncomingReferral = function(data) { const self = this; if (!data) return; @@ -183,8 +186,8 @@ BlockchainMonitor.prototype._handleIncomingReferral = function (data) { txid: data.hash, blockHash: null, }; - self._uniqueMessageProcessing(identity, function () { - self.storage.fetchReferralByCodeHash(data.address, function (err, referral) { + self._uniqueMessageProcessing(identity, function() { + self.storage.fetchReferralByCodeHash(data.address, function(err, referral) { if (err) { log.error('Could not fetch referral from the db'); return; @@ -195,7 +198,7 @@ BlockchainMonitor.prototype._handleIncomingReferral = function (data) { return; } - self.storage.storeReferral(data, function (err) { + self.storage.storeReferral(data, function(err) { if (err) log.error('Could not store referral'); const args = data; @@ -210,10 +213,10 @@ BlockchainMonitor.prototype._handleIncomingReferral = function (data) { }); }; -BlockchainMonitor.prototype._uniqueMessageProcessing = function (identity, cb) { +BlockchainMonitor.prototype._uniqueMessageProcessing = function(identity, cb) { const self = this; - self.storage.checkKnownMessages(identity, function (err, found) { + self.storage.checkKnownMessages(identity, function(err, found) { if (err) { log.warn('Could not check message', identity, err); return; @@ -229,11 +232,11 @@ BlockchainMonitor.prototype._uniqueMessageProcessing = function (identity, cb) { }); }; -BlockchainMonitor.prototype._handleThirdPartyBroadcasts = function (data, processIt) { +BlockchainMonitor.prototype._handleThirdPartyBroadcasts = function(data, processIt) { var self = this; if (!data || !data.txid) return; - self.storage.fetchTxByHash(data.txid, function (err, txp) { + self.storage.fetchTxByHash(data.txid, function(err, txp) { if (err) { log.error('Could not fetch tx from the db'); return; @@ -263,8 +266,8 @@ BlockchainMonitor.prototype._handleThirdPartyBroadcasts = function (data, proces txp.setBroadcasted(); - self.storage.softResetTxHistoryCache(walletId, function () { - self.storage.storeTx(self.walletId, txp, function (err) { + self.storage.softResetTxHistoryCache(walletId, function() { + self.storage.storeTx(self.walletId, txp, function(err) { if (err) log.error('Could not save TX'); var args = { @@ -284,7 +287,7 @@ BlockchainMonitor.prototype._handleThirdPartyBroadcasts = function (data, proces }); }; -BlockchainMonitor.prototype._handleIncomingPayments = function (data, network) { +BlockchainMonitor.prototype._handleIncomingPayments = function(data, network) { const self = this; if (!data || !data.vout) return; @@ -292,7 +295,7 @@ BlockchainMonitor.prototype._handleIncomingPayments = function (data, network) { // Let's format the object to be easier to process below. const outs = _.reduce( data.vout, - function (acc, out, index) { + function(acc, out, index) { if (out.isChangeOutput) { return acc; } @@ -303,10 +306,10 @@ BlockchainMonitor.prototype._handleIncomingPayments = function (data, network) { return acc.concat({ address, amount, - index + index, }); }, - [] + [], ); // Let's roll up any vouts that go to the same address. @@ -316,7 +319,7 @@ BlockchainMonitor.prototype._handleIncomingPayments = function (data, network) { _.forEach(outs, out => { const oIndex = _.findIndex(filteredOutputs, { - address: out.address + address: out.address, }); if (filteredOutputs[oIndex]) { @@ -334,130 +337,130 @@ BlockchainMonitor.prototype._handleIncomingPayments = function (data, network) { async.eachSeries( filteredOutputs, - function (out, next) { - + function(out, next) { let address, isAddressConfirmed; - async.series([ - - // 1. Fetch the address from storage - (cb) => { - self.storage.fetchAddress(out.address, (err, addr) => { - if (err || !addr) { - log.error('Could not fetch addresses from the db'); - return cb(err || 'Address not found'); - } + async.series( + [ + // 1. Fetch the address from storage + cb => { + self.storage.fetchAddress(out.address, (err, addr) => { + if (err || !addr) { + log.error('Could not fetch addresses from the db'); + return cb(err || 'Address not found'); + } + + if (addr.isChange) { + log.info('Address is not registered for notifications, skipping'); + return cb('Address not registered for notifications'); + } + + address = addr; + cb(); + }); + }, - if (addr.isChange) { - log.info('Address is not registered for notifications, skipping'); - return cb('Address not registered for notifications'); + // 2. Check if the address is confirmed IF NEEDED + cb => { + // we only need to know if the address is confirmed if we're handling invites + if (!data.isInvite) { + return cb(); } - address = addr; - cb(); - }); - }, - - // 2. Check if the address is confirmed IF NEEDED - (cb) => { - - // we only need to know if the address is confirmed if we're handling invites - if (!data.isInvite) { - return cb(); - } - - explorer.getUtxos([out.address], true, (err, utxos) => { - utxos = utxos || []; - - // Check if the recipient address is unlocked; by checking if it has - // received any invites in the past. - isAddressConfirmed = utxos.some(u => u.isInvite && u.txid !== data.txid); - - cb(); - }); - }, + explorer.getUtxos([out.address], true, (err, utxos) => { + utxos = utxos || []; - // 3. Set the appropriate notification type - (cb) => { - const walletId = address.walletId; + // Check if the recipient address is unlocked; by checking if it has + // received any invites in the past. + isAddressConfirmed = utxos.some(u => u.isInvite && u.txid !== data.txid); - let notificationType = ''; + cb(); + }); + }, - if (data.isCoinbase) { - if (data.isInvite) { - notificationType = 'MinedInvite'; - } else if (out.index === 0) { - notificationType = 'MiningReward'; + // 3. Set the appropriate notification type + cb => { + const walletId = address.walletId; + + let notificationType = ''; + + if (data.isCoinbase) { + if (data.isInvite) { + notificationType = 'MinedInvite'; + } else if (out.index === 0) { + notificationType = 'MiningReward'; + } else { + notificationType = 'GrowthReward'; + } + } else if (data.isInvite) { + if (isAddressConfirmed) { + notificationType = 'IncomingInvite'; + } else { + notificationType = 'WalletUnlocked'; + } } else { - notificationType = 'GrowthReward'; + notificationType = 'IncomingTx'; } - } else if (data.isInvite) { - if (isAddressConfirmed) { - notificationType = 'IncomingInvite'; - } else { - notificationType = 'WalletUnlocked'; - } - } else { - notificationType = 'IncomingTx'; - } - log.info( - `${notificationType} for wallet ${walletId} [ ${out.amount} ${!data.isInvite ? 'micros' : 'invites'} -> ${ - out.address + log.info( + `${notificationType} for wallet ${walletId} [ ${out.amount} ${!data.isInvite ? 'micros' : 'invites'} -> ${ + out.address } ]`, - ); - - const fromTs = Date.now() - 24 * 3600 * 1000; - self.storage.fetchNotifications(walletId, null, fromTs, function (err, notifications) { - if (err) return cb(err); - - const alreadyNotified = _.some(notifications, n => - n.type === notificationType && n.data && n.data.txid === data.txid ); - if (alreadyNotified) { - log.info(`The incoming tx ${data.txid} was already notified`); - return cb(); - } - - const notification = Notification.create({ - type: notificationType, - data: { - txid: data.txid, - address: out.address, - amount: out.amount, - isInvite: data.isInvite, - }, - walletId: walletId, - }); + const fromTs = Date.now() - 24 * 3600 * 1000; + self.storage.fetchNotifications(walletId, null, fromTs, function(err, notifications) { + if (err) return cb(err); + + const alreadyNotified = _.some( + notifications, + n => n.type === notificationType && n.data && n.data.txid === data.txid, + ); + + if (alreadyNotified) { + log.info(`The incoming tx ${data.txid} was already notified`); + return cb(); + } + + const notification = Notification.create({ + type: notificationType, + data: { + txid: data.txid, + address: out.address, + amount: out.amount, + isInvite: data.isInvite, + }, + walletId: walletId, + }); - self.storage.softResetTxHistoryCache(walletId, function () { - self._updateActiveAddress(address, function () { - self._storeAndBroadcastNotification(notification, cb); + self.storage.softResetTxHistoryCache(walletId, function() { + self._updateActiveAddress(address, function() { + self._storeAndBroadcastNotification(notification, cb); + }); }); }); - }); + }, + ], + err => { + if (err) { + // If an error occurs in our async.series, + // let's send it up the chain to async.seriesEach + next(err); + } else { + next(null); + } }, - - ], (err) => { - if (err) { - // If an error occurs in our async.series, - // let's send it up the chain to async.seriesEach - next(err); - } else { - next(null); - } - }); + ); }, - err => {} + err => {}, ); }; -BlockchainMonitor.prototype._updateActiveAddress = function (address, cb) { +BlockchainMonitor.prototype._updateActiveAddress = function(address, cb) { var self = this; var addrs = [address.address]; - self.storage.storeActiveAddresses(address.walletId, addrs, function (err) { + self.storage.storeActiveAddresses(address.walletId, addrs, function(err) { if (err) { log.warn('Could not update wallet cache', err); } @@ -465,7 +468,7 @@ BlockchainMonitor.prototype._updateActiveAddress = function (address, cb) { }); }; -BlockchainMonitor.prototype._notifyNewBlock = function (network, hash) { +BlockchainMonitor.prototype._notifyNewBlock = function(network, hash) { var self = this; log.info('New ' + network + ' block: ' + hash); @@ -478,8 +481,8 @@ BlockchainMonitor.prototype._notifyNewBlock = function (network, hash) { }, }); - self.storage.softResetAllTxHistoryCache(function () { - self._storeAndBroadcastNotification(notification, function (err) { + self.storage.softResetAllTxHistoryCache(function() { + self._storeAndBroadcastNotification(notification, function(err) { return; }); }); @@ -488,9 +491,9 @@ BlockchainMonitor.prototype._notifyNewBlock = function (network, hash) { // handle txs that were confirmed (i.e. added to a block) // set these subscriptions as inactive // and send TxConfirmation notification -BlockchainMonitor.prototype._handleTxConfirmations = function (network, txids) { +BlockchainMonitor.prototype._handleTxConfirmations = function(network, txids) { const processTriggeredSubs = (subs, cb) => { - async.each(subs, function (sub, cb) { + async.each(subs, function(sub, cb) { log.info('New tx confirmation ' + sub.txid); sub.isActive = false; @@ -516,15 +519,15 @@ BlockchainMonitor.prototype._handleTxConfirmations = function (network, txids) { }); }; - this.storage.fetchActiveTxConfirmationSubs(null, function (err, subs) { + this.storage.fetchActiveTxConfirmationSubs(null, function(err, subs) { if (err) return; if (_.isEmpty(subs)) return; const indexedSubs = _.keyBy(subs, 'txid'); const triggered = []; - _.each(txids, function (txid) { + _.each(txids, function(txid) { if (indexedSubs[txid]) triggered.push(indexedSubs[txid]); }); - processTriggeredSubs(triggered, function (err) { + processTriggeredSubs(triggered, function(err) { if (err) { log.error('Could not process tx confirmations', err); } @@ -535,7 +538,7 @@ BlockchainMonitor.prototype._handleTxConfirmations = function (network, txids) { // TODO: update this method and methods to set subscriptions // to use hash or address of referral instead codeHash -BlockchainMonitor.prototype._handleReferralConfirmations = function (network, referrals) { +BlockchainMonitor.prototype._handleReferralConfirmations = function(network, referrals) { if (_.isEmpty(referrals)) { return; } @@ -549,12 +552,13 @@ BlockchainMonitor.prototype._handleReferralConfirmations = function (network, re const indexedSubs = _.keyBy(subs, 'address'); const triggered = _.reduce( referrals, - function (acc, reftx) { + function(acc, reftx) { if (!indexedSubs[reftx]) return acc; acc.push(indexedSubs[reftx]); return acc; - }, [], + }, + [], ); async.each(triggered, (sub, cb) => { @@ -582,7 +586,7 @@ BlockchainMonitor.prototype._handleReferralConfirmations = function (network, re }); }; -BlockchainMonitor.prototype._handleVaultConfirmations = function (network, txids) { +BlockchainMonitor.prototype._handleVaultConfirmations = function(network, txids) { async.each(txids, (txId, cb) => { log.info(`Checking if TX with id ${txId} is vault TX`); @@ -610,7 +614,7 @@ BlockchainMonitor.prototype._handleVaultConfirmations = function (network, txids data: result, }); - this._storeAndBroadcastNotification(notification, function () { + this._storeAndBroadcastNotification(notification, function() { log.info(`Vault confirmation with code ${txId} successfully sent`); }); }); @@ -620,7 +624,7 @@ BlockchainMonitor.prototype._handleVaultConfirmations = function (network, txids }); }; -BlockchainMonitor.prototype._storeAndBroadcastNotification = function (notification, cb) { +BlockchainMonitor.prototype._storeAndBroadcastNotification = function(notification, cb) { if (!(this.pushNotificationServiceEnabled || this.emailNotificationServiceEnabled || this.smsNotificationsEnabled)) { return cb(); } diff --git a/packages/merit-wallet-service/lib/common/constants.js b/packages/merit-wallet-service/lib/common/constants.js index a0567f5d78..293af8dafb 100644 --- a/packages/merit-wallet-service/lib/common/constants.js +++ b/packages/merit-wallet-service/lib/common/constants.js @@ -20,7 +20,7 @@ Constants.DERIVATION_STRATEGIES = { Constants.PATHS = { REQUEST_KEY: "m/1'/0", TXPROPOSAL_KEY: "m/1'/1", - REQUEST_KEY_AUTH: "m/2", // relative to BASE + REQUEST_KEY_AUTH: 'm/2', // relative to BASE }; Constants.BIP45_SHARED_INDEX = 0x80000000 - 1; diff --git a/packages/merit-wallet-service/lib/common/defaults.js b/packages/merit-wallet-service/lib/common/defaults.js index f009638720..0b2b5edba1 100644 --- a/packages/merit-wallet-service/lib/common/defaults.js +++ b/packages/merit-wallet-service/lib/common/defaults.js @@ -25,31 +25,36 @@ Defaults.MAX_MAIN_ADDRESS_GAP = 200; // TODO: should allow different gap sizes for external/internal chains Defaults.SCAN_ADDRESS_GAP = Defaults.MAX_MAIN_ADDRESS_GAP + 20; -Defaults.FEE_LEVELS = [{ - name: 'urgent', - nbBlocks: 2, - multiplier: 1.5, - defaultValue: 150000, -}, { - name: 'priority', - nbBlocks: 2, - defaultValue: 100000 -}, { - name: 'normal', - nbBlocks: 3, - defaultValue: 80000 -}, { - name: 'economy', - nbBlocks: 6, - defaultValue: 50000 -}, { - name: 'superEconomy', - nbBlocks: 24, - defaultValue: 20000 -}]; - - -Defaults.EASYRECEIVE_FEE = 20000*1; //super economy * avg easyreceive fee size TODO: calculate tx size +Defaults.FEE_LEVELS = [ + { + name: 'urgent', + nbBlocks: 2, + multiplier: 1.5, + defaultValue: 150000, + }, + { + name: 'priority', + nbBlocks: 2, + defaultValue: 100000, + }, + { + name: 'normal', + nbBlocks: 3, + defaultValue: 80000, + }, + { + name: 'economy', + nbBlocks: 6, + defaultValue: 50000, + }, + { + name: 'superEconomy', + nbBlocks: 24, + defaultValue: 20000, + }, +]; + +Defaults.EASYRECEIVE_FEE = 20000 * 1; //super economy * avg easyreceive fee size TODO: calculate tx size Defaults.DEFAULT_FEE_PER_KB = Defaults.FEE_LEVELS[1].defaultValue; @@ -92,7 +97,6 @@ Defaults.HISTORY_CACHE_ADDRESS_THRESOLD = 100; // Cache time for blockchain height (in seconds) Defaults.BLOCKHEIGHT_CACHE_TIME = 10 * 60; - // Max allowed timespan for notification queries in seconds Defaults.MAX_NOTIFICATIONS_TIMESPAN = 60 * 60 * 24 * 14; // ~ 2 weeks Defaults.NOTIFICATIONS_TIMESPAN = 60; @@ -105,7 +109,7 @@ Defaults.RateLimit = { delayAfter: 10, // begin slowing down responses after the 3rd request delayMs: 3000, // slow down subsequent responses by 3 seconds per request max: 20, // start blocking after 20 request - message: "Too many wallets created from this IP, please try again after an hour" + message: 'Too many wallets created from this IP, please try again after an hour', }, // otherPosts: { // windowMs: 60 * 60 * 1000, // 1 hour window @@ -116,6 +120,6 @@ Defaults.RateLimit = { Defaults.adjustableMaxFee = function(value) { const percents = value * Defaults.MAX_TX_FEE_PERCENT; return percents > Defaults.MAX_TX_FEE ? percents : Defaults.MAX_TX_FEE; -} +}; module.exports = Defaults; diff --git a/packages/merit-wallet-service/lib/common/utils.js b/packages/merit-wallet-service/lib/common/utils.js index 52a8e37a8b..b98edba5a4 100644 --- a/packages/merit-wallet-service/lib/common/utils.js +++ b/packages/merit-wallet-service/lib/common/utils.js @@ -25,7 +25,7 @@ Utils.getMissingFields = function(obj, args) { */ Utils.strip = function(number) { return parseFloat(number.toPrecision(12)); -} +}; /* TODO: It would be nice to be compatible with meritd signmessage. How * the hash is calculated there? */ @@ -64,7 +64,7 @@ Utils._tryImportPublicKey = function(publicKey) { publicKeyBuffer = new Buffer(publicKey, 'hex'); } return publicKeyBuffer; - } catch(e) { + } catch (e) { return false; } }; @@ -76,7 +76,7 @@ Utils._tryImportSignature = function(signature) { signatureBuffer = new Buffer(signature, 'hex'); } return secp256k1.signatureImport(signatureBuffer); - } catch(e) { + } catch (e) { return false; } }; @@ -84,7 +84,7 @@ Utils._tryImportSignature = function(signature) { Utils._tryVerifyMessage = function(hash, sig, publicKeyBuffer) { try { return secp256k1.verify(hash, sig, publicKeyBuffer); - } catch(e) { + } catch (e) { return false; } }; @@ -105,7 +105,7 @@ Utils.formatAmount = function(micros, unit, opts) { toMicros: 1, maxDecimals: 0, minDecimals: 0, - } + }, }; $.shouldBeNumber(micros); @@ -134,10 +134,12 @@ Utils.formatAmount = function(micros, unit, opts) { }; Utils.formatAmountInMrt = function(amount) { - return Utils.formatAmount(amount, 'mrt', { - minDecimals: 8, - maxDecimals: 8, - }) + 'mrt'; + return ( + Utils.formatAmount(amount, 'mrt', { + minDecimals: 8, + maxDecimals: 8, + }) + 'mrt' + ); }; Utils.formatUtxos = function(utxos) { @@ -150,11 +152,11 @@ Utils.formatUtxos = function(utxos) { }; Utils.formatRatio = function(ratio) { - return (ratio * 100.).toFixed(4) + '%'; + return (ratio * 100).toFixed(4) + '%'; }; Utils.formatSize = function(size) { - return (size / 1000.).toFixed(4) + 'kB'; + return (size / 1000).toFixed(4) + 'kB'; }; Utils.parseVersion = function(version) { @@ -176,7 +178,7 @@ Utils.parseVersion = function(version) { return v; }; -Utils.isHash = function (value) { +Utils.isHash = function(value) { return typeof value === 'string' && value.length === 64 && /^[0-9a-fA-F]+$/.test(value); }; diff --git a/packages/merit-wallet-service/lib/emailservice.js b/packages/merit-wallet-service/lib/emailservice.js index 0abe0bb075..2eab147774 100644 --- a/packages/merit-wallet-service/lib/emailservice.js +++ b/packages/merit-wallet-service/lib/emailservice.js @@ -19,50 +19,50 @@ var Model = require('./model'); var Notification = Model.Notification; var EMAIL_TYPES = { - 'NewCopayer': { + NewCopayer: { filename: 'new_copayer', notifyDoer: false, notifyOthers: true, }, - 'WalletComplete': { + WalletComplete: { filename: 'wallet_complete', notifyDoer: true, notifyOthers: true, }, - 'NewTxProposal': { + NewTxProposal: { filename: 'new_tx_proposal', notifyDoer: false, notifyOthers: true, }, - 'OutgoingTx': { + OutgoingTx: { filename: 'outgoing_tx', notifyDoer: true, notifyOthers: true, }, - 'OutgoingInviteTx': { + OutgoingInviteTx: { filename: 'outgoing_invite_tx', notifyDoer: true, notifyOthers: true, }, - 'IncomingTx': { + IncomingTx: { filename: 'incoming_tx', notifyDoer: true, notifyOthers: true, }, - 'IncomingInvite': { + IncomingInvite: { filename: 'incoming_invite', notifyDoer: true, - notifyOthers: true + notifyOthers: true, }, - 'WalletUnlocked': { + WalletUnlocked: { filename: 'wallet_unlocked', notifyDoer: true, - notifyOthers: true + notifyOthers: true, }, - 'IncomingInviteRequest': { + IncomingInviteRequest: { filename: 'incoming_invite_request', notifyDoer: true, - notifyOthers: true + notifyOthers: true, }, MiningReward: { filename: 'mining_reward', @@ -76,114 +76,122 @@ var EMAIL_TYPES = { }, MinedInvite: { notifyDoer: true, - notifyOthers: true + notifyOthers: true, }, - 'TxProposalFinallyRejected': { + TxProposalFinallyRejected: { filename: 'txp_finally_rejected', notifyDoer: false, notifyOthers: true, }, - 'TxConfirmation': { + TxConfirmation: { filename: 'tx_confirmation', notifyDoer: true, notifyOthers: false, }, - 'NewIncomingReferralTx': { + NewIncomingReferralTx: { filename: 'new_incoming_referral', notifyDoer: true, notifyOthers: true, }, - 'ReferralConfirmation': { + ReferralConfirmation: { filename: 'referral_confirmation', notifyDoer: true, notifyOthers: false, }, - 'ReferralWasRejected': { + ReferralWasRejected: { filename: 'referral_rejected', notifyDoer: true, notifyOthers: false, }, - 'IncomingPoolPayment': { + IncomingPoolPayment: { filename: 'pool_payment', notifyDoer: true, notifyOthers: false, - } + }, }; +function EmailService() {} -function EmailService() {}; - -EmailService.prototype.start = function (opts, cb) { +EmailService.prototype.start = function(opts, cb) { opts = opts || {}; function _readDirectories(basePath, cb) { - fs.readdir(basePath, function (err, files) { + fs.readdir(basePath, function(err, files) { if (err) return cb(err); - const dirs = _.reduce(files, function (dirs, file) { - if (fs.lstatSync(path.join(basePath, file)).isDirectory()) { - dirs.push(file); - } - return dirs; - }, []); + const dirs = _.reduce( + files, + function(dirs, file) { + if (fs.lstatSync(path.join(basePath, file)).isDirectory()) { + dirs.push(file); + } + return dirs; + }, + [], + ); return cb(null, dirs); }); - }; + } const self = this; self.defaultLanguage = opts.emailOpts.defaultLanguage || 'en'; self.defaultUnit = opts.emailOpts.defaultUnit || 'mrt'; - self.templatePath = path.normalize((opts.emailOpts.templatePath || (__dirname + '/templates')) + '/'); + self.templatePath = path.normalize((opts.emailOpts.templatePath || __dirname + '/templates') + '/'); self.publicTxUrlTemplate = opts.emailOpts.publicTxUrlTemplate || {}; self.subjectPrefix = opts.emailOpts.subjectPrefix || '[Wallet service]'; self.from = opts.emailOpts.from; self.types = ['plain', 'html']; - async.parallel([ - - function (done) { - _readDirectories(self.templatePath, function (err, res) { - self.availableLanguages = res; - done(err); - }); - }, - function (done) { - if (opts.storage) { - self.storage = opts.storage; + async.parallel( + [ + function(done) { + _readDirectories(self.templatePath, function(err, res) { + self.availableLanguages = res; + done(err); + }); + }, + function(done) { + if (opts.storage) { + self.storage = opts.storage; + done(); + } else { + self.storage = new Storage(); + self.storage.connect( + opts.storageOpts, + done, + ); + } + }, + function(done) { + self.messageBroker = opts.messageBroker || new MessageBroker(opts.messageBrokerOpts); + self.messageBroker.onMessage(_.bind(self.sendEmail, self)); done(); - } else { - self.storage = new Storage(); - self.storage.connect(opts.storageOpts, done); - } - }, - function (done) { - self.messageBroker = opts.messageBroker || new MessageBroker(opts.messageBrokerOpts); - self.messageBroker.onMessage(_.bind(self.sendEmail, self)); - done(); - }, - function (done) { - self.lock = opts.lock || new Lock(opts.lockOpts); - done(); - }, - function (done) { - if (opts.mailer) { - self.mailer = nodemailer.createTransport(opts.mailer); - } else { - self.mailer = nodemailer.createTransport(opts.emailOpts); + }, + function(done) { + self.lock = opts.lock || new Lock(opts.lockOpts); + done(); + }, + function(done) { + if (opts.mailer) { + self.mailer = nodemailer.createTransport(opts.mailer); + } else { + self.mailer = nodemailer.createTransport(opts.emailOpts); + } + done(); + }, + ], + function(err) { + if (err) { + log.error(err); } - done(); + return cb(err); }, - ], function (err) { - if (err) { - log.error(err); - } - return cb(err); - }); + ); }; -EmailService.prototype._compileTemplate = function (template, extension) { +EmailService.prototype._compileTemplate = function(template, extension) { var lines = template.split('\n'); if (extension == '.html') { lines.unshift(''); @@ -194,11 +202,11 @@ EmailService.prototype._compileTemplate = function (template, extension) { }; }; -EmailService.prototype._readTemplateFile = function (language, filename, cb) { +EmailService.prototype._readTemplateFile = function(language, filename, cb) { var self = this; var fullFilename = path.join(self.templatePath, language, filename); - fs.readFile(fullFilename, 'utf8', function (err, template) { + fs.readFile(fullFilename, 'utf8', function(err, template) { if (err) { return cb(new Error('Could not read template file ' + fullFilename, err)); } @@ -207,20 +215,20 @@ EmailService.prototype._readTemplateFile = function (language, filename, cb) { }; // TODO: cache for X minutes -EmailService.prototype._loadTemplate = function (emailType, recipient, extension, cb) { +EmailService.prototype._loadTemplate = function(emailType, recipient, extension, cb) { var self = this; - self._readTemplateFile(recipient.language, emailType.filename + extension, function (err, template) { + self._readTemplateFile(recipient.language, emailType.filename + extension, function(err, template) { if (err) return cb(err); return cb(null, self._compileTemplate(template, extension)); }); }; -EmailService.prototype._applyTemplate = function (template, data, cb) { +EmailService.prototype._applyTemplate = function(template, data, cb) { if (!data) return cb(new Error('Could not apply template to empty data')); var error; - var result = _.mapValues(template, function (t) { + var result = _.mapValues(template, function(t) { try { return Mustache.render(t, data); } catch (e) { @@ -232,45 +240,47 @@ EmailService.prototype._applyTemplate = function (template, data, cb) { return cb(null, result); }; -EmailService.prototype._getRecipientsList = function (notification, emailType, cb) { +EmailService.prototype._getRecipientsList = function(notification, emailType, cb) { var self = this; - self.storage.fetchPreferences(notification.walletId, null, function (err, preferences) { + self.storage.fetchPreferences(notification.walletId, null, function(err, preferences) { if (err) return cb(err); if (_.isEmpty(preferences)) return cb(null, []); var usedEmails = {}; - var recipients = _.compact(_.map(preferences, function (p) { - if (!p.email || usedEmails[p.email]) return; - - usedEmails[p.email] = true; - if (notification.creatorId == p.copayerId && !emailType.notifyDoer) return; - if (notification.creatorId != p.copayerId && !emailType.notifyOthers) return; - if (!_.includes(self.availableLanguages, p.language)) { - if (p.language) { - log.warn('Language for email "' + p.language + '" not available.'); + var recipients = _.compact( + _.map(preferences, function(p) { + if (!p.email || usedEmails[p.email]) return; + + usedEmails[p.email] = true; + if (notification.creatorId == p.copayerId && !emailType.notifyDoer) return; + if (notification.creatorId != p.copayerId && !emailType.notifyOthers) return; + if (!_.includes(self.availableLanguages, p.language)) { + if (p.language) { + log.warn('Language for email "' + p.language + '" not available.'); + } + p.language = self.defaultLanguage; } - p.language = self.defaultLanguage; - } - return { - copayerId: p.copayerId, - emailAddress: p.email, - language: p.language, - unit: p.unit || self.defaultUnit, - }; - })); + return { + copayerId: p.copayerId, + emailAddress: p.email, + language: p.language, + unit: p.unit || self.defaultUnit, + }; + }), + ); return cb(null, recipients); }); }; -EmailService.prototype._getDataForTemplate = function (notification, recipient, cb) { +EmailService.prototype._getDataForTemplate = function(notification, recipient, cb) { var self = this; // TODO: Declare these in BWU var UNIT_LABELS = { - mrt: 'MRT' + mrt: 'MRT', }; var data = _.cloneDeep(notification.data); @@ -278,14 +288,15 @@ EmailService.prototype._getDataForTemplate = function (notification, recipient, if (data.amount) { try { var unit = recipient.unit.toLowerCase(); - data.amount = data.isInvite ? data.amount + ' invites' : Utils.formatAmount(+data.amount, unit) + ' ' + - UNIT_LABELS[unit]; + data.amount = data.isInvite + ? data.amount + ' invites' + : Utils.formatAmount(+data.amount, unit) + ' ' + UNIT_LABELS[unit]; } catch (ex) { return cb(new Error('Could not format amount', ex)); } } - self.storage.fetchWallet(notification.walletId, function (err, wallet) { + self.storage.fetchWallet(notification.walletId, function(err, wallet) { if (err) return cb(err); data.walletId = wallet.id; @@ -294,7 +305,7 @@ EmailService.prototype._getDataForTemplate = function (notification, recipient, data.walletN = wallet.n; var copayer = _.find(wallet.copayers, { - id: notification.creatorId + id: notification.creatorId, }); if (copayer) { @@ -303,10 +314,10 @@ EmailService.prototype._getDataForTemplate = function (notification, recipient, } if (notification.type == 'TxProposalFinallyRejected' && data.rejectedBy) { - var rejectors = _.map(data.rejectedBy, function (copayerId) { + var rejectors = _.map(data.rejectedBy, function(copayerId) { return _.find(wallet.copayers, { - id: copayerId - }).name + id: copayerId, + }).name; }); data.rejectorsNames = rejectors.join(', '); } @@ -326,7 +337,7 @@ EmailService.prototype._getDataForTemplate = function (notification, recipient, }); }; -EmailService.prototype._send = function (email, cb) { +EmailService.prototype._send = function(email, cb) { var self = this; var mailOptions = { @@ -338,7 +349,7 @@ EmailService.prototype._send = function (email, cb) { if (email.bodyHtml) { mailOptions.html = email.bodyHtml; } - self.mailer.sendMail(mailOptions, function (err, result) { + self.mailer.sendMail(mailOptions, function(err, result) { if (err) { log.error('An error occurred when trying to send email to ' + email.to, err); return cb(err); @@ -348,58 +359,66 @@ EmailService.prototype._send = function (email, cb) { }); }; -EmailService.prototype._readAndApplyTemplates = function (notification, emailType, recipientsList, cb) { +EmailService.prototype._readAndApplyTemplates = function(notification, emailType, recipientsList, cb) { var self = this; - async.map(recipientsList, function (recipient, next) { - async.waterfall([ - function (next) { - self._getDataForTemplate(notification, recipient, next); - }, - function (data, next) { - async.map(self.types, - function (type, mapNext) { - self._loadTemplate(emailType, recipient, '.' + type, function (err, template) { - if (err && type === 'html') return mapNext(); - if (err) return mapNext(err); - - self._applyTemplate(template, data, function (err, res) { - return mapNext(err, { - [type]: res + async.map( + recipientsList, + function(recipient, next) { + async.waterfall( + [ + function(next) { + self._getDataForTemplate(notification, recipient, next); + }, + function(data, next) { + async.map( + self.types, + function(type, mapNext) { + self._loadTemplate(emailType, recipient, '.' + type, function(err, template) { + if (err && type === 'html') return mapNext(); + if (err) return mapNext(err); + + self._applyTemplate(template, data, function(err, res) { + return mapNext(err, { + [type]: res, + }); + }); }); - }); - }); + }, + function(err, res) { + return next(err, _.merge(_.compact(res))); + }, + ); }, - function (err, res) { - return next(err, _.merge(_.compact(res))); - } - ); - } - ], function (err, result) { - next(err, { - [recipient.language]: result - }); - }); - }, function (err, res) { - return cb(err, res[0]); // ToDo: get rid of this aync hell, it's not needed here and creates a lot of useless wrappers around data - }); + ], + function(err, result) { + next(err, { + [recipient.language]: result, + }); + }, + ); + }, + function(err, res) { + return cb(err, res[0]); // ToDo: get rid of this aync hell, it's not needed here and creates a lot of useless wrappers around data + }, + ); }; -EmailService.prototype._checkShouldSendEmail = function (notification, cb) { +EmailService.prototype._checkShouldSendEmail = function(notification, cb) { const self = this; if (notification.type != 'NewTxProposal') return cb(null, true); - self.storage.fetchWallet(notification.walletId, function (err, wallet) { + self.storage.fetchWallet(notification.walletId, function(err, wallet) { return cb(err, wallet.m > 1); }); }; -EmailService.prototype.sendEmail = function (notification, cb) { +EmailService.prototype.sendEmail = function(notification, cb) { const self = this; - cb = cb || function () {}; + cb = cb || function() {}; - self.storage.fetchAndLockNotificationForEmails(Notification.fromObj(notification), function (err, isLocked) { + self.storage.fetchAndLockNotificationForEmails(Notification.fromObj(notification), function(err, isLocked) { if (err) { log.warn('Notification ' + notification.id + ' could not be locked.', err); return cb(); @@ -409,7 +428,7 @@ EmailService.prototype.sendEmail = function (notification, cb) { log.warn('Notification ' + notification.id + 'is already locked, skipping.'); return cb(); } - self.storage.fetchNotification(notification, function (err, notification) { + self.storage.fetchNotification(notification, function(err, notification) { if (err) { log.warn('Could not update notification state: ' + notification.id, err); return cb(); @@ -418,75 +437,82 @@ EmailService.prototype.sendEmail = function (notification, cb) { var emailType = EMAIL_TYPES[notification.type]; if (!emailType) return cb(); - self._checkShouldSendEmail(notification, function (err, should) { + self._checkShouldSendEmail(notification, function(err, should) { if (err) return cb(err); if (!should) return cb(); - self._getRecipientsList(notification, emailType, function (err, recipientsList) { + self._getRecipientsList(notification, emailType, function(err, recipientsList) { if (_.isEmpty(recipientsList)) return cb(); // TODO: Optimize so one process does not have to wait until all others are done // Instead set a flag somewhere in the db to indicate that this process is free // to serve another request. - self.lock.runLocked('email-' + notification.id, cb, function (cb) { - self.storage.fetchEmailByNotification(notification.id, function (err, email) { + self.lock.runLocked('email-' + notification.id, cb, function(cb) { + self.storage.fetchEmailByNotification(notification.id, function(err, email) { if (err) return cb(err); if (email) return cb(); - async.waterfall([ - - function (next) { - self._readAndApplyTemplates(notification, emailType, recipientsList, - next); + async.waterfall( + [ + function(next) { + self._readAndApplyTemplates(notification, emailType, recipientsList, next); + }, + function(contents, next) { + async.map( + recipientsList, + function(recipient, next) { + var content = contents[recipient.language]; + // ToDo; improve it too, it's the result of asyncs in _readAndApplyTemplates + _.map(content, function(instance) { + var email = Model.Email.create({ + walletId: notification.walletId, + copayerId: recipient.copayerId, + from: self.from, + to: recipient.emailAddress, + subject: instance.plain.subject, + bodyPlain: instance.plain.body, + bodyHtml: instance.html ? instance.html.body : null, + notificationId: notification.id, + }); + self.storage.storeEmail(email, function(err) { + return next(err, email); + }); + }); + }, + next, + ); + }, + function(emails, next) { + async.each( + emails, + function(email, next) { + self._send(email, function(err) { + if (err) { + email.setFail(); + } else { + email.setSent(); + } + self.storage.storeEmail(email, next); + }); + }, + function(err) { + return next(); + }, + ); + }, + ], + function(err) { + if (err) { + log.error('An error ocurred generating email notification', err); + } + return cb(err); }, - function (contents, next) { - - async.map(recipientsList, function (recipient, next) { - var content = contents[recipient.language]; - // ToDo; improve it too, it's the result of asyncs in _readAndApplyTemplates - _.map(content, function (instance) { - var email = Model.Email.create({ - walletId: notification.walletId, - copayerId: recipient.copayerId, - from: self.from, - to: recipient.emailAddress, - subject: instance.plain.subject, - bodyPlain: instance.plain.body, - bodyHtml: instance.html ? instance.html.body : null, - notificationId: notification.id, - }); - self.storage.storeEmail(email, function (err) { - return next(err, email); - }); - }); - }, next); - }, - function (emails, next) { - async.each(emails, function (email, next) { - self._send(email, function (err) { - if (err) { - email.setFail(); - } else { - email.setSent(); - } - self.storage.storeEmail(email, next); - }); - }, function (err) { - return next(); - }); - }, - ], function (err) { - if (err) { - log.error('An error ocurred generating email notification', err); - } - return cb(err); - }); + ); }); }); }); }); }); - }); }; diff --git a/packages/merit-wallet-service/lib/errors/clienterror.js b/packages/merit-wallet-service/lib/errors/clienterror.js index 98f264b208..0d2e96eeb9 100644 --- a/packages/merit-wallet-service/lib/errors/clienterror.js +++ b/packages/merit-wallet-service/lib/errors/clienterror.js @@ -18,7 +18,7 @@ function ClientError() { this.message = args[1]; break; } -}; +} ClientError.prototype.toString = function() { return ''; diff --git a/packages/merit-wallet-service/lib/errors/errordefinitions.js b/packages/merit-wallet-service/lib/errors/errordefinitions.js index 53db8822d9..02fef36973 100644 --- a/packages/merit-wallet-service/lib/errors/errordefinitions.js +++ b/packages/merit-wallet-service/lib/errors/errordefinitions.js @@ -36,16 +36,18 @@ var errors = { WALLET_LOCKED: 'Wallet is locked', WALLET_NOT_COMPLETE: 'Wallet is not complete', WALLET_NOT_FOUND: 'Wallet not found', - UNLOCKED_ALREADY: "Address already unlocked.", - INVALID_PARAMETERS: "Invalid parameters sent to server.", - INVALID_REFERRAL: "Invalid referral id", - MISSING_REFERRER: "Referrer address not found", + UNLOCKED_ALREADY: 'Address already unlocked.', + INVALID_PARAMETERS: 'Invalid parameters sent to server.', + INVALID_REFERRAL: 'Invalid referral id', + MISSING_REFERRER: 'Referrer address not found', INSUFFICIENT_INVITES: 'Insufficient invites', }; -var errorObjects = _.fromPairs(_.map(errors, function(msg, code) { - return [code, new ClientError(code, msg)]; -})); +var errorObjects = _.fromPairs( + _.map(errors, function(msg, code) { + return [code, new ClientError(code, msg)]; + }), +); errorObjects.codes = _.mapValues(errors, function(v, k) { return k; diff --git a/packages/merit-wallet-service/lib/expressapp.js b/packages/merit-wallet-service/lib/expressapp.js index b125709863..435cce9c41 100644 --- a/packages/merit-wallet-service/lib/expressapp.js +++ b/packages/merit-wallet-service/lib/expressapp.js @@ -25,7 +25,7 @@ var ExpressApp = function(node) { // If merit-node isn't here, then you probably didn't run MWS from merit-node. if (!node) { - throw new Error("Merit node not detected; shutting down..."); + throw new Error('Merit node not detected; shutting down...'); } this.node = node; @@ -48,7 +48,10 @@ ExpressApp.prototype.start = function(opts, cb) { this.app.use(function(req, res, next) { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE'); - res.setHeader('Access-Control-Allow-Headers', 'x-signature,x-identity,x-session,x-client-version,x-wallet-id,X-Requested-With,Content-Type,Authorization'); + res.setHeader( + 'Access-Control-Allow-Headers', + 'x-signature,x-identity,x-session,x-client-version,x-wallet-id,X-Requested-With,Content-Type,Authorization', + ); res.setHeader('x-service-version', WalletService.getServiceVersion()); next(); }); @@ -59,12 +62,10 @@ ExpressApp.prototype.start = function(opts, cb) { return; } next(); - } + }; this.app.use(allowCORS); this.app.enable('trust proxy'); - - // handle `abort` https://nodejs.org/api/http.html#http_event_abort this.app.use(function(req, res, next) { req.on('abort', function() { @@ -73,48 +74,52 @@ ExpressApp.prototype.start = function(opts, cb) { next(); }); - var POST_LIMIT = 10 * 1024 * 1024 /* Max POST 10mb */ ; + var POST_LIMIT = 10 * 1024 * 1024 /* Max POST 10mb */; - this.app.use(bodyParser.json({ - limit: POST_LIMIT - })); + this.app.use( + bodyParser.json({ + limit: POST_LIMIT, + }), + ); if (opts.disableLogs) { log.level = 'silent'; } else { var morgan = require('morgan'); morgan.token('walletId', function getId(req) { - return req.walletId + return req.walletId; }); morgan.token('copayerId', function getId(req) { - return req.copayerId + return req.copayerId; }); - var logFormat = ':remote-addr :date[iso] ":method :url" :status :res[content-length] :req[content-length] :response-time ":user-agent" :walletId :copayerId'; + var logFormat = + ':remote-addr :date[iso] ":method :url" :status :res[content-length] :req[content-length] :response-time ":user-agent" :walletId :copayerId'; var logOpts = { skip: function(req, res) { if (res.statusCode != 200) return false; return req.path.indexOf('/notifications/') >= 0; - } + }, }; this.app.use(morgan(logFormat, logOpts)); } var router = express.Router(); - function returnError(err, res, req) { if (err instanceof WalletService.ClientError) { // Return a 401 if the unlock code is not valid, or the request is broadly unauthorized. - var status = (err.code == 'NOT_AUTHORIZED') ? 401 : 400; - if (!opts.disableLogs) - log.info('Client Err: ' + status + ' ' + req.url + ' ' + JSON.stringify(err)); - - return res.status(status).json({ - code: err.code, - message: err.message, - }).end(); + var status = err.code == 'NOT_AUTHORIZED' ? 401 : 400; + if (!opts.disableLogs) log.info('Client Err: ' + status + ' ' + req.url + ' ' + JSON.stringify(err)); + + return res + .status(status) + .json({ + code: err.code, + message: err.message, + }) + .end(); } else { var code = 500, message; @@ -125,18 +130,20 @@ ExpressApp.prototype.start = function(opts, cb) { var m = message || err.toString(); - if (!opts.disableLogs) - log.error(req.url + ' :' + code + ':' + m); + if (!opts.disableLogs) log.error(req.url + ' :' + code + ':' + m); - return res.status(code || 500).json({ - error: m, - }).end(); + return res + .status(code || 500) + .json({ + error: m, + }) + .end(); } - }; + } function logDeprecated(req) { log.warn('DEPRECATED', req.method, req.url, '(' + req.header('x-client-version') + ')'); - }; + } function getCredentials(req) { var identity = req.header('x-identity'); @@ -147,14 +154,14 @@ ExpressApp.prototype.start = function(opts, cb) { signature: req.header('x-signature'), session: req.header('x-session'), }; - }; + } function getServer(req, res) { var opts = { clientVersion: req.header('x-client-version'), }; return WalletService.getInstance(opts); - }; + } function getServerWithAuth(req, res, opts, cb) { if (_.isFunction(opts)) { @@ -165,16 +172,18 @@ ExpressApp.prototype.start = function(opts, cb) { var util = require('util'); - var credentials = getCredentials(req); if (!credentials) { - log.debug("NO CREDENTIALS SUPPLIED TO MWS"); - return returnError(new WalletService.ClientError({ - code: 'NOT_AUTHORIZED' - }), res, req); + log.debug('NO CREDENTIALS SUPPLIED TO MWS'); + return returnError( + new WalletService.ClientError({ + code: 'NOT_AUTHORIZED', + }), + res, + req, + ); } - var auth = { copayerId: credentials.copayerId, message: req.method.toLowerCase() + '|' + req.url + '|' + JSON.stringify(req.body), @@ -187,7 +196,7 @@ ExpressApp.prototype.start = function(opts, cb) { } WalletService.getInstanceWithAuth(auth, function(err, server) { if (err) { - log.debug("Could not get Wallet Instance with Auth"); + log.debug('Could not get Wallet Instance with Auth'); return returnError(err, res, req); } @@ -197,23 +206,25 @@ ExpressApp.prototype.start = function(opts, cb) { return cb(server); }); - }; - + } var createWalletLimiter; if (Defaults.RateLimit.createWallet && !opts.ignoreRateLimiter) { - log.info('', 'Limiting wallet creation per IP: %d req/h', (Defaults.RateLimit.createWallet.max / Defaults.RateLimit.createWallet.windowMs * 60 * 60 * 1000).toFixed(2)) + log.info( + '', + 'Limiting wallet creation per IP: %d req/h', + ((Defaults.RateLimit.createWallet.max / Defaults.RateLimit.createWallet.windowMs) * 60 * 60 * 1000).toFixed(2), + ); createWalletLimiter = new RateLimit(Defaults.RateLimit.createWallet); // router.use(/\/v\d+\/wallets\/$/, createWalletLimiter) } else { log.info('', 'Running without wallet creation rate limiting'); createWalletLimiter = function(req, res, next) { - next() + next(); }; } - router.post('/v1/wallets/', createWalletLimiter, function(req, res) { var server; try { @@ -227,7 +238,7 @@ ExpressApp.prototype.start = function(opts, cb) { server.createWallet(req.body, function(err, walletId) { if (err) return returnError(err, res, req); res.json({ - walletId + walletId, }); }); }); @@ -242,11 +253,10 @@ ExpressApp.prototype.start = function(opts, cb) { server.recreateWallet(req.body, function(err, walletId, parentAddress) { if (err) return returnError(err, res, req); - res.json({walletId, parentAddress}); + res.json({ walletId, parentAddress }); }); }); - router.put('/v1/copayers/:id/', function(req, res) { req.body.copayerId = req.params['id']; var server; @@ -290,26 +300,31 @@ ExpressApp.prototype.start = function(opts, cb) { }); router.get('/v1/wallets/:identifier/', function(req, res) { - getServerWithAuth(req, res, { - onlySupportStaff: true - }, function(server) { - var opts = { - identifier: req.params['identifier'], - }; - server.getWalletFromIdentifier(opts, function(err, wallet) { - if (err) return returnError(err, res, req); - if (!wallet) return res.end(); - - server.walletId = wallet.id; - var opts = {}; - if (req.query.includeExtendedInfo == '1') opts.includeExtendedInfo = true; - if (req.query.twoStep == '1') opts.twoStep = true; - server.getStatus(opts, function(err, status) { + getServerWithAuth( + req, + res, + { + onlySupportStaff: true, + }, + function(server) { + var opts = { + identifier: req.params['identifier'], + }; + server.getWalletFromIdentifier(opts, function(err, wallet) { if (err) return returnError(err, res, req); - res.json(status); + if (!wallet) return res.end(); + + server.walletId = wallet.id; + var opts = {}; + if (req.query.includeExtendedInfo == '1') opts.includeExtendedInfo = true; + if (req.query.twoStep == '1') opts.twoStep = true; + server.getStatus(opts, function(err, status) { + if (err) return returnError(err, res, req); + res.json(status); + }); }); - }); - }); + }, + ); }); router.get('/v1/preferences/', function(req, res) { @@ -372,7 +387,7 @@ ExpressApp.prototype.start = function(opts, cb) { getServerWithAuth(req, res, function(server) { var opts = {}; if (req.query.limit) opts.limit = +req.query.limit; - opts.reverse = (req.query.reverse == '1'); + opts.reverse = req.query.reverse == '1'; server.getMainAddresses(opts, function(err, addresses) { if (err) return returnError(err, res, req); @@ -512,7 +527,7 @@ ExpressApp.prototype.start = function(opts, cb) { server.removePendingTx(req.body, function(err) { if (err) return returnError(err, res, req); res.json({ - success: true + success: true, }); res.end(); }); @@ -530,15 +545,14 @@ ExpressApp.prototype.start = function(opts, cb) { }); }); - router.get('/v1/unlockrequests', function(req, res) { - getServerWithAuth(req, res, function(server) { - server.getUnlockRequests(opts, function(err, refs) { - if (err) return returnError(err, res, req); - res.json(refs); - res.end(); - }); + getServerWithAuth(req, res, function(server) { + server.getUnlockRequests(opts, function(err, refs) { + if (err) return returnError(err, res, req); + res.json(refs); + res.end(); }); + }); }); router.get('/v1/txhistory/', function(req, res) { @@ -617,20 +631,27 @@ ExpressApp.prototype.start = function(opts, cb) { }); router.get('/v1/notifications/', function(req, res) { - getServerWithAuth(req, res, { - allowSession: true, - }, function(server) { - var timeSpan = req.query.timeSpan ? Math.min(+req.query.timeSpan || 0, Defaults.MAX_NOTIFICATIONS_TIMESPAN) : Defaults.NOTIFICATIONS_TIMESPAN; - var opts = { - minTs: +Date.now() - (timeSpan * 1000), - notificationId: req.query.notificationId, - }; - - server.getNotifications(opts, function(err, notifications) { - if (err) return returnError(err, res, req); - res.json(notifications); - }); - }); + getServerWithAuth( + req, + res, + { + allowSession: true, + }, + function(server) { + var timeSpan = req.query.timeSpan + ? Math.min(+req.query.timeSpan || 0, Defaults.MAX_NOTIFICATIONS_TIMESPAN) + : Defaults.NOTIFICATIONS_TIMESPAN; + var opts = { + minTs: +Date.now() - timeSpan * 1000, + notificationId: req.query.notificationId, + }; + + server.getNotifications(opts, function(err, notifications) { + if (err) return returnError(err, res, req); + res.json(notifications); + }); + }, + ); }); router.get('/v1/txnotes/:txid', function(req, res) { @@ -695,7 +716,6 @@ ExpressApp.prototype.start = function(opts, cb) { }); }); - router.delete('/v1/pushnotifications/subscriptions/:token', function(req, res) { var opts = { token: req.params['token'], @@ -760,12 +780,12 @@ ExpressApp.prototype.start = function(opts, cb) { * EasySend Routes */ router.get('/v1/easyreceive/validate/:scriptId', function(req, res) { - var scriptId = req.params['scriptId'] + var scriptId = req.params['scriptId']; var server = getServer(req, res); server.validateEasyScript(scriptId, function(err, response) { if (err) { - log.debug("Called Validate EasyReceipt in MWS: ", err); + log.debug('Called Validate EasyReceipt in MWS: ', err); return returnError(err, res, req); } res.json(response); @@ -811,14 +831,14 @@ ExpressApp.prototype.start = function(opts, cb) { router.get('/v1/communityinfo', (req, res) => { const opts = { network: req.query.network || 'testnet', - keys: req.query.keys.split(',') + keys: req.query.keys.split(','), }; getServerWithAuth(req, res, server => { server.getCommunityInfo(opts, (err, response) => { if (err) return returnError(err, res, req); res.json(response); - }) + }); }); }); @@ -859,10 +879,10 @@ ExpressApp.prototype.start = function(opts, cb) { router.post('/v1/vaults/:id/update_info', function(req, res) { getServerWithAuth(req, res, function(server) { - server.updateVaultInfo(req.body, function(err, vault) { - if (err) return returnError(err, res, req); - res.json(vault); - }); + server.updateVaultInfo(req.body, function(err, vault) { + if (err) return returnError(err, res, req); + res.json(vault); + }); }); }); @@ -883,13 +903,12 @@ ExpressApp.prototype.start = function(opts, cb) { }); }); - router.get('/v1/vaults/:vaultId', function(req, res) { getServerWithAuth(req, res, function(server) { - server.getVault(req.params.vaultId, function(err, vault) { - if (err) return returnError(err, res, req); - res.json(vault); - }); + server.getVault(req.params.vaultId, function(err, vault) { + if (err) return returnError(err, res, req); + res.json(vault); + }); }); }); @@ -929,72 +948,74 @@ ExpressApp.prototype.start = function(opts, cb) { }); router.get('/v1/rates', function(req, res) { - const dummy = [{"code": "USD", "name": "US Dollar", "rate": 0}]; + const dummy = [{ code: 'USD', name: 'US Dollar', rate: 0 }]; res.json(dummy); res.end(); }); router.post('/v1/globalsend/register', function(req, res) { - getServerWithAuth(req, res, function(server) { - server.registerGlobalSend(req.body, function(err) { - if (err) return returnError(err, res, req); - res.json('ok').end(); - }); + getServerWithAuth(req, res, function(server) { + server.registerGlobalSend(req.body, function(err) { + if (err) return returnError(err, res, req); + res.json('ok').end(); }); + }); }); router.post('/v1/globalsend/cancel', function(req, res) { - getServerWithAuth(req, res, function(server) { - server.cancelGlobalSend(req.body, function(err) { - if (err) return returnError(err, res, req); - res.json('ok').end(); - }); + getServerWithAuth(req, res, function(server) { + server.cancelGlobalSend(req.body, function(err) { + if (err) return returnError(err, res, req); + res.json('ok').end(); }); + }); }); router.get('/v1/globalsend/history', function(req, res) { - getServerWithAuth(req, res, function(server) { - server.getGlobalSends(req, function(err, links) { - if (err) return returnError(err, res, req); - res.json(links).end(); - }); + getServerWithAuth(req, res, function(server) { + server.getGlobalSends(req, function(err, links) { + if (err) return returnError(err, res, req); + res.json(links).end(); }); + }); }); - router.post('/v1/globalsend', (req, res) => { getServerWithAuth(req, res, () => { - request({ - method: 'POST', - uri: opts.meritMessagingUrl + '/globalsend', - json: req.body - }, (err, response) => { - if (!err && parseInt(response.statusCode) === 200) { - res.send(); - } else { - res.status(400).send(); - } - }); + request( + { + method: 'POST', + uri: opts.meritMessagingUrl + '/globalsend', + json: req.body, + }, + (err, response) => { + if (!err && parseInt(response.statusCode) === 200) { + res.send(); + } else { + res.status(400).send(); + } + }, + ); }); }); router.get('/v1/community/rank/', function(req, res) { getServerWithAuth(req, res, function(server) { - server.getCommunityRank(function(err, txs) { - if (err) return returnError(err, res, req); - res.json(txs); - res.end(); - }); + server.getCommunityRank(function(err, txs) { + if (err) return returnError(err, res, req); + res.json(txs); + res.end(); + }); }); }); router.post('/v1/community/ranks/', function(req, res) { getServerWithAuth(req, res, function(server) { - server.getCommunityRanks(req.body.addresses, function(err, txs) { - if (err) return returnError(err, res, req); - res.json(txs); - res.end(); - }); + server.getCommunityRanks(req.body.addresses, function(err, txs) { + if (err) return returnError(err, res, req); + res.json(txs); + res.end(); + }); }); }); @@ -1013,7 +1034,6 @@ ExpressApp.prototype.start = function(opts, cb) { // This allows us to access Meritd directly from MWS. opts.node = this.node; WalletService.initialize(opts, cb); - }; module.exports = ExpressApp; diff --git a/packages/merit-wallet-service/lib/fiatrateproviders/bitpay.js b/packages/merit-wallet-service/lib/fiatrateproviders/bitpay.js index 6c22874554..b47a48f751 100644 --- a/packages/merit-wallet-service/lib/fiatrateproviders/bitpay.js +++ b/packages/merit-wallet-service/lib/fiatrateproviders/bitpay.js @@ -4,13 +4,15 @@ var provider = { name: 'BitPay', url: 'https://bitpay.com/api/rates/', parseFn: function(raw) { - var rates = _.compact(_.map(raw, function(d) { - if (!d.code || !d.rate) return null; - return { - code: d.code, - value: d.rate, - }; - })); + var rates = _.compact( + _.map(raw, function(d) { + if (!d.code || !d.rate) return null; + return { + code: d.code, + value: d.rate, + }; + }), + ); return rates; }, }; diff --git a/packages/merit-wallet-service/lib/fiatrateproviders/bitstamp.js b/packages/merit-wallet-service/lib/fiatrateproviders/bitstamp.js index dab4775a08..e840e19157 100644 --- a/packages/merit-wallet-service/lib/fiatrateproviders/bitstamp.js +++ b/packages/merit-wallet-service/lib/fiatrateproviders/bitstamp.js @@ -2,11 +2,13 @@ var provider = { name: 'Bitstamp', url: 'https://www.bitstamp.net/api/ticker/', parseFn: function(raw) { - return [{ - code: 'USD', - value: parseFloat(raw.last) - }]; - } + return [ + { + code: 'USD', + value: parseFloat(raw.last), + }, + ]; + }, }; module.exports = provider; diff --git a/packages/merit-wallet-service/lib/fiatrateproviders/index.js b/packages/merit-wallet-service/lib/fiatrateproviders/index.js index d361b21093..7c9f5a1dc4 100644 --- a/packages/merit-wallet-service/lib/fiatrateproviders/index.js +++ b/packages/merit-wallet-service/lib/fiatrateproviders/index.js @@ -1,6 +1,6 @@ var Providers = { BitPay: require('./bitpay'), Bitstamp: require('./bitstamp'), -} +}; module.exports = Providers; diff --git a/packages/merit-wallet-service/lib/fiatrateservice.js b/packages/merit-wallet-service/lib/fiatrateservice.js index 0db7e85708..3c7d7ad167 100644 --- a/packages/merit-wallet-service/lib/fiatrateservice.js +++ b/packages/merit-wallet-service/lib/fiatrateservice.js @@ -13,7 +13,7 @@ var Defaults = Common.Defaults; var Storage = require('./storage'); var Model = require('./model'); -function FiatRateService() {}; +function FiatRateService() {} FiatRateService.prototype.init = function(opts, cb) { var self = this; @@ -23,23 +23,28 @@ FiatRateService.prototype.init = function(opts, cb) { self.request = opts.request || request; self.defaultProvider = opts.defaultProvider || Defaults.FIAT_RATE_PROVIDER; - async.parallel([ - - function(done) { - if (opts.storage) { - self.storage = opts.storage; - done(); - } else { - self.storage = new Storage(); - self.storage.connect(opts.storageOpts, done); + async.parallel( + [ + function(done) { + if (opts.storage) { + self.storage = opts.storage; + done(); + } else { + self.storage = new Storage(); + self.storage.connect( + opts.storageOpts, + done, + ); + } + }, + ], + function(err) { + if (err) { + log.error(err); } + return cb(err); }, - ], function(err) { - if (err) { - log.error(err); - } - return cb(err); - }); + ); }; FiatRateService.prototype.startCron = function(opts, cb) { @@ -65,46 +70,52 @@ FiatRateService.prototype._fetch = function(cb) { cb = cb || function() {}; - async.each(self.providers, function(provider, next) { - self._retrieve(provider, function(err, res) { - if (err) { - log.warn('Error retrieving data for ' + provider.name, err); - return next(); - } - self.storage.storeFiatRate(provider.name, res, function(err) { + async.each( + self.providers, + function(provider, next) { + self._retrieve(provider, function(err, res) { if (err) { - log.warn('Error storing data for ' + provider.name, err); + log.warn('Error retrieving data for ' + provider.name, err); + return next(); } - return next(); + self.storage.storeFiatRate(provider.name, res, function(err) { + if (err) { + log.warn('Error storing data for ' + provider.name, err); + } + return next(); + }); }); - }); - }, cb); + }, + cb, + ); }; FiatRateService.prototype._retrieve = function(provider, cb) { var self = this; log.debug('Fetching data for ' + provider.name); - self.request.get({ - url: provider.url, - json: true, - }, function(err, res, body) { - if (err || !body) { - return cb(err); - } + self.request.get( + { + url: provider.url, + json: true, + }, + function(err, res, body) { + if (err || !body) { + return cb(err); + } - log.debug('Data for ' + provider.name + ' fetched successfully'); + log.debug('Data for ' + provider.name + ' fetched successfully'); - if (!provider.parseFn) { - return cb(new Error('No parse function for provider ' + provider.name)); - } - var rates = provider.parseFn(body); + if (!provider.parseFn) { + return cb(new Error('No parse function for provider ' + provider.name)); + } + var rates = provider.parseFn(body); - return cb(null, rates); - }); + return cb(null, rates); + }, + ); }; - FiatRateService.prototype.getRate = function(opts, cb) { var self = this; @@ -114,25 +125,28 @@ FiatRateService.prototype.getRate = function(opts, cb) { var now = Date.now(); var provider = opts.provider || self.defaultProvider; - var ts = (_.isNumber(opts.ts) || _.isArray(opts.ts)) ? opts.ts : now; - - async.map([].concat(ts), function(ts, cb) { - self.storage.fetchFiatRate(provider, opts.code, ts, function(err, rate) { - if (err) return cb(err); - if (rate && (ts - rate.ts) > Defaults.FIAT_RATE_MAX_LOOK_BACK_TIME * 60 * 1000) rate = null; - - return cb(null, { - ts: +ts, - rate: rate ? rate.value : undefined, - fetchedOn: rate ? rate.ts : undefined, + var ts = _.isNumber(opts.ts) || _.isArray(opts.ts) ? opts.ts : now; + + async.map( + [].concat(ts), + function(ts, cb) { + self.storage.fetchFiatRate(provider, opts.code, ts, function(err, rate) { + if (err) return cb(err); + if (rate && ts - rate.ts > Defaults.FIAT_RATE_MAX_LOOK_BACK_TIME * 60 * 1000) rate = null; + + return cb(null, { + ts: +ts, + rate: rate ? rate.value : undefined, + fetchedOn: rate ? rate.ts : undefined, + }); }); - }); - }, function(err, res) { - if (err) return cb(err); - if (!_.isArray(ts)) res = res[0]; - return cb(null, res); - }); + }, + function(err, res) { + if (err) return cb(err); + if (!_.isArray(ts)) res = res[0]; + return cb(null, res); + }, + ); }; - module.exports = FiatRateService; diff --git a/packages/merit-wallet-service/lib/locallock.js b/packages/merit-wallet-service/lib/locallock.js index 3cf871778e..090005f8aa 100644 --- a/packages/merit-wallet-service/lib/locallock.js +++ b/packages/merit-wallet-service/lib/locallock.js @@ -3,7 +3,7 @@ var $ = require('preconditions').singleton(); function Lock() { this.tasks = {}; -}; +} Lock.prototype._release = function(token, task) { if (!task.running) return; @@ -15,9 +15,12 @@ Lock.prototype._release = function(token, task) { Lock.prototype._runOne = function(token) { var self = this; - if (_.some(self.tasks[token], { - running: true - })) return; + if ( + _.some(self.tasks[token], { + running: true, + }) + ) + return; var task = _.head(self.tasks[token]); if (!task) return; diff --git a/packages/merit-wallet-service/lib/lock.js b/packages/merit-wallet-service/lib/lock.js index 0dd2e6994c..26ad60d399 100644 --- a/packages/merit-wallet-service/lib/lock.js +++ b/packages/merit-wallet-service/lib/lock.js @@ -25,7 +25,7 @@ function Lock(opts) { } else { this.lock = new LocalLock(); } -}; +} Lock.prototype.runLocked = function(token, cb, task) { $.shouldBeDefined(token); diff --git a/packages/merit-wallet-service/lib/messagebroker.js b/packages/merit-wallet-service/lib/messagebroker.js index e41da43ac7..ce9ca9863f 100644 --- a/packages/merit-wallet-service/lib/messagebroker.js +++ b/packages/merit-wallet-service/lib/messagebroker.js @@ -27,7 +27,7 @@ function MessageBroker(opts) { log.info('Using message broker server at ' + url); } -}; +} nodeutil.inherits(MessageBroker, events.EventEmitter); diff --git a/packages/merit-wallet-service/lib/model/address.js b/packages/merit-wallet-service/lib/model/address.js index 104051bd41..3336d82a37 100644 --- a/packages/merit-wallet-service/lib/model/address.js +++ b/packages/merit-wallet-service/lib/model/address.js @@ -6,7 +6,7 @@ var _ = require('lodash'); var meritcore = require('meritcore-lib'); var Constants = require('../common/constants'); -function Address() {}; +function Address() {} Address.create = function(opts) { opts = opts || {}; @@ -81,12 +81,13 @@ Address._deriveAddress = function(scriptType, publicKeyRing, path, m, network) { Address.derive = function(walletId, scriptType, publicKeyRing, path, m, network, isChange) { var raw = Address._deriveAddress(scriptType, publicKeyRing, path, m, network); - return Address.create(_.extend(raw, { - walletId: walletId, - type: scriptType, - isChange: isChange - })); + return Address.create( + _.extend(raw, { + walletId: walletId, + type: scriptType, + isChange: isChange, + }), + ); }; - module.exports = Address; diff --git a/packages/merit-wallet-service/lib/model/addressmanager.js b/packages/merit-wallet-service/lib/model/addressmanager.js index db19075514..e625de85af 100644 --- a/packages/merit-wallet-service/lib/model/addressmanager.js +++ b/packages/merit-wallet-service/lib/model/addressmanager.js @@ -4,7 +4,7 @@ var $ = require('preconditions').singleton(); var Meritcore = require('meritcore-lib'); var Constants = require('../common/constants'); -function AddressManager() {}; +function AddressManager() {} AddressManager.create = function(opts) { opts = opts || {}; @@ -56,10 +56,13 @@ AddressManager.prototype.rewindIndex = function(isChange, n) { }; AddressManager.prototype.getCurrentAddressPath = function(isChange) { - return 'm/' + + return ( + 'm/' + (this.derivationStrategy == Constants.DERIVATION_STRATEGIES.BIP45 ? this.copayerIndex + '/' : '') + - (isChange ? 1 : 0) + '/' + - (isChange ? this.changeAddressIndex : this.receiveAddressIndex); + (isChange ? 1 : 0) + + '/' + + (isChange ? this.changeAddressIndex : this.receiveAddressIndex) + ); }; AddressManager.prototype.getNewAddressPath = function(isChange) { diff --git a/packages/merit-wallet-service/lib/model/copayer.js b/packages/merit-wallet-service/lib/model/copayer.js index d6e107836f..b92cb08c15 100644 --- a/packages/merit-wallet-service/lib/model/copayer.js +++ b/packages/merit-wallet-service/lib/model/copayer.js @@ -12,7 +12,7 @@ var Meritcore = require('meritcore-lib'); var Constants = require('../common/constants'); -function Copayer() {}; +function Copayer() {} Copayer._xPubToCopayerId = function(xpub) { var hash = sjcl.hash.sha256.hash(xpub); @@ -36,10 +36,12 @@ Copayer.create = function(opts) { x.name = opts.name; x.requestPubKey = opts.requestPubKey; x.signature = opts.signature; - x.requestPubKeys = [{ - key: opts.requestPubKey, - signature: opts.signature, - }]; + x.requestPubKeys = [ + { + key: opts.requestPubKey, + signature: opts.signature, + }, + ]; var derivationStrategy = opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP45; if (AddressManager.supportsCopayerBranches(derivationStrategy)) { @@ -66,10 +68,12 @@ Copayer.fromObj = function(obj) { x.signature = obj.signature; if (parseInt(x.version) == 1) { - x.requestPubKeys = [{ - key: x.requestPubKey, - signature: x.signature, - }]; + x.requestPubKeys = [ + { + key: x.requestPubKey, + signature: x.signature, + }, + ]; x.version = 2; } else { x.requestPubKeys = obj.requestPubKeys; @@ -87,7 +91,15 @@ Copayer.prototype.createAddress = function(wallet, isChange) { $.checkState(wallet.isComplete()); var path = this.addressManager.getNewAddressPath(isChange); - var address = Address.derive(wallet.id, wallet.addressType, wallet.publicKeyRing, path, wallet.m, wallet.network, isChange); + var address = Address.derive( + wallet.id, + wallet.addressType, + wallet.publicKeyRing, + path, + wallet.m, + wallet.network, + isChange, + ); return address; }; diff --git a/packages/merit-wallet-service/lib/model/email.js b/packages/merit-wallet-service/lib/model/email.js index eb47469702..5a4538b7a4 100644 --- a/packages/merit-wallet-service/lib/model/email.js +++ b/packages/merit-wallet-service/lib/model/email.js @@ -3,7 +3,7 @@ var _ = require('lodash'); var Uuid = require('uuid'); -function Email() {}; +function Email() {} Email.create = function(opts) { opts = opts || {}; @@ -69,5 +69,4 @@ Email.prototype.setFail = function() { this._logAttempt('fail'); }; - module.exports = Email; diff --git a/packages/merit-wallet-service/lib/model/notification.js b/packages/merit-wallet-service/lib/model/notification.js index d5ec415de5..43d7979f9b 100644 --- a/packages/merit-wallet-service/lib/model/notification.js +++ b/packages/merit-wallet-service/lib/model/notification.js @@ -23,7 +23,7 @@ var Uuid = require('uuid'); * to notify the user * */ -function Notification() {}; +function Notification() {} Notification.create = function(opts) { opts = opts || {}; @@ -51,8 +51,7 @@ Notification.fromObj = function(obj) { x.version = obj.version; x.createdOn = obj.createdOn; x.id = obj.id; - x.type = obj.type, - x.data = obj.data; + (x.type = obj.type), (x.data = obj.data); x.walletId = obj.walletId; x.creatorId = obj.creatorId; x.lockedForPushNotifications = obj.lockedForPushNotifications ? obj.lockedForPushNotifications : false; diff --git a/packages/merit-wallet-service/lib/model/preferences.js b/packages/merit-wallet-service/lib/model/preferences.js index 9a4451ddd0..9221a98381 100644 --- a/packages/merit-wallet-service/lib/model/preferences.js +++ b/packages/merit-wallet-service/lib/model/preferences.js @@ -1,6 +1,6 @@ 'use strict'; -function Preferences() {}; +function Preferences() {} Preferences.create = function(opts) { opts = opts || {}; @@ -30,5 +30,4 @@ Preferences.fromObj = function(obj) { return x; }; - module.exports = Preferences; diff --git a/packages/merit-wallet-service/lib/model/pushnotificationsub.js b/packages/merit-wallet-service/lib/model/pushnotificationsub.js index c0ee377480..ef42034938 100644 --- a/packages/merit-wallet-service/lib/model/pushnotificationsub.js +++ b/packages/merit-wallet-service/lib/model/pushnotificationsub.js @@ -1,6 +1,6 @@ 'use strict'; -function PushNotificationSub() {}; +function PushNotificationSub() {} PushNotificationSub.create = function(opts) { opts = opts || {}; @@ -28,5 +28,4 @@ PushNotificationSub.fromObj = function(obj) { return x; }; - module.exports = PushNotificationSub; diff --git a/packages/merit-wallet-service/lib/model/referraltxconfirmationsub.js b/packages/merit-wallet-service/lib/model/referraltxconfirmationsub.js index c5b388155b..4a259936ff 100644 --- a/packages/merit-wallet-service/lib/model/referraltxconfirmationsub.js +++ b/packages/merit-wallet-service/lib/model/referraltxconfirmationsub.js @@ -1,8 +1,8 @@ 'use strict'; -function ReferralTxConfirmationSub() {}; +function ReferralTxConfirmationSub() {} -ReferralTxConfirmationSub.create = function (opts) { +ReferralTxConfirmationSub.create = function(opts) { opts = opts || {}; const rtx = new ReferralTxConfirmationSub(); @@ -18,7 +18,7 @@ ReferralTxConfirmationSub.create = function (opts) { return rtx; }; -ReferralTxConfirmationSub.fromObj = function (obj) { +ReferralTxConfirmationSub.fromObj = function(obj) { const rtx = new ReferralTxConfirmationSub(); rtx.version = obj.version; diff --git a/packages/merit-wallet-service/lib/model/session.js b/packages/merit-wallet-service/lib/model/session.js index 32183ee73c..a545e3fbaf 100644 --- a/packages/merit-wallet-service/lib/model/session.js +++ b/packages/merit-wallet-service/lib/model/session.js @@ -3,7 +3,7 @@ var Uuid = require('uuid'); var Defaults = require('../common/defaults'); -function Session() {}; +function Session() {} Session.create = function(opts) { opts = opts || {}; @@ -41,7 +41,7 @@ Session.prototype.toObject = function() { Session.prototype.isValid = function() { var now = Math.floor(Date.now() / 1000); - return (now - this.updatedOn) <= Defaults.SESSION_EXPIRATION; + return now - this.updatedOn <= Defaults.SESSION_EXPIRATION; }; Session.prototype.touch = function() { diff --git a/packages/merit-wallet-service/lib/model/txconfirmationsub.js b/packages/merit-wallet-service/lib/model/txconfirmationsub.js index ed07f820d6..d7e2a267bb 100644 --- a/packages/merit-wallet-service/lib/model/txconfirmationsub.js +++ b/packages/merit-wallet-service/lib/model/txconfirmationsub.js @@ -1,6 +1,6 @@ 'use strict'; -function TxConfirmationSub() {}; +function TxConfirmationSub() {} TxConfirmationSub.create = function(opts) { opts = opts || {}; @@ -28,5 +28,4 @@ TxConfirmationSub.fromObj = function(obj) { return x; }; - module.exports = TxConfirmationSub; diff --git a/packages/merit-wallet-service/lib/model/txnote.js b/packages/merit-wallet-service/lib/model/txnote.js index 2d333453ed..4de6324aaf 100644 --- a/packages/merit-wallet-service/lib/model/txnote.js +++ b/packages/merit-wallet-service/lib/model/txnote.js @@ -1,7 +1,7 @@ var _ = require('lodash'); var Uuid = require('uuid'); -function TxNote() {}; +function TxNote() {} TxNote.create = function(opts) { opts = opts || {}; diff --git a/packages/merit-wallet-service/lib/model/txproposal.js b/packages/merit-wallet-service/lib/model/txproposal.js index 3218488420..30a5ff2ba2 100644 --- a/packages/merit-wallet-service/lib/model/txproposal.js +++ b/packages/merit-wallet-service/lib/model/txproposal.js @@ -15,7 +15,7 @@ var Defaults = Common.Defaults; var TxProposalAction = require('./txproposalaction'); -function TxProposal() {}; +function TxProposal() {} TxProposal.create = function(opts) { opts = opts || {}; @@ -43,8 +43,7 @@ TxProposal.create = function(opts) { x.walletM = opts.walletM; x.walletN = opts.walletN; x.requiredSignatures = x.walletM; - x.requiredRejections = Math.min(x.walletM, x.walletN - x.walletM + 1), - x.status = 'temporary'; + (x.requiredRejections = Math.min(x.walletM, x.walletN - x.walletM + 1)), (x.status = 'temporary'); x.actions = []; x.feeLevel = opts.feeLevel; x.feePerKb = opts.feePerKb; @@ -159,10 +158,12 @@ TxProposal.prototype._buildTx = function() { _.each(self.outputs, function(o) { $.checkState(o.script || o.toAddress, 'Output should have either toAddress or script specified'); if (o.script) { - t.addOutput(new Meritcore.Transaction.Output({ - script: o.script, - micros: o.amount - })); + t.addOutput( + new Meritcore.Transaction.Output({ + script: o.script, + micros: o.amount, + }), + ); } else { t.to(o.toAddress, o.amount); } @@ -191,18 +192,21 @@ TxProposal.prototype._buildTx = function() { var totalInputs = _.sumBy(t.inputs, 'output.micros'); var totalOutputs = _.sumBy(t.outputs, 'micros'); - $.checkState(totalInputs > 0 && totalOutputs > 0 && totalInputs >= totalOutputs, - 'Value in outputs is greater than value in inputs'); - $.checkState(totalInputs - totalOutputs <= Defaults.adjustableMaxFee(totalOutputs), - 'Maximum fee is higher than safe boundary (0.01%): ' + ((totalInputs - totalOutputs) / totalOutputs)); + $.checkState( + totalInputs > 0 && totalOutputs > 0 && totalInputs >= totalOutputs, + 'Value in outputs is greater than value in inputs', + ); + $.checkState( + totalInputs - totalOutputs <= Defaults.adjustableMaxFee(totalOutputs), + 'Maximum fee is higher than safe boundary (0.01%): ' + (totalInputs - totalOutputs) / totalOutputs, + ); return t; }; - TxProposal.prototype._getCurrentSignatures = function() { var acceptedActions = _.filter(this.actions, { - type: 'accept' + type: 'accept', }); return _.map(acceptedActions, function(x) { @@ -269,12 +273,12 @@ TxProposal.prototype.getEstimatedSize = function() { TxProposal.prototype.getEstimatedFee = function() { if (this.isInvite) return 0; $.checkState(_.isNumber(this.feePerKb)); - var fee = this.feePerKb * this.getEstimatedSize() / 1000; + var fee = (this.feePerKb * this.getEstimatedSize()) / 1000; return parseInt(fee.toFixed(0)); }; TxProposal.prototype.estimateFee = function() { - this.fee = this.isInvite? 0 : this.getEstimatedFee(); + this.fee = this.isInvite ? 0 : this.getEstimatedFee(); }; /** @@ -295,7 +299,6 @@ TxProposal.prototype.getActors = function() { return _.map(this.actions, 'copayerId'); }; - /** * getApprovers * @@ -304,8 +307,10 @@ TxProposal.prototype.getActors = function() { TxProposal.prototype.getApprovers = function() { return _.map( _.filter(this.actions, { - type: 'accept' - }), 'copayerId'); + type: 'accept', + }), + 'copayerId', + ); }; /** @@ -316,7 +321,7 @@ TxProposal.prototype.getApprovers = function() { */ TxProposal.prototype.getActionBy = function(copayerId) { return _.find(this.actions, { - copayerId: copayerId + copayerId: copayerId, }); }; @@ -335,8 +340,7 @@ TxProposal.prototype.addAction = function(copayerId, type, comment, signatures, TxProposal.prototype._addSignaturesToMeritcoreTx = function(tx, signatures, xpub) { var self = this; - if (signatures.length != this.inputs.length) - throw new Error('Number of signatures does not match number of inputs'); + if (signatures.length != this.inputs.length) throw new Error('Number of signatures does not match number of inputs'); var i = 0, x = new Meritcore.HDPublicKey(xpub); @@ -354,14 +358,12 @@ TxProposal.prototype._addSignaturesToMeritcoreTx = function(tx, signatures, xpub }; tx.inputs[i].addSignature(tx, s); i++; - } catch (e) {}; + } catch (e) {} }); - if (i != tx.inputs.length) - throw new Error('Wrong signatures'); + if (i != tx.inputs.length) throw new Error('Wrong signatures'); }; - TxProposal.prototype.sign = function(copayerId, signatures, xpub) { try { // Tests signatures are OK diff --git a/packages/merit-wallet-service/lib/model/txproposalaction.js b/packages/merit-wallet-service/lib/model/txproposalaction.js index bbe090fbfc..279c163f88 100644 --- a/packages/merit-wallet-service/lib/model/txproposalaction.js +++ b/packages/merit-wallet-service/lib/model/txproposalaction.js @@ -1,6 +1,6 @@ 'use strict'; -function TxProposalAction() {}; +function TxProposalAction() {} TxProposalAction.create = function(opts) { opts = opts || {}; diff --git a/packages/merit-wallet-service/lib/model/vaulttxconfirmationsub.js b/packages/merit-wallet-service/lib/model/vaulttxconfirmationsub.js index 3e2ee5d924..1614d11f68 100644 --- a/packages/merit-wallet-service/lib/model/vaulttxconfirmationsub.js +++ b/packages/merit-wallet-service/lib/model/vaulttxconfirmationsub.js @@ -1,8 +1,8 @@ 'use strict'; -function VaultTxConfirmationSub() {}; +function VaultTxConfirmationSub() {} -VaultTxConfirmationSub.create = function (opts) { +VaultTxConfirmationSub.create = function(opts) { opts = opts || {}; const rtx = new VaultTxConfirmationSub(); @@ -18,7 +18,7 @@ VaultTxConfirmationSub.create = function (opts) { return rtx; }; -VaultTxConfirmationSub.fromObj = function (obj) { +VaultTxConfirmationSub.fromObj = function(obj) { const rtx = new VaultTxConfirmationSub(); rtx.version = obj.version; diff --git a/packages/merit-wallet-service/lib/model/wallet.js b/packages/merit-wallet-service/lib/model/wallet.js index 5797688d40..28fea884c3 100644 --- a/packages/merit-wallet-service/lib/model/wallet.js +++ b/packages/merit-wallet-service/lib/model/wallet.js @@ -11,7 +11,7 @@ var AddressManager = require('./addressmanager'); var Constants = require('../common/constants'); -function Wallet() {}; +function Wallet() {} Wallet.create = function(opts) { opts = opts || {}; @@ -94,14 +94,13 @@ Wallet.getMaxRequiredCopayers = function(totalCopayers) { }; Wallet.verifyCopayerLimits = function(m, n) { - return (n >= 1 && n <= 15) && (m >= 1 && m <= n); + return n >= 1 && n <= 15 && (m >= 1 && m <= n); }; Wallet.prototype.isShared = function() { return this.n > 1; }; - Wallet.prototype._updatePublicKeyRing = function() { this.publicKeyRing = _.map(this.copayers, function(copayer) { return _.pick(copayer, ['xPubKey', 'requestPubKey']); @@ -109,7 +108,6 @@ Wallet.prototype._updatePublicKeyRing = function() { }; Wallet.prototype.addCopayer = function(copayer) { - this.copayers.push(copayer); if (this.copayers.length < this.n) return; @@ -134,7 +132,7 @@ Wallet.prototype.addCopayerRequestKey = function(copayerId, requestPubKey, signa Wallet.prototype.getCopayer = function(copayerId) { return _.find(this.copayers, { - id: copayerId + id: copayerId, }); }; @@ -160,5 +158,4 @@ Wallet.prototype.createAddress = function(isChange) { return address; }; - module.exports = Wallet; diff --git a/packages/merit-wallet-service/lib/notificationbroadcaster.js b/packages/merit-wallet-service/lib/notificationbroadcaster.js index 4357d3d599..10dcc790bb 100644 --- a/packages/merit-wallet-service/lib/notificationbroadcaster.js +++ b/packages/merit-wallet-service/lib/notificationbroadcaster.js @@ -6,7 +6,7 @@ var inherits = require('inherits'); var events = require('events'); var nodeutil = require('util'); -function NotificationBroadcaster() {}; +function NotificationBroadcaster() {} nodeutil.inherits(NotificationBroadcaster, events.EventEmitter); diff --git a/packages/merit-wallet-service/lib/pushnotificationsservice.js b/packages/merit-wallet-service/lib/pushnotificationsservice.js index ec42ddef1e..8135fdd8b4 100644 --- a/packages/merit-wallet-service/lib/pushnotificationsservice.js +++ b/packages/merit-wallet-service/lib/pushnotificationsservice.js @@ -17,147 +17,154 @@ var Notification = Model.Notification; log.debug = log.verbose; var PUSHNOTIFICATIONS_TYPES = { - 'NewCopayer': { + NewCopayer: { filename: 'new_copayer', }, - 'WalletComplete': { + WalletComplete: { filename: 'wallet_complete', }, - 'NewTxProposal': { + NewTxProposal: { filename: 'incoming_tx_proposal', }, - 'OutgoingTx': { + OutgoingTx: { filename: 'outgoing_tx', }, - 'OutgoingInviteTx': { + OutgoingInviteTx: { filename: 'outgoing_invite_tx', }, - 'IncomingTx': { + IncomingTx: { filename: 'incoming_tx', }, - 'IncomingInvite': { - filename: 'incoming_invite' + IncomingInvite: { + filename: 'incoming_invite', }, - 'WalletUnlocked': { - filename: 'wallet_unlocked' + WalletUnlocked: { + filename: 'wallet_unlocked', }, - 'IncomingInviteRequest': { - filename: 'incoming_invite_request' + IncomingInviteRequest: { + filename: 'incoming_invite_request', }, MiningReward: { - filename: 'mining_reward' + filename: 'mining_reward', }, GrowthReward: { - filename: 'growth_reward' + filename: 'growth_reward', }, - 'TxProposalFinallyRejected': { + TxProposalFinallyRejected: { filename: 'txp_finally_rejected', }, - 'TxConfirmation': { + TxConfirmation: { filename: 'tx_confirmation', notifyCreatorOnly: true, }, - 'NewIncomingReferralTx': { + NewIncomingReferralTx: { filename: 'incoming_referral', notifyCreatorOnly: true, }, - 'ReferralConfirmation': { + ReferralConfirmation: { filename: 'referral_confirmation', notifyCreatorOnly: true, }, - 'ReferralWasRejected': { + ReferralWasRejected: { filename: 'referral_rejected', notifyCreatorOnly: true, }, - 'NewIncomingVaultTx': { + NewIncomingVaultTx: { filename: 'incoming_vault', notifyCreatorOnly: true, }, - 'VaultConfirmation': { + VaultConfirmation: { filename: 'vault_confirmation', notifyCreatorOnly: true, }, - 'VaultWasRejected': { + VaultWasRejected: { filename: 'vault_rejected', notifyCreatorOnly: true, }, - 'IncomingPoolPayment': { + IncomingPoolPayment: { filename: 'pool_payment', }, MinedInvite: { filename: 'mined_invite', }, - }; -function PushNotificationsService() {}; +function PushNotificationsService() {} -PushNotificationsService.prototype.start = function (opts, cb) { - console.warn("**** Starting Push Notification Service"); +PushNotificationsService.prototype.start = function(opts, cb) { + console.warn('**** Starting Push Notification Service'); var self = this; opts = opts || {}; self.request = opts.request || defaultRequest; function _readDirectories(basePath, cb) { - fs.readdir(basePath, function (err, files) { + fs.readdir(basePath, function(err, files) { if (err) return cb(err); - const dirs = _.reduce(files, function (dirs, file) { - if (fs.lstatSync(path.join(basePath, file)).isDirectory()) { - dirs.push(file); - } - return dirs; - }, []); + const dirs = _.reduce( + files, + function(dirs, file) { + if (fs.lstatSync(path.join(basePath, file)).isDirectory()) { + dirs.push(file); + } + return dirs; + }, + [], + ); return cb(null, dirs); }); - }; + } - self.templatePath = path.normalize((opts.pushNotificationsOpts.templatePath || (__dirname + '/templates')) + '/'); + self.templatePath = path.normalize((opts.pushNotificationsOpts.templatePath || __dirname + '/templates') + '/'); self.defaultLanguage = opts.pushNotificationsOpts.defaultLanguage || 'en'; self.defaultUnit = opts.pushNotificationsOpts.defaultUnit || 'mrt'; self.subjectPrefix = opts.pushNotificationsOpts.subjectPrefix || ''; self.pushServerUrl = opts.pushNotificationsOpts.pushServerUrl; self.authorizationKey = opts.pushNotificationsOpts.authorizationKey; - if (!self.authorizationKey) return cb(new Error('Missing authorizationKey attribute in configuration.')) - - async.parallel([ + if (!self.authorizationKey) return cb(new Error('Missing authorizationKey attribute in configuration.')); - function (done) { - _readDirectories(self.templatePath, function (err, res) { - self.availableLanguages = res; - done(err); - }); - }, - function (done) { - if (opts.storage) { - self.storage = opts.storage; + async.parallel( + [ + function(done) { + _readDirectories(self.templatePath, function(err, res) { + self.availableLanguages = res; + done(err); + }); + }, + function(done) { + if (opts.storage) { + self.storage = opts.storage; + done(); + } else { + self.storage = new Storage(); + self.storage.connect( + opts.storageOpts, + done, + ); + } + }, + function(done) { + self.messageBroker = opts.messageBroker || new MessageBroker(opts.messageBrokerOpts); + self.messageBroker.onMessage(_.bind(self._sendPushNotifications, self)); done(); - } else { - self.storage = new Storage(); - self.storage.connect(opts.storageOpts, done); + }, + ], + function(err) { + if (err) { + log.error(err); } + return cb(err); }, - function (done) { - self.messageBroker = opts.messageBroker || new MessageBroker(opts.messageBrokerOpts); - self.messageBroker.onMessage(_.bind(self._sendPushNotifications, self)); - done(); - }, - ], function (err) { - if (err) { - log.error(err); - } - return cb(err); - }); - + ); }; -PushNotificationsService.prototype._sendPushNotifications = function (notification, cb) { +PushNotificationsService.prototype._sendPushNotifications = function(notification, cb) { const self = this; - cb = cb || function () {}; + cb = cb || function() {}; - self.storage.fetchAndLockNotificationForPushes(Notification.fromObj(notification), function (err, isLocked) { + self.storage.fetchAndLockNotificationForPushes(Notification.fromObj(notification), function(err, isLocked) { if (err) { log.warn('Notification ' + notification.id + ' could not be locked.', err); return cb(); @@ -167,7 +174,7 @@ PushNotificationsService.prototype._sendPushNotifications = function (notificati log.warn('Notification ' + notification.id + 'is already locked, skipping.'); return cb(); } - self.storage.fetchNotification(notification, function (err, notification) { + self.storage.fetchNotification(notification, function(err, notification) { if (err) { log.warn('Could not update notification state: ' + notification.id, err); return cb(); @@ -179,195 +186,219 @@ PushNotificationsService.prototype._sendPushNotifications = function (notificati log.debug('Notification received: ' + notification.type); log.debug(JSON.stringify(notification)); - self._checkShouldSendNotif(notification, function (err, should) { + self._checkShouldSendNotif(notification, function(err, should) { if (err) return cb(err); log.debug('Should send notification: ', should); if (!should) return cb(); - self._getRecipientsList(notification, notifType, function (err, recipientsList) { + self._getRecipientsList(notification, notifType, function(err, recipientsList) { if (err) return cb(err); if (!recipientsList) { log.warn('Recipient list is empty, skipping notifications.'); return cb(); } - async.waterfall([ - - function (next) { - self._readAndApplyTemplates(notification, notifType, recipientsList, next); - }, - function (contents, next) { - async.map(recipientsList, function (recipient, next) { - const content = contents[recipient.language]; - - self.storage.fetchPushNotificationSubs(recipient.copayerId, function (err, - subs) { - if (err) return next(err); - - const notifications = _.map(subs, function (sub) { - const pushNotification = { - to: sub.token, - priority: 'high', - notification: { - title: content.plain.subject, - body: content.plain.body, - sound: "default", - click_action: "FCM_PLUGIN_ACTIVITY", - icon: "fcm_push_icon", - }, - data: { - id: notification.id, - walletId: notification.walletId, - copayerId: recipient.copayerId, - type: notification.type, - ...notification.data, - timestamp: Date.now() + async.waterfall( + [ + function(next) { + self._readAndApplyTemplates(notification, notifType, recipientsList, next); + }, + function(contents, next) { + async.map( + recipientsList, + function(recipient, next) { + const content = contents[recipient.language]; + + self.storage.fetchPushNotificationSubs(recipient.copayerId, function(err, subs) { + if (err) return next(err); + + const notifications = _.map(subs, function(sub) { + const pushNotification = { + to: sub.token, + priority: 'high', + notification: { + title: content.plain.subject, + body: content.plain.body, + sound: 'default', + click_action: 'FCM_PLUGIN_ACTIVITY', + icon: 'fcm_push_icon', + }, + data: { + id: notification.id, + walletId: notification.walletId, + copayerId: recipient.copayerId, + type: notification.type, + ...notification.data, + timestamp: Date.now(), + }, + }; + + if (sub.platform === 'web') { + pushNotification.notification.click_action = sub.packageName; + pushNotification.notification.icon = '/assets/v1/icons/merit-512x512.png'; + } else if (sub.packageName) { + pushNotification.restricted_package_name = sub.packageName; + } + + return pushNotification; + }); + return next(err, notifications); + }); + }, + function(err, allNotifications) { + if (err) return next(err); + return next(null, _.flatten(allNotifications)); + }, + ); + }, + function(notifications, next) { + async.each( + notifications, + function(notification, next) { + self._makeRequest(notification, function(err, response) { + if (err) log.error('Could not send push notification: ', err); + if (response) { + log.debug('Request status: ', response.statusCode); + log.debug('Request message: ', response.statusMessage); + log.debug('Request body: ', response.request.body); } - }; - - if (sub.platform === 'web') { - pushNotification.notification.click_action = sub.packageName; - pushNotification.notification.icon = - '/assets/v1/icons/merit-512x512.png'; - } else if (sub.packageName) { - pushNotification.restricted_package_name = sub.packageName; - } - - return pushNotification; - }); - return next(err, notifications); - }); - }, function (err, allNotifications) { - if (err) return next(err); - return next(null, _.flatten(allNotifications)); - }); - }, - function (notifications, next) { - async.each(notifications, - function (notification, next) { - self._makeRequest(notification, function (err, response) { - if (err) log.error("Could not send push notification: ", err); - if (response) { - log.debug('Request status: ', response.statusCode); - log.debug('Request message: ', response.statusMessage); - log.debug('Request body: ', response.request.body); - } - next(); - }); - }, - function (err) { - return next(err); - } - ); + next(); + }); + }, + function(err) { + return next(err); + }, + ); + }, + ], + function(err) { + if (err) { + log.error('An error occurred generating notification', err); + } + return cb(err); }, - ], function (err) { - if (err) { - log.error('An error occurred generating notification', err); - } - return cb(err); - }); + ); }); }); }); }); }; -PushNotificationsService.prototype._checkShouldSendNotif = function (notification, cb) { +PushNotificationsService.prototype._checkShouldSendNotif = function(notification, cb) { var self = this; if (notification.type != 'NewTxProposal') return cb(null, true); - self.storage.fetchWallet(notification.walletId, function (err, wallet) { + self.storage.fetchWallet(notification.walletId, function(err, wallet) { return cb(err, wallet && wallet.m > 1); }); }; -PushNotificationsService.prototype._getRecipientsList = function (notification, notificationType, cb) { +PushNotificationsService.prototype._getRecipientsList = function(notification, notificationType, cb) { var self = this; - self.storage.fetchWallet(notification.walletId, function (err, wallet) { + self.storage.fetchWallet(notification.walletId, function(err, wallet) { if (err) return cb(err); if (!wallet) return cb(); - self.storage.fetchPreferences(notification.walletId, null, function (err, preferences) { - + self.storage.fetchPreferences(notification.walletId, null, function(err, preferences) { if (err) log.error(err); if (_.isEmpty(preferences)) preferences = []; - var recipientPreferences = _.compact(_.map(preferences, function (p) { - if (!_.includes(self.availableLanguages, p.language)) { - if (p.language) - log.warn('Language for notifications "' + p.language + '" not available.'); - p.language = self.defaultLanguage; - } + var recipientPreferences = _.compact( + _.map(preferences, function(p) { + if (!_.includes(self.availableLanguages, p.language)) { + if (p.language) log.warn('Language for notifications "' + p.language + '" not available.'); + p.language = self.defaultLanguage; + } - return { - copayerId: p.copayerId, - language: p.language, - unit: p.unit, - }; - })); + return { + copayerId: p.copayerId, + language: p.language, + unit: p.unit, + }; + }), + ); recipientPreferences = _.keyBy(recipientPreferences, 'copayerId'); - var recipientsList = _.compact(_.map(wallet.copayers, function (copayer) { - if ((copayer.id == notification.creatorId && notificationType.notifyCreatorOnly) || - (copayer.id != notification.creatorId && !notificationType.notifyCreatorOnly)) { - var p = recipientPreferences[copayer.id] || {}; - return { - copayerId: copayer.id, - language: p.language || self.defaultLanguage, - unit: p.unit || self.defaultUnit, + var recipientsList = _.compact( + _.map(wallet.copayers, function(copayer) { + if ( + (copayer.id == notification.creatorId && notificationType.notifyCreatorOnly) || + (copayer.id != notification.creatorId && !notificationType.notifyCreatorOnly) + ) { + var p = recipientPreferences[copayer.id] || {}; + return { + copayerId: copayer.id, + language: p.language || self.defaultLanguage, + unit: p.unit || self.defaultUnit, + }; } - } - })); + }), + ); return cb(null, recipientsList); }); }); }; -PushNotificationsService.prototype._readAndApplyTemplates = function (notification, notifType, recipientsList, cb) { +PushNotificationsService.prototype._readAndApplyTemplates = function(notification, notifType, recipientsList, cb) { var self = this; var util = require('util'); - async.map(recipientsList, function (recipient, next) { - async.waterfall([ + async.map( + recipientsList, + function(recipient, next) { + async.waterfall( + [ + function(next) { + self._getDataForTemplate(notification, recipient, next); + }, + function(data, next) { + async.map( + ['plain', 'html'], + function(type, next) { + self._loadTemplate(notifType, recipient, '.' + type, function(err, template) { + if (err && type == 'html') return next(); + if (err) return next(err); - function (next) { - self._getDataForTemplate(notification, recipient, next); - }, - function (data, next) { - async.map(['plain', 'html'], function (type, next) { - self._loadTemplate(notifType, recipient, '.' + type, function (err, template) { - if (err && type == 'html') return next(); - if (err) return next(err); - - self._applyTemplate(template, data, function (err, res) { - return next(err, [type, res]); - }); - }); - }, function (err, res) { - return next(err, _.fromPairs(_.filter(res, function (pair) { - return (!_.isEmpty(pair)); - }))); - }); - }, - function (result, next) { - next(null, result); - }, - ], function (err, res) { - next(err, [recipient.language, res]); - }); - }, function (err, res) { - return cb(err, _.fromPairs(res)); - }); + self._applyTemplate(template, data, function(err, res) { + return next(err, [type, res]); + }); + }); + }, + function(err, res) { + return next( + err, + _.fromPairs( + _.filter(res, function(pair) { + return !_.isEmpty(pair); + }), + ), + ); + }, + ); + }, + function(result, next) { + next(null, result); + }, + ], + function(err, res) { + next(err, [recipient.language, res]); + }, + ); + }, + function(err, res) { + return cb(err, _.fromPairs(res)); + }, + ); }; -PushNotificationsService.prototype._getDataForTemplate = function (notification, recipient, cb) { +PushNotificationsService.prototype._getDataForTemplate = function(notification, recipient, cb) { var self = this; var UNIT_LABELS = { - mrt: 'MRT' + mrt: 'MRT', }; var data = _.cloneDeep(notification.data); @@ -381,7 +412,7 @@ PushNotificationsService.prototype._getDataForTemplate = function (notification, } } - self.storage.fetchWallet(notification.walletId, function (err, wallet) { + self.storage.fetchWallet(notification.walletId, function(err, wallet) { if (err || !wallet) return cb(err); data.walletId = wallet.id; @@ -390,7 +421,7 @@ PushNotificationsService.prototype._getDataForTemplate = function (notification, data.walletN = wallet.n; var copayer = _.find(wallet.copayers, { - id: notification.creatorId + id: notification.creatorId, }); if (copayer) { @@ -399,10 +430,10 @@ PushNotificationsService.prototype._getDataForTemplate = function (notification, } if (notification.type == 'TxProposalFinallyRejected' && data.rejectedBy) { - var rejectors = _.map(data.rejectedBy, function (copayerId) { + var rejectors = _.map(data.rejectedBy, function(copayerId) { return _.find(wallet.copayers, { - id: copayerId - }).name + id: copayerId, + }).name; }); data.rejectorsNames = rejectors.join(', '); } @@ -411,11 +442,11 @@ PushNotificationsService.prototype._getDataForTemplate = function (notification, }); }; -PushNotificationsService.prototype._applyTemplate = function (template, data, cb) { +PushNotificationsService.prototype._applyTemplate = function(template, data, cb) { if (!data) return cb(new Error('Could not apply template to empty data')); var error; - var result = _.mapValues(template, function (t) { + var result = _.mapValues(template, function(t) { try { return Mustache.render(t, data); } catch (e) { @@ -428,20 +459,20 @@ PushNotificationsService.prototype._applyTemplate = function (template, data, cb return cb(null, result); }; -PushNotificationsService.prototype._loadTemplate = function (notifType, recipient, extension, cb) { +PushNotificationsService.prototype._loadTemplate = function(notifType, recipient, extension, cb) { var self = this; - self._readTemplateFile(recipient.language, notifType.filename + extension, function (err, template) { + self._readTemplateFile(recipient.language, notifType.filename + extension, function(err, template) { if (err) return cb(err); return cb(null, self._compileTemplate(template, extension)); }); }; -PushNotificationsService.prototype._readTemplateFile = function (language, filename, cb) { +PushNotificationsService.prototype._readTemplateFile = function(language, filename, cb) { var self = this; var fullFilename = path.join(self.templatePath, language, filename); - fs.readFile(fullFilename, 'utf8', function (err, template) { + fs.readFile(fullFilename, 'utf8', function(err, template) { if (err) { return cb(new Error('Could not read template file ' + fullFilename, err)); } @@ -449,7 +480,7 @@ PushNotificationsService.prototype._readTemplateFile = function (language, filen }); }; -PushNotificationsService.prototype._compileTemplate = function (template, extension) { +PushNotificationsService.prototype._compileTemplate = function(template, extension) { var lines = template.split('\n'); if (extension == '.html') { lines.unshift(''); @@ -460,19 +491,22 @@ PushNotificationsService.prototype._compileTemplate = function (template, extens }; }; -PushNotificationsService.prototype._makeRequest = function (opts, cb) { +PushNotificationsService.prototype._makeRequest = function(opts, cb) { var self = this; - self.request({ - url: self.pushServerUrl + '/send', - method: 'POST', - json: true, - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'key=' + self.authorizationKey, + self.request( + { + url: self.pushServerUrl + '/send', + method: 'POST', + json: true, + headers: { + 'Content-Type': 'application/json', + Authorization: 'key=' + self.authorizationKey, + }, + body: opts, }, - body: opts, - }, cb); + cb, + ); }; module.exports = PushNotificationsService; diff --git a/packages/merit-wallet-service/lib/server.js b/packages/merit-wallet-service/lib/server.js index ab12d686e3..692c1ecb9c 100644 --- a/packages/merit-wallet-service/lib/server.js +++ b/packages/merit-wallet-service/lib/server.js @@ -102,11 +102,14 @@ WalletService.initialize = function(opts, cb) { return cb(); } else { var newStorage = new Storage(); - newStorage.connect(opts.storageOpts, function(err) { - if (err) return cb(err); - storage = newStorage; - return cb(); - }); + newStorage.connect( + opts.storageOpts, + function(err) { + if (err) return cb(err); + storage = newStorage; + return cb(); + }, + ); } } @@ -154,7 +157,7 @@ WalletService.initialize = function(opts, cb) { } initialized = true; return cb(); - } + }, ); }; @@ -300,7 +303,7 @@ WalletService.prototype.login = function(opts, cb) { if (!session) return cb(new Error('Could not get current session for this copayer')); return cb(null, session.id); - } + }, ); }; @@ -390,7 +393,7 @@ WalletService.prototype.recreateWallet = function(opts, cb) { err => { const newWalletId = newWallet ? newWallet.id : null; return cb(err, newWalletId, parentAddress); - } + }, ); }; @@ -489,7 +492,7 @@ WalletService.prototype.createWallet = function(opts, cb) { creatorId: parentAddress.walletId, }, null, - acb + acb, ); }); }); @@ -498,7 +501,7 @@ WalletService.prototype.createWallet = function(opts, cb) { function(err) { var newWalletId = newWallet ? newWallet.id : null; return cb(err, newWalletId); - } + }, ); }; @@ -630,7 +633,7 @@ WalletService.prototype.getWalletFromIdentifier = function(opts, cb) { }, function(err) { nextNetwork(err, !!walletId); - } + }, ); }); }, @@ -640,9 +643,9 @@ WalletService.prototype.getWalletFromIdentifier = function(opts, cb) { return self.storage.fetchWallet(walletId, cb); } cb(); - } + }, ); - } + }, ); }; @@ -725,7 +728,7 @@ WalletService.prototype.sendReferral = function(rawReferral, cb) { } return localMeritDaemon.sendReferral(rawReferral, cb); - } + }, ); }); }); @@ -840,7 +843,7 @@ WalletService.prototype.getStatus = function(opts, cb) { }, 0); return cb(null, status); - } + }, ); }); }; @@ -932,7 +935,7 @@ WalletService.prototype._notifyTxProposalAction = function(type, txp, extraArgs, amount: txp.getTotalAmount(), message: txp.message, }, - extraArgs + extraArgs, ); self._notify(type, data, {}, cb); @@ -974,7 +977,7 @@ WalletService.prototype._addCopayerToWallet = function(wallet, opts, cb) { copayerId: copayer.id, copayerName: copayer.name, }, - next + next, ); }, function(next) { @@ -987,7 +990,7 @@ WalletService.prototype._addCopayerToWallet = function(wallet, opts, cb) { { isGlobal: true, }, - next + next, ); } else { next(); @@ -1008,7 +1011,7 @@ WalletService.prototype._addCopayerToWallet = function(wallet, opts, cb) { copayerId: copayer.id, wallet: wallet, }); - } + }, ); }); }); @@ -1127,14 +1130,14 @@ WalletService.prototype.joinWallet = function(opts, cb) { // New client trying to join legacy wallet if (wallet.derivationStrategy == Constants.DERIVATION_STRATEGIES.BIP45) { return cb( - new ClientError('The wallet you are trying to join was created with an older version of the client app.') + new ClientError('The wallet you are trying to join was created with an older version of the client app.'), ); } } else { // Legacy client trying to join new wallet if (wallet.derivationStrategy == Constants.DERIVATION_STRATEGIES.BIP44) { return cb( - new ClientError(Errors.codes.UPGRADE_NEEDED, 'To join this wallet you need to upgrade your client app.') + new ClientError(Errors.codes.UPGRADE_NEEDED, 'To join this wallet you need to upgrade your client app.'), ); } } @@ -1246,7 +1249,7 @@ WalletService.prototype._canCreateAddress = function(ignoreMaxGap, cb) { _.reject(addresses, { isChange: true, }), - Defaults.MAX_MAIN_ADDRESS_GAP + Defaults.MAX_MAIN_ADDRESS_GAP, ); if ( latestAddresses.length < Defaults.MAX_MAIN_ADDRESS_GAP || @@ -1280,7 +1283,7 @@ WalletService.prototype._canCreateAddress = function(ignoreMaxGap, cb) { self.storage.storeAddress(address, function(err) { return cb(err, true); }); - } + }, ); }); }; @@ -1310,7 +1313,7 @@ WalletService.prototype.createAddress = function(opts, cb) { }, function() { return cb(null, address); - } + }, ); }); } @@ -1521,7 +1524,7 @@ WalletService.prototype._getUtxosForCurrentWallet = function(addresses, invites, }); return next(); - } + }, ); }, function(next) { @@ -1540,7 +1543,7 @@ WalletService.prototype._getUtxosForCurrentWallet = function(addresses, invites, ], function(err) { return cb(err, allUtxos); - } + }, ); }; @@ -1601,7 +1604,7 @@ WalletService.prototype._totalizeUtxos = function(utxos) { totalPendingCoinbaseAmount: 0, totalConfirmedAmount: 0, lockedConfirmedAmount: 0, - } + }, ); balance.availableAmount = balance.totalAmount - balance.lockedAmount; balance.availableConfirmedAmount = balance.totalConfirmedAmount - balance.lockedConfirmedAmount; @@ -1609,11 +1612,11 @@ WalletService.prototype._totalizeUtxos = function(utxos) { $.checkArgument(balance.availableAmount <= balance.totalAmount, 'Total amount must be greater than available'); $.checkArgument( balance.lockedConfirmedAmount <= balance.lockedAmount, - 'Total lockedAmount must be greater than lockedConfirmedAmount' + 'Total lockedAmount must be greater than lockedConfirmedAmount', ); $.checkArgument( balance.totalConfirmedAmount <= balance.totalAmount, - 'Total totalAmount must be greater than totalConfirmedAmount' + 'Total totalAmount must be greater than totalConfirmedAmount', ); $.checkArgument(balance.lockedAmount <= balance.totalAmount, 'Total amount must be greater than lockedAmount'); @@ -1630,8 +1633,11 @@ WalletService.prototype._getBalanceFromAddresses = async function(addresses, inv try { var addressStrs = _.map(addresses, 'address'); - let balance = await localMeritDaemon.getAddressBalance( - addressStrs, {invites: invites, detailed: true, mempool: true}); + let balance = await localMeritDaemon.getAddressBalance(addressStrs, { + invites: invites, + detailed: true, + mempool: true, + }); balance.lockedAmount = 0; balance.lockedConfirmedAmount = 0; @@ -1639,10 +1645,9 @@ WalletService.prototype._getBalanceFromAddresses = async function(addresses, inv balance.availableConfirmedAmount = balance.totalConfirmedAmount; return cb(null, balance); - } catch(err) { + } catch (err) { return cb(err); } - }; WalletService.prototype._getBalanceOneStep = function(addresses, opts, cb) { @@ -1673,7 +1678,7 @@ WalletService.prototype._getActiveAddresses = function(cb) { _.filter(allAddresses, function(address) { return address.createdOn > now - 24 * 3600; }), - 'address' + 'address', ); var result = _.union(active, recent); @@ -1682,7 +1687,7 @@ WalletService.prototype._getActiveAddresses = function(cb) { result = _.compact( _.map(result, function(r) { return index[r]; - }) + }), ); return cb(null, result); }); @@ -1770,7 +1775,7 @@ WalletService.prototype.getSendMaxInfo = function(opts, cb) { }) ) return cb( - new ClientError('Invalid fee level. Valid values are ' + _.map(Defaults.FEE_LEVELS, 'name').join(', ')) + new ClientError('Invalid fee level. Valid values are ' + _.map(Defaults.FEE_LEVELS, 'name').join(', ')), ); } @@ -1824,9 +1829,9 @@ WalletService.prototype.getSendMaxInfo = function(opts, cb) { }); var baseTxpSize = txp.getEstimatedSize(); - var baseTxpFee = baseTxpSize * txp.feePerKb / 1000; + var baseTxpFee = (baseTxpSize * txp.feePerKb) / 1000; var sizePerInput = txp.getEstimatedSizeForSingleInput(); - var feePerInput = sizePerInput * txp.feePerKb / 1000; + var feePerInput = (sizePerInput * txp.feePerKb) / 1000; var partitionedByAmount = _.partition(inputs, function(input) { return input.micros > feePerInput; @@ -1915,8 +1920,8 @@ WalletService.prototype.getFeeLevels = function(opts, cb) { _.flatten( _.map(definedPoints, function(p) { return _.range(p, p + Defaults.FEE_LEVELS_FALLBACK + 1); - }) - ) + }), + ), ); } @@ -2012,9 +2017,9 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { var txpAmount = txp.getTotalAmount(); var baseTxpSize = txp.getEstimatedSize(); - var baseTxpFee = baseTxpSize * txp.feePerKb / 1000; + var baseTxpFee = (baseTxpSize * txp.feePerKb) / 1000; var sizePerInput = txp.getEstimatedSizeForSingleInput(); - var feePerInput = sizePerInput * txp.feePerKb / 1000; + var feePerInput = (sizePerInput * txp.feePerKb) / 1000; function sanitizeUtxos(utxos) { var excludeIndex = _.reduce( @@ -2023,7 +2028,7 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { res[val] = val; return res; }, - {} + {}, ); // We should ensure that utxos are not locked and are mature enough. @@ -2062,7 +2067,7 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { Utils.formatAmountInMrt(totalValueInUtxos) + ') is insufficient to cover for txp amount (' + Utils.formatAmountInMrt(txpAmount) + - ')' + ')', ); return cb(Errors.INSUFFICIENT_FUNDS); } @@ -2072,7 +2077,7 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { Utils.formatAmountInMrt(netValueInUtxos) + ') is insufficient to cover for txp amount (' + Utils.formatAmountInMrt(txpAmount) + - ')' + ')', ); return cb(Errors.INSUFFICIENT_FUNDS_FOR_FEE); } @@ -2123,14 +2128,14 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { Utils.formatRatio(feeVsAmountRatio) + ' (max: ' + Utils.formatRatio(Defaults.UTXO_SELECTION_MAX_FEE_VS_TX_AMOUNT_FACTOR) + - ')' + ')', ); log.debug( 'Tx amount/Input amount:' + Utils.formatRatio(amountVsUtxoRatio) + ' (min: ' + Utils.formatRatio(Defaults.UTXO_SELECTION_MIN_TX_AMOUNT_VS_UTXO_FACTOR) + - ')' + ')', ); if (txpSize / 1000 > Defaults.MAX_TX_SIZE_IN_KB) { @@ -2139,7 +2144,7 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { Utils.formatSize(txpSize) + ') is too big (max: ' + Utils.formatSize(Defaults.MAX_TX_SIZE_IN_KB * 1000) + - ')' + ')', ); error = Errors.TX_MAX_SIZE_EXCEEDED; return false; @@ -2160,18 +2165,23 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { Utils.formatRatio(Defaults.UTXO_SELECTION_MAX_FEE_VS_SINGLE_UTXO_FEE_FACTOR) + ')' + ' loses wrt single-input tx: ' + - Utils.formatAmountInMrt((selected.length - 1) * feePerInput) + Utils.formatAmountInMrt((selected.length - 1) * feePerInput), ); if (feeVsSingleInputFeeRatio > Defaults.UTXO_SELECTION_MAX_FEE_VS_SINGLE_UTXO_FEE_FACTOR) { log.debug( - 'Breaking because fee is too significant compared to tx amount and it is too expensive compared to using single input' + 'Breaking because fee is too significant compared to tx amount and it is too expensive compared to using single input', ); return false; } } } - log.debug('Cumulative total so far: ' + Utils.formatAmountInMrt(total) + ', Net total so far: ' + Utils.formatAmountInMrt(netTotal)); + log.debug( + 'Cumulative total so far: ' + + Utils.formatAmountInMrt(total) + + ', Net total so far: ' + + Utils.formatAmountInMrt(netTotal), + ); if (netTotal >= txpAmount) { var changeAmount = Math.round(total - txpAmount - fee); @@ -2182,7 +2192,7 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { log.debug( 'Change below dust threshold (' + Utils.formatAmountInMrt(dustThreshold) + - '). Incrementing fee to remove change.' + '). Incrementing fee to remove change.', ); // Remove dust change by incrementing fee @@ -2201,7 +2211,7 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { 'Could not reach Txp total (' + Utils.formatAmountInMrt(txpAmount) + '), still missing: ' + - Utils.formatAmountInMrt(txpAmount - netTotal) + Utils.formatAmountInMrt(txpAmount - netTotal), ); selected = []; @@ -2240,9 +2250,9 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { availableAmount = balance.availableAmount; } - if(txp.isInvite) { + if (txp.isInvite) { // User needs to maintain one invite to keep an activated account. - if(totalAmount < (txp.getTotalAmount() + 1 )) return cb(Errors.INSUFFICIENT_INVITES); + if (totalAmount < txp.getTotalAmount() + 1) return cb(Errors.INSUFFICIENT_INVITES); } if (totalAmount < txp.getTotalAmount()) return cb(Errors.INSUFFICIENT_FUNDS); if (availableAmount < txp.getTotalAmount()) return cb(Errors.LOCKED_FUNDS); @@ -2304,7 +2314,7 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { if (selectionError || _.isEmpty(inputs)) return cb(selectionError || new Error('Could not select tx inputs')); txp.setInputs(_.shuffle(inputs)); - txp.fee = txp.isInvite? 0 : fee; + txp.fee = txp.isInvite ? 0 : fee; var err = self._checkTx(txp); @@ -2314,14 +2324,14 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { 'Successfully built transaction. Total fees: ' + Utils.formatAmountInMrt(txp.fee) + ', total change: ' + - Utils.formatAmountInMrt(change) + Utils.formatAmountInMrt(change), ); } else { log.warn('Error building transaction', err); } return cb(err); - } + }, ); }); }; @@ -2418,7 +2428,7 @@ WalletService.prototype._validateAndSanitizeTxOpts = function(wallet, opts, cb) }) ) return next( - new ClientError('Invalid fee level. Valid values are ' + _.map(Defaults.FEE_LEVELS, 'name').join(', ')) + new ClientError('Invalid fee level. Valid values are ' + _.map(Defaults.FEE_LEVELS, 'name').join(', ')), ); } @@ -2459,7 +2469,7 @@ WalletService.prototype._validateAndSanitizeTxOpts = function(wallet, opts, cb) opts.inputs = info.inputs; opts.fee = info.fee; return next(); - } + }, ); }, function(next) { @@ -2471,7 +2481,7 @@ WalletService.prototype._validateAndSanitizeTxOpts = function(wallet, opts, cb) next(); }, ], - cb + cb, ); }; @@ -2494,7 +2504,7 @@ WalletService.prototype._getFeePerKb = function(wallet, opts, cb) { return cb(new ClientError(msg)); } return cb(null, level.feePerKb); - } + }, ); }; @@ -2645,7 +2655,7 @@ WalletService.prototype.createTx = function(opts, cb) { function(err) { if (err) return cb(err); return cb(null, txp); - } + }, ); }); }); @@ -2732,7 +2742,7 @@ WalletService.prototype.publishTx = function(opts, cb) { }); }); }); - } + }, ); }); }); @@ -2772,7 +2782,7 @@ WalletService.prototype.getTx = function(opts, cb) { txp.note = note; return cb(null, txp); }); - } + }, ); }; @@ -2810,7 +2820,7 @@ WalletService.prototype.getPendingTx = function(opts, cb) { txp.note = note; return cb(null, txp); }); - } + }, ); }; @@ -2932,7 +2942,7 @@ WalletService.prototype.removePendingTx = function(opts, cb) { self.storage.removeTx(self.walletId, txp.id, function() { self._notifyTxProposalAction('TxProposalRemoved', txp, cb); }); - } + }, ); }); }; @@ -3033,7 +3043,7 @@ WalletService.prototype.signTx = function(opts, cb) { { copayerId: self.copayerId, }, - next + next, ); }, function(next) { @@ -3046,10 +3056,10 @@ WalletService.prototype.signTx = function(opts, cb) { ], function() { return cb(null, txp); - } + }, ); }); - } + }, ); }); }; @@ -3123,7 +3133,7 @@ WalletService.prototype.broadcastTx = function(opts, cb) { { byThirdParty: true, }, - cb + cb, ); }); } else { @@ -3135,11 +3145,11 @@ WalletService.prototype.broadcastTx = function(opts, cb) { function(err) { if (err) return cb(err); return cb(null, txp); - } + }, ); } }); - } + }, ); }); }; @@ -3185,7 +3195,7 @@ WalletService.prototype.rejectTx = function(opts, cb) { { copayerId: self.copayerId, }, - next + next, ); }, function(next) { @@ -3194,7 +3204,7 @@ WalletService.prototype.rejectTx = function(opts, cb) { _.filter(txp.actions, { type: 'reject', }), - 'copayerId' + 'copayerId', ); self._notifyTxProposalAction( @@ -3203,7 +3213,7 @@ WalletService.prototype.rejectTx = function(opts, cb) { { rejectedBy: rejectedBy, }, - next + next, ); } else { next(); @@ -3212,10 +3222,10 @@ WalletService.prototype.rejectTx = function(opts, cb) { ], function() { return cb(null, txp); - } + }, ); }); - } + }, ); }; @@ -3246,7 +3256,7 @@ WalletService.prototype.getPendingTxs = function(opts, cb) { { byThirdParty: true, }, - next + next, ); }); }, @@ -3255,9 +3265,9 @@ WalletService.prototype.getPendingTxs = function(opts, cb) { err, _.reject(txps, function(txp) { return txp.status == 'broadcasted'; - }) + }), ); - } + }, ); }); }; @@ -3307,11 +3317,11 @@ WalletService.prototype.getNotifications = function(opts, cb) { n.walletId = self.walletId; return n; }), - 'id' + 'id', ); return cb(null, notifications); - } + }, ); }); }; @@ -3587,7 +3597,7 @@ WalletService.prototype.getTxHistory = function(opts, cb) { }; if (_.isNumber(tx.size) && tx.size > 0) { - newTx.feePerKb = +(tx.fees * 1000 / tx.size).toFixed(); + newTx.feePerKb = +((tx.fees * 1000) / tx.size).toFixed(); } if (opts.includeExtendedInfo) { @@ -3717,7 +3727,7 @@ WalletService.prototype.getTxHistory = function(opts, cb) { items: txs, fromCache: fromCache, }); - } + }, ); } @@ -3748,7 +3758,7 @@ WalletService.prototype.getTxHistory = function(opts, cb) { } } return cb(); - } + }, ); } @@ -3788,7 +3798,7 @@ WalletService.prototype.getTxHistory = function(opts, cb) { minTs: minTs, maxTs: maxTs, }, - done + done, ); }, function(done) { @@ -3797,7 +3807,7 @@ WalletService.prototype.getTxHistory = function(opts, cb) { { minTs: minTs, }, - done + done, ); }, ], @@ -3807,7 +3817,7 @@ WalletService.prototype.getTxHistory = function(opts, cb) { txps: res[0], notes: res[1], }); - } + }, ); }, ], @@ -3829,7 +3839,7 @@ WalletService.prototype.getTxHistory = function(opts, cb) { return cb(null, finalTxs, !!res.txs.fromCache); }); - } + }, ); }); }); @@ -3874,7 +3884,7 @@ WalletService.prototype.scan = function(opts, cb) { function(err) { derivator.rewind(gap); return cb(err, _.dropRight(allAddresses, gap)); - } + }, ); } @@ -3923,7 +3933,7 @@ WalletService.prototype.scan = function(opts, cb) { return cb(error); }); }); - } + }, ); }); }); @@ -4058,7 +4068,7 @@ WalletService.prototype.smsNotificationsSubscribe = function(opts, cb) { platform: opts.platform, settings: opts.settings, }, - cb + cb, ); }; @@ -4258,7 +4268,7 @@ WalletService.prototype.createVault = function(opts, cb) { if (err) return cb(err); return cb(null, toStore); }); - } + }, ); }); }, @@ -4370,7 +4380,7 @@ WalletService.prototype.getVaultTxHistory = function(opts, cb) { items: txs, fromCache: fromCache, }); - } + }, ); } @@ -4401,7 +4411,7 @@ WalletService.prototype.getVaultTxHistory = function(opts, cb) { } } return cb(); - } + }, ); } @@ -4438,7 +4448,7 @@ WalletService.prototype.getVaultTxHistory = function(opts, cb) { minTs: minTs, maxTs: maxTs, }, - done + done, ); }, function(done) { @@ -4447,7 +4457,7 @@ WalletService.prototype.getVaultTxHistory = function(opts, cb) { { minTs: minTs, }, - done + done, ); }, ], @@ -4457,7 +4467,7 @@ WalletService.prototype.getVaultTxHistory = function(opts, cb) { txps: res[0], notes: res[1], }); - } + }, ); }, ], @@ -4480,7 +4490,7 @@ WalletService.prototype.getVaultTxHistory = function(opts, cb) { return cb(null, finalTxs, !!res.txs.fromCache); }); - } + }, ); }); }; diff --git a/packages/merit-wallet-service/lib/sms-notification-service.js b/packages/merit-wallet-service/lib/sms-notification-service.js index f9aef6ea25..6e8432e9d4 100644 --- a/packages/merit-wallet-service/lib/sms-notification-service.js +++ b/packages/merit-wallet-service/lib/sms-notification-service.js @@ -23,7 +23,10 @@ function SmsNotificationService(opts) { this.storage = opts.storage; } else { this.storage = new Storage(); - this.storage.connect(opts.storageOpts, () => {}); + this.storage.connect( + opts.storageOpts, + () => {}, + ); } console.log('[SMS Service] Started!'); @@ -46,28 +49,31 @@ SmsNotificationService.prototype.sendSMS = function(notification, cb) { const { amount, isInvite } = notification.data; - request({ - method: 'POST', - uri: this.notificationsServiceUrl + '/notification', - json: { - type: 'sms', - destination: recipient.phoneNumber, - id: notification.id, - template: _.snakeCase(notification.type), - language: 'en', - notification: { - amount: isInvite? String(amount) : (amount / 1e8) + 'MRT' + request( + { + method: 'POST', + uri: this.notificationsServiceUrl + '/notification', + json: { + type: 'sms', + destination: recipient.phoneNumber, + id: notification.id, + template: _.snakeCase(notification.type), + language: 'en', + notification: { + amount: isInvite ? String(amount) : amount / 1e8 + 'MRT', + }, + }, + }, + (err, response) => { + if (!err && parseInt(response.statusCode) === 200) { + console.log('[SMS Service] Sent notification!'); + cb(); + } else { + console.log('[SMS Service] Error sending notification!', err); + cb(err || 'Unexpected error'); } - } - }, (err, response) => { - if (!err && parseInt(response.statusCode) === 200) { - console.log('[SMS Service] Sent notification!'); - cb(); - } else { - console.log('[SMS Service] Error sending notification!', err); - cb(err || 'Unexpected error'); - } - }); + }, + ); }); }; diff --git a/packages/merit-wallet-service/lib/stats.js b/packages/merit-wallet-service/lib/stats.js index bc578040d8..1ab07564b9 100644 --- a/packages/merit-wallet-service/lib/stats.js +++ b/packages/merit-wallet-service/lib/stats.js @@ -14,7 +14,6 @@ var moment = require('moment'); var config = require('../config'); var storage = require('./storage'); - var INITIAL_DATE = '2015-01-01'; function Stats(opts) { @@ -25,64 +24,72 @@ function Stats(opts) { this.to = moment(opts.to); this.fromTs = this.from.startOf('day').valueOf(); this.toTs = this.to.endOf('day').valueOf(); -}; +} Stats.prototype.run = function(cb) { var self = this; var uri = config.storageOpts.mongoDb.uri; - mongodb.MongoClient.connect(uri, function(err, db) { - if (err) { - log.error('Unable to connect to the mongoDB', err); - return cb(err, null); - } - log.info('Connection established to ' + uri); - self.db = db; - self._getStats(function(err, stats) { - if (err) return cb(err); - return cb(null, stats); - }); - }); + mongodb.MongoClient.connect( + uri, + function(err, db) { + if (err) { + log.error('Unable to connect to the mongoDB', err); + return cb(err, null); + } + log.info('Connection established to ' + uri); + self.db = db; + self._getStats(function(err, stats) { + if (err) return cb(err); + return cb(null, stats); + }); + }, + ); }; Stats.prototype._getStats = function(cb) { var self = this; var result = {}; - async.parallel([ + async.parallel( + [ + function(next) { + self._getNewWallets(next); + }, + function(next) { + self._getTxProposals(next); + }, + ], + function(err, results) { + if (err) return cb(err); - function(next) { - self._getNewWallets(next); - }, - function(next) { - self._getTxProposals(next); + result.newWallets = results[0]; + result.txProposals = results[1]; + return cb(null, result); }, - ], function(err, results) { - if (err) return cb(err); - - result.newWallets = results[0]; - result.txProposals = results[1]; - return cb(null, result); - }); + ); }; Stats.prototype._getNewWallets = function(cb) { var self = this; function getLastDate(cb) { - self.db.collection('stats_wallets') + self.db + .collection('stats_wallets') .find({}) .sort({ - '_id.day': -1 + '_id.day': -1, }) .limit(1) .toArray(function(err, lastRecord) { if (_.isEmpty(lastRecord)) return cb(null, moment(INITIAL_DATE)); return cb(null, moment(lastRecord[0]._id.day)); }); - }; + } function updateStats(from, cb) { - var to = moment().subtract(1, 'day').endOf('day'); + var to = moment() + .subtract(1, 'day') + .endOf('day'); var map = function() { var day = new Date(this.createdOn * 1000); day.setHours(0); @@ -93,7 +100,7 @@ Stats.prototype._getNewWallets = function(cb) { network: this.network, }; var value = { - count: 1 + count: 1, }; emit(key, value); }; @@ -115,16 +122,16 @@ Stats.prototype._getNewWallets = function(cb) { }, out: { merge: 'stats_wallets', - } + }, }; - self.db.collection(storage.collections.WALLETS) - .mapReduce(map, reduce, opts, function(err, collection, stats) { - return cb(err); - }); - }; + self.db.collection(storage.collections.WALLETS).mapReduce(map, reduce, opts, function(err, collection, stats) { + return cb(err); + }); + } function queryStats(cb) { - self.db.collection('stats_wallets') + self.db + .collection('stats_wallets') .find({ '_id.network': self.network, '_id.day': { @@ -133,7 +140,7 @@ Stats.prototype._getNewWallets = function(cb) { }, }) .sort({ - '_id.day': 1 + '_id.day': 1, }) .toArray(function(err, results) { if (err) return cb(err); @@ -147,16 +154,18 @@ Stats.prototype._getNewWallets = function(cb) { }); return cb(null, stats); }); - }; - - async.series([ + } + async.series( + [ function(next) { getLastDate(function(err, lastDate) { if (err) return next(err); lastDate = lastDate.startOf('day'); - var yesterday = moment().subtract(1, 'day').startOf('day'); + var yesterday = moment() + .subtract(1, 'day') + .startOf('day'); if (lastDate.isBefore(yesterday)) { // Needs update return updateStats(lastDate, next); @@ -173,27 +182,31 @@ Stats.prototype._getNewWallets = function(cb) { log.error(err); } return cb(err, res[1]); - }); + }, + ); }; Stats.prototype._getTxProposals = function(cb) { var self = this; function getLastDate(cb) { - self.db.collection('stats_txps') + self.db + .collection('stats_txps') .find({}) .sort({ - '_id.day': -1 + '_id.day': -1, }) .limit(1) .toArray(function(err, lastRecord) { if (_.isEmpty(lastRecord)) return cb(null, moment(INITIAL_DATE)); return cb(null, moment(lastRecord[0]._id.day)); }); - }; + } function updateStats(from, cb) { - var to = moment().subtract(1, 'day').endOf('day'); + var to = moment() + .subtract(1, 'day') + .endOf('day'); var map = function() { var day = new Date(this.broadcastedOn * 1000); day.setHours(0); @@ -205,7 +218,7 @@ Stats.prototype._getTxProposals = function(cb) { }; var value = { count: 1, - amount: this.amount + amount: this.amount, }; emit(key, value); }; @@ -231,16 +244,16 @@ Stats.prototype._getTxProposals = function(cb) { }, out: { merge: 'stats_txps', - } + }, }; - self.db.collection(storage.collections.TXS) - .mapReduce(map, reduce, opts, function(err, collection, stats) { - return cb(err); - }); - }; + self.db.collection(storage.collections.TXS).mapReduce(map, reduce, opts, function(err, collection, stats) { + return cb(err); + }); + } function queryStats(cb) { - self.db.collection('stats_txps') + self.db + .collection('stats_txps') .find({ '_id.network': self.network, '_id.day': { @@ -249,14 +262,14 @@ Stats.prototype._getTxProposals = function(cb) { }, }) .sort({ - '_id.day': 1 + '_id.day': 1, }) .toArray(function(err, results) { if (err) return cb(err); var stats = { nbByDay: [], - amountByDay: [] + amountByDay: [], }; _.each(results, function(record) { var day = moment(record._id.day).format('YYYYMMDD'); @@ -271,16 +284,18 @@ Stats.prototype._getTxProposals = function(cb) { }); return cb(null, stats); }); - }; - - async.series([ + } + async.series( + [ function(next) { getLastDate(function(err, lastDate) { if (err) return next(err); lastDate = lastDate.startOf('day'); - var yesterday = moment().subtract(1, 'day').startOf('day'); + var yesterday = moment() + .subtract(1, 'day') + .startOf('day'); if (lastDate.isBefore(yesterday)) { // Needs update return updateStats(lastDate, next); @@ -297,7 +312,8 @@ Stats.prototype._getTxProposals = function(cb) { log.error(err); } return cb(err, res[1]); - }); + }, + ); }; module.exports = Stats; diff --git a/packages/merit-wallet-service/lib/storage.js b/packages/merit-wallet-service/lib/storage.js index c512b235c5..24d7d528bd 100644 --- a/packages/merit-wallet-service/lib/storage.js +++ b/packages/merit-wallet-service/lib/storage.js @@ -39,17 +39,17 @@ var collections = { LEADERBOARD: 'leaderboard', }; -var Storage = function (opts) { +var Storage = function(opts) { opts = opts || {}; this.db = opts.db; }; -Storage.prototype._createIndexes = function () { +Storage.prototype._createIndexes = function() { this.db.collection(collections.WALLETS).createIndex({ - id: 1 + id: 1, }); this.db.collection(collections.COPAYERS_LOOKUP).createIndex({ - copayerId: 1 + copayerId: 1, }); this.db.collection(collections.TXS).createIndex({ walletId: 1, @@ -99,7 +99,7 @@ Storage.prototype._createIndexes = function () { }); this.db.collection(collections.REFERRAL_TX_CONFIRMATION_SUBS).createIndex({ codeHash: 1, - }) + }); this.db.collection(collections.SESSIONS).createIndex({ copayerId: 1, }); @@ -110,18 +110,21 @@ Storage.prototype._createIndexes = function () { initialTxId: 1, }); this.db.collection(collections.SMS_NOTIFICATION_SUBS).createIndex({ - walletId: 1 - }); - this.db.collection(collections.KNOWN_MESSAGES).createIndex({ - type: 1, - txid: 1, - blockHash: 1 - }, { - unique: true + walletId: 1, }); + this.db.collection(collections.KNOWN_MESSAGES).createIndex( + { + type: 1, + txid: 1, + blockHash: 1, + }, + { + unique: true, + }, + ); }; -Storage.prototype.connect = function (opts, cb) { +Storage.prototype.connect = function(opts, cb) { var self = this; opts = opts || {}; @@ -129,51 +132,61 @@ Storage.prototype.connect = function (opts, cb) { if (this.db) return cb(); var config = opts.mongoDb || {}; - mongodb.MongoClient.connect(config.uri, function (err, db) { - if (err) { - log.error('Unable to connect to the mongoDB. Check the credentials.'); - return cb(err); - } - self.db = db; - self._createIndexes(); - console.log('Connection established to mongoDB'); - return cb(); - }); + mongodb.MongoClient.connect( + config.uri, + function(err, db) { + if (err) { + log.error('Unable to connect to the mongoDB. Check the credentials.'); + return cb(err); + } + self.db = db; + self._createIndexes(); + console.log('Connection established to mongoDB'); + return cb(); + }, + ); }; - -Storage.prototype.disconnect = function (cb) { +Storage.prototype.disconnect = function(cb) { var self = this; - this.db.close(true, function (err) { + this.db.close(true, function(err) { if (err) return cb(err); self.db = null; return cb(); }); }; -Storage.prototype.fetchWallet = function (id, cb) { - this.db.collection(collections.WALLETS).findOne({ - id: id - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(); - return cb(null, Model.Wallet.fromObj(result)); - }); +Storage.prototype.fetchWallet = function(id, cb) { + this.db.collection(collections.WALLETS).findOne( + { + id: id, + }, + function(err, result) { + if (err) return cb(err); + if (!result) return cb(); + return cb(null, Model.Wallet.fromObj(result)); + }, + ); }; -Storage.prototype.storeWallet = function (wallet, cb) { - this.db.collection(collections.WALLETS).update({ - id: wallet.id - }, wallet.toObject(), { - w: 1, - upsert: true, - }, cb); +Storage.prototype.storeWallet = function(wallet, cb) { + this.db.collection(collections.WALLETS).update( + { + id: wallet.id, + }, + wallet.toObject(), + { + w: 1, + upsert: true, + }, + cb, + ); }; -Storage.prototype.storeWalletAndUpdateCopayersLookup = function (wallet, cb) { +Storage.prototype.storeWalletAndUpdateCopayersLookup = function(wallet, cb) { var self = this; - var copayerLookups = _.map(wallet.copayers, function (copayer) { + var copayerLookups = _.map(wallet.copayers, function(copayer) { $.checkState(copayer.requestPubKeys); return { copayerId: copayer.id, @@ -182,197 +195,239 @@ Storage.prototype.storeWalletAndUpdateCopayersLookup = function (wallet, cb) { }; }); - this.db.collection(collections.COPAYERS_LOOKUP).remove({ - walletId: wallet.id - }, { - w: 1 - }, function (err) { - if (err) return cb(err); - self.db.collection(collections.COPAYERS_LOOKUP).insert(copayerLookups, { - w: 1 - }, function (err) { + this.db.collection(collections.COPAYERS_LOOKUP).remove( + { + walletId: wallet.id, + }, + { + w: 1, + }, + function(err) { if (err) return cb(err); - return self.storeWallet(wallet, cb); - }); - }); + self.db.collection(collections.COPAYERS_LOOKUP).insert( + copayerLookups, + { + w: 1, + }, + function(err) { + if (err) return cb(err); + return self.storeWallet(wallet, cb); + }, + ); + }, + ); }; -Storage.prototype.fetchCopayerLookup = function (copayerId, cb) { - - this.db.collection(collections.COPAYERS_LOOKUP).findOne({ - copayerId: copayerId - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(); +Storage.prototype.fetchCopayerLookup = function(copayerId, cb) { + this.db.collection(collections.COPAYERS_LOOKUP).findOne( + { + copayerId: copayerId, + }, + function(err, result) { + if (err) return cb(err); + if (!result) return cb(); - if (!result.requestPubKeys) { - result.requestPubKeys = [{ - key: result.requestPubKey, - signature: result.signature, - }]; - } + if (!result.requestPubKeys) { + result.requestPubKeys = [ + { + key: result.requestPubKey, + signature: result.signature, + }, + ]; + } - return cb(null, result); - }); + return cb(null, result); + }, + ); }; // TODO: should be done client-side -Storage.prototype._completeTxData = function (walletId, txs, cb) { +Storage.prototype._completeTxData = function(walletId, txs, cb) { var self = this; - self.fetchWallet(walletId, function (err, wallet) { + self.fetchWallet(walletId, function(err, wallet) { if (err) return cb(err); - _.each([].concat(txs), function (tx) { + _.each([].concat(txs), function(tx) { tx.derivationStrategy = wallet.derivationStrategy || 'BIP45'; tx.creatorName = wallet.getCopayer(tx.creatorId).name; - _.each(tx.actions, function (action) { + _.each(tx.actions, function(action) { action.copayerName = wallet.getCopayer(action.copayerId).name; }); - }); return cb(null, txs); }); }; // TODO: remove walletId from signature -Storage.prototype.fetchTx = function (walletId, txProposalId, cb) { +Storage.prototype.fetchTx = function(walletId, txProposalId, cb) { var self = this; - this.db.collection(collections.TXS).findOne({ - id: txProposalId, - walletId: walletId - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(); - return self._completeTxData(walletId, Model.TxProposal.fromObj(result), cb); - }); + this.db.collection(collections.TXS).findOne( + { + id: txProposalId, + walletId: walletId, + }, + function(err, result) { + if (err) return cb(err); + if (!result) return cb(); + return self._completeTxData(walletId, Model.TxProposal.fromObj(result), cb); + }, + ); }; // This is an explicit fetch method that returns an error if a TX is not found. // We need this approach to ensure that we preserve the integrity of retry logic -Storage.prototype.mustFetchTx = function (walletId, txProposalId, cb, last) { +Storage.prototype.mustFetchTx = function(walletId, txProposalId, cb, last) { var self = this; last = !!last; if (last) { - this.db.collection(collections.TXS).find({ - id: txProposalId, - walletId: walletId - }, { - limit: 1, - readPreference: mongodb.ReadPreference.PRIMARY, - }).toArray(function (err, results) { - if (err) return cb(err); + this.db + .collection(collections.TXS) + .find( + { + id: txProposalId, + walletId: walletId, + }, + { + limit: 1, + readPreference: mongodb.ReadPreference.PRIMARY, + }, + ) + .toArray(function(err, results) { + if (err) return cb(err); - if (!results || results.length < 1 || !results[0]) return cb(new Error("TX_NOT_FOUND")); + if (!results || results.length < 1 || !results[0]) return cb(new Error('TX_NOT_FOUND')); - var result = results[0]; - return self._completeTxData(walletId, Model.TxProposal.fromObj(result), cb); - }); + var result = results[0]; + return self._completeTxData(walletId, Model.TxProposal.fromObj(result), cb); + }); } else { - this.db.collection(collections.TXS).findOne({ - id: txProposalId, - walletId: walletId - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(new Error("TX_NOT_FOUND")); - return self._completeTxData(walletId, Model.TxProposal.fromObj(result), cb); - }); + this.db.collection(collections.TXS).findOne( + { + id: txProposalId, + walletId: walletId, + }, + function(err, result) { + if (err) return cb(err); + if (!result) return cb(new Error('TX_NOT_FOUND')); + return self._completeTxData(walletId, Model.TxProposal.fromObj(result), cb); + }, + ); } }; // This is an explicit fetch method that returns an error if a TX is not found. // We need this approach to ensure that we preserve the integrity of retry logic -Storage.prototype.mustFetchPendingTx = function (walletId, txProposalId, cb, last) { +Storage.prototype.mustFetchPendingTx = function(walletId, txProposalId, cb, last) { var self = this; last = !!last; if (last) { - this.db.collection(collections.TXS).find({ - id: txProposalId, - walletId: walletId - }, { - limit: 1, - readPreference: mongodb.ReadPreference.PRIMARY, - }).toArray(function (err, results) { - if (err) return cb(err); + this.db + .collection(collections.TXS) + .find( + { + id: txProposalId, + walletId: walletId, + }, + { + limit: 1, + readPreference: mongodb.ReadPreference.PRIMARY, + }, + ) + .toArray(function(err, results) { + if (err) return cb(err); - if (!results || results.length < 1 || !results[0]) { - return cb(new Error("TX_NOT_FOUND")); - } - const areAnyPending = results.some(result => result.isPending) - if (!areAnyPending) return cb(new Error("TX_NOT_PENDING")) - var result = results[0]; - return self._completeTxData(walletId, Model.TxProposal.fromObj(result), cb); - }); + if (!results || results.length < 1 || !results[0]) { + return cb(new Error('TX_NOT_FOUND')); + } + const areAnyPending = results.some(result => result.isPending); + if (!areAnyPending) return cb(new Error('TX_NOT_PENDING')); + var result = results[0]; + return self._completeTxData(walletId, Model.TxProposal.fromObj(result), cb); + }); } else { - this.db.collection(collections.TXS).findOne({ - id: txProposalId, - walletId: walletId - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(new Error("TX_NOT_FOUND")); - if (!result.isPending) return cb(new Error("TX_NOT_PENDING")); - return self._completeTxData(walletId, Model.TxProposal.fromObj(result), cb); - }); + this.db.collection(collections.TXS).findOne( + { + id: txProposalId, + walletId: walletId, + }, + function(err, result) { + if (err) return cb(err); + if (!result) return cb(new Error('TX_NOT_FOUND')); + if (!result.isPending) return cb(new Error('TX_NOT_PENDING')); + return self._completeTxData(walletId, Model.TxProposal.fromObj(result), cb); + }, + ); } }; - - -Storage.prototype.fetchTxByHash = function (hash, cb) { +Storage.prototype.fetchTxByHash = function(hash, cb) { var self = this; - this.db.collection(collections.TXS).findOne({ - txid: hash, - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(); + this.db.collection(collections.TXS).findOne( + { + txid: hash, + }, + function(err, result) { + if (err) return cb(err); + if (!result) return cb(); - return self._completeTxData(result.walletId, Model.TxProposal.fromObj(result), cb); - }); + return self._completeTxData(result.walletId, Model.TxProposal.fromObj(result), cb); + }, + ); }; -Storage.prototype.fetchLastTxs = function (walletId, creatorId, limit, cb) { +Storage.prototype.fetchLastTxs = function(walletId, creatorId, limit, cb) { var self = this; - this.db.collection(collections.TXS).find({ - walletId: walletId, - creatorId: creatorId, - }, { - limit: limit || 5 - }).sort({ - createdOn: -1 - }).toArray(function (err, result) { - if (err) return cb(err); - if (!result) return cb(); - var txs = _.map(result, function (tx) { - return Model.TxProposal.fromObj(tx); + this.db + .collection(collections.TXS) + .find( + { + walletId: walletId, + creatorId: creatorId, + }, + { + limit: limit || 5, + }, + ) + .sort({ + createdOn: -1, + }) + .toArray(function(err, result) { + if (err) return cb(err); + if (!result) return cb(); + var txs = _.map(result, function(tx) { + return Model.TxProposal.fromObj(tx); + }); + return cb(null, txs); }); - return cb(null, txs); - }); }; - - -Storage.prototype.fetchPendingTxs = function (walletId, cb) { +Storage.prototype.fetchPendingTxs = function(walletId, cb) { var self = this; - self.db.collection(collections.TXS).find({ - walletId: walletId, - isPending: true, - }).sort({ - createdOn: -1 - }).toArray(function (err, result) { - if (err) return cb(err); - if (!result) return cb(); - var txs = _.map(result, function (tx) { - return Model.TxProposal.fromObj(tx); + self.db + .collection(collections.TXS) + .find({ + walletId: walletId, + isPending: true, + }) + .sort({ + createdOn: -1, + }) + .toArray(function(err, result) { + if (err) return cb(err); + if (!result) return cb(); + var txs = _.map(result, function(tx) { + return Model.TxProposal.fromObj(tx); + }); + return self._completeTxData(walletId, txs, cb); }); - return self._completeTxData(walletId, txs, cb); - }); }; /** @@ -383,7 +438,7 @@ Storage.prototype.fetchPendingTxs = function (walletId, cb) { * @param opts.maxTs * @param opts.limit */ -Storage.prototype.fetchTxs = function (walletId, opts, cb) { +Storage.prototype.fetchTxs = function(walletId, opts, cb) { var self = this; opts = opts || {}; @@ -393,23 +448,27 @@ Storage.prototype.fetchTxs = function (walletId, opts, cb) { if (_.isNumber(opts.maxTs)) tsFilter.$lte = opts.maxTs; var filter = { - walletId: walletId + walletId: walletId, }; if (!_.isEmpty(tsFilter)) filter.createdOn = tsFilter; var mods = {}; if (_.isNumber(opts.limit)) mods.limit = opts.limit; - this.db.collection(collections.TXS).find(filter, mods).sort({ - createdOn: -1 - }).toArray(function (err, result) { - if (err) return cb(err); - if (!result) return cb(); - var txs = _.map(result, function (tx) { - return Model.TxProposal.fromObj(tx); + this.db + .collection(collections.TXS) + .find(filter, mods) + .sort({ + createdOn: -1, + }) + .toArray(function(err, result) { + if (err) return cb(err); + if (!result) return cb(); + var txs = _.map(result, function(tx) { + return Model.TxProposal.fromObj(tx); + }); + return self._completeTxData(walletId, txs, cb); }); - return self._completeTxData(walletId, txs, cb); - }); }; /** @@ -420,7 +479,7 @@ Storage.prototype.fetchTxs = function (walletId, opts, cb) { * @param opts.maxTs * @param opts.limit */ -Storage.prototype.fetchBroadcastedTxs = function (walletId, opts, cb) { +Storage.prototype.fetchBroadcastedTxs = function(walletId, opts, cb) { var self = this; opts = opts || {}; @@ -438,59 +497,67 @@ Storage.prototype.fetchBroadcastedTxs = function (walletId, opts, cb) { var mods = {}; if (_.isNumber(opts.limit)) mods.limit = opts.limit; - this.db.collection(collections.TXS).find(filter, mods).sort({ - createdOn: -1 - }).toArray(function (err, result) { - if (err) return cb(err); - if (!result) return cb(); - var txs = _.map(result, function (tx) { - return Model.TxProposal.fromObj(tx); + this.db + .collection(collections.TXS) + .find(filter, mods) + .sort({ + createdOn: -1, + }) + .toArray(function(err, result) { + if (err) return cb(err); + if (!result) return cb(); + var txs = _.map(result, function(tx) { + return Model.TxProposal.fromObj(tx); + }); + return self._completeTxData(walletId, txs, cb); }); - return self._completeTxData(walletId, txs, cb); - }); }; -Storage.prototype.fetchInvitedAddresses = function (walletId, cb) { - +Storage.prototype.fetchInvitedAddresses = function(walletId, cb) { var filter = { isInvite: true, walletId: walletId, - status: 'broadcasted' + status: 'broadcasted', }; var fields = { - outputs: 1 + outputs: 1, }; - this.db.collection(collections.TXS).find(filter, fields).sort({ - broadcastedOn: -1 - }).toArray(function (err, result) { - if (err) return cb(err); - if (!result) return cb(null, []); - - var addresses = result.reduce(function (addrs, tx) { - - return addrs.concat( - tx.outputs.filter(function (output) { - return (addrs.indexOf(output.address) == -1); - }).map(function (output) { - return output.toAddress; - }) - ); - }, []); - - return cb(null, addresses); - }); + this.db + .collection(collections.TXS) + .find(filter, fields) + .sort({ + broadcastedOn: -1, + }) + .toArray(function(err, result) { + if (err) return cb(err); + if (!result) return cb(null, []); + + var addresses = result.reduce(function(addrs, tx) { + return addrs.concat( + tx.outputs + .filter(function(output) { + return addrs.indexOf(output.address) == -1; + }) + .map(function(output) { + return output.toAddress; + }), + ); + }, []); + + return cb(null, addresses); + }); }; -Storage.prototype.fetchReferralByCodeHash = function (codeHash, cb) { +Storage.prototype.fetchReferralByCodeHash = function(codeHash, cb) { const self = this; const filter = { codeHash, }; - self.db.collection(collections.REFERRALS).find(filter, function (err, result) { + self.db.collection(collections.REFERRALS).find(filter, function(err, result) { if (err) return cb(err); if (!result) return cb(); @@ -498,13 +565,18 @@ Storage.prototype.fetchReferralByCodeHash = function (codeHash, cb) { }); }; -Storage.prototype.storeReferral = function (referral, cb) { - this.db.collection(collections.REFERRALS).update({ - address: referral.address, - }, referral, { - w: 1, - upsert: true, - }, cb); +Storage.prototype.storeReferral = function(referral, cb) { + this.db.collection(collections.REFERRALS).update( + { + address: referral.address, + }, + referral, + { + w: 1, + upsert: true, + }, + cb, + ); }; /** @@ -514,10 +586,10 @@ Storage.prototype.storeReferral = function (referral, cb) { * @param {Number} minTs * @returns {Notification[]} Notifications */ -Storage.prototype.fetchNotifications = function (walletId, notificationId, minTs, cb) { +Storage.prototype.fetchNotifications = function(walletId, notificationId, minTs, cb) { function makeId(timestamp) { return _.padStart(timestamp, 14, '0') + _.repeat('0', 4); - }; + } var self = this; @@ -526,475 +598,618 @@ Storage.prototype.fetchNotifications = function (walletId, notificationId, minTs minId = notificationId > minId ? notificationId : minId; } - this.db.collection(collections.NOTIFICATIONS) - .find({ - walletId: walletId, - id: { - $gt: minId, + this.db + .collection(collections.NOTIFICATIONS) + .find( + { + walletId: walletId, + id: { + $gt: minId, + }, }, - }, { - readPreference: mongodb.ReadPreference.PRIMARY, - }).sort({ - id: 1 - }).toArray(function (err, result) { + { + readPreference: mongodb.ReadPreference.PRIMARY, + }, + ) + .sort({ + id: 1, + }) + .toArray(function(err, result) { if (err) return cb(err); if (!result) return cb(); - var notifications = _.map(result, function (notification) { + var notifications = _.map(result, function(notification) { return Model.Notification.fromObj(notification); }); return cb(null, notifications); }); }; -Storage.prototype.storeNotification = function (notification, cb) { - this.db.collection(collections.NOTIFICATIONS).insert(notification, { - w: "majority", - }, function (err, result) { - cb(err, result); - }); +Storage.prototype.storeNotification = function(notification, cb) { + this.db.collection(collections.NOTIFICATIONS).insert( + notification, + { + w: 'majority', + }, + function(err, result) { + cb(err, result); + }, + ); }; -Storage.prototype.fetchNotification = function (notification, cb) { - this.db.collection(collections.NOTIFICATIONS).find({ - id: notification.id, - walletId: notification.walletId, - }, { - readPreference: mongodb.ReadPreference.PRIMARY, - }).toArray(function (err, result) { - if (err) return cb(err); - if (!result || _.isEmpty(result)) return cb(); - cb(null, result[0]); - }); +Storage.prototype.fetchNotification = function(notification, cb) { + this.db + .collection(collections.NOTIFICATIONS) + .find( + { + id: notification.id, + walletId: notification.walletId, + }, + { + readPreference: mongodb.ReadPreference.PRIMARY, + }, + ) + .toArray(function(err, result) { + if (err) return cb(err); + if (!result || _.isEmpty(result)) return cb(); + cb(null, result[0]); + }); }; -Storage.prototype.fetchAndLockNotificationForPushes = function (notification, cb) { +Storage.prototype.fetchAndLockNotificationForPushes = function(notification, cb) { notification.lockForPushNotifications(); - this.db.collection(collections.NOTIFICATIONS).findOneAndUpdate({ - id: notification.id, - walletId: notification.walletId, - lockedForPushNotifications: false, - }, notification, { - readPreference: mongodb.ReadPreference.PRIMARY, - w: "majority", - writeConcern: { - w: "majority", - wtimeout: 5000 - }, - new: true, - returnOriginal: false, - }, function (err, result) { - cb(err, result.lastErrorObject && result.lastErrorObject.updatedExisting && result.value && result.ok); - }); + this.db.collection(collections.NOTIFICATIONS).findOneAndUpdate( + { + id: notification.id, + walletId: notification.walletId, + lockedForPushNotifications: false, + }, + notification, + { + readPreference: mongodb.ReadPreference.PRIMARY, + w: 'majority', + writeConcern: { + w: 'majority', + wtimeout: 5000, + }, + new: true, + returnOriginal: false, + }, + function(err, result) { + cb(err, result.lastErrorObject && result.lastErrorObject.updatedExisting && result.value && result.ok); + }, + ); }; -Storage.prototype.fetchAndLockNotificationForEmails = function (notification, cb) { +Storage.prototype.fetchAndLockNotificationForEmails = function(notification, cb) { notification.lockForEmailNotifications(); - this.db.collection(collections.NOTIFICATIONS).findOneAndUpdate({ - id: notification.id, - walletId: notification.walletId, - lockedForEmailNotifications: false, - }, notification, { - readPreference: mongodb.ReadPreference.PRIMARY, - w: "majority", - writeConcern: { - w: "majority", - wtimeout: 5000 - }, - new: true, - returnOriginal: false, - }, function (err, result) { - cb(err, result.lastErrorObject && result.lastErrorObject.updatedExisting && result.value && result.ok); - }); + this.db.collection(collections.NOTIFICATIONS).findOneAndUpdate( + { + id: notification.id, + walletId: notification.walletId, + lockedForEmailNotifications: false, + }, + notification, + { + readPreference: mongodb.ReadPreference.PRIMARY, + w: 'majority', + writeConcern: { + w: 'majority', + wtimeout: 5000, + }, + new: true, + returnOriginal: false, + }, + function(err, result) { + cb(err, result.lastErrorObject && result.lastErrorObject.updatedExisting && result.value && result.ok); + }, + ); }; // TODO: remove walletId from signature -Storage.prototype.storeTx = function (walletId, txp, cb) { - this.db.collection(collections.TXS).update({ - id: txp.id, - walletId: walletId - }, txp.toObject(), { - w: 1, - upsert: true, - }, cb); -}; - -Storage.prototype.removeTx = function (walletId, txProposalId, cb) { - this.db.collection(collections.TXS).findAndRemove({ - id: txProposalId, - walletId: walletId - }, { - w: 1 - }, cb); -}; - -Storage.prototype.removeWallet = function (walletId, cb) { - var self = this; - - async.parallel([ +Storage.prototype.storeTx = function(walletId, txp, cb) { + this.db.collection(collections.TXS).update( + { + id: txp.id, + walletId: walletId, + }, + txp.toObject(), + { + w: 1, + upsert: true, + }, + cb, + ); +}; - function (next) { - self.db.collection(collections.WALLETS).findAndRemove({ - id: walletId - }, next); +Storage.prototype.removeTx = function(walletId, txProposalId, cb) { + this.db.collection(collections.TXS).findAndRemove( + { + id: txProposalId, + walletId: walletId, }, - function (next) { - var otherCollections = _.without(_.values(collections), collections.WALLETS); - async.each(otherCollections, function (col, next) { - self.db.collection(col).remove({ - walletId: walletId - }, next); - }, next); + { + w: 1, }, - ], cb); + cb, + ); }; +Storage.prototype.removeWallet = function(walletId, cb) { + var self = this; + + async.parallel( + [ + function(next) { + self.db.collection(collections.WALLETS).findAndRemove( + { + id: walletId, + }, + next, + ); + }, + function(next) { + var otherCollections = _.without(_.values(collections), collections.WALLETS); + async.each( + otherCollections, + function(col, next) { + self.db.collection(col).remove( + { + walletId: walletId, + }, + next, + ); + }, + next, + ); + }, + ], + cb, + ); +}; -Storage.prototype.fetchAddresses = function (walletId, cb) { +Storage.prototype.fetchAddresses = function(walletId, cb) { var self = this; - this.db.collection(collections.ADDRESSES).find({ - walletId: walletId, - signed: true, - }).sort({ - createdOn: 1 - }).toArray(function (err, result) { - if (err) return cb(err); - if (!result) return cb(); - var addresses = _.map(result, function (address) { - return Model.Address.fromObj(address); + this.db + .collection(collections.ADDRESSES) + .find({ + walletId: walletId, + signed: true, + }) + .sort({ + createdOn: 1, + }) + .toArray(function(err, result) { + if (err) return cb(err); + if (!result) return cb(); + var addresses = _.map(result, function(address) { + return Model.Address.fromObj(address); + }); + return cb(null, addresses); }); - return cb(null, addresses); - }); }; -Storage.prototype.countAddresses = function (walletId, cb) { - this.db.collection(collections.ADDRESSES).find({ - walletId: walletId, - }).count(cb); +Storage.prototype.countAddresses = function(walletId, cb) { + this.db + .collection(collections.ADDRESSES) + .find({ + walletId: walletId, + }) + .count(cb); }; -Storage.prototype.storeAddress = function (address, cb) { +Storage.prototype.storeAddress = function(address, cb) { var self = this; - self.db.collection(collections.ADDRESSES).update({ - address: address.address - }, address, { - w: 1, - upsert: false, - }, cb); + self.db.collection(collections.ADDRESSES).update( + { + address: address.address, + }, + address, + { + w: 1, + upsert: false, + }, + cb, + ); }; -Storage.prototype.storeAddressAndWallet = function (wallet, addresses, cb) { +Storage.prototype.storeAddressAndWallet = function(wallet, addresses, cb) { var self = this; function saveAddresses(addresses, cb) { if (_.isEmpty(addresses)) return cb(); - self.db.collection(collections.ADDRESSES).insert(addresses, { - w: 1 - }, cb); - }; + self.db.collection(collections.ADDRESSES).insert( + addresses, + { + w: 1, + }, + cb, + ); + } var addresses = [].concat(addresses); if (addresses.length == 0) return cb(); - async.filter(addresses, function (address, next) { - self.db.collection(collections.ADDRESSES).findOne({ - address: address.address, - }, { - walletId: true, - }, function (err, result) { - if (err || !result) return next(true); - if (result.walletId != wallet.id) { - log.warn('Address ' + address.address + ' exists in more than one wallet.'); - return next(true); + async.filter( + addresses, + function(address, next) { + self.db.collection(collections.ADDRESSES).findOne( + { + address: address.address, + }, + { + walletId: true, + }, + function(err, result) { + if (err || !result) return next(true); + if (result.walletId != wallet.id) { + log.warn('Address ' + address.address + ' exists in more than one wallet.'); + return next(true); + } + // Ignore if address was already in wallet + return next(false); + }, + ); + }, + function(newAddresses) { + if (newAddresses) { + saveAddresses(addresses, function(err) { + if (err) return cb(err); + self.storeWallet(wallet, cb); + }); + } else { + return cb(null); } - // Ignore if address was already in wallet - return next(false); - }); - }, function (newAddresses) { - if (newAddresses) { - saveAddresses(addresses, function (err) { - if (err) return cb(err); - self.storeWallet(wallet, cb); - }); - } else { - return cb(null); - } - }); + }, + ); }; -Storage.prototype.fetchAddress = function (address, cb) { +Storage.prototype.fetchAddress = function(address, cb) { var self = this; - this.db.collection(collections.ADDRESSES).findOne({ - address: address, - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(); - return cb(null, Model.Address.fromObj(result)); - }); + this.db.collection(collections.ADDRESSES).findOne( + { + address: address, + }, + function(err, result) { + if (err) return cb(err); + if (!result) return cb(); + return cb(null, Model.Address.fromObj(result)); + }, + ); }; -Storage.prototype.fetchPreferences = function (walletId, copayerId, cb) { - this.db.collection(collections.PREFERENCES).find({ - walletId: walletId, - }).toArray(function (err, result) { - if (err) return cb(err); +Storage.prototype.fetchPreferences = function(walletId, copayerId, cb) { + this.db + .collection(collections.PREFERENCES) + .find({ + walletId: walletId, + }) + .toArray(function(err, result) { + if (err) return cb(err); - if (copayerId) { - result = _.find(result, { - copayerId: copayerId - }); - } - if (!result) return cb(); + if (copayerId) { + result = _.find(result, { + copayerId: copayerId, + }); + } + if (!result) return cb(); - var preferences = _.map([].concat(result), function (r) { - return Model.Preferences.fromObj(r); + var preferences = _.map([].concat(result), function(r) { + return Model.Preferences.fromObj(r); + }); + if (copayerId) { + preferences = preferences[0]; + } + return cb(null, preferences); }); - if (copayerId) { - preferences = preferences[0]; - } - return cb(null, preferences); - }); }; -Storage.prototype.storePreferences = function (preferences, cb) { - this.db.collection(collections.PREFERENCES).update({ - walletId: preferences.walletId, - copayerId: preferences.copayerId, - }, preferences, { - w: 1, - upsert: true, - }, cb); +Storage.prototype.storePreferences = function(preferences, cb) { + this.db.collection(collections.PREFERENCES).update( + { + walletId: preferences.walletId, + copayerId: preferences.copayerId, + }, + preferences, + { + w: 1, + upsert: true, + }, + cb, + ); }; -Storage.prototype.storeEmail = function (email, cb) { - this.db.collection(collections.EMAIL_QUEUE).update({ - id: email.id, - }, email, { - w: 1, - upsert: true, - }, cb); +Storage.prototype.storeEmail = function(email, cb) { + this.db.collection(collections.EMAIL_QUEUE).update( + { + id: email.id, + }, + email, + { + w: 1, + upsert: true, + }, + cb, + ); }; -Storage.prototype.fetchUnsentEmails = function (cb) { - this.db.collection(collections.EMAIL_QUEUE).find({ - status: 'pending', - }).toArray(function (err, result) { - if (err) return cb(err); - if (!result || _.isEmpty(result)) return cb(null, []); - return cb(null, Model.Email.fromObj(result)); - }); +Storage.prototype.fetchUnsentEmails = function(cb) { + this.db + .collection(collections.EMAIL_QUEUE) + .find({ + status: 'pending', + }) + .toArray(function(err, result) { + if (err) return cb(err); + if (!result || _.isEmpty(result)) return cb(null, []); + return cb(null, Model.Email.fromObj(result)); + }); }; -Storage.prototype.fetchEmailByNotification = function (notificationId, cb) { - this.db.collection(collections.EMAIL_QUEUE).findOne({ - notificationId: notificationId, - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(); +Storage.prototype.fetchEmailByNotification = function(notificationId, cb) { + this.db.collection(collections.EMAIL_QUEUE).findOne( + { + notificationId: notificationId, + }, + function(err, result) { + if (err) return cb(err); + if (!result) return cb(); - return cb(null, Model.Email.fromObj(result)); - }); + return cb(null, Model.Email.fromObj(result)); + }, + ); }; -Storage.prototype.cleanActiveAddresses = function (walletId, cb) { +Storage.prototype.cleanActiveAddresses = function(walletId, cb) { var self = this; - async.series([ - - function (next) { - self.db.collection(collections.CACHE).remove({ - walletId: walletId, - type: 'activeAddresses', - }, { - w: 1 - }, next); - }, - function (next) { - self.db.collection(collections.CACHE).insert({ - walletId: walletId, - type: 'activeAddresses', - key: null - }, { - w: 1 - }, next); - }, - ], cb); + async.series( + [ + function(next) { + self.db.collection(collections.CACHE).remove( + { + walletId: walletId, + type: 'activeAddresses', + }, + { + w: 1, + }, + next, + ); + }, + function(next) { + self.db.collection(collections.CACHE).insert( + { + walletId: walletId, + type: 'activeAddresses', + key: null, + }, + { + w: 1, + }, + next, + ); + }, + ], + cb, + ); }; -Storage.prototype.storeActiveAddresses = function (walletId, addresses, cb) { +Storage.prototype.storeActiveAddresses = function(walletId, addresses, cb) { var self = this; - async.each(addresses, function (address, next) { - var record = { - walletId: walletId, - type: 'activeAddresses', - key: address, - }; - self.db.collection(collections.CACHE).update({ - walletId: record.walletId, - type: record.type, - key: record.key, - }, record, { - w: 1, - upsert: true, - }, next); - }, cb); + async.each( + addresses, + function(address, next) { + var record = { + walletId: walletId, + type: 'activeAddresses', + key: address, + }; + self.db.collection(collections.CACHE).update( + { + walletId: record.walletId, + type: record.type, + key: record.key, + }, + record, + { + w: 1, + upsert: true, + }, + next, + ); + }, + cb, + ); }; -Storage.prototype.getReferralsHistoryCache = function (walletId, from, to, cb) { +Storage.prototype.getReferralsHistoryCache = function(walletId, from, to, cb) { var self = this; $.checkArgument(from >= 0); $.checkArgument(from <= to); - self.db.collection(collections.CACHE).findOne({ - walletId: walletId, - type: 'referralsCacheStatus', - key: null - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(); - if (!result.isUpdated) return cb(); - - // Reverse indexes - var fwdIndex = result.totalItems - to; - - if (fwdIndex < 0) { - fwdIndex = 0; - } - - var end = result.totalItems - from; - - // nothing to return - if (end <= 0) return cb(null, []); - - // Cache is OK. - self.db.collection(collections.CACHE).find({ + self.db.collection(collections.CACHE).findOne( + { walletId: walletId, - type: 'referralsCache', - key: { - $gte: fwdIndex, - $lt: end - } - }).sort({ - key: -1 - }).toArray(function (err, result) { + type: 'referralsCacheStatus', + key: null, + }, + function(err, result) { if (err) return cb(err); - if (!result) return cb(); + if (!result.isUpdated) return cb(); - if (result.length < end - fwdIndex) { - // some items are not yet defined. - return cb(); + // Reverse indexes + var fwdIndex = result.totalItems - to; + + if (fwdIndex < 0) { + fwdIndex = 0; } - var referals = _.map(result, 'referral'); - return cb(null, referals); - }); - }); + var end = result.totalItems - from; + + // nothing to return + if (end <= 0) return cb(null, []); + + // Cache is OK. + self.db + .collection(collections.CACHE) + .find({ + walletId: walletId, + type: 'referralsCache', + key: { + $gte: fwdIndex, + $lt: end, + }, + }) + .sort({ + key: -1, + }) + .toArray(function(err, result) { + if (err) return cb(err); + + if (!result) return cb(); + + if (result.length < end - fwdIndex) { + // some items are not yet defined. + return cb(); + } + + var referals = _.map(result, 'referral'); + return cb(null, referals); + }); + }, + ); }; // -------- --------------------------- Total // > Time > // ^to <= ^from // ^fwdIndex => ^end -Storage.prototype.getTxHistoryCache = function (walletId, from, to, cb) { +Storage.prototype.getTxHistoryCache = function(walletId, from, to, cb) { var self = this; $.checkArgument(from >= 0); $.checkArgument(from <= to); - self.db.collection(collections.CACHE).findOne({ - walletId: walletId, - type: 'historyCacheStatus', - key: null - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(); - if (!result.isUpdated) return cb(); - - // Reverse indexes - var fwdIndex = result.totalItems - to; - - if (fwdIndex < 0) { - fwdIndex = 0; - } - - var end = result.totalItems - from; - - // nothing to return - if (end <= 0) return cb(null, []); - - // Cache is OK. - self.db.collection(collections.CACHE).find({ + self.db.collection(collections.CACHE).findOne( + { walletId: walletId, - type: 'historyCache', - key: { - $gte: fwdIndex, - $lt: end - }, - }).sort({ - key: -1, - }).toArray(function (err, result) { + type: 'historyCacheStatus', + key: null, + }, + function(err, result) { if (err) return cb(err); - if (!result) return cb(); + if (!result.isUpdated) return cb(); + + // Reverse indexes + var fwdIndex = result.totalItems - to; - if (result.length < end - fwdIndex) { - // some items are not yet defined. - return cb(); + if (fwdIndex < 0) { + fwdIndex = 0; } - var txs = _.map(result, 'tx'); - return cb(null, txs); - }); - }) + var end = result.totalItems - from; + + // nothing to return + if (end <= 0) return cb(null, []); + + // Cache is OK. + self.db + .collection(collections.CACHE) + .find({ + walletId: walletId, + type: 'historyCache', + key: { + $gte: fwdIndex, + $lt: end, + }, + }) + .sort({ + key: -1, + }) + .toArray(function(err, result) { + if (err) return cb(err); + + if (!result) return cb(); + + if (result.length < end - fwdIndex) { + // some items are not yet defined. + return cb(); + } + + var txs = _.map(result, 'tx'); + return cb(null, txs); + }); + }, + ); }; -Storage.prototype.softResetAllTxHistoryCache = function (cb) { - this.db.collection(collections.CACHE).update({ - type: 'historyCacheStatus', - }, { - isUpdated: false, - }, { - multi: true, - }, cb); +Storage.prototype.softResetAllTxHistoryCache = function(cb) { + this.db.collection(collections.CACHE).update( + { + type: 'historyCacheStatus', + }, + { + isUpdated: false, + }, + { + multi: true, + }, + cb, + ); }; -Storage.prototype.softResetTxHistoryCache = function (walletId, cb) { - this.db.collection(collections.CACHE).update({ - walletId: walletId, - type: 'historyCacheStatus', - key: null - }, { - isUpdated: false, - }, { - w: 1, - upsert: true, - }, cb); +Storage.prototype.softResetTxHistoryCache = function(walletId, cb) { + this.db.collection(collections.CACHE).update( + { + walletId: walletId, + type: 'historyCacheStatus', + key: null, + }, + { + isUpdated: false, + }, + { + w: 1, + upsert: true, + }, + cb, + ); }; -Storage.prototype.clearTxHistoryCache = function (walletId, cb) { +Storage.prototype.clearTxHistoryCache = function(walletId, cb) { var self = this; - self.db.collection(collections.CACHE).remove({ - walletId: walletId, - type: 'historyCache', - }, { - multi: 1 - }, function (err) { - if (err) return cb(err); - self.db.collection(collections.CACHE).remove({ + self.db.collection(collections.CACHE).remove( + { walletId: walletId, - type: 'historyCacheStatus', - key: null - }, { - w: 1 - }, cb); - }); + type: 'historyCache', + }, + { + multi: 1, + }, + function(err) { + if (err) return cb(err); + self.db.collection(collections.CACHE).remove( + { + walletId: walletId, + type: 'historyCacheStatus', + key: null, + }, + { + w: 1, + }, + cb, + ); + }, + ); }; // items should be in CHRONOLOGICAL order -Storage.prototype.storeTxHistoryCache = function (walletId, totalItems, firstPosition, items, cb) { +Storage.prototype.storeTxHistoryCache = function(walletId, totalItems, firstPosition, items, cb) { $.shouldBeNumber(firstPosition); $.checkArgument(firstPosition >= 0); $.shouldBeNumber(totalItems); @@ -1002,120 +1217,149 @@ Storage.prototype.storeTxHistoryCache = function (walletId, totalItems, firstPos var self = this; - _.each(items, function (item, i) { + _.each(items, function(item, i) { item.position = firstPosition + i; }); - var cacheIsComplete = (firstPosition == 0); + var cacheIsComplete = firstPosition == 0; // TODO: check txid uniqness? - async.each(items, function (item, next) { - var pos = item.position; - delete item.position; - self.db.collection(collections.CACHE).update({ - walletId: walletId, - type: 'historyCache', - key: pos, - }, { - walletId: walletId, - type: 'historyCache', - key: pos, - tx: item, - }, { - w: 1, - upsert: true, - }, next); - }, function (err) { - if (err) return cb(err); + async.each( + items, + function(item, next) { + var pos = item.position; + delete item.position; + self.db.collection(collections.CACHE).update( + { + walletId: walletId, + type: 'historyCache', + key: pos, + }, + { + walletId: walletId, + type: 'historyCache', + key: pos, + tx: item, + }, + { + w: 1, + upsert: true, + }, + next, + ); + }, + function(err) { + if (err) return cb(err); - self.db.collection(collections.CACHE).update({ - walletId: walletId, - type: 'historyCacheStatus', - key: null - }, { - walletId: walletId, - type: 'historyCacheStatus', - key: null, - totalItems: totalItems, - updatedOn: Date.now(), - isComplete: cacheIsComplete, - isUpdated: true, - }, { - w: 1, - upsert: true, - }, cb); - }); + self.db.collection(collections.CACHE).update( + { + walletId: walletId, + type: 'historyCacheStatus', + key: null, + }, + { + walletId: walletId, + type: 'historyCacheStatus', + key: null, + totalItems: totalItems, + updatedOn: Date.now(), + isComplete: cacheIsComplete, + isUpdated: true, + }, + { + w: 1, + upsert: true, + }, + cb, + ); + }, + ); }; - - - - -Storage.prototype.fetchActiveAddresses = function (walletId, cb) { +Storage.prototype.fetchActiveAddresses = function(walletId, cb) { var self = this; - self.db.collection(collections.CACHE).find({ - walletId: walletId, - type: 'activeAddresses', - }).toArray(function (err, result) { - if (err) return cb(err); - if (_.isEmpty(result)) return cb(); + self.db + .collection(collections.CACHE) + .find({ + walletId: walletId, + type: 'activeAddresses', + }) + .toArray(function(err, result) { + if (err) return cb(err); + if (_.isEmpty(result)) return cb(); - return cb(null, _.compact(_.map(result, 'key'))); - }); + return cb(null, _.compact(_.map(result, 'key'))); + }); }; -Storage.prototype.storeFiatRate = function (providerName, rates, cb) { +Storage.prototype.storeFiatRate = function(providerName, rates, cb) { var self = this; var now = Date.now(); - async.each(rates, function (rate, next) { - self.db.collection(collections.FIAT_RATES).insert({ - provider: providerName, - ts: now, - code: rate.code, - value: rate.value, - }, { - w: 1 - }, next); - }, cb); + async.each( + rates, + function(rate, next) { + self.db.collection(collections.FIAT_RATES).insert( + { + provider: providerName, + ts: now, + code: rate.code, + value: rate.value, + }, + { + w: 1, + }, + next, + ); + }, + cb, + ); }; -Storage.prototype.fetchFiatRate = function (providerName, code, ts, cb) { +Storage.prototype.fetchFiatRate = function(providerName, code, ts, cb) { var self = this; - self.db.collection(collections.FIAT_RATES).find({ - provider: providerName, - code: code, - ts: { - $lte: ts - }, - }).sort({ - ts: -1 - }).limit(1).toArray(function (err, result) { - if (err || _.isEmpty(result)) return cb(err); - return cb(null, result[0]); - }); + self.db + .collection(collections.FIAT_RATES) + .find({ + provider: providerName, + code: code, + ts: { + $lte: ts, + }, + }) + .sort({ + ts: -1, + }) + .limit(1) + .toArray(function(err, result) { + if (err || _.isEmpty(result)) return cb(err); + return cb(null, result[0]); + }); }; -Storage.prototype.fetchTxNote = function (walletId, txid, cb) { +Storage.prototype.fetchTxNote = function(walletId, txid, cb) { var self = this; - self.db.collection(collections.TX_NOTES).findOne({ - walletId: walletId, - txid: txid, - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(); - return self._completeTxNotesData(walletId, Model.TxNote.fromObj(result), cb); - }); + self.db.collection(collections.TX_NOTES).findOne( + { + walletId: walletId, + txid: txid, + }, + function(err, result) { + if (err) return cb(err); + if (!result) return cb(); + return self._completeTxNotesData(walletId, Model.TxNote.fromObj(result), cb); + }, + ); }; // TODO: should be done client-side -Storage.prototype._completeTxNotesData = function (walletId, notes, cb) { +Storage.prototype._completeTxNotesData = function(walletId, notes, cb) { var self = this; - self.fetchWallet(walletId, function (err, wallet) { + self.fetchWallet(walletId, function(err, wallet) { if (err) return cb(err); - _.each([].concat(notes), function (note) { + _.each([].concat(notes), function(note) { note.editedByName = wallet.getCopayer(note.editedBy).name; }); return cb(null, notes); @@ -1128,346 +1372,450 @@ Storage.prototype._completeTxNotesData = function (walletId, notes, cb) { * @param walletId * @param opts.minTs */ -Storage.prototype.fetchTxNotes = function (walletId, opts, cb) { +Storage.prototype.fetchTxNotes = function(walletId, opts, cb) { var self = this; var filter = { walletId: walletId, }; - if (_.isNumber(opts.minTs)) filter.editedOn = { - $gte: opts.minTs - }; - this.db.collection(collections.TX_NOTES).find(filter).toArray(function (err, result) { - if (err) return cb(err); - var notes = _.compact(_.map(result, function (note) { - return Model.TxNote.fromObj(note); - })); - return self._completeTxNotesData(walletId, notes, cb); - }); + if (_.isNumber(opts.minTs)) + filter.editedOn = { + $gte: opts.minTs, + }; + this.db + .collection(collections.TX_NOTES) + .find(filter) + .toArray(function(err, result) { + if (err) return cb(err); + var notes = _.compact( + _.map(result, function(note) { + return Model.TxNote.fromObj(note); + }), + ); + return self._completeTxNotesData(walletId, notes, cb); + }); }; -Storage.prototype.storeTxNote = function (txNote, cb) { - this.db.collection(collections.TX_NOTES).update({ - txid: txNote.txid, - walletId: txNote.walletId - }, txNote.toObject(), { - w: 1, - upsert: true, - }, cb); +Storage.prototype.storeTxNote = function(txNote, cb) { + this.db.collection(collections.TX_NOTES).update( + { + txid: txNote.txid, + walletId: txNote.walletId, + }, + txNote.toObject(), + { + w: 1, + upsert: true, + }, + cb, + ); }; -Storage.prototype.getSession = function (copayerId, cb) { +Storage.prototype.getSession = function(copayerId, cb) { var self = this; - self.db.collection(collections.SESSIONS).findOne({ + self.db.collection(collections.SESSIONS).findOne( + { copayerId: copayerId, }, - function (err, result) { + function(err, result) { if (err || !result) return cb(err); return cb(null, Model.Session.fromObj(result)); - }); + }, + ); }; -Storage.prototype.storeSession = function (session, cb) { - this.db.collection(collections.SESSIONS).update({ - copayerId: session.copayerId, - }, session.toObject(), { - w: 1, - upsert: true, - }, cb); +Storage.prototype.storeSession = function(session, cb) { + this.db.collection(collections.SESSIONS).update( + { + copayerId: session.copayerId, + }, + session.toObject(), + { + w: 1, + upsert: true, + }, + cb, + ); }; -Storage.prototype.fetchPushNotificationSubs = function (copayerId, cb) { - this.db.collection(collections.PUSH_NOTIFICATION_SUBS).find({ - copayerId: copayerId, - }).toArray(function (err, result) { - if (err) return cb(err); +Storage.prototype.fetchPushNotificationSubs = function(copayerId, cb) { + this.db + .collection(collections.PUSH_NOTIFICATION_SUBS) + .find({ + copayerId: copayerId, + }) + .toArray(function(err, result) { + if (err) return cb(err); - if (!result) return cb(); + if (!result) return cb(); - var tokens = _.map([].concat(result), function (r) { - return Model.PushNotificationSub.fromObj(r); + var tokens = _.map([].concat(result), function(r) { + return Model.PushNotificationSub.fromObj(r); + }); + return cb(null, tokens); }); - return cb(null, tokens); - }); }; -Storage.prototype.storePushNotificationSub = function (pushNotificationSub, cb) { - this.db.collection(collections.PUSH_NOTIFICATION_SUBS).update({ - copayerId: pushNotificationSub.copayerId, - token: pushNotificationSub.token, - }, pushNotificationSub, { - w: 1, - upsert: true, - }, cb); +Storage.prototype.storePushNotificationSub = function(pushNotificationSub, cb) { + this.db.collection(collections.PUSH_NOTIFICATION_SUBS).update( + { + copayerId: pushNotificationSub.copayerId, + token: pushNotificationSub.token, + }, + pushNotificationSub, + { + w: 1, + upsert: true, + }, + cb, + ); }; -Storage.prototype.removePushNotificationSub = function (copayerId, token, cb) { - this.db.collection(collections.PUSH_NOTIFICATION_SUBS).remove({ - copayerId: copayerId, - token: token, - }, { - w: 1 - }, cb); +Storage.prototype.removePushNotificationSub = function(copayerId, token, cb) { + this.db.collection(collections.PUSH_NOTIFICATION_SUBS).remove( + { + copayerId: copayerId, + token: token, + }, + { + w: 1, + }, + cb, + ); }; Storage.prototype.storeSmsNotificationSub = function(sub, cb) { - this.db.collection(collections.SMS_NOTIFICATION_SUBS) - .update({ walletId: sub.walletId }, sub, { + this.db.collection(collections.SMS_NOTIFICATION_SUBS).update( + { walletId: sub.walletId }, + sub, + { w: 1, - upsert: true - }, cb); + upsert: true, + }, + cb, + ); }; Storage.prototype.fetchSmsNotificationSub = function(walletId, cb) { - this.db.collection(collections.SMS_NOTIFICATION_SUBS) - .findOne({ walletId }, (err, result) => { - if (err) return cb(err); - if (!result) return cb(); + this.db.collection(collections.SMS_NOTIFICATION_SUBS).findOne({ walletId }, (err, result) => { + if (err) return cb(err); + if (!result) return cb(); - return cb(null, Model.SmsNotificationSub.fromObj(result)); - }); + return cb(null, Model.SmsNotificationSub.fromObj(result)); + }); }; Storage.prototype.removeSmsNotificationSub = function(walletId, cb) { - this.db.collection(collections.SMS_NOTIFICATION_SUBS) - .remove({ walletId }, { w: 1 }, cb); + this.db.collection(collections.SMS_NOTIFICATION_SUBS).remove({ walletId }, { w: 1 }, cb); }; -Storage.prototype.fetchActiveTxConfirmationSubs = function (copayerId, cb) { +Storage.prototype.fetchActiveTxConfirmationSubs = function(copayerId, cb) { var filter = { - isActive: true + isActive: true, }; if (copayerId) filter.copayerId = copayerId; - this.db.collection(collections.TX_CONFIRMATION_SUBS).find(filter) - .toArray(function (err, result) { + this.db + .collection(collections.TX_CONFIRMATION_SUBS) + .find(filter) + .toArray(function(err, result) { if (err) return cb(err); if (!result) return cb(); - var subs = _.map([].concat(result), function (r) { + var subs = _.map([].concat(result), function(r) { return Model.TxConfirmationSub.fromObj(r); }); return cb(null, subs); }); }; - -Storage.prototype.fetchActiveReferralConfirmationSubs = function (cb) { +Storage.prototype.fetchActiveReferralConfirmationSubs = function(cb) { const filter = { - isActive: true + isActive: true, }; - this.db.collection(collections.REFERRAL_TX_CONFIRMATION_SUBS).find(filter) - .toArray(function (err, result) { + this.db + .collection(collections.REFERRAL_TX_CONFIRMATION_SUBS) + .find(filter) + .toArray(function(err, result) { if (err) return cb(err); if (!result) return cb(); - const subs = _.map([].concat(result), function (r) { + const subs = _.map([].concat(result), function(r) { return Model.ReferralTxConfirmationSub.fromObj(r); }); return cb(null, subs); }); }; -Storage.prototype.storeTxConfirmationSub = function (txConfirmationSub, cb) { - this.db.collection(collections.TX_CONFIRMATION_SUBS).update({ - copayerId: txConfirmationSub.copayerId, - txid: txConfirmationSub.txid, - }, txConfirmationSub, { - w: 1, - upsert: true, - }, cb); +Storage.prototype.storeTxConfirmationSub = function(txConfirmationSub, cb) { + this.db.collection(collections.TX_CONFIRMATION_SUBS).update( + { + copayerId: txConfirmationSub.copayerId, + txid: txConfirmationSub.txid, + }, + txConfirmationSub, + { + w: 1, + upsert: true, + }, + cb, + ); }; -Storage.prototype.removeTxConfirmationSub = function (copayerId, txid, cb) { - this.db.collection(collections.TX_CONFIRMATION_SUBS).remove({ - copayerId: copayerId, - txid: txid, - }, { - w: 1 - }, cb); +Storage.prototype.removeTxConfirmationSub = function(copayerId, txid, cb) { + this.db.collection(collections.TX_CONFIRMATION_SUBS).remove( + { + copayerId: copayerId, + txid: txid, + }, + { + w: 1, + }, + cb, + ); }; -Storage.prototype.storeReferralTxConfirmationSub = function (referralConfirmationSub, cb) { - this.db.collection(collections.REFERRAL_TX_CONFIRMATION_SUBS).update({ - copayerId: referralConfirmationSub.copayerId, - codeHash: referralConfirmationSub.codeHash, - }, referralConfirmationSub, { - w: 1, - upsert: true, - }, cb); +Storage.prototype.storeReferralTxConfirmationSub = function(referralConfirmationSub, cb) { + this.db.collection(collections.REFERRAL_TX_CONFIRMATION_SUBS).update( + { + copayerId: referralConfirmationSub.copayerId, + codeHash: referralConfirmationSub.codeHash, + }, + referralConfirmationSub, + { + w: 1, + upsert: true, + }, + cb, + ); }; -Storage.prototype.removeReferralTxConfirmationSub = function (copayerId, codeHash, cb) { - this.db.collection(collections.REFERRAL_TX_CONFIRMATION_SUBS).remove({ - codeHash: codeHash, - }, { - w: 1, - upsert: true, - }, cb); +Storage.prototype.removeReferralTxConfirmationSub = function(copayerId, codeHash, cb) { + this.db.collection(collections.REFERRAL_TX_CONFIRMATION_SUBS).remove( + { + codeHash: codeHash, + }, + { + w: 1, + upsert: true, + }, + cb, + ); }; - -Storage.prototype._dump = function (cb, fn) { +Storage.prototype._dump = function(cb, fn) { fn = fn || console.log; - cb = cb || function () {}; + cb = cb || function() {}; var self = this; - this.db.collections(function (err, collections) { + this.db.collections(function(err, collections) { if (err) return cb(err); - async.eachSeries(collections, function (col, next) { - col.find().toArray(function (err, items) { - fn('--------', col.s.name); - fn(items); - fn('------------------------------------------------------------------\n\n'); - next(err); - }); - }, cb); + async.eachSeries( + collections, + function(col, next) { + col.find().toArray(function(err, items) { + fn('--------', col.s.name); + fn(items); + fn('------------------------------------------------------------------\n\n'); + next(err); + }); + }, + cb, + ); }); }; /** * Vaults */ -Storage.prototype.fetchVaults = function (copayerId, cb) { - this.db.collection(collections.VAULTS).find({ - copayerId, - }).toArray(function (err, result) { - if (err) return cb(err); +Storage.prototype.fetchVaults = function(copayerId, cb) { + this.db + .collection(collections.VAULTS) + .find({ + copayerId, + }) + .toArray(function(err, result) { + if (err) return cb(err); - if (!result) return cb(); + if (!result) return cb(); - return cb(null, result); - }); + return cb(null, result); + }); }; -Storage.prototype.storeVault = function (copayerId, walletId, vaultTx, cb) { - this.db.collection(collections.VAULTS).insertOne({ - copayerId, - walletId, - ...vaultTx, - }, { - w: 1 - }, cb); +Storage.prototype.storeVault = function(copayerId, walletId, vaultTx, cb) { + this.db.collection(collections.VAULTS).insertOne( + { + copayerId, + walletId, + ...vaultTx, + }, + { + w: 1, + }, + cb, + ); }; -Storage.prototype.updateVault = function (copayerId, vaultTx, cb) { +Storage.prototype.updateVault = function(copayerId, vaultTx, cb) { vaultTx._id = new ObjectID(vaultTx._id); - this.db.collection(collections.VAULTS).update({ - copayerId, - _id: new ObjectID(vaultTx._id), - }, vaultTx, { - w: 1, - upsert: false, - }, cb); -}; - -Storage.prototype.fetchVaultByInitialTxId = function (txId, cb) { - this.db.collection(collections.VAULTS).findOne({ - initialTxId: txId, - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(); + this.db.collection(collections.VAULTS).update( + { + copayerId, + _id: new ObjectID(vaultTx._id), + }, + vaultTx, + { + w: 1, + upsert: false, + }, + cb, + ); +}; - return cb(null, result); - }); +Storage.prototype.fetchVaultByInitialTxId = function(txId, cb) { + this.db.collection(collections.VAULTS).findOne( + { + initialTxId: txId, + }, + function(err, result) { + if (err) return cb(err); + if (!result) return cb(); + + return cb(null, result); + }, + ); }; -Storage.prototype.fetchVaultById = function (id, cb) { - this.db.collection(collections.VAULTS).findOne({ - _id: new ObjectID(id), - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(); +Storage.prototype.fetchVaultById = function(id, cb) { + this.db.collection(collections.VAULTS).findOne( + { + _id: new ObjectID(id), + }, + function(err, result) { + if (err) return cb(err); + if (!result) return cb(); - return cb(null, result); - }); + return cb(null, result); + }, + ); }; -Storage.prototype.fetchVaultByCopayerId = function (copayerId, id, cb) { - this.db.collection(collections.VAULTS).findOne({ - copayerId, - _id: new ObjectID(id), - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(); +Storage.prototype.fetchVaultByCopayerId = function(copayerId, id, cb) { + this.db.collection(collections.VAULTS).findOne( + { + copayerId, + _id: new ObjectID(id), + }, + function(err, result) { + if (err) return cb(err); + if (!result) return cb(); - return cb(null, result); - }); + return cb(null, result); + }, + ); }; -Storage.prototype.setVaultConfirmed = function (tx, txId, cb) { +Storage.prototype.setVaultConfirmed = function(tx, txId, cb) { tx.status = Meritcore.Vault.Vault.VaultStates.APPROVED; - this.db.collection(collections.VAULTS).update({ - initialTxId: tx.initialTxId, - }, tx, { - w: 1, - upsert: false, - }, cb); -}; - -Storage.prototype.registerGlobalSend = function (walletAddress, scriptAddress, globalsend, cb) { - this.db.collection(collections.GLOBALSENDS).insertOne({ - walletAddress, - scriptAddress, - globalsend - }, { - w: 1 - }, cb); -}; - -Storage.prototype.cancelGlobalSend = function (walletAddress, scriptAddress, cb) { - - this.db.collection(collections.GLOBALSENDS).findOneAndUpdate({ - walletAddress, - scriptAddress - }, { - $set: { - cancelled: true - } - }, { - w: 1, - upsert: false - }, cb); -}; - -Storage.prototype.getGlobalSends = function (walletAddress, cb) { - this.db.collection(collections.GLOBALSENDS).find({ - walletAddress - }).toArray(function (err, result) { - if (err) return cb(err); - return cb(null, result); - }); + this.db.collection(collections.VAULTS).update( + { + initialTxId: tx.initialTxId, + }, + tx, + { + w: 1, + upsert: false, + }, + cb, + ); }; -Storage.prototype.checkKnownMessages = function (data, cb) { - this.db.collection(collections.KNOWN_MESSAGES).findOneAndUpdate(data, data, { - readPreference: mongodb.ReadPreference.PRIMARY, - w: "majority", - writeConcern: { - w: "majority", - wtimeout: 5000 +Storage.prototype.registerGlobalSend = function(walletAddress, scriptAddress, globalsend, cb) { + this.db.collection(collections.GLOBALSENDS).insertOne( + { + walletAddress, + scriptAddress, + globalsend, }, - new: true, - returnOriginal: false, - upsert: true, - }, function (err, result) { - if (err) return cb(err); - return cb(null, result && result.lastErrorObject && result.lastErrorObject.updatedExisting && result.value && result.ok); - }); + { + w: 1, + }, + cb, + ); }; -Storage.prototype.getLeaderboard = function (limit, cb) { - this.db.collection(collections.LEADERBOARD).findOne({ - limit: parseInt(limit), - }, function (err, result) { - if (err) return cb(err); - if (!result) return cb(); - return cb(null, result); - }); +Storage.prototype.cancelGlobalSend = function(walletAddress, scriptAddress, cb) { + this.db.collection(collections.GLOBALSENDS).findOneAndUpdate( + { + walletAddress, + scriptAddress, + }, + { + $set: { + cancelled: true, + }, + }, + { + w: 1, + upsert: false, + }, + cb, + ); +}; + +Storage.prototype.getGlobalSends = function(walletAddress, cb) { + this.db + .collection(collections.GLOBALSENDS) + .find({ + walletAddress, + }) + .toArray(function(err, result) { + if (err) return cb(err); + return cb(null, result); + }); +}; + +Storage.prototype.checkKnownMessages = function(data, cb) { + this.db.collection(collections.KNOWN_MESSAGES).findOneAndUpdate( + data, + data, + { + readPreference: mongodb.ReadPreference.PRIMARY, + w: 'majority', + writeConcern: { + w: 'majority', + wtimeout: 5000, + }, + new: true, + returnOriginal: false, + upsert: true, + }, + function(err, result) { + if (err) return cb(err); + return cb( + null, + result && result.lastErrorObject && result.lastErrorObject.updatedExisting && result.value && result.ok, + ); + }, + ); +}; + +Storage.prototype.getLeaderboard = function(limit, cb) { + this.db.collection(collections.LEADERBOARD).findOne( + { + limit: parseInt(limit), + }, + function(err, result) { + if (err) return cb(err); + if (!result) return cb(); + return cb(null, result); + }, + ); }; Storage.collections = collections; diff --git a/packages/merit-wallet-service/meritnode/index.js b/packages/merit-wallet-service/meritnode/index.js index fd2399bd14..1c395a7993 100644 --- a/packages/merit-wallet-service/meritnode/index.js +++ b/packages/merit-wallet-service/meritnode/index.js @@ -41,7 +41,7 @@ function Service(options) { this.lockerPort = baseConfig.lockOpts.lockerServer.port; } this.lockerPort = options.lockerPort || this.lockerPort; -}; +} util.inherits(Service, EventEmitter); @@ -66,7 +66,7 @@ Service.prototype._readHttpsOptions = function() { serverOpts.ca = [ fs.readFileSync(this.httpsOptions.CAinter1), fs.readFileSync(this.httpsOptions.CAinter2), - fs.readFileSync(this.httpsOptions.CAroot) + fs.readFileSync(this.httpsOptions.CAroot), ]; } return serverOpts; @@ -83,7 +83,7 @@ Service.prototype._getConfiguration = function() { var providerOptions = { provider: 'insight', url: (self.node.https ? 'https://' : 'http://') + 'localhost:' + self.node.port, - apiPrefix: '/insight-api' + apiPrefix: '/insight-api', }; // A merit-node is either livenet or testnet, so we'll pass @@ -91,18 +91,17 @@ Service.prototype._getConfiguration = function() { // instance of the insight-api service. if (self.node.network === Networks.livenet) { baseConfig.blockchainExplorerOpts = { - livenet: providerOptions + livenet: providerOptions, }; } else if (self.node.network === Networks.testnet) { baseConfig.blockchainExplorerOpts = { - testnet: providerOptions + testnet: providerOptions, }; } else { throw new Error('Unknown network'); } return baseConfig; - }; /** @@ -119,7 +118,7 @@ Service.prototype._startWalletService = function(config, next) { self.server = http.Server(expressApp.app); } - expressApp.start(config, function(err){ + expressApp.start(config, function(err) { if (err) { return next(err); } @@ -131,7 +130,6 @@ Service.prototype._startWalletService = function(config, next) { * Called by the node to start the service */ Service.prototype.start = function(done) { - var self = this; var config; try { @@ -152,44 +150,45 @@ Service.prototype.start = function(done) { }); }); - async.series([ - - function(next) { - // Blockchain Monitor - var blockChainMonitor = new BlockchainMonitor(); - blockChainMonitor.start(config, next); - }, - function(next) { - // Email Service - if (config.emailOpts) { - var emailService = new EmailService(); - emailService.start(config, next); - } else { - setImmediate(next); - } - }, - function(next) { - // Push notification service - if (config.pushNotificationsOpts) { - var pushNotificationService = new PushNotificationService(); - pushNotificationService.start(config, next); - } else { - setImmediate(next); - } - }, - function(next) { - if (config.smsOpts.enabled) { - // Start SMS Notifications service - new SmsService(config); - } - - next(); - }, - function(next) { - self._startWalletService(config, next); - } - ], done); - + async.series( + [ + function(next) { + // Blockchain Monitor + var blockChainMonitor = new BlockchainMonitor(); + blockChainMonitor.start(config, next); + }, + function(next) { + // Email Service + if (config.emailOpts) { + var emailService = new EmailService(); + emailService.start(config, next); + } else { + setImmediate(next); + } + }, + function(next) { + // Push notification service + if (config.pushNotificationsOpts) { + var pushNotificationService = new PushNotificationService(); + pushNotificationService.start(config, next); + } else { + setImmediate(next); + } + }, + function(next) { + if (config.smsOpts.enabled) { + // Start SMS Notifications service + new SmsService(config); + } + + next(); + }, + function(next) { + self._startWalletService(config, next); + }, + ], + done, + ); }; /** diff --git a/packages/merit-wallet-service/messagebroker/messagebroker.js b/packages/merit-wallet-service/messagebroker/messagebroker.js index d48dc637b5..82058ba6fb 100644 --- a/packages/merit-wallet-service/messagebroker/messagebroker.js +++ b/packages/merit-wallet-service/messagebroker/messagebroker.js @@ -20,4 +20,4 @@ server.on('connection', function(socket) { }); }); -console.log('Message broker server listening on port ' + opts.port) +console.log('Message broker server listening on port ' + opts.port); diff --git a/packages/merit-wallet-service/mws.js b/packages/merit-wallet-service/mws.js index b219be63ea..1142cfbb13 100755 --- a/packages/merit-wallet-service/mws.js +++ b/packages/merit-wallet-service/mws.js @@ -9,9 +9,6 @@ var log = require('npmlog'); log.debug = log.verbose; log.disableColor(); - - - var port = process.env.MWS_PORT || config.port || 3232; var cluster = require('cluster'); @@ -28,15 +25,16 @@ if (config.https) { if (config.ciphers) { serverOpts.ciphers = config.ciphers; serverOpts.honorCipherOrder = true; - }; + } // This sets the intermediate CA certs only if they have all been designated in the config.js if (config.CAinter1 && config.CAinter2 && config.CAroot) { - serverOpts.ca = [fs.readFileSync(config.CAinter1), + serverOpts.ca = [ + fs.readFileSync(config.CAinter1), fs.readFileSync(config.CAinter2), - fs.readFileSync(config.CAroot) + fs.readFileSync(config.CAroot), ]; - }; + } } if (config.cluster && !config.lockOpts.lockerServer) @@ -48,11 +46,13 @@ if (config.cluster && !config.messageBrokerOpts.messageBrokerServer) var expressApp = new ExpressApp(); function startInstance(cb) { - var server = config.https ? serverModule.createServer(serverOpts, expressApp.app) : serverModule.Server(expressApp.app); + var server = config.https + ? serverModule.createServer(serverOpts, expressApp.app) + : serverModule.Server(expressApp.app); server.on('connection', function(socket) { socket.setTimeout(300 * 1000); - }) + }); expressApp.start(config, function(err) { if (err) { @@ -64,13 +64,12 @@ function startInstance(cb) { var instanceInfo = cluster.worker ? ' [Instance:' + cluster.worker.id + ']' : ''; log.info('MWS running ' + instanceInfo); - log.debug("We have a Merit Node: ", this.node); + log.debug('We have a Merit Node: ', this.node); return; }); -}; +} if (config.cluster && cluster.isMaster) { - log.info('Starting ' + clusterInstances + ' instances'); // Create a worker for each CPU @@ -88,4 +87,4 @@ if (config.cluster && cluster.isMaster) { } else { log.info('Listening on port: ' + port); startInstance(); -}; +} diff --git a/packages/merit-wallet-service/scripts/level2mongo.js b/packages/merit-wallet-service/scripts/level2mongo.js index f7ea2bd7e4..4e85f29fc8 100644 --- a/packages/merit-wallet-service/scripts/level2mongo.js +++ b/packages/merit-wallet-service/scripts/level2mongo.js @@ -9,10 +9,11 @@ var level = new LevelStorage({ }); var mongo = new MongoStorage(); -mongo.connect({ +mongo.connect( + { mongoDb: { uri: 'mongodb://localhost:27017/bws', - } + }, }, function(err) { if (err) throw err; @@ -24,13 +25,14 @@ mongo.connect({ // process.exit(0); // }); }); - }); - + }, +); function run(cb) { var pending = 0, ended = false; - level.db.readStream() + level.db + .readStream() .on('data', function(data) { pending++; migrate(data.key, data.value, function(err) { @@ -45,13 +47,13 @@ function run(cb) { return cb(err); }) .on('end', function() { - console.log('All old data read') + console.log('All old data read'); ended = true; if (!pending) { return cb(); } }); -}; +} function migrate(key, value, cb) { if (key.match(/^copayer!/)) { @@ -72,4 +74,4 @@ function migrate(key, value, cb) { } else { return cb(new Error('Invalid key ' + key)); } -}; +} diff --git a/packages/merit-wallet-service/test/blockchainexplorer.js b/packages/merit-wallet-service/test/blockchainexplorer.js index bab8fb1ae9..e38a0ca851 100644 --- a/packages/merit-wallet-service/test/blockchainexplorer.js +++ b/packages/merit-wallet-service/test/blockchainexplorer.js @@ -32,7 +32,7 @@ describe('Blockchain explorer', function() { var exp = new BlockchainExplorer({ provider: 'dummy', }); - }).should.throw('not supported'); + }.should.throw('not supported')); }); }); }); diff --git a/packages/merit-wallet-service/test/expressapp.js b/packages/merit-wallet-service/test/expressapp.js index d437297e4e..22bfe19455 100644 --- a/packages/merit-wallet-service/test/expressapp.js +++ b/packages/merit-wallet-service/test/expressapp.js @@ -11,8 +11,6 @@ var config = require('../config.js'); var Common = require('../lib/common'); var Defaults = Common.Defaults; - - describe('ExpressApp', function() { describe('#constructor', function() { it('will set an express app', function() { @@ -28,8 +26,8 @@ describe('ExpressApp', function() { var initialize = sinon.stub().callsArg(1); var TestExpressApp = proxyquire('../lib/expressapp', { './server': { - initialize: initialize - } + initialize: initialize, + }, }); var app = new TestExpressApp(); var options = {}; @@ -54,7 +52,7 @@ describe('ExpressApp', function() { httpServer.listen(testPort); done(); }); - }; + } afterEach(function() { httpServer.close(); @@ -68,15 +66,15 @@ describe('ExpressApp', function() { './server': { initialize: sinon.stub().callsArg(1), getInstanceWithAuth: sinon.stub().callsArgWith(1, null, server), - } + }, }); start(TestExpressApp, function() { var requestOptions = { url: testHost + ':' + testPort + config.basePath + '/v2/wallets', headers: { 'x-identity': 'identity', - 'x-signature': 'signature' - } + 'x-signature': 'signature', + }, }; request(requestOptions, function(err, res, body) { should.not.exist(err); @@ -97,15 +95,15 @@ describe('ExpressApp', function() { './server': { initialize: sinon.stub().callsArg(1), getInstanceWithAuth: sinon.stub().callsArgWith(1, null, server), - } + }, }); start(TestExpressApp, function() { var requestOptions = { url: testHost + ':' + testPort + config.basePath + '/v1/addresses?limit=4&reverse=1', headers: { 'x-identity': 'identity', - 'x-signature': 'signature' - } + 'x-signature': 'signature', + }, }; request(requestOptions, function(err, res, body) { should.not.exist(err); @@ -121,22 +119,22 @@ describe('ExpressApp', function() { it('/v1/sendmaxinfo', function(done) { var server = { getSendMaxInfo: sinon.stub().callsArgWith(1, null, { - amount: 123 + amount: 123, }), }; var TestExpressApp = proxyquire('../lib/expressapp', { './server': { initialize: sinon.stub().callsArg(1), getInstanceWithAuth: sinon.stub().callsArgWith(1, null, server), - } + }, }); start(TestExpressApp, function() { var requestOptions = { url: testHost + ':' + testPort + config.basePath + '/v1/sendmaxinfo?feePerKb=10000&returnInputs=1', headers: { 'x-identity': 'identity', - 'x-signature': 'signature' - } + 'x-signature': 'signature', + }, }; request(requestOptions, function(err, res, body) { should.not.exist(err); @@ -159,15 +157,15 @@ describe('ExpressApp', function() { './server': { initialize: sinon.stub().callsArg(1), getInstanceWithAuth: sinon.stub().callsArgWith(1, null, server), - } + }, }); start(TestExpressApp, function() { var reqOpts = { url: testHost + ':' + testPort + config.basePath + '/v1/balance', headers: { 'x-identity': 'identity', - 'x-signature': 'signature' - } + 'x-signature': 'signature', + }, }; request(reqOpts, function(err, res, body) { should.not.exist(err); @@ -194,13 +192,13 @@ describe('ExpressApp', function() { clock = sinon.useFakeTimers(2000000000, 'Date'); server = { - getNotifications: sinon.stub().callsArgWith(1, null, {}) + getNotifications: sinon.stub().callsArgWith(1, null, {}), }; TestExpressApp = proxyquire('../lib/expressapp', { './server': { initialize: sinon.stub().callsArg(1), getInstanceWithAuth: sinon.stub().callsArgWith(1, null, server), - } + }, }); }); afterEach(function() { @@ -213,8 +211,8 @@ describe('ExpressApp', function() { url: testHost + ':' + testPort + config.basePath + '/v1/notifications' + '?notificationId=123', headers: { 'x-identity': 'identity', - 'x-signature': 'signature' - } + 'x-signature': 'signature', + }, }; request(requestOptions, function(err, res, body) { should.not.exist(err); @@ -234,8 +232,8 @@ describe('ExpressApp', function() { url: testHost + ':' + testPort + config.basePath + '/v1/notifications' + '?timeSpan=30', headers: { 'x-identity': 'identity', - 'x-signature': 'signature' - } + 'x-signature': 'signature', + }, }; request(requestOptions, function(err, res, body) { should.not.exist(err); @@ -250,13 +248,13 @@ describe('ExpressApp', function() { }); it('should limit minTs to Defaults.MAX_NOTIFICATIONS_TIMESPAN', function(done) { start(TestExpressApp, function() { - var overLimit = Defaults.MAX_NOTIFICATIONS_TIMESPAN * 2; + var overLimit = Defaults.MAX_NOTIFICATIONS_TIMESPAN * 2; var requestOptions = { - url: testHost + ':' + testPort + config.basePath + '/v1/notifications' + '?timeSpan=' + overLimit , + url: testHost + ':' + testPort + config.basePath + '/v1/notifications' + '?timeSpan=' + overLimit, headers: { 'x-identity': 'identity', - 'x-signature': 'signature' - } + 'x-signature': 'signature', + }, }; request(requestOptions, function(err, res, body) { should.not.exist(err); diff --git a/packages/merit-wallet-service/test/integration/bcmonitor.js b/packages/merit-wallet-service/test/integration/bcmonitor.js index 3af6eb4cce..41d340222c 100644 --- a/packages/merit-wallet-service/test/integration/bcmonitor.js +++ b/packages/merit-wallet-service/test/integration/bcmonitor.js @@ -44,18 +44,21 @@ describe('Blockchain monitor', function() { wallet = w; var bcmonitor = new BlockchainMonitor(); - bcmonitor.start({ - lockOpts: {}, - messageBroker: server.messageBroker, - storage: storage, - blockchainExplorers: { - 'testnet': blockchainExplorer, - 'livenet': blockchainExplorer + bcmonitor.start( + { + lockOpts: {}, + messageBroker: server.messageBroker, + storage: storage, + blockchainExplorers: { + testnet: blockchainExplorer, + livenet: blockchainExplorer, + }, }, - }, function(err) { - should.not.exist(err); - done(); - }); + function(err) { + should.not.exist(err); + done(); + }, + ); }); }); }); @@ -75,7 +78,7 @@ describe('Blockchain monitor', function() { server.getNotifications({}, function(err, notifications) { should.not.exist(err); var notification = _.find(notifications, { - type: 'IncomingTx' + type: 'IncomingTx', }); should.exist(notification); notification.walletId.should.equal(wallet.id); @@ -105,7 +108,7 @@ describe('Blockchain monitor', function() { server.getNotifications({}, function(err, notifications) { should.not.exist(err); var notification = _.filter(notifications, { - type: 'IncomingTx' + type: 'IncomingTx', }); notification.length.should.equal(1); done(); @@ -125,34 +128,37 @@ describe('Blockchain monitor', function() { }; incoming.vout[0][address.address] = 1500; - server.txConfirmationSubscribe({ - txid: '123' - }, function(err) { - should.not.exist(err); - - blockchainExplorer.getBlock = sinon.stub().callsArgWith(1, null, ['123', '456']); - socket.handlers['block']('block1'); + server.txConfirmationSubscribe( + { + txid: '123', + }, + function(err) { + should.not.exist(err); - setTimeout(function() { blockchainExplorer.getBlock = sinon.stub().callsArgWith(1, null, ['123', '456']); - socket.handlers['block']('block2'); + socket.handlers['block']('block1'); setTimeout(function() { - server.getNotifications({}, function(err, notifications) { - should.not.exist(err); - var notifications = _.filter(notifications, { - type: 'TxConfirmation' + blockchainExplorer.getBlock = sinon.stub().callsArgWith(1, null, ['123', '456']); + socket.handlers['block']('block2'); + + setTimeout(function() { + server.getNotifications({}, function(err, notifications) { + should.not.exist(err); + var notifications = _.filter(notifications, { + type: 'TxConfirmation', + }); + notifications.length.should.equal(1); + var n = notifications[0]; + n.walletId.should.equal(wallet.id); + n.creatorId.should.equal(server.copayerId); + n.data.txid.should.equal('123'); + done(); }); - notifications.length.should.equal(1); - var n = notifications[0]; - n.walletId.should.equal(wallet.id); - n.creatorId.should.equal(server.copayerId); - n.data.txid.should.equal('123'); - done(); - }); + }, 50); }, 50); - }, 50); - }); + }, + ); }); }); }); diff --git a/packages/merit-wallet-service/test/integration/emailnotifications.js b/packages/merit-wallet-service/test/integration/emailnotifications.js index b3e2f66413..8f4cba688f 100644 --- a/packages/merit-wallet-service/test/integration/emailnotifications.js +++ b/packages/merit-wallet-service/test/integration/emailnotifications.js @@ -33,39 +33,49 @@ describe('Email notifications', function() { wallet = w; var i = 0; - async.eachSeries(w.copayers, function(copayer, next) { - helpers.getAuthServer(copayer.id, function(server) { - server.savePreferences({ - email: 'copayer' + (++i) + '@domain.com', - unit: 'bit', - }, next); - }); - }, function(err) { - should.not.exist(err); + async.eachSeries( + w.copayers, + function(copayer, next) { + helpers.getAuthServer(copayer.id, function(server) { + server.savePreferences( + { + email: 'copayer' + ++i + '@domain.com', + unit: 'bit', + }, + next, + ); + }); + }, + function(err) { + should.not.exist(err); - mailerStub = sinon.stub(); - mailerStub.sendMail = sinon.stub(); - mailerStub.sendMail.yields(); - - emailService = new EmailService(); - emailService.start({ - lockOpts: {}, - messageBroker: server.messageBroker, - storage: helpers.getStorage(), - mailer: mailerStub, - emailOpts: { - from: 'bws@dummy.net', - subjectPrefix: '[test wallet]', - publicTxUrlTemplate: { - livenet: 'https://insight.bitpay.com/tx/{{txid}}', - testnet: 'https://test-insight.bitpay.com/tx/{{txid}}', + mailerStub = sinon.stub(); + mailerStub.sendMail = sinon.stub(); + mailerStub.sendMail.yields(); + + emailService = new EmailService(); + emailService.start( + { + lockOpts: {}, + messageBroker: server.messageBroker, + storage: helpers.getStorage(), + mailer: mailerStub, + emailOpts: { + from: 'bws@dummy.net', + subjectPrefix: '[test wallet]', + publicTxUrlTemplate: { + livenet: 'https://insight.bitpay.com/tx/{{txid}}', + testnet: 'https://test-insight.bitpay.com/tx/{{txid}}', + }, + }, }, - }, - }, function(err) { - should.not.exist(err); - done(); - }); - }); + function(err) { + should.not.exist(err); + done(); + }, + ); + }, + ); }); }); }); @@ -81,11 +91,13 @@ describe('Email notifications', function() { }; helpers.stubUtxos(server, wallet, [1, 1], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], - feePerKb: 100e2 + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], + feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { setTimeout(function() { @@ -118,11 +130,13 @@ describe('Email notifications', function() { }; helpers.stubUtxos(server, wallet, [1, 1], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], - feePerKb: 100e2 + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], + feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { setTimeout(function() { @@ -150,204 +164,171 @@ describe('Email notifications', function() { }; helpers.stubUtxos(server, wallet, [1, 1], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], - feePerKb: 100e2 + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], + feePerKb: 100e2, }; var txp; - async.waterfall([ - - function(next) { - helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { - next(null, tx); - }); - }, - function(t, next) { - txp = t; - async.eachSeries(_.range(2), function(i, next) { - var copayer = TestData.copayers[i]; - helpers.getAuthServer(copayer.id44, function(server) { - var signatures = helpers.clientSign(txp, copayer.xPrivKey_44H_0H_0H); - server.signTx({ + async.waterfall( + [ + function(next) { + helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { + next(null, tx); + }); + }, + function(t, next) { + txp = t; + async.eachSeries( + _.range(2), + function(i, next) { + var copayer = TestData.copayers[i]; + helpers.getAuthServer(copayer.id44, function(server) { + var signatures = helpers.clientSign(txp, copayer.xPrivKey_44H_0H_0H); + server.signTx( + { + txProposalId: txp.id, + signatures: signatures, + }, + function(err, t) { + txp = t; + next(); + }, + ); + }); + }, + next, + ); + }, + function(next) { + helpers.stubBroadcast(); + server.broadcastTx( + { txProposalId: txp.id, - signatures: signatures, - }, function(err, t) { - txp = t; - next(); - }); + }, + next, + ); + }, + ], + function(err) { + should.not.exist(err); + + setTimeout(function() { + var calls = mailerStub.sendMail.getCalls(); + var emails = _.map(_.takeRight(calls, 3), function(c) { + return c.args[0]; }); - }, next); - }, - function(next) { - helpers.stubBroadcast(); - server.broadcastTx({ - txProposalId: txp.id, - }, next); + _.difference( + ['copayer1@domain.com', 'copayer2@domain.com', 'copayer3@domain.com'], + _.map(emails, 'to'), + ).should.be.empty; + var one = emails[0]; + one.from.should.equal('bws@dummy.net'); + one.subject.should.contain('Payment sent'); + one.text.should.contain('800,000'); + should.exist(one.html); + one.html.should.contain('https://insight.bitpay.com/tx/' + txp.txid); + server.storage.fetchUnsentEmails(function(err, unsent) { + should.not.exist(err); + unsent.should.be.empty; + emailService._readTemplateFile = _readTemplateFile_old; + done(); + }); + }, 100); }, - ], function(err) { - should.not.exist(err); - - setTimeout(function() { - var calls = mailerStub.sendMail.getCalls(); - var emails = _.map(_.takeRight(calls, 3), function(c) { - return c.args[0]; - }); - _.difference(['copayer1@domain.com', 'copayer2@domain.com', 'copayer3@domain.com'], _.map(emails, 'to')).should.be.empty; - var one = emails[0]; - one.from.should.equal('bws@dummy.net'); - one.subject.should.contain('Payment sent'); - one.text.should.contain('800,000'); - should.exist(one.html); - one.html.should.contain('https://insight.bitpay.com/tx/' + txp.txid); - server.storage.fetchUnsentEmails(function(err, unsent) { - should.not.exist(err); - unsent.should.be.empty; - emailService._readTemplateFile = _readTemplateFile_old; - done(); - }); - }, 100); - }); + ); }); }); it('should notify copayers a tx has been finally rejected', function(done) { helpers.stubUtxos(server, wallet, 1, function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], - feePerKb: 100e2 + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], + feePerKb: 100e2, }; var txpId; - async.waterfall([ - - function(next) { - helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { - next(null, tx); - }); - }, - function(txp, next) { - txpId = txp.id; - async.eachSeries(_.range(1, 3), function(i, next) { - var copayer = TestData.copayers[i]; - helpers.getAuthServer(copayer.id44, function(server) { - server.rejectTx({ - txProposalId: txp.id, - }, next); + async.waterfall( + [ + function(next) { + helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { + next(null, tx); }); - }, next); - }, - ], function(err) { - should.not.exist(err); - - setTimeout(function() { - var calls = mailerStub.sendMail.getCalls(); - var emails = _.map(_.takeRight(calls, 2), function(c) { - return c.args[0]; - }); - _.difference(['copayer1@domain.com', 'copayer2@domain.com'], _.map(emails, 'to')).should.be.empty; - var one = emails[0]; - one.from.should.equal('bws@dummy.net'); - one.subject.should.contain('Payment proposal rejected'); - server.storage.fetchUnsentEmails(function(err, unsent) { - should.not.exist(err); - unsent.should.be.empty; - done(); - }); - }, 100); - }); - }); - }); - - it('should notify copayers of incoming txs', function(done) { - server.createAddress({}, function(err, address) { - should.not.exist(err); - - // Simulate incoming tx notification - server._notify('IncomingTx', { - txid: '999', - address: address, - amount: 12300000, - }, function(err) { - setTimeout(function() { - var calls = mailerStub.sendMail.getCalls(); - calls.length.should.equal(3); - var emails = _.map(calls, function(c) { - return c.args[0]; - }); - _.difference(['copayer1@domain.com', 'copayer2@domain.com', 'copayer3@domain.com'], _.map(emails, 'to')).should.be.empty; - var one = emails[0]; - one.from.should.equal('bws@dummy.net'); - one.subject.should.contain('New payment received'); - one.text.should.contain('123,000'); - server.storage.fetchUnsentEmails(function(err, unsent) { - should.not.exist(err); - unsent.should.be.empty; - done(); - }); - }, 100); - }); - }); - }); - - it('should notify copayers when tx is confirmed if they are subscribed', function(done) { - server.createAddress({}, function(err, address) { - should.not.exist(err); - - server.txConfirmationSubscribe({ - txid: '123' - }, function(err) { - should.not.exist(err); + }, + function(txp, next) { + txpId = txp.id; + async.eachSeries( + _.range(1, 3), + function(i, next) { + var copayer = TestData.copayers[i]; + helpers.getAuthServer(copayer.id44, function(server) { + server.rejectTx( + { + txProposalId: txp.id, + }, + next, + ); + }); + }, + next, + ); + }, + ], + function(err) { + should.not.exist(err); - // Simulate tx confirmation notification - server._notify('TxConfirmation', { - txid: '123', - }, function(err) { setTimeout(function() { var calls = mailerStub.sendMail.getCalls(); - calls.length.should.equal(1); - var email = calls[0].args[0]; - email.to.should.equal('copayer1@domain.com'); - email.from.should.equal('bws@dummy.net'); - email.subject.should.contain('Transaction confirmed'); + var emails = _.map(_.takeRight(calls, 2), function(c) { + return c.args[0]; + }); + _.difference(['copayer1@domain.com', 'copayer2@domain.com'], _.map(emails, 'to')).should.be.empty; + var one = emails[0]; + one.from.should.equal('bws@dummy.net'); + one.subject.should.contain('Payment proposal rejected'); server.storage.fetchUnsentEmails(function(err, unsent) { should.not.exist(err); unsent.should.be.empty; done(); }); }, 100); - }); - }); + }, + ); }); }); + it('should notify copayers of incoming txs', function(done) { + server.createAddress({}, function(err, address) { + should.not.exist(err); - it('should notify each email address only once', function(done) { - // Set same email address for copayer1 and copayer2 - server.savePreferences({ - email: 'copayer2@domain.com', - }, function(err) { - server.createAddress({}, function(err, address) { - should.not.exist(err); - - // Simulate incoming tx notification - server._notify('IncomingTx', { + // Simulate incoming tx notification + server._notify( + 'IncomingTx', + { txid: '999', address: address, amount: 12300000, - }, function(err) { + }, + function(err) { setTimeout(function() { var calls = mailerStub.sendMail.getCalls(); - calls.length.should.equal(2); + calls.length.should.equal(3); var emails = _.map(calls, function(c) { return c.args[0]; }); - _.difference(['copayer2@domain.com', 'copayer3@domain.com'], _.map(emails, 'to')).should.be.empty; + _.difference( + ['copayer1@domain.com', 'copayer2@domain.com', 'copayer3@domain.com'], + _.map(emails, 'to'), + ).should.be.empty; var one = emails[0]; one.from.should.equal('bws@dummy.net'); one.subject.should.contain('New payment received'); @@ -358,85 +339,178 @@ describe('Email notifications', function() { done(); }); }, 100); - }); - }); + }, + ); + }); + }); + + it('should notify copayers when tx is confirmed if they are subscribed', function(done) { + server.createAddress({}, function(err, address) { + should.not.exist(err); + + server.txConfirmationSubscribe( + { + txid: '123', + }, + function(err) { + should.not.exist(err); + + // Simulate tx confirmation notification + server._notify( + 'TxConfirmation', + { + txid: '123', + }, + function(err) { + setTimeout(function() { + var calls = mailerStub.sendMail.getCalls(); + calls.length.should.equal(1); + var email = calls[0].args[0]; + email.to.should.equal('copayer1@domain.com'); + email.from.should.equal('bws@dummy.net'); + email.subject.should.contain('Transaction confirmed'); + server.storage.fetchUnsentEmails(function(err, unsent) { + should.not.exist(err); + unsent.should.be.empty; + done(); + }); + }, 100); + }, + ); + }, + ); }); }); + it('should notify each email address only once', function(done) { + // Set same email address for copayer1 and copayer2 + server.savePreferences( + { + email: 'copayer2@domain.com', + }, + function(err) { + server.createAddress({}, function(err, address) { + should.not.exist(err); + + // Simulate incoming tx notification + server._notify( + 'IncomingTx', + { + txid: '999', + address: address, + amount: 12300000, + }, + function(err) { + setTimeout(function() { + var calls = mailerStub.sendMail.getCalls(); + calls.length.should.equal(2); + var emails = _.map(calls, function(c) { + return c.args[0]; + }); + _.difference(['copayer2@domain.com', 'copayer3@domain.com'], _.map(emails, 'to')).should.be.empty; + var one = emails[0]; + one.from.should.equal('bws@dummy.net'); + one.subject.should.contain('New payment received'); + one.text.should.contain('123,000'); + server.storage.fetchUnsentEmails(function(err, unsent) { + should.not.exist(err); + unsent.should.be.empty; + done(); + }); + }, 100); + }, + ); + }); + }, + ); + }); + it('should build each email using preferences of the copayers', function(done) { // Set same email address for copayer1 and copayer2 - server.savePreferences({ - email: 'copayer1@domain.com', - language: 'es', - unit: 'mrt', - }, function(err) { - server.createAddress({}, function(err, address) { - should.not.exist(err); - - // Simulate incoming tx notification - server._notify('IncomingTx', { - txid: '999', - address: address, - amount: 12300000, - }, function(err) { - setTimeout(function() { - var calls = mailerStub.sendMail.getCalls(); - calls.length.should.equal(3); - var emails = _.map(calls, function(c) { - return c.args[0]; - }); - var spanish = _.find(emails, { - to: 'copayer1@domain.com' - }); - spanish.from.should.equal('bws@dummy.net'); - spanish.subject.should.contain('Nuevo pago recibido'); - spanish.text.should.contain('0.123 MRT'); - var english = _.find(emails, { - to: 'copayer2@domain.com' - }); - english.from.should.equal('bws@dummy.net'); - english.subject.should.contain('New payment received'); - english.text.should.contain('123,000 bits'); - done(); - }, 100); + server.savePreferences( + { + email: 'copayer1@domain.com', + language: 'es', + unit: 'mrt', + }, + function(err) { + server.createAddress({}, function(err, address) { + should.not.exist(err); + + // Simulate incoming tx notification + server._notify( + 'IncomingTx', + { + txid: '999', + address: address, + amount: 12300000, + }, + function(err) { + setTimeout(function() { + var calls = mailerStub.sendMail.getCalls(); + calls.length.should.equal(3); + var emails = _.map(calls, function(c) { + return c.args[0]; + }); + var spanish = _.find(emails, { + to: 'copayer1@domain.com', + }); + spanish.from.should.equal('bws@dummy.net'); + spanish.subject.should.contain('Nuevo pago recibido'); + spanish.text.should.contain('0.123 MRT'); + var english = _.find(emails, { + to: 'copayer2@domain.com', + }); + english.from.should.equal('bws@dummy.net'); + english.subject.should.contain('New payment received'); + english.text.should.contain('123,000 bits'); + done(); + }, 100); + }, + ); }); - }); - }); + }, + ); }); it('should support multiple emailservice instances running concurrently', function(done) { var emailService2 = new EmailService(); - emailService2.start({ - lock: emailService.lock, // Use same locker service - messageBroker: server.messageBroker, - storage: helpers.getStorage(), - mailer: mailerStub, - emailOpts: { - from: 'bws2@dummy.net', - subjectPrefix: '[test wallet 2]', + emailService2.start( + { + lock: emailService.lock, // Use same locker service + messageBroker: server.messageBroker, + storage: helpers.getStorage(), + mailer: mailerStub, + emailOpts: { + from: 'bws2@dummy.net', + subjectPrefix: '[test wallet 2]', + }, }, - }, function(err) { - helpers.stubUtxos(server, wallet, 1, function() { - var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], - feePerKb: 100e2 - }; - helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { - setTimeout(function() { - var calls = mailerStub.sendMail.getCalls(); - calls.length.should.equal(2); - server.storage.fetchUnsentEmails(function(err, unsent) { - should.not.exist(err); - unsent.should.be.empty; - done(); - }); - }, 100); + function(err) { + helpers.stubUtxos(server, wallet, 1, function() { + var txOpts = { + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], + feePerKb: 100e2, + }; + helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { + setTimeout(function() { + var calls = mailerStub.sendMail.getCalls(); + calls.length.should.equal(2); + server.storage.fetchUnsentEmails(function(err, unsent) { + should.not.exist(err); + unsent.should.be.empty; + done(); + }); + }, 100); + }); }); - }); - }); + }, + ); }); }); @@ -448,50 +522,62 @@ describe('Email notifications', function() { wallet = w; var i = 0; - async.eachSeries(w.copayers, function(copayer, next) { - helpers.getAuthServer(copayer.id, function(server) { - server.savePreferences({ - email: 'copayer' + (++i) + '@domain.com', - unit: 'bit', - }, next); - }); - }, function(err) { - should.not.exist(err); + async.eachSeries( + w.copayers, + function(copayer, next) { + helpers.getAuthServer(copayer.id, function(server) { + server.savePreferences( + { + email: 'copayer' + ++i + '@domain.com', + unit: 'bit', + }, + next, + ); + }); + }, + function(err) { + should.not.exist(err); - mailerStub = sinon.stub(); - mailerStub.sendMail = sinon.stub(); - mailerStub.sendMail.yields(); - - emailService = new EmailService(); - emailService.start({ - lockOpts: {}, - messageBroker: server.messageBroker, - storage: helpers.getStorage(), - mailer: mailerStub, - emailOpts: { - from: 'bws@dummy.net', - subjectPrefix: '[test wallet]', - publicTxUrlTemplate: { - livenet: 'https://insight.bitpay.com/tx/{{txid}}', - testnet: 'https://test-insight.bitpay.com/tx/{{txid}}', + mailerStub = sinon.stub(); + mailerStub.sendMail = sinon.stub(); + mailerStub.sendMail.yields(); + + emailService = new EmailService(); + emailService.start( + { + lockOpts: {}, + messageBroker: server.messageBroker, + storage: helpers.getStorage(), + mailer: mailerStub, + emailOpts: { + from: 'bws@dummy.net', + subjectPrefix: '[test wallet]', + publicTxUrlTemplate: { + livenet: 'https://insight.bitpay.com/tx/{{txid}}', + testnet: 'https://test-insight.bitpay.com/tx/{{txid}}', + }, + }, }, - }, - }, function(err) { - should.not.exist(err); - done(); - }); - }); + function(err) { + should.not.exist(err); + done(); + }, + ); + }, + ); }); }); it('should NOT notify copayers a new tx proposal has been created', function(done) { helpers.stubUtxos(server, wallet, [1, 1], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], - feePerKb: 100e2 + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], + feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { setTimeout(function() { diff --git a/packages/merit-wallet-service/test/integration/fiatrateservice.js b/packages/merit-wallet-service/test/integration/fiatrateservice.js index 7a60e0bc01..6e6ddec379 100644 --- a/packages/merit-wallet-service/test/integration/fiatrateservice.js +++ b/packages/merit-wallet-service/test/integration/fiatrateservice.js @@ -28,268 +28,379 @@ describe('Fiat rate service', function() { service = new FiatRateService(); request = sinon.stub(); request.get = sinon.stub(); - service.init({ - storage: helpers.getStorage(), - request: request, - }, function(err) { - should.not.exist(err); - service.startCron({}, done); - }); + service.init( + { + storage: helpers.getStorage(), + request: request, + }, + function(err) { + should.not.exist(err); + service.startCron({}, done); + }, + ); }); }); describe('#getRate', function() { it('should get current rate', function(done) { - service.storage.storeFiatRate('BitPay', [{ - code: 'USD', - value: 123.45, - }], function(err) { - should.not.exist(err); - service.getRate({ - code: 'USD' - }, function(err, res) { + service.storage.storeFiatRate( + 'BitPay', + [ + { + code: 'USD', + value: 123.45, + }, + ], + function(err) { should.not.exist(err); - res.rate.should.equal(123.45); - done(); - }); - }); + service.getRate( + { + code: 'USD', + }, + function(err, res) { + should.not.exist(err); + res.rate.should.equal(123.45); + done(); + }, + ); + }, + ); }); it('should get current rate for different currency', function(done) { - service.storage.storeFiatRate('BitPay', [{ - code: 'USD', - value: 123.45, - }], function(err) { - should.not.exist(err); - service.storage.storeFiatRate('BitPay', [{ - code: 'EUR', - value: 345.67, - }], function(err) { + service.storage.storeFiatRate( + 'BitPay', + [ + { + code: 'USD', + value: 123.45, + }, + ], + function(err) { should.not.exist(err); - service.getRate({ - code: 'EUR' - }, function(err, res) { - should.not.exist(err); - res.rate.should.equal(345.67); - done(); - }); - }); - }); + service.storage.storeFiatRate( + 'BitPay', + [ + { + code: 'EUR', + value: 345.67, + }, + ], + function(err) { + should.not.exist(err); + service.getRate( + { + code: 'EUR', + }, + function(err, res) { + should.not.exist(err); + res.rate.should.equal(345.67); + done(); + }, + ); + }, + ); + }, + ); }); it('should get current rate for different provider', function(done) { - service.storage.storeFiatRate('BitPay', [{ - code: 'USD', - value: 100.00, - }], function(err) { - should.not.exist(err); - service.storage.storeFiatRate('Bitstamp', [{ - code: 'USD', - value: 200.00, - }], function(err) { + service.storage.storeFiatRate( + 'BitPay', + [ + { + code: 'USD', + value: 100.0, + }, + ], + function(err) { should.not.exist(err); - service.getRate({ - code: 'USD' - }, function(err, res) { - should.not.exist(err); - res.rate.should.equal(100.00, 'Should use default provider'); - service.getRate({ - code: 'USD', - provider: 'Bitstamp', - }, function(err, res) { + service.storage.storeFiatRate( + 'Bitstamp', + [ + { + code: 'USD', + value: 200.0, + }, + ], + function(err) { should.not.exist(err); - res.rate.should.equal(200.00); - done(); - }); - }); - }); - }); + service.getRate( + { + code: 'USD', + }, + function(err, res) { + should.not.exist(err); + res.rate.should.equal(100.0, 'Should use default provider'); + service.getRate( + { + code: 'USD', + provider: 'Bitstamp', + }, + function(err, res) { + should.not.exist(err); + res.rate.should.equal(200.0); + done(); + }, + ); + }, + ); + }, + ); + }, + ); }); it('should get rate for specific ts', function(done) { var clock = sinon.useFakeTimers(0, 'Date'); clock.tick(20); - service.storage.storeFiatRate('BitPay', [{ - code: 'USD', - value: 123.45, - }], function(err) { - should.not.exist(err); - clock.tick(100); - service.storage.storeFiatRate('BitPay', [{ - code: 'USD', - value: 345.67, - }], function(err) { - should.not.exist(err); - service.getRate({ + service.storage.storeFiatRate( + 'BitPay', + [ + { code: 'USD', - ts: 50, - }, function(err, res) { - should.not.exist(err); - res.ts.should.equal(50); - res.rate.should.equal(123.45); - res.fetchedOn.should.equal(20); - clock.restore(); - done(); - }); - }); - }); + value: 123.45, + }, + ], + function(err) { + should.not.exist(err); + clock.tick(100); + service.storage.storeFiatRate( + 'BitPay', + [ + { + code: 'USD', + value: 345.67, + }, + ], + function(err) { + should.not.exist(err); + service.getRate( + { + code: 'USD', + ts: 50, + }, + function(err, res) { + should.not.exist(err); + res.ts.should.equal(50); + res.rate.should.equal(123.45); + res.fetchedOn.should.equal(20); + clock.restore(); + done(); + }, + ); + }, + ); + }, + ); }); it('should get rates for a series of ts', function(done) { var clock = sinon.useFakeTimers(0, 'Date'); - async.each([1.00, 2.00, 3.00, 4.00], function(value, next) { - clock.tick(100); - service.storage.storeFiatRate('BitPay', [{ - code: 'USD', - value: value, - }, { - code: 'EUR', - value: value, - }], next); - }, function(err) { - should.not.exist(err); - service.getRate({ - code: 'USD', - ts: [50, 100, 199, 500], - }, function(err, res) { + async.each( + [1.0, 2.0, 3.0, 4.0], + function(value, next) { + clock.tick(100); + service.storage.storeFiatRate( + 'BitPay', + [ + { + code: 'USD', + value: value, + }, + { + code: 'EUR', + value: value, + }, + ], + next, + ); + }, + function(err) { should.not.exist(err); - res.length.should.equal(4); + service.getRate( + { + code: 'USD', + ts: [50, 100, 199, 500], + }, + function(err, res) { + should.not.exist(err); + res.length.should.equal(4); - res[0].ts.should.equal(50); - should.not.exist(res[0].rate); - should.not.exist(res[0].fetchedOn); + res[0].ts.should.equal(50); + should.not.exist(res[0].rate); + should.not.exist(res[0].fetchedOn); - res[1].ts.should.equal(100); - res[1].rate.should.equal(1.00); - res[1].fetchedOn.should.equal(100); + res[1].ts.should.equal(100); + res[1].rate.should.equal(1.0); + res[1].fetchedOn.should.equal(100); - res[2].ts.should.equal(199); - res[2].rate.should.equal(1.00); - res[2].fetchedOn.should.equal(100); + res[2].ts.should.equal(199); + res[2].rate.should.equal(1.0); + res[2].fetchedOn.should.equal(100); - res[3].ts.should.equal(500); - res[3].rate.should.equal(4.00); - res[3].fetchedOn.should.equal(400); + res[3].ts.should.equal(500); + res[3].rate.should.equal(4.0); + res[3].fetchedOn.should.equal(400); - clock.restore(); - done(); - }); - }); + clock.restore(); + done(); + }, + ); + }, + ); }); it('should not get rate older than 2hs', function(done) { var clock = sinon.useFakeTimers(0, 'Date'); - service.storage.storeFiatRate('BitPay', [{ - code: 'USD', - value: 123.45, - }], function(err) { - should.not.exist(err); - clock.tick(24 * 3600 * 1000); // Some time in the future - service.getRate({ - ts: 2 * 3600 * 1000 - 1, // almost 2 hours - code: 'USD', - }, function(err, res) { - should.not.exist(err); - res.rate.should.equal(123.45); - res.fetchedOn.should.equal(0); - service.getRate({ - ts: 2 * 3600 * 1000 + 1, // just past 2 hours + service.storage.storeFiatRate( + 'BitPay', + [ + { code: 'USD', - }, function(err, res) { - should.not.exist(err); - should.not.exist(res.rate); - clock.restore(); - done(); - }); - }); - }); + value: 123.45, + }, + ], + function(err) { + should.not.exist(err); + clock.tick(24 * 3600 * 1000); // Some time in the future + service.getRate( + { + ts: 2 * 3600 * 1000 - 1, // almost 2 hours + code: 'USD', + }, + function(err, res) { + should.not.exist(err); + res.rate.should.equal(123.45); + res.fetchedOn.should.equal(0); + service.getRate( + { + ts: 2 * 3600 * 1000 + 1, // just past 2 hours + code: 'USD', + }, + function(err, res) { + should.not.exist(err); + should.not.exist(res.rate); + clock.restore(); + done(); + }, + ); + }, + ); + }, + ); }); - }); describe('#fetch', function() { it('should fetch rates from all providers', function(done) { var clock = sinon.useFakeTimers(100, 'Date'); - var bitpay = [{ - code: 'USD', - rate: 123.45, - }, { - code: 'EUR', - rate: 234.56, - }]; + var bitpay = [ + { + code: 'USD', + rate: 123.45, + }, + { + code: 'EUR', + rate: 234.56, + }, + ]; var bitstamp = { - last: 120.00, + last: 120.0, }; - request.get.withArgs({ - url: 'https://bitpay.com/api/rates/', - json: true - }).yields(null, null, bitpay); - request.get.withArgs({ - url: 'https://www.bitstamp.net/api/ticker/', - json: true - }).yields(null, null, bitstamp); + request.get + .withArgs({ + url: 'https://bitpay.com/api/rates/', + json: true, + }) + .yields(null, null, bitpay); + request.get + .withArgs({ + url: 'https://www.bitstamp.net/api/ticker/', + json: true, + }) + .yields(null, null, bitstamp); service._fetch(function(err) { should.not.exist(err); - service.getRate({ - code: 'USD' - }, function(err, res) { - should.not.exist(err); - res.fetchedOn.should.equal(100); - res.rate.should.equal(123.45); - service.getRate({ + service.getRate( + { code: 'USD', - provider: 'Bitstamp', - }, function(err, res) { + }, + function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); - res.rate.should.equal(120.00); - service.getRate({ - code: 'EUR' - }, function(err, res) { - should.not.exist(err); - res.fetchedOn.should.equal(100); - res.rate.should.equal(234.56); - clock.restore(); - done(); - }); - }); - }); + res.rate.should.equal(123.45); + service.getRate( + { + code: 'USD', + provider: 'Bitstamp', + }, + function(err, res) { + should.not.exist(err); + res.fetchedOn.should.equal(100); + res.rate.should.equal(120.0); + service.getRate( + { + code: 'EUR', + }, + function(err, res) { + should.not.exist(err); + res.fetchedOn.should.equal(100); + res.rate.should.equal(234.56); + clock.restore(); + done(); + }, + ); + }, + ); + }, + ); }); }); it('should not stop when failing to fetch provider', function(done) { var clock = sinon.useFakeTimers(100, 'Date'); var bitstamp = { - last: 120.00, + last: 120.0, }; - request.get.withArgs({ - url: 'https://bitpay.com/api/rates/', - json: true - }).yields('dummy error', null, null); - request.get.withArgs({ - url: 'https://www.bitstamp.net/api/ticker/', - json: true - }).yields(null, null, bitstamp); + request.get + .withArgs({ + url: 'https://bitpay.com/api/rates/', + json: true, + }) + .yields('dummy error', null, null); + request.get + .withArgs({ + url: 'https://www.bitstamp.net/api/ticker/', + json: true, + }) + .yields(null, null, bitstamp); service._fetch(function(err) { should.not.exist(err); - service.getRate({ - code: 'USD' - }, function(err, res) { - should.not.exist(err); - res.ts.should.equal(100); - should.not.exist(res.rate) - should.not.exist(res.fetchedOn) - service.getRate({ + service.getRate( + { code: 'USD', - provider: 'Bitstamp' - }, function(err, res) { + }, + function(err, res) { should.not.exist(err); - res.fetchedOn.should.equal(100); - res.rate.should.equal(120.00); - clock.restore(); - done(); - }); - }); + res.ts.should.equal(100); + should.not.exist(res.rate); + should.not.exist(res.fetchedOn); + service.getRate( + { + code: 'USD', + provider: 'Bitstamp', + }, + function(err, res) { + should.not.exist(err); + res.fetchedOn.should.equal(100); + res.rate.should.equal(120.0); + clock.restore(); + done(); + }, + ); + }, + ); }); }); }); diff --git a/packages/merit-wallet-service/test/integration/helpers.js b/packages/merit-wallet-service/test/integration/helpers.js index 3a424583fe..ff7e9b6b73 100644 --- a/packages/merit-wallet-service/test/integration/helpers.js +++ b/packages/merit-wallet-service/test/integration/helpers.js @@ -9,7 +9,7 @@ var should = chai.should(); var log = require('npmlog'); log.debug = log.verbose; var tingodb = require('tingodb')({ - memStore: true + memStore: true, }); var Meritcore = require('meritcore-lib'); @@ -36,10 +36,13 @@ helpers.before = function(cb) { function getDb(cb) { if (useMongoDb) { var mongodb = require('mongodb'); - mongodb.MongoClient.connect('mongodb://localhost:27017/bws_test', function(err, db) { - if (err) throw err; - return cb(db); - }); + mongodb.MongoClient.connect( + 'mongodb://localhost:27017/bws_test', + function(err, db) { + if (err) throw err; + return cb(db); + }, + ); } else { var db = new tingodb.Db('./db/test', {}); return cb(db); @@ -47,14 +50,13 @@ helpers.before = function(cb) { } getDb(function(db) { storage = new Storage({ - db: db + db: db, }); return cb(); }); }; helpers.beforeEach = function(cb) { - if (!storage.db) return cb(); storage.db.dropDatabase(function(err) { if (err) return cb(err); @@ -63,7 +65,7 @@ helpers.beforeEach = function(cb) { var opts = { storage: storage, blockchainExplorer: blockchainExplorer, - request: sinon.stub() + request: sinon.stub(), }; WalletService.initialize(opts, function() { return cb(opts); @@ -97,16 +99,19 @@ helpers.signRequestPubKey = function(requestPubKey, xPrivKey) { helpers.getAuthServer = function(copayerId, cb) { var verifyStub = sinon.stub(WalletService.prototype, '_verifySignature'); verifyStub.returns(true); - WalletService.getInstanceWithAuth({ - copayerId: copayerId, - message: 'dummy', - signature: 'dummy', - clientVersion: helpers.CLIENT_VERSION, - }, function(err, server) { - verifyStub.restore(); - if (err || !server) throw new Error('Could not login as copayerId ' + copayerId + ' err: ' + err); - return cb(server); - }); + WalletService.getInstanceWithAuth( + { + copayerId: copayerId, + message: 'dummy', + signature: 'dummy', + clientVersion: helpers.CLIENT_VERSION, + }, + function(err, server) { + verifyStub.restore(); + if (err || !server) throw new Error('Could not login as copayerId ' + copayerId + ' err: ' + err); + return cb(server); + }, + ); }; helpers._generateCopayersTestData = function(n) { @@ -119,7 +124,10 @@ helpers._generateCopayersTestData = function(n) { var xpub_45H = Meritcore.HDPublicKey(xpriv_45H); var id45 = Copayer._xPubToCopayerId(xpub_45H.toString()); - var xpriv_44H_0H_0H = xpriv.deriveChild(44, true).deriveChild(0, true).deriveChild(0, true); + var xpriv_44H_0H_0H = xpriv + .deriveChild(44, true) + .deriveChild(0, true) + .deriveChild(0, true); var xpub_44H_0H_0H = Meritcore.HDPublicKey(xpriv_44H_0H_0H); var id44 = Copayer._xPubToCopayerId(xpub_44H_0H_0H.toString()); @@ -169,43 +177,47 @@ helpers.createAndJoinWallet = function(m, n, opts, cb) { pubKey: TestData.keyPair.pub, singleAddress: !!opts.singleAddress, }; - if (_.isBoolean(opts.supportBIP44AndP2PKH)) - walletOpts.supportBIP44AndP2PKH = opts.supportBIP44AndP2PKH; + if (_.isBoolean(opts.supportBIP44AndP2PKH)) walletOpts.supportBIP44AndP2PKH = opts.supportBIP44AndP2PKH; server.createWallet(walletOpts, function(err, walletId) { if (err) return cb(err); - async.each(_.range(n), function(i, cb) { - var copayerData = TestData.copayers[i + offset]; - var copayerOpts = helpers.getSignedCopayerOpts({ - walletId: walletId, - name: 'copayer ' + (i + 1), - xPubKey: (_.isBoolean(opts.supportBIP44AndP2PKH) && !opts.supportBIP44AndP2PKH) ? copayerData.xPubKey_45H : copayerData.xPubKey_44H_0H_0H, - requestPubKey: copayerData.pubKey_1H_0, - customData: 'custom data ' + (i + 1), - }); - if (_.isBoolean(opts.supportBIP44AndP2PKH)) - copayerOpts.supportBIP44AndP2PKH = opts.supportBIP44AndP2PKH; + async.each( + _.range(n), + function(i, cb) { + var copayerData = TestData.copayers[i + offset]; + var copayerOpts = helpers.getSignedCopayerOpts({ + walletId: walletId, + name: 'copayer ' + (i + 1), + xPubKey: + _.isBoolean(opts.supportBIP44AndP2PKH) && !opts.supportBIP44AndP2PKH + ? copayerData.xPubKey_45H + : copayerData.xPubKey_44H_0H_0H, + requestPubKey: copayerData.pubKey_1H_0, + customData: 'custom data ' + (i + 1), + }); + if (_.isBoolean(opts.supportBIP44AndP2PKH)) copayerOpts.supportBIP44AndP2PKH = opts.supportBIP44AndP2PKH; - server.joinWallet(copayerOpts, function(err, result) { - should.not.exist(err); - copayerIds.push(result.copayerId); - return cb(err); - }); - }, function(err) { - if (err) return new Error('Could not generate wallet'); - helpers.getAuthServer(copayerIds[0], function(s) { - s.getWallet({}, function(err, w) { - cb(s, w); + server.joinWallet(copayerOpts, function(err, result) { + should.not.exist(err); + copayerIds.push(result.copayerId); + return cb(err); }); - }); - }); + }, + function(err) { + if (err) return new Error('Could not generate wallet'); + helpers.getAuthServer(copayerIds[0], function(s) { + s.getWallet({}, function(err, w) { + cb(s, w); + }); + }); + }, + ); }); }; - helpers.randomTXID = function() { - return Meritcore.crypto.Hash.sha256(new Buffer(Math.random() * 100000)).toString('hex');; + return Meritcore.crypto.Hash.sha256(new Buffer(Math.random() * 100000)).toString('hex'); }; helpers.toMicro = function(mrt) { @@ -241,11 +253,11 @@ helpers._parseAmount = function(str) { break; case 'bit': result.amount = Utils.strip(+match[2] * 1e2); - break + break; case 'micros': result.amount = Utils.strip(+match[2]); break; - }; + } return result; }; @@ -259,65 +271,73 @@ helpers.stubUtxos = function(server, wallet, amounts, opts, cb) { if (!helpers._utxos) helpers._utxos = {}; - async.waterfall([ - - function(next) { - if (opts.addresses) return next(null, [].concat(opts.addresses)); - async.mapSeries(_.range(0, amounts.length > 2 ? 2 : 1), function(i, next) { - server.createAddress({}, next); - }, next); - }, - function(addresses, next) { - addresses.should.not.be.empty; - - var utxos = _.compact(_.map([].concat(amounts), function(amount, i) { - var parsed = helpers._parseAmount(amount); - - if (parsed.amount <= 0) return null; - - var address = addresses[i % addresses.length]; - - var scriptPubKey; - switch (wallet.addressType) { - case Constants.SCRIPT_TYPES.P2SH: - scriptPubKey = Meritcore.Script.buildMultisigOut(address.publicKeys, wallet.m).toScriptHashOut(); - break; - case Constants.SCRIPT_TYPES.P2PKH: - scriptPubKey = Meritcore.Script.buildPublicKeyHashOut(address.address); - break; + async.waterfall( + [ + function(next) { + if (opts.addresses) return next(null, [].concat(opts.addresses)); + async.mapSeries( + _.range(0, amounts.length > 2 ? 2 : 1), + function(i, next) { + server.createAddress({}, next); + }, + next, + ); + }, + function(addresses, next) { + addresses.should.not.be.empty; + + var utxos = _.compact( + _.map([].concat(amounts), function(amount, i) { + var parsed = helpers._parseAmount(amount); + + if (parsed.amount <= 0) return null; + + var address = addresses[i % addresses.length]; + + var scriptPubKey; + switch (wallet.addressType) { + case Constants.SCRIPT_TYPES.P2SH: + scriptPubKey = Meritcore.Script.buildMultisigOut(address.publicKeys, wallet.m).toScriptHashOut(); + break; + case Constants.SCRIPT_TYPES.P2PKH: + scriptPubKey = Meritcore.Script.buildPublicKeyHashOut(address.address); + break; + } + should.exist(scriptPubKey); + + return { + txid: helpers.randomTXID(), + vout: _.random(0, 10), + micros: parsed.amount, + scriptPubKey: scriptPubKey.toBuffer().toString('hex'), + address: address.address, + confirmations: parsed.confirmations, + publicKeys: address.publicKeys, + }; + }), + ); + + if (opts.keepUtxos) { + helpers._utxos = helpers._utxos.concat(utxos); + } else { + helpers._utxos = utxos; } - should.exist(scriptPubKey); - - return { - txid: helpers.randomTXID(), - vout: _.random(0, 10), - micros: parsed.amount, - scriptPubKey: scriptPubKey.toBuffer().toString('hex'), - address: address.address, - confirmations: parsed.confirmations, - publicKeys: address.publicKeys, - }; - })); - - if (opts.keepUtxos) { - helpers._utxos = helpers._utxos.concat(utxos); - } else { - helpers._utxos = utxos; - } - blockchainExplorer.getUtxos = function(addresses, cb) { - var selected = _.filter(helpers._utxos, function(utxo) { - return _.includes(addresses, utxo.address); - }); - return cb(null, selected); - }; + blockchainExplorer.getUtxos = function(addresses, cb) { + var selected = _.filter(helpers._utxos, function(utxo) { + return _.includes(addresses, utxo.address); + }); + return cb(null, selected); + }; - return next(); + return next(); + }, + ], + function(err) { + should.not.exist(err); + return cb(helpers._utxos); }, - ], function(err) { - should.not.exist(err); - return cb(helpers._utxos); - }); + ); }; helpers.stubBroadcast = function(thirdPartyBroadcast) { @@ -335,11 +355,9 @@ helpers.stubHistory = function(txs) { from = 0; to = MAX_BATCH_SIZE; } - if (!_.isUndefined(from) && _.isUndefined(to)) - to = from + MAX_BATCH_SIZE; + if (!_.isUndefined(from) && _.isUndefined(to)) to = from + MAX_BATCH_SIZE; - if (!_.isUndefined(from) && !_.isUndefined(to) && to - from > MAX_BATCH_SIZE) - to = from + MAX_BATCH_SIZE; + if (!_.isUndefined(from) && !_.isUndefined(to) && to - from > MAX_BATCH_SIZE) to = from + MAX_BATCH_SIZE; if (from < 0) from = 0; if (to < 0) to = 0; @@ -353,9 +371,11 @@ helpers.stubHistory = function(txs) { helpers.stubFeeLevels = function(levels) { blockchainExplorer.estimateFee = function(nbBlocks, cb) { - var result = _.zipObject(_.map(_.pick(levels, nbBlocks), function(fee, n) { - return [+n, fee > 0 ? fee / 1e8 : fee]; - })); + var result = _.zipObject( + _.map(_.pick(levels, nbBlocks), function(fee, n) { + return [+n, fee > 0 ? fee / 1e8 : fee]; + }), + ); return cb(null, result); }; }; @@ -402,23 +422,26 @@ helpers.getProposalSignatureOpts = function(txp, signingKey) { return { txProposalId: txp.id, proposalSignature: proposalSignature, - } + }; }; - helpers.createAddresses = function(server, wallet, main, change, cb) { // var clock = sinon.useFakeTimers('Date'); - async.mapSeries(_.range(main + change), function(i, next) { - // clock.tick(1000); - var address = wallet.createAddress(i >= main); - server.storage.storeAddressAndWallet(wallet, address, function(err) { - next(err, address); - }); - }, function(err, addresses) { - should.not.exist(err); - // clock.restore(); - return cb(_.take(addresses, main), _.takeRight(addresses, change)); - }); + async.mapSeries( + _.range(main + change), + function(i, next) { + // clock.tick(1000); + var address = wallet.createAddress(i >= main); + server.storage.storeAddressAndWallet(wallet, address, function(err) { + next(err, address); + }); + }, + function(err, addresses) { + should.not.exist(err); + // clock.restore(); + return cb(_.take(addresses, main), _.takeRight(addresses, change)); + }, + ); }; helpers.createAndPublishTx = function(server, txOpts, signingKey, cb) { @@ -432,42 +455,42 @@ helpers.createAndPublishTx = function(server, txOpts, signingKey, cb) { }); }; - helpers.historyCacheTest = function(items) { var template = { - txid: "fad88682ccd2ff34cac6f7355fe9ecd8addd9ef167e3788455972010e0d9d0de", - vin: [{ - txid: "0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04", - vout: 0, - n: 0, - addr: "2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V", - valueMicros: 45753, - value: 0.00045753, - }], - vout: [{ - value: "0.00011454", - n: 0, - scriptPubKey: { - addresses: [ - "2N7GT7XaN637eBFMmeczton2aZz5rfRdZso" - ] - } - }, { - value: "0.00020000", - n: 1, - scriptPubKey: { - addresses: [ - "mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE" - ] - } - }], + txid: 'fad88682ccd2ff34cac6f7355fe9ecd8addd9ef167e3788455972010e0d9d0de', + vin: [ + { + txid: '0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04', + vout: 0, + n: 0, + addr: '2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V', + valueMicros: 45753, + value: 0.00045753, + }, + ], + vout: [ + { + value: '0.00011454', + n: 0, + scriptPubKey: { + addresses: ['2N7GT7XaN637eBFMmeczton2aZz5rfRdZso'], + }, + }, + { + value: '0.00020000', + n: 1, + scriptPubKey: { + addresses: ['mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE'], + }, + }, + ], confirmations: 1, blockheight: 423499, time: 1424472242, blocktime: 1424472242, valueOut: 0.00031454, valueIn: 0.00045753, - fees: 0.00014299 + fees: 0.00014299, }; var ret = []; diff --git a/packages/merit-wallet-service/test/integration/pushNotifications.js b/packages/merit-wallet-service/test/integration/pushNotifications.js index 1bbdea4a96..5a8fb75630 100644 --- a/packages/merit-wallet-service/test/integration/pushNotifications.js +++ b/packages/merit-wallet-service/test/integration/pushNotifications.js @@ -36,105 +36,132 @@ describe('Push notifications', function() { wallet = w; var i = 0; - async.eachSeries(w.copayers, function(copayer, next) { - helpers.getAuthServer(copayer.id, function(server) { - async.parallel([ - - function(done) { - server.savePreferences({ - email: 'copayer' + (++i) + '@domain.com', - language: 'en', - unit: 'bit', - }, done); + async.eachSeries( + w.copayers, + function(copayer, next) { + helpers.getAuthServer(copayer.id, function(server) { + async.parallel( + [ + function(done) { + server.savePreferences( + { + email: 'copayer' + ++i + '@domain.com', + language: 'en', + unit: 'bit', + }, + done, + ); + }, + function(done) { + server.pushNotificationsSubscribe( + { + token: '1234', + packageName: 'com.wallet', + platform: 'Android', + }, + done, + ); + }, + ], + next, + ); + }); + }, + function(err) { + should.not.exist(err); + + requestStub = sinon.stub(); + requestStub.yields(); + + pushNotificationsService = new PushNotificationsService(); + pushNotificationsService.start( + { + lockOpts: {}, + messageBroker: server.messageBroker, + storage: helpers.getStorage(), + request: requestStub, + pushNotificationsOpts: { + templatePath: './lib/templates', + defaultLanguage: 'en', + defaultUnit: 'mrt', + subjectPrefix: '', + pushServerUrl: 'http://localhost:8000', + authorizationKey: 'secret', + }, }, - function(done) { - server.pushNotificationsSubscribe({ - token: '1234', - packageName: 'com.wallet', - platform: 'Android', - }, done); + function(err) { + should.not.exist(err); + done(); }, - ], next); + ); + }, + ); + }); + }); + }); - }); - }, function(err) { + it('should build each notifications using preferences of the copayers', function(done) { + server.savePreferences( + { + language: 'en', + unit: 'bit', + }, + function(err) { + server.createAddress({}, function(err, address) { should.not.exist(err); - requestStub = sinon.stub(); - requestStub.yields(); - - pushNotificationsService = new PushNotificationsService(); - pushNotificationsService.start({ - lockOpts: {}, - messageBroker: server.messageBroker, - storage: helpers.getStorage(), - request: requestStub, - pushNotificationsOpts: { - templatePath: './lib/templates', - defaultLanguage: 'en', - defaultUnit: 'mrt', - subjectPrefix: '', - pushServerUrl: 'http://localhost:8000', - authorizationKey: 'secret', + // Simulate incoming tx notification + server._notify( + 'IncomingTx', + { + txid: '999', + address: address, + amount: 12300000, }, - }, function(err) { - should.not.exist(err); - done(); - }); + { + isGlobal: true, + }, + function(err) { + setTimeout(function() { + var calls = requestStub.getCalls(); + var args = _.map(calls, function(c) { + return c.args[0]; + }); + calls.length.should.equal(1); + args[0].body.notification.title.should.contain('New payment received'); + args[0].body.notification.body.should.contain('123,000'); + done(); + }, 100); + }, + ); }); - }); - }); + }, + ); }); - it('should build each notifications using preferences of the copayers', function(done) { - server.savePreferences({ - language: 'en', - unit: 'bit', - }, function(err) { - server.createAddress({}, function(err, address) { - should.not.exist(err); + it('should not notify auto-payments to creator', function(done) { + server.createAddress({}, function(err, address) { + should.not.exist(err); - // Simulate incoming tx notification - server._notify('IncomingTx', { + // Simulate incoming tx notification + server._notify( + 'IncomingTx', + { txid: '999', address: address, amount: 12300000, - }, { - isGlobal: true - }, function(err) { + }, + { + isGlobal: false, + }, + function(err) { setTimeout(function() { var calls = requestStub.getCalls(); - var args = _.map(calls, function(c) { - return c.args[0]; - }); - calls.length.should.equal(1); - args[0].body.notification.title.should.contain('New payment received'); - args[0].body.notification.body.should.contain('123,000'); + calls.length.should.equal(0); done(); }, 100); - }); - }); - }); - }); - - it('should not notify auto-payments to creator', function(done) { - server.createAddress({}, function(err, address) { - should.not.exist(err); - - // Simulate incoming tx notification - server._notify('IncomingTx', { - txid: '999', - address: address, - amount: 12300000, - }, { - isGlobal: false - }, function(err) { - setTimeout(function() { - var calls = requestStub.getCalls(); - calls.length.should.equal(0); - done(); - }, 100); - }); + }, + ); }); }); @@ -143,19 +170,24 @@ describe('Push notifications', function() { should.not.exist(err); // Simulate incoming tx notification - server._notify('IncomingTx', { - txid: '999', - address: address, - amount: 12300000, - }, { - isGlobal: true - }, function(err) { - setTimeout(function() { - var calls = requestStub.getCalls(); - calls.length.should.equal(1); - done(); - }, 100); - }); + server._notify( + 'IncomingTx', + { + txid: '999', + address: address, + amount: 12300000, + }, + { + isGlobal: true, + }, + function(err) { + setTimeout(function() { + var calls = requestStub.getCalls(); + calls.length.should.equal(1); + done(); + }, 100); + }, + ); }); }); @@ -163,22 +195,29 @@ describe('Push notifications', function() { server.createAddress({}, function(err, address) { should.not.exist(err); - server.txConfirmationSubscribe({ - txid: '123' - }, function(err) { - should.not.exist(err); - - // Simulate tx confirmation notification - server._notify('TxConfirmation', { + server.txConfirmationSubscribe( + { txid: '123', - }, function(err) { - setTimeout(function() { - var calls = requestStub.getCalls(); - calls.length.should.equal(1); - done(); - }, 100); - }); - }); + }, + function(err) { + should.not.exist(err); + + // Simulate tx confirmation notification + server._notify( + 'TxConfirmation', + { + txid: '123', + }, + function(err) { + setTimeout(function() { + var calls = requestStub.getCalls(); + calls.length.should.equal(1); + done(); + }, 100); + }, + ); + }, + ); }); }); }); @@ -190,94 +229,116 @@ describe('Push notifications', function() { server = s; wallet = w; var i = 0; - async.eachSeries(w.copayers, function(copayer, next) { - helpers.getAuthServer(copayer.id, function(server) { - async.parallel([ - - function(done) { - server.savePreferences({ - email: 'copayer' + (++i) + '@domain.com', - language: 'en', - unit: 'bit', - }, done); + async.eachSeries( + w.copayers, + function(copayer, next) { + helpers.getAuthServer(copayer.id, function(server) { + async.parallel( + [ + function(done) { + server.savePreferences( + { + email: 'copayer' + ++i + '@domain.com', + language: 'en', + unit: 'bit', + }, + done, + ); + }, + function(done) { + server.pushNotificationsSubscribe( + { + token: '1234', + packageName: 'com.wallet', + platform: 'Android', + }, + done, + ); + }, + ], + next, + ); + }); + }, + function(err) { + should.not.exist(err); + + requestStub = sinon.stub(); + requestStub.yields(); + + pushNotificationsService = new PushNotificationsService(); + pushNotificationsService.start( + { + lockOpts: {}, + messageBroker: server.messageBroker, + storage: helpers.getStorage(), + request: requestStub, + pushNotificationsOpts: { + templatePath: './lib/templates', + defaultLanguage: 'en', + defaultUnit: 'mrt', + subjectPrefix: '', + pushServerUrl: 'http://localhost:8000', + authorizationKey: 'secret', + }, }, - function(done) { - server.pushNotificationsSubscribe({ - token: '1234', - packageName: 'com.wallet', - platform: 'Android', - }, done); + function(err) { + should.not.exist(err); + done(); }, - ], next); - - }); - }, function(err) { - should.not.exist(err); - - requestStub = sinon.stub(); - requestStub.yields(); - - pushNotificationsService = new PushNotificationsService(); - pushNotificationsService.start({ - lockOpts: {}, - messageBroker: server.messageBroker, - storage: helpers.getStorage(), - request: requestStub, - pushNotificationsOpts: { - templatePath: './lib/templates', - defaultLanguage: 'en', - defaultUnit: 'mrt', - subjectPrefix: '', - pushServerUrl: 'http://localhost:8000', - authorizationKey: 'secret', - }, - }, function(err) { - should.not.exist(err); - done(); - }); - }); + ); + }, + ); }); }); }); it('should build each notifications using preferences of the copayers', function(done) { - server.savePreferences({ - email: 'copayer1@domain.com', - language: 'es', - unit: 'mrt', - }, function(err) { - server.createAddress({}, function(err, address) { - should.not.exist(err); + server.savePreferences( + { + email: 'copayer1@domain.com', + language: 'es', + unit: 'mrt', + }, + function(err) { + server.createAddress({}, function(err, address) { + should.not.exist(err); - // Simulate incoming tx notification - server._notify('IncomingTx', { - txid: '999', - address: address, - amount: 12300000, - }, { - isGlobal: true - }, function(err) { - setTimeout(function() { - var calls = requestStub.getCalls(); - var args = _.map(calls, function(c) { - return c.args[0]; - }); + // Simulate incoming tx notification + server._notify( + 'IncomingTx', + { + txid: '999', + address: address, + amount: 12300000, + }, + { + isGlobal: true, + }, + function(err) { + setTimeout(function() { + var calls = requestStub.getCalls(); + var args = _.map(calls, function(c) { + return c.args[0]; + }); - calls.length.should.equal(3); + calls.length.should.equal(3); - args[0].body.notification.title.should.contain('Nuevo pago recibido'); - args[0].body.notification.body.should.contain('0.123'); + args[0].body.notification.title.should.contain('Nuevo pago recibido'); + args[0].body.notification.body.should.contain('0.123'); - args[1].body.notification.title.should.contain('New payment received'); - args[1].body.notification.body.should.contain('123,000'); + args[1].body.notification.title.should.contain('New payment received'); + args[1].body.notification.body.should.contain('123,000'); - args[2].body.notification.title.should.contain('New payment received'); - args[2].body.notification.body.should.contain('123,000'); - done(); - }, 100); + args[2].body.notification.title.should.contain('New payment received'); + args[2].body.notification.body.should.contain('123,000'); + done(); + }, 100); + }, + ); }); - }); - }); + }, + ); }); it('should notify copayers when payment is received', function(done) { @@ -285,20 +346,25 @@ describe('Push notifications', function() { should.not.exist(err); // Simulate incoming tx notification - server._notify('IncomingTx', { - txid: '999', - address: address, - amount: 12300000, - }, { - isGlobal: true - }, function(err) { - setTimeout(function() { - var calls = requestStub.getCalls(); - calls.length.should.equal(3); + server._notify( + 'IncomingTx', + { + txid: '999', + address: address, + amount: 12300000, + }, + { + isGlobal: true, + }, + function(err) { + setTimeout(function() { + var calls = requestStub.getCalls(); + calls.length.should.equal(3); - done(); - }, 100); - }); + done(); + }, 100); + }, + ); }); }); @@ -307,41 +373,51 @@ describe('Push notifications', function() { should.not.exist(err); // Simulate incoming tx notification - server._notify('IncomingTx', { - txid: '999', - address: address, - amount: 12300000, - }, { - isGlobal: false - }, function(err) { - setTimeout(function() { - var calls = requestStub.getCalls(); - calls.length.should.equal(2); - - done(); - }, 100); - }); - }); - }); - - it('should notify copayers a new tx proposal has been created', function(done) { - helpers.stubUtxos(server, wallet, [1, 1], function() { - server.createAddress({}, function(err, address) { - should.not.exist(err); - server._notify('NewTxProposal', { + server._notify( + 'IncomingTx', + { txid: '999', address: address, amount: 12300000, - }, { - isGlobal: false - }, function(err) { + }, + { + isGlobal: false, + }, + function(err) { setTimeout(function() { var calls = requestStub.getCalls(); calls.length.should.equal(2); done(); }, 100); - }); + }, + ); + }); + }); + + it('should notify copayers a new tx proposal has been created', function(done) { + helpers.stubUtxos(server, wallet, [1, 1], function() { + server.createAddress({}, function(err, address) { + should.not.exist(err); + server._notify( + 'NewTxProposal', + { + txid: '999', + address: address, + amount: 12300000, + }, + { + isGlobal: false, + }, + function(err) { + setTimeout(function() { + var calls = requestStub.getCalls(); + calls.length.should.equal(2); + + done(); + }, 100); + }, + ); }); }); }); @@ -349,106 +425,135 @@ describe('Push notifications', function() { it('should notify copayers a tx has been finally rejected', function(done) { helpers.stubUtxos(server, wallet, 1, function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], - feePerKb: 100e2 + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], + feePerKb: 100e2, }; var txpId; - async.waterfall([ - - function(next) { - helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { - next(null, tx); - }); - }, - function(txp, next) { - txpId = txp.id; - async.eachSeries(_.range(1, 3), function(i, next) { - var copayer = TestData.copayers[i]; - helpers.getAuthServer(copayer.id44, function(server) { - server.rejectTx({ - txProposalId: txp.id, - }, next); + async.waterfall( + [ + function(next) { + helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { + next(null, tx); }); - }, next); - }, - ], function(err) { - should.not.exist(err); + }, + function(txp, next) { + txpId = txp.id; + async.eachSeries( + _.range(1, 3), + function(i, next) { + var copayer = TestData.copayers[i]; + helpers.getAuthServer(copayer.id44, function(server) { + server.rejectTx( + { + txProposalId: txp.id, + }, + next, + ); + }); + }, + next, + ); + }, + ], + function(err) { + should.not.exist(err); - setTimeout(function() { - var calls = requestStub.getCalls(); - var args = _.map(_.takeRight(calls, 2), function(c) { - return c.args[0]; - }); + setTimeout(function() { + var calls = requestStub.getCalls(); + var args = _.map(_.takeRight(calls, 2), function(c) { + return c.args[0]; + }); - args[0].body.notification.title.should.contain('Payment proposal rejected'); - done(); - }, 100); - }); + args[0].body.notification.title.should.contain('Payment proposal rejected'); + done(); + }, 100); + }, + ); }); }); it('should notify copayers a new outgoing tx has been created', function(done) { helpers.stubUtxos(server, wallet, 1, function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], - feePerKb: 100e2 + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], + feePerKb: 100e2, }; var txp; - async.waterfall([ - - function(next) { - helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { - next(null, tx); - }); - }, - function(t, next) { - txp = t; - async.eachSeries(_.range(1, 3), function(i, next) { - var copayer = TestData.copayers[i]; - helpers.getAuthServer(copayer.id44, function(s) { - server = s; - var signatures = helpers.clientSign(txp, copayer.xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: txp.id, - signatures: signatures, - }, function(err, t) { - txp = t; - next(); - }); + async.waterfall( + [ + function(next) { + helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { + next(null, tx); }); - }, next); - }, - function(next) { - helpers.stubBroadcast(); - server.broadcastTx({ - txProposalId: txp.id, - }, next); - }, - ], function(err) { - should.not.exist(err); + }, + function(t, next) { + txp = t; + async.eachSeries( + _.range(1, 3), + function(i, next) { + var copayer = TestData.copayers[i]; + helpers.getAuthServer(copayer.id44, function(s) { + server = s; + var signatures = helpers.clientSign(txp, copayer.xPrivKey_44H_0H_0H); + server.signTx( + { + txProposalId: txp.id, + signatures: signatures, + }, + function(err, t) { + txp = t; + next(); + }, + ); + }); + }, + next, + ); + }, + function(next) { + helpers.stubBroadcast(); + server.broadcastTx( + { + txProposalId: txp.id, + }, + next, + ); + }, + ], + function(err) { + should.not.exist(err); - setTimeout(function() { - var calls = requestStub.getCalls(); - var args = _.map(_.takeRight(calls, 2), function(c) { - return c.args[0]; - }); + setTimeout(function() { + var calls = requestStub.getCalls(); + var args = _.map(_.takeRight(calls, 2), function(c) { + return c.args[0]; + }); - args[0].body.notification.title.should.contain('Payment sent'); - args[1].body.notification.title.should.contain('Payment sent'); + args[0].body.notification.title.should.contain('Payment sent'); + args[1].body.notification.title.should.contain('Payment sent'); - sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(server.copayerId)).should.not.equal(args[0].body.data.copayerId); - sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(server.copayerId)).should.not.equal(args[1].body.data.copayerId); - done(); - }, 100); - }); + sjcl.codec.hex + .fromBits(sjcl.hash.sha256.hash(server.copayerId)) + .should.not.equal(args[0].body.data.copayerId); + sjcl.codec.hex + .fromBits(sjcl.hash.sha256.hash(server.copayerId)) + .should.not.equal(args[1].body.data.copayerId); + done(); + }, 100); + }, + ); }); }); }); @@ -472,89 +577,102 @@ describe('Push notifications', function() { requestStub.yields(); pushNotificationsService = new PushNotificationsService(); - pushNotificationsService.start({ - lockOpts: {}, - messageBroker: server.messageBroker, - storage: helpers.getStorage(), - request: requestStub, - pushNotificationsOpts: { - templatePath: './lib/templates', - defaultLanguage: 'en', - defaultUnit: 'mrt', - subjectPrefix: '', - pushServerUrl: 'http://localhost:8000', - authorizationKey: 'secret', + pushNotificationsService.start( + { + lockOpts: {}, + messageBroker: server.messageBroker, + storage: helpers.getStorage(), + request: requestStub, + pushNotificationsOpts: { + templatePath: './lib/templates', + defaultLanguage: 'en', + defaultUnit: 'mrt', + subjectPrefix: '', + pushServerUrl: 'http://localhost:8000', + authorizationKey: 'secret', + }, }, - }, function(err) { - should.not.exist(err); - done(); - }); + function(err) { + should.not.exist(err); + done(); + }, + ); }); }); }); it('should notify copayers when a new copayer just joined into your wallet except the one who joined', function(done) { - async.eachSeries(_.range(3), function(i, next) { - var copayerOpts = helpers.getSignedCopayerOpts({ - walletId: walletId, - name: 'copayer ' + (i + 1), - xPubKey: TestData.copayers[i].xPubKey_44H_0H_0H, - requestPubKey: TestData.copayers[i].pubKey_1H_0, - customData: 'custom data ' + (i + 1), - }); + async.eachSeries( + _.range(3), + function(i, next) { + var copayerOpts = helpers.getSignedCopayerOpts({ + walletId: walletId, + name: 'copayer ' + (i + 1), + xPubKey: TestData.copayers[i].xPubKey_44H_0H_0H, + requestPubKey: TestData.copayers[i].pubKey_1H_0, + customData: 'custom data ' + (i + 1), + }); - server.joinWallet(copayerOpts, function(err, res) { - if (err) return next(err); + server.joinWallet(copayerOpts, function(err, res) { + if (err) return next(err); - helpers.getAuthServer(res.copayerId, function(server) { - server.pushNotificationsSubscribe({ - token: 'token:' + copayerOpts.name, - packageName: 'com.wallet', - platform: 'Android', - }, next); - }); - }); - }, function(err) { - should.not.exist(err); - setTimeout(function() { - var calls = requestStub.getCalls(); - var args = _.filter(_.map(calls, function(call) { - return call.args[0]; - }), function(arg) { - return arg.body.notification.title == 'New copayer'; + helpers.getAuthServer(res.copayerId, function(server) { + server.pushNotificationsSubscribe( + { + token: 'token:' + copayerOpts.name, + packageName: 'com.wallet', + platform: 'Android', + }, + next, + ); + }); }); + }, + function(err) { + should.not.exist(err); + setTimeout(function() { + var calls = requestStub.getCalls(); + var args = _.filter( + _.map(calls, function(call) { + return call.args[0]; + }), + function(arg) { + return arg.body.notification.title == 'New copayer'; + }, + ); - server.getWallet(null, function(err, wallet) { - /* + server.getWallet(null, function(err, wallet) { + /* First call - copayer2 joined copayer2 should notify to copayer1 copayer2 should NOT be notifyed */ - var hashedCopayerIds = _.map(wallet.copayers, function(copayer) { - return sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(copayer.id)); - }); - hashedCopayerIds[0].should.equal((args[0].body.data.copayerId)); - hashedCopayerIds[1].should.not.equal((args[0].body.data.copayerId)); + var hashedCopayerIds = _.map(wallet.copayers, function(copayer) { + return sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(copayer.id)); + }); + hashedCopayerIds[0].should.equal(args[0].body.data.copayerId); + hashedCopayerIds[1].should.not.equal(args[0].body.data.copayerId); - /* + /* Second call - copayer3 joined copayer3 should notify to copayer1 */ - hashedCopayerIds[0].should.equal((args[1].body.data.copayerId)); + hashedCopayerIds[0].should.equal(args[1].body.data.copayerId); - /* + /* Third call - copayer3 joined copayer3 should notify to copayer2 */ - hashedCopayerIds[1].should.equal((args[2].body.data.copayerId)); + hashedCopayerIds[1].should.equal(args[2].body.data.copayerId); - // copayer3 should NOT notify any other copayer - hashedCopayerIds[2].should.not.equal((args[1].body.data.copayerId)); - hashedCopayerIds[2].should.not.equal((args[2].body.data.copayerId)); - done(); - }); - }, 100); - }); + // copayer3 should NOT notify any other copayer + hashedCopayerIds[2].should.not.equal(args[1].body.data.copayerId); + hashedCopayerIds[2].should.not.equal(args[2].body.data.copayerId); + done(); + }); + }, 100); + }, + ); }); }); }); diff --git a/packages/merit-wallet-service/test/integration/server.js b/packages/merit-wallet-service/test/integration/server.js index 82513ff0c9..ad2dbd499c 100644 --- a/packages/merit-wallet-service/test/integration/server.js +++ b/packages/merit-wallet-service/test/integration/server.js @@ -25,7 +25,6 @@ var TestData = require('../testdata'); var helpers = require('./helpers'); var storage, blockchainExplorer, request; - describe('Wallet service', function() { before(function(done) { helpers.before(done); @@ -79,17 +78,20 @@ describe('Wallet service', function() { describe('#getInstanceWithAuth', function() { it('should not get server instance for BWC lower than v1.2', function(done) { - var server = WalletService.getInstanceWithAuth({ - copayerId: '1234', - message: 'hello world', - signature: 'xxx', - clientVersion: 'bwc-1.1.99', - }, function(err, server) { - should.exist(err); - should.not.exist(server); - err.code.should.equal('UPGRADE_NEEDED'); - done(); - }); + var server = WalletService.getInstanceWithAuth( + { + copayerId: '1234', + message: 'hello world', + signature: 'xxx', + clientVersion: 'bwc-1.1.99', + }, + function(err, server) { + should.exist(err); + should.not.exist(server); + err.code.should.equal('UPGRADE_NEEDED'); + done(); + }, + ); }); it('should get server instance for existing copayer', function(done) { helpers.createAndJoinWallet(1, 2, function(s, wallet) { @@ -98,19 +100,22 @@ describe('Wallet service', function() { var sig = helpers.signMessage('hello world', priv); - WalletService.getInstanceWithAuth({ - copayerId: wallet.copayers[0].id, - message: 'hello world', - signature: sig, - clientVersion: 'bwc-2.0.0', - walletId: '123', - }, function(err, server) { - should.not.exist(err); - server.walletId.should.equal(wallet.id); - server.copayerId.should.equal(wallet.copayers[0].id); - server.clientVersion.should.equal('bwc-2.0.0'); - done(); - }); + WalletService.getInstanceWithAuth( + { + copayerId: wallet.copayers[0].id, + message: 'hello world', + signature: sig, + clientVersion: 'bwc-2.0.0', + walletId: '123', + }, + function(err, server) { + should.not.exist(err); + server.walletId.should.equal(wallet.id); + server.copayerId.should.equal(wallet.copayers[0].id); + server.clientVersion.should.equal('bwc-2.0.0'); + done(); + }, + ); }); }); @@ -130,45 +135,54 @@ describe('Wallet service', function() { it('should fail when message signature cannot be verified', function(done) { helpers.createAndJoinWallet(1, 2, function(s, wallet) { - WalletService.getInstanceWithAuth({ - copayerId: wallet.copayers[0].id, - message: 'dummy', - signature: 'dummy', - }, function(err, server) { - err.code.should.equal('NOT_AUTHORIZED'); - err.message.should.contain('Invalid signature'); - done(); - }); + WalletService.getInstanceWithAuth( + { + copayerId: wallet.copayers[0].id, + message: 'dummy', + signature: 'dummy', + }, + function(err, server) { + err.code.should.equal('NOT_AUTHORIZED'); + err.message.should.contain('Invalid signature'); + done(); + }, + ); }); }); it('should get server instance for support staff', function(done) { helpers.createAndJoinWallet(1, 1, function(s, wallet) { var collections = require('../../lib/storage').collections; - s.storage.db.collection(collections.COPAYERS_LOOKUP).update({ - copayerId: wallet.copayers[0].id - }, { - $set: { - isSupportStaff: true - } - }); + s.storage.db.collection(collections.COPAYERS_LOOKUP).update( + { + copayerId: wallet.copayers[0].id, + }, + { + $set: { + isSupportStaff: true, + }, + }, + ); var xpriv = TestData.copayers[0].xPrivKey; var priv = TestData.copayers[0].privKey_1H_0; var sig = helpers.signMessage('hello world', priv); - WalletService.getInstanceWithAuth({ - copayerId: wallet.copayers[0].id, - message: 'hello world', - signature: sig, - walletId: '123', - }, function(err, server) { - should.not.exist(err); - server.walletId.should.equal('123'); - server.copayerId.should.equal(wallet.copayers[0].id); - done(); - }); + WalletService.getInstanceWithAuth( + { + copayerId: wallet.copayers[0].id, + message: 'hello world', + signature: sig, + walletId: '123', + }, + function(err, server) { + should.not.exist(err); + server.walletId.should.equal('123'); + server.copayerId.should.equal(wallet.copayers[0].id); + done(); + }, + ); }); }); }); @@ -184,29 +198,35 @@ describe('Wallet service', function() { }); it('should get a new session & authenticate', function(done) { - WalletService.getInstanceWithAuth({ - copayerId: server.copayerId, - session: 'dummy', - }, function(err, server2) { - should.exist(err); - err.code.should.equal('NOT_AUTHORIZED'); - err.message.toLowerCase().should.contain('session'); - should.not.exist(server2); - server.login({}, function(err, token) { - should.not.exist(err); - should.exist(token); - WalletService.getInstanceWithAuth({ - copayerId: server.copayerId, - session: token, - }, function(err, server2) { + WalletService.getInstanceWithAuth( + { + copayerId: server.copayerId, + session: 'dummy', + }, + function(err, server2) { + should.exist(err); + err.code.should.equal('NOT_AUTHORIZED'); + err.message.toLowerCase().should.contain('session'); + should.not.exist(server2); + server.login({}, function(err, token) { should.not.exist(err); - should.exist(server2); - server2.copayerId.should.equal(server.copayerId); - server2.walletId.should.equal(server.walletId); - done(); + should.exist(token); + WalletService.getInstanceWithAuth( + { + copayerId: server.copayerId, + session: token, + }, + function(err, server2) { + should.not.exist(err); + should.exist(server2); + server2.copayerId.should.equal(server.copayerId); + server2.walletId.should.equal(server.walletId); + done(); + }, + ); }); - }); - }); + }, + ); }); it('should get the same session token for two requests in a row', function(done) { server.login({}, function(err, token) { @@ -222,53 +242,61 @@ describe('Wallet service', function() { it('should create a new session if the previous one has expired', function(done) { var timer = sinon.useFakeTimers('Date'); var token; - async.series([ - - function(next) { - server.login({}, function(err, t) { - should.not.exist(err); - should.exist(t); - token = t; - next(); - }); - }, - function(next) { - WalletService.getInstanceWithAuth({ - copayerId: server.copayerId, - session: token, - }, function(err, server2) { - should.not.exist(err); - should.exist(server2); - next(); - }); - }, - function(next) { - timer.tick((Defaults.SESSION_EXPIRATION + 1) * 1000); - next(); - }, - function(next) { - server.login({}, function(err, t) { - should.not.exist(err); - t.should.not.equal(token); - next(); - }); - }, - function(next) { - WalletService.getInstanceWithAuth({ - copayerId: server.copayerId, - session: token, - }, function(err, server2) { - should.exist(err); - err.code.should.equal('NOT_AUTHORIZED'); - err.message.should.contain('expired'); + async.series( + [ + function(next) { + server.login({}, function(err, t) { + should.not.exist(err); + should.exist(t); + token = t; + next(); + }); + }, + function(next) { + WalletService.getInstanceWithAuth( + { + copayerId: server.copayerId, + session: token, + }, + function(err, server2) { + should.not.exist(err); + should.exist(server2); + next(); + }, + ); + }, + function(next) { + timer.tick((Defaults.SESSION_EXPIRATION + 1) * 1000); next(); - }); + }, + function(next) { + server.login({}, function(err, t) { + should.not.exist(err); + t.should.not.equal(token); + next(); + }); + }, + function(next) { + WalletService.getInstanceWithAuth( + { + copayerId: server.copayerId, + session: token, + }, + function(err, server2) { + should.exist(err); + err.code.should.equal('NOT_AUTHORIZED'); + err.message.should.contain('expired'); + next(); + }, + ); + }, + ], + function(err) { + should.not.exist(err); + timer.restore(); + done(); }, - ], function(err) { - should.not.exist(err); - timer.restore(); - done(); - }); + ); }); }); @@ -351,76 +379,93 @@ describe('Wallet service', function() { }); it('should check m-n combination', function(done) { - var pairs = [{ - m: 0, - n: 0, - valid: false, - }, { - m: 1, - n: 1, - valid: true, - }, { - m: 2, - n: 3, - valid: true, - }, { - m: 0, - n: 2, - valid: false, - }, { - m: 2, - n: 1, - valid: false, - }, { - m: 0, - n: 10, - valid: false, - }, { - m: 1, - n: 20, - valid: false, - }, { - m: 10, - n: 10, - valid: true, - }, { - m: 15, - n: 15, - valid: true, - }, { - m: 16, - n: 16, - valid: false, - }, { - m: 1, - n: 15, - valid: true, - }, { - m: -2, - n: -2, - valid: false, - }, ]; + var pairs = [ + { + m: 0, + n: 0, + valid: false, + }, + { + m: 1, + n: 1, + valid: true, + }, + { + m: 2, + n: 3, + valid: true, + }, + { + m: 0, + n: 2, + valid: false, + }, + { + m: 2, + n: 1, + valid: false, + }, + { + m: 0, + n: 10, + valid: false, + }, + { + m: 1, + n: 20, + valid: false, + }, + { + m: 10, + n: 10, + valid: true, + }, + { + m: 15, + n: 15, + valid: true, + }, + { + m: 16, + n: 16, + valid: false, + }, + { + m: 1, + n: 15, + valid: true, + }, + { + m: -2, + n: -2, + valid: false, + }, + ]; var opts = { id: '123', name: 'my wallet', beacon: 'code', pubKey: TestData.keyPair.pub, }; - async.each(pairs, function(pair, cb) { - opts.m = pair.m; - opts.n = pair.n; - server.createWallet(opts, function(err) { - if (!pair.valid) { - should.exist(err); - err.message.should.equal('Invalid combination of required copayers / total copayers'); - } else { - should.not.exist(err); - } - return cb(); - }); - }, function(err) { - done(); - }); + async.each( + pairs, + function(pair, cb) { + opts.m = pair.m; + opts.n = pair.n; + server.createWallet(opts, function(err) { + if (!pair.valid) { + should.exist(err); + err.message.should.equal('Invalid combination of required copayers / total copayers'); + } else { + should.not.exist(err); + } + return cb(); + }); + }, + function(err) { + done(); + }, + ); }); it('should fail to create wallet with invalid pubKey argument', function(done) { @@ -523,7 +568,6 @@ describe('Wallet service', function() { describe('#joinWallet', function() { describe('New clients', function() { - var server, walletId; beforeEach(function(done) { server = new WalletService(); @@ -564,7 +608,7 @@ describe('Wallet service', function() { server.getNotifications({}, function(err, notifications) { should.not.exist(err); var notif = _.find(notifications, { - type: 'NewCopayer' + type: 'NewCopayer', }); should.exist(notif); notif.data.walletId.should.equal(walletId); @@ -572,7 +616,7 @@ describe('Wallet service', function() { notif.data.copayerName.should.equal('me'); notif = _.find(notifications, { - type: 'WalletComplete' + type: 'WalletComplete', }); should.not.exist(notif); done(); @@ -789,7 +833,7 @@ describe('Wallet service', function() { server.getNotifications({}, function(err, notifications) { should.not.exist(err); var notif = _.find(notifications, { - type: 'WalletComplete' + type: 'WalletComplete', }); should.exist(notif); notif.data.walletId.should.equal(wallet.id); @@ -804,7 +848,7 @@ describe('Wallet service', function() { server.getNotifications({}, function(err, notifications) { should.not.exist(err); var notif = _.find(notifications, { - type: 'WalletComplete' + type: 'WalletComplete', }); should.not.exist(notif); done(); @@ -839,7 +883,9 @@ describe('Wallet service', function() { }); server.joinWallet(copayerOpts, function(err, result) { should.exist(err); - err.message.should.contain('The wallet you are trying to join was created with an older version of the client app'); + err.message.should.contain( + 'The wallet you are trying to join was created with an older version of the client app', + ); done(); }); }); @@ -883,17 +929,23 @@ describe('Wallet service', function() { helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.1e8, + }, + ], feePerKb: 100e2, }; - async.eachSeries(_.range(2), function(i, next) { - helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function() { - next(); - }); - }, done); + async.eachSeries( + _.range(2), + function(i, next) { + helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function() { + next(); + }); + }, + done, + ); }); }); }); @@ -905,30 +957,32 @@ describe('Wallet service', function() { should.exist(err); err.code.should.equal('WALLET_NOT_FOUND'); should.not.exist(w); - async.parallel([ - - function(next) { - server.storage.fetchAddresses(wallet.id, function(err, items) { - items.length.should.equal(0); - next(); - }); - }, - function(next) { - server.storage.fetchTxs(wallet.id, {}, function(err, items) { - items.length.should.equal(0); - next(); - }); - }, - function(next) { - server.storage.fetchNotifications(wallet.id, null, 0, function(err, items) { - items.length.should.equal(0); - next(); - }); + async.parallel( + [ + function(next) { + server.storage.fetchAddresses(wallet.id, function(err, items) { + items.length.should.equal(0); + next(); + }); + }, + function(next) { + server.storage.fetchTxs(wallet.id, {}, function(err, items) { + items.length.should.equal(0); + next(); + }); + }, + function(next) { + server.storage.fetchNotifications(wallet.id, null, 0, function(err, items) { + items.length.should.equal(0); + next(); + }); + }, + ], + function(err) { + should.not.exist(err); + done(); }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); }); }); }); @@ -936,77 +990,90 @@ describe('Wallet service', function() { // creates 2 wallet, and deletes only 1. it('should delete a wallet, and only that wallet', function(done) { var server2, wallet2; - async.series([ - - function(next) { - helpers.createAndJoinWallet(1, 1, { - offset: 1 - }, function(s, w) { - server2 = s; - wallet2 = w; - - helpers.stubUtxos(server2, wallet2, [1, 2, 3], function() { - var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.1e8, - }], - feePerKb: 100e2, - }; - async.eachSeries(_.range(2), function(i, next) { - helpers.createAndPublishTx(server2, txOpts, TestData.copayers[1].privKey_1H_0, function() { - next(); + async.series( + [ + function(next) { + helpers.createAndJoinWallet( + 1, + 1, + { + offset: 1, + }, + function(s, w) { + server2 = s; + wallet2 = w; + + helpers.stubUtxos(server2, wallet2, [1, 2, 3], function() { + var txOpts = { + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.1e8, + }, + ], + feePerKb: 100e2, + }; + async.eachSeries( + _.range(2), + function(i, next) { + helpers.createAndPublishTx(server2, txOpts, TestData.copayers[1].privKey_1H_0, function() { + next(); + }); + }, + next, + ); }); - }, next); + }, + ); + }, + function(next) { + server.removeWallet({}, next); + }, + function(next) { + server.getWallet({}, function(err, wallet) { + should.exist(err); + err.code.should.equal('WALLET_NOT_FOUND'); + next(); }); - }); - }, - function(next) { - server.removeWallet({}, next); - }, - function(next) { - server.getWallet({}, function(err, wallet) { - should.exist(err); - err.code.should.equal('WALLET_NOT_FOUND'); - next(); - }); - }, - function(next) { - server2.getWallet({}, function(err, wallet) { - should.not.exist(err); - should.exist(wallet); - wallet.id.should.equal(wallet2.id); - next(); - }); - }, - function(next) { - server2.getMainAddresses({}, function(err, addresses) { - should.not.exist(err); - should.exist(addresses); - addresses.length.should.above(0); - next(); - }); - }, - function(next) { - server2.getTxs({}, function(err, txs) { - should.not.exist(err); - should.exist(txs); - txs.length.should.equal(2); - next(); - }); - }, - function(next) { - server2.getNotifications({}, function(err, notifications) { - should.not.exist(err); - should.exist(notifications); - notifications.length.should.above(0); - next(); - }); + }, + function(next) { + server2.getWallet({}, function(err, wallet) { + should.not.exist(err); + should.exist(wallet); + wallet.id.should.equal(wallet2.id); + next(); + }); + }, + function(next) { + server2.getMainAddresses({}, function(err, addresses) { + should.not.exist(err); + should.exist(addresses); + addresses.length.should.above(0); + next(); + }); + }, + function(next) { + server2.getTxs({}, function(err, txs) { + should.not.exist(err); + should.exist(txs); + txs.length.should.equal(2); + next(); + }); + }, + function(next) { + server2.getNotifications({}, function(err, notifications) { + should.not.exist(err); + should.exist(notifications); + notifications.length.should.above(0); + next(); + }); + }, + ], + function(err) { + should.not.exist(err); + done(); }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); }); }); @@ -1049,34 +1116,39 @@ describe('Wallet service', function() { }); }); it('should get status including extended info', function(done) { - server.getStatus({ - includeExtendedInfo: true - }, function(err, status) { - should.not.exist(err); - should.exist(status); - should.exist(status.wallet.publicKeyRing); - should.exist(status.wallet.pubKey); - should.exist(status.wallet.addressManager); - should.exist(status.wallet.copayers[0].xPubKey); - should.exist(status.wallet.copayers[0].requestPubKey); - should.exist(status.wallet.copayers[0].signature); - should.exist(status.wallet.copayers[0].requestPubKey); - should.exist(status.wallet.copayers[0].customData); - // Do not return other copayer's custom data - _.each(_.tail(status.wallet.copayers), function(copayer) { - should.not.exist(copayer.customData); - }); - done(); - }); + server.getStatus( + { + includeExtendedInfo: true, + }, + function(err, status) { + should.not.exist(err); + should.exist(status); + should.exist(status.wallet.publicKeyRing); + should.exist(status.wallet.pubKey); + should.exist(status.wallet.addressManager); + should.exist(status.wallet.copayers[0].xPubKey); + should.exist(status.wallet.copayers[0].requestPubKey); + should.exist(status.wallet.copayers[0].signature); + should.exist(status.wallet.copayers[0].requestPubKey); + should.exist(status.wallet.copayers[0].customData); + // Do not return other copayer's custom data + _.each(_.tail(status.wallet.copayers), function(copayer) { + should.not.exist(copayer.customData); + }); + done(); + }, + ); }); it('should get status after tx creation', function(done) { helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], - feePerKb: 100e2 + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], + feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { should.exist(tx); @@ -1138,13 +1210,18 @@ describe('Wallet service', function() { describe('shared wallets (BIP45)', function() { beforeEach(function(done) { - helpers.createAndJoinWallet(2, 2, { - supportBIP44AndP2PKH: false - }, function(s, w) { - server = s; - wallet = w; - done(); - }); + helpers.createAndJoinWallet( + 2, + 2, + { + supportBIP44AndP2PKH: false, + }, + function(s, w) { + server = s; + wallet = w; + done(); + }, + ); }); it('should create address', function(done) { @@ -1160,7 +1237,7 @@ describe('Wallet service', function() { server.getNotifications({}, function(err, notifications) { should.not.exist(err); var notif = _.find(notifications, { - type: 'NewAddress' + type: 'NewAddress', }); should.exist(notif); notif.data.address.should.equal(address.address); @@ -1188,18 +1265,22 @@ describe('Wallet service', function() { // skip for singleAddress = true it.skip('should create many addresses on simultaneous requests', function(done) { var N = 5; - async.mapSeries(_.range(N), function(i, cb) { - server.createAddress({}, cb); - }, function(err, addresses) { - var x = _.map(addresses, 'path'); - addresses.length.should.equal(N); - _.each(_.range(N), function(i) { - addresses[i].path.should.equal('m/2147483647/0/' + i); - }); - // No two identical addresses - _.uniq(_.map(addresses, 'address')).length.should.equal(N); - done(); - }); + async.mapSeries( + _.range(N), + function(i, cb) { + server.createAddress({}, cb); + }, + function(err, addresses) { + var x = _.map(addresses, 'path'); + addresses.length.should.equal(N); + _.each(_.range(N), function(i) { + addresses[i].path.should.equal('m/2147483647/0/' + i); + }); + // No two identical addresses + _.uniq(_.map(addresses, 'address')).length.should.equal(N); + done(); + }, + ); }); }); @@ -1225,7 +1306,7 @@ describe('Wallet service', function() { server.getNotifications({}, function(err, notifications) { should.not.exist(err); var notif = _.find(notifications, { - type: 'NewAddress' + type: 'NewAddress', }); should.exist(notif); notif.data.address.should.equal(address.address); @@ -1237,17 +1318,21 @@ describe('Wallet service', function() { // skip for singleAddress = true it.skip('should create many addresses on simultaneous requests', function(done) { var N = 5; - async.mapSeries(_.range(N), function(i, cb) { - server.createAddress({}, cb); - }, function(err, addresses) { - addresses.length.should.equal(N); - _.each(_.range(N), function(i) { - addresses[i].path.should.equal('m/0/' + i); - }); - // No two identical addresses - _.uniq(_.map(addresses, 'address')).length.should.equal(N); - done(); - }); + async.mapSeries( + _.range(N), + function(i, cb) { + server.createAddress({}, cb); + }, + function(err, addresses) { + addresses.length.should.equal(N); + _.each(_.range(N), function(i) { + addresses[i].path.should.equal('m/0/' + i); + }); + // No two identical addresses + _.uniq(_.map(addresses, 'address')).length.should.equal(N); + done(); + }, + ); }); it('should not create address if unable to store it', function(done) { @@ -1293,7 +1378,7 @@ describe('Wallet service', function() { server.getNotifications({}, function(err, notifications) { should.not.exist(err); var notif = _.find(notifications, { - type: 'NewAddress' + type: 'NewAddress', }); should.exist(notif); notif.data.address.should.equal(address.address); @@ -1302,22 +1387,25 @@ describe('Wallet service', function() { }); }); - // skip for singleAddress = true it.skip('should create many addresses on simultaneous requests', function(done) { var N = 5; - async.mapSeries(_.range(N), function(i, cb) { - server.createAddress({}, cb); - }, function(err, addresses) { - addresses = _.sortBy(addresses, 'path'); - addresses.length.should.equal(N); - _.each(_.range(N), function(i) { - addresses[i].path.should.equal('m/0/' + i); - }); - // No two identical addresses - _.uniq(_.map(addresses, 'address')).length.should.equal(N); - done(); - }); + async.mapSeries( + _.range(N), + function(i, cb) { + server.createAddress({}, cb); + }, + function(err, addresses) { + addresses = _.sortBy(addresses, 'path'); + addresses.length.should.equal(N); + _.each(_.range(N), function(i) { + addresses[i].path.should.equal('m/0/' + i); + }); + // No two identical addresses + _.uniq(_.map(addresses, 'address')).length.should.equal(N); + done(); + }, + ); }); // skip for singleAddress = true @@ -1325,36 +1413,43 @@ describe('Wallet service', function() { var MAX_MAIN_ADDRESS_GAP_old = Defaults.MAX_MAIN_ADDRESS_GAP; Defaults.MAX_MAIN_ADDRESS_GAP = 2; helpers.stubAddressActivity([]); - async.map(_.range(2), function(i, next) { - server.createAddress({}, next); - }, function(err, addresses) { - addresses.length.should.equal(2); + async.map( + _.range(2), + function(i, next) { + server.createAddress({}, next); + }, + function(err, addresses) { + addresses.length.should.equal(2); - server.createAddress({}, function(err, address) { - should.exist(err); - should.not.exist(address); - err.code.should.equal('MAIN_ADDRESS_GAP_REACHED'); - server.createAddress({ - ignoreMaxGap: true - }, function(err, address) { - should.not.exist(err); - should.exist(address); - address.path.should.equal('m/0/2'); + server.createAddress({}, function(err, address) { + should.exist(err); + should.not.exist(address); + err.code.should.equal('MAIN_ADDRESS_GAP_REACHED'); + server.createAddress( + { + ignoreMaxGap: true, + }, + function(err, address) { + should.not.exist(err); + should.exist(address); + address.path.should.equal('m/0/2'); - helpers.stubAddressActivity([ - '1GdXraZ1gtoVAvBh49D4hK9xLm6SKgesoE', // m/0/2 - ]); - server.createAddress({}, function(err, address) { - should.not.exist(err); - should.exist(address); - address.path.should.equal('m/0/3'); + helpers.stubAddressActivity([ + '1GdXraZ1gtoVAvBh49D4hK9xLm6SKgesoE', // m/0/2 + ]); + server.createAddress({}, function(err, address) { + should.not.exist(err); + should.exist(address); + address.path.should.equal('m/0/3'); - Defaults.MAX_MAIN_ADDRESS_GAP = MAX_MAIN_ADDRESS_GAP_old; - done(); - }); + Defaults.MAX_MAIN_ADDRESS_GAP = MAX_MAIN_ADDRESS_GAP_old; + done(); + }); + }, + ); }); - }); - }); + }, + ); }); // skip for singleAddress = true @@ -1362,23 +1457,27 @@ describe('Wallet service', function() { var MAX_MAIN_ADDRESS_GAP_old = Defaults.MAX_MAIN_ADDRESS_GAP; Defaults.MAX_MAIN_ADDRESS_GAP = 2; helpers.stubAddressActivity([]); - async.mapSeries(_.range(2), function(i, next) { - server.createAddress({}, next); - }, function(err, addresses) { - addresses.length.should.equal(2); - - helpers.stubAddressActivity([addresses[1].address]); - var getAddressActivitySpy = sinon.spy(blockchainExplorer, 'getAddressActivity'); - server.createAddress({}, function(err, address) { - should.not.exist(err); + async.mapSeries( + _.range(2), + function(i, next) { + server.createAddress({}, next); + }, + function(err, addresses) { + addresses.length.should.equal(2); + + helpers.stubAddressActivity([addresses[1].address]); + var getAddressActivitySpy = sinon.spy(blockchainExplorer, 'getAddressActivity'); server.createAddress({}, function(err, address) { should.not.exist(err); - getAddressActivitySpy.callCount.should.equal(1); - Defaults.MAX_MAIN_ADDRESS_GAP = MAX_MAIN_ADDRESS_GAP_old; - done(); + server.createAddress({}, function(err, address) { + should.not.exist(err); + getAddressActivitySpy.callCount.should.equal(1); + Defaults.MAX_MAIN_ADDRESS_GAP = MAX_MAIN_ADDRESS_GAP_old; + done(); + }); }); - }); - }); + }, + ); }); }); }); @@ -1406,27 +1505,33 @@ describe('Wallet service', function() { }); }); it('should get first N addresses', function(done) { - server.getMainAddresses({ - limit: 3 - }, function(err, addresses) { - should.not.exist(err); - addresses.length.should.equal(3); - addresses[0].path.should.equal('m/0/0'); - addresses[2].path.should.equal('m/0/2'); - done(); - }); + server.getMainAddresses( + { + limit: 3, + }, + function(err, addresses) { + should.not.exist(err); + addresses.length.should.equal(3); + addresses[0].path.should.equal('m/0/0'); + addresses[2].path.should.equal('m/0/2'); + done(); + }, + ); }); it('should get last N addresses in reverse order', function(done) { - server.getMainAddresses({ - limit: 3, - reverse: true, - }, function(err, addresses) { - should.not.exist(err); - addresses.length.should.equal(3); - addresses[0].path.should.equal('m/0/4'); - addresses[2].path.should.equal('m/0/2'); - done(); - }); + server.getMainAddresses( + { + limit: 3, + reverse: true, + }, + function(err, addresses) { + should.not.exist(err); + addresses.length.should.equal(3); + addresses[0].path.should.equal('m/0/4'); + addresses[2].path.should.equal('m/0/2'); + done(); + }, + ); }); }); @@ -1441,125 +1546,152 @@ describe('Wallet service', function() { }); it('should save & retrieve preferences', function(done) { - server.savePreferences({ - email: 'dummy@dummy.com', - language: 'es', - unit: 'bit', - dummy: 'ignored', - }, function(err) { - should.not.exist(err); - server.getPreferences({}, function(err, preferences) { - should.not.exist(err); - should.exist(preferences); - preferences.email.should.equal('dummy@dummy.com'); - preferences.language.should.equal('es'); - preferences.unit.should.equal('bit'); - should.not.exist(preferences.dummy); - done(); - }); - }); - }); - it('should save preferences only for requesting copayer', function(done) { - server.savePreferences({ - email: 'dummy@dummy.com' - }, function(err) { - should.not.exist(err); - helpers.getAuthServer(wallet.copayers[1].id, function(server2) { - server2.getPreferences({}, function(err, preferences) { - should.not.exist(err); - should.not.exist(preferences.email); - done(); - }); - }); - }); - }); - it('should save preferences incrementally', function(done) { - async.series([ - - function(next) { - server.savePreferences({ - email: 'dummy@dummy.com', - }, next); + server.savePreferences( + { + email: 'dummy@dummy.com', + language: 'es', + unit: 'bit', + dummy: 'ignored', }, - function(next) { + function(err) { + should.not.exist(err); server.getPreferences({}, function(err, preferences) { should.not.exist(err); should.exist(preferences); preferences.email.should.equal('dummy@dummy.com'); - should.not.exist(preferences.language); - next(); - }); - }, - function(next) { - server.savePreferences({ - language: 'es', - }, next); - }, - function(next) { - server.getPreferences({}, function(err, preferences) { - should.not.exist(err); - should.exist(preferences); preferences.language.should.equal('es'); - preferences.email.should.equal('dummy@dummy.com'); - next(); + preferences.unit.should.equal('bit'); + should.not.exist(preferences.dummy); + done(); }); }, - function(next) { - server.savePreferences({ - language: null, - unit: 'bit', - }, next); + ); + }); + it('should save preferences only for requesting copayer', function(done) { + server.savePreferences( + { + email: 'dummy@dummy.com', }, - function(next) { - server.getPreferences({}, function(err, preferences) { - should.not.exist(err); - should.exist(preferences); - preferences.unit.should.equal('bit'); - should.not.exist(preferences.language); - preferences.email.should.equal('dummy@dummy.com'); - next(); + function(err) { + should.not.exist(err); + helpers.getAuthServer(wallet.copayers[1].id, function(server2) { + server2.getPreferences({}, function(err, preferences) { + should.not.exist(err); + should.not.exist(preferences.email); + done(); + }); }); }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); + }); + it('should save preferences incrementally', function(done) { + async.series( + [ + function(next) { + server.savePreferences( + { + email: 'dummy@dummy.com', + }, + next, + ); + }, + function(next) { + server.getPreferences({}, function(err, preferences) { + should.not.exist(err); + should.exist(preferences); + preferences.email.should.equal('dummy@dummy.com'); + should.not.exist(preferences.language); + next(); + }); + }, + function(next) { + server.savePreferences( + { + language: 'es', + }, + next, + ); + }, + function(next) { + server.getPreferences({}, function(err, preferences) { + should.not.exist(err); + should.exist(preferences); + preferences.language.should.equal('es'); + preferences.email.should.equal('dummy@dummy.com'); + next(); + }); + }, + function(next) { + server.savePreferences( + { + language: null, + unit: 'bit', + }, + next, + ); + }, + function(next) { + server.getPreferences({}, function(err, preferences) { + should.not.exist(err); + should.exist(preferences); + preferences.unit.should.equal('bit'); + should.not.exist(preferences.language); + preferences.email.should.equal('dummy@dummy.com'); + next(); + }); + }, + ], + function(err) { + should.not.exist(err); + done(); + }, + ); }); it.skip('should save preferences only for requesting wallet', function(done) {}); it('should validate entries', function(done) { - var invalid = [{ - preferences: { - email: ' ', - }, - expected: 'email' - }, { - preferences: { - email: 'dummy@' + _.repeat('domain', 50), - }, - expected: 'email' - }, { - preferences: { - language: 'xxxxx', - }, - expected: 'language' - }, { - preferences: { - language: 123, - }, - expected: 'language' - }, { - preferences: { - unit: 'xxxxx', - }, - expected: 'unit' - }, ]; - async.each(invalid, function(item, next) { - server.savePreferences(item.preferences, function(err) { - should.exist(err); - err.message.should.contain(item.expected); - next(); - }); - }, done); + var invalid = [ + { + preferences: { + email: ' ', + }, + expected: 'email', + }, + { + preferences: { + email: 'dummy@' + _.repeat('domain', 50), + }, + expected: 'email', + }, + { + preferences: { + language: 'xxxxx', + }, + expected: 'language', + }, + { + preferences: { + language: 123, + }, + expected: 'language', + }, + { + preferences: { + unit: 'xxxxx', + }, + expected: 'unit', + }, + ]; + async.each( + invalid, + function(item, next) { + server.savePreferences(item.preferences, function(err) { + should.exist(err); + err.message.should.contain(item.expected); + next(); + }); + }, + done, + ); }); }); @@ -1583,7 +1715,7 @@ describe('Wallet service', function() { server.getMainAddresses({}, function(err, addresses) { var utxo = utxos[0]; var address = _.find(addresses, { - address: utxo.address + address: utxo.address, }); should.exist(address); utxo.path.should.equal(address.path); @@ -1597,26 +1729,34 @@ describe('Wallet service', function() { helpers.stubUtxos(server, wallet, [1, 2, 3], function(utxos) { // _.uniq(utxos, 'address').length.should.be.above(1); // for singleAddress = true var address = utxos[0].address; - var amount = _.sumBy(_.filter(utxos, { - address: address - }), 'micros'); - server.getUtxos({ - addresses: [address] - }, function(err, utxos) { - should.not.exist(err); - should.exist(utxos); - _.sumBy(utxos, 'micros').should.equal(amount); - done(); - }); + var amount = _.sumBy( + _.filter(utxos, { + address: address, + }), + 'micros', + ); + server.getUtxos( + { + addresses: [address], + }, + function(err, utxos) { + should.not.exist(err); + should.exist(utxos); + _.sumBy(utxos, 'micros').should.equal(amount); + done(); + }, + ); }); }); it('should not fail when getting UTXOs for wallet with 0 UTXOs and pending txps', function(done) { helpers.stubUtxos(server, wallet, [1, 1], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1e8, + }, + ], feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(txp) { @@ -1640,14 +1780,17 @@ describe('Wallet service', function() { var getAuthServer = function(copayerId, privKey, cb) { var msg = 'dummy'; var sig = helpers.signMessage(msg, privKey); - WalletService.getInstanceWithAuth({ - copayerId: copayerId, - message: msg, - signature: sig, - clientVersion: helpers.CLIENT_VERSION, - }, function(err, server) { - return cb(err, server); - }); + WalletService.getInstanceWithAuth( + { + copayerId: copayerId, + message: msg, + signature: sig, + clientVersion: helpers.CLIENT_VERSION, + }, + function(err, server) { + return cb(err, server); + }, + ); }; beforeEach(function() { @@ -1713,10 +1856,10 @@ describe('Wallet service', function() { server.getBalance(res.wallet.walletId, function(err, bal) { should.not.exist(err); var privKey = new Meritcore.PrivateKey(); - (getAuthServer(opts.copayerId, privKey, function(err, server2) { + getAuthServer(opts.copayerId, privKey, function(err, server2) { err.code.should.equal('NOT_AUTHORIZED'); done(); - })); + }); }); }); }); @@ -1726,11 +1869,13 @@ describe('Wallet service', function() { should.not.exist(err); getAuthServer(opts.copayerId, reqPrivKey, function(err, server2) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], - feePerKb: 100e2 + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], + feePerKb: 100e2, }; server2.createTx(txOpts, function(err, tx) { should.not.exist(err); @@ -1774,10 +1919,12 @@ describe('Wallet service', function() { should.not.exist(err); getAuthServer(opts.copayerId, reqPrivKey, function(err, server2) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, reqPrivKey, function() { @@ -1906,293 +2053,367 @@ describe('Wallet service', function() { it('should get balance', function(done) { // helpers.stubUtxos(server, wallet, [1, 'u2', 3], function() { helpers.stubUtxos(server, wallet, [1, 3], function() { - server.getBalance({ - twoStep: true - }, function(err, balance) { - should.not.exist(err); - should.exist(balance); - balance.totalAmount.should.equal(helpers.toMicro(4)); - balance.lockedAmount.should.equal(0); - balance.availableAmount.should.equal(helpers.toMicro(4)); + server.getBalance( + { + twoStep: true, + }, + function(err, balance) { + should.not.exist(err); + should.exist(balance); + balance.totalAmount.should.equal(helpers.toMicro(4)); + balance.lockedAmount.should.equal(0); + balance.availableAmount.should.equal(helpers.toMicro(4)); - balance.totalConfirmedAmount.should.equal(helpers.toMicro(4)); - balance.lockedConfirmedAmount.should.equal(0); - balance.availableConfirmedAmount.should.equal(helpers.toMicro(4)); + balance.totalConfirmedAmount.should.equal(helpers.toMicro(4)); + balance.lockedConfirmedAmount.should.equal(0); + balance.availableConfirmedAmount.should.equal(helpers.toMicro(4)); - should.exist(balance.byAddress); - // balance.byAddress.length.should.equal(2); - balance.byAddress.length.should.equal(1); - balance.byAddress[0].amount.should.equal(helpers.toMicro(4)); - // balance.byAddress[1].amount.should.equal(helpers.toMicro(2)); - setTimeout(done, 100); - }); + should.exist(balance.byAddress); + // balance.byAddress.length.should.equal(2); + balance.byAddress.length.should.equal(1); + balance.byAddress[0].amount.should.equal(helpers.toMicro(4)); + // balance.byAddress[1].amount.should.equal(helpers.toMicro(2)); + setTimeout(done, 100); + }, + ); }); }); it('should trigger notification when balance of non-prioritary addresses is updated', function(done) { var oldAddrs, newAddrs; - async.series([ - - function(next) { - helpers.createAddresses(server, wallet, 2, 0, function(addrs) { - oldAddrs = addrs; - next(); - }); - }, - function(next) { - clock.tick(7 * 24 * 3600 * 1000); - helpers.createAddresses(server, wallet, 2, 0, function(addrs) { - newAddrs = addrs; - server._getActiveAddresses(function(err, active) { - should.not.exist(err); - should.not.exist(active); - helpers.stubUtxos(server, wallet, [1, 2], { - addresses: [oldAddrs[0], newAddrs[0]], - }, function() { - next(); + async.series( + [ + function(next) { + helpers.createAddresses(server, wallet, 2, 0, function(addrs) { + oldAddrs = addrs; + next(); + }); + }, + function(next) { + clock.tick(7 * 24 * 3600 * 1000); + helpers.createAddresses(server, wallet, 2, 0, function(addrs) { + newAddrs = addrs; + server._getActiveAddresses(function(err, active) { + should.not.exist(err); + should.not.exist(active); + helpers.stubUtxos( + server, + wallet, + [1, 2], + { + addresses: [oldAddrs[0], newAddrs[0]], + }, + function() { + next(); + }, + ); }); }); - }); - }, - function(next) { - server.getBalance({ - twoStep: true - }, function(err, balance) { - should.not.exist(err); - should.exist(balance); - balance.totalAmount.should.equal(helpers.toMicro(3)); - next(); - }); - }, - function(next) { - setTimeout(next, 100); - }, - function(next) { - server._getActiveAddresses(function(err, active) { - should.not.exist(err); - should.exist(active); - active.length.should.equal(3); - next(); - }); - }, - function(next) { - helpers.stubUtxos(server, wallet, 0.5, { - addresses: oldAddrs[1], - keepUtxos: true, - }, function() { - next(); - }); - }, - function(next) { - server.getBalance({ - twoStep: true - }, function(err, balance) { - should.not.exist(err); - should.exist(balance); - balance.totalAmount.should.equal(helpers.toMicro(3)); - next(); - }); - }, - function(next) { - setTimeout(next, 100); - }, - function(next) { - server.getNotifications({}, function(err, notifications) { - should.not.exist(err); - var last = _.last(notifications); - last.type.should.equal('BalanceUpdated'); - var balance = last.data; - balance.totalAmount.should.equal(helpers.toMicro(3.5)); - next(); - }); + }, + function(next) { + server.getBalance( + { + twoStep: true, + }, + function(err, balance) { + should.not.exist(err); + should.exist(balance); + balance.totalAmount.should.equal(helpers.toMicro(3)); + next(); + }, + ); + }, + function(next) { + setTimeout(next, 100); + }, + function(next) { + server._getActiveAddresses(function(err, active) { + should.not.exist(err); + should.exist(active); + active.length.should.equal(3); + next(); + }); + }, + function(next) { + helpers.stubUtxos( + server, + wallet, + 0.5, + { + addresses: oldAddrs[1], + keepUtxos: true, + }, + function() { + next(); + }, + ); + }, + function(next) { + server.getBalance( + { + twoStep: true, + }, + function(err, balance) { + should.not.exist(err); + should.exist(balance); + balance.totalAmount.should.equal(helpers.toMicro(3)); + next(); + }, + ); + }, + function(next) { + setTimeout(next, 100); + }, + function(next) { + server.getNotifications({}, function(err, notifications) { + should.not.exist(err); + var last = _.last(notifications); + last.type.should.equal('BalanceUpdated'); + var balance = last.data; + balance.totalAmount.should.equal(helpers.toMicro(3.5)); + next(); + }); + }, + ], + function(err) { + should.not.exist(err); + done(); }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); }); it('should not trigger notification when only balance of prioritary addresses is updated', function(done) { var oldAddrs, newAddrs; - async.series([ - - function(next) { - helpers.createAddresses(server, wallet, 2, 0, function(addrs) { - oldAddrs = addrs; - next(); - }); - }, - function(next) { - clock.tick(7 * 24 * 3600 * 1000); - helpers.createAddresses(server, wallet, 2, 0, function(addrs) { - newAddrs = addrs; - helpers.stubUtxos(server, wallet, [1, 2], { - addresses: newAddrs, - }, function() { + async.series( + [ + function(next) { + helpers.createAddresses(server, wallet, 2, 0, function(addrs) { + oldAddrs = addrs; next(); }); - }); - }, - function(next) { - server.getBalance({ - twoStep: true - }, function(err, balance) { - should.not.exist(err); - should.exist(balance); - balance.totalAmount.should.equal(helpers.toMicro(3)); - next(); - }); - }, - function(next) { - setTimeout(next, 100); - }, - function(next) { - helpers.stubUtxos(server, wallet, 0.5, { - addresses: newAddrs[0], - keepUtxos: true, - }, function() { - next(); - }); - }, - function(next) { - server.getBalance({ - twoStep: true - }, function(err, balance) { - should.not.exist(err); - should.exist(balance); - balance.totalAmount.should.equal(helpers.toMicro(3.5)); - next(); - }); - }, - function(next) { - setTimeout(next, 100); - }, - function(next) { - server.getNotifications({}, function(err, notifications) { - should.not.exist(err); - var last = _.last(notifications); - last.type.should.not.equal('BalanceUpdated'); - next(); - }); + }, + function(next) { + clock.tick(7 * 24 * 3600 * 1000); + helpers.createAddresses(server, wallet, 2, 0, function(addrs) { + newAddrs = addrs; + helpers.stubUtxos( + server, + wallet, + [1, 2], + { + addresses: newAddrs, + }, + function() { + next(); + }, + ); + }); + }, + function(next) { + server.getBalance( + { + twoStep: true, + }, + function(err, balance) { + should.not.exist(err); + should.exist(balance); + balance.totalAmount.should.equal(helpers.toMicro(3)); + next(); + }, + ); + }, + function(next) { + setTimeout(next, 100); + }, + function(next) { + helpers.stubUtxos( + server, + wallet, + 0.5, + { + addresses: newAddrs[0], + keepUtxos: true, + }, + function() { + next(); + }, + ); + }, + function(next) { + server.getBalance( + { + twoStep: true, + }, + function(err, balance) { + should.not.exist(err); + should.exist(balance); + balance.totalAmount.should.equal(helpers.toMicro(3.5)); + next(); + }, + ); + }, + function(next) { + setTimeout(next, 100); + }, + function(next) { + server.getNotifications({}, function(err, notifications) { + should.not.exist(err); + var last = _.last(notifications); + last.type.should.not.equal('BalanceUpdated'); + next(); + }); + }, + ], + function(err) { + should.not.exist(err); + done(); }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); }); it('should resolve balance of new addresses immediately', function(done) { var addresses; - async.series([ - - function(next) { - helpers.createAddresses(server, wallet, 4, 0, function(addrs) { - addresses = addrs; - helpers.stubUtxos(server, wallet, [1, 2], { - addresses: _.take(addresses, 2), - }, function() { - next(); + async.series( + [ + function(next) { + helpers.createAddresses(server, wallet, 4, 0, function(addrs) { + addresses = addrs; + helpers.stubUtxos( + server, + wallet, + [1, 2], + { + addresses: _.take(addresses, 2), + }, + function() { + next(); + }, + ); }); - }); - }, - function(next) { - server.getBalance({ - twoStep: true - }, function(err, balance) { - should.not.exist(err); - should.exist(balance); - balance.totalAmount.should.equal(helpers.toMicro(3)); - next(); - }); - }, - function(next) { - server.createAddress({}, function(err, addr) { - helpers.stubUtxos(server, wallet, 0.5, { - addresses: addr, - keepUtxos: true, - }, function() { + }, + function(next) { + server.getBalance( + { + twoStep: true, + }, + function(err, balance) { + should.not.exist(err); + should.exist(balance); + balance.totalAmount.should.equal(helpers.toMicro(3)); + next(); + }, + ); + }, + function(next) { + server.createAddress({}, function(err, addr) { + helpers.stubUtxos( + server, + wallet, + 0.5, + { + addresses: addr, + keepUtxos: true, + }, + function() { + next(); + }, + ); + }); + }, + function(next) { + server.getBalance( + { + twoStep: true, + }, + function(err, balance) { + should.not.exist(err); + should.exist(balance); + balance.totalAmount.should.equal(helpers.toMicro(3.5)); + next(); + }, + ); + }, + function(next) { + setTimeout(next, 100); + }, + function(next) { + server.getNotifications({}, function(err, notifications) { + should.not.exist(err); + var last = _.last(notifications); + last.type.should.not.equal('BalanceUpdated'); next(); }); - }); - }, - function(next) { - server.getBalance({ - twoStep: true - }, function(err, balance) { - should.not.exist(err); - should.exist(balance); - balance.totalAmount.should.equal(helpers.toMicro(3.5)); - next(); - }); - }, - function(next) { - setTimeout(next, 100); - }, - function(next) { - server.getNotifications({}, function(err, notifications) { - should.not.exist(err); - var last = _.last(notifications); - last.type.should.not.equal('BalanceUpdated'); - next(); - }); + }, + ], + function(err) { + should.not.exist(err); + done(); }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); }); it('should not perform 2 steps when nb of addresses below threshold', function(done) { var oldAddrs, newAddrs; Defaults.TWO_STEP_BALANCE_THRESHOLD = 5; - async.series([ - - function(next) { - helpers.createAddresses(server, wallet, 2, 0, function(addrs) { - oldAddrs = addrs; - next(); - }); - }, - function(next) { - clock.tick(7 * 24 * 3600 * 1000); - helpers.createAddresses(server, wallet, 2, 0, function(addrs) { - newAddrs = addrs; - helpers.stubUtxos(server, wallet, [1, 2], { - addresses: [oldAddrs[0], newAddrs[0]], - }, function() { + async.series( + [ + function(next) { + helpers.createAddresses(server, wallet, 2, 0, function(addrs) { + oldAddrs = addrs; next(); }); - }); - }, - function(next) { - server.getBalance({ - twoStep: true - }, function(err, balance) { - should.not.exist(err); - should.exist(balance); - balance.totalAmount.should.equal(helpers.toMicro(3)); - next(); - }); - }, - function(next) { - setTimeout(next, 100); - }, - function(next) { - server.getNotifications({}, function(err, notifications) { - should.not.exist(err); - var last = _.last(notifications); - last.type.should.not.equal('BalanceUpdated'); - next(); - }); + }, + function(next) { + clock.tick(7 * 24 * 3600 * 1000); + helpers.createAddresses(server, wallet, 2, 0, function(addrs) { + newAddrs = addrs; + helpers.stubUtxos( + server, + wallet, + [1, 2], + { + addresses: [oldAddrs[0], newAddrs[0]], + }, + function() { + next(); + }, + ); + }); + }, + function(next) { + server.getBalance( + { + twoStep: true, + }, + function(err, balance) { + should.not.exist(err); + should.exist(balance); + balance.totalAmount.should.equal(helpers.toMicro(3)); + next(); + }, + ); + }, + function(next) { + setTimeout(next, 100); + }, + function(next) { + server.getNotifications({}, function(err, notifications) { + should.not.exist(err); + var last = _.last(notifications); + last.type.should.not.equal('BalanceUpdated'); + next(); + }); + }, + ], + function(err) { + should.not.exist(err); + done(); }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); }); }); @@ -2200,28 +2421,34 @@ describe('Wallet service', function() { var server, wallet, levels; before(function() { levels = Defaults.FEE_LEVELS; - Defaults.FEE_LEVELS = [{ - name: 'urgent', - nbBlocks: 1, - multiplier: 1.5, - defaultValue: 50000, - }, { - name: 'priority', - nbBlocks: 1, - defaultValue: 50000 - }, { - name: 'normal', - nbBlocks: 2, - defaultValue: 40000 - }, { - name: 'economy', - nbBlocks: 6, - defaultValue: 25000 - }, { - name: 'superEconomy', - nbBlocks: 24, - defaultValue: 10000 - }]; + Defaults.FEE_LEVELS = [ + { + name: 'urgent', + nbBlocks: 1, + multiplier: 1.5, + defaultValue: 50000, + }, + { + name: 'priority', + nbBlocks: 1, + defaultValue: 50000, + }, + { + name: 'normal', + nbBlocks: 2, + defaultValue: 40000, + }, + { + name: 'economy', + nbBlocks: 6, + defaultValue: 25000, + }, + { + name: 'superEconomy', + nbBlocks: 24, + defaultValue: 10000, + }, + ]; }); after(function() { Defaults.FEE_LEVELS = levels; @@ -2243,9 +2470,11 @@ describe('Wallet service', function() { }); server.getFeeLevels({}, function(err, fees) { should.not.exist(err); - fees = _.zipObject(_.map(fees, function(item) { - return [item.level, item]; - })); + fees = _.zipObject( + _.map(fees, function(item) { + return [item.level, item]; + }), + ); fees.urgent.feePerKb.should.equal(60000); fees.urgent.nbBlocks.should.equal(1); @@ -2267,12 +2496,16 @@ describe('Wallet service', function() { blockchainExplorer.estimateFee = sinon.stub().yields('dummy error'); server.getFeeLevels({}, function(err, fees) { should.not.exist(err); - fees = _.zipObject(_.map(fees, function(item) { - return [item.level, item.feePerKb]; - })); - var defaults = _.zipObject(_.map(Defaults.FEE_LEVELS, function(item) { - return [item.name, item.defaultValue]; - })); + fees = _.zipObject( + _.map(fees, function(item) { + return [item.level, item.feePerKb]; + }), + ); + var defaults = _.zipObject( + _.map(Defaults.FEE_LEVELS, function(item) { + return [item.name, item.defaultValue]; + }), + ); fees.priority.should.equal(defaults.priority); fees.normal.should.equal(defaults.normal); fees.economy.should.equal(defaults.economy); @@ -2289,9 +2522,11 @@ describe('Wallet service', function() { }); server.getFeeLevels({}, function(err, fees) { should.not.exist(err); - fees = _.zipObject(_.map(fees, function(item) { - return [item.level, item]; - })); + fees = _.zipObject( + _.map(fees, function(item) { + return [item.level, item]; + }), + ); fees.priority.feePerKb.should.equal(18000); fees.priority.nbBlocks.should.equal(2); @@ -2317,9 +2552,11 @@ describe('Wallet service', function() { }); server.getFeeLevels({}, function(err, fees) { should.not.exist(err); - fees = _.zipObject(_.map(fees, function(item) { - return [item.level, item]; - })); + fees = _.zipObject( + _.map(fees, function(item) { + return [item.level, item]; + }), + ); fees.priority.feePerKb.should.equal(45000); fees.priority.nbBlocks.should.equal(1); @@ -2334,7 +2571,7 @@ describe('Wallet service', function() { }); it('should get monotonically decreasing fee values', function(done) { _.find(Defaults.FEE_LEVELS, { - nbBlocks: 6 + nbBlocks: 6, }).defaultValue.should.equal(25000); helpers.stubFeeLevels({ 1: 45000, @@ -2346,9 +2583,11 @@ describe('Wallet service', function() { }); server.getFeeLevels({}, function(err, fees) { should.not.exist(err); - fees = _.zipObject(_.map(fees, function(item) { - return [item.level, item]; - })); + fees = _.zipObject( + _.map(fees, function(item) { + return [item.level, item]; + }), + ); fees.priority.feePerKb.should.equal(45000); fees.priority.nbBlocks.should.equal(1); @@ -2420,11 +2659,13 @@ describe('Wallet service', function() { should.not.exist(err); helpers.getAuthServer(result.copayerId, function(server, wallet) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], - feePerKb: 100e2 + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], + feePerKb: 100e2, }; server.createTx(txOpts, function(err, tx) { should.not.exist(tx); @@ -2452,10 +2693,12 @@ describe('Wallet service', function() { it('should create a tx', function(done) { helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8 * 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8 * 1e8, + }, + ], message: 'some message', customData: 'some custom data', feePerKb: 123e2, @@ -2501,10 +2744,12 @@ describe('Wallet service', function() { it('should fail to create tx for invalid address', function(done) { helpers.stubUtxos(server, wallet, 1, function() { var txOpts = { - outputs: [{ - toAddress: 'invalid address', - amount: 0.5e8 - }], + outputs: [ + { + toAddress: 'invalid address', + amount: 0.5e8, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, tx) { @@ -2518,10 +2763,12 @@ describe('Wallet service', function() { it('should fail to create tx for address of different network', function(done) { helpers.stubUtxos(server, wallet, 1, function() { var txOpts = { - outputs: [{ - toAddress: 'myE38JHdxmQcTJGP1ZiX4BiGhDxMJDvLJD', - amount: 0.5e8 - }], + outputs: [ + { + toAddress: 'myE38JHdxmQcTJGP1ZiX4BiGhDxMJDvLJD', + amount: 0.5e8, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, tx) { @@ -2535,10 +2782,12 @@ describe('Wallet service', function() { }); it('should fail to create tx for invalid amount', function(done) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, tx) { @@ -2551,10 +2800,12 @@ describe('Wallet service', function() { it('should fail to specify both feeLevel & feePerKb', function(done) { helpers.stubUtxos(server, wallet, 2, function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1e8, + }, + ], feeLevel: 'normal', feePerKb: 123e2, }; @@ -2572,10 +2823,12 @@ describe('Wallet service', function() { should.not.exist(err); var inputs = [utxos[0], utxos[2]]; var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 2.5e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 2.5e8, + }, + ], feePerKb: 100e2, inputs: inputs, }; @@ -2592,14 +2845,16 @@ describe('Wallet service', function() { }); }); - // skip for singleAddress = true + // skip for singleAddress = true it.skip('should be able to specify change address', function(done) { helpers.stubUtxos(server, wallet, [1, 2], function(utxos) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], feePerKb: 100e2, changeAddress: utxos[0].address, }; @@ -2607,7 +2862,10 @@ describe('Wallet service', function() { should.not.exist(err); should.exist(tx); var t = tx.getMeritcoreTx(); - t.getChangeOutput().script.toAddress().toString().should.equal(txOpts.changeAddress); + t.getChangeOutput() + .script.toAddress() + .toString() + .should.equal(txOpts.changeAddress); done(); }); }); @@ -2616,10 +2874,12 @@ describe('Wallet service', function() { it('should be able to specify inputs & absolute fee', function(done) { helpers.stubUtxos(server, wallet, [1, 2], function(utxos) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], inputs: utxos, fee: 1000e2, }; @@ -2643,10 +2903,12 @@ describe('Wallet service', function() { helpers.stubUtxos(server, wallet, 2, function() { var txOpts = { txProposalId: '123', - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1e8, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, tx) { @@ -2661,10 +2923,12 @@ describe('Wallet service', function() { helpers.stubUtxos(server, wallet, 2, function() { var txOpts = { txProposalId: '123', - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1e8, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, tx) { @@ -2689,10 +2953,12 @@ describe('Wallet service', function() { helpers.stubUtxos(server, wallet, [2, 2, 2], function() { var txOpts = { txProposalId: '123', - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1e8, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, tx) { @@ -2724,10 +2990,12 @@ describe('Wallet service', function() { it('should be able to publish a temporary tx proposal', function(done) { helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8 * 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8 * 1e8, + }, + ], feePerKb: 100e2, message: 'some message', customData: 'some custom data', @@ -2751,10 +3019,12 @@ describe('Wallet service', function() { it('should not be able to publish a temporary tx proposal created in a dry run', function(done) { helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8 * 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8 * 1e8, + }, + ], feePerKb: 100e2, dryRun: true, }; @@ -2777,10 +3047,12 @@ describe('Wallet service', function() { it('should delay NewTxProposal notification until published', function(done) { helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8 * 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8 * 1e8, + }, + ], feePerKb: 100e2, message: 'some message', }; @@ -2797,7 +3069,7 @@ describe('Wallet service', function() { should.not.exist(err); var n = _.find(notifications, { - 'type': 'NewTxProposal' + type: 'NewTxProposal', }); should.exist(n); should.exist(n.data.txProposalId); @@ -2812,49 +3084,59 @@ describe('Wallet service', function() { }); }); it('should fail to publish non-existent tx proposal', function(done) { - server.publishTx({ - txProposalId: 'wrong-id', - proposalSignature: 'dummy', - }, function(err) { - should.exist(err); - server.getPendingTxs({}, function(err, txs) { - should.not.exist(err); - txs.should.be.empty; - done(); - }); - }); + server.publishTx( + { + txProposalId: 'wrong-id', + proposalSignature: 'dummy', + }, + function(err) { + should.exist(err); + server.getPendingTxs({}, function(err, txs) { + should.not.exist(err); + txs.should.be.empty; + done(); + }); + }, + ); }); it('should fail to publish tx proposal with wrong signature', function(done) { helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8 * 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8 * 1e8, + }, + ], feePerKb: 100e2, message: 'some message', }; server.createTx(txOpts, function(err, txp) { should.not.exist(err); should.exist(txp); - server.publishTx({ - txProposalId: txp.id, - proposalSignature: 'dummy' - }, function(err) { - should.exist(err); - err.message.should.contain('Invalid proposal signature'); - done(); - }); + server.publishTx( + { + txProposalId: txp.id, + proposalSignature: 'dummy', + }, + function(err) { + should.exist(err); + err.message.should.contain('Invalid proposal signature'); + done(); + }, + ); }); }); }); it('should fail to publish tx proposal not signed by the creator', function(done) { helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8 * 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8 * 1e8, + }, + ], feePerKb: 100e2, message: 'some message', }; @@ -2865,7 +3147,7 @@ describe('Wallet service', function() { var publishOpts = { txProposalId: txp.id, proposalSignature: helpers.signMessage(txp.getRawTx(), TestData.copayers[1].privKey_1H_0), - } + }; server.publishTx(publishOpts, function(err) { should.exist(err); @@ -2878,135 +3160,149 @@ describe('Wallet service', function() { it('should fail to publish a temporary tx proposal if utxos are locked by other pending proposals', function(done) { var txp1, txp2; var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8 * 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8 * 1e8, + }, + ], message: 'some message', feePerKb: 100e2, }; - async.waterfall([ - - function(next) { - helpers.stubUtxos(server, wallet, [1, 2], function() { - next(); - }); - }, - function(next) { - server.createTx(txOpts, next); - }, - function(txp, next) { - txp1 = txp; - server.createTx(txOpts, next); - }, - function(txp, next) { - txp2 = txp; - should.exist(txp1); - should.exist(txp2); - var publishOpts = helpers.getProposalSignatureOpts(txp1, TestData.copayers[0].privKey_1H_0); - server.publishTx(publishOpts, next); - }, - function(txp, next) { - var publishOpts = helpers.getProposalSignatureOpts(txp2, TestData.copayers[0].privKey_1H_0); - server.publishTx(publishOpts, function(err) { - should.exist(err); - err.code.should.equal('UNAVAILABLE_UTXOS'); - next(); - }); - }, - function(next) { - server.getPendingTxs({}, function(err, txs) { - should.not.exist(err); - txs.length.should.equal(1); - next(); - }); - }, - function(next) { - // A new tx proposal should use the next available UTXO - server.createTx(txOpts, next); - }, - function(txp3, next) { - should.exist(txp3); - var publishOpts = helpers.getProposalSignatureOpts(txp3, TestData.copayers[0].privKey_1H_0); - server.publishTx(publishOpts, next); - }, - function(txp, next) { - server.getPendingTxs({}, function(err, txs) { - should.not.exist(err); - txs.length.should.equal(2); - next(); - }); + async.waterfall( + [ + function(next) { + helpers.stubUtxos(server, wallet, [1, 2], function() { + next(); + }); + }, + function(next) { + server.createTx(txOpts, next); + }, + function(txp, next) { + txp1 = txp; + server.createTx(txOpts, next); + }, + function(txp, next) { + txp2 = txp; + should.exist(txp1); + should.exist(txp2); + var publishOpts = helpers.getProposalSignatureOpts(txp1, TestData.copayers[0].privKey_1H_0); + server.publishTx(publishOpts, next); + }, + function(txp, next) { + var publishOpts = helpers.getProposalSignatureOpts(txp2, TestData.copayers[0].privKey_1H_0); + server.publishTx(publishOpts, function(err) { + should.exist(err); + err.code.should.equal('UNAVAILABLE_UTXOS'); + next(); + }); + }, + function(next) { + server.getPendingTxs({}, function(err, txs) { + should.not.exist(err); + txs.length.should.equal(1); + next(); + }); + }, + function(next) { + // A new tx proposal should use the next available UTXO + server.createTx(txOpts, next); + }, + function(txp3, next) { + should.exist(txp3); + var publishOpts = helpers.getProposalSignatureOpts(txp3, TestData.copayers[0].privKey_1H_0); + server.publishTx(publishOpts, next); + }, + function(txp, next) { + server.getPendingTxs({}, function(err, txs) { + should.not.exist(err); + txs.length.should.equal(2); + next(); + }); + }, + ], + function(err) { + should.not.exist(err); + done(); }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); }); it('should fail to publish a temporary tx proposal if utxos are already spent', function(done) { var txp1, txp2; var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8 * 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8 * 1e8, + }, + ], message: 'some message', feePerKb: 100e2, }; - async.waterfall([ - - function(next) { - helpers.stubUtxos(server, wallet, [1, 2], function() { - next(); - }); - }, - function(next) { - server.createTx(txOpts, next); - }, - function(txp, next) { - txp1 = txp; - server.createTx(txOpts, next); - }, - function(txp, next) { - txp2 = txp; - should.exist(txp1); - should.exist(txp2); - var publishOpts = helpers.getProposalSignatureOpts(txp1, TestData.copayers[0].privKey_1H_0); - server.publishTx(publishOpts, next); - }, - function(txp, next) { - // Sign & Broadcast txp1 - var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: txp.id, - signatures: signatures, - }, function(err, txp) { - should.not.exist(err); + async.waterfall( + [ + function(next) { + helpers.stubUtxos(server, wallet, [1, 2], function() { + next(); + }); + }, + function(next) { + server.createTx(txOpts, next); + }, + function(txp, next) { + txp1 = txp; + server.createTx(txOpts, next); + }, + function(txp, next) { + txp2 = txp; + should.exist(txp1); + should.exist(txp2); + var publishOpts = helpers.getProposalSignatureOpts(txp1, TestData.copayers[0].privKey_1H_0); + server.publishTx(publishOpts, next); + }, + function(txp, next) { + // Sign & Broadcast txp1 + var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_44H_0H_0H); + server.signTx( + { + txProposalId: txp.id, + signatures: signatures, + }, + function(err, txp) { + should.not.exist(err); - helpers.stubBroadcast(); - server.broadcastTx({ - txProposalId: txp.id - }, function(err, txp) { - should.not.exist(err); - should.exist(txp.txid); - txp.status.should.equal('broadcasted'); + helpers.stubBroadcast(); + server.broadcastTx( + { + txProposalId: txp.id, + }, + function(err, txp) { + should.not.exist(err); + should.exist(txp.txid); + txp.status.should.equal('broadcasted'); + next(); + }, + ); + }, + ); + }, + function(next) { + var publishOpts = helpers.getProposalSignatureOpts(txp2, TestData.copayers[0].privKey_1H_0); + server.publishTx(publishOpts, function(err) { + should.exist(err); + err.code.should.equal('UNAVAILABLE_UTXOS'); next(); }); - }); - }, - function(next) { - var publishOpts = helpers.getProposalSignatureOpts(txp2, TestData.copayers[0].privKey_1H_0); - server.publishTx(publishOpts, function(err) { - should.exist(err); - err.code.should.equal('UNAVAILABLE_UTXOS'); - next(); - }); + }, + ], + function(err) { + should.not.exist(err); + done(); }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); }); }); @@ -3020,10 +3316,12 @@ describe('Wallet service', function() { }); helpers.stubUtxos(server, wallet, 2, function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1e8, + }, + ], feeLevel: 'economy', }; server.createTx(txOpts, function(err, txp) { @@ -3038,10 +3336,12 @@ describe('Wallet service', function() { it('should fail if the specified fee level does not exist', function(done) { helpers.stubUtxos(server, wallet, 2, function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1e8, + }, + ], feeLevel: 'madeUpLevel', }; server.createTx(txOpts, function(err, txp) { @@ -3061,10 +3361,12 @@ describe('Wallet service', function() { }); helpers.stubUtxos(server, wallet, 2, function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1e8, + }, + ], }; server.createTx(txOpts, function(err, txp) { should.not.exist(err); @@ -3081,10 +3383,12 @@ describe('Wallet service', function() { it.skip('should generate new change address for each created tx', function(done) { helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, tx1) { @@ -3104,10 +3408,12 @@ describe('Wallet service', function() { helpers.stubUtxos(server, wallet, [1, 2], function() { var max = 3e8 - 7000; // Fees for this tx at 100bits/kB = 7000 micros var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: max, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: max, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, txp) { @@ -3125,10 +3431,12 @@ describe('Wallet service', function() { server.createAddress({}, function(err, address) { should.not.exist(err); var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1e8 - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1e8, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, tx) { @@ -3143,13 +3451,15 @@ describe('Wallet service', function() { var meritcoreStub = sinon.stub(Meritcore, 'Transaction'); meritcoreStub.throws({ name: 'dummy', - message: 'dummy exception' + message: 'dummy exception', }); var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.5e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.5e8, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, tx) { @@ -3165,10 +3475,12 @@ describe('Wallet service', function() { Defaults.MAX_TX_SIZE_IN_KB = 1; helpers.stubUtxos(server, wallet, _.range(1, 10, 0), function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 8e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 8e8, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, tx) { @@ -3182,10 +3494,12 @@ describe('Wallet service', function() { it('should fail with different error for insufficient funds and locked funds', function(done) { helpers.stubUtxos(server, wallet, [1, 1], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1.1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1.1e8, + }, + ], feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { @@ -3207,10 +3521,12 @@ describe('Wallet service', function() { it('should fail to create tx for dust amount in outputs', function(done) { helpers.stubUtxos(server, wallet, 1, function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 20e2, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 20e2, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, tx) { @@ -3227,10 +3543,12 @@ describe('Wallet service', function() { var amount = 1e8 - fee; var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: amount, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: amount, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, tx) { @@ -3246,10 +3564,12 @@ describe('Wallet service', function() { it('should create tx when there is a pending tx and enough UTXOs', function(done) { helpers.stubUtxos(server, wallet, [1.1, 1.2, 1.3], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1.5e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1.5e8, + }, + ], feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { @@ -3274,10 +3594,12 @@ describe('Wallet service', function() { it('should fail to create tx when there is a pending tx and not enough UTXOs', function(done) { helpers.stubUtxos(server, wallet, [1.1, 1.2, 1.3], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1.5e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1.5e8, + }, + ], feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { @@ -3320,10 +3642,12 @@ describe('Wallet service', function() { helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8 * 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8 * 1e8, + }, + ], message: 'some message', feePerKb: 100e2, }; @@ -3334,19 +3658,22 @@ describe('Wallet service', function() { var publishOpts = { txProposalId: txp.id, proposalSignature: helpers.signMessage(txp.getRawTx(), reqPrivKey), - } + }; server.publishTx(publishOpts, function(err) { should.not.exist(err); - server.getTx({ - txProposalId: txp.id - }, function(err, x) { - should.not.exist(err); - x.proposalSignature.should.equal(publishOpts.proposalSignature); - x.proposalSignaturePubKey.should.equal(accessOpts.requestPubKey); - x.proposalSignaturePubKeySig.should.equal(accessOpts.signature); - done(); - }); + server.getTx( + { + txProposalId: txp.id, + }, + function(err, x) { + should.not.exist(err); + x.proposalSignature.should.equal(publishOpts.proposalSignature); + x.proposalSignaturePubKey.should.equal(accessOpts.requestPubKey); + x.proposalSignaturePubKeySig.should.equal(accessOpts.signature); + done(); + }, + ); }); }); }); @@ -3355,10 +3682,12 @@ describe('Wallet service', function() { it('should be able to send max funds', function(done) { helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: null, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: null, + }, + ], feePerKb: 10000, sendMax: true, }; @@ -3435,73 +3764,92 @@ describe('Wallet service', function() { it('should follow backoff time after consecutive rejections', function(done) { clock = sinon.useFakeTimers(Date.now(), 'Date'); var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1e8, + }, + ], feePerKb: 100e2, }; - async.series([ - - function(next) { - async.each(_.range(3), function(i, next) { - helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { - server.rejectTx({ + async.series( + [ + function(next) { + async.each( + _.range(3), + function(i, next) { + helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { + server.rejectTx( + { + txProposalId: tx.id, + reason: 'some reason', + }, + next, + ); + }); + }, + next, + ); + }, + function(next) { + // Allow a 4th tx + helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { + server.rejectTx( + { txProposalId: tx.id, reason: 'some reason', - }, next); - }); - }, - next); + }, + next, + ); + }); + }, + function(next) { + // Do not allow before backoff time + server.createTx(txOpts, function(err, tx) { + should.exist(err); + err.code.should.equal('TX_CANNOT_CREATE'); + next(); + }); + }, + function(next) { + clock.tick((Defaults.BACKOFF_TIME + 1) * 1000); + helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { + server.rejectTx( + { + txProposalId: tx.id, + reason: 'some reason', + }, + next, + ); + }); + }, + function(next) { + // Do not allow a 5th tx before backoff time + clock.tick((Defaults.BACKOFF_TIME - 1) * 1000); + server.createTx(txOpts, function(err, tx) { + should.exist(err); + err.code.should.equal('TX_CANNOT_CREATE'); + next(); + }); + }, + function(next) { + clock.tick(2000); + helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { + server.rejectTx( + { + txProposalId: tx.id, + reason: 'some reason', + }, + next, + ); + }); + }, + ], + function(err) { + should.not.exist(err); + done(); }, - function(next) { - // Allow a 4th tx - helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { - server.rejectTx({ - txProposalId: tx.id, - reason: 'some reason', - }, next); - }); - }, - function(next) { - // Do not allow before backoff time - server.createTx(txOpts, function(err, tx) { - should.exist(err); - err.code.should.equal('TX_CANNOT_CREATE'); - next(); - }); - }, - function(next) { - clock.tick((Defaults.BACKOFF_TIME + 1) * 1000); - helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { - server.rejectTx({ - txProposalId: tx.id, - reason: 'some reason', - }, next); - }); - }, - function(next) { - // Do not allow a 5th tx before backoff time - clock.tick((Defaults.BACKOFF_TIME - 1) * 1000); - server.createTx(txOpts, function(err, tx) { - should.exist(err); - err.code.should.equal('TX_CANNOT_CREATE'); - next(); - }); - }, - function(next) { - clock.tick(2000); - helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { - server.rejectTx({ - txProposalId: tx.id, - reason: 'some reason', - }, next); - }); - }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); }); }); @@ -3522,10 +3870,12 @@ describe('Wallet service', function() { it('should exclude unconfirmed utxos if specified', function(done) { helpers.stubUtxos(server, wallet, [1.3, 'u2', 'u0.1', 1.2], function(utxos) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 3e8 - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 3e8, + }, + ], feePerKb: 100e2, excludeUnconfirmedUtxos: true, }; @@ -3546,10 +3896,12 @@ describe('Wallet service', function() { it('should use non-locked confirmed utxos when specified', function(done) { helpers.stubUtxos(server, wallet, [1.3, 'u2', 'u0.1', 1.2], function(utxos) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1.4e8 - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1.4e8, + }, + ], feePerKb: 100e2, excludeUnconfirmedUtxos: true, }; @@ -3573,10 +3925,12 @@ describe('Wallet service', function() { it('should not use UTXO provided in utxosToExclude option', function(done) { helpers.stubUtxos(server, wallet, [1, 2, 3], function(utxos) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 3.5e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 3.5e8, + }, + ], feePerKb: 100e2, utxosToExclude: [utxos[2].txid + ':' + utxos[2].vout], }; @@ -3596,10 +3950,12 @@ describe('Wallet service', function() { it('should select a single utxo if within thresholds relative to tx amount', function(done) { helpers.stubUtxos(server, wallet, [1, '350bit', '100bit', '100bit', '100bit'], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 200e2, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 200e2, + }, + ], feePerKb: 10e2, }; server.createTx(txOpts, function(err, txp) { @@ -3616,10 +3972,12 @@ describe('Wallet service', function() { // NOTE: this test has a chance of failing of 1 in 1'073'741'824 :P helpers.stubUtxos(server, wallet, _.range(1, 31), function(utxos) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: _.sumBy(utxos, 'micros') - 0.5e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: _.sumBy(utxos, 'micros') - 0.5e8, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, txp) { @@ -3638,10 +3996,12 @@ describe('Wallet service', function() { it('should select a confirmed utxos if within thresholds relative to tx amount', function(done) { helpers.stubUtxos(server, wallet, [1, 'u 350bit', '100bit', '100bit', '100bit'], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 200e2, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 200e2, + }, + ], feePerKb: 10e2, }; server.createTx(txOpts, function(err, txp) { @@ -3657,10 +4017,12 @@ describe('Wallet service', function() { it('should select smaller utxos if within fee constraints', function(done) { helpers.stubUtxos(server, wallet, [1, '800bit', '800bit', '800bit'], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 2000e2, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 2000e2, + }, + ], feePerKb: 10e2, }; server.createTx(txOpts, function(err, txp) { @@ -3677,10 +4039,12 @@ describe('Wallet service', function() { it('should select smallest big utxo if small utxos are insufficient', function(done) { helpers.stubUtxos(server, wallet, [3, 1, 2, '100bit', '100bit', '100bit'], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 300e2, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 300e2, + }, + ], feePerKb: 10e2, }; server.createTx(txOpts, function(err, txp) { @@ -3699,10 +4063,12 @@ describe('Wallet service', function() { // because it cannot cover for fee on its own. helpers.stubUtxos(server, wallet, [1, '605bit', '100bit', '100bit', '100bit'], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 300e2, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 300e2, + }, + ], feePerKb: 1200e2, }; server.createTx(txOpts, function(err, txp) { @@ -3716,33 +4082,44 @@ describe('Wallet service', function() { }); }); it('should select smallest big utxo if small utxos exceed maximum fee', function(done) { - helpers.stubUtxos(server, wallet, [3, 1, 2].concat(_.times(20, function() { - return '1000bit'; - })), function() { - var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 12000e2, - }], - feePerKb: 20e2, - }; - server.createTx(txOpts, function(err, txp) { - should.not.exist(err); - should.exist(txp); - txp.inputs.length.should.equal(1); - txp.inputs[0].micros.should.equal(1e8); + helpers.stubUtxos( + server, + wallet, + [3, 1, 2].concat( + _.times(20, function() { + return '1000bit'; + }), + ), + function() { + var txOpts = { + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 12000e2, + }, + ], + feePerKb: 20e2, + }; + server.createTx(txOpts, function(err, txp) { + should.not.exist(err); + should.exist(txp); + txp.inputs.length.should.equal(1); + txp.inputs[0].micros.should.equal(1e8); - done(); - }); - }); + done(); + }); + }, + ); }); it('should select smallest big utxo if small utxos are below accepted ratio of txp amount', function(done) { helpers.stubUtxos(server, wallet, [9, 1, 1, 0.5, 0.2, 0.2, 0.2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 3e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 3e8, + }, + ], feePerKb: 10e2, }; server.createTx(txOpts, function(err, txp) { @@ -3762,10 +4139,12 @@ describe('Wallet service', function() { helpers.stubUtxos(server, wallet, [100].concat(_.range(1, 20, 0)), function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 15e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 15e8, + }, + ], feePerKb: 120e2, }; server.createTx(txOpts, function(err, txp) { @@ -3782,10 +4161,12 @@ describe('Wallet service', function() { it('should ignore utxos not contributing enough to cover increase in fee', function(done) { helpers.stubUtxos(server, wallet, ['100bit', '100bit', '100bit'], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 200e2, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 200e2, + }, + ], feePerKb: 80e2, }; server.createTx(txOpts, function(err, txp) { @@ -3804,10 +4185,12 @@ describe('Wallet service', function() { it('should fail to select utxos if not enough to cover tx amount', function(done) { helpers.stubUtxos(server, wallet, ['100bit', '100bit', '100bit'], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 400e2, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 400e2, + }, + ], feePerKb: 10e2, }; server.createTx(txOpts, function(err, txp) { @@ -3821,10 +4204,12 @@ describe('Wallet service', function() { it('should fail to select utxos if not enough to cover fees', function(done) { helpers.stubUtxos(server, wallet, ['100bit', '100bit', '100bit'], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 299e2, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 299e2, + }, + ], feePerKb: 10e2, }; server.createTx(txOpts, function(err, txp) { @@ -3836,33 +4221,44 @@ describe('Wallet service', function() { }); }); it('should prefer a higher fee (breaking all limits) if inputs have 6+ confirmations', function(done) { - helpers.stubUtxos(server, wallet, ['2c 2000bit'].concat(_.times(20, function() { - return '100bit'; - })), function() { - var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1500e2, - }], - feePerKb: 10e2, - }; - server.createTx(txOpts, function(err, txp) { - should.not.exist(err); - should.exist(txp); - _.every(txp.inputs, function(input) { - return input == 100e2; + helpers.stubUtxos( + server, + wallet, + ['2c 2000bit'].concat( + _.times(20, function() { + return '100bit'; + }), + ), + function() { + var txOpts = { + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1500e2, + }, + ], + feePerKb: 10e2, + }; + server.createTx(txOpts, function(err, txp) { + should.not.exist(err); + should.exist(txp); + _.every(txp.inputs, function(input) { + return input == 100e2; + }); + done(); }); - done(); - }); - }); + }, + ); }); it('should select unconfirmed utxos if not enough confirmed utxos', function(done) { helpers.stubUtxos(server, wallet, ['u 1mrt', '0.5mrt'], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, txp) { @@ -3875,50 +4271,70 @@ describe('Wallet service', function() { }); }); it('should ignore utxos too small to pay for fee', function(done) { - helpers.stubUtxos(server, wallet, ['1c200bit', '200bit'].concat(_.times(20, function() { - return '1bit'; - })), function() { - var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 200e2, - }], - feePerKb: 90e2, - }; - server.createTx(txOpts, function(err, txp) { - should.not.exist(err); - should.exist(txp); - txp.inputs.length.should.equal(2); - done(); - }); - }); + helpers.stubUtxos( + server, + wallet, + ['1c200bit', '200bit'].concat( + _.times(20, function() { + return '1bit'; + }), + ), + function() { + var txOpts = { + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 200e2, + }, + ], + feePerKb: 90e2, + }; + server.createTx(txOpts, function(err, txp) { + should.not.exist(err); + should.exist(txp); + txp.inputs.length.should.equal(2); + done(); + }); + }, + ); }); it('should use small utxos if fee is low', function(done) { - helpers.stubUtxos(server, wallet, [].concat(_.times(10, function() { - return '30bit'; - })), function() { - var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 200e2, - }], - feePerKb: 10e2, - }; - server.createTx(txOpts, function(err, txp) { - should.not.exist(err); - should.exist(txp); - txp.inputs.length.should.equal(8); - done(); - }); - }); + helpers.stubUtxos( + server, + wallet, + [].concat( + _.times(10, function() { + return '30bit'; + }), + ), + function() { + var txOpts = { + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 200e2, + }, + ], + feePerKb: 10e2, + }; + server.createTx(txOpts, function(err, txp) { + should.not.exist(err); + should.exist(txp); + txp.inputs.length.should.equal(8); + done(); + }); + }, + ); }); it('should correct fee if resulting change would be below threshold', function(done) { helpers.stubUtxos(server, wallet, ['200bit', '500micros'], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 150e2, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 150e2, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, txp) { @@ -3932,30 +4348,41 @@ describe('Wallet service', function() { }); }); it('should ignore small utxos if fee is higher', function(done) { - helpers.stubUtxos(server, wallet, [].concat(_.times(10, function() { - return '30bit'; - })), function() { - var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 200e2, - }], - feePerKb: 80e2, - }; - server.createTx(txOpts, function(err, txp) { - should.exist(err); - err.code.should.equal('INSUFFICIENT_FUNDS_FOR_FEE'); - done(); - }); - }); + helpers.stubUtxos( + server, + wallet, + [].concat( + _.times(10, function() { + return '30bit'; + }), + ), + function() { + var txOpts = { + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 200e2, + }, + ], + feePerKb: 80e2, + }; + server.createTx(txOpts, function(err, txp) { + should.exist(err); + err.code.should.equal('INSUFFICIENT_FUNDS_FOR_FEE'); + done(); + }); + }, + ); }); it('should always select inputs as long as there are sufficient funds', function(done) { helpers.stubUtxos(server, wallet, [80, '50bit', '50bit', '50bit', '50bit', '50bit'], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 101e2, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 101e2, + }, + ], feePerKb: 100e2, }; server.createTx(txOpts, function(err, txp) { @@ -3968,37 +4395,45 @@ describe('Wallet service', function() { it('should not use UTXOs of recently broadcasted txs', function(done) { helpers.stubUtxos(server, wallet, [1, 1], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1.5e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1.5e8, + }, + ], feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(txp) { should.exist(txp); var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: txp.id, - signatures: signatures, - }, function(err, txp) { - should.not.exist(err); - should.exist(txp); - - helpers.stubBroadcast(); - server.broadcastTx({ - txProposalId: txp.id - }, function(err, txp) { + server.signTx( + { + txProposalId: txp.id, + signatures: signatures, + }, + function(err, txp) { should.not.exist(err); - should.exist(txp.txid); - txp.status.should.equal('broadcasted'); - server.createTx(txOpts, function(err, txp) { - should.exist(err); - err.code.should.equal('INSUFFICIENT_FUNDS'); - should.not.exist(txp); - done(); - }); - }); - }); + should.exist(txp); + + helpers.stubBroadcast(); + server.broadcastTx( + { + txProposalId: txp.id, + }, + function(err, txp) { + should.not.exist(err); + should.exist(txp.txid); + txp.status.should.equal('broadcasted'); + server.createTx(txOpts, function(err, txp) { + should.exist(err); + err.code.should.equal('INSUFFICIENT_FUNDS'); + should.not.exist(txp); + done(); + }); + }, + ); + }, + ); }); }); }); @@ -4016,314 +4451,404 @@ describe('Wallet service', function() { }); it('should edit a note for an arbitrary txid', function(done) { - server.editTxNote({ - txid: '123', - body: 'note body' - }, function(err, note) { - should.not.exist(err); - note.txid.should.equal('123'); - note.walletId.should.equal(wallet.id); - note.body.should.equal('note body'); - note.editedBy.should.equal(server.copayerId); - note.editedByName.should.equal('copayer 1'); - note.createdOn.should.equal(note.editedOn); - server.getTxNote({ + server.editTxNote( + { txid: '123', - }, function(err, note) { + body: 'note body', + }, + function(err, note) { should.not.exist(err); - should.exist(note); + note.txid.should.equal('123'); + note.walletId.should.equal(wallet.id); note.body.should.equal('note body'); note.editedBy.should.equal(server.copayerId); - done(); - }); - }); + note.editedByName.should.equal('copayer 1'); + note.createdOn.should.equal(note.editedOn); + server.getTxNote( + { + txid: '123', + }, + function(err, note) { + should.not.exist(err); + should.exist(note); + note.body.should.equal('note body'); + note.editedBy.should.equal(server.copayerId); + done(); + }, + ); + }, + ); }); it('should preserve last edit', function(done) { var clock = sinon.useFakeTimers('Date'); - server.editTxNote({ - txid: '123', - body: 'note body' - }, function(err) { - should.not.exist(err); - server.getTxNote({ + server.editTxNote( + { txid: '123', - }, function(err, note) { + body: 'note body', + }, + function(err) { should.not.exist(err); - should.exist(note); - note.editedBy.should.equal(server.copayerId); - note.createdOn.should.equal(note.editedOn); - var creator = note.editedBy; - helpers.getAuthServer(wallet.copayers[1].id, function(server) { - clock.tick(60 * 1000); - server.editTxNote({ + server.getTxNote( + { txid: '123', - body: 'edited text' - }, function(err) { + }, + function(err, note) { should.not.exist(err); - server.getTxNote({ - txid: '123', - }, function(err, note) { - should.not.exist(err); - should.exist(note); - note.editedBy.should.equal(server.copayerId); - note.createdOn.should.be.below(note.editedOn); - creator.should.not.equal(note.editedBy); - clock.restore(); - done(); + should.exist(note); + note.editedBy.should.equal(server.copayerId); + note.createdOn.should.equal(note.editedOn); + var creator = note.editedBy; + helpers.getAuthServer(wallet.copayers[1].id, function(server) { + clock.tick(60 * 1000); + server.editTxNote( + { + txid: '123', + body: 'edited text', + }, + function(err) { + should.not.exist(err); + server.getTxNote( + { + txid: '123', + }, + function(err, note) { + should.not.exist(err); + should.exist(note); + note.editedBy.should.equal(server.copayerId); + note.createdOn.should.be.below(note.editedOn); + creator.should.not.equal(note.editedBy); + clock.restore(); + done(); + }, + ); + }, + ); }); - }); - }); - }); - }); + }, + ); + }, + ); }); it('should edit a note for an outgoing tx and retrieve it', function(done) { helpers.stubUtxos(server, wallet, 2, function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1e8, + }, + ], message: 'some message', feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(txp) { should.exist(txp); var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: txp.id, - signatures: signatures, - }, function(err, txp) { - should.not.exist(err); - should.exist(txp); - should.exist(txp.txid); - server.editTxNote({ - txid: txp.txid, - body: 'note body' - }, function(err) { + server.signTx( + { + txProposalId: txp.id, + signatures: signatures, + }, + function(err, txp) { should.not.exist(err); - server.getTx({ - txProposalId: txp.id, - }, function(err, txp) { - should.not.exist(err); - should.exist(txp.note); - txp.note.txid.should.equal(txp.txid); - txp.note.walletId.should.equal(wallet.id); - txp.note.body.should.equal('note body'); - txp.note.editedBy.should.equal(server.copayerId); - done(); - }); - }); - }); + should.exist(txp); + should.exist(txp.txid); + server.editTxNote( + { + txid: txp.txid, + body: 'note body', + }, + function(err) { + should.not.exist(err); + server.getTx( + { + txProposalId: txp.id, + }, + function(err, txp) { + should.not.exist(err); + should.exist(txp.note); + txp.note.txid.should.equal(txp.txid); + txp.note.walletId.should.equal(wallet.id); + txp.note.body.should.equal('note body'); + txp.note.editedBy.should.equal(server.copayerId); + done(); + }, + ); + }, + ); + }, + ); }); }); }); it('should share notes between copayers', function(done) { - server.editTxNote({ - txid: '123', - body: 'note body' - }, function(err) { - should.not.exist(err); - server.getTxNote({ + server.editTxNote( + { txid: '123', - }, function(err, note) { + body: 'note body', + }, + function(err) { should.not.exist(err); - should.exist(note); - note.editedBy.should.equal(server.copayerId); - var creator = note.editedBy; - helpers.getAuthServer(wallet.copayers[1].id, function(server) { - server.getTxNote({ + server.getTxNote( + { txid: '123', - }, function(err, note) { + }, + function(err, note) { should.not.exist(err); should.exist(note); - note.body.should.equal('note body'); - note.editedBy.should.equal(creator); - done(); - }); - }); - }); - }); + note.editedBy.should.equal(server.copayerId); + var creator = note.editedBy; + helpers.getAuthServer(wallet.copayers[1].id, function(server) { + server.getTxNote( + { + txid: '123', + }, + function(err, note) { + should.not.exist(err); + should.exist(note); + note.body.should.equal('note body'); + note.editedBy.should.equal(creator); + done(); + }, + ); + }); + }, + ); + }, + ); }); it('should be possible to set an empty note', function(done) { - server.editTxNote({ - txid: '123', - body: 'note body' - }, function(err) { - should.not.exist(err); - server.getTxNote({ + server.editTxNote( + { txid: '123', - }, function(err, note) { + body: 'note body', + }, + function(err) { should.not.exist(err); - should.exist(note); - server.editTxNote({ - txid: '123', - body: null, - }, function(err) { - should.not.exist(err); - server.getTxNote({ + server.getTxNote( + { txid: '123', - }, function(err, note) { + }, + function(err, note) { should.not.exist(err); should.exist(note); - note.should.have.property('body'); - should.equal(note.body, null); - server.getTxNotes({ - minTs: 0 - }, function(err, notes) { - should.not.exist(err); - should.exist(notes); - notes.length.should.equal(1); - should.equal(notes[0].body, null); - done(); - }); - }); - }); - }); - }); + server.editTxNote( + { + txid: '123', + body: null, + }, + function(err) { + should.not.exist(err); + server.getTxNote( + { + txid: '123', + }, + function(err, note) { + should.not.exist(err); + should.exist(note); + note.should.have.property('body'); + should.equal(note.body, null); + server.getTxNotes( + { + minTs: 0, + }, + function(err, notes) { + should.not.exist(err); + should.exist(notes); + notes.length.should.equal(1); + should.equal(notes[0].body, null); + done(); + }, + ); + }, + ); + }, + ); + }, + ); + }, + ); }); it('should include the note in tx history listing', function(done) { helpers.createAddresses(server, wallet, 1, 1, function(mainAddresses, changeAddress) { blockchainExplorer.getBlockchainHeight = sinon.stub().callsArgWith(0, null, 1000); server._normalizeTxHistory = sinon.stub().returnsArg(0); - var txs = [{ - txid: '123', - confirmations: 1, - fees: 100, - time: 20, - inputs: [{ - address: 'external', - amount: 500, - }], - outputs: [{ - address: mainAddresses[0].address, - amount: 200, - }], - }]; + var txs = [ + { + txid: '123', + confirmations: 1, + fees: 100, + time: 20, + inputs: [ + { + address: 'external', + amount: 500, + }, + ], + outputs: [ + { + address: mainAddresses[0].address, + amount: 200, + }, + ], + }, + ]; helpers.stubHistory(txs); helpers.stubFeeLevels({ 24: 10000, }); - server.editTxNote({ - txid: '123', - body: 'just some note' - }, function(err) { - should.not.exist(err); - server.getTxHistory({}, function(err, txs) { + server.editTxNote( + { + txid: '123', + body: 'just some note', + }, + function(err) { should.not.exist(err); - should.exist(txs); - txs.length.should.equal(1); - var tx = txs[0]; - should.exist(tx.note); - tx.note.body.should.equal('just some note'); - tx.note.editedBy.should.equal(server.copayerId); - should.exist(tx.note.editedOn); - done(); - }); - }); + server.getTxHistory({}, function(err, txs) { + should.not.exist(err); + should.exist(txs); + txs.length.should.equal(1); + var tx = txs[0]; + should.exist(tx.note); + tx.note.body.should.equal('just some note'); + tx.note.editedBy.should.equal(server.copayerId); + should.exist(tx.note.editedOn); + done(); + }); + }, + ); }); }); it('should get all notes edited past a given date', function(done) { var clock = sinon.useFakeTimers('Date'); - async.series([ - - function(next) { - server.getTxNotes({}, function(err, notes) { - should.not.exist(err); - notes.should.be.empty; - next(); - }); - }, - function(next) { - server.editTxNote({ - txid: '123', - body: 'note body' - }, next); - }, - function(next) { - server.getTxNotes({ - minTs: 0, - }, function(err, notes) { - should.not.exist(err); - notes.length.should.equal(1); - notes[0].txid.should.equal('123'); - next(); - }); - }, - function(next) { - clock.tick(60 * 1000); - server.editTxNote({ - txid: '456', - body: 'another note' - }, next); - }, - function(next) { - server.getTxNotes({ - minTs: 0, - }, function(err, notes) { - should.not.exist(err); - notes.length.should.equal(2); - _.difference(_.map(notes, 'txid'), ['123', '456']).should.be.empty; - next(); - }); - }, - function(next) { - server.getTxNotes({ - minTs: 50, - }, function(err, notes) { - should.not.exist(err); - notes.length.should.equal(1); - notes[0].txid.should.equal('456'); - next(); - }); - }, - function(next) { - clock.tick(60 * 1000); - server.editTxNote({ - txid: '123', - body: 'an edit' - }, next); - }, - function(next) { - server.getTxNotes({ - minTs: 100, - }, function(err, notes) { - should.not.exist(err); - notes.length.should.equal(1); - notes[0].txid.should.equal('123'); - notes[0].body.should.equal('an edit'); - next(); - }); - }, - function(next) { - server.getTxNotes({}, function(err, notes) { - should.not.exist(err); - notes.length.should.equal(2); - next(); - }); + async.series( + [ + function(next) { + server.getTxNotes({}, function(err, notes) { + should.not.exist(err); + notes.should.be.empty; + next(); + }); + }, + function(next) { + server.editTxNote( + { + txid: '123', + body: 'note body', + }, + next, + ); + }, + function(next) { + server.getTxNotes( + { + minTs: 0, + }, + function(err, notes) { + should.not.exist(err); + notes.length.should.equal(1); + notes[0].txid.should.equal('123'); + next(); + }, + ); + }, + function(next) { + clock.tick(60 * 1000); + server.editTxNote( + { + txid: '456', + body: 'another note', + }, + next, + ); + }, + function(next) { + server.getTxNotes( + { + minTs: 0, + }, + function(err, notes) { + should.not.exist(err); + notes.length.should.equal(2); + _.difference(_.map(notes, 'txid'), ['123', '456']).should.be.empty; + next(); + }, + ); + }, + function(next) { + server.getTxNotes( + { + minTs: 50, + }, + function(err, notes) { + should.not.exist(err); + notes.length.should.equal(1); + notes[0].txid.should.equal('456'); + next(); + }, + ); + }, + function(next) { + clock.tick(60 * 1000); + server.editTxNote( + { + txid: '123', + body: 'an edit', + }, + next, + ); + }, + function(next) { + server.getTxNotes( + { + minTs: 100, + }, + function(err, notes) { + should.not.exist(err); + notes.length.should.equal(1); + notes[0].txid.should.equal('123'); + notes[0].body.should.equal('an edit'); + next(); + }, + ); + }, + function(next) { + server.getTxNotes({}, function(err, notes) { + should.not.exist(err); + notes.length.should.equal(2); + next(); + }); + }, + ], + function(err) { + should.not.exist(err); + clock.restore(); + done(); }, - ], function(err) { - should.not.exist(err); - clock.restore(); - done(); - }); + ); }); }); describe('Single-address wallet', function() { var server, wallet, firstAddress; beforeEach(function(done) { - helpers.createAndJoinWallet(1, 2, { - singleAddress: true, - }, function(s, w) { - server = s; - wallet = w; - server.createAddress({}, function(err, a) { - should.not.exist(err); - should.exist(a.address); - firstAddress = a; - done(); - }); - }); + helpers.createAndJoinWallet( + 1, + 2, + { + singleAddress: true, + }, + function(s, w) { + server = s; + wallet = w; + server.createAddress({}, function(err, a) { + should.not.exist(err); + should.exist(a.address); + firstAddress = a; + done(); + }); + }, + ); }); it('should include singleAddress property', function(done) { server.getWallet({}, function(err, wallet) { @@ -4350,10 +4875,12 @@ describe('Wallet service', function() { helpers.stubUtxos(server, wallet, 2, function() { var toAddress = '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7'; var opts = { - outputs: [{ - amount: 1e8, - toAddress: toAddress, - }], + outputs: [ + { + amount: 1e8, + toAddress: toAddress, + }, + ], feePerKb: 100e2, }; server.createTx(opts, function(err, txp) { @@ -4370,10 +4897,12 @@ describe('Wallet service', function() { helpers.stubUtxos(server, wallet, 2, function() { var toAddress = '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7'; var opts = { - outputs: [{ - amount: 1e8, - toAddress: toAddress, - }], + outputs: [ + { + amount: 1e8, + toAddress: toAddress, + }, + ], feePerKb: 100e2, changeAddress: firstAddress.address, }; @@ -4387,23 +4916,30 @@ describe('Wallet service', function() { it('should correctly handle change in tx history', function(done) { server._normalizeTxHistory = sinon.stub().returnsArg(0); helpers.stubUtxos(server, wallet, 2, function() { - var txs = [{ - txid: '1', - confirmations: 1, - fees: 150, - time: Date.now() / 1000, - inputs: [{ - address: firstAddress.address, - amount: 550, - }], - outputs: [{ - address: firstAddress.address, - amount: 100, - }, { - address: 'external', - amount: 300, - }], - }]; + var txs = [ + { + txid: '1', + confirmations: 1, + fees: 150, + time: Date.now() / 1000, + inputs: [ + { + address: firstAddress.address, + amount: 550, + }, + ], + outputs: [ + { + address: firstAddress.address, + amount: 100, + }, + { + address: 'external', + amount: 300, + }, + ], + }, + ]; helpers.stubHistory(txs); helpers.stubFeeLevels({ 24: 10000, @@ -4437,10 +4973,12 @@ describe('Wallet service', function() { function sendTx(info, cb) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: info.amount, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: info.amount, + }, + ], inputs: info.inputs, fee: info.fee, }; @@ -4453,72 +4991,84 @@ describe('Wallet service', function() { should.not.exist(t.getChangeOutput()); return cb(); }); - }; + } it('should be able to get send max info on 0 utxo wallet', function(done) { - server.getSendMaxInfo({ - feePerKb: 10000, - returnInputs: true, - }, function(err, info) { - should.not.exist(err); - should.exist(info); - info.size.should.equal(0); - info.amount.should.equal(0); - info.fee.should.equal(0); - info.inputs.should.be.empty; - info.utxosBelowFee.should.equal(0); - info.amountBelowFee.should.equal(0); - info.utxosAboveMaxSize.should.equal(0); - info.amountAboveMaxSize.should.equal(0); - done(); - }); - }); - it('should correctly get send max info', function(done) { - helpers.stubUtxos(server, wallet, [0.1, 0.2, 0.3, 0.4], function() { - server.getSendMaxInfo({ + server.getSendMaxInfo( + { feePerKb: 10000, returnInputs: true, - }, function(err, info) { + }, + function(err, info) { should.not.exist(err); should.exist(info); - info.inputs.length.should.equal(4); - info.size.should.equal(1304); - info.fee.should.equal(info.size * 10000 / 1000.); - info.amount.should.equal(1e8 - info.fee); + info.size.should.equal(0); + info.amount.should.equal(0); + info.fee.should.equal(0); + info.inputs.should.be.empty; info.utxosBelowFee.should.equal(0); info.amountBelowFee.should.equal(0); info.utxosAboveMaxSize.should.equal(0); info.amountAboveMaxSize.should.equal(0); - sendTx(info, done); - }); + done(); + }, + ); + }); + it('should correctly get send max info', function(done) { + helpers.stubUtxos(server, wallet, [0.1, 0.2, 0.3, 0.4], function() { + server.getSendMaxInfo( + { + feePerKb: 10000, + returnInputs: true, + }, + function(err, info) { + should.not.exist(err); + should.exist(info); + info.inputs.length.should.equal(4); + info.size.should.equal(1304); + info.fee.should.equal((info.size * 10000) / 1000); + info.amount.should.equal(1e8 - info.fee); + info.utxosBelowFee.should.equal(0); + info.amountBelowFee.should.equal(0); + info.utxosAboveMaxSize.should.equal(0); + info.amountAboveMaxSize.should.equal(0); + sendTx(info, done); + }, + ); }); }); it('should correctly get send max info when resulting amount is below dust', function(done) { helpers.stubUtxos(server, wallet, [300e-6, 300e-6], function() { - server.getSendMaxInfo({ - feePerKb: 500e2, - returnInputs: true, - }, function(err, info) { - should.not.exist(err); - should.exist(info); - info.size.should.equal(700); - info.fee.should.equal(350e2); - info.amount.should.equal(250e2); - - var _min_output_amount = Defaults.MIN_OUTPUT_AMOUNT; - Defaults.MIN_OUTPUT_AMOUNT = 300e2; - server.getSendMaxInfo({ + server.getSendMaxInfo( + { feePerKb: 500e2, returnInputs: true, - }, function(err, info) { + }, + function(err, info) { should.not.exist(err); should.exist(info); - info.size.should.equal(0); - info.amount.should.equal(0); - Defaults.MIN_OUTPUT_AMOUNT = _min_output_amount; - done(); - }); - }); + info.size.should.equal(700); + info.fee.should.equal(350e2); + info.amount.should.equal(250e2); + + var _min_output_amount = Defaults.MIN_OUTPUT_AMOUNT; + Defaults.MIN_OUTPUT_AMOUNT = 300e2; + server.getSendMaxInfo( + { + feePerKb: 500e2, + returnInputs: true, + }, + function(err, info) { + should.not.exist(err); + should.exist(info); + info.size.should.equal(0); + info.amount.should.equal(0); + Defaults.MIN_OUTPUT_AMOUNT = _min_output_amount; + done(); + }, + ); + }, + ); }); }); @@ -4531,16 +5081,19 @@ describe('Wallet service', function() { 24: 90e2, }); helpers.stubUtxos(server, wallet, [0.1, 0.2, 0.3, 0.4], function() { - server.getSendMaxInfo({ - feeLevel: 'economy', - returnInputs: true, - }, function(err, info) { - should.not.exist(err); - should.exist(info); - info.feePerKb.should.equal(180e2); - info.fee.should.equal(info.size * 180e2 / 1000.); - sendTx(info, done); - }); + server.getSendMaxInfo( + { + feeLevel: 'economy', + returnInputs: true, + }, + function(err, info) { + should.not.exist(err); + should.exist(info); + info.feePerKb.should.equal(180e2); + info.fee.should.equal((info.size * 180e2) / 1000); + sendTx(info, done); + }, + ); }); }); it('should assume "normal" fee level if not specified', function(done) { @@ -4555,156 +5108,182 @@ describe('Wallet service', function() { should.not.exist(err); should.exist(info); info.feePerKb.should.equal(200e2); - info.fee.should.equal(info.size * 200e2 / 1000.); + info.fee.should.equal((info.size * 200e2) / 1000); done(); }); }); }); it('should fail on invalid fee level', function(done) { helpers.stubUtxos(server, wallet, [0.1, 0.2, 0.3, 0.4], function() { - server.getSendMaxInfo({ - feeLevel: 'madeUpLevel', - }, function(err, info) { - should.exist(err); - should.not.exist(info); - err.toString().should.contain('Invalid fee level'); - done(); - }); + server.getSendMaxInfo( + { + feeLevel: 'madeUpLevel', + }, + function(err, info) { + should.exist(err); + should.not.exist(info); + err.toString().should.contain('Invalid fee level'); + done(); + }, + ); }); }); }); it('should return inputs in random order', function(done) { // NOTE: this test has a chance of failing of 1 in 1'073'741'824 :P helpers.stubUtxos(server, wallet, _.range(1, 31), function(utxos) { - server.getSendMaxInfo({ - feePerKb: 100e2, - returnInputs: true - }, function(err, info) { - should.not.exist(err); - should.exist(info); - var amounts = _.map(info.inputs, 'micros'); - amounts.length.should.equal(30); - _.every(amounts, function(amount, i) { - if (i == 0) return true; - return amount < amounts[i - 1]; - }).should.be.false; - done(); - }); + server.getSendMaxInfo( + { + feePerKb: 100e2, + returnInputs: true, + }, + function(err, info) { + should.not.exist(err); + should.exist(info); + var amounts = _.map(info.inputs, 'micros'); + amounts.length.should.equal(30); + _.every(amounts, function(amount, i) { + if (i == 0) return true; + return amount < amounts[i - 1]; + }).should.be.false; + done(); + }, + ); }); }); it('should exclude unconfirmed inputs', function(done) { helpers.stubUtxos(server, wallet, ['u0.1', 0.2, 0.3, 0.4], function() { - server.getSendMaxInfo({ - feePerKb: 10000, - excludeUnconfirmedUtxos: true, - returnInputs: true, - }, function(err, info) { - should.not.exist(err); - should.exist(info); - info.inputs.length.should.equal(3); - info.size.should.equal(1002); - info.fee.should.equal(info.size * 10000 / 1000.); - info.amount.should.equal(0.9e8 - info.fee); - sendTx(info, done); - }); + server.getSendMaxInfo( + { + feePerKb: 10000, + excludeUnconfirmedUtxos: true, + returnInputs: true, + }, + function(err, info) { + should.not.exist(err); + should.exist(info); + info.inputs.length.should.equal(3); + info.size.should.equal(1002); + info.fee.should.equal((info.size * 10000) / 1000); + info.amount.should.equal(0.9e8 - info.fee); + sendTx(info, done); + }, + ); }); }); it('should exclude locked inputs', function(done) { helpers.stubUtxos(server, wallet, ['u0.1', 0.1, 0.1, 0.1], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.09e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.09e8, + }, + ], feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { should.exist(tx); - server.getSendMaxInfo({ - feePerKb: 10000, - excludeUnconfirmedUtxos: true, - returnInputs: true, - }, function(err, info) { - should.not.exist(err); - should.exist(info); - info.inputs.length.should.equal(2); - info.size.should.equal(700); - info.fee.should.equal(info.size * 10000 / 1000.); - info.amount.should.equal(0.2e8 - info.fee); - sendTx(info, done); - }); + server.getSendMaxInfo( + { + feePerKb: 10000, + excludeUnconfirmedUtxos: true, + returnInputs: true, + }, + function(err, info) { + should.not.exist(err); + should.exist(info); + info.inputs.length.should.equal(2); + info.size.should.equal(700); + info.fee.should.equal((info.size * 10000) / 1000); + info.amount.should.equal(0.2e8 - info.fee); + sendTx(info, done); + }, + ); }); }); }); it('should ignore utxos not contributing to total amount (below their cost in fee)', function(done) { helpers.stubUtxos(server, wallet, ['u0.1', 0.2, 0.3, 0.4, '1bit', '100bit', '200bit'], function() { - server.getSendMaxInfo({ - feePerKb: 0.001e8, - returnInputs: true, - }, function(err, info) { - should.not.exist(err); - should.exist(info); - info.inputs.length.should.equal(4); - info.size.should.equal(1304); - info.fee.should.equal(info.size * 0.001e8 / 1000.); - info.amount.should.equal(1e8 - info.fee); - info.utxosBelowFee.should.equal(3); - info.amountBelowFee.should.equal(301e2); - server.getSendMaxInfo({ - feePerKb: 0.0001e8, + server.getSendMaxInfo( + { + feePerKb: 0.001e8, returnInputs: true, - }, function(err, info) { + }, + function(err, info) { should.not.exist(err); should.exist(info); - info.inputs.length.should.equal(6); - info.size.should.equal(1907); - info.fee.should.equal(info.size * 0.0001e8 / 1000.); - info.amount.should.equal(1.0003e8 - info.fee); - info.utxosBelowFee.should.equal(1); - info.amountBelowFee.should.equal(1e2); - sendTx(info, done); - }); - }); + info.inputs.length.should.equal(4); + info.size.should.equal(1304); + info.fee.should.equal((info.size * 0.001e8) / 1000); + info.amount.should.equal(1e8 - info.fee); + info.utxosBelowFee.should.equal(3); + info.amountBelowFee.should.equal(301e2); + server.getSendMaxInfo( + { + feePerKb: 0.0001e8, + returnInputs: true, + }, + function(err, info) { + should.not.exist(err); + should.exist(info); + info.inputs.length.should.equal(6); + info.size.should.equal(1907); + info.fee.should.equal((info.size * 0.0001e8) / 1000); + info.amount.should.equal(1.0003e8 - info.fee); + info.utxosBelowFee.should.equal(1); + info.amountBelowFee.should.equal(1e2); + sendTx(info, done); + }, + ); + }, + ); }); }); it('should work when all inputs are below their cost in fee', function(done) { helpers.stubUtxos(server, wallet, ['u 10bit', '10bit', '20bit'], function() { - server.getSendMaxInfo({ - feePerKb: 500e2, - returnInputs: true, - }, function(err, info) { - should.not.exist(err); - should.exist(info); - info.inputs.should.be.empty; - info.size.should.equal(0); - info.fee.should.equal(0); - info.amount.should.equal(0); - info.utxosBelowFee.should.equal(3); - info.amountBelowFee.should.equal(40e2); - done(); - }); + server.getSendMaxInfo( + { + feePerKb: 500e2, + returnInputs: true, + }, + function(err, info) { + should.not.exist(err); + should.exist(info); + info.inputs.should.be.empty; + info.size.should.equal(0); + info.fee.should.equal(0); + info.amount.should.equal(0); + info.utxosBelowFee.should.equal(3); + info.amountBelowFee.should.equal(40e2); + done(); + }, + ); }); }); it('should not go beyond max tx size', function(done) { var _oldDefault = Defaults.MAX_TX_SIZE_IN_KB; Defaults.MAX_TX_SIZE_IN_KB = 2; helpers.stubUtxos(server, wallet, _.range(1, 10, 0), function() { - server.getSendMaxInfo({ - feePerKb: 10000, - returnInputs: true, - }, function(err, info) { - should.not.exist(err); - should.exist(info); - info.size.should.be.below(2000); - info.inputs.length.should.be.below(9); - info.utxosAboveMaxSize.should.equal(3); - info.amountAboveMaxSize.should.equal(3e8); - Defaults.MAX_TX_SIZE_IN_KB = _oldDefault; - sendTx(info, done); - }); + server.getSendMaxInfo( + { + feePerKb: 10000, + returnInputs: true, + }, + function(err, info) { + should.not.exist(err); + should.exist(info); + info.size.should.be.below(2000); + info.inputs.length.should.be.below(9); + info.utxosAboveMaxSize.should.equal(3); + info.amountAboveMaxSize.should.equal(3e8); + Defaults.MAX_TX_SIZE_IN_KB = _oldDefault; + sendTx(info, done); + }, + ); }); }); - }) + }); describe('#rejectTx', function() { var server, wallet, txid; @@ -4715,10 +5294,12 @@ describe('Wallet service', function() { wallet = w; helpers.stubUtxos(server, wallet, _.range(1, 9), function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 10e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 10e8, + }, + ], feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { @@ -4735,32 +5316,37 @@ describe('Wallet service', function() { var tx = txs[0]; tx.id.should.equal(txid); - server.rejectTx({ - txProposalId: txid, - reason: 'some reason', - }, function(err) { - should.not.exist(err); - server.getPendingTxs({}, function(err, txs) { + server.rejectTx( + { + txProposalId: txid, + reason: 'some reason', + }, + function(err) { should.not.exist(err); - txs.should.be.empty; - server.getTx({ - txProposalId: txid - }, function(err, tx) { - var actors = tx.getActors(); - actors.length.should.equal(1); - actors[0].should.equal(wallet.copayers[0].id); - var action = tx.getActionBy(wallet.copayers[0].id); - action.type.should.equal('reject'); - action.comment.should.equal('some reason'); - done(); + server.getPendingTxs({}, function(err, txs) { + should.not.exist(err); + txs.should.be.empty; + server.getTx( + { + txProposalId: txid, + }, + function(err, tx) { + var actors = tx.getActors(); + actors.length.should.equal(1); + actors[0].should.equal(wallet.copayers[0].id); + var action = tx.getActionBy(wallet.copayers[0].id); + action.type.should.equal('reject'); + action.comment.should.equal('some reason'); + done(); + }, + ); }); - }); - }); + }, + ); }); }); it('should fail to reject non-pending TX', function(done) { async.waterfall([ - function(next) { server.getPendingTxs({}, function(err, txs) { var tx = txs[0]; @@ -4769,13 +5355,16 @@ describe('Wallet service', function() { }); }, function(next) { - server.rejectTx({ - txProposalId: txid, - reason: 'some reason', - }, function(err) { - should.not.exist(err); - next(); - }); + server.rejectTx( + { + txProposalId: txid, + reason: 'some reason', + }, + function(err) { + should.not.exist(err); + next(); + }, + ); }, function(next) { server.getPendingTxs({}, function(err, txs) { @@ -4786,14 +5375,17 @@ describe('Wallet service', function() { }, function(next) { helpers.getAuthServer(wallet.copayers[1].id, function(server) { - server.rejectTx({ - txProposalId: txid, - reason: 'some other reason', - }, function(err) { - should.exist(err); - err.code.should.equal('TX_NOT_PENDING'); - done(); - }); + server.rejectTx( + { + txProposalId: txid, + reason: 'some other reason', + }, + function(err) { + should.exist(err); + err.code.should.equal('TX_NOT_PENDING'); + done(); + }, + ); }); }, ]); @@ -4810,10 +5402,12 @@ describe('Wallet service', function() { wallet = w; helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 2.5e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 2.5e8, + }, + ], feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { @@ -4833,24 +5427,27 @@ describe('Wallet service', function() { tx.id.should.equal(txid); var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_44H_0H_0H); should.not.exist(tx.raw); - server.signTx({ - txProposalId: txid, - signatures: signatures, - }, function(err, txp) { - should.not.exist(err); - txp.status.should.equal('accepted'); - // The raw Tx should contain the Signatures. - txp.raw.should.contain(signatures[0]); - - // Get pending should also contains the raw TX - server.getPendingTxs({}, function(err, txs) { - var tx = txs[0]; + server.signTx( + { + txProposalId: txid, + signatures: signatures, + }, + function(err, txp) { should.not.exist(err); - tx.status.should.equal('accepted'); - tx.raw.should.contain(signatures[0]); - done(); - }); - }); + txp.status.should.equal('accepted'); + // The raw Tx should contain the Signatures. + txp.raw.should.contain(signatures[0]); + + // Get pending should also contains the raw TX + server.getPendingTxs({}, function(err, txs) { + var tx = txs[0]; + should.not.exist(err); + tx.status.should.equal('accepted'); + tx.raw.should.contain(signatures[0]); + done(); + }); + }, + ); }); }); }); @@ -4864,10 +5461,12 @@ describe('Wallet service', function() { wallet = w; helpers.stubUtxos(server, wallet, _.range(1, 9), function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 20e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 20e8, + }, + ], feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { @@ -4885,25 +5484,28 @@ describe('Wallet service', function() { tx.id.should.equal(txid); var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: txid, - signatures: signatures, - }, function(err, txp) { - should.not.exist(err); - should.not.exist(tx.raw); - server.getPendingTxs({}, function(err, txs) { + server.signTx( + { + txProposalId: txid, + signatures: signatures, + }, + function(err, txp) { should.not.exist(err); - var tx = txs[0]; - tx.id.should.equal(txid); + should.not.exist(tx.raw); + server.getPendingTxs({}, function(err, txs) { + should.not.exist(err); + var tx = txs[0]; + tx.id.should.equal(txid); - var actors = tx.getActors(); - actors.length.should.equal(1); - actors[0].should.equal(wallet.copayers[0].id); - tx.getActionBy(wallet.copayers[0].id).type.should.equal('accept'); + var actors = tx.getActors(); + actors.length.should.equal(1); + actors[0].should.equal(wallet.copayers[0].id); + tx.getActionBy(wallet.copayers[0].id).type.should.equal('accept'); - done(); - }); - }); + done(); + }); + }, + ); }); }); @@ -4912,13 +5514,16 @@ describe('Wallet service', function() { var tx = txs[0]; tx.id.should.equal(txid); var signatures = helpers.clientSign(tx, TestData.copayers[1].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: txid, - signatures: signatures, - }, function(err) { - err.code.should.equal('BAD_SIGNATURES'); - done(); - }); + server.signTx( + { + txProposalId: txid, + signatures: signatures, + }, + function(err) { + err.code.should.equal('BAD_SIGNATURES'); + done(); + }, + ); }); }); @@ -4930,13 +5535,16 @@ describe('Wallet service', function() { var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_44H_0H_0H); signatures[0] = 1; - server.signTx({ - txProposalId: txid, - signatures: signatures, - }, function(err) { - err.message.should.contain('signatures'); - done(); - }); + server.signTx( + { + txProposalId: txid, + signatures: signatures, + }, + function(err) { + err.message.should.contain('signatures'); + done(); + }, + ); }); }); @@ -4946,14 +5554,17 @@ describe('Wallet service', function() { tx.id.should.equal(txid); var signatures = ['11', '22', '33', '44', '55']; - server.signTx({ - txProposalId: txid, - signatures: signatures, - }, function(err) { - should.exist(err); - err.message.should.contain('Bad signatures'); - done(); - }); + server.signTx( + { + txProposalId: txid, + signatures: signatures, + }, + function(err) { + should.exist(err); + err.message.should.contain('Bad signatures'); + done(); + }, + ); }); }); @@ -4962,15 +5573,21 @@ describe('Wallet service', function() { var tx = txs[0]; tx.id.should.equal(txid); - var signatures = _.take(helpers.clientSign(tx, TestData.copayers[0].xPrivKey_44H_0H_0H), tx.inputs.length - 1); - server.signTx({ - txProposalId: txid, - signatures: signatures, - }, function(err) { - should.exist(err); - err.message.should.contain('Bad signatures'); - done(); - }); + var signatures = _.take( + helpers.clientSign(tx, TestData.copayers[0].xPrivKey_44H_0H_0H), + tx.inputs.length - 1, + ); + server.signTx( + { + txProposalId: txid, + signatures: signatures, + }, + function(err) { + should.exist(err); + err.message.should.contain('Bad signatures'); + done(); + }, + ); }); }); @@ -4980,17 +5597,23 @@ describe('Wallet service', function() { tx.id.should.equal(txid); var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: txid, - signatures: signatures, - }, function(err) { - server.rejectTx({ + server.signTx( + { txProposalId: txid, - }, function(err) { - err.code.should.contain('COPAYER_VOTED'); - done(); - }); - }); + signatures: signatures, + }, + function(err) { + server.rejectTx( + { + txProposalId: txid, + }, + function(err) { + err.code.should.contain('COPAYER_VOTED'); + done(); + }, + ); + }, + ); }); }); @@ -4999,42 +5622,53 @@ describe('Wallet service', function() { var tx = txs[0]; tx.id.should.equal(txid); - server.rejectTx({ - txProposalId: txid, - }, function(err) { - var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ + server.rejectTx( + { txProposalId: txid, - signatures: signatures, - }, function(err) { - err.code.should.contain('COPAYER_VOTED'); - done(); - }); - }); + }, + function(err) { + var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_44H_0H_0H); + server.signTx( + { + txProposalId: txid, + signatures: signatures, + }, + function(err) { + err.code.should.contain('COPAYER_VOTED'); + done(); + }, + ); + }, + ); }); }); it('should fail to sign a non-pending TX', function(done) { async.waterfall([ - - function(next) { - server.rejectTx({ - txProposalId: txid, - reason: 'some reason', - }, function(err) { - should.not.exist(err); - next(); - }); - }, function(next) { - helpers.getAuthServer(wallet.copayers[1].id, function(server) { - server.rejectTx({ + server.rejectTx( + { txProposalId: txid, reason: 'some reason', - }, function(err) { + }, + function(err) { should.not.exist(err); next(); - }); + }, + ); + }, + function(next) { + helpers.getAuthServer(wallet.copayers[1].id, function(server) { + server.rejectTx( + { + txProposalId: txid, + reason: 'some reason', + }, + function(err) { + should.not.exist(err); + next(); + }, + ); }); }, function(next) { @@ -5046,20 +5680,26 @@ describe('Wallet service', function() { }, function(next) { helpers.getAuthServer(wallet.copayers[2].id, function(server) { - server.getTx({ - txProposalId: txid - }, function(err, tx) { - should.not.exist(err); - var signatures = helpers.clientSign(tx, TestData.copayers[2].xPrivKey_44H_0H_0H); - server.signTx({ + server.getTx( + { txProposalId: txid, - signatures: signatures, - }, function(err) { - should.exist(err); - err.code.should.equal('TX_NOT_PENDING'); - done(); - }); - }); + }, + function(err, tx) { + should.not.exist(err); + var signatures = helpers.clientSign(tx, TestData.copayers[2].xPrivKey_44H_0H_0H); + server.signTx( + { + txProposalId: txid, + signatures: signatures, + }, + function(err) { + should.exist(err); + err.code.should.equal('TX_NOT_PENDING'); + done(); + }, + ); + }, + ); }); }, ]); @@ -5075,28 +5715,33 @@ describe('Wallet service', function() { wallet = w; helpers.stubUtxos(server, wallet, [10, 10], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 9e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 9e8, + }, + ], message: 'some message', feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(txp) { should.exist(txp); var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: txp.id, - signatures: signatures, - }, function(err, txp) { - should.not.exist(err); - should.exist(txp); - txp.isAccepted().should.be.true; - txp.isBroadcasted().should.be.false; - txid = txp.txid; - txpid = txp.id; - done(); - }); + server.signTx( + { + txProposalId: txp.id, + signatures: signatures, + }, + function(err, txp) { + should.not.exist(err); + should.exist(txp); + txp.isAccepted().should.be.true; + txp.isBroadcasted().should.be.false; + txid = txp.txid; + txpid = txp.id; + done(); + }, + ); }); }); }); @@ -5105,48 +5750,63 @@ describe('Wallet service', function() { it('should broadcast a tx', function(done) { var clock = sinon.useFakeTimers(1234000, 'Date'); helpers.stubBroadcast(); - server.broadcastTx({ - txProposalId: txpid - }, function(err) { - should.not.exist(err); - server.getTx({ - txProposalId: txpid - }, function(err, txp) { + server.broadcastTx( + { + txProposalId: txpid, + }, + function(err) { should.not.exist(err); - should.not.exist(txp.raw); - txp.txid.should.equal(txid); - txp.isBroadcasted().should.be.true; - txp.broadcastedOn.should.equal(1234); - clock.restore(); - done(); - }); - }); + server.getTx( + { + txProposalId: txpid, + }, + function(err, txp) { + should.not.exist(err); + should.not.exist(txp.raw); + txp.txid.should.equal(txid); + txp.isBroadcasted().should.be.true; + txp.broadcastedOn.should.equal(1234); + clock.restore(); + done(); + }, + ); + }, + ); }); it('should broadcast a raw tx', function(done) { helpers.stubBroadcast(); - server.broadcastRawTx({ - network: 'testnet', - rawTx: 'raw tx', - }, function(err, txid) { - should.not.exist(err); - should.exist(txid); - done(); - }); + server.broadcastRawTx( + { + network: 'testnet', + rawTx: 'raw tx', + }, + function(err, txid) { + should.not.exist(err); + should.exist(txid); + done(); + }, + ); }); it('should fail to brodcast a tx already marked as broadcasted', function(done) { helpers.stubBroadcast(); - server.broadcastTx({ - txProposalId: txpid - }, function(err) { - should.not.exist(err); - server.broadcastTx({ - txProposalId: txpid - }, function(err) { - should.exist(err); - err.code.should.equal('TX_ALREADY_BROADCASTED'); - done(); - }); - }); + server.broadcastTx( + { + txProposalId: txpid, + }, + function(err) { + should.not.exist(err); + server.broadcastTx( + { + txProposalId: txpid, + }, + function(err) { + should.exist(err); + err.code.should.equal('TX_ALREADY_BROADCASTED'); + done(); + }, + ); + }, + ); }); it('should auto process already broadcasted txs', function(done) { helpers.stubBroadcast(); @@ -5154,7 +5814,7 @@ describe('Wallet service', function() { should.not.exist(err); txs.length.should.equal(1); blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, null, { - txid: 999 + txid: 999, }); server.getPendingTxs({}, function(err, txs) { should.not.exist(err); @@ -5166,10 +5826,12 @@ describe('Wallet service', function() { it('should process only broadcasted txs', function(done) { helpers.stubBroadcast(); var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 9e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 9e8, + }, + ], feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(txp) { @@ -5177,7 +5839,7 @@ describe('Wallet service', function() { should.not.exist(err); txs.length.should.equal(2); blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, null, { - txid: 999 + txid: 999, }); server.getPendingTxs({}, function(err, txs) { should.not.exist(err); @@ -5192,82 +5854,105 @@ describe('Wallet service', function() { it('should fail to brodcast a not yet accepted tx', function(done) { helpers.stubBroadcast(); var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 9e8, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 9e8, + }, + ], feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(txp) { should.exist(txp); - server.broadcastTx({ - txProposalId: txp.id - }, function(err) { - should.exist(err); - err.code.should.equal('TX_NOT_ACCEPTED'); - done(); - }); + server.broadcastTx( + { + txProposalId: txp.id, + }, + function(err) { + should.exist(err); + err.code.should.equal('TX_NOT_ACCEPTED'); + done(); + }, + ); }); }); it('should keep tx as accepted if unable to broadcast it', function(done) { blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'broadcast error'); blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, null, null); - server.broadcastTx({ - txProposalId: txpid - }, function(err) { - should.exist(err); - err.toString().should.equal('broadcast error'); - server.getTx({ - txProposalId: txpid - }, function(err, txp) { - should.not.exist(err); - should.exist(txp.txid); - txp.isBroadcasted().should.be.false; - should.not.exist(txp.broadcastedOn); - txp.isAccepted().should.be.true; - done(); - }); - }); + server.broadcastTx( + { + txProposalId: txpid, + }, + function(err) { + should.exist(err); + err.toString().should.equal('broadcast error'); + server.getTx( + { + txProposalId: txpid, + }, + function(err, txp) { + should.not.exist(err); + should.exist(txp.txid); + txp.isBroadcasted().should.be.false; + should.not.exist(txp.broadcastedOn); + txp.isAccepted().should.be.true; + done(); + }, + ); + }, + ); }); it('should mark tx as broadcasted if accepted but already in blockchain', function(done) { blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'broadcast error'); blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, null, { - txid: '999' + txid: '999', }); - server.broadcastTx({ - txProposalId: txpid - }, function(err) { - should.not.exist(err); - server.getTx({ - txProposalId: txpid - }, function(err, txp) { + server.broadcastTx( + { + txProposalId: txpid, + }, + function(err) { should.not.exist(err); - should.exist(txp.txid); - txp.isBroadcasted().should.be.true; - should.exist(txp.broadcastedOn); - done(); - }); - }); + server.getTx( + { + txProposalId: txpid, + }, + function(err, txp) { + should.not.exist(err); + should.exist(txp.txid); + txp.isBroadcasted().should.be.true; + should.exist(txp.broadcastedOn); + done(); + }, + ); + }, + ); }); it('should keep tx as accepted if broadcast fails and cannot check tx in blockchain', function(done) { blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'broadcast error'); blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, 'bc check error'); - server.broadcastTx({ - txProposalId: txpid - }, function(err) { - should.exist(err); - err.toString().should.equal('bc check error'); - server.getTx({ - txProposalId: txpid - }, function(err, txp) { - should.not.exist(err); - should.exist(txp.txid); - txp.isBroadcasted().should.be.false; - should.not.exist(txp.broadcastedOn); - txp.isAccepted().should.be.true; - done(); - }); - }); + server.broadcastTx( + { + txProposalId: txpid, + }, + function(err) { + should.exist(err); + err.toString().should.equal('bc check error'); + server.getTx( + { + txProposalId: txpid, + }, + function(err, txp) { + should.not.exist(err); + should.exist(txp.txid); + txp.isBroadcasted().should.be.false; + should.not.exist(txp.broadcastedOn); + txp.isAccepted().should.be.true; + done(); + }, + ); + }, + ); }); }); @@ -5286,10 +5971,12 @@ describe('Wallet service', function() { it('other copayers should see pending proposal created by one copayer', function(done) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 10e8 - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 10e8, + }, + ], feePerKb: 100e2, message: 'some message', }; @@ -5309,13 +5996,14 @@ describe('Wallet service', function() { it('tx proposals should not be finally accepted until quorum is reached', function(done) { var txpId; async.waterfall([ - function(next) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 10e8 - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 10e8, + }, + ], feePerKb: 100e2, message: 'some message', }; @@ -5336,13 +6024,16 @@ describe('Wallet service', function() { }, function(txp, next) { var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: txpId, - signatures: signatures, - }, function(err) { - should.not.exist(err); - next(); - }); + server.signTx( + { + txProposalId: txpId, + signatures: signatures, + }, + function(err) { + should.not.exist(err); + next(); + }, + ); }, function(next) { server.getPendingTxs({}, function(err, txps) { @@ -5367,13 +6058,16 @@ describe('Wallet service', function() { function(txp, next) { helpers.getAuthServer(wallet.copayers[1].id, function(server, wallet) { var signatures = helpers.clientSign(txp, TestData.copayers[1].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: txpId, - signatures: signatures, - }, function(err) { - should.not.exist(err); - next(); - }); + server.signTx( + { + txProposalId: txpId, + signatures: signatures, + }, + function(err) { + should.not.exist(err); + next(); + }, + ); }); }, function(next) { @@ -5402,13 +6096,14 @@ describe('Wallet service', function() { it('tx proposals should accept as many rejections as possible without finally rejecting', function(done) { var txpId; async.waterfall([ - function(next) { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 10e8 - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 10e8, + }, + ], feePerKb: 100e2, message: 'some message', }; @@ -5428,13 +6123,16 @@ describe('Wallet service', function() { }); }, function(next) { - server.rejectTx({ - txProposalId: txpId, - reason: 'just because' - }, function(err) { - should.not.exist(err); - next(); - }); + server.rejectTx( + { + txProposalId: txpId, + reason: 'just because', + }, + function(err) { + should.not.exist(err); + next(); + }, + ); }, function(next) { server.getPendingTxs({}, function(err, txps) { @@ -5453,13 +6151,16 @@ describe('Wallet service', function() { }, function(next) { helpers.getAuthServer(wallet.copayers[1].id, function(server, wallet) { - server.rejectTx({ - txProposalId: txpId, - reason: 'some other reason' - }, function(err) { - should.not.exist(err); - next(); - }); + server.rejectTx( + { + txProposalId: txpId, + reason: 'some other reason', + }, + function(err) { + should.not.exist(err); + next(); + }, + ); }); }, function(next) { @@ -5470,16 +6171,19 @@ describe('Wallet service', function() { }); }, function(next) { - server.getTx({ - txProposalId: txpId - }, function(err, txp) { - should.not.exist(err); - txp.isPending().should.be.false; - txp.isRejected().should.be.true; - txp.isAccepted().should.be.false; - txp.actions.length.should.equal(2); - done(); - }); + server.getTx( + { + txProposalId: txpId, + }, + function(err, txp) { + should.not.exist(err); + txp.isPending().should.be.false; + txp.isRejected().should.be.true; + txp.isAccepted().should.be.false; + txp.actions.length.should.equal(2); + done(); + }, + ); }, ]); }); @@ -5493,10 +6197,12 @@ describe('Wallet service', function() { wallet = w; helpers.stubUtxos(server, wallet, 1, function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.5e8 - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.5e8, + }, + ], feePerKb: 100e2, message: 'some message', }; @@ -5510,37 +6216,45 @@ describe('Wallet service', function() { }); it('should get own transaction proposal', function(done) { - server.getTx({ - txProposalId: txpid - }, function(err, txp) { - should.not.exist(err); - should.exist(txp); - txp.id.should.equal(txpid); - done(); - }); + server.getTx( + { + txProposalId: txpid, + }, + function(err, txp) { + should.not.exist(err); + should.exist(txp); + txp.id.should.equal(txpid); + done(); + }, + ); }); it('should get someone elses transaction proposal', function(done) { helpers.getAuthServer(wallet.copayers[1].id, function(server2, wallet) { - server2.getTx({ - txProposalId: txpid - }, function(err, res) { - should.not.exist(err); - res.id.should.equal(txpid); - done(); - }); + server2.getTx( + { + txProposalId: txpid, + }, + function(err, res) { + should.not.exist(err); + res.id.should.equal(txpid); + done(); + }, + ); }); - }); it('should fail to get non-existent transaction proposal', function(done) { - server.getTx({ - txProposalId: 'dummy' - }, function(err, txp) { - should.exist(err); - should.not.exist(txp); - err.code.should.equal('TX_NOT_FOUND') - err.message.should.equal('Transaction proposal not found'); - done(); - }); + server.getTx( + { + txProposalId: 'dummy', + }, + function(err, txp) { + should.exist(err); + should.not.exist(txp); + err.code.should.equal('TX_NOT_FOUND'); + err.message.should.equal('Transaction proposal not found'); + done(); + }, + ); }); it.skip('should get accepted/rejected transaction proposal', function(done) {}); it.skip('should get broadcasted transaction proposal', function(done) {}); @@ -5557,22 +6271,28 @@ describe('Wallet service', function() { wallet = w; helpers.stubUtxos(server, wallet, _.range(1, 11), function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.1e8 - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.1e8, + }, + ], feePerKb: 100e2, message: 'some message', }; - async.eachSeries(_.range(10), function(i, next) { - clock.tick(10 * 1000); - helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(txp) { - next(); - }); - }, function(err) { - clock.restore(); - return done(err); - }); + async.eachSeries( + _.range(10), + function(i, next) { + clock.tick(10 * 1000); + helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(txp) { + next(); + }); + }, + function(err) { + clock.restore(); + return done(err); + }, + ); }); }); }); @@ -5580,36 +6300,45 @@ describe('Wallet service', function() { clock.restore(); }); it('should pull 4 txs, down to to time 60', function(done) { - server.getTxs({ - minTs: 60, - limit: 8 - }, function(err, txps) { - should.not.exist(err); - var times = _.map(txps, 'createdOn'); - times.should.deep.equal([100, 90, 80, 70, 60]); - done(); - }); + server.getTxs( + { + minTs: 60, + limit: 8, + }, + function(err, txps) { + should.not.exist(err); + var times = _.map(txps, 'createdOn'); + times.should.deep.equal([100, 90, 80, 70, 60]); + done(); + }, + ); }); it('should pull the first 5 txs', function(done) { - server.getTxs({ - maxTs: 50, - limit: 5 - }, function(err, txps) { - should.not.exist(err); - var times = _.map(txps, 'createdOn'); - times.should.deep.equal([50, 40, 30, 20, 10]); - done(); - }); + server.getTxs( + { + maxTs: 50, + limit: 5, + }, + function(err, txps) { + should.not.exist(err); + var times = _.map(txps, 'createdOn'); + times.should.deep.equal([50, 40, 30, 20, 10]); + done(); + }, + ); }); it('should pull the last 4 txs', function(done) { - server.getTxs({ - limit: 4 - }, function(err, txps) { - should.not.exist(err); - var times = _.map(txps, 'createdOn'); - times.should.deep.equal([100, 90, 80, 70]); - done(); - }); + server.getTxs( + { + limit: 4, + }, + function(err, txps) { + should.not.exist(err); + var times = _.map(txps, 'createdOn'); + times.should.deep.equal([100, 90, 80, 70]); + done(); + }, + ); }); it('should pull all txs', function(done) { server.getTxs({}, function(err, txps) { @@ -5619,18 +6348,20 @@ describe('Wallet service', function() { done(); }); }); - it('should txs from times 50 to 70', - function(done) { - server.getTxs({ + it('should txs from times 50 to 70', function(done) { + server.getTxs( + { minTs: 50, maxTs: 70, - }, function(err, txps) { + }, + function(err, txps) { should.not.exist(err); var times = _.map(txps, 'createdOn'); times.should.deep.equal([70, 60, 50]); done(); - }); - }); + }, + ); + }); }); describe('#getNotifications', function() { @@ -5644,22 +6375,28 @@ describe('Wallet service', function() { wallet = w; helpers.stubUtxos(server, wallet, _.range(4), function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.1e8 - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.1e8, + }, + ], feePerKb: 100e2, message: 'some message', }; - async.eachSeries(_.range(3), function(i, next) { - clock.tick(25 * 1000); - helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(txp) { - next(); - }); - }, function(err) { - clock.tick(20 * 1000); - return done(err); - }); + async.eachSeries( + _.range(3), + function(i, next) { + clock.tick(25 * 1000); + helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(txp) { + next(); + }); + }, + function(err) { + clock.tick(20 * 1000); + return done(err); + }, + ); }); }); }); @@ -5684,81 +6421,106 @@ describe('Wallet service', function() { it('should pull new block notifications along with wallet notifications in the last 60 seconds', function(done) { // Simulate new block notification server.walletId = 'livenet'; - server._notify('NewBlock', { - hash: 'dummy hash', - }, { - isGlobal: true - }, function(err) { - should.not.exist(err); - server.walletId = 'testnet'; - server._notify('NewBlock', { + server._notify( + 'NewBlock', + { hash: 'dummy hash', - }, { - isGlobal: true - }, function(err) { + }, + { + isGlobal: true, + }, + function(err) { should.not.exist(err); - server.walletId = wallet.id; - server.getNotifications({ - minTs: +Date.now() - (60 * 1000), - }, function(err, notifications) { - should.not.exist(err); - var types = _.map(notifications, 'type'); - types.should.deep.equal(['NewTxProposal', 'NewTxProposal', 'NewBlock']); - var walletIds = _.uniq(_.map(notifications, 'walletId')); - walletIds.length.should.equal(1); - walletIds[0].should.equal(wallet.id); - done(); - }); - }); - }); + server.walletId = 'testnet'; + server._notify( + 'NewBlock', + { + hash: 'dummy hash', + }, + { + isGlobal: true, + }, + function(err) { + should.not.exist(err); + server.walletId = wallet.id; + server.getNotifications( + { + minTs: +Date.now() - 60 * 1000, + }, + function(err, notifications) { + should.not.exist(err); + var types = _.map(notifications, 'type'); + types.should.deep.equal(['NewTxProposal', 'NewTxProposal', 'NewBlock']); + var walletIds = _.uniq(_.map(notifications, 'walletId')); + walletIds.length.should.equal(1); + walletIds[0].should.equal(wallet.id); + done(); + }, + ); + }, + ); + }, + ); }); it('should pull notifications in the last 60 seconds', function(done) { - server.getNotifications({ - minTs: +Date.now() - (60 * 1000), - }, function(err, notifications) { - should.not.exist(err); - var types = _.map(notifications, 'type'); - types.should.deep.equal(['NewTxProposal', 'NewTxProposal']); - done(); - }); + server.getNotifications( + { + minTs: +Date.now() - 60 * 1000, + }, + function(err, notifications) { + should.not.exist(err); + var types = _.map(notifications, 'type'); + types.should.deep.equal(['NewTxProposal', 'NewTxProposal']); + done(); + }, + ); }); it('should pull notifications after a given notification id', function(done) { server.getNotifications({}, function(err, notifications) { should.not.exist(err); var from = _.head(_.takeRight(notifications, 2)).id; // second to last - server.getNotifications({ - notificationId: from, - minTs: +Date.now() - (60 * 1000), - }, function(err, res) { - should.not.exist(err); - res.length.should.equal(1); - res[0].id.should.equal(_.head(_.takeRight(notifications)).id); - done(); - }); + server.getNotifications( + { + notificationId: from, + minTs: +Date.now() - 60 * 1000, + }, + function(err, res) { + should.not.exist(err); + res.length.should.equal(1); + res[0].id.should.equal(_.head(_.takeRight(notifications)).id); + done(); + }, + ); }); }); it('should return empty if no notifications found after a given id', function(done) { server.getNotifications({}, function(err, notifications) { should.not.exist(err); var from = _.head(_.takeRight(notifications)).id; // last one - server.getNotifications({ - notificationId: from, - }, function(err, res) { - should.not.exist(err); - res.length.should.equal(0); - done(); - }); + server.getNotifications( + { + notificationId: from, + }, + function(err, res) { + should.not.exist(err); + res.length.should.equal(0); + done(); + }, + ); }); }); it('should return empty if no notifications exist in the given timespan', function(done) { clock.tick(100 * 1000); - server.getNotifications({ - minTs: +Date.now() - (60 * 1000), - }, function(err, res) { - should.not.exist(err); - res.length.should.equal(0); - done(); - }); + server.getNotifications( + { + minTs: +Date.now() - 60 * 1000, + }, + function(err, res) { + should.not.exist(err); + res.length.should.equal(0); + done(); + }, + ); }); it('should contain walletId & creatorId on NewCopayer', function(done) { server.getNotifications({}, function(err, notifications) { @@ -5772,99 +6534,133 @@ describe('Wallet service', function() { }); it('should notify sign and acceptance', function(done) { server.getPendingTxs({}, function(err, txs) { - blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'broadcast error'); - var tx = txs[0]; - var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: tx.id, - signatures: signatures, - }, function(err) { - server.getNotifications({ - minTs: Date.now(), - }, function(err, notifications) { - should.not.exist(err); - notifications.length.should.equal(2); - var types = _.map(notifications, 'type'); - types.should.deep.equal(['TxProposalAcceptedBy', 'TxProposalFinallyAccepted']); - done(); - }); - }); + blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'broadcast error'); + var tx = txs[0]; + var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_44H_0H_0H); + server.signTx( + { + txProposalId: tx.id, + signatures: signatures, + }, + function(err) { + server.getNotifications( + { + minTs: Date.now(), + }, + function(err, notifications) { + should.not.exist(err); + notifications.length.should.equal(2); + var types = _.map(notifications, 'type'); + types.should.deep.equal(['TxProposalAcceptedBy', 'TxProposalFinallyAccepted']); + done(); + }, + ); + }, + ); }); }); it('should notify rejection', function(done) { server.getPendingTxs({}, function(err, txs) { var tx = txs[1]; - server.rejectTx({ - txProposalId: tx.id, - }, function(err) { - should.not.exist(err); - server.getNotifications({ - minTs: Date.now(), - }, function(err, notifications) { + server.rejectTx( + { + txProposalId: tx.id, + }, + function(err) { should.not.exist(err); - notifications.length.should.equal(2); - var types = _.map(notifications, 'type'); - types.should.deep.equal(['TxProposalRejectedBy', 'TxProposalFinallyRejected']); - done(); - }); - }); + server.getNotifications( + { + minTs: Date.now(), + }, + function(err, notifications) { + should.not.exist(err); + notifications.length.should.equal(2); + var types = _.map(notifications, 'type'); + types.should.deep.equal(['TxProposalRejectedBy', 'TxProposalFinallyRejected']); + done(); + }, + ); + }, + ); }); }); it('should notify sign, acceptance, and broadcast, and emit', function(done) { server.getPendingTxs({}, function(err, txs) { var tx = txs[2]; var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: tx.id, - signatures: signatures, - }, function(err) { - should.not.exist(err); - helpers.stubBroadcast(); - server.broadcastTx({ - txProposalId: tx.id - }, function(err, txp) { + server.signTx( + { + txProposalId: tx.id, + signatures: signatures, + }, + function(err) { should.not.exist(err); - server.getNotifications({ - minTs: Date.now(), - }, function(err, notifications) { - should.not.exist(err); - notifications.length.should.equal(3); - var types = _.map(notifications, 'type'); - types.should.deep.equal(['TxProposalAcceptedBy', 'TxProposalFinallyAccepted', 'OutgoingTx']); - done(); - }); - }); - }); + helpers.stubBroadcast(); + server.broadcastTx( + { + txProposalId: tx.id, + }, + function(err, txp) { + should.not.exist(err); + server.getNotifications( + { + minTs: Date.now(), + }, + function(err, notifications) { + should.not.exist(err); + notifications.length.should.equal(3); + var types = _.map(notifications, 'type'); + types.should.deep.equal(['TxProposalAcceptedBy', 'TxProposalFinallyAccepted', 'OutgoingTx']); + done(); + }, + ); + }, + ); + }, + ); }); }); it('should notify sign, acceptance, and broadcast, and emit (with 3rd party broadcast', function(done) { server.getPendingTxs({}, function(err, txs) { var tx = txs[2]; var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: tx.id, - signatures: signatures, - }, function(err) { - should.not.exist(err); - blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'err'); - blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, null, { - txid: 11 - }); - server.broadcastTx({ - txProposalId: tx.id - }, function(err, txp) { + server.signTx( + { + txProposalId: tx.id, + signatures: signatures, + }, + function(err) { should.not.exist(err); - server.getNotifications({ - minTs: Date.now(), - }, function(err, notifications) { - should.not.exist(err); - notifications.length.should.equal(3); - var types = _.map(notifications, 'type'); - types.should.deep.equal(['TxProposalAcceptedBy', 'TxProposalFinallyAccepted', 'OutgoingTxByThirdParty']); - done(); + blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'err'); + blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, null, { + txid: 11, }); - }); - }); + server.broadcastTx( + { + txProposalId: tx.id, + }, + function(err, txp) { + should.not.exist(err); + server.getNotifications( + { + minTs: Date.now(), + }, + function(err, notifications) { + should.not.exist(err); + notifications.length.should.equal(3); + var types = _.map(notifications, 'type'); + types.should.deep.equal([ + 'TxProposalAcceptedBy', + 'TxProposalFinallyAccepted', + 'OutgoingTxByThirdParty', + ]); + done(); + }, + ); + }, + ); + }, + ); }); }); }); @@ -5877,10 +6673,12 @@ describe('Wallet service', function() { wallet = w; helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], feePerKb: 100e2, message: 'some message', }; @@ -5894,65 +6692,82 @@ describe('Wallet service', function() { }); }); it('should allow creator to remove an unsigned TX', function(done) { - server.removePendingTx({ - txProposalId: txp.id - }, function(err) { - should.not.exist(err); - server.getPendingTxs({}, function(err, txs) { - txs.length.should.equal(0); - done(); - }); - }); - }); - it('should allow creator to remove a signed TX by himself', function(done) { - var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: txp.id, - signatures: signatures, - }, function(err) { - should.not.exist(err); - server.removePendingTx({ - txProposalId: txp.id - }, function(err) { + server.removePendingTx( + { + txProposalId: txp.id, + }, + function(err) { should.not.exist(err); server.getPendingTxs({}, function(err, txs) { txs.length.should.equal(0); done(); }); - }); - }); + }, + ); + }); + it('should allow creator to remove a signed TX by himself', function(done) { + var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_44H_0H_0H); + server.signTx( + { + txProposalId: txp.id, + signatures: signatures, + }, + function(err) { + should.not.exist(err); + server.removePendingTx( + { + txProposalId: txp.id, + }, + function(err) { + should.not.exist(err); + server.getPendingTxs({}, function(err, txs) { + txs.length.should.equal(0); + done(); + }); + }, + ); + }, + ); }); it('should fail to remove non-pending TX', function(done) { async.waterfall([ - function(next) { var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: txp.id, - signatures: signatures, - }, function(err) { - should.not.exist(err); - next(); - }); - }, - function(next) { - helpers.getAuthServer(wallet.copayers[1].id, function(server) { - server.rejectTx({ + server.signTx( + { txProposalId: txp.id, - }, function(err) { + signatures: signatures, + }, + function(err) { should.not.exist(err); next(); - }); + }, + ); + }, + function(next) { + helpers.getAuthServer(wallet.copayers[1].id, function(server) { + server.rejectTx( + { + txProposalId: txp.id, + }, + function(err) { + should.not.exist(err); + next(); + }, + ); }); }, function(next) { helpers.getAuthServer(wallet.copayers[2].id, function(server) { - server.rejectTx({ - txProposalId: txp.id, - }, function(err) { - should.not.exist(err); - next(); - }); + server.rejectTx( + { + txProposalId: txp.id, + }, + function(err) { + should.not.exist(err); + next(); + }, + ); }); }, function(next) { @@ -5963,108 +6778,138 @@ describe('Wallet service', function() { }); }, function(next) { - server.removePendingTx({ - txProposalId: txp.id - }, function(err) { - should.exist(err); - err.code.should.equal('TX_NOT_PENDING'); - done(); - }); + server.removePendingTx( + { + txProposalId: txp.id, + }, + function(err) { + should.exist(err); + err.code.should.equal('TX_NOT_PENDING'); + done(); + }, + ); }, ]); }); it('should not allow non-creator copayer to remove an unsigned TX ', function(done) { helpers.getAuthServer(wallet.copayers[1].id, function(server2) { - server2.removePendingTx({ - txProposalId: txp.id - }, function(err) { - should.exist(err); - err.code.should.contain('TX_CANNOT_REMOVE'); - server2.getPendingTxs({}, function(err, txs) { - txs.length.should.equal(1); - done(); - }); - }); + server2.removePendingTx( + { + txProposalId: txp.id, + }, + function(err) { + should.exist(err); + err.code.should.contain('TX_CANNOT_REMOVE'); + server2.getPendingTxs({}, function(err, txs) { + txs.length.should.equal(1); + done(); + }); + }, + ); }); }); it('should not allow creator copayer to remove a TX signed by other copayer, in less than 24hrs', function(done) { helpers.getAuthServer(wallet.copayers[1].id, function(server2) { var signatures = helpers.clientSign(txp, TestData.copayers[1].xPrivKey_44H_0H_0H); - server2.signTx({ - txProposalId: txp.id, - signatures: signatures, - }, function(err) { - should.not.exist(err); - server.removePendingTx({ - txProposalId: txp.id - }, function(err) { - err.code.should.equal('TX_CANNOT_REMOVE'); - err.message.should.contain('Cannot remove'); - done(); - }); - }); + server2.signTx( + { + txProposalId: txp.id, + signatures: signatures, + }, + function(err) { + should.not.exist(err); + server.removePendingTx( + { + txProposalId: txp.id, + }, + function(err) { + err.code.should.equal('TX_CANNOT_REMOVE'); + err.message.should.contain('Cannot remove'); + done(); + }, + ); + }, + ); }); }); it('should allow creator copayer to remove a TX rejected by other copayer, in less than 24hrs', function(done) { helpers.getAuthServer(wallet.copayers[1].id, function(server2) { var signatures = helpers.clientSign(txp, TestData.copayers[1].xPrivKey_44H_0H_0H); - server2.rejectTx({ - txProposalId: txp.id, - signatures: signatures, - }, function(err) { - should.not.exist(err); - server.removePendingTx({ - txProposalId: txp.id - }, function(err) { + server2.rejectTx( + { + txProposalId: txp.id, + signatures: signatures, + }, + function(err) { should.not.exist(err); - done(); - }); - }); + server.removePendingTx( + { + txProposalId: txp.id, + }, + function(err) { + should.not.exist(err); + done(); + }, + ); + }, + ); }); }); it('should allow creator copayer to remove a TX signed by other copayer, after 24hrs', function(done) { helpers.getAuthServer(wallet.copayers[1].id, function(server2) { var signatures = helpers.clientSign(txp, TestData.copayers[1].xPrivKey_44H_0H_0H); - server2.signTx({ - txProposalId: txp.id, - signatures: signatures, - }, function(err) { - should.not.exist(err); - - server.getPendingTxs({}, function(err, txs) { + server2.signTx( + { + txProposalId: txp.id, + signatures: signatures, + }, + function(err) { should.not.exist(err); - txs[0].deleteLockTime.should.be.above(Defaults.DELETE_LOCKTIME - 10); - var clock = sinon.useFakeTimers(Date.now() + 1 + 24 * 3600 * 1000, 'Date'); - server.removePendingTx({ - txProposalId: txp.id - }, function(err) { + server.getPendingTxs({}, function(err, txs) { should.not.exist(err); - clock.restore(); - done(); + txs[0].deleteLockTime.should.be.above(Defaults.DELETE_LOCKTIME - 10); + + var clock = sinon.useFakeTimers(Date.now() + 1 + 24 * 3600 * 1000, 'Date'); + server.removePendingTx( + { + txProposalId: txp.id, + }, + function(err) { + should.not.exist(err); + clock.restore(); + done(); + }, + ); }); - }); - }); + }, + ); }); }); it('should allow other copayer to remove a TX signed, after 24hrs', function(done) { helpers.getAuthServer(wallet.copayers[1].id, function(server2) { var signatures = helpers.clientSign(txp, TestData.copayers[1].xPrivKey_44H_0H_0H); - server2.signTx({ - txProposalId: txp.id, - signatures: signatures, - }, function(err) { - should.not.exist(err); - - var clock = sinon.useFakeTimers(Date.now() + 2000 + Defaults.DELETE_LOCKTIME * 1000, 'Date'); - server2.removePendingTx({ - txProposalId: txp.id - }, function(err) { + server2.signTx( + { + txProposalId: txp.id, + signatures: signatures, + }, + function(err) { should.not.exist(err); - clock.restore(); - done(); - }); - }); + + var clock = sinon.useFakeTimers(Date.now() + 2000 + Defaults.DELETE_LOCKTIME * 1000, 'Date'); + server2.removePendingTx( + { + txProposalId: txp.id, + }, + function(err) { + should.not.exist(err); + clock.restore(); + done(); + }, + ); + }, + ); }); }); }); @@ -6103,20 +6948,26 @@ describe('Wallet service', function() { }); it('should get tx history for incoming txs', function(done) { server._normalizeTxHistory = sinon.stub().returnsArg(0); - var txs = [{ - txid: '1', - confirmations: 1, - fees: 100, - time: 20, - inputs: [{ - address: 'external', - amount: 500, - }], - outputs: [{ - address: mainAddresses[0].address, - amount: 200, - }], - }]; + var txs = [ + { + txid: '1', + confirmations: 1, + fees: 100, + time: 20, + inputs: [ + { + address: 'external', + amount: 500, + }, + ], + outputs: [ + { + address: mainAddresses[0].address, + amount: 200, + }, + ], + }, + ]; helpers.stubHistory(txs); server.getTxHistory({}, function(err, txs) { should.not.exist(err); @@ -6132,20 +6983,26 @@ describe('Wallet service', function() { }); it('should get tx history for outgoing txs', function(done) { server._normalizeTxHistory = sinon.stub().returnsArg(0); - var txs = [{ - txid: '1', - confirmations: 1, - fees: 100, - time: 12345, - inputs: [{ - address: mainAddresses[0].address, - amount: 500, - }], - outputs: [{ - address: 'external', - amount: 400, - }], - }]; + var txs = [ + { + txid: '1', + confirmations: 1, + fees: 100, + time: 12345, + inputs: [ + { + address: mainAddresses[0].address, + amount: 500, + }, + ], + outputs: [ + { + address: 'external', + amount: 400, + }, + ], + }, + ]; helpers.stubHistory(txs); server.getTxHistory({}, function(err, txs) { should.not.exist(err); @@ -6161,23 +7018,30 @@ describe('Wallet service', function() { }); it('should get tx history for outgoing txs + change', function(done) { server._normalizeTxHistory = sinon.stub().returnsArg(0); - var txs = [{ - txid: '1', - confirmations: 1, - fees: 100, - time: Date.now() / 1000, - inputs: [{ - address: mainAddresses[0].address, - amount: 500, - }], - outputs: [{ - address: 'external', - amount: 300, - }, { - address: changeAddresses[0].address, - amount: 100, - }], - }]; + var txs = [ + { + txid: '1', + confirmations: 1, + fees: 100, + time: Date.now() / 1000, + inputs: [ + { + address: mainAddresses[0].address, + amount: 500, + }, + ], + outputs: [ + { + address: 'external', + amount: 300, + }, + { + address: changeAddresses[0].address, + amount: 100, + }, + ], + }, + ]; helpers.stubHistory(txs); server.getTxHistory({}, function(err, txs) { should.not.exist(err); @@ -6198,140 +7062,167 @@ describe('Wallet service', function() { helpers.stubUtxos(server, wallet, [1, 2], function(utxos) { var txOpts = { - outputs: [{ - toAddress: external, - amount: 0.5e8, - message: undefined // no message - }, { - toAddress: external, - amount: 0.3e8, - message: 'message #2' - }], + outputs: [ + { + toAddress: external, + amount: 0.5e8, + message: undefined, // no message + }, + { + toAddress: external, + amount: 0.3e8, + message: 'message #2', + }, + ], feePerKb: 100e2, message: 'some message', customData: { - "test": true + test: true, }, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(tx) { should.exist(tx); var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: tx.id, - signatures: signatures, - }, function(err, tx) { - should.not.exist(err); - - helpers.stubBroadcast(); - server.broadcastTx({ - txProposalId: tx.id - }, function(err, txp) { + server.signTx( + { + txProposalId: tx.id, + signatures: signatures, + }, + function(err, tx) { should.not.exist(err); - var txs = [{ - txid: txp.txid, - confirmations: 1, - fees: 5460, - time: Date.now() / 1000, - inputs: [{ - address: tx.inputs[0].address, - amount: utxos[0].micros, - }], - outputs: [{ - address: changeAddresses[0].address, - amount: 0.2e8 - 5460, - }, { - address: external, - amount: 0.5e8, - }, { - address: external, - amount: 0.3e8, - }] - }]; - helpers.stubHistory(txs); - - server.getTxHistory({}, function(err, txs) { - should.not.exist(err); - should.exist(txs); - txs.length.should.equal(1); - var tx = txs[0]; - tx.createdOn.should.equal(txp.createdOn); - tx.action.should.equal('sent'); - tx.amount.should.equal(0.8e8); - tx.message.should.equal('some message'); - tx.addressTo.should.equal(external); - tx.actions.length.should.equal(1); - tx.actions[0].type.should.equal('accept'); - tx.actions[0].copayerName.should.equal('copayer 1'); - tx.outputs[0].address.should.equal(external); - tx.outputs[0].amount.should.equal(0.5e8); - should.not.exist(tx.outputs[0].message); - should.not.exist(tx.outputs[0]['isMine']); - should.not.exist(tx.outputs[0]['isChange']); - tx.outputs[1].address.should.equal(external); - tx.outputs[1].amount.should.equal(0.3e8); - should.exist(tx.outputs[1].message); - tx.outputs[1].message.should.equal('message #2'); - should.exist(tx.customData); - should.exist(tx.customData["test"]); - done(); - }); - }); - }); + + helpers.stubBroadcast(); + server.broadcastTx( + { + txProposalId: tx.id, + }, + function(err, txp) { + should.not.exist(err); + var txs = [ + { + txid: txp.txid, + confirmations: 1, + fees: 5460, + time: Date.now() / 1000, + inputs: [ + { + address: tx.inputs[0].address, + amount: utxos[0].micros, + }, + ], + outputs: [ + { + address: changeAddresses[0].address, + amount: 0.2e8 - 5460, + }, + { + address: external, + amount: 0.5e8, + }, + { + address: external, + amount: 0.3e8, + }, + ], + }, + ]; + helpers.stubHistory(txs); + + server.getTxHistory({}, function(err, txs) { + should.not.exist(err); + should.exist(txs); + txs.length.should.equal(1); + var tx = txs[0]; + tx.createdOn.should.equal(txp.createdOn); + tx.action.should.equal('sent'); + tx.amount.should.equal(0.8e8); + tx.message.should.equal('some message'); + tx.addressTo.should.equal(external); + tx.actions.length.should.equal(1); + tx.actions[0].type.should.equal('accept'); + tx.actions[0].copayerName.should.equal('copayer 1'); + tx.outputs[0].address.should.equal(external); + tx.outputs[0].amount.should.equal(0.5e8); + should.not.exist(tx.outputs[0].message); + should.not.exist(tx.outputs[0]['isMine']); + should.not.exist(tx.outputs[0]['isChange']); + tx.outputs[1].address.should.equal(external); + tx.outputs[1].amount.should.equal(0.3e8); + should.exist(tx.outputs[1].message); + tx.outputs[1].message.should.equal('message #2'); + should.exist(tx.customData); + should.exist(tx.customData['test']); + done(); + }); + }, + ); + }, + ); }); }); }); it('should get various paginated tx history', function(done) { - var testCases = [{ - opts: {}, - expected: [50, 40, 30, 20, 10], - }, { - opts: { - skip: 1, - limit: 3, + var testCases = [ + { + opts: {}, + expected: [50, 40, 30, 20, 10], }, - expected: [40, 30, 20], - }, { - opts: { - skip: 1, - limit: 2, + { + opts: { + skip: 1, + limit: 3, + }, + expected: [40, 30, 20], }, - expected: [40, 30], - }, { - opts: { - skip: 2, + { + opts: { + skip: 1, + limit: 2, + }, + expected: [40, 30], }, - expected: [30, 20, 10], - }, { - opts: { - limit: 4, + { + opts: { + skip: 2, + }, + expected: [30, 20, 10], }, - expected: [50, 40, 30, 20], - }, { - opts: { - skip: 0, - limit: 3, + { + opts: { + limit: 4, + }, + expected: [50, 40, 30, 20], }, - expected: [50, 40, 30], - }, { - opts: { - skip: 0, - limit: 0, + { + opts: { + skip: 0, + limit: 3, + }, + expected: [50, 40, 30], }, - expected: [], - }, { - opts: { - skip: 4, - limit: 10, + { + opts: { + skip: 0, + limit: 0, + }, + expected: [], + }, + { + opts: { + skip: 4, + limit: 10, + }, + expected: [10], }, - expected: [10], - }, { - opts: { - skip: 20, - limit: 1, + { + opts: { + skip: 20, + limit: 1, + }, + expected: [], }, - expected: [], - }]; + ]; server._normalizeTxHistory = sinon.stub().returnsArg(0); var timestamps = [50, 40, 30, 20, 10]; @@ -6341,26 +7232,34 @@ describe('Wallet service', function() { confirmations: ts / 10, fees: 100, time: ts, - inputs: [{ - address: 'external', - amount: 500, - }], - outputs: [{ - address: mainAddresses[0].address, - amount: 200, - }], + inputs: [ + { + address: 'external', + amount: 500, + }, + ], + outputs: [ + { + address: mainAddresses[0].address, + amount: 200, + }, + ], }; }); helpers.stubHistory(txs); - async.each(testCases, function(testCase, next) { - server.getTxHistory(testCase.opts, function(err, txs) { - should.not.exist(err); - should.exist(txs); - _.map(txs, 'time').should.deep.equal(testCase.expected); - next(); - }); - }, done); + async.each( + testCases, + function(testCase, next) { + server.getTxHistory(testCase.opts, function(err, txs) { + should.not.exist(err); + should.exist(txs); + _.map(txs, 'time').should.deep.equal(testCase.expected); + next(); + }); + }, + done, + ); }); it('should fail gracefully if unable to reach the blockchain', function(done) { blockchainExplorer.getTransactions = sinon.stub().callsArgWith(3, 'dummy error'); @@ -6373,8 +7272,8 @@ describe('Wallet service', function() { it('should handle invalid tx in history ', function(done) { var h = _.clone(TestData.history); h.push({ - txid: 'xx' - }) + txid: 'xx', + }); helpers.stubHistory(h); var l = TestData.history.length; @@ -6387,61 +7286,80 @@ describe('Wallet service', function() { }); }); it('should handle exceeded limit', function(done) { - server.getTxHistory({ - limit: 1000 - }, function(err, txs) { - err.code.should.equal('HISTORY_LIMIT_EXCEEDED'); - done(); - }); + server.getTxHistory( + { + limit: 1000, + }, + function(err, txs) { + err.code.should.equal('HISTORY_LIMIT_EXCEEDED'); + done(); + }, + ); }); it('should set lowFees atribute for sub-superEconomy level fees on unconfirmed txs', function(done) { helpers.stubFeeLevels({ 24: 10000, }); server._normalizeTxHistory = sinon.stub().returnsArg(0); - var txs = [{ - txid: '1', - confirmations: 0, - fees: 100, - time: 20, - inputs: [{ - address: 'external', - amount: 500, - }], - outputs: [{ - address: mainAddresses[0].address, - amount: 200, - }], - size: 500, - }, { - txid: '2', - confirmations: 0, - fees: 6000, - time: 20, - inputs: [{ - address: 'external', - amount: 500, - }], - outputs: [{ - address: mainAddresses[0].address, - amount: 200, - }], - size: 500, - }, { - txid: '3', - confirmations: 6, - fees: 100, - time: 20, - inputs: [{ - address: 'external', - amount: 500, - }], - outputs: [{ - address: mainAddresses[0].address, - amount: 200, - }], - size: 500, - }]; + var txs = [ + { + txid: '1', + confirmations: 0, + fees: 100, + time: 20, + inputs: [ + { + address: 'external', + amount: 500, + }, + ], + outputs: [ + { + address: mainAddresses[0].address, + amount: 200, + }, + ], + size: 500, + }, + { + txid: '2', + confirmations: 0, + fees: 6000, + time: 20, + inputs: [ + { + address: 'external', + amount: 500, + }, + ], + outputs: [ + { + address: mainAddresses[0].address, + amount: 200, + }, + ], + size: 500, + }, + { + txid: '3', + confirmations: 6, + fees: 100, + time: 20, + inputs: [ + { + address: 'external', + amount: 500, + }, + ], + outputs: [ + { + address: mainAddresses[0].address, + amount: 200, + }, + ], + size: 500, + }, + ]; helpers.stubHistory(txs); server.getTxHistory({}, function(err, txs) { should.not.exist(err); @@ -6460,21 +7378,27 @@ describe('Wallet service', function() { it('should get tx history even if fee levels are unavailable', function(done) { blockchainExplorer.estimateFee = sinon.stub().yields('dummy error'); server._normalizeTxHistory = sinon.stub().returnsArg(0); - var txs = [{ - txid: '1', - confirmations: 1, - fees: 100, - time: 20, - inputs: [{ - address: 'external', - amount: 500, - }], - outputs: [{ - address: mainAddresses[0].address, - amount: 200, - }], - size: 500, - }]; + var txs = [ + { + txid: '1', + confirmations: 1, + fees: 100, + time: 20, + inputs: [ + { + address: 'external', + amount: 500, + }, + ], + outputs: [ + { + address: mainAddresses[0].address, + amount: 200, + }, + ], + size: 500, + }, + ]; helpers.stubHistory(txs); server.getTxHistory({}, function(err, txs) { should.not.exist(err); @@ -6518,53 +7442,55 @@ describe('Wallet service', function() { blockchainExplorer.getBlockchainHeight = sinon.stub().callsArgWith(0, null, 200); var storeTxHistoryCacheSpy = sinon.spy(server.storage, 'storeTxHistoryCache'); + server.getTxHistory( + { + skip: skip, + limit: limit, + }, + function(err, txs) { + // FROM the END, we are getting items + // End-1, end-2, end-3. - server.getTxHistory({ - skip: skip, - limit: limit, - }, function(err, txs) { + should.not.exist(err); + should.exist(txs); + txs.length.should.equal(limit); + var calls = storeTxHistoryCacheSpy.getCalls(); + calls.length.should.equal(1); - // FROM the END, we are getting items - // End-1, end-2, end-3. + calls[0].args[1].should.equal(totalItems); // total + calls[0].args[2].should.equal(totalItems - skip - limit); // position + calls[0].args[3].length.should.equal(5); // 5 txs have confirmations>= 36 - should.not.exist(err); - should.exist(txs); - txs.length.should.equal(limit); - var calls = storeTxHistoryCacheSpy.getCalls(); - calls.length.should.equal(1); - - calls[0].args[1].should.equal(totalItems); // total - calls[0].args[2].should.equal(totalItems - skip - limit); // position - calls[0].args[3].length.should.equal(5); // 5 txs have confirmations>= 36 - - // should be reversed! - calls[0].args[3][0].confirmations.should.equal(skip + limit - 1); - calls[0].args[3][0].txid.should.equal(h[skip + limit - 1].txid); - server.storage.storeTxHistoryCache.restore(); - done(); - }); + // should be reversed! + calls[0].args[3][0].confirmations.should.equal(skip + limit - 1); + calls[0].args[3][0].txid.should.equal(h[skip + limit - 1].txid); + server.storage.storeTxHistoryCache.restore(); + done(); + }, + ); }); - it('should not cache tx history when requesting txs with low # of confirmations', function(done) { var h = helpers.historyCacheTest(200); helpers.stubHistory(h); blockchainExplorer.getBlockchainHeight = sinon.stub().callsArgWith(0, null, 1000); var storeTxHistoryCacheSpy = sinon.spy(server.storage, 'storeTxHistoryCache'); - server.getTxHistory({ - skip: 0, - limit: 10, - }, function(err, txs) { - should.not.exist(err); - should.exist(txs); - var calls = storeTxHistoryCacheSpy.getCalls(); - calls.length.should.equal(0); - server.storage.storeTxHistoryCache.restore(); - done(); - }); + server.getTxHistory( + { + skip: 0, + limit: 10, + }, + function(err, txs) { + should.not.exist(err); + should.exist(txs); + var calls = storeTxHistoryCacheSpy.getCalls(); + calls.length.should.equal(0); + server.storage.storeTxHistoryCache.restore(); + done(); + }, + ); }); - it('should store cache all tx history from insight', function(done) { var skip = 195; var limit = 5; @@ -6575,27 +7501,29 @@ describe('Wallet service', function() { blockchainExplorer.getBlockchainHeight = sinon.stub().callsArgWith(0, null, 200); var storeTxHistoryCacheSpy = sinon.spy(server.storage, 'storeTxHistoryCache'); - server.getTxHistory({ - skip: skip, - limit: limit, - }, function(err, txs) { + server.getTxHistory( + { + skip: skip, + limit: limit, + }, + function(err, txs) { + should.not.exist(err); + should.exist(txs); + txs.length.should.equal(limit); + var calls = storeTxHistoryCacheSpy.getCalls(); + calls.length.should.equal(1); - should.not.exist(err); - should.exist(txs); - txs.length.should.equal(limit); - var calls = storeTxHistoryCacheSpy.getCalls(); - calls.length.should.equal(1); - - calls[0].args[1].should.equal(totalItems); // total - calls[0].args[2].should.equal(totalItems - skip - limit); // position - calls[0].args[3].length.should.equal(5); - - // should be reversed! - calls[0].args[3][0].confirmations.should.equal(totalItems - 1); - calls[0].args[3][0].txid.should.equal(h[totalItems - 1].txid); - server.storage.storeTxHistoryCache.restore(); - done(); - }); + calls[0].args[1].should.equal(totalItems); // total + calls[0].args[2].should.equal(totalItems - skip - limit); // position + calls[0].args[3].length.should.equal(5); + + // should be reversed! + calls[0].args[3][0].confirmations.should.equal(totalItems - 1); + calls[0].args[3][0].txid.should.equal(h[totalItems - 1].txid); + server.storage.storeTxHistoryCache.restore(); + done(); + }, + ); }); it('should get real # of confirmations based on current block height', function(done) { @@ -6614,49 +7542,63 @@ describe('Wallet service', function() { blockchainExplorer.getBlockchainHeight = sinon.stub().callsArgWith(0, null, 1500); // Cache txs - server.getTxHistory({ - skip: 0, - limit: 30, - }, function(err, txs) { - should.not.exist(err); - should.exist(txs); - var calls = storeTxHistoryCacheSpy.getCalls(); - calls.length.should.equal(1); - - server.getTxHistory({ + server.getTxHistory( + { skip: 0, limit: 30, - }, function(err, txs) { + }, + function(err, txs) { should.not.exist(err); - txs.length.should.equal(20); - _.head(txs).confirmations.should.equal(501); - _.last(txs).confirmations.should.equal(520); - - blockchainExplorer.getBlockchainHeight = sinon.stub().callsArgWith(0, null, 2000); - server._notify('NewBlock', { - network: 'livenet', - hash: 'dummy hash', - }, { - isGlobal: true - }, function(err) { - should.not.exist(err); - setTimeout(function() { - server.getTxHistory({ - skip: 0, - limit: 30, - }, function(err, txs) { - should.not.exist(err); - _.head(txs).confirmations.should.equal(1001); - _.last(txs).confirmations.should.equal(1020); + should.exist(txs); + var calls = storeTxHistoryCacheSpy.getCalls(); + calls.length.should.equal(1); - server.storage.storeTxHistoryCache.restore(); - Defaults.CONFIRMATIONS_TO_START_CACHING = _confirmations; - done(); - }); - }, 100); - }); - }); - }); + server.getTxHistory( + { + skip: 0, + limit: 30, + }, + function(err, txs) { + should.not.exist(err); + txs.length.should.equal(20); + _.head(txs).confirmations.should.equal(501); + _.last(txs).confirmations.should.equal(520); + + blockchainExplorer.getBlockchainHeight = sinon.stub().callsArgWith(0, null, 2000); + server._notify( + 'NewBlock', + { + network: 'livenet', + hash: 'dummy hash', + }, + { + isGlobal: true, + }, + function(err) { + should.not.exist(err); + setTimeout(function() { + server.getTxHistory( + { + skip: 0, + limit: 30, + }, + function(err, txs) { + should.not.exist(err); + _.head(txs).confirmations.should.equal(1001); + _.last(txs).confirmations.should.equal(1020); + + server.storage.storeTxHistoryCache.restore(); + Defaults.CONFIRMATIONS_TO_START_CACHING = _confirmations; + done(); + }, + ); + }, 100); + }, + ); + }, + ); + }, + ); }); it('should get cached # of confirmations if current height unknown', function(done) { @@ -6675,30 +7617,36 @@ describe('Wallet service', function() { blockchainExplorer.getBlockchainHeight = sinon.stub().callsArgWith(0, null, null); // Cache txs - server.getTxHistory({ - skip: 0, - limit: 30, - }, function(err, txs) { - should.not.exist(err); - should.exist(txs); - txs.length.should.equal(20); - var calls = storeTxHistoryCacheSpy.getCalls(); - calls.length.should.equal(1); - - server.getTxHistory({ + server.getTxHistory( + { skip: 0, limit: 30, - }, function(err, txs) { + }, + function(err, txs) { should.not.exist(err); + should.exist(txs); txs.length.should.equal(20); - _.head(txs).confirmations.should.equal(500); - _.last(txs).confirmations.should.equal(519); + var calls = storeTxHistoryCacheSpy.getCalls(); + calls.length.should.equal(1); - server.storage.storeTxHistoryCache.restore(); - Defaults.CONFIRMATIONS_TO_START_CACHING = _confirmations; - done(); - }); - }); + server.getTxHistory( + { + skip: 0, + limit: 30, + }, + function(err, txs) { + should.not.exist(err); + txs.length.should.equal(20); + _.head(txs).confirmations.should.equal(500); + _.last(txs).confirmations.should.equal(519); + + server.storage.storeTxHistoryCache.restore(); + Defaults.CONFIRMATIONS_TO_START_CACHING = _confirmations; + done(); + }, + ); + }, + ); }); it('should get returned # of confirmations for non cached txs', function(done) { @@ -6713,30 +7661,36 @@ describe('Wallet service', function() { blockchainExplorer.getBlockchainHeight = sinon.stub().callsArgWith(0, null, 500); // Cache txs - server.getTxHistory({ - skip: 0, - limit: 30, - }, function(err, txs) { - should.not.exist(err); - should.exist(txs); - txs.length.should.equal(20); - var calls = storeTxHistoryCacheSpy.getCalls(); - calls.length.should.equal(1); - - server.getTxHistory({ + server.getTxHistory( + { skip: 0, limit: 30, - }, function(err, txs) { + }, + function(err, txs) { should.not.exist(err); + should.exist(txs); txs.length.should.equal(20); - _.head(txs).confirmations.should.equal(0); - _.last(txs).confirmations.should.equal(19); + var calls = storeTxHistoryCacheSpy.getCalls(); + calls.length.should.equal(1); - server.storage.storeTxHistoryCache.restore(); - Defaults.CONFIRMATIONS_TO_START_CACHING = _confirmations; - done(); - }); - }); + server.getTxHistory( + { + skip: 0, + limit: 30, + }, + function(err, txs) { + should.not.exist(err); + txs.length.should.equal(20); + _.head(txs).confirmations.should.equal(0); + _.last(txs).confirmations.should.equal(19); + + server.storage.storeTxHistoryCache.restore(); + Defaults.CONFIRMATIONS_TO_START_CACHING = _confirmations; + done(); + }, + ); + }, + ); }); describe('Downloading history', function() { @@ -6751,118 +7705,156 @@ describe('Wallet service', function() { }); it('from 0 to 200, two times, in order', function(done) { - async.eachSeries(_.range(0, 200, 5), function(i, next) { - server.getTxHistory({ - skip: i, - limit: 5, - }, function(err, txs, fromCache) { - should.not.exist(err); - should.exist(txs); - txs.length.should.equal(5); - var s = h.slice(i, i + 5); - _.map(txs, 'txid').should.deep.equal(_.map(s, 'txid')); - fromCache.should.equal(false); - next(); - }); - }, function() { - async.eachSeries(_.range(0, 200, 5), function(i, next) { - server.getTxHistory({ - skip: i, - limit: 5, - }, function(err, txs, fromCache) { - should.not.exist(err); - should.exist(txs); - txs.length.should.equal(5); - var s = h.slice(i, i + 5); - _.map(txs, 'txid').should.deep.equal(_.map(s, 'txid')); - fromCache.should.equal(i >= Defaults.CONFIRMATIONS_TO_START_CACHING && i < 200); - next(); - }); - }, done); - }); + async.eachSeries( + _.range(0, 200, 5), + function(i, next) { + server.getTxHistory( + { + skip: i, + limit: 5, + }, + function(err, txs, fromCache) { + should.not.exist(err); + should.exist(txs); + txs.length.should.equal(5); + var s = h.slice(i, i + 5); + _.map(txs, 'txid').should.deep.equal(_.map(s, 'txid')); + fromCache.should.equal(false); + next(); + }, + ); + }, + function() { + async.eachSeries( + _.range(0, 200, 5), + function(i, next) { + server.getTxHistory( + { + skip: i, + limit: 5, + }, + function(err, txs, fromCache) { + should.not.exist(err); + should.exist(txs); + txs.length.should.equal(5); + var s = h.slice(i, i + 5); + _.map(txs, 'txid').should.deep.equal(_.map(s, 'txid')); + fromCache.should.equal(i >= Defaults.CONFIRMATIONS_TO_START_CACHING && i < 200); + next(); + }, + ); + }, + done, + ); + }, + ); }); it('from 0 to 200, two times, random', function(done) { var indexes = _.range(0, 200, 5); - async.eachSeries(_.shuffle(indexes), function(i, next) { - server.getTxHistory({ - skip: i, - limit: 5, - }, function(err, txs, fromCache) { - should.not.exist(err); - should.exist(txs); - txs.length.should.equal(5); - var s = h.slice(i, i + 5); - _.map(txs, 'txid').should.deep.equal(_.map(s, 'txid')); - fromCache.should.equal(false); - next(); - }); - }, function() { - async.eachSeries(_.range(0, 190, 7), function(i, next) { - server.getTxHistory({ - skip: i, - limit: 7, - }, function(err, txs, fromCache) { - should.not.exist(err); - should.exist(txs); - txs.length.should.equal(7); - var s = h.slice(i, i + 7); - _.map(txs, 'txid').should.deep.equal(_.map(s, 'txid')); - fromCache.should.equal(i >= Defaults.CONFIRMATIONS_TO_START_CACHING); - next(); - }); - }, done); - }); + async.eachSeries( + _.shuffle(indexes), + function(i, next) { + server.getTxHistory( + { + skip: i, + limit: 5, + }, + function(err, txs, fromCache) { + should.not.exist(err); + should.exist(txs); + txs.length.should.equal(5); + var s = h.slice(i, i + 5); + _.map(txs, 'txid').should.deep.equal(_.map(s, 'txid')); + fromCache.should.equal(false); + next(); + }, + ); + }, + function() { + async.eachSeries( + _.range(0, 190, 7), + function(i, next) { + server.getTxHistory( + { + skip: i, + limit: 7, + }, + function(err, txs, fromCache) { + should.not.exist(err); + should.exist(txs); + txs.length.should.equal(7); + var s = h.slice(i, i + 7); + _.map(txs, 'txid').should.deep.equal(_.map(s, 'txid')); + fromCache.should.equal(i >= Defaults.CONFIRMATIONS_TO_START_CACHING); + next(); + }, + ); + }, + done, + ); + }, + ); }); - it('from 0 to 200, two times, random, with resets', function(done) { var indexes = _.range(0, 200, 5); - async.eachSeries(_.shuffle(indexes), function(i, next) { - server.getTxHistory({ - skip: i, - limit: 5, - }, function(err, txs, fromCache) { - should.not.exist(err); - should.exist(txs); - txs.length.should.equal(5); - var s = h.slice(i, i + 5); - _.map(txs, 'txid').should.deep.equal(_.map(s, 'txid')); - fromCache.should.equal(false); - next(); - }); - }, function() { - async.eachSeries(_.range(0, 200, 5), function(i, next) { - - function resetCache(cb) { - if (!(i % 25)) { - storage.softResetTxHistoryCache(server.walletId, function() { - return cb(true); - }); - } else { - return cb(false); - } - } - - resetCache(function(reset) { - server.getTxHistory({ + async.eachSeries( + _.shuffle(indexes), + function(i, next) { + server.getTxHistory( + { skip: i, limit: 5, - }, function(err, txs, fromCache) { + }, + function(err, txs, fromCache) { should.not.exist(err); should.exist(txs); txs.length.should.equal(5); var s = h.slice(i, i + 5); _.map(txs, 'txid').should.deep.equal(_.map(s, 'txid')); - fromCache.should.equal(i >= Defaults.CONFIRMATIONS_TO_START_CACHING && !reset); + fromCache.should.equal(false); next(); - }); - }); - }, done); - }); + }, + ); + }, + function() { + async.eachSeries( + _.range(0, 200, 5), + function(i, next) { + function resetCache(cb) { + if (!(i % 25)) { + storage.softResetTxHistoryCache(server.walletId, function() { + return cb(true); + }); + } else { + return cb(false); + } + } + + resetCache(function(reset) { + server.getTxHistory( + { + skip: i, + limit: 5, + }, + function(err, txs, fromCache) { + should.not.exist(err); + should.exist(txs); + txs.length.should.equal(5); + var s = h.slice(i, i + 5); + _.map(txs, 'txid').should.deep.equal(_.map(s, 'txid')); + fromCache.should.equal(i >= Defaults.CONFIRMATIONS_TO_START_CACHING && !reset); + next(); + }, + ); + }); + }, + done, + ); + }, + ); }); - - }); }); @@ -6883,17 +7875,12 @@ describe('Wallet service', function() { afterEach(function() {}); it('should scan main addresses', function(done) { - helpers.stubAddressActivity( - ['1L3z9LPd861FWQhf3vDn89Fnc9dkdBo2CG', // m/0/0 - '1GdXraZ1gtoVAvBh49D4hK9xLm6SKgesoE', // m/0/2 - '1FUzgKcyPJsYwDLUEVJYeE2N3KVaoxTjGS', // m/1/0 - ]); - var expectedPaths = [ - 'm/0/0', - 'm/0/1', - 'm/0/2', - 'm/1/0', - ]; + helpers.stubAddressActivity([ + '1L3z9LPd861FWQhf3vDn89Fnc9dkdBo2CG', // m/0/0 + '1GdXraZ1gtoVAvBh49D4hK9xLm6SKgesoE', // m/0/2 + '1FUzgKcyPJsYwDLUEVJYeE2N3KVaoxTjGS', // m/1/0 + ]); + var expectedPaths = ['m/0/0', 'm/0/1', 'm/0/2', 'm/1/0']; server.scan({}, function(err) { should.not.exist(err); server.getWallet({}, function(err, wallet) { @@ -6915,17 +7902,13 @@ describe('Wallet service', function() { }); it('should not go beyond max gap', function(done) { - helpers.stubAddressActivity( - ['1L3z9LPd861FWQhf3vDn89Fnc9dkdBo2CG', // m/0/0 - '1GdXraZ1gtoVAvBh49D4hK9xLm6SKgesoE', // m/0/2 - '1DY9exavapgnCUWDnSTJe1BPzXcpgwAQC4', // m/0/5 - '1LD7Cr68LvBPTUeXrr6YXfGrogR7TVj3WQ', // m/1/3 - ]); - var expectedPaths = [ - 'm/0/0', - 'm/0/1', - 'm/0/2', - ]; + helpers.stubAddressActivity([ + '1L3z9LPd861FWQhf3vDn89Fnc9dkdBo2CG', // m/0/0 + '1GdXraZ1gtoVAvBh49D4hK9xLm6SKgesoE', // m/0/2 + '1DY9exavapgnCUWDnSTJe1BPzXcpgwAQC4', // m/0/5 + '1LD7Cr68LvBPTUeXrr6YXfGrogR7TVj3WQ', // m/1/3 + ]); + var expectedPaths = ['m/0/0', 'm/0/1', 'm/0/2']; server.scan({}, function(err) { should.not.exist(err); server.getWallet({}, function(err, wallet) { @@ -7000,45 +7983,47 @@ describe('Wallet service', function() { }); it('should restore wallet balance', function(done) { - async.waterfall([ - - function(next) { - helpers.stubUtxos(server, wallet, [1, 2, 3], function(utxos) { - should.exist(utxos); - helpers.stubAddressActivity(_.map(utxos, 'address')); - server.getBalance({}, function(err, balance) { - balance.totalAmount.should.equal(helpers.toMicro(6)); - next(null, server, wallet); + async.waterfall( + [ + function(next) { + helpers.stubUtxos(server, wallet, [1, 2, 3], function(utxos) { + should.exist(utxos); + helpers.stubAddressActivity(_.map(utxos, 'address')); + server.getBalance({}, function(err, balance) { + balance.totalAmount.should.equal(helpers.toMicro(6)); + next(null, server, wallet); + }); }); - }); - }, - function(server, wallet, next) { - server.removeWallet({}, function(err) { - next(err); - }); - }, - function(next) { - // NOTE: this works because it creates the exact same wallet! - helpers.createAndJoinWallet(1, 1, function(server, wallet) { - server.getBalance({}, function(err, balance) { - balance.totalAmount.should.equal(0); - next(null, server, wallet); + }, + function(server, wallet, next) { + server.removeWallet({}, function(err) { + next(err); }); - }); - }, - function(server, wallet, next) { - server.scan({}, function(err) { - should.not.exist(err); - server.getBalance(wallet.id, function(err, balance) { - balance.totalAmount.should.equal(helpers.toMicro(6)); - next(); - }) - }); + }, + function(next) { + // NOTE: this works because it creates the exact same wallet! + helpers.createAndJoinWallet(1, 1, function(server, wallet) { + server.getBalance({}, function(err, balance) { + balance.totalAmount.should.equal(0); + next(null, server, wallet); + }); + }); + }, + function(server, wallet, next) { + server.scan({}, function(err) { + should.not.exist(err); + server.getBalance(wallet.id, function(err, balance) { + balance.totalAmount.should.equal(helpers.toMicro(6)); + next(); + }); + }); + }, + ], + function(err) { + should.not.exist(err); + done(); }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); }); it('should abort scan if there is an error checking address activity', function(done) { @@ -7062,33 +8047,32 @@ describe('Wallet service', function() { }); describe('shared wallet (BIP45)', function() { - beforeEach(function(done) { this.timeout(5000); Defaults.SCAN_ADDRESS_GAP = 2; - helpers.createAndJoinWallet(1, 2, { - supportBIP44AndP2PKH: false - }, function(s, w) { - server = s; - wallet = w; - done(); - }); + helpers.createAndJoinWallet( + 1, + 2, + { + supportBIP44AndP2PKH: false, + }, + function(s, w) { + server = s; + wallet = w; + done(); + }, + ); }); afterEach(function() {}); it('should scan main addresses', function(done) { - helpers.stubAddressActivity( - ['39AA1Y2VvPJhV3RFbc7cKbUax1WgkPwweR', // m/2147483647/0/0 - '3QX2MNSijnhCALBmUVnDo5UGPj3SEGASWx', // m/2147483647/0/2 - '3MzGaz4KKX66w8ShKaR536ZqzVvREBqqYu', // m/2147483647/1/0 - ]); - var expectedPaths = [ - 'm/2147483647/0/0', - 'm/2147483647/0/1', - 'm/2147483647/0/2', - 'm/2147483647/1/0', - ]; + helpers.stubAddressActivity([ + '39AA1Y2VvPJhV3RFbc7cKbUax1WgkPwweR', // m/2147483647/0/0 + '3QX2MNSijnhCALBmUVnDo5UGPj3SEGASWx', // m/2147483647/0/2 + '3MzGaz4KKX66w8ShKaR536ZqzVvREBqqYu', // m/2147483647/1/0 + ]); + var expectedPaths = ['m/2147483647/0/0', 'm/2147483647/0/1', 'm/2147483647/0/2', 'm/2147483647/1/0']; server.scan({}, function(err) { should.not.exist(err); server.getWallet({}, function(err, wallet) { @@ -7110,33 +8094,29 @@ describe('Wallet service', function() { }); }); it('should scan main addresses & copayer addresses', function(done) { - helpers.stubAddressActivity( - ['39AA1Y2VvPJhV3RFbc7cKbUax1WgkPwweR', // m/2147483647/0/0 - '3MzGaz4KKX66w8ShKaR536ZqzVvREBqqYu', // m/2147483647/1/0 - '3BYoynejwBH9q4Jhr9m9P5YTnLTu57US6g', // m/0/0/1 - '37Pb8c32hzm16tCZaVHj4Dtjva45L2a3A3', // m/1/1/0 - '32TB2n283YsXdseMqUm9zHSRcfS5JxTWxx', // m/1/0/0 - ]); - var expectedPaths = [ - 'm/2147483647/0/0', - 'm/2147483647/1/0', - 'm/0/0/0', - 'm/0/0/1', - 'm/1/0/0', - 'm/1/1/0', - ]; - server.scan({ - includeCopayerBranches: true - }, function(err) { - should.not.exist(err); - server.storage.fetchAddresses(wallet.id, function(err, addresses) { - should.exist(addresses); - addresses.length.should.equal(expectedPaths.length); - var paths = _.map(addresses, 'path'); - _.difference(paths, expectedPaths).length.should.equal(0); - done(); - }) - }); + helpers.stubAddressActivity([ + '39AA1Y2VvPJhV3RFbc7cKbUax1WgkPwweR', // m/2147483647/0/0 + '3MzGaz4KKX66w8ShKaR536ZqzVvREBqqYu', // m/2147483647/1/0 + '3BYoynejwBH9q4Jhr9m9P5YTnLTu57US6g', // m/0/0/1 + '37Pb8c32hzm16tCZaVHj4Dtjva45L2a3A3', // m/1/1/0 + '32TB2n283YsXdseMqUm9zHSRcfS5JxTWxx', // m/1/0/0 + ]); + var expectedPaths = ['m/2147483647/0/0', 'm/2147483647/1/0', 'm/0/0/0', 'm/0/0/1', 'm/1/0/0', 'm/1/1/0']; + server.scan( + { + includeCopayerBranches: true, + }, + function(err) { + should.not.exist(err); + server.storage.fetchAddresses(wallet.id, function(err, addresses) { + should.exist(addresses); + addresses.length.should.equal(expectedPaths.length); + var paths = _.map(addresses, 'path'); + _.difference(paths, expectedPaths).length.should.equal(0); + done(); + }); + }, + ); }); }); }); @@ -7147,30 +8127,30 @@ describe('Wallet service', function() { this.timeout(5000); Defaults.SCAN_ADDRESS_GAP = 2; - helpers.createAndJoinWallet(1, 1, { - supportBIP44AndP2PKH: false - }, function(s, w) { - server = s; - wallet = w; - done(); - }); + helpers.createAndJoinWallet( + 1, + 1, + { + supportBIP44AndP2PKH: false, + }, + function(s, w) { + server = s; + wallet = w; + done(); + }, + ); }); afterEach(function() { server.messageBroker.removeAllListeners(); }); it('should start an asynchronous scan', function(done) { - helpers.stubAddressActivity( - ['3GvvHimEMk2GBZnPxTF89GHZL6QhZjUZVs', // m/2147483647/0/0 - '37pd1jjTUiGBh8JL2hKLDgsyrhBoiz5vsi', // m/2147483647/0/2 - '3C3tBn8Sr1wHTp2brMgYsj9ncB7R7paYuB', // m/2147483647/1/0 - ]); - var expectedPaths = [ - 'm/2147483647/0/0', - 'm/2147483647/0/1', - 'm/2147483647/0/2', - 'm/2147483647/1/0', - ]; + helpers.stubAddressActivity([ + '3GvvHimEMk2GBZnPxTF89GHZL6QhZjUZVs', // m/2147483647/0/0 + '37pd1jjTUiGBh8JL2hKLDgsyrhBoiz5vsi', // m/2147483647/0/2 + '3C3tBn8Sr1wHTp2brMgYsj9ncB7R7paYuB', // m/2147483647/1/0 + ]); + var expectedPaths = ['m/2147483647/0/0', 'm/2147483647/0/1', 'm/2147483647/0/2', 'm/2147483647/1/0']; server.messageBroker.onMessage(function(n) { if (n.type == 'ScanFinished') { server.getWallet({}, function(err, wallet) { @@ -7188,7 +8168,7 @@ describe('Wallet service', function() { address.path.should.equal('m/2147483647/0/0'); // it takes first address in case singleAddress = true done(); }); - }) + }); }); } }); @@ -7273,10 +8253,12 @@ describe('Wallet service', function() { it('should create a paypro tx', function(done) { helpers.stubUtxos(server, wallet, [1, 2], function() { var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 0.8e8 - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 0.8e8, + }, + ], feePerKb: 100e2, message: 'some message', customData: 'some custom data', @@ -7305,105 +8287,128 @@ describe('Wallet service', function() { it('should subscribe copayer to push notifications service', function(done) { helpers.getAuthServer(wallet.copayers[0].id, function(server) { should.exist(server); - server.pushNotificationsSubscribe({ - token: 'DEVICE_TOKEN', - packageName: 'com.wallet', - platform: 'Android', - }, function(err) { - should.not.exist(err); - server.storage.fetchPushNotificationSubs(wallet.copayers[0].id, function(err, subs) { - should.not.exist(err); - should.exist(subs); - subs.length.should.equal(1); - var s = subs[0]; - s.token.should.equal('DEVICE_TOKEN'); - s.packageName.should.equal('com.wallet'); - s.platform.should.equal('Android') - done(); - }); - }); - }); - }); - it('should allow multiple subscriptions for the same copayer', function(done) { - helpers.getAuthServer(wallet.copayers[0].id, function(server) { - should.exist(server); - server.pushNotificationsSubscribe({ - token: 'DEVICE_TOKEN', - packageName: 'com.wallet', - platform: 'Android', - }, function(err) { - server.pushNotificationsSubscribe({ - token: 'DEVICE_TOKEN2', - packageName: 'com.my-other-wallet', - platform: 'iOS', - }, function(err) { + server.pushNotificationsSubscribe( + { + token: 'DEVICE_TOKEN', + packageName: 'com.wallet', + platform: 'Android', + }, + function(err) { should.not.exist(err); server.storage.fetchPushNotificationSubs(wallet.copayers[0].id, function(err, subs) { should.not.exist(err); should.exist(subs); - subs.length.should.equal(2); + subs.length.should.equal(1); + var s = subs[0]; + s.token.should.equal('DEVICE_TOKEN'); + s.packageName.should.equal('com.wallet'); + s.platform.should.equal('Android'); done(); }); - }); - }); + }, + ); }); }); - - it('should unsubscribe copayer to push notifications service', function(done) { + it('should allow multiple subscriptions for the same copayer', function(done) { helpers.getAuthServer(wallet.copayers[0].id, function(server) { should.exist(server); - async.series([ - - function(next) { - server.pushNotificationsSubscribe({ - token: 'DEVICE_TOKEN', - packageName: 'com.wallet', - platform: 'Android', - }, next); - }, - function(next) { - server.pushNotificationsSubscribe({ - token: 'DEVICE_TOKEN2', - packageName: 'com.my-other-wallet', - platform: 'iOS', - }, next); - }, - function(next) { - server.pushNotificationsUnsubscribe({ - token: 'DEVICE_TOKEN2' - }, next); - }, - function(next) { - server.storage.fetchPushNotificationSubs(wallet.copayers[0].id, function(err, subs) { - should.not.exist(err); - should.exist(subs); - subs.length.should.equal(1); - var s = subs[0]; - s.token.should.equal('DEVICE_TOKEN'); - next(); - }); + server.pushNotificationsSubscribe( + { + token: 'DEVICE_TOKEN', + packageName: 'com.wallet', + platform: 'Android', }, - function(next) { - helpers.getAuthServer(wallet.copayers[1].id, function(server) { - server.pushNotificationsUnsubscribe({ - token: 'DEVICE_TOKEN' - }, next); - }); + function(err) { + server.pushNotificationsSubscribe( + { + token: 'DEVICE_TOKEN2', + packageName: 'com.my-other-wallet', + platform: 'iOS', + }, + function(err) { + should.not.exist(err); + server.storage.fetchPushNotificationSubs(wallet.copayers[0].id, function(err, subs) { + should.not.exist(err); + should.exist(subs); + subs.length.should.equal(2); + done(); + }); + }, + ); }, - function(next) { - server.storage.fetchPushNotificationSubs(wallet.copayers[0].id, function(err, subs) { - should.not.exist(err); - should.exist(subs); - subs.length.should.equal(1); - var s = subs[0]; - s.token.should.equal('DEVICE_TOKEN'); - next(); - }); + ); + }); + }); + + it('should unsubscribe copayer to push notifications service', function(done) { + helpers.getAuthServer(wallet.copayers[0].id, function(server) { + should.exist(server); + async.series( + [ + function(next) { + server.pushNotificationsSubscribe( + { + token: 'DEVICE_TOKEN', + packageName: 'com.wallet', + platform: 'Android', + }, + next, + ); + }, + function(next) { + server.pushNotificationsSubscribe( + { + token: 'DEVICE_TOKEN2', + packageName: 'com.my-other-wallet', + platform: 'iOS', + }, + next, + ); + }, + function(next) { + server.pushNotificationsUnsubscribe( + { + token: 'DEVICE_TOKEN2', + }, + next, + ); + }, + function(next) { + server.storage.fetchPushNotificationSubs(wallet.copayers[0].id, function(err, subs) { + should.not.exist(err); + should.exist(subs); + subs.length.should.equal(1); + var s = subs[0]; + s.token.should.equal('DEVICE_TOKEN'); + next(); + }); + }, + function(next) { + helpers.getAuthServer(wallet.copayers[1].id, function(server) { + server.pushNotificationsUnsubscribe( + { + token: 'DEVICE_TOKEN', + }, + next, + ); + }); + }, + function(next) { + server.storage.fetchPushNotificationSubs(wallet.copayers[0].id, function(err, subs) { + should.not.exist(err); + should.exist(subs); + subs.length.should.equal(1); + var s = subs[0]; + s.token.should.equal('DEVICE_TOKEN'); + next(); + }); + }, + ], + function(err) { + should.not.exist(err); + done(); }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); }); }); }); @@ -7421,94 +8426,117 @@ describe('Wallet service', function() { it('should subscribe copayer to a tx confirmation', function(done) { helpers.getAuthServer(wallet.copayers[0].id, function(server) { should.exist(server); - server.txConfirmationSubscribe({ - txid: '123', - }, function(err) { - should.not.exist(err); - server.storage.fetchActiveTxConfirmationSubs(wallet.copayers[0].id, function(err, subs) { - should.not.exist(err); - should.exist(subs); - subs.length.should.equal(1); - var s = subs[0]; - s.txid.should.equal('123'); - s.isActive.should.be.true; - done(); - }); - }); - }); - }); - it('should overwrite last subscription', function(done) { - helpers.getAuthServer(wallet.copayers[0].id, function(server) { - should.exist(server); - server.txConfirmationSubscribe({ - txid: '123', - }, function(err) { - server.txConfirmationSubscribe({ + server.txConfirmationSubscribe( + { txid: '123', - }, function(err) { + }, + function(err) { should.not.exist(err); server.storage.fetchActiveTxConfirmationSubs(wallet.copayers[0].id, function(err, subs) { should.not.exist(err); should.exist(subs); subs.length.should.equal(1); + var s = subs[0]; + s.txid.should.equal('123'); + s.isActive.should.be.true; done(); }); - }); - }); + }, + ); }); }); - - it('should unsubscribe copayer to the specified tx', function(done) { + it('should overwrite last subscription', function(done) { helpers.getAuthServer(wallet.copayers[0].id, function(server) { should.exist(server); - async.series([ - - function(next) { - server.txConfirmationSubscribe({ - txid: '123', - }, next); - }, - function(next) { - server.txConfirmationSubscribe({ - txid: '456', - }, next); - }, - function(next) { - server.txConfirmationUnsubscribe({ - txid: '123', - }, next); - }, - function(next) { - server.storage.fetchActiveTxConfirmationSubs(wallet.copayers[0].id, function(err, subs) { - should.not.exist(err); - should.exist(subs); - subs.length.should.equal(1); - var s = subs[0]; - s.txid.should.equal('456'); - next(); - }); + server.txConfirmationSubscribe( + { + txid: '123', }, - function(next) { - helpers.getAuthServer(wallet.copayers[1].id, function(server) { - server.txConfirmationUnsubscribe({ - txid: '456' - }, next); - }); + function(err) { + server.txConfirmationSubscribe( + { + txid: '123', + }, + function(err) { + should.not.exist(err); + server.storage.fetchActiveTxConfirmationSubs(wallet.copayers[0].id, function(err, subs) { + should.not.exist(err); + should.exist(subs); + subs.length.should.equal(1); + done(); + }); + }, + ); }, - function(next) { - server.storage.fetchActiveTxConfirmationSubs(wallet.copayers[0].id, function(err, subs) { - should.not.exist(err); - should.exist(subs); - subs.length.should.equal(1); - var s = subs[0]; - s.txid.should.equal('456'); - next(); - }); + ); + }); + }); + + it('should unsubscribe copayer to the specified tx', function(done) { + helpers.getAuthServer(wallet.copayers[0].id, function(server) { + should.exist(server); + async.series( + [ + function(next) { + server.txConfirmationSubscribe( + { + txid: '123', + }, + next, + ); + }, + function(next) { + server.txConfirmationSubscribe( + { + txid: '456', + }, + next, + ); + }, + function(next) { + server.txConfirmationUnsubscribe( + { + txid: '123', + }, + next, + ); + }, + function(next) { + server.storage.fetchActiveTxConfirmationSubs(wallet.copayers[0].id, function(err, subs) { + should.not.exist(err); + should.exist(subs); + subs.length.should.equal(1); + var s = subs[0]; + s.txid.should.equal('456'); + next(); + }); + }, + function(next) { + helpers.getAuthServer(wallet.copayers[1].id, function(server) { + server.txConfirmationUnsubscribe( + { + txid: '456', + }, + next, + ); + }); + }, + function(next) { + server.storage.fetchActiveTxConfirmationSubs(wallet.copayers[0].id, function(err, subs) { + should.not.exist(err); + should.exist(subs); + subs.length.should.equal(1); + var s = subs[0]; + s.txid.should.equal('456'); + next(); + }); + }, + ], + function(err) { + should.not.exist(err); + done(); }, - ], function(err) { - should.not.exist(err); - done(); - }); + ); }); }); }); @@ -7524,61 +8552,75 @@ describe('Wallet service', function() { }); it('should get wallet from id', function(done) { - server.getWalletFromIdentifier({ - identifier: wallet.id - }, function(err, w) { - should.not.exist(err); - should.exist(w); - w.id.should.equal(wallet.id); - done(); - }); + server.getWalletFromIdentifier( + { + identifier: wallet.id, + }, + function(err, w) { + should.not.exist(err); + should.exist(w); + w.id.should.equal(wallet.id); + done(); + }, + ); }); it('should get wallet from address', function(done) { server.createAddress({}, function(err, address) { should.not.exist(err); should.exist(address); - server.getWalletFromIdentifier({ - identifier: address.address - }, function(err, w) { - should.not.exist(err); - should.exist(w); - w.id.should.equal(wallet.id); - done(); - }); + server.getWalletFromIdentifier( + { + identifier: address.address, + }, + function(err, w) { + should.not.exist(err); + should.exist(w); + w.id.should.equal(wallet.id); + done(); + }, + ); }); }); it('should get wallet from tx proposal', function(done) { helpers.stubUtxos(server, wallet, '1 mrt', function() { helpers.stubBroadcast(); var txOpts = { - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 1000e2 - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 1000e2, + }, + ], feePerKb: 100e2, message: 'some message', }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(txp) { should.exist(txp); var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_44H_0H_0H); - server.signTx({ - txProposalId: txp.id, - signatures: signatures, - }, function(err) { - should.not.exist(err); - server.getPendingTxs({}, function(err, txps) { + server.signTx( + { + txProposalId: txp.id, + signatures: signatures, + }, + function(err) { should.not.exist(err); - txp = txps[0]; - server.getWalletFromIdentifier({ - identifier: txp.txid - }, function(err, w) { + server.getPendingTxs({}, function(err, txps) { should.not.exist(err); - should.exist(w); - w.id.should.equal(wallet.id); - done(); + txp = txps[0]; + server.getWalletFromIdentifier( + { + identifier: txp.txid, + }, + function(err, w) { + should.not.exist(err); + should.exist(w); + w.id.should.equal(wallet.id); + done(); + }, + ); }); - }); - }); + }, + ); }); }); }); @@ -7588,31 +8630,39 @@ describe('Wallet service', function() { should.exist(address); blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, null, { txid: '999', - vout: [{ - scriptPubKey: { - addresses: [address.address] - } - }], - }); - server.getWalletFromIdentifier({ - identifier: '999' - }, function(err, w) { - should.not.exist(err); - should.exist(w); - w.id.should.equal(wallet.id); - done(); + vout: [ + { + scriptPubKey: { + addresses: [address.address], + }, + }, + ], }); + server.getWalletFromIdentifier( + { + identifier: '999', + }, + function(err, w) { + should.not.exist(err); + should.exist(w); + w.id.should.equal(wallet.id); + done(); + }, + ); }); }); it('should return nothing if identifier not associated with a wallet', function(done) { blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, null, null); - server.getWalletFromIdentifier({ - identifier: 'dummy' - }, function(err, w) { - should.not.exist(err); - should.not.exist(w); - done(); - }); + server.getWalletFromIdentifier( + { + identifier: 'dummy', + }, + function(err, w) { + should.not.exist(err); + should.not.exist(w); + done(); + }, + ); }); }); }); diff --git a/packages/merit-wallet-service/test/locallock.js b/packages/merit-wallet-service/test/locallock.js index 5604511dda..70bbd2e8e5 100644 --- a/packages/merit-wallet-service/test/locallock.js +++ b/packages/merit-wallet-service/test/locallock.js @@ -6,7 +6,6 @@ var sinon = require('sinon'); var should = chai.should(); var Lock = require('../lib/locallock'); - describe('Local locks', function() { var lock; beforeEach(function() { @@ -103,9 +102,8 @@ describe('Local locks', function() { }); i.should.equal(1); this.clock.tick(4); - i.should.equal(2) + i.should.equal(2); this.clock.tick(7); - i.should.equal(3) + i.should.equal(3); }); - }); diff --git a/packages/merit-wallet-service/test/meritnode.js b/packages/merit-wallet-service/test/meritnode.js index 6052dff762..5c3a15f5d2 100644 --- a/packages/merit-wallet-service/test/meritnode.js +++ b/packages/merit-wallet-service/test/meritnode.js @@ -13,18 +13,18 @@ describe('Merit Node Service', function() { https: true, httpsOptions: { key: 'key', - cert: 'cert' - } + cert: 'cert', + }, }; var options = { - node: node + node: node, }; var service = new Service(options); service.node.should.equal(node); service.https.should.equal(true); service.httpsOptions.should.deep.equal({ key: 'key', - cert: 'cert' + cert: 'cert', }); service.bwsPort.should.equal(3232); service.messageBrokerPort.should.equal(3380); @@ -37,14 +37,14 @@ describe('Merit Node Service', function() { https: true, httpsOptions: { key: 'key', - cert: 'cert' - } + cert: 'cert', + }, }; var service = new Service(options); service.https.should.equal(true); service.httpsOptions.should.deep.equal({ key: 'key', - cert: 'cert' + cert: 'cert', }); service.bwsPort.should.equal(3232); service.messageBrokerPort.should.equal(3380); @@ -56,7 +56,7 @@ describe('Merit Node Service', function() { node: node, bwsPort: 1000, messageBrokerPort: 1001, - lockerPort: 1002 + lockerPort: 1002, }; var service = new Service(options); service.bwsPort.should.equal(1000); @@ -69,8 +69,8 @@ describe('Merit Node Service', function() { fs: { readFileSync: function(arg) { return arg; - } - } + }, + }, }); it('will create server options from httpsOptions', function() { var options = { @@ -81,9 +81,9 @@ describe('Merit Node Service', function() { cert: 'cert', CAinter1: 'CAinter1', CAinter2: 'CAinter2', - CAroot: 'CAroot' - } - } + CAroot: 'CAroot', + }, + }, }; var service = new TestService(options); var serverOptions = service._readHttpsOptions(); @@ -98,42 +98,42 @@ describe('Merit Node Service', function() { it('will throw with an unknown network', function() { var options = { node: { - network: 'unknown' - } + network: 'unknown', + }, }; var service = new Service(options); (function() { service._getConfiguration(); - }).should.throw('Unknown network'); + }.should.throw('Unknown network')); }); it('livenet local insight', function() { var options = { node: { network: meritcore.Networks.livenet, - port: 3001 - } + port: 3001, + }, }; var service = new Service(options); var config = service._getConfiguration(); config.blockchainExplorerOpts.livenet.should.deep.equal({ - 'apiPrefix': '/insight-api', - 'provider': 'insight', - 'url': 'http://localhost:3001' + apiPrefix: '/insight-api', + provider: 'insight', + url: 'http://localhost:3001', }); }); it('testnet local insight', function() { var options = { node: { network: meritcore.Networks.testnet, - port: 3001 - } + port: 3001, + }, }; var service = new Service(options); var config = service._getConfiguration(); config.blockchainExplorerOpts.testnet.should.deep.equal({ - 'apiPrefix': '/insight-api', - 'provider': 'insight', - 'url': 'http://localhost:3001' + apiPrefix: '/insight-api', + provider: 'insight', + url: 'http://localhost:3001', }); }); }); @@ -147,16 +147,16 @@ describe('Merit Node Service', function() { var TestService = proxyquire('../meritnode', { '../lib/expressapp': TestExpressApp, '../lib/wsapp': TestWSApp, - 'http': { + http: { Server: sinon.stub().returns({ - listen: listen - }) - } + listen: listen, + }), + }, }); var options = { node: { - bwsPort: 3232 - } + bwsPort: 3232, + }, }; var service = new TestService(options); var config = {}; @@ -177,19 +177,19 @@ describe('Merit Node Service', function() { var TestService = proxyquire('../meritnode', { '../lib/expressapp': TestExpressApp, '../lib/wsapp': TestWSApp, - 'http': { + http: { Server: function() { arguments[0].should.equal(app); return { - listen: listen + listen: listen, }; - } - } + }, + }, }); var options = { node: { - bwsPort: 3232 - } + bwsPort: 3232, + }, }; var service = new TestService(options); var config = {}; @@ -212,21 +212,21 @@ describe('Merit Node Service', function() { arguments[0].should.equal(httpsOptions); arguments[1].should.equal(app); return { - listen: listen + listen: listen, }; }; var TestService = proxyquire('../meritnode', { '../lib/expressapp': TestExpressApp, '../lib/wsapp': TestWSApp, - 'https': { - createServer: createServer - } + https: { + createServer: createServer, + }, }); var options = { node: { https: true, - bwsPort: 3232 - } + bwsPort: 3232, + }, }; var service = new TestService(options); service._readHttpsOptions = sinon.stub().returns(httpsOptions); @@ -241,7 +241,7 @@ describe('Merit Node Service', function() { describe('#start', function(done) { it('error from configuration', function(done) { var options = { - node: {} + node: {}, }; var service = new Service(options); service._getConfiguration = function() { @@ -264,12 +264,12 @@ describe('Merit Node Service', function() { '../lib/blockchainmonitor': TestBlockchainMonitor, '../lib/emailservice': TestEmailService, 'socket.io': sinon.stub().returns({ - on: sinon.stub() + on: sinon.stub(), }), 'locker-server': TestLocker, }); var options = { - node: {} + node: {}, }; var service = new TestService(options); var config = {}; @@ -292,16 +292,16 @@ describe('Merit Node Service', function() { '../lib/blockchainmonitor': TestBlockchainMonitor, '../lib/emailservice': TestEmailService, 'socket.io': sinon.stub().returns({ - on: sinon.stub() + on: sinon.stub(), }), 'locker-server': TestLocker, }); var options = { - node: {} + node: {}, }; var service = new TestService(options); service._getConfiguration = sinon.stub().returns({ - emailOpts: {} + emailOpts: {}, }); var config = {}; service._startWalletService = sinon.stub().callsArg(1); diff --git a/packages/merit-wallet-service/test/model/address.js b/packages/merit-wallet-service/test/model/address.js index 23bcbfcdf4..17234421a6 100644 --- a/packages/merit-wallet-service/test/model/address.js +++ b/packages/merit-wallet-service/test/model/address.js @@ -33,13 +33,26 @@ describe('Address', function() { }); describe('#derive', function() { it('should derive multi-sig P2SH address', function() { - var address = Address.derive('wallet-id', 'P2SH', [{ - xPubKey: 'xpub686v8eJUJEqxzAtkWPyQ9nvpBHfucVsB8Q8HQHw5mxYPQtBact2rmA8wRXFYaVESK8f7WrxeU4ayALaEhicdXCX5ZHktNeRFnvFeffztiY1' - // PubKey(xPubKey/0/0) -> 03fe466ea829aa4c9a1c289f9ba61ebc26a61816500860c8d23f94aad9af152ecd - }, { - xPubKey: 'xpub68tpbrfk747AvDUCdtEUgK2yDPmtGKf7YXzEcUUqnF3jmAMeZgcpoZqgXwwoi8CpwDkyzVX6wxUktTw2wh9EhhVjh5S71MLL3FkZDGF5GeY' - // PubKey(xPubKey/0/0) -> 03162179906dbe6a67979d4f8f46ee1db6ff81715f465e6615a4f5969478ad2171 - }], 'm/0/0', 1, 'livenet', false); + var address = Address.derive( + 'wallet-id', + 'P2SH', + [ + { + xPubKey: + 'xpub686v8eJUJEqxzAtkWPyQ9nvpBHfucVsB8Q8HQHw5mxYPQtBact2rmA8wRXFYaVESK8f7WrxeU4ayALaEhicdXCX5ZHktNeRFnvFeffztiY1', + // PubKey(xPubKey/0/0) -> 03fe466ea829aa4c9a1c289f9ba61ebc26a61816500860c8d23f94aad9af152ecd + }, + { + xPubKey: + 'xpub68tpbrfk747AvDUCdtEUgK2yDPmtGKf7YXzEcUUqnF3jmAMeZgcpoZqgXwwoi8CpwDkyzVX6wxUktTw2wh9EhhVjh5S71MLL3FkZDGF5GeY', + // PubKey(xPubKey/0/0) -> 03162179906dbe6a67979d4f8f46ee1db6ff81715f465e6615a4f5969478ad2171 + }, + ], + 'm/0/0', + 1, + 'livenet', + false, + ); should.exist(address); address.walletId.should.equal('wallet-id'); address.address.should.equal('3QN2CiSxcUsFuRxZJwXMNDQ2esnr5RXTvw'); @@ -49,10 +62,21 @@ describe('Address', function() { address.type.should.equal('P2SH'); }); it('should derive 1-of-1 P2SH address', function() { - var address = Address.derive('wallet-id', 'P2SH', [{ - xPubKey: 'xpub686v8eJUJEqxzAtkWPyQ9nvpBHfucVsB8Q8HQHw5mxYPQtBact2rmA8wRXFYaVESK8f7WrxeU4ayALaEhicdXCX5ZHktNeRFnvFeffztiY1' - // PubKey(xPubKey/0/0) -> 03fe466ea829aa4c9a1c289f9ba61ebc26a61816500860c8d23f94aad9af152ecd - }], 'm/0/0', 1, 'livenet', false); + var address = Address.derive( + 'wallet-id', + 'P2SH', + [ + { + xPubKey: + 'xpub686v8eJUJEqxzAtkWPyQ9nvpBHfucVsB8Q8HQHw5mxYPQtBact2rmA8wRXFYaVESK8f7WrxeU4ayALaEhicdXCX5ZHktNeRFnvFeffztiY1', + // PubKey(xPubKey/0/0) -> 03fe466ea829aa4c9a1c289f9ba61ebc26a61816500860c8d23f94aad9af152ecd + }, + ], + 'm/0/0', + 1, + 'livenet', + false, + ); should.exist(address); address.walletId.should.equal('wallet-id'); address.address.should.equal('3BY4K8dfsHryhWh2MJ6XHxxsRfcvPAyseH'); @@ -62,10 +86,21 @@ describe('Address', function() { address.type.should.equal('P2SH'); }); it('should derive 1-of-1 P2PKH address', function() { - var address = Address.derive('wallet-id', 'P2PKH', [{ - xPubKey: 'xpub686v8eJUJEqxzAtkWPyQ9nvpBHfucVsB8Q8HQHw5mxYPQtBact2rmA8wRXFYaVESK8f7WrxeU4ayALaEhicdXCX5ZHktNeRFnvFeffztiY1' - // PubKey(xPubKey/1/2) -> 0232c09a6edd8e2189628132d530c038e0b15b414cf3984e532358cbcfb83a7bd7 - }], 'm/1/2', 1, 'livenet', true); + var address = Address.derive( + 'wallet-id', + 'P2PKH', + [ + { + xPubKey: + 'xpub686v8eJUJEqxzAtkWPyQ9nvpBHfucVsB8Q8HQHw5mxYPQtBact2rmA8wRXFYaVESK8f7WrxeU4ayALaEhicdXCX5ZHktNeRFnvFeffztiY1', + // PubKey(xPubKey/1/2) -> 0232c09a6edd8e2189628132d530c038e0b15b414cf3984e532358cbcfb83a7bd7 + }, + ], + 'm/1/2', + 1, + 'livenet', + true, + ); should.exist(address); address.walletId.should.equal('wallet-id'); address.address.should.equal('1G4wgi9YzmSSwQaQVLXQ5HUVquQDgJf8oT'); diff --git a/packages/merit-wallet-service/test/model/addressmanager.js b/packages/merit-wallet-service/test/model/addressmanager.js index 129be4fe51..4277e42f81 100644 --- a/packages/merit-wallet-service/test/model/addressmanager.js +++ b/packages/merit-wallet-service/test/model/addressmanager.js @@ -6,7 +6,6 @@ var sinon = require('sinon'); var should = chai.should(); var AddressManager = require('../../lib/model/addressmanager'); - describe('AddressManager', function() { describe('#create', function() { it('should create BIP45 address manager by default', function() { @@ -20,7 +19,7 @@ describe('AddressManager', function() { version: '1.0.0', receiveAddressIndex: 2, changeAddressIndex: 0, - copayerIndex: 4 + copayerIndex: 4, }; var am = AddressManager.fromObj(obj); am.derivationStrategy.should.equal('BIP45'); diff --git a/packages/merit-wallet-service/test/model/copayer.js b/packages/merit-wallet-service/test/model/copayer.js index 0a2c4571ed..6f9d211e44 100644 --- a/packages/merit-wallet-service/test/model/copayer.js +++ b/packages/merit-wallet-service/test/model/copayer.js @@ -7,9 +7,7 @@ var should = chai.should(); var Wallet = require('../../lib/model/wallet'); var Copayer = require('../../lib/model/copayer'); - describe('Copayer', function() { - describe('#fromObj', function() { it('read a copayer', function() { var c = Copayer.fromObj(testWallet.copayers[0]); @@ -32,7 +30,6 @@ describe('Copayer', function() { }); }); - var testWallet = { addressManager: { receiveAddressIndex: 0, @@ -45,57 +42,75 @@ var testWallet = { m: 2, n: 3, status: 'complete', - publicKeyRing: [{ - xPubKey: 'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9', - requestPubKey: '03814ac7decf64321a3c6967bfb746112fdb5b583531cd512cc3787eaf578947dc' - }, { - xPubKey: 'xpub661MyMwAqRbcEzHgVwwxoXksq21rRNsJsn7AFy4VD4PzsEmjjWwsyEiTjsdQviXbqZ5yHVWJR8zFUDgUKkq4R97su3UyNo36Z8hSaCPrv6o', - requestPubKey: '03fc086d2bd8b6507b1909b24c198c946e68775d745492ea4ca70adfce7be92a60' - }, { - xPubKey: 'xpub661MyMwAqRbcFXUfkjfSaRwxJbAPpzNUvTiNFjgZwDJ8sZuhyodkP24L4LvsrgThYAAwKkVVSSmL7Ts7o9EHEHPB3EE89roAra7njoSeiMd', - requestPubKey: '0246c30040eda1e36e02629ae8cd2a845fcfa947239c4c703f7ea7550d39cfb43a' - }, ], - copayers: [{ - addressManager: { - receiveAddressIndex: 0, - changeAddressIndex: 0, - copayerIndex: 0, + publicKeyRing: [ + { + xPubKey: + 'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9', + requestPubKey: '03814ac7decf64321a3c6967bfb746112fdb5b583531cd512cc3787eaf578947dc', + }, + { + xPubKey: + 'xpub661MyMwAqRbcEzHgVwwxoXksq21rRNsJsn7AFy4VD4PzsEmjjWwsyEiTjsdQviXbqZ5yHVWJR8zFUDgUKkq4R97su3UyNo36Z8hSaCPrv6o', + requestPubKey: '03fc086d2bd8b6507b1909b24c198c946e68775d745492ea4ca70adfce7be92a60', + }, + { + xPubKey: + 'xpub661MyMwAqRbcFXUfkjfSaRwxJbAPpzNUvTiNFjgZwDJ8sZuhyodkP24L4LvsrgThYAAwKkVVSSmL7Ts7o9EHEHPB3EE89roAra7njoSeiMd', + requestPubKey: '0246c30040eda1e36e02629ae8cd2a845fcfa947239c4c703f7ea7550d39cfb43a', + }, + ], + copayers: [ + { + addressManager: { + receiveAddressIndex: 0, + changeAddressIndex: 0, + copayerIndex: 0, + }, + createdOn: 1422904189, + id: '1', + name: 'copayer 1', + xPubKey: + 'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9', + requestPubKey: '03814ac7decf64321a3c6967bfb746112fdb5b583531cd512cc3787eaf578947dc', + signature: + '30440220192ae7345d980f45f908bd63ccad60ce04270d07b91f1a9d92424a07a38af85202201591f0f71dd4e79d9206d2306862e6b8375e13a62c193953d768e884b6fb5a46', + version: '1.0.0', }, - createdOn: 1422904189, - id: '1', - name: 'copayer 1', - xPubKey: 'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9', - requestPubKey: '03814ac7decf64321a3c6967bfb746112fdb5b583531cd512cc3787eaf578947dc', - signature: '30440220192ae7345d980f45f908bd63ccad60ce04270d07b91f1a9d92424a07a38af85202201591f0f71dd4e79d9206d2306862e6b8375e13a62c193953d768e884b6fb5a46', - version: '1.0.0', - }, { - addressManager: { - receiveAddressIndex: 0, - changeAddressIndex: 0, - copayerIndex: 1, + { + addressManager: { + receiveAddressIndex: 0, + changeAddressIndex: 0, + copayerIndex: 1, + }, + createdOn: 1422904189, + id: '2', + name: 'copayer 2', + xPubKey: + 'xpub661MyMwAqRbcEzHgVwwxoXksq21rRNsJsn7AFy4VD4PzsEmjjWwsyEiTjsdQviXbqZ5yHVWJR8zFUDgUKkq4R97su3UyNo36Z8hSaCPrv6o', + requestPubKey: '03fc086d2bd8b6507b1909b24c198c946e68775d745492ea4ca70adfce7be92a60', + signature: + '30440220134d13139323ba16ff26471c415035679ee18b2281bf85550ccdf6a370899153022066ef56ff97091b9be7dede8e40f50a3a8aad8205f2e3d8e194f39c20f3d15c62', + version: '1.0.0', }, - createdOn: 1422904189, - id: '2', - name: 'copayer 2', - xPubKey: 'xpub661MyMwAqRbcEzHgVwwxoXksq21rRNsJsn7AFy4VD4PzsEmjjWwsyEiTjsdQviXbqZ5yHVWJR8zFUDgUKkq4R97su3UyNo36Z8hSaCPrv6o', - requestPubKey: '03fc086d2bd8b6507b1909b24c198c946e68775d745492ea4ca70adfce7be92a60', - signature: '30440220134d13139323ba16ff26471c415035679ee18b2281bf85550ccdf6a370899153022066ef56ff97091b9be7dede8e40f50a3a8aad8205f2e3d8e194f39c20f3d15c62', - version: '1.0.0', - }, { - addressManager: { - receiveAddressIndex: 0, - changeAddressIndex: 0, - copayerIndex: 2, + { + addressManager: { + receiveAddressIndex: 0, + changeAddressIndex: 0, + copayerIndex: 2, + }, + createdOn: 1422904189, + id: '3', + name: 'copayer 3', + xPubKey: + 'xpub661MyMwAqRbcFXUfkjfSaRwxJbAPpzNUvTiNFjgZwDJ8sZuhyodkP24L4LvsrgThYAAwKkVVSSmL7Ts7o9EHEHPB3EE89roAra7njoSeiMd', + requestPubKey: '0246c30040eda1e36e02629ae8cd2a845fcfa947239c4c703f7ea7550d39cfb43a', + signature: + '304402207a4e7067d823a98fa634f9c9d991b8c42cd0f82da24f686992acf96cdeb5e387022021ceba729bf763fc8e4277f6851fc2b856a82a22b35f20d2eeb23d99c5f5a41c', + version: '1.0.0', }, - createdOn: 1422904189, - id: '3', - name: 'copayer 3', - xPubKey: 'xpub661MyMwAqRbcFXUfkjfSaRwxJbAPpzNUvTiNFjgZwDJ8sZuhyodkP24L4LvsrgThYAAwKkVVSSmL7Ts7o9EHEHPB3EE89roAra7njoSeiMd', - requestPubKey: '0246c30040eda1e36e02629ae8cd2a845fcfa947239c4c703f7ea7550d39cfb43a', - signature: '304402207a4e7067d823a98fa634f9c9d991b8c42cd0f82da24f686992acf96cdeb5e387022021ceba729bf763fc8e4277f6851fc2b856a82a22b35f20d2eeb23d99c5f5a41c', - version: '1.0.0', - }], + ], version: '1.0.0', - pubKey: '{"x":"6092daeed8ecb2212869395770e956ffc9bf453f803e700f64ffa70c97a00d80","y":"ba5e7082351115af6f8a9eb218979c7ed1f8aa94214f627ae624ab00048b8650","compressed":true}', - isTestnet: false + pubKey: + '{"x":"6092daeed8ecb2212869395770e956ffc9bf453f803e700f64ffa70c97a00d80","y":"ba5e7082351115af6f8a9eb218979c7ed1f8aa94214f627ae624ab00048b8650","compressed":true}', + isTestnet: false, }; diff --git a/packages/merit-wallet-service/test/model/txproposal.js b/packages/merit-wallet-service/test/model/txproposal.js index 09b8526bf3..fa308250ea 100644 --- a/packages/merit-wallet-service/test/model/txproposal.js +++ b/packages/merit-wallet-service/test/model/txproposal.js @@ -100,79 +100,96 @@ describe('TxProposal', function() { txp.isRejected().should.equal(true); }); }); - }); -var theXPriv = 'xprv9s21ZrQH143K2rMHbXTJmWTuFx6ssqn1vyRoZqPkCXYchBSkp5ey8kMJe84sxfXq5uChWH4gk94rWbXZt2opN9kg4ufKGvUM7HQSLjnoh7e'; -var theXPub = 'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9'; -var theSignatures = ['304402201d210f731fa8cb8473ce49554382ad5d950c963d48b173a0591f13ed8cee10ce022027b30dc3a55c46b1f977a72491d338fc14b6d13a7b1a7c5a35950d8543c1ced6']; -var theRawTx = '0100000001ab069f7073be9b491bb1ad4233a45d2e383082ccc7206df905662d6d8499e66e08000000910047304402201d210f731fa8cb8473ce49554382ad5d950c963d48b173a0591f13ed8cee10ce022027b30dc3a55c46b1f977a72491d338fc14b6d13a7b1a7c5a35950d8543c1ced6014752210319008ffe1b3e208f5ebed8f46495c056763f87b07930a7027a92ee477fb0cb0f2103b5f035af8be40d0db5abb306b7754949ab39032cf99ad177691753b37d10130152aeffffffff0380969800000000001976a91451224bca38efcaa31d5340917c3f3f713b8b20e488ac002d3101000000001976a91451224bca38efcaa31d5340917c3f3f713b8b20e488ac70f62b040000000017a914778192003f0e9e1d865c082179cc3dae5464b03d8700000000'; +var theXPriv = + 'xprv9s21ZrQH143K2rMHbXTJmWTuFx6ssqn1vyRoZqPkCXYchBSkp5ey8kMJe84sxfXq5uChWH4gk94rWbXZt2opN9kg4ufKGvUM7HQSLjnoh7e'; +var theXPub = + 'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9'; +var theSignatures = [ + '304402201d210f731fa8cb8473ce49554382ad5d950c963d48b173a0591f13ed8cee10ce022027b30dc3a55c46b1f977a72491d338fc14b6d13a7b1a7c5a35950d8543c1ced6', +]; +var theRawTx = + '0100000001ab069f7073be9b491bb1ad4233a45d2e383082ccc7206df905662d6d8499e66e08000000910047304402201d210f731fa8cb8473ce49554382ad5d950c963d48b173a0591f13ed8cee10ce022027b30dc3a55c46b1f977a72491d338fc14b6d13a7b1a7c5a35950d8543c1ced6014752210319008ffe1b3e208f5ebed8f46495c056763f87b07930a7027a92ee477fb0cb0f2103b5f035af8be40d0db5abb306b7754949ab39032cf99ad177691753b37d10130152aeffffffff0380969800000000001976a91451224bca38efcaa31d5340917c3f3f713b8b20e488ac002d3101000000001976a91451224bca38efcaa31d5340917c3f3f713b8b20e488ac70f62b040000000017a914778192003f0e9e1d865c082179cc3dae5464b03d8700000000'; var aTxpOpts = function(type) { var opts = { - message: 'some message' + message: 'some message', }; - opts.outputs = [{ - toAddress: "18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7", - amount: 10000000, - message: "first message" - }, { - toAddress: "18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7", - amount: 20000000, - message: "second message" - }, ]; + opts.outputs = [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 10000000, + message: 'first message', + }, + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 20000000, + message: 'second message', + }, + ]; return opts; }; var aTXP = function(type) { var txp = { - "version": 3, - "createdOn": 1423146231, - "id": "75c34f49-1ed6-255f-e9fd-0c71ae75ed1e", - "walletId": "1", - "creatorId": "1", - "network": "livenet", - "amount": 30000000, - "message": 'some message', - "proposalSignature": '7035022100896aeb8db75fec22fddb5facf791927a996eb3aee23ee6deaa15471ea46047de02204c0c33f42a9d3ff93d62738712a8c8a5ecd21b45393fdd144e7b01b5a186f1f9', - "changeAddress": { - "version": '1.0.0', - "createdOn": 1424372337, - "address": '3CauZ5JUFfmSAx2yANvCRoNXccZ3YSUjXH', - "path": 'm/2147483647/1/0', - "publicKeys": ['030562cb099e6043dc499eb359dd97c9d500a3586498e4bcf0228a178cc20e6f16', + version: 3, + createdOn: 1423146231, + id: '75c34f49-1ed6-255f-e9fd-0c71ae75ed1e', + walletId: '1', + creatorId: '1', + network: 'livenet', + amount: 30000000, + message: 'some message', + proposalSignature: + '7035022100896aeb8db75fec22fddb5facf791927a996eb3aee23ee6deaa15471ea46047de02204c0c33f42a9d3ff93d62738712a8c8a5ecd21b45393fdd144e7b01b5a186f1f9', + changeAddress: { + version: '1.0.0', + createdOn: 1424372337, + address: '3CauZ5JUFfmSAx2yANvCRoNXccZ3YSUjXH', + path: 'm/2147483647/1/0', + publicKeys: [ + '030562cb099e6043dc499eb359dd97c9d500a3586498e4bcf0228a178cc20e6f16', '0367027d17dbdfc27b5e31f8ed70e14d47949f0fa392261e977db0851c8b0d6fac', - '0315ae1e8aa866794ae603389fb2b8549153ebf04e7cdf74501dadde5c75ddad11' - ] + '0315ae1e8aa866794ae603389fb2b8549153ebf04e7cdf74501dadde5c75ddad11', + ], }, - "inputs": [{ - "txid": "6ee699846d2d6605f96d20c7cc8230382e5da43342adb11b499bbe73709f06ab", - "vout": 8, - "micros": 100000000, - "scriptPubKey": "a914a8a9648754fbda1b6c208ac9d4e252075447f36887", - "address": "3H4pNP6J4PW4NnvdrTg37VvZ7h2QWuAwtA", - "path": "m/2147483647/0/1", - "publicKeys": ["0319008ffe1b3e208f5ebed8f46495c056763f87b07930a7027a92ee477fb0cb0f", "03b5f035af8be40d0db5abb306b7754949ab39032cf99ad177691753b37d101301"] - }], - "inputPaths": ["m/2147483647/0/1"], - "requiredSignatures": 2, - "requiredRejections": 1, - "walletN": 2, - "addressType": "P2SH", - "status": "pending", - "actions": [], - "fee": 10000, - "outputs": [{ - "toAddress": "18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7", - "amount": 10000000, - "message": "first message" - }, { - "toAddress": "18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7", - "amount": 20000000, - "message": "second message" - }, ], - "outputOrder": [0, 1, 2] + inputs: [ + { + txid: '6ee699846d2d6605f96d20c7cc8230382e5da43342adb11b499bbe73709f06ab', + vout: 8, + micros: 100000000, + scriptPubKey: 'a914a8a9648754fbda1b6c208ac9d4e252075447f36887', + address: '3H4pNP6J4PW4NnvdrTg37VvZ7h2QWuAwtA', + path: 'm/2147483647/0/1', + publicKeys: [ + '0319008ffe1b3e208f5ebed8f46495c056763f87b07930a7027a92ee477fb0cb0f', + '03b5f035af8be40d0db5abb306b7754949ab39032cf99ad177691753b37d101301', + ], + }, + ], + inputPaths: ['m/2147483647/0/1'], + requiredSignatures: 2, + requiredRejections: 1, + walletN: 2, + addressType: 'P2SH', + status: 'pending', + actions: [], + fee: 10000, + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 10000000, + message: 'first message', + }, + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 20000000, + message: 'second message', + }, + ], + outputOrder: [0, 1, 2], }; return txp; diff --git a/packages/merit-wallet-service/test/model/wallet.js b/packages/merit-wallet-service/test/model/wallet.js index 0e4de354e0..d5588b1d9e 100644 --- a/packages/merit-wallet-service/test/model/wallet.js +++ b/packages/merit-wallet-service/test/model/wallet.js @@ -6,23 +6,21 @@ var sinon = require('sinon'); var should = chai.should(); var Wallet = require('../../lib/model/wallet'); - describe('Wallet', function() { - describe('#create', function() { it('will throw with an invalid string argument for "m" or "n"', function() { (function() { Wallet.create({ m: '2', - n: 2 + n: 2, }); - }).should.throw('Variable should be a Number.'); + }.should.throw('Variable should be a Number.')); (function() { Wallet.create({ m: 2, - n: '2' + n: '2', }); - }).should.throw('Variable should be a Number.'); + }.should.throw('Variable should be a Number.')); }); }); @@ -31,15 +29,15 @@ describe('Wallet', function() { (function() { Wallet.fromObj({ m: '2', - n: 2 + n: 2, }); - }).should.throw('Variable should be a Number.'); + }.should.throw('Variable should be a Number.')); (function() { Wallet.fromObj({ m: 2, - n: '2' + n: '2', }); - }).should.throw('Variable should be a Number.'); + }.should.throw('Variable should be a Number.')); }); it('read a wallet', function() { var w = Wallet.fromObj(testWallet); @@ -57,7 +55,6 @@ describe('Wallet', function() { }); }); - var testWallet = { addressManager: { receiveAddressIndex: 0, @@ -70,57 +67,75 @@ var testWallet = { m: 2, n: 3, status: 'complete', - publicKeyRing: [{ - xPubKey: 'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9', - requestPubKey: '03814ac7decf64321a3c6967bfb746112fdb5b583531cd512cc3787eaf578947dc' - }, { - xPubKey: 'xpub661MyMwAqRbcEzHgVwwxoXksq21rRNsJsn7AFy4VD4PzsEmjjWwsyEiTjsdQviXbqZ5yHVWJR8zFUDgUKkq4R97su3UyNo36Z8hSaCPrv6o', - requestPubKey: '03fc086d2bd8b6507b1909b24c198c946e68775d745492ea4ca70adfce7be92a60' - }, { - xPubKey: 'xpub661MyMwAqRbcFXUfkjfSaRwxJbAPpzNUvTiNFjgZwDJ8sZuhyodkP24L4LvsrgThYAAwKkVVSSmL7Ts7o9EHEHPB3EE89roAra7njoSeiMd', - requestPubKey: '0246c30040eda1e36e02629ae8cd2a845fcfa947239c4c703f7ea7550d39cfb43a' - }, ], - copayers: [{ - addressManager: { - receiveAddressIndex: 0, - changeAddressIndex: 0, - copayerIndex: 0, + publicKeyRing: [ + { + xPubKey: + 'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9', + requestPubKey: '03814ac7decf64321a3c6967bfb746112fdb5b583531cd512cc3787eaf578947dc', + }, + { + xPubKey: + 'xpub661MyMwAqRbcEzHgVwwxoXksq21rRNsJsn7AFy4VD4PzsEmjjWwsyEiTjsdQviXbqZ5yHVWJR8zFUDgUKkq4R97su3UyNo36Z8hSaCPrv6o', + requestPubKey: '03fc086d2bd8b6507b1909b24c198c946e68775d745492ea4ca70adfce7be92a60', + }, + { + xPubKey: + 'xpub661MyMwAqRbcFXUfkjfSaRwxJbAPpzNUvTiNFjgZwDJ8sZuhyodkP24L4LvsrgThYAAwKkVVSSmL7Ts7o9EHEHPB3EE89roAra7njoSeiMd', + requestPubKey: '0246c30040eda1e36e02629ae8cd2a845fcfa947239c4c703f7ea7550d39cfb43a', + }, + ], + copayers: [ + { + addressManager: { + receiveAddressIndex: 0, + changeAddressIndex: 0, + copayerIndex: 0, + }, + createdOn: 1422904189, + id: '1', + name: 'copayer 1', + xPubKey: + 'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9', + requestPubKey: '03814ac7decf64321a3c6967bfb746112fdb5b583531cd512cc3787eaf578947dc', + signature: + '30440220192ae7345d980f45f908bd63ccad60ce04270d07b91f1a9d92424a07a38af85202201591f0f71dd4e79d9206d2306862e6b8375e13a62c193953d768e884b6fb5a46', + version: '1.0.0', }, - createdOn: 1422904189, - id: '1', - name: 'copayer 1', - xPubKey: 'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9', - requestPubKey: '03814ac7decf64321a3c6967bfb746112fdb5b583531cd512cc3787eaf578947dc', - signature: '30440220192ae7345d980f45f908bd63ccad60ce04270d07b91f1a9d92424a07a38af85202201591f0f71dd4e79d9206d2306862e6b8375e13a62c193953d768e884b6fb5a46', - version: '1.0.0', - }, { - addressManager: { - receiveAddressIndex: 0, - changeAddressIndex: 0, - copayerIndex: 1, + { + addressManager: { + receiveAddressIndex: 0, + changeAddressIndex: 0, + copayerIndex: 1, + }, + createdOn: 1422904189, + id: '2', + name: 'copayer 2', + xPubKey: + 'xpub661MyMwAqRbcEzHgVwwxoXksq21rRNsJsn7AFy4VD4PzsEmjjWwsyEiTjsdQviXbqZ5yHVWJR8zFUDgUKkq4R97su3UyNo36Z8hSaCPrv6o', + requestPubKey: '03fc086d2bd8b6507b1909b24c198c946e68775d745492ea4ca70adfce7be92a60', + signature: + '30440220134d13139323ba16ff26471c415035679ee18b2281bf85550ccdf6a370899153022066ef56ff97091b9be7dede8e40f50a3a8aad8205f2e3d8e194f39c20f3d15c62', + version: '1.0.0', }, - createdOn: 1422904189, - id: '2', - name: 'copayer 2', - xPubKey: 'xpub661MyMwAqRbcEzHgVwwxoXksq21rRNsJsn7AFy4VD4PzsEmjjWwsyEiTjsdQviXbqZ5yHVWJR8zFUDgUKkq4R97su3UyNo36Z8hSaCPrv6o', - requestPubKey: '03fc086d2bd8b6507b1909b24c198c946e68775d745492ea4ca70adfce7be92a60', - signature: '30440220134d13139323ba16ff26471c415035679ee18b2281bf85550ccdf6a370899153022066ef56ff97091b9be7dede8e40f50a3a8aad8205f2e3d8e194f39c20f3d15c62', - version: '1.0.0', - }, { - addressManager: { - receiveAddressIndex: 0, - changeAddressIndex: 0, - copayerIndex: 2, + { + addressManager: { + receiveAddressIndex: 0, + changeAddressIndex: 0, + copayerIndex: 2, + }, + createdOn: 1422904189, + id: '3', + name: 'copayer 3', + xPubKey: + 'xpub661MyMwAqRbcFXUfkjfSaRwxJbAPpzNUvTiNFjgZwDJ8sZuhyodkP24L4LvsrgThYAAwKkVVSSmL7Ts7o9EHEHPB3EE89roAra7njoSeiMd', + requestPubKey: '0246c30040eda1e36e02629ae8cd2a845fcfa947239c4c703f7ea7550d39cfb43a', + signature: + '304402207a4e7067d823a98fa634f9c9d991b8c42cd0f82da24f686992acf96cdeb5e387022021ceba729bf763fc8e4277f6851fc2b856a82a22b35f20d2eeb23d99c5f5a41c', + version: '1.0.0', }, - createdOn: 1422904189, - id: '3', - name: 'copayer 3', - xPubKey: 'xpub661MyMwAqRbcFXUfkjfSaRwxJbAPpzNUvTiNFjgZwDJ8sZuhyodkP24L4LvsrgThYAAwKkVVSSmL7Ts7o9EHEHPB3EE89roAra7njoSeiMd', - requestPubKey: '0246c30040eda1e36e02629ae8cd2a845fcfa947239c4c703f7ea7550d39cfb43a', - signature: '304402207a4e7067d823a98fa634f9c9d991b8c42cd0f82da24f686992acf96cdeb5e387022021ceba729bf763fc8e4277f6851fc2b856a82a22b35f20d2eeb23d99c5f5a41c', - version: '1.0.0', - }], + ], version: '1.0.0', - pubKey: '{"x":"6092daeed8ecb2212869395770e956ffc9bf453f803e700f64ffa70c97a00d80","y":"ba5e7082351115af6f8a9eb218979c7ed1f8aa94214f627ae624ab00048b8650","compressed":true}', - isTestnet: false + pubKey: + '{"x":"6092daeed8ecb2212869395770e956ffc9bf453f803e700f64ffa70c97a00d80","y":"ba5e7082351115af6f8a9eb218979c7ed1f8aa94214f627ae624ab00048b8650","compressed":true}', + isTestnet: false, }; diff --git a/packages/merit-wallet-service/test/request-list.js b/packages/merit-wallet-service/test/request-list.js index be0eec954b..ddfa2c3579 100644 --- a/packages/merit-wallet-service/test/request-list.js +++ b/packages/merit-wallet-service/test/request-list.js @@ -13,158 +13,219 @@ describe('request-list', function() { request = sinon.stub(); }); it('should support url as string', function(done) { + request.yields( + null, + { + statusCode: 200, + }, + 'abc', + ); - request.yields(null, { - statusCode: 200 - }, 'abc'); - - prequest({ - hosts: 'url1', - request: request, - }, function(err, res, body) { - should.not.exist(err); - body.should.be.equal('abc'); - res.statusCode.should.be.equal(200); - done(); - }); + prequest( + { + hosts: 'url1', + request: request, + }, + function(err, res, body) { + should.not.exist(err); + body.should.be.equal('abc'); + res.statusCode.should.be.equal(200); + done(); + }, + ); }); it('should support url as string (500 response)', function(done) { request.yields(null, { - statusCode: 500 - }); - prequest({ - hosts: 'url1', - request: request, - }, function(err, res, body) { - should.not.exist(err); - res.statusCode.should.be.equal(500); - done(); - }); + statusCode: 500, + }); + prequest( + { + hosts: 'url1', + request: request, + }, + function(err, res, body) { + should.not.exist(err); + res.statusCode.should.be.equal(500); + done(); + }, + ); }); it('should support url as array of strings', function(done) { - request.yields(null, { - statusCode: 200 - }, 'abc'); - prequest({ - hosts: ['url1', 'url2'], - request: request, - }, function(err, res, body) { - should.not.exist(err); - body.should.be.equal('abc'); - done(); - }); + request.yields( + null, + { + statusCode: 200, + }, + 'abc', + ); + prequest( + { + hosts: ['url1', 'url2'], + request: request, + }, + function(err, res, body) { + should.not.exist(err); + body.should.be.equal('abc'); + done(); + }, + ); }); it('should try 2nd url if first is unsuccessful (5xx)', function(done) { request.onCall(0).yields(null, { - statusCode: 500 + statusCode: 500, }); request.onCall(1).yields(null, { - statusCode: 550 - }); - prequest({ - hosts: ['url1', 'url2'], - request: request, - }, function(err, res, body) { - should.not.exist(err); - res.statusCode.should.be.equal(550); - done(); - }); + statusCode: 550, + }); + prequest( + { + hosts: ['url1', 'url2'], + request: request, + }, + function(err, res, body) { + should.not.exist(err); + res.statusCode.should.be.equal(550); + done(); + }, + ); }); it('should query 3th url if first 2 are unsuccessful (5xx)', function(done) { request.onCall(0).yields(null, { - statusCode: 500 + statusCode: 500, }); request.onCall(1).yields(null, { - statusCode: 550 - }); - request.onCall(2).yields(null, { - statusCode: 200, - }, 'abc'); - prequest({ - hosts: ['url1', 'url2', 'url3'], - request: request, - }, function(err, res, body) { - should.not.exist(err); - body.should.be.equal('abc'); - done(); - }); + statusCode: 550, + }); + request.onCall(2).yields( + null, + { + statusCode: 200, + }, + 'abc', + ); + prequest( + { + hosts: ['url1', 'url2', 'url3'], + request: request, + }, + function(err, res, body) { + should.not.exist(err); + body.should.be.equal('abc'); + done(); + }, + ); }); it('should query only the first url if response is 404', function(done) { request.onCall(0).yields(null, { - statusCode: 404 + statusCode: 404, }); request.onCall(1).yields(null, { - statusCode: 550 - }); - prequest({ - hosts: ['url1', 'url2'], - request: request, - }, function(err, res, body) { - should.not.exist(err); - res.statusCode.should.be.equal(404); - done(); - }); + statusCode: 550, + }); + prequest( + { + hosts: ['url1', 'url2'], + request: request, + }, + function(err, res, body) { + should.not.exist(err); + res.statusCode.should.be.equal(404); + done(); + }, + ); }); it('should query only the first 2 urls if the second is successfull (5xx)', function(done) { request.onCall(0).yields(null, { - statusCode: 500 - }); - request.onCall(1).yields(null, { - statusCode: 200, - }, '2nd'); - request.onCall(2).yields(null, { - statusCode: 200, - }, 'abc'); - prequest({ - hosts: ['url1', 'url2', 'url3'], - request: request, - }, function(err, res, body) { - should.not.exist(err); - body.should.be.equal('2nd'); - res.statusCode.should.be.equal(200); - done(); - }); + statusCode: 500, + }); + request.onCall(1).yields( + null, + { + statusCode: 200, + }, + '2nd', + ); + request.onCall(2).yields( + null, + { + statusCode: 200, + }, + 'abc', + ); + prequest( + { + hosts: ['url1', 'url2', 'url3'], + request: request, + }, + function(err, res, body) { + should.not.exist(err); + body.should.be.equal('2nd'); + res.statusCode.should.be.equal(200); + done(); + }, + ); }); it('should query only the first 2 urls if the second is successfull (timeout)', function(done) { request.onCall(0).yields({ code: 'ETIMEDOUT', - connect: true - }); - request.onCall(1).yields(null, { - statusCode: 200, - }, '2nd'); - request.onCall(2).yields(null, { - statusCode: 200, - }, 'abc'); - prequest({ - hosts: ['url1', 'url2', 'url3'], - request: request, - }, function(err, res, body) { - should.not.exist(err); - body.should.be.equal('2nd'); - res.statusCode.should.be.equal(200); - done(); - }); - + connect: true, + }); + request.onCall(1).yields( + null, + { + statusCode: 200, + }, + '2nd', + ); + request.onCall(2).yields( + null, + { + statusCode: 200, + }, + 'abc', + ); + prequest( + { + hosts: ['url1', 'url2', 'url3'], + request: request, + }, + function(err, res, body) { + should.not.exist(err); + body.should.be.equal('2nd'); + res.statusCode.should.be.equal(200); + done(); + }, + ); }); it('should use the latest response if all requests are unsuccessfull', function(done) { request.onCall(0).yields({ code: 'ETIMEDOUT', - connect: true - }); - request.onCall(1).yields(null, { - statusCode: 505, - }, '2nd'); - request.onCall(2).yields(null, { - statusCode: 510, - }, 'abc'); - prequest({ - hosts: ['url1', 'url2', 'url3'], - request: request, - }, function(err, res, body) { - should.not.exist(err); - res.statusCode.should.be.equal(510); - done(); - }); + connect: true, + }); + request.onCall(1).yields( + null, + { + statusCode: 505, + }, + '2nd', + ); + request.onCall(2).yields( + null, + { + statusCode: 510, + }, + 'abc', + ); + prequest( + { + hosts: ['url1', 'url2', 'url3'], + request: request, + }, + function(err, res, body) { + should.not.exist(err); + res.statusCode.should.be.equal(510); + done(); + }, + ); }); }); diff --git a/packages/merit-wallet-service/test/storage.js b/packages/merit-wallet-service/test/storage.js index 6a3c830e88..864509a380 100644 --- a/packages/merit-wallet-service/test/storage.js +++ b/packages/merit-wallet-service/test/storage.js @@ -6,7 +6,7 @@ var chai = require('chai'); var sinon = require('sinon'); var should = chai.should(); var tingodb = require('tingodb')({ - memStore: true + memStore: true, }); var Storage = require('../lib/storage'); @@ -23,22 +23,20 @@ function openDb(cb) { return cb(); }; return cb(); -}; - +} function resetDb(cb) { if (!db) return cb(); db.dropDatabase(function(err) { return cb(); }); -}; - +} describe('Storage', function() { before(function(done) { openDb(function() { storage = new Storage({ - db: db + db: db, }); done(); }); @@ -66,7 +64,7 @@ describe('Storage', function() { w.m.should.equal(wallet.m); w.n.should.equal(wallet.n); done(); - }) + }); }); }); it('should not return error if wallet not found', function(done) { @@ -106,7 +104,7 @@ describe('Storage', function() { lookup.requestPubKeys[0].key.should.equal('requestPubKey 1'); lookup.requestPubKeys[0].signature.should.equal('xxx'); done(); - }) + }); }); }); it('should not return error if copayer not found', function(done) { @@ -144,10 +142,12 @@ describe('Storage', function() { proposals = _.map(_.range(4), function(i) { var tx = Model.TxProposal.create({ walletId: '123', - outputs: [{ - toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: i + 100, - }], + outputs: [ + { + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: i + 100, + }, + ], feePerKb: 100e2, creatorId: wallet.copayers[0].id, }); @@ -161,12 +161,16 @@ describe('Storage', function() { tx.txid = 'txid' + i; return tx; }); - async.each(proposals, function(tx, next) { - storage.storeTx('123', tx, next); - }, function(err) { - should.not.exist(err); - done(); - }); + async.each( + proposals, + function(tx, next) { + storage.storeTx('123', tx, next); + }, + function(err) { + should.not.exist(err); + done(); + }, + ); }); }); it('should fetch tx', function(done) { @@ -212,7 +216,7 @@ describe('Storage', function() { should.exist(txs); txs.length.should.equal(3); _.some(txs, { - id: proposals[0].id + id: proposals[0].id, }).should.be.false; done(); }); diff --git a/packages/merit-wallet-service/test/testdata.js b/packages/merit-wallet-service/test/testdata.js index 5e74bf7e09..5bd3f1f27b 100644 --- a/packages/merit-wallet-service/test/testdata.js +++ b/packages/merit-wallet-service/test/testdata.js @@ -3,254 +3,351 @@ var keyPair = { pub: '026092daeed8ecb2212869395770e956ffc9bf453f803e700f64ffa70c97a00d80', }; -var copayers = [{ - id44: '626452e5e0e35df4d9ae4d3e60653c9ae9a814f00c84dc40f5887069b18e2110', - id45: 'e7467366d5754be2b7d386c9737ab87214c26314bdc3489702e09c719be1bdb7', - xPrivKey: 'xprv9s21ZrQH143K2n4rV4AtAJFptEmd1tNMKCcSyQBCSuN5eq1dCUhcv6KQJS49joRxu8NNdFxy8yuwTtzCPNYUZvVGC7EPRm2st2cvE7oyTbB', - xPubKey: 'xpub661MyMwAqRbcFG9Kb5htXSCZSGc7RM6CgRY3mnap1Eu4XdLmk21sTtdt9iWAiL64KazU3QWrYEYSRAKgLvkMRe8JMxffDvt4AhCDzyMsnsT', - xPrivKey_45H: 'xprv9upyD5bqT9HDgybvt15zN7VZk9TyTzenFuBktJfyweXtVSr9eNYpnBWQQvzxaW8kDWLeiddLu9brYma5WdtD1Maev4aGUfJjiy9EBc1QSFg', - xPubKey_45H: 'xpub68pKcb8jHWqWuTgPz2czjFSJJBJTsTNdd87Mgh5bVz4sNFBJBus5KyptGBWgA4V6LGCi12s4Mw4S1JC2GkqX4NJ4kfQ47XqRZLbyM2DY9Jd', - xPrivKey_44H_0H_0H: 'xprv9zWRZ7CXrC4z9xA9RRBFXohmPKbyCajWaCNTHPtwNeJwTnysHG5QK7WMqpNLVtvqGxts7WNcNtqBLfdaFdCGknDPXjLKt2E2BUrPaFDqrLh', - xPubKey_44H_0H_0H: 'xpub6DVmxcjRgZdHNSEcXSiFtweVwMSTc3TMwRJ45nJYvyqvLbK1poPerupqh87rSoz27wvckb1CKnGZoLmLXSZyNGZtVd7neqSvdwJL6fceQpe', - xPrivKey_1H: 'xprv9upyD5bqT9HBkWym7TvTH3njEzTnjrtkLB2sg3DD2CxxA5hZKGee1sYJUtD8C4QaeATLXQ33TirRzRhuTGDBA6XRoYDMwfXAj1KSmGyNBio', - xPubKey_1H: 'xpub68pKcb8jHWqUy14EDVTTeBjTo2JH9KcbhPxUURcpaYVw2t2hroxtZfrnLBw1bWzBrHbEJA48QmZ8DB9gTvhphKSitC15SiYx9k2ncGh55Hq', - privKey_1H_0: 'a710be25950738a7d13637e2e09affd7f579a3479fd7cc024bd9459f8fba6659', - pubKey_1H_0: '026e3020913420a5b9425952627f0a074c9235e7a329869b322061f786e997ae0d' -}, { - id44: '842c048066e7d10ae1bbf67edccf69f2e5ff9a754d0c2b5524f0d01a87d6acbb', - id45: 'ee75154b646277c8d0d256fc1a0aa0470e4c3435497f208092c865737040b55b', - xPrivKey: 'xprv9s21ZrQH143K3BwkLceWNLUsgES15JoZuv8BZfnmDRcCGtDooUAPhY8KovhCWcRLXUun5AYL5vVtUNRrmPEibtfk9ongxAGLXZzEHifpvwZ', - xPubKey: 'xpub661MyMwAqRbcFg2DSeBWjURcEGGVUmXRH93nN4CNmm9B9gYxM1UeFLSofD6gtMnRYeucgPjfrWNxaAEhiT4di6HLty8Un6aheCKev4REvhZ', - xPrivKey_45H: 'xprv9uHco76yN7arptqnjGr7LiC9VqvXhTYjYeZ4k9MU6kfrX8zBme1gRM2jbBxxt3zfeKBkmpQK4FQ2XFXXkJd2rBE2qoPdMjfC4xvxJ8iqqPW', - xPubKey_45H: 'xpub68GyCcdsCV9A3NvFqJP7hr8t3sm26vGausUfYXm5f6CqPwKLKBKvy9MDSUA6ot6WMzXCWFyWCFfZyhcqK4uZGPZL83rKW9KfuGLPJ6P38Ex', - xPrivKey_44H_0H_0H: 'xprv9yBDgTV58cC2XLCp3bGpe6tvmVHxJdE2GTkqM64TUjgRdp4vBnaF4QoMrsz3BjmFQDEx4nPaC4tfk7GUrNFpJZmQgxvp1H7FoveXA7rAPqH', - xPubKey_44H_0H_0H: 'xpub6CAa5y1xxykKjpHH9coq1EqfKX8Si5wsdggS9UU535DQWcQ4jKtVcD7qi9TCvhV31N3QCLdEaftLjNdXv8R72XiorEnrTfn1ULjA35RgQVp', - xPrivKey_1H: 'xprv9uHco76yN7aptKFWZW9Cc9KQhwDbFMDeK1C5jBTrN8JKUinAzAZt9G7fL5rcDBQYtXWT7umm4r91tx3kJRZKPKVkd35dzgfwMBLUxBHneAY', - xPubKey_1H: 'xpub68GyCcdsCV986oKyfXgCyHG9Fy45eowVgE7gXZsTvTqJMX7KXht8h4S9BLnHyWx8YbT8kRX5v4xnZAZvHmdUSdQhvZ2q97PG8m8Ef86yjzK', - privKey_1H_0: 'ee062ce6dc5ece50e8110646b5e858c98dba9315cdfdd19da85ab0d33dcac74a', - pubKey_1H_0: '02c679bf169233a273dec87fae5a1830481866c4e96a350d56346ac267808c905d' -}, { - id44: '719f4ee61c691fbf0ebefa34e2151a1a3dbe39cf2fa4a498cb6af53600d30d1a', - id45: 'acd666d7c677d9f2c85b55a5fad1610fe272eac46ef7a577c7aeeab0b1474e43', - xPrivKey: 'xprv9s21ZrQH143K3xgLzxd6SuWqG5Zp1iUmyGgSsJVhdQNeTzAqBFvXXLZqZzFZqocTx4HD9vUVYU27At5i8q46LmBXXL97fo4H9C3tHm4BnjY', - xPubKey: 'xpub661MyMwAqRbcGSkp6zA6p3TZp7QJRBCdLVc3fguKBjudLnVyioEn58tKRFPmGMkdGJWMX69mgZWHKrKmpQ3fwBXeFjLc5Sd2rnxcQthSW42', - xPrivKey_45H: 'xprv9vGShhcT8rDFomkiF72D5UXt5BsVydntE7rYbKaa9qtscnWVHaZSPkV9N9SkDkhWbDvkmTGVLYKJf23Z8QjXMRRMTwQYLj26VkPbsKxnUwV', - xPubKey_45H: 'xpub69Fo7D9LyDmZ2FqBM8ZDScUcdDhzP6WjbLn9PhzBiBRrVaqdq7sgwYodDPUzXyGxpEfTCQyTAA9baAwCApmTiing2S7KTQTmLZjw3Wmaojn', - xPrivKey_44H_0H_0H: 'xprv9yVpGpTwwtc5aNLkACpuAWmyBUZy1hYy22WQ58Cx614fM7oHpYyjrWbYbExMtZa3sTTywU9mziYBoSZtR4rXVhvfvoVmqZPsYysvpYNUDrk', - xPubKey_44H_0H_0H: 'xpub6CVAgKzqnGANnrRDGEMuXeihjWQTRAGpPFRzsWcZeLbeDv8SN6HzQJv2SWxg2QSQ7GABwgZJb9KzK8yTXB44CRkqy3cMGEEzniWvBKRCGr5', - xPrivKey_1H: 'xprv9vGShhcT8rDDu2FvheGgrGvcg5JLQce7kXqC2VnhyYdnggErZA2KJjDwSvQhFZtBVH8T7QQd7JTDXVSvgEijvoYdvCeoRyjQL5EnHRUZgre', - xPubKey_1H: 'xpub69Fo7D9LyDmX7WLPofohDQsME78pp5My7kknptCKXtAmZUa16hLZrXYRJCL7wLWtTWzMvEn1HKQ8uzp4iLbkS72WPJsLTLayGPw7HGh6hEW', - privKey_1H_0: '5009c8488e9a364fc24a999d99a81ae955271de1d06d46c2f2f09e20c6281b04', - pubKey_1H_0: '03338a3b7c08e9d9832e1baff0758e08f9cc691497dd6e91d4c191cd960fb2f043' -}, { - id44: 'e225a29864060823df67b98432b070a40aad1bf9af517005b0b5fe09c96e29c9', - id45: 'c65a89f64794cb7e1886c7010a32dd6fa362d3e81710bac32e97e325b9109fd8', - xPrivKey: 'xprv9s21ZrQH143K48nfuK14gKJtML7eQzV2dAH1RaqAMj8v2zs79uaavA9UTWMxpBdgbMH2mhJLeKGq8AFA6GDnFyWP4rLmknqZAfgFFV718vo', - xPubKey: 'xpub661MyMwAqRbcGcs91LY53TFcuMx8pTCszPCcDyEmv4ftuoCFhStqTxTxJoy35yjp2H3qQtxDYGe1gtkZu4T7mR7ARK1MLYte2fptZVt6hkD', - xPrivKey_45H: 'xprv9vYQ7HC96LzvDwJ2r99m4ALTEtXTfUCHPbs7gpPzWboFP3NFgzMjXPf9Pp7D3vmTUqRtsZfSfVghvUhLKGGAs3LdVf9rf89TgRAvqAWMSwN', - xPubKey_45H: 'xpub69XkWnj2viZDSRNVxAgmRJHBnvMx4vv8kpniVCoc4wLEFqhQEXfz5BydF79LoErgaokMLv7u2sRNsoiJqjr5nyfBqJGykfR3kvCex7z8Ar3', - xPrivKey_44H_0H_0H: 'xprv9yn1LP3ViLTXUYgZP5sDFG94H6sd8v5AKRBbd35Ub5FjPq2HuzC9bAb6LReTXRSA4XTtYvzwpiktvuRrLY98df2KZMCuyZxXUB7FpBQ2ndA', - xPubKey_44H_0H_0H: 'xpub6CmMjtaPYi1ph2m2V7QDcQ5nq8i7YNo1ge7CRRV69QniGdMSTXWQ8xuaBiNt74nJCMZjaeNgRbMiZmdgrEqogvjARnBx8k4y853MZGAkjmo', - xPrivKey_1H: 'xprv9vYQ7HC96LztKQouECporZgezbjktKyhipWavsJvEJ4ok577RxVcmnyeRUUbAqmq5FnuhDie62Z962xNvF9JwAXoJZx2VeJPUWMPHsuoAkM', - xPubKey_1H: 'xpub69XkWnj2viZBXttNLEMpDhdPYdaFHnhZ63SBjFiXndbncsSFyVosKbJ8GjGMT7LX1rF6aisHM2YmFKye7bR3xQn5Bj875iGxyVrbRF7k5N8', - privKey_1H_0: '460ee692f05de66b5d8e2fa1d005a8b6bdb1442e2ce6b3facfcee2f9012c9474', - pubKey_1H_0: '03d0e0c526619b158aac9a8de8082f439df43d389ec50cb54386c3d87cfde4c99b' -}, { - id44: '120416cd4c427a7e4d94213cebe242f56a06bc6dd5c5c6cae27dc920a0ddf1fb', - id45: '65ae087eb9efdc7e0ada3a7ef954285e9e5ba4b8c7ab2d36747ddd286f7a334f', - xPrivKey: 'xprv9s21ZrQH143K44Bb9G3EVNmLfAUKjTBAA2YtKxF4zc8SLV1o15JBoddhGHE9PGLXePMbEsSjCCvTvP3fUv6yMXZrnHigBboRBn2DmNoJkJg', - xPubKey: 'xpub661MyMwAqRbcGYG4FHaErWi5DCJp8uu1XFUV8LegYwfRDHLwYccSMRxB7Z3L1NgKychKdXQvbVEyDhSwNnNnnNKh9mBEAdQ5tv2guK8ywKU', - xPrivKey_45H: 'xprv9vKBPQfZS4jWfLtSAoSeBHdLU1yJicKVmhTdbewKwQWU2CPdm61scXvKXHaMshmDEBaspUc994GAzZK1x7PtfzZ2PGtGHHhJhDn3yoT8gAi', - xPubKey_45H: 'xpub69JXnvCTGSHospxuGpyeYRa523oo853M8vPEQ3LwVk3StzinJdL8ALEoNa8AwwJsAWrfFtwfDgTCB9o1kKwn9n2tdN9nbdrw2zs5rNqQpM2', - xPrivKey_44H_0H_0H: 'xprv9xuBGYz7dmjgyroeDKMKyjSCiWyqskWavGjLPJbC9W32TkTy8NqXX4y5WQKcK24SnGiDMpUhFUNqjh284RjHoNYC2gUKagKfVfWZqn1gey4', - xPubKey_44H_0H_0H: 'xpub6BtXg4X1U9HzCLt7KLtLLsNwGYpLHDESHVewBgzohqa1LYo7fv9n4sHZMdzdBh5pxiAgLyUvsAqAQ5J1CRK4uA9htCWbKbVxFsfMEij3MDA', - xPrivKey_1H: 'xprv9vKBPQfZS4jUjK546Cjyf8ZgtEvRhQyjfuE89DAnYatevTusA8wwXiDxEFPSFk4fp8wwC5nRGmkSnTi9ascW9LJjujm2g36eGocNMtEsDwX', - xPubKey_1H: 'xpub69JXnvCTGSHmwo9XCEGz2GWRSGkv6shb389iwbaQ6vRdoGF1hgGC5WYS5YhxaM6RpfzsbPJqfR7iCLdEMSMUYvhaG4tvmEsn8ztwtysjgp8', - privKey_1H_0: '7a5158b92d9ed4cb9644ddbd472b43428832a5f3bb91a481532a081908e62b2e', - pubKey_1H_0: '02b47d5c977c93c883f369165ebc2b564d14a52712ec6892f7097fa99e0d36ca20' -}, { - id44: '85de9f025ee190fab7cb1bd9b6772c64df26188ce705d4f258c5adaf7bc610f9', - id45: 'dacc5c350cef4449a3ca12939711c7449d0d6189e5e7f33cff60095a7a29b0f9', - xPrivKey: 'xprv9s21ZrQH143K48PpVxrh71KdViTFhAaiDSVtNFkmbWNYjwwwPbTrcqoVXsgBfue3Gq9b71hQeEbk67JgtTBcpYgKLF8pTwVnGz56f1BaCYt', - xPubKey: 'xpub661MyMwAqRbcGcUHbzPhU9GN3kHk6dJZafRVAeAP9quXckH5w8n7Ae7yP8e2Zh6SPPKFn2K6oE3GBpcz9QzfJTNRWXbY7w1L3nGLE5beZL1', - xPrivKey_45H: 'xprv9u8SxxhEJB4pzk6P3VKwmRRFqgHX94kBHDTBDaFXeaMS7dggkQcf2Tt14AvTvMJYjpogB2bVgmkHEW4Ze1iVzZeF5S5FLj6zpqwyrwh9yRW', - xPubKey_45H: 'xpub687oNUE88Yd8DEAr9Wrx8ZMzPi81YXU2eSNn1xf9CutQzS1qHwvuaGCUuTHJXkvzrRSiRtuJid3LsPaS3hUAdahdy3ZpQCcsLEQjC2Q2tNT', - xPrivKey_44H_0H_0H: 'xprv9yTxyEKAvyMLaocWZ4rXUUC7xWUqzhcvDJc2Ms7fndKaSfityJdaGrhLCSsLZz2E9NG3VkhbbsYwZVW9J5W3BQegyWWNsuEKmkdCsr9DRkM', - xPubKey_44H_0H_0H: 'xpub6CTKNjr4mLudoHgyf6PXqc8rWYKLQALmaXXdAFXHLxrZKU43Wqwppf1p3kj8sC9b9Sx5uqXfnATdvz5jeFYKELnngksCzwABLfNcW8CPkfg', - xPrivKey_1H: 'xprv9u8SxxhEJB4o6KfWV3csVTsJzhePBtMz8CmJCcn83vaWSiydgv6CADdbxjq3YsnusKPyPw1G235KibW67VjdbJ2ZoTG4nFA6ivwPRBmScKW', - xPubKey_1H: 'xpub687oNUE88Yd6Jojyb59srbp3YjUsbM5qVRgu11BjcG7VKXJnETQSi1x5p3onkhodzQcydFLTkZ3ym35UmAAWrjLY4rDAt2RjHKidx6AzgVz', - privKey_1H_0: '3c49816d4e83d8758f89e8e104e3566a8a61426a9b7d4945b34212fbbb8e8290', - pubKey_1H_0: '0307ab8c0d8eea1fe3c3781050a69e71f9e7c8cc8476a77103e08a461506a0e780' -}, { - id44: '4d0c1eaab0aafc08aea7328f9ed1d3fc2812791ad2ebb9cbc1a8537b51b18afa', - id45: '9129a0454adcf659f4f9d65a9b4dc4f9793bd1f59664268b56a7ef73f29f1b8a', - xPrivKey: 'xprv9s21ZrQH143K3pgRcRBRnmcxNkNNLmJrpneMkEXY6o5TWBuJLMfdRpAWdb2cG3yxbL4DxfpUnQpjfQUmwPdVrRGoDJmtAf5u8cyqKCoDV97', - xPubKey: 'xpub661MyMwAqRbcGJktiSiS9uZgvnCrkE2iC1ZxYcw9f8cSNzESstysycUzUsDCU6KnnjR29VZ1eRAXDgEXfYxGw1B9E7VLSAcHa9UuifSozmy', - xPrivKey_45H: 'xprv9um7h3RnANyeDTTn7SCVckpA65rWTL7MExcta2iz8BaDqxNic6Gmjgv9GfYVs95x5tQJUpeJiuoApbnrwZQQZja5uUQxaySV7wMBV3P27qn', - xPubKey_45H: 'xpub68kU6YxfzkXwRwYFDTjVytkte7gzrnqCcBYVNR8bgX7Cikhs9db2HVEd7yFQVRV19xJ93DHh64fr5jDyWssXGuSt5AsiBurY3eaffcwjafa', - xPrivKey_44H_0H_0H: 'xprv9z9zXfC9effsNS9zXSD4XBUjuEqh6d5ofeF3xqSZPuq1DwAhTDZVuzpNwWfzTgpTm42s6DicHaG2eWesUQ8Cm8Es7kKyt1tCq6W9VM6ot4H', - xPubKey_44H_0H_0H: 'xpub6D9LwAj3V3EAavETdTk4tKRUTGgBW5of2sAemDrAxFMz6jVqzkskTo8rnq5DsoAnTyqnukWsPG7JueVLwLAN6vLXA4MpYceDPQbA6WuFfiV', - xPrivKey_1H: 'xprv9um7h3RnANycGJkyD9iAZy2BUkMpWr6SDV5WzgNYTRjAqX4WpYS7b8Xn8hGLiwmUhCvXnwhdhPEVejSpGVKFD1mxLDy7NSJ5C5oK4SELwJu', - xPubKey_1H: 'xpub68kU6YxfzkXuUnqSKBFAw6xv2nCJvJpHai17o4nA1mG9iKPfN5kN8vrFyzU2hYTBcVcDNoxcDbyqcauCxYJZpQLFzDnaHY5Uej3FCvYwU1P', - privKey_1H_0: '87f8a2b92dd04d2782c3d40a34f09f2ab42076bd02b81fbe4a4a72f87ad2e6df', - pubKey_1H_0: '02a0370d6f1213ab3390ac666585614ad71146f3f28ec326e2e779f999c1a497eb' -}, { - id44: '5ae7b75deb3b4d7e251f1fc5613904c9ef8548af7601d93ef668299be4f75ddd', - id45: '37b81e2544b43ce7f37a132a748426e1566ecbb758564d4d7d07b716fbe1b368', - xPrivKey: 'xprv9s21ZrQH143K3nvcmdjDDDZbDJHpfWZCUiunwraZdcamYcafHvUnZfV51fivH9FPyfo12NyKH5JDxGLsQePyWKtTiJx3pkEaiwxsMLkVapp', - xPubKey: 'xpub661MyMwAqRbcGH15sfGDaMWKmL8K4yH3qwqPkEzBBx7kRQuoqTo37ToYrvLJh7JpV5FQSverERMcdF4HcP1UCiie2ayeMXRq67zr75PzMKs', - xPrivKey_45H: 'xprv9twbreBMkWvwgk9kvzrdygVdir22YSi1dMwMd3GzdhjAD6seKqFidYpehhNR2JL3p41Yeun8ELYAs9pCvKqeH1mu2tQc4PZgWKAUJpaanKo', - xPubKey_45H: 'xpub67vxG9iFatVEuEEE32PeLpSNGsrWwuRrzarxRRgcC3G95uCnsNZyBM98Z145fPbqMgjVG4fPpKrsU7hbq33cpmPXAFF23VMCp7e9ucCGm2v', - xPrivKey_44H_0H_0H: 'xprv9yKWzK3qGKoWD7vkUpPhHQSUvyPrFBL2nBkZHDQPqjZfiR3ws6tL7LoGtrUqSye8cBeCFUzHZhG4i8RPqQuVQGVXgG6dGi2sor5SLh8bN59', - xPubKey_44H_0H_0H: 'xpub6CJsPpaj6hMoRc1DaqvheYPDV1ELee3t9QgA5bp1Q56ebDP6QeCaf97kk9SZPvxDkxt9RGmZBNdDyAyyHMfWDXYmJgAd1dutwgVaLQraVC4', - xPrivKey_1H: 'xprv9twbreBMkWvukJn57LL7aqa4vY9Zg8w8A19uUuDFqzuauaHoRmVTaETtfArRsvzdz41FY9pgLXJspuAF1nadXPTRSBgpNKoUwPM4eWTehSp', - xPubKey_1H: 'xpub67vxG9iFatVCxnrYDMs7wyWoUZz45beyXE5WHHcsQLSZnNcwyJoi82nNWSfrNKeqRnGpCuFGcsTuHi6zEBucxRJDgZbfyny2sUs88ZaMey1', - privKey_1H_0: '66230b6b8b65725162ea43313fcc233f4f0dd135cea00d04b73a84d3f681ef25', - pubKey_1H_0: '03f148bde0784c80051acd159b28a30022e685aca56418f8f50100d9f8a0192c37' -}, { - id44: '98e78a9cb2ab340a245c5082897eadb28c367319f97b93e7b51b4d5ca5cdc68e', - id45: 'e1557d3421a8884fe007674f3f0b6f0feafa76289a0edcc5ec736161b4d02257', - xPrivKey: 'xprv9s21ZrQH143K2uYgqtYtphEQkFAgiWSqahFUWjgCdKykJagiNDz6Lf7xRVQdtZ7MvkhX9V3pEcK3xTAWZ6Y6ecJqrXnCpzrH9GSHn8wyrT5', - xPubKey: 'xpub661MyMwAqRbcFPd9wv5uBqB9JH1B7yAgwvB5K85pBfWjBP1rumJLtTSSGnCdsJSXfwmTyexsRjbUhzB4J6LWfL8mC2Ka117JrnXetyCzk3r', - xPrivKey_45H: 'xprv9vQyc56VRojih8sHwa4gitBJsva7TiRnMg3pBUxFR8NRGNxAbAr3vEb9iH8fxTZmmEnvzLee5DVUckDYJKfRnuxVz6Nm4Wpq1mbHE3K7WeK', - xPubKey_45H: 'xpub69QL1adPGBJ1ucwm3bbh6283RxQbsB9dityQysMryTuQ9BHK8iAJU2udZZNN2t3MNSGnzFiu97BUCjjMUAXqb4caURCMEStMorDU3y3NtgB', - xPrivKey_44H_0H_0H: 'xprv9yowiefD68DG79Xh3J6wAo8u5aTwZ32bsa5jtB4qgKS7r6Tszm42ovSgu7naNPCwT2wt42BXFR4sviY6PEpihhz8LRoHVj2v8WRydzEzqfd', - xPubKey_44H_0H_0H: 'xpub6CoJ8AC6vVmZKdcA9KdwXw5ddcJRxVkTEo1LgZUTEey6ito2YJNHMimAkPuaZ1NCZ1iYAadqQrCvYvrwDzb6wdJpjWWK4EBzmg6mUtVdJZ5', - xPrivKey_1H: 'xprv9vQyc56VRojgmQtXPaDpf5Y1zzmA3aH1SQUwbxqJDJEbjbZSHzpuXmabA2Lx5WThvw1srKUcNez2U4ovSh237mi6bNMufk5XrUcYbXLam2u', - xPubKey_1H: 'xpub69QL1adPGBHyytxzVbkq2DUkZ2beT2zrodQYQMEumdmacPtaqY9A5Zu51KMp7cEgWVsZCADGtqFiLoVzaarkMLXxiVYBSebSBSMZWYkNVr9', - privKey_1H_0: '9e215580c8e5876215ad101ded325bcacc5ab9d97b26e8fdfab89ef5bb6e0ab7', - pubKey_1H_0: '0265d33caaa128a77cc38ab8751c7d730e0274a212f1f65b73f637eddb3a3fb151' -}, { - id44: 'f716dbeec58e44c698b34c2d81bae4699ed5a5a522281733ec50aa03caf76a19', - id45: '8a6d840580549a34422c9b150dbd1e96e369c5db69ee736caab95616f8abb22b', - xPrivKey: 'xprv9s21ZrQH143K2wcRMP75tAEL5JnUx4xU2AbUBQzVVUDP7DHZJkjF3kaRE7tcnPLLLL9PGjYTWTJmCQPaQ4GGzgWEUFJ6snwJG9YnQHBFRNR', - xPubKey: 'xpub661MyMwAqRbcFRgtTQe6FJB4dLcyMXgKPPX4yoQ73okMz1chrJ3VbYtu5PRTxMBGuXt6eyqwAuG2BEBzQPLc1x8gnSQiATS3GRzKi1BuQAR', - xPrivKey_45H: 'xprv9vDicbkxQi4VK49bqmGuj4FSMSuzubjDVBqqwjBxJzUJ9JhQDtF45Nb1ex13D82uqkLyM6YhknAHZ2s4GjuYxQGySECGU82eGkrKi1Pct9v', - xPubKey_45H: 'xpub69D527HrF5cnXYE4wnov6CCAuUkVK4T4rQmSk7bZsL1H272YmRZJdAuVWEfsWKeSfVVTA4NTfyKt4ewZ6gtdPN1RuG5fRj45RYHT5LjvwsJ', - xPrivKey_44H_0H_0H: 'xprv9ynVNvxjepWN96d9wsT1jbWR6iu3YSZNSMeSWLgUqrnKKtZNquZvkd24qNc5wbSj3rvmW7WerhFutju6orHZfena88LFqzn4FUvSMJU928t', - xPubKey_44H_0H_0H: 'xpub6CmqnSVdVC4fMahd3tz26jT9ekjXwuHDoaa3Jj66QCKJCgtXPStBJRLYgfp5TcrH195VmbZUQGdYDFbYDpYKj7a7XsB34WmVDbCFSyAFty7', - xPrivKey_1H: 'xprv9vDicbkxQi4TNYTwjWnLG6kwMMEmndxZbcVRaHxoLtJQYyB5e5napwNeN7xkHhRMqrUEU1ARW6AQH4zsDzj3ra19J5Wjb4UMTxMeXWUAd37', - xPubKey_1H: 'xpub69D527HrF5ckb2YQqYKLdEhfuP5GC6gQxqR2NgNQuDqPRmWEBd6qNjh8DRJfYzQ4Y2WCw3NWR9Bn3YZkKa2yQiCG2xWKSMnMfg71pFEjCWd', - privKey_1H_0: '95951f0e40d31bafe54a3098bd0ed898d370cc5d52a9318d7b7b14568da6cb5c', - pubKey_1H_0: '0266cdb57b8a4d7c1b5b20ddeea43705420c6e3aef2c2979a3768b7b585839a0d3' -}, ]; +var copayers = [ + { + id44: '626452e5e0e35df4d9ae4d3e60653c9ae9a814f00c84dc40f5887069b18e2110', + id45: 'e7467366d5754be2b7d386c9737ab87214c26314bdc3489702e09c719be1bdb7', + xPrivKey: + 'xprv9s21ZrQH143K2n4rV4AtAJFptEmd1tNMKCcSyQBCSuN5eq1dCUhcv6KQJS49joRxu8NNdFxy8yuwTtzCPNYUZvVGC7EPRm2st2cvE7oyTbB', + xPubKey: + 'xpub661MyMwAqRbcFG9Kb5htXSCZSGc7RM6CgRY3mnap1Eu4XdLmk21sTtdt9iWAiL64KazU3QWrYEYSRAKgLvkMRe8JMxffDvt4AhCDzyMsnsT', + xPrivKey_45H: + 'xprv9upyD5bqT9HDgybvt15zN7VZk9TyTzenFuBktJfyweXtVSr9eNYpnBWQQvzxaW8kDWLeiddLu9brYma5WdtD1Maev4aGUfJjiy9EBc1QSFg', + xPubKey_45H: + 'xpub68pKcb8jHWqWuTgPz2czjFSJJBJTsTNdd87Mgh5bVz4sNFBJBus5KyptGBWgA4V6LGCi12s4Mw4S1JC2GkqX4NJ4kfQ47XqRZLbyM2DY9Jd', + xPrivKey_44H_0H_0H: + 'xprv9zWRZ7CXrC4z9xA9RRBFXohmPKbyCajWaCNTHPtwNeJwTnysHG5QK7WMqpNLVtvqGxts7WNcNtqBLfdaFdCGknDPXjLKt2E2BUrPaFDqrLh', + xPubKey_44H_0H_0H: + 'xpub6DVmxcjRgZdHNSEcXSiFtweVwMSTc3TMwRJ45nJYvyqvLbK1poPerupqh87rSoz27wvckb1CKnGZoLmLXSZyNGZtVd7neqSvdwJL6fceQpe', + xPrivKey_1H: + 'xprv9upyD5bqT9HBkWym7TvTH3njEzTnjrtkLB2sg3DD2CxxA5hZKGee1sYJUtD8C4QaeATLXQ33TirRzRhuTGDBA6XRoYDMwfXAj1KSmGyNBio', + xPubKey_1H: + 'xpub68pKcb8jHWqUy14EDVTTeBjTo2JH9KcbhPxUURcpaYVw2t2hroxtZfrnLBw1bWzBrHbEJA48QmZ8DB9gTvhphKSitC15SiYx9k2ncGh55Hq', + privKey_1H_0: 'a710be25950738a7d13637e2e09affd7f579a3479fd7cc024bd9459f8fba6659', + pubKey_1H_0: '026e3020913420a5b9425952627f0a074c9235e7a329869b322061f786e997ae0d', + }, + { + id44: '842c048066e7d10ae1bbf67edccf69f2e5ff9a754d0c2b5524f0d01a87d6acbb', + id45: 'ee75154b646277c8d0d256fc1a0aa0470e4c3435497f208092c865737040b55b', + xPrivKey: + 'xprv9s21ZrQH143K3BwkLceWNLUsgES15JoZuv8BZfnmDRcCGtDooUAPhY8KovhCWcRLXUun5AYL5vVtUNRrmPEibtfk9ongxAGLXZzEHifpvwZ', + xPubKey: + 'xpub661MyMwAqRbcFg2DSeBWjURcEGGVUmXRH93nN4CNmm9B9gYxM1UeFLSofD6gtMnRYeucgPjfrWNxaAEhiT4di6HLty8Un6aheCKev4REvhZ', + xPrivKey_45H: + 'xprv9uHco76yN7arptqnjGr7LiC9VqvXhTYjYeZ4k9MU6kfrX8zBme1gRM2jbBxxt3zfeKBkmpQK4FQ2XFXXkJd2rBE2qoPdMjfC4xvxJ8iqqPW', + xPubKey_45H: + 'xpub68GyCcdsCV9A3NvFqJP7hr8t3sm26vGausUfYXm5f6CqPwKLKBKvy9MDSUA6ot6WMzXCWFyWCFfZyhcqK4uZGPZL83rKW9KfuGLPJ6P38Ex', + xPrivKey_44H_0H_0H: + 'xprv9yBDgTV58cC2XLCp3bGpe6tvmVHxJdE2GTkqM64TUjgRdp4vBnaF4QoMrsz3BjmFQDEx4nPaC4tfk7GUrNFpJZmQgxvp1H7FoveXA7rAPqH', + xPubKey_44H_0H_0H: + 'xpub6CAa5y1xxykKjpHH9coq1EqfKX8Si5wsdggS9UU535DQWcQ4jKtVcD7qi9TCvhV31N3QCLdEaftLjNdXv8R72XiorEnrTfn1ULjA35RgQVp', + xPrivKey_1H: + 'xprv9uHco76yN7aptKFWZW9Cc9KQhwDbFMDeK1C5jBTrN8JKUinAzAZt9G7fL5rcDBQYtXWT7umm4r91tx3kJRZKPKVkd35dzgfwMBLUxBHneAY', + xPubKey_1H: + 'xpub68GyCcdsCV986oKyfXgCyHG9Fy45eowVgE7gXZsTvTqJMX7KXht8h4S9BLnHyWx8YbT8kRX5v4xnZAZvHmdUSdQhvZ2q97PG8m8Ef86yjzK', + privKey_1H_0: 'ee062ce6dc5ece50e8110646b5e858c98dba9315cdfdd19da85ab0d33dcac74a', + pubKey_1H_0: '02c679bf169233a273dec87fae5a1830481866c4e96a350d56346ac267808c905d', + }, + { + id44: '719f4ee61c691fbf0ebefa34e2151a1a3dbe39cf2fa4a498cb6af53600d30d1a', + id45: 'acd666d7c677d9f2c85b55a5fad1610fe272eac46ef7a577c7aeeab0b1474e43', + xPrivKey: + 'xprv9s21ZrQH143K3xgLzxd6SuWqG5Zp1iUmyGgSsJVhdQNeTzAqBFvXXLZqZzFZqocTx4HD9vUVYU27At5i8q46LmBXXL97fo4H9C3tHm4BnjY', + xPubKey: + 'xpub661MyMwAqRbcGSkp6zA6p3TZp7QJRBCdLVc3fguKBjudLnVyioEn58tKRFPmGMkdGJWMX69mgZWHKrKmpQ3fwBXeFjLc5Sd2rnxcQthSW42', + xPrivKey_45H: + 'xprv9vGShhcT8rDFomkiF72D5UXt5BsVydntE7rYbKaa9qtscnWVHaZSPkV9N9SkDkhWbDvkmTGVLYKJf23Z8QjXMRRMTwQYLj26VkPbsKxnUwV', + xPubKey_45H: + 'xpub69Fo7D9LyDmZ2FqBM8ZDScUcdDhzP6WjbLn9PhzBiBRrVaqdq7sgwYodDPUzXyGxpEfTCQyTAA9baAwCApmTiing2S7KTQTmLZjw3Wmaojn', + xPrivKey_44H_0H_0H: + 'xprv9yVpGpTwwtc5aNLkACpuAWmyBUZy1hYy22WQ58Cx614fM7oHpYyjrWbYbExMtZa3sTTywU9mziYBoSZtR4rXVhvfvoVmqZPsYysvpYNUDrk', + xPubKey_44H_0H_0H: + 'xpub6CVAgKzqnGANnrRDGEMuXeihjWQTRAGpPFRzsWcZeLbeDv8SN6HzQJv2SWxg2QSQ7GABwgZJb9KzK8yTXB44CRkqy3cMGEEzniWvBKRCGr5', + xPrivKey_1H: + 'xprv9vGShhcT8rDDu2FvheGgrGvcg5JLQce7kXqC2VnhyYdnggErZA2KJjDwSvQhFZtBVH8T7QQd7JTDXVSvgEijvoYdvCeoRyjQL5EnHRUZgre', + xPubKey_1H: + 'xpub69Fo7D9LyDmX7WLPofohDQsME78pp5My7kknptCKXtAmZUa16hLZrXYRJCL7wLWtTWzMvEn1HKQ8uzp4iLbkS72WPJsLTLayGPw7HGh6hEW', + privKey_1H_0: '5009c8488e9a364fc24a999d99a81ae955271de1d06d46c2f2f09e20c6281b04', + pubKey_1H_0: '03338a3b7c08e9d9832e1baff0758e08f9cc691497dd6e91d4c191cd960fb2f043', + }, + { + id44: 'e225a29864060823df67b98432b070a40aad1bf9af517005b0b5fe09c96e29c9', + id45: 'c65a89f64794cb7e1886c7010a32dd6fa362d3e81710bac32e97e325b9109fd8', + xPrivKey: + 'xprv9s21ZrQH143K48nfuK14gKJtML7eQzV2dAH1RaqAMj8v2zs79uaavA9UTWMxpBdgbMH2mhJLeKGq8AFA6GDnFyWP4rLmknqZAfgFFV718vo', + xPubKey: + 'xpub661MyMwAqRbcGcs91LY53TFcuMx8pTCszPCcDyEmv4ftuoCFhStqTxTxJoy35yjp2H3qQtxDYGe1gtkZu4T7mR7ARK1MLYte2fptZVt6hkD', + xPrivKey_45H: + 'xprv9vYQ7HC96LzvDwJ2r99m4ALTEtXTfUCHPbs7gpPzWboFP3NFgzMjXPf9Pp7D3vmTUqRtsZfSfVghvUhLKGGAs3LdVf9rf89TgRAvqAWMSwN', + xPubKey_45H: + 'xpub69XkWnj2viZDSRNVxAgmRJHBnvMx4vv8kpniVCoc4wLEFqhQEXfz5BydF79LoErgaokMLv7u2sRNsoiJqjr5nyfBqJGykfR3kvCex7z8Ar3', + xPrivKey_44H_0H_0H: + 'xprv9yn1LP3ViLTXUYgZP5sDFG94H6sd8v5AKRBbd35Ub5FjPq2HuzC9bAb6LReTXRSA4XTtYvzwpiktvuRrLY98df2KZMCuyZxXUB7FpBQ2ndA', + xPubKey_44H_0H_0H: + 'xpub6CmMjtaPYi1ph2m2V7QDcQ5nq8i7YNo1ge7CRRV69QniGdMSTXWQ8xuaBiNt74nJCMZjaeNgRbMiZmdgrEqogvjARnBx8k4y853MZGAkjmo', + xPrivKey_1H: + 'xprv9vYQ7HC96LztKQouECporZgezbjktKyhipWavsJvEJ4ok577RxVcmnyeRUUbAqmq5FnuhDie62Z962xNvF9JwAXoJZx2VeJPUWMPHsuoAkM', + xPubKey_1H: + 'xpub69XkWnj2viZBXttNLEMpDhdPYdaFHnhZ63SBjFiXndbncsSFyVosKbJ8GjGMT7LX1rF6aisHM2YmFKye7bR3xQn5Bj875iGxyVrbRF7k5N8', + privKey_1H_0: '460ee692f05de66b5d8e2fa1d005a8b6bdb1442e2ce6b3facfcee2f9012c9474', + pubKey_1H_0: '03d0e0c526619b158aac9a8de8082f439df43d389ec50cb54386c3d87cfde4c99b', + }, + { + id44: '120416cd4c427a7e4d94213cebe242f56a06bc6dd5c5c6cae27dc920a0ddf1fb', + id45: '65ae087eb9efdc7e0ada3a7ef954285e9e5ba4b8c7ab2d36747ddd286f7a334f', + xPrivKey: + 'xprv9s21ZrQH143K44Bb9G3EVNmLfAUKjTBAA2YtKxF4zc8SLV1o15JBoddhGHE9PGLXePMbEsSjCCvTvP3fUv6yMXZrnHigBboRBn2DmNoJkJg', + xPubKey: + 'xpub661MyMwAqRbcGYG4FHaErWi5DCJp8uu1XFUV8LegYwfRDHLwYccSMRxB7Z3L1NgKychKdXQvbVEyDhSwNnNnnNKh9mBEAdQ5tv2guK8ywKU', + xPrivKey_45H: + 'xprv9vKBPQfZS4jWfLtSAoSeBHdLU1yJicKVmhTdbewKwQWU2CPdm61scXvKXHaMshmDEBaspUc994GAzZK1x7PtfzZ2PGtGHHhJhDn3yoT8gAi', + xPubKey_45H: + 'xpub69JXnvCTGSHospxuGpyeYRa523oo853M8vPEQ3LwVk3StzinJdL8ALEoNa8AwwJsAWrfFtwfDgTCB9o1kKwn9n2tdN9nbdrw2zs5rNqQpM2', + xPrivKey_44H_0H_0H: + 'xprv9xuBGYz7dmjgyroeDKMKyjSCiWyqskWavGjLPJbC9W32TkTy8NqXX4y5WQKcK24SnGiDMpUhFUNqjh284RjHoNYC2gUKagKfVfWZqn1gey4', + xPubKey_44H_0H_0H: + 'xpub6BtXg4X1U9HzCLt7KLtLLsNwGYpLHDESHVewBgzohqa1LYo7fv9n4sHZMdzdBh5pxiAgLyUvsAqAQ5J1CRK4uA9htCWbKbVxFsfMEij3MDA', + xPrivKey_1H: + 'xprv9vKBPQfZS4jUjK546Cjyf8ZgtEvRhQyjfuE89DAnYatevTusA8wwXiDxEFPSFk4fp8wwC5nRGmkSnTi9ascW9LJjujm2g36eGocNMtEsDwX', + xPubKey_1H: + 'xpub69JXnvCTGSHmwo9XCEGz2GWRSGkv6shb389iwbaQ6vRdoGF1hgGC5WYS5YhxaM6RpfzsbPJqfR7iCLdEMSMUYvhaG4tvmEsn8ztwtysjgp8', + privKey_1H_0: '7a5158b92d9ed4cb9644ddbd472b43428832a5f3bb91a481532a081908e62b2e', + pubKey_1H_0: '02b47d5c977c93c883f369165ebc2b564d14a52712ec6892f7097fa99e0d36ca20', + }, + { + id44: '85de9f025ee190fab7cb1bd9b6772c64df26188ce705d4f258c5adaf7bc610f9', + id45: 'dacc5c350cef4449a3ca12939711c7449d0d6189e5e7f33cff60095a7a29b0f9', + xPrivKey: + 'xprv9s21ZrQH143K48PpVxrh71KdViTFhAaiDSVtNFkmbWNYjwwwPbTrcqoVXsgBfue3Gq9b71hQeEbk67JgtTBcpYgKLF8pTwVnGz56f1BaCYt', + xPubKey: + 'xpub661MyMwAqRbcGcUHbzPhU9GN3kHk6dJZafRVAeAP9quXckH5w8n7Ae7yP8e2Zh6SPPKFn2K6oE3GBpcz9QzfJTNRWXbY7w1L3nGLE5beZL1', + xPrivKey_45H: + 'xprv9u8SxxhEJB4pzk6P3VKwmRRFqgHX94kBHDTBDaFXeaMS7dggkQcf2Tt14AvTvMJYjpogB2bVgmkHEW4Ze1iVzZeF5S5FLj6zpqwyrwh9yRW', + xPubKey_45H: + 'xpub687oNUE88Yd8DEAr9Wrx8ZMzPi81YXU2eSNn1xf9CutQzS1qHwvuaGCUuTHJXkvzrRSiRtuJid3LsPaS3hUAdahdy3ZpQCcsLEQjC2Q2tNT', + xPrivKey_44H_0H_0H: + 'xprv9yTxyEKAvyMLaocWZ4rXUUC7xWUqzhcvDJc2Ms7fndKaSfityJdaGrhLCSsLZz2E9NG3VkhbbsYwZVW9J5W3BQegyWWNsuEKmkdCsr9DRkM', + xPubKey_44H_0H_0H: + 'xpub6CTKNjr4mLudoHgyf6PXqc8rWYKLQALmaXXdAFXHLxrZKU43Wqwppf1p3kj8sC9b9Sx5uqXfnATdvz5jeFYKELnngksCzwABLfNcW8CPkfg', + xPrivKey_1H: + 'xprv9u8SxxhEJB4o6KfWV3csVTsJzhePBtMz8CmJCcn83vaWSiydgv6CADdbxjq3YsnusKPyPw1G235KibW67VjdbJ2ZoTG4nFA6ivwPRBmScKW', + xPubKey_1H: + 'xpub687oNUE88Yd6Jojyb59srbp3YjUsbM5qVRgu11BjcG7VKXJnETQSi1x5p3onkhodzQcydFLTkZ3ym35UmAAWrjLY4rDAt2RjHKidx6AzgVz', + privKey_1H_0: '3c49816d4e83d8758f89e8e104e3566a8a61426a9b7d4945b34212fbbb8e8290', + pubKey_1H_0: '0307ab8c0d8eea1fe3c3781050a69e71f9e7c8cc8476a77103e08a461506a0e780', + }, + { + id44: '4d0c1eaab0aafc08aea7328f9ed1d3fc2812791ad2ebb9cbc1a8537b51b18afa', + id45: '9129a0454adcf659f4f9d65a9b4dc4f9793bd1f59664268b56a7ef73f29f1b8a', + xPrivKey: + 'xprv9s21ZrQH143K3pgRcRBRnmcxNkNNLmJrpneMkEXY6o5TWBuJLMfdRpAWdb2cG3yxbL4DxfpUnQpjfQUmwPdVrRGoDJmtAf5u8cyqKCoDV97', + xPubKey: + 'xpub661MyMwAqRbcGJktiSiS9uZgvnCrkE2iC1ZxYcw9f8cSNzESstysycUzUsDCU6KnnjR29VZ1eRAXDgEXfYxGw1B9E7VLSAcHa9UuifSozmy', + xPrivKey_45H: + 'xprv9um7h3RnANyeDTTn7SCVckpA65rWTL7MExcta2iz8BaDqxNic6Gmjgv9GfYVs95x5tQJUpeJiuoApbnrwZQQZja5uUQxaySV7wMBV3P27qn', + xPubKey_45H: + 'xpub68kU6YxfzkXwRwYFDTjVytkte7gzrnqCcBYVNR8bgX7Cikhs9db2HVEd7yFQVRV19xJ93DHh64fr5jDyWssXGuSt5AsiBurY3eaffcwjafa', + xPrivKey_44H_0H_0H: + 'xprv9z9zXfC9effsNS9zXSD4XBUjuEqh6d5ofeF3xqSZPuq1DwAhTDZVuzpNwWfzTgpTm42s6DicHaG2eWesUQ8Cm8Es7kKyt1tCq6W9VM6ot4H', + xPubKey_44H_0H_0H: + 'xpub6D9LwAj3V3EAavETdTk4tKRUTGgBW5of2sAemDrAxFMz6jVqzkskTo8rnq5DsoAnTyqnukWsPG7JueVLwLAN6vLXA4MpYceDPQbA6WuFfiV', + xPrivKey_1H: + 'xprv9um7h3RnANycGJkyD9iAZy2BUkMpWr6SDV5WzgNYTRjAqX4WpYS7b8Xn8hGLiwmUhCvXnwhdhPEVejSpGVKFD1mxLDy7NSJ5C5oK4SELwJu', + xPubKey_1H: + 'xpub68kU6YxfzkXuUnqSKBFAw6xv2nCJvJpHai17o4nA1mG9iKPfN5kN8vrFyzU2hYTBcVcDNoxcDbyqcauCxYJZpQLFzDnaHY5Uej3FCvYwU1P', + privKey_1H_0: '87f8a2b92dd04d2782c3d40a34f09f2ab42076bd02b81fbe4a4a72f87ad2e6df', + pubKey_1H_0: '02a0370d6f1213ab3390ac666585614ad71146f3f28ec326e2e779f999c1a497eb', + }, + { + id44: '5ae7b75deb3b4d7e251f1fc5613904c9ef8548af7601d93ef668299be4f75ddd', + id45: '37b81e2544b43ce7f37a132a748426e1566ecbb758564d4d7d07b716fbe1b368', + xPrivKey: + 'xprv9s21ZrQH143K3nvcmdjDDDZbDJHpfWZCUiunwraZdcamYcafHvUnZfV51fivH9FPyfo12NyKH5JDxGLsQePyWKtTiJx3pkEaiwxsMLkVapp', + xPubKey: + 'xpub661MyMwAqRbcGH15sfGDaMWKmL8K4yH3qwqPkEzBBx7kRQuoqTo37ToYrvLJh7JpV5FQSverERMcdF4HcP1UCiie2ayeMXRq67zr75PzMKs', + xPrivKey_45H: + 'xprv9twbreBMkWvwgk9kvzrdygVdir22YSi1dMwMd3GzdhjAD6seKqFidYpehhNR2JL3p41Yeun8ELYAs9pCvKqeH1mu2tQc4PZgWKAUJpaanKo', + xPubKey_45H: + 'xpub67vxG9iFatVEuEEE32PeLpSNGsrWwuRrzarxRRgcC3G95uCnsNZyBM98Z145fPbqMgjVG4fPpKrsU7hbq33cpmPXAFF23VMCp7e9ucCGm2v', + xPrivKey_44H_0H_0H: + 'xprv9yKWzK3qGKoWD7vkUpPhHQSUvyPrFBL2nBkZHDQPqjZfiR3ws6tL7LoGtrUqSye8cBeCFUzHZhG4i8RPqQuVQGVXgG6dGi2sor5SLh8bN59', + xPubKey_44H_0H_0H: + 'xpub6CJsPpaj6hMoRc1DaqvheYPDV1ELee3t9QgA5bp1Q56ebDP6QeCaf97kk9SZPvxDkxt9RGmZBNdDyAyyHMfWDXYmJgAd1dutwgVaLQraVC4', + xPrivKey_1H: + 'xprv9twbreBMkWvukJn57LL7aqa4vY9Zg8w8A19uUuDFqzuauaHoRmVTaETtfArRsvzdz41FY9pgLXJspuAF1nadXPTRSBgpNKoUwPM4eWTehSp', + xPubKey_1H: + 'xpub67vxG9iFatVCxnrYDMs7wyWoUZz45beyXE5WHHcsQLSZnNcwyJoi82nNWSfrNKeqRnGpCuFGcsTuHi6zEBucxRJDgZbfyny2sUs88ZaMey1', + privKey_1H_0: '66230b6b8b65725162ea43313fcc233f4f0dd135cea00d04b73a84d3f681ef25', + pubKey_1H_0: '03f148bde0784c80051acd159b28a30022e685aca56418f8f50100d9f8a0192c37', + }, + { + id44: '98e78a9cb2ab340a245c5082897eadb28c367319f97b93e7b51b4d5ca5cdc68e', + id45: 'e1557d3421a8884fe007674f3f0b6f0feafa76289a0edcc5ec736161b4d02257', + xPrivKey: + 'xprv9s21ZrQH143K2uYgqtYtphEQkFAgiWSqahFUWjgCdKykJagiNDz6Lf7xRVQdtZ7MvkhX9V3pEcK3xTAWZ6Y6ecJqrXnCpzrH9GSHn8wyrT5', + xPubKey: + 'xpub661MyMwAqRbcFPd9wv5uBqB9JH1B7yAgwvB5K85pBfWjBP1rumJLtTSSGnCdsJSXfwmTyexsRjbUhzB4J6LWfL8mC2Ka117JrnXetyCzk3r', + xPrivKey_45H: + 'xprv9vQyc56VRojih8sHwa4gitBJsva7TiRnMg3pBUxFR8NRGNxAbAr3vEb9iH8fxTZmmEnvzLee5DVUckDYJKfRnuxVz6Nm4Wpq1mbHE3K7WeK', + xPubKey_45H: + 'xpub69QL1adPGBJ1ucwm3bbh6283RxQbsB9dityQysMryTuQ9BHK8iAJU2udZZNN2t3MNSGnzFiu97BUCjjMUAXqb4caURCMEStMorDU3y3NtgB', + xPrivKey_44H_0H_0H: + 'xprv9yowiefD68DG79Xh3J6wAo8u5aTwZ32bsa5jtB4qgKS7r6Tszm42ovSgu7naNPCwT2wt42BXFR4sviY6PEpihhz8LRoHVj2v8WRydzEzqfd', + xPubKey_44H_0H_0H: + 'xpub6CoJ8AC6vVmZKdcA9KdwXw5ddcJRxVkTEo1LgZUTEey6ito2YJNHMimAkPuaZ1NCZ1iYAadqQrCvYvrwDzb6wdJpjWWK4EBzmg6mUtVdJZ5', + xPrivKey_1H: + 'xprv9vQyc56VRojgmQtXPaDpf5Y1zzmA3aH1SQUwbxqJDJEbjbZSHzpuXmabA2Lx5WThvw1srKUcNez2U4ovSh237mi6bNMufk5XrUcYbXLam2u', + xPubKey_1H: + 'xpub69QL1adPGBHyytxzVbkq2DUkZ2beT2zrodQYQMEumdmacPtaqY9A5Zu51KMp7cEgWVsZCADGtqFiLoVzaarkMLXxiVYBSebSBSMZWYkNVr9', + privKey_1H_0: '9e215580c8e5876215ad101ded325bcacc5ab9d97b26e8fdfab89ef5bb6e0ab7', + pubKey_1H_0: '0265d33caaa128a77cc38ab8751c7d730e0274a212f1f65b73f637eddb3a3fb151', + }, + { + id44: 'f716dbeec58e44c698b34c2d81bae4699ed5a5a522281733ec50aa03caf76a19', + id45: '8a6d840580549a34422c9b150dbd1e96e369c5db69ee736caab95616f8abb22b', + xPrivKey: + 'xprv9s21ZrQH143K2wcRMP75tAEL5JnUx4xU2AbUBQzVVUDP7DHZJkjF3kaRE7tcnPLLLL9PGjYTWTJmCQPaQ4GGzgWEUFJ6snwJG9YnQHBFRNR', + xPubKey: + 'xpub661MyMwAqRbcFRgtTQe6FJB4dLcyMXgKPPX4yoQ73okMz1chrJ3VbYtu5PRTxMBGuXt6eyqwAuG2BEBzQPLc1x8gnSQiATS3GRzKi1BuQAR', + xPrivKey_45H: + 'xprv9vDicbkxQi4VK49bqmGuj4FSMSuzubjDVBqqwjBxJzUJ9JhQDtF45Nb1ex13D82uqkLyM6YhknAHZ2s4GjuYxQGySECGU82eGkrKi1Pct9v', + xPubKey_45H: + 'xpub69D527HrF5cnXYE4wnov6CCAuUkVK4T4rQmSk7bZsL1H272YmRZJdAuVWEfsWKeSfVVTA4NTfyKt4ewZ6gtdPN1RuG5fRj45RYHT5LjvwsJ', + xPrivKey_44H_0H_0H: + 'xprv9ynVNvxjepWN96d9wsT1jbWR6iu3YSZNSMeSWLgUqrnKKtZNquZvkd24qNc5wbSj3rvmW7WerhFutju6orHZfena88LFqzn4FUvSMJU928t', + xPubKey_44H_0H_0H: + 'xpub6CmqnSVdVC4fMahd3tz26jT9ekjXwuHDoaa3Jj66QCKJCgtXPStBJRLYgfp5TcrH195VmbZUQGdYDFbYDpYKj7a7XsB34WmVDbCFSyAFty7', + xPrivKey_1H: + 'xprv9vDicbkxQi4TNYTwjWnLG6kwMMEmndxZbcVRaHxoLtJQYyB5e5napwNeN7xkHhRMqrUEU1ARW6AQH4zsDzj3ra19J5Wjb4UMTxMeXWUAd37', + xPubKey_1H: + 'xpub69D527HrF5ckb2YQqYKLdEhfuP5GC6gQxqR2NgNQuDqPRmWEBd6qNjh8DRJfYzQ4Y2WCw3NWR9Bn3YZkKa2yQiCG2xWKSMnMfg71pFEjCWd', + privKey_1H_0: '95951f0e40d31bafe54a3098bd0ed898d370cc5d52a9318d7b7b14568da6cb5c', + pubKey_1H_0: '0266cdb57b8a4d7c1b5b20ddeea43705420c6e3aef2c2979a3768b7b585839a0d3', + }, +]; var history = [ { - txid: "0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04", - vin: [{ - txid: "c8e221141e8bb60977896561b77fa59d6dacfcc10db82bf6f5f923048b11c70d", - vout: 0, - n: 0, - addr: "2N6Zutg26LEC4iYVxi7SHhopVLP1iZPU1rZ", - valueMicros: 485645, - value: 0.00485645, - }, { - txid: "6e599eea3e2898b91087eb87e041c5d8dec5362447a8efba185ed593f6dc64c0", - vout: 1, - n: 1, - addr: "2MyqmcWjmVxW8i39wdk1CVPdEqKyFSY9H1S", - valueMicros: 885590, - value: 0.0088559, - }], - vout: [{ - value: "0.00045753", - n: 0, - scriptPubKey: { - addresses: [ - "2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V" - ] - }, - }, { - value: "0.01300000", - n: 1, - scriptPubKey: { - addresses: [ - "mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE" - ] - } - }], - confirmations: 0, - firstSeenTs: 1424471000, - valueOut: 0.01345753, - valueIn: 0.01371235, - fees: 0.00025482 -}, + txid: '0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04', + vin: [ + { + txid: 'c8e221141e8bb60977896561b77fa59d6dacfcc10db82bf6f5f923048b11c70d', + vout: 0, + n: 0, + addr: '2N6Zutg26LEC4iYVxi7SHhopVLP1iZPU1rZ', + valueMicros: 485645, + value: 0.00485645, + }, + { + txid: '6e599eea3e2898b91087eb87e041c5d8dec5362447a8efba185ed593f6dc64c0', + vout: 1, + n: 1, + addr: '2MyqmcWjmVxW8i39wdk1CVPdEqKyFSY9H1S', + valueMicros: 885590, + value: 0.0088559, + }, + ], + vout: [ + { + value: '0.00045753', + n: 0, + scriptPubKey: { + addresses: ['2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V'], + }, + }, + { + value: '0.01300000', + n: 1, + scriptPubKey: { + addresses: ['mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE'], + }, + }, + ], + confirmations: 0, + firstSeenTs: 1424471000, + valueOut: 0.01345753, + valueIn: 0.01371235, + fees: 0.00025482, + }, { - txid: "0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04", - vin: [{ - txid: "c8e221141e8bb60977896561b77fa59d6dacfcc10db82bf6f5f923048b11c70d", - vout: 0, - n: 0, - addr: "2N6Zutg26LEC4iYVxi7SHhopVLP1iZPU1rZ", - valueMicros: 485645, - value: 0.00485645, - }, { - txid: "6e599eea3e2898b91087eb87e041c5d8dec5362447a8efba185ed593f6dc64c0", - vout: 1, - n: 1, - addr: "2MyqmcWjmVxW8i39wdk1CVPdEqKyFSY9H1S", - valueMicros: 885590, - value: 0.0088559, - }], - vout: [{ - value: "0.00045753", - n: 0, - scriptPubKey: { - addresses: [ - "2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V" - ] - }, - }, { - value: "0.01300000", - n: 1, - scriptPubKey: { - addresses: [ - "mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE" - ] - } - }], - confirmations: 2, - firstSeenTs: 1424471041, - blocktime: 1424471051, - valueOut: 0.01345753, - valueIn: 0.01371235, - fees: 0.00025482 -}, { - txid: "fad88682ccd2ff34cac6f7355fe9ecd8addd9ef167e3788455972010e0d9d0de", - vin: [{ - txid: "0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04", - vout: 0, - n: 0, - addr: "2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V", - valueMicros: 45753, - value: 0.00045753, - }], - vout: [{ - value: "0.00011454", - n: 0, - scriptPubKey: { - addresses: [ - "2N7GT7XaN637eBFMmeczton2aZz5rfRdZso" - ] - } - }, { - value: "0.00020000", - n: 1, - scriptPubKey: { - addresses: [ - "mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE" - ] - } - }], - confirmations: 1, - time: 1424472242, - blocktime: 1424472242, - valueOut: 0.00031454, - valueIn: 0.00045753, - fees: 0.00014299 -}]; - + txid: '0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04', + vin: [ + { + txid: 'c8e221141e8bb60977896561b77fa59d6dacfcc10db82bf6f5f923048b11c70d', + vout: 0, + n: 0, + addr: '2N6Zutg26LEC4iYVxi7SHhopVLP1iZPU1rZ', + valueMicros: 485645, + value: 0.00485645, + }, + { + txid: '6e599eea3e2898b91087eb87e041c5d8dec5362447a8efba185ed593f6dc64c0', + vout: 1, + n: 1, + addr: '2MyqmcWjmVxW8i39wdk1CVPdEqKyFSY9H1S', + valueMicros: 885590, + value: 0.0088559, + }, + ], + vout: [ + { + value: '0.00045753', + n: 0, + scriptPubKey: { + addresses: ['2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V'], + }, + }, + { + value: '0.01300000', + n: 1, + scriptPubKey: { + addresses: ['mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE'], + }, + }, + ], + confirmations: 2, + firstSeenTs: 1424471041, + blocktime: 1424471051, + valueOut: 0.01345753, + valueIn: 0.01371235, + fees: 0.00025482, + }, + { + txid: 'fad88682ccd2ff34cac6f7355fe9ecd8addd9ef167e3788455972010e0d9d0de', + vin: [ + { + txid: '0279ef7b21630f859deb723e28beac9e7011660bd1346c2da40321d2f7e34f04', + vout: 0, + n: 0, + addr: '2NAVFnsHqy5JvqDJydbHPx393LFqFFBQ89V', + valueMicros: 45753, + value: 0.00045753, + }, + ], + vout: [ + { + value: '0.00011454', + n: 0, + scriptPubKey: { + addresses: ['2N7GT7XaN637eBFMmeczton2aZz5rfRdZso'], + }, + }, + { + value: '0.00020000', + n: 1, + scriptPubKey: { + addresses: ['mq4D3Va5mYHohMEHrgHNGzCjKhBKvuEhPE'], + }, + }, + ], + confirmations: 1, + time: 1424472242, + blocktime: 1424472242, + valueOut: 0.00031454, + valueIn: 0.00045753, + fees: 0.00014299, + }, +]; module.exports.keyPair = keyPair; module.exports.copayers = copayers; diff --git a/packages/merit-wallet-service/test/utils.js b/packages/merit-wallet-service/test/utils.js index 0c476dc6d0..222408be4c 100644 --- a/packages/merit-wallet-service/test/utils.js +++ b/packages/merit-wallet-service/test/utils.js @@ -14,31 +14,40 @@ describe('Utils', function() { name: 'name', array: ['a', 'b'], }; - var fixtures = [{ - args: 'id', - check: [], - }, { - args: ['id'], - check: [] - }, { - args: ['id, name'], - check: ['id, name'], - }, { - args: ['id', 'name'], - check: [] - }, { - args: 'array', - check: [] - }, { - args: 'dummy', - check: ['dummy'] - }, { - args: ['dummy1', 'dummy2'], - check: ['dummy1', 'dummy2'] - }, { - args: ['id', 'dummy'], - check: ['dummy'] - }, ]; + var fixtures = [ + { + args: 'id', + check: [], + }, + { + args: ['id'], + check: [], + }, + { + args: ['id, name'], + check: ['id, name'], + }, + { + args: ['id', 'name'], + check: [], + }, + { + args: 'array', + check: [], + }, + { + args: 'dummy', + check: ['dummy'], + }, + { + args: ['dummy1', 'dummy2'], + check: ['dummy1', 'dummy2'], + }, + { + args: ['id', 'dummy'], + check: ['dummy'], + }, + ]; _.each(fixtures, function(f) { Utils.getMissingFields(obj, f.args).should.deep.equal(f.check); }); @@ -58,7 +67,11 @@ describe('Utils', function() { describe('#verifyMessage', function() { it('should fail to verify a malformed signature', function() { - var res = Utils.verifyMessage('hola', 'badsignature', '02555a2d45e309c00cc8c5090b6ec533c6880ab2d3bc970b3943def989b3373f16'); + var res = Utils.verifyMessage( + 'hola', + 'badsignature', + '02555a2d45e309c00cc8c5090b6ec533c6880ab2d3bc970b3943def989b3373f16', + ); should.exist(res); res.should.equal(false); }); @@ -68,12 +81,20 @@ describe('Utils', function() { res.should.equal(false); }); it('should fail to verify with wrong pubkey', function() { - var res = Utils.verifyMessage('hola', '3045022100d6186930e4cd9984e3168e15535e2297988555838ad10126d6c20d4ac0e74eb502201095a6319ea0a0de1f1e5fb50f7bf10b8069de10e0083e23dbbf8de9b8e02785', '02555a2d45e309c00cc8c5090b6ec533c6880ab2d3bc970b3943def989b3373f16'); + var res = Utils.verifyMessage( + 'hola', + '3045022100d6186930e4cd9984e3168e15535e2297988555838ad10126d6c20d4ac0e74eb502201095a6319ea0a0de1f1e5fb50f7bf10b8069de10e0083e23dbbf8de9b8e02785', + '02555a2d45e309c00cc8c5090b6ec533c6880ab2d3bc970b3943def989b3373f16', + ); should.exist(res); res.should.equal(false); }); it('should verify', function() { - var res = Utils.verifyMessage('hola', '3045022100d6186930e4cd9984e3168e15535e2297988555838ad10126d6c20d4ac0e74eb502201095a6319ea0a0de1f1e5fb50f7bf10b8069de10e0083e23dbbf8de9b8e02785', '03bec86ad4a8a91fe7c11ec06af27246ec55094db3d86098b7d8b2f12afe47627f'); + var res = Utils.verifyMessage( + 'hola', + '3045022100d6186930e4cd9984e3168e15535e2297988555838ad10126d6c20d4ac0e74eb502201095a6319ea0a0de1f1e5fb50f7bf10b8069de10e0083e23dbbf8de9b8e02785', + '03bec86ad4a8a91fe7c11ec06af27246ec55094db3d86098b7d8b2f12afe47627f', + ); should.exist(res); res.should.equal(true); }); @@ -81,50 +102,75 @@ describe('Utils', function() { describe('#formatAmount', function() { it('should successfully format amount', function() { - var cases = [{ - args: [1, 'bit'], - expected: '0', - }, { - args: [1, 'mrt'], - expected: '0.00', - }, { - args: [0, 'bit'], - expected: '0', - }, { - args: [12345678, 'bit'], - expected: '123,457', - }, { - args: [12345678, 'mrt'], - expected: '0.123457', - }, { - args: [12345611, 'mrt'], - expected: '0.123456', - }, { - args: [1234, 'mrt'], - expected: '0.000012', - }, { - args: [1299, 'mrt'], - expected: '0.000013', - }, { - args: [1234567899999, 'mrt'], - expected: '12,345.679', - }, { - args: [12345678, 'bit', { - thousandsSeparator: '.' - }], - expected: '123.457', - }, { - args: [12345678, 'mrt', { - decimalSeparator: ',' - }], - expected: '0,123457', - }, { - args: [1234567899999, 'mrt', { - thousandsSeparator: ' ', - decimalSeparator: ',' - }], - expected: '12 345,679', - }, ]; + var cases = [ + { + args: [1, 'bit'], + expected: '0', + }, + { + args: [1, 'mrt'], + expected: '0.00', + }, + { + args: [0, 'bit'], + expected: '0', + }, + { + args: [12345678, 'bit'], + expected: '123,457', + }, + { + args: [12345678, 'mrt'], + expected: '0.123457', + }, + { + args: [12345611, 'mrt'], + expected: '0.123456', + }, + { + args: [1234, 'mrt'], + expected: '0.000012', + }, + { + args: [1299, 'mrt'], + expected: '0.000013', + }, + { + args: [1234567899999, 'mrt'], + expected: '12,345.679', + }, + { + args: [ + 12345678, + 'bit', + { + thousandsSeparator: '.', + }, + ], + expected: '123.457', + }, + { + args: [ + 12345678, + 'mrt', + { + decimalSeparator: ',', + }, + ], + expected: '0,123457', + }, + { + args: [ + 1234567899999, + 'mrt', + { + thousandsSeparator: ' ', + decimalSeparator: ',', + }, + ], + expected: '12 345,679', + }, + ]; _.each(cases, function(testCase) { Utils.formatAmount.apply(this, testCase.args).should.equal(testCase.expected); diff --git a/packages/meritcore-lib/README.md b/packages/meritcore-lib/README.md index 918120dc86..1f63ed0c3c 100644 --- a/packages/meritcore-lib/README.md +++ b/packages/meritcore-lib/README.md @@ -1,5 +1,4 @@ -Merit Library -======= +# Merit Library A pure and powerful JavaScript Merit library. @@ -9,7 +8,6 @@ Merit is a powerful new peer-to-peer platform for the next generation of financi To get community assistance and ask for help with implementation questions, please use our [community forums](https://forum.merit.me/), [Discord](https://discordapp.com/invite/X3v3n3b), or [Telegram](https://t.me/meritocracy). - ## Security We're using Merit library in production, but please use common sense when doing anything related to finances! We take no responsibility for your implementation decisions. diff --git a/packages/meritcore-lib/benchmark/script.js b/packages/meritcore-lib/benchmark/script.js index d58af2d053..f29814bf82 100644 --- a/packages/meritcore-lib/benchmark/script.js +++ b/packages/meritcore-lib/benchmark/script.js @@ -10,76 +10,78 @@ var maxTime = 10; console.log('Benchmarking Script'); console.log('---------------------------------------'); -async.series([ - function(next) { - - var c = 0; - var scripts = []; - var block = meritcore.Block.fromString(blockData); - for (var i = 0; i < block.transactions.length; i++) { - var tx = block.transactions[i]; - for (var j = 0; j < tx.inputs.length; j++) { - var input = tx.inputs[j]; - if (input.script) { - scripts.push(input.script); +async.series( + [ + function(next) { + var c = 0; + var scripts = []; + var block = meritcore.Block.fromString(blockData); + for (var i = 0; i < block.transactions.length; i++) { + var tx = block.transactions[i]; + for (var j = 0; j < tx.inputs.length; j++) { + var input = tx.inputs[j]; + if (input.script) { + scripts.push(input.script); + } } - } - for (var k = 0; k < tx.outputs.length; k++) { - var output = tx.outputs[k]; - if (output.script) { - scripts.push(output.script); + for (var k = 0; k < tx.outputs.length; k++) { + var output = tx.outputs[k]; + if (output.script) { + scripts.push(output.script); + } } } - } - function isPublicKeyOut() { - if (c >= scripts.length) { - c = 0; + function isPublicKeyOut() { + if (c >= scripts.length) { + c = 0; + } + scripts[c].isPublicKeyOut(); + c++; } - scripts[c].isPublicKeyOut(); - c++; - } - function isPublicKeyHashIn() { - if (c >= scripts.length) { - c = 0; + function isPublicKeyHashIn() { + if (c >= scripts.length) { + c = 0; + } + scripts[c].isPublicKeyHashIn(); + c++; } - scripts[c].isPublicKeyHashIn(); - c++; - } - function toAddress() { - if (c >= scripts.length) { - c = 0; + function toAddress() { + if (c >= scripts.length) { + c = 0; + } + scripts[c].toAddress(); + c++; } - scripts[c].toAddress(); - c++; - } - function getAddressInfo() { - if (c >= scripts.length) { - c = 0; + function getAddressInfo() { + if (c >= scripts.length) { + c = 0; + } + scripts[c].getAddressInfo(); + c++; } - scripts[c].getAddressInfo(); - c++; - } - var suite = new benchmark.Suite(); - suite.add('isPublicKeyHashIn', isPublicKeyHashIn, {maxTime: maxTime}); - suite.add('isPublicKeyOut', isPublicKeyOut, {maxTime: maxTime}); - suite.add('toAddress', toAddress, {maxTime: maxTime}); - suite.add('getAddressInfo', getAddressInfo, {maxTime: maxTime}); - suite - .on('cycle', function(event) { - console.log(String(event.target)); - }) - .on('complete', function() { - console.log('Done'); - console.log('----------------------------------------------------------------------'); - next(); - }) - .run(); - } -], function(err) { - console.log('Finished'); -}); + var suite = new benchmark.Suite(); + suite.add('isPublicKeyHashIn', isPublicKeyHashIn, { maxTime: maxTime }); + suite.add('isPublicKeyOut', isPublicKeyOut, { maxTime: maxTime }); + suite.add('toAddress', toAddress, { maxTime: maxTime }); + suite.add('getAddressInfo', getAddressInfo, { maxTime: maxTime }); + suite + .on('cycle', function(event) { + console.log(String(event.target)); + }) + .on('complete', function() { + console.log('Done'); + console.log('----------------------------------------------------------------------'); + next(); + }) + .run(); + }, + ], + function(err) { + console.log('Finished'); + }, +); diff --git a/packages/meritcore-lib/benchmark/serialization.js b/packages/meritcore-lib/benchmark/serialization.js index 7b084e6f36..9110e53fd4 100644 --- a/packages/meritcore-lib/benchmark/serialization.js +++ b/packages/meritcore-lib/benchmark/serialization.js @@ -13,110 +13,110 @@ var maxTime = 20; console.log('Benchmarking Block/Transaction Serialization'); console.log('---------------------------------------'); -async.series([ - function(next) { - - var buffers = []; - var hashBuffers = []; - console.log('Generating Random Test Data...'); - for (var i = 0; i < 100; i++) { - - // uint64le - var br = new bitcore.encoding.BufferWriter(); - var num = Math.round(Math.random() * 10000000000000); - br.writeUInt64LEBN(new bitcore.crypto.BN(num)); - buffers.push(br.toBuffer()); - - // hashes - var data = bitcore.crypto.Hash.sha256sha256(new Buffer(32)); - hashBuffers.push(data); - } - - var c = 0; - var bn; - - function readUInt64LEBN() { - if (c >= buffers.length) { - c = 0; +async.series( + [ + function(next) { + var buffers = []; + var hashBuffers = []; + console.log('Generating Random Test Data...'); + for (var i = 0; i < 100; i++) { + // uint64le + var br = new bitcore.encoding.BufferWriter(); + var num = Math.round(Math.random() * 10000000000000); + br.writeUInt64LEBN(new bitcore.crypto.BN(num)); + buffers.push(br.toBuffer()); + + // hashes + var data = bitcore.crypto.Hash.sha256sha256(new Buffer(32)); + hashBuffers.push(data); } - var buf = buffers[c]; - var br = new bitcore.encoding.BufferReader(buf); - bn = br.readUInt64LEBN(); - c++; - } - var reversed; + var c = 0; + var bn; + + function readUInt64LEBN() { + if (c >= buffers.length) { + c = 0; + } + var buf = buffers[c]; + var br = new bitcore.encoding.BufferReader(buf); + bn = br.readUInt64LEBN(); + c++; + } + + var reversed; + + function readReverse() { + if (c >= hashBuffers.length) { + c = 0; + } + var buf = hashBuffers[c]; + var br = new bitcore.encoding.BufferReader(buf); + reversed = br.readReverse(); + c++; + } - function readReverse() { - if (c >= hashBuffers.length) { - c = 0; + console.log('Starting benchmark...'); + + var suite = new benchmark.Suite(); + suite.add('bufferReader.readUInt64LEBN()', readUInt64LEBN, { maxTime: maxTime }); + suite.add('bufferReader.readReverse()', readReverse, { maxTime: maxTime }); + suite + .on('cycle', function(event) { + console.log(String(event.target)); + }) + .on('complete', function() { + console.log('Done'); + console.log('----------------------------------------------------------------------'); + next(); + }) + .run(); + }, + function(next) { + var block1; + var block2; + var block3; + + function bitcoreTest() { + block1 = bitcore.Block.fromString(blockData); } - var buf = hashBuffers[c]; - var br = new bitcore.encoding.BufferReader(buf); - reversed = br.readReverse(); - c++; - } - - console.log('Starting benchmark...'); - - var suite = new benchmark.Suite(); - suite.add('bufferReader.readUInt64LEBN()', readUInt64LEBN, {maxTime: maxTime}); - suite.add('bufferReader.readReverse()', readReverse, {maxTime: maxTime}); - suite - .on('cycle', function(event) { - console.log(String(event.target)); - }) - .on('complete', function() { - console.log('Done'); - console.log('----------------------------------------------------------------------'); - next(); - }) - .run(); + + function bitcoinJSTest() { + block2 = bitcoinjs.Block.fromHex(blockData); + } + + var parser = new bcoin.protocol.parser(); + + function bcoinTest() { + var raw = bcoin.utils.toArray(blockData, 'hex'); + var data = parser.parseBlock(raw); + block3 = new bcoin.block(data, 'block'); + } + + var blockDataMessage = '0000000000000000' + blockData; // add mock leading magic and size + + function fullnodeTest() { + fullnode.Block().fromHex(blockDataMessage); + } + + var suite = new benchmark.Suite(); + suite.add('bitcore', bitcoreTest, { maxTime: maxTime }); + suite.add('bitcoinjs', bitcoinJSTest, { maxTime: maxTime }); + suite.add('bcoin', bcoinTest, { maxTime: maxTime }); + suite.add('fullnode', fullnodeTest, { maxTime: maxTime }); + suite + .on('cycle', function(event) { + console.log(String(event.target)); + }) + .on('complete', function() { + console.log('Fastest is ' + this.filter('fastest').map('name')); + console.log('----------------------------------------------------------------------'); + next(); + }) + .run(); + }, + ], + function(err) { + console.log('Finished'); }, - function(next) { - - var block1; - var block2; - var block3; - - function bitcoreTest() { - block1 = bitcore.Block.fromString(blockData); - } - - function bitcoinJSTest() { - block2 = bitcoinjs.Block.fromHex(blockData); - } - - var parser = new bcoin.protocol.parser(); - - function bcoinTest() { - var raw = bcoin.utils.toArray(blockData, 'hex'); - var data = parser.parseBlock(raw); - block3 = new bcoin.block(data, 'block'); - } - - var blockDataMessage = '0000000000000000' + blockData; // add mock leading magic and size - - function fullnodeTest() { - fullnode.Block().fromHex(blockDataMessage); - } - - var suite = new benchmark.Suite(); - suite.add('bitcore', bitcoreTest, {maxTime: maxTime}); - suite.add('bitcoinjs', bitcoinJSTest, {maxTime: maxTime}); - suite.add('bcoin', bcoinTest, {maxTime: maxTime}); - suite.add('fullnode', fullnodeTest, {maxTime: maxTime}); - suite - .on('cycle', function(event) { - console.log(String(event.target)); - }) - .on('complete', function() { - console.log('Fastest is ' + this.filter('fastest').map('name')); - console.log('----------------------------------------------------------------------'); - next(); - }) - .run(); - } -], function(err) { - console.log('Finished'); -}); +); diff --git a/packages/meritcore-lib/bitcore-lib.js b/packages/meritcore-lib/bitcore-lib.js index 432dbeaf3b..d36a7d7234 100644 --- a/packages/meritcore-lib/bitcore-lib.js +++ b/packages/meritcore-lib/bitcore-lib.js @@ -1,54177 +1,57008 @@ -require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o'; + }; + + module.exports = Address; + + var Script = require('./script'); + }.call(this, require('buffer').Buffer)); + }, + { + './crypto/hash': 8, + './encoding/base58check': 13, + './errors': 17, + './networks': 21, + './publickey': 24, + './script': 25, + './util/js': 43, + './util/preconditions': 44, + buffer: 113, + lodash: 187, + }, + ], + 2: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var _ = require('lodash'); + var BlockHeader = require('./blockheader'); + var BN = require('../crypto/bn'); + var BufferUtil = require('../util/buffer'); + var BufferReader = require('../encoding/bufferreader'); + var BufferWriter = require('../encoding/bufferwriter'); + var Hash = require('../crypto/hash'); + var Transaction = require('../transaction'); + var $ = require('../util/preconditions'); + + /** + * Instantiate a Block from a Buffer, JSON object, or Object with + * the properties of the Block + * + * @param {*} - A Buffer, JSON string, or Object + * @returns {Block} + * @constructor + */ + function Block(arg) { + if (!(this instanceof Block)) { + return new Block(arg); + } + _.extend(this, Block._from(arg)); + return this; + } - if (!bufferVersion.network || (network && network !== bufferVersion.network)) { - throw new TypeError('Address has mismatched network type.'); - } + // https://github.com/bitcoin/bitcoin/blob/b5fa132329f0377d787a4a21c1686609c2bfaece/src/primitives/block.h#L14 + Block.MAX_BLOCK_SIZE = 1000000; + + /** + * @param {*} - A Buffer, JSON string or Object + * @returns {Object} - An object representing block data + * @throws {TypeError} - If the argument was not recognized + * @private + */ + Block._from = function _from(arg) { + var info = {}; + if (BufferUtil.isBuffer(arg)) { + info = Block._fromBufferReader(BufferReader(arg)); + } else if (_.isObject(arg)) { + info = Block._fromObject(arg); + } else { + throw new TypeError('Unrecognized argument for Block'); + } + return info; + }; + + /** + * @param {Object} - A plain JavaScript object + * @returns {Object} - An object representing block data + * @private + */ + Block._fromObject = function _fromObject(data) { + var transactions = []; + data.transactions.forEach(function(tx) { + if (tx instanceof Transaction) { + transactions.push(tx); + } else { + transactions.push(Transaction().fromObject(tx)); + } + }); + var info = { + header: BlockHeader.fromObject(data.header), + transactions: transactions, + }; + return info; + }; + + /** + * @param {Object} - A plain JavaScript object + * @returns {Block} - An instance of block + */ + Block.fromObject = function fromObject(obj) { + var info = Block._fromObject(obj); + return new Block(info); + }; + + /** + * @param {BufferReader} - Block data + * @returns {Object} - An object representing the block data + * @private + */ + Block._fromBufferReader = function _fromBufferReader(br) { + var info = {}; + $.checkState(!br.finished(), 'No block data received'); + info.header = BlockHeader.fromBufferReader(br); + var transactions = br.readVarintNum(); + info.transactions = []; + for (var i = 0; i < transactions; i++) { + info.transactions.push(Transaction().fromBufferReader(br)); + } + return info; + }; + + /** + * @param {BufferReader} - A buffer reader of the block + * @returns {Block} - An instance of block + */ + Block.fromBufferReader = function fromBufferReader(br) { + $.checkArgument(br, 'br is required'); + var info = Block._fromBufferReader(br); + return new Block(info); + }; + + /** + * @param {Buffer} - A buffer of the block + * @returns {Block} - An instance of block + */ + Block.fromBuffer = function fromBuffer(buf) { + return Block.fromBufferReader(new BufferReader(buf)); + }; + + /** + * @param {string} - str - A hex encoded string of the block + * @returns {Block} - A hex encoded string of the block + */ + Block.fromString = function fromString(str) { + var buf = new Buffer(str, 'hex'); + return Block.fromBuffer(buf); + }; + + /** + * @param {Binary} - Raw block binary data or buffer + * @returns {Block} - An instance of block + */ + Block.fromRawBlock = function fromRawBlock(data) { + if (!BufferUtil.isBuffer(data)) { + data = new Buffer(data, 'binary'); + } + var br = BufferReader(data); + br.pos = Block.Values.START_OF_BLOCK; + var info = Block._fromBufferReader(br); + return new Block(info); + }; + + /** + * @returns {Object} - A plain object with the block properties + */ + Block.prototype.toObject = Block.prototype.toJSON = function toObject() { + var transactions = []; + this.transactions.forEach(function(tx) { + transactions.push(tx.toObject()); + }); + return { + header: this.header.toObject(), + transactions: transactions, + }; + }; + + /** + * @returns {Buffer} - A buffer of the block + */ + Block.prototype.toBuffer = function toBuffer() { + return this.toBufferWriter().concat(); + }; + + /** + * @returns {string} - A hex encoded string of the block + */ + Block.prototype.toString = function toString() { + return this.toBuffer().toString('hex'); + }; + + /** + * @param {BufferWriter} - An existing instance of BufferWriter + * @returns {BufferWriter} - An instance of BufferWriter representation of the Block + */ + Block.prototype.toBufferWriter = function toBufferWriter(bw) { + if (!bw) { + bw = new BufferWriter(); + } + bw.write(this.header.toBuffer()); + bw.writeVarintNum(this.transactions.length); + for (var i = 0; i < this.transactions.length; i++) { + this.transactions[i].toBufferWriter(bw); + } + return bw; + }; + + /** + * Will iterate through each transaction and return an array of hashes + * @returns {Array} - An array with transaction hashes + */ + Block.prototype.getTransactionHashes = function getTransactionHashes() { + var hashes = []; + if (this.transactions.length === 0) { + return [Block.Values.NULL_HASH]; + } + for (var t = 0; t < this.transactions.length; t++) { + hashes.push(this.transactions[t]._getHash()); + } + return hashes; + }; + + /** + * Will build a merkle tree of all the transactions, ultimately arriving at + * a single point, the merkle root. + * @link https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees + * @returns {Array} - An array with each level of the tree after the other. + */ + Block.prototype.getMerkleTree = function getMerkleTree() { + var tree = this.getTransactionHashes(); + + var j = 0; + for (var size = this.transactions.length; size > 1; size = Math.floor((size + 1) / 2)) { + for (var i = 0; i < size; i += 2) { + var i2 = Math.min(i + 1, size - 1); + var buf = Buffer.concat([tree[j + i], tree[j + i2]]); + tree.push(Hash.sha256sha256(buf)); + } + j += size; + } - if (!bufferVersion.type || (type && type !== bufferVersion.type)) { - throw new TypeError('Address has mismatched type.'); - } + return tree; + }; + + /** + * Calculates the merkleRoot from the transactions. + * @returns {Buffer} - A buffer of the merkle root hash + */ + Block.prototype.getMerkleRoot = function getMerkleRoot() { + var tree = this.getMerkleTree(); + return tree[tree.length - 1]; + }; + + /** + * Verifies that the transactions in the block match the header merkle root + * @returns {Boolean} - If the merkle roots match + */ + Block.prototype.validMerkleRoot = function validMerkleRoot() { + var h = new BN(this.header.merkleRoot.toString('hex'), 'hex'); + var c = new BN(this.getMerkleRoot().toString('hex'), 'hex'); + + if (h.cmp(c) !== 0) { + return false; + } - info.hashBuffer = buffer.slice(1); - info.network = bufferVersion.network; - info.type = bufferVersion.type; - return info; -}; + return true; + }; + + /** + * @returns {Buffer} - The little endian hash buffer of the header + */ + Block.prototype._getHash = function() { + return this.header._getHash(); + }; + + var idProperty = { + configurable: false, + enumerable: true, + /** + * @returns {string} - The big endian hash buffer of the header + */ + get: function() { + if (!this._id) { + this._id = this.header.id; + } + return this._id; + }, + set: _.noop, + }; + Object.defineProperty(Block.prototype, 'id', idProperty); + Object.defineProperty(Block.prototype, 'hash', idProperty); + + /** + * @returns {string} - A string formatted for the console + */ + Block.prototype.inspect = function inspect() { + return ''; + }; + + Block.Values = { + START_OF_BLOCK: 8, // Start of block in raw block data + NULL_HASH: new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), + }; + + module.exports = Block; + }.call(this, require('buffer').Buffer)); + }, + { + '../crypto/bn': 6, + '../crypto/hash': 8, + '../encoding/bufferreader': 14, + '../encoding/bufferwriter': 15, + '../transaction': 28, + '../util/buffer': 42, + '../util/preconditions': 44, + './blockheader': 3, + buffer: 113, + lodash: 187, + }, + ], + 3: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var _ = require('lodash'); + var BN = require('../crypto/bn'); + var BufferUtil = require('../util/buffer'); + var BufferReader = require('../encoding/bufferreader'); + var BufferWriter = require('../encoding/bufferwriter'); + var Hash = require('../crypto/hash'); + var JSUtil = require('../util/js'); + var $ = require('../util/preconditions'); + + var GENESIS_BITS = 0x1d00ffff; + + /** + * Instantiate a BlockHeader from a Buffer, JSON object, or Object with + * the properties of the BlockHeader + * + * @param {*} - A Buffer, JSON string, or Object + * @returns {BlockHeader} - An instance of block header + * @constructor + */ + var BlockHeader = function BlockHeader(arg) { + if (!(this instanceof BlockHeader)) { + return new BlockHeader(arg); + } + var info = BlockHeader._from(arg); + this.version = info.version; + this.prevHash = info.prevHash; + this.merkleRoot = info.merkleRoot; + this.time = info.time; + this.timestamp = info.time; + this.bits = info.bits; + this.nonce = info.nonce; + + if (info.hash) { + $.checkState(this.hash === info.hash, 'Argument object hash property does not match block hash.'); + } -/** - * Internal function to transform a {@link PublicKey} - * - * @param {PublicKey} pubkey - An instance of PublicKey - * @returns {Object} An object with keys: hashBuffer, type - * @private - */ -Address._transformPublicKey = function(pubkey) { - var info = {}; - if (!(pubkey instanceof PublicKey)) { - throw new TypeError('Address must be an instance of PublicKey.'); - } - info.hashBuffer = Hash.sha256ripemd160(pubkey.toBuffer()); - info.type = Address.PayToPublicKeyHash; - return info; -}; + return this; + }; + + /** + * @param {*} - A Buffer, JSON string or Object + * @returns {Object} - An object representing block header data + * @throws {TypeError} - If the argument was not recognized + * @private + */ + BlockHeader._from = function _from(arg) { + var info = {}; + if (BufferUtil.isBuffer(arg)) { + info = BlockHeader._fromBufferReader(BufferReader(arg)); + } else if (_.isObject(arg)) { + info = BlockHeader._fromObject(arg); + } else { + throw new TypeError('Unrecognized argument for BlockHeader'); + } + return info; + }; + + /** + * @param {Object} - A JSON string + * @returns {Object} - An object representing block header data + * @private + */ + BlockHeader._fromObject = function _fromObject(data) { + $.checkArgument(data, 'data is required'); + var prevHash = data.prevHash; + var merkleRoot = data.merkleRoot; + if (_.isString(data.prevHash)) { + prevHash = BufferUtil.reverse(new Buffer(data.prevHash, 'hex')); + } + if (_.isString(data.merkleRoot)) { + merkleRoot = BufferUtil.reverse(new Buffer(data.merkleRoot, 'hex')); + } + var info = { + hash: data.hash, + version: data.version, + prevHash: prevHash, + merkleRoot: merkleRoot, + time: data.time, + timestamp: data.time, + bits: data.bits, + nonce: data.nonce, + }; + return info; + }; + + /** + * @param {Object} - A plain JavaScript object + * @returns {BlockHeader} - An instance of block header + */ + BlockHeader.fromObject = function fromObject(obj) { + var info = BlockHeader._fromObject(obj); + return new BlockHeader(info); + }; + + /** + * @param {Binary} - Raw block binary data or buffer + * @returns {BlockHeader} - An instance of block header + */ + BlockHeader.fromRawBlock = function fromRawBlock(data) { + if (!BufferUtil.isBuffer(data)) { + data = new Buffer(data, 'binary'); + } + var br = BufferReader(data); + br.pos = BlockHeader.Constants.START_OF_HEADER; + var info = BlockHeader._fromBufferReader(br); + return new BlockHeader(info); + }; + + /** + * @param {Buffer} - A buffer of the block header + * @returns {BlockHeader} - An instance of block header + */ + BlockHeader.fromBuffer = function fromBuffer(buf) { + var info = BlockHeader._fromBufferReader(BufferReader(buf)); + return new BlockHeader(info); + }; + + /** + * @param {string} - A hex encoded buffer of the block header + * @returns {BlockHeader} - An instance of block header + */ + BlockHeader.fromString = function fromString(str) { + var buf = new Buffer(str, 'hex'); + return BlockHeader.fromBuffer(buf); + }; + + /** + * @param {BufferReader} - A BufferReader of the block header + * @returns {Object} - An object representing block header data + * @private + */ + BlockHeader._fromBufferReader = function _fromBufferReader(br) { + var info = {}; + info.version = br.readInt32LE(); + info.prevHash = br.read(32); + info.merkleRoot = br.read(32); + info.time = br.readUInt32LE(); + info.bits = br.readUInt32LE(); + info.nonce = br.readUInt32LE(); + return info; + }; + + /** + * @param {BufferReader} - A BufferReader of the block header + * @returns {BlockHeader} - An instance of block header + */ + BlockHeader.fromBufferReader = function fromBufferReader(br) { + var info = BlockHeader._fromBufferReader(br); + return new BlockHeader(info); + }; + + /** + * @returns {Object} - A plain object of the BlockHeader + */ + BlockHeader.prototype.toObject = BlockHeader.prototype.toJSON = function toObject() { + return { + hash: this.hash, + version: this.version, + prevHash: BufferUtil.reverse(this.prevHash).toString('hex'), + merkleRoot: BufferUtil.reverse(this.merkleRoot).toString('hex'), + time: this.time, + bits: this.bits, + nonce: this.nonce, + }; + }; + + /** + * @returns {Buffer} - A Buffer of the BlockHeader + */ + BlockHeader.prototype.toBuffer = function toBuffer() { + return this.toBufferWriter().concat(); + }; + + /** + * @returns {string} - A hex encoded string of the BlockHeader + */ + BlockHeader.prototype.toString = function toString() { + return this.toBuffer().toString('hex'); + }; + + /** + * @param {BufferWriter} - An existing instance BufferWriter + * @returns {BufferWriter} - An instance of BufferWriter representation of the BlockHeader + */ + BlockHeader.prototype.toBufferWriter = function toBufferWriter(bw) { + if (!bw) { + bw = new BufferWriter(); + } + bw.writeInt32LE(this.version); + bw.write(this.prevHash); + bw.write(this.merkleRoot); + bw.writeUInt32LE(this.time); + bw.writeUInt32LE(this.bits); + bw.writeUInt32LE(this.nonce); + return bw; + }; + + /** + * Returns the target difficulty for this block + * @param {Number} bits + * @returns {BN} An instance of BN with the decoded difficulty bits + */ + BlockHeader.prototype.getTargetDifficulty = function getTargetDifficulty(bits) { + bits = bits || this.bits; + + var target = new BN(bits & 0xffffff); + var mov = 8 * ((bits >>> 24) - 3); + while (mov-- > 0) { + target = target.mul(new BN(2)); + } + return target; + }; + + /** + * @link https://en.bitcoin.it/wiki/Difficulty + * @return {Number} + */ + BlockHeader.prototype.getDifficulty = function getDifficulty() { + var difficulty1TargetBN = this.getTargetDifficulty(GENESIS_BITS).mul(new BN(Math.pow(10, 8))); + var currentTargetBN = this.getTargetDifficulty(); + + var difficultyString = difficulty1TargetBN.div(currentTargetBN).toString(10); + var decimalPos = difficultyString.length - 8; + difficultyString = difficultyString.slice(0, decimalPos) + '.' + difficultyString.slice(decimalPos); + + return parseFloat(difficultyString); + }; + + /** + * @returns {Buffer} - The little endian hash buffer of the header + */ + BlockHeader.prototype._getHash = function hash() { + var buf = this.toBuffer(); + return Hash.sha256sha256(buf); + }; + + var idProperty = { + configurable: false, + enumerable: true, + /** + * @returns {string} - The big endian hash buffer of the header + */ + get: function() { + if (!this._id) { + this._id = BufferReader(this._getHash()) + .readReverse() + .toString('hex'); + } + return this._id; + }, + set: _.noop, + }; + Object.defineProperty(BlockHeader.prototype, 'id', idProperty); + Object.defineProperty(BlockHeader.prototype, 'hash', idProperty); + + /** + * @returns {Boolean} - If timestamp is not too far in the future + */ + BlockHeader.prototype.validTimestamp = function validTimestamp() { + var currentTime = Math.round(new Date().getTime() / 1000); + if (this.time > currentTime + BlockHeader.Constants.MAX_TIME_OFFSET) { + return false; + } + return true; + }; -/** - * Internal function to transform a {@link Script} into a `info` object. - * - * @param {Script} script - An instance of Script - * @returns {Object} An object with keys: hashBuffer, type - * @private - */ -Address._transformScript = function(script, network) { - $.checkArgument(script instanceof Script, 'script must be a Script instance'); - var info = script.getAddressInfo(network); - if (!info) { - throw new errors.Script.CantDeriveAddress(script); - } - return info; -}; + /** + * @returns {Boolean} - If the proof-of-work hash satisfies the target difficulty + */ + BlockHeader.prototype.validProofOfWork = function validProofOfWork() { + var pow = new BN(this.id, 'hex'); + var target = this.getTargetDifficulty(); -/** - * Creates a P2SH address from a set of public keys and a threshold. - * - * The addresses will be sorted lexicographically, as that is the trend in Merit. - * To create an address from unsorted public keys, use the {@link Script#buildMultisigOut} - * interface. - * - * @param {Array} publicKeys - a set of public keys to create an address - * @param {number} threshold - the number of signatures needed to release the funds - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @return {Address} - */ -Address.createMultisig = function(publicKeys, threshold, network) { - network = network || publicKeys[0].network || Networks.defaultNetwork; - return Address.payingTo(Script.buildMultisigOut(publicKeys, threshold), network); -}; + if (pow.cmp(target) > 0) { + return false; + } + return true; + }; + + /** + * @returns {string} - A string formatted for the console + */ + BlockHeader.prototype.inspect = function inspect() { + return ''; + }; + + BlockHeader.Constants = { + START_OF_HEADER: 8, // Start buffer position in raw block data + MAX_TIME_OFFSET: 2 * 60 * 60, // The max a timestamp can be in the future + LARGEST_HASH: new BN('10000000000000000000000000000000000000000000000000000000000000000', 'hex'), + }; + + module.exports = BlockHeader; + }.call(this, require('buffer').Buffer)); + }, + { + '../crypto/bn': 6, + '../crypto/hash': 8, + '../encoding/bufferreader': 14, + '../encoding/bufferwriter': 15, + '../util/buffer': 42, + '../util/js': 43, + '../util/preconditions': 44, + buffer: 113, + lodash: 187, + }, + ], + 4: [ + function(require, module, exports) { + module.exports = require('./block'); -/** - * Internal function to transform a Merit address string - * - * @param {string} data - * @param {String|Network=} network - either a Network instance, 'livenet', or 'testnet' - * @param {string=} type - The type: 'pubkeyhash' or 'scripthash' - * @returns {Object} An object with keys: hashBuffer, network and type - * @private - */ -Address._transformString = function(data, network, type) { - if (typeof(data) !== 'string') { - throw new TypeError('data parameter supplied is not a string.'); - } - data = data.trim(); - var addressBuffer = Base58Check.decode(data); - var info = Address._transformBuffer(addressBuffer, network, type); - return info; -}; - -/** - * Instantiate an address from a PublicKey instance - * - * @param {PublicKey} data - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @returns {Address} A new valid and frozen instance of an Address - */ -Address.fromPublicKey = function(data, network) { - var info = Address._transformPublicKey(data); - network = network || Networks.defaultNetwork; - return new Address(info.hashBuffer, network, info.type); -}; - -/** - * Instantiate an address from a ripemd160 public key hash - * - * @param {Buffer} hash - An instance of buffer of the hash - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @returns {Address} A new valid and frozen instance of an Address - */ -Address.fromPublicKeyHash = function(hash, network) { - var info = Address._transformHash(hash); - return new Address(info.hashBuffer, network, Address.PayToPublicKeyHash); -}; + module.exports.BlockHeader = require('./blockheader'); + module.exports.MerkleBlock = require('./merkleblock'); + }, + { './block': 2, './blockheader': 3, './merkleblock': 5 }, + ], + 5: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var _ = require('lodash'); + var BlockHeader = require('./blockheader'); + var BufferUtil = require('../util/buffer'); + var BufferReader = require('../encoding/bufferreader'); + var BufferWriter = require('../encoding/bufferwriter'); + var Hash = require('../crypto/hash'); + var JSUtil = require('../util/js'); + var Transaction = require('../transaction'); + var $ = require('../util/preconditions'); + + /** + * Instantiate a MerkleBlock from a Buffer, JSON object, or Object with + * the properties of the Block + * + * @param {*} - A Buffer, JSON string, or Object representing a MerkleBlock + * @returns {MerkleBlock} + * @constructor + */ + function MerkleBlock(arg) { + /* jshint maxstatements: 18 */ + + if (!(this instanceof MerkleBlock)) { + return new MerkleBlock(arg); + } -/** - * Instantiate an address from a ripemd160 script hash - * - * @param {Buffer} hash - An instance of buffer of the hash - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @returns {Address} A new valid and frozen instance of an Address - */ -Address.fromScriptHash = function(hash, network) { - $.checkArgument(hash, 'hash parameter is required'); - var info = Address._transformHash(hash); - return new Address(info.hashBuffer, network, Address.PayToScriptHash); -}; - -/** - * Builds a p2sh address paying to script. This will hash the script and - * use that to create the address. - * If you want to extract an address associated with a script instead, - * see {{Address#fromScript}} - * - * @param {Script} script - An instance of Script - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @returns {Address} A new valid and frozen instance of an Address - */ -Address.payingTo = function(script, network) { - $.checkArgument(script, 'script is required'); - $.checkArgument(script instanceof Script, 'script must be instance of Script'); - - return Address.fromScriptHash(Hash.sha256ripemd160(script.toBuffer()), network); -}; - -/** - * Extract address from a Script. The script must be of one - * of the following types: p2pkh input, p2pkh output, p2sh input - * or p2sh output. - * This will analyze the script and extract address information from it. - * If you want to transform any script to a p2sh Address paying - * to that script's hash instead, use {{Address#payingTo}} - * - * @param {Script} script - An instance of Script - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @returns {Address} A new valid and frozen instance of an Address - */ -Address.fromScript = function(script, network) { - $.checkArgument(script instanceof Script, 'script must be a Script instance'); - var info = Address._transformScript(script, network); - return new Address(info.hashBuffer, network, info.type); -}; - -/** - * Instantiate an address from a buffer of the address - * - * @param {Buffer} buffer - An instance of buffer of the address - * @param {String|Network=} network - either a Network instance, 'livenet', or 'testnet' - * @param {string=} type - The type of address: 'script' or 'pubkey' - * @returns {Address} A new valid and frozen instance of an Address - */ -Address.fromBuffer = function(buffer, network, type) { - var info = Address._transformBuffer(buffer, network, type); - return new Address(info.hashBuffer, info.network, info.type); -}; + var info = {}; + if (BufferUtil.isBuffer(arg)) { + info = MerkleBlock._fromBufferReader(BufferReader(arg)); + } else if (_.isObject(arg)) { + var header; + if (arg.header instanceof BlockHeader) { + header = arg.header; + } else { + header = BlockHeader.fromObject(arg.header); + } + info = { + /** + * @name MerkleBlock#header + * @type {BlockHeader} + */ + header: header, + /** + * @name MerkleBlock#numTransactions + * @type {Number} + */ + numTransactions: arg.numTransactions, + /** + * @name MerkleBlock#hashes + * @type {String[]} + */ + hashes: arg.hashes, + /** + * @name MerkleBlock#flags + * @type {Number[]} + */ + flags: arg.flags, + }; + } else { + throw new TypeError('Unrecognized argument for MerkleBlock'); + } + _.extend(this, info); + this._flagBitsUsed = 0; + this._hashesUsed = 0; + return this; + } -/** - * Instantiate an address from an address string - * - * @param {string} str - An string of the Merit address - * @param {String|Network=} network - either a Network instance, 'livenet', or 'testnet' - * @param {string=} type - The type of address: 'script' or 'pubkey' - * @returns {Address} A new valid and frozen instance of an Address - */ -Address.fromString = function(str, network, type) { - var info = Address._transformString(str, network, type); - return new Address(info.hashBuffer, info.network, info.type); -}; + /** + * @param {Buffer} - MerkleBlock data in a Buffer object + * @returns {MerkleBlock} - A MerkleBlock object + */ + MerkleBlock.fromBuffer = function fromBuffer(buf) { + return MerkleBlock.fromBufferReader(BufferReader(buf)); + }; + + /** + * @param {BufferReader} - MerkleBlock data in a BufferReader object + * @returns {MerkleBlock} - A MerkleBlock object + */ + MerkleBlock.fromBufferReader = function fromBufferReader(br) { + return new MerkleBlock(MerkleBlock._fromBufferReader(br)); + }; + + /** + * @returns {Buffer} - A buffer of the block + */ + MerkleBlock.prototype.toBuffer = function toBuffer() { + return this.toBufferWriter().concat(); + }; + + /** + * @param {BufferWriter} - An existing instance of BufferWriter + * @returns {BufferWriter} - An instance of BufferWriter representation of the MerkleBlock + */ + MerkleBlock.prototype.toBufferWriter = function toBufferWriter(bw) { + if (!bw) { + bw = new BufferWriter(); + } + bw.write(this.header.toBuffer()); + bw.writeUInt32LE(this.numTransactions); + bw.writeVarintNum(this.hashes.length); + for (var i = 0; i < this.hashes.length; i++) { + bw.write(new Buffer(this.hashes[i], 'hex')); + } + bw.writeVarintNum(this.flags.length); + for (i = 0; i < this.flags.length; i++) { + bw.writeUInt8(this.flags[i]); + } + return bw; + }; + + /** + * @returns {Object} - A plain object with the MerkleBlock properties + */ + MerkleBlock.prototype.toObject = MerkleBlock.prototype.toJSON = function toObject() { + return { + header: this.header.toObject(), + numTransactions: this.numTransactions, + hashes: this.hashes, + flags: this.flags, + }; + }; + + /** + * Verify that the MerkleBlock is valid + * @returns {Boolean} - True/False whether this MerkleBlock is Valid + */ + MerkleBlock.prototype.validMerkleTree = function validMerkleTree() { + $.checkState(_.isArray(this.flags), 'MerkleBlock flags is not an array'); + $.checkState(_.isArray(this.hashes), 'MerkleBlock hashes is not an array'); + + // Can't have more hashes than numTransactions + if (this.hashes.length > this.numTransactions) { + return false; + } -/** - * Instantiate an address from an Object - * - * @param {string} json - An JSON string or Object with keys: hash, network and type - * @returns {Address} A new valid instance of an Address - */ -Address.fromObject = function fromObject(obj) { - $.checkState( - JSUtil.isHexa(obj.hash), - 'Unexpected hash property, "' + obj.hash + '", expected to be hex.' - ); - var hashBuffer = new Buffer(obj.hash, 'hex'); - return new Address(hashBuffer, obj.network, obj.type); -}; - -/** - * Will return a validation error if exists - * - * @example - * ```javascript - * // a network mismatch error - * var error = Address.getValidationError('15vkcKf7gB23wLAnZLmbVuMiiVDc1Nm4a2', 'testnet'); - * ``` - * - * @param {string} data - The encoded data - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @param {string} type - The type of address: 'script' or 'pubkey' - * @returns {null|Error} The corresponding error message - */ -Address.getValidationError = function(data, network, type) { - var error; - try { - /* jshint nonew: false */ - new Address(data, network, type); - } catch (e) { - error = e; - } - return error; -}; + // Can't have more flag bits than num hashes + if (this.flags.length * 8 < this.hashes.length) { + return false; + } -/** - * Will return a boolean if an address is valid - * - * @example - * ```javascript - * assert(Address.isValid('15vkcKf7gB23wLAnZLmbVuMiiVDc1Nm4a2', 'livenet')); - * ``` - * - * @param {string} data - The encoded data - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @param {string} type - The type of address: 'script' or 'pubkey' - * @returns {boolean} The corresponding error message - */ -Address.isValid = function(data, network, type) { - return !Address.getValidationError(data, network, type); -}; + var height = this._calcTreeHeight(); + var opts = { hashesUsed: 0, flagBitsUsed: 0 }; + var root = this._traverseMerkleTree(height, 0, opts); + if (opts.hashesUsed !== this.hashes.length) { + return false; + } + return BufferUtil.equals(root, this.header.merkleRoot); + }; + + /** + * Traverse a the tree in this MerkleBlock, validating it along the way + * Modeled after Merit Core merkleblock.cpp TraverseAndExtract() + * @param {Number} - depth - Current height + * @param {Number} - pos - Current position in the tree + * @param {Object} - opts - Object with values that need to be mutated throughout the traversal + * @param {Number} - opts.flagBitsUsed - Number of flag bits used, should start at 0 + * @param {Number} - opts.hashesUsed - Number of hashes used, should start at 0 + * @param {Array} - opts.txs - Will finish populated by transactions found during traversal + * @returns {Buffer|null} - Buffer containing the Merkle Hash for that height + * @private + */ + MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, pos, opts) { + /* jshint maxcomplexity: 12*/ + /* jshint maxstatements: 20 */ + + opts = opts || {}; + opts.txs = opts.txs || []; + opts.flagBitsUsed = opts.flagBitsUsed || 0; + opts.hashesUsed = opts.hashesUsed || 0; + + if (opts.flagBitsUsed > this.flags.length * 8) { + return null; + } + var isParentOfMatch = (this.flags[opts.flagBitsUsed >> 3] >>> (opts.flagBitsUsed++ & 7)) & 1; + if (depth === 0 || !isParentOfMatch) { + if (opts.hashesUsed >= this.hashes.length) { + return null; + } + var hash = this.hashes[opts.hashesUsed++]; + if (depth === 0 && isParentOfMatch) { + opts.txs.push(hash); + } + return new Buffer(hash, 'hex'); + } else { + var left = this._traverseMerkleTree(depth - 1, pos * 2, opts); + var right = left; + if (pos * 2 + 1 < this._calcTreeWidth(depth - 1)) { + right = this._traverseMerkleTree(depth - 1, pos * 2 + 1, opts); + } + return Hash.sha256sha256(new Buffer.concat([left, right])); + } + }; + + /** Calculates the width of a merkle tree at a given height. + * Modeled after Merit Core merkleblock.h CalcTreeWidth() + * @param {Number} - Height at which we want the tree width + * @returns {Number} - Width of the tree at a given height + * @private + */ + MerkleBlock.prototype._calcTreeWidth = function calcTreeWidth(height) { + return (this.numTransactions + (1 << height) - 1) >> height; + }; + + /** Calculates the height of the merkle tree in this MerkleBlock + * @param {Number} - Height at which we want the tree width + * @returns {Number} - Height of the merkle tree in this MerkleBlock + * @private + */ + MerkleBlock.prototype._calcTreeHeight = function calcTreeHeight() { + var height = 0; + while (this._calcTreeWidth(height) > 1) { + height++; + } + return height; + }; + + /** + * @param {Transaction|String} - Transaction or Transaction ID Hash + * @returns {Boolean} - return true/false if this MerkleBlock has the TX or not + * @private + */ + MerkleBlock.prototype.hasTransaction = function hasTransaction(tx) { + $.checkArgument(!_.isUndefined(tx), 'tx cannot be undefined'); + $.checkArgument( + tx instanceof Transaction || typeof tx === 'string', + 'Invalid tx given, tx must be a "string" or "Transaction"', + ); + + var hash = tx; + if (tx instanceof Transaction) { + // We need to reverse the id hash for the lookup + hash = BufferUtil.reverse(new Buffer(tx.id, 'hex')).toString('hex'); + } -/** - * Returns true if an address is of pay to public key hash type - * @return boolean - */ -Address.prototype.isPayToPublicKeyHash = function() { - return this.type === Address.PayToPublicKeyHash; -}; + var txs = []; + var height = this._calcTreeHeight(); + this._traverseMerkleTree(height, 0, { txs: txs }); + return txs.indexOf(hash) !== -1; + }; + + /** + * @param {Buffer} - MerkleBlock data + * @returns {Object} - An Object representing merkleblock data + * @private + */ + MerkleBlock._fromBufferReader = function _fromBufferReader(br) { + $.checkState(!br.finished(), 'No merkleblock data received'); + var info = {}; + info.header = BlockHeader.fromBufferReader(br); + info.numTransactions = br.readUInt32LE(); + var numHashes = br.readVarintNum(); + info.hashes = []; + for (var i = 0; i < numHashes; i++) { + info.hashes.push(br.read(32).toString('hex')); + } + var numFlags = br.readVarintNum(); + info.flags = []; + for (i = 0; i < numFlags; i++) { + info.flags.push(br.readUInt8()); + } + return info; + }; + + /** + * @param {Object} - A plain JavaScript object + * @returns {Block} - An instance of block + */ + MerkleBlock.fromObject = function fromObject(obj) { + return new MerkleBlock(obj); + }; + + module.exports = MerkleBlock; + }.call(this, require('buffer').Buffer)); + }, + { + '../crypto/hash': 8, + '../encoding/bufferreader': 14, + '../encoding/bufferwriter': 15, + '../transaction': 28, + '../util/buffer': 42, + '../util/js': 43, + '../util/preconditions': 44, + './blockheader': 3, + buffer: 113, + lodash: 187, + }, + ], + 6: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var BN = require('bn.js'); + var $ = require('../util/preconditions'); + var _ = require('lodash'); + + var reversebuf = function(buf) { + var buf2 = new Buffer(buf.length); + for (var i = 0; i < buf.length; i++) { + buf2[i] = buf[buf.length - 1 - i]; + } + return buf2; + }; + + BN.Zero = new BN(0); + BN.One = new BN(1); + BN.Minus1 = new BN(-1); + + BN.fromNumber = function(n) { + $.checkArgument(_.isNumber(n)); + return new BN(n); + }; + + BN.fromString = function(str, base) { + $.checkArgument(_.isString(str)); + return new BN(str, base); + }; + + BN.fromBuffer = function(buf, opts) { + if (typeof opts !== 'undefined' && opts.endian === 'little') { + buf = reversebuf(buf); + } + var hex = buf.toString('hex'); + var bn = new BN(hex, 16); + return bn; + }; + + /** + * Instantiate a BigNumber from a "signed magnitude buffer" + * (a buffer where the most significant bit represents the sign (0 = positive, -1 = negative)) + */ + BN.fromSM = function(buf, opts) { + var ret; + if (buf.length === 0) { + return BN.fromBuffer(new Buffer([0])); + } -/** - * Returns true if an address is of pay to script hash type - * @return boolean - */ -Address.prototype.isPayToScriptHash = function() { - return this.type === Address.PayToScriptHash; -}; + var endian = 'big'; + if (opts) { + endian = opts.endian; + } + if (endian === 'little') { + buf = reversebuf(buf); + } -/** - * Will return a buffer representation of the address - * - * @returns {Buffer} Merit address buffer - */ -Address.prototype.toBuffer = function() { - var version = new Buffer([this.network[this.type]]); - var buf = Buffer.concat([version, this.hashBuffer]); - return buf; -}; - -/** - * @returns {Object} A plain object with the address information - */ -Address.prototype.toObject = Address.prototype.toJSON = function toObject() { - return { - hash: this.hashBuffer.toString('hex'), - type: this.type, - network: this.network.toString() - }; -}; - -/** - * Will return a the string representation of the address - * - * @returns {string} Merit address - */ -Address.prototype.toString = function() { - return Base58Check.encode(this.toBuffer()); -}; + if (buf[0] & 0x80) { + buf[0] = buf[0] & 0x7f; + ret = BN.fromBuffer(buf); + ret.neg().copy(ret); + } else { + ret = BN.fromBuffer(buf); + } + return ret; + }; + + BN.prototype.toNumber = function() { + return parseInt(this.toString(10), 10); + }; + + BN.prototype.toBuffer = function(opts) { + var buf, hex; + if (opts && opts.size) { + hex = this.toString(16, 2); + var natlen = hex.length / 2; + buf = new Buffer(hex, 'hex'); + + if (natlen === opts.size) { + buf = buf; + } else if (natlen > opts.size) { + buf = BN.trim(buf, natlen); + } else if (natlen < opts.size) { + buf = BN.pad(buf, natlen, opts.size); + } + } else { + hex = this.toString(16, 2); + buf = new Buffer(hex, 'hex'); + } -/** - * Will return a string formatted for the console - * - * @returns {string} Merit address - */ -Address.prototype.inspect = function() { - return ''; -}; - -module.exports = Address; - -var Script = require('./script'); - -}).call(this,require("buffer").Buffer) -},{"./crypto/hash":8,"./encoding/base58check":13,"./errors":17,"./networks":21,"./publickey":24,"./script":25,"./util/js":43,"./util/preconditions":44,"buffer":113,"lodash":187}],2:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var BlockHeader = require('./blockheader'); -var BN = require('../crypto/bn'); -var BufferUtil = require('../util/buffer'); -var BufferReader = require('../encoding/bufferreader'); -var BufferWriter = require('../encoding/bufferwriter'); -var Hash = require('../crypto/hash'); -var Transaction = require('../transaction'); -var $ = require('../util/preconditions'); - -/** - * Instantiate a Block from a Buffer, JSON object, or Object with - * the properties of the Block - * - * @param {*} - A Buffer, JSON string, or Object - * @returns {Block} - * @constructor - */ -function Block(arg) { - if (!(this instanceof Block)) { - return new Block(arg); - } - _.extend(this, Block._from(arg)); - return this; -} + if (typeof opts !== 'undefined' && opts.endian === 'little') { + buf = reversebuf(buf); + } -// https://github.com/bitcoin/bitcoin/blob/b5fa132329f0377d787a4a21c1686609c2bfaece/src/primitives/block.h#L14 -Block.MAX_BLOCK_SIZE = 1000000; + return buf; + }; + + BN.prototype.toSMBigEndian = function() { + var buf; + if (this.cmp(BN.Zero) === -1) { + buf = this.neg().toBuffer(); + if (buf[0] & 0x80) { + buf = Buffer.concat([new Buffer([0x80]), buf]); + } else { + buf[0] = buf[0] | 0x80; + } + } else { + buf = this.toBuffer(); + if (buf[0] & 0x80) { + buf = Buffer.concat([new Buffer([0x00]), buf]); + } + } -/** - * @param {*} - A Buffer, JSON string or Object - * @returns {Object} - An object representing block data - * @throws {TypeError} - If the argument was not recognized - * @private - */ -Block._from = function _from(arg) { - var info = {}; - if (BufferUtil.isBuffer(arg)) { - info = Block._fromBufferReader(BufferReader(arg)); - } else if (_.isObject(arg)) { - info = Block._fromObject(arg); - } else { - throw new TypeError('Unrecognized argument for Block'); - } - return info; -}; + if ((buf.length === 1) & (buf[0] === 0)) { + buf = new Buffer([]); + } + return buf; + }; -/** - * @param {Object} - A plain JavaScript object - * @returns {Object} - An object representing block data - * @private - */ -Block._fromObject = function _fromObject(data) { - var transactions = []; - data.transactions.forEach(function(tx) { - if (tx instanceof Transaction) { - transactions.push(tx); - } else { - transactions.push(Transaction().fromObject(tx)); - } - }); - var info = { - header: BlockHeader.fromObject(data.header), - transactions: transactions - }; - return info; -}; - -/** - * @param {Object} - A plain JavaScript object - * @returns {Block} - An instance of block - */ -Block.fromObject = function fromObject(obj) { - var info = Block._fromObject(obj); - return new Block(info); -}; - -/** - * @param {BufferReader} - Block data - * @returns {Object} - An object representing the block data - * @private - */ -Block._fromBufferReader = function _fromBufferReader(br) { - var info = {}; - $.checkState(!br.finished(), 'No block data received'); - info.header = BlockHeader.fromBufferReader(br); - var transactions = br.readVarintNum(); - info.transactions = []; - for (var i = 0; i < transactions; i++) { - info.transactions.push(Transaction().fromBufferReader(br)); - } - return info; -}; + BN.prototype.toSM = function(opts) { + var endian = opts ? opts.endian : 'big'; + var buf = this.toSMBigEndian(); -/** - * @param {BufferReader} - A buffer reader of the block - * @returns {Block} - An instance of block - */ -Block.fromBufferReader = function fromBufferReader(br) { - $.checkArgument(br, 'br is required'); - var info = Block._fromBufferReader(br); - return new Block(info); -}; - -/** - * @param {Buffer} - A buffer of the block - * @returns {Block} - An instance of block - */ -Block.fromBuffer = function fromBuffer(buf) { - return Block.fromBufferReader(new BufferReader(buf)); -}; + if (endian === 'little') { + buf = reversebuf(buf); + } + return buf; + }; + + /** + * Create a BN from a "ScriptNum": + * This is analogous to the constructor for CScriptNum in meritd. Many ops in + * meritd's script interpreter use CScriptNum, which is not really a proper + * bignum. Instead, an error is thrown if trying to input a number bigger than + * 4 bytes. We copy that behavior here. A third argument, `size`, is provided to + * extend the hard limit of 4 bytes, as some usages require more than 4 bytes. + */ + BN.fromScriptNumBuffer = function(buf, fRequireMinimal, size) { + var nMaxNumSize = size || 4; + $.checkArgument(buf.length <= nMaxNumSize, new Error('script number overflow')); + if (fRequireMinimal && buf.length > 0) { + // Check that the number is encoded with the minimum possible + // number of bytes. + // + // If the most-significant-byte - excluding the sign bit - is zero + // then we're not minimal. Note how this test also rejects the + // negative-zero encoding, 0x80. + if ((buf[buf.length - 1] & 0x7f) === 0) { + // One exception: if there's more than one byte and the most + // significant bit of the second-most-significant-byte is set + // it would conflict with the sign bit. An example of this case + // is +-255, which encode to 0xff00 and 0xff80 respectively. + // (big-endian). + if (buf.length <= 1 || (buf[buf.length - 2] & 0x80) === 0) { + throw new Error('non-minimally encoded script number'); + } + } + } + return BN.fromSM(buf, { + endian: 'little', + }); + }; + + /** + * The corollary to the above, with the notable exception that we do not throw + * an error if the output is larger than four bytes. (Which can happen if + * performing a numerical operation that results in an overflow to more than 4 + * bytes). + */ + BN.prototype.toScriptNumBuffer = function() { + return this.toSM({ + endian: 'little', + }); + }; + + BN.prototype.gt = function(b) { + return this.cmp(b) > 0; + }; + + BN.prototype.gte = function(b) { + return this.cmp(b) >= 0; + }; + + BN.prototype.lt = function(b) { + return this.cmp(b) < 0; + }; + + BN.trim = function(buf, natlen) { + return buf.slice(natlen - buf.length, buf.length); + }; + + BN.pad = function(buf, natlen, size) { + var rbuf = new Buffer(size); + for (var i = 0; i < buf.length; i++) { + rbuf[rbuf.length - 1 - i] = buf[buf.length - 1 - i]; + } + for (i = 0; i < size - natlen; i++) { + rbuf[i] = 0; + } + return rbuf; + }; -/** - * @param {string} - str - A hex encoded string of the block - * @returns {Block} - A hex encoded string of the block - */ -Block.fromString = function fromString(str) { - var buf = new Buffer(str, 'hex'); - return Block.fromBuffer(buf); -}; - -/** - * @param {Binary} - Raw block binary data or buffer - * @returns {Block} - An instance of block - */ -Block.fromRawBlock = function fromRawBlock(data) { - if (!BufferUtil.isBuffer(data)) { - data = new Buffer(data, 'binary'); - } - var br = BufferReader(data); - br.pos = Block.Values.START_OF_BLOCK; - var info = Block._fromBufferReader(br); - return new Block(info); -}; - -/** - * @returns {Object} - A plain object with the block properties - */ -Block.prototype.toObject = Block.prototype.toJSON = function toObject() { - var transactions = []; - this.transactions.forEach(function(tx) { - transactions.push(tx.toObject()); - }); - return { - header: this.header.toObject(), - transactions: transactions - }; -}; - -/** - * @returns {Buffer} - A buffer of the block - */ -Block.prototype.toBuffer = function toBuffer() { - return this.toBufferWriter().concat(); -}; + module.exports = BN; + }.call(this, require('buffer').Buffer)); + }, + { '../util/preconditions': 44, 'bn.js': 62, buffer: 113, lodash: 187 }, + ], + 7: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var BN = require('./bn'); + var Point = require('./point'); + var Signature = require('./signature'); + var PublicKey = require('../publickey'); + var Random = require('./random'); + var Hash = require('./hash'); + var BufferUtil = require('../util/buffer'); + var _ = require('lodash'); + var $ = require('../util/preconditions'); + + var ECDSA = function ECDSA(obj) { + if (!(this instanceof ECDSA)) { + return new ECDSA(obj); + } + if (obj) { + this.set(obj); + } + }; + + /* jshint maxcomplexity: 9 */ + ECDSA.prototype.set = function(obj) { + this.hashbuf = obj.hashbuf || this.hashbuf; + this.endian = obj.endian || this.endian; //the endianness of hashbuf + this.privkey = obj.privkey || this.privkey; + this.pubkey = obj.pubkey || (this.privkey ? this.privkey.publicKey : this.pubkey); + this.sig = obj.sig || this.sig; + this.k = obj.k || this.k; + this.verified = obj.verified || this.verified; + return this; + }; + + ECDSA.prototype.privkey2pubkey = function() { + this.pubkey = this.privkey.toPublicKey(); + }; + + ECDSA.prototype.calci = function() { + for (var i = 0; i < 4; i++) { + this.sig.i = i; + var Qprime; + try { + Qprime = this.toPublicKey(); + } catch (e) { + console.error(e); + continue; + } -/** - * @returns {string} - A hex encoded string of the block - */ -Block.prototype.toString = function toString() { - return this.toBuffer().toString('hex'); -}; + if (Qprime.point.eq(this.pubkey.point)) { + this.sig.compressed = this.pubkey.compressed; + return this; + } + } -/** - * @param {BufferWriter} - An existing instance of BufferWriter - * @returns {BufferWriter} - An instance of BufferWriter representation of the Block - */ -Block.prototype.toBufferWriter = function toBufferWriter(bw) { - if (!bw) { - bw = new BufferWriter(); - } - bw.write(this.header.toBuffer()); - bw.writeVarintNum(this.transactions.length); - for (var i = 0; i < this.transactions.length; i++) { - this.transactions[i].toBufferWriter(bw); - } - return bw; -}; + this.sig.i = undefined; + throw new Error('Unable to find valid recovery factor'); + }; + + ECDSA.fromString = function(str) { + var obj = JSON.parse(str); + return new ECDSA(obj); + }; + + ECDSA.prototype.randomK = function() { + var N = Point.getN(); + var k; + do { + k = BN.fromBuffer(Random.getRandomBuffer(32)); + } while (!(k.lt(N) && k.gt(BN.Zero))); + this.k = k; + return this; + }; + + // https://tools.ietf.org/html/rfc6979#section-3.2 + ECDSA.prototype.deterministicK = function(badrs) { + /* jshint maxstatements: 25 */ + // if r or s were invalid when this function was used in signing, + // we do not want to actually compute r, s here for efficiency, so, + // we can increment badrs. explained at end of RFC 6979 section 3.2 + if (_.isUndefined(badrs)) { + badrs = 0; + } + var v = new Buffer(32); + v.fill(0x01); + var k = new Buffer(32); + k.fill(0x00); + var x = this.privkey.bn.toBuffer({ + size: 32, + }); + var hashbuf = this.endian === 'little' ? BufferUtil.reverse(this.hashbuf) : this.hashbuf; + k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00]), x, hashbuf]), k); + v = Hash.sha256hmac(v, k); + k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x01]), x, hashbuf]), k); + v = Hash.sha256hmac(v, k); + v = Hash.sha256hmac(v, k); + var T = BN.fromBuffer(v); + var N = Point.getN(); + + // also explained in 3.2, we must ensure T is in the proper range (0, N) + for (var i = 0; i < badrs || !(T.lt(N) && T.gt(BN.Zero)); i++) { + k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00])]), k); + v = Hash.sha256hmac(v, k); + v = Hash.sha256hmac(v, k); + T = BN.fromBuffer(v); + } -/** - * Will iterate through each transaction and return an array of hashes - * @returns {Array} - An array with transaction hashes - */ -Block.prototype.getTransactionHashes = function getTransactionHashes() { - var hashes = []; - if (this.transactions.length === 0) { - return [Block.Values.NULL_HASH]; - } - for (var t = 0; t < this.transactions.length; t++) { - hashes.push(this.transactions[t]._getHash()); - } - return hashes; -}; - -/** - * Will build a merkle tree of all the transactions, ultimately arriving at - * a single point, the merkle root. - * @link https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees - * @returns {Array} - An array with each level of the tree after the other. - */ -Block.prototype.getMerkleTree = function getMerkleTree() { + this.k = T; + return this; + }; - var tree = this.getTransactionHashes(); + // Information about public key recovery: + // https://bitcointalk.org/index.php?topic=6430.0 + // http://stackoverflow.com/questions/19665491/how-do-i-get-an-ecdsa-public-key-from-just-a-bitcoin-signature-sec1-4-1-6-k + ECDSA.prototype.toPublicKey = function() { + /* jshint maxstatements: 25 */ + var i = this.sig.i; + $.checkArgument(i === 0 || i === 1 || i === 2 || i === 3, new Error('i must be equal to 0, 1, 2, or 3')); - var j = 0; - for (var size = this.transactions.length; size > 1; size = Math.floor((size + 1) / 2)) { - for (var i = 0; i < size; i += 2) { - var i2 = Math.min(i + 1, size - 1); - var buf = Buffer.concat([tree[j + i], tree[j + i2]]); - tree.push(Hash.sha256sha256(buf)); - } - j += size; - } + var e = BN.fromBuffer(this.hashbuf); + var r = this.sig.r; + var s = this.sig.s; - return tree; -}; + // A set LSB signifies that the y-coordinate is odd + var isYOdd = i & 1; -/** - * Calculates the merkleRoot from the transactions. - * @returns {Buffer} - A buffer of the merkle root hash - */ -Block.prototype.getMerkleRoot = function getMerkleRoot() { - var tree = this.getMerkleTree(); - return tree[tree.length - 1]; -}; - -/** - * Verifies that the transactions in the block match the header merkle root - * @returns {Boolean} - If the merkle roots match - */ -Block.prototype.validMerkleRoot = function validMerkleRoot() { + // The more significant bit specifies whether we should use the + // first or second candidate key. + var isSecondKey = i >> 1; - var h = new BN(this.header.merkleRoot.toString('hex'), 'hex'); - var c = new BN(this.getMerkleRoot().toString('hex'), 'hex'); + var n = Point.getN(); + var G = Point.getG(); - if (h.cmp(c) !== 0) { - return false; - } + // 1.1 Let x = r + jn + var x = isSecondKey ? r.add(n) : r; + var R = Point.fromX(isYOdd, x); - return true; -}; + // 1.4 Check that nR is at infinity + var nR = R.mul(n); -/** - * @returns {Buffer} - The little endian hash buffer of the header - */ -Block.prototype._getHash = function() { - return this.header._getHash(); -}; - -var idProperty = { - configurable: false, - enumerable: true, - /** - * @returns {string} - The big endian hash buffer of the header - */ - get: function() { - if (!this._id) { - this._id = this.header.id; - } - return this._id; - }, - set: _.noop -}; -Object.defineProperty(Block.prototype, 'id', idProperty); -Object.defineProperty(Block.prototype, 'hash', idProperty); + if (!nR.isInfinity()) { + throw new Error('nR is not a valid curve point'); + } -/** - * @returns {string} - A string formatted for the console - */ -Block.prototype.inspect = function inspect() { - return ''; -}; - -Block.Values = { - START_OF_BLOCK: 8, // Start of block in raw block data - NULL_HASH: new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') -}; - -module.exports = Block; - -}).call(this,require("buffer").Buffer) -},{"../crypto/bn":6,"../crypto/hash":8,"../encoding/bufferreader":14,"../encoding/bufferwriter":15,"../transaction":28,"../util/buffer":42,"../util/preconditions":44,"./blockheader":3,"buffer":113,"lodash":187}],3:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var BN = require('../crypto/bn'); -var BufferUtil = require('../util/buffer'); -var BufferReader = require('../encoding/bufferreader'); -var BufferWriter = require('../encoding/bufferwriter'); -var Hash = require('../crypto/hash'); -var JSUtil = require('../util/js'); -var $ = require('../util/preconditions'); - -var GENESIS_BITS = 0x1d00ffff; - -/** - * Instantiate a BlockHeader from a Buffer, JSON object, or Object with - * the properties of the BlockHeader - * - * @param {*} - A Buffer, JSON string, or Object - * @returns {BlockHeader} - An instance of block header - * @constructor - */ -var BlockHeader = function BlockHeader(arg) { - if (!(this instanceof BlockHeader)) { - return new BlockHeader(arg); - } - var info = BlockHeader._from(arg); - this.version = info.version; - this.prevHash = info.prevHash; - this.merkleRoot = info.merkleRoot; - this.time = info.time; - this.timestamp = info.time; - this.bits = info.bits; - this.nonce = info.nonce; - - if (info.hash) { - $.checkState( - this.hash === info.hash, - 'Argument object hash property does not match block hash.' - ); - } + // Compute -e from e + var eNeg = e.neg().mod(n); - return this; -}; + // 1.6.1 Compute Q = r^-1 (sR - eG) + // Q = r^-1 (sR + -eG) + var rInv = r.invm(n); -/** - * @param {*} - A Buffer, JSON string or Object - * @returns {Object} - An object representing block header data - * @throws {TypeError} - If the argument was not recognized - * @private - */ -BlockHeader._from = function _from(arg) { - var info = {}; - if (BufferUtil.isBuffer(arg)) { - info = BlockHeader._fromBufferReader(BufferReader(arg)); - } else if (_.isObject(arg)) { - info = BlockHeader._fromObject(arg); - } else { - throw new TypeError('Unrecognized argument for BlockHeader'); - } - return info; -}; + //var Q = R.multiplyTwo(s, G, eNeg).mul(rInv); + var Q = R.mul(s) + .add(G.mul(eNeg)) + .mul(rInv); -/** - * @param {Object} - A JSON string - * @returns {Object} - An object representing block header data - * @private - */ -BlockHeader._fromObject = function _fromObject(data) { - $.checkArgument(data, 'data is required'); - var prevHash = data.prevHash; - var merkleRoot = data.merkleRoot; - if (_.isString(data.prevHash)) { - prevHash = BufferUtil.reverse(new Buffer(data.prevHash, 'hex')); - } - if (_.isString(data.merkleRoot)) { - merkleRoot = BufferUtil.reverse(new Buffer(data.merkleRoot, 'hex')); - } - var info = { - hash: data.hash, - version: data.version, - prevHash: prevHash, - merkleRoot: merkleRoot, - time: data.time, - timestamp: data.time, - bits: data.bits, - nonce: data.nonce - }; - return info; -}; - -/** - * @param {Object} - A plain JavaScript object - * @returns {BlockHeader} - An instance of block header - */ -BlockHeader.fromObject = function fromObject(obj) { - var info = BlockHeader._fromObject(obj); - return new BlockHeader(info); -}; - -/** - * @param {Binary} - Raw block binary data or buffer - * @returns {BlockHeader} - An instance of block header - */ -BlockHeader.fromRawBlock = function fromRawBlock(data) { - if (!BufferUtil.isBuffer(data)) { - data = new Buffer(data, 'binary'); - } - var br = BufferReader(data); - br.pos = BlockHeader.Constants.START_OF_HEADER; - var info = BlockHeader._fromBufferReader(br); - return new BlockHeader(info); -}; - -/** - * @param {Buffer} - A buffer of the block header - * @returns {BlockHeader} - An instance of block header - */ -BlockHeader.fromBuffer = function fromBuffer(buf) { - var info = BlockHeader._fromBufferReader(BufferReader(buf)); - return new BlockHeader(info); -}; - -/** - * @param {string} - A hex encoded buffer of the block header - * @returns {BlockHeader} - An instance of block header - */ -BlockHeader.fromString = function fromString(str) { - var buf = new Buffer(str, 'hex'); - return BlockHeader.fromBuffer(buf); -}; - -/** - * @param {BufferReader} - A BufferReader of the block header - * @returns {Object} - An object representing block header data - * @private - */ -BlockHeader._fromBufferReader = function _fromBufferReader(br) { - var info = {}; - info.version = br.readInt32LE(); - info.prevHash = br.read(32); - info.merkleRoot = br.read(32); - info.time = br.readUInt32LE(); - info.bits = br.readUInt32LE(); - info.nonce = br.readUInt32LE(); - return info; -}; - -/** - * @param {BufferReader} - A BufferReader of the block header - * @returns {BlockHeader} - An instance of block header - */ -BlockHeader.fromBufferReader = function fromBufferReader(br) { - var info = BlockHeader._fromBufferReader(br); - return new BlockHeader(info); -}; + var pubkey = PublicKey.fromPoint(Q, this.sig.compressed); -/** - * @returns {Object} - A plain object of the BlockHeader - */ -BlockHeader.prototype.toObject = BlockHeader.prototype.toJSON = function toObject() { - return { - hash: this.hash, - version: this.version, - prevHash: BufferUtil.reverse(this.prevHash).toString('hex'), - merkleRoot: BufferUtil.reverse(this.merkleRoot).toString('hex'), - time: this.time, - bits: this.bits, - nonce: this.nonce - }; -}; - -/** - * @returns {Buffer} - A Buffer of the BlockHeader - */ -BlockHeader.prototype.toBuffer = function toBuffer() { - return this.toBufferWriter().concat(); -}; + return pubkey; + }; -/** - * @returns {string} - A hex encoded string of the BlockHeader - */ -BlockHeader.prototype.toString = function toString() { - return this.toBuffer().toString('hex'); -}; + ECDSA.prototype.sigError = function() { + /* jshint maxstatements: 25 */ + if (!BufferUtil.isBuffer(this.hashbuf) || this.hashbuf.length !== 32) { + return 'hashbuf must be a 32 byte buffer'; + } -/** - * @param {BufferWriter} - An existing instance BufferWriter - * @returns {BufferWriter} - An instance of BufferWriter representation of the BlockHeader - */ -BlockHeader.prototype.toBufferWriter = function toBufferWriter(bw) { - if (!bw) { - bw = new BufferWriter(); - } - bw.writeInt32LE(this.version); - bw.write(this.prevHash); - bw.write(this.merkleRoot); - bw.writeUInt32LE(this.time); - bw.writeUInt32LE(this.bits); - bw.writeUInt32LE(this.nonce); - return bw; -}; - -/** - * Returns the target difficulty for this block - * @param {Number} bits - * @returns {BN} An instance of BN with the decoded difficulty bits - */ -BlockHeader.prototype.getTargetDifficulty = function getTargetDifficulty(bits) { - bits = bits || this.bits; + var r = this.sig.r; + var s = this.sig.s; + if (!(r.gt(BN.Zero) && r.lt(Point.getN())) || !(s.gt(BN.Zero) && s.lt(Point.getN()))) { + return 'r and s not in range'; + } - var target = new BN(bits & 0xffffff); - var mov = 8 * ((bits >>> 24) - 3); - while (mov-- > 0) { - target = target.mul(new BN(2)); - } - return target; -}; + var e = BN.fromBuffer( + this.hashbuf, + this.endian + ? { + endian: this.endian, + } + : undefined, + ); + var n = Point.getN(); + var sinv = s.invm(n); + var u1 = sinv.mul(e).mod(n); + var u2 = sinv.mul(r).mod(n); + + var p = Point.getG().mulAdd(u1, this.pubkey.point, u2); + if (p.isInfinity()) { + return 'p is infinity'; + } -/** - * @link https://en.bitcoin.it/wiki/Difficulty - * @return {Number} - */ -BlockHeader.prototype.getDifficulty = function getDifficulty() { - var difficulty1TargetBN = this.getTargetDifficulty(GENESIS_BITS).mul(new BN(Math.pow(10, 8))); - var currentTargetBN = this.getTargetDifficulty(); - - var difficultyString = difficulty1TargetBN.div(currentTargetBN).toString(10); - var decimalPos = difficultyString.length - 8; - difficultyString = difficultyString.slice(0, decimalPos) + '.' + difficultyString.slice(decimalPos); - - return parseFloat(difficultyString); -}; - -/** - * @returns {Buffer} - The little endian hash buffer of the header - */ -BlockHeader.prototype._getHash = function hash() { - var buf = this.toBuffer(); - return Hash.sha256sha256(buf); -}; - -var idProperty = { - configurable: false, - enumerable: true, - /** - * @returns {string} - The big endian hash buffer of the header - */ - get: function() { - if (!this._id) { - this._id = BufferReader(this._getHash()).readReverse().toString('hex'); - } - return this._id; - }, - set: _.noop -}; -Object.defineProperty(BlockHeader.prototype, 'id', idProperty); -Object.defineProperty(BlockHeader.prototype, 'hash', idProperty); - -/** - * @returns {Boolean} - If timestamp is not too far in the future - */ -BlockHeader.prototype.validTimestamp = function validTimestamp() { - var currentTime = Math.round(new Date().getTime() / 1000); - if (this.time > currentTime + BlockHeader.Constants.MAX_TIME_OFFSET) { - return false; - } - return true; -}; + if ( + p + .getX() + .mod(n) + .cmp(r) !== 0 + ) { + return 'Invalid signature'; + } else { + return false; + } + }; -/** - * @returns {Boolean} - If the proof-of-work hash satisfies the target difficulty - */ -BlockHeader.prototype.validProofOfWork = function validProofOfWork() { - var pow = new BN(this.id, 'hex'); - var target = this.getTargetDifficulty(); + ECDSA.toLowS = function(s) { + //enforce low s + //see BIP 62, "low S values in signatures" + if ( + s.gt(BN.fromBuffer(new Buffer('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex'))) + ) { + s = Point.getN().sub(s); + } + return s; + }; + + ECDSA.prototype._findSignature = function(d, e) { + var N = Point.getN(); + var G = Point.getG(); + // try different values of k until r, s are valid + var badrs = 0; + var k, Q, r, s; + do { + if (!this.k || badrs > 0) { + this.deterministicK(badrs); + } + badrs++; + k = this.k; + Q = G.mul(k); + r = Q.x.mod(N); + s = k + .invm(N) + .mul(e.add(d.mul(r))) + .mod(N); + } while (r.cmp(BN.Zero) <= 0 || s.cmp(BN.Zero) <= 0); + + s = ECDSA.toLowS(s); + return { + s: s, + r: r, + }; + }; + + ECDSA.prototype.sign = function() { + var hashbuf = this.hashbuf; + var privkey = this.privkey; + var d = privkey.bn; + + $.checkState(hashbuf && privkey && d, new Error('invalid parameters')); + $.checkState( + BufferUtil.isBuffer(hashbuf) && hashbuf.length === 32, + new Error('hashbuf must be a 32 byte buffer'), + ); + + var e = BN.fromBuffer( + hashbuf, + this.endian + ? { + endian: this.endian, + } + : undefined, + ); + + var obj = this._findSignature(d, e); + obj.compressed = this.pubkey.compressed; + + this.sig = new Signature(obj); + return this; + }; + + ECDSA.prototype.signRandomK = function() { + this.randomK(); + return this.sign(); + }; + + ECDSA.prototype.toString = function() { + var obj = {}; + if (this.hashbuf) { + obj.hashbuf = this.hashbuf.toString('hex'); + } + if (this.privkey) { + obj.privkey = this.privkey.toString(); + } + if (this.pubkey) { + obj.pubkey = this.pubkey.toString(); + } + if (this.sig) { + obj.sig = this.sig.toString(); + } + if (this.k) { + obj.k = this.k.toString(); + } + return JSON.stringify(obj); + }; - if (pow.cmp(target) > 0) { - return false; - } - return true; -}; + ECDSA.prototype.verify = function() { + if (!this.sigError()) { + this.verified = true; + } else { + this.verified = false; + } + return this; + }; + + ECDSA.sign = function(hashbuf, privkey, endian) { + return ECDSA() + .set({ + hashbuf: hashbuf, + endian: endian, + privkey: privkey, + }) + .sign().sig; + }; + + ECDSA.verify = function(hashbuf, sig, pubkey, endian) { + return ECDSA() + .set({ + hashbuf: hashbuf, + endian: endian, + sig: sig, + pubkey: pubkey, + }) + .verify().verified; + }; + + module.exports = ECDSA; + }.call(this, require('buffer').Buffer)); + }, + { + '../publickey': 24, + '../util/buffer': 42, + '../util/preconditions': 44, + './bn': 6, + './hash': 8, + './point': 9, + './random': 10, + './signature': 11, + buffer: 113, + lodash: 187, + }, + ], + 8: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var crypto = require('crypto'); + var BufferUtil = require('../util/buffer'); + var $ = require('../util/preconditions'); + + var Hash = module.exports; + + Hash.sha1 = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + return crypto + .createHash('sha1') + .update(buf) + .digest(); + }; + + Hash.sha1.blocksize = 512; + + Hash.sha256 = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + return crypto + .createHash('sha256') + .update(buf) + .digest(); + }; + + Hash.sha256.blocksize = 512; + + Hash.sha256sha256 = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + return Hash.sha256(Hash.sha256(buf)); + }; + + Hash.ripemd160 = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + return crypto + .createHash('ripemd160') + .update(buf) + .digest(); + }; + + Hash.sha256ripemd160 = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + return Hash.ripemd160(Hash.sha256(buf)); + }; + + Hash.sha512 = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + return crypto + .createHash('sha512') + .update(buf) + .digest(); + }; + + Hash.sha512.blocksize = 1024; + + Hash.hmac = function(hashf, data, key) { + //http://en.wikipedia.org/wiki/Hash-based_message_authentication_code + //http://tools.ietf.org/html/rfc4868#section-2 + $.checkArgument(BufferUtil.isBuffer(data)); + $.checkArgument(BufferUtil.isBuffer(key)); + $.checkArgument(hashf.blocksize); + + var blocksize = hashf.blocksize / 8; + + if (key.length > blocksize) { + key = hashf(key); + } else if (key < blocksize) { + var fill = new Buffer(blocksize); + fill.fill(0); + key.copy(fill); + key = fill; + } -/** - * @returns {string} - A string formatted for the console - */ -BlockHeader.prototype.inspect = function inspect() { - return ''; -}; - -BlockHeader.Constants = { - START_OF_HEADER: 8, // Start buffer position in raw block data - MAX_TIME_OFFSET: 2 * 60 * 60, // The max a timestamp can be in the future - LARGEST_HASH: new BN('10000000000000000000000000000000000000000000000000000000000000000', 'hex') -}; - -module.exports = BlockHeader; - -}).call(this,require("buffer").Buffer) -},{"../crypto/bn":6,"../crypto/hash":8,"../encoding/bufferreader":14,"../encoding/bufferwriter":15,"../util/buffer":42,"../util/js":43,"../util/preconditions":44,"buffer":113,"lodash":187}],4:[function(require,module,exports){ -module.exports = require('./block'); - -module.exports.BlockHeader = require('./blockheader'); -module.exports.MerkleBlock = require('./merkleblock'); - -},{"./block":2,"./blockheader":3,"./merkleblock":5}],5:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var BlockHeader = require('./blockheader'); -var BufferUtil = require('../util/buffer'); -var BufferReader = require('../encoding/bufferreader'); -var BufferWriter = require('../encoding/bufferwriter'); -var Hash = require('../crypto/hash'); -var JSUtil = require('../util/js'); -var Transaction = require('../transaction'); -var $ = require('../util/preconditions'); - -/** - * Instantiate a MerkleBlock from a Buffer, JSON object, or Object with - * the properties of the Block - * - * @param {*} - A Buffer, JSON string, or Object representing a MerkleBlock - * @returns {MerkleBlock} - * @constructor - */ -function MerkleBlock(arg) { - /* jshint maxstatements: 18 */ + var o_key = new Buffer(blocksize); + o_key.fill(0x5c); - if (!(this instanceof MerkleBlock)) { - return new MerkleBlock(arg); - } + var i_key = new Buffer(blocksize); + i_key.fill(0x36); - var info = {}; - if (BufferUtil.isBuffer(arg)) { - info = MerkleBlock._fromBufferReader(BufferReader(arg)); - } else if (_.isObject(arg)) { - var header; - if(arg.header instanceof BlockHeader) { - header = arg.header; - } else { - header = BlockHeader.fromObject(arg.header); - } - info = { - /** - * @name MerkleBlock#header - * @type {BlockHeader} - */ - header: header, - /** - * @name MerkleBlock#numTransactions - * @type {Number} - */ - numTransactions: arg.numTransactions, - /** - * @name MerkleBlock#hashes - * @type {String[]} - */ - hashes: arg.hashes, - /** - * @name MerkleBlock#flags - * @type {Number[]} - */ - flags: arg.flags - }; - } else { - throw new TypeError('Unrecognized argument for MerkleBlock'); - } - _.extend(this,info); - this._flagBitsUsed = 0; - this._hashesUsed = 0; - return this; -} + var o_key_pad = new Buffer(blocksize); + var i_key_pad = new Buffer(blocksize); + for (var i = 0; i < blocksize; i++) { + o_key_pad[i] = o_key[i] ^ key[i]; + i_key_pad[i] = i_key[i] ^ key[i]; + } -/** - * @param {Buffer} - MerkleBlock data in a Buffer object - * @returns {MerkleBlock} - A MerkleBlock object - */ -MerkleBlock.fromBuffer = function fromBuffer(buf) { - return MerkleBlock.fromBufferReader(BufferReader(buf)); -}; + return hashf(Buffer.concat([o_key_pad, hashf(Buffer.concat([i_key_pad, data]))])); + }; -/** - * @param {BufferReader} - MerkleBlock data in a BufferReader object - * @returns {MerkleBlock} - A MerkleBlock object - */ -MerkleBlock.fromBufferReader = function fromBufferReader(br) { - return new MerkleBlock(MerkleBlock._fromBufferReader(br)); -}; + Hash.sha256hmac = function(data, key) { + return Hash.hmac(Hash.sha256, data, key); + }; -/** - * @returns {Buffer} - A buffer of the block - */ -MerkleBlock.prototype.toBuffer = function toBuffer() { - return this.toBufferWriter().concat(); -}; + Hash.sha512hmac = function(data, key) { + return Hash.hmac(Hash.sha512, data, key); + }; + }.call(this, require('buffer').Buffer)); + }, + { '../util/buffer': 42, '../util/preconditions': 44, buffer: 113, crypto: 139 }, + ], + 9: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var BN = require('./bn'); + var BufferUtil = require('../util/buffer'); + var ec = require('elliptic').curves.secp256k1; + var ecPoint = ec.curve.point.bind(ec.curve); + var ecPointFromX = ec.curve.pointFromX.bind(ec.curve); + + /** + * + * Instantiate a valid secp256k1 Point from the X and Y coordinates. + * + * @param {BN|String} x - The X coordinate + * @param {BN|String} y - The Y coordinate + * @link https://github.com/indutny/elliptic + * @augments elliptic.curve.point + * @throws {Error} A validation error if exists + * @returns {Point} An instance of Point + * @constructor + */ + var Point = function Point(x, y, isRed) { + var point = ecPoint(x, y, isRed); + point.validate(); + return point; + }; + + Point.prototype = Object.getPrototypeOf(ec.curve.point()); + + /** + * + * Instantiate a valid secp256k1 Point from only the X coordinate + * + * @param {boolean} odd - If the Y coordinate is odd + * @param {BN|String} x - The X coordinate + * @throws {Error} A validation error if exists + * @returns {Point} An instance of Point + */ + Point.fromX = function fromX(odd, x) { + var point = ecPointFromX(odd, x); + point.validate(); + return point; + }; + + /** + * + * Will return a secp256k1 ECDSA base point. + * + * @link https://en.bitcoin.it/wiki/Secp256k1 + * @returns {Point} An instance of the base point. + */ + Point.getG = function getG() { + return ec.curve.g; + }; + + /** + * + * Will return the max of range of valid private keys as governed by the secp256k1 ECDSA standard. + * + * @link https://en.bitcoin.it/wiki/Private_key#Range_of_valid_ECDSA_private_keys + * @returns {BN} A BN instance of the number of points on the curve + */ + Point.getN = function getN() { + return new BN(ec.curve.n.toArray()); + }; + + Point.prototype._getX = Point.prototype.getX; + + /** + * + * Will return the X coordinate of the Point + * + * @returns {BN} A BN instance of the X coordinate + */ + Point.prototype.getX = function getX() { + return new BN(this._getX().toArray()); + }; + + Point.prototype._getY = Point.prototype.getY; + + /** + * + * Will return the Y coordinate of the Point + * + * @returns {BN} A BN instance of the Y coordinate + */ + Point.prototype.getY = function getY() { + return new BN(this._getY().toArray()); + }; + + /** + * + * Will determine if the point is valid + * + * @link https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf + * @param {Point} An instance of Point + * @throws {Error} A validation error if exists + * @returns {Point} An instance of the same Point + */ + Point.prototype.validate = function validate() { + if (this.isInfinity()) { + throw new Error('Point cannot be equal to Infinity'); + } -/** - * @param {BufferWriter} - An existing instance of BufferWriter - * @returns {BufferWriter} - An instance of BufferWriter representation of the MerkleBlock - */ -MerkleBlock.prototype.toBufferWriter = function toBufferWriter(bw) { - if (!bw) { - bw = new BufferWriter(); - } - bw.write(this.header.toBuffer()); - bw.writeUInt32LE(this.numTransactions); - bw.writeVarintNum(this.hashes.length); - for (var i = 0; i < this.hashes.length; i++) { - bw.write(new Buffer(this.hashes[i], 'hex')); - } - bw.writeVarintNum(this.flags.length); - for (i = 0; i < this.flags.length; i++) { - bw.writeUInt8(this.flags[i]); - } - return bw; -}; + if (this.getX().cmp(BN.Zero) === 0 || this.getY().cmp(BN.Zero) === 0) { + throw new Error('Invalid x,y value for curve, cannot equal 0.'); + } -/** - * @returns {Object} - A plain object with the MerkleBlock properties - */ -MerkleBlock.prototype.toObject = MerkleBlock.prototype.toJSON = function toObject() { - return { - header: this.header.toObject(), - numTransactions: this.numTransactions, - hashes: this.hashes, - flags: this.flags - }; -}; - -/** - * Verify that the MerkleBlock is valid - * @returns {Boolean} - True/False whether this MerkleBlock is Valid - */ -MerkleBlock.prototype.validMerkleTree = function validMerkleTree() { - $.checkState(_.isArray(this.flags), 'MerkleBlock flags is not an array'); - $.checkState(_.isArray(this.hashes), 'MerkleBlock hashes is not an array'); + var p2 = ecPointFromX(this.getY().isOdd(), this.getX()); - // Can't have more hashes than numTransactions - if(this.hashes.length > this.numTransactions) { - return false; - } + if (p2.y.cmp(this.y) !== 0) { + throw new Error('Invalid y value for curve.'); + } - // Can't have more flag bits than num hashes - if(this.flags.length * 8 < this.hashes.length) { - return false; - } + var xValidRange = this.getX().gt(BN.Minus1) && this.getX().lt(Point.getN()); + var yValidRange = this.getY().gt(BN.Minus1) && this.getY().lt(Point.getN()); - var height = this._calcTreeHeight(); - var opts = { hashesUsed: 0, flagBitsUsed: 0 }; - var root = this._traverseMerkleTree(height, 0, opts); - if(opts.hashesUsed !== this.hashes.length) { - return false; - } - return BufferUtil.equals(root, this.header.merkleRoot); -}; - -/** - * Traverse a the tree in this MerkleBlock, validating it along the way - * Modeled after Merit Core merkleblock.cpp TraverseAndExtract() - * @param {Number} - depth - Current height - * @param {Number} - pos - Current position in the tree - * @param {Object} - opts - Object with values that need to be mutated throughout the traversal - * @param {Number} - opts.flagBitsUsed - Number of flag bits used, should start at 0 - * @param {Number} - opts.hashesUsed - Number of hashes used, should start at 0 - * @param {Array} - opts.txs - Will finish populated by transactions found during traversal - * @returns {Buffer|null} - Buffer containing the Merkle Hash for that height - * @private - */ -MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, pos, opts) { - /* jshint maxcomplexity: 12*/ - /* jshint maxstatements: 20 */ + if (!xValidRange || !yValidRange) { + throw new Error('Point does not lie on the curve'); + } - opts = opts || {}; - opts.txs = opts.txs || []; - opts.flagBitsUsed = opts.flagBitsUsed || 0; - opts.hashesUsed = opts.hashesUsed || 0; + //todo: needs test case + if (!this.mul(Point.getN()).isInfinity()) { + throw new Error('Point times N must be infinity'); + } - if(opts.flagBitsUsed > this.flags.length * 8) { - return null; - } - var isParentOfMatch = (this.flags[opts.flagBitsUsed >> 3] >>> (opts.flagBitsUsed++ & 7)) & 1; - if(depth === 0 || !isParentOfMatch) { - if(opts.hashesUsed >= this.hashes.length) { - return null; - } - var hash = this.hashes[opts.hashesUsed++]; - if(depth === 0 && isParentOfMatch) { - opts.txs.push(hash); - } - return new Buffer(hash, 'hex'); - } else { - var left = this._traverseMerkleTree(depth-1, pos*2, opts); - var right = left; - if(pos*2+1 < this._calcTreeWidth(depth-1)) { - right = this._traverseMerkleTree(depth-1, pos*2+1, opts); - } - return Hash.sha256sha256(new Buffer.concat([left, right])); - } -}; + return this; + }; -/** Calculates the width of a merkle tree at a given height. - * Modeled after Merit Core merkleblock.h CalcTreeWidth() - * @param {Number} - Height at which we want the tree width - * @returns {Number} - Width of the tree at a given height - * @private - */ -MerkleBlock.prototype._calcTreeWidth = function calcTreeWidth(height) { - return (this.numTransactions + (1 << height) - 1) >> height; -}; - -/** Calculates the height of the merkle tree in this MerkleBlock - * @param {Number} - Height at which we want the tree width - * @returns {Number} - Height of the merkle tree in this MerkleBlock - * @private - */ -MerkleBlock.prototype._calcTreeHeight = function calcTreeHeight() { - var height = 0; - while (this._calcTreeWidth(height) > 1) { - height++; - } - return height; -}; + Point.pointToCompressed = function pointToCompressed(point) { + var xbuf = point.getX().toBuffer({ size: 32 }); + var ybuf = point.getY().toBuffer({ size: 32 }); -/** - * @param {Transaction|String} - Transaction or Transaction ID Hash - * @returns {Boolean} - return true/false if this MerkleBlock has the TX or not - * @private - */ -MerkleBlock.prototype.hasTransaction = function hasTransaction(tx) { - $.checkArgument(!_.isUndefined(tx), 'tx cannot be undefined'); - $.checkArgument(tx instanceof Transaction || typeof tx === 'string', - 'Invalid tx given, tx must be a "string" or "Transaction"'); - - var hash = tx; - if(tx instanceof Transaction) { - // We need to reverse the id hash for the lookup - hash = BufferUtil.reverse(new Buffer(tx.id, 'hex')).toString('hex'); - } + var prefix; + var odd = ybuf[ybuf.length - 1] % 2; + if (odd) { + prefix = new Buffer([0x03]); + } else { + prefix = new Buffer([0x02]); + } + return BufferUtil.concat([prefix, xbuf]); + }; - var txs = []; - var height = this._calcTreeHeight(); - this._traverseMerkleTree(height, 0, { txs: txs }); - return txs.indexOf(hash) !== -1; -}; + module.exports = Point; + }.call(this, require('buffer').Buffer)); + }, + { '../util/buffer': 42, './bn': 6, buffer: 113, elliptic: 151 }, + ], + 10: [ + function(require, module, exports) { + (function(process, Buffer) { + 'use strict'; + + function Random() {} + + /* secure random bytes that sometimes throws an error due to lack of entropy */ + Random.getRandomBuffer = function(size) { + if (process.browser) return Random.getRandomBufferBrowser(size); + else return Random.getRandomBufferNode(size); + }; + + Random.getRandomBufferNode = function(size) { + var crypto = require('crypto'); + return crypto.randomBytes(size); + }; + + Random.getRandomBufferBrowser = function(size) { + if (!window.crypto && !window.msCrypto) throw new Error('window.crypto not available'); + + if (window.crypto && window.crypto.getRandomValues) var crypto = window.crypto; + else if (window.msCrypto && window.msCrypto.getRandomValues) + //internet explorer + var crypto = window.msCrypto; + else throw new Error('window.crypto.getRandomValues not available'); + + var bbuf = new Uint8Array(size); + crypto.getRandomValues(bbuf); + var buf = new Buffer(bbuf); + + return buf; + }; + + /* insecure random bytes, but it never fails */ + Random.getPseudoRandomBuffer = function(size) { + var b32 = 0x100000000; + var b = new Buffer(size); + var r; + + for (var i = 0; i <= size; i++) { + var j = Math.floor(i / 4); + var k = i - j * 4; + if (k === 0) { + r = Math.random() * b32; + b[i] = r & 0xff; + } else { + b[i] = (r = r >>> 8) & 0xff; + } + } -/** - * @param {Buffer} - MerkleBlock data - * @returns {Object} - An Object representing merkleblock data - * @private - */ -MerkleBlock._fromBufferReader = function _fromBufferReader(br) { - $.checkState(!br.finished(), 'No merkleblock data received'); - var info = {}; - info.header = BlockHeader.fromBufferReader(br); - info.numTransactions = br.readUInt32LE(); - var numHashes = br.readVarintNum(); - info.hashes = []; - for (var i = 0; i < numHashes; i++) { - info.hashes.push(br.read(32).toString('hex')); - } - var numFlags = br.readVarintNum(); - info.flags = []; - for (i = 0; i < numFlags; i++) { - info.flags.push(br.readUInt8()); - } - return info; -}; + return b; + }; -/** - * @param {Object} - A plain JavaScript object - * @returns {Block} - An instance of block - */ -MerkleBlock.fromObject = function fromObject(obj) { - return new MerkleBlock(obj); -}; + module.exports = Random; + }.call(this, require('_process'), require('buffer').Buffer)); + }, + { _process: 205, buffer: 113, crypto: 139 }, + ], + 11: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var BN = require('./bn'); + var _ = require('lodash'); + var $ = require('../util/preconditions'); + var BufferUtil = require('../util/buffer'); + var JSUtil = require('../util/js'); + + var Signature = function Signature(r, s) { + if (!(this instanceof Signature)) { + return new Signature(r, s); + } + if (r instanceof BN) { + this.set({ + r: r, + s: s, + }); + } else if (r) { + var obj = r; + this.set(obj); + } + }; + + /* jshint maxcomplexity: 7 */ + Signature.prototype.set = function(obj) { + this.r = obj.r || this.r || undefined; + this.s = obj.s || this.s || undefined; + this.i = typeof obj.i !== 'undefined' ? obj.i : this.i; //public key recovery parameter in range [0, 3] + this.compressed = typeof obj.compressed !== 'undefined' ? obj.compressed : this.compressed; //whether the recovered pubkey is compressed + this.nhashtype = obj.nhashtype || this.nhashtype || undefined; + return this; + }; + + Signature.fromCompact = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf), 'Argument is expected to be a Buffer'); + + var sig = new Signature(); + + var compressed = true; + var i = buf.slice(0, 1)[0] - 27 - 4; + if (i < 0) { + compressed = false; + i = i + 4; + } -module.exports = MerkleBlock; + var b2 = buf.slice(1, 33); + var b3 = buf.slice(33, 65); + + $.checkArgument(i === 0 || i === 1 || i === 2 || i === 3, new Error('i must be 0, 1, 2, or 3')); + $.checkArgument(b2.length === 32, new Error('r must be 32 bytes')); + $.checkArgument(b3.length === 32, new Error('s must be 32 bytes')); + + sig.compressed = compressed; + sig.i = i; + sig.r = BN.fromBuffer(b2); + sig.s = BN.fromBuffer(b3); + + return sig; + }; + + Signature.fromDER = Signature.fromBuffer = function(buf, strict) { + var obj = Signature.parseDER(buf, strict); + var sig = new Signature(); + + sig.r = obj.r; + sig.s = obj.s; + + return sig; + }; + + // The format used in a tx + Signature.fromTxFormat = function(buf) { + var nhashtype = buf.readUInt8(buf.length - 1); + var derbuf = buf.slice(0, buf.length - 1); + var sig = new Signature.fromDER(derbuf, false); + sig.nhashtype = nhashtype; + return sig; + }; + + Signature.fromString = function(str) { + var buf = new Buffer(str, 'hex'); + return Signature.fromDER(buf); + }; + + /** + * In order to mimic the non-strict DER encoding of OpenSSL, set strict = false. + */ + Signature.parseDER = function(buf, strict) { + $.checkArgument(BufferUtil.isBuffer(buf), new Error('DER formatted signature should be a buffer')); + if (_.isUndefined(strict)) { + strict = true; + } -}).call(this,require("buffer").Buffer) -},{"../crypto/hash":8,"../encoding/bufferreader":14,"../encoding/bufferwriter":15,"../transaction":28,"../util/buffer":42,"../util/js":43,"../util/preconditions":44,"./blockheader":3,"buffer":113,"lodash":187}],6:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + var header = buf[0]; + $.checkArgument(header === 0x30, new Error('Header byte should be 0x30')); + + var length = buf[1]; + var buflength = buf.slice(2).length; + $.checkArgument(!strict || length === buflength, new Error('Length byte should length of what follows')); + + length = length < buflength ? length : buflength; + + var rheader = buf[2 + 0]; + $.checkArgument(rheader === 0x02, new Error('Integer byte for r should be 0x02')); + + var rlength = buf[2 + 1]; + var rbuf = buf.slice(2 + 2, 2 + 2 + rlength); + var r = BN.fromBuffer(rbuf); + var rneg = buf[2 + 1 + 1] === 0x00 ? true : false; + $.checkArgument(rlength === rbuf.length, new Error('Length of r incorrect')); + + var sheader = buf[2 + 2 + rlength + 0]; + $.checkArgument(sheader === 0x02, new Error('Integer byte for s should be 0x02')); + + var slength = buf[2 + 2 + rlength + 1]; + var sbuf = buf.slice(2 + 2 + rlength + 2, 2 + 2 + rlength + 2 + slength); + var s = BN.fromBuffer(sbuf); + var sneg = buf[2 + 2 + rlength + 2 + 2] === 0x00 ? true : false; + $.checkArgument(slength === sbuf.length, new Error('Length of s incorrect')); + + var sumlength = 2 + 2 + rlength + 2 + slength; + $.checkArgument(length === sumlength - 2, new Error('Length of signature incorrect')); + + var obj = { + header: header, + length: length, + rheader: rheader, + rlength: rlength, + rneg: rneg, + rbuf: rbuf, + r: r, + sheader: sheader, + slength: slength, + sneg: sneg, + sbuf: sbuf, + s: s, + }; -var BN = require('bn.js'); -var $ = require('../util/preconditions'); -var _ = require('lodash'); + return obj; + }; -var reversebuf = function(buf) { - var buf2 = new Buffer(buf.length); - for (var i = 0; i < buf.length; i++) { - buf2[i] = buf[buf.length - 1 - i]; - } - return buf2; -}; - -BN.Zero = new BN(0); -BN.One = new BN(1); -BN.Minus1 = new BN(-1); - -BN.fromNumber = function(n) { - $.checkArgument(_.isNumber(n)); - return new BN(n); -}; - -BN.fromString = function(str, base) { - $.checkArgument(_.isString(str)); - return new BN(str, base); -}; - -BN.fromBuffer = function(buf, opts) { - if (typeof opts !== 'undefined' && opts.endian === 'little') { - buf = reversebuf(buf); - } - var hex = buf.toString('hex'); - var bn = new BN(hex, 16); - return bn; -}; - -/** - * Instantiate a BigNumber from a "signed magnitude buffer" - * (a buffer where the most significant bit represents the sign (0 = positive, -1 = negative)) - */ -BN.fromSM = function(buf, opts) { - var ret; - if (buf.length === 0) { - return BN.fromBuffer(new Buffer([0])); - } + Signature.prototype.toCompact = function(i, compressed) { + i = typeof i === 'number' ? i : this.i; + compressed = typeof compressed === 'boolean' ? compressed : this.compressed; - var endian = 'big'; - if (opts) { - endian = opts.endian; - } - if (endian === 'little') { - buf = reversebuf(buf); - } + if (!(i === 0 || i === 1 || i === 2 || i === 3)) { + throw new Error('i must be equal to 0, 1, 2, or 3'); + } - if (buf[0] & 0x80) { - buf[0] = buf[0] & 0x7f; - ret = BN.fromBuffer(buf); - ret.neg().copy(ret); - } else { - ret = BN.fromBuffer(buf); - } - return ret; -}; - - -BN.prototype.toNumber = function() { - return parseInt(this.toString(10), 10); -}; - -BN.prototype.toBuffer = function(opts) { - var buf, hex; - if (opts && opts.size) { - hex = this.toString(16, 2); - var natlen = hex.length / 2; - buf = new Buffer(hex, 'hex'); - - if (natlen === opts.size) { - buf = buf; - } else if (natlen > opts.size) { - buf = BN.trim(buf, natlen); - } else if (natlen < opts.size) { - buf = BN.pad(buf, natlen, opts.size); - } - } else { - hex = this.toString(16, 2); - buf = new Buffer(hex, 'hex'); - } + var val = i + 27 + 4; + if (compressed === false) { + val = val - 4; + } + var b1 = new Buffer([val]); + var b2 = this.r.toBuffer({ + size: 32, + }); + var b3 = this.s.toBuffer({ + size: 32, + }); + return Buffer.concat([b1, b2, b3]); + }; + + Signature.prototype.toBuffer = Signature.prototype.toDER = function() { + var rnbuf = this.r.toBuffer(); + var snbuf = this.s.toBuffer(); + + var rneg = rnbuf[0] & 0x80 ? true : false; + var sneg = snbuf[0] & 0x80 ? true : false; + + var rbuf = rneg ? Buffer.concat([new Buffer([0x00]), rnbuf]) : rnbuf; + var sbuf = sneg ? Buffer.concat([new Buffer([0x00]), snbuf]) : snbuf; + + var rlength = rbuf.length; + var slength = sbuf.length; + var length = 2 + rlength + 2 + slength; + var rheader = 0x02; + var sheader = 0x02; + var header = 0x30; + + var der = Buffer.concat([ + new Buffer([header, length, rheader, rlength]), + rbuf, + new Buffer([sheader, slength]), + sbuf, + ]); + return der; + }; + + Signature.prototype.toString = function() { + var buf = this.toDER(); + return buf.toString('hex'); + }; + + /** + * This function is translated from bitcoind's IsDERSignature and is used in + * the script interpreter. This "DER" format actually includes an extra byte, + * the nhashtype, at the end. It is really the tx format, not DER format. + * + * A canonical signature exists of: [30] [total len] [02] [len R] [R] [02] [len S] [S] [hashtype] + * Where R and S are not negative (their first byte has its highest bit not set), and not + * excessively padded (do not start with a 0 byte, unless an otherwise negative number follows, + * in which case a single 0 byte is necessary and even required). + * + * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 + */ + Signature.isTxDER = function(buf) { + if (buf.length < 9) { + // Non-canonical signature: too short + return false; + } + if (buf.length > 73) { + // Non-canonical signature: too long + return false; + } + if (buf[0] !== 0x30) { + // Non-canonical signature: wrong type + return false; + } + if (buf[1] !== buf.length - 3) { + // Non-canonical signature: wrong length marker + return false; + } + var nLenR = buf[3]; + if (5 + nLenR >= buf.length) { + // Non-canonical signature: S length misplaced + return false; + } + var nLenS = buf[5 + nLenR]; + if (nLenR + nLenS + 7 !== buf.length) { + // Non-canonical signature: R+S length mismatch + return false; + } - if (typeof opts !== 'undefined' && opts.endian === 'little') { - buf = reversebuf(buf); - } + var R = buf.slice(4); + if (buf[4 - 2] !== 0x02) { + // Non-canonical signature: R value type mismatch + return false; + } + if (nLenR === 0) { + // Non-canonical signature: R length is zero + return false; + } + if (R[0] & 0x80) { + // Non-canonical signature: R value negative + return false; + } + if (nLenR > 1 && R[0] === 0x00 && !(R[1] & 0x80)) { + // Non-canonical signature: R value excessively padded + return false; + } - return buf; -}; - -BN.prototype.toSMBigEndian = function() { - var buf; - if (this.cmp(BN.Zero) === -1) { - buf = this.neg().toBuffer(); - if (buf[0] & 0x80) { - buf = Buffer.concat([new Buffer([0x80]), buf]); - } else { - buf[0] = buf[0] | 0x80; - } - } else { - buf = this.toBuffer(); - if (buf[0] & 0x80) { - buf = Buffer.concat([new Buffer([0x00]), buf]); - } - } + var S = buf.slice(6 + nLenR); + if (buf[6 + nLenR - 2] !== 0x02) { + // Non-canonical signature: S value type mismatch + return false; + } + if (nLenS === 0) { + // Non-canonical signature: S length is zero + return false; + } + if (S[0] & 0x80) { + // Non-canonical signature: S value negative + return false; + } + if (nLenS > 1 && S[0] === 0x00 && !(S[1] & 0x80)) { + // Non-canonical signature: S value excessively padded + return false; + } + return true; + }; + + /** + * Compares to bitcoind's IsLowDERSignature + * See also ECDSA signature algorithm which enforces this. + * See also BIP 62, "low S values in signatures" + */ + Signature.prototype.hasLowS = function() { + if ( + this.s.lt(new BN(1)) || + this.s.gt(new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex')) + ) { + return false; + } + return true; + }; + + /** + * @returns true if the nhashtype is exactly equal to one of the standard options or combinations thereof. + * Translated from bitcoind's IsDefinedHashtypeSignature + */ + Signature.prototype.hasDefinedHashtype = function() { + if (!JSUtil.isNaturalNumber(this.nhashtype)) { + return false; + } + // accept with or without Signature.SIGHASH_ANYONECANPAY by ignoring the bit + var temp = this.nhashtype & ~Signature.SIGHASH_ANYONECANPAY; + if (temp < Signature.SIGHASH_ALL || temp > Signature.SIGHASH_SINGLE) { + return false; + } + return true; + }; + + Signature.prototype.toTxFormat = function() { + var derbuf = this.toDER(); + var buf = new Buffer(1); + buf.writeUInt8(this.nhashtype, 0); + return Buffer.concat([derbuf, buf]); + }; + + Signature.SIGHASH_ALL = 0x01; + Signature.SIGHASH_NONE = 0x02; + Signature.SIGHASH_SINGLE = 0x03; + Signature.SIGHASH_ANYONECANPAY = 0x80; + + module.exports = Signature; + }.call(this, require('buffer').Buffer)); + }, + { '../util/buffer': 42, '../util/js': 43, '../util/preconditions': 44, './bn': 6, buffer: 113, lodash: 187 }, + ], + 12: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var _ = require('lodash'); + var bs58 = require('bs58'); + var buffer = require('buffer'); + + var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'.split(''); + + var Base58 = function Base58(obj) { + /* jshint maxcomplexity: 8 */ + if (!(this instanceof Base58)) { + return new Base58(obj); + } + if (Buffer.isBuffer(obj)) { + var buf = obj; + this.fromBuffer(buf); + } else if (typeof obj === 'string') { + var str = obj; + this.fromString(str); + } else if (obj) { + this.set(obj); + } + }; - if (buf.length === 1 & buf[0] === 0) { - buf = new Buffer([]); - } - return buf; -}; + Base58.validCharacters = function validCharacters(chars) { + if (buffer.Buffer.isBuffer(chars)) { + chars = chars.toString(); + } + return _.every( + _.map(chars, function(char) { + return _.includes(ALPHABET, char); + }), + ); + }; + + Base58.prototype.set = function(obj) { + this.buf = obj.buf || this.buf || undefined; + return this; + }; + + Base58.encode = function(buf) { + if (!buffer.Buffer.isBuffer(buf)) { + throw new Error('Input should be a buffer'); + } + return bs58.encode(buf); + }; -BN.prototype.toSM = function(opts) { - var endian = opts ? opts.endian : 'big'; - var buf = this.toSMBigEndian(); + Base58.decode = function(str) { + if (typeof str !== 'string') { + throw new Error('Input should be a string'); + } + return new Buffer(bs58.decode(str)); + }; + + Base58.prototype.fromBuffer = function(buf) { + this.buf = buf; + return this; + }; + + Base58.prototype.fromString = function(str) { + var buf = Base58.decode(str); + this.buf = buf; + return this; + }; + + Base58.prototype.toBuffer = function() { + return this.buf; + }; + + Base58.prototype.toString = function() { + return Base58.encode(this.buf); + }; + + module.exports = Base58; + }.call(this, require('buffer').Buffer)); + }, + { bs58: 110, buffer: 113, lodash: 187 }, + ], + 13: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var _ = require('lodash'); + var Base58 = require('./base58'); + var buffer = require('buffer'); + var sha256sha256 = require('../crypto/hash').sha256sha256; + + var Base58Check = function Base58Check(obj) { + if (!(this instanceof Base58Check)) return new Base58Check(obj); + if (Buffer.isBuffer(obj)) { + var buf = obj; + this.fromBuffer(buf); + } else if (typeof obj === 'string') { + var str = obj; + this.fromString(str); + } else if (obj) { + this.set(obj); + } + }; - if (endian === 'little') { - buf = reversebuf(buf); - } - return buf; -}; - -/** - * Create a BN from a "ScriptNum": - * This is analogous to the constructor for CScriptNum in meritd. Many ops in - * meritd's script interpreter use CScriptNum, which is not really a proper - * bignum. Instead, an error is thrown if trying to input a number bigger than - * 4 bytes. We copy that behavior here. A third argument, `size`, is provided to - * extend the hard limit of 4 bytes, as some usages require more than 4 bytes. - */ -BN.fromScriptNumBuffer = function(buf, fRequireMinimal, size) { - var nMaxNumSize = size || 4; - $.checkArgument(buf.length <= nMaxNumSize, new Error('script number overflow')); - if (fRequireMinimal && buf.length > 0) { - // Check that the number is encoded with the minimum possible - // number of bytes. - // - // If the most-significant-byte - excluding the sign bit - is zero - // then we're not minimal. Note how this test also rejects the - // negative-zero encoding, 0x80. - if ((buf[buf.length - 1] & 0x7f) === 0) { - // One exception: if there's more than one byte and the most - // significant bit of the second-most-significant-byte is set - // it would conflict with the sign bit. An example of this case - // is +-255, which encode to 0xff00 and 0xff80 respectively. - // (big-endian). - if (buf.length <= 1 || (buf[buf.length - 2] & 0x80) === 0) { - throw new Error('non-minimally encoded script number'); - } - } - } - return BN.fromSM(buf, { - endian: 'little' - }); -}; - -/** - * The corollary to the above, with the notable exception that we do not throw - * an error if the output is larger than four bytes. (Which can happen if - * performing a numerical operation that results in an overflow to more than 4 - * bytes). - */ -BN.prototype.toScriptNumBuffer = function() { - return this.toSM({ - endian: 'little' - }); -}; - -BN.prototype.gt = function(b) { - return this.cmp(b) > 0; -}; - -BN.prototype.gte = function(b) { - return this.cmp(b) >= 0; -}; - -BN.prototype.lt = function(b) { - return this.cmp(b) < 0; -}; - -BN.trim = function(buf, natlen) { - return buf.slice(natlen - buf.length, buf.length); -}; - -BN.pad = function(buf, natlen, size) { - var rbuf = new Buffer(size); - for (var i = 0; i < buf.length; i++) { - rbuf[rbuf.length - 1 - i] = buf[buf.length - 1 - i]; - } - for (i = 0; i < size - natlen; i++) { - rbuf[i] = 0; - } - return rbuf; -}; - -module.exports = BN; - -}).call(this,require("buffer").Buffer) -},{"../util/preconditions":44,"bn.js":62,"buffer":113,"lodash":187}],7:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var BN = require('./bn'); -var Point = require('./point'); -var Signature = require('./signature'); -var PublicKey = require('../publickey'); -var Random = require('./random'); -var Hash = require('./hash'); -var BufferUtil = require('../util/buffer'); -var _ = require('lodash'); -var $ = require('../util/preconditions'); - -var ECDSA = function ECDSA(obj) { - if (!(this instanceof ECDSA)) { - return new ECDSA(obj); - } - if (obj) { - this.set(obj); - } -}; - -/* jshint maxcomplexity: 9 */ -ECDSA.prototype.set = function(obj) { - this.hashbuf = obj.hashbuf || this.hashbuf; - this.endian = obj.endian || this.endian; //the endianness of hashbuf - this.privkey = obj.privkey || this.privkey; - this.pubkey = obj.pubkey || (this.privkey ? this.privkey.publicKey : this.pubkey); - this.sig = obj.sig || this.sig; - this.k = obj.k || this.k; - this.verified = obj.verified || this.verified; - return this; -}; - -ECDSA.prototype.privkey2pubkey = function() { - this.pubkey = this.privkey.toPublicKey(); -}; - -ECDSA.prototype.calci = function() { - for (var i = 0; i < 4; i++) { - this.sig.i = i; - var Qprime; - try { - Qprime = this.toPublicKey(); - } catch (e) { - console.error(e); - continue; - } + Base58Check.prototype.set = function(obj) { + this.buf = obj.buf || this.buf || undefined; + return this; + }; - if (Qprime.point.eq(this.pubkey.point)) { - this.sig.compressed = this.pubkey.compressed; - return this; - } - } + Base58Check.validChecksum = function validChecksum(data, checksum) { + if (_.isString(data)) { + data = new buffer.Buffer(Base58.decode(data)); + } + if (_.isString(checksum)) { + checksum = new buffer.Buffer(Base58.decode(checksum)); + } + if (!checksum) { + checksum = data.slice(-4); + data = data.slice(0, -4); + } + return Base58Check.checksum(data).toString('hex') === checksum.toString('hex'); + }; - this.sig.i = undefined; - throw new Error('Unable to find valid recovery factor'); -}; - -ECDSA.fromString = function(str) { - var obj = JSON.parse(str); - return new ECDSA(obj); -}; - -ECDSA.prototype.randomK = function() { - var N = Point.getN(); - var k; - do { - k = BN.fromBuffer(Random.getRandomBuffer(32)); - } while (!(k.lt(N) && k.gt(BN.Zero))); - this.k = k; - return this; -}; - - -// https://tools.ietf.org/html/rfc6979#section-3.2 -ECDSA.prototype.deterministicK = function(badrs) { - /* jshint maxstatements: 25 */ - // if r or s were invalid when this function was used in signing, - // we do not want to actually compute r, s here for efficiency, so, - // we can increment badrs. explained at end of RFC 6979 section 3.2 - if (_.isUndefined(badrs)) { - badrs = 0; - } - var v = new Buffer(32); - v.fill(0x01); - var k = new Buffer(32); - k.fill(0x00); - var x = this.privkey.bn.toBuffer({ - size: 32 - }); - var hashbuf = this.endian === 'little' ? BufferUtil.reverse(this.hashbuf) : this.hashbuf - k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00]), x, hashbuf]), k); - v = Hash.sha256hmac(v, k); - k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x01]), x, hashbuf]), k); - v = Hash.sha256hmac(v, k); - v = Hash.sha256hmac(v, k); - var T = BN.fromBuffer(v); - var N = Point.getN(); - - // also explained in 3.2, we must ensure T is in the proper range (0, N) - for (var i = 0; i < badrs || !(T.lt(N) && T.gt(BN.Zero)); i++) { - k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00])]), k); - v = Hash.sha256hmac(v, k); - v = Hash.sha256hmac(v, k); - T = BN.fromBuffer(v); - } + Base58Check.decode = function(s) { + if (typeof s !== 'string') throw new Error('Input must be a string'); - this.k = T; - return this; -}; + var buf = new Buffer(Base58.decode(s)); -// Information about public key recovery: -// https://bitcointalk.org/index.php?topic=6430.0 -// http://stackoverflow.com/questions/19665491/how-do-i-get-an-ecdsa-public-key-from-just-a-bitcoin-signature-sec1-4-1-6-k -ECDSA.prototype.toPublicKey = function() { - /* jshint maxstatements: 25 */ - var i = this.sig.i; - $.checkArgument(i === 0 || i === 1 || i === 2 || i === 3, new Error('i must be equal to 0, 1, 2, or 3')); + if (buf.length < 4) throw new Error('Input string too short'); - var e = BN.fromBuffer(this.hashbuf); - var r = this.sig.r; - var s = this.sig.s; + var data = buf.slice(0, -4); + var csum = buf.slice(-4); - // A set LSB signifies that the y-coordinate is odd - var isYOdd = i & 1; + var hash = sha256sha256(data); + var hash4 = hash.slice(0, 4); - // The more significant bit specifies whether we should use the - // first or second candidate key. - var isSecondKey = i >> 1; + if (csum.toString('hex') !== hash4.toString('hex')) throw new Error('Checksum mismatch'); - var n = Point.getN(); - var G = Point.getG(); + return data; + }; - // 1.1 Let x = r + jn - var x = isSecondKey ? r.add(n) : r; - var R = Point.fromX(isYOdd, x); + Base58Check.checksum = function(buffer) { + return sha256sha256(buffer).slice(0, 4); + }; - // 1.4 Check that nR is at infinity - var nR = R.mul(n); + Base58Check.encode = function(buf) { + if (!Buffer.isBuffer(buf)) throw new Error('Input must be a buffer'); + var checkedBuf = new Buffer(buf.length + 4); + var hash = Base58Check.checksum(buf); + buf.copy(checkedBuf); + hash.copy(checkedBuf, buf.length); + return Base58.encode(checkedBuf); + }; - if (!nR.isInfinity()) { - throw new Error('nR is not a valid curve point'); - } + Base58Check.prototype.fromBuffer = function(buf) { + this.buf = buf; + return this; + }; - // Compute -e from e - var eNeg = e.neg().mod(n); + Base58Check.prototype.fromString = function(str) { + var buf = Base58Check.decode(str); + this.buf = buf; + return this; + }; - // 1.6.1 Compute Q = r^-1 (sR - eG) - // Q = r^-1 (sR + -eG) - var rInv = r.invm(n); + Base58Check.prototype.toBuffer = function() { + return this.buf; + }; - //var Q = R.multiplyTwo(s, G, eNeg).mul(rInv); - var Q = R.mul(s).add(G.mul(eNeg)).mul(rInv); + Base58Check.prototype.toString = function() { + return Base58Check.encode(this.buf); + }; - var pubkey = PublicKey.fromPoint(Q, this.sig.compressed); + module.exports = Base58Check; + }.call(this, require('buffer').Buffer)); + }, + { '../crypto/hash': 8, './base58': 12, buffer: 113, lodash: 187 }, + ], + 14: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var _ = require('lodash'); + var $ = require('../util/preconditions'); + var BufferUtil = require('../util/buffer'); + var BN = require('../crypto/bn'); + + var BufferReader = function BufferReader(buf) { + if (!(this instanceof BufferReader)) { + return new BufferReader(buf); + } + if (_.isUndefined(buf)) { + return; + } + if (Buffer.isBuffer(buf)) { + this.set({ + buf: buf, + }); + } else if (_.isString(buf)) { + this.set({ + buf: new Buffer(buf, 'hex'), + }); + } else if (_.isObject(buf)) { + var obj = buf; + this.set(obj); + } else { + throw new TypeError('Unrecognized argument for BufferReader'); + } + }; + + BufferReader.prototype.set = function(obj) { + this.buf = obj.buf || this.buf || undefined; + this.pos = obj.pos || this.pos || 0; + return this; + }; + + BufferReader.prototype.eof = function() { + return this.pos >= this.buf.length; + }; + + BufferReader.prototype.finished = BufferReader.prototype.eof; + + BufferReader.prototype.read = function(len) { + $.checkArgument(!_.isUndefined(len), 'Must specify a length'); + var buf = this.buf.slice(this.pos, this.pos + len); + this.pos = this.pos + len; + return buf; + }; + + BufferReader.prototype.readAll = function() { + var buf = this.buf.slice(this.pos, this.buf.length); + this.pos = this.buf.length; + return buf; + }; + + BufferReader.prototype.readUInt8 = function() { + var val = this.buf.readUInt8(this.pos); + this.pos = this.pos + 1; + return val; + }; + + BufferReader.prototype.readUInt16BE = function() { + var val = this.buf.readUInt16BE(this.pos); + this.pos = this.pos + 2; + return val; + }; + + BufferReader.prototype.readUInt16LE = function() { + var val = this.buf.readUInt16LE(this.pos); + this.pos = this.pos + 2; + return val; + }; + + BufferReader.prototype.readUInt32BE = function() { + var val = this.buf.readUInt32BE(this.pos); + this.pos = this.pos + 4; + return val; + }; + + BufferReader.prototype.readUInt32LE = function() { + var val = this.buf.readUInt32LE(this.pos); + this.pos = this.pos + 4; + return val; + }; + + BufferReader.prototype.readInt32LE = function() { + var val = this.buf.readInt32LE(this.pos); + this.pos = this.pos + 4; + return val; + }; + + BufferReader.prototype.readUInt64BEBN = function() { + var buf = this.buf.slice(this.pos, this.pos + 8); + var bn = BN.fromBuffer(buf); + this.pos = this.pos + 8; + return bn; + }; + + BufferReader.prototype.readUInt64LEBN = function() { + var second = this.buf.readUInt32LE(this.pos); + var first = this.buf.readUInt32LE(this.pos + 4); + var combined = first * 0x100000000 + second; + // Instantiating an instance of BN with a number is faster than with an + // array or string. However, the maximum safe number for a double precision + // floating point is 2 ^ 52 - 1 (0x1fffffffffffff), thus we can safely use + // non-floating point numbers less than this amount (52 bits). And in the case + // that the number is larger, we can instatiate an instance of BN by passing + // an array from the buffer (slower) and specifying the endianness. + var bn; + if (combined <= 0x1fffffffffffff) { + bn = new BN(combined); + } else { + var data = Array.prototype.slice.call(this.buf, this.pos, this.pos + 8); + bn = new BN(data, 10, 'le'); + } + this.pos = this.pos + 8; + return bn; + }; + + BufferReader.prototype.readVarintNum = function() { + var first = this.readUInt8(); + switch (first) { + case 0xfd: + return this.readUInt16LE(); + case 0xfe: + return this.readUInt32LE(); + case 0xff: + var bn = this.readUInt64LEBN(); + var n = bn.toNumber(); + if (n <= Math.pow(2, 53)) { + return n; + } else { + throw new Error('number too large to retain precision - use readVarintBN'); + } + break; + default: + return first; + } + }; + + /** + * reads a length prepended buffer + */ + BufferReader.prototype.readVarLengthBuffer = function() { + var len = this.readVarintNum(); + var buf = this.read(len); + $.checkState( + buf.length === len, + 'Invalid length while reading varlength buffer. ' + + 'Expected to read: ' + + len + + ' and read ' + + buf.length, + ); + return buf; + }; + + BufferReader.prototype.readVarintBuf = function() { + var first = this.buf.readUInt8(this.pos); + switch (first) { + case 0xfd: + return this.read(1 + 2); + case 0xfe: + return this.read(1 + 4); + case 0xff: + return this.read(1 + 8); + default: + return this.read(1); + } + }; + + BufferReader.prototype.readVarintBN = function() { + var first = this.readUInt8(); + switch (first) { + case 0xfd: + return new BN(this.readUInt16LE()); + case 0xfe: + return new BN(this.readUInt32LE()); + case 0xff: + return this.readUInt64LEBN(); + default: + return new BN(first); + } + }; - return pubkey; -}; + BufferReader.prototype.reverse = function() { + var buf = new Buffer(this.buf.length); + for (var i = 0; i < buf.length; i++) { + buf[i] = this.buf[this.buf.length - 1 - i]; + } + this.buf = buf; + return this; + }; -ECDSA.prototype.sigError = function() { - /* jshint maxstatements: 25 */ - if (!BufferUtil.isBuffer(this.hashbuf) || this.hashbuf.length !== 32) { - return 'hashbuf must be a 32 byte buffer'; - } + BufferReader.prototype.readReverse = function(len) { + if (_.isUndefined(len)) { + len = this.buf.length; + } + var buf = this.buf.slice(this.pos, this.pos + len); + this.pos = this.pos + len; + return BufferUtil.reverse(buf); + }; - var r = this.sig.r; - var s = this.sig.s; - if (!(r.gt(BN.Zero) && r.lt(Point.getN())) || !(s.gt(BN.Zero) && s.lt(Point.getN()))) { - return 'r and s not in range'; - } + module.exports = BufferReader; + }.call(this, require('buffer').Buffer)); + }, + { '../crypto/bn': 6, '../util/buffer': 42, '../util/preconditions': 44, buffer: 113, lodash: 187 }, + ], + 15: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var bufferUtil = require('../util/buffer'); + var assert = require('assert'); + + var BufferWriter = function BufferWriter(obj) { + if (!(this instanceof BufferWriter)) return new BufferWriter(obj); + if (obj) this.set(obj); + else this.bufs = []; + }; + + BufferWriter.prototype.set = function(obj) { + this.bufs = obj.bufs || this.bufs || []; + return this; + }; + + BufferWriter.prototype.toBuffer = function() { + return this.concat(); + }; + + BufferWriter.prototype.concat = function() { + return Buffer.concat(this.bufs); + }; + + BufferWriter.prototype.write = function(buf) { + assert(bufferUtil.isBuffer(buf)); + this.bufs.push(buf); + return this; + }; + + BufferWriter.prototype.writeReverse = function(buf) { + assert(bufferUtil.isBuffer(buf)); + this.bufs.push(bufferUtil.reverse(buf)); + return this; + }; + + BufferWriter.prototype.writeUInt8 = function(n) { + var buf = new Buffer(1); + buf.writeUInt8(n, 0); + this.write(buf); + return this; + }; + + BufferWriter.prototype.writeUInt16BE = function(n) { + var buf = new Buffer(2); + buf.writeUInt16BE(n, 0); + this.write(buf); + return this; + }; + + BufferWriter.prototype.writeUInt16LE = function(n) { + var buf = new Buffer(2); + buf.writeUInt16LE(n, 0); + this.write(buf); + return this; + }; + + BufferWriter.prototype.writeUInt32BE = function(n) { + var buf = new Buffer(4); + buf.writeUInt32BE(n, 0); + this.write(buf); + return this; + }; + + BufferWriter.prototype.writeInt32LE = function(n) { + var buf = new Buffer(4); + buf.writeInt32LE(n, 0); + this.write(buf); + return this; + }; + + BufferWriter.prototype.writeUInt32LE = function(n) { + var buf = new Buffer(4); + buf.writeUInt32LE(n, 0); + this.write(buf); + return this; + }; + + BufferWriter.prototype.writeUInt64BEBN = function(bn) { + var buf = bn.toBuffer({ size: 8 }); + this.write(buf); + return this; + }; + + BufferWriter.prototype.writeUInt64LEBN = function(bn) { + var buf = bn.toBuffer({ size: 8 }); + this.writeReverse(buf); + return this; + }; + + BufferWriter.prototype.writeVarintNum = function(n) { + var buf = BufferWriter.varintBufNum(n); + this.write(buf); + return this; + }; + + BufferWriter.prototype.writeVarintBN = function(bn) { + var buf = BufferWriter.varintBufBN(bn); + this.write(buf); + return this; + }; + + BufferWriter.varintBufNum = function(n) { + var buf = undefined; + if (n < 253) { + buf = new Buffer(1); + buf.writeUInt8(n, 0); + } else if (n < 0x10000) { + buf = new Buffer(1 + 2); + buf.writeUInt8(253, 0); + buf.writeUInt16LE(n, 1); + } else if (n < 0x100000000) { + buf = new Buffer(1 + 4); + buf.writeUInt8(254, 0); + buf.writeUInt32LE(n, 1); + } else { + buf = new Buffer(1 + 8); + buf.writeUInt8(255, 0); + buf.writeInt32LE(n & -1, 1); + buf.writeUInt32LE(Math.floor(n / 0x100000000), 5); + } + return buf; + }; + + BufferWriter.varintBufBN = function(bn) { + var buf = undefined; + var n = bn.toNumber(); + if (n < 253) { + buf = new Buffer(1); + buf.writeUInt8(n, 0); + } else if (n < 0x10000) { + buf = new Buffer(1 + 2); + buf.writeUInt8(253, 0); + buf.writeUInt16LE(n, 1); + } else if (n < 0x100000000) { + buf = new Buffer(1 + 4); + buf.writeUInt8(254, 0); + buf.writeUInt32LE(n, 1); + } else { + var bw = new BufferWriter(); + bw.writeUInt8(255); + bw.writeUInt64LEBN(bn); + var buf = bw.concat(); + } + return buf; + }; - var e = BN.fromBuffer(this.hashbuf, this.endian ? { - endian: this.endian - } : undefined); - var n = Point.getN(); - var sinv = s.invm(n); - var u1 = sinv.mul(e).mod(n); - var u2 = sinv.mul(r).mod(n); - - var p = Point.getG().mulAdd(u1, this.pubkey.point, u2); - if (p.isInfinity()) { - return 'p is infinity'; - } + module.exports = BufferWriter; + }.call(this, require('buffer').Buffer)); + }, + { '../util/buffer': 42, assert: 60, buffer: 113 }, + ], + 16: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var BufferWriter = require('./bufferwriter'); + var BufferReader = require('./bufferreader'); + var BN = require('../crypto/bn'); + + var Varint = function Varint(buf) { + if (!(this instanceof Varint)) return new Varint(buf); + if (Buffer.isBuffer(buf)) { + this.buf = buf; + } else if (typeof buf === 'number') { + var num = buf; + this.fromNumber(num); + } else if (buf instanceof BN) { + var bn = buf; + this.fromBN(bn); + } else if (buf) { + var obj = buf; + this.set(obj); + } + }; + + Varint.prototype.set = function(obj) { + this.buf = obj.buf || this.buf; + return this; + }; + + Varint.prototype.fromString = function(str) { + this.set({ + buf: new Buffer(str, 'hex'), + }); + return this; + }; + + Varint.prototype.toString = function() { + return this.buf.toString('hex'); + }; + + Varint.prototype.fromBuffer = function(buf) { + this.buf = buf; + return this; + }; + + Varint.prototype.fromBufferReader = function(br) { + this.buf = br.readVarintBuf(); + return this; + }; + + Varint.prototype.fromBN = function(bn) { + this.buf = BufferWriter() + .writeVarintBN(bn) + .concat(); + return this; + }; + + Varint.prototype.fromNumber = function(num) { + this.buf = BufferWriter() + .writeVarintNum(num) + .concat(); + return this; + }; + + Varint.prototype.toBuffer = function() { + return this.buf; + }; + + Varint.prototype.toBN = function() { + return BufferReader(this.buf).readVarintBN(); + }; + + Varint.prototype.toNumber = function() { + return BufferReader(this.buf).readVarintNum(); + }; + + module.exports = Varint; + }.call(this, require('buffer').Buffer)); + }, + { '../crypto/bn': 6, './bufferreader': 14, './bufferwriter': 15, buffer: 113 }, + ], + 17: [ + function(require, module, exports) { + 'use strict'; + + var _ = require('lodash'); + + function format(message, args) { + return message + .replace('{0}', args[0]) + .replace('{1}', args[1]) + .replace('{2}', args[2]); + } + var traverseNode = function(parent, errorDefinition) { + var NodeError = function() { + if (_.isString(errorDefinition.message)) { + this.message = format(errorDefinition.message, arguments); + } else if (_.isFunction(errorDefinition.message)) { + this.message = errorDefinition.message.apply(null, arguments); + } else { + throw new Error('Invalid error definition for ' + errorDefinition.name); + } + this.stack = this.message + '\n' + new Error().stack; + }; + NodeError.prototype = Object.create(parent.prototype); + NodeError.prototype.name = parent.prototype.name + errorDefinition.name; + parent[errorDefinition.name] = NodeError; + if (errorDefinition.errors) { + childDefinitions(NodeError, errorDefinition.errors); + } + return NodeError; + }; - if (p.getX().mod(n).cmp(r) !== 0) { - return 'Invalid signature'; - } else { - return false; - } -}; + /* jshint latedef: false */ + var childDefinitions = function(parent, childDefinitions) { + _.each(childDefinitions, function(childDefinition) { + traverseNode(parent, childDefinition); + }); + }; + /* jshint latedef: true */ -ECDSA.toLowS = function(s) { - //enforce low s - //see BIP 62, "low S values in signatures" - if (s.gt(BN.fromBuffer(new Buffer('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex')))) { - s = Point.getN().sub(s); - } - return s; -}; - -ECDSA.prototype._findSignature = function(d, e) { - var N = Point.getN(); - var G = Point.getG(); - // try different values of k until r, s are valid - var badrs = 0; - var k, Q, r, s; - do { - if (!this.k || badrs > 0) { - this.deterministicK(badrs); - } - badrs++; - k = this.k; - Q = G.mul(k); - r = Q.x.mod(N); - s = k.invm(N).mul(e.add(d.mul(r))).mod(N); - } while (r.cmp(BN.Zero) <= 0 || s.cmp(BN.Zero) <= 0); - - s = ECDSA.toLowS(s); - return { - s: s, - r: r - }; - -}; - -ECDSA.prototype.sign = function() { - var hashbuf = this.hashbuf; - var privkey = this.privkey; - var d = privkey.bn; - - $.checkState(hashbuf && privkey && d, new Error('invalid parameters')); - $.checkState(BufferUtil.isBuffer(hashbuf) && hashbuf.length === 32, new Error('hashbuf must be a 32 byte buffer')); - - var e = BN.fromBuffer(hashbuf, this.endian ? { - endian: this.endian - } : undefined); - - var obj = this._findSignature(d, e); - obj.compressed = this.pubkey.compressed; - - this.sig = new Signature(obj); - return this; -}; - -ECDSA.prototype.signRandomK = function() { - this.randomK(); - return this.sign(); -}; - -ECDSA.prototype.toString = function() { - var obj = {}; - if (this.hashbuf) { - obj.hashbuf = this.hashbuf.toString('hex'); - } - if (this.privkey) { - obj.privkey = this.privkey.toString(); - } - if (this.pubkey) { - obj.pubkey = this.pubkey.toString(); - } - if (this.sig) { - obj.sig = this.sig.toString(); - } - if (this.k) { - obj.k = this.k.toString(); - } - return JSON.stringify(obj); -}; - -ECDSA.prototype.verify = function() { - if (!this.sigError()) { - this.verified = true; - } else { - this.verified = false; - } - return this; -}; - -ECDSA.sign = function(hashbuf, privkey, endian) { - return ECDSA().set({ - hashbuf: hashbuf, - endian: endian, - privkey: privkey - }).sign().sig; -}; - -ECDSA.verify = function(hashbuf, sig, pubkey, endian) { - return ECDSA().set({ - hashbuf: hashbuf, - endian: endian, - sig: sig, - pubkey: pubkey - }).verify().verified; -}; - -module.exports = ECDSA; - -}).call(this,require("buffer").Buffer) -},{"../publickey":24,"../util/buffer":42,"../util/preconditions":44,"./bn":6,"./hash":8,"./point":9,"./random":10,"./signature":11,"buffer":113,"lodash":187}],8:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var crypto = require('crypto'); -var BufferUtil = require('../util/buffer'); -var $ = require('../util/preconditions'); - -var Hash = module.exports; - -Hash.sha1 = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - return crypto.createHash('sha1').update(buf).digest(); -}; - -Hash.sha1.blocksize = 512; - -Hash.sha256 = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - return crypto.createHash('sha256').update(buf).digest(); -}; - -Hash.sha256.blocksize = 512; - -Hash.sha256sha256 = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - return Hash.sha256(Hash.sha256(buf)); -}; - -Hash.ripemd160 = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - return crypto.createHash('ripemd160').update(buf).digest(); -}; - -Hash.sha256ripemd160 = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - return Hash.ripemd160(Hash.sha256(buf)); -}; - -Hash.sha512 = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - return crypto.createHash('sha512').update(buf).digest(); -}; - -Hash.sha512.blocksize = 1024; - -Hash.hmac = function(hashf, data, key) { - //http://en.wikipedia.org/wiki/Hash-based_message_authentication_code - //http://tools.ietf.org/html/rfc4868#section-2 - $.checkArgument(BufferUtil.isBuffer(data)); - $.checkArgument(BufferUtil.isBuffer(key)); - $.checkArgument(hashf.blocksize); - - var blocksize = hashf.blocksize / 8; - - if (key.length > blocksize) { - key = hashf(key); - } else if (key < blocksize) { - var fill = new Buffer(blocksize); - fill.fill(0); - key.copy(fill); - key = fill; - } + var traverseRoot = function(parent, errorsDefinition) { + childDefinitions(parent, errorsDefinition); + return parent; + }; - var o_key = new Buffer(blocksize); - o_key.fill(0x5c); + var bitcore = {}; + bitcore.Error = function() { + this.message = 'Internal error'; + this.stack = this.message + '\n' + new Error().stack; + }; + bitcore.Error.prototype = Object.create(Error.prototype); + bitcore.Error.prototype.name = 'bitcore.Error'; - var i_key = new Buffer(blocksize); - i_key.fill(0x36); + var data = require('./spec'); + traverseRoot(bitcore.Error, data); - var o_key_pad = new Buffer(blocksize); - var i_key_pad = new Buffer(blocksize); - for (var i = 0; i < blocksize; i++) { - o_key_pad[i] = o_key[i] ^ key[i]; - i_key_pad[i] = i_key[i] ^ key[i]; - } + module.exports = bitcore.Error; - return hashf(Buffer.concat([o_key_pad, hashf(Buffer.concat([i_key_pad, data]))])); -}; + module.exports.extend = function(spec) { + return traverseNode(bitcore.Error, spec); + }; + }, + { './spec': 18, lodash: 187 }, + ], + 18: [ + function(require, module, exports) { + 'use strict'; + + var docsURL = 'http://bitcore.io/'; + + module.exports = [ + { + name: 'InvalidB58Char', + message: 'Invalid Base58 character: {0} in {1}', + }, + { + name: 'InvalidB58Checksum', + message: 'Invalid Base58 checksum for {0}', + }, + { + name: 'InvalidNetwork', + message: 'Invalid version for network: got {0}', + }, + { + name: 'InvalidState', + message: 'Invalid state: {0}', + }, + { + name: 'NotImplemented', + message: 'Function {0} was not implemented yet', + }, + { + name: 'InvalidNetworkArgument', + message: 'Invalid network: must be "livenet" or "testnet", got {0}', + }, + { + name: 'InvalidArgument', + message: function() { + return ( + 'Invalid Argument' + + (arguments[0] ? ': ' + arguments[0] : '') + + (arguments[1] ? ' Documentation: ' + docsURL + arguments[1] : '') + ); + }, + }, + { + name: 'AbstractMethodInvoked', + message: 'Abstract Method Invocation: {0}', + }, + { + name: 'InvalidArgumentType', + message: function() { + return ( + 'Invalid Argument for ' + + arguments[2] + + ', expected ' + + arguments[1] + + ' but got ' + + typeof arguments[0] + ); + }, + }, + { + name: 'Unit', + message: 'Internal Error on Unit {0}', + errors: [ + { + name: 'UnknownCode', + message: 'Unrecognized unit code: {0}', + }, + { + name: 'InvalidRate', + message: 'Invalid exchange rate: {0}', + }, + ], + }, + { + name: 'Transaction', + message: 'Internal Error on Transaction {0}', + errors: [ + { + name: 'Input', + message: 'Internal Error on Input {0}', + errors: [ + { + name: 'MissingScript', + message: 'Need a script to create an input', + }, + { + name: 'UnsupportedScript', + message: 'Unsupported input script type: {0}', + }, + { + name: 'MissingPreviousOutput', + message: 'No previous output information.', + }, + ], + }, + { + name: 'NeedMoreInfo', + message: '{0}', + }, + { + name: 'InvalidSorting', + message: 'The sorting function provided did not return the change output as one of the array elements', + }, + { + name: 'InvalidOutputAmountSum', + message: '{0}', + }, + { + name: 'MissingSignatures', + message: 'Some inputs have not been fully signed', + }, + { + name: 'InvalidIndex', + message: 'Invalid index: {0} is not between 0, {1}', + }, + { + name: 'UnableToVerifySignature', + message: 'Unable to verify signature: {0}', + }, + { + name: 'DustOutputs', + message: 'Dust amount detected in one output', + }, + { + name: 'InvalidMicros', + message: 'Output micros are invalid', + }, + { + name: 'FeeError', + message: 'Internal Error on Fee {0}', + errors: [ + { + name: 'TooSmall', + message: 'Fee is too small: {0}', + }, + { + name: 'TooLarge', + message: 'Fee is too large: {0}', + }, + { + name: 'Different', + message: 'Unspent value is different from specified fee: {0}', + }, + ], + }, + { + name: 'ChangeAddressMissing', + message: 'Change address is missing', + }, + { + name: 'BlockHeightTooHigh', + message: 'Block Height can be at most 2^32 -1', + }, + { + name: 'NLockTimeOutOfRange', + message: 'Block Height can only be between 0 and 499 999 999', + }, + { + name: 'LockTimeTooEarly', + message: "Lock Time can't be earlier than UNIX date 500 000 000", + }, + ], + }, + { + name: 'Script', + message: 'Internal Error on Script {0}', + errors: [ + { + name: 'UnrecognizedAddress', + message: 'Expected argument {0} to be an address', + }, + { + name: 'CantDeriveAddress', + message: + "Can't derive address associated with script {0}, needs to be p2pkh in, p2pkh out, p2sh in, or p2sh out.", + }, + { + name: 'InvalidBuffer', + message: "Invalid script buffer: can't parse valid script from given buffer {0}", + }, + ], + }, + { + name: 'HDPrivateKey', + message: 'Internal Error on HDPrivateKey {0}', + errors: [ + { + name: 'InvalidDerivationArgument', + message: 'Invalid derivation argument {0}, expected string, or number and boolean', + }, + { + name: 'InvalidEntropyArgument', + message: 'Invalid entropy: must be an hexa string or binary buffer, got {0}', + errors: [ + { + name: 'TooMuchEntropy', + message: 'Invalid entropy: more than 512 bits is non standard, got "{0}"', + }, + { + name: 'NotEnoughEntropy', + message: 'Invalid entropy: at least 128 bits needed, got "{0}"', + }, + ], + }, + { + name: 'InvalidLength', + message: 'Invalid length for xprivkey string in {0}', + }, + { + name: 'InvalidPath', + message: 'Invalid derivation path: {0}', + }, + { + name: 'UnrecognizedArgument', + message: + 'Invalid argument: creating a HDPrivateKey requires a string, buffer, json or object, got "{0}"', + }, + ], + }, + { + name: 'HDPublicKey', + message: 'Internal Error on HDPublicKey {0}', + errors: [ + { + name: 'ArgumentIsPrivateExtended', + message: 'Argument is an extended private key: {0}', + }, + { + name: 'InvalidDerivationArgument', + message: 'Invalid derivation argument: got {0}', + }, + { + name: 'InvalidLength', + message: 'Invalid length for xpubkey: got "{0}"', + }, + { + name: 'InvalidPath', + message: 'Invalid derivation path, it should look like: "m/1/100", got "{0}"', + }, + { + name: 'InvalidIndexCantDeriveHardened', + message: 'Invalid argument: creating a hardened path requires an HDPrivateKey', + }, + { + name: 'MustSupplyArgument', + message: 'Must supply an argument to create a HDPublicKey', + }, + { + name: 'UnrecognizedArgument', + message: 'Invalid argument for creation, must be string, json, buffer, or object', + }, + ], + }, + ]; + }, + {}, + ], + 19: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var assert = require('assert'); + var buffer = require('buffer'); + var _ = require('lodash'); + var $ = require('./util/preconditions'); + + var BN = require('./crypto/bn'); + var Base58 = require('./encoding/base58'); + var Base58Check = require('./encoding/base58check'); + var Hash = require('./crypto/hash'); + var Network = require('./networks'); + var Point = require('./crypto/point'); + var PrivateKey = require('./privatekey'); + var Random = require('./crypto/random'); + + var errors = require('./errors'); + var hdErrors = errors.HDPrivateKey; + var BufferUtil = require('./util/buffer'); + var JSUtil = require('./util/js'); + + var MINIMUM_ENTROPY_BITS = 128; + var BITS_TO_BYTES = 1 / 8; + var MAXIMUM_ENTROPY_BITS = 512; + + /** + * Represents an instance of an hierarchically derived private key. + * + * More info on https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki + * + * @constructor + * @param {string|Buffer|Object} arg + */ + function HDPrivateKey(arg) { + /* jshint maxcomplexity: 10 */ + if (arg instanceof HDPrivateKey) { + return arg; + } + if (!(this instanceof HDPrivateKey)) { + return new HDPrivateKey(arg); + } + if (!arg) { + return this._generateRandomly(); + } -Hash.sha256hmac = function(data, key) { - return Hash.hmac(Hash.sha256, data, key); -}; + if (Network.get(arg)) { + return this._generateRandomly(arg); + } else if (_.isString(arg) || BufferUtil.isBuffer(arg)) { + if (HDPrivateKey.isValidSerialized(arg)) { + this._buildFromSerialized(arg); + } else if (JSUtil.isValidJSON(arg)) { + this._buildFromJSON(arg); + } else if (BufferUtil.isBuffer(arg) && HDPrivateKey.isValidSerialized(arg.toString())) { + this._buildFromSerialized(arg.toString()); + } else { + throw HDPrivateKey.getSerializedError(arg); + } + } else if (_.isObject(arg)) { + this._buildFromObject(arg); + } else { + throw new hdErrors.UnrecognizedArgument(arg); + } + } -Hash.sha512hmac = function(data, key) { - return Hash.hmac(Hash.sha512, data, key); -}; + /** + * Verifies that a given path is valid. + * + * @param {string|number} arg + * @param {boolean?} hardened + * @return {boolean} + */ + HDPrivateKey.isValidPath = function(arg, hardened) { + if (_.isString(arg)) { + var indexes = HDPrivateKey._getDerivationIndexes(arg); + return indexes !== null && _.every(indexes, HDPrivateKey.isValidPath); + } -}).call(this,require("buffer").Buffer) -},{"../util/buffer":42,"../util/preconditions":44,"buffer":113,"crypto":139}],9:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + if (_.isNumber(arg)) { + if (arg < HDPrivateKey.Hardened && hardened === true) { + arg += HDPrivateKey.Hardened; + } + return arg >= 0 && arg < HDPrivateKey.MaxIndex; + } -var BN = require('./bn'); -var BufferUtil = require('../util/buffer'); -var ec = require('elliptic').curves.secp256k1; -var ecPoint = ec.curve.point.bind(ec.curve); -var ecPointFromX = ec.curve.pointFromX.bind(ec.curve); + return false; + }; + + /** + * Internal function that splits a string path into a derivation index array. + * It will return null if the string path is malformed. + * It does not validate if indexes are in bounds. + * + * @param {string} path + * @return {Array} + */ + HDPrivateKey._getDerivationIndexes = function(path) { + var steps = path.split('/'); + + // Special cases: + if (_.includes(HDPrivateKey.RootElementAlias, path)) { + return []; + } -/** - * - * Instantiate a valid secp256k1 Point from the X and Y coordinates. - * - * @param {BN|String} x - The X coordinate - * @param {BN|String} y - The Y coordinate - * @link https://github.com/indutny/elliptic - * @augments elliptic.curve.point - * @throws {Error} A validation error if exists - * @returns {Point} An instance of Point - * @constructor - */ -var Point = function Point(x, y, isRed) { - var point = ecPoint(x, y, isRed); - point.validate(); - return point; -}; + if (!_.includes(HDPrivateKey.RootElementAlias, steps[0])) { + return null; + } -Point.prototype = Object.getPrototypeOf(ec.curve.point()); + var indexes = steps.slice(1).map(function(step) { + var isHardened = step.slice(-1) === "'"; + if (isHardened) { + step = step.slice(0, -1); + } + if (!step || step[0] === '-') { + return NaN; + } + var index = +step; // cast to number + if (isHardened) { + index += HDPrivateKey.Hardened; + } -/** - * - * Instantiate a valid secp256k1 Point from only the X coordinate - * - * @param {boolean} odd - If the Y coordinate is odd - * @param {BN|String} x - The X coordinate - * @throws {Error} A validation error if exists - * @returns {Point} An instance of Point - */ -Point.fromX = function fromX(odd, x){ - var point = ecPointFromX(odd, x); - point.validate(); - return point; -}; + return index; + }); + + return _.some(indexes, isNaN) ? null : indexes; + }; + + /** + * WARNING: This method is deprecated. Use deriveChild or deriveNonCompliantChild instead. This is not BIP32 compliant + * + * + * Get a derived child based on a string or number. + * + * If the first argument is a string, it's parsed as the full path of + * derivation. Valid values for this argument include "m" (which returns the + * same private key), "m/0/1/40/2'/1000", where the ' quote means a hardened + * derivation. + * + * If the first argument is a number, the child with that index will be + * derived. If the second argument is truthy, the hardened version will be + * derived. See the example usage for clarification. + * + * @example + * ```javascript + * var parent = new HDPrivateKey('xprv...'); + * var child_0_1_2h = parent.derive(0).derive(1).derive(2, true); + * var copy_of_child_0_1_2h = parent.derive("m/0/1/2'"); + * assert(child_0_1_2h.xprivkey === copy_of_child_0_1_2h); + * ``` + * + * @param {string|number} arg + * @param {boolean?} hardened + */ + HDPrivateKey.prototype.derive = function(arg, hardened) { + return this.deriveNonCompliantChild(arg, hardened); + }; + + /** + * WARNING: This method will not be officially supported until v1.0.0. + * + * + * Get a derived child based on a string or number. + * + * If the first argument is a string, it's parsed as the full path of + * derivation. Valid values for this argument include "m" (which returns the + * same private key), "m/0/1/40/2'/1000", where the ' quote means a hardened + * derivation. + * + * If the first argument is a number, the child with that index will be + * derived. If the second argument is truthy, the hardened version will be + * derived. See the example usage for clarification. + * + * WARNING: The `nonCompliant` option should NOT be used, except for older implementation + * that used a derivation strategy that used a non-zero padded private key. + * + * @example + * ```javascript + * var parent = new HDPrivateKey('xprv...'); + * var child_0_1_2h = parent.deriveChild(0).deriveChild(1).deriveChild(2, true); + * var copy_of_child_0_1_2h = parent.deriveChild("m/0/1/2'"); + * assert(child_0_1_2h.xprivkey === copy_of_child_0_1_2h); + * ``` + * + * @param {string|number} arg + * @param {boolean?} hardened + */ + HDPrivateKey.prototype.deriveChild = function(arg, hardened) { + if (_.isNumber(arg)) { + return this._deriveWithNumber(arg, hardened); + } else if (_.isString(arg)) { + return this._deriveFromString(arg); + } else { + throw new hdErrors.InvalidDerivationArgument(arg); + } + }; + + /** + * WARNING: This method will not be officially supported until v1.0.0 + * + * + * WARNING: If this is a new implementation you should NOT use this method, you should be using + * `derive` instead. + * + * This method is explicitly for use and compatibility with an implementation that + * was not compliant with BIP32 regarding the derivation algorithm. The private key + * must be 32 bytes hashing, and this implementation will use the non-zero padded + * serialization of a private key, such that it's still possible to derive the privateKey + * to recover those funds. + * + * @param {string|number} arg + * @param {boolean?} hardened + */ + HDPrivateKey.prototype.deriveNonCompliantChild = function(arg, hardened) { + if (_.isNumber(arg)) { + return this._deriveWithNumber(arg, hardened, true); + } else if (_.isString(arg)) { + return this._deriveFromString(arg, true); + } else { + throw new hdErrors.InvalidDerivationArgument(arg); + } + }; -/** - * - * Will return a secp256k1 ECDSA base point. - * - * @link https://en.bitcoin.it/wiki/Secp256k1 - * @returns {Point} An instance of the base point. - */ -Point.getG = function getG() { - return ec.curve.g; -}; + HDPrivateKey.prototype._deriveWithNumber = function(index, hardened, nonCompliant) { + /* jshint maxstatements: 20 */ + /* jshint maxcomplexity: 10 */ + if (!HDPrivateKey.isValidPath(index, hardened)) { + throw new hdErrors.InvalidPath(index); + } -/** - * - * Will return the max of range of valid private keys as governed by the secp256k1 ECDSA standard. - * - * @link https://en.bitcoin.it/wiki/Private_key#Range_of_valid_ECDSA_private_keys - * @returns {BN} A BN instance of the number of points on the curve - */ -Point.getN = function getN() { - return new BN(ec.curve.n.toArray()); -}; + hardened = index >= HDPrivateKey.Hardened ? true : hardened; + if (index < HDPrivateKey.Hardened && hardened === true) { + index += HDPrivateKey.Hardened; + } -Point.prototype._getX = Point.prototype.getX; + var indexBuffer = BufferUtil.integerAsBuffer(index); + var data; + if (hardened && nonCompliant) { + // The private key serialization in this case will not be exactly 32 bytes and can be + // any value less, and the value is not zero-padded. + var nonZeroPadded = this.privateKey.bn.toBuffer(); + data = BufferUtil.concat([new buffer.Buffer([0]), nonZeroPadded, indexBuffer]); + } else if (hardened) { + // This will use a 32 byte zero padded serialization of the private key + var privateKeyBuffer = this.privateKey.bn.toBuffer({ size: 32 }); + assert(privateKeyBuffer.length === 32, 'length of private key buffer is expected to be 32 bytes'); + data = BufferUtil.concat([new buffer.Buffer([0]), privateKeyBuffer, indexBuffer]); + } else { + data = BufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]); + } + var hash = Hash.sha512hmac(data, this._buffers.chainCode); + var leftPart = BN.fromBuffer(hash.slice(0, 32), { + size: 32, + }); + var chainCode = hash.slice(32, 64); + + var privateKey = leftPart + .add(this.privateKey.toBigNumber()) + .mod(Point.getN()) + .toBuffer({ + size: 32, + }); + + if (!PrivateKey.isValid(privateKey)) { + // Index at this point is already hardened, we can pass null as the hardened arg + return this._deriveWithNumber(index + 1, null, nonCompliant); + } -/** - * - * Will return the X coordinate of the Point - * - * @returns {BN} A BN instance of the X coordinate - */ -Point.prototype.getX = function getX() { - return new BN(this._getX().toArray()); -}; + var derived = new HDPrivateKey({ + network: this.network, + depth: this.depth + 1, + parentFingerPrint: this.fingerPrint, + childIndex: index, + chainCode: chainCode, + privateKey: privateKey, + }); + + return derived; + }; + + HDPrivateKey.prototype._deriveFromString = function(path, nonCompliant) { + if (!HDPrivateKey.isValidPath(path)) { + throw new hdErrors.InvalidPath(path); + } -Point.prototype._getY = Point.prototype.getY; + var indexes = HDPrivateKey._getDerivationIndexes(path); + var derived = indexes.reduce(function(prev, index) { + return prev._deriveWithNumber(index, null, nonCompliant); + }, this); + + return derived; + }; + + /** + * Verifies that a given serialized private key in base58 with checksum format + * is valid. + * + * @param {string|Buffer} data - the serialized private key + * @param {string|Network=} network - optional, if present, checks that the + * network provided matches the network serialized. + * @return {boolean} + */ + HDPrivateKey.isValidSerialized = function(data, network) { + return !HDPrivateKey.getSerializedError(data, network); + }; + + /** + * Checks what's the error that causes the validation of a serialized private key + * in base58 with checksum to fail. + * + * @param {string|Buffer} data - the serialized private key + * @param {string|Network=} network - optional, if present, checks that the + * network provided matches the network serialized. + * @return {errors.InvalidArgument|null} + */ + HDPrivateKey.getSerializedError = function(data, network) { + /* jshint maxcomplexity: 10 */ + if (!(_.isString(data) || BufferUtil.isBuffer(data))) { + return new hdErrors.UnrecognizedArgument('Expected string or buffer'); + } + if (!Base58.validCharacters(data)) { + return new errors.InvalidB58Char('(unknown)', data); + } + try { + data = Base58Check.decode(data); + } catch (e) { + return new errors.InvalidB58Checksum(data); + } + if (data.length !== HDPrivateKey.DataLength) { + return new hdErrors.InvalidLength(data); + } + if (!_.isUndefined(network)) { + var error = HDPrivateKey._validateNetwork(data, network); + if (error) { + return error; + } + } + return null; + }; -/** - * - * Will return the Y coordinate of the Point - * - * @returns {BN} A BN instance of the Y coordinate - */ -Point.prototype.getY = function getY() { - return new BN(this._getY().toArray()); -}; + HDPrivateKey._validateNetwork = function(data, networkArg) { + var network = Network.get(networkArg); + if (!network) { + return new errors.InvalidNetworkArgument(networkArg); + } + var version = data.slice(0, 4); + if (BufferUtil.integerFromBuffer(version) !== network.xprivkey) { + return new errors.InvalidNetwork(version); + } + return null; + }; + + HDPrivateKey.fromString = function(arg) { + $.checkArgument(_.isString(arg), 'No valid string was provided'); + return new HDPrivateKey(arg); + }; + + HDPrivateKey.fromObject = function(arg) { + $.checkArgument(_.isObject(arg), 'No valid argument was provided'); + return new HDPrivateKey(arg); + }; + + HDPrivateKey.prototype._buildFromJSON = function(arg) { + return this._buildFromObject(JSON.parse(arg)); + }; + + HDPrivateKey.prototype._buildFromObject = function(arg) { + /* jshint maxcomplexity: 12 */ + // TODO: Type validation + var buffers = { + version: arg.network ? BufferUtil.integerAsBuffer(Network.get(arg.network).xprivkey) : arg.version, + depth: _.isNumber(arg.depth) ? BufferUtil.integerAsSingleByteBuffer(arg.depth) : arg.depth, + parentFingerPrint: _.isNumber(arg.parentFingerPrint) + ? BufferUtil.integerAsBuffer(arg.parentFingerPrint) + : arg.parentFingerPrint, + childIndex: _.isNumber(arg.childIndex) ? BufferUtil.integerAsBuffer(arg.childIndex) : arg.childIndex, + chainCode: _.isString(arg.chainCode) ? BufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode, + privateKey: + _.isString(arg.privateKey) && JSUtil.isHexa(arg.privateKey) + ? BufferUtil.hexToBuffer(arg.privateKey) + : arg.privateKey, + checksum: arg.checksum + ? arg.checksum.length + ? arg.checksum + : BufferUtil.integerAsBuffer(arg.checksum) + : undefined, + }; + return this._buildFromBuffers(buffers); + }; + + HDPrivateKey.prototype._buildFromSerialized = function(arg) { + var decoded = Base58Check.decode(arg); + var buffers = { + version: decoded.slice(HDPrivateKey.VersionStart, HDPrivateKey.VersionEnd), + depth: decoded.slice(HDPrivateKey.DepthStart, HDPrivateKey.DepthEnd), + parentFingerPrint: decoded.slice(HDPrivateKey.ParentFingerPrintStart, HDPrivateKey.ParentFingerPrintEnd), + childIndex: decoded.slice(HDPrivateKey.ChildIndexStart, HDPrivateKey.ChildIndexEnd), + chainCode: decoded.slice(HDPrivateKey.ChainCodeStart, HDPrivateKey.ChainCodeEnd), + privateKey: decoded.slice(HDPrivateKey.PrivateKeyStart, HDPrivateKey.PrivateKeyEnd), + checksum: decoded.slice(HDPrivateKey.ChecksumStart, HDPrivateKey.ChecksumEnd), + xprivkey: arg, + }; + return this._buildFromBuffers(buffers); + }; + + HDPrivateKey.prototype._generateRandomly = function(network) { + return HDPrivateKey.fromSeed(Random.getRandomBuffer(64), network); + }; + + /** + * Generate a private key from a seed, as described in BIP32 + * + * @param {string|Buffer} hexa + * @param {*} network + * @return HDPrivateKey + */ + HDPrivateKey.fromSeed = function(hexa, network) { + /* jshint maxcomplexity: 8 */ + if (JSUtil.isHexaString(hexa)) { + hexa = BufferUtil.hexToBuffer(hexa); + } + if (!Buffer.isBuffer(hexa)) { + throw new hdErrors.InvalidEntropyArgument(hexa); + } + if (hexa.length < MINIMUM_ENTROPY_BITS * BITS_TO_BYTES) { + throw new hdErrors.InvalidEntropyArgument.NotEnoughEntropy(hexa); + } + if (hexa.length > MAXIMUM_ENTROPY_BITS * BITS_TO_BYTES) { + throw new hdErrors.InvalidEntropyArgument.TooMuchEntropy(hexa); + } + var hash = Hash.sha512hmac(hexa, new buffer.Buffer('Merit seed')); + + return new HDPrivateKey({ + network: Network.get(network) || Network.defaultNetwork, + depth: 0, + parentFingerPrint: 0, + childIndex: 0, + privateKey: hash.slice(0, 32), + chainCode: hash.slice(32, 64), + }); + }; + + HDPrivateKey.prototype._calcHDPublicKey = function() { + if (!this._hdPublicKey) { + var HDPublicKey = require('./hdpublickey'); + this._hdPublicKey = new HDPublicKey(this); + } + }; + + /** + * Receives a object with buffers in all the properties and populates the + * internal structure + * + * @param {Object} arg + * @param {buffer.Buffer} arg.version + * @param {buffer.Buffer} arg.depth + * @param {buffer.Buffer} arg.parentFingerPrint + * @param {buffer.Buffer} arg.childIndex + * @param {buffer.Buffer} arg.chainCode + * @param {buffer.Buffer} arg.privateKey + * @param {buffer.Buffer} arg.checksum + * @param {string=} arg.xprivkey - if set, don't recalculate the base58 + * representation + * @return {HDPrivateKey} this + */ + HDPrivateKey.prototype._buildFromBuffers = function(arg) { + /* jshint maxcomplexity: 8 */ + /* jshint maxstatements: 20 */ + + HDPrivateKey._validateBufferArguments(arg); + + JSUtil.defineImmutable(this, { + _buffers: arg, + }); + + var sequence = [ + arg.version, + arg.depth, + arg.parentFingerPrint, + arg.childIndex, + arg.chainCode, + BufferUtil.emptyBuffer(1), + arg.privateKey, + ]; + var concat = buffer.Buffer.concat(sequence); + if (!arg.checksum || !arg.checksum.length) { + arg.checksum = Base58Check.checksum(concat); + } else { + if (arg.checksum.toString() !== Base58Check.checksum(concat).toString()) { + throw new errors.InvalidB58Checksum(concat); + } + } -/** - * - * Will determine if the point is valid - * - * @link https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf - * @param {Point} An instance of Point - * @throws {Error} A validation error if exists - * @returns {Point} An instance of the same Point - */ -Point.prototype.validate = function validate() { + var network = Network.get(BufferUtil.integerFromBuffer(arg.version)); + var xprivkey; + xprivkey = Base58Check.encode(buffer.Buffer.concat(sequence)); + arg.xprivkey = new Buffer(xprivkey); + + var privateKey = new PrivateKey(BN.fromBuffer(arg.privateKey), network); + var publicKey = privateKey.toPublicKey(); + var size = HDPrivateKey.ParentFingerPrintSize; + var fingerPrint = Hash.sha256ripemd160(publicKey.toBuffer()).slice(0, size); + + JSUtil.defineImmutable(this, { + xprivkey: xprivkey, + network: network, + depth: BufferUtil.integerFromSingleByteBuffer(arg.depth), + privateKey: privateKey, + publicKey: publicKey, + fingerPrint: fingerPrint, + }); + + this._hdPublicKey = null; + + Object.defineProperty(this, 'hdPublicKey', { + configurable: false, + enumerable: true, + get: function() { + this._calcHDPublicKey(); + return this._hdPublicKey; + }, + }); + Object.defineProperty(this, 'xpubkey', { + configurable: false, + enumerable: true, + get: function() { + this._calcHDPublicKey(); + return this._hdPublicKey.xpubkey; + }, + }); + return this; + }; + + HDPrivateKey._validateBufferArguments = function(arg) { + var checkBuffer = function(name, size) { + var buff = arg[name]; + assert(BufferUtil.isBuffer(buff), name + ' argument is not a buffer'); + assert( + buff.length === size, + name + ' has not the expected size: found ' + buff.length + ', expected ' + size, + ); + }; + checkBuffer('version', HDPrivateKey.VersionSize); + checkBuffer('depth', HDPrivateKey.DepthSize); + checkBuffer('parentFingerPrint', HDPrivateKey.ParentFingerPrintSize); + checkBuffer('childIndex', HDPrivateKey.ChildIndexSize); + checkBuffer('chainCode', HDPrivateKey.ChainCodeSize); + checkBuffer('privateKey', HDPrivateKey.PrivateKeySize); + if (arg.checksum && arg.checksum.length) { + checkBuffer('checksum', HDPrivateKey.CheckSumSize); + } + }; + + /** + * Returns the string representation of this private key (a string starting + * with "xprv..." + * + * @return string + */ + HDPrivateKey.prototype.toString = function() { + return this.xprivkey; + }; + + /** + * Returns the console representation of this extended private key. + * @return string + */ + HDPrivateKey.prototype.inspect = function() { + return ''; + }; + + /** + * Returns a plain object with a representation of this private key. + * + * Fields include:
    + *
  • network: either 'livenet' or 'testnet' + *
  • depth: a number ranging from 0 to 255 + *
  • fingerPrint: a number ranging from 0 to 2^32-1, taken from the hash of the + *
  • associated public key + *
  • parentFingerPrint: a number ranging from 0 to 2^32-1, taken from the hash + *
  • of this parent's associated public key or zero. + *
  • childIndex: the index from which this child was derived (or zero) + *
  • chainCode: an hexa string representing a number used in the derivation + *
  • privateKey: the private key associated, in hexa representation + *
  • xprivkey: the representation of this extended private key in checksum + *
  • base58 format + *
  • checksum: the base58 checksum of xprivkey + *
+ * @return {Object} + */ + HDPrivateKey.prototype.toObject = HDPrivateKey.prototype.toJSON = function toObject() { + return { + network: Network.get(BufferUtil.integerFromBuffer(this._buffers.version), 'xprivkey').name, + depth: BufferUtil.integerFromSingleByteBuffer(this._buffers.depth), + fingerPrint: BufferUtil.integerFromBuffer(this.fingerPrint), + parentFingerPrint: BufferUtil.integerFromBuffer(this._buffers.parentFingerPrint), + childIndex: BufferUtil.integerFromBuffer(this._buffers.childIndex), + chainCode: BufferUtil.bufferToHex(this._buffers.chainCode), + privateKey: this.privateKey.toBuffer().toString('hex'), + checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), + xprivkey: this.xprivkey, + }; + }; + + /** + * Build a HDPrivateKey from a buffer + * + * @param {Buffer} arg + * @return {HDPrivateKey} + */ + HDPrivateKey.fromBuffer = function(arg) { + return new HDPrivateKey(arg.toString()); + }; + + /** + * Returns a buffer representation of the HDPrivateKey + * + * @return {string} + */ + HDPrivateKey.prototype.toBuffer = function() { + return BufferUtil.copy(this._buffers.xprivkey); + }; + + HDPrivateKey.DefaultDepth = 0; + HDPrivateKey.DefaultFingerprint = 0; + HDPrivateKey.DefaultChildIndex = 0; + HDPrivateKey.Hardened = 0x80000000; + HDPrivateKey.MaxIndex = 2 * HDPrivateKey.Hardened; + + HDPrivateKey.RootElementAlias = ['m', 'M', "m'", "M'"]; + + HDPrivateKey.VersionSize = 4; + HDPrivateKey.DepthSize = 1; + HDPrivateKey.ParentFingerPrintSize = 4; + HDPrivateKey.ChildIndexSize = 4; + HDPrivateKey.ChainCodeSize = 32; + HDPrivateKey.PrivateKeySize = 32; + HDPrivateKey.CheckSumSize = 4; + + HDPrivateKey.DataLength = 78; + HDPrivateKey.SerializedByteSize = 82; + + HDPrivateKey.VersionStart = 0; + HDPrivateKey.VersionEnd = HDPrivateKey.VersionStart + HDPrivateKey.VersionSize; + HDPrivateKey.DepthStart = HDPrivateKey.VersionEnd; + HDPrivateKey.DepthEnd = HDPrivateKey.DepthStart + HDPrivateKey.DepthSize; + HDPrivateKey.ParentFingerPrintStart = HDPrivateKey.DepthEnd; + HDPrivateKey.ParentFingerPrintEnd = HDPrivateKey.ParentFingerPrintStart + HDPrivateKey.ParentFingerPrintSize; + HDPrivateKey.ChildIndexStart = HDPrivateKey.ParentFingerPrintEnd; + HDPrivateKey.ChildIndexEnd = HDPrivateKey.ChildIndexStart + HDPrivateKey.ChildIndexSize; + HDPrivateKey.ChainCodeStart = HDPrivateKey.ChildIndexEnd; + HDPrivateKey.ChainCodeEnd = HDPrivateKey.ChainCodeStart + HDPrivateKey.ChainCodeSize; + HDPrivateKey.PrivateKeyStart = HDPrivateKey.ChainCodeEnd + 1; + HDPrivateKey.PrivateKeyEnd = HDPrivateKey.PrivateKeyStart + HDPrivateKey.PrivateKeySize; + HDPrivateKey.ChecksumStart = HDPrivateKey.PrivateKeyEnd; + HDPrivateKey.ChecksumEnd = HDPrivateKey.ChecksumStart + HDPrivateKey.CheckSumSize; + + assert(HDPrivateKey.ChecksumEnd === HDPrivateKey.SerializedByteSize); + + module.exports = HDPrivateKey; + }.call(this, require('buffer').Buffer)); + }, + { + './crypto/bn': 6, + './crypto/hash': 8, + './crypto/point': 9, + './crypto/random': 10, + './encoding/base58': 12, + './encoding/base58check': 13, + './errors': 17, + './hdpublickey': 20, + './networks': 21, + './privatekey': 23, + './util/buffer': 42, + './util/js': 43, + './util/preconditions': 44, + assert: 60, + buffer: 113, + lodash: 187, + }, + ], + 20: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var _ = require('lodash'); + var $ = require('./util/preconditions'); + + var BN = require('./crypto/bn'); + var Base58 = require('./encoding/base58'); + var Base58Check = require('./encoding/base58check'); + var Hash = require('./crypto/hash'); + var HDPrivateKey = require('./hdprivatekey'); + var Network = require('./networks'); + var Point = require('./crypto/point'); + var PublicKey = require('./publickey'); + + var bitcoreErrors = require('./errors'); + var errors = bitcoreErrors; + var hdErrors = bitcoreErrors.HDPublicKey; + var assert = require('assert'); + + var JSUtil = require('./util/js'); + var BufferUtil = require('./util/buffer'); + + /** + * The representation of an hierarchically derived public key. + * + * See https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki + * + * @constructor + * @param {Object|string|Buffer} arg + */ + function HDPublicKey(arg) { + /* jshint maxcomplexity: 12 */ + /* jshint maxstatements: 20 */ + if (arg instanceof HDPublicKey) { + return arg; + } + if (!(this instanceof HDPublicKey)) { + return new HDPublicKey(arg); + } + if (arg) { + if (_.isString(arg) || BufferUtil.isBuffer(arg)) { + var error = HDPublicKey.getSerializedError(arg); + if (!error) { + return this._buildFromSerialized(arg); + } else if (BufferUtil.isBuffer(arg) && !HDPublicKey.getSerializedError(arg.toString())) { + return this._buildFromSerialized(arg.toString()); + } else { + if (error instanceof hdErrors.ArgumentIsPrivateExtended) { + return new HDPrivateKey(arg).hdPublicKey; + } + throw error; + } + } else { + if (_.isObject(arg)) { + if (arg instanceof HDPrivateKey) { + return this._buildFromPrivate(arg); + } else { + return this._buildFromObject(arg); + } + } else { + throw new hdErrors.UnrecognizedArgument(arg); + } + } + } else { + throw new hdErrors.MustSupplyArgument(); + } + } - if (this.isInfinity()){ - throw new Error('Point cannot be equal to Infinity'); - } + /** + * Verifies that a given path is valid. + * + * @param {string|number} arg + * @return {boolean} + */ + HDPublicKey.isValidPath = function(arg) { + if (_.isString(arg)) { + var indexes = HDPrivateKey._getDerivationIndexes(arg); + return indexes !== null && _.every(indexes, HDPublicKey.isValidPath); + } - if (this.getX().cmp(BN.Zero) === 0 || this.getY().cmp(BN.Zero) === 0){ - throw new Error('Invalid x,y value for curve, cannot equal 0.'); - } + if (_.isNumber(arg)) { + return arg >= 0 && arg < HDPublicKey.Hardened; + } - var p2 = ecPointFromX(this.getY().isOdd(), this.getX()); + return false; + }; + + /** + * WARNING: This method is deprecated. Use deriveChild instead. + * + * + * Get a derivated child based on a string or number. + * + * If the first argument is a string, it's parsed as the full path of + * derivation. Valid values for this argument include "m" (which returns the + * same public key), "m/0/1/40/2/1000". + * + * Note that hardened keys can't be derived from a public extended key. + * + * If the first argument is a number, the child with that index will be + * derived. See the example usage for clarification. + * + * @example + * ```javascript + * var parent = new HDPublicKey('xpub...'); + * var child_0_1_2 = parent.derive(0).derive(1).derive(2); + * var copy_of_child_0_1_2 = parent.derive("m/0/1/2"); + * assert(child_0_1_2.xprivkey === copy_of_child_0_1_2); + * ``` + * + * @param {string|number} arg + */ + HDPublicKey.prototype.derive = function(arg, hardened) { + return this.deriveChild(arg, hardened); + }; + + /** + * WARNING: This method will not be officially supported until v1.0.0. + * + * + * Get a derivated child based on a string or number. + * + * If the first argument is a string, it's parsed as the full path of + * derivation. Valid values for this argument include "m" (which returns the + * same public key), "m/0/1/40/2/1000". + * + * Note that hardened keys can't be derived from a public extended key. + * + * If the first argument is a number, the child with that index will be + * derived. See the example usage for clarification. + * + * @example + * ```javascript + * var parent = new HDPublicKey('xpub...'); + * var child_0_1_2 = parent.deriveChild(0).deriveChild(1).deriveChild(2); + * var copy_of_child_0_1_2 = parent.deriveChild("m/0/1/2"); + * assert(child_0_1_2.xprivkey === copy_of_child_0_1_2); + * ``` + * + * @param {string|number} arg + */ + HDPublicKey.prototype.deriveChild = function(arg, hardened) { + if (_.isNumber(arg)) { + return this._deriveWithNumber(arg, hardened); + } else if (_.isString(arg)) { + return this._deriveFromString(arg); + } else { + throw new hdErrors.InvalidDerivationArgument(arg); + } + }; - if (p2.y.cmp(this.y) !== 0) { - throw new Error('Invalid y value for curve.'); - } + HDPublicKey.prototype._deriveWithNumber = function(index, hardened) { + if (index >= HDPublicKey.Hardened || hardened) { + throw new hdErrors.InvalidIndexCantDeriveHardened(); + } + if (index < 0) { + throw new hdErrors.InvalidPath(index); + } - var xValidRange = (this.getX().gt(BN.Minus1) && this.getX().lt(Point.getN())); - var yValidRange = (this.getY().gt(BN.Minus1) && this.getY().lt(Point.getN())); + var indexBuffer = BufferUtil.integerAsBuffer(index); + var data = BufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]); + var hash = Hash.sha512hmac(data, this._buffers.chainCode); + var leftPart = BN.fromBuffer(hash.slice(0, 32), { size: 32 }); + var chainCode = hash.slice(32, 64); - if ( !xValidRange || !yValidRange ) { - throw new Error('Point does not lie on the curve'); - } + var publicKey; + try { + publicKey = PublicKey.fromPoint( + Point.getG() + .mul(leftPart) + .add(this.publicKey.point), + ); + } catch (e) { + return this._deriveWithNumber(index + 1); + } - //todo: needs test case - if (!(this.mul(Point.getN()).isInfinity())) { - throw new Error('Point times N must be infinity'); - } + var derived = new HDPublicKey({ + network: this.network, + depth: this.depth + 1, + parentFingerPrint: this.fingerPrint, + childIndex: index, + chainCode: chainCode, + publicKey: publicKey, + }); + + return derived; + }; + + HDPublicKey.prototype._deriveFromString = function(path) { + /* jshint maxcomplexity: 8 */ + if (_.includes(path, "'")) { + throw new hdErrors.InvalidIndexCantDeriveHardened(); + } else if (!HDPublicKey.isValidPath(path)) { + throw new hdErrors.InvalidPath(path); + } - return this; + var indexes = HDPrivateKey._getDerivationIndexes(path); + var derived = indexes.reduce(function(prev, index) { + return prev._deriveWithNumber(index); + }, this); + + return derived; + }; + + /** + * Verifies that a given serialized public key in base58 with checksum format + * is valid. + * + * @param {string|Buffer} data - the serialized public key + * @param {string|Network=} network - optional, if present, checks that the + * network provided matches the network serialized. + * @return {boolean} + */ + HDPublicKey.isValidSerialized = function(data, network) { + return _.isNull(HDPublicKey.getSerializedError(data, network)); + }; + + /** + * Checks what's the error that causes the validation of a serialized public key + * in base58 with checksum to fail. + * + * @param {string|Buffer} data - the serialized public key + * @param {string|Network=} network - optional, if present, checks that the + * network provided matches the network serialized. + * @return {errors|null} + */ + HDPublicKey.getSerializedError = function(data, network) { + /* jshint maxcomplexity: 10 */ + /* jshint maxstatements: 20 */ + if (!(_.isString(data) || BufferUtil.isBuffer(data))) { + return new hdErrors.UnrecognizedArgument('expected buffer or string'); + } + if (!Base58.validCharacters(data)) { + return new errors.InvalidB58Char('(unknown)', data); + } + try { + data = Base58Check.decode(data); + } catch (e) { + return new errors.InvalidB58Checksum(data); + } + if (data.length !== HDPublicKey.DataSize) { + return new hdErrors.InvalidLength(data); + } + if (!_.isUndefined(network)) { + var error = HDPublicKey._validateNetwork(data, network); + if (error) { + return error; + } + } + var version = BufferUtil.integerFromBuffer(data.slice(0, 4)); + if (version === Network.livenet.xprivkey || version === Network.testnet.xprivkey) { + return new hdErrors.ArgumentIsPrivateExtended(); + } + return null; + }; -}; + HDPublicKey._validateNetwork = function(data, networkArg) { + var network = Network.get(networkArg); + if (!network) { + return new errors.InvalidNetworkArgument(networkArg); + } + var version = data.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd); + if (BufferUtil.integerFromBuffer(version) !== network.xpubkey) { + return new errors.InvalidNetwork(version); + } + return null; + }; + + HDPublicKey.prototype._buildFromPrivate = function(arg) { + var args = _.clone(arg._buffers); + var point = Point.getG().mul(BN.fromBuffer(args.privateKey)); + args.publicKey = Point.pointToCompressed(point); + args.version = BufferUtil.integerAsBuffer(Network.get(BufferUtil.integerFromBuffer(args.version)).xpubkey); + args.privateKey = undefined; + args.checksum = undefined; + args.xprivkey = undefined; + return this._buildFromBuffers(args); + }; + + HDPublicKey.prototype._buildFromObject = function(arg) { + /* jshint maxcomplexity: 10 */ + // TODO: Type validation + var buffers = { + version: arg.network ? BufferUtil.integerAsBuffer(Network.get(arg.network).xpubkey) : arg.version, + depth: _.isNumber(arg.depth) ? BufferUtil.integerAsSingleByteBuffer(arg.depth) : arg.depth, + parentFingerPrint: _.isNumber(arg.parentFingerPrint) + ? BufferUtil.integerAsBuffer(arg.parentFingerPrint) + : arg.parentFingerPrint, + childIndex: _.isNumber(arg.childIndex) ? BufferUtil.integerAsBuffer(arg.childIndex) : arg.childIndex, + chainCode: _.isString(arg.chainCode) ? BufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode, + publicKey: _.isString(arg.publicKey) + ? BufferUtil.hexToBuffer(arg.publicKey) + : BufferUtil.isBuffer(arg.publicKey) + ? arg.publicKey + : arg.publicKey.toBuffer(), + checksum: _.isNumber(arg.checksum) ? BufferUtil.integerAsBuffer(arg.checksum) : arg.checksum, + }; + return this._buildFromBuffers(buffers); + }; + + HDPublicKey.prototype._buildFromSerialized = function(arg) { + var decoded = Base58Check.decode(arg); + var buffers = { + version: decoded.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd), + depth: decoded.slice(HDPublicKey.DepthStart, HDPublicKey.DepthEnd), + parentFingerPrint: decoded.slice(HDPublicKey.ParentFingerPrintStart, HDPublicKey.ParentFingerPrintEnd), + childIndex: decoded.slice(HDPublicKey.ChildIndexStart, HDPublicKey.ChildIndexEnd), + chainCode: decoded.slice(HDPublicKey.ChainCodeStart, HDPublicKey.ChainCodeEnd), + publicKey: decoded.slice(HDPublicKey.PublicKeyStart, HDPublicKey.PublicKeyEnd), + checksum: decoded.slice(HDPublicKey.ChecksumStart, HDPublicKey.ChecksumEnd), + xpubkey: arg, + }; + return this._buildFromBuffers(buffers); + }; + + /** + * Receives a object with buffers in all the properties and populates the + * internal structure + * + * @param {Object} arg + * @param {buffer.Buffer} arg.version + * @param {buffer.Buffer} arg.depth + * @param {buffer.Buffer} arg.parentFingerPrint + * @param {buffer.Buffer} arg.childIndex + * @param {buffer.Buffer} arg.chainCode + * @param {buffer.Buffer} arg.publicKey + * @param {buffer.Buffer} arg.checksum + * @param {string=} arg.xpubkey - if set, don't recalculate the base58 + * representation + * @return {HDPublicKey} this + */ + HDPublicKey.prototype._buildFromBuffers = function(arg) { + /* jshint maxcomplexity: 8 */ + /* jshint maxstatements: 20 */ + + HDPublicKey._validateBufferArguments(arg); + + JSUtil.defineImmutable(this, { + _buffers: arg, + }); + + var sequence = [ + arg.version, + arg.depth, + arg.parentFingerPrint, + arg.childIndex, + arg.chainCode, + arg.publicKey, + ]; + var concat = BufferUtil.concat(sequence); + var checksum = Base58Check.checksum(concat); + if (!arg.checksum || !arg.checksum.length) { + arg.checksum = checksum; + } else { + if (arg.checksum.toString('hex') !== checksum.toString('hex')) { + throw new errors.InvalidB58Checksum(concat, checksum); + } + } + var network = Network.get(BufferUtil.integerFromBuffer(arg.version)); + + var xpubkey; + xpubkey = Base58Check.encode(BufferUtil.concat(sequence)); + arg.xpubkey = new Buffer(xpubkey); + + var publicKey = new PublicKey(arg.publicKey, { network: network }); + var size = HDPublicKey.ParentFingerPrintSize; + var fingerPrint = Hash.sha256ripemd160(publicKey.toBuffer()).slice(0, size); + + JSUtil.defineImmutable(this, { + xpubkey: xpubkey, + network: network, + depth: BufferUtil.integerFromSingleByteBuffer(arg.depth), + publicKey: publicKey, + fingerPrint: fingerPrint, + }); + + return this; + }; + + HDPublicKey._validateBufferArguments = function(arg) { + var checkBuffer = function(name, size) { + var buff = arg[name]; + assert(BufferUtil.isBuffer(buff), name + " argument is not a buffer, it's " + typeof buff); + assert( + buff.length === size, + name + ' has not the expected size: found ' + buff.length + ', expected ' + size, + ); + }; + checkBuffer('version', HDPublicKey.VersionSize); + checkBuffer('depth', HDPublicKey.DepthSize); + checkBuffer('parentFingerPrint', HDPublicKey.ParentFingerPrintSize); + checkBuffer('childIndex', HDPublicKey.ChildIndexSize); + checkBuffer('chainCode', HDPublicKey.ChainCodeSize); + checkBuffer('publicKey', HDPublicKey.PublicKeySize); + if (arg.checksum && arg.checksum.length) { + checkBuffer('checksum', HDPublicKey.CheckSumSize); + } + }; + + HDPublicKey.fromString = function(arg) { + $.checkArgument(_.isString(arg), 'No valid string was provided'); + return new HDPublicKey(arg); + }; + + HDPublicKey.fromObject = function(arg) { + $.checkArgument(_.isObject(arg), 'No valid argument was provided'); + return new HDPublicKey(arg); + }; + + /** + * Returns the base58 checked representation of the public key + * @return {string} a string starting with "xpub..." in livenet + */ + HDPublicKey.prototype.toString = function() { + return this.xpubkey; + }; + + /** + * Returns the console representation of this extended public key. + * @return string + */ + HDPublicKey.prototype.inspect = function() { + return ''; + }; + + /** + * Returns a plain JavaScript object with information to reconstruct a key. + * + * Fields are:
    + *
  • network: 'livenet' or 'testnet' + *
  • depth: a number from 0 to 255, the depth to the master extended key + *
  • fingerPrint: a number of 32 bits taken from the hash of the public key + *
  • fingerPrint: a number of 32 bits taken from the hash of this key's + *
  • parent's public key + *
  • childIndex: index with which this key was derived + *
  • chainCode: string in hexa encoding used for derivation + *
  • publicKey: string, hexa encoded, in compressed key format + *
  • checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), + *
  • xpubkey: the string with the base58 representation of this extended key + *
  • checksum: the base58 checksum of xpubkey + *
+ */ + HDPublicKey.prototype.toObject = HDPublicKey.prototype.toJSON = function toObject() { + return { + network: Network.get(BufferUtil.integerFromBuffer(this._buffers.version)).name, + depth: BufferUtil.integerFromSingleByteBuffer(this._buffers.depth), + fingerPrint: BufferUtil.integerFromBuffer(this.fingerPrint), + parentFingerPrint: BufferUtil.integerFromBuffer(this._buffers.parentFingerPrint), + childIndex: BufferUtil.integerFromBuffer(this._buffers.childIndex), + chainCode: BufferUtil.bufferToHex(this._buffers.chainCode), + publicKey: this.publicKey.toString(), + checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), + xpubkey: this.xpubkey, + }; + }; + + /** + * Create a HDPublicKey from a buffer argument + * + * @param {Buffer} arg + * @return {HDPublicKey} + */ + HDPublicKey.fromBuffer = function(arg) { + return new HDPublicKey(arg); + }; + + /** + * Return a buffer representation of the xpubkey + * + * @return {Buffer} + */ + HDPublicKey.prototype.toBuffer = function() { + return BufferUtil.copy(this._buffers.xpubkey); + }; + + HDPublicKey.Hardened = 0x80000000; + HDPublicKey.RootElementAlias = ['m', 'M']; + + HDPublicKey.VersionSize = 4; + HDPublicKey.DepthSize = 1; + HDPublicKey.ParentFingerPrintSize = 4; + HDPublicKey.ChildIndexSize = 4; + HDPublicKey.ChainCodeSize = 32; + HDPublicKey.PublicKeySize = 33; + HDPublicKey.CheckSumSize = 4; + + HDPublicKey.DataSize = 78; + HDPublicKey.SerializedByteSize = 82; + + HDPublicKey.VersionStart = 0; + HDPublicKey.VersionEnd = HDPublicKey.VersionStart + HDPublicKey.VersionSize; + HDPublicKey.DepthStart = HDPublicKey.VersionEnd; + HDPublicKey.DepthEnd = HDPublicKey.DepthStart + HDPublicKey.DepthSize; + HDPublicKey.ParentFingerPrintStart = HDPublicKey.DepthEnd; + HDPublicKey.ParentFingerPrintEnd = HDPublicKey.ParentFingerPrintStart + HDPublicKey.ParentFingerPrintSize; + HDPublicKey.ChildIndexStart = HDPublicKey.ParentFingerPrintEnd; + HDPublicKey.ChildIndexEnd = HDPublicKey.ChildIndexStart + HDPublicKey.ChildIndexSize; + HDPublicKey.ChainCodeStart = HDPublicKey.ChildIndexEnd; + HDPublicKey.ChainCodeEnd = HDPublicKey.ChainCodeStart + HDPublicKey.ChainCodeSize; + HDPublicKey.PublicKeyStart = HDPublicKey.ChainCodeEnd; + HDPublicKey.PublicKeyEnd = HDPublicKey.PublicKeyStart + HDPublicKey.PublicKeySize; + HDPublicKey.ChecksumStart = HDPublicKey.PublicKeyEnd; + HDPublicKey.ChecksumEnd = HDPublicKey.ChecksumStart + HDPublicKey.CheckSumSize; + + assert(HDPublicKey.PublicKeyEnd === HDPublicKey.DataSize); + assert(HDPublicKey.ChecksumEnd === HDPublicKey.SerializedByteSize); + + module.exports = HDPublicKey; + }.call(this, require('buffer').Buffer)); + }, + { + './crypto/bn': 6, + './crypto/hash': 8, + './crypto/point': 9, + './encoding/base58': 12, + './encoding/base58check': 13, + './errors': 17, + './hdprivatekey': 19, + './networks': 21, + './publickey': 24, + './util/buffer': 42, + './util/js': 43, + './util/preconditions': 44, + assert: 60, + buffer: 113, + lodash: 187, + }, + ], + 21: [ + function(require, module, exports) { + 'use strict'; + var _ = require('lodash'); -Point.pointToCompressed = function pointToCompressed(point) { - var xbuf = point.getX().toBuffer({size: 32}); - var ybuf = point.getY().toBuffer({size: 32}); + var BufferUtil = require('./util/buffer'); + var JSUtil = require('./util/js'); + var networks = []; + var networkMaps = {}; - var prefix; - var odd = ybuf[ybuf.length - 1] % 2; - if (odd) { - prefix = new Buffer([0x03]); - } else { - prefix = new Buffer([0x02]); - } - return BufferUtil.concat([prefix, xbuf]); -}; + /** + * A network is merely a map containing values that correspond to version + * numbers for each Merit network. Currently only supporting "livenet" + * (a.k.a. "mainnet") and "testnet". + * @constructor + */ + function Network() {} -module.exports = Point; + Network.prototype.toString = function toString() { + return this.name; + }; -}).call(this,require("buffer").Buffer) -},{"../util/buffer":42,"./bn":6,"buffer":113,"elliptic":151}],10:[function(require,module,exports){ -(function (process,Buffer){ -'use strict'; + /** + * @function + * @member Networks#get + * Retrieves the network associated with a magic number or string. + * @param {string|number|Network} arg + * @param {string|Array} keys - if set, only check if the magic number associated with this name matches + * @return Network + */ + function get(arg, keys) { + if (~networks.indexOf(arg)) { + return arg; + } + if (keys) { + if (!_.isArray(keys)) { + keys = [keys]; + } + var containsArg = function(key) { + return networks[index][key] === arg; + }; + for (var index in networks) { + if (_.some(keys, containsArg)) { + return networks[index]; + } + } + return undefined; + } + return networkMaps[arg]; + } -function Random() { -} + /** + * @function + * @member Networks#add + * Will add a custom Network + * @param {Object} data + * @param {string} data.name - The name of the network + * @param {string} data.alias - The aliased name of the network + * @param {Number} data.pubkeyhash - The publickey hash prefix + * @param {Number} data.privatekey - The privatekey prefix + * @param {Number} data.scripthash - The scripthash prefix + * @param {Number} data.xpubkey - The extended public key magic + * @param {Number} data.xprivkey - The extended private key magic + * @param {Number} data.networkMagic - The network magic number + * @param {Number} data.port - The network port + * @param {Array} data.dnsSeeds - An array of dns seeds + * @return Network + */ + function addNetwork(data) { + var network = new Network(); + + JSUtil.defineImmutable(network, { + name: data.name, + alias: data.alias, + pubkeyhash: data.pubkeyhash, + privatekey: data.privatekey, + scripthash: data.scripthash, + xpubkey: data.xpubkey, + xprivkey: data.xprivkey, + }); -/* secure random bytes that sometimes throws an error due to lack of entropy */ -Random.getRandomBuffer = function(size) { - if (process.browser) - return Random.getRandomBufferBrowser(size); - else - return Random.getRandomBufferNode(size); -}; - -Random.getRandomBufferNode = function(size) { - var crypto = require('crypto'); - return crypto.randomBytes(size); -}; - -Random.getRandomBufferBrowser = function(size) { - if (!window.crypto && !window.msCrypto) - throw new Error('window.crypto not available'); - - if (window.crypto && window.crypto.getRandomValues) - var crypto = window.crypto; - else if (window.msCrypto && window.msCrypto.getRandomValues) //internet explorer - var crypto = window.msCrypto; - else - throw new Error('window.crypto.getRandomValues not available'); - - var bbuf = new Uint8Array(size); - crypto.getRandomValues(bbuf); - var buf = new Buffer(bbuf); - - return buf; -}; - -/* insecure random bytes, but it never fails */ -Random.getPseudoRandomBuffer = function(size) { - var b32 = 0x100000000; - var b = new Buffer(size); - var r; - - for (var i = 0; i <= size; i++) { - var j = Math.floor(i / 4); - var k = i - j * 4; - if (k === 0) { - r = Math.random() * b32; - b[i] = r & 0xff; - } else { - b[i] = (r = r >>> 8) & 0xff; - } - } + if (data.networkMagic) { + JSUtil.defineImmutable(network, { + networkMagic: BufferUtil.integerAsBuffer(data.networkMagic), + }); + } - return b; -}; + if (data.port) { + JSUtil.defineImmutable(network, { + port: data.port, + }); + } -module.exports = Random; + if (data.dnsSeeds) { + JSUtil.defineImmutable(network, { + dnsSeeds: data.dnsSeeds, + }); + } + _.each(network, function(value) { + if (!_.isUndefined(value) && !_.isObject(value)) { + networkMaps[value] = network; + } + }); -}).call(this,require('_process'),require("buffer").Buffer) -},{"_process":205,"buffer":113,"crypto":139}],11:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + networks.push(network); -var BN = require('./bn'); -var _ = require('lodash'); -var $ = require('../util/preconditions'); -var BufferUtil = require('../util/buffer'); -var JSUtil = require('../util/js'); + return network; + } -var Signature = function Signature(r, s) { - if (!(this instanceof Signature)) { - return new Signature(r, s); - } - if (r instanceof BN) { - this.set({ - r: r, - s: s - }); - } else if (r) { - var obj = r; - this.set(obj); - } -}; - -/* jshint maxcomplexity: 7 */ -Signature.prototype.set = function(obj) { - this.r = obj.r || this.r || undefined; - this.s = obj.s || this.s || undefined; - this.i = typeof obj.i !== 'undefined' ? obj.i : this.i; //public key recovery parameter in range [0, 3] - this.compressed = typeof obj.compressed !== 'undefined' ? - obj.compressed : this.compressed; //whether the recovered pubkey is compressed - this.nhashtype = obj.nhashtype || this.nhashtype || undefined; - return this; -}; - -Signature.fromCompact = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf), 'Argument is expected to be a Buffer'); - - var sig = new Signature(); - - var compressed = true; - var i = buf.slice(0, 1)[0] - 27 - 4; - if (i < 0) { - compressed = false; - i = i + 4; - } + /** + * @function + * @member Networks#remove + * Will remove a custom network + * @param {Network} network + */ + function removeNetwork(network) { + for (var i = 0; i < networks.length; i++) { + if (networks[i] === network) { + networks.splice(i, 1); + } + } + for (var key in networkMaps) { + if (networkMaps[key] === network) { + delete networkMaps[key]; + } + } + } - var b2 = buf.slice(1, 33); - var b3 = buf.slice(33, 65); + // ToDo: change seeds to Merit + addNetwork({ + name: 'livenet', + alias: 'mainnet', + pubkeyhash: 0x00, + privatekey: 0x80, + scripthash: 0x05, + xpubkey: 0x0488b21e, + xprivkey: 0x0488ade4, + networkMagic: 0xf9beb4d9, + port: 8333, + dnsSeeds: [], + }); - $.checkArgument(i === 0 || i === 1 || i === 2 || i === 3, new Error('i must be 0, 1, 2, or 3')); - $.checkArgument(b2.length === 32, new Error('r must be 32 bytes')); - $.checkArgument(b3.length === 32, new Error('s must be 32 bytes')); + /** + * @instance + * @member Networks#livenet + */ + var livenet = get('livenet'); + + addNetwork({ + name: 'testnet', + alias: 'regtest', + pubkeyhash: 0x6f, + privatekey: 0xef, + scripthash: 0xc4, + xpubkey: 0x043587cf, + xprivkey: 0x04358394, + }); - sig.compressed = compressed; - sig.i = i; - sig.r = BN.fromBuffer(b2); - sig.s = BN.fromBuffer(b3); + /** + * @instance + * @member Networks#testnet + */ + var testnet = get('testnet'); - return sig; -}; + // Add configurable values for testnet/regtest -Signature.fromDER = Signature.fromBuffer = function(buf, strict) { - var obj = Signature.parseDER(buf, strict); - var sig = new Signature(); + // ToDo: change seeds to Merit + var TESTNET = { + PORT: 18333, + NETWORK_MAGIC: BufferUtil.integerAsBuffer(0x0b110907), + DNS_SEEDS: [], + }; - sig.r = obj.r; - sig.s = obj.s; + for (var key in TESTNET) { + if (!_.isObject(TESTNET[key])) { + networkMaps[TESTNET[key]] = testnet; + } + } - return sig; -}; + var REGTEST = { + PORT: 18444, + NETWORK_MAGIC: BufferUtil.integerAsBuffer(0xfabfb5da), + DNS_SEEDS: [], + }; -// The format used in a tx -Signature.fromTxFormat = function(buf) { - var nhashtype = buf.readUInt8(buf.length - 1); - var derbuf = buf.slice(0, buf.length - 1); - var sig = new Signature.fromDER(derbuf, false); - sig.nhashtype = nhashtype; - return sig; -}; + for (var key in REGTEST) { + if (!_.isObject(REGTEST[key])) { + networkMaps[REGTEST[key]] = testnet; + } + } -Signature.fromString = function(str) { - var buf = new Buffer(str, 'hex'); - return Signature.fromDER(buf); -}; + Object.defineProperty(testnet, 'port', { + enumerable: true, + configurable: false, + get: function() { + if (this.regtestEnabled) { + return REGTEST.PORT; + } else { + return TESTNET.PORT; + } + }, + }); + Object.defineProperty(testnet, 'networkMagic', { + enumerable: true, + configurable: false, + get: function() { + if (this.regtestEnabled) { + return REGTEST.NETWORK_MAGIC; + } else { + return TESTNET.NETWORK_MAGIC; + } + }, + }); -/** - * In order to mimic the non-strict DER encoding of OpenSSL, set strict = false. - */ -Signature.parseDER = function(buf, strict) { - $.checkArgument(BufferUtil.isBuffer(buf), new Error('DER formatted signature should be a buffer')); - if (_.isUndefined(strict)) { - strict = true; - } + Object.defineProperty(testnet, 'dnsSeeds', { + enumerable: true, + configurable: false, + get: function() { + if (this.regtestEnabled) { + return REGTEST.DNS_SEEDS; + } else { + return TESTNET.DNS_SEEDS; + } + }, + }); - var header = buf[0]; - $.checkArgument(header === 0x30, new Error('Header byte should be 0x30')); - - var length = buf[1]; - var buflength = buf.slice(2).length; - $.checkArgument(!strict || length === buflength, new Error('Length byte should length of what follows')); - - length = length < buflength ? length : buflength; - - var rheader = buf[2 + 0]; - $.checkArgument(rheader === 0x02, new Error('Integer byte for r should be 0x02')); - - var rlength = buf[2 + 1]; - var rbuf = buf.slice(2 + 2, 2 + 2 + rlength); - var r = BN.fromBuffer(rbuf); - var rneg = buf[2 + 1 + 1] === 0x00 ? true : false; - $.checkArgument(rlength === rbuf.length, new Error('Length of r incorrect')); - - var sheader = buf[2 + 2 + rlength + 0]; - $.checkArgument(sheader === 0x02, new Error('Integer byte for s should be 0x02')); - - var slength = buf[2 + 2 + rlength + 1]; - var sbuf = buf.slice(2 + 2 + rlength + 2, 2 + 2 + rlength + 2 + slength); - var s = BN.fromBuffer(sbuf); - var sneg = buf[2 + 2 + rlength + 2 + 2] === 0x00 ? true : false; - $.checkArgument(slength === sbuf.length, new Error('Length of s incorrect')); - - var sumlength = 2 + 2 + rlength + 2 + slength; - $.checkArgument(length === sumlength - 2, new Error('Length of signature incorrect')); - - var obj = { - header: header, - length: length, - rheader: rheader, - rlength: rlength, - rneg: rneg, - rbuf: rbuf, - r: r, - sheader: sheader, - slength: slength, - sneg: sneg, - sbuf: sbuf, - s: s - }; - - return obj; -}; - - -Signature.prototype.toCompact = function(i, compressed) { - i = typeof i === 'number' ? i : this.i; - compressed = typeof compressed === 'boolean' ? compressed : this.compressed; - - if (!(i === 0 || i === 1 || i === 2 || i === 3)) { - throw new Error('i must be equal to 0, 1, 2, or 3'); - } + /** + * @function + * @member Networks#enableRegtest + * Will enable regtest features for testnet + */ + function enableRegtest() { + testnet.regtestEnabled = true; + } - var val = i + 27 + 4; - if (compressed === false) { - val = val - 4; - } - var b1 = new Buffer([val]); - var b2 = this.r.toBuffer({ - size: 32 - }); - var b3 = this.s.toBuffer({ - size: 32 - }); - return Buffer.concat([b1, b2, b3]); -}; - -Signature.prototype.toBuffer = Signature.prototype.toDER = function() { - var rnbuf = this.r.toBuffer(); - var snbuf = this.s.toBuffer(); - - var rneg = rnbuf[0] & 0x80 ? true : false; - var sneg = snbuf[0] & 0x80 ? true : false; - - var rbuf = rneg ? Buffer.concat([new Buffer([0x00]), rnbuf]) : rnbuf; - var sbuf = sneg ? Buffer.concat([new Buffer([0x00]), snbuf]) : snbuf; - - var rlength = rbuf.length; - var slength = sbuf.length; - var length = 2 + rlength + 2 + slength; - var rheader = 0x02; - var sheader = 0x02; - var header = 0x30; - - var der = Buffer.concat([new Buffer([header, length, rheader, rlength]), rbuf, new Buffer([sheader, slength]), sbuf]); - return der; -}; - -Signature.prototype.toString = function() { - var buf = this.toDER(); - return buf.toString('hex'); -}; - -/** - * This function is translated from bitcoind's IsDERSignature and is used in - * the script interpreter. This "DER" format actually includes an extra byte, - * the nhashtype, at the end. It is really the tx format, not DER format. - * - * A canonical signature exists of: [30] [total len] [02] [len R] [R] [02] [len S] [S] [hashtype] - * Where R and S are not negative (their first byte has its highest bit not set), and not - * excessively padded (do not start with a 0 byte, unless an otherwise negative number follows, - * in which case a single 0 byte is necessary and even required). - * - * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 - */ -Signature.isTxDER = function(buf) { - if (buf.length < 9) { - // Non-canonical signature: too short - return false; - } - if (buf.length > 73) { - // Non-canonical signature: too long - return false; - } - if (buf[0] !== 0x30) { - // Non-canonical signature: wrong type - return false; - } - if (buf[1] !== buf.length - 3) { - // Non-canonical signature: wrong length marker - return false; - } - var nLenR = buf[3]; - if (5 + nLenR >= buf.length) { - // Non-canonical signature: S length misplaced - return false; - } - var nLenS = buf[5 + nLenR]; - if ((nLenR + nLenS + 7) !== buf.length) { - // Non-canonical signature: R+S length mismatch - return false; - } + /** + * @function + * @member Networks#disableRegtest + * Will disable regtest features for testnet + */ + function disableRegtest() { + testnet.regtestEnabled = false; + } - var R = buf.slice(4); - if (buf[4 - 2] !== 0x02) { - // Non-canonical signature: R value type mismatch - return false; - } - if (nLenR === 0) { - // Non-canonical signature: R length is zero - return false; - } - if (R[0] & 0x80) { - // Non-canonical signature: R value negative - return false; - } - if (nLenR > 1 && (R[0] === 0x00) && !(R[1] & 0x80)) { - // Non-canonical signature: R value excessively padded - return false; - } + /** + * @namespace Networks + */ + module.exports = { + add: addNetwork, + remove: removeNetwork, + defaultNetwork: livenet, + livenet: livenet, + mainnet: livenet, + testnet: testnet, + get: get, + enableRegtest: enableRegtest, + disableRegtest: disableRegtest, + }; + }, + { './util/buffer': 42, './util/js': 43, lodash: 187 }, + ], + 22: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var _ = require('lodash'); + var $ = require('./util/preconditions'); + var BufferUtil = require('./util/buffer'); + var JSUtil = require('./util/js'); + + function Opcode(num) { + if (!(this instanceof Opcode)) { + return new Opcode(num); + } - var S = buf.slice(6 + nLenR); - if (buf[6 + nLenR - 2] !== 0x02) { - // Non-canonical signature: S value type mismatch - return false; - } - if (nLenS === 0) { - // Non-canonical signature: S length is zero - return false; - } - if (S[0] & 0x80) { - // Non-canonical signature: S value negative - return false; - } - if (nLenS > 1 && (S[0] === 0x00) && !(S[1] & 0x80)) { - // Non-canonical signature: S value excessively padded - return false; - } - return true; -}; + var value; -/** - * Compares to bitcoind's IsLowDERSignature - * See also ECDSA signature algorithm which enforces this. - * See also BIP 62, "low S values in signatures" - */ -Signature.prototype.hasLowS = function() { - if (this.s.lt(new BN(1)) || - this.s.gt(new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex'))) { - return false; - } - return true; -}; + if (_.isNumber(num)) { + value = num; + } else if (_.isString(num)) { + value = Opcode.map[num]; + } else { + throw new TypeError('Unrecognized num type: "' + typeof num + '" for Opcode'); + } -/** - * @returns true if the nhashtype is exactly equal to one of the standard options or combinations thereof. - * Translated from bitcoind's IsDefinedHashtypeSignature - */ -Signature.prototype.hasDefinedHashtype = function() { - if (!JSUtil.isNaturalNumber(this.nhashtype)) { - return false; - } - // accept with or without Signature.SIGHASH_ANYONECANPAY by ignoring the bit - var temp = this.nhashtype & ~Signature.SIGHASH_ANYONECANPAY; - if (temp < Signature.SIGHASH_ALL || temp > Signature.SIGHASH_SINGLE) { - return false; - } - return true; -}; - -Signature.prototype.toTxFormat = function() { - var derbuf = this.toDER(); - var buf = new Buffer(1); - buf.writeUInt8(this.nhashtype, 0); - return Buffer.concat([derbuf, buf]); -}; - -Signature.SIGHASH_ALL = 0x01; -Signature.SIGHASH_NONE = 0x02; -Signature.SIGHASH_SINGLE = 0x03; -Signature.SIGHASH_ANYONECANPAY = 0x80; - -module.exports = Signature; - -}).call(this,require("buffer").Buffer) -},{"../util/buffer":42,"../util/js":43,"../util/preconditions":44,"./bn":6,"buffer":113,"lodash":187}],12:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var bs58 = require('bs58'); -var buffer = require('buffer'); - -var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'.split(''); - -var Base58 = function Base58(obj) { - /* jshint maxcomplexity: 8 */ - if (!(this instanceof Base58)) { - return new Base58(obj); - } - if (Buffer.isBuffer(obj)) { - var buf = obj; - this.fromBuffer(buf); - } else if (typeof obj === 'string') { - var str = obj; - this.fromString(str); - } else if (obj) { - this.set(obj); - } -}; + JSUtil.defineImmutable(this, { + num: value, + }); -Base58.validCharacters = function validCharacters(chars) { - if (buffer.Buffer.isBuffer(chars)) { - chars = chars.toString(); - } - return _.every(_.map(chars, function(char) { return _.includes(ALPHABET, char); })); -}; + return this; + } -Base58.prototype.set = function(obj) { - this.buf = obj.buf || this.buf || undefined; - return this; -}; + Opcode.fromBuffer = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + return new Opcode(Number('0x' + buf.toString('hex'))); + }; + + Opcode.fromNumber = function(num) { + $.checkArgument(_.isNumber(num)); + return new Opcode(num); + }; + + Opcode.fromString = function(str) { + $.checkArgument(_.isString(str)); + var value = Opcode.map[str]; + if (typeof value === 'undefined') { + throw new TypeError('Invalid opcodestr'); + } + return new Opcode(value); + }; -Base58.encode = function(buf) { - if (!buffer.Buffer.isBuffer(buf)) { - throw new Error('Input should be a buffer'); - } - return bs58.encode(buf); -}; + Opcode.prototype.toHex = function() { + return this.num.toString(16); + }; -Base58.decode = function(str) { - if (typeof str !== 'string') { - throw new Error('Input should be a string'); - } - return new Buffer(bs58.decode(str)); -}; - -Base58.prototype.fromBuffer = function(buf) { - this.buf = buf; - return this; -}; - -Base58.prototype.fromString = function(str) { - var buf = Base58.decode(str); - this.buf = buf; - return this; -}; - -Base58.prototype.toBuffer = function() { - return this.buf; -}; - -Base58.prototype.toString = function() { - return Base58.encode(this.buf); -}; - -module.exports = Base58; - -}).call(this,require("buffer").Buffer) -},{"bs58":110,"buffer":113,"lodash":187}],13:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var Base58 = require('./base58'); -var buffer = require('buffer'); -var sha256sha256 = require('../crypto/hash').sha256sha256; - -var Base58Check = function Base58Check(obj) { - if (!(this instanceof Base58Check)) - return new Base58Check(obj); - if (Buffer.isBuffer(obj)) { - var buf = obj; - this.fromBuffer(buf); - } else if (typeof obj === 'string') { - var str = obj; - this.fromString(str); - } else if (obj) { - this.set(obj); - } -}; + Opcode.prototype.toBuffer = function() { + return new Buffer(this.toHex(), 'hex'); + }; -Base58Check.prototype.set = function(obj) { - this.buf = obj.buf || this.buf || undefined; - return this; -}; + Opcode.prototype.toNumber = function() { + return this.num; + }; -Base58Check.validChecksum = function validChecksum(data, checksum) { - if (_.isString(data)) { - data = new buffer.Buffer(Base58.decode(data)); - } - if (_.isString(checksum)) { - checksum = new buffer.Buffer(Base58.decode(checksum)); - } - if (!checksum) { - checksum = data.slice(-4); - data = data.slice(0, -4); - } - return Base58Check.checksum(data).toString('hex') === checksum.toString('hex'); -}; - -Base58Check.decode = function(s) { - if (typeof s !== 'string') - throw new Error('Input must be a string'); - - var buf = new Buffer(Base58.decode(s)); - - if (buf.length < 4) - throw new Error("Input string too short"); - - var data = buf.slice(0, -4); - var csum = buf.slice(-4); - - var hash = sha256sha256(data); - var hash4 = hash.slice(0, 4); - - if (csum.toString('hex') !== hash4.toString('hex')) - throw new Error("Checksum mismatch"); - - return data; -}; - -Base58Check.checksum = function(buffer) { - return sha256sha256(buffer).slice(0, 4); -}; - -Base58Check.encode = function(buf) { - if (!Buffer.isBuffer(buf)) - throw new Error('Input must be a buffer'); - var checkedBuf = new Buffer(buf.length + 4); - var hash = Base58Check.checksum(buf); - buf.copy(checkedBuf); - hash.copy(checkedBuf, buf.length); - return Base58.encode(checkedBuf); -}; - -Base58Check.prototype.fromBuffer = function(buf) { - this.buf = buf; - return this; -}; - -Base58Check.prototype.fromString = function(str) { - var buf = Base58Check.decode(str); - this.buf = buf; - return this; -}; - -Base58Check.prototype.toBuffer = function() { - return this.buf; -}; - -Base58Check.prototype.toString = function() { - return Base58Check.encode(this.buf); -}; - -module.exports = Base58Check; - -}).call(this,require("buffer").Buffer) -},{"../crypto/hash":8,"./base58":12,"buffer":113,"lodash":187}],14:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var $ = require('../util/preconditions'); -var BufferUtil = require('../util/buffer'); -var BN = require('../crypto/bn'); - -var BufferReader = function BufferReader(buf) { - if (!(this instanceof BufferReader)) { - return new BufferReader(buf); - } - if (_.isUndefined(buf)) { - return; - } - if (Buffer.isBuffer(buf)) { - this.set({ - buf: buf - }); - } else if (_.isString(buf)) { - this.set({ - buf: new Buffer(buf, 'hex'), - }); - } else if (_.isObject(buf)) { - var obj = buf; - this.set(obj); - } else { - throw new TypeError('Unrecognized argument for BufferReader'); - } -}; - -BufferReader.prototype.set = function(obj) { - this.buf = obj.buf || this.buf || undefined; - this.pos = obj.pos || this.pos || 0; - return this; -}; - -BufferReader.prototype.eof = function() { - return this.pos >= this.buf.length; -}; - -BufferReader.prototype.finished = BufferReader.prototype.eof; - -BufferReader.prototype.read = function(len) { - $.checkArgument(!_.isUndefined(len), 'Must specify a length'); - var buf = this.buf.slice(this.pos, this.pos + len); - this.pos = this.pos + len; - return buf; -}; - -BufferReader.prototype.readAll = function() { - var buf = this.buf.slice(this.pos, this.buf.length); - this.pos = this.buf.length; - return buf; -}; - -BufferReader.prototype.readUInt8 = function() { - var val = this.buf.readUInt8(this.pos); - this.pos = this.pos + 1; - return val; -}; - -BufferReader.prototype.readUInt16BE = function() { - var val = this.buf.readUInt16BE(this.pos); - this.pos = this.pos + 2; - return val; -}; - -BufferReader.prototype.readUInt16LE = function() { - var val = this.buf.readUInt16LE(this.pos); - this.pos = this.pos + 2; - return val; -}; - -BufferReader.prototype.readUInt32BE = function() { - var val = this.buf.readUInt32BE(this.pos); - this.pos = this.pos + 4; - return val; -}; - -BufferReader.prototype.readUInt32LE = function() { - var val = this.buf.readUInt32LE(this.pos); - this.pos = this.pos + 4; - return val; -}; - -BufferReader.prototype.readInt32LE = function() { - var val = this.buf.readInt32LE(this.pos); - this.pos = this.pos + 4; - return val; -}; - -BufferReader.prototype.readUInt64BEBN = function() { - var buf = this.buf.slice(this.pos, this.pos + 8); - var bn = BN.fromBuffer(buf); - this.pos = this.pos + 8; - return bn; -}; - -BufferReader.prototype.readUInt64LEBN = function() { - var second = this.buf.readUInt32LE(this.pos); - var first = this.buf.readUInt32LE(this.pos + 4); - var combined = (first * 0x100000000) + second; - // Instantiating an instance of BN with a number is faster than with an - // array or string. However, the maximum safe number for a double precision - // floating point is 2 ^ 52 - 1 (0x1fffffffffffff), thus we can safely use - // non-floating point numbers less than this amount (52 bits). And in the case - // that the number is larger, we can instatiate an instance of BN by passing - // an array from the buffer (slower) and specifying the endianness. - var bn; - if (combined <= 0x1fffffffffffff) { - bn = new BN(combined); - } else { - var data = Array.prototype.slice.call(this.buf, this.pos, this.pos + 8); - bn = new BN(data, 10, 'le'); - } - this.pos = this.pos + 8; - return bn; -}; - -BufferReader.prototype.readVarintNum = function() { - var first = this.readUInt8(); - switch (first) { - case 0xFD: - return this.readUInt16LE(); - case 0xFE: - return this.readUInt32LE(); - case 0xFF: - var bn = this.readUInt64LEBN(); - var n = bn.toNumber(); - if (n <= Math.pow(2, 53)) { - return n; - } else { - throw new Error('number too large to retain precision - use readVarintBN'); - } - break; - default: - return first; - } -}; + Opcode.prototype.toString = function() { + var str = Opcode.reverseMap[this.num]; + if (typeof str === 'undefined') { + throw new Error('Opcode does not have a string representation'); + } + return str; + }; + + Opcode.smallInt = function(n) { + $.checkArgument(_.isNumber(n), 'Invalid Argument: n should be number'); + $.checkArgument(n >= 0 && n <= 16, 'Invalid Argument: n must be between 0 and 16'); + if (n === 0) { + return Opcode('OP_0'); + } + return new Opcode(Opcode.map.OP_1 + n - 1); + }; + + Opcode.map = { + // push value + OP_FALSE: 0, + OP_0: 0, + OP_PUSHDATA1: 76, + OP_PUSHDATA2: 77, + OP_PUSHDATA4: 78, + OP_1NEGATE: 79, + OP_RESERVED: 80, + OP_TRUE: 81, + OP_1: 81, + OP_2: 82, + OP_3: 83, + OP_4: 84, + OP_5: 85, + OP_6: 86, + OP_7: 87, + OP_8: 88, + OP_9: 89, + OP_10: 90, + OP_11: 91, + OP_12: 92, + OP_13: 93, + OP_14: 94, + OP_15: 95, + OP_16: 96, + + // control + OP_NOP: 97, + OP_VER: 98, + OP_IF: 99, + OP_NOTIF: 100, + OP_VERIF: 101, + OP_VERNOTIF: 102, + OP_ELSE: 103, + OP_ENDIF: 104, + OP_VERIFY: 105, + OP_RETURN: 106, + + // stack ops + OP_TOALTSTACK: 107, + OP_FROMALTSTACK: 108, + OP_2DROP: 109, + OP_2DUP: 110, + OP_3DUP: 111, + OP_2OVER: 112, + OP_2ROT: 113, + OP_2SWAP: 114, + OP_IFDUP: 115, + OP_DEPTH: 116, + OP_DROP: 117, + OP_DUP: 118, + OP_NIP: 119, + OP_OVER: 120, + OP_PICK: 121, + OP_ROLL: 122, + OP_ROT: 123, + OP_SWAP: 124, + OP_TUCK: 125, + + // splice ops + OP_CAT: 126, + OP_SUBSTR: 127, + OP_LEFT: 128, + OP_RIGHT: 129, + OP_SIZE: 130, + + // bit logic + OP_INVERT: 131, + OP_AND: 132, + OP_OR: 133, + OP_XOR: 134, + OP_EQUAL: 135, + OP_EQUALVERIFY: 136, + OP_RESERVED1: 137, + OP_RESERVED2: 138, + + // numeric + OP_1ADD: 139, + OP_1SUB: 140, + OP_2MUL: 141, + OP_2DIV: 142, + OP_NEGATE: 143, + OP_ABS: 144, + OP_NOT: 145, + OP_0NOTEQUAL: 146, + + OP_ADD: 147, + OP_SUB: 148, + OP_MUL: 149, + OP_DIV: 150, + OP_MOD: 151, + OP_LSHIFT: 152, + OP_RSHIFT: 153, + + OP_BOOLAND: 154, + OP_BOOLOR: 155, + OP_NUMEQUAL: 156, + OP_NUMEQUALVERIFY: 157, + OP_NUMNOTEQUAL: 158, + OP_LESSTHAN: 159, + OP_GREATERTHAN: 160, + OP_LESSTHANOREQUAL: 161, + OP_GREATERTHANOREQUAL: 162, + OP_MIN: 163, + OP_MAX: 164, + + OP_WITHIN: 165, + + // crypto + OP_RIPEMD160: 166, + OP_SHA1: 167, + OP_SHA256: 168, + OP_HASH160: 169, + OP_HASH256: 170, + OP_CODESEPARATOR: 171, + OP_CHECKSIG: 172, + OP_CHECKSIGVERIFY: 173, + OP_CHECKMULTISIG: 174, + OP_CHECKMULTISIGVERIFY: 175, + + OP_CHECKLOCKTIMEVERIFY: 177, + OP_EASYSEND: 179, + + // expansion + OP_NOP1: 176, + OP_NOP2: 177, + OP_NOP3: 178, + OP_NOP4: 179, + OP_NOP5: 180, + OP_NOP6: 181, + OP_NOP7: 182, + OP_NOP8: 183, + OP_NOP9: 184, + OP_NOP10: 185, + + // template matching params + OP_PUBKEYHASH: 253, + OP_PUBKEY: 254, + OP_INVALIDOPCODE: 255, + }; + + Opcode.reverseMap = []; + + for (var k in Opcode.map) { + Opcode.reverseMap[Opcode.map[k]] = k; + } -/** - * reads a length prepended buffer - */ -BufferReader.prototype.readVarLengthBuffer = function() { - var len = this.readVarintNum(); - var buf = this.read(len); - $.checkState(buf.length === len, 'Invalid length while reading varlength buffer. ' + - 'Expected to read: ' + len + ' and read ' + buf.length); - return buf; -}; - -BufferReader.prototype.readVarintBuf = function() { - var first = this.buf.readUInt8(this.pos); - switch (first) { - case 0xFD: - return this.read(1 + 2); - case 0xFE: - return this.read(1 + 4); - case 0xFF: - return this.read(1 + 8); - default: - return this.read(1); - } -}; - -BufferReader.prototype.readVarintBN = function() { - var first = this.readUInt8(); - switch (first) { - case 0xFD: - return new BN(this.readUInt16LE()); - case 0xFE: - return new BN(this.readUInt32LE()); - case 0xFF: - return this.readUInt64LEBN(); - default: - return new BN(first); - } -}; + // Easier access to opcodes + _.extend(Opcode, Opcode.map); -BufferReader.prototype.reverse = function() { - var buf = new Buffer(this.buf.length); - for (var i = 0; i < buf.length; i++) { - buf[i] = this.buf[this.buf.length - 1 - i]; - } - this.buf = buf; - return this; -}; + /** + * @returns true if opcode is one of OP_0, OP_1, ..., OP_16 + */ + Opcode.isSmallIntOp = function(opcode) { + if (opcode instanceof Opcode) { + opcode = opcode.toNumber(); + } + return opcode === Opcode.map.OP_0 || (opcode >= Opcode.map.OP_1 && opcode <= Opcode.map.OP_16); + }; + + /** + * Will return a string formatted for the console + * + * @returns {string} Script opcode + */ + Opcode.prototype.inspect = function() { + return ''; + }; + + module.exports = Opcode; + }.call(this, require('buffer').Buffer)); + }, + { './util/buffer': 42, './util/js': 43, './util/preconditions': 44, buffer: 113, lodash: 187 }, + ], + 23: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var _ = require('lodash'); + var Address = require('./address'); + var Base58Check = require('./encoding/base58check'); + var BN = require('./crypto/bn'); + var JSUtil = require('./util/js'); + var Networks = require('./networks'); + var Point = require('./crypto/point'); + var PublicKey = require('./publickey'); + var Random = require('./crypto/random'); + var $ = require('./util/preconditions'); + + /** + * Instantiate a PrivateKey from a BN, Buffer and WIF. + * + * @example + * ```javascript + * // generate a new random key + * var key = PrivateKey(); + * + * // get the associated address + * var address = key.toAddress(); + * + * // encode into wallet export format + * var exported = key.toWIF(); + * + * // instantiate from the exported (and saved) private key + * var imported = PrivateKey.fromWIF(exported); + * ``` + * + * @param {string} data - The encoded data in various formats + * @param {Network|string=} network - a {@link Network} object, or a string with the network name + * @returns {PrivateKey} A new valid instance of an PrivateKey + * @constructor + */ + function PrivateKey(data, network) { + /* jshint maxstatements: 20 */ + /* jshint maxcomplexity: 8 */ + + if (!(this instanceof PrivateKey)) { + return new PrivateKey(data, network); + } + if (data instanceof PrivateKey) { + return data; + } -BufferReader.prototype.readReverse = function(len) { - if (_.isUndefined(len)) { - len = this.buf.length; - } - var buf = this.buf.slice(this.pos, this.pos + len); - this.pos = this.pos + len; - return BufferUtil.reverse(buf); -}; - -module.exports = BufferReader; - -}).call(this,require("buffer").Buffer) -},{"../crypto/bn":6,"../util/buffer":42,"../util/preconditions":44,"buffer":113,"lodash":187}],15:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var bufferUtil = require('../util/buffer'); -var assert = require('assert'); - -var BufferWriter = function BufferWriter(obj) { - if (!(this instanceof BufferWriter)) - return new BufferWriter(obj); - if (obj) - this.set(obj); - else - this.bufs = []; -}; - -BufferWriter.prototype.set = function(obj) { - this.bufs = obj.bufs || this.bufs || []; - return this; -}; - -BufferWriter.prototype.toBuffer = function() { - return this.concat(); -}; - -BufferWriter.prototype.concat = function() { - return Buffer.concat(this.bufs); -}; - -BufferWriter.prototype.write = function(buf) { - assert(bufferUtil.isBuffer(buf)); - this.bufs.push(buf); - return this; -}; - -BufferWriter.prototype.writeReverse = function(buf) { - assert(bufferUtil.isBuffer(buf)); - this.bufs.push(bufferUtil.reverse(buf)); - return this; -}; - -BufferWriter.prototype.writeUInt8 = function(n) { - var buf = new Buffer(1); - buf.writeUInt8(n, 0); - this.write(buf); - return this; -}; - -BufferWriter.prototype.writeUInt16BE = function(n) { - var buf = new Buffer(2); - buf.writeUInt16BE(n, 0); - this.write(buf); - return this; -}; - -BufferWriter.prototype.writeUInt16LE = function(n) { - var buf = new Buffer(2); - buf.writeUInt16LE(n, 0); - this.write(buf); - return this; -}; - -BufferWriter.prototype.writeUInt32BE = function(n) { - var buf = new Buffer(4); - buf.writeUInt32BE(n, 0); - this.write(buf); - return this; -}; - -BufferWriter.prototype.writeInt32LE = function(n) { - var buf = new Buffer(4); - buf.writeInt32LE(n, 0); - this.write(buf); - return this; -}; - -BufferWriter.prototype.writeUInt32LE = function(n) { - var buf = new Buffer(4); - buf.writeUInt32LE(n, 0); - this.write(buf); - return this; -}; - -BufferWriter.prototype.writeUInt64BEBN = function(bn) { - var buf = bn.toBuffer({size: 8}); - this.write(buf); - return this; -}; - -BufferWriter.prototype.writeUInt64LEBN = function(bn) { - var buf = bn.toBuffer({size: 8}); - this.writeReverse(buf); - return this; -}; - -BufferWriter.prototype.writeVarintNum = function(n) { - var buf = BufferWriter.varintBufNum(n); - this.write(buf); - return this; -}; - -BufferWriter.prototype.writeVarintBN = function(bn) { - var buf = BufferWriter.varintBufBN(bn); - this.write(buf); - return this; -}; - -BufferWriter.varintBufNum = function(n) { - var buf = undefined; - if (n < 253) { - buf = new Buffer(1); - buf.writeUInt8(n, 0); - } else if (n < 0x10000) { - buf = new Buffer(1 + 2); - buf.writeUInt8(253, 0); - buf.writeUInt16LE(n, 1); - } else if (n < 0x100000000) { - buf = new Buffer(1 + 4); - buf.writeUInt8(254, 0); - buf.writeUInt32LE(n, 1); - } else { - buf = new Buffer(1 + 8); - buf.writeUInt8(255, 0); - buf.writeInt32LE(n & -1, 1); - buf.writeUInt32LE(Math.floor(n / 0x100000000), 5); - } - return buf; -}; - -BufferWriter.varintBufBN = function(bn) { - var buf = undefined; - var n = bn.toNumber(); - if (n < 253) { - buf = new Buffer(1); - buf.writeUInt8(n, 0); - } else if (n < 0x10000) { - buf = new Buffer(1 + 2); - buf.writeUInt8(253, 0); - buf.writeUInt16LE(n, 1); - } else if (n < 0x100000000) { - buf = new Buffer(1 + 4); - buf.writeUInt8(254, 0); - buf.writeUInt32LE(n, 1); - } else { - var bw = new BufferWriter(); - bw.writeUInt8(255); - bw.writeUInt64LEBN(bn); - var buf = bw.concat(); - } - return buf; -}; - -module.exports = BufferWriter; - -}).call(this,require("buffer").Buffer) -},{"../util/buffer":42,"assert":60,"buffer":113}],16:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var BufferWriter = require('./bufferwriter'); -var BufferReader = require('./bufferreader'); -var BN = require('../crypto/bn'); - -var Varint = function Varint(buf) { - if (!(this instanceof Varint)) - return new Varint(buf); - if (Buffer.isBuffer(buf)) { - this.buf = buf; - } else if (typeof buf === 'number') { - var num = buf; - this.fromNumber(num); - } else if (buf instanceof BN) { - var bn = buf; - this.fromBN(bn); - } else if (buf) { - var obj = buf; - this.set(obj); - } -}; - -Varint.prototype.set = function(obj) { - this.buf = obj.buf || this.buf; - return this; -}; - -Varint.prototype.fromString = function(str) { - this.set({ - buf: new Buffer(str, 'hex') - }); - return this; -}; - -Varint.prototype.toString = function() { - return this.buf.toString('hex'); -}; - -Varint.prototype.fromBuffer = function(buf) { - this.buf = buf; - return this; -}; - -Varint.prototype.fromBufferReader = function(br) { - this.buf = br.readVarintBuf(); - return this; -}; - -Varint.prototype.fromBN = function(bn) { - this.buf = BufferWriter().writeVarintBN(bn).concat(); - return this; -}; - -Varint.prototype.fromNumber = function(num) { - this.buf = BufferWriter().writeVarintNum(num).concat(); - return this; -}; - -Varint.prototype.toBuffer = function() { - return this.buf; -}; - -Varint.prototype.toBN = function() { - return BufferReader(this.buf).readVarintBN(); -}; - -Varint.prototype.toNumber = function() { - return BufferReader(this.buf).readVarintNum(); -}; - -module.exports = Varint; - -}).call(this,require("buffer").Buffer) -},{"../crypto/bn":6,"./bufferreader":14,"./bufferwriter":15,"buffer":113}],17:[function(require,module,exports){ -'use strict'; - -var _ = require('lodash'); - -function format(message, args) { - return message - .replace('{0}', args[0]) - .replace('{1}', args[1]) - .replace('{2}', args[2]); -} -var traverseNode = function(parent, errorDefinition) { - var NodeError = function() { - if (_.isString(errorDefinition.message)) { - this.message = format(errorDefinition.message, arguments); - } else if (_.isFunction(errorDefinition.message)) { - this.message = errorDefinition.message.apply(null, arguments); - } else { - throw new Error('Invalid error definition for ' + errorDefinition.name); - } - this.stack = this.message + '\n' + (new Error()).stack; - }; - NodeError.prototype = Object.create(parent.prototype); - NodeError.prototype.name = parent.prototype.name + errorDefinition.name; - parent[errorDefinition.name] = NodeError; - if (errorDefinition.errors) { - childDefinitions(NodeError, errorDefinition.errors); - } - return NodeError; -}; - -/* jshint latedef: false */ -var childDefinitions = function(parent, childDefinitions) { - _.each(childDefinitions, function(childDefinition) { - traverseNode(parent, childDefinition); - }); -}; -/* jshint latedef: true */ - -var traverseRoot = function(parent, errorsDefinition) { - childDefinitions(parent, errorsDefinition); - return parent; -}; - - -var bitcore = {}; -bitcore.Error = function() { - this.message = 'Internal error'; - this.stack = this.message + '\n' + (new Error()).stack; -}; -bitcore.Error.prototype = Object.create(Error.prototype); -bitcore.Error.prototype.name = 'bitcore.Error'; - - -var data = require('./spec'); -traverseRoot(bitcore.Error, data); - -module.exports = bitcore.Error; - -module.exports.extend = function(spec) { - return traverseNode(bitcore.Error, spec); -}; - -},{"./spec":18,"lodash":187}],18:[function(require,module,exports){ -'use strict'; - -var docsURL = 'http://bitcore.io/'; - -module.exports = [{ - name: 'InvalidB58Char', - message: 'Invalid Base58 character: {0} in {1}' -}, { - name: 'InvalidB58Checksum', - message: 'Invalid Base58 checksum for {0}' -}, { - name: 'InvalidNetwork', - message: 'Invalid version for network: got {0}' -}, { - name: 'InvalidState', - message: 'Invalid state: {0}' -}, { - name: 'NotImplemented', - message: 'Function {0} was not implemented yet' -}, { - name: 'InvalidNetworkArgument', - message: 'Invalid network: must be "livenet" or "testnet", got {0}' -}, { - name: 'InvalidArgument', - message: function() { - return 'Invalid Argument' + (arguments[0] ? (': ' + arguments[0]) : '') + - (arguments[1] ? (' Documentation: ' + docsURL + arguments[1]) : ''); - } -}, { - name: 'AbstractMethodInvoked', - message: 'Abstract Method Invocation: {0}' -}, { - name: 'InvalidArgumentType', - message: function() { - return 'Invalid Argument for ' + arguments[2] + ', expected ' + arguments[1] + ' but got ' + typeof arguments[0]; - } -}, { - name: 'Unit', - message: 'Internal Error on Unit {0}', - errors: [{ - 'name': 'UnknownCode', - 'message': 'Unrecognized unit code: {0}' - }, { - 'name': 'InvalidRate', - 'message': 'Invalid exchange rate: {0}' - }] -}, { - name: 'Transaction', - message: 'Internal Error on Transaction {0}', - errors: [{ - name: 'Input', - message: 'Internal Error on Input {0}', - errors: [{ - name: 'MissingScript', - message: 'Need a script to create an input' - }, { - name: 'UnsupportedScript', - message: 'Unsupported input script type: {0}' - }, { - name: 'MissingPreviousOutput', - message: 'No previous output information.' - }] - }, { - name: 'NeedMoreInfo', - message: '{0}' - }, { - name: 'InvalidSorting', - message: 'The sorting function provided did not return the change output as one of the array elements' - }, { - name: 'InvalidOutputAmountSum', - message: '{0}' - }, { - name: 'MissingSignatures', - message: 'Some inputs have not been fully signed' - }, { - name: 'InvalidIndex', - message: 'Invalid index: {0} is not between 0, {1}' - }, { - name: 'UnableToVerifySignature', - message: 'Unable to verify signature: {0}' - }, { - name: 'DustOutputs', - message: 'Dust amount detected in one output' - }, { - name: 'InvalidMicros', - message: 'Output micros are invalid', - }, { - name: 'FeeError', - message: 'Internal Error on Fee {0}', - errors: [{ - name: 'TooSmall', - message: 'Fee is too small: {0}', - }, { - name: 'TooLarge', - message: 'Fee is too large: {0}', - }, { - name: 'Different', - message: 'Unspent value is different from specified fee: {0}', - }] - }, { - name: 'ChangeAddressMissing', - message: 'Change address is missing' - }, { - name: 'BlockHeightTooHigh', - message: 'Block Height can be at most 2^32 -1' - }, { - name: 'NLockTimeOutOfRange', - message: 'Block Height can only be between 0 and 499 999 999' - }, { - name: 'LockTimeTooEarly', - message: 'Lock Time can\'t be earlier than UNIX date 500 000 000' - }] -}, { - name: 'Script', - message: 'Internal Error on Script {0}', - errors: [{ - name: 'UnrecognizedAddress', - message: 'Expected argument {0} to be an address' - }, { - name: 'CantDeriveAddress', - message: 'Can\'t derive address associated with script {0}, needs to be p2pkh in, p2pkh out, p2sh in, or p2sh out.' - }, { - name: 'InvalidBuffer', - message: 'Invalid script buffer: can\'t parse valid script from given buffer {0}' - }] -}, { - name: 'HDPrivateKey', - message: 'Internal Error on HDPrivateKey {0}', - errors: [{ - name: 'InvalidDerivationArgument', - message: 'Invalid derivation argument {0}, expected string, or number and boolean' - }, { - name: 'InvalidEntropyArgument', - message: 'Invalid entropy: must be an hexa string or binary buffer, got {0}', - errors: [{ - name: 'TooMuchEntropy', - message: 'Invalid entropy: more than 512 bits is non standard, got "{0}"' - }, { - name: 'NotEnoughEntropy', - message: 'Invalid entropy: at least 128 bits needed, got "{0}"' - }] - }, { - name: 'InvalidLength', - message: 'Invalid length for xprivkey string in {0}' - }, { - name: 'InvalidPath', - message: 'Invalid derivation path: {0}' - }, { - name: 'UnrecognizedArgument', - message: 'Invalid argument: creating a HDPrivateKey requires a string, buffer, json or object, got "{0}"' - }] -}, { - name: 'HDPublicKey', - message: 'Internal Error on HDPublicKey {0}', - errors: [{ - name: 'ArgumentIsPrivateExtended', - message: 'Argument is an extended private key: {0}' - }, { - name: 'InvalidDerivationArgument', - message: 'Invalid derivation argument: got {0}' - }, { - name: 'InvalidLength', - message: 'Invalid length for xpubkey: got "{0}"' - }, { - name: 'InvalidPath', - message: 'Invalid derivation path, it should look like: "m/1/100", got "{0}"' - }, { - name: 'InvalidIndexCantDeriveHardened', - message: 'Invalid argument: creating a hardened path requires an HDPrivateKey' - }, { - name: 'MustSupplyArgument', - message: 'Must supply an argument to create a HDPublicKey' - }, { - name: 'UnrecognizedArgument', - message: 'Invalid argument for creation, must be string, json, buffer, or object' - }] -}]; - -},{}],19:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - - -var assert = require('assert'); -var buffer = require('buffer'); -var _ = require('lodash'); -var $ = require('./util/preconditions'); - -var BN = require('./crypto/bn'); -var Base58 = require('./encoding/base58'); -var Base58Check = require('./encoding/base58check'); -var Hash = require('./crypto/hash'); -var Network = require('./networks'); -var Point = require('./crypto/point'); -var PrivateKey = require('./privatekey'); -var Random = require('./crypto/random'); - -var errors = require('./errors'); -var hdErrors = errors.HDPrivateKey; -var BufferUtil = require('./util/buffer'); -var JSUtil = require('./util/js'); - -var MINIMUM_ENTROPY_BITS = 128; -var BITS_TO_BYTES = 1 / 8; -var MAXIMUM_ENTROPY_BITS = 512; - - -/** - * Represents an instance of an hierarchically derived private key. - * - * More info on https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki - * - * @constructor - * @param {string|Buffer|Object} arg - */ -function HDPrivateKey(arg) { - /* jshint maxcomplexity: 10 */ - if (arg instanceof HDPrivateKey) { - return arg; - } - if (!(this instanceof HDPrivateKey)) { - return new HDPrivateKey(arg); - } - if (!arg) { - return this._generateRandomly(); - } + var info = this._classifyArguments(data, network); - if (Network.get(arg)) { - return this._generateRandomly(arg); - } else if (_.isString(arg) || BufferUtil.isBuffer(arg)) { - if (HDPrivateKey.isValidSerialized(arg)) { - this._buildFromSerialized(arg); - } else if (JSUtil.isValidJSON(arg)) { - this._buildFromJSON(arg); - } else if (BufferUtil.isBuffer(arg) && HDPrivateKey.isValidSerialized(arg.toString())) { - this._buildFromSerialized(arg.toString()); - } else { - throw HDPrivateKey.getSerializedError(arg); - } - } else if (_.isObject(arg)) { - this._buildFromObject(arg); - } else { - throw new hdErrors.UnrecognizedArgument(arg); - } -} + // validation + if (!info.bn || info.bn.cmp(new BN(0)) === 0) { + throw new TypeError('Number can not be equal to zero, undefined, null or false'); + } + if (!info.bn.lt(Point.getN())) { + throw new TypeError('Number must be less than N'); + } + if (typeof info.network === 'undefined') { + throw new TypeError('Must specify the network ("livenet" or "testnet")'); + } -/** - * Verifies that a given path is valid. - * - * @param {string|number} arg - * @param {boolean?} hardened - * @return {boolean} - */ -HDPrivateKey.isValidPath = function(arg, hardened) { - if (_.isString(arg)) { - var indexes = HDPrivateKey._getDerivationIndexes(arg); - return indexes !== null && _.every(indexes, HDPrivateKey.isValidPath); - } + JSUtil.defineImmutable(this, { + bn: info.bn, + compressed: info.compressed, + network: info.network, + }); - if (_.isNumber(arg)) { - if (arg < HDPrivateKey.Hardened && hardened === true) { - arg += HDPrivateKey.Hardened; - } - return arg >= 0 && arg < HDPrivateKey.MaxIndex; - } + Object.defineProperty(this, 'publicKey', { + configurable: false, + enumerable: true, + get: this.toPublicKey.bind(this), + }); - return false; -}; + return this; + } -/** - * Internal function that splits a string path into a derivation index array. - * It will return null if the string path is malformed. - * It does not validate if indexes are in bounds. - * - * @param {string} path - * @return {Array} - */ -HDPrivateKey._getDerivationIndexes = function(path) { - var steps = path.split('/'); + /** + * Internal helper to instantiate PrivateKey internal `info` object from + * different kinds of arguments passed to the constructor. + * + * @param {*} data + * @param {Network|string=} network - a {@link Network} object, or a string with the network name + * @return {Object} + */ + PrivateKey.prototype._classifyArguments = function(data, network) { + /* jshint maxcomplexity: 10 */ + var info = { + compressed: true, + network: network ? Networks.get(network) : Networks.defaultNetwork, + }; - // Special cases: - if (_.includes(HDPrivateKey.RootElementAlias, path)) { - return []; - } + // detect type of data + if (_.isUndefined(data) || _.isNull(data)) { + info.bn = PrivateKey._getRandomBN(); + } else if (data instanceof BN) { + info.bn = data; + } else if (data instanceof Buffer || data instanceof Uint8Array) { + info = PrivateKey._transformBuffer(data, network); + } else if (data.bn && data.network) { + info = PrivateKey._transformObject(data); + } else if (!network && Networks.get(data)) { + info.bn = PrivateKey._getRandomBN(); + info.network = Networks.get(data); + } else if (typeof data === 'string') { + if (JSUtil.isHexa(data)) { + info.bn = new BN(new Buffer(data, 'hex')); + } else { + info = PrivateKey._transformWIF(data, network); + } + } else { + throw new TypeError('First argument is an unrecognized data type.'); + } + return info; + }; + + /** + * Internal function to get a random Big Number (BN) + * + * @returns {BN} A new randomly generated BN + * @private + */ + PrivateKey._getRandomBN = function() { + var condition; + var bn; + do { + var privbuf = Random.getRandomBuffer(32); + bn = BN.fromBuffer(privbuf); + condition = bn.lt(Point.getN()); + } while (!condition); + return bn; + }; + + /** + * Internal function to transform a WIF Buffer into a private key + * + * @param {Buffer} buf - An WIF string + * @param {Network|string=} network - a {@link Network} object, or a string with the network name + * @returns {Object} An object with keys: bn, network and compressed + * @private + */ + PrivateKey._transformBuffer = function(buf, network) { + var info = {}; + + if (buf.length === 32) { + return PrivateKey._transformBNBuffer(buf, network); + } - if (!_.includes(HDPrivateKey.RootElementAlias, steps[0])) { - return null; - } + info.network = Networks.get(buf[0], 'privatekey'); - var indexes = steps.slice(1).map(function(step) { - var isHardened = step.slice(-1) === '\''; - if (isHardened) { - step = step.slice(0, -1); - } - if (!step || step[0] === '-') { - return NaN; - } - var index = +step; // cast to number - if (isHardened) { - index += HDPrivateKey.Hardened; - } + if (!info.network) { + throw new Error('Invalid network'); + } - return index; - }); + if (network && info.network !== Networks.get(network)) { + throw new TypeError('Private key network mismatch'); + } - return _.some(indexes, isNaN) ? null : indexes; -}; + if (buf.length === 1 + 32 + 1 && buf[1 + 32 + 1 - 1] === 1) { + info.compressed = true; + } else if (buf.length === 1 + 32) { + info.compressed = false; + } else { + throw new Error('Length of buffer must be 33 (uncompressed) or 34 (compressed)'); + } -/** - * WARNING: This method is deprecated. Use deriveChild or deriveNonCompliantChild instead. This is not BIP32 compliant - * - * - * Get a derived child based on a string or number. - * - * If the first argument is a string, it's parsed as the full path of - * derivation. Valid values for this argument include "m" (which returns the - * same private key), "m/0/1/40/2'/1000", where the ' quote means a hardened - * derivation. - * - * If the first argument is a number, the child with that index will be - * derived. If the second argument is truthy, the hardened version will be - * derived. See the example usage for clarification. - * - * @example - * ```javascript - * var parent = new HDPrivateKey('xprv...'); - * var child_0_1_2h = parent.derive(0).derive(1).derive(2, true); - * var copy_of_child_0_1_2h = parent.derive("m/0/1/2'"); - * assert(child_0_1_2h.xprivkey === copy_of_child_0_1_2h); - * ``` - * - * @param {string|number} arg - * @param {boolean?} hardened - */ -HDPrivateKey.prototype.derive = function(arg, hardened) { - return this.deriveNonCompliantChild(arg, hardened); -}; + info.bn = BN.fromBuffer(buf.slice(1, 32 + 1)); + + return info; + }; + + /** + * Internal function to transform a BN buffer into a private key + * + * @param {Buffer} buf + * @param {Network|string=} network - a {@link Network} object, or a string with the network name + * @returns {object} an Object with keys: bn, network, and compressed + * @private + */ + PrivateKey._transformBNBuffer = function(buf, network) { + var info = {}; + info.network = Networks.get(network) || Networks.defaultNetwork; + info.bn = BN.fromBuffer(buf); + info.compressed = false; + return info; + }; + + /** + * Internal function to transform a WIF string into a private key + * + * @param {string} buf - An WIF string + * @returns {Object} An object with keys: bn, network and compressed + * @private + */ + PrivateKey._transformWIF = function(str, network) { + return PrivateKey._transformBuffer(Base58Check.decode(str), network); + }; + + /** + * Instantiate a PrivateKey from a Buffer with the DER or WIF representation + * + * @param {Buffer} arg + * @param {Network} network + * @return {PrivateKey} + */ + PrivateKey.fromBuffer = function(arg, network) { + return new PrivateKey(arg, network); + }; + + /** + * Internal function to transform a JSON string on plain object into a private key + * return this. + * + * @param {string} json - A JSON string or plain object + * @returns {Object} An object with keys: bn, network and compressed + * @private + */ + PrivateKey._transformObject = function(json) { + var bn = new BN(json.bn, 'hex'); + var network = Networks.get(json.network); + return { + bn: bn, + network: network, + compressed: json.compressed, + }; + }; + + /** + * Instantiate a PrivateKey from a WIF string + * + * @param {string} str - The WIF encoded private key string + * @returns {PrivateKey} A new valid instance of PrivateKey + */ + PrivateKey.fromString = PrivateKey.fromWIF = function(str) { + $.checkArgument(_.isString(str), 'First argument is expected to be a string.'); + return new PrivateKey(str); + }; + + /** + * Instantiate a PrivateKey from a plain JavaScript object + * + * @param {Object} obj - The output from privateKey.toObject() + */ + PrivateKey.fromObject = function(obj) { + $.checkArgument(_.isObject(obj), 'First argument is expected to be an object.'); + return new PrivateKey(obj); + }; + + /** + * Instantiate a PrivateKey from random bytes + * + * @param {string=} network - Either "livenet" or "testnet" + * @returns {PrivateKey} A new valid instance of PrivateKey + */ + PrivateKey.fromRandom = function(network) { + var bn = PrivateKey._getRandomBN(); + return new PrivateKey(bn, network); + }; + + /** + * Check if there would be any errors when initializing a PrivateKey + * + * @param {string} data - The encoded data in various formats + * @param {string=} network - Either "livenet" or "testnet" + * @returns {null|Error} An error if exists + */ + + PrivateKey.getValidationError = function(data, network) { + var error; + try { + /* jshint nonew: false */ + new PrivateKey(data, network); + } catch (e) { + error = e; + } + return error; + }; + + /** + * Check if the parameters are valid + * + * @param {string} data - The encoded data in various formats + * @param {string=} network - Either "livenet" or "testnet" + * @returns {Boolean} If the private key is would be valid + */ + PrivateKey.isValid = function(data, network) { + if (!data) { + return false; + } + return !PrivateKey.getValidationError(data, network); + }; + + /** + * Will output the PrivateKey encoded as hex string + * + * @returns {string} + */ + PrivateKey.prototype.toString = function() { + return this.toBuffer().toString('hex'); + }; + + /** + * Will output the PrivateKey to a WIF string + * + * @returns {string} A WIP representation of the private key + */ + PrivateKey.prototype.toWIF = function() { + var network = this.network; + var compressed = this.compressed; + + var buf; + if (compressed) { + buf = Buffer.concat([ + new Buffer([network.privatekey]), + this.bn.toBuffer({ size: 32 }), + new Buffer([0x01]), + ]); + } else { + buf = Buffer.concat([new Buffer([network.privatekey]), this.bn.toBuffer({ size: 32 })]); + } -/** - * WARNING: This method will not be officially supported until v1.0.0. - * - * - * Get a derived child based on a string or number. - * - * If the first argument is a string, it's parsed as the full path of - * derivation. Valid values for this argument include "m" (which returns the - * same private key), "m/0/1/40/2'/1000", where the ' quote means a hardened - * derivation. - * - * If the first argument is a number, the child with that index will be - * derived. If the second argument is truthy, the hardened version will be - * derived. See the example usage for clarification. - * - * WARNING: The `nonCompliant` option should NOT be used, except for older implementation - * that used a derivation strategy that used a non-zero padded private key. - * - * @example - * ```javascript - * var parent = new HDPrivateKey('xprv...'); - * var child_0_1_2h = parent.deriveChild(0).deriveChild(1).deriveChild(2, true); - * var copy_of_child_0_1_2h = parent.deriveChild("m/0/1/2'"); - * assert(child_0_1_2h.xprivkey === copy_of_child_0_1_2h); - * ``` - * - * @param {string|number} arg - * @param {boolean?} hardened - */ -HDPrivateKey.prototype.deriveChild = function(arg, hardened) { - if (_.isNumber(arg)) { - return this._deriveWithNumber(arg, hardened); - } else if (_.isString(arg)) { - return this._deriveFromString(arg); - } else { - throw new hdErrors.InvalidDerivationArgument(arg); - } -}; + return Base58Check.encode(buf); + }; + + /** + * Will return the private key as a BN instance + * + * @returns {BN} A BN instance of the private key + */ + PrivateKey.prototype.toBigNumber = function() { + return this.bn; + }; + + /** + * Will return the private key as a BN buffer + * + * @returns {Buffer} A buffer of the private key + */ + PrivateKey.prototype.toBuffer = function() { + // TODO: use `return this.bn.toBuffer({ size: 32 })` in v1.0.0 + return this.bn.toBuffer(); + }; + + /** + * WARNING: This method will not be officially supported until v1.0.0. + * + * + * Will return the private key as a BN buffer without leading zero padding + * + * @returns {Buffer} A buffer of the private key + */ + PrivateKey.prototype.toBufferNoPadding = function() { + return this.bn.toBuffer(); + }; + + /** + * Will return the corresponding public key + * + * @returns {PublicKey} A public key generated from the private key + */ + PrivateKey.prototype.toPublicKey = function() { + if (!this._pubkey) { + this._pubkey = PublicKey.fromPrivateKey(this); + } + return this._pubkey; + }; + + /** + * Will return an address for the private key + * @param {Network=} network - optional parameter specifying + * the desired network for the address + * + * @returns {Address} An address generated from the private key + */ + PrivateKey.prototype.toAddress = function(network) { + var pubkey = this.toPublicKey(); + return Address.fromPublicKey(pubkey, network || this.network); + }; + + /** + * @returns {Object} A plain object representation + */ + PrivateKey.prototype.toObject = PrivateKey.prototype.toJSON = function toObject() { + return { + bn: this.bn.toString('hex'), + compressed: this.compressed, + network: this.network.toString(), + }; + }; + + /** + * Will return a string formatted for the console + * + * @returns {string} Private key + */ + PrivateKey.prototype.inspect = function() { + var uncompressed = !this.compressed ? ', uncompressed' : ''; + return ''; + }; + + module.exports = PrivateKey; + }.call(this, require('buffer').Buffer)); + }, + { + './address': 1, + './crypto/bn': 6, + './crypto/point': 9, + './crypto/random': 10, + './encoding/base58check': 13, + './networks': 21, + './publickey': 24, + './util/js': 43, + './util/preconditions': 44, + buffer: 113, + lodash: 187, + }, + ], + 24: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var BN = require('./crypto/bn'); + var Point = require('./crypto/point'); + var Hash = require('./crypto/hash'); + var JSUtil = require('./util/js'); + var Network = require('./networks'); + var _ = require('lodash'); + var $ = require('./util/preconditions'); + + /** + * Instantiate a PublicKey from a {@link PrivateKey}, {@link Point}, `string`, or `Buffer`. + * + * There are two internal properties, `network` and `compressed`, that deal with importing + * a PublicKey from a PrivateKey in WIF format. More details described on {@link PrivateKey} + * + * @example + * ```javascript + * // instantiate from a private key + * var key = PublicKey(privateKey, true); + * + * // export to as a DER hex encoded string + * var exported = key.toString(); + * + * // import the public key + * var imported = PublicKey.fromString(exported); + * ``` + * + * @param {string} data - The encoded data in various formats + * @param {Object} extra - additional options + * @param {Network=} extra.network - Which network should the address for this public key be for + * @param {String=} extra.compressed - If the public key is compressed + * @returns {PublicKey} A new valid instance of an PublicKey + * @constructor + */ + function PublicKey(data, extra) { + if (!(this instanceof PublicKey)) { + return new PublicKey(data, extra); + } + + $.checkArgument(data, 'First argument is required, please include public key data.'); + + if (data instanceof PublicKey) { + // Return copy, but as it's an immutable object, return same argument + return data; + } + extra = extra || {}; + + var info = this._classifyArgs(data, extra); + + // validation + info.point.validate(); + + JSUtil.defineImmutable(this, { + point: info.point, + compressed: info.compressed, + network: info.network || Network.defaultNetwork, + }); + + return this; + } + + /** + * Internal function to differentiate between arguments passed to the constructor + * @param {*} data + * @param {Object} extra + */ + PublicKey.prototype._classifyArgs = function(data, extra) { + /* jshint maxcomplexity: 10 */ + var info = { + compressed: _.isUndefined(extra.compressed) || extra.compressed, + }; + + // detect type of data + if (data instanceof Point) { + info.point = data; + } else if (data.x && data.y) { + info = PublicKey._transformObject(data); + } else if (typeof data === 'string') { + info = PublicKey._transformDER(new Buffer(data, 'hex')); + } else if (PublicKey._isBuffer(data)) { + info = PublicKey._transformDER(data); + } else if (PublicKey._isPrivateKey(data)) { + info = PublicKey._transformPrivateKey(data); + } else { + throw new TypeError('First argument is an unrecognized data format.'); + } + if (!info.network) { + info.network = _.isUndefined(extra.network) ? undefined : Network.get(extra.network); + } + return info; + }; + + /** + * Internal function to detect if an object is a {@link PrivateKey} + * + * @param {*} param - object to test + * @returns {boolean} + * @private + */ + PublicKey._isPrivateKey = function(param) { + var PrivateKey = require('./privatekey'); + return param instanceof PrivateKey; + }; + + /** + * Internal function to detect if an object is a Buffer + * + * @param {*} param - object to test + * @returns {boolean} + * @private + */ + PublicKey._isBuffer = function(param) { + return param instanceof Buffer || param instanceof Uint8Array; + }; + + /** + * Internal function to transform a private key into a public key point + * + * @param {PrivateKey} privkey - An instance of PrivateKey + * @returns {Object} An object with keys: point and compressed + * @private + */ + PublicKey._transformPrivateKey = function(privkey) { + $.checkArgument(PublicKey._isPrivateKey(privkey), 'Must be an instance of PrivateKey'); + var info = {}; + info.point = Point.getG().mul(privkey.bn); + info.compressed = privkey.compressed; + info.network = privkey.network; + return info; + }; + + /** + * Internal function to transform DER into a public key point + * + * @param {Buffer} buf - An hex encoded buffer + * @param {bool=} strict - if set to false, will loosen some conditions + * @returns {Object} An object with keys: point and compressed + * @private + */ + PublicKey._transformDER = function(buf, strict) { + /* jshint maxstatements: 30 */ + /* jshint maxcomplexity: 12 */ + $.checkArgument(PublicKey._isBuffer(buf), 'Must be a hex buffer of DER encoded public key'); + var info = {}; + + strict = _.isUndefined(strict) ? true : strict; + + var x; + var y; + var xbuf; + var ybuf; + + if (buf[0] === 0x04 || (!strict && (buf[0] === 0x06 || buf[0] === 0x07))) { + xbuf = buf.slice(1, 33); + ybuf = buf.slice(33, 65); + if (xbuf.length !== 32 || ybuf.length !== 32 || buf.length !== 65) { + throw new TypeError('Length of x and y must be 32 bytes'); + } + x = new BN(xbuf); + y = new BN(ybuf); + info.point = new Point(x, y); + info.compressed = false; + } else if (buf[0] === 0x03) { + xbuf = buf.slice(1); + x = new BN(xbuf); + info = PublicKey._transformX(true, x); + info.compressed = true; + } else if (buf[0] === 0x02) { + xbuf = buf.slice(1); + x = new BN(xbuf); + info = PublicKey._transformX(false, x); + info.compressed = true; + } else { + throw new TypeError('Invalid DER format public key'); + } + return info; + }; + + /** + * Internal function to transform X into a public key point + * + * @param {Boolean} odd - If the point is above or below the x axis + * @param {Point} x - The x point + * @returns {Object} An object with keys: point and compressed + * @private + */ + PublicKey._transformX = function(odd, x) { + $.checkArgument(typeof odd === 'boolean', 'Must specify whether y is odd or not (true or false)'); + var info = {}; + info.point = Point.fromX(odd, x); + return info; + }; + + /** + * Internal function to transform a JSON into a public key point + * + * @param {String|Object} json - a JSON string or plain object + * @returns {Object} An object with keys: point and compressed + * @private + */ + PublicKey._transformObject = function(json) { + var x = new BN(json.x, 'hex'); + var y = new BN(json.y, 'hex'); + var point = new Point(x, y); + return new PublicKey(point, { + compressed: json.compressed, + }); + }; + + /** + * Instantiate a PublicKey from a PrivateKey + * + * @param {PrivateKey} privkey - An instance of PrivateKey + * @returns {PublicKey} A new valid instance of PublicKey + */ + PublicKey.fromPrivateKey = function(privkey) { + $.checkArgument(PublicKey._isPrivateKey(privkey), 'Must be an instance of PrivateKey'); + var info = PublicKey._transformPrivateKey(privkey); + return new PublicKey(info.point, { + compressed: info.compressed, + network: info.network, + }); + }; + + /** + * Instantiate a PublicKey from a Buffer + * @param {Buffer} buf - A DER hex buffer + * @param {bool=} strict - if set to false, will loosen some conditions + * @returns {PublicKey} A new valid instance of PublicKey + */ + PublicKey.fromDER = PublicKey.fromBuffer = function(buf, strict) { + $.checkArgument(PublicKey._isBuffer(buf), 'Must be a hex buffer of DER encoded public key'); + var info = PublicKey._transformDER(buf, strict); + return new PublicKey(info.point, { + compressed: info.compressed, + }); + }; + + /** + * Instantiate a PublicKey from a Point + * + * @param {Point} point - A Point instance + * @param {boolean=} compressed - whether to store this public key as compressed format + * @returns {PublicKey} A new valid instance of PublicKey + */ + PublicKey.fromPoint = function(point, compressed) { + $.checkArgument(point instanceof Point, 'First argument must be an instance of Point.'); + return new PublicKey(point, { + compressed: compressed, + }); + }; + + /** + * Instantiate a PublicKey from a DER hex encoded string + * + * @param {string} str - A DER hex string + * @param {String=} encoding - The type of string encoding + * @returns {PublicKey} A new valid instance of PublicKey + */ + PublicKey.fromString = function(str, encoding) { + var buf = new Buffer(str, encoding || 'hex'); + var info = PublicKey._transformDER(buf); + return new PublicKey(info.point, { + compressed: info.compressed, + }); + }; + + /** + * Instantiate a PublicKey from an X Point + * + * @param {Boolean} odd - If the point is above or below the x axis + * @param {Point} x - The x point + * @returns {PublicKey} A new valid instance of PublicKey + */ + PublicKey.fromX = function(odd, x) { + var info = PublicKey._transformX(odd, x); + return new PublicKey(info.point, { + compressed: info.compressed, + }); + }; + + /** + * Check if there would be any errors when initializing a PublicKey + * + * @param {string} data - The encoded data in various formats + * @returns {null|Error} An error if exists + */ + PublicKey.getValidationError = function(data) { + var error; + try { + /* jshint nonew: false */ + new PublicKey(data); + } catch (e) { + error = e; + } + return error; + }; + + /** + * Check if the parameters are valid + * + * @param {string} data - The encoded data in various formats + * @returns {Boolean} If the public key would be valid + */ + PublicKey.isValid = function(data) { + return !PublicKey.getValidationError(data); + }; + + /** + * @returns {Object} A plain object of the PublicKey + */ + PublicKey.prototype.toObject = PublicKey.prototype.toJSON = function toObject() { + return { + x: this.point.getX().toString('hex', 2), + y: this.point.getY().toString('hex', 2), + compressed: this.compressed, + }; + }; + + /** + * Will output the PublicKey to a DER Buffer + * + * @returns {Buffer} A DER hex encoded buffer + */ + PublicKey.prototype.toBuffer = PublicKey.prototype.toDER = function() { + var x = this.point.getX(); + var y = this.point.getY(); + + var xbuf = x.toBuffer({ + size: 32, + }); + var ybuf = y.toBuffer({ + size: 32, + }); + + var prefix; + if (!this.compressed) { + prefix = new Buffer([0x04]); + return Buffer.concat([prefix, xbuf, ybuf]); + } else { + var odd = ybuf[ybuf.length - 1] % 2; + if (odd) { + prefix = new Buffer([0x03]); + } else { + prefix = new Buffer([0x02]); + } + return Buffer.concat([prefix, xbuf]); + } + }; + + /** + * Will return a sha256 + ripemd160 hash of the serialized public key + * @see https://github.com/bitcoin/bitcoin/blob/master/src/pubkey.h#L141 + * @returns {Buffer} + */ + PublicKey.prototype._getID = function _getID() { + return Hash.sha256ripemd160(this.toBuffer()); + }; + + /** + * Will return an address for the public key + * + * @param {String|Network=} network - Which network should the address be for + * @returns {Address} An address generated from the public key + */ + PublicKey.prototype.toAddress = function(network) { + var Address = require('./address'); + return Address.fromPublicKey(this, network || this.network); + }; + + /** + * Will output the PublicKey to a DER encoded hex string + * + * @returns {string} A DER hex encoded string + */ + PublicKey.prototype.toString = function() { + return this.toDER().toString('hex'); + }; + + /** + * Will return a string formatted for the console + * + * @returns {string} Public key + */ + PublicKey.prototype.inspect = function() { + return ''; + }; + + module.exports = PublicKey; + }.call(this, require('buffer').Buffer)); + }, + { + './address': 1, + './crypto/bn': 6, + './crypto/hash': 8, + './crypto/point': 9, + './networks': 21, + './privatekey': 23, + './util/js': 43, + './util/preconditions': 44, + buffer: 113, + lodash: 187, + }, + ], + 25: [ + function(require, module, exports) { + module.exports = require('./script'); + + module.exports.Interpreter = require('./interpreter'); + }, + { './interpreter': 26, './script': 27 }, + ], + 26: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var _ = require('lodash'); + + var Script = require('./script'); + var Opcode = require('../opcode'); + var BN = require('../crypto/bn'); + var Hash = require('../crypto/hash'); + var Signature = require('../crypto/signature'); + var PublicKey = require('../publickey'); + + /** + * Merit transactions contain scripts. Each input has a script called the + * scriptSig, and each output has a script called the scriptPubkey. To validate + * an input, the input's script is concatenated with the referenced output script, + * and the result is executed. If at the end of execution the stack contains a + * "true" value, then the transaction is valid. + * + * The primary way to use this class is via the verify function. + * e.g., Interpreter().verify( ... ); + */ + var Interpreter = function Interpreter(obj) { + if (!(this instanceof Interpreter)) { + return new Interpreter(obj); + } + if (obj) { + this.initialize(); + this.set(obj); + } else { + this.initialize(); + } + }; + + /** + * Verifies a Script by executing it and returns true if it is valid. + * This function needs to be provided with the scriptSig and the scriptPubkey + * separately. + * @param {Script} scriptSig - the script's first part (corresponding to the tx input) + * @param {Script} scriptPubkey - the script's last part (corresponding to the tx output) + * @param {Transaction=} tx - the Transaction containing the scriptSig in one input (used + * to check signature validity for some opcodes like OP_CHECKSIG) + * @param {number} nin - index of the transaction input containing the scriptSig verified. + * @param {number} flags - evaluation flags. See Interpreter.SCRIPT_* constants + * + * Translated from bitcoind's VerifyScript + */ + Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags) { + var Transaction = require('../transaction'); + if (_.isUndefined(tx)) { + tx = new Transaction(); + } + if (_.isUndefined(nin)) { + nin = 0; + } + if (_.isUndefined(flags)) { + flags = 0; + } + this.set({ + script: scriptSig, + tx: tx, + nin: nin, + flags: flags, + }); + var stackCopy; + + if ((flags & Interpreter.SCRIPT_VERIFY_SIGPUSHONLY) !== 0 && !scriptSig.isPushOnly()) { + this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'; + return false; + } + + // evaluate scriptSig + if (!this.evaluate()) { + return false; + } + + if (flags & Interpreter.SCRIPT_VERIFY_P2SH) { + stackCopy = this.stack.slice(); + } + + var stack = this.stack; + this.initialize(); + this.set({ + script: scriptPubkey, + stack: stack, + tx: tx, + nin: nin, + flags: flags, + }); + + // evaluate scriptPubkey + if (!this.evaluate()) { + return false; + } + + if (this.stack.length === 0) { + this.errstr = 'SCRIPT_ERR_EVAL_FALSE_NO_RESULT'; + return false; + } + + var buf = this.stack[this.stack.length - 1]; + if (!Interpreter.castToBool(buf)) { + this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_STACK'; + return false; + } + + // Additional validation for spend-to-script-hash transactions: + if (flags & Interpreter.SCRIPT_VERIFY_P2SH && scriptPubkey.isScriptHashOut()) { + // scriptSig must be literals-only or validation fails + if (!scriptSig.isPushOnly()) { + this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'; + return false; + } + + // stackCopy cannot be empty here, because if it was the + // P2SH HASH <> EQUAL scriptPubKey would be evaluated with + // an empty stack and the EvalScript above would return false. + if (stackCopy.length === 0) { + throw new Error('internal error - stack copy empty'); + } + + var redeemScriptSerialized = stackCopy[stackCopy.length - 1]; + var redeemScript = Script.fromBuffer(redeemScriptSerialized); + stackCopy.pop(); + + this.initialize(); + this.set({ + script: redeemScript, + stack: stackCopy, + tx: tx, + nin: nin, + flags: flags, + }); + + // evaluate redeemScript + if (!this.evaluate()) { + return false; + } + + if (stackCopy.length === 0) { + this.errstr = 'SCRIPT_ERR_EVAL_FALSE_NO_P2SH_STACK'; + return false; + } + + if (!Interpreter.castToBool(stackCopy[stackCopy.length - 1])) { + this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_P2SH_STACK'; + return false; + } else { + return true; + } + } + + return true; + }; + + module.exports = Interpreter; + + Interpreter.prototype.initialize = function(obj) { + this.stack = []; + this.altstack = []; + this.pc = 0; + this.pbegincodehash = 0; + this.nOpCount = 0; + this.vfExec = []; + this.errstr = ''; + this.flags = 0; + }; + + Interpreter.prototype.set = function(obj) { + this.script = obj.script || this.script; + this.tx = obj.tx || this.tx; + this.nin = typeof obj.nin !== 'undefined' ? obj.nin : this.nin; + this.stack = obj.stack || this.stack; + this.altstack = obj.altack || this.altstack; + this.pc = typeof obj.pc !== 'undefined' ? obj.pc : this.pc; + this.pbegincodehash = typeof obj.pbegincodehash !== 'undefined' ? obj.pbegincodehash : this.pbegincodehash; + this.nOpCount = typeof obj.nOpCount !== 'undefined' ? obj.nOpCount : this.nOpCount; + this.vfExec = obj.vfExec || this.vfExec; + this.errstr = obj.errstr || this.errstr; + this.flags = typeof obj.flags !== 'undefined' ? obj.flags : this.flags; + }; + + Interpreter.true = new Buffer([1]); + Interpreter.false = new Buffer([]); + + Interpreter.MAX_SCRIPT_ELEMENT_SIZE = 520; + + Interpreter.LOCKTIME_THRESHOLD = 500000000; + Interpreter.LOCKTIME_THRESHOLD_BN = new BN(Interpreter.LOCKTIME_THRESHOLD); + + // flags taken from bitcoind + // bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 + Interpreter.SCRIPT_VERIFY_NONE = 0; + + // Evaluate P2SH subscripts (softfork safe, BIP16). + Interpreter.SCRIPT_VERIFY_P2SH = 1 << 0; + + // Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure. + // Passing a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) to checksig causes that pubkey to be + // skipped (not softfork safe: this flag can widen the validity of OP_CHECKSIG OP_NOT). + Interpreter.SCRIPT_VERIFY_STRICTENC = 1 << 1; + + // Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1) + Interpreter.SCRIPT_VERIFY_DERSIG = 1 << 2; + + // Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure + // (softfork safe, BIP62 rule 5). + Interpreter.SCRIPT_VERIFY_LOW_S = 1 << 3; + + // verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7). + Interpreter.SCRIPT_VERIFY_NULLDUMMY = 1 << 4; + + // Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2). + Interpreter.SCRIPT_VERIFY_SIGPUSHONLY = 1 << 5; + + // Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct + // pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating + // any other push causes the script to fail (BIP62 rule 3). + // In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4). + // (softfork safe) + Interpreter.SCRIPT_VERIFY_MINIMALDATA = 1 << 6; + + // Discourage use of NOPs reserved for upgrades (NOP1-10) + // + // Provided so that nodes can avoid accepting or mining transactions + // containing executed NOP's whose meaning may change after a soft-fork, + // thus rendering the script invalid; with this flag set executing + // discouraged NOPs fails the script. This verification flag will never be + // a mandatory flag applied to scripts in a block. NOPs that are not + // executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected. + Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = 1 << 7; + + // CLTV See BIP65 for details. + Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = 1 << 9; + + Interpreter.castToBool = function(buf) { + for (var i = 0; i < buf.length; i++) { + if (buf[i] !== 0) { + // can be negative zero + if (i === buf.length - 1 && buf[i] === 0x80) { + return false; + } + return true; + } + } + return false; + }; + + /** + * Translated from bitcoind's CheckSignatureEncoding + */ + Interpreter.prototype.checkSignatureEncoding = function(buf) { + var sig; + if ( + (this.flags & + (Interpreter.SCRIPT_VERIFY_DERSIG | + Interpreter.SCRIPT_VERIFY_LOW_S | + Interpreter.SCRIPT_VERIFY_STRICTENC)) !== + 0 && + !Signature.isTxDER(buf) + ) { + this.errstr = 'SCRIPT_ERR_SIG_DER_INVALID_FORMAT'; + return false; + } else if ((this.flags & Interpreter.SCRIPT_VERIFY_LOW_S) !== 0) { + sig = Signature.fromTxFormat(buf); + if (!sig.hasLowS()) { + this.errstr = 'SCRIPT_ERR_SIG_DER_HIGH_S'; + return false; + } + } else if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0) { + sig = Signature.fromTxFormat(buf); + if (!sig.hasDefinedHashtype()) { + this.errstr = 'SCRIPT_ERR_SIG_HASHTYPE'; + return false; + } + } + return true; + }; + + /** + * Translated from bitcoind's CheckPubKeyEncoding + */ + Interpreter.prototype.checkPubkeyEncoding = function(buf) { + if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0 && !PublicKey.isValid(buf)) { + this.errstr = 'SCRIPT_ERR_PUBKEYTYPE'; + return false; + } + return true; + }; + + /** + * Based on bitcoind's EvalScript function, with the inner loop moved to + * Interpreter.prototype.step() + * bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 + */ + Interpreter.prototype.evaluate = function() { + if (this.script.toBuffer().length > 10000) { + this.errstr = 'SCRIPT_ERR_SCRIPT_SIZE'; + return false; + } + + try { + while (this.pc < this.script.chunks.length) { + var fSuccess = this.step(); + if (!fSuccess) { + return false; + } + } + + // Size limits + if (this.stack.length + this.altstack.length > 1000) { + this.errstr = 'SCRIPT_ERR_STACK_SIZE'; + return false; + } + } catch (e) { + this.errstr = 'SCRIPT_ERR_UNKNOWN_ERROR: ' + e; + return false; + } + + if (this.vfExec.length > 0) { + this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; + return false; + } + + return true; + }; + + /** + * Checks a locktime parameter with the transaction's locktime. + * There are two times of nLockTime: lock-by-blockheight and lock-by-blocktime, + * distinguished by whether nLockTime < LOCKTIME_THRESHOLD = 500000000 + * + * See the corresponding code on Merit core: + * https://github.com/bitcoin/bitcoin/blob/ffd75adce01a78b3461b3ff05bcc2b530a9ce994/src/script/interpreter.cpp#L1129 + * + * @param {BN} nLockTime the locktime read from the script + * @return {boolean} true if the transaction's locktime is less than or equal to + * the transaction's locktime + */ + Interpreter.prototype.checkLockTime = function(nLockTime) { + // We want to compare apples to apples, so fail the script + // unless the type of nLockTime being tested is the same as + // the nLockTime in the transaction. + if ( + !( + (this.tx.nLockTime < Interpreter.LOCKTIME_THRESHOLD && + nLockTime.lt(Interpreter.LOCKTIME_THRESHOLD_BN)) || + (this.tx.nLockTime >= Interpreter.LOCKTIME_THRESHOLD && + nLockTime.gte(Interpreter.LOCKTIME_THRESHOLD_BN)) + ) + ) { + return false; + } + + // Now that we know we're comparing apples-to-apples, the + // comparison is a simple numeric one. + if (nLockTime.gt(new BN(this.tx.nLockTime))) { + return false; + } + + // Finally the nLockTime feature can be disabled and thus + // CHECKLOCKTIMEVERIFY bypassed if every txin has been + // finalized by setting nSequence to maxint. The + // transaction would be allowed into the blockchain, making + // the opcode ineffective. + // + // Testing if this vin is not final is sufficient to + // prevent this condition. Alternatively we could test all + // inputs, but testing just this input minimizes the data + // required to prove correct CHECKLOCKTIMEVERIFY execution. + if (!this.tx.inputs[this.nin].isFinal()) { + return false; + } + + return true; + }; + + /** + * Based on the inner loop of bitcoind's EvalScript function + * bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 + */ + Interpreter.prototype.step = function() { + var fRequireMinimal = (this.flags & Interpreter.SCRIPT_VERIFY_MINIMALDATA) !== 0; + + //bool fExec = !count(vfExec.begin(), vfExec.end(), false); + var fExec = this.vfExec.indexOf(false) === -1; + var buf, buf1, buf2, spliced, n, x1, x2, bn, bn1, bn2, bufSig, bufPubkey, subscript; + var sig, pubkey; + var fValue, fSuccess; + + // Read instruction + var chunk = this.script.chunks[this.pc]; + this.pc++; + var opcodenum = chunk.opcodenum; + if (_.isUndefined(opcodenum)) { + this.errstr = 'SCRIPT_ERR_UNDEFINED_OPCODE'; + return false; + } + if (chunk.buf && chunk.buf.length > Interpreter.MAX_SCRIPT_ELEMENT_SIZE) { + this.errstr = 'SCRIPT_ERR_PUSH_SIZE'; + return false; + } + + // Note how Opcode.OP_RESERVED does not count towards the opcode limit. + if (opcodenum > Opcode.OP_16 && ++this.nOpCount > 201) { + this.errstr = 'SCRIPT_ERR_OP_COUNT'; + return false; + } + + if ( + opcodenum === Opcode.OP_CAT || + opcodenum === Opcode.OP_SUBSTR || + opcodenum === Opcode.OP_LEFT || + opcodenum === Opcode.OP_RIGHT || + opcodenum === Opcode.OP_INVERT || + opcodenum === Opcode.OP_AND || + opcodenum === Opcode.OP_OR || + opcodenum === Opcode.OP_XOR || + opcodenum === Opcode.OP_2MUL || + opcodenum === Opcode.OP_2DIV || + opcodenum === Opcode.OP_MUL || + opcodenum === Opcode.OP_DIV || + opcodenum === Opcode.OP_MOD || + opcodenum === Opcode.OP_LSHIFT || + opcodenum === Opcode.OP_RSHIFT + ) { + this.errstr = 'SCRIPT_ERR_DISABLED_OPCODE'; + return false; + } + + if (fExec && 0 <= opcodenum && opcodenum <= Opcode.OP_PUSHDATA4) { + if (fRequireMinimal && !this.script.checkMinimalPush(this.pc - 1)) { + this.errstr = 'SCRIPT_ERR_MINIMALDATA'; + return false; + } + if (!chunk.buf) { + this.stack.push(Interpreter.false); + } else if (chunk.len !== chunk.buf.length) { + throw new Error('Length of push value not equal to length of data'); + } else { + this.stack.push(chunk.buf); + } + } else if (fExec || (Opcode.OP_IF <= opcodenum && opcodenum <= Opcode.OP_ENDIF)) { + switch (opcodenum) { + // Push value + case Opcode.OP_1NEGATE: + case Opcode.OP_1: + case Opcode.OP_2: + case Opcode.OP_3: + case Opcode.OP_4: + case Opcode.OP_5: + case Opcode.OP_6: + case Opcode.OP_7: + case Opcode.OP_8: + case Opcode.OP_9: + case Opcode.OP_10: + case Opcode.OP_11: + case Opcode.OP_12: + case Opcode.OP_13: + case Opcode.OP_14: + case Opcode.OP_15: + case Opcode.OP_16: + { + // ( -- value) + // ScriptNum bn((int)opcode - (int)(Opcode.OP_1 - 1)); + n = opcodenum - (Opcode.OP_1 - 1); + buf = new BN(n).toScriptNumBuffer(); + this.stack.push(buf); + // The result of these opcodes should always be the minimal way to push the data + // they push, so no need for a CheckMinimalPush here. + } + break; + + // + // Control + // + case Opcode.OP_NOP: + break; + + case Opcode.OP_NOP2: + case Opcode.OP_CHECKLOCKTIMEVERIFY: + if (!(this.flags & Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) { + // not enabled; treat as a NOP2 + if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { + this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'; + return false; + } + break; + } + + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + + // Note that elsewhere numeric opcodes are limited to + // operands in the range -2**31+1 to 2**31-1, however it is + // legal for opcodes to produce results exceeding that + // range. This limitation is implemented by CScriptNum's + // default 4-byte limit. + // + // If we kept to that limit we'd have a year 2038 problem, + // even though the nLockTime field in transactions + // themselves is uint32 which only becomes meaningless + // after the year 2106. + // + // Thus as a special case we tell CScriptNum to accept up + // to 5-byte bignums, which are good until 2**39-1, well + // beyond the 2**32-1 limit of the nLockTime field itself. + var nLockTime = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal, 5); + + // In the rare event that the argument may be < 0 due to + // some arithmetic being done first, you can always use + // 0 MAX CHECKLOCKTIMEVERIFY. + if (nLockTime.lt(new BN(0))) { + this.errstr = 'SCRIPT_ERR_NEGATIVE_LOCKTIME'; + return false; + } + + // Actually compare the specified lock time with the transaction. + if (!this.checkLockTime(nLockTime)) { + this.errstr = 'SCRIPT_ERR_UNSATISFIED_LOCKTIME'; + return false; + } + break; + + case Opcode.OP_NOP1: + case Opcode.OP_NOP3: + case Opcode.OP_NOP4: + case Opcode.OP_NOP5: + case Opcode.OP_NOP6: + case Opcode.OP_NOP7: + case Opcode.OP_NOP8: + case Opcode.OP_NOP9: + case Opcode.OP_NOP10: + { + if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { + this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'; + return false; + } + } + break; + + case Opcode.OP_IF: + case Opcode.OP_NOTIF: + { + // if [statements] [else [statements]] endif + // bool fValue = false; + fValue = false; + if (fExec) { + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; + return false; + } + buf = this.stack.pop(); + fValue = Interpreter.castToBool(buf); + if (opcodenum === Opcode.OP_NOTIF) { + fValue = !fValue; + } + } + this.vfExec.push(fValue); + } + break; + + case Opcode.OP_ELSE: + { + if (this.vfExec.length === 0) { + this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; + return false; + } + this.vfExec[this.vfExec.length - 1] = !this.vfExec[this.vfExec.length - 1]; + } + break; + + case Opcode.OP_ENDIF: + { + if (this.vfExec.length === 0) { + this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; + return false; + } + this.vfExec.pop(); + } + break; + + case Opcode.OP_VERIFY: + { + // (true -- ) or + // (false -- false) and return + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf = this.stack[this.stack.length - 1]; + fValue = Interpreter.castToBool(buf); + if (fValue) { + this.stack.pop(); + } else { + this.errstr = 'SCRIPT_ERR_VERIFY'; + return false; + } + } + break; + + case Opcode.OP_RETURN: + { + this.errstr = 'SCRIPT_ERR_OP_RETURN'; + return false; + } + break; + + // + // Stack ops + // + case Opcode.OP_TOALTSTACK: + { + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.altstack.push(this.stack.pop()); + } + break; + + case Opcode.OP_FROMALTSTACK: + { + if (this.altstack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_ALTSTACK_OPERATION'; + return false; + } + this.stack.push(this.altstack.pop()); + } + break; + + case Opcode.OP_2DROP: + { + // (x1 x2 -- ) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.stack.pop(); + this.stack.pop(); + } + break; + + case Opcode.OP_2DUP: + { + // (x1 x2 -- x1 x2 x1 x2) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf1 = this.stack[this.stack.length - 2]; + buf2 = this.stack[this.stack.length - 1]; + this.stack.push(buf1); + this.stack.push(buf2); + } + break; + + case Opcode.OP_3DUP: + { + // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) + if (this.stack.length < 3) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf1 = this.stack[this.stack.length - 3]; + buf2 = this.stack[this.stack.length - 2]; + var buf3 = this.stack[this.stack.length - 1]; + this.stack.push(buf1); + this.stack.push(buf2); + this.stack.push(buf3); + } + break; + + case Opcode.OP_2OVER: + { + // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) + if (this.stack.length < 4) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf1 = this.stack[this.stack.length - 4]; + buf2 = this.stack[this.stack.length - 3]; + this.stack.push(buf1); + this.stack.push(buf2); + } + break; + + case Opcode.OP_2ROT: + { + // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) + if (this.stack.length < 6) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + spliced = this.stack.splice(this.stack.length - 6, 2); + this.stack.push(spliced[0]); + this.stack.push(spliced[1]); + } + break; + + case Opcode.OP_2SWAP: + { + // (x1 x2 x3 x4 -- x3 x4 x1 x2) + if (this.stack.length < 4) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + spliced = this.stack.splice(this.stack.length - 4, 2); + this.stack.push(spliced[0]); + this.stack.push(spliced[1]); + } + break; + + case Opcode.OP_IFDUP: + { + // (x - 0 | x x) + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf = this.stack[this.stack.length - 1]; + fValue = Interpreter.castToBool(buf); + if (fValue) { + this.stack.push(buf); + } + } + break; + + case Opcode.OP_DEPTH: + { + // -- stacksize + buf = new BN(this.stack.length).toScriptNumBuffer(); + this.stack.push(buf); + } + break; + + case Opcode.OP_DROP: + { + // (x -- ) + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.stack.pop(); + } + break; + + case Opcode.OP_DUP: + { + // (x -- x x) + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.stack.push(this.stack[this.stack.length - 1]); + } + break; + + case Opcode.OP_NIP: + { + // (x1 x2 -- x2) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.stack.splice(this.stack.length - 2, 1); + } + break; + + case Opcode.OP_OVER: + { + // (x1 x2 -- x1 x2 x1) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.stack.push(this.stack[this.stack.length - 2]); + } + break; + + case Opcode.OP_PICK: + case Opcode.OP_ROLL: + { + // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) + // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf = this.stack[this.stack.length - 1]; + bn = BN.fromScriptNumBuffer(buf, fRequireMinimal); + n = bn.toNumber(); + this.stack.pop(); + if (n < 0 || n >= this.stack.length) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf = this.stack[this.stack.length - n - 1]; + if (opcodenum === Opcode.OP_ROLL) { + this.stack.splice(this.stack.length - n - 1, 1); + } + this.stack.push(buf); + } + break; + + case Opcode.OP_ROT: + { + // (x1 x2 x3 -- x2 x3 x1) + // x2 x1 x3 after first swap + // x2 x3 x1 after second swap + if (this.stack.length < 3) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + x1 = this.stack[this.stack.length - 3]; + x2 = this.stack[this.stack.length - 2]; + var x3 = this.stack[this.stack.length - 1]; + this.stack[this.stack.length - 3] = x2; + this.stack[this.stack.length - 2] = x3; + this.stack[this.stack.length - 1] = x1; + } + break; + + case Opcode.OP_SWAP: + { + // (x1 x2 -- x2 x1) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + x1 = this.stack[this.stack.length - 2]; + x2 = this.stack[this.stack.length - 1]; + this.stack[this.stack.length - 2] = x2; + this.stack[this.stack.length - 1] = x1; + } + break; + + case Opcode.OP_TUCK: + { + // (x1 x2 -- x2 x1 x2) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.stack.splice(this.stack.length - 2, 0, this.stack[this.stack.length - 1]); + } + break; + + case Opcode.OP_SIZE: + { + // (in -- in size) + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + bn = new BN(this.stack[this.stack.length - 1].length); + this.stack.push(bn.toScriptNumBuffer()); + } + break; + + // + // Bitwise logic + // + case Opcode.OP_EQUAL: + case Opcode.OP_EQUALVERIFY: + //case Opcode.OP_NOTEQUAL: // use Opcode.OP_NUMNOTEQUAL + { + // (x1 x2 - bool) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf1 = this.stack[this.stack.length - 2]; + buf2 = this.stack[this.stack.length - 1]; + var fEqual = buf1.toString('hex') === buf2.toString('hex'); + this.stack.pop(); + this.stack.pop(); + this.stack.push(fEqual ? Interpreter.true : Interpreter.false); + if (opcodenum === Opcode.OP_EQUALVERIFY) { + if (fEqual) { + this.stack.pop(); + } else { + this.errstr = 'SCRIPT_ERR_EQUALVERIFY'; + return false; + } + } + } + break; + + // + // Numeric + // + case Opcode.OP_1ADD: + case Opcode.OP_1SUB: + case Opcode.OP_NEGATE: + case Opcode.OP_ABS: + case Opcode.OP_NOT: + case Opcode.OP_0NOTEQUAL: + { + // (in -- out) + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf = this.stack[this.stack.length - 1]; + bn = BN.fromScriptNumBuffer(buf, fRequireMinimal); + switch (opcodenum) { + case Opcode.OP_1ADD: + bn = bn.add(BN.One); + break; + case Opcode.OP_1SUB: + bn = bn.sub(BN.One); + break; + case Opcode.OP_NEGATE: + bn = bn.neg(); + break; + case Opcode.OP_ABS: + if (bn.cmp(BN.Zero) < 0) { + bn = bn.neg(); + } + break; + case Opcode.OP_NOT: + bn = new BN((bn.cmp(BN.Zero) === 0) + 0); + break; + case Opcode.OP_0NOTEQUAL: + bn = new BN((bn.cmp(BN.Zero) !== 0) + 0); + break; + //default: assert(!'invalid opcode'); break; // TODO: does this ever occur? + } + this.stack.pop(); + this.stack.push(bn.toScriptNumBuffer()); + } + break; + + case Opcode.OP_ADD: + case Opcode.OP_SUB: + case Opcode.OP_BOOLAND: + case Opcode.OP_BOOLOR: + case Opcode.OP_NUMEQUAL: + case Opcode.OP_NUMEQUALVERIFY: + case Opcode.OP_NUMNOTEQUAL: + case Opcode.OP_LESSTHAN: + case Opcode.OP_GREATERTHAN: + case Opcode.OP_LESSTHANOREQUAL: + case Opcode.OP_GREATERTHANOREQUAL: + case Opcode.OP_MIN: + case Opcode.OP_MAX: + { + // (x1 x2 -- out) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + bn1 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal); + bn2 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal); + bn = new BN(0); + + switch (opcodenum) { + case Opcode.OP_ADD: + bn = bn1.add(bn2); + break; + + case Opcode.OP_SUB: + bn = bn1.sub(bn2); + break; + + // case Opcode.OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; + case Opcode.OP_BOOLAND: + bn = new BN((bn1.cmp(BN.Zero) !== 0 && bn2.cmp(BN.Zero) !== 0) + 0); + break; + // case Opcode.OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; + case Opcode.OP_BOOLOR: + bn = new BN((bn1.cmp(BN.Zero) !== 0 || bn2.cmp(BN.Zero) !== 0) + 0); + break; + // case Opcode.OP_NUMEQUAL: bn = (bn1 == bn2); break; + case Opcode.OP_NUMEQUAL: + bn = new BN((bn1.cmp(bn2) === 0) + 0); + break; + // case Opcode.OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break; + case Opcode.OP_NUMEQUALVERIFY: + bn = new BN((bn1.cmp(bn2) === 0) + 0); + break; + // case Opcode.OP_NUMNOTEQUAL: bn = (bn1 != bn2); break; + case Opcode.OP_NUMNOTEQUAL: + bn = new BN((bn1.cmp(bn2) !== 0) + 0); + break; + // case Opcode.OP_LESSTHAN: bn = (bn1 < bn2); break; + case Opcode.OP_LESSTHAN: + bn = new BN((bn1.cmp(bn2) < 0) + 0); + break; + // case Opcode.OP_GREATERTHAN: bn = (bn1 > bn2); break; + case Opcode.OP_GREATERTHAN: + bn = new BN((bn1.cmp(bn2) > 0) + 0); + break; + // case Opcode.OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break; + case Opcode.OP_LESSTHANOREQUAL: + bn = new BN((bn1.cmp(bn2) <= 0) + 0); + break; + // case Opcode.OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; + case Opcode.OP_GREATERTHANOREQUAL: + bn = new BN((bn1.cmp(bn2) >= 0) + 0); + break; + case Opcode.OP_MIN: + bn = bn1.cmp(bn2) < 0 ? bn1 : bn2; + break; + case Opcode.OP_MAX: + bn = bn1.cmp(bn2) > 0 ? bn1 : bn2; + break; + // default: assert(!'invalid opcode'); break; //TODO: does this ever occur? + } + this.stack.pop(); + this.stack.pop(); + this.stack.push(bn.toScriptNumBuffer()); + + if (opcodenum === Opcode.OP_NUMEQUALVERIFY) { + // if (CastToBool(stacktop(-1))) + if (Interpreter.castToBool(this.stack[this.stack.length - 1])) { + this.stack.pop(); + } else { + this.errstr = 'SCRIPT_ERR_NUMEQUALVERIFY'; + return false; + } + } + } + break; + + case Opcode.OP_WITHIN: + { + // (x min max -- out) + if (this.stack.length < 3) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + bn1 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 3], fRequireMinimal); + bn2 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal); + var bn3 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal); + //bool fValue = (bn2 <= bn1 && bn1 < bn3); + fValue = bn2.cmp(bn1) <= 0 && bn1.cmp(bn3) < 0; + this.stack.pop(); + this.stack.pop(); + this.stack.pop(); + this.stack.push(fValue ? Interpreter.true : Interpreter.false); + } + break; + + // + // Crypto + // + case Opcode.OP_RIPEMD160: + case Opcode.OP_SHA1: + case Opcode.OP_SHA256: + case Opcode.OP_HASH160: + case Opcode.OP_HASH256: + { + // (in -- hash) + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf = this.stack[this.stack.length - 1]; + //valtype vchHash((opcode == Opcode.OP_RIPEMD160 || + // opcode == Opcode.OP_SHA1 || opcode == Opcode.OP_HASH160) ? 20 : 32); + var bufHash; + if (opcodenum === Opcode.OP_RIPEMD160) { + bufHash = Hash.ripemd160(buf); + } else if (opcodenum === Opcode.OP_SHA1) { + bufHash = Hash.sha1(buf); + } else if (opcodenum === Opcode.OP_SHA256) { + bufHash = Hash.sha256(buf); + } else if (opcodenum === Opcode.OP_HASH160) { + bufHash = Hash.sha256ripemd160(buf); + } else if (opcodenum === Opcode.OP_HASH256) { + bufHash = Hash.sha256sha256(buf); + } + this.stack.pop(); + this.stack.push(bufHash); + } + break; + + case Opcode.OP_CODESEPARATOR: + { + // Hash starts after the code separator + this.pbegincodehash = this.pc; + } + break; + + case Opcode.OP_CHECKSIG: + case Opcode.OP_CHECKSIGVERIFY: + { + // (sig pubkey -- bool) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + + bufSig = this.stack[this.stack.length - 2]; + bufPubkey = this.stack[this.stack.length - 1]; + + // Subset of script starting at the most recent codeseparator + // CScript scriptCode(pbegincodehash, pend); + subscript = new Script().set({ + chunks: this.script.chunks.slice(this.pbegincodehash), + }); + + // Drop the signature, since there's no way for a signature to sign itself + var tmpScript = new Script().add(bufSig); + subscript.findAndDelete(tmpScript); + + if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) { + return false; + } + + try { + sig = Signature.fromTxFormat(bufSig); + pubkey = PublicKey.fromBuffer(bufPubkey, false); + fSuccess = this.tx.verifySignature(sig, pubkey, this.nin, subscript); + } catch (e) { + //invalid sig or pubkey + fSuccess = false; + } + + this.stack.pop(); + this.stack.pop(); + // stack.push_back(fSuccess ? vchTrue : vchFalse); + this.stack.push(fSuccess ? Interpreter.true : Interpreter.false); + if (opcodenum === Opcode.OP_CHECKSIGVERIFY) { + if (fSuccess) { + this.stack.pop(); + } else { + this.errstr = 'SCRIPT_ERR_CHECKSIGVERIFY'; + return false; + } + } + } + break; + + case Opcode.OP_CHECKMULTISIG: + case Opcode.OP_CHECKMULTISIGVERIFY: + { + // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) + + var i = 1; + if (this.stack.length < i) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + + var nKeysCount = BN.fromScriptNumBuffer( + this.stack[this.stack.length - i], + fRequireMinimal, + ).toNumber(); + if (nKeysCount < 0 || nKeysCount > 20) { + this.errstr = 'SCRIPT_ERR_PUBKEY_COUNT'; + return false; + } + this.nOpCount += nKeysCount; + if (this.nOpCount > 201) { + this.errstr = 'SCRIPT_ERR_OP_COUNT'; + return false; + } + // int ikey = ++i; + var ikey = ++i; + i += nKeysCount; + if (this.stack.length < i) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + + var nSigsCount = BN.fromScriptNumBuffer( + this.stack[this.stack.length - i], + fRequireMinimal, + ).toNumber(); + if (nSigsCount < 0 || nSigsCount > nKeysCount) { + this.errstr = 'SCRIPT_ERR_SIG_COUNT'; + return false; + } + // int isig = ++i; + var isig = ++i; + i += nSigsCount; + if (this.stack.length < i) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + + // Subset of script starting at the most recent codeseparator + subscript = new Script().set({ + chunks: this.script.chunks.slice(this.pbegincodehash), + }); + + // Drop the signatures, since there's no way for a signature to sign itself + for (var k = 0; k < nSigsCount; k++) { + bufSig = this.stack[this.stack.length - isig - k]; + subscript.findAndDelete(new Script().add(bufSig)); + } + + fSuccess = true; + while (fSuccess && nSigsCount > 0) { + // valtype& vchSig = stacktop(-isig); + bufSig = this.stack[this.stack.length - isig]; + // valtype& vchPubKey = stacktop(-ikey); + bufPubkey = this.stack[this.stack.length - ikey]; + + if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) { + return false; + } + + var fOk; + try { + sig = Signature.fromTxFormat(bufSig); + pubkey = PublicKey.fromBuffer(bufPubkey, false); + fOk = this.tx.verifySignature(sig, pubkey, this.nin, subscript); + } catch (e) { + //invalid sig or pubkey + fOk = false; + } + + if (fOk) { + isig++; + nSigsCount--; + } + ikey++; + nKeysCount--; + + // If there are more signatures left than keys left, + // then too many signatures have failed + if (nSigsCount > nKeysCount) { + fSuccess = false; + } + } + + // Clean up stack of actual arguments + while (i-- > 1) { + this.stack.pop(); + } + + // A bug causes CHECKMULTISIG to consume one extra argument + // whose contents were not checked in any way. + // + // Unfortunately this is a potential source of mutability, + // so optionally verify it is exactly equal to zero prior + // to removing it from the stack. + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + if (this.flags & Interpreter.SCRIPT_VERIFY_NULLDUMMY && this.stack[this.stack.length - 1].length) { + this.errstr = 'SCRIPT_ERR_SIG_NULLDUMMY'; + return false; + } + this.stack.pop(); + + this.stack.push(fSuccess ? Interpreter.true : Interpreter.false); + + if (opcodenum === Opcode.OP_CHECKMULTISIGVERIFY) { + if (fSuccess) { + this.stack.pop(); + } else { + this.errstr = 'SCRIPT_ERR_CHECKMULTISIGVERIFY'; + return false; + } + } + } + break; + + default: + this.errstr = 'SCRIPT_ERR_BAD_OPCODE'; + return false; + } + } + + return true; + }; + }.call(this, require('buffer').Buffer)); + }, + { + '../crypto/bn': 6, + '../crypto/hash': 8, + '../crypto/signature': 11, + '../opcode': 22, + '../publickey': 24, + '../transaction': 28, + './script': 27, + buffer: 113, + lodash: 187, + }, + ], + 27: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var Address = require('../address'); + var BufferReader = require('../encoding/bufferreader'); + var BufferWriter = require('../encoding/bufferwriter'); + var Hash = require('../crypto/hash'); + var Opcode = require('../opcode'); + var PublicKey = require('../publickey'); + var Signature = require('../crypto/signature'); + var Networks = require('../networks'); + var $ = require('../util/preconditions'); + var _ = require('lodash'); + var errors = require('../errors'); + var buffer = require('buffer'); + var BufferUtil = require('../util/buffer'); + var JSUtil = require('../util/js'); + + /** + * A Merit transaction script. Each transaction's inputs and outputs + * has a script that is evaluated to validate it's spending. + * + * See https://en.bitcoin.it/wiki/Script + * + * @constructor + * @param {Object|string|Buffer=} from optional data to populate script + */ + var Script = function Script(from) { + if (!(this instanceof Script)) { + return new Script(from); + } + this.chunks = []; + + if (BufferUtil.isBuffer(from)) { + return Script.fromBuffer(from); + } else if (from instanceof Address) { + return Script.fromAddress(from); + } else if (from instanceof Script) { + return Script.fromBuffer(from.toBuffer()); + } else if (typeof from === 'string') { + return Script.fromString(from); + } else if (typeof from !== 'undefined') { + this.set(from); + } + }; + + Script.prototype.set = function(obj) { + this.chunks = obj.chunks || this.chunks; + return this; + }; + + Script.fromBuffer = function(buffer) { + var script = new Script(); + script.chunks = []; + + var br = new BufferReader(buffer); + while (!br.finished()) { + try { + var opcodenum = br.readUInt8(); + + var len, buf; + if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) { + len = opcodenum; + script.chunks.push({ + buf: br.read(len), + len: len, + opcodenum: opcodenum, + }); + } else if (opcodenum === Opcode.OP_PUSHDATA1) { + len = br.readUInt8(); + buf = br.read(len); + script.chunks.push({ + buf: buf, + len: len, + opcodenum: opcodenum, + }); + } else if (opcodenum === Opcode.OP_PUSHDATA2) { + len = br.readUInt16LE(); + buf = br.read(len); + script.chunks.push({ + buf: buf, + len: len, + opcodenum: opcodenum, + }); + } else if (opcodenum === Opcode.OP_PUSHDATA4) { + len = br.readUInt32LE(); + buf = br.read(len); + script.chunks.push({ + buf: buf, + len: len, + opcodenum: opcodenum, + }); + } else { + script.chunks.push({ + opcodenum: opcodenum, + }); + } + } catch (e) { + if (e instanceof RangeError) { + throw new errors.Script.InvalidBuffer(buffer.toString('hex')); + } + throw e; + } + } + + return script; + }; + + Script.prototype.toBuffer = function() { + var bw = new BufferWriter(); + + for (var i = 0; i < this.chunks.length; i++) { + var chunk = this.chunks[i]; + var opcodenum = chunk.opcodenum; + bw.writeUInt8(chunk.opcodenum); + if (chunk.buf) { + if (opcodenum < Opcode.OP_PUSHDATA1) { + bw.write(chunk.buf); + } else if (opcodenum === Opcode.OP_PUSHDATA1) { + bw.writeUInt8(chunk.len); + bw.write(chunk.buf); + } else if (opcodenum === Opcode.OP_PUSHDATA2) { + bw.writeUInt16LE(chunk.len); + bw.write(chunk.buf); + } else if (opcodenum === Opcode.OP_PUSHDATA4) { + bw.writeUInt32LE(chunk.len); + bw.write(chunk.buf); + } + } + } + + return bw.concat(); + }; + + Script.fromASM = function(str) { + var script = new Script(); + script.chunks = []; + + var tokens = str.split(' '); + var i = 0; + while (i < tokens.length) { + var token = tokens[i]; + var opcode = Opcode(token); + var opcodenum = opcode.toNumber(); + + if (_.isUndefined(opcodenum)) { + var buf = new Buffer(tokens[i], 'hex'); + script.chunks.push({ + buf: buf, + len: buf.length, + opcodenum: buf.length, + }); + i = i + 1; + } else if ( + opcodenum === Opcode.OP_PUSHDATA1 || + opcodenum === Opcode.OP_PUSHDATA2 || + opcodenum === Opcode.OP_PUSHDATA4 + ) { + script.chunks.push({ + buf: new Buffer(tokens[i + 2], 'hex'), + len: parseInt(tokens[i + 1]), + opcodenum: opcodenum, + }); + i = i + 3; + } else { + script.chunks.push({ + opcodenum: opcodenum, + }); + i = i + 1; + } + } + return script; + }; + + Script.fromHex = function(str) { + return new Script(new buffer.Buffer(str, 'hex')); + }; + + Script.fromString = function(str) { + if (JSUtil.isHexa(str) || str.length === 0) { + return new Script(new buffer.Buffer(str, 'hex')); + } + var script = new Script(); + script.chunks = []; + + var tokens = str.split(' '); + var i = 0; + while (i < tokens.length) { + var token = tokens[i]; + var opcode = Opcode(token); + var opcodenum = opcode.toNumber(); + + if (_.isUndefined(opcodenum)) { + opcodenum = parseInt(token); + if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) { + script.chunks.push({ + buf: new Buffer(tokens[i + 1].slice(2), 'hex'), + len: opcodenum, + opcodenum: opcodenum, + }); + i = i + 2; + } else { + throw new Error('Invalid script: ' + JSON.stringify(str)); + } + } else if ( + opcodenum === Opcode.OP_PUSHDATA1 || + opcodenum === Opcode.OP_PUSHDATA2 || + opcodenum === Opcode.OP_PUSHDATA4 + ) { + if (tokens[i + 2].slice(0, 2) !== '0x') { + throw new Error('Pushdata data must start with 0x'); + } + script.chunks.push({ + buf: new Buffer(tokens[i + 2].slice(2), 'hex'), + len: parseInt(tokens[i + 1]), + opcodenum: opcodenum, + }); + i = i + 3; + } else { + script.chunks.push({ + opcodenum: opcodenum, + }); + i = i + 1; + } + } + return script; + }; + + Script.prototype._chunkToString = function(chunk, type) { + var opcodenum = chunk.opcodenum; + var asm = type === 'asm'; + var str = ''; + if (!chunk.buf) { + // no data chunk + if (typeof Opcode.reverseMap[opcodenum] !== 'undefined') { + str = str + ' ' + Opcode(opcodenum).toString(); + } else { + var numstr = opcodenum.toString(16); + if (numstr.length % 2 !== 0) { + numstr = '0' + numstr; + } + if (asm) { + str = str + ' ' + numstr; + } else { + str = str + ' ' + '0x' + numstr; + } + } + } else { + // data chunk + if ( + opcodenum === Opcode.OP_PUSHDATA1 || + opcodenum === Opcode.OP_PUSHDATA2 || + opcodenum === Opcode.OP_PUSHDATA4 + ) { + str = str + ' ' + Opcode(opcodenum).toString(); + } + if (chunk.len > 0) { + if (asm) { + str = str + ' ' + chunk.buf.toString('hex'); + } else { + str = str + ' ' + chunk.len + ' ' + '0x' + chunk.buf.toString('hex'); + } + } + } + return str; + }; + + Script.prototype.toASM = function() { + var str = ''; + for (var i = 0; i < this.chunks.length; i++) { + var chunk = this.chunks[i]; + str += this._chunkToString(chunk, 'asm'); + } + + return str.substr(1); + }; + + Script.prototype.toString = function() { + var str = ''; + for (var i = 0; i < this.chunks.length; i++) { + var chunk = this.chunks[i]; + str += this._chunkToString(chunk); + } + + return str.substr(1); + }; + + Script.prototype.toHex = function() { + return this.toBuffer().toString('hex'); + }; + + Script.prototype.inspect = function() { + return ''; + }; + + // script classification methods + + /** + * @returns {boolean} if this is a pay to pubkey hash output script + */ + Script.prototype.isPublicKeyHashOut = function() { + return !!( + this.chunks.length === 5 && + this.chunks[0].opcodenum === Opcode.OP_DUP && + this.chunks[1].opcodenum === Opcode.OP_HASH160 && + this.chunks[2].buf && + this.chunks[2].buf.length === 20 && + this.chunks[3].opcodenum === Opcode.OP_EQUALVERIFY && + this.chunks[4].opcodenum === Opcode.OP_CHECKSIG + ); + }; + + /** + * @returns {boolean} if this is a pay to public key hash input script + */ + Script.prototype.isPublicKeyHashIn = function() { + if (this.chunks.length === 2) { + var signatureBuf = this.chunks[0].buf; + var pubkeyBuf = this.chunks[1].buf; + if (signatureBuf && signatureBuf.length && signatureBuf[0] === 0x30 && pubkeyBuf && pubkeyBuf.length) { + var version = pubkeyBuf[0]; + if ((version === 0x04 || version === 0x06 || version === 0x07) && pubkeyBuf.length === 65) { + return true; + } else if ((version === 0x03 || version === 0x02) && pubkeyBuf.length === 33) { + return true; + } + } + } + return false; + }; + + Script.prototype.getPublicKey = function() { + $.checkState(this.isPublicKeyOut(), "Can't retrieve PublicKey from a non-PK output"); + return this.chunks[0].buf; + }; + + Script.prototype.getPublicKeyHash = function() { + $.checkState(this.isPublicKeyHashOut(), "Can't retrieve PublicKeyHash from a non-PKH output"); + return this.chunks[2].buf; + }; + + /** + * @returns {boolean} if this is a public key output script + */ + Script.prototype.isPublicKeyOut = function() { + if ( + this.chunks.length === 2 && + this.chunks[0].buf && + this.chunks[0].buf.length && + this.chunks[1].opcodenum === Opcode.OP_CHECKSIG + ) { + var pubkeyBuf = this.chunks[0].buf; + var version = pubkeyBuf[0]; + var isVersion = false; + if ((version === 0x04 || version === 0x06 || version === 0x07) && pubkeyBuf.length === 65) { + isVersion = true; + } else if ((version === 0x03 || version === 0x02) && pubkeyBuf.length === 33) { + isVersion = true; + } + if (isVersion) { + return PublicKey.isValid(pubkeyBuf); + } + } + return false; + }; + + /** + * @returns {boolean} if this is a pay to public key input script + */ + Script.prototype.isPublicKeyIn = function() { + if (this.chunks.length === 1) { + var signatureBuf = this.chunks[0].buf; + if (signatureBuf && signatureBuf.length && signatureBuf[0] === 0x30) { + return true; + } + } + return false; + }; + + /** + * @returns {boolean} if this is a p2sh output script + */ + Script.prototype.isScriptHashOut = function() { + var buf = this.toBuffer(); + return ( + buf.length === 23 && + buf[0] === Opcode.OP_HASH160 && + buf[1] === 0x14 && + buf[buf.length - 1] === Opcode.OP_EQUAL + ); + }; + + /** + * @returns {boolean} if this is a p2sh input script + * Note that these are frequently indistinguishable from pubkeyhashin + */ + Script.prototype.isScriptHashIn = function() { + if (this.chunks.length <= 1) { + return false; + } + var redeemChunk = this.chunks[this.chunks.length - 1]; + var redeemBuf = redeemChunk.buf; + if (!redeemBuf) { + return false; + } + + var redeemScript; + try { + redeemScript = Script.fromBuffer(redeemBuf); + } catch (e) { + if (e instanceof errors.Script.InvalidBuffer) { + return false; + } + throw e; + } + var type = redeemScript.classify(); + return type !== Script.types.UNKNOWN; + }; + + /** + * @returns {boolean} if this is a mutlsig output script + */ + Script.prototype.isMultisigOut = function() { + return ( + this.chunks.length > 3 && + Opcode.isSmallIntOp(this.chunks[0].opcodenum) && + this.chunks.slice(1, this.chunks.length - 2).every(function(obj) { + return obj.buf && BufferUtil.isBuffer(obj.buf); + }) && + Opcode.isSmallIntOp(this.chunks[this.chunks.length - 2].opcodenum) && + this.chunks[this.chunks.length - 1].opcodenum === Opcode.OP_CHECKMULTISIG + ); + }; + + /** + * @returns {boolean} if this is a multisig input script + */ + Script.prototype.isMultisigIn = function() { + return ( + this.chunks.length >= 2 && + this.chunks[0].opcodenum === 0 && + this.chunks.slice(1, this.chunks.length).every(function(obj) { + return obj.buf && BufferUtil.isBuffer(obj.buf) && Signature.isTxDER(obj.buf); + }) + ); + }; + + /** + * @returns {boolean} true if this is a valid standard OP_RETURN output + */ + Script.prototype.isDataOut = function() { + return ( + this.chunks.length >= 1 && + this.chunks[0].opcodenum === Opcode.OP_RETURN && + (this.chunks.length === 1 || + (this.chunks.length === 2 && + this.chunks[1].buf && + this.chunks[1].buf.length <= Script.OP_RETURN_STANDARD_SIZE && + this.chunks[1].length === this.chunks.len)) + ); + }; + + /** + * Retrieve the associated data for this script. + * In the case of a pay to public key hash or P2SH, return the hash. + * In the case of a standard OP_RETURN, return the data + * @returns {Buffer} + */ + Script.prototype.getData = function() { + if (this.isDataOut() || this.isScriptHashOut()) { + if (_.isUndefined(this.chunks[1])) { + return new Buffer(0); + } else { + return new Buffer(this.chunks[1].buf); + } + } + if (this.isPublicKeyHashOut()) { + return new Buffer(this.chunks[2].buf); + } + throw new Error('Unrecognized script type to get data from'); + }; + + /** + * @returns {boolean} if the script is only composed of data pushing + * opcodes or small int opcodes (OP_0, OP_1, ..., OP_16) + */ + Script.prototype.isPushOnly = function() { + return _.every(this.chunks, function(chunk) { + return chunk.opcodenum <= Opcode.OP_16; + }); + }; + + Script.types = {}; + Script.types.UNKNOWN = 'Unknown'; + Script.types.PUBKEY_OUT = 'Pay to public key'; + Script.types.PUBKEY_IN = 'Spend from public key'; + Script.types.PUBKEYHASH_OUT = 'Pay to public key hash'; + Script.types.PUBKEYHASH_IN = 'Spend from public key hash'; + Script.types.SCRIPTHASH_OUT = 'Pay to script hash'; + Script.types.PARAMETERIZED_SCRIPTHASH_OUT = 'Parameterized Pay to script hash'; + Script.types.SCRIPTHASH_IN = 'Spend from script hash'; + Script.types.MULTISIG_OUT = 'Pay to multisig'; + Script.types.MULTISIG_IN = 'Spend from multisig'; + Script.types.DATA_OUT = 'Data push'; + + Script.OP_RETURN_STANDARD_SIZE = 80; + + /** + * @returns {object} The Script type if it is a known form, + * or Script.UNKNOWN if it isn't + */ + Script.prototype.classify = function() { + if (this._isInput) { + return this.classifyInput(); + } else if (this._isOutput) { + return this.classifyOutput(); + } else { + var outputType = this.classifyOutput(); + return outputType != Script.types.UNKNOWN ? outputType : this.classifyInput(); + } + }; + + Script.outputIdentifiers = {}; + Script.outputIdentifiers.PUBKEY_OUT = Script.prototype.isPublicKeyOut; + Script.outputIdentifiers.PUBKEYHASH_OUT = Script.prototype.isPublicKeyHashOut; + Script.outputIdentifiers.MULTISIG_OUT = Script.prototype.isMultisigOut; + Script.outputIdentifiers.SCRIPTHASH_OUT = Script.prototype.isScriptHashOut; + Script.outputIdentifiers.DATA_OUT = Script.prototype.isDataOut; + + /** + * @returns {object} The Script type if it is a known form, + * or Script.UNKNOWN if it isn't + */ + Script.prototype.classifyOutput = function() { + for (var type in Script.outputIdentifiers) { + if (Script.outputIdentifiers[type].bind(this)()) { + return Script.types[type]; + } + } + return Script.types.UNKNOWN; + }; + + Script.inputIdentifiers = {}; + Script.inputIdentifiers.PUBKEY_IN = Script.prototype.isPublicKeyIn; + Script.inputIdentifiers.PUBKEYHASH_IN = Script.prototype.isPublicKeyHashIn; + Script.inputIdentifiers.MULTISIG_IN = Script.prototype.isMultisigIn; + Script.inputIdentifiers.SCRIPTHASH_IN = Script.prototype.isScriptHashIn; + + /** + * @returns {object} The Script type if it is a known form, + * or Script.UNKNOWN if it isn't + */ + Script.prototype.classifyInput = function() { + for (var type in Script.inputIdentifiers) { + if (Script.inputIdentifiers[type].bind(this)()) { + return Script.types[type]; + } + } + return Script.types.UNKNOWN; + }; + + /** + * @returns {boolean} if script is one of the known types + */ + Script.prototype.isStandard = function() { + // TODO: Add BIP62 compliance + return this.classify() !== Script.types.UNKNOWN; + }; + + // Script construction methods + + /** + * Adds a script element at the start of the script. + * @param {*} obj a string, number, Opcode, Buffer, or object to add + * @returns {Script} this script instance + */ + Script.prototype.prepend = function(obj) { + this._addByType(obj, true); + return this; + }; + + /** + * Compares a script with another script + */ + Script.prototype.equals = function(script) { + $.checkState(script instanceof Script, 'Must provide another script'); + if (this.chunks.length !== script.chunks.length) { + return false; + } + var i; + for (i = 0; i < this.chunks.length; i++) { + if (BufferUtil.isBuffer(this.chunks[i].buf) && !BufferUtil.isBuffer(script.chunks[i].buf)) { + return false; + } + if ( + BufferUtil.isBuffer(this.chunks[i].buf) && + !BufferUtil.equals(this.chunks[i].buf, script.chunks[i].buf) + ) { + return false; + } else if (this.chunks[i].opcodenum !== script.chunks[i].opcodenum) { + return false; + } + } + return true; + }; + + /** + * Adds a script element to the end of the script. + * + * @param {*} obj a string, number, Opcode, Buffer, or object to add + * @returns {Script} this script instance + * + */ + Script.prototype.add = function(obj) { + this._addByType(obj, false); + return this; + }; + + Script.prototype._addByType = function(obj, prepend) { + if (typeof obj === 'string') { + this._addOpcode(obj, prepend); + } else if (typeof obj === 'number') { + this._addOpcode(obj, prepend); + } else if (obj instanceof Opcode) { + this._addOpcode(obj, prepend); + } else if (BufferUtil.isBuffer(obj)) { + this._addBuffer(obj, prepend); + } else if (obj instanceof Script) { + this.chunks = this.chunks.concat(obj.chunks); + } else if (typeof obj === 'object') { + this._insertAtPosition(obj, prepend); + } else { + throw new Error('Invalid script chunk'); + } + }; + + Script.prototype._insertAtPosition = function(op, prepend) { + if (prepend) { + this.chunks.unshift(op); + } else { + this.chunks.push(op); + } + }; + + Script.prototype._addOpcode = function(opcode, prepend) { + var op; + if (typeof opcode === 'number') { + op = opcode; + } else if (opcode instanceof Opcode) { + op = opcode.toNumber(); + } else { + op = Opcode(opcode).toNumber(); + } + this._insertAtPosition( + { + opcodenum: op, + }, + prepend, + ); + return this; + }; + + Script.prototype._addBuffer = function(buf, prepend) { + var opcodenum; + var len = buf.length; + if (len >= 0 && len < Opcode.OP_PUSHDATA1) { + opcodenum = len; + } else if (len < Math.pow(2, 8)) { + opcodenum = Opcode.OP_PUSHDATA1; + } else if (len < Math.pow(2, 16)) { + opcodenum = Opcode.OP_PUSHDATA2; + } else if (len < Math.pow(2, 32)) { + opcodenum = Opcode.OP_PUSHDATA4; + } else { + throw new Error("You can't push that much data"); + } + this._insertAtPosition( + { + buf: buf, + len: len, + opcodenum: opcodenum, + }, + prepend, + ); + return this; + }; + + Script.prototype.removeCodeseparators = function() { + var chunks = []; + for (var i = 0; i < this.chunks.length; i++) { + if (this.chunks[i].opcodenum !== Opcode.OP_CODESEPARATOR) { + chunks.push(this.chunks[i]); + } + } + this.chunks = chunks; + return this; + }; + + // high level script builder methods + + /** + * @returns {Script} a new Multisig output script for given public keys, + * requiring m of those public keys to spend + * @param {PublicKey[]} publicKeys - list of all public keys controlling the output + * @param {number} threshold - amount of required signatures to spend the output + * @param {Object=} opts - Several options: + * - noSorting: defaults to false, if true, don't sort the given + * public keys before creating the script + */ + Script.buildMultisigOut = function(publicKeys, threshold, opts) { + $.checkArgument( + threshold <= publicKeys.length, + 'Number of required signatures must be less than or equal to the number of public keys', + ); + opts = opts || {}; + var script = new Script(); + script.add(Opcode.smallInt(threshold)); + publicKeys = _.map(publicKeys, PublicKey); + var sorted = publicKeys; + if (!opts.noSorting) { + sorted = _.sortBy(publicKeys, function(publicKey) { + return publicKey.toString('hex'); + }); + } + for (var i = 0; i < sorted.length; i++) { + var publicKey = sorted[i]; + script.add(publicKey.toBuffer()); + } + script.add(Opcode.smallInt(publicKeys.length)); + script.add(Opcode.OP_CHECKMULTISIG); + return script; + }; + + /** + * A new Multisig input script for the given public keys, requiring m of those public keys to spend + * + * @param {PublicKey[]} pubkeys list of all public keys controlling the output + * @param {number} threshold amount of required signatures to spend the output + * @param {Array} signatures and array of signature buffers to append to the script + * @param {Object=} opts + * @param {boolean=} opts.noSorting don't sort the given public keys before creating the script (false by default) + * @param {Script=} opts.cachedMultisig don't recalculate the redeemScript + * + * @returns {Script} + */ + Script.buildMultisigIn = function(pubkeys, threshold, signatures, opts) { + $.checkArgument(_.isArray(pubkeys)); + $.checkArgument(_.isNumber(threshold)); + $.checkArgument(_.isArray(signatures)); + opts = opts || {}; + var s = new Script(); + s.add(Opcode.OP_0); + _.each(signatures, function(signature) { + $.checkArgument(BufferUtil.isBuffer(signature), 'Signatures must be an array of Buffers'); + // TODO: allow signatures to be an array of Signature objects + s.add(signature); + }); + return s; + }; + + /** + * A new P2SH Multisig input script for the given public keys, requiring m of those public keys to spend + * + * @param {PublicKey[]} pubkeys list of all public keys controlling the output + * @param {number} threshold amount of required signatures to spend the output + * @param {Array} signatures and array of signature buffers to append to the script + * @param {Object=} opts + * @param {boolean=} opts.noSorting don't sort the given public keys before creating the script (false by default) + * @param {Script=} opts.cachedMultisig don't recalculate the redeemScript + * + * @returns {Script} + */ + Script.buildP2SHMultisigIn = function(pubkeys, threshold, signatures, opts) { + $.checkArgument(_.isArray(pubkeys)); + $.checkArgument(_.isNumber(threshold)); + $.checkArgument(_.isArray(signatures)); + opts = opts || {}; + var s = new Script(); + s.add(Opcode.OP_0); + _.each(signatures, function(signature) { + $.checkArgument(BufferUtil.isBuffer(signature), 'Signatures must be an array of Buffers'); + // TODO: allow signatures to be an array of Signature objects + s.add(signature); + }); + s.add((opts.cachedMultisig || Script.buildMultisigOut(pubkeys, threshold, opts)).toBuffer()); + return s; + }; + + /** + * @returns {Script} a new pay to public key hash output for the given + * address or public key + * @param {(Address|PublicKey)} to - destination address or public key + */ + Script.buildPublicKeyHashOut = function(to) { + $.checkArgument(!_.isUndefined(to)); + $.checkArgument(to instanceof PublicKey || to instanceof Address || _.isString(to)); + if (to instanceof PublicKey) { + to = to.toAddress(); + } else if (_.isString(to)) { + to = new Address(to); + } + var s = new Script(); + s.add(Opcode.OP_DUP) + .add(Opcode.OP_HASH160) + .add(to.hashBuffer) + .add(Opcode.OP_EQUALVERIFY) + .add(Opcode.OP_CHECKSIG); + s._network = to.network; + return s; + }; + + /** + * @returns {Script} a new pay to public key output for the given + * public key + */ + Script.buildPublicKeyOut = function(pubkey) { + $.checkArgument(pubkey instanceof PublicKey); + var s = new Script(); + s.add(pubkey.toBuffer()).add(Opcode.OP_CHECKSIG); + return s; + }; + + /** + * @returns {Script} a new OP_RETURN script with data + * @param {(string|Buffer)} data - the data to embed in the output + * @param {(string)} encoding - the type of encoding of the string + */ + Script.buildDataOut = function(data, encoding) { + $.checkArgument(_.isUndefined(data) || _.isString(data) || BufferUtil.isBuffer(data)); + if (_.isString(data)) { + data = new Buffer(data, encoding); + } + var s = new Script(); + s.add(Opcode.OP_RETURN); + if (!_.isUndefined(data)) { + s.add(data); + } + return s; + }; + + /** + * @param {Script|Address} script - the redeemScript for the new p2sh output. + * It can also be a p2sh address + * @returns {Script} new pay to script hash script for given script + */ + Script.buildScriptHashOut = function(script) { + $.checkArgument(script instanceof Script || (script instanceof Address && script.isPayToScriptHash())); + var s = new Script(); + s.add(Opcode.OP_HASH160) + .add(script instanceof Address ? script.hashBuffer : Hash.sha256ripemd160(script.toBuffer())) + .add(Opcode.OP_EQUAL); + + s._network = script._network || script.network; + return s; + }; + + /** + * Builds a scriptSig (a script for an input) that signs a public key output script. + * + * @param {Signature|Buffer} signature - a Signature object, or the signature in DER canonical encoding + * @param {number=} sigtype - the type of the signature (defaults to SIGHASH_ALL) + */ + Script.buildPublicKeyIn = function(signature, sigtype) { + $.checkArgument(signature instanceof Signature || BufferUtil.isBuffer(signature)); + $.checkArgument(_.isUndefined(sigtype) || _.isNumber(sigtype)); + if (signature instanceof Signature) { + signature = signature.toBuffer(); + } + var script = new Script(); + script.add( + BufferUtil.concat([signature, BufferUtil.integerAsSingleByteBuffer(sigtype || Signature.SIGHASH_ALL)]), + ); + return script; + }; + + /** + * Builds a scriptSig (a script for an input) that signs a public key hash + * output script. + * + * @param {Buffer|string|PublicKey} publicKey + * @param {Signature|Buffer} signature - a Signature object, or the signature in DER canonical encoding + * @param {number=} sigtype - the type of the signature (defaults to SIGHASH_ALL) + */ + Script.buildPublicKeyHashIn = function(publicKey, signature, sigtype) { + $.checkArgument(signature instanceof Signature || BufferUtil.isBuffer(signature)); + $.checkArgument(_.isUndefined(sigtype) || _.isNumber(sigtype)); + if (signature instanceof Signature) { + signature = signature.toBuffer(); + } + var script = new Script() + .add( + BufferUtil.concat([signature, BufferUtil.integerAsSingleByteBuffer(sigtype || Signature.SIGHASH_ALL)]), + ) + .add(new PublicKey(publicKey).toBuffer()); + return script; + }; + + /** + * @returns {Script} an empty script + */ + Script.empty = function() { + return new Script(); + }; + + /** + * @returns {Script} a new pay to script hash script that pays to this script + */ + Script.prototype.toScriptHashOut = function() { + return Script.buildScriptHashOut(this); + }; + + /** + * @return {Script} an output script built from the address + */ + Script.fromAddress = function(address) { + address = Address(address); + if (address.isPayToScriptHash()) { + return Script.buildScriptHashOut(address); + } else if (address.isPayToPublicKeyHash()) { + return Script.buildPublicKeyHashOut(address); + } + throw new errors.Script.UnrecognizedAddress(address); + }; + + /** + * Will return the associated address information object + * @return {Address|boolean} + */ + Script.prototype.getAddressInfo = function(opts) { + if (this._isInput) { + return this._getInputAddressInfo(); + } else if (this._isOutput) { + return this._getOutputAddressInfo(); + } else { + var info = this._getOutputAddressInfo(); + if (!info) { + return this._getInputAddressInfo(); + } + return info; + } + }; + + /** + * Will return the associated output scriptPubKey address information object + * @return {Address|boolean} + * @private + */ + Script.prototype._getOutputAddressInfo = function() { + var info = {}; + if (this.isScriptHashOut()) { + info.hashBuffer = this.getData(); + info.type = Address.PayToScriptHash; + } else if (this.isPublicKeyHashOut()) { + info.hashBuffer = this.getData(); + info.type = Address.PayToPublicKeyHash; + } else { + return false; + } + return info; + }; + + /** + * Will return the associated input scriptSig address information object + * @return {Address|boolean} + * @private + */ + Script.prototype._getInputAddressInfo = function() { + var info = {}; + if (this.isPublicKeyHashIn()) { + // hash the publickey found in the scriptSig + info.hashBuffer = Hash.sha256ripemd160(this.chunks[1].buf); + info.type = Address.PayToPublicKeyHash; + } else if (this.isScriptHashIn()) { + // hash the redeemscript found at the end of the scriptSig + info.hashBuffer = Hash.sha256ripemd160(this.chunks[this.chunks.length - 1].buf); + info.type = Address.PayToScriptHash; + } else { + return false; + } + return info; + }; + + /** + * @param {Network=} network + * @return {Address|boolean} the associated address for this script if possible, or false + */ + Script.prototype.toAddress = function(network) { + var info = this.getAddressInfo(); + if (!info) { + return false; + } + info.network = Networks.get(network) || this._network || Networks.defaultNetwork; + return new Address(info); + }; + + /** + * Analogous to bitcoind's FindAndDelete. Find and delete equivalent chunks, + * typically used with push data chunks. Note that this will find and delete + * not just the same data, but the same data with the same push data op as + * produced by default. i.e., if a pushdata in a tx does not use the minimal + * pushdata op, then when you try to remove the data it is pushing, it will not + * be removed, because they do not use the same pushdata op. + */ + Script.prototype.findAndDelete = function(script) { + var buf = script.toBuffer(); + var hex = buf.toString('hex'); + for (var i = 0; i < this.chunks.length; i++) { + var script2 = Script({ + chunks: [this.chunks[i]], + }); + var buf2 = script2.toBuffer(); + var hex2 = buf2.toString('hex'); + if (hex === hex2) { + this.chunks.splice(i, 1); + } + } + return this; + }; + + /** + * Comes from bitcoind's script interpreter CheckMinimalPush function + * @returns {boolean} if the chunk {i} is the smallest way to push that particular data. + */ + Script.prototype.checkMinimalPush = function(i) { + var chunk = this.chunks[i]; + var buf = chunk.buf; + var opcodenum = chunk.opcodenum; + if (!buf) { + return true; + } + if (buf.length === 0) { + // Could have used OP_0. + return opcodenum === Opcode.OP_0; + } else if (buf.length === 1 && buf[0] >= 1 && buf[0] <= 16) { + // Could have used OP_1 .. OP_16. + return opcodenum === Opcode.OP_1 + (buf[0] - 1); + } else if (buf.length === 1 && buf[0] === 0x81) { + // Could have used OP_1NEGATE + return opcodenum === Opcode.OP_1NEGATE; + } else if (buf.length <= 75) { + // Could have used a direct push (opcode indicating number of bytes pushed + those bytes). + return opcodenum === buf.length; + } else if (buf.length <= 255) { + // Could have used OP_PUSHDATA. + return opcodenum === Opcode.OP_PUSHDATA1; + } else if (buf.length <= 65535) { + // Could have used OP_PUSHDATA2. + return opcodenum === Opcode.OP_PUSHDATA2; + } + return true; + }; + + /** + * Comes from bitcoind's script DecodeOP_N function + * @param {number} opcode + * @returns {number} numeric value in range of 0 to 16 + */ + Script.prototype._decodeOP_N = function(opcode) { + if (opcode === Opcode.OP_0) { + return 0; + } else if (opcode >= Opcode.OP_1 && opcode <= Opcode.OP_16) { + return opcode - (Opcode.OP_1 - 1); + } else { + throw new Error('Invalid opcode: ' + JSON.stringify(opcode)); + } + }; + + /** + * Comes from bitcoind's script GetSigOpCount(boolean) function + * @param {boolean} use current (true) or pre-version-0.6 (false) logic + * @returns {number} number of signature operations required by this script + */ + Script.prototype.getSignatureOperationsCount = function(accurate) { + accurate = _.isUndefined(accurate) ? true : accurate; + var self = this; + var n = 0; + var lastOpcode = Opcode.OP_INVALIDOPCODE; + _.each(self.chunks, function getChunk(chunk) { + var opcode = chunk.opcodenum; + if (opcode == Opcode.OP_CHECKSIG || opcode == Opcode.OP_CHECKSIGVERIFY) { + n++; + } else if (opcode == Opcode.OP_CHECKMULTISIG || opcode == Opcode.OP_CHECKMULTISIGVERIFY) { + if (accurate && lastOpcode >= Opcode.OP_1 && lastOpcode <= Opcode.OP_16) { + n += self._decodeOP_N(lastOpcode); + } else { + n += 20; + } + } + lastOpcode = opcode; + }); + return n; + }; + + module.exports = Script; + }.call(this, require('buffer').Buffer)); + }, + { + '../address': 1, + '../crypto/hash': 8, + '../crypto/signature': 11, + '../encoding/bufferreader': 14, + '../encoding/bufferwriter': 15, + '../errors': 17, + '../networks': 21, + '../opcode': 22, + '../publickey': 24, + '../util/buffer': 42, + '../util/js': 43, + '../util/preconditions': 44, + buffer: 113, + lodash: 187, + }, + ], + 28: [ + function(require, module, exports) { + module.exports = require('./transaction'); + + module.exports.Input = require('./input'); + module.exports.Output = require('./output'); + module.exports.UnspentOutput = require('./unspentoutput'); + module.exports.Signature = require('./signature'); + module.exports.Sighash = require('./sighash'); + }, + { './input': 29, './output': 35, './sighash': 36, './signature': 37, './transaction': 38, './unspentoutput': 39 }, + ], + 29: [ + function(require, module, exports) { + module.exports = require('./input'); + + module.exports.PublicKey = require('./publickey'); + module.exports.PublicKeyHash = require('./publickeyhash'); + module.exports.MultiSig = require('./multisig.js'); + module.exports.MultiSigScriptHash = require('./multisigscripthash.js'); + }, + { './input': 30, './multisig.js': 31, './multisigscripthash.js': 32, './publickey': 33, './publickeyhash': 34 }, + ], + 30: [ + function(require, module, exports) { + 'use strict'; + + var _ = require('lodash'); + var $ = require('../../util/preconditions'); + var errors = require('../../errors'); + var BufferWriter = require('../../encoding/bufferwriter'); + var buffer = require('buffer'); + var BufferUtil = require('../../util/buffer'); + var JSUtil = require('../../util/js'); + var Script = require('../../script'); + var Sighash = require('../sighash'); + var Output = require('../output'); + + var MAXINT = 0xffffffff; // Math.pow(2, 32) - 1; + var DEFAULT_RBF_SEQNUMBER = MAXINT - 2; + var DEFAULT_SEQNUMBER = MAXINT; + var DEFAULT_LOCKTIME_SEQNUMBER = MAXINT - 1; + + function Input(params) { + if (!(this instanceof Input)) { + return new Input(params); + } + if (params) { + return this._fromObject(params); + } + } + + Input.MAXINT = MAXINT; + Input.DEFAULT_SEQNUMBER = DEFAULT_SEQNUMBER; + Input.DEFAULT_LOCKTIME_SEQNUMBER = DEFAULT_LOCKTIME_SEQNUMBER; + Input.DEFAULT_RBF_SEQNUMBER = DEFAULT_RBF_SEQNUMBER; + + Object.defineProperty(Input.prototype, 'script', { + configurable: false, + enumerable: true, + get: function() { + if (this.isNull()) { + return null; + } + if (!this._script) { + this._script = new Script(this._scriptBuffer); + this._script._isInput = true; + } + return this._script; + }, + }); + + Input.fromObject = function(obj) { + $.checkArgument(_.isObject(obj)); + var input = new Input(); + return input._fromObject(obj); + }; + + Input.prototype._fromObject = function(params) { + var prevTxId; + if (_.isString(params.prevTxId) && JSUtil.isHexa(params.prevTxId)) { + prevTxId = new buffer.Buffer(params.prevTxId, 'hex'); + } else { + prevTxId = params.prevTxId; + } + this.output = params.output + ? params.output instanceof Output + ? params.output + : new Output(params.output) + : undefined; + this.prevTxId = prevTxId || params.txidbuf; + this.outputIndex = _.isUndefined(params.outputIndex) ? params.txoutnum : params.outputIndex; + this.sequenceNumber = _.isUndefined(params.sequenceNumber) + ? _.isUndefined(params.seqnum) + ? DEFAULT_SEQNUMBER + : params.seqnum + : params.sequenceNumber; + if (_.isUndefined(params.script) && _.isUndefined(params.scriptBuffer)) { + throw new errors.Transaction.Input.MissingScript(); + } + this.setScript(params.scriptBuffer || params.script); + return this; + }; + + Input.prototype.toObject = Input.prototype.toJSON = function toObject() { + var obj = { + prevTxId: this.prevTxId.toString('hex'), + outputIndex: this.outputIndex, + sequenceNumber: this.sequenceNumber, + script: this._scriptBuffer.toString('hex'), + }; + // add human readable form if input contains valid script + if (this.script) { + obj.scriptString = this.script.toString(); + } + if (this.output) { + obj.output = this.output.toObject(); + } + return obj; + }; + + Input.fromBufferReader = function(br) { + var input = new Input(); + input.prevTxId = br.readReverse(32); + input.outputIndex = br.readUInt32LE(); + input._scriptBuffer = br.readVarLengthBuffer(); + input.sequenceNumber = br.readUInt32LE(); + // TODO: return different classes according to which input it is + // e.g: CoinbaseInput, PublicKeyHashInput, MultiSigScriptHashInput, etc. + return input; + }; + + Input.prototype.toBufferWriter = function(writer) { + if (!writer) { + writer = new BufferWriter(); + } + writer.writeReverse(this.prevTxId); + writer.writeUInt32LE(this.outputIndex); + var script = this._scriptBuffer; + writer.writeVarintNum(script.length); + writer.write(script); + writer.writeUInt32LE(this.sequenceNumber); + return writer; + }; + + Input.prototype.setScript = function(script) { + this._script = null; + if (script instanceof Script) { + this._script = script; + this._script._isInput = true; + this._scriptBuffer = script.toBuffer(); + } else if (JSUtil.isHexa(script)) { + // hex string script + this._scriptBuffer = new buffer.Buffer(script, 'hex'); + } else if (_.isString(script)) { + // human readable string script + this._script = new Script(script); + this._script._isInput = true; + this._scriptBuffer = this._script.toBuffer(); + } else if (BufferUtil.isBuffer(script)) { + // buffer script + this._scriptBuffer = new buffer.Buffer(script); + } else { + throw new TypeError('Invalid argument type: script'); + } + return this; + }; + + /** + * Retrieve signatures for the provided PrivateKey. + * + * @param {Transaction} transaction - the transaction to be signed + * @param {PrivateKey} privateKey - the private key to use when signing + * @param {number} inputIndex - the index of this input in the provided transaction + * @param {number} sigType - defaults to Signature.SIGHASH_ALL + * @param {Buffer} addressHash - if provided, don't calculate the hash of the + * public key associated with the private key provided + * @abstract + */ + Input.prototype.getSignatures = function() { + throw new errors.AbstractMethodInvoked( + 'Trying to sign unsupported output type (only P2PKH and P2SH multisig inputs are supported)' + + ' for input: ' + + JSON.stringify(this), + ); + }; + + Input.prototype.isFullySigned = function() { + throw new errors.AbstractMethodInvoked('Input#isFullySigned'); + }; + + Input.prototype.isFinal = function() { + return this.sequenceNumber !== 4294967295; + }; + + Input.prototype.addSignature = function() { + throw new errors.AbstractMethodInvoked('Input#addSignature'); + }; + + Input.prototype.clearSignatures = function() { + throw new errors.AbstractMethodInvoked('Input#clearSignatures'); + }; + + Input.prototype.isValidSignature = function(transaction, signature) { + // FIXME: Refactor signature so this is not necessary + signature.signature.nhashtype = signature.sigtype; + return Sighash.verify( + transaction, + signature.signature, + signature.publicKey, + signature.inputIndex, + this.output.script, + ); + }; + + /** + * @returns true if this is a coinbase input (represents no input) + */ + Input.prototype.isNull = function() { + return ( + this.prevTxId.toString('hex') === '0000000000000000000000000000000000000000000000000000000000000000' && + this.outputIndex === 0xffffffff + ); + }; + + Input.prototype._estimateSize = function() { + return this.toBufferWriter().toBuffer().length; + }; + + module.exports = Input; + }, + { + '../../encoding/bufferwriter': 15, + '../../errors': 17, + '../../script': 25, + '../../util/buffer': 42, + '../../util/js': 43, + '../../util/preconditions': 44, + '../output': 35, + '../sighash': 36, + buffer: 113, + lodash: 187, + }, + ], + 31: [ + function(require, module, exports) { + 'use strict'; + + var _ = require('lodash'); + var inherits = require('inherits'); + var Transaction = require('../transaction'); + var Input = require('./input'); + var Output = require('../output'); + var $ = require('../../util/preconditions'); + + var Script = require('../../script'); + var Signature = require('../../crypto/signature'); + var Sighash = require('../sighash'); + var PublicKey = require('../../publickey'); + var BufferUtil = require('../../util/buffer'); + var TransactionSignature = require('../signature'); + + /** + * @constructor + */ + function MultiSigInput(input, pubkeys, threshold, signatures) { + Input.apply(this, arguments); + var self = this; + pubkeys = pubkeys || input.publicKeys; + threshold = threshold || input.threshold; + signatures = signatures || input.signatures; + this.publicKeys = _.sortBy(pubkeys, function(publicKey) { + return publicKey.toString('hex'); + }); + $.checkState( + Script.buildMultisigOut(this.publicKeys, threshold).equals(this.output.script), + "Provided public keys don't match to the provided output script", + ); + this.publicKeyIndex = {}; + _.each(this.publicKeys, function(publicKey, index) { + self.publicKeyIndex[publicKey.toString()] = index; + }); + this.threshold = threshold; + // Empty array of signatures + this.signatures = signatures ? this._deserializeSignatures(signatures) : new Array(this.publicKeys.length); + } + inherits(MultiSigInput, Input); + + MultiSigInput.prototype.toObject = function() { + var obj = Input.prototype.toObject.apply(this, arguments); + obj.threshold = this.threshold; + obj.publicKeys = _.map(this.publicKeys, function(publicKey) { + return publicKey.toString(); + }); + obj.signatures = this._serializeSignatures(); + return obj; + }; + + MultiSigInput.prototype._deserializeSignatures = function(signatures) { + return _.map(signatures, function(signature) { + if (!signature) { + return undefined; + } + return new TransactionSignature(signature); + }); + }; + + MultiSigInput.prototype._serializeSignatures = function() { + return _.map(this.signatures, function(signature) { + if (!signature) { + return undefined; + } + return signature.toObject(); + }); + }; + + MultiSigInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype) { + $.checkState(this.output instanceof Output); + sigtype = sigtype || Signature.SIGHASH_ALL; + + var self = this; + var results = []; + _.each(this.publicKeys, function(publicKey) { + if (publicKey.toString() === privateKey.publicKey.toString()) { + results.push( + new TransactionSignature({ + publicKey: privateKey.publicKey, + prevTxId: self.prevTxId, + outputIndex: self.outputIndex, + inputIndex: index, + signature: Sighash.sign(transaction, privateKey, sigtype, index, self.output.script), + sigtype: sigtype, + }), + ); + } + }); + + return results; + }; + + MultiSigInput.prototype.addSignature = function(transaction, signature) { + $.checkState(!this.isFullySigned(), 'All needed signatures have already been added'); + $.checkArgument( + !_.isUndefined(this.publicKeyIndex[signature.publicKey.toString()]), + 'Signature has no matching public key', + ); + $.checkState(this.isValidSignature(transaction, signature)); + this.signatures[this.publicKeyIndex[signature.publicKey.toString()]] = signature; + this._updateScript(); + return this; + }; + + MultiSigInput.prototype._updateScript = function() { + this.setScript(Script.buildMultisigIn(this.publicKeys, this.threshold, this._createSignatures())); + return this; + }; + + MultiSigInput.prototype._createSignatures = function() { + return _.map( + _.filter(this.signatures, function(signature) { + return !_.isUndefined(signature); + }), + function(signature) { + return BufferUtil.concat([ + signature.signature.toDER(), + BufferUtil.integerAsSingleByteBuffer(signature.sigtype), + ]); + }, + ); + }; + + MultiSigInput.prototype.clearSignatures = function() { + this.signatures = new Array(this.publicKeys.length); + this._updateScript(); + }; + + MultiSigInput.prototype.isFullySigned = function() { + return this.countSignatures() === this.threshold; + }; + + MultiSigInput.prototype.countMissingSignatures = function() { + return this.threshold - this.countSignatures(); + }; + + MultiSigInput.prototype.countSignatures = function() { + return _.reduce( + this.signatures, + function(sum, signature) { + return sum + !!signature; + }, + 0, + ); + }; + + MultiSigInput.prototype.publicKeysWithoutSignature = function() { + var self = this; + return _.filter(this.publicKeys, function(publicKey) { + return !self.signatures[self.publicKeyIndex[publicKey.toString()]]; + }); + }; + + MultiSigInput.prototype.isValidSignature = function(transaction, signature) { + // FIXME: Refactor signature so this is not necessary + signature.signature.nhashtype = signature.sigtype; + return Sighash.verify( + transaction, + signature.signature, + signature.publicKey, + signature.inputIndex, + this.output.script, + ); + }; + + /** + * + * @param {Buffer[]} signatures + * @param {PublicKey[]} publicKeys + * @param {Transaction} transaction + * @param {Integer} inputIndex + * @param {Input} input + * @returns {TransactionSignature[]} + */ + MultiSigInput.normalizeSignatures = function(transaction, input, inputIndex, signatures, publicKeys) { + return publicKeys.map(function(pubKey) { + var signatureMatch = null; + signatures = signatures.filter(function(signatureBuffer) { + if (signatureMatch) { + return true; + } + + var signature = new TransactionSignature({ + signature: Signature.fromTxFormat(signatureBuffer), + publicKey: pubKey, + prevTxId: input.prevTxId, + outputIndex: input.outputIndex, + inputIndex: inputIndex, + sigtype: Signature.SIGHASH_ALL, + }); + + signature.signature.nhashtype = signature.sigtype; + var isMatch = Sighash.verify( + transaction, + signature.signature, + signature.publicKey, + signature.inputIndex, + input.output.script, + ); + + if (isMatch) { + signatureMatch = signature; + return false; + } + + return true; + }); + + return signatureMatch ? signatureMatch : null; + }); + }; + + MultiSigInput.OPCODES_SIZE = 1; // 0 + MultiSigInput.SIGNATURE_SIZE = 73; // size (1) + DER (<=72) + + MultiSigInput.prototype._estimateSize = function() { + return MultiSigInput.OPCODES_SIZE + this.threshold * MultiSigInput.SIGNATURE_SIZE; + }; + + module.exports = MultiSigInput; + }, + { + '../../crypto/signature': 11, + '../../publickey': 24, + '../../script': 25, + '../../util/buffer': 42, + '../../util/preconditions': 44, + '../output': 35, + '../sighash': 36, + '../signature': 37, + '../transaction': 38, + './input': 30, + inherits: 184, + lodash: 187, + }, + ], + 32: [ + function(require, module, exports) { + 'use strict'; + + var _ = require('lodash'); + var inherits = require('inherits'); + var Input = require('./input'); + var Output = require('../output'); + var $ = require('../../util/preconditions'); + + var Script = require('../../script'); + var Signature = require('../../crypto/signature'); + var Sighash = require('../sighash'); + var PublicKey = require('../../publickey'); + var BufferUtil = require('../../util/buffer'); + var TransactionSignature = require('../signature'); + + /** + * @constructor + */ + function MultiSigScriptHashInput(input, pubkeys, threshold, signatures) { + Input.apply(this, arguments); + var self = this; + pubkeys = pubkeys || input.publicKeys; + threshold = threshold || input.threshold; + signatures = signatures || input.signatures; + this.publicKeys = _.sortBy(pubkeys, function(publicKey) { + return publicKey.toString('hex'); + }); + this.redeemScript = Script.buildMultisigOut(this.publicKeys, threshold); + $.checkState( + Script.buildScriptHashOut(this.redeemScript).equals(this.output.script), + "Provided public keys don't hash to the provided output", + ); + this.publicKeyIndex = {}; + _.each(this.publicKeys, function(publicKey, index) { + self.publicKeyIndex[publicKey.toString()] = index; + }); + this.threshold = threshold; + // Empty array of signatures + this.signatures = signatures ? this._deserializeSignatures(signatures) : new Array(this.publicKeys.length); + } + inherits(MultiSigScriptHashInput, Input); + + MultiSigScriptHashInput.prototype.toObject = function() { + var obj = Input.prototype.toObject.apply(this, arguments); + obj.threshold = this.threshold; + obj.publicKeys = _.map(this.publicKeys, function(publicKey) { + return publicKey.toString(); + }); + obj.signatures = this._serializeSignatures(); + return obj; + }; + + MultiSigScriptHashInput.prototype._deserializeSignatures = function(signatures) { + return _.map(signatures, function(signature) { + if (!signature) { + return undefined; + } + return new TransactionSignature(signature); + }); + }; + + MultiSigScriptHashInput.prototype._serializeSignatures = function() { + return _.map(this.signatures, function(signature) { + if (!signature) { + return undefined; + } + return signature.toObject(); + }); + }; + + MultiSigScriptHashInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype) { + $.checkState(this.output instanceof Output); + sigtype = sigtype || Signature.SIGHASH_ALL; + + var self = this; + var results = []; + _.each(this.publicKeys, function(publicKey) { + if (publicKey.toString() === privateKey.publicKey.toString()) { + results.push( + new TransactionSignature({ + publicKey: privateKey.publicKey, + prevTxId: self.prevTxId, + outputIndex: self.outputIndex, + inputIndex: index, + signature: Sighash.sign(transaction, privateKey, sigtype, index, self.redeemScript), + sigtype: sigtype, + }), + ); + } + }); + return results; + }; + + MultiSigScriptHashInput.prototype.addSignature = function(transaction, signature) { + $.checkState(!this.isFullySigned(), 'All needed signatures have already been added'); + $.checkArgument( + !_.isUndefined(this.publicKeyIndex[signature.publicKey.toString()]), + 'Signature has no matching public key', + ); + $.checkState(this.isValidSignature(transaction, signature)); + this.signatures[this.publicKeyIndex[signature.publicKey.toString()]] = signature; + this._updateScript(); + return this; + }; + + MultiSigScriptHashInput.prototype._updateScript = function() { + this.setScript( + Script.buildP2SHMultisigIn(this.publicKeys, this.threshold, this._createSignatures(), { + cachedMultisig: this.redeemScript, + }), + ); + return this; + }; + + MultiSigScriptHashInput.prototype._createSignatures = function() { + return _.map( + _.filter(this.signatures, function(signature) { + return !_.isUndefined(signature); + }), + function(signature) { + return BufferUtil.concat([ + signature.signature.toDER(), + BufferUtil.integerAsSingleByteBuffer(signature.sigtype), + ]); + }, + ); + }; + + MultiSigScriptHashInput.prototype.clearSignatures = function() { + this.signatures = new Array(this.publicKeys.length); + this._updateScript(); + }; + + MultiSigScriptHashInput.prototype.isFullySigned = function() { + return this.countSignatures() === this.threshold; + }; + + MultiSigScriptHashInput.prototype.countMissingSignatures = function() { + return this.threshold - this.countSignatures(); + }; + + MultiSigScriptHashInput.prototype.countSignatures = function() { + return _.reduce( + this.signatures, + function(sum, signature) { + return sum + !!signature; + }, + 0, + ); + }; + + MultiSigScriptHashInput.prototype.publicKeysWithoutSignature = function() { + var self = this; + return _.filter(this.publicKeys, function(publicKey) { + return !self.signatures[self.publicKeyIndex[publicKey.toString()]]; + }); + }; + + MultiSigScriptHashInput.prototype.isValidSignature = function(transaction, signature) { + // FIXME: Refactor signature so this is not necessary + signature.signature.nhashtype = signature.sigtype; + return Sighash.verify( + transaction, + signature.signature, + signature.publicKey, + signature.inputIndex, + this.redeemScript, + ); + }; + + MultiSigScriptHashInput.OPCODES_SIZE = 7; // serialized size (<=3) + 0 .. N .. M OP_CHECKMULTISIG + MultiSigScriptHashInput.SIGNATURE_SIZE = 74; // size (1) + DER (<=72) + sighash (1) + MultiSigScriptHashInput.PUBKEY_SIZE = 34; // size (1) + DER (<=33) + + MultiSigScriptHashInput.prototype._estimateSize = function() { + return ( + MultiSigScriptHashInput.OPCODES_SIZE + + this.threshold * MultiSigScriptHashInput.SIGNATURE_SIZE + + this.publicKeys.length * MultiSigScriptHashInput.PUBKEY_SIZE + ); + }; + + module.exports = MultiSigScriptHashInput; + }, + { + '../../crypto/signature': 11, + '../../publickey': 24, + '../../script': 25, + '../../util/buffer': 42, + '../../util/preconditions': 44, + '../output': 35, + '../sighash': 36, + '../signature': 37, + './input': 30, + inherits: 184, + lodash: 187, + }, + ], + 33: [ + function(require, module, exports) { + 'use strict'; + + var inherits = require('inherits'); + + var $ = require('../../util/preconditions'); + var BufferUtil = require('../../util/buffer'); + + var Input = require('./input'); + var Output = require('../output'); + var Sighash = require('../sighash'); + var Script = require('../../script'); + var Signature = require('../../crypto/signature'); + var TransactionSignature = require('../signature'); + + /** + * Represents a special kind of input of PayToPublicKey kind. + * @constructor + */ + function PublicKeyInput() { + Input.apply(this, arguments); + } + inherits(PublicKeyInput, Input); + + /** + * @param {Transaction} transaction - the transaction to be signed + * @param {PrivateKey} privateKey - the private key with which to sign the transaction + * @param {number} index - the index of the input in the transaction input vector + * @param {number=} sigtype - the type of signature, defaults to Signature.SIGHASH_ALL + * @return {Array} of objects that can be + */ + PublicKeyInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype) { + $.checkState(this.output instanceof Output); + sigtype = sigtype || Signature.SIGHASH_ALL; + var publicKey = privateKey.toPublicKey(); + if (publicKey.toString() === this.output.script.getPublicKey().toString('hex')) { + return [ + new TransactionSignature({ + publicKey: publicKey, + prevTxId: this.prevTxId, + outputIndex: this.outputIndex, + inputIndex: index, + signature: Sighash.sign(transaction, privateKey, sigtype, index, this.output.script), + sigtype: sigtype, + }), + ]; + } + return []; + }; + + /** + * Add the provided signature + * + * @param {Object} signature + * @param {PublicKey} signature.publicKey + * @param {Signature} signature.signature + * @param {number=} signature.sigtype + * @return {PublicKeyInput} this, for chaining + */ + PublicKeyInput.prototype.addSignature = function(transaction, signature) { + $.checkState(this.isValidSignature(transaction, signature), 'Signature is invalid'); + this.setScript(Script.buildPublicKeyIn(signature.signature.toDER(), signature.sigtype)); + return this; + }; + + /** + * Clear the input's signature + * @return {PublicKeyHashInput} this, for chaining + */ + PublicKeyInput.prototype.clearSignatures = function() { + this.setScript(Script.empty()); + return this; + }; + + /** + * Query whether the input is signed + * @return {boolean} + */ + PublicKeyInput.prototype.isFullySigned = function() { + return this.script.isPublicKeyIn(); + }; + + PublicKeyInput.SCRIPT_MAX_SIZE = 73; // sigsize (1 + 72) + + PublicKeyInput.prototype._estimateSize = function() { + return PublicKeyInput.SCRIPT_MAX_SIZE; + }; + + module.exports = PublicKeyInput; + }, + { + '../../crypto/signature': 11, + '../../script': 25, + '../../util/buffer': 42, + '../../util/preconditions': 44, + '../output': 35, + '../sighash': 36, + '../signature': 37, + './input': 30, + inherits: 184, + }, + ], + 34: [ + function(require, module, exports) { + 'use strict'; + + var inherits = require('inherits'); + + var $ = require('../../util/preconditions'); + var BufferUtil = require('../../util/buffer'); + + var Hash = require('../../crypto/hash'); + var Input = require('./input'); + var Output = require('../output'); + var Sighash = require('../sighash'); + var Script = require('../../script'); + var Signature = require('../../crypto/signature'); + var TransactionSignature = require('../signature'); + + /** + * Represents a special kind of input of PayToPublicKeyHash kind. + * @constructor + */ + function PublicKeyHashInput() { + Input.apply(this, arguments); + } + inherits(PublicKeyHashInput, Input); + + /* jshint maxparams: 5 */ + /** + * @param {Transaction} transaction - the transaction to be signed + * @param {PrivateKey} privateKey - the private key with which to sign the transaction + * @param {number} index - the index of the input in the transaction input vector + * @param {number=} sigtype - the type of signature, defaults to Signature.SIGHASH_ALL + * @param {Buffer=} hashData - the precalculated hash of the public key associated with the privateKey provided + * @return {Array} of objects that can be + */ + PublicKeyHashInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype, hashData) { + $.checkState(this.output instanceof Output); + hashData = hashData || Hash.sha256ripemd160(privateKey.publicKey.toBuffer()); + sigtype = sigtype || Signature.SIGHASH_ALL; + + if (BufferUtil.equals(hashData, this.output.script.getPublicKeyHash())) { + return [ + new TransactionSignature({ + publicKey: privateKey.publicKey, + prevTxId: this.prevTxId, + outputIndex: this.outputIndex, + inputIndex: index, + signature: Sighash.sign(transaction, privateKey, sigtype, index, this.output.script), + sigtype: sigtype, + }), + ]; + } + return []; + }; + /* jshint maxparams: 3 */ + + /** + * Add the provided signature + * + * @param {Object} signature + * @param {PublicKey} signature.publicKey + * @param {Signature} signature.signature + * @param {number=} signature.sigtype + * @return {PublicKeyHashInput} this, for chaining + */ + PublicKeyHashInput.prototype.addSignature = function(transaction, signature) { + $.checkState(this.isValidSignature(transaction, signature), 'Signature is invalid'); + this.setScript( + Script.buildPublicKeyHashIn(signature.publicKey, signature.signature.toDER(), signature.sigtype), + ); + return this; + }; + + /** + * Clear the input's signature + * @return {PublicKeyHashInput} this, for chaining + */ + PublicKeyHashInput.prototype.clearSignatures = function() { + this.setScript(Script.empty()); + return this; + }; + + /** + * Query whether the input is signed + * @return {boolean} + */ + PublicKeyHashInput.prototype.isFullySigned = function() { + return this.script.isPublicKeyHashIn(); + }; + + PublicKeyHashInput.SCRIPT_MAX_SIZE = 73 + 34; // sigsize (1 + 72) + pubkey (1 + 33) + + PublicKeyHashInput.prototype._estimateSize = function() { + return PublicKeyHashInput.SCRIPT_MAX_SIZE; + }; + + module.exports = PublicKeyHashInput; + }, + { + '../../crypto/hash': 8, + '../../crypto/signature': 11, + '../../script': 25, + '../../util/buffer': 42, + '../../util/preconditions': 44, + '../output': 35, + '../sighash': 36, + '../signature': 37, + './input': 30, + inherits: 184, + }, + ], + 35: [ + function(require, module, exports) { + 'use strict'; + + var _ = require('lodash'); + var BN = require('../crypto/bn'); + var buffer = require('buffer'); + var bufferUtil = require('../util/buffer'); + var JSUtil = require('../util/js'); + var BufferWriter = require('../encoding/bufferwriter'); + var Script = require('../script'); + var $ = require('../util/preconditions'); + var errors = require('../errors'); + + var MAX_SAFE_INTEGER = 0x1fffffffffffff; + + function Output(args) { + if (!(this instanceof Output)) { + return new Output(args); + } + if (_.isObject(args)) { + this.micros = args.micros; + if (bufferUtil.isBuffer(args.script)) { + this._scriptBuffer = args.script; + } else { + var script; + if (_.isString(args.script) && JSUtil.isHexa(args.script)) { + script = new buffer.Buffer(args.script, 'hex'); + } else { + script = args.script; + } + this.setScript(script); + } + } else { + throw new TypeError('Unrecognized argument for Output'); + } + } + + Object.defineProperty(Output.prototype, 'script', { + configurable: false, + enumerable: true, + get: function() { + if (this._script) { + return this._script; + } else { + this.setScriptFromBuffer(this._scriptBuffer); + return this._script; + } + }, + }); + + Object.defineProperty(Output.prototype, 'micros', { + configurable: false, + enumerable: true, + get: function() { + return this._micros; + }, + set: function(num) { + if (num instanceof BN) { + this._microsBN = num; + this._micros = num.toNumber(); + } else if (_.isString(num)) { + this._micros = parseInt(num); + this._microsBN = BN.fromNumber(this._micros); + } else { + $.checkArgument(JSUtil.isNaturalNumber(num), 'Output micros is not a natural number'); + this._microsBN = BN.fromNumber(num); + this._micros = num; + } + $.checkState(JSUtil.isNaturalNumber(this._micros), 'Output micros is not a natural number'); + }, + }); + + Output.prototype.invalidMicros = function() { + if (this._micros > MAX_SAFE_INTEGER) { + return 'transaction txout micros greater than max safe integer'; + } + if (this._micros !== this._microsBN.toNumber()) { + return 'transaction txout micros has corrupted value'; + } + if (this._micros < 0) { + return 'transaction txout negative'; + } + return false; + }; + + Output.prototype.toObject = Output.prototype.toJSON = function toObject() { + var obj = { + micros: this.micros, + }; + obj.script = this._scriptBuffer.toString('hex'); + return obj; + }; + + Output.fromObject = function(data) { + return new Output(data); + }; + + Output.prototype.setScriptFromBuffer = function(buffer) { + this._scriptBuffer = buffer; + try { + this._script = Script.fromBuffer(this._scriptBuffer); + this._script._isOutput = true; + } catch (e) { + if (e instanceof errors.Script.InvalidBuffer) { + this._script = null; + } else { + throw e; + } + } + }; + + Output.prototype.setScript = function(script) { + if (script instanceof Script) { + this._scriptBuffer = script.toBuffer(); + this._script = script; + this._script._isOutput = true; + } else if (_.isString(script)) { + this._script = Script.fromString(script); + this._scriptBuffer = this._script.toBuffer(); + this._script._isOutput = true; + } else if (bufferUtil.isBuffer(script)) { + this.setScriptFromBuffer(script); + } else { + throw new TypeError('Invalid argument type: script'); + } + return this; + }; + + Output.prototype.inspect = function() { + var scriptStr; + if (this.script) { + scriptStr = this.script.inspect(); + } else { + scriptStr = this._scriptBuffer.toString('hex'); + } + return ''; + }; + + Output.fromBufferReader = function(br) { + var obj = {}; + obj.micros = br.readUInt64LEBN(); + var size = br.readVarintNum(); + if (size !== 0) { + obj.script = br.read(size); + } else { + obj.script = new buffer.Buffer([]); + } + return new Output(obj); + }; + + Output.prototype.toBufferWriter = function(writer) { + if (!writer) { + writer = new BufferWriter(); + } + writer.writeUInt64LEBN(this._microsBN); + var script = this._scriptBuffer; + writer.writeVarintNum(script.length); + writer.write(script); + return writer; + }; + + module.exports = Output; + }, + { + '../crypto/bn': 6, + '../encoding/bufferwriter': 15, + '../errors': 17, + '../script': 25, + '../util/buffer': 42, + '../util/js': 43, + '../util/preconditions': 44, + buffer: 113, + lodash: 187, + }, + ], + 36: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var buffer = require('buffer'); + + var Signature = require('../crypto/signature'); + var Script = require('../script'); + var Output = require('./output'); + var BufferReader = require('../encoding/bufferreader'); + var BufferWriter = require('../encoding/bufferwriter'); + var BN = require('../crypto/bn'); + var Hash = require('../crypto/hash'); + var ECDSA = require('../crypto/ecdsa'); + var $ = require('../util/preconditions'); + var _ = require('lodash'); + + var SIGHASH_SINGLE_BUG = '0000000000000000000000000000000000000000000000000000000000000001'; + var BITS_64_ON = 'ffffffffffffffff'; + + /** + * Returns a buffer of length 32 bytes with the hash that needs to be signed + * for OP_CHECKSIG. + * + * @name Signing.sighash + * @param {Transaction} transaction the transaction to sign + * @param {number} sighashType the type of the hash + * @param {number} inputNumber the input index for the signature + * @param {Script} subscript the script that will be signed + */ + var sighash = function sighash(transaction, sighashType, inputNumber, subscript) { + var Transaction = require('./transaction'); + var Input = require('./input'); + + var i; + // Copy transaction + var txcopy = Transaction.shallowCopy(transaction); + + // Copy script + subscript = new Script(subscript); + subscript.removeCodeseparators(); + + for (i = 0; i < txcopy.inputs.length; i++) { + // Blank signatures for other inputs + txcopy.inputs[i] = new Input(txcopy.inputs[i]).setScript(Script.empty()); + } + + txcopy.inputs[inputNumber] = new Input(txcopy.inputs[inputNumber]).setScript(subscript); + + if ((sighashType & 31) === Signature.SIGHASH_NONE || (sighashType & 31) === Signature.SIGHASH_SINGLE) { + // clear all sequenceNumbers + for (i = 0; i < txcopy.inputs.length; i++) { + if (i !== inputNumber) { + txcopy.inputs[i].sequenceNumber = 0; + } + } + } + + if ((sighashType & 31) === Signature.SIGHASH_NONE) { + txcopy.outputs = []; + } else if ((sighashType & 31) === Signature.SIGHASH_SINGLE) { + // The SIGHASH_SINGLE bug. + // https://bitcointalk.org/index.php?topic=260595.0 + if (inputNumber >= txcopy.outputs.length) { + return new Buffer(SIGHASH_SINGLE_BUG, 'hex'); + } + + txcopy.outputs.length = inputNumber + 1; + + for (i = 0; i < inputNumber; i++) { + txcopy.outputs[i] = new Output({ + micros: BN.fromBuffer(new buffer.Buffer(BITS_64_ON, 'hex')), + script: Script.empty(), + }); + } + } + + if (sighashType & Signature.SIGHASH_ANYONECANPAY) { + txcopy.inputs = [txcopy.inputs[inputNumber]]; + } + + var buf = new BufferWriter() + .write(txcopy.toBuffer()) + .writeInt32LE(sighashType) + .toBuffer(); + var ret = Hash.sha256sha256(buf); + ret = new BufferReader(ret).readReverse(); + return ret; + }; + + /** + * Create a signature + * + * @name Signing.sign + * @param {Transaction} transaction + * @param {PrivateKey} privateKey + * @param {number} sighash + * @param {number} inputIndex + * @param {Script} subscript + * @return {Signature} + */ + function sign(transaction, privateKey, sighashType, inputIndex, subscript) { + var hashbuf = sighash(transaction, sighashType, inputIndex, subscript); + var sig = ECDSA.sign(hashbuf, privateKey, 'little').set({ + nhashtype: sighashType, + }); + return sig; + } + + /** + * Verify a signature + * + * @name Signing.verify + * @param {Transaction} transaction + * @param {Signature} signature + * @param {PublicKey} publicKey + * @param {number} inputIndex + * @param {Script} subscript + * @return {boolean} + */ + function verify(transaction, signature, publicKey, inputIndex, subscript) { + $.checkArgument(!_.isUndefined(transaction)); + $.checkArgument(!_.isUndefined(signature) && !_.isUndefined(signature.nhashtype)); + var hashbuf = sighash(transaction, signature.nhashtype, inputIndex, subscript); + return ECDSA.verify(hashbuf, signature, publicKey, 'little'); + } + + /** + * @namespace Signing + */ + module.exports = { + sighash: sighash, + sign: sign, + verify: verify, + }; + }.call(this, require('buffer').Buffer)); + }, + { + '../crypto/bn': 6, + '../crypto/ecdsa': 7, + '../crypto/hash': 8, + '../crypto/signature': 11, + '../encoding/bufferreader': 14, + '../encoding/bufferwriter': 15, + '../script': 25, + '../util/preconditions': 44, + './input': 29, + './output': 35, + './transaction': 38, + buffer: 113, + lodash: 187, + }, + ], + 37: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var _ = require('lodash'); + var $ = require('../util/preconditions'); + var inherits = require('inherits'); + var BufferUtil = require('../util/buffer'); + var JSUtil = require('../util/js'); + + var PublicKey = require('../publickey'); + var errors = require('../errors'); + var Signature = require('../crypto/signature'); + + /** + * @desc + * Wrapper around Signature with fields related to signing a transaction specifically + * + * @param {Object|string|TransactionSignature} arg + * @constructor + */ + function TransactionSignature(arg) { + if (!(this instanceof TransactionSignature)) { + return new TransactionSignature(arg); + } + if (arg instanceof TransactionSignature) { + return arg; + } + if (_.isObject(arg)) { + return this._fromObject(arg); + } + throw new errors.InvalidArgument('TransactionSignatures must be instantiated from an object'); + } + inherits(TransactionSignature, Signature); + + TransactionSignature.prototype._fromObject = function(arg) { + this._checkObjectArgs(arg); + this.publicKey = new PublicKey(arg.publicKey); + this.prevTxId = BufferUtil.isBuffer(arg.prevTxId) ? arg.prevTxId : new Buffer(arg.prevTxId, 'hex'); + this.outputIndex = arg.outputIndex; + this.inputIndex = arg.inputIndex; + this.signature = + arg.signature instanceof Signature + ? arg.signature + : BufferUtil.isBuffer(arg.signature) + ? Signature.fromBuffer(arg.signature) + : Signature.fromString(arg.signature); + this.sigtype = arg.sigtype; + return this; + }; + + TransactionSignature.prototype._checkObjectArgs = function(arg) { + $.checkArgument(PublicKey(arg.publicKey), 'publicKey'); + $.checkArgument(!_.isUndefined(arg.inputIndex), 'inputIndex'); + $.checkArgument(!_.isUndefined(arg.outputIndex), 'outputIndex'); + $.checkState(_.isNumber(arg.inputIndex), 'inputIndex must be a number'); + $.checkState(_.isNumber(arg.outputIndex), 'outputIndex must be a number'); + $.checkArgument(arg.signature, 'signature'); + $.checkArgument(arg.prevTxId, 'prevTxId'); + $.checkState( + arg.signature instanceof Signature || BufferUtil.isBuffer(arg.signature) || JSUtil.isHexa(arg.signature), + 'signature must be a buffer or hexa value', + ); + $.checkState( + BufferUtil.isBuffer(arg.prevTxId) || JSUtil.isHexa(arg.prevTxId), + 'prevTxId must be a buffer or hexa value', + ); + $.checkArgument(arg.sigtype, 'sigtype'); + $.checkState(_.isNumber(arg.sigtype), 'sigtype must be a number'); + }; + + /** + * Serializes a transaction to a plain JS object + * @return {Object} + */ + TransactionSignature.prototype.toObject = TransactionSignature.prototype.toJSON = function toObject() { + return { + publicKey: this.publicKey.toString(), + prevTxId: this.prevTxId.toString('hex'), + outputIndex: this.outputIndex, + inputIndex: this.inputIndex, + signature: this.signature.toString(), + sigtype: this.sigtype, + }; + }; + + /** + * Builds a TransactionSignature from an object + * @param {Object} object + * @return {TransactionSignature} + */ + TransactionSignature.fromObject = function(object) { + $.checkArgument(object); + return new TransactionSignature(object); + }; + + module.exports = TransactionSignature; + }.call(this, require('buffer').Buffer)); + }, + { + '../crypto/signature': 11, + '../errors': 17, + '../publickey': 24, + '../util/buffer': 42, + '../util/js': 43, + '../util/preconditions': 44, + buffer: 113, + inherits: 184, + lodash: 187, + }, + ], + 38: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + + var _ = require('lodash'); + var $ = require('../util/preconditions'); + var buffer = require('buffer'); + var compare = Buffer.compare || require('buffer-compare'); + + var errors = require('../errors'); + var BufferUtil = require('../util/buffer'); + var JSUtil = require('../util/js'); + var BufferReader = require('../encoding/bufferreader'); + var BufferWriter = require('../encoding/bufferwriter'); + var Hash = require('../crypto/hash'); + var Signature = require('../crypto/signature'); + var Sighash = require('./sighash'); + + var Address = require('../address'); + var UnspentOutput = require('./unspentoutput'); + var Input = require('./input'); + var PublicKeyHashInput = Input.PublicKeyHash; + var PublicKeyInput = Input.PublicKey; + var MultiSigScriptHashInput = Input.MultiSigScriptHash; + var MultiSigInput = Input.MultiSig; + var Output = require('./output'); + var Script = require('../script'); + var PrivateKey = require('../privatekey'); + var BN = require('../crypto/bn'); + + /** + * Represents a transaction, a set of inputs and outputs to change ownership of tokens + * + * @param {*} serialized + * @constructor + */ + function Transaction(serialized) { + if (!(this instanceof Transaction)) { + return new Transaction(serialized); + } + this.inputs = []; + this.outputs = []; + this._inputAmount = undefined; + this._outputAmount = undefined; + + if (serialized) { + if (serialized instanceof Transaction) { + return Transaction.shallowCopy(serialized); + } else if (JSUtil.isHexa(serialized)) { + this.fromString(serialized); + } else if (BufferUtil.isBuffer(serialized)) { + this.fromBuffer(serialized); + } else if (_.isObject(serialized)) { + this.fromObject(serialized); + } else { + throw new errors.InvalidArgument('Must provide an object or string to deserialize a transaction'); + } + } else { + this._newTransaction(); + } + } + + var CURRENT_VERSION = 1; + var DEFAULT_NLOCKTIME = 0; + var MAX_BLOCK_SIZE = 1000000; + + // Minimum amount for an output for it not to be considered a dust output + Transaction.DUST_AMOUNT = 546; + + // Margin of error to allow fees in the vecinity of the expected value but doesn't allow a big difference + Transaction.FEE_SECURITY_MARGIN = 150; + + // max amount of micros in circulation + Transaction.MAX_MONEY = 21000000 * 1e8; + + // nlocktime limit to be considered block height rather than a timestamp + Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT = 5e8; + + // Max value for an unsigned 32 bit value + Transaction.NLOCKTIME_MAX_VALUE = 4294967295; + + // Value used for fee estimation (micros per kilobyte) + Transaction.FEE_PER_KB = 100000; + + // Safe upper bound for change address script size in bytes + Transaction.CHANGE_OUTPUT_MAX_SIZE = 20 + 4 + 34 + 4; + Transaction.MAXIMUM_EXTRA_SIZE = 4 + 9 + 9 + 4; + + /* Constructors and Serialization */ + + /** + * Create a 'shallow' copy of the transaction, by serializing and deserializing + * it dropping any additional information that inputs and outputs may have hold + * + * @param {Transaction} transaction + * @return {Transaction} + */ + Transaction.shallowCopy = function(transaction) { + var copy = new Transaction(transaction.toBuffer()); + return copy; + }; + + var hashProperty = { + configurable: false, + enumerable: true, + get: function() { + return new BufferReader(this._getHash()).readReverse().toString('hex'); + }, + }; + Object.defineProperty(Transaction.prototype, 'hash', hashProperty); + Object.defineProperty(Transaction.prototype, 'id', hashProperty); + + var ioProperty = { + configurable: false, + enumerable: true, + get: function() { + return this._getInputAmount(); + }, + }; + Object.defineProperty(Transaction.prototype, 'inputAmount', ioProperty); + ioProperty.get = function() { + return this._getOutputAmount(); + }; + Object.defineProperty(Transaction.prototype, 'outputAmount', ioProperty); + + /** + * Retrieve the little endian hash of the transaction (used for serialization) + * @return {Buffer} + */ + Transaction.prototype._getHash = function() { + return Hash.sha256sha256(this.toBuffer()); + }; + + /** + * Retrieve a hexa string that can be used with bitcoind's CLI interface + * (decoderawtransaction, sendrawtransaction) + * + * @param {Object|boolean=} unsafe if true, skip all tests. if it's an object, + * it's expected to contain a set of flags to skip certain tests: + * * `disableAll`: disable all checks + * * `disableSmallFees`: disable checking for fees that are too small + * * `disableLargeFees`: disable checking for fees that are too large + * * `disableIsFullySigned`: disable checking if all inputs are fully signed + * * `disableDustOutputs`: disable checking if there are no outputs that are dust amounts + * * `disableMoreOutputThanInput`: disable checking if the transaction spends more bitcoins than the sum of the input amounts + * @return {string} + */ + Transaction.prototype.serialize = function(unsafe) { + if (true === unsafe || (unsafe && unsafe.disableAll)) { + return this.uncheckedSerialize(); + } else { + return this.checkedSerialize(unsafe); + } + }; + + Transaction.prototype.uncheckedSerialize = Transaction.prototype.toString = function() { + return this.toBuffer().toString('hex'); + }; + + /** + * Retrieve a hexa string that can be used with bitcoind's CLI interface + * (decoderawtransaction, sendrawtransaction) + * + * @param {Object} opts allows to skip certain tests. {@see Transaction#serialize} + * @return {string} + */ + Transaction.prototype.checkedSerialize = function(opts) { + var serializationError = this.getSerializationError(opts); + if (serializationError) { + serializationError.message += + ' - For more information please see: ' + 'https://bitcore.io/api/lib/transaction#serialization-checks'; + throw serializationError; + } + return this.uncheckedSerialize(); + }; + + Transaction.prototype.invalidMicros = function() { + var invalid = false; + for (var i = 0; i < this.outputs.length; i++) { + if (this.outputs[i].invalidMicros()) { + invalid = true; + } + } + return invalid; + }; + + /** + * Retrieve a possible error that could appear when trying to serialize and + * broadcast this transaction. + * + * @param {Object} opts allows to skip certain tests. {@see Transaction#serialize} + * @return {bitcore.Error} + */ + Transaction.prototype.getSerializationError = function(opts) { + opts = opts || {}; + + if (this.invalidMicros()) { + return new errors.Transaction.InvalidMicros(); + } + + var unspent = this._getUnspentValue(); + var unspentError; + if (unspent < 0) { + if (!opts.disableMoreOutputThanInput) { + unspentError = new errors.Transaction.InvalidOutputAmountSum(); + } + } else { + unspentError = this._hasFeeError(opts, unspent); + } + + return unspentError || this._hasDustOutputs(opts) || this._isMissingSignatures(opts); + }; + + Transaction.prototype._hasFeeError = function(opts, unspent) { + if (!_.isUndefined(this._fee) && this._fee !== unspent) { + return new errors.Transaction.FeeError.Different( + 'Unspent value is ' + unspent + ' but specified fee is ' + this._fee, + ); + } + + if (!opts.disableLargeFees) { + var maximumFee = Math.floor(Transaction.FEE_SECURITY_MARGIN * this._estimateFee()); + if (unspent > maximumFee) { + if (this._missingChange()) { + return new errors.Transaction.ChangeAddressMissing( + 'Fee is too large and no change address was provided', + ); + } + return new errors.Transaction.FeeError.TooLarge( + 'expected less than ' + maximumFee + ' but got ' + unspent, + ); + } + } + + if (!opts.disableSmallFees) { + var minimumFee = Math.ceil(this._estimateFee() / Transaction.FEE_SECURITY_MARGIN); + if (unspent < minimumFee) { + return new errors.Transaction.FeeError.TooSmall( + 'expected more than ' + minimumFee + ' but got ' + unspent, + ); + } + } + }; + + Transaction.prototype._missingChange = function() { + return !this._changeScript; + }; + + Transaction.prototype._hasDustOutputs = function(opts) { + if (opts.disableDustOutputs) { + return; + } + var index, output; + for (index in this.outputs) { + output = this.outputs[index]; + if (output.micros < Transaction.DUST_AMOUNT && !output.script.isDataOut()) { + return new errors.Transaction.DustOutputs(); + } + } + }; + + Transaction.prototype._isMissingSignatures = function(opts) { + if (opts.disableIsFullySigned) { + return; + } + if (!this.isFullySigned()) { + return new errors.Transaction.MissingSignatures(); + } + }; + + Transaction.prototype.inspect = function() { + return ''; + }; + + Transaction.prototype.toBuffer = function() { + var writer = new BufferWriter(); + return this.toBufferWriter(writer).toBuffer(); + }; + + Transaction.prototype.toBufferWriter = function(writer) { + writer.writeInt32LE(this.version); + writer.writeVarintNum(this.inputs.length); + _.each(this.inputs, function(input) { + input.toBufferWriter(writer); + }); + writer.writeVarintNum(this.outputs.length); + _.each(this.outputs, function(output) { + output.toBufferWriter(writer); + }); + writer.writeUInt32LE(this.nLockTime); + return writer; + }; + + Transaction.prototype.fromBuffer = function(buffer) { + var reader = new BufferReader(buffer); + return this.fromBufferReader(reader); + }; + + Transaction.prototype.fromBufferReader = function(reader) { + $.checkArgument(!reader.finished(), 'No transaction data received'); + var i, sizeTxIns, sizeTxOuts; + + this.version = reader.readInt32LE(); + sizeTxIns = reader.readVarintNum(); + for (i = 0; i < sizeTxIns; i++) { + var input = Input.fromBufferReader(reader); + this.inputs.push(input); + } + sizeTxOuts = reader.readVarintNum(); + for (i = 0; i < sizeTxOuts; i++) { + this.outputs.push(Output.fromBufferReader(reader)); + } + this.nLockTime = reader.readUInt32LE(); + return this; + }; + + Transaction.prototype.toObject = Transaction.prototype.toJSON = function toObject() { + var inputs = []; + this.inputs.forEach(function(input) { + inputs.push(input.toObject()); + }); + var outputs = []; + this.outputs.forEach(function(output) { + outputs.push(output.toObject()); + }); + var obj = { + hash: this.hash, + version: this.version, + inputs: inputs, + outputs: outputs, + nLockTime: this.nLockTime, + }; + if (this._changeScript) { + obj.changeScript = this._changeScript.toString(); + } + if (!_.isUndefined(this._changeIndex)) { + obj.changeIndex = this._changeIndex; + } + if (!_.isUndefined(this._fee)) { + obj.fee = this._fee; + } + return obj; + }; + + Transaction.prototype.fromObject = function fromObject(arg) { + /* jshint maxstatements: 20 */ + $.checkArgument(_.isObject(arg) || arg instanceof Transaction); + var self = this; + var transaction; + if (arg instanceof Transaction) { + transaction = transaction.toObject(); + } else { + transaction = arg; + } + _.each(transaction.inputs, function(input) { + if (!input.output || !input.output.script) { + self.uncheckedAddInput(new Input(input)); + return; + } + var script = new Script(input.output.script); + var txin; + if (script.isPublicKeyHashOut()) { + txin = new Input.PublicKeyHash(input); + } else if (script.isScriptHashOut() && input.publicKeys && input.threshold) { + txin = new Input.MultiSigScriptHash(input, input.publicKeys, input.threshold, input.signatures); + } else if (script.isPublicKeyOut()) { + txin = new Input.PublicKey(input); + } else { + throw new errors.Transaction.Input.UnsupportedScript(input.output.script); + } + self.addInput(txin); + }); + _.each(transaction.outputs, function(output) { + self.addOutput(new Output(output)); + }); + if (transaction.changeIndex) { + this._changeIndex = transaction.changeIndex; + } + if (transaction.changeScript) { + this._changeScript = new Script(transaction.changeScript); + } + if (transaction.fee) { + this._fee = transaction.fee; + } + this.nLockTime = transaction.nLockTime; + this.version = transaction.version; + this._checkConsistency(arg); + return this; + }; + + Transaction.prototype._checkConsistency = function(arg) { + if (!_.isUndefined(this._changeIndex)) { + $.checkState(this._changeScript); + $.checkState(this.outputs[this._changeIndex]); + $.checkState(this.outputs[this._changeIndex].script.toString() === this._changeScript.toString()); + } + if (arg && arg.hash) { + $.checkState(arg.hash === this.hash, 'Hash in object does not match transaction hash'); + } + }; + + /** + * Sets nLockTime so that transaction is not valid until the desired date(a + * timestamp in seconds since UNIX epoch is also accepted) + * + * @param {Date | Number} time + * @return {Transaction} this + */ + Transaction.prototype.lockUntilDate = function(time) { + $.checkArgument(time); + if (_.isNumber(time) && time < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) { + throw new errors.Transaction.LockTimeTooEarly(); + } + if (_.isDate(time)) { + time = time.getTime() / 1000; + } -/** - * WARNING: This method will not be officially supported until v1.0.0 - * - * - * WARNING: If this is a new implementation you should NOT use this method, you should be using - * `derive` instead. - * - * This method is explicitly for use and compatibility with an implementation that - * was not compliant with BIP32 regarding the derivation algorithm. The private key - * must be 32 bytes hashing, and this implementation will use the non-zero padded - * serialization of a private key, such that it's still possible to derive the privateKey - * to recover those funds. - * - * @param {string|number} arg - * @param {boolean?} hardened - */ -HDPrivateKey.prototype.deriveNonCompliantChild = function(arg, hardened) { - if (_.isNumber(arg)) { - return this._deriveWithNumber(arg, hardened, true); - } else if (_.isString(arg)) { - return this._deriveFromString(arg, true); - } else { - throw new hdErrors.InvalidDerivationArgument(arg); - } -}; + for (var i = 0; i < this.inputs.length; i++) { + if (this.inputs[i].sequenceNumber === Input.DEFAULT_SEQNUMBER) { + this.inputs[i].sequenceNumber = Input.DEFAULT_LOCKTIME_SEQNUMBER; + } + } -HDPrivateKey.prototype._deriveWithNumber = function(index, hardened, nonCompliant) { - /* jshint maxstatements: 20 */ - /* jshint maxcomplexity: 10 */ - if (!HDPrivateKey.isValidPath(index, hardened)) { - throw new hdErrors.InvalidPath(index); - } + this.nLockTime = time; + return this; + }; + + /** + * Sets nLockTime so that transaction is not valid until the desired block + * height. + * + * @param {Number} height + * @return {Transaction} this + */ + Transaction.prototype.lockUntilBlockHeight = function(height) { + $.checkArgument(_.isNumber(height)); + if (height >= Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) { + throw new errors.Transaction.BlockHeightTooHigh(); + } + if (height < 0) { + throw new errors.Transaction.NLockTimeOutOfRange(); + } - hardened = index >= HDPrivateKey.Hardened ? true : hardened; - if (index < HDPrivateKey.Hardened && hardened === true) { - index += HDPrivateKey.Hardened; - } + for (var i = 0; i < this.inputs.length; i++) { + if (this.inputs[i].sequenceNumber === Input.DEFAULT_SEQNUMBER) { + this.inputs[i].sequenceNumber = Input.DEFAULT_LOCKTIME_SEQNUMBER; + } + } - var indexBuffer = BufferUtil.integerAsBuffer(index); - var data; - if (hardened && nonCompliant) { - // The private key serialization in this case will not be exactly 32 bytes and can be - // any value less, and the value is not zero-padded. - var nonZeroPadded = this.privateKey.bn.toBuffer(); - data = BufferUtil.concat([new buffer.Buffer([0]), nonZeroPadded, indexBuffer]); - } else if (hardened) { - // This will use a 32 byte zero padded serialization of the private key - var privateKeyBuffer = this.privateKey.bn.toBuffer({size: 32}); - assert(privateKeyBuffer.length === 32, 'length of private key buffer is expected to be 32 bytes'); - data = BufferUtil.concat([new buffer.Buffer([0]), privateKeyBuffer, indexBuffer]); - } else { - data = BufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]); - } - var hash = Hash.sha512hmac(data, this._buffers.chainCode); - var leftPart = BN.fromBuffer(hash.slice(0, 32), { - size: 32 - }); - var chainCode = hash.slice(32, 64); - - var privateKey = leftPart.add(this.privateKey.toBigNumber()).mod(Point.getN()).toBuffer({ - size: 32 - }); - - if (!PrivateKey.isValid(privateKey)) { - // Index at this point is already hardened, we can pass null as the hardened arg - return this._deriveWithNumber(index + 1, null, nonCompliant); - } + this.nLockTime = height; + return this; + }; + + /** + * Returns a semantic version of the transaction's nLockTime. + * @return {Number|Date} + * If nLockTime is 0, it returns null, + * if it is < 500000000, it returns a block height (number) + * else it returns a Date object. + */ + Transaction.prototype.getLockTime = function() { + if (!this.nLockTime) { + return null; + } + if (this.nLockTime < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) { + return this.nLockTime; + } + return new Date(1000 * this.nLockTime); + }; + + Transaction.prototype.fromString = function(string) { + this.fromBuffer(new buffer.Buffer(string, 'hex')); + }; + + Transaction.prototype._newTransaction = function() { + this.version = CURRENT_VERSION; + this.nLockTime = DEFAULT_NLOCKTIME; + }; + + /* Transaction creation interface */ + + /** + * @typedef {Object} Transaction~fromObject + * @property {string} prevTxId + * @property {number} outputIndex + * @property {(Buffer|string|Script)} script + * @property {number} micros + */ + + /** + * Add an input to this transaction. This is a high level interface + * to add an input, for more control, use @{link Transaction#addInput}. + * + * Can receive, as output information, the output of bitcoind's `listunspent` command, + * and a slightly fancier format recognized by Merit library: + * + * ``` + * { + * address: 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1', + * txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458', + * outputIndex: 0, + * script: Script.empty(), + * micros: 1020000 + * } + * ``` + * Where `address` can be either a string or a Merit Address object. The + * same is true for `script`, which can be a string or a Merit Script. + * + * Beware that this resets all the signatures for inputs (in further versions, + * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). + * + * @example + * ```javascript + * var transaction = new Transaction(); + * + * // From a pay to public key hash output from bitcoind's listunspent + * transaction.from({'txid': '0000...', vout: 0, amount: 0.1, scriptPubKey: 'OP_DUP ...'}); + * + * // From a pay to public key hash output + * transaction.from({'txId': '0000...', outputIndex: 0, micros: 1000, script: 'OP_DUP ...'}); + * + * // From a multisig P2SH output + * transaction.from({'txId': '0000...', inputIndex: 0, micros: 1000, script: '... OP_HASH'}, + * ['03000...', '02000...'], 2); + * ``` + * + * @param {(Array.|Transaction~fromObject)} utxo + * @param {Array=} pubkeys + * @param {number=} threshold + */ + Transaction.prototype.from = function(utxo, pubkeys, threshold) { + if (_.isArray(utxo)) { + var self = this; + _.each(utxo, function(utxo) { + self.from(utxo, pubkeys, threshold); + }); + return this; + } + var exists = _.some(this.inputs, function(input) { + // TODO: Maybe prevTxId should be a string? Or defined as read only property? + return input.prevTxId.toString('hex') === utxo.txId && input.outputIndex === utxo.outputIndex; + }); + if (exists) { + return this; + } + if (pubkeys && threshold) { + this._fromMultisigUtxo(utxo, pubkeys, threshold); + } else { + this._fromNonP2SH(utxo); + } + return this; + }; + + Transaction.prototype._fromNonP2SH = function(utxo) { + var clazz; + utxo = new UnspentOutput(utxo); + if (utxo.script.isPublicKeyHashOut()) { + clazz = PublicKeyHashInput; + } else if (utxo.script.isPublicKeyOut()) { + clazz = PublicKeyInput; + } else { + clazz = Input; + } + this.addInput( + new clazz({ + output: new Output({ + script: utxo.script, + micros: utxo.micros, + }), + prevTxId: utxo.txId, + outputIndex: utxo.outputIndex, + script: Script.empty(), + }), + ); + }; + + Transaction.prototype._fromMultisigUtxo = function(utxo, pubkeys, threshold) { + $.checkArgument( + threshold <= pubkeys.length, + 'Number of required signatures must be greater than the number of public keys', + ); + var clazz; + utxo = new UnspentOutput(utxo); + if (utxo.script.isMultisigOut()) { + clazz = MultiSigInput; + } else if (utxo.script.isScriptHashOut()) { + clazz = MultiSigScriptHashInput; + } else { + throw new Error('@TODO'); + } + this.addInput( + new clazz( + { + output: new Output({ + script: utxo.script, + micros: utxo.micros, + }), + prevTxId: utxo.txId, + outputIndex: utxo.outputIndex, + script: Script.empty(), + }, + pubkeys, + threshold, + ), + ); + }; + + /** + * Add an input to this transaction. The input must be an instance of the `Input` class. + * It should have information about the Output that it's spending, but if it's not already + * set, two additional parameters, `outputScript` and `micros` can be provided. + * + * @param {Input} input + * @param {String|Script} outputScript + * @param {number} micros + * @return Transaction this, for chaining + */ + Transaction.prototype.addInput = function(input, outputScript, micros) { + $.checkArgumentType(input, Input, 'input'); + if (!input.output && (_.isUndefined(outputScript) || _.isUndefined(micros))) { + throw new errors.Transaction.NeedMoreInfo('Need information about the UTXO script and micros'); + } + if (!input.output && outputScript && !_.isUndefined(micros)) { + outputScript = outputScript instanceof Script ? outputScript : new Script(outputScript); + $.checkArgumentType(micros, 'number', 'micros'); + input.output = new Output({ + script: outputScript, + micros: micros, + }); + } + return this.uncheckedAddInput(input); + }; + + /** + * Add an input to this transaction, without checking that the input has information about + * the output that it's spending. + * + * @param {Input} input + * @return Transaction this, for chaining + */ + Transaction.prototype.uncheckedAddInput = function(input) { + $.checkArgumentType(input, Input, 'input'); + this.inputs.push(input); + this._inputAmount = undefined; + this._updateChangeOutput(); + return this; + }; + + /** + * Returns true if the transaction has enough info on all inputs to be correctly validated + * + * @return {boolean} + */ + Transaction.prototype.hasAllUtxoInfo = function() { + return _.every( + this.inputs.map(function(input) { + return !!input.output; + }), + ); + }; + + /** + * Manually set the fee for this transaction. Beware that this resets all the signatures + * for inputs (in further versions, SIGHASH_SINGLE or SIGHASH_NONE signatures will not + * be reset). + * + * @param {number} amount micros to be sent + * @return {Transaction} this, for chaining + */ + Transaction.prototype.fee = function(amount) { + $.checkArgument(_.isNumber(amount), 'amount must be a number'); + this._fee = amount; + this._updateChangeOutput(); + return this; + }; + + /** + * Manually set the fee per KB for this transaction. Beware that this resets all the signatures + * for inputs (in further versions, SIGHASH_SINGLE or SIGHASH_NONE signatures will not + * be reset). + * + * @param {number} amount micros per KB to be sent + * @return {Transaction} this, for chaining + */ + Transaction.prototype.feePerKb = function(amount) { + $.checkArgument(_.isNumber(amount), 'amount must be a number'); + this._feePerKb = amount; + this._updateChangeOutput(); + return this; + }; + + /* Output management */ + + /** + * Set the change address for this transaction + * + * Beware that this resets all the signatures for inputs (in further versions, + * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). + * + * @param {Address} address An address for change to be sent to. + * @return {Transaction} this, for chaining + */ + Transaction.prototype.change = function(address) { + $.checkArgument(address, 'address is required'); + this._changeScript = Script.fromAddress(address); + this._updateChangeOutput(); + return this; + }; + + /** + * @return {Output} change output, if it exists + */ + Transaction.prototype.getChangeOutput = function() { + if (!_.isUndefined(this._changeIndex)) { + return this.outputs[this._changeIndex]; + } + return null; + }; + + /** + * @typedef {Object} Transaction~toObject + * @property {(string|Address)} address + * @property {number} micros + */ + + /** + * Add an output to the transaction. + * + * Beware that this resets all the signatures for inputs (in further versions, + * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). + * + * @param {(string|Address|Array.)} address + * @param {number} amount in micros + * @return {Transaction} this, for chaining + */ + Transaction.prototype.to = function(address, amount) { + if (_.isArray(address)) { + var self = this; + _.each(address, function(to) { + self.to(to.address, to.micros); + }); + return this; + } - var derived = new HDPrivateKey({ - network: this.network, - depth: this.depth + 1, - parentFingerPrint: this.fingerPrint, - childIndex: index, - chainCode: chainCode, - privateKey: privateKey - }); - - return derived; -}; - -HDPrivateKey.prototype._deriveFromString = function(path, nonCompliant) { - if (!HDPrivateKey.isValidPath(path)) { - throw new hdErrors.InvalidPath(path); - } + $.checkArgument(JSUtil.isNaturalNumber(amount), 'Amount is expected to be a positive integer'); + this.addOutput( + new Output({ + script: Script(new Address(address)), + micros: amount, + }), + ); + return this; + }; + + /** + * Add an OP_RETURN output to the transaction. + * + * Beware that this resets all the signatures for inputs (in further versions, + * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). + * + * @param {Buffer|string} value the data to be stored in the OP_RETURN output. + * In case of a string, the UTF-8 representation will be stored + * @return {Transaction} this, for chaining + */ + Transaction.prototype.addData = function(value) { + this.addOutput( + new Output({ + script: Script.buildDataOut(value), + micros: 0, + }), + ); + return this; + }; + + /** + * Add an output to the transaction. + * + * @param {Output} output the output to add. + * @return {Transaction} this, for chaining + */ + Transaction.prototype.addOutput = function(output) { + $.checkArgumentType(output, Output, 'output'); + this._addOutput(output); + this._updateChangeOutput(); + return this; + }; + + /** + * Remove all outputs from the transaction. + * + * @return {Transaction} this, for chaining + */ + Transaction.prototype.clearOutputs = function() { + this.outputs = []; + this._clearSignatures(); + this._outputAmount = undefined; + this._changeIndex = undefined; + this._updateChangeOutput(); + return this; + }; + + Transaction.prototype._addOutput = function(output) { + this.outputs.push(output); + this._outputAmount = undefined; + }; + + /** + * Calculates or gets the total output amount in micros + * + * @return {Number} the transaction total output amount + */ + Transaction.prototype._getOutputAmount = function() { + if (_.isUndefined(this._outputAmount)) { + var self = this; + this._outputAmount = 0; + _.each(this.outputs, function(output) { + self._outputAmount += output.micros; + }); + } + return this._outputAmount; + }; + + /** + * Calculates or gets the total input amount in micros + * + * @return {Number} the transaction total input amount + */ + Transaction.prototype._getInputAmount = function() { + if (_.isUndefined(this._inputAmount)) { + var self = this; + this._inputAmount = 0; + _.each(this.inputs, function(input) { + if (_.isUndefined(input.output)) { + throw new errors.Transaction.Input.MissingPreviousOutput(); + } + self._inputAmount += input.output.micros; + }); + } + return this._inputAmount; + }; - var indexes = HDPrivateKey._getDerivationIndexes(path); - var derived = indexes.reduce(function(prev, index) { - return prev._deriveWithNumber(index, null, nonCompliant); - }, this); + Transaction.prototype._updateChangeOutput = function() { + if (!this._changeScript) { + return; + } + this._clearSignatures(); + if (!_.isUndefined(this._changeIndex)) { + this._removeOutput(this._changeIndex); + } + var available = this._getUnspentValue(); + var fee = this.getFee(); + var changeAmount = available - fee; + if (changeAmount > 0) { + this._changeIndex = this.outputs.length; + this._addOutput( + new Output({ + script: this._changeScript, + micros: changeAmount, + }), + ); + } else { + this._changeIndex = undefined; + } + }; + /** + * Calculates the fee of the transaction. + * + * If there's a fixed fee set, return that. + * + * If there is no change output set, the fee is the + * total value of the outputs minus inputs. Note that + * a serialized transaction only specifies the value + * of its outputs. (The value of inputs are recorded + * in the previous transaction outputs being spent.) + * This method therefore raises a "MissingPreviousOutput" + * error when called on a serialized transaction. + * + * If there's no fee set and no change address, + * estimate the fee based on size. + * + * @return {Number} fee of this transaction in micros + */ + Transaction.prototype.getFee = function() { + if (this.isCoinbase()) { + return 0; + } + if (!_.isUndefined(this._fee)) { + return this._fee; + } + // if no change output is set, fees should equal all the unspent amount + if (!this._changeScript) { + return this._getUnspentValue(); + } + return this._estimateFee(); + }; + + /** + * Estimates fee from serialized transaction size in bytes. + */ + Transaction.prototype._estimateFee = function() { + var estimatedSize = this._estimateSize(); + var available = this._getUnspentValue(); + return Transaction._estimateFee(estimatedSize, available, this._feePerKb); + }; + + Transaction.prototype._getUnspentValue = function() { + return this._getInputAmount() - this._getOutputAmount(); + }; + + Transaction.prototype._clearSignatures = function() { + _.each(this.inputs, function(input) { + input.clearSignatures(); + }); + }; + + Transaction._estimateFee = function(size, amountAvailable, feePerKb) { + var fee = Math.ceil(size / 1000) * (feePerKb || Transaction.FEE_PER_KB); + if (amountAvailable > fee) { + size += Transaction.CHANGE_OUTPUT_MAX_SIZE; + } + return Math.ceil(size / 1000) * (feePerKb || Transaction.FEE_PER_KB); + }; + + Transaction.prototype._estimateSize = function() { + var result = Transaction.MAXIMUM_EXTRA_SIZE; + _.each(this.inputs, function(input) { + result += input._estimateSize(); + }); + _.each(this.outputs, function(output) { + result += output.script.toBuffer().length + 9; + }); + return result; + }; + + Transaction.prototype._removeOutput = function(index) { + var output = this.outputs[index]; + this.outputs = _.without(this.outputs, output); + this._outputAmount = undefined; + }; + + Transaction.prototype.removeOutput = function(index) { + this._removeOutput(index); + this._updateChangeOutput(); + }; + + /** + * Sort a transaction's inputs and outputs according to BIP69 + * + * @see {https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki} + * @return {Transaction} this + */ + Transaction.prototype.sort = function() { + this.sortInputs(function(inputs) { + var copy = Array.prototype.concat.apply([], inputs); + copy.sort(function(first, second) { + return compare(first.prevTxId, second.prevTxId) || first.outputIndex - second.outputIndex; + }); + return copy; + }); + this.sortOutputs(function(outputs) { + var copy = Array.prototype.concat.apply([], outputs); + copy.sort(function(first, second) { + return first.micros - second.micros || compare(first.script.toBuffer(), second.script.toBuffer()); + }); + return copy; + }); + return this; + }; + + /** + * Randomize this transaction's outputs ordering. The shuffling algorithm is a + * version of the Fisher-Yates shuffle, provided by lodash's _.shuffle(). + * + * @return {Transaction} this + */ + Transaction.prototype.shuffleOutputs = function() { + return this.sortOutputs(_.shuffle); + }; + + /** + * Sort this transaction's outputs, according to a given sorting function that + * takes an array as argument and returns a new array, with the same elements + * but with a different order. The argument function MUST NOT modify the order + * of the original array + * + * @param {Function} sortingFunction + * @return {Transaction} this + */ + Transaction.prototype.sortOutputs = function(sortingFunction) { + var outs = sortingFunction(this.outputs); + return this._newOutputOrder(outs); + }; + + /** + * Sort this transaction's inputs, according to a given sorting function that + * takes an array as argument and returns a new array, with the same elements + * but with a different order. + * + * @param {Function} sortingFunction + * @return {Transaction} this + */ + Transaction.prototype.sortInputs = function(sortingFunction) { + this.inputs = sortingFunction(this.inputs); + this._clearSignatures(); + return this; + }; + + Transaction.prototype._newOutputOrder = function(newOutputs) { + var isInvalidSorting = + this.outputs.length !== newOutputs.length || _.difference(this.outputs, newOutputs).length !== 0; + if (isInvalidSorting) { + throw new errors.Transaction.InvalidSorting(); + } - return derived; -}; + if (!_.isUndefined(this._changeIndex)) { + var changeOutput = this.outputs[this._changeIndex]; + this._changeIndex = _.findIndex(newOutputs, changeOutput); + } -/** - * Verifies that a given serialized private key in base58 with checksum format - * is valid. - * - * @param {string|Buffer} data - the serialized private key - * @param {string|Network=} network - optional, if present, checks that the - * network provided matches the network serialized. - * @return {boolean} - */ -HDPrivateKey.isValidSerialized = function(data, network) { - return !HDPrivateKey.getSerializedError(data, network); -}; + this.outputs = newOutputs; + return this; + }; -/** - * Checks what's the error that causes the validation of a serialized private key - * in base58 with checksum to fail. - * - * @param {string|Buffer} data - the serialized private key - * @param {string|Network=} network - optional, if present, checks that the - * network provided matches the network serialized. - * @return {errors.InvalidArgument|null} - */ -HDPrivateKey.getSerializedError = function(data, network) { - /* jshint maxcomplexity: 10 */ - if (!(_.isString(data) || BufferUtil.isBuffer(data))) { - return new hdErrors.UnrecognizedArgument('Expected string or buffer'); - } - if (!Base58.validCharacters(data)) { - return new errors.InvalidB58Char('(unknown)', data); - } - try { - data = Base58Check.decode(data); - } catch (e) { - return new errors.InvalidB58Checksum(data); - } - if (data.length !== HDPrivateKey.DataLength) { - return new hdErrors.InvalidLength(data); - } - if (!_.isUndefined(network)) { - var error = HDPrivateKey._validateNetwork(data, network); - if (error) { - return error; - } - } - return null; -}; + Transaction.prototype.removeInput = function(txId, outputIndex) { + var index; + if (!outputIndex && _.isNumber(txId)) { + index = txId; + } else { + index = _.findIndex(this.inputs, function(input) { + return input.prevTxId.toString('hex') === txId && input.outputIndex === outputIndex; + }); + } + if (index < 0 || index >= this.inputs.length) { + throw new errors.Transaction.InvalidIndex(index, this.inputs.length); + } + var input = this.inputs[index]; + this.inputs = _.without(this.inputs, input); + this._inputAmount = undefined; + this._updateChangeOutput(); + }; + + /* Signature handling */ + + /** + * Sign the transaction using one or more private keys. + * + * It tries to sign each input, verifying that the signature will be valid + * (matches a public key). + * + * @param {Array|String|PrivateKey} privateKey + * @param {number} sigtype + * @return {Transaction} this, for chaining + */ + Transaction.prototype.sign = function(privateKey, sigtype) { + $.checkState(this.hasAllUtxoInfo()); + var self = this; + if (_.isArray(privateKey)) { + _.each(privateKey, function(privateKey) { + self.sign(privateKey, sigtype); + }); + return this; + } + _.each(this.getSignatures(privateKey, sigtype), function(signature) { + self.applySignature(signature); + }); + return this; + }; + + Transaction.prototype.getSignatures = function(privKey, sigtype) { + privKey = new PrivateKey(privKey); + sigtype = sigtype || Signature.SIGHASH_ALL; + var transaction = this; + var results = []; + var hashData = Hash.sha256ripemd160(privKey.publicKey.toBuffer()); + _.each(this.inputs, function forEachInput(input, index) { + _.each(input.getSignatures(transaction, privKey, index, sigtype, hashData), function(signature) { + results.push(signature); + }); + }); + return results; + }; + + /** + * Add a signature to the transaction + * + * @param {Object} signature + * @param {number} signature.inputIndex + * @param {number} signature.sigtype + * @param {PublicKey} signature.publicKey + * @param {Signature} signature.signature + * @return {Transaction} this, for chaining + */ + Transaction.prototype.applySignature = function(signature) { + this.inputs[signature.inputIndex].addSignature(this, signature); + return this; + }; + + Transaction.prototype.isFullySigned = function() { + _.each(this.inputs, function(input) { + if (input.isFullySigned === Input.prototype.isFullySigned) { + throw new errors.Transaction.UnableToVerifySignature( + 'Unrecognized script kind, or not enough information to execute script.' + + 'This usually happens when creating a transaction from a serialized transaction', + ); + } + }); + return _.every( + _.map(this.inputs, function(input) { + return input.isFullySigned(); + }), + ); + }; + + Transaction.prototype.isValidSignature = function(signature) { + var self = this; + if (this.inputs[signature.inputIndex].isValidSignature === Input.prototype.isValidSignature) { + throw new errors.Transaction.UnableToVerifySignature( + 'Unrecognized script kind, or not enough information to execute script.' + + 'This usually happens when creating a transaction from a serialized transaction', + ); + } + return this.inputs[signature.inputIndex].isValidSignature(self, signature); + }; + + /** + * @returns {bool} whether the signature is valid for this transaction input + */ + Transaction.prototype.verifySignature = function(sig, pubkey, nin, subscript) { + return Sighash.verify(this, sig, pubkey, nin, subscript); + }; + + /** + * Check that a transaction passes basic sanity tests. If not, return a string + * describing the error. This function contains the same logic as + * CheckTransaction in Merit core. + */ + Transaction.prototype.verify = function() { + // Basic checks that don't depend on any context + if (this.inputs.length === 0) { + return 'transaction txins empty'; + } -HDPrivateKey._validateNetwork = function(data, networkArg) { - var network = Network.get(networkArg); - if (!network) { - return new errors.InvalidNetworkArgument(networkArg); - } - var version = data.slice(0, 4); - if (BufferUtil.integerFromBuffer(version) !== network.xprivkey) { - return new errors.InvalidNetwork(version); - } - return null; -}; - -HDPrivateKey.fromString = function(arg) { - $.checkArgument(_.isString(arg), 'No valid string was provided'); - return new HDPrivateKey(arg); -}; - -HDPrivateKey.fromObject = function(arg) { - $.checkArgument(_.isObject(arg), 'No valid argument was provided'); - return new HDPrivateKey(arg); -}; - -HDPrivateKey.prototype._buildFromJSON = function(arg) { - return this._buildFromObject(JSON.parse(arg)); -}; - -HDPrivateKey.prototype._buildFromObject = function(arg) { - /* jshint maxcomplexity: 12 */ - // TODO: Type validation - var buffers = { - version: arg.network ? BufferUtil.integerAsBuffer(Network.get(arg.network).xprivkey) : arg.version, - depth: _.isNumber(arg.depth) ? BufferUtil.integerAsSingleByteBuffer(arg.depth) : arg.depth, - parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? BufferUtil.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint, - childIndex: _.isNumber(arg.childIndex) ? BufferUtil.integerAsBuffer(arg.childIndex) : arg.childIndex, - chainCode: _.isString(arg.chainCode) ? BufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode, - privateKey: (_.isString(arg.privateKey) && JSUtil.isHexa(arg.privateKey)) ? BufferUtil.hexToBuffer(arg.privateKey) : arg.privateKey, - checksum: arg.checksum ? (arg.checksum.length ? arg.checksum : BufferUtil.integerAsBuffer(arg.checksum)) : undefined - }; - return this._buildFromBuffers(buffers); -}; - -HDPrivateKey.prototype._buildFromSerialized = function(arg) { - var decoded = Base58Check.decode(arg); - var buffers = { - version: decoded.slice(HDPrivateKey.VersionStart, HDPrivateKey.VersionEnd), - depth: decoded.slice(HDPrivateKey.DepthStart, HDPrivateKey.DepthEnd), - parentFingerPrint: decoded.slice(HDPrivateKey.ParentFingerPrintStart, - HDPrivateKey.ParentFingerPrintEnd), - childIndex: decoded.slice(HDPrivateKey.ChildIndexStart, HDPrivateKey.ChildIndexEnd), - chainCode: decoded.slice(HDPrivateKey.ChainCodeStart, HDPrivateKey.ChainCodeEnd), - privateKey: decoded.slice(HDPrivateKey.PrivateKeyStart, HDPrivateKey.PrivateKeyEnd), - checksum: decoded.slice(HDPrivateKey.ChecksumStart, HDPrivateKey.ChecksumEnd), - xprivkey: arg - }; - return this._buildFromBuffers(buffers); -}; - -HDPrivateKey.prototype._generateRandomly = function(network) { - return HDPrivateKey.fromSeed(Random.getRandomBuffer(64), network); -}; - -/** - * Generate a private key from a seed, as described in BIP32 - * - * @param {string|Buffer} hexa - * @param {*} network - * @return HDPrivateKey - */ -HDPrivateKey.fromSeed = function(hexa, network) { - /* jshint maxcomplexity: 8 */ - if (JSUtil.isHexaString(hexa)) { - hexa = BufferUtil.hexToBuffer(hexa); - } - if (!Buffer.isBuffer(hexa)) { - throw new hdErrors.InvalidEntropyArgument(hexa); - } - if (hexa.length < MINIMUM_ENTROPY_BITS * BITS_TO_BYTES) { - throw new hdErrors.InvalidEntropyArgument.NotEnoughEntropy(hexa); - } - if (hexa.length > MAXIMUM_ENTROPY_BITS * BITS_TO_BYTES) { - throw new hdErrors.InvalidEntropyArgument.TooMuchEntropy(hexa); - } - var hash = Hash.sha512hmac(hexa, new buffer.Buffer('Merit seed')); + if (this.outputs.length === 0) { + return 'transaction txouts empty'; + } - return new HDPrivateKey({ - network: Network.get(network) || Network.defaultNetwork, - depth: 0, - parentFingerPrint: 0, - childIndex: 0, - privateKey: hash.slice(0, 32), - chainCode: hash.slice(32, 64) - }); -}; + // Check for negative or overflow output values + var valueoutbn = new BN(0); + for (var i = 0; i < this.outputs.length; i++) { + var txout = this.outputs[i]; + if (txout.invalidMicros()) { + return 'transaction txout ' + i + ' micros is invalid'; + } + if (txout._microsBN.gt(new BN(Transaction.MAX_MONEY, 10))) { + return 'transaction txout ' + i + ' greater than MAX_MONEY'; + } + valueoutbn = valueoutbn.add(txout._microsBN); + if (valueoutbn.gt(new BN(Transaction.MAX_MONEY))) { + return 'transaction txout ' + i + ' total output greater than MAX_MONEY'; + } + } + // Size limits + if (this.toBuffer().length > MAX_BLOCK_SIZE) { + return 'transaction over the maximum block size'; + } -HDPrivateKey.prototype._calcHDPublicKey = function() { - if (!this._hdPublicKey) { - var HDPublicKey = require('./hdpublickey'); - this._hdPublicKey = new HDPublicKey(this); - } -}; + // Check for duplicate inputs + var txinmap = {}; + for (i = 0; i < this.inputs.length; i++) { + var txin = this.inputs[i]; -/** - * Receives a object with buffers in all the properties and populates the - * internal structure - * - * @param {Object} arg - * @param {buffer.Buffer} arg.version - * @param {buffer.Buffer} arg.depth - * @param {buffer.Buffer} arg.parentFingerPrint - * @param {buffer.Buffer} arg.childIndex - * @param {buffer.Buffer} arg.chainCode - * @param {buffer.Buffer} arg.privateKey - * @param {buffer.Buffer} arg.checksum - * @param {string=} arg.xprivkey - if set, don't recalculate the base58 - * representation - * @return {HDPrivateKey} this - */ -HDPrivateKey.prototype._buildFromBuffers = function(arg) { - /* jshint maxcomplexity: 8 */ - /* jshint maxstatements: 20 */ + var inputid = txin.prevTxId + ':' + txin.outputIndex; + if (!_.isUndefined(txinmap[inputid])) { + return 'transaction input ' + i + ' duplicate input'; + } + txinmap[inputid] = true; + } - HDPrivateKey._validateBufferArguments(arg); + var isCoinbase = this.isCoinbase(); + if (isCoinbase) { + var buf = this.inputs[0]._scriptBuffer; + if (buf.length < 2 || buf.length > 100) { + return 'coinbase transaction script size invalid'; + } + } else { + for (i = 0; i < this.inputs.length; i++) { + if (this.inputs[i].isNull()) { + return 'transaction input ' + i + ' has null input'; + } + } + } + return true; + }; + + /** + * Analogous to bitcoind's IsCoinBase function in transaction.h + */ + Transaction.prototype.isCoinbase = function() { + return this.inputs.length === 1 && this.inputs[0].isNull(); + }; + + /** + * Determines if this transaction can be replaced in the mempool with another + * transaction that provides a sufficiently higher fee (RBF). + */ + Transaction.prototype.isRBF = function() { + for (var i = 0; i < this.inputs.length; i++) { + var input = this.inputs[i]; + if (input.sequenceNumber < Input.MAXINT - 1) { + return true; + } + } + return false; + }; + + /** + * Enable this transaction to be replaced in the mempool (RBF) if a transaction + * includes a sufficiently higher fee. It will set the sequenceNumber to + * DEFAULT_RBF_SEQNUMBER for all inputs if the sequence number does not + * already enable RBF. + */ + Transaction.prototype.enableRBF = function() { + for (var i = 0; i < this.inputs.length; i++) { + var input = this.inputs[i]; + if (input.sequenceNumber >= Input.MAXINT - 1) { + input.sequenceNumber = Input.DEFAULT_RBF_SEQNUMBER; + } + } + return this; + }; - JSUtil.defineImmutable(this, { - _buffers: arg - }); + module.exports = Transaction; + }.call(this, require('buffer').Buffer)); + }, + { + '../address': 1, + '../crypto/bn': 6, + '../crypto/hash': 8, + '../crypto/signature': 11, + '../encoding/bufferreader': 14, + '../encoding/bufferwriter': 15, + '../errors': 17, + '../privatekey': 23, + '../script': 25, + '../util/buffer': 42, + '../util/js': 43, + '../util/preconditions': 44, + './input': 29, + './output': 35, + './sighash': 36, + './unspentoutput': 39, + buffer: 113, + 'buffer-compare': 111, + lodash: 187, + }, + ], + 39: [ + function(require, module, exports) { + 'use strict'; - var sequence = [ - arg.version, arg.depth, arg.parentFingerPrint, arg.childIndex, arg.chainCode, - BufferUtil.emptyBuffer(1), arg.privateKey - ]; - var concat = buffer.Buffer.concat(sequence); - if (!arg.checksum || !arg.checksum.length) { - arg.checksum = Base58Check.checksum(concat); - } else { - if (arg.checksum.toString() !== Base58Check.checksum(concat).toString()) { - throw new errors.InvalidB58Checksum(concat); - } - } + var _ = require('lodash'); + var $ = require('../util/preconditions'); + var JSUtil = require('../util/js'); - var network = Network.get(BufferUtil.integerFromBuffer(arg.version)); - var xprivkey; - xprivkey = Base58Check.encode(buffer.Buffer.concat(sequence)); - arg.xprivkey = new Buffer(xprivkey); - - var privateKey = new PrivateKey(BN.fromBuffer(arg.privateKey), network); - var publicKey = privateKey.toPublicKey(); - var size = HDPrivateKey.ParentFingerPrintSize; - var fingerPrint = Hash.sha256ripemd160(publicKey.toBuffer()).slice(0, size); - - JSUtil.defineImmutable(this, { - xprivkey: xprivkey, - network: network, - depth: BufferUtil.integerFromSingleByteBuffer(arg.depth), - privateKey: privateKey, - publicKey: publicKey, - fingerPrint: fingerPrint - }); - - this._hdPublicKey = null; - - Object.defineProperty(this, 'hdPublicKey', { - configurable: false, - enumerable: true, - get: function() { - this._calcHDPublicKey(); - return this._hdPublicKey; - } - }); - Object.defineProperty(this, 'xpubkey', { - configurable: false, - enumerable: true, - get: function() { - this._calcHDPublicKey(); - return this._hdPublicKey.xpubkey; - } - }); - return this; -}; - -HDPrivateKey._validateBufferArguments = function(arg) { - var checkBuffer = function(name, size) { - var buff = arg[name]; - assert(BufferUtil.isBuffer(buff), name + ' argument is not a buffer'); - assert( - buff.length === size, - name + ' has not the expected size: found ' + buff.length + ', expected ' + size - ); - }; - checkBuffer('version', HDPrivateKey.VersionSize); - checkBuffer('depth', HDPrivateKey.DepthSize); - checkBuffer('parentFingerPrint', HDPrivateKey.ParentFingerPrintSize); - checkBuffer('childIndex', HDPrivateKey.ChildIndexSize); - checkBuffer('chainCode', HDPrivateKey.ChainCodeSize); - checkBuffer('privateKey', HDPrivateKey.PrivateKeySize); - if (arg.checksum && arg.checksum.length) { - checkBuffer('checksum', HDPrivateKey.CheckSumSize); - } -}; + var Script = require('../script'); + var Address = require('../address'); + var Unit = require('../unit'); -/** - * Returns the string representation of this private key (a string starting - * with "xprv..." - * - * @return string - */ -HDPrivateKey.prototype.toString = function() { - return this.xprivkey; -}; + /** + * Represents an unspent output information: its script, associated amount and address, + * transaction id and output index. + * + * @constructor + * @param {object} data + * @param {string} data.txid the previous transaction id + * @param {string=} data.txId alias for `txid` + * @param {number} data.vout the index in the transaction + * @param {number=} data.outputIndex alias for `vout` + * @param {string|Script} data.scriptPubKey the script that must be resolved to release the funds + * @param {string|Script=} data.script alias for `scriptPubKey` + * @param {number} data.amount amount of bitcoins associated + * @param {number=} data.micros alias for `amount`, but expressed in micros (1 MRT = 1e8 micros) + * @param {string|Address=} data.address the associated address to the script, if provided + */ + function UnspentOutput(data) { + /* jshint maxcomplexity: 20 */ + /* jshint maxstatements: 20 */ + if (!(this instanceof UnspentOutput)) { + return new UnspentOutput(data); + } + $.checkArgument(_.isObject(data), 'Must provide an object from where to extract data'); + var address = data.address ? new Address(data.address) : undefined; + var txId = data.txid ? data.txid : data.txId; + if (!txId || !JSUtil.isHexaString(txId) || txId.length > 64) { + // TODO: Use the errors library + throw new Error('Invalid TXID in object', data); + } + var outputIndex = _.isUndefined(data.vout) ? data.outputIndex : data.vout; + if (!_.isNumber(outputIndex)) { + throw new Error('Invalid outputIndex, received ' + outputIndex); + } + $.checkArgument( + !_.isUndefined(data.scriptPubKey) || !_.isUndefined(data.script), + 'Must provide the scriptPubKey for that output!', + ); + var script = new Script(data.scriptPubKey || data.script); + $.checkArgument( + !_.isUndefined(data.amount) || !_.isUndefined(data.micros), + 'Must provide an amount for the output', + ); + var amount = !_.isUndefined(data.amount) ? new Unit.fromMRT(data.amount).toMicros() : data.micros; + $.checkArgument(_.isNumber(amount), 'Amount must be a number'); + JSUtil.defineImmutable(this, { + address: address, + txId: txId, + outputIndex: outputIndex, + script: script, + micros: amount, + }); + } -/** - * Returns the console representation of this extended private key. - * @return string - */ -HDPrivateKey.prototype.inspect = function() { - return ''; -}; + /** + * Provide an informative output when displaying this object in the console + * @returns string + */ + UnspentOutput.prototype.inspect = function() { + return ( + '' + ); + }; -/** - * Returns a plain object with a representation of this private key. - * - * Fields include:
    - *
  • network: either 'livenet' or 'testnet' - *
  • depth: a number ranging from 0 to 255 - *
  • fingerPrint: a number ranging from 0 to 2^32-1, taken from the hash of the - *
  • associated public key - *
  • parentFingerPrint: a number ranging from 0 to 2^32-1, taken from the hash - *
  • of this parent's associated public key or zero. - *
  • childIndex: the index from which this child was derived (or zero) - *
  • chainCode: an hexa string representing a number used in the derivation - *
  • privateKey: the private key associated, in hexa representation - *
  • xprivkey: the representation of this extended private key in checksum - *
  • base58 format - *
  • checksum: the base58 checksum of xprivkey - *
- * @return {Object} - */ -HDPrivateKey.prototype.toObject = HDPrivateKey.prototype.toJSON = function toObject() { - return { - network: Network.get(BufferUtil.integerFromBuffer(this._buffers.version), 'xprivkey').name, - depth: BufferUtil.integerFromSingleByteBuffer(this._buffers.depth), - fingerPrint: BufferUtil.integerFromBuffer(this.fingerPrint), - parentFingerPrint: BufferUtil.integerFromBuffer(this._buffers.parentFingerPrint), - childIndex: BufferUtil.integerFromBuffer(this._buffers.childIndex), - chainCode: BufferUtil.bufferToHex(this._buffers.chainCode), - privateKey: this.privateKey.toBuffer().toString('hex'), - checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), - xprivkey: this.xprivkey - }; -}; - -/** - * Build a HDPrivateKey from a buffer - * - * @param {Buffer} arg - * @return {HDPrivateKey} - */ -HDPrivateKey.fromBuffer = function(arg) { - return new HDPrivateKey(arg.toString()); -}; + /** + * String representation: just "txid:index" + * @returns string + */ + UnspentOutput.prototype.toString = function() { + return this.txId + ':' + this.outputIndex; + }; -/** - * Returns a buffer representation of the HDPrivateKey - * - * @return {string} - */ -HDPrivateKey.prototype.toBuffer = function() { - return BufferUtil.copy(this._buffers.xprivkey); -}; - -HDPrivateKey.DefaultDepth = 0; -HDPrivateKey.DefaultFingerprint = 0; -HDPrivateKey.DefaultChildIndex = 0; -HDPrivateKey.Hardened = 0x80000000; -HDPrivateKey.MaxIndex = 2 * HDPrivateKey.Hardened; - -HDPrivateKey.RootElementAlias = ['m', 'M', 'm\'', 'M\'']; - -HDPrivateKey.VersionSize = 4; -HDPrivateKey.DepthSize = 1; -HDPrivateKey.ParentFingerPrintSize = 4; -HDPrivateKey.ChildIndexSize = 4; -HDPrivateKey.ChainCodeSize = 32; -HDPrivateKey.PrivateKeySize = 32; -HDPrivateKey.CheckSumSize = 4; - -HDPrivateKey.DataLength = 78; -HDPrivateKey.SerializedByteSize = 82; - -HDPrivateKey.VersionStart = 0; -HDPrivateKey.VersionEnd = HDPrivateKey.VersionStart + HDPrivateKey.VersionSize; -HDPrivateKey.DepthStart = HDPrivateKey.VersionEnd; -HDPrivateKey.DepthEnd = HDPrivateKey.DepthStart + HDPrivateKey.DepthSize; -HDPrivateKey.ParentFingerPrintStart = HDPrivateKey.DepthEnd; -HDPrivateKey.ParentFingerPrintEnd = HDPrivateKey.ParentFingerPrintStart + HDPrivateKey.ParentFingerPrintSize; -HDPrivateKey.ChildIndexStart = HDPrivateKey.ParentFingerPrintEnd; -HDPrivateKey.ChildIndexEnd = HDPrivateKey.ChildIndexStart + HDPrivateKey.ChildIndexSize; -HDPrivateKey.ChainCodeStart = HDPrivateKey.ChildIndexEnd; -HDPrivateKey.ChainCodeEnd = HDPrivateKey.ChainCodeStart + HDPrivateKey.ChainCodeSize; -HDPrivateKey.PrivateKeyStart = HDPrivateKey.ChainCodeEnd + 1; -HDPrivateKey.PrivateKeyEnd = HDPrivateKey.PrivateKeyStart + HDPrivateKey.PrivateKeySize; -HDPrivateKey.ChecksumStart = HDPrivateKey.PrivateKeyEnd; -HDPrivateKey.ChecksumEnd = HDPrivateKey.ChecksumStart + HDPrivateKey.CheckSumSize; - -assert(HDPrivateKey.ChecksumEnd === HDPrivateKey.SerializedByteSize); - -module.exports = HDPrivateKey; - -}).call(this,require("buffer").Buffer) -},{"./crypto/bn":6,"./crypto/hash":8,"./crypto/point":9,"./crypto/random":10,"./encoding/base58":12,"./encoding/base58check":13,"./errors":17,"./hdpublickey":20,"./networks":21,"./privatekey":23,"./util/buffer":42,"./util/js":43,"./util/preconditions":44,"assert":60,"buffer":113,"lodash":187}],20:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var $ = require('./util/preconditions'); - -var BN = require('./crypto/bn'); -var Base58 = require('./encoding/base58'); -var Base58Check = require('./encoding/base58check'); -var Hash = require('./crypto/hash'); -var HDPrivateKey = require('./hdprivatekey'); -var Network = require('./networks'); -var Point = require('./crypto/point'); -var PublicKey = require('./publickey'); - -var bitcoreErrors = require('./errors'); -var errors = bitcoreErrors; -var hdErrors = bitcoreErrors.HDPublicKey; -var assert = require('assert'); - -var JSUtil = require('./util/js'); -var BufferUtil = require('./util/buffer'); - -/** - * The representation of an hierarchically derived public key. - * - * See https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki - * - * @constructor - * @param {Object|string|Buffer} arg - */ -function HDPublicKey(arg) { - /* jshint maxcomplexity: 12 */ - /* jshint maxstatements: 20 */ - if (arg instanceof HDPublicKey) { - return arg; - } - if (!(this instanceof HDPublicKey)) { - return new HDPublicKey(arg); - } - if (arg) { - if (_.isString(arg) || BufferUtil.isBuffer(arg)) { - var error = HDPublicKey.getSerializedError(arg); - if (!error) { - return this._buildFromSerialized(arg); - } else if (BufferUtil.isBuffer(arg) && !HDPublicKey.getSerializedError(arg.toString())) { - return this._buildFromSerialized(arg.toString()); - } else { - if (error instanceof hdErrors.ArgumentIsPrivateExtended) { - return new HDPrivateKey(arg).hdPublicKey; - } - throw error; - } - } else { - if (_.isObject(arg)) { - if (arg instanceof HDPrivateKey) { - return this._buildFromPrivate(arg); - } else { - return this._buildFromObject(arg); + /** + * Deserialize an UnspentOutput from an object + * @param {object|string} data + * @return UnspentOutput + */ + UnspentOutput.fromObject = function(data) { + return new UnspentOutput(data); + }; + + /** + * Returns a plain object (no prototype or methods) with the associated info for this output + * @return {object} + */ + UnspentOutput.prototype.toObject = UnspentOutput.prototype.toJSON = function toObject() { + return { + address: this.address ? this.address.toString() : undefined, + txid: this.txId, + vout: this.outputIndex, + scriptPubKey: this.script.toBuffer().toString('hex'), + amount: Unit.fromMicros(this.micros).toMRT(), + }; + }; + + module.exports = UnspentOutput; + }, + { '../address': 1, '../script': 25, '../unit': 40, '../util/js': 43, '../util/preconditions': 44, lodash: 187 }, + ], + 40: [ + function(require, module, exports) { + 'use strict'; + + var _ = require('lodash'); + + var errors = require('./errors'); + var $ = require('./util/preconditions'); + + var UNITS = { + MRT: [1e8, 8], + mMRT: [1e5, 5], + uMRT: [1e2, 2], + bits: [1e2, 2], + micros: [1, 0], + }; + + /** + * Utility for handling and converting bitcoins units. The supported units are + * MRT, mMRT, bits (also named uMRT) and micros. A unit instance can be created with an + * amount and a unit code, or alternatively using static methods like {fromMRT}. + * It also allows to be created from a fiat amount and the exchange rate, or + * alternatively using the {fromFiat} static method. + * You can consult for different representation of a unit instance using it's + * {to} method, the fixed unit methods like {toMicros} or alternatively using + * the unit accessors. It also can be converted to a fiat amount by providing the + * corresponding MRT/fiat exchange rate. + * + * @example + * ```javascript + * var micros = Unit.fromMRT(1.3).toMicros(); + * var mili = Unit.fromBits(1.3).to(Unit.mMRT); + * var bits = Unit.fromFiat(1.3, 350).bits; + * var mrt = new Unit(1.3, Unit.bits).MRT; + * ``` + * + * @param {Number} amount - The amount to be represented + * @param {String|Number} code - The unit of the amount or the exchange rate + * @returns {Unit} A new instance of an Unit + * @constructor + */ + function Unit(amount, code) { + if (!(this instanceof Unit)) { + return new Unit(amount, code); + } + + // convert fiat to MRT + if (_.isNumber(code)) { + if (code <= 0) { + throw new errors.Unit.InvalidRate(code); + } + amount = amount / code; + code = Unit.MRT; + } + + this._value = this._from(amount, code); + + var self = this; + var defineAccesor = function(key) { + Object.defineProperty(self, key, { + get: function() { + return self.to(key); + }, + enumerable: true, + }); + }; + + Object.keys(UNITS).forEach(defineAccesor); } - } else { - throw new hdErrors.UnrecognizedArgument(arg); - } - } - } else { - throw new hdErrors.MustSupplyArgument(); - } -} -/** - * Verifies that a given path is valid. - * - * @param {string|number} arg - * @return {boolean} - */ -HDPublicKey.isValidPath = function(arg) { - if (_.isString(arg)) { - var indexes = HDPrivateKey._getDerivationIndexes(arg); - return indexes !== null && _.every(indexes, HDPublicKey.isValidPath); - } + Object.keys(UNITS).forEach(function(key) { + Unit[key] = key; + }); - if (_.isNumber(arg)) { - return arg >= 0 && arg < HDPublicKey.Hardened; - } + /** + * Returns a Unit instance created from JSON string or object + * + * @param {String|Object} json - JSON with keys: amount and code + * @returns {Unit} A Unit instance + */ + Unit.fromObject = function fromObject(data) { + $.checkArgument(_.isObject(data), 'Argument is expected to be an object'); + return new Unit(data.amount, data.code); + }; - return false; -}; + /** + * Returns a Unit instance created from an amount in MRT + * + * @param {Number} amount - The amount in MRT + * @returns {Unit} A Unit instance + */ + Unit.fromMRT = function(amount) { + return new Unit(amount, Unit.MRT); + }; -/** - * WARNING: This method is deprecated. Use deriveChild instead. - * - * - * Get a derivated child based on a string or number. - * - * If the first argument is a string, it's parsed as the full path of - * derivation. Valid values for this argument include "m" (which returns the - * same public key), "m/0/1/40/2/1000". - * - * Note that hardened keys can't be derived from a public extended key. - * - * If the first argument is a number, the child with that index will be - * derived. See the example usage for clarification. - * - * @example - * ```javascript - * var parent = new HDPublicKey('xpub...'); - * var child_0_1_2 = parent.derive(0).derive(1).derive(2); - * var copy_of_child_0_1_2 = parent.derive("m/0/1/2"); - * assert(child_0_1_2.xprivkey === copy_of_child_0_1_2); - * ``` - * - * @param {string|number} arg - */ -HDPublicKey.prototype.derive = function(arg, hardened) { - return this.deriveChild(arg, hardened); -}; + /** + * Returns a Unit instance created from an amount in mMRT + * + * @param {Number} amount - The amount in mMRT + * @returns {Unit} A Unit instance + */ + Unit.fromMillis = Unit.fromMilis = function(amount) { + return new Unit(amount, Unit.mMRT); + }; -/** - * WARNING: This method will not be officially supported until v1.0.0. - * - * - * Get a derivated child based on a string or number. - * - * If the first argument is a string, it's parsed as the full path of - * derivation. Valid values for this argument include "m" (which returns the - * same public key), "m/0/1/40/2/1000". - * - * Note that hardened keys can't be derived from a public extended key. - * - * If the first argument is a number, the child with that index will be - * derived. See the example usage for clarification. - * - * @example - * ```javascript - * var parent = new HDPublicKey('xpub...'); - * var child_0_1_2 = parent.deriveChild(0).deriveChild(1).deriveChild(2); - * var copy_of_child_0_1_2 = parent.deriveChild("m/0/1/2"); - * assert(child_0_1_2.xprivkey === copy_of_child_0_1_2); - * ``` - * - * @param {string|number} arg - */ -HDPublicKey.prototype.deriveChild = function(arg, hardened) { - if (_.isNumber(arg)) { - return this._deriveWithNumber(arg, hardened); - } else if (_.isString(arg)) { - return this._deriveFromString(arg); - } else { - throw new hdErrors.InvalidDerivationArgument(arg); - } -}; + /** + * Returns a Unit instance created from an amount in bits + * + * @param {Number} amount - The amount in bits + * @returns {Unit} A Unit instance + */ + Unit.fromMicros = Unit.fromBits = function(amount) { + return new Unit(amount, Unit.bits); + }; -HDPublicKey.prototype._deriveWithNumber = function(index, hardened) { - if (index >= HDPublicKey.Hardened || hardened) { - throw new hdErrors.InvalidIndexCantDeriveHardened(); - } - if (index < 0) { - throw new hdErrors.InvalidPath(index); - } + /** + * Returns a Unit instance created from an amount in micros + * + * @param {Number} amount - The amount in micros + * @returns {Unit} A Unit instance + */ + Unit.fromMicros = function(amount) { + return new Unit(amount, Unit.micros); + }; - var indexBuffer = BufferUtil.integerAsBuffer(index); - var data = BufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]); - var hash = Hash.sha512hmac(data, this._buffers.chainCode); - var leftPart = BN.fromBuffer(hash.slice(0, 32), {size: 32}); - var chainCode = hash.slice(32, 64); - - var publicKey; - try { - publicKey = PublicKey.fromPoint(Point.getG().mul(leftPart).add(this.publicKey.point)); - } catch (e) { - return this._deriveWithNumber(index + 1); - } + /** + * Returns a Unit instance created from a fiat amount and exchange rate. + * + * @param {Number} amount - The amount in fiat + * @param {Number} rate - The exchange rate MRT/fiat + * @returns {Unit} A Unit instance + */ + Unit.fromFiat = function(amount, rate) { + return new Unit(amount, rate); + }; - var derived = new HDPublicKey({ - network: this.network, - depth: this.depth + 1, - parentFingerPrint: this.fingerPrint, - childIndex: index, - chainCode: chainCode, - publicKey: publicKey - }); - - return derived; -}; - -HDPublicKey.prototype._deriveFromString = function(path) { - /* jshint maxcomplexity: 8 */ - if (_.includes(path, "'")) { - throw new hdErrors.InvalidIndexCantDeriveHardened(); - } else if (!HDPublicKey.isValidPath(path)) { - throw new hdErrors.InvalidPath(path); - } + Unit.prototype._from = function(amount, code) { + if (!UNITS[code]) { + throw new errors.Unit.UnknownCode(code); + } + return parseInt((amount * UNITS[code][0]).toFixed()); + }; + + /** + * Returns the value represented in the specified unit + * + * @param {String|Number} code - The unit code or exchange rate + * @returns {Number} The converted value + */ + Unit.prototype.to = function(code) { + if (_.isNumber(code)) { + if (code <= 0) { + throw new errors.Unit.InvalidRate(code); + } + return parseFloat((this.MRT * code).toFixed(2)); + } + + if (!UNITS[code]) { + throw new errors.Unit.UnknownCode(code); + } + + var value = this._value / UNITS[code][0]; + return parseFloat(value.toFixed(UNITS[code][1])); + }; + + /** + * Returns the value represented in MRT + * + * @returns {Number} The value converted to MRT + */ + Unit.prototype.toMRT = function() { + return this.to(Unit.MRT); + }; + + /** + * Returns the value represented in mMRT + * + * @returns {Number} The value converted to mMRT + */ + Unit.prototype.toMillis = Unit.prototype.toMilis = function() { + return this.to(Unit.mMRT); + }; - var indexes = HDPrivateKey._getDerivationIndexes(path); - var derived = indexes.reduce(function(prev, index) { - return prev._deriveWithNumber(index); - }, this); + /** + * Returns the value represented in bits + * + * @returns {Number} The value converted to bits + */ + Unit.prototype.toMicros = Unit.prototype.toBits = function() { + return this.to(Unit.bits); + }; + + /** + * Returns the value represented in micros + * + * @returns {Number} The value converted to micros + */ + Unit.prototype.toMicros = function() { + return this.to(Unit.micros); + }; + + /** + * Returns the value represented in fiat + * + * @param {string} rate - The exchange rate between MRT/currency + * @returns {Number} The value converted to micros + */ + Unit.prototype.atRate = function(rate) { + return this.to(rate); + }; - return derived; -}; + /** + * Returns a the string representation of the value in micros + * + * @returns {string} the value in micros + */ + Unit.prototype.toString = function() { + return this.micros + ' micros'; + }; -/** - * Verifies that a given serialized public key in base58 with checksum format - * is valid. - * - * @param {string|Buffer} data - the serialized public key - * @param {string|Network=} network - optional, if present, checks that the - * network provided matches the network serialized. - * @return {boolean} - */ -HDPublicKey.isValidSerialized = function(data, network) { - return _.isNull(HDPublicKey.getSerializedError(data, network)); -}; + /** + * Returns a plain object representation of the Unit + * + * @returns {Object} An object with the keys: amount and code + */ + Unit.prototype.toObject = Unit.prototype.toJSON = function toObject() { + return { + amount: this.MRT, + code: Unit.MRT, + }; + }; -/** - * Checks what's the error that causes the validation of a serialized public key - * in base58 with checksum to fail. - * - * @param {string|Buffer} data - the serialized public key - * @param {string|Network=} network - optional, if present, checks that the - * network provided matches the network serialized. - * @return {errors|null} - */ -HDPublicKey.getSerializedError = function(data, network) { - /* jshint maxcomplexity: 10 */ - /* jshint maxstatements: 20 */ - if (!(_.isString(data) || BufferUtil.isBuffer(data))) { - return new hdErrors.UnrecognizedArgument('expected buffer or string'); - } - if (!Base58.validCharacters(data)) { - return new errors.InvalidB58Char('(unknown)', data); - } - try { - data = Base58Check.decode(data); - } catch (e) { - return new errors.InvalidB58Checksum(data); - } - if (data.length !== HDPublicKey.DataSize) { - return new hdErrors.InvalidLength(data); - } - if (!_.isUndefined(network)) { - var error = HDPublicKey._validateNetwork(data, network); - if (error) { - return error; - } - } - var version = BufferUtil.integerFromBuffer(data.slice(0, 4)); - if (version === Network.livenet.xprivkey || version === Network.testnet.xprivkey ) { - return new hdErrors.ArgumentIsPrivateExtended(); - } - return null; -}; + /** + * Returns a string formatted for the console + * + * @returns {string} the value in micros + */ + Unit.prototype.inspect = function() { + return ''; + }; -HDPublicKey._validateNetwork = function(data, networkArg) { - var network = Network.get(networkArg); - if (!network) { - return new errors.InvalidNetworkArgument(networkArg); - } - var version = data.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd); - if (BufferUtil.integerFromBuffer(version) !== network.xpubkey) { - return new errors.InvalidNetwork(version); - } - return null; -}; - -HDPublicKey.prototype._buildFromPrivate = function (arg) { - var args = _.clone(arg._buffers); - var point = Point.getG().mul(BN.fromBuffer(args.privateKey)); - args.publicKey = Point.pointToCompressed(point); - args.version = BufferUtil.integerAsBuffer(Network.get(BufferUtil.integerFromBuffer(args.version)).xpubkey); - args.privateKey = undefined; - args.checksum = undefined; - args.xprivkey = undefined; - return this._buildFromBuffers(args); -}; - -HDPublicKey.prototype._buildFromObject = function(arg) { - /* jshint maxcomplexity: 10 */ - // TODO: Type validation - var buffers = { - version: arg.network ? BufferUtil.integerAsBuffer(Network.get(arg.network).xpubkey) : arg.version, - depth: _.isNumber(arg.depth) ? BufferUtil.integerAsSingleByteBuffer(arg.depth) : arg.depth, - parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? BufferUtil.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint, - childIndex: _.isNumber(arg.childIndex) ? BufferUtil.integerAsBuffer(arg.childIndex) : arg.childIndex, - chainCode: _.isString(arg.chainCode) ? BufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode, - publicKey: _.isString(arg.publicKey) ? BufferUtil.hexToBuffer(arg.publicKey) : - BufferUtil.isBuffer(arg.publicKey) ? arg.publicKey : arg.publicKey.toBuffer(), - checksum: _.isNumber(arg.checksum) ? BufferUtil.integerAsBuffer(arg.checksum) : arg.checksum - }; - return this._buildFromBuffers(buffers); -}; - -HDPublicKey.prototype._buildFromSerialized = function(arg) { - var decoded = Base58Check.decode(arg); - var buffers = { - version: decoded.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd), - depth: decoded.slice(HDPublicKey.DepthStart, HDPublicKey.DepthEnd), - parentFingerPrint: decoded.slice(HDPublicKey.ParentFingerPrintStart, - HDPublicKey.ParentFingerPrintEnd), - childIndex: decoded.slice(HDPublicKey.ChildIndexStart, HDPublicKey.ChildIndexEnd), - chainCode: decoded.slice(HDPublicKey.ChainCodeStart, HDPublicKey.ChainCodeEnd), - publicKey: decoded.slice(HDPublicKey.PublicKeyStart, HDPublicKey.PublicKeyEnd), - checksum: decoded.slice(HDPublicKey.ChecksumStart, HDPublicKey.ChecksumEnd), - xpubkey: arg - }; - return this._buildFromBuffers(buffers); -}; - -/** - * Receives a object with buffers in all the properties and populates the - * internal structure - * - * @param {Object} arg - * @param {buffer.Buffer} arg.version - * @param {buffer.Buffer} arg.depth - * @param {buffer.Buffer} arg.parentFingerPrint - * @param {buffer.Buffer} arg.childIndex - * @param {buffer.Buffer} arg.chainCode - * @param {buffer.Buffer} arg.publicKey - * @param {buffer.Buffer} arg.checksum - * @param {string=} arg.xpubkey - if set, don't recalculate the base58 - * representation - * @return {HDPublicKey} this - */ -HDPublicKey.prototype._buildFromBuffers = function(arg) { - /* jshint maxcomplexity: 8 */ - /* jshint maxstatements: 20 */ + module.exports = Unit; + }, + { './errors': 17, './util/preconditions': 44, lodash: 187 }, + ], + 41: [ + function(require, module, exports) { + 'use strict'; - HDPublicKey._validateBufferArguments(arg); + var _ = require('lodash'); + var URL = require('url'); - JSUtil.defineImmutable(this, { - _buffers: arg - }); + var Address = require('./address'); + var Unit = require('./unit'); - var sequence = [ - arg.version, arg.depth, arg.parentFingerPrint, arg.childIndex, arg.chainCode, - arg.publicKey - ]; - var concat = BufferUtil.concat(sequence); - var checksum = Base58Check.checksum(concat); - if (!arg.checksum || !arg.checksum.length) { - arg.checksum = checksum; - } else { - if (arg.checksum.toString('hex') !== checksum.toString('hex')) { - throw new errors.InvalidB58Checksum(concat, checksum); - } - } - var network = Network.get(BufferUtil.integerFromBuffer(arg.version)); - - var xpubkey; - xpubkey = Base58Check.encode(BufferUtil.concat(sequence)); - arg.xpubkey = new Buffer(xpubkey); - - var publicKey = new PublicKey(arg.publicKey, {network: network}); - var size = HDPublicKey.ParentFingerPrintSize; - var fingerPrint = Hash.sha256ripemd160(publicKey.toBuffer()).slice(0, size); - - JSUtil.defineImmutable(this, { - xpubkey: xpubkey, - network: network, - depth: BufferUtil.integerFromSingleByteBuffer(arg.depth), - publicKey: publicKey, - fingerPrint: fingerPrint - }); - - return this; -}; - -HDPublicKey._validateBufferArguments = function(arg) { - var checkBuffer = function(name, size) { - var buff = arg[name]; - assert(BufferUtil.isBuffer(buff), name + ' argument is not a buffer, it\'s ' + typeof buff); - assert( - buff.length === size, - name + ' has not the expected size: found ' + buff.length + ', expected ' + size - ); - }; - checkBuffer('version', HDPublicKey.VersionSize); - checkBuffer('depth', HDPublicKey.DepthSize); - checkBuffer('parentFingerPrint', HDPublicKey.ParentFingerPrintSize); - checkBuffer('childIndex', HDPublicKey.ChildIndexSize); - checkBuffer('chainCode', HDPublicKey.ChainCodeSize); - checkBuffer('publicKey', HDPublicKey.PublicKeySize); - if (arg.checksum && arg.checksum.length) { - checkBuffer('checksum', HDPublicKey.CheckSumSize); - } -}; + /** + * Merit URI + * + * Instantiate an URI from a Merit URI String or an Object. An URI instance + * can be created with a Merit uri string or an object. All instances of + * URI are valid, the static method isValid allows checking before instantiation. + * + * All standard parameters can be found as members of the class, the address + * is represented using an {Address} instance and the amount is represented in + * micros. Any other non-standard parameters can be found under the extra member. + * + * @example + * ```javascript + * + * var uri = new URI('merit:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu?amount=1.2'); + * console.log(uri.address, uri.amount); + * ``` + * + * @param {string|Object} data - A Merit URI string or an Object + * @param {Array.=} knownParams - Required non-standard params + * @throws {TypeError} Invalid Merit address + * @throws {TypeError} Invalid amount + * @throws {Error} Unknown required argument + * @returns {URI} A new valid and frozen instance of URI + * @constructor + */ + var URI = function(data, knownParams) { + if (!(this instanceof URI)) { + return new URI(data, knownParams); + } -HDPublicKey.fromString = function(arg) { - $.checkArgument(_.isString(arg), 'No valid string was provided'); - return new HDPublicKey(arg); -}; + this.extras = {}; + this.knownParams = knownParams || []; + this.address = this.network = this.amount = this.message = null; -HDPublicKey.fromObject = function(arg) { - $.checkArgument(_.isObject(arg), 'No valid argument was provided'); - return new HDPublicKey(arg); -}; + if (typeof data === 'string') { + var params = URI.parse(data); + if (params.amount) { + params.amount = this._parseAmount(params.amount); + } + this._fromObject(params); + } else if (typeof data === 'object') { + this._fromObject(data); + } else { + throw new TypeError('Unrecognized data format.'); + } + }; -/** - * Returns the base58 checked representation of the public key - * @return {string} a string starting with "xpub..." in livenet - */ -HDPublicKey.prototype.toString = function() { - return this.xpubkey; -}; + /** + * Instantiate a URI from a String + * + * @param {string} str - JSON string or object of the URI + * @returns {URI} A new instance of a URI + */ + URI.fromString = function fromString(str) { + if (typeof str !== 'string') { + throw new TypeError('Expected a string'); + } + return new URI(str); + }; -/** - * Returns the console representation of this extended public key. - * @return string - */ -HDPublicKey.prototype.inspect = function() { - return ''; -}; + /** + * Instantiate a URI from an Object + * + * @param {Object} data - object of the URI + * @returns {URI} A new instance of a URI + */ + URI.fromObject = function fromObject(json) { + return new URI(json); + }; -/** - * Returns a plain JavaScript object with information to reconstruct a key. - * - * Fields are:
    - *
  • network: 'livenet' or 'testnet' - *
  • depth: a number from 0 to 255, the depth to the master extended key - *
  • fingerPrint: a number of 32 bits taken from the hash of the public key - *
  • fingerPrint: a number of 32 bits taken from the hash of this key's - *
  • parent's public key - *
  • childIndex: index with which this key was derived - *
  • chainCode: string in hexa encoding used for derivation - *
  • publicKey: string, hexa encoded, in compressed key format - *
  • checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), - *
  • xpubkey: the string with the base58 representation of this extended key - *
  • checksum: the base58 checksum of xpubkey - *
- */ -HDPublicKey.prototype.toObject = HDPublicKey.prototype.toJSON = function toObject() { - return { - network: Network.get(BufferUtil.integerFromBuffer(this._buffers.version)).name, - depth: BufferUtil.integerFromSingleByteBuffer(this._buffers.depth), - fingerPrint: BufferUtil.integerFromBuffer(this.fingerPrint), - parentFingerPrint: BufferUtil.integerFromBuffer(this._buffers.parentFingerPrint), - childIndex: BufferUtil.integerFromBuffer(this._buffers.childIndex), - chainCode: BufferUtil.bufferToHex(this._buffers.chainCode), - publicKey: this.publicKey.toString(), - checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), - xpubkey: this.xpubkey - }; -}; - -/** - * Create a HDPublicKey from a buffer argument - * - * @param {Buffer} arg - * @return {HDPublicKey} - */ -HDPublicKey.fromBuffer = function(arg) { - return new HDPublicKey(arg); -}; + /** + * Check if an Merit URI string is valid + * + * @example + * ```javascript + * + * var valid = URI.isValid('merit:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu'); + * // true + * ``` + * + * @param {string|Object} data - A Merit URI string or an Object + * @param {Array.=} knownParams - Required non-standard params + * @returns {boolean} Result of uri validation + */ + URI.isValid = function(arg, knownParams) { + try { + new URI(arg, knownParams); + } catch (err) { + return false; + } + return true; + }; -/** - * Return a buffer representation of the xpubkey - * - * @return {Buffer} - */ -HDPublicKey.prototype.toBuffer = function() { - return BufferUtil.copy(this._buffers.xpubkey); -}; - -HDPublicKey.Hardened = 0x80000000; -HDPublicKey.RootElementAlias = ['m', 'M']; - -HDPublicKey.VersionSize = 4; -HDPublicKey.DepthSize = 1; -HDPublicKey.ParentFingerPrintSize = 4; -HDPublicKey.ChildIndexSize = 4; -HDPublicKey.ChainCodeSize = 32; -HDPublicKey.PublicKeySize = 33; -HDPublicKey.CheckSumSize = 4; - -HDPublicKey.DataSize = 78; -HDPublicKey.SerializedByteSize = 82; - -HDPublicKey.VersionStart = 0; -HDPublicKey.VersionEnd = HDPublicKey.VersionStart + HDPublicKey.VersionSize; -HDPublicKey.DepthStart = HDPublicKey.VersionEnd; -HDPublicKey.DepthEnd = HDPublicKey.DepthStart + HDPublicKey.DepthSize; -HDPublicKey.ParentFingerPrintStart = HDPublicKey.DepthEnd; -HDPublicKey.ParentFingerPrintEnd = HDPublicKey.ParentFingerPrintStart + HDPublicKey.ParentFingerPrintSize; -HDPublicKey.ChildIndexStart = HDPublicKey.ParentFingerPrintEnd; -HDPublicKey.ChildIndexEnd = HDPublicKey.ChildIndexStart + HDPublicKey.ChildIndexSize; -HDPublicKey.ChainCodeStart = HDPublicKey.ChildIndexEnd; -HDPublicKey.ChainCodeEnd = HDPublicKey.ChainCodeStart + HDPublicKey.ChainCodeSize; -HDPublicKey.PublicKeyStart = HDPublicKey.ChainCodeEnd; -HDPublicKey.PublicKeyEnd = HDPublicKey.PublicKeyStart + HDPublicKey.PublicKeySize; -HDPublicKey.ChecksumStart = HDPublicKey.PublicKeyEnd; -HDPublicKey.ChecksumEnd = HDPublicKey.ChecksumStart + HDPublicKey.CheckSumSize; - -assert(HDPublicKey.PublicKeyEnd === HDPublicKey.DataSize); -assert(HDPublicKey.ChecksumEnd === HDPublicKey.SerializedByteSize); - -module.exports = HDPublicKey; - -}).call(this,require("buffer").Buffer) -},{"./crypto/bn":6,"./crypto/hash":8,"./crypto/point":9,"./encoding/base58":12,"./encoding/base58check":13,"./errors":17,"./hdprivatekey":19,"./networks":21,"./publickey":24,"./util/buffer":42,"./util/js":43,"./util/preconditions":44,"assert":60,"buffer":113,"lodash":187}],21:[function(require,module,exports){ -'use strict'; -var _ = require('lodash'); - -var BufferUtil = require('./util/buffer'); -var JSUtil = require('./util/js'); -var networks = []; -var networkMaps = {}; - -/** - * A network is merely a map containing values that correspond to version - * numbers for each Merit network. Currently only supporting "livenet" - * (a.k.a. "mainnet") and "testnet". - * @constructor - */ -function Network() {} - -Network.prototype.toString = function toString() { - return this.name; -}; - -/** - * @function - * @member Networks#get - * Retrieves the network associated with a magic number or string. - * @param {string|number|Network} arg - * @param {string|Array} keys - if set, only check if the magic number associated with this name matches - * @return Network - */ -function get(arg, keys) { - if (~networks.indexOf(arg)) { - return arg; - } - if (keys) { - if (!_.isArray(keys)) { - keys = [keys]; - } - var containsArg = function(key) { - return networks[index][key] === arg; - }; - for (var index in networks) { - if (_.some(keys, containsArg)) { - return networks[index]; - } - } - return undefined; - } - return networkMaps[arg]; -} + /** + * Convert a Merit URI string into a simple object. + * + * @param {string} uri - A Merit URI string + * @throws {TypeError} Invalid Merit URI + * @returns {Object} An object with the parsed params + */ + URI.parse = function(uri) { + var info = URL.parse(uri, true); -/** - * @function - * @member Networks#add - * Will add a custom Network - * @param {Object} data - * @param {string} data.name - The name of the network - * @param {string} data.alias - The aliased name of the network - * @param {Number} data.pubkeyhash - The publickey hash prefix - * @param {Number} data.privatekey - The privatekey prefix - * @param {Number} data.scripthash - The scripthash prefix - * @param {Number} data.xpubkey - The extended public key magic - * @param {Number} data.xprivkey - The extended private key magic - * @param {Number} data.networkMagic - The network magic number - * @param {Number} data.port - The network port - * @param {Array} data.dnsSeeds - An array of dns seeds - * @return Network - */ -function addNetwork(data) { - - var network = new Network(); - - JSUtil.defineImmutable(network, { - name: data.name, - alias: data.alias, - pubkeyhash: data.pubkeyhash, - privatekey: data.privatekey, - scripthash: data.scripthash, - xpubkey: data.xpubkey, - xprivkey: data.xprivkey - }); - - if (data.networkMagic) { - JSUtil.defineImmutable(network, { - networkMagic: BufferUtil.integerAsBuffer(data.networkMagic) - }); - } + if (info.protocol !== 'merit:') { + throw new TypeError('Invalid Merit URI'); + } - if (data.port) { - JSUtil.defineImmutable(network, { - port: data.port - }); - } + // workaround to host insensitiveness + var group = /[^:]*:\/?\/?([^?]*)/.exec(uri); + info.query.address = (group && group[1]) || undefined; - if (data.dnsSeeds) { - JSUtil.defineImmutable(network, { - dnsSeeds: data.dnsSeeds - }); - } - _.each(network, function(value) { - if (!_.isUndefined(value) && !_.isObject(value)) { - networkMaps[value] = network; - } - }); + return info.query; + }; - networks.push(network); + URI.Members = ['address', 'amount', 'message', 'label', 'r']; - return network; + /** + * Internal function to load the URI instance with an object. + * + * @param {Object} obj - Object with the information + * @throws {TypeError} Invalid Merit address + * @throws {TypeError} Invalid amount + * @throws {Error} Unknown required argument + */ + URI.prototype._fromObject = function(obj) { + /* jshint maxcomplexity: 10 */ -} + if (!Address.isValid(obj.address)) { + throw new TypeError('Invalid Merit address'); + } -/** - * @function - * @member Networks#remove - * Will remove a custom network - * @param {Network} network - */ -function removeNetwork(network) { - for (var i = 0; i < networks.length; i++) { - if (networks[i] === network) { - networks.splice(i, 1); - } - } - for (var key in networkMaps) { - if (networkMaps[key] === network) { - delete networkMaps[key]; - } - } -} + this.address = new Address(obj.address); + this.network = this.address.network; + this.amount = obj.amount; -// ToDo: change seeds to Merit -addNetwork({ - name: 'livenet', - alias: 'mainnet', - pubkeyhash: 0x00, - privatekey: 0x80, - scripthash: 0x05, - xpubkey: 0x0488b21e, - xprivkey: 0x0488ade4, - networkMagic: 0xf9beb4d9, - port: 8333, - dnsSeeds: [] -}); - -/** - * @instance - * @member Networks#livenet - */ -var livenet = get('livenet'); - -addNetwork({ - name: 'testnet', - alias: 'regtest', - pubkeyhash: 0x6f, - privatekey: 0xef, - scripthash: 0xc4, - xpubkey: 0x043587cf, - xprivkey: 0x04358394 -}); - -/** - * @instance - * @member Networks#testnet - */ -var testnet = get('testnet'); + for (var key in obj) { + if (key === 'address' || key === 'amount') { + continue; + } -// Add configurable values for testnet/regtest + if (/^req-/.exec(key) && this.knownParams.indexOf(key) === -1) { + throw Error('Unknown required argument ' + key); + } -// ToDo: change seeds to Merit -var TESTNET = { - PORT: 18333, - NETWORK_MAGIC: BufferUtil.integerAsBuffer(0x0b110907), - DNS_SEEDS: [] -}; + var destination = URI.Members.indexOf(key) > -1 ? this : this.extras; + destination[key] = obj[key]; + } + }; -for (var key in TESTNET) { - if (!_.isObject(TESTNET[key])) { - networkMaps[TESTNET[key]] = testnet; - } -} + /** + * Internal function to transform a MRT string amount into micros + * + * @param {string} amount - Amount MRT string + * @throws {TypeError} Invalid amount + * @returns {Object} Amount represented in micros + */ + URI.prototype._parseAmount = function(amount) { + amount = Number(amount); + if (isNaN(amount)) { + throw new TypeError('Invalid amount'); + } + return Unit.fromMRT(amount).toMicros(); + }; -var REGTEST = { - PORT: 18444, - NETWORK_MAGIC: BufferUtil.integerAsBuffer(0xfabfb5da), - DNS_SEEDS: [] -}; + URI.prototype.toObject = URI.prototype.toJSON = function toObject() { + var json = {}; + for (var i = 0; i < URI.Members.length; i++) { + var m = URI.Members[i]; + if (this.hasOwnProperty(m) && typeof this[m] !== 'undefined') { + json[m] = this[m].toString(); + } + } + _.extend(json, this.extras); + return json; + }; -for (var key in REGTEST) { - if (!_.isObject(REGTEST[key])) { - networkMaps[REGTEST[key]] = testnet; - } -} + /** + * Will return a the string representation of the URI + * + * @returns {string} Merit URI string + */ + URI.prototype.toString = function() { + var query = {}; + if (this.amount) { + query.amount = Unit.fromMicros(this.amount).toMRT(); + } + if (this.message) { + query.message = this.message; + } + if (this.label) { + query.label = this.label; + } + if (this.r) { + query.r = this.r; + } + _.extend(query, this.extras); -Object.defineProperty(testnet, 'port', { - enumerable: true, - configurable: false, - get: function() { - if (this.regtestEnabled) { - return REGTEST.PORT; - } else { - return TESTNET.PORT; - } - } -}); - -Object.defineProperty(testnet, 'networkMagic', { - enumerable: true, - configurable: false, - get: function() { - if (this.regtestEnabled) { - return REGTEST.NETWORK_MAGIC; - } else { - return TESTNET.NETWORK_MAGIC; - } - } -}); - -Object.defineProperty(testnet, 'dnsSeeds', { - enumerable: true, - configurable: false, - get: function() { - if (this.regtestEnabled) { - return REGTEST.DNS_SEEDS; - } else { - return TESTNET.DNS_SEEDS; - } - } -}); + return URL.format({ + protocol: 'merit:', + host: this.address, + query: query, + }); + }; -/** - * @function - * @member Networks#enableRegtest - * Will enable regtest features for testnet - */ -function enableRegtest() { - testnet.regtestEnabled = true; -} + /** + * Will return a string formatted for the console + * + * @returns {string} Merit URI + */ + URI.prototype.inspect = function() { + return ''; + }; -/** - * @function - * @member Networks#disableRegtest - * Will disable regtest features for testnet - */ -function disableRegtest() { - testnet.regtestEnabled = false; -} + module.exports = URI; + }, + { './address': 1, './unit': 40, lodash: 187, url: 244 }, + ], + 42: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; -/** - * @namespace Networks - */ -module.exports = { - add: addNetwork, - remove: removeNetwork, - defaultNetwork: livenet, - livenet: livenet, - mainnet: livenet, - testnet: testnet, - get: get, - enableRegtest: enableRegtest, - disableRegtest: disableRegtest -}; - -},{"./util/buffer":42,"./util/js":43,"lodash":187}],22:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var $ = require('./util/preconditions'); -var BufferUtil = require('./util/buffer'); -var JSUtil = require('./util/js'); - -function Opcode(num) { - if (!(this instanceof Opcode)) { - return new Opcode(num); - } + var buffer = require('buffer'); + var assert = require('assert'); - var value; + var js = require('./js'); + var $ = require('./preconditions'); - if (_.isNumber(num)) { - value = num; - } else if (_.isString(num)) { - value = Opcode.map[num]; - } else { - throw new TypeError('Unrecognized num type: "' + typeof(num) + '" for Opcode'); - } + function equals(a, b) { + if (a.length !== b.length) { + return false; + } + var length = a.length; + for (var i = 0; i < length; i++) { + if (a[i] !== b[i]) { + return false; + } + } + return true; + } - JSUtil.defineImmutable(this, { - num: value - }); + module.exports = { + /** + * Fill a buffer with a value. + * + * @param {Buffer} buffer + * @param {number} value + * @return {Buffer} + */ + fill: function fill(buffer, value) { + $.checkArgumentType(buffer, 'Buffer', 'buffer'); + $.checkArgumentType(value, 'number', 'value'); + var length = buffer.length; + for (var i = 0; i < length; i++) { + buffer[i] = value; + } + return buffer; + }, + + /** + * Return a copy of a buffer + * + * @param {Buffer} original + * @return {Buffer} + */ + copy: function(original) { + var buffer = new Buffer(original.length); + original.copy(buffer); + return buffer; + }, + + /** + * Returns true if the given argument is an instance of a buffer. Tests for + * both node's Buffer and Uint8Array + * + * @param {*} arg + * @return {boolean} + */ + isBuffer: function isBuffer(arg) { + return buffer.Buffer.isBuffer(arg) || arg instanceof Uint8Array; + }, + + /** + * Returns a zero-filled byte array + * + * @param {number} bytes + * @return {Buffer} + */ + emptyBuffer: function emptyBuffer(bytes) { + $.checkArgumentType(bytes, 'number', 'bytes'); + var result = new buffer.Buffer(bytes); + for (var i = 0; i < bytes; i++) { + result.write('\0', i); + } + return result; + }, + + /** + * Concatenates a buffer + * + * Shortcut for buffer.Buffer.concat + */ + concat: buffer.Buffer.concat, + + equals: equals, + equal: equals, + + /** + * Transforms a number from 0 to 255 into a Buffer of size 1 with that value + * + * @param {number} integer + * @return {Buffer} + */ + integerAsSingleByteBuffer: function integerAsSingleByteBuffer(integer) { + $.checkArgumentType(integer, 'number', 'integer'); + return new buffer.Buffer([integer & 0xff]); + }, + + /** + * Transform a 4-byte integer into a Buffer of length 4. + * + * @param {number} integer + * @return {Buffer} + */ + integerAsBuffer: function integerAsBuffer(integer) { + $.checkArgumentType(integer, 'number', 'integer'); + var bytes = []; + bytes.push((integer >> 24) & 0xff); + bytes.push((integer >> 16) & 0xff); + bytes.push((integer >> 8) & 0xff); + bytes.push(integer & 0xff); + return new Buffer(bytes); + }, + + /** + * Transform the first 4 values of a Buffer into a number, in little endian encoding + * + * @param {Buffer} buffer + * @return {number} + */ + integerFromBuffer: function integerFromBuffer(buffer) { + $.checkArgumentType(buffer, 'Buffer', 'buffer'); + return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; + }, + + /** + * Transforms the first byte of an array into a number ranging from -128 to 127 + * @param {Buffer} buffer + * @return {number} + */ + integerFromSingleByteBuffer: function integerFromBuffer(buffer) { + $.checkArgumentType(buffer, 'Buffer', 'buffer'); + return buffer[0]; + }, + + /** + * Transforms a buffer into a string with a number in hexa representation + * + * Shorthand for buffer.toString('hex') + * + * @param {Buffer} buffer + * @return {string} + */ + bufferToHex: function bufferToHex(buffer) { + $.checkArgumentType(buffer, 'Buffer', 'buffer'); + return buffer.toString('hex'); + }, + + /** + * Reverse a buffer + * @param {Buffer} param + * @return {Buffer} + */ + reverse: function reverse(param) { + var ret = new buffer.Buffer(param.length); + for (var i = 0; i < param.length; i++) { + ret[i] = param[param.length - i - 1]; + } + return ret; + }, + + /** + * Transforms an hexa encoded string into a Buffer with binary values + * + * Shorthand for Buffer(string, 'hex') + * + * @param {string} string + * @return {Buffer} + */ + hexToBuffer: function hexToBuffer(string) { + assert(js.isHexa(string)); + return new buffer.Buffer(string, 'hex'); + }, + }; + + module.exports.NULL_HASH = module.exports.fill(new Buffer(32), 0); + module.exports.EMPTY_BUFFER = new Buffer(0); + }.call(this, require('buffer').Buffer)); + }, + { './js': 43, './preconditions': 44, assert: 60, buffer: 113 }, + ], + 43: [ + function(require, module, exports) { + 'use strict'; - return this; -} + var _ = require('lodash'); -Opcode.fromBuffer = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - return new Opcode(Number('0x' + buf.toString('hex'))); -}; - -Opcode.fromNumber = function(num) { - $.checkArgument(_.isNumber(num)); - return new Opcode(num); -}; - -Opcode.fromString = function(str) { - $.checkArgument(_.isString(str)); - var value = Opcode.map[str]; - if (typeof value === 'undefined') { - throw new TypeError('Invalid opcodestr'); - } - return new Opcode(value); -}; + /** + * Determines whether a string contains only hexadecimal values + * + * @name JSUtil.isHexa + * @param {string} value + * @return {boolean} true if the string is the hexa representation of a number + */ + var isHexa = function isHexa(value) { + if (!_.isString(value)) { + return false; + } + return /^[0-9a-fA-F]+$/.test(value); + }; -Opcode.prototype.toHex = function() { - return this.num.toString(16); -}; + /** + * @namespace JSUtil + */ + module.exports = { + /** + * Test if an argument is a valid JSON object. If it is, returns a truthy + * value (the json object decoded), so no double JSON.parse call is necessary + * + * @param {string} arg + * @return {Object|boolean} false if the argument is not a JSON string. + */ + isValidJSON: function isValidJSON(arg) { + var parsed; + if (!_.isString(arg)) { + return false; + } + try { + parsed = JSON.parse(arg); + } catch (e) { + return false; + } + if (typeof parsed === 'object') { + return true; + } + return false; + }, + isHexa: isHexa, + isHexaString: isHexa, + + /** + * Clone an array + */ + cloneArray: function(array) { + return [].concat(array); + }, + + /** + * Define immutable properties on a target object + * + * @param {Object} target - An object to be extended + * @param {Object} values - An object of properties + * @return {Object} The target object + */ + defineImmutable: function defineImmutable(target, values) { + Object.keys(values).forEach(function(key) { + Object.defineProperty(target, key, { + configurable: false, + enumerable: true, + value: values[key], + }); + }); + return target; + }, + /** + * Checks that a value is a natural number, a positive integer or zero. + * + * @param {*} value + * @return {Boolean} + */ + isNaturalNumber: function isNaturalNumber(value) { + return typeof value === 'number' && isFinite(value) && Math.floor(value) === value && value >= 0; + }, + }; + }, + { lodash: 187 }, + ], + 44: [ + function(require, module, exports) { + 'use strict'; + + var errors = require('../errors'); + var _ = require('lodash'); + + module.exports = { + checkState: function(condition, message) { + if (!condition) { + throw new errors.InvalidState(message); + } + }, + checkArgument: function(condition, argumentName, message, docsPath) { + if (!condition) { + throw new errors.InvalidArgument(argumentName, message, docsPath); + } + }, + checkArgumentType: function(argument, type, argumentName) { + argumentName = argumentName || '(unknown name)'; + if (_.isString(type)) { + if (type === 'Buffer') { + var buffer = require('buffer'); // './buffer' fails on cordova & RN + if (!buffer.Buffer.isBuffer(argument)) { + throw new errors.InvalidArgumentType(argument, type, argumentName); + } + } else if (typeof argument !== type) { + throw new errors.InvalidArgumentType(argument, type, argumentName); + } + } else { + if (!(argument instanceof type)) { + throw new errors.InvalidArgumentType(argument, type.name, argumentName); + } + } + }, + }; + }, + { '../errors': 17, buffer: 113, lodash: 187 }, + ], + 45: [ + function(require, module, exports) { + var asn1 = exports; + + asn1.bignum = require('bn.js'); + + asn1.define = require('./asn1/api').define; + asn1.base = require('./asn1/base'); + asn1.constants = require('./asn1/constants'); + asn1.decoders = require('./asn1/decoders'); + asn1.encoders = require('./asn1/encoders'); + }, + { + './asn1/api': 46, + './asn1/base': 48, + './asn1/constants': 52, + './asn1/decoders': 54, + './asn1/encoders': 57, + 'bn.js': 59, + }, + ], + 46: [ + function(require, module, exports) { + var asn1 = require('../asn1'); + var inherits = require('inherits'); -Opcode.prototype.toBuffer = function() { - return new Buffer(this.toHex(), 'hex'); -}; + var api = exports; -Opcode.prototype.toNumber = function() { - return this.num; -}; + api.define = function define(name, body) { + return new Entity(name, body); + }; -Opcode.prototype.toString = function() { - var str = Opcode.reverseMap[this.num]; - if (typeof str === 'undefined') { - throw new Error('Opcode does not have a string representation'); - } - return str; -}; - -Opcode.smallInt = function(n) { - $.checkArgument(_.isNumber(n), 'Invalid Argument: n should be number'); - $.checkArgument(n >= 0 && n <= 16, 'Invalid Argument: n must be between 0 and 16'); - if (n === 0) { - return Opcode('OP_0'); - } - return new Opcode(Opcode.map.OP_1 + n - 1); -}; - -Opcode.map = { - // push value - OP_FALSE: 0, - OP_0: 0, - OP_PUSHDATA1: 76, - OP_PUSHDATA2: 77, - OP_PUSHDATA4: 78, - OP_1NEGATE: 79, - OP_RESERVED: 80, - OP_TRUE: 81, - OP_1: 81, - OP_2: 82, - OP_3: 83, - OP_4: 84, - OP_5: 85, - OP_6: 86, - OP_7: 87, - OP_8: 88, - OP_9: 89, - OP_10: 90, - OP_11: 91, - OP_12: 92, - OP_13: 93, - OP_14: 94, - OP_15: 95, - OP_16: 96, - - // control - OP_NOP: 97, - OP_VER: 98, - OP_IF: 99, - OP_NOTIF: 100, - OP_VERIF: 101, - OP_VERNOTIF: 102, - OP_ELSE: 103, - OP_ENDIF: 104, - OP_VERIFY: 105, - OP_RETURN: 106, - - // stack ops - OP_TOALTSTACK: 107, - OP_FROMALTSTACK: 108, - OP_2DROP: 109, - OP_2DUP: 110, - OP_3DUP: 111, - OP_2OVER: 112, - OP_2ROT: 113, - OP_2SWAP: 114, - OP_IFDUP: 115, - OP_DEPTH: 116, - OP_DROP: 117, - OP_DUP: 118, - OP_NIP: 119, - OP_OVER: 120, - OP_PICK: 121, - OP_ROLL: 122, - OP_ROT: 123, - OP_SWAP: 124, - OP_TUCK: 125, - - // splice ops - OP_CAT: 126, - OP_SUBSTR: 127, - OP_LEFT: 128, - OP_RIGHT: 129, - OP_SIZE: 130, - - // bit logic - OP_INVERT: 131, - OP_AND: 132, - OP_OR: 133, - OP_XOR: 134, - OP_EQUAL: 135, - OP_EQUALVERIFY: 136, - OP_RESERVED1: 137, - OP_RESERVED2: 138, - - // numeric - OP_1ADD: 139, - OP_1SUB: 140, - OP_2MUL: 141, - OP_2DIV: 142, - OP_NEGATE: 143, - OP_ABS: 144, - OP_NOT: 145, - OP_0NOTEQUAL: 146, - - OP_ADD: 147, - OP_SUB: 148, - OP_MUL: 149, - OP_DIV: 150, - OP_MOD: 151, - OP_LSHIFT: 152, - OP_RSHIFT: 153, - - OP_BOOLAND: 154, - OP_BOOLOR: 155, - OP_NUMEQUAL: 156, - OP_NUMEQUALVERIFY: 157, - OP_NUMNOTEQUAL: 158, - OP_LESSTHAN: 159, - OP_GREATERTHAN: 160, - OP_LESSTHANOREQUAL: 161, - OP_GREATERTHANOREQUAL: 162, - OP_MIN: 163, - OP_MAX: 164, - - OP_WITHIN: 165, - - // crypto - OP_RIPEMD160: 166, - OP_SHA1: 167, - OP_SHA256: 168, - OP_HASH160: 169, - OP_HASH256: 170, - OP_CODESEPARATOR: 171, - OP_CHECKSIG: 172, - OP_CHECKSIGVERIFY: 173, - OP_CHECKMULTISIG: 174, - OP_CHECKMULTISIGVERIFY: 175, - - OP_CHECKLOCKTIMEVERIFY: 177, - OP_EASYSEND: 179, - - // expansion - OP_NOP1: 176, - OP_NOP2: 177, - OP_NOP3: 178, - OP_NOP4: 179, - OP_NOP5: 180, - OP_NOP6: 181, - OP_NOP7: 182, - OP_NOP8: 183, - OP_NOP9: 184, - OP_NOP10: 185, - - // template matching params - OP_PUBKEYHASH: 253, - OP_PUBKEY: 254, - OP_INVALIDOPCODE: 255 -}; - -Opcode.reverseMap = []; - -for (var k in Opcode.map) { - Opcode.reverseMap[Opcode.map[k]] = k; -} + function Entity(name, body) { + this.name = name; + this.body = body; -// Easier access to opcodes -_.extend(Opcode, Opcode.map); + this.decoders = {}; + this.encoders = {}; + } -/** - * @returns true if opcode is one of OP_0, OP_1, ..., OP_16 - */ -Opcode.isSmallIntOp = function(opcode) { - if (opcode instanceof Opcode) { - opcode = opcode.toNumber(); - } - return ((opcode === Opcode.map.OP_0) || - ((opcode >= Opcode.map.OP_1) && (opcode <= Opcode.map.OP_16))); -}; + Entity.prototype._createNamed = function createNamed(base) { + var named; + try { + named = require('vm').runInThisContext( + '(function ' + this.name + '(entity) {\n' + ' this._initNamed(entity);\n' + '})', + ); + } catch (e) { + named = function(entity) { + this._initNamed(entity); + }; + } + inherits(named, base); + named.prototype._initNamed = function initnamed(entity) { + base.call(this, entity); + }; -/** - * Will return a string formatted for the console - * - * @returns {string} Script opcode - */ -Opcode.prototype.inspect = function() { - return ''; -}; - -module.exports = Opcode; - -}).call(this,require("buffer").Buffer) -},{"./util/buffer":42,"./util/js":43,"./util/preconditions":44,"buffer":113,"lodash":187}],23:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var Address = require('./address'); -var Base58Check = require('./encoding/base58check'); -var BN = require('./crypto/bn'); -var JSUtil = require('./util/js'); -var Networks = require('./networks'); -var Point = require('./crypto/point'); -var PublicKey = require('./publickey'); -var Random = require('./crypto/random'); -var $ = require('./util/preconditions'); - -/** - * Instantiate a PrivateKey from a BN, Buffer and WIF. - * - * @example - * ```javascript - * // generate a new random key - * var key = PrivateKey(); - * - * // get the associated address - * var address = key.toAddress(); - * - * // encode into wallet export format - * var exported = key.toWIF(); - * - * // instantiate from the exported (and saved) private key - * var imported = PrivateKey.fromWIF(exported); - * ``` - * - * @param {string} data - The encoded data in various formats - * @param {Network|string=} network - a {@link Network} object, or a string with the network name - * @returns {PrivateKey} A new valid instance of an PrivateKey - * @constructor - */ -function PrivateKey(data, network) { - /* jshint maxstatements: 20 */ - /* jshint maxcomplexity: 8 */ + return new named(this); + }; - if (!(this instanceof PrivateKey)) { - return new PrivateKey(data, network); - } - if (data instanceof PrivateKey) { - return data; - } + Entity.prototype._getDecoder = function _getDecoder(enc) { + enc = enc || 'der'; + // Lazily create decoder + if (!this.decoders.hasOwnProperty(enc)) this.decoders[enc] = this._createNamed(asn1.decoders[enc]); + return this.decoders[enc]; + }; - var info = this._classifyArguments(data, network); + Entity.prototype.decode = function decode(data, enc, options) { + return this._getDecoder(enc).decode(data, options); + }; - // validation - if (!info.bn || info.bn.cmp(new BN(0)) === 0){ - throw new TypeError('Number can not be equal to zero, undefined, null or false'); - } - if (!info.bn.lt(Point.getN())) { - throw new TypeError('Number must be less than N'); - } - if (typeof(info.network) === 'undefined') { - throw new TypeError('Must specify the network ("livenet" or "testnet")'); - } + Entity.prototype._getEncoder = function _getEncoder(enc) { + enc = enc || 'der'; + // Lazily create encoder + if (!this.encoders.hasOwnProperty(enc)) this.encoders[enc] = this._createNamed(asn1.encoders[enc]); + return this.encoders[enc]; + }; - JSUtil.defineImmutable(this, { - bn: info.bn, - compressed: info.compressed, - network: info.network - }); + Entity.prototype.encode = function encode(data, enc, /* internal */ reporter) { + return this._getEncoder(enc).encode(data, reporter); + }; + }, + { '../asn1': 45, inherits: 184, vm: 249 }, + ], + 47: [ + function(require, module, exports) { + var inherits = require('inherits'); + var Reporter = require('../base').Reporter; + var Buffer = require('buffer').Buffer; + + function DecoderBuffer(base, options) { + Reporter.call(this, options); + if (!Buffer.isBuffer(base)) { + this.error('Input not Buffer'); + return; + } - Object.defineProperty(this, 'publicKey', { - configurable: false, - enumerable: true, - get: this.toPublicKey.bind(this) - }); + this.base = base; + this.offset = 0; + this.length = base.length; + } + inherits(DecoderBuffer, Reporter); + exports.DecoderBuffer = DecoderBuffer; - return this; + DecoderBuffer.prototype.save = function save() { + return { offset: this.offset, reporter: Reporter.prototype.save.call(this) }; + }; -}; + DecoderBuffer.prototype.restore = function restore(save) { + // Return skipped data + var res = new DecoderBuffer(this.base); + res.offset = save.offset; + res.length = this.offset; -/** - * Internal helper to instantiate PrivateKey internal `info` object from - * different kinds of arguments passed to the constructor. - * - * @param {*} data - * @param {Network|string=} network - a {@link Network} object, or a string with the network name - * @return {Object} - */ -PrivateKey.prototype._classifyArguments = function(data, network) { - /* jshint maxcomplexity: 10 */ - var info = { - compressed: true, - network: network ? Networks.get(network) : Networks.defaultNetwork - }; - - // detect type of data - if (_.isUndefined(data) || _.isNull(data)){ - info.bn = PrivateKey._getRandomBN(); - } else if (data instanceof BN) { - info.bn = data; - } else if (data instanceof Buffer || data instanceof Uint8Array) { - info = PrivateKey._transformBuffer(data, network); - } else if (data.bn && data.network){ - info = PrivateKey._transformObject(data); - } else if (!network && Networks.get(data)) { - info.bn = PrivateKey._getRandomBN(); - info.network = Networks.get(data); - } else if (typeof(data) === 'string'){ - if (JSUtil.isHexa(data)) { - info.bn = new BN(new Buffer(data, 'hex')); - } else { - info = PrivateKey._transformWIF(data, network); - } - } else { - throw new TypeError('First argument is an unrecognized data type.'); - } - return info; -}; + this.offset = save.offset; + Reporter.prototype.restore.call(this, save.reporter); -/** - * Internal function to get a random Big Number (BN) - * - * @returns {BN} A new randomly generated BN - * @private - */ -PrivateKey._getRandomBN = function(){ - var condition; - var bn; - do { - var privbuf = Random.getRandomBuffer(32); - bn = BN.fromBuffer(privbuf); - condition = bn.lt(Point.getN()); - } while (!condition); - return bn; -}; - -/** - * Internal function to transform a WIF Buffer into a private key - * - * @param {Buffer} buf - An WIF string - * @param {Network|string=} network - a {@link Network} object, or a string with the network name - * @returns {Object} An object with keys: bn, network and compressed - * @private - */ -PrivateKey._transformBuffer = function(buf, network) { + return res; + }; - var info = {}; + DecoderBuffer.prototype.isEmpty = function isEmpty() { + return this.offset === this.length; + }; - if (buf.length === 32) { - return PrivateKey._transformBNBuffer(buf, network); - } + DecoderBuffer.prototype.readUInt8 = function readUInt8(fail) { + if (this.offset + 1 <= this.length) return this.base.readUInt8(this.offset++, true); + else return this.error(fail || 'DecoderBuffer overrun'); + }; - info.network = Networks.get(buf[0], 'privatekey'); + DecoderBuffer.prototype.skip = function skip(bytes, fail) { + if (!(this.offset + bytes <= this.length)) return this.error(fail || 'DecoderBuffer overrun'); - if (!info.network) { - throw new Error('Invalid network'); - } + var res = new DecoderBuffer(this.base); - if (network && info.network !== Networks.get(network)) { - throw new TypeError('Private key network mismatch'); - } + // Share reporter state + res._reporterState = this._reporterState; - if (buf.length === 1 + 32 + 1 && buf[1 + 32 + 1 - 1] === 1) { - info.compressed = true; - } else if (buf.length === 1 + 32) { - info.compressed = false; - } else { - throw new Error('Length of buffer must be 33 (uncompressed) or 34 (compressed)'); - } + res.offset = this.offset; + res.length = this.offset + bytes; + this.offset += bytes; + return res; + }; - info.bn = BN.fromBuffer(buf.slice(1, 32 + 1)); + DecoderBuffer.prototype.raw = function raw(save) { + return this.base.slice(save ? save.offset : this.offset, this.length); + }; - return info; -}; + function EncoderBuffer(value, reporter) { + if (Array.isArray(value)) { + this.length = 0; + this.value = value.map(function(item) { + if (!(item instanceof EncoderBuffer)) item = new EncoderBuffer(item, reporter); + this.length += item.length; + return item; + }, this); + } else if (typeof value === 'number') { + if (!(0 <= value && value <= 0xff)) return reporter.error('non-byte EncoderBuffer value'); + this.value = value; + this.length = 1; + } else if (typeof value === 'string') { + this.value = value; + this.length = Buffer.byteLength(value); + } else if (Buffer.isBuffer(value)) { + this.value = value; + this.length = value.length; + } else { + return reporter.error('Unsupported type: ' + typeof value); + } + } + exports.EncoderBuffer = EncoderBuffer; -/** - * Internal function to transform a BN buffer into a private key - * - * @param {Buffer} buf - * @param {Network|string=} network - a {@link Network} object, or a string with the network name - * @returns {object} an Object with keys: bn, network, and compressed - * @private - */ -PrivateKey._transformBNBuffer = function(buf, network) { - var info = {}; - info.network = Networks.get(network) || Networks.defaultNetwork; - info.bn = BN.fromBuffer(buf); - info.compressed = false; - return info; -}; - -/** - * Internal function to transform a WIF string into a private key - * - * @param {string} buf - An WIF string - * @returns {Object} An object with keys: bn, network and compressed - * @private - */ -PrivateKey._transformWIF = function(str, network) { - return PrivateKey._transformBuffer(Base58Check.decode(str), network); -}; + EncoderBuffer.prototype.join = function join(out, offset) { + if (!out) out = new Buffer(this.length); + if (!offset) offset = 0; -/** - * Instantiate a PrivateKey from a Buffer with the DER or WIF representation - * - * @param {Buffer} arg - * @param {Network} network - * @return {PrivateKey} - */ -PrivateKey.fromBuffer = function(arg, network) { - return new PrivateKey(arg, network); -}; + if (this.length === 0) return out; -/** - * Internal function to transform a JSON string on plain object into a private key - * return this. - * - * @param {string} json - A JSON string or plain object - * @returns {Object} An object with keys: bn, network and compressed - * @private - */ -PrivateKey._transformObject = function(json) { - var bn = new BN(json.bn, 'hex'); - var network = Networks.get(json.network); - return { - bn: bn, - network: network, - compressed: json.compressed - }; -}; - -/** - * Instantiate a PrivateKey from a WIF string - * - * @param {string} str - The WIF encoded private key string - * @returns {PrivateKey} A new valid instance of PrivateKey - */ -PrivateKey.fromString = PrivateKey.fromWIF = function(str) { - $.checkArgument(_.isString(str), 'First argument is expected to be a string.'); - return new PrivateKey(str); -}; + if (Array.isArray(this.value)) { + this.value.forEach(function(item) { + item.join(out, offset); + offset += item.length; + }); + } else { + if (typeof this.value === 'number') out[offset] = this.value; + else if (typeof this.value === 'string') out.write(this.value, offset); + else if (Buffer.isBuffer(this.value)) this.value.copy(out, offset); + offset += this.length; + } -/** - * Instantiate a PrivateKey from a plain JavaScript object - * - * @param {Object} obj - The output from privateKey.toObject() - */ -PrivateKey.fromObject = function(obj) { - $.checkArgument(_.isObject(obj), 'First argument is expected to be an object.'); - return new PrivateKey(obj); -}; + return out; + }; + }, + { '../base': 48, buffer: 113, inherits: 184 }, + ], + 48: [ + function(require, module, exports) { + var base = exports; + + base.Reporter = require('./reporter').Reporter; + base.DecoderBuffer = require('./buffer').DecoderBuffer; + base.EncoderBuffer = require('./buffer').EncoderBuffer; + base.Node = require('./node'); + }, + { './buffer': 47, './node': 49, './reporter': 50 }, + ], + 49: [ + function(require, module, exports) { + var Reporter = require('../base').Reporter; + var EncoderBuffer = require('../base').EncoderBuffer; + var DecoderBuffer = require('../base').DecoderBuffer; + var assert = require('minimalistic-assert'); + + // Supported tags + var tags = [ + 'seq', + 'seqof', + 'set', + 'setof', + 'objid', + 'bool', + 'gentime', + 'utctime', + 'null_', + 'enum', + 'int', + 'objDesc', + 'bitstr', + 'bmpstr', + 'charstr', + 'genstr', + 'graphstr', + 'ia5str', + 'iso646str', + 'numstr', + 'octstr', + 'printstr', + 't61str', + 'unistr', + 'utf8str', + 'videostr', + ]; + + // Public methods list + var methods = [ + 'key', + 'obj', + 'use', + 'optional', + 'explicit', + 'implicit', + 'def', + 'choice', + 'any', + 'contains', + ].concat(tags); + + // Overrided methods list + var overrided = [ + '_peekTag', + '_decodeTag', + '_use', + '_decodeStr', + '_decodeObjid', + '_decodeTime', + '_decodeNull', + '_decodeInt', + '_decodeBool', + '_decodeList', + + '_encodeComposite', + '_encodeStr', + '_encodeObjid', + '_encodeTime', + '_encodeNull', + '_encodeInt', + '_encodeBool', + ]; + + function Node(enc, parent) { + var state = {}; + this._baseState = state; + + state.enc = enc; + + state.parent = parent || null; + state.children = null; + + // State + state.tag = null; + state.args = null; + state.reverseArgs = null; + state.choice = null; + state.optional = false; + state.any = false; + state.obj = false; + state.use = null; + state.useDecoder = null; + state.key = null; + state['default'] = null; + state.explicit = null; + state.implicit = null; + state.contains = null; + + // Should create new instance on each method + if (!state.parent) { + state.children = []; + this._wrap(); + } + } + module.exports = Node; + + var stateProps = [ + 'enc', + 'parent', + 'children', + 'tag', + 'args', + 'reverseArgs', + 'choice', + 'optional', + 'any', + 'obj', + 'use', + 'alteredUse', + 'key', + 'default', + 'explicit', + 'implicit', + 'contains', + ]; + + Node.prototype.clone = function clone() { + var state = this._baseState; + var cstate = {}; + stateProps.forEach(function(prop) { + cstate[prop] = state[prop]; + }); + var res = new this.constructor(cstate.parent); + res._baseState = cstate; + return res; + }; -/** - * Instantiate a PrivateKey from random bytes - * - * @param {string=} network - Either "livenet" or "testnet" - * @returns {PrivateKey} A new valid instance of PrivateKey - */ -PrivateKey.fromRandom = function(network) { - var bn = PrivateKey._getRandomBN(); - return new PrivateKey(bn, network); -}; + Node.prototype._wrap = function wrap() { + var state = this._baseState; + methods.forEach(function(method) { + this[method] = function _wrappedMethod() { + var clone = new this.constructor(this); + state.children.push(clone); + return clone[method].apply(clone, arguments); + }; + }, this); + }; -/** - * Check if there would be any errors when initializing a PrivateKey - * - * @param {string} data - The encoded data in various formats - * @param {string=} network - Either "livenet" or "testnet" - * @returns {null|Error} An error if exists - */ + Node.prototype._init = function init(body) { + var state = this._baseState; -PrivateKey.getValidationError = function(data, network) { - var error; - try { - /* jshint nonew: false */ - new PrivateKey(data, network); - } catch (e) { - error = e; - } - return error; -}; + assert(state.parent === null); + body.call(this); -/** - * Check if the parameters are valid - * - * @param {string} data - The encoded data in various formats - * @param {string=} network - Either "livenet" or "testnet" - * @returns {Boolean} If the private key is would be valid - */ -PrivateKey.isValid = function(data, network){ - if (!data) { - return false; - } - return !PrivateKey.getValidationError(data, network); -}; + // Filter children + state.children = state.children.filter(function(child) { + return child._baseState.parent === this; + }, this); + assert.equal(state.children.length, 1, 'Root node can have only one child'); + }; -/** - * Will output the PrivateKey encoded as hex string - * - * @returns {string} - */ -PrivateKey.prototype.toString = function() { - return this.toBuffer().toString('hex'); -}; + Node.prototype._useArgs = function useArgs(args) { + var state = this._baseState; + + // Filter children and args + var children = args.filter(function(arg) { + return arg instanceof this.constructor; + }, this); + args = args.filter(function(arg) { + return !(arg instanceof this.constructor); + }, this); + + if (children.length !== 0) { + assert(state.children === null); + state.children = children; + + // Replace parent to maintain backward link + children.forEach(function(child) { + child._baseState.parent = this; + }, this); + } + if (args.length !== 0) { + assert(state.args === null); + state.args = args; + state.reverseArgs = args.map(function(arg) { + if (typeof arg !== 'object' || arg.constructor !== Object) return arg; + + var res = {}; + Object.keys(arg).forEach(function(key) { + if (key == (key | 0)) key |= 0; + var value = arg[key]; + res[value] = key; + }); + return res; + }); + } + }; -/** - * Will output the PrivateKey to a WIF string - * - * @returns {string} A WIP representation of the private key - */ -PrivateKey.prototype.toWIF = function() { - var network = this.network; - var compressed = this.compressed; - - var buf; - if (compressed) { - buf = Buffer.concat([new Buffer([network.privatekey]), - this.bn.toBuffer({size: 32}), - new Buffer([0x01])]); - } else { - buf = Buffer.concat([new Buffer([network.privatekey]), - this.bn.toBuffer({size: 32})]); - } + // + // Overrided methods + // - return Base58Check.encode(buf); -}; + overrided.forEach(function(method) { + Node.prototype[method] = function _overrided() { + var state = this._baseState; + throw new Error(method + ' not implemented for encoding: ' + state.enc); + }; + }); -/** - * Will return the private key as a BN instance - * - * @returns {BN} A BN instance of the private key - */ -PrivateKey.prototype.toBigNumber = function(){ - return this.bn; -}; + // + // Public methods + // -/** - * Will return the private key as a BN buffer - * - * @returns {Buffer} A buffer of the private key - */ -PrivateKey.prototype.toBuffer = function(){ - // TODO: use `return this.bn.toBuffer({ size: 32 })` in v1.0.0 - return this.bn.toBuffer(); -}; + tags.forEach(function(tag) { + Node.prototype[tag] = function _tagMethod() { + var state = this._baseState; + var args = Array.prototype.slice.call(arguments); -/** - * WARNING: This method will not be officially supported until v1.0.0. - * - * - * Will return the private key as a BN buffer without leading zero padding - * - * @returns {Buffer} A buffer of the private key - */ -PrivateKey.prototype.toBufferNoPadding = function() { - return this.bn.toBuffer(); -}; + assert(state.tag === null); + state.tag = tag; -/** - * Will return the corresponding public key - * - * @returns {PublicKey} A public key generated from the private key - */ -PrivateKey.prototype.toPublicKey = function(){ - if (!this._pubkey) { - this._pubkey = PublicKey.fromPrivateKey(this); - } - return this._pubkey; -}; + this._useArgs(args); -/** - * Will return an address for the private key - * @param {Network=} network - optional parameter specifying - * the desired network for the address - * - * @returns {Address} An address generated from the private key - */ -PrivateKey.prototype.toAddress = function(network) { - var pubkey = this.toPublicKey(); - return Address.fromPublicKey(pubkey, network || this.network); -}; + return this; + }; + }); -/** - * @returns {Object} A plain object representation - */ -PrivateKey.prototype.toObject = PrivateKey.prototype.toJSON = function toObject() { - return { - bn: this.bn.toString('hex'), - compressed: this.compressed, - network: this.network.toString() - }; -}; - -/** - * Will return a string formatted for the console - * - * @returns {string} Private key - */ -PrivateKey.prototype.inspect = function() { - var uncompressed = !this.compressed ? ', uncompressed' : ''; - return ''; -}; - -module.exports = PrivateKey; - -}).call(this,require("buffer").Buffer) -},{"./address":1,"./crypto/bn":6,"./crypto/point":9,"./crypto/random":10,"./encoding/base58check":13,"./networks":21,"./publickey":24,"./util/js":43,"./util/preconditions":44,"buffer":113,"lodash":187}],24:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var BN = require('./crypto/bn'); -var Point = require('./crypto/point'); -var Hash = require('./crypto/hash'); -var JSUtil = require('./util/js'); -var Network = require('./networks'); -var _ = require('lodash'); -var $ = require('./util/preconditions'); - -/** - * Instantiate a PublicKey from a {@link PrivateKey}, {@link Point}, `string`, or `Buffer`. - * - * There are two internal properties, `network` and `compressed`, that deal with importing - * a PublicKey from a PrivateKey in WIF format. More details described on {@link PrivateKey} - * - * @example - * ```javascript - * // instantiate from a private key - * var key = PublicKey(privateKey, true); - * - * // export to as a DER hex encoded string - * var exported = key.toString(); - * - * // import the public key - * var imported = PublicKey.fromString(exported); - * ``` - * - * @param {string} data - The encoded data in various formats - * @param {Object} extra - additional options - * @param {Network=} extra.network - Which network should the address for this public key be for - * @param {String=} extra.compressed - If the public key is compressed - * @returns {PublicKey} A new valid instance of an PublicKey - * @constructor - */ -function PublicKey(data, extra) { + Node.prototype.use = function use(item) { + assert(item); + var state = this._baseState; - if (!(this instanceof PublicKey)) { - return new PublicKey(data, extra); - } + assert(state.use === null); + state.use = item; - $.checkArgument(data, 'First argument is required, please include public key data.'); + return this; + }; - if (data instanceof PublicKey) { - // Return copy, but as it's an immutable object, return same argument - return data; - } - extra = extra || {}; + Node.prototype.optional = function optional() { + var state = this._baseState; - var info = this._classifyArgs(data, extra); + state.optional = true; - // validation - info.point.validate(); + return this; + }; - JSUtil.defineImmutable(this, { - point: info.point, - compressed: info.compressed, - network: info.network || Network.defaultNetwork - }); + Node.prototype.def = function def(val) { + var state = this._baseState; - return this; -}; + assert(state['default'] === null); + state['default'] = val; + state.optional = true; -/** - * Internal function to differentiate between arguments passed to the constructor - * @param {*} data - * @param {Object} extra - */ -PublicKey.prototype._classifyArgs = function(data, extra) { - /* jshint maxcomplexity: 10 */ - var info = { - compressed: _.isUndefined(extra.compressed) || extra.compressed - }; - - // detect type of data - if (data instanceof Point) { - info.point = data; - } else if (data.x && data.y) { - info = PublicKey._transformObject(data); - } else if (typeof(data) === 'string') { - info = PublicKey._transformDER(new Buffer(data, 'hex')); - } else if (PublicKey._isBuffer(data)) { - info = PublicKey._transformDER(data); - } else if (PublicKey._isPrivateKey(data)) { - info = PublicKey._transformPrivateKey(data); - } else { - throw new TypeError('First argument is an unrecognized data format.'); - } - if (!info.network) { - info.network = _.isUndefined(extra.network) ? undefined : Network.get(extra.network); - } - return info; -}; + return this; + }; -/** - * Internal function to detect if an object is a {@link PrivateKey} - * - * @param {*} param - object to test - * @returns {boolean} - * @private - */ -PublicKey._isPrivateKey = function(param) { - var PrivateKey = require('./privatekey'); - return param instanceof PrivateKey; -}; + Node.prototype.explicit = function explicit(num) { + var state = this._baseState; -/** - * Internal function to detect if an object is a Buffer - * - * @param {*} param - object to test - * @returns {boolean} - * @private - */ -PublicKey._isBuffer = function(param) { - return (param instanceof Buffer) || (param instanceof Uint8Array); -}; + assert(state.explicit === null && state.implicit === null); + state.explicit = num; -/** - * Internal function to transform a private key into a public key point - * - * @param {PrivateKey} privkey - An instance of PrivateKey - * @returns {Object} An object with keys: point and compressed - * @private - */ -PublicKey._transformPrivateKey = function(privkey) { - $.checkArgument(PublicKey._isPrivateKey(privkey), 'Must be an instance of PrivateKey'); - var info = {}; - info.point = Point.getG().mul(privkey.bn); - info.compressed = privkey.compressed; - info.network = privkey.network; - return info; -}; - -/** - * Internal function to transform DER into a public key point - * - * @param {Buffer} buf - An hex encoded buffer - * @param {bool=} strict - if set to false, will loosen some conditions - * @returns {Object} An object with keys: point and compressed - * @private - */ -PublicKey._transformDER = function(buf, strict) { - /* jshint maxstatements: 30 */ - /* jshint maxcomplexity: 12 */ - $.checkArgument(PublicKey._isBuffer(buf), 'Must be a hex buffer of DER encoded public key'); - var info = {}; - - strict = _.isUndefined(strict) ? true : strict; - - var x; - var y; - var xbuf; - var ybuf; - - if (buf[0] === 0x04 || (!strict && (buf[0] === 0x06 || buf[0] === 0x07))) { - xbuf = buf.slice(1, 33); - ybuf = buf.slice(33, 65); - if (xbuf.length !== 32 || ybuf.length !== 32 || buf.length !== 65) { - throw new TypeError('Length of x and y must be 32 bytes'); - } - x = new BN(xbuf); - y = new BN(ybuf); - info.point = new Point(x, y); - info.compressed = false; - } else if (buf[0] === 0x03) { - xbuf = buf.slice(1); - x = new BN(xbuf); - info = PublicKey._transformX(true, x); - info.compressed = true; - } else if (buf[0] === 0x02) { - xbuf = buf.slice(1); - x = new BN(xbuf); - info = PublicKey._transformX(false, x); - info.compressed = true; - } else { - throw new TypeError('Invalid DER format public key'); - } - return info; -}; + return this; + }; -/** - * Internal function to transform X into a public key point - * - * @param {Boolean} odd - If the point is above or below the x axis - * @param {Point} x - The x point - * @returns {Object} An object with keys: point and compressed - * @private - */ -PublicKey._transformX = function(odd, x) { - $.checkArgument(typeof odd === 'boolean', 'Must specify whether y is odd or not (true or false)'); - var info = {}; - info.point = Point.fromX(odd, x); - return info; -}; - -/** - * Internal function to transform a JSON into a public key point - * - * @param {String|Object} json - a JSON string or plain object - * @returns {Object} An object with keys: point and compressed - * @private - */ -PublicKey._transformObject = function(json) { - var x = new BN(json.x, 'hex'); - var y = new BN(json.y, 'hex'); - var point = new Point(x, y); - return new PublicKey(point, { - compressed: json.compressed - }); -}; - -/** - * Instantiate a PublicKey from a PrivateKey - * - * @param {PrivateKey} privkey - An instance of PrivateKey - * @returns {PublicKey} A new valid instance of PublicKey - */ -PublicKey.fromPrivateKey = function(privkey) { - $.checkArgument(PublicKey._isPrivateKey(privkey), 'Must be an instance of PrivateKey'); - var info = PublicKey._transformPrivateKey(privkey); - return new PublicKey(info.point, { - compressed: info.compressed, - network: info.network - }); -}; - -/** - * Instantiate a PublicKey from a Buffer - * @param {Buffer} buf - A DER hex buffer - * @param {bool=} strict - if set to false, will loosen some conditions - * @returns {PublicKey} A new valid instance of PublicKey - */ -PublicKey.fromDER = PublicKey.fromBuffer = function(buf, strict) { - $.checkArgument(PublicKey._isBuffer(buf), 'Must be a hex buffer of DER encoded public key'); - var info = PublicKey._transformDER(buf, strict); - return new PublicKey(info.point, { - compressed: info.compressed - }); -}; - -/** - * Instantiate a PublicKey from a Point - * - * @param {Point} point - A Point instance - * @param {boolean=} compressed - whether to store this public key as compressed format - * @returns {PublicKey} A new valid instance of PublicKey - */ -PublicKey.fromPoint = function(point, compressed) { - $.checkArgument(point instanceof Point, 'First argument must be an instance of Point.'); - return new PublicKey(point, { - compressed: compressed - }); -}; - -/** - * Instantiate a PublicKey from a DER hex encoded string - * - * @param {string} str - A DER hex string - * @param {String=} encoding - The type of string encoding - * @returns {PublicKey} A new valid instance of PublicKey - */ -PublicKey.fromString = function(str, encoding) { - var buf = new Buffer(str, encoding || 'hex'); - var info = PublicKey._transformDER(buf); - return new PublicKey(info.point, { - compressed: info.compressed - }); -}; - -/** - * Instantiate a PublicKey from an X Point - * - * @param {Boolean} odd - If the point is above or below the x axis - * @param {Point} x - The x point - * @returns {PublicKey} A new valid instance of PublicKey - */ -PublicKey.fromX = function(odd, x) { - var info = PublicKey._transformX(odd, x); - return new PublicKey(info.point, { - compressed: info.compressed - }); -}; - -/** - * Check if there would be any errors when initializing a PublicKey - * - * @param {string} data - The encoded data in various formats - * @returns {null|Error} An error if exists - */ -PublicKey.getValidationError = function(data) { - var error; - try { - /* jshint nonew: false */ - new PublicKey(data); - } catch (e) { - error = e; - } - return error; -}; + Node.prototype.implicit = function implicit(num) { + var state = this._baseState; -/** - * Check if the parameters are valid - * - * @param {string} data - The encoded data in various formats - * @returns {Boolean} If the public key would be valid - */ -PublicKey.isValid = function(data) { - return !PublicKey.getValidationError(data); -}; + assert(state.explicit === null && state.implicit === null); + state.implicit = num; -/** - * @returns {Object} A plain object of the PublicKey - */ -PublicKey.prototype.toObject = PublicKey.prototype.toJSON = function toObject() { - return { - x: this.point.getX().toString('hex', 2), - y: this.point.getY().toString('hex', 2), - compressed: this.compressed - }; -}; - -/** - * Will output the PublicKey to a DER Buffer - * - * @returns {Buffer} A DER hex encoded buffer - */ -PublicKey.prototype.toBuffer = PublicKey.prototype.toDER = function() { - var x = this.point.getX(); - var y = this.point.getY(); - - var xbuf = x.toBuffer({ - size: 32 - }); - var ybuf = y.toBuffer({ - size: 32 - }); - - var prefix; - if (!this.compressed) { - prefix = new Buffer([0x04]); - return Buffer.concat([prefix, xbuf, ybuf]); - } else { - var odd = ybuf[ybuf.length - 1] % 2; - if (odd) { - prefix = new Buffer([0x03]); - } else { - prefix = new Buffer([0x02]); - } - return Buffer.concat([prefix, xbuf]); - } -}; + return this; + }; -/** - * Will return a sha256 + ripemd160 hash of the serialized public key - * @see https://github.com/bitcoin/bitcoin/blob/master/src/pubkey.h#L141 - * @returns {Buffer} - */ -PublicKey.prototype._getID = function _getID() { - return Hash.sha256ripemd160(this.toBuffer()); -}; + Node.prototype.obj = function obj() { + var state = this._baseState; + var args = Array.prototype.slice.call(arguments); -/** - * Will return an address for the public key - * - * @param {String|Network=} network - Which network should the address be for - * @returns {Address} An address generated from the public key - */ -PublicKey.prototype.toAddress = function(network) { - var Address = require('./address'); - return Address.fromPublicKey(this, network || this.network); -}; + state.obj = true; -/** - * Will output the PublicKey to a DER encoded hex string - * - * @returns {string} A DER hex encoded string - */ -PublicKey.prototype.toString = function() { - return this.toDER().toString('hex'); -}; + if (args.length !== 0) this._useArgs(args); -/** - * Will return a string formatted for the console - * - * @returns {string} Public key - */ -PublicKey.prototype.inspect = function() { - return ''; -}; + return this; + }; + Node.prototype.key = function key(newKey) { + var state = this._baseState; -module.exports = PublicKey; + assert(state.key === null); + state.key = newKey; -}).call(this,require("buffer").Buffer) -},{"./address":1,"./crypto/bn":6,"./crypto/hash":8,"./crypto/point":9,"./networks":21,"./privatekey":23,"./util/js":43,"./util/preconditions":44,"buffer":113,"lodash":187}],25:[function(require,module,exports){ -module.exports = require('./script'); + return this; + }; -module.exports.Interpreter = require('./interpreter'); + Node.prototype.any = function any() { + var state = this._baseState; -},{"./interpreter":26,"./script":27}],26:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + state.any = true; -var _ = require('lodash'); + return this; + }; -var Script = require('./script'); -var Opcode = require('../opcode'); -var BN = require('../crypto/bn'); -var Hash = require('../crypto/hash'); -var Signature = require('../crypto/signature'); -var PublicKey = require('../publickey'); + Node.prototype.choice = function choice(obj) { + var state = this._baseState; -/** - * Merit transactions contain scripts. Each input has a script called the - * scriptSig, and each output has a script called the scriptPubkey. To validate - * an input, the input's script is concatenated with the referenced output script, - * and the result is executed. If at the end of execution the stack contains a - * "true" value, then the transaction is valid. - * - * The primary way to use this class is via the verify function. - * e.g., Interpreter().verify( ... ); - */ -var Interpreter = function Interpreter(obj) { - if (!(this instanceof Interpreter)) { - return new Interpreter(obj); - } - if (obj) { - this.initialize(); - this.set(obj); - } else { - this.initialize(); - } -}; - -/** - * Verifies a Script by executing it and returns true if it is valid. - * This function needs to be provided with the scriptSig and the scriptPubkey - * separately. - * @param {Script} scriptSig - the script's first part (corresponding to the tx input) - * @param {Script} scriptPubkey - the script's last part (corresponding to the tx output) - * @param {Transaction=} tx - the Transaction containing the scriptSig in one input (used - * to check signature validity for some opcodes like OP_CHECKSIG) - * @param {number} nin - index of the transaction input containing the scriptSig verified. - * @param {number} flags - evaluation flags. See Interpreter.SCRIPT_* constants - * - * Translated from bitcoind's VerifyScript - */ -Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags) { - var Transaction = require('../transaction'); - if (_.isUndefined(tx)) { - tx = new Transaction(); - } - if (_.isUndefined(nin)) { - nin = 0; - } - if (_.isUndefined(flags)) { - flags = 0; - } - this.set({ - script: scriptSig, - tx: tx, - nin: nin, - flags: flags - }); - var stackCopy; - - if ((flags & Interpreter.SCRIPT_VERIFY_SIGPUSHONLY) !== 0 && !scriptSig.isPushOnly()) { - this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'; - return false; - } + assert(state.choice === null); + state.choice = obj; + this._useArgs( + Object.keys(obj).map(function(key) { + return obj[key]; + }), + ); - // evaluate scriptSig - if (!this.evaluate()) { - return false; - } + return this; + }; - if (flags & Interpreter.SCRIPT_VERIFY_P2SH) { - stackCopy = this.stack.slice(); - } + Node.prototype.contains = function contains(item) { + var state = this._baseState; - var stack = this.stack; - this.initialize(); - this.set({ - script: scriptPubkey, - stack: stack, - tx: tx, - nin: nin, - flags: flags - }); - - // evaluate scriptPubkey - if (!this.evaluate()) { - return false; - } + assert(state.use === null); + state.contains = item; - if (this.stack.length === 0) { - this.errstr = 'SCRIPT_ERR_EVAL_FALSE_NO_RESULT'; - return false; - } + return this; + }; - var buf = this.stack[this.stack.length - 1]; - if (!Interpreter.castToBool(buf)) { - this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_STACK'; - return false; - } + // + // Decoding + // - // Additional validation for spend-to-script-hash transactions: - if ((flags & Interpreter.SCRIPT_VERIFY_P2SH) && scriptPubkey.isScriptHashOut()) { - // scriptSig must be literals-only or validation fails - if (!scriptSig.isPushOnly()) { - this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'; - return false; - } + Node.prototype._decode = function decode(input, options) { + var state = this._baseState; + + // Decode root node + if (state.parent === null) return input.wrapResult(state.children[0]._decode(input, options)); + + var result = state['default']; + var present = true; + + var prevKey = null; + if (state.key !== null) prevKey = input.enterKey(state.key); + + // Check if tag is there + if (state.optional) { + var tag = null; + if (state.explicit !== null) tag = state.explicit; + else if (state.implicit !== null) tag = state.implicit; + else if (state.tag !== null) tag = state.tag; + + if (tag === null && !state.any) { + // Trial and Error + var save = input.save(); + try { + if (state.choice === null) this._decodeGeneric(state.tag, input, options); + else this._decodeChoice(input, options); + present = true; + } catch (e) { + present = false; + } + input.restore(save); + } else { + present = this._peekTag(input, tag, state.any); - // stackCopy cannot be empty here, because if it was the - // P2SH HASH <> EQUAL scriptPubKey would be evaluated with - // an empty stack and the EvalScript above would return false. - if (stackCopy.length === 0) { - throw new Error('internal error - stack copy empty'); - } + if (input.isError(present)) return present; + } + } - var redeemScriptSerialized = stackCopy[stackCopy.length - 1]; - var redeemScript = Script.fromBuffer(redeemScriptSerialized); - stackCopy.pop(); - - this.initialize(); - this.set({ - script: redeemScript, - stack: stackCopy, - tx: tx, - nin: nin, - flags: flags - }); - - // evaluate redeemScript - if (!this.evaluate()) { - return false; - } + // Push object on stack + var prevObj; + if (state.obj && present) prevObj = input.enterObject(); - if (stackCopy.length === 0) { - this.errstr = 'SCRIPT_ERR_EVAL_FALSE_NO_P2SH_STACK'; - return false; - } + if (present) { + // Unwrap explicit values + if (state.explicit !== null) { + var explicit = this._decodeTag(input, state.explicit); + if (input.isError(explicit)) return explicit; + input = explicit; + } - if (!Interpreter.castToBool(stackCopy[stackCopy.length - 1])) { - this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_P2SH_STACK'; - return false; - } else { - return true; - } - } + var start = input.offset; - return true; -}; - -module.exports = Interpreter; - -Interpreter.prototype.initialize = function(obj) { - this.stack = []; - this.altstack = []; - this.pc = 0; - this.pbegincodehash = 0; - this.nOpCount = 0; - this.vfExec = []; - this.errstr = ''; - this.flags = 0; -}; - -Interpreter.prototype.set = function(obj) { - this.script = obj.script || this.script; - this.tx = obj.tx || this.tx; - this.nin = typeof obj.nin !== 'undefined' ? obj.nin : this.nin; - this.stack = obj.stack || this.stack; - this.altstack = obj.altack || this.altstack; - this.pc = typeof obj.pc !== 'undefined' ? obj.pc : this.pc; - this.pbegincodehash = typeof obj.pbegincodehash !== 'undefined' ? obj.pbegincodehash : this.pbegincodehash; - this.nOpCount = typeof obj.nOpCount !== 'undefined' ? obj.nOpCount : this.nOpCount; - this.vfExec = obj.vfExec || this.vfExec; - this.errstr = obj.errstr || this.errstr; - this.flags = typeof obj.flags !== 'undefined' ? obj.flags : this.flags; -}; - -Interpreter.true = new Buffer([1]); -Interpreter.false = new Buffer([]); - -Interpreter.MAX_SCRIPT_ELEMENT_SIZE = 520; - -Interpreter.LOCKTIME_THRESHOLD = 500000000; -Interpreter.LOCKTIME_THRESHOLD_BN = new BN(Interpreter.LOCKTIME_THRESHOLD); - -// flags taken from bitcoind -// bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 -Interpreter.SCRIPT_VERIFY_NONE = 0; - -// Evaluate P2SH subscripts (softfork safe, BIP16). -Interpreter.SCRIPT_VERIFY_P2SH = (1 << 0); - -// Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure. -// Passing a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) to checksig causes that pubkey to be -// skipped (not softfork safe: this flag can widen the validity of OP_CHECKSIG OP_NOT). -Interpreter.SCRIPT_VERIFY_STRICTENC = (1 << 1); - -// Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1) -Interpreter.SCRIPT_VERIFY_DERSIG = (1 << 2); - -// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure -// (softfork safe, BIP62 rule 5). -Interpreter.SCRIPT_VERIFY_LOW_S = (1 << 3); - -// verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7). -Interpreter.SCRIPT_VERIFY_NULLDUMMY = (1 << 4); - -// Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2). -Interpreter.SCRIPT_VERIFY_SIGPUSHONLY = (1 << 5); - -// Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct -// pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating -// any other push causes the script to fail (BIP62 rule 3). -// In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4). -// (softfork safe) -Interpreter.SCRIPT_VERIFY_MINIMALDATA = (1 << 6); - -// Discourage use of NOPs reserved for upgrades (NOP1-10) -// -// Provided so that nodes can avoid accepting or mining transactions -// containing executed NOP's whose meaning may change after a soft-fork, -// thus rendering the script invalid; with this flag set executing -// discouraged NOPs fails the script. This verification flag will never be -// a mandatory flag applied to scripts in a block. NOPs that are not -// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected. -Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1 << 7); - -// CLTV See BIP65 for details. -Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1 << 9); - -Interpreter.castToBool = function(buf) { - for (var i = 0; i < buf.length; i++) { - if (buf[i] !== 0) { - // can be negative zero - if (i === buf.length - 1 && buf[i] === 0x80) { - return false; - } - return true; - } - } - return false; -}; + // Unwrap implicit and normal values + if (state.use === null && state.choice === null) { + if (state.any) var save = input.save(); + var body = this._decodeTag(input, state.implicit !== null ? state.implicit : state.tag, state.any); + if (input.isError(body)) return body; -/** - * Translated from bitcoind's CheckSignatureEncoding - */ -Interpreter.prototype.checkSignatureEncoding = function(buf) { - var sig; - if ((this.flags & (Interpreter.SCRIPT_VERIFY_DERSIG | Interpreter.SCRIPT_VERIFY_LOW_S | Interpreter.SCRIPT_VERIFY_STRICTENC)) !== 0 && !Signature.isTxDER(buf)) { - this.errstr = 'SCRIPT_ERR_SIG_DER_INVALID_FORMAT'; - return false; - } else if ((this.flags & Interpreter.SCRIPT_VERIFY_LOW_S) !== 0) { - sig = Signature.fromTxFormat(buf); - if (!sig.hasLowS()) { - this.errstr = 'SCRIPT_ERR_SIG_DER_HIGH_S'; - return false; - } - } else if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0) { - sig = Signature.fromTxFormat(buf); - if (!sig.hasDefinedHashtype()) { - this.errstr = 'SCRIPT_ERR_SIG_HASHTYPE'; - return false; - } - } - return true; -}; + if (state.any) result = input.raw(save); + else input = body; + } -/** - * Translated from bitcoind's CheckPubKeyEncoding - */ -Interpreter.prototype.checkPubkeyEncoding = function(buf) { - if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0 && !PublicKey.isValid(buf)) { - this.errstr = 'SCRIPT_ERR_PUBKEYTYPE'; - return false; - } - return true; -}; + if (options && options.track && state.tag !== null) + options.track(input.path(), start, input.length, 'tagged'); -/** - * Based on bitcoind's EvalScript function, with the inner loop moved to - * Interpreter.prototype.step() - * bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 - */ -Interpreter.prototype.evaluate = function() { - if (this.script.toBuffer().length > 10000) { - this.errstr = 'SCRIPT_ERR_SCRIPT_SIZE'; - return false; - } + if (options && options.track && state.tag !== null) + options.track(input.path(), input.offset, input.length, 'content'); - try { - while (this.pc < this.script.chunks.length) { - var fSuccess = this.step(); - if (!fSuccess) { - return false; - } - } + // Select proper method for tag + if (state.any) result = result; + else if (state.choice === null) result = this._decodeGeneric(state.tag, input, options); + else result = this._decodeChoice(input, options); - // Size limits - if (this.stack.length + this.altstack.length > 1000) { - this.errstr = 'SCRIPT_ERR_STACK_SIZE'; - return false; - } - } catch (e) { - this.errstr = 'SCRIPT_ERR_UNKNOWN_ERROR: ' + e; - return false; - } + if (input.isError(result)) return result; - if (this.vfExec.length > 0) { - this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; - return false; - } + // Decode children + if (!state.any && state.choice === null && state.children !== null) { + state.children.forEach(function decodeChildren(child) { + // NOTE: We are ignoring errors here, to let parser continue with other + // parts of encoded data + child._decode(input, options); + }); + } - return true; -}; + // Decode contained/encoded by schema, only in bit or octet strings + if (state.contains && (state.tag === 'octstr' || state.tag === 'bitstr')) { + var data = new DecoderBuffer(result); + result = this._getUse(state.contains, input._reporterState.obj)._decode(data, options); + } + } -/** - * Checks a locktime parameter with the transaction's locktime. - * There are two times of nLockTime: lock-by-blockheight and lock-by-blocktime, - * distinguished by whether nLockTime < LOCKTIME_THRESHOLD = 500000000 - * - * See the corresponding code on Merit core: - * https://github.com/bitcoin/bitcoin/blob/ffd75adce01a78b3461b3ff05bcc2b530a9ce994/src/script/interpreter.cpp#L1129 - * - * @param {BN} nLockTime the locktime read from the script - * @return {boolean} true if the transaction's locktime is less than or equal to - * the transaction's locktime - */ -Interpreter.prototype.checkLockTime = function(nLockTime) { - - // We want to compare apples to apples, so fail the script - // unless the type of nLockTime being tested is the same as - // the nLockTime in the transaction. - if (!( - (this.tx.nLockTime < Interpreter.LOCKTIME_THRESHOLD && nLockTime.lt(Interpreter.LOCKTIME_THRESHOLD_BN)) || - (this.tx.nLockTime >= Interpreter.LOCKTIME_THRESHOLD && nLockTime.gte(Interpreter.LOCKTIME_THRESHOLD_BN)) - )) { - return false; - } + // Pop object + if (state.obj && present) result = input.leaveObject(prevObj); - // Now that we know we're comparing apples-to-apples, the - // comparison is a simple numeric one. - if (nLockTime.gt(new BN(this.tx.nLockTime))) { - return false; - } + // Set key + if (state.key !== null && (result !== null || present === true)) input.leaveKey(prevKey, state.key, result); + else if (prevKey !== null) input.exitKey(prevKey); - // Finally the nLockTime feature can be disabled and thus - // CHECKLOCKTIMEVERIFY bypassed if every txin has been - // finalized by setting nSequence to maxint. The - // transaction would be allowed into the blockchain, making - // the opcode ineffective. - // - // Testing if this vin is not final is sufficient to - // prevent this condition. Alternatively we could test all - // inputs, but testing just this input minimizes the data - // required to prove correct CHECKLOCKTIMEVERIFY execution. - if (!this.tx.inputs[this.nin].isFinal()) { - return false; - } + return result; + }; - return true; -} + Node.prototype._decodeGeneric = function decodeGeneric(tag, input, options) { + var state = this._baseState; + + if (tag === 'seq' || tag === 'set') return null; + if (tag === 'seqof' || tag === 'setof') return this._decodeList(input, tag, state.args[0], options); + else if (/str$/.test(tag)) return this._decodeStr(input, tag, options); + else if (tag === 'objid' && state.args) + return this._decodeObjid(input, state.args[0], state.args[1], options); + else if (tag === 'objid') return this._decodeObjid(input, null, null, options); + else if (tag === 'gentime' || tag === 'utctime') return this._decodeTime(input, tag, options); + else if (tag === 'null_') return this._decodeNull(input, options); + else if (tag === 'bool') return this._decodeBool(input, options); + else if (tag === 'objDesc') return this._decodeStr(input, tag, options); + else if (tag === 'int' || tag === 'enum') return this._decodeInt(input, state.args && state.args[0], options); + + if (state.use !== null) { + return this._getUse(state.use, input._reporterState.obj)._decode(input, options); + } else { + return input.error('unknown tag: ' + tag); + } + }; -/** - * Based on the inner loop of bitcoind's EvalScript function - * bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 - */ -Interpreter.prototype.step = function() { - - var fRequireMinimal = (this.flags & Interpreter.SCRIPT_VERIFY_MINIMALDATA) !== 0; - - //bool fExec = !count(vfExec.begin(), vfExec.end(), false); - var fExec = (this.vfExec.indexOf(false) === -1); - var buf, buf1, buf2, spliced, n, x1, x2, bn, bn1, bn2, bufSig, bufPubkey, subscript; - var sig, pubkey; - var fValue, fSuccess; - - // Read instruction - var chunk = this.script.chunks[this.pc]; - this.pc++; - var opcodenum = chunk.opcodenum; - if (_.isUndefined(opcodenum)) { - this.errstr = 'SCRIPT_ERR_UNDEFINED_OPCODE'; - return false; - } - if (chunk.buf && chunk.buf.length > Interpreter.MAX_SCRIPT_ELEMENT_SIZE) { - this.errstr = 'SCRIPT_ERR_PUSH_SIZE'; - return false; - } + Node.prototype._getUse = function _getUse(entity, obj) { + var state = this._baseState; + // Create altered use decoder if implicit is set + state.useDecoder = this._use(entity, obj); + assert(state.useDecoder._baseState.parent === null); + state.useDecoder = state.useDecoder._baseState.children[0]; + if (state.implicit !== state.useDecoder._baseState.implicit) { + state.useDecoder = state.useDecoder.clone(); + state.useDecoder._baseState.implicit = state.implicit; + } + return state.useDecoder; + }; - // Note how Opcode.OP_RESERVED does not count towards the opcode limit. - if (opcodenum > Opcode.OP_16 && ++(this.nOpCount) > 201) { - this.errstr = 'SCRIPT_ERR_OP_COUNT'; - return false; - } + Node.prototype._decodeChoice = function decodeChoice(input, options) { + var state = this._baseState; + var result = null; + var match = false; + Object.keys(state.choice).some(function(key) { + var save = input.save(); + var node = state.choice[key]; + try { + var value = node._decode(input, options); + if (input.isError(value)) return false; - if (opcodenum === Opcode.OP_CAT || - opcodenum === Opcode.OP_SUBSTR || - opcodenum === Opcode.OP_LEFT || - opcodenum === Opcode.OP_RIGHT || - opcodenum === Opcode.OP_INVERT || - opcodenum === Opcode.OP_AND || - opcodenum === Opcode.OP_OR || - opcodenum === Opcode.OP_XOR || - opcodenum === Opcode.OP_2MUL || - opcodenum === Opcode.OP_2DIV || - opcodenum === Opcode.OP_MUL || - opcodenum === Opcode.OP_DIV || - opcodenum === Opcode.OP_MOD || - opcodenum === Opcode.OP_LSHIFT || - opcodenum === Opcode.OP_RSHIFT) { - this.errstr = 'SCRIPT_ERR_DISABLED_OPCODE'; - return false; - } + result = { type: key, value: value }; + match = true; + } catch (e) { + input.restore(save); + return false; + } + return true; + }, this); - if (fExec && 0 <= opcodenum && opcodenum <= Opcode.OP_PUSHDATA4) { - if (fRequireMinimal && !this.script.checkMinimalPush(this.pc - 1)) { - this.errstr = 'SCRIPT_ERR_MINIMALDATA'; - return false; - } - if (!chunk.buf) { - this.stack.push(Interpreter.false); - } else if (chunk.len !== chunk.buf.length) { - throw new Error('Length of push value not equal to length of data'); - } else { - this.stack.push(chunk.buf); - } - } else if (fExec || (Opcode.OP_IF <= opcodenum && opcodenum <= Opcode.OP_ENDIF)) { - switch (opcodenum) { - // Push value - case Opcode.OP_1NEGATE: - case Opcode.OP_1: - case Opcode.OP_2: - case Opcode.OP_3: - case Opcode.OP_4: - case Opcode.OP_5: - case Opcode.OP_6: - case Opcode.OP_7: - case Opcode.OP_8: - case Opcode.OP_9: - case Opcode.OP_10: - case Opcode.OP_11: - case Opcode.OP_12: - case Opcode.OP_13: - case Opcode.OP_14: - case Opcode.OP_15: - case Opcode.OP_16: - { - // ( -- value) - // ScriptNum bn((int)opcode - (int)(Opcode.OP_1 - 1)); - n = opcodenum - (Opcode.OP_1 - 1); - buf = new BN(n).toScriptNumBuffer(); - this.stack.push(buf); - // The result of these opcodes should always be the minimal way to push the data - // they push, so no need for a CheckMinimalPush here. - } - break; + if (!match) return input.error('Choice not matched'); + return result; + }; // - // Control + // Encoding // - case Opcode.OP_NOP: - break; - case Opcode.OP_NOP2: - case Opcode.OP_CHECKLOCKTIMEVERIFY: + Node.prototype._createEncoderBuffer = function createEncoderBuffer(data) { + return new EncoderBuffer(data, this.reporter); + }; - if (!(this.flags & Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) { - // not enabled; treat as a NOP2 - if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { - this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'; - return false; - } - break; - } + Node.prototype._encode = function encode(data, reporter, parent) { + var state = this._baseState; + if (state['default'] !== null && state['default'] === data) return; - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } + var result = this._encodeValue(data, reporter, parent); + if (result === undefined) return; - // Note that elsewhere numeric opcodes are limited to - // operands in the range -2**31+1 to 2**31-1, however it is - // legal for opcodes to produce results exceeding that - // range. This limitation is implemented by CScriptNum's - // default 4-byte limit. - // - // If we kept to that limit we'd have a year 2038 problem, - // even though the nLockTime field in transactions - // themselves is uint32 which only becomes meaningless - // after the year 2106. - // - // Thus as a special case we tell CScriptNum to accept up - // to 5-byte bignums, which are good until 2**39-1, well - // beyond the 2**32-1 limit of the nLockTime field itself. - var nLockTime = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal, 5); - - // In the rare event that the argument may be < 0 due to - // some arithmetic being done first, you can always use - // 0 MAX CHECKLOCKTIMEVERIFY. - if (nLockTime.lt(new BN(0))) { - this.errstr = 'SCRIPT_ERR_NEGATIVE_LOCKTIME'; - return false; - } + if (this._skipDefault(result, reporter, parent)) return; - // Actually compare the specified lock time with the transaction. - if (!this.checkLockTime(nLockTime)) { - this.errstr = 'SCRIPT_ERR_UNSATISFIED_LOCKTIME'; - return false; - } - break; - - case Opcode.OP_NOP1: - case Opcode.OP_NOP3: - case Opcode.OP_NOP4: - case Opcode.OP_NOP5: - case Opcode.OP_NOP6: - case Opcode.OP_NOP7: - case Opcode.OP_NOP8: - case Opcode.OP_NOP9: - case Opcode.OP_NOP10: - { - if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { - this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'; - return false; + return result; + }; + + Node.prototype._encodeValue = function encode(data, reporter, parent) { + var state = this._baseState; + + // Decode root node + if (state.parent === null) return state.children[0]._encode(data, reporter || new Reporter()); + + var result = null; + + // Set reporter to share it with a child class + this.reporter = reporter; + + // Check if data is there + if (state.optional && data === undefined) { + if (state['default'] !== null) data = state['default']; + else return; } - } - break; - case Opcode.OP_IF: - case Opcode.OP_NOTIF: - { - // if [statements] [else [statements]] endif - // bool fValue = false; - fValue = false; - if (fExec) { - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; - return false; - } - buf = this.stack.pop(); - fValue = Interpreter.castToBool(buf); - if (opcodenum === Opcode.OP_NOTIF) { - fValue = !fValue; + // Encode children first + var content = null; + var primitive = false; + if (state.any) { + // Anything that was given is translated to buffer + result = this._createEncoderBuffer(data); + } else if (state.choice) { + result = this._encodeChoice(data, reporter); + } else if (state.contains) { + content = this._getUse(state.contains, parent)._encode(data, reporter); + primitive = true; + } else if (state.children) { + content = state.children + .map(function(child) { + if (child._baseState.tag === 'null_') return child._encode(null, reporter, data); + + if (child._baseState.key === null) return reporter.error('Child should have a key'); + var prevKey = reporter.enterKey(child._baseState.key); + + if (typeof data !== 'object') return reporter.error('Child expected, but input is not object'); + + var res = child._encode(data[child._baseState.key], reporter, data); + reporter.leaveKey(prevKey); + + return res; + }, this) + .filter(function(child) { + return child; + }); + content = this._createEncoderBuffer(content); + } else { + if (state.tag === 'seqof' || state.tag === 'setof') { + // TODO(indutny): this should be thrown on DSL level + if (!(state.args && state.args.length === 1)) return reporter.error('Too many args for : ' + state.tag); + + if (!Array.isArray(data)) return reporter.error('seqof/setof, but data is not Array'); + + var child = this.clone(); + child._baseState.implicit = null; + content = this._createEncoderBuffer( + data.map(function(item) { + var state = this._baseState; + + return this._getUse(state.args[0], data)._encode(item, reporter); + }, child), + ); + } else if (state.use !== null) { + result = this._getUse(state.use, parent)._encode(data, reporter); + } else { + content = this._encodePrimitive(state.tag, data); + primitive = true; } } - this.vfExec.push(fValue); - } - break; - case Opcode.OP_ELSE: - { - if (this.vfExec.length === 0) { - this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; - return false; - } - this.vfExec[this.vfExec.length - 1] = !this.vfExec[this.vfExec.length - 1]; - } - break; + // Encode data itself + var result; + if (!state.any && state.choice === null) { + var tag = state.implicit !== null ? state.implicit : state.tag; + var cls = state.implicit === null ? 'universal' : 'context'; - case Opcode.OP_ENDIF: - { - if (this.vfExec.length === 0) { - this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; - return false; + if (tag === null) { + if (state.use === null) reporter.error('Tag could be ommited only for .use()'); + } else { + if (state.use === null) result = this._encodeComposite(tag, primitive, cls, content); + } } - this.vfExec.pop(); - } - break; - case Opcode.OP_VERIFY: - { - // (true -- ) or - // (false -- false) and return - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf = this.stack[this.stack.length - 1]; - fValue = Interpreter.castToBool(buf); - if (fValue) { - this.stack.pop(); - } else { - this.errstr = 'SCRIPT_ERR_VERIFY'; - return false; - } - } - break; + // Wrap in explicit + if (state.explicit !== null) result = this._encodeComposite(state.explicit, false, 'context', result); - case Opcode.OP_RETURN: - { - this.errstr = 'SCRIPT_ERR_OP_RETURN'; - return false; - } - break; + return result; + }; + Node.prototype._encodeChoice = function encodeChoice(data, reporter) { + var state = this._baseState; - // - // Stack ops - // - case Opcode.OP_TOALTSTACK: - { - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; + var node = state.choice[data.type]; + if (!node) { + assert(false, data.type + ' not found in ' + JSON.stringify(Object.keys(state.choice))); } - this.altstack.push(this.stack.pop()); - } - break; + return node._encode(data.value, reporter); + }; - case Opcode.OP_FROMALTSTACK: - { - if (this.altstack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_ALTSTACK_OPERATION'; - return false; - } - this.stack.push(this.altstack.pop()); - } - break; + Node.prototype._encodePrimitive = function encodePrimitive(tag, data) { + var state = this._baseState; + + if (/str$/.test(tag)) return this._encodeStr(data, tag); + else if (tag === 'objid' && state.args) return this._encodeObjid(data, state.reverseArgs[0], state.args[1]); + else if (tag === 'objid') return this._encodeObjid(data, null, null); + else if (tag === 'gentime' || tag === 'utctime') return this._encodeTime(data, tag); + else if (tag === 'null_') return this._encodeNull(); + else if (tag === 'int' || tag === 'enum') return this._encodeInt(data, state.args && state.reverseArgs[0]); + else if (tag === 'bool') return this._encodeBool(data); + else if (tag === 'objDesc') return this._encodeStr(data, tag); + else throw new Error('Unsupported tag: ' + tag); + }; - case Opcode.OP_2DROP: - { - // (x1 x2 -- ) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - this.stack.pop(); - this.stack.pop(); - } - break; + Node.prototype._isNumstr = function isNumstr(str) { + return /^[0-9 ]*$/.test(str); + }; - case Opcode.OP_2DUP: - { - // (x1 x2 -- x1 x2 x1 x2) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf1 = this.stack[this.stack.length - 2]; - buf2 = this.stack[this.stack.length - 1]; - this.stack.push(buf1); - this.stack.push(buf2); + Node.prototype._isPrintstr = function isPrintstr(str) { + return /^[A-Za-z0-9 '\(\)\+,\-\.\/:=\?]*$/.test(str); + }; + }, + { '../base': 48, 'minimalistic-assert': 192 }, + ], + 50: [ + function(require, module, exports) { + var inherits = require('inherits'); + + function Reporter(options) { + this._reporterState = { + obj: null, + path: [], + options: options || {}, + errors: [], + }; } - break; + exports.Reporter = Reporter; - case Opcode.OP_3DUP: - { - // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) - if (this.stack.length < 3) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf1 = this.stack[this.stack.length - 3]; - buf2 = this.stack[this.stack.length - 2]; - var buf3 = this.stack[this.stack.length - 1]; - this.stack.push(buf1); - this.stack.push(buf2); - this.stack.push(buf3); - } - break; + Reporter.prototype.isError = function isError(obj) { + return obj instanceof ReporterError; + }; - case Opcode.OP_2OVER: - { - // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) - if (this.stack.length < 4) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf1 = this.stack[this.stack.length - 4]; - buf2 = this.stack[this.stack.length - 3]; - this.stack.push(buf1); - this.stack.push(buf2); - } - break; + Reporter.prototype.save = function save() { + var state = this._reporterState; + + return { obj: state.obj, pathLen: state.path.length }; + }; + + Reporter.prototype.restore = function restore(data) { + var state = this._reporterState; + + state.obj = data.obj; + state.path = state.path.slice(0, data.pathLen); + }; + + Reporter.prototype.enterKey = function enterKey(key) { + return this._reporterState.path.push(key); + }; + + Reporter.prototype.exitKey = function exitKey(index) { + var state = this._reporterState; + + state.path = state.path.slice(0, index - 1); + }; - case Opcode.OP_2ROT: - { - // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) - if (this.stack.length < 6) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - spliced = this.stack.splice(this.stack.length - 6, 2); - this.stack.push(spliced[0]); - this.stack.push(spliced[1]); - } - break; + Reporter.prototype.leaveKey = function leaveKey(index, key, value) { + var state = this._reporterState; - case Opcode.OP_2SWAP: - { - // (x1 x2 x3 x4 -- x3 x4 x1 x2) - if (this.stack.length < 4) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - spliced = this.stack.splice(this.stack.length - 4, 2); - this.stack.push(spliced[0]); - this.stack.push(spliced[1]); - } - break; + this.exitKey(index); + if (state.obj !== null) state.obj[key] = value; + }; - case Opcode.OP_IFDUP: - { - // (x - 0 | x x) - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf = this.stack[this.stack.length - 1]; - fValue = Interpreter.castToBool(buf); - if (fValue) { - this.stack.push(buf); - } - } - break; + Reporter.prototype.path = function path() { + return this._reporterState.path.join('/'); + }; - case Opcode.OP_DEPTH: - { - // -- stacksize - buf = new BN(this.stack.length).toScriptNumBuffer(); - this.stack.push(buf); - } - break; + Reporter.prototype.enterObject = function enterObject() { + var state = this._reporterState; - case Opcode.OP_DROP: - { - // (x -- ) - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - this.stack.pop(); - } - break; + var prev = state.obj; + state.obj = {}; + return prev; + }; - case Opcode.OP_DUP: - { - // (x -- x x) - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - this.stack.push(this.stack[this.stack.length - 1]); - } - break; + Reporter.prototype.leaveObject = function leaveObject(prev) { + var state = this._reporterState; - case Opcode.OP_NIP: - { - // (x1 x2 -- x2) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - this.stack.splice(this.stack.length - 2, 1); - } - break; + var now = state.obj; + state.obj = prev; + return now; + }; - case Opcode.OP_OVER: - { - // (x1 x2 -- x1 x2 x1) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - this.stack.push(this.stack[this.stack.length - 2]); - } - break; + Reporter.prototype.error = function error(msg) { + var err; + var state = this._reporterState; - case Opcode.OP_PICK: - case Opcode.OP_ROLL: - { - // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) - // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf = this.stack[this.stack.length - 1]; - bn = BN.fromScriptNumBuffer(buf, fRequireMinimal); - n = bn.toNumber(); - this.stack.pop(); - if (n < 0 || n >= this.stack.length) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf = this.stack[this.stack.length - n - 1]; - if (opcodenum === Opcode.OP_ROLL) { - this.stack.splice(this.stack.length - n - 1, 1); + var inherited = msg instanceof ReporterError; + if (inherited) { + err = msg; + } else { + err = new ReporterError( + state.path + .map(function(elem) { + return '[' + JSON.stringify(elem) + ']'; + }) + .join(''), + msg.message || msg, + msg.stack, + ); } - this.stack.push(buf); - } - break; - case Opcode.OP_ROT: - { - // (x1 x2 x3 -- x2 x3 x1) - // x2 x1 x3 after first swap - // x2 x3 x1 after second swap - if (this.stack.length < 3) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - x1 = this.stack[this.stack.length - 3]; - x2 = this.stack[this.stack.length - 2]; - var x3 = this.stack[this.stack.length - 1]; - this.stack[this.stack.length - 3] = x2; - this.stack[this.stack.length - 2] = x3; - this.stack[this.stack.length - 1] = x1; - } - break; + if (!state.options.partial) throw err; - case Opcode.OP_SWAP: - { - // (x1 x2 -- x2 x1) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - x1 = this.stack[this.stack.length - 2]; - x2 = this.stack[this.stack.length - 1]; - this.stack[this.stack.length - 2] = x2; - this.stack[this.stack.length - 1] = x1; - } - break; + if (!inherited) state.errors.push(err); - case Opcode.OP_TUCK: - { - // (x1 x2 -- x2 x1 x2) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - this.stack.splice(this.stack.length - 2, 0, this.stack[this.stack.length - 1]); - } - break; + return err; + }; + Reporter.prototype.wrapResult = function wrapResult(result) { + var state = this._reporterState; + if (!state.options.partial) return result; - case Opcode.OP_SIZE: - { - // (in -- in size) - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - bn = new BN(this.stack[this.stack.length - 1].length); - this.stack.push(bn.toScriptNumBuffer()); + return { + result: this.isError(result) ? null : result, + errors: state.errors, + }; + }; + + function ReporterError(path, msg) { + this.path = path; + this.rethrow(msg); } - break; + inherits(ReporterError, Error); + ReporterError.prototype.rethrow = function rethrow(msg) { + this.message = msg + ' at: ' + (this.path || '(shallow)'); + if (Error.captureStackTrace) Error.captureStackTrace(this, ReporterError); - // - // Bitwise logic - // - case Opcode.OP_EQUAL: - case Opcode.OP_EQUALVERIFY: - //case Opcode.OP_NOTEQUAL: // use Opcode.OP_NUMNOTEQUAL - { - // (x1 x2 - bool) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf1 = this.stack[this.stack.length - 2]; - buf2 = this.stack[this.stack.length - 1]; - var fEqual = buf1.toString('hex') === buf2.toString('hex'); - this.stack.pop(); - this.stack.pop(); - this.stack.push(fEqual ? Interpreter.true : Interpreter.false); - if (opcodenum === Opcode.OP_EQUALVERIFY) { - if (fEqual) { - this.stack.pop(); - } else { - this.errstr = 'SCRIPT_ERR_EQUALVERIFY'; - return false; + if (!this.stack) { + try { + // IE only adds stack when thrown + throw new Error(this.message); + } catch (e) { + this.stack = e.stack; } } - } - break; + return this; + }; + }, + { inherits: 184 }, + ], + 51: [ + function(require, module, exports) { + var constants = require('../constants'); + + exports.tagClass = { + 0: 'universal', + 1: 'application', + 2: 'context', + 3: 'private', + }; + exports.tagClassByName = constants._reverse(exports.tagClass); + + exports.tag = { + 0x00: 'end', + 0x01: 'bool', + 0x02: 'int', + 0x03: 'bitstr', + 0x04: 'octstr', + 0x05: 'null_', + 0x06: 'objid', + 0x07: 'objDesc', + 0x08: 'external', + 0x09: 'real', + 0x0a: 'enum', + 0x0b: 'embed', + 0x0c: 'utf8str', + 0x0d: 'relativeOid', + 0x10: 'seq', + 0x11: 'set', + 0x12: 'numstr', + 0x13: 'printstr', + 0x14: 't61str', + 0x15: 'videostr', + 0x16: 'ia5str', + 0x17: 'utctime', + 0x18: 'gentime', + 0x19: 'graphstr', + 0x1a: 'iso646str', + 0x1b: 'genstr', + 0x1c: 'unistr', + 0x1d: 'charstr', + 0x1e: 'bmpstr', + }; + exports.tagByName = constants._reverse(exports.tag); + }, + { '../constants': 52 }, + ], + 52: [ + function(require, module, exports) { + var constants = exports; + + // Helper + constants._reverse = function reverse(map) { + var res = {}; + + Object.keys(map).forEach(function(key) { + // Convert key to integer if it is stringified + if ((key | 0) == key) key = key | 0; + + var value = map[key]; + res[value] = key; + }); + return res; + }; - // - // Numeric - // - case Opcode.OP_1ADD: - case Opcode.OP_1SUB: - case Opcode.OP_NEGATE: - case Opcode.OP_ABS: - case Opcode.OP_NOT: - case Opcode.OP_0NOTEQUAL: - { - // (in -- out) - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf = this.stack[this.stack.length - 1]; - bn = BN.fromScriptNumBuffer(buf, fRequireMinimal); - switch (opcodenum) { - case Opcode.OP_1ADD: - bn = bn.add(BN.One); - break; - case Opcode.OP_1SUB: - bn = bn.sub(BN.One); - break; - case Opcode.OP_NEGATE: - bn = bn.neg(); - break; - case Opcode.OP_ABS: - if (bn.cmp(BN.Zero) < 0) { - bn = bn.neg(); - } - break; - case Opcode.OP_NOT: - bn = new BN((bn.cmp(BN.Zero) === 0) + 0); - break; - case Opcode.OP_0NOTEQUAL: - bn = new BN((bn.cmp(BN.Zero) !== 0) + 0); - break; - //default: assert(!'invalid opcode'); break; // TODO: does this ever occur? - } - this.stack.pop(); - this.stack.push(bn.toScriptNumBuffer()); - } - break; - - case Opcode.OP_ADD: - case Opcode.OP_SUB: - case Opcode.OP_BOOLAND: - case Opcode.OP_BOOLOR: - case Opcode.OP_NUMEQUAL: - case Opcode.OP_NUMEQUALVERIFY: - case Opcode.OP_NUMNOTEQUAL: - case Opcode.OP_LESSTHAN: - case Opcode.OP_GREATERTHAN: - case Opcode.OP_LESSTHANOREQUAL: - case Opcode.OP_GREATERTHANOREQUAL: - case Opcode.OP_MIN: - case Opcode.OP_MAX: - { - // (x1 x2 -- out) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - bn1 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal); - bn2 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal); - bn = new BN(0); + constants.der = require('./der'); + }, + { './der': 51 }, + ], + 53: [ + function(require, module, exports) { + var inherits = require('inherits'); + + var asn1 = require('../../asn1'); + var base = asn1.base; + var bignum = asn1.bignum; + + // Import DER constants + var der = asn1.constants.der; + + function DERDecoder(entity) { + this.enc = 'der'; + this.name = entity.name; + this.entity = entity; + + // Construct base tree + this.tree = new DERNode(); + this.tree._init(entity.body); + } + module.exports = DERDecoder; - switch (opcodenum) { - case Opcode.OP_ADD: - bn = bn1.add(bn2); - break; + DERDecoder.prototype.decode = function decode(data, options) { + if (!(data instanceof base.DecoderBuffer)) data = new base.DecoderBuffer(data, options); - case Opcode.OP_SUB: - bn = bn1.sub(bn2); - break; + return this.tree._decode(data, options); + }; - // case Opcode.OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; - case Opcode.OP_BOOLAND: - bn = new BN(((bn1.cmp(BN.Zero) !== 0) && (bn2.cmp(BN.Zero) !== 0)) + 0); - break; - // case Opcode.OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; - case Opcode.OP_BOOLOR: - bn = new BN(((bn1.cmp(BN.Zero) !== 0) || (bn2.cmp(BN.Zero) !== 0)) + 0); - break; - // case Opcode.OP_NUMEQUAL: bn = (bn1 == bn2); break; - case Opcode.OP_NUMEQUAL: - bn = new BN((bn1.cmp(bn2) === 0) + 0); - break; - // case Opcode.OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break; - case Opcode.OP_NUMEQUALVERIFY: - bn = new BN((bn1.cmp(bn2) === 0) + 0); - break; - // case Opcode.OP_NUMNOTEQUAL: bn = (bn1 != bn2); break; - case Opcode.OP_NUMNOTEQUAL: - bn = new BN((bn1.cmp(bn2) !== 0) + 0); - break; - // case Opcode.OP_LESSTHAN: bn = (bn1 < bn2); break; - case Opcode.OP_LESSTHAN: - bn = new BN((bn1.cmp(bn2) < 0) + 0); - break; - // case Opcode.OP_GREATERTHAN: bn = (bn1 > bn2); break; - case Opcode.OP_GREATERTHAN: - bn = new BN((bn1.cmp(bn2) > 0) + 0); - break; - // case Opcode.OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break; - case Opcode.OP_LESSTHANOREQUAL: - bn = new BN((bn1.cmp(bn2) <= 0) + 0); - break; - // case Opcode.OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; - case Opcode.OP_GREATERTHANOREQUAL: - bn = new BN((bn1.cmp(bn2) >= 0) + 0); - break; - case Opcode.OP_MIN: - bn = (bn1.cmp(bn2) < 0 ? bn1 : bn2); - break; - case Opcode.OP_MAX: - bn = (bn1.cmp(bn2) > 0 ? bn1 : bn2); - break; - // default: assert(!'invalid opcode'); break; //TODO: does this ever occur? - } - this.stack.pop(); - this.stack.pop(); - this.stack.push(bn.toScriptNumBuffer()); + // Tree methods - if (opcodenum === Opcode.OP_NUMEQUALVERIFY) { - // if (CastToBool(stacktop(-1))) - if (Interpreter.castToBool(this.stack[this.stack.length - 1])) { - this.stack.pop(); - } else { - this.errstr = 'SCRIPT_ERR_NUMEQUALVERIFY'; - return false; - } - } + function DERNode(parent) { + base.Node.call(this, 'der', parent); } - break; + inherits(DERNode, base.Node); - case Opcode.OP_WITHIN: - { - // (x min max -- out) - if (this.stack.length < 3) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - bn1 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 3], fRequireMinimal); - bn2 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal); - var bn3 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal); - //bool fValue = (bn2 <= bn1 && bn1 < bn3); - fValue = (bn2.cmp(bn1) <= 0) && (bn1.cmp(bn3) < 0); - this.stack.pop(); - this.stack.pop(); - this.stack.pop(); - this.stack.push(fValue ? Interpreter.true : Interpreter.false); - } - break; + DERNode.prototype._peekTag = function peekTag(buffer, tag, any) { + if (buffer.isEmpty()) return false; + var state = buffer.save(); + var decodedTag = derDecodeTag(buffer, 'Failed to peek tag: "' + tag + '"'); + if (buffer.isError(decodedTag)) return decodedTag; - // - // Crypto - // - case Opcode.OP_RIPEMD160: - case Opcode.OP_SHA1: - case Opcode.OP_SHA256: - case Opcode.OP_HASH160: - case Opcode.OP_HASH256: - { - // (in -- hash) - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf = this.stack[this.stack.length - 1]; - //valtype vchHash((opcode == Opcode.OP_RIPEMD160 || - // opcode == Opcode.OP_SHA1 || opcode == Opcode.OP_HASH160) ? 20 : 32); - var bufHash; - if (opcodenum === Opcode.OP_RIPEMD160) { - bufHash = Hash.ripemd160(buf); - } else if (opcodenum === Opcode.OP_SHA1) { - bufHash = Hash.sha1(buf); - } else if (opcodenum === Opcode.OP_SHA256) { - bufHash = Hash.sha256(buf); - } else if (opcodenum === Opcode.OP_HASH160) { - bufHash = Hash.sha256ripemd160(buf); - } else if (opcodenum === Opcode.OP_HASH256) { - bufHash = Hash.sha256sha256(buf); - } - this.stack.pop(); - this.stack.push(bufHash); - } - break; - - case Opcode.OP_CODESEPARATOR: - { - // Hash starts after the code separator - this.pbegincodehash = this.pc; - } - break; - - case Opcode.OP_CHECKSIG: - case Opcode.OP_CHECKSIGVERIFY: - { - // (sig pubkey -- bool) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } + buffer.restore(state); - bufSig = this.stack[this.stack.length - 2]; - bufPubkey = this.stack[this.stack.length - 1]; + return decodedTag.tag === tag || decodedTag.tagStr === tag || decodedTag.tagStr + 'of' === tag || any; + }; - // Subset of script starting at the most recent codeseparator - // CScript scriptCode(pbegincodehash, pend); - subscript = new Script().set({ - chunks: this.script.chunks.slice(this.pbegincodehash) - }); + DERNode.prototype._decodeTag = function decodeTag(buffer, tag, any) { + var decodedTag = derDecodeTag(buffer, 'Failed to decode tag of "' + tag + '"'); + if (buffer.isError(decodedTag)) return decodedTag; - // Drop the signature, since there's no way for a signature to sign itself - var tmpScript = new Script().add(bufSig); - subscript.findAndDelete(tmpScript); + var len = derDecodeLen(buffer, decodedTag.primitive, 'Failed to get length of "' + tag + '"'); - if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) { - return false; - } + // Failure + if (buffer.isError(len)) return len; - try { - sig = Signature.fromTxFormat(bufSig); - pubkey = PublicKey.fromBuffer(bufPubkey, false); - fSuccess = this.tx.verifySignature(sig, pubkey, this.nin, subscript); - } catch (e) { - //invalid sig or pubkey - fSuccess = false; + if (!any && decodedTag.tag !== tag && decodedTag.tagStr !== tag && decodedTag.tagStr + 'of' !== tag) { + return buffer.error('Failed to match tag: "' + tag + '"'); } - this.stack.pop(); - this.stack.pop(); - // stack.push_back(fSuccess ? vchTrue : vchFalse); - this.stack.push(fSuccess ? Interpreter.true : Interpreter.false); - if (opcodenum === Opcode.OP_CHECKSIGVERIFY) { - if (fSuccess) { - this.stack.pop(); - } else { - this.errstr = 'SCRIPT_ERR_CHECKSIGVERIFY'; - return false; - } - } - } - break; + if (decodedTag.primitive || len !== null) return buffer.skip(len, 'Failed to match body of: "' + tag + '"'); - case Opcode.OP_CHECKMULTISIG: - case Opcode.OP_CHECKMULTISIGVERIFY: - { - // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) + // Indefinite length... find END tag + var state = buffer.save(); + var res = this._skipUntilEnd(buffer, 'Failed to skip indefinite length body: "' + this.tag + '"'); + if (buffer.isError(res)) return res; - var i = 1; - if (this.stack.length < i) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } + len = buffer.offset - state.offset; + buffer.restore(state); + return buffer.skip(len, 'Failed to match body of: "' + tag + '"'); + }; - var nKeysCount = BN.fromScriptNumBuffer(this.stack[this.stack.length - i], fRequireMinimal).toNumber(); - if (nKeysCount < 0 || nKeysCount > 20) { - this.errstr = 'SCRIPT_ERR_PUBKEY_COUNT'; - return false; - } - this.nOpCount += nKeysCount; - if (this.nOpCount > 201) { - this.errstr = 'SCRIPT_ERR_OP_COUNT'; - return false; - } - // int ikey = ++i; - var ikey = ++i; - i += nKeysCount; - if (this.stack.length < i) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } + DERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer, fail) { + while (true) { + var tag = derDecodeTag(buffer, fail); + if (buffer.isError(tag)) return tag; + var len = derDecodeLen(buffer, tag.primitive, fail); + if (buffer.isError(len)) return len; - var nSigsCount = BN.fromScriptNumBuffer(this.stack[this.stack.length - i], fRequireMinimal).toNumber(); - if (nSigsCount < 0 || nSigsCount > nKeysCount) { - this.errstr = 'SCRIPT_ERR_SIG_COUNT'; - return false; - } - // int isig = ++i; - var isig = ++i; - i += nSigsCount; - if (this.stack.length < i) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } + var res; + if (tag.primitive || len !== null) res = buffer.skip(len); + else res = this._skipUntilEnd(buffer, fail); - // Subset of script starting at the most recent codeseparator - subscript = new Script().set({ - chunks: this.script.chunks.slice(this.pbegincodehash) - }); + // Failure + if (buffer.isError(res)) return res; - // Drop the signatures, since there's no way for a signature to sign itself - for (var k = 0; k < nSigsCount; k++) { - bufSig = this.stack[this.stack.length - isig - k]; - subscript.findAndDelete(new Script().add(bufSig)); + if (tag.tagStr === 'end') break; } + }; - fSuccess = true; - while (fSuccess && nSigsCount > 0) { - // valtype& vchSig = stacktop(-isig); - bufSig = this.stack[this.stack.length - isig]; - // valtype& vchPubKey = stacktop(-ikey); - bufPubkey = this.stack[this.stack.length - ikey]; + DERNode.prototype._decodeList = function decodeList(buffer, tag, decoder, options) { + var result = []; + while (!buffer.isEmpty()) { + var possibleEnd = this._peekTag(buffer, 'end'); + if (buffer.isError(possibleEnd)) return possibleEnd; - if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) { - return false; - } + var res = decoder.decode(buffer, 'der', options); + if (buffer.isError(res) && possibleEnd) break; + result.push(res); + } + return result; + }; - var fOk; - try { - sig = Signature.fromTxFormat(bufSig); - pubkey = PublicKey.fromBuffer(bufPubkey, false); - fOk = this.tx.verifySignature(sig, pubkey, this.nin, subscript); - } catch (e) { - //invalid sig or pubkey - fOk = false; + DERNode.prototype._decodeStr = function decodeStr(buffer, tag) { + if (tag === 'bitstr') { + var unused = buffer.readUInt8(); + if (buffer.isError(unused)) return unused; + return { unused: unused, data: buffer.raw() }; + } else if (tag === 'bmpstr') { + var raw = buffer.raw(); + if (raw.length % 2 === 1) return buffer.error('Decoding of string type: bmpstr length mismatch'); + + var str = ''; + for (var i = 0; i < raw.length / 2; i++) { + str += String.fromCharCode(raw.readUInt16BE(i * 2)); } - - if (fOk) { - isig++; - nSigsCount--; + return str; + } else if (tag === 'numstr') { + var numstr = buffer.raw().toString('ascii'); + if (!this._isNumstr(numstr)) { + return buffer.error('Decoding of string type: ' + 'numstr unsupported characters'); } - ikey++; - nKeysCount--; - - // If there are more signatures left than keys left, - // then too many signatures have failed - if (nSigsCount > nKeysCount) { - fSuccess = false; + return numstr; + } else if (tag === 'octstr') { + return buffer.raw(); + } else if (tag === 'objDesc') { + return buffer.raw(); + } else if (tag === 'printstr') { + var printstr = buffer.raw().toString('ascii'); + if (!this._isPrintstr(printstr)) { + return buffer.error('Decoding of string type: ' + 'printstr unsupported characters'); } + return printstr; + } else if (/str$/.test(tag)) { + return buffer.raw().toString(); + } else { + return buffer.error('Decoding of string type: ' + tag + ' unsupported'); } + }; - // Clean up stack of actual arguments - while (i-- > 1) { - this.stack.pop(); + DERNode.prototype._decodeObjid = function decodeObjid(buffer, values, relative) { + var result; + var identifiers = []; + var ident = 0; + while (!buffer.isEmpty()) { + var subident = buffer.readUInt8(); + ident <<= 7; + ident |= subident & 0x7f; + if ((subident & 0x80) === 0) { + identifiers.push(ident); + ident = 0; + } } + if (subident & 0x80) identifiers.push(ident); - // A bug causes CHECKMULTISIG to consume one extra argument - // whose contents were not checked in any way. - // - // Unfortunately this is a potential source of mutability, - // so optionally verify it is exactly equal to zero prior - // to removing it from the stack. - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - if ((this.flags & Interpreter.SCRIPT_VERIFY_NULLDUMMY) && this.stack[this.stack.length - 1].length) { - this.errstr = 'SCRIPT_ERR_SIG_NULLDUMMY'; - return false; + var first = (identifiers[0] / 40) | 0; + var second = identifiers[0] % 40; + + if (relative) result = identifiers; + else result = [first, second].concat(identifiers.slice(1)); + + if (values) { + var tmp = values[result.join(' ')]; + if (tmp === undefined) tmp = values[result.join('.')]; + if (tmp !== undefined) result = tmp; } - this.stack.pop(); - this.stack.push(fSuccess ? Interpreter.true : Interpreter.false); + return result; + }; - if (opcodenum === Opcode.OP_CHECKMULTISIGVERIFY) { - if (fSuccess) { - this.stack.pop(); - } else { - this.errstr = 'SCRIPT_ERR_CHECKMULTISIGVERIFY'; - return false; - } + DERNode.prototype._decodeTime = function decodeTime(buffer, tag) { + var str = buffer.raw().toString(); + if (tag === 'gentime') { + var year = str.slice(0, 4) | 0; + var mon = str.slice(4, 6) | 0; + var day = str.slice(6, 8) | 0; + var hour = str.slice(8, 10) | 0; + var min = str.slice(10, 12) | 0; + var sec = str.slice(12, 14) | 0; + } else if (tag === 'utctime') { + var year = str.slice(0, 2) | 0; + var mon = str.slice(2, 4) | 0; + var day = str.slice(4, 6) | 0; + var hour = str.slice(6, 8) | 0; + var min = str.slice(8, 10) | 0; + var sec = str.slice(10, 12) | 0; + if (year < 70) year = 2000 + year; + else year = 1900 + year; + } else { + return buffer.error('Decoding ' + tag + ' time is not supported yet'); } - } - break; - default: - this.errstr = 'SCRIPT_ERR_BAD_OPCODE'; - return false; - } - } + return Date.UTC(year, mon - 1, day, hour, min, sec, 0); + }; - return true; -}; - - -}).call(this,require("buffer").Buffer) -},{"../crypto/bn":6,"../crypto/hash":8,"../crypto/signature":11,"../opcode":22,"../publickey":24,"../transaction":28,"./script":27,"buffer":113,"lodash":187}],27:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var Address = require('../address'); -var BufferReader = require('../encoding/bufferreader'); -var BufferWriter = require('../encoding/bufferwriter'); -var Hash = require('../crypto/hash'); -var Opcode = require('../opcode'); -var PublicKey = require('../publickey'); -var Signature = require('../crypto/signature'); -var Networks = require('../networks'); -var $ = require('../util/preconditions'); -var _ = require('lodash'); -var errors = require('../errors'); -var buffer = require('buffer'); -var BufferUtil = require('../util/buffer'); -var JSUtil = require('../util/js'); - -/** - * A Merit transaction script. Each transaction's inputs and outputs - * has a script that is evaluated to validate it's spending. - * - * See https://en.bitcoin.it/wiki/Script - * - * @constructor - * @param {Object|string|Buffer=} from optional data to populate script - */ -var Script = function Script(from) { - if (!(this instanceof Script)) { - return new Script(from); - } - this.chunks = []; - - if (BufferUtil.isBuffer(from)) { - return Script.fromBuffer(from); - } else if (from instanceof Address) { - return Script.fromAddress(from); - } else if (from instanceof Script) { - return Script.fromBuffer(from.toBuffer()); - } else if (typeof from === 'string') { - return Script.fromString(from); - } else if (typeof from !== 'undefined') { - this.set(from); - } -}; - -Script.prototype.set = function(obj) { - this.chunks = obj.chunks || this.chunks; - return this; -}; - -Script.fromBuffer = function(buffer) { - var script = new Script(); - script.chunks = []; - - var br = new BufferReader(buffer); - while (!br.finished()) { - try { - var opcodenum = br.readUInt8(); - - var len, buf; - if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) { - len = opcodenum; - script.chunks.push({ - buf: br.read(len), - len: len, - opcodenum: opcodenum - }); - } else if (opcodenum === Opcode.OP_PUSHDATA1) { - len = br.readUInt8(); - buf = br.read(len); - script.chunks.push({ - buf: buf, - len: len, - opcodenum: opcodenum - }); - } else if (opcodenum === Opcode.OP_PUSHDATA2) { - len = br.readUInt16LE(); - buf = br.read(len); - script.chunks.push({ - buf: buf, - len: len, - opcodenum: opcodenum - }); - } else if (opcodenum === Opcode.OP_PUSHDATA4) { - len = br.readUInt32LE(); - buf = br.read(len); - script.chunks.push({ - buf: buf, - len: len, - opcodenum: opcodenum - }); - } else { - script.chunks.push({ - opcodenum: opcodenum - }); - } - } catch (e) { - if (e instanceof RangeError) { - throw new errors.Script.InvalidBuffer(buffer.toString('hex')); - } - throw e; - } - } + DERNode.prototype._decodeNull = function decodeNull(buffer) { + return null; + }; - return script; -}; - -Script.prototype.toBuffer = function() { - var bw = new BufferWriter(); - - for (var i = 0; i < this.chunks.length; i++) { - var chunk = this.chunks[i]; - var opcodenum = chunk.opcodenum; - bw.writeUInt8(chunk.opcodenum); - if (chunk.buf) { - if (opcodenum < Opcode.OP_PUSHDATA1) { - bw.write(chunk.buf); - } else if (opcodenum === Opcode.OP_PUSHDATA1) { - bw.writeUInt8(chunk.len); - bw.write(chunk.buf); - } else if (opcodenum === Opcode.OP_PUSHDATA2) { - bw.writeUInt16LE(chunk.len); - bw.write(chunk.buf); - } else if (opcodenum === Opcode.OP_PUSHDATA4) { - bw.writeUInt32LE(chunk.len); - bw.write(chunk.buf); - } - } - } + DERNode.prototype._decodeBool = function decodeBool(buffer) { + var res = buffer.readUInt8(); + if (buffer.isError(res)) return res; + else return res !== 0; + }; - return bw.concat(); -}; - -Script.fromASM = function(str) { - var script = new Script(); - script.chunks = []; - - var tokens = str.split(' '); - var i = 0; - while (i < tokens.length) { - var token = tokens[i]; - var opcode = Opcode(token); - var opcodenum = opcode.toNumber(); - - if (_.isUndefined(opcodenum)) { - var buf = new Buffer(tokens[i], 'hex'); - script.chunks.push({ - buf: buf, - len: buf.length, - opcodenum: buf.length - }); - i = i + 1; - } else if (opcodenum === Opcode.OP_PUSHDATA1 || - opcodenum === Opcode.OP_PUSHDATA2 || - opcodenum === Opcode.OP_PUSHDATA4) { - script.chunks.push({ - buf: new Buffer(tokens[i + 2], 'hex'), - len: parseInt(tokens[i + 1]), - opcodenum: opcodenum - }); - i = i + 3; - } else { - script.chunks.push({ - opcodenum: opcodenum - }); - i = i + 1; - } - } - return script; -}; + DERNode.prototype._decodeInt = function decodeInt(buffer, values) { + // Bigint, return as it is (assume big endian) + var raw = buffer.raw(); + var res = new bignum(raw); -Script.fromHex = function(str) { - return new Script(new buffer.Buffer(str, 'hex')); -}; + if (values) res = values[res.toString(10)] || res; -Script.fromString = function(str) { - if (JSUtil.isHexa(str) || str.length === 0) { - return new Script(new buffer.Buffer(str, 'hex')); - } - var script = new Script(); - script.chunks = []; - - var tokens = str.split(' '); - var i = 0; - while (i < tokens.length) { - var token = tokens[i]; - var opcode = Opcode(token); - var opcodenum = opcode.toNumber(); - - if (_.isUndefined(opcodenum)) { - opcodenum = parseInt(token); - if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) { - script.chunks.push({ - buf: new Buffer(tokens[i + 1].slice(2), 'hex'), - len: opcodenum, - opcodenum: opcodenum - }); - i = i + 2; - } else { - throw new Error('Invalid script: ' + JSON.stringify(str)); - } - } else if (opcodenum === Opcode.OP_PUSHDATA1 || - opcodenum === Opcode.OP_PUSHDATA2 || - opcodenum === Opcode.OP_PUSHDATA4) { - if (tokens[i + 2].slice(0, 2) !== '0x') { - throw new Error('Pushdata data must start with 0x'); - } - script.chunks.push({ - buf: new Buffer(tokens[i + 2].slice(2), 'hex'), - len: parseInt(tokens[i + 1]), - opcodenum: opcodenum - }); - i = i + 3; - } else { - script.chunks.push({ - opcodenum: opcodenum - }); - i = i + 1; - } - } - return script; -}; - -Script.prototype._chunkToString = function(chunk, type) { - var opcodenum = chunk.opcodenum; - var asm = (type === 'asm'); - var str = ''; - if (!chunk.buf) { - // no data chunk - if (typeof Opcode.reverseMap[opcodenum] !== 'undefined') { - str = str + ' ' + Opcode(opcodenum).toString(); - } else { - var numstr = opcodenum.toString(16); - if (numstr.length % 2 !== 0) { - numstr = '0' + numstr; - } - if (asm) { - str = str + ' ' + numstr; - } else { - str = str + ' ' + '0x' + numstr; - } - } - } else { - // data chunk - if (opcodenum === Opcode.OP_PUSHDATA1 || - opcodenum === Opcode.OP_PUSHDATA2 || - opcodenum === Opcode.OP_PUSHDATA4) { - str = str + ' ' + Opcode(opcodenum).toString(); - } - if (chunk.len > 0) { - if (asm) { - str = str + ' ' + chunk.buf.toString('hex'); - } else { - str = str + ' ' + chunk.len + ' ' + '0x' + chunk.buf.toString('hex'); - } - } - } - return str; -}; - -Script.prototype.toASM = function() { - var str = ''; - for (var i = 0; i < this.chunks.length; i++) { - var chunk = this.chunks[i]; - str += this._chunkToString(chunk, 'asm'); - } + return res; + }; - return str.substr(1); -}; + DERNode.prototype._use = function use(entity, obj) { + if (typeof entity === 'function') entity = entity(obj); + return entity._getDecoder('der').tree; + }; -Script.prototype.toString = function() { - var str = ''; - for (var i = 0; i < this.chunks.length; i++) { - var chunk = this.chunks[i]; - str += this._chunkToString(chunk); - } + // Utility methods - return str.substr(1); -}; + function derDecodeTag(buf, fail) { + var tag = buf.readUInt8(fail); + if (buf.isError(tag)) return tag; -Script.prototype.toHex = function() { - return this.toBuffer().toString('hex'); -}; + var cls = der.tagClass[tag >> 6]; + var primitive = (tag & 0x20) === 0; -Script.prototype.inspect = function() { - return ''; -}; + // Multi-octet tag - load + if ((tag & 0x1f) === 0x1f) { + var oct = tag; + tag = 0; + while ((oct & 0x80) === 0x80) { + oct = buf.readUInt8(fail); + if (buf.isError(oct)) return oct; -// script classification methods + tag <<= 7; + tag |= oct & 0x7f; + } + } else { + tag &= 0x1f; + } + var tagStr = der.tag[tag]; -/** - * @returns {boolean} if this is a pay to pubkey hash output script - */ -Script.prototype.isPublicKeyHashOut = function() { - return !!(this.chunks.length === 5 && - this.chunks[0].opcodenum === Opcode.OP_DUP && - this.chunks[1].opcodenum === Opcode.OP_HASH160 && - this.chunks[2].buf && - this.chunks[2].buf.length === 20 && - this.chunks[3].opcodenum === Opcode.OP_EQUALVERIFY && - this.chunks[4].opcodenum === Opcode.OP_CHECKSIG); -}; - -/** - * @returns {boolean} if this is a pay to public key hash input script - */ -Script.prototype.isPublicKeyHashIn = function() { - if (this.chunks.length === 2) { - var signatureBuf = this.chunks[0].buf; - var pubkeyBuf = this.chunks[1].buf; - if (signatureBuf && - signatureBuf.length && - signatureBuf[0] === 0x30 && - pubkeyBuf && - pubkeyBuf.length - ) { - var version = pubkeyBuf[0]; - if ((version === 0x04 || - version === 0x06 || - version === 0x07) && pubkeyBuf.length === 65) { - return true; - } else if ((version === 0x03 || version === 0x02) && pubkeyBuf.length === 33) { - return true; - } - } - } - return false; -}; + return { + cls: cls, + primitive: primitive, + tag: tag, + tagStr: tagStr, + }; + } -Script.prototype.getPublicKey = function() { - $.checkState(this.isPublicKeyOut(), 'Can\'t retrieve PublicKey from a non-PK output'); - return this.chunks[0].buf; -}; + function derDecodeLen(buf, primitive, fail) { + var len = buf.readUInt8(fail); + if (buf.isError(len)) return len; -Script.prototype.getPublicKeyHash = function() { - $.checkState(this.isPublicKeyHashOut(), 'Can\'t retrieve PublicKeyHash from a non-PKH output'); - return this.chunks[2].buf; -}; + // Indefinite form + if (!primitive && len === 0x80) return null; -/** - * @returns {boolean} if this is a public key output script - */ -Script.prototype.isPublicKeyOut = function() { - if (this.chunks.length === 2 && - this.chunks[0].buf && - this.chunks[0].buf.length && - this.chunks[1].opcodenum === Opcode.OP_CHECKSIG) { - var pubkeyBuf = this.chunks[0].buf; - var version = pubkeyBuf[0]; - var isVersion = false; - if ((version === 0x04 || - version === 0x06 || - version === 0x07) && pubkeyBuf.length === 65) { - isVersion = true; - } else if ((version === 0x03 || version === 0x02) && pubkeyBuf.length === 33) { - isVersion = true; - } - if (isVersion) { - return PublicKey.isValid(pubkeyBuf); - } - } - return false; -}; + // Definite form + if ((len & 0x80) === 0) { + // Short form + return len; + } -/** - * @returns {boolean} if this is a pay to public key input script - */ -Script.prototype.isPublicKeyIn = function() { - if (this.chunks.length === 1) { - var signatureBuf = this.chunks[0].buf; - if (signatureBuf && - signatureBuf.length && - signatureBuf[0] === 0x30) { - return true; - } - } - return false; -}; + // Long form + var num = len & 0x7f; + if (num > 4) return buf.error('length octect is too long'); -/** - * @returns {boolean} if this is a p2sh output script - */ -Script.prototype.isScriptHashOut = function() { - var buf = this.toBuffer(); - return (buf.length === 23 && - buf[0] === Opcode.OP_HASH160 && - buf[1] === 0x14 && - buf[buf.length - 1] === Opcode.OP_EQUAL); -}; - -/** - * @returns {boolean} if this is a p2sh input script - * Note that these are frequently indistinguishable from pubkeyhashin - */ -Script.prototype.isScriptHashIn = function() { - if (this.chunks.length <= 1) { - return false; - } - var redeemChunk = this.chunks[this.chunks.length - 1]; - var redeemBuf = redeemChunk.buf; - if (!redeemBuf) { - return false; - } + len = 0; + for (var i = 0; i < num; i++) { + len <<= 8; + var j = buf.readUInt8(fail); + if (buf.isError(j)) return j; + len |= j; + } - var redeemScript; - try { - redeemScript = Script.fromBuffer(redeemBuf); - } catch (e) { - if (e instanceof errors.Script.InvalidBuffer) { - return false; - } - throw e; - } - var type = redeemScript.classify(); - return type !== Script.types.UNKNOWN; -}; + return len; + } + }, + { '../../asn1': 45, inherits: 184 }, + ], + 54: [ + function(require, module, exports) { + var decoders = exports; + + decoders.der = require('./der'); + decoders.pem = require('./pem'); + }, + { './der': 53, './pem': 55 }, + ], + 55: [ + function(require, module, exports) { + var inherits = require('inherits'); + var Buffer = require('buffer').Buffer; + + var DERDecoder = require('./der'); + + function PEMDecoder(entity) { + DERDecoder.call(this, entity); + this.enc = 'pem'; + } + inherits(PEMDecoder, DERDecoder); + module.exports = PEMDecoder; -/** - * @returns {boolean} if this is a mutlsig output script - */ -Script.prototype.isMultisigOut = function() { - return (this.chunks.length > 3 && - Opcode.isSmallIntOp(this.chunks[0].opcodenum) && - this.chunks.slice(1, this.chunks.length - 2).every(function(obj) { - return obj.buf && BufferUtil.isBuffer(obj.buf); - }) && - Opcode.isSmallIntOp(this.chunks[this.chunks.length - 2].opcodenum) && - this.chunks[this.chunks.length - 1].opcodenum === Opcode.OP_CHECKMULTISIG); -}; - - -/** - * @returns {boolean} if this is a multisig input script - */ -Script.prototype.isMultisigIn = function() { - return this.chunks.length >= 2 && - this.chunks[0].opcodenum === 0 && - this.chunks.slice(1, this.chunks.length).every(function(obj) { - return obj.buf && - BufferUtil.isBuffer(obj.buf) && - Signature.isTxDER(obj.buf); - }); -}; - -/** - * @returns {boolean} true if this is a valid standard OP_RETURN output - */ -Script.prototype.isDataOut = function() { - return this.chunks.length >= 1 && - this.chunks[0].opcodenum === Opcode.OP_RETURN && - (this.chunks.length === 1 || - (this.chunks.length === 2 && - this.chunks[1].buf && - this.chunks[1].buf.length <= Script.OP_RETURN_STANDARD_SIZE && - this.chunks[1].length === this.chunks.len)); -}; - -/** - * Retrieve the associated data for this script. - * In the case of a pay to public key hash or P2SH, return the hash. - * In the case of a standard OP_RETURN, return the data - * @returns {Buffer} - */ -Script.prototype.getData = function() { - if (this.isDataOut() || this.isScriptHashOut()) { - if (_.isUndefined(this.chunks[1])) { - return new Buffer(0); - } else { - return new Buffer(this.chunks[1].buf); - } - } - if (this.isPublicKeyHashOut()) { - return new Buffer(this.chunks[2].buf); - } - throw new Error('Unrecognized script type to get data from'); -}; + PEMDecoder.prototype.decode = function decode(data, options) { + var lines = data.toString().split(/[\r\n]+/g); -/** - * @returns {boolean} if the script is only composed of data pushing - * opcodes or small int opcodes (OP_0, OP_1, ..., OP_16) - */ -Script.prototype.isPushOnly = function() { - return _.every(this.chunks, function(chunk) { - return chunk.opcodenum <= Opcode.OP_16; - }); -}; - - -Script.types = {}; -Script.types.UNKNOWN = 'Unknown'; -Script.types.PUBKEY_OUT = 'Pay to public key'; -Script.types.PUBKEY_IN = 'Spend from public key'; -Script.types.PUBKEYHASH_OUT = 'Pay to public key hash'; -Script.types.PUBKEYHASH_IN = 'Spend from public key hash'; -Script.types.SCRIPTHASH_OUT = 'Pay to script hash'; -Script.types.PARAMETERIZED_SCRIPTHASH_OUT = 'Parameterized Pay to script hash'; -Script.types.SCRIPTHASH_IN = 'Spend from script hash'; -Script.types.MULTISIG_OUT = 'Pay to multisig'; -Script.types.MULTISIG_IN = 'Spend from multisig'; -Script.types.DATA_OUT = 'Data push'; - -Script.OP_RETURN_STANDARD_SIZE = 80; - -/** - * @returns {object} The Script type if it is a known form, - * or Script.UNKNOWN if it isn't - */ -Script.prototype.classify = function() { - if (this._isInput) { - return this.classifyInput(); - } else if (this._isOutput) { - return this.classifyOutput(); - } else { - var outputType = this.classifyOutput(); - return outputType != Script.types.UNKNOWN ? outputType : this.classifyInput(); - } -}; - -Script.outputIdentifiers = {}; -Script.outputIdentifiers.PUBKEY_OUT = Script.prototype.isPublicKeyOut; -Script.outputIdentifiers.PUBKEYHASH_OUT = Script.prototype.isPublicKeyHashOut; -Script.outputIdentifiers.MULTISIG_OUT = Script.prototype.isMultisigOut; -Script.outputIdentifiers.SCRIPTHASH_OUT = Script.prototype.isScriptHashOut; -Script.outputIdentifiers.DATA_OUT = Script.prototype.isDataOut; - -/** - * @returns {object} The Script type if it is a known form, - * or Script.UNKNOWN if it isn't - */ -Script.prototype.classifyOutput = function() { - for (var type in Script.outputIdentifiers) { - if (Script.outputIdentifiers[type].bind(this)()) { - return Script.types[type]; - } - } - return Script.types.UNKNOWN; -}; - -Script.inputIdentifiers = {}; -Script.inputIdentifiers.PUBKEY_IN = Script.prototype.isPublicKeyIn; -Script.inputIdentifiers.PUBKEYHASH_IN = Script.prototype.isPublicKeyHashIn; -Script.inputIdentifiers.MULTISIG_IN = Script.prototype.isMultisigIn; -Script.inputIdentifiers.SCRIPTHASH_IN = Script.prototype.isScriptHashIn; - -/** - * @returns {object} The Script type if it is a known form, - * or Script.UNKNOWN if it isn't - */ -Script.prototype.classifyInput = function() { - for (var type in Script.inputIdentifiers) { - if (Script.inputIdentifiers[type].bind(this)()) { - return Script.types[type]; - } - } - return Script.types.UNKNOWN; -}; + var label = options.label.toUpperCase(); + + var re = /^-----(BEGIN|END) ([^-]+)-----$/; + var start = -1; + var end = -1; + for (var i = 0; i < lines.length; i++) { + var match = lines[i].match(re); + if (match === null) continue; + + if (match[2] !== label) continue; + + if (start === -1) { + if (match[1] !== 'BEGIN') break; + start = i; + } else { + if (match[1] !== 'END') break; + end = i; + break; + } + } + if (start === -1 || end === -1) throw new Error('PEM section not found for: ' + label); + + var base64 = lines.slice(start + 1, end).join(''); + // Remove excessive symbols + base64.replace(/[^a-z0-9\+\/=]+/gi, ''); + var input = new Buffer(base64, 'base64'); + return DERDecoder.prototype.decode.call(this, input, options); + }; + }, + { './der': 53, buffer: 113, inherits: 184 }, + ], + 56: [ + function(require, module, exports) { + var inherits = require('inherits'); + var Buffer = require('buffer').Buffer; + + var asn1 = require('../../asn1'); + var base = asn1.base; + + // Import DER constants + var der = asn1.constants.der; + + function DEREncoder(entity) { + this.enc = 'der'; + this.name = entity.name; + this.entity = entity; + + // Construct base tree + this.tree = new DERNode(); + this.tree._init(entity.body); + } + module.exports = DEREncoder; -/** - * @returns {boolean} if script is one of the known types - */ -Script.prototype.isStandard = function() { - // TODO: Add BIP62 compliance - return this.classify() !== Script.types.UNKNOWN; -}; + DEREncoder.prototype.encode = function encode(data, reporter) { + return this.tree._encode(data, reporter).join(); + }; + // Tree methods -// Script construction methods + function DERNode(parent) { + base.Node.call(this, 'der', parent); + } + inherits(DERNode, base.Node); -/** - * Adds a script element at the start of the script. - * @param {*} obj a string, number, Opcode, Buffer, or object to add - * @returns {Script} this script instance - */ -Script.prototype.prepend = function(obj) { - this._addByType(obj, true); - return this; -}; + DERNode.prototype._encodeComposite = function encodeComposite(tag, primitive, cls, content) { + var encodedTag = encodeTag(tag, primitive, cls, this.reporter); -/** - * Compares a script with another script - */ -Script.prototype.equals = function(script) { - $.checkState(script instanceof Script, 'Must provide another script'); - if (this.chunks.length !== script.chunks.length) { - return false; - } - var i; - for (i = 0; i < this.chunks.length; i++) { - if (BufferUtil.isBuffer(this.chunks[i].buf) && !BufferUtil.isBuffer(script.chunks[i].buf)) { - return false; - } - if (BufferUtil.isBuffer(this.chunks[i].buf) && !BufferUtil.equals(this.chunks[i].buf, script.chunks[i].buf)) { - return false; - } else if (this.chunks[i].opcodenum !== script.chunks[i].opcodenum) { - return false; - } - } - return true; -}; + // Short form + if (content.length < 0x80) { + var header = new Buffer(2); + header[0] = encodedTag; + header[1] = content.length; + return this._createEncoderBuffer([header, content]); + } -/** - * Adds a script element to the end of the script. - * - * @param {*} obj a string, number, Opcode, Buffer, or object to add - * @returns {Script} this script instance - * - */ -Script.prototype.add = function(obj) { - this._addByType(obj, false); - return this; -}; - -Script.prototype._addByType = function(obj, prepend) { - if (typeof obj === 'string') { - this._addOpcode(obj, prepend); - } else if (typeof obj === 'number') { - this._addOpcode(obj, prepend); - } else if (obj instanceof Opcode) { - this._addOpcode(obj, prepend); - } else if (BufferUtil.isBuffer(obj)) { - this._addBuffer(obj, prepend); - } else if (obj instanceof Script) { - this.chunks = this.chunks.concat(obj.chunks); - } else if (typeof obj === 'object') { - this._insertAtPosition(obj, prepend); - } else { - throw new Error('Invalid script chunk'); - } -}; + // Long form + // Count octets required to store length + var lenOctets = 1; + for (var i = content.length; i >= 0x100; i >>= 8) lenOctets++; -Script.prototype._insertAtPosition = function(op, prepend) { - if (prepend) { - this.chunks.unshift(op); - } else { - this.chunks.push(op); - } -}; - -Script.prototype._addOpcode = function(opcode, prepend) { - var op; - if (typeof opcode === 'number') { - op = opcode; - } else if (opcode instanceof Opcode) { - op = opcode.toNumber(); - } else { - op = Opcode(opcode).toNumber(); - } - this._insertAtPosition({ - opcodenum: op - }, prepend); - return this; -}; - -Script.prototype._addBuffer = function(buf, prepend) { - var opcodenum; - var len = buf.length; - if (len >= 0 && len < Opcode.OP_PUSHDATA1) { - opcodenum = len; - } else if (len < Math.pow(2, 8)) { - opcodenum = Opcode.OP_PUSHDATA1; - } else if (len < Math.pow(2, 16)) { - opcodenum = Opcode.OP_PUSHDATA2; - } else if (len < Math.pow(2, 32)) { - opcodenum = Opcode.OP_PUSHDATA4; - } else { - throw new Error('You can\'t push that much data'); - } - this._insertAtPosition({ - buf: buf, - len: len, - opcodenum: opcodenum - }, prepend); - return this; -}; - -Script.prototype.removeCodeseparators = function() { - var chunks = []; - for (var i = 0; i < this.chunks.length; i++) { - if (this.chunks[i].opcodenum !== Opcode.OP_CODESEPARATOR) { - chunks.push(this.chunks[i]); - } - } - this.chunks = chunks; - return this; -}; - -// high level script builder methods - -/** - * @returns {Script} a new Multisig output script for given public keys, - * requiring m of those public keys to spend - * @param {PublicKey[]} publicKeys - list of all public keys controlling the output - * @param {number} threshold - amount of required signatures to spend the output - * @param {Object=} opts - Several options: - * - noSorting: defaults to false, if true, don't sort the given - * public keys before creating the script - */ -Script.buildMultisigOut = function(publicKeys, threshold, opts) { - $.checkArgument(threshold <= publicKeys.length, - 'Number of required signatures must be less than or equal to the number of public keys'); - opts = opts || {}; - var script = new Script(); - script.add(Opcode.smallInt(threshold)); - publicKeys = _.map(publicKeys, PublicKey); - var sorted = publicKeys; - if (!opts.noSorting) { - sorted = _.sortBy(publicKeys, function(publicKey) { - return publicKey.toString('hex'); - }); - } - for (var i = 0; i < sorted.length; i++) { - var publicKey = sorted[i]; - script.add(publicKey.toBuffer()); - } - script.add(Opcode.smallInt(publicKeys.length)); - script.add(Opcode.OP_CHECKMULTISIG); - return script; -}; + var header = new Buffer(1 + 1 + lenOctets); + header[0] = encodedTag; + header[1] = 0x80 | lenOctets; -/** - * A new Multisig input script for the given public keys, requiring m of those public keys to spend - * - * @param {PublicKey[]} pubkeys list of all public keys controlling the output - * @param {number} threshold amount of required signatures to spend the output - * @param {Array} signatures and array of signature buffers to append to the script - * @param {Object=} opts - * @param {boolean=} opts.noSorting don't sort the given public keys before creating the script (false by default) - * @param {Script=} opts.cachedMultisig don't recalculate the redeemScript - * - * @returns {Script} - */ -Script.buildMultisigIn = function(pubkeys, threshold, signatures, opts) { - $.checkArgument(_.isArray(pubkeys)); - $.checkArgument(_.isNumber(threshold)); - $.checkArgument(_.isArray(signatures)); - opts = opts || {}; - var s = new Script(); - s.add(Opcode.OP_0); - _.each(signatures, function(signature) { - $.checkArgument(BufferUtil.isBuffer(signature), 'Signatures must be an array of Buffers'); - // TODO: allow signatures to be an array of Signature objects - s.add(signature); - }); - return s; -}; + for (var i = 1 + lenOctets, j = content.length; j > 0; i--, j >>= 8) header[i] = j & 0xff; -/** - * A new P2SH Multisig input script for the given public keys, requiring m of those public keys to spend - * - * @param {PublicKey[]} pubkeys list of all public keys controlling the output - * @param {number} threshold amount of required signatures to spend the output - * @param {Array} signatures and array of signature buffers to append to the script - * @param {Object=} opts - * @param {boolean=} opts.noSorting don't sort the given public keys before creating the script (false by default) - * @param {Script=} opts.cachedMultisig don't recalculate the redeemScript - * - * @returns {Script} - */ -Script.buildP2SHMultisigIn = function(pubkeys, threshold, signatures, opts) { - $.checkArgument(_.isArray(pubkeys)); - $.checkArgument(_.isNumber(threshold)); - $.checkArgument(_.isArray(signatures)); - opts = opts || {}; - var s = new Script(); - s.add(Opcode.OP_0); - _.each(signatures, function(signature) { - $.checkArgument(BufferUtil.isBuffer(signature), 'Signatures must be an array of Buffers'); - // TODO: allow signatures to be an array of Signature objects - s.add(signature); - }); - s.add((opts.cachedMultisig || Script.buildMultisigOut(pubkeys, threshold, opts)).toBuffer()); - return s; -}; + return this._createEncoderBuffer([header, content]); + }; -/** - * @returns {Script} a new pay to public key hash output for the given - * address or public key - * @param {(Address|PublicKey)} to - destination address or public key - */ -Script.buildPublicKeyHashOut = function(to) { - $.checkArgument(!_.isUndefined(to)); - $.checkArgument(to instanceof PublicKey || to instanceof Address || _.isString(to)); - if (to instanceof PublicKey) { - to = to.toAddress(); - } else if (_.isString(to)) { - to = new Address(to); - } - var s = new Script(); - s.add(Opcode.OP_DUP) - .add(Opcode.OP_HASH160) - .add(to.hashBuffer) - .add(Opcode.OP_EQUALVERIFY) - .add(Opcode.OP_CHECKSIG); - s._network = to.network; - return s; -}; + DERNode.prototype._encodeStr = function encodeStr(str, tag) { + if (tag === 'bitstr') { + return this._createEncoderBuffer([str.unused | 0, str.data]); + } else if (tag === 'bmpstr') { + var buf = new Buffer(str.length * 2); + for (var i = 0; i < str.length; i++) { + buf.writeUInt16BE(str.charCodeAt(i), i * 2); + } + return this._createEncoderBuffer(buf); + } else if (tag === 'numstr') { + if (!this._isNumstr(str)) { + return this.reporter.error('Encoding of string type: numstr supports ' + 'only digits and space'); + } + return this._createEncoderBuffer(str); + } else if (tag === 'printstr') { + if (!this._isPrintstr(str)) { + return this.reporter.error( + 'Encoding of string type: printstr supports ' + + 'only latin upper and lower case letters, ' + + 'digits, space, apostrophe, left and rigth ' + + 'parenthesis, plus sign, comma, hyphen, ' + + 'dot, slash, colon, equal sign, ' + + 'question mark', + ); + } + return this._createEncoderBuffer(str); + } else if (/str$/.test(tag)) { + return this._createEncoderBuffer(str); + } else if (tag === 'objDesc') { + return this._createEncoderBuffer(str); + } else { + return this.reporter.error('Encoding of string type: ' + tag + ' unsupported'); + } + }; -/** - * @returns {Script} a new pay to public key output for the given - * public key - */ -Script.buildPublicKeyOut = function(pubkey) { - $.checkArgument(pubkey instanceof PublicKey); - var s = new Script(); - s.add(pubkey.toBuffer()) - .add(Opcode.OP_CHECKSIG); - return s; -}; + DERNode.prototype._encodeObjid = function encodeObjid(id, values, relative) { + if (typeof id === 'string') { + if (!values) return this.reporter.error('string objid given, but no values map found'); + if (!values.hasOwnProperty(id)) return this.reporter.error('objid not found in values map'); + id = values[id].split(/[\s\.]+/g); + for (var i = 0; i < id.length; i++) id[i] |= 0; + } else if (Array.isArray(id)) { + id = id.slice(); + for (var i = 0; i < id.length; i++) id[i] |= 0; + } -/** - * @returns {Script} a new OP_RETURN script with data - * @param {(string|Buffer)} data - the data to embed in the output - * @param {(string)} encoding - the type of encoding of the string - */ -Script.buildDataOut = function(data, encoding) { - $.checkArgument(_.isUndefined(data) || _.isString(data) || BufferUtil.isBuffer(data)); - if (_.isString(data)) { - data = new Buffer(data, encoding); - } - var s = new Script(); - s.add(Opcode.OP_RETURN); - if (!_.isUndefined(data)) { - s.add(data); - } - return s; -}; + if (!Array.isArray(id)) { + return this.reporter.error('objid() should be either array or string, ' + 'got: ' + JSON.stringify(id)); + } -/** - * @param {Script|Address} script - the redeemScript for the new p2sh output. - * It can also be a p2sh address - * @returns {Script} new pay to script hash script for given script - */ -Script.buildScriptHashOut = function(script) { - $.checkArgument(script instanceof Script || - (script instanceof Address && script.isPayToScriptHash())); - var s = new Script(); - s.add(Opcode.OP_HASH160) - .add(script instanceof Address ? script.hashBuffer : Hash.sha256ripemd160(script.toBuffer())) - .add(Opcode.OP_EQUAL); - - s._network = script._network || script.network; - return s; -}; + if (!relative) { + if (id[1] >= 40) return this.reporter.error('Second objid identifier OOB'); + id.splice(0, 2, id[0] * 40 + id[1]); + } -/** - * Builds a scriptSig (a script for an input) that signs a public key output script. - * - * @param {Signature|Buffer} signature - a Signature object, or the signature in DER canonical encoding - * @param {number=} sigtype - the type of the signature (defaults to SIGHASH_ALL) - */ -Script.buildPublicKeyIn = function(signature, sigtype) { - $.checkArgument(signature instanceof Signature || BufferUtil.isBuffer(signature)); - $.checkArgument(_.isUndefined(sigtype) || _.isNumber(sigtype)); - if (signature instanceof Signature) { - signature = signature.toBuffer(); - } - var script = new Script(); - script.add(BufferUtil.concat([ - signature, - BufferUtil.integerAsSingleByteBuffer(sigtype || Signature.SIGHASH_ALL) - ])); - return script; -}; - -/** - * Builds a scriptSig (a script for an input) that signs a public key hash - * output script. - * - * @param {Buffer|string|PublicKey} publicKey - * @param {Signature|Buffer} signature - a Signature object, or the signature in DER canonical encoding - * @param {number=} sigtype - the type of the signature (defaults to SIGHASH_ALL) - */ -Script.buildPublicKeyHashIn = function(publicKey, signature, sigtype) { - $.checkArgument(signature instanceof Signature || BufferUtil.isBuffer(signature)); - $.checkArgument(_.isUndefined(sigtype) || _.isNumber(sigtype)); - if (signature instanceof Signature) { - signature = signature.toBuffer(); - } - var script = new Script() - .add(BufferUtil.concat([ - signature, - BufferUtil.integerAsSingleByteBuffer(sigtype || Signature.SIGHASH_ALL) - ])) - .add(new PublicKey(publicKey).toBuffer()); - return script; -}; - -/** - * @returns {Script} an empty script - */ -Script.empty = function() { - return new Script(); -}; + // Count number of octets + var size = 0; + for (var i = 0; i < id.length; i++) { + var ident = id[i]; + for (size++; ident >= 0x80; ident >>= 7) size++; + } -/** - * @returns {Script} a new pay to script hash script that pays to this script - */ -Script.prototype.toScriptHashOut = function() { - return Script.buildScriptHashOut(this); -}; + var objid = new Buffer(size); + var offset = objid.length - 1; + for (var i = id.length - 1; i >= 0; i--) { + var ident = id[i]; + objid[offset--] = ident & 0x7f; + while ((ident >>= 7) > 0) objid[offset--] = 0x80 | (ident & 0x7f); + } -/** - * @return {Script} an output script built from the address - */ -Script.fromAddress = function(address) { - address = Address(address); - if (address.isPayToScriptHash()) { - return Script.buildScriptHashOut(address); - } else if (address.isPayToPublicKeyHash()) { - return Script.buildPublicKeyHashOut(address); - } - throw new errors.Script.UnrecognizedAddress(address); -}; + return this._createEncoderBuffer(objid); + }; -/** - * Will return the associated address information object - * @return {Address|boolean} - */ -Script.prototype.getAddressInfo = function(opts) { - if (this._isInput) { - return this._getInputAddressInfo(); - } else if (this._isOutput) { - return this._getOutputAddressInfo(); - } else { - var info = this._getOutputAddressInfo(); - if (!info) { - return this._getInputAddressInfo(); - } - return info; - } -}; + function two(num) { + if (num < 10) return '0' + num; + else return num; + } -/** - * Will return the associated output scriptPubKey address information object - * @return {Address|boolean} - * @private - */ -Script.prototype._getOutputAddressInfo = function() { - var info = {}; - if (this.isScriptHashOut()) { - info.hashBuffer = this.getData(); - info.type = Address.PayToScriptHash; - } else if (this.isPublicKeyHashOut()) { - info.hashBuffer = this.getData(); - info.type = Address.PayToPublicKeyHash; - } else { - return false; - } - return info; -}; + DERNode.prototype._encodeTime = function encodeTime(time, tag) { + var str; + var date = new Date(time); + + if (tag === 'gentime') { + str = [ + two(date.getFullYear()), + two(date.getUTCMonth() + 1), + two(date.getUTCDate()), + two(date.getUTCHours()), + two(date.getUTCMinutes()), + two(date.getUTCSeconds()), + 'Z', + ].join(''); + } else if (tag === 'utctime') { + str = [ + two(date.getFullYear() % 100), + two(date.getUTCMonth() + 1), + two(date.getUTCDate()), + two(date.getUTCHours()), + two(date.getUTCMinutes()), + two(date.getUTCSeconds()), + 'Z', + ].join(''); + } else { + this.reporter.error('Encoding ' + tag + ' time is not supported yet'); + } -/** - * Will return the associated input scriptSig address information object - * @return {Address|boolean} - * @private - */ -Script.prototype._getInputAddressInfo = function() { - var info = {}; - if (this.isPublicKeyHashIn()) { - // hash the publickey found in the scriptSig - info.hashBuffer = Hash.sha256ripemd160(this.chunks[1].buf); - info.type = Address.PayToPublicKeyHash; - } else if (this.isScriptHashIn()) { - // hash the redeemscript found at the end of the scriptSig - info.hashBuffer = Hash.sha256ripemd160(this.chunks[this.chunks.length - 1].buf); - info.type = Address.PayToScriptHash; - } else { - return false; - } - return info; -}; + return this._encodeStr(str, 'octstr'); + }; -/** - * @param {Network=} network - * @return {Address|boolean} the associated address for this script if possible, or false - */ -Script.prototype.toAddress = function(network) { - var info = this.getAddressInfo(); - if (!info) { - return false; - } - info.network = Networks.get(network) || this._network || Networks.defaultNetwork; - return new Address(info); -}; - -/** - * Analogous to bitcoind's FindAndDelete. Find and delete equivalent chunks, - * typically used with push data chunks. Note that this will find and delete - * not just the same data, but the same data with the same push data op as - * produced by default. i.e., if a pushdata in a tx does not use the minimal - * pushdata op, then when you try to remove the data it is pushing, it will not - * be removed, because they do not use the same pushdata op. - */ -Script.prototype.findAndDelete = function(script) { - var buf = script.toBuffer(); - var hex = buf.toString('hex'); - for (var i = 0; i < this.chunks.length; i++) { - var script2 = Script({ - chunks: [this.chunks[i]] - }); - var buf2 = script2.toBuffer(); - var hex2 = buf2.toString('hex'); - if (hex === hex2) { - this.chunks.splice(i, 1); - } - } - return this; -}; + DERNode.prototype._encodeNull = function encodeNull() { + return this._createEncoderBuffer(''); + }; -/** - * Comes from bitcoind's script interpreter CheckMinimalPush function - * @returns {boolean} if the chunk {i} is the smallest way to push that particular data. - */ -Script.prototype.checkMinimalPush = function(i) { - var chunk = this.chunks[i]; - var buf = chunk.buf; - var opcodenum = chunk.opcodenum; - if (!buf) { - return true; - } - if (buf.length === 0) { - // Could have used OP_0. - return opcodenum === Opcode.OP_0; - } else if (buf.length === 1 && buf[0] >= 1 && buf[0] <= 16) { - // Could have used OP_1 .. OP_16. - return opcodenum === Opcode.OP_1 + (buf[0] - 1); - } else if (buf.length === 1 && buf[0] === 0x81) { - // Could have used OP_1NEGATE - return opcodenum === Opcode.OP_1NEGATE; - } else if (buf.length <= 75) { - // Could have used a direct push (opcode indicating number of bytes pushed + those bytes). - return opcodenum === buf.length; - } else if (buf.length <= 255) { - // Could have used OP_PUSHDATA. - return opcodenum === Opcode.OP_PUSHDATA1; - } else if (buf.length <= 65535) { - // Could have used OP_PUSHDATA2. - return opcodenum === Opcode.OP_PUSHDATA2; - } - return true; -}; + DERNode.prototype._encodeInt = function encodeInt(num, values) { + if (typeof num === 'string') { + if (!values) return this.reporter.error('String int or enum given, but no values map'); + if (!values.hasOwnProperty(num)) { + return this.reporter.error("Values map doesn't contain: " + JSON.stringify(num)); + } + num = values[num]; + } -/** - * Comes from bitcoind's script DecodeOP_N function - * @param {number} opcode - * @returns {number} numeric value in range of 0 to 16 - */ -Script.prototype._decodeOP_N = function(opcode) { - if (opcode === Opcode.OP_0) { - return 0; - } else if (opcode >= Opcode.OP_1 && opcode <= Opcode.OP_16) { - return opcode - (Opcode.OP_1 - 1); - } else { - throw new Error('Invalid opcode: ' + JSON.stringify(opcode)); - } -}; + // Bignum, assume big endian + if (typeof num !== 'number' && !Buffer.isBuffer(num)) { + var numArray = num.toArray(); + if (!num.sign && numArray[0] & 0x80) { + numArray.unshift(0); + } + num = new Buffer(numArray); + } -/** - * Comes from bitcoind's script GetSigOpCount(boolean) function - * @param {boolean} use current (true) or pre-version-0.6 (false) logic - * @returns {number} number of signature operations required by this script - */ -Script.prototype.getSignatureOperationsCount = function(accurate) { - accurate = (_.isUndefined(accurate) ? true : accurate); - var self = this; - var n = 0; - var lastOpcode = Opcode.OP_INVALIDOPCODE; - _.each(self.chunks, function getChunk(chunk) { - var opcode = chunk.opcodenum; - if (opcode == Opcode.OP_CHECKSIG || opcode == Opcode.OP_CHECKSIGVERIFY) { - n++; - } else if (opcode == Opcode.OP_CHECKMULTISIG || opcode == Opcode.OP_CHECKMULTISIGVERIFY) { - if (accurate && lastOpcode >= Opcode.OP_1 && lastOpcode <= Opcode.OP_16) { - n += self._decodeOP_N(lastOpcode); - } else { - n += 20; - } - } - lastOpcode = opcode; - }); - return n; -}; - -module.exports = Script; - -}).call(this,require("buffer").Buffer) -},{"../address":1,"../crypto/hash":8,"../crypto/signature":11,"../encoding/bufferreader":14,"../encoding/bufferwriter":15,"../errors":17,"../networks":21,"../opcode":22,"../publickey":24,"../util/buffer":42,"../util/js":43,"../util/preconditions":44,"buffer":113,"lodash":187}],28:[function(require,module,exports){ -module.exports = require('./transaction'); - -module.exports.Input = require('./input'); -module.exports.Output = require('./output'); -module.exports.UnspentOutput = require('./unspentoutput'); -module.exports.Signature = require('./signature'); -module.exports.Sighash = require('./sighash'); - -},{"./input":29,"./output":35,"./sighash":36,"./signature":37,"./transaction":38,"./unspentoutput":39}],29:[function(require,module,exports){ -module.exports = require('./input'); - -module.exports.PublicKey = require('./publickey'); -module.exports.PublicKeyHash = require('./publickeyhash'); -module.exports.MultiSig = require('./multisig.js'); -module.exports.MultiSigScriptHash = require('./multisigscripthash.js'); - -},{"./input":30,"./multisig.js":31,"./multisigscripthash.js":32,"./publickey":33,"./publickeyhash":34}],30:[function(require,module,exports){ -'use strict'; - -var _ = require('lodash'); -var $ = require('../../util/preconditions'); -var errors = require('../../errors'); -var BufferWriter = require('../../encoding/bufferwriter'); -var buffer = require('buffer'); -var BufferUtil = require('../../util/buffer'); -var JSUtil = require('../../util/js'); -var Script = require('../../script'); -var Sighash = require('../sighash'); -var Output = require('../output'); - -var MAXINT = 0xffffffff; // Math.pow(2, 32) - 1; -var DEFAULT_RBF_SEQNUMBER = MAXINT - 2; -var DEFAULT_SEQNUMBER = MAXINT; -var DEFAULT_LOCKTIME_SEQNUMBER = MAXINT - 1; - -function Input(params) { - if (!(this instanceof Input)) { - return new Input(params); - } - if (params) { - return this._fromObject(params); - } -} + if (Buffer.isBuffer(num)) { + var size = num.length; + if (num.length === 0) size++; -Input.MAXINT = MAXINT; -Input.DEFAULT_SEQNUMBER = DEFAULT_SEQNUMBER; -Input.DEFAULT_LOCKTIME_SEQNUMBER = DEFAULT_LOCKTIME_SEQNUMBER; -Input.DEFAULT_RBF_SEQNUMBER = DEFAULT_RBF_SEQNUMBER; - -Object.defineProperty(Input.prototype, 'script', { - configurable: false, - enumerable: true, - get: function() { - if (this.isNull()) { - return null; - } - if (!this._script) { - this._script = new Script(this._scriptBuffer); - this._script._isInput = true; - } - return this._script; - } -}); - -Input.fromObject = function(obj) { - $.checkArgument(_.isObject(obj)); - var input = new Input(); - return input._fromObject(obj); -}; - -Input.prototype._fromObject = function(params) { - var prevTxId; - if (_.isString(params.prevTxId) && JSUtil.isHexa(params.prevTxId)) { - prevTxId = new buffer.Buffer(params.prevTxId, 'hex'); - } else { - prevTxId = params.prevTxId; - } - this.output = params.output ? - (params.output instanceof Output ? params.output : new Output(params.output)) : undefined; - this.prevTxId = prevTxId || params.txidbuf; - this.outputIndex = _.isUndefined(params.outputIndex) ? params.txoutnum : params.outputIndex; - this.sequenceNumber = _.isUndefined(params.sequenceNumber) ? - (_.isUndefined(params.seqnum) ? DEFAULT_SEQNUMBER : params.seqnum) : params.sequenceNumber; - if (_.isUndefined(params.script) && _.isUndefined(params.scriptBuffer)) { - throw new errors.Transaction.Input.MissingScript(); - } - this.setScript(params.scriptBuffer || params.script); - return this; -}; - -Input.prototype.toObject = Input.prototype.toJSON = function toObject() { - var obj = { - prevTxId: this.prevTxId.toString('hex'), - outputIndex: this.outputIndex, - sequenceNumber: this.sequenceNumber, - script: this._scriptBuffer.toString('hex'), - }; - // add human readable form if input contains valid script - if (this.script) { - obj.scriptString = this.script.toString(); - } - if (this.output) { - obj.output = this.output.toObject(); - } - return obj; -}; - -Input.fromBufferReader = function(br) { - var input = new Input(); - input.prevTxId = br.readReverse(32); - input.outputIndex = br.readUInt32LE(); - input._scriptBuffer = br.readVarLengthBuffer(); - input.sequenceNumber = br.readUInt32LE(); - // TODO: return different classes according to which input it is - // e.g: CoinbaseInput, PublicKeyHashInput, MultiSigScriptHashInput, etc. - return input; -}; - -Input.prototype.toBufferWriter = function(writer) { - if (!writer) { - writer = new BufferWriter(); - } - writer.writeReverse(this.prevTxId); - writer.writeUInt32LE(this.outputIndex); - var script = this._scriptBuffer; - writer.writeVarintNum(script.length); - writer.write(script); - writer.writeUInt32LE(this.sequenceNumber); - return writer; -}; - -Input.prototype.setScript = function(script) { - this._script = null; - if (script instanceof Script) { - this._script = script; - this._script._isInput = true; - this._scriptBuffer = script.toBuffer(); - } else if (JSUtil.isHexa(script)) { - // hex string script - this._scriptBuffer = new buffer.Buffer(script, 'hex'); - } else if (_.isString(script)) { - // human readable string script - this._script = new Script(script); - this._script._isInput = true; - this._scriptBuffer = this._script.toBuffer(); - } else if (BufferUtil.isBuffer(script)) { - // buffer script - this._scriptBuffer = new buffer.Buffer(script); - } else { - throw new TypeError('Invalid argument type: script'); - } - return this; -}; + var out = new Buffer(size); + num.copy(out); + if (num.length === 0) out[0] = 0; + return this._createEncoderBuffer(out); + } -/** - * Retrieve signatures for the provided PrivateKey. - * - * @param {Transaction} transaction - the transaction to be signed - * @param {PrivateKey} privateKey - the private key to use when signing - * @param {number} inputIndex - the index of this input in the provided transaction - * @param {number} sigType - defaults to Signature.SIGHASH_ALL - * @param {Buffer} addressHash - if provided, don't calculate the hash of the - * public key associated with the private key provided - * @abstract - */ -Input.prototype.getSignatures = function() { - throw new errors.AbstractMethodInvoked( - 'Trying to sign unsupported output type (only P2PKH and P2SH multisig inputs are supported)' + - ' for input: ' + JSON.stringify(this) - ); -}; - -Input.prototype.isFullySigned = function() { - throw new errors.AbstractMethodInvoked('Input#isFullySigned'); -}; - -Input.prototype.isFinal = function() { - return this.sequenceNumber !== 4294967295; -}; - -Input.prototype.addSignature = function() { - throw new errors.AbstractMethodInvoked('Input#addSignature'); -}; - -Input.prototype.clearSignatures = function() { - throw new errors.AbstractMethodInvoked('Input#clearSignatures'); -}; - -Input.prototype.isValidSignature = function(transaction, signature) { - // FIXME: Refactor signature so this is not necessary - signature.signature.nhashtype = signature.sigtype; - return Sighash.verify( - transaction, - signature.signature, - signature.publicKey, - signature.inputIndex, - this.output.script - ); -}; - -/** - * @returns true if this is a coinbase input (represents no input) - */ -Input.prototype.isNull = function() { - return this.prevTxId.toString('hex') === '0000000000000000000000000000000000000000000000000000000000000000' && - this.outputIndex === 0xffffffff; -}; - -Input.prototype._estimateSize = function() { - return this.toBufferWriter().toBuffer().length; -}; - -module.exports = Input; - -},{"../../encoding/bufferwriter":15,"../../errors":17,"../../script":25,"../../util/buffer":42,"../../util/js":43,"../../util/preconditions":44,"../output":35,"../sighash":36,"buffer":113,"lodash":187}],31:[function(require,module,exports){ -'use strict'; - -var _ = require('lodash'); -var inherits = require('inherits'); -var Transaction = require('../transaction'); -var Input = require('./input'); -var Output = require('../output'); -var $ = require('../../util/preconditions'); - -var Script = require('../../script'); -var Signature = require('../../crypto/signature'); -var Sighash = require('../sighash'); -var PublicKey = require('../../publickey'); -var BufferUtil = require('../../util/buffer'); -var TransactionSignature = require('../signature'); - -/** - * @constructor - */ -function MultiSigInput(input, pubkeys, threshold, signatures) { - Input.apply(this, arguments); - var self = this; - pubkeys = pubkeys || input.publicKeys; - threshold = threshold || input.threshold; - signatures = signatures || input.signatures; - this.publicKeys = _.sortBy(pubkeys, function(publicKey) { return publicKey.toString('hex'); }); - $.checkState(Script.buildMultisigOut(this.publicKeys, threshold).equals(this.output.script), - 'Provided public keys don\'t match to the provided output script'); - this.publicKeyIndex = {}; - _.each(this.publicKeys, function(publicKey, index) { - self.publicKeyIndex[publicKey.toString()] = index; - }); - this.threshold = threshold; - // Empty array of signatures - this.signatures = signatures ? this._deserializeSignatures(signatures) : new Array(this.publicKeys.length); -} -inherits(MultiSigInput, Input); - -MultiSigInput.prototype.toObject = function() { - var obj = Input.prototype.toObject.apply(this, arguments); - obj.threshold = this.threshold; - obj.publicKeys = _.map(this.publicKeys, function(publicKey) { return publicKey.toString(); }); - obj.signatures = this._serializeSignatures(); - return obj; -}; - -MultiSigInput.prototype._deserializeSignatures = function(signatures) { - return _.map(signatures, function(signature) { - if (!signature) { - return undefined; - } - return new TransactionSignature(signature); - }); -}; - -MultiSigInput.prototype._serializeSignatures = function() { - return _.map(this.signatures, function(signature) { - if (!signature) { - return undefined; - } - return signature.toObject(); - }); -}; - -MultiSigInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype) { - $.checkState(this.output instanceof Output); - sigtype = sigtype || Signature.SIGHASH_ALL; - - var self = this; - var results = []; - _.each(this.publicKeys, function(publicKey) { - if (publicKey.toString() === privateKey.publicKey.toString()) { - results.push(new TransactionSignature({ - publicKey: privateKey.publicKey, - prevTxId: self.prevTxId, - outputIndex: self.outputIndex, - inputIndex: index, - signature: Sighash.sign(transaction, privateKey, sigtype, index, self.output.script), - sigtype: sigtype - })); - } - }); - - return results; -}; - -MultiSigInput.prototype.addSignature = function(transaction, signature) { - $.checkState(!this.isFullySigned(), 'All needed signatures have already been added'); - $.checkArgument(!_.isUndefined(this.publicKeyIndex[signature.publicKey.toString()]), - 'Signature has no matching public key'); - $.checkState(this.isValidSignature(transaction, signature)); - this.signatures[this.publicKeyIndex[signature.publicKey.toString()]] = signature; - this._updateScript(); - return this; -}; - -MultiSigInput.prototype._updateScript = function() { - this.setScript(Script.buildMultisigIn( - this.publicKeys, - this.threshold, - this._createSignatures() - )); - return this; -}; - -MultiSigInput.prototype._createSignatures = function() { - return _.map( - _.filter(this.signatures, function(signature) { return !_.isUndefined(signature); }), - function(signature) { - return BufferUtil.concat([ - signature.signature.toDER(), - BufferUtil.integerAsSingleByteBuffer(signature.sigtype) - ]); - } - ); -}; - -MultiSigInput.prototype.clearSignatures = function() { - this.signatures = new Array(this.publicKeys.length); - this._updateScript(); -}; - -MultiSigInput.prototype.isFullySigned = function() { - return this.countSignatures() === this.threshold; -}; - -MultiSigInput.prototype.countMissingSignatures = function() { - return this.threshold - this.countSignatures(); -}; - -MultiSigInput.prototype.countSignatures = function() { - return _.reduce(this.signatures, function(sum, signature) { - return sum + (!!signature); - }, 0); -}; - -MultiSigInput.prototype.publicKeysWithoutSignature = function() { - var self = this; - return _.filter(this.publicKeys, function(publicKey) { - return !(self.signatures[self.publicKeyIndex[publicKey.toString()]]); - }); -}; - -MultiSigInput.prototype.isValidSignature = function(transaction, signature) { - // FIXME: Refactor signature so this is not necessary - signature.signature.nhashtype = signature.sigtype; - return Sighash.verify( - transaction, - signature.signature, - signature.publicKey, - signature.inputIndex, - this.output.script - ); -}; - -/** - * - * @param {Buffer[]} signatures - * @param {PublicKey[]} publicKeys - * @param {Transaction} transaction - * @param {Integer} inputIndex - * @param {Input} input - * @returns {TransactionSignature[]} - */ -MultiSigInput.normalizeSignatures = function(transaction, input, inputIndex, signatures, publicKeys) { - return publicKeys.map(function (pubKey) { - var signatureMatch = null; - signatures = signatures.filter(function (signatureBuffer) { - if (signatureMatch) { - return true; - } + if (num < 0x80) return this._createEncoderBuffer(num); - var signature = new TransactionSignature({ - signature: Signature.fromTxFormat(signatureBuffer), - publicKey: pubKey, - prevTxId: input.prevTxId, - outputIndex: input.outputIndex, - inputIndex: inputIndex, - sigtype: Signature.SIGHASH_ALL - }); - - signature.signature.nhashtype = signature.sigtype; - var isMatch = Sighash.verify( - transaction, - signature.signature, - signature.publicKey, - signature.inputIndex, - input.output.script - ); + if (num < 0x100) return this._createEncoderBuffer([0, num]); - if (isMatch) { - signatureMatch = signature; - return false; - } + var size = 1; + for (var i = num; i >= 0x100; i >>= 8) size++; + + var out = new Array(size); + for (var i = out.length - 1; i >= 0; i--) { + out[i] = num & 0xff; + num >>= 8; + } + if (out[0] & 0x80) { + out.unshift(0); + } + + return this._createEncoderBuffer(new Buffer(out)); + }; - return true; - }); + DERNode.prototype._encodeBool = function encodeBool(value) { + return this._createEncoderBuffer(value ? 0xff : 0); + }; - return signatureMatch ? signatureMatch : null; - }); -}; + DERNode.prototype._use = function use(entity, obj) { + if (typeof entity === 'function') entity = entity(obj); + return entity._getEncoder('der').tree; + }; -MultiSigInput.OPCODES_SIZE = 1; // 0 -MultiSigInput.SIGNATURE_SIZE = 73; // size (1) + DER (<=72) + DERNode.prototype._skipDefault = function skipDefault(dataBuffer, reporter, parent) { + var state = this._baseState; + var i; + if (state['default'] === null) return false; -MultiSigInput.prototype._estimateSize = function() { - return MultiSigInput.OPCODES_SIZE + - this.threshold * MultiSigInput.SIGNATURE_SIZE; -}; + var data = dataBuffer.join(); + if (state.defaultBuffer === undefined) + state.defaultBuffer = this._encodeValue(state['default'], reporter, parent).join(); -module.exports = MultiSigInput; + if (data.length !== state.defaultBuffer.length) return false; -},{"../../crypto/signature":11,"../../publickey":24,"../../script":25,"../../util/buffer":42,"../../util/preconditions":44,"../output":35,"../sighash":36,"../signature":37,"../transaction":38,"./input":30,"inherits":184,"lodash":187}],32:[function(require,module,exports){ -'use strict'; + for (i = 0; i < data.length; i++) if (data[i] !== state.defaultBuffer[i]) return false; -var _ = require('lodash'); -var inherits = require('inherits'); -var Input = require('./input'); -var Output = require('../output'); -var $ = require('../../util/preconditions'); + return true; + }; -var Script = require('../../script'); -var Signature = require('../../crypto/signature'); -var Sighash = require('../sighash'); -var PublicKey = require('../../publickey'); -var BufferUtil = require('../../util/buffer'); -var TransactionSignature = require('../signature'); + // Utility methods -/** - * @constructor - */ -function MultiSigScriptHashInput(input, pubkeys, threshold, signatures) { - Input.apply(this, arguments); - var self = this; - pubkeys = pubkeys || input.publicKeys; - threshold = threshold || input.threshold; - signatures = signatures || input.signatures; - this.publicKeys = _.sortBy(pubkeys, function(publicKey) { return publicKey.toString('hex'); }); - this.redeemScript = Script.buildMultisigOut(this.publicKeys, threshold); - $.checkState(Script.buildScriptHashOut(this.redeemScript).equals(this.output.script), - 'Provided public keys don\'t hash to the provided output'); - this.publicKeyIndex = {}; - _.each(this.publicKeys, function(publicKey, index) { - self.publicKeyIndex[publicKey.toString()] = index; - }); - this.threshold = threshold; - // Empty array of signatures - this.signatures = signatures ? this._deserializeSignatures(signatures) : new Array(this.publicKeys.length); -} -inherits(MultiSigScriptHashInput, Input); - -MultiSigScriptHashInput.prototype.toObject = function() { - var obj = Input.prototype.toObject.apply(this, arguments); - obj.threshold = this.threshold; - obj.publicKeys = _.map(this.publicKeys, function(publicKey) { return publicKey.toString(); }); - obj.signatures = this._serializeSignatures(); - return obj; -}; - -MultiSigScriptHashInput.prototype._deserializeSignatures = function(signatures) { - return _.map(signatures, function(signature) { - if (!signature) { - return undefined; - } - return new TransactionSignature(signature); - }); -}; - -MultiSigScriptHashInput.prototype._serializeSignatures = function() { - return _.map(this.signatures, function(signature) { - if (!signature) { - return undefined; - } - return signature.toObject(); - }); -}; - -MultiSigScriptHashInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype) { - $.checkState(this.output instanceof Output); - sigtype = sigtype || Signature.SIGHASH_ALL; - - var self = this; - var results = []; - _.each(this.publicKeys, function(publicKey) { - if (publicKey.toString() === privateKey.publicKey.toString()) { - results.push(new TransactionSignature({ - publicKey: privateKey.publicKey, - prevTxId: self.prevTxId, - outputIndex: self.outputIndex, - inputIndex: index, - signature: Sighash.sign(transaction, privateKey, sigtype, index, self.redeemScript), - sigtype: sigtype - })); - } - }); - return results; -}; - -MultiSigScriptHashInput.prototype.addSignature = function(transaction, signature) { - $.checkState(!this.isFullySigned(), 'All needed signatures have already been added'); - $.checkArgument(!_.isUndefined(this.publicKeyIndex[signature.publicKey.toString()]), - 'Signature has no matching public key'); - $.checkState(this.isValidSignature(transaction, signature)); - this.signatures[this.publicKeyIndex[signature.publicKey.toString()]] = signature; - this._updateScript(); - return this; -}; - -MultiSigScriptHashInput.prototype._updateScript = function() { - this.setScript(Script.buildP2SHMultisigIn( - this.publicKeys, - this.threshold, - this._createSignatures(), - { cachedMultisig: this.redeemScript } - )); - return this; -}; - -MultiSigScriptHashInput.prototype._createSignatures = function() { - return _.map( - _.filter(this.signatures, function(signature) { return !_.isUndefined(signature); }), - function(signature) { - return BufferUtil.concat([ - signature.signature.toDER(), - BufferUtil.integerAsSingleByteBuffer(signature.sigtype) - ]); - } - ); -}; - -MultiSigScriptHashInput.prototype.clearSignatures = function() { - this.signatures = new Array(this.publicKeys.length); - this._updateScript(); -}; - -MultiSigScriptHashInput.prototype.isFullySigned = function() { - return this.countSignatures() === this.threshold; -}; - -MultiSigScriptHashInput.prototype.countMissingSignatures = function() { - return this.threshold - this.countSignatures(); -}; - -MultiSigScriptHashInput.prototype.countSignatures = function() { - return _.reduce(this.signatures, function(sum, signature) { - return sum + (!!signature); - }, 0); -}; - -MultiSigScriptHashInput.prototype.publicKeysWithoutSignature = function() { - var self = this; - return _.filter(this.publicKeys, function(publicKey) { - return !(self.signatures[self.publicKeyIndex[publicKey.toString()]]); - }); -}; - -MultiSigScriptHashInput.prototype.isValidSignature = function(transaction, signature) { - // FIXME: Refactor signature so this is not necessary - signature.signature.nhashtype = signature.sigtype; - return Sighash.verify( - transaction, - signature.signature, - signature.publicKey, - signature.inputIndex, - this.redeemScript - ); -}; - -MultiSigScriptHashInput.OPCODES_SIZE = 7; // serialized size (<=3) + 0 .. N .. M OP_CHECKMULTISIG -MultiSigScriptHashInput.SIGNATURE_SIZE = 74; // size (1) + DER (<=72) + sighash (1) -MultiSigScriptHashInput.PUBKEY_SIZE = 34; // size (1) + DER (<=33) - -MultiSigScriptHashInput.prototype._estimateSize = function() { - return MultiSigScriptHashInput.OPCODES_SIZE + - this.threshold * MultiSigScriptHashInput.SIGNATURE_SIZE + - this.publicKeys.length * MultiSigScriptHashInput.PUBKEY_SIZE; -}; - -module.exports = MultiSigScriptHashInput; - -},{"../../crypto/signature":11,"../../publickey":24,"../../script":25,"../../util/buffer":42,"../../util/preconditions":44,"../output":35,"../sighash":36,"../signature":37,"./input":30,"inherits":184,"lodash":187}],33:[function(require,module,exports){ -'use strict'; - -var inherits = require('inherits'); - -var $ = require('../../util/preconditions'); -var BufferUtil = require('../../util/buffer'); - -var Input = require('./input'); -var Output = require('../output'); -var Sighash = require('../sighash'); -var Script = require('../../script'); -var Signature = require('../../crypto/signature'); -var TransactionSignature = require('../signature'); - -/** - * Represents a special kind of input of PayToPublicKey kind. - * @constructor - */ -function PublicKeyInput() { - Input.apply(this, arguments); -} -inherits(PublicKeyInput, Input); - -/** - * @param {Transaction} transaction - the transaction to be signed - * @param {PrivateKey} privateKey - the private key with which to sign the transaction - * @param {number} index - the index of the input in the transaction input vector - * @param {number=} sigtype - the type of signature, defaults to Signature.SIGHASH_ALL - * @return {Array} of objects that can be - */ -PublicKeyInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype) { - $.checkState(this.output instanceof Output); - sigtype = sigtype || Signature.SIGHASH_ALL; - var publicKey = privateKey.toPublicKey(); - if (publicKey.toString() === this.output.script.getPublicKey().toString('hex')) { - return [new TransactionSignature({ - publicKey: publicKey, - prevTxId: this.prevTxId, - outputIndex: this.outputIndex, - inputIndex: index, - signature: Sighash.sign(transaction, privateKey, sigtype, index, this.output.script), - sigtype: sigtype - })]; - } - return []; -}; + function encodeTag(tag, primitive, cls, reporter) { + var res; -/** - * Add the provided signature - * - * @param {Object} signature - * @param {PublicKey} signature.publicKey - * @param {Signature} signature.signature - * @param {number=} signature.sigtype - * @return {PublicKeyInput} this, for chaining - */ -PublicKeyInput.prototype.addSignature = function(transaction, signature) { - $.checkState(this.isValidSignature(transaction, signature), 'Signature is invalid'); - this.setScript(Script.buildPublicKeyIn( - signature.signature.toDER(), - signature.sigtype - )); - return this; -}; - -/** - * Clear the input's signature - * @return {PublicKeyHashInput} this, for chaining - */ -PublicKeyInput.prototype.clearSignatures = function() { - this.setScript(Script.empty()); - return this; -}; - -/** - * Query whether the input is signed - * @return {boolean} - */ -PublicKeyInput.prototype.isFullySigned = function() { - return this.script.isPublicKeyIn(); -}; + if (tag === 'seqof') tag = 'seq'; + else if (tag === 'setof') tag = 'set'; -PublicKeyInput.SCRIPT_MAX_SIZE = 73; // sigsize (1 + 72) + if (der.tagByName.hasOwnProperty(tag)) res = der.tagByName[tag]; + else if (typeof tag === 'number' && (tag | 0) === tag) res = tag; + else return reporter.error('Unknown tag: ' + tag); -PublicKeyInput.prototype._estimateSize = function() { - return PublicKeyInput.SCRIPT_MAX_SIZE; -}; + if (res >= 0x1f) return reporter.error('Multi-octet tag encoding unsupported'); -module.exports = PublicKeyInput; + if (!primitive) res |= 0x20; -},{"../../crypto/signature":11,"../../script":25,"../../util/buffer":42,"../../util/preconditions":44,"../output":35,"../sighash":36,"../signature":37,"./input":30,"inherits":184}],34:[function(require,module,exports){ -'use strict'; + res |= der.tagClassByName[cls || 'universal'] << 6; -var inherits = require('inherits'); + return res; + } + }, + { '../../asn1': 45, buffer: 113, inherits: 184 }, + ], + 57: [ + function(require, module, exports) { + var encoders = exports; + + encoders.der = require('./der'); + encoders.pem = require('./pem'); + }, + { './der': 56, './pem': 58 }, + ], + 58: [ + function(require, module, exports) { + var inherits = require('inherits'); -var $ = require('../../util/preconditions'); -var BufferUtil = require('../../util/buffer'); + var DEREncoder = require('./der'); -var Hash = require('../../crypto/hash'); -var Input = require('./input'); -var Output = require('../output'); -var Sighash = require('../sighash'); -var Script = require('../../script'); -var Signature = require('../../crypto/signature'); -var TransactionSignature = require('../signature'); + function PEMEncoder(entity) { + DEREncoder.call(this, entity); + this.enc = 'pem'; + } + inherits(PEMEncoder, DEREncoder); + module.exports = PEMEncoder; -/** - * Represents a special kind of input of PayToPublicKeyHash kind. - * @constructor - */ -function PublicKeyHashInput() { - Input.apply(this, arguments); -} -inherits(PublicKeyHashInput, Input); - -/* jshint maxparams: 5 */ -/** - * @param {Transaction} transaction - the transaction to be signed - * @param {PrivateKey} privateKey - the private key with which to sign the transaction - * @param {number} index - the index of the input in the transaction input vector - * @param {number=} sigtype - the type of signature, defaults to Signature.SIGHASH_ALL - * @param {Buffer=} hashData - the precalculated hash of the public key associated with the privateKey provided - * @return {Array} of objects that can be - */ -PublicKeyHashInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype, hashData) { - $.checkState(this.output instanceof Output); - hashData = hashData || Hash.sha256ripemd160(privateKey.publicKey.toBuffer()); - sigtype = sigtype || Signature.SIGHASH_ALL; - - if (BufferUtil.equals(hashData, this.output.script.getPublicKeyHash())) { - return [new TransactionSignature({ - publicKey: privateKey.publicKey, - prevTxId: this.prevTxId, - outputIndex: this.outputIndex, - inputIndex: index, - signature: Sighash.sign(transaction, privateKey, sigtype, index, this.output.script), - sigtype: sigtype - })]; - } - return []; -}; -/* jshint maxparams: 3 */ + PEMEncoder.prototype.encode = function encode(data, options) { + var buf = DEREncoder.prototype.encode.call(this, data); -/** - * Add the provided signature - * - * @param {Object} signature - * @param {PublicKey} signature.publicKey - * @param {Signature} signature.signature - * @param {number=} signature.sigtype - * @return {PublicKeyHashInput} this, for chaining - */ -PublicKeyHashInput.prototype.addSignature = function(transaction, signature) { - $.checkState(this.isValidSignature(transaction, signature), 'Signature is invalid'); - this.setScript(Script.buildPublicKeyHashIn( - signature.publicKey, - signature.signature.toDER(), - signature.sigtype - )); - return this; -}; - -/** - * Clear the input's signature - * @return {PublicKeyHashInput} this, for chaining - */ -PublicKeyHashInput.prototype.clearSignatures = function() { - this.setScript(Script.empty()); - return this; -}; - -/** - * Query whether the input is signed - * @return {boolean} - */ -PublicKeyHashInput.prototype.isFullySigned = function() { - return this.script.isPublicKeyHashIn(); -}; + var p = buf.toString('base64'); + var out = ['-----BEGIN ' + options.label + '-----']; + for (var i = 0; i < p.length; i += 64) out.push(p.slice(i, i + 64)); + out.push('-----END ' + options.label + '-----'); + return out.join('\n'); + }; + }, + { './der': 56, inherits: 184 }, + ], + 59: [ + function(require, module, exports) { + (function(module, exports) { + 'use strict'; + + // Utils + function assert(val, msg) { + if (!val) throw new Error(msg || 'Assertion failed'); + } -PublicKeyHashInput.SCRIPT_MAX_SIZE = 73 + 34; // sigsize (1 + 72) + pubkey (1 + 33) + // Could use `inherits` module, but don't want to move from single file + // architecture yet. + function inherits(ctor, superCtor) { + ctor.super_ = superCtor; + var TempCtor = function() {}; + TempCtor.prototype = superCtor.prototype; + ctor.prototype = new TempCtor(); + ctor.prototype.constructor = ctor; + } -PublicKeyHashInput.prototype._estimateSize = function() { - return PublicKeyHashInput.SCRIPT_MAX_SIZE; -}; + // BN -module.exports = PublicKeyHashInput; + function BN(number, base, endian) { + if (BN.isBN(number)) { + return number; + } -},{"../../crypto/hash":8,"../../crypto/signature":11,"../../script":25,"../../util/buffer":42,"../../util/preconditions":44,"../output":35,"../sighash":36,"../signature":37,"./input":30,"inherits":184}],35:[function(require,module,exports){ -'use strict'; + this.negative = 0; + this.words = null; + this.length = 0; -var _ = require('lodash'); -var BN = require('../crypto/bn'); -var buffer = require('buffer'); -var bufferUtil = require('../util/buffer'); -var JSUtil = require('../util/js'); -var BufferWriter = require('../encoding/bufferwriter'); -var Script = require('../script'); -var $ = require('../util/preconditions'); -var errors = require('../errors'); + // Reduction context + this.red = null; -var MAX_SAFE_INTEGER = 0x1fffffffffffff; + if (number !== null) { + if (base === 'le' || base === 'be') { + endian = base; + base = 10; + } -function Output(args) { - if (!(this instanceof Output)) { - return new Output(args); - } - if (_.isObject(args)) { - this.micros = args.micros; - if (bufferUtil.isBuffer(args.script)) { - this._scriptBuffer = args.script; - } else { - var script; - if (_.isString(args.script) && JSUtil.isHexa(args.script)) { - script = new buffer.Buffer(args.script, 'hex'); - } else { - script = args.script; - } - this.setScript(script); - } - } else { - throw new TypeError('Unrecognized argument for Output'); - } -} + this._init(number || 0, base || 10, endian || 'be'); + } + } + if (typeof module === 'object') { + module.exports = BN; + } else { + exports.BN = BN; + } -Object.defineProperty(Output.prototype, 'script', { - configurable: false, - enumerable: true, - get: function() { - if (this._script) { - return this._script; - } else { - this.setScriptFromBuffer(this._scriptBuffer); - return this._script; - } + BN.BN = BN; + BN.wordSize = 26; - } -}); + var Buffer; + try { + Buffer = require('buffer').Buffer; + } catch (e) {} -Object.defineProperty(Output.prototype, 'micros', { - configurable: false, - enumerable: true, - get: function() { - return this._micros; - }, - set: function(num) { - if (num instanceof BN) { - this._microsBN = num; - this._micros = num.toNumber(); - } else if (_.isString(num)) { - this._micros = parseInt(num); - this._microsBN = BN.fromNumber(this._micros); - } else { - $.checkArgument( - JSUtil.isNaturalNumber(num), - 'Output micros is not a natural number' - ); - this._microsBN = BN.fromNumber(num); - this._micros = num; - } - $.checkState( - JSUtil.isNaturalNumber(this._micros), - 'Output micros is not a natural number' - ); - } -}); + BN.isBN = function isBN(num) { + if (num instanceof BN) { + return true; + } -Output.prototype.invalidMicros = function() { - if (this._micros > MAX_SAFE_INTEGER) { - return 'transaction txout micros greater than max safe integer'; - } - if (this._micros !== this._microsBN.toNumber()) { - return 'transaction txout micros has corrupted value'; - } - if (this._micros < 0) { - return 'transaction txout negative'; - } - return false; -}; - -Output.prototype.toObject = Output.prototype.toJSON = function toObject() { - var obj = { - micros: this.micros - }; - obj.script = this._scriptBuffer.toString('hex'); - return obj; -}; - -Output.fromObject = function(data) { - return new Output(data); -}; - -Output.prototype.setScriptFromBuffer = function(buffer) { - this._scriptBuffer = buffer; - try { - this._script = Script.fromBuffer(this._scriptBuffer); - this._script._isOutput = true; - } catch(e) { - if (e instanceof errors.Script.InvalidBuffer) { - this._script = null; - } else { - throw e; - } - } -}; - -Output.prototype.setScript = function(script) { - if (script instanceof Script) { - this._scriptBuffer = script.toBuffer(); - this._script = script; - this._script._isOutput = true; - } else if (_.isString(script)) { - this._script = Script.fromString(script); - this._scriptBuffer = this._script.toBuffer(); - this._script._isOutput = true; - } else if (bufferUtil.isBuffer(script)) { - this.setScriptFromBuffer(script); - } else { - throw new TypeError('Invalid argument type: script'); - } - return this; -}; - -Output.prototype.inspect = function() { - var scriptStr; - if (this.script) { - scriptStr = this.script.inspect(); - } else { - scriptStr = this._scriptBuffer.toString('hex'); - } - return ''; -}; - -Output.fromBufferReader = function(br) { - var obj = {}; - obj.micros = br.readUInt64LEBN(); - var size = br.readVarintNum(); - if (size !== 0) { - obj.script = br.read(size); - } else { - obj.script = new buffer.Buffer([]); - } - return new Output(obj); -}; + return ( + num !== null && + typeof num === 'object' && + num.constructor.wordSize === BN.wordSize && + Array.isArray(num.words) + ); + }; + + BN.max = function max(left, right) { + if (left.cmp(right) > 0) return left; + return right; + }; + + BN.min = function min(left, right) { + if (left.cmp(right) < 0) return left; + return right; + }; + + BN.prototype._init = function init(number, base, endian) { + if (typeof number === 'number') { + return this._initNumber(number, base, endian); + } -Output.prototype.toBufferWriter = function(writer) { - if (!writer) { - writer = new BufferWriter(); - } - writer.writeUInt64LEBN(this._microsBN); - var script = this._scriptBuffer; - writer.writeVarintNum(script.length); - writer.write(script); - return writer; -}; - -module.exports = Output; - -},{"../crypto/bn":6,"../encoding/bufferwriter":15,"../errors":17,"../script":25,"../util/buffer":42,"../util/js":43,"../util/preconditions":44,"buffer":113,"lodash":187}],36:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var buffer = require('buffer'); - -var Signature = require('../crypto/signature'); -var Script = require('../script'); -var Output = require('./output'); -var BufferReader = require('../encoding/bufferreader'); -var BufferWriter = require('../encoding/bufferwriter'); -var BN = require('../crypto/bn'); -var Hash = require('../crypto/hash'); -var ECDSA = require('../crypto/ecdsa'); -var $ = require('../util/preconditions'); -var _ = require('lodash'); - -var SIGHASH_SINGLE_BUG = '0000000000000000000000000000000000000000000000000000000000000001'; -var BITS_64_ON = 'ffffffffffffffff'; - -/** - * Returns a buffer of length 32 bytes with the hash that needs to be signed - * for OP_CHECKSIG. - * - * @name Signing.sighash - * @param {Transaction} transaction the transaction to sign - * @param {number} sighashType the type of the hash - * @param {number} inputNumber the input index for the signature - * @param {Script} subscript the script that will be signed - */ -var sighash = function sighash(transaction, sighashType, inputNumber, subscript) { - var Transaction = require('./transaction'); - var Input = require('./input'); + if (typeof number === 'object') { + return this._initArray(number, base, endian); + } - var i; - // Copy transaction - var txcopy = Transaction.shallowCopy(transaction); + if (base === 'hex') { + base = 16; + } + assert(base === (base | 0) && base >= 2 && base <= 36); - // Copy script - subscript = new Script(subscript); - subscript.removeCodeseparators(); + number = number.toString().replace(/\s+/g, ''); + var start = 0; + if (number[0] === '-') { + start++; + } - for (i = 0; i < txcopy.inputs.length; i++) { - // Blank signatures for other inputs - txcopy.inputs[i] = new Input(txcopy.inputs[i]).setScript(Script.empty()); - } + if (base === 16) { + this._parseHex(number, start); + } else { + this._parseBase(number, base, start); + } - txcopy.inputs[inputNumber] = new Input(txcopy.inputs[inputNumber]).setScript(subscript); + if (number[0] === '-') { + this.negative = 1; + } - if ((sighashType & 31) === Signature.SIGHASH_NONE || - (sighashType & 31) === Signature.SIGHASH_SINGLE) { + this.strip(); - // clear all sequenceNumbers - for (i = 0; i < txcopy.inputs.length; i++) { - if (i !== inputNumber) { - txcopy.inputs[i].sequenceNumber = 0; - } - } - } + if (endian !== 'le') return; - if ((sighashType & 31) === Signature.SIGHASH_NONE) { - txcopy.outputs = []; + this._initArray(this.toArray(), base, endian); + }; - } else if ((sighashType & 31) === Signature.SIGHASH_SINGLE) { - // The SIGHASH_SINGLE bug. - // https://bitcointalk.org/index.php?topic=260595.0 - if (inputNumber >= txcopy.outputs.length) { - return new Buffer(SIGHASH_SINGLE_BUG, 'hex'); - } + BN.prototype._initNumber = function _initNumber(number, base, endian) { + if (number < 0) { + this.negative = 1; + number = -number; + } + if (number < 0x4000000) { + this.words = [number & 0x3ffffff]; + this.length = 1; + } else if (number < 0x10000000000000) { + this.words = [number & 0x3ffffff, (number / 0x4000000) & 0x3ffffff]; + this.length = 2; + } else { + assert(number < 0x20000000000000); // 2 ^ 53 (unsafe) + this.words = [number & 0x3ffffff, (number / 0x4000000) & 0x3ffffff, 1]; + this.length = 3; + } - txcopy.outputs.length = inputNumber + 1; + if (endian !== 'le') return; - for (i = 0; i < inputNumber; i++) { - txcopy.outputs[i] = new Output({ - micros: BN.fromBuffer(new buffer.Buffer(BITS_64_ON, 'hex')), - script: Script.empty() - }); - } - } + // Reverse the bytes + this._initArray(this.toArray(), base, endian); + }; - if (sighashType & Signature.SIGHASH_ANYONECANPAY) { - txcopy.inputs = [txcopy.inputs[inputNumber]]; - } + BN.prototype._initArray = function _initArray(number, base, endian) { + // Perhaps a Uint8Array + assert(typeof number.length === 'number'); + if (number.length <= 0) { + this.words = [0]; + this.length = 1; + return this; + } - var buf = new BufferWriter() - .write(txcopy.toBuffer()) - .writeInt32LE(sighashType) - .toBuffer(); - var ret = Hash.sha256sha256(buf); - ret = new BufferReader(ret).readReverse(); - return ret; -}; - -/** - * Create a signature - * - * @name Signing.sign - * @param {Transaction} transaction - * @param {PrivateKey} privateKey - * @param {number} sighash - * @param {number} inputIndex - * @param {Script} subscript - * @return {Signature} - */ -function sign(transaction, privateKey, sighashType, inputIndex, subscript) { - var hashbuf = sighash(transaction, sighashType, inputIndex, subscript); - var sig = ECDSA.sign(hashbuf, privateKey, 'little').set({ - nhashtype: sighashType - }); - return sig; -} + this.length = Math.ceil(number.length / 3); + this.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + this.words[i] = 0; + } -/** - * Verify a signature - * - * @name Signing.verify - * @param {Transaction} transaction - * @param {Signature} signature - * @param {PublicKey} publicKey - * @param {number} inputIndex - * @param {Script} subscript - * @return {boolean} - */ -function verify(transaction, signature, publicKey, inputIndex, subscript) { - $.checkArgument(!_.isUndefined(transaction)); - $.checkArgument(!_.isUndefined(signature) && !_.isUndefined(signature.nhashtype)); - var hashbuf = sighash(transaction, signature.nhashtype, inputIndex, subscript); - return ECDSA.verify(hashbuf, signature, publicKey, 'little'); -} + var j, w; + var off = 0; + if (endian === 'be') { + for (i = number.length - 1, j = 0; i >= 0; i -= 3) { + w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + } else if (endian === 'le') { + for (i = 0, j = 0; i < number.length; i += 3) { + w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + } + return this.strip(); + }; -/** - * @namespace Signing - */ -module.exports = { - sighash: sighash, - sign: sign, - verify: verify -}; - -}).call(this,require("buffer").Buffer) -},{"../crypto/bn":6,"../crypto/ecdsa":7,"../crypto/hash":8,"../crypto/signature":11,"../encoding/bufferreader":14,"../encoding/bufferwriter":15,"../script":25,"../util/preconditions":44,"./input":29,"./output":35,"./transaction":38,"buffer":113,"lodash":187}],37:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var $ = require('../util/preconditions'); -var inherits = require('inherits'); -var BufferUtil = require('../util/buffer'); -var JSUtil = require('../util/js'); - -var PublicKey = require('../publickey'); -var errors = require('../errors'); -var Signature = require('../crypto/signature'); - -/** - * @desc - * Wrapper around Signature with fields related to signing a transaction specifically - * - * @param {Object|string|TransactionSignature} arg - * @constructor - */ -function TransactionSignature(arg) { - if (!(this instanceof TransactionSignature)) { - return new TransactionSignature(arg); - } - if (arg instanceof TransactionSignature) { - return arg; - } - if (_.isObject(arg)) { - return this._fromObject(arg); - } - throw new errors.InvalidArgument('TransactionSignatures must be instantiated from an object'); -} -inherits(TransactionSignature, Signature); - -TransactionSignature.prototype._fromObject = function(arg) { - this._checkObjectArgs(arg); - this.publicKey = new PublicKey(arg.publicKey); - this.prevTxId = BufferUtil.isBuffer(arg.prevTxId) ? arg.prevTxId : new Buffer(arg.prevTxId, 'hex'); - this.outputIndex = arg.outputIndex; - this.inputIndex = arg.inputIndex; - this.signature = (arg.signature instanceof Signature) ? arg.signature : - BufferUtil.isBuffer(arg.signature) ? Signature.fromBuffer(arg.signature) : - Signature.fromString(arg.signature); - this.sigtype = arg.sigtype; - return this; -}; - -TransactionSignature.prototype._checkObjectArgs = function(arg) { - $.checkArgument(PublicKey(arg.publicKey), 'publicKey'); - $.checkArgument(!_.isUndefined(arg.inputIndex), 'inputIndex'); - $.checkArgument(!_.isUndefined(arg.outputIndex), 'outputIndex'); - $.checkState(_.isNumber(arg.inputIndex), 'inputIndex must be a number'); - $.checkState(_.isNumber(arg.outputIndex), 'outputIndex must be a number'); - $.checkArgument(arg.signature, 'signature'); - $.checkArgument(arg.prevTxId, 'prevTxId'); - $.checkState(arg.signature instanceof Signature || - BufferUtil.isBuffer(arg.signature) || - JSUtil.isHexa(arg.signature), 'signature must be a buffer or hexa value'); - $.checkState(BufferUtil.isBuffer(arg.prevTxId) || - JSUtil.isHexa(arg.prevTxId), 'prevTxId must be a buffer or hexa value'); - $.checkArgument(arg.sigtype, 'sigtype'); - $.checkState(_.isNumber(arg.sigtype), 'sigtype must be a number'); -}; - -/** - * Serializes a transaction to a plain JS object - * @return {Object} - */ -TransactionSignature.prototype.toObject = TransactionSignature.prototype.toJSON = function toObject() { - return { - publicKey: this.publicKey.toString(), - prevTxId: this.prevTxId.toString('hex'), - outputIndex: this.outputIndex, - inputIndex: this.inputIndex, - signature: this.signature.toString(), - sigtype: this.sigtype - }; -}; - -/** - * Builds a TransactionSignature from an object - * @param {Object} object - * @return {TransactionSignature} - */ -TransactionSignature.fromObject = function(object) { - $.checkArgument(object); - return new TransactionSignature(object); -}; - -module.exports = TransactionSignature; - -}).call(this,require("buffer").Buffer) -},{"../crypto/signature":11,"../errors":17,"../publickey":24,"../util/buffer":42,"../util/js":43,"../util/preconditions":44,"buffer":113,"inherits":184,"lodash":187}],38:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var $ = require('../util/preconditions'); -var buffer = require('buffer'); -var compare = Buffer.compare || require('buffer-compare'); - -var errors = require('../errors'); -var BufferUtil = require('../util/buffer'); -var JSUtil = require('../util/js'); -var BufferReader = require('../encoding/bufferreader'); -var BufferWriter = require('../encoding/bufferwriter'); -var Hash = require('../crypto/hash'); -var Signature = require('../crypto/signature'); -var Sighash = require('./sighash'); - -var Address = require('../address'); -var UnspentOutput = require('./unspentoutput'); -var Input = require('./input'); -var PublicKeyHashInput = Input.PublicKeyHash; -var PublicKeyInput = Input.PublicKey; -var MultiSigScriptHashInput = Input.MultiSigScriptHash; -var MultiSigInput = Input.MultiSig; -var Output = require('./output'); -var Script = require('../script'); -var PrivateKey = require('../privatekey'); -var BN = require('../crypto/bn'); - -/** - * Represents a transaction, a set of inputs and outputs to change ownership of tokens - * - * @param {*} serialized - * @constructor - */ -function Transaction(serialized) { - if (!(this instanceof Transaction)) { - return new Transaction(serialized); - } - this.inputs = []; - this.outputs = []; - this._inputAmount = undefined; - this._outputAmount = undefined; - - if (serialized) { - if (serialized instanceof Transaction) { - return Transaction.shallowCopy(serialized); - } else if (JSUtil.isHexa(serialized)) { - this.fromString(serialized); - } else if (BufferUtil.isBuffer(serialized)) { - this.fromBuffer(serialized); - } else if (_.isObject(serialized)) { - this.fromObject(serialized); - } else { - throw new errors.InvalidArgument('Must provide an object or string to deserialize a transaction'); - } - } else { - this._newTransaction(); - } -} + function parseHex(str, start, end) { + var r = 0; + var len = Math.min(str.length, end); + for (var i = start; i < len; i++) { + var c = str.charCodeAt(i) - 48; -var CURRENT_VERSION = 1; -var DEFAULT_NLOCKTIME = 0; -var MAX_BLOCK_SIZE = 1000000; + r <<= 4; -// Minimum amount for an output for it not to be considered a dust output -Transaction.DUST_AMOUNT = 546; + // 'a' - 'f' + if (c >= 49 && c <= 54) { + r |= c - 49 + 0xa; -// Margin of error to allow fees in the vecinity of the expected value but doesn't allow a big difference -Transaction.FEE_SECURITY_MARGIN = 150; + // 'A' - 'F' + } else if (c >= 17 && c <= 22) { + r |= c - 17 + 0xa; -// max amount of micros in circulation -Transaction.MAX_MONEY = 21000000 * 1e8; + // '0' - '9' + } else { + r |= c & 0xf; + } + } + return r; + } -// nlocktime limit to be considered block height rather than a timestamp -Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT = 5e8; + BN.prototype._parseHex = function _parseHex(number, start) { + // Create possibly bigger array to ensure that it fits the number + this.length = Math.ceil((number.length - start) / 6); + this.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + this.words[i] = 0; + } -// Max value for an unsigned 32 bit value -Transaction.NLOCKTIME_MAX_VALUE = 4294967295; + var j, w; + // Scan 24-bit chunks and add them to the number + var off = 0; + for (i = number.length - 6, j = 0; i >= start; i -= 6) { + w = parseHex(number, i, i + 6); + this.words[j] |= (w << off) & 0x3ffffff; + // NOTE: `0x3fffff` is intentional here, 26bits max shift + 24bit hex limb + this.words[j + 1] |= (w >>> (26 - off)) & 0x3fffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + if (i + 6 !== start) { + w = parseHex(number, start, i + 6); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] |= (w >>> (26 - off)) & 0x3fffff; + } + this.strip(); + }; -// Value used for fee estimation (micros per kilobyte) -Transaction.FEE_PER_KB = 100000; + function parseBase(str, start, end, mul) { + var r = 0; + var len = Math.min(str.length, end); + for (var i = start; i < len; i++) { + var c = str.charCodeAt(i) - 48; -// Safe upper bound for change address script size in bytes -Transaction.CHANGE_OUTPUT_MAX_SIZE = 20 + 4 + 34 + 4; -Transaction.MAXIMUM_EXTRA_SIZE = 4 + 9 + 9 + 4; + r *= mul; -/* Constructors and Serialization */ + // 'a' + if (c >= 49) { + r += c - 49 + 0xa; -/** - * Create a 'shallow' copy of the transaction, by serializing and deserializing - * it dropping any additional information that inputs and outputs may have hold - * - * @param {Transaction} transaction - * @return {Transaction} - */ -Transaction.shallowCopy = function(transaction) { - var copy = new Transaction(transaction.toBuffer()); - return copy; -}; - -var hashProperty = { - configurable: false, - enumerable: true, - get: function() { - return new BufferReader(this._getHash()).readReverse().toString('hex'); - } -}; -Object.defineProperty(Transaction.prototype, 'hash', hashProperty); -Object.defineProperty(Transaction.prototype, 'id', hashProperty); - -var ioProperty = { - configurable: false, - enumerable: true, - get: function() { - return this._getInputAmount(); - } -}; -Object.defineProperty(Transaction.prototype, 'inputAmount', ioProperty); -ioProperty.get = function() { - return this._getOutputAmount(); -}; -Object.defineProperty(Transaction.prototype, 'outputAmount', ioProperty); - -/** - * Retrieve the little endian hash of the transaction (used for serialization) - * @return {Buffer} - */ -Transaction.prototype._getHash = function() { - return Hash.sha256sha256(this.toBuffer()); -}; + // 'A' + } else if (c >= 17) { + r += c - 17 + 0xa; -/** - * Retrieve a hexa string that can be used with bitcoind's CLI interface - * (decoderawtransaction, sendrawtransaction) - * - * @param {Object|boolean=} unsafe if true, skip all tests. if it's an object, - * it's expected to contain a set of flags to skip certain tests: - * * `disableAll`: disable all checks - * * `disableSmallFees`: disable checking for fees that are too small - * * `disableLargeFees`: disable checking for fees that are too large - * * `disableIsFullySigned`: disable checking if all inputs are fully signed - * * `disableDustOutputs`: disable checking if there are no outputs that are dust amounts - * * `disableMoreOutputThanInput`: disable checking if the transaction spends more bitcoins than the sum of the input amounts - * @return {string} - */ -Transaction.prototype.serialize = function(unsafe) { - if (true === unsafe || unsafe && unsafe.disableAll) { - return this.uncheckedSerialize(); - } else { - return this.checkedSerialize(unsafe); - } -}; + // '0' - '9' + } else { + r += c; + } + } + return r; + } -Transaction.prototype.uncheckedSerialize = Transaction.prototype.toString = function() { - return this.toBuffer().toString('hex'); -}; + BN.prototype._parseBase = function _parseBase(number, base, start) { + // Initialize as zero + this.words = [0]; + this.length = 1; -/** - * Retrieve a hexa string that can be used with bitcoind's CLI interface - * (decoderawtransaction, sendrawtransaction) - * - * @param {Object} opts allows to skip certain tests. {@see Transaction#serialize} - * @return {string} - */ -Transaction.prototype.checkedSerialize = function(opts) { - var serializationError = this.getSerializationError(opts); - if (serializationError) { - serializationError.message += ' - For more information please see: ' + - 'https://bitcore.io/api/lib/transaction#serialization-checks'; - throw serializationError; - } - return this.uncheckedSerialize(); -}; - -Transaction.prototype.invalidMicros = function() { - var invalid = false; - for (var i = 0; i < this.outputs.length; i++) { - if (this.outputs[i].invalidMicros()) { - invalid = true; - } - } - return invalid; -}; + // Find length of limb in base + for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) { + limbLen++; + } + limbLen--; + limbPow = (limbPow / base) | 0; + + var total = number.length - start; + var mod = total % limbLen; + var end = Math.min(total, total - mod) + start; + + var word = 0; + for (var i = start; i < end; i += limbLen) { + word = parseBase(number, i, i + limbLen, base); + + this.imuln(limbPow); + if (this.words[0] + word < 0x4000000) { + this.words[0] += word; + } else { + this._iaddn(word); + } + } -/** - * Retrieve a possible error that could appear when trying to serialize and - * broadcast this transaction. - * - * @param {Object} opts allows to skip certain tests. {@see Transaction#serialize} - * @return {bitcore.Error} - */ -Transaction.prototype.getSerializationError = function(opts) { - opts = opts || {}; + if (mod !== 0) { + var pow = 1; + word = parseBase(number, i, number.length, base); - if (this.invalidMicros()) { - return new errors.Transaction.InvalidMicros(); - } + for (i = 0; i < mod; i++) { + pow *= base; + } - var unspent = this._getUnspentValue(); - var unspentError; - if (unspent < 0) { - if (!opts.disableMoreOutputThanInput) { - unspentError = new errors.Transaction.InvalidOutputAmountSum(); - } - } else { - unspentError = this._hasFeeError(opts, unspent); - } + this.imuln(pow); + if (this.words[0] + word < 0x4000000) { + this.words[0] += word; + } else { + this._iaddn(word); + } + } + }; - return unspentError || - this._hasDustOutputs(opts) || - this._isMissingSignatures(opts); -}; + BN.prototype.copy = function copy(dest) { + dest.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + dest.words[i] = this.words[i]; + } + dest.length = this.length; + dest.negative = this.negative; + dest.red = this.red; + }; + + BN.prototype.clone = function clone() { + var r = new BN(null); + this.copy(r); + return r; + }; + + BN.prototype._expand = function _expand(size) { + while (this.length < size) { + this.words[this.length++] = 0; + } + return this; + }; -Transaction.prototype._hasFeeError = function(opts, unspent) { + // Remove leading `0` from `this` + BN.prototype.strip = function strip() { + while (this.length > 1 && this.words[this.length - 1] === 0) { + this.length--; + } + return this._normSign(); + }; - if (!_.isUndefined(this._fee) && this._fee !== unspent) { - return new errors.Transaction.FeeError.Different( - 'Unspent value is ' + unspent + ' but specified fee is ' + this._fee - ); - } + BN.prototype._normSign = function _normSign() { + // -0 = 0 + if (this.length === 1 && this.words[0] === 0) { + this.negative = 0; + } + return this; + }; - if (!opts.disableLargeFees) { - var maximumFee = Math.floor(Transaction.FEE_SECURITY_MARGIN * this._estimateFee()); - if (unspent > maximumFee) { - if (this._missingChange()) { - return new errors.Transaction.ChangeAddressMissing( - 'Fee is too large and no change address was provided' - ); - } - return new errors.Transaction.FeeError.TooLarge( - 'expected less than ' + maximumFee + ' but got ' + unspent - ); - } - } + BN.prototype.inspect = function inspect() { + return (this.red ? ''; + }; - if (!opts.disableSmallFees) { - var minimumFee = Math.ceil(this._estimateFee() / Transaction.FEE_SECURITY_MARGIN); - if (unspent < minimumFee) { - return new errors.Transaction.FeeError.TooSmall( - 'expected more than ' + minimumFee + ' but got ' + unspent - ); - } - } -}; + /* -Transaction.prototype._missingChange = function() { - return !this._changeScript; -}; + var zeros = []; + var groupSizes = []; + var groupBases = []; -Transaction.prototype._hasDustOutputs = function(opts) { - if (opts.disableDustOutputs) { - return; + var s = ''; + var i = -1; + while (++i < BN.wordSize) { + zeros[i] = s; + s += '0'; } - var index, output; - for (index in this.outputs) { - output = this.outputs[index]; - if (output.micros < Transaction.DUST_AMOUNT && !output.script.isDataOut()) { - return new errors.Transaction.DustOutputs(); + groupSizes[0] = 0; + groupSizes[1] = 0; + groupBases[0] = 0; + groupBases[1] = 0; + var base = 2 - 1; + while (++base < 36 + 1) { + var groupSize = 0; + var groupBase = 1; + while (groupBase < (1 << BN.wordSize) / base) { + groupBase *= base; + groupSize += 1; } + groupSizes[base] = groupSize; + groupBases[base] = groupBase; } -}; -Transaction.prototype._isMissingSignatures = function(opts) { - if (opts.disableIsFullySigned) { - return; - } - if (!this.isFullySigned()) { - return new errors.Transaction.MissingSignatures(); - } -}; - -Transaction.prototype.inspect = function() { - return ''; -}; - -Transaction.prototype.toBuffer = function() { - var writer = new BufferWriter(); - return this.toBufferWriter(writer).toBuffer(); -}; - -Transaction.prototype.toBufferWriter = function(writer) { - writer.writeInt32LE(this.version); - writer.writeVarintNum(this.inputs.length); - _.each(this.inputs, function(input) { - input.toBufferWriter(writer); - }); - writer.writeVarintNum(this.outputs.length); - _.each(this.outputs, function(output) { - output.toBufferWriter(writer); - }); - writer.writeUInt32LE(this.nLockTime); - return writer; -}; - -Transaction.prototype.fromBuffer = function(buffer) { - var reader = new BufferReader(buffer); - return this.fromBufferReader(reader); -}; - -Transaction.prototype.fromBufferReader = function(reader) { - $.checkArgument(!reader.finished(), 'No transaction data received'); - var i, sizeTxIns, sizeTxOuts; - - this.version = reader.readInt32LE(); - sizeTxIns = reader.readVarintNum(); - for (i = 0; i < sizeTxIns; i++) { - var input = Input.fromBufferReader(reader); - this.inputs.push(input); - } - sizeTxOuts = reader.readVarintNum(); - for (i = 0; i < sizeTxOuts; i++) { - this.outputs.push(Output.fromBufferReader(reader)); - } - this.nLockTime = reader.readUInt32LE(); - return this; -}; - -Transaction.prototype.toObject = Transaction.prototype.toJSON = function toObject() { - var inputs = []; - this.inputs.forEach(function(input) { - inputs.push(input.toObject()); - }); - var outputs = []; - this.outputs.forEach(function(output) { - outputs.push(output.toObject()); - }); - var obj = { - hash: this.hash, - version: this.version, - inputs: inputs, - outputs: outputs, - nLockTime: this.nLockTime - }; - if (this._changeScript) { - obj.changeScript = this._changeScript.toString(); - } - if (!_.isUndefined(this._changeIndex)) { - obj.changeIndex = this._changeIndex; - } - if (!_.isUndefined(this._fee)) { - obj.fee = this._fee; - } - return obj; -}; - -Transaction.prototype.fromObject = function fromObject(arg) { - /* jshint maxstatements: 20 */ - $.checkArgument(_.isObject(arg) || arg instanceof Transaction); - var self = this; - var transaction; - if (arg instanceof Transaction) { - transaction = transaction.toObject(); - } else { - transaction = arg; - } - _.each(transaction.inputs, function(input) { - if (!input.output || !input.output.script) { - self.uncheckedAddInput(new Input(input)); - return; - } - var script = new Script(input.output.script); - var txin; - if (script.isPublicKeyHashOut()) { - txin = new Input.PublicKeyHash(input); - } else if (script.isScriptHashOut() && input.publicKeys && input.threshold) { - txin = new Input.MultiSigScriptHash( - input, input.publicKeys, input.threshold, input.signatures - ); - } else if (script.isPublicKeyOut()) { - txin = new Input.PublicKey(input); - } else { - throw new errors.Transaction.Input.UnsupportedScript(input.output.script); - } - self.addInput(txin); - }); - _.each(transaction.outputs, function(output) { - self.addOutput(new Output(output)); - }); - if (transaction.changeIndex) { - this._changeIndex = transaction.changeIndex; - } - if (transaction.changeScript) { - this._changeScript = new Script(transaction.changeScript); - } - if (transaction.fee) { - this._fee = transaction.fee; - } - this.nLockTime = transaction.nLockTime; - this.version = transaction.version; - this._checkConsistency(arg); - return this; -}; - -Transaction.prototype._checkConsistency = function(arg) { - if (!_.isUndefined(this._changeIndex)) { - $.checkState(this._changeScript); - $.checkState(this.outputs[this._changeIndex]); - $.checkState(this.outputs[this._changeIndex].script.toString() === - this._changeScript.toString()); - } - if (arg && arg.hash) { - $.checkState(arg.hash === this.hash, 'Hash in object does not match transaction hash'); - } -}; + */ -/** - * Sets nLockTime so that transaction is not valid until the desired date(a - * timestamp in seconds since UNIX epoch is also accepted) - * - * @param {Date | Number} time - * @return {Transaction} this - */ -Transaction.prototype.lockUntilDate = function(time) { - $.checkArgument(time); - if (_.isNumber(time) && time < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) { - throw new errors.Transaction.LockTimeTooEarly(); - } - if (_.isDate(time)) { - time = time.getTime() / 1000; - } + var zeros = [ + '', + '0', + '00', + '000', + '0000', + '00000', + '000000', + '0000000', + '00000000', + '000000000', + '0000000000', + '00000000000', + '000000000000', + '0000000000000', + '00000000000000', + '000000000000000', + '0000000000000000', + '00000000000000000', + '000000000000000000', + '0000000000000000000', + '00000000000000000000', + '000000000000000000000', + '0000000000000000000000', + '00000000000000000000000', + '000000000000000000000000', + '0000000000000000000000000', + ]; + + var groupSizes = [ + 0, + 0, + 25, + 16, + 12, + 11, + 10, + 9, + 8, + 8, + 7, + 7, + 7, + 7, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + ]; + + var groupBases = [ + 0, + 0, + 33554432, + 43046721, + 16777216, + 48828125, + 60466176, + 40353607, + 16777216, + 43046721, + 10000000, + 19487171, + 35831808, + 62748517, + 7529536, + 11390625, + 16777216, + 24137569, + 34012224, + 47045881, + 64000000, + 4084101, + 5153632, + 6436343, + 7962624, + 9765625, + 11881376, + 14348907, + 17210368, + 20511149, + 24300000, + 28629151, + 33554432, + 39135393, + 45435424, + 52521875, + 60466176, + ]; + + BN.prototype.toString = function toString(base, padding) { + base = base || 10; + padding = padding | 0 || 1; + + var out; + if (base === 16 || base === 'hex') { + out = ''; + var off = 0; + var carry = 0; + for (var i = 0; i < this.length; i++) { + var w = this.words[i]; + var word = (((w << off) | carry) & 0xffffff).toString(16); + carry = (w >>> (24 - off)) & 0xffffff; + if (carry !== 0 || i !== this.length - 1) { + out = zeros[6 - word.length] + word + out; + } else { + out = word + out; + } + off += 2; + if (off >= 26) { + off -= 26; + i--; + } + } + if (carry !== 0) { + out = carry.toString(16) + out; + } + while (out.length % padding !== 0) { + out = '0' + out; + } + if (this.negative !== 0) { + out = '-' + out; + } + return out; + } - for (var i = 0; i < this.inputs.length; i++) { - if (this.inputs[i].sequenceNumber === Input.DEFAULT_SEQNUMBER){ - this.inputs[i].sequenceNumber = Input.DEFAULT_LOCKTIME_SEQNUMBER; - } - } + if (base === (base | 0) && base >= 2 && base <= 36) { + // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base)); + var groupSize = groupSizes[base]; + // var groupBase = Math.pow(base, groupSize); + var groupBase = groupBases[base]; + out = ''; + var c = this.clone(); + c.negative = 0; + while (!c.isZero()) { + var r = c.modn(groupBase).toString(base); + c = c.idivn(groupBase); + + if (!c.isZero()) { + out = zeros[groupSize - r.length] + r + out; + } else { + out = r + out; + } + } + if (this.isZero()) { + out = '0' + out; + } + while (out.length % padding !== 0) { + out = '0' + out; + } + if (this.negative !== 0) { + out = '-' + out; + } + return out; + } - this.nLockTime = time; - return this; -}; + assert(false, 'Base should be between 2 and 36'); + }; + + BN.prototype.toNumber = function toNumber() { + var ret = this.words[0]; + if (this.length === 2) { + ret += this.words[1] * 0x4000000; + } else if (this.length === 3 && this.words[2] === 0x01) { + // NOTE: at this stage it is known that the top bit is set + ret += 0x10000000000000 + this.words[1] * 0x4000000; + } else if (this.length > 2) { + assert(false, 'Number can only safely store up to 53 bits'); + } + return this.negative !== 0 ? -ret : ret; + }; + + BN.prototype.toJSON = function toJSON() { + return this.toString(16); + }; + + BN.prototype.toBuffer = function toBuffer(endian, length) { + assert(typeof Buffer !== 'undefined'); + return this.toArrayLike(Buffer, endian, length); + }; + + BN.prototype.toArray = function toArray(endian, length) { + return this.toArrayLike(Array, endian, length); + }; + + BN.prototype.toArrayLike = function toArrayLike(ArrayType, endian, length) { + var byteLength = this.byteLength(); + var reqLength = length || Math.max(1, byteLength); + assert(byteLength <= reqLength, 'byte array longer than desired length'); + assert(reqLength > 0, 'Requested array length <= 0'); + + this.strip(); + var littleEndian = endian === 'le'; + var res = new ArrayType(reqLength); + + var b, i; + var q = this.clone(); + if (!littleEndian) { + // Assume big-endian + for (i = 0; i < reqLength - byteLength; i++) { + res[i] = 0; + } -/** - * Sets nLockTime so that transaction is not valid until the desired block - * height. - * - * @param {Number} height - * @return {Transaction} this - */ -Transaction.prototype.lockUntilBlockHeight = function(height) { - $.checkArgument(_.isNumber(height)); - if (height >= Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) { - throw new errors.Transaction.BlockHeightTooHigh(); - } - if (height < 0) { - throw new errors.Transaction.NLockTimeOutOfRange(); - } + for (i = 0; !q.isZero(); i++) { + b = q.andln(0xff); + q.iushrn(8); - for (var i = 0; i < this.inputs.length; i++) { - if (this.inputs[i].sequenceNumber === Input.DEFAULT_SEQNUMBER){ - this.inputs[i].sequenceNumber = Input.DEFAULT_LOCKTIME_SEQNUMBER; - } - } + res[reqLength - i - 1] = b; + } + } else { + for (i = 0; !q.isZero(); i++) { + b = q.andln(0xff); + q.iushrn(8); + res[i] = b; + } - this.nLockTime = height; - return this; -}; + for (; i < reqLength; i++) { + res[i] = 0; + } + } -/** - * Returns a semantic version of the transaction's nLockTime. - * @return {Number|Date} - * If nLockTime is 0, it returns null, - * if it is < 500000000, it returns a block height (number) - * else it returns a Date object. - */ -Transaction.prototype.getLockTime = function() { - if (!this.nLockTime) { - return null; - } - if (this.nLockTime < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) { - return this.nLockTime; - } - return new Date(1000 * this.nLockTime); -}; - -Transaction.prototype.fromString = function(string) { - this.fromBuffer(new buffer.Buffer(string, 'hex')); -}; - -Transaction.prototype._newTransaction = function() { - this.version = CURRENT_VERSION; - this.nLockTime = DEFAULT_NLOCKTIME; -}; - -/* Transaction creation interface */ - -/** - * @typedef {Object} Transaction~fromObject - * @property {string} prevTxId - * @property {number} outputIndex - * @property {(Buffer|string|Script)} script - * @property {number} micros - */ + return res; + }; -/** - * Add an input to this transaction. This is a high level interface - * to add an input, for more control, use @{link Transaction#addInput}. - * - * Can receive, as output information, the output of bitcoind's `listunspent` command, - * and a slightly fancier format recognized by Merit library: - * - * ``` - * { - * address: 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1', - * txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458', - * outputIndex: 0, - * script: Script.empty(), - * micros: 1020000 - * } - * ``` - * Where `address` can be either a string or a Merit Address object. The - * same is true for `script`, which can be a string or a Merit Script. - * - * Beware that this resets all the signatures for inputs (in further versions, - * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). - * - * @example - * ```javascript - * var transaction = new Transaction(); - * - * // From a pay to public key hash output from bitcoind's listunspent - * transaction.from({'txid': '0000...', vout: 0, amount: 0.1, scriptPubKey: 'OP_DUP ...'}); - * - * // From a pay to public key hash output - * transaction.from({'txId': '0000...', outputIndex: 0, micros: 1000, script: 'OP_DUP ...'}); - * - * // From a multisig P2SH output - * transaction.from({'txId': '0000...', inputIndex: 0, micros: 1000, script: '... OP_HASH'}, - * ['03000...', '02000...'], 2); - * ``` - * - * @param {(Array.|Transaction~fromObject)} utxo - * @param {Array=} pubkeys - * @param {number=} threshold - */ -Transaction.prototype.from = function(utxo, pubkeys, threshold) { - if (_.isArray(utxo)) { - var self = this; - _.each(utxo, function(utxo) { - self.from(utxo, pubkeys, threshold); - }); - return this; - } - var exists = _.some(this.inputs, function(input) { - // TODO: Maybe prevTxId should be a string? Or defined as read only property? - return input.prevTxId.toString('hex') === utxo.txId && input.outputIndex === utxo.outputIndex; - }); - if (exists) { - return this; - } - if (pubkeys && threshold) { - this._fromMultisigUtxo(utxo, pubkeys, threshold); - } else { - this._fromNonP2SH(utxo); - } - return this; -}; - -Transaction.prototype._fromNonP2SH = function(utxo) { - var clazz; - utxo = new UnspentOutput(utxo); - if (utxo.script.isPublicKeyHashOut()) { - clazz = PublicKeyHashInput; - } else if (utxo.script.isPublicKeyOut()) { - clazz = PublicKeyInput; - } else { - clazz = Input; - } - this.addInput(new clazz({ - output: new Output({ - script: utxo.script, - micros: utxo.micros - }), - prevTxId: utxo.txId, - outputIndex: utxo.outputIndex, - script: Script.empty() - })); -}; - -Transaction.prototype._fromMultisigUtxo = function(utxo, pubkeys, threshold) { - $.checkArgument(threshold <= pubkeys.length, - 'Number of required signatures must be greater than the number of public keys'); - var clazz; - utxo = new UnspentOutput(utxo); - if (utxo.script.isMultisigOut()) { - clazz = MultiSigInput; - } else if (utxo.script.isScriptHashOut()) { - clazz = MultiSigScriptHashInput; - } else { - throw new Error("@TODO"); - } - this.addInput(new clazz({ - output: new Output({ - script: utxo.script, - micros: utxo.micros - }), - prevTxId: utxo.txId, - outputIndex: utxo.outputIndex, - script: Script.empty() - }, pubkeys, threshold)); -}; - -/** - * Add an input to this transaction. The input must be an instance of the `Input` class. - * It should have information about the Output that it's spending, but if it's not already - * set, two additional parameters, `outputScript` and `micros` can be provided. - * - * @param {Input} input - * @param {String|Script} outputScript - * @param {number} micros - * @return Transaction this, for chaining - */ -Transaction.prototype.addInput = function(input, outputScript, micros) { - $.checkArgumentType(input, Input, 'input'); - if (!input.output && (_.isUndefined(outputScript) || _.isUndefined(micros))) { - throw new errors.Transaction.NeedMoreInfo('Need information about the UTXO script and micros'); - } - if (!input.output && outputScript && !_.isUndefined(micros)) { - outputScript = outputScript instanceof Script ? outputScript : new Script(outputScript); - $.checkArgumentType(micros, 'number', 'micros'); - input.output = new Output({ - script: outputScript, - micros: micros - }); - } - return this.uncheckedAddInput(input); -}; + if (Math.clz32) { + BN.prototype._countBits = function _countBits(w) { + return 32 - Math.clz32(w); + }; + } else { + BN.prototype._countBits = function _countBits(w) { + var t = w; + var r = 0; + if (t >= 0x1000) { + r += 13; + t >>>= 13; + } + if (t >= 0x40) { + r += 7; + t >>>= 7; + } + if (t >= 0x8) { + r += 4; + t >>>= 4; + } + if (t >= 0x02) { + r += 2; + t >>>= 2; + } + return r + t; + }; + } -/** - * Add an input to this transaction, without checking that the input has information about - * the output that it's spending. - * - * @param {Input} input - * @return Transaction this, for chaining - */ -Transaction.prototype.uncheckedAddInput = function(input) { - $.checkArgumentType(input, Input, 'input'); - this.inputs.push(input); - this._inputAmount = undefined; - this._updateChangeOutput(); - return this; -}; - -/** - * Returns true if the transaction has enough info on all inputs to be correctly validated - * - * @return {boolean} - */ -Transaction.prototype.hasAllUtxoInfo = function() { - return _.every(this.inputs.map(function(input) { - return !!input.output; - })); -}; - -/** - * Manually set the fee for this transaction. Beware that this resets all the signatures - * for inputs (in further versions, SIGHASH_SINGLE or SIGHASH_NONE signatures will not - * be reset). - * - * @param {number} amount micros to be sent - * @return {Transaction} this, for chaining - */ -Transaction.prototype.fee = function(amount) { - $.checkArgument(_.isNumber(amount), 'amount must be a number'); - this._fee = amount; - this._updateChangeOutput(); - return this; -}; - -/** - * Manually set the fee per KB for this transaction. Beware that this resets all the signatures - * for inputs (in further versions, SIGHASH_SINGLE or SIGHASH_NONE signatures will not - * be reset). - * - * @param {number} amount micros per KB to be sent - * @return {Transaction} this, for chaining - */ -Transaction.prototype.feePerKb = function(amount) { - $.checkArgument(_.isNumber(amount), 'amount must be a number'); - this._feePerKb = amount; - this._updateChangeOutput(); - return this; -}; + BN.prototype._zeroBits = function _zeroBits(w) { + // Short-cut + if (w === 0) return 26; -/* Output management */ + var t = w; + var r = 0; + if ((t & 0x1fff) === 0) { + r += 13; + t >>>= 13; + } + if ((t & 0x7f) === 0) { + r += 7; + t >>>= 7; + } + if ((t & 0xf) === 0) { + r += 4; + t >>>= 4; + } + if ((t & 0x3) === 0) { + r += 2; + t >>>= 2; + } + if ((t & 0x1) === 0) { + r++; + } + return r; + }; -/** - * Set the change address for this transaction - * - * Beware that this resets all the signatures for inputs (in further versions, - * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). - * - * @param {Address} address An address for change to be sent to. - * @return {Transaction} this, for chaining - */ -Transaction.prototype.change = function(address) { - $.checkArgument(address, 'address is required'); - this._changeScript = Script.fromAddress(address); - this._updateChangeOutput(); - return this; -}; + // Return number of used bits in a BN + BN.prototype.bitLength = function bitLength() { + var w = this.words[this.length - 1]; + var hi = this._countBits(w); + return (this.length - 1) * 26 + hi; + }; + function toBitArray(num) { + var w = new Array(num.bitLength()); -/** - * @return {Output} change output, if it exists - */ -Transaction.prototype.getChangeOutput = function() { - if (!_.isUndefined(this._changeIndex)) { - return this.outputs[this._changeIndex]; - } - return null; -}; + for (var bit = 0; bit < w.length; bit++) { + var off = (bit / 26) | 0; + var wbit = bit % 26; -/** - * @typedef {Object} Transaction~toObject - * @property {(string|Address)} address - * @property {number} micros - */ + w[bit] = (num.words[off] & (1 << wbit)) >>> wbit; + } -/** - * Add an output to the transaction. - * - * Beware that this resets all the signatures for inputs (in further versions, - * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). - * - * @param {(string|Address|Array.)} address - * @param {number} amount in micros - * @return {Transaction} this, for chaining - */ -Transaction.prototype.to = function(address, amount) { - if (_.isArray(address)) { - var self = this; - _.each(address, function(to) { - self.to(to.address, to.micros); - }); - return this; - } + return w; + } - $.checkArgument( - JSUtil.isNaturalNumber(amount), - 'Amount is expected to be a positive integer' - ); - this.addOutput(new Output({ - script: Script(new Address(address)), - micros: amount - })); - return this; -}; - -/** - * Add an OP_RETURN output to the transaction. - * - * Beware that this resets all the signatures for inputs (in further versions, - * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). - * - * @param {Buffer|string} value the data to be stored in the OP_RETURN output. - * In case of a string, the UTF-8 representation will be stored - * @return {Transaction} this, for chaining - */ -Transaction.prototype.addData = function(value) { - this.addOutput(new Output({ - script: Script.buildDataOut(value), - micros: 0 - })); - return this; -}; + // Number of trailing zero bits + BN.prototype.zeroBits = function zeroBits() { + if (this.isZero()) return 0; + var r = 0; + for (var i = 0; i < this.length; i++) { + var b = this._zeroBits(this.words[i]); + r += b; + if (b !== 26) break; + } + return r; + }; + + BN.prototype.byteLength = function byteLength() { + return Math.ceil(this.bitLength() / 8); + }; + + BN.prototype.toTwos = function toTwos(width) { + if (this.negative !== 0) { + return this.abs() + .inotn(width) + .iaddn(1); + } + return this.clone(); + }; + + BN.prototype.fromTwos = function fromTwos(width) { + if (this.testn(width - 1)) { + return this.notn(width) + .iaddn(1) + .ineg(); + } + return this.clone(); + }; -/** - * Add an output to the transaction. - * - * @param {Output} output the output to add. - * @return {Transaction} this, for chaining - */ -Transaction.prototype.addOutput = function(output) { - $.checkArgumentType(output, Output, 'output'); - this._addOutput(output); - this._updateChangeOutput(); - return this; -}; + BN.prototype.isNeg = function isNeg() { + return this.negative !== 0; + }; + // Return negative clone of `this` + BN.prototype.neg = function neg() { + return this.clone().ineg(); + }; -/** - * Remove all outputs from the transaction. - * - * @return {Transaction} this, for chaining - */ -Transaction.prototype.clearOutputs = function() { - this.outputs = []; - this._clearSignatures(); - this._outputAmount = undefined; - this._changeIndex = undefined; - this._updateChangeOutput(); - return this; -}; + BN.prototype.ineg = function ineg() { + if (!this.isZero()) { + this.negative ^= 1; + } + return this; + }; -Transaction.prototype._addOutput = function(output) { - this.outputs.push(output); - this._outputAmount = undefined; -}; + // Or `num` with `this` in-place + BN.prototype.iuor = function iuor(num) { + while (this.length < num.length) { + this.words[this.length++] = 0; + } + for (var i = 0; i < num.length; i++) { + this.words[i] = this.words[i] | num.words[i]; + } -/** - * Calculates or gets the total output amount in micros - * - * @return {Number} the transaction total output amount - */ -Transaction.prototype._getOutputAmount = function() { - if (_.isUndefined(this._outputAmount)) { - var self = this; - this._outputAmount = 0; - _.each(this.outputs, function(output) { - self._outputAmount += output.micros; - }); - } - return this._outputAmount; -}; + return this.strip(); + }; + + BN.prototype.ior = function ior(num) { + assert((this.negative | num.negative) === 0); + return this.iuor(num); + }; + + // Or `num` with `this` + BN.prototype.or = function or(num) { + if (this.length > num.length) return this.clone().ior(num); + return num.clone().ior(this); + }; + + BN.prototype.uor = function uor(num) { + if (this.length > num.length) return this.clone().iuor(num); + return num.clone().iuor(this); + }; + + // And `num` with `this` in-place + BN.prototype.iuand = function iuand(num) { + // b = min-length(num, this) + var b; + if (this.length > num.length) { + b = num; + } else { + b = this; + } + for (var i = 0; i < b.length; i++) { + this.words[i] = this.words[i] & num.words[i]; + } -/** - * Calculates or gets the total input amount in micros - * - * @return {Number} the transaction total input amount - */ -Transaction.prototype._getInputAmount = function() { - if (_.isUndefined(this._inputAmount)) { - var self = this; - this._inputAmount = 0; - _.each(this.inputs, function(input) { - if (_.isUndefined(input.output)) { - throw new errors.Transaction.Input.MissingPreviousOutput(); - } - self._inputAmount += input.output.micros; - }); - } - return this._inputAmount; -}; + this.length = b.length; + + return this.strip(); + }; + + BN.prototype.iand = function iand(num) { + assert((this.negative | num.negative) === 0); + return this.iuand(num); + }; + + // And `num` with `this` + BN.prototype.and = function and(num) { + if (this.length > num.length) return this.clone().iand(num); + return num.clone().iand(this); + }; + + BN.prototype.uand = function uand(num) { + if (this.length > num.length) return this.clone().iuand(num); + return num.clone().iuand(this); + }; + + // Xor `num` with `this` in-place + BN.prototype.iuxor = function iuxor(num) { + // a.length > b.length + var a; + var b; + if (this.length > num.length) { + a = this; + b = num; + } else { + a = num; + b = this; + } -Transaction.prototype._updateChangeOutput = function() { - if (!this._changeScript) { - return; - } - this._clearSignatures(); - if (!_.isUndefined(this._changeIndex)) { - this._removeOutput(this._changeIndex); - } - var available = this._getUnspentValue(); - var fee = this.getFee(); - var changeAmount = available - fee; - if (changeAmount > 0) { - this._changeIndex = this.outputs.length; - this._addOutput(new Output({ - script: this._changeScript, - micros: changeAmount - })); - } else { - this._changeIndex = undefined; - } -}; -/** - * Calculates the fee of the transaction. - * - * If there's a fixed fee set, return that. - * - * If there is no change output set, the fee is the - * total value of the outputs minus inputs. Note that - * a serialized transaction only specifies the value - * of its outputs. (The value of inputs are recorded - * in the previous transaction outputs being spent.) - * This method therefore raises a "MissingPreviousOutput" - * error when called on a serialized transaction. - * - * If there's no fee set and no change address, - * estimate the fee based on size. - * - * @return {Number} fee of this transaction in micros - */ -Transaction.prototype.getFee = function() { - if (this.isCoinbase()) { - return 0; - } - if (!_.isUndefined(this._fee)) { - return this._fee; - } - // if no change output is set, fees should equal all the unspent amount - if (!this._changeScript) { - return this._getUnspentValue(); - } - return this._estimateFee(); -}; + for (var i = 0; i < b.length; i++) { + this.words[i] = a.words[i] ^ b.words[i]; + } -/** - * Estimates fee from serialized transaction size in bytes. - */ -Transaction.prototype._estimateFee = function() { - var estimatedSize = this._estimateSize(); - var available = this._getUnspentValue(); - return Transaction._estimateFee(estimatedSize, available, this._feePerKb); -}; - -Transaction.prototype._getUnspentValue = function() { - return this._getInputAmount() - this._getOutputAmount(); -}; - -Transaction.prototype._clearSignatures = function() { - _.each(this.inputs, function(input) { - input.clearSignatures(); - }); -}; - -Transaction._estimateFee = function(size, amountAvailable, feePerKb) { - var fee = Math.ceil(size / 1000) * (feePerKb || Transaction.FEE_PER_KB); - if (amountAvailable > fee) { - size += Transaction.CHANGE_OUTPUT_MAX_SIZE; - } - return Math.ceil(size / 1000) * (feePerKb || Transaction.FEE_PER_KB); -}; - -Transaction.prototype._estimateSize = function() { - var result = Transaction.MAXIMUM_EXTRA_SIZE; - _.each(this.inputs, function(input) { - result += input._estimateSize(); - }); - _.each(this.outputs, function(output) { - result += output.script.toBuffer().length + 9; - }); - return result; -}; - -Transaction.prototype._removeOutput = function(index) { - var output = this.outputs[index]; - this.outputs = _.without(this.outputs, output); - this._outputAmount = undefined; -}; - -Transaction.prototype.removeOutput = function(index) { - this._removeOutput(index); - this._updateChangeOutput(); -}; - -/** - * Sort a transaction's inputs and outputs according to BIP69 - * - * @see {https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki} - * @return {Transaction} this - */ -Transaction.prototype.sort = function() { - this.sortInputs(function(inputs) { - var copy = Array.prototype.concat.apply([], inputs); - copy.sort(function(first, second) { - return compare(first.prevTxId, second.prevTxId) - || first.outputIndex - second.outputIndex; - }); - return copy; - }); - this.sortOutputs(function(outputs) { - var copy = Array.prototype.concat.apply([], outputs); - copy.sort(function(first, second) { - return first.micros - second.micros - || compare(first.script.toBuffer(), second.script.toBuffer()); - }); - return copy; - }); - return this; -}; - -/** - * Randomize this transaction's outputs ordering. The shuffling algorithm is a - * version of the Fisher-Yates shuffle, provided by lodash's _.shuffle(). - * - * @return {Transaction} this - */ -Transaction.prototype.shuffleOutputs = function() { - return this.sortOutputs(_.shuffle); -}; - -/** - * Sort this transaction's outputs, according to a given sorting function that - * takes an array as argument and returns a new array, with the same elements - * but with a different order. The argument function MUST NOT modify the order - * of the original array - * - * @param {Function} sortingFunction - * @return {Transaction} this - */ -Transaction.prototype.sortOutputs = function(sortingFunction) { - var outs = sortingFunction(this.outputs); - return this._newOutputOrder(outs); -}; - -/** - * Sort this transaction's inputs, according to a given sorting function that - * takes an array as argument and returns a new array, with the same elements - * but with a different order. - * - * @param {Function} sortingFunction - * @return {Transaction} this - */ -Transaction.prototype.sortInputs = function(sortingFunction) { - this.inputs = sortingFunction(this.inputs); - this._clearSignatures(); - return this; -}; - -Transaction.prototype._newOutputOrder = function(newOutputs) { - var isInvalidSorting = (this.outputs.length !== newOutputs.length || - _.difference(this.outputs, newOutputs).length !== 0); - if (isInvalidSorting) { - throw new errors.Transaction.InvalidSorting(); - } + if (this !== a) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } - if (!_.isUndefined(this._changeIndex)) { - var changeOutput = this.outputs[this._changeIndex]; - this._changeIndex = _.findIndex(newOutputs, changeOutput); - } + this.length = a.length; - this.outputs = newOutputs; - return this; -}; - -Transaction.prototype.removeInput = function(txId, outputIndex) { - var index; - if (!outputIndex && _.isNumber(txId)) { - index = txId; - } else { - index = _.findIndex(this.inputs, function(input) { - return input.prevTxId.toString('hex') === txId && input.outputIndex === outputIndex; - }); - } - if (index < 0 || index >= this.inputs.length) { - throw new errors.Transaction.InvalidIndex(index, this.inputs.length); - } - var input = this.inputs[index]; - this.inputs = _.without(this.inputs, input); - this._inputAmount = undefined; - this._updateChangeOutput(); -}; + return this.strip(); + }; -/* Signature handling */ + BN.prototype.ixor = function ixor(num) { + assert((this.negative | num.negative) === 0); + return this.iuxor(num); + }; -/** - * Sign the transaction using one or more private keys. - * - * It tries to sign each input, verifying that the signature will be valid - * (matches a public key). - * - * @param {Array|String|PrivateKey} privateKey - * @param {number} sigtype - * @return {Transaction} this, for chaining - */ -Transaction.prototype.sign = function(privateKey, sigtype) { - $.checkState(this.hasAllUtxoInfo()); - var self = this; - if (_.isArray(privateKey)) { - _.each(privateKey, function(privateKey) { - self.sign(privateKey, sigtype); - }); - return this; - } - _.each(this.getSignatures(privateKey, sigtype), function(signature) { - self.applySignature(signature); - }); - return this; -}; - -Transaction.prototype.getSignatures = function(privKey, sigtype) { - privKey = new PrivateKey(privKey); - sigtype = sigtype || Signature.SIGHASH_ALL; - var transaction = this; - var results = []; - var hashData = Hash.sha256ripemd160(privKey.publicKey.toBuffer()); - _.each(this.inputs, function forEachInput(input, index) { - _.each(input.getSignatures(transaction, privKey, index, sigtype, hashData), function(signature) { - results.push(signature); - }); - }); - return results; -}; - -/** - * Add a signature to the transaction - * - * @param {Object} signature - * @param {number} signature.inputIndex - * @param {number} signature.sigtype - * @param {PublicKey} signature.publicKey - * @param {Signature} signature.signature - * @return {Transaction} this, for chaining - */ -Transaction.prototype.applySignature = function(signature) { - this.inputs[signature.inputIndex].addSignature(this, signature); - return this; -}; - -Transaction.prototype.isFullySigned = function() { - _.each(this.inputs, function(input) { - if (input.isFullySigned === Input.prototype.isFullySigned) { - throw new errors.Transaction.UnableToVerifySignature( - 'Unrecognized script kind, or not enough information to execute script.' + - 'This usually happens when creating a transaction from a serialized transaction' - ); - } - }); - return _.every(_.map(this.inputs, function(input) { - return input.isFullySigned(); - })); -}; - -Transaction.prototype.isValidSignature = function(signature) { - var self = this; - if (this.inputs[signature.inputIndex].isValidSignature === Input.prototype.isValidSignature) { - throw new errors.Transaction.UnableToVerifySignature( - 'Unrecognized script kind, or not enough information to execute script.' + - 'This usually happens when creating a transaction from a serialized transaction' - ); - } - return this.inputs[signature.inputIndex].isValidSignature(self, signature); -}; + // Xor `num` with `this` + BN.prototype.xor = function xor(num) { + if (this.length > num.length) return this.clone().ixor(num); + return num.clone().ixor(this); + }; -/** - * @returns {bool} whether the signature is valid for this transaction input - */ -Transaction.prototype.verifySignature = function(sig, pubkey, nin, subscript) { - return Sighash.verify(this, sig, pubkey, nin, subscript); -}; - -/** - * Check that a transaction passes basic sanity tests. If not, return a string - * describing the error. This function contains the same logic as - * CheckTransaction in Merit core. - */ -Transaction.prototype.verify = function() { - // Basic checks that don't depend on any context - if (this.inputs.length === 0) { - return 'transaction txins empty'; - } + BN.prototype.uxor = function uxor(num) { + if (this.length > num.length) return this.clone().iuxor(num); + return num.clone().iuxor(this); + }; - if (this.outputs.length === 0) { - return 'transaction txouts empty'; - } + // Not ``this`` with ``width`` bitwidth + BN.prototype.inotn = function inotn(width) { + assert(typeof width === 'number' && width >= 0); - // Check for negative or overflow output values - var valueoutbn = new BN(0); - for (var i = 0; i < this.outputs.length; i++) { - var txout = this.outputs[i]; + var bytesNeeded = Math.ceil(width / 26) | 0; + var bitsLeft = width % 26; - if (txout.invalidMicros()) { - return 'transaction txout ' + i + ' micros is invalid'; - } - if (txout._microsBN.gt(new BN(Transaction.MAX_MONEY, 10))) { - return 'transaction txout ' + i + ' greater than MAX_MONEY'; - } - valueoutbn = valueoutbn.add(txout._microsBN); - if (valueoutbn.gt(new BN(Transaction.MAX_MONEY))) { - return 'transaction txout ' + i + ' total output greater than MAX_MONEY'; - } - } + // Extend the buffer with leading zeroes + this._expand(bytesNeeded); - // Size limits - if (this.toBuffer().length > MAX_BLOCK_SIZE) { - return 'transaction over the maximum block size'; - } + if (bitsLeft > 0) { + bytesNeeded--; + } - // Check for duplicate inputs - var txinmap = {}; - for (i = 0; i < this.inputs.length; i++) { - var txin = this.inputs[i]; + // Handle complete words + for (var i = 0; i < bytesNeeded; i++) { + this.words[i] = ~this.words[i] & 0x3ffffff; + } - var inputid = txin.prevTxId + ':' + txin.outputIndex; - if (!_.isUndefined(txinmap[inputid])) { - return 'transaction input ' + i + ' duplicate input'; - } - txinmap[inputid] = true; - } + // Handle the residue + if (bitsLeft > 0) { + this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft)); + } - var isCoinbase = this.isCoinbase(); - if (isCoinbase) { - var buf = this.inputs[0]._scriptBuffer; - if (buf.length < 2 || buf.length > 100) { - return 'coinbase transaction script size invalid'; - } - } else { - for (i = 0; i < this.inputs.length; i++) { - if (this.inputs[i].isNull()) { - return 'transaction input ' + i + ' has null input'; - } - } - } - return true; -}; + // And remove leading zeroes + return this.strip(); + }; -/** - * Analogous to bitcoind's IsCoinBase function in transaction.h - */ -Transaction.prototype.isCoinbase = function() { - return (this.inputs.length === 1 && this.inputs[0].isNull()); -}; + BN.prototype.notn = function notn(width) { + return this.clone().inotn(width); + }; -/** - * Determines if this transaction can be replaced in the mempool with another - * transaction that provides a sufficiently higher fee (RBF). - */ -Transaction.prototype.isRBF = function() { - for (var i = 0; i < this.inputs.length; i++) { - var input = this.inputs[i]; - if (input.sequenceNumber < Input.MAXINT - 1) { - return true; - } - } - return false; -}; - -/** - * Enable this transaction to be replaced in the mempool (RBF) if a transaction - * includes a sufficiently higher fee. It will set the sequenceNumber to - * DEFAULT_RBF_SEQNUMBER for all inputs if the sequence number does not - * already enable RBF. - */ -Transaction.prototype.enableRBF = function() { - for (var i = 0; i < this.inputs.length; i++) { - var input = this.inputs[i]; - if (input.sequenceNumber >= Input.MAXINT - 1) { - input.sequenceNumber = Input.DEFAULT_RBF_SEQNUMBER; - } - } - return this; -}; + // Set `bit` of `this` + BN.prototype.setn = function setn(bit, val) { + assert(typeof bit === 'number' && bit >= 0); + + var off = (bit / 26) | 0; + var wbit = bit % 26; + + this._expand(off + 1); + + if (val) { + this.words[off] = this.words[off] | (1 << wbit); + } else { + this.words[off] = this.words[off] & ~(1 << wbit); + } -module.exports = Transaction; + return this.strip(); + }; + + // Add `num` to `this` in-place + BN.prototype.iadd = function iadd(num) { + var r; + + // negative + positive + if (this.negative !== 0 && num.negative === 0) { + this.negative = 0; + r = this.isub(num); + this.negative ^= 1; + return this._normSign(); + + // positive + negative + } else if (this.negative === 0 && num.negative !== 0) { + num.negative = 0; + r = this.isub(num); + num.negative = 1; + return r._normSign(); + } -}).call(this,require("buffer").Buffer) -},{"../address":1,"../crypto/bn":6,"../crypto/hash":8,"../crypto/signature":11,"../encoding/bufferreader":14,"../encoding/bufferwriter":15,"../errors":17,"../privatekey":23,"../script":25,"../util/buffer":42,"../util/js":43,"../util/preconditions":44,"./input":29,"./output":35,"./sighash":36,"./unspentoutput":39,"buffer":113,"buffer-compare":111,"lodash":187}],39:[function(require,module,exports){ -'use strict'; + // a.length > b.length + var a, b; + if (this.length > num.length) { + a = this; + b = num; + } else { + a = num; + b = this; + } -var _ = require('lodash'); -var $ = require('../util/preconditions'); -var JSUtil = require('../util/js'); + var carry = 0; + for (var i = 0; i < b.length; i++) { + r = (a.words[i] | 0) + (b.words[i] | 0) + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; + } + for (; carry !== 0 && i < a.length; i++) { + r = (a.words[i] | 0) + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; + } -var Script = require('../script'); -var Address = require('../address'); -var Unit = require('../unit'); + this.length = a.length; + if (carry !== 0) { + this.words[this.length] = carry; + this.length++; + // Copy the rest of the words + } else if (a !== this) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } -/** - * Represents an unspent output information: its script, associated amount and address, - * transaction id and output index. - * - * @constructor - * @param {object} data - * @param {string} data.txid the previous transaction id - * @param {string=} data.txId alias for `txid` - * @param {number} data.vout the index in the transaction - * @param {number=} data.outputIndex alias for `vout` - * @param {string|Script} data.scriptPubKey the script that must be resolved to release the funds - * @param {string|Script=} data.script alias for `scriptPubKey` - * @param {number} data.amount amount of bitcoins associated - * @param {number=} data.micros alias for `amount`, but expressed in micros (1 MRT = 1e8 micros) - * @param {string|Address=} data.address the associated address to the script, if provided - */ -function UnspentOutput(data) { - /* jshint maxcomplexity: 20 */ - /* jshint maxstatements: 20 */ - if (!(this instanceof UnspentOutput)) { - return new UnspentOutput(data); - } - $.checkArgument(_.isObject(data), 'Must provide an object from where to extract data'); - var address = data.address ? new Address(data.address) : undefined; - var txId = data.txid ? data.txid : data.txId; - if (!txId || !JSUtil.isHexaString(txId) || txId.length > 64) { - // TODO: Use the errors library - throw new Error('Invalid TXID in object', data); - } - var outputIndex = _.isUndefined(data.vout) ? data.outputIndex : data.vout; - if (!_.isNumber(outputIndex)) { - throw new Error('Invalid outputIndex, received ' + outputIndex); - } - $.checkArgument(!_.isUndefined(data.scriptPubKey) || !_.isUndefined(data.script), - 'Must provide the scriptPubKey for that output!'); - var script = new Script(data.scriptPubKey || data.script); - $.checkArgument(!_.isUndefined(data.amount) || !_.isUndefined(data.micros), - 'Must provide an amount for the output'); - var amount = !_.isUndefined(data.amount) ? new Unit.fromMRT(data.amount).toMicros() : data.micros; - $.checkArgument(_.isNumber(amount), 'Amount must be a number'); - JSUtil.defineImmutable(this, { - address: address, - txId: txId, - outputIndex: outputIndex, - script: script, - micros: amount - }); -} + return this; + }; + + // Add `num` to `this` + BN.prototype.add = function add(num) { + var res; + if (num.negative !== 0 && this.negative === 0) { + num.negative = 0; + res = this.sub(num); + num.negative ^= 1; + return res; + } else if (num.negative === 0 && this.negative !== 0) { + this.negative = 0; + res = num.sub(this); + this.negative = 1; + return res; + } -/** - * Provide an informative output when displaying this object in the console - * @returns string - */ -UnspentOutput.prototype.inspect = function() { - return ''; -}; - -/** - * String representation: just "txid:index" - * @returns string - */ -UnspentOutput.prototype.toString = function() { - return this.txId + ':' + this.outputIndex; -}; - -/** - * Deserialize an UnspentOutput from an object - * @param {object|string} data - * @return UnspentOutput - */ -UnspentOutput.fromObject = function(data) { - return new UnspentOutput(data); -}; + if (this.length > num.length) return this.clone().iadd(num); + + return num.clone().iadd(this); + }; + + // Subtract `num` from `this` in-place + BN.prototype.isub = function isub(num) { + // this - (-num) = this + num + if (num.negative !== 0) { + num.negative = 0; + var r = this.iadd(num); + num.negative = 1; + return r._normSign(); + + // -this - num = -(this + num) + } else if (this.negative !== 0) { + this.negative = 0; + this.iadd(num); + this.negative = 1; + return this._normSign(); + } -/** - * Returns a plain object (no prototype or methods) with the associated info for this output - * @return {object} - */ -UnspentOutput.prototype.toObject = UnspentOutput.prototype.toJSON = function toObject() { - return { - address: this.address ? this.address.toString() : undefined, - txid: this.txId, - vout: this.outputIndex, - scriptPubKey: this.script.toBuffer().toString('hex'), - amount: Unit.fromMicros(this.micros).toMRT() - }; -}; - -module.exports = UnspentOutput; - -},{"../address":1,"../script":25,"../unit":40,"../util/js":43,"../util/preconditions":44,"lodash":187}],40:[function(require,module,exports){ -'use strict'; - -var _ = require('lodash'); - -var errors = require('./errors'); -var $ = require('./util/preconditions'); - -var UNITS = { - 'MRT' : [1e8, 8], - 'mMRT' : [1e5, 5], - 'uMRT' : [1e2, 2], - 'bits' : [1e2, 2], - 'micros' : [1, 0] -}; - -/** - * Utility for handling and converting bitcoins units. The supported units are - * MRT, mMRT, bits (also named uMRT) and micros. A unit instance can be created with an - * amount and a unit code, or alternatively using static methods like {fromMRT}. - * It also allows to be created from a fiat amount and the exchange rate, or - * alternatively using the {fromFiat} static method. - * You can consult for different representation of a unit instance using it's - * {to} method, the fixed unit methods like {toMicros} or alternatively using - * the unit accessors. It also can be converted to a fiat amount by providing the - * corresponding MRT/fiat exchange rate. - * - * @example - * ```javascript - * var micros = Unit.fromMRT(1.3).toMicros(); - * var mili = Unit.fromBits(1.3).to(Unit.mMRT); - * var bits = Unit.fromFiat(1.3, 350).bits; - * var mrt = new Unit(1.3, Unit.bits).MRT; - * ``` - * - * @param {Number} amount - The amount to be represented - * @param {String|Number} code - The unit of the amount or the exchange rate - * @returns {Unit} A new instance of an Unit - * @constructor - */ -function Unit(amount, code) { - if (!(this instanceof Unit)) { - return new Unit(amount, code); - } + // At this point both numbers are positive + var cmp = this.cmp(num); - // convert fiat to MRT - if (_.isNumber(code)) { - if (code <= 0) { - throw new errors.Unit.InvalidRate(code); - } - amount = amount / code; - code = Unit.MRT; - } + // Optimization - zeroify + if (cmp === 0) { + this.negative = 0; + this.length = 1; + this.words[0] = 0; + return this; + } - this._value = this._from(amount, code); + // a > b + var a, b; + if (cmp > 0) { + a = this; + b = num; + } else { + a = num; + b = this; + } - var self = this; - var defineAccesor = function(key) { - Object.defineProperty(self, key, { - get: function() { return self.to(key); }, - enumerable: true, - }); - }; + var carry = 0; + for (var i = 0; i < b.length; i++) { + r = (a.words[i] | 0) - (b.words[i] | 0) + carry; + carry = r >> 26; + this.words[i] = r & 0x3ffffff; + } + for (; carry !== 0 && i < a.length; i++) { + r = (a.words[i] | 0) + carry; + carry = r >> 26; + this.words[i] = r & 0x3ffffff; + } - Object.keys(UNITS).forEach(defineAccesor); -} + // Copy rest of the words + if (carry === 0 && i < a.length && a !== this) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } -Object.keys(UNITS).forEach(function(key) { - Unit[key] = key; -}); + this.length = Math.max(this.length, i); -/** - * Returns a Unit instance created from JSON string or object - * - * @param {String|Object} json - JSON with keys: amount and code - * @returns {Unit} A Unit instance - */ -Unit.fromObject = function fromObject(data){ - $.checkArgument(_.isObject(data), 'Argument is expected to be an object'); - return new Unit(data.amount, data.code); -}; + if (a !== this) { + this.negative = 1; + } -/** - * Returns a Unit instance created from an amount in MRT - * - * @param {Number} amount - The amount in MRT - * @returns {Unit} A Unit instance - */ -Unit.fromMRT = function(amount) { - return new Unit(amount, Unit.MRT); -}; + return this.strip(); + }; + + // Subtract `num` from `this` + BN.prototype.sub = function sub(num) { + return this.clone().isub(num); + }; + + function smallMulTo(self, num, out) { + out.negative = num.negative ^ self.negative; + var len = (self.length + num.length) | 0; + out.length = len; + len = (len - 1) | 0; + + // Peel one iteration (compiler can't do it, because of code complexity) + var a = self.words[0] | 0; + var b = num.words[0] | 0; + var r = a * b; + + var lo = r & 0x3ffffff; + var carry = (r / 0x4000000) | 0; + out.words[0] = lo; + + for (var k = 1; k < len; k++) { + // Sum all words with the same `i + j = k` and accumulate `ncarry`, + // note that ncarry could be >= 0x3ffffff + var ncarry = carry >>> 26; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { + var i = (k - j) | 0; + a = self.words[i] | 0; + b = num.words[j] | 0; + r = a * b + rword; + ncarry += (r / 0x4000000) | 0; + rword = r & 0x3ffffff; + } + out.words[k] = rword | 0; + carry = ncarry | 0; + } + if (carry !== 0) { + out.words[k] = carry | 0; + } else { + out.length--; + } -/** - * Returns a Unit instance created from an amount in mMRT - * - * @param {Number} amount - The amount in mMRT - * @returns {Unit} A Unit instance - */ -Unit.fromMillis = Unit.fromMilis = function(amount) { - return new Unit(amount, Unit.mMRT); -}; + return out.strip(); + } -/** - * Returns a Unit instance created from an amount in bits - * - * @param {Number} amount - The amount in bits - * @returns {Unit} A Unit instance - */ -Unit.fromMicros = Unit.fromBits = function(amount) { - return new Unit(amount, Unit.bits); -}; + // TODO(indutny): it may be reasonable to omit it for users who don't need + // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit + // multiplication (like elliptic secp256k1). + var comb10MulTo = function comb10MulTo(self, num, out) { + var a = self.words; + var b = num.words; + var o = out.words; + var c = 0; + var lo; + var mid; + var hi; + var a0 = a[0] | 0; + var al0 = a0 & 0x1fff; + var ah0 = a0 >>> 13; + var a1 = a[1] | 0; + var al1 = a1 & 0x1fff; + var ah1 = a1 >>> 13; + var a2 = a[2] | 0; + var al2 = a2 & 0x1fff; + var ah2 = a2 >>> 13; + var a3 = a[3] | 0; + var al3 = a3 & 0x1fff; + var ah3 = a3 >>> 13; + var a4 = a[4] | 0; + var al4 = a4 & 0x1fff; + var ah4 = a4 >>> 13; + var a5 = a[5] | 0; + var al5 = a5 & 0x1fff; + var ah5 = a5 >>> 13; + var a6 = a[6] | 0; + var al6 = a6 & 0x1fff; + var ah6 = a6 >>> 13; + var a7 = a[7] | 0; + var al7 = a7 & 0x1fff; + var ah7 = a7 >>> 13; + var a8 = a[8] | 0; + var al8 = a8 & 0x1fff; + var ah8 = a8 >>> 13; + var a9 = a[9] | 0; + var al9 = a9 & 0x1fff; + var ah9 = a9 >>> 13; + var b0 = b[0] | 0; + var bl0 = b0 & 0x1fff; + var bh0 = b0 >>> 13; + var b1 = b[1] | 0; + var bl1 = b1 & 0x1fff; + var bh1 = b1 >>> 13; + var b2 = b[2] | 0; + var bl2 = b2 & 0x1fff; + var bh2 = b2 >>> 13; + var b3 = b[3] | 0; + var bl3 = b3 & 0x1fff; + var bh3 = b3 >>> 13; + var b4 = b[4] | 0; + var bl4 = b4 & 0x1fff; + var bh4 = b4 >>> 13; + var b5 = b[5] | 0; + var bl5 = b5 & 0x1fff; + var bh5 = b5 >>> 13; + var b6 = b[6] | 0; + var bl6 = b6 & 0x1fff; + var bh6 = b6 >>> 13; + var b7 = b[7] | 0; + var bl7 = b7 & 0x1fff; + var bh7 = b7 >>> 13; + var b8 = b[8] | 0; + var bl8 = b8 & 0x1fff; + var bh8 = b8 >>> 13; + var b9 = b[9] | 0; + var bl9 = b9 & 0x1fff; + var bh9 = b9 >>> 13; + + out.negative = self.negative ^ num.negative; + out.length = 19; + /* k = 0 */ + lo = Math.imul(al0, bl0); + mid = Math.imul(al0, bh0); + mid = (mid + Math.imul(ah0, bl0)) | 0; + hi = Math.imul(ah0, bh0); + var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0; + w0 &= 0x3ffffff; + /* k = 1 */ + lo = Math.imul(al1, bl0); + mid = Math.imul(al1, bh0); + mid = (mid + Math.imul(ah1, bl0)) | 0; + hi = Math.imul(ah1, bh0); + lo = (lo + Math.imul(al0, bl1)) | 0; + mid = (mid + Math.imul(al0, bh1)) | 0; + mid = (mid + Math.imul(ah0, bl1)) | 0; + hi = (hi + Math.imul(ah0, bh1)) | 0; + var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0; + w1 &= 0x3ffffff; + /* k = 2 */ + lo = Math.imul(al2, bl0); + mid = Math.imul(al2, bh0); + mid = (mid + Math.imul(ah2, bl0)) | 0; + hi = Math.imul(ah2, bh0); + lo = (lo + Math.imul(al1, bl1)) | 0; + mid = (mid + Math.imul(al1, bh1)) | 0; + mid = (mid + Math.imul(ah1, bl1)) | 0; + hi = (hi + Math.imul(ah1, bh1)) | 0; + lo = (lo + Math.imul(al0, bl2)) | 0; + mid = (mid + Math.imul(al0, bh2)) | 0; + mid = (mid + Math.imul(ah0, bl2)) | 0; + hi = (hi + Math.imul(ah0, bh2)) | 0; + var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0; + w2 &= 0x3ffffff; + /* k = 3 */ + lo = Math.imul(al3, bl0); + mid = Math.imul(al3, bh0); + mid = (mid + Math.imul(ah3, bl0)) | 0; + hi = Math.imul(ah3, bh0); + lo = (lo + Math.imul(al2, bl1)) | 0; + mid = (mid + Math.imul(al2, bh1)) | 0; + mid = (mid + Math.imul(ah2, bl1)) | 0; + hi = (hi + Math.imul(ah2, bh1)) | 0; + lo = (lo + Math.imul(al1, bl2)) | 0; + mid = (mid + Math.imul(al1, bh2)) | 0; + mid = (mid + Math.imul(ah1, bl2)) | 0; + hi = (hi + Math.imul(ah1, bh2)) | 0; + lo = (lo + Math.imul(al0, bl3)) | 0; + mid = (mid + Math.imul(al0, bh3)) | 0; + mid = (mid + Math.imul(ah0, bl3)) | 0; + hi = (hi + Math.imul(ah0, bh3)) | 0; + var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0; + w3 &= 0x3ffffff; + /* k = 4 */ + lo = Math.imul(al4, bl0); + mid = Math.imul(al4, bh0); + mid = (mid + Math.imul(ah4, bl0)) | 0; + hi = Math.imul(ah4, bh0); + lo = (lo + Math.imul(al3, bl1)) | 0; + mid = (mid + Math.imul(al3, bh1)) | 0; + mid = (mid + Math.imul(ah3, bl1)) | 0; + hi = (hi + Math.imul(ah3, bh1)) | 0; + lo = (lo + Math.imul(al2, bl2)) | 0; + mid = (mid + Math.imul(al2, bh2)) | 0; + mid = (mid + Math.imul(ah2, bl2)) | 0; + hi = (hi + Math.imul(ah2, bh2)) | 0; + lo = (lo + Math.imul(al1, bl3)) | 0; + mid = (mid + Math.imul(al1, bh3)) | 0; + mid = (mid + Math.imul(ah1, bl3)) | 0; + hi = (hi + Math.imul(ah1, bh3)) | 0; + lo = (lo + Math.imul(al0, bl4)) | 0; + mid = (mid + Math.imul(al0, bh4)) | 0; + mid = (mid + Math.imul(ah0, bl4)) | 0; + hi = (hi + Math.imul(ah0, bh4)) | 0; + var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0; + w4 &= 0x3ffffff; + /* k = 5 */ + lo = Math.imul(al5, bl0); + mid = Math.imul(al5, bh0); + mid = (mid + Math.imul(ah5, bl0)) | 0; + hi = Math.imul(ah5, bh0); + lo = (lo + Math.imul(al4, bl1)) | 0; + mid = (mid + Math.imul(al4, bh1)) | 0; + mid = (mid + Math.imul(ah4, bl1)) | 0; + hi = (hi + Math.imul(ah4, bh1)) | 0; + lo = (lo + Math.imul(al3, bl2)) | 0; + mid = (mid + Math.imul(al3, bh2)) | 0; + mid = (mid + Math.imul(ah3, bl2)) | 0; + hi = (hi + Math.imul(ah3, bh2)) | 0; + lo = (lo + Math.imul(al2, bl3)) | 0; + mid = (mid + Math.imul(al2, bh3)) | 0; + mid = (mid + Math.imul(ah2, bl3)) | 0; + hi = (hi + Math.imul(ah2, bh3)) | 0; + lo = (lo + Math.imul(al1, bl4)) | 0; + mid = (mid + Math.imul(al1, bh4)) | 0; + mid = (mid + Math.imul(ah1, bl4)) | 0; + hi = (hi + Math.imul(ah1, bh4)) | 0; + lo = (lo + Math.imul(al0, bl5)) | 0; + mid = (mid + Math.imul(al0, bh5)) | 0; + mid = (mid + Math.imul(ah0, bl5)) | 0; + hi = (hi + Math.imul(ah0, bh5)) | 0; + var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0; + w5 &= 0x3ffffff; + /* k = 6 */ + lo = Math.imul(al6, bl0); + mid = Math.imul(al6, bh0); + mid = (mid + Math.imul(ah6, bl0)) | 0; + hi = Math.imul(ah6, bh0); + lo = (lo + Math.imul(al5, bl1)) | 0; + mid = (mid + Math.imul(al5, bh1)) | 0; + mid = (mid + Math.imul(ah5, bl1)) | 0; + hi = (hi + Math.imul(ah5, bh1)) | 0; + lo = (lo + Math.imul(al4, bl2)) | 0; + mid = (mid + Math.imul(al4, bh2)) | 0; + mid = (mid + Math.imul(ah4, bl2)) | 0; + hi = (hi + Math.imul(ah4, bh2)) | 0; + lo = (lo + Math.imul(al3, bl3)) | 0; + mid = (mid + Math.imul(al3, bh3)) | 0; + mid = (mid + Math.imul(ah3, bl3)) | 0; + hi = (hi + Math.imul(ah3, bh3)) | 0; + lo = (lo + Math.imul(al2, bl4)) | 0; + mid = (mid + Math.imul(al2, bh4)) | 0; + mid = (mid + Math.imul(ah2, bl4)) | 0; + hi = (hi + Math.imul(ah2, bh4)) | 0; + lo = (lo + Math.imul(al1, bl5)) | 0; + mid = (mid + Math.imul(al1, bh5)) | 0; + mid = (mid + Math.imul(ah1, bl5)) | 0; + hi = (hi + Math.imul(ah1, bh5)) | 0; + lo = (lo + Math.imul(al0, bl6)) | 0; + mid = (mid + Math.imul(al0, bh6)) | 0; + mid = (mid + Math.imul(ah0, bl6)) | 0; + hi = (hi + Math.imul(ah0, bh6)) | 0; + var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0; + w6 &= 0x3ffffff; + /* k = 7 */ + lo = Math.imul(al7, bl0); + mid = Math.imul(al7, bh0); + mid = (mid + Math.imul(ah7, bl0)) | 0; + hi = Math.imul(ah7, bh0); + lo = (lo + Math.imul(al6, bl1)) | 0; + mid = (mid + Math.imul(al6, bh1)) | 0; + mid = (mid + Math.imul(ah6, bl1)) | 0; + hi = (hi + Math.imul(ah6, bh1)) | 0; + lo = (lo + Math.imul(al5, bl2)) | 0; + mid = (mid + Math.imul(al5, bh2)) | 0; + mid = (mid + Math.imul(ah5, bl2)) | 0; + hi = (hi + Math.imul(ah5, bh2)) | 0; + lo = (lo + Math.imul(al4, bl3)) | 0; + mid = (mid + Math.imul(al4, bh3)) | 0; + mid = (mid + Math.imul(ah4, bl3)) | 0; + hi = (hi + Math.imul(ah4, bh3)) | 0; + lo = (lo + Math.imul(al3, bl4)) | 0; + mid = (mid + Math.imul(al3, bh4)) | 0; + mid = (mid + Math.imul(ah3, bl4)) | 0; + hi = (hi + Math.imul(ah3, bh4)) | 0; + lo = (lo + Math.imul(al2, bl5)) | 0; + mid = (mid + Math.imul(al2, bh5)) | 0; + mid = (mid + Math.imul(ah2, bl5)) | 0; + hi = (hi + Math.imul(ah2, bh5)) | 0; + lo = (lo + Math.imul(al1, bl6)) | 0; + mid = (mid + Math.imul(al1, bh6)) | 0; + mid = (mid + Math.imul(ah1, bl6)) | 0; + hi = (hi + Math.imul(ah1, bh6)) | 0; + lo = (lo + Math.imul(al0, bl7)) | 0; + mid = (mid + Math.imul(al0, bh7)) | 0; + mid = (mid + Math.imul(ah0, bl7)) | 0; + hi = (hi + Math.imul(ah0, bh7)) | 0; + var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0; + w7 &= 0x3ffffff; + /* k = 8 */ + lo = Math.imul(al8, bl0); + mid = Math.imul(al8, bh0); + mid = (mid + Math.imul(ah8, bl0)) | 0; + hi = Math.imul(ah8, bh0); + lo = (lo + Math.imul(al7, bl1)) | 0; + mid = (mid + Math.imul(al7, bh1)) | 0; + mid = (mid + Math.imul(ah7, bl1)) | 0; + hi = (hi + Math.imul(ah7, bh1)) | 0; + lo = (lo + Math.imul(al6, bl2)) | 0; + mid = (mid + Math.imul(al6, bh2)) | 0; + mid = (mid + Math.imul(ah6, bl2)) | 0; + hi = (hi + Math.imul(ah6, bh2)) | 0; + lo = (lo + Math.imul(al5, bl3)) | 0; + mid = (mid + Math.imul(al5, bh3)) | 0; + mid = (mid + Math.imul(ah5, bl3)) | 0; + hi = (hi + Math.imul(ah5, bh3)) | 0; + lo = (lo + Math.imul(al4, bl4)) | 0; + mid = (mid + Math.imul(al4, bh4)) | 0; + mid = (mid + Math.imul(ah4, bl4)) | 0; + hi = (hi + Math.imul(ah4, bh4)) | 0; + lo = (lo + Math.imul(al3, bl5)) | 0; + mid = (mid + Math.imul(al3, bh5)) | 0; + mid = (mid + Math.imul(ah3, bl5)) | 0; + hi = (hi + Math.imul(ah3, bh5)) | 0; + lo = (lo + Math.imul(al2, bl6)) | 0; + mid = (mid + Math.imul(al2, bh6)) | 0; + mid = (mid + Math.imul(ah2, bl6)) | 0; + hi = (hi + Math.imul(ah2, bh6)) | 0; + lo = (lo + Math.imul(al1, bl7)) | 0; + mid = (mid + Math.imul(al1, bh7)) | 0; + mid = (mid + Math.imul(ah1, bl7)) | 0; + hi = (hi + Math.imul(ah1, bh7)) | 0; + lo = (lo + Math.imul(al0, bl8)) | 0; + mid = (mid + Math.imul(al0, bh8)) | 0; + mid = (mid + Math.imul(ah0, bl8)) | 0; + hi = (hi + Math.imul(ah0, bh8)) | 0; + var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0; + w8 &= 0x3ffffff; + /* k = 9 */ + lo = Math.imul(al9, bl0); + mid = Math.imul(al9, bh0); + mid = (mid + Math.imul(ah9, bl0)) | 0; + hi = Math.imul(ah9, bh0); + lo = (lo + Math.imul(al8, bl1)) | 0; + mid = (mid + Math.imul(al8, bh1)) | 0; + mid = (mid + Math.imul(ah8, bl1)) | 0; + hi = (hi + Math.imul(ah8, bh1)) | 0; + lo = (lo + Math.imul(al7, bl2)) | 0; + mid = (mid + Math.imul(al7, bh2)) | 0; + mid = (mid + Math.imul(ah7, bl2)) | 0; + hi = (hi + Math.imul(ah7, bh2)) | 0; + lo = (lo + Math.imul(al6, bl3)) | 0; + mid = (mid + Math.imul(al6, bh3)) | 0; + mid = (mid + Math.imul(ah6, bl3)) | 0; + hi = (hi + Math.imul(ah6, bh3)) | 0; + lo = (lo + Math.imul(al5, bl4)) | 0; + mid = (mid + Math.imul(al5, bh4)) | 0; + mid = (mid + Math.imul(ah5, bl4)) | 0; + hi = (hi + Math.imul(ah5, bh4)) | 0; + lo = (lo + Math.imul(al4, bl5)) | 0; + mid = (mid + Math.imul(al4, bh5)) | 0; + mid = (mid + Math.imul(ah4, bl5)) | 0; + hi = (hi + Math.imul(ah4, bh5)) | 0; + lo = (lo + Math.imul(al3, bl6)) | 0; + mid = (mid + Math.imul(al3, bh6)) | 0; + mid = (mid + Math.imul(ah3, bl6)) | 0; + hi = (hi + Math.imul(ah3, bh6)) | 0; + lo = (lo + Math.imul(al2, bl7)) | 0; + mid = (mid + Math.imul(al2, bh7)) | 0; + mid = (mid + Math.imul(ah2, bl7)) | 0; + hi = (hi + Math.imul(ah2, bh7)) | 0; + lo = (lo + Math.imul(al1, bl8)) | 0; + mid = (mid + Math.imul(al1, bh8)) | 0; + mid = (mid + Math.imul(ah1, bl8)) | 0; + hi = (hi + Math.imul(ah1, bh8)) | 0; + lo = (lo + Math.imul(al0, bl9)) | 0; + mid = (mid + Math.imul(al0, bh9)) | 0; + mid = (mid + Math.imul(ah0, bl9)) | 0; + hi = (hi + Math.imul(ah0, bh9)) | 0; + var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0; + w9 &= 0x3ffffff; + /* k = 10 */ + lo = Math.imul(al9, bl1); + mid = Math.imul(al9, bh1); + mid = (mid + Math.imul(ah9, bl1)) | 0; + hi = Math.imul(ah9, bh1); + lo = (lo + Math.imul(al8, bl2)) | 0; + mid = (mid + Math.imul(al8, bh2)) | 0; + mid = (mid + Math.imul(ah8, bl2)) | 0; + hi = (hi + Math.imul(ah8, bh2)) | 0; + lo = (lo + Math.imul(al7, bl3)) | 0; + mid = (mid + Math.imul(al7, bh3)) | 0; + mid = (mid + Math.imul(ah7, bl3)) | 0; + hi = (hi + Math.imul(ah7, bh3)) | 0; + lo = (lo + Math.imul(al6, bl4)) | 0; + mid = (mid + Math.imul(al6, bh4)) | 0; + mid = (mid + Math.imul(ah6, bl4)) | 0; + hi = (hi + Math.imul(ah6, bh4)) | 0; + lo = (lo + Math.imul(al5, bl5)) | 0; + mid = (mid + Math.imul(al5, bh5)) | 0; + mid = (mid + Math.imul(ah5, bl5)) | 0; + hi = (hi + Math.imul(ah5, bh5)) | 0; + lo = (lo + Math.imul(al4, bl6)) | 0; + mid = (mid + Math.imul(al4, bh6)) | 0; + mid = (mid + Math.imul(ah4, bl6)) | 0; + hi = (hi + Math.imul(ah4, bh6)) | 0; + lo = (lo + Math.imul(al3, bl7)) | 0; + mid = (mid + Math.imul(al3, bh7)) | 0; + mid = (mid + Math.imul(ah3, bl7)) | 0; + hi = (hi + Math.imul(ah3, bh7)) | 0; + lo = (lo + Math.imul(al2, bl8)) | 0; + mid = (mid + Math.imul(al2, bh8)) | 0; + mid = (mid + Math.imul(ah2, bl8)) | 0; + hi = (hi + Math.imul(ah2, bh8)) | 0; + lo = (lo + Math.imul(al1, bl9)) | 0; + mid = (mid + Math.imul(al1, bh9)) | 0; + mid = (mid + Math.imul(ah1, bl9)) | 0; + hi = (hi + Math.imul(ah1, bh9)) | 0; + var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0; + w10 &= 0x3ffffff; + /* k = 11 */ + lo = Math.imul(al9, bl2); + mid = Math.imul(al9, bh2); + mid = (mid + Math.imul(ah9, bl2)) | 0; + hi = Math.imul(ah9, bh2); + lo = (lo + Math.imul(al8, bl3)) | 0; + mid = (mid + Math.imul(al8, bh3)) | 0; + mid = (mid + Math.imul(ah8, bl3)) | 0; + hi = (hi + Math.imul(ah8, bh3)) | 0; + lo = (lo + Math.imul(al7, bl4)) | 0; + mid = (mid + Math.imul(al7, bh4)) | 0; + mid = (mid + Math.imul(ah7, bl4)) | 0; + hi = (hi + Math.imul(ah7, bh4)) | 0; + lo = (lo + Math.imul(al6, bl5)) | 0; + mid = (mid + Math.imul(al6, bh5)) | 0; + mid = (mid + Math.imul(ah6, bl5)) | 0; + hi = (hi + Math.imul(ah6, bh5)) | 0; + lo = (lo + Math.imul(al5, bl6)) | 0; + mid = (mid + Math.imul(al5, bh6)) | 0; + mid = (mid + Math.imul(ah5, bl6)) | 0; + hi = (hi + Math.imul(ah5, bh6)) | 0; + lo = (lo + Math.imul(al4, bl7)) | 0; + mid = (mid + Math.imul(al4, bh7)) | 0; + mid = (mid + Math.imul(ah4, bl7)) | 0; + hi = (hi + Math.imul(ah4, bh7)) | 0; + lo = (lo + Math.imul(al3, bl8)) | 0; + mid = (mid + Math.imul(al3, bh8)) | 0; + mid = (mid + Math.imul(ah3, bl8)) | 0; + hi = (hi + Math.imul(ah3, bh8)) | 0; + lo = (lo + Math.imul(al2, bl9)) | 0; + mid = (mid + Math.imul(al2, bh9)) | 0; + mid = (mid + Math.imul(ah2, bl9)) | 0; + hi = (hi + Math.imul(ah2, bh9)) | 0; + var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0; + w11 &= 0x3ffffff; + /* k = 12 */ + lo = Math.imul(al9, bl3); + mid = Math.imul(al9, bh3); + mid = (mid + Math.imul(ah9, bl3)) | 0; + hi = Math.imul(ah9, bh3); + lo = (lo + Math.imul(al8, bl4)) | 0; + mid = (mid + Math.imul(al8, bh4)) | 0; + mid = (mid + Math.imul(ah8, bl4)) | 0; + hi = (hi + Math.imul(ah8, bh4)) | 0; + lo = (lo + Math.imul(al7, bl5)) | 0; + mid = (mid + Math.imul(al7, bh5)) | 0; + mid = (mid + Math.imul(ah7, bl5)) | 0; + hi = (hi + Math.imul(ah7, bh5)) | 0; + lo = (lo + Math.imul(al6, bl6)) | 0; + mid = (mid + Math.imul(al6, bh6)) | 0; + mid = (mid + Math.imul(ah6, bl6)) | 0; + hi = (hi + Math.imul(ah6, bh6)) | 0; + lo = (lo + Math.imul(al5, bl7)) | 0; + mid = (mid + Math.imul(al5, bh7)) | 0; + mid = (mid + Math.imul(ah5, bl7)) | 0; + hi = (hi + Math.imul(ah5, bh7)) | 0; + lo = (lo + Math.imul(al4, bl8)) | 0; + mid = (mid + Math.imul(al4, bh8)) | 0; + mid = (mid + Math.imul(ah4, bl8)) | 0; + hi = (hi + Math.imul(ah4, bh8)) | 0; + lo = (lo + Math.imul(al3, bl9)) | 0; + mid = (mid + Math.imul(al3, bh9)) | 0; + mid = (mid + Math.imul(ah3, bl9)) | 0; + hi = (hi + Math.imul(ah3, bh9)) | 0; + var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0; + w12 &= 0x3ffffff; + /* k = 13 */ + lo = Math.imul(al9, bl4); + mid = Math.imul(al9, bh4); + mid = (mid + Math.imul(ah9, bl4)) | 0; + hi = Math.imul(ah9, bh4); + lo = (lo + Math.imul(al8, bl5)) | 0; + mid = (mid + Math.imul(al8, bh5)) | 0; + mid = (mid + Math.imul(ah8, bl5)) | 0; + hi = (hi + Math.imul(ah8, bh5)) | 0; + lo = (lo + Math.imul(al7, bl6)) | 0; + mid = (mid + Math.imul(al7, bh6)) | 0; + mid = (mid + Math.imul(ah7, bl6)) | 0; + hi = (hi + Math.imul(ah7, bh6)) | 0; + lo = (lo + Math.imul(al6, bl7)) | 0; + mid = (mid + Math.imul(al6, bh7)) | 0; + mid = (mid + Math.imul(ah6, bl7)) | 0; + hi = (hi + Math.imul(ah6, bh7)) | 0; + lo = (lo + Math.imul(al5, bl8)) | 0; + mid = (mid + Math.imul(al5, bh8)) | 0; + mid = (mid + Math.imul(ah5, bl8)) | 0; + hi = (hi + Math.imul(ah5, bh8)) | 0; + lo = (lo + Math.imul(al4, bl9)) | 0; + mid = (mid + Math.imul(al4, bh9)) | 0; + mid = (mid + Math.imul(ah4, bl9)) | 0; + hi = (hi + Math.imul(ah4, bh9)) | 0; + var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0; + w13 &= 0x3ffffff; + /* k = 14 */ + lo = Math.imul(al9, bl5); + mid = Math.imul(al9, bh5); + mid = (mid + Math.imul(ah9, bl5)) | 0; + hi = Math.imul(ah9, bh5); + lo = (lo + Math.imul(al8, bl6)) | 0; + mid = (mid + Math.imul(al8, bh6)) | 0; + mid = (mid + Math.imul(ah8, bl6)) | 0; + hi = (hi + Math.imul(ah8, bh6)) | 0; + lo = (lo + Math.imul(al7, bl7)) | 0; + mid = (mid + Math.imul(al7, bh7)) | 0; + mid = (mid + Math.imul(ah7, bl7)) | 0; + hi = (hi + Math.imul(ah7, bh7)) | 0; + lo = (lo + Math.imul(al6, bl8)) | 0; + mid = (mid + Math.imul(al6, bh8)) | 0; + mid = (mid + Math.imul(ah6, bl8)) | 0; + hi = (hi + Math.imul(ah6, bh8)) | 0; + lo = (lo + Math.imul(al5, bl9)) | 0; + mid = (mid + Math.imul(al5, bh9)) | 0; + mid = (mid + Math.imul(ah5, bl9)) | 0; + hi = (hi + Math.imul(ah5, bh9)) | 0; + var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0; + w14 &= 0x3ffffff; + /* k = 15 */ + lo = Math.imul(al9, bl6); + mid = Math.imul(al9, bh6); + mid = (mid + Math.imul(ah9, bl6)) | 0; + hi = Math.imul(ah9, bh6); + lo = (lo + Math.imul(al8, bl7)) | 0; + mid = (mid + Math.imul(al8, bh7)) | 0; + mid = (mid + Math.imul(ah8, bl7)) | 0; + hi = (hi + Math.imul(ah8, bh7)) | 0; + lo = (lo + Math.imul(al7, bl8)) | 0; + mid = (mid + Math.imul(al7, bh8)) | 0; + mid = (mid + Math.imul(ah7, bl8)) | 0; + hi = (hi + Math.imul(ah7, bh8)) | 0; + lo = (lo + Math.imul(al6, bl9)) | 0; + mid = (mid + Math.imul(al6, bh9)) | 0; + mid = (mid + Math.imul(ah6, bl9)) | 0; + hi = (hi + Math.imul(ah6, bh9)) | 0; + var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0; + w15 &= 0x3ffffff; + /* k = 16 */ + lo = Math.imul(al9, bl7); + mid = Math.imul(al9, bh7); + mid = (mid + Math.imul(ah9, bl7)) | 0; + hi = Math.imul(ah9, bh7); + lo = (lo + Math.imul(al8, bl8)) | 0; + mid = (mid + Math.imul(al8, bh8)) | 0; + mid = (mid + Math.imul(ah8, bl8)) | 0; + hi = (hi + Math.imul(ah8, bh8)) | 0; + lo = (lo + Math.imul(al7, bl9)) | 0; + mid = (mid + Math.imul(al7, bh9)) | 0; + mid = (mid + Math.imul(ah7, bl9)) | 0; + hi = (hi + Math.imul(ah7, bh9)) | 0; + var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0; + w16 &= 0x3ffffff; + /* k = 17 */ + lo = Math.imul(al9, bl8); + mid = Math.imul(al9, bh8); + mid = (mid + Math.imul(ah9, bl8)) | 0; + hi = Math.imul(ah9, bh8); + lo = (lo + Math.imul(al8, bl9)) | 0; + mid = (mid + Math.imul(al8, bh9)) | 0; + mid = (mid + Math.imul(ah8, bl9)) | 0; + hi = (hi + Math.imul(ah8, bh9)) | 0; + var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0; + w17 &= 0x3ffffff; + /* k = 18 */ + lo = Math.imul(al9, bl9); + mid = Math.imul(al9, bh9); + mid = (mid + Math.imul(ah9, bl9)) | 0; + hi = Math.imul(ah9, bh9); + var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0; + w18 &= 0x3ffffff; + o[0] = w0; + o[1] = w1; + o[2] = w2; + o[3] = w3; + o[4] = w4; + o[5] = w5; + o[6] = w6; + o[7] = w7; + o[8] = w8; + o[9] = w9; + o[10] = w10; + o[11] = w11; + o[12] = w12; + o[13] = w13; + o[14] = w14; + o[15] = w15; + o[16] = w16; + o[17] = w17; + o[18] = w18; + if (c !== 0) { + o[19] = c; + out.length++; + } + return out; + }; -/** - * Returns a Unit instance created from an amount in micros - * - * @param {Number} amount - The amount in micros - * @returns {Unit} A Unit instance - */ -Unit.fromMicros = function(amount) { - return new Unit(amount, Unit.micros); -}; + // Polyfill comb + if (!Math.imul) { + comb10MulTo = smallMulTo; + } -/** - * Returns a Unit instance created from a fiat amount and exchange rate. - * - * @param {Number} amount - The amount in fiat - * @param {Number} rate - The exchange rate MRT/fiat - * @returns {Unit} A Unit instance - */ -Unit.fromFiat = function(amount, rate) { - return new Unit(amount, rate); -}; + function bigMulTo(self, num, out) { + out.negative = num.negative ^ self.negative; + out.length = self.length + num.length; + + var carry = 0; + var hncarry = 0; + for (var k = 0; k < out.length - 1; k++) { + // Sum all words with the same `i + j = k` and accumulate `ncarry`, + // note that ncarry could be >= 0x3ffffff + var ncarry = hncarry; + hncarry = 0; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { + var i = k - j; + var a = self.words[i] | 0; + var b = num.words[j] | 0; + var r = a * b; + + var lo = r & 0x3ffffff; + ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0; + lo = (lo + rword) | 0; + rword = lo & 0x3ffffff; + ncarry = (ncarry + (lo >>> 26)) | 0; + + hncarry += ncarry >>> 26; + ncarry &= 0x3ffffff; + } + out.words[k] = rword; + carry = ncarry; + ncarry = hncarry; + } + if (carry !== 0) { + out.words[k] = carry; + } else { + out.length--; + } -Unit.prototype._from = function(amount, code) { - if (!UNITS[code]) { - throw new errors.Unit.UnknownCode(code); - } - return parseInt((amount * UNITS[code][0]).toFixed()); -}; + return out.strip(); + } -/** - * Returns the value represented in the specified unit - * - * @param {String|Number} code - The unit code or exchange rate - * @returns {Number} The converted value - */ -Unit.prototype.to = function(code) { - if (_.isNumber(code)) { - if (code <= 0) { - throw new errors.Unit.InvalidRate(code); - } - return parseFloat((this.MRT * code).toFixed(2)); - } + function jumboMulTo(self, num, out) { + var fftm = new FFTM(); + return fftm.mulp(self, num, out); + } - if (!UNITS[code]) { - throw new errors.Unit.UnknownCode(code); - } + BN.prototype.mulTo = function mulTo(num, out) { + var res; + var len = this.length + num.length; + if (this.length === 10 && num.length === 10) { + res = comb10MulTo(this, num, out); + } else if (len < 63) { + res = smallMulTo(this, num, out); + } else if (len < 1024) { + res = bigMulTo(this, num, out); + } else { + res = jumboMulTo(this, num, out); + } - var value = this._value / UNITS[code][0]; - return parseFloat(value.toFixed(UNITS[code][1])); -}; + return res; + }; -/** - * Returns the value represented in MRT - * - * @returns {Number} The value converted to MRT - */ -Unit.prototype.toMRT = function() { - return this.to(Unit.MRT); -}; + // Cooley-Tukey algorithm for FFT + // slightly revisited to rely on looping instead of recursion -/** - * Returns the value represented in mMRT - * - * @returns {Number} The value converted to mMRT - */ -Unit.prototype.toMillis = Unit.prototype.toMilis = function() { - return this.to(Unit.mMRT); -}; + function FFTM(x, y) { + this.x = x; + this.y = y; + } -/** - * Returns the value represented in bits - * - * @returns {Number} The value converted to bits - */ -Unit.prototype.toMicros = Unit.prototype.toBits = function() { - return this.to(Unit.bits); -}; + FFTM.prototype.makeRBT = function makeRBT(N) { + var t = new Array(N); + var l = BN.prototype._countBits(N) - 1; + for (var i = 0; i < N; i++) { + t[i] = this.revBin(i, l, N); + } -/** - * Returns the value represented in micros - * - * @returns {Number} The value converted to micros - */ -Unit.prototype.toMicros = function() { - return this.to(Unit.micros); -}; + return t; + }; -/** - * Returns the value represented in fiat - * - * @param {string} rate - The exchange rate between MRT/currency - * @returns {Number} The value converted to micros - */ -Unit.prototype.atRate = function(rate) { - return this.to(rate); -}; + // Returns binary-reversed representation of `x` + FFTM.prototype.revBin = function revBin(x, l, N) { + if (x === 0 || x === N - 1) return x; -/** - * Returns a the string representation of the value in micros - * - * @returns {string} the value in micros - */ -Unit.prototype.toString = function() { - return this.micros + ' micros'; -}; + var rb = 0; + for (var i = 0; i < l; i++) { + rb |= (x & 1) << (l - i - 1); + x >>= 1; + } -/** - * Returns a plain object representation of the Unit - * - * @returns {Object} An object with the keys: amount and code - */ -Unit.prototype.toObject = Unit.prototype.toJSON = function toObject() { - return { - amount: this.MRT, - code: Unit.MRT - }; -}; - -/** - * Returns a string formatted for the console - * - * @returns {string} the value in micros - */ -Unit.prototype.inspect = function() { - return ''; -}; + return rb; + }; -module.exports = Unit; + // Performs "tweedling" phase, therefore 'emulating' + // behaviour of the recursive algorithm + FFTM.prototype.permute = function permute(rbt, rws, iws, rtws, itws, N) { + for (var i = 0; i < N; i++) { + rtws[i] = rws[rbt[i]]; + itws[i] = iws[rbt[i]]; + } + }; -},{"./errors":17,"./util/preconditions":44,"lodash":187}],41:[function(require,module,exports){ -'use strict'; + FFTM.prototype.transform = function transform(rws, iws, rtws, itws, N, rbt) { + this.permute(rbt, rws, iws, rtws, itws, N); -var _ = require('lodash'); -var URL = require('url'); + for (var s = 1; s < N; s <<= 1) { + var l = s << 1; -var Address = require('./address'); -var Unit = require('./unit'); + var rtwdf = Math.cos((2 * Math.PI) / l); + var itwdf = Math.sin((2 * Math.PI) / l); -/** - * Merit URI - * - * Instantiate an URI from a Merit URI String or an Object. An URI instance - * can be created with a Merit uri string or an object. All instances of - * URI are valid, the static method isValid allows checking before instantiation. - * - * All standard parameters can be found as members of the class, the address - * is represented using an {Address} instance and the amount is represented in - * micros. Any other non-standard parameters can be found under the extra member. - * - * @example - * ```javascript - * - * var uri = new URI('merit:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu?amount=1.2'); - * console.log(uri.address, uri.amount); - * ``` - * - * @param {string|Object} data - A Merit URI string or an Object - * @param {Array.=} knownParams - Required non-standard params - * @throws {TypeError} Invalid Merit address - * @throws {TypeError} Invalid amount - * @throws {Error} Unknown required argument - * @returns {URI} A new valid and frozen instance of URI - * @constructor - */ -var URI = function(data, knownParams) { - if (!(this instanceof URI)) { - return new URI(data, knownParams); - } + for (var p = 0; p < N; p += l) { + var rtwdf_ = rtwdf; + var itwdf_ = itwdf; - this.extras = {}; - this.knownParams = knownParams || []; - this.address = this.network = this.amount = this.message = null; + for (var j = 0; j < s; j++) { + var re = rtws[p + j]; + var ie = itws[p + j]; - if (typeof(data) === 'string') { - var params = URI.parse(data); - if (params.amount) { - params.amount = this._parseAmount(params.amount); - } - this._fromObject(params); - } else if (typeof(data) === 'object') { - this._fromObject(data); - } else { - throw new TypeError('Unrecognized data format.'); - } -}; + var ro = rtws[p + j + s]; + var io = itws[p + j + s]; -/** - * Instantiate a URI from a String - * - * @param {string} str - JSON string or object of the URI - * @returns {URI} A new instance of a URI - */ -URI.fromString = function fromString(str) { - if (typeof(str) !== 'string') { - throw new TypeError('Expected a string'); - } - return new URI(str); -}; + var rx = rtwdf_ * ro - itwdf_ * io; -/** - * Instantiate a URI from an Object - * - * @param {Object} data - object of the URI - * @returns {URI} A new instance of a URI - */ -URI.fromObject = function fromObject(json) { - return new URI(json); -}; + io = rtwdf_ * io + itwdf_ * ro; + ro = rx; -/** - * Check if an Merit URI string is valid - * - * @example - * ```javascript - * - * var valid = URI.isValid('merit:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu'); - * // true - * ``` - * - * @param {string|Object} data - A Merit URI string or an Object - * @param {Array.=} knownParams - Required non-standard params - * @returns {boolean} Result of uri validation - */ -URI.isValid = function(arg, knownParams) { - try { - new URI(arg, knownParams); - } catch (err) { - return false; - } - return true; -}; + rtws[p + j] = re + ro; + itws[p + j] = ie + io; -/** - * Convert a Merit URI string into a simple object. - * - * @param {string} uri - A Merit URI string - * @throws {TypeError} Invalid Merit URI - * @returns {Object} An object with the parsed params - */ -URI.parse = function(uri) { - var info = URL.parse(uri, true); + rtws[p + j + s] = re - ro; + itws[p + j + s] = ie - io; - if (info.protocol !== 'merit:') { - throw new TypeError('Invalid Merit URI'); - } + /* jshint maxdepth : false */ + if (j !== l) { + rx = rtwdf * rtwdf_ - itwdf * itwdf_; - // workaround to host insensitiveness - var group = /[^:]*:\/?\/?([^?]*)/.exec(uri); - info.query.address = group && group[1] || undefined; + itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_; + rtwdf_ = rx; + } + } + } + } + }; + + FFTM.prototype.guessLen13b = function guessLen13b(n, m) { + var N = Math.max(m, n) | 1; + var odd = N & 1; + var i = 0; + for (N = (N / 2) | 0; N; N = N >>> 1) { + i++; + } - return info.query; -}; + return 1 << (i + 1 + odd); + }; -URI.Members = ['address', 'amount', 'message', 'label', 'r']; + FFTM.prototype.conjugate = function conjugate(rws, iws, N) { + if (N <= 1) return; -/** - * Internal function to load the URI instance with an object. - * - * @param {Object} obj - Object with the information - * @throws {TypeError} Invalid Merit address - * @throws {TypeError} Invalid amount - * @throws {Error} Unknown required argument - */ -URI.prototype._fromObject = function(obj) { - /* jshint maxcomplexity: 10 */ + for (var i = 0; i < N / 2; i++) { + var t = rws[i]; - if (!Address.isValid(obj.address)) { - throw new TypeError('Invalid Merit address'); - } + rws[i] = rws[N - i - 1]; + rws[N - i - 1] = t; - this.address = new Address(obj.address); - this.network = this.address.network; - this.amount = obj.amount; + t = iws[i]; - for (var key in obj) { - if (key === 'address' || key === 'amount') { - continue; - } + iws[i] = -iws[N - i - 1]; + iws[N - i - 1] = -t; + } + }; - if (/^req-/.exec(key) && this.knownParams.indexOf(key) === -1) { - throw Error('Unknown required argument ' + key); - } + FFTM.prototype.normalize13b = function normalize13b(ws, N) { + var carry = 0; + for (var i = 0; i < N / 2; i++) { + var w = Math.round(ws[2 * i + 1] / N) * 0x2000 + Math.round(ws[2 * i] / N) + carry; - var destination = URI.Members.indexOf(key) > -1 ? this : this.extras; - destination[key] = obj[key]; - } -}; + ws[i] = w & 0x3ffffff; -/** - * Internal function to transform a MRT string amount into micros - * - * @param {string} amount - Amount MRT string - * @throws {TypeError} Invalid amount - * @returns {Object} Amount represented in micros - */ -URI.prototype._parseAmount = function(amount) { - amount = Number(amount); - if (isNaN(amount)) { - throw new TypeError('Invalid amount'); - } - return Unit.fromMRT(amount).toMicros(); -}; - -URI.prototype.toObject = URI.prototype.toJSON = function toObject() { - var json = {}; - for (var i = 0; i < URI.Members.length; i++) { - var m = URI.Members[i]; - if (this.hasOwnProperty(m) && typeof(this[m]) !== 'undefined') { - json[m] = this[m].toString(); - } - } - _.extend(json, this.extras); - return json; -}; + if (w < 0x4000000) { + carry = 0; + } else { + carry = (w / 0x4000000) | 0; + } + } -/** - * Will return a the string representation of the URI - * - * @returns {string} Merit URI string - */ -URI.prototype.toString = function() { - var query = {}; - if (this.amount) { - query.amount = Unit.fromMicros(this.amount).toMRT(); - } - if (this.message) { - query.message = this.message; - } - if (this.label) { - query.label = this.label; - } - if (this.r) { - query.r = this.r; - } - _.extend(query, this.extras); + return ws; + }; - return URL.format({ - protocol: 'merit:', - host: this.address, - query: query - }); -}; + FFTM.prototype.convert13b = function convert13b(ws, len, rws, N) { + var carry = 0; + for (var i = 0; i < len; i++) { + carry = carry + (ws[i] | 0); -/** - * Will return a string formatted for the console - * - * @returns {string} Merit URI - */ -URI.prototype.inspect = function() { - return ''; -}; + rws[2 * i] = carry & 0x1fff; + carry = carry >>> 13; + rws[2 * i + 1] = carry & 0x1fff; + carry = carry >>> 13; + } -module.exports = URI; + // Pad with zeroes + for (i = 2 * len; i < N; ++i) { + rws[i] = 0; + } -},{"./address":1,"./unit":40,"lodash":187,"url":244}],42:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + assert(carry === 0); + assert((carry & ~0x1fff) === 0); + }; -var buffer = require('buffer'); -var assert = require('assert'); + FFTM.prototype.stub = function stub(N) { + var ph = new Array(N); + for (var i = 0; i < N; i++) { + ph[i] = 0; + } -var js = require('./js'); -var $ = require('./preconditions'); + return ph; + }; -function equals(a, b) { - if (a.length !== b.length) { - return false; - } - var length = a.length; - for (var i = 0; i < length; i++) { - if (a[i] !== b[i]) { - return false; - } - } - return true; -} + FFTM.prototype.mulp = function mulp(x, y, out) { + var N = 2 * this.guessLen13b(x.length, y.length); -module.exports = { - /** - * Fill a buffer with a value. - * - * @param {Buffer} buffer - * @param {number} value - * @return {Buffer} - */ - fill: function fill(buffer, value) { - $.checkArgumentType(buffer, 'Buffer', 'buffer'); - $.checkArgumentType(value, 'number', 'value'); - var length = buffer.length; - for (var i = 0; i < length; i++) { - buffer[i] = value; - } - return buffer; - }, + var rbt = this.makeRBT(N); - /** - * Return a copy of a buffer - * - * @param {Buffer} original - * @return {Buffer} - */ - copy: function(original) { - var buffer = new Buffer(original.length); - original.copy(buffer); - return buffer; - }, + var _ = this.stub(N); - /** - * Returns true if the given argument is an instance of a buffer. Tests for - * both node's Buffer and Uint8Array - * - * @param {*} arg - * @return {boolean} - */ - isBuffer: function isBuffer(arg) { - return buffer.Buffer.isBuffer(arg) || arg instanceof Uint8Array; - }, + var rws = new Array(N); + var rwst = new Array(N); + var iwst = new Array(N); - /** - * Returns a zero-filled byte array - * - * @param {number} bytes - * @return {Buffer} - */ - emptyBuffer: function emptyBuffer(bytes) { - $.checkArgumentType(bytes, 'number', 'bytes'); - var result = new buffer.Buffer(bytes); - for (var i = 0; i < bytes; i++) { - result.write('\0', i); - } - return result; - }, + var nrws = new Array(N); + var nrwst = new Array(N); + var niwst = new Array(N); - /** - * Concatenates a buffer - * - * Shortcut for buffer.Buffer.concat - */ - concat: buffer.Buffer.concat, - - equals: equals, - equal: equals, - - /** - * Transforms a number from 0 to 255 into a Buffer of size 1 with that value - * - * @param {number} integer - * @return {Buffer} - */ - integerAsSingleByteBuffer: function integerAsSingleByteBuffer(integer) { - $.checkArgumentType(integer, 'number', 'integer'); - return new buffer.Buffer([integer & 0xff]); - }, + var rmws = out.words; + rmws.length = N; - /** - * Transform a 4-byte integer into a Buffer of length 4. - * - * @param {number} integer - * @return {Buffer} - */ - integerAsBuffer: function integerAsBuffer(integer) { - $.checkArgumentType(integer, 'number', 'integer'); - var bytes = []; - bytes.push((integer >> 24) & 0xff); - bytes.push((integer >> 16) & 0xff); - bytes.push((integer >> 8) & 0xff); - bytes.push(integer & 0xff); - return new Buffer(bytes); - }, + this.convert13b(x.words, x.length, rws, N); + this.convert13b(y.words, y.length, nrws, N); - /** - * Transform the first 4 values of a Buffer into a number, in little endian encoding - * - * @param {Buffer} buffer - * @return {number} - */ - integerFromBuffer: function integerFromBuffer(buffer) { - $.checkArgumentType(buffer, 'Buffer', 'buffer'); - return buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; - }, + this.transform(rws, _, rwst, iwst, N, rbt); + this.transform(nrws, _, nrwst, niwst, N, rbt); - /** - * Transforms the first byte of an array into a number ranging from -128 to 127 - * @param {Buffer} buffer - * @return {number} - */ - integerFromSingleByteBuffer: function integerFromBuffer(buffer) { - $.checkArgumentType(buffer, 'Buffer', 'buffer'); - return buffer[0]; - }, + for (var i = 0; i < N; i++) { + var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i]; + iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i]; + rwst[i] = rx; + } - /** - * Transforms a buffer into a string with a number in hexa representation - * - * Shorthand for buffer.toString('hex') - * - * @param {Buffer} buffer - * @return {string} - */ - bufferToHex: function bufferToHex(buffer) { - $.checkArgumentType(buffer, 'Buffer', 'buffer'); - return buffer.toString('hex'); - }, + this.conjugate(rwst, iwst, N); + this.transform(rwst, iwst, rmws, _, N, rbt); + this.conjugate(rmws, _, N); + this.normalize13b(rmws, N); + + out.negative = x.negative ^ y.negative; + out.length = x.length + y.length; + return out.strip(); + }; + + // Multiply `this` by `num` + BN.prototype.mul = function mul(num) { + var out = new BN(null); + out.words = new Array(this.length + num.length); + return this.mulTo(num, out); + }; + + // Multiply employing FFT + BN.prototype.mulf = function mulf(num) { + var out = new BN(null); + out.words = new Array(this.length + num.length); + return jumboMulTo(this, num, out); + }; + + // In-place Multiplication + BN.prototype.imul = function imul(num) { + return this.clone().mulTo(num, this); + }; + + BN.prototype.imuln = function imuln(num) { + assert(typeof num === 'number'); + assert(num < 0x4000000); + + // Carry + var carry = 0; + for (var i = 0; i < this.length; i++) { + var w = (this.words[i] | 0) * num; + var lo = (w & 0x3ffffff) + (carry & 0x3ffffff); + carry >>= 26; + carry += (w / 0x4000000) | 0; + // NOTE: lo is 27bit maximum + carry += lo >>> 26; + this.words[i] = lo & 0x3ffffff; + } - /** - * Reverse a buffer - * @param {Buffer} param - * @return {Buffer} - */ - reverse: function reverse(param) { - var ret = new buffer.Buffer(param.length); - for (var i = 0; i < param.length; i++) { - ret[i] = param[param.length - i - 1]; - } - return ret; - }, + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } - /** - * Transforms an hexa encoded string into a Buffer with binary values - * - * Shorthand for Buffer(string, 'hex') - * - * @param {string} string - * @return {Buffer} - */ - hexToBuffer: function hexToBuffer(string) { - assert(js.isHexa(string)); - return new buffer.Buffer(string, 'hex'); - } -}; + return this; + }; -module.exports.NULL_HASH = module.exports.fill(new Buffer(32), 0); -module.exports.EMPTY_BUFFER = new Buffer(0); + BN.prototype.muln = function muln(num) { + return this.clone().imuln(num); + }; -}).call(this,require("buffer").Buffer) -},{"./js":43,"./preconditions":44,"assert":60,"buffer":113}],43:[function(require,module,exports){ -'use strict'; + // `this` * `this` + BN.prototype.sqr = function sqr() { + return this.mul(this); + }; -var _ = require('lodash'); + // `this` * `this` in-place + BN.prototype.isqr = function isqr() { + return this.imul(this.clone()); + }; -/** - * Determines whether a string contains only hexadecimal values - * - * @name JSUtil.isHexa - * @param {string} value - * @return {boolean} true if the string is the hexa representation of a number - */ -var isHexa = function isHexa(value) { - if (!_.isString(value)) { - return false; - } - return /^[0-9a-fA-F]+$/.test(value); -}; + // Math.pow(`this`, `num`) + BN.prototype.pow = function pow(num) { + var w = toBitArray(num); + if (w.length === 0) return new BN(1); -/** - * @namespace JSUtil - */ -module.exports = { - /** - * Test if an argument is a valid JSON object. If it is, returns a truthy - * value (the json object decoded), so no double JSON.parse call is necessary - * - * @param {string} arg - * @return {Object|boolean} false if the argument is not a JSON string. - */ - isValidJSON: function isValidJSON(arg) { - var parsed; - if (!_.isString(arg)) { - return false; - } - try { - parsed = JSON.parse(arg); - } catch (e) { - return false; - } - if (typeof(parsed) === 'object') { - return true; - } - return false; - }, - isHexa: isHexa, - isHexaString: isHexa, - - /** - * Clone an array - */ - cloneArray: function(array) { - return [].concat(array); - }, + // Skip leading zeroes + var res = this; + for (var i = 0; i < w.length; i++, res = res.sqr()) { + if (w[i] !== 0) break; + } - /** - * Define immutable properties on a target object - * - * @param {Object} target - An object to be extended - * @param {Object} values - An object of properties - * @return {Object} The target object - */ - defineImmutable: function defineImmutable(target, values) { - Object.keys(values).forEach(function(key){ - Object.defineProperty(target, key, { - configurable: false, - enumerable: true, - value: values[key] - }); - }); - return target; - }, - /** - * Checks that a value is a natural number, a positive integer or zero. - * - * @param {*} value - * @return {Boolean} - */ - isNaturalNumber: function isNaturalNumber(value) { - return typeof value === 'number' && - isFinite(value) && - Math.floor(value) === value && - value >= 0; - } -}; + if (++i < w.length) { + for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) { + if (w[i] === 0) continue; -},{"lodash":187}],44:[function(require,module,exports){ -'use strict'; + res = res.mul(q); + } + } -var errors = require('../errors'); -var _ = require('lodash'); + return res; + }; + + // Shift-left in-place + BN.prototype.iushln = function iushln(bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; + var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r); + var i; + + if (r !== 0) { + var carry = 0; + + for (i = 0; i < this.length; i++) { + var newCarry = this.words[i] & carryMask; + var c = ((this.words[i] | 0) - newCarry) << r; + this.words[i] = c | carry; + carry = newCarry >>> (26 - r); + } -module.exports = { - checkState: function(condition, message) { - if (!condition) { - throw new errors.InvalidState(message); - } - }, - checkArgument: function(condition, argumentName, message, docsPath) { - if (!condition) { - throw new errors.InvalidArgument(argumentName, message, docsPath); - } - }, - checkArgumentType: function(argument, type, argumentName) { - argumentName = argumentName || '(unknown name)'; - if (_.isString(type)) { - if (type === 'Buffer') { - var buffer = require('buffer'); // './buffer' fails on cordova & RN - if (!buffer.Buffer.isBuffer(argument)) { - throw new errors.InvalidArgumentType(argument, type, argumentName); - } - } else if (typeof argument !== type) { - throw new errors.InvalidArgumentType(argument, type, argumentName); - } - } else { - if (!(argument instanceof type)) { - throw new errors.InvalidArgumentType(argument, type.name, argumentName); - } - } - } -}; - -},{"../errors":17,"buffer":113,"lodash":187}],45:[function(require,module,exports){ -var asn1 = exports; - -asn1.bignum = require('bn.js'); - -asn1.define = require('./asn1/api').define; -asn1.base = require('./asn1/base'); -asn1.constants = require('./asn1/constants'); -asn1.decoders = require('./asn1/decoders'); -asn1.encoders = require('./asn1/encoders'); - -},{"./asn1/api":46,"./asn1/base":48,"./asn1/constants":52,"./asn1/decoders":54,"./asn1/encoders":57,"bn.js":59}],46:[function(require,module,exports){ -var asn1 = require('../asn1'); -var inherits = require('inherits'); - -var api = exports; - -api.define = function define(name, body) { - return new Entity(name, body); -}; - -function Entity(name, body) { - this.name = name; - this.body = body; - - this.decoders = {}; - this.encoders = {}; -}; - -Entity.prototype._createNamed = function createNamed(base) { - var named; - try { - named = require('vm').runInThisContext( - '(function ' + this.name + '(entity) {\n' + - ' this._initNamed(entity);\n' + - '})' - ); - } catch (e) { - named = function (entity) { - this._initNamed(entity); - }; - } - inherits(named, base); - named.prototype._initNamed = function initnamed(entity) { - base.call(this, entity); - }; - - return new named(this); -}; - -Entity.prototype._getDecoder = function _getDecoder(enc) { - enc = enc || 'der'; - // Lazily create decoder - if (!this.decoders.hasOwnProperty(enc)) - this.decoders[enc] = this._createNamed(asn1.decoders[enc]); - return this.decoders[enc]; -}; - -Entity.prototype.decode = function decode(data, enc, options) { - return this._getDecoder(enc).decode(data, options); -}; - -Entity.prototype._getEncoder = function _getEncoder(enc) { - enc = enc || 'der'; - // Lazily create encoder - if (!this.encoders.hasOwnProperty(enc)) - this.encoders[enc] = this._createNamed(asn1.encoders[enc]); - return this.encoders[enc]; -}; - -Entity.prototype.encode = function encode(data, enc, /* internal */ reporter) { - return this._getEncoder(enc).encode(data, reporter); -}; - -},{"../asn1":45,"inherits":184,"vm":249}],47:[function(require,module,exports){ -var inherits = require('inherits'); -var Reporter = require('../base').Reporter; -var Buffer = require('buffer').Buffer; - -function DecoderBuffer(base, options) { - Reporter.call(this, options); - if (!Buffer.isBuffer(base)) { - this.error('Input not Buffer'); - return; - } + if (carry) { + this.words[i] = carry; + this.length++; + } + } - this.base = base; - this.offset = 0; - this.length = base.length; -} -inherits(DecoderBuffer, Reporter); -exports.DecoderBuffer = DecoderBuffer; - -DecoderBuffer.prototype.save = function save() { - return { offset: this.offset, reporter: Reporter.prototype.save.call(this) }; -}; - -DecoderBuffer.prototype.restore = function restore(save) { - // Return skipped data - var res = new DecoderBuffer(this.base); - res.offset = save.offset; - res.length = this.offset; - - this.offset = save.offset; - Reporter.prototype.restore.call(this, save.reporter); - - return res; -}; - -DecoderBuffer.prototype.isEmpty = function isEmpty() { - return this.offset === this.length; -}; - -DecoderBuffer.prototype.readUInt8 = function readUInt8(fail) { - if (this.offset + 1 <= this.length) - return this.base.readUInt8(this.offset++, true); - else - return this.error(fail || 'DecoderBuffer overrun'); -} + if (s !== 0) { + for (i = this.length - 1; i >= 0; i--) { + this.words[i + s] = this.words[i]; + } -DecoderBuffer.prototype.skip = function skip(bytes, fail) { - if (!(this.offset + bytes <= this.length)) - return this.error(fail || 'DecoderBuffer overrun'); + for (i = 0; i < s; i++) { + this.words[i] = 0; + } - var res = new DecoderBuffer(this.base); + this.length += s; + } - // Share reporter state - res._reporterState = this._reporterState; + return this.strip(); + }; + + BN.prototype.ishln = function ishln(bits) { + // TODO(indutny): implement me + assert(this.negative === 0); + return this.iushln(bits); + }; + + // Shift-right in-place + // NOTE: `hint` is a lowest bit before trailing zeroes + // NOTE: if `extended` is present - it will be filled with destroyed bits + BN.prototype.iushrn = function iushrn(bits, hint, extended) { + assert(typeof bits === 'number' && bits >= 0); + var h; + if (hint) { + h = (hint - (hint % 26)) / 26; + } else { + h = 0; + } - res.offset = this.offset; - res.length = this.offset + bytes; - this.offset += bytes; - return res; -} + var r = bits % 26; + var s = Math.min((bits - r) / 26, this.length); + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + var maskedWords = extended; -DecoderBuffer.prototype.raw = function raw(save) { - return this.base.slice(save ? save.offset : this.offset, this.length); -} + h -= s; + h = Math.max(0, h); -function EncoderBuffer(value, reporter) { - if (Array.isArray(value)) { - this.length = 0; - this.value = value.map(function(item) { - if (!(item instanceof EncoderBuffer)) - item = new EncoderBuffer(item, reporter); - this.length += item.length; - return item; - }, this); - } else if (typeof value === 'number') { - if (!(0 <= value && value <= 0xff)) - return reporter.error('non-byte EncoderBuffer value'); - this.value = value; - this.length = 1; - } else if (typeof value === 'string') { - this.value = value; - this.length = Buffer.byteLength(value); - } else if (Buffer.isBuffer(value)) { - this.value = value; - this.length = value.length; - } else { - return reporter.error('Unsupported type: ' + typeof value); - } -} -exports.EncoderBuffer = EncoderBuffer; - -EncoderBuffer.prototype.join = function join(out, offset) { - if (!out) - out = new Buffer(this.length); - if (!offset) - offset = 0; - - if (this.length === 0) - return out; - - if (Array.isArray(this.value)) { - this.value.forEach(function(item) { - item.join(out, offset); - offset += item.length; - }); - } else { - if (typeof this.value === 'number') - out[offset] = this.value; - else if (typeof this.value === 'string') - out.write(this.value, offset); - else if (Buffer.isBuffer(this.value)) - this.value.copy(out, offset); - offset += this.length; - } + // Extended mode, copy masked part + if (maskedWords) { + for (var i = 0; i < s; i++) { + maskedWords.words[i] = this.words[i]; + } + maskedWords.length = s; + } - return out; -}; - -},{"../base":48,"buffer":113,"inherits":184}],48:[function(require,module,exports){ -var base = exports; - -base.Reporter = require('./reporter').Reporter; -base.DecoderBuffer = require('./buffer').DecoderBuffer; -base.EncoderBuffer = require('./buffer').EncoderBuffer; -base.Node = require('./node'); - -},{"./buffer":47,"./node":49,"./reporter":50}],49:[function(require,module,exports){ -var Reporter = require('../base').Reporter; -var EncoderBuffer = require('../base').EncoderBuffer; -var DecoderBuffer = require('../base').DecoderBuffer; -var assert = require('minimalistic-assert'); - -// Supported tags -var tags = [ - 'seq', 'seqof', 'set', 'setof', 'objid', 'bool', - 'gentime', 'utctime', 'null_', 'enum', 'int', 'objDesc', - 'bitstr', 'bmpstr', 'charstr', 'genstr', 'graphstr', 'ia5str', 'iso646str', - 'numstr', 'octstr', 'printstr', 't61str', 'unistr', 'utf8str', 'videostr' -]; - -// Public methods list -var methods = [ - 'key', 'obj', 'use', 'optional', 'explicit', 'implicit', 'def', 'choice', - 'any', 'contains' -].concat(tags); - -// Overrided methods list -var overrided = [ - '_peekTag', '_decodeTag', '_use', - '_decodeStr', '_decodeObjid', '_decodeTime', - '_decodeNull', '_decodeInt', '_decodeBool', '_decodeList', - - '_encodeComposite', '_encodeStr', '_encodeObjid', '_encodeTime', - '_encodeNull', '_encodeInt', '_encodeBool' -]; - -function Node(enc, parent) { - var state = {}; - this._baseState = state; - - state.enc = enc; - - state.parent = parent || null; - state.children = null; - - // State - state.tag = null; - state.args = null; - state.reverseArgs = null; - state.choice = null; - state.optional = false; - state.any = false; - state.obj = false; - state.use = null; - state.useDecoder = null; - state.key = null; - state['default'] = null; - state.explicit = null; - state.implicit = null; - state.contains = null; - - // Should create new instance on each method - if (!state.parent) { - state.children = []; - this._wrap(); - } -} -module.exports = Node; - -var stateProps = [ - 'enc', 'parent', 'children', 'tag', 'args', 'reverseArgs', 'choice', - 'optional', 'any', 'obj', 'use', 'alteredUse', 'key', 'default', 'explicit', - 'implicit', 'contains' -]; - -Node.prototype.clone = function clone() { - var state = this._baseState; - var cstate = {}; - stateProps.forEach(function(prop) { - cstate[prop] = state[prop]; - }); - var res = new this.constructor(cstate.parent); - res._baseState = cstate; - return res; -}; - -Node.prototype._wrap = function wrap() { - var state = this._baseState; - methods.forEach(function(method) { - this[method] = function _wrappedMethod() { - var clone = new this.constructor(this); - state.children.push(clone); - return clone[method].apply(clone, arguments); - }; - }, this); -}; - -Node.prototype._init = function init(body) { - var state = this._baseState; - - assert(state.parent === null); - body.call(this); - - // Filter children - state.children = state.children.filter(function(child) { - return child._baseState.parent === this; - }, this); - assert.equal(state.children.length, 1, 'Root node can have only one child'); -}; - -Node.prototype._useArgs = function useArgs(args) { - var state = this._baseState; - - // Filter children and args - var children = args.filter(function(arg) { - return arg instanceof this.constructor; - }, this); - args = args.filter(function(arg) { - return !(arg instanceof this.constructor); - }, this); - - if (children.length !== 0) { - assert(state.children === null); - state.children = children; - - // Replace parent to maintain backward link - children.forEach(function(child) { - child._baseState.parent = this; - }, this); - } - if (args.length !== 0) { - assert(state.args === null); - state.args = args; - state.reverseArgs = args.map(function(arg) { - if (typeof arg !== 'object' || arg.constructor !== Object) - return arg; - - var res = {}; - Object.keys(arg).forEach(function(key) { - if (key == (key | 0)) - key |= 0; - var value = arg[key]; - res[value] = key; - }); - return res; - }); - } -}; + if (s === 0) { + // No-op, we should not move anything at all + } else if (this.length > s) { + this.length -= s; + for (i = 0; i < this.length; i++) { + this.words[i] = this.words[i + s]; + } + } else { + this.words[0] = 0; + this.length = 1; + } -// -// Overrided methods -// + var carry = 0; + for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) { + var word = this.words[i] | 0; + this.words[i] = (carry << (26 - r)) | (word >>> r); + carry = word & mask; + } -overrided.forEach(function(method) { - Node.prototype[method] = function _overrided() { - var state = this._baseState; - throw new Error(method + ' not implemented for encoding: ' + state.enc); - }; -}); + // Push carried bits as a mask + if (maskedWords && carry !== 0) { + maskedWords.words[maskedWords.length++] = carry; + } -// -// Public methods -// + if (this.length === 0) { + this.words[0] = 0; + this.length = 1; + } -tags.forEach(function(tag) { - Node.prototype[tag] = function _tagMethod() { - var state = this._baseState; - var args = Array.prototype.slice.call(arguments); + return this.strip(); + }; - assert(state.tag === null); - state.tag = tag; + BN.prototype.ishrn = function ishrn(bits, hint, extended) { + // TODO(indutny): implement me + assert(this.negative === 0); + return this.iushrn(bits, hint, extended); + }; - this._useArgs(args); + // Shift-left + BN.prototype.shln = function shln(bits) { + return this.clone().ishln(bits); + }; - return this; - }; -}); + BN.prototype.ushln = function ushln(bits) { + return this.clone().iushln(bits); + }; -Node.prototype.use = function use(item) { - assert(item); - var state = this._baseState; + // Shift-right + BN.prototype.shrn = function shrn(bits) { + return this.clone().ishrn(bits); + }; - assert(state.use === null); - state.use = item; + BN.prototype.ushrn = function ushrn(bits) { + return this.clone().iushrn(bits); + }; - return this; -}; + // Test if n bit is set + BN.prototype.testn = function testn(bit) { + assert(typeof bit === 'number' && bit >= 0); + var r = bit % 26; + var s = (bit - r) / 26; + var q = 1 << r; -Node.prototype.optional = function optional() { - var state = this._baseState; + // Fast case: bit is much higher than all existing words + if (this.length <= s) return false; - state.optional = true; + // Check bit and return + var w = this.words[s]; - return this; -}; + return !!(w & q); + }; -Node.prototype.def = function def(val) { - var state = this._baseState; + // Return only lowers bits of number (in-place) + BN.prototype.imaskn = function imaskn(bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; - assert(state['default'] === null); - state['default'] = val; - state.optional = true; + assert(this.negative === 0, 'imaskn works only with positive numbers'); - return this; -}; + if (this.length <= s) { + return this; + } -Node.prototype.explicit = function explicit(num) { - var state = this._baseState; + if (r !== 0) { + s++; + } + this.length = Math.min(s, this.length); - assert(state.explicit === null && state.implicit === null); - state.explicit = num; + if (r !== 0) { + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + this.words[this.length - 1] &= mask; + } - return this; -}; + return this.strip(); + }; + + // Return only lowers bits of number + BN.prototype.maskn = function maskn(bits) { + return this.clone().imaskn(bits); + }; + + // Add plain number `num` to `this` + BN.prototype.iaddn = function iaddn(num) { + assert(typeof num === 'number'); + assert(num < 0x4000000); + if (num < 0) return this.isubn(-num); + + // Possible sign change + if (this.negative !== 0) { + if (this.length === 1 && (this.words[0] | 0) < num) { + this.words[0] = num - (this.words[0] | 0); + this.negative = 0; + return this; + } -Node.prototype.implicit = function implicit(num) { - var state = this._baseState; + this.negative = 0; + this.isubn(num); + this.negative = 1; + return this; + } - assert(state.explicit === null && state.implicit === null); - state.implicit = num; + // Add without checks + return this._iaddn(num); + }; - return this; -}; + BN.prototype._iaddn = function _iaddn(num) { + this.words[0] += num; -Node.prototype.obj = function obj() { - var state = this._baseState; - var args = Array.prototype.slice.call(arguments); + // Carry + for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) { + this.words[i] -= 0x4000000; + if (i === this.length - 1) { + this.words[i + 1] = 1; + } else { + this.words[i + 1]++; + } + } + this.length = Math.max(this.length, i + 1); + + return this; + }; + + // Subtract plain number `num` from `this` + BN.prototype.isubn = function isubn(num) { + assert(typeof num === 'number'); + assert(num < 0x4000000); + if (num < 0) return this.iaddn(-num); + + if (this.negative !== 0) { + this.negative = 0; + this.iaddn(num); + this.negative = 1; + return this; + } - state.obj = true; + this.words[0] -= num; - if (args.length !== 0) - this._useArgs(args); + if (this.length === 1 && this.words[0] < 0) { + this.words[0] = -this.words[0]; + this.negative = 1; + } else { + // Carry + for (var i = 0; i < this.length && this.words[i] < 0; i++) { + this.words[i] += 0x4000000; + this.words[i + 1] -= 1; + } + } - return this; -}; + return this.strip(); + }; -Node.prototype.key = function key(newKey) { - var state = this._baseState; + BN.prototype.addn = function addn(num) { + return this.clone().iaddn(num); + }; - assert(state.key === null); - state.key = newKey; + BN.prototype.subn = function subn(num) { + return this.clone().isubn(num); + }; - return this; -}; + BN.prototype.iabs = function iabs() { + this.negative = 0; -Node.prototype.any = function any() { - var state = this._baseState; + return this; + }; - state.any = true; + BN.prototype.abs = function abs() { + return this.clone().iabs(); + }; - return this; -}; + BN.prototype._ishlnsubmul = function _ishlnsubmul(num, mul, shift) { + var len = num.length + shift; + var i; -Node.prototype.choice = function choice(obj) { - var state = this._baseState; + this._expand(len); - assert(state.choice === null); - state.choice = obj; - this._useArgs(Object.keys(obj).map(function(key) { - return obj[key]; - })); + var w; + var carry = 0; + for (i = 0; i < num.length; i++) { + w = (this.words[i + shift] | 0) + carry; + var right = (num.words[i] | 0) * mul; + w -= right & 0x3ffffff; + carry = (w >> 26) - ((right / 0x4000000) | 0); + this.words[i + shift] = w & 0x3ffffff; + } + for (; i < this.length - shift; i++) { + w = (this.words[i + shift] | 0) + carry; + carry = w >> 26; + this.words[i + shift] = w & 0x3ffffff; + } - return this; -}; + if (carry === 0) return this.strip(); -Node.prototype.contains = function contains(item) { - var state = this._baseState; + // Subtraction overflow + assert(carry === -1); + carry = 0; + for (i = 0; i < this.length; i++) { + w = -(this.words[i] | 0) + carry; + carry = w >> 26; + this.words[i] = w & 0x3ffffff; + } + this.negative = 1; - assert(state.use === null); - state.contains = item; + return this.strip(); + }; - return this; -}; + BN.prototype._wordDiv = function _wordDiv(num, mode) { + var shift = this.length - num.length; -// -// Decoding -// + var a = this.clone(); + var b = num; -Node.prototype._decode = function decode(input, options) { - var state = this._baseState; + // Normalize + var bhi = b.words[b.length - 1] | 0; + var bhiBits = this._countBits(bhi); + shift = 26 - bhiBits; + if (shift !== 0) { + b = b.ushln(shift); + a.iushln(shift); + bhi = b.words[b.length - 1] | 0; + } - // Decode root node - if (state.parent === null) - return input.wrapResult(state.children[0]._decode(input, options)); + // Initialize quotient + var m = a.length - b.length; + var q; - var result = state['default']; - var present = true; + if (mode !== 'mod') { + q = new BN(null); + q.length = m + 1; + q.words = new Array(q.length); + for (var i = 0; i < q.length; i++) { + q.words[i] = 0; + } + } - var prevKey = null; - if (state.key !== null) - prevKey = input.enterKey(state.key); + var diff = a.clone()._ishlnsubmul(b, 1, m); + if (diff.negative === 0) { + a = diff; + if (q) { + q.words[m] = 1; + } + } - // Check if tag is there - if (state.optional) { - var tag = null; - if (state.explicit !== null) - tag = state.explicit; - else if (state.implicit !== null) - tag = state.implicit; - else if (state.tag !== null) - tag = state.tag; + for (var j = m - 1; j >= 0; j--) { + var qj = (a.words[b.length + j] | 0) * 0x4000000 + (a.words[b.length + j - 1] | 0); + + // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max + // (0x7ffffff) + qj = Math.min((qj / bhi) | 0, 0x3ffffff); + + a._ishlnsubmul(b, qj, j); + while (a.negative !== 0) { + qj--; + a.negative = 0; + a._ishlnsubmul(b, 1, j); + if (!a.isZero()) { + a.negative ^= 1; + } + } + if (q) { + q.words[j] = qj; + } + } + if (q) { + q.strip(); + } + a.strip(); - if (tag === null && !state.any) { - // Trial and Error - var save = input.save(); - try { - if (state.choice === null) - this._decodeGeneric(state.tag, input, options); - else - this._decodeChoice(input, options); - present = true; - } catch (e) { - present = false; - } - input.restore(save); - } else { - present = this._peekTag(input, tag, state.any); + // Denormalize + if (mode !== 'div' && shift !== 0) { + a.iushrn(shift); + } - if (input.isError(present)) - return present; - } - } + return { + div: q || null, + mod: a, + }; + }; + + // NOTE: 1) `mode` can be set to `mod` to request mod only, + // to `div` to request div only, or be absent to + // request both div & mod + // 2) `positive` is true if unsigned mod is requested + BN.prototype.divmod = function divmod(num, mode, positive) { + assert(!num.isZero()); + + if (this.isZero()) { + return { + div: new BN(0), + mod: new BN(0), + }; + } - // Push object on stack - var prevObj; - if (state.obj && present) - prevObj = input.enterObject(); - - if (present) { - // Unwrap explicit values - if (state.explicit !== null) { - var explicit = this._decodeTag(input, state.explicit); - if (input.isError(explicit)) - return explicit; - input = explicit; - } + var div, mod, res; + if (this.negative !== 0 && num.negative === 0) { + res = this.neg().divmod(num, mode); - var start = input.offset; + if (mode !== 'mod') { + div = res.div.neg(); + } - // Unwrap implicit and normal values - if (state.use === null && state.choice === null) { - if (state.any) - var save = input.save(); - var body = this._decodeTag( - input, - state.implicit !== null ? state.implicit : state.tag, - state.any - ); - if (input.isError(body)) - return body; + if (mode !== 'div') { + mod = res.mod.neg(); + if (positive && mod.negative !== 0) { + mod.iadd(num); + } + } - if (state.any) - result = input.raw(save); - else - input = body; - } + return { + div: div, + mod: mod, + }; + } - if (options && options.track && state.tag !== null) - options.track(input.path(), start, input.length, 'tagged'); - - if (options && options.track && state.tag !== null) - options.track(input.path(), input.offset, input.length, 'content'); - - // Select proper method for tag - if (state.any) - result = result; - else if (state.choice === null) - result = this._decodeGeneric(state.tag, input, options); - else - result = this._decodeChoice(input, options); - - if (input.isError(result)) - return result; - - // Decode children - if (!state.any && state.choice === null && state.children !== null) { - state.children.forEach(function decodeChildren(child) { - // NOTE: We are ignoring errors here, to let parser continue with other - // parts of encoded data - child._decode(input, options); - }); - } + if (this.negative === 0 && num.negative !== 0) { + res = this.divmod(num.neg(), mode); - // Decode contained/encoded by schema, only in bit or octet strings - if (state.contains && (state.tag === 'octstr' || state.tag === 'bitstr')) { - var data = new DecoderBuffer(result); - result = this._getUse(state.contains, input._reporterState.obj) - ._decode(data, options); - } - } + if (mode !== 'mod') { + div = res.div.neg(); + } - // Pop object - if (state.obj && present) - result = input.leaveObject(prevObj); - - // Set key - if (state.key !== null && (result !== null || present === true)) - input.leaveKey(prevKey, state.key, result); - else if (prevKey !== null) - input.exitKey(prevKey); - - return result; -}; - -Node.prototype._decodeGeneric = function decodeGeneric(tag, input, options) { - var state = this._baseState; - - if (tag === 'seq' || tag === 'set') - return null; - if (tag === 'seqof' || tag === 'setof') - return this._decodeList(input, tag, state.args[0], options); - else if (/str$/.test(tag)) - return this._decodeStr(input, tag, options); - else if (tag === 'objid' && state.args) - return this._decodeObjid(input, state.args[0], state.args[1], options); - else if (tag === 'objid') - return this._decodeObjid(input, null, null, options); - else if (tag === 'gentime' || tag === 'utctime') - return this._decodeTime(input, tag, options); - else if (tag === 'null_') - return this._decodeNull(input, options); - else if (tag === 'bool') - return this._decodeBool(input, options); - else if (tag === 'objDesc') - return this._decodeStr(input, tag, options); - else if (tag === 'int' || tag === 'enum') - return this._decodeInt(input, state.args && state.args[0], options); - - if (state.use !== null) { - return this._getUse(state.use, input._reporterState.obj) - ._decode(input, options); - } else { - return input.error('unknown tag: ' + tag); - } -}; - -Node.prototype._getUse = function _getUse(entity, obj) { - - var state = this._baseState; - // Create altered use decoder if implicit is set - state.useDecoder = this._use(entity, obj); - assert(state.useDecoder._baseState.parent === null); - state.useDecoder = state.useDecoder._baseState.children[0]; - if (state.implicit !== state.useDecoder._baseState.implicit) { - state.useDecoder = state.useDecoder.clone(); - state.useDecoder._baseState.implicit = state.implicit; - } - return state.useDecoder; -}; - -Node.prototype._decodeChoice = function decodeChoice(input, options) { - var state = this._baseState; - var result = null; - var match = false; - - Object.keys(state.choice).some(function(key) { - var save = input.save(); - var node = state.choice[key]; - try { - var value = node._decode(input, options); - if (input.isError(value)) - return false; - - result = { type: key, value: value }; - match = true; - } catch (e) { - input.restore(save); - return false; - } - return true; - }, this); + return { + div: div, + mod: res.mod, + }; + } - if (!match) - return input.error('Choice not matched'); + if ((this.negative & num.negative) !== 0) { + res = this.neg().divmod(num.neg(), mode); + + if (mode !== 'div') { + mod = res.mod.neg(); + if (positive && mod.negative !== 0) { + mod.isub(num); + } + } - return result; -}; + return { + div: res.div, + mod: mod, + }; + } -// -// Encoding -// + // Both numbers are positive at this point -Node.prototype._createEncoderBuffer = function createEncoderBuffer(data) { - return new EncoderBuffer(data, this.reporter); -}; + // Strip both numbers to approximate shift value + if (num.length > this.length || this.cmp(num) < 0) { + return { + div: new BN(0), + mod: this, + }; + } -Node.prototype._encode = function encode(data, reporter, parent) { - var state = this._baseState; - if (state['default'] !== null && state['default'] === data) - return; + // Very short reduction + if (num.length === 1) { + if (mode === 'div') { + return { + div: this.divn(num.words[0]), + mod: null, + }; + } - var result = this._encodeValue(data, reporter, parent); - if (result === undefined) - return; + if (mode === 'mod') { + return { + div: null, + mod: new BN(this.modn(num.words[0])), + }; + } - if (this._skipDefault(result, reporter, parent)) - return; + return { + div: this.divn(num.words[0]), + mod: new BN(this.modn(num.words[0])), + }; + } - return result; -}; + return this._wordDiv(num, mode); + }; -Node.prototype._encodeValue = function encode(data, reporter, parent) { - var state = this._baseState; + // Find `this` / `num` + BN.prototype.div = function div(num) { + return this.divmod(num, 'div', false).div; + }; - // Decode root node - if (state.parent === null) - return state.children[0]._encode(data, reporter || new Reporter()); + // Find `this` % `num` + BN.prototype.mod = function mod(num) { + return this.divmod(num, 'mod', false).mod; + }; - var result = null; + BN.prototype.umod = function umod(num) { + return this.divmod(num, 'mod', true).mod; + }; - // Set reporter to share it with a child class - this.reporter = reporter; + // Find Round(`this` / `num`) + BN.prototype.divRound = function divRound(num) { + var dm = this.divmod(num); - // Check if data is there - if (state.optional && data === undefined) { - if (state['default'] !== null) - data = state['default'] - else - return; - } + // Fast case - exact division + if (dm.mod.isZero()) return dm.div; - // Encode children first - var content = null; - var primitive = false; - if (state.any) { - // Anything that was given is translated to buffer - result = this._createEncoderBuffer(data); - } else if (state.choice) { - result = this._encodeChoice(data, reporter); - } else if (state.contains) { - content = this._getUse(state.contains, parent)._encode(data, reporter); - primitive = true; - } else if (state.children) { - content = state.children.map(function(child) { - if (child._baseState.tag === 'null_') - return child._encode(null, reporter, data); - - if (child._baseState.key === null) - return reporter.error('Child should have a key'); - var prevKey = reporter.enterKey(child._baseState.key); - - if (typeof data !== 'object') - return reporter.error('Child expected, but input is not object'); - - var res = child._encode(data[child._baseState.key], reporter, data); - reporter.leaveKey(prevKey); - - return res; - }, this).filter(function(child) { - return child; - }); - content = this._createEncoderBuffer(content); - } else { - if (state.tag === 'seqof' || state.tag === 'setof') { - // TODO(indutny): this should be thrown on DSL level - if (!(state.args && state.args.length === 1)) - return reporter.error('Too many args for : ' + state.tag); - - if (!Array.isArray(data)) - return reporter.error('seqof/setof, but data is not Array'); - - var child = this.clone(); - child._baseState.implicit = null; - content = this._createEncoderBuffer(data.map(function(item) { - var state = this._baseState; - - return this._getUse(state.args[0], data)._encode(item, reporter); - }, child)); - } else if (state.use !== null) { - result = this._getUse(state.use, parent)._encode(data, reporter); - } else { - content = this._encodePrimitive(state.tag, data); - primitive = true; - } - } + var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod; - // Encode data itself - var result; - if (!state.any && state.choice === null) { - var tag = state.implicit !== null ? state.implicit : state.tag; - var cls = state.implicit === null ? 'universal' : 'context'; - - if (tag === null) { - if (state.use === null) - reporter.error('Tag could be ommited only for .use()'); - } else { - if (state.use === null) - result = this._encodeComposite(tag, primitive, cls, content); - } - } + var half = num.ushrn(1); + var r2 = num.andln(1); + var cmp = mod.cmp(half); - // Wrap in explicit - if (state.explicit !== null) - result = this._encodeComposite(state.explicit, false, 'context', result); + // Round down + if (cmp < 0 || (r2 === 1 && cmp === 0)) return dm.div; - return result; -}; + // Round up + return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1); + }; -Node.prototype._encodeChoice = function encodeChoice(data, reporter) { - var state = this._baseState; + BN.prototype.modn = function modn(num) { + assert(num <= 0x3ffffff); + var p = (1 << 26) % num; - var node = state.choice[data.type]; - if (!node) { - assert( - false, - data.type + ' not found in ' + - JSON.stringify(Object.keys(state.choice))); - } - return node._encode(data.value, reporter); -}; - -Node.prototype._encodePrimitive = function encodePrimitive(tag, data) { - var state = this._baseState; - - if (/str$/.test(tag)) - return this._encodeStr(data, tag); - else if (tag === 'objid' && state.args) - return this._encodeObjid(data, state.reverseArgs[0], state.args[1]); - else if (tag === 'objid') - return this._encodeObjid(data, null, null); - else if (tag === 'gentime' || tag === 'utctime') - return this._encodeTime(data, tag); - else if (tag === 'null_') - return this._encodeNull(); - else if (tag === 'int' || tag === 'enum') - return this._encodeInt(data, state.args && state.reverseArgs[0]); - else if (tag === 'bool') - return this._encodeBool(data); - else if (tag === 'objDesc') - return this._encodeStr(data, tag); - else - throw new Error('Unsupported tag: ' + tag); -}; - -Node.prototype._isNumstr = function isNumstr(str) { - return /^[0-9 ]*$/.test(str); -}; - -Node.prototype._isPrintstr = function isPrintstr(str) { - return /^[A-Za-z0-9 '\(\)\+,\-\.\/:=\?]*$/.test(str); -}; - -},{"../base":48,"minimalistic-assert":192}],50:[function(require,module,exports){ -var inherits = require('inherits'); - -function Reporter(options) { - this._reporterState = { - obj: null, - path: [], - options: options || {}, - errors: [] - }; -} -exports.Reporter = Reporter; + var acc = 0; + for (var i = this.length - 1; i >= 0; i--) { + acc = (p * acc + (this.words[i] | 0)) % num; + } -Reporter.prototype.isError = function isError(obj) { - return obj instanceof ReporterError; -}; + return acc; + }; -Reporter.prototype.save = function save() { - var state = this._reporterState; + // In-place division by number + BN.prototype.idivn = function idivn(num) { + assert(num <= 0x3ffffff); - return { obj: state.obj, pathLen: state.path.length }; -}; + var carry = 0; + for (var i = this.length - 1; i >= 0; i--) { + var w = (this.words[i] | 0) + carry * 0x4000000; + this.words[i] = (w / num) | 0; + carry = w % num; + } -Reporter.prototype.restore = function restore(data) { - var state = this._reporterState; + return this.strip(); + }; - state.obj = data.obj; - state.path = state.path.slice(0, data.pathLen); -}; + BN.prototype.divn = function divn(num) { + return this.clone().idivn(num); + }; -Reporter.prototype.enterKey = function enterKey(key) { - return this._reporterState.path.push(key); -}; + BN.prototype.egcd = function egcd(p) { + assert(p.negative === 0); + assert(!p.isZero()); -Reporter.prototype.exitKey = function exitKey(index) { - var state = this._reporterState; + var x = this; + var y = p.clone(); - state.path = state.path.slice(0, index - 1); -}; + if (x.negative !== 0) { + x = x.umod(p); + } else { + x = x.clone(); + } -Reporter.prototype.leaveKey = function leaveKey(index, key, value) { - var state = this._reporterState; + // A * x + B * y = x + var A = new BN(1); + var B = new BN(0); - this.exitKey(index); - if (state.obj !== null) - state.obj[key] = value; -}; + // C * x + D * y = y + var C = new BN(0); + var D = new BN(1); -Reporter.prototype.path = function path() { - return this._reporterState.path.join('/'); -}; + var g = 0; -Reporter.prototype.enterObject = function enterObject() { - var state = this._reporterState; + while (x.isEven() && y.isEven()) { + x.iushrn(1); + y.iushrn(1); + ++g; + } - var prev = state.obj; - state.obj = {}; - return prev; -}; + var yp = y.clone(); + var xp = x.clone(); + + while (!x.isZero()) { + for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1); + if (i > 0) { + x.iushrn(i); + while (i-- > 0) { + if (A.isOdd() || B.isOdd()) { + A.iadd(yp); + B.isub(xp); + } + + A.iushrn(1); + B.iushrn(1); + } + } -Reporter.prototype.leaveObject = function leaveObject(prev) { - var state = this._reporterState; + for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); + if (j > 0) { + y.iushrn(j); + while (j-- > 0) { + if (C.isOdd() || D.isOdd()) { + C.iadd(yp); + D.isub(xp); + } + + C.iushrn(1); + D.iushrn(1); + } + } - var now = state.obj; - state.obj = prev; - return now; -}; + if (x.cmp(y) >= 0) { + x.isub(y); + A.isub(C); + B.isub(D); + } else { + y.isub(x); + C.isub(A); + D.isub(B); + } + } -Reporter.prototype.error = function error(msg) { - var err; - var state = this._reporterState; + return { + a: C, + b: D, + gcd: y.iushln(g), + }; + }; - var inherited = msg instanceof ReporterError; - if (inherited) { - err = msg; - } else { - err = new ReporterError(state.path.map(function(elem) { - return '[' + JSON.stringify(elem) + ']'; - }).join(''), msg.message || msg, msg.stack); - } + // This is reduced incarnation of the binary EEA + // above, designated to invert members of the + // _prime_ fields F(p) at a maximal speed + BN.prototype._invmp = function _invmp(p) { + assert(p.negative === 0); + assert(!p.isZero()); - if (!state.options.partial) - throw err; - - if (!inherited) - state.errors.push(err); - - return err; -}; - -Reporter.prototype.wrapResult = function wrapResult(result) { - var state = this._reporterState; - if (!state.options.partial) - return result; - - return { - result: this.isError(result) ? null : result, - errors: state.errors - }; -}; - -function ReporterError(path, msg) { - this.path = path; - this.rethrow(msg); -}; -inherits(ReporterError, Error); - -ReporterError.prototype.rethrow = function rethrow(msg) { - this.message = msg + ' at: ' + (this.path || '(shallow)'); - if (Error.captureStackTrace) - Error.captureStackTrace(this, ReporterError); - - if (!this.stack) { - try { - // IE only adds stack when thrown - throw new Error(this.message); - } catch (e) { - this.stack = e.stack; - } - } - return this; -}; - -},{"inherits":184}],51:[function(require,module,exports){ -var constants = require('../constants'); - -exports.tagClass = { - 0: 'universal', - 1: 'application', - 2: 'context', - 3: 'private' -}; -exports.tagClassByName = constants._reverse(exports.tagClass); - -exports.tag = { - 0x00: 'end', - 0x01: 'bool', - 0x02: 'int', - 0x03: 'bitstr', - 0x04: 'octstr', - 0x05: 'null_', - 0x06: 'objid', - 0x07: 'objDesc', - 0x08: 'external', - 0x09: 'real', - 0x0a: 'enum', - 0x0b: 'embed', - 0x0c: 'utf8str', - 0x0d: 'relativeOid', - 0x10: 'seq', - 0x11: 'set', - 0x12: 'numstr', - 0x13: 'printstr', - 0x14: 't61str', - 0x15: 'videostr', - 0x16: 'ia5str', - 0x17: 'utctime', - 0x18: 'gentime', - 0x19: 'graphstr', - 0x1a: 'iso646str', - 0x1b: 'genstr', - 0x1c: 'unistr', - 0x1d: 'charstr', - 0x1e: 'bmpstr' -}; -exports.tagByName = constants._reverse(exports.tag); - -},{"../constants":52}],52:[function(require,module,exports){ -var constants = exports; - -// Helper -constants._reverse = function reverse(map) { - var res = {}; - - Object.keys(map).forEach(function(key) { - // Convert key to integer if it is stringified - if ((key | 0) == key) - key = key | 0; - - var value = map[key]; - res[value] = key; - }); - - return res; -}; - -constants.der = require('./der'); - -},{"./der":51}],53:[function(require,module,exports){ -var inherits = require('inherits'); - -var asn1 = require('../../asn1'); -var base = asn1.base; -var bignum = asn1.bignum; - -// Import DER constants -var der = asn1.constants.der; - -function DERDecoder(entity) { - this.enc = 'der'; - this.name = entity.name; - this.entity = entity; - - // Construct base tree - this.tree = new DERNode(); - this.tree._init(entity.body); -}; -module.exports = DERDecoder; - -DERDecoder.prototype.decode = function decode(data, options) { - if (!(data instanceof base.DecoderBuffer)) - data = new base.DecoderBuffer(data, options); - - return this.tree._decode(data, options); -}; - -// Tree methods - -function DERNode(parent) { - base.Node.call(this, 'der', parent); -} -inherits(DERNode, base.Node); - -DERNode.prototype._peekTag = function peekTag(buffer, tag, any) { - if (buffer.isEmpty()) - return false; - - var state = buffer.save(); - var decodedTag = derDecodeTag(buffer, 'Failed to peek tag: "' + tag + '"'); - if (buffer.isError(decodedTag)) - return decodedTag; - - buffer.restore(state); - - return decodedTag.tag === tag || decodedTag.tagStr === tag || - (decodedTag.tagStr + 'of') === tag || any; -}; - -DERNode.prototype._decodeTag = function decodeTag(buffer, tag, any) { - var decodedTag = derDecodeTag(buffer, - 'Failed to decode tag of "' + tag + '"'); - if (buffer.isError(decodedTag)) - return decodedTag; - - var len = derDecodeLen(buffer, - decodedTag.primitive, - 'Failed to get length of "' + tag + '"'); - - // Failure - if (buffer.isError(len)) - return len; - - if (!any && - decodedTag.tag !== tag && - decodedTag.tagStr !== tag && - decodedTag.tagStr + 'of' !== tag) { - return buffer.error('Failed to match tag: "' + tag + '"'); - } + var a = this; + var b = p.clone(); - if (decodedTag.primitive || len !== null) - return buffer.skip(len, 'Failed to match body of: "' + tag + '"'); - - // Indefinite length... find END tag - var state = buffer.save(); - var res = this._skipUntilEnd( - buffer, - 'Failed to skip indefinite length body: "' + this.tag + '"'); - if (buffer.isError(res)) - return res; - - len = buffer.offset - state.offset; - buffer.restore(state); - return buffer.skip(len, 'Failed to match body of: "' + tag + '"'); -}; - -DERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer, fail) { - while (true) { - var tag = derDecodeTag(buffer, fail); - if (buffer.isError(tag)) - return tag; - var len = derDecodeLen(buffer, tag.primitive, fail); - if (buffer.isError(len)) - return len; - - var res; - if (tag.primitive || len !== null) - res = buffer.skip(len) - else - res = this._skipUntilEnd(buffer, fail); - - // Failure - if (buffer.isError(res)) - return res; - - if (tag.tagStr === 'end') - break; - } -}; - -DERNode.prototype._decodeList = function decodeList(buffer, tag, decoder, - options) { - var result = []; - while (!buffer.isEmpty()) { - var possibleEnd = this._peekTag(buffer, 'end'); - if (buffer.isError(possibleEnd)) - return possibleEnd; - - var res = decoder.decode(buffer, 'der', options); - if (buffer.isError(res) && possibleEnd) - break; - result.push(res); - } - return result; -}; - -DERNode.prototype._decodeStr = function decodeStr(buffer, tag) { - if (tag === 'bitstr') { - var unused = buffer.readUInt8(); - if (buffer.isError(unused)) - return unused; - return { unused: unused, data: buffer.raw() }; - } else if (tag === 'bmpstr') { - var raw = buffer.raw(); - if (raw.length % 2 === 1) - return buffer.error('Decoding of string type: bmpstr length mismatch'); - - var str = ''; - for (var i = 0; i < raw.length / 2; i++) { - str += String.fromCharCode(raw.readUInt16BE(i * 2)); - } - return str; - } else if (tag === 'numstr') { - var numstr = buffer.raw().toString('ascii'); - if (!this._isNumstr(numstr)) { - return buffer.error('Decoding of string type: ' + - 'numstr unsupported characters'); - } - return numstr; - } else if (tag === 'octstr') { - return buffer.raw(); - } else if (tag === 'objDesc') { - return buffer.raw(); - } else if (tag === 'printstr') { - var printstr = buffer.raw().toString('ascii'); - if (!this._isPrintstr(printstr)) { - return buffer.error('Decoding of string type: ' + - 'printstr unsupported characters'); - } - return printstr; - } else if (/str$/.test(tag)) { - return buffer.raw().toString(); - } else { - return buffer.error('Decoding of string type: ' + tag + ' unsupported'); - } -}; - -DERNode.prototype._decodeObjid = function decodeObjid(buffer, values, relative) { - var result; - var identifiers = []; - var ident = 0; - while (!buffer.isEmpty()) { - var subident = buffer.readUInt8(); - ident <<= 7; - ident |= subident & 0x7f; - if ((subident & 0x80) === 0) { - identifiers.push(ident); - ident = 0; - } - } - if (subident & 0x80) - identifiers.push(ident); - - var first = (identifiers[0] / 40) | 0; - var second = identifiers[0] % 40; - - if (relative) - result = identifiers; - else - result = [first, second].concat(identifiers.slice(1)); - - if (values) { - var tmp = values[result.join(' ')]; - if (tmp === undefined) - tmp = values[result.join('.')]; - if (tmp !== undefined) - result = tmp; - } + if (a.negative !== 0) { + a = a.umod(p); + } else { + a = a.clone(); + } - return result; -}; - -DERNode.prototype._decodeTime = function decodeTime(buffer, tag) { - var str = buffer.raw().toString(); - if (tag === 'gentime') { - var year = str.slice(0, 4) | 0; - var mon = str.slice(4, 6) | 0; - var day = str.slice(6, 8) | 0; - var hour = str.slice(8, 10) | 0; - var min = str.slice(10, 12) | 0; - var sec = str.slice(12, 14) | 0; - } else if (tag === 'utctime') { - var year = str.slice(0, 2) | 0; - var mon = str.slice(2, 4) | 0; - var day = str.slice(4, 6) | 0; - var hour = str.slice(6, 8) | 0; - var min = str.slice(8, 10) | 0; - var sec = str.slice(10, 12) | 0; - if (year < 70) - year = 2000 + year; - else - year = 1900 + year; - } else { - return buffer.error('Decoding ' + tag + ' time is not supported yet'); - } + var x1 = new BN(1); + var x2 = new BN(0); - return Date.UTC(year, mon - 1, day, hour, min, sec, 0); -}; - -DERNode.prototype._decodeNull = function decodeNull(buffer) { - return null; -}; - -DERNode.prototype._decodeBool = function decodeBool(buffer) { - var res = buffer.readUInt8(); - if (buffer.isError(res)) - return res; - else - return res !== 0; -}; - -DERNode.prototype._decodeInt = function decodeInt(buffer, values) { - // Bigint, return as it is (assume big endian) - var raw = buffer.raw(); - var res = new bignum(raw); - - if (values) - res = values[res.toString(10)] || res; - - return res; -}; - -DERNode.prototype._use = function use(entity, obj) { - if (typeof entity === 'function') - entity = entity(obj); - return entity._getDecoder('der').tree; -}; - -// Utility methods - -function derDecodeTag(buf, fail) { - var tag = buf.readUInt8(fail); - if (buf.isError(tag)) - return tag; - - var cls = der.tagClass[tag >> 6]; - var primitive = (tag & 0x20) === 0; - - // Multi-octet tag - load - if ((tag & 0x1f) === 0x1f) { - var oct = tag; - tag = 0; - while ((oct & 0x80) === 0x80) { - oct = buf.readUInt8(fail); - if (buf.isError(oct)) - return oct; - - tag <<= 7; - tag |= oct & 0x7f; - } - } else { - tag &= 0x1f; - } - var tagStr = der.tag[tag]; - - return { - cls: cls, - primitive: primitive, - tag: tag, - tagStr: tagStr - }; -} + var delta = b.clone(); -function derDecodeLen(buf, primitive, fail) { - var len = buf.readUInt8(fail); - if (buf.isError(len)) - return len; + while (a.cmpn(1) > 0 && b.cmpn(1) > 0) { + for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1); + if (i > 0) { + a.iushrn(i); + while (i-- > 0) { + if (x1.isOdd()) { + x1.iadd(delta); + } - // Indefinite form - if (!primitive && len === 0x80) - return null; + x1.iushrn(1); + } + } - // Definite form - if ((len & 0x80) === 0) { - // Short form - return len; - } + for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); + if (j > 0) { + b.iushrn(j); + while (j-- > 0) { + if (x2.isOdd()) { + x2.iadd(delta); + } - // Long form - var num = len & 0x7f; - if (num > 4) - return buf.error('length octect is too long'); - - len = 0; - for (var i = 0; i < num; i++) { - len <<= 8; - var j = buf.readUInt8(fail); - if (buf.isError(j)) - return j; - len |= j; - } + x2.iushrn(1); + } + } - return len; -} + if (a.cmp(b) >= 0) { + a.isub(b); + x1.isub(x2); + } else { + b.isub(a); + x2.isub(x1); + } + } -},{"../../asn1":45,"inherits":184}],54:[function(require,module,exports){ -var decoders = exports; - -decoders.der = require('./der'); -decoders.pem = require('./pem'); - -},{"./der":53,"./pem":55}],55:[function(require,module,exports){ -var inherits = require('inherits'); -var Buffer = require('buffer').Buffer; - -var DERDecoder = require('./der'); - -function PEMDecoder(entity) { - DERDecoder.call(this, entity); - this.enc = 'pem'; -}; -inherits(PEMDecoder, DERDecoder); -module.exports = PEMDecoder; - -PEMDecoder.prototype.decode = function decode(data, options) { - var lines = data.toString().split(/[\r\n]+/g); - - var label = options.label.toUpperCase(); - - var re = /^-----(BEGIN|END) ([^-]+)-----$/; - var start = -1; - var end = -1; - for (var i = 0; i < lines.length; i++) { - var match = lines[i].match(re); - if (match === null) - continue; - - if (match[2] !== label) - continue; - - if (start === -1) { - if (match[1] !== 'BEGIN') - break; - start = i; - } else { - if (match[1] !== 'END') - break; - end = i; - break; - } - } - if (start === -1 || end === -1) - throw new Error('PEM section not found for: ' + label); + var res; + if (a.cmpn(1) === 0) { + res = x1; + } else { + res = x2; + } - var base64 = lines.slice(start + 1, end).join(''); - // Remove excessive symbols - base64.replace(/[^a-z0-9\+\/=]+/gi, ''); + if (res.cmpn(0) < 0) { + res.iadd(p); + } - var input = new Buffer(base64, 'base64'); - return DERDecoder.prototype.decode.call(this, input, options); -}; + return res; + }; -},{"./der":53,"buffer":113,"inherits":184}],56:[function(require,module,exports){ -var inherits = require('inherits'); -var Buffer = require('buffer').Buffer; + BN.prototype.gcd = function gcd(num) { + if (this.isZero()) return num.abs(); + if (num.isZero()) return this.abs(); -var asn1 = require('../../asn1'); -var base = asn1.base; + var a = this.clone(); + var b = num.clone(); + a.negative = 0; + b.negative = 0; -// Import DER constants -var der = asn1.constants.der; + // Remove common factor of two + for (var shift = 0; a.isEven() && b.isEven(); shift++) { + a.iushrn(1); + b.iushrn(1); + } -function DEREncoder(entity) { - this.enc = 'der'; - this.name = entity.name; - this.entity = entity; + do { + while (a.isEven()) { + a.iushrn(1); + } + while (b.isEven()) { + b.iushrn(1); + } - // Construct base tree - this.tree = new DERNode(); - this.tree._init(entity.body); -}; -module.exports = DEREncoder; + var r = a.cmp(b); + if (r < 0) { + // Swap `a` and `b` to make `a` always bigger than `b` + var t = a; + a = b; + b = t; + } else if (r === 0 || b.cmpn(1) === 0) { + break; + } -DEREncoder.prototype.encode = function encode(data, reporter) { - return this.tree._encode(data, reporter).join(); -}; + a.isub(b); + } while (true); + + return b.iushln(shift); + }; + + // Invert number in the field F(num) + BN.prototype.invm = function invm(num) { + return this.egcd(num).a.umod(num); + }; + + BN.prototype.isEven = function isEven() { + return (this.words[0] & 1) === 0; + }; + + BN.prototype.isOdd = function isOdd() { + return (this.words[0] & 1) === 1; + }; + + // And first word and num + BN.prototype.andln = function andln(num) { + return this.words[0] & num; + }; + + // Increment at the bit position in-line + BN.prototype.bincn = function bincn(bit) { + assert(typeof bit === 'number'); + var r = bit % 26; + var s = (bit - r) / 26; + var q = 1 << r; + + // Fast case: bit is much higher than all existing words + if (this.length <= s) { + this._expand(s + 1); + this.words[s] |= q; + return this; + } -// Tree methods + // Add bit and propagate, if needed + var carry = q; + for (var i = s; carry !== 0 && i < this.length; i++) { + var w = this.words[i] | 0; + w += carry; + carry = w >>> 26; + w &= 0x3ffffff; + this.words[i] = w; + } + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } + return this; + }; -function DERNode(parent) { - base.Node.call(this, 'der', parent); -} -inherits(DERNode, base.Node); - -DERNode.prototype._encodeComposite = function encodeComposite(tag, - primitive, - cls, - content) { - var encodedTag = encodeTag(tag, primitive, cls, this.reporter); - - // Short form - if (content.length < 0x80) { - var header = new Buffer(2); - header[0] = encodedTag; - header[1] = content.length; - return this._createEncoderBuffer([ header, content ]); - } + BN.prototype.isZero = function isZero() { + return this.length === 1 && this.words[0] === 0; + }; - // Long form - // Count octets required to store length - var lenOctets = 1; - for (var i = content.length; i >= 0x100; i >>= 8) - lenOctets++; - - var header = new Buffer(1 + 1 + lenOctets); - header[0] = encodedTag; - header[1] = 0x80 | lenOctets; - - for (var i = 1 + lenOctets, j = content.length; j > 0; i--, j >>= 8) - header[i] = j & 0xff; - - return this._createEncoderBuffer([ header, content ]); -}; - -DERNode.prototype._encodeStr = function encodeStr(str, tag) { - if (tag === 'bitstr') { - return this._createEncoderBuffer([ str.unused | 0, str.data ]); - } else if (tag === 'bmpstr') { - var buf = new Buffer(str.length * 2); - for (var i = 0; i < str.length; i++) { - buf.writeUInt16BE(str.charCodeAt(i), i * 2); - } - return this._createEncoderBuffer(buf); - } else if (tag === 'numstr') { - if (!this._isNumstr(str)) { - return this.reporter.error('Encoding of string type: numstr supports ' + - 'only digits and space'); - } - return this._createEncoderBuffer(str); - } else if (tag === 'printstr') { - if (!this._isPrintstr(str)) { - return this.reporter.error('Encoding of string type: printstr supports ' + - 'only latin upper and lower case letters, ' + - 'digits, space, apostrophe, left and rigth ' + - 'parenthesis, plus sign, comma, hyphen, ' + - 'dot, slash, colon, equal sign, ' + - 'question mark'); - } - return this._createEncoderBuffer(str); - } else if (/str$/.test(tag)) { - return this._createEncoderBuffer(str); - } else if (tag === 'objDesc') { - return this._createEncoderBuffer(str); - } else { - return this.reporter.error('Encoding of string type: ' + tag + - ' unsupported'); - } -}; - -DERNode.prototype._encodeObjid = function encodeObjid(id, values, relative) { - if (typeof id === 'string') { - if (!values) - return this.reporter.error('string objid given, but no values map found'); - if (!values.hasOwnProperty(id)) - return this.reporter.error('objid not found in values map'); - id = values[id].split(/[\s\.]+/g); - for (var i = 0; i < id.length; i++) - id[i] |= 0; - } else if (Array.isArray(id)) { - id = id.slice(); - for (var i = 0; i < id.length; i++) - id[i] |= 0; - } + BN.prototype.cmpn = function cmpn(num) { + var negative = num < 0; - if (!Array.isArray(id)) { - return this.reporter.error('objid() should be either array or string, ' + - 'got: ' + JSON.stringify(id)); - } + if (this.negative !== 0 && !negative) return -1; + if (this.negative === 0 && negative) return 1; - if (!relative) { - if (id[1] >= 40) - return this.reporter.error('Second objid identifier OOB'); - id.splice(0, 2, id[0] * 40 + id[1]); - } + this.strip(); - // Count number of octets - var size = 0; - for (var i = 0; i < id.length; i++) { - var ident = id[i]; - for (size++; ident >= 0x80; ident >>= 7) - size++; - } + var res; + if (this.length > 1) { + res = 1; + } else { + if (negative) { + num = -num; + } - var objid = new Buffer(size); - var offset = objid.length - 1; - for (var i = id.length - 1; i >= 0; i--) { - var ident = id[i]; - objid[offset--] = ident & 0x7f; - while ((ident >>= 7) > 0) - objid[offset--] = 0x80 | (ident & 0x7f); - } + assert(num <= 0x3ffffff, 'Number is too big'); - return this._createEncoderBuffer(objid); -}; + var w = this.words[0] | 0; + res = w === num ? 0 : w < num ? -1 : 1; + } + if (this.negative !== 0) return -res | 0; + return res; + }; + + // Compare two numbers and return: + // 1 - if `this` > `num` + // 0 - if `this` == `num` + // -1 - if `this` < `num` + BN.prototype.cmp = function cmp(num) { + if (this.negative !== 0 && num.negative === 0) return -1; + if (this.negative === 0 && num.negative !== 0) return 1; + + var res = this.ucmp(num); + if (this.negative !== 0) return -res | 0; + return res; + }; + + // Unsigned comparison + BN.prototype.ucmp = function ucmp(num) { + // At this point both numbers have the same sign + if (this.length > num.length) return 1; + if (this.length < num.length) return -1; + + var res = 0; + for (var i = this.length - 1; i >= 0; i--) { + var a = this.words[i] | 0; + var b = num.words[i] | 0; + + if (a === b) continue; + if (a < b) { + res = -1; + } else if (a > b) { + res = 1; + } + break; + } + return res; + }; -function two(num) { - if (num < 10) - return '0' + num; - else - return num; -} + BN.prototype.gtn = function gtn(num) { + return this.cmpn(num) === 1; + }; -DERNode.prototype._encodeTime = function encodeTime(time, tag) { - var str; - var date = new Date(time); - - if (tag === 'gentime') { - str = [ - two(date.getFullYear()), - two(date.getUTCMonth() + 1), - two(date.getUTCDate()), - two(date.getUTCHours()), - two(date.getUTCMinutes()), - two(date.getUTCSeconds()), - 'Z' - ].join(''); - } else if (tag === 'utctime') { - str = [ - two(date.getFullYear() % 100), - two(date.getUTCMonth() + 1), - two(date.getUTCDate()), - two(date.getUTCHours()), - two(date.getUTCMinutes()), - two(date.getUTCSeconds()), - 'Z' - ].join(''); - } else { - this.reporter.error('Encoding ' + tag + ' time is not supported yet'); - } + BN.prototype.gt = function gt(num) { + return this.cmp(num) === 1; + }; - return this._encodeStr(str, 'octstr'); -}; + BN.prototype.gten = function gten(num) { + return this.cmpn(num) >= 0; + }; -DERNode.prototype._encodeNull = function encodeNull() { - return this._createEncoderBuffer(''); -}; + BN.prototype.gte = function gte(num) { + return this.cmp(num) >= 0; + }; -DERNode.prototype._encodeInt = function encodeInt(num, values) { - if (typeof num === 'string') { - if (!values) - return this.reporter.error('String int or enum given, but no values map'); - if (!values.hasOwnProperty(num)) { - return this.reporter.error('Values map doesn\'t contain: ' + - JSON.stringify(num)); - } - num = values[num]; - } + BN.prototype.ltn = function ltn(num) { + return this.cmpn(num) === -1; + }; - // Bignum, assume big endian - if (typeof num !== 'number' && !Buffer.isBuffer(num)) { - var numArray = num.toArray(); - if (!num.sign && numArray[0] & 0x80) { - numArray.unshift(0); - } - num = new Buffer(numArray); - } + BN.prototype.lt = function lt(num) { + return this.cmp(num) === -1; + }; - if (Buffer.isBuffer(num)) { - var size = num.length; - if (num.length === 0) - size++; + BN.prototype.lten = function lten(num) { + return this.cmpn(num) <= 0; + }; - var out = new Buffer(size); - num.copy(out); - if (num.length === 0) - out[0] = 0 - return this._createEncoderBuffer(out); - } + BN.prototype.lte = function lte(num) { + return this.cmp(num) <= 0; + }; - if (num < 0x80) - return this._createEncoderBuffer(num); + BN.prototype.eqn = function eqn(num) { + return this.cmpn(num) === 0; + }; - if (num < 0x100) - return this._createEncoderBuffer([0, num]); + BN.prototype.eq = function eq(num) { + return this.cmp(num) === 0; + }; - var size = 1; - for (var i = num; i >= 0x100; i >>= 8) - size++; + // + // A reduce context, could be using montgomery or something better, depending + // on the `m` itself. + // + BN.red = function red(num) { + return new Red(num); + }; + + BN.prototype.toRed = function toRed(ctx) { + assert(!this.red, 'Already a number in reduction context'); + assert(this.negative === 0, 'red works only with positives'); + return ctx.convertTo(this)._forceRed(ctx); + }; + + BN.prototype.fromRed = function fromRed() { + assert(this.red, 'fromRed works only with numbers in reduction context'); + return this.red.convertFrom(this); + }; + + BN.prototype._forceRed = function _forceRed(ctx) { + this.red = ctx; + return this; + }; + + BN.prototype.forceRed = function forceRed(ctx) { + assert(!this.red, 'Already a number in reduction context'); + return this._forceRed(ctx); + }; + + BN.prototype.redAdd = function redAdd(num) { + assert(this.red, 'redAdd works only with red numbers'); + return this.red.add(this, num); + }; + + BN.prototype.redIAdd = function redIAdd(num) { + assert(this.red, 'redIAdd works only with red numbers'); + return this.red.iadd(this, num); + }; + + BN.prototype.redSub = function redSub(num) { + assert(this.red, 'redSub works only with red numbers'); + return this.red.sub(this, num); + }; + + BN.prototype.redISub = function redISub(num) { + assert(this.red, 'redISub works only with red numbers'); + return this.red.isub(this, num); + }; + + BN.prototype.redShl = function redShl(num) { + assert(this.red, 'redShl works only with red numbers'); + return this.red.shl(this, num); + }; + + BN.prototype.redMul = function redMul(num) { + assert(this.red, 'redMul works only with red numbers'); + this.red._verify2(this, num); + return this.red.mul(this, num); + }; + + BN.prototype.redIMul = function redIMul(num) { + assert(this.red, 'redMul works only with red numbers'); + this.red._verify2(this, num); + return this.red.imul(this, num); + }; + + BN.prototype.redSqr = function redSqr() { + assert(this.red, 'redSqr works only with red numbers'); + this.red._verify1(this); + return this.red.sqr(this); + }; + + BN.prototype.redISqr = function redISqr() { + assert(this.red, 'redISqr works only with red numbers'); + this.red._verify1(this); + return this.red.isqr(this); + }; + + // Square root over p + BN.prototype.redSqrt = function redSqrt() { + assert(this.red, 'redSqrt works only with red numbers'); + this.red._verify1(this); + return this.red.sqrt(this); + }; + + BN.prototype.redInvm = function redInvm() { + assert(this.red, 'redInvm works only with red numbers'); + this.red._verify1(this); + return this.red.invm(this); + }; + + // Return negative clone of `this` % `red modulo` + BN.prototype.redNeg = function redNeg() { + assert(this.red, 'redNeg works only with red numbers'); + this.red._verify1(this); + return this.red.neg(this); + }; + + BN.prototype.redPow = function redPow(num) { + assert(this.red && !num.red, 'redPow(normalNum)'); + this.red._verify1(this); + return this.red.pow(this, num); + }; + + // Prime numbers with efficient reduction + var primes = { + k256: null, + p224: null, + p192: null, + p25519: null, + }; + + // Pseudo-Mersenne prime + function MPrime(name, p) { + // P = 2 ^ N - K + this.name = name; + this.p = new BN(p, 16); + this.n = this.p.bitLength(); + this.k = new BN(1).iushln(this.n).isub(this.p); + + this.tmp = this._tmp(); + } - var out = new Array(size); - for (var i = out.length - 1; i >= 0; i--) { - out[i] = num & 0xff; - num >>= 8; - } - if(out[0] & 0x80) { - out.unshift(0); - } + MPrime.prototype._tmp = function _tmp() { + var tmp = new BN(null); + tmp.words = new Array(Math.ceil(this.n / 13)); + return tmp; + }; + + MPrime.prototype.ireduce = function ireduce(num) { + // Assumes that `num` is less than `P^2` + // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P) + var r = num; + var rlen; + + do { + this.split(r, this.tmp); + r = this.imulK(r); + r = r.iadd(this.tmp); + rlen = r.bitLength(); + } while (rlen > this.n); + + var cmp = rlen < this.n ? -1 : r.ucmp(this.p); + if (cmp === 0) { + r.words[0] = 0; + r.length = 1; + } else if (cmp > 0) { + r.isub(this.p); + } else { + r.strip(); + } - return this._createEncoderBuffer(new Buffer(out)); -}; + return r; + }; -DERNode.prototype._encodeBool = function encodeBool(value) { - return this._createEncoderBuffer(value ? 0xff : 0); -}; + MPrime.prototype.split = function split(input, out) { + input.iushrn(this.n, 0, out); + }; -DERNode.prototype._use = function use(entity, obj) { - if (typeof entity === 'function') - entity = entity(obj); - return entity._getEncoder('der').tree; -}; + MPrime.prototype.imulK = function imulK(num) { + return num.imul(this.k); + }; -DERNode.prototype._skipDefault = function skipDefault(dataBuffer, reporter, parent) { - var state = this._baseState; - var i; - if (state['default'] === null) - return false; + function K256() { + MPrime.call(this, 'k256', 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f'); + } + inherits(K256, MPrime); - var data = dataBuffer.join(); - if (state.defaultBuffer === undefined) - state.defaultBuffer = this._encodeValue(state['default'], reporter, parent).join(); + K256.prototype.split = function split(input, output) { + // 256 = 9 * 26 + 22 + var mask = 0x3fffff; - if (data.length !== state.defaultBuffer.length) - return false; + var outLen = Math.min(input.length, 9); + for (var i = 0; i < outLen; i++) { + output.words[i] = input.words[i]; + } + output.length = outLen; - for (i=0; i < data.length; i++) - if (data[i] !== state.defaultBuffer[i]) - return false; + if (input.length <= 9) { + input.words[0] = 0; + input.length = 1; + return; + } - return true; -}; + // Shift by 9 limbs + var prev = input.words[9]; + output.words[output.length++] = prev & mask; -// Utility methods + for (i = 10; i < input.length; i++) { + var next = input.words[i] | 0; + input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22); + prev = next; + } + prev >>>= 22; + input.words[i - 10] = prev; + if (prev === 0 && input.length > 10) { + input.length -= 10; + } else { + input.length -= 9; + } + }; + + K256.prototype.imulK = function imulK(num) { + // K = 0x1000003d1 = [ 0x40, 0x3d1 ] + num.words[num.length] = 0; + num.words[num.length + 1] = 0; + num.length += 2; + + // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390 + var lo = 0; + for (var i = 0; i < num.length; i++) { + var w = num.words[i] | 0; + lo += w * 0x3d1; + num.words[i] = lo & 0x3ffffff; + lo = w * 0x40 + ((lo / 0x4000000) | 0); + } -function encodeTag(tag, primitive, cls, reporter) { - var res; + // Fast length reduction + if (num.words[num.length - 1] === 0) { + num.length--; + if (num.words[num.length - 1] === 0) { + num.length--; + } + } + return num; + }; - if (tag === 'seqof') - tag = 'seq'; - else if (tag === 'setof') - tag = 'set'; + function P224() { + MPrime.call(this, 'p224', 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001'); + } + inherits(P224, MPrime); - if (der.tagByName.hasOwnProperty(tag)) - res = der.tagByName[tag]; - else if (typeof tag === 'number' && (tag | 0) === tag) - res = tag; - else - return reporter.error('Unknown tag: ' + tag); + function P192() { + MPrime.call(this, 'p192', 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff'); + } + inherits(P192, MPrime); - if (res >= 0x1f) - return reporter.error('Multi-octet tag encoding unsupported'); + function P25519() { + // 2 ^ 255 - 19 + MPrime.call(this, '25519', '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed'); + } + inherits(P25519, MPrime); + + P25519.prototype.imulK = function imulK(num) { + // K = 0x13 + var carry = 0; + for (var i = 0; i < num.length; i++) { + var hi = (num.words[i] | 0) * 0x13 + carry; + var lo = hi & 0x3ffffff; + hi >>>= 26; + + num.words[i] = lo; + carry = hi; + } + if (carry !== 0) { + num.words[num.length++] = carry; + } + return num; + }; + + // Exported mostly for testing purposes, use plain name instead + BN._prime = function prime(name) { + // Cached version of prime + if (primes[name]) return primes[name]; + + var prime; + if (name === 'k256') { + prime = new K256(); + } else if (name === 'p224') { + prime = new P224(); + } else if (name === 'p192') { + prime = new P192(); + } else if (name === 'p25519') { + prime = new P25519(); + } else { + throw new Error('Unknown prime ' + name); + } + primes[name] = prime; - if (!primitive) - res |= 0x20; + return prime; + }; - res |= (der.tagClassByName[cls || 'universal'] << 6); + // + // Base reduction engine + // + function Red(m) { + if (typeof m === 'string') { + var prime = BN._prime(m); + this.m = prime.p; + this.prime = prime; + } else { + assert(m.gtn(1), 'modulus must be greater than 1'); + this.m = m; + this.prime = null; + } + } - return res; -} + Red.prototype._verify1 = function _verify1(a) { + assert(a.negative === 0, 'red works only with positives'); + assert(a.red, 'red works only with red numbers'); + }; -},{"../../asn1":45,"buffer":113,"inherits":184}],57:[function(require,module,exports){ -var encoders = exports; + Red.prototype._verify2 = function _verify2(a, b) { + assert((a.negative | b.negative) === 0, 'red works only with positives'); + assert(a.red && a.red === b.red, 'red works only with red numbers'); + }; -encoders.der = require('./der'); -encoders.pem = require('./pem'); + Red.prototype.imod = function imod(a) { + if (this.prime) return this.prime.ireduce(a)._forceRed(this); + return a.umod(this.m)._forceRed(this); + }; -},{"./der":56,"./pem":58}],58:[function(require,module,exports){ -var inherits = require('inherits'); + Red.prototype.neg = function neg(a) { + if (a.isZero()) { + return a.clone(); + } -var DEREncoder = require('./der'); + return this.m.sub(a)._forceRed(this); + }; -function PEMEncoder(entity) { - DEREncoder.call(this, entity); - this.enc = 'pem'; -}; -inherits(PEMEncoder, DEREncoder); -module.exports = PEMEncoder; + Red.prototype.add = function add(a, b) { + this._verify2(a, b); -PEMEncoder.prototype.encode = function encode(data, options) { - var buf = DEREncoder.prototype.encode.call(this, data); + var res = a.add(b); + if (res.cmp(this.m) >= 0) { + res.isub(this.m); + } + return res._forceRed(this); + }; - var p = buf.toString('base64'); - var out = [ '-----BEGIN ' + options.label + '-----' ]; - for (var i = 0; i < p.length; i += 64) - out.push(p.slice(i, i + 64)); - out.push('-----END ' + options.label + '-----'); - return out.join('\n'); -}; + Red.prototype.iadd = function iadd(a, b) { + this._verify2(a, b); -},{"./der":56,"inherits":184}],59:[function(require,module,exports){ -(function (module, exports) { - 'use strict'; + var res = a.iadd(b); + if (res.cmp(this.m) >= 0) { + res.isub(this.m); + } + return res; + }; - // Utils - function assert (val, msg) { - if (!val) throw new Error(msg || 'Assertion failed'); - } + Red.prototype.sub = function sub(a, b) { + this._verify2(a, b); - // Could use `inherits` module, but don't want to move from single file - // architecture yet. - function inherits (ctor, superCtor) { - ctor.super_ = superCtor; - var TempCtor = function () {}; - TempCtor.prototype = superCtor.prototype; - ctor.prototype = new TempCtor(); - ctor.prototype.constructor = ctor; - } + var res = a.sub(b); + if (res.cmpn(0) < 0) { + res.iadd(this.m); + } + return res._forceRed(this); + }; - // BN + Red.prototype.isub = function isub(a, b) { + this._verify2(a, b); - function BN (number, base, endian) { - if (BN.isBN(number)) { - return number; - } + var res = a.isub(b); + if (res.cmpn(0) < 0) { + res.iadd(this.m); + } + return res; + }; + + Red.prototype.shl = function shl(a, num) { + this._verify1(a); + return this.imod(a.ushln(num)); + }; + + Red.prototype.imul = function imul(a, b) { + this._verify2(a, b); + return this.imod(a.imul(b)); + }; + + Red.prototype.mul = function mul(a, b) { + this._verify2(a, b); + return this.imod(a.mul(b)); + }; + + Red.prototype.isqr = function isqr(a) { + return this.imul(a, a.clone()); + }; + + Red.prototype.sqr = function sqr(a) { + return this.mul(a, a); + }; + + Red.prototype.sqrt = function sqrt(a) { + if (a.isZero()) return a.clone(); + + var mod3 = this.m.andln(3); + assert(mod3 % 2 === 1); + + // Fast case + if (mod3 === 3) { + var pow = this.m.add(new BN(1)).iushrn(2); + return this.pow(a, pow); + } - this.negative = 0; - this.words = null; - this.length = 0; + // Tonelli-Shanks algorithm (Totally unoptimized and slow) + // + // Find Q and S, that Q * 2 ^ S = (P - 1) + var q = this.m.subn(1); + var s = 0; + while (!q.isZero() && q.andln(1) === 0) { + s++; + q.iushrn(1); + } + assert(!q.isZero()); - // Reduction context - this.red = null; + var one = new BN(1).toRed(this); + var nOne = one.redNeg(); - if (number !== null) { - if (base === 'le' || base === 'be') { - endian = base; - base = 10; - } + // Find quadratic non-residue + // NOTE: Max is such because of generalized Riemann hypothesis. + var lpow = this.m.subn(1).iushrn(1); + var z = this.m.bitLength(); + z = new BN(2 * z * z).toRed(this); - this._init(number || 0, base || 10, endian || 'be'); - } - } - if (typeof module === 'object') { - module.exports = BN; - } else { - exports.BN = BN; - } + while (this.pow(z, lpow).cmp(nOne) !== 0) { + z.redIAdd(nOne); + } - BN.BN = BN; - BN.wordSize = 26; + var c = this.pow(z, q); + var r = this.pow(a, q.addn(1).iushrn(1)); + var t = this.pow(a, q); + var m = s; + while (t.cmp(one) !== 0) { + var tmp = t; + for (var i = 0; tmp.cmp(one) !== 0; i++) { + tmp = tmp.redSqr(); + } + assert(i < m); + var b = this.pow(c, new BN(1).iushln(m - i - 1)); - var Buffer; - try { - Buffer = require('buffer').Buffer; - } catch (e) { - } + r = r.redMul(b); + c = b.redSqr(); + t = t.redMul(c); + m = i; + } - BN.isBN = function isBN (num) { - if (num instanceof BN) { - return true; - } + return r; + }; - return num !== null && typeof num === 'object' && - num.constructor.wordSize === BN.wordSize && Array.isArray(num.words); - }; + Red.prototype.invm = function invm(a) { + var inv = a._invmp(this.m); + if (inv.negative !== 0) { + inv.negative = 0; + return this.imod(inv).redNeg(); + } else { + return this.imod(inv); + } + }; + + Red.prototype.pow = function pow(a, num) { + if (num.isZero()) return new BN(1).toRed(this); + if (num.cmpn(1) === 0) return a.clone(); + + var windowSize = 4; + var wnd = new Array(1 << windowSize); + wnd[0] = new BN(1).toRed(this); + wnd[1] = a; + for (var i = 2; i < wnd.length; i++) { + wnd[i] = this.mul(wnd[i - 1], a); + } - BN.max = function max (left, right) { - if (left.cmp(right) > 0) return left; - return right; - }; + var res = wnd[0]; + var current = 0; + var currentLen = 0; + var start = num.bitLength() % 26; + if (start === 0) { + start = 26; + } - BN.min = function min (left, right) { - if (left.cmp(right) < 0) return left; - return right; - }; + for (i = num.length - 1; i >= 0; i--) { + var word = num.words[i]; + for (var j = start - 1; j >= 0; j--) { + var bit = (word >> j) & 1; + if (res !== wnd[0]) { + res = this.sqr(res); + } + + if (bit === 0 && current === 0) { + currentLen = 0; + continue; + } + + current <<= 1; + current |= bit; + currentLen++; + if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue; + + res = this.mul(res, wnd[current]); + currentLen = 0; + current = 0; + } + start = 26; + } - BN.prototype._init = function init (number, base, endian) { - if (typeof number === 'number') { - return this._initNumber(number, base, endian); - } + return res; + }; - if (typeof number === 'object') { - return this._initArray(number, base, endian); - } + Red.prototype.convertTo = function convertTo(num) { + var r = num.umod(this.m); - if (base === 'hex') { - base = 16; - } - assert(base === (base | 0) && base >= 2 && base <= 36); + return r === num ? r.clone() : r; + }; - number = number.toString().replace(/\s+/g, ''); - var start = 0; - if (number[0] === '-') { - start++; - } + Red.prototype.convertFrom = function convertFrom(num) { + var res = num.clone(); + res.red = null; + return res; + }; - if (base === 16) { - this._parseHex(number, start); - } else { - this._parseBase(number, base, start); - } + // + // Montgomery method engine + // - if (number[0] === '-') { - this.negative = 1; - } + BN.mont = function mont(num) { + return new Mont(num); + }; - this.strip(); + function Mont(m) { + Red.call(this, m); - if (endian !== 'le') return; + this.shift = this.m.bitLength(); + if (this.shift % 26 !== 0) { + this.shift += 26 - (this.shift % 26); + } - this._initArray(this.toArray(), base, endian); - }; + this.r = new BN(1).iushln(this.shift); + this.r2 = this.imod(this.r.sqr()); + this.rinv = this.r._invmp(this.m); - BN.prototype._initNumber = function _initNumber (number, base, endian) { - if (number < 0) { - this.negative = 1; - number = -number; - } - if (number < 0x4000000) { - this.words = [ number & 0x3ffffff ]; - this.length = 1; - } else if (number < 0x10000000000000) { - this.words = [ - number & 0x3ffffff, - (number / 0x4000000) & 0x3ffffff - ]; - this.length = 2; - } else { - assert(number < 0x20000000000000); // 2 ^ 53 (unsafe) - this.words = [ - number & 0x3ffffff, - (number / 0x4000000) & 0x3ffffff, - 1 - ]; - this.length = 3; - } + this.minv = this.rinv + .mul(this.r) + .isubn(1) + .div(this.m); + this.minv = this.minv.umod(this.r); + this.minv = this.r.sub(this.minv); + } + inherits(Mont, Red); + + Mont.prototype.convertTo = function convertTo(num) { + return this.imod(num.ushln(this.shift)); + }; + + Mont.prototype.convertFrom = function convertFrom(num) { + var r = this.imod(num.mul(this.rinv)); + r.red = null; + return r; + }; + + Mont.prototype.imul = function imul(a, b) { + if (a.isZero() || b.isZero()) { + a.words[0] = 0; + a.length = 1; + return a; + } - if (endian !== 'le') return; + var t = a.imul(b); + var c = t + .maskn(this.shift) + .mul(this.minv) + .imaskn(this.shift) + .mul(this.m); + var u = t.isub(c).iushrn(this.shift); + var res = u; + + if (u.cmp(this.m) >= 0) { + res = u.isub(this.m); + } else if (u.cmpn(0) < 0) { + res = u.iadd(this.m); + } - // Reverse the bytes - this._initArray(this.toArray(), base, endian); - }; + return res._forceRed(this); + }; + + Mont.prototype.mul = function mul(a, b) { + if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this); + + var t = a.mul(b); + var c = t + .maskn(this.shift) + .mul(this.minv) + .imaskn(this.shift) + .mul(this.m); + var u = t.isub(c).iushrn(this.shift); + var res = u; + if (u.cmp(this.m) >= 0) { + res = u.isub(this.m); + } else if (u.cmpn(0) < 0) { + res = u.iadd(this.m); + } - BN.prototype._initArray = function _initArray (number, base, endian) { - // Perhaps a Uint8Array - assert(typeof number.length === 'number'); - if (number.length <= 0) { - this.words = [ 0 ]; - this.length = 1; - return this; - } + return res._forceRed(this); + }; - this.length = Math.ceil(number.length / 3); - this.words = new Array(this.length); - for (var i = 0; i < this.length; i++) { - this.words[i] = 0; - } + Mont.prototype.invm = function invm(a) { + // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R + var res = this.imod(a._invmp(this.m).mul(this.r2)); + return res._forceRed(this); + }; + })(typeof module === 'undefined' || module, this); + }, + { buffer: 64 }, + ], + 60: [ + function(require, module, exports) { + (function(global) { + 'use strict'; - var j, w; - var off = 0; - if (endian === 'be') { - for (i = number.length - 1, j = 0; i >= 0; i -= 3) { - w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16); - this.words[j] |= (w << off) & 0x3ffffff; - this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; - off += 24; - if (off >= 26) { - off -= 26; - j++; - } - } - } else if (endian === 'le') { - for (i = 0, j = 0; i < number.length; i += 3) { - w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16); - this.words[j] |= (w << off) & 0x3ffffff; - this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; - off += 24; - if (off >= 26) { - off -= 26; - j++; - } - } - } - return this.strip(); - }; + // compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js + // original notice: - function parseHex (str, start, end) { - var r = 0; - var len = Math.min(str.length, end); - for (var i = start; i < len; i++) { - var c = str.charCodeAt(i) - 48; + /*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ + function compare(a, b) { + if (a === b) { + return 0; + } - r <<= 4; + var x = a.length; + var y = b.length; - // 'a' - 'f' - if (c >= 49 && c <= 54) { - r |= c - 49 + 0xa; + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i]; + y = b[i]; + break; + } + } - // 'A' - 'F' - } else if (c >= 17 && c <= 22) { - r |= c - 17 + 0xa; + if (x < y) { + return -1; + } + if (y < x) { + return 1; + } + return 0; + } + function isBuffer(b) { + if (global.Buffer && typeof global.Buffer.isBuffer === 'function') { + return global.Buffer.isBuffer(b); + } + return !!(b != null && b._isBuffer); + } - // '0' - '9' - } else { - r |= c & 0xf; - } - } - return r; - } + // based on node assert, original notice: - BN.prototype._parseHex = function _parseHex (number, start) { - // Create possibly bigger array to ensure that it fits the number - this.length = Math.ceil((number.length - start) / 6); - this.words = new Array(this.length); - for (var i = 0; i < this.length; i++) { - this.words[i] = 0; - } + // http://wiki.commonjs.org/wiki/Unit_Testing/1.0 + // + // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! + // + // Originally from narwhal.js (http://narwhaljs.org) + // Copyright (c) 2009 Thomas Robinson <280north.com> + // + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the 'Software'), to + // deal in the Software without restriction, including without limitation the + // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + // sell copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + // + // The above copyright notice and this permission notice shall be included in + // all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + var util = require('util/'); + var hasOwn = Object.prototype.hasOwnProperty; + var pSlice = Array.prototype.slice; + var functionsHaveNames = (function() { + return function foo() {}.name === 'foo'; + })(); + function pToString(obj) { + return Object.prototype.toString.call(obj); + } + function isView(arrbuf) { + if (isBuffer(arrbuf)) { + return false; + } + if (typeof global.ArrayBuffer !== 'function') { + return false; + } + if (typeof ArrayBuffer.isView === 'function') { + return ArrayBuffer.isView(arrbuf); + } + if (!arrbuf) { + return false; + } + if (arrbuf instanceof DataView) { + return true; + } + if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) { + return true; + } + return false; + } + // 1. The assert module provides functions that throw + // AssertionError's when particular conditions are not met. The + // assert module must conform to the following interface. + + var assert = (module.exports = ok); + + // 2. The AssertionError is defined in assert. + // new assert.AssertionError({ message: message, + // actual: actual, + // expected: expected }) + + var regex = /\s*function\s+([^\(\s]*)\s*/; + // based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js + function getName(func) { + if (!util.isFunction(func)) { + return; + } + if (functionsHaveNames) { + return func.name; + } + var str = func.toString(); + var match = str.match(regex); + return match && match[1]; + } + assert.AssertionError = function AssertionError(options) { + this.name = 'AssertionError'; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + if (options.message) { + this.message = options.message; + this.generatedMessage = false; + } else { + this.message = getMessage(this); + this.generatedMessage = true; + } + var stackStartFunction = options.stackStartFunction || fail; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } else { + // non v8 browsers so we can have a stacktrace + var err = new Error(); + if (err.stack) { + var out = err.stack; + + // try to strip useless frames + var fn_name = getName(stackStartFunction); + var idx = out.indexOf('\n' + fn_name); + if (idx >= 0) { + // once we have located the function frame + // we need to strip out everything before it (and its line) + var next_line = out.indexOf('\n', idx + 1); + out = out.substring(next_line + 1); + } + + this.stack = out; + } + } + }; - var j, w; - // Scan 24-bit chunks and add them to the number - var off = 0; - for (i = number.length - 6, j = 0; i >= start; i -= 6) { - w = parseHex(number, i, i + 6); - this.words[j] |= (w << off) & 0x3ffffff; - // NOTE: `0x3fffff` is intentional here, 26bits max shift + 24bit hex limb - this.words[j + 1] |= w >>> (26 - off) & 0x3fffff; - off += 24; - if (off >= 26) { - off -= 26; - j++; - } - } - if (i + 6 !== start) { - w = parseHex(number, start, i + 6); - this.words[j] |= (w << off) & 0x3ffffff; - this.words[j + 1] |= w >>> (26 - off) & 0x3fffff; - } - this.strip(); - }; + // assert.AssertionError instanceof Error + util.inherits(assert.AssertionError, Error); - function parseBase (str, start, end, mul) { - var r = 0; - var len = Math.min(str.length, end); - for (var i = start; i < len; i++) { - var c = str.charCodeAt(i) - 48; + function truncate(s, n) { + if (typeof s === 'string') { + return s.length < n ? s : s.slice(0, n); + } else { + return s; + } + } + function inspect(something) { + if (functionsHaveNames || !util.isFunction(something)) { + return util.inspect(something); + } + var rawname = getName(something); + var name = rawname ? ': ' + rawname : ''; + return '[Function' + name + ']'; + } + function getMessage(self) { + return ( + truncate(inspect(self.actual), 128) + ' ' + self.operator + ' ' + truncate(inspect(self.expected), 128) + ); + } - r *= mul; + // At present only the three keys mentioned above are used and + // understood by the spec. Implementations or sub modules can pass + // other keys to the AssertionError's constructor - they will be + // ignored. + + // 3. All of the following functions must throw an AssertionError + // when a corresponding condition is not met, with a message that + // may be undefined if not provided. All assertion methods provide + // both the actual and expected values to the assertion error for + // display purposes. + + function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction, + }); + } - // 'a' - if (c >= 49) { - r += c - 49 + 0xa; + // EXTENSION! allows for well behaved errors defined elsewhere. + assert.fail = fail; - // 'A' - } else if (c >= 17) { - r += c - 17 + 0xa; + // 4. Pure assertion tests whether a value is truthy, as determined + // by !!guard. + // assert.ok(guard, message_opt); + // This statement is equivalent to assert.equal(true, !!guard, + // message_opt);. To test strictly for the value true, use + // assert.strictEqual(true, guard, message_opt);. - // '0' - '9' - } else { - r += c; - } - } - return r; - } + function ok(value, message) { + if (!value) fail(value, true, message, '==', assert.ok); + } + assert.ok = ok; - BN.prototype._parseBase = function _parseBase (number, base, start) { - // Initialize as zero - this.words = [ 0 ]; - this.length = 1; + // 5. The equality assertion tests shallow, coercive equality with + // ==. + // assert.equal(actual, expected, message_opt); - // Find length of limb in base - for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) { - limbLen++; - } - limbLen--; - limbPow = (limbPow / base) | 0; + assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, '==', assert.equal); + }; - var total = number.length - start; - var mod = total % limbLen; - var end = Math.min(total, total - mod) + start; + // 6. The non-equality assertion tests for whether two objects are not equal + // with != assert.notEqual(actual, expected, message_opt); - var word = 0; - for (var i = start; i < end; i += limbLen) { - word = parseBase(number, i, i + limbLen, base); + assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, '!=', assert.notEqual); + } + }; - this.imuln(limbPow); - if (this.words[0] + word < 0x4000000) { - this.words[0] += word; - } else { - this._iaddn(word); - } - } + // 7. The equivalence assertion tests a deep equality relation. + // assert.deepEqual(actual, expected, message_opt); - if (mod !== 0) { - var pow = 1; - word = parseBase(number, i, number.length, base); + assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected, false)) { + fail(actual, expected, message, 'deepEqual', assert.deepEqual); + } + }; - for (i = 0; i < mod; i++) { - pow *= base; - } + assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { + if (!_deepEqual(actual, expected, true)) { + fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual); + } + }; + + function _deepEqual(actual, expected, strict, memos) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + } else if (isBuffer(actual) && isBuffer(expected)) { + return compare(actual, expected) === 0; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (util.isDate(actual) && util.isDate(expected)) { + return actual.getTime() === expected.getTime(); + + // 7.3 If the expected value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object with the same source and + // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). + } else if (util.isRegExp(actual) && util.isRegExp(expected)) { + return ( + actual.source === expected.source && + actual.global === expected.global && + actual.multiline === expected.multiline && + actual.lastIndex === expected.lastIndex && + actual.ignoreCase === expected.ignoreCase + ); + + // 7.4. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if ( + (actual === null || typeof actual !== 'object') && + (expected === null || typeof expected !== 'object') + ) { + return strict ? actual === expected : actual == expected; + + // If both values are instances of typed arrays, wrap their underlying + // ArrayBuffers in a Buffer each to increase performance + // This optimization requires the arrays to have the same type as checked by + // Object.prototype.toString (aka pToString). Never perform binary + // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their + // bit patterns are not identical. + } else if ( + isView(actual) && + isView(expected) && + pToString(actual) === pToString(expected) && + !(actual instanceof Float32Array || actual instanceof Float64Array) + ) { + return compare(new Uint8Array(actual.buffer), new Uint8Array(expected.buffer)) === 0; + + // 7.5 For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else if (isBuffer(actual) !== isBuffer(expected)) { + return false; + } else { + memos = memos || { actual: [], expected: [] }; - this.imuln(pow); - if (this.words[0] + word < 0x4000000) { - this.words[0] += word; - } else { - this._iaddn(word); - } - } - }; + var actualIndex = memos.actual.indexOf(actual); + if (actualIndex !== -1) { + if (actualIndex === memos.expected.indexOf(expected)) { + return true; + } + } - BN.prototype.copy = function copy (dest) { - dest.words = new Array(this.length); - for (var i = 0; i < this.length; i++) { - dest.words[i] = this.words[i]; - } - dest.length = this.length; - dest.negative = this.negative; - dest.red = this.red; - }; - - BN.prototype.clone = function clone () { - var r = new BN(null); - this.copy(r); - return r; - }; - - BN.prototype._expand = function _expand (size) { - while (this.length < size) { - this.words[this.length++] = 0; - } - return this; - }; + memos.actual.push(actual); + memos.expected.push(expected); - // Remove leading `0` from `this` - BN.prototype.strip = function strip () { - while (this.length > 1 && this.words[this.length - 1] === 0) { - this.length--; - } - return this._normSign(); - }; + return objEquiv(actual, expected, strict, memos); + } + } - BN.prototype._normSign = function _normSign () { - // -0 = 0 - if (this.length === 1 && this.words[0] === 0) { - this.negative = 0; - } - return this; - }; + function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; + } - BN.prototype.inspect = function inspect () { - return (this.red ? ''; - }; + function objEquiv(a, b, strict, actualVisitedObjects) { + if (a === null || a === undefined || b === null || b === undefined) return false; + // if one is a primitive, the other must be same + if (util.isPrimitive(a) || util.isPrimitive(b)) return a === b; + if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) return false; + var aIsArgs = isArguments(a); + var bIsArgs = isArguments(b); + if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) return false; + if (aIsArgs) { + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b, strict); + } + var ka = objectKeys(a); + var kb = objectKeys(b); + var key, i; + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length !== kb.length) return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] !== kb[i]) return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects)) return false; + } + return true; + } - /* + // 8. The non-equivalence assertion tests for any deep inequality. + // assert.notDeepEqual(actual, expected, message_opt); - var zeros = []; - var groupSizes = []; - var groupBases = []; + assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected, false)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + } + }; - var s = ''; - var i = -1; - while (++i < BN.wordSize) { - zeros[i] = s; - s += '0'; - } - groupSizes[0] = 0; - groupSizes[1] = 0; - groupBases[0] = 0; - groupBases[1] = 0; - var base = 2 - 1; - while (++base < 36 + 1) { - var groupSize = 0; - var groupBase = 1; - while (groupBase < (1 << BN.wordSize) / base) { - groupBase *= base; - groupSize += 1; - } - groupSizes[base] = groupSize; - groupBases[base] = groupBase; - } + assert.notDeepStrictEqual = notDeepStrictEqual; + function notDeepStrictEqual(actual, expected, message) { + if (_deepEqual(actual, expected, true)) { + fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual); + } + } - */ + // 9. The strict equality assertion tests strict equality, as determined by ===. + // assert.strictEqual(actual, expected, message_opt); - var zeros = [ - '', - '0', - '00', - '000', - '0000', - '00000', - '000000', - '0000000', - '00000000', - '000000000', - '0000000000', - '00000000000', - '000000000000', - '0000000000000', - '00000000000000', - '000000000000000', - '0000000000000000', - '00000000000000000', - '000000000000000000', - '0000000000000000000', - '00000000000000000000', - '000000000000000000000', - '0000000000000000000000', - '00000000000000000000000', - '000000000000000000000000', - '0000000000000000000000000' - ]; + assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, '===', assert.strictEqual); + } + }; - var groupSizes = [ - 0, 0, - 25, 16, 12, 11, 10, 9, 8, - 8, 7, 7, 7, 7, 6, 6, - 6, 6, 6, 6, 6, 5, 5, - 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5 - ]; + // 10. The strict non-equality assertion tests for strict inequality, as + // determined by !==. assert.notStrictEqual(actual, expected, message_opt); - var groupBases = [ - 0, 0, - 33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216, - 43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625, - 16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632, - 6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149, - 24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176 - ]; + assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, '!==', assert.notStrictEqual); + } + }; - BN.prototype.toString = function toString (base, padding) { - base = base || 10; - padding = padding | 0 || 1; - - var out; - if (base === 16 || base === 'hex') { - out = ''; - var off = 0; - var carry = 0; - for (var i = 0; i < this.length; i++) { - var w = this.words[i]; - var word = (((w << off) | carry) & 0xffffff).toString(16); - carry = (w >>> (24 - off)) & 0xffffff; - if (carry !== 0 || i !== this.length - 1) { - out = zeros[6 - word.length] + word + out; - } else { - out = word + out; - } - off += 2; - if (off >= 26) { - off -= 26; - i--; - } - } - if (carry !== 0) { - out = carry.toString(16) + out; - } - while (out.length % padding !== 0) { - out = '0' + out; - } - if (this.negative !== 0) { - out = '-' + out; - } - return out; - } + function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } - if (base === (base | 0) && base >= 2 && base <= 36) { - // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base)); - var groupSize = groupSizes[base]; - // var groupBase = Math.pow(base, groupSize); - var groupBase = groupBases[base]; - out = ''; - var c = this.clone(); - c.negative = 0; - while (!c.isZero()) { - var r = c.modn(groupBase).toString(base); - c = c.idivn(groupBase); - - if (!c.isZero()) { - out = zeros[groupSize - r.length] + r + out; - } else { - out = r + out; - } - } - if (this.isZero()) { - out = '0' + out; - } - while (out.length % padding !== 0) { - out = '0' + out; - } - if (this.negative !== 0) { - out = '-' + out; - } - return out; - } + if (Object.prototype.toString.call(expected) == '[object RegExp]') { + return expected.test(actual); + } - assert(false, 'Base should be between 2 and 36'); - }; - - BN.prototype.toNumber = function toNumber () { - var ret = this.words[0]; - if (this.length === 2) { - ret += this.words[1] * 0x4000000; - } else if (this.length === 3 && this.words[2] === 0x01) { - // NOTE: at this stage it is known that the top bit is set - ret += 0x10000000000000 + (this.words[1] * 0x4000000); - } else if (this.length > 2) { - assert(false, 'Number can only safely store up to 53 bits'); - } - return (this.negative !== 0) ? -ret : ret; - }; - - BN.prototype.toJSON = function toJSON () { - return this.toString(16); - }; - - BN.prototype.toBuffer = function toBuffer (endian, length) { - assert(typeof Buffer !== 'undefined'); - return this.toArrayLike(Buffer, endian, length); - }; - - BN.prototype.toArray = function toArray (endian, length) { - return this.toArrayLike(Array, endian, length); - }; - - BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) { - var byteLength = this.byteLength(); - var reqLength = length || Math.max(1, byteLength); - assert(byteLength <= reqLength, 'byte array longer than desired length'); - assert(reqLength > 0, 'Requested array length <= 0'); - - this.strip(); - var littleEndian = endian === 'le'; - var res = new ArrayType(reqLength); - - var b, i; - var q = this.clone(); - if (!littleEndian) { - // Assume big-endian - for (i = 0; i < reqLength - byteLength; i++) { - res[i] = 0; - } + try { + if (actual instanceof expected) { + return true; + } + } catch (e) { + // Ignore. The instanceof check doesn't work for arrow functions. + } - for (i = 0; !q.isZero(); i++) { - b = q.andln(0xff); - q.iushrn(8); + if (Error.isPrototypeOf(expected)) { + return false; + } - res[reqLength - i - 1] = b; - } - } else { - for (i = 0; !q.isZero(); i++) { - b = q.andln(0xff); - q.iushrn(8); + return expected.call({}, actual) === true; + } - res[i] = b; - } + function _tryBlock(block) { + var error; + try { + block(); + } catch (e) { + error = e; + } + return error; + } - for (; i < reqLength; i++) { - res[i] = 0; - } - } + function _throws(shouldThrow, block, expected, message) { + var actual; - return res; - }; - - if (Math.clz32) { - BN.prototype._countBits = function _countBits (w) { - return 32 - Math.clz32(w); - }; - } else { - BN.prototype._countBits = function _countBits (w) { - var t = w; - var r = 0; - if (t >= 0x1000) { - r += 13; - t >>>= 13; - } - if (t >= 0x40) { - r += 7; - t >>>= 7; - } - if (t >= 0x8) { - r += 4; - t >>>= 4; - } - if (t >= 0x02) { - r += 2; - t >>>= 2; - } - return r + t; - }; - } + if (typeof block !== 'function') { + throw new TypeError('"block" argument must be a function'); + } - BN.prototype._zeroBits = function _zeroBits (w) { - // Short-cut - if (w === 0) return 26; + if (typeof expected === 'string') { + message = expected; + expected = null; + } - var t = w; - var r = 0; - if ((t & 0x1fff) === 0) { - r += 13; - t >>>= 13; - } - if ((t & 0x7f) === 0) { - r += 7; - t >>>= 7; - } - if ((t & 0xf) === 0) { - r += 4; - t >>>= 4; - } - if ((t & 0x3) === 0) { - r += 2; - t >>>= 2; - } - if ((t & 0x1) === 0) { - r++; - } - return r; - }; + actual = _tryBlock(block); - // Return number of used bits in a BN - BN.prototype.bitLength = function bitLength () { - var w = this.words[this.length - 1]; - var hi = this._countBits(w); - return (this.length - 1) * 26 + hi; - }; + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + (message ? ' ' + message : '.'); - function toBitArray (num) { - var w = new Array(num.bitLength()); + if (shouldThrow && !actual) { + fail(actual, expected, 'Missing expected exception' + message); + } - for (var bit = 0; bit < w.length; bit++) { - var off = (bit / 26) | 0; - var wbit = bit % 26; + var userProvidedMessage = typeof message === 'string'; + var isUnwantedException = !shouldThrow && util.isError(actual); + var isUnexpectedException = !shouldThrow && actual && !expected; - w[bit] = (num.words[off] & (1 << wbit)) >>> wbit; - } + if ( + (isUnwantedException && userProvidedMessage && expectedException(actual, expected)) || + isUnexpectedException + ) { + fail(actual, expected, 'Got unwanted exception' + message); + } - return w; - } + if ( + (shouldThrow && actual && expected && !expectedException(actual, expected)) || + (!shouldThrow && actual) + ) { + throw actual; + } + } - // Number of trailing zero bits - BN.prototype.zeroBits = function zeroBits () { - if (this.isZero()) return 0; + // 11. Expected to throw an error: + // assert.throws(block, Error_opt, message_opt); - var r = 0; - for (var i = 0; i < this.length; i++) { - var b = this._zeroBits(this.words[i]); - r += b; - if (b !== 26) break; - } - return r; - }; + assert.throws = function(block, /*optional*/ error, /*optional*/ message) { + _throws(true, block, error, message); + }; - BN.prototype.byteLength = function byteLength () { - return Math.ceil(this.bitLength() / 8); - }; + // EXTENSION! This is annoying to write outside this module. + assert.doesNotThrow = function(block, /*optional*/ error, /*optional*/ message) { + _throws(false, block, error, message); + }; - BN.prototype.toTwos = function toTwos (width) { - if (this.negative !== 0) { - return this.abs().inotn(width).iaddn(1); - } - return this.clone(); - }; + assert.ifError = function(err) { + if (err) throw err; + }; - BN.prototype.fromTwos = function fromTwos (width) { - if (this.testn(width - 1)) { - return this.notn(width).iaddn(1).ineg(); - } - return this.clone(); - }; + var objectKeys = + Object.keys || + function(obj) { + var keys = []; + for (var key in obj) { + if (hasOwn.call(obj, key)) keys.push(key); + } + return keys; + }; + }.call( + this, + typeof global !== 'undefined' + ? global + : typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : {}, + )); + }, + { 'util/': 248 }, + ], + 61: [ + function(require, module, exports) { + 'use strict'; + + exports.byteLength = byteLength; + exports.toByteArray = toByteArray; + exports.fromByteArray = fromByteArray; + + var lookup = []; + var revLookup = []; + var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array; + + var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i]; + revLookup[code.charCodeAt(i)] = i; + } - BN.prototype.isNeg = function isNeg () { - return this.negative !== 0; - }; + revLookup['-'.charCodeAt(0)] = 62; + revLookup['_'.charCodeAt(0)] = 63; - // Return negative clone of `this` - BN.prototype.neg = function neg () { - return this.clone().ineg(); - }; + function placeHoldersCount(b64) { + var len = b64.length; + if (len % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4'); + } - BN.prototype.ineg = function ineg () { - if (!this.isZero()) { - this.negative ^= 1; - } + // the number of equal signs (place holders) + // if there are two placeholders, than the two characters before it + // represent one byte + // if there is only one, then the three characters before it represent 2 bytes + // this is just a cheap hack to not do indexOf twice + return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0; + } - return this; - }; + function byteLength(b64) { + // base64 is 4/3 + up to two characters of the original data + return (b64.length * 3) / 4 - placeHoldersCount(b64); + } - // Or `num` with `this` in-place - BN.prototype.iuor = function iuor (num) { - while (this.length < num.length) { - this.words[this.length++] = 0; - } + function toByteArray(b64) { + var i, l, tmp, placeHolders, arr; + var len = b64.length; + placeHolders = placeHoldersCount(b64); - for (var i = 0; i < num.length; i++) { - this.words[i] = this.words[i] | num.words[i]; - } + arr = new Arr((len * 3) / 4 - placeHolders); - return this.strip(); - }; - - BN.prototype.ior = function ior (num) { - assert((this.negative | num.negative) === 0); - return this.iuor(num); - }; - - // Or `num` with `this` - BN.prototype.or = function or (num) { - if (this.length > num.length) return this.clone().ior(num); - return num.clone().ior(this); - }; - - BN.prototype.uor = function uor (num) { - if (this.length > num.length) return this.clone().iuor(num); - return num.clone().iuor(this); - }; - - // And `num` with `this` in-place - BN.prototype.iuand = function iuand (num) { - // b = min-length(num, this) - var b; - if (this.length > num.length) { - b = num; - } else { - b = this; - } + // if there are placeholders, only get up to the last complete 4 chars + l = placeHolders > 0 ? len - 4 : len; - for (var i = 0; i < b.length; i++) { - this.words[i] = this.words[i] & num.words[i]; - } + var L = 0; - this.length = b.length; - - return this.strip(); - }; - - BN.prototype.iand = function iand (num) { - assert((this.negative | num.negative) === 0); - return this.iuand(num); - }; - - // And `num` with `this` - BN.prototype.and = function and (num) { - if (this.length > num.length) return this.clone().iand(num); - return num.clone().iand(this); - }; - - BN.prototype.uand = function uand (num) { - if (this.length > num.length) return this.clone().iuand(num); - return num.clone().iuand(this); - }; - - // Xor `num` with `this` in-place - BN.prototype.iuxor = function iuxor (num) { - // a.length > b.length - var a; - var b; - if (this.length > num.length) { - a = this; - b = num; - } else { - a = num; - b = this; - } + for (i = 0; i < l; i += 4) { + tmp = + (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)]; + arr[L++] = (tmp >> 16) & 0xff; + arr[L++] = (tmp >> 8) & 0xff; + arr[L++] = tmp & 0xff; + } - for (var i = 0; i < b.length; i++) { - this.words[i] = a.words[i] ^ b.words[i]; - } + if (placeHolders === 2) { + tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4); + arr[L++] = tmp & 0xff; + } else if (placeHolders === 1) { + tmp = + (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2); + arr[L++] = (tmp >> 8) & 0xff; + arr[L++] = tmp & 0xff; + } - if (this !== a) { - for (; i < a.length; i++) { - this.words[i] = a.words[i]; - } - } + return arr; + } - this.length = a.length; + function tripletToBase64(num) { + return ( + lookup[(num >> 18) & 0x3f] + lookup[(num >> 12) & 0x3f] + lookup[(num >> 6) & 0x3f] + lookup[num & 0x3f] + ); + } - return this.strip(); - }; + function encodeChunk(uint8, start, end) { + var tmp; + var output = []; + for (var i = start; i < end; i += 3) { + tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + uint8[i + 2]; + output.push(tripletToBase64(tmp)); + } + return output.join(''); + } - BN.prototype.ixor = function ixor (num) { - assert((this.negative | num.negative) === 0); - return this.iuxor(num); - }; + function fromByteArray(uint8) { + var tmp; + var len = uint8.length; + var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes + var output = ''; + var parts = []; + var maxChunkLength = 16383; // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength)); + } - // Xor `num` with `this` - BN.prototype.xor = function xor (num) { - if (this.length > num.length) return this.clone().ixor(num); - return num.clone().ixor(this); - }; + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1]; + output += lookup[tmp >> 2]; + output += lookup[(tmp << 4) & 0x3f]; + output += '=='; + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + uint8[len - 1]; + output += lookup[tmp >> 10]; + output += lookup[(tmp >> 4) & 0x3f]; + output += lookup[(tmp << 2) & 0x3f]; + output += '='; + } - BN.prototype.uxor = function uxor (num) { - if (this.length > num.length) return this.clone().iuxor(num); - return num.clone().iuxor(this); - }; + parts.push(output); - // Not ``this`` with ``width`` bitwidth - BN.prototype.inotn = function inotn (width) { - assert(typeof width === 'number' && width >= 0); + return parts.join(''); + } + }, + {}, + ], + 62: [ + function(require, module, exports) { + (function(module, exports) { + 'use strict'; - var bytesNeeded = Math.ceil(width / 26) | 0; - var bitsLeft = width % 26; + // Utils - // Extend the buffer with leading zeroes - this._expand(bytesNeeded); + function assert(val, msg) { + if (!val) throw new Error(msg || 'Assertion failed'); + } - if (bitsLeft > 0) { - bytesNeeded--; - } + // Could use `inherits` module, but don't want to move from single file + // architecture yet. + function inherits(ctor, superCtor) { + ctor.super_ = superCtor; + var TempCtor = function() {}; + TempCtor.prototype = superCtor.prototype; + ctor.prototype = new TempCtor(); + ctor.prototype.constructor = ctor; + } - // Handle complete words - for (var i = 0; i < bytesNeeded; i++) { - this.words[i] = ~this.words[i] & 0x3ffffff; - } + // BN - // Handle the residue - if (bitsLeft > 0) { - this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft)); - } + function BN(number, base, endian) { + // May be `new BN(bn)` ? + if (number !== null && typeof number === 'object' && Array.isArray(number.words)) { + return number; + } - // And remove leading zeroes - return this.strip(); - }; + this.sign = false; + this.words = null; + this.length = 0; - BN.prototype.notn = function notn (width) { - return this.clone().inotn(width); - }; + // Reduction context + this.red = null; - // Set `bit` of `this` - BN.prototype.setn = function setn (bit, val) { - assert(typeof bit === 'number' && bit >= 0); + if (base === 'le' || base === 'be') { + endian = base; + base = 10; + } - var off = (bit / 26) | 0; - var wbit = bit % 26; + if (number !== null) this._init(number || 0, base || 10, endian || 'be'); + } + if (typeof module === 'object') module.exports = BN; + else exports.BN = BN; - this._expand(off + 1); + BN.BN = BN; + BN.wordSize = 26; - if (val) { - this.words[off] = this.words[off] | (1 << wbit); - } else { - this.words[off] = this.words[off] & ~(1 << wbit); - } + BN.prototype._init = function init(number, base, endian) { + if (typeof number === 'number') { + if (number < 0) { + this.sign = true; + number = -number; + } + if (number < 0x4000000) { + this.words = [number & 0x3ffffff]; + this.length = 1; + } else if (number < 0x10000000000000) { + this.words = [number & 0x3ffffff, (number / 0x4000000) & 0x3ffffff]; + this.length = 2; + } else { + assert(number < 0x20000000000000); // 2 ^ 53 (unsafe) + this.words = [number & 0x3ffffff, (number / 0x4000000) & 0x3ffffff, 1]; + this.length = 3; + } + return; + } else if (typeof number === 'object') { + return this._initArray(number, base, endian); + } + if (base === 'hex') base = 16; + assert(base === (base | 0) && base >= 2 && base <= 36); - return this.strip(); - }; - - // Add `num` to `this` in-place - BN.prototype.iadd = function iadd (num) { - var r; - - // negative + positive - if (this.negative !== 0 && num.negative === 0) { - this.negative = 0; - r = this.isub(num); - this.negative ^= 1; - return this._normSign(); - - // positive + negative - } else if (this.negative === 0 && num.negative !== 0) { - num.negative = 0; - r = this.isub(num); - num.negative = 1; - return r._normSign(); - } + number = number.toString().replace(/\s+/g, ''); + var start = 0; + if (number[0] === '-') start++; - // a.length > b.length - var a, b; - if (this.length > num.length) { - a = this; - b = num; - } else { - a = num; - b = this; - } + if (base === 16) this._parseHex(number, start); + else this._parseBase(number, base, start); - var carry = 0; - for (var i = 0; i < b.length; i++) { - r = (a.words[i] | 0) + (b.words[i] | 0) + carry; - this.words[i] = r & 0x3ffffff; - carry = r >>> 26; - } - for (; carry !== 0 && i < a.length; i++) { - r = (a.words[i] | 0) + carry; - this.words[i] = r & 0x3ffffff; - carry = r >>> 26; - } + if (number[0] === '-') this.sign = true; - this.length = a.length; - if (carry !== 0) { - this.words[this.length] = carry; - this.length++; - // Copy the rest of the words - } else if (a !== this) { - for (; i < a.length; i++) { - this.words[i] = a.words[i]; - } - } + this.strip(); + }; - return this; - }; - - // Add `num` to `this` - BN.prototype.add = function add (num) { - var res; - if (num.negative !== 0 && this.negative === 0) { - num.negative = 0; - res = this.sub(num); - num.negative ^= 1; - return res; - } else if (num.negative === 0 && this.negative !== 0) { - this.negative = 0; - res = num.sub(this); - this.negative = 1; - return res; - } + BN.prototype._initArray = function _initArray(number, base, endian) { + // Perhaps a Uint8Array + assert(typeof number.length === 'number'); + if (number.length <= 0) { + this.words = [0]; + this.length = 1; + return this; + } - if (this.length > num.length) return this.clone().iadd(num); - - return num.clone().iadd(this); - }; - - // Subtract `num` from `this` in-place - BN.prototype.isub = function isub (num) { - // this - (-num) = this + num - if (num.negative !== 0) { - num.negative = 0; - var r = this.iadd(num); - num.negative = 1; - return r._normSign(); - - // -this - num = -(this + num) - } else if (this.negative !== 0) { - this.negative = 0; - this.iadd(num); - this.negative = 1; - return this._normSign(); - } + this.length = Math.ceil(number.length / 3); + this.words = new Array(this.length); + for (var i = 0; i < this.length; i++) this.words[i] = 0; + + var off = 0; + if (endian === 'be') { + for (var i = number.length - 1, j = 0; i >= 0; i -= 3) { + var w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + } else if (endian === 'le') { + for (var i = 0, j = 0; i < number.length; i += 3) { + var w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + } + return this.strip(); + }; + + function parseHex(str, start, end) { + var r = 0; + var len = Math.min(str.length, end); + for (var i = start; i < len; i++) { + var c = str.charCodeAt(i) - 48; + + r <<= 4; + + // 'a' - 'f' + if (c >= 49 && c <= 54) r |= c - 49 + 0xa; + // 'A' - 'F' + else if (c >= 17 && c <= 22) r |= c - 17 + 0xa; + // '0' - '9' + else r |= c & 0xf; + } + return r; + } - // At this point both numbers are positive - var cmp = this.cmp(num); + BN.prototype._parseHex = function _parseHex(number, start) { + // Create possibly bigger array to ensure that it fits the number + this.length = Math.ceil((number.length - start) / 6); + this.words = new Array(this.length); + for (var i = 0; i < this.length; i++) this.words[i] = 0; + + // Scan 24-bit chunks and add them to the number + var off = 0; + for (var i = number.length - 6, j = 0; i >= start; i -= 6) { + var w = parseHex(number, i, i + 6); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] |= (w >>> (26 - off)) & 0x3fffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + if (i + 6 !== start) { + var w = parseHex(number, start, i + 6); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] |= (w >>> (26 - off)) & 0x3fffff; + } + this.strip(); + }; + + function parseBase(str, start, end, mul) { + var r = 0; + var len = Math.min(str.length, end); + for (var i = start; i < len; i++) { + var c = str.charCodeAt(i) - 48; + + r *= mul; + + // 'a' + if (c >= 49) r += c - 49 + 0xa; + // 'A' + else if (c >= 17) r += c - 17 + 0xa; + // '0' - '9' + else r += c; + } + return r; + } - // Optimization - zeroify - if (cmp === 0) { - this.negative = 0; - this.length = 1; - this.words[0] = 0; - return this; - } + BN.prototype._parseBase = function _parseBase(number, base, start) { + // Initialize as zero + this.words = [0]; + this.length = 1; - // a > b - var a, b; - if (cmp > 0) { - a = this; - b = num; - } else { - a = num; - b = this; - } + // Find length of limb in base + for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) limbLen++; + limbLen--; + limbPow = (limbPow / base) | 0; - var carry = 0; - for (var i = 0; i < b.length; i++) { - r = (a.words[i] | 0) - (b.words[i] | 0) + carry; - carry = r >> 26; - this.words[i] = r & 0x3ffffff; - } - for (; carry !== 0 && i < a.length; i++) { - r = (a.words[i] | 0) + carry; - carry = r >> 26; - this.words[i] = r & 0x3ffffff; - } + var total = number.length - start; + var mod = total % limbLen; + var end = Math.min(total, total - mod) + start; - // Copy rest of the words - if (carry === 0 && i < a.length && a !== this) { - for (; i < a.length; i++) { - this.words[i] = a.words[i]; - } - } + var word = 0; + for (var i = start; i < end; i += limbLen) { + word = parseBase(number, i, i + limbLen, base); - this.length = Math.max(this.length, i); + this.imuln(limbPow); + if (this.words[0] + word < 0x4000000) this.words[0] += word; + else this._iaddn(word); + } - if (a !== this) { - this.negative = 1; - } + if (mod !== 0) { + var pow = 1; + var word = parseBase(number, i, number.length, base); - return this.strip(); - }; - - // Subtract `num` from `this` - BN.prototype.sub = function sub (num) { - return this.clone().isub(num); - }; - - function smallMulTo (self, num, out) { - out.negative = num.negative ^ self.negative; - var len = (self.length + num.length) | 0; - out.length = len; - len = (len - 1) | 0; - - // Peel one iteration (compiler can't do it, because of code complexity) - var a = self.words[0] | 0; - var b = num.words[0] | 0; - var r = a * b; - - var lo = r & 0x3ffffff; - var carry = (r / 0x4000000) | 0; - out.words[0] = lo; - - for (var k = 1; k < len; k++) { - // Sum all words with the same `i + j = k` and accumulate `ncarry`, - // note that ncarry could be >= 0x3ffffff - var ncarry = carry >>> 26; - var rword = carry & 0x3ffffff; - var maxJ = Math.min(k, num.length - 1); - for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { - var i = (k - j) | 0; - a = self.words[i] | 0; - b = num.words[j] | 0; - r = a * b + rword; - ncarry += (r / 0x4000000) | 0; - rword = r & 0x3ffffff; - } - out.words[k] = rword | 0; - carry = ncarry | 0; - } - if (carry !== 0) { - out.words[k] = carry | 0; - } else { - out.length--; - } + for (var i = 0; i < mod; i++) pow *= base; + this.imuln(pow); + if (this.words[0] + word < 0x4000000) this.words[0] += word; + else this._iaddn(word); + } + }; + + BN.prototype.copy = function copy(dest) { + dest.words = new Array(this.length); + for (var i = 0; i < this.length; i++) dest.words[i] = this.words[i]; + dest.length = this.length; + dest.sign = this.sign; + dest.red = this.red; + }; + + BN.prototype.clone = function clone() { + var r = new BN(null); + this.copy(r); + return r; + }; + + // Remove leading `0` from `this` + BN.prototype.strip = function strip() { + while (this.length > 1 && this.words[this.length - 1] === 0) this.length--; + return this._normSign(); + }; + + BN.prototype._normSign = function _normSign() { + // -0 = 0 + if (this.length === 1 && this.words[0] === 0) this.sign = false; + return this; + }; + + BN.prototype.inspect = function inspect() { + return (this.red ? ''; + }; + + /* + +var zeros = []; +var groupSizes = []; +var groupBases = []; - return out.strip(); +var s = ''; +var i = -1; +while (++i < BN.wordSize) { + zeros[i] = s; + s += '0'; +} +groupSizes[0] = 0; +groupSizes[1] = 0; +groupBases[0] = 0; +groupBases[1] = 0; +var base = 2 - 1; +while (++base < 36 + 1) { + var groupSize = 0; + var groupBase = 1; + while (groupBase < (1 << BN.wordSize) / base) { + groupBase *= base; + groupSize += 1; } + groupSizes[base] = groupSize; + groupBases[base] = groupBase; +} - // TODO(indutny): it may be reasonable to omit it for users who don't need - // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit - // multiplication (like elliptic secp256k1). - var comb10MulTo = function comb10MulTo (self, num, out) { - var a = self.words; - var b = num.words; - var o = out.words; - var c = 0; - var lo; - var mid; - var hi; - var a0 = a[0] | 0; - var al0 = a0 & 0x1fff; - var ah0 = a0 >>> 13; - var a1 = a[1] | 0; - var al1 = a1 & 0x1fff; - var ah1 = a1 >>> 13; - var a2 = a[2] | 0; - var al2 = a2 & 0x1fff; - var ah2 = a2 >>> 13; - var a3 = a[3] | 0; - var al3 = a3 & 0x1fff; - var ah3 = a3 >>> 13; - var a4 = a[4] | 0; - var al4 = a4 & 0x1fff; - var ah4 = a4 >>> 13; - var a5 = a[5] | 0; - var al5 = a5 & 0x1fff; - var ah5 = a5 >>> 13; - var a6 = a[6] | 0; - var al6 = a6 & 0x1fff; - var ah6 = a6 >>> 13; - var a7 = a[7] | 0; - var al7 = a7 & 0x1fff; - var ah7 = a7 >>> 13; - var a8 = a[8] | 0; - var al8 = a8 & 0x1fff; - var ah8 = a8 >>> 13; - var a9 = a[9] | 0; - var al9 = a9 & 0x1fff; - var ah9 = a9 >>> 13; - var b0 = b[0] | 0; - var bl0 = b0 & 0x1fff; - var bh0 = b0 >>> 13; - var b1 = b[1] | 0; - var bl1 = b1 & 0x1fff; - var bh1 = b1 >>> 13; - var b2 = b[2] | 0; - var bl2 = b2 & 0x1fff; - var bh2 = b2 >>> 13; - var b3 = b[3] | 0; - var bl3 = b3 & 0x1fff; - var bh3 = b3 >>> 13; - var b4 = b[4] | 0; - var bl4 = b4 & 0x1fff; - var bh4 = b4 >>> 13; - var b5 = b[5] | 0; - var bl5 = b5 & 0x1fff; - var bh5 = b5 >>> 13; - var b6 = b[6] | 0; - var bl6 = b6 & 0x1fff; - var bh6 = b6 >>> 13; - var b7 = b[7] | 0; - var bl7 = b7 & 0x1fff; - var bh7 = b7 >>> 13; - var b8 = b[8] | 0; - var bl8 = b8 & 0x1fff; - var bh8 = b8 >>> 13; - var b9 = b[9] | 0; - var bl9 = b9 & 0x1fff; - var bh9 = b9 >>> 13; - - out.negative = self.negative ^ num.negative; - out.length = 19; - /* k = 0 */ - lo = Math.imul(al0, bl0); - mid = Math.imul(al0, bh0); - mid = (mid + Math.imul(ah0, bl0)) | 0; - hi = Math.imul(ah0, bh0); - var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0; - w0 &= 0x3ffffff; - /* k = 1 */ - lo = Math.imul(al1, bl0); - mid = Math.imul(al1, bh0); - mid = (mid + Math.imul(ah1, bl0)) | 0; - hi = Math.imul(ah1, bh0); - lo = (lo + Math.imul(al0, bl1)) | 0; - mid = (mid + Math.imul(al0, bh1)) | 0; - mid = (mid + Math.imul(ah0, bl1)) | 0; - hi = (hi + Math.imul(ah0, bh1)) | 0; - var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0; - w1 &= 0x3ffffff; - /* k = 2 */ - lo = Math.imul(al2, bl0); - mid = Math.imul(al2, bh0); - mid = (mid + Math.imul(ah2, bl0)) | 0; - hi = Math.imul(ah2, bh0); - lo = (lo + Math.imul(al1, bl1)) | 0; - mid = (mid + Math.imul(al1, bh1)) | 0; - mid = (mid + Math.imul(ah1, bl1)) | 0; - hi = (hi + Math.imul(ah1, bh1)) | 0; - lo = (lo + Math.imul(al0, bl2)) | 0; - mid = (mid + Math.imul(al0, bh2)) | 0; - mid = (mid + Math.imul(ah0, bl2)) | 0; - hi = (hi + Math.imul(ah0, bh2)) | 0; - var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0; - w2 &= 0x3ffffff; - /* k = 3 */ - lo = Math.imul(al3, bl0); - mid = Math.imul(al3, bh0); - mid = (mid + Math.imul(ah3, bl0)) | 0; - hi = Math.imul(ah3, bh0); - lo = (lo + Math.imul(al2, bl1)) | 0; - mid = (mid + Math.imul(al2, bh1)) | 0; - mid = (mid + Math.imul(ah2, bl1)) | 0; - hi = (hi + Math.imul(ah2, bh1)) | 0; - lo = (lo + Math.imul(al1, bl2)) | 0; - mid = (mid + Math.imul(al1, bh2)) | 0; - mid = (mid + Math.imul(ah1, bl2)) | 0; - hi = (hi + Math.imul(ah1, bh2)) | 0; - lo = (lo + Math.imul(al0, bl3)) | 0; - mid = (mid + Math.imul(al0, bh3)) | 0; - mid = (mid + Math.imul(ah0, bl3)) | 0; - hi = (hi + Math.imul(ah0, bh3)) | 0; - var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0; - w3 &= 0x3ffffff; - /* k = 4 */ - lo = Math.imul(al4, bl0); - mid = Math.imul(al4, bh0); - mid = (mid + Math.imul(ah4, bl0)) | 0; - hi = Math.imul(ah4, bh0); - lo = (lo + Math.imul(al3, bl1)) | 0; - mid = (mid + Math.imul(al3, bh1)) | 0; - mid = (mid + Math.imul(ah3, bl1)) | 0; - hi = (hi + Math.imul(ah3, bh1)) | 0; - lo = (lo + Math.imul(al2, bl2)) | 0; - mid = (mid + Math.imul(al2, bh2)) | 0; - mid = (mid + Math.imul(ah2, bl2)) | 0; - hi = (hi + Math.imul(ah2, bh2)) | 0; - lo = (lo + Math.imul(al1, bl3)) | 0; - mid = (mid + Math.imul(al1, bh3)) | 0; - mid = (mid + Math.imul(ah1, bl3)) | 0; - hi = (hi + Math.imul(ah1, bh3)) | 0; - lo = (lo + Math.imul(al0, bl4)) | 0; - mid = (mid + Math.imul(al0, bh4)) | 0; - mid = (mid + Math.imul(ah0, bl4)) | 0; - hi = (hi + Math.imul(ah0, bh4)) | 0; - var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0; - w4 &= 0x3ffffff; - /* k = 5 */ - lo = Math.imul(al5, bl0); - mid = Math.imul(al5, bh0); - mid = (mid + Math.imul(ah5, bl0)) | 0; - hi = Math.imul(ah5, bh0); - lo = (lo + Math.imul(al4, bl1)) | 0; - mid = (mid + Math.imul(al4, bh1)) | 0; - mid = (mid + Math.imul(ah4, bl1)) | 0; - hi = (hi + Math.imul(ah4, bh1)) | 0; - lo = (lo + Math.imul(al3, bl2)) | 0; - mid = (mid + Math.imul(al3, bh2)) | 0; - mid = (mid + Math.imul(ah3, bl2)) | 0; - hi = (hi + Math.imul(ah3, bh2)) | 0; - lo = (lo + Math.imul(al2, bl3)) | 0; - mid = (mid + Math.imul(al2, bh3)) | 0; - mid = (mid + Math.imul(ah2, bl3)) | 0; - hi = (hi + Math.imul(ah2, bh3)) | 0; - lo = (lo + Math.imul(al1, bl4)) | 0; - mid = (mid + Math.imul(al1, bh4)) | 0; - mid = (mid + Math.imul(ah1, bl4)) | 0; - hi = (hi + Math.imul(ah1, bh4)) | 0; - lo = (lo + Math.imul(al0, bl5)) | 0; - mid = (mid + Math.imul(al0, bh5)) | 0; - mid = (mid + Math.imul(ah0, bl5)) | 0; - hi = (hi + Math.imul(ah0, bh5)) | 0; - var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0; - w5 &= 0x3ffffff; - /* k = 6 */ - lo = Math.imul(al6, bl0); - mid = Math.imul(al6, bh0); - mid = (mid + Math.imul(ah6, bl0)) | 0; - hi = Math.imul(ah6, bh0); - lo = (lo + Math.imul(al5, bl1)) | 0; - mid = (mid + Math.imul(al5, bh1)) | 0; - mid = (mid + Math.imul(ah5, bl1)) | 0; - hi = (hi + Math.imul(ah5, bh1)) | 0; - lo = (lo + Math.imul(al4, bl2)) | 0; - mid = (mid + Math.imul(al4, bh2)) | 0; - mid = (mid + Math.imul(ah4, bl2)) | 0; - hi = (hi + Math.imul(ah4, bh2)) | 0; - lo = (lo + Math.imul(al3, bl3)) | 0; - mid = (mid + Math.imul(al3, bh3)) | 0; - mid = (mid + Math.imul(ah3, bl3)) | 0; - hi = (hi + Math.imul(ah3, bh3)) | 0; - lo = (lo + Math.imul(al2, bl4)) | 0; - mid = (mid + Math.imul(al2, bh4)) | 0; - mid = (mid + Math.imul(ah2, bl4)) | 0; - hi = (hi + Math.imul(ah2, bh4)) | 0; - lo = (lo + Math.imul(al1, bl5)) | 0; - mid = (mid + Math.imul(al1, bh5)) | 0; - mid = (mid + Math.imul(ah1, bl5)) | 0; - hi = (hi + Math.imul(ah1, bh5)) | 0; - lo = (lo + Math.imul(al0, bl6)) | 0; - mid = (mid + Math.imul(al0, bh6)) | 0; - mid = (mid + Math.imul(ah0, bl6)) | 0; - hi = (hi + Math.imul(ah0, bh6)) | 0; - var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0; - w6 &= 0x3ffffff; - /* k = 7 */ - lo = Math.imul(al7, bl0); - mid = Math.imul(al7, bh0); - mid = (mid + Math.imul(ah7, bl0)) | 0; - hi = Math.imul(ah7, bh0); - lo = (lo + Math.imul(al6, bl1)) | 0; - mid = (mid + Math.imul(al6, bh1)) | 0; - mid = (mid + Math.imul(ah6, bl1)) | 0; - hi = (hi + Math.imul(ah6, bh1)) | 0; - lo = (lo + Math.imul(al5, bl2)) | 0; - mid = (mid + Math.imul(al5, bh2)) | 0; - mid = (mid + Math.imul(ah5, bl2)) | 0; - hi = (hi + Math.imul(ah5, bh2)) | 0; - lo = (lo + Math.imul(al4, bl3)) | 0; - mid = (mid + Math.imul(al4, bh3)) | 0; - mid = (mid + Math.imul(ah4, bl3)) | 0; - hi = (hi + Math.imul(ah4, bh3)) | 0; - lo = (lo + Math.imul(al3, bl4)) | 0; - mid = (mid + Math.imul(al3, bh4)) | 0; - mid = (mid + Math.imul(ah3, bl4)) | 0; - hi = (hi + Math.imul(ah3, bh4)) | 0; - lo = (lo + Math.imul(al2, bl5)) | 0; - mid = (mid + Math.imul(al2, bh5)) | 0; - mid = (mid + Math.imul(ah2, bl5)) | 0; - hi = (hi + Math.imul(ah2, bh5)) | 0; - lo = (lo + Math.imul(al1, bl6)) | 0; - mid = (mid + Math.imul(al1, bh6)) | 0; - mid = (mid + Math.imul(ah1, bl6)) | 0; - hi = (hi + Math.imul(ah1, bh6)) | 0; - lo = (lo + Math.imul(al0, bl7)) | 0; - mid = (mid + Math.imul(al0, bh7)) | 0; - mid = (mid + Math.imul(ah0, bl7)) | 0; - hi = (hi + Math.imul(ah0, bh7)) | 0; - var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0; - w7 &= 0x3ffffff; - /* k = 8 */ - lo = Math.imul(al8, bl0); - mid = Math.imul(al8, bh0); - mid = (mid + Math.imul(ah8, bl0)) | 0; - hi = Math.imul(ah8, bh0); - lo = (lo + Math.imul(al7, bl1)) | 0; - mid = (mid + Math.imul(al7, bh1)) | 0; - mid = (mid + Math.imul(ah7, bl1)) | 0; - hi = (hi + Math.imul(ah7, bh1)) | 0; - lo = (lo + Math.imul(al6, bl2)) | 0; - mid = (mid + Math.imul(al6, bh2)) | 0; - mid = (mid + Math.imul(ah6, bl2)) | 0; - hi = (hi + Math.imul(ah6, bh2)) | 0; - lo = (lo + Math.imul(al5, bl3)) | 0; - mid = (mid + Math.imul(al5, bh3)) | 0; - mid = (mid + Math.imul(ah5, bl3)) | 0; - hi = (hi + Math.imul(ah5, bh3)) | 0; - lo = (lo + Math.imul(al4, bl4)) | 0; - mid = (mid + Math.imul(al4, bh4)) | 0; - mid = (mid + Math.imul(ah4, bl4)) | 0; - hi = (hi + Math.imul(ah4, bh4)) | 0; - lo = (lo + Math.imul(al3, bl5)) | 0; - mid = (mid + Math.imul(al3, bh5)) | 0; - mid = (mid + Math.imul(ah3, bl5)) | 0; - hi = (hi + Math.imul(ah3, bh5)) | 0; - lo = (lo + Math.imul(al2, bl6)) | 0; - mid = (mid + Math.imul(al2, bh6)) | 0; - mid = (mid + Math.imul(ah2, bl6)) | 0; - hi = (hi + Math.imul(ah2, bh6)) | 0; - lo = (lo + Math.imul(al1, bl7)) | 0; - mid = (mid + Math.imul(al1, bh7)) | 0; - mid = (mid + Math.imul(ah1, bl7)) | 0; - hi = (hi + Math.imul(ah1, bh7)) | 0; - lo = (lo + Math.imul(al0, bl8)) | 0; - mid = (mid + Math.imul(al0, bh8)) | 0; - mid = (mid + Math.imul(ah0, bl8)) | 0; - hi = (hi + Math.imul(ah0, bh8)) | 0; - var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0; - w8 &= 0x3ffffff; - /* k = 9 */ - lo = Math.imul(al9, bl0); - mid = Math.imul(al9, bh0); - mid = (mid + Math.imul(ah9, bl0)) | 0; - hi = Math.imul(ah9, bh0); - lo = (lo + Math.imul(al8, bl1)) | 0; - mid = (mid + Math.imul(al8, bh1)) | 0; - mid = (mid + Math.imul(ah8, bl1)) | 0; - hi = (hi + Math.imul(ah8, bh1)) | 0; - lo = (lo + Math.imul(al7, bl2)) | 0; - mid = (mid + Math.imul(al7, bh2)) | 0; - mid = (mid + Math.imul(ah7, bl2)) | 0; - hi = (hi + Math.imul(ah7, bh2)) | 0; - lo = (lo + Math.imul(al6, bl3)) | 0; - mid = (mid + Math.imul(al6, bh3)) | 0; - mid = (mid + Math.imul(ah6, bl3)) | 0; - hi = (hi + Math.imul(ah6, bh3)) | 0; - lo = (lo + Math.imul(al5, bl4)) | 0; - mid = (mid + Math.imul(al5, bh4)) | 0; - mid = (mid + Math.imul(ah5, bl4)) | 0; - hi = (hi + Math.imul(ah5, bh4)) | 0; - lo = (lo + Math.imul(al4, bl5)) | 0; - mid = (mid + Math.imul(al4, bh5)) | 0; - mid = (mid + Math.imul(ah4, bl5)) | 0; - hi = (hi + Math.imul(ah4, bh5)) | 0; - lo = (lo + Math.imul(al3, bl6)) | 0; - mid = (mid + Math.imul(al3, bh6)) | 0; - mid = (mid + Math.imul(ah3, bl6)) | 0; - hi = (hi + Math.imul(ah3, bh6)) | 0; - lo = (lo + Math.imul(al2, bl7)) | 0; - mid = (mid + Math.imul(al2, bh7)) | 0; - mid = (mid + Math.imul(ah2, bl7)) | 0; - hi = (hi + Math.imul(ah2, bh7)) | 0; - lo = (lo + Math.imul(al1, bl8)) | 0; - mid = (mid + Math.imul(al1, bh8)) | 0; - mid = (mid + Math.imul(ah1, bl8)) | 0; - hi = (hi + Math.imul(ah1, bh8)) | 0; - lo = (lo + Math.imul(al0, bl9)) | 0; - mid = (mid + Math.imul(al0, bh9)) | 0; - mid = (mid + Math.imul(ah0, bl9)) | 0; - hi = (hi + Math.imul(ah0, bh9)) | 0; - var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0; - w9 &= 0x3ffffff; - /* k = 10 */ - lo = Math.imul(al9, bl1); - mid = Math.imul(al9, bh1); - mid = (mid + Math.imul(ah9, bl1)) | 0; - hi = Math.imul(ah9, bh1); - lo = (lo + Math.imul(al8, bl2)) | 0; - mid = (mid + Math.imul(al8, bh2)) | 0; - mid = (mid + Math.imul(ah8, bl2)) | 0; - hi = (hi + Math.imul(ah8, bh2)) | 0; - lo = (lo + Math.imul(al7, bl3)) | 0; - mid = (mid + Math.imul(al7, bh3)) | 0; - mid = (mid + Math.imul(ah7, bl3)) | 0; - hi = (hi + Math.imul(ah7, bh3)) | 0; - lo = (lo + Math.imul(al6, bl4)) | 0; - mid = (mid + Math.imul(al6, bh4)) | 0; - mid = (mid + Math.imul(ah6, bl4)) | 0; - hi = (hi + Math.imul(ah6, bh4)) | 0; - lo = (lo + Math.imul(al5, bl5)) | 0; - mid = (mid + Math.imul(al5, bh5)) | 0; - mid = (mid + Math.imul(ah5, bl5)) | 0; - hi = (hi + Math.imul(ah5, bh5)) | 0; - lo = (lo + Math.imul(al4, bl6)) | 0; - mid = (mid + Math.imul(al4, bh6)) | 0; - mid = (mid + Math.imul(ah4, bl6)) | 0; - hi = (hi + Math.imul(ah4, bh6)) | 0; - lo = (lo + Math.imul(al3, bl7)) | 0; - mid = (mid + Math.imul(al3, bh7)) | 0; - mid = (mid + Math.imul(ah3, bl7)) | 0; - hi = (hi + Math.imul(ah3, bh7)) | 0; - lo = (lo + Math.imul(al2, bl8)) | 0; - mid = (mid + Math.imul(al2, bh8)) | 0; - mid = (mid + Math.imul(ah2, bl8)) | 0; - hi = (hi + Math.imul(ah2, bh8)) | 0; - lo = (lo + Math.imul(al1, bl9)) | 0; - mid = (mid + Math.imul(al1, bh9)) | 0; - mid = (mid + Math.imul(ah1, bl9)) | 0; - hi = (hi + Math.imul(ah1, bh9)) | 0; - var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0; - w10 &= 0x3ffffff; - /* k = 11 */ - lo = Math.imul(al9, bl2); - mid = Math.imul(al9, bh2); - mid = (mid + Math.imul(ah9, bl2)) | 0; - hi = Math.imul(ah9, bh2); - lo = (lo + Math.imul(al8, bl3)) | 0; - mid = (mid + Math.imul(al8, bh3)) | 0; - mid = (mid + Math.imul(ah8, bl3)) | 0; - hi = (hi + Math.imul(ah8, bh3)) | 0; - lo = (lo + Math.imul(al7, bl4)) | 0; - mid = (mid + Math.imul(al7, bh4)) | 0; - mid = (mid + Math.imul(ah7, bl4)) | 0; - hi = (hi + Math.imul(ah7, bh4)) | 0; - lo = (lo + Math.imul(al6, bl5)) | 0; - mid = (mid + Math.imul(al6, bh5)) | 0; - mid = (mid + Math.imul(ah6, bl5)) | 0; - hi = (hi + Math.imul(ah6, bh5)) | 0; - lo = (lo + Math.imul(al5, bl6)) | 0; - mid = (mid + Math.imul(al5, bh6)) | 0; - mid = (mid + Math.imul(ah5, bl6)) | 0; - hi = (hi + Math.imul(ah5, bh6)) | 0; - lo = (lo + Math.imul(al4, bl7)) | 0; - mid = (mid + Math.imul(al4, bh7)) | 0; - mid = (mid + Math.imul(ah4, bl7)) | 0; - hi = (hi + Math.imul(ah4, bh7)) | 0; - lo = (lo + Math.imul(al3, bl8)) | 0; - mid = (mid + Math.imul(al3, bh8)) | 0; - mid = (mid + Math.imul(ah3, bl8)) | 0; - hi = (hi + Math.imul(ah3, bh8)) | 0; - lo = (lo + Math.imul(al2, bl9)) | 0; - mid = (mid + Math.imul(al2, bh9)) | 0; - mid = (mid + Math.imul(ah2, bl9)) | 0; - hi = (hi + Math.imul(ah2, bh9)) | 0; - var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0; - w11 &= 0x3ffffff; - /* k = 12 */ - lo = Math.imul(al9, bl3); - mid = Math.imul(al9, bh3); - mid = (mid + Math.imul(ah9, bl3)) | 0; - hi = Math.imul(ah9, bh3); - lo = (lo + Math.imul(al8, bl4)) | 0; - mid = (mid + Math.imul(al8, bh4)) | 0; - mid = (mid + Math.imul(ah8, bl4)) | 0; - hi = (hi + Math.imul(ah8, bh4)) | 0; - lo = (lo + Math.imul(al7, bl5)) | 0; - mid = (mid + Math.imul(al7, bh5)) | 0; - mid = (mid + Math.imul(ah7, bl5)) | 0; - hi = (hi + Math.imul(ah7, bh5)) | 0; - lo = (lo + Math.imul(al6, bl6)) | 0; - mid = (mid + Math.imul(al6, bh6)) | 0; - mid = (mid + Math.imul(ah6, bl6)) | 0; - hi = (hi + Math.imul(ah6, bh6)) | 0; - lo = (lo + Math.imul(al5, bl7)) | 0; - mid = (mid + Math.imul(al5, bh7)) | 0; - mid = (mid + Math.imul(ah5, bl7)) | 0; - hi = (hi + Math.imul(ah5, bh7)) | 0; - lo = (lo + Math.imul(al4, bl8)) | 0; - mid = (mid + Math.imul(al4, bh8)) | 0; - mid = (mid + Math.imul(ah4, bl8)) | 0; - hi = (hi + Math.imul(ah4, bh8)) | 0; - lo = (lo + Math.imul(al3, bl9)) | 0; - mid = (mid + Math.imul(al3, bh9)) | 0; - mid = (mid + Math.imul(ah3, bl9)) | 0; - hi = (hi + Math.imul(ah3, bh9)) | 0; - var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0; - w12 &= 0x3ffffff; - /* k = 13 */ - lo = Math.imul(al9, bl4); - mid = Math.imul(al9, bh4); - mid = (mid + Math.imul(ah9, bl4)) | 0; - hi = Math.imul(ah9, bh4); - lo = (lo + Math.imul(al8, bl5)) | 0; - mid = (mid + Math.imul(al8, bh5)) | 0; - mid = (mid + Math.imul(ah8, bl5)) | 0; - hi = (hi + Math.imul(ah8, bh5)) | 0; - lo = (lo + Math.imul(al7, bl6)) | 0; - mid = (mid + Math.imul(al7, bh6)) | 0; - mid = (mid + Math.imul(ah7, bl6)) | 0; - hi = (hi + Math.imul(ah7, bh6)) | 0; - lo = (lo + Math.imul(al6, bl7)) | 0; - mid = (mid + Math.imul(al6, bh7)) | 0; - mid = (mid + Math.imul(ah6, bl7)) | 0; - hi = (hi + Math.imul(ah6, bh7)) | 0; - lo = (lo + Math.imul(al5, bl8)) | 0; - mid = (mid + Math.imul(al5, bh8)) | 0; - mid = (mid + Math.imul(ah5, bl8)) | 0; - hi = (hi + Math.imul(ah5, bh8)) | 0; - lo = (lo + Math.imul(al4, bl9)) | 0; - mid = (mid + Math.imul(al4, bh9)) | 0; - mid = (mid + Math.imul(ah4, bl9)) | 0; - hi = (hi + Math.imul(ah4, bh9)) | 0; - var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0; - w13 &= 0x3ffffff; - /* k = 14 */ - lo = Math.imul(al9, bl5); - mid = Math.imul(al9, bh5); - mid = (mid + Math.imul(ah9, bl5)) | 0; - hi = Math.imul(ah9, bh5); - lo = (lo + Math.imul(al8, bl6)) | 0; - mid = (mid + Math.imul(al8, bh6)) | 0; - mid = (mid + Math.imul(ah8, bl6)) | 0; - hi = (hi + Math.imul(ah8, bh6)) | 0; - lo = (lo + Math.imul(al7, bl7)) | 0; - mid = (mid + Math.imul(al7, bh7)) | 0; - mid = (mid + Math.imul(ah7, bl7)) | 0; - hi = (hi + Math.imul(ah7, bh7)) | 0; - lo = (lo + Math.imul(al6, bl8)) | 0; - mid = (mid + Math.imul(al6, bh8)) | 0; - mid = (mid + Math.imul(ah6, bl8)) | 0; - hi = (hi + Math.imul(ah6, bh8)) | 0; - lo = (lo + Math.imul(al5, bl9)) | 0; - mid = (mid + Math.imul(al5, bh9)) | 0; - mid = (mid + Math.imul(ah5, bl9)) | 0; - hi = (hi + Math.imul(ah5, bh9)) | 0; - var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0; - w14 &= 0x3ffffff; - /* k = 15 */ - lo = Math.imul(al9, bl6); - mid = Math.imul(al9, bh6); - mid = (mid + Math.imul(ah9, bl6)) | 0; - hi = Math.imul(ah9, bh6); - lo = (lo + Math.imul(al8, bl7)) | 0; - mid = (mid + Math.imul(al8, bh7)) | 0; - mid = (mid + Math.imul(ah8, bl7)) | 0; - hi = (hi + Math.imul(ah8, bh7)) | 0; - lo = (lo + Math.imul(al7, bl8)) | 0; - mid = (mid + Math.imul(al7, bh8)) | 0; - mid = (mid + Math.imul(ah7, bl8)) | 0; - hi = (hi + Math.imul(ah7, bh8)) | 0; - lo = (lo + Math.imul(al6, bl9)) | 0; - mid = (mid + Math.imul(al6, bh9)) | 0; - mid = (mid + Math.imul(ah6, bl9)) | 0; - hi = (hi + Math.imul(ah6, bh9)) | 0; - var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0; - w15 &= 0x3ffffff; - /* k = 16 */ - lo = Math.imul(al9, bl7); - mid = Math.imul(al9, bh7); - mid = (mid + Math.imul(ah9, bl7)) | 0; - hi = Math.imul(ah9, bh7); - lo = (lo + Math.imul(al8, bl8)) | 0; - mid = (mid + Math.imul(al8, bh8)) | 0; - mid = (mid + Math.imul(ah8, bl8)) | 0; - hi = (hi + Math.imul(ah8, bh8)) | 0; - lo = (lo + Math.imul(al7, bl9)) | 0; - mid = (mid + Math.imul(al7, bh9)) | 0; - mid = (mid + Math.imul(ah7, bl9)) | 0; - hi = (hi + Math.imul(ah7, bh9)) | 0; - var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0; - w16 &= 0x3ffffff; - /* k = 17 */ - lo = Math.imul(al9, bl8); - mid = Math.imul(al9, bh8); - mid = (mid + Math.imul(ah9, bl8)) | 0; - hi = Math.imul(ah9, bh8); - lo = (lo + Math.imul(al8, bl9)) | 0; - mid = (mid + Math.imul(al8, bh9)) | 0; - mid = (mid + Math.imul(ah8, bl9)) | 0; - hi = (hi + Math.imul(ah8, bh9)) | 0; - var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0; - w17 &= 0x3ffffff; - /* k = 18 */ - lo = Math.imul(al9, bl9); - mid = Math.imul(al9, bh9); - mid = (mid + Math.imul(ah9, bl9)) | 0; - hi = Math.imul(ah9, bh9); - var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0; - w18 &= 0x3ffffff; - o[0] = w0; - o[1] = w1; - o[2] = w2; - o[3] = w3; - o[4] = w4; - o[5] = w5; - o[6] = w6; - o[7] = w7; - o[8] = w8; - o[9] = w9; - o[10] = w10; - o[11] = w11; - o[12] = w12; - o[13] = w13; - o[14] = w14; - o[15] = w15; - o[16] = w16; - o[17] = w17; - o[18] = w18; - if (c !== 0) { - o[19] = c; - out.length++; - } - return out; - }; +*/ - // Polyfill comb - if (!Math.imul) { - comb10MulTo = smallMulTo; - } + var zeros = [ + '', + '0', + '00', + '000', + '0000', + '00000', + '000000', + '0000000', + '00000000', + '000000000', + '0000000000', + '00000000000', + '000000000000', + '0000000000000', + '00000000000000', + '000000000000000', + '0000000000000000', + '00000000000000000', + '000000000000000000', + '0000000000000000000', + '00000000000000000000', + '000000000000000000000', + '0000000000000000000000', + '00000000000000000000000', + '000000000000000000000000', + '0000000000000000000000000', + ]; + + var groupSizes = [ + 0, + 0, + 25, + 16, + 12, + 11, + 10, + 9, + 8, + 8, + 7, + 7, + 7, + 7, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + ]; + + var groupBases = [ + 0, + 0, + 33554432, + 43046721, + 16777216, + 48828125, + 60466176, + 40353607, + 16777216, + 43046721, + 10000000, + 19487171, + 35831808, + 62748517, + 7529536, + 11390625, + 16777216, + 24137569, + 34012224, + 47045881, + 64000000, + 4084101, + 5153632, + 6436343, + 7962624, + 9765625, + 11881376, + 14348907, + 17210368, + 20511149, + 24300000, + 28629151, + 33554432, + 39135393, + 45435424, + 52521875, + 60466176, + ]; + + BN.prototype.toString = function toString(base, padding) { + base = base || 10; + if (base === 16 || base === 'hex') { + var out = ''; + var off = 0; + var padding = padding | 0 || 1; + var carry = 0; + for (var i = 0; i < this.length; i++) { + var w = this.words[i]; + var word = (((w << off) | carry) & 0xffffff).toString(16); + carry = (w >>> (24 - off)) & 0xffffff; + if (carry !== 0 || i !== this.length - 1) out = zeros[6 - word.length] + word + out; + else out = word + out; + off += 2; + if (off >= 26) { + off -= 26; + i--; + } + } + if (carry !== 0) out = carry.toString(16) + out; + while (out.length % padding !== 0) out = '0' + out; + if (this.sign) out = '-' + out; + return out; + } else if (base === (base | 0) && base >= 2 && base <= 36) { + // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base)); + var groupSize = groupSizes[base]; + // var groupBase = Math.pow(base, groupSize); + var groupBase = groupBases[base]; + var out = ''; + var c = this.clone(); + c.sign = false; + while (c.cmpn(0) !== 0) { + var r = c.modn(groupBase).toString(base); + c = c.idivn(groupBase); + + if (c.cmpn(0) !== 0) out = zeros[groupSize - r.length] + r + out; + else out = r + out; + } + if (this.cmpn(0) === 0) out = '0' + out; + if (this.sign) out = '-' + out; + return out; + } else { + assert(false, 'Base should be between 2 and 36'); + } + }; - function bigMulTo (self, num, out) { - out.negative = num.negative ^ self.negative; - out.length = self.length + num.length; - - var carry = 0; - var hncarry = 0; - for (var k = 0; k < out.length - 1; k++) { - // Sum all words with the same `i + j = k` and accumulate `ncarry`, - // note that ncarry could be >= 0x3ffffff - var ncarry = hncarry; - hncarry = 0; - var rword = carry & 0x3ffffff; - var maxJ = Math.min(k, num.length - 1); - for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { - var i = k - j; - var a = self.words[i] | 0; - var b = num.words[j] | 0; - var r = a * b; - - var lo = r & 0x3ffffff; - ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0; - lo = (lo + rword) | 0; - rword = lo & 0x3ffffff; - ncarry = (ncarry + (lo >>> 26)) | 0; - - hncarry += ncarry >>> 26; - ncarry &= 0x3ffffff; - } - out.words[k] = rword; - carry = ncarry; - ncarry = hncarry; - } - if (carry !== 0) { - out.words[k] = carry; - } else { - out.length--; - } + BN.prototype.toJSON = function toJSON() { + return this.toString(16); + }; - return out.strip(); - } + BN.prototype.toArray = function toArray() { + this.strip(); + var res = new Array(this.byteLength()); + res[0] = 0; - function jumboMulTo (self, num, out) { - var fftm = new FFTM(); - return fftm.mulp(self, num, out); - } + var q = this.clone(); + for (var i = 0; q.cmpn(0) !== 0; i++) { + var b = q.andln(0xff); + q.ishrn(8); - BN.prototype.mulTo = function mulTo (num, out) { - var res; - var len = this.length + num.length; - if (this.length === 10 && num.length === 10) { - res = comb10MulTo(this, num, out); - } else if (len < 63) { - res = smallMulTo(this, num, out); - } else if (len < 1024) { - res = bigMulTo(this, num, out); - } else { - res = jumboMulTo(this, num, out); - } + // Assume big-endian + res[res.length - i - 1] = b; + } - return res; - }; + return res; + }; - // Cooley-Tukey algorithm for FFT - // slightly revisited to rely on looping instead of recursion + if (Math.clz32) { + BN.prototype._countBits = function _countBits(w) { + return 32 - Math.clz32(w); + }; + } else { + BN.prototype._countBits = function _countBits(w) { + var t = w; + var r = 0; + if (t >= 0x1000) { + r += 13; + t >>>= 13; + } + if (t >= 0x40) { + r += 7; + t >>>= 7; + } + if (t >= 0x8) { + r += 4; + t >>>= 4; + } + if (t >= 0x02) { + r += 2; + t >>>= 2; + } + return r + t; + }; + } - function FFTM (x, y) { - this.x = x; - this.y = y; - } + BN.prototype._zeroBits = function _zeroBits(w) { + // Short-cut + if (w === 0) return 26; - FFTM.prototype.makeRBT = function makeRBT (N) { - var t = new Array(N); - var l = BN.prototype._countBits(N) - 1; - for (var i = 0; i < N; i++) { - t[i] = this.revBin(i, l, N); - } + var t = w; + var r = 0; + if ((t & 0x1fff) === 0) { + r += 13; + t >>>= 13; + } + if ((t & 0x7f) === 0) { + r += 7; + t >>>= 7; + } + if ((t & 0xf) === 0) { + r += 4; + t >>>= 4; + } + if ((t & 0x3) === 0) { + r += 2; + t >>>= 2; + } + if ((t & 0x1) === 0) r++; + return r; + }; + + // Return number of used bits in a BN + BN.prototype.bitLength = function bitLength() { + var hi = 0; + var w = this.words[this.length - 1]; + var hi = this._countBits(w); + return (this.length - 1) * 26 + hi; + }; + + // Number of trailing zero bits + BN.prototype.zeroBits = function zeroBits() { + if (this.cmpn(0) === 0) return 0; + + var r = 0; + for (var i = 0; i < this.length; i++) { + var b = this._zeroBits(this.words[i]); + r += b; + if (b !== 26) break; + } + return r; + }; - return t; - }; + BN.prototype.byteLength = function byteLength() { + return Math.ceil(this.bitLength() / 8); + }; - // Returns binary-reversed representation of `x` - FFTM.prototype.revBin = function revBin (x, l, N) { - if (x === 0 || x === N - 1) return x; + // Return negative clone of `this` + BN.prototype.neg = function neg() { + if (this.cmpn(0) === 0) return this.clone(); - var rb = 0; - for (var i = 0; i < l; i++) { - rb |= (x & 1) << (l - i - 1); - x >>= 1; - } + var r = this.clone(); + r.sign = !this.sign; + return r; + }; - return rb; - }; + // Or `num` with `this` in-place + BN.prototype.ior = function ior(num) { + this.sign = this.sign || num.sign; - // Performs "tweedling" phase, therefore 'emulating' - // behaviour of the recursive algorithm - FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) { - for (var i = 0; i < N; i++) { - rtws[i] = rws[rbt[i]]; - itws[i] = iws[rbt[i]]; - } - }; + while (this.length < num.length) this.words[this.length++] = 0; - FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) { - this.permute(rbt, rws, iws, rtws, itws, N); + for (var i = 0; i < num.length; i++) this.words[i] = this.words[i] | num.words[i]; - for (var s = 1; s < N; s <<= 1) { - var l = s << 1; + return this.strip(); + }; - var rtwdf = Math.cos(2 * Math.PI / l); - var itwdf = Math.sin(2 * Math.PI / l); + // Or `num` with `this` + BN.prototype.or = function or(num) { + if (this.length > num.length) return this.clone().ior(num); + else return num.clone().ior(this); + }; - for (var p = 0; p < N; p += l) { - var rtwdf_ = rtwdf; - var itwdf_ = itwdf; + // And `num` with `this` in-place + BN.prototype.iand = function iand(num) { + this.sign = this.sign && num.sign; - for (var j = 0; j < s; j++) { - var re = rtws[p + j]; - var ie = itws[p + j]; + // b = min-length(num, this) + var b; + if (this.length > num.length) b = num; + else b = this; - var ro = rtws[p + j + s]; - var io = itws[p + j + s]; + for (var i = 0; i < b.length; i++) this.words[i] = this.words[i] & num.words[i]; - var rx = rtwdf_ * ro - itwdf_ * io; + this.length = b.length; - io = rtwdf_ * io + itwdf_ * ro; - ro = rx; + return this.strip(); + }; - rtws[p + j] = re + ro; - itws[p + j] = ie + io; + // And `num` with `this` + BN.prototype.and = function and(num) { + if (this.length > num.length) return this.clone().iand(num); + else return num.clone().iand(this); + }; - rtws[p + j + s] = re - ro; - itws[p + j + s] = ie - io; + // Xor `num` with `this` in-place + BN.prototype.ixor = function ixor(num) { + this.sign = this.sign || num.sign; - /* jshint maxdepth : false */ - if (j !== l) { - rx = rtwdf * rtwdf_ - itwdf * itwdf_; + // a.length > b.length + var a; + var b; + if (this.length > num.length) { + a = this; + b = num; + } else { + a = num; + b = this; + } - itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_; - rtwdf_ = rx; - } - } - } - } - }; - - FFTM.prototype.guessLen13b = function guessLen13b (n, m) { - var N = Math.max(m, n) | 1; - var odd = N & 1; - var i = 0; - for (N = N / 2 | 0; N; N = N >>> 1) { - i++; - } + for (var i = 0; i < b.length; i++) this.words[i] = a.words[i] ^ b.words[i]; - return 1 << i + 1 + odd; - }; + if (this !== a) for (; i < a.length; i++) this.words[i] = a.words[i]; - FFTM.prototype.conjugate = function conjugate (rws, iws, N) { - if (N <= 1) return; + this.length = a.length; - for (var i = 0; i < N / 2; i++) { - var t = rws[i]; + return this.strip(); + }; - rws[i] = rws[N - i - 1]; - rws[N - i - 1] = t; + // Xor `num` with `this` + BN.prototype.xor = function xor(num) { + if (this.length > num.length) return this.clone().ixor(num); + else return num.clone().ixor(this); + }; - t = iws[i]; + // Set `bit` of `this` + BN.prototype.setn = function setn(bit, val) { + assert(typeof bit === 'number' && bit >= 0); - iws[i] = -iws[N - i - 1]; - iws[N - i - 1] = -t; - } - }; + var off = (bit / 26) | 0; + var wbit = bit % 26; - FFTM.prototype.normalize13b = function normalize13b (ws, N) { - var carry = 0; - for (var i = 0; i < N / 2; i++) { - var w = Math.round(ws[2 * i + 1] / N) * 0x2000 + - Math.round(ws[2 * i] / N) + - carry; + while (this.length <= off) this.words[this.length++] = 0; - ws[i] = w & 0x3ffffff; + if (val) this.words[off] = this.words[off] | (1 << wbit); + else this.words[off] = this.words[off] & ~(1 << wbit); - if (w < 0x4000000) { - carry = 0; - } else { - carry = w / 0x4000000 | 0; - } - } + return this.strip(); + }; - return ws; - }; + // Add `num` to `this` in-place + BN.prototype.iadd = function iadd(num) { + // negative + positive + if (this.sign && !num.sign) { + this.sign = false; + var r = this.isub(num); + this.sign = !this.sign; + return this._normSign(); - FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) { - var carry = 0; - for (var i = 0; i < len; i++) { - carry = carry + (ws[i] | 0); + // positive + negative + } else if (!this.sign && num.sign) { + num.sign = false; + var r = this.isub(num); + num.sign = true; + return r._normSign(); + } - rws[2 * i] = carry & 0x1fff; carry = carry >>> 13; - rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13; - } + // a.length > b.length + var a; + var b; + if (this.length > num.length) { + a = this; + b = num; + } else { + a = num; + b = this; + } - // Pad with zeroes - for (i = 2 * len; i < N; ++i) { - rws[i] = 0; - } + var carry = 0; + for (var i = 0; i < b.length; i++) { + var r = a.words[i] + b.words[i] + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; + } + for (; carry !== 0 && i < a.length; i++) { + var r = a.words[i] + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; + } - assert(carry === 0); - assert((carry & ~0x1fff) === 0); - }; + this.length = a.length; + if (carry !== 0) { + this.words[this.length] = carry; + this.length++; + // Copy the rest of the words + } else if (a !== this) { + for (; i < a.length; i++) this.words[i] = a.words[i]; + } - FFTM.prototype.stub = function stub (N) { - var ph = new Array(N); - for (var i = 0; i < N; i++) { - ph[i] = 0; - } + return this; + }; + + // Add `num` to `this` + BN.prototype.add = function add(num) { + if (num.sign && !this.sign) { + num.sign = false; + var res = this.sub(num); + num.sign = true; + return res; + } else if (!num.sign && this.sign) { + this.sign = false; + var res = num.sub(this); + this.sign = true; + return res; + } - return ph; - }; + if (this.length > num.length) return this.clone().iadd(num); + else return num.clone().iadd(this); + }; + + // Subtract `num` from `this` in-place + BN.prototype.isub = function isub(num) { + // this - (-num) = this + num + if (num.sign) { + num.sign = false; + var r = this.iadd(num); + num.sign = true; + return r._normSign(); + + // -this - num = -(this + num) + } else if (this.sign) { + this.sign = false; + this.iadd(num); + this.sign = true; + return this._normSign(); + } - FFTM.prototype.mulp = function mulp (x, y, out) { - var N = 2 * this.guessLen13b(x.length, y.length); + // At this point both numbers are positive + var cmp = this.cmp(num); - var rbt = this.makeRBT(N); + // Optimization - zeroify + if (cmp === 0) { + this.sign = false; + this.length = 1; + this.words[0] = 0; + return this; + } - var _ = this.stub(N); + // a > b + var a; + var b; + if (cmp > 0) { + a = this; + b = num; + } else { + a = num; + b = this; + } - var rws = new Array(N); - var rwst = new Array(N); - var iwst = new Array(N); + var carry = 0; + for (var i = 0; i < b.length; i++) { + var r = a.words[i] - b.words[i] + carry; + carry = r >> 26; + this.words[i] = r & 0x3ffffff; + } + for (; carry !== 0 && i < a.length; i++) { + var r = a.words[i] + carry; + carry = r >> 26; + this.words[i] = r & 0x3ffffff; + } - var nrws = new Array(N); - var nrwst = new Array(N); - var niwst = new Array(N); + // Copy rest of the words + if (carry === 0 && i < a.length && a !== this) for (; i < a.length; i++) this.words[i] = a.words[i]; + this.length = Math.max(this.length, i); - var rmws = out.words; - rmws.length = N; + if (a !== this) this.sign = true; - this.convert13b(x.words, x.length, rws, N); - this.convert13b(y.words, y.length, nrws, N); + return this.strip(); + }; - this.transform(rws, _, rwst, iwst, N, rbt); - this.transform(nrws, _, nrwst, niwst, N, rbt); + // Subtract `num` from `this` + BN.prototype.sub = function sub(num) { + return this.clone().isub(num); + }; - for (var i = 0; i < N; i++) { - var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i]; - iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i]; - rwst[i] = rx; - } + /* +// NOTE: This could be potentionally used to generate loop-less multiplications +function _genCombMulTo(alen, blen) { + var len = alen + blen - 1; + var src = [ + 'var a = this.words, b = num.words, o = out.words, c = 0, w, ' + + 'mask = 0x3ffffff, shift = 0x4000000;', + 'out.length = ' + len + ';' + ]; + for (var k = 0; k < len; k++) { + var minJ = Math.max(0, k - alen + 1); + var maxJ = Math.min(k, blen - 1); - this.conjugate(rwst, iwst, N); - this.transform(rwst, iwst, rmws, _, N, rbt); - this.conjugate(rmws, _, N); - this.normalize13b(rmws, N); - - out.negative = x.negative ^ y.negative; - out.length = x.length + y.length; - return out.strip(); - }; - - // Multiply `this` by `num` - BN.prototype.mul = function mul (num) { - var out = new BN(null); - out.words = new Array(this.length + num.length); - return this.mulTo(num, out); - }; - - // Multiply employing FFT - BN.prototype.mulf = function mulf (num) { - var out = new BN(null); - out.words = new Array(this.length + num.length); - return jumboMulTo(this, num, out); - }; - - // In-place Multiplication - BN.prototype.imul = function imul (num) { - return this.clone().mulTo(num, this); - }; - - BN.prototype.imuln = function imuln (num) { - assert(typeof num === 'number'); - assert(num < 0x4000000); - - // Carry - var carry = 0; - for (var i = 0; i < this.length; i++) { - var w = (this.words[i] | 0) * num; - var lo = (w & 0x3ffffff) + (carry & 0x3ffffff); - carry >>= 26; - carry += (w / 0x4000000) | 0; - // NOTE: lo is 27bit maximum - carry += lo >>> 26; - this.words[i] = lo & 0x3ffffff; - } + for (var j = minJ; j <= maxJ; j++) { + var i = k - j; + var mul = 'a[' + i + '] * b[' + j + ']'; - if (carry !== 0) { - this.words[i] = carry; - this.length++; + if (j === minJ) { + src.push('w = ' + mul + ' + c;'); + src.push('c = (w / shift) | 0;'); + } else { + src.push('w += ' + mul + ';'); + src.push('c += (w / shift) | 0;'); + } + src.push('w &= mask;'); } + src.push('o[' + k + '] = w;'); + } + src.push('if (c !== 0) {', + ' o[' + k + '] = c;', + ' out.length++;', + '}', + 'return out;'); - return this; - }; - - BN.prototype.muln = function muln (num) { - return this.clone().imuln(num); - }; + return src.join('\n'); +} +*/ - // `this` * `this` - BN.prototype.sqr = function sqr () { - return this.mul(this); - }; + BN.prototype._smallMulTo = function _smallMulTo(num, out) { + out.sign = num.sign !== this.sign; + out.length = this.length + num.length; + + var carry = 0; + for (var k = 0; k < out.length - 1; k++) { + // Sum all words with the same `i + j = k` and accumulate `ncarry`, + // note that ncarry could be >= 0x3ffffff + var ncarry = carry >>> 26; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - this.length + 1); j <= maxJ; j++) { + var i = k - j; + var a = this.words[i] | 0; + var b = num.words[j] | 0; + var r = a * b; + + var lo = r & 0x3ffffff; + ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0; + lo = (lo + rword) | 0; + rword = lo & 0x3ffffff; + ncarry = (ncarry + (lo >>> 26)) | 0; + } + out.words[k] = rword; + carry = ncarry; + } + if (carry !== 0) { + out.words[k] = carry; + } else { + out.length--; + } - // `this` * `this` in-place - BN.prototype.isqr = function isqr () { - return this.imul(this.clone()); - }; + return out.strip(); + }; + + BN.prototype._bigMulTo = function _bigMulTo(num, out) { + out.sign = num.sign !== this.sign; + out.length = this.length + num.length; + + var carry = 0; + var hncarry = 0; + for (var k = 0; k < out.length - 1; k++) { + // Sum all words with the same `i + j = k` and accumulate `ncarry`, + // note that ncarry could be >= 0x3ffffff + var ncarry = hncarry; + hncarry = 0; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - this.length + 1); j <= maxJ; j++) { + var i = k - j; + var a = this.words[i] | 0; + var b = num.words[j] | 0; + var r = a * b; + + var lo = r & 0x3ffffff; + ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0; + lo = (lo + rword) | 0; + rword = lo & 0x3ffffff; + ncarry = (ncarry + (lo >>> 26)) | 0; + + hncarry += ncarry >>> 26; + ncarry &= 0x3ffffff; + } + out.words[k] = rword; + carry = ncarry; + ncarry = hncarry; + } + if (carry !== 0) { + out.words[k] = carry; + } else { + out.length--; + } - // Math.pow(`this`, `num`) - BN.prototype.pow = function pow (num) { - var w = toBitArray(num); - if (w.length === 0) return new BN(1); + return out.strip(); + }; + + BN.prototype.mulTo = function mulTo(num, out) { + var res; + if (this.length + num.length < 63) res = this._smallMulTo(num, out); + else res = this._bigMulTo(num, out); + return res; + }; + + // Multiply `this` by `num` + BN.prototype.mul = function mul(num) { + var out = new BN(null); + out.words = new Array(this.length + num.length); + return this.mulTo(num, out); + }; + + // In-place Multiplication + BN.prototype.imul = function imul(num) { + if (this.cmpn(0) === 0 || num.cmpn(0) === 0) { + this.words[0] = 0; + this.length = 1; + return this; + } - // Skip leading zeroes - var res = this; - for (var i = 0; i < w.length; i++, res = res.sqr()) { - if (w[i] !== 0) break; - } + var tlen = this.length; + var nlen = num.length; + + this.sign = num.sign !== this.sign; + this.length = this.length + num.length; + this.words[this.length - 1] = 0; + + for (var k = this.length - 2; k >= 0; k--) { + // Sum all words with the same `i + j = k` and accumulate `carry`, + // note that carry could be >= 0x3ffffff + var carry = 0; + var rword = 0; + var maxJ = Math.min(k, nlen - 1); + for (var j = Math.max(0, k - tlen + 1); j <= maxJ; j++) { + var i = k - j; + var a = this.words[i]; + var b = num.words[j]; + var r = a * b; + + var lo = r & 0x3ffffff; + carry += (r / 0x4000000) | 0; + lo += rword; + rword = lo & 0x3ffffff; + carry += lo >>> 26; + } + this.words[k] = rword; + this.words[k + 1] += carry; + carry = 0; + } - if (++i < w.length) { - for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) { - if (w[i] === 0) continue; + // Propagate overflows + var carry = 0; + for (var i = 1; i < this.length; i++) { + var w = this.words[i] + carry; + this.words[i] = w & 0x3ffffff; + carry = w >>> 26; + } - res = res.mul(q); - } - } + return this.strip(); + }; + + BN.prototype.imuln = function imuln(num) { + assert(typeof num === 'number'); + + // Carry + var carry = 0; + for (var i = 0; i < this.length; i++) { + var w = this.words[i] * num; + var lo = (w & 0x3ffffff) + (carry & 0x3ffffff); + carry >>= 26; + carry += (w / 0x4000000) | 0; + // NOTE: lo is 27bit maximum + carry += lo >>> 26; + this.words[i] = lo & 0x3ffffff; + } - return res; - }; - - // Shift-left in-place - BN.prototype.iushln = function iushln (bits) { - assert(typeof bits === 'number' && bits >= 0); - var r = bits % 26; - var s = (bits - r) / 26; - var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r); - var i; - - if (r !== 0) { - var carry = 0; - - for (i = 0; i < this.length; i++) { - var newCarry = this.words[i] & carryMask; - var c = ((this.words[i] | 0) - newCarry) << r; - this.words[i] = c | carry; - carry = newCarry >>> (26 - r); - } + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } - if (carry) { - this.words[i] = carry; - this.length++; - } - } + return this; + }; + + // `this` * `this` + BN.prototype.sqr = function sqr() { + return this.mul(this); + }; + + // `this` * `this` in-place + BN.prototype.isqr = function isqr() { + return this.mul(this); + }; + + // Shift-left in-place + BN.prototype.ishln = function ishln(bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; + var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r); + + if (r !== 0) { + var carry = 0; + for (var i = 0; i < this.length; i++) { + var newCarry = this.words[i] & carryMask; + var c = (this.words[i] - newCarry) << r; + this.words[i] = c | carry; + carry = newCarry >>> (26 - r); + } + if (carry) { + this.words[i] = carry; + this.length++; + } + } - if (s !== 0) { - for (i = this.length - 1; i >= 0; i--) { - this.words[i + s] = this.words[i]; - } + if (s !== 0) { + for (var i = this.length - 1; i >= 0; i--) this.words[i + s] = this.words[i]; + for (var i = 0; i < s; i++) this.words[i] = 0; + this.length += s; + } - for (i = 0; i < s; i++) { - this.words[i] = 0; - } + return this.strip(); + }; + + // Shift-right in-place + // NOTE: `hint` is a lowest bit before trailing zeroes + // NOTE: if `extended` is present - it will be filled with destroyed bits + BN.prototype.ishrn = function ishrn(bits, hint, extended) { + assert(typeof bits === 'number' && bits >= 0); + var h; + if (hint) h = (hint - (hint % 26)) / 26; + else h = 0; + + var r = bits % 26; + var s = Math.min((bits - r) / 26, this.length); + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + var maskedWords = extended; + + h -= s; + h = Math.max(0, h); + + // Extended mode, copy masked part + if (maskedWords) { + for (var i = 0; i < s; i++) maskedWords.words[i] = this.words[i]; + maskedWords.length = s; + } - this.length += s; - } + if (s === 0) { + // No-op, we should not move anything at all + } else if (this.length > s) { + this.length -= s; + for (var i = 0; i < this.length; i++) this.words[i] = this.words[i + s]; + } else { + this.words[0] = 0; + this.length = 1; + } - return this.strip(); - }; - - BN.prototype.ishln = function ishln (bits) { - // TODO(indutny): implement me - assert(this.negative === 0); - return this.iushln(bits); - }; - - // Shift-right in-place - // NOTE: `hint` is a lowest bit before trailing zeroes - // NOTE: if `extended` is present - it will be filled with destroyed bits - BN.prototype.iushrn = function iushrn (bits, hint, extended) { - assert(typeof bits === 'number' && bits >= 0); - var h; - if (hint) { - h = (hint - (hint % 26)) / 26; - } else { - h = 0; - } + var carry = 0; + for (var i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) { + var word = this.words[i]; + this.words[i] = (carry << (26 - r)) | (word >>> r); + carry = word & mask; + } - var r = bits % 26; - var s = Math.min((bits - r) / 26, this.length); - var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); - var maskedWords = extended; + // Push carried bits as a mask + if (maskedWords && carry !== 0) maskedWords.words[maskedWords.length++] = carry; - h -= s; - h = Math.max(0, h); + if (this.length === 0) { + this.words[0] = 0; + this.length = 1; + } - // Extended mode, copy masked part - if (maskedWords) { - for (var i = 0; i < s; i++) { - maskedWords.words[i] = this.words[i]; - } - maskedWords.length = s; - } + this.strip(); - if (s === 0) { - // No-op, we should not move anything at all - } else if (this.length > s) { - this.length -= s; - for (i = 0; i < this.length; i++) { - this.words[i] = this.words[i + s]; - } - } else { - this.words[0] = 0; - this.length = 1; - } + return this; + }; - var carry = 0; - for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) { - var word = this.words[i] | 0; - this.words[i] = (carry << (26 - r)) | (word >>> r); - carry = word & mask; - } + // Shift-left + BN.prototype.shln = function shln(bits) { + return this.clone().ishln(bits); + }; - // Push carried bits as a mask - if (maskedWords && carry !== 0) { - maskedWords.words[maskedWords.length++] = carry; - } + // Shift-right + BN.prototype.shrn = function shrn(bits) { + return this.clone().ishrn(bits); + }; - if (this.length === 0) { - this.words[0] = 0; - this.length = 1; - } + // Test if n bit is set + BN.prototype.testn = function testn(bit) { + assert(typeof bit === 'number' && bit >= 0); + var r = bit % 26; + var s = (bit - r) / 26; + var q = 1 << r; - return this.strip(); - }; + // Fast case: bit is much higher than all existing words + if (this.length <= s) { + return false; + } - BN.prototype.ishrn = function ishrn (bits, hint, extended) { - // TODO(indutny): implement me - assert(this.negative === 0); - return this.iushrn(bits, hint, extended); - }; + // Check bit and return + var w = this.words[s]; - // Shift-left - BN.prototype.shln = function shln (bits) { - return this.clone().ishln(bits); - }; + return !!(w & q); + }; - BN.prototype.ushln = function ushln (bits) { - return this.clone().iushln(bits); - }; + // Return only lowers bits of number (in-place) + BN.prototype.imaskn = function imaskn(bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; - // Shift-right - BN.prototype.shrn = function shrn (bits) { - return this.clone().ishrn(bits); - }; + assert(!this.sign, 'imaskn works only with positive numbers'); - BN.prototype.ushrn = function ushrn (bits) { - return this.clone().iushrn(bits); - }; + if (r !== 0) s++; + this.length = Math.min(s, this.length); - // Test if n bit is set - BN.prototype.testn = function testn (bit) { - assert(typeof bit === 'number' && bit >= 0); - var r = bit % 26; - var s = (bit - r) / 26; - var q = 1 << r; + if (r !== 0) { + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + this.words[this.length - 1] &= mask; + } - // Fast case: bit is much higher than all existing words - if (this.length <= s) return false; + return this.strip(); + }; + + // Return only lowers bits of number + BN.prototype.maskn = function maskn(bits) { + return this.clone().imaskn(bits); + }; + + // Add plain number `num` to `this` + BN.prototype.iaddn = function iaddn(num) { + assert(typeof num === 'number'); + if (num < 0) return this.isubn(-num); + + // Possible sign change + if (this.sign) { + if (this.length === 1 && this.words[0] < num) { + this.words[0] = num - this.words[0]; + this.sign = false; + return this; + } - // Check bit and return - var w = this.words[s]; + this.sign = false; + this.isubn(num); + this.sign = true; + return this; + } - return !!(w & q); - }; + // Add without checks + return this._iaddn(num); + }; - // Return only lowers bits of number (in-place) - BN.prototype.imaskn = function imaskn (bits) { - assert(typeof bits === 'number' && bits >= 0); - var r = bits % 26; - var s = (bits - r) / 26; + BN.prototype._iaddn = function _iaddn(num) { + this.words[0] += num; - assert(this.negative === 0, 'imaskn works only with positive numbers'); + // Carry + for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) { + this.words[i] -= 0x4000000; + if (i === this.length - 1) this.words[i + 1] = 1; + else this.words[i + 1]++; + } + this.length = Math.max(this.length, i + 1); - if (this.length <= s) { - return this; - } + return this; + }; - if (r !== 0) { - s++; - } - this.length = Math.min(s, this.length); + // Subtract plain number `num` from `this` + BN.prototype.isubn = function isubn(num) { + assert(typeof num === 'number'); + if (num < 0) return this.iaddn(-num); - if (r !== 0) { - var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); - this.words[this.length - 1] &= mask; - } + if (this.sign) { + this.sign = false; + this.iaddn(num); + this.sign = true; + return this; + } - return this.strip(); - }; - - // Return only lowers bits of number - BN.prototype.maskn = function maskn (bits) { - return this.clone().imaskn(bits); - }; - - // Add plain number `num` to `this` - BN.prototype.iaddn = function iaddn (num) { - assert(typeof num === 'number'); - assert(num < 0x4000000); - if (num < 0) return this.isubn(-num); - - // Possible sign change - if (this.negative !== 0) { - if (this.length === 1 && (this.words[0] | 0) < num) { - this.words[0] = num - (this.words[0] | 0); - this.negative = 0; - return this; - } + this.words[0] -= num; - this.negative = 0; - this.isubn(num); - this.negative = 1; - return this; - } + // Carry + for (var i = 0; i < this.length && this.words[i] < 0; i++) { + this.words[i] += 0x4000000; + this.words[i + 1] -= 1; + } - // Add without checks - return this._iaddn(num); - }; + return this.strip(); + }; - BN.prototype._iaddn = function _iaddn (num) { - this.words[0] += num; + BN.prototype.addn = function addn(num) { + return this.clone().iaddn(num); + }; - // Carry - for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) { - this.words[i] -= 0x4000000; - if (i === this.length - 1) { - this.words[i + 1] = 1; - } else { - this.words[i + 1]++; - } - } - this.length = Math.max(this.length, i + 1); - - return this; - }; - - // Subtract plain number `num` from `this` - BN.prototype.isubn = function isubn (num) { - assert(typeof num === 'number'); - assert(num < 0x4000000); - if (num < 0) return this.iaddn(-num); - - if (this.negative !== 0) { - this.negative = 0; - this.iaddn(num); - this.negative = 1; - return this; - } + BN.prototype.subn = function subn(num) { + return this.clone().isubn(num); + }; - this.words[0] -= num; + BN.prototype.iabs = function iabs() { + this.sign = false; - if (this.length === 1 && this.words[0] < 0) { - this.words[0] = -this.words[0]; - this.negative = 1; - } else { - // Carry - for (var i = 0; i < this.length && this.words[i] < 0; i++) { - this.words[i] += 0x4000000; - this.words[i + 1] -= 1; - } - } + return this; + }; - return this.strip(); - }; + BN.prototype.abs = function abs() { + return this.clone().iabs(); + }; - BN.prototype.addn = function addn (num) { - return this.clone().iaddn(num); - }; + BN.prototype._ishlnsubmul = function _ishlnsubmul(num, mul, shift) { + // Bigger storage is needed + var len = num.length + shift; + var i; + if (this.words.length < len) { + var t = new Array(len); + for (var i = 0; i < this.length; i++) t[i] = this.words[i]; + this.words = t; + } else { + i = this.length; + } - BN.prototype.subn = function subn (num) { - return this.clone().isubn(num); - }; + // Zeroify rest + this.length = Math.max(this.length, len); + for (; i < this.length; i++) this.words[i] = 0; + + var carry = 0; + for (var i = 0; i < num.length; i++) { + var w = this.words[i + shift] + carry; + var right = num.words[i] * mul; + w -= right & 0x3ffffff; + carry = (w >> 26) - ((right / 0x4000000) | 0); + this.words[i + shift] = w & 0x3ffffff; + } + for (; i < this.length - shift; i++) { + var w = this.words[i + shift] + carry; + carry = w >> 26; + this.words[i + shift] = w & 0x3ffffff; + } - BN.prototype.iabs = function iabs () { - this.negative = 0; + if (carry === 0) return this.strip(); - return this; - }; + // Subtraction overflow + assert(carry === -1); + carry = 0; + for (var i = 0; i < this.length; i++) { + var w = -this.words[i] + carry; + carry = w >> 26; + this.words[i] = w & 0x3ffffff; + } + this.sign = true; - BN.prototype.abs = function abs () { - return this.clone().iabs(); - }; + return this.strip(); + }; - BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) { - var len = num.length + shift; - var i; + BN.prototype._wordDiv = function _wordDiv(num, mode) { + var shift = this.length - num.length; - this._expand(len); + var a = this.clone(); + var b = num; - var w; - var carry = 0; - for (i = 0; i < num.length; i++) { - w = (this.words[i + shift] | 0) + carry; - var right = (num.words[i] | 0) * mul; - w -= right & 0x3ffffff; - carry = (w >> 26) - ((right / 0x4000000) | 0); - this.words[i + shift] = w & 0x3ffffff; - } - for (; i < this.length - shift; i++) { - w = (this.words[i + shift] | 0) + carry; - carry = w >> 26; - this.words[i + shift] = w & 0x3ffffff; - } + // Normalize + var bhi = b.words[b.length - 1]; + var bhiBits = this._countBits(bhi); + shift = 26 - bhiBits; + if (shift !== 0) { + b = b.shln(shift); + a.ishln(shift); + bhi = b.words[b.length - 1]; + } - if (carry === 0) return this.strip(); + // Initialize quotient + var m = a.length - b.length; + var q; - // Subtraction overflow - assert(carry === -1); - carry = 0; - for (i = 0; i < this.length; i++) { - w = -(this.words[i] | 0) + carry; - carry = w >> 26; - this.words[i] = w & 0x3ffffff; - } - this.negative = 1; + if (mode !== 'mod') { + q = new BN(null); + q.length = m + 1; + q.words = new Array(q.length); + for (var i = 0; i < q.length; i++) q.words[i] = 0; + } - return this.strip(); - }; + var diff = a.clone()._ishlnsubmul(b, 1, m); + if (!diff.sign) { + a = diff; + if (q) q.words[m] = 1; + } - BN.prototype._wordDiv = function _wordDiv (num, mode) { - var shift = this.length - num.length; + for (var j = m - 1; j >= 0; j--) { + var qj = a.words[b.length + j] * 0x4000000 + a.words[b.length + j - 1]; - var a = this.clone(); - var b = num; + // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max + // (0x7ffffff) + qj = Math.min((qj / bhi) | 0, 0x3ffffff); - // Normalize - var bhi = b.words[b.length - 1] | 0; - var bhiBits = this._countBits(bhi); - shift = 26 - bhiBits; - if (shift !== 0) { - b = b.ushln(shift); - a.iushln(shift); - bhi = b.words[b.length - 1] | 0; - } + a._ishlnsubmul(b, qj, j); + while (a.sign) { + qj--; + a.sign = false; + a._ishlnsubmul(b, 1, j); + if (a.cmpn(0) !== 0) a.sign = !a.sign; + } + if (q) q.words[j] = qj; + } + if (q) q.strip(); + a.strip(); + + // Denormalize + if (mode !== 'div' && shift !== 0) a.ishrn(shift); + return { div: q ? q : null, mod: a }; + }; + + BN.prototype.divmod = function divmod(num, mode) { + assert(num.cmpn(0) !== 0); + + if (this.sign && !num.sign) { + var res = this.neg().divmod(num, mode); + var div; + var mod; + if (mode !== 'mod') div = res.div.neg(); + if (mode !== 'div') mod = res.mod.cmpn(0) === 0 ? res.mod : num.sub(res.mod); + return { + div: div, + mod: mod, + }; + } else if (!this.sign && num.sign) { + var res = this.divmod(num.neg(), mode); + var div; + if (mode !== 'mod') div = res.div.neg(); + return { div: div, mod: res.mod }; + } else if (this.sign && num.sign) { + return this.neg().divmod(num.neg(), mode); + } - // Initialize quotient - var m = a.length - b.length; - var q; + // Both numbers are positive at this point - if (mode !== 'mod') { - q = new BN(null); - q.length = m + 1; - q.words = new Array(q.length); - for (var i = 0; i < q.length; i++) { - q.words[i] = 0; - } - } + // Strip both numbers to approximate shift value + if (num.length > this.length || this.cmp(num) < 0) return { div: new BN(0), mod: this }; - var diff = a.clone()._ishlnsubmul(b, 1, m); - if (diff.negative === 0) { - a = diff; - if (q) { - q.words[m] = 1; - } - } + // Very short reduction + if (num.length === 1) { + if (mode === 'div') return { div: this.divn(num.words[0]), mod: null }; + else if (mode === 'mod') return { div: null, mod: new BN(this.modn(num.words[0])) }; + return { + div: this.divn(num.words[0]), + mod: new BN(this.modn(num.words[0])), + }; + } - for (var j = m - 1; j >= 0; j--) { - var qj = (a.words[b.length + j] | 0) * 0x4000000 + - (a.words[b.length + j - 1] | 0); + return this._wordDiv(num, mode); + }; - // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max - // (0x7ffffff) - qj = Math.min((qj / bhi) | 0, 0x3ffffff); + // Find `this` / `num` + BN.prototype.div = function div(num) { + return this.divmod(num, 'div').div; + }; - a._ishlnsubmul(b, qj, j); - while (a.negative !== 0) { - qj--; - a.negative = 0; - a._ishlnsubmul(b, 1, j); - if (!a.isZero()) { - a.negative ^= 1; - } - } - if (q) { - q.words[j] = qj; - } - } - if (q) { - q.strip(); - } - a.strip(); + // Find `this` % `num` + BN.prototype.mod = function mod(num) { + return this.divmod(num, 'mod').mod; + }; - // Denormalize - if (mode !== 'div' && shift !== 0) { - a.iushrn(shift); - } + // Find Round(`this` / `num`) + BN.prototype.divRound = function divRound(num) { + var dm = this.divmod(num); - return { - div: q || null, - mod: a - }; - }; - - // NOTE: 1) `mode` can be set to `mod` to request mod only, - // to `div` to request div only, or be absent to - // request both div & mod - // 2) `positive` is true if unsigned mod is requested - BN.prototype.divmod = function divmod (num, mode, positive) { - assert(!num.isZero()); - - if (this.isZero()) { - return { - div: new BN(0), - mod: new BN(0) - }; - } + // Fast case - exact division + if (dm.mod.cmpn(0) === 0) return dm.div; - var div, mod, res; - if (this.negative !== 0 && num.negative === 0) { - res = this.neg().divmod(num, mode); + var mod = dm.div.sign ? dm.mod.isub(num) : dm.mod; - if (mode !== 'mod') { - div = res.div.neg(); - } + var half = num.shrn(1); + var r2 = num.andln(1); + var cmp = mod.cmp(half); - if (mode !== 'div') { - mod = res.mod.neg(); - if (positive && mod.negative !== 0) { - mod.iadd(num); - } - } + // Round down + if (cmp < 0 || (r2 === 1 && cmp === 0)) return dm.div; - return { - div: div, - mod: mod - }; - } + // Round up + return dm.div.sign ? dm.div.isubn(1) : dm.div.iaddn(1); + }; - if (this.negative === 0 && num.negative !== 0) { - res = this.divmod(num.neg(), mode); + BN.prototype.modn = function modn(num) { + assert(num <= 0x3ffffff); + var p = (1 << 26) % num; - if (mode !== 'mod') { - div = res.div.neg(); - } + var acc = 0; + for (var i = this.length - 1; i >= 0; i--) acc = (p * acc + this.words[i]) % num; - return { - div: div, - mod: res.mod - }; - } + return acc; + }; - if ((this.negative & num.negative) !== 0) { - res = this.neg().divmod(num.neg(), mode); + // In-place division by number + BN.prototype.idivn = function idivn(num) { + assert(num <= 0x3ffffff); - if (mode !== 'div') { - mod = res.mod.neg(); - if (positive && mod.negative !== 0) { - mod.isub(num); - } - } + var carry = 0; + for (var i = this.length - 1; i >= 0; i--) { + var w = this.words[i] + carry * 0x4000000; + this.words[i] = (w / num) | 0; + carry = w % num; + } - return { - div: res.div, - mod: mod - }; - } + return this.strip(); + }; - // Both numbers are positive at this point + BN.prototype.divn = function divn(num) { + return this.clone().idivn(num); + }; - // Strip both numbers to approximate shift value - if (num.length > this.length || this.cmp(num) < 0) { - return { - div: new BN(0), - mod: this - }; - } + BN.prototype.egcd = function egcd(p) { + assert(!p.sign); + assert(p.cmpn(0) !== 0); - // Very short reduction - if (num.length === 1) { - if (mode === 'div') { - return { - div: this.divn(num.words[0]), - mod: null - }; - } + var x = this; + var y = p.clone(); - if (mode === 'mod') { - return { - div: null, - mod: new BN(this.modn(num.words[0])) - }; - } + if (x.sign) x = x.mod(p); + else x = x.clone(); - return { - div: this.divn(num.words[0]), - mod: new BN(this.modn(num.words[0])) - }; - } + // A * x + B * y = x + var A = new BN(1); + var B = new BN(0); - return this._wordDiv(num, mode); - }; + // C * x + D * y = y + var C = new BN(0); + var D = new BN(1); - // Find `this` / `num` - BN.prototype.div = function div (num) { - return this.divmod(num, 'div', false).div; - }; + var g = 0; - // Find `this` % `num` - BN.prototype.mod = function mod (num) { - return this.divmod(num, 'mod', false).mod; - }; + while (x.isEven() && y.isEven()) { + x.ishrn(1); + y.ishrn(1); + ++g; + } - BN.prototype.umod = function umod (num) { - return this.divmod(num, 'mod', true).mod; - }; + var yp = y.clone(); + var xp = x.clone(); + + while (x.cmpn(0) !== 0) { + while (x.isEven()) { + x.ishrn(1); + if (A.isEven() && B.isEven()) { + A.ishrn(1); + B.ishrn(1); + } else { + A.iadd(yp).ishrn(1); + B.isub(xp).ishrn(1); + } + } - // Find Round(`this` / `num`) - BN.prototype.divRound = function divRound (num) { - var dm = this.divmod(num); + while (y.isEven()) { + y.ishrn(1); + if (C.isEven() && D.isEven()) { + C.ishrn(1); + D.ishrn(1); + } else { + C.iadd(yp).ishrn(1); + D.isub(xp).ishrn(1); + } + } - // Fast case - exact division - if (dm.mod.isZero()) return dm.div; + if (x.cmp(y) >= 0) { + x.isub(y); + A.isub(C); + B.isub(D); + } else { + y.isub(x); + C.isub(A); + D.isub(B); + } + } - var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod; + return { + a: C, + b: D, + gcd: y.ishln(g), + }; + }; - var half = num.ushrn(1); - var r2 = num.andln(1); - var cmp = mod.cmp(half); + // This is reduced incarnation of the binary EEA + // above, designated to invert members of the + // _prime_ fields F(p) at a maximal speed + BN.prototype._invmp = function _invmp(p) { + assert(!p.sign); + assert(p.cmpn(0) !== 0); - // Round down - if (cmp < 0 || r2 === 1 && cmp === 0) return dm.div; + var a = this; + var b = p.clone(); - // Round up - return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1); - }; + if (a.sign) a = a.mod(p); + else a = a.clone(); - BN.prototype.modn = function modn (num) { - assert(num <= 0x3ffffff); - var p = (1 << 26) % num; + var x1 = new BN(1); + var x2 = new BN(0); - var acc = 0; - for (var i = this.length - 1; i >= 0; i--) { - acc = (p * acc + (this.words[i] | 0)) % num; - } + var delta = b.clone(); - return acc; - }; + while (a.cmpn(1) > 0 && b.cmpn(1) > 0) { + while (a.isEven()) { + a.ishrn(1); + if (x1.isEven()) x1.ishrn(1); + else x1.iadd(delta).ishrn(1); + } + while (b.isEven()) { + b.ishrn(1); + if (x2.isEven()) x2.ishrn(1); + else x2.iadd(delta).ishrn(1); + } + if (a.cmp(b) >= 0) { + a.isub(b); + x1.isub(x2); + } else { + b.isub(a); + x2.isub(x1); + } + } + if (a.cmpn(1) === 0) return x1; + else return x2; + }; + + BN.prototype.gcd = function gcd(num) { + if (this.cmpn(0) === 0) return num.clone(); + if (num.cmpn(0) === 0) return this.clone(); + + var a = this.clone(); + var b = num.clone(); + a.sign = false; + b.sign = false; + + // Remove common factor of two + for (var shift = 0; a.isEven() && b.isEven(); shift++) { + a.ishrn(1); + b.ishrn(1); + } - // In-place division by number - BN.prototype.idivn = function idivn (num) { - assert(num <= 0x3ffffff); + do { + while (a.isEven()) a.ishrn(1); + while (b.isEven()) b.ishrn(1); + + var r = a.cmp(b); + if (r < 0) { + // Swap `a` and `b` to make `a` always bigger than `b` + var t = a; + a = b; + b = t; + } else if (r === 0 || b.cmpn(1) === 0) { + break; + } - var carry = 0; - for (var i = this.length - 1; i >= 0; i--) { - var w = (this.words[i] | 0) + carry * 0x4000000; - this.words[i] = (w / num) | 0; - carry = w % num; - } + a.isub(b); + } while (true); + + return b.ishln(shift); + }; + + // Invert number in the field F(num) + BN.prototype.invm = function invm(num) { + return this.egcd(num).a.mod(num); + }; + + BN.prototype.isEven = function isEven() { + return (this.words[0] & 1) === 0; + }; + + BN.prototype.isOdd = function isOdd() { + return (this.words[0] & 1) === 1; + }; + + // And first word and num + BN.prototype.andln = function andln(num) { + return this.words[0] & num; + }; + + // Increment at the bit position in-line + BN.prototype.bincn = function bincn(bit) { + assert(typeof bit === 'number'); + var r = bit % 26; + var s = (bit - r) / 26; + var q = 1 << r; + + // Fast case: bit is much higher than all existing words + if (this.length <= s) { + for (var i = this.length; i < s + 1; i++) this.words[i] = 0; + this.words[s] |= q; + this.length = s + 1; + return this; + } - return this.strip(); - }; + // Add bit and propagate, if needed + var carry = q; + for (var i = s; carry !== 0 && i < this.length; i++) { + var w = this.words[i]; + w += carry; + carry = w >>> 26; + w &= 0x3ffffff; + this.words[i] = w; + } + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } + return this; + }; - BN.prototype.divn = function divn (num) { - return this.clone().idivn(num); - }; + BN.prototype.cmpn = function cmpn(num) { + var sign = num < 0; + if (sign) num = -num; - BN.prototype.egcd = function egcd (p) { - assert(p.negative === 0); - assert(!p.isZero()); + if (this.sign && !sign) return -1; + else if (!this.sign && sign) return 1; - var x = this; - var y = p.clone(); + num &= 0x3ffffff; + this.strip(); - if (x.negative !== 0) { - x = x.umod(p); - } else { - x = x.clone(); - } + var res; + if (this.length > 1) { + res = 1; + } else { + var w = this.words[0]; + res = w === num ? 0 : w < num ? -1 : 1; + } + if (this.sign) res = -res; + return res; + }; + + // Compare two numbers and return: + // 1 - if `this` > `num` + // 0 - if `this` == `num` + // -1 - if `this` < `num` + BN.prototype.cmp = function cmp(num) { + if (this.sign && !num.sign) return -1; + else if (!this.sign && num.sign) return 1; + + var res = this.ucmp(num); + if (this.sign) return -res; + else return res; + }; + + // Unsigned comparison + BN.prototype.ucmp = function ucmp(num) { + // At this point both numbers have the same sign + if (this.length > num.length) return 1; + else if (this.length < num.length) return -1; + + var res = 0; + for (var i = this.length - 1; i >= 0; i--) { + var a = this.words[i]; + var b = num.words[i]; + + if (a === b) continue; + if (a < b) res = -1; + else if (a > b) res = 1; + break; + } + return res; + }; - // A * x + B * y = x - var A = new BN(1); - var B = new BN(0); + // + // A reduce context, could be using montgomery or something better, depending + // on the `m` itself. + // + BN.red = function red(num) { + return new Red(num); + }; + + BN.prototype.toRed = function toRed(ctx) { + assert(!this.red, 'Already a number in reduction context'); + assert(!this.sign, 'red works only with positives'); + return ctx.convertTo(this)._forceRed(ctx); + }; + + BN.prototype.fromRed = function fromRed() { + assert(this.red, 'fromRed works only with numbers in reduction context'); + return this.red.convertFrom(this); + }; + + BN.prototype._forceRed = function _forceRed(ctx) { + this.red = ctx; + return this; + }; + + BN.prototype.forceRed = function forceRed(ctx) { + assert(!this.red, 'Already a number in reduction context'); + return this._forceRed(ctx); + }; + + BN.prototype.redAdd = function redAdd(num) { + assert(this.red, 'redAdd works only with red numbers'); + return this.red.add(this, num); + }; + + BN.prototype.redIAdd = function redIAdd(num) { + assert(this.red, 'redIAdd works only with red numbers'); + return this.red.iadd(this, num); + }; + + BN.prototype.redSub = function redSub(num) { + assert(this.red, 'redSub works only with red numbers'); + return this.red.sub(this, num); + }; + + BN.prototype.redISub = function redISub(num) { + assert(this.red, 'redISub works only with red numbers'); + return this.red.isub(this, num); + }; + + BN.prototype.redShl = function redShl(num) { + assert(this.red, 'redShl works only with red numbers'); + return this.red.shl(this, num); + }; + + BN.prototype.redMul = function redMul(num) { + assert(this.red, 'redMul works only with red numbers'); + this.red._verify2(this, num); + return this.red.mul(this, num); + }; + + BN.prototype.redIMul = function redIMul(num) { + assert(this.red, 'redMul works only with red numbers'); + this.red._verify2(this, num); + return this.red.imul(this, num); + }; + + BN.prototype.redSqr = function redSqr() { + assert(this.red, 'redSqr works only with red numbers'); + this.red._verify1(this); + return this.red.sqr(this); + }; + + BN.prototype.redISqr = function redISqr() { + assert(this.red, 'redISqr works only with red numbers'); + this.red._verify1(this); + return this.red.isqr(this); + }; + + // Square root over p + BN.prototype.redSqrt = function redSqrt() { + assert(this.red, 'redSqrt works only with red numbers'); + this.red._verify1(this); + return this.red.sqrt(this); + }; + + BN.prototype.redInvm = function redInvm() { + assert(this.red, 'redInvm works only with red numbers'); + this.red._verify1(this); + return this.red.invm(this); + }; + + // Return negative clone of `this` % `red modulo` + BN.prototype.redNeg = function redNeg() { + assert(this.red, 'redNeg works only with red numbers'); + this.red._verify1(this); + return this.red.neg(this); + }; + + BN.prototype.redPow = function redPow(num) { + assert(this.red && !num.red, 'redPow(normalNum)'); + this.red._verify1(this); + return this.red.pow(this, num); + }; + + // Prime numbers with efficient reduction + var primes = { + k256: null, + p224: null, + p192: null, + p25519: null, + }; + + // Pseudo-Mersenne prime + function MPrime(name, p) { + // P = 2 ^ N - K + this.name = name; + this.p = new BN(p, 16); + this.n = this.p.bitLength(); + this.k = new BN(1).ishln(this.n).isub(this.p); + + this.tmp = this._tmp(); + } - // C * x + D * y = y - var C = new BN(0); - var D = new BN(1); + MPrime.prototype._tmp = function _tmp() { + var tmp = new BN(null); + tmp.words = new Array(Math.ceil(this.n / 13)); + return tmp; + }; + + MPrime.prototype.ireduce = function ireduce(num) { + // Assumes that `num` is less than `P^2` + // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P) + var r = num; + var rlen; + + do { + this.split(r, this.tmp); + r = this.imulK(r); + r = r.iadd(this.tmp); + rlen = r.bitLength(); + } while (rlen > this.n); + + var cmp = rlen < this.n ? -1 : r.ucmp(this.p); + if (cmp === 0) { + r.words[0] = 0; + r.length = 1; + } else if (cmp > 0) { + r.isub(this.p); + } else { + r.strip(); + } - var g = 0; + return r; + }; - while (x.isEven() && y.isEven()) { - x.iushrn(1); - y.iushrn(1); - ++g; - } + MPrime.prototype.split = function split(input, out) { + input.ishrn(this.n, 0, out); + }; - var yp = y.clone(); - var xp = x.clone(); + MPrime.prototype.imulK = function imulK(num) { + return num.imul(this.k); + }; - while (!x.isZero()) { - for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1); - if (i > 0) { - x.iushrn(i); - while (i-- > 0) { - if (A.isOdd() || B.isOdd()) { - A.iadd(yp); - B.isub(xp); + function K256() { + MPrime.call(this, 'k256', 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f'); } + inherits(K256, MPrime); - A.iushrn(1); - B.iushrn(1); - } - } - - for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); - if (j > 0) { - y.iushrn(j); - while (j-- > 0) { - if (C.isOdd() || D.isOdd()) { - C.iadd(yp); - D.isub(xp); - } + K256.prototype.split = function split(input, output) { + // 256 = 9 * 26 + 22 + var mask = 0x3fffff; - C.iushrn(1); - D.iushrn(1); - } - } + var outLen = Math.min(input.length, 9); + for (var i = 0; i < outLen; i++) output.words[i] = input.words[i]; + output.length = outLen; - if (x.cmp(y) >= 0) { - x.isub(y); - A.isub(C); - B.isub(D); - } else { - y.isub(x); - C.isub(A); - D.isub(B); - } - } + if (input.length <= 9) { + input.words[0] = 0; + input.length = 1; + return; + } - return { - a: C, - b: D, - gcd: y.iushln(g) - }; - }; - - // This is reduced incarnation of the binary EEA - // above, designated to invert members of the - // _prime_ fields F(p) at a maximal speed - BN.prototype._invmp = function _invmp (p) { - assert(p.negative === 0); - assert(!p.isZero()); - - var a = this; - var b = p.clone(); - - if (a.negative !== 0) { - a = a.umod(p); - } else { - a = a.clone(); - } + // Shift by 9 limbs + var prev = input.words[9]; + output.words[output.length++] = prev & mask; - var x1 = new BN(1); - var x2 = new BN(0); + for (var i = 10; i < input.length; i++) { + var next = input.words[i]; + input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22); + prev = next; + } + input.words[i - 10] = prev >>> 22; + input.length -= 9; + }; + + K256.prototype.imulK = function imulK(num) { + // K = 0x1000003d1 = [ 0x40, 0x3d1 ] + num.words[num.length] = 0; + num.words[num.length + 1] = 0; + num.length += 2; + + // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390 + var hi; + var lo = 0; + for (var i = 0; i < num.length; i++) { + var w = num.words[i]; + hi = w * 0x40; + lo += w * 0x3d1; + hi += (lo / 0x4000000) | 0; + lo &= 0x3ffffff; + + num.words[i] = lo; + + lo = hi; + } - var delta = b.clone(); + // Fast length reduction + if (num.words[num.length - 1] === 0) { + num.length--; + if (num.words[num.length - 1] === 0) num.length--; + } + return num; + }; - while (a.cmpn(1) > 0 && b.cmpn(1) > 0) { - for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1); - if (i > 0) { - a.iushrn(i); - while (i-- > 0) { - if (x1.isOdd()) { - x1.iadd(delta); + function P224() { + MPrime.call(this, 'p224', 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001'); } + inherits(P224, MPrime); - x1.iushrn(1); - } - } - - for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); - if (j > 0) { - b.iushrn(j); - while (j-- > 0) { - if (x2.isOdd()) { - x2.iadd(delta); + function P192() { + MPrime.call(this, 'p192', 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff'); } + inherits(P192, MPrime); - x2.iushrn(1); - } - } - - if (a.cmp(b) >= 0) { - a.isub(b); - x1.isub(x2); - } else { - b.isub(a); - x2.isub(x1); - } - } - - var res; - if (a.cmpn(1) === 0) { - res = x1; - } else { - res = x2; - } - - if (res.cmpn(0) < 0) { - res.iadd(p); - } - - return res; - }; - - BN.prototype.gcd = function gcd (num) { - if (this.isZero()) return num.abs(); - if (num.isZero()) return this.abs(); + function P25519() { + // 2 ^ 255 - 19 + MPrime.call(this, '25519', '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed'); + } + inherits(P25519, MPrime); + + P25519.prototype.imulK = function imulK(num) { + // K = 0x13 + var carry = 0; + for (var i = 0; i < num.length; i++) { + var hi = num.words[i] * 0x13 + carry; + var lo = hi & 0x3ffffff; + hi >>>= 26; + + num.words[i] = lo; + carry = hi; + } + if (carry !== 0) num.words[num.length++] = carry; + return num; + }; + + // Exported mostly for testing purposes, use plain name instead + BN._prime = function prime(name) { + // Cached version of prime + if (primes[name]) return primes[name]; + + var prime; + if (name === 'k256') prime = new K256(); + else if (name === 'p224') prime = new P224(); + else if (name === 'p192') prime = new P192(); + else if (name === 'p25519') prime = new P25519(); + else throw new Error('Unknown prime ' + name); + primes[name] = prime; + + return prime; + }; - var a = this.clone(); - var b = num.clone(); - a.negative = 0; - b.negative = 0; + // + // Base reduction engine + // + function Red(m) { + if (typeof m === 'string') { + var prime = BN._prime(m); + this.m = prime.p; + this.prime = prime; + } else { + this.m = m; + this.prime = null; + } + } - // Remove common factor of two - for (var shift = 0; a.isEven() && b.isEven(); shift++) { - a.iushrn(1); - b.iushrn(1); - } + Red.prototype._verify1 = function _verify1(a) { + assert(!a.sign, 'red works only with positives'); + assert(a.red, 'red works only with red numbers'); + }; + + Red.prototype._verify2 = function _verify2(a, b) { + assert(!a.sign && !b.sign, 'red works only with positives'); + assert(a.red && a.red === b.red, 'red works only with red numbers'); + }; + + Red.prototype.imod = function imod(a) { + if (this.prime) return this.prime.ireduce(a)._forceRed(this); + return a.mod(this.m)._forceRed(this); + }; + + Red.prototype.neg = function neg(a) { + var r = a.clone(); + r.sign = !r.sign; + return r.iadd(this.m)._forceRed(this); + }; + + Red.prototype.add = function add(a, b) { + this._verify2(a, b); + + var res = a.add(b); + if (res.cmp(this.m) >= 0) res.isub(this.m); + return res._forceRed(this); + }; + + Red.prototype.iadd = function iadd(a, b) { + this._verify2(a, b); + + var res = a.iadd(b); + if (res.cmp(this.m) >= 0) res.isub(this.m); + return res; + }; + + Red.prototype.sub = function sub(a, b) { + this._verify2(a, b); + + var res = a.sub(b); + if (res.cmpn(0) < 0) res.iadd(this.m); + return res._forceRed(this); + }; + + Red.prototype.isub = function isub(a, b) { + this._verify2(a, b); + + var res = a.isub(b); + if (res.cmpn(0) < 0) res.iadd(this.m); + return res; + }; + + Red.prototype.shl = function shl(a, num) { + this._verify1(a); + return this.imod(a.shln(num)); + }; + + Red.prototype.imul = function imul(a, b) { + this._verify2(a, b); + return this.imod(a.imul(b)); + }; + + Red.prototype.mul = function mul(a, b) { + this._verify2(a, b); + return this.imod(a.mul(b)); + }; + + Red.prototype.isqr = function isqr(a) { + return this.imul(a, a); + }; + + Red.prototype.sqr = function sqr(a) { + return this.mul(a, a); + }; + + Red.prototype.sqrt = function sqrt(a) { + if (a.cmpn(0) === 0) return a.clone(); + + var mod3 = this.m.andln(3); + assert(mod3 % 2 === 1); + + // Fast case + if (mod3 === 3) { + var pow = this.m.add(new BN(1)).ishrn(2); + var r = this.pow(a, pow); + return r; + } - do { - while (a.isEven()) { - a.iushrn(1); - } - while (b.isEven()) { - b.iushrn(1); - } + // Tonelli-Shanks algorithm (Totally unoptimized and slow) + // + // Find Q and S, that Q * 2 ^ S = (P - 1) + var q = this.m.subn(1); + var s = 0; + while (q.cmpn(0) !== 0 && q.andln(1) === 0) { + s++; + q.ishrn(1); + } + assert(q.cmpn(0) !== 0); + + var one = new BN(1).toRed(this); + var nOne = one.redNeg(); + + // Find quadratic non-residue + // NOTE: Max is such because of generalized Riemann hypothesis. + var lpow = this.m.subn(1).ishrn(1); + var z = this.m.bitLength(); + z = new BN(2 * z * z).toRed(this); + while (this.pow(z, lpow).cmp(nOne) !== 0) z.redIAdd(nOne); + + var c = this.pow(z, q); + var r = this.pow(a, q.addn(1).ishrn(1)); + var t = this.pow(a, q); + var m = s; + while (t.cmp(one) !== 0) { + var tmp = t; + for (var i = 0; tmp.cmp(one) !== 0; i++) tmp = tmp.redSqr(); + assert(i < m); + var b = this.pow(c, new BN(1).ishln(m - i - 1)); + + r = r.redMul(b); + c = b.redSqr(); + t = t.redMul(c); + m = i; + } - var r = a.cmp(b); - if (r < 0) { - // Swap `a` and `b` to make `a` always bigger than `b` - var t = a; - a = b; - b = t; - } else if (r === 0 || b.cmpn(1) === 0) { - break; - } + return r; + }; - a.isub(b); - } while (true); - - return b.iushln(shift); - }; - - // Invert number in the field F(num) - BN.prototype.invm = function invm (num) { - return this.egcd(num).a.umod(num); - }; - - BN.prototype.isEven = function isEven () { - return (this.words[0] & 1) === 0; - }; - - BN.prototype.isOdd = function isOdd () { - return (this.words[0] & 1) === 1; - }; - - // And first word and num - BN.prototype.andln = function andln (num) { - return this.words[0] & num; - }; - - // Increment at the bit position in-line - BN.prototype.bincn = function bincn (bit) { - assert(typeof bit === 'number'); - var r = bit % 26; - var s = (bit - r) / 26; - var q = 1 << r; - - // Fast case: bit is much higher than all existing words - if (this.length <= s) { - this._expand(s + 1); - this.words[s] |= q; - return this; - } + Red.prototype.invm = function invm(a) { + var inv = a._invmp(this.m); + if (inv.sign) { + inv.sign = false; + return this.imod(inv).redNeg(); + } else { + return this.imod(inv); + } + }; - // Add bit and propagate, if needed - var carry = q; - for (var i = s; carry !== 0 && i < this.length; i++) { - var w = this.words[i] | 0; - w += carry; - carry = w >>> 26; - w &= 0x3ffffff; - this.words[i] = w; - } - if (carry !== 0) { - this.words[i] = carry; - this.length++; - } - return this; - }; + Red.prototype.pow = function pow(a, num) { + var w = []; - BN.prototype.isZero = function isZero () { - return this.length === 1 && this.words[0] === 0; - }; + if (num.cmpn(0) === 0) return new BN(1); - BN.prototype.cmpn = function cmpn (num) { - var negative = num < 0; + var q = num.clone(); - if (this.negative !== 0 && !negative) return -1; - if (this.negative === 0 && negative) return 1; + while (q.cmpn(0) !== 0) { + w.push(q.andln(1)); + q.ishrn(1); + } - this.strip(); + // Skip leading zeroes + var res = a; + for (var i = 0; i < w.length; i++, res = this.sqr(res)) if (w[i] !== 0) break; - var res; - if (this.length > 1) { - res = 1; - } else { - if (negative) { - num = -num; - } + if (++i < w.length) { + for (var q = this.sqr(res); i < w.length; i++, q = this.sqr(q)) { + if (w[i] === 0) continue; + res = this.mul(res, q); + } + } - assert(num <= 0x3ffffff, 'Number is too big'); + return res; + }; - var w = this.words[0] | 0; - res = w === num ? 0 : w < num ? -1 : 1; - } - if (this.negative !== 0) return -res | 0; - return res; - }; - - // Compare two numbers and return: - // 1 - if `this` > `num` - // 0 - if `this` == `num` - // -1 - if `this` < `num` - BN.prototype.cmp = function cmp (num) { - if (this.negative !== 0 && num.negative === 0) return -1; - if (this.negative === 0 && num.negative !== 0) return 1; - - var res = this.ucmp(num); - if (this.negative !== 0) return -res | 0; - return res; - }; - - // Unsigned comparison - BN.prototype.ucmp = function ucmp (num) { - // At this point both numbers have the same sign - if (this.length > num.length) return 1; - if (this.length < num.length) return -1; - - var res = 0; - for (var i = this.length - 1; i >= 0; i--) { - var a = this.words[i] | 0; - var b = num.words[i] | 0; - - if (a === b) continue; - if (a < b) { - res = -1; - } else if (a > b) { - res = 1; - } - break; - } - return res; - }; - - BN.prototype.gtn = function gtn (num) { - return this.cmpn(num) === 1; - }; - - BN.prototype.gt = function gt (num) { - return this.cmp(num) === 1; - }; - - BN.prototype.gten = function gten (num) { - return this.cmpn(num) >= 0; - }; - - BN.prototype.gte = function gte (num) { - return this.cmp(num) >= 0; - }; - - BN.prototype.ltn = function ltn (num) { - return this.cmpn(num) === -1; - }; - - BN.prototype.lt = function lt (num) { - return this.cmp(num) === -1; - }; - - BN.prototype.lten = function lten (num) { - return this.cmpn(num) <= 0; - }; - - BN.prototype.lte = function lte (num) { - return this.cmp(num) <= 0; - }; - - BN.prototype.eqn = function eqn (num) { - return this.cmpn(num) === 0; - }; - - BN.prototype.eq = function eq (num) { - return this.cmp(num) === 0; - }; - - // - // A reduce context, could be using montgomery or something better, depending - // on the `m` itself. - // - BN.red = function red (num) { - return new Red(num); - }; - - BN.prototype.toRed = function toRed (ctx) { - assert(!this.red, 'Already a number in reduction context'); - assert(this.negative === 0, 'red works only with positives'); - return ctx.convertTo(this)._forceRed(ctx); - }; - - BN.prototype.fromRed = function fromRed () { - assert(this.red, 'fromRed works only with numbers in reduction context'); - return this.red.convertFrom(this); - }; - - BN.prototype._forceRed = function _forceRed (ctx) { - this.red = ctx; - return this; - }; - - BN.prototype.forceRed = function forceRed (ctx) { - assert(!this.red, 'Already a number in reduction context'); - return this._forceRed(ctx); - }; - - BN.prototype.redAdd = function redAdd (num) { - assert(this.red, 'redAdd works only with red numbers'); - return this.red.add(this, num); - }; - - BN.prototype.redIAdd = function redIAdd (num) { - assert(this.red, 'redIAdd works only with red numbers'); - return this.red.iadd(this, num); - }; - - BN.prototype.redSub = function redSub (num) { - assert(this.red, 'redSub works only with red numbers'); - return this.red.sub(this, num); - }; - - BN.prototype.redISub = function redISub (num) { - assert(this.red, 'redISub works only with red numbers'); - return this.red.isub(this, num); - }; - - BN.prototype.redShl = function redShl (num) { - assert(this.red, 'redShl works only with red numbers'); - return this.red.shl(this, num); - }; - - BN.prototype.redMul = function redMul (num) { - assert(this.red, 'redMul works only with red numbers'); - this.red._verify2(this, num); - return this.red.mul(this, num); - }; - - BN.prototype.redIMul = function redIMul (num) { - assert(this.red, 'redMul works only with red numbers'); - this.red._verify2(this, num); - return this.red.imul(this, num); - }; - - BN.prototype.redSqr = function redSqr () { - assert(this.red, 'redSqr works only with red numbers'); - this.red._verify1(this); - return this.red.sqr(this); - }; - - BN.prototype.redISqr = function redISqr () { - assert(this.red, 'redISqr works only with red numbers'); - this.red._verify1(this); - return this.red.isqr(this); - }; - - // Square root over p - BN.prototype.redSqrt = function redSqrt () { - assert(this.red, 'redSqrt works only with red numbers'); - this.red._verify1(this); - return this.red.sqrt(this); - }; - - BN.prototype.redInvm = function redInvm () { - assert(this.red, 'redInvm works only with red numbers'); - this.red._verify1(this); - return this.red.invm(this); - }; - - // Return negative clone of `this` % `red modulo` - BN.prototype.redNeg = function redNeg () { - assert(this.red, 'redNeg works only with red numbers'); - this.red._verify1(this); - return this.red.neg(this); - }; - - BN.prototype.redPow = function redPow (num) { - assert(this.red && !num.red, 'redPow(normalNum)'); - this.red._verify1(this); - return this.red.pow(this, num); - }; - - // Prime numbers with efficient reduction - var primes = { - k256: null, - p224: null, - p192: null, - p25519: null - }; - - // Pseudo-Mersenne prime - function MPrime (name, p) { - // P = 2 ^ N - K - this.name = name; - this.p = new BN(p, 16); - this.n = this.p.bitLength(); - this.k = new BN(1).iushln(this.n).isub(this.p); - - this.tmp = this._tmp(); - } + Red.prototype.convertTo = function convertTo(num) { + return num.clone(); + }; - MPrime.prototype._tmp = function _tmp () { - var tmp = new BN(null); - tmp.words = new Array(Math.ceil(this.n / 13)); - return tmp; - }; - - MPrime.prototype.ireduce = function ireduce (num) { - // Assumes that `num` is less than `P^2` - // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P) - var r = num; - var rlen; - - do { - this.split(r, this.tmp); - r = this.imulK(r); - r = r.iadd(this.tmp); - rlen = r.bitLength(); - } while (rlen > this.n); - - var cmp = rlen < this.n ? -1 : r.ucmp(this.p); - if (cmp === 0) { - r.words[0] = 0; - r.length = 1; - } else if (cmp > 0) { - r.isub(this.p); - } else { - r.strip(); - } + Red.prototype.convertFrom = function convertFrom(num) { + var res = num.clone(); + res.red = null; + return res; + }; - return r; - }; + // + // Montgomery method engine + // - MPrime.prototype.split = function split (input, out) { - input.iushrn(this.n, 0, out); - }; + BN.mont = function mont(num) { + return new Mont(num); + }; + + function Mont(m) { + Red.call(this, m); + + this.shift = this.m.bitLength(); + if (this.shift % 26 !== 0) this.shift += 26 - (this.shift % 26); + this.r = new BN(1).ishln(this.shift); + this.r2 = this.imod(this.r.sqr()); + this.rinv = this.r._invmp(this.m); + + this.minv = this.rinv + .mul(this.r) + .isubn(1) + .div(this.m); + this.minv.sign = true; + this.minv = this.minv.mod(this.r); + } + inherits(Mont, Red); + + Mont.prototype.convertTo = function convertTo(num) { + return this.imod(num.shln(this.shift)); + }; + + Mont.prototype.convertFrom = function convertFrom(num) { + var r = this.imod(num.mul(this.rinv)); + r.red = null; + return r; + }; + + Mont.prototype.imul = function imul(a, b) { + if (a.cmpn(0) === 0 || b.cmpn(0) === 0) { + a.words[0] = 0; + a.length = 1; + return a; + } - MPrime.prototype.imulK = function imulK (num) { - return num.imul(this.k); - }; + var t = a.imul(b); + var c = t + .maskn(this.shift) + .mul(this.minv) + .imaskn(this.shift) + .mul(this.m); + var u = t.isub(c).ishrn(this.shift); + var res = u; + if (u.cmp(this.m) >= 0) res = u.isub(this.m); + else if (u.cmpn(0) < 0) res = u.iadd(this.m); + + return res._forceRed(this); + }; + + Mont.prototype.mul = function mul(a, b) { + if (a.cmpn(0) === 0 || b.cmpn(0) === 0) return new BN(0)._forceRed(this); + + var t = a.mul(b); + var c = t + .maskn(this.shift) + .mul(this.minv) + .imaskn(this.shift) + .mul(this.m); + var u = t.isub(c).ishrn(this.shift); + var res = u; + if (u.cmp(this.m) >= 0) res = u.isub(this.m); + else if (u.cmpn(0) < 0) res = u.iadd(this.m); + + return res._forceRed(this); + }; + + Mont.prototype.invm = function invm(a) { + // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R + var res = this.imod(a._invmp(this.m).mul(this.r2)); + return res._forceRed(this); + }; + })(typeof module === 'undefined' || module, this); + }, + {}, + ], + 63: [ + function(require, module, exports) { + var r; - function K256 () { - MPrime.call( - this, - 'k256', - 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f'); - } - inherits(K256, MPrime); + module.exports = function rand(len) { + if (!r) r = new Rand(null); - K256.prototype.split = function split (input, output) { - // 256 = 9 * 26 + 22 - var mask = 0x3fffff; + return r.generate(len); + }; - var outLen = Math.min(input.length, 9); - for (var i = 0; i < outLen; i++) { - output.words[i] = input.words[i]; - } - output.length = outLen; + function Rand(rand) { + this.rand = rand; + } + module.exports.Rand = Rand; - if (input.length <= 9) { - input.words[0] = 0; - input.length = 1; - return; - } + Rand.prototype.generate = function generate(len) { + return this._rand(len); + }; - // Shift by 9 limbs - var prev = input.words[9]; - output.words[output.length++] = prev & mask; + // Emulate crypto API using randy + Rand.prototype._rand = function _rand(n) { + if (this.rand.getBytes) return this.rand.getBytes(n); - for (i = 10; i < input.length; i++) { - var next = input.words[i] | 0; - input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22); - prev = next; - } - prev >>>= 22; - input.words[i - 10] = prev; - if (prev === 0 && input.length > 10) { - input.length -= 10; - } else { - input.length -= 9; - } - }; - - K256.prototype.imulK = function imulK (num) { - // K = 0x1000003d1 = [ 0x40, 0x3d1 ] - num.words[num.length] = 0; - num.words[num.length + 1] = 0; - num.length += 2; - - // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390 - var lo = 0; - for (var i = 0; i < num.length; i++) { - var w = num.words[i] | 0; - lo += w * 0x3d1; - num.words[i] = lo & 0x3ffffff; - lo = w * 0x40 + ((lo / 0x4000000) | 0); - } + var res = new Uint8Array(n); + for (var i = 0; i < res.length; i++) res[i] = this.rand.getByte(); + return res; + }; - // Fast length reduction - if (num.words[num.length - 1] === 0) { - num.length--; - if (num.words[num.length - 1] === 0) { - num.length--; - } - } - return num; - }; - - function P224 () { - MPrime.call( - this, - 'p224', - 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001'); - } - inherits(P224, MPrime); + if (typeof self === 'object') { + if (self.crypto && self.crypto.getRandomValues) { + // Modern browsers + Rand.prototype._rand = function _rand(n) { + var arr = new Uint8Array(n); + self.crypto.getRandomValues(arr); + return arr; + }; + } else if (self.msCrypto && self.msCrypto.getRandomValues) { + // IE + Rand.prototype._rand = function _rand(n) { + var arr = new Uint8Array(n); + self.msCrypto.getRandomValues(arr); + return arr; + }; - function P192 () { - MPrime.call( - this, - 'p192', - 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff'); - } - inherits(P192, MPrime); - - function P25519 () { - // 2 ^ 255 - 19 - MPrime.call( - this, - '25519', - '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed'); - } - inherits(P25519, MPrime); - - P25519.prototype.imulK = function imulK (num) { - // K = 0x13 - var carry = 0; - for (var i = 0; i < num.length; i++) { - var hi = (num.words[i] | 0) * 0x13 + carry; - var lo = hi & 0x3ffffff; - hi >>>= 26; - - num.words[i] = lo; - carry = hi; - } - if (carry !== 0) { - num.words[num.length++] = carry; - } - return num; - }; - - // Exported mostly for testing purposes, use plain name instead - BN._prime = function prime (name) { - // Cached version of prime - if (primes[name]) return primes[name]; - - var prime; - if (name === 'k256') { - prime = new K256(); - } else if (name === 'p224') { - prime = new P224(); - } else if (name === 'p192') { - prime = new P192(); - } else if (name === 'p25519') { - prime = new P25519(); - } else { - throw new Error('Unknown prime ' + name); - } - primes[name] = prime; - - return prime; - }; - - // - // Base reduction engine - // - function Red (m) { - if (typeof m === 'string') { - var prime = BN._prime(m); - this.m = prime.p; - this.prime = prime; - } else { - assert(m.gtn(1), 'modulus must be greater than 1'); - this.m = m; - this.prime = null; - } - } + // Safari's WebWorkers do not have `crypto` + } else if (typeof window === 'object') { + // Old junk + Rand.prototype._rand = function() { + throw new Error('Not implemented yet'); + }; + } + } else { + // Node.js or Web worker with no crypto support + try { + var crypto = require('crypto'); + if (typeof crypto.randomBytes !== 'function') throw new Error('Not supported'); - Red.prototype._verify1 = function _verify1 (a) { - assert(a.negative === 0, 'red works only with positives'); - assert(a.red, 'red works only with red numbers'); - }; - - Red.prototype._verify2 = function _verify2 (a, b) { - assert((a.negative | b.negative) === 0, 'red works only with positives'); - assert(a.red && a.red === b.red, - 'red works only with red numbers'); - }; - - Red.prototype.imod = function imod (a) { - if (this.prime) return this.prime.ireduce(a)._forceRed(this); - return a.umod(this.m)._forceRed(this); - }; - - Red.prototype.neg = function neg (a) { - if (a.isZero()) { - return a.clone(); - } + Rand.prototype._rand = function _rand(n) { + return crypto.randomBytes(n); + }; + } catch (e) {} + } + }, + { crypto: 64 }, + ], + 64: [function(require, module, exports) {}, {}], + 65: [ + function(require, module, exports) { + // based on the aes implimentation in triple sec + // https://github.com/keybase/triplesec + // which is in turn based on the one from crypto-js + // https://code.google.com/p/crypto-js/ + + var Buffer = require('safe-buffer').Buffer; + + function asUInt32Array(buf) { + if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf); + + var len = (buf.length / 4) | 0; + var out = new Array(len); + + for (var i = 0; i < len; i++) { + out[i] = buf.readUInt32BE(i * 4); + } - return this.m.sub(a)._forceRed(this); - }; + return out; + } - Red.prototype.add = function add (a, b) { - this._verify2(a, b); + function scrubVec(v) { + for (var i = 0; i < v.length; v++) { + v[i] = 0; + } + } - var res = a.add(b); - if (res.cmp(this.m) >= 0) { - res.isub(this.m); - } - return res._forceRed(this); - }; + function cryptBlock(M, keySchedule, SUB_MIX, SBOX, nRounds) { + var SUB_MIX0 = SUB_MIX[0]; + var SUB_MIX1 = SUB_MIX[1]; + var SUB_MIX2 = SUB_MIX[2]; + var SUB_MIX3 = SUB_MIX[3]; + + var s0 = M[0] ^ keySchedule[0]; + var s1 = M[1] ^ keySchedule[1]; + var s2 = M[2] ^ keySchedule[2]; + var s3 = M[3] ^ keySchedule[3]; + var t0, t1, t2, t3; + var ksRow = 4; + + for (var round = 1; round < nRounds; round++) { + t0 = + SUB_MIX0[s0 >>> 24] ^ + SUB_MIX1[(s1 >>> 16) & 0xff] ^ + SUB_MIX2[(s2 >>> 8) & 0xff] ^ + SUB_MIX3[s3 & 0xff] ^ + keySchedule[ksRow++]; + t1 = + SUB_MIX0[s1 >>> 24] ^ + SUB_MIX1[(s2 >>> 16) & 0xff] ^ + SUB_MIX2[(s3 >>> 8) & 0xff] ^ + SUB_MIX3[s0 & 0xff] ^ + keySchedule[ksRow++]; + t2 = + SUB_MIX0[s2 >>> 24] ^ + SUB_MIX1[(s3 >>> 16) & 0xff] ^ + SUB_MIX2[(s0 >>> 8) & 0xff] ^ + SUB_MIX3[s1 & 0xff] ^ + keySchedule[ksRow++]; + t3 = + SUB_MIX0[s3 >>> 24] ^ + SUB_MIX1[(s0 >>> 16) & 0xff] ^ + SUB_MIX2[(s1 >>> 8) & 0xff] ^ + SUB_MIX3[s2 & 0xff] ^ + keySchedule[ksRow++]; + s0 = t0; + s1 = t1; + s2 = t2; + s3 = t3; + } - Red.prototype.iadd = function iadd (a, b) { - this._verify2(a, b); + t0 = + ((SBOX[s0 >>> 24] << 24) | + (SBOX[(s1 >>> 16) & 0xff] << 16) | + (SBOX[(s2 >>> 8) & 0xff] << 8) | + SBOX[s3 & 0xff]) ^ + keySchedule[ksRow++]; + t1 = + ((SBOX[s1 >>> 24] << 24) | + (SBOX[(s2 >>> 16) & 0xff] << 16) | + (SBOX[(s3 >>> 8) & 0xff] << 8) | + SBOX[s0 & 0xff]) ^ + keySchedule[ksRow++]; + t2 = + ((SBOX[s2 >>> 24] << 24) | + (SBOX[(s3 >>> 16) & 0xff] << 16) | + (SBOX[(s0 >>> 8) & 0xff] << 8) | + SBOX[s1 & 0xff]) ^ + keySchedule[ksRow++]; + t3 = + ((SBOX[s3 >>> 24] << 24) | + (SBOX[(s0 >>> 16) & 0xff] << 16) | + (SBOX[(s1 >>> 8) & 0xff] << 8) | + SBOX[s2 & 0xff]) ^ + keySchedule[ksRow++]; + t0 = t0 >>> 0; + t1 = t1 >>> 0; + t2 = t2 >>> 0; + t3 = t3 >>> 0; + + return [t0, t1, t2, t3]; + } - var res = a.iadd(b); - if (res.cmp(this.m) >= 0) { - res.isub(this.m); - } - return res; - }; + // AES constants + var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]; + var G = (function() { + // Compute double table + var d = new Array(256); + for (var j = 0; j < 256; j++) { + if (j < 128) { + d[j] = j << 1; + } else { + d[j] = (j << 1) ^ 0x11b; + } + } - Red.prototype.sub = function sub (a, b) { - this._verify2(a, b); + var SBOX = []; + var INV_SBOX = []; + var SUB_MIX = [[], [], [], []]; + var INV_SUB_MIX = [[], [], [], []]; + + // Walk GF(2^8) + var x = 0; + var xi = 0; + for (var i = 0; i < 256; ++i) { + // Compute sbox + var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4); + sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63; + SBOX[x] = sx; + INV_SBOX[sx] = x; + + // Compute multiplication + var x2 = d[x]; + var x4 = d[x2]; + var x8 = d[x4]; + + // Compute sub bytes, mix columns tables + var t = (d[sx] * 0x101) ^ (sx * 0x1010100); + SUB_MIX[0][x] = (t << 24) | (t >>> 8); + SUB_MIX[1][x] = (t << 16) | (t >>> 16); + SUB_MIX[2][x] = (t << 8) | (t >>> 24); + SUB_MIX[3][x] = t; + + // Compute inv sub bytes, inv mix columns tables + t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100); + INV_SUB_MIX[0][sx] = (t << 24) | (t >>> 8); + INV_SUB_MIX[1][sx] = (t << 16) | (t >>> 16); + INV_SUB_MIX[2][sx] = (t << 8) | (t >>> 24); + INV_SUB_MIX[3][sx] = t; + + if (x === 0) { + x = xi = 1; + } else { + x = x2 ^ d[d[d[x8 ^ x2]]]; + xi ^= d[d[xi]]; + } + } - var res = a.sub(b); - if (res.cmpn(0) < 0) { - res.iadd(this.m); - } - return res._forceRed(this); - }; + return { + SBOX: SBOX, + INV_SBOX: INV_SBOX, + SUB_MIX: SUB_MIX, + INV_SUB_MIX: INV_SUB_MIX, + }; + })(); + + function AES(key) { + this._key = asUInt32Array(key); + this._reset(); + } - Red.prototype.isub = function isub (a, b) { - this._verify2(a, b); + AES.blockSize = 4 * 4; + AES.keySize = 256 / 8; + AES.prototype.blockSize = AES.blockSize; + AES.prototype.keySize = AES.keySize; + AES.prototype._reset = function() { + var keyWords = this._key; + var keySize = keyWords.length; + var nRounds = keySize + 6; + var ksRows = (nRounds + 1) * 4; + + var keySchedule = []; + for (var k = 0; k < keySize; k++) { + keySchedule[k] = keyWords[k]; + } - var res = a.isub(b); - if (res.cmpn(0) < 0) { - res.iadd(this.m); - } - return res; - }; - - Red.prototype.shl = function shl (a, num) { - this._verify1(a); - return this.imod(a.ushln(num)); - }; - - Red.prototype.imul = function imul (a, b) { - this._verify2(a, b); - return this.imod(a.imul(b)); - }; - - Red.prototype.mul = function mul (a, b) { - this._verify2(a, b); - return this.imod(a.mul(b)); - }; - - Red.prototype.isqr = function isqr (a) { - return this.imul(a, a.clone()); - }; - - Red.prototype.sqr = function sqr (a) { - return this.mul(a, a); - }; - - Red.prototype.sqrt = function sqrt (a) { - if (a.isZero()) return a.clone(); - - var mod3 = this.m.andln(3); - assert(mod3 % 2 === 1); - - // Fast case - if (mod3 === 3) { - var pow = this.m.add(new BN(1)).iushrn(2); - return this.pow(a, pow); - } + for (k = keySize; k < ksRows; k++) { + var t = keySchedule[k - 1]; + + if (k % keySize === 0) { + t = (t << 8) | (t >>> 24); + t = + (G.SBOX[t >>> 24] << 24) | + (G.SBOX[(t >>> 16) & 0xff] << 16) | + (G.SBOX[(t >>> 8) & 0xff] << 8) | + G.SBOX[t & 0xff]; + + t ^= RCON[(k / keySize) | 0] << 24; + } else if (keySize > 6 && k % keySize === 4) { + t = + (G.SBOX[t >>> 24] << 24) | + (G.SBOX[(t >>> 16) & 0xff] << 16) | + (G.SBOX[(t >>> 8) & 0xff] << 8) | + G.SBOX[t & 0xff]; + } - // Tonelli-Shanks algorithm (Totally unoptimized and slow) - // - // Find Q and S, that Q * 2 ^ S = (P - 1) - var q = this.m.subn(1); - var s = 0; - while (!q.isZero() && q.andln(1) === 0) { - s++; - q.iushrn(1); - } - assert(!q.isZero()); + keySchedule[k] = keySchedule[k - keySize] ^ t; + } - var one = new BN(1).toRed(this); - var nOne = one.redNeg(); + var invKeySchedule = []; + for (var ik = 0; ik < ksRows; ik++) { + var ksR = ksRows - ik; + var tt = keySchedule[ksR - (ik % 4 ? 0 : 4)]; - // Find quadratic non-residue - // NOTE: Max is such because of generalized Riemann hypothesis. - var lpow = this.m.subn(1).iushrn(1); - var z = this.m.bitLength(); - z = new BN(2 * z * z).toRed(this); + if (ik < 4 || ksR <= 4) { + invKeySchedule[ik] = tt; + } else { + invKeySchedule[ik] = + G.INV_SUB_MIX[0][G.SBOX[tt >>> 24]] ^ + G.INV_SUB_MIX[1][G.SBOX[(tt >>> 16) & 0xff]] ^ + G.INV_SUB_MIX[2][G.SBOX[(tt >>> 8) & 0xff]] ^ + G.INV_SUB_MIX[3][G.SBOX[tt & 0xff]]; + } + } - while (this.pow(z, lpow).cmp(nOne) !== 0) { - z.redIAdd(nOne); - } + this._nRounds = nRounds; + this._keySchedule = keySchedule; + this._invKeySchedule = invKeySchedule; + }; - var c = this.pow(z, q); - var r = this.pow(a, q.addn(1).iushrn(1)); - var t = this.pow(a, q); - var m = s; - while (t.cmp(one) !== 0) { - var tmp = t; - for (var i = 0; tmp.cmp(one) !== 0; i++) { - tmp = tmp.redSqr(); - } - assert(i < m); - var b = this.pow(c, new BN(1).iushln(m - i - 1)); + AES.prototype.encryptBlockRaw = function(M) { + M = asUInt32Array(M); + return cryptBlock(M, this._keySchedule, G.SUB_MIX, G.SBOX, this._nRounds); + }; - r = r.redMul(b); - c = b.redSqr(); - t = t.redMul(c); - m = i; - } + AES.prototype.encryptBlock = function(M) { + var out = this.encryptBlockRaw(M); + var buf = Buffer.allocUnsafe(16); + buf.writeUInt32BE(out[0], 0); + buf.writeUInt32BE(out[1], 4); + buf.writeUInt32BE(out[2], 8); + buf.writeUInt32BE(out[3], 12); + return buf; + }; - return r; - }; + AES.prototype.decryptBlock = function(M) { + M = asUInt32Array(M); + + // swap + var m1 = M[1]; + M[1] = M[3]; + M[3] = m1; + + var out = cryptBlock(M, this._invKeySchedule, G.INV_SUB_MIX, G.INV_SBOX, this._nRounds); + var buf = Buffer.allocUnsafe(16); + buf.writeUInt32BE(out[0], 0); + buf.writeUInt32BE(out[3], 4); + buf.writeUInt32BE(out[2], 8); + buf.writeUInt32BE(out[1], 12); + return buf; + }; - Red.prototype.invm = function invm (a) { - var inv = a._invmp(this.m); - if (inv.negative !== 0) { - inv.negative = 0; - return this.imod(inv).redNeg(); - } else { - return this.imod(inv); - } - }; - - Red.prototype.pow = function pow (a, num) { - if (num.isZero()) return new BN(1).toRed(this); - if (num.cmpn(1) === 0) return a.clone(); - - var windowSize = 4; - var wnd = new Array(1 << windowSize); - wnd[0] = new BN(1).toRed(this); - wnd[1] = a; - for (var i = 2; i < wnd.length; i++) { - wnd[i] = this.mul(wnd[i - 1], a); - } + AES.prototype.scrub = function() { + scrubVec(this._keySchedule); + scrubVec(this._invKeySchedule); + scrubVec(this._key); + }; - var res = wnd[0]; - var current = 0; - var currentLen = 0; - var start = num.bitLength() % 26; - if (start === 0) { - start = 26; - } + module.exports.AES = AES; + }, + { 'safe-buffer': 233 }, + ], + 66: [ + function(require, module, exports) { + var aes = require('./aes'); + var Buffer = require('safe-buffer').Buffer; + var Transform = require('cipher-base'); + var inherits = require('inherits'); + var GHASH = require('./ghash'); + var xor = require('buffer-xor'); + + function xorTest(a, b) { + var out = 0; + if (a.length !== b.length) out++; + + var len = Math.min(a.length, b.length); + for (var i = 0; i < len; ++i) { + out += a[i] ^ b[i]; + } - for (i = num.length - 1; i >= 0; i--) { - var word = num.words[i]; - for (var j = start - 1; j >= 0; j--) { - var bit = (word >> j) & 1; - if (res !== wnd[0]) { - res = this.sqr(res); + return out; } - if (bit === 0 && current === 0) { - currentLen = 0; - continue; + function StreamCipher(mode, key, iv, decrypt) { + Transform.call(this); + + this._finID = Buffer.concat([iv, Buffer.from([0, 0, 0, 1])]); + iv = Buffer.concat([iv, Buffer.from([0, 0, 0, 2])]); + + this._cipher = new aes.AES(key); + this._prev = Buffer.from(iv); + this._cache = Buffer.allocUnsafe(0); + this._secCache = Buffer.allocUnsafe(0); + this._decrypt = decrypt; + this._alen = 0; + this._len = 0; + this._mode = mode; + + var h = Buffer.alloc(4, 0); + this._ghash = new GHASH(this._cipher.encryptBlock(h)); + this._authTag = null; + this._called = false; } - current <<= 1; - current |= bit; - currentLen++; - if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue; + inherits(StreamCipher, Transform); - res = this.mul(res, wnd[current]); - currentLen = 0; - current = 0; - } - start = 26; - } + StreamCipher.prototype._update = function(chunk) { + if (!this._called && this._alen) { + var rump = 16 - (this._alen % 16); + if (rump < 16) { + rump = Buffer.alloc(rump, 0); + this._ghash.update(rump); + } + } - return res; - }; + this._called = true; + var out = this._mode.encrypt(this, chunk); + if (this._decrypt) { + this._ghash.update(chunk); + } else { + this._ghash.update(out); + } + this._len += chunk.length; + return out; + }; - Red.prototype.convertTo = function convertTo (num) { - var r = num.umod(this.m); + StreamCipher.prototype._final = function() { + if (this._decrypt && !this._authTag) throw new Error('Unsupported state or unable to authenticate data'); - return r === num ? r.clone() : r; - }; + var tag = xor(this._ghash.final(this._alen * 8, this._len * 8), this._cipher.encryptBlock(this._finID)); + if (this._decrypt && xorTest(tag, this._authTag)) + throw new Error('Unsupported state or unable to authenticate data'); - Red.prototype.convertFrom = function convertFrom (num) { - var res = num.clone(); - res.red = null; - return res; - }; + this._authTag = tag; + this._cipher.scrub(); + }; - // - // Montgomery method engine - // + StreamCipher.prototype.getAuthTag = function getAuthTag() { + if (this._decrypt || !Buffer.isBuffer(this._authTag)) + throw new Error('Attempting to get auth tag in unsupported state'); - BN.mont = function mont (num) { - return new Mont(num); - }; + return this._authTag; + }; - function Mont (m) { - Red.call(this, m); + StreamCipher.prototype.setAuthTag = function setAuthTag(tag) { + if (!this._decrypt) throw new Error('Attempting to set auth tag in unsupported state'); - this.shift = this.m.bitLength(); - if (this.shift % 26 !== 0) { - this.shift += 26 - (this.shift % 26); - } + this._authTag = tag; + }; - this.r = new BN(1).iushln(this.shift); - this.r2 = this.imod(this.r.sqr()); - this.rinv = this.r._invmp(this.m); + StreamCipher.prototype.setAAD = function setAAD(buf) { + if (this._called) throw new Error('Attempting to set AAD in unsupported state'); - this.minv = this.rinv.mul(this.r).isubn(1).div(this.m); - this.minv = this.minv.umod(this.r); - this.minv = this.r.sub(this.minv); - } - inherits(Mont, Red); - - Mont.prototype.convertTo = function convertTo (num) { - return this.imod(num.ushln(this.shift)); - }; - - Mont.prototype.convertFrom = function convertFrom (num) { - var r = this.imod(num.mul(this.rinv)); - r.red = null; - return r; - }; - - Mont.prototype.imul = function imul (a, b) { - if (a.isZero() || b.isZero()) { - a.words[0] = 0; - a.length = 1; - return a; - } + this._ghash.update(buf); + this._alen += buf.length; + }; - var t = a.imul(b); - var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); - var u = t.isub(c).iushrn(this.shift); - var res = u; + module.exports = StreamCipher; + }, + { './aes': 65, './ghash': 70, 'buffer-xor': 112, 'cipher-base': 114, inherits: 184, 'safe-buffer': 233 }, + ], + 67: [ + function(require, module, exports) { + var ciphers = require('./encrypter'); + var deciphers = require('./decrypter'); + var modes = require('./modes/list.json'); + + function getCiphers() { + return Object.keys(modes); + } - if (u.cmp(this.m) >= 0) { - res = u.isub(this.m); - } else if (u.cmpn(0) < 0) { - res = u.iadd(this.m); - } + exports.createCipher = exports.Cipher = ciphers.createCipher; + exports.createCipheriv = exports.Cipheriv = ciphers.createCipheriv; + exports.createDecipher = exports.Decipher = deciphers.createDecipher; + exports.createDecipheriv = exports.Decipheriv = deciphers.createDecipheriv; + exports.listCiphers = exports.getCiphers = getCiphers; + }, + { './decrypter': 68, './encrypter': 69, './modes/list.json': 78 }, + ], + 68: [ + function(require, module, exports) { + var AuthCipher = require('./authCipher'); + var Buffer = require('safe-buffer').Buffer; + var MODES = require('./modes'); + var StreamCipher = require('./streamCipher'); + var Transform = require('cipher-base'); + var aes = require('./aes'); + var ebtk = require('evp_bytestokey'); + var inherits = require('inherits'); + + function Decipher(mode, key, iv) { + Transform.call(this); + + this._cache = new Splitter(); + this._last = void 0; + this._cipher = new aes.AES(key); + this._prev = Buffer.from(iv); + this._mode = mode; + this._autopadding = true; + } - return res._forceRed(this); - }; + inherits(Decipher, Transform); - Mont.prototype.mul = function mul (a, b) { - if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this); + Decipher.prototype._update = function(data) { + this._cache.add(data); + var chunk; + var thing; + var out = []; + while ((chunk = this._cache.get(this._autopadding))) { + thing = this._mode.decrypt(this, chunk); + out.push(thing); + } + return Buffer.concat(out); + }; - var t = a.mul(b); - var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); - var u = t.isub(c).iushrn(this.shift); - var res = u; - if (u.cmp(this.m) >= 0) { - res = u.isub(this.m); - } else if (u.cmpn(0) < 0) { - res = u.iadd(this.m); - } + Decipher.prototype._final = function() { + var chunk = this._cache.flush(); + if (this._autopadding) { + return unpad(this._mode.decrypt(this, chunk)); + } else if (chunk) { + throw new Error('data not multiple of block length'); + } + }; - return res._forceRed(this); - }; + Decipher.prototype.setAutoPadding = function(setTo) { + this._autopadding = !!setTo; + return this; + }; - Mont.prototype.invm = function invm (a) { - // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R - var res = this.imod(a._invmp(this.m).mul(this.r2)); - return res._forceRed(this); - }; -})(typeof module === 'undefined' || module, this); + function Splitter() { + this.cache = Buffer.allocUnsafe(0); + } -},{"buffer":64}],60:[function(require,module,exports){ -(function (global){ -'use strict'; + Splitter.prototype.add = function(data) { + this.cache = Buffer.concat([this.cache, data]); + }; -// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js -// original notice: + Splitter.prototype.get = function(autoPadding) { + var out; + if (autoPadding) { + if (this.cache.length > 16) { + out = this.cache.slice(0, 16); + this.cache = this.cache.slice(16); + return out; + } + } else { + if (this.cache.length >= 16) { + out = this.cache.slice(0, 16); + this.cache = this.cache.slice(16); + return out; + } + } -/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ -function compare(a, b) { - if (a === b) { - return 0; - } + return null; + }; - var x = a.length; - var y = b.length; + Splitter.prototype.flush = function() { + if (this.cache.length) return this.cache; + }; - for (var i = 0, len = Math.min(x, y); i < len; ++i) { - if (a[i] !== b[i]) { - x = a[i]; - y = b[i]; - break; - } - } + function unpad(last) { + var padded = last[15]; + var i = -1; + while (++i < padded) { + if (last[i + (16 - padded)] !== padded) { + throw new Error('unable to decrypt data'); + } + } + if (padded === 16) return; - if (x < y) { - return -1; - } - if (y < x) { - return 1; - } - return 0; -} -function isBuffer(b) { - if (global.Buffer && typeof global.Buffer.isBuffer === 'function') { - return global.Buffer.isBuffer(b); - } - return !!(b != null && b._isBuffer); -} + return last.slice(0, 16 - padded); + } -// based on node assert, original notice: - -// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 -// -// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! -// -// Originally from narwhal.js (http://narwhaljs.org) -// Copyright (c) 2009 Thomas Robinson <280north.com> -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the 'Software'), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -var util = require('util/'); -var hasOwn = Object.prototype.hasOwnProperty; -var pSlice = Array.prototype.slice; -var functionsHaveNames = (function () { - return function foo() {}.name === 'foo'; -}()); -function pToString (obj) { - return Object.prototype.toString.call(obj); -} -function isView(arrbuf) { - if (isBuffer(arrbuf)) { - return false; - } - if (typeof global.ArrayBuffer !== 'function') { - return false; - } - if (typeof ArrayBuffer.isView === 'function') { - return ArrayBuffer.isView(arrbuf); - } - if (!arrbuf) { - return false; - } - if (arrbuf instanceof DataView) { - return true; - } - if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) { - return true; - } - return false; -} -// 1. The assert module provides functions that throw -// AssertionError's when particular conditions are not met. The -// assert module must conform to the following interface. - -var assert = module.exports = ok; - -// 2. The AssertionError is defined in assert. -// new assert.AssertionError({ message: message, -// actual: actual, -// expected: expected }) - -var regex = /\s*function\s+([^\(\s]*)\s*/; -// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js -function getName(func) { - if (!util.isFunction(func)) { - return; - } - if (functionsHaveNames) { - return func.name; - } - var str = func.toString(); - var match = str.match(regex); - return match && match[1]; -} -assert.AssertionError = function AssertionError(options) { - this.name = 'AssertionError'; - this.actual = options.actual; - this.expected = options.expected; - this.operator = options.operator; - if (options.message) { - this.message = options.message; - this.generatedMessage = false; - } else { - this.message = getMessage(this); - this.generatedMessage = true; - } - var stackStartFunction = options.stackStartFunction || fail; - if (Error.captureStackTrace) { - Error.captureStackTrace(this, stackStartFunction); - } else { - // non v8 browsers so we can have a stacktrace - var err = new Error(); - if (err.stack) { - var out = err.stack; - - // try to strip useless frames - var fn_name = getName(stackStartFunction); - var idx = out.indexOf('\n' + fn_name); - if (idx >= 0) { - // once we have located the function frame - // we need to strip out everything before it (and its line) - var next_line = out.indexOf('\n', idx + 1); - out = out.substring(next_line + 1); - } + function createDecipheriv(suite, password, iv) { + var config = MODES[suite.toLowerCase()]; + if (!config) throw new TypeError('invalid suite type'); - this.stack = out; - } - } -}; + if (typeof iv === 'string') iv = Buffer.from(iv); + if (iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length); -// assert.AssertionError instanceof Error -util.inherits(assert.AssertionError, Error); + if (typeof password === 'string') password = Buffer.from(password); + if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length); -function truncate(s, n) { - if (typeof s === 'string') { - return s.length < n ? s : s.slice(0, n); - } else { - return s; - } -} -function inspect(something) { - if (functionsHaveNames || !util.isFunction(something)) { - return util.inspect(something); - } - var rawname = getName(something); - var name = rawname ? ': ' + rawname : ''; - return '[Function' + name + ']'; -} -function getMessage(self) { - return truncate(inspect(self.actual), 128) + ' ' + - self.operator + ' ' + - truncate(inspect(self.expected), 128); -} + if (config.type === 'stream') { + return new StreamCipher(config.module, password, iv, true); + } else if (config.type === 'auth') { + return new AuthCipher(config.module, password, iv, true); + } -// At present only the three keys mentioned above are used and -// understood by the spec. Implementations or sub modules can pass -// other keys to the AssertionError's constructor - they will be -// ignored. - -// 3. All of the following functions must throw an AssertionError -// when a corresponding condition is not met, with a message that -// may be undefined if not provided. All assertion methods provide -// both the actual and expected values to the assertion error for -// display purposes. - -function fail(actual, expected, message, operator, stackStartFunction) { - throw new assert.AssertionError({ - message: message, - actual: actual, - expected: expected, - operator: operator, - stackStartFunction: stackStartFunction - }); -} + return new Decipher(config.module, password, iv); + } -// EXTENSION! allows for well behaved errors defined elsewhere. -assert.fail = fail; + function createDecipher(suite, password) { + var config = MODES[suite.toLowerCase()]; + if (!config) throw new TypeError('invalid suite type'); -// 4. Pure assertion tests whether a value is truthy, as determined -// by !!guard. -// assert.ok(guard, message_opt); -// This statement is equivalent to assert.equal(true, !!guard, -// message_opt);. To test strictly for the value true, use -// assert.strictEqual(true, guard, message_opt);. + var keys = ebtk(password, false, config.key, config.iv); + return createDecipheriv(suite, keys.key, keys.iv); + } -function ok(value, message) { - if (!value) fail(value, true, message, '==', assert.ok); -} -assert.ok = ok; + exports.createDecipher = createDecipher; + exports.createDecipheriv = createDecipheriv; + }, + { + './aes': 65, + './authCipher': 66, + './modes': 77, + './streamCipher': 80, + 'cipher-base': 114, + evp_bytestokey: 166, + inherits: 184, + 'safe-buffer': 233, + }, + ], + 69: [ + function(require, module, exports) { + var MODES = require('./modes'); + var AuthCipher = require('./authCipher'); + var Buffer = require('safe-buffer').Buffer; + var StreamCipher = require('./streamCipher'); + var Transform = require('cipher-base'); + var aes = require('./aes'); + var ebtk = require('evp_bytestokey'); + var inherits = require('inherits'); + + function Cipher(mode, key, iv) { + Transform.call(this); + + this._cache = new Splitter(); + this._cipher = new aes.AES(key); + this._prev = Buffer.from(iv); + this._mode = mode; + this._autopadding = true; + } -// 5. The equality assertion tests shallow, coercive equality with -// ==. -// assert.equal(actual, expected, message_opt); + inherits(Cipher, Transform); -assert.equal = function equal(actual, expected, message) { - if (actual != expected) fail(actual, expected, message, '==', assert.equal); -}; + Cipher.prototype._update = function(data) { + this._cache.add(data); + var chunk; + var thing; + var out = []; -// 6. The non-equality assertion tests for whether two objects are not equal -// with != assert.notEqual(actual, expected, message_opt); + while ((chunk = this._cache.get())) { + thing = this._mode.encrypt(this, chunk); + out.push(thing); + } -assert.notEqual = function notEqual(actual, expected, message) { - if (actual == expected) { - fail(actual, expected, message, '!=', assert.notEqual); - } -}; + return Buffer.concat(out); + }; -// 7. The equivalence assertion tests a deep equality relation. -// assert.deepEqual(actual, expected, message_opt); + var PADDING = Buffer.alloc(16, 0x10); -assert.deepEqual = function deepEqual(actual, expected, message) { - if (!_deepEqual(actual, expected, false)) { - fail(actual, expected, message, 'deepEqual', assert.deepEqual); - } -}; + Cipher.prototype._final = function() { + var chunk = this._cache.flush(); + if (this._autopadding) { + chunk = this._mode.encrypt(this, chunk); + this._cipher.scrub(); + return chunk; + } -assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { - if (!_deepEqual(actual, expected, true)) { - fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual); - } -}; - -function _deepEqual(actual, expected, strict, memos) { - // 7.1. All identical values are equivalent, as determined by ===. - if (actual === expected) { - return true; - } else if (isBuffer(actual) && isBuffer(expected)) { - return compare(actual, expected) === 0; - - // 7.2. If the expected value is a Date object, the actual value is - // equivalent if it is also a Date object that refers to the same time. - } else if (util.isDate(actual) && util.isDate(expected)) { - return actual.getTime() === expected.getTime(); - - // 7.3 If the expected value is a RegExp object, the actual value is - // equivalent if it is also a RegExp object with the same source and - // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). - } else if (util.isRegExp(actual) && util.isRegExp(expected)) { - return actual.source === expected.source && - actual.global === expected.global && - actual.multiline === expected.multiline && - actual.lastIndex === expected.lastIndex && - actual.ignoreCase === expected.ignoreCase; - - // 7.4. Other pairs that do not both pass typeof value == 'object', - // equivalence is determined by ==. - } else if ((actual === null || typeof actual !== 'object') && - (expected === null || typeof expected !== 'object')) { - return strict ? actual === expected : actual == expected; - - // If both values are instances of typed arrays, wrap their underlying - // ArrayBuffers in a Buffer each to increase performance - // This optimization requires the arrays to have the same type as checked by - // Object.prototype.toString (aka pToString). Never perform binary - // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their - // bit patterns are not identical. - } else if (isView(actual) && isView(expected) && - pToString(actual) === pToString(expected) && - !(actual instanceof Float32Array || - actual instanceof Float64Array)) { - return compare(new Uint8Array(actual.buffer), - new Uint8Array(expected.buffer)) === 0; - - // 7.5 For all other Object pairs, including Array objects, equivalence is - // determined by having the same number of owned properties (as verified - // with Object.prototype.hasOwnProperty.call), the same set of keys - // (although not necessarily the same order), equivalent values for every - // corresponding key, and an identical 'prototype' property. Note: this - // accounts for both named and indexed properties on Arrays. - } else if (isBuffer(actual) !== isBuffer(expected)) { - return false; - } else { - memos = memos || {actual: [], expected: []}; - - var actualIndex = memos.actual.indexOf(actual); - if (actualIndex !== -1) { - if (actualIndex === memos.expected.indexOf(expected)) { - return true; - } - } + if (!chunk.equals(PADDING)) { + this._cipher.scrub(); + throw new Error('data not multiple of block length'); + } + }; - memos.actual.push(actual); - memos.expected.push(expected); + Cipher.prototype.setAutoPadding = function(setTo) { + this._autopadding = !!setTo; + return this; + }; - return objEquiv(actual, expected, strict, memos); - } -} + function Splitter() { + this.cache = Buffer.allocUnsafe(0); + } -function isArguments(object) { - return Object.prototype.toString.call(object) == '[object Arguments]'; -} + Splitter.prototype.add = function(data) { + this.cache = Buffer.concat([this.cache, data]); + }; -function objEquiv(a, b, strict, actualVisitedObjects) { - if (a === null || a === undefined || b === null || b === undefined) - return false; - // if one is a primitive, the other must be same - if (util.isPrimitive(a) || util.isPrimitive(b)) - return a === b; - if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) - return false; - var aIsArgs = isArguments(a); - var bIsArgs = isArguments(b); - if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) - return false; - if (aIsArgs) { - a = pSlice.call(a); - b = pSlice.call(b); - return _deepEqual(a, b, strict); - } - var ka = objectKeys(a); - var kb = objectKeys(b); - var key, i; - // having the same number of owned properties (keys incorporates - // hasOwnProperty) - if (ka.length !== kb.length) - return false; - //the same set of keys (although not necessarily the same order), - ka.sort(); - kb.sort(); - //~~~cheap key test - for (i = ka.length - 1; i >= 0; i--) { - if (ka[i] !== kb[i]) - return false; - } - //equivalent values for every corresponding key, and - //~~~possibly expensive deep test - for (i = ka.length - 1; i >= 0; i--) { - key = ka[i]; - if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects)) - return false; - } - return true; -} + Splitter.prototype.get = function() { + if (this.cache.length > 15) { + var out = this.cache.slice(0, 16); + this.cache = this.cache.slice(16); + return out; + } + return null; + }; -// 8. The non-equivalence assertion tests for any deep inequality. -// assert.notDeepEqual(actual, expected, message_opt); + Splitter.prototype.flush = function() { + var len = 16 - this.cache.length; + var padBuff = Buffer.allocUnsafe(len); -assert.notDeepEqual = function notDeepEqual(actual, expected, message) { - if (_deepEqual(actual, expected, false)) { - fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); - } -}; + var i = -1; + while (++i < len) { + padBuff.writeUInt8(len, i); + } -assert.notDeepStrictEqual = notDeepStrictEqual; -function notDeepStrictEqual(actual, expected, message) { - if (_deepEqual(actual, expected, true)) { - fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual); - } -} + return Buffer.concat([this.cache, padBuff]); + }; + function createCipheriv(suite, password, iv) { + var config = MODES[suite.toLowerCase()]; + if (!config) throw new TypeError('invalid suite type'); -// 9. The strict equality assertion tests strict equality, as determined by ===. -// assert.strictEqual(actual, expected, message_opt); + if (typeof password === 'string') password = Buffer.from(password); + if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length); -assert.strictEqual = function strictEqual(actual, expected, message) { - if (actual !== expected) { - fail(actual, expected, message, '===', assert.strictEqual); - } -}; + if (typeof iv === 'string') iv = Buffer.from(iv); + if (iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length); -// 10. The strict non-equality assertion tests for strict inequality, as -// determined by !==. assert.notStrictEqual(actual, expected, message_opt); + if (config.type === 'stream') { + return new StreamCipher(config.module, password, iv); + } else if (config.type === 'auth') { + return new AuthCipher(config.module, password, iv); + } -assert.notStrictEqual = function notStrictEqual(actual, expected, message) { - if (actual === expected) { - fail(actual, expected, message, '!==', assert.notStrictEqual); - } -}; + return new Cipher(config.module, password, iv); + } -function expectedException(actual, expected) { - if (!actual || !expected) { - return false; - } + function createCipher(suite, password) { + var config = MODES[suite.toLowerCase()]; + if (!config) throw new TypeError('invalid suite type'); - if (Object.prototype.toString.call(expected) == '[object RegExp]') { - return expected.test(actual); - } + var keys = ebtk(password, false, config.key, config.iv); + return createCipheriv(suite, keys.key, keys.iv); + } - try { - if (actual instanceof expected) { - return true; - } - } catch (e) { - // Ignore. The instanceof check doesn't work for arrow functions. - } + exports.createCipheriv = createCipheriv; + exports.createCipher = createCipher; + }, + { + './aes': 65, + './authCipher': 66, + './modes': 77, + './streamCipher': 80, + 'cipher-base': 114, + evp_bytestokey: 166, + inherits: 184, + 'safe-buffer': 233, + }, + ], + 70: [ + function(require, module, exports) { + var Buffer = require('safe-buffer').Buffer; + var ZEROES = Buffer.alloc(16, 0); + + function toArray(buf) { + return [buf.readUInt32BE(0), buf.readUInt32BE(4), buf.readUInt32BE(8), buf.readUInt32BE(12)]; + } - if (Error.isPrototypeOf(expected)) { - return false; - } + function fromArray(out) { + var buf = Buffer.allocUnsafe(16); + buf.writeUInt32BE(out[0] >>> 0, 0); + buf.writeUInt32BE(out[1] >>> 0, 4); + buf.writeUInt32BE(out[2] >>> 0, 8); + buf.writeUInt32BE(out[3] >>> 0, 12); + return buf; + } - return expected.call({}, actual) === true; -} + function GHASH(key) { + this.h = key; + this.state = Buffer.alloc(16, 0); + this.cache = Buffer.allocUnsafe(0); + } -function _tryBlock(block) { - var error; - try { - block(); - } catch (e) { - error = e; - } - return error; -} + // from http://bitwiseshiftleft.github.io/sjcl/doc/symbols/src/core_gcm.js.html + // by Juho Vรคhรค-Herttua + GHASH.prototype.ghash = function(block) { + var i = -1; + while (++i < block.length) { + this.state[i] ^= block[i]; + } + this._multiply(); + }; -function _throws(shouldThrow, block, expected, message) { - var actual; + GHASH.prototype._multiply = function() { + var Vi = toArray(this.h); + var Zi = [0, 0, 0, 0]; + var j, xi, lsbVi; + var i = -1; + while (++i < 128) { + xi = (this.state[~~(i / 8)] & (1 << (7 - (i % 8)))) !== 0; + if (xi) { + // Z_i+1 = Z_i ^ V_i + Zi[0] ^= Vi[0]; + Zi[1] ^= Vi[1]; + Zi[2] ^= Vi[2]; + Zi[3] ^= Vi[3]; + } - if (typeof block !== 'function') { - throw new TypeError('"block" argument must be a function'); - } + // Store the value of LSB(V_i) + lsbVi = (Vi[3] & 1) !== 0; - if (typeof expected === 'string') { - message = expected; - expected = null; - } + // V_i+1 = V_i >> 1 + for (j = 3; j > 0; j--) { + Vi[j] = (Vi[j] >>> 1) | ((Vi[j - 1] & 1) << 31); + } + Vi[0] = Vi[0] >>> 1; - actual = _tryBlock(block); + // If LSB(V_i) is 1, V_i+1 = (V_i >> 1) ^ R + if (lsbVi) { + Vi[0] = Vi[0] ^ (0xe1 << 24); + } + } + this.state = fromArray(Zi); + }; - message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + - (message ? ' ' + message : '.'); + GHASH.prototype.update = function(buf) { + this.cache = Buffer.concat([this.cache, buf]); + var chunk; + while (this.cache.length >= 16) { + chunk = this.cache.slice(0, 16); + this.cache = this.cache.slice(16); + this.ghash(chunk); + } + }; - if (shouldThrow && !actual) { - fail(actual, expected, 'Missing expected exception' + message); - } + GHASH.prototype.final = function(abl, bl) { + if (this.cache.length) { + this.ghash(Buffer.concat([this.cache, ZEROES], 16)); + } - var userProvidedMessage = typeof message === 'string'; - var isUnwantedException = !shouldThrow && util.isError(actual); - var isUnexpectedException = !shouldThrow && actual && !expected; + this.ghash(fromArray([0, abl, 0, bl])); + return this.state; + }; - if ((isUnwantedException && - userProvidedMessage && - expectedException(actual, expected)) || - isUnexpectedException) { - fail(actual, expected, 'Got unwanted exception' + message); - } + module.exports = GHASH; + }, + { 'safe-buffer': 233 }, + ], + 71: [ + function(require, module, exports) { + var xor = require('buffer-xor'); - if ((shouldThrow && actual && expected && - !expectedException(actual, expected)) || (!shouldThrow && actual)) { - throw actual; - } -} + exports.encrypt = function(self, block) { + var data = xor(block, self._prev); -// 11. Expected to throw an error: -// assert.throws(block, Error_opt, message_opt); + self._prev = self._cipher.encryptBlock(data); + return self._prev; + }; -assert.throws = function(block, /*optional*/error, /*optional*/message) { - _throws(true, block, error, message); -}; + exports.decrypt = function(self, block) { + var pad = self._prev; -// EXTENSION! This is annoying to write outside this module. -assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { - _throws(false, block, error, message); -}; + self._prev = block; + var out = self._cipher.decryptBlock(block); -assert.ifError = function(err) { if (err) throw err; }; + return xor(out, pad); + }; + }, + { 'buffer-xor': 112 }, + ], + 72: [ + function(require, module, exports) { + var Buffer = require('safe-buffer').Buffer; + var xor = require('buffer-xor'); + + function encryptStart(self, data, decrypt) { + var len = data.length; + var out = xor(data, self._cache); + self._cache = self._cache.slice(len); + self._prev = Buffer.concat([self._prev, decrypt ? data : out]); + return out; + } -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) { - if (hasOwn.call(obj, key)) keys.push(key); - } - return keys; -}; + exports.encrypt = function(self, data, decrypt) { + var out = Buffer.allocUnsafe(0); + var len; -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"util/":248}],61:[function(require,module,exports){ -'use strict' + while (data.length) { + if (self._cache.length === 0) { + self._cache = self._cipher.encryptBlock(self._prev); + self._prev = Buffer.allocUnsafe(0); + } -exports.byteLength = byteLength -exports.toByteArray = toByteArray -exports.fromByteArray = fromByteArray + if (self._cache.length <= data.length) { + len = self._cache.length; + out = Buffer.concat([out, encryptStart(self, data.slice(0, len), decrypt)]); + data = data.slice(len); + } else { + out = Buffer.concat([out, encryptStart(self, data, decrypt)]); + break; + } + } -var lookup = [] -var revLookup = [] -var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array + return out; + }; + }, + { 'buffer-xor': 112, 'safe-buffer': 233 }, + ], + 73: [ + function(require, module, exports) { + var Buffer = require('safe-buffer').Buffer; + + function encryptByte(self, byteParam, decrypt) { + var pad; + var i = -1; + var len = 8; + var out = 0; + var bit, value; + while (++i < len) { + pad = self._cipher.encryptBlock(self._prev); + bit = byteParam & (1 << (7 - i)) ? 0x80 : 0; + value = pad[0] ^ bit; + out += (value & 0x80) >> i % 8; + self._prev = shiftIn(self._prev, decrypt ? bit : value); + } + return out; + } -var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -for (var i = 0, len = code.length; i < len; ++i) { - lookup[i] = code[i] - revLookup[code.charCodeAt(i)] = i -} + function shiftIn(buffer, value) { + var len = buffer.length; + var i = -1; + var out = Buffer.allocUnsafe(buffer.length); + buffer = Buffer.concat([buffer, Buffer.from([value])]); -revLookup['-'.charCodeAt(0)] = 62 -revLookup['_'.charCodeAt(0)] = 63 + while (++i < len) { + out[i] = (buffer[i] << 1) | (buffer[i + 1] >> 7); + } -function placeHoldersCount (b64) { - var len = b64.length - if (len % 4 > 0) { - throw new Error('Invalid string. Length must be a multiple of 4') - } + return out; + } - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0 -} + exports.encrypt = function(self, chunk, decrypt) { + var len = chunk.length; + var out = Buffer.allocUnsafe(len); + var i = -1; -function byteLength (b64) { - // base64 is 4/3 + up to two characters of the original data - return (b64.length * 3 / 4) - placeHoldersCount(b64) -} + while (++i < len) { + out[i] = encryptByte(self, chunk[i], decrypt); + } -function toByteArray (b64) { - var i, l, tmp, placeHolders, arr - var len = b64.length - placeHolders = placeHoldersCount(b64) + return out; + }; + }, + { 'safe-buffer': 233 }, + ], + 74: [ + function(require, module, exports) { + (function(Buffer) { + function encryptByte(self, byteParam, decrypt) { + var pad = self._cipher.encryptBlock(self._prev); + var out = pad[0] ^ byteParam; + + self._prev = Buffer.concat([self._prev.slice(1), Buffer.from([decrypt ? byteParam : out])]); + + return out; + } - arr = new Arr((len * 3 / 4) - placeHolders) + exports.encrypt = function(self, chunk, decrypt) { + var len = chunk.length; + var out = Buffer.allocUnsafe(len); + var i = -1; - // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? len - 4 : len + while (++i < len) { + out[i] = encryptByte(self, chunk[i], decrypt); + } - var L = 0 + return out; + }; + }.call(this, require('buffer').Buffer)); + }, + { buffer: 113 }, + ], + 75: [ + function(require, module, exports) { + (function(Buffer) { + var xor = require('buffer-xor'); + + function incr32(iv) { + var len = iv.length; + var item; + while (len--) { + item = iv.readUInt8(len); + if (item === 255) { + iv.writeUInt8(0, len); + } else { + item++; + iv.writeUInt8(item, len); + break; + } + } + } - for (i = 0; i < l; i += 4) { - tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] - arr[L++] = (tmp >> 16) & 0xFF - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF - } + function getBlock(self) { + var out = self._cipher.encryptBlockRaw(self._prev); + incr32(self._prev); + return out; + } - if (placeHolders === 2) { - tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4) - arr[L++] = tmp & 0xFF - } else if (placeHolders === 1) { - tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2) - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF - } + var blockSize = 16; + exports.encrypt = function(self, chunk) { + var chunkNum = Math.ceil(chunk.length / blockSize); + var start = self._cache.length; + self._cache = Buffer.concat([self._cache, Buffer.allocUnsafe(chunkNum * blockSize)]); + for (var i = 0; i < chunkNum; i++) { + var out = getBlock(self); + var offset = start + i * blockSize; + self._cache.writeUInt32BE(out[0], offset + 0); + self._cache.writeUInt32BE(out[1], offset + 4); + self._cache.writeUInt32BE(out[2], offset + 8); + self._cache.writeUInt32BE(out[3], offset + 12); + } + var pad = self._cache.slice(0, chunk.length); + self._cache = self._cache.slice(chunk.length); + return xor(chunk, pad); + }; + }.call(this, require('buffer').Buffer)); + }, + { buffer: 113, 'buffer-xor': 112 }, + ], + 76: [ + function(require, module, exports) { + exports.encrypt = function(self, block) { + return self._cipher.encryptBlock(block); + }; - return arr -} + exports.decrypt = function(self, block) { + return self._cipher.decryptBlock(block); + }; + }, + {}, + ], + 77: [ + function(require, module, exports) { + var modeModules = { + ECB: require('./ecb'), + CBC: require('./cbc'), + CFB: require('./cfb'), + CFB8: require('./cfb8'), + CFB1: require('./cfb1'), + OFB: require('./ofb'), + CTR: require('./ctr'), + GCM: require('./ctr'), + }; -function tripletToBase64 (num) { - return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] -} + var modes = require('./list.json'); -function encodeChunk (uint8, start, end) { - var tmp - var output = [] - for (var i = start; i < end; i += 3) { - tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) - output.push(tripletToBase64(tmp)) - } - return output.join('') -} + for (var key in modes) { + modes[key].module = modeModules[modes[key].mode]; + } -function fromByteArray (uint8) { - var tmp - var len = uint8.length - var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes - var output = '' - var parts = [] - var maxChunkLength = 16383 // must be multiple of 3 - - // go through the array every three bytes, we'll deal with trailing stuff later - for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { - parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) - } + module.exports = modes; + }, + { + './cbc': 71, + './cfb': 72, + './cfb1': 73, + './cfb8': 74, + './ctr': 75, + './ecb': 76, + './list.json': 78, + './ofb': 79, + }, + ], + 78: [ + function(require, module, exports) { + module.exports = { + 'aes-128-ecb': { + cipher: 'AES', + key: 128, + iv: 0, + mode: 'ECB', + type: 'block', + }, + 'aes-192-ecb': { + cipher: 'AES', + key: 192, + iv: 0, + mode: 'ECB', + type: 'block', + }, + 'aes-256-ecb': { + cipher: 'AES', + key: 256, + iv: 0, + mode: 'ECB', + type: 'block', + }, + 'aes-128-cbc': { + cipher: 'AES', + key: 128, + iv: 16, + mode: 'CBC', + type: 'block', + }, + 'aes-192-cbc': { + cipher: 'AES', + key: 192, + iv: 16, + mode: 'CBC', + type: 'block', + }, + 'aes-256-cbc': { + cipher: 'AES', + key: 256, + iv: 16, + mode: 'CBC', + type: 'block', + }, + aes128: { + cipher: 'AES', + key: 128, + iv: 16, + mode: 'CBC', + type: 'block', + }, + aes192: { + cipher: 'AES', + key: 192, + iv: 16, + mode: 'CBC', + type: 'block', + }, + aes256: { + cipher: 'AES', + key: 256, + iv: 16, + mode: 'CBC', + type: 'block', + }, + 'aes-128-cfb': { + cipher: 'AES', + key: 128, + iv: 16, + mode: 'CFB', + type: 'stream', + }, + 'aes-192-cfb': { + cipher: 'AES', + key: 192, + iv: 16, + mode: 'CFB', + type: 'stream', + }, + 'aes-256-cfb': { + cipher: 'AES', + key: 256, + iv: 16, + mode: 'CFB', + type: 'stream', + }, + 'aes-128-cfb8': { + cipher: 'AES', + key: 128, + iv: 16, + mode: 'CFB8', + type: 'stream', + }, + 'aes-192-cfb8': { + cipher: 'AES', + key: 192, + iv: 16, + mode: 'CFB8', + type: 'stream', + }, + 'aes-256-cfb8': { + cipher: 'AES', + key: 256, + iv: 16, + mode: 'CFB8', + type: 'stream', + }, + 'aes-128-cfb1': { + cipher: 'AES', + key: 128, + iv: 16, + mode: 'CFB1', + type: 'stream', + }, + 'aes-192-cfb1': { + cipher: 'AES', + key: 192, + iv: 16, + mode: 'CFB1', + type: 'stream', + }, + 'aes-256-cfb1': { + cipher: 'AES', + key: 256, + iv: 16, + mode: 'CFB1', + type: 'stream', + }, + 'aes-128-ofb': { + cipher: 'AES', + key: 128, + iv: 16, + mode: 'OFB', + type: 'stream', + }, + 'aes-192-ofb': { + cipher: 'AES', + key: 192, + iv: 16, + mode: 'OFB', + type: 'stream', + }, + 'aes-256-ofb': { + cipher: 'AES', + key: 256, + iv: 16, + mode: 'OFB', + type: 'stream', + }, + 'aes-128-ctr': { + cipher: 'AES', + key: 128, + iv: 16, + mode: 'CTR', + type: 'stream', + }, + 'aes-192-ctr': { + cipher: 'AES', + key: 192, + iv: 16, + mode: 'CTR', + type: 'stream', + }, + 'aes-256-ctr': { + cipher: 'AES', + key: 256, + iv: 16, + mode: 'CTR', + type: 'stream', + }, + 'aes-128-gcm': { + cipher: 'AES', + key: 128, + iv: 12, + mode: 'GCM', + type: 'auth', + }, + 'aes-192-gcm': { + cipher: 'AES', + key: 192, + iv: 12, + mode: 'GCM', + type: 'auth', + }, + 'aes-256-gcm': { + cipher: 'AES', + key: 256, + iv: 12, + mode: 'GCM', + type: 'auth', + }, + }; + }, + {}, + ], + 79: [ + function(require, module, exports) { + (function(Buffer) { + var xor = require('buffer-xor'); + + function getBlock(self) { + self._prev = self._cipher.encryptBlock(self._prev); + return self._prev; + } - // pad the end with zeros, but make sure to not forget the extra bytes - if (extraBytes === 1) { - tmp = uint8[len - 1] - output += lookup[tmp >> 2] - output += lookup[(tmp << 4) & 0x3F] - output += '==' - } else if (extraBytes === 2) { - tmp = (uint8[len - 2] << 8) + (uint8[len - 1]) - output += lookup[tmp >> 10] - output += lookup[(tmp >> 4) & 0x3F] - output += lookup[(tmp << 2) & 0x3F] - output += '=' - } + exports.encrypt = function(self, chunk) { + while (self._cache.length < chunk.length) { + self._cache = Buffer.concat([self._cache, getBlock(self)]); + } - parts.push(output) + var pad = self._cache.slice(0, chunk.length); + self._cache = self._cache.slice(chunk.length); + return xor(chunk, pad); + }; + }.call(this, require('buffer').Buffer)); + }, + { buffer: 113, 'buffer-xor': 112 }, + ], + 80: [ + function(require, module, exports) { + var aes = require('./aes'); + var Buffer = require('safe-buffer').Buffer; + var Transform = require('cipher-base'); + var inherits = require('inherits'); + + function StreamCipher(mode, key, iv, decrypt) { + Transform.call(this); + + this._cipher = new aes.AES(key); + this._prev = Buffer.from(iv); + this._cache = Buffer.allocUnsafe(0); + this._secCache = Buffer.allocUnsafe(0); + this._decrypt = decrypt; + this._mode = mode; + } - return parts.join('') -} + inherits(StreamCipher, Transform); -},{}],62:[function(require,module,exports){ -(function (module, exports) { + StreamCipher.prototype._update = function(chunk) { + return this._mode.encrypt(this, chunk, this._decrypt); + }; -'use strict'; + StreamCipher.prototype._final = function() { + this._cipher.scrub(); + }; -// Utils + module.exports = StreamCipher; + }, + { './aes': 65, 'cipher-base': 114, inherits: 184, 'safe-buffer': 233 }, + ], + 81: [ + function(require, module, exports) { + var ebtk = require('evp_bytestokey'); + var aes = require('browserify-aes/browser'); + var DES = require('browserify-des'); + var desModes = require('browserify-des/modes'); + var aesModes = require('browserify-aes/modes'); + function createCipher(suite, password) { + var keyLen, ivLen; + suite = suite.toLowerCase(); + if (aesModes[suite]) { + keyLen = aesModes[suite].key; + ivLen = aesModes[suite].iv; + } else if (desModes[suite]) { + keyLen = desModes[suite].key * 8; + ivLen = desModes[suite].iv; + } else { + throw new TypeError('invalid suite type'); + } + var keys = ebtk(password, false, keyLen, ivLen); + return createCipheriv(suite, keys.key, keys.iv); + } + function createDecipher(suite, password) { + var keyLen, ivLen; + suite = suite.toLowerCase(); + if (aesModes[suite]) { + keyLen = aesModes[suite].key; + ivLen = aesModes[suite].iv; + } else if (desModes[suite]) { + keyLen = desModes[suite].key * 8; + ivLen = desModes[suite].iv; + } else { + throw new TypeError('invalid suite type'); + } + var keys = ebtk(password, false, keyLen, ivLen); + return createDecipheriv(suite, keys.key, keys.iv); + } -function assert(val, msg) { - if (!val) - throw new Error(msg || 'Assertion failed'); -} + function createCipheriv(suite, key, iv) { + suite = suite.toLowerCase(); + if (aesModes[suite]) { + return aes.createCipheriv(suite, key, iv); + } else if (desModes[suite]) { + return new DES({ + key: key, + iv: iv, + mode: suite, + }); + } else { + throw new TypeError('invalid suite type'); + } + } + function createDecipheriv(suite, key, iv) { + suite = suite.toLowerCase(); + if (aesModes[suite]) { + return aes.createDecipheriv(suite, key, iv); + } else if (desModes[suite]) { + return new DES({ + key: key, + iv: iv, + mode: suite, + decrypt: true, + }); + } else { + throw new TypeError('invalid suite type'); + } + } + exports.createCipher = exports.Cipher = createCipher; + exports.createCipheriv = exports.Cipheriv = createCipheriv; + exports.createDecipher = exports.Decipher = createDecipher; + exports.createDecipheriv = exports.Decipheriv = createDecipheriv; + function getCiphers() { + return Object.keys(desModes).concat(aes.getCiphers()); + } + exports.listCiphers = exports.getCiphers = getCiphers; + }, + { + 'browserify-aes/browser': 67, + 'browserify-aes/modes': 77, + 'browserify-des': 82, + 'browserify-des/modes': 83, + evp_bytestokey: 166, + }, + ], + 82: [ + function(require, module, exports) { + (function(Buffer) { + var CipherBase = require('cipher-base'); + var des = require('des.js'); + var inherits = require('inherits'); + + var modes = { + 'des-ede3-cbc': des.CBC.instantiate(des.EDE), + 'des-ede3': des.EDE, + 'des-ede-cbc': des.CBC.instantiate(des.EDE), + 'des-ede': des.EDE, + 'des-cbc': des.CBC.instantiate(des.DES), + 'des-ecb': des.DES, + }; + modes.des = modes['des-cbc']; + modes.des3 = modes['des-ede3-cbc']; + module.exports = DES; + inherits(DES, CipherBase); + function DES(opts) { + CipherBase.call(this); + var modeName = opts.mode.toLowerCase(); + var mode = modes[modeName]; + var type; + if (opts.decrypt) { + type = 'decrypt'; + } else { + type = 'encrypt'; + } + var key = opts.key; + if (modeName === 'des-ede' || modeName === 'des-ede-cbc') { + key = Buffer.concat([key, key.slice(0, 8)]); + } + var iv = opts.iv; + this._des = mode.create({ + key: key, + iv: iv, + type: type, + }); + } + DES.prototype._update = function(data) { + return new Buffer(this._des.update(data)); + }; + DES.prototype._final = function() { + return new Buffer(this._des.final()); + }; + }.call(this, require('buffer').Buffer)); + }, + { buffer: 113, 'cipher-base': 114, 'des.js': 140, inherits: 184 }, + ], + 83: [ + function(require, module, exports) { + exports['des-ecb'] = { + key: 8, + iv: 0, + }; + exports['des-cbc'] = exports.des = { + key: 8, + iv: 8, + }; + exports['des-ede3-cbc'] = exports.des3 = { + key: 24, + iv: 8, + }; + exports['des-ede3'] = { + key: 24, + iv: 0, + }; + exports['des-ede-cbc'] = { + key: 16, + iv: 8, + }; + exports['des-ede'] = { + key: 16, + iv: 0, + }; + }, + {}, + ], + 84: [ + function(require, module, exports) { + (function(Buffer) { + var bn = require('bn.js'); + var randomBytes = require('randombytes'); + module.exports = crt; + function blind(priv) { + var r = getr(priv); + var blinder = r + .toRed(bn.mont(priv.modulus)) + .redPow(new bn(priv.publicExponent)) + .fromRed(); + return { + blinder: blinder, + unblinder: r.invm(priv.modulus), + }; + } + function crt(msg, priv) { + var blinds = blind(priv); + var len = priv.modulus.byteLength(); + var mod = bn.mont(priv.modulus); + var blinded = new bn(msg).mul(blinds.blinder).umod(priv.modulus); + var c1 = blinded.toRed(bn.mont(priv.prime1)); + var c2 = blinded.toRed(bn.mont(priv.prime2)); + var qinv = priv.coefficient; + var p = priv.prime1; + var q = priv.prime2; + var m1 = c1.redPow(priv.exponent1); + var m2 = c2.redPow(priv.exponent2); + m1 = m1.fromRed(); + m2 = m2.fromRed(); + var h = m1 + .isub(m2) + .imul(qinv) + .umod(p); + h.imul(q); + m2.iadd(h); + return new Buffer( + m2 + .imul(blinds.unblinder) + .umod(priv.modulus) + .toArray(false, len), + ); + } + crt.getr = getr; + function getr(priv) { + var len = priv.modulus.byteLength(); + var r = new bn(randomBytes(len)); + while (r.cmp(priv.modulus) >= 0 || !r.umod(priv.prime1) || !r.umod(priv.prime2)) { + r = new bn(randomBytes(len)); + } + return r; + } + }.call(this, require('buffer').Buffer)); + }, + { 'bn.js': 85, buffer: 113, randombytes: 217 }, + ], + 85: [ + function(require, module, exports) { + arguments[4][59][0].apply(exports, arguments); + }, + { buffer: 64, dup: 59 }, + ], + 86: [ + function(require, module, exports) { + module.exports = require('./browser/algorithms.json'); + }, + { './browser/algorithms.json': 87 }, + ], + 87: [ + function(require, module, exports) { + module.exports = { + sha224WithRSAEncryption: { + sign: 'rsa', + hash: 'sha224', + id: '302d300d06096086480165030402040500041c', + }, + 'RSA-SHA224': { + sign: 'ecdsa/rsa', + hash: 'sha224', + id: '302d300d06096086480165030402040500041c', + }, + sha256WithRSAEncryption: { + sign: 'rsa', + hash: 'sha256', + id: '3031300d060960864801650304020105000420', + }, + 'RSA-SHA256': { + sign: 'ecdsa/rsa', + hash: 'sha256', + id: '3031300d060960864801650304020105000420', + }, + sha384WithRSAEncryption: { + sign: 'rsa', + hash: 'sha384', + id: '3041300d060960864801650304020205000430', + }, + 'RSA-SHA384': { + sign: 'ecdsa/rsa', + hash: 'sha384', + id: '3041300d060960864801650304020205000430', + }, + sha512WithRSAEncryption: { + sign: 'rsa', + hash: 'sha512', + id: '3051300d060960864801650304020305000440', + }, + 'RSA-SHA512': { + sign: 'ecdsa/rsa', + hash: 'sha512', + id: '3051300d060960864801650304020305000440', + }, + 'RSA-SHA1': { + sign: 'rsa', + hash: 'sha1', + id: '3021300906052b0e03021a05000414', + }, + 'ecdsa-with-SHA1': { + sign: 'ecdsa', + hash: 'sha1', + id: '', + }, + sha256: { + sign: 'ecdsa', + hash: 'sha256', + id: '', + }, + sha224: { + sign: 'ecdsa', + hash: 'sha224', + id: '', + }, + sha384: { + sign: 'ecdsa', + hash: 'sha384', + id: '', + }, + sha512: { + sign: 'ecdsa', + hash: 'sha512', + id: '', + }, + 'DSA-SHA': { + sign: 'dsa', + hash: 'sha1', + id: '', + }, + 'DSA-SHA1': { + sign: 'dsa', + hash: 'sha1', + id: '', + }, + DSA: { + sign: 'dsa', + hash: 'sha1', + id: '', + }, + 'DSA-WITH-SHA224': { + sign: 'dsa', + hash: 'sha224', + id: '', + }, + 'DSA-SHA224': { + sign: 'dsa', + hash: 'sha224', + id: '', + }, + 'DSA-WITH-SHA256': { + sign: 'dsa', + hash: 'sha256', + id: '', + }, + 'DSA-SHA256': { + sign: 'dsa', + hash: 'sha256', + id: '', + }, + 'DSA-WITH-SHA384': { + sign: 'dsa', + hash: 'sha384', + id: '', + }, + 'DSA-SHA384': { + sign: 'dsa', + hash: 'sha384', + id: '', + }, + 'DSA-WITH-SHA512': { + sign: 'dsa', + hash: 'sha512', + id: '', + }, + 'DSA-SHA512': { + sign: 'dsa', + hash: 'sha512', + id: '', + }, + 'DSA-RIPEMD160': { + sign: 'dsa', + hash: 'rmd160', + id: '', + }, + ripemd160WithRSA: { + sign: 'rsa', + hash: 'rmd160', + id: '3021300906052b2403020105000414', + }, + 'RSA-RIPEMD160': { + sign: 'rsa', + hash: 'rmd160', + id: '3021300906052b2403020105000414', + }, + md5WithRSAEncryption: { + sign: 'rsa', + hash: 'md5', + id: '3020300c06082a864886f70d020505000410', + }, + 'RSA-MD5': { + sign: 'rsa', + hash: 'md5', + id: '3020300c06082a864886f70d020505000410', + }, + }; + }, + {}, + ], + 88: [ + function(require, module, exports) { + module.exports = { + '1.3.132.0.10': 'secp256k1', + '1.3.132.0.33': 'p224', + '1.2.840.10045.3.1.1': 'p192', + '1.2.840.10045.3.1.7': 'p256', + '1.3.132.0.34': 'p384', + '1.3.132.0.35': 'p521', + }; + }, + {}, + ], + 89: [ + function(require, module, exports) { + (function(Buffer) { + var createHash = require('create-hash'); + var stream = require('stream'); + var inherits = require('inherits'); + var sign = require('./sign'); + var verify = require('./verify'); + + var algorithms = require('./algorithms.json'); + Object.keys(algorithms).forEach(function(key) { + algorithms[key].id = new Buffer(algorithms[key].id, 'hex'); + algorithms[key.toLowerCase()] = algorithms[key]; + }); -// Could use `inherits` module, but don't want to move from single file -// architecture yet. -function inherits(ctor, superCtor) { - ctor.super_ = superCtor; - var TempCtor = function () {}; - TempCtor.prototype = superCtor.prototype; - ctor.prototype = new TempCtor(); - ctor.prototype.constructor = ctor; -} + function Sign(algorithm) { + stream.Writable.call(this); -// BN + var data = algorithms[algorithm]; + if (!data) throw new Error('Unknown message digest'); -function BN(number, base, endian) { - // May be `new BN(bn)` ? - if (number !== null && - typeof number === 'object' && - Array.isArray(number.words)) { - return number; - } + this._hashType = data.hash; + this._hash = createHash(data.hash); + this._tag = data.id; + this._signType = data.sign; + } + inherits(Sign, stream.Writable); - this.sign = false; - this.words = null; - this.length = 0; + Sign.prototype._write = function _write(data, _, done) { + this._hash.update(data); + done(); + }; - // Reduction context - this.red = null; + Sign.prototype.update = function update(data, enc) { + if (typeof data === 'string') data = new Buffer(data, enc); - if (base === 'le' || base === 'be') { - endian = base; - base = 10; - } + this._hash.update(data); + return this; + }; - if (number !== null) - this._init(number || 0, base || 10, endian || 'be'); -} -if (typeof module === 'object') - module.exports = BN; -else - exports.BN = BN; - -BN.BN = BN; -BN.wordSize = 26; - -BN.prototype._init = function init(number, base, endian) { - if (typeof number === 'number') { - if (number < 0) { - this.sign = true; - number = -number; - } - if (number < 0x4000000) { - this.words = [ number & 0x3ffffff ]; - this.length = 1; - } else if (number < 0x10000000000000) { - this.words = [ - number & 0x3ffffff, - (number / 0x4000000) & 0x3ffffff - ]; - this.length = 2; - } else { - assert(number < 0x20000000000000); // 2 ^ 53 (unsafe) - this.words = [ - number & 0x3ffffff, - (number / 0x4000000) & 0x3ffffff, - 1 - ]; - this.length = 3; - } - return; - } else if (typeof number === 'object') { - return this._initArray(number, base, endian); - } - if (base === 'hex') - base = 16; - assert(base === (base | 0) && base >= 2 && base <= 36); - - number = number.toString().replace(/\s+/g, ''); - var start = 0; - if (number[0] === '-') - start++; - - if (base === 16) - this._parseHex(number, start); - else - this._parseBase(number, base, start); - - if (number[0] === '-') - this.sign = true; - - this.strip(); -}; - -BN.prototype._initArray = function _initArray(number, base, endian) { - // Perhaps a Uint8Array - assert(typeof number.length === 'number'); - if (number.length <= 0) { - this.words = [ 0 ]; - this.length = 1; - return this; - } + Sign.prototype.sign = function signMethod(key, enc) { + this.end(); + var hash = this._hash.digest(); + var sig = sign(hash, key, this._hashType, this._signType, this._tag); - this.length = Math.ceil(number.length / 3); - this.words = new Array(this.length); - for (var i = 0; i < this.length; i++) - this.words[i] = 0; - - var off = 0; - if (endian === 'be') { - for (var i = number.length - 1, j = 0; i >= 0; i -= 3) { - var w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16); - this.words[j] |= (w << off) & 0x3ffffff; - this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; - off += 24; - if (off >= 26) { - off -= 26; - j++; - } - } - } else if (endian === 'le') { - for (var i = 0, j = 0; i < number.length; i += 3) { - var w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16); - this.words[j] |= (w << off) & 0x3ffffff; - this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; - off += 24; - if (off >= 26) { - off -= 26; - j++; - } - } - } - return this.strip(); -}; + return enc ? sig.toString(enc) : sig; + }; + + function Verify(algorithm) { + stream.Writable.call(this); + + var data = algorithms[algorithm]; + if (!data) throw new Error('Unknown message digest'); + + this._hash = createHash(data.hash); + this._tag = data.id; + this._signType = data.sign; + } + inherits(Verify, stream.Writable); -function parseHex(str, start, end) { - var r = 0; - var len = Math.min(str.length, end); - for (var i = start; i < len; i++) { - var c = str.charCodeAt(i) - 48; + Verify.prototype._write = function _write(data, _, done) { + this._hash.update(data); + done(); + }; - r <<= 4; + Verify.prototype.update = function update(data, enc) { + if (typeof data === 'string') data = new Buffer(data, enc); - // 'a' - 'f' - if (c >= 49 && c <= 54) - r |= c - 49 + 0xa; + this._hash.update(data); + return this; + }; - // 'A' - 'F' - else if (c >= 17 && c <= 22) - r |= c - 17 + 0xa; + Verify.prototype.verify = function verifyMethod(key, sig, enc) { + if (typeof sig === 'string') sig = new Buffer(sig, enc); - // '0' - '9' - else - r |= c & 0xf; - } - return r; -} + this.end(); + var hash = this._hash.digest(); + return verify(sig, hash, key, this._signType, this._tag); + }; -BN.prototype._parseHex = function _parseHex(number, start) { - // Create possibly bigger array to ensure that it fits the number - this.length = Math.ceil((number.length - start) / 6); - this.words = new Array(this.length); - for (var i = 0; i < this.length; i++) - this.words[i] = 0; - - // Scan 24-bit chunks and add them to the number - var off = 0; - for (var i = number.length - 6, j = 0; i >= start; i -= 6) { - var w = parseHex(number, i, i + 6); - this.words[j] |= (w << off) & 0x3ffffff; - this.words[j + 1] |= w >>> (26 - off) & 0x3fffff; - off += 24; - if (off >= 26) { - off -= 26; - j++; - } - } - if (i + 6 !== start) { - var w = parseHex(number, start, i + 6); - this.words[j] |= (w << off) & 0x3ffffff; - this.words[j + 1] |= w >>> (26 - off) & 0x3fffff; - } - this.strip(); -}; + function createSign(algorithm) { + return new Sign(algorithm); + } -function parseBase(str, start, end, mul) { - var r = 0; - var len = Math.min(str.length, end); - for (var i = start; i < len; i++) { - var c = str.charCodeAt(i) - 48; + function createVerify(algorithm) { + return new Verify(algorithm); + } - r *= mul; + module.exports = { + Sign: createSign, + Verify: createVerify, + createSign: createSign, + createVerify: createVerify, + }; + }.call(this, require('buffer').Buffer)); + }, + { + './algorithms.json': 87, + './sign': 90, + './verify': 91, + buffer: 113, + 'create-hash': 134, + inherits: 184, + stream: 242, + }, + ], + 90: [ + function(require, module, exports) { + (function(Buffer) { + // much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js + var createHmac = require('create-hmac'); + var crt = require('browserify-rsa'); + var EC = require('elliptic').ec; + var BN = require('bn.js'); + var parseKeys = require('parse-asn1'); + var curves = require('./curves.json'); + + function sign(hash, key, hashType, signType, tag) { + var priv = parseKeys(key); + if (priv.curve) { + // rsa keys can be interpreted as ecdsa ones in openssl + if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') throw new Error('wrong private key type'); + return ecSign(hash, priv); + } else if (priv.type === 'dsa') { + if (signType !== 'dsa') throw new Error('wrong private key type'); + return dsaSign(hash, priv, hashType); + } else { + if (signType !== 'rsa' && signType !== 'ecdsa/rsa') throw new Error('wrong private key type'); + } + hash = Buffer.concat([tag, hash]); + var len = priv.modulus.byteLength(); + var pad = [0, 1]; + while (hash.length + pad.length + 1 < len) pad.push(0xff); + pad.push(0x00); + var i = -1; + while (++i < hash.length) pad.push(hash[i]); + + var out = crt(pad, priv); + return out; + } - // 'a' - if (c >= 49) - r += c - 49 + 0xa; + function ecSign(hash, priv) { + var curveId = curves[priv.curve.join('.')]; + if (!curveId) throw new Error('unknown curve ' + priv.curve.join('.')); - // 'A' - else if (c >= 17) - r += c - 17 + 0xa; + var curve = new EC(curveId); + var key = curve.keyFromPrivate(priv.privateKey); + var out = key.sign(hash); - // '0' - '9' - else - r += c; - } - return r; -} + return new Buffer(out.toDER()); + } -BN.prototype._parseBase = function _parseBase(number, base, start) { - // Initialize as zero - this.words = [ 0 ]; - this.length = 1; - - // Find length of limb in base - for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) - limbLen++; - limbLen--; - limbPow = (limbPow / base) | 0; - - var total = number.length - start; - var mod = total % limbLen; - var end = Math.min(total, total - mod) + start; - - var word = 0; - for (var i = start; i < end; i += limbLen) { - word = parseBase(number, i, i + limbLen, base); - - this.imuln(limbPow); - if (this.words[0] + word < 0x4000000) - this.words[0] += word; - else - this._iaddn(word); - } + function dsaSign(hash, priv, algo) { + var x = priv.params.priv_key; + var p = priv.params.p; + var q = priv.params.q; + var g = priv.params.g; + var r = new BN(0); + var k; + var H = bits2int(hash, q).mod(q); + var s = false; + var kv = getKey(x, q, hash, algo); + while (s === false) { + k = makeKey(q, kv, algo); + r = makeR(g, k, p, q); + s = k + .invm(q) + .imul(H.add(x.mul(r))) + .mod(q); + if (s.cmpn(0) === 0) { + s = false; + r = new BN(0); + } + } + return toDER(r, s); + } - if (mod !== 0) { - var pow = 1; - var word = parseBase(number, i, number.length, base); - - for (var i = 0; i < mod; i++) - pow *= base; - this.imuln(pow); - if (this.words[0] + word < 0x4000000) - this.words[0] += word; - else - this._iaddn(word); - } -}; - -BN.prototype.copy = function copy(dest) { - dest.words = new Array(this.length); - for (var i = 0; i < this.length; i++) - dest.words[i] = this.words[i]; - dest.length = this.length; - dest.sign = this.sign; - dest.red = this.red; -}; - -BN.prototype.clone = function clone() { - var r = new BN(null); - this.copy(r); - return r; -}; - -// Remove leading `0` from `this` -BN.prototype.strip = function strip() { - while (this.length > 1 && this.words[this.length - 1] === 0) - this.length--; - return this._normSign(); -}; - -BN.prototype._normSign = function _normSign() { - // -0 = 0 - if (this.length === 1 && this.words[0] === 0) - this.sign = false; - return this; -}; - -BN.prototype.inspect = function inspect() { - return (this.red ? ''; -}; - -/* + function toDER(r, s) { + r = r.toArray(); + s = s.toArray(); -var zeros = []; -var groupSizes = []; -var groupBases = []; + // Pad values + if (r[0] & 0x80) r = [0].concat(r); + if (s[0] & 0x80) s = [0].concat(s); -var s = ''; -var i = -1; -while (++i < BN.wordSize) { - zeros[i] = s; - s += '0'; -} -groupSizes[0] = 0; -groupSizes[1] = 0; -groupBases[0] = 0; -groupBases[1] = 0; -var base = 2 - 1; -while (++base < 36 + 1) { - var groupSize = 0; - var groupBase = 1; - while (groupBase < (1 << BN.wordSize) / base) { - groupBase *= base; - groupSize += 1; - } - groupSizes[base] = groupSize; - groupBases[base] = groupBase; -} + var total = r.length + s.length + 4; + var res = [0x30, total, 0x02, r.length]; + res = res.concat(r, [0x02, s.length], s); + return new Buffer(res); + } -*/ + function getKey(x, q, hash, algo) { + x = new Buffer(x.toArray()); + if (x.length < q.byteLength()) { + var zeros = new Buffer(q.byteLength() - x.length); + zeros.fill(0); + x = Buffer.concat([zeros, x]); + } + var hlen = hash.length; + var hbits = bits2octets(hash, q); + var v = new Buffer(hlen); + v.fill(1); + var k = new Buffer(hlen); + k.fill(0); + k = createHmac(algo, k) + .update(v) + .update(new Buffer([0])) + .update(x) + .update(hbits) + .digest(); + v = createHmac(algo, k) + .update(v) + .digest(); + k = createHmac(algo, k) + .update(v) + .update(new Buffer([1])) + .update(x) + .update(hbits) + .digest(); + v = createHmac(algo, k) + .update(v) + .digest(); + return { k: k, v: v }; + } -var zeros = [ - '', - '0', - '00', - '000', - '0000', - '00000', - '000000', - '0000000', - '00000000', - '000000000', - '0000000000', - '00000000000', - '000000000000', - '0000000000000', - '00000000000000', - '000000000000000', - '0000000000000000', - '00000000000000000', - '000000000000000000', - '0000000000000000000', - '00000000000000000000', - '000000000000000000000', - '0000000000000000000000', - '00000000000000000000000', - '000000000000000000000000', - '0000000000000000000000000' -]; - -var groupSizes = [ - 0, 0, - 25, 16, 12, 11, 10, 9, 8, - 8, 7, 7, 7, 7, 6, 6, - 6, 6, 6, 6, 6, 5, 5, - 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5 -]; - -var groupBases = [ - 0, 0, - 33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216, - 43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625, - 16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632, - 6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149, - 24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176 -]; - -BN.prototype.toString = function toString(base, padding) { - base = base || 10; - if (base === 16 || base === 'hex') { - var out = ''; - var off = 0; - var padding = padding | 0 || 1; - var carry = 0; - for (var i = 0; i < this.length; i++) { - var w = this.words[i]; - var word = (((w << off) | carry) & 0xffffff).toString(16); - carry = (w >>> (24 - off)) & 0xffffff; - if (carry !== 0 || i !== this.length - 1) - out = zeros[6 - word.length] + word + out; - else - out = word + out; - off += 2; - if (off >= 26) { - off -= 26; - i--; - } - } - if (carry !== 0) - out = carry.toString(16) + out; - while (out.length % padding !== 0) - out = '0' + out; - if (this.sign) - out = '-' + out; - return out; - } else if (base === (base | 0) && base >= 2 && base <= 36) { - // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base)); - var groupSize = groupSizes[base]; - // var groupBase = Math.pow(base, groupSize); - var groupBase = groupBases[base]; - var out = ''; - var c = this.clone(); - c.sign = false; - while (c.cmpn(0) !== 0) { - var r = c.modn(groupBase).toString(base); - c = c.idivn(groupBase); - - if (c.cmpn(0) !== 0) - out = zeros[groupSize - r.length] + r + out; - else - out = r + out; - } - if (this.cmpn(0) === 0) - out = '0' + out; - if (this.sign) - out = '-' + out; - return out; - } else { - assert(false, 'Base should be between 2 and 36'); - } -}; + function bits2int(obits, q) { + var bits = new BN(obits); + var shift = (obits.length << 3) - q.bitLength(); + if (shift > 0) bits.ishrn(shift); + return bits; + } -BN.prototype.toJSON = function toJSON() { - return this.toString(16); -}; + function bits2octets(bits, q) { + bits = bits2int(bits, q); + bits = bits.mod(q); + var out = new Buffer(bits.toArray()); + if (out.length < q.byteLength()) { + var zeros = new Buffer(q.byteLength() - out.length); + zeros.fill(0); + out = Buffer.concat([zeros, out]); + } + return out; + } -BN.prototype.toArray = function toArray() { - this.strip(); - var res = new Array(this.byteLength()); - res[0] = 0; + function makeKey(q, kv, algo) { + var t; + var k; - var q = this.clone(); - for (var i = 0; q.cmpn(0) !== 0; i++) { - var b = q.andln(0xff); - q.ishrn(8); + do { + t = new Buffer(0); - // Assume big-endian - res[res.length - i - 1] = b; - } + while (t.length * 8 < q.bitLength()) { + kv.v = createHmac(algo, kv.k) + .update(kv.v) + .digest(); + t = Buffer.concat([t, kv.v]); + } - return res; -}; - -if (Math.clz32) { - BN.prototype._countBits = function _countBits(w) { - return 32 - Math.clz32(w); - }; -} else { - BN.prototype._countBits = function _countBits(w) { - var t = w; - var r = 0; - if (t >= 0x1000) { - r += 13; - t >>>= 13; - } - if (t >= 0x40) { - r += 7; - t >>>= 7; - } - if (t >= 0x8) { - r += 4; - t >>>= 4; - } - if (t >= 0x02) { - r += 2; - t >>>= 2; - } - return r + t; - }; -} + k = bits2int(t, q); + kv.k = createHmac(algo, kv.k) + .update(kv.v) + .update(new Buffer([0])) + .digest(); + kv.v = createHmac(algo, kv.k) + .update(kv.v) + .digest(); + } while (k.cmp(q) !== -1); + + return k; + } -BN.prototype._zeroBits = function _zeroBits(w) { - // Short-cut - if (w === 0) - return 26; + function makeR(g, k, p, q) { + return g + .toRed(BN.mont(p)) + .redPow(k) + .fromRed() + .mod(q); + } - var t = w; - var r = 0; - if ((t & 0x1fff) === 0) { - r += 13; - t >>>= 13; - } - if ((t & 0x7f) === 0) { - r += 7; - t >>>= 7; - } - if ((t & 0xf) === 0) { - r += 4; - t >>>= 4; - } - if ((t & 0x3) === 0) { - r += 2; - t >>>= 2; - } - if ((t & 0x1) === 0) - r++; - return r; -}; - -// Return number of used bits in a BN -BN.prototype.bitLength = function bitLength() { - var hi = 0; - var w = this.words[this.length - 1]; - var hi = this._countBits(w); - return (this.length - 1) * 26 + hi; -}; - -// Number of trailing zero bits -BN.prototype.zeroBits = function zeroBits() { - if (this.cmpn(0) === 0) - return 0; - - var r = 0; - for (var i = 0; i < this.length; i++) { - var b = this._zeroBits(this.words[i]); - r += b; - if (b !== 26) - break; - } - return r; -}; + module.exports = sign; + module.exports.getKey = getKey; + module.exports.makeKey = makeKey; + }.call(this, require('buffer').Buffer)); + }, + { + './curves.json': 88, + 'bn.js': 92, + 'browserify-rsa': 84, + buffer: 113, + 'create-hmac': 137, + elliptic: 93, + 'parse-asn1': 198, + }, + ], + 91: [ + function(require, module, exports) { + (function(Buffer) { + // much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js + var BN = require('bn.js'); + var EC = require('elliptic').ec; + var parseKeys = require('parse-asn1'); + var curves = require('./curves.json'); + + function verify(sig, hash, key, signType, tag) { + var pub = parseKeys(key); + if (pub.type === 'ec') { + // rsa keys can be interpreted as ecdsa ones in openssl + if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') throw new Error('wrong public key type'); + return ecVerify(sig, hash, pub); + } else if (pub.type === 'dsa') { + if (signType !== 'dsa') throw new Error('wrong public key type'); + return dsaVerify(sig, hash, pub); + } else { + if (signType !== 'rsa' && signType !== 'ecdsa/rsa') throw new Error('wrong public key type'); + } + hash = Buffer.concat([tag, hash]); + var len = pub.modulus.byteLength(); + var pad = [1]; + var padNum = 0; + while (hash.length + pad.length + 2 < len) { + pad.push(0xff); + padNum++; + } + pad.push(0x00); + var i = -1; + while (++i < hash.length) { + pad.push(hash[i]); + } + pad = new Buffer(pad); + var red = BN.mont(pub.modulus); + sig = new BN(sig).toRed(red); + + sig = sig.redPow(new BN(pub.publicExponent)); + sig = new Buffer(sig.fromRed().toArray()); + var out = padNum < 8 ? 1 : 0; + len = Math.min(sig.length, pad.length); + if (sig.length !== pad.length) out = 1; + + i = -1; + while (++i < len) out |= sig[i] ^ pad[i]; + return out === 0; + } -BN.prototype.byteLength = function byteLength() { - return Math.ceil(this.bitLength() / 8); -}; + function ecVerify(sig, hash, pub) { + var curveId = curves[pub.data.algorithm.curve.join('.')]; + if (!curveId) throw new Error('unknown curve ' + pub.data.algorithm.curve.join('.')); -// Return negative clone of `this` -BN.prototype.neg = function neg() { - if (this.cmpn(0) === 0) - return this.clone(); + var curve = new EC(curveId); + var pubkey = pub.data.subjectPrivateKey.data; - var r = this.clone(); - r.sign = !this.sign; - return r; -}; + return curve.verify(hash, sig, pubkey); + } + function dsaVerify(sig, hash, pub) { + var p = pub.data.p; + var q = pub.data.q; + var g = pub.data.g; + var y = pub.data.pub_key; + var unpacked = parseKeys.signature.decode(sig, 'der'); + var s = unpacked.s; + var r = unpacked.r; + checkValue(s, q); + checkValue(r, q); + var montp = BN.mont(p); + var w = s.invm(q); + var v = g + .toRed(montp) + .redPow(new BN(hash).mul(w).mod(q)) + .fromRed() + .mul( + y + .toRed(montp) + .redPow(r.mul(w).mod(q)) + .fromRed(), + ) + .mod(p) + .mod(q); + return v.cmp(r) === 0; + } -// Or `num` with `this` in-place -BN.prototype.ior = function ior(num) { - this.sign = this.sign || num.sign; + function checkValue(b, q) { + if (b.cmpn(0) <= 0) throw new Error('invalid sig'); + if (b.cmp(q) >= q) throw new Error('invalid sig'); + } - while (this.length < num.length) - this.words[this.length++] = 0; + module.exports = verify; + }.call(this, require('buffer').Buffer)); + }, + { './curves.json': 88, 'bn.js': 92, buffer: 113, elliptic: 93, 'parse-asn1': 198 }, + ], + 92: [ + function(require, module, exports) { + arguments[4][59][0].apply(exports, arguments); + }, + { buffer: 64, dup: 59 }, + ], + 93: [ + function(require, module, exports) { + 'use strict'; + + var elliptic = exports; + + elliptic.version = require('../package.json').version; + elliptic.utils = require('./elliptic/utils'); + elliptic.rand = require('brorand'); + elliptic.curve = require('./elliptic/curve'); + elliptic.curves = require('./elliptic/curves'); + + // Protocols + elliptic.ec = require('./elliptic/ec'); + elliptic.eddsa = require('./elliptic/eddsa'); + }, + { + '../package.json': 108, + './elliptic/curve': 96, + './elliptic/curves': 99, + './elliptic/ec': 100, + './elliptic/eddsa': 103, + './elliptic/utils': 107, + brorand: 63, + }, + ], + 94: [ + function(require, module, exports) { + 'use strict'; + + var BN = require('bn.js'); + var elliptic = require('../../elliptic'); + var utils = elliptic.utils; + var getNAF = utils.getNAF; + var getJSF = utils.getJSF; + var assert = utils.assert; + + function BaseCurve(type, conf) { + this.type = type; + this.p = new BN(conf.p, 16); + + // Use Montgomery, when there is no fast reduction for the prime + this.red = conf.prime ? BN.red(conf.prime) : BN.mont(this.p); + + // Useful for many curves + this.zero = new BN(0).toRed(this.red); + this.one = new BN(1).toRed(this.red); + this.two = new BN(2).toRed(this.red); + + // Curve configuration, optional + this.n = conf.n && new BN(conf.n, 16); + this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed); + + // Temporary arrays + this._wnafT1 = new Array(4); + this._wnafT2 = new Array(4); + this._wnafT3 = new Array(4); + this._wnafT4 = new Array(4); + + // Generalized Greg Maxwell's trick + var adjustCount = this.n && this.p.div(this.n); + if (!adjustCount || adjustCount.cmpn(100) > 0) { + this.redN = null; + } else { + this._maxwellTrick = true; + this.redN = this.n.toRed(this.red); + } + } + module.exports = BaseCurve; - for (var i = 0; i < num.length; i++) - this.words[i] = this.words[i] | num.words[i]; + BaseCurve.prototype.point = function point() { + throw new Error('Not implemented'); + }; - return this.strip(); -}; + BaseCurve.prototype.validate = function validate() { + throw new Error('Not implemented'); + }; + BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) { + assert(p.precomputed); + var doubles = p._getDoubles(); -// Or `num` with `this` -BN.prototype.or = function or(num) { - if (this.length > num.length) - return this.clone().ior(num); - else - return num.clone().ior(this); -}; + var naf = getNAF(k, 1); + var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1); + I /= 3; + // Translate into more windowed form + var repr = []; + for (var j = 0; j < naf.length; j += doubles.step) { + var nafW = 0; + for (var k = j + doubles.step - 1; k >= j; k--) nafW = (nafW << 1) + naf[k]; + repr.push(nafW); + } -// And `num` with `this` in-place -BN.prototype.iand = function iand(num) { - this.sign = this.sign && num.sign; + var a = this.jpoint(null, null, null); + var b = this.jpoint(null, null, null); + for (var i = I; i > 0; i--) { + for (var j = 0; j < repr.length; j++) { + var nafW = repr[j]; + if (nafW === i) b = b.mixedAdd(doubles.points[j]); + else if (nafW === -i) b = b.mixedAdd(doubles.points[j].neg()); + } + a = a.add(b); + } + return a.toP(); + }; - // b = min-length(num, this) - var b; - if (this.length > num.length) - b = num; - else - b = this; + BaseCurve.prototype._wnafMul = function _wnafMul(p, k) { + var w = 4; + + // Precompute window + var nafPoints = p._getNAFPoints(w); + w = nafPoints.wnd; + var wnd = nafPoints.points; + + // Get NAF form + var naf = getNAF(k, w); + + // Add `this`*(N+1) for every w-NAF index + var acc = this.jpoint(null, null, null); + for (var i = naf.length - 1; i >= 0; i--) { + // Count zeroes + for (var k = 0; i >= 0 && naf[i] === 0; i--) k++; + if (i >= 0) k++; + acc = acc.dblp(k); + + if (i < 0) break; + var z = naf[i]; + assert(z !== 0); + if (p.type === 'affine') { + // J +- P + if (z > 0) acc = acc.mixedAdd(wnd[(z - 1) >> 1]); + else acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg()); + } else { + // J +- J + if (z > 0) acc = acc.add(wnd[(z - 1) >> 1]); + else acc = acc.add(wnd[(-z - 1) >> 1].neg()); + } + } + return p.type === 'affine' ? acc.toP() : acc; + }; - for (var i = 0; i < b.length; i++) - this.words[i] = this.words[i] & num.words[i]; + BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW, points, coeffs, len, jacobianResult) { + var wndWidth = this._wnafT1; + var wnd = this._wnafT2; + var naf = this._wnafT3; + + // Fill all arrays + var max = 0; + for (var i = 0; i < len; i++) { + var p = points[i]; + var nafPoints = p._getNAFPoints(defW); + wndWidth[i] = nafPoints.wnd; + wnd[i] = nafPoints.points; + } - this.length = b.length; + // Comb small window NAFs + for (var i = len - 1; i >= 1; i -= 2) { + var a = i - 1; + var b = i; + if (wndWidth[a] !== 1 || wndWidth[b] !== 1) { + naf[a] = getNAF(coeffs[a], wndWidth[a]); + naf[b] = getNAF(coeffs[b], wndWidth[b]); + max = Math.max(naf[a].length, max); + max = Math.max(naf[b].length, max); + continue; + } - return this.strip(); -}; + var comb = [points[a] /* 1 */, null /* 3 */, null /* 5 */, points[b] /* 7 */]; + // Try to avoid Projective points, if possible + if (points[a].y.cmp(points[b].y) === 0) { + comb[1] = points[a].add(points[b]); + comb[2] = points[a].toJ().mixedAdd(points[b].neg()); + } else if (points[a].y.cmp(points[b].y.redNeg()) === 0) { + comb[1] = points[a].toJ().mixedAdd(points[b]); + comb[2] = points[a].add(points[b].neg()); + } else { + comb[1] = points[a].toJ().mixedAdd(points[b]); + comb[2] = points[a].toJ().mixedAdd(points[b].neg()); + } -// And `num` with `this` -BN.prototype.and = function and(num) { - if (this.length > num.length) - return this.clone().iand(num); - else - return num.clone().iand(this); -}; + var index = [ + -3 /* -1 -1 */, + -1 /* -1 0 */, + -5 /* -1 1 */, + -7 /* 0 -1 */, + 0 /* 0 0 */, + 7 /* 0 1 */, + 5 /* 1 -1 */, + 1 /* 1 0 */, + 3 /* 1 1 */, + ]; + + var jsf = getJSF(coeffs[a], coeffs[b]); + max = Math.max(jsf[0].length, max); + naf[a] = new Array(max); + naf[b] = new Array(max); + for (var j = 0; j < max; j++) { + var ja = jsf[0][j] | 0; + var jb = jsf[1][j] | 0; + + naf[a][j] = index[(ja + 1) * 3 + (jb + 1)]; + naf[b][j] = 0; + wnd[a] = comb; + } + } + var acc = this.jpoint(null, null, null); + var tmp = this._wnafT4; + for (var i = max; i >= 0; i--) { + var k = 0; -// Xor `num` with `this` in-place -BN.prototype.ixor = function ixor(num) { - this.sign = this.sign || num.sign; + while (i >= 0) { + var zero = true; + for (var j = 0; j < len; j++) { + tmp[j] = naf[j][i] | 0; + if (tmp[j] !== 0) zero = false; + } + if (!zero) break; + k++; + i--; + } + if (i >= 0) k++; + acc = acc.dblp(k); + if (i < 0) break; + + for (var j = 0; j < len; j++) { + var z = tmp[j]; + var p; + if (z === 0) continue; + else if (z > 0) p = wnd[j][(z - 1) >> 1]; + else if (z < 0) p = wnd[j][(-z - 1) >> 1].neg(); + + if (p.type === 'affine') acc = acc.mixedAdd(p); + else acc = acc.add(p); + } + } + // Zeroify references + for (var i = 0; i < len; i++) wnd[i] = null; - // a.length > b.length - var a; - var b; - if (this.length > num.length) { - a = this; - b = num; - } else { - a = num; - b = this; - } + if (jacobianResult) return acc; + else return acc.toP(); + }; - for (var i = 0; i < b.length; i++) - this.words[i] = a.words[i] ^ b.words[i]; + function BasePoint(curve, type) { + this.curve = curve; + this.type = type; + this.precomputed = null; + } + BaseCurve.BasePoint = BasePoint; - if (this !== a) - for (; i < a.length; i++) - this.words[i] = a.words[i]; + BasePoint.prototype.eq = function eq(/*other*/) { + throw new Error('Not implemented'); + }; - this.length = a.length; + BasePoint.prototype.validate = function validate() { + return this.curve.validate(this); + }; - return this.strip(); -}; + BaseCurve.prototype.decodePoint = function decodePoint(bytes, enc) { + bytes = utils.toArray(bytes, enc); + var len = this.p.byteLength(); -// Xor `num` with `this` -BN.prototype.xor = function xor(num) { - if (this.length > num.length) - return this.clone().ixor(num); - else - return num.clone().ixor(this); -}; + // uncompressed, hybrid-odd, hybrid-even + if ((bytes[0] === 0x04 || bytes[0] === 0x06 || bytes[0] === 0x07) && bytes.length - 1 === 2 * len) { + if (bytes[0] === 0x06) assert(bytes[bytes.length - 1] % 2 === 0); + else if (bytes[0] === 0x07) assert(bytes[bytes.length - 1] % 2 === 1); + var res = this.point(bytes.slice(1, 1 + len), bytes.slice(1 + len, 1 + 2 * len)); -// Set `bit` of `this` -BN.prototype.setn = function setn(bit, val) { - assert(typeof bit === 'number' && bit >= 0); + return res; + } else if ((bytes[0] === 0x02 || bytes[0] === 0x03) && bytes.length - 1 === len) { + return this.pointFromX(bytes.slice(1, 1 + len), bytes[0] === 0x03); + } + throw new Error('Unknown point format'); + }; - var off = (bit / 26) | 0; - var wbit = bit % 26; + BasePoint.prototype.encodeCompressed = function encodeCompressed(enc) { + return this.encode(enc, true); + }; - while (this.length <= off) - this.words[this.length++] = 0; + BasePoint.prototype._encode = function _encode(compact) { + var len = this.curve.p.byteLength(); + var x = this.getX().toArray('be', len); - if (val) - this.words[off] = this.words[off] | (1 << wbit); - else - this.words[off] = this.words[off] & ~(1 << wbit); + if (compact) return [this.getY().isEven() ? 0x02 : 0x03].concat(x); - return this.strip(); -}; + return [0x04].concat(x, this.getY().toArray('be', len)); + }; + BasePoint.prototype.encode = function encode(enc, compact) { + return utils.encode(this._encode(compact), enc); + }; -// Add `num` to `this` in-place -BN.prototype.iadd = function iadd(num) { - // negative + positive - if (this.sign && !num.sign) { - this.sign = false; - var r = this.isub(num); - this.sign = !this.sign; - return this._normSign(); + BasePoint.prototype.precompute = function precompute(power) { + if (this.precomputed) return this; - // positive + negative - } else if (!this.sign && num.sign) { - num.sign = false; - var r = this.isub(num); - num.sign = true; - return r._normSign(); - } + var precomputed = { + doubles: null, + naf: null, + beta: null, + }; + precomputed.naf = this._getNAFPoints(8); + precomputed.doubles = this._getDoubles(4, power); + precomputed.beta = this._getBeta(); + this.precomputed = precomputed; - // a.length > b.length - var a; - var b; - if (this.length > num.length) { - a = this; - b = num; - } else { - a = num; - b = this; - } + return this; + }; - var carry = 0; - for (var i = 0; i < b.length; i++) { - var r = a.words[i] + b.words[i] + carry; - this.words[i] = r & 0x3ffffff; - carry = r >>> 26; - } - for (; carry !== 0 && i < a.length; i++) { - var r = a.words[i] + carry; - this.words[i] = r & 0x3ffffff; - carry = r >>> 26; - } + BasePoint.prototype._hasDoubles = function _hasDoubles(k) { + if (!this.precomputed) return false; - this.length = a.length; - if (carry !== 0) { - this.words[this.length] = carry; - this.length++; - // Copy the rest of the words - } else if (a !== this) { - for (; i < a.length; i++) - this.words[i] = a.words[i]; - } + var doubles = this.precomputed.doubles; + if (!doubles) return false; - return this; -}; - -// Add `num` to `this` -BN.prototype.add = function add(num) { - if (num.sign && !this.sign) { - num.sign = false; - var res = this.sub(num); - num.sign = true; - return res; - } else if (!num.sign && this.sign) { - this.sign = false; - var res = num.sub(this); - this.sign = true; - return res; - } + return doubles.points.length >= Math.ceil((k.bitLength() + 1) / doubles.step); + }; - if (this.length > num.length) - return this.clone().iadd(num); - else - return num.clone().iadd(this); -}; - -// Subtract `num` from `this` in-place -BN.prototype.isub = function isub(num) { - // this - (-num) = this + num - if (num.sign) { - num.sign = false; - var r = this.iadd(num); - num.sign = true; - return r._normSign(); - - // -this - num = -(this + num) - } else if (this.sign) { - this.sign = false; - this.iadd(num); - this.sign = true; - return this._normSign(); - } + BasePoint.prototype._getDoubles = function _getDoubles(step, power) { + if (this.precomputed && this.precomputed.doubles) return this.precomputed.doubles; - // At this point both numbers are positive - var cmp = this.cmp(num); + var doubles = [this]; + var acc = this; + for (var i = 0; i < power; i += step) { + for (var j = 0; j < step; j++) acc = acc.dbl(); + doubles.push(acc); + } + return { + step: step, + points: doubles, + }; + }; - // Optimization - zeroify - if (cmp === 0) { - this.sign = false; - this.length = 1; - this.words[0] = 0; - return this; - } + BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) { + if (this.precomputed && this.precomputed.naf) return this.precomputed.naf; - // a > b - var a; - var b; - if (cmp > 0) { - a = this; - b = num; - } else { - a = num; - b = this; - } + var res = [this]; + var max = (1 << wnd) - 1; + var dbl = max === 1 ? null : this.dbl(); + for (var i = 1; i < max; i++) res[i] = res[i - 1].add(dbl); + return { + wnd: wnd, + points: res, + }; + }; - var carry = 0; - for (var i = 0; i < b.length; i++) { - var r = a.words[i] - b.words[i] + carry; - carry = r >> 26; - this.words[i] = r & 0x3ffffff; - } - for (; carry !== 0 && i < a.length; i++) { - var r = a.words[i] + carry; - carry = r >> 26; - this.words[i] = r & 0x3ffffff; - } + BasePoint.prototype._getBeta = function _getBeta() { + return null; + }; - // Copy rest of the words - if (carry === 0 && i < a.length && a !== this) - for (; i < a.length; i++) - this.words[i] = a.words[i]; - this.length = Math.max(this.length, i); + BasePoint.prototype.dblp = function dblp(k) { + var r = this; + for (var i = 0; i < k; i++) r = r.dbl(); + return r; + }; + }, + { '../../elliptic': 93, 'bn.js': 92 }, + ], + 95: [ + function(require, module, exports) { + 'use strict'; + + var curve = require('../curve'); + var elliptic = require('../../elliptic'); + var BN = require('bn.js'); + var inherits = require('inherits'); + var Base = curve.base; + + var assert = elliptic.utils.assert; + + function EdwardsCurve(conf) { + // NOTE: Important as we are creating point in Base.call() + this.twisted = (conf.a | 0) !== 1; + this.mOneA = this.twisted && (conf.a | 0) === -1; + this.extended = this.mOneA; + + Base.call(this, 'edwards', conf); + + this.a = new BN(conf.a, 16).umod(this.red.m); + this.a = this.a.toRed(this.red); + this.c = new BN(conf.c, 16).toRed(this.red); + this.c2 = this.c.redSqr(); + this.d = new BN(conf.d, 16).toRed(this.red); + this.dd = this.d.redAdd(this.d); + + assert(!this.twisted || this.c.fromRed().cmpn(1) === 0); + this.oneC = (conf.c | 0) === 1; + } + inherits(EdwardsCurve, Base); + module.exports = EdwardsCurve; - if (a !== this) - this.sign = true; + EdwardsCurve.prototype._mulA = function _mulA(num) { + if (this.mOneA) return num.redNeg(); + else return this.a.redMul(num); + }; - return this.strip(); -}; + EdwardsCurve.prototype._mulC = function _mulC(num) { + if (this.oneC) return num; + else return this.c.redMul(num); + }; -// Subtract `num` from `this` -BN.prototype.sub = function sub(num) { - return this.clone().isub(num); -}; + // Just for compatibility with Short curve + EdwardsCurve.prototype.jpoint = function jpoint(x, y, z, t) { + return this.point(x, y, z, t); + }; -/* -// NOTE: This could be potentionally used to generate loop-less multiplications -function _genCombMulTo(alen, blen) { - var len = alen + blen - 1; - var src = [ - 'var a = this.words, b = num.words, o = out.words, c = 0, w, ' + - 'mask = 0x3ffffff, shift = 0x4000000;', - 'out.length = ' + len + ';' - ]; - for (var k = 0; k < len; k++) { - var minJ = Math.max(0, k - alen + 1); - var maxJ = Math.min(k, blen - 1); + EdwardsCurve.prototype.pointFromX = function pointFromX(x, odd) { + x = new BN(x, 16); + if (!x.red) x = x.toRed(this.red); + + var x2 = x.redSqr(); + var rhs = this.c2.redSub(this.a.redMul(x2)); + var lhs = this.one.redSub(this.c2.redMul(this.d).redMul(x2)); + + var y2 = rhs.redMul(lhs.redInvm()); + var y = y2.redSqrt(); + if ( + y + .redSqr() + .redSub(y2) + .cmp(this.zero) !== 0 + ) + throw new Error('invalid point'); - for (var j = minJ; j <= maxJ; j++) { - var i = k - j; - var mul = 'a[' + i + '] * b[' + j + ']'; + var isOdd = y.fromRed().isOdd(); + if ((odd && !isOdd) || (!odd && isOdd)) y = y.redNeg(); - if (j === minJ) { - src.push('w = ' + mul + ' + c;'); - src.push('c = (w / shift) | 0;'); - } else { - src.push('w += ' + mul + ';'); - src.push('c += (w / shift) | 0;'); - } - src.push('w &= mask;'); - } - src.push('o[' + k + '] = w;'); - } - src.push('if (c !== 0) {', - ' o[' + k + '] = c;', - ' out.length++;', - '}', - 'return out;'); + return this.point(x, y); + }; - return src.join('\n'); -} -*/ + EdwardsCurve.prototype.pointFromY = function pointFromY(y, odd) { + y = new BN(y, 16); + if (!y.red) y = y.toRed(this.red); -BN.prototype._smallMulTo = function _smallMulTo(num, out) { - out.sign = num.sign !== this.sign; - out.length = this.length + num.length; - - var carry = 0; - for (var k = 0; k < out.length - 1; k++) { - // Sum all words with the same `i + j = k` and accumulate `ncarry`, - // note that ncarry could be >= 0x3ffffff - var ncarry = carry >>> 26; - var rword = carry & 0x3ffffff; - var maxJ = Math.min(k, num.length - 1); - for (var j = Math.max(0, k - this.length + 1); j <= maxJ; j++) { - var i = k - j; - var a = this.words[i] | 0; - var b = num.words[j] | 0; - var r = a * b; - - var lo = r & 0x3ffffff; - ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0; - lo = (lo + rword) | 0; - rword = lo & 0x3ffffff; - ncarry = (ncarry + (lo >>> 26)) | 0; - } - out.words[k] = rword; - carry = ncarry; - } - if (carry !== 0) { - out.words[k] = carry; - } else { - out.length--; - } + // x^2 = (y^2 - 1) / (d y^2 + 1) + var y2 = y.redSqr(); + var lhs = y2.redSub(this.one); + var rhs = y2.redMul(this.d).redAdd(this.one); + var x2 = lhs.redMul(rhs.redInvm()); - return out.strip(); -}; - -BN.prototype._bigMulTo = function _bigMulTo(num, out) { - out.sign = num.sign !== this.sign; - out.length = this.length + num.length; - - var carry = 0; - var hncarry = 0; - for (var k = 0; k < out.length - 1; k++) { - // Sum all words with the same `i + j = k` and accumulate `ncarry`, - // note that ncarry could be >= 0x3ffffff - var ncarry = hncarry; - hncarry = 0; - var rword = carry & 0x3ffffff; - var maxJ = Math.min(k, num.length - 1); - for (var j = Math.max(0, k - this.length + 1); j <= maxJ; j++) { - var i = k - j; - var a = this.words[i] | 0; - var b = num.words[j] | 0; - var r = a * b; - - var lo = r & 0x3ffffff; - ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0; - lo = (lo + rword) | 0; - rword = lo & 0x3ffffff; - ncarry = (ncarry + (lo >>> 26)) | 0; - - hncarry += ncarry >>> 26; - ncarry &= 0x3ffffff; - } - out.words[k] = rword; - carry = ncarry; - ncarry = hncarry; - } - if (carry !== 0) { - out.words[k] = carry; - } else { - out.length--; - } + if (x2.cmp(this.zero) === 0) { + if (odd) throw new Error('invalid point'); + else return this.point(this.zero, y); + } - return out.strip(); -}; - -BN.prototype.mulTo = function mulTo(num, out) { - var res; - if (this.length + num.length < 63) - res = this._smallMulTo(num, out); - else - res = this._bigMulTo(num, out); - return res; -}; - -// Multiply `this` by `num` -BN.prototype.mul = function mul(num) { - var out = new BN(null); - out.words = new Array(this.length + num.length); - return this.mulTo(num, out); -}; - -// In-place Multiplication -BN.prototype.imul = function imul(num) { - if (this.cmpn(0) === 0 || num.cmpn(0) === 0) { - this.words[0] = 0; - this.length = 1; - return this; - } + var x = x2.redSqrt(); + if ( + x + .redSqr() + .redSub(x2) + .cmp(this.zero) !== 0 + ) + throw new Error('invalid point'); - var tlen = this.length; - var nlen = num.length; + if (x.isOdd() !== odd) x = x.redNeg(); - this.sign = num.sign !== this.sign; - this.length = this.length + num.length; - this.words[this.length - 1] = 0; + return this.point(x, y); + }; - for (var k = this.length - 2; k >= 0; k--) { - // Sum all words with the same `i + j = k` and accumulate `carry`, - // note that carry could be >= 0x3ffffff - var carry = 0; - var rword = 0; - var maxJ = Math.min(k, nlen - 1); - for (var j = Math.max(0, k - tlen + 1); j <= maxJ; j++) { - var i = k - j; - var a = this.words[i]; - var b = num.words[j]; - var r = a * b; - - var lo = r & 0x3ffffff; - carry += (r / 0x4000000) | 0; - lo += rword; - rword = lo & 0x3ffffff; - carry += lo >>> 26; - } - this.words[k] = rword; - this.words[k + 1] += carry; - carry = 0; - } + EdwardsCurve.prototype.validate = function validate(point) { + if (point.isInfinity()) return true; - // Propagate overflows - var carry = 0; - for (var i = 1; i < this.length; i++) { - var w = this.words[i] + carry; - this.words[i] = w & 0x3ffffff; - carry = w >>> 26; - } + // Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2) + point.normalize(); - return this.strip(); -}; - -BN.prototype.imuln = function imuln(num) { - assert(typeof num === 'number'); - - // Carry - var carry = 0; - for (var i = 0; i < this.length; i++) { - var w = this.words[i] * num; - var lo = (w & 0x3ffffff) + (carry & 0x3ffffff); - carry >>= 26; - carry += (w / 0x4000000) | 0; - // NOTE: lo is 27bit maximum - carry += lo >>> 26; - this.words[i] = lo & 0x3ffffff; - } + var x2 = point.x.redSqr(); + var y2 = point.y.redSqr(); + var lhs = x2.redMul(this.a).redAdd(y2); + var rhs = this.c2.redMul(this.one.redAdd(this.d.redMul(x2).redMul(y2))); - if (carry !== 0) { - this.words[i] = carry; - this.length++; - } + return lhs.cmp(rhs) === 0; + }; - return this; -}; - -// `this` * `this` -BN.prototype.sqr = function sqr() { - return this.mul(this); -}; - -// `this` * `this` in-place -BN.prototype.isqr = function isqr() { - return this.mul(this); -}; - -// Shift-left in-place -BN.prototype.ishln = function ishln(bits) { - assert(typeof bits === 'number' && bits >= 0); - var r = bits % 26; - var s = (bits - r) / 26; - var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r); - - if (r !== 0) { - var carry = 0; - for (var i = 0; i < this.length; i++) { - var newCarry = this.words[i] & carryMask; - var c = (this.words[i] - newCarry) << r; - this.words[i] = c | carry; - carry = newCarry >>> (26 - r); - } - if (carry) { - this.words[i] = carry; - this.length++; - } - } + function Point(curve, x, y, z, t) { + Base.BasePoint.call(this, curve, 'projective'); + if (x === null && y === null && z === null) { + this.x = this.curve.zero; + this.y = this.curve.one; + this.z = this.curve.one; + this.t = this.curve.zero; + this.zOne = true; + } else { + this.x = new BN(x, 16); + this.y = new BN(y, 16); + this.z = z ? new BN(z, 16) : this.curve.one; + this.t = t && new BN(t, 16); + if (!this.x.red) this.x = this.x.toRed(this.curve.red); + if (!this.y.red) this.y = this.y.toRed(this.curve.red); + if (!this.z.red) this.z = this.z.toRed(this.curve.red); + if (this.t && !this.t.red) this.t = this.t.toRed(this.curve.red); + this.zOne = this.z === this.curve.one; + + // Use extended coordinates + if (this.curve.extended && !this.t) { + this.t = this.x.redMul(this.y); + if (!this.zOne) this.t = this.t.redMul(this.z.redInvm()); + } + } + } + inherits(Point, Base.BasePoint); - if (s !== 0) { - for (var i = this.length - 1; i >= 0; i--) - this.words[i + s] = this.words[i]; - for (var i = 0; i < s; i++) - this.words[i] = 0; - this.length += s; - } + EdwardsCurve.prototype.pointFromJSON = function pointFromJSON(obj) { + return Point.fromJSON(this, obj); + }; - return this.strip(); -}; - -// Shift-right in-place -// NOTE: `hint` is a lowest bit before trailing zeroes -// NOTE: if `extended` is present - it will be filled with destroyed bits -BN.prototype.ishrn = function ishrn(bits, hint, extended) { - assert(typeof bits === 'number' && bits >= 0); - var h; - if (hint) - h = (hint - (hint % 26)) / 26; - else - h = 0; - - var r = bits % 26; - var s = Math.min((bits - r) / 26, this.length); - var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); - var maskedWords = extended; - - h -= s; - h = Math.max(0, h); - - // Extended mode, copy masked part - if (maskedWords) { - for (var i = 0; i < s; i++) - maskedWords.words[i] = this.words[i]; - maskedWords.length = s; - } + EdwardsCurve.prototype.point = function point(x, y, z, t) { + return new Point(this, x, y, z, t); + }; - if (s === 0) { - // No-op, we should not move anything at all - } else if (this.length > s) { - this.length -= s; - for (var i = 0; i < this.length; i++) - this.words[i] = this.words[i + s]; - } else { - this.words[0] = 0; - this.length = 1; - } + Point.fromJSON = function fromJSON(curve, obj) { + return new Point(curve, obj[0], obj[1], obj[2]); + }; - var carry = 0; - for (var i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) { - var word = this.words[i]; - this.words[i] = (carry << (26 - r)) | (word >>> r); - carry = word & mask; - } + Point.prototype.inspect = function inspect() { + if (this.isInfinity()) return ''; + return ( + '' + ); + }; - // Push carried bits as a mask - if (maskedWords && carry !== 0) - maskedWords.words[maskedWords.length++] = carry; + Point.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.x.cmpn(0) === 0 && this.y.cmp(this.z) === 0; + }; - if (this.length === 0) { - this.words[0] = 0; - this.length = 1; - } + Point.prototype._extDbl = function _extDbl() { + // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html + // #doubling-dbl-2008-hwcd + // 4M + 4S + + // A = X1^2 + var a = this.x.redSqr(); + // B = Y1^2 + var b = this.y.redSqr(); + // C = 2 * Z1^2 + var c = this.z.redSqr(); + c = c.redIAdd(c); + // D = a * A + var d = this.curve._mulA(a); + // E = (X1 + Y1)^2 - A - B + var e = this.x + .redAdd(this.y) + .redSqr() + .redISub(a) + .redISub(b); + // G = D + B + var g = d.redAdd(b); + // F = G - C + var f = g.redSub(c); + // H = D - B + var h = d.redSub(b); + // X3 = E * F + var nx = e.redMul(f); + // Y3 = G * H + var ny = g.redMul(h); + // T3 = E * H + var nt = e.redMul(h); + // Z3 = F * G + var nz = f.redMul(g); + return this.curve.point(nx, ny, nz, nt); + }; - this.strip(); + Point.prototype._projDbl = function _projDbl() { + // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html + // #doubling-dbl-2008-bbjlp + // #doubling-dbl-2007-bl + // and others + // Generally 3M + 4S or 2M + 4S + + // B = (X1 + Y1)^2 + var b = this.x.redAdd(this.y).redSqr(); + // C = X1^2 + var c = this.x.redSqr(); + // D = Y1^2 + var d = this.y.redSqr(); + + var nx; + var ny; + var nz; + if (this.curve.twisted) { + // E = a * C + var e = this.curve._mulA(c); + // F = E + D + var f = e.redAdd(d); + if (this.zOne) { + // X3 = (B - C - D) * (F - 2) + nx = b + .redSub(c) + .redSub(d) + .redMul(f.redSub(this.curve.two)); + // Y3 = F * (E - D) + ny = f.redMul(e.redSub(d)); + // Z3 = F^2 - 2 * F + nz = f + .redSqr() + .redSub(f) + .redSub(f); + } else { + // H = Z1^2 + var h = this.z.redSqr(); + // J = F - 2 * H + var j = f.redSub(h).redISub(h); + // X3 = (B-C-D)*J + nx = b + .redSub(c) + .redISub(d) + .redMul(j); + // Y3 = F * (E - D) + ny = f.redMul(e.redSub(d)); + // Z3 = F * J + nz = f.redMul(j); + } + } else { + // E = C + D + var e = c.redAdd(d); + // H = (c * Z1)^2 + var h = this.curve._mulC(this.c.redMul(this.z)).redSqr(); + // J = E - 2 * H + var j = e.redSub(h).redSub(h); + // X3 = c * (B - E) * J + nx = this.curve._mulC(b.redISub(e)).redMul(j); + // Y3 = c * E * (C - D) + ny = this.curve._mulC(e).redMul(c.redISub(d)); + // Z3 = E * J + nz = e.redMul(j); + } + return this.curve.point(nx, ny, nz); + }; - return this; -}; + Point.prototype.dbl = function dbl() { + if (this.isInfinity()) return this; -// Shift-left -BN.prototype.shln = function shln(bits) { - return this.clone().ishln(bits); -}; + // Double in extended coordinates + if (this.curve.extended) return this._extDbl(); + else return this._projDbl(); + }; -// Shift-right -BN.prototype.shrn = function shrn(bits) { - return this.clone().ishrn(bits); -}; + Point.prototype._extAdd = function _extAdd(p) { + // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html + // #addition-add-2008-hwcd-3 + // 8M + + // A = (Y1 - X1) * (Y2 - X2) + var a = this.y.redSub(this.x).redMul(p.y.redSub(p.x)); + // B = (Y1 + X1) * (Y2 + X2) + var b = this.y.redAdd(this.x).redMul(p.y.redAdd(p.x)); + // C = T1 * k * T2 + var c = this.t.redMul(this.curve.dd).redMul(p.t); + // D = Z1 * 2 * Z2 + var d = this.z.redMul(p.z.redAdd(p.z)); + // E = B - A + var e = b.redSub(a); + // F = D - C + var f = d.redSub(c); + // G = D + C + var g = d.redAdd(c); + // H = B + A + var h = b.redAdd(a); + // X3 = E * F + var nx = e.redMul(f); + // Y3 = G * H + var ny = g.redMul(h); + // T3 = E * H + var nt = e.redMul(h); + // Z3 = F * G + var nz = f.redMul(g); + return this.curve.point(nx, ny, nz, nt); + }; -// Test if n bit is set -BN.prototype.testn = function testn(bit) { - assert(typeof bit === 'number' && bit >= 0); - var r = bit % 26; - var s = (bit - r) / 26; - var q = 1 << r; + Point.prototype._projAdd = function _projAdd(p) { + // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html + // #addition-add-2008-bbjlp + // #addition-add-2007-bl + // 10M + 1S + + // A = Z1 * Z2 + var a = this.z.redMul(p.z); + // B = A^2 + var b = a.redSqr(); + // C = X1 * X2 + var c = this.x.redMul(p.x); + // D = Y1 * Y2 + var d = this.y.redMul(p.y); + // E = d * C * D + var e = this.curve.d.redMul(c).redMul(d); + // F = B - E + var f = b.redSub(e); + // G = B + E + var g = b.redAdd(e); + // X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D) + var tmp = this.x + .redAdd(this.y) + .redMul(p.x.redAdd(p.y)) + .redISub(c) + .redISub(d); + var nx = a.redMul(f).redMul(tmp); + var ny; + var nz; + if (this.curve.twisted) { + // Y3 = A * G * (D - a * C) + ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c))); + // Z3 = F * G + nz = f.redMul(g); + } else { + // Y3 = A * G * (D - C) + ny = a.redMul(g).redMul(d.redSub(c)); + // Z3 = c * F * G + nz = this.curve._mulC(f).redMul(g); + } + return this.curve.point(nx, ny, nz); + }; - // Fast case: bit is much higher than all existing words - if (this.length <= s) { - return false; - } + Point.prototype.add = function add(p) { + if (this.isInfinity()) return p; + if (p.isInfinity()) return this; - // Check bit and return - var w = this.words[s]; + if (this.curve.extended) return this._extAdd(p); + else return this._projAdd(p); + }; - return !!(w & q); -}; + Point.prototype.mul = function mul(k) { + if (this._hasDoubles(k)) return this.curve._fixedNafMul(this, k); + else return this.curve._wnafMul(this, k); + }; -// Return only lowers bits of number (in-place) -BN.prototype.imaskn = function imaskn(bits) { - assert(typeof bits === 'number' && bits >= 0); - var r = bits % 26; - var s = (bits - r) / 26; + Point.prototype.mulAdd = function mulAdd(k1, p, k2) { + return this.curve._wnafMulAdd(1, [this, p], [k1, k2], 2, false); + }; - assert(!this.sign, 'imaskn works only with positive numbers'); + Point.prototype.jmulAdd = function jmulAdd(k1, p, k2) { + return this.curve._wnafMulAdd(1, [this, p], [k1, k2], 2, true); + }; - if (r !== 0) - s++; - this.length = Math.min(s, this.length); + Point.prototype.normalize = function normalize() { + if (this.zOne) return this; + + // Normalize coordinates + var zi = this.z.redInvm(); + this.x = this.x.redMul(zi); + this.y = this.y.redMul(zi); + if (this.t) this.t = this.t.redMul(zi); + this.z = this.curve.one; + this.zOne = true; + return this; + }; - if (r !== 0) { - var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); - this.words[this.length - 1] &= mask; - } + Point.prototype.neg = function neg() { + return this.curve.point(this.x.redNeg(), this.y, this.z, this.t && this.t.redNeg()); + }; - return this.strip(); -}; - -// Return only lowers bits of number -BN.prototype.maskn = function maskn(bits) { - return this.clone().imaskn(bits); -}; - -// Add plain number `num` to `this` -BN.prototype.iaddn = function iaddn(num) { - assert(typeof num === 'number'); - if (num < 0) - return this.isubn(-num); - - // Possible sign change - if (this.sign) { - if (this.length === 1 && this.words[0] < num) { - this.words[0] = num - this.words[0]; - this.sign = false; - return this; - } + Point.prototype.getX = function getX() { + this.normalize(); + return this.x.fromRed(); + }; - this.sign = false; - this.isubn(num); - this.sign = true; - return this; - } + Point.prototype.getY = function getY() { + this.normalize(); + return this.y.fromRed(); + }; - // Add without checks - return this._iaddn(num); -}; + Point.prototype.eq = function eq(other) { + return this === other || (this.getX().cmp(other.getX()) === 0 && this.getY().cmp(other.getY()) === 0); + }; -BN.prototype._iaddn = function _iaddn(num) { - this.words[0] += num; + Point.prototype.eqXToP = function eqXToP(x) { + var rx = x.toRed(this.curve.red).redMul(this.z); + if (this.x.cmp(rx) === 0) return true; - // Carry - for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) { - this.words[i] -= 0x4000000; - if (i === this.length - 1) - this.words[i + 1] = 1; - else - this.words[i + 1]++; - } - this.length = Math.max(this.length, i + 1); - - return this; -}; - -// Subtract plain number `num` from `this` -BN.prototype.isubn = function isubn(num) { - assert(typeof num === 'number'); - if (num < 0) - return this.iaddn(-num); - - if (this.sign) { - this.sign = false; - this.iaddn(num); - this.sign = true; - return this; - } + var xc = x.clone(); + var t = this.curve.redN.redMul(this.z); + for (;;) { + xc.iadd(this.curve.n); + if (xc.cmp(this.curve.p) >= 0) return false; - this.words[0] -= num; + rx.redIAdd(t); + if (this.x.cmp(rx) === 0) return true; + } + return false; + }; - // Carry - for (var i = 0; i < this.length && this.words[i] < 0; i++) { - this.words[i] += 0x4000000; - this.words[i + 1] -= 1; - } + // Compatibility with BaseCurve + Point.prototype.toP = Point.prototype.normalize; + Point.prototype.mixedAdd = Point.prototype.add; + }, + { '../../elliptic': 93, '../curve': 96, 'bn.js': 92, inherits: 184 }, + ], + 96: [ + function(require, module, exports) { + 'use strict'; + + var curve = exports; + + curve.base = require('./base'); + curve.short = require('./short'); + curve.mont = require('./mont'); + curve.edwards = require('./edwards'); + }, + { './base': 94, './edwards': 95, './mont': 97, './short': 98 }, + ], + 97: [ + function(require, module, exports) { + 'use strict'; + + var curve = require('../curve'); + var BN = require('bn.js'); + var inherits = require('inherits'); + var Base = curve.base; + + var elliptic = require('../../elliptic'); + var utils = elliptic.utils; + + function MontCurve(conf) { + Base.call(this, 'mont', conf); + + this.a = new BN(conf.a, 16).toRed(this.red); + this.b = new BN(conf.b, 16).toRed(this.red); + this.i4 = new BN(4).toRed(this.red).redInvm(); + this.two = new BN(2).toRed(this.red); + this.a24 = this.i4.redMul(this.a.redAdd(this.two)); + } + inherits(MontCurve, Base); + module.exports = MontCurve; + + MontCurve.prototype.validate = function validate(point) { + var x = point.normalize().x; + var x2 = x.redSqr(); + var rhs = x2 + .redMul(x) + .redAdd(x2.redMul(this.a)) + .redAdd(x); + var y = rhs.redSqrt(); + + return y.redSqr().cmp(rhs) === 0; + }; - return this.strip(); -}; - -BN.prototype.addn = function addn(num) { - return this.clone().iaddn(num); -}; - -BN.prototype.subn = function subn(num) { - return this.clone().isubn(num); -}; - -BN.prototype.iabs = function iabs() { - this.sign = false; - - return this; -}; - -BN.prototype.abs = function abs() { - return this.clone().iabs(); -}; - -BN.prototype._ishlnsubmul = function _ishlnsubmul(num, mul, shift) { - // Bigger storage is needed - var len = num.length + shift; - var i; - if (this.words.length < len) { - var t = new Array(len); - for (var i = 0; i < this.length; i++) - t[i] = this.words[i]; - this.words = t; - } else { - i = this.length; - } + function Point(curve, x, z) { + Base.BasePoint.call(this, curve, 'projective'); + if (x === null && z === null) { + this.x = this.curve.one; + this.z = this.curve.zero; + } else { + this.x = new BN(x, 16); + this.z = new BN(z, 16); + if (!this.x.red) this.x = this.x.toRed(this.curve.red); + if (!this.z.red) this.z = this.z.toRed(this.curve.red); + } + } + inherits(Point, Base.BasePoint); - // Zeroify rest - this.length = Math.max(this.length, len); - for (; i < this.length; i++) - this.words[i] = 0; - - var carry = 0; - for (var i = 0; i < num.length; i++) { - var w = this.words[i + shift] + carry; - var right = num.words[i] * mul; - w -= right & 0x3ffffff; - carry = (w >> 26) - ((right / 0x4000000) | 0); - this.words[i + shift] = w & 0x3ffffff; - } - for (; i < this.length - shift; i++) { - var w = this.words[i + shift] + carry; - carry = w >> 26; - this.words[i + shift] = w & 0x3ffffff; - } + MontCurve.prototype.decodePoint = function decodePoint(bytes, enc) { + return this.point(utils.toArray(bytes, enc), 1); + }; - if (carry === 0) - return this.strip(); + MontCurve.prototype.point = function point(x, z) { + return new Point(this, x, z); + }; - // Subtraction overflow - assert(carry === -1); - carry = 0; - for (var i = 0; i < this.length; i++) { - var w = -this.words[i] + carry; - carry = w >> 26; - this.words[i] = w & 0x3ffffff; - } - this.sign = true; + MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) { + return Point.fromJSON(this, obj); + }; - return this.strip(); -}; + Point.prototype.precompute = function precompute() { + // No-op + }; -BN.prototype._wordDiv = function _wordDiv(num, mode) { - var shift = this.length - num.length; + Point.prototype._encode = function _encode() { + return this.getX().toArray('be', this.curve.p.byteLength()); + }; - var a = this.clone(); - var b = num; + Point.fromJSON = function fromJSON(curve, obj) { + return new Point(curve, obj[0], obj[1] || curve.one); + }; - // Normalize - var bhi = b.words[b.length - 1]; - var bhiBits = this._countBits(bhi); - shift = 26 - bhiBits; - if (shift !== 0) { - b = b.shln(shift); - a.ishln(shift); - bhi = b.words[b.length - 1]; - } + Point.prototype.inspect = function inspect() { + if (this.isInfinity()) return ''; + return ''; + }; - // Initialize quotient - var m = a.length - b.length; - var q; + Point.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.z.cmpn(0) === 0; + }; - if (mode !== 'mod') { - q = new BN(null); - q.length = m + 1; - q.words = new Array(q.length); - for (var i = 0; i < q.length; i++) - q.words[i] = 0; - } + Point.prototype.dbl = function dbl() { + // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3 + // 2M + 2S + 4A + + // A = X1 + Z1 + var a = this.x.redAdd(this.z); + // AA = A^2 + var aa = a.redSqr(); + // B = X1 - Z1 + var b = this.x.redSub(this.z); + // BB = B^2 + var bb = b.redSqr(); + // C = AA - BB + var c = aa.redSub(bb); + // X3 = AA * BB + var nx = aa.redMul(bb); + // Z3 = C * (BB + A24 * C) + var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c))); + return this.curve.point(nx, nz); + }; - var diff = a.clone()._ishlnsubmul(b, 1, m); - if (!diff.sign) { - a = diff; - if (q) - q.words[m] = 1; - } + Point.prototype.add = function add() { + throw new Error('Not supported on Montgomery curve'); + }; - for (var j = m - 1; j >= 0; j--) { - var qj = a.words[b.length + j] * 0x4000000 + a.words[b.length + j - 1]; + Point.prototype.diffAdd = function diffAdd(p, diff) { + // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3 + // 4M + 2S + 6A + + // A = X2 + Z2 + var a = this.x.redAdd(this.z); + // B = X2 - Z2 + var b = this.x.redSub(this.z); + // C = X3 + Z3 + var c = p.x.redAdd(p.z); + // D = X3 - Z3 + var d = p.x.redSub(p.z); + // DA = D * A + var da = d.redMul(a); + // CB = C * B + var cb = c.redMul(b); + // X5 = Z1 * (DA + CB)^2 + var nx = diff.z.redMul(da.redAdd(cb).redSqr()); + // Z5 = X1 * (DA - CB)^2 + var nz = diff.x.redMul(da.redISub(cb).redSqr()); + return this.curve.point(nx, nz); + }; - // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max - // (0x7ffffff) - qj = Math.min((qj / bhi) | 0, 0x3ffffff); + Point.prototype.mul = function mul(k) { + var t = k.clone(); + var a = this; // (N / 2) * Q + Q + var b = this.curve.point(null, null); // (N / 2) * Q + var c = this; // Q - a._ishlnsubmul(b, qj, j); - while (a.sign) { - qj--; - a.sign = false; - a._ishlnsubmul(b, 1, j); - if (a.cmpn(0) !== 0) - a.sign = !a.sign; - } - if (q) - q.words[j] = qj; - } - if (q) - q.strip(); - a.strip(); - - // Denormalize - if (mode !== 'div' && shift !== 0) - a.ishrn(shift); - return { div: q ? q : null, mod: a }; -}; - -BN.prototype.divmod = function divmod(num, mode) { - assert(num.cmpn(0) !== 0); - - if (this.sign && !num.sign) { - var res = this.neg().divmod(num, mode); - var div; - var mod; - if (mode !== 'mod') - div = res.div.neg(); - if (mode !== 'div') - mod = res.mod.cmpn(0) === 0 ? res.mod : num.sub(res.mod); - return { - div: div, - mod: mod - }; - } else if (!this.sign && num.sign) { - var res = this.divmod(num.neg(), mode); - var div; - if (mode !== 'mod') - div = res.div.neg(); - return { div: div, mod: res.mod }; - } else if (this.sign && num.sign) { - return this.neg().divmod(num.neg(), mode); - } + for (var bits = []; t.cmpn(0) !== 0; t.iushrn(1)) bits.push(t.andln(1)); - // Both numbers are positive at this point - - // Strip both numbers to approximate shift value - if (num.length > this.length || this.cmp(num) < 0) - return { div: new BN(0), mod: this }; - - // Very short reduction - if (num.length === 1) { - if (mode === 'div') - return { div: this.divn(num.words[0]), mod: null }; - else if (mode === 'mod') - return { div: null, mod: new BN(this.modn(num.words[0])) }; - return { - div: this.divn(num.words[0]), - mod: new BN(this.modn(num.words[0])) - }; - } + for (var i = bits.length - 1; i >= 0; i--) { + if (bits[i] === 0) { + // N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q + a = a.diffAdd(b, c); + // N * Q = 2 * ((N / 2) * Q + Q)) + b = b.dbl(); + } else { + // N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q) + b = a.diffAdd(b, c); + // N * Q + Q = 2 * ((N / 2) * Q + Q) + a = a.dbl(); + } + } + return b; + }; - return this._wordDiv(num, mode); -}; + Point.prototype.mulAdd = function mulAdd() { + throw new Error('Not supported on Montgomery curve'); + }; -// Find `this` / `num` -BN.prototype.div = function div(num) { - return this.divmod(num, 'div').div; -}; + Point.prototype.jumlAdd = function jumlAdd() { + throw new Error('Not supported on Montgomery curve'); + }; -// Find `this` % `num` -BN.prototype.mod = function mod(num) { - return this.divmod(num, 'mod').mod; -}; + Point.prototype.eq = function eq(other) { + return this.getX().cmp(other.getX()) === 0; + }; -// Find Round(`this` / `num`) -BN.prototype.divRound = function divRound(num) { - var dm = this.divmod(num); + Point.prototype.normalize = function normalize() { + this.x = this.x.redMul(this.z.redInvm()); + this.z = this.curve.one; + return this; + }; - // Fast case - exact division - if (dm.mod.cmpn(0) === 0) - return dm.div; + Point.prototype.getX = function getX() { + // Normalize coordinates + this.normalize(); - var mod = dm.div.sign ? dm.mod.isub(num) : dm.mod; + return this.x.fromRed(); + }; + }, + { '../../elliptic': 93, '../curve': 96, 'bn.js': 92, inherits: 184 }, + ], + 98: [ + function(require, module, exports) { + 'use strict'; + + var curve = require('../curve'); + var elliptic = require('../../elliptic'); + var BN = require('bn.js'); + var inherits = require('inherits'); + var Base = curve.base; + + var assert = elliptic.utils.assert; + + function ShortCurve(conf) { + Base.call(this, 'short', conf); + + this.a = new BN(conf.a, 16).toRed(this.red); + this.b = new BN(conf.b, 16).toRed(this.red); + this.tinv = this.two.redInvm(); + + this.zeroA = this.a.fromRed().cmpn(0) === 0; + this.threeA = + this.a + .fromRed() + .sub(this.p) + .cmpn(-3) === 0; + + // If the curve is endomorphic, precalculate beta and lambda + this.endo = this._getEndomorphism(conf); + this._endoWnafT1 = new Array(4); + this._endoWnafT2 = new Array(4); + } + inherits(ShortCurve, Base); + module.exports = ShortCurve; + + ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) { + // No efficient endomorphism + if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1) return; + + // Compute beta and lambda, that lambda * P = (beta * Px; Py) + var beta; + var lambda; + if (conf.beta) { + beta = new BN(conf.beta, 16).toRed(this.red); + } else { + var betas = this._getEndoRoots(this.p); + // Choose the smallest beta + beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1]; + beta = beta.toRed(this.red); + } + if (conf.lambda) { + lambda = new BN(conf.lambda, 16); + } else { + // Choose the lambda that is matching selected beta + var lambdas = this._getEndoRoots(this.n); + if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) { + lambda = lambdas[0]; + } else { + lambda = lambdas[1]; + assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0); + } + } - var half = num.shrn(1); - var r2 = num.andln(1); - var cmp = mod.cmp(half); + // Get basis vectors, used for balanced length-two representation + var basis; + if (conf.basis) { + basis = conf.basis.map(function(vec) { + return { + a: new BN(vec.a, 16), + b: new BN(vec.b, 16), + }; + }); + } else { + basis = this._getEndoBasis(lambda); + } - // Round down - if (cmp < 0 || r2 === 1 && cmp === 0) - return dm.div; + return { + beta: beta, + lambda: lambda, + basis: basis, + }; + }; - // Round up - return dm.div.sign ? dm.div.isubn(1) : dm.div.iaddn(1); -}; + ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) { + // Find roots of for x^2 + x + 1 in F + // Root = (-1 +- Sqrt(-3)) / 2 + // + var red = num === this.p ? this.red : BN.mont(num); + var tinv = new BN(2).toRed(red).redInvm(); + var ntinv = tinv.redNeg(); + + var s = new BN(3) + .toRed(red) + .redNeg() + .redSqrt() + .redMul(tinv); + + var l1 = ntinv.redAdd(s).fromRed(); + var l2 = ntinv.redSub(s).fromRed(); + return [l1, l2]; + }; -BN.prototype.modn = function modn(num) { - assert(num <= 0x3ffffff); - var p = (1 << 26) % num; + ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) { + // aprxSqrt >= sqrt(this.n) + var aprxSqrt = this.n.ushrn(Math.floor(this.n.bitLength() / 2)); + + // 3.74 + // Run EGCD, until r(L + 1) < aprxSqrt + var u = lambda; + var v = this.n.clone(); + var x1 = new BN(1); + var y1 = new BN(0); + var x2 = new BN(0); + var y2 = new BN(1); + + // NOTE: all vectors are roots of: a + b * lambda = 0 (mod n) + var a0; + var b0; + // First vector + var a1; + var b1; + // Second vector + var a2; + var b2; + + var prevR; + var i = 0; + var r; + var x; + while (u.cmpn(0) !== 0) { + var q = v.div(u); + r = v.sub(q.mul(u)); + x = x2.sub(q.mul(x1)); + var y = y2.sub(q.mul(y1)); + + if (!a1 && r.cmp(aprxSqrt) < 0) { + a0 = prevR.neg(); + b0 = x1; + a1 = r.neg(); + b1 = x; + } else if (a1 && ++i === 2) { + break; + } + prevR = r; + + v = u; + u = r; + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + } + a2 = r.neg(); + b2 = x; + + var len1 = a1.sqr().add(b1.sqr()); + var len2 = a2.sqr().add(b2.sqr()); + if (len2.cmp(len1) >= 0) { + a2 = a0; + b2 = b0; + } - var acc = 0; - for (var i = this.length - 1; i >= 0; i--) - acc = (p * acc + this.words[i]) % num; + // Normalize signs + if (a1.negative) { + a1 = a1.neg(); + b1 = b1.neg(); + } + if (a2.negative) { + a2 = a2.neg(); + b2 = b2.neg(); + } - return acc; -}; + return [{ a: a1, b: b1 }, { a: a2, b: b2 }]; + }; -// In-place division by number -BN.prototype.idivn = function idivn(num) { - assert(num <= 0x3ffffff); + ShortCurve.prototype._endoSplit = function _endoSplit(k) { + var basis = this.endo.basis; + var v1 = basis[0]; + var v2 = basis[1]; + + var c1 = v2.b.mul(k).divRound(this.n); + var c2 = v1.b + .neg() + .mul(k) + .divRound(this.n); + + var p1 = c1.mul(v1.a); + var p2 = c2.mul(v2.a); + var q1 = c1.mul(v1.b); + var q2 = c2.mul(v2.b); + + // Calculate answer + var k1 = k.sub(p1).sub(p2); + var k2 = q1.add(q2).neg(); + return { k1: k1, k2: k2 }; + }; - var carry = 0; - for (var i = this.length - 1; i >= 0; i--) { - var w = this.words[i] + carry * 0x4000000; - this.words[i] = (w / num) | 0; - carry = w % num; - } + ShortCurve.prototype.pointFromX = function pointFromX(x, odd) { + x = new BN(x, 16); + if (!x.red) x = x.toRed(this.red); + + var y2 = x + .redSqr() + .redMul(x) + .redIAdd(x.redMul(this.a)) + .redIAdd(this.b); + var y = y2.redSqrt(); + if ( + y + .redSqr() + .redSub(y2) + .cmp(this.zero) !== 0 + ) + throw new Error('invalid point'); - return this.strip(); -}; + // XXX Is there any way to tell if the number is odd without converting it + // to non-red form? + var isOdd = y.fromRed().isOdd(); + if ((odd && !isOdd) || (!odd && isOdd)) y = y.redNeg(); -BN.prototype.divn = function divn(num) { - return this.clone().idivn(num); -}; + return this.point(x, y); + }; -BN.prototype.egcd = function egcd(p) { - assert(!p.sign); - assert(p.cmpn(0) !== 0); + ShortCurve.prototype.validate = function validate(point) { + if (point.inf) return true; + + var x = point.x; + var y = point.y; + + var ax = this.a.redMul(x); + var rhs = x + .redSqr() + .redMul(x) + .redIAdd(ax) + .redIAdd(this.b); + return ( + y + .redSqr() + .redISub(rhs) + .cmpn(0) === 0 + ); + }; - var x = this; - var y = p.clone(); + ShortCurve.prototype._endoWnafMulAdd = function _endoWnafMulAdd(points, coeffs, jacobianResult) { + var npoints = this._endoWnafT1; + var ncoeffs = this._endoWnafT2; + for (var i = 0; i < points.length; i++) { + var split = this._endoSplit(coeffs[i]); + var p = points[i]; + var beta = p._getBeta(); + + if (split.k1.negative) { + split.k1.ineg(); + p = p.neg(true); + } + if (split.k2.negative) { + split.k2.ineg(); + beta = beta.neg(true); + } - if (x.sign) - x = x.mod(p); - else - x = x.clone(); + npoints[i * 2] = p; + npoints[i * 2 + 1] = beta; + ncoeffs[i * 2] = split.k1; + ncoeffs[i * 2 + 1] = split.k2; + } + var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2, jacobianResult); - // A * x + B * y = x - var A = new BN(1); - var B = new BN(0); + // Clean-up references to points and coefficients + for (var j = 0; j < i * 2; j++) { + npoints[j] = null; + ncoeffs[j] = null; + } + return res; + }; - // C * x + D * y = y - var C = new BN(0); - var D = new BN(1); + function Point(curve, x, y, isRed) { + Base.BasePoint.call(this, curve, 'affine'); + if (x === null && y === null) { + this.x = null; + this.y = null; + this.inf = true; + } else { + this.x = new BN(x, 16); + this.y = new BN(y, 16); + // Force redgomery representation when loading from JSON + if (isRed) { + this.x.forceRed(this.curve.red); + this.y.forceRed(this.curve.red); + } + if (!this.x.red) this.x = this.x.toRed(this.curve.red); + if (!this.y.red) this.y = this.y.toRed(this.curve.red); + this.inf = false; + } + } + inherits(Point, Base.BasePoint); - var g = 0; + ShortCurve.prototype.point = function point(x, y, isRed) { + return new Point(this, x, y, isRed); + }; - while (x.isEven() && y.isEven()) { - x.ishrn(1); - y.ishrn(1); - ++g; - } + ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) { + return Point.fromJSON(this, obj, red); + }; - var yp = y.clone(); - var xp = x.clone(); + Point.prototype._getBeta = function _getBeta() { + if (!this.curve.endo) return; - while (x.cmpn(0) !== 0) { - while (x.isEven()) { - x.ishrn(1); - if (A.isEven() && B.isEven()) { - A.ishrn(1); - B.ishrn(1); - } else { - A.iadd(yp).ishrn(1); - B.isub(xp).ishrn(1); - } - } + var pre = this.precomputed; + if (pre && pre.beta) return pre.beta; - while (y.isEven()) { - y.ishrn(1); - if (C.isEven() && D.isEven()) { - C.ishrn(1); - D.ishrn(1); - } else { - C.iadd(yp).ishrn(1); - D.isub(xp).ishrn(1); - } - } + var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y); + if (pre) { + var curve = this.curve; + var endoMul = function(p) { + return curve.point(p.x.redMul(curve.endo.beta), p.y); + }; + pre.beta = beta; + beta.precomputed = { + beta: null, + naf: pre.naf && { + wnd: pre.naf.wnd, + points: pre.naf.points.map(endoMul), + }, + doubles: pre.doubles && { + step: pre.doubles.step, + points: pre.doubles.points.map(endoMul), + }, + }; + } + return beta; + }; - if (x.cmp(y) >= 0) { - x.isub(y); - A.isub(C); - B.isub(D); - } else { - y.isub(x); - C.isub(A); - D.isub(B); - } - } + Point.prototype.toJSON = function toJSON() { + if (!this.precomputed) return [this.x, this.y]; + + return [ + this.x, + this.y, + this.precomputed && { + doubles: this.precomputed.doubles && { + step: this.precomputed.doubles.step, + points: this.precomputed.doubles.points.slice(1), + }, + naf: this.precomputed.naf && { + wnd: this.precomputed.naf.wnd, + points: this.precomputed.naf.points.slice(1), + }, + }, + ]; + }; - return { - a: C, - b: D, - gcd: y.ishln(g) - }; -}; - -// This is reduced incarnation of the binary EEA -// above, designated to invert members of the -// _prime_ fields F(p) at a maximal speed -BN.prototype._invmp = function _invmp(p) { - assert(!p.sign); - assert(p.cmpn(0) !== 0); - - var a = this; - var b = p.clone(); - - if (a.sign) - a = a.mod(p); - else - a = a.clone(); - - var x1 = new BN(1); - var x2 = new BN(0); - - var delta = b.clone(); - - while (a.cmpn(1) > 0 && b.cmpn(1) > 0) { - while (a.isEven()) { - a.ishrn(1); - if (x1.isEven()) - x1.ishrn(1); - else - x1.iadd(delta).ishrn(1); - } - while (b.isEven()) { - b.ishrn(1); - if (x2.isEven()) - x2.ishrn(1); - else - x2.iadd(delta).ishrn(1); - } - if (a.cmp(b) >= 0) { - a.isub(b); - x1.isub(x2); - } else { - b.isub(a); - x2.isub(x1); - } - } - if (a.cmpn(1) === 0) - return x1; - else - return x2; -}; - -BN.prototype.gcd = function gcd(num) { - if (this.cmpn(0) === 0) - return num.clone(); - if (num.cmpn(0) === 0) - return this.clone(); - - var a = this.clone(); - var b = num.clone(); - a.sign = false; - b.sign = false; - - // Remove common factor of two - for (var shift = 0; a.isEven() && b.isEven(); shift++) { - a.ishrn(1); - b.ishrn(1); - } + Point.fromJSON = function fromJSON(curve, obj, red) { + if (typeof obj === 'string') obj = JSON.parse(obj); + var res = curve.point(obj[0], obj[1], red); + if (!obj[2]) return res; - do { - while (a.isEven()) - a.ishrn(1); - while (b.isEven()) - b.ishrn(1); - - var r = a.cmp(b); - if (r < 0) { - // Swap `a` and `b` to make `a` always bigger than `b` - var t = a; - a = b; - b = t; - } else if (r === 0 || b.cmpn(1) === 0) { - break; - } + function obj2point(obj) { + return curve.point(obj[0], obj[1], red); + } - a.isub(b); - } while (true); - - return b.ishln(shift); -}; - -// Invert number in the field F(num) -BN.prototype.invm = function invm(num) { - return this.egcd(num).a.mod(num); -}; - -BN.prototype.isEven = function isEven() { - return (this.words[0] & 1) === 0; -}; - -BN.prototype.isOdd = function isOdd() { - return (this.words[0] & 1) === 1; -}; - -// And first word and num -BN.prototype.andln = function andln(num) { - return this.words[0] & num; -}; - -// Increment at the bit position in-line -BN.prototype.bincn = function bincn(bit) { - assert(typeof bit === 'number'); - var r = bit % 26; - var s = (bit - r) / 26; - var q = 1 << r; - - // Fast case: bit is much higher than all existing words - if (this.length <= s) { - for (var i = this.length; i < s + 1; i++) - this.words[i] = 0; - this.words[s] |= q; - this.length = s + 1; - return this; - } + var pre = obj[2]; + res.precomputed = { + beta: null, + doubles: pre.doubles && { + step: pre.doubles.step, + points: [res].concat(pre.doubles.points.map(obj2point)), + }, + naf: pre.naf && { + wnd: pre.naf.wnd, + points: [res].concat(pre.naf.points.map(obj2point)), + }, + }; + return res; + }; - // Add bit and propagate, if needed - var carry = q; - for (var i = s; carry !== 0 && i < this.length; i++) { - var w = this.words[i]; - w += carry; - carry = w >>> 26; - w &= 0x3ffffff; - this.words[i] = w; - } - if (carry !== 0) { - this.words[i] = carry; - this.length++; - } - return this; -}; - -BN.prototype.cmpn = function cmpn(num) { - var sign = num < 0; - if (sign) - num = -num; - - if (this.sign && !sign) - return -1; - else if (!this.sign && sign) - return 1; - - num &= 0x3ffffff; - this.strip(); - - var res; - if (this.length > 1) { - res = 1; - } else { - var w = this.words[0]; - res = w === num ? 0 : w < num ? -1 : 1; - } - if (this.sign) - res = -res; - return res; -}; - -// Compare two numbers and return: -// 1 - if `this` > `num` -// 0 - if `this` == `num` -// -1 - if `this` < `num` -BN.prototype.cmp = function cmp(num) { - if (this.sign && !num.sign) - return -1; - else if (!this.sign && num.sign) - return 1; - - var res = this.ucmp(num); - if (this.sign) - return -res; - else - return res; -}; - -// Unsigned comparison -BN.prototype.ucmp = function ucmp(num) { - // At this point both numbers have the same sign - if (this.length > num.length) - return 1; - else if (this.length < num.length) - return -1; - - var res = 0; - for (var i = this.length - 1; i >= 0; i--) { - var a = this.words[i]; - var b = num.words[i]; - - if (a === b) - continue; - if (a < b) - res = -1; - else if (a > b) - res = 1; - break; - } - return res; -}; - -// -// A reduce context, could be using montgomery or something better, depending -// on the `m` itself. -// -BN.red = function red(num) { - return new Red(num); -}; - -BN.prototype.toRed = function toRed(ctx) { - assert(!this.red, 'Already a number in reduction context'); - assert(!this.sign, 'red works only with positives'); - return ctx.convertTo(this)._forceRed(ctx); -}; - -BN.prototype.fromRed = function fromRed() { - assert(this.red, 'fromRed works only with numbers in reduction context'); - return this.red.convertFrom(this); -}; - -BN.prototype._forceRed = function _forceRed(ctx) { - this.red = ctx; - return this; -}; - -BN.prototype.forceRed = function forceRed(ctx) { - assert(!this.red, 'Already a number in reduction context'); - return this._forceRed(ctx); -}; - -BN.prototype.redAdd = function redAdd(num) { - assert(this.red, 'redAdd works only with red numbers'); - return this.red.add(this, num); -}; - -BN.prototype.redIAdd = function redIAdd(num) { - assert(this.red, 'redIAdd works only with red numbers'); - return this.red.iadd(this, num); -}; - -BN.prototype.redSub = function redSub(num) { - assert(this.red, 'redSub works only with red numbers'); - return this.red.sub(this, num); -}; - -BN.prototype.redISub = function redISub(num) { - assert(this.red, 'redISub works only with red numbers'); - return this.red.isub(this, num); -}; - -BN.prototype.redShl = function redShl(num) { - assert(this.red, 'redShl works only with red numbers'); - return this.red.shl(this, num); -}; - -BN.prototype.redMul = function redMul(num) { - assert(this.red, 'redMul works only with red numbers'); - this.red._verify2(this, num); - return this.red.mul(this, num); -}; - -BN.prototype.redIMul = function redIMul(num) { - assert(this.red, 'redMul works only with red numbers'); - this.red._verify2(this, num); - return this.red.imul(this, num); -}; - -BN.prototype.redSqr = function redSqr() { - assert(this.red, 'redSqr works only with red numbers'); - this.red._verify1(this); - return this.red.sqr(this); -}; - -BN.prototype.redISqr = function redISqr() { - assert(this.red, 'redISqr works only with red numbers'); - this.red._verify1(this); - return this.red.isqr(this); -}; - -// Square root over p -BN.prototype.redSqrt = function redSqrt() { - assert(this.red, 'redSqrt works only with red numbers'); - this.red._verify1(this); - return this.red.sqrt(this); -}; - -BN.prototype.redInvm = function redInvm() { - assert(this.red, 'redInvm works only with red numbers'); - this.red._verify1(this); - return this.red.invm(this); -}; - -// Return negative clone of `this` % `red modulo` -BN.prototype.redNeg = function redNeg() { - assert(this.red, 'redNeg works only with red numbers'); - this.red._verify1(this); - return this.red.neg(this); -}; - -BN.prototype.redPow = function redPow(num) { - assert(this.red && !num.red, 'redPow(normalNum)'); - this.red._verify1(this); - return this.red.pow(this, num); -}; - -// Prime numbers with efficient reduction -var primes = { - k256: null, - p224: null, - p192: null, - p25519: null -}; - -// Pseudo-Mersenne prime -function MPrime(name, p) { - // P = 2 ^ N - K - this.name = name; - this.p = new BN(p, 16); - this.n = this.p.bitLength(); - this.k = new BN(1).ishln(this.n).isub(this.p); - - this.tmp = this._tmp(); -} + Point.prototype.inspect = function inspect() { + if (this.isInfinity()) return ''; + return ''; + }; -MPrime.prototype._tmp = function _tmp() { - var tmp = new BN(null); - tmp.words = new Array(Math.ceil(this.n / 13)); - return tmp; -}; - -MPrime.prototype.ireduce = function ireduce(num) { - // Assumes that `num` is less than `P^2` - // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P) - var r = num; - var rlen; - - do { - this.split(r, this.tmp); - r = this.imulK(r); - r = r.iadd(this.tmp); - rlen = r.bitLength(); - } while (rlen > this.n); - - var cmp = rlen < this.n ? -1 : r.ucmp(this.p); - if (cmp === 0) { - r.words[0] = 0; - r.length = 1; - } else if (cmp > 0) { - r.isub(this.p); - } else { - r.strip(); - } + Point.prototype.isInfinity = function isInfinity() { + return this.inf; + }; - return r; -}; + Point.prototype.add = function add(p) { + // O + P = P + if (this.inf) return p; -MPrime.prototype.split = function split(input, out) { - input.ishrn(this.n, 0, out); -}; + // P + O = P + if (p.inf) return this; -MPrime.prototype.imulK = function imulK(num) { - return num.imul(this.k); -}; + // P + P = 2P + if (this.eq(p)) return this.dbl(); -function K256() { - MPrime.call( - this, - 'k256', - 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f'); -} -inherits(K256, MPrime); + // P + (-P) = O + if (this.neg().eq(p)) return this.curve.point(null, null); -K256.prototype.split = function split(input, output) { - // 256 = 9 * 26 + 22 - var mask = 0x3fffff; + // P + Q = O + if (this.x.cmp(p.x) === 0) return this.curve.point(null, null); - var outLen = Math.min(input.length, 9); - for (var i = 0; i < outLen; i++) - output.words[i] = input.words[i]; - output.length = outLen; + var c = this.y.redSub(p.y); + if (c.cmpn(0) !== 0) c = c.redMul(this.x.redSub(p.x).redInvm()); + var nx = c + .redSqr() + .redISub(this.x) + .redISub(p.x); + var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); + return this.curve.point(nx, ny); + }; - if (input.length <= 9) { - input.words[0] = 0; - input.length = 1; - return; - } + Point.prototype.dbl = function dbl() { + if (this.inf) return this; - // Shift by 9 limbs - var prev = input.words[9]; - output.words[output.length++] = prev & mask; + // 2P = O + var ys1 = this.y.redAdd(this.y); + if (ys1.cmpn(0) === 0) return this.curve.point(null, null); - for (var i = 10; i < input.length; i++) { - var next = input.words[i]; - input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22); - prev = next; - } - input.words[i - 10] = prev >>> 22; - input.length -= 9; -}; - -K256.prototype.imulK = function imulK(num) { - // K = 0x1000003d1 = [ 0x40, 0x3d1 ] - num.words[num.length] = 0; - num.words[num.length + 1] = 0; - num.length += 2; - - // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390 - var hi; - var lo = 0; - for (var i = 0; i < num.length; i++) { - var w = num.words[i]; - hi = w * 0x40; - lo += w * 0x3d1; - hi += (lo / 0x4000000) | 0; - lo &= 0x3ffffff; - - num.words[i] = lo; - - lo = hi; - } + var a = this.curve.a; - // Fast length reduction - if (num.words[num.length - 1] === 0) { - num.length--; - if (num.words[num.length - 1] === 0) - num.length--; - } - return num; -}; - -function P224() { - MPrime.call( - this, - 'p224', - 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001'); -} -inherits(P224, MPrime); + var x2 = this.x.redSqr(); + var dyinv = ys1.redInvm(); + var c = x2 + .redAdd(x2) + .redIAdd(x2) + .redIAdd(a) + .redMul(dyinv); -function P192() { - MPrime.call( - this, - 'p192', - 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff'); -} -inherits(P192, MPrime); - -function P25519() { - // 2 ^ 255 - 19 - MPrime.call( - this, - '25519', - '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed'); -} -inherits(P25519, MPrime); - -P25519.prototype.imulK = function imulK(num) { - // K = 0x13 - var carry = 0; - for (var i = 0; i < num.length; i++) { - var hi = num.words[i] * 0x13 + carry; - var lo = hi & 0x3ffffff; - hi >>>= 26; - - num.words[i] = lo; - carry = hi; - } - if (carry !== 0) - num.words[num.length++] = carry; - return num; -}; - -// Exported mostly for testing purposes, use plain name instead -BN._prime = function prime(name) { - // Cached version of prime - if (primes[name]) - return primes[name]; - - var prime; - if (name === 'k256') - prime = new K256(); - else if (name === 'p224') - prime = new P224(); - else if (name === 'p192') - prime = new P192(); - else if (name === 'p25519') - prime = new P25519(); - else - throw new Error('Unknown prime ' + name); - primes[name] = prime; - - return prime; -}; - -// -// Base reduction engine -// -function Red(m) { - if (typeof m === 'string') { - var prime = BN._prime(m); - this.m = prime.p; - this.prime = prime; - } else { - this.m = m; - this.prime = null; - } -} + var nx = c.redSqr().redISub(this.x.redAdd(this.x)); + var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); + return this.curve.point(nx, ny); + }; -Red.prototype._verify1 = function _verify1(a) { - assert(!a.sign, 'red works only with positives'); - assert(a.red, 'red works only with red numbers'); -}; - -Red.prototype._verify2 = function _verify2(a, b) { - assert(!a.sign && !b.sign, 'red works only with positives'); - assert(a.red && a.red === b.red, - 'red works only with red numbers'); -}; - -Red.prototype.imod = function imod(a) { - if (this.prime) - return this.prime.ireduce(a)._forceRed(this); - return a.mod(this.m)._forceRed(this); -}; - -Red.prototype.neg = function neg(a) { - var r = a.clone(); - r.sign = !r.sign; - return r.iadd(this.m)._forceRed(this); -}; - -Red.prototype.add = function add(a, b) { - this._verify2(a, b); - - var res = a.add(b); - if (res.cmp(this.m) >= 0) - res.isub(this.m); - return res._forceRed(this); -}; - -Red.prototype.iadd = function iadd(a, b) { - this._verify2(a, b); - - var res = a.iadd(b); - if (res.cmp(this.m) >= 0) - res.isub(this.m); - return res; -}; - -Red.prototype.sub = function sub(a, b) { - this._verify2(a, b); - - var res = a.sub(b); - if (res.cmpn(0) < 0) - res.iadd(this.m); - return res._forceRed(this); -}; - -Red.prototype.isub = function isub(a, b) { - this._verify2(a, b); - - var res = a.isub(b); - if (res.cmpn(0) < 0) - res.iadd(this.m); - return res; -}; - -Red.prototype.shl = function shl(a, num) { - this._verify1(a); - return this.imod(a.shln(num)); -}; - -Red.prototype.imul = function imul(a, b) { - this._verify2(a, b); - return this.imod(a.imul(b)); -}; - -Red.prototype.mul = function mul(a, b) { - this._verify2(a, b); - return this.imod(a.mul(b)); -}; - -Red.prototype.isqr = function isqr(a) { - return this.imul(a, a); -}; - -Red.prototype.sqr = function sqr(a) { - return this.mul(a, a); -}; - -Red.prototype.sqrt = function sqrt(a) { - if (a.cmpn(0) === 0) - return a.clone(); - - var mod3 = this.m.andln(3); - assert(mod3 % 2 === 1); - - // Fast case - if (mod3 === 3) { - var pow = this.m.add(new BN(1)).ishrn(2); - var r = this.pow(a, pow); - return r; - } + Point.prototype.getX = function getX() { + return this.x.fromRed(); + }; - // Tonelli-Shanks algorithm (Totally unoptimized and slow) - // - // Find Q and S, that Q * 2 ^ S = (P - 1) - var q = this.m.subn(1); - var s = 0; - while (q.cmpn(0) !== 0 && q.andln(1) === 0) { - s++; - q.ishrn(1); - } - assert(q.cmpn(0) !== 0); - - var one = new BN(1).toRed(this); - var nOne = one.redNeg(); - - // Find quadratic non-residue - // NOTE: Max is such because of generalized Riemann hypothesis. - var lpow = this.m.subn(1).ishrn(1); - var z = this.m.bitLength(); - z = new BN(2 * z * z).toRed(this); - while (this.pow(z, lpow).cmp(nOne) !== 0) - z.redIAdd(nOne); - - var c = this.pow(z, q); - var r = this.pow(a, q.addn(1).ishrn(1)); - var t = this.pow(a, q); - var m = s; - while (t.cmp(one) !== 0) { - var tmp = t; - for (var i = 0; tmp.cmp(one) !== 0; i++) - tmp = tmp.redSqr(); - assert(i < m); - var b = this.pow(c, new BN(1).ishln(m - i - 1)); - - r = r.redMul(b); - c = b.redSqr(); - t = t.redMul(c); - m = i; - } + Point.prototype.getY = function getY() { + return this.y.fromRed(); + }; - return r; -}; + Point.prototype.mul = function mul(k) { + k = new BN(k, 16); -Red.prototype.invm = function invm(a) { - var inv = a._invmp(this.m); - if (inv.sign) { - inv.sign = false; - return this.imod(inv).redNeg(); - } else { - return this.imod(inv); - } -}; + if (this._hasDoubles(k)) return this.curve._fixedNafMul(this, k); + else if (this.curve.endo) return this.curve._endoWnafMulAdd([this], [k]); + else return this.curve._wnafMul(this, k); + }; -Red.prototype.pow = function pow(a, num) { - var w = []; + Point.prototype.mulAdd = function mulAdd(k1, p2, k2) { + var points = [this, p2]; + var coeffs = [k1, k2]; + if (this.curve.endo) return this.curve._endoWnafMulAdd(points, coeffs); + else return this.curve._wnafMulAdd(1, points, coeffs, 2); + }; - if (num.cmpn(0) === 0) - return new BN(1); + Point.prototype.jmulAdd = function jmulAdd(k1, p2, k2) { + var points = [this, p2]; + var coeffs = [k1, k2]; + if (this.curve.endo) return this.curve._endoWnafMulAdd(points, coeffs, true); + else return this.curve._wnafMulAdd(1, points, coeffs, 2, true); + }; - var q = num.clone(); + Point.prototype.eq = function eq(p) { + return this === p || (this.inf === p.inf && (this.inf || (this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0))); + }; - while (q.cmpn(0) !== 0) { - w.push(q.andln(1)); - q.ishrn(1); - } + Point.prototype.neg = function neg(_precompute) { + if (this.inf) return this; - // Skip leading zeroes - var res = a; - for (var i = 0; i < w.length; i++, res = this.sqr(res)) - if (w[i] !== 0) - break; - - if (++i < w.length) { - for (var q = this.sqr(res); i < w.length; i++, q = this.sqr(q)) { - if (w[i] === 0) - continue; - res = this.mul(res, q); - } - } + var res = this.curve.point(this.x, this.y.redNeg()); + if (_precompute && this.precomputed) { + var pre = this.precomputed; + var negate = function(p) { + return p.neg(); + }; + res.precomputed = { + naf: pre.naf && { + wnd: pre.naf.wnd, + points: pre.naf.points.map(negate), + }, + doubles: pre.doubles && { + step: pre.doubles.step, + points: pre.doubles.points.map(negate), + }, + }; + } + return res; + }; - return res; -}; + Point.prototype.toJ = function toJ() { + if (this.inf) return this.curve.jpoint(null, null, null); -Red.prototype.convertTo = function convertTo(num) { - return num.clone(); -}; + var res = this.curve.jpoint(this.x, this.y, this.curve.one); + return res; + }; -Red.prototype.convertFrom = function convertFrom(num) { - var res = num.clone(); - res.red = null; - return res; -}; + function JPoint(curve, x, y, z) { + Base.BasePoint.call(this, curve, 'jacobian'); + if (x === null && y === null && z === null) { + this.x = this.curve.one; + this.y = this.curve.one; + this.z = new BN(0); + } else { + this.x = new BN(x, 16); + this.y = new BN(y, 16); + this.z = new BN(z, 16); + } + if (!this.x.red) this.x = this.x.toRed(this.curve.red); + if (!this.y.red) this.y = this.y.toRed(this.curve.red); + if (!this.z.red) this.z = this.z.toRed(this.curve.red); -// -// Montgomery method engine -// + this.zOne = this.z === this.curve.one; + } + inherits(JPoint, Base.BasePoint); -BN.mont = function mont(num) { - return new Mont(num); -}; + ShortCurve.prototype.jpoint = function jpoint(x, y, z) { + return new JPoint(this, x, y, z); + }; -function Mont(m) { - Red.call(this, m); + JPoint.prototype.toP = function toP() { + if (this.isInfinity()) return this.curve.point(null, null); - this.shift = this.m.bitLength(); - if (this.shift % 26 !== 0) - this.shift += 26 - (this.shift % 26); - this.r = new BN(1).ishln(this.shift); - this.r2 = this.imod(this.r.sqr()); - this.rinv = this.r._invmp(this.m); + var zinv = this.z.redInvm(); + var zinv2 = zinv.redSqr(); + var ax = this.x.redMul(zinv2); + var ay = this.y.redMul(zinv2).redMul(zinv); - this.minv = this.rinv.mul(this.r).isubn(1).div(this.m); - this.minv.sign = true; - this.minv = this.minv.mod(this.r); -} -inherits(Mont, Red); - -Mont.prototype.convertTo = function convertTo(num) { - return this.imod(num.shln(this.shift)); -}; - -Mont.prototype.convertFrom = function convertFrom(num) { - var r = this.imod(num.mul(this.rinv)); - r.red = null; - return r; -}; - -Mont.prototype.imul = function imul(a, b) { - if (a.cmpn(0) === 0 || b.cmpn(0) === 0) { - a.words[0] = 0; - a.length = 1; - return a; - } + return this.curve.point(ax, ay); + }; - var t = a.imul(b); - var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); - var u = t.isub(c).ishrn(this.shift); - var res = u; - if (u.cmp(this.m) >= 0) - res = u.isub(this.m); - else if (u.cmpn(0) < 0) - res = u.iadd(this.m); - - return res._forceRed(this); -}; - -Mont.prototype.mul = function mul(a, b) { - if (a.cmpn(0) === 0 || b.cmpn(0) === 0) - return new BN(0)._forceRed(this); - - var t = a.mul(b); - var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); - var u = t.isub(c).ishrn(this.shift); - var res = u; - if (u.cmp(this.m) >= 0) - res = u.isub(this.m); - else if (u.cmpn(0) < 0) - res = u.iadd(this.m); - - return res._forceRed(this); -}; - -Mont.prototype.invm = function invm(a) { - // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R - var res = this.imod(a._invmp(this.m).mul(this.r2)); - return res._forceRed(this); -}; - -})(typeof module === 'undefined' || module, this); - -},{}],63:[function(require,module,exports){ -var r; - -module.exports = function rand(len) { - if (!r) - r = new Rand(null); - - return r.generate(len); -}; - -function Rand(rand) { - this.rand = rand; -} -module.exports.Rand = Rand; - -Rand.prototype.generate = function generate(len) { - return this._rand(len); -}; - -// Emulate crypto API using randy -Rand.prototype._rand = function _rand(n) { - if (this.rand.getBytes) - return this.rand.getBytes(n); - - var res = new Uint8Array(n); - for (var i = 0; i < res.length; i++) - res[i] = this.rand.getByte(); - return res; -}; - -if (typeof self === 'object') { - if (self.crypto && self.crypto.getRandomValues) { - // Modern browsers - Rand.prototype._rand = function _rand(n) { - var arr = new Uint8Array(n); - self.crypto.getRandomValues(arr); - return arr; - }; - } else if (self.msCrypto && self.msCrypto.getRandomValues) { - // IE - Rand.prototype._rand = function _rand(n) { - var arr = new Uint8Array(n); - self.msCrypto.getRandomValues(arr); - return arr; - }; - - // Safari's WebWorkers do not have `crypto` - } else if (typeof window === 'object') { - // Old junk - Rand.prototype._rand = function() { - throw new Error('Not implemented yet'); - }; - } -} else { - // Node.js or Web worker with no crypto support - try { - var crypto = require('crypto'); - if (typeof crypto.randomBytes !== 'function') - throw new Error('Not supported'); - - Rand.prototype._rand = function _rand(n) { - return crypto.randomBytes(n); - }; - } catch (e) { - } -} + JPoint.prototype.neg = function neg() { + return this.curve.jpoint(this.x, this.y.redNeg(), this.z); + }; -},{"crypto":64}],64:[function(require,module,exports){ + JPoint.prototype.add = function add(p) { + // O + P = P + if (this.isInfinity()) return p; + + // P + O = P + if (p.isInfinity()) return this; + + // 12M + 4S + 7A + var pz2 = p.z.redSqr(); + var z2 = this.z.redSqr(); + var u1 = this.x.redMul(pz2); + var u2 = p.x.redMul(z2); + var s1 = this.y.redMul(pz2.redMul(p.z)); + var s2 = p.y.redMul(z2.redMul(this.z)); + + var h = u1.redSub(u2); + var r = s1.redSub(s2); + if (h.cmpn(0) === 0) { + if (r.cmpn(0) !== 0) return this.curve.jpoint(null, null, null); + else return this.dbl(); + } -},{}],65:[function(require,module,exports){ -// based on the aes implimentation in triple sec -// https://github.com/keybase/triplesec -// which is in turn based on the one from crypto-js -// https://code.google.com/p/crypto-js/ + var h2 = h.redSqr(); + var h3 = h2.redMul(h); + var v = u1.redMul(h2); -var Buffer = require('safe-buffer').Buffer + var nx = r + .redSqr() + .redIAdd(h3) + .redISub(v) + .redISub(v); + var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); + var nz = this.z.redMul(p.z).redMul(h); -function asUInt32Array (buf) { - if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf) + return this.curve.jpoint(nx, ny, nz); + }; - var len = (buf.length / 4) | 0 - var out = new Array(len) + JPoint.prototype.mixedAdd = function mixedAdd(p) { + // O + P = P + if (this.isInfinity()) return p.toJ(); + + // P + O = P + if (p.isInfinity()) return this; + + // 8M + 3S + 7A + var z2 = this.z.redSqr(); + var u1 = this.x; + var u2 = p.x.redMul(z2); + var s1 = this.y; + var s2 = p.y.redMul(z2).redMul(this.z); + + var h = u1.redSub(u2); + var r = s1.redSub(s2); + if (h.cmpn(0) === 0) { + if (r.cmpn(0) !== 0) return this.curve.jpoint(null, null, null); + else return this.dbl(); + } - for (var i = 0; i < len; i++) { - out[i] = buf.readUInt32BE(i * 4) - } + var h2 = h.redSqr(); + var h3 = h2.redMul(h); + var v = u1.redMul(h2); - return out -} + var nx = r + .redSqr() + .redIAdd(h3) + .redISub(v) + .redISub(v); + var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); + var nz = this.z.redMul(h); -function scrubVec (v) { - for (var i = 0; i < v.length; v++) { - v[i] = 0 - } -} + return this.curve.jpoint(nx, ny, nz); + }; -function cryptBlock (M, keySchedule, SUB_MIX, SBOX, nRounds) { - var SUB_MIX0 = SUB_MIX[0] - var SUB_MIX1 = SUB_MIX[1] - var SUB_MIX2 = SUB_MIX[2] - var SUB_MIX3 = SUB_MIX[3] - - var s0 = M[0] ^ keySchedule[0] - var s1 = M[1] ^ keySchedule[1] - var s2 = M[2] ^ keySchedule[2] - var s3 = M[3] ^ keySchedule[3] - var t0, t1, t2, t3 - var ksRow = 4 - - for (var round = 1; round < nRounds; round++) { - t0 = SUB_MIX0[s0 >>> 24] ^ SUB_MIX1[(s1 >>> 16) & 0xff] ^ SUB_MIX2[(s2 >>> 8) & 0xff] ^ SUB_MIX3[s3 & 0xff] ^ keySchedule[ksRow++] - t1 = SUB_MIX0[s1 >>> 24] ^ SUB_MIX1[(s2 >>> 16) & 0xff] ^ SUB_MIX2[(s3 >>> 8) & 0xff] ^ SUB_MIX3[s0 & 0xff] ^ keySchedule[ksRow++] - t2 = SUB_MIX0[s2 >>> 24] ^ SUB_MIX1[(s3 >>> 16) & 0xff] ^ SUB_MIX2[(s0 >>> 8) & 0xff] ^ SUB_MIX3[s1 & 0xff] ^ keySchedule[ksRow++] - t3 = SUB_MIX0[s3 >>> 24] ^ SUB_MIX1[(s0 >>> 16) & 0xff] ^ SUB_MIX2[(s1 >>> 8) & 0xff] ^ SUB_MIX3[s2 & 0xff] ^ keySchedule[ksRow++] - s0 = t0 - s1 = t1 - s2 = t2 - s3 = t3 - } + JPoint.prototype.dblp = function dblp(pow) { + if (pow === 0) return this; + if (this.isInfinity()) return this; + if (!pow) return this.dbl(); - t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++] - t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++] - t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++] - t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++] - t0 = t0 >>> 0 - t1 = t1 >>> 0 - t2 = t2 >>> 0 - t3 = t3 >>> 0 + if (this.curve.zeroA || this.curve.threeA) { + var r = this; + for (var i = 0; i < pow; i++) r = r.dbl(); + return r; + } - return [t0, t1, t2, t3] -} + // 1M + 2S + 1A + N * (4S + 5M + 8A) + // N = 1 => 6M + 6S + 9A + var a = this.curve.a; + var tinv = this.curve.tinv; + + var jx = this.x; + var jy = this.y; + var jz = this.z; + var jz4 = jz.redSqr().redSqr(); + + // Reuse results + var jyd = jy.redAdd(jy); + for (var i = 0; i < pow; i++) { + var jx2 = jx.redSqr(); + var jyd2 = jyd.redSqr(); + var jyd4 = jyd2.redSqr(); + var c = jx2 + .redAdd(jx2) + .redIAdd(jx2) + .redIAdd(a.redMul(jz4)); + + var t1 = jx.redMul(jyd2); + var nx = c.redSqr().redISub(t1.redAdd(t1)); + var t2 = t1.redISub(nx); + var dny = c.redMul(t2); + dny = dny.redIAdd(dny).redISub(jyd4); + var nz = jyd.redMul(jz); + if (i + 1 < pow) jz4 = jz4.redMul(jyd4); + + jx = nx; + jz = nz; + jyd = dny; + } -// AES constants -var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36] -var G = (function () { - // Compute double table - var d = new Array(256) - for (var j = 0; j < 256; j++) { - if (j < 128) { - d[j] = j << 1 - } else { - d[j] = (j << 1) ^ 0x11b - } - } + return this.curve.jpoint(jx, jyd.redMul(tinv), jz); + }; - var SBOX = [] - var INV_SBOX = [] - var SUB_MIX = [[], [], [], []] - var INV_SUB_MIX = [[], [], [], []] - - // Walk GF(2^8) - var x = 0 - var xi = 0 - for (var i = 0; i < 256; ++i) { - // Compute sbox - var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4) - sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63 - SBOX[x] = sx - INV_SBOX[sx] = x - - // Compute multiplication - var x2 = d[x] - var x4 = d[x2] - var x8 = d[x4] - - // Compute sub bytes, mix columns tables - var t = (d[sx] * 0x101) ^ (sx * 0x1010100) - SUB_MIX[0][x] = (t << 24) | (t >>> 8) - SUB_MIX[1][x] = (t << 16) | (t >>> 16) - SUB_MIX[2][x] = (t << 8) | (t >>> 24) - SUB_MIX[3][x] = t - - // Compute inv sub bytes, inv mix columns tables - t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100) - INV_SUB_MIX[0][sx] = (t << 24) | (t >>> 8) - INV_SUB_MIX[1][sx] = (t << 16) | (t >>> 16) - INV_SUB_MIX[2][sx] = (t << 8) | (t >>> 24) - INV_SUB_MIX[3][sx] = t - - if (x === 0) { - x = xi = 1 - } else { - x = x2 ^ d[d[d[x8 ^ x2]]] - xi ^= d[d[xi]] - } - } + JPoint.prototype.dbl = function dbl() { + if (this.isInfinity()) return this; - return { - SBOX: SBOX, - INV_SBOX: INV_SBOX, - SUB_MIX: SUB_MIX, - INV_SUB_MIX: INV_SUB_MIX - } -})() + if (this.curve.zeroA) return this._zeroDbl(); + else if (this.curve.threeA) return this._threeDbl(); + else return this._dbl(); + }; -function AES (key) { - this._key = asUInt32Array(key) - this._reset() -} + JPoint.prototype._zeroDbl = function _zeroDbl() { + var nx; + var ny; + var nz; + // Z = 1 + if (this.zOne) { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html + // #doubling-mdbl-2007-bl + // 1M + 5S + 14A + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // S = 2 * ((X1 + YY)^2 - XX - YYYY) + var s = this.x + .redAdd(yy) + .redSqr() + .redISub(xx) + .redISub(yyyy); + s = s.redIAdd(s); + // M = 3 * XX + a; a = 0 + var m = xx.redAdd(xx).redIAdd(xx); + // T = M ^ 2 - 2*S + var t = m + .redSqr() + .redISub(s) + .redISub(s); + + // 8 * YYYY + var yyyy8 = yyyy.redIAdd(yyyy); + yyyy8 = yyyy8.redIAdd(yyyy8); + yyyy8 = yyyy8.redIAdd(yyyy8); + + // X3 = T + nx = t; + // Y3 = M * (S - T) - 8 * YYYY + ny = m.redMul(s.redISub(t)).redISub(yyyy8); + // Z3 = 2*Y1 + nz = this.y.redAdd(this.y); + } else { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html + // #doubling-dbl-2009-l + // 2M + 5S + 13A + + // A = X1^2 + var a = this.x.redSqr(); + // B = Y1^2 + var b = this.y.redSqr(); + // C = B^2 + var c = b.redSqr(); + // D = 2 * ((X1 + B)^2 - A - C) + var d = this.x + .redAdd(b) + .redSqr() + .redISub(a) + .redISub(c); + d = d.redIAdd(d); + // E = 3 * A + var e = a.redAdd(a).redIAdd(a); + // F = E^2 + var f = e.redSqr(); + + // 8 * C + var c8 = c.redIAdd(c); + c8 = c8.redIAdd(c8); + c8 = c8.redIAdd(c8); + + // X3 = F - 2 * D + nx = f.redISub(d).redISub(d); + // Y3 = E * (D - X3) - 8 * C + ny = e.redMul(d.redISub(nx)).redISub(c8); + // Z3 = 2 * Y1 * Z1 + nz = this.y.redMul(this.z); + nz = nz.redIAdd(nz); + } -AES.blockSize = 4 * 4 -AES.keySize = 256 / 8 -AES.prototype.blockSize = AES.blockSize -AES.prototype.keySize = AES.keySize -AES.prototype._reset = function () { - var keyWords = this._key - var keySize = keyWords.length - var nRounds = keySize + 6 - var ksRows = (nRounds + 1) * 4 - - var keySchedule = [] - for (var k = 0; k < keySize; k++) { - keySchedule[k] = keyWords[k] - } + return this.curve.jpoint(nx, ny, nz); + }; - for (k = keySize; k < ksRows; k++) { - var t = keySchedule[k - 1] - - if (k % keySize === 0) { - t = (t << 8) | (t >>> 24) - t = - (G.SBOX[t >>> 24] << 24) | - (G.SBOX[(t >>> 16) & 0xff] << 16) | - (G.SBOX[(t >>> 8) & 0xff] << 8) | - (G.SBOX[t & 0xff]) - - t ^= RCON[(k / keySize) | 0] << 24 - } else if (keySize > 6 && k % keySize === 4) { - t = - (G.SBOX[t >>> 24] << 24) | - (G.SBOX[(t >>> 16) & 0xff] << 16) | - (G.SBOX[(t >>> 8) & 0xff] << 8) | - (G.SBOX[t & 0xff]) - } + JPoint.prototype._threeDbl = function _threeDbl() { + var nx; + var ny; + var nz; + // Z = 1 + if (this.zOne) { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html + // #doubling-mdbl-2007-bl + // 1M + 5S + 15A + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // S = 2 * ((X1 + YY)^2 - XX - YYYY) + var s = this.x + .redAdd(yy) + .redSqr() + .redISub(xx) + .redISub(yyyy); + s = s.redIAdd(s); + // M = 3 * XX + a + var m = xx + .redAdd(xx) + .redIAdd(xx) + .redIAdd(this.curve.a); + // T = M^2 - 2 * S + var t = m + .redSqr() + .redISub(s) + .redISub(s); + // X3 = T + nx = t; + // Y3 = M * (S - T) - 8 * YYYY + var yyyy8 = yyyy.redIAdd(yyyy); + yyyy8 = yyyy8.redIAdd(yyyy8); + yyyy8 = yyyy8.redIAdd(yyyy8); + ny = m.redMul(s.redISub(t)).redISub(yyyy8); + // Z3 = 2 * Y1 + nz = this.y.redAdd(this.y); + } else { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b + // 3M + 5S + + // delta = Z1^2 + var delta = this.z.redSqr(); + // gamma = Y1^2 + var gamma = this.y.redSqr(); + // beta = X1 * gamma + var beta = this.x.redMul(gamma); + // alpha = 3 * (X1 - delta) * (X1 + delta) + var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta)); + alpha = alpha.redAdd(alpha).redIAdd(alpha); + // X3 = alpha^2 - 8 * beta + var beta4 = beta.redIAdd(beta); + beta4 = beta4.redIAdd(beta4); + var beta8 = beta4.redAdd(beta4); + nx = alpha.redSqr().redISub(beta8); + // Z3 = (Y1 + Z1)^2 - gamma - delta + nz = this.y + .redAdd(this.z) + .redSqr() + .redISub(gamma) + .redISub(delta); + // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2 + var ggamma8 = gamma.redSqr(); + ggamma8 = ggamma8.redIAdd(ggamma8); + ggamma8 = ggamma8.redIAdd(ggamma8); + ggamma8 = ggamma8.redIAdd(ggamma8); + ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8); + } - keySchedule[k] = keySchedule[k - keySize] ^ t - } + return this.curve.jpoint(nx, ny, nz); + }; - var invKeySchedule = [] - for (var ik = 0; ik < ksRows; ik++) { - var ksR = ksRows - ik - var tt = keySchedule[ksR - (ik % 4 ? 0 : 4)] - - if (ik < 4 || ksR <= 4) { - invKeySchedule[ik] = tt - } else { - invKeySchedule[ik] = - G.INV_SUB_MIX[0][G.SBOX[tt >>> 24]] ^ - G.INV_SUB_MIX[1][G.SBOX[(tt >>> 16) & 0xff]] ^ - G.INV_SUB_MIX[2][G.SBOX[(tt >>> 8) & 0xff]] ^ - G.INV_SUB_MIX[3][G.SBOX[tt & 0xff]] - } - } + JPoint.prototype._dbl = function _dbl() { + var a = this.curve.a; + + // 4M + 6S + 10A + var jx = this.x; + var jy = this.y; + var jz = this.z; + var jz4 = jz.redSqr().redSqr(); + + var jx2 = jx.redSqr(); + var jy2 = jy.redSqr(); + + var c = jx2 + .redAdd(jx2) + .redIAdd(jx2) + .redIAdd(a.redMul(jz4)); + + var jxd4 = jx.redAdd(jx); + jxd4 = jxd4.redIAdd(jxd4); + var t1 = jxd4.redMul(jy2); + var nx = c.redSqr().redISub(t1.redAdd(t1)); + var t2 = t1.redISub(nx); + + var jyd8 = jy2.redSqr(); + jyd8 = jyd8.redIAdd(jyd8); + jyd8 = jyd8.redIAdd(jyd8); + jyd8 = jyd8.redIAdd(jyd8); + var ny = c.redMul(t2).redISub(jyd8); + var nz = jy.redAdd(jy).redMul(jz); + + return this.curve.jpoint(nx, ny, nz); + }; - this._nRounds = nRounds - this._keySchedule = keySchedule - this._invKeySchedule = invKeySchedule -} + JPoint.prototype.trpl = function trpl() { + if (!this.curve.zeroA) return this.dbl().add(this); + + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl + // 5M + 10S + ... + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // ZZ = Z1^2 + var zz = this.z.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // M = 3 * XX + a * ZZ2; a = 0 + var m = xx.redAdd(xx).redIAdd(xx); + // MM = M^2 + var mm = m.redSqr(); + // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM + var e = this.x + .redAdd(yy) + .redSqr() + .redISub(xx) + .redISub(yyyy); + e = e.redIAdd(e); + e = e.redAdd(e).redIAdd(e); + e = e.redISub(mm); + // EE = E^2 + var ee = e.redSqr(); + // T = 16*YYYY + var t = yyyy.redIAdd(yyyy); + t = t.redIAdd(t); + t = t.redIAdd(t); + t = t.redIAdd(t); + // U = (M + E)^2 - MM - EE - T + var u = m + .redIAdd(e) + .redSqr() + .redISub(mm) + .redISub(ee) + .redISub(t); + // X3 = 4 * (X1 * EE - 4 * YY * U) + var yyu4 = yy.redMul(u); + yyu4 = yyu4.redIAdd(yyu4); + yyu4 = yyu4.redIAdd(yyu4); + var nx = this.x.redMul(ee).redISub(yyu4); + nx = nx.redIAdd(nx); + nx = nx.redIAdd(nx); + // Y3 = 8 * Y1 * (U * (T - U) - E * EE) + var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee))); + ny = ny.redIAdd(ny); + ny = ny.redIAdd(ny); + ny = ny.redIAdd(ny); + // Z3 = (Z1 + E)^2 - ZZ - EE + var nz = this.z + .redAdd(e) + .redSqr() + .redISub(zz) + .redISub(ee); + + return this.curve.jpoint(nx, ny, nz); + }; -AES.prototype.encryptBlockRaw = function (M) { - M = asUInt32Array(M) - return cryptBlock(M, this._keySchedule, G.SUB_MIX, G.SBOX, this._nRounds) -} + JPoint.prototype.mul = function mul(k, kbase) { + k = new BN(k, kbase); -AES.prototype.encryptBlock = function (M) { - var out = this.encryptBlockRaw(M) - var buf = Buffer.allocUnsafe(16) - buf.writeUInt32BE(out[0], 0) - buf.writeUInt32BE(out[1], 4) - buf.writeUInt32BE(out[2], 8) - buf.writeUInt32BE(out[3], 12) - return buf -} + return this.curve._wnafMul(this, k); + }; -AES.prototype.decryptBlock = function (M) { - M = asUInt32Array(M) - - // swap - var m1 = M[1] - M[1] = M[3] - M[3] = m1 - - var out = cryptBlock(M, this._invKeySchedule, G.INV_SUB_MIX, G.INV_SBOX, this._nRounds) - var buf = Buffer.allocUnsafe(16) - buf.writeUInt32BE(out[0], 0) - buf.writeUInt32BE(out[3], 4) - buf.writeUInt32BE(out[2], 8) - buf.writeUInt32BE(out[1], 12) - return buf -} + JPoint.prototype.eq = function eq(p) { + if (p.type === 'affine') return this.eq(p.toJ()); -AES.prototype.scrub = function () { - scrubVec(this._keySchedule) - scrubVec(this._invKeySchedule) - scrubVec(this._key) -} + if (this === p) return true; -module.exports.AES = AES + // x1 * z2^2 == x2 * z1^2 + var z2 = this.z.redSqr(); + var pz2 = p.z.redSqr(); + if ( + this.x + .redMul(pz2) + .redISub(p.x.redMul(z2)) + .cmpn(0) !== 0 + ) + return false; -},{"safe-buffer":233}],66:[function(require,module,exports){ -var aes = require('./aes') -var Buffer = require('safe-buffer').Buffer -var Transform = require('cipher-base') -var inherits = require('inherits') -var GHASH = require('./ghash') -var xor = require('buffer-xor') + // y1 * z2^3 == y2 * z1^3 + var z3 = z2.redMul(this.z); + var pz3 = pz2.redMul(p.z); + return ( + this.y + .redMul(pz3) + .redISub(p.y.redMul(z3)) + .cmpn(0) === 0 + ); + }; -function xorTest (a, b) { - var out = 0 - if (a.length !== b.length) out++ + JPoint.prototype.eqXToP = function eqXToP(x) { + var zs = this.z.redSqr(); + var rx = x.toRed(this.curve.red).redMul(zs); + if (this.x.cmp(rx) === 0) return true; - var len = Math.min(a.length, b.length) - for (var i = 0; i < len; ++i) { - out += (a[i] ^ b[i]) - } + var xc = x.clone(); + var t = this.curve.redN.redMul(zs); + for (;;) { + xc.iadd(this.curve.n); + if (xc.cmp(this.curve.p) >= 0) return false; - return out -} + rx.redIAdd(t); + if (this.x.cmp(rx) === 0) return true; + } + return false; + }; -function StreamCipher (mode, key, iv, decrypt) { - Transform.call(this) - - this._finID = Buffer.concat([iv, Buffer.from([0, 0, 0, 1])]) - iv = Buffer.concat([iv, Buffer.from([0, 0, 0, 2])]) - - this._cipher = new aes.AES(key) - this._prev = Buffer.from(iv) - this._cache = Buffer.allocUnsafe(0) - this._secCache = Buffer.allocUnsafe(0) - this._decrypt = decrypt - this._alen = 0 - this._len = 0 - this._mode = mode - - var h = Buffer.alloc(4, 0) - this._ghash = new GHASH(this._cipher.encryptBlock(h)) - this._authTag = null - this._called = false -} + JPoint.prototype.inspect = function inspect() { + if (this.isInfinity()) return ''; + return ( + '' + ); + }; -inherits(StreamCipher, Transform) + JPoint.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.z.cmpn(0) === 0; + }; + }, + { '../../elliptic': 93, '../curve': 96, 'bn.js': 92, inherits: 184 }, + ], + 99: [ + function(require, module, exports) { + 'use strict'; -StreamCipher.prototype._update = function (chunk) { - if (!this._called && this._alen) { - var rump = 16 - (this._alen % 16) - if (rump < 16) { - rump = Buffer.alloc(rump, 0) - this._ghash.update(rump) - } - } + var curves = exports; - this._called = true - var out = this._mode.encrypt(this, chunk) - if (this._decrypt) { - this._ghash.update(chunk) - } else { - this._ghash.update(out) - } - this._len += chunk.length - return out -} + var hash = require('hash.js'); + var elliptic = require('../elliptic'); -StreamCipher.prototype._final = function () { - if (this._decrypt && !this._authTag) throw new Error('Unsupported state or unable to authenticate data') + var assert = elliptic.utils.assert; - var tag = xor(this._ghash.final(this._alen * 8, this._len * 8), this._cipher.encryptBlock(this._finID)) - if (this._decrypt && xorTest(tag, this._authTag)) throw new Error('Unsupported state or unable to authenticate data') + function PresetCurve(options) { + if (options.type === 'short') this.curve = new elliptic.curve.short(options); + else if (options.type === 'edwards') this.curve = new elliptic.curve.edwards(options); + else this.curve = new elliptic.curve.mont(options); + this.g = this.curve.g; + this.n = this.curve.n; + this.hash = options.hash; - this._authTag = tag - this._cipher.scrub() -} + assert(this.g.validate(), 'Invalid curve'); + assert(this.g.mul(this.n).isInfinity(), 'Invalid curve, G*N != O'); + } + curves.PresetCurve = PresetCurve; + + function defineCurve(name, options) { + Object.defineProperty(curves, name, { + configurable: true, + enumerable: true, + get: function() { + var curve = new PresetCurve(options); + Object.defineProperty(curves, name, { + configurable: true, + enumerable: true, + value: curve, + }); + return curve; + }, + }); + } -StreamCipher.prototype.getAuthTag = function getAuthTag () { - if (this._decrypt || !Buffer.isBuffer(this._authTag)) throw new Error('Attempting to get auth tag in unsupported state') + defineCurve('p192', { + type: 'short', + prime: 'p192', + p: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff', + a: 'ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc', + b: '64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1', + n: 'ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831', + hash: hash.sha256, + gRed: false, + g: [ + '188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012', + '07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811', + ], + }); - return this._authTag -} + defineCurve('p224', { + type: 'short', + prime: 'p224', + p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001', + a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe', + b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4', + n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d', + hash: hash.sha256, + gRed: false, + g: [ + 'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21', + 'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34', + ], + }); -StreamCipher.prototype.setAuthTag = function setAuthTag (tag) { - if (!this._decrypt) throw new Error('Attempting to set auth tag in unsupported state') + defineCurve('p256', { + type: 'short', + prime: null, + p: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff', + a: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc', + b: '5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b', + n: 'ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551', + hash: hash.sha256, + gRed: false, + g: [ + '6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296', + '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5', + ], + }); - this._authTag = tag -} + defineCurve('p384', { + type: 'short', + prime: null, + p: + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'fffffffe ffffffff 00000000 00000000 ffffffff', + a: + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'fffffffe ffffffff 00000000 00000000 fffffffc', + b: + 'b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 0314088f ' + + '5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef', + n: + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff c7634d81 ' + + 'f4372ddf 581a0db2 48b0a77a ecec196a ccc52973', + hash: hash.sha384, + gRed: false, + g: [ + 'aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 59f741e0 82542a38 ' + + '5502f25d bf55296c 3a545e38 72760ab7', + '3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c e9da3113 b5f0b8c0 ' + + '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f', + ], + }); -StreamCipher.prototype.setAAD = function setAAD (buf) { - if (this._called) throw new Error('Attempting to set AAD in unsupported state') + defineCurve('p521', { + type: 'short', + prime: null, + p: + '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff ffffffff ffffffff ffffffff', + a: + '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff ffffffff ffffffff fffffffc', + b: + '00000051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b ' + + '99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd ' + + '3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00', + n: + '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff fffffffa 51868783 bf2f966b 7fcc0148 ' + + 'f709a5d0 3bb5c9b8 899c47ae bb6fb71e 91386409', + hash: hash.sha512, + gRed: false, + g: [ + '000000c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 ' + + '053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 ' + + 'a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66', + '00000118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 ' + + '579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901 ' + + '3fad0761 353c7086 a272c240 88be9476 9fd16650', + ], + }); - this._ghash.update(buf) - this._alen += buf.length -} + defineCurve('curve25519', { + type: 'mont', + prime: 'p25519', + p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', + a: '76d06', + b: '1', + n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', + hash: hash.sha256, + gRed: false, + g: ['9'], + }); -module.exports = StreamCipher + defineCurve('ed25519', { + type: 'edwards', + prime: 'p25519', + p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', + a: '-1', + c: '1', + // -121665 * (121666^(-1)) (mod P) + d: '52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3', + n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', + hash: hash.sha256, + gRed: false, + g: [ + '216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a', + + // 4/5 + '6666666666666666666666666666666666666666666666666666666666666658', + ], + }); -},{"./aes":65,"./ghash":70,"buffer-xor":112,"cipher-base":114,"inherits":184,"safe-buffer":233}],67:[function(require,module,exports){ -var ciphers = require('./encrypter') -var deciphers = require('./decrypter') -var modes = require('./modes/list.json') + var pre; + try { + pre = require('./precomputed/secp256k1'); + } catch (e) { + pre = undefined; + } -function getCiphers () { - return Object.keys(modes) -} + defineCurve('secp256k1', { + type: 'short', + prime: 'k256', + p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f', + a: '0', + b: '7', + n: 'ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141', + h: '1', + hash: hash.sha256, + + // Precomputed endomorphism + beta: '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee', + lambda: '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72', + basis: [ + { + a: '3086d221a7d46bcde86c90e49284eb15', + b: '-e4437ed6010e88286f547fa90abfe4c3', + }, + { + a: '114ca50f7a8e2f3f657c1108d9d44cfd8', + b: '3086d221a7d46bcde86c90e49284eb15', + }, + ], + + gRed: false, + g: [ + '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', + '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', + pre, + ], + }); + }, + { '../elliptic': 93, './precomputed/secp256k1': 106, 'hash.js': 168 }, + ], + 100: [ + function(require, module, exports) { + 'use strict'; -exports.createCipher = exports.Cipher = ciphers.createCipher -exports.createCipheriv = exports.Cipheriv = ciphers.createCipheriv -exports.createDecipher = exports.Decipher = deciphers.createDecipher -exports.createDecipheriv = exports.Decipheriv = deciphers.createDecipheriv -exports.listCiphers = exports.getCiphers = getCiphers - -},{"./decrypter":68,"./encrypter":69,"./modes/list.json":78}],68:[function(require,module,exports){ -var AuthCipher = require('./authCipher') -var Buffer = require('safe-buffer').Buffer -var MODES = require('./modes') -var StreamCipher = require('./streamCipher') -var Transform = require('cipher-base') -var aes = require('./aes') -var ebtk = require('evp_bytestokey') -var inherits = require('inherits') - -function Decipher (mode, key, iv) { - Transform.call(this) - - this._cache = new Splitter() - this._last = void 0 - this._cipher = new aes.AES(key) - this._prev = Buffer.from(iv) - this._mode = mode - this._autopadding = true -} + var BN = require('bn.js'); + var HmacDRBG = require('hmac-drbg'); + var elliptic = require('../../elliptic'); + var utils = elliptic.utils; + var assert = utils.assert; -inherits(Decipher, Transform) + var KeyPair = require('./key'); + var Signature = require('./signature'); -Decipher.prototype._update = function (data) { - this._cache.add(data) - var chunk - var thing - var out = [] - while ((chunk = this._cache.get(this._autopadding))) { - thing = this._mode.decrypt(this, chunk) - out.push(thing) - } - return Buffer.concat(out) -} + function EC(options) { + if (!(this instanceof EC)) return new EC(options); -Decipher.prototype._final = function () { - var chunk = this._cache.flush() - if (this._autopadding) { - return unpad(this._mode.decrypt(this, chunk)) - } else if (chunk) { - throw new Error('data not multiple of block length') - } -} + // Shortcut `elliptic.ec(curve-name)` + if (typeof options === 'string') { + assert(elliptic.curves.hasOwnProperty(options), 'Unknown curve ' + options); -Decipher.prototype.setAutoPadding = function (setTo) { - this._autopadding = !!setTo - return this -} + options = elliptic.curves[options]; + } -function Splitter () { - this.cache = Buffer.allocUnsafe(0) -} + // Shortcut for `elliptic.ec(elliptic.curves.curveName)` + if (options instanceof elliptic.curves.PresetCurve) options = { curve: options }; -Splitter.prototype.add = function (data) { - this.cache = Buffer.concat([this.cache, data]) -} + this.curve = options.curve.curve; + this.n = this.curve.n; + this.nh = this.n.ushrn(1); + this.g = this.curve.g; -Splitter.prototype.get = function (autoPadding) { - var out - if (autoPadding) { - if (this.cache.length > 16) { - out = this.cache.slice(0, 16) - this.cache = this.cache.slice(16) - return out - } - } else { - if (this.cache.length >= 16) { - out = this.cache.slice(0, 16) - this.cache = this.cache.slice(16) - return out - } - } + // Point on curve + this.g = options.curve.g; + this.g.precompute(options.curve.n.bitLength() + 1); - return null -} + // Hash for function for DRBG + this.hash = options.hash || options.curve.hash; + } + module.exports = EC; -Splitter.prototype.flush = function () { - if (this.cache.length) return this.cache -} + EC.prototype.keyPair = function keyPair(options) { + return new KeyPair(this, options); + }; -function unpad (last) { - var padded = last[15] - var i = -1 - while (++i < padded) { - if (last[(i + (16 - padded))] !== padded) { - throw new Error('unable to decrypt data') - } - } - if (padded === 16) return + EC.prototype.keyFromPrivate = function keyFromPrivate(priv, enc) { + return KeyPair.fromPrivate(this, priv, enc); + }; - return last.slice(0, 16 - padded) -} + EC.prototype.keyFromPublic = function keyFromPublic(pub, enc) { + return KeyPair.fromPublic(this, pub, enc); + }; -function createDecipheriv (suite, password, iv) { - var config = MODES[suite.toLowerCase()] - if (!config) throw new TypeError('invalid suite type') + EC.prototype.genKeyPair = function genKeyPair(options) { + if (!options) options = {}; + + // Instantiate Hmac_DRBG + var drbg = new HmacDRBG({ + hash: this.hash, + pers: options.pers, + persEnc: options.persEnc || 'utf8', + entropy: options.entropy || elliptic.rand(this.hash.hmacStrength), + entropyEnc: (options.entropy && options.entropyEnc) || 'utf8', + nonce: this.n.toArray(), + }); - if (typeof iv === 'string') iv = Buffer.from(iv) - if (iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length) + var bytes = this.n.byteLength(); + var ns2 = this.n.sub(new BN(2)); + do { + var priv = new BN(drbg.generate(bytes)); + if (priv.cmp(ns2) > 0) continue; - if (typeof password === 'string') password = Buffer.from(password) - if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length) + priv.iaddn(1); + return this.keyFromPrivate(priv); + } while (true); + }; - if (config.type === 'stream') { - return new StreamCipher(config.module, password, iv, true) - } else if (config.type === 'auth') { - return new AuthCipher(config.module, password, iv, true) - } + EC.prototype._truncateToN = function truncateToN(msg, truncOnly) { + var delta = msg.byteLength() * 8 - this.n.bitLength(); + if (delta > 0) msg = msg.ushrn(delta); + if (!truncOnly && msg.cmp(this.n) >= 0) return msg.sub(this.n); + else return msg; + }; - return new Decipher(config.module, password, iv) -} + EC.prototype.sign = function sign(msg, key, enc, options) { + if (typeof enc === 'object') { + options = enc; + enc = null; + } + if (!options) options = {}; -function createDecipher (suite, password) { - var config = MODES[suite.toLowerCase()] - if (!config) throw new TypeError('invalid suite type') + key = this.keyFromPrivate(key, enc); + msg = this._truncateToN(new BN(msg, 16)); - var keys = ebtk(password, false, config.key, config.iv) - return createDecipheriv(suite, keys.key, keys.iv) -} + // Zero-extend key to provide enough entropy + var bytes = this.n.byteLength(); + var bkey = key.getPrivate().toArray('be', bytes); -exports.createDecipher = createDecipher -exports.createDecipheriv = createDecipheriv - -},{"./aes":65,"./authCipher":66,"./modes":77,"./streamCipher":80,"cipher-base":114,"evp_bytestokey":166,"inherits":184,"safe-buffer":233}],69:[function(require,module,exports){ -var MODES = require('./modes') -var AuthCipher = require('./authCipher') -var Buffer = require('safe-buffer').Buffer -var StreamCipher = require('./streamCipher') -var Transform = require('cipher-base') -var aes = require('./aes') -var ebtk = require('evp_bytestokey') -var inherits = require('inherits') - -function Cipher (mode, key, iv) { - Transform.call(this) - - this._cache = new Splitter() - this._cipher = new aes.AES(key) - this._prev = Buffer.from(iv) - this._mode = mode - this._autopadding = true -} + // Zero-extend nonce to have the same byte size as N + var nonce = msg.toArray('be', bytes); -inherits(Cipher, Transform) + // Instantiate Hmac_DRBG + var drbg = new HmacDRBG({ + hash: this.hash, + entropy: bkey, + nonce: nonce, + pers: options.pers, + persEnc: options.persEnc || 'utf8', + }); -Cipher.prototype._update = function (data) { - this._cache.add(data) - var chunk - var thing - var out = [] + // Number of bytes to generate + var ns1 = this.n.sub(new BN(1)); - while ((chunk = this._cache.get())) { - thing = this._mode.encrypt(this, chunk) - out.push(thing) - } + for (var iter = 0; true; iter++) { + var k = options.k ? options.k(iter) : new BN(drbg.generate(this.n.byteLength())); + k = this._truncateToN(k, true); + if (k.cmpn(1) <= 0 || k.cmp(ns1) >= 0) continue; - return Buffer.concat(out) -} + var kp = this.g.mul(k); + if (kp.isInfinity()) continue; -var PADDING = Buffer.alloc(16, 0x10) + var kpX = kp.getX(); + var r = kpX.umod(this.n); + if (r.cmpn(0) === 0) continue; -Cipher.prototype._final = function () { - var chunk = this._cache.flush() - if (this._autopadding) { - chunk = this._mode.encrypt(this, chunk) - this._cipher.scrub() - return chunk - } + var s = k.invm(this.n).mul(r.mul(key.getPrivate()).iadd(msg)); + s = s.umod(this.n); + if (s.cmpn(0) === 0) continue; - if (!chunk.equals(PADDING)) { - this._cipher.scrub() - throw new Error('data not multiple of block length') - } -} + var recoveryParam = (kp.getY().isOdd() ? 1 : 0) | (kpX.cmp(r) !== 0 ? 2 : 0); -Cipher.prototype.setAutoPadding = function (setTo) { - this._autopadding = !!setTo - return this -} + // Use complement of `s`, if it is > `n / 2` + if (options.canonical && s.cmp(this.nh) > 0) { + s = this.n.sub(s); + recoveryParam ^= 1; + } -function Splitter () { - this.cache = Buffer.allocUnsafe(0) -} + return new Signature({ r: r, s: s, recoveryParam: recoveryParam }); + } + }; -Splitter.prototype.add = function (data) { - this.cache = Buffer.concat([this.cache, data]) -} + EC.prototype.verify = function verify(msg, signature, key, enc) { + msg = this._truncateToN(new BN(msg, 16)); + key = this.keyFromPublic(key, enc); + signature = new Signature(signature, 'hex'); + + // Perform primitive values validation + var r = signature.r; + var s = signature.s; + if (r.cmpn(1) < 0 || r.cmp(this.n) >= 0) return false; + if (s.cmpn(1) < 0 || s.cmp(this.n) >= 0) return false; + + // Validate signature + var sinv = s.invm(this.n); + var u1 = sinv.mul(msg).umod(this.n); + var u2 = sinv.mul(r).umod(this.n); + + if (!this.curve._maxwellTrick) { + var p = this.g.mulAdd(u1, key.getPublic(), u2); + if (p.isInfinity()) return false; + + return ( + p + .getX() + .umod(this.n) + .cmp(r) === 0 + ); + } -Splitter.prototype.get = function () { - if (this.cache.length > 15) { - var out = this.cache.slice(0, 16) - this.cache = this.cache.slice(16) - return out - } - return null -} + // NOTE: Greg Maxwell's trick, inspired by: + // https://git.io/vad3K -Splitter.prototype.flush = function () { - var len = 16 - this.cache.length - var padBuff = Buffer.allocUnsafe(len) + var p = this.g.jmulAdd(u1, key.getPublic(), u2); + if (p.isInfinity()) return false; - var i = -1 - while (++i < len) { - padBuff.writeUInt8(len, i) - } + // Compare `p.x` of Jacobian point with `r`, + // this will do `p.x == r * p.z^2` instead of multiplying `p.x` by the + // inverse of `p.z^2` + return p.eqXToP(r); + }; - return Buffer.concat([this.cache, padBuff]) -} + EC.prototype.recoverPubKey = function(msg, signature, j, enc) { + assert((3 & j) === j, 'The recovery param is more than two bits'); + signature = new Signature(signature, enc); + + var n = this.n; + var e = new BN(msg); + var r = signature.r; + var s = signature.s; + + // A set LSB signifies that the y-coordinate is odd + var isYOdd = j & 1; + var isSecondKey = j >> 1; + if (r.cmp(this.curve.p.umod(this.curve.n)) >= 0 && isSecondKey) + throw new Error('Unable to find sencond key candinate'); + + // 1.1. Let x = r + jn. + if (isSecondKey) r = this.curve.pointFromX(r.add(this.curve.n), isYOdd); + else r = this.curve.pointFromX(r, isYOdd); + + var rInv = signature.r.invm(n); + var s1 = n + .sub(e) + .mul(rInv) + .umod(n); + var s2 = s.mul(rInv).umod(n); + + // 1.6.1 Compute Q = r^-1 (sR - eG) + // Q = r^-1 (sR + -eG) + return this.g.mulAdd(s1, r, s2); + }; -function createCipheriv (suite, password, iv) { - var config = MODES[suite.toLowerCase()] - if (!config) throw new TypeError('invalid suite type') + EC.prototype.getKeyRecoveryParam = function(e, signature, Q, enc) { + signature = new Signature(signature, enc); + if (signature.recoveryParam !== null) return signature.recoveryParam; - if (typeof password === 'string') password = Buffer.from(password) - if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length) + for (var i = 0; i < 4; i++) { + var Qprime; + try { + Qprime = this.recoverPubKey(e, signature, i); + } catch (e) { + continue; + } - if (typeof iv === 'string') iv = Buffer.from(iv) - if (iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length) + if (Qprime.eq(Q)) return i; + } + throw new Error('Unable to find valid recovery factor'); + }; + }, + { '../../elliptic': 93, './key': 101, './signature': 102, 'bn.js': 92, 'hmac-drbg': 181 }, + ], + 101: [ + function(require, module, exports) { + 'use strict'; + + var BN = require('bn.js'); + var elliptic = require('../../elliptic'); + var utils = elliptic.utils; + var assert = utils.assert; + + function KeyPair(ec, options) { + this.ec = ec; + this.priv = null; + this.pub = null; + + // KeyPair(ec, { priv: ..., pub: ... }) + if (options.priv) this._importPrivate(options.priv, options.privEnc); + if (options.pub) this._importPublic(options.pub, options.pubEnc); + } + module.exports = KeyPair; - if (config.type === 'stream') { - return new StreamCipher(config.module, password, iv) - } else if (config.type === 'auth') { - return new AuthCipher(config.module, password, iv) - } + KeyPair.fromPublic = function fromPublic(ec, pub, enc) { + if (pub instanceof KeyPair) return pub; - return new Cipher(config.module, password, iv) -} + return new KeyPair(ec, { + pub: pub, + pubEnc: enc, + }); + }; -function createCipher (suite, password) { - var config = MODES[suite.toLowerCase()] - if (!config) throw new TypeError('invalid suite type') + KeyPair.fromPrivate = function fromPrivate(ec, priv, enc) { + if (priv instanceof KeyPair) return priv; - var keys = ebtk(password, false, config.key, config.iv) - return createCipheriv(suite, keys.key, keys.iv) -} + return new KeyPair(ec, { + priv: priv, + privEnc: enc, + }); + }; -exports.createCipheriv = createCipheriv -exports.createCipher = createCipher + KeyPair.prototype.validate = function validate() { + var pub = this.getPublic(); -},{"./aes":65,"./authCipher":66,"./modes":77,"./streamCipher":80,"cipher-base":114,"evp_bytestokey":166,"inherits":184,"safe-buffer":233}],70:[function(require,module,exports){ -var Buffer = require('safe-buffer').Buffer -var ZEROES = Buffer.alloc(16, 0) + if (pub.isInfinity()) return { result: false, reason: 'Invalid public key' }; + if (!pub.validate()) return { result: false, reason: 'Public key is not a point' }; + if (!pub.mul(this.ec.curve.n).isInfinity()) return { result: false, reason: 'Public key * N != O' }; -function toArray (buf) { - return [ - buf.readUInt32BE(0), - buf.readUInt32BE(4), - buf.readUInt32BE(8), - buf.readUInt32BE(12) - ] -} + return { result: true, reason: null }; + }; -function fromArray (out) { - var buf = Buffer.allocUnsafe(16) - buf.writeUInt32BE(out[0] >>> 0, 0) - buf.writeUInt32BE(out[1] >>> 0, 4) - buf.writeUInt32BE(out[2] >>> 0, 8) - buf.writeUInt32BE(out[3] >>> 0, 12) - return buf -} + KeyPair.prototype.getPublic = function getPublic(compact, enc) { + // compact is optional argument + if (typeof compact === 'string') { + enc = compact; + compact = null; + } -function GHASH (key) { - this.h = key - this.state = Buffer.alloc(16, 0) - this.cache = Buffer.allocUnsafe(0) -} + if (!this.pub) this.pub = this.ec.g.mul(this.priv); -// from http://bitwiseshiftleft.github.io/sjcl/doc/symbols/src/core_gcm.js.html -// by Juho Vรคhรค-Herttua -GHASH.prototype.ghash = function (block) { - var i = -1 - while (++i < block.length) { - this.state[i] ^= block[i] - } - this._multiply() -} + if (!enc) return this.pub; -GHASH.prototype._multiply = function () { - var Vi = toArray(this.h) - var Zi = [0, 0, 0, 0] - var j, xi, lsbVi - var i = -1 - while (++i < 128) { - xi = (this.state[~~(i / 8)] & (1 << (7 - (i % 8)))) !== 0 - if (xi) { - // Z_i+1 = Z_i ^ V_i - Zi[0] ^= Vi[0] - Zi[1] ^= Vi[1] - Zi[2] ^= Vi[2] - Zi[3] ^= Vi[3] - } + return this.pub.encode(enc, compact); + }; - // Store the value of LSB(V_i) - lsbVi = (Vi[3] & 1) !== 0 + KeyPair.prototype.getPrivate = function getPrivate(enc) { + if (enc === 'hex') return this.priv.toString(16, 2); + else return this.priv; + }; - // V_i+1 = V_i >> 1 - for (j = 3; j > 0; j--) { - Vi[j] = (Vi[j] >>> 1) | ((Vi[j - 1] & 1) << 31) - } - Vi[0] = Vi[0] >>> 1 + KeyPair.prototype._importPrivate = function _importPrivate(key, enc) { + this.priv = new BN(key, enc || 16); - // If LSB(V_i) is 1, V_i+1 = (V_i >> 1) ^ R - if (lsbVi) { - Vi[0] = Vi[0] ^ (0xe1 << 24) - } - } - this.state = fromArray(Zi) -} + // Ensure that the priv won't be bigger than n, otherwise we may fail + // in fixed multiplication method + this.priv = this.priv.umod(this.ec.curve.n); + }; -GHASH.prototype.update = function (buf) { - this.cache = Buffer.concat([this.cache, buf]) - var chunk - while (this.cache.length >= 16) { - chunk = this.cache.slice(0, 16) - this.cache = this.cache.slice(16) - this.ghash(chunk) - } -} + KeyPair.prototype._importPublic = function _importPublic(key, enc) { + if (key.x || key.y) { + // Montgomery points only have an `x` coordinate. + // Weierstrass/Edwards points on the other hand have both `x` and + // `y` coordinates. + if (this.ec.curve.type === 'mont') { + assert(key.x, 'Need x coordinate'); + } else if (this.ec.curve.type === 'short' || this.ec.curve.type === 'edwards') { + assert(key.x && key.y, 'Need both x and y coordinate'); + } + this.pub = this.ec.curve.point(key.x, key.y); + return; + } + this.pub = this.ec.curve.decodePoint(key, enc); + }; -GHASH.prototype.final = function (abl, bl) { - if (this.cache.length) { - this.ghash(Buffer.concat([this.cache, ZEROES], 16)) - } + // ECDH + KeyPair.prototype.derive = function derive(pub) { + return pub.mul(this.priv).getX(); + }; - this.ghash(fromArray([0, abl, 0, bl])) - return this.state -} + // ECDSA + KeyPair.prototype.sign = function sign(msg, enc, options) { + return this.ec.sign(msg, this, enc, options); + }; -module.exports = GHASH + KeyPair.prototype.verify = function verify(msg, signature) { + return this.ec.verify(msg, signature, this); + }; -},{"safe-buffer":233}],71:[function(require,module,exports){ -var xor = require('buffer-xor') + KeyPair.prototype.inspect = function inspect() { + return ( + '' + ); + }; + }, + { '../../elliptic': 93, 'bn.js': 92 }, + ], + 102: [ + function(require, module, exports) { + 'use strict'; -exports.encrypt = function (self, block) { - var data = xor(block, self._prev) + var BN = require('bn.js'); - self._prev = self._cipher.encryptBlock(data) - return self._prev -} + var elliptic = require('../../elliptic'); + var utils = elliptic.utils; + var assert = utils.assert; -exports.decrypt = function (self, block) { - var pad = self._prev + function Signature(options, enc) { + if (options instanceof Signature) return options; - self._prev = block - var out = self._cipher.decryptBlock(block) + if (this._importDER(options, enc)) return; - return xor(out, pad) -} + assert(options.r && options.s, 'Signature without r or s'); + this.r = new BN(options.r, 16); + this.s = new BN(options.s, 16); + if (options.recoveryParam === undefined) this.recoveryParam = null; + else this.recoveryParam = options.recoveryParam; + } + module.exports = Signature; -},{"buffer-xor":112}],72:[function(require,module,exports){ -var Buffer = require('safe-buffer').Buffer -var xor = require('buffer-xor') + function Position() { + this.place = 0; + } -function encryptStart (self, data, decrypt) { - var len = data.length - var out = xor(data, self._cache) - self._cache = self._cache.slice(len) - self._prev = Buffer.concat([self._prev, decrypt ? data : out]) - return out -} + function getLength(buf, p) { + var initial = buf[p.place++]; + if (!(initial & 0x80)) { + return initial; + } + var octetLen = initial & 0xf; + var val = 0; + for (var i = 0, off = p.place; i < octetLen; i++, off++) { + val <<= 8; + val |= buf[off]; + } + p.place = off; + return val; + } -exports.encrypt = function (self, data, decrypt) { - var out = Buffer.allocUnsafe(0) - var len + function rmPadding(buf) { + var i = 0; + var len = buf.length - 1; + while (!buf[i] && !(buf[i + 1] & 0x80) && i < len) { + i++; + } + if (i === 0) { + return buf; + } + return buf.slice(i); + } - while (data.length) { - if (self._cache.length === 0) { - self._cache = self._cipher.encryptBlock(self._prev) - self._prev = Buffer.allocUnsafe(0) - } + Signature.prototype._importDER = function _importDER(data, enc) { + data = utils.toArray(data, enc); + var p = new Position(); + if (data[p.place++] !== 0x30) { + return false; + } + var len = getLength(data, p); + if (len + p.place !== data.length) { + return false; + } + if (data[p.place++] !== 0x02) { + return false; + } + var rlen = getLength(data, p); + var r = data.slice(p.place, rlen + p.place); + p.place += rlen; + if (data[p.place++] !== 0x02) { + return false; + } + var slen = getLength(data, p); + if (data.length !== slen + p.place) { + return false; + } + var s = data.slice(p.place, slen + p.place); + if (r[0] === 0 && r[1] & 0x80) { + r = r.slice(1); + } + if (s[0] === 0 && s[1] & 0x80) { + s = s.slice(1); + } - if (self._cache.length <= data.length) { - len = self._cache.length - out = Buffer.concat([out, encryptStart(self, data.slice(0, len), decrypt)]) - data = data.slice(len) - } else { - out = Buffer.concat([out, encryptStart(self, data, decrypt)]) - break - } - } + this.r = new BN(r); + this.s = new BN(s); + this.recoveryParam = null; - return out -} + return true; + }; -},{"buffer-xor":112,"safe-buffer":233}],73:[function(require,module,exports){ -var Buffer = require('safe-buffer').Buffer - -function encryptByte (self, byteParam, decrypt) { - var pad - var i = -1 - var len = 8 - var out = 0 - var bit, value - while (++i < len) { - pad = self._cipher.encryptBlock(self._prev) - bit = (byteParam & (1 << (7 - i))) ? 0x80 : 0 - value = pad[0] ^ bit - out += ((value & 0x80) >> (i % 8)) - self._prev = shiftIn(self._prev, decrypt ? bit : value) - } - return out -} + function constructLength(arr, len) { + if (len < 0x80) { + arr.push(len); + return; + } + var octets = 1 + ((Math.log(len) / Math.LN2) >>> 3); + arr.push(octets | 0x80); + while (--octets) { + arr.push((len >>> (octets << 3)) & 0xff); + } + arr.push(len); + } -function shiftIn (buffer, value) { - var len = buffer.length - var i = -1 - var out = Buffer.allocUnsafe(buffer.length) - buffer = Buffer.concat([buffer, Buffer.from([value])]) + Signature.prototype.toDER = function toDER(enc) { + var r = this.r.toArray(); + var s = this.s.toArray(); - while (++i < len) { - out[i] = buffer[i] << 1 | buffer[i + 1] >> (7) - } + // Pad values + if (r[0] & 0x80) r = [0].concat(r); + // Pad values + if (s[0] & 0x80) s = [0].concat(s); - return out -} + r = rmPadding(r); + s = rmPadding(s); -exports.encrypt = function (self, chunk, decrypt) { - var len = chunk.length - var out = Buffer.allocUnsafe(len) - var i = -1 + while (!s[0] && !(s[1] & 0x80)) { + s = s.slice(1); + } + var arr = [0x02]; + constructLength(arr, r.length); + arr = arr.concat(r); + arr.push(0x02); + constructLength(arr, s.length); + var backHalf = arr.concat(s); + var res = [0x30]; + constructLength(res, backHalf.length); + res = res.concat(backHalf); + return utils.encode(res, enc); + }; + }, + { '../../elliptic': 93, 'bn.js': 92 }, + ], + 103: [ + function(require, module, exports) { + 'use strict'; + + var hash = require('hash.js'); + var elliptic = require('../../elliptic'); + var utils = elliptic.utils; + var assert = utils.assert; + var parseBytes = utils.parseBytes; + var KeyPair = require('./key'); + var Signature = require('./signature'); + + function EDDSA(curve) { + assert(curve === 'ed25519', 'only tested with ed25519 so far'); + + if (!(this instanceof EDDSA)) return new EDDSA(curve); + + var curve = elliptic.curves[curve].curve; + this.curve = curve; + this.g = curve.g; + this.g.precompute(curve.n.bitLength() + 1); + + this.pointClass = curve.point().constructor; + this.encodingLength = Math.ceil(curve.n.bitLength() / 8); + this.hash = hash.sha512; + } - while (++i < len) { - out[i] = encryptByte(self, chunk[i], decrypt) - } + module.exports = EDDSA; - return out -} + /** + * @param {Array|String} message - message bytes + * @param {Array|String|KeyPair} secret - secret bytes or a keypair + * @returns {Signature} - signature + */ + EDDSA.prototype.sign = function sign(message, secret) { + message = parseBytes(message); + var key = this.keyFromSecret(secret); + var r = this.hashInt(key.messagePrefix(), message); + var R = this.g.mul(r); + var Rencoded = this.encodePoint(R); + var s_ = this.hashInt(Rencoded, key.pubBytes(), message).mul(key.priv()); + var S = r.add(s_).umod(this.curve.n); + return this.makeSignature({ R: R, S: S, Rencoded: Rencoded }); + }; -},{"safe-buffer":233}],74:[function(require,module,exports){ -(function (Buffer){ -function encryptByte (self, byteParam, decrypt) { - var pad = self._cipher.encryptBlock(self._prev) - var out = pad[0] ^ byteParam + /** + * @param {Array} message - message bytes + * @param {Array|String|Signature} sig - sig bytes + * @param {Array|String|Point|KeyPair} pub - public key + * @returns {Boolean} - true if public key matches sig of message + */ + EDDSA.prototype.verify = function verify(message, sig, pub) { + message = parseBytes(message); + sig = this.makeSignature(sig); + var key = this.keyFromPublic(pub); + var h = this.hashInt(sig.Rencoded(), key.pubBytes(), message); + var SG = this.g.mul(sig.S()); + var RplusAh = sig.R().add(key.pub().mul(h)); + return RplusAh.eq(SG); + }; - self._prev = Buffer.concat([ - self._prev.slice(1), - Buffer.from([decrypt ? byteParam : out]) - ]) + EDDSA.prototype.hashInt = function hashInt() { + var hash = this.hash(); + for (var i = 0; i < arguments.length; i++) hash.update(arguments[i]); + return utils.intFromLE(hash.digest()).umod(this.curve.n); + }; - return out -} + EDDSA.prototype.keyFromPublic = function keyFromPublic(pub) { + return KeyPair.fromPublic(this, pub); + }; -exports.encrypt = function (self, chunk, decrypt) { - var len = chunk.length - var out = Buffer.allocUnsafe(len) - var i = -1 + EDDSA.prototype.keyFromSecret = function keyFromSecret(secret) { + return KeyPair.fromSecret(this, secret); + }; - while (++i < len) { - out[i] = encryptByte(self, chunk[i], decrypt) - } + EDDSA.prototype.makeSignature = function makeSignature(sig) { + if (sig instanceof Signature) return sig; + return new Signature(this, sig); + }; - return out -} + /** + * * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-5.2 + * + * EDDSA defines methods for encoding and decoding points and integers. These are + * helper convenience methods, that pass along to utility functions implied + * parameters. + * + */ + EDDSA.prototype.encodePoint = function encodePoint(point) { + var enc = point.getY().toArray('le', this.encodingLength); + enc[this.encodingLength - 1] |= point.getX().isOdd() ? 0x80 : 0; + return enc; + }; -}).call(this,require("buffer").Buffer) -},{"buffer":113}],75:[function(require,module,exports){ -(function (Buffer){ -var xor = require('buffer-xor') - -function incr32 (iv) { - var len = iv.length - var item - while (len--) { - item = iv.readUInt8(len) - if (item === 255) { - iv.writeUInt8(0, len) - } else { - item++ - iv.writeUInt8(item, len) - break - } - } -} + EDDSA.prototype.decodePoint = function decodePoint(bytes) { + bytes = utils.parseBytes(bytes); -function getBlock (self) { - var out = self._cipher.encryptBlockRaw(self._prev) - incr32(self._prev) - return out -} + var lastIx = bytes.length - 1; + var normed = bytes.slice(0, lastIx).concat(bytes[lastIx] & ~0x80); + var xIsOdd = (bytes[lastIx] & 0x80) !== 0; -var blockSize = 16 -exports.encrypt = function (self, chunk) { - var chunkNum = Math.ceil(chunk.length / blockSize) - var start = self._cache.length - self._cache = Buffer.concat([ - self._cache, - Buffer.allocUnsafe(chunkNum * blockSize) - ]) - for (var i = 0; i < chunkNum; i++) { - var out = getBlock(self) - var offset = start + i * blockSize - self._cache.writeUInt32BE(out[0], offset + 0) - self._cache.writeUInt32BE(out[1], offset + 4) - self._cache.writeUInt32BE(out[2], offset + 8) - self._cache.writeUInt32BE(out[3], offset + 12) - } - var pad = self._cache.slice(0, chunk.length) - self._cache = self._cache.slice(chunk.length) - return xor(chunk, pad) -} + var y = utils.intFromLE(normed); + return this.curve.pointFromY(y, xIsOdd); + }; -}).call(this,require("buffer").Buffer) -},{"buffer":113,"buffer-xor":112}],76:[function(require,module,exports){ -exports.encrypt = function (self, block) { - return self._cipher.encryptBlock(block) -} + EDDSA.prototype.encodeInt = function encodeInt(num) { + return num.toArray('le', this.encodingLength); + }; -exports.decrypt = function (self, block) { - return self._cipher.decryptBlock(block) -} + EDDSA.prototype.decodeInt = function decodeInt(bytes) { + return utils.intFromLE(bytes); + }; -},{}],77:[function(require,module,exports){ -var modeModules = { - ECB: require('./ecb'), - CBC: require('./cbc'), - CFB: require('./cfb'), - CFB8: require('./cfb8'), - CFB1: require('./cfb1'), - OFB: require('./ofb'), - CTR: require('./ctr'), - GCM: require('./ctr') -} + EDDSA.prototype.isPoint = function isPoint(val) { + return val instanceof this.pointClass; + }; + }, + { '../../elliptic': 93, './key': 104, './signature': 105, 'hash.js': 168 }, + ], + 104: [ + function(require, module, exports) { + 'use strict'; + + var elliptic = require('../../elliptic'); + var utils = elliptic.utils; + var assert = utils.assert; + var parseBytes = utils.parseBytes; + var cachedProperty = utils.cachedProperty; -var modes = require('./list.json') + /** + * @param {EDDSA} eddsa - instance + * @param {Object} params - public/private key parameters + * + * @param {Array} [params.secret] - secret seed bytes + * @param {Point} [params.pub] - public key point (aka `A` in eddsa terms) + * @param {Array} [params.pub] - public key point encoded as bytes + * + */ + function KeyPair(eddsa, params) { + this.eddsa = eddsa; + this._secret = parseBytes(params.secret); + if (eddsa.isPoint(params.pub)) this._pub = params.pub; + else this._pubBytes = parseBytes(params.pub); + } -for (var key in modes) { - modes[key].module = modeModules[modes[key].mode] -} + KeyPair.fromPublic = function fromPublic(eddsa, pub) { + if (pub instanceof KeyPair) return pub; + return new KeyPair(eddsa, { pub: pub }); + }; -module.exports = modes + KeyPair.fromSecret = function fromSecret(eddsa, secret) { + if (secret instanceof KeyPair) return secret; + return new KeyPair(eddsa, { secret: secret }); + }; -},{"./cbc":71,"./cfb":72,"./cfb1":73,"./cfb8":74,"./ctr":75,"./ecb":76,"./list.json":78,"./ofb":79}],78:[function(require,module,exports){ -module.exports={ - "aes-128-ecb": { - "cipher": "AES", - "key": 128, - "iv": 0, - "mode": "ECB", - "type": "block" - }, - "aes-192-ecb": { - "cipher": "AES", - "key": 192, - "iv": 0, - "mode": "ECB", - "type": "block" - }, - "aes-256-ecb": { - "cipher": "AES", - "key": 256, - "iv": 0, - "mode": "ECB", - "type": "block" - }, - "aes-128-cbc": { - "cipher": "AES", - "key": 128, - "iv": 16, - "mode": "CBC", - "type": "block" - }, - "aes-192-cbc": { - "cipher": "AES", - "key": 192, - "iv": 16, - "mode": "CBC", - "type": "block" - }, - "aes-256-cbc": { - "cipher": "AES", - "key": 256, - "iv": 16, - "mode": "CBC", - "type": "block" - }, - "aes128": { - "cipher": "AES", - "key": 128, - "iv": 16, - "mode": "CBC", - "type": "block" - }, - "aes192": { - "cipher": "AES", - "key": 192, - "iv": 16, - "mode": "CBC", - "type": "block" - }, - "aes256": { - "cipher": "AES", - "key": 256, - "iv": 16, - "mode": "CBC", - "type": "block" - }, - "aes-128-cfb": { - "cipher": "AES", - "key": 128, - "iv": 16, - "mode": "CFB", - "type": "stream" - }, - "aes-192-cfb": { - "cipher": "AES", - "key": 192, - "iv": 16, - "mode": "CFB", - "type": "stream" - }, - "aes-256-cfb": { - "cipher": "AES", - "key": 256, - "iv": 16, - "mode": "CFB", - "type": "stream" - }, - "aes-128-cfb8": { - "cipher": "AES", - "key": 128, - "iv": 16, - "mode": "CFB8", - "type": "stream" - }, - "aes-192-cfb8": { - "cipher": "AES", - "key": 192, - "iv": 16, - "mode": "CFB8", - "type": "stream" - }, - "aes-256-cfb8": { - "cipher": "AES", - "key": 256, - "iv": 16, - "mode": "CFB8", - "type": "stream" - }, - "aes-128-cfb1": { - "cipher": "AES", - "key": 128, - "iv": 16, - "mode": "CFB1", - "type": "stream" - }, - "aes-192-cfb1": { - "cipher": "AES", - "key": 192, - "iv": 16, - "mode": "CFB1", - "type": "stream" - }, - "aes-256-cfb1": { - "cipher": "AES", - "key": 256, - "iv": 16, - "mode": "CFB1", - "type": "stream" - }, - "aes-128-ofb": { - "cipher": "AES", - "key": 128, - "iv": 16, - "mode": "OFB", - "type": "stream" - }, - "aes-192-ofb": { - "cipher": "AES", - "key": 192, - "iv": 16, - "mode": "OFB", - "type": "stream" - }, - "aes-256-ofb": { - "cipher": "AES", - "key": 256, - "iv": 16, - "mode": "OFB", - "type": "stream" - }, - "aes-128-ctr": { - "cipher": "AES", - "key": 128, - "iv": 16, - "mode": "CTR", - "type": "stream" - }, - "aes-192-ctr": { - "cipher": "AES", - "key": 192, - "iv": 16, - "mode": "CTR", - "type": "stream" - }, - "aes-256-ctr": { - "cipher": "AES", - "key": 256, - "iv": 16, - "mode": "CTR", - "type": "stream" - }, - "aes-128-gcm": { - "cipher": "AES", - "key": 128, - "iv": 12, - "mode": "GCM", - "type": "auth" - }, - "aes-192-gcm": { - "cipher": "AES", - "key": 192, - "iv": 12, - "mode": "GCM", - "type": "auth" - }, - "aes-256-gcm": { - "cipher": "AES", - "key": 256, - "iv": 12, - "mode": "GCM", - "type": "auth" - } -} + KeyPair.prototype.secret = function secret() { + return this._secret; + }; -},{}],79:[function(require,module,exports){ -(function (Buffer){ -var xor = require('buffer-xor') + cachedProperty(KeyPair, 'pubBytes', function pubBytes() { + return this.eddsa.encodePoint(this.pub()); + }); -function getBlock (self) { - self._prev = self._cipher.encryptBlock(self._prev) - return self._prev -} + cachedProperty(KeyPair, 'pub', function pub() { + if (this._pubBytes) return this.eddsa.decodePoint(this._pubBytes); + return this.eddsa.g.mul(this.priv()); + }); -exports.encrypt = function (self, chunk) { - while (self._cache.length < chunk.length) { - self._cache = Buffer.concat([self._cache, getBlock(self)]) - } + cachedProperty(KeyPair, 'privBytes', function privBytes() { + var eddsa = this.eddsa; + var hash = this.hash(); + var lastIx = eddsa.encodingLength - 1; - var pad = self._cache.slice(0, chunk.length) - self._cache = self._cache.slice(chunk.length) - return xor(chunk, pad) -} + var a = hash.slice(0, eddsa.encodingLength); + a[0] &= 248; + a[lastIx] &= 127; + a[lastIx] |= 64; -}).call(this,require("buffer").Buffer) -},{"buffer":113,"buffer-xor":112}],80:[function(require,module,exports){ -var aes = require('./aes') -var Buffer = require('safe-buffer').Buffer -var Transform = require('cipher-base') -var inherits = require('inherits') - -function StreamCipher (mode, key, iv, decrypt) { - Transform.call(this) - - this._cipher = new aes.AES(key) - this._prev = Buffer.from(iv) - this._cache = Buffer.allocUnsafe(0) - this._secCache = Buffer.allocUnsafe(0) - this._decrypt = decrypt - this._mode = mode -} + return a; + }); -inherits(StreamCipher, Transform) + cachedProperty(KeyPair, 'priv', function priv() { + return this.eddsa.decodeInt(this.privBytes()); + }); -StreamCipher.prototype._update = function (chunk) { - return this._mode.encrypt(this, chunk, this._decrypt) -} + cachedProperty(KeyPair, 'hash', function hash() { + return this.eddsa + .hash() + .update(this.secret()) + .digest(); + }); -StreamCipher.prototype._final = function () { - this._cipher.scrub() -} + cachedProperty(KeyPair, 'messagePrefix', function messagePrefix() { + return this.hash().slice(this.eddsa.encodingLength); + }); -module.exports = StreamCipher - -},{"./aes":65,"cipher-base":114,"inherits":184,"safe-buffer":233}],81:[function(require,module,exports){ -var ebtk = require('evp_bytestokey') -var aes = require('browserify-aes/browser') -var DES = require('browserify-des') -var desModes = require('browserify-des/modes') -var aesModes = require('browserify-aes/modes') -function createCipher (suite, password) { - var keyLen, ivLen - suite = suite.toLowerCase() - if (aesModes[suite]) { - keyLen = aesModes[suite].key - ivLen = aesModes[suite].iv - } else if (desModes[suite]) { - keyLen = desModes[suite].key * 8 - ivLen = desModes[suite].iv - } else { - throw new TypeError('invalid suite type') - } - var keys = ebtk(password, false, keyLen, ivLen) - return createCipheriv(suite, keys.key, keys.iv) -} -function createDecipher (suite, password) { - var keyLen, ivLen - suite = suite.toLowerCase() - if (aesModes[suite]) { - keyLen = aesModes[suite].key - ivLen = aesModes[suite].iv - } else if (desModes[suite]) { - keyLen = desModes[suite].key * 8 - ivLen = desModes[suite].iv - } else { - throw new TypeError('invalid suite type') - } - var keys = ebtk(password, false, keyLen, ivLen) - return createDecipheriv(suite, keys.key, keys.iv) -} + KeyPair.prototype.sign = function sign(message) { + assert(this._secret, 'KeyPair can only verify'); + return this.eddsa.sign(message, this); + }; -function createCipheriv (suite, key, iv) { - suite = suite.toLowerCase() - if (aesModes[suite]) { - return aes.createCipheriv(suite, key, iv) - } else if (desModes[suite]) { - return new DES({ - key: key, - iv: iv, - mode: suite - }) - } else { - throw new TypeError('invalid suite type') - } -} -function createDecipheriv (suite, key, iv) { - suite = suite.toLowerCase() - if (aesModes[suite]) { - return aes.createDecipheriv(suite, key, iv) - } else if (desModes[suite]) { - return new DES({ - key: key, - iv: iv, - mode: suite, - decrypt: true - }) - } else { - throw new TypeError('invalid suite type') - } -} -exports.createCipher = exports.Cipher = createCipher -exports.createCipheriv = exports.Cipheriv = createCipheriv -exports.createDecipher = exports.Decipher = createDecipher -exports.createDecipheriv = exports.Decipheriv = createDecipheriv -function getCiphers () { - return Object.keys(desModes).concat(aes.getCiphers()) -} -exports.listCiphers = exports.getCiphers = getCiphers - -},{"browserify-aes/browser":67,"browserify-aes/modes":77,"browserify-des":82,"browserify-des/modes":83,"evp_bytestokey":166}],82:[function(require,module,exports){ -(function (Buffer){ -var CipherBase = require('cipher-base') -var des = require('des.js') -var inherits = require('inherits') - -var modes = { - 'des-ede3-cbc': des.CBC.instantiate(des.EDE), - 'des-ede3': des.EDE, - 'des-ede-cbc': des.CBC.instantiate(des.EDE), - 'des-ede': des.EDE, - 'des-cbc': des.CBC.instantiate(des.DES), - 'des-ecb': des.DES -} -modes.des = modes['des-cbc'] -modes.des3 = modes['des-ede3-cbc'] -module.exports = DES -inherits(DES, CipherBase) -function DES (opts) { - CipherBase.call(this) - var modeName = opts.mode.toLowerCase() - var mode = modes[modeName] - var type - if (opts.decrypt) { - type = 'decrypt' - } else { - type = 'encrypt' - } - var key = opts.key - if (modeName === 'des-ede' || modeName === 'des-ede-cbc') { - key = Buffer.concat([key, key.slice(0, 8)]) - } - var iv = opts.iv - this._des = mode.create({ - key: key, - iv: iv, - type: type - }) -} -DES.prototype._update = function (data) { - return new Buffer(this._des.update(data)) -} -DES.prototype._final = function () { - return new Buffer(this._des.final()) -} + KeyPair.prototype.verify = function verify(message, sig) { + return this.eddsa.verify(message, sig, this); + }; -}).call(this,require("buffer").Buffer) -},{"buffer":113,"cipher-base":114,"des.js":140,"inherits":184}],83:[function(require,module,exports){ -exports['des-ecb'] = { - key: 8, - iv: 0 -} -exports['des-cbc'] = exports.des = { - key: 8, - iv: 8 -} -exports['des-ede3-cbc'] = exports.des3 = { - key: 24, - iv: 8 -} -exports['des-ede3'] = { - key: 24, - iv: 0 -} -exports['des-ede-cbc'] = { - key: 16, - iv: 8 -} -exports['des-ede'] = { - key: 16, - iv: 0 -} + KeyPair.prototype.getSecret = function getSecret(enc) { + assert(this._secret, 'KeyPair is public only'); + return utils.encode(this.secret(), enc); + }; -},{}],84:[function(require,module,exports){ -(function (Buffer){ -var bn = require('bn.js'); -var randomBytes = require('randombytes'); -module.exports = crt; -function blind(priv) { - var r = getr(priv); - var blinder = r.toRed(bn.mont(priv.modulus)) - .redPow(new bn(priv.publicExponent)).fromRed(); - return { - blinder: blinder, - unblinder:r.invm(priv.modulus) - }; -} -function crt(msg, priv) { - var blinds = blind(priv); - var len = priv.modulus.byteLength(); - var mod = bn.mont(priv.modulus); - var blinded = new bn(msg).mul(blinds.blinder).umod(priv.modulus); - var c1 = blinded.toRed(bn.mont(priv.prime1)); - var c2 = blinded.toRed(bn.mont(priv.prime2)); - var qinv = priv.coefficient; - var p = priv.prime1; - var q = priv.prime2; - var m1 = c1.redPow(priv.exponent1); - var m2 = c2.redPow(priv.exponent2); - m1 = m1.fromRed(); - m2 = m2.fromRed(); - var h = m1.isub(m2).imul(qinv).umod(p); - h.imul(q); - m2.iadd(h); - return new Buffer(m2.imul(blinds.unblinder).umod(priv.modulus).toArray(false, len)); -} -crt.getr = getr; -function getr(priv) { - var len = priv.modulus.byteLength(); - var r = new bn(randomBytes(len)); - while (r.cmp(priv.modulus) >= 0 || !r.umod(priv.prime1) || !r.umod(priv.prime2)) { - r = new bn(randomBytes(len)); - } - return r; -} + KeyPair.prototype.getPublic = function getPublic(enc) { + return utils.encode(this.pubBytes(), enc); + }; -}).call(this,require("buffer").Buffer) -},{"bn.js":85,"buffer":113,"randombytes":217}],85:[function(require,module,exports){ -arguments[4][59][0].apply(exports,arguments) -},{"buffer":64,"dup":59}],86:[function(require,module,exports){ -module.exports = require('./browser/algorithms.json') - -},{"./browser/algorithms.json":87}],87:[function(require,module,exports){ -module.exports={ - "sha224WithRSAEncryption": { - "sign": "rsa", - "hash": "sha224", - "id": "302d300d06096086480165030402040500041c" - }, - "RSA-SHA224": { - "sign": "ecdsa/rsa", - "hash": "sha224", - "id": "302d300d06096086480165030402040500041c" - }, - "sha256WithRSAEncryption": { - "sign": "rsa", - "hash": "sha256", - "id": "3031300d060960864801650304020105000420" - }, - "RSA-SHA256": { - "sign": "ecdsa/rsa", - "hash": "sha256", - "id": "3031300d060960864801650304020105000420" - }, - "sha384WithRSAEncryption": { - "sign": "rsa", - "hash": "sha384", - "id": "3041300d060960864801650304020205000430" - }, - "RSA-SHA384": { - "sign": "ecdsa/rsa", - "hash": "sha384", - "id": "3041300d060960864801650304020205000430" - }, - "sha512WithRSAEncryption": { - "sign": "rsa", - "hash": "sha512", - "id": "3051300d060960864801650304020305000440" - }, - "RSA-SHA512": { - "sign": "ecdsa/rsa", - "hash": "sha512", - "id": "3051300d060960864801650304020305000440" - }, - "RSA-SHA1": { - "sign": "rsa", - "hash": "sha1", - "id": "3021300906052b0e03021a05000414" - }, - "ecdsa-with-SHA1": { - "sign": "ecdsa", - "hash": "sha1", - "id": "" - }, - "sha256": { - "sign": "ecdsa", - "hash": "sha256", - "id": "" - }, - "sha224": { - "sign": "ecdsa", - "hash": "sha224", - "id": "" - }, - "sha384": { - "sign": "ecdsa", - "hash": "sha384", - "id": "" - }, - "sha512": { - "sign": "ecdsa", - "hash": "sha512", - "id": "" - }, - "DSA-SHA": { - "sign": "dsa", - "hash": "sha1", - "id": "" - }, - "DSA-SHA1": { - "sign": "dsa", - "hash": "sha1", - "id": "" - }, - "DSA": { - "sign": "dsa", - "hash": "sha1", - "id": "" - }, - "DSA-WITH-SHA224": { - "sign": "dsa", - "hash": "sha224", - "id": "" - }, - "DSA-SHA224": { - "sign": "dsa", - "hash": "sha224", - "id": "" - }, - "DSA-WITH-SHA256": { - "sign": "dsa", - "hash": "sha256", - "id": "" - }, - "DSA-SHA256": { - "sign": "dsa", - "hash": "sha256", - "id": "" - }, - "DSA-WITH-SHA384": { - "sign": "dsa", - "hash": "sha384", - "id": "" - }, - "DSA-SHA384": { - "sign": "dsa", - "hash": "sha384", - "id": "" - }, - "DSA-WITH-SHA512": { - "sign": "dsa", - "hash": "sha512", - "id": "" - }, - "DSA-SHA512": { - "sign": "dsa", - "hash": "sha512", - "id": "" - }, - "DSA-RIPEMD160": { - "sign": "dsa", - "hash": "rmd160", - "id": "" - }, - "ripemd160WithRSA": { - "sign": "rsa", - "hash": "rmd160", - "id": "3021300906052b2403020105000414" - }, - "RSA-RIPEMD160": { - "sign": "rsa", - "hash": "rmd160", - "id": "3021300906052b2403020105000414" - }, - "md5WithRSAEncryption": { - "sign": "rsa", - "hash": "md5", - "id": "3020300c06082a864886f70d020505000410" - }, - "RSA-MD5": { - "sign": "rsa", - "hash": "md5", - "id": "3020300c06082a864886f70d020505000410" - } -} + module.exports = KeyPair; + }, + { '../../elliptic': 93 }, + ], + 105: [ + function(require, module, exports) { + 'use strict'; + + var BN = require('bn.js'); + var elliptic = require('../../elliptic'); + var utils = elliptic.utils; + var assert = utils.assert; + var cachedProperty = utils.cachedProperty; + var parseBytes = utils.parseBytes; -},{}],88:[function(require,module,exports){ -module.exports={ - "1.3.132.0.10": "secp256k1", - "1.3.132.0.33": "p224", - "1.2.840.10045.3.1.1": "p192", - "1.2.840.10045.3.1.7": "p256", - "1.3.132.0.34": "p384", - "1.3.132.0.35": "p521" -} + /** + * @param {EDDSA} eddsa - eddsa instance + * @param {Array|Object} sig - + * @param {Array|Point} [sig.R] - R point as Point or bytes + * @param {Array|bn} [sig.S] - S scalar as bn or bytes + * @param {Array} [sig.Rencoded] - R point encoded + * @param {Array} [sig.Sencoded] - S scalar encoded + */ + function Signature(eddsa, sig) { + this.eddsa = eddsa; -},{}],89:[function(require,module,exports){ -(function (Buffer){ -var createHash = require('create-hash') -var stream = require('stream') -var inherits = require('inherits') -var sign = require('./sign') -var verify = require('./verify') - -var algorithms = require('./algorithms.json') -Object.keys(algorithms).forEach(function (key) { - algorithms[key].id = new Buffer(algorithms[key].id, 'hex') - algorithms[key.toLowerCase()] = algorithms[key] -}) - -function Sign (algorithm) { - stream.Writable.call(this) - - var data = algorithms[algorithm] - if (!data) throw new Error('Unknown message digest') - - this._hashType = data.hash - this._hash = createHash(data.hash) - this._tag = data.id - this._signType = data.sign -} -inherits(Sign, stream.Writable) + if (typeof sig !== 'object') sig = parseBytes(sig); -Sign.prototype._write = function _write (data, _, done) { - this._hash.update(data) - done() -} + if (Array.isArray(sig)) { + sig = { + R: sig.slice(0, eddsa.encodingLength), + S: sig.slice(eddsa.encodingLength), + }; + } -Sign.prototype.update = function update (data, enc) { - if (typeof data === 'string') data = new Buffer(data, enc) + assert(sig.R && sig.S, 'Signature without R or S'); - this._hash.update(data) - return this -} + if (eddsa.isPoint(sig.R)) this._R = sig.R; + if (sig.S instanceof BN) this._S = sig.S; -Sign.prototype.sign = function signMethod (key, enc) { - this.end() - var hash = this._hash.digest() - var sig = sign(hash, key, this._hashType, this._signType, this._tag) + this._Rencoded = Array.isArray(sig.R) ? sig.R : sig.Rencoded; + this._Sencoded = Array.isArray(sig.S) ? sig.S : sig.Sencoded; + } - return enc ? sig.toString(enc) : sig -} + cachedProperty(Signature, 'S', function S() { + return this.eddsa.decodeInt(this.Sencoded()); + }); -function Verify (algorithm) { - stream.Writable.call(this) + cachedProperty(Signature, 'R', function R() { + return this.eddsa.decodePoint(this.Rencoded()); + }); - var data = algorithms[algorithm] - if (!data) throw new Error('Unknown message digest') + cachedProperty(Signature, 'Rencoded', function Rencoded() { + return this.eddsa.encodePoint(this.R()); + }); - this._hash = createHash(data.hash) - this._tag = data.id - this._signType = data.sign -} -inherits(Verify, stream.Writable) + cachedProperty(Signature, 'Sencoded', function Sencoded() { + return this.eddsa.encodeInt(this.S()); + }); -Verify.prototype._write = function _write (data, _, done) { - this._hash.update(data) - done() -} + Signature.prototype.toBytes = function toBytes() { + return this.Rencoded().concat(this.Sencoded()); + }; -Verify.prototype.update = function update (data, enc) { - if (typeof data === 'string') data = new Buffer(data, enc) + Signature.prototype.toHex = function toHex() { + return utils.encode(this.toBytes(), 'hex').toUpperCase(); + }; - this._hash.update(data) - return this -} + module.exports = Signature; + }, + { '../../elliptic': 93, 'bn.js': 92 }, + ], + 106: [ + function(require, module, exports) { + module.exports = { + doubles: { + step: 4, + points: [ + [ + 'e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a', + 'f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821', + ], + [ + '8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508', + '11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf', + ], + [ + '175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739', + 'd3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695', + ], + [ + '363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640', + '4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9', + ], + [ + '8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c', + '4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36', + ], + [ + '723cbaa6e5db996d6bf771c00bd548c7b700dbffa6c0e77bcb6115925232fcda', + '96e867b5595cc498a921137488824d6e2660a0653779494801dc069d9eb39f5f', + ], + [ + 'eebfa4d493bebf98ba5feec812c2d3b50947961237a919839a533eca0e7dd7fa', + '5d9a8ca3970ef0f269ee7edaf178089d9ae4cdc3a711f712ddfd4fdae1de8999', + ], + [ + '100f44da696e71672791d0a09b7bde459f1215a29b3c03bfefd7835b39a48db0', + 'cdd9e13192a00b772ec8f3300c090666b7ff4a18ff5195ac0fbd5cd62bc65a09', + ], + [ + 'e1031be262c7ed1b1dc9227a4a04c017a77f8d4464f3b3852c8acde6e534fd2d', + '9d7061928940405e6bb6a4176597535af292dd419e1ced79a44f18f29456a00d', + ], + [ + 'feea6cae46d55b530ac2839f143bd7ec5cf8b266a41d6af52d5e688d9094696d', + 'e57c6b6c97dce1bab06e4e12bf3ecd5c981c8957cc41442d3155debf18090088', + ], + [ + 'da67a91d91049cdcb367be4be6ffca3cfeed657d808583de33fa978bc1ec6cb1', + '9bacaa35481642bc41f463f7ec9780e5dec7adc508f740a17e9ea8e27a68be1d', + ], + [ + '53904faa0b334cdda6e000935ef22151ec08d0f7bb11069f57545ccc1a37b7c0', + '5bc087d0bc80106d88c9eccac20d3c1c13999981e14434699dcb096b022771c8', + ], + [ + '8e7bcd0bd35983a7719cca7764ca906779b53a043a9b8bcaeff959f43ad86047', + '10b7770b2a3da4b3940310420ca9514579e88e2e47fd68b3ea10047e8460372a', + ], + [ + '385eed34c1cdff21e6d0818689b81bde71a7f4f18397e6690a841e1599c43862', + '283bebc3e8ea23f56701de19e9ebf4576b304eec2086dc8cc0458fe5542e5453', + ], + [ + '6f9d9b803ecf191637c73a4413dfa180fddf84a5947fbc9c606ed86c3fac3a7', + '7c80c68e603059ba69b8e2a30e45c4d47ea4dd2f5c281002d86890603a842160', + ], + [ + '3322d401243c4e2582a2147c104d6ecbf774d163db0f5e5313b7e0e742d0e6bd', + '56e70797e9664ef5bfb019bc4ddaf9b72805f63ea2873af624f3a2e96c28b2a0', + ], + [ + '85672c7d2de0b7da2bd1770d89665868741b3f9af7643397721d74d28134ab83', + '7c481b9b5b43b2eb6374049bfa62c2e5e77f17fcc5298f44c8e3094f790313a6', + ], + [ + '948bf809b1988a46b06c9f1919413b10f9226c60f668832ffd959af60c82a0a', + '53a562856dcb6646dc6b74c5d1c3418c6d4dff08c97cd2bed4cb7f88d8c8e589', + ], + [ + '6260ce7f461801c34f067ce0f02873a8f1b0e44dfc69752accecd819f38fd8e8', + 'bc2da82b6fa5b571a7f09049776a1ef7ecd292238051c198c1a84e95b2b4ae17', + ], + [ + 'e5037de0afc1d8d43d8348414bbf4103043ec8f575bfdc432953cc8d2037fa2d', + '4571534baa94d3b5f9f98d09fb990bddbd5f5b03ec481f10e0e5dc841d755bda', + ], + [ + 'e06372b0f4a207adf5ea905e8f1771b4e7e8dbd1c6a6c5b725866a0ae4fce725', + '7a908974bce18cfe12a27bb2ad5a488cd7484a7787104870b27034f94eee31dd', + ], + [ + '213c7a715cd5d45358d0bbf9dc0ce02204b10bdde2a3f58540ad6908d0559754', + '4b6dad0b5ae462507013ad06245ba190bb4850f5f36a7eeddff2c27534b458f2', + ], + [ + '4e7c272a7af4b34e8dbb9352a5419a87e2838c70adc62cddf0cc3a3b08fbd53c', + '17749c766c9d0b18e16fd09f6def681b530b9614bff7dd33e0b3941817dcaae6', + ], + [ + 'fea74e3dbe778b1b10f238ad61686aa5c76e3db2be43057632427e2840fb27b6', + '6e0568db9b0b13297cf674deccb6af93126b596b973f7b77701d3db7f23cb96f', + ], + [ + '76e64113f677cf0e10a2570d599968d31544e179b760432952c02a4417bdde39', + 'c90ddf8dee4e95cf577066d70681f0d35e2a33d2b56d2032b4b1752d1901ac01', + ], + [ + 'c738c56b03b2abe1e8281baa743f8f9a8f7cc643df26cbee3ab150242bcbb891', + '893fb578951ad2537f718f2eacbfbbbb82314eef7880cfe917e735d9699a84c3', + ], + [ + 'd895626548b65b81e264c7637c972877d1d72e5f3a925014372e9f6588f6c14b', + 'febfaa38f2bc7eae728ec60818c340eb03428d632bb067e179363ed75d7d991f', + ], + [ + 'b8da94032a957518eb0f6433571e8761ceffc73693e84edd49150a564f676e03', + '2804dfa44805a1e4d7c99cc9762808b092cc584d95ff3b511488e4e74efdf6e7', + ], + [ + 'e80fea14441fb33a7d8adab9475d7fab2019effb5156a792f1a11778e3c0df5d', + 'eed1de7f638e00771e89768ca3ca94472d155e80af322ea9fcb4291b6ac9ec78', + ], + [ + 'a301697bdfcd704313ba48e51d567543f2a182031efd6915ddc07bbcc4e16070', + '7370f91cfb67e4f5081809fa25d40f9b1735dbf7c0a11a130c0d1a041e177ea1', + ], + [ + '90ad85b389d6b936463f9d0512678de208cc330b11307fffab7ac63e3fb04ed4', + 'e507a3620a38261affdcbd9427222b839aefabe1582894d991d4d48cb6ef150', + ], + [ + '8f68b9d2f63b5f339239c1ad981f162ee88c5678723ea3351b7b444c9ec4c0da', + '662a9f2dba063986de1d90c2b6be215dbbea2cfe95510bfdf23cbf79501fff82', + ], + [ + 'e4f3fb0176af85d65ff99ff9198c36091f48e86503681e3e6686fd5053231e11', + '1e63633ad0ef4f1c1661a6d0ea02b7286cc7e74ec951d1c9822c38576feb73bc', + ], + [ + '8c00fa9b18ebf331eb961537a45a4266c7034f2f0d4e1d0716fb6eae20eae29e', + 'efa47267fea521a1a9dc343a3736c974c2fadafa81e36c54e7d2a4c66702414b', + ], + [ + 'e7a26ce69dd4829f3e10cec0a9e98ed3143d084f308b92c0997fddfc60cb3e41', + '2a758e300fa7984b471b006a1aafbb18d0a6b2c0420e83e20e8a9421cf2cfd51', + ], + [ + 'b6459e0ee3662ec8d23540c223bcbdc571cbcb967d79424f3cf29eb3de6b80ef', + '67c876d06f3e06de1dadf16e5661db3c4b3ae6d48e35b2ff30bf0b61a71ba45', + ], + [ + 'd68a80c8280bb840793234aa118f06231d6f1fc67e73c5a5deda0f5b496943e8', + 'db8ba9fff4b586d00c4b1f9177b0e28b5b0e7b8f7845295a294c84266b133120', + ], + [ + '324aed7df65c804252dc0270907a30b09612aeb973449cea4095980fc28d3d5d', + '648a365774b61f2ff130c0c35aec1f4f19213b0c7e332843967224af96ab7c84', + ], + [ + '4df9c14919cde61f6d51dfdbe5fee5dceec4143ba8d1ca888e8bd373fd054c96', + '35ec51092d8728050974c23a1d85d4b5d506cdc288490192ebac06cad10d5d', + ], + [ + '9c3919a84a474870faed8a9c1cc66021523489054d7f0308cbfc99c8ac1f98cd', + 'ddb84f0f4a4ddd57584f044bf260e641905326f76c64c8e6be7e5e03d4fc599d', + ], + [ + '6057170b1dd12fdf8de05f281d8e06bb91e1493a8b91d4cc5a21382120a959e5', + '9a1af0b26a6a4807add9a2daf71df262465152bc3ee24c65e899be932385a2a8', + ], + [ + 'a576df8e23a08411421439a4518da31880cef0fba7d4df12b1a6973eecb94266', + '40a6bf20e76640b2c92b97afe58cd82c432e10a7f514d9f3ee8be11ae1b28ec8', + ], + [ + '7778a78c28dec3e30a05fe9629de8c38bb30d1f5cf9a3a208f763889be58ad71', + '34626d9ab5a5b22ff7098e12f2ff580087b38411ff24ac563b513fc1fd9f43ac', + ], + [ + '928955ee637a84463729fd30e7afd2ed5f96274e5ad7e5cb09eda9c06d903ac', + 'c25621003d3f42a827b78a13093a95eeac3d26efa8a8d83fc5180e935bcd091f', + ], + [ + '85d0fef3ec6db109399064f3a0e3b2855645b4a907ad354527aae75163d82751', + '1f03648413a38c0be29d496e582cf5663e8751e96877331582c237a24eb1f962', + ], + [ + 'ff2b0dce97eece97c1c9b6041798b85dfdfb6d8882da20308f5404824526087e', + '493d13fef524ba188af4c4dc54d07936c7b7ed6fb90e2ceb2c951e01f0c29907', + ], + [ + '827fbbe4b1e880ea9ed2b2e6301b212b57f1ee148cd6dd28780e5e2cf856e241', + 'c60f9c923c727b0b71bef2c67d1d12687ff7a63186903166d605b68baec293ec', + ], + [ + 'eaa649f21f51bdbae7be4ae34ce6e5217a58fdce7f47f9aa7f3b58fa2120e2b3', + 'be3279ed5bbbb03ac69a80f89879aa5a01a6b965f13f7e59d47a5305ba5ad93d', + ], + [ + 'e4a42d43c5cf169d9391df6decf42ee541b6d8f0c9a137401e23632dda34d24f', + '4d9f92e716d1c73526fc99ccfb8ad34ce886eedfa8d8e4f13a7f7131deba9414', + ], + [ + '1ec80fef360cbdd954160fadab352b6b92b53576a88fea4947173b9d4300bf19', + 'aeefe93756b5340d2f3a4958a7abbf5e0146e77f6295a07b671cdc1cc107cefd', + ], + [ + '146a778c04670c2f91b00af4680dfa8bce3490717d58ba889ddb5928366642be', + 'b318e0ec3354028add669827f9d4b2870aaa971d2f7e5ed1d0b297483d83efd0', + ], + [ + 'fa50c0f61d22e5f07e3acebb1aa07b128d0012209a28b9776d76a8793180eef9', + '6b84c6922397eba9b72cd2872281a68a5e683293a57a213b38cd8d7d3f4f2811', + ], + [ + 'da1d61d0ca721a11b1a5bf6b7d88e8421a288ab5d5bba5220e53d32b5f067ec2', + '8157f55a7c99306c79c0766161c91e2966a73899d279b48a655fba0f1ad836f1', + ], + [ + 'a8e282ff0c9706907215ff98e8fd416615311de0446f1e062a73b0610d064e13', + '7f97355b8db81c09abfb7f3c5b2515888b679a3e50dd6bd6cef7c73111f4cc0c', + ], + [ + '174a53b9c9a285872d39e56e6913cab15d59b1fa512508c022f382de8319497c', + 'ccc9dc37abfc9c1657b4155f2c47f9e6646b3a1d8cb9854383da13ac079afa73', + ], + [ + '959396981943785c3d3e57edf5018cdbe039e730e4918b3d884fdff09475b7ba', + '2e7e552888c331dd8ba0386a4b9cd6849c653f64c8709385e9b8abf87524f2fd', + ], + [ + 'd2a63a50ae401e56d645a1153b109a8fcca0a43d561fba2dbb51340c9d82b151', + 'e82d86fb6443fcb7565aee58b2948220a70f750af484ca52d4142174dcf89405', + ], + [ + '64587e2335471eb890ee7896d7cfdc866bacbdbd3839317b3436f9b45617e073', + 'd99fcdd5bf6902e2ae96dd6447c299a185b90a39133aeab358299e5e9faf6589', + ], + [ + '8481bde0e4e4d885b3a546d3e549de042f0aa6cea250e7fd358d6c86dd45e458', + '38ee7b8cba5404dd84a25bf39cecb2ca900a79c42b262e556d64b1b59779057e', + ], + [ + '13464a57a78102aa62b6979ae817f4637ffcfed3c4b1ce30bcd6303f6caf666b', + '69be159004614580ef7e433453ccb0ca48f300a81d0942e13f495a907f6ecc27', + ], + [ + 'bc4a9df5b713fe2e9aef430bcc1dc97a0cd9ccede2f28588cada3a0d2d83f366', + 'd3a81ca6e785c06383937adf4b798caa6e8a9fbfa547b16d758d666581f33c1', + ], + [ + '8c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa', + '40a30463a3305193378fedf31f7cc0eb7ae784f0451cb9459e71dc73cbef9482', + ], + [ + '8ea9666139527a8c1dd94ce4f071fd23c8b350c5a4bb33748c4ba111faccae0', + '620efabbc8ee2782e24e7c0cfb95c5d735b783be9cf0f8e955af34a30e62b945', + ], + [ + 'dd3625faef5ba06074669716bbd3788d89bdde815959968092f76cc4eb9a9787', + '7a188fa3520e30d461da2501045731ca941461982883395937f68d00c644a573', + ], + [ + 'f710d79d9eb962297e4f6232b40e8f7feb2bc63814614d692c12de752408221e', + 'ea98e67232d3b3295d3b535532115ccac8612c721851617526ae47a9c77bfc82', + ], + ], + }, + naf: { + wnd: 7, + points: [ + [ + 'f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9', + '388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672', + ], + [ + '2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4', + 'd8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6', + ], + [ + '5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc', + '6aebca40ba255960a3178d6d861a54dba813d0b813fde7b5a5082628087264da', + ], + [ + 'acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe', + 'cc338921b0a7d9fd64380971763b61e9add888a4375f8e0f05cc262ac64f9c37', + ], + [ + '774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb', + 'd984a032eb6b5e190243dd56d7b7b365372db1e2dff9d6a8301d74c9c953c61b', + ], + [ + 'f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8', + 'ab0902e8d880a89758212eb65cdaf473a1a06da521fa91f29b5cb52db03ed81', + ], + [ + 'd7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e', + '581e2872a86c72a683842ec228cc6defea40af2bd896d3a5c504dc9ff6a26b58', + ], + [ + 'defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34', + '4211ab0694635168e997b0ead2a93daeced1f4a04a95c0f6cfb199f69e56eb77', + ], + [ + '2b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c', + '85e89bc037945d93b343083b5a1c86131a01f60c50269763b570c854e5c09b7a', + ], + [ + '352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5', + '321eb4075348f534d59c18259dda3e1f4a1b3b2e71b1039c67bd3d8bcf81998c', + ], + [ + '2fa2104d6b38d11b0230010559879124e42ab8dfeff5ff29dc9cdadd4ecacc3f', + '2de1068295dd865b64569335bd5dd80181d70ecfc882648423ba76b532b7d67', + ], + [ + '9248279b09b4d68dab21a9b066edda83263c3d84e09572e269ca0cd7f5453714', + '73016f7bf234aade5d1aa71bdea2b1ff3fc0de2a887912ffe54a32ce97cb3402', + ], + [ + 'daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729', + 'a69dce4a7d6c98e8d4a1aca87ef8d7003f83c230f3afa726ab40e52290be1c55', + ], + [ + 'c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db', + '2119a460ce326cdc76c45926c982fdac0e106e861edf61c5a039063f0e0e6482', + ], + [ + '6a245bf6dc698504c89a20cfded60853152b695336c28063b61c65cbd269e6b4', + 'e022cf42c2bd4a708b3f5126f16a24ad8b33ba48d0423b6efd5e6348100d8a82', + ], + [ + '1697ffa6fd9de627c077e3d2fe541084ce13300b0bec1146f95ae57f0d0bd6a5', + 'b9c398f186806f5d27561506e4557433a2cf15009e498ae7adee9d63d01b2396', + ], + [ + '605bdb019981718b986d0f07e834cb0d9deb8360ffb7f61df982345ef27a7479', + '2972d2de4f8d20681a78d93ec96fe23c26bfae84fb14db43b01e1e9056b8c49', + ], + [ + '62d14dab4150bf497402fdc45a215e10dcb01c354959b10cfe31c7e9d87ff33d', + '80fc06bd8cc5b01098088a1950eed0db01aa132967ab472235f5642483b25eaf', + ], + [ + '80c60ad0040f27dade5b4b06c408e56b2c50e9f56b9b8b425e555c2f86308b6f', + '1c38303f1cc5c30f26e66bad7fe72f70a65eed4cbe7024eb1aa01f56430bd57a', + ], + [ + '7a9375ad6167ad54aa74c6348cc54d344cc5dc9487d847049d5eabb0fa03c8fb', + 'd0e3fa9eca8726909559e0d79269046bdc59ea10c70ce2b02d499ec224dc7f7', + ], + [ + 'd528ecd9b696b54c907a9ed045447a79bb408ec39b68df504bb51f459bc3ffc9', + 'eecf41253136e5f99966f21881fd656ebc4345405c520dbc063465b521409933', + ], + [ + '49370a4b5f43412ea25f514e8ecdad05266115e4a7ecb1387231808f8b45963', + '758f3f41afd6ed428b3081b0512fd62a54c3f3afbb5b6764b653052a12949c9a', + ], + [ + '77f230936ee88cbbd73df930d64702ef881d811e0e1498e2f1c13eb1fc345d74', + '958ef42a7886b6400a08266e9ba1b37896c95330d97077cbbe8eb3c7671c60d6', + ], + [ + 'f2dac991cc4ce4b9ea44887e5c7c0bce58c80074ab9d4dbaeb28531b7739f530', + 'e0dedc9b3b2f8dad4da1f32dec2531df9eb5fbeb0598e4fd1a117dba703a3c37', + ], + [ + '463b3d9f662621fb1b4be8fbbe2520125a216cdfc9dae3debcba4850c690d45b', + '5ed430d78c296c3543114306dd8622d7c622e27c970a1de31cb377b01af7307e', + ], + [ + 'f16f804244e46e2a09232d4aff3b59976b98fac14328a2d1a32496b49998f247', + 'cedabd9b82203f7e13d206fcdf4e33d92a6c53c26e5cce26d6579962c4e31df6', + ], + [ + 'caf754272dc84563b0352b7a14311af55d245315ace27c65369e15f7151d41d1', + 'cb474660ef35f5f2a41b643fa5e460575f4fa9b7962232a5c32f908318a04476', + ], + [ + '2600ca4b282cb986f85d0f1709979d8b44a09c07cb86d7c124497bc86f082120', + '4119b88753c15bd6a693b03fcddbb45d5ac6be74ab5f0ef44b0be9475a7e4b40', + ], + [ + '7635ca72d7e8432c338ec53cd12220bc01c48685e24f7dc8c602a7746998e435', + '91b649609489d613d1d5e590f78e6d74ecfc061d57048bad9e76f302c5b9c61', + ], + [ + '754e3239f325570cdbbf4a87deee8a66b7f2b33479d468fbc1a50743bf56cc18', + '673fb86e5bda30fb3cd0ed304ea49a023ee33d0197a695d0c5d98093c536683', + ], + [ + 'e3e6bd1071a1e96aff57859c82d570f0330800661d1c952f9fe2694691d9b9e8', + '59c9e0bba394e76f40c0aa58379a3cb6a5a2283993e90c4167002af4920e37f5', + ], + [ + '186b483d056a033826ae73d88f732985c4ccb1f32ba35f4b4cc47fdcf04aa6eb', + '3b952d32c67cf77e2e17446e204180ab21fb8090895138b4a4a797f86e80888b', + ], + [ + 'df9d70a6b9876ce544c98561f4be4f725442e6d2b737d9c91a8321724ce0963f', + '55eb2dafd84d6ccd5f862b785dc39d4ab157222720ef9da217b8c45cf2ba2417', + ], + [ + '5edd5cc23c51e87a497ca815d5dce0f8ab52554f849ed8995de64c5f34ce7143', + 'efae9c8dbc14130661e8cec030c89ad0c13c66c0d17a2905cdc706ab7399a868', + ], + [ + '290798c2b6476830da12fe02287e9e777aa3fba1c355b17a722d362f84614fba', + 'e38da76dcd440621988d00bcf79af25d5b29c094db2a23146d003afd41943e7a', + ], + [ + 'af3c423a95d9f5b3054754efa150ac39cd29552fe360257362dfdecef4053b45', + 'f98a3fd831eb2b749a93b0e6f35cfb40c8cd5aa667a15581bc2feded498fd9c6', + ], + [ + '766dbb24d134e745cccaa28c99bf274906bb66b26dcf98df8d2fed50d884249a', + '744b1152eacbe5e38dcc887980da38b897584a65fa06cedd2c924f97cbac5996', + ], + [ + '59dbf46f8c94759ba21277c33784f41645f7b44f6c596a58ce92e666191abe3e', + 'c534ad44175fbc300f4ea6ce648309a042ce739a7919798cd85e216c4a307f6e', + ], + [ + 'f13ada95103c4537305e691e74e9a4a8dd647e711a95e73cb62dc6018cfd87b8', + 'e13817b44ee14de663bf4bc808341f326949e21a6a75c2570778419bdaf5733d', + ], + [ + '7754b4fa0e8aced06d4167a2c59cca4cda1869c06ebadfb6488550015a88522c', + '30e93e864e669d82224b967c3020b8fa8d1e4e350b6cbcc537a48b57841163a2', + ], + [ + '948dcadf5990e048aa3874d46abef9d701858f95de8041d2a6828c99e2262519', + 'e491a42537f6e597d5d28a3224b1bc25df9154efbd2ef1d2cbba2cae5347d57e', + ], + [ + '7962414450c76c1689c7b48f8202ec37fb224cf5ac0bfa1570328a8a3d7c77ab', + '100b610ec4ffb4760d5c1fc133ef6f6b12507a051f04ac5760afa5b29db83437', + ], + [ + '3514087834964b54b15b160644d915485a16977225b8847bb0dd085137ec47ca', + 'ef0afbb2056205448e1652c48e8127fc6039e77c15c2378b7e7d15a0de293311', + ], + [ + 'd3cc30ad6b483e4bc79ce2c9dd8bc54993e947eb8df787b442943d3f7b527eaf', + '8b378a22d827278d89c5e9be8f9508ae3c2ad46290358630afb34db04eede0a4', + ], + [ + '1624d84780732860ce1c78fcbfefe08b2b29823db913f6493975ba0ff4847610', + '68651cf9b6da903e0914448c6cd9d4ca896878f5282be4c8cc06e2a404078575', + ], + [ + '733ce80da955a8a26902c95633e62a985192474b5af207da6df7b4fd5fc61cd4', + 'f5435a2bd2badf7d485a4d8b8db9fcce3e1ef8e0201e4578c54673bc1dc5ea1d', + ], + [ + '15d9441254945064cf1a1c33bbd3b49f8966c5092171e699ef258dfab81c045c', + 'd56eb30b69463e7234f5137b73b84177434800bacebfc685fc37bbe9efe4070d', + ], + [ + 'a1d0fcf2ec9de675b612136e5ce70d271c21417c9d2b8aaaac138599d0717940', + 'edd77f50bcb5a3cab2e90737309667f2641462a54070f3d519212d39c197a629', + ], + [ + 'e22fbe15c0af8ccc5780c0735f84dbe9a790badee8245c06c7ca37331cb36980', + 'a855babad5cd60c88b430a69f53a1a7a38289154964799be43d06d77d31da06', + ], + [ + '311091dd9860e8e20ee13473c1155f5f69635e394704eaa74009452246cfa9b3', + '66db656f87d1f04fffd1f04788c06830871ec5a64feee685bd80f0b1286d8374', + ], + [ + '34c1fd04d301be89b31c0442d3e6ac24883928b45a9340781867d4232ec2dbdf', + '9414685e97b1b5954bd46f730174136d57f1ceeb487443dc5321857ba73abee', + ], + [ + 'f219ea5d6b54701c1c14de5b557eb42a8d13f3abbcd08affcc2a5e6b049b8d63', + '4cb95957e83d40b0f73af4544cccf6b1f4b08d3c07b27fb8d8c2962a400766d1', + ], + [ + 'd7b8740f74a8fbaab1f683db8f45de26543a5490bca627087236912469a0b448', + 'fa77968128d9c92ee1010f337ad4717eff15db5ed3c049b3411e0315eaa4593b', + ], + [ + '32d31c222f8f6f0ef86f7c98d3a3335ead5bcd32abdd94289fe4d3091aa824bf', + '5f3032f5892156e39ccd3d7915b9e1da2e6dac9e6f26e961118d14b8462e1661', + ], + [ + '7461f371914ab32671045a155d9831ea8793d77cd59592c4340f86cbc18347b5', + '8ec0ba238b96bec0cbdddcae0aa442542eee1ff50c986ea6b39847b3cc092ff6', + ], + [ + 'ee079adb1df1860074356a25aa38206a6d716b2c3e67453d287698bad7b2b2d6', + '8dc2412aafe3be5c4c5f37e0ecc5f9f6a446989af04c4e25ebaac479ec1c8c1e', + ], + [ + '16ec93e447ec83f0467b18302ee620f7e65de331874c9dc72bfd8616ba9da6b5', + '5e4631150e62fb40d0e8c2a7ca5804a39d58186a50e497139626778e25b0674d', + ], + [ + 'eaa5f980c245f6f038978290afa70b6bd8855897f98b6aa485b96065d537bd99', + 'f65f5d3e292c2e0819a528391c994624d784869d7e6ea67fb18041024edc07dc', + ], + [ + '78c9407544ac132692ee1910a02439958ae04877151342ea96c4b6b35a49f51', + 'f3e0319169eb9b85d5404795539a5e68fa1fbd583c064d2462b675f194a3ddb4', + ], + [ + '494f4be219a1a77016dcd838431aea0001cdc8ae7a6fc688726578d9702857a5', + '42242a969283a5f339ba7f075e36ba2af925ce30d767ed6e55f4b031880d562c', + ], + [ + 'a598a8030da6d86c6bc7f2f5144ea549d28211ea58faa70ebf4c1e665c1fe9b5', + '204b5d6f84822c307e4b4a7140737aec23fc63b65b35f86a10026dbd2d864e6b', + ], + [ + 'c41916365abb2b5d09192f5f2dbeafec208f020f12570a184dbadc3e58595997', + '4f14351d0087efa49d245b328984989d5caf9450f34bfc0ed16e96b58fa9913', + ], + [ + '841d6063a586fa475a724604da03bc5b92a2e0d2e0a36acfe4c73a5514742881', + '73867f59c0659e81904f9a1c7543698e62562d6744c169ce7a36de01a8d6154', + ], + [ + '5e95bb399a6971d376026947f89bde2f282b33810928be4ded112ac4d70e20d5', + '39f23f366809085beebfc71181313775a99c9aed7d8ba38b161384c746012865', + ], + [ + '36e4641a53948fd476c39f8a99fd974e5ec07564b5315d8bf99471bca0ef2f66', + 'd2424b1b1abe4eb8164227b085c9aa9456ea13493fd563e06fd51cf5694c78fc', + ], + [ + '336581ea7bfbbb290c191a2f507a41cf5643842170e914faeab27c2c579f726', + 'ead12168595fe1be99252129b6e56b3391f7ab1410cd1e0ef3dcdcabd2fda224', + ], + [ + '8ab89816dadfd6b6a1f2634fcf00ec8403781025ed6890c4849742706bd43ede', + '6fdcef09f2f6d0a044e654aef624136f503d459c3e89845858a47a9129cdd24e', + ], + [ + '1e33f1a746c9c5778133344d9299fcaa20b0938e8acff2544bb40284b8c5fb94', + '60660257dd11b3aa9c8ed618d24edff2306d320f1d03010e33a7d2057f3b3b6', + ], + [ + '85b7c1dcb3cec1b7ee7f30ded79dd20a0ed1f4cc18cbcfcfa410361fd8f08f31', + '3d98a9cdd026dd43f39048f25a8847f4fcafad1895d7a633c6fed3c35e999511', + ], + [ + '29df9fbd8d9e46509275f4b125d6d45d7fbe9a3b878a7af872a2800661ac5f51', + 'b4c4fe99c775a606e2d8862179139ffda61dc861c019e55cd2876eb2a27d84b', + ], + [ + 'a0b1cae06b0a847a3fea6e671aaf8adfdfe58ca2f768105c8082b2e449fce252', + 'ae434102edde0958ec4b19d917a6a28e6b72da1834aff0e650f049503a296cf2', + ], + [ + '4e8ceafb9b3e9a136dc7ff67e840295b499dfb3b2133e4ba113f2e4c0e121e5', + 'cf2174118c8b6d7a4b48f6d534ce5c79422c086a63460502b827ce62a326683c', + ], + [ + 'd24a44e047e19b6f5afb81c7ca2f69080a5076689a010919f42725c2b789a33b', + '6fb8d5591b466f8fc63db50f1c0f1c69013f996887b8244d2cdec417afea8fa3', + ], + [ + 'ea01606a7a6c9cdd249fdfcfacb99584001edd28abbab77b5104e98e8e3b35d4', + '322af4908c7312b0cfbfe369f7a7b3cdb7d4494bc2823700cfd652188a3ea98d', + ], + [ + 'af8addbf2b661c8a6c6328655eb96651252007d8c5ea31be4ad196de8ce2131f', + '6749e67c029b85f52a034eafd096836b2520818680e26ac8f3dfbcdb71749700', + ], + [ + 'e3ae1974566ca06cc516d47e0fb165a674a3dabcfca15e722f0e3450f45889', + '2aeabe7e4531510116217f07bf4d07300de97e4874f81f533420a72eeb0bd6a4', + ], + [ + '591ee355313d99721cf6993ffed1e3e301993ff3ed258802075ea8ced397e246', + 'b0ea558a113c30bea60fc4775460c7901ff0b053d25ca2bdeee98f1a4be5d196', + ], + [ + '11396d55fda54c49f19aa97318d8da61fa8584e47b084945077cf03255b52984', + '998c74a8cd45ac01289d5833a7beb4744ff536b01b257be4c5767bea93ea57a4', + ], + [ + '3c5d2a1ba39c5a1790000738c9e0c40b8dcdfd5468754b6405540157e017aa7a', + 'b2284279995a34e2f9d4de7396fc18b80f9b8b9fdd270f6661f79ca4c81bd257', + ], + [ + 'cc8704b8a60a0defa3a99a7299f2e9c3fbc395afb04ac078425ef8a1793cc030', + 'bdd46039feed17881d1e0862db347f8cf395b74fc4bcdc4e940b74e3ac1f1b13', + ], + [ + 'c533e4f7ea8555aacd9777ac5cad29b97dd4defccc53ee7ea204119b2889b197', + '6f0a256bc5efdf429a2fb6242f1a43a2d9b925bb4a4b3a26bb8e0f45eb596096', + ], + [ + 'c14f8f2ccb27d6f109f6d08d03cc96a69ba8c34eec07bbcf566d48e33da6593', + 'c359d6923bb398f7fd4473e16fe1c28475b740dd098075e6c0e8649113dc3a38', + ], + [ + 'a6cbc3046bc6a450bac24789fa17115a4c9739ed75f8f21ce441f72e0b90e6ef', + '21ae7f4680e889bb130619e2c0f95a360ceb573c70603139862afd617fa9b9f', + ], + [ + '347d6d9a02c48927ebfb86c1359b1caf130a3c0267d11ce6344b39f99d43cc38', + '60ea7f61a353524d1c987f6ecec92f086d565ab687870cb12689ff1e31c74448', + ], + [ + 'da6545d2181db8d983f7dcb375ef5866d47c67b1bf31c8cf855ef7437b72656a', + '49b96715ab6878a79e78f07ce5680c5d6673051b4935bd897fea824b77dc208a', + ], + [ + 'c40747cc9d012cb1a13b8148309c6de7ec25d6945d657146b9d5994b8feb1111', + '5ca560753be2a12fc6de6caf2cb489565db936156b9514e1bb5e83037e0fa2d4', + ], + [ + '4e42c8ec82c99798ccf3a610be870e78338c7f713348bd34c8203ef4037f3502', + '7571d74ee5e0fb92a7a8b33a07783341a5492144cc54bcc40a94473693606437', + ], + [ + '3775ab7089bc6af823aba2e1af70b236d251cadb0c86743287522a1b3b0dedea', + 'be52d107bcfa09d8bcb9736a828cfa7fac8db17bf7a76a2c42ad961409018cf7', + ], + [ + 'cee31cbf7e34ec379d94fb814d3d775ad954595d1314ba8846959e3e82f74e26', + '8fd64a14c06b589c26b947ae2bcf6bfa0149ef0be14ed4d80f448a01c43b1c6d', + ], + [ + 'b4f9eaea09b6917619f6ea6a4eb5464efddb58fd45b1ebefcdc1a01d08b47986', + '39e5c9925b5a54b07433a4f18c61726f8bb131c012ca542eb24a8ac07200682a', + ], + [ + 'd4263dfc3d2df923a0179a48966d30ce84e2515afc3dccc1b77907792ebcc60e', + '62dfaf07a0f78feb30e30d6295853ce189e127760ad6cf7fae164e122a208d54', + ], + [ + '48457524820fa65a4f8d35eb6930857c0032acc0a4a2de422233eeda897612c4', + '25a748ab367979d98733c38a1fa1c2e7dc6cc07db2d60a9ae7a76aaa49bd0f77', + ], + [ + 'dfeeef1881101f2cb11644f3a2afdfc2045e19919152923f367a1767c11cceda', + 'ecfb7056cf1de042f9420bab396793c0c390bde74b4bbdff16a83ae09a9a7517', + ], + [ + '6d7ef6b17543f8373c573f44e1f389835d89bcbc6062ced36c82df83b8fae859', + 'cd450ec335438986dfefa10c57fea9bcc521a0959b2d80bbf74b190dca712d10', + ], + [ + 'e75605d59102a5a2684500d3b991f2e3f3c88b93225547035af25af66e04541f', + 'f5c54754a8f71ee540b9b48728473e314f729ac5308b06938360990e2bfad125', + ], + [ + 'eb98660f4c4dfaa06a2be453d5020bc99a0c2e60abe388457dd43fefb1ed620c', + '6cb9a8876d9cb8520609af3add26cd20a0a7cd8a9411131ce85f44100099223e', + ], + [ + '13e87b027d8514d35939f2e6892b19922154596941888336dc3563e3b8dba942', + 'fef5a3c68059a6dec5d624114bf1e91aac2b9da568d6abeb2570d55646b8adf1', + ], + [ + 'ee163026e9fd6fe017c38f06a5be6fc125424b371ce2708e7bf4491691e5764a', + '1acb250f255dd61c43d94ccc670d0f58f49ae3fa15b96623e5430da0ad6c62b2', + ], + [ + 'b268f5ef9ad51e4d78de3a750c2dc89b1e626d43505867999932e5db33af3d80', + '5f310d4b3c99b9ebb19f77d41c1dee018cf0d34fd4191614003e945a1216e423', + ], + [ + 'ff07f3118a9df035e9fad85eb6c7bfe42b02f01ca99ceea3bf7ffdba93c4750d', + '438136d603e858a3a5c440c38eccbaddc1d2942114e2eddd4740d098ced1f0d8', + ], + [ + '8d8b9855c7c052a34146fd20ffb658bea4b9f69e0d825ebec16e8c3ce2b526a1', + 'cdb559eedc2d79f926baf44fb84ea4d44bcf50fee51d7ceb30e2e7f463036758', + ], + [ + '52db0b5384dfbf05bfa9d472d7ae26dfe4b851ceca91b1eba54263180da32b63', + 'c3b997d050ee5d423ebaf66a6db9f57b3180c902875679de924b69d84a7b375', + ], + [ + 'e62f9490d3d51da6395efd24e80919cc7d0f29c3f3fa48c6fff543becbd43352', + '6d89ad7ba4876b0b22c2ca280c682862f342c8591f1daf5170e07bfd9ccafa7d', + ], + [ + '7f30ea2476b399b4957509c88f77d0191afa2ff5cb7b14fd6d8e7d65aaab1193', + 'ca5ef7d4b231c94c3b15389a5f6311e9daff7bb67b103e9880ef4bff637acaec', + ], + [ + '5098ff1e1d9f14fb46a210fada6c903fef0fb7b4a1dd1d9ac60a0361800b7a00', + '9731141d81fc8f8084d37c6e7542006b3ee1b40d60dfe5362a5b132fd17ddc0', + ], + [ + '32b78c7de9ee512a72895be6b9cbefa6e2f3c4ccce445c96b9f2c81e2778ad58', + 'ee1849f513df71e32efc3896ee28260c73bb80547ae2275ba497237794c8753c', + ], + [ + 'e2cb74fddc8e9fbcd076eef2a7c72b0ce37d50f08269dfc074b581550547a4f7', + 'd3aa2ed71c9dd2247a62df062736eb0baddea9e36122d2be8641abcb005cc4a4', + ], + [ + '8438447566d4d7bedadc299496ab357426009a35f235cb141be0d99cd10ae3a8', + 'c4e1020916980a4da5d01ac5e6ad330734ef0d7906631c4f2390426b2edd791f', + ], + [ + '4162d488b89402039b584c6fc6c308870587d9c46f660b878ab65c82c711d67e', + '67163e903236289f776f22c25fb8a3afc1732f2b84b4e95dbda47ae5a0852649', + ], + [ + '3fad3fa84caf0f34f0f89bfd2dcf54fc175d767aec3e50684f3ba4a4bf5f683d', + 'cd1bc7cb6cc407bb2f0ca647c718a730cf71872e7d0d2a53fa20efcdfe61826', + ], + [ + '674f2600a3007a00568c1a7ce05d0816c1fb84bf1370798f1c69532faeb1a86b', + '299d21f9413f33b3edf43b257004580b70db57da0b182259e09eecc69e0d38a5', + ], + [ + 'd32f4da54ade74abb81b815ad1fb3b263d82d6c692714bcff87d29bd5ee9f08f', + 'f9429e738b8e53b968e99016c059707782e14f4535359d582fc416910b3eea87', + ], + [ + '30e4e670435385556e593657135845d36fbb6931f72b08cb1ed954f1e3ce3ff6', + '462f9bce619898638499350113bbc9b10a878d35da70740dc695a559eb88db7b', + ], + [ + 'be2062003c51cc3004682904330e4dee7f3dcd10b01e580bf1971b04d4cad297', + '62188bc49d61e5428573d48a74e1c655b1c61090905682a0d5558ed72dccb9bc', + ], + [ + '93144423ace3451ed29e0fb9ac2af211cb6e84a601df5993c419859fff5df04a', + '7c10dfb164c3425f5c71a3f9d7992038f1065224f72bb9d1d902a6d13037b47c', + ], + [ + 'b015f8044f5fcbdcf21ca26d6c34fb8197829205c7b7d2a7cb66418c157b112c', + 'ab8c1e086d04e813744a655b2df8d5f83b3cdc6faa3088c1d3aea1454e3a1d5f', + ], + [ + 'd5e9e1da649d97d89e4868117a465a3a4f8a18de57a140d36b3f2af341a21b52', + '4cb04437f391ed73111a13cc1d4dd0db1693465c2240480d8955e8592f27447a', + ], + [ + 'd3ae41047dd7ca065dbf8ed77b992439983005cd72e16d6f996a5316d36966bb', + 'bd1aeb21ad22ebb22a10f0303417c6d964f8cdd7df0aca614b10dc14d125ac46', + ], + [ + '463e2763d885f958fc66cdd22800f0a487197d0a82e377b49f80af87c897b065', + 'bfefacdb0e5d0fd7df3a311a94de062b26b80c61fbc97508b79992671ef7ca7f', + ], + [ + '7985fdfd127c0567c6f53ec1bb63ec3158e597c40bfe747c83cddfc910641917', + '603c12daf3d9862ef2b25fe1de289aed24ed291e0ec6708703a5bd567f32ed03', + ], + [ + '74a1ad6b5f76e39db2dd249410eac7f99e74c59cb83d2d0ed5ff1543da7703e9', + 'cc6157ef18c9c63cd6193d83631bbea0093e0968942e8c33d5737fd790e0db08', + ], + [ + '30682a50703375f602d416664ba19b7fc9bab42c72747463a71d0896b22f6da3', + '553e04f6b018b4fa6c8f39e7f311d3176290d0e0f19ca73f17714d9977a22ff8', + ], + [ + '9e2158f0d7c0d5f26c3791efefa79597654e7a2b2464f52b1ee6c1347769ef57', + '712fcdd1b9053f09003a3481fa7762e9ffd7c8ef35a38509e2fbf2629008373', + ], + [ + '176e26989a43c9cfeba4029c202538c28172e566e3c4fce7322857f3be327d66', + 'ed8cc9d04b29eb877d270b4878dc43c19aefd31f4eee09ee7b47834c1fa4b1c3', + ], + [ + '75d46efea3771e6e68abb89a13ad747ecf1892393dfc4f1b7004788c50374da8', + '9852390a99507679fd0b86fd2b39a868d7efc22151346e1a3ca4726586a6bed8', + ], + [ + '809a20c67d64900ffb698c4c825f6d5f2310fb0451c869345b7319f645605721', + '9e994980d9917e22b76b061927fa04143d096ccc54963e6a5ebfa5f3f8e286c1', + ], + [ + '1b38903a43f7f114ed4500b4eac7083fdefece1cf29c63528d563446f972c180', + '4036edc931a60ae889353f77fd53de4a2708b26b6f5da72ad3394119daf408f9', + ], + ], + }, + }; + }, + {}, + ], + 107: [ + function(require, module, exports) { + 'use strict'; + + var utils = exports; + var BN = require('bn.js'); + var minAssert = require('minimalistic-assert'); + var minUtils = require('minimalistic-crypto-utils'); + + utils.assert = minAssert; + utils.toArray = minUtils.toArray; + utils.zero2 = minUtils.zero2; + utils.toHex = minUtils.toHex; + utils.encode = minUtils.encode; + + // Represent num in a w-NAF form + function getNAF(num, w) { + var naf = []; + var ws = 1 << (w + 1); + var k = num.clone(); + while (k.cmpn(1) >= 0) { + var z; + if (k.isOdd()) { + var mod = k.andln(ws - 1); + if (mod > (ws >> 1) - 1) z = (ws >> 1) - mod; + else z = mod; + k.isubn(z); + } else { + z = 0; + } + naf.push(z); -Verify.prototype.verify = function verifyMethod (key, sig, enc) { - if (typeof sig === 'string') sig = new Buffer(sig, enc) + // Optimization, shift by word if possible + var shift = k.cmpn(0) !== 0 && k.andln(ws - 1) === 0 ? w + 1 : 1; + for (var i = 1; i < shift; i++) naf.push(0); + k.iushrn(shift); + } - this.end() - var hash = this._hash.digest() - return verify(sig, hash, key, this._signType, this._tag) -} + return naf; + } + utils.getNAF = getNAF; + + // Represent k1, k2 in a Joint Sparse Form + function getJSF(k1, k2) { + var jsf = [[], []]; + + k1 = k1.clone(); + k2 = k2.clone(); + var d1 = 0; + var d2 = 0; + while (k1.cmpn(-d1) > 0 || k2.cmpn(-d2) > 0) { + // First phase + var m14 = (k1.andln(3) + d1) & 3; + var m24 = (k2.andln(3) + d2) & 3; + if (m14 === 3) m14 = -1; + if (m24 === 3) m24 = -1; + var u1; + if ((m14 & 1) === 0) { + u1 = 0; + } else { + var m8 = (k1.andln(7) + d1) & 7; + if ((m8 === 3 || m8 === 5) && m24 === 2) u1 = -m14; + else u1 = m14; + } + jsf[0].push(u1); -function createSign (algorithm) { - return new Sign(algorithm) -} + var u2; + if ((m24 & 1) === 0) { + u2 = 0; + } else { + var m8 = (k2.andln(7) + d2) & 7; + if ((m8 === 3 || m8 === 5) && m14 === 2) u2 = -m24; + else u2 = m24; + } + jsf[1].push(u2); -function createVerify (algorithm) { - return new Verify(algorithm) -} + // Second phase + if (2 * d1 === u1 + 1) d1 = 1 - d1; + if (2 * d2 === u2 + 1) d2 = 1 - d2; + k1.iushrn(1); + k2.iushrn(1); + } -module.exports = { - Sign: createSign, - Verify: createVerify, - createSign: createSign, - createVerify: createVerify -} + return jsf; + } + utils.getJSF = getJSF; -}).call(this,require("buffer").Buffer) -},{"./algorithms.json":87,"./sign":90,"./verify":91,"buffer":113,"create-hash":134,"inherits":184,"stream":242}],90:[function(require,module,exports){ -(function (Buffer){ -// much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js -var createHmac = require('create-hmac') -var crt = require('browserify-rsa') -var EC = require('elliptic').ec -var BN = require('bn.js') -var parseKeys = require('parse-asn1') -var curves = require('./curves.json') - -function sign (hash, key, hashType, signType, tag) { - var priv = parseKeys(key) - if (priv.curve) { - // rsa keys can be interpreted as ecdsa ones in openssl - if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') throw new Error('wrong private key type') - return ecSign(hash, priv) - } else if (priv.type === 'dsa') { - if (signType !== 'dsa') throw new Error('wrong private key type') - return dsaSign(hash, priv, hashType) - } else { - if (signType !== 'rsa' && signType !== 'ecdsa/rsa') throw new Error('wrong private key type') - } - hash = Buffer.concat([tag, hash]) - var len = priv.modulus.byteLength() - var pad = [ 0, 1 ] - while (hash.length + pad.length + 1 < len) pad.push(0xff) - pad.push(0x00) - var i = -1 - while (++i < hash.length) pad.push(hash[i]) - - var out = crt(pad, priv) - return out -} + function cachedProperty(obj, name, computer) { + var key = '_' + name; + obj.prototype[name] = function cachedProperty() { + return this[key] !== undefined ? this[key] : (this[key] = computer.call(this)); + }; + } + utils.cachedProperty = cachedProperty; -function ecSign (hash, priv) { - var curveId = curves[priv.curve.join('.')] - if (!curveId) throw new Error('unknown curve ' + priv.curve.join('.')) + function parseBytes(bytes) { + return typeof bytes === 'string' ? utils.toArray(bytes, 'hex') : bytes; + } + utils.parseBytes = parseBytes; - var curve = new EC(curveId) - var key = curve.keyFromPrivate(priv.privateKey) - var out = key.sign(hash) + function intFromLE(bytes) { + return new BN(bytes, 'hex', 'le'); + } + utils.intFromLE = intFromLE; + }, + { 'bn.js': 92, 'minimalistic-assert': 192, 'minimalistic-crypto-utils': 193 }, + ], + 108: [ + function(require, module, exports) { + module.exports = { + _args: [['elliptic@6.4.0', '/Users/tonypizzicato/dev/meritlabs/lightwallet-stack/packages/bitcore-lib']], + _from: 'elliptic@6.4.0', + _id: 'elliptic@6.4.0', + _inBundle: false, + _integrity: 'sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=', + _location: '/browserify-sign/elliptic', + _phantomChildren: {}, + _requested: { + type: 'version', + registry: true, + raw: 'elliptic@6.4.0', + name: 'elliptic', + escapedName: 'elliptic', + rawSpec: '6.4.0', + saveSpec: null, + fetchSpec: '6.4.0', + }, + _requiredBy: ['/browserify-sign'], + _resolved: 'https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz', + _spec: '6.4.0', + _where: '/Users/tonypizzicato/dev/meritlabs/lightwallet-stack/packages/bitcore-lib', + author: { + name: 'Fedor Indutny', + email: 'fedor@indutny.com', + }, + bugs: { + url: 'https://github.com/indutny/elliptic/issues', + }, + dependencies: { + 'bn.js': '^4.4.0', + brorand: '^1.0.1', + 'hash.js': '^1.0.0', + 'hmac-drbg': '^1.0.0', + inherits: '^2.0.1', + 'minimalistic-assert': '^1.0.0', + 'minimalistic-crypto-utils': '^1.0.0', + }, + description: 'EC cryptography', + devDependencies: { + brfs: '^1.4.3', + grunt: '^0.4.5', + 'grunt-browserify': '^5.0.0', + 'grunt-cli': '^1.2.0', + 'grunt-contrib-connect': '^1.0.0', + 'grunt-contrib-copy': '^1.0.0', + 'grunt-contrib-uglify': '^1.0.1', + 'grunt-saucelabs': '^8.6.2', + jscs: '^2.9.0', + jshint: '^2.6.0', + mocha: '^2.1.0', + }, + files: ['lib'], + homepage: 'https://github.com/indutny/elliptic', + keywords: ['EC', 'Elliptic', 'curve', 'Cryptography'], + license: 'MIT', + main: 'lib/elliptic.js', + name: 'elliptic', + repository: { + type: 'git', + url: 'git+ssh://git@github.com/indutny/elliptic.git', + }, + scripts: { + jscs: 'jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js', + jshint: 'jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js', + lint: 'npm run jscs && npm run jshint', + test: 'npm run lint && npm run unit', + version: 'grunt dist && git add dist/', + }, + version: '6.4.0', + }; + }, + {}, + ], + 109: [ + function(require, module, exports) { + // Copyright Joyent, Inc. and other Node contributors. + // + // Permission is hereby granted, free of charge, to any person obtaining a + // copy of this software and associated documentation files (the + // "Software"), to deal in the Software without restriction, including + // without limitation the rights to use, copy, modify, merge, publish, + // distribute, sublicense, and/or sell copies of the Software, and to permit + // persons to whom the Software is furnished to do so, subject to the + // following conditions: + // + // The above copyright notice and this permission notice shall be included + // in all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + // USE OR OTHER DEALINGS IN THE SOFTWARE. + + var Buffer = require('buffer').Buffer; + + var isBufferEncoding = + Buffer.isEncoding || + function(encoding) { + switch (encoding && encoding.toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'binary': + case 'base64': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + case 'raw': + return true; + default: + return false; + } + }; - return new Buffer(out.toDER()) -} + function assertEncoding(encoding) { + if (encoding && !isBufferEncoding(encoding)) { + throw new Error('Unknown encoding: ' + encoding); + } + } -function dsaSign (hash, priv, algo) { - var x = priv.params.priv_key - var p = priv.params.p - var q = priv.params.q - var g = priv.params.g - var r = new BN(0) - var k - var H = bits2int(hash, q).mod(q) - var s = false - var kv = getKey(x, q, hash, algo) - while (s === false) { - k = makeKey(q, kv, algo) - r = makeR(g, k, p, q) - s = k.invm(q).imul(H.add(x.mul(r))).mod(q) - if (s.cmpn(0) === 0) { - s = false - r = new BN(0) - } - } - return toDER(r, s) -} + // StringDecoder provides an interface for efficiently splitting a series of + // buffers into a series of JS strings without breaking apart multi-byte + // characters. CESU-8 is handled as part of the UTF-8 encoding. + // + // @TODO Handling all encodings inside a single object makes it very difficult + // to reason about this code, so it should be split up in the future. + // @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code + // points as used by CESU-8. + var StringDecoder = (exports.StringDecoder = function(encoding) { + this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); + assertEncoding(encoding); + switch (this.encoding) { + case 'utf8': + // CESU-8 represents each of Surrogate Pair by 3-bytes + this.surrogateSize = 3; + break; + case 'ucs2': + case 'utf16le': + // UTF-16 represents each of Surrogate Pair by 2-bytes + this.surrogateSize = 2; + this.detectIncompleteChar = utf16DetectIncompleteChar; + break; + case 'base64': + // Base-64 stores 3 bytes in 4 chars, and pads the remainder. + this.surrogateSize = 3; + this.detectIncompleteChar = base64DetectIncompleteChar; + break; + default: + this.write = passThroughWrite; + return; + } -function toDER (r, s) { - r = r.toArray() - s = s.toArray() + // Enough space to store all bytes of a single character. UTF-8 needs 4 + // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate). + this.charBuffer = new Buffer(6); + // Number of bytes received for the current incomplete multi-byte character. + this.charReceived = 0; + // Number of bytes expected for the current incomplete multi-byte character. + this.charLength = 0; + }); - // Pad values - if (r[0] & 0x80) r = [ 0 ].concat(r) - if (s[0] & 0x80) s = [ 0 ].concat(s) + // write decodes the given buffer and returns it as JS string that is + // guaranteed to not contain any partial multi-byte characters. Any partial + // character found at the end of the buffer is buffered up, and will be + // returned when calling write again with the remaining bytes. + // + // Note: Converting a Buffer containing an orphan surrogate to a String + // currently works, but converting a String to a Buffer (via `new Buffer`, or + // Buffer#write) will replace incomplete surrogates with the unicode + // replacement character. See https://codereview.chromium.org/121173009/ . + StringDecoder.prototype.write = function(buffer) { + var charStr = ''; + // if our last write ended with an incomplete multibyte character + while (this.charLength) { + // determine how many remaining bytes this buffer has to offer for this char + var available = + buffer.length >= this.charLength - this.charReceived + ? this.charLength - this.charReceived + : buffer.length; + + // add the new bytes to the char buffer + buffer.copy(this.charBuffer, this.charReceived, 0, available); + this.charReceived += available; + + if (this.charReceived < this.charLength) { + // still not enough chars in this buffer? wait for more ... + return ''; + } - var total = r.length + s.length + 4 - var res = [ 0x30, total, 0x02, r.length ] - res = res.concat(r, [ 0x02, s.length ], s) - return new Buffer(res) -} + // remove bytes belonging to the current character from the buffer + buffer = buffer.slice(available, buffer.length); -function getKey (x, q, hash, algo) { - x = new Buffer(x.toArray()) - if (x.length < q.byteLength()) { - var zeros = new Buffer(q.byteLength() - x.length) - zeros.fill(0) - x = Buffer.concat([ zeros, x ]) - } - var hlen = hash.length - var hbits = bits2octets(hash, q) - var v = new Buffer(hlen) - v.fill(1) - var k = new Buffer(hlen) - k.fill(0) - k = createHmac(algo, k).update(v).update(new Buffer([ 0 ])).update(x).update(hbits).digest() - v = createHmac(algo, k).update(v).digest() - k = createHmac(algo, k).update(v).update(new Buffer([ 1 ])).update(x).update(hbits).digest() - v = createHmac(algo, k).update(v).digest() - return { k: k, v: v } -} + // get the character that was split + charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); -function bits2int (obits, q) { - var bits = new BN(obits) - var shift = (obits.length << 3) - q.bitLength() - if (shift > 0) bits.ishrn(shift) - return bits -} + // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character + var charCode = charStr.charCodeAt(charStr.length - 1); + if (charCode >= 0xd800 && charCode <= 0xdbff) { + this.charLength += this.surrogateSize; + charStr = ''; + continue; + } + this.charReceived = this.charLength = 0; -function bits2octets (bits, q) { - bits = bits2int(bits, q) - bits = bits.mod(q) - var out = new Buffer(bits.toArray()) - if (out.length < q.byteLength()) { - var zeros = new Buffer(q.byteLength() - out.length) - zeros.fill(0) - out = Buffer.concat([ zeros, out ]) - } - return out -} + // if there are no more bytes in this buffer, just emit our char + if (buffer.length === 0) { + return charStr; + } + break; + } -function makeKey (q, kv, algo) { - var t - var k + // determine and set charLength / charReceived + this.detectIncompleteChar(buffer); - do { - t = new Buffer(0) + var end = buffer.length; + if (this.charLength) { + // buffer the incomplete character bytes we got + buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end); + end -= this.charReceived; + } - while (t.length * 8 < q.bitLength()) { - kv.v = createHmac(algo, kv.k).update(kv.v).digest() - t = Buffer.concat([ t, kv.v ]) - } + charStr += buffer.toString(this.encoding, 0, end); + + var end = charStr.length - 1; + var charCode = charStr.charCodeAt(end); + // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character + if (charCode >= 0xd800 && charCode <= 0xdbff) { + var size = this.surrogateSize; + this.charLength += size; + this.charReceived += size; + this.charBuffer.copy(this.charBuffer, size, 0, size); + buffer.copy(this.charBuffer, 0, 0, size); + return charStr.substring(0, end); + } - k = bits2int(t, q) - kv.k = createHmac(algo, kv.k).update(kv.v).update(new Buffer([ 0 ])).digest() - kv.v = createHmac(algo, kv.k).update(kv.v).digest() - } while (k.cmp(q) !== -1) + // or just emit the charStr + return charStr; + }; - return k -} + // detectIncompleteChar determines if there is an incomplete UTF-8 character at + // the end of the given buffer. If so, it sets this.charLength to the byte + // length that character, and sets this.charReceived to the number of bytes + // that are available for this character. + StringDecoder.prototype.detectIncompleteChar = function(buffer) { + // determine how many bytes we have to check at the end of this buffer + var i = buffer.length >= 3 ? 3 : buffer.length; -function makeR (g, k, p, q) { - return g.toRed(BN.mont(p)).redPow(k).fromRed().mod(q) -} + // Figure out if one of the last i bytes of our buffer announces an + // incomplete char. + for (; i > 0; i--) { + var c = buffer[buffer.length - i]; -module.exports = sign -module.exports.getKey = getKey -module.exports.makeKey = makeKey - -}).call(this,require("buffer").Buffer) -},{"./curves.json":88,"bn.js":92,"browserify-rsa":84,"buffer":113,"create-hmac":137,"elliptic":93,"parse-asn1":198}],91:[function(require,module,exports){ -(function (Buffer){ -// much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js -var BN = require('bn.js') -var EC = require('elliptic').ec -var parseKeys = require('parse-asn1') -var curves = require('./curves.json') - -function verify (sig, hash, key, signType, tag) { - var pub = parseKeys(key) - if (pub.type === 'ec') { - // rsa keys can be interpreted as ecdsa ones in openssl - if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') throw new Error('wrong public key type') - return ecVerify(sig, hash, pub) - } else if (pub.type === 'dsa') { - if (signType !== 'dsa') throw new Error('wrong public key type') - return dsaVerify(sig, hash, pub) - } else { - if (signType !== 'rsa' && signType !== 'ecdsa/rsa') throw new Error('wrong public key type') - } - hash = Buffer.concat([tag, hash]) - var len = pub.modulus.byteLength() - var pad = [ 1 ] - var padNum = 0 - while (hash.length + pad.length + 2 < len) { - pad.push(0xff) - padNum++ - } - pad.push(0x00) - var i = -1 - while (++i < hash.length) { - pad.push(hash[i]) - } - pad = new Buffer(pad) - var red = BN.mont(pub.modulus) - sig = new BN(sig).toRed(red) - - sig = sig.redPow(new BN(pub.publicExponent)) - sig = new Buffer(sig.fromRed().toArray()) - var out = padNum < 8 ? 1 : 0 - len = Math.min(sig.length, pad.length) - if (sig.length !== pad.length) out = 1 - - i = -1 - while (++i < len) out |= sig[i] ^ pad[i] - return out === 0 -} + // See http://en.wikipedia.org/wiki/UTF-8#Description -function ecVerify (sig, hash, pub) { - var curveId = curves[pub.data.algorithm.curve.join('.')] - if (!curveId) throw new Error('unknown curve ' + pub.data.algorithm.curve.join('.')) + // 110XXXXX + if (i == 1 && c >> 5 == 0x06) { + this.charLength = 2; + break; + } - var curve = new EC(curveId) - var pubkey = pub.data.subjectPrivateKey.data + // 1110XXXX + if (i <= 2 && c >> 4 == 0x0e) { + this.charLength = 3; + break; + } - return curve.verify(hash, sig, pubkey) -} + // 11110XXX + if (i <= 3 && c >> 3 == 0x1e) { + this.charLength = 4; + break; + } + } + this.charReceived = i; + }; -function dsaVerify (sig, hash, pub) { - var p = pub.data.p - var q = pub.data.q - var g = pub.data.g - var y = pub.data.pub_key - var unpacked = parseKeys.signature.decode(sig, 'der') - var s = unpacked.s - var r = unpacked.r - checkValue(s, q) - checkValue(r, q) - var montp = BN.mont(p) - var w = s.invm(q) - var v = g.toRed(montp) - .redPow(new BN(hash).mul(w).mod(q)) - .fromRed() - .mul(y.toRed(montp).redPow(r.mul(w).mod(q)).fromRed()) - .mod(p) - .mod(q) - return v.cmp(r) === 0 -} + StringDecoder.prototype.end = function(buffer) { + var res = ''; + if (buffer && buffer.length) res = this.write(buffer); -function checkValue (b, q) { - if (b.cmpn(0) <= 0) throw new Error('invalid sig') - if (b.cmp(q) >= q) throw new Error('invalid sig') -} + if (this.charReceived) { + var cr = this.charReceived; + var buf = this.charBuffer; + var enc = this.encoding; + res += buf.slice(0, cr).toString(enc); + } -module.exports = verify - -}).call(this,require("buffer").Buffer) -},{"./curves.json":88,"bn.js":92,"buffer":113,"elliptic":93,"parse-asn1":198}],92:[function(require,module,exports){ -arguments[4][59][0].apply(exports,arguments) -},{"buffer":64,"dup":59}],93:[function(require,module,exports){ -'use strict'; - -var elliptic = exports; - -elliptic.version = require('../package.json').version; -elliptic.utils = require('./elliptic/utils'); -elliptic.rand = require('brorand'); -elliptic.curve = require('./elliptic/curve'); -elliptic.curves = require('./elliptic/curves'); - -// Protocols -elliptic.ec = require('./elliptic/ec'); -elliptic.eddsa = require('./elliptic/eddsa'); - -},{"../package.json":108,"./elliptic/curve":96,"./elliptic/curves":99,"./elliptic/ec":100,"./elliptic/eddsa":103,"./elliptic/utils":107,"brorand":63}],94:[function(require,module,exports){ -'use strict'; - -var BN = require('bn.js'); -var elliptic = require('../../elliptic'); -var utils = elliptic.utils; -var getNAF = utils.getNAF; -var getJSF = utils.getJSF; -var assert = utils.assert; - -function BaseCurve(type, conf) { - this.type = type; - this.p = new BN(conf.p, 16); - - // Use Montgomery, when there is no fast reduction for the prime - this.red = conf.prime ? BN.red(conf.prime) : BN.mont(this.p); - - // Useful for many curves - this.zero = new BN(0).toRed(this.red); - this.one = new BN(1).toRed(this.red); - this.two = new BN(2).toRed(this.red); - - // Curve configuration, optional - this.n = conf.n && new BN(conf.n, 16); - this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed); - - // Temporary arrays - this._wnafT1 = new Array(4); - this._wnafT2 = new Array(4); - this._wnafT3 = new Array(4); - this._wnafT4 = new Array(4); - - // Generalized Greg Maxwell's trick - var adjustCount = this.n && this.p.div(this.n); - if (!adjustCount || adjustCount.cmpn(100) > 0) { - this.redN = null; - } else { - this._maxwellTrick = true; - this.redN = this.n.toRed(this.red); - } -} -module.exports = BaseCurve; - -BaseCurve.prototype.point = function point() { - throw new Error('Not implemented'); -}; - -BaseCurve.prototype.validate = function validate() { - throw new Error('Not implemented'); -}; - -BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) { - assert(p.precomputed); - var doubles = p._getDoubles(); - - var naf = getNAF(k, 1); - var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1); - I /= 3; - - // Translate into more windowed form - var repr = []; - for (var j = 0; j < naf.length; j += doubles.step) { - var nafW = 0; - for (var k = j + doubles.step - 1; k >= j; k--) - nafW = (nafW << 1) + naf[k]; - repr.push(nafW); - } + return res; + }; - var a = this.jpoint(null, null, null); - var b = this.jpoint(null, null, null); - for (var i = I; i > 0; i--) { - for (var j = 0; j < repr.length; j++) { - var nafW = repr[j]; - if (nafW === i) - b = b.mixedAdd(doubles.points[j]); - else if (nafW === -i) - b = b.mixedAdd(doubles.points[j].neg()); - } - a = a.add(b); - } - return a.toP(); -}; - -BaseCurve.prototype._wnafMul = function _wnafMul(p, k) { - var w = 4; - - // Precompute window - var nafPoints = p._getNAFPoints(w); - w = nafPoints.wnd; - var wnd = nafPoints.points; - - // Get NAF form - var naf = getNAF(k, w); - - // Add `this`*(N+1) for every w-NAF index - var acc = this.jpoint(null, null, null); - for (var i = naf.length - 1; i >= 0; i--) { - // Count zeroes - for (var k = 0; i >= 0 && naf[i] === 0; i--) - k++; - if (i >= 0) - k++; - acc = acc.dblp(k); - - if (i < 0) - break; - var z = naf[i]; - assert(z !== 0); - if (p.type === 'affine') { - // J +- P - if (z > 0) - acc = acc.mixedAdd(wnd[(z - 1) >> 1]); - else - acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg()); - } else { - // J +- J - if (z > 0) - acc = acc.add(wnd[(z - 1) >> 1]); - else - acc = acc.add(wnd[(-z - 1) >> 1].neg()); - } - } - return p.type === 'affine' ? acc.toP() : acc; -}; - -BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW, - points, - coeffs, - len, - jacobianResult) { - var wndWidth = this._wnafT1; - var wnd = this._wnafT2; - var naf = this._wnafT3; - - // Fill all arrays - var max = 0; - for (var i = 0; i < len; i++) { - var p = points[i]; - var nafPoints = p._getNAFPoints(defW); - wndWidth[i] = nafPoints.wnd; - wnd[i] = nafPoints.points; - } + function passThroughWrite(buffer) { + return buffer.toString(this.encoding); + } - // Comb small window NAFs - for (var i = len - 1; i >= 1; i -= 2) { - var a = i - 1; - var b = i; - if (wndWidth[a] !== 1 || wndWidth[b] !== 1) { - naf[a] = getNAF(coeffs[a], wndWidth[a]); - naf[b] = getNAF(coeffs[b], wndWidth[b]); - max = Math.max(naf[a].length, max); - max = Math.max(naf[b].length, max); - continue; - } + function utf16DetectIncompleteChar(buffer) { + this.charReceived = buffer.length % 2; + this.charLength = this.charReceived ? 2 : 0; + } - var comb = [ - points[a], /* 1 */ - null, /* 3 */ - null, /* 5 */ - points[b] /* 7 */ - ]; - - // Try to avoid Projective points, if possible - if (points[a].y.cmp(points[b].y) === 0) { - comb[1] = points[a].add(points[b]); - comb[2] = points[a].toJ().mixedAdd(points[b].neg()); - } else if (points[a].y.cmp(points[b].y.redNeg()) === 0) { - comb[1] = points[a].toJ().mixedAdd(points[b]); - comb[2] = points[a].add(points[b].neg()); - } else { - comb[1] = points[a].toJ().mixedAdd(points[b]); - comb[2] = points[a].toJ().mixedAdd(points[b].neg()); - } + function base64DetectIncompleteChar(buffer) { + this.charReceived = buffer.length % 3; + this.charLength = this.charReceived ? 3 : 0; + } + }, + { buffer: 113 }, + ], + 110: [ + function(require, module, exports) { + // Base58 encoding/decoding + // Originally written by Mike Hearn for BitcoinJ + // Copyright (c) 2011 Google Inc + // Ported to JavaScript by Stefan Thomas + // Merged Buffer refactorings from base58-native by Stephen Pair + // Copyright (c) 2013 BitPay Inc + + var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; + var ALPHABET_MAP = {}; + for (var i = 0; i < ALPHABET.length; i++) { + ALPHABET_MAP[ALPHABET.charAt(i)] = i; + } + var BASE = 58; - var index = [ - -3, /* -1 -1 */ - -1, /* -1 0 */ - -5, /* -1 1 */ - -7, /* 0 -1 */ - 0, /* 0 0 */ - 7, /* 0 1 */ - 5, /* 1 -1 */ - 1, /* 1 0 */ - 3 /* 1 1 */ - ]; - - var jsf = getJSF(coeffs[a], coeffs[b]); - max = Math.max(jsf[0].length, max); - naf[a] = new Array(max); - naf[b] = new Array(max); - for (var j = 0; j < max; j++) { - var ja = jsf[0][j] | 0; - var jb = jsf[1][j] | 0; - - naf[a][j] = index[(ja + 1) * 3 + (jb + 1)]; - naf[b][j] = 0; - wnd[a] = comb; - } - } + function encode(buffer) { + if (buffer.length === 0) return ''; - var acc = this.jpoint(null, null, null); - var tmp = this._wnafT4; - for (var i = max; i >= 0; i--) { - var k = 0; - - while (i >= 0) { - var zero = true; - for (var j = 0; j < len; j++) { - tmp[j] = naf[j][i] | 0; - if (tmp[j] !== 0) - zero = false; - } - if (!zero) - break; - k++; - i--; - } - if (i >= 0) - k++; - acc = acc.dblp(k); - if (i < 0) - break; - - for (var j = 0; j < len; j++) { - var z = tmp[j]; - var p; - if (z === 0) - continue; - else if (z > 0) - p = wnd[j][(z - 1) >> 1]; - else if (z < 0) - p = wnd[j][(-z - 1) >> 1].neg(); - - if (p.type === 'affine') - acc = acc.mixedAdd(p); - else - acc = acc.add(p); - } - } - // Zeroify references - for (var i = 0; i < len; i++) - wnd[i] = null; - - if (jacobianResult) - return acc; - else - return acc.toP(); -}; - -function BasePoint(curve, type) { - this.curve = curve; - this.type = type; - this.precomputed = null; -} -BaseCurve.BasePoint = BasePoint; + var i, + j, + digits = [0]; + for (i = 0; i < buffer.length; i++) { + for (j = 0; j < digits.length; j++) digits[j] <<= 8; -BasePoint.prototype.eq = function eq(/*other*/) { - throw new Error('Not implemented'); -}; + digits[0] += buffer[i]; -BasePoint.prototype.validate = function validate() { - return this.curve.validate(this); -}; + var carry = 0; + for (j = 0; j < digits.length; ++j) { + digits[j] += carry; -BaseCurve.prototype.decodePoint = function decodePoint(bytes, enc) { - bytes = utils.toArray(bytes, enc); + carry = (digits[j] / BASE) | 0; + digits[j] %= BASE; + } - var len = this.p.byteLength(); + while (carry) { + digits.push(carry % BASE); - // uncompressed, hybrid-odd, hybrid-even - if ((bytes[0] === 0x04 || bytes[0] === 0x06 || bytes[0] === 0x07) && - bytes.length - 1 === 2 * len) { - if (bytes[0] === 0x06) - assert(bytes[bytes.length - 1] % 2 === 0); - else if (bytes[0] === 0x07) - assert(bytes[bytes.length - 1] % 2 === 1); + carry = (carry / BASE) | 0; + } + } - var res = this.point(bytes.slice(1, 1 + len), - bytes.slice(1 + len, 1 + 2 * len)); + // deal with leading zeros + for (i = 0; buffer[i] === 0 && i < buffer.length - 1; i++) digits.push(0); - return res; - } else if ((bytes[0] === 0x02 || bytes[0] === 0x03) && - bytes.length - 1 === len) { - return this.pointFromX(bytes.slice(1, 1 + len), bytes[0] === 0x03); - } - throw new Error('Unknown point format'); -}; - -BasePoint.prototype.encodeCompressed = function encodeCompressed(enc) { - return this.encode(enc, true); -}; - -BasePoint.prototype._encode = function _encode(compact) { - var len = this.curve.p.byteLength(); - var x = this.getX().toArray('be', len); - - if (compact) - return [ this.getY().isEven() ? 0x02 : 0x03 ].concat(x); - - return [ 0x04 ].concat(x, this.getY().toArray('be', len)) ; -}; - -BasePoint.prototype.encode = function encode(enc, compact) { - return utils.encode(this._encode(compact), enc); -}; - -BasePoint.prototype.precompute = function precompute(power) { - if (this.precomputed) - return this; - - var precomputed = { - doubles: null, - naf: null, - beta: null - }; - precomputed.naf = this._getNAFPoints(8); - precomputed.doubles = this._getDoubles(4, power); - precomputed.beta = this._getBeta(); - this.precomputed = precomputed; - - return this; -}; - -BasePoint.prototype._hasDoubles = function _hasDoubles(k) { - if (!this.precomputed) - return false; - - var doubles = this.precomputed.doubles; - if (!doubles) - return false; - - return doubles.points.length >= Math.ceil((k.bitLength() + 1) / doubles.step); -}; - -BasePoint.prototype._getDoubles = function _getDoubles(step, power) { - if (this.precomputed && this.precomputed.doubles) - return this.precomputed.doubles; - - var doubles = [ this ]; - var acc = this; - for (var i = 0; i < power; i += step) { - for (var j = 0; j < step; j++) - acc = acc.dbl(); - doubles.push(acc); - } - return { - step: step, - points: doubles - }; -}; - -BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) { - if (this.precomputed && this.precomputed.naf) - return this.precomputed.naf; - - var res = [ this ]; - var max = (1 << wnd) - 1; - var dbl = max === 1 ? null : this.dbl(); - for (var i = 1; i < max; i++) - res[i] = res[i - 1].add(dbl); - return { - wnd: wnd, - points: res - }; -}; - -BasePoint.prototype._getBeta = function _getBeta() { - return null; -}; - -BasePoint.prototype.dblp = function dblp(k) { - var r = this; - for (var i = 0; i < k; i++) - r = r.dbl(); - return r; -}; - -},{"../../elliptic":93,"bn.js":92}],95:[function(require,module,exports){ -'use strict'; - -var curve = require('../curve'); -var elliptic = require('../../elliptic'); -var BN = require('bn.js'); -var inherits = require('inherits'); -var Base = curve.base; - -var assert = elliptic.utils.assert; - -function EdwardsCurve(conf) { - // NOTE: Important as we are creating point in Base.call() - this.twisted = (conf.a | 0) !== 1; - this.mOneA = this.twisted && (conf.a | 0) === -1; - this.extended = this.mOneA; - - Base.call(this, 'edwards', conf); - - this.a = new BN(conf.a, 16).umod(this.red.m); - this.a = this.a.toRed(this.red); - this.c = new BN(conf.c, 16).toRed(this.red); - this.c2 = this.c.redSqr(); - this.d = new BN(conf.d, 16).toRed(this.red); - this.dd = this.d.redAdd(this.d); - - assert(!this.twisted || this.c.fromRed().cmpn(1) === 0); - this.oneC = (conf.c | 0) === 1; -} -inherits(EdwardsCurve, Base); -module.exports = EdwardsCurve; - -EdwardsCurve.prototype._mulA = function _mulA(num) { - if (this.mOneA) - return num.redNeg(); - else - return this.a.redMul(num); -}; - -EdwardsCurve.prototype._mulC = function _mulC(num) { - if (this.oneC) - return num; - else - return this.c.redMul(num); -}; - -// Just for compatibility with Short curve -EdwardsCurve.prototype.jpoint = function jpoint(x, y, z, t) { - return this.point(x, y, z, t); -}; - -EdwardsCurve.prototype.pointFromX = function pointFromX(x, odd) { - x = new BN(x, 16); - if (!x.red) - x = x.toRed(this.red); - - var x2 = x.redSqr(); - var rhs = this.c2.redSub(this.a.redMul(x2)); - var lhs = this.one.redSub(this.c2.redMul(this.d).redMul(x2)); - - var y2 = rhs.redMul(lhs.redInvm()); - var y = y2.redSqrt(); - if (y.redSqr().redSub(y2).cmp(this.zero) !== 0) - throw new Error('invalid point'); - - var isOdd = y.fromRed().isOdd(); - if (odd && !isOdd || !odd && isOdd) - y = y.redNeg(); - - return this.point(x, y); -}; - -EdwardsCurve.prototype.pointFromY = function pointFromY(y, odd) { - y = new BN(y, 16); - if (!y.red) - y = y.toRed(this.red); - - // x^2 = (y^2 - 1) / (d y^2 + 1) - var y2 = y.redSqr(); - var lhs = y2.redSub(this.one); - var rhs = y2.redMul(this.d).redAdd(this.one); - var x2 = lhs.redMul(rhs.redInvm()); - - if (x2.cmp(this.zero) === 0) { - if (odd) - throw new Error('invalid point'); - else - return this.point(this.zero, y); - } + return digits + .reverse() + .map(function(digit) { + return ALPHABET[digit]; + }) + .join(''); + } - var x = x2.redSqrt(); - if (x.redSqr().redSub(x2).cmp(this.zero) !== 0) - throw new Error('invalid point'); - - if (x.isOdd() !== odd) - x = x.redNeg(); - - return this.point(x, y); -}; - -EdwardsCurve.prototype.validate = function validate(point) { - if (point.isInfinity()) - return true; - - // Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2) - point.normalize(); - - var x2 = point.x.redSqr(); - var y2 = point.y.redSqr(); - var lhs = x2.redMul(this.a).redAdd(y2); - var rhs = this.c2.redMul(this.one.redAdd(this.d.redMul(x2).redMul(y2))); - - return lhs.cmp(rhs) === 0; -}; - -function Point(curve, x, y, z, t) { - Base.BasePoint.call(this, curve, 'projective'); - if (x === null && y === null && z === null) { - this.x = this.curve.zero; - this.y = this.curve.one; - this.z = this.curve.one; - this.t = this.curve.zero; - this.zOne = true; - } else { - this.x = new BN(x, 16); - this.y = new BN(y, 16); - this.z = z ? new BN(z, 16) : this.curve.one; - this.t = t && new BN(t, 16); - if (!this.x.red) - this.x = this.x.toRed(this.curve.red); - if (!this.y.red) - this.y = this.y.toRed(this.curve.red); - if (!this.z.red) - this.z = this.z.toRed(this.curve.red); - if (this.t && !this.t.red) - this.t = this.t.toRed(this.curve.red); - this.zOne = this.z === this.curve.one; - - // Use extended coordinates - if (this.curve.extended && !this.t) { - this.t = this.x.redMul(this.y); - if (!this.zOne) - this.t = this.t.redMul(this.z.redInvm()); - } - } -} -inherits(Point, Base.BasePoint); - -EdwardsCurve.prototype.pointFromJSON = function pointFromJSON(obj) { - return Point.fromJSON(this, obj); -}; - -EdwardsCurve.prototype.point = function point(x, y, z, t) { - return new Point(this, x, y, z, t); -}; - -Point.fromJSON = function fromJSON(curve, obj) { - return new Point(curve, obj[0], obj[1], obj[2]); -}; - -Point.prototype.inspect = function inspect() { - if (this.isInfinity()) - return ''; - return ''; -}; - -Point.prototype.isInfinity = function isInfinity() { - // XXX This code assumes that zero is always zero in red - return this.x.cmpn(0) === 0 && - this.y.cmp(this.z) === 0; -}; - -Point.prototype._extDbl = function _extDbl() { - // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html - // #doubling-dbl-2008-hwcd - // 4M + 4S - - // A = X1^2 - var a = this.x.redSqr(); - // B = Y1^2 - var b = this.y.redSqr(); - // C = 2 * Z1^2 - var c = this.z.redSqr(); - c = c.redIAdd(c); - // D = a * A - var d = this.curve._mulA(a); - // E = (X1 + Y1)^2 - A - B - var e = this.x.redAdd(this.y).redSqr().redISub(a).redISub(b); - // G = D + B - var g = d.redAdd(b); - // F = G - C - var f = g.redSub(c); - // H = D - B - var h = d.redSub(b); - // X3 = E * F - var nx = e.redMul(f); - // Y3 = G * H - var ny = g.redMul(h); - // T3 = E * H - var nt = e.redMul(h); - // Z3 = F * G - var nz = f.redMul(g); - return this.curve.point(nx, ny, nz, nt); -}; - -Point.prototype._projDbl = function _projDbl() { - // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html - // #doubling-dbl-2008-bbjlp - // #doubling-dbl-2007-bl - // and others - // Generally 3M + 4S or 2M + 4S - - // B = (X1 + Y1)^2 - var b = this.x.redAdd(this.y).redSqr(); - // C = X1^2 - var c = this.x.redSqr(); - // D = Y1^2 - var d = this.y.redSqr(); - - var nx; - var ny; - var nz; - if (this.curve.twisted) { - // E = a * C - var e = this.curve._mulA(c); - // F = E + D - var f = e.redAdd(d); - if (this.zOne) { - // X3 = (B - C - D) * (F - 2) - nx = b.redSub(c).redSub(d).redMul(f.redSub(this.curve.two)); - // Y3 = F * (E - D) - ny = f.redMul(e.redSub(d)); - // Z3 = F^2 - 2 * F - nz = f.redSqr().redSub(f).redSub(f); - } else { - // H = Z1^2 - var h = this.z.redSqr(); - // J = F - 2 * H - var j = f.redSub(h).redISub(h); - // X3 = (B-C-D)*J - nx = b.redSub(c).redISub(d).redMul(j); - // Y3 = F * (E - D) - ny = f.redMul(e.redSub(d)); - // Z3 = F * J - nz = f.redMul(j); - } - } else { - // E = C + D - var e = c.redAdd(d); - // H = (c * Z1)^2 - var h = this.curve._mulC(this.c.redMul(this.z)).redSqr(); - // J = E - 2 * H - var j = e.redSub(h).redSub(h); - // X3 = c * (B - E) * J - nx = this.curve._mulC(b.redISub(e)).redMul(j); - // Y3 = c * E * (C - D) - ny = this.curve._mulC(e).redMul(c.redISub(d)); - // Z3 = E * J - nz = e.redMul(j); - } - return this.curve.point(nx, ny, nz); -}; - -Point.prototype.dbl = function dbl() { - if (this.isInfinity()) - return this; - - // Double in extended coordinates - if (this.curve.extended) - return this._extDbl(); - else - return this._projDbl(); -}; - -Point.prototype._extAdd = function _extAdd(p) { - // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html - // #addition-add-2008-hwcd-3 - // 8M - - // A = (Y1 - X1) * (Y2 - X2) - var a = this.y.redSub(this.x).redMul(p.y.redSub(p.x)); - // B = (Y1 + X1) * (Y2 + X2) - var b = this.y.redAdd(this.x).redMul(p.y.redAdd(p.x)); - // C = T1 * k * T2 - var c = this.t.redMul(this.curve.dd).redMul(p.t); - // D = Z1 * 2 * Z2 - var d = this.z.redMul(p.z.redAdd(p.z)); - // E = B - A - var e = b.redSub(a); - // F = D - C - var f = d.redSub(c); - // G = D + C - var g = d.redAdd(c); - // H = B + A - var h = b.redAdd(a); - // X3 = E * F - var nx = e.redMul(f); - // Y3 = G * H - var ny = g.redMul(h); - // T3 = E * H - var nt = e.redMul(h); - // Z3 = F * G - var nz = f.redMul(g); - return this.curve.point(nx, ny, nz, nt); -}; - -Point.prototype._projAdd = function _projAdd(p) { - // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html - // #addition-add-2008-bbjlp - // #addition-add-2007-bl - // 10M + 1S - - // A = Z1 * Z2 - var a = this.z.redMul(p.z); - // B = A^2 - var b = a.redSqr(); - // C = X1 * X2 - var c = this.x.redMul(p.x); - // D = Y1 * Y2 - var d = this.y.redMul(p.y); - // E = d * C * D - var e = this.curve.d.redMul(c).redMul(d); - // F = B - E - var f = b.redSub(e); - // G = B + E - var g = b.redAdd(e); - // X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D) - var tmp = this.x.redAdd(this.y).redMul(p.x.redAdd(p.y)).redISub(c).redISub(d); - var nx = a.redMul(f).redMul(tmp); - var ny; - var nz; - if (this.curve.twisted) { - // Y3 = A * G * (D - a * C) - ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c))); - // Z3 = F * G - nz = f.redMul(g); - } else { - // Y3 = A * G * (D - C) - ny = a.redMul(g).redMul(d.redSub(c)); - // Z3 = c * F * G - nz = this.curve._mulC(f).redMul(g); - } - return this.curve.point(nx, ny, nz); -}; - -Point.prototype.add = function add(p) { - if (this.isInfinity()) - return p; - if (p.isInfinity()) - return this; - - if (this.curve.extended) - return this._extAdd(p); - else - return this._projAdd(p); -}; - -Point.prototype.mul = function mul(k) { - if (this._hasDoubles(k)) - return this.curve._fixedNafMul(this, k); - else - return this.curve._wnafMul(this, k); -}; - -Point.prototype.mulAdd = function mulAdd(k1, p, k2) { - return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, false); -}; - -Point.prototype.jmulAdd = function jmulAdd(k1, p, k2) { - return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, true); -}; - -Point.prototype.normalize = function normalize() { - if (this.zOne) - return this; - - // Normalize coordinates - var zi = this.z.redInvm(); - this.x = this.x.redMul(zi); - this.y = this.y.redMul(zi); - if (this.t) - this.t = this.t.redMul(zi); - this.z = this.curve.one; - this.zOne = true; - return this; -}; - -Point.prototype.neg = function neg() { - return this.curve.point(this.x.redNeg(), - this.y, - this.z, - this.t && this.t.redNeg()); -}; - -Point.prototype.getX = function getX() { - this.normalize(); - return this.x.fromRed(); -}; - -Point.prototype.getY = function getY() { - this.normalize(); - return this.y.fromRed(); -}; - -Point.prototype.eq = function eq(other) { - return this === other || - this.getX().cmp(other.getX()) === 0 && - this.getY().cmp(other.getY()) === 0; -}; - -Point.prototype.eqXToP = function eqXToP(x) { - var rx = x.toRed(this.curve.red).redMul(this.z); - if (this.x.cmp(rx) === 0) - return true; - - var xc = x.clone(); - var t = this.curve.redN.redMul(this.z); - for (;;) { - xc.iadd(this.curve.n); - if (xc.cmp(this.curve.p) >= 0) - return false; - - rx.redIAdd(t); - if (this.x.cmp(rx) === 0) - return true; - } - return false; -}; + function decode(string) { + if (string.length === 0) return []; -// Compatibility with BaseCurve -Point.prototype.toP = Point.prototype.normalize; -Point.prototype.mixedAdd = Point.prototype.add; + var i, + j, + bytes = [0]; + for (i = 0; i < string.length; i++) { + var c = string[i]; + if (!(c in ALPHABET_MAP)) throw new Error('Non-base58 character'); -},{"../../elliptic":93,"../curve":96,"bn.js":92,"inherits":184}],96:[function(require,module,exports){ -'use strict'; + for (j = 0; j < bytes.length; j++) bytes[j] *= BASE; + bytes[0] += ALPHABET_MAP[c]; -var curve = exports; + var carry = 0; + for (j = 0; j < bytes.length; ++j) { + bytes[j] += carry; -curve.base = require('./base'); -curve.short = require('./short'); -curve.mont = require('./mont'); -curve.edwards = require('./edwards'); + carry = bytes[j] >> 8; + bytes[j] &= 0xff; + } -},{"./base":94,"./edwards":95,"./mont":97,"./short":98}],97:[function(require,module,exports){ -'use strict'; + while (carry) { + bytes.push(carry & 0xff); -var curve = require('../curve'); -var BN = require('bn.js'); -var inherits = require('inherits'); -var Base = curve.base; + carry >>= 8; + } + } -var elliptic = require('../../elliptic'); -var utils = elliptic.utils; + // deal with leading zeros + for (i = 0; string[i] === '1' && i < string.length - 1; i++) bytes.push(0); -function MontCurve(conf) { - Base.call(this, 'mont', conf); + return bytes.reverse(); + } - this.a = new BN(conf.a, 16).toRed(this.red); - this.b = new BN(conf.b, 16).toRed(this.red); - this.i4 = new BN(4).toRed(this.red).redInvm(); - this.two = new BN(2).toRed(this.red); - this.a24 = this.i4.redMul(this.a.redAdd(this.two)); -} -inherits(MontCurve, Base); -module.exports = MontCurve; - -MontCurve.prototype.validate = function validate(point) { - var x = point.normalize().x; - var x2 = x.redSqr(); - var rhs = x2.redMul(x).redAdd(x2.redMul(this.a)).redAdd(x); - var y = rhs.redSqrt(); - - return y.redSqr().cmp(rhs) === 0; -}; - -function Point(curve, x, z) { - Base.BasePoint.call(this, curve, 'projective'); - if (x === null && z === null) { - this.x = this.curve.one; - this.z = this.curve.zero; - } else { - this.x = new BN(x, 16); - this.z = new BN(z, 16); - if (!this.x.red) - this.x = this.x.toRed(this.curve.red); - if (!this.z.red) - this.z = this.z.toRed(this.curve.red); - } -} -inherits(Point, Base.BasePoint); - -MontCurve.prototype.decodePoint = function decodePoint(bytes, enc) { - return this.point(utils.toArray(bytes, enc), 1); -}; - -MontCurve.prototype.point = function point(x, z) { - return new Point(this, x, z); -}; - -MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) { - return Point.fromJSON(this, obj); -}; - -Point.prototype.precompute = function precompute() { - // No-op -}; - -Point.prototype._encode = function _encode() { - return this.getX().toArray('be', this.curve.p.byteLength()); -}; - -Point.fromJSON = function fromJSON(curve, obj) { - return new Point(curve, obj[0], obj[1] || curve.one); -}; - -Point.prototype.inspect = function inspect() { - if (this.isInfinity()) - return ''; - return ''; -}; - -Point.prototype.isInfinity = function isInfinity() { - // XXX This code assumes that zero is always zero in red - return this.z.cmpn(0) === 0; -}; - -Point.prototype.dbl = function dbl() { - // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3 - // 2M + 2S + 4A - - // A = X1 + Z1 - var a = this.x.redAdd(this.z); - // AA = A^2 - var aa = a.redSqr(); - // B = X1 - Z1 - var b = this.x.redSub(this.z); - // BB = B^2 - var bb = b.redSqr(); - // C = AA - BB - var c = aa.redSub(bb); - // X3 = AA * BB - var nx = aa.redMul(bb); - // Z3 = C * (BB + A24 * C) - var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c))); - return this.curve.point(nx, nz); -}; - -Point.prototype.add = function add() { - throw new Error('Not supported on Montgomery curve'); -}; - -Point.prototype.diffAdd = function diffAdd(p, diff) { - // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3 - // 4M + 2S + 6A - - // A = X2 + Z2 - var a = this.x.redAdd(this.z); - // B = X2 - Z2 - var b = this.x.redSub(this.z); - // C = X3 + Z3 - var c = p.x.redAdd(p.z); - // D = X3 - Z3 - var d = p.x.redSub(p.z); - // DA = D * A - var da = d.redMul(a); - // CB = C * B - var cb = c.redMul(b); - // X5 = Z1 * (DA + CB)^2 - var nx = diff.z.redMul(da.redAdd(cb).redSqr()); - // Z5 = X1 * (DA - CB)^2 - var nz = diff.x.redMul(da.redISub(cb).redSqr()); - return this.curve.point(nx, nz); -}; - -Point.prototype.mul = function mul(k) { - var t = k.clone(); - var a = this; // (N / 2) * Q + Q - var b = this.curve.point(null, null); // (N / 2) * Q - var c = this; // Q - - for (var bits = []; t.cmpn(0) !== 0; t.iushrn(1)) - bits.push(t.andln(1)); - - for (var i = bits.length - 1; i >= 0; i--) { - if (bits[i] === 0) { - // N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q - a = a.diffAdd(b, c); - // N * Q = 2 * ((N / 2) * Q + Q)) - b = b.dbl(); - } else { - // N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q) - b = a.diffAdd(b, c); - // N * Q + Q = 2 * ((N / 2) * Q + Q) - a = a.dbl(); - } - } - return b; -}; + module.exports = { + encode: encode, + decode: decode, + }; + }, + {}, + ], + 111: [ + function(require, module, exports) { + module.exports = function(cmp, to) { + var c = 0; + for (var i = 0; i < cmp.length; ++i) { + if (i == to.length) break; + c = cmp[i] < to[i] ? -1 : cmp[i] > to[i] ? 1 : 0; + if (c != 0) break; + } + if (c == 0) { + if (to.length > cmp.length) c = -1; + else if (cmp.length > to.length) c = 1; + } + return c; + }; + }, + {}, + ], + 112: [ + function(require, module, exports) { + (function(Buffer) { + module.exports = function xor(a, b) { + var length = Math.min(a.length, b.length); + var buffer = new Buffer(length); + + for (var i = 0; i < length; ++i) { + buffer[i] = a[i] ^ b[i]; + } -Point.prototype.mulAdd = function mulAdd() { - throw new Error('Not supported on Montgomery curve'); -}; + return buffer; + }; + }.call(this, require('buffer').Buffer)); + }, + { buffer: 113 }, + ], + 113: [ + function(require, module, exports) { + (function(global) { + /*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ + /* eslint-disable no-proto */ -Point.prototype.jumlAdd = function jumlAdd() { - throw new Error('Not supported on Montgomery curve'); -}; + 'use strict'; -Point.prototype.eq = function eq(other) { - return this.getX().cmp(other.getX()) === 0; -}; + var base64 = require('base64-js'); + var ieee754 = require('ieee754'); + var isArray = require('isarray'); -Point.prototype.normalize = function normalize() { - this.x = this.x.redMul(this.z.redInvm()); - this.z = this.curve.one; - return this; -}; + exports.Buffer = Buffer; + exports.SlowBuffer = SlowBuffer; + exports.INSPECT_MAX_BYTES = 50; -Point.prototype.getX = function getX() { - // Normalize coordinates - this.normalize(); + /** + * If `Buffer.TYPED_ARRAY_SUPPORT`: + * === true Use Uint8Array implementation (fastest) + * === false Use Object implementation (most compatible, even IE6) + * + * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, + * Opera 11.6+, iOS 4.2+. + * + * Due to various browser bugs, sometimes the Object implementation will be used even + * when the browser supports typed arrays. + * + * Note: + * + * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, + * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. + * + * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. + * + * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of + * incorrect length in some situations. - return this.x.fromRed(); -}; + * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they + * get the Object implementation, which is slower but behaves correctly. + */ + Buffer.TYPED_ARRAY_SUPPORT = + global.TYPED_ARRAY_SUPPORT !== undefined ? global.TYPED_ARRAY_SUPPORT : typedArraySupport(); -},{"../../elliptic":93,"../curve":96,"bn.js":92,"inherits":184}],98:[function(require,module,exports){ -'use strict'; + /* + * Export kMaxLength after typed array support is determined. + */ + exports.kMaxLength = kMaxLength(); -var curve = require('../curve'); -var elliptic = require('../../elliptic'); -var BN = require('bn.js'); -var inherits = require('inherits'); -var Base = curve.base; + function typedArraySupport() { + try { + var arr = new Uint8Array(1); + arr.__proto__ = { + __proto__: Uint8Array.prototype, + foo: function() { + return 42; + }, + }; + return ( + arr.foo() === 42 && // typed array instances can be augmented + typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` + arr.subarray(1, 1).byteLength === 0 + ); // ie10 has broken `subarray` + } catch (e) { + return false; + } + } -var assert = elliptic.utils.assert; + function kMaxLength() { + return Buffer.TYPED_ARRAY_SUPPORT ? 0x7fffffff : 0x3fffffff; + } -function ShortCurve(conf) { - Base.call(this, 'short', conf); + function createBuffer(that, length) { + if (kMaxLength() < length) { + throw new RangeError('Invalid typed array length'); + } + if (Buffer.TYPED_ARRAY_SUPPORT) { + // Return an augmented `Uint8Array` instance, for best performance + that = new Uint8Array(length); + that.__proto__ = Buffer.prototype; + } else { + // Fallback: Return an object instance of the Buffer class + if (that === null) { + that = new Buffer(length); + } + that.length = length; + } - this.a = new BN(conf.a, 16).toRed(this.red); - this.b = new BN(conf.b, 16).toRed(this.red); - this.tinv = this.two.redInvm(); + return that; + } - this.zeroA = this.a.fromRed().cmpn(0) === 0; - this.threeA = this.a.fromRed().sub(this.p).cmpn(-3) === 0; + /** + * The Buffer constructor returns instances of `Uint8Array` that have their + * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of + * `Uint8Array`, so the returned instances will have all the node `Buffer` methods + * and the `Uint8Array` methods. Square bracket notation works as expected -- it + * returns a single octet. + * + * The `Uint8Array` prototype remains unmodified. + */ + + function Buffer(arg, encodingOrOffset, length) { + if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { + return new Buffer(arg, encodingOrOffset, length); + } - // If the curve is endomorphic, precalculate beta and lambda - this.endo = this._getEndomorphism(conf); - this._endoWnafT1 = new Array(4); - this._endoWnafT2 = new Array(4); -} -inherits(ShortCurve, Base); -module.exports = ShortCurve; - -ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) { - // No efficient endomorphism - if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1) - return; - - // Compute beta and lambda, that lambda * P = (beta * Px; Py) - var beta; - var lambda; - if (conf.beta) { - beta = new BN(conf.beta, 16).toRed(this.red); - } else { - var betas = this._getEndoRoots(this.p); - // Choose the smallest beta - beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1]; - beta = beta.toRed(this.red); - } - if (conf.lambda) { - lambda = new BN(conf.lambda, 16); - } else { - // Choose the lambda that is matching selected beta - var lambdas = this._getEndoRoots(this.n); - if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) { - lambda = lambdas[0]; - } else { - lambda = lambdas[1]; - assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0); - } - } + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new Error('If encoding is specified then the first argument must be a string'); + } + return allocUnsafe(this, arg); + } + return from(this, arg, encodingOrOffset, length); + } - // Get basis vectors, used for balanced length-two representation - var basis; - if (conf.basis) { - basis = conf.basis.map(function(vec) { - return { - a: new BN(vec.a, 16), - b: new BN(vec.b, 16) - }; - }); - } else { - basis = this._getEndoBasis(lambda); - } + Buffer.poolSize = 8192; // not used by this implementation - return { - beta: beta, - lambda: lambda, - basis: basis - }; -}; - -ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) { - // Find roots of for x^2 + x + 1 in F - // Root = (-1 +- Sqrt(-3)) / 2 - // - var red = num === this.p ? this.red : BN.mont(num); - var tinv = new BN(2).toRed(red).redInvm(); - var ntinv = tinv.redNeg(); - - var s = new BN(3).toRed(red).redNeg().redSqrt().redMul(tinv); - - var l1 = ntinv.redAdd(s).fromRed(); - var l2 = ntinv.redSub(s).fromRed(); - return [ l1, l2 ]; -}; - -ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) { - // aprxSqrt >= sqrt(this.n) - var aprxSqrt = this.n.ushrn(Math.floor(this.n.bitLength() / 2)); - - // 3.74 - // Run EGCD, until r(L + 1) < aprxSqrt - var u = lambda; - var v = this.n.clone(); - var x1 = new BN(1); - var y1 = new BN(0); - var x2 = new BN(0); - var y2 = new BN(1); - - // NOTE: all vectors are roots of: a + b * lambda = 0 (mod n) - var a0; - var b0; - // First vector - var a1; - var b1; - // Second vector - var a2; - var b2; - - var prevR; - var i = 0; - var r; - var x; - while (u.cmpn(0) !== 0) { - var q = v.div(u); - r = v.sub(q.mul(u)); - x = x2.sub(q.mul(x1)); - var y = y2.sub(q.mul(y1)); - - if (!a1 && r.cmp(aprxSqrt) < 0) { - a0 = prevR.neg(); - b0 = x1; - a1 = r.neg(); - b1 = x; - } else if (a1 && ++i === 2) { - break; - } - prevR = r; - - v = u; - u = r; - x2 = x1; - x1 = x; - y2 = y1; - y1 = y; - } - a2 = r.neg(); - b2 = x; - - var len1 = a1.sqr().add(b1.sqr()); - var len2 = a2.sqr().add(b2.sqr()); - if (len2.cmp(len1) >= 0) { - a2 = a0; - b2 = b0; - } + // TODO: Legacy, not needed anymore. Remove in next major version. + Buffer._augment = function(arr) { + arr.__proto__ = Buffer.prototype; + return arr; + }; - // Normalize signs - if (a1.negative) { - a1 = a1.neg(); - b1 = b1.neg(); - } - if (a2.negative) { - a2 = a2.neg(); - b2 = b2.neg(); - } + function from(that, value, encodingOrOffset, length) { + if (typeof value === 'number') { + throw new TypeError('"value" argument must not be a number'); + } - return [ - { a: a1, b: b1 }, - { a: a2, b: b2 } - ]; -}; - -ShortCurve.prototype._endoSplit = function _endoSplit(k) { - var basis = this.endo.basis; - var v1 = basis[0]; - var v2 = basis[1]; - - var c1 = v2.b.mul(k).divRound(this.n); - var c2 = v1.b.neg().mul(k).divRound(this.n); - - var p1 = c1.mul(v1.a); - var p2 = c2.mul(v2.a); - var q1 = c1.mul(v1.b); - var q2 = c2.mul(v2.b); - - // Calculate answer - var k1 = k.sub(p1).sub(p2); - var k2 = q1.add(q2).neg(); - return { k1: k1, k2: k2 }; -}; - -ShortCurve.prototype.pointFromX = function pointFromX(x, odd) { - x = new BN(x, 16); - if (!x.red) - x = x.toRed(this.red); - - var y2 = x.redSqr().redMul(x).redIAdd(x.redMul(this.a)).redIAdd(this.b); - var y = y2.redSqrt(); - if (y.redSqr().redSub(y2).cmp(this.zero) !== 0) - throw new Error('invalid point'); - - // XXX Is there any way to tell if the number is odd without converting it - // to non-red form? - var isOdd = y.fromRed().isOdd(); - if (odd && !isOdd || !odd && isOdd) - y = y.redNeg(); - - return this.point(x, y); -}; - -ShortCurve.prototype.validate = function validate(point) { - if (point.inf) - return true; - - var x = point.x; - var y = point.y; - - var ax = this.a.redMul(x); - var rhs = x.redSqr().redMul(x).redIAdd(ax).redIAdd(this.b); - return y.redSqr().redISub(rhs).cmpn(0) === 0; -}; - -ShortCurve.prototype._endoWnafMulAdd = - function _endoWnafMulAdd(points, coeffs, jacobianResult) { - var npoints = this._endoWnafT1; - var ncoeffs = this._endoWnafT2; - for (var i = 0; i < points.length; i++) { - var split = this._endoSplit(coeffs[i]); - var p = points[i]; - var beta = p._getBeta(); - - if (split.k1.negative) { - split.k1.ineg(); - p = p.neg(true); - } - if (split.k2.negative) { - split.k2.ineg(); - beta = beta.neg(true); - } + if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { + return fromArrayBuffer(that, value, encodingOrOffset, length); + } - npoints[i * 2] = p; - npoints[i * 2 + 1] = beta; - ncoeffs[i * 2] = split.k1; - ncoeffs[i * 2 + 1] = split.k2; - } - var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2, jacobianResult); + if (typeof value === 'string') { + return fromString(that, value, encodingOrOffset); + } - // Clean-up references to points and coefficients - for (var j = 0; j < i * 2; j++) { - npoints[j] = null; - ncoeffs[j] = null; - } - return res; -}; - -function Point(curve, x, y, isRed) { - Base.BasePoint.call(this, curve, 'affine'); - if (x === null && y === null) { - this.x = null; - this.y = null; - this.inf = true; - } else { - this.x = new BN(x, 16); - this.y = new BN(y, 16); - // Force redgomery representation when loading from JSON - if (isRed) { - this.x.forceRed(this.curve.red); - this.y.forceRed(this.curve.red); - } - if (!this.x.red) - this.x = this.x.toRed(this.curve.red); - if (!this.y.red) - this.y = this.y.toRed(this.curve.red); - this.inf = false; - } -} -inherits(Point, Base.BasePoint); - -ShortCurve.prototype.point = function point(x, y, isRed) { - return new Point(this, x, y, isRed); -}; - -ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) { - return Point.fromJSON(this, obj, red); -}; - -Point.prototype._getBeta = function _getBeta() { - if (!this.curve.endo) - return; - - var pre = this.precomputed; - if (pre && pre.beta) - return pre.beta; - - var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y); - if (pre) { - var curve = this.curve; - var endoMul = function(p) { - return curve.point(p.x.redMul(curve.endo.beta), p.y); - }; - pre.beta = beta; - beta.precomputed = { - beta: null, - naf: pre.naf && { - wnd: pre.naf.wnd, - points: pre.naf.points.map(endoMul) - }, - doubles: pre.doubles && { - step: pre.doubles.step, - points: pre.doubles.points.map(endoMul) - } - }; - } - return beta; -}; - -Point.prototype.toJSON = function toJSON() { - if (!this.precomputed) - return [ this.x, this.y ]; - - return [ this.x, this.y, this.precomputed && { - doubles: this.precomputed.doubles && { - step: this.precomputed.doubles.step, - points: this.precomputed.doubles.points.slice(1) - }, - naf: this.precomputed.naf && { - wnd: this.precomputed.naf.wnd, - points: this.precomputed.naf.points.slice(1) - } - } ]; -}; - -Point.fromJSON = function fromJSON(curve, obj, red) { - if (typeof obj === 'string') - obj = JSON.parse(obj); - var res = curve.point(obj[0], obj[1], red); - if (!obj[2]) - return res; - - function obj2point(obj) { - return curve.point(obj[0], obj[1], red); - } + return fromObject(that, value); + } - var pre = obj[2]; - res.precomputed = { - beta: null, - doubles: pre.doubles && { - step: pre.doubles.step, - points: [ res ].concat(pre.doubles.points.map(obj2point)) - }, - naf: pre.naf && { - wnd: pre.naf.wnd, - points: [ res ].concat(pre.naf.points.map(obj2point)) - } - }; - return res; -}; - -Point.prototype.inspect = function inspect() { - if (this.isInfinity()) - return ''; - return ''; -}; - -Point.prototype.isInfinity = function isInfinity() { - return this.inf; -}; - -Point.prototype.add = function add(p) { - // O + P = P - if (this.inf) - return p; - - // P + O = P - if (p.inf) - return this; - - // P + P = 2P - if (this.eq(p)) - return this.dbl(); - - // P + (-P) = O - if (this.neg().eq(p)) - return this.curve.point(null, null); - - // P + Q = O - if (this.x.cmp(p.x) === 0) - return this.curve.point(null, null); - - var c = this.y.redSub(p.y); - if (c.cmpn(0) !== 0) - c = c.redMul(this.x.redSub(p.x).redInvm()); - var nx = c.redSqr().redISub(this.x).redISub(p.x); - var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); - return this.curve.point(nx, ny); -}; - -Point.prototype.dbl = function dbl() { - if (this.inf) - return this; - - // 2P = O - var ys1 = this.y.redAdd(this.y); - if (ys1.cmpn(0) === 0) - return this.curve.point(null, null); - - var a = this.curve.a; - - var x2 = this.x.redSqr(); - var dyinv = ys1.redInvm(); - var c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv); - - var nx = c.redSqr().redISub(this.x.redAdd(this.x)); - var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); - return this.curve.point(nx, ny); -}; - -Point.prototype.getX = function getX() { - return this.x.fromRed(); -}; - -Point.prototype.getY = function getY() { - return this.y.fromRed(); -}; - -Point.prototype.mul = function mul(k) { - k = new BN(k, 16); - - if (this._hasDoubles(k)) - return this.curve._fixedNafMul(this, k); - else if (this.curve.endo) - return this.curve._endoWnafMulAdd([ this ], [ k ]); - else - return this.curve._wnafMul(this, k); -}; - -Point.prototype.mulAdd = function mulAdd(k1, p2, k2) { - var points = [ this, p2 ]; - var coeffs = [ k1, k2 ]; - if (this.curve.endo) - return this.curve._endoWnafMulAdd(points, coeffs); - else - return this.curve._wnafMulAdd(1, points, coeffs, 2); -}; - -Point.prototype.jmulAdd = function jmulAdd(k1, p2, k2) { - var points = [ this, p2 ]; - var coeffs = [ k1, k2 ]; - if (this.curve.endo) - return this.curve._endoWnafMulAdd(points, coeffs, true); - else - return this.curve._wnafMulAdd(1, points, coeffs, 2, true); -}; - -Point.prototype.eq = function eq(p) { - return this === p || - this.inf === p.inf && - (this.inf || this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0); -}; - -Point.prototype.neg = function neg(_precompute) { - if (this.inf) - return this; - - var res = this.curve.point(this.x, this.y.redNeg()); - if (_precompute && this.precomputed) { - var pre = this.precomputed; - var negate = function(p) { - return p.neg(); - }; - res.precomputed = { - naf: pre.naf && { - wnd: pre.naf.wnd, - points: pre.naf.points.map(negate) - }, - doubles: pre.doubles && { - step: pre.doubles.step, - points: pre.doubles.points.map(negate) - } - }; - } - return res; -}; - -Point.prototype.toJ = function toJ() { - if (this.inf) - return this.curve.jpoint(null, null, null); - - var res = this.curve.jpoint(this.x, this.y, this.curve.one); - return res; -}; - -function JPoint(curve, x, y, z) { - Base.BasePoint.call(this, curve, 'jacobian'); - if (x === null && y === null && z === null) { - this.x = this.curve.one; - this.y = this.curve.one; - this.z = new BN(0); - } else { - this.x = new BN(x, 16); - this.y = new BN(y, 16); - this.z = new BN(z, 16); - } - if (!this.x.red) - this.x = this.x.toRed(this.curve.red); - if (!this.y.red) - this.y = this.y.toRed(this.curve.red); - if (!this.z.red) - this.z = this.z.toRed(this.curve.red); - - this.zOne = this.z === this.curve.one; -} -inherits(JPoint, Base.BasePoint); - -ShortCurve.prototype.jpoint = function jpoint(x, y, z) { - return new JPoint(this, x, y, z); -}; - -JPoint.prototype.toP = function toP() { - if (this.isInfinity()) - return this.curve.point(null, null); - - var zinv = this.z.redInvm(); - var zinv2 = zinv.redSqr(); - var ax = this.x.redMul(zinv2); - var ay = this.y.redMul(zinv2).redMul(zinv); - - return this.curve.point(ax, ay); -}; - -JPoint.prototype.neg = function neg() { - return this.curve.jpoint(this.x, this.y.redNeg(), this.z); -}; - -JPoint.prototype.add = function add(p) { - // O + P = P - if (this.isInfinity()) - return p; - - // P + O = P - if (p.isInfinity()) - return this; - - // 12M + 4S + 7A - var pz2 = p.z.redSqr(); - var z2 = this.z.redSqr(); - var u1 = this.x.redMul(pz2); - var u2 = p.x.redMul(z2); - var s1 = this.y.redMul(pz2.redMul(p.z)); - var s2 = p.y.redMul(z2.redMul(this.z)); - - var h = u1.redSub(u2); - var r = s1.redSub(s2); - if (h.cmpn(0) === 0) { - if (r.cmpn(0) !== 0) - return this.curve.jpoint(null, null, null); - else - return this.dbl(); - } + /** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + **/ + Buffer.from = function(value, encodingOrOffset, length) { + return from(null, value, encodingOrOffset, length); + }; + + if (Buffer.TYPED_ARRAY_SUPPORT) { + Buffer.prototype.__proto__ = Uint8Array.prototype; + Buffer.__proto__ = Uint8Array; + if (typeof Symbol !== 'undefined' && Symbol.species && Buffer[Symbol.species] === Buffer) { + // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 + Object.defineProperty(Buffer, Symbol.species, { + value: null, + configurable: true, + }); + } + } - var h2 = h.redSqr(); - var h3 = h2.redMul(h); - var v = u1.redMul(h2); - - var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); - var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); - var nz = this.z.redMul(p.z).redMul(h); - - return this.curve.jpoint(nx, ny, nz); -}; - -JPoint.prototype.mixedAdd = function mixedAdd(p) { - // O + P = P - if (this.isInfinity()) - return p.toJ(); - - // P + O = P - if (p.isInfinity()) - return this; - - // 8M + 3S + 7A - var z2 = this.z.redSqr(); - var u1 = this.x; - var u2 = p.x.redMul(z2); - var s1 = this.y; - var s2 = p.y.redMul(z2).redMul(this.z); - - var h = u1.redSub(u2); - var r = s1.redSub(s2); - if (h.cmpn(0) === 0) { - if (r.cmpn(0) !== 0) - return this.curve.jpoint(null, null, null); - else - return this.dbl(); - } + function assertSize(size) { + if (typeof size !== 'number') { + throw new TypeError('"size" argument must be a number'); + } else if (size < 0) { + throw new RangeError('"size" argument must not be negative'); + } + } - var h2 = h.redSqr(); - var h3 = h2.redMul(h); - var v = u1.redMul(h2); - - var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); - var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); - var nz = this.z.redMul(h); - - return this.curve.jpoint(nx, ny, nz); -}; - -JPoint.prototype.dblp = function dblp(pow) { - if (pow === 0) - return this; - if (this.isInfinity()) - return this; - if (!pow) - return this.dbl(); - - if (this.curve.zeroA || this.curve.threeA) { - var r = this; - for (var i = 0; i < pow; i++) - r = r.dbl(); - return r; - } + function alloc(that, size, fill, encoding) { + assertSize(size); + if (size <= 0) { + return createBuffer(that, size); + } + if (fill !== undefined) { + // Only pay attention to encoding if it's a string. This + // prevents accidentally sending in a number that would + // be interpretted as a start offset. + return typeof encoding === 'string' + ? createBuffer(that, size).fill(fill, encoding) + : createBuffer(that, size).fill(fill); + } + return createBuffer(that, size); + } - // 1M + 2S + 1A + N * (4S + 5M + 8A) - // N = 1 => 6M + 6S + 9A - var a = this.curve.a; - var tinv = this.curve.tinv; - - var jx = this.x; - var jy = this.y; - var jz = this.z; - var jz4 = jz.redSqr().redSqr(); - - // Reuse results - var jyd = jy.redAdd(jy); - for (var i = 0; i < pow; i++) { - var jx2 = jx.redSqr(); - var jyd2 = jyd.redSqr(); - var jyd4 = jyd2.redSqr(); - var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); - - var t1 = jx.redMul(jyd2); - var nx = c.redSqr().redISub(t1.redAdd(t1)); - var t2 = t1.redISub(nx); - var dny = c.redMul(t2); - dny = dny.redIAdd(dny).redISub(jyd4); - var nz = jyd.redMul(jz); - if (i + 1 < pow) - jz4 = jz4.redMul(jyd4); - - jx = nx; - jz = nz; - jyd = dny; - } + /** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + **/ + Buffer.alloc = function(size, fill, encoding) { + return alloc(null, size, fill, encoding); + }; + + function allocUnsafe(that, size) { + assertSize(size); + that = createBuffer(that, size < 0 ? 0 : checked(size) | 0); + if (!Buffer.TYPED_ARRAY_SUPPORT) { + for (var i = 0; i < size; ++i) { + that[i] = 0; + } + } + return that; + } - return this.curve.jpoint(jx, jyd.redMul(tinv), jz); -}; - -JPoint.prototype.dbl = function dbl() { - if (this.isInfinity()) - return this; - - if (this.curve.zeroA) - return this._zeroDbl(); - else if (this.curve.threeA) - return this._threeDbl(); - else - return this._dbl(); -}; - -JPoint.prototype._zeroDbl = function _zeroDbl() { - var nx; - var ny; - var nz; - // Z = 1 - if (this.zOne) { - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html - // #doubling-mdbl-2007-bl - // 1M + 5S + 14A - - // XX = X1^2 - var xx = this.x.redSqr(); - // YY = Y1^2 - var yy = this.y.redSqr(); - // YYYY = YY^2 - var yyyy = yy.redSqr(); - // S = 2 * ((X1 + YY)^2 - XX - YYYY) - var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); - s = s.redIAdd(s); - // M = 3 * XX + a; a = 0 - var m = xx.redAdd(xx).redIAdd(xx); - // T = M ^ 2 - 2*S - var t = m.redSqr().redISub(s).redISub(s); - - // 8 * YYYY - var yyyy8 = yyyy.redIAdd(yyyy); - yyyy8 = yyyy8.redIAdd(yyyy8); - yyyy8 = yyyy8.redIAdd(yyyy8); - - // X3 = T - nx = t; - // Y3 = M * (S - T) - 8 * YYYY - ny = m.redMul(s.redISub(t)).redISub(yyyy8); - // Z3 = 2*Y1 - nz = this.y.redAdd(this.y); - } else { - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html - // #doubling-dbl-2009-l - // 2M + 5S + 13A - - // A = X1^2 - var a = this.x.redSqr(); - // B = Y1^2 - var b = this.y.redSqr(); - // C = B^2 - var c = b.redSqr(); - // D = 2 * ((X1 + B)^2 - A - C) - var d = this.x.redAdd(b).redSqr().redISub(a).redISub(c); - d = d.redIAdd(d); - // E = 3 * A - var e = a.redAdd(a).redIAdd(a); - // F = E^2 - var f = e.redSqr(); - - // 8 * C - var c8 = c.redIAdd(c); - c8 = c8.redIAdd(c8); - c8 = c8.redIAdd(c8); - - // X3 = F - 2 * D - nx = f.redISub(d).redISub(d); - // Y3 = E * (D - X3) - 8 * C - ny = e.redMul(d.redISub(nx)).redISub(c8); - // Z3 = 2 * Y1 * Z1 - nz = this.y.redMul(this.z); - nz = nz.redIAdd(nz); - } + /** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. + * */ + Buffer.allocUnsafe = function(size) { + return allocUnsafe(null, size); + }; + /** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. + */ + Buffer.allocUnsafeSlow = function(size) { + return allocUnsafe(null, size); + }; + + function fromString(that, string, encoding) { + if (typeof encoding !== 'string' || encoding === '') { + encoding = 'utf8'; + } - return this.curve.jpoint(nx, ny, nz); -}; - -JPoint.prototype._threeDbl = function _threeDbl() { - var nx; - var ny; - var nz; - // Z = 1 - if (this.zOne) { - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html - // #doubling-mdbl-2007-bl - // 1M + 5S + 15A - - // XX = X1^2 - var xx = this.x.redSqr(); - // YY = Y1^2 - var yy = this.y.redSqr(); - // YYYY = YY^2 - var yyyy = yy.redSqr(); - // S = 2 * ((X1 + YY)^2 - XX - YYYY) - var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); - s = s.redIAdd(s); - // M = 3 * XX + a - var m = xx.redAdd(xx).redIAdd(xx).redIAdd(this.curve.a); - // T = M^2 - 2 * S - var t = m.redSqr().redISub(s).redISub(s); - // X3 = T - nx = t; - // Y3 = M * (S - T) - 8 * YYYY - var yyyy8 = yyyy.redIAdd(yyyy); - yyyy8 = yyyy8.redIAdd(yyyy8); - yyyy8 = yyyy8.redIAdd(yyyy8); - ny = m.redMul(s.redISub(t)).redISub(yyyy8); - // Z3 = 2 * Y1 - nz = this.y.redAdd(this.y); - } else { - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b - // 3M + 5S - - // delta = Z1^2 - var delta = this.z.redSqr(); - // gamma = Y1^2 - var gamma = this.y.redSqr(); - // beta = X1 * gamma - var beta = this.x.redMul(gamma); - // alpha = 3 * (X1 - delta) * (X1 + delta) - var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta)); - alpha = alpha.redAdd(alpha).redIAdd(alpha); - // X3 = alpha^2 - 8 * beta - var beta4 = beta.redIAdd(beta); - beta4 = beta4.redIAdd(beta4); - var beta8 = beta4.redAdd(beta4); - nx = alpha.redSqr().redISub(beta8); - // Z3 = (Y1 + Z1)^2 - gamma - delta - nz = this.y.redAdd(this.z).redSqr().redISub(gamma).redISub(delta); - // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2 - var ggamma8 = gamma.redSqr(); - ggamma8 = ggamma8.redIAdd(ggamma8); - ggamma8 = ggamma8.redIAdd(ggamma8); - ggamma8 = ggamma8.redIAdd(ggamma8); - ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8); - } + if (!Buffer.isEncoding(encoding)) { + throw new TypeError('"encoding" must be a valid string encoding'); + } - return this.curve.jpoint(nx, ny, nz); -}; - -JPoint.prototype._dbl = function _dbl() { - var a = this.curve.a; - - // 4M + 6S + 10A - var jx = this.x; - var jy = this.y; - var jz = this.z; - var jz4 = jz.redSqr().redSqr(); - - var jx2 = jx.redSqr(); - var jy2 = jy.redSqr(); - - var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); - - var jxd4 = jx.redAdd(jx); - jxd4 = jxd4.redIAdd(jxd4); - var t1 = jxd4.redMul(jy2); - var nx = c.redSqr().redISub(t1.redAdd(t1)); - var t2 = t1.redISub(nx); - - var jyd8 = jy2.redSqr(); - jyd8 = jyd8.redIAdd(jyd8); - jyd8 = jyd8.redIAdd(jyd8); - jyd8 = jyd8.redIAdd(jyd8); - var ny = c.redMul(t2).redISub(jyd8); - var nz = jy.redAdd(jy).redMul(jz); - - return this.curve.jpoint(nx, ny, nz); -}; - -JPoint.prototype.trpl = function trpl() { - if (!this.curve.zeroA) - return this.dbl().add(this); - - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl - // 5M + 10S + ... - - // XX = X1^2 - var xx = this.x.redSqr(); - // YY = Y1^2 - var yy = this.y.redSqr(); - // ZZ = Z1^2 - var zz = this.z.redSqr(); - // YYYY = YY^2 - var yyyy = yy.redSqr(); - // M = 3 * XX + a * ZZ2; a = 0 - var m = xx.redAdd(xx).redIAdd(xx); - // MM = M^2 - var mm = m.redSqr(); - // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM - var e = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); - e = e.redIAdd(e); - e = e.redAdd(e).redIAdd(e); - e = e.redISub(mm); - // EE = E^2 - var ee = e.redSqr(); - // T = 16*YYYY - var t = yyyy.redIAdd(yyyy); - t = t.redIAdd(t); - t = t.redIAdd(t); - t = t.redIAdd(t); - // U = (M + E)^2 - MM - EE - T - var u = m.redIAdd(e).redSqr().redISub(mm).redISub(ee).redISub(t); - // X3 = 4 * (X1 * EE - 4 * YY * U) - var yyu4 = yy.redMul(u); - yyu4 = yyu4.redIAdd(yyu4); - yyu4 = yyu4.redIAdd(yyu4); - var nx = this.x.redMul(ee).redISub(yyu4); - nx = nx.redIAdd(nx); - nx = nx.redIAdd(nx); - // Y3 = 8 * Y1 * (U * (T - U) - E * EE) - var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee))); - ny = ny.redIAdd(ny); - ny = ny.redIAdd(ny); - ny = ny.redIAdd(ny); - // Z3 = (Z1 + E)^2 - ZZ - EE - var nz = this.z.redAdd(e).redSqr().redISub(zz).redISub(ee); - - return this.curve.jpoint(nx, ny, nz); -}; - -JPoint.prototype.mul = function mul(k, kbase) { - k = new BN(k, kbase); - - return this.curve._wnafMul(this, k); -}; - -JPoint.prototype.eq = function eq(p) { - if (p.type === 'affine') - return this.eq(p.toJ()); - - if (this === p) - return true; - - // x1 * z2^2 == x2 * z1^2 - var z2 = this.z.redSqr(); - var pz2 = p.z.redSqr(); - if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0) - return false; - - // y1 * z2^3 == y2 * z1^3 - var z3 = z2.redMul(this.z); - var pz3 = pz2.redMul(p.z); - return this.y.redMul(pz3).redISub(p.y.redMul(z3)).cmpn(0) === 0; -}; - -JPoint.prototype.eqXToP = function eqXToP(x) { - var zs = this.z.redSqr(); - var rx = x.toRed(this.curve.red).redMul(zs); - if (this.x.cmp(rx) === 0) - return true; - - var xc = x.clone(); - var t = this.curve.redN.redMul(zs); - for (;;) { - xc.iadd(this.curve.n); - if (xc.cmp(this.curve.p) >= 0) - return false; - - rx.redIAdd(t); - if (this.x.cmp(rx) === 0) - return true; - } - return false; -}; - -JPoint.prototype.inspect = function inspect() { - if (this.isInfinity()) - return ''; - return ''; -}; - -JPoint.prototype.isInfinity = function isInfinity() { - // XXX This code assumes that zero is always zero in red - return this.z.cmpn(0) === 0; -}; - -},{"../../elliptic":93,"../curve":96,"bn.js":92,"inherits":184}],99:[function(require,module,exports){ -'use strict'; - -var curves = exports; - -var hash = require('hash.js'); -var elliptic = require('../elliptic'); - -var assert = elliptic.utils.assert; - -function PresetCurve(options) { - if (options.type === 'short') - this.curve = new elliptic.curve.short(options); - else if (options.type === 'edwards') - this.curve = new elliptic.curve.edwards(options); - else - this.curve = new elliptic.curve.mont(options); - this.g = this.curve.g; - this.n = this.curve.n; - this.hash = options.hash; - - assert(this.g.validate(), 'Invalid curve'); - assert(this.g.mul(this.n).isInfinity(), 'Invalid curve, G*N != O'); -} -curves.PresetCurve = PresetCurve; - -function defineCurve(name, options) { - Object.defineProperty(curves, name, { - configurable: true, - enumerable: true, - get: function() { - var curve = new PresetCurve(options); - Object.defineProperty(curves, name, { - configurable: true, - enumerable: true, - value: curve - }); - return curve; - } - }); -} + var length = byteLength(string, encoding) | 0; + that = createBuffer(that, length); -defineCurve('p192', { - type: 'short', - prime: 'p192', - p: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff', - a: 'ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc', - b: '64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1', - n: 'ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831', - hash: hash.sha256, - gRed: false, - g: [ - '188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012', - '07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811' - ] -}); - -defineCurve('p224', { - type: 'short', - prime: 'p224', - p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001', - a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe', - b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4', - n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d', - hash: hash.sha256, - gRed: false, - g: [ - 'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21', - 'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34' - ] -}); - -defineCurve('p256', { - type: 'short', - prime: null, - p: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff', - a: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc', - b: '5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b', - n: 'ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551', - hash: hash.sha256, - gRed: false, - g: [ - '6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296', - '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5' - ] -}); - -defineCurve('p384', { - type: 'short', - prime: null, - p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + - 'fffffffe ffffffff 00000000 00000000 ffffffff', - a: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + - 'fffffffe ffffffff 00000000 00000000 fffffffc', - b: 'b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 0314088f ' + - '5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef', - n: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff c7634d81 ' + - 'f4372ddf 581a0db2 48b0a77a ecec196a ccc52973', - hash: hash.sha384, - gRed: false, - g: [ - 'aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 59f741e0 82542a38 ' + - '5502f25d bf55296c 3a545e38 72760ab7', - '3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c e9da3113 b5f0b8c0 ' + - '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f' - ] -}); - -defineCurve('p521', { - type: 'short', - prime: null, - p: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + - 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + - 'ffffffff ffffffff ffffffff ffffffff ffffffff', - a: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + - 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + - 'ffffffff ffffffff ffffffff ffffffff fffffffc', - b: '00000051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b ' + - '99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd ' + - '3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00', - n: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + - 'ffffffff ffffffff fffffffa 51868783 bf2f966b 7fcc0148 ' + - 'f709a5d0 3bb5c9b8 899c47ae bb6fb71e 91386409', - hash: hash.sha512, - gRed: false, - g: [ - '000000c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 ' + - '053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 ' + - 'a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66', - '00000118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 ' + - '579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901 ' + - '3fad0761 353c7086 a272c240 88be9476 9fd16650' - ] -}); - -defineCurve('curve25519', { - type: 'mont', - prime: 'p25519', - p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', - a: '76d06', - b: '1', - n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', - hash: hash.sha256, - gRed: false, - g: [ - '9' - ] -}); - -defineCurve('ed25519', { - type: 'edwards', - prime: 'p25519', - p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', - a: '-1', - c: '1', - // -121665 * (121666^(-1)) (mod P) - d: '52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3', - n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', - hash: hash.sha256, - gRed: false, - g: [ - '216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a', - - // 4/5 - '6666666666666666666666666666666666666666666666666666666666666658' - ] -}); - -var pre; -try { - pre = require('./precomputed/secp256k1'); -} catch (e) { - pre = undefined; -} + var actual = that.write(string, encoding); -defineCurve('secp256k1', { - type: 'short', - prime: 'k256', - p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f', - a: '0', - b: '7', - n: 'ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141', - h: '1', - hash: hash.sha256, - - // Precomputed endomorphism - beta: '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee', - lambda: '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72', - basis: [ - { - a: '3086d221a7d46bcde86c90e49284eb15', - b: '-e4437ed6010e88286f547fa90abfe4c3' - }, - { - a: '114ca50f7a8e2f3f657c1108d9d44cfd8', - b: '3086d221a7d46bcde86c90e49284eb15' - } - ], + if (actual !== length) { + // Writing a hex string, for example, that contains invalid characters will + // cause everything after the first invalid character to be ignored. (e.g. + // 'abxxcd' will be treated as 'ab') + that = that.slice(0, actual); + } - gRed: false, - g: [ - '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', - '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', - pre - ] -}); + return that; + } -},{"../elliptic":93,"./precomputed/secp256k1":106,"hash.js":168}],100:[function(require,module,exports){ -'use strict'; + function fromArrayLike(that, array) { + var length = array.length < 0 ? 0 : checked(array.length) | 0; + that = createBuffer(that, length); + for (var i = 0; i < length; i += 1) { + that[i] = array[i] & 255; + } + return that; + } -var BN = require('bn.js'); -var HmacDRBG = require('hmac-drbg'); -var elliptic = require('../../elliptic'); -var utils = elliptic.utils; -var assert = utils.assert; + function fromArrayBuffer(that, array, byteOffset, length) { + array.byteLength; // this throws if `array` is not a valid ArrayBuffer -var KeyPair = require('./key'); -var Signature = require('./signature'); + if (byteOffset < 0 || array.byteLength < byteOffset) { + throw new RangeError("'offset' is out of bounds"); + } -function EC(options) { - if (!(this instanceof EC)) - return new EC(options); + if (array.byteLength < byteOffset + (length || 0)) { + throw new RangeError("'length' is out of bounds"); + } - // Shortcut `elliptic.ec(curve-name)` - if (typeof options === 'string') { - assert(elliptic.curves.hasOwnProperty(options), 'Unknown curve ' + options); + if (byteOffset === undefined && length === undefined) { + array = new Uint8Array(array); + } else if (length === undefined) { + array = new Uint8Array(array, byteOffset); + } else { + array = new Uint8Array(array, byteOffset, length); + } - options = elliptic.curves[options]; - } + if (Buffer.TYPED_ARRAY_SUPPORT) { + // Return an augmented `Uint8Array` instance, for best performance + that = array; + that.__proto__ = Buffer.prototype; + } else { + // Fallback: Return an object instance of the Buffer class + that = fromArrayLike(that, array); + } + return that; + } - // Shortcut for `elliptic.ec(elliptic.curves.curveName)` - if (options instanceof elliptic.curves.PresetCurve) - options = { curve: options }; + function fromObject(that, obj) { + if (Buffer.isBuffer(obj)) { + var len = checked(obj.length) | 0; + that = createBuffer(that, len); - this.curve = options.curve.curve; - this.n = this.curve.n; - this.nh = this.n.ushrn(1); - this.g = this.curve.g; + if (that.length === 0) { + return that; + } - // Point on curve - this.g = options.curve.g; - this.g.precompute(options.curve.n.bitLength() + 1); + obj.copy(that, 0, 0, len); + return that; + } - // Hash for function for DRBG - this.hash = options.hash || options.curve.hash; -} -module.exports = EC; - -EC.prototype.keyPair = function keyPair(options) { - return new KeyPair(this, options); -}; - -EC.prototype.keyFromPrivate = function keyFromPrivate(priv, enc) { - return KeyPair.fromPrivate(this, priv, enc); -}; - -EC.prototype.keyFromPublic = function keyFromPublic(pub, enc) { - return KeyPair.fromPublic(this, pub, enc); -}; - -EC.prototype.genKeyPair = function genKeyPair(options) { - if (!options) - options = {}; - - // Instantiate Hmac_DRBG - var drbg = new HmacDRBG({ - hash: this.hash, - pers: options.pers, - persEnc: options.persEnc || 'utf8', - entropy: options.entropy || elliptic.rand(this.hash.hmacStrength), - entropyEnc: options.entropy && options.entropyEnc || 'utf8', - nonce: this.n.toArray() - }); - - var bytes = this.n.byteLength(); - var ns2 = this.n.sub(new BN(2)); - do { - var priv = new BN(drbg.generate(bytes)); - if (priv.cmp(ns2) > 0) - continue; - - priv.iaddn(1); - return this.keyFromPrivate(priv); - } while (true); -}; - -EC.prototype._truncateToN = function truncateToN(msg, truncOnly) { - var delta = msg.byteLength() * 8 - this.n.bitLength(); - if (delta > 0) - msg = msg.ushrn(delta); - if (!truncOnly && msg.cmp(this.n) >= 0) - return msg.sub(this.n); - else - return msg; -}; - -EC.prototype.sign = function sign(msg, key, enc, options) { - if (typeof enc === 'object') { - options = enc; - enc = null; - } - if (!options) - options = {}; - - key = this.keyFromPrivate(key, enc); - msg = this._truncateToN(new BN(msg, 16)); - - // Zero-extend key to provide enough entropy - var bytes = this.n.byteLength(); - var bkey = key.getPrivate().toArray('be', bytes); - - // Zero-extend nonce to have the same byte size as N - var nonce = msg.toArray('be', bytes); - - // Instantiate Hmac_DRBG - var drbg = new HmacDRBG({ - hash: this.hash, - entropy: bkey, - nonce: nonce, - pers: options.pers, - persEnc: options.persEnc || 'utf8' - }); - - // Number of bytes to generate - var ns1 = this.n.sub(new BN(1)); - - for (var iter = 0; true; iter++) { - var k = options.k ? - options.k(iter) : - new BN(drbg.generate(this.n.byteLength())); - k = this._truncateToN(k, true); - if (k.cmpn(1) <= 0 || k.cmp(ns1) >= 0) - continue; - - var kp = this.g.mul(k); - if (kp.isInfinity()) - continue; - - var kpX = kp.getX(); - var r = kpX.umod(this.n); - if (r.cmpn(0) === 0) - continue; - - var s = k.invm(this.n).mul(r.mul(key.getPrivate()).iadd(msg)); - s = s.umod(this.n); - if (s.cmpn(0) === 0) - continue; - - var recoveryParam = (kp.getY().isOdd() ? 1 : 0) | - (kpX.cmp(r) !== 0 ? 2 : 0); - - // Use complement of `s`, if it is > `n / 2` - if (options.canonical && s.cmp(this.nh) > 0) { - s = this.n.sub(s); - recoveryParam ^= 1; - } + if (obj) { + if ((typeof ArrayBuffer !== 'undefined' && obj.buffer instanceof ArrayBuffer) || 'length' in obj) { + if (typeof obj.length !== 'number' || isnan(obj.length)) { + return createBuffer(that, 0); + } + return fromArrayLike(that, obj); + } - return new Signature({ r: r, s: s, recoveryParam: recoveryParam }); - } -}; - -EC.prototype.verify = function verify(msg, signature, key, enc) { - msg = this._truncateToN(new BN(msg, 16)); - key = this.keyFromPublic(key, enc); - signature = new Signature(signature, 'hex'); - - // Perform primitive values validation - var r = signature.r; - var s = signature.s; - if (r.cmpn(1) < 0 || r.cmp(this.n) >= 0) - return false; - if (s.cmpn(1) < 0 || s.cmp(this.n) >= 0) - return false; - - // Validate signature - var sinv = s.invm(this.n); - var u1 = sinv.mul(msg).umod(this.n); - var u2 = sinv.mul(r).umod(this.n); - - if (!this.curve._maxwellTrick) { - var p = this.g.mulAdd(u1, key.getPublic(), u2); - if (p.isInfinity()) - return false; - - return p.getX().umod(this.n).cmp(r) === 0; - } + if (obj.type === 'Buffer' && isArray(obj.data)) { + return fromArrayLike(that, obj.data); + } + } - // NOTE: Greg Maxwell's trick, inspired by: - // https://git.io/vad3K - - var p = this.g.jmulAdd(u1, key.getPublic(), u2); - if (p.isInfinity()) - return false; - - // Compare `p.x` of Jacobian point with `r`, - // this will do `p.x == r * p.z^2` instead of multiplying `p.x` by the - // inverse of `p.z^2` - return p.eqXToP(r); -}; - -EC.prototype.recoverPubKey = function(msg, signature, j, enc) { - assert((3 & j) === j, 'The recovery param is more than two bits'); - signature = new Signature(signature, enc); - - var n = this.n; - var e = new BN(msg); - var r = signature.r; - var s = signature.s; - - // A set LSB signifies that the y-coordinate is odd - var isYOdd = j & 1; - var isSecondKey = j >> 1; - if (r.cmp(this.curve.p.umod(this.curve.n)) >= 0 && isSecondKey) - throw new Error('Unable to find sencond key candinate'); - - // 1.1. Let x = r + jn. - if (isSecondKey) - r = this.curve.pointFromX(r.add(this.curve.n), isYOdd); - else - r = this.curve.pointFromX(r, isYOdd); - - var rInv = signature.r.invm(n); - var s1 = n.sub(e).mul(rInv).umod(n); - var s2 = s.mul(rInv).umod(n); - - // 1.6.1 Compute Q = r^-1 (sR - eG) - // Q = r^-1 (sR + -eG) - return this.g.mulAdd(s1, r, s2); -}; - -EC.prototype.getKeyRecoveryParam = function(e, signature, Q, enc) { - signature = new Signature(signature, enc); - if (signature.recoveryParam !== null) - return signature.recoveryParam; - - for (var i = 0; i < 4; i++) { - var Qprime; - try { - Qprime = this.recoverPubKey(e, signature, i); - } catch (e) { - continue; - } + throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.'); + } - if (Qprime.eq(Q)) - return i; - } - throw new Error('Unable to find valid recovery factor'); -}; - -},{"../../elliptic":93,"./key":101,"./signature":102,"bn.js":92,"hmac-drbg":181}],101:[function(require,module,exports){ -'use strict'; - -var BN = require('bn.js'); -var elliptic = require('../../elliptic'); -var utils = elliptic.utils; -var assert = utils.assert; - -function KeyPair(ec, options) { - this.ec = ec; - this.priv = null; - this.pub = null; - - // KeyPair(ec, { priv: ..., pub: ... }) - if (options.priv) - this._importPrivate(options.priv, options.privEnc); - if (options.pub) - this._importPublic(options.pub, options.pubEnc); -} -module.exports = KeyPair; - -KeyPair.fromPublic = function fromPublic(ec, pub, enc) { - if (pub instanceof KeyPair) - return pub; - - return new KeyPair(ec, { - pub: pub, - pubEnc: enc - }); -}; - -KeyPair.fromPrivate = function fromPrivate(ec, priv, enc) { - if (priv instanceof KeyPair) - return priv; - - return new KeyPair(ec, { - priv: priv, - privEnc: enc - }); -}; - -KeyPair.prototype.validate = function validate() { - var pub = this.getPublic(); - - if (pub.isInfinity()) - return { result: false, reason: 'Invalid public key' }; - if (!pub.validate()) - return { result: false, reason: 'Public key is not a point' }; - if (!pub.mul(this.ec.curve.n).isInfinity()) - return { result: false, reason: 'Public key * N != O' }; - - return { result: true, reason: null }; -}; - -KeyPair.prototype.getPublic = function getPublic(compact, enc) { - // compact is optional argument - if (typeof compact === 'string') { - enc = compact; - compact = null; - } + function checked(length) { + // Note: cannot use `length < kMaxLength()` here because that fails when + // length is NaN (which is otherwise coerced to zero.) + if (length >= kMaxLength()) { + throw new RangeError( + 'Attempt to allocate Buffer larger than maximum ' + 'size: 0x' + kMaxLength().toString(16) + ' bytes', + ); + } + return length | 0; + } - if (!this.pub) - this.pub = this.ec.g.mul(this.priv); - - if (!enc) - return this.pub; - - return this.pub.encode(enc, compact); -}; - -KeyPair.prototype.getPrivate = function getPrivate(enc) { - if (enc === 'hex') - return this.priv.toString(16, 2); - else - return this.priv; -}; - -KeyPair.prototype._importPrivate = function _importPrivate(key, enc) { - this.priv = new BN(key, enc || 16); - - // Ensure that the priv won't be bigger than n, otherwise we may fail - // in fixed multiplication method - this.priv = this.priv.umod(this.ec.curve.n); -}; - -KeyPair.prototype._importPublic = function _importPublic(key, enc) { - if (key.x || key.y) { - // Montgomery points only have an `x` coordinate. - // Weierstrass/Edwards points on the other hand have both `x` and - // `y` coordinates. - if (this.ec.curve.type === 'mont') { - assert(key.x, 'Need x coordinate'); - } else if (this.ec.curve.type === 'short' || - this.ec.curve.type === 'edwards') { - assert(key.x && key.y, 'Need both x and y coordinate'); - } - this.pub = this.ec.curve.point(key.x, key.y); - return; - } - this.pub = this.ec.curve.decodePoint(key, enc); -}; - -// ECDH -KeyPair.prototype.derive = function derive(pub) { - return pub.mul(this.priv).getX(); -}; - -// ECDSA -KeyPair.prototype.sign = function sign(msg, enc, options) { - return this.ec.sign(msg, this, enc, options); -}; - -KeyPair.prototype.verify = function verify(msg, signature) { - return this.ec.verify(msg, signature, this); -}; - -KeyPair.prototype.inspect = function inspect() { - return ''; -}; - -},{"../../elliptic":93,"bn.js":92}],102:[function(require,module,exports){ -'use strict'; - -var BN = require('bn.js'); - -var elliptic = require('../../elliptic'); -var utils = elliptic.utils; -var assert = utils.assert; - -function Signature(options, enc) { - if (options instanceof Signature) - return options; - - if (this._importDER(options, enc)) - return; - - assert(options.r && options.s, 'Signature without r or s'); - this.r = new BN(options.r, 16); - this.s = new BN(options.s, 16); - if (options.recoveryParam === undefined) - this.recoveryParam = null; - else - this.recoveryParam = options.recoveryParam; -} -module.exports = Signature; + function SlowBuffer(length) { + if (+length != length) { + // eslint-disable-line eqeqeq + length = 0; + } + return Buffer.alloc(+length); + } -function Position() { - this.place = 0; -} + Buffer.isBuffer = function isBuffer(b) { + return !!(b != null && b._isBuffer); + }; -function getLength(buf, p) { - var initial = buf[p.place++]; - if (!(initial & 0x80)) { - return initial; - } - var octetLen = initial & 0xf; - var val = 0; - for (var i = 0, off = p.place; i < octetLen; i++, off++) { - val <<= 8; - val |= buf[off]; - } - p.place = off; - return val; -} + Buffer.compare = function compare(a, b) { + if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { + throw new TypeError('Arguments must be Buffers'); + } -function rmPadding(buf) { - var i = 0; - var len = buf.length - 1; - while (!buf[i] && !(buf[i + 1] & 0x80) && i < len) { - i++; - } - if (i === 0) { - return buf; - } - return buf.slice(i); -} + if (a === b) return 0; -Signature.prototype._importDER = function _importDER(data, enc) { - data = utils.toArray(data, enc); - var p = new Position(); - if (data[p.place++] !== 0x30) { - return false; - } - var len = getLength(data, p); - if ((len + p.place) !== data.length) { - return false; - } - if (data[p.place++] !== 0x02) { - return false; - } - var rlen = getLength(data, p); - var r = data.slice(p.place, rlen + p.place); - p.place += rlen; - if (data[p.place++] !== 0x02) { - return false; - } - var slen = getLength(data, p); - if (data.length !== slen + p.place) { - return false; - } - var s = data.slice(p.place, slen + p.place); - if (r[0] === 0 && (r[1] & 0x80)) { - r = r.slice(1); - } - if (s[0] === 0 && (s[1] & 0x80)) { - s = s.slice(1); - } + var x = a.length; + var y = b.length; - this.r = new BN(r); - this.s = new BN(s); - this.recoveryParam = null; + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i]; + y = b[i]; + break; + } + } - return true; -}; + if (x < y) return -1; + if (y < x) return 1; + return 0; + }; + + Buffer.isEncoding = function isEncoding(encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'latin1': + case 'binary': + case 'base64': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true; + default: + return false; + } + }; -function constructLength(arr, len) { - if (len < 0x80) { - arr.push(len); - return; - } - var octets = 1 + (Math.log(len) / Math.LN2 >>> 3); - arr.push(octets | 0x80); - while (--octets) { - arr.push((len >>> (octets << 3)) & 0xff); - } - arr.push(len); -} + Buffer.concat = function concat(list, length) { + if (!isArray(list)) { + throw new TypeError('"list" argument must be an Array of Buffers'); + } -Signature.prototype.toDER = function toDER(enc) { - var r = this.r.toArray(); - var s = this.s.toArray(); + if (list.length === 0) { + return Buffer.alloc(0); + } - // Pad values - if (r[0] & 0x80) - r = [ 0 ].concat(r); - // Pad values - if (s[0] & 0x80) - s = [ 0 ].concat(s); + var i; + if (length === undefined) { + length = 0; + for (i = 0; i < list.length; ++i) { + length += list[i].length; + } + } - r = rmPadding(r); - s = rmPadding(s); + var buffer = Buffer.allocUnsafe(length); + var pos = 0; + for (i = 0; i < list.length; ++i) { + var buf = list[i]; + if (!Buffer.isBuffer(buf)) { + throw new TypeError('"list" argument must be an Array of Buffers'); + } + buf.copy(buffer, pos); + pos += buf.length; + } + return buffer; + }; - while (!s[0] && !(s[1] & 0x80)) { - s = s.slice(1); - } - var arr = [ 0x02 ]; - constructLength(arr, r.length); - arr = arr.concat(r); - arr.push(0x02); - constructLength(arr, s.length); - var backHalf = arr.concat(s); - var res = [ 0x30 ]; - constructLength(res, backHalf.length); - res = res.concat(backHalf); - return utils.encode(res, enc); -}; - -},{"../../elliptic":93,"bn.js":92}],103:[function(require,module,exports){ -'use strict'; - -var hash = require('hash.js'); -var elliptic = require('../../elliptic'); -var utils = elliptic.utils; -var assert = utils.assert; -var parseBytes = utils.parseBytes; -var KeyPair = require('./key'); -var Signature = require('./signature'); - -function EDDSA(curve) { - assert(curve === 'ed25519', 'only tested with ed25519 so far'); - - if (!(this instanceof EDDSA)) - return new EDDSA(curve); - - var curve = elliptic.curves[curve].curve; - this.curve = curve; - this.g = curve.g; - this.g.precompute(curve.n.bitLength() + 1); - - this.pointClass = curve.point().constructor; - this.encodingLength = Math.ceil(curve.n.bitLength() / 8); - this.hash = hash.sha512; -} + function byteLength(string, encoding) { + if (Buffer.isBuffer(string)) { + return string.length; + } + if ( + typeof ArrayBuffer !== 'undefined' && + typeof ArrayBuffer.isView === 'function' && + (ArrayBuffer.isView(string) || string instanceof ArrayBuffer) + ) { + return string.byteLength; + } + if (typeof string !== 'string') { + string = '' + string; + } -module.exports = EDDSA; + var len = string.length; + if (len === 0) return 0; + + // Use a for loop to avoid recursion + var loweredCase = false; + for (;;) { + switch (encoding) { + case 'ascii': + case 'latin1': + case 'binary': + return len; + case 'utf8': + case 'utf-8': + case undefined: + return utf8ToBytes(string).length; + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return len * 2; + case 'hex': + return len >>> 1; + case 'base64': + return base64ToBytes(string).length; + default: + if (loweredCase) return utf8ToBytes(string).length; // assume utf8 + encoding = ('' + encoding).toLowerCase(); + loweredCase = true; + } + } + } + Buffer.byteLength = byteLength; -/** -* @param {Array|String} message - message bytes -* @param {Array|String|KeyPair} secret - secret bytes or a keypair -* @returns {Signature} - signature -*/ -EDDSA.prototype.sign = function sign(message, secret) { - message = parseBytes(message); - var key = this.keyFromSecret(secret); - var r = this.hashInt(key.messagePrefix(), message); - var R = this.g.mul(r); - var Rencoded = this.encodePoint(R); - var s_ = this.hashInt(Rencoded, key.pubBytes(), message) - .mul(key.priv()); - var S = r.add(s_).umod(this.curve.n); - return this.makeSignature({ R: R, S: S, Rencoded: Rencoded }); -}; - -/** -* @param {Array} message - message bytes -* @param {Array|String|Signature} sig - sig bytes -* @param {Array|String|Point|KeyPair} pub - public key -* @returns {Boolean} - true if public key matches sig of message -*/ -EDDSA.prototype.verify = function verify(message, sig, pub) { - message = parseBytes(message); - sig = this.makeSignature(sig); - var key = this.keyFromPublic(pub); - var h = this.hashInt(sig.Rencoded(), key.pubBytes(), message); - var SG = this.g.mul(sig.S()); - var RplusAh = sig.R().add(key.pub().mul(h)); - return RplusAh.eq(SG); -}; - -EDDSA.prototype.hashInt = function hashInt() { - var hash = this.hash(); - for (var i = 0; i < arguments.length; i++) - hash.update(arguments[i]); - return utils.intFromLE(hash.digest()).umod(this.curve.n); -}; - -EDDSA.prototype.keyFromPublic = function keyFromPublic(pub) { - return KeyPair.fromPublic(this, pub); -}; - -EDDSA.prototype.keyFromSecret = function keyFromSecret(secret) { - return KeyPair.fromSecret(this, secret); -}; - -EDDSA.prototype.makeSignature = function makeSignature(sig) { - if (sig instanceof Signature) - return sig; - return new Signature(this, sig); -}; - -/** -* * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-5.2 -* -* EDDSA defines methods for encoding and decoding points and integers. These are -* helper convenience methods, that pass along to utility functions implied -* parameters. -* -*/ -EDDSA.prototype.encodePoint = function encodePoint(point) { - var enc = point.getY().toArray('le', this.encodingLength); - enc[this.encodingLength - 1] |= point.getX().isOdd() ? 0x80 : 0; - return enc; -}; - -EDDSA.prototype.decodePoint = function decodePoint(bytes) { - bytes = utils.parseBytes(bytes); - - var lastIx = bytes.length - 1; - var normed = bytes.slice(0, lastIx).concat(bytes[lastIx] & ~0x80); - var xIsOdd = (bytes[lastIx] & 0x80) !== 0; - - var y = utils.intFromLE(normed); - return this.curve.pointFromY(y, xIsOdd); -}; - -EDDSA.prototype.encodeInt = function encodeInt(num) { - return num.toArray('le', this.encodingLength); -}; - -EDDSA.prototype.decodeInt = function decodeInt(bytes) { - return utils.intFromLE(bytes); -}; - -EDDSA.prototype.isPoint = function isPoint(val) { - return val instanceof this.pointClass; -}; - -},{"../../elliptic":93,"./key":104,"./signature":105,"hash.js":168}],104:[function(require,module,exports){ -'use strict'; - -var elliptic = require('../../elliptic'); -var utils = elliptic.utils; -var assert = utils.assert; -var parseBytes = utils.parseBytes; -var cachedProperty = utils.cachedProperty; - -/** -* @param {EDDSA} eddsa - instance -* @param {Object} params - public/private key parameters -* -* @param {Array} [params.secret] - secret seed bytes -* @param {Point} [params.pub] - public key point (aka `A` in eddsa terms) -* @param {Array} [params.pub] - public key point encoded as bytes -* -*/ -function KeyPair(eddsa, params) { - this.eddsa = eddsa; - this._secret = parseBytes(params.secret); - if (eddsa.isPoint(params.pub)) - this._pub = params.pub; - else - this._pubBytes = parseBytes(params.pub); -} + function slowToString(encoding, start, end) { + var loweredCase = false; -KeyPair.fromPublic = function fromPublic(eddsa, pub) { - if (pub instanceof KeyPair) - return pub; - return new KeyPair(eddsa, { pub: pub }); -}; - -KeyPair.fromSecret = function fromSecret(eddsa, secret) { - if (secret instanceof KeyPair) - return secret; - return new KeyPair(eddsa, { secret: secret }); -}; - -KeyPair.prototype.secret = function secret() { - return this._secret; -}; - -cachedProperty(KeyPair, 'pubBytes', function pubBytes() { - return this.eddsa.encodePoint(this.pub()); -}); - -cachedProperty(KeyPair, 'pub', function pub() { - if (this._pubBytes) - return this.eddsa.decodePoint(this._pubBytes); - return this.eddsa.g.mul(this.priv()); -}); - -cachedProperty(KeyPair, 'privBytes', function privBytes() { - var eddsa = this.eddsa; - var hash = this.hash(); - var lastIx = eddsa.encodingLength - 1; - - var a = hash.slice(0, eddsa.encodingLength); - a[0] &= 248; - a[lastIx] &= 127; - a[lastIx] |= 64; - - return a; -}); - -cachedProperty(KeyPair, 'priv', function priv() { - return this.eddsa.decodeInt(this.privBytes()); -}); - -cachedProperty(KeyPair, 'hash', function hash() { - return this.eddsa.hash().update(this.secret()).digest(); -}); - -cachedProperty(KeyPair, 'messagePrefix', function messagePrefix() { - return this.hash().slice(this.eddsa.encodingLength); -}); - -KeyPair.prototype.sign = function sign(message) { - assert(this._secret, 'KeyPair can only verify'); - return this.eddsa.sign(message, this); -}; - -KeyPair.prototype.verify = function verify(message, sig) { - return this.eddsa.verify(message, sig, this); -}; - -KeyPair.prototype.getSecret = function getSecret(enc) { - assert(this._secret, 'KeyPair is public only'); - return utils.encode(this.secret(), enc); -}; - -KeyPair.prototype.getPublic = function getPublic(enc) { - return utils.encode(this.pubBytes(), enc); -}; - -module.exports = KeyPair; - -},{"../../elliptic":93}],105:[function(require,module,exports){ -'use strict'; - -var BN = require('bn.js'); -var elliptic = require('../../elliptic'); -var utils = elliptic.utils; -var assert = utils.assert; -var cachedProperty = utils.cachedProperty; -var parseBytes = utils.parseBytes; - -/** -* @param {EDDSA} eddsa - eddsa instance -* @param {Array|Object} sig - -* @param {Array|Point} [sig.R] - R point as Point or bytes -* @param {Array|bn} [sig.S] - S scalar as bn or bytes -* @param {Array} [sig.Rencoded] - R point encoded -* @param {Array} [sig.Sencoded] - S scalar encoded -*/ -function Signature(eddsa, sig) { - this.eddsa = eddsa; + // No need to verify that "this.length <= MAX_UINT32" since it's a read-only + // property of a typed array. - if (typeof sig !== 'object') - sig = parseBytes(sig); + // This behaves neither like String nor Uint8Array in that we set start/end + // to their upper/lower bounds if the value passed is out of range. + // undefined is handled specially as per ECMA-262 6th Edition, + // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. + if (start === undefined || start < 0) { + start = 0; + } + // Return early if start > this.length. Done here to prevent potential uint32 + // coercion fail below. + if (start > this.length) { + return ''; + } - if (Array.isArray(sig)) { - sig = { - R: sig.slice(0, eddsa.encodingLength), - S: sig.slice(eddsa.encodingLength) - }; - } + if (end === undefined || end > this.length) { + end = this.length; + } - assert(sig.R && sig.S, 'Signature without R or S'); + if (end <= 0) { + return ''; + } - if (eddsa.isPoint(sig.R)) - this._R = sig.R; - if (sig.S instanceof BN) - this._S = sig.S; + // Force coersion to uint32. This will also coerce falsey/NaN values to 0. + end >>>= 0; + start >>>= 0; - this._Rencoded = Array.isArray(sig.R) ? sig.R : sig.Rencoded; - this._Sencoded = Array.isArray(sig.S) ? sig.S : sig.Sencoded; -} + if (end <= start) { + return ''; + } -cachedProperty(Signature, 'S', function S() { - return this.eddsa.decodeInt(this.Sencoded()); -}); - -cachedProperty(Signature, 'R', function R() { - return this.eddsa.decodePoint(this.Rencoded()); -}); - -cachedProperty(Signature, 'Rencoded', function Rencoded() { - return this.eddsa.encodePoint(this.R()); -}); - -cachedProperty(Signature, 'Sencoded', function Sencoded() { - return this.eddsa.encodeInt(this.S()); -}); - -Signature.prototype.toBytes = function toBytes() { - return this.Rencoded().concat(this.Sencoded()); -}; - -Signature.prototype.toHex = function toHex() { - return utils.encode(this.toBytes(), 'hex').toUpperCase(); -}; - -module.exports = Signature; - -},{"../../elliptic":93,"bn.js":92}],106:[function(require,module,exports){ -module.exports = { - doubles: { - step: 4, - points: [ - [ - 'e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a', - 'f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821' - ], - [ - '8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508', - '11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf' - ], - [ - '175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739', - 'd3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695' - ], - [ - '363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640', - '4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9' - ], - [ - '8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c', - '4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36' - ], - [ - '723cbaa6e5db996d6bf771c00bd548c7b700dbffa6c0e77bcb6115925232fcda', - '96e867b5595cc498a921137488824d6e2660a0653779494801dc069d9eb39f5f' - ], - [ - 'eebfa4d493bebf98ba5feec812c2d3b50947961237a919839a533eca0e7dd7fa', - '5d9a8ca3970ef0f269ee7edaf178089d9ae4cdc3a711f712ddfd4fdae1de8999' - ], - [ - '100f44da696e71672791d0a09b7bde459f1215a29b3c03bfefd7835b39a48db0', - 'cdd9e13192a00b772ec8f3300c090666b7ff4a18ff5195ac0fbd5cd62bc65a09' - ], - [ - 'e1031be262c7ed1b1dc9227a4a04c017a77f8d4464f3b3852c8acde6e534fd2d', - '9d7061928940405e6bb6a4176597535af292dd419e1ced79a44f18f29456a00d' - ], - [ - 'feea6cae46d55b530ac2839f143bd7ec5cf8b266a41d6af52d5e688d9094696d', - 'e57c6b6c97dce1bab06e4e12bf3ecd5c981c8957cc41442d3155debf18090088' - ], - [ - 'da67a91d91049cdcb367be4be6ffca3cfeed657d808583de33fa978bc1ec6cb1', - '9bacaa35481642bc41f463f7ec9780e5dec7adc508f740a17e9ea8e27a68be1d' - ], - [ - '53904faa0b334cdda6e000935ef22151ec08d0f7bb11069f57545ccc1a37b7c0', - '5bc087d0bc80106d88c9eccac20d3c1c13999981e14434699dcb096b022771c8' - ], - [ - '8e7bcd0bd35983a7719cca7764ca906779b53a043a9b8bcaeff959f43ad86047', - '10b7770b2a3da4b3940310420ca9514579e88e2e47fd68b3ea10047e8460372a' - ], - [ - '385eed34c1cdff21e6d0818689b81bde71a7f4f18397e6690a841e1599c43862', - '283bebc3e8ea23f56701de19e9ebf4576b304eec2086dc8cc0458fe5542e5453' - ], - [ - '6f9d9b803ecf191637c73a4413dfa180fddf84a5947fbc9c606ed86c3fac3a7', - '7c80c68e603059ba69b8e2a30e45c4d47ea4dd2f5c281002d86890603a842160' - ], - [ - '3322d401243c4e2582a2147c104d6ecbf774d163db0f5e5313b7e0e742d0e6bd', - '56e70797e9664ef5bfb019bc4ddaf9b72805f63ea2873af624f3a2e96c28b2a0' - ], - [ - '85672c7d2de0b7da2bd1770d89665868741b3f9af7643397721d74d28134ab83', - '7c481b9b5b43b2eb6374049bfa62c2e5e77f17fcc5298f44c8e3094f790313a6' - ], - [ - '948bf809b1988a46b06c9f1919413b10f9226c60f668832ffd959af60c82a0a', - '53a562856dcb6646dc6b74c5d1c3418c6d4dff08c97cd2bed4cb7f88d8c8e589' - ], - [ - '6260ce7f461801c34f067ce0f02873a8f1b0e44dfc69752accecd819f38fd8e8', - 'bc2da82b6fa5b571a7f09049776a1ef7ecd292238051c198c1a84e95b2b4ae17' - ], - [ - 'e5037de0afc1d8d43d8348414bbf4103043ec8f575bfdc432953cc8d2037fa2d', - '4571534baa94d3b5f9f98d09fb990bddbd5f5b03ec481f10e0e5dc841d755bda' - ], - [ - 'e06372b0f4a207adf5ea905e8f1771b4e7e8dbd1c6a6c5b725866a0ae4fce725', - '7a908974bce18cfe12a27bb2ad5a488cd7484a7787104870b27034f94eee31dd' - ], - [ - '213c7a715cd5d45358d0bbf9dc0ce02204b10bdde2a3f58540ad6908d0559754', - '4b6dad0b5ae462507013ad06245ba190bb4850f5f36a7eeddff2c27534b458f2' - ], - [ - '4e7c272a7af4b34e8dbb9352a5419a87e2838c70adc62cddf0cc3a3b08fbd53c', - '17749c766c9d0b18e16fd09f6def681b530b9614bff7dd33e0b3941817dcaae6' - ], - [ - 'fea74e3dbe778b1b10f238ad61686aa5c76e3db2be43057632427e2840fb27b6', - '6e0568db9b0b13297cf674deccb6af93126b596b973f7b77701d3db7f23cb96f' - ], - [ - '76e64113f677cf0e10a2570d599968d31544e179b760432952c02a4417bdde39', - 'c90ddf8dee4e95cf577066d70681f0d35e2a33d2b56d2032b4b1752d1901ac01' - ], - [ - 'c738c56b03b2abe1e8281baa743f8f9a8f7cc643df26cbee3ab150242bcbb891', - '893fb578951ad2537f718f2eacbfbbbb82314eef7880cfe917e735d9699a84c3' - ], - [ - 'd895626548b65b81e264c7637c972877d1d72e5f3a925014372e9f6588f6c14b', - 'febfaa38f2bc7eae728ec60818c340eb03428d632bb067e179363ed75d7d991f' - ], - [ - 'b8da94032a957518eb0f6433571e8761ceffc73693e84edd49150a564f676e03', - '2804dfa44805a1e4d7c99cc9762808b092cc584d95ff3b511488e4e74efdf6e7' - ], - [ - 'e80fea14441fb33a7d8adab9475d7fab2019effb5156a792f1a11778e3c0df5d', - 'eed1de7f638e00771e89768ca3ca94472d155e80af322ea9fcb4291b6ac9ec78' - ], - [ - 'a301697bdfcd704313ba48e51d567543f2a182031efd6915ddc07bbcc4e16070', - '7370f91cfb67e4f5081809fa25d40f9b1735dbf7c0a11a130c0d1a041e177ea1' - ], - [ - '90ad85b389d6b936463f9d0512678de208cc330b11307fffab7ac63e3fb04ed4', - 'e507a3620a38261affdcbd9427222b839aefabe1582894d991d4d48cb6ef150' - ], - [ - '8f68b9d2f63b5f339239c1ad981f162ee88c5678723ea3351b7b444c9ec4c0da', - '662a9f2dba063986de1d90c2b6be215dbbea2cfe95510bfdf23cbf79501fff82' - ], - [ - 'e4f3fb0176af85d65ff99ff9198c36091f48e86503681e3e6686fd5053231e11', - '1e63633ad0ef4f1c1661a6d0ea02b7286cc7e74ec951d1c9822c38576feb73bc' - ], - [ - '8c00fa9b18ebf331eb961537a45a4266c7034f2f0d4e1d0716fb6eae20eae29e', - 'efa47267fea521a1a9dc343a3736c974c2fadafa81e36c54e7d2a4c66702414b' - ], - [ - 'e7a26ce69dd4829f3e10cec0a9e98ed3143d084f308b92c0997fddfc60cb3e41', - '2a758e300fa7984b471b006a1aafbb18d0a6b2c0420e83e20e8a9421cf2cfd51' - ], - [ - 'b6459e0ee3662ec8d23540c223bcbdc571cbcb967d79424f3cf29eb3de6b80ef', - '67c876d06f3e06de1dadf16e5661db3c4b3ae6d48e35b2ff30bf0b61a71ba45' - ], - [ - 'd68a80c8280bb840793234aa118f06231d6f1fc67e73c5a5deda0f5b496943e8', - 'db8ba9fff4b586d00c4b1f9177b0e28b5b0e7b8f7845295a294c84266b133120' - ], - [ - '324aed7df65c804252dc0270907a30b09612aeb973449cea4095980fc28d3d5d', - '648a365774b61f2ff130c0c35aec1f4f19213b0c7e332843967224af96ab7c84' - ], - [ - '4df9c14919cde61f6d51dfdbe5fee5dceec4143ba8d1ca888e8bd373fd054c96', - '35ec51092d8728050974c23a1d85d4b5d506cdc288490192ebac06cad10d5d' - ], - [ - '9c3919a84a474870faed8a9c1cc66021523489054d7f0308cbfc99c8ac1f98cd', - 'ddb84f0f4a4ddd57584f044bf260e641905326f76c64c8e6be7e5e03d4fc599d' - ], - [ - '6057170b1dd12fdf8de05f281d8e06bb91e1493a8b91d4cc5a21382120a959e5', - '9a1af0b26a6a4807add9a2daf71df262465152bc3ee24c65e899be932385a2a8' - ], - [ - 'a576df8e23a08411421439a4518da31880cef0fba7d4df12b1a6973eecb94266', - '40a6bf20e76640b2c92b97afe58cd82c432e10a7f514d9f3ee8be11ae1b28ec8' - ], - [ - '7778a78c28dec3e30a05fe9629de8c38bb30d1f5cf9a3a208f763889be58ad71', - '34626d9ab5a5b22ff7098e12f2ff580087b38411ff24ac563b513fc1fd9f43ac' - ], - [ - '928955ee637a84463729fd30e7afd2ed5f96274e5ad7e5cb09eda9c06d903ac', - 'c25621003d3f42a827b78a13093a95eeac3d26efa8a8d83fc5180e935bcd091f' - ], - [ - '85d0fef3ec6db109399064f3a0e3b2855645b4a907ad354527aae75163d82751', - '1f03648413a38c0be29d496e582cf5663e8751e96877331582c237a24eb1f962' - ], - [ - 'ff2b0dce97eece97c1c9b6041798b85dfdfb6d8882da20308f5404824526087e', - '493d13fef524ba188af4c4dc54d07936c7b7ed6fb90e2ceb2c951e01f0c29907' - ], - [ - '827fbbe4b1e880ea9ed2b2e6301b212b57f1ee148cd6dd28780e5e2cf856e241', - 'c60f9c923c727b0b71bef2c67d1d12687ff7a63186903166d605b68baec293ec' - ], - [ - 'eaa649f21f51bdbae7be4ae34ce6e5217a58fdce7f47f9aa7f3b58fa2120e2b3', - 'be3279ed5bbbb03ac69a80f89879aa5a01a6b965f13f7e59d47a5305ba5ad93d' - ], - [ - 'e4a42d43c5cf169d9391df6decf42ee541b6d8f0c9a137401e23632dda34d24f', - '4d9f92e716d1c73526fc99ccfb8ad34ce886eedfa8d8e4f13a7f7131deba9414' - ], - [ - '1ec80fef360cbdd954160fadab352b6b92b53576a88fea4947173b9d4300bf19', - 'aeefe93756b5340d2f3a4958a7abbf5e0146e77f6295a07b671cdc1cc107cefd' - ], - [ - '146a778c04670c2f91b00af4680dfa8bce3490717d58ba889ddb5928366642be', - 'b318e0ec3354028add669827f9d4b2870aaa971d2f7e5ed1d0b297483d83efd0' - ], - [ - 'fa50c0f61d22e5f07e3acebb1aa07b128d0012209a28b9776d76a8793180eef9', - '6b84c6922397eba9b72cd2872281a68a5e683293a57a213b38cd8d7d3f4f2811' - ], - [ - 'da1d61d0ca721a11b1a5bf6b7d88e8421a288ab5d5bba5220e53d32b5f067ec2', - '8157f55a7c99306c79c0766161c91e2966a73899d279b48a655fba0f1ad836f1' - ], - [ - 'a8e282ff0c9706907215ff98e8fd416615311de0446f1e062a73b0610d064e13', - '7f97355b8db81c09abfb7f3c5b2515888b679a3e50dd6bd6cef7c73111f4cc0c' - ], - [ - '174a53b9c9a285872d39e56e6913cab15d59b1fa512508c022f382de8319497c', - 'ccc9dc37abfc9c1657b4155f2c47f9e6646b3a1d8cb9854383da13ac079afa73' - ], - [ - '959396981943785c3d3e57edf5018cdbe039e730e4918b3d884fdff09475b7ba', - '2e7e552888c331dd8ba0386a4b9cd6849c653f64c8709385e9b8abf87524f2fd' - ], - [ - 'd2a63a50ae401e56d645a1153b109a8fcca0a43d561fba2dbb51340c9d82b151', - 'e82d86fb6443fcb7565aee58b2948220a70f750af484ca52d4142174dcf89405' - ], - [ - '64587e2335471eb890ee7896d7cfdc866bacbdbd3839317b3436f9b45617e073', - 'd99fcdd5bf6902e2ae96dd6447c299a185b90a39133aeab358299e5e9faf6589' - ], - [ - '8481bde0e4e4d885b3a546d3e549de042f0aa6cea250e7fd358d6c86dd45e458', - '38ee7b8cba5404dd84a25bf39cecb2ca900a79c42b262e556d64b1b59779057e' - ], - [ - '13464a57a78102aa62b6979ae817f4637ffcfed3c4b1ce30bcd6303f6caf666b', - '69be159004614580ef7e433453ccb0ca48f300a81d0942e13f495a907f6ecc27' - ], - [ - 'bc4a9df5b713fe2e9aef430bcc1dc97a0cd9ccede2f28588cada3a0d2d83f366', - 'd3a81ca6e785c06383937adf4b798caa6e8a9fbfa547b16d758d666581f33c1' - ], - [ - '8c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa', - '40a30463a3305193378fedf31f7cc0eb7ae784f0451cb9459e71dc73cbef9482' - ], - [ - '8ea9666139527a8c1dd94ce4f071fd23c8b350c5a4bb33748c4ba111faccae0', - '620efabbc8ee2782e24e7c0cfb95c5d735b783be9cf0f8e955af34a30e62b945' - ], - [ - 'dd3625faef5ba06074669716bbd3788d89bdde815959968092f76cc4eb9a9787', - '7a188fa3520e30d461da2501045731ca941461982883395937f68d00c644a573' - ], - [ - 'f710d79d9eb962297e4f6232b40e8f7feb2bc63814614d692c12de752408221e', - 'ea98e67232d3b3295d3b535532115ccac8612c721851617526ae47a9c77bfc82' - ] - ] - }, - naf: { - wnd: 7, - points: [ - [ - 'f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9', - '388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672' - ], - [ - '2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4', - 'd8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6' - ], - [ - '5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc', - '6aebca40ba255960a3178d6d861a54dba813d0b813fde7b5a5082628087264da' - ], - [ - 'acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe', - 'cc338921b0a7d9fd64380971763b61e9add888a4375f8e0f05cc262ac64f9c37' - ], - [ - '774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb', - 'd984a032eb6b5e190243dd56d7b7b365372db1e2dff9d6a8301d74c9c953c61b' - ], - [ - 'f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8', - 'ab0902e8d880a89758212eb65cdaf473a1a06da521fa91f29b5cb52db03ed81' - ], - [ - 'd7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e', - '581e2872a86c72a683842ec228cc6defea40af2bd896d3a5c504dc9ff6a26b58' - ], - [ - 'defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34', - '4211ab0694635168e997b0ead2a93daeced1f4a04a95c0f6cfb199f69e56eb77' - ], - [ - '2b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c', - '85e89bc037945d93b343083b5a1c86131a01f60c50269763b570c854e5c09b7a' - ], - [ - '352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5', - '321eb4075348f534d59c18259dda3e1f4a1b3b2e71b1039c67bd3d8bcf81998c' - ], - [ - '2fa2104d6b38d11b0230010559879124e42ab8dfeff5ff29dc9cdadd4ecacc3f', - '2de1068295dd865b64569335bd5dd80181d70ecfc882648423ba76b532b7d67' - ], - [ - '9248279b09b4d68dab21a9b066edda83263c3d84e09572e269ca0cd7f5453714', - '73016f7bf234aade5d1aa71bdea2b1ff3fc0de2a887912ffe54a32ce97cb3402' - ], - [ - 'daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729', - 'a69dce4a7d6c98e8d4a1aca87ef8d7003f83c230f3afa726ab40e52290be1c55' - ], - [ - 'c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db', - '2119a460ce326cdc76c45926c982fdac0e106e861edf61c5a039063f0e0e6482' - ], - [ - '6a245bf6dc698504c89a20cfded60853152b695336c28063b61c65cbd269e6b4', - 'e022cf42c2bd4a708b3f5126f16a24ad8b33ba48d0423b6efd5e6348100d8a82' - ], - [ - '1697ffa6fd9de627c077e3d2fe541084ce13300b0bec1146f95ae57f0d0bd6a5', - 'b9c398f186806f5d27561506e4557433a2cf15009e498ae7adee9d63d01b2396' - ], - [ - '605bdb019981718b986d0f07e834cb0d9deb8360ffb7f61df982345ef27a7479', - '2972d2de4f8d20681a78d93ec96fe23c26bfae84fb14db43b01e1e9056b8c49' - ], - [ - '62d14dab4150bf497402fdc45a215e10dcb01c354959b10cfe31c7e9d87ff33d', - '80fc06bd8cc5b01098088a1950eed0db01aa132967ab472235f5642483b25eaf' - ], - [ - '80c60ad0040f27dade5b4b06c408e56b2c50e9f56b9b8b425e555c2f86308b6f', - '1c38303f1cc5c30f26e66bad7fe72f70a65eed4cbe7024eb1aa01f56430bd57a' - ], - [ - '7a9375ad6167ad54aa74c6348cc54d344cc5dc9487d847049d5eabb0fa03c8fb', - 'd0e3fa9eca8726909559e0d79269046bdc59ea10c70ce2b02d499ec224dc7f7' - ], - [ - 'd528ecd9b696b54c907a9ed045447a79bb408ec39b68df504bb51f459bc3ffc9', - 'eecf41253136e5f99966f21881fd656ebc4345405c520dbc063465b521409933' - ], - [ - '49370a4b5f43412ea25f514e8ecdad05266115e4a7ecb1387231808f8b45963', - '758f3f41afd6ed428b3081b0512fd62a54c3f3afbb5b6764b653052a12949c9a' - ], - [ - '77f230936ee88cbbd73df930d64702ef881d811e0e1498e2f1c13eb1fc345d74', - '958ef42a7886b6400a08266e9ba1b37896c95330d97077cbbe8eb3c7671c60d6' - ], - [ - 'f2dac991cc4ce4b9ea44887e5c7c0bce58c80074ab9d4dbaeb28531b7739f530', - 'e0dedc9b3b2f8dad4da1f32dec2531df9eb5fbeb0598e4fd1a117dba703a3c37' - ], - [ - '463b3d9f662621fb1b4be8fbbe2520125a216cdfc9dae3debcba4850c690d45b', - '5ed430d78c296c3543114306dd8622d7c622e27c970a1de31cb377b01af7307e' - ], - [ - 'f16f804244e46e2a09232d4aff3b59976b98fac14328a2d1a32496b49998f247', - 'cedabd9b82203f7e13d206fcdf4e33d92a6c53c26e5cce26d6579962c4e31df6' - ], - [ - 'caf754272dc84563b0352b7a14311af55d245315ace27c65369e15f7151d41d1', - 'cb474660ef35f5f2a41b643fa5e460575f4fa9b7962232a5c32f908318a04476' - ], - [ - '2600ca4b282cb986f85d0f1709979d8b44a09c07cb86d7c124497bc86f082120', - '4119b88753c15bd6a693b03fcddbb45d5ac6be74ab5f0ef44b0be9475a7e4b40' - ], - [ - '7635ca72d7e8432c338ec53cd12220bc01c48685e24f7dc8c602a7746998e435', - '91b649609489d613d1d5e590f78e6d74ecfc061d57048bad9e76f302c5b9c61' - ], - [ - '754e3239f325570cdbbf4a87deee8a66b7f2b33479d468fbc1a50743bf56cc18', - '673fb86e5bda30fb3cd0ed304ea49a023ee33d0197a695d0c5d98093c536683' - ], - [ - 'e3e6bd1071a1e96aff57859c82d570f0330800661d1c952f9fe2694691d9b9e8', - '59c9e0bba394e76f40c0aa58379a3cb6a5a2283993e90c4167002af4920e37f5' - ], - [ - '186b483d056a033826ae73d88f732985c4ccb1f32ba35f4b4cc47fdcf04aa6eb', - '3b952d32c67cf77e2e17446e204180ab21fb8090895138b4a4a797f86e80888b' - ], - [ - 'df9d70a6b9876ce544c98561f4be4f725442e6d2b737d9c91a8321724ce0963f', - '55eb2dafd84d6ccd5f862b785dc39d4ab157222720ef9da217b8c45cf2ba2417' - ], - [ - '5edd5cc23c51e87a497ca815d5dce0f8ab52554f849ed8995de64c5f34ce7143', - 'efae9c8dbc14130661e8cec030c89ad0c13c66c0d17a2905cdc706ab7399a868' - ], - [ - '290798c2b6476830da12fe02287e9e777aa3fba1c355b17a722d362f84614fba', - 'e38da76dcd440621988d00bcf79af25d5b29c094db2a23146d003afd41943e7a' - ], - [ - 'af3c423a95d9f5b3054754efa150ac39cd29552fe360257362dfdecef4053b45', - 'f98a3fd831eb2b749a93b0e6f35cfb40c8cd5aa667a15581bc2feded498fd9c6' - ], - [ - '766dbb24d134e745cccaa28c99bf274906bb66b26dcf98df8d2fed50d884249a', - '744b1152eacbe5e38dcc887980da38b897584a65fa06cedd2c924f97cbac5996' - ], - [ - '59dbf46f8c94759ba21277c33784f41645f7b44f6c596a58ce92e666191abe3e', - 'c534ad44175fbc300f4ea6ce648309a042ce739a7919798cd85e216c4a307f6e' - ], - [ - 'f13ada95103c4537305e691e74e9a4a8dd647e711a95e73cb62dc6018cfd87b8', - 'e13817b44ee14de663bf4bc808341f326949e21a6a75c2570778419bdaf5733d' - ], - [ - '7754b4fa0e8aced06d4167a2c59cca4cda1869c06ebadfb6488550015a88522c', - '30e93e864e669d82224b967c3020b8fa8d1e4e350b6cbcc537a48b57841163a2' - ], - [ - '948dcadf5990e048aa3874d46abef9d701858f95de8041d2a6828c99e2262519', - 'e491a42537f6e597d5d28a3224b1bc25df9154efbd2ef1d2cbba2cae5347d57e' - ], - [ - '7962414450c76c1689c7b48f8202ec37fb224cf5ac0bfa1570328a8a3d7c77ab', - '100b610ec4ffb4760d5c1fc133ef6f6b12507a051f04ac5760afa5b29db83437' - ], - [ - '3514087834964b54b15b160644d915485a16977225b8847bb0dd085137ec47ca', - 'ef0afbb2056205448e1652c48e8127fc6039e77c15c2378b7e7d15a0de293311' - ], - [ - 'd3cc30ad6b483e4bc79ce2c9dd8bc54993e947eb8df787b442943d3f7b527eaf', - '8b378a22d827278d89c5e9be8f9508ae3c2ad46290358630afb34db04eede0a4' - ], - [ - '1624d84780732860ce1c78fcbfefe08b2b29823db913f6493975ba0ff4847610', - '68651cf9b6da903e0914448c6cd9d4ca896878f5282be4c8cc06e2a404078575' - ], - [ - '733ce80da955a8a26902c95633e62a985192474b5af207da6df7b4fd5fc61cd4', - 'f5435a2bd2badf7d485a4d8b8db9fcce3e1ef8e0201e4578c54673bc1dc5ea1d' - ], - [ - '15d9441254945064cf1a1c33bbd3b49f8966c5092171e699ef258dfab81c045c', - 'd56eb30b69463e7234f5137b73b84177434800bacebfc685fc37bbe9efe4070d' - ], - [ - 'a1d0fcf2ec9de675b612136e5ce70d271c21417c9d2b8aaaac138599d0717940', - 'edd77f50bcb5a3cab2e90737309667f2641462a54070f3d519212d39c197a629' - ], - [ - 'e22fbe15c0af8ccc5780c0735f84dbe9a790badee8245c06c7ca37331cb36980', - 'a855babad5cd60c88b430a69f53a1a7a38289154964799be43d06d77d31da06' - ], - [ - '311091dd9860e8e20ee13473c1155f5f69635e394704eaa74009452246cfa9b3', - '66db656f87d1f04fffd1f04788c06830871ec5a64feee685bd80f0b1286d8374' - ], - [ - '34c1fd04d301be89b31c0442d3e6ac24883928b45a9340781867d4232ec2dbdf', - '9414685e97b1b5954bd46f730174136d57f1ceeb487443dc5321857ba73abee' - ], - [ - 'f219ea5d6b54701c1c14de5b557eb42a8d13f3abbcd08affcc2a5e6b049b8d63', - '4cb95957e83d40b0f73af4544cccf6b1f4b08d3c07b27fb8d8c2962a400766d1' - ], - [ - 'd7b8740f74a8fbaab1f683db8f45de26543a5490bca627087236912469a0b448', - 'fa77968128d9c92ee1010f337ad4717eff15db5ed3c049b3411e0315eaa4593b' - ], - [ - '32d31c222f8f6f0ef86f7c98d3a3335ead5bcd32abdd94289fe4d3091aa824bf', - '5f3032f5892156e39ccd3d7915b9e1da2e6dac9e6f26e961118d14b8462e1661' - ], - [ - '7461f371914ab32671045a155d9831ea8793d77cd59592c4340f86cbc18347b5', - '8ec0ba238b96bec0cbdddcae0aa442542eee1ff50c986ea6b39847b3cc092ff6' - ], - [ - 'ee079adb1df1860074356a25aa38206a6d716b2c3e67453d287698bad7b2b2d6', - '8dc2412aafe3be5c4c5f37e0ecc5f9f6a446989af04c4e25ebaac479ec1c8c1e' - ], - [ - '16ec93e447ec83f0467b18302ee620f7e65de331874c9dc72bfd8616ba9da6b5', - '5e4631150e62fb40d0e8c2a7ca5804a39d58186a50e497139626778e25b0674d' - ], - [ - 'eaa5f980c245f6f038978290afa70b6bd8855897f98b6aa485b96065d537bd99', - 'f65f5d3e292c2e0819a528391c994624d784869d7e6ea67fb18041024edc07dc' - ], - [ - '78c9407544ac132692ee1910a02439958ae04877151342ea96c4b6b35a49f51', - 'f3e0319169eb9b85d5404795539a5e68fa1fbd583c064d2462b675f194a3ddb4' - ], - [ - '494f4be219a1a77016dcd838431aea0001cdc8ae7a6fc688726578d9702857a5', - '42242a969283a5f339ba7f075e36ba2af925ce30d767ed6e55f4b031880d562c' - ], - [ - 'a598a8030da6d86c6bc7f2f5144ea549d28211ea58faa70ebf4c1e665c1fe9b5', - '204b5d6f84822c307e4b4a7140737aec23fc63b65b35f86a10026dbd2d864e6b' - ], - [ - 'c41916365abb2b5d09192f5f2dbeafec208f020f12570a184dbadc3e58595997', - '4f14351d0087efa49d245b328984989d5caf9450f34bfc0ed16e96b58fa9913' - ], - [ - '841d6063a586fa475a724604da03bc5b92a2e0d2e0a36acfe4c73a5514742881', - '73867f59c0659e81904f9a1c7543698e62562d6744c169ce7a36de01a8d6154' - ], - [ - '5e95bb399a6971d376026947f89bde2f282b33810928be4ded112ac4d70e20d5', - '39f23f366809085beebfc71181313775a99c9aed7d8ba38b161384c746012865' - ], - [ - '36e4641a53948fd476c39f8a99fd974e5ec07564b5315d8bf99471bca0ef2f66', - 'd2424b1b1abe4eb8164227b085c9aa9456ea13493fd563e06fd51cf5694c78fc' - ], - [ - '336581ea7bfbbb290c191a2f507a41cf5643842170e914faeab27c2c579f726', - 'ead12168595fe1be99252129b6e56b3391f7ab1410cd1e0ef3dcdcabd2fda224' - ], - [ - '8ab89816dadfd6b6a1f2634fcf00ec8403781025ed6890c4849742706bd43ede', - '6fdcef09f2f6d0a044e654aef624136f503d459c3e89845858a47a9129cdd24e' - ], - [ - '1e33f1a746c9c5778133344d9299fcaa20b0938e8acff2544bb40284b8c5fb94', - '60660257dd11b3aa9c8ed618d24edff2306d320f1d03010e33a7d2057f3b3b6' - ], - [ - '85b7c1dcb3cec1b7ee7f30ded79dd20a0ed1f4cc18cbcfcfa410361fd8f08f31', - '3d98a9cdd026dd43f39048f25a8847f4fcafad1895d7a633c6fed3c35e999511' - ], - [ - '29df9fbd8d9e46509275f4b125d6d45d7fbe9a3b878a7af872a2800661ac5f51', - 'b4c4fe99c775a606e2d8862179139ffda61dc861c019e55cd2876eb2a27d84b' - ], - [ - 'a0b1cae06b0a847a3fea6e671aaf8adfdfe58ca2f768105c8082b2e449fce252', - 'ae434102edde0958ec4b19d917a6a28e6b72da1834aff0e650f049503a296cf2' - ], - [ - '4e8ceafb9b3e9a136dc7ff67e840295b499dfb3b2133e4ba113f2e4c0e121e5', - 'cf2174118c8b6d7a4b48f6d534ce5c79422c086a63460502b827ce62a326683c' - ], - [ - 'd24a44e047e19b6f5afb81c7ca2f69080a5076689a010919f42725c2b789a33b', - '6fb8d5591b466f8fc63db50f1c0f1c69013f996887b8244d2cdec417afea8fa3' - ], - [ - 'ea01606a7a6c9cdd249fdfcfacb99584001edd28abbab77b5104e98e8e3b35d4', - '322af4908c7312b0cfbfe369f7a7b3cdb7d4494bc2823700cfd652188a3ea98d' - ], - [ - 'af8addbf2b661c8a6c6328655eb96651252007d8c5ea31be4ad196de8ce2131f', - '6749e67c029b85f52a034eafd096836b2520818680e26ac8f3dfbcdb71749700' - ], - [ - 'e3ae1974566ca06cc516d47e0fb165a674a3dabcfca15e722f0e3450f45889', - '2aeabe7e4531510116217f07bf4d07300de97e4874f81f533420a72eeb0bd6a4' - ], - [ - '591ee355313d99721cf6993ffed1e3e301993ff3ed258802075ea8ced397e246', - 'b0ea558a113c30bea60fc4775460c7901ff0b053d25ca2bdeee98f1a4be5d196' - ], - [ - '11396d55fda54c49f19aa97318d8da61fa8584e47b084945077cf03255b52984', - '998c74a8cd45ac01289d5833a7beb4744ff536b01b257be4c5767bea93ea57a4' - ], - [ - '3c5d2a1ba39c5a1790000738c9e0c40b8dcdfd5468754b6405540157e017aa7a', - 'b2284279995a34e2f9d4de7396fc18b80f9b8b9fdd270f6661f79ca4c81bd257' - ], - [ - 'cc8704b8a60a0defa3a99a7299f2e9c3fbc395afb04ac078425ef8a1793cc030', - 'bdd46039feed17881d1e0862db347f8cf395b74fc4bcdc4e940b74e3ac1f1b13' - ], - [ - 'c533e4f7ea8555aacd9777ac5cad29b97dd4defccc53ee7ea204119b2889b197', - '6f0a256bc5efdf429a2fb6242f1a43a2d9b925bb4a4b3a26bb8e0f45eb596096' - ], - [ - 'c14f8f2ccb27d6f109f6d08d03cc96a69ba8c34eec07bbcf566d48e33da6593', - 'c359d6923bb398f7fd4473e16fe1c28475b740dd098075e6c0e8649113dc3a38' - ], - [ - 'a6cbc3046bc6a450bac24789fa17115a4c9739ed75f8f21ce441f72e0b90e6ef', - '21ae7f4680e889bb130619e2c0f95a360ceb573c70603139862afd617fa9b9f' - ], - [ - '347d6d9a02c48927ebfb86c1359b1caf130a3c0267d11ce6344b39f99d43cc38', - '60ea7f61a353524d1c987f6ecec92f086d565ab687870cb12689ff1e31c74448' - ], - [ - 'da6545d2181db8d983f7dcb375ef5866d47c67b1bf31c8cf855ef7437b72656a', - '49b96715ab6878a79e78f07ce5680c5d6673051b4935bd897fea824b77dc208a' - ], - [ - 'c40747cc9d012cb1a13b8148309c6de7ec25d6945d657146b9d5994b8feb1111', - '5ca560753be2a12fc6de6caf2cb489565db936156b9514e1bb5e83037e0fa2d4' - ], - [ - '4e42c8ec82c99798ccf3a610be870e78338c7f713348bd34c8203ef4037f3502', - '7571d74ee5e0fb92a7a8b33a07783341a5492144cc54bcc40a94473693606437' - ], - [ - '3775ab7089bc6af823aba2e1af70b236d251cadb0c86743287522a1b3b0dedea', - 'be52d107bcfa09d8bcb9736a828cfa7fac8db17bf7a76a2c42ad961409018cf7' - ], - [ - 'cee31cbf7e34ec379d94fb814d3d775ad954595d1314ba8846959e3e82f74e26', - '8fd64a14c06b589c26b947ae2bcf6bfa0149ef0be14ed4d80f448a01c43b1c6d' - ], - [ - 'b4f9eaea09b6917619f6ea6a4eb5464efddb58fd45b1ebefcdc1a01d08b47986', - '39e5c9925b5a54b07433a4f18c61726f8bb131c012ca542eb24a8ac07200682a' - ], - [ - 'd4263dfc3d2df923a0179a48966d30ce84e2515afc3dccc1b77907792ebcc60e', - '62dfaf07a0f78feb30e30d6295853ce189e127760ad6cf7fae164e122a208d54' - ], - [ - '48457524820fa65a4f8d35eb6930857c0032acc0a4a2de422233eeda897612c4', - '25a748ab367979d98733c38a1fa1c2e7dc6cc07db2d60a9ae7a76aaa49bd0f77' - ], - [ - 'dfeeef1881101f2cb11644f3a2afdfc2045e19919152923f367a1767c11cceda', - 'ecfb7056cf1de042f9420bab396793c0c390bde74b4bbdff16a83ae09a9a7517' - ], - [ - '6d7ef6b17543f8373c573f44e1f389835d89bcbc6062ced36c82df83b8fae859', - 'cd450ec335438986dfefa10c57fea9bcc521a0959b2d80bbf74b190dca712d10' - ], - [ - 'e75605d59102a5a2684500d3b991f2e3f3c88b93225547035af25af66e04541f', - 'f5c54754a8f71ee540b9b48728473e314f729ac5308b06938360990e2bfad125' - ], - [ - 'eb98660f4c4dfaa06a2be453d5020bc99a0c2e60abe388457dd43fefb1ed620c', - '6cb9a8876d9cb8520609af3add26cd20a0a7cd8a9411131ce85f44100099223e' - ], - [ - '13e87b027d8514d35939f2e6892b19922154596941888336dc3563e3b8dba942', - 'fef5a3c68059a6dec5d624114bf1e91aac2b9da568d6abeb2570d55646b8adf1' - ], - [ - 'ee163026e9fd6fe017c38f06a5be6fc125424b371ce2708e7bf4491691e5764a', - '1acb250f255dd61c43d94ccc670d0f58f49ae3fa15b96623e5430da0ad6c62b2' - ], - [ - 'b268f5ef9ad51e4d78de3a750c2dc89b1e626d43505867999932e5db33af3d80', - '5f310d4b3c99b9ebb19f77d41c1dee018cf0d34fd4191614003e945a1216e423' - ], - [ - 'ff07f3118a9df035e9fad85eb6c7bfe42b02f01ca99ceea3bf7ffdba93c4750d', - '438136d603e858a3a5c440c38eccbaddc1d2942114e2eddd4740d098ced1f0d8' - ], - [ - '8d8b9855c7c052a34146fd20ffb658bea4b9f69e0d825ebec16e8c3ce2b526a1', - 'cdb559eedc2d79f926baf44fb84ea4d44bcf50fee51d7ceb30e2e7f463036758' - ], - [ - '52db0b5384dfbf05bfa9d472d7ae26dfe4b851ceca91b1eba54263180da32b63', - 'c3b997d050ee5d423ebaf66a6db9f57b3180c902875679de924b69d84a7b375' - ], - [ - 'e62f9490d3d51da6395efd24e80919cc7d0f29c3f3fa48c6fff543becbd43352', - '6d89ad7ba4876b0b22c2ca280c682862f342c8591f1daf5170e07bfd9ccafa7d' - ], - [ - '7f30ea2476b399b4957509c88f77d0191afa2ff5cb7b14fd6d8e7d65aaab1193', - 'ca5ef7d4b231c94c3b15389a5f6311e9daff7bb67b103e9880ef4bff637acaec' - ], - [ - '5098ff1e1d9f14fb46a210fada6c903fef0fb7b4a1dd1d9ac60a0361800b7a00', - '9731141d81fc8f8084d37c6e7542006b3ee1b40d60dfe5362a5b132fd17ddc0' - ], - [ - '32b78c7de9ee512a72895be6b9cbefa6e2f3c4ccce445c96b9f2c81e2778ad58', - 'ee1849f513df71e32efc3896ee28260c73bb80547ae2275ba497237794c8753c' - ], - [ - 'e2cb74fddc8e9fbcd076eef2a7c72b0ce37d50f08269dfc074b581550547a4f7', - 'd3aa2ed71c9dd2247a62df062736eb0baddea9e36122d2be8641abcb005cc4a4' - ], - [ - '8438447566d4d7bedadc299496ab357426009a35f235cb141be0d99cd10ae3a8', - 'c4e1020916980a4da5d01ac5e6ad330734ef0d7906631c4f2390426b2edd791f' - ], - [ - '4162d488b89402039b584c6fc6c308870587d9c46f660b878ab65c82c711d67e', - '67163e903236289f776f22c25fb8a3afc1732f2b84b4e95dbda47ae5a0852649' - ], - [ - '3fad3fa84caf0f34f0f89bfd2dcf54fc175d767aec3e50684f3ba4a4bf5f683d', - 'cd1bc7cb6cc407bb2f0ca647c718a730cf71872e7d0d2a53fa20efcdfe61826' - ], - [ - '674f2600a3007a00568c1a7ce05d0816c1fb84bf1370798f1c69532faeb1a86b', - '299d21f9413f33b3edf43b257004580b70db57da0b182259e09eecc69e0d38a5' - ], - [ - 'd32f4da54ade74abb81b815ad1fb3b263d82d6c692714bcff87d29bd5ee9f08f', - 'f9429e738b8e53b968e99016c059707782e14f4535359d582fc416910b3eea87' - ], - [ - '30e4e670435385556e593657135845d36fbb6931f72b08cb1ed954f1e3ce3ff6', - '462f9bce619898638499350113bbc9b10a878d35da70740dc695a559eb88db7b' - ], - [ - 'be2062003c51cc3004682904330e4dee7f3dcd10b01e580bf1971b04d4cad297', - '62188bc49d61e5428573d48a74e1c655b1c61090905682a0d5558ed72dccb9bc' - ], - [ - '93144423ace3451ed29e0fb9ac2af211cb6e84a601df5993c419859fff5df04a', - '7c10dfb164c3425f5c71a3f9d7992038f1065224f72bb9d1d902a6d13037b47c' - ], - [ - 'b015f8044f5fcbdcf21ca26d6c34fb8197829205c7b7d2a7cb66418c157b112c', - 'ab8c1e086d04e813744a655b2df8d5f83b3cdc6faa3088c1d3aea1454e3a1d5f' - ], - [ - 'd5e9e1da649d97d89e4868117a465a3a4f8a18de57a140d36b3f2af341a21b52', - '4cb04437f391ed73111a13cc1d4dd0db1693465c2240480d8955e8592f27447a' - ], - [ - 'd3ae41047dd7ca065dbf8ed77b992439983005cd72e16d6f996a5316d36966bb', - 'bd1aeb21ad22ebb22a10f0303417c6d964f8cdd7df0aca614b10dc14d125ac46' - ], - [ - '463e2763d885f958fc66cdd22800f0a487197d0a82e377b49f80af87c897b065', - 'bfefacdb0e5d0fd7df3a311a94de062b26b80c61fbc97508b79992671ef7ca7f' - ], - [ - '7985fdfd127c0567c6f53ec1bb63ec3158e597c40bfe747c83cddfc910641917', - '603c12daf3d9862ef2b25fe1de289aed24ed291e0ec6708703a5bd567f32ed03' - ], - [ - '74a1ad6b5f76e39db2dd249410eac7f99e74c59cb83d2d0ed5ff1543da7703e9', - 'cc6157ef18c9c63cd6193d83631bbea0093e0968942e8c33d5737fd790e0db08' - ], - [ - '30682a50703375f602d416664ba19b7fc9bab42c72747463a71d0896b22f6da3', - '553e04f6b018b4fa6c8f39e7f311d3176290d0e0f19ca73f17714d9977a22ff8' - ], - [ - '9e2158f0d7c0d5f26c3791efefa79597654e7a2b2464f52b1ee6c1347769ef57', - '712fcdd1b9053f09003a3481fa7762e9ffd7c8ef35a38509e2fbf2629008373' - ], - [ - '176e26989a43c9cfeba4029c202538c28172e566e3c4fce7322857f3be327d66', - 'ed8cc9d04b29eb877d270b4878dc43c19aefd31f4eee09ee7b47834c1fa4b1c3' - ], - [ - '75d46efea3771e6e68abb89a13ad747ecf1892393dfc4f1b7004788c50374da8', - '9852390a99507679fd0b86fd2b39a868d7efc22151346e1a3ca4726586a6bed8' - ], - [ - '809a20c67d64900ffb698c4c825f6d5f2310fb0451c869345b7319f645605721', - '9e994980d9917e22b76b061927fa04143d096ccc54963e6a5ebfa5f3f8e286c1' - ], - [ - '1b38903a43f7f114ed4500b4eac7083fdefece1cf29c63528d563446f972c180', - '4036edc931a60ae889353f77fd53de4a2708b26b6f5da72ad3394119daf408f9' - ] - ] - } -}; - -},{}],107:[function(require,module,exports){ -'use strict'; - -var utils = exports; -var BN = require('bn.js'); -var minAssert = require('minimalistic-assert'); -var minUtils = require('minimalistic-crypto-utils'); - -utils.assert = minAssert; -utils.toArray = minUtils.toArray; -utils.zero2 = minUtils.zero2; -utils.toHex = minUtils.toHex; -utils.encode = minUtils.encode; - -// Represent num in a w-NAF form -function getNAF(num, w) { - var naf = []; - var ws = 1 << (w + 1); - var k = num.clone(); - while (k.cmpn(1) >= 0) { - var z; - if (k.isOdd()) { - var mod = k.andln(ws - 1); - if (mod > (ws >> 1) - 1) - z = (ws >> 1) - mod; - else - z = mod; - k.isubn(z); - } else { - z = 0; - } - naf.push(z); + if (!encoding) encoding = 'utf8'; - // Optimization, shift by word if possible - var shift = (k.cmpn(0) !== 0 && k.andln(ws - 1) === 0) ? (w + 1) : 1; - for (var i = 1; i < shift; i++) - naf.push(0); - k.iushrn(shift); - } + while (true) { + switch (encoding) { + case 'hex': + return hexSlice(this, start, end); - return naf; -} -utils.getNAF = getNAF; + case 'utf8': + case 'utf-8': + return utf8Slice(this, start, end); -// Represent k1, k2 in a Joint Sparse Form -function getJSF(k1, k2) { - var jsf = [ - [], - [] - ]; + case 'ascii': + return asciiSlice(this, start, end); - k1 = k1.clone(); - k2 = k2.clone(); - var d1 = 0; - var d2 = 0; - while (k1.cmpn(-d1) > 0 || k2.cmpn(-d2) > 0) { - - // First phase - var m14 = (k1.andln(3) + d1) & 3; - var m24 = (k2.andln(3) + d2) & 3; - if (m14 === 3) - m14 = -1; - if (m24 === 3) - m24 = -1; - var u1; - if ((m14 & 1) === 0) { - u1 = 0; - } else { - var m8 = (k1.andln(7) + d1) & 7; - if ((m8 === 3 || m8 === 5) && m24 === 2) - u1 = -m14; - else - u1 = m14; - } - jsf[0].push(u1); - - var u2; - if ((m24 & 1) === 0) { - u2 = 0; - } else { - var m8 = (k2.andln(7) + d2) & 7; - if ((m8 === 3 || m8 === 5) && m14 === 2) - u2 = -m24; - else - u2 = m24; - } - jsf[1].push(u2); - - // Second phase - if (2 * d1 === u1 + 1) - d1 = 1 - d1; - if (2 * d2 === u2 + 1) - d2 = 1 - d2; - k1.iushrn(1); - k2.iushrn(1); - } + case 'latin1': + case 'binary': + return latin1Slice(this, start, end); - return jsf; -} -utils.getJSF = getJSF; - -function cachedProperty(obj, name, computer) { - var key = '_' + name; - obj.prototype[name] = function cachedProperty() { - return this[key] !== undefined ? this[key] : - this[key] = computer.call(this); - }; -} -utils.cachedProperty = cachedProperty; + case 'base64': + return base64Slice(this, start, end); -function parseBytes(bytes) { - return typeof bytes === 'string' ? utils.toArray(bytes, 'hex') : - bytes; -} -utils.parseBytes = parseBytes; + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return utf16leSlice(this, start, end); -function intFromLE(bytes) { - return new BN(bytes, 'hex', 'le'); -} -utils.intFromLE = intFromLE; - - -},{"bn.js":92,"minimalistic-assert":192,"minimalistic-crypto-utils":193}],108:[function(require,module,exports){ -module.exports={ - "_args": [ - [ - "elliptic@6.4.0", - "/Users/tonypizzicato/dev/meritlabs/lightwallet-stack/packages/bitcore-lib" - ] - ], - "_from": "elliptic@6.4.0", - "_id": "elliptic@6.4.0", - "_inBundle": false, - "_integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", - "_location": "/browserify-sign/elliptic", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "elliptic@6.4.0", - "name": "elliptic", - "escapedName": "elliptic", - "rawSpec": "6.4.0", - "saveSpec": null, - "fetchSpec": "6.4.0" - }, - "_requiredBy": [ - "/browserify-sign" - ], - "_resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "_spec": "6.4.0", - "_where": "/Users/tonypizzicato/dev/meritlabs/lightwallet-stack/packages/bitcore-lib", - "author": { - "name": "Fedor Indutny", - "email": "fedor@indutny.com" - }, - "bugs": { - "url": "https://github.com/indutny/elliptic/issues" - }, - "dependencies": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - }, - "description": "EC cryptography", - "devDependencies": { - "brfs": "^1.4.3", - "grunt": "^0.4.5", - "grunt-browserify": "^5.0.0", - "grunt-cli": "^1.2.0", - "grunt-contrib-connect": "^1.0.0", - "grunt-contrib-copy": "^1.0.0", - "grunt-contrib-uglify": "^1.0.1", - "grunt-saucelabs": "^8.6.2", - "jscs": "^2.9.0", - "jshint": "^2.6.0", - "mocha": "^2.1.0" - }, - "files": [ - "lib" - ], - "homepage": "https://github.com/indutny/elliptic", - "keywords": [ - "EC", - "Elliptic", - "curve", - "Cryptography" - ], - "license": "MIT", - "main": "lib/elliptic.js", - "name": "elliptic", - "repository": { - "type": "git", - "url": "git+ssh://git@github.com/indutny/elliptic.git" - }, - "scripts": { - "jscs": "jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js", - "jshint": "jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js", - "lint": "npm run jscs && npm run jshint", - "test": "npm run lint && npm run unit", - "version": "grunt dist && git add dist/" - }, - "version": "6.4.0" -} + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding); + encoding = (encoding + '').toLowerCase(); + loweredCase = true; + } + } + } -},{}],109:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var Buffer = require('buffer').Buffer; - -var isBufferEncoding = Buffer.isEncoding - || function(encoding) { - switch (encoding && encoding.toLowerCase()) { - case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true; - default: return false; - } - } - - -function assertEncoding(encoding) { - if (encoding && !isBufferEncoding(encoding)) { - throw new Error('Unknown encoding: ' + encoding); - } -} + // The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect + // Buffer instances. + Buffer.prototype._isBuffer = true; -// StringDecoder provides an interface for efficiently splitting a series of -// buffers into a series of JS strings without breaking apart multi-byte -// characters. CESU-8 is handled as part of the UTF-8 encoding. -// -// @TODO Handling all encodings inside a single object makes it very difficult -// to reason about this code, so it should be split up in the future. -// @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code -// points as used by CESU-8. -var StringDecoder = exports.StringDecoder = function(encoding) { - this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); - assertEncoding(encoding); - switch (this.encoding) { - case 'utf8': - // CESU-8 represents each of Surrogate Pair by 3-bytes - this.surrogateSize = 3; - break; - case 'ucs2': - case 'utf16le': - // UTF-16 represents each of Surrogate Pair by 2-bytes - this.surrogateSize = 2; - this.detectIncompleteChar = utf16DetectIncompleteChar; - break; - case 'base64': - // Base-64 stores 3 bytes in 4 chars, and pads the remainder. - this.surrogateSize = 3; - this.detectIncompleteChar = base64DetectIncompleteChar; - break; - default: - this.write = passThroughWrite; - return; - } + function swap(b, n, m) { + var i = b[n]; + b[n] = b[m]; + b[m] = i; + } - // Enough space to store all bytes of a single character. UTF-8 needs 4 - // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate). - this.charBuffer = new Buffer(6); - // Number of bytes received for the current incomplete multi-byte character. - this.charReceived = 0; - // Number of bytes expected for the current incomplete multi-byte character. - this.charLength = 0; -}; - - -// write decodes the given buffer and returns it as JS string that is -// guaranteed to not contain any partial multi-byte characters. Any partial -// character found at the end of the buffer is buffered up, and will be -// returned when calling write again with the remaining bytes. -// -// Note: Converting a Buffer containing an orphan surrogate to a String -// currently works, but converting a String to a Buffer (via `new Buffer`, or -// Buffer#write) will replace incomplete surrogates with the unicode -// replacement character. See https://codereview.chromium.org/121173009/ . -StringDecoder.prototype.write = function(buffer) { - var charStr = ''; - // if our last write ended with an incomplete multibyte character - while (this.charLength) { - // determine how many remaining bytes this buffer has to offer for this char - var available = (buffer.length >= this.charLength - this.charReceived) ? - this.charLength - this.charReceived : - buffer.length; - - // add the new bytes to the char buffer - buffer.copy(this.charBuffer, this.charReceived, 0, available); - this.charReceived += available; - - if (this.charReceived < this.charLength) { - // still not enough chars in this buffer? wait for more ... - return ''; - } + Buffer.prototype.swap16 = function swap16() { + var len = this.length; + if (len % 2 !== 0) { + throw new RangeError('Buffer size must be a multiple of 16-bits'); + } + for (var i = 0; i < len; i += 2) { + swap(this, i, i + 1); + } + return this; + }; - // remove bytes belonging to the current character from the buffer - buffer = buffer.slice(available, buffer.length); + Buffer.prototype.swap32 = function swap32() { + var len = this.length; + if (len % 4 !== 0) { + throw new RangeError('Buffer size must be a multiple of 32-bits'); + } + for (var i = 0; i < len; i += 4) { + swap(this, i, i + 3); + swap(this, i + 1, i + 2); + } + return this; + }; - // get the character that was split - charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); + Buffer.prototype.swap64 = function swap64() { + var len = this.length; + if (len % 8 !== 0) { + throw new RangeError('Buffer size must be a multiple of 64-bits'); + } + for (var i = 0; i < len; i += 8) { + swap(this, i, i + 7); + swap(this, i + 1, i + 6); + swap(this, i + 2, i + 5); + swap(this, i + 3, i + 4); + } + return this; + }; + + Buffer.prototype.toString = function toString() { + var length = this.length | 0; + if (length === 0) return ''; + if (arguments.length === 0) return utf8Slice(this, 0, length); + return slowToString.apply(this, arguments); + }; + + Buffer.prototype.equals = function equals(b) { + if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer'); + if (this === b) return true; + return Buffer.compare(this, b) === 0; + }; + + Buffer.prototype.inspect = function inspect() { + var str = ''; + var max = exports.INSPECT_MAX_BYTES; + if (this.length > 0) { + str = this.toString('hex', 0, max) + .match(/.{2}/g) + .join(' '); + if (this.length > max) str += ' ... '; + } + return ''; + }; - // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character - var charCode = charStr.charCodeAt(charStr.length - 1); - if (charCode >= 0xD800 && charCode <= 0xDBFF) { - this.charLength += this.surrogateSize; - charStr = ''; - continue; - } - this.charReceived = this.charLength = 0; + Buffer.prototype.compare = function compare(target, start, end, thisStart, thisEnd) { + if (!Buffer.isBuffer(target)) { + throw new TypeError('Argument must be a Buffer'); + } - // if there are no more bytes in this buffer, just emit our char - if (buffer.length === 0) { - return charStr; - } - break; - } + if (start === undefined) { + start = 0; + } + if (end === undefined) { + end = target ? target.length : 0; + } + if (thisStart === undefined) { + thisStart = 0; + } + if (thisEnd === undefined) { + thisEnd = this.length; + } - // determine and set charLength / charReceived - this.detectIncompleteChar(buffer); + if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { + throw new RangeError('out of range index'); + } - var end = buffer.length; - if (this.charLength) { - // buffer the incomplete character bytes we got - buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end); - end -= this.charReceived; - } + if (thisStart >= thisEnd && start >= end) { + return 0; + } + if (thisStart >= thisEnd) { + return -1; + } + if (start >= end) { + return 1; + } - charStr += buffer.toString(this.encoding, 0, end); - - var end = charStr.length - 1; - var charCode = charStr.charCodeAt(end); - // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character - if (charCode >= 0xD800 && charCode <= 0xDBFF) { - var size = this.surrogateSize; - this.charLength += size; - this.charReceived += size; - this.charBuffer.copy(this.charBuffer, size, 0, size); - buffer.copy(this.charBuffer, 0, 0, size); - return charStr.substring(0, end); - } + start >>>= 0; + end >>>= 0; + thisStart >>>= 0; + thisEnd >>>= 0; - // or just emit the charStr - return charStr; -}; - -// detectIncompleteChar determines if there is an incomplete UTF-8 character at -// the end of the given buffer. If so, it sets this.charLength to the byte -// length that character, and sets this.charReceived to the number of bytes -// that are available for this character. -StringDecoder.prototype.detectIncompleteChar = function(buffer) { - // determine how many bytes we have to check at the end of this buffer - var i = (buffer.length >= 3) ? 3 : buffer.length; - - // Figure out if one of the last i bytes of our buffer announces an - // incomplete char. - for (; i > 0; i--) { - var c = buffer[buffer.length - i]; - - // See http://en.wikipedia.org/wiki/UTF-8#Description - - // 110XXXXX - if (i == 1 && c >> 5 == 0x06) { - this.charLength = 2; - break; - } + if (this === target) return 0; - // 1110XXXX - if (i <= 2 && c >> 4 == 0x0E) { - this.charLength = 3; - break; - } + var x = thisEnd - thisStart; + var y = end - start; + var len = Math.min(x, y); - // 11110XXX - if (i <= 3 && c >> 3 == 0x1E) { - this.charLength = 4; - break; - } - } - this.charReceived = i; -}; - -StringDecoder.prototype.end = function(buffer) { - var res = ''; - if (buffer && buffer.length) - res = this.write(buffer); - - if (this.charReceived) { - var cr = this.charReceived; - var buf = this.charBuffer; - var enc = this.encoding; - res += buf.slice(0, cr).toString(enc); - } + var thisCopy = this.slice(thisStart, thisEnd); + var targetCopy = target.slice(start, end); - return res; -}; + for (var i = 0; i < len; ++i) { + if (thisCopy[i] !== targetCopy[i]) { + x = thisCopy[i]; + y = targetCopy[i]; + break; + } + } -function passThroughWrite(buffer) { - return buffer.toString(this.encoding); -} + if (x < y) return -1; + if (y < x) return 1; + return 0; + }; -function utf16DetectIncompleteChar(buffer) { - this.charReceived = buffer.length % 2; - this.charLength = this.charReceived ? 2 : 0; -} + // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, + // OR the last index of `val` in `buffer` at offset <= `byteOffset`. + // + // Arguments: + // - buffer - a Buffer to search + // - val - a string, Buffer, or number + // - byteOffset - an index into `buffer`; will be clamped to an int32 + // - encoding - an optional encoding, relevant is val is a string + // - dir - true for indexOf, false for lastIndexOf + function bidirectionalIndexOf(buffer, val, byteOffset, encoding, dir) { + // Empty buffer means no match + if (buffer.length === 0) return -1; + + // Normalize byteOffset + if (typeof byteOffset === 'string') { + encoding = byteOffset; + byteOffset = 0; + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff; + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000; + } + byteOffset = +byteOffset; // Coerce to Number. + if (isNaN(byteOffset)) { + // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer + byteOffset = dir ? 0 : buffer.length - 1; + } -function base64DetectIncompleteChar(buffer) { - this.charReceived = buffer.length % 3; - this.charLength = this.charReceived ? 3 : 0; -} + // Normalize byteOffset: negative offsets start from the end of the buffer + if (byteOffset < 0) byteOffset = buffer.length + byteOffset; + if (byteOffset >= buffer.length) { + if (dir) return -1; + else byteOffset = buffer.length - 1; + } else if (byteOffset < 0) { + if (dir) byteOffset = 0; + else return -1; + } -},{"buffer":113}],110:[function(require,module,exports){ -// Base58 encoding/decoding -// Originally written by Mike Hearn for BitcoinJ -// Copyright (c) 2011 Google Inc -// Ported to JavaScript by Stefan Thomas -// Merged Buffer refactorings from base58-native by Stephen Pair -// Copyright (c) 2013 BitPay Inc - -var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' -var ALPHABET_MAP = {} -for(var i = 0; i < ALPHABET.length; i++) { - ALPHABET_MAP[ALPHABET.charAt(i)] = i -} -var BASE = 58 + // Normalize val + if (typeof val === 'string') { + val = Buffer.from(val, encoding); + } -function encode(buffer) { - if (buffer.length === 0) return '' + // Finally, search either indexOf (if dir is true) or lastIndexOf + if (Buffer.isBuffer(val)) { + // Special case: looking for empty string/buffer always fails + if (val.length === 0) { + return -1; + } + return arrayIndexOf(buffer, val, byteOffset, encoding, dir); + } else if (typeof val === 'number') { + val = val & 0xff; // Search for a byte value [0-255] + if (Buffer.TYPED_ARRAY_SUPPORT && typeof Uint8Array.prototype.indexOf === 'function') { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset); + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset); + } + } + return arrayIndexOf(buffer, [val], byteOffset, encoding, dir); + } - var i, j, digits = [0] - for (i = 0; i < buffer.length; i++) { - for (j = 0; j < digits.length; j++) digits[j] <<= 8 + throw new TypeError('val must be string, number or Buffer'); + } - digits[0] += buffer[i] + function arrayIndexOf(arr, val, byteOffset, encoding, dir) { + var indexSize = 1; + var arrLength = arr.length; + var valLength = val.length; + + if (encoding !== undefined) { + encoding = String(encoding).toLowerCase(); + if (encoding === 'ucs2' || encoding === 'ucs-2' || encoding === 'utf16le' || encoding === 'utf-16le') { + if (arr.length < 2 || val.length < 2) { + return -1; + } + indexSize = 2; + arrLength /= 2; + valLength /= 2; + byteOffset /= 2; + } + } - var carry = 0 - for (j = 0; j < digits.length; ++j) { - digits[j] += carry + function read(buf, i) { + if (indexSize === 1) { + return buf[i]; + } else { + return buf.readUInt16BE(i * indexSize); + } + } - carry = (digits[j] / BASE) | 0 - digits[j] %= BASE - } + var i; + if (dir) { + var foundIndex = -1; + for (i = byteOffset; i < arrLength; i++) { + if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i; + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize; + } else { + if (foundIndex !== -1) i -= i - foundIndex; + foundIndex = -1; + } + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength; + for (i = byteOffset; i >= 0; i--) { + var found = true; + for (var j = 0; j < valLength; j++) { + if (read(arr, i + j) !== read(val, j)) { + found = false; + break; + } + } + if (found) return i; + } + } - while (carry) { - digits.push(carry % BASE) + return -1; + } - carry = (carry / BASE) | 0 - } - } + Buffer.prototype.includes = function includes(val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1; + }; - // deal with leading zeros - for (i = 0; buffer[i] === 0 && i < buffer.length - 1; i++) digits.push(0) + Buffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true); + }; - return digits.reverse().map(function(digit) { return ALPHABET[digit] }).join('') -} + Buffer.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false); + }; -function decode(string) { - if (string.length === 0) return [] + function hexWrite(buf, string, offset, length) { + offset = Number(offset) || 0; + var remaining = buf.length - offset; + if (!length) { + length = remaining; + } else { + length = Number(length); + if (length > remaining) { + length = remaining; + } + } - var i, j, bytes = [0] - for (i = 0; i < string.length; i++) { - var c = string[i] - if (!(c in ALPHABET_MAP)) throw new Error('Non-base58 character') + // must be an even number of digits + var strLen = string.length; + if (strLen % 2 !== 0) throw new TypeError('Invalid hex string'); - for (j = 0; j < bytes.length; j++) bytes[j] *= BASE - bytes[0] += ALPHABET_MAP[c] + if (length > strLen / 2) { + length = strLen / 2; + } + for (var i = 0; i < length; ++i) { + var parsed = parseInt(string.substr(i * 2, 2), 16); + if (isNaN(parsed)) return i; + buf[offset + i] = parsed; + } + return i; + } - var carry = 0 - for (j = 0; j < bytes.length; ++j) { - bytes[j] += carry + function utf8Write(buf, string, offset, length) { + return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length); + } - carry = bytes[j] >> 8 - bytes[j] &= 0xff - } + function asciiWrite(buf, string, offset, length) { + return blitBuffer(asciiToBytes(string), buf, offset, length); + } - while (carry) { - bytes.push(carry & 0xff) + function latin1Write(buf, string, offset, length) { + return asciiWrite(buf, string, offset, length); + } - carry >>= 8 - } - } + function base64Write(buf, string, offset, length) { + return blitBuffer(base64ToBytes(string), buf, offset, length); + } - // deal with leading zeros - for (i = 0; string[i] === '1' && i < string.length - 1; i++) bytes.push(0) + function ucs2Write(buf, string, offset, length) { + return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length); + } - return bytes.reverse() -} + Buffer.prototype.write = function write(string, offset, length, encoding) { + // Buffer#write(string) + if (offset === undefined) { + encoding = 'utf8'; + length = this.length; + offset = 0; + // Buffer#write(string, encoding) + } else if (length === undefined && typeof offset === 'string') { + encoding = offset; + length = this.length; + offset = 0; + // Buffer#write(string, offset[, length][, encoding]) + } else if (isFinite(offset)) { + offset = offset | 0; + if (isFinite(length)) { + length = length | 0; + if (encoding === undefined) encoding = 'utf8'; + } else { + encoding = length; + length = undefined; + } + // legacy write(string, encoding, offset, length) - remove in v0.13 + } else { + throw new Error('Buffer.write(string, encoding, offset[, length]) is no longer supported'); + } -module.exports = { - encode: encode, - decode: decode -} + var remaining = this.length - offset; + if (length === undefined || length > remaining) length = remaining; -},{}],111:[function(require,module,exports){ + if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { + throw new RangeError('Attempt to write outside buffer bounds'); + } + if (!encoding) encoding = 'utf8'; -module.exports = function(cmp,to){ - var c = 0; - for(var i=0;i to[i]?1:0; - if(c != 0) break; - } - if(c == 0){ - if(to.length > cmp.length) c = -1; - else if(cmp.length > to.length) c = 1; - } - return c; -} + var loweredCase = false; + for (;;) { + switch (encoding) { + case 'hex': + return hexWrite(this, string, offset, length); + case 'utf8': + case 'utf-8': + return utf8Write(this, string, offset, length); -},{}],112:[function(require,module,exports){ -(function (Buffer){ -module.exports = function xor (a, b) { - var length = Math.min(a.length, b.length) - var buffer = new Buffer(length) + case 'ascii': + return asciiWrite(this, string, offset, length); - for (var i = 0; i < length; ++i) { - buffer[i] = a[i] ^ b[i] - } + case 'latin1': + case 'binary': + return latin1Write(this, string, offset, length); - return buffer -} + case 'base64': + // Warning: maxLength not taken into account in base64Write + return base64Write(this, string, offset, length); -}).call(this,require("buffer").Buffer) -},{"buffer":113}],113:[function(require,module,exports){ -(function (global){ -/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ -/* eslint-disable no-proto */ + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return ucs2Write(this, string, offset, length); -'use strict' + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding); + encoding = ('' + encoding).toLowerCase(); + loweredCase = true; + } + } + }; -var base64 = require('base64-js') -var ieee754 = require('ieee754') -var isArray = require('isarray') + Buffer.prototype.toJSON = function toJSON() { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0), + }; + }; -exports.Buffer = Buffer -exports.SlowBuffer = SlowBuffer -exports.INSPECT_MAX_BYTES = 50 + function base64Slice(buf, start, end) { + if (start === 0 && end === buf.length) { + return base64.fromByteArray(buf); + } else { + return base64.fromByteArray(buf.slice(start, end)); + } + } -/** - * If `Buffer.TYPED_ARRAY_SUPPORT`: - * === true Use Uint8Array implementation (fastest) - * === false Use Object implementation (most compatible, even IE6) - * - * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, - * Opera 11.6+, iOS 4.2+. - * - * Due to various browser bugs, sometimes the Object implementation will be used even - * when the browser supports typed arrays. - * - * Note: - * - * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, - * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. - * - * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. - * - * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of - * incorrect length in some situations. + function utf8Slice(buf, start, end) { + end = Math.min(buf.length, end); + var res = []; + + var i = start; + while (i < end) { + var firstByte = buf[i]; + var codePoint = null; + var bytesPerSequence = firstByte > 0xef ? 4 : firstByte > 0xdf ? 3 : firstByte > 0xbf ? 2 : 1; + + if (i + bytesPerSequence <= end) { + var secondByte, thirdByte, fourthByte, tempCodePoint; + + switch (bytesPerSequence) { + case 1: + if (firstByte < 0x80) { + codePoint = firstByte; + } + break; + case 2: + secondByte = buf[i + 1]; + if ((secondByte & 0xc0) === 0x80) { + tempCodePoint = ((firstByte & 0x1f) << 0x6) | (secondByte & 0x3f); + if (tempCodePoint > 0x7f) { + codePoint = tempCodePoint; + } + } + break; + case 3: + secondByte = buf[i + 1]; + thirdByte = buf[i + 2]; + if ((secondByte & 0xc0) === 0x80 && (thirdByte & 0xc0) === 0x80) { + tempCodePoint = ((firstByte & 0xf) << 0xc) | ((secondByte & 0x3f) << 0x6) | (thirdByte & 0x3f); + if (tempCodePoint > 0x7ff && (tempCodePoint < 0xd800 || tempCodePoint > 0xdfff)) { + codePoint = tempCodePoint; + } + } + break; + case 4: + secondByte = buf[i + 1]; + thirdByte = buf[i + 2]; + fourthByte = buf[i + 3]; + if ((secondByte & 0xc0) === 0x80 && (thirdByte & 0xc0) === 0x80 && (fourthByte & 0xc0) === 0x80) { + tempCodePoint = + ((firstByte & 0xf) << 0x12) | + ((secondByte & 0x3f) << 0xc) | + ((thirdByte & 0x3f) << 0x6) | + (fourthByte & 0x3f); + if (tempCodePoint > 0xffff && tempCodePoint < 0x110000) { + codePoint = tempCodePoint; + } + } + } + } - * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they - * get the Object implementation, which is slower but behaves correctly. - */ -Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined - ? global.TYPED_ARRAY_SUPPORT - : typedArraySupport() + if (codePoint === null) { + // we did not generate a valid codePoint so insert a + // replacement char (U+FFFD) and advance only 1 byte + codePoint = 0xfffd; + bytesPerSequence = 1; + } else if (codePoint > 0xffff) { + // encode to utf16 (surrogate pair dance) + codePoint -= 0x10000; + res.push(((codePoint >>> 10) & 0x3ff) | 0xd800); + codePoint = 0xdc00 | (codePoint & 0x3ff); + } -/* - * Export kMaxLength after typed array support is determined. - */ -exports.kMaxLength = kMaxLength() - -function typedArraySupport () { - try { - var arr = new Uint8Array(1) - arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }} - return arr.foo() === 42 && // typed array instances can be augmented - typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` - arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` - } catch (e) { - return false - } -} + res.push(codePoint); + i += bytesPerSequence; + } -function kMaxLength () { - return Buffer.TYPED_ARRAY_SUPPORT - ? 0x7fffffff - : 0x3fffffff -} + return decodeCodePointsArray(res); + } -function createBuffer (that, length) { - if (kMaxLength() < length) { - throw new RangeError('Invalid typed array length') - } - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = new Uint8Array(length) - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - if (that === null) { - that = new Buffer(length) - } - that.length = length - } + // Based on http://stackoverflow.com/a/22747272/680742, the browser with + // the lowest limit is Chrome, with 0x10000 args. + // We go 1 magnitude less, for safety + var MAX_ARGUMENTS_LENGTH = 0x1000; - return that -} + function decodeCodePointsArray(codePoints) { + var len = codePoints.length; + if (len <= MAX_ARGUMENTS_LENGTH) { + return String.fromCharCode.apply(String, codePoints); // avoid extra slice() + } -/** - * The Buffer constructor returns instances of `Uint8Array` that have their - * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of - * `Uint8Array`, so the returned instances will have all the node `Buffer` methods - * and the `Uint8Array` methods. Square bracket notation works as expected -- it - * returns a single octet. - * - * The `Uint8Array` prototype remains unmodified. - */ + // Decode in chunks to avoid "call stack size exceeded". + var res = ''; + var i = 0; + while (i < len) { + res += String.fromCharCode.apply(String, codePoints.slice(i, (i += MAX_ARGUMENTS_LENGTH))); + } + return res; + } -function Buffer (arg, encodingOrOffset, length) { - if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { - return new Buffer(arg, encodingOrOffset, length) - } + function asciiSlice(buf, start, end) { + var ret = ''; + end = Math.min(buf.length, end); - // Common case. - if (typeof arg === 'number') { - if (typeof encodingOrOffset === 'string') { - throw new Error( - 'If encoding is specified then the first argument must be a string' - ) - } - return allocUnsafe(this, arg) - } - return from(this, arg, encodingOrOffset, length) -} + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i] & 0x7f); + } + return ret; + } -Buffer.poolSize = 8192 // not used by this implementation + function latin1Slice(buf, start, end) { + var ret = ''; + end = Math.min(buf.length, end); -// TODO: Legacy, not needed anymore. Remove in next major version. -Buffer._augment = function (arr) { - arr.__proto__ = Buffer.prototype - return arr -} + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i]); + } + return ret; + } -function from (that, value, encodingOrOffset, length) { - if (typeof value === 'number') { - throw new TypeError('"value" argument must not be a number') - } + function hexSlice(buf, start, end) { + var len = buf.length; - if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { - return fromArrayBuffer(that, value, encodingOrOffset, length) - } + if (!start || start < 0) start = 0; + if (!end || end < 0 || end > len) end = len; - if (typeof value === 'string') { - return fromString(that, value, encodingOrOffset) - } + var out = ''; + for (var i = start; i < end; ++i) { + out += toHex(buf[i]); + } + return out; + } - return fromObject(that, value) -} + function utf16leSlice(buf, start, end) { + var bytes = buf.slice(start, end); + var res = ''; + for (var i = 0; i < bytes.length; i += 2) { + res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256); + } + return res; + } -/** - * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError - * if value is a number. - * Buffer.from(str[, encoding]) - * Buffer.from(array) - * Buffer.from(buffer) - * Buffer.from(arrayBuffer[, byteOffset[, length]]) - **/ -Buffer.from = function (value, encodingOrOffset, length) { - return from(null, value, encodingOrOffset, length) -} + Buffer.prototype.slice = function slice(start, end) { + var len = this.length; + start = ~~start; + end = end === undefined ? len : ~~end; -if (Buffer.TYPED_ARRAY_SUPPORT) { - Buffer.prototype.__proto__ = Uint8Array.prototype - Buffer.__proto__ = Uint8Array - if (typeof Symbol !== 'undefined' && Symbol.species && - Buffer[Symbol.species] === Buffer) { - // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 - Object.defineProperty(Buffer, Symbol.species, { - value: null, - configurable: true - }) - } -} + if (start < 0) { + start += len; + if (start < 0) start = 0; + } else if (start > len) { + start = len; + } -function assertSize (size) { - if (typeof size !== 'number') { - throw new TypeError('"size" argument must be a number') - } else if (size < 0) { - throw new RangeError('"size" argument must not be negative') - } -} + if (end < 0) { + end += len; + if (end < 0) end = 0; + } else if (end > len) { + end = len; + } -function alloc (that, size, fill, encoding) { - assertSize(size) - if (size <= 0) { - return createBuffer(that, size) - } - if (fill !== undefined) { - // Only pay attention to encoding if it's a string. This - // prevents accidentally sending in a number that would - // be interpretted as a start offset. - return typeof encoding === 'string' - ? createBuffer(that, size).fill(fill, encoding) - : createBuffer(that, size).fill(fill) - } - return createBuffer(that, size) -} + if (end < start) end = start; -/** - * Creates a new filled Buffer instance. - * alloc(size[, fill[, encoding]]) - **/ -Buffer.alloc = function (size, fill, encoding) { - return alloc(null, size, fill, encoding) -} + var newBuf; + if (Buffer.TYPED_ARRAY_SUPPORT) { + newBuf = this.subarray(start, end); + newBuf.__proto__ = Buffer.prototype; + } else { + var sliceLen = end - start; + newBuf = new Buffer(sliceLen, undefined); + for (var i = 0; i < sliceLen; ++i) { + newBuf[i] = this[i + start]; + } + } -function allocUnsafe (that, size) { - assertSize(size) - that = createBuffer(that, size < 0 ? 0 : checked(size) | 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) { - for (var i = 0; i < size; ++i) { - that[i] = 0 - } - } - return that -} + return newBuf; + }; -/** - * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. - * */ -Buffer.allocUnsafe = function (size) { - return allocUnsafe(null, size) -} -/** - * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. + /* + * Need to make sure that buffer isn't trying to write out of bounds. */ -Buffer.allocUnsafeSlow = function (size) { - return allocUnsafe(null, size) -} - -function fromString (that, string, encoding) { - if (typeof encoding !== 'string' || encoding === '') { - encoding = 'utf8' - } - - if (!Buffer.isEncoding(encoding)) { - throw new TypeError('"encoding" must be a valid string encoding') - } + function checkOffset(offset, ext, length) { + if (offset % 1 !== 0 || offset < 0) throw new RangeError('offset is not uint'); + if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length'); + } - var length = byteLength(string, encoding) | 0 - that = createBuffer(that, length) + Buffer.prototype.readUIntLE = function readUIntLE(offset, byteLength, noAssert) { + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) checkOffset(offset, byteLength, this.length); - var actual = that.write(string, encoding) + var val = this[offset]; + var mul = 1; + var i = 0; + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul; + } - if (actual !== length) { - // Writing a hex string, for example, that contains invalid characters will - // cause everything after the first invalid character to be ignored. (e.g. - // 'abxxcd' will be treated as 'ab') - that = that.slice(0, actual) - } + return val; + }; - return that -} + Buffer.prototype.readUIntBE = function readUIntBE(offset, byteLength, noAssert) { + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) { + checkOffset(offset, byteLength, this.length); + } -function fromArrayLike (that, array) { - var length = array.length < 0 ? 0 : checked(array.length) | 0 - that = createBuffer(that, length) - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that -} + var val = this[offset + --byteLength]; + var mul = 1; + while (byteLength > 0 && (mul *= 0x100)) { + val += this[offset + --byteLength] * mul; + } -function fromArrayBuffer (that, array, byteOffset, length) { - array.byteLength // this throws if `array` is not a valid ArrayBuffer + return val; + }; - if (byteOffset < 0 || array.byteLength < byteOffset) { - throw new RangeError('\'offset\' is out of bounds') - } + Buffer.prototype.readUInt8 = function readUInt8(offset, noAssert) { + if (!noAssert) checkOffset(offset, 1, this.length); + return this[offset]; + }; - if (array.byteLength < byteOffset + (length || 0)) { - throw new RangeError('\'length\' is out of bounds') - } + Buffer.prototype.readUInt16LE = function readUInt16LE(offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length); + return this[offset] | (this[offset + 1] << 8); + }; - if (byteOffset === undefined && length === undefined) { - array = new Uint8Array(array) - } else if (length === undefined) { - array = new Uint8Array(array, byteOffset) - } else { - array = new Uint8Array(array, byteOffset, length) - } + Buffer.prototype.readUInt16BE = function readUInt16BE(offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length); + return (this[offset] << 8) | this[offset + 1]; + }; - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = array - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - that = fromArrayLike(that, array) - } - return that -} + Buffer.prototype.readUInt32LE = function readUInt32LE(offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); -function fromObject (that, obj) { - if (Buffer.isBuffer(obj)) { - var len = checked(obj.length) | 0 - that = createBuffer(that, len) + return (this[offset] | (this[offset + 1] << 8) | (this[offset + 2] << 16)) + this[offset + 3] * 0x1000000; + }; - if (that.length === 0) { - return that - } + Buffer.prototype.readUInt32BE = function readUInt32BE(offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); - obj.copy(that, 0, 0, len) - return that - } + return this[offset] * 0x1000000 + ((this[offset + 1] << 16) | (this[offset + 2] << 8) | this[offset + 3]); + }; - if (obj) { - if ((typeof ArrayBuffer !== 'undefined' && - obj.buffer instanceof ArrayBuffer) || 'length' in obj) { - if (typeof obj.length !== 'number' || isnan(obj.length)) { - return createBuffer(that, 0) - } - return fromArrayLike(that, obj) - } + Buffer.prototype.readIntLE = function readIntLE(offset, byteLength, noAssert) { + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) checkOffset(offset, byteLength, this.length); - if (obj.type === 'Buffer' && isArray(obj.data)) { - return fromArrayLike(that, obj.data) - } - } + var val = this[offset]; + var mul = 1; + var i = 0; + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul; + } + mul *= 0x80; - throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') -} + if (val >= mul) val -= Math.pow(2, 8 * byteLength); -function checked (length) { - // Note: cannot use `length < kMaxLength()` here because that fails when - // length is NaN (which is otherwise coerced to zero.) - if (length >= kMaxLength()) { - throw new RangeError('Attempt to allocate Buffer larger than maximum ' + - 'size: 0x' + kMaxLength().toString(16) + ' bytes') - } - return length | 0 -} + return val; + }; -function SlowBuffer (length) { - if (+length != length) { // eslint-disable-line eqeqeq - length = 0 - } - return Buffer.alloc(+length) -} + Buffer.prototype.readIntBE = function readIntBE(offset, byteLength, noAssert) { + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) checkOffset(offset, byteLength, this.length); -Buffer.isBuffer = function isBuffer (b) { - return !!(b != null && b._isBuffer) -} + var i = byteLength; + var mul = 1; + var val = this[offset + --i]; + while (i > 0 && (mul *= 0x100)) { + val += this[offset + --i] * mul; + } + mul *= 0x80; + + if (val >= mul) val -= Math.pow(2, 8 * byteLength); + + return val; + }; + + Buffer.prototype.readInt8 = function readInt8(offset, noAssert) { + if (!noAssert) checkOffset(offset, 1, this.length); + if (!(this[offset] & 0x80)) return this[offset]; + return (0xff - this[offset] + 1) * -1; + }; + + Buffer.prototype.readInt16LE = function readInt16LE(offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length); + var val = this[offset] | (this[offset + 1] << 8); + return val & 0x8000 ? val | 0xffff0000 : val; + }; + + Buffer.prototype.readInt16BE = function readInt16BE(offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length); + var val = this[offset + 1] | (this[offset] << 8); + return val & 0x8000 ? val | 0xffff0000 : val; + }; + + Buffer.prototype.readInt32LE = function readInt32LE(offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + + return this[offset] | (this[offset + 1] << 8) | (this[offset + 2] << 16) | (this[offset + 3] << 24); + }; + + Buffer.prototype.readInt32BE = function readInt32BE(offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + + return (this[offset] << 24) | (this[offset + 1] << 16) | (this[offset + 2] << 8) | this[offset + 3]; + }; + + Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + return ieee754.read(this, offset, true, 23, 4); + }; + + Buffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + return ieee754.read(this, offset, false, 23, 4); + }; + + Buffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) { + if (!noAssert) checkOffset(offset, 8, this.length); + return ieee754.read(this, offset, true, 52, 8); + }; + + Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) { + if (!noAssert) checkOffset(offset, 8, this.length); + return ieee754.read(this, offset, false, 52, 8); + }; + + function checkInt(buf, value, offset, ext, max, min) { + if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance'); + if (value > max || value < min) throw new RangeError('"value" argument is out of bounds'); + if (offset + ext > buf.length) throw new RangeError('Index out of range'); + } -Buffer.compare = function compare (a, b) { - if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { - throw new TypeError('Arguments must be Buffers') - } + Buffer.prototype.writeUIntLE = function writeUIntLE(value, offset, byteLength, noAssert) { + value = +value; + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1; + checkInt(this, value, offset, byteLength, maxBytes, 0); + } - if (a === b) return 0 + var mul = 1; + var i = 0; + this[offset] = value & 0xff; + while (++i < byteLength && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xff; + } - var x = a.length - var y = b.length + return offset + byteLength; + }; - for (var i = 0, len = Math.min(x, y); i < len; ++i) { - if (a[i] !== b[i]) { - x = a[i] - y = b[i] - break - } - } + Buffer.prototype.writeUIntBE = function writeUIntBE(value, offset, byteLength, noAssert) { + value = +value; + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1; + checkInt(this, value, offset, byteLength, maxBytes, 0); + } - if (x < y) return -1 - if (y < x) return 1 - return 0 -} + var i = byteLength - 1; + var mul = 1; + this[offset + i] = value & 0xff; + while (--i >= 0 && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xff; + } -Buffer.isEncoding = function isEncoding (encoding) { - switch (String(encoding).toLowerCase()) { - case 'hex': - case 'utf8': - case 'utf-8': - case 'ascii': - case 'latin1': - case 'binary': - case 'base64': - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return true - default: - return false - } -} + return offset + byteLength; + }; + + Buffer.prototype.writeUInt8 = function writeUInt8(value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0); + if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value); + this[offset] = value & 0xff; + return offset + 1; + }; + + function objectWriteUInt16(buf, value, offset, littleEndian) { + if (value < 0) value = 0xffff + value + 1; + for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) { + buf[offset + i] = + (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> ((littleEndian ? i : 1 - i) * 8); + } + } -Buffer.concat = function concat (list, length) { - if (!isArray(list)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } + Buffer.prototype.writeUInt16LE = function writeUInt16LE(value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = value & 0xff; + this[offset + 1] = value >>> 8; + } else { + objectWriteUInt16(this, value, offset, true); + } + return offset + 2; + }; + + Buffer.prototype.writeUInt16BE = function writeUInt16BE(value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = value >>> 8; + this[offset + 1] = value & 0xff; + } else { + objectWriteUInt16(this, value, offset, false); + } + return offset + 2; + }; - if (list.length === 0) { - return Buffer.alloc(0) - } + function objectWriteUInt32(buf, value, offset, littleEndian) { + if (value < 0) value = 0xffffffff + value + 1; + for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) { + buf[offset + i] = (value >>> ((littleEndian ? i : 3 - i) * 8)) & 0xff; + } + } - var i - if (length === undefined) { - length = 0 - for (i = 0; i < list.length; ++i) { - length += list[i].length - } - } + Buffer.prototype.writeUInt32LE = function writeUInt32LE(value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset + 3] = value >>> 24; + this[offset + 2] = value >>> 16; + this[offset + 1] = value >>> 8; + this[offset] = value & 0xff; + } else { + objectWriteUInt32(this, value, offset, true); + } + return offset + 4; + }; + + Buffer.prototype.writeUInt32BE = function writeUInt32BE(value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = value >>> 24; + this[offset + 1] = value >>> 16; + this[offset + 2] = value >>> 8; + this[offset + 3] = value & 0xff; + } else { + objectWriteUInt32(this, value, offset, false); + } + return offset + 4; + }; - var buffer = Buffer.allocUnsafe(length) - var pos = 0 - for (i = 0; i < list.length; ++i) { - var buf = list[i] - if (!Buffer.isBuffer(buf)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - buf.copy(buffer, pos) - pos += buf.length - } - return buffer -} + Buffer.prototype.writeIntLE = function writeIntLE(value, offset, byteLength, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) { + var limit = Math.pow(2, 8 * byteLength - 1); -function byteLength (string, encoding) { - if (Buffer.isBuffer(string)) { - return string.length - } - if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && - (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { - return string.byteLength - } - if (typeof string !== 'string') { - string = '' + string - } + checkInt(this, value, offset, byteLength, limit - 1, -limit); + } - var len = string.length - if (len === 0) return 0 - - // Use a for loop to avoid recursion - var loweredCase = false - for (;;) { - switch (encoding) { - case 'ascii': - case 'latin1': - case 'binary': - return len - case 'utf8': - case 'utf-8': - case undefined: - return utf8ToBytes(string).length - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return len * 2 - case 'hex': - return len >>> 1 - case 'base64': - return base64ToBytes(string).length - default: - if (loweredCase) return utf8ToBytes(string).length // assume utf8 - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } -} -Buffer.byteLength = byteLength + var i = 0; + var mul = 1; + var sub = 0; + this[offset] = value & 0xff; + while (++i < byteLength && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { + sub = 1; + } + this[offset + i] = (((value / mul) >> 0) - sub) & 0xff; + } -function slowToString (encoding, start, end) { - var loweredCase = false + return offset + byteLength; + }; - // No need to verify that "this.length <= MAX_UINT32" since it's a read-only - // property of a typed array. + Buffer.prototype.writeIntBE = function writeIntBE(value, offset, byteLength, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) { + var limit = Math.pow(2, 8 * byteLength - 1); - // This behaves neither like String nor Uint8Array in that we set start/end - // to their upper/lower bounds if the value passed is out of range. - // undefined is handled specially as per ECMA-262 6th Edition, - // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. - if (start === undefined || start < 0) { - start = 0 - } - // Return early if start > this.length. Done here to prevent potential uint32 - // coercion fail below. - if (start > this.length) { - return '' - } + checkInt(this, value, offset, byteLength, limit - 1, -limit); + } - if (end === undefined || end > this.length) { - end = this.length - } + var i = byteLength - 1; + var mul = 1; + var sub = 0; + this[offset + i] = value & 0xff; + while (--i >= 0 && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { + sub = 1; + } + this[offset + i] = (((value / mul) >> 0) - sub) & 0xff; + } - if (end <= 0) { - return '' - } + return offset + byteLength; + }; + + Buffer.prototype.writeInt8 = function writeInt8(value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80); + if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value); + if (value < 0) value = 0xff + value + 1; + this[offset] = value & 0xff; + return offset + 1; + }; + + Buffer.prototype.writeInt16LE = function writeInt16LE(value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = value & 0xff; + this[offset + 1] = value >>> 8; + } else { + objectWriteUInt16(this, value, offset, true); + } + return offset + 2; + }; + + Buffer.prototype.writeInt16BE = function writeInt16BE(value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = value >>> 8; + this[offset + 1] = value & 0xff; + } else { + objectWriteUInt16(this, value, offset, false); + } + return offset + 2; + }; + + Buffer.prototype.writeInt32LE = function writeInt32LE(value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = value & 0xff; + this[offset + 1] = value >>> 8; + this[offset + 2] = value >>> 16; + this[offset + 3] = value >>> 24; + } else { + objectWriteUInt32(this, value, offset, true); + } + return offset + 4; + }; + + Buffer.prototype.writeInt32BE = function writeInt32BE(value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000); + if (value < 0) value = 0xffffffff + value + 1; + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = value >>> 24; + this[offset + 1] = value >>> 16; + this[offset + 2] = value >>> 8; + this[offset + 3] = value & 0xff; + } else { + objectWriteUInt32(this, value, offset, false); + } + return offset + 4; + }; - // Force coersion to uint32. This will also coerce falsey/NaN values to 0. - end >>>= 0 - start >>>= 0 + function checkIEEE754(buf, value, offset, ext, max, min) { + if (offset + ext > buf.length) throw new RangeError('Index out of range'); + if (offset < 0) throw new RangeError('Index out of range'); + } - if (end <= start) { - return '' - } + function writeFloat(buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + checkIEEE754(buf, value, offset, 4, 3.4028234663852886e38, -3.4028234663852886e38); + } + ieee754.write(buf, value, offset, littleEndian, 23, 4); + return offset + 4; + } - if (!encoding) encoding = 'utf8' + Buffer.prototype.writeFloatLE = function writeFloatLE(value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert); + }; - while (true) { - switch (encoding) { - case 'hex': - return hexSlice(this, start, end) + Buffer.prototype.writeFloatBE = function writeFloatBE(value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert); + }; - case 'utf8': - case 'utf-8': - return utf8Slice(this, start, end) + function writeDouble(buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + checkIEEE754(buf, value, offset, 8, 1.7976931348623157e308, -1.7976931348623157e308); + } + ieee754.write(buf, value, offset, littleEndian, 52, 8); + return offset + 8; + } - case 'ascii': - return asciiSlice(this, start, end) + Buffer.prototype.writeDoubleLE = function writeDoubleLE(value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert); + }; + + Buffer.prototype.writeDoubleBE = function writeDoubleBE(value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert); + }; + + // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) + Buffer.prototype.copy = function copy(target, targetStart, start, end) { + if (!start) start = 0; + if (!end && end !== 0) end = this.length; + if (targetStart >= target.length) targetStart = target.length; + if (!targetStart) targetStart = 0; + if (end > 0 && end < start) end = start; + + // Copy 0 bytes; we're done + if (end === start) return 0; + if (target.length === 0 || this.length === 0) return 0; + + // Fatal error conditions + if (targetStart < 0) { + throw new RangeError('targetStart out of bounds'); + } + if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds'); + if (end < 0) throw new RangeError('sourceEnd out of bounds'); - case 'latin1': - case 'binary': - return latin1Slice(this, start, end) + // Are we oob? + if (end > this.length) end = this.length; + if (target.length - targetStart < end - start) { + end = target.length - targetStart + start; + } - case 'base64': - return base64Slice(this, start, end) + var len = end - start; + var i; - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return utf16leSlice(this, start, end) + if (this === target && start < targetStart && targetStart < end) { + // descending copy from end + for (i = len - 1; i >= 0; --i) { + target[i + targetStart] = this[i + start]; + } + } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { + // ascending copy from start + for (i = 0; i < len; ++i) { + target[i + targetStart] = this[i + start]; + } + } else { + Uint8Array.prototype.set.call(target, this.subarray(start, start + len), targetStart); + } - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = (encoding + '').toLowerCase() - loweredCase = true - } - } -} + return len; + }; + + // Usage: + // buffer.fill(number[, offset[, end]]) + // buffer.fill(buffer[, offset[, end]]) + // buffer.fill(string[, offset[, end]][, encoding]) + Buffer.prototype.fill = function fill(val, start, end, encoding) { + // Handle string cases: + if (typeof val === 'string') { + if (typeof start === 'string') { + encoding = start; + start = 0; + end = this.length; + } else if (typeof end === 'string') { + encoding = end; + end = this.length; + } + if (val.length === 1) { + var code = val.charCodeAt(0); + if (code < 256) { + val = code; + } + } + if (encoding !== undefined && typeof encoding !== 'string') { + throw new TypeError('encoding must be a string'); + } + if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding); + } + } else if (typeof val === 'number') { + val = val & 255; + } -// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect -// Buffer instances. -Buffer.prototype._isBuffer = true + // Invalid ranges are not set to a default, so can range check early. + if (start < 0 || this.length < start || this.length < end) { + throw new RangeError('Out of range index'); + } -function swap (b, n, m) { - var i = b[n] - b[n] = b[m] - b[m] = i -} + if (end <= start) { + return this; + } -Buffer.prototype.swap16 = function swap16 () { - var len = this.length - if (len % 2 !== 0) { - throw new RangeError('Buffer size must be a multiple of 16-bits') - } - for (var i = 0; i < len; i += 2) { - swap(this, i, i + 1) - } - return this -} + start = start >>> 0; + end = end === undefined ? this.length : end >>> 0; -Buffer.prototype.swap32 = function swap32 () { - var len = this.length - if (len % 4 !== 0) { - throw new RangeError('Buffer size must be a multiple of 32-bits') - } - for (var i = 0; i < len; i += 4) { - swap(this, i, i + 3) - swap(this, i + 1, i + 2) - } - return this -} + if (!val) val = 0; -Buffer.prototype.swap64 = function swap64 () { - var len = this.length - if (len % 8 !== 0) { - throw new RangeError('Buffer size must be a multiple of 64-bits') - } - for (var i = 0; i < len; i += 8) { - swap(this, i, i + 7) - swap(this, i + 1, i + 6) - swap(this, i + 2, i + 5) - swap(this, i + 3, i + 4) - } - return this -} + var i; + if (typeof val === 'number') { + for (i = start; i < end; ++i) { + this[i] = val; + } + } else { + var bytes = Buffer.isBuffer(val) ? val : utf8ToBytes(new Buffer(val, encoding).toString()); + var len = bytes.length; + for (i = 0; i < end - start; ++i) { + this[i + start] = bytes[i % len]; + } + } -Buffer.prototype.toString = function toString () { - var length = this.length | 0 - if (length === 0) return '' - if (arguments.length === 0) return utf8Slice(this, 0, length) - return slowToString.apply(this, arguments) -} + return this; + }; -Buffer.prototype.equals = function equals (b) { - if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') - if (this === b) return true - return Buffer.compare(this, b) === 0 -} + // HELPER FUNCTIONS + // ================ -Buffer.prototype.inspect = function inspect () { - var str = '' - var max = exports.INSPECT_MAX_BYTES - if (this.length > 0) { - str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') - if (this.length > max) str += ' ... ' - } - return '' -} + var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g; -Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { - if (!Buffer.isBuffer(target)) { - throw new TypeError('Argument must be a Buffer') - } + function base64clean(str) { + // Node strips out invalid characters like \n and \t from the string, base64-js does not + str = stringtrim(str).replace(INVALID_BASE64_RE, ''); + // Node converts strings with length < 2 to '' + if (str.length < 2) return ''; + // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not + while (str.length % 4 !== 0) { + str = str + '='; + } + return str; + } - if (start === undefined) { - start = 0 - } - if (end === undefined) { - end = target ? target.length : 0 - } - if (thisStart === undefined) { - thisStart = 0 - } - if (thisEnd === undefined) { - thisEnd = this.length - } + function stringtrim(str) { + if (str.trim) return str.trim(); + return str.replace(/^\s+|\s+$/g, ''); + } - if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { - throw new RangeError('out of range index') - } + function toHex(n) { + if (n < 16) return '0' + n.toString(16); + return n.toString(16); + } - if (thisStart >= thisEnd && start >= end) { - return 0 - } - if (thisStart >= thisEnd) { - return -1 - } - if (start >= end) { - return 1 - } + function utf8ToBytes(string, units) { + units = units || Infinity; + var codePoint; + var length = string.length; + var leadSurrogate = null; + var bytes = []; + + for (var i = 0; i < length; ++i) { + codePoint = string.charCodeAt(i); + + // is surrogate component + if (codePoint > 0xd7ff && codePoint < 0xe000) { + // last char was a lead + if (!leadSurrogate) { + // no lead yet + if (codePoint > 0xdbff) { + // unexpected trail + if ((units -= 3) > -1) bytes.push(0xef, 0xbf, 0xbd); + continue; + } else if (i + 1 === length) { + // unpaired lead + if ((units -= 3) > -1) bytes.push(0xef, 0xbf, 0xbd); + continue; + } + + // valid lead + leadSurrogate = codePoint; + + continue; + } + + // 2 leads in a row + if (codePoint < 0xdc00) { + if ((units -= 3) > -1) bytes.push(0xef, 0xbf, 0xbd); + leadSurrogate = codePoint; + continue; + } + + // valid surrogate pair + codePoint = (((leadSurrogate - 0xd800) << 10) | (codePoint - 0xdc00)) + 0x10000; + } else if (leadSurrogate) { + // valid bmp char, but last char was a lead + if ((units -= 3) > -1) bytes.push(0xef, 0xbf, 0xbd); + } - start >>>= 0 - end >>>= 0 - thisStart >>>= 0 - thisEnd >>>= 0 + leadSurrogate = null; + + // encode utf8 + if (codePoint < 0x80) { + if ((units -= 1) < 0) break; + bytes.push(codePoint); + } else if (codePoint < 0x800) { + if ((units -= 2) < 0) break; + bytes.push((codePoint >> 0x6) | 0xc0, (codePoint & 0x3f) | 0x80); + } else if (codePoint < 0x10000) { + if ((units -= 3) < 0) break; + bytes.push((codePoint >> 0xc) | 0xe0, ((codePoint >> 0x6) & 0x3f) | 0x80, (codePoint & 0x3f) | 0x80); + } else if (codePoint < 0x110000) { + if ((units -= 4) < 0) break; + bytes.push( + (codePoint >> 0x12) | 0xf0, + ((codePoint >> 0xc) & 0x3f) | 0x80, + ((codePoint >> 0x6) & 0x3f) | 0x80, + (codePoint & 0x3f) | 0x80, + ); + } else { + throw new Error('Invalid code point'); + } + } - if (this === target) return 0 + return bytes; + } - var x = thisEnd - thisStart - var y = end - start - var len = Math.min(x, y) + function asciiToBytes(str) { + var byteArray = []; + for (var i = 0; i < str.length; ++i) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xff); + } + return byteArray; + } - var thisCopy = this.slice(thisStart, thisEnd) - var targetCopy = target.slice(start, end) + function utf16leToBytes(str, units) { + var c, hi, lo; + var byteArray = []; + for (var i = 0; i < str.length; ++i) { + if ((units -= 2) < 0) break; + + c = str.charCodeAt(i); + hi = c >> 8; + lo = c % 256; + byteArray.push(lo); + byteArray.push(hi); + } - for (var i = 0; i < len; ++i) { - if (thisCopy[i] !== targetCopy[i]) { - x = thisCopy[i] - y = targetCopy[i] - break - } - } + return byteArray; + } - if (x < y) return -1 - if (y < x) return 1 - return 0 -} + function base64ToBytes(str) { + return base64.toByteArray(base64clean(str)); + } -// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, -// OR the last index of `val` in `buffer` at offset <= `byteOffset`. -// -// Arguments: -// - buffer - a Buffer to search -// - val - a string, Buffer, or number -// - byteOffset - an index into `buffer`; will be clamped to an int32 -// - encoding - an optional encoding, relevant is val is a string -// - dir - true for indexOf, false for lastIndexOf -function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { - // Empty buffer means no match - if (buffer.length === 0) return -1 - - // Normalize byteOffset - if (typeof byteOffset === 'string') { - encoding = byteOffset - byteOffset = 0 - } else if (byteOffset > 0x7fffffff) { - byteOffset = 0x7fffffff - } else if (byteOffset < -0x80000000) { - byteOffset = -0x80000000 - } - byteOffset = +byteOffset // Coerce to Number. - if (isNaN(byteOffset)) { - // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer - byteOffset = dir ? 0 : (buffer.length - 1) - } + function blitBuffer(src, dst, offset, length) { + for (var i = 0; i < length; ++i) { + if (i + offset >= dst.length || i >= src.length) break; + dst[i + offset] = src[i]; + } + return i; + } - // Normalize byteOffset: negative offsets start from the end of the buffer - if (byteOffset < 0) byteOffset = buffer.length + byteOffset - if (byteOffset >= buffer.length) { - if (dir) return -1 - else byteOffset = buffer.length - 1 - } else if (byteOffset < 0) { - if (dir) byteOffset = 0 - else return -1 - } + function isnan(val) { + return val !== val; // eslint-disable-line no-self-compare + } + }.call( + this, + typeof global !== 'undefined' + ? global + : typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : {}, + )); + }, + { 'base64-js': 61, ieee754: 182, isarray: 186 }, + ], + 114: [ + function(require, module, exports) { + var Buffer = require('safe-buffer').Buffer; + var Transform = require('stream').Transform; + var StringDecoder = require('string_decoder').StringDecoder; + var inherits = require('inherits'); + + function CipherBase(hashMode) { + Transform.call(this); + this.hashMode = typeof hashMode === 'string'; + if (this.hashMode) { + this[hashMode] = this._finalOrDigest; + } else { + this.final = this._finalOrDigest; + } + if (this._final) { + this.__final = this._final; + this._final = null; + } + this._decoder = null; + this._encoding = null; + } + inherits(CipherBase, Transform); - // Normalize val - if (typeof val === 'string') { - val = Buffer.from(val, encoding) - } + CipherBase.prototype.update = function(data, inputEnc, outputEnc) { + if (typeof data === 'string') { + data = Buffer.from(data, inputEnc); + } - // Finally, search either indexOf (if dir is true) or lastIndexOf - if (Buffer.isBuffer(val)) { - // Special case: looking for empty string/buffer always fails - if (val.length === 0) { - return -1 - } - return arrayIndexOf(buffer, val, byteOffset, encoding, dir) - } else if (typeof val === 'number') { - val = val & 0xFF // Search for a byte value [0-255] - if (Buffer.TYPED_ARRAY_SUPPORT && - typeof Uint8Array.prototype.indexOf === 'function') { - if (dir) { - return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) - } else { - return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) - } - } - return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) - } + var outData = this._update(data); + if (this.hashMode) return this; - throw new TypeError('val must be string, number or Buffer') -} + if (outputEnc) { + outData = this._toString(outData, outputEnc); + } -function arrayIndexOf (arr, val, byteOffset, encoding, dir) { - var indexSize = 1 - var arrLength = arr.length - var valLength = val.length - - if (encoding !== undefined) { - encoding = String(encoding).toLowerCase() - if (encoding === 'ucs2' || encoding === 'ucs-2' || - encoding === 'utf16le' || encoding === 'utf-16le') { - if (arr.length < 2 || val.length < 2) { - return -1 - } - indexSize = 2 - arrLength /= 2 - valLength /= 2 - byteOffset /= 2 - } - } + return outData; + }; - function read (buf, i) { - if (indexSize === 1) { - return buf[i] - } else { - return buf.readUInt16BE(i * indexSize) - } - } + CipherBase.prototype.setAutoPadding = function() {}; + CipherBase.prototype.getAuthTag = function() { + throw new Error('trying to get auth tag in unsupported state'); + }; - var i - if (dir) { - var foundIndex = -1 - for (i = byteOffset; i < arrLength; i++) { - if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { - if (foundIndex === -1) foundIndex = i - if (i - foundIndex + 1 === valLength) return foundIndex * indexSize - } else { - if (foundIndex !== -1) i -= i - foundIndex - foundIndex = -1 - } - } - } else { - if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength - for (i = byteOffset; i >= 0; i--) { - var found = true - for (var j = 0; j < valLength; j++) { - if (read(arr, i + j) !== read(val, j)) { - found = false - break - } - } - if (found) return i - } - } + CipherBase.prototype.setAuthTag = function() { + throw new Error('trying to set auth tag in unsupported state'); + }; - return -1 -} + CipherBase.prototype.setAAD = function() { + throw new Error('trying to set aad in unsupported state'); + }; -Buffer.prototype.includes = function includes (val, byteOffset, encoding) { - return this.indexOf(val, byteOffset, encoding) !== -1 -} + CipherBase.prototype._transform = function(data, _, next) { + var err; + try { + if (this.hashMode) { + this._update(data); + } else { + this.push(this._update(data)); + } + } catch (e) { + err = e; + } finally { + next(err); + } + }; + CipherBase.prototype._flush = function(done) { + var err; + try { + this.push(this.__final()); + } catch (e) { + err = e; + } -Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, true) -} + done(err); + }; + CipherBase.prototype._finalOrDigest = function(outputEnc) { + var outData = this.__final() || Buffer.alloc(0); + if (outputEnc) { + outData = this._toString(outData, outputEnc, true); + } + return outData; + }; -Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, false) -} + CipherBase.prototype._toString = function(value, enc, fin) { + if (!this._decoder) { + this._decoder = new StringDecoder(enc); + this._encoding = enc; + } -function hexWrite (buf, string, offset, length) { - offset = Number(offset) || 0 - var remaining = buf.length - offset - if (!length) { - length = remaining - } else { - length = Number(length) - if (length > remaining) { - length = remaining - } - } + if (this._encoding !== enc) throw new Error("can't switch encodings"); - // must be an even number of digits - var strLen = string.length - if (strLen % 2 !== 0) throw new TypeError('Invalid hex string') + var out = this._decoder.write(value); + if (fin) { + out += this._decoder.end(); + } - if (length > strLen / 2) { - length = strLen / 2 - } - for (var i = 0; i < length; ++i) { - var parsed = parseInt(string.substr(i * 2, 2), 16) - if (isNaN(parsed)) return i - buf[offset + i] = parsed - } - return i -} + return out; + }; -function utf8Write (buf, string, offset, length) { - return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) -} + module.exports = CipherBase; + }, + { inherits: 184, 'safe-buffer': 233, stream: 242, string_decoder: 109 }, + ], + 115: [ + function(require, module, exports) { + (function(Buffer) { + // Copyright Joyent, Inc. and other Node contributors. + // + // Permission is hereby granted, free of charge, to any person obtaining a + // copy of this software and associated documentation files (the + // "Software"), to deal in the Software without restriction, including + // without limitation the rights to use, copy, modify, merge, publish, + // distribute, sublicense, and/or sell copies of the Software, and to permit + // persons to whom the Software is furnished to do so, subject to the + // following conditions: + // + // The above copyright notice and this permission notice shall be included + // in all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + // USE OR OTHER DEALINGS IN THE SOFTWARE. + + // NOTE: These type checking functions intentionally don't use `instanceof` + // because it is fragile and can be easily faked with `Object.create()`. + + function isArray(arg) { + if (Array.isArray) { + return Array.isArray(arg); + } + return objectToString(arg) === '[object Array]'; + } + exports.isArray = isArray; -function asciiWrite (buf, string, offset, length) { - return blitBuffer(asciiToBytes(string), buf, offset, length) -} + function isBoolean(arg) { + return typeof arg === 'boolean'; + } + exports.isBoolean = isBoolean; -function latin1Write (buf, string, offset, length) { - return asciiWrite(buf, string, offset, length) -} + function isNull(arg) { + return arg === null; + } + exports.isNull = isNull; -function base64Write (buf, string, offset, length) { - return blitBuffer(base64ToBytes(string), buf, offset, length) -} + function isNullOrUndefined(arg) { + return arg == null; + } + exports.isNullOrUndefined = isNullOrUndefined; -function ucs2Write (buf, string, offset, length) { - return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) -} + function isNumber(arg) { + return typeof arg === 'number'; + } + exports.isNumber = isNumber; -Buffer.prototype.write = function write (string, offset, length, encoding) { - // Buffer#write(string) - if (offset === undefined) { - encoding = 'utf8' - length = this.length - offset = 0 - // Buffer#write(string, encoding) - } else if (length === undefined && typeof offset === 'string') { - encoding = offset - length = this.length - offset = 0 - // Buffer#write(string, offset[, length][, encoding]) - } else if (isFinite(offset)) { - offset = offset | 0 - if (isFinite(length)) { - length = length | 0 - if (encoding === undefined) encoding = 'utf8' - } else { - encoding = length - length = undefined - } - // legacy write(string, encoding, offset, length) - remove in v0.13 - } else { - throw new Error( - 'Buffer.write(string, encoding, offset[, length]) is no longer supported' - ) - } + function isString(arg) { + return typeof arg === 'string'; + } + exports.isString = isString; - var remaining = this.length - offset - if (length === undefined || length > remaining) length = remaining + function isSymbol(arg) { + return typeof arg === 'symbol'; + } + exports.isSymbol = isSymbol; - if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { - throw new RangeError('Attempt to write outside buffer bounds') - } + function isUndefined(arg) { + return arg === void 0; + } + exports.isUndefined = isUndefined; - if (!encoding) encoding = 'utf8' + function isRegExp(re) { + return objectToString(re) === '[object RegExp]'; + } + exports.isRegExp = isRegExp; - var loweredCase = false - for (;;) { - switch (encoding) { - case 'hex': - return hexWrite(this, string, offset, length) + function isObject(arg) { + return typeof arg === 'object' && arg !== null; + } + exports.isObject = isObject; - case 'utf8': - case 'utf-8': - return utf8Write(this, string, offset, length) + function isDate(d) { + return objectToString(d) === '[object Date]'; + } + exports.isDate = isDate; - case 'ascii': - return asciiWrite(this, string, offset, length) + function isError(e) { + return objectToString(e) === '[object Error]' || e instanceof Error; + } + exports.isError = isError; - case 'latin1': - case 'binary': - return latin1Write(this, string, offset, length) + function isFunction(arg) { + return typeof arg === 'function'; + } + exports.isFunction = isFunction; + + function isPrimitive(arg) { + return ( + arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined' + ); + } + exports.isPrimitive = isPrimitive; - case 'base64': - // Warning: maxLength not taken into account in base64Write - return base64Write(this, string, offset, length) + exports.isBuffer = Buffer.isBuffer; - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return ucs2Write(this, string, offset, length) + function objectToString(o) { + return Object.prototype.toString.call(o); + } + }.call(this, { isBuffer: require('../../is-buffer/index.js') })); + }, + { '../../is-buffer/index.js': 185 }, + ], + 116: [ + function(require, module, exports) { + (function(Buffer) { + var elliptic = require('elliptic'); + var BN = require('bn.js'); + + module.exports = function createECDH(curve) { + return new ECDH(curve); + }; + + var aliases = { + secp256k1: { + name: 'secp256k1', + byteLength: 32, + }, + secp224r1: { + name: 'p224', + byteLength: 28, + }, + prime256v1: { + name: 'p256', + byteLength: 32, + }, + prime192v1: { + name: 'p192', + byteLength: 24, + }, + ed25519: { + name: 'ed25519', + byteLength: 32, + }, + secp384r1: { + name: 'p384', + byteLength: 48, + }, + secp521r1: { + name: 'p521', + byteLength: 66, + }, + }; + + aliases.p224 = aliases.secp224r1; + aliases.p256 = aliases.secp256r1 = aliases.prime256v1; + aliases.p192 = aliases.secp192r1 = aliases.prime192v1; + aliases.p384 = aliases.secp384r1; + aliases.p521 = aliases.secp521r1; + + function ECDH(curve) { + this.curveType = aliases[curve]; + if (!this.curveType) { + this.curveType = { + name: curve, + }; + } + this.curve = new elliptic.ec(this.curveType.name); + this.keys = void 0; + } - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } -} + ECDH.prototype.generateKeys = function(enc, format) { + this.keys = this.curve.genKeyPair(); + return this.getPublicKey(enc, format); + }; -Buffer.prototype.toJSON = function toJSON () { - return { - type: 'Buffer', - data: Array.prototype.slice.call(this._arr || this, 0) - } -} + ECDH.prototype.computeSecret = function(other, inenc, enc) { + inenc = inenc || 'utf8'; + if (!Buffer.isBuffer(other)) { + other = new Buffer(other, inenc); + } + var otherPub = this.curve.keyFromPublic(other).getPublic(); + var out = otherPub.mul(this.keys.getPrivate()).getX(); + return formatReturnValue(out, enc, this.curveType.byteLength); + }; + + ECDH.prototype.getPublicKey = function(enc, format) { + var key = this.keys.getPublic(format === 'compressed', true); + if (format === 'hybrid') { + if (key[key.length - 1] % 2) { + key[0] = 7; + } else { + key[0] = 6; + } + } + return formatReturnValue(key, enc); + }; -function base64Slice (buf, start, end) { - if (start === 0 && end === buf.length) { - return base64.fromByteArray(buf) - } else { - return base64.fromByteArray(buf.slice(start, end)) - } -} + ECDH.prototype.getPrivateKey = function(enc) { + return formatReturnValue(this.keys.getPrivate(), enc); + }; -function utf8Slice (buf, start, end) { - end = Math.min(buf.length, end) - var res = [] - - var i = start - while (i < end) { - var firstByte = buf[i] - var codePoint = null - var bytesPerSequence = (firstByte > 0xEF) ? 4 - : (firstByte > 0xDF) ? 3 - : (firstByte > 0xBF) ? 2 - : 1 - - if (i + bytesPerSequence <= end) { - var secondByte, thirdByte, fourthByte, tempCodePoint - - switch (bytesPerSequence) { - case 1: - if (firstByte < 0x80) { - codePoint = firstByte - } - break - case 2: - secondByte = buf[i + 1] - if ((secondByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) - if (tempCodePoint > 0x7F) { - codePoint = tempCodePoint - } - } - break - case 3: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) - if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { - codePoint = tempCodePoint - } - } - break - case 4: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - fourthByte = buf[i + 3] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) - if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { - codePoint = tempCodePoint + ECDH.prototype.setPublicKey = function(pub, enc) { + enc = enc || 'utf8'; + if (!Buffer.isBuffer(pub)) { + pub = new Buffer(pub, enc); } + this.keys._importPublic(pub); + return this; + }; + + ECDH.prototype.setPrivateKey = function(priv, enc) { + enc = enc || 'utf8'; + if (!Buffer.isBuffer(priv)) { + priv = new Buffer(priv, enc); + } + var _priv = new BN(priv); + _priv = _priv.toString(16); + this.keys._importPrivate(_priv); + return this; + }; + + function formatReturnValue(bn, enc, len) { + if (!Array.isArray(bn)) { + bn = bn.toArray(); + } + var buf = new Buffer(bn); + if (len && buf.length < len) { + var zeros = new Buffer(len - buf.length); + zeros.fill(0); + buf = Buffer.concat([zeros, buf]); + } + if (!enc) { + return buf; + } else { + return buf.toString(enc); + } + } + }.call(this, require('buffer').Buffer)); + }, + { 'bn.js': 117, buffer: 113, elliptic: 118 }, + ], + 117: [ + function(require, module, exports) { + arguments[4][59][0].apply(exports, arguments); + }, + { buffer: 64, dup: 59 }, + ], + 118: [ + function(require, module, exports) { + arguments[4][93][0].apply(exports, arguments); + }, + { + '../package.json': 133, + './elliptic/curve': 121, + './elliptic/curves': 124, + './elliptic/ec': 125, + './elliptic/eddsa': 128, + './elliptic/utils': 132, + brorand: 63, + dup: 93, + }, + ], + 119: [ + function(require, module, exports) { + arguments[4][94][0].apply(exports, arguments); + }, + { '../../elliptic': 118, 'bn.js': 117, dup: 94 }, + ], + 120: [ + function(require, module, exports) { + arguments[4][95][0].apply(exports, arguments); + }, + { '../../elliptic': 118, '../curve': 121, 'bn.js': 117, dup: 95, inherits: 184 }, + ], + 121: [ + function(require, module, exports) { + arguments[4][96][0].apply(exports, arguments); + }, + { './base': 119, './edwards': 120, './mont': 122, './short': 123, dup: 96 }, + ], + 122: [ + function(require, module, exports) { + arguments[4][97][0].apply(exports, arguments); + }, + { '../../elliptic': 118, '../curve': 121, 'bn.js': 117, dup: 97, inherits: 184 }, + ], + 123: [ + function(require, module, exports) { + arguments[4][98][0].apply(exports, arguments); + }, + { '../../elliptic': 118, '../curve': 121, 'bn.js': 117, dup: 98, inherits: 184 }, + ], + 124: [ + function(require, module, exports) { + arguments[4][99][0].apply(exports, arguments); + }, + { '../elliptic': 118, './precomputed/secp256k1': 131, dup: 99, 'hash.js': 168 }, + ], + 125: [ + function(require, module, exports) { + arguments[4][100][0].apply(exports, arguments); + }, + { '../../elliptic': 118, './key': 126, './signature': 127, 'bn.js': 117, dup: 100, 'hmac-drbg': 181 }, + ], + 126: [ + function(require, module, exports) { + arguments[4][101][0].apply(exports, arguments); + }, + { '../../elliptic': 118, 'bn.js': 117, dup: 101 }, + ], + 127: [ + function(require, module, exports) { + arguments[4][102][0].apply(exports, arguments); + }, + { '../../elliptic': 118, 'bn.js': 117, dup: 102 }, + ], + 128: [ + function(require, module, exports) { + arguments[4][103][0].apply(exports, arguments); + }, + { '../../elliptic': 118, './key': 129, './signature': 130, dup: 103, 'hash.js': 168 }, + ], + 129: [ + function(require, module, exports) { + arguments[4][104][0].apply(exports, arguments); + }, + { '../../elliptic': 118, dup: 104 }, + ], + 130: [ + function(require, module, exports) { + arguments[4][105][0].apply(exports, arguments); + }, + { '../../elliptic': 118, 'bn.js': 117, dup: 105 }, + ], + 131: [ + function(require, module, exports) { + arguments[4][106][0].apply(exports, arguments); + }, + { dup: 106 }, + ], + 132: [ + function(require, module, exports) { + arguments[4][107][0].apply(exports, arguments); + }, + { 'bn.js': 117, dup: 107, 'minimalistic-assert': 192, 'minimalistic-crypto-utils': 193 }, + ], + 133: [ + function(require, module, exports) { + module.exports = { + _args: [['elliptic@6.4.0', '/Users/tonypizzicato/dev/meritlabs/lightwallet-stack/packages/bitcore-lib']], + _from: 'elliptic@6.4.0', + _id: 'elliptic@6.4.0', + _inBundle: false, + _integrity: 'sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=', + _location: '/create-ecdh/elliptic', + _phantomChildren: {}, + _requested: { + type: 'version', + registry: true, + raw: 'elliptic@6.4.0', + name: 'elliptic', + escapedName: 'elliptic', + rawSpec: '6.4.0', + saveSpec: null, + fetchSpec: '6.4.0', + }, + _requiredBy: ['/create-ecdh'], + _resolved: 'https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz', + _spec: '6.4.0', + _where: '/Users/tonypizzicato/dev/meritlabs/lightwallet-stack/packages/bitcore-lib', + author: { + name: 'Fedor Indutny', + email: 'fedor@indutny.com', + }, + bugs: { + url: 'https://github.com/indutny/elliptic/issues', + }, + dependencies: { + 'bn.js': '^4.4.0', + brorand: '^1.0.1', + 'hash.js': '^1.0.0', + 'hmac-drbg': '^1.0.0', + inherits: '^2.0.1', + 'minimalistic-assert': '^1.0.0', + 'minimalistic-crypto-utils': '^1.0.0', + }, + description: 'EC cryptography', + devDependencies: { + brfs: '^1.4.3', + grunt: '^0.4.5', + 'grunt-browserify': '^5.0.0', + 'grunt-cli': '^1.2.0', + 'grunt-contrib-connect': '^1.0.0', + 'grunt-contrib-copy': '^1.0.0', + 'grunt-contrib-uglify': '^1.0.1', + 'grunt-saucelabs': '^8.6.2', + jscs: '^2.9.0', + jshint: '^2.6.0', + mocha: '^2.1.0', + }, + files: ['lib'], + homepage: 'https://github.com/indutny/elliptic', + keywords: ['EC', 'Elliptic', 'curve', 'Cryptography'], + license: 'MIT', + main: 'lib/elliptic.js', + name: 'elliptic', + repository: { + type: 'git', + url: 'git+ssh://git@github.com/indutny/elliptic.git', + }, + scripts: { + jscs: 'jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js', + jshint: 'jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js', + lint: 'npm run jscs && npm run jshint', + test: 'npm run lint && npm run unit', + version: 'grunt dist && git add dist/', + }, + version: '6.4.0', + }; + }, + {}, + ], + 134: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + var inherits = require('inherits'); + var md5 = require('./md5'); + var RIPEMD160 = require('ripemd160'); + var sha = require('sha.js'); + + var Base = require('cipher-base'); + + function HashNoConstructor(hash) { + Base.call(this, 'digest'); + + this._hash = hash; + this.buffers = []; } - } - } - - if (codePoint === null) { - // we did not generate a valid codePoint so insert a - // replacement char (U+FFFD) and advance only 1 byte - codePoint = 0xFFFD - bytesPerSequence = 1 - } else if (codePoint > 0xFFFF) { - // encode to utf16 (surrogate pair dance) - codePoint -= 0x10000 - res.push(codePoint >>> 10 & 0x3FF | 0xD800) - codePoint = 0xDC00 | codePoint & 0x3FF - } - - res.push(codePoint) - i += bytesPerSequence - } - return decodeCodePointsArray(res) -} + inherits(HashNoConstructor, Base); -// Based on http://stackoverflow.com/a/22747272/680742, the browser with -// the lowest limit is Chrome, with 0x10000 args. -// We go 1 magnitude less, for safety -var MAX_ARGUMENTS_LENGTH = 0x1000 + HashNoConstructor.prototype._update = function(data) { + this.buffers.push(data); + }; -function decodeCodePointsArray (codePoints) { - var len = codePoints.length - if (len <= MAX_ARGUMENTS_LENGTH) { - return String.fromCharCode.apply(String, codePoints) // avoid extra slice() - } + HashNoConstructor.prototype._final = function() { + var buf = Buffer.concat(this.buffers); + var r = this._hash(buf); + this.buffers = null; - // Decode in chunks to avoid "call stack size exceeded". - var res = '' - var i = 0 - while (i < len) { - res += String.fromCharCode.apply( - String, - codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) - ) - } - return res -} + return r; + }; -function asciiSlice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) + function Hash(hash) { + Base.call(this, 'digest'); - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i] & 0x7F) - } - return ret -} + this._hash = hash; + } -function latin1Slice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) + inherits(Hash, Base); - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i]) - } - return ret -} + Hash.prototype._update = function(data) { + this._hash.update(data); + }; -function hexSlice (buf, start, end) { - var len = buf.length + Hash.prototype._final = function() { + return this._hash.digest(); + }; - if (!start || start < 0) start = 0 - if (!end || end < 0 || end > len) end = len + module.exports = function createHash(alg) { + alg = alg.toLowerCase(); + if (alg === 'md5') return new HashNoConstructor(md5); + if (alg === 'rmd160' || alg === 'ripemd160') return new Hash(new RIPEMD160()); - var out = '' - for (var i = start; i < end; ++i) { - out += toHex(buf[i]) - } - return out -} + return new Hash(sha(alg)); + }; + }.call(this, require('buffer').Buffer)); + }, + { './md5': 136, buffer: 113, 'cipher-base': 114, inherits: 184, ripemd160: 232, 'sha.js': 235 }, + ], + 135: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + var intSize = 4; + var zeroBuffer = new Buffer(intSize); + zeroBuffer.fill(0); + + var charSize = 8; + var hashSize = 16; + + function toArray(buf) { + if (buf.length % intSize !== 0) { + var len = buf.length + (intSize - (buf.length % intSize)); + buf = Buffer.concat([buf, zeroBuffer], len); + } -function utf16leSlice (buf, start, end) { - var bytes = buf.slice(start, end) - var res = '' - for (var i = 0; i < bytes.length; i += 2) { - res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) - } - return res -} + var arr = new Array(buf.length >>> 2); + for (var i = 0, j = 0; i < buf.length; i += intSize, j++) { + arr[j] = buf.readInt32LE(i); + } -Buffer.prototype.slice = function slice (start, end) { - var len = this.length - start = ~~start - end = end === undefined ? len : ~~end + return arr; + } - if (start < 0) { - start += len - if (start < 0) start = 0 - } else if (start > len) { - start = len - } + module.exports = function hash(buf, fn) { + var arr = fn(toArray(buf), buf.length * charSize); + buf = new Buffer(hashSize); + for (var i = 0; i < arr.length; i++) { + buf.writeInt32LE(arr[i], i << 2, true); + } + return buf; + }; + }.call(this, require('buffer').Buffer)); + }, + { buffer: 113 }, + ], + 136: [ + function(require, module, exports) { + 'use strict'; + /* + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message + * Digest Algorithm, as defined in RFC 1321. + * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for more info. + */ - if (end < 0) { - end += len - if (end < 0) end = 0 - } else if (end > len) { - end = len - } + var makeHash = require('./make-hash'); - if (end < start) end = start - - var newBuf - if (Buffer.TYPED_ARRAY_SUPPORT) { - newBuf = this.subarray(start, end) - newBuf.__proto__ = Buffer.prototype - } else { - var sliceLen = end - start - newBuf = new Buffer(sliceLen, undefined) - for (var i = 0; i < sliceLen; ++i) { - newBuf[i] = this[i + start] - } - } + /* + * Calculate the MD5 of an array of little-endian words, and a bit length + */ + function core_md5(x, len) { + /* append padding */ + x[len >> 5] |= 0x80 << len % 32; + x[(((len + 64) >>> 9) << 4) + 14] = len; + + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + + for (var i = 0; i < x.length; i += 16) { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + + a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936); + d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586); + c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819); + b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330); + a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897); + d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426); + c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341); + b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983); + a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416); + d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417); + c = md5_ff(c, d, a, b, x[i + 10], 17, -42063); + b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162); + a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682); + d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101); + c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290); + b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329); + + a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510); + d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632); + c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713); + b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302); + a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691); + d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083); + c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335); + b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848); + a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438); + d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690); + c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961); + b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501); + a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467); + d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784); + c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473); + b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734); + + a = md5_hh(a, b, c, d, x[i + 5], 4, -378558); + d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463); + c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562); + b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556); + a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060); + d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353); + c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632); + b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640); + a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174); + d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222); + c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979); + b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189); + a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487); + d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835); + c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520); + b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651); + + a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844); + d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415); + c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905); + b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055); + a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571); + d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606); + c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523); + b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799); + a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359); + d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744); + c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380); + b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649); + a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070); + d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379); + c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259); + b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551); + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + } - return newBuf -} + return [a, b, c, d]; + } -/* - * Need to make sure that buffer isn't trying to write out of bounds. + /* + * These functions implement the four basic operations the algorithm uses. */ -function checkOffset (offset, ext, length) { - if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') - if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') -} - -Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) + function md5_cmn(q, a, b, x, s, t) { + return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b); + } - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } + function md5_ff(a, b, c, d, x, s, t) { + return md5_cmn((b & c) | (~b & d), a, b, x, s, t); + } - return val -} + function md5_gg(a, b, c, d, x, s, t) { + return md5_cmn((b & d) | (c & ~d), a, b, x, s, t); + } -Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - checkOffset(offset, byteLength, this.length) - } + function md5_hh(a, b, c, d, x, s, t) { + return md5_cmn(b ^ c ^ d, a, b, x, s, t); + } - var val = this[offset + --byteLength] - var mul = 1 - while (byteLength > 0 && (mul *= 0x100)) { - val += this[offset + --byteLength] * mul - } + function md5_ii(a, b, c, d, x, s, t) { + return md5_cmn(c ^ (b | ~d), a, b, x, s, t); + } - return val -} + /* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ + function safe_add(x, y) { + var lsw = (x & 0xffff) + (y & 0xffff); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xffff); + } -Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - return this[offset] -} + /* + * Bitwise rotate a 32-bit number to the left. + */ + function bit_rol(num, cnt) { + return (num << cnt) | (num >>> (32 - cnt)); + } -Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return this[offset] | (this[offset + 1] << 8) -} + module.exports = function md5(buf) { + return makeHash(buf, core_md5); + }; + }, + { './make-hash': 135 }, + ], + 137: [ + function(require, module, exports) { + 'use strict'; + var inherits = require('inherits'); + var Legacy = require('./legacy'); + var Base = require('cipher-base'); + var Buffer = require('safe-buffer').Buffer; + var md5 = require('create-hash/md5'); + var RIPEMD160 = require('ripemd160'); + + var sha = require('sha.js'); + + var ZEROS = Buffer.alloc(128); + + function Hmac(alg, key) { + Base.call(this, 'digest'); + if (typeof key === 'string') { + key = Buffer.from(key); + } -Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return (this[offset] << 8) | this[offset + 1] -} + var blocksize = alg === 'sha512' || alg === 'sha384' ? 128 : 64; -Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) + this._alg = alg; + this._key = key; + if (key.length > blocksize) { + var hash = alg === 'rmd160' ? new RIPEMD160() : sha(alg); + key = hash.update(key).digest(); + } else if (key.length < blocksize) { + key = Buffer.concat([key, ZEROS], blocksize); + } - return ((this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16)) + - (this[offset + 3] * 0x1000000) -} + var ipad = (this._ipad = Buffer.allocUnsafe(blocksize)); + var opad = (this._opad = Buffer.allocUnsafe(blocksize)); -Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) + for (var i = 0; i < blocksize; i++) { + ipad[i] = key[i] ^ 0x36; + opad[i] = key[i] ^ 0x5c; + } + this._hash = alg === 'rmd160' ? new RIPEMD160() : sha(alg); + this._hash.update(ipad); + } - return (this[offset] * 0x1000000) + - ((this[offset + 1] << 16) | - (this[offset + 2] << 8) | - this[offset + 3]) -} + inherits(Hmac, Base); -Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) + Hmac.prototype._update = function(data) { + this._hash.update(data); + }; - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - mul *= 0x80 + Hmac.prototype._final = function() { + var h = this._hash.digest(); + var hash = this._alg === 'rmd160' ? new RIPEMD160() : sha(this._alg); + return hash + .update(this._opad) + .update(h) + .digest(); + }; - if (val >= mul) val -= Math.pow(2, 8 * byteLength) + module.exports = function createHmac(alg, key) { + alg = alg.toLowerCase(); + if (alg === 'rmd160' || alg === 'ripemd160') { + return new Hmac('rmd160', key); + } + if (alg === 'md5') { + return new Legacy(md5, key); + } + return new Hmac(alg, key); + }; + }, + { + './legacy': 138, + 'cipher-base': 114, + 'create-hash/md5': 136, + inherits: 184, + ripemd160: 232, + 'safe-buffer': 233, + 'sha.js': 235, + }, + ], + 138: [ + function(require, module, exports) { + 'use strict'; + var inherits = require('inherits'); + var Buffer = require('safe-buffer').Buffer; + + var Base = require('cipher-base'); + + var ZEROS = Buffer.alloc(128); + var blocksize = 64; + + function Hmac(alg, key) { + Base.call(this, 'digest'); + if (typeof key === 'string') { + key = Buffer.from(key); + } - return val -} + this._alg = alg; + this._key = key; -Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) + if (key.length > blocksize) { + key = alg(key); + } else if (key.length < blocksize) { + key = Buffer.concat([key, ZEROS], blocksize); + } - var i = byteLength - var mul = 1 - var val = this[offset + --i] - while (i > 0 && (mul *= 0x100)) { - val += this[offset + --i] * mul - } - mul *= 0x80 + var ipad = (this._ipad = Buffer.allocUnsafe(blocksize)); + var opad = (this._opad = Buffer.allocUnsafe(blocksize)); - if (val >= mul) val -= Math.pow(2, 8 * byteLength) + for (var i = 0; i < blocksize; i++) { + ipad[i] = key[i] ^ 0x36; + opad[i] = key[i] ^ 0x5c; + } - return val -} + this._hash = [ipad]; + } -Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - if (!(this[offset] & 0x80)) return (this[offset]) - return ((0xff - this[offset] + 1) * -1) -} + inherits(Hmac, Base); -Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset] | (this[offset + 1] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} + Hmac.prototype._update = function(data) { + this._hash.push(data); + }; -Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset + 1] | (this[offset] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} + Hmac.prototype._final = function() { + var h = this._alg(Buffer.concat(this._hash)); + return this._alg(Buffer.concat([this._opad, h])); + }; + module.exports = Hmac; + }, + { 'cipher-base': 114, inherits: 184, 'safe-buffer': 233 }, + ], + 139: [ + function(require, module, exports) { + 'use strict'; + + exports.randomBytes = exports.rng = exports.pseudoRandomBytes = exports.prng = require('randombytes'); + exports.createHash = exports.Hash = require('create-hash'); + exports.createHmac = exports.Hmac = require('create-hmac'); + + var algos = require('browserify-sign/algos'); + var algoKeys = Object.keys(algos); + var hashes = ['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'md5', 'rmd160'].concat(algoKeys); + exports.getHashes = function() { + return hashes; + }; -Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) + var p = require('pbkdf2'); + exports.pbkdf2 = p.pbkdf2; + exports.pbkdf2Sync = p.pbkdf2Sync; + + var aes = require('browserify-cipher'); + + exports.Cipher = aes.Cipher; + exports.createCipher = aes.createCipher; + exports.Cipheriv = aes.Cipheriv; + exports.createCipheriv = aes.createCipheriv; + exports.Decipher = aes.Decipher; + exports.createDecipher = aes.createDecipher; + exports.Decipheriv = aes.Decipheriv; + exports.createDecipheriv = aes.createDecipheriv; + exports.getCiphers = aes.getCiphers; + exports.listCiphers = aes.listCiphers; + + var dh = require('diffie-hellman'); + + exports.DiffieHellmanGroup = dh.DiffieHellmanGroup; + exports.createDiffieHellmanGroup = dh.createDiffieHellmanGroup; + exports.getDiffieHellman = dh.getDiffieHellman; + exports.createDiffieHellman = dh.createDiffieHellman; + exports.DiffieHellman = dh.DiffieHellman; + + var sign = require('browserify-sign'); + + exports.createSign = sign.createSign; + exports.Sign = sign.Sign; + exports.createVerify = sign.createVerify; + exports.Verify = sign.Verify; + + exports.createECDH = require('create-ecdh'); + + var publicEncrypt = require('public-encrypt'); + + exports.publicEncrypt = publicEncrypt.publicEncrypt; + exports.privateEncrypt = publicEncrypt.privateEncrypt; + exports.publicDecrypt = publicEncrypt.publicDecrypt; + exports.privateDecrypt = publicEncrypt.privateDecrypt; + + // the least I can do is make error messages for the rest of the node.js/crypto api. + // ;[ + // 'createCredentials' + // ].forEach(function (name) { + // exports[name] = function () { + // throw new Error([ + // 'sorry, ' + name + ' is not implemented yet', + // 'we accept pull requests', + // 'https://github.com/crypto-browserify/crypto-browserify' + // ].join('\n')) + // } + // }) + + exports.createCredentials = function() { + throw new Error( + [ + 'sorry, createCredentials is not implemented yet', + 'we accept pull requests', + 'https://github.com/crypto-browserify/crypto-browserify', + ].join('\n'), + ); + }; - return (this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16) | - (this[offset + 3] << 24) -} + exports.constants = { + DH_CHECK_P_NOT_SAFE_PRIME: 2, + DH_CHECK_P_NOT_PRIME: 1, + DH_UNABLE_TO_CHECK_GENERATOR: 4, + DH_NOT_SUITABLE_GENERATOR: 8, + NPN_ENABLED: 1, + ALPN_ENABLED: 1, + RSA_PKCS1_PADDING: 1, + RSA_SSLV23_PADDING: 2, + RSA_NO_PADDING: 3, + RSA_PKCS1_OAEP_PADDING: 4, + RSA_X931_PADDING: 5, + RSA_PKCS1_PSS_PADDING: 6, + POINT_CONVERSION_COMPRESSED: 2, + POINT_CONVERSION_UNCOMPRESSED: 4, + POINT_CONVERSION_HYBRID: 6, + }; + }, + { + 'browserify-cipher': 81, + 'browserify-sign': 89, + 'browserify-sign/algos': 86, + 'create-ecdh': 116, + 'create-hash': 134, + 'create-hmac': 137, + 'diffie-hellman': 146, + pbkdf2: 199, + 'public-encrypt': 206, + randombytes: 217, + }, + ], + 140: [ + function(require, module, exports) { + 'use strict'; + + exports.utils = require('./des/utils'); + exports.Cipher = require('./des/cipher'); + exports.DES = require('./des/des'); + exports.CBC = require('./des/cbc'); + exports.EDE = require('./des/ede'); + }, + { './des/cbc': 141, './des/cipher': 142, './des/des': 143, './des/ede': 144, './des/utils': 145 }, + ], + 141: [ + function(require, module, exports) { + 'use strict'; -Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) + var assert = require('minimalistic-assert'); + var inherits = require('inherits'); - return (this[offset] << 24) | - (this[offset + 1] << 16) | - (this[offset + 2] << 8) | - (this[offset + 3]) -} + var proto = {}; -Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, true, 23, 4) -} + function CBCState(iv) { + assert.equal(iv.length, 8, 'Invalid IV length'); -Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, false, 23, 4) -} + this.iv = new Array(8); + for (var i = 0; i < this.iv.length; i++) this.iv[i] = iv[i]; + } -Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, true, 52, 8) -} + function instantiate(Base) { + function CBC(options) { + Base.call(this, options); + this._cbcInit(); + } + inherits(CBC, Base); -Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, false, 52, 8) -} + var keys = Object.keys(proto); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + CBC.prototype[key] = proto[key]; + } -function checkInt (buf, value, offset, ext, max, min) { - if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') - if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') - if (offset + ext > buf.length) throw new RangeError('Index out of range') -} + CBC.create = function create(options) { + return new CBC(options); + }; -Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } + return CBC; + } - var mul = 1 - var i = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } + exports.instantiate = instantiate; - return offset + byteLength -} + proto._cbcInit = function _cbcInit() { + var state = new CBCState(this.options.iv); + this._cbcState = state; + }; -Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } + proto._update = function _update(inp, inOff, out, outOff) { + var state = this._cbcState; + var superProto = this.constructor.super_.prototype; - var i = byteLength - 1 - var mul = 1 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } + var iv = state.iv; + if (this.type === 'encrypt') { + for (var i = 0; i < this.blockSize; i++) iv[i] ^= inp[inOff + i]; - return offset + byteLength -} + superProto._update.call(this, iv, 0, out, outOff); -Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - this[offset] = (value & 0xff) - return offset + 1 -} + for (var i = 0; i < this.blockSize; i++) iv[i] = out[outOff + i]; + } else { + superProto._update.call(this, inp, inOff, out, outOff); -function objectWriteUInt16 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) { - buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> - (littleEndian ? i : 1 - i) * 8 - } -} + for (var i = 0; i < this.blockSize; i++) out[outOff + i] ^= iv[i]; -Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 -} + for (var i = 0; i < this.blockSize; i++) iv[i] = inp[inOff + i]; + } + }; + }, + { inherits: 184, 'minimalistic-assert': 192 }, + ], + 142: [ + function(require, module, exports) { + 'use strict'; -Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 -} + var assert = require('minimalistic-assert'); -function objectWriteUInt32 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffffffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) { - buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff - } -} + function Cipher(options) { + this.options = options; -Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset + 3] = (value >>> 24) - this[offset + 2] = (value >>> 16) - this[offset + 1] = (value >>> 8) - this[offset] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 -} + this.type = this.options.type; + this.blockSize = 8; + this._init(); -Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 -} + this.buffer = new Array(this.blockSize); + this.bufferOff = 0; + } + module.exports = Cipher; -Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) + Cipher.prototype._init = function _init() { + // Might be overrided + }; - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } + Cipher.prototype.update = function update(data) { + if (data.length === 0) return []; - var i = 0 - var mul = 1 - var sub = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { - sub = 1 - } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } + if (this.type === 'decrypt') return this._updateDecrypt(data); + else return this._updateEncrypt(data); + }; - return offset + byteLength -} + Cipher.prototype._buffer = function _buffer(data, off) { + // Append data to buffer + var min = Math.min(this.buffer.length - this.bufferOff, data.length - off); + for (var i = 0; i < min; i++) this.buffer[this.bufferOff + i] = data[off + i]; + this.bufferOff += min; -Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) + // Shift next + return min; + }; - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } + Cipher.prototype._flushBuffer = function _flushBuffer(out, off) { + this._update(this.buffer, 0, out, off); + this.bufferOff = 0; + return this.blockSize; + }; - var i = byteLength - 1 - var mul = 1 - var sub = 0 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { - sub = 1 - } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } + Cipher.prototype._updateEncrypt = function _updateEncrypt(data) { + var inputOff = 0; + var outputOff = 0; - return offset + byteLength -} + var count = ((this.bufferOff + data.length) / this.blockSize) | 0; + var out = new Array(count * this.blockSize); -Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - if (value < 0) value = 0xff + value + 1 - this[offset] = (value & 0xff) - return offset + 1 -} + if (this.bufferOff !== 0) { + inputOff += this._buffer(data, inputOff); -Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 -} + if (this.bufferOff === this.buffer.length) outputOff += this._flushBuffer(out, outputOff); + } -Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 -} + // Write blocks + var max = data.length - ((data.length - inputOff) % this.blockSize); + for (; inputOff < max; inputOff += this.blockSize) { + this._update(data, inputOff, out, outputOff); + outputOff += this.blockSize; + } -Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - this[offset + 2] = (value >>> 16) - this[offset + 3] = (value >>> 24) - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 -} + // Queue rest + for (; inputOff < data.length; inputOff++, this.bufferOff++) this.buffer[this.bufferOff] = data[inputOff]; -Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (value < 0) value = 0xffffffff + value + 1 - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 -} + return out; + }; -function checkIEEE754 (buf, value, offset, ext, max, min) { - if (offset + ext > buf.length) throw new RangeError('Index out of range') - if (offset < 0) throw new RangeError('Index out of range') -} + Cipher.prototype._updateDecrypt = function _updateDecrypt(data) { + var inputOff = 0; + var outputOff = 0; -function writeFloat (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) - } - ieee754.write(buf, value, offset, littleEndian, 23, 4) - return offset + 4 -} + var count = Math.ceil((this.bufferOff + data.length) / this.blockSize) - 1; + var out = new Array(count * this.blockSize); -Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { - return writeFloat(this, value, offset, true, noAssert) -} + // TODO(indutny): optimize it, this is far from optimal + for (; count > 0; count--) { + inputOff += this._buffer(data, inputOff); + outputOff += this._flushBuffer(out, outputOff); + } -Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { - return writeFloat(this, value, offset, false, noAssert) -} + // Buffer rest of the input + inputOff += this._buffer(data, inputOff); -function writeDouble (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) - } - ieee754.write(buf, value, offset, littleEndian, 52, 8) - return offset + 8 -} + return out; + }; -Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { - return writeDouble(this, value, offset, true, noAssert) -} + Cipher.prototype.final = function final(buffer) { + var first; + if (buffer) first = this.update(buffer); -Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { - return writeDouble(this, value, offset, false, noAssert) -} + var last; + if (this.type === 'encrypt') last = this._finalEncrypt(); + else last = this._finalDecrypt(); -// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) -Buffer.prototype.copy = function copy (target, targetStart, start, end) { - if (!start) start = 0 - if (!end && end !== 0) end = this.length - if (targetStart >= target.length) targetStart = target.length - if (!targetStart) targetStart = 0 - if (end > 0 && end < start) end = start - - // Copy 0 bytes; we're done - if (end === start) return 0 - if (target.length === 0 || this.length === 0) return 0 - - // Fatal error conditions - if (targetStart < 0) { - throw new RangeError('targetStart out of bounds') - } - if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') - if (end < 0) throw new RangeError('sourceEnd out of bounds') + if (first) return first.concat(last); + else return last; + }; - // Are we oob? - if (end > this.length) end = this.length - if (target.length - targetStart < end - start) { - end = target.length - targetStart + start - } + Cipher.prototype._pad = function _pad(buffer, off) { + if (off === 0) return false; - var len = end - start - var i + while (off < buffer.length) buffer[off++] = 0; - if (this === target && start < targetStart && targetStart < end) { - // descending copy from end - for (i = len - 1; i >= 0; --i) { - target[i + targetStart] = this[i + start] - } - } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { - // ascending copy from start - for (i = 0; i < len; ++i) { - target[i + targetStart] = this[i + start] - } - } else { - Uint8Array.prototype.set.call( - target, - this.subarray(start, start + len), - targetStart - ) - } + return true; + }; - return len -} + Cipher.prototype._finalEncrypt = function _finalEncrypt() { + if (!this._pad(this.buffer, this.bufferOff)) return []; -// Usage: -// buffer.fill(number[, offset[, end]]) -// buffer.fill(buffer[, offset[, end]]) -// buffer.fill(string[, offset[, end]][, encoding]) -Buffer.prototype.fill = function fill (val, start, end, encoding) { - // Handle string cases: - if (typeof val === 'string') { - if (typeof start === 'string') { - encoding = start - start = 0 - end = this.length - } else if (typeof end === 'string') { - encoding = end - end = this.length - } - if (val.length === 1) { - var code = val.charCodeAt(0) - if (code < 256) { - val = code - } - } - if (encoding !== undefined && typeof encoding !== 'string') { - throw new TypeError('encoding must be a string') - } - if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { - throw new TypeError('Unknown encoding: ' + encoding) - } - } else if (typeof val === 'number') { - val = val & 255 - } + var out = new Array(this.blockSize); + this._update(this.buffer, 0, out, 0); + return out; + }; - // Invalid ranges are not set to a default, so can range check early. - if (start < 0 || this.length < start || this.length < end) { - throw new RangeError('Out of range index') - } + Cipher.prototype._unpad = function _unpad(buffer) { + return buffer; + }; - if (end <= start) { - return this - } + Cipher.prototype._finalDecrypt = function _finalDecrypt() { + assert.equal(this.bufferOff, this.blockSize, 'Not enough data to decrypt'); + var out = new Array(this.blockSize); + this._flushBuffer(out, 0); - start = start >>> 0 - end = end === undefined ? this.length : end >>> 0 + return this._unpad(out); + }; + }, + { 'minimalistic-assert': 192 }, + ], + 143: [ + function(require, module, exports) { + 'use strict'; + + var assert = require('minimalistic-assert'); + var inherits = require('inherits'); + + var des = require('../des'); + var utils = des.utils; + var Cipher = des.Cipher; + + function DESState() { + this.tmp = new Array(2); + this.keys = null; + } - if (!val) val = 0 + function DES(options) { + Cipher.call(this, options); - var i - if (typeof val === 'number') { - for (i = start; i < end; ++i) { - this[i] = val - } - } else { - var bytes = Buffer.isBuffer(val) - ? val - : utf8ToBytes(new Buffer(val, encoding).toString()) - var len = bytes.length - for (i = 0; i < end - start; ++i) { - this[i + start] = bytes[i % len] - } - } + var state = new DESState(); + this._desState = state; - return this -} + this.deriveKeys(state, options.key); + } + inherits(DES, Cipher); + module.exports = DES; -// HELPER FUNCTIONS -// ================ + DES.create = function create(options) { + return new DES(options); + }; -var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g + var shiftTable = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]; -function base64clean (str) { - // Node strips out invalid characters like \n and \t from the string, base64-js does not - str = stringtrim(str).replace(INVALID_BASE64_RE, '') - // Node converts strings with length < 2 to '' - if (str.length < 2) return '' - // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not - while (str.length % 4 !== 0) { - str = str + '=' - } - return str -} + DES.prototype.deriveKeys = function deriveKeys(state, key) { + state.keys = new Array(16 * 2); -function stringtrim (str) { - if (str.trim) return str.trim() - return str.replace(/^\s+|\s+$/g, '') -} + assert.equal(key.length, this.blockSize, 'Invalid key length'); -function toHex (n) { - if (n < 16) return '0' + n.toString(16) - return n.toString(16) -} + var kL = utils.readUInt32BE(key, 0); + var kR = utils.readUInt32BE(key, 4); -function utf8ToBytes (string, units) { - units = units || Infinity - var codePoint - var length = string.length - var leadSurrogate = null - var bytes = [] - - for (var i = 0; i < length; ++i) { - codePoint = string.charCodeAt(i) - - // is surrogate component - if (codePoint > 0xD7FF && codePoint < 0xE000) { - // last char was a lead - if (!leadSurrogate) { - // no lead yet - if (codePoint > 0xDBFF) { - // unexpected trail - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } else if (i + 1 === length) { - // unpaired lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } - - // valid lead - leadSurrogate = codePoint - - continue - } + utils.pc1(kL, kR, state.tmp, 0); + kL = state.tmp[0]; + kR = state.tmp[1]; + for (var i = 0; i < state.keys.length; i += 2) { + var shift = shiftTable[i >>> 1]; + kL = utils.r28shl(kL, shift); + kR = utils.r28shl(kR, shift); + utils.pc2(kL, kR, state.keys, i); + } + }; - // 2 leads in a row - if (codePoint < 0xDC00) { - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - leadSurrogate = codePoint - continue - } + DES.prototype._update = function _update(inp, inOff, out, outOff) { + var state = this._desState; - // valid surrogate pair - codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 - } else if (leadSurrogate) { - // valid bmp char, but last char was a lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - } + var l = utils.readUInt32BE(inp, inOff); + var r = utils.readUInt32BE(inp, inOff + 4); - leadSurrogate = null - - // encode utf8 - if (codePoint < 0x80) { - if ((units -= 1) < 0) break - bytes.push(codePoint) - } else if (codePoint < 0x800) { - if ((units -= 2) < 0) break - bytes.push( - codePoint >> 0x6 | 0xC0, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x10000) { - if ((units -= 3) < 0) break - bytes.push( - codePoint >> 0xC | 0xE0, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x110000) { - if ((units -= 4) < 0) break - bytes.push( - codePoint >> 0x12 | 0xF0, - codePoint >> 0xC & 0x3F | 0x80, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else { - throw new Error('Invalid code point') - } - } + // Initial Permutation + utils.ip(l, r, state.tmp, 0); + l = state.tmp[0]; + r = state.tmp[1]; - return bytes -} + if (this.type === 'encrypt') this._encrypt(state, l, r, state.tmp, 0); + else this._decrypt(state, l, r, state.tmp, 0); -function asciiToBytes (str) { - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - // Node's code seems to be doing this and not & 0x7F.. - byteArray.push(str.charCodeAt(i) & 0xFF) - } - return byteArray -} + l = state.tmp[0]; + r = state.tmp[1]; -function utf16leToBytes (str, units) { - var c, hi, lo - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - if ((units -= 2) < 0) break - - c = str.charCodeAt(i) - hi = c >> 8 - lo = c % 256 - byteArray.push(lo) - byteArray.push(hi) - } + utils.writeUInt32BE(out, l, outOff); + utils.writeUInt32BE(out, r, outOff + 4); + }; - return byteArray -} + DES.prototype._pad = function _pad(buffer, off) { + var value = buffer.length - off; + for (var i = off; i < buffer.length; i++) buffer[i] = value; -function base64ToBytes (str) { - return base64.toByteArray(base64clean(str)) -} + return true; + }; -function blitBuffer (src, dst, offset, length) { - for (var i = 0; i < length; ++i) { - if ((i + offset >= dst.length) || (i >= src.length)) break - dst[i + offset] = src[i] - } - return i -} + DES.prototype._unpad = function _unpad(buffer) { + var pad = buffer[buffer.length - 1]; + for (var i = buffer.length - pad; i < buffer.length; i++) assert.equal(buffer[i], pad); -function isnan (val) { - return val !== val // eslint-disable-line no-self-compare -} + return buffer.slice(0, buffer.length - pad); + }; -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"base64-js":61,"ieee754":182,"isarray":186}],114:[function(require,module,exports){ -var Buffer = require('safe-buffer').Buffer -var Transform = require('stream').Transform -var StringDecoder = require('string_decoder').StringDecoder -var inherits = require('inherits') - -function CipherBase (hashMode) { - Transform.call(this) - this.hashMode = typeof hashMode === 'string' - if (this.hashMode) { - this[hashMode] = this._finalOrDigest - } else { - this.final = this._finalOrDigest - } - if (this._final) { - this.__final = this._final - this._final = null - } - this._decoder = null - this._encoding = null -} -inherits(CipherBase, Transform) + DES.prototype._encrypt = function _encrypt(state, lStart, rStart, out, off) { + var l = lStart; + var r = rStart; -CipherBase.prototype.update = function (data, inputEnc, outputEnc) { - if (typeof data === 'string') { - data = Buffer.from(data, inputEnc) - } + // Apply f() x16 times + for (var i = 0; i < state.keys.length; i += 2) { + var keyL = state.keys[i]; + var keyR = state.keys[i + 1]; - var outData = this._update(data) - if (this.hashMode) return this + // f(r, k) + utils.expand(r, state.tmp, 0); - if (outputEnc) { - outData = this._toString(outData, outputEnc) - } + keyL ^= state.tmp[0]; + keyR ^= state.tmp[1]; + var s = utils.substitute(keyL, keyR); + var f = utils.permute(s); - return outData -} + var t = r; + r = (l ^ f) >>> 0; + l = t; + } -CipherBase.prototype.setAutoPadding = function () {} -CipherBase.prototype.getAuthTag = function () { - throw new Error('trying to get auth tag in unsupported state') -} + // Reverse Initial Permutation + utils.rip(r, l, out, off); + }; -CipherBase.prototype.setAuthTag = function () { - throw new Error('trying to set auth tag in unsupported state') -} + DES.prototype._decrypt = function _decrypt(state, lStart, rStart, out, off) { + var l = rStart; + var r = lStart; -CipherBase.prototype.setAAD = function () { - throw new Error('trying to set aad in unsupported state') -} + // Apply f() x16 times + for (var i = state.keys.length - 2; i >= 0; i -= 2) { + var keyL = state.keys[i]; + var keyR = state.keys[i + 1]; -CipherBase.prototype._transform = function (data, _, next) { - var err - try { - if (this.hashMode) { - this._update(data) - } else { - this.push(this._update(data)) - } - } catch (e) { - err = e - } finally { - next(err) - } -} -CipherBase.prototype._flush = function (done) { - var err - try { - this.push(this.__final()) - } catch (e) { - err = e - } + // f(r, k) + utils.expand(l, state.tmp, 0); - done(err) -} -CipherBase.prototype._finalOrDigest = function (outputEnc) { - var outData = this.__final() || Buffer.alloc(0) - if (outputEnc) { - outData = this._toString(outData, outputEnc, true) - } - return outData -} + keyL ^= state.tmp[0]; + keyR ^= state.tmp[1]; + var s = utils.substitute(keyL, keyR); + var f = utils.permute(s); -CipherBase.prototype._toString = function (value, enc, fin) { - if (!this._decoder) { - this._decoder = new StringDecoder(enc) - this._encoding = enc - } + var t = l; + l = (r ^ f) >>> 0; + r = t; + } - if (this._encoding !== enc) throw new Error('can\'t switch encodings') + // Reverse Initial Permutation + utils.rip(l, r, out, off); + }; + }, + { '../des': 140, inherits: 184, 'minimalistic-assert': 192 }, + ], + 144: [ + function(require, module, exports) { + 'use strict'; + + var assert = require('minimalistic-assert'); + var inherits = require('inherits'); + + var des = require('../des'); + var Cipher = des.Cipher; + var DES = des.DES; + + function EDEState(type, key) { + assert.equal(key.length, 24, 'Invalid key length'); + + var k1 = key.slice(0, 8); + var k2 = key.slice(8, 16); + var k3 = key.slice(16, 24); + + if (type === 'encrypt') { + this.ciphers = [ + DES.create({ type: 'encrypt', key: k1 }), + DES.create({ type: 'decrypt', key: k2 }), + DES.create({ type: 'encrypt', key: k3 }), + ]; + } else { + this.ciphers = [ + DES.create({ type: 'decrypt', key: k3 }), + DES.create({ type: 'encrypt', key: k2 }), + DES.create({ type: 'decrypt', key: k1 }), + ]; + } + } - var out = this._decoder.write(value) - if (fin) { - out += this._decoder.end() - } + function EDE(options) { + Cipher.call(this, options); - return out -} + var state = new EDEState(this.type, this.options.key); + this._edeState = state; + } + inherits(EDE, Cipher); -module.exports = CipherBase - -},{"inherits":184,"safe-buffer":233,"stream":242,"string_decoder":109}],115:[function(require,module,exports){ -(function (Buffer){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. - -function isArray(arg) { - if (Array.isArray) { - return Array.isArray(arg); - } - return objectToString(arg) === '[object Array]'; -} -exports.isArray = isArray; + module.exports = EDE; -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; + EDE.create = function create(options) { + return new EDE(options); + }; -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; + EDE.prototype._update = function _update(inp, inOff, out, outOff) { + var state = this._edeState; -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; + state.ciphers[0]._update(inp, inOff, out, outOff); + state.ciphers[1]._update(out, outOff, out, outOff); + state.ciphers[2]._update(out, outOff, out, outOff); + }; -function isNumber(arg) { - return typeof arg === 'number'; -} -exports.isNumber = isNumber; + EDE.prototype._pad = DES.prototype._pad; + EDE.prototype._unpad = DES.prototype._unpad; + }, + { '../des': 140, inherits: 184, 'minimalistic-assert': 192 }, + ], + 145: [ + function(require, module, exports) { + 'use strict'; + + exports.readUInt32BE = function readUInt32BE(bytes, off) { + var res = (bytes[0 + off] << 24) | (bytes[1 + off] << 16) | (bytes[2 + off] << 8) | bytes[3 + off]; + return res >>> 0; + }; -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; + exports.writeUInt32BE = function writeUInt32BE(bytes, value, off) { + bytes[0 + off] = value >>> 24; + bytes[1 + off] = (value >>> 16) & 0xff; + bytes[2 + off] = (value >>> 8) & 0xff; + bytes[3 + off] = value & 0xff; + }; -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; + exports.ip = function ip(inL, inR, out, off) { + var outL = 0; + var outR = 0; -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; + for (var i = 6; i >= 0; i -= 2) { + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inR >>> (j + i)) & 1; + } + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inL >>> (j + i)) & 1; + } + } -function isRegExp(re) { - return objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; + for (var i = 6; i >= 0; i -= 2) { + for (var j = 1; j <= 25; j += 8) { + outR <<= 1; + outR |= (inR >>> (j + i)) & 1; + } + for (var j = 1; j <= 25; j += 8) { + outR <<= 1; + outR |= (inL >>> (j + i)) & 1; + } + } -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; + }; -function isDate(d) { - return objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; + exports.rip = function rip(inL, inR, out, off) { + var outL = 0; + var outR = 0; -function isError(e) { - return (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; + for (var i = 0; i < 4; i++) { + for (var j = 24; j >= 0; j -= 8) { + outL <<= 1; + outL |= (inR >>> (j + i)) & 1; + outL <<= 1; + outL |= (inL >>> (j + i)) & 1; + } + } + for (var i = 4; i < 8; i++) { + for (var j = 24; j >= 0; j -= 8) { + outR <<= 1; + outR |= (inR >>> (j + i)) & 1; + outR <<= 1; + outR |= (inL >>> (j + i)) & 1; + } + } -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; - -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; + }; -exports.isBuffer = Buffer.isBuffer; + exports.pc1 = function pc1(inL, inR, out, off) { + var outL = 0; + var outR = 0; + + // 7, 15, 23, 31, 39, 47, 55, 63 + // 6, 14, 22, 30, 39, 47, 55, 63 + // 5, 13, 21, 29, 39, 47, 55, 63 + // 4, 12, 20, 28 + for (var i = 7; i >= 5; i--) { + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inR >> (j + i)) & 1; + } + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inL >> (j + i)) & 1; + } + } + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inR >> (j + i)) & 1; + } -function objectToString(o) { - return Object.prototype.toString.call(o); -} + // 1, 9, 17, 25, 33, 41, 49, 57 + // 2, 10, 18, 26, 34, 42, 50, 58 + // 3, 11, 19, 27, 35, 43, 51, 59 + // 36, 44, 52, 60 + for (var i = 1; i <= 3; i++) { + for (var j = 0; j <= 24; j += 8) { + outR <<= 1; + outR |= (inR >> (j + i)) & 1; + } + for (var j = 0; j <= 24; j += 8) { + outR <<= 1; + outR |= (inL >> (j + i)) & 1; + } + } + for (var j = 0; j <= 24; j += 8) { + outR <<= 1; + outR |= (inL >> (j + i)) & 1; + } -}).call(this,{"isBuffer":require("../../is-buffer/index.js")}) -},{"../../is-buffer/index.js":185}],116:[function(require,module,exports){ -(function (Buffer){ -var elliptic = require('elliptic'); -var BN = require('bn.js'); - -module.exports = function createECDH(curve) { - return new ECDH(curve); -}; - -var aliases = { - secp256k1: { - name: 'secp256k1', - byteLength: 32 - }, - secp224r1: { - name: 'p224', - byteLength: 28 - }, - prime256v1: { - name: 'p256', - byteLength: 32 - }, - prime192v1: { - name: 'p192', - byteLength: 24 - }, - ed25519: { - name: 'ed25519', - byteLength: 32 - }, - secp384r1: { - name: 'p384', - byteLength: 48 - }, - secp521r1: { - name: 'p521', - byteLength: 66 - } -}; - -aliases.p224 = aliases.secp224r1; -aliases.p256 = aliases.secp256r1 = aliases.prime256v1; -aliases.p192 = aliases.secp192r1 = aliases.prime192v1; -aliases.p384 = aliases.secp384r1; -aliases.p521 = aliases.secp521r1; - -function ECDH(curve) { - this.curveType = aliases[curve]; - if (!this.curveType ) { - this.curveType = { - name: curve - }; - } - this.curve = new elliptic.ec(this.curveType.name); - this.keys = void 0; -} + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; + }; -ECDH.prototype.generateKeys = function (enc, format) { - this.keys = this.curve.genKeyPair(); - return this.getPublicKey(enc, format); -}; - -ECDH.prototype.computeSecret = function (other, inenc, enc) { - inenc = inenc || 'utf8'; - if (!Buffer.isBuffer(other)) { - other = new Buffer(other, inenc); - } - var otherPub = this.curve.keyFromPublic(other).getPublic(); - var out = otherPub.mul(this.keys.getPrivate()).getX(); - return formatReturnValue(out, enc, this.curveType.byteLength); -}; - -ECDH.prototype.getPublicKey = function (enc, format) { - var key = this.keys.getPublic(format === 'compressed', true); - if (format === 'hybrid') { - if (key[key.length - 1] % 2) { - key[0] = 7; - } else { - key [0] = 6; - } - } - return formatReturnValue(key, enc); -}; - -ECDH.prototype.getPrivateKey = function (enc) { - return formatReturnValue(this.keys.getPrivate(), enc); -}; - -ECDH.prototype.setPublicKey = function (pub, enc) { - enc = enc || 'utf8'; - if (!Buffer.isBuffer(pub)) { - pub = new Buffer(pub, enc); - } - this.keys._importPublic(pub); - return this; -}; - -ECDH.prototype.setPrivateKey = function (priv, enc) { - enc = enc || 'utf8'; - if (!Buffer.isBuffer(priv)) { - priv = new Buffer(priv, enc); - } - var _priv = new BN(priv); - _priv = _priv.toString(16); - this.keys._importPrivate(_priv); - return this; -}; - -function formatReturnValue(bn, enc, len) { - if (!Array.isArray(bn)) { - bn = bn.toArray(); - } - var buf = new Buffer(bn); - if (len && buf.length < len) { - var zeros = new Buffer(len - buf.length); - zeros.fill(0); - buf = Buffer.concat([zeros, buf]); - } - if (!enc) { - return buf; - } else { - return buf.toString(enc); - } -} + exports.r28shl = function r28shl(num, shift) { + return ((num << shift) & 0xfffffff) | (num >>> (28 - shift)); + }; -}).call(this,require("buffer").Buffer) -},{"bn.js":117,"buffer":113,"elliptic":118}],117:[function(require,module,exports){ -arguments[4][59][0].apply(exports,arguments) -},{"buffer":64,"dup":59}],118:[function(require,module,exports){ -arguments[4][93][0].apply(exports,arguments) -},{"../package.json":133,"./elliptic/curve":121,"./elliptic/curves":124,"./elliptic/ec":125,"./elliptic/eddsa":128,"./elliptic/utils":132,"brorand":63,"dup":93}],119:[function(require,module,exports){ -arguments[4][94][0].apply(exports,arguments) -},{"../../elliptic":118,"bn.js":117,"dup":94}],120:[function(require,module,exports){ -arguments[4][95][0].apply(exports,arguments) -},{"../../elliptic":118,"../curve":121,"bn.js":117,"dup":95,"inherits":184}],121:[function(require,module,exports){ -arguments[4][96][0].apply(exports,arguments) -},{"./base":119,"./edwards":120,"./mont":122,"./short":123,"dup":96}],122:[function(require,module,exports){ -arguments[4][97][0].apply(exports,arguments) -},{"../../elliptic":118,"../curve":121,"bn.js":117,"dup":97,"inherits":184}],123:[function(require,module,exports){ -arguments[4][98][0].apply(exports,arguments) -},{"../../elliptic":118,"../curve":121,"bn.js":117,"dup":98,"inherits":184}],124:[function(require,module,exports){ -arguments[4][99][0].apply(exports,arguments) -},{"../elliptic":118,"./precomputed/secp256k1":131,"dup":99,"hash.js":168}],125:[function(require,module,exports){ -arguments[4][100][0].apply(exports,arguments) -},{"../../elliptic":118,"./key":126,"./signature":127,"bn.js":117,"dup":100,"hmac-drbg":181}],126:[function(require,module,exports){ -arguments[4][101][0].apply(exports,arguments) -},{"../../elliptic":118,"bn.js":117,"dup":101}],127:[function(require,module,exports){ -arguments[4][102][0].apply(exports,arguments) -},{"../../elliptic":118,"bn.js":117,"dup":102}],128:[function(require,module,exports){ -arguments[4][103][0].apply(exports,arguments) -},{"../../elliptic":118,"./key":129,"./signature":130,"dup":103,"hash.js":168}],129:[function(require,module,exports){ -arguments[4][104][0].apply(exports,arguments) -},{"../../elliptic":118,"dup":104}],130:[function(require,module,exports){ -arguments[4][105][0].apply(exports,arguments) -},{"../../elliptic":118,"bn.js":117,"dup":105}],131:[function(require,module,exports){ -arguments[4][106][0].apply(exports,arguments) -},{"dup":106}],132:[function(require,module,exports){ -arguments[4][107][0].apply(exports,arguments) -},{"bn.js":117,"dup":107,"minimalistic-assert":192,"minimalistic-crypto-utils":193}],133:[function(require,module,exports){ -module.exports={ - "_args": [ - [ - "elliptic@6.4.0", - "/Users/tonypizzicato/dev/meritlabs/lightwallet-stack/packages/bitcore-lib" - ] - ], - "_from": "elliptic@6.4.0", - "_id": "elliptic@6.4.0", - "_inBundle": false, - "_integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", - "_location": "/create-ecdh/elliptic", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "elliptic@6.4.0", - "name": "elliptic", - "escapedName": "elliptic", - "rawSpec": "6.4.0", - "saveSpec": null, - "fetchSpec": "6.4.0" - }, - "_requiredBy": [ - "/create-ecdh" - ], - "_resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "_spec": "6.4.0", - "_where": "/Users/tonypizzicato/dev/meritlabs/lightwallet-stack/packages/bitcore-lib", - "author": { - "name": "Fedor Indutny", - "email": "fedor@indutny.com" - }, - "bugs": { - "url": "https://github.com/indutny/elliptic/issues" - }, - "dependencies": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - }, - "description": "EC cryptography", - "devDependencies": { - "brfs": "^1.4.3", - "grunt": "^0.4.5", - "grunt-browserify": "^5.0.0", - "grunt-cli": "^1.2.0", - "grunt-contrib-connect": "^1.0.0", - "grunt-contrib-copy": "^1.0.0", - "grunt-contrib-uglify": "^1.0.1", - "grunt-saucelabs": "^8.6.2", - "jscs": "^2.9.0", - "jshint": "^2.6.0", - "mocha": "^2.1.0" - }, - "files": [ - "lib" - ], - "homepage": "https://github.com/indutny/elliptic", - "keywords": [ - "EC", - "Elliptic", - "curve", - "Cryptography" - ], - "license": "MIT", - "main": "lib/elliptic.js", - "name": "elliptic", - "repository": { - "type": "git", - "url": "git+ssh://git@github.com/indutny/elliptic.git" - }, - "scripts": { - "jscs": "jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js", - "jshint": "jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js", - "lint": "npm run jscs && npm run jshint", - "test": "npm run lint && npm run unit", - "version": "grunt dist && git add dist/" - }, - "version": "6.4.0" -} + var pc2table = [ + // inL => outL + 14, + 11, + 17, + 4, + 27, + 23, + 25, + 0, + 13, + 22, + 7, + 18, + 5, + 9, + 16, + 24, + 2, + 20, + 12, + 21, + 1, + 8, + 15, + 26, + + // inR => outR + 15, + 4, + 25, + 19, + 9, + 1, + 26, + 16, + 5, + 11, + 23, + 8, + 12, + 7, + 17, + 0, + 22, + 3, + 10, + 14, + 6, + 20, + 27, + 24, + ]; + + exports.pc2 = function pc2(inL, inR, out, off) { + var outL = 0; + var outR = 0; + + var len = pc2table.length >>> 1; + for (var i = 0; i < len; i++) { + outL <<= 1; + outL |= (inL >>> pc2table[i]) & 0x1; + } + for (var i = len; i < pc2table.length; i++) { + outR <<= 1; + outR |= (inR >>> pc2table[i]) & 0x1; + } -},{}],134:[function(require,module,exports){ -(function (Buffer){ -'use strict' -var inherits = require('inherits') -var md5 = require('./md5') -var RIPEMD160 = require('ripemd160') -var sha = require('sha.js') + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; + }; -var Base = require('cipher-base') + exports.expand = function expand(r, out, off) { + var outL = 0; + var outR = 0; -function HashNoConstructor (hash) { - Base.call(this, 'digest') + outL = ((r & 1) << 5) | (r >>> 27); + for (var i = 23; i >= 15; i -= 4) { + outL <<= 6; + outL |= (r >>> i) & 0x3f; + } + for (var i = 11; i >= 3; i -= 4) { + outR |= (r >>> i) & 0x3f; + outR <<= 6; + } + outR |= ((r & 0x1f) << 1) | (r >>> 31); - this._hash = hash - this.buffers = [] -} + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; + }; -inherits(HashNoConstructor, Base) + var sTable = [ + 14, + 0, + 4, + 15, + 13, + 7, + 1, + 4, + 2, + 14, + 15, + 2, + 11, + 13, + 8, + 1, + 3, + 10, + 10, + 6, + 6, + 12, + 12, + 11, + 5, + 9, + 9, + 5, + 0, + 3, + 7, + 8, + 4, + 15, + 1, + 12, + 14, + 8, + 8, + 2, + 13, + 4, + 6, + 9, + 2, + 1, + 11, + 7, + 15, + 5, + 12, + 11, + 9, + 3, + 7, + 14, + 3, + 10, + 10, + 0, + 5, + 6, + 0, + 13, + + 15, + 3, + 1, + 13, + 8, + 4, + 14, + 7, + 6, + 15, + 11, + 2, + 3, + 8, + 4, + 14, + 9, + 12, + 7, + 0, + 2, + 1, + 13, + 10, + 12, + 6, + 0, + 9, + 5, + 11, + 10, + 5, + 0, + 13, + 14, + 8, + 7, + 10, + 11, + 1, + 10, + 3, + 4, + 15, + 13, + 4, + 1, + 2, + 5, + 11, + 8, + 6, + 12, + 7, + 6, + 12, + 9, + 0, + 3, + 5, + 2, + 14, + 15, + 9, + + 10, + 13, + 0, + 7, + 9, + 0, + 14, + 9, + 6, + 3, + 3, + 4, + 15, + 6, + 5, + 10, + 1, + 2, + 13, + 8, + 12, + 5, + 7, + 14, + 11, + 12, + 4, + 11, + 2, + 15, + 8, + 1, + 13, + 1, + 6, + 10, + 4, + 13, + 9, + 0, + 8, + 6, + 15, + 9, + 3, + 8, + 0, + 7, + 11, + 4, + 1, + 15, + 2, + 14, + 12, + 3, + 5, + 11, + 10, + 5, + 14, + 2, + 7, + 12, + + 7, + 13, + 13, + 8, + 14, + 11, + 3, + 5, + 0, + 6, + 6, + 15, + 9, + 0, + 10, + 3, + 1, + 4, + 2, + 7, + 8, + 2, + 5, + 12, + 11, + 1, + 12, + 10, + 4, + 14, + 15, + 9, + 10, + 3, + 6, + 15, + 9, + 0, + 0, + 6, + 12, + 10, + 11, + 1, + 7, + 13, + 13, + 8, + 15, + 9, + 1, + 4, + 3, + 5, + 14, + 11, + 5, + 12, + 2, + 7, + 8, + 2, + 4, + 14, + + 2, + 14, + 12, + 11, + 4, + 2, + 1, + 12, + 7, + 4, + 10, + 7, + 11, + 13, + 6, + 1, + 8, + 5, + 5, + 0, + 3, + 15, + 15, + 10, + 13, + 3, + 0, + 9, + 14, + 8, + 9, + 6, + 4, + 11, + 2, + 8, + 1, + 12, + 11, + 7, + 10, + 1, + 13, + 14, + 7, + 2, + 8, + 13, + 15, + 6, + 9, + 15, + 12, + 0, + 5, + 9, + 6, + 10, + 3, + 4, + 0, + 5, + 14, + 3, + + 12, + 10, + 1, + 15, + 10, + 4, + 15, + 2, + 9, + 7, + 2, + 12, + 6, + 9, + 8, + 5, + 0, + 6, + 13, + 1, + 3, + 13, + 4, + 14, + 14, + 0, + 7, + 11, + 5, + 3, + 11, + 8, + 9, + 4, + 14, + 3, + 15, + 2, + 5, + 12, + 2, + 9, + 8, + 5, + 12, + 15, + 3, + 10, + 7, + 11, + 0, + 14, + 4, + 1, + 10, + 7, + 1, + 6, + 13, + 0, + 11, + 8, + 6, + 13, + + 4, + 13, + 11, + 0, + 2, + 11, + 14, + 7, + 15, + 4, + 0, + 9, + 8, + 1, + 13, + 10, + 3, + 14, + 12, + 3, + 9, + 5, + 7, + 12, + 5, + 2, + 10, + 15, + 6, + 8, + 1, + 6, + 1, + 6, + 4, + 11, + 11, + 13, + 13, + 8, + 12, + 1, + 3, + 4, + 7, + 10, + 14, + 7, + 10, + 9, + 15, + 5, + 6, + 0, + 8, + 15, + 0, + 14, + 5, + 2, + 9, + 3, + 2, + 12, + + 13, + 1, + 2, + 15, + 8, + 13, + 4, + 8, + 6, + 10, + 15, + 3, + 11, + 7, + 1, + 4, + 10, + 12, + 9, + 5, + 3, + 6, + 14, + 11, + 5, + 0, + 0, + 14, + 12, + 9, + 7, + 2, + 7, + 2, + 11, + 1, + 4, + 14, + 1, + 7, + 9, + 4, + 12, + 10, + 14, + 8, + 2, + 13, + 0, + 15, + 6, + 12, + 10, + 9, + 13, + 0, + 15, + 3, + 3, + 5, + 5, + 6, + 8, + 11, + ]; + + exports.substitute = function substitute(inL, inR) { + var out = 0; + for (var i = 0; i < 4; i++) { + var b = (inL >>> (18 - i * 6)) & 0x3f; + var sb = sTable[i * 0x40 + b]; + + out <<= 4; + out |= sb; + } + for (var i = 0; i < 4; i++) { + var b = (inR >>> (18 - i * 6)) & 0x3f; + var sb = sTable[4 * 0x40 + i * 0x40 + b]; -HashNoConstructor.prototype._update = function (data) { - this.buffers.push(data) -} + out <<= 4; + out |= sb; + } + return out >>> 0; + }; -HashNoConstructor.prototype._final = function () { - var buf = Buffer.concat(this.buffers) - var r = this._hash(buf) - this.buffers = null + var permuteTable = [ + 16, + 25, + 12, + 11, + 3, + 20, + 4, + 15, + 31, + 17, + 9, + 6, + 27, + 14, + 1, + 22, + 30, + 24, + 8, + 18, + 0, + 5, + 29, + 23, + 13, + 19, + 2, + 26, + 10, + 21, + 28, + 7, + ]; + + exports.permute = function permute(num) { + var out = 0; + for (var i = 0; i < permuteTable.length; i++) { + out <<= 1; + out |= (num >>> permuteTable[i]) & 0x1; + } + return out >>> 0; + }; - return r -} + exports.padSplit = function padSplit(num, size, group) { + var str = num.toString(2); + while (str.length < size) str = '0' + str; -function Hash (hash) { - Base.call(this, 'digest') + var out = []; + for (var i = 0; i < size; i += group) out.push(str.slice(i, i + group)); + return out.join(' '); + }; + }, + {}, + ], + 146: [ + function(require, module, exports) { + (function(Buffer) { + var generatePrime = require('./lib/generatePrime'); + var primes = require('./lib/primes.json'); - this._hash = hash -} + var DH = require('./lib/dh'); -inherits(Hash, Base) + function getDiffieHellman(mod) { + var prime = new Buffer(primes[mod].prime, 'hex'); + var gen = new Buffer(primes[mod].gen, 'hex'); -Hash.prototype._update = function (data) { - this._hash.update(data) -} + return new DH(prime, gen); + } -Hash.prototype._final = function () { - return this._hash.digest() -} + var ENCODINGS = { + binary: true, + hex: true, + base64: true, + }; -module.exports = function createHash (alg) { - alg = alg.toLowerCase() - if (alg === 'md5') return new HashNoConstructor(md5) - if (alg === 'rmd160' || alg === 'ripemd160') return new Hash(new RIPEMD160()) + function createDiffieHellman(prime, enc, generator, genc) { + if (Buffer.isBuffer(enc) || ENCODINGS[enc] === undefined) { + return createDiffieHellman(prime, 'binary', enc, generator); + } - return new Hash(sha(alg)) -} + enc = enc || 'binary'; + genc = genc || 'binary'; + generator = generator || new Buffer([2]); -}).call(this,require("buffer").Buffer) -},{"./md5":136,"buffer":113,"cipher-base":114,"inherits":184,"ripemd160":232,"sha.js":235}],135:[function(require,module,exports){ -(function (Buffer){ -'use strict' -var intSize = 4 -var zeroBuffer = new Buffer(intSize) -zeroBuffer.fill(0) - -var charSize = 8 -var hashSize = 16 - -function toArray (buf) { - if ((buf.length % intSize) !== 0) { - var len = buf.length + (intSize - (buf.length % intSize)) - buf = Buffer.concat([buf, zeroBuffer], len) - } + if (!Buffer.isBuffer(generator)) { + generator = new Buffer(generator, genc); + } - var arr = new Array(buf.length >>> 2) - for (var i = 0, j = 0; i < buf.length; i += intSize, j++) { - arr[j] = buf.readInt32LE(i) - } + if (typeof prime === 'number') { + return new DH(generatePrime(prime, generator), generator, true); + } - return arr -} + if (!Buffer.isBuffer(prime)) { + prime = new Buffer(prime, enc); + } -module.exports = function hash (buf, fn) { - var arr = fn(toArray(buf), buf.length * charSize) - buf = new Buffer(hashSize) - for (var i = 0; i < arr.length; i++) { - buf.writeInt32LE(arr[i], i << 2, true) - } - return buf -} + return new DH(prime, generator, true); + } -}).call(this,require("buffer").Buffer) -},{"buffer":113}],136:[function(require,module,exports){ -'use strict' -/* - * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message - * Digest Algorithm, as defined in RFC 1321. - * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002. - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * Distributed under the BSD License - * See http://pajhome.org.uk/crypt/md5 for more info. - */ + exports.DiffieHellmanGroup = exports.createDiffieHellmanGroup = exports.getDiffieHellman = getDiffieHellman; + exports.createDiffieHellman = exports.DiffieHellman = createDiffieHellman; + }.call(this, require('buffer').Buffer)); + }, + { './lib/dh': 147, './lib/generatePrime': 148, './lib/primes.json': 149, buffer: 113 }, + ], + 147: [ + function(require, module, exports) { + (function(Buffer) { + var BN = require('bn.js'); + var MillerRabin = require('miller-rabin'); + var millerRabin = new MillerRabin(); + var TWENTYFOUR = new BN(24); + var ELEVEN = new BN(11); + var TEN = new BN(10); + var THREE = new BN(3); + var SEVEN = new BN(7); + var primes = require('./generatePrime'); + var randomBytes = require('randombytes'); + module.exports = DH; + + function setPublicKey(pub, enc) { + enc = enc || 'utf8'; + if (!Buffer.isBuffer(pub)) { + pub = new Buffer(pub, enc); + } + this._pub = new BN(pub); + return this; + } -var makeHash = require('./make-hash') + function setPrivateKey(priv, enc) { + enc = enc || 'utf8'; + if (!Buffer.isBuffer(priv)) { + priv = new Buffer(priv, enc); + } + this._priv = new BN(priv); + return this; + } -/* - * Calculate the MD5 of an array of little-endian words, and a bit length - */ -function core_md5 (x, len) { - /* append padding */ - x[len >> 5] |= 0x80 << ((len) % 32) - x[(((len + 64) >>> 9) << 4) + 14] = len - - var a = 1732584193 - var b = -271733879 - var c = -1732584194 - var d = 271733878 - - for (var i = 0; i < x.length; i += 16) { - var olda = a - var oldb = b - var oldc = c - var oldd = d - - a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936) - d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586) - c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819) - b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330) - a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897) - d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426) - c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341) - b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983) - a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416) - d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417) - c = md5_ff(c, d, a, b, x[i + 10], 17, -42063) - b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162) - a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682) - d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101) - c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290) - b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329) - - a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510) - d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632) - c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713) - b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302) - a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691) - d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083) - c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335) - b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848) - a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438) - d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690) - c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961) - b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501) - a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467) - d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784) - c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473) - b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734) - - a = md5_hh(a, b, c, d, x[i + 5], 4, -378558) - d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463) - c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562) - b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556) - a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060) - d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353) - c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632) - b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640) - a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174) - d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222) - c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979) - b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189) - a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487) - d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835) - c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520) - b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651) - - a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844) - d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415) - c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905) - b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055) - a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571) - d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606) - c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523) - b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799) - a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359) - d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744) - c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380) - b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649) - a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070) - d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379) - c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259) - b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551) - - a = safe_add(a, olda) - b = safe_add(b, oldb) - c = safe_add(c, oldc) - d = safe_add(d, oldd) - } + var primeCache = {}; + function checkPrime(prime, generator) { + var gen = generator.toString('hex'); + var hex = [gen, prime.toString(16)].join('_'); + if (hex in primeCache) { + return primeCache[hex]; + } + var error = 0; + + if (prime.isEven() || !primes.simpleSieve || !primes.fermatTest(prime) || !millerRabin.test(prime)) { + //not a prime so +1 + error += 1; + + if (gen === '02' || gen === '05') { + // we'd be able to check the generator + // it would fail so +8 + error += 8; + } else { + //we wouldn't be able to test the generator + // so +4 + error += 4; + } + primeCache[hex] = error; + return error; + } + if (!millerRabin.test(prime.shrn(1))) { + //not a safe prime + error += 2; + } + var rem; + switch (gen) { + case '02': + if (prime.mod(TWENTYFOUR).cmp(ELEVEN)) { + // unsuidable generator + error += 8; + } + break; + case '05': + rem = prime.mod(TEN); + if (rem.cmp(THREE) && rem.cmp(SEVEN)) { + // prime mod 10 needs to equal 3 or 7 + error += 8; + } + break; + default: + error += 4; + } + primeCache[hex] = error; + return error; + } - return [a, b, c, d] -} + function DH(prime, generator, malleable) { + this.setGenerator(generator); + this.__prime = new BN(prime); + this._prime = BN.mont(this.__prime); + this._primeLen = prime.length; + this._pub = undefined; + this._priv = undefined; + this._primeCode = undefined; + if (malleable) { + this.setPublicKey = setPublicKey; + this.setPrivateKey = setPrivateKey; + } else { + this._primeCode = 8; + } + } + Object.defineProperty(DH.prototype, 'verifyError', { + enumerable: true, + get: function() { + if (typeof this._primeCode !== 'number') { + this._primeCode = checkPrime(this.__prime, this.__gen); + } + return this._primeCode; + }, + }); + DH.prototype.generateKeys = function() { + if (!this._priv) { + this._priv = new BN(randomBytes(this._primeLen)); + } + this._pub = this._gen + .toRed(this._prime) + .redPow(this._priv) + .fromRed(); + return this.getPublicKey(); + }; + + DH.prototype.computeSecret = function(other) { + other = new BN(other); + other = other.toRed(this._prime); + var secret = other.redPow(this._priv).fromRed(); + var out = new Buffer(secret.toArray()); + var prime = this.getPrime(); + if (out.length < prime.length) { + var front = new Buffer(prime.length - out.length); + front.fill(0); + out = Buffer.concat([front, out]); + } + return out; + }; -/* - * These functions implement the four basic operations the algorithm uses. - */ -function md5_cmn (q, a, b, x, s, t) { - return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b) -} + DH.prototype.getPublicKey = function getPublicKey(enc) { + return formatReturnValue(this._pub, enc); + }; -function md5_ff (a, b, c, d, x, s, t) { - return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t) -} + DH.prototype.getPrivateKey = function getPrivateKey(enc) { + return formatReturnValue(this._priv, enc); + }; -function md5_gg (a, b, c, d, x, s, t) { - return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t) -} + DH.prototype.getPrime = function(enc) { + return formatReturnValue(this.__prime, enc); + }; -function md5_hh (a, b, c, d, x, s, t) { - return md5_cmn(b ^ c ^ d, a, b, x, s, t) -} + DH.prototype.getGenerator = function(enc) { + return formatReturnValue(this._gen, enc); + }; -function md5_ii (a, b, c, d, x, s, t) { - return md5_cmn(c ^ (b | (~d)), a, b, x, s, t) -} + DH.prototype.setGenerator = function(gen, enc) { + enc = enc || 'utf8'; + if (!Buffer.isBuffer(gen)) { + gen = new Buffer(gen, enc); + } + this.__gen = gen; + this._gen = new BN(gen); + return this; + }; + + function formatReturnValue(bn, enc) { + var buf = new Buffer(bn.toArray()); + if (!enc) { + return buf; + } else { + return buf.toString(enc); + } + } + }.call(this, require('buffer').Buffer)); + }, + { './generatePrime': 148, 'bn.js': 150, buffer: 113, 'miller-rabin': 190, randombytes: 217 }, + ], + 148: [ + function(require, module, exports) { + var randomBytes = require('randombytes'); + module.exports = findPrime; + findPrime.simpleSieve = simpleSieve; + findPrime.fermatTest = fermatTest; + var BN = require('bn.js'); + var TWENTYFOUR = new BN(24); + var MillerRabin = require('miller-rabin'); + var millerRabin = new MillerRabin(); + var ONE = new BN(1); + var TWO = new BN(2); + var FIVE = new BN(5); + var SIXTEEN = new BN(16); + var EIGHT = new BN(8); + var TEN = new BN(10); + var THREE = new BN(3); + var SEVEN = new BN(7); + var ELEVEN = new BN(11); + var FOUR = new BN(4); + var TWELVE = new BN(12); + var primes = null; + + function _getPrimes() { + if (primes !== null) return primes; + + var limit = 0x100000; + var res = []; + res[0] = 2; + for (var i = 1, k = 3; k < limit; k += 2) { + var sqrt = Math.ceil(Math.sqrt(k)); + for (var j = 0; j < i && res[j] <= sqrt; j++) if (k % res[j] === 0) break; + + if (i !== j && res[j] <= sqrt) continue; + + res[i++] = k; + } + primes = res; + return res; + } -/* - * Add integers, wrapping at 2^32. This uses 16-bit operations internally - * to work around bugs in some JS interpreters. - */ -function safe_add (x, y) { - var lsw = (x & 0xFFFF) + (y & 0xFFFF) - var msw = (x >> 16) + (y >> 16) + (lsw >> 16) - return (msw << 16) | (lsw & 0xFFFF) -} + function simpleSieve(p) { + var primes = _getPrimes(); -/* - * Bitwise rotate a 32-bit number to the left. - */ -function bit_rol (num, cnt) { - return (num << cnt) | (num >>> (32 - cnt)) -} + for (var i = 0; i < primes.length; i++) + if (p.modn(primes[i]) === 0) { + if (p.cmpn(primes[i]) === 0) { + return true; + } else { + return false; + } + } -module.exports = function md5 (buf) { - return makeHash(buf, core_md5) -} + return true; + } -},{"./make-hash":135}],137:[function(require,module,exports){ -'use strict' -var inherits = require('inherits') -var Legacy = require('./legacy') -var Base = require('cipher-base') -var Buffer = require('safe-buffer').Buffer -var md5 = require('create-hash/md5') -var RIPEMD160 = require('ripemd160') + function fermatTest(p) { + var red = BN.mont(p); + return ( + TWO.toRed(red) + .redPow(p.subn(1)) + .fromRed() + .cmpn(1) === 0 + ); + } -var sha = require('sha.js') + function findPrime(bits, gen) { + if (bits < 16) { + // this is what openssl does + if (gen === 2 || gen === 5) { + return new BN([0x8c, 0x7b]); + } else { + return new BN([0x8c, 0x27]); + } + } + gen = new BN(gen); -var ZEROS = Buffer.alloc(128) + var num, n2; -function Hmac (alg, key) { - Base.call(this, 'digest') - if (typeof key === 'string') { - key = Buffer.from(key) - } + while (true) { + num = new BN(randomBytes(Math.ceil(bits / 8))); + while (num.bitLength() > bits) { + num.ishrn(1); + } + if (num.isEven()) { + num.iadd(ONE); + } + if (!num.testn(1)) { + num.iadd(TWO); + } + if (!gen.cmp(TWO)) { + while (num.mod(TWENTYFOUR).cmp(ELEVEN)) { + num.iadd(FOUR); + } + } else if (!gen.cmp(FIVE)) { + while (num.mod(TEN).cmp(THREE)) { + num.iadd(FOUR); + } + } + n2 = num.shrn(1); + if ( + simpleSieve(n2) && + simpleSieve(num) && + fermatTest(n2) && + fermatTest(num) && + millerRabin.test(n2) && + millerRabin.test(num) + ) { + return num; + } + } + } + }, + { 'bn.js': 150, 'miller-rabin': 190, randombytes: 217 }, + ], + 149: [ + function(require, module, exports) { + module.exports = { + modp1: { + gen: '02', + prime: + 'ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a63a3620ffffffffffffffff', + }, + modp2: { + gen: '02', + prime: + 'ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff', + }, + modp5: { + gen: '02', + prime: + 'ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff', + }, + modp14: { + gen: '02', + prime: + 'ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff', + }, + modp15: { + gen: '02', + prime: + 'ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a93ad2caffffffffffffffff', + }, + modp16: { + gen: '02', + prime: + 'ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c934063199ffffffffffffffff', + }, + modp17: { + gen: '02', + prime: + 'ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dcc4024ffffffffffffffff', + }, + modp18: { + gen: '02', + prime: + 'ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dbe115974a3926f12fee5e438777cb6a932df8cd8bec4d073b931ba3bc832b68d9dd300741fa7bf8afc47ed2576f6936ba424663aab639c5ae4f5683423b4742bf1c978238f16cbe39d652de3fdb8befc848ad922222e04a4037c0713eb57a81a23f0c73473fc646cea306b4bcbc8862f8385ddfa9d4b7fa2c087e879683303ed5bdd3a062b3cf5b3a278a66d2a13f83f44f82ddf310ee074ab6a364597e899a0255dc164f31cc50846851df9ab48195ded7ea1b1d510bd7ee74d73faf36bc31ecfa268359046f4eb879f924009438b481c6cd7889a002ed5ee382bc9190da6fc026e479558e4475677e9aa9e3050e2765694dfc81f56e880b96e7160c980dd98edd3dfffffffffffffffff', + }, + }; + }, + {}, + ], + 150: [ + function(require, module, exports) { + arguments[4][59][0].apply(exports, arguments); + }, + { buffer: 64, dup: 59 }, + ], + 151: [ + function(require, module, exports) { + 'use strict'; + + var elliptic = exports; + + elliptic.version = require('../package.json').version; + elliptic.utils = require('./elliptic/utils'); + elliptic.rand = require('brorand'); + elliptic.hmacDRBG = require('./elliptic/hmac-drbg'); + elliptic.curve = require('./elliptic/curve'); + elliptic.curves = require('./elliptic/curves'); + + // Protocols + elliptic.ec = require('./elliptic/ec'); + }, + { + '../package.json': 164, + './elliptic/curve': 154, + './elliptic/curves': 157, + './elliptic/ec': 158, + './elliptic/hmac-drbg': 161, + './elliptic/utils': 163, + brorand: 63, + }, + ], + 152: [ + function(require, module, exports) { + 'use strict'; + + var bn = require('bn.js'); + var elliptic = require('../../elliptic'); + + var getNAF = elliptic.utils.getNAF; + var getJSF = elliptic.utils.getJSF; + var assert = elliptic.utils.assert; + + function BaseCurve(type, conf) { + this.type = type; + this.p = new bn(conf.p, 16); + + // Use Montgomery, when there is no fast reduction for the prime + this.red = conf.prime ? bn.red(conf.prime) : bn.mont(this.p); + + // Useful for many curves + this.zero = new bn(0).toRed(this.red); + this.one = new bn(1).toRed(this.red); + this.two = new bn(2).toRed(this.red); + + // Curve configuration, optional + this.n = conf.n && new bn(conf.n, 16); + this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed); + + // Temporary arrays + this._wnafT1 = new Array(4); + this._wnafT2 = new Array(4); + this._wnafT3 = new Array(4); + this._wnafT4 = new Array(4); + } + module.exports = BaseCurve; - var blocksize = (alg === 'sha512' || alg === 'sha384') ? 128 : 64 + BaseCurve.prototype.point = function point() { + throw new Error('Not implemented'); + }; - this._alg = alg - this._key = key - if (key.length > blocksize) { - var hash = alg === 'rmd160' ? new RIPEMD160() : sha(alg) - key = hash.update(key).digest() - } else if (key.length < blocksize) { - key = Buffer.concat([key, ZEROS], blocksize) - } + BaseCurve.prototype.validate = function validate() { + throw new Error('Not implemented'); + }; - var ipad = this._ipad = Buffer.allocUnsafe(blocksize) - var opad = this._opad = Buffer.allocUnsafe(blocksize) + BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) { + var doubles = p._getDoubles(); - for (var i = 0; i < blocksize; i++) { - ipad[i] = key[i] ^ 0x36 - opad[i] = key[i] ^ 0x5C - } - this._hash = alg === 'rmd160' ? new RIPEMD160() : sha(alg) - this._hash.update(ipad) -} + var naf = getNAF(k, 1); + var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1); + I /= 3; -inherits(Hmac, Base) + // Translate into more windowed form + var repr = []; + for (var j = 0; j < naf.length; j += doubles.step) { + var nafW = 0; + for (var k = j + doubles.step - 1; k >= j; k--) nafW = (nafW << 1) + naf[k]; + repr.push(nafW); + } -Hmac.prototype._update = function (data) { - this._hash.update(data) -} + var a = this.jpoint(null, null, null); + var b = this.jpoint(null, null, null); + for (var i = I; i > 0; i--) { + for (var j = 0; j < repr.length; j++) { + var nafW = repr[j]; + if (nafW === i) b = b.mixedAdd(doubles.points[j]); + else if (nafW === -i) b = b.mixedAdd(doubles.points[j].neg()); + } + a = a.add(b); + } + return a.toP(); + }; -Hmac.prototype._final = function () { - var h = this._hash.digest() - var hash = this._alg === 'rmd160' ? new RIPEMD160() : sha(this._alg) - return hash.update(this._opad).update(h).digest() -} + BaseCurve.prototype._wnafMul = function _wnafMul(p, k) { + var w = 4; + + // Precompute window + var nafPoints = p._getNAFPoints(w); + w = nafPoints.wnd; + var wnd = nafPoints.points; + + // Get NAF form + var naf = getNAF(k, w); + + // Add `this`*(N+1) for every w-NAF index + var acc = this.jpoint(null, null, null); + for (var i = naf.length - 1; i >= 0; i--) { + // Count zeroes + for (var k = 0; i >= 0 && naf[i] === 0; i--) k++; + if (i >= 0) k++; + acc = acc.dblp(k); + + if (i < 0) break; + var z = naf[i]; + assert(z !== 0); + if (p.type === 'affine') { + // J +- P + if (z > 0) acc = acc.mixedAdd(wnd[(z - 1) >> 1]); + else acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg()); + } else { + // J +- J + if (z > 0) acc = acc.add(wnd[(z - 1) >> 1]); + else acc = acc.add(wnd[(-z - 1) >> 1].neg()); + } + } + return p.type === 'affine' ? acc.toP() : acc; + }; -module.exports = function createHmac (alg, key) { - alg = alg.toLowerCase() - if (alg === 'rmd160' || alg === 'ripemd160') { - return new Hmac('rmd160', key) - } - if (alg === 'md5') { - return new Legacy(md5, key) - } - return new Hmac(alg, key) -} + BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW, points, coeffs, len) { + var wndWidth = this._wnafT1; + var wnd = this._wnafT2; + var naf = this._wnafT3; + + // Fill all arrays + var max = 0; + for (var i = 0; i < len; i++) { + var p = points[i]; + var nafPoints = p._getNAFPoints(defW); + wndWidth[i] = nafPoints.wnd; + wnd[i] = nafPoints.points; + } -},{"./legacy":138,"cipher-base":114,"create-hash/md5":136,"inherits":184,"ripemd160":232,"safe-buffer":233,"sha.js":235}],138:[function(require,module,exports){ -'use strict' -var inherits = require('inherits') -var Buffer = require('safe-buffer').Buffer + // Comb small window NAFs + for (var i = len - 1; i >= 1; i -= 2) { + var a = i - 1; + var b = i; + if (wndWidth[a] !== 1 || wndWidth[b] !== 1) { + naf[a] = getNAF(coeffs[a], wndWidth[a]); + naf[b] = getNAF(coeffs[b], wndWidth[b]); + max = Math.max(naf[a].length, max); + max = Math.max(naf[b].length, max); + continue; + } -var Base = require('cipher-base') + var comb = [points[a] /* 1 */, null /* 3 */, null /* 5 */, points[b] /* 7 */]; -var ZEROS = Buffer.alloc(128) -var blocksize = 64 + // Try to avoid Projective points, if possible + if (points[a].y.cmp(points[b].y) === 0) { + comb[1] = points[a].add(points[b]); + comb[2] = points[a].toJ().mixedAdd(points[b].neg()); + } else if (points[a].y.cmp(points[b].y.redNeg()) === 0) { + comb[1] = points[a].toJ().mixedAdd(points[b]); + comb[2] = points[a].add(points[b].neg()); + } else { + comb[1] = points[a].toJ().mixedAdd(points[b]); + comb[2] = points[a].toJ().mixedAdd(points[b].neg()); + } -function Hmac (alg, key) { - Base.call(this, 'digest') - if (typeof key === 'string') { - key = Buffer.from(key) - } + var index = [ + -3 /* -1 -1 */, + -1 /* -1 0 */, + -5 /* -1 1 */, + -7 /* 0 -1 */, + 0 /* 0 0 */, + 7 /* 0 1 */, + 5 /* 1 -1 */, + 1 /* 1 0 */, + 3 /* 1 1 */, + ]; + + var jsf = getJSF(coeffs[a], coeffs[b]); + max = Math.max(jsf[0].length, max); + naf[a] = new Array(max); + naf[b] = new Array(max); + for (var j = 0; j < max; j++) { + var ja = jsf[0][j] | 0; + var jb = jsf[1][j] | 0; + + naf[a][j] = index[(ja + 1) * 3 + (jb + 1)]; + naf[b][j] = 0; + wnd[a] = comb; + } + } - this._alg = alg - this._key = key + var acc = this.jpoint(null, null, null); + var tmp = this._wnafT4; + for (var i = max; i >= 0; i--) { + var k = 0; - if (key.length > blocksize) { - key = alg(key) - } else if (key.length < blocksize) { - key = Buffer.concat([key, ZEROS], blocksize) - } + while (i >= 0) { + var zero = true; + for (var j = 0; j < len; j++) { + tmp[j] = naf[j][i] | 0; + if (tmp[j] !== 0) zero = false; + } + if (!zero) break; + k++; + i--; + } + if (i >= 0) k++; + acc = acc.dblp(k); + if (i < 0) break; + + for (var j = 0; j < len; j++) { + var z = tmp[j]; + var p; + if (z === 0) continue; + else if (z > 0) p = wnd[j][(z - 1) >> 1]; + else if (z < 0) p = wnd[j][(-z - 1) >> 1].neg(); + + if (p.type === 'affine') acc = acc.mixedAdd(p); + else acc = acc.add(p); + } + } + // Zeroify references + for (var i = 0; i < len; i++) wnd[i] = null; + return acc.toP(); + }; - var ipad = this._ipad = Buffer.allocUnsafe(blocksize) - var opad = this._opad = Buffer.allocUnsafe(blocksize) + function BasePoint(curve, type) { + this.curve = curve; + this.type = type; + this.precomputed = null; + } + BaseCurve.BasePoint = BasePoint; - for (var i = 0; i < blocksize; i++) { - ipad[i] = key[i] ^ 0x36 - opad[i] = key[i] ^ 0x5C - } + BasePoint.prototype.validate = function validate() { + return this.curve.validate(this); + }; - this._hash = [ipad] -} + BasePoint.prototype.precompute = function precompute(power) { + if (this.precomputed) return this; -inherits(Hmac, Base) + var precomputed = { + doubles: null, + naf: null, + beta: null, + }; + precomputed.naf = this._getNAFPoints(8); + precomputed.doubles = this._getDoubles(4, power); + precomputed.beta = this._getBeta(); + this.precomputed = precomputed; -Hmac.prototype._update = function (data) { - this._hash.push(data) -} + return this; + }; -Hmac.prototype._final = function () { - var h = this._alg(Buffer.concat(this._hash)) - return this._alg(Buffer.concat([this._opad, h])) -} -module.exports = Hmac + BasePoint.prototype._getDoubles = function _getDoubles(step, power) { + if (this.precomputed && this.precomputed.doubles) return this.precomputed.doubles; -},{"cipher-base":114,"inherits":184,"safe-buffer":233}],139:[function(require,module,exports){ -'use strict' + var doubles = [this]; + var acc = this; + for (var i = 0; i < power; i += step) { + for (var j = 0; j < step; j++) acc = acc.dbl(); + doubles.push(acc); + } + return { + step: step, + points: doubles, + }; + }; -exports.randomBytes = exports.rng = exports.pseudoRandomBytes = exports.prng = require('randombytes') -exports.createHash = exports.Hash = require('create-hash') -exports.createHmac = exports.Hmac = require('create-hmac') + BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) { + if (this.precomputed && this.precomputed.naf) return this.precomputed.naf; -var algos = require('browserify-sign/algos') -var algoKeys = Object.keys(algos) -var hashes = ['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'md5', 'rmd160'].concat(algoKeys) -exports.getHashes = function () { - return hashes -} + var res = [this]; + var max = (1 << wnd) - 1; + var dbl = max === 1 ? null : this.dbl(); + for (var i = 1; i < max; i++) res[i] = res[i - 1].add(dbl); + return { + wnd: wnd, + points: res, + }; + }; -var p = require('pbkdf2') -exports.pbkdf2 = p.pbkdf2 -exports.pbkdf2Sync = p.pbkdf2Sync - -var aes = require('browserify-cipher') - -exports.Cipher = aes.Cipher -exports.createCipher = aes.createCipher -exports.Cipheriv = aes.Cipheriv -exports.createCipheriv = aes.createCipheriv -exports.Decipher = aes.Decipher -exports.createDecipher = aes.createDecipher -exports.Decipheriv = aes.Decipheriv -exports.createDecipheriv = aes.createDecipheriv -exports.getCiphers = aes.getCiphers -exports.listCiphers = aes.listCiphers - -var dh = require('diffie-hellman') - -exports.DiffieHellmanGroup = dh.DiffieHellmanGroup -exports.createDiffieHellmanGroup = dh.createDiffieHellmanGroup -exports.getDiffieHellman = dh.getDiffieHellman -exports.createDiffieHellman = dh.createDiffieHellman -exports.DiffieHellman = dh.DiffieHellman - -var sign = require('browserify-sign') - -exports.createSign = sign.createSign -exports.Sign = sign.Sign -exports.createVerify = sign.createVerify -exports.Verify = sign.Verify - -exports.createECDH = require('create-ecdh') - -var publicEncrypt = require('public-encrypt') - -exports.publicEncrypt = publicEncrypt.publicEncrypt -exports.privateEncrypt = publicEncrypt.privateEncrypt -exports.publicDecrypt = publicEncrypt.publicDecrypt -exports.privateDecrypt = publicEncrypt.privateDecrypt - -// the least I can do is make error messages for the rest of the node.js/crypto api. -// ;[ -// 'createCredentials' -// ].forEach(function (name) { -// exports[name] = function () { -// throw new Error([ -// 'sorry, ' + name + ' is not implemented yet', -// 'we accept pull requests', -// 'https://github.com/crypto-browserify/crypto-browserify' -// ].join('\n')) -// } -// }) - -exports.createCredentials = function () { - throw new Error([ - 'sorry, createCredentials is not implemented yet', - 'we accept pull requests', - 'https://github.com/crypto-browserify/crypto-browserify' - ].join('\n')) -} + BasePoint.prototype._getBeta = function _getBeta() { + return null; + }; -exports.constants = { - 'DH_CHECK_P_NOT_SAFE_PRIME': 2, - 'DH_CHECK_P_NOT_PRIME': 1, - 'DH_UNABLE_TO_CHECK_GENERATOR': 4, - 'DH_NOT_SUITABLE_GENERATOR': 8, - 'NPN_ENABLED': 1, - 'ALPN_ENABLED': 1, - 'RSA_PKCS1_PADDING': 1, - 'RSA_SSLV23_PADDING': 2, - 'RSA_NO_PADDING': 3, - 'RSA_PKCS1_OAEP_PADDING': 4, - 'RSA_X931_PADDING': 5, - 'RSA_PKCS1_PSS_PADDING': 6, - 'POINT_CONVERSION_COMPRESSED': 2, - 'POINT_CONVERSION_UNCOMPRESSED': 4, - 'POINT_CONVERSION_HYBRID': 6 -} + BasePoint.prototype.dblp = function dblp(k) { + var r = this; + for (var i = 0; i < k; i++) r = r.dbl(); + return r; + }; + }, + { '../../elliptic': 151, 'bn.js': 62 }, + ], + 153: [ + function(require, module, exports) { + 'use strict'; + + var curve = require('../curve'); + var elliptic = require('../../elliptic'); + var bn = require('bn.js'); + var inherits = require('inherits'); + var Base = curve.base; + + var assert = elliptic.utils.assert; + + function EdwardsCurve(conf) { + // NOTE: Important as we are creating point in Base.call() + this.twisted = (conf.a | 0) !== 1; + this.mOneA = this.twisted && (conf.a | 0) === -1; + this.extended = this.mOneA; + + Base.call(this, 'edwards', conf); + + this.a = new bn(conf.a, 16).mod(this.red.m).toRed(this.red); + this.c = new bn(conf.c, 16).toRed(this.red); + this.c2 = this.c.redSqr(); + this.d = new bn(conf.d, 16).toRed(this.red); + this.dd = this.d.redAdd(this.d); + + assert(!this.twisted || this.c.fromRed().cmpn(1) === 0); + this.oneC = (conf.c | 0) === 1; + } + inherits(EdwardsCurve, Base); + module.exports = EdwardsCurve; -},{"browserify-cipher":81,"browserify-sign":89,"browserify-sign/algos":86,"create-ecdh":116,"create-hash":134,"create-hmac":137,"diffie-hellman":146,"pbkdf2":199,"public-encrypt":206,"randombytes":217}],140:[function(require,module,exports){ -'use strict'; + EdwardsCurve.prototype._mulA = function _mulA(num) { + if (this.mOneA) return num.redNeg(); + else return this.a.redMul(num); + }; -exports.utils = require('./des/utils'); -exports.Cipher = require('./des/cipher'); -exports.DES = require('./des/des'); -exports.CBC = require('./des/cbc'); -exports.EDE = require('./des/ede'); + EdwardsCurve.prototype._mulC = function _mulC(num) { + if (this.oneC) return num; + else return this.c.redMul(num); + }; -},{"./des/cbc":141,"./des/cipher":142,"./des/des":143,"./des/ede":144,"./des/utils":145}],141:[function(require,module,exports){ -'use strict'; + // Just for compatibility with Short curve + EdwardsCurve.prototype.jpoint = function jpoint(x, y, z, t) { + return this.point(x, y, z, t); + }; -var assert = require('minimalistic-assert'); -var inherits = require('inherits'); + EdwardsCurve.prototype.pointFromX = function pointFromX(odd, x) { + x = new bn(x, 16); + if (!x.red) x = x.toRed(this.red); -var proto = {}; + var x2 = x.redSqr(); + var rhs = this.c2.redSub(this.a.redMul(x2)); + var lhs = this.one.redSub(this.c2.redMul(this.d).redMul(x2)); -function CBCState(iv) { - assert.equal(iv.length, 8, 'Invalid IV length'); + var y = rhs.redMul(lhs.redInvm()).redSqrt(); + var isOdd = y.fromRed().isOdd(); + if ((odd && !isOdd) || (!odd && isOdd)) y = y.redNeg(); - this.iv = new Array(8); - for (var i = 0; i < this.iv.length; i++) - this.iv[i] = iv[i]; -} + return this.point(x, y, curve.one); + }; -function instantiate(Base) { - function CBC(options) { - Base.call(this, options); - this._cbcInit(); - } - inherits(CBC, Base); + EdwardsCurve.prototype.validate = function validate(point) { + if (point.isInfinity()) return true; - var keys = Object.keys(proto); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - CBC.prototype[key] = proto[key]; - } + // Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2) + point.normalize(); - CBC.create = function create(options) { - return new CBC(options); - }; + var x2 = point.x.redSqr(); + var y2 = point.y.redSqr(); + var lhs = x2.redMul(this.a).redAdd(y2); + var rhs = this.c2.redMul(this.one.redAdd(this.d.redMul(x2).redMul(y2))); - return CBC; -} + return lhs.cmp(rhs) === 0; + }; -exports.instantiate = instantiate; + function Point(curve, x, y, z, t) { + Base.BasePoint.call(this, curve, 'projective'); + if (x === null && y === null && z === null) { + this.x = this.curve.zero; + this.y = this.curve.one; + this.z = this.curve.one; + this.t = this.curve.zero; + this.zOne = true; + } else { + this.x = new bn(x, 16); + this.y = new bn(y, 16); + this.z = z ? new bn(z, 16) : this.curve.one; + this.t = t && new bn(t, 16); + if (!this.x.red) this.x = this.x.toRed(this.curve.red); + if (!this.y.red) this.y = this.y.toRed(this.curve.red); + if (!this.z.red) this.z = this.z.toRed(this.curve.red); + if (this.t && !this.t.red) this.t = this.t.toRed(this.curve.red); + this.zOne = this.z === this.curve.one; + + // Use extended coordinates + if (this.curve.extended && !this.t) { + this.t = this.x.redMul(this.y); + if (!this.zOne) this.t = this.t.redMul(this.z.redInvm()); + } + } + } + inherits(Point, Base.BasePoint); -proto._cbcInit = function _cbcInit() { - var state = new CBCState(this.options.iv); - this._cbcState = state; -}; + EdwardsCurve.prototype.pointFromJSON = function pointFromJSON(obj) { + return Point.fromJSON(this, obj); + }; -proto._update = function _update(inp, inOff, out, outOff) { - var state = this._cbcState; - var superProto = this.constructor.super_.prototype; + EdwardsCurve.prototype.point = function point(x, y, z, t) { + return new Point(this, x, y, z, t); + }; - var iv = state.iv; - if (this.type === 'encrypt') { - for (var i = 0; i < this.blockSize; i++) - iv[i] ^= inp[inOff + i]; + Point.fromJSON = function fromJSON(curve, obj) { + return new Point(curve, obj[0], obj[1], obj[2]); + }; - superProto._update.call(this, iv, 0, out, outOff); + Point.prototype.inspect = function inspect() { + if (this.isInfinity()) return ''; + return ( + '' + ); + }; - for (var i = 0; i < this.blockSize; i++) - iv[i] = out[outOff + i]; - } else { - superProto._update.call(this, inp, inOff, out, outOff); + Point.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.x.cmpn(0) === 0 && this.y.cmp(this.z) === 0; + }; - for (var i = 0; i < this.blockSize; i++) - out[outOff + i] ^= iv[i]; + Point.prototype._extDbl = function _extDbl() { + // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html + // #doubling-dbl-2008-hwcd + // 4M + 4S + + // A = X1^2 + var a = this.x.redSqr(); + // B = Y1^2 + var b = this.y.redSqr(); + // C = 2 * Z1^2 + var c = this.z.redSqr(); + c = c.redIAdd(c); + // D = a * A + var d = this.curve._mulA(a); + // E = (X1 + Y1)^2 - A - B + var e = this.x + .redAdd(this.y) + .redSqr() + .redISub(a) + .redISub(b); + // G = D + B + var g = d.redAdd(b); + // F = G - C + var f = g.redSub(c); + // H = D - B + var h = d.redSub(b); + // X3 = E * F + var nx = e.redMul(f); + // Y3 = G * H + var ny = g.redMul(h); + // T3 = E * H + var nt = e.redMul(h); + // Z3 = F * G + var nz = f.redMul(g); + return this.curve.point(nx, ny, nz, nt); + }; - for (var i = 0; i < this.blockSize; i++) - iv[i] = inp[inOff + i]; - } -}; + Point.prototype._projDbl = function _projDbl() { + // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html + // #doubling-dbl-2008-bbjlp + // #doubling-dbl-2007-bl + // and others + // Generally 3M + 4S or 2M + 4S + + // B = (X1 + Y1)^2 + var b = this.x.redAdd(this.y).redSqr(); + // C = X1^2 + var c = this.x.redSqr(); + // D = Y1^2 + var d = this.y.redSqr(); + + var nx; + var ny; + var nz; + if (this.curve.twisted) { + // E = a * C + var e = this.curve._mulA(c); + // F = E + D + var f = e.redAdd(d); + if (this.zOne) { + // X3 = (B - C - D) * (F - 2) + nx = b + .redSub(c) + .redSub(d) + .redMul(f.redSub(this.curve.two)); + // Y3 = F * (E - D) + ny = f.redMul(e.redSub(d)); + // Z3 = F^2 - 2 * F + nz = f + .redSqr() + .redSub(f) + .redSub(f); + } else { + // H = Z1^2 + var h = this.z.redSqr(); + // J = F - 2 * H + var j = f.redSub(h).redISub(h); + // X3 = (B-C-D)*J + nx = b + .redSub(c) + .redISub(d) + .redMul(j); + // Y3 = F * (E - D) + ny = f.redMul(e.redSub(d)); + // Z3 = F * J + nz = f.redMul(j); + } + } else { + // E = C + D + var e = c.redAdd(d); + // H = (c * Z1)^2 + var h = this.curve._mulC(this.c.redMul(this.z)).redSqr(); + // J = E - 2 * H + var j = e.redSub(h).redSub(h); + // X3 = c * (B - E) * J + nx = this.curve._mulC(b.redISub(e)).redMul(j); + // Y3 = c * E * (C - D) + ny = this.curve._mulC(e).redMul(c.redISub(d)); + // Z3 = E * J + nz = e.redMul(j); + } + return this.curve.point(nx, ny, nz); + }; -},{"inherits":184,"minimalistic-assert":192}],142:[function(require,module,exports){ -'use strict'; + Point.prototype.dbl = function dbl() { + if (this.isInfinity()) return this; -var assert = require('minimalistic-assert'); + // Double in extended coordinates + if (this.curve.extended) return this._extDbl(); + else return this._projDbl(); + }; -function Cipher(options) { - this.options = options; + Point.prototype._extAdd = function _extAdd(p) { + // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html + // #addition-add-2008-hwcd-3 + // 8M + + // A = (Y1 - X1) * (Y2 - X2) + var a = this.y.redSub(this.x).redMul(p.y.redSub(p.x)); + // B = (Y1 + X1) * (Y2 + X2) + var b = this.y.redAdd(this.x).redMul(p.y.redAdd(p.x)); + // C = T1 * k * T2 + var c = this.t.redMul(this.curve.dd).redMul(p.t); + // D = Z1 * 2 * Z2 + var d = this.z.redMul(p.z.redAdd(p.z)); + // E = B - A + var e = b.redSub(a); + // F = D - C + var f = d.redSub(c); + // G = D + C + var g = d.redAdd(c); + // H = B + A + var h = b.redAdd(a); + // X3 = E * F + var nx = e.redMul(f); + // Y3 = G * H + var ny = g.redMul(h); + // T3 = E * H + var nt = e.redMul(h); + // Z3 = F * G + var nz = f.redMul(g); + return this.curve.point(nx, ny, nz, nt); + }; - this.type = this.options.type; - this.blockSize = 8; - this._init(); + Point.prototype._projAdd = function _projAdd(p) { + // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html + // #addition-add-2008-bbjlp + // #addition-add-2007-bl + // 10M + 1S + + // A = Z1 * Z2 + var a = this.z.redMul(p.z); + // B = A^2 + var b = a.redSqr(); + // C = X1 * X2 + var c = this.x.redMul(p.x); + // D = Y1 * Y2 + var d = this.y.redMul(p.y); + // E = d * C * D + var e = this.curve.d.redMul(c).redMul(d); + // F = B - E + var f = b.redSub(e); + // G = B + E + var g = b.redAdd(e); + // X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D) + var tmp = this.x + .redAdd(this.y) + .redMul(p.x.redAdd(p.y)) + .redISub(c) + .redISub(d); + var nx = a.redMul(f).redMul(tmp); + var ny; + var nz; + if (this.curve.twisted) { + // Y3 = A * G * (D - a * C) + ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c))); + // Z3 = F * G + nz = f.redMul(g); + } else { + // Y3 = A * G * (D - C) + ny = a.redMul(g).redMul(d.redSub(c)); + // Z3 = c * F * G + nz = this.curve._mulC(f).redMul(g); + } + return this.curve.point(nx, ny, nz); + }; - this.buffer = new Array(this.blockSize); - this.bufferOff = 0; -} -module.exports = Cipher; - -Cipher.prototype._init = function _init() { - // Might be overrided -}; - -Cipher.prototype.update = function update(data) { - if (data.length === 0) - return []; - - if (this.type === 'decrypt') - return this._updateDecrypt(data); - else - return this._updateEncrypt(data); -}; - -Cipher.prototype._buffer = function _buffer(data, off) { - // Append data to buffer - var min = Math.min(this.buffer.length - this.bufferOff, data.length - off); - for (var i = 0; i < min; i++) - this.buffer[this.bufferOff + i] = data[off + i]; - this.bufferOff += min; - - // Shift next - return min; -}; - -Cipher.prototype._flushBuffer = function _flushBuffer(out, off) { - this._update(this.buffer, 0, out, off); - this.bufferOff = 0; - return this.blockSize; -}; - -Cipher.prototype._updateEncrypt = function _updateEncrypt(data) { - var inputOff = 0; - var outputOff = 0; - - var count = ((this.bufferOff + data.length) / this.blockSize) | 0; - var out = new Array(count * this.blockSize); - - if (this.bufferOff !== 0) { - inputOff += this._buffer(data, inputOff); - - if (this.bufferOff === this.buffer.length) - outputOff += this._flushBuffer(out, outputOff); - } + Point.prototype.add = function add(p) { + if (this.isInfinity()) return p; + if (p.isInfinity()) return this; - // Write blocks - var max = data.length - ((data.length - inputOff) % this.blockSize); - for (; inputOff < max; inputOff += this.blockSize) { - this._update(data, inputOff, out, outputOff); - outputOff += this.blockSize; - } + if (this.curve.extended) return this._extAdd(p); + else return this._projAdd(p); + }; - // Queue rest - for (; inputOff < data.length; inputOff++, this.bufferOff++) - this.buffer[this.bufferOff] = data[inputOff]; + Point.prototype.mul = function mul(k) { + if (this.precomputed && this.precomputed.doubles) return this.curve._fixedNafMul(this, k); + else return this.curve._wnafMul(this, k); + }; - return out; -}; + Point.prototype.mulAdd = function mulAdd(k1, p, k2) { + return this.curve._wnafMulAdd(1, [this, p], [k1, k2], 2); + }; -Cipher.prototype._updateDecrypt = function _updateDecrypt(data) { - var inputOff = 0; - var outputOff = 0; + Point.prototype.normalize = function normalize() { + if (this.zOne) return this; + + // Normalize coordinates + var zi = this.z.redInvm(); + this.x = this.x.redMul(zi); + this.y = this.y.redMul(zi); + if (this.t) this.t = this.t.redMul(zi); + this.z = this.curve.one; + this.zOne = true; + return this; + }; - var count = Math.ceil((this.bufferOff + data.length) / this.blockSize) - 1; - var out = new Array(count * this.blockSize); + Point.prototype.neg = function neg() { + return this.curve.point(this.x.redNeg(), this.y, this.z, this.t && this.t.redNeg()); + }; - // TODO(indutny): optimize it, this is far from optimal - for (; count > 0; count--) { - inputOff += this._buffer(data, inputOff); - outputOff += this._flushBuffer(out, outputOff); - } + Point.prototype.getX = function getX() { + this.normalize(); + return this.x.fromRed(); + }; - // Buffer rest of the input - inputOff += this._buffer(data, inputOff); + Point.prototype.getY = function getY() { + this.normalize(); + return this.y.fromRed(); + }; - return out; -}; + // Compatibility with BaseCurve + Point.prototype.toP = Point.prototype.normalize; + Point.prototype.mixedAdd = Point.prototype.add; + }, + { '../../elliptic': 151, '../curve': 154, 'bn.js': 62, inherits: 184 }, + ], + 154: [ + function(require, module, exports) { + arguments[4][96][0].apply(exports, arguments); + }, + { './base': 152, './edwards': 153, './mont': 155, './short': 156, dup: 96 }, + ], + 155: [ + function(require, module, exports) { + 'use strict'; + + var curve = require('../curve'); + var bn = require('bn.js'); + var inherits = require('inherits'); + var Base = curve.base; + + function MontCurve(conf) { + Base.call(this, 'mont', conf); + + this.a = new bn(conf.a, 16).toRed(this.red); + this.b = new bn(conf.b, 16).toRed(this.red); + this.i4 = new bn(4).toRed(this.red).redInvm(); + this.two = new bn(2).toRed(this.red); + this.a24 = this.i4.redMul(this.a.redAdd(this.two)); + } + inherits(MontCurve, Base); + module.exports = MontCurve; + + MontCurve.prototype.validate = function validate(point) { + var x = point.normalize().x; + var x2 = x.redSqr(); + var rhs = x2 + .redMul(x) + .redAdd(x2.redMul(this.a)) + .redAdd(x); + var y = rhs.redSqrt(); + + return y.redSqr().cmp(rhs) === 0; + }; -Cipher.prototype.final = function final(buffer) { - var first; - if (buffer) - first = this.update(buffer); + function Point(curve, x, z) { + Base.BasePoint.call(this, curve, 'projective'); + if (x === null && z === null) { + this.x = this.curve.one; + this.z = this.curve.zero; + } else { + this.x = new bn(x, 16); + this.z = new bn(z, 16); + if (!this.x.red) this.x = this.x.toRed(this.curve.red); + if (!this.z.red) this.z = this.z.toRed(this.curve.red); + } + } + inherits(Point, Base.BasePoint); - var last; - if (this.type === 'encrypt') - last = this._finalEncrypt(); - else - last = this._finalDecrypt(); + MontCurve.prototype.point = function point(x, z) { + return new Point(this, x, z); + }; - if (first) - return first.concat(last); - else - return last; -}; + MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) { + return Point.fromJSON(this, obj); + }; -Cipher.prototype._pad = function _pad(buffer, off) { - if (off === 0) - return false; + Point.prototype.precompute = function precompute() { + // No-op + }; - while (off < buffer.length) - buffer[off++] = 0; + Point.fromJSON = function fromJSON(curve, obj) { + return new Point(curve, obj[0], obj[1] || curve.one); + }; - return true; -}; + Point.prototype.inspect = function inspect() { + if (this.isInfinity()) return ''; + return ''; + }; -Cipher.prototype._finalEncrypt = function _finalEncrypt() { - if (!this._pad(this.buffer, this.bufferOff)) - return []; + Point.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.z.cmpn(0) === 0; + }; - var out = new Array(this.blockSize); - this._update(this.buffer, 0, out, 0); - return out; -}; + Point.prototype.dbl = function dbl() { + // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3 + // 2M + 2S + 4A + + // A = X1 + Z1 + var a = this.x.redAdd(this.z); + // AA = A^2 + var aa = a.redSqr(); + // B = X1 - Z1 + var b = this.x.redSub(this.z); + // BB = B^2 + var bb = b.redSqr(); + // C = AA - BB + var c = aa.redSub(bb); + // X3 = AA * BB + var nx = aa.redMul(bb); + // Z3 = C * (BB + A24 * C) + var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c))); + return this.curve.point(nx, nz); + }; -Cipher.prototype._unpad = function _unpad(buffer) { - return buffer; -}; + Point.prototype.add = function add() { + throw new Error('Not supported on Montgomery curve'); + }; -Cipher.prototype._finalDecrypt = function _finalDecrypt() { - assert.equal(this.bufferOff, this.blockSize, 'Not enough data to decrypt'); - var out = new Array(this.blockSize); - this._flushBuffer(out, 0); + Point.prototype.diffAdd = function diffAdd(p, diff) { + // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3 + // 4M + 2S + 6A + + // A = X2 + Z2 + var a = this.x.redAdd(this.z); + // B = X2 - Z2 + var b = this.x.redSub(this.z); + // C = X3 + Z3 + var c = p.x.redAdd(p.z); + // D = X3 - Z3 + var d = p.x.redSub(p.z); + // DA = D * A + var da = d.redMul(a); + // CB = C * B + var cb = c.redMul(b); + // X5 = Z1 * (DA + CB)^2 + var nx = diff.z.redMul(da.redAdd(cb).redSqr()); + // Z5 = X1 * (DA - CB)^2 + var nz = diff.x.redMul(da.redISub(cb).redSqr()); + return this.curve.point(nx, nz); + }; - return this._unpad(out); -}; + Point.prototype.mul = function mul(k) { + var t = k.clone(); + var a = this; // (N / 2) * Q + Q + var b = this.curve.point(null, null); // (N / 2) * Q + var c = this; // Q -},{"minimalistic-assert":192}],143:[function(require,module,exports){ -'use strict'; + for (var bits = []; t.cmpn(0) !== 0; t.ishrn(1)) bits.push(t.andln(1)); -var assert = require('minimalistic-assert'); -var inherits = require('inherits'); + for (var i = bits.length - 1; i >= 0; i--) { + if (bits[i] === 0) { + // N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q + a = a.diffAdd(b, c); + // N * Q = 2 * ((N / 2) * Q + Q)) + b = b.dbl(); + } else { + // N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q) + b = a.diffAdd(b, c); + // N * Q + Q = 2 * ((N / 2) * Q + Q) + a = a.dbl(); + } + } + return b; + }; -var des = require('../des'); -var utils = des.utils; -var Cipher = des.Cipher; + Point.prototype.mulAdd = function mulAdd() { + throw new Error('Not supported on Montgomery curve'); + }; -function DESState() { - this.tmp = new Array(2); - this.keys = null; -} + Point.prototype.normalize = function normalize() { + this.x = this.x.redMul(this.z.redInvm()); + this.z = this.curve.one; + return this; + }; -function DES(options) { - Cipher.call(this, options); + Point.prototype.getX = function getX() { + // Normalize coordinates + this.normalize(); - var state = new DESState(); - this._desState = state; + return this.x.fromRed(); + }; + }, + { '../curve': 154, 'bn.js': 62, inherits: 184 }, + ], + 156: [ + function(require, module, exports) { + 'use strict'; + + var curve = require('../curve'); + var elliptic = require('../../elliptic'); + var bn = require('bn.js'); + var inherits = require('inherits'); + var Base = curve.base; + + var assert = elliptic.utils.assert; + + function ShortCurve(conf) { + Base.call(this, 'short', conf); + + this.a = new bn(conf.a, 16).toRed(this.red); + this.b = new bn(conf.b, 16).toRed(this.red); + this.tinv = this.two.redInvm(); + + this.zeroA = this.a.fromRed().cmpn(0) === 0; + this.threeA = + this.a + .fromRed() + .sub(this.p) + .cmpn(-3) === 0; + + // If the curve is endomorphic, precalculate beta and lambda + this.endo = this._getEndomorphism(conf); + this._endoWnafT1 = new Array(4); + this._endoWnafT2 = new Array(4); + } + inherits(ShortCurve, Base); + module.exports = ShortCurve; + + ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) { + // No efficient endomorphism + if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1) return; + + // Compute beta and lambda, that lambda * P = (beta * Px; Py) + var beta; + var lambda; + if (conf.beta) { + beta = new bn(conf.beta, 16).toRed(this.red); + } else { + var betas = this._getEndoRoots(this.p); + // Choose the smallest beta + beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1]; + beta = beta.toRed(this.red); + } + if (conf.lambda) { + lambda = new bn(conf.lambda, 16); + } else { + // Choose the lambda that is matching selected beta + var lambdas = this._getEndoRoots(this.n); + if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) { + lambda = lambdas[0]; + } else { + lambda = lambdas[1]; + assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0); + } + } - this.deriveKeys(state, options.key); -} -inherits(DES, Cipher); -module.exports = DES; - -DES.create = function create(options) { - return new DES(options); -}; - -var shiftTable = [ - 1, 1, 2, 2, 2, 2, 2, 2, - 1, 2, 2, 2, 2, 2, 2, 1 -]; - -DES.prototype.deriveKeys = function deriveKeys(state, key) { - state.keys = new Array(16 * 2); - - assert.equal(key.length, this.blockSize, 'Invalid key length'); - - var kL = utils.readUInt32BE(key, 0); - var kR = utils.readUInt32BE(key, 4); - - utils.pc1(kL, kR, state.tmp, 0); - kL = state.tmp[0]; - kR = state.tmp[1]; - for (var i = 0; i < state.keys.length; i += 2) { - var shift = shiftTable[i >>> 1]; - kL = utils.r28shl(kL, shift); - kR = utils.r28shl(kR, shift); - utils.pc2(kL, kR, state.keys, i); - } -}; + // Get basis vectors, used for balanced length-two representation + var basis; + if (conf.basis) { + basis = conf.basis.map(function(vec) { + return { + a: new bn(vec.a, 16), + b: new bn(vec.b, 16), + }; + }); + } else { + basis = this._getEndoBasis(lambda); + } -DES.prototype._update = function _update(inp, inOff, out, outOff) { - var state = this._desState; + return { + beta: beta, + lambda: lambda, + basis: basis, + }; + }; - var l = utils.readUInt32BE(inp, inOff); - var r = utils.readUInt32BE(inp, inOff + 4); + ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) { + // Find roots of for x^2 + x + 1 in F + // Root = (-1 +- Sqrt(-3)) / 2 + // + var red = num === this.p ? this.red : bn.mont(num); + var tinv = new bn(2).toRed(red).redInvm(); + var ntinv = tinv.redNeg(); + + var s = new bn(3) + .toRed(red) + .redNeg() + .redSqrt() + .redMul(tinv); + + var l1 = ntinv.redAdd(s).fromRed(); + var l2 = ntinv.redSub(s).fromRed(); + return [l1, l2]; + }; - // Initial Permutation - utils.ip(l, r, state.tmp, 0); - l = state.tmp[0]; - r = state.tmp[1]; + ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) { + // aprxSqrt >= sqrt(this.n) + var aprxSqrt = this.n.shrn(Math.floor(this.n.bitLength() / 2)); + + // 3.74 + // Run EGCD, until r(L + 1) < aprxSqrt + var u = lambda; + var v = this.n.clone(); + var x1 = new bn(1); + var y1 = new bn(0); + var x2 = new bn(0); + var y2 = new bn(1); + + // NOTE: all vectors are roots of: a + b * lambda = 0 (mod n) + var a0; + var b0; + // First vector + var a1; + var b1; + // Second vector + var a2; + var b2; + + var prevR; + var i = 0; + var r; + var x; + while (u.cmpn(0) !== 0) { + var q = v.div(u); + r = v.sub(q.mul(u)); + x = x2.sub(q.mul(x1)); + var y = y2.sub(q.mul(y1)); + + if (!a1 && r.cmp(aprxSqrt) < 0) { + a0 = prevR.neg(); + b0 = x1; + a1 = r.neg(); + b1 = x; + } else if (a1 && ++i === 2) { + break; + } + prevR = r; + + v = u; + u = r; + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + } + a2 = r.neg(); + b2 = x; + + var len1 = a1.sqr().add(b1.sqr()); + var len2 = a2.sqr().add(b2.sqr()); + if (len2.cmp(len1) >= 0) { + a2 = a0; + b2 = b0; + } - if (this.type === 'encrypt') - this._encrypt(state, l, r, state.tmp, 0); - else - this._decrypt(state, l, r, state.tmp, 0); + // Normalize signs + if (a1.sign) { + a1 = a1.neg(); + b1 = b1.neg(); + } + if (a2.sign) { + a2 = a2.neg(); + b2 = b2.neg(); + } - l = state.tmp[0]; - r = state.tmp[1]; + return [{ a: a1, b: b1 }, { a: a2, b: b2 }]; + }; - utils.writeUInt32BE(out, l, outOff); - utils.writeUInt32BE(out, r, outOff + 4); -}; + ShortCurve.prototype._endoSplit = function _endoSplit(k) { + var basis = this.endo.basis; + var v1 = basis[0]; + var v2 = basis[1]; + + var c1 = v2.b.mul(k).divRound(this.n); + var c2 = v1.b + .neg() + .mul(k) + .divRound(this.n); + + var p1 = c1.mul(v1.a); + var p2 = c2.mul(v2.a); + var q1 = c1.mul(v1.b); + var q2 = c2.mul(v2.b); + + // Calculate answer + var k1 = k.sub(p1).sub(p2); + var k2 = q1.add(q2).neg(); + return { k1: k1, k2: k2 }; + }; -DES.prototype._pad = function _pad(buffer, off) { - var value = buffer.length - off; - for (var i = off; i < buffer.length; i++) - buffer[i] = value; + ShortCurve.prototype.pointFromX = function pointFromX(odd, x) { + x = new bn(x, 16); + if (!x.red) x = x.toRed(this.red); - return true; -}; + var y2 = x + .redSqr() + .redMul(x) + .redIAdd(x.redMul(this.a)) + .redIAdd(this.b); + var y = y2.redSqrt(); -DES.prototype._unpad = function _unpad(buffer) { - var pad = buffer[buffer.length - 1]; - for (var i = buffer.length - pad; i < buffer.length; i++) - assert.equal(buffer[i], pad); + // XXX Is there any way to tell if the number is odd without converting it + // to non-red form? + var isOdd = y.fromRed().isOdd(); + if ((odd && !isOdd) || (!odd && isOdd)) y = y.redNeg(); - return buffer.slice(0, buffer.length - pad); -}; + return this.point(x, y); + }; -DES.prototype._encrypt = function _encrypt(state, lStart, rStart, out, off) { - var l = lStart; - var r = rStart; + ShortCurve.prototype.validate = function validate(point) { + if (point.inf) return true; + + var x = point.x; + var y = point.y; + + var ax = this.a.redMul(x); + var rhs = x + .redSqr() + .redMul(x) + .redIAdd(ax) + .redIAdd(this.b); + return ( + y + .redSqr() + .redISub(rhs) + .cmpn(0) === 0 + ); + }; - // Apply f() x16 times - for (var i = 0; i < state.keys.length; i += 2) { - var keyL = state.keys[i]; - var keyR = state.keys[i + 1]; + ShortCurve.prototype._endoWnafMulAdd = function _endoWnafMulAdd(points, coeffs) { + var npoints = this._endoWnafT1; + var ncoeffs = this._endoWnafT2; + for (var i = 0; i < points.length; i++) { + var split = this._endoSplit(coeffs[i]); + var p = points[i]; + var beta = p._getBeta(); + + if (split.k1.sign) { + split.k1.sign = !split.k1.sign; + p = p.neg(true); + } + if (split.k2.sign) { + split.k2.sign = !split.k2.sign; + beta = beta.neg(true); + } - // f(r, k) - utils.expand(r, state.tmp, 0); + npoints[i * 2] = p; + npoints[i * 2 + 1] = beta; + ncoeffs[i * 2] = split.k1; + ncoeffs[i * 2 + 1] = split.k2; + } + var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2); - keyL ^= state.tmp[0]; - keyR ^= state.tmp[1]; - var s = utils.substitute(keyL, keyR); - var f = utils.permute(s); + // Clean-up references to points and coefficients + for (var j = 0; j < i * 2; j++) { + npoints[j] = null; + ncoeffs[j] = null; + } + return res; + }; - var t = r; - r = (l ^ f) >>> 0; - l = t; - } + function Point(curve, x, y, isRed) { + Base.BasePoint.call(this, curve, 'affine'); + if (x === null && y === null) { + this.x = null; + this.y = null; + this.inf = true; + } else { + this.x = new bn(x, 16); + this.y = new bn(y, 16); + // Force redgomery representation when loading from JSON + if (isRed) { + this.x.forceRed(this.curve.red); + this.y.forceRed(this.curve.red); + } + if (!this.x.red) this.x = this.x.toRed(this.curve.red); + if (!this.y.red) this.y = this.y.toRed(this.curve.red); + this.inf = false; + } + } + inherits(Point, Base.BasePoint); - // Reverse Initial Permutation - utils.rip(r, l, out, off); -}; + ShortCurve.prototype.point = function point(x, y, isRed) { + return new Point(this, x, y, isRed); + }; -DES.prototype._decrypt = function _decrypt(state, lStart, rStart, out, off) { - var l = rStart; - var r = lStart; + ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) { + return Point.fromJSON(this, obj, red); + }; - // Apply f() x16 times - for (var i = state.keys.length - 2; i >= 0; i -= 2) { - var keyL = state.keys[i]; - var keyR = state.keys[i + 1]; + Point.prototype._getBeta = function _getBeta() { + if (!this.curve.endo) return; - // f(r, k) - utils.expand(l, state.tmp, 0); + var pre = this.precomputed; + if (pre && pre.beta) return pre.beta; - keyL ^= state.tmp[0]; - keyR ^= state.tmp[1]; - var s = utils.substitute(keyL, keyR); - var f = utils.permute(s); + var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y); + if (pre) { + var curve = this.curve; + var endoMul = function(p) { + return curve.point(p.x.redMul(curve.endo.beta), p.y); + }; + pre.beta = beta; + beta.precomputed = { + beta: null, + naf: pre.naf && { + wnd: pre.naf.wnd, + points: pre.naf.points.map(endoMul), + }, + doubles: pre.doubles && { + step: pre.doubles.step, + points: pre.doubles.points.map(endoMul), + }, + }; + } + return beta; + }; - var t = l; - l = (r ^ f) >>> 0; - r = t; - } + Point.prototype.toJSON = function toJSON() { + if (!this.precomputed) return [this.x, this.y]; + + return [ + this.x, + this.y, + this.precomputed && { + doubles: this.precomputed.doubles && { + step: this.precomputed.doubles.step, + points: this.precomputed.doubles.points.slice(1), + }, + naf: this.precomputed.naf && { + wnd: this.precomputed.naf.wnd, + points: this.precomputed.naf.points.slice(1), + }, + }, + ]; + }; - // Reverse Initial Permutation - utils.rip(l, r, out, off); -}; - -},{"../des":140,"inherits":184,"minimalistic-assert":192}],144:[function(require,module,exports){ -'use strict'; - -var assert = require('minimalistic-assert'); -var inherits = require('inherits'); - -var des = require('../des'); -var Cipher = des.Cipher; -var DES = des.DES; - -function EDEState(type, key) { - assert.equal(key.length, 24, 'Invalid key length'); - - var k1 = key.slice(0, 8); - var k2 = key.slice(8, 16); - var k3 = key.slice(16, 24); - - if (type === 'encrypt') { - this.ciphers = [ - DES.create({ type: 'encrypt', key: k1 }), - DES.create({ type: 'decrypt', key: k2 }), - DES.create({ type: 'encrypt', key: k3 }) - ]; - } else { - this.ciphers = [ - DES.create({ type: 'decrypt', key: k3 }), - DES.create({ type: 'encrypt', key: k2 }), - DES.create({ type: 'decrypt', key: k1 }) - ]; - } -} + Point.fromJSON = function fromJSON(curve, obj, red) { + if (typeof obj === 'string') obj = JSON.parse(obj); + var res = curve.point(obj[0], obj[1], red); + if (!obj[2]) return res; -function EDE(options) { - Cipher.call(this, options); + function obj2point(obj) { + return curve.point(obj[0], obj[1], red); + } - var state = new EDEState(this.type, this.options.key); - this._edeState = state; -} -inherits(EDE, Cipher); - -module.exports = EDE; - -EDE.create = function create(options) { - return new EDE(options); -}; - -EDE.prototype._update = function _update(inp, inOff, out, outOff) { - var state = this._edeState; - - state.ciphers[0]._update(inp, inOff, out, outOff); - state.ciphers[1]._update(out, outOff, out, outOff); - state.ciphers[2]._update(out, outOff, out, outOff); -}; - -EDE.prototype._pad = DES.prototype._pad; -EDE.prototype._unpad = DES.prototype._unpad; - -},{"../des":140,"inherits":184,"minimalistic-assert":192}],145:[function(require,module,exports){ -'use strict'; - -exports.readUInt32BE = function readUInt32BE(bytes, off) { - var res = (bytes[0 + off] << 24) | - (bytes[1 + off] << 16) | - (bytes[2 + off] << 8) | - bytes[3 + off]; - return res >>> 0; -}; - -exports.writeUInt32BE = function writeUInt32BE(bytes, value, off) { - bytes[0 + off] = value >>> 24; - bytes[1 + off] = (value >>> 16) & 0xff; - bytes[2 + off] = (value >>> 8) & 0xff; - bytes[3 + off] = value & 0xff; -}; - -exports.ip = function ip(inL, inR, out, off) { - var outL = 0; - var outR = 0; - - for (var i = 6; i >= 0; i -= 2) { - for (var j = 0; j <= 24; j += 8) { - outL <<= 1; - outL |= (inR >>> (j + i)) & 1; - } - for (var j = 0; j <= 24; j += 8) { - outL <<= 1; - outL |= (inL >>> (j + i)) & 1; - } - } + var pre = obj[2]; + res.precomputed = { + beta: null, + doubles: pre.doubles && { + step: pre.doubles.step, + points: [res].concat(pre.doubles.points.map(obj2point)), + }, + naf: pre.naf && { + wnd: pre.naf.wnd, + points: [res].concat(pre.naf.points.map(obj2point)), + }, + }; + return res; + }; - for (var i = 6; i >= 0; i -= 2) { - for (var j = 1; j <= 25; j += 8) { - outR <<= 1; - outR |= (inR >>> (j + i)) & 1; - } - for (var j = 1; j <= 25; j += 8) { - outR <<= 1; - outR |= (inL >>> (j + i)) & 1; - } - } + Point.prototype.inspect = function inspect() { + if (this.isInfinity()) return ''; + return ''; + }; - out[off + 0] = outL >>> 0; - out[off + 1] = outR >>> 0; -}; + Point.prototype.isInfinity = function isInfinity() { + return this.inf; + }; -exports.rip = function rip(inL, inR, out, off) { - var outL = 0; - var outR = 0; + Point.prototype.add = function add(p) { + // O + P = P + if (this.inf) return p; - for (var i = 0; i < 4; i++) { - for (var j = 24; j >= 0; j -= 8) { - outL <<= 1; - outL |= (inR >>> (j + i)) & 1; - outL <<= 1; - outL |= (inL >>> (j + i)) & 1; - } - } - for (var i = 4; i < 8; i++) { - for (var j = 24; j >= 0; j -= 8) { - outR <<= 1; - outR |= (inR >>> (j + i)) & 1; - outR <<= 1; - outR |= (inL >>> (j + i)) & 1; - } - } + // P + O = P + if (p.inf) return this; - out[off + 0] = outL >>> 0; - out[off + 1] = outR >>> 0; -}; - -exports.pc1 = function pc1(inL, inR, out, off) { - var outL = 0; - var outR = 0; - - // 7, 15, 23, 31, 39, 47, 55, 63 - // 6, 14, 22, 30, 39, 47, 55, 63 - // 5, 13, 21, 29, 39, 47, 55, 63 - // 4, 12, 20, 28 - for (var i = 7; i >= 5; i--) { - for (var j = 0; j <= 24; j += 8) { - outL <<= 1; - outL |= (inR >> (j + i)) & 1; - } - for (var j = 0; j <= 24; j += 8) { - outL <<= 1; - outL |= (inL >> (j + i)) & 1; - } - } - for (var j = 0; j <= 24; j += 8) { - outL <<= 1; - outL |= (inR >> (j + i)) & 1; - } + // P + P = 2P + if (this.eq(p)) return this.dbl(); - // 1, 9, 17, 25, 33, 41, 49, 57 - // 2, 10, 18, 26, 34, 42, 50, 58 - // 3, 11, 19, 27, 35, 43, 51, 59 - // 36, 44, 52, 60 - for (var i = 1; i <= 3; i++) { - for (var j = 0; j <= 24; j += 8) { - outR <<= 1; - outR |= (inR >> (j + i)) & 1; - } - for (var j = 0; j <= 24; j += 8) { - outR <<= 1; - outR |= (inL >> (j + i)) & 1; - } - } - for (var j = 0; j <= 24; j += 8) { - outR <<= 1; - outR |= (inL >> (j + i)) & 1; - } + // P + (-P) = O + if (this.neg().eq(p)) return this.curve.point(null, null); - out[off + 0] = outL >>> 0; - out[off + 1] = outR >>> 0; -}; - -exports.r28shl = function r28shl(num, shift) { - return ((num << shift) & 0xfffffff) | (num >>> (28 - shift)); -}; - -var pc2table = [ - // inL => outL - 14, 11, 17, 4, 27, 23, 25, 0, - 13, 22, 7, 18, 5, 9, 16, 24, - 2, 20, 12, 21, 1, 8, 15, 26, - - // inR => outR - 15, 4, 25, 19, 9, 1, 26, 16, - 5, 11, 23, 8, 12, 7, 17, 0, - 22, 3, 10, 14, 6, 20, 27, 24 -]; - -exports.pc2 = function pc2(inL, inR, out, off) { - var outL = 0; - var outR = 0; - - var len = pc2table.length >>> 1; - for (var i = 0; i < len; i++) { - outL <<= 1; - outL |= (inL >>> pc2table[i]) & 0x1; - } - for (var i = len; i < pc2table.length; i++) { - outR <<= 1; - outR |= (inR >>> pc2table[i]) & 0x1; - } + // P + Q = O + if (this.x.cmp(p.x) === 0) return this.curve.point(null, null); - out[off + 0] = outL >>> 0; - out[off + 1] = outR >>> 0; -}; + var c = this.y.redSub(p.y); + if (c.cmpn(0) !== 0) c = c.redMul(this.x.redSub(p.x).redInvm()); + var nx = c + .redSqr() + .redISub(this.x) + .redISub(p.x); + var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); + return this.curve.point(nx, ny); + }; -exports.expand = function expand(r, out, off) { - var outL = 0; - var outR = 0; + Point.prototype.dbl = function dbl() { + if (this.inf) return this; - outL = ((r & 1) << 5) | (r >>> 27); - for (var i = 23; i >= 15; i -= 4) { - outL <<= 6; - outL |= (r >>> i) & 0x3f; - } - for (var i = 11; i >= 3; i -= 4) { - outR |= (r >>> i) & 0x3f; - outR <<= 6; - } - outR |= ((r & 0x1f) << 1) | (r >>> 31); - - out[off + 0] = outL >>> 0; - out[off + 1] = outR >>> 0; -}; - -var sTable = [ - 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, - 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, - 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, - 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13, - - 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, - 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, - 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, - 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9, - - 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, - 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, - 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, - 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12, - - 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, - 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, - 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, - 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14, - - 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, - 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, - 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13, - 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3, - - 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, - 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, - 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, - 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13, - - 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, - 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, - 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, - 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12, - - 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, - 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, - 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, - 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11 -]; - -exports.substitute = function substitute(inL, inR) { - var out = 0; - for (var i = 0; i < 4; i++) { - var b = (inL >>> (18 - i * 6)) & 0x3f; - var sb = sTable[i * 0x40 + b]; - - out <<= 4; - out |= sb; - } - for (var i = 0; i < 4; i++) { - var b = (inR >>> (18 - i * 6)) & 0x3f; - var sb = sTable[4 * 0x40 + i * 0x40 + b]; + // 2P = O + var ys1 = this.y.redAdd(this.y); + if (ys1.cmpn(0) === 0) return this.curve.point(null, null); - out <<= 4; - out |= sb; - } - return out >>> 0; -}; - -var permuteTable = [ - 16, 25, 12, 11, 3, 20, 4, 15, 31, 17, 9, 6, 27, 14, 1, 22, - 30, 24, 8, 18, 0, 5, 29, 23, 13, 19, 2, 26, 10, 21, 28, 7 -]; - -exports.permute = function permute(num) { - var out = 0; - for (var i = 0; i < permuteTable.length; i++) { - out <<= 1; - out |= (num >>> permuteTable[i]) & 0x1; - } - return out >>> 0; -}; + var a = this.curve.a; -exports.padSplit = function padSplit(num, size, group) { - var str = num.toString(2); - while (str.length < size) - str = '0' + str; + var x2 = this.x.redSqr(); + var dyinv = ys1.redInvm(); + var c = x2 + .redAdd(x2) + .redIAdd(x2) + .redIAdd(a) + .redMul(dyinv); - var out = []; - for (var i = 0; i < size; i += group) - out.push(str.slice(i, i + group)); - return out.join(' '); -}; + var nx = c.redSqr().redISub(this.x.redAdd(this.x)); + var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); + return this.curve.point(nx, ny); + }; -},{}],146:[function(require,module,exports){ -(function (Buffer){ -var generatePrime = require('./lib/generatePrime') -var primes = require('./lib/primes.json') + Point.prototype.getX = function getX() { + return this.x.fromRed(); + }; -var DH = require('./lib/dh') + Point.prototype.getY = function getY() { + return this.y.fromRed(); + }; -function getDiffieHellman (mod) { - var prime = new Buffer(primes[mod].prime, 'hex') - var gen = new Buffer(primes[mod].gen, 'hex') + Point.prototype.mul = function mul(k) { + k = new bn(k, 16); - return new DH(prime, gen) -} + if (this.precomputed && this.precomputed.doubles) return this.curve._fixedNafMul(this, k); + else if (this.curve.endo) return this.curve._endoWnafMulAdd([this], [k]); + else return this.curve._wnafMul(this, k); + }; -var ENCODINGS = { - 'binary': true, 'hex': true, 'base64': true -} + Point.prototype.mulAdd = function mulAdd(k1, p2, k2) { + var points = [this, p2]; + var coeffs = [k1, k2]; + if (this.curve.endo) return this.curve._endoWnafMulAdd(points, coeffs); + else return this.curve._wnafMulAdd(1, points, coeffs, 2); + }; -function createDiffieHellman (prime, enc, generator, genc) { - if (Buffer.isBuffer(enc) || ENCODINGS[enc] === undefined) { - return createDiffieHellman(prime, 'binary', enc, generator) - } + Point.prototype.eq = function eq(p) { + return this === p || (this.inf === p.inf && (this.inf || (this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0))); + }; - enc = enc || 'binary' - genc = genc || 'binary' - generator = generator || new Buffer([2]) + Point.prototype.neg = function neg(_precompute) { + if (this.inf) return this; - if (!Buffer.isBuffer(generator)) { - generator = new Buffer(generator, genc) - } + var res = this.curve.point(this.x, this.y.redNeg()); + if (_precompute && this.precomputed) { + var pre = this.precomputed; + var negate = function(p) { + return p.neg(); + }; + res.precomputed = { + naf: pre.naf && { + wnd: pre.naf.wnd, + points: pre.naf.points.map(negate), + }, + doubles: pre.doubles && { + step: pre.doubles.step, + points: pre.doubles.points.map(negate), + }, + }; + } + return res; + }; - if (typeof prime === 'number') { - return new DH(generatePrime(prime, generator), generator, true) - } + Point.prototype.toJ = function toJ() { + if (this.inf) return this.curve.jpoint(null, null, null); - if (!Buffer.isBuffer(prime)) { - prime = new Buffer(prime, enc) - } + var res = this.curve.jpoint(this.x, this.y, this.curve.one); + return res; + }; - return new DH(prime, generator, true) -} + function JPoint(curve, x, y, z) { + Base.BasePoint.call(this, curve, 'jacobian'); + if (x === null && y === null && z === null) { + this.x = this.curve.one; + this.y = this.curve.one; + this.z = new bn(0); + } else { + this.x = new bn(x, 16); + this.y = new bn(y, 16); + this.z = new bn(z, 16); + } + if (!this.x.red) this.x = this.x.toRed(this.curve.red); + if (!this.y.red) this.y = this.y.toRed(this.curve.red); + if (!this.z.red) this.z = this.z.toRed(this.curve.red); -exports.DiffieHellmanGroup = exports.createDiffieHellmanGroup = exports.getDiffieHellman = getDiffieHellman -exports.createDiffieHellman = exports.DiffieHellman = createDiffieHellman - -}).call(this,require("buffer").Buffer) -},{"./lib/dh":147,"./lib/generatePrime":148,"./lib/primes.json":149,"buffer":113}],147:[function(require,module,exports){ -(function (Buffer){ -var BN = require('bn.js'); -var MillerRabin = require('miller-rabin'); -var millerRabin = new MillerRabin(); -var TWENTYFOUR = new BN(24); -var ELEVEN = new BN(11); -var TEN = new BN(10); -var THREE = new BN(3); -var SEVEN = new BN(7); -var primes = require('./generatePrime'); -var randomBytes = require('randombytes'); -module.exports = DH; - -function setPublicKey(pub, enc) { - enc = enc || 'utf8'; - if (!Buffer.isBuffer(pub)) { - pub = new Buffer(pub, enc); - } - this._pub = new BN(pub); - return this; -} + this.zOne = this.z === this.curve.one; + } + inherits(JPoint, Base.BasePoint); -function setPrivateKey(priv, enc) { - enc = enc || 'utf8'; - if (!Buffer.isBuffer(priv)) { - priv = new Buffer(priv, enc); - } - this._priv = new BN(priv); - return this; -} + ShortCurve.prototype.jpoint = function jpoint(x, y, z) { + return new JPoint(this, x, y, z); + }; -var primeCache = {}; -function checkPrime(prime, generator) { - var gen = generator.toString('hex'); - var hex = [gen, prime.toString(16)].join('_'); - if (hex in primeCache) { - return primeCache[hex]; - } - var error = 0; - - if (prime.isEven() || - !primes.simpleSieve || - !primes.fermatTest(prime) || - !millerRabin.test(prime)) { - //not a prime so +1 - error += 1; - - if (gen === '02' || gen === '05') { - // we'd be able to check the generator - // it would fail so +8 - error += 8; - } else { - //we wouldn't be able to test the generator - // so +4 - error += 4; - } - primeCache[hex] = error; - return error; - } - if (!millerRabin.test(prime.shrn(1))) { - //not a safe prime - error += 2; - } - var rem; - switch (gen) { - case '02': - if (prime.mod(TWENTYFOUR).cmp(ELEVEN)) { - // unsuidable generator - error += 8; - } - break; - case '05': - rem = prime.mod(TEN); - if (rem.cmp(THREE) && rem.cmp(SEVEN)) { - // prime mod 10 needs to equal 3 or 7 - error += 8; - } - break; - default: - error += 4; - } - primeCache[hex] = error; - return error; -} + JPoint.prototype.toP = function toP() { + if (this.isInfinity()) return this.curve.point(null, null); -function DH(prime, generator, malleable) { - this.setGenerator(generator); - this.__prime = new BN(prime); - this._prime = BN.mont(this.__prime); - this._primeLen = prime.length; - this._pub = undefined; - this._priv = undefined; - this._primeCode = undefined; - if (malleable) { - this.setPublicKey = setPublicKey; - this.setPrivateKey = setPrivateKey; - } else { - this._primeCode = 8; - } -} -Object.defineProperty(DH.prototype, 'verifyError', { - enumerable: true, - get: function () { - if (typeof this._primeCode !== 'number') { - this._primeCode = checkPrime(this.__prime, this.__gen); - } - return this._primeCode; - } -}); -DH.prototype.generateKeys = function () { - if (!this._priv) { - this._priv = new BN(randomBytes(this._primeLen)); - } - this._pub = this._gen.toRed(this._prime).redPow(this._priv).fromRed(); - return this.getPublicKey(); -}; - -DH.prototype.computeSecret = function (other) { - other = new BN(other); - other = other.toRed(this._prime); - var secret = other.redPow(this._priv).fromRed(); - var out = new Buffer(secret.toArray()); - var prime = this.getPrime(); - if (out.length < prime.length) { - var front = new Buffer(prime.length - out.length); - front.fill(0); - out = Buffer.concat([front, out]); - } - return out; -}; + var zinv = this.z.redInvm(); + var zinv2 = zinv.redSqr(); + var ax = this.x.redMul(zinv2); + var ay = this.y.redMul(zinv2).redMul(zinv); -DH.prototype.getPublicKey = function getPublicKey(enc) { - return formatReturnValue(this._pub, enc); -}; + return this.curve.point(ax, ay); + }; -DH.prototype.getPrivateKey = function getPrivateKey(enc) { - return formatReturnValue(this._priv, enc); -}; + JPoint.prototype.neg = function neg() { + return this.curve.jpoint(this.x, this.y.redNeg(), this.z); + }; -DH.prototype.getPrime = function (enc) { - return formatReturnValue(this.__prime, enc); -}; + JPoint.prototype.add = function add(p) { + // O + P = P + if (this.isInfinity()) return p; + + // P + O = P + if (p.isInfinity()) return this; + + // 12M + 4S + 7A + var pz2 = p.z.redSqr(); + var z2 = this.z.redSqr(); + var u1 = this.x.redMul(pz2); + var u2 = p.x.redMul(z2); + var s1 = this.y.redMul(pz2.redMul(p.z)); + var s2 = p.y.redMul(z2.redMul(this.z)); + + var h = u1.redSub(u2); + var r = s1.redSub(s2); + if (h.cmpn(0) === 0) { + if (r.cmpn(0) !== 0) return this.curve.jpoint(null, null, null); + else return this.dbl(); + } -DH.prototype.getGenerator = function (enc) { - return formatReturnValue(this._gen, enc); -}; + var h2 = h.redSqr(); + var h3 = h2.redMul(h); + var v = u1.redMul(h2); -DH.prototype.setGenerator = function (gen, enc) { - enc = enc || 'utf8'; - if (!Buffer.isBuffer(gen)) { - gen = new Buffer(gen, enc); - } - this.__gen = gen; - this._gen = new BN(gen); - return this; -}; - -function formatReturnValue(bn, enc) { - var buf = new Buffer(bn.toArray()); - if (!enc) { - return buf; - } else { - return buf.toString(enc); - } -} + var nx = r + .redSqr() + .redIAdd(h3) + .redISub(v) + .redISub(v); + var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); + var nz = this.z.redMul(p.z).redMul(h); -}).call(this,require("buffer").Buffer) -},{"./generatePrime":148,"bn.js":150,"buffer":113,"miller-rabin":190,"randombytes":217}],148:[function(require,module,exports){ -var randomBytes = require('randombytes'); -module.exports = findPrime; -findPrime.simpleSieve = simpleSieve; -findPrime.fermatTest = fermatTest; -var BN = require('bn.js'); -var TWENTYFOUR = new BN(24); -var MillerRabin = require('miller-rabin'); -var millerRabin = new MillerRabin(); -var ONE = new BN(1); -var TWO = new BN(2); -var FIVE = new BN(5); -var SIXTEEN = new BN(16); -var EIGHT = new BN(8); -var TEN = new BN(10); -var THREE = new BN(3); -var SEVEN = new BN(7); -var ELEVEN = new BN(11); -var FOUR = new BN(4); -var TWELVE = new BN(12); -var primes = null; - -function _getPrimes() { - if (primes !== null) - return primes; - - var limit = 0x100000; - var res = []; - res[0] = 2; - for (var i = 1, k = 3; k < limit; k += 2) { - var sqrt = Math.ceil(Math.sqrt(k)); - for (var j = 0; j < i && res[j] <= sqrt; j++) - if (k % res[j] === 0) - break; - - if (i !== j && res[j] <= sqrt) - continue; - - res[i++] = k; - } - primes = res; - return res; -} + return this.curve.jpoint(nx, ny, nz); + }; -function simpleSieve(p) { - var primes = _getPrimes(); + JPoint.prototype.mixedAdd = function mixedAdd(p) { + // O + P = P + if (this.isInfinity()) return p.toJ(); + + // P + O = P + if (p.isInfinity()) return this; + + // 8M + 3S + 7A + var z2 = this.z.redSqr(); + var u1 = this.x; + var u2 = p.x.redMul(z2); + var s1 = this.y; + var s2 = p.y.redMul(z2).redMul(this.z); + + var h = u1.redSub(u2); + var r = s1.redSub(s2); + if (h.cmpn(0) === 0) { + if (r.cmpn(0) !== 0) return this.curve.jpoint(null, null, null); + else return this.dbl(); + } - for (var i = 0; i < primes.length; i++) - if (p.modn(primes[i]) === 0) { - if (p.cmpn(primes[i]) === 0) { - return true; - } else { - return false; - } - } + var h2 = h.redSqr(); + var h3 = h2.redMul(h); + var v = u1.redMul(h2); - return true; -} + var nx = r + .redSqr() + .redIAdd(h3) + .redISub(v) + .redISub(v); + var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); + var nz = this.z.redMul(h); -function fermatTest(p) { - var red = BN.mont(p); - return TWO.toRed(red).redPow(p.subn(1)).fromRed().cmpn(1) === 0; -} + return this.curve.jpoint(nx, ny, nz); + }; -function findPrime(bits, gen) { - if (bits < 16) { - // this is what openssl does - if (gen === 2 || gen === 5) { - return new BN([0x8c, 0x7b]); - } else { - return new BN([0x8c, 0x27]); - } - } - gen = new BN(gen); + JPoint.prototype.dblp = function dblp(pow) { + if (pow === 0) return this; + if (this.isInfinity()) return this; + if (!pow) return this.dbl(); - var num, n2; + if (this.curve.zeroA || this.curve.threeA) { + var r = this; + for (var i = 0; i < pow; i++) r = r.dbl(); + return r; + } - while (true) { - num = new BN(randomBytes(Math.ceil(bits / 8))); - while (num.bitLength() > bits) { - num.ishrn(1); - } - if (num.isEven()) { - num.iadd(ONE); - } - if (!num.testn(1)) { - num.iadd(TWO); - } - if (!gen.cmp(TWO)) { - while (num.mod(TWENTYFOUR).cmp(ELEVEN)) { - num.iadd(FOUR); - } - } else if (!gen.cmp(FIVE)) { - while (num.mod(TEN).cmp(THREE)) { - num.iadd(FOUR); - } - } - n2 = num.shrn(1); - if (simpleSieve(n2) && simpleSieve(num) && - fermatTest(n2) && fermatTest(num) && - millerRabin.test(n2) && millerRabin.test(num)) { - return num; - } - } + // 1M + 2S + 1A + N * (4S + 5M + 8A) + // N = 1 => 6M + 6S + 9A + var a = this.curve.a; + var tinv = this.curve.tinv; + + var jx = this.x; + var jy = this.y; + var jz = this.z; + var jz4 = jz.redSqr().redSqr(); + + // Reuse results + var jyd = jy.redAdd(jy); + for (var i = 0; i < pow; i++) { + var jx2 = jx.redSqr(); + var jyd2 = jyd.redSqr(); + var jyd4 = jyd2.redSqr(); + var c = jx2 + .redAdd(jx2) + .redIAdd(jx2) + .redIAdd(a.redMul(jz4)); + + var t1 = jx.redMul(jyd2); + var nx = c.redSqr().redISub(t1.redAdd(t1)); + var t2 = t1.redISub(nx); + var dny = c.redMul(t2); + dny = dny.redIAdd(dny).redISub(jyd4); + var nz = jyd.redMul(jz); + if (i + 1 < pow) jz4 = jz4.redMul(jyd4); + + jx = nx; + jz = nz; + jyd = dny; + } -} + return this.curve.jpoint(jx, jyd.redMul(tinv), jz); + }; -},{"bn.js":150,"miller-rabin":190,"randombytes":217}],149:[function(require,module,exports){ -module.exports={ - "modp1": { - "gen": "02", - "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a63a3620ffffffffffffffff" - }, - "modp2": { - "gen": "02", - "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff" - }, - "modp5": { - "gen": "02", - "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff" - }, - "modp14": { - "gen": "02", - "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff" - }, - "modp15": { - "gen": "02", - "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a93ad2caffffffffffffffff" - }, - "modp16": { - "gen": "02", - "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c934063199ffffffffffffffff" - }, - "modp17": { - "gen": "02", - "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dcc4024ffffffffffffffff" - }, - "modp18": { - "gen": "02", - "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dbe115974a3926f12fee5e438777cb6a932df8cd8bec4d073b931ba3bc832b68d9dd300741fa7bf8afc47ed2576f6936ba424663aab639c5ae4f5683423b4742bf1c978238f16cbe39d652de3fdb8befc848ad922222e04a4037c0713eb57a81a23f0c73473fc646cea306b4bcbc8862f8385ddfa9d4b7fa2c087e879683303ed5bdd3a062b3cf5b3a278a66d2a13f83f44f82ddf310ee074ab6a364597e899a0255dc164f31cc50846851df9ab48195ded7ea1b1d510bd7ee74d73faf36bc31ecfa268359046f4eb879f924009438b481c6cd7889a002ed5ee382bc9190da6fc026e479558e4475677e9aa9e3050e2765694dfc81f56e880b96e7160c980dd98edd3dfffffffffffffffff" - } -} -},{}],150:[function(require,module,exports){ -arguments[4][59][0].apply(exports,arguments) -},{"buffer":64,"dup":59}],151:[function(require,module,exports){ -'use strict'; - -var elliptic = exports; - -elliptic.version = require('../package.json').version; -elliptic.utils = require('./elliptic/utils'); -elliptic.rand = require('brorand'); -elliptic.hmacDRBG = require('./elliptic/hmac-drbg'); -elliptic.curve = require('./elliptic/curve'); -elliptic.curves = require('./elliptic/curves'); - -// Protocols -elliptic.ec = require('./elliptic/ec'); - -},{"../package.json":164,"./elliptic/curve":154,"./elliptic/curves":157,"./elliptic/ec":158,"./elliptic/hmac-drbg":161,"./elliptic/utils":163,"brorand":63}],152:[function(require,module,exports){ -'use strict'; - -var bn = require('bn.js'); -var elliptic = require('../../elliptic'); - -var getNAF = elliptic.utils.getNAF; -var getJSF = elliptic.utils.getJSF; -var assert = elliptic.utils.assert; - -function BaseCurve(type, conf) { - this.type = type; - this.p = new bn(conf.p, 16); - - // Use Montgomery, when there is no fast reduction for the prime - this.red = conf.prime ? bn.red(conf.prime) : bn.mont(this.p); - - // Useful for many curves - this.zero = new bn(0).toRed(this.red); - this.one = new bn(1).toRed(this.red); - this.two = new bn(2).toRed(this.red); - - // Curve configuration, optional - this.n = conf.n && new bn(conf.n, 16); - this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed); - - // Temporary arrays - this._wnafT1 = new Array(4); - this._wnafT2 = new Array(4); - this._wnafT3 = new Array(4); - this._wnafT4 = new Array(4); -} -module.exports = BaseCurve; - -BaseCurve.prototype.point = function point() { - throw new Error('Not implemented'); -}; - -BaseCurve.prototype.validate = function validate() { - throw new Error('Not implemented'); -}; - -BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) { - var doubles = p._getDoubles(); - - var naf = getNAF(k, 1); - var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1); - I /= 3; - - // Translate into more windowed form - var repr = []; - for (var j = 0; j < naf.length; j += doubles.step) { - var nafW = 0; - for (var k = j + doubles.step - 1; k >= j; k--) - nafW = (nafW << 1) + naf[k]; - repr.push(nafW); - } + JPoint.prototype.dbl = function dbl() { + if (this.isInfinity()) return this; - var a = this.jpoint(null, null, null); - var b = this.jpoint(null, null, null); - for (var i = I; i > 0; i--) { - for (var j = 0; j < repr.length; j++) { - var nafW = repr[j]; - if (nafW === i) - b = b.mixedAdd(doubles.points[j]); - else if (nafW === -i) - b = b.mixedAdd(doubles.points[j].neg()); - } - a = a.add(b); - } - return a.toP(); -}; - -BaseCurve.prototype._wnafMul = function _wnafMul(p, k) { - var w = 4; - - // Precompute window - var nafPoints = p._getNAFPoints(w); - w = nafPoints.wnd; - var wnd = nafPoints.points; - - // Get NAF form - var naf = getNAF(k, w); - - // Add `this`*(N+1) for every w-NAF index - var acc = this.jpoint(null, null, null); - for (var i = naf.length - 1; i >= 0; i--) { - // Count zeroes - for (var k = 0; i >= 0 && naf[i] === 0; i--) - k++; - if (i >= 0) - k++; - acc = acc.dblp(k); - - if (i < 0) - break; - var z = naf[i]; - assert(z !== 0); - if (p.type === 'affine') { - // J +- P - if (z > 0) - acc = acc.mixedAdd(wnd[(z - 1) >> 1]); - else - acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg()); - } else { - // J +- J - if (z > 0) - acc = acc.add(wnd[(z - 1) >> 1]); - else - acc = acc.add(wnd[(-z - 1) >> 1].neg()); - } - } - return p.type === 'affine' ? acc.toP() : acc; -}; - -BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW, - points, - coeffs, - len) { - var wndWidth = this._wnafT1; - var wnd = this._wnafT2; - var naf = this._wnafT3; - - // Fill all arrays - var max = 0; - for (var i = 0; i < len; i++) { - var p = points[i]; - var nafPoints = p._getNAFPoints(defW); - wndWidth[i] = nafPoints.wnd; - wnd[i] = nafPoints.points; - } + if (this.curve.zeroA) return this._zeroDbl(); + else if (this.curve.threeA) return this._threeDbl(); + else return this._dbl(); + }; - // Comb small window NAFs - for (var i = len - 1; i >= 1; i -= 2) { - var a = i - 1; - var b = i; - if (wndWidth[a] !== 1 || wndWidth[b] !== 1) { - naf[a] = getNAF(coeffs[a], wndWidth[a]); - naf[b] = getNAF(coeffs[b], wndWidth[b]); - max = Math.max(naf[a].length, max); - max = Math.max(naf[b].length, max); - continue; - } + JPoint.prototype._zeroDbl = function _zeroDbl() { + var nx; + var ny; + var nz; + // Z = 1 + if (this.zOne) { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html + // #doubling-mdbl-2007-bl + // 1M + 5S + 14A + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // S = 2 * ((X1 + YY)^2 - XX - YYYY) + var s = this.x + .redAdd(yy) + .redSqr() + .redISub(xx) + .redISub(yyyy); + s = s.redIAdd(s); + // M = 3 * XX + a; a = 0 + var m = xx.redAdd(xx).redIAdd(xx); + // T = M ^ 2 - 2*S + var t = m + .redSqr() + .redISub(s) + .redISub(s); + + // 8 * YYYY + var yyyy8 = yyyy.redIAdd(yyyy); + yyyy8 = yyyy8.redIAdd(yyyy8); + yyyy8 = yyyy8.redIAdd(yyyy8); + + // X3 = T + nx = t; + // Y3 = M * (S - T) - 8 * YYYY + ny = m.redMul(s.redISub(t)).redISub(yyyy8); + // Z3 = 2*Y1 + nz = this.y.redAdd(this.y); + } else { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html + // #doubling-dbl-2009-l + // 2M + 5S + 13A + + // A = X1^2 + var a = this.x.redSqr(); + // B = Y1^2 + var b = this.y.redSqr(); + // C = B^2 + var c = b.redSqr(); + // D = 2 * ((X1 + B)^2 - A - C) + var d = this.x + .redAdd(b) + .redSqr() + .redISub(a) + .redISub(c); + d = d.redIAdd(d); + // E = 3 * A + var e = a.redAdd(a).redIAdd(a); + // F = E^2 + var f = e.redSqr(); + + // 8 * C + var c8 = c.redIAdd(c); + c8 = c8.redIAdd(c8); + c8 = c8.redIAdd(c8); + + // X3 = F - 2 * D + nx = f.redISub(d).redISub(d); + // Y3 = E * (D - X3) - 8 * C + ny = e.redMul(d.redISub(nx)).redISub(c8); + // Z3 = 2 * Y1 * Z1 + nz = this.y.redMul(this.z); + nz = nz.redIAdd(nz); + } - var comb = [ - points[a], /* 1 */ - null, /* 3 */ - null, /* 5 */ - points[b] /* 7 */ - ]; - - // Try to avoid Projective points, if possible - if (points[a].y.cmp(points[b].y) === 0) { - comb[1] = points[a].add(points[b]); - comb[2] = points[a].toJ().mixedAdd(points[b].neg()); - } else if (points[a].y.cmp(points[b].y.redNeg()) === 0) { - comb[1] = points[a].toJ().mixedAdd(points[b]); - comb[2] = points[a].add(points[b].neg()); - } else { - comb[1] = points[a].toJ().mixedAdd(points[b]); - comb[2] = points[a].toJ().mixedAdd(points[b].neg()); - } + return this.curve.jpoint(nx, ny, nz); + }; - var index = [ - -3, /* -1 -1 */ - -1, /* -1 0 */ - -5, /* -1 1 */ - -7, /* 0 -1 */ - 0, /* 0 0 */ - 7, /* 0 1 */ - 5, /* 1 -1 */ - 1, /* 1 0 */ - 3 /* 1 1 */ - ]; - - var jsf = getJSF(coeffs[a], coeffs[b]); - max = Math.max(jsf[0].length, max); - naf[a] = new Array(max); - naf[b] = new Array(max); - for (var j = 0; j < max; j++) { - var ja = jsf[0][j] | 0; - var jb = jsf[1][j] | 0; - - naf[a][j] = index[(ja + 1) * 3 + (jb + 1)]; - naf[b][j] = 0; - wnd[a] = comb; - } - } + JPoint.prototype._threeDbl = function _threeDbl() { + var nx; + var ny; + var nz; + // Z = 1 + if (this.zOne) { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html + // #doubling-mdbl-2007-bl + // 1M + 5S + 15A + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // S = 2 * ((X1 + YY)^2 - XX - YYYY) + var s = this.x + .redAdd(yy) + .redSqr() + .redISub(xx) + .redISub(yyyy); + s = s.redIAdd(s); + // M = 3 * XX + a + var m = xx + .redAdd(xx) + .redIAdd(xx) + .redIAdd(this.curve.a); + // T = M^2 - 2 * S + var t = m + .redSqr() + .redISub(s) + .redISub(s); + // X3 = T + nx = t; + // Y3 = M * (S - T) - 8 * YYYY + var yyyy8 = yyyy.redIAdd(yyyy); + yyyy8 = yyyy8.redIAdd(yyyy8); + yyyy8 = yyyy8.redIAdd(yyyy8); + ny = m.redMul(s.redISub(t)).redISub(yyyy8); + // Z3 = 2 * Y1 + nz = this.y.redAdd(this.y); + } else { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b + // 3M + 5S + + // delta = Z1^2 + var delta = this.z.redSqr(); + // gamma = Y1^2 + var gamma = this.y.redSqr(); + // beta = X1 * gamma + var beta = this.x.redMul(gamma); + // alpha = 3 * (X1 - delta) * (X1 + delta) + var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta)); + alpha = alpha.redAdd(alpha).redIAdd(alpha); + // X3 = alpha^2 - 8 * beta + var beta4 = beta.redIAdd(beta); + beta4 = beta4.redIAdd(beta4); + var beta8 = beta4.redAdd(beta4); + nx = alpha.redSqr().redISub(beta8); + // Z3 = (Y1 + Z1)^2 - gamma - delta + nz = this.y + .redAdd(this.z) + .redSqr() + .redISub(gamma) + .redISub(delta); + // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2 + var ggamma8 = gamma.redSqr(); + ggamma8 = ggamma8.redIAdd(ggamma8); + ggamma8 = ggamma8.redIAdd(ggamma8); + ggamma8 = ggamma8.redIAdd(ggamma8); + ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8); + } - var acc = this.jpoint(null, null, null); - var tmp = this._wnafT4; - for (var i = max; i >= 0; i--) { - var k = 0; - - while (i >= 0) { - var zero = true; - for (var j = 0; j < len; j++) { - tmp[j] = naf[j][i] | 0; - if (tmp[j] !== 0) - zero = false; - } - if (!zero) - break; - k++; - i--; - } - if (i >= 0) - k++; - acc = acc.dblp(k); - if (i < 0) - break; - - for (var j = 0; j < len; j++) { - var z = tmp[j]; - var p; - if (z === 0) - continue; - else if (z > 0) - p = wnd[j][(z - 1) >> 1]; - else if (z < 0) - p = wnd[j][(-z - 1) >> 1].neg(); - - if (p.type === 'affine') - acc = acc.mixedAdd(p); - else - acc = acc.add(p); - } - } - // Zeroify references - for (var i = 0; i < len; i++) - wnd[i] = null; - return acc.toP(); -}; - -function BasePoint(curve, type) { - this.curve = curve; - this.type = type; - this.precomputed = null; -} -BaseCurve.BasePoint = BasePoint; - -BasePoint.prototype.validate = function validate() { - return this.curve.validate(this); -}; - -BasePoint.prototype.precompute = function precompute(power) { - if (this.precomputed) - return this; - - var precomputed = { - doubles: null, - naf: null, - beta: null - }; - precomputed.naf = this._getNAFPoints(8); - precomputed.doubles = this._getDoubles(4, power); - precomputed.beta = this._getBeta(); - this.precomputed = precomputed; - - return this; -}; - -BasePoint.prototype._getDoubles = function _getDoubles(step, power) { - if (this.precomputed && this.precomputed.doubles) - return this.precomputed.doubles; - - var doubles = [ this ]; - var acc = this; - for (var i = 0; i < power; i += step) { - for (var j = 0; j < step; j++) - acc = acc.dbl(); - doubles.push(acc); - } - return { - step: step, - points: doubles - }; -}; - -BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) { - if (this.precomputed && this.precomputed.naf) - return this.precomputed.naf; - - var res = [ this ]; - var max = (1 << wnd) - 1; - var dbl = max === 1 ? null : this.dbl(); - for (var i = 1; i < max; i++) - res[i] = res[i - 1].add(dbl); - return { - wnd: wnd, - points: res - }; -}; - -BasePoint.prototype._getBeta = function _getBeta() { - return null; -}; - -BasePoint.prototype.dblp = function dblp(k) { - var r = this; - for (var i = 0; i < k; i++) - r = r.dbl(); - return r; -}; - -},{"../../elliptic":151,"bn.js":62}],153:[function(require,module,exports){ -'use strict'; - -var curve = require('../curve'); -var elliptic = require('../../elliptic'); -var bn = require('bn.js'); -var inherits = require('inherits'); -var Base = curve.base; - -var assert = elliptic.utils.assert; - -function EdwardsCurve(conf) { - // NOTE: Important as we are creating point in Base.call() - this.twisted = (conf.a | 0) !== 1; - this.mOneA = this.twisted && (conf.a | 0) === -1; - this.extended = this.mOneA; - - Base.call(this, 'edwards', conf); - - this.a = new bn(conf.a, 16).mod(this.red.m).toRed(this.red); - this.c = new bn(conf.c, 16).toRed(this.red); - this.c2 = this.c.redSqr(); - this.d = new bn(conf.d, 16).toRed(this.red); - this.dd = this.d.redAdd(this.d); - - assert(!this.twisted || this.c.fromRed().cmpn(1) === 0); - this.oneC = (conf.c | 0) === 1; -} -inherits(EdwardsCurve, Base); -module.exports = EdwardsCurve; - -EdwardsCurve.prototype._mulA = function _mulA(num) { - if (this.mOneA) - return num.redNeg(); - else - return this.a.redMul(num); -}; - -EdwardsCurve.prototype._mulC = function _mulC(num) { - if (this.oneC) - return num; - else - return this.c.redMul(num); -}; - -// Just for compatibility with Short curve -EdwardsCurve.prototype.jpoint = function jpoint(x, y, z, t) { - return this.point(x, y, z, t); -}; - -EdwardsCurve.prototype.pointFromX = function pointFromX(odd, x) { - x = new bn(x, 16); - if (!x.red) - x = x.toRed(this.red); - - var x2 = x.redSqr(); - var rhs = this.c2.redSub(this.a.redMul(x2)); - var lhs = this.one.redSub(this.c2.redMul(this.d).redMul(x2)); - - var y = rhs.redMul(lhs.redInvm()).redSqrt(); - var isOdd = y.fromRed().isOdd(); - if (odd && !isOdd || !odd && isOdd) - y = y.redNeg(); - - return this.point(x, y, curve.one); -}; - -EdwardsCurve.prototype.validate = function validate(point) { - if (point.isInfinity()) - return true; - - // Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2) - point.normalize(); - - var x2 = point.x.redSqr(); - var y2 = point.y.redSqr(); - var lhs = x2.redMul(this.a).redAdd(y2); - var rhs = this.c2.redMul(this.one.redAdd(this.d.redMul(x2).redMul(y2))); - - return lhs.cmp(rhs) === 0; -}; - -function Point(curve, x, y, z, t) { - Base.BasePoint.call(this, curve, 'projective'); - if (x === null && y === null && z === null) { - this.x = this.curve.zero; - this.y = this.curve.one; - this.z = this.curve.one; - this.t = this.curve.zero; - this.zOne = true; - } else { - this.x = new bn(x, 16); - this.y = new bn(y, 16); - this.z = z ? new bn(z, 16) : this.curve.one; - this.t = t && new bn(t, 16); - if (!this.x.red) - this.x = this.x.toRed(this.curve.red); - if (!this.y.red) - this.y = this.y.toRed(this.curve.red); - if (!this.z.red) - this.z = this.z.toRed(this.curve.red); - if (this.t && !this.t.red) - this.t = this.t.toRed(this.curve.red); - this.zOne = this.z === this.curve.one; - - // Use extended coordinates - if (this.curve.extended && !this.t) { - this.t = this.x.redMul(this.y); - if (!this.zOne) - this.t = this.t.redMul(this.z.redInvm()); - } - } -} -inherits(Point, Base.BasePoint); - -EdwardsCurve.prototype.pointFromJSON = function pointFromJSON(obj) { - return Point.fromJSON(this, obj); -}; - -EdwardsCurve.prototype.point = function point(x, y, z, t) { - return new Point(this, x, y, z, t); -}; - -Point.fromJSON = function fromJSON(curve, obj) { - return new Point(curve, obj[0], obj[1], obj[2]); -}; - -Point.prototype.inspect = function inspect() { - if (this.isInfinity()) - return ''; - return ''; -}; - -Point.prototype.isInfinity = function isInfinity() { - // XXX This code assumes that zero is always zero in red - return this.x.cmpn(0) === 0 && - this.y.cmp(this.z) === 0; -}; - -Point.prototype._extDbl = function _extDbl() { - // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html - // #doubling-dbl-2008-hwcd - // 4M + 4S - - // A = X1^2 - var a = this.x.redSqr(); - // B = Y1^2 - var b = this.y.redSqr(); - // C = 2 * Z1^2 - var c = this.z.redSqr(); - c = c.redIAdd(c); - // D = a * A - var d = this.curve._mulA(a); - // E = (X1 + Y1)^2 - A - B - var e = this.x.redAdd(this.y).redSqr().redISub(a).redISub(b); - // G = D + B - var g = d.redAdd(b); - // F = G - C - var f = g.redSub(c); - // H = D - B - var h = d.redSub(b); - // X3 = E * F - var nx = e.redMul(f); - // Y3 = G * H - var ny = g.redMul(h); - // T3 = E * H - var nt = e.redMul(h); - // Z3 = F * G - var nz = f.redMul(g); - return this.curve.point(nx, ny, nz, nt); -}; - -Point.prototype._projDbl = function _projDbl() { - // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html - // #doubling-dbl-2008-bbjlp - // #doubling-dbl-2007-bl - // and others - // Generally 3M + 4S or 2M + 4S - - // B = (X1 + Y1)^2 - var b = this.x.redAdd(this.y).redSqr(); - // C = X1^2 - var c = this.x.redSqr(); - // D = Y1^2 - var d = this.y.redSqr(); - - var nx; - var ny; - var nz; - if (this.curve.twisted) { - // E = a * C - var e = this.curve._mulA(c); - // F = E + D - var f = e.redAdd(d); - if (this.zOne) { - // X3 = (B - C - D) * (F - 2) - nx = b.redSub(c).redSub(d).redMul(f.redSub(this.curve.two)); - // Y3 = F * (E - D) - ny = f.redMul(e.redSub(d)); - // Z3 = F^2 - 2 * F - nz = f.redSqr().redSub(f).redSub(f); - } else { - // H = Z1^2 - var h = this.z.redSqr(); - // J = F - 2 * H - var j = f.redSub(h).redISub(h); - // X3 = (B-C-D)*J - nx = b.redSub(c).redISub(d).redMul(j); - // Y3 = F * (E - D) - ny = f.redMul(e.redSub(d)); - // Z3 = F * J - nz = f.redMul(j); - } - } else { - // E = C + D - var e = c.redAdd(d); - // H = (c * Z1)^2 - var h = this.curve._mulC(this.c.redMul(this.z)).redSqr(); - // J = E - 2 * H - var j = e.redSub(h).redSub(h); - // X3 = c * (B - E) * J - nx = this.curve._mulC(b.redISub(e)).redMul(j); - // Y3 = c * E * (C - D) - ny = this.curve._mulC(e).redMul(c.redISub(d)); - // Z3 = E * J - nz = e.redMul(j); - } - return this.curve.point(nx, ny, nz); -}; - -Point.prototype.dbl = function dbl() { - if (this.isInfinity()) - return this; - - // Double in extended coordinates - if (this.curve.extended) - return this._extDbl(); - else - return this._projDbl(); -}; - -Point.prototype._extAdd = function _extAdd(p) { - // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html - // #addition-add-2008-hwcd-3 - // 8M - - // A = (Y1 - X1) * (Y2 - X2) - var a = this.y.redSub(this.x).redMul(p.y.redSub(p.x)); - // B = (Y1 + X1) * (Y2 + X2) - var b = this.y.redAdd(this.x).redMul(p.y.redAdd(p.x)); - // C = T1 * k * T2 - var c = this.t.redMul(this.curve.dd).redMul(p.t); - // D = Z1 * 2 * Z2 - var d = this.z.redMul(p.z.redAdd(p.z)); - // E = B - A - var e = b.redSub(a); - // F = D - C - var f = d.redSub(c); - // G = D + C - var g = d.redAdd(c); - // H = B + A - var h = b.redAdd(a); - // X3 = E * F - var nx = e.redMul(f); - // Y3 = G * H - var ny = g.redMul(h); - // T3 = E * H - var nt = e.redMul(h); - // Z3 = F * G - var nz = f.redMul(g); - return this.curve.point(nx, ny, nz, nt); -}; - -Point.prototype._projAdd = function _projAdd(p) { - // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html - // #addition-add-2008-bbjlp - // #addition-add-2007-bl - // 10M + 1S - - // A = Z1 * Z2 - var a = this.z.redMul(p.z); - // B = A^2 - var b = a.redSqr(); - // C = X1 * X2 - var c = this.x.redMul(p.x); - // D = Y1 * Y2 - var d = this.y.redMul(p.y); - // E = d * C * D - var e = this.curve.d.redMul(c).redMul(d); - // F = B - E - var f = b.redSub(e); - // G = B + E - var g = b.redAdd(e); - // X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D) - var tmp = this.x.redAdd(this.y).redMul(p.x.redAdd(p.y)).redISub(c).redISub(d); - var nx = a.redMul(f).redMul(tmp); - var ny; - var nz; - if (this.curve.twisted) { - // Y3 = A * G * (D - a * C) - ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c))); - // Z3 = F * G - nz = f.redMul(g); - } else { - // Y3 = A * G * (D - C) - ny = a.redMul(g).redMul(d.redSub(c)); - // Z3 = c * F * G - nz = this.curve._mulC(f).redMul(g); - } - return this.curve.point(nx, ny, nz); -}; - -Point.prototype.add = function add(p) { - if (this.isInfinity()) - return p; - if (p.isInfinity()) - return this; - - if (this.curve.extended) - return this._extAdd(p); - else - return this._projAdd(p); -}; - -Point.prototype.mul = function mul(k) { - if (this.precomputed && this.precomputed.doubles) - return this.curve._fixedNafMul(this, k); - else - return this.curve._wnafMul(this, k); -}; - -Point.prototype.mulAdd = function mulAdd(k1, p, k2) { - return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2); -}; - -Point.prototype.normalize = function normalize() { - if (this.zOne) - return this; - - // Normalize coordinates - var zi = this.z.redInvm(); - this.x = this.x.redMul(zi); - this.y = this.y.redMul(zi); - if (this.t) - this.t = this.t.redMul(zi); - this.z = this.curve.one; - this.zOne = true; - return this; -}; - -Point.prototype.neg = function neg() { - return this.curve.point(this.x.redNeg(), - this.y, - this.z, - this.t && this.t.redNeg()); -}; - -Point.prototype.getX = function getX() { - this.normalize(); - return this.x.fromRed(); -}; - -Point.prototype.getY = function getY() { - this.normalize(); - return this.y.fromRed(); -}; - -// Compatibility with BaseCurve -Point.prototype.toP = Point.prototype.normalize; -Point.prototype.mixedAdd = Point.prototype.add; - -},{"../../elliptic":151,"../curve":154,"bn.js":62,"inherits":184}],154:[function(require,module,exports){ -arguments[4][96][0].apply(exports,arguments) -},{"./base":152,"./edwards":153,"./mont":155,"./short":156,"dup":96}],155:[function(require,module,exports){ -'use strict'; - -var curve = require('../curve'); -var bn = require('bn.js'); -var inherits = require('inherits'); -var Base = curve.base; - -function MontCurve(conf) { - Base.call(this, 'mont', conf); - - this.a = new bn(conf.a, 16).toRed(this.red); - this.b = new bn(conf.b, 16).toRed(this.red); - this.i4 = new bn(4).toRed(this.red).redInvm(); - this.two = new bn(2).toRed(this.red); - this.a24 = this.i4.redMul(this.a.redAdd(this.two)); -} -inherits(MontCurve, Base); -module.exports = MontCurve; - -MontCurve.prototype.validate = function validate(point) { - var x = point.normalize().x; - var x2 = x.redSqr(); - var rhs = x2.redMul(x).redAdd(x2.redMul(this.a)).redAdd(x); - var y = rhs.redSqrt(); - - return y.redSqr().cmp(rhs) === 0; -}; - -function Point(curve, x, z) { - Base.BasePoint.call(this, curve, 'projective'); - if (x === null && z === null) { - this.x = this.curve.one; - this.z = this.curve.zero; - } else { - this.x = new bn(x, 16); - this.z = new bn(z, 16); - if (!this.x.red) - this.x = this.x.toRed(this.curve.red); - if (!this.z.red) - this.z = this.z.toRed(this.curve.red); - } -} -inherits(Point, Base.BasePoint); - -MontCurve.prototype.point = function point(x, z) { - return new Point(this, x, z); -}; - -MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) { - return Point.fromJSON(this, obj); -}; - -Point.prototype.precompute = function precompute() { - // No-op -}; - -Point.fromJSON = function fromJSON(curve, obj) { - return new Point(curve, obj[0], obj[1] || curve.one); -}; - -Point.prototype.inspect = function inspect() { - if (this.isInfinity()) - return ''; - return ''; -}; - -Point.prototype.isInfinity = function isInfinity() { - // XXX This code assumes that zero is always zero in red - return this.z.cmpn(0) === 0; -}; - -Point.prototype.dbl = function dbl() { - // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3 - // 2M + 2S + 4A - - // A = X1 + Z1 - var a = this.x.redAdd(this.z); - // AA = A^2 - var aa = a.redSqr(); - // B = X1 - Z1 - var b = this.x.redSub(this.z); - // BB = B^2 - var bb = b.redSqr(); - // C = AA - BB - var c = aa.redSub(bb); - // X3 = AA * BB - var nx = aa.redMul(bb); - // Z3 = C * (BB + A24 * C) - var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c))); - return this.curve.point(nx, nz); -}; - -Point.prototype.add = function add() { - throw new Error('Not supported on Montgomery curve'); -}; - -Point.prototype.diffAdd = function diffAdd(p, diff) { - // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3 - // 4M + 2S + 6A - - // A = X2 + Z2 - var a = this.x.redAdd(this.z); - // B = X2 - Z2 - var b = this.x.redSub(this.z); - // C = X3 + Z3 - var c = p.x.redAdd(p.z); - // D = X3 - Z3 - var d = p.x.redSub(p.z); - // DA = D * A - var da = d.redMul(a); - // CB = C * B - var cb = c.redMul(b); - // X5 = Z1 * (DA + CB)^2 - var nx = diff.z.redMul(da.redAdd(cb).redSqr()); - // Z5 = X1 * (DA - CB)^2 - var nz = diff.x.redMul(da.redISub(cb).redSqr()); - return this.curve.point(nx, nz); -}; - -Point.prototype.mul = function mul(k) { - var t = k.clone(); - var a = this; // (N / 2) * Q + Q - var b = this.curve.point(null, null); // (N / 2) * Q - var c = this; // Q - - for (var bits = []; t.cmpn(0) !== 0; t.ishrn(1)) - bits.push(t.andln(1)); - - for (var i = bits.length - 1; i >= 0; i--) { - if (bits[i] === 0) { - // N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q - a = a.diffAdd(b, c); - // N * Q = 2 * ((N / 2) * Q + Q)) - b = b.dbl(); - } else { - // N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q) - b = a.diffAdd(b, c); - // N * Q + Q = 2 * ((N / 2) * Q + Q) - a = a.dbl(); - } - } - return b; -}; + return this.curve.jpoint(nx, ny, nz); + }; -Point.prototype.mulAdd = function mulAdd() { - throw new Error('Not supported on Montgomery curve'); -}; + JPoint.prototype._dbl = function _dbl() { + var a = this.curve.a; + + // 4M + 6S + 10A + var jx = this.x; + var jy = this.y; + var jz = this.z; + var jz4 = jz.redSqr().redSqr(); + + var jx2 = jx.redSqr(); + var jy2 = jy.redSqr(); + + var c = jx2 + .redAdd(jx2) + .redIAdd(jx2) + .redIAdd(a.redMul(jz4)); + + var jxd4 = jx.redAdd(jx); + jxd4 = jxd4.redIAdd(jxd4); + var t1 = jxd4.redMul(jy2); + var nx = c.redSqr().redISub(t1.redAdd(t1)); + var t2 = t1.redISub(nx); + + var jyd8 = jy2.redSqr(); + jyd8 = jyd8.redIAdd(jyd8); + jyd8 = jyd8.redIAdd(jyd8); + jyd8 = jyd8.redIAdd(jyd8); + var ny = c.redMul(t2).redISub(jyd8); + var nz = jy.redAdd(jy).redMul(jz); + + return this.curve.jpoint(nx, ny, nz); + }; -Point.prototype.normalize = function normalize() { - this.x = this.x.redMul(this.z.redInvm()); - this.z = this.curve.one; - return this; -}; + JPoint.prototype.trpl = function trpl() { + if (!this.curve.zeroA) return this.dbl().add(this); + + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl + // 5M + 10S + ... + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // ZZ = Z1^2 + var zz = this.z.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // M = 3 * XX + a * ZZ2; a = 0 + var m = xx.redAdd(xx).redIAdd(xx); + // MM = M^2 + var mm = m.redSqr(); + // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM + var e = this.x + .redAdd(yy) + .redSqr() + .redISub(xx) + .redISub(yyyy); + e = e.redIAdd(e); + e = e.redAdd(e).redIAdd(e); + e = e.redISub(mm); + // EE = E^2 + var ee = e.redSqr(); + // T = 16*YYYY + var t = yyyy.redIAdd(yyyy); + t = t.redIAdd(t); + t = t.redIAdd(t); + t = t.redIAdd(t); + // U = (M + E)^2 - MM - EE - T + var u = m + .redIAdd(e) + .redSqr() + .redISub(mm) + .redISub(ee) + .redISub(t); + // X3 = 4 * (X1 * EE - 4 * YY * U) + var yyu4 = yy.redMul(u); + yyu4 = yyu4.redIAdd(yyu4); + yyu4 = yyu4.redIAdd(yyu4); + var nx = this.x.redMul(ee).redISub(yyu4); + nx = nx.redIAdd(nx); + nx = nx.redIAdd(nx); + // Y3 = 8 * Y1 * (U * (T - U) - E * EE) + var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee))); + ny = ny.redIAdd(ny); + ny = ny.redIAdd(ny); + ny = ny.redIAdd(ny); + // Z3 = (Z1 + E)^2 - ZZ - EE + var nz = this.z + .redAdd(e) + .redSqr() + .redISub(zz) + .redISub(ee); + + return this.curve.jpoint(nx, ny, nz); + }; -Point.prototype.getX = function getX() { - // Normalize coordinates - this.normalize(); + JPoint.prototype.mul = function mul(k, kbase) { + k = new bn(k, kbase); - return this.x.fromRed(); -}; + return this.curve._wnafMul(this, k); + }; -},{"../curve":154,"bn.js":62,"inherits":184}],156:[function(require,module,exports){ -'use strict'; + JPoint.prototype.eq = function eq(p) { + if (p.type === 'affine') return this.eq(p.toJ()); -var curve = require('../curve'); -var elliptic = require('../../elliptic'); -var bn = require('bn.js'); -var inherits = require('inherits'); -var Base = curve.base; + if (this === p) return true; -var assert = elliptic.utils.assert; + // x1 * z2^2 == x2 * z1^2 + var z2 = this.z.redSqr(); + var pz2 = p.z.redSqr(); + if ( + this.x + .redMul(pz2) + .redISub(p.x.redMul(z2)) + .cmpn(0) !== 0 + ) + return false; -function ShortCurve(conf) { - Base.call(this, 'short', conf); + // y1 * z2^3 == y2 * z1^3 + var z3 = z2.redMul(this.z); + var pz3 = pz2.redMul(p.z); + return ( + this.y + .redMul(pz3) + .redISub(p.y.redMul(z3)) + .cmpn(0) === 0 + ); + }; - this.a = new bn(conf.a, 16).toRed(this.red); - this.b = new bn(conf.b, 16).toRed(this.red); - this.tinv = this.two.redInvm(); + JPoint.prototype.inspect = function inspect() { + if (this.isInfinity()) return ''; + return ( + '' + ); + }; - this.zeroA = this.a.fromRed().cmpn(0) === 0; - this.threeA = this.a.fromRed().sub(this.p).cmpn(-3) === 0; + JPoint.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.z.cmpn(0) === 0; + }; + }, + { '../../elliptic': 151, '../curve': 154, 'bn.js': 62, inherits: 184 }, + ], + 157: [ + function(require, module, exports) { + 'use strict'; - // If the curve is endomorphic, precalculate beta and lambda - this.endo = this._getEndomorphism(conf); - this._endoWnafT1 = new Array(4); - this._endoWnafT2 = new Array(4); -} -inherits(ShortCurve, Base); -module.exports = ShortCurve; - -ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) { - // No efficient endomorphism - if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1) - return; - - // Compute beta and lambda, that lambda * P = (beta * Px; Py) - var beta; - var lambda; - if (conf.beta) { - beta = new bn(conf.beta, 16).toRed(this.red); - } else { - var betas = this._getEndoRoots(this.p); - // Choose the smallest beta - beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1]; - beta = beta.toRed(this.red); - } - if (conf.lambda) { - lambda = new bn(conf.lambda, 16); - } else { - // Choose the lambda that is matching selected beta - var lambdas = this._getEndoRoots(this.n); - if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) { - lambda = lambdas[0]; - } else { - lambda = lambdas[1]; - assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0); - } - } + var curves = exports; - // Get basis vectors, used for balanced length-two representation - var basis; - if (conf.basis) { - basis = conf.basis.map(function(vec) { - return { - a: new bn(vec.a, 16), - b: new bn(vec.b, 16) - }; - }); - } else { - basis = this._getEndoBasis(lambda); - } + var hash = require('hash.js'); + var elliptic = require('../elliptic'); - return { - beta: beta, - lambda: lambda, - basis: basis - }; -}; - -ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) { - // Find roots of for x^2 + x + 1 in F - // Root = (-1 +- Sqrt(-3)) / 2 - // - var red = num === this.p ? this.red : bn.mont(num); - var tinv = new bn(2).toRed(red).redInvm(); - var ntinv = tinv.redNeg(); - - var s = new bn(3).toRed(red).redNeg().redSqrt().redMul(tinv); - - var l1 = ntinv.redAdd(s).fromRed(); - var l2 = ntinv.redSub(s).fromRed(); - return [ l1, l2 ]; -}; - -ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) { - // aprxSqrt >= sqrt(this.n) - var aprxSqrt = this.n.shrn(Math.floor(this.n.bitLength() / 2)); - - // 3.74 - // Run EGCD, until r(L + 1) < aprxSqrt - var u = lambda; - var v = this.n.clone(); - var x1 = new bn(1); - var y1 = new bn(0); - var x2 = new bn(0); - var y2 = new bn(1); - - // NOTE: all vectors are roots of: a + b * lambda = 0 (mod n) - var a0; - var b0; - // First vector - var a1; - var b1; - // Second vector - var a2; - var b2; - - var prevR; - var i = 0; - var r; - var x; - while (u.cmpn(0) !== 0) { - var q = v.div(u); - r = v.sub(q.mul(u)); - x = x2.sub(q.mul(x1)); - var y = y2.sub(q.mul(y1)); - - if (!a1 && r.cmp(aprxSqrt) < 0) { - a0 = prevR.neg(); - b0 = x1; - a1 = r.neg(); - b1 = x; - } else if (a1 && ++i === 2) { - break; - } - prevR = r; - - v = u; - u = r; - x2 = x1; - x1 = x; - y2 = y1; - y1 = y; - } - a2 = r.neg(); - b2 = x; - - var len1 = a1.sqr().add(b1.sqr()); - var len2 = a2.sqr().add(b2.sqr()); - if (len2.cmp(len1) >= 0) { - a2 = a0; - b2 = b0; - } + var assert = elliptic.utils.assert; - // Normalize signs - if (a1.sign) { - a1 = a1.neg(); - b1 = b1.neg(); - } - if (a2.sign) { - a2 = a2.neg(); - b2 = b2.neg(); - } + function PresetCurve(options) { + if (options.type === 'short') this.curve = new elliptic.curve.short(options); + else if (options.type === 'edwards') this.curve = new elliptic.curve.edwards(options); + else this.curve = new elliptic.curve.mont(options); + this.g = this.curve.g; + this.n = this.curve.n; + this.hash = options.hash; - return [ - { a: a1, b: b1 }, - { a: a2, b: b2 } - ]; -}; - -ShortCurve.prototype._endoSplit = function _endoSplit(k) { - var basis = this.endo.basis; - var v1 = basis[0]; - var v2 = basis[1]; - - var c1 = v2.b.mul(k).divRound(this.n); - var c2 = v1.b.neg().mul(k).divRound(this.n); - - var p1 = c1.mul(v1.a); - var p2 = c2.mul(v2.a); - var q1 = c1.mul(v1.b); - var q2 = c2.mul(v2.b); - - // Calculate answer - var k1 = k.sub(p1).sub(p2); - var k2 = q1.add(q2).neg(); - return { k1: k1, k2: k2 }; -}; - -ShortCurve.prototype.pointFromX = function pointFromX(odd, x) { - x = new bn(x, 16); - if (!x.red) - x = x.toRed(this.red); - - var y2 = x.redSqr().redMul(x).redIAdd(x.redMul(this.a)).redIAdd(this.b); - var y = y2.redSqrt(); - - // XXX Is there any way to tell if the number is odd without converting it - // to non-red form? - var isOdd = y.fromRed().isOdd(); - if (odd && !isOdd || !odd && isOdd) - y = y.redNeg(); - - return this.point(x, y); -}; - -ShortCurve.prototype.validate = function validate(point) { - if (point.inf) - return true; - - var x = point.x; - var y = point.y; - - var ax = this.a.redMul(x); - var rhs = x.redSqr().redMul(x).redIAdd(ax).redIAdd(this.b); - return y.redSqr().redISub(rhs).cmpn(0) === 0; -}; - -ShortCurve.prototype._endoWnafMulAdd = - function _endoWnafMulAdd(points, coeffs) { - var npoints = this._endoWnafT1; - var ncoeffs = this._endoWnafT2; - for (var i = 0; i < points.length; i++) { - var split = this._endoSplit(coeffs[i]); - var p = points[i]; - var beta = p._getBeta(); - - if (split.k1.sign) { - split.k1.sign = !split.k1.sign; - p = p.neg(true); - } - if (split.k2.sign) { - split.k2.sign = !split.k2.sign; - beta = beta.neg(true); - } + assert(this.g.validate(), 'Invalid curve'); + assert(this.g.mul(this.n).isInfinity(), 'Invalid curve, G*N != O'); + } + curves.PresetCurve = PresetCurve; + + function defineCurve(name, options) { + Object.defineProperty(curves, name, { + configurable: true, + enumerable: true, + get: function() { + var curve = new PresetCurve(options); + Object.defineProperty(curves, name, { + configurable: true, + enumerable: true, + value: curve, + }); + return curve; + }, + }); + } - npoints[i * 2] = p; - npoints[i * 2 + 1] = beta; - ncoeffs[i * 2] = split.k1; - ncoeffs[i * 2 + 1] = split.k2; - } - var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2); + defineCurve('p192', { + type: 'short', + prime: 'p192', + p: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff', + a: 'ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc', + b: '64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1', + n: 'ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831', + hash: hash.sha256, + gRed: false, + g: [ + '188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012', + '07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811', + ], + }); - // Clean-up references to points and coefficients - for (var j = 0; j < i * 2; j++) { - npoints[j] = null; - ncoeffs[j] = null; - } - return res; -}; - -function Point(curve, x, y, isRed) { - Base.BasePoint.call(this, curve, 'affine'); - if (x === null && y === null) { - this.x = null; - this.y = null; - this.inf = true; - } else { - this.x = new bn(x, 16); - this.y = new bn(y, 16); - // Force redgomery representation when loading from JSON - if (isRed) { - this.x.forceRed(this.curve.red); - this.y.forceRed(this.curve.red); - } - if (!this.x.red) - this.x = this.x.toRed(this.curve.red); - if (!this.y.red) - this.y = this.y.toRed(this.curve.red); - this.inf = false; - } -} -inherits(Point, Base.BasePoint); - -ShortCurve.prototype.point = function point(x, y, isRed) { - return new Point(this, x, y, isRed); -}; - -ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) { - return Point.fromJSON(this, obj, red); -}; - -Point.prototype._getBeta = function _getBeta() { - if (!this.curve.endo) - return; - - var pre = this.precomputed; - if (pre && pre.beta) - return pre.beta; - - var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y); - if (pre) { - var curve = this.curve; - var endoMul = function(p) { - return curve.point(p.x.redMul(curve.endo.beta), p.y); - }; - pre.beta = beta; - beta.precomputed = { - beta: null, - naf: pre.naf && { - wnd: pre.naf.wnd, - points: pre.naf.points.map(endoMul) - }, - doubles: pre.doubles && { - step: pre.doubles.step, - points: pre.doubles.points.map(endoMul) - } - }; - } - return beta; -}; - -Point.prototype.toJSON = function toJSON() { - if (!this.precomputed) - return [ this.x, this.y ]; - - return [ this.x, this.y, this.precomputed && { - doubles: this.precomputed.doubles && { - step: this.precomputed.doubles.step, - points: this.precomputed.doubles.points.slice(1) - }, - naf: this.precomputed.naf && { - wnd: this.precomputed.naf.wnd, - points: this.precomputed.naf.points.slice(1) - } - } ]; -}; - -Point.fromJSON = function fromJSON(curve, obj, red) { - if (typeof obj === 'string') - obj = JSON.parse(obj); - var res = curve.point(obj[0], obj[1], red); - if (!obj[2]) - return res; - - function obj2point(obj) { - return curve.point(obj[0], obj[1], red); - } + defineCurve('p224', { + type: 'short', + prime: 'p224', + p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001', + a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe', + b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4', + n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d', + hash: hash.sha256, + gRed: false, + g: [ + 'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21', + 'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34', + ], + }); - var pre = obj[2]; - res.precomputed = { - beta: null, - doubles: pre.doubles && { - step: pre.doubles.step, - points: [ res ].concat(pre.doubles.points.map(obj2point)) - }, - naf: pre.naf && { - wnd: pre.naf.wnd, - points: [ res ].concat(pre.naf.points.map(obj2point)) - } - }; - return res; -}; - -Point.prototype.inspect = function inspect() { - if (this.isInfinity()) - return ''; - return ''; -}; - -Point.prototype.isInfinity = function isInfinity() { - return this.inf; -}; - -Point.prototype.add = function add(p) { - // O + P = P - if (this.inf) - return p; - - // P + O = P - if (p.inf) - return this; - - // P + P = 2P - if (this.eq(p)) - return this.dbl(); - - // P + (-P) = O - if (this.neg().eq(p)) - return this.curve.point(null, null); - - // P + Q = O - if (this.x.cmp(p.x) === 0) - return this.curve.point(null, null); - - var c = this.y.redSub(p.y); - if (c.cmpn(0) !== 0) - c = c.redMul(this.x.redSub(p.x).redInvm()); - var nx = c.redSqr().redISub(this.x).redISub(p.x); - var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); - return this.curve.point(nx, ny); -}; - -Point.prototype.dbl = function dbl() { - if (this.inf) - return this; - - // 2P = O - var ys1 = this.y.redAdd(this.y); - if (ys1.cmpn(0) === 0) - return this.curve.point(null, null); - - var a = this.curve.a; - - var x2 = this.x.redSqr(); - var dyinv = ys1.redInvm(); - var c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv); - - var nx = c.redSqr().redISub(this.x.redAdd(this.x)); - var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); - return this.curve.point(nx, ny); -}; - -Point.prototype.getX = function getX() { - return this.x.fromRed(); -}; - -Point.prototype.getY = function getY() { - return this.y.fromRed(); -}; - -Point.prototype.mul = function mul(k) { - k = new bn(k, 16); - - if (this.precomputed && this.precomputed.doubles) - return this.curve._fixedNafMul(this, k); - else if (this.curve.endo) - return this.curve._endoWnafMulAdd([ this ], [ k ]); - else - return this.curve._wnafMul(this, k); -}; - -Point.prototype.mulAdd = function mulAdd(k1, p2, k2) { - var points = [ this, p2 ]; - var coeffs = [ k1, k2 ]; - if (this.curve.endo) - return this.curve._endoWnafMulAdd(points, coeffs); - else - return this.curve._wnafMulAdd(1, points, coeffs, 2); -}; - -Point.prototype.eq = function eq(p) { - return this === p || - this.inf === p.inf && - (this.inf || this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0); -}; - -Point.prototype.neg = function neg(_precompute) { - if (this.inf) - return this; - - var res = this.curve.point(this.x, this.y.redNeg()); - if (_precompute && this.precomputed) { - var pre = this.precomputed; - var negate = function(p) { - return p.neg(); - }; - res.precomputed = { - naf: pre.naf && { - wnd: pre.naf.wnd, - points: pre.naf.points.map(negate) - }, - doubles: pre.doubles && { - step: pre.doubles.step, - points: pre.doubles.points.map(negate) - } - }; - } - return res; -}; - -Point.prototype.toJ = function toJ() { - if (this.inf) - return this.curve.jpoint(null, null, null); - - var res = this.curve.jpoint(this.x, this.y, this.curve.one); - return res; -}; - -function JPoint(curve, x, y, z) { - Base.BasePoint.call(this, curve, 'jacobian'); - if (x === null && y === null && z === null) { - this.x = this.curve.one; - this.y = this.curve.one; - this.z = new bn(0); - } else { - this.x = new bn(x, 16); - this.y = new bn(y, 16); - this.z = new bn(z, 16); - } - if (!this.x.red) - this.x = this.x.toRed(this.curve.red); - if (!this.y.red) - this.y = this.y.toRed(this.curve.red); - if (!this.z.red) - this.z = this.z.toRed(this.curve.red); - - this.zOne = this.z === this.curve.one; -} -inherits(JPoint, Base.BasePoint); - -ShortCurve.prototype.jpoint = function jpoint(x, y, z) { - return new JPoint(this, x, y, z); -}; - -JPoint.prototype.toP = function toP() { - if (this.isInfinity()) - return this.curve.point(null, null); - - var zinv = this.z.redInvm(); - var zinv2 = zinv.redSqr(); - var ax = this.x.redMul(zinv2); - var ay = this.y.redMul(zinv2).redMul(zinv); - - return this.curve.point(ax, ay); -}; - -JPoint.prototype.neg = function neg() { - return this.curve.jpoint(this.x, this.y.redNeg(), this.z); -}; - -JPoint.prototype.add = function add(p) { - // O + P = P - if (this.isInfinity()) - return p; - - // P + O = P - if (p.isInfinity()) - return this; - - // 12M + 4S + 7A - var pz2 = p.z.redSqr(); - var z2 = this.z.redSqr(); - var u1 = this.x.redMul(pz2); - var u2 = p.x.redMul(z2); - var s1 = this.y.redMul(pz2.redMul(p.z)); - var s2 = p.y.redMul(z2.redMul(this.z)); - - var h = u1.redSub(u2); - var r = s1.redSub(s2); - if (h.cmpn(0) === 0) { - if (r.cmpn(0) !== 0) - return this.curve.jpoint(null, null, null); - else - return this.dbl(); - } + defineCurve('p256', { + type: 'short', + prime: null, + p: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff', + a: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc', + b: '5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b', + n: 'ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551', + hash: hash.sha256, + gRed: false, + g: [ + '6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296', + '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5', + ], + }); - var h2 = h.redSqr(); - var h3 = h2.redMul(h); - var v = u1.redMul(h2); - - var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); - var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); - var nz = this.z.redMul(p.z).redMul(h); - - return this.curve.jpoint(nx, ny, nz); -}; - -JPoint.prototype.mixedAdd = function mixedAdd(p) { - // O + P = P - if (this.isInfinity()) - return p.toJ(); - - // P + O = P - if (p.isInfinity()) - return this; - - // 8M + 3S + 7A - var z2 = this.z.redSqr(); - var u1 = this.x; - var u2 = p.x.redMul(z2); - var s1 = this.y; - var s2 = p.y.redMul(z2).redMul(this.z); - - var h = u1.redSub(u2); - var r = s1.redSub(s2); - if (h.cmpn(0) === 0) { - if (r.cmpn(0) !== 0) - return this.curve.jpoint(null, null, null); - else - return this.dbl(); - } + defineCurve('curve25519', { + type: 'mont', + prime: 'p25519', + p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', + a: '76d06', + b: '0', + n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', + hash: hash.sha256, + gRed: false, + g: ['9'], + }); - var h2 = h.redSqr(); - var h3 = h2.redMul(h); - var v = u1.redMul(h2); - - var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); - var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); - var nz = this.z.redMul(h); - - return this.curve.jpoint(nx, ny, nz); -}; - -JPoint.prototype.dblp = function dblp(pow) { - if (pow === 0) - return this; - if (this.isInfinity()) - return this; - if (!pow) - return this.dbl(); - - if (this.curve.zeroA || this.curve.threeA) { - var r = this; - for (var i = 0; i < pow; i++) - r = r.dbl(); - return r; - } + defineCurve('ed25519', { + type: 'edwards', + prime: 'p25519', + p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', + a: '-1', + c: '1', + // -121665 * (121666^(-1)) (mod P) + d: '52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3', + n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', + hash: hash.sha256, + gRed: false, + g: [ + '216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a', + + // 4/5 + '6666666666666666666666666666666666666666666666666666666666666658', + ], + }); - // 1M + 2S + 1A + N * (4S + 5M + 8A) - // N = 1 => 6M + 6S + 9A - var a = this.curve.a; - var tinv = this.curve.tinv; - - var jx = this.x; - var jy = this.y; - var jz = this.z; - var jz4 = jz.redSqr().redSqr(); - - // Reuse results - var jyd = jy.redAdd(jy); - for (var i = 0; i < pow; i++) { - var jx2 = jx.redSqr(); - var jyd2 = jyd.redSqr(); - var jyd4 = jyd2.redSqr(); - var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); - - var t1 = jx.redMul(jyd2); - var nx = c.redSqr().redISub(t1.redAdd(t1)); - var t2 = t1.redISub(nx); - var dny = c.redMul(t2); - dny = dny.redIAdd(dny).redISub(jyd4); - var nz = jyd.redMul(jz); - if (i + 1 < pow) - jz4 = jz4.redMul(jyd4); - - jx = nx; - jz = nz; - jyd = dny; - } + var pre; + try { + pre = require('./precomputed/secp256k1'); + } catch (e) { + pre = undefined; + } - return this.curve.jpoint(jx, jyd.redMul(tinv), jz); -}; - -JPoint.prototype.dbl = function dbl() { - if (this.isInfinity()) - return this; - - if (this.curve.zeroA) - return this._zeroDbl(); - else if (this.curve.threeA) - return this._threeDbl(); - else - return this._dbl(); -}; - -JPoint.prototype._zeroDbl = function _zeroDbl() { - var nx; - var ny; - var nz; - // Z = 1 - if (this.zOne) { - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html - // #doubling-mdbl-2007-bl - // 1M + 5S + 14A - - // XX = X1^2 - var xx = this.x.redSqr(); - // YY = Y1^2 - var yy = this.y.redSqr(); - // YYYY = YY^2 - var yyyy = yy.redSqr(); - // S = 2 * ((X1 + YY)^2 - XX - YYYY) - var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); - s = s.redIAdd(s); - // M = 3 * XX + a; a = 0 - var m = xx.redAdd(xx).redIAdd(xx); - // T = M ^ 2 - 2*S - var t = m.redSqr().redISub(s).redISub(s); - - // 8 * YYYY - var yyyy8 = yyyy.redIAdd(yyyy); - yyyy8 = yyyy8.redIAdd(yyyy8); - yyyy8 = yyyy8.redIAdd(yyyy8); - - // X3 = T - nx = t; - // Y3 = M * (S - T) - 8 * YYYY - ny = m.redMul(s.redISub(t)).redISub(yyyy8); - // Z3 = 2*Y1 - nz = this.y.redAdd(this.y); - } else { - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html - // #doubling-dbl-2009-l - // 2M + 5S + 13A - - // A = X1^2 - var a = this.x.redSqr(); - // B = Y1^2 - var b = this.y.redSqr(); - // C = B^2 - var c = b.redSqr(); - // D = 2 * ((X1 + B)^2 - A - C) - var d = this.x.redAdd(b).redSqr().redISub(a).redISub(c); - d = d.redIAdd(d); - // E = 3 * A - var e = a.redAdd(a).redIAdd(a); - // F = E^2 - var f = e.redSqr(); - - // 8 * C - var c8 = c.redIAdd(c); - c8 = c8.redIAdd(c8); - c8 = c8.redIAdd(c8); - - // X3 = F - 2 * D - nx = f.redISub(d).redISub(d); - // Y3 = E * (D - X3) - 8 * C - ny = e.redMul(d.redISub(nx)).redISub(c8); - // Z3 = 2 * Y1 * Z1 - nz = this.y.redMul(this.z); - nz = nz.redIAdd(nz); - } + defineCurve('secp256k1', { + type: 'short', + prime: 'k256', + p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f', + a: '0', + b: '7', + n: 'ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141', + h: '1', + hash: hash.sha256, + + // Precomputed endomorphism + beta: '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee', + lambda: '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72', + basis: [ + { + a: '3086d221a7d46bcde86c90e49284eb15', + b: '-e4437ed6010e88286f547fa90abfe4c3', + }, + { + a: '114ca50f7a8e2f3f657c1108d9d44cfd8', + b: '3086d221a7d46bcde86c90e49284eb15', + }, + ], + + gRed: false, + g: [ + '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', + '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', + pre, + ], + }); + }, + { '../elliptic': 151, './precomputed/secp256k1': 162, 'hash.js': 168 }, + ], + 158: [ + function(require, module, exports) { + 'use strict'; - return this.curve.jpoint(nx, ny, nz); -}; - -JPoint.prototype._threeDbl = function _threeDbl() { - var nx; - var ny; - var nz; - // Z = 1 - if (this.zOne) { - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html - // #doubling-mdbl-2007-bl - // 1M + 5S + 15A - - // XX = X1^2 - var xx = this.x.redSqr(); - // YY = Y1^2 - var yy = this.y.redSqr(); - // YYYY = YY^2 - var yyyy = yy.redSqr(); - // S = 2 * ((X1 + YY)^2 - XX - YYYY) - var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); - s = s.redIAdd(s); - // M = 3 * XX + a - var m = xx.redAdd(xx).redIAdd(xx).redIAdd(this.curve.a); - // T = M^2 - 2 * S - var t = m.redSqr().redISub(s).redISub(s); - // X3 = T - nx = t; - // Y3 = M * (S - T) - 8 * YYYY - var yyyy8 = yyyy.redIAdd(yyyy); - yyyy8 = yyyy8.redIAdd(yyyy8); - yyyy8 = yyyy8.redIAdd(yyyy8); - ny = m.redMul(s.redISub(t)).redISub(yyyy8); - // Z3 = 2 * Y1 - nz = this.y.redAdd(this.y); - } else { - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b - // 3M + 5S - - // delta = Z1^2 - var delta = this.z.redSqr(); - // gamma = Y1^2 - var gamma = this.y.redSqr(); - // beta = X1 * gamma - var beta = this.x.redMul(gamma); - // alpha = 3 * (X1 - delta) * (X1 + delta) - var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta)); - alpha = alpha.redAdd(alpha).redIAdd(alpha); - // X3 = alpha^2 - 8 * beta - var beta4 = beta.redIAdd(beta); - beta4 = beta4.redIAdd(beta4); - var beta8 = beta4.redAdd(beta4); - nx = alpha.redSqr().redISub(beta8); - // Z3 = (Y1 + Z1)^2 - gamma - delta - nz = this.y.redAdd(this.z).redSqr().redISub(gamma).redISub(delta); - // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2 - var ggamma8 = gamma.redSqr(); - ggamma8 = ggamma8.redIAdd(ggamma8); - ggamma8 = ggamma8.redIAdd(ggamma8); - ggamma8 = ggamma8.redIAdd(ggamma8); - ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8); - } + var bn = require('bn.js'); + var elliptic = require('../../elliptic'); + var utils = elliptic.utils; + var assert = utils.assert; - return this.curve.jpoint(nx, ny, nz); -}; - -JPoint.prototype._dbl = function _dbl() { - var a = this.curve.a; - - // 4M + 6S + 10A - var jx = this.x; - var jy = this.y; - var jz = this.z; - var jz4 = jz.redSqr().redSqr(); - - var jx2 = jx.redSqr(); - var jy2 = jy.redSqr(); - - var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); - - var jxd4 = jx.redAdd(jx); - jxd4 = jxd4.redIAdd(jxd4); - var t1 = jxd4.redMul(jy2); - var nx = c.redSqr().redISub(t1.redAdd(t1)); - var t2 = t1.redISub(nx); - - var jyd8 = jy2.redSqr(); - jyd8 = jyd8.redIAdd(jyd8); - jyd8 = jyd8.redIAdd(jyd8); - jyd8 = jyd8.redIAdd(jyd8); - var ny = c.redMul(t2).redISub(jyd8); - var nz = jy.redAdd(jy).redMul(jz); - - return this.curve.jpoint(nx, ny, nz); -}; - -JPoint.prototype.trpl = function trpl() { - if (!this.curve.zeroA) - return this.dbl().add(this); - - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl - // 5M + 10S + ... - - // XX = X1^2 - var xx = this.x.redSqr(); - // YY = Y1^2 - var yy = this.y.redSqr(); - // ZZ = Z1^2 - var zz = this.z.redSqr(); - // YYYY = YY^2 - var yyyy = yy.redSqr(); - // M = 3 * XX + a * ZZ2; a = 0 - var m = xx.redAdd(xx).redIAdd(xx); - // MM = M^2 - var mm = m.redSqr(); - // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM - var e = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); - e = e.redIAdd(e); - e = e.redAdd(e).redIAdd(e); - e = e.redISub(mm); - // EE = E^2 - var ee = e.redSqr(); - // T = 16*YYYY - var t = yyyy.redIAdd(yyyy); - t = t.redIAdd(t); - t = t.redIAdd(t); - t = t.redIAdd(t); - // U = (M + E)^2 - MM - EE - T - var u = m.redIAdd(e).redSqr().redISub(mm).redISub(ee).redISub(t); - // X3 = 4 * (X1 * EE - 4 * YY * U) - var yyu4 = yy.redMul(u); - yyu4 = yyu4.redIAdd(yyu4); - yyu4 = yyu4.redIAdd(yyu4); - var nx = this.x.redMul(ee).redISub(yyu4); - nx = nx.redIAdd(nx); - nx = nx.redIAdd(nx); - // Y3 = 8 * Y1 * (U * (T - U) - E * EE) - var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee))); - ny = ny.redIAdd(ny); - ny = ny.redIAdd(ny); - ny = ny.redIAdd(ny); - // Z3 = (Z1 + E)^2 - ZZ - EE - var nz = this.z.redAdd(e).redSqr().redISub(zz).redISub(ee); - - return this.curve.jpoint(nx, ny, nz); -}; - -JPoint.prototype.mul = function mul(k, kbase) { - k = new bn(k, kbase); - - return this.curve._wnafMul(this, k); -}; - -JPoint.prototype.eq = function eq(p) { - if (p.type === 'affine') - return this.eq(p.toJ()); - - if (this === p) - return true; - - // x1 * z2^2 == x2 * z1^2 - var z2 = this.z.redSqr(); - var pz2 = p.z.redSqr(); - if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0) - return false; - - // y1 * z2^3 == y2 * z1^3 - var z3 = z2.redMul(this.z); - var pz3 = pz2.redMul(p.z); - return this.y.redMul(pz3).redISub(p.y.redMul(z3)).cmpn(0) === 0; -}; - -JPoint.prototype.inspect = function inspect() { - if (this.isInfinity()) - return ''; - return ''; -}; - -JPoint.prototype.isInfinity = function isInfinity() { - // XXX This code assumes that zero is always zero in red - return this.z.cmpn(0) === 0; -}; - -},{"../../elliptic":151,"../curve":154,"bn.js":62,"inherits":184}],157:[function(require,module,exports){ -'use strict'; - -var curves = exports; - -var hash = require('hash.js'); -var elliptic = require('../elliptic'); - -var assert = elliptic.utils.assert; - -function PresetCurve(options) { - if (options.type === 'short') - this.curve = new elliptic.curve.short(options); - else if (options.type === 'edwards') - this.curve = new elliptic.curve.edwards(options); - else - this.curve = new elliptic.curve.mont(options); - this.g = this.curve.g; - this.n = this.curve.n; - this.hash = options.hash; - - assert(this.g.validate(), 'Invalid curve'); - assert(this.g.mul(this.n).isInfinity(), 'Invalid curve, G*N != O'); -} -curves.PresetCurve = PresetCurve; - -function defineCurve(name, options) { - Object.defineProperty(curves, name, { - configurable: true, - enumerable: true, - get: function() { - var curve = new PresetCurve(options); - Object.defineProperty(curves, name, { - configurable: true, - enumerable: true, - value: curve - }); - return curve; - } - }); -} + var KeyPair = require('./key'); + var Signature = require('./signature'); -defineCurve('p192', { - type: 'short', - prime: 'p192', - p: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff', - a: 'ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc', - b: '64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1', - n: 'ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831', - hash: hash.sha256, - gRed: false, - g: [ - '188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012', - '07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811' - ] -}); - -defineCurve('p224', { - type: 'short', - prime: 'p224', - p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001', - a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe', - b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4', - n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d', - hash: hash.sha256, - gRed: false, - g: [ - 'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21', - 'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34' - ] -}); - -defineCurve('p256', { - type: 'short', - prime: null, - p: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff', - a: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc', - b: '5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b', - n: 'ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551', - hash: hash.sha256, - gRed: false, - g: [ - '6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296', - '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5' - ] -}); - -defineCurve('curve25519', { - type: 'mont', - prime: 'p25519', - p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', - a: '76d06', - b: '0', - n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', - hash: hash.sha256, - gRed: false, - g: [ - '9' - ] -}); - -defineCurve('ed25519', { - type: 'edwards', - prime: 'p25519', - p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', - a: '-1', - c: '1', - // -121665 * (121666^(-1)) (mod P) - d: '52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3', - n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', - hash: hash.sha256, - gRed: false, - g: [ - '216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a', - - // 4/5 - '6666666666666666666666666666666666666666666666666666666666666658' - ] -}); - -var pre; -try { - pre = require('./precomputed/secp256k1'); -} catch (e) { - pre = undefined; -} + function EC(options) { + if (!(this instanceof EC)) return new EC(options); -defineCurve('secp256k1', { - type: 'short', - prime: 'k256', - p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f', - a: '0', - b: '7', - n: 'ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141', - h: '1', - hash: hash.sha256, - - // Precomputed endomorphism - beta: '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee', - lambda: '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72', - basis: [ - { - a: '3086d221a7d46bcde86c90e49284eb15', - b: '-e4437ed6010e88286f547fa90abfe4c3' - }, - { - a: '114ca50f7a8e2f3f657c1108d9d44cfd8', - b: '3086d221a7d46bcde86c90e49284eb15' - } - ], + // Shortcut `elliptic.ec(curve-name)` + if (typeof options === 'string') { + assert(elliptic.curves.hasOwnProperty(options), 'Unknown curve ' + options); - gRed: false, - g: [ - '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', - '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', - pre - ] -}); + options = elliptic.curves[options]; + } -},{"../elliptic":151,"./precomputed/secp256k1":162,"hash.js":168}],158:[function(require,module,exports){ -'use strict'; + // Shortcut for `elliptic.ec(elliptic.curves.curveName)` + if (options instanceof elliptic.curves.PresetCurve) options = { curve: options }; -var bn = require('bn.js'); -var elliptic = require('../../elliptic'); -var utils = elliptic.utils; -var assert = utils.assert; + this.curve = options.curve.curve; + this.n = this.curve.n; + this.nh = this.n.shrn(1); + this.g = this.curve.g; -var KeyPair = require('./key'); -var Signature = require('./signature'); + // Point on curve + this.g = options.curve.g; + this.g.precompute(options.curve.n.bitLength() + 1); -function EC(options) { - if (!(this instanceof EC)) - return new EC(options); + // Hash for function for DRBG + this.hash = options.hash || options.curve.hash; + } + module.exports = EC; - // Shortcut `elliptic.ec(curve-name)` - if (typeof options === 'string') { - assert(elliptic.curves.hasOwnProperty(options), 'Unknown curve ' + options); + EC.prototype.keyPair = function keyPair(options) { + return new KeyPair(this, options); + }; - options = elliptic.curves[options]; - } + EC.prototype.keyFromPrivate = function keyFromPrivate(priv, enc) { + return KeyPair.fromPrivate(this, priv, enc); + }; - // Shortcut for `elliptic.ec(elliptic.curves.curveName)` - if (options instanceof elliptic.curves.PresetCurve) - options = { curve: options }; + EC.prototype.keyFromPublic = function keyFromPublic(pub, enc) { + return KeyPair.fromPublic(this, pub, enc); + }; - this.curve = options.curve.curve; - this.n = this.curve.n; - this.nh = this.n.shrn(1); - this.g = this.curve.g; + EC.prototype.genKeyPair = function genKeyPair(options) { + if (!options) options = {}; - // Point on curve - this.g = options.curve.g; - this.g.precompute(options.curve.n.bitLength() + 1); + // Instantiate Hmac_DRBG + var drbg = new elliptic.hmacDRBG({ + hash: this.hash, + pers: options.pers, + entropy: options.entropy || elliptic.rand(this.hash.hmacStrength), + nonce: this.n.toArray(), + }); - // Hash for function for DRBG - this.hash = options.hash || options.curve.hash; -} -module.exports = EC; - -EC.prototype.keyPair = function keyPair(options) { - return new KeyPair(this, options); -}; - -EC.prototype.keyFromPrivate = function keyFromPrivate(priv, enc) { - return KeyPair.fromPrivate(this, priv, enc); -}; - -EC.prototype.keyFromPublic = function keyFromPublic(pub, enc) { - return KeyPair.fromPublic(this, pub, enc); -}; - -EC.prototype.genKeyPair = function genKeyPair(options) { - if (!options) - options = {}; - - // Instantiate Hmac_DRBG - var drbg = new elliptic.hmacDRBG({ - hash: this.hash, - pers: options.pers, - entropy: options.entropy || elliptic.rand(this.hash.hmacStrength), - nonce: this.n.toArray() - }); - - var bytes = this.n.byteLength(); - var ns2 = this.n.sub(new bn(2)); - do { - var priv = new bn(drbg.generate(bytes)); - if (priv.cmp(ns2) > 0) - continue; - - priv.iaddn(1); - return this.keyFromPrivate(priv); - } while (true); -}; - -EC.prototype._truncateToN = function truncateToN(msg, truncOnly) { - var delta = msg.byteLength() * 8 - this.n.bitLength(); - if (delta > 0) - msg = msg.shrn(delta); - if (!truncOnly && msg.cmp(this.n) >= 0) - return msg.sub(this.n); - else - return msg; -}; - -EC.prototype.sign = function sign(msg, key, enc, options) { - if (typeof enc === 'object') { - options = enc; - enc = null; - } - if (!options) - options = {}; - - key = this.keyFromPrivate(key, enc); - msg = this._truncateToN(new bn(msg, 16)); - - // Zero-extend key to provide enough entropy - var bytes = this.n.byteLength(); - var bkey = key.getPrivate().toArray(); - for (var i = bkey.length; i < 21; i++) - bkey.unshift(0); - - // Zero-extend nonce to have the same byte size as N - var nonce = msg.toArray(); - for (var i = nonce.length; i < bytes; i++) - nonce.unshift(0); - - // Instantiate Hmac_DRBG - var drbg = new elliptic.hmacDRBG({ - hash: this.hash, - entropy: bkey, - nonce: nonce - }); - - // Number of bytes to generate - var ns1 = this.n.sub(new bn(1)); - do { - var k = new bn(drbg.generate(this.n.byteLength())); - k = this._truncateToN(k, true); - if (k.cmpn(1) <= 0 || k.cmp(ns1) >= 0) - continue; - - var kp = this.g.mul(k); - if (kp.isInfinity()) - continue; - - var r = kp.getX().mod(this.n); - if (r.cmpn(0) === 0) - continue; - - var s = k.invm(this.n).mul(r.mul(key.getPrivate()).iadd(msg)).mod(this.n); - if (s.cmpn(0) === 0) - continue; - - // Use complement of `s`, if it is > `n / 2` - if (options.canonical && s.cmp(this.nh) > 0) - s = this.n.sub(s); - - return new Signature({ r: r, s: s }); - } while (true); -}; - -EC.prototype.verify = function verify(msg, signature, key, enc) { - msg = this._truncateToN(new bn(msg, 16)); - key = this.keyFromPublic(key, enc); - signature = new Signature(signature, 'hex'); - - // Perform primitive values validation - var r = signature.r; - var s = signature.s; - if (r.cmpn(1) < 0 || r.cmp(this.n) >= 0) - return false; - if (s.cmpn(1) < 0 || s.cmp(this.n) >= 0) - return false; - - // Validate signature - var sinv = s.invm(this.n); - var u1 = sinv.mul(msg).mod(this.n); - var u2 = sinv.mul(r).mod(this.n); - - var p = this.g.mulAdd(u1, key.getPublic(), u2); - if (p.isInfinity()) - return false; - - return p.getX().mod(this.n).cmp(r) === 0; -}; - -},{"../../elliptic":151,"./key":159,"./signature":160,"bn.js":62}],159:[function(require,module,exports){ -'use strict'; - -var bn = require('bn.js'); - -var elliptic = require('../../elliptic'); -var utils = elliptic.utils; - -function KeyPair(ec, options) { - this.ec = ec; - this.priv = null; - this.pub = null; - - // KeyPair(ec, { priv: ..., pub: ... }) - if (options.priv) - this._importPrivate(options.priv, options.privEnc); - if (options.pub) - this._importPublic(options.pub, options.pubEnc); -} -module.exports = KeyPair; - -KeyPair.fromPublic = function fromPublic(ec, pub, enc) { - if (pub instanceof KeyPair) - return pub; - - return new KeyPair(ec, { - pub: pub, - pubEnc: enc - }); -}; - -KeyPair.fromPrivate = function fromPrivate(ec, priv, enc) { - if (priv instanceof KeyPair) - return priv; - - return new KeyPair(ec, { - priv: priv, - privEnc: enc - }); -}; - -KeyPair.prototype.validate = function validate() { - var pub = this.getPublic(); - - if (pub.isInfinity()) - return { result: false, reason: 'Invalid public key' }; - if (!pub.validate()) - return { result: false, reason: 'Public key is not a point' }; - if (!pub.mul(this.ec.curve.n).isInfinity()) - return { result: false, reason: 'Public key * N != O' }; - - return { result: true, reason: null }; -}; - -KeyPair.prototype.getPublic = function getPublic(compact, enc) { - if (!this.pub) - this.pub = this.ec.g.mul(this.priv); - - // compact is optional argument - if (typeof compact === 'string') { - enc = compact; - compact = null; - } + var bytes = this.n.byteLength(); + var ns2 = this.n.sub(new bn(2)); + do { + var priv = new bn(drbg.generate(bytes)); + if (priv.cmp(ns2) > 0) continue; - if (!enc) - return this.pub; + priv.iaddn(1); + return this.keyFromPrivate(priv); + } while (true); + }; - var len = this.ec.curve.p.byteLength(); - var x = this.pub.getX().toArray(); + EC.prototype._truncateToN = function truncateToN(msg, truncOnly) { + var delta = msg.byteLength() * 8 - this.n.bitLength(); + if (delta > 0) msg = msg.shrn(delta); + if (!truncOnly && msg.cmp(this.n) >= 0) return msg.sub(this.n); + else return msg; + }; - for (var i = x.length; i < len; i++) - x.unshift(0); + EC.prototype.sign = function sign(msg, key, enc, options) { + if (typeof enc === 'object') { + options = enc; + enc = null; + } + if (!options) options = {}; - var res; - if (this.ec.curve.type !== 'mont') { - if (compact) { - res = [ this.pub.getY().isEven() ? 0x02 : 0x03 ].concat(x); - } else { - var y = this.pub.getY().toArray(); - for (var i = y.length; i < len; i++) - y.unshift(0); - var res = [ 0x04 ].concat(x, y); - } - } else { - res = x; - } + key = this.keyFromPrivate(key, enc); + msg = this._truncateToN(new bn(msg, 16)); - return utils.encode(res, enc); -}; + // Zero-extend key to provide enough entropy + var bytes = this.n.byteLength(); + var bkey = key.getPrivate().toArray(); + for (var i = bkey.length; i < 21; i++) bkey.unshift(0); -KeyPair.prototype.getPrivate = function getPrivate(enc) { - if (enc === 'hex') - return this.priv.toString(16, 2); - else - return this.priv; -}; + // Zero-extend nonce to have the same byte size as N + var nonce = msg.toArray(); + for (var i = nonce.length; i < bytes; i++) nonce.unshift(0); -KeyPair.prototype._importPrivate = function _importPrivate(key, enc) { - this.priv = new bn(key, enc || 16); + // Instantiate Hmac_DRBG + var drbg = new elliptic.hmacDRBG({ + hash: this.hash, + entropy: bkey, + nonce: nonce, + }); - // Ensure that the priv won't be bigger than n, otherwise we may fail - // in fixed multiplication method - this.priv = this.priv.mod(this.ec.curve.n); -}; + // Number of bytes to generate + var ns1 = this.n.sub(new bn(1)); + do { + var k = new bn(drbg.generate(this.n.byteLength())); + k = this._truncateToN(k, true); + if (k.cmpn(1) <= 0 || k.cmp(ns1) >= 0) continue; -KeyPair.prototype._importPublic = function _importPublic(key, enc) { - if (key.x || key.y) { - this.pub = this.ec.curve.point(key.x, key.y); - return; - } + var kp = this.g.mul(k); + if (kp.isInfinity()) continue; - key = utils.toArray(key, enc); - if (this.ec.curve.type !== 'mont') - return this._importPublicShort(key); - else - return this._importPublicMont(key); -}; - -KeyPair.prototype._importPublicShort = function _importPublicShort(key) { - var len = this.ec.curve.p.byteLength(); - if (key[0] === 0x04 && key.length - 1 === 2 * len) { - this.pub = this.ec.curve.point( - key.slice(1, 1 + len), - key.slice(1 + len, 1 + 2 * len)); - } else if ((key[0] === 0x02 || key[0] === 0x03) && key.length - 1 === len) { - this.pub = this.ec.curve.pointFromX(key[0] === 0x03, key.slice(1, 1 + len)); - } -}; + var r = kp.getX().mod(this.n); + if (r.cmpn(0) === 0) continue; -KeyPair.prototype._importPublicMont = function _importPublicMont(key) { - this.pub = this.ec.curve.point(key, 1); -}; + var s = k + .invm(this.n) + .mul(r.mul(key.getPrivate()).iadd(msg)) + .mod(this.n); + if (s.cmpn(0) === 0) continue; -// ECDH -KeyPair.prototype.derive = function derive(pub) { - return pub.mul(this.priv).getX(); -}; + // Use complement of `s`, if it is > `n / 2` + if (options.canonical && s.cmp(this.nh) > 0) s = this.n.sub(s); -// ECDSA -KeyPair.prototype.sign = function sign(msg) { - return this.ec.sign(msg, this); -}; + return new Signature({ r: r, s: s }); + } while (true); + }; -KeyPair.prototype.verify = function verify(msg, signature) { - return this.ec.verify(msg, signature, this); -}; + EC.prototype.verify = function verify(msg, signature, key, enc) { + msg = this._truncateToN(new bn(msg, 16)); + key = this.keyFromPublic(key, enc); + signature = new Signature(signature, 'hex'); + + // Perform primitive values validation + var r = signature.r; + var s = signature.s; + if (r.cmpn(1) < 0 || r.cmp(this.n) >= 0) return false; + if (s.cmpn(1) < 0 || s.cmp(this.n) >= 0) return false; + + // Validate signature + var sinv = s.invm(this.n); + var u1 = sinv.mul(msg).mod(this.n); + var u2 = sinv.mul(r).mod(this.n); + + var p = this.g.mulAdd(u1, key.getPublic(), u2); + if (p.isInfinity()) return false; + + return ( + p + .getX() + .mod(this.n) + .cmp(r) === 0 + ); + }; + }, + { '../../elliptic': 151, './key': 159, './signature': 160, 'bn.js': 62 }, + ], + 159: [ + function(require, module, exports) { + 'use strict'; -KeyPair.prototype.inspect = function inspect() { - return ''; -}; + var bn = require('bn.js'); -},{"../../elliptic":151,"bn.js":62}],160:[function(require,module,exports){ -'use strict'; + var elliptic = require('../../elliptic'); + var utils = elliptic.utils; -var bn = require('bn.js'); + function KeyPair(ec, options) { + this.ec = ec; + this.priv = null; + this.pub = null; -var elliptic = require('../../elliptic'); -var utils = elliptic.utils; -var assert = utils.assert; + // KeyPair(ec, { priv: ..., pub: ... }) + if (options.priv) this._importPrivate(options.priv, options.privEnc); + if (options.pub) this._importPublic(options.pub, options.pubEnc); + } + module.exports = KeyPair; -function Signature(options, enc) { - if (options instanceof Signature) - return options; + KeyPair.fromPublic = function fromPublic(ec, pub, enc) { + if (pub instanceof KeyPair) return pub; - if (this._importDER(options, enc)) - return; + return new KeyPair(ec, { + pub: pub, + pubEnc: enc, + }); + }; - assert(options.r && options.s, 'Signature without r or s'); - this.r = new bn(options.r, 16); - this.s = new bn(options.s, 16); -} -module.exports = Signature; - -Signature.prototype._importDER = function _importDER(data, enc) { - data = utils.toArray(data, enc); - if (data.length < 6 || data[0] !== 0x30 || data[2] !== 0x02) - return false; - var total = data[1]; - if (1 + total > data.length) - return false; - var rlen = data[3]; - // Short length notation - if (rlen >= 0x80) - return false; - if (4 + rlen + 2 >= data.length) - return false; - if (data[4 + rlen] !== 0x02) - return false; - var slen = data[5 + rlen]; - // Short length notation - if (slen >= 0x80) - return false; - if (4 + rlen + 2 + slen > data.length) - return false; - - this.r = new bn(data.slice(4, 4 + rlen)); - this.s = new bn(data.slice(4 + rlen + 2, 4 + rlen + 2 + slen)); - - return true; -}; - -Signature.prototype.toDER = function toDER(enc) { - var r = this.r.toArray(); - var s = this.s.toArray(); - - // Pad values - if (r[0] & 0x80) - r = [ 0 ].concat(r); - // Pad values - if (s[0] & 0x80) - s = [ 0 ].concat(s); - - var total = r.length + s.length + 4; - var res = [ 0x30, total, 0x02, r.length ]; - res = res.concat(r, [ 0x02, s.length ], s); - return utils.encode(res, enc); -}; - -},{"../../elliptic":151,"bn.js":62}],161:[function(require,module,exports){ -'use strict'; - -var hash = require('hash.js'); -var elliptic = require('../elliptic'); -var utils = elliptic.utils; -var assert = utils.assert; - -function HmacDRBG(options) { - if (!(this instanceof HmacDRBG)) - return new HmacDRBG(options); - this.hash = options.hash; - this.predResist = !!options.predResist; - - this.outLen = this.hash.outSize; - this.minEntropy = options.minEntropy || this.hash.hmacStrength; - - this.reseed = null; - this.reseedInterval = null; - this.K = null; - this.V = null; - - var entropy = utils.toArray(options.entropy, options.entropyEnc); - var nonce = utils.toArray(options.nonce, options.nonceEnc); - var pers = utils.toArray(options.pers, options.persEnc); - assert(entropy.length >= (this.minEntropy / 8), - 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); - this._init(entropy, nonce, pers); -} -module.exports = HmacDRBG; + KeyPair.fromPrivate = function fromPrivate(ec, priv, enc) { + if (priv instanceof KeyPair) return priv; -HmacDRBG.prototype._init = function init(entropy, nonce, pers) { - var seed = entropy.concat(nonce).concat(pers); + return new KeyPair(ec, { + priv: priv, + privEnc: enc, + }); + }; - this.K = new Array(this.outLen / 8); - this.V = new Array(this.outLen / 8); - for (var i = 0; i < this.V.length; i++) { - this.K[i] = 0x00; - this.V[i] = 0x01; - } + KeyPair.prototype.validate = function validate() { + var pub = this.getPublic(); - this._update(seed); - this.reseed = 1; - this.reseedInterval = 0x1000000000000; // 2^48 -}; - -HmacDRBG.prototype._hmac = function hmac() { - return new hash.hmac(this.hash, this.K); -}; - -HmacDRBG.prototype._update = function update(seed) { - var kmac = this._hmac() - .update(this.V) - .update([ 0x00 ]); - if (seed) - kmac = kmac.update(seed); - this.K = kmac.digest(); - this.V = this._hmac().update(this.V).digest(); - if (!seed) - return; - - this.K = this._hmac() - .update(this.V) - .update([ 0x01 ]) - .update(seed) - .digest(); - this.V = this._hmac().update(this.V).digest(); -}; - -HmacDRBG.prototype.reseed = function reseed(entropy, entropyEnc, add, addEnc) { - // Optional entropy enc - if (typeof entropyEnc !== 'string') { - addEnc = add; - add = entropyEnc; - entropyEnc = null; - } + if (pub.isInfinity()) return { result: false, reason: 'Invalid public key' }; + if (!pub.validate()) return { result: false, reason: 'Public key is not a point' }; + if (!pub.mul(this.ec.curve.n).isInfinity()) return { result: false, reason: 'Public key * N != O' }; - entropy = utils.toBuffer(entropy, entropyEnc); - add = utils.toBuffer(add, addEnc); + return { result: true, reason: null }; + }; - assert(entropy.length >= (this.minEntropy / 8), - 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); + KeyPair.prototype.getPublic = function getPublic(compact, enc) { + if (!this.pub) this.pub = this.ec.g.mul(this.priv); - this._update(entropy.concat(add || [])); - this.reseed = 1; -}; + // compact is optional argument + if (typeof compact === 'string') { + enc = compact; + compact = null; + } -HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) { - if (this.reseed > this.reseedInterval) - throw new Error('Reseed is required'); + if (!enc) return this.pub; - // Optional encoding - if (typeof enc !== 'string') { - addEnc = add; - add = enc; - enc = null; - } + var len = this.ec.curve.p.byteLength(); + var x = this.pub.getX().toArray(); - // Optional additional data - if (add) { - add = utils.toArray(add, addEnc); - this._update(add); - } + for (var i = x.length; i < len; i++) x.unshift(0); - var temp = []; - while (temp.length < len) { - this.V = this._hmac().update(this.V).digest(); - temp = temp.concat(this.V); - } + var res; + if (this.ec.curve.type !== 'mont') { + if (compact) { + res = [this.pub.getY().isEven() ? 0x02 : 0x03].concat(x); + } else { + var y = this.pub.getY().toArray(); + for (var i = y.length; i < len; i++) y.unshift(0); + var res = [0x04].concat(x, y); + } + } else { + res = x; + } - var res = temp.slice(0, len); - this._update(add); - this.reseed++; - return utils.encode(res, enc); -}; - -},{"../elliptic":151,"hash.js":168}],162:[function(require,module,exports){ -arguments[4][106][0].apply(exports,arguments) -},{"dup":106}],163:[function(require,module,exports){ -'use strict'; - -var utils = exports; - -utils.assert = function assert(val, msg) { - if (!val) - throw new Error(msg || 'Assertion failed'); -}; - -function toArray(msg, enc) { - if (Array.isArray(msg)) - return msg.slice(); - if (!msg) - return []; - var res = []; - if (typeof msg !== 'string') { - for (var i = 0; i < msg.length; i++) - res[i] = msg[i] | 0; - return res; - } - if (!enc) { - for (var i = 0; i < msg.length; i++) { - var c = msg.charCodeAt(i); - var hi = c >> 8; - var lo = c & 0xff; - if (hi) - res.push(hi, lo); - else - res.push(lo); - } - } else if (enc === 'hex') { - msg = msg.replace(/[^a-z0-9]+/ig, ''); - if (msg.length % 2 !== 0) - msg = '0' + msg; - for (var i = 0; i < msg.length; i += 2) - res.push(parseInt(msg[i] + msg[i + 1], 16)); - } - return res; -} -utils.toArray = toArray; + return utils.encode(res, enc); + }; -function zero2(word) { - if (word.length === 1) - return '0' + word; - else - return word; -} -utils.zero2 = zero2; + KeyPair.prototype.getPrivate = function getPrivate(enc) { + if (enc === 'hex') return this.priv.toString(16, 2); + else return this.priv; + }; -function toHex(msg) { - var res = ''; - for (var i = 0; i < msg.length; i++) - res += zero2(msg[i].toString(16)); - return res; -} -utils.toHex = toHex; - -utils.encode = function encode(arr, enc) { - if (enc === 'hex') - return toHex(arr); - else - return arr; -}; - -// Represent num in a w-NAF form -function getNAF(num, w) { - var naf = []; - var ws = 1 << (w + 1); - var k = num.clone(); - while (k.cmpn(1) >= 0) { - var z; - if (k.isOdd()) { - var mod = k.andln(ws - 1); - if (mod > (ws >> 1) - 1) - z = (ws >> 1) - mod; - else - z = mod; - k.isubn(z); - } else { - z = 0; - } - naf.push(z); + KeyPair.prototype._importPrivate = function _importPrivate(key, enc) { + this.priv = new bn(key, enc || 16); - // Optimization, shift by word if possible - var shift = (k.cmpn(0) !== 0 && k.andln(ws - 1) === 0) ? (w + 1) : 1; - for (var i = 1; i < shift; i++) - naf.push(0); - k.ishrn(shift); - } + // Ensure that the priv won't be bigger than n, otherwise we may fail + // in fixed multiplication method + this.priv = this.priv.mod(this.ec.curve.n); + }; - return naf; -} -utils.getNAF = getNAF; + KeyPair.prototype._importPublic = function _importPublic(key, enc) { + if (key.x || key.y) { + this.pub = this.ec.curve.point(key.x, key.y); + return; + } -// Represent k1, k2 in a Joint Sparse Form -function getJSF(k1, k2) { - var jsf = [ - [], - [] - ]; + key = utils.toArray(key, enc); + if (this.ec.curve.type !== 'mont') return this._importPublicShort(key); + else return this._importPublicMont(key); + }; - k1 = k1.clone(); - k2 = k2.clone(); - var d1 = 0; - var d2 = 0; - while (k1.cmpn(-d1) > 0 || k2.cmpn(-d2) > 0) { - - // First phase - var m14 = (k1.andln(3) + d1) & 3; - var m24 = (k2.andln(3) + d2) & 3; - if (m14 === 3) - m14 = -1; - if (m24 === 3) - m24 = -1; - var u1; - if ((m14 & 1) === 0) { - u1 = 0; - } else { - var m8 = (k1.andln(7) + d1) & 7; - if ((m8 === 3 || m8 === 5) && m24 === 2) - u1 = -m14; - else - u1 = m14; - } - jsf[0].push(u1); - - var u2; - if ((m24 & 1) === 0) { - u2 = 0; - } else { - var m8 = (k2.andln(7) + d2) & 7; - if ((m8 === 3 || m8 === 5) && m14 === 2) - u2 = -m24; - else - u2 = m24; - } - jsf[1].push(u2); - - // Second phase - if (2 * d1 === u1 + 1) - d1 = 1 - d1; - if (2 * d2 === u2 + 1) - d2 = 1 - d2; - k1.ishrn(1); - k2.ishrn(1); - } + KeyPair.prototype._importPublicShort = function _importPublicShort(key) { + var len = this.ec.curve.p.byteLength(); + if (key[0] === 0x04 && key.length - 1 === 2 * len) { + this.pub = this.ec.curve.point(key.slice(1, 1 + len), key.slice(1 + len, 1 + 2 * len)); + } else if ((key[0] === 0x02 || key[0] === 0x03) && key.length - 1 === len) { + this.pub = this.ec.curve.pointFromX(key[0] === 0x03, key.slice(1, 1 + len)); + } + }; - return jsf; -} -utils.getJSF = getJSF; - -},{}],164:[function(require,module,exports){ -module.exports={ - "_args": [ - [ - "elliptic@3.0.3", - "/Users/tonypizzicato/dev/meritlabs/lightwallet-stack/packages/bitcore-lib" - ] - ], - "_from": "elliptic@3.0.3", - "_id": "elliptic@3.0.3", - "_inBundle": false, - "_integrity": "sha1-hlybQgv75VAGuflp+XoNLESWZZU=", - "_location": "/elliptic", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "elliptic@3.0.3", - "name": "elliptic", - "escapedName": "elliptic", - "rawSpec": "3.0.3", - "saveSpec": null, - "fetchSpec": "3.0.3" - }, - "_requiredBy": [ - "/" - ], - "_resolved": "https://registry.npmjs.org/elliptic/-/elliptic-3.0.3.tgz", - "_spec": "3.0.3", - "_where": "/Users/tonypizzicato/dev/meritlabs/lightwallet-stack/packages/bitcore-lib", - "author": { - "name": "Fedor Indutny", - "email": "fedor@indutny.com" - }, - "bugs": { - "url": "https://github.com/indutny/elliptic/issues" - }, - "dependencies": { - "bn.js": "^2.0.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "inherits": "^2.0.1" - }, - "description": "EC cryptography", - "devDependencies": { - "browserify": "^3.44.2", - "jscs": "^1.11.3", - "jshint": "^2.6.0", - "mocha": "^2.1.0", - "uglify-js": "^2.4.13" - }, - "homepage": "https://github.com/indutny/elliptic", - "keywords": [ - "EC", - "Elliptic", - "curve", - "Cryptography" - ], - "license": "MIT", - "main": "lib/elliptic.js", - "name": "elliptic", - "repository": { - "type": "git", - "url": "git+ssh://git@github.com/indutny/elliptic.git" - }, - "scripts": { - "test": "make lint && mocha --reporter=spec test/*-test.js" - }, - "version": "3.0.3" -} + KeyPair.prototype._importPublicMont = function _importPublicMont(key) { + this.pub = this.ec.curve.point(key, 1); + }; -},{}],165:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; - -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; - -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; - -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; - -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; -}; - -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) - this._events = {}; - - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } else { - // At least give some kind of context to the user - var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); - err.context = er; - throw err; - } - } - } + // ECDH + KeyPair.prototype.derive = function derive(pub) { + return pub.mul(this.priv).getX(); + }; - handler = this._events[type]; - - if (isUndefined(handler)) - return false; - - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - args = Array.prototype.slice.call(arguments, 1); - handler.apply(this, args); - } - } else if (isObject(handler)) { - args = Array.prototype.slice.call(arguments, 1); - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } + // ECDSA + KeyPair.prototype.sign = function sign(msg) { + return this.ec.sign(msg, this); + }; - return true; -}; - -EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events) - this._events = {}; - - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); - - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } + KeyPair.prototype.verify = function verify(msg, signature) { + return this.ec.verify(msg, signature, this); + }; - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } + KeyPair.prototype.inspect = function inspect() { + return ( + '' + ); + }; + }, + { '../../elliptic': 151, 'bn.js': 62 }, + ], + 160: [ + function(require, module, exports) { + 'use strict'; - return this; -}; + var bn = require('bn.js'); -EventEmitter.prototype.on = EventEmitter.prototype.addListener; + var elliptic = require('../../elliptic'); + var utils = elliptic.utils; + var assert = utils.assert; -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); + function Signature(options, enc) { + if (options instanceof Signature) return options; - var fired = false; + if (this._importDER(options, enc)) return; - function g() { - this.removeListener(type, g); + assert(options.r && options.s, 'Signature without r or s'); + this.r = new bn(options.r, 16); + this.s = new bn(options.s, 16); + } + module.exports = Signature; + + Signature.prototype._importDER = function _importDER(data, enc) { + data = utils.toArray(data, enc); + if (data.length < 6 || data[0] !== 0x30 || data[2] !== 0x02) return false; + var total = data[1]; + if (1 + total > data.length) return false; + var rlen = data[3]; + // Short length notation + if (rlen >= 0x80) return false; + if (4 + rlen + 2 >= data.length) return false; + if (data[4 + rlen] !== 0x02) return false; + var slen = data[5 + rlen]; + // Short length notation + if (slen >= 0x80) return false; + if (4 + rlen + 2 + slen > data.length) return false; + + this.r = new bn(data.slice(4, 4 + rlen)); + this.s = new bn(data.slice(4 + rlen + 2, 4 + rlen + 2 + slen)); - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } + return true; + }; - g.listener = listener; - this.on(type, g); + Signature.prototype.toDER = function toDER(enc) { + var r = this.r.toArray(); + var s = this.s.toArray(); - return this; -}; + // Pad values + if (r[0] & 0x80) r = [0].concat(r); + // Pad values + if (s[0] & 0x80) s = [0].concat(s); -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; + var total = r.length + s.length + 4; + var res = [0x30, total, 0x02, r.length]; + res = res.concat(r, [0x02, s.length], s); + return utils.encode(res, enc); + }; + }, + { '../../elliptic': 151, 'bn.js': 62 }, + ], + 161: [ + function(require, module, exports) { + 'use strict'; + + var hash = require('hash.js'); + var elliptic = require('../elliptic'); + var utils = elliptic.utils; + var assert = utils.assert; + + function HmacDRBG(options) { + if (!(this instanceof HmacDRBG)) return new HmacDRBG(options); + this.hash = options.hash; + this.predResist = !!options.predResist; + + this.outLen = this.hash.outSize; + this.minEntropy = options.minEntropy || this.hash.hmacStrength; + + this.reseed = null; + this.reseedInterval = null; + this.K = null; + this.V = null; + + var entropy = utils.toArray(options.entropy, options.entropyEnc); + var nonce = utils.toArray(options.nonce, options.nonceEnc); + var pers = utils.toArray(options.pers, options.persEnc); + assert(entropy.length >= this.minEntropy / 8, 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); + this._init(entropy, nonce, pers); + } + module.exports = HmacDRBG; - if (!isFunction(listener)) - throw TypeError('listener must be a function'); + HmacDRBG.prototype._init = function init(entropy, nonce, pers) { + var seed = entropy.concat(nonce).concat(pers); - if (!this._events || !this._events[type]) - return this; + this.K = new Array(this.outLen / 8); + this.V = new Array(this.outLen / 8); + for (var i = 0; i < this.V.length; i++) { + this.K[i] = 0x00; + this.V[i] = 0x01; + } - list = this._events[type]; - length = list.length; - position = -1; + this._update(seed); + this.reseed = 1; + this.reseedInterval = 0x1000000000000; // 2^48 + }; - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); + HmacDRBG.prototype._hmac = function hmac() { + return new hash.hmac(this.hash, this.K); + }; - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } + HmacDRBG.prototype._update = function update(seed) { + var kmac = this._hmac() + .update(this.V) + .update([0x00]); + if (seed) kmac = kmac.update(seed); + this.K = kmac.digest(); + this.V = this._hmac() + .update(this.V) + .digest(); + if (!seed) return; + + this.K = this._hmac() + .update(this.V) + .update([0x01]) + .update(seed) + .digest(); + this.V = this._hmac() + .update(this.V) + .digest(); + }; - if (position < 0) - return this; + HmacDRBG.prototype.reseed = function reseed(entropy, entropyEnc, add, addEnc) { + // Optional entropy enc + if (typeof entropyEnc !== 'string') { + addEnc = add; + add = entropyEnc; + entropyEnc = null; + } - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } + entropy = utils.toBuffer(entropy, entropyEnc); + add = utils.toBuffer(add, addEnc); - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } + assert(entropy.length >= this.minEntropy / 8, 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); - return this; -}; + this._update(entropy.concat(add || [])); + this.reseed = 1; + }; -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; + HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) { + if (this.reseed > this.reseedInterval) throw new Error('Reseed is required'); - if (!this._events) - return this; + // Optional encoding + if (typeof enc !== 'string') { + addEnc = add; + add = enc; + enc = null; + } - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } + // Optional additional data + if (add) { + add = utils.toArray(add, addEnc); + this._update(add); + } - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } + var temp = []; + while (temp.length < len) { + this.V = this._hmac() + .update(this.V) + .digest(); + temp = temp.concat(this.V); + } - listeners = this._events[type]; + var res = temp.slice(0, len); + this._update(add); + this.reseed++; + return utils.encode(res, enc); + }; + }, + { '../elliptic': 151, 'hash.js': 168 }, + ], + 162: [ + function(require, module, exports) { + arguments[4][106][0].apply(exports, arguments); + }, + { dup: 106 }, + ], + 163: [ + function(require, module, exports) { + 'use strict'; - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else if (listeners) { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; - - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; - -EventEmitter.prototype.listenerCount = function(type) { - if (this._events) { - var evlistener = this._events[type]; - - if (isFunction(evlistener)) - return 1; - else if (evlistener) - return evlistener.length; - } - return 0; -}; + var utils = exports; -EventEmitter.listenerCount = function(emitter, type) { - return emitter.listenerCount(type); -}; + utils.assert = function assert(val, msg) { + if (!val) throw new Error(msg || 'Assertion failed'); + }; -function isFunction(arg) { - return typeof arg === 'function'; -} + function toArray(msg, enc) { + if (Array.isArray(msg)) return msg.slice(); + if (!msg) return []; + var res = []; + if (typeof msg !== 'string') { + for (var i = 0; i < msg.length; i++) res[i] = msg[i] | 0; + return res; + } + if (!enc) { + for (var i = 0; i < msg.length; i++) { + var c = msg.charCodeAt(i); + var hi = c >> 8; + var lo = c & 0xff; + if (hi) res.push(hi, lo); + else res.push(lo); + } + } else if (enc === 'hex') { + msg = msg.replace(/[^a-z0-9]+/gi, ''); + if (msg.length % 2 !== 0) msg = '0' + msg; + for (var i = 0; i < msg.length; i += 2) res.push(parseInt(msg[i] + msg[i + 1], 16)); + } + return res; + } + utils.toArray = toArray; -function isNumber(arg) { - return typeof arg === 'number'; -} + function zero2(word) { + if (word.length === 1) return '0' + word; + else return word; + } + utils.zero2 = zero2; -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} + function toHex(msg) { + var res = ''; + for (var i = 0; i < msg.length; i++) res += zero2(msg[i].toString(16)); + return res; + } + utils.toHex = toHex; -function isUndefined(arg) { - return arg === void 0; -} + utils.encode = function encode(arr, enc) { + if (enc === 'hex') return toHex(arr); + else return arr; + }; -},{}],166:[function(require,module,exports){ -var Buffer = require('safe-buffer').Buffer -var MD5 = require('md5.js') + // Represent num in a w-NAF form + function getNAF(num, w) { + var naf = []; + var ws = 1 << (w + 1); + var k = num.clone(); + while (k.cmpn(1) >= 0) { + var z; + if (k.isOdd()) { + var mod = k.andln(ws - 1); + if (mod > (ws >> 1) - 1) z = (ws >> 1) - mod; + else z = mod; + k.isubn(z); + } else { + z = 0; + } + naf.push(z); -/* eslint-disable camelcase */ -function EVP_BytesToKey (password, salt, keyBits, ivLen) { - if (!Buffer.isBuffer(password)) password = Buffer.from(password, 'binary') - if (salt) { - if (!Buffer.isBuffer(salt)) salt = Buffer.from(salt, 'binary') - if (salt.length !== 8) throw new RangeError('salt should be Buffer with 8 byte length') - } + // Optimization, shift by word if possible + var shift = k.cmpn(0) !== 0 && k.andln(ws - 1) === 0 ? w + 1 : 1; + for (var i = 1; i < shift; i++) naf.push(0); + k.ishrn(shift); + } - var keyLen = keyBits / 8 - var key = Buffer.alloc(keyLen) - var iv = Buffer.alloc(ivLen || 0) - var tmp = Buffer.alloc(0) - - while (keyLen > 0 || ivLen > 0) { - var hash = new MD5() - hash.update(tmp) - hash.update(password) - if (salt) hash.update(salt) - tmp = hash.digest() - - var used = 0 - - if (keyLen > 0) { - var keyStart = key.length - keyLen - used = Math.min(keyLen, tmp.length) - tmp.copy(key, keyStart, 0, used) - keyLen -= used - } + return naf; + } + utils.getNAF = getNAF; + + // Represent k1, k2 in a Joint Sparse Form + function getJSF(k1, k2) { + var jsf = [[], []]; + + k1 = k1.clone(); + k2 = k2.clone(); + var d1 = 0; + var d2 = 0; + while (k1.cmpn(-d1) > 0 || k2.cmpn(-d2) > 0) { + // First phase + var m14 = (k1.andln(3) + d1) & 3; + var m24 = (k2.andln(3) + d2) & 3; + if (m14 === 3) m14 = -1; + if (m24 === 3) m24 = -1; + var u1; + if ((m14 & 1) === 0) { + u1 = 0; + } else { + var m8 = (k1.andln(7) + d1) & 7; + if ((m8 === 3 || m8 === 5) && m24 === 2) u1 = -m14; + else u1 = m14; + } + jsf[0].push(u1); - if (used < tmp.length && ivLen > 0) { - var ivStart = iv.length - ivLen - var length = Math.min(ivLen, tmp.length - used) - tmp.copy(iv, ivStart, used, used + length) - ivLen -= length - } - } + var u2; + if ((m24 & 1) === 0) { + u2 = 0; + } else { + var m8 = (k2.andln(7) + d2) & 7; + if ((m8 === 3 || m8 === 5) && m14 === 2) u2 = -m24; + else u2 = m24; + } + jsf[1].push(u2); - tmp.fill(0) - return { key: key, iv: iv } -} + // Second phase + if (2 * d1 === u1 + 1) d1 = 1 - d1; + if (2 * d2 === u2 + 1) d2 = 1 - d2; + k1.ishrn(1); + k2.ishrn(1); + } -module.exports = EVP_BytesToKey + return jsf; + } + utils.getJSF = getJSF; + }, + {}, + ], + 164: [ + function(require, module, exports) { + module.exports = { + _args: [['elliptic@3.0.3', '/Users/tonypizzicato/dev/meritlabs/lightwallet-stack/packages/bitcore-lib']], + _from: 'elliptic@3.0.3', + _id: 'elliptic@3.0.3', + _inBundle: false, + _integrity: 'sha1-hlybQgv75VAGuflp+XoNLESWZZU=', + _location: '/elliptic', + _phantomChildren: {}, + _requested: { + type: 'version', + registry: true, + raw: 'elliptic@3.0.3', + name: 'elliptic', + escapedName: 'elliptic', + rawSpec: '3.0.3', + saveSpec: null, + fetchSpec: '3.0.3', + }, + _requiredBy: ['/'], + _resolved: 'https://registry.npmjs.org/elliptic/-/elliptic-3.0.3.tgz', + _spec: '3.0.3', + _where: '/Users/tonypizzicato/dev/meritlabs/lightwallet-stack/packages/bitcore-lib', + author: { + name: 'Fedor Indutny', + email: 'fedor@indutny.com', + }, + bugs: { + url: 'https://github.com/indutny/elliptic/issues', + }, + dependencies: { + 'bn.js': '^2.0.0', + brorand: '^1.0.1', + 'hash.js': '^1.0.0', + inherits: '^2.0.1', + }, + description: 'EC cryptography', + devDependencies: { + browserify: '^3.44.2', + jscs: '^1.11.3', + jshint: '^2.6.0', + mocha: '^2.1.0', + 'uglify-js': '^2.4.13', + }, + homepage: 'https://github.com/indutny/elliptic', + keywords: ['EC', 'Elliptic', 'curve', 'Cryptography'], + license: 'MIT', + main: 'lib/elliptic.js', + name: 'elliptic', + repository: { + type: 'git', + url: 'git+ssh://git@github.com/indutny/elliptic.git', + }, + scripts: { + test: 'make lint && mocha --reporter=spec test/*-test.js', + }, + version: '3.0.3', + }; + }, + {}, + ], + 165: [ + function(require, module, exports) { + // Copyright Joyent, Inc. and other Node contributors. + // + // Permission is hereby granted, free of charge, to any person obtaining a + // copy of this software and associated documentation files (the + // "Software"), to deal in the Software without restriction, including + // without limitation the rights to use, copy, modify, merge, publish, + // distribute, sublicense, and/or sell copies of the Software, and to permit + // persons to whom the Software is furnished to do so, subject to the + // following conditions: + // + // The above copyright notice and this permission notice shall be included + // in all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + // USE OR OTHER DEALINGS IN THE SOFTWARE. + + function EventEmitter() { + this._events = this._events || {}; + this._maxListeners = this._maxListeners || undefined; + } + module.exports = EventEmitter; -},{"md5.js":188,"safe-buffer":233}],167:[function(require,module,exports){ -(function (Buffer){ -'use strict' -var Transform = require('stream').Transform -var inherits = require('inherits') + // Backwards-compat with node 0.10.x + EventEmitter.EventEmitter = EventEmitter; -function HashBase (blockSize) { - Transform.call(this) + EventEmitter.prototype._events = undefined; + EventEmitter.prototype._maxListeners = undefined; - this._block = new Buffer(blockSize) - this._blockSize = blockSize - this._blockOffset = 0 - this._length = [0, 0, 0, 0] + // By default EventEmitters will print a warning if more than 10 listeners are + // added to it. This is a useful default which helps finding memory leaks. + EventEmitter.defaultMaxListeners = 10; - this._finalized = false -} + // Obviously not all Emitters should be limited to 10. This function allows + // that to be increased. Set to zero for unlimited. + EventEmitter.prototype.setMaxListeners = function(n) { + if (!isNumber(n) || n < 0 || isNaN(n)) throw TypeError('n must be a positive number'); + this._maxListeners = n; + return this; + }; -inherits(HashBase, Transform) + EventEmitter.prototype.emit = function(type) { + var er, handler, len, args, i, listeners; + + if (!this._events) this._events = {}; + + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events.error || (isObject(this._events.error) && !this._events.error.length)) { + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } else { + // At least give some kind of context to the user + var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); + err.context = er; + throw err; + } + } + } -HashBase.prototype._transform = function (chunk, encoding, callback) { - var error = null - try { - if (encoding !== 'buffer') chunk = new Buffer(chunk, encoding) - this.update(chunk) - } catch (err) { - error = err - } + handler = this._events[type]; + + if (isUndefined(handler)) return false; + + if (isFunction(handler)) { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + args = Array.prototype.slice.call(arguments, 1); + handler.apply(this, args); + } + } else if (isObject(handler)) { + args = Array.prototype.slice.call(arguments, 1); + listeners = handler.slice(); + len = listeners.length; + for (i = 0; i < len; i++) listeners[i].apply(this, args); + } - callback(error) -} + return true; + }; -HashBase.prototype._flush = function (callback) { - var error = null - try { - this.push(this._digest()) - } catch (err) { - error = err - } + EventEmitter.prototype.addListener = function(type, listener) { + var m; - callback(error) -} + if (!isFunction(listener)) throw TypeError('listener must be a function'); -HashBase.prototype.update = function (data, encoding) { - if (!Buffer.isBuffer(data) && typeof data !== 'string') throw new TypeError('Data must be a string or a buffer') - if (this._finalized) throw new Error('Digest already called') - if (!Buffer.isBuffer(data)) data = new Buffer(data, encoding || 'binary') - - // consume data - var block = this._block - var offset = 0 - while (this._blockOffset + data.length - offset >= this._blockSize) { - for (var i = this._blockOffset; i < this._blockSize;) block[i++] = data[offset++] - this._update() - this._blockOffset = 0 - } - while (offset < data.length) block[this._blockOffset++] = data[offset++] + if (!this._events) this._events = {}; - // update length - for (var j = 0, carry = data.length * 8; carry > 0; ++j) { - this._length[j] += carry - carry = (this._length[j] / 0x0100000000) | 0 - if (carry > 0) this._length[j] -= 0x0100000000 * carry - } + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (this._events.newListener) + this.emit('newListener', type, isFunction(listener.listener) ? listener.listener : listener); - return this -} + if (!this._events[type]) + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + else if (isObject(this._events[type])) + // If we've already got an array, just append. + this._events[type].push(listener); + // Adding the second element, need to change to array. + else this._events[type] = [this._events[type], listener]; -HashBase.prototype._update = function (data) { - throw new Error('_update is not implemented') -} + // Check for listener leak + if (isObject(this._events[type]) && !this._events[type].warned) { + if (!isUndefined(this._maxListeners)) { + m = this._maxListeners; + } else { + m = EventEmitter.defaultMaxListeners; + } -HashBase.prototype.digest = function (encoding) { - if (this._finalized) throw new Error('Digest already called') - this._finalized = true + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error( + '(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length, + ); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); + } + } + } - var digest = this._digest() - if (encoding !== undefined) digest = digest.toString(encoding) - return digest -} + return this; + }; -HashBase.prototype._digest = function () { - throw new Error('_digest is not implemented') -} + EventEmitter.prototype.on = EventEmitter.prototype.addListener; -module.exports = HashBase - -}).call(this,require("buffer").Buffer) -},{"buffer":113,"inherits":184,"stream":242}],168:[function(require,module,exports){ -var hash = exports; - -hash.utils = require('./hash/utils'); -hash.common = require('./hash/common'); -hash.sha = require('./hash/sha'); -hash.ripemd = require('./hash/ripemd'); -hash.hmac = require('./hash/hmac'); - -// Proxy hash functions to the main object -hash.sha1 = hash.sha.sha1; -hash.sha256 = hash.sha.sha256; -hash.sha224 = hash.sha.sha224; -hash.sha384 = hash.sha.sha384; -hash.sha512 = hash.sha.sha512; -hash.ripemd160 = hash.ripemd.ripemd160; - -},{"./hash/common":169,"./hash/hmac":170,"./hash/ripemd":171,"./hash/sha":172,"./hash/utils":179}],169:[function(require,module,exports){ -'use strict'; - -var utils = require('./utils'); -var assert = require('minimalistic-assert'); - -function BlockHash() { - this.pending = null; - this.pendingTotal = 0; - this.blockSize = this.constructor.blockSize; - this.outSize = this.constructor.outSize; - this.hmacStrength = this.constructor.hmacStrength; - this.padLength = this.constructor.padLength / 8; - this.endian = 'big'; - - this._delta8 = this.blockSize / 8; - this._delta32 = this.blockSize / 32; -} -exports.BlockHash = BlockHash; - -BlockHash.prototype.update = function update(msg, enc) { - // Convert message to array, pad it, and join into 32bit blocks - msg = utils.toArray(msg, enc); - if (!this.pending) - this.pending = msg; - else - this.pending = this.pending.concat(msg); - this.pendingTotal += msg.length; - - // Enough data, try updating - if (this.pending.length >= this._delta8) { - msg = this.pending; - - // Process pending data in blocks - var r = msg.length % this._delta8; - this.pending = msg.slice(msg.length - r, msg.length); - if (this.pending.length === 0) - this.pending = null; - - msg = utils.join32(msg, 0, msg.length - r, this.endian); - for (var i = 0; i < msg.length; i += this._delta32) - this._update(msg, i, i + this._delta32); - } + EventEmitter.prototype.once = function(type, listener) { + if (!isFunction(listener)) throw TypeError('listener must be a function'); - return this; -}; - -BlockHash.prototype.digest = function digest(enc) { - this.update(this._pad()); - assert(this.pending === null); - - return this._digest(enc); -}; - -BlockHash.prototype._pad = function pad() { - var len = this.pendingTotal; - var bytes = this._delta8; - var k = bytes - ((len + this.padLength) % bytes); - var res = new Array(k + this.padLength); - res[0] = 0x80; - for (var i = 1; i < k; i++) - res[i] = 0; - - // Append length - len <<= 3; - if (this.endian === 'big') { - for (var t = 8; t < this.padLength; t++) - res[i++] = 0; - - res[i++] = 0; - res[i++] = 0; - res[i++] = 0; - res[i++] = 0; - res[i++] = (len >>> 24) & 0xff; - res[i++] = (len >>> 16) & 0xff; - res[i++] = (len >>> 8) & 0xff; - res[i++] = len & 0xff; - } else { - res[i++] = len & 0xff; - res[i++] = (len >>> 8) & 0xff; - res[i++] = (len >>> 16) & 0xff; - res[i++] = (len >>> 24) & 0xff; - res[i++] = 0; - res[i++] = 0; - res[i++] = 0; - res[i++] = 0; - - for (t = 8; t < this.padLength; t++) - res[i++] = 0; - } + var fired = false; - return res; -}; + function g() { + this.removeListener(type, g); -},{"./utils":179,"minimalistic-assert":192}],170:[function(require,module,exports){ -'use strict'; + if (!fired) { + fired = true; + listener.apply(this, arguments); + } + } -var utils = require('./utils'); -var assert = require('minimalistic-assert'); + g.listener = listener; + this.on(type, g); -function Hmac(hash, key, enc) { - if (!(this instanceof Hmac)) - return new Hmac(hash, key, enc); - this.Hash = hash; - this.blockSize = hash.blockSize / 8; - this.outSize = hash.outSize / 8; - this.inner = null; - this.outer = null; + return this; + }; - this._init(utils.toArray(key, enc)); -} -module.exports = Hmac; - -Hmac.prototype._init = function init(key) { - // Shorten key, if needed - if (key.length > this.blockSize) - key = new this.Hash().update(key).digest(); - assert(key.length <= this.blockSize); - - // Add padding to key - for (var i = key.length; i < this.blockSize; i++) - key.push(0); - - for (i = 0; i < key.length; i++) - key[i] ^= 0x36; - this.inner = new this.Hash().update(key); - - // 0x36 ^ 0x5c = 0x6a - for (i = 0; i < key.length; i++) - key[i] ^= 0x6a; - this.outer = new this.Hash().update(key); -}; - -Hmac.prototype.update = function update(msg, enc) { - this.inner.update(msg, enc); - return this; -}; - -Hmac.prototype.digest = function digest(enc) { - this.outer.update(this.inner.digest()); - return this.outer.digest(enc); -}; - -},{"./utils":179,"minimalistic-assert":192}],171:[function(require,module,exports){ -'use strict'; - -var utils = require('./utils'); -var common = require('./common'); - -var rotl32 = utils.rotl32; -var sum32 = utils.sum32; -var sum32_3 = utils.sum32_3; -var sum32_4 = utils.sum32_4; -var BlockHash = common.BlockHash; - -function RIPEMD160() { - if (!(this instanceof RIPEMD160)) - return new RIPEMD160(); - - BlockHash.call(this); - - this.h = [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 ]; - this.endian = 'little'; -} -utils.inherits(RIPEMD160, BlockHash); -exports.ripemd160 = RIPEMD160; - -RIPEMD160.blockSize = 512; -RIPEMD160.outSize = 160; -RIPEMD160.hmacStrength = 192; -RIPEMD160.padLength = 64; - -RIPEMD160.prototype._update = function update(msg, start) { - var A = this.h[0]; - var B = this.h[1]; - var C = this.h[2]; - var D = this.h[3]; - var E = this.h[4]; - var Ah = A; - var Bh = B; - var Ch = C; - var Dh = D; - var Eh = E; - for (var j = 0; j < 80; j++) { - var T = sum32( - rotl32( - sum32_4(A, f(j, B, C, D), msg[r[j] + start], K(j)), - s[j]), - E); - A = E; - E = D; - D = rotl32(C, 10); - C = B; - B = T; - T = sum32( - rotl32( - sum32_4(Ah, f(79 - j, Bh, Ch, Dh), msg[rh[j] + start], Kh(j)), - sh[j]), - Eh); - Ah = Eh; - Eh = Dh; - Dh = rotl32(Ch, 10); - Ch = Bh; - Bh = T; - } - T = sum32_3(this.h[1], C, Dh); - this.h[1] = sum32_3(this.h[2], D, Eh); - this.h[2] = sum32_3(this.h[3], E, Ah); - this.h[3] = sum32_3(this.h[4], A, Bh); - this.h[4] = sum32_3(this.h[0], B, Ch); - this.h[0] = T; -}; - -RIPEMD160.prototype._digest = function digest(enc) { - if (enc === 'hex') - return utils.toHex32(this.h, 'little'); - else - return utils.split32(this.h, 'little'); -}; - -function f(j, x, y, z) { - if (j <= 15) - return x ^ y ^ z; - else if (j <= 31) - return (x & y) | ((~x) & z); - else if (j <= 47) - return (x | (~y)) ^ z; - else if (j <= 63) - return (x & z) | (y & (~z)); - else - return x ^ (y | (~z)); -} + // emits a 'removeListener' event iff the listener was removed + EventEmitter.prototype.removeListener = function(type, listener) { + var list, position, length, i; -function K(j) { - if (j <= 15) - return 0x00000000; - else if (j <= 31) - return 0x5a827999; - else if (j <= 47) - return 0x6ed9eba1; - else if (j <= 63) - return 0x8f1bbcdc; - else - return 0xa953fd4e; -} + if (!isFunction(listener)) throw TypeError('listener must be a function'); -function Kh(j) { - if (j <= 15) - return 0x50a28be6; - else if (j <= 31) - return 0x5c4dd124; - else if (j <= 47) - return 0x6d703ef3; - else if (j <= 63) - return 0x7a6d76e9; - else - return 0x00000000; -} + if (!this._events || !this._events[type]) return this; -var r = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, - 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, - 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, - 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 -]; - -var rh = [ - 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, - 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, - 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, - 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, - 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 -]; - -var s = [ - 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, - 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, - 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, - 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, - 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 -]; - -var sh = [ - 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, - 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, - 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, - 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, - 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 -]; - -},{"./common":169,"./utils":179}],172:[function(require,module,exports){ -'use strict'; - -exports.sha1 = require('./sha/1'); -exports.sha224 = require('./sha/224'); -exports.sha256 = require('./sha/256'); -exports.sha384 = require('./sha/384'); -exports.sha512 = require('./sha/512'); - -},{"./sha/1":173,"./sha/224":174,"./sha/256":175,"./sha/384":176,"./sha/512":177}],173:[function(require,module,exports){ -'use strict'; - -var utils = require('../utils'); -var common = require('../common'); -var shaCommon = require('./common'); - -var rotl32 = utils.rotl32; -var sum32 = utils.sum32; -var sum32_5 = utils.sum32_5; -var ft_1 = shaCommon.ft_1; -var BlockHash = common.BlockHash; - -var sha1_K = [ - 0x5A827999, 0x6ED9EBA1, - 0x8F1BBCDC, 0xCA62C1D6 -]; - -function SHA1() { - if (!(this instanceof SHA1)) - return new SHA1(); - - BlockHash.call(this); - this.h = [ - 0x67452301, 0xefcdab89, 0x98badcfe, - 0x10325476, 0xc3d2e1f0 ]; - this.W = new Array(80); -} + list = this._events[type]; + length = list.length; + position = -1; -utils.inherits(SHA1, BlockHash); -module.exports = SHA1; - -SHA1.blockSize = 512; -SHA1.outSize = 160; -SHA1.hmacStrength = 80; -SHA1.padLength = 64; - -SHA1.prototype._update = function _update(msg, start) { - var W = this.W; - - for (var i = 0; i < 16; i++) - W[i] = msg[start + i]; - - for(; i < W.length; i++) - W[i] = rotl32(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1); - - var a = this.h[0]; - var b = this.h[1]; - var c = this.h[2]; - var d = this.h[3]; - var e = this.h[4]; - - for (i = 0; i < W.length; i++) { - var s = ~~(i / 20); - var t = sum32_5(rotl32(a, 5), ft_1(s, b, c, d), e, W[i], sha1_K[s]); - e = d; - d = c; - c = rotl32(b, 30); - b = a; - a = t; - } + if (list === listener || (isFunction(list.listener) && list.listener === listener)) { + delete this._events[type]; + if (this._events.removeListener) this.emit('removeListener', type, listener); + } else if (isObject(list)) { + for (i = length; i-- > 0; ) { + if (list[i] === listener || (list[i].listener && list[i].listener === listener)) { + position = i; + break; + } + } - this.h[0] = sum32(this.h[0], a); - this.h[1] = sum32(this.h[1], b); - this.h[2] = sum32(this.h[2], c); - this.h[3] = sum32(this.h[3], d); - this.h[4] = sum32(this.h[4], e); -}; - -SHA1.prototype._digest = function digest(enc) { - if (enc === 'hex') - return utils.toHex32(this.h, 'big'); - else - return utils.split32(this.h, 'big'); -}; - -},{"../common":169,"../utils":179,"./common":178}],174:[function(require,module,exports){ -'use strict'; - -var utils = require('../utils'); -var SHA256 = require('./256'); - -function SHA224() { - if (!(this instanceof SHA224)) - return new SHA224(); - - SHA256.call(this); - this.h = [ - 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, - 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 ]; -} -utils.inherits(SHA224, SHA256); -module.exports = SHA224; - -SHA224.blockSize = 512; -SHA224.outSize = 224; -SHA224.hmacStrength = 192; -SHA224.padLength = 64; - -SHA224.prototype._digest = function digest(enc) { - // Just truncate output - if (enc === 'hex') - return utils.toHex32(this.h.slice(0, 7), 'big'); - else - return utils.split32(this.h.slice(0, 7), 'big'); -}; - - -},{"../utils":179,"./256":175}],175:[function(require,module,exports){ -'use strict'; - -var utils = require('../utils'); -var common = require('../common'); -var shaCommon = require('./common'); -var assert = require('minimalistic-assert'); - -var sum32 = utils.sum32; -var sum32_4 = utils.sum32_4; -var sum32_5 = utils.sum32_5; -var ch32 = shaCommon.ch32; -var maj32 = shaCommon.maj32; -var s0_256 = shaCommon.s0_256; -var s1_256 = shaCommon.s1_256; -var g0_256 = shaCommon.g0_256; -var g1_256 = shaCommon.g1_256; - -var BlockHash = common.BlockHash; - -var sha256_K = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -]; - -function SHA256() { - if (!(this instanceof SHA256)) - return new SHA256(); - - BlockHash.call(this); - this.h = [ - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, - 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 - ]; - this.k = sha256_K; - this.W = new Array(64); -} -utils.inherits(SHA256, BlockHash); -module.exports = SHA256; - -SHA256.blockSize = 512; -SHA256.outSize = 256; -SHA256.hmacStrength = 192; -SHA256.padLength = 64; - -SHA256.prototype._update = function _update(msg, start) { - var W = this.W; - - for (var i = 0; i < 16; i++) - W[i] = msg[start + i]; - for (; i < W.length; i++) - W[i] = sum32_4(g1_256(W[i - 2]), W[i - 7], g0_256(W[i - 15]), W[i - 16]); - - var a = this.h[0]; - var b = this.h[1]; - var c = this.h[2]; - var d = this.h[3]; - var e = this.h[4]; - var f = this.h[5]; - var g = this.h[6]; - var h = this.h[7]; - - assert(this.k.length === W.length); - for (i = 0; i < W.length; i++) { - var T1 = sum32_5(h, s1_256(e), ch32(e, f, g), this.k[i], W[i]); - var T2 = sum32(s0_256(a), maj32(a, b, c)); - h = g; - g = f; - f = e; - e = sum32(d, T1); - d = c; - c = b; - b = a; - a = sum32(T1, T2); - } + if (position < 0) return this; - this.h[0] = sum32(this.h[0], a); - this.h[1] = sum32(this.h[1], b); - this.h[2] = sum32(this.h[2], c); - this.h[3] = sum32(this.h[3], d); - this.h[4] = sum32(this.h[4], e); - this.h[5] = sum32(this.h[5], f); - this.h[6] = sum32(this.h[6], g); - this.h[7] = sum32(this.h[7], h); -}; - -SHA256.prototype._digest = function digest(enc) { - if (enc === 'hex') - return utils.toHex32(this.h, 'big'); - else - return utils.split32(this.h, 'big'); -}; - -},{"../common":169,"../utils":179,"./common":178,"minimalistic-assert":192}],176:[function(require,module,exports){ -'use strict'; - -var utils = require('../utils'); - -var SHA512 = require('./512'); - -function SHA384() { - if (!(this instanceof SHA384)) - return new SHA384(); - - SHA512.call(this); - this.h = [ - 0xcbbb9d5d, 0xc1059ed8, - 0x629a292a, 0x367cd507, - 0x9159015a, 0x3070dd17, - 0x152fecd8, 0xf70e5939, - 0x67332667, 0xffc00b31, - 0x8eb44a87, 0x68581511, - 0xdb0c2e0d, 0x64f98fa7, - 0x47b5481d, 0xbefa4fa4 ]; -} -utils.inherits(SHA384, SHA512); -module.exports = SHA384; - -SHA384.blockSize = 1024; -SHA384.outSize = 384; -SHA384.hmacStrength = 192; -SHA384.padLength = 128; - -SHA384.prototype._digest = function digest(enc) { - if (enc === 'hex') - return utils.toHex32(this.h.slice(0, 12), 'big'); - else - return utils.split32(this.h.slice(0, 12), 'big'); -}; - -},{"../utils":179,"./512":177}],177:[function(require,module,exports){ -'use strict'; - -var utils = require('../utils'); -var common = require('../common'); -var assert = require('minimalistic-assert'); - -var rotr64_hi = utils.rotr64_hi; -var rotr64_lo = utils.rotr64_lo; -var shr64_hi = utils.shr64_hi; -var shr64_lo = utils.shr64_lo; -var sum64 = utils.sum64; -var sum64_hi = utils.sum64_hi; -var sum64_lo = utils.sum64_lo; -var sum64_4_hi = utils.sum64_4_hi; -var sum64_4_lo = utils.sum64_4_lo; -var sum64_5_hi = utils.sum64_5_hi; -var sum64_5_lo = utils.sum64_5_lo; - -var BlockHash = common.BlockHash; - -var sha512_K = [ - 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, - 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc, - 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, - 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118, - 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, - 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2, - 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, - 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694, - 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, - 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65, - 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, - 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5, - 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, - 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4, - 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, - 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70, - 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, - 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df, - 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, - 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b, - 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, - 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30, - 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, - 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8, - 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, - 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8, - 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, - 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3, - 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, - 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec, - 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, - 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b, - 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, - 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178, - 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, - 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b, - 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, - 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c, - 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, - 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817 -]; - -function SHA512() { - if (!(this instanceof SHA512)) - return new SHA512(); - - BlockHash.call(this); - this.h = [ - 0x6a09e667, 0xf3bcc908, - 0xbb67ae85, 0x84caa73b, - 0x3c6ef372, 0xfe94f82b, - 0xa54ff53a, 0x5f1d36f1, - 0x510e527f, 0xade682d1, - 0x9b05688c, 0x2b3e6c1f, - 0x1f83d9ab, 0xfb41bd6b, - 0x5be0cd19, 0x137e2179 ]; - this.k = sha512_K; - this.W = new Array(160); -} -utils.inherits(SHA512, BlockHash); -module.exports = SHA512; - -SHA512.blockSize = 1024; -SHA512.outSize = 512; -SHA512.hmacStrength = 192; -SHA512.padLength = 128; - -SHA512.prototype._prepareBlock = function _prepareBlock(msg, start) { - var W = this.W; - - // 32 x 32bit words - for (var i = 0; i < 32; i++) - W[i] = msg[start + i]; - for (; i < W.length; i += 2) { - var c0_hi = g1_512_hi(W[i - 4], W[i - 3]); // i - 2 - var c0_lo = g1_512_lo(W[i - 4], W[i - 3]); - var c1_hi = W[i - 14]; // i - 7 - var c1_lo = W[i - 13]; - var c2_hi = g0_512_hi(W[i - 30], W[i - 29]); // i - 15 - var c2_lo = g0_512_lo(W[i - 30], W[i - 29]); - var c3_hi = W[i - 32]; // i - 16 - var c3_lo = W[i - 31]; - - W[i] = sum64_4_hi( - c0_hi, c0_lo, - c1_hi, c1_lo, - c2_hi, c2_lo, - c3_hi, c3_lo); - W[i + 1] = sum64_4_lo( - c0_hi, c0_lo, - c1_hi, c1_lo, - c2_hi, c2_lo, - c3_hi, c3_lo); - } -}; - -SHA512.prototype._update = function _update(msg, start) { - this._prepareBlock(msg, start); - - var W = this.W; - - var ah = this.h[0]; - var al = this.h[1]; - var bh = this.h[2]; - var bl = this.h[3]; - var ch = this.h[4]; - var cl = this.h[5]; - var dh = this.h[6]; - var dl = this.h[7]; - var eh = this.h[8]; - var el = this.h[9]; - var fh = this.h[10]; - var fl = this.h[11]; - var gh = this.h[12]; - var gl = this.h[13]; - var hh = this.h[14]; - var hl = this.h[15]; - - assert(this.k.length === W.length); - for (var i = 0; i < W.length; i += 2) { - var c0_hi = hh; - var c0_lo = hl; - var c1_hi = s1_512_hi(eh, el); - var c1_lo = s1_512_lo(eh, el); - var c2_hi = ch64_hi(eh, el, fh, fl, gh, gl); - var c2_lo = ch64_lo(eh, el, fh, fl, gh, gl); - var c3_hi = this.k[i]; - var c3_lo = this.k[i + 1]; - var c4_hi = W[i]; - var c4_lo = W[i + 1]; - - var T1_hi = sum64_5_hi( - c0_hi, c0_lo, - c1_hi, c1_lo, - c2_hi, c2_lo, - c3_hi, c3_lo, - c4_hi, c4_lo); - var T1_lo = sum64_5_lo( - c0_hi, c0_lo, - c1_hi, c1_lo, - c2_hi, c2_lo, - c3_hi, c3_lo, - c4_hi, c4_lo); - - c0_hi = s0_512_hi(ah, al); - c0_lo = s0_512_lo(ah, al); - c1_hi = maj64_hi(ah, al, bh, bl, ch, cl); - c1_lo = maj64_lo(ah, al, bh, bl, ch, cl); - - var T2_hi = sum64_hi(c0_hi, c0_lo, c1_hi, c1_lo); - var T2_lo = sum64_lo(c0_hi, c0_lo, c1_hi, c1_lo); - - hh = gh; - hl = gl; - - gh = fh; - gl = fl; - - fh = eh; - fl = el; - - eh = sum64_hi(dh, dl, T1_hi, T1_lo); - el = sum64_lo(dl, dl, T1_hi, T1_lo); - - dh = ch; - dl = cl; - - ch = bh; - cl = bl; - - bh = ah; - bl = al; - - ah = sum64_hi(T1_hi, T1_lo, T2_hi, T2_lo); - al = sum64_lo(T1_hi, T1_lo, T2_hi, T2_lo); - } + if (list.length === 1) { + list.length = 0; + delete this._events[type]; + } else { + list.splice(position, 1); + } - sum64(this.h, 0, ah, al); - sum64(this.h, 2, bh, bl); - sum64(this.h, 4, ch, cl); - sum64(this.h, 6, dh, dl); - sum64(this.h, 8, eh, el); - sum64(this.h, 10, fh, fl); - sum64(this.h, 12, gh, gl); - sum64(this.h, 14, hh, hl); -}; - -SHA512.prototype._digest = function digest(enc) { - if (enc === 'hex') - return utils.toHex32(this.h, 'big'); - else - return utils.split32(this.h, 'big'); -}; - -function ch64_hi(xh, xl, yh, yl, zh) { - var r = (xh & yh) ^ ((~xh) & zh); - if (r < 0) - r += 0x100000000; - return r; -} + if (this._events.removeListener) this.emit('removeListener', type, listener); + } -function ch64_lo(xh, xl, yh, yl, zh, zl) { - var r = (xl & yl) ^ ((~xl) & zl); - if (r < 0) - r += 0x100000000; - return r; -} + return this; + }; -function maj64_hi(xh, xl, yh, yl, zh) { - var r = (xh & yh) ^ (xh & zh) ^ (yh & zh); - if (r < 0) - r += 0x100000000; - return r; -} + EventEmitter.prototype.removeAllListeners = function(type) { + var key, listeners; -function maj64_lo(xh, xl, yh, yl, zh, zl) { - var r = (xl & yl) ^ (xl & zl) ^ (yl & zl); - if (r < 0) - r += 0x100000000; - return r; -} + if (!this._events) return this; -function s0_512_hi(xh, xl) { - var c0_hi = rotr64_hi(xh, xl, 28); - var c1_hi = rotr64_hi(xl, xh, 2); // 34 - var c2_hi = rotr64_hi(xl, xh, 7); // 39 + // not listening for removeListener, no need to emit + if (!this._events.removeListener) { + if (arguments.length === 0) this._events = {}; + else if (this._events[type]) delete this._events[type]; + return this; + } - var r = c0_hi ^ c1_hi ^ c2_hi; - if (r < 0) - r += 0x100000000; - return r; -} + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + for (key in this._events) { + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = {}; + return this; + } -function s0_512_lo(xh, xl) { - var c0_lo = rotr64_lo(xh, xl, 28); - var c1_lo = rotr64_lo(xl, xh, 2); // 34 - var c2_lo = rotr64_lo(xl, xh, 7); // 39 + listeners = this._events[type]; - var r = c0_lo ^ c1_lo ^ c2_lo; - if (r < 0) - r += 0x100000000; - return r; -} + if (isFunction(listeners)) { + this.removeListener(type, listeners); + } else if (listeners) { + // LIFO order + while (listeners.length) this.removeListener(type, listeners[listeners.length - 1]); + } + delete this._events[type]; -function s1_512_hi(xh, xl) { - var c0_hi = rotr64_hi(xh, xl, 14); - var c1_hi = rotr64_hi(xh, xl, 18); - var c2_hi = rotr64_hi(xl, xh, 9); // 41 + return this; + }; - var r = c0_hi ^ c1_hi ^ c2_hi; - if (r < 0) - r += 0x100000000; - return r; -} + EventEmitter.prototype.listeners = function(type) { + var ret; + if (!this._events || !this._events[type]) ret = []; + else if (isFunction(this._events[type])) ret = [this._events[type]]; + else ret = this._events[type].slice(); + return ret; + }; -function s1_512_lo(xh, xl) { - var c0_lo = rotr64_lo(xh, xl, 14); - var c1_lo = rotr64_lo(xh, xl, 18); - var c2_lo = rotr64_lo(xl, xh, 9); // 41 + EventEmitter.prototype.listenerCount = function(type) { + if (this._events) { + var evlistener = this._events[type]; - var r = c0_lo ^ c1_lo ^ c2_lo; - if (r < 0) - r += 0x100000000; - return r; -} + if (isFunction(evlistener)) return 1; + else if (evlistener) return evlistener.length; + } + return 0; + }; -function g0_512_hi(xh, xl) { - var c0_hi = rotr64_hi(xh, xl, 1); - var c1_hi = rotr64_hi(xh, xl, 8); - var c2_hi = shr64_hi(xh, xl, 7); + EventEmitter.listenerCount = function(emitter, type) { + return emitter.listenerCount(type); + }; - var r = c0_hi ^ c1_hi ^ c2_hi; - if (r < 0) - r += 0x100000000; - return r; -} + function isFunction(arg) { + return typeof arg === 'function'; + } -function g0_512_lo(xh, xl) { - var c0_lo = rotr64_lo(xh, xl, 1); - var c1_lo = rotr64_lo(xh, xl, 8); - var c2_lo = shr64_lo(xh, xl, 7); + function isNumber(arg) { + return typeof arg === 'number'; + } - var r = c0_lo ^ c1_lo ^ c2_lo; - if (r < 0) - r += 0x100000000; - return r; -} + function isObject(arg) { + return typeof arg === 'object' && arg !== null; + } -function g1_512_hi(xh, xl) { - var c0_hi = rotr64_hi(xh, xl, 19); - var c1_hi = rotr64_hi(xl, xh, 29); // 61 - var c2_hi = shr64_hi(xh, xl, 6); + function isUndefined(arg) { + return arg === void 0; + } + }, + {}, + ], + 166: [ + function(require, module, exports) { + var Buffer = require('safe-buffer').Buffer; + var MD5 = require('md5.js'); + + /* eslint-disable camelcase */ + function EVP_BytesToKey(password, salt, keyBits, ivLen) { + if (!Buffer.isBuffer(password)) password = Buffer.from(password, 'binary'); + if (salt) { + if (!Buffer.isBuffer(salt)) salt = Buffer.from(salt, 'binary'); + if (salt.length !== 8) throw new RangeError('salt should be Buffer with 8 byte length'); + } - var r = c0_hi ^ c1_hi ^ c2_hi; - if (r < 0) - r += 0x100000000; - return r; -} + var keyLen = keyBits / 8; + var key = Buffer.alloc(keyLen); + var iv = Buffer.alloc(ivLen || 0); + var tmp = Buffer.alloc(0); + + while (keyLen > 0 || ivLen > 0) { + var hash = new MD5(); + hash.update(tmp); + hash.update(password); + if (salt) hash.update(salt); + tmp = hash.digest(); + + var used = 0; + + if (keyLen > 0) { + var keyStart = key.length - keyLen; + used = Math.min(keyLen, tmp.length); + tmp.copy(key, keyStart, 0, used); + keyLen -= used; + } -function g1_512_lo(xh, xl) { - var c0_lo = rotr64_lo(xh, xl, 19); - var c1_lo = rotr64_lo(xl, xh, 29); // 61 - var c2_lo = shr64_lo(xh, xl, 6); + if (used < tmp.length && ivLen > 0) { + var ivStart = iv.length - ivLen; + var length = Math.min(ivLen, tmp.length - used); + tmp.copy(iv, ivStart, used, used + length); + ivLen -= length; + } + } - var r = c0_lo ^ c1_lo ^ c2_lo; - if (r < 0) - r += 0x100000000; - return r; -} + tmp.fill(0); + return { key: key, iv: iv }; + } -},{"../common":169,"../utils":179,"minimalistic-assert":192}],178:[function(require,module,exports){ -'use strict'; + module.exports = EVP_BytesToKey; + }, + { 'md5.js': 188, 'safe-buffer': 233 }, + ], + 167: [ + function(require, module, exports) { + (function(Buffer) { + 'use strict'; + var Transform = require('stream').Transform; + var inherits = require('inherits'); + + function HashBase(blockSize) { + Transform.call(this); + + this._block = new Buffer(blockSize); + this._blockSize = blockSize; + this._blockOffset = 0; + this._length = [0, 0, 0, 0]; + + this._finalized = false; + } -var utils = require('../utils'); -var rotr32 = utils.rotr32; + inherits(HashBase, Transform); -function ft_1(s, x, y, z) { - if (s === 0) - return ch32(x, y, z); - if (s === 1 || s === 3) - return p32(x, y, z); - if (s === 2) - return maj32(x, y, z); -} -exports.ft_1 = ft_1; + HashBase.prototype._transform = function(chunk, encoding, callback) { + var error = null; + try { + if (encoding !== 'buffer') chunk = new Buffer(chunk, encoding); + this.update(chunk); + } catch (err) { + error = err; + } -function ch32(x, y, z) { - return (x & y) ^ ((~x) & z); -} -exports.ch32 = ch32; + callback(error); + }; -function maj32(x, y, z) { - return (x & y) ^ (x & z) ^ (y & z); -} -exports.maj32 = maj32; + HashBase.prototype._flush = function(callback) { + var error = null; + try { + this.push(this._digest()); + } catch (err) { + error = err; + } -function p32(x, y, z) { - return x ^ y ^ z; -} -exports.p32 = p32; + callback(error); + }; + + HashBase.prototype.update = function(data, encoding) { + if (!Buffer.isBuffer(data) && typeof data !== 'string') + throw new TypeError('Data must be a string or a buffer'); + if (this._finalized) throw new Error('Digest already called'); + if (!Buffer.isBuffer(data)) data = new Buffer(data, encoding || 'binary'); + + // consume data + var block = this._block; + var offset = 0; + while (this._blockOffset + data.length - offset >= this._blockSize) { + for (var i = this._blockOffset; i < this._blockSize; ) block[i++] = data[offset++]; + this._update(); + this._blockOffset = 0; + } + while (offset < data.length) block[this._blockOffset++] = data[offset++]; -function s0_256(x) { - return rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22); -} -exports.s0_256 = s0_256; + // update length + for (var j = 0, carry = data.length * 8; carry > 0; ++j) { + this._length[j] += carry; + carry = (this._length[j] / 0x0100000000) | 0; + if (carry > 0) this._length[j] -= 0x0100000000 * carry; + } -function s1_256(x) { - return rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25); -} -exports.s1_256 = s1_256; + return this; + }; -function g0_256(x) { - return rotr32(x, 7) ^ rotr32(x, 18) ^ (x >>> 3); -} -exports.g0_256 = g0_256; + HashBase.prototype._update = function(data) { + throw new Error('_update is not implemented'); + }; -function g1_256(x) { - return rotr32(x, 17) ^ rotr32(x, 19) ^ (x >>> 10); -} -exports.g1_256 = g1_256; - -},{"../utils":179}],179:[function(require,module,exports){ -'use strict'; - -var assert = require('minimalistic-assert'); -var inherits = require('inherits'); - -exports.inherits = inherits; - -function toArray(msg, enc) { - if (Array.isArray(msg)) - return msg.slice(); - if (!msg) - return []; - var res = []; - if (typeof msg === 'string') { - if (!enc) { - for (var i = 0; i < msg.length; i++) { - var c = msg.charCodeAt(i); - var hi = c >> 8; - var lo = c & 0xff; - if (hi) - res.push(hi, lo); - else - res.push(lo); - } - } else if (enc === 'hex') { - msg = msg.replace(/[^a-z0-9]+/ig, ''); - if (msg.length % 2 !== 0) - msg = '0' + msg; - for (i = 0; i < msg.length; i += 2) - res.push(parseInt(msg[i] + msg[i + 1], 16)); - } - } else { - for (i = 0; i < msg.length; i++) - res[i] = msg[i] | 0; - } - return res; -} -exports.toArray = toArray; + HashBase.prototype.digest = function(encoding) { + if (this._finalized) throw new Error('Digest already called'); + this._finalized = true; -function toHex(msg) { - var res = ''; - for (var i = 0; i < msg.length; i++) - res += zero2(msg[i].toString(16)); - return res; -} -exports.toHex = toHex; - -function htonl(w) { - var res = (w >>> 24) | - ((w >>> 8) & 0xff00) | - ((w << 8) & 0xff0000) | - ((w & 0xff) << 24); - return res >>> 0; -} -exports.htonl = htonl; - -function toHex32(msg, endian) { - var res = ''; - for (var i = 0; i < msg.length; i++) { - var w = msg[i]; - if (endian === 'little') - w = htonl(w); - res += zero8(w.toString(16)); - } - return res; -} -exports.toHex32 = toHex32; + var digest = this._digest(); + if (encoding !== undefined) digest = digest.toString(encoding); + return digest; + }; -function zero2(word) { - if (word.length === 1) - return '0' + word; - else - return word; -} -exports.zero2 = zero2; - -function zero8(word) { - if (word.length === 7) - return '0' + word; - else if (word.length === 6) - return '00' + word; - else if (word.length === 5) - return '000' + word; - else if (word.length === 4) - return '0000' + word; - else if (word.length === 3) - return '00000' + word; - else if (word.length === 2) - return '000000' + word; - else if (word.length === 1) - return '0000000' + word; - else - return word; -} -exports.zero8 = zero8; - -function join32(msg, start, end, endian) { - var len = end - start; - assert(len % 4 === 0); - var res = new Array(len / 4); - for (var i = 0, k = start; i < res.length; i++, k += 4) { - var w; - if (endian === 'big') - w = (msg[k] << 24) | (msg[k + 1] << 16) | (msg[k + 2] << 8) | msg[k + 3]; - else - w = (msg[k + 3] << 24) | (msg[k + 2] << 16) | (msg[k + 1] << 8) | msg[k]; - res[i] = w >>> 0; - } - return res; -} -exports.join32 = join32; - -function split32(msg, endian) { - var res = new Array(msg.length * 4); - for (var i = 0, k = 0; i < msg.length; i++, k += 4) { - var m = msg[i]; - if (endian === 'big') { - res[k] = m >>> 24; - res[k + 1] = (m >>> 16) & 0xff; - res[k + 2] = (m >>> 8) & 0xff; - res[k + 3] = m & 0xff; - } else { - res[k + 3] = m >>> 24; - res[k + 2] = (m >>> 16) & 0xff; - res[k + 1] = (m >>> 8) & 0xff; - res[k] = m & 0xff; - } - } - return res; -} -exports.split32 = split32; + HashBase.prototype._digest = function() { + throw new Error('_digest is not implemented'); + }; -function rotr32(w, b) { - return (w >>> b) | (w << (32 - b)); -} -exports.rotr32 = rotr32; + module.exports = HashBase; + }.call(this, require('buffer').Buffer)); + }, + { buffer: 113, inherits: 184, stream: 242 }, + ], + 168: [ + function(require, module, exports) { + var hash = exports; + + hash.utils = require('./hash/utils'); + hash.common = require('./hash/common'); + hash.sha = require('./hash/sha'); + hash.ripemd = require('./hash/ripemd'); + hash.hmac = require('./hash/hmac'); + + // Proxy hash functions to the main object + hash.sha1 = hash.sha.sha1; + hash.sha256 = hash.sha.sha256; + hash.sha224 = hash.sha.sha224; + hash.sha384 = hash.sha.sha384; + hash.sha512 = hash.sha.sha512; + hash.ripemd160 = hash.ripemd.ripemd160; + }, + { './hash/common': 169, './hash/hmac': 170, './hash/ripemd': 171, './hash/sha': 172, './hash/utils': 179 }, + ], + 169: [ + function(require, module, exports) { + 'use strict'; + + var utils = require('./utils'); + var assert = require('minimalistic-assert'); + + function BlockHash() { + this.pending = null; + this.pendingTotal = 0; + this.blockSize = this.constructor.blockSize; + this.outSize = this.constructor.outSize; + this.hmacStrength = this.constructor.hmacStrength; + this.padLength = this.constructor.padLength / 8; + this.endian = 'big'; + + this._delta8 = this.blockSize / 8; + this._delta32 = this.blockSize / 32; + } + exports.BlockHash = BlockHash; + + BlockHash.prototype.update = function update(msg, enc) { + // Convert message to array, pad it, and join into 32bit blocks + msg = utils.toArray(msg, enc); + if (!this.pending) this.pending = msg; + else this.pending = this.pending.concat(msg); + this.pendingTotal += msg.length; + + // Enough data, try updating + if (this.pending.length >= this._delta8) { + msg = this.pending; + + // Process pending data in blocks + var r = msg.length % this._delta8; + this.pending = msg.slice(msg.length - r, msg.length); + if (this.pending.length === 0) this.pending = null; + + msg = utils.join32(msg, 0, msg.length - r, this.endian); + for (var i = 0; i < msg.length; i += this._delta32) this._update(msg, i, i + this._delta32); + } -function rotl32(w, b) { - return (w << b) | (w >>> (32 - b)); -} -exports.rotl32 = rotl32; + return this; + }; -function sum32(a, b) { - return (a + b) >>> 0; -} -exports.sum32 = sum32; + BlockHash.prototype.digest = function digest(enc) { + this.update(this._pad()); + assert(this.pending === null); -function sum32_3(a, b, c) { - return (a + b + c) >>> 0; -} -exports.sum32_3 = sum32_3; + return this._digest(enc); + }; -function sum32_4(a, b, c, d) { - return (a + b + c + d) >>> 0; -} -exports.sum32_4 = sum32_4; + BlockHash.prototype._pad = function pad() { + var len = this.pendingTotal; + var bytes = this._delta8; + var k = bytes - ((len + this.padLength) % bytes); + var res = new Array(k + this.padLength); + res[0] = 0x80; + for (var i = 1; i < k; i++) res[i] = 0; + + // Append length + len <<= 3; + if (this.endian === 'big') { + for (var t = 8; t < this.padLength; t++) res[i++] = 0; + + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + res[i++] = (len >>> 24) & 0xff; + res[i++] = (len >>> 16) & 0xff; + res[i++] = (len >>> 8) & 0xff; + res[i++] = len & 0xff; + } else { + res[i++] = len & 0xff; + res[i++] = (len >>> 8) & 0xff; + res[i++] = (len >>> 16) & 0xff; + res[i++] = (len >>> 24) & 0xff; + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + + for (t = 8; t < this.padLength; t++) res[i++] = 0; + } -function sum32_5(a, b, c, d, e) { - return (a + b + c + d + e) >>> 0; -} -exports.sum32_5 = sum32_5; + return res; + }; + }, + { './utils': 179, 'minimalistic-assert': 192 }, + ], + 170: [ + function(require, module, exports) { + 'use strict'; + + var utils = require('./utils'); + var assert = require('minimalistic-assert'); + + function Hmac(hash, key, enc) { + if (!(this instanceof Hmac)) return new Hmac(hash, key, enc); + this.Hash = hash; + this.blockSize = hash.blockSize / 8; + this.outSize = hash.outSize / 8; + this.inner = null; + this.outer = null; + + this._init(utils.toArray(key, enc)); + } + module.exports = Hmac; -function sum64(buf, pos, ah, al) { - var bh = buf[pos]; - var bl = buf[pos + 1]; + Hmac.prototype._init = function init(key) { + // Shorten key, if needed + if (key.length > this.blockSize) key = new this.Hash().update(key).digest(); + assert(key.length <= this.blockSize); - var lo = (al + bl) >>> 0; - var hi = (lo < al ? 1 : 0) + ah + bh; - buf[pos] = hi >>> 0; - buf[pos + 1] = lo; -} -exports.sum64 = sum64; + // Add padding to key + for (var i = key.length; i < this.blockSize; i++) key.push(0); -function sum64_hi(ah, al, bh, bl) { - var lo = (al + bl) >>> 0; - var hi = (lo < al ? 1 : 0) + ah + bh; - return hi >>> 0; -} -exports.sum64_hi = sum64_hi; + for (i = 0; i < key.length; i++) key[i] ^= 0x36; + this.inner = new this.Hash().update(key); -function sum64_lo(ah, al, bh, bl) { - var lo = al + bl; - return lo >>> 0; -} -exports.sum64_lo = sum64_lo; - -function sum64_4_hi(ah, al, bh, bl, ch, cl, dh, dl) { - var carry = 0; - var lo = al; - lo = (lo + bl) >>> 0; - carry += lo < al ? 1 : 0; - lo = (lo + cl) >>> 0; - carry += lo < cl ? 1 : 0; - lo = (lo + dl) >>> 0; - carry += lo < dl ? 1 : 0; - - var hi = ah + bh + ch + dh + carry; - return hi >>> 0; -} -exports.sum64_4_hi = sum64_4_hi; + // 0x36 ^ 0x5c = 0x6a + for (i = 0; i < key.length; i++) key[i] ^= 0x6a; + this.outer = new this.Hash().update(key); + }; -function sum64_4_lo(ah, al, bh, bl, ch, cl, dh, dl) { - var lo = al + bl + cl + dl; - return lo >>> 0; -} -exports.sum64_4_lo = sum64_4_lo; - -function sum64_5_hi(ah, al, bh, bl, ch, cl, dh, dl, eh, el) { - var carry = 0; - var lo = al; - lo = (lo + bl) >>> 0; - carry += lo < al ? 1 : 0; - lo = (lo + cl) >>> 0; - carry += lo < cl ? 1 : 0; - lo = (lo + dl) >>> 0; - carry += lo < dl ? 1 : 0; - lo = (lo + el) >>> 0; - carry += lo < el ? 1 : 0; - - var hi = ah + bh + ch + dh + eh + carry; - return hi >>> 0; -} -exports.sum64_5_hi = sum64_5_hi; + Hmac.prototype.update = function update(msg, enc) { + this.inner.update(msg, enc); + return this; + }; -function sum64_5_lo(ah, al, bh, bl, ch, cl, dh, dl, eh, el) { - var lo = al + bl + cl + dl + el; + Hmac.prototype.digest = function digest(enc) { + this.outer.update(this.inner.digest()); + return this.outer.digest(enc); + }; + }, + { './utils': 179, 'minimalistic-assert': 192 }, + ], + 171: [ + function(require, module, exports) { + 'use strict'; - return lo >>> 0; -} -exports.sum64_5_lo = sum64_5_lo; + var utils = require('./utils'); + var common = require('./common'); -function rotr64_hi(ah, al, num) { - var r = (al << (32 - num)) | (ah >>> num); - return r >>> 0; -} -exports.rotr64_hi = rotr64_hi; + var rotl32 = utils.rotl32; + var sum32 = utils.sum32; + var sum32_3 = utils.sum32_3; + var sum32_4 = utils.sum32_4; + var BlockHash = common.BlockHash; -function rotr64_lo(ah, al, num) { - var r = (ah << (32 - num)) | (al >>> num); - return r >>> 0; -} -exports.rotr64_lo = rotr64_lo; + function RIPEMD160() { + if (!(this instanceof RIPEMD160)) return new RIPEMD160(); -function shr64_hi(ah, al, num) { - return ah >>> num; -} -exports.shr64_hi = shr64_hi; + BlockHash.call(this); -function shr64_lo(ah, al, num) { - var r = (ah << (32 - num)) | (al >>> num); - return r >>> 0; -} -exports.shr64_lo = shr64_lo; - -},{"inherits":180,"minimalistic-assert":192}],180:[function(require,module,exports){ -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } -} + this.h = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; + this.endian = 'little'; + } + utils.inherits(RIPEMD160, BlockHash); + exports.ripemd160 = RIPEMD160; + + RIPEMD160.blockSize = 512; + RIPEMD160.outSize = 160; + RIPEMD160.hmacStrength = 192; + RIPEMD160.padLength = 64; + + RIPEMD160.prototype._update = function update(msg, start) { + var A = this.h[0]; + var B = this.h[1]; + var C = this.h[2]; + var D = this.h[3]; + var E = this.h[4]; + var Ah = A; + var Bh = B; + var Ch = C; + var Dh = D; + var Eh = E; + for (var j = 0; j < 80; j++) { + var T = sum32(rotl32(sum32_4(A, f(j, B, C, D), msg[r[j] + start], K(j)), s[j]), E); + A = E; + E = D; + D = rotl32(C, 10); + C = B; + B = T; + T = sum32(rotl32(sum32_4(Ah, f(79 - j, Bh, Ch, Dh), msg[rh[j] + start], Kh(j)), sh[j]), Eh); + Ah = Eh; + Eh = Dh; + Dh = rotl32(Ch, 10); + Ch = Bh; + Bh = T; + } + T = sum32_3(this.h[1], C, Dh); + this.h[1] = sum32_3(this.h[2], D, Eh); + this.h[2] = sum32_3(this.h[3], E, Ah); + this.h[3] = sum32_3(this.h[4], A, Bh); + this.h[4] = sum32_3(this.h[0], B, Ch); + this.h[0] = T; + }; -},{}],181:[function(require,module,exports){ -'use strict'; - -var hash = require('hash.js'); -var utils = require('minimalistic-crypto-utils'); -var assert = require('minimalistic-assert'); - -function HmacDRBG(options) { - if (!(this instanceof HmacDRBG)) - return new HmacDRBG(options); - this.hash = options.hash; - this.predResist = !!options.predResist; - - this.outLen = this.hash.outSize; - this.minEntropy = options.minEntropy || this.hash.hmacStrength; - - this._reseed = null; - this.reseedInterval = null; - this.K = null; - this.V = null; - - var entropy = utils.toArray(options.entropy, options.entropyEnc || 'hex'); - var nonce = utils.toArray(options.nonce, options.nonceEnc || 'hex'); - var pers = utils.toArray(options.pers, options.persEnc || 'hex'); - assert(entropy.length >= (this.minEntropy / 8), - 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); - this._init(entropy, nonce, pers); -} -module.exports = HmacDRBG; + RIPEMD160.prototype._digest = function digest(enc) { + if (enc === 'hex') return utils.toHex32(this.h, 'little'); + else return utils.split32(this.h, 'little'); + }; -HmacDRBG.prototype._init = function init(entropy, nonce, pers) { - var seed = entropy.concat(nonce).concat(pers); + function f(j, x, y, z) { + if (j <= 15) return x ^ y ^ z; + else if (j <= 31) return (x & y) | (~x & z); + else if (j <= 47) return (x | ~y) ^ z; + else if (j <= 63) return (x & z) | (y & ~z); + else return x ^ (y | ~z); + } - this.K = new Array(this.outLen / 8); - this.V = new Array(this.outLen / 8); - for (var i = 0; i < this.V.length; i++) { - this.K[i] = 0x00; - this.V[i] = 0x01; - } + function K(j) { + if (j <= 15) return 0x00000000; + else if (j <= 31) return 0x5a827999; + else if (j <= 47) return 0x6ed9eba1; + else if (j <= 63) return 0x8f1bbcdc; + else return 0xa953fd4e; + } - this._update(seed); - this._reseed = 1; - this.reseedInterval = 0x1000000000000; // 2^48 -}; - -HmacDRBG.prototype._hmac = function hmac() { - return new hash.hmac(this.hash, this.K); -}; - -HmacDRBG.prototype._update = function update(seed) { - var kmac = this._hmac() - .update(this.V) - .update([ 0x00 ]); - if (seed) - kmac = kmac.update(seed); - this.K = kmac.digest(); - this.V = this._hmac().update(this.V).digest(); - if (!seed) - return; - - this.K = this._hmac() - .update(this.V) - .update([ 0x01 ]) - .update(seed) - .digest(); - this.V = this._hmac().update(this.V).digest(); -}; - -HmacDRBG.prototype.reseed = function reseed(entropy, entropyEnc, add, addEnc) { - // Optional entropy enc - if (typeof entropyEnc !== 'string') { - addEnc = add; - add = entropyEnc; - entropyEnc = null; - } + function Kh(j) { + if (j <= 15) return 0x50a28be6; + else if (j <= 31) return 0x5c4dd124; + else if (j <= 47) return 0x6d703ef3; + else if (j <= 63) return 0x7a6d76e9; + else return 0x00000000; + } - entropy = utils.toArray(entropy, entropyEnc); - add = utils.toArray(add, addEnc); + var r = [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 7, + 4, + 13, + 1, + 10, + 6, + 15, + 3, + 12, + 0, + 9, + 5, + 2, + 14, + 11, + 8, + 3, + 10, + 14, + 4, + 9, + 15, + 8, + 1, + 2, + 7, + 0, + 6, + 13, + 11, + 5, + 12, + 1, + 9, + 11, + 10, + 0, + 8, + 12, + 4, + 13, + 3, + 7, + 15, + 14, + 5, + 6, + 2, + 4, + 0, + 5, + 9, + 7, + 12, + 2, + 10, + 14, + 1, + 3, + 8, + 11, + 6, + 15, + 13, + ]; + + var rh = [ + 5, + 14, + 7, + 0, + 9, + 2, + 11, + 4, + 13, + 6, + 15, + 8, + 1, + 10, + 3, + 12, + 6, + 11, + 3, + 7, + 0, + 13, + 5, + 10, + 14, + 15, + 8, + 12, + 4, + 9, + 1, + 2, + 15, + 5, + 1, + 3, + 7, + 14, + 6, + 9, + 11, + 8, + 12, + 2, + 10, + 0, + 4, + 13, + 8, + 6, + 4, + 1, + 3, + 11, + 15, + 0, + 5, + 12, + 2, + 13, + 9, + 7, + 10, + 14, + 12, + 15, + 10, + 4, + 1, + 5, + 8, + 7, + 6, + 2, + 13, + 14, + 0, + 3, + 9, + 11, + ]; + + var s = [ + 11, + 14, + 15, + 12, + 5, + 8, + 7, + 9, + 11, + 13, + 14, + 15, + 6, + 7, + 9, + 8, + 7, + 6, + 8, + 13, + 11, + 9, + 7, + 15, + 7, + 12, + 15, + 9, + 11, + 7, + 13, + 12, + 11, + 13, + 6, + 7, + 14, + 9, + 13, + 15, + 14, + 8, + 13, + 6, + 5, + 12, + 7, + 5, + 11, + 12, + 14, + 15, + 14, + 15, + 9, + 8, + 9, + 14, + 5, + 6, + 8, + 6, + 5, + 12, + 9, + 15, + 5, + 11, + 6, + 8, + 13, + 12, + 5, + 12, + 13, + 14, + 11, + 8, + 5, + 6, + ]; + + var sh = [ + 8, + 9, + 9, + 11, + 13, + 15, + 15, + 5, + 7, + 7, + 8, + 11, + 14, + 14, + 12, + 6, + 9, + 13, + 15, + 7, + 12, + 8, + 9, + 11, + 7, + 7, + 12, + 7, + 6, + 15, + 13, + 11, + 9, + 7, + 15, + 11, + 8, + 6, + 6, + 14, + 12, + 13, + 5, + 14, + 13, + 13, + 7, + 5, + 15, + 5, + 8, + 11, + 14, + 14, + 6, + 14, + 6, + 9, + 12, + 9, + 12, + 5, + 15, + 8, + 8, + 5, + 12, + 9, + 12, + 5, + 14, + 6, + 8, + 13, + 6, + 5, + 15, + 13, + 11, + 11, + ]; + }, + { './common': 169, './utils': 179 }, + ], + 172: [ + function(require, module, exports) { + 'use strict'; + + exports.sha1 = require('./sha/1'); + exports.sha224 = require('./sha/224'); + exports.sha256 = require('./sha/256'); + exports.sha384 = require('./sha/384'); + exports.sha512 = require('./sha/512'); + }, + { './sha/1': 173, './sha/224': 174, './sha/256': 175, './sha/384': 176, './sha/512': 177 }, + ], + 173: [ + function(require, module, exports) { + 'use strict'; + + var utils = require('../utils'); + var common = require('../common'); + var shaCommon = require('./common'); + + var rotl32 = utils.rotl32; + var sum32 = utils.sum32; + var sum32_5 = utils.sum32_5; + var ft_1 = shaCommon.ft_1; + var BlockHash = common.BlockHash; + + var sha1_K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; + + function SHA1() { + if (!(this instanceof SHA1)) return new SHA1(); + + BlockHash.call(this); + this.h = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; + this.W = new Array(80); + } - assert(entropy.length >= (this.minEntropy / 8), - 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); + utils.inherits(SHA1, BlockHash); + module.exports = SHA1; - this._update(entropy.concat(add || [])); - this._reseed = 1; -}; + SHA1.blockSize = 512; + SHA1.outSize = 160; + SHA1.hmacStrength = 80; + SHA1.padLength = 64; -HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) { - if (this._reseed > this.reseedInterval) - throw new Error('Reseed is required'); + SHA1.prototype._update = function _update(msg, start) { + var W = this.W; - // Optional encoding - if (typeof enc !== 'string') { - addEnc = add; - add = enc; - enc = null; - } + for (var i = 0; i < 16; i++) W[i] = msg[start + i]; - // Optional additional data - if (add) { - add = utils.toArray(add, addEnc || 'hex'); - this._update(add); - } + for (; i < W.length; i++) W[i] = rotl32(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1); - var temp = []; - while (temp.length < len) { - this.V = this._hmac().update(this.V).digest(); - temp = temp.concat(this.V); - } + var a = this.h[0]; + var b = this.h[1]; + var c = this.h[2]; + var d = this.h[3]; + var e = this.h[4]; - var res = temp.slice(0, len); - this._update(add); - this._reseed++; - return utils.encode(res, enc); -}; - -},{"hash.js":168,"minimalistic-assert":192,"minimalistic-crypto-utils":193}],182:[function(require,module,exports){ -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] - - i += d - - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) -} + for (i = 0; i < W.length; i++) { + var s = ~~(i / 20); + var t = sum32_5(rotl32(a, 5), ft_1(s, b, c, d), e, W[i], sha1_K[s]); + e = d; + d = c; + c = rotl32(b, 30); + b = a; + a = t; + } -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 - - value = Math.abs(value) - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } + this.h[0] = sum32(this.h[0], a); + this.h[1] = sum32(this.h[1], b); + this.h[2] = sum32(this.h[2], c); + this.h[3] = sum32(this.h[3], d); + this.h[4] = sum32(this.h[4], e); + }; - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } + SHA1.prototype._digest = function digest(enc) { + if (enc === 'hex') return utils.toHex32(this.h, 'big'); + else return utils.split32(this.h, 'big'); + }; + }, + { '../common': 169, '../utils': 179, './common': 178 }, + ], + 174: [ + function(require, module, exports) { + 'use strict'; - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + var utils = require('../utils'); + var SHA256 = require('./256'); - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + function SHA224() { + if (!(this instanceof SHA224)) return new SHA224(); - buffer[offset + i - d] |= s * 128 -} + SHA256.call(this); + this.h = [0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4]; + } + utils.inherits(SHA224, SHA256); + module.exports = SHA224; + + SHA224.blockSize = 512; + SHA224.outSize = 224; + SHA224.hmacStrength = 192; + SHA224.padLength = 64; + + SHA224.prototype._digest = function digest(enc) { + // Just truncate output + if (enc === 'hex') return utils.toHex32(this.h.slice(0, 7), 'big'); + else return utils.split32(this.h.slice(0, 7), 'big'); + }; + }, + { '../utils': 179, './256': 175 }, + ], + 175: [ + function(require, module, exports) { + 'use strict'; + + var utils = require('../utils'); + var common = require('../common'); + var shaCommon = require('./common'); + var assert = require('minimalistic-assert'); + + var sum32 = utils.sum32; + var sum32_4 = utils.sum32_4; + var sum32_5 = utils.sum32_5; + var ch32 = shaCommon.ch32; + var maj32 = shaCommon.maj32; + var s0_256 = shaCommon.s0_256; + var s1_256 = shaCommon.s1_256; + var g0_256 = shaCommon.g0_256; + var g1_256 = shaCommon.g1_256; + + var BlockHash = common.BlockHash; + + var sha256_K = [ + 0x428a2f98, + 0x71374491, + 0xb5c0fbcf, + 0xe9b5dba5, + 0x3956c25b, + 0x59f111f1, + 0x923f82a4, + 0xab1c5ed5, + 0xd807aa98, + 0x12835b01, + 0x243185be, + 0x550c7dc3, + 0x72be5d74, + 0x80deb1fe, + 0x9bdc06a7, + 0xc19bf174, + 0xe49b69c1, + 0xefbe4786, + 0x0fc19dc6, + 0x240ca1cc, + 0x2de92c6f, + 0x4a7484aa, + 0x5cb0a9dc, + 0x76f988da, + 0x983e5152, + 0xa831c66d, + 0xb00327c8, + 0xbf597fc7, + 0xc6e00bf3, + 0xd5a79147, + 0x06ca6351, + 0x14292967, + 0x27b70a85, + 0x2e1b2138, + 0x4d2c6dfc, + 0x53380d13, + 0x650a7354, + 0x766a0abb, + 0x81c2c92e, + 0x92722c85, + 0xa2bfe8a1, + 0xa81a664b, + 0xc24b8b70, + 0xc76c51a3, + 0xd192e819, + 0xd6990624, + 0xf40e3585, + 0x106aa070, + 0x19a4c116, + 0x1e376c08, + 0x2748774c, + 0x34b0bcb5, + 0x391c0cb3, + 0x4ed8aa4a, + 0x5b9cca4f, + 0x682e6ff3, + 0x748f82ee, + 0x78a5636f, + 0x84c87814, + 0x8cc70208, + 0x90befffa, + 0xa4506ceb, + 0xbef9a3f7, + 0xc67178f2, + ]; + + function SHA256() { + if (!(this instanceof SHA256)) return new SHA256(); + + BlockHash.call(this); + this.h = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]; + this.k = sha256_K; + this.W = new Array(64); + } + utils.inherits(SHA256, BlockHash); + module.exports = SHA256; + + SHA256.blockSize = 512; + SHA256.outSize = 256; + SHA256.hmacStrength = 192; + SHA256.padLength = 64; + + SHA256.prototype._update = function _update(msg, start) { + var W = this.W; + + for (var i = 0; i < 16; i++) W[i] = msg[start + i]; + for (; i < W.length; i++) W[i] = sum32_4(g1_256(W[i - 2]), W[i - 7], g0_256(W[i - 15]), W[i - 16]); + + var a = this.h[0]; + var b = this.h[1]; + var c = this.h[2]; + var d = this.h[3]; + var e = this.h[4]; + var f = this.h[5]; + var g = this.h[6]; + var h = this.h[7]; + + assert(this.k.length === W.length); + for (i = 0; i < W.length; i++) { + var T1 = sum32_5(h, s1_256(e), ch32(e, f, g), this.k[i], W[i]); + var T2 = sum32(s0_256(a), maj32(a, b, c)); + h = g; + g = f; + f = e; + e = sum32(d, T1); + d = c; + c = b; + b = a; + a = sum32(T1, T2); + } -},{}],183:[function(require,module,exports){ + this.h[0] = sum32(this.h[0], a); + this.h[1] = sum32(this.h[1], b); + this.h[2] = sum32(this.h[2], c); + this.h[3] = sum32(this.h[3], d); + this.h[4] = sum32(this.h[4], e); + this.h[5] = sum32(this.h[5], f); + this.h[6] = sum32(this.h[6], g); + this.h[7] = sum32(this.h[7], h); + }; -var indexOf = [].indexOf; + SHA256.prototype._digest = function digest(enc) { + if (enc === 'hex') return utils.toHex32(this.h, 'big'); + else return utils.split32(this.h, 'big'); + }; + }, + { '../common': 169, '../utils': 179, './common': 178, 'minimalistic-assert': 192 }, + ], + 176: [ + function(require, module, exports) { + 'use strict'; + + var utils = require('../utils'); + + var SHA512 = require('./512'); + + function SHA384() { + if (!(this instanceof SHA384)) return new SHA384(); + + SHA512.call(this); + this.h = [ + 0xcbbb9d5d, + 0xc1059ed8, + 0x629a292a, + 0x367cd507, + 0x9159015a, + 0x3070dd17, + 0x152fecd8, + 0xf70e5939, + 0x67332667, + 0xffc00b31, + 0x8eb44a87, + 0x68581511, + 0xdb0c2e0d, + 0x64f98fa7, + 0x47b5481d, + 0xbefa4fa4, + ]; + } + utils.inherits(SHA384, SHA512); + module.exports = SHA384; -module.exports = function(arr, obj){ - if (indexOf) return arr.indexOf(obj); - for (var i = 0; i < arr.length; ++i) { - if (arr[i] === obj) return i; - } - return -1; -}; -},{}],184:[function(require,module,exports){ -arguments[4][180][0].apply(exports,arguments) -},{"dup":180}],185:[function(require,module,exports){ -/*! - * Determine if an object is a Buffer - * - * @author Feross Aboukhadijeh - * @license MIT - */ + SHA384.blockSize = 1024; + SHA384.outSize = 384; + SHA384.hmacStrength = 192; + SHA384.padLength = 128; -// The _isBuffer check is for Safari 5-7 support, because it's missing -// Object.prototype.constructor. Remove this eventually -module.exports = function (obj) { - return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) -} + SHA384.prototype._digest = function digest(enc) { + if (enc === 'hex') return utils.toHex32(this.h.slice(0, 12), 'big'); + else return utils.split32(this.h.slice(0, 12), 'big'); + }; + }, + { '../utils': 179, './512': 177 }, + ], + 177: [ + function(require, module, exports) { + 'use strict'; + + var utils = require('../utils'); + var common = require('../common'); + var assert = require('minimalistic-assert'); + + var rotr64_hi = utils.rotr64_hi; + var rotr64_lo = utils.rotr64_lo; + var shr64_hi = utils.shr64_hi; + var shr64_lo = utils.shr64_lo; + var sum64 = utils.sum64; + var sum64_hi = utils.sum64_hi; + var sum64_lo = utils.sum64_lo; + var sum64_4_hi = utils.sum64_4_hi; + var sum64_4_lo = utils.sum64_4_lo; + var sum64_5_hi = utils.sum64_5_hi; + var sum64_5_lo = utils.sum64_5_lo; + + var BlockHash = common.BlockHash; + + var sha512_K = [ + 0x428a2f98, + 0xd728ae22, + 0x71374491, + 0x23ef65cd, + 0xb5c0fbcf, + 0xec4d3b2f, + 0xe9b5dba5, + 0x8189dbbc, + 0x3956c25b, + 0xf348b538, + 0x59f111f1, + 0xb605d019, + 0x923f82a4, + 0xaf194f9b, + 0xab1c5ed5, + 0xda6d8118, + 0xd807aa98, + 0xa3030242, + 0x12835b01, + 0x45706fbe, + 0x243185be, + 0x4ee4b28c, + 0x550c7dc3, + 0xd5ffb4e2, + 0x72be5d74, + 0xf27b896f, + 0x80deb1fe, + 0x3b1696b1, + 0x9bdc06a7, + 0x25c71235, + 0xc19bf174, + 0xcf692694, + 0xe49b69c1, + 0x9ef14ad2, + 0xefbe4786, + 0x384f25e3, + 0x0fc19dc6, + 0x8b8cd5b5, + 0x240ca1cc, + 0x77ac9c65, + 0x2de92c6f, + 0x592b0275, + 0x4a7484aa, + 0x6ea6e483, + 0x5cb0a9dc, + 0xbd41fbd4, + 0x76f988da, + 0x831153b5, + 0x983e5152, + 0xee66dfab, + 0xa831c66d, + 0x2db43210, + 0xb00327c8, + 0x98fb213f, + 0xbf597fc7, + 0xbeef0ee4, + 0xc6e00bf3, + 0x3da88fc2, + 0xd5a79147, + 0x930aa725, + 0x06ca6351, + 0xe003826f, + 0x14292967, + 0x0a0e6e70, + 0x27b70a85, + 0x46d22ffc, + 0x2e1b2138, + 0x5c26c926, + 0x4d2c6dfc, + 0x5ac42aed, + 0x53380d13, + 0x9d95b3df, + 0x650a7354, + 0x8baf63de, + 0x766a0abb, + 0x3c77b2a8, + 0x81c2c92e, + 0x47edaee6, + 0x92722c85, + 0x1482353b, + 0xa2bfe8a1, + 0x4cf10364, + 0xa81a664b, + 0xbc423001, + 0xc24b8b70, + 0xd0f89791, + 0xc76c51a3, + 0x0654be30, + 0xd192e819, + 0xd6ef5218, + 0xd6990624, + 0x5565a910, + 0xf40e3585, + 0x5771202a, + 0x106aa070, + 0x32bbd1b8, + 0x19a4c116, + 0xb8d2d0c8, + 0x1e376c08, + 0x5141ab53, + 0x2748774c, + 0xdf8eeb99, + 0x34b0bcb5, + 0xe19b48a8, + 0x391c0cb3, + 0xc5c95a63, + 0x4ed8aa4a, + 0xe3418acb, + 0x5b9cca4f, + 0x7763e373, + 0x682e6ff3, + 0xd6b2b8a3, + 0x748f82ee, + 0x5defb2fc, + 0x78a5636f, + 0x43172f60, + 0x84c87814, + 0xa1f0ab72, + 0x8cc70208, + 0x1a6439ec, + 0x90befffa, + 0x23631e28, + 0xa4506ceb, + 0xde82bde9, + 0xbef9a3f7, + 0xb2c67915, + 0xc67178f2, + 0xe372532b, + 0xca273ece, + 0xea26619c, + 0xd186b8c7, + 0x21c0c207, + 0xeada7dd6, + 0xcde0eb1e, + 0xf57d4f7f, + 0xee6ed178, + 0x06f067aa, + 0x72176fba, + 0x0a637dc5, + 0xa2c898a6, + 0x113f9804, + 0xbef90dae, + 0x1b710b35, + 0x131c471b, + 0x28db77f5, + 0x23047d84, + 0x32caab7b, + 0x40c72493, + 0x3c9ebe0a, + 0x15c9bebc, + 0x431d67c4, + 0x9c100d4c, + 0x4cc5d4be, + 0xcb3e42b6, + 0x597f299c, + 0xfc657e2a, + 0x5fcb6fab, + 0x3ad6faec, + 0x6c44198c, + 0x4a475817, + ]; + + function SHA512() { + if (!(this instanceof SHA512)) return new SHA512(); + + BlockHash.call(this); + this.h = [ + 0x6a09e667, + 0xf3bcc908, + 0xbb67ae85, + 0x84caa73b, + 0x3c6ef372, + 0xfe94f82b, + 0xa54ff53a, + 0x5f1d36f1, + 0x510e527f, + 0xade682d1, + 0x9b05688c, + 0x2b3e6c1f, + 0x1f83d9ab, + 0xfb41bd6b, + 0x5be0cd19, + 0x137e2179, + ]; + this.k = sha512_K; + this.W = new Array(160); + } + utils.inherits(SHA512, BlockHash); + module.exports = SHA512; + + SHA512.blockSize = 1024; + SHA512.outSize = 512; + SHA512.hmacStrength = 192; + SHA512.padLength = 128; + + SHA512.prototype._prepareBlock = function _prepareBlock(msg, start) { + var W = this.W; + + // 32 x 32bit words + for (var i = 0; i < 32; i++) W[i] = msg[start + i]; + for (; i < W.length; i += 2) { + var c0_hi = g1_512_hi(W[i - 4], W[i - 3]); // i - 2 + var c0_lo = g1_512_lo(W[i - 4], W[i - 3]); + var c1_hi = W[i - 14]; // i - 7 + var c1_lo = W[i - 13]; + var c2_hi = g0_512_hi(W[i - 30], W[i - 29]); // i - 15 + var c2_lo = g0_512_lo(W[i - 30], W[i - 29]); + var c3_hi = W[i - 32]; // i - 16 + var c3_lo = W[i - 31]; + + W[i] = sum64_4_hi(c0_hi, c0_lo, c1_hi, c1_lo, c2_hi, c2_lo, c3_hi, c3_lo); + W[i + 1] = sum64_4_lo(c0_hi, c0_lo, c1_hi, c1_lo, c2_hi, c2_lo, c3_hi, c3_lo); + } + }; -function isBuffer (obj) { - return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) -} + SHA512.prototype._update = function _update(msg, start) { + this._prepareBlock(msg, start); + + var W = this.W; + + var ah = this.h[0]; + var al = this.h[1]; + var bh = this.h[2]; + var bl = this.h[3]; + var ch = this.h[4]; + var cl = this.h[5]; + var dh = this.h[6]; + var dl = this.h[7]; + var eh = this.h[8]; + var el = this.h[9]; + var fh = this.h[10]; + var fl = this.h[11]; + var gh = this.h[12]; + var gl = this.h[13]; + var hh = this.h[14]; + var hl = this.h[15]; + + assert(this.k.length === W.length); + for (var i = 0; i < W.length; i += 2) { + var c0_hi = hh; + var c0_lo = hl; + var c1_hi = s1_512_hi(eh, el); + var c1_lo = s1_512_lo(eh, el); + var c2_hi = ch64_hi(eh, el, fh, fl, gh, gl); + var c2_lo = ch64_lo(eh, el, fh, fl, gh, gl); + var c3_hi = this.k[i]; + var c3_lo = this.k[i + 1]; + var c4_hi = W[i]; + var c4_lo = W[i + 1]; + + var T1_hi = sum64_5_hi(c0_hi, c0_lo, c1_hi, c1_lo, c2_hi, c2_lo, c3_hi, c3_lo, c4_hi, c4_lo); + var T1_lo = sum64_5_lo(c0_hi, c0_lo, c1_hi, c1_lo, c2_hi, c2_lo, c3_hi, c3_lo, c4_hi, c4_lo); + + c0_hi = s0_512_hi(ah, al); + c0_lo = s0_512_lo(ah, al); + c1_hi = maj64_hi(ah, al, bh, bl, ch, cl); + c1_lo = maj64_lo(ah, al, bh, bl, ch, cl); + + var T2_hi = sum64_hi(c0_hi, c0_lo, c1_hi, c1_lo); + var T2_lo = sum64_lo(c0_hi, c0_lo, c1_hi, c1_lo); + + hh = gh; + hl = gl; + + gh = fh; + gl = fl; + + fh = eh; + fl = el; + + eh = sum64_hi(dh, dl, T1_hi, T1_lo); + el = sum64_lo(dl, dl, T1_hi, T1_lo); + + dh = ch; + dl = cl; + + ch = bh; + cl = bl; + + bh = ah; + bl = al; + + ah = sum64_hi(T1_hi, T1_lo, T2_hi, T2_lo); + al = sum64_lo(T1_hi, T1_lo, T2_hi, T2_lo); + } -// For Node v0.10 support. Remove this eventually. -function isSlowBuffer (obj) { - return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) -} + sum64(this.h, 0, ah, al); + sum64(this.h, 2, bh, bl); + sum64(this.h, 4, ch, cl); + sum64(this.h, 6, dh, dl); + sum64(this.h, 8, eh, el); + sum64(this.h, 10, fh, fl); + sum64(this.h, 12, gh, gl); + sum64(this.h, 14, hh, hl); + }; -},{}],186:[function(require,module,exports){ -var toString = {}.toString; - -module.exports = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; -}; - -},{}],187:[function(require,module,exports){ -(function (global){ -/** - * @license - * lodash 3.10.1 (Custom Build) - * Build: `lodash modern -d -o ./index.js` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -;(function() { - - /** Used as a safe reference for `undefined` in pre-ES5 environments. */ - var undefined; - - /** Used as the semantic version number. */ - var VERSION = '3.10.1'; - - /** Used to compose bitmasks for wrapper metadata. */ - var BIND_FLAG = 1, - BIND_KEY_FLAG = 2, - CURRY_BOUND_FLAG = 4, - CURRY_FLAG = 8, - CURRY_RIGHT_FLAG = 16, - PARTIAL_FLAG = 32, - PARTIAL_RIGHT_FLAG = 64, - ARY_FLAG = 128, - REARG_FLAG = 256; - - /** Used as default options for `_.trunc`. */ - var DEFAULT_TRUNC_LENGTH = 30, - DEFAULT_TRUNC_OMISSION = '...'; - - /** Used to detect when a function becomes hot. */ - var HOT_COUNT = 150, - HOT_SPAN = 16; - - /** Used as the size to enable large array optimizations. */ - var LARGE_ARRAY_SIZE = 200; - - /** Used to indicate the type of lazy iteratees. */ - var LAZY_FILTER_FLAG = 1, - LAZY_MAP_FLAG = 2; - - /** Used as the `TypeError` message for "Functions" methods. */ - var FUNC_ERROR_TEXT = 'Expected a function'; - - /** Used as the internal argument placeholder. */ - var PLACEHOLDER = '__lodash_placeholder__'; - - /** `Object#toString` result references. */ - var argsTag = '[object Arguments]', - arrayTag = '[object Array]', - boolTag = '[object Boolean]', - dateTag = '[object Date]', - errorTag = '[object Error]', - funcTag = '[object Function]', - mapTag = '[object Map]', - numberTag = '[object Number]', - objectTag = '[object Object]', - regexpTag = '[object RegExp]', - setTag = '[object Set]', - stringTag = '[object String]', - weakMapTag = '[object WeakMap]'; - - var arrayBufferTag = '[object ArrayBuffer]', - float32Tag = '[object Float32Array]', - float64Tag = '[object Float64Array]', - int8Tag = '[object Int8Array]', - int16Tag = '[object Int16Array]', - int32Tag = '[object Int32Array]', - uint8Tag = '[object Uint8Array]', - uint8ClampedTag = '[object Uint8ClampedArray]', - uint16Tag = '[object Uint16Array]', - uint32Tag = '[object Uint32Array]'; - - /** Used to match empty string literals in compiled template source. */ - var reEmptyStringLeading = /\b__p \+= '';/g, - reEmptyStringMiddle = /\b(__p \+=) '' \+/g, - reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; - - /** Used to match HTML entities and HTML characters. */ - var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g, - reUnescapedHtml = /[&<>"'`]/g, - reHasEscapedHtml = RegExp(reEscapedHtml.source), - reHasUnescapedHtml = RegExp(reUnescapedHtml.source); - - /** Used to match template delimiters. */ - var reEscape = /<%-([\s\S]+?)%>/g, - reEvaluate = /<%([\s\S]+?)%>/g, - reInterpolate = /<%=([\s\S]+?)%>/g; - - /** Used to match property names within property paths. */ - var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/, - reIsPlainProp = /^\w*$/, - rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g; - - /** - * Used to match `RegExp` [syntax characters](http://ecma-international.org/ecma-262/6.0/#sec-patterns) - * and those outlined by [`EscapeRegExpPattern`](http://ecma-international.org/ecma-262/6.0/#sec-escaperegexppattern). - */ - var reRegExpChars = /^[:!,]|[\\^$.*+?()[\]{}|\/]|(^[0-9a-fA-Fnrtuvx])|([\n\r\u2028\u2029])/g, - reHasRegExpChars = RegExp(reRegExpChars.source); - - /** Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). */ - var reComboMark = /[\u0300-\u036f\ufe20-\ufe23]/g; - - /** Used to match backslashes in property paths. */ - var reEscapeChar = /\\(\\)?/g; - - /** Used to match [ES template delimiters](http://ecma-international.org/ecma-262/6.0/#sec-template-literal-lexical-components). */ - var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; - - /** Used to match `RegExp` flags from their coerced string values. */ - var reFlags = /\w*$/; - - /** Used to detect hexadecimal string values. */ - var reHasHexPrefix = /^0[xX]/; - - /** Used to detect host constructors (Safari > 5). */ - var reIsHostCtor = /^\[object .+?Constructor\]$/; - - /** Used to detect unsigned integer values. */ - var reIsUint = /^\d+$/; - - /** Used to match latin-1 supplementary letters (excluding mathematical operators). */ - var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g; - - /** Used to ensure capturing order of template delimiters. */ - var reNoMatch = /($^)/; - - /** Used to match unescaped characters in compiled string literals. */ - var reUnescapedString = /['\n\r\u2028\u2029\\]/g; - - /** Used to match words to create compound words. */ - var reWords = (function() { - var upper = '[A-Z\\xc0-\\xd6\\xd8-\\xde]', - lower = '[a-z\\xdf-\\xf6\\xf8-\\xff]+'; - - return RegExp(upper + '+(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g'); - }()); - - /** Used to assign default `context` object properties. */ - var contextProps = [ - 'Array', 'ArrayBuffer', 'Date', 'Error', 'Float32Array', 'Float64Array', - 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number', - 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'isFinite', - 'parseFloat', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array', - 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap' - ]; + SHA512.prototype._digest = function digest(enc) { + if (enc === 'hex') return utils.toHex32(this.h, 'big'); + else return utils.split32(this.h, 'big'); + }; - /** Used to make template sourceURLs easier to identify. */ - var templateCounter = -1; - - /** Used to identify `toStringTag` values of typed arrays. */ - var typedArrayTags = {}; - typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = - typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = - typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = - typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = - typedArrayTags[uint32Tag] = true; - typedArrayTags[argsTag] = typedArrayTags[arrayTag] = - typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = - typedArrayTags[dateTag] = typedArrayTags[errorTag] = - typedArrayTags[funcTag] = typedArrayTags[mapTag] = - typedArrayTags[numberTag] = typedArrayTags[objectTag] = - typedArrayTags[regexpTag] = typedArrayTags[setTag] = - typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; - - /** Used to identify `toStringTag` values supported by `_.clone`. */ - var cloneableTags = {}; - cloneableTags[argsTag] = cloneableTags[arrayTag] = - cloneableTags[arrayBufferTag] = cloneableTags[boolTag] = - cloneableTags[dateTag] = cloneableTags[float32Tag] = - cloneableTags[float64Tag] = cloneableTags[int8Tag] = - cloneableTags[int16Tag] = cloneableTags[int32Tag] = - cloneableTags[numberTag] = cloneableTags[objectTag] = - cloneableTags[regexpTag] = cloneableTags[stringTag] = - cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = - cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; - cloneableTags[errorTag] = cloneableTags[funcTag] = - cloneableTags[mapTag] = cloneableTags[setTag] = - cloneableTags[weakMapTag] = false; - - /** Used to map latin-1 supplementary letters to basic latin letters. */ - var deburredLetters = { - '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', - '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', - '\xc7': 'C', '\xe7': 'c', - '\xd0': 'D', '\xf0': 'd', - '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', - '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', - '\xcC': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', - '\xeC': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', - '\xd1': 'N', '\xf1': 'n', - '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', - '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', - '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', - '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', - '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', - '\xc6': 'Ae', '\xe6': 'ae', - '\xde': 'Th', '\xfe': 'th', - '\xdf': 'ss' - }; - - /** Used to map characters to HTML entities. */ - var htmlEscapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '`': '`' - }; - - /** Used to map HTML entities to characters. */ - var htmlUnescapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - ''': "'", - '`': '`' - }; - - /** Used to determine if values are of the language type `Object`. */ - var objectTypes = { - 'function': true, - 'object': true - }; - - /** Used to escape characters for inclusion in compiled regexes. */ - var regexpEscapes = { - '0': 'x30', '1': 'x31', '2': 'x32', '3': 'x33', '4': 'x34', - '5': 'x35', '6': 'x36', '7': 'x37', '8': 'x38', '9': 'x39', - 'A': 'x41', 'B': 'x42', 'C': 'x43', 'D': 'x44', 'E': 'x45', 'F': 'x46', - 'a': 'x61', 'b': 'x62', 'c': 'x63', 'd': 'x64', 'e': 'x65', 'f': 'x66', - 'n': 'x6e', 'r': 'x72', 't': 'x74', 'u': 'x75', 'v': 'x76', 'x': 'x78' - }; - - /** Used to escape characters for inclusion in compiled string literals. */ - var stringEscapes = { - '\\': '\\', - "'": "'", - '\n': 'n', - '\r': 'r', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; - - /** Detect free variable `exports`. */ - var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; - - /** Detect free variable `module`. */ - var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; - - /** Detect free variable `global` from Node.js. */ - var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global; - - /** Detect free variable `self`. */ - var freeSelf = objectTypes[typeof self] && self && self.Object && self; - - /** Detect free variable `window`. */ - var freeWindow = objectTypes[typeof window] && window && window.Object && window; - - /** Detect the popular CommonJS extension `module.exports`. */ - var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; - - /** - * Used as a reference to the global object. - * - * The `this` value is used if it's the global object to avoid Greasemonkey's - * restricted `window` object, otherwise the `window` object is used. - */ - var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this; - - /*--------------------------------------------------------------------------*/ - - /** - * The base implementation of `compareAscending` which compares values and - * sorts them in ascending order without guaranteeing a stable sort. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {number} Returns the sort order indicator for `value`. - */ - function baseCompareAscending(value, other) { - if (value !== other) { - var valIsNull = value === null, - valIsUndef = value === undefined, - valIsReflexive = value === value; - - var othIsNull = other === null, - othIsUndef = other === undefined, - othIsReflexive = other === other; - - if ((value > other && !othIsNull) || !valIsReflexive || - (valIsNull && !othIsUndef && othIsReflexive) || - (valIsUndef && othIsReflexive)) { - return 1; - } - if ((value < other && !valIsNull) || !othIsReflexive || - (othIsNull && !valIsUndef && valIsReflexive) || - (othIsUndef && valIsReflexive)) { - return -1; - } - } - return 0; - } + function ch64_hi(xh, xl, yh, yl, zh) { + var r = (xh & yh) ^ (~xh & zh); + if (r < 0) r += 0x100000000; + return r; + } - /** - * The base implementation of `_.findIndex` and `_.findLastIndex` without - * support for callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to search. - * @param {Function} predicate The function invoked per iteration. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseFindIndex(array, predicate, fromRight) { - var length = array.length, - index = fromRight ? length : -1; - - while ((fromRight ? index-- : ++index < length)) { - if (predicate(array[index], index, array)) { - return index; - } - } - return -1; - } + function ch64_lo(xh, xl, yh, yl, zh, zl) { + var r = (xl & yl) ^ (~xl & zl); + if (r < 0) r += 0x100000000; + return r; + } - /** - * The base implementation of `_.indexOf` without support for binary searches. - * - * @private - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOf(array, value, fromIndex) { - if (value !== value) { - return indexOfNaN(array, fromIndex); - } - var index = fromIndex - 1, - length = array.length; + function maj64_hi(xh, xl, yh, yl, zh) { + var r = (xh & yh) ^ (xh & zh) ^ (yh & zh); + if (r < 0) r += 0x100000000; + return r; + } - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; - } + function maj64_lo(xh, xl, yh, yl, zh, zl) { + var r = (xl & yl) ^ (xl & zl) ^ (yl & zl); + if (r < 0) r += 0x100000000; + return r; + } - /** - * The base implementation of `_.isFunction` without support for environments - * with incorrect `typeof` results. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - */ - function baseIsFunction(value) { - // Avoid a Chakra JIT bug in compatibility modes of IE 11. - // See https://github.com/jashkenas/underscore/issues/1621 for more details. - return typeof value == 'function' || false; - } + function s0_512_hi(xh, xl) { + var c0_hi = rotr64_hi(xh, xl, 28); + var c1_hi = rotr64_hi(xl, xh, 2); // 34 + var c2_hi = rotr64_hi(xl, xh, 7); // 39 - /** - * Converts `value` to a string if it's not one. An empty string is returned - * for `null` or `undefined` values. - * - * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. - */ - function baseToString(value) { - return value == null ? '' : (value + ''); - } + var r = c0_hi ^ c1_hi ^ c2_hi; + if (r < 0) r += 0x100000000; + return r; + } - /** - * Used by `_.trim` and `_.trimLeft` to get the index of the first character - * of `string` that is not found in `chars`. - * - * @private - * @param {string} string The string to inspect. - * @param {string} chars The characters to find. - * @returns {number} Returns the index of the first character not found in `chars`. - */ - function charsLeftIndex(string, chars) { - var index = -1, - length = string.length; - - while (++index < length && chars.indexOf(string.charAt(index)) > -1) {} - return index; - } + function s0_512_lo(xh, xl) { + var c0_lo = rotr64_lo(xh, xl, 28); + var c1_lo = rotr64_lo(xl, xh, 2); // 34 + var c2_lo = rotr64_lo(xl, xh, 7); // 39 - /** - * Used by `_.trim` and `_.trimRight` to get the index of the last character - * of `string` that is not found in `chars`. - * - * @private - * @param {string} string The string to inspect. - * @param {string} chars The characters to find. - * @returns {number} Returns the index of the last character not found in `chars`. - */ - function charsRightIndex(string, chars) { - var index = string.length; - - while (index-- && chars.indexOf(string.charAt(index)) > -1) {} - return index; - } + var r = c0_lo ^ c1_lo ^ c2_lo; + if (r < 0) r += 0x100000000; + return r; + } - /** - * Used by `_.sortBy` to compare transformed elements of a collection and stable - * sort them in ascending order. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @returns {number} Returns the sort order indicator for `object`. - */ - function compareAscending(object, other) { - return baseCompareAscending(object.criteria, other.criteria) || (object.index - other.index); - } + function s1_512_hi(xh, xl) { + var c0_hi = rotr64_hi(xh, xl, 14); + var c1_hi = rotr64_hi(xh, xl, 18); + var c2_hi = rotr64_hi(xl, xh, 9); // 41 - /** - * Used by `_.sortByOrder` to compare multiple properties of a value to another - * and stable sort them. - * - * If `orders` is unspecified, all valuess are sorted in ascending order. Otherwise, - * a value is sorted in ascending order if its corresponding order is "asc", and - * descending if "desc". - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {boolean[]} orders The order to sort by for each property. - * @returns {number} Returns the sort order indicator for `object`. - */ - function compareMultiple(object, other, orders) { - var index = -1, - objCriteria = object.criteria, - othCriteria = other.criteria, - length = objCriteria.length, - ordersLength = orders.length; - - while (++index < length) { - var result = baseCompareAscending(objCriteria[index], othCriteria[index]); - if (result) { - if (index >= ordersLength) { - return result; + var r = c0_hi ^ c1_hi ^ c2_hi; + if (r < 0) r += 0x100000000; + return r; } - var order = orders[index]; - return result * ((order === 'asc' || order === true) ? 1 : -1); - } - } - // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications - // that causes it, under certain circumstances, to provide the same value for - // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 - // for more details. - // - // This also ensures a stable sort in V8 and other engines. - // See https://code.google.com/p/v8/issues/detail?id=90 for more details. - return object.index - other.index; - } - /** - * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters. - * - * @private - * @param {string} letter The matched letter to deburr. - * @returns {string} Returns the deburred letter. - */ - function deburrLetter(letter) { - return deburredLetters[letter]; - } + function s1_512_lo(xh, xl) { + var c0_lo = rotr64_lo(xh, xl, 14); + var c1_lo = rotr64_lo(xh, xl, 18); + var c2_lo = rotr64_lo(xl, xh, 9); // 41 - /** - * Used by `_.escape` to convert characters to HTML entities. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - function escapeHtmlChar(chr) { - return htmlEscapes[chr]; - } + var r = c0_lo ^ c1_lo ^ c2_lo; + if (r < 0) r += 0x100000000; + return r; + } - /** - * Used by `_.escapeRegExp` to escape characters for inclusion in compiled regexes. - * - * @private - * @param {string} chr The matched character to escape. - * @param {string} leadingChar The capture group for a leading character. - * @param {string} whitespaceChar The capture group for a whitespace character. - * @returns {string} Returns the escaped character. - */ - function escapeRegExpChar(chr, leadingChar, whitespaceChar) { - if (leadingChar) { - chr = regexpEscapes[chr]; - } else if (whitespaceChar) { - chr = stringEscapes[chr]; - } - return '\\' + chr; - } + function g0_512_hi(xh, xl) { + var c0_hi = rotr64_hi(xh, xl, 1); + var c1_hi = rotr64_hi(xh, xl, 8); + var c2_hi = shr64_hi(xh, xl, 7); - /** - * Used by `_.template` to escape characters for inclusion in compiled string literals. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - function escapeStringChar(chr) { - return '\\' + stringEscapes[chr]; - } + var r = c0_hi ^ c1_hi ^ c2_hi; + if (r < 0) r += 0x100000000; + return r; + } - /** - * Gets the index at which the first occurrence of `NaN` is found in `array`. - * - * @private - * @param {Array} array The array to search. - * @param {number} fromIndex The index to search from. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {number} Returns the index of the matched `NaN`, else `-1`. - */ - function indexOfNaN(array, fromIndex, fromRight) { - var length = array.length, - index = fromIndex + (fromRight ? 0 : -1); - - while ((fromRight ? index-- : ++index < length)) { - var other = array[index]; - if (other !== other) { - return index; - } - } - return -1; - } + function g0_512_lo(xh, xl) { + var c0_lo = rotr64_lo(xh, xl, 1); + var c1_lo = rotr64_lo(xh, xl, 8); + var c2_lo = shr64_lo(xh, xl, 7); - /** - * Checks if `value` is object-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - */ - function isObjectLike(value) { - return !!value && typeof value == 'object'; - } + var r = c0_lo ^ c1_lo ^ c2_lo; + if (r < 0) r += 0x100000000; + return r; + } - /** - * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a - * character code is whitespace. - * - * @private - * @param {number} charCode The character code to inspect. - * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`. - */ - function isSpace(charCode) { - return ((charCode <= 160 && (charCode >= 9 && charCode <= 13) || charCode == 32 || charCode == 160) || charCode == 5760 || charCode == 6158 || - (charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279))); - } + function g1_512_hi(xh, xl) { + var c0_hi = rotr64_hi(xh, xl, 19); + var c1_hi = rotr64_hi(xl, xh, 29); // 61 + var c2_hi = shr64_hi(xh, xl, 6); - /** - * Replaces all `placeholder` elements in `array` with an internal placeholder - * and returns an array of their indexes. - * - * @private - * @param {Array} array The array to modify. - * @param {*} placeholder The placeholder to replace. - * @returns {Array} Returns the new array of placeholder indexes. - */ - function replaceHolders(array, placeholder) { - var index = -1, - length = array.length, - resIndex = -1, - result = []; - - while (++index < length) { - if (array[index] === placeholder) { - array[index] = PLACEHOLDER; - result[++resIndex] = index; - } - } - return result; - } + var r = c0_hi ^ c1_hi ^ c2_hi; + if (r < 0) r += 0x100000000; + return r; + } - /** - * An implementation of `_.uniq` optimized for sorted arrays without support - * for callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The function invoked per iteration. - * @returns {Array} Returns the new duplicate-value-free array. - */ - function sortedUniq(array, iteratee) { - var seen, - index = -1, - length = array.length, - resIndex = -1, - result = []; - - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value, index, array) : value; - - if (!index || seen !== computed) { - seen = computed; - result[++resIndex] = value; - } - } - return result; - } + function g1_512_lo(xh, xl) { + var c0_lo = rotr64_lo(xh, xl, 19); + var c1_lo = rotr64_lo(xl, xh, 29); // 61 + var c2_lo = shr64_lo(xh, xl, 6); - /** - * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace - * character of `string`. - * - * @private - * @param {string} string The string to inspect. - * @returns {number} Returns the index of the first non-whitespace character. - */ - function trimmedLeftIndex(string) { - var index = -1, - length = string.length; - - while (++index < length && isSpace(string.charCodeAt(index))) {} - return index; - } + var r = c0_lo ^ c1_lo ^ c2_lo; + if (r < 0) r += 0x100000000; + return r; + } + }, + { '../common': 169, '../utils': 179, 'minimalistic-assert': 192 }, + ], + 178: [ + function(require, module, exports) { + 'use strict'; + + var utils = require('../utils'); + var rotr32 = utils.rotr32; + + function ft_1(s, x, y, z) { + if (s === 0) return ch32(x, y, z); + if (s === 1 || s === 3) return p32(x, y, z); + if (s === 2) return maj32(x, y, z); + } + exports.ft_1 = ft_1; - /** - * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace - * character of `string`. - * - * @private - * @param {string} string The string to inspect. - * @returns {number} Returns the index of the last non-whitespace character. - */ - function trimmedRightIndex(string) { - var index = string.length; - - while (index-- && isSpace(string.charCodeAt(index))) {} - return index; - } + function ch32(x, y, z) { + return (x & y) ^ (~x & z); + } + exports.ch32 = ch32; - /** - * Used by `_.unescape` to convert HTML entities to characters. - * - * @private - * @param {string} chr The matched character to unescape. - * @returns {string} Returns the unescaped character. - */ - function unescapeHtmlChar(chr) { - return htmlUnescapes[chr]; - } + function maj32(x, y, z) { + return (x & y) ^ (x & z) ^ (y & z); + } + exports.maj32 = maj32; - /*--------------------------------------------------------------------------*/ - - /** - * Create a new pristine `lodash` function using the given `context` object. - * - * @static - * @memberOf _ - * @category Utility - * @param {Object} [context=root] The context object. - * @returns {Function} Returns a new `lodash` function. - * @example - * - * _.mixin({ 'foo': _.constant('foo') }); - * - * var lodash = _.runInContext(); - * lodash.mixin({ 'bar': lodash.constant('bar') }); - * - * _.isFunction(_.foo); - * // => true - * _.isFunction(_.bar); - * // => false - * - * lodash.isFunction(lodash.foo); - * // => false - * lodash.isFunction(lodash.bar); - * // => true - * - * // using `context` to mock `Date#getTime` use in `_.now` - * var mock = _.runInContext({ - * 'Date': function() { - * return { 'getTime': getTimeMock }; - * } - * }); - * - * // or creating a suped-up `defer` in Node.js - * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; - */ - function runInContext(context) { - // Avoid issues with some ES3 environments that attempt to use values, named - // after built-in constructors like `Object`, for the creation of literals. - // ES5 clears this up by stating that literals must use built-in constructors. - // See https://es5.github.io/#x11.1.5 for more details. - context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root; - - /** Native constructor references. */ - var Array = context.Array, - Date = context.Date, - Error = context.Error, - Function = context.Function, - Math = context.Math, - Number = context.Number, - Object = context.Object, - RegExp = context.RegExp, - String = context.String, - TypeError = context.TypeError; - - /** Used for native method references. */ - var arrayProto = Array.prototype, - objectProto = Object.prototype, - stringProto = String.prototype; - - /** Used to resolve the decompiled source of functions. */ - var fnToString = Function.prototype.toString; - - /** Used to check objects for own properties. */ - var hasOwnProperty = objectProto.hasOwnProperty; - - /** Used to generate unique IDs. */ - var idCounter = 0; - - /** - * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) - * of values. - */ - var objToString = objectProto.toString; - - /** Used to restore the original `_` reference in `_.noConflict`. */ - var oldDash = root._; - - /** Used to detect if a method is native. */ - var reIsNative = RegExp('^' + - fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' - ); - - /** Native method references. */ - var ArrayBuffer = context.ArrayBuffer, - clearTimeout = context.clearTimeout, - parseFloat = context.parseFloat, - pow = Math.pow, - propertyIsEnumerable = objectProto.propertyIsEnumerable, - Set = getNative(context, 'Set'), - setTimeout = context.setTimeout, - splice = arrayProto.splice, - Uint8Array = context.Uint8Array, - WeakMap = getNative(context, 'WeakMap'); - - /* Native method references for those with the same name as other `lodash` methods. */ - var nativeCeil = Math.ceil, - nativeCreate = getNative(Object, 'create'), - nativeFloor = Math.floor, - nativeIsArray = getNative(Array, 'isArray'), - nativeIsFinite = context.isFinite, - nativeKeys = getNative(Object, 'keys'), - nativeMax = Math.max, - nativeMin = Math.min, - nativeNow = getNative(Date, 'now'), - nativeParseInt = context.parseInt, - nativeRandom = Math.random; - - /** Used as references for `-Infinity` and `Infinity`. */ - var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY, - POSITIVE_INFINITY = Number.POSITIVE_INFINITY; - - /** Used as references for the maximum length and index of an array. */ - var MAX_ARRAY_LENGTH = 4294967295, - MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, - HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; - - /** - * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) - * of an array-like value. - */ - var MAX_SAFE_INTEGER = 9007199254740991; - - /** Used to store function metadata. */ - var metaMap = WeakMap && new WeakMap; - - /** Used to lookup unminified function names. */ - var realNames = {}; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` object which wraps `value` to enable implicit chaining. - * Methods that operate on and return arrays, collections, and functions can - * be chained together. Methods that retrieve a single value or may return a - * primitive value will automatically end the chain returning the unwrapped - * value. Explicit chaining may be enabled using `_.chain`. The execution of - * chained methods is lazy, that is, execution is deferred until `_#value` - * is implicitly or explicitly called. - * - * Lazy evaluation allows several methods to support shortcut fusion. Shortcut - * fusion is an optimization strategy which merge iteratee calls; this can help - * to avoid the creation of intermediate data structures and greatly reduce the - * number of iteratee executions. - * - * Chaining is supported in custom builds as long as the `_#value` method is - * directly or indirectly included in the build. - * - * In addition to lodash methods, wrappers have `Array` and `String` methods. - * - * The wrapper `Array` methods are: - * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, - * `splice`, and `unshift` - * - * The wrapper `String` methods are: - * `replace` and `split` - * - * The wrapper methods that support shortcut fusion are: - * `compact`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, - * `first`, `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, - * `slice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `toArray`, - * and `where` - * - * The chainable wrapper methods are: - * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`, - * `callback`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`, - * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defaultsDeep`, - * `defer`, `delay`, `difference`, `drop`, `dropRight`, `dropRightWhile`, - * `dropWhile`, `fill`, `filter`, `flatten`, `flattenDeep`, `flow`, `flowRight`, - * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, - * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, - * `invoke`, `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, - * `matchesProperty`, `memoize`, `merge`, `method`, `methodOf`, `mixin`, - * `modArgs`, `negate`, `omit`, `once`, `pairs`, `partial`, `partialRight`, - * `partition`, `pick`, `plant`, `pluck`, `property`, `propertyOf`, `pull`, - * `pullAt`, `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`, - * `reverse`, `set`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByAll`, - * `sortByOrder`, `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`, - * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, - * `transform`, `union`, `uniq`, `unshift`, `unzip`, `unzipWith`, `values`, - * `valuesIn`, `where`, `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith` - * - * The wrapper methods that are **not** chainable by default are: - * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clone`, `cloneDeep`, - * `deburr`, `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, - * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, - * `floor`, `get`, `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`, - * `inRange`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, - * `isEmpty`, `isEqual`, `isError`, `isFinite` `isFunction`, `isMatch`, - * `isNative`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, - * `isRegExp`, `isString`, `isUndefined`, `isTypedArray`, `join`, `kebabCase`, - * `last`, `lastIndexOf`, `lt`, `lte`, `max`, `min`, `noConflict`, `noop`, - * `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, `random`, `reduce`, - * `reduceRight`, `repeat`, `result`, `round`, `runInContext`, `shift`, `size`, - * `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`, `startCase`, - * `startsWith`, `sum`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`, - * `unescape`, `uniqueId`, `value`, and `words` - * - * The wrapper method `sample` will return a wrapped value when `n` is provided, - * otherwise an unwrapped value is returned. - * - * @name _ - * @constructor - * @category Chain - * @param {*} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var wrapped = _([1, 2, 3]); - * - * // returns an unwrapped value - * wrapped.reduce(function(total, n) { - * return total + n; - * }); - * // => 6 - * - * // returns a wrapped value - * var squares = wrapped.map(function(n) { - * return n * n; - * }); - * - * _.isArray(squares); - * // => false - * - * _.isArray(squares.value()); - * // => true - */ - function lodash(value) { - if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { - if (value instanceof LodashWrapper) { - return value; - } - if (hasOwnProperty.call(value, '__chain__') && hasOwnProperty.call(value, '__wrapped__')) { - return wrapperClone(value); + function p32(x, y, z) { + return x ^ y ^ z; } - } - return new LodashWrapper(value); - } + exports.p32 = p32; - /** - * The function whose prototype all chaining wrappers inherit from. - * - * @private - */ - function baseLodash() { - // No operation performed. - } + function s0_256(x) { + return rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22); + } + exports.s0_256 = s0_256; - /** - * The base constructor for creating `lodash` wrapper objects. - * - * @private - * @param {*} value The value to wrap. - * @param {boolean} [chainAll] Enable chaining for all wrapper methods. - * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value. - */ - function LodashWrapper(value, chainAll, actions) { - this.__wrapped__ = value; - this.__actions__ = actions || []; - this.__chain__ = !!chainAll; - } + function s1_256(x) { + return rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25); + } + exports.s1_256 = s1_256; - /** - * An object environment feature flags. - * - * @static - * @memberOf _ - * @type Object - */ - var support = lodash.support = {}; - - /** - * By default, the template delimiters used by lodash are like those in - * embedded Ruby (ERB). Change the following template settings to use - * alternative delimiters. - * - * @static - * @memberOf _ - * @type Object - */ - lodash.templateSettings = { - - /** - * Used to detect `data` property values to be HTML-escaped. - * - * @memberOf _.templateSettings - * @type RegExp - */ - 'escape': reEscape, - - /** - * Used to detect code to be evaluated. - * - * @memberOf _.templateSettings - * @type RegExp - */ - 'evaluate': reEvaluate, - - /** - * Used to detect `data` property values to inject. - * - * @memberOf _.templateSettings - * @type RegExp - */ - 'interpolate': reInterpolate, - - /** - * Used to reference the data object in the template text. - * - * @memberOf _.templateSettings - * @type string - */ - 'variable': '', - - /** - * Used to import variables into the compiled template. - * - * @memberOf _.templateSettings - * @type Object - */ - 'imports': { + function g0_256(x) { + return rotr32(x, 7) ^ rotr32(x, 18) ^ (x >>> 3); + } + exports.g0_256 = g0_256; - /** - * A reference to the `lodash` function. - * - * @memberOf _.templateSettings.imports - * @type Function - */ - '_': lodash - } - }; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. - * - * @private - * @param {*} value The value to wrap. - */ - function LazyWrapper(value) { - this.__wrapped__ = value; - this.__actions__ = []; - this.__dir__ = 1; - this.__filtered__ = false; - this.__iteratees__ = []; - this.__takeCount__ = POSITIVE_INFINITY; - this.__views__ = []; - } + function g1_256(x) { + return rotr32(x, 17) ^ rotr32(x, 19) ^ (x >>> 10); + } + exports.g1_256 = g1_256; + }, + { '../utils': 179 }, + ], + 179: [ + function(require, module, exports) { + 'use strict'; + + var assert = require('minimalistic-assert'); + var inherits = require('inherits'); + + exports.inherits = inherits; + + function toArray(msg, enc) { + if (Array.isArray(msg)) return msg.slice(); + if (!msg) return []; + var res = []; + if (typeof msg === 'string') { + if (!enc) { + for (var i = 0; i < msg.length; i++) { + var c = msg.charCodeAt(i); + var hi = c >> 8; + var lo = c & 0xff; + if (hi) res.push(hi, lo); + else res.push(lo); + } + } else if (enc === 'hex') { + msg = msg.replace(/[^a-z0-9]+/gi, ''); + if (msg.length % 2 !== 0) msg = '0' + msg; + for (i = 0; i < msg.length; i += 2) res.push(parseInt(msg[i] + msg[i + 1], 16)); + } + } else { + for (i = 0; i < msg.length; i++) res[i] = msg[i] | 0; + } + return res; + } + exports.toArray = toArray; - /** - * Creates a clone of the lazy wrapper object. - * - * @private - * @name clone - * @memberOf LazyWrapper - * @returns {Object} Returns the cloned `LazyWrapper` object. - */ - function lazyClone() { - var result = new LazyWrapper(this.__wrapped__); - result.__actions__ = arrayCopy(this.__actions__); - result.__dir__ = this.__dir__; - result.__filtered__ = this.__filtered__; - result.__iteratees__ = arrayCopy(this.__iteratees__); - result.__takeCount__ = this.__takeCount__; - result.__views__ = arrayCopy(this.__views__); - return result; - } + function toHex(msg) { + var res = ''; + for (var i = 0; i < msg.length; i++) res += zero2(msg[i].toString(16)); + return res; + } + exports.toHex = toHex; - /** - * Reverses the direction of lazy iteration. - * - * @private - * @name reverse - * @memberOf LazyWrapper - * @returns {Object} Returns the new reversed `LazyWrapper` object. - */ - function lazyReverse() { - if (this.__filtered__) { - var result = new LazyWrapper(this); - result.__dir__ = -1; - result.__filtered__ = true; - } else { - result = this.clone(); - result.__dir__ *= -1; - } - return result; - } + function htonl(w) { + var res = (w >>> 24) | ((w >>> 8) & 0xff00) | ((w << 8) & 0xff0000) | ((w & 0xff) << 24); + return res >>> 0; + } + exports.htonl = htonl; + + function toHex32(msg, endian) { + var res = ''; + for (var i = 0; i < msg.length; i++) { + var w = msg[i]; + if (endian === 'little') w = htonl(w); + res += zero8(w.toString(16)); + } + return res; + } + exports.toHex32 = toHex32; - /** - * Extracts the unwrapped value from its lazy wrapper. - * - * @private - * @name value - * @memberOf LazyWrapper - * @returns {*} Returns the unwrapped value. - */ - function lazyValue() { - var array = this.__wrapped__.value(), - dir = this.__dir__, - isArr = isArray(array), - isRight = dir < 0, - arrLength = isArr ? array.length : 0, - view = getView(0, arrLength, this.__views__), - start = view.start, - end = view.end, - length = end - start, - index = isRight ? end : (start - 1), - iteratees = this.__iteratees__, - iterLength = iteratees.length, - resIndex = 0, - takeCount = nativeMin(length, this.__takeCount__); - - if (!isArr || arrLength < LARGE_ARRAY_SIZE || (arrLength == length && takeCount == length)) { - return baseWrapperValue((isRight && isArr) ? array.reverse() : array, this.__actions__); - } - var result = []; - - outer: - while (length-- && resIndex < takeCount) { - index += dir; - - var iterIndex = -1, - value = array[index]; - - while (++iterIndex < iterLength) { - var data = iteratees[iterIndex], - iteratee = data.iteratee, - type = data.type, - computed = iteratee(value); - - if (type == LAZY_MAP_FLAG) { - value = computed; - } else if (!computed) { - if (type == LAZY_FILTER_FLAG) { - continue outer; + function zero2(word) { + if (word.length === 1) return '0' + word; + else return word; + } + exports.zero2 = zero2; + + function zero8(word) { + if (word.length === 7) return '0' + word; + else if (word.length === 6) return '00' + word; + else if (word.length === 5) return '000' + word; + else if (word.length === 4) return '0000' + word; + else if (word.length === 3) return '00000' + word; + else if (word.length === 2) return '000000' + word; + else if (word.length === 1) return '0000000' + word; + else return word; + } + exports.zero8 = zero8; + + function join32(msg, start, end, endian) { + var len = end - start; + assert(len % 4 === 0); + var res = new Array(len / 4); + for (var i = 0, k = start; i < res.length; i++, k += 4) { + var w; + if (endian === 'big') w = (msg[k] << 24) | (msg[k + 1] << 16) | (msg[k + 2] << 8) | msg[k + 3]; + else w = (msg[k + 3] << 24) | (msg[k + 2] << 16) | (msg[k + 1] << 8) | msg[k]; + res[i] = w >>> 0; + } + return res; + } + exports.join32 = join32; + + function split32(msg, endian) { + var res = new Array(msg.length * 4); + for (var i = 0, k = 0; i < msg.length; i++, k += 4) { + var m = msg[i]; + if (endian === 'big') { + res[k] = m >>> 24; + res[k + 1] = (m >>> 16) & 0xff; + res[k + 2] = (m >>> 8) & 0xff; + res[k + 3] = m & 0xff; } else { - break outer; + res[k + 3] = m >>> 24; + res[k + 2] = (m >>> 16) & 0xff; + res[k + 1] = (m >>> 8) & 0xff; + res[k] = m & 0xff; } } + return res; } - result[resIndex++] = value; - } - return result; - } + exports.split32 = split32; - /*------------------------------------------------------------------------*/ - - /** - * Creates a cache object to store key/value pairs. - * - * @private - * @static - * @name Cache - * @memberOf _.memoize - */ - function MapCache() { - this.__data__ = {}; - } + function rotr32(w, b) { + return (w >>> b) | (w << (32 - b)); + } + exports.rotr32 = rotr32; - /** - * Removes `key` and its value from the cache. - * - * @private - * @name delete - * @memberOf _.memoize.Cache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`. - */ - function mapDelete(key) { - return this.has(key) && delete this.__data__[key]; - } + function rotl32(w, b) { + return (w << b) | (w >>> (32 - b)); + } + exports.rotl32 = rotl32; - /** - * Gets the cached value for `key`. - * - * @private - * @name get - * @memberOf _.memoize.Cache - * @param {string} key The key of the value to get. - * @returns {*} Returns the cached value. - */ - function mapGet(key) { - return key == '__proto__' ? undefined : this.__data__[key]; - } + function sum32(a, b) { + return (a + b) >>> 0; + } + exports.sum32 = sum32; - /** - * Checks if a cached value for `key` exists. - * - * @private - * @name has - * @memberOf _.memoize.Cache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function mapHas(key) { - return key != '__proto__' && hasOwnProperty.call(this.__data__, key); - } + function sum32_3(a, b, c) { + return (a + b + c) >>> 0; + } + exports.sum32_3 = sum32_3; - /** - * Sets `value` to `key` of the cache. - * - * @private - * @name set - * @memberOf _.memoize.Cache - * @param {string} key The key of the value to cache. - * @param {*} value The value to cache. - * @returns {Object} Returns the cache object. - */ - function mapSet(key, value) { - if (key != '__proto__') { - this.__data__[key] = value; - } - return this; - } + function sum32_4(a, b, c, d) { + return (a + b + c + d) >>> 0; + } + exports.sum32_4 = sum32_4; - /*------------------------------------------------------------------------*/ - - /** - * - * Creates a cache object to store unique values. - * - * @private - * @param {Array} [values] The values to cache. - */ - function SetCache(values) { - var length = values ? values.length : 0; - - this.data = { 'hash': nativeCreate(null), 'set': new Set }; - while (length--) { - this.push(values[length]); - } - } + function sum32_5(a, b, c, d, e) { + return (a + b + c + d + e) >>> 0; + } + exports.sum32_5 = sum32_5; - /** - * Checks if `value` is in `cache` mimicking the return signature of - * `_.indexOf` by returning `0` if the value is found, else `-1`. - * - * @private - * @param {Object} cache The cache to search. - * @param {*} value The value to search for. - * @returns {number} Returns `0` if `value` is found, else `-1`. - */ - function cacheIndexOf(cache, value) { - var data = cache.data, - result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value]; - - return result ? 0 : -1; - } + function sum64(buf, pos, ah, al) { + var bh = buf[pos]; + var bl = buf[pos + 1]; - /** - * Adds `value` to the cache. - * - * @private - * @name push - * @memberOf SetCache - * @param {*} value The value to cache. - */ - function cachePush(value) { - var data = this.data; - if (typeof value == 'string' || isObject(value)) { - data.set.add(value); - } else { - data.hash[value] = true; - } - } + var lo = (al + bl) >>> 0; + var hi = (lo < al ? 1 : 0) + ah + bh; + buf[pos] = hi >>> 0; + buf[pos + 1] = lo; + } + exports.sum64 = sum64; - /*------------------------------------------------------------------------*/ - - /** - * Creates a new array joining `array` with `other`. - * - * @private - * @param {Array} array The array to join. - * @param {Array} other The other array to join. - * @returns {Array} Returns the new concatenated array. - */ - function arrayConcat(array, other) { - var index = -1, - length = array.length, - othIndex = -1, - othLength = other.length, - result = Array(length + othLength); - - while (++index < length) { - result[index] = array[index]; - } - while (++othIndex < othLength) { - result[index++] = other[othIndex]; - } - return result; - } + function sum64_hi(ah, al, bh, bl) { + var lo = (al + bl) >>> 0; + var hi = (lo < al ? 1 : 0) + ah + bh; + return hi >>> 0; + } + exports.sum64_hi = sum64_hi; - /** - * Copies the values of `source` to `array`. - * - * @private - * @param {Array} source The array to copy values from. - * @param {Array} [array=[]] The array to copy values to. - * @returns {Array} Returns `array`. - */ - function arrayCopy(source, array) { - var index = -1, - length = source.length; - - array || (array = Array(length)); - while (++index < length) { - array[index] = source[index]; - } - return array; - } + function sum64_lo(ah, al, bh, bl) { + var lo = al + bl; + return lo >>> 0; + } + exports.sum64_lo = sum64_lo; + + function sum64_4_hi(ah, al, bh, bl, ch, cl, dh, dl) { + var carry = 0; + var lo = al; + lo = (lo + bl) >>> 0; + carry += lo < al ? 1 : 0; + lo = (lo + cl) >>> 0; + carry += lo < cl ? 1 : 0; + lo = (lo + dl) >>> 0; + carry += lo < dl ? 1 : 0; + + var hi = ah + bh + ch + dh + carry; + return hi >>> 0; + } + exports.sum64_4_hi = sum64_4_hi; - /** - * A specialized version of `_.forEach` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ - function arrayEach(array, iteratee) { - var index = -1, - length = array.length; - - while (++index < length) { - if (iteratee(array[index], index, array) === false) { - break; + function sum64_4_lo(ah, al, bh, bl, ch, cl, dh, dl) { + var lo = al + bl + cl + dl; + return lo >>> 0; } - } - return array; - } + exports.sum64_4_lo = sum64_4_lo; + + function sum64_5_hi(ah, al, bh, bl, ch, cl, dh, dl, eh, el) { + var carry = 0; + var lo = al; + lo = (lo + bl) >>> 0; + carry += lo < al ? 1 : 0; + lo = (lo + cl) >>> 0; + carry += lo < cl ? 1 : 0; + lo = (lo + dl) >>> 0; + carry += lo < dl ? 1 : 0; + lo = (lo + el) >>> 0; + carry += lo < el ? 1 : 0; + + var hi = ah + bh + ch + dh + eh + carry; + return hi >>> 0; + } + exports.sum64_5_hi = sum64_5_hi; + + function sum64_5_lo(ah, al, bh, bl, ch, cl, dh, dl, eh, el) { + var lo = al + bl + cl + dl + el; - /** - * A specialized version of `_.forEachRight` for arrays without support for - * callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ - function arrayEachRight(array, iteratee) { - var length = array.length; - - while (length--) { - if (iteratee(array[length], length, array) === false) { - break; + return lo >>> 0; } - } - return array; - } + exports.sum64_5_lo = sum64_5_lo; - /** - * A specialized version of `_.every` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - */ - function arrayEvery(array, predicate) { - var index = -1, - length = array.length; - - while (++index < length) { - if (!predicate(array[index], index, array)) { - return false; + function rotr64_hi(ah, al, num) { + var r = (al << (32 - num)) | (ah >>> num); + return r >>> 0; } - } - return true; - } + exports.rotr64_hi = rotr64_hi; - /** - * A specialized version of `baseExtremum` for arrays which invokes `iteratee` - * with one argument: (value). - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} comparator The function used to compare values. - * @param {*} exValue The initial extremum value. - * @returns {*} Returns the extremum value. - */ - function arrayExtremum(array, iteratee, comparator, exValue) { - var index = -1, - length = array.length, - computed = exValue, - result = computed; - - while (++index < length) { - var value = array[index], - current = +iteratee(value); - - if (comparator(current, computed)) { - computed = current; - result = value; + function rotr64_lo(ah, al, num) { + var r = (ah << (32 - num)) | (al >>> num); + return r >>> 0; } - } - return result; - } + exports.rotr64_lo = rotr64_lo; + + function shr64_hi(ah, al, num) { + return ah >>> num; + } + exports.shr64_hi = shr64_hi; + + function shr64_lo(ah, al, num) { + var r = (ah << (32 - num)) | (al >>> num); + return r >>> 0; + } + exports.shr64_lo = shr64_lo; + }, + { inherits: 180, 'minimalistic-assert': 192 }, + ], + 180: [ + function(require, module, exports) { + if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor; + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true, + }, + }); + }; + } else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor; + var TempCtor = function() {}; + TempCtor.prototype = superCtor.prototype; + ctor.prototype = new TempCtor(); + ctor.prototype.constructor = ctor; + }; + } + }, + {}, + ], + 181: [ + function(require, module, exports) { + 'use strict'; + + var hash = require('hash.js'); + var utils = require('minimalistic-crypto-utils'); + var assert = require('minimalistic-assert'); + + function HmacDRBG(options) { + if (!(this instanceof HmacDRBG)) return new HmacDRBG(options); + this.hash = options.hash; + this.predResist = !!options.predResist; + + this.outLen = this.hash.outSize; + this.minEntropy = options.minEntropy || this.hash.hmacStrength; + + this._reseed = null; + this.reseedInterval = null; + this.K = null; + this.V = null; + + var entropy = utils.toArray(options.entropy, options.entropyEnc || 'hex'); + var nonce = utils.toArray(options.nonce, options.nonceEnc || 'hex'); + var pers = utils.toArray(options.pers, options.persEnc || 'hex'); + assert(entropy.length >= this.minEntropy / 8, 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); + this._init(entropy, nonce, pers); + } + module.exports = HmacDRBG; + + HmacDRBG.prototype._init = function init(entropy, nonce, pers) { + var seed = entropy.concat(nonce).concat(pers); + + this.K = new Array(this.outLen / 8); + this.V = new Array(this.outLen / 8); + for (var i = 0; i < this.V.length; i++) { + this.K[i] = 0x00; + this.V[i] = 0x01; + } + + this._update(seed); + this._reseed = 1; + this.reseedInterval = 0x1000000000000; // 2^48 + }; - /** - * A specialized version of `_.filter` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function arrayFilter(array, predicate) { - var index = -1, - length = array.length, - resIndex = -1, - result = []; - - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result[++resIndex] = value; - } - } - return result; - } + HmacDRBG.prototype._hmac = function hmac() { + return new hash.hmac(this.hash, this.K); + }; - /** - * A specialized version of `_.map` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function arrayMap(array, iteratee) { - var index = -1, - length = array.length, - result = Array(length); - - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; - } + HmacDRBG.prototype._update = function update(seed) { + var kmac = this._hmac() + .update(this.V) + .update([0x00]); + if (seed) kmac = kmac.update(seed); + this.K = kmac.digest(); + this.V = this._hmac() + .update(this.V) + .digest(); + if (!seed) return; + + this.K = this._hmac() + .update(this.V) + .update([0x01]) + .update(seed) + .digest(); + this.V = this._hmac() + .update(this.V) + .digest(); + }; - /** - * Appends the elements of `values` to `array`. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to append. - * @returns {Array} Returns `array`. - */ - function arrayPush(array, values) { - var index = -1, - length = values.length, - offset = array.length; - - while (++index < length) { - array[offset + index] = values[index]; - } - return array; - } + HmacDRBG.prototype.reseed = function reseed(entropy, entropyEnc, add, addEnc) { + // Optional entropy enc + if (typeof entropyEnc !== 'string') { + addEnc = add; + add = entropyEnc; + entropyEnc = null; + } - /** - * A specialized version of `_.reduce` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {boolean} [initFromArray] Specify using the first element of `array` - * as the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduce(array, iteratee, accumulator, initFromArray) { - var index = -1, - length = array.length; - - if (initFromArray && length) { - accumulator = array[++index]; - } - while (++index < length) { - accumulator = iteratee(accumulator, array[index], index, array); - } - return accumulator; - } + entropy = utils.toArray(entropy, entropyEnc); + add = utils.toArray(add, addEnc); - /** - * A specialized version of `_.reduceRight` for arrays without support for - * callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {boolean} [initFromArray] Specify using the last element of `array` - * as the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduceRight(array, iteratee, accumulator, initFromArray) { - var length = array.length; - if (initFromArray && length) { - accumulator = array[--length]; - } - while (length--) { - accumulator = iteratee(accumulator, array[length], length, array); - } - return accumulator; - } + assert(entropy.length >= this.minEntropy / 8, 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); - /** - * A specialized version of `_.some` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function arraySome(array, predicate) { - var index = -1, - length = array.length; - - while (++index < length) { - if (predicate(array[index], index, array)) { - return true; - } - } - return false; - } + this._update(entropy.concat(add || [])); + this._reseed = 1; + }; - /** - * A specialized version of `_.sum` for arrays without support for callback - * shorthands and `this` binding.. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the sum. - */ - function arraySum(array, iteratee) { - var length = array.length, - result = 0; - - while (length--) { - result += +iteratee(array[length]) || 0; - } - return result; - } + HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) { + if (this._reseed > this.reseedInterval) throw new Error('Reseed is required'); - /** - * Used by `_.defaults` to customize its `_.assign` use. - * - * @private - * @param {*} objectValue The destination object property value. - * @param {*} sourceValue The source object property value. - * @returns {*} Returns the value to assign to the destination object. - */ - function assignDefaults(objectValue, sourceValue) { - return objectValue === undefined ? sourceValue : objectValue; - } + // Optional encoding + if (typeof enc !== 'string') { + addEnc = add; + add = enc; + enc = null; + } - /** - * Used by `_.template` to customize its `_.assign` use. - * - * **Note:** This function is like `assignDefaults` except that it ignores - * inherited property values when checking if a property is `undefined`. - * - * @private - * @param {*} objectValue The destination object property value. - * @param {*} sourceValue The source object property value. - * @param {string} key The key associated with the object and source values. - * @param {Object} object The destination object. - * @returns {*} Returns the value to assign to the destination object. - */ - function assignOwnDefaults(objectValue, sourceValue, key, object) { - return (objectValue === undefined || !hasOwnProperty.call(object, key)) - ? sourceValue - : objectValue; - } + // Optional additional data + if (add) { + add = utils.toArray(add, addEnc || 'hex'); + this._update(add); + } - /** - * A specialized version of `_.assign` for customizing assigned values without - * support for argument juggling, multiple sources, and `this` binding `customizer` - * functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {Function} customizer The function to customize assigned values. - * @returns {Object} Returns `object`. - */ - function assignWith(object, source, customizer) { - var index = -1, - props = keys(source), - length = props.length; - - while (++index < length) { - var key = props[index], - value = object[key], - result = customizer(value, source[key], key, object, source); - - if ((result === result ? (result !== value) : (value === value)) || - (value === undefined && !(key in object))) { - object[key] = result; - } - } - return object; - } + var temp = []; + while (temp.length < len) { + this.V = this._hmac() + .update(this.V) + .digest(); + temp = temp.concat(this.V); + } - /** - * The base implementation of `_.assign` without support for argument juggling, - * multiple sources, and `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ - function baseAssign(object, source) { - return source == null - ? object - : baseCopy(source, keys(source), object); - } + var res = temp.slice(0, len); + this._update(add); + this._reseed++; + return utils.encode(res, enc); + }; + }, + { 'hash.js': 168, 'minimalistic-assert': 192, 'minimalistic-crypto-utils': 193 }, + ], + 182: [ + function(require, module, exports) { + exports.read = function(buffer, offset, isLE, mLen, nBytes) { + var e, m; + var eLen = nBytes * 8 - mLen - 1; + var eMax = (1 << eLen) - 1; + var eBias = eMax >> 1; + var nBits = -7; + var i = isLE ? nBytes - 1 : 0; + var d = isLE ? -1 : 1; + var s = buffer[offset + i]; + + i += d; + + e = s & ((1 << -nBits) - 1); + s >>= -nBits; + nBits += eLen; + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << -nBits) - 1); + e >>= -nBits; + nBits += mLen; + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias; + } else if (e === eMax) { + return m ? NaN : (s ? -1 : 1) * Infinity; + } else { + m = m + Math.pow(2, mLen); + e = e - eBias; + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen); + }; - /** - * The base implementation of `_.at` without support for string collections - * and individual key arguments. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {number[]|string[]} props The property names or indexes of elements to pick. - * @returns {Array} Returns the new array of picked elements. - */ - function baseAt(collection, props) { - var index = -1, - isNil = collection == null, - isArr = !isNil && isArrayLike(collection), - length = isArr ? collection.length : 0, - propsLength = props.length, - result = Array(propsLength); - - while(++index < propsLength) { - var key = props[index]; - if (isArr) { - result[index] = isIndex(key, length) ? collection[key] : undefined; - } else { - result[index] = isNil ? undefined : collection[key]; - } - } - return result; - } + exports.write = function(buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c; + var eLen = nBytes * 8 - mLen - 1; + var eMax = (1 << eLen) - 1; + var eBias = eMax >> 1; + var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0; + var i = isLE ? 0 : nBytes - 1; + var d = isLE ? 1 : -1; + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; + + value = Math.abs(value); + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0; + e = eMax; + } else { + e = Math.floor(Math.log(value) / Math.LN2); + if (value * (c = Math.pow(2, -e)) < 1) { + e--; + c *= 2; + } + if (e + eBias >= 1) { + value += rt / c; + } else { + value += rt * Math.pow(2, 1 - eBias); + } + if (value * c >= 2) { + e++; + c /= 2; + } - /** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property names to copy. - * @param {Object} [object={}] The object to copy properties to. - * @returns {Object} Returns `object`. - */ - function baseCopy(source, props, object) { - object || (object = {}); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index]; - object[key] = source[key]; - } - return object; - } + if (e + eBias >= eMax) { + m = 0; + e = eMax; + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen); + e = e + eBias; + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); + e = 0; + } + } - /** - * The base implementation of `_.callback` which supports specifying the - * number of arguments to provide to `func`. - * - * @private - * @param {*} [func=_.identity] The value to convert to a callback. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {number} [argCount] The number of arguments to provide to `func`. - * @returns {Function} Returns the callback. - */ - function baseCallback(func, thisArg, argCount) { - var type = typeof func; - if (type == 'function') { - return thisArg === undefined - ? func - : bindCallback(func, thisArg, argCount); - } - if (func == null) { - return identity; - } - if (type == 'object') { - return baseMatches(func); - } - return thisArg === undefined - ? property(func) - : baseMatchesProperty(func, thisArg); - } + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - /** - * The base implementation of `_.clone` without support for argument juggling - * and `this` binding `customizer` functions. - * - * @private - * @param {*} value The value to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @param {Function} [customizer] The function to customize cloning values. - * @param {string} [key] The key of `value`. - * @param {Object} [object] The object `value` belongs to. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates clones with source counterparts. - * @returns {*} Returns the cloned value. - */ - function baseClone(value, isDeep, customizer, key, object, stackA, stackB) { - var result; - if (customizer) { - result = object ? customizer(value, key, object) : customizer(value); - } - if (result !== undefined) { - return result; - } - if (!isObject(value)) { - return value; - } - var isArr = isArray(value); - if (isArr) { - result = initCloneArray(value); - if (!isDeep) { - return arrayCopy(value, result); - } - } else { - var tag = objToString.call(value), - isFunc = tag == funcTag; + e = (e << mLen) | m; + eLen += mLen; + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - if (tag == objectTag || tag == argsTag || (isFunc && !object)) { - result = initCloneObject(isFunc ? {} : value); - if (!isDeep) { - return baseAssign(result, value); + buffer[offset + i - d] |= s * 128; + }; + }, + {}, + ], + 183: [ + function(require, module, exports) { + var indexOf = [].indexOf; + + module.exports = function(arr, obj) { + if (indexOf) return arr.indexOf(obj); + for (var i = 0; i < arr.length; ++i) { + if (arr[i] === obj) return i; } - } else { - return cloneableTags[tag] - ? initCloneByTag(value, tag, isDeep) - : (object ? value : {}); + return -1; + }; + }, + {}, + ], + 184: [ + function(require, module, exports) { + arguments[4][180][0].apply(exports, arguments); + }, + { dup: 180 }, + ], + 185: [ + function(require, module, exports) { + /*! + * Determine if an object is a Buffer + * + * @author Feross Aboukhadijeh + * @license MIT + */ + + // The _isBuffer check is for Safari 5-7 support, because it's missing + // Object.prototype.constructor. Remove this eventually + module.exports = function(obj) { + return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer); + }; + + function isBuffer(obj) { + return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj); } - } - // Check for circular references and return its corresponding clone. - stackA || (stackA = []); - stackB || (stackB = []); - var length = stackA.length; - while (length--) { - if (stackA[length] == value) { - return stackB[length]; + // For Node v0.10 support. Remove this eventually. + function isSlowBuffer(obj) { + return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)); } - } - // Add the source value to the stack of traversed objects and associate it with its clone. - stackA.push(value); - stackB.push(result); - - // Recursively populate clone (susceptible to call stack limits). - (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) { - result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB); - }); - return result; - } + }, + {}, + ], + 186: [ + function(require, module, exports) { + var toString = {}.toString; + + module.exports = + Array.isArray || + function(arr) { + return toString.call(arr) == '[object Array]'; + }; + }, + {}, + ], + 187: [ + function(require, module, exports) { + (function(global) { + /** + * @license + * lodash 3.10.1 (Custom Build) + * Build: `lodash modern -d -o ./index.js` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + (function() { + /** Used as a safe reference for `undefined` in pre-ES5 environments. */ + var undefined; + + /** Used as the semantic version number. */ + var VERSION = '3.10.1'; + + /** Used to compose bitmasks for wrapper metadata. */ + var BIND_FLAG = 1, + BIND_KEY_FLAG = 2, + CURRY_BOUND_FLAG = 4, + CURRY_FLAG = 8, + CURRY_RIGHT_FLAG = 16, + PARTIAL_FLAG = 32, + PARTIAL_RIGHT_FLAG = 64, + ARY_FLAG = 128, + REARG_FLAG = 256; + + /** Used as default options for `_.trunc`. */ + var DEFAULT_TRUNC_LENGTH = 30, + DEFAULT_TRUNC_OMISSION = '...'; + + /** Used to detect when a function becomes hot. */ + var HOT_COUNT = 150, + HOT_SPAN = 16; + + /** Used as the size to enable large array optimizations. */ + var LARGE_ARRAY_SIZE = 200; + + /** Used to indicate the type of lazy iteratees. */ + var LAZY_FILTER_FLAG = 1, + LAZY_MAP_FLAG = 2; + + /** Used as the `TypeError` message for "Functions" methods. */ + var FUNC_ERROR_TEXT = 'Expected a function'; + + /** Used as the internal argument placeholder. */ + var PLACEHOLDER = '__lodash_placeholder__'; + + /** `Object#toString` result references. */ + var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + mapTag = '[object Map]', + numberTag = '[object Number]', + objectTag = '[object Object]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + weakMapTag = '[object WeakMap]'; + + var arrayBufferTag = '[object ArrayBuffer]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + + /** Used to match empty string literals in compiled template source. */ + var reEmptyStringLeading = /\b__p \+= '';/g, + reEmptyStringMiddle = /\b(__p \+=) '' \+/g, + reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; + + /** Used to match HTML entities and HTML characters. */ + var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g, + reUnescapedHtml = /[&<>"'`]/g, + reHasEscapedHtml = RegExp(reEscapedHtml.source), + reHasUnescapedHtml = RegExp(reUnescapedHtml.source); + + /** Used to match template delimiters. */ + var reEscape = /<%-([\s\S]+?)%>/g, + reEvaluate = /<%([\s\S]+?)%>/g, + reInterpolate = /<%=([\s\S]+?)%>/g; + + /** Used to match property names within property paths. */ + var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/, + rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g; + + /** + * Used to match `RegExp` [syntax characters](http://ecma-international.org/ecma-262/6.0/#sec-patterns) + * and those outlined by [`EscapeRegExpPattern`](http://ecma-international.org/ecma-262/6.0/#sec-escaperegexppattern). + */ + var reRegExpChars = /^[:!,]|[\\^$.*+?()[\]{}|\/]|(^[0-9a-fA-Fnrtuvx])|([\n\r\u2028\u2029])/g, + reHasRegExpChars = RegExp(reRegExpChars.source); + + /** Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). */ + var reComboMark = /[\u0300-\u036f\ufe20-\ufe23]/g; + + /** Used to match backslashes in property paths. */ + var reEscapeChar = /\\(\\)?/g; + + /** Used to match [ES template delimiters](http://ecma-international.org/ecma-262/6.0/#sec-template-literal-lexical-components). */ + var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; + + /** Used to match `RegExp` flags from their coerced string values. */ + var reFlags = /\w*$/; + + /** Used to detect hexadecimal string values. */ + var reHasHexPrefix = /^0[xX]/; + + /** Used to detect host constructors (Safari > 5). */ + var reIsHostCtor = /^\[object .+?Constructor\]$/; + + /** Used to detect unsigned integer values. */ + var reIsUint = /^\d+$/; + + /** Used to match latin-1 supplementary letters (excluding mathematical operators). */ + var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g; + + /** Used to ensure capturing order of template delimiters. */ + var reNoMatch = /($^)/; + + /** Used to match unescaped characters in compiled string literals. */ + var reUnescapedString = /['\n\r\u2028\u2029\\]/g; + + /** Used to match words to create compound words. */ + var reWords = (function() { + var upper = '[A-Z\\xc0-\\xd6\\xd8-\\xde]', + lower = '[a-z\\xdf-\\xf6\\xf8-\\xff]+'; + + return RegExp( + upper + '+(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', + 'g', + ); + })(); + + /** Used to assign default `context` object properties. */ + var contextProps = [ + 'Array', + 'ArrayBuffer', + 'Date', + 'Error', + 'Float32Array', + 'Float64Array', + 'Function', + 'Int8Array', + 'Int16Array', + 'Int32Array', + 'Math', + 'Number', + 'Object', + 'RegExp', + 'Set', + 'String', + '_', + 'clearTimeout', + 'isFinite', + 'parseFloat', + 'parseInt', + 'setTimeout', + 'TypeError', + 'Uint8Array', + 'Uint8ClampedArray', + 'Uint16Array', + 'Uint32Array', + 'WeakMap', + ]; + + /** Used to make template sourceURLs easier to identify. */ + var templateCounter = -1; + + /** Used to identify `toStringTag` values of typed arrays. */ + var typedArrayTags = {}; + typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = typedArrayTags[int8Tag] = typedArrayTags[ + int16Tag + ] = typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = typedArrayTags[uint8ClampedTag] = typedArrayTags[ + uint16Tag + ] = typedArrayTags[uint32Tag] = true; + typedArrayTags[argsTag] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[ + boolTag + ] = typedArrayTags[dateTag] = typedArrayTags[errorTag] = typedArrayTags[funcTag] = typedArrayTags[ + mapTag + ] = typedArrayTags[numberTag] = typedArrayTags[objectTag] = typedArrayTags[regexpTag] = typedArrayTags[ + setTag + ] = typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; + + /** Used to identify `toStringTag` values supported by `_.clone`. */ + var cloneableTags = {}; + cloneableTags[argsTag] = cloneableTags[arrayTag] = cloneableTags[arrayBufferTag] = cloneableTags[ + boolTag + ] = cloneableTags[dateTag] = cloneableTags[float32Tag] = cloneableTags[float64Tag] = cloneableTags[ + int8Tag + ] = cloneableTags[int16Tag] = cloneableTags[int32Tag] = cloneableTags[numberTag] = cloneableTags[ + objectTag + ] = cloneableTags[regexpTag] = cloneableTags[stringTag] = cloneableTags[uint8Tag] = cloneableTags[ + uint8ClampedTag + ] = cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; + cloneableTags[errorTag] = cloneableTags[funcTag] = cloneableTags[mapTag] = cloneableTags[ + setTag + ] = cloneableTags[weakMapTag] = false; + + /** Used to map latin-1 supplementary letters to basic latin letters. */ + var deburredLetters = { + ร€: 'A', + ร: 'A', + ร‚: 'A', + รƒ: 'A', + ร„: 'A', + ร…: 'A', + ร : 'a', + รก: 'a', + รข: 'a', + รฃ: 'a', + รค: 'a', + รฅ: 'a', + ร‡: 'C', + รง: 'c', + ร: 'D', + รฐ: 'd', + รˆ: 'E', + ร‰: 'E', + รŠ: 'E', + ร‹: 'E', + รจ: 'e', + รฉ: 'e', + รช: 'e', + รซ: 'e', + รŒ: 'I', + ร: 'I', + รŽ: 'I', + ร: 'I', + รฌ: 'i', + รญ: 'i', + รฎ: 'i', + รฏ: 'i', + ร‘: 'N', + รฑ: 'n', + ร’: 'O', + ร“: 'O', + ร”: 'O', + ร•: 'O', + ร–: 'O', + ร˜: 'O', + รฒ: 'o', + รณ: 'o', + รด: 'o', + รต: 'o', + รถ: 'o', + รธ: 'o', + ร™: 'U', + รš: 'U', + ร›: 'U', + รœ: 'U', + รน: 'u', + รบ: 'u', + รป: 'u', + รผ: 'u', + ร: 'Y', + รฝ: 'y', + รฟ: 'y', + ร†: 'Ae', + รฆ: 'ae', + รž: 'Th', + รพ: 'th', + รŸ: 'ss', + }; - /** - * The base implementation of `_.create` without support for assigning - * properties to the created object. - * - * @private - * @param {Object} prototype The object to inherit from. - * @returns {Object} Returns the new object. - */ - var baseCreate = (function() { - function object() {} - return function(prototype) { - if (isObject(prototype)) { - object.prototype = prototype; - var result = new object; - object.prototype = undefined; - } - return result || {}; - }; - }()); - - /** - * The base implementation of `_.delay` and `_.defer` which accepts an index - * of where to slice the arguments to provide to `func`. - * - * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {Object} args The arguments provide to `func`. - * @returns {number} Returns the timer id. - */ - function baseDelay(func, wait, args) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return setTimeout(function() { func.apply(undefined, args); }, wait); - } + /** Used to map characters to HTML entities. */ + var htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`', + }; - /** - * The base implementation of `_.difference` which accepts a single array - * of values to exclude. - * - * @private - * @param {Array} array The array to inspect. - * @param {Array} values The values to exclude. - * @returns {Array} Returns the new array of filtered values. - */ - function baseDifference(array, values) { - var length = array ? array.length : 0, - result = []; - - if (!length) { - return result; - } - var index = -1, - indexOf = getIndexOf(), - isCommon = indexOf == baseIndexOf, - cache = (isCommon && values.length >= LARGE_ARRAY_SIZE) ? createCache(values) : null, - valuesLength = values.length; - - if (cache) { - indexOf = cacheIndexOf; - isCommon = false; - values = cache; - } - outer: - while (++index < length) { - var value = array[index]; + /** Used to map HTML entities to characters. */ + var htmlUnescapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'", + '`': '`', + }; + + /** Used to determine if values are of the language type `Object`. */ + var objectTypes = { + function: true, + object: true, + }; + + /** Used to escape characters for inclusion in compiled regexes. */ + var regexpEscapes = { + '0': 'x30', + '1': 'x31', + '2': 'x32', + '3': 'x33', + '4': 'x34', + '5': 'x35', + '6': 'x36', + '7': 'x37', + '8': 'x38', + '9': 'x39', + A: 'x41', + B: 'x42', + C: 'x43', + D: 'x44', + E: 'x45', + F: 'x46', + a: 'x61', + b: 'x62', + c: 'x63', + d: 'x64', + e: 'x65', + f: 'x66', + n: 'x6e', + r: 'x72', + t: 'x74', + u: 'x75', + v: 'x76', + x: 'x78', + }; + + /** Used to escape characters for inclusion in compiled string literals. */ + var stringEscapes = { + '\\': '\\', + "'": "'", + '\n': 'n', + '\r': 'r', + '\u2028': 'u2028', + '\u2029': 'u2029', + }; - if (isCommon && value === value) { - var valuesIndex = valuesLength; - while (valuesIndex--) { - if (values[valuesIndex] === value) { - continue outer; + /** Detect free variable `exports`. */ + var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; + + /** Detect free variable `global` from Node.js. */ + var freeGlobal = + freeExports && freeModule && typeof global == 'object' && global && global.Object && global; + + /** Detect free variable `self`. */ + var freeSelf = objectTypes[typeof self] && self && self.Object && self; + + /** Detect free variable `window`. */ + var freeWindow = objectTypes[typeof window] && window && window.Object && window; + + /** Detect the popular CommonJS extension `module.exports`. */ + var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; + + /** + * Used as a reference to the global object. + * + * The `this` value is used if it's the global object to avoid Greasemonkey's + * restricted `window` object, otherwise the `window` object is used. + */ + var root = freeGlobal || (freeWindow !== (this && this.window) && freeWindow) || freeSelf || this; + + /*--------------------------------------------------------------------------*/ + + /** + * The base implementation of `compareAscending` which compares values and + * sorts them in ascending order without guaranteeing a stable sort. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {number} Returns the sort order indicator for `value`. + */ + function baseCompareAscending(value, other) { + if (value !== other) { + var valIsNull = value === null, + valIsUndef = value === undefined, + valIsReflexive = value === value; + + var othIsNull = other === null, + othIsUndef = other === undefined, + othIsReflexive = other === other; + + if ( + (value > other && !othIsNull) || + !valIsReflexive || + (valIsNull && !othIsUndef && othIsReflexive) || + (valIsUndef && othIsReflexive) + ) { + return 1; + } + if ( + (value < other && !valIsNull) || + !othIsReflexive || + (othIsNull && !valIsUndef && valIsReflexive) || + (othIsUndef && valIsReflexive) + ) { + return -1; + } + } + return 0; } - } - result.push(value); - } - else if (indexOf(values, value, 0) < 0) { - result.push(value); - } - } - return result; - } - /** - * The base implementation of `_.forEach` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object|string} Returns `collection`. - */ - var baseEach = createBaseEach(baseForOwn); - - /** - * The base implementation of `_.forEachRight` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object|string} Returns `collection`. - */ - var baseEachRight = createBaseEach(baseForOwnRight, true); - - /** - * The base implementation of `_.every` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false` - */ - function baseEvery(collection, predicate) { - var result = true; - baseEach(collection, function(value, index, collection) { - result = !!predicate(value, index, collection); - return result; - }); - return result; - } + /** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for callback shorthands and `this` binding. + * + * @private + * @param {Array} array The array to search. + * @param {Function} predicate The function invoked per iteration. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseFindIndex(array, predicate, fromRight) { + var length = array.length, + index = fromRight ? length : -1; + + while (fromRight ? index-- : ++index < length) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; + } - /** - * Gets the extremum value of `collection` invoking `iteratee` for each value - * in `collection` to generate the criterion by which the value is ranked. - * The `iteratee` is invoked with three arguments: (value, index|key, collection). - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} comparator The function used to compare values. - * @param {*} exValue The initial extremum value. - * @returns {*} Returns the extremum value. - */ - function baseExtremum(collection, iteratee, comparator, exValue) { - var computed = exValue, - result = computed; - - baseEach(collection, function(value, index, collection) { - var current = +iteratee(value, index, collection); - if (comparator(current, computed) || (current === exValue && current === result)) { - computed = current; - result = value; - } - }); - return result; - } + /** + * The base implementation of `_.indexOf` without support for binary searches. + * + * @private + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOf(array, value, fromIndex) { + if (value !== value) { + return indexOfNaN(array, fromIndex); + } + var index = fromIndex - 1, + length = array.length; - /** - * The base implementation of `_.fill` without an iteratee call guard. - * - * @private - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - */ - function baseFill(array, value, start, end) { - var length = array.length; - - start = start == null ? 0 : (+start || 0); - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = (end === undefined || end > length) ? length : (+end || 0); - if (end < 0) { - end += length; - } - length = start > end ? 0 : (end >>> 0); - start >>>= 0; + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } - while (start < length) { - array[start++] = value; - } - return array; - } + /** + * The base implementation of `_.isFunction` without support for environments + * with incorrect `typeof` results. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + */ + function baseIsFunction(value) { + // Avoid a Chakra JIT bug in compatibility modes of IE 11. + // See https://github.com/jashkenas/underscore/issues/1621 for more details. + return typeof value == 'function' || false; + } - /** - * The base implementation of `_.filter` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function baseFilter(collection, predicate) { - var result = []; - baseEach(collection, function(value, index, collection) { - if (predicate(value, index, collection)) { - result.push(value); - } - }); - return result; - } + /** + * Converts `value` to a string if it's not one. An empty string is returned + * for `null` or `undefined` values. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ + function baseToString(value) { + return value == null ? '' : value + ''; + } - /** - * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`, - * without support for callback shorthands and `this` binding, which iterates - * over `collection` using the provided `eachFunc`. - * - * @private - * @param {Array|Object|string} collection The collection to search. - * @param {Function} predicate The function invoked per iteration. - * @param {Function} eachFunc The function to iterate over `collection`. - * @param {boolean} [retKey] Specify returning the key of the found element - * instead of the element itself. - * @returns {*} Returns the found element or its key, else `undefined`. - */ - function baseFind(collection, predicate, eachFunc, retKey) { - var result; - eachFunc(collection, function(value, key, collection) { - if (predicate(value, key, collection)) { - result = retKey ? key : value; - return false; - } - }); - return result; - } + /** + * Used by `_.trim` and `_.trimLeft` to get the index of the first character + * of `string` that is not found in `chars`. + * + * @private + * @param {string} string The string to inspect. + * @param {string} chars The characters to find. + * @returns {number} Returns the index of the first character not found in `chars`. + */ + function charsLeftIndex(string, chars) { + var index = -1, + length = string.length; + + while (++index < length && chars.indexOf(string.charAt(index)) > -1) {} + return index; + } - /** - * The base implementation of `_.flatten` with added support for restricting - * flattening and specifying the start index. - * - * @private - * @param {Array} array The array to flatten. - * @param {boolean} [isDeep] Specify a deep flatten. - * @param {boolean} [isStrict] Restrict flattening to arrays-like objects. - * @param {Array} [result=[]] The initial result value. - * @returns {Array} Returns the new flattened array. - */ - function baseFlatten(array, isDeep, isStrict, result) { - result || (result = []); - - var index = -1, - length = array.length; - - while (++index < length) { - var value = array[index]; - if (isObjectLike(value) && isArrayLike(value) && - (isStrict || isArray(value) || isArguments(value))) { - if (isDeep) { - // Recursively flatten arrays (susceptible to call stack limits). - baseFlatten(value, isDeep, isStrict, result); - } else { - arrayPush(result, value); - } - } else if (!isStrict) { - result[result.length] = value; - } - } - return result; - } + /** + * Used by `_.trim` and `_.trimRight` to get the index of the last character + * of `string` that is not found in `chars`. + * + * @private + * @param {string} string The string to inspect. + * @param {string} chars The characters to find. + * @returns {number} Returns the index of the last character not found in `chars`. + */ + function charsRightIndex(string, chars) { + var index = string.length; + + while (index-- && chars.indexOf(string.charAt(index)) > -1) {} + return index; + } - /** - * The base implementation of `baseForIn` and `baseForOwn` which iterates - * over `object` properties returned by `keysFunc` invoking `iteratee` for - * each property. Iteratee functions may exit iteration early by explicitly - * returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseFor = createBaseFor(); - - /** - * This function is like `baseFor` except that it iterates over properties - * in the opposite order. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseForRight = createBaseFor(true); - - /** - * The base implementation of `_.forIn` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForIn(object, iteratee) { - return baseFor(object, iteratee, keysIn); - } + /** + * Used by `_.sortBy` to compare transformed elements of a collection and stable + * sort them in ascending order. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @returns {number} Returns the sort order indicator for `object`. + */ + function compareAscending(object, other) { + return baseCompareAscending(object.criteria, other.criteria) || object.index - other.index; + } - /** - * The base implementation of `_.forOwn` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwn(object, iteratee) { - return baseFor(object, iteratee, keys); - } + /** + * Used by `_.sortByOrder` to compare multiple properties of a value to another + * and stable sort them. + * + * If `orders` is unspecified, all valuess are sorted in ascending order. Otherwise, + * a value is sorted in ascending order if its corresponding order is "asc", and + * descending if "desc". + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {boolean[]} orders The order to sort by for each property. + * @returns {number} Returns the sort order indicator for `object`. + */ + function compareMultiple(object, other, orders) { + var index = -1, + objCriteria = object.criteria, + othCriteria = other.criteria, + length = objCriteria.length, + ordersLength = orders.length; + + while (++index < length) { + var result = baseCompareAscending(objCriteria[index], othCriteria[index]); + if (result) { + if (index >= ordersLength) { + return result; + } + var order = orders[index]; + return result * (order === 'asc' || order === true ? 1 : -1); + } + } + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to provide the same value for + // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 + // for more details. + // + // This also ensures a stable sort in V8 and other engines. + // See https://code.google.com/p/v8/issues/detail?id=90 for more details. + return object.index - other.index; + } - /** - * The base implementation of `_.forOwnRight` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwnRight(object, iteratee) { - return baseForRight(object, iteratee, keys); - } + /** + * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters. + * + * @private + * @param {string} letter The matched letter to deburr. + * @returns {string} Returns the deburred letter. + */ + function deburrLetter(letter) { + return deburredLetters[letter]; + } - /** - * The base implementation of `_.functions` which creates an array of - * `object` function property names filtered from those provided. - * - * @private - * @param {Object} object The object to inspect. - * @param {Array} props The property names to filter. - * @returns {Array} Returns the new array of filtered property names. - */ - function baseFunctions(object, props) { - var index = -1, - length = props.length, - resIndex = -1, - result = []; - - while (++index < length) { - var key = props[index]; - if (isFunction(object[key])) { - result[++resIndex] = key; - } - } - return result; - } + /** + * Used by `_.escape` to convert characters to HTML entities. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + function escapeHtmlChar(chr) { + return htmlEscapes[chr]; + } - /** - * The base implementation of `get` without support for string paths - * and default values. - * - * @private - * @param {Object} object The object to query. - * @param {Array} path The path of the property to get. - * @param {string} [pathKey] The key representation of path. - * @returns {*} Returns the resolved value. - */ - function baseGet(object, path, pathKey) { - if (object == null) { - return; - } - if (pathKey !== undefined && pathKey in toObject(object)) { - path = [pathKey]; - } - var index = 0, - length = path.length; + /** + * Used by `_.escapeRegExp` to escape characters for inclusion in compiled regexes. + * + * @private + * @param {string} chr The matched character to escape. + * @param {string} leadingChar The capture group for a leading character. + * @param {string} whitespaceChar The capture group for a whitespace character. + * @returns {string} Returns the escaped character. + */ + function escapeRegExpChar(chr, leadingChar, whitespaceChar) { + if (leadingChar) { + chr = regexpEscapes[chr]; + } else if (whitespaceChar) { + chr = stringEscapes[chr]; + } + return '\\' + chr; + } - while (object != null && index < length) { - object = object[path[index++]]; - } - return (index && index == length) ? object : undefined; - } + /** + * Used by `_.template` to escape characters for inclusion in compiled string literals. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + function escapeStringChar(chr) { + return '\\' + stringEscapes[chr]; + } - /** - * The base implementation of `_.isEqual` without support for `this` binding - * `customizer` functions. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparing values. - * @param {boolean} [isLoose] Specify performing partial comparisons. - * @param {Array} [stackA] Tracks traversed `value` objects. - * @param {Array} [stackB] Tracks traversed `other` objects. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - */ - function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) { - if (value === other) { - return true; - } - if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { - return value !== value && other !== other; - } - return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB); - } + /** + * Gets the index at which the first occurrence of `NaN` is found in `array`. + * + * @private + * @param {Array} array The array to search. + * @param {number} fromIndex The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched `NaN`, else `-1`. + */ + function indexOfNaN(array, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 0 : -1); + + while (fromRight ? index-- : ++index < length) { + var other = array[index]; + if (other !== other) { + return index; + } + } + return -1; + } - /** - * A specialized version of `baseIsEqual` for arrays and objects which performs - * deep comparisons and tracks traversed objects enabling objects with circular - * references to be compared. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparing objects. - * @param {boolean} [isLoose] Specify performing partial comparisons. - * @param {Array} [stackA=[]] Tracks traversed `value` objects. - * @param {Array} [stackB=[]] Tracks traversed `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) { - var objIsArr = isArray(object), - othIsArr = isArray(other), - objTag = arrayTag, - othTag = arrayTag; - - if (!objIsArr) { - objTag = objToString.call(object); - if (objTag == argsTag) { - objTag = objectTag; - } else if (objTag != objectTag) { - objIsArr = isTypedArray(object); - } - } - if (!othIsArr) { - othTag = objToString.call(other); - if (othTag == argsTag) { - othTag = objectTag; - } else if (othTag != objectTag) { - othIsArr = isTypedArray(other); - } - } - var objIsObj = objTag == objectTag, - othIsObj = othTag == objectTag, - isSameTag = objTag == othTag; + /** + * Checks if `value` is object-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + */ + function isObjectLike(value) { + return !!value && typeof value == 'object'; + } - if (isSameTag && !(objIsArr || objIsObj)) { - return equalByTag(object, other, objTag); - } - if (!isLoose) { - var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), - othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); + /** + * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a + * character code is whitespace. + * + * @private + * @param {number} charCode The character code to inspect. + * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`. + */ + function isSpace(charCode) { + return ( + (charCode <= 160 && (charCode >= 9 && charCode <= 13)) || + charCode == 32 || + charCode == 160 || + charCode == 5760 || + charCode == 6158 || + (charCode >= 8192 && + (charCode <= 8202 || + charCode == 8232 || + charCode == 8233 || + charCode == 8239 || + charCode == 8287 || + charCode == 12288 || + charCode == 65279)) + ); + } - if (objIsWrapped || othIsWrapped) { - return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB); - } - } - if (!isSameTag) { - return false; - } - // Assume cyclic values are equal. - // For more information on detecting circular references see https://es5.github.io/#JO. - stackA || (stackA = []); - stackB || (stackB = []); + /** + * Replaces all `placeholder` elements in `array` with an internal placeholder + * and returns an array of their indexes. + * + * @private + * @param {Array} array The array to modify. + * @param {*} placeholder The placeholder to replace. + * @returns {Array} Returns the new array of placeholder indexes. + */ + function replaceHolders(array, placeholder) { + var index = -1, + length = array.length, + resIndex = -1, + result = []; + + while (++index < length) { + if (array[index] === placeholder) { + array[index] = PLACEHOLDER; + result[++resIndex] = index; + } + } + return result; + } - var length = stackA.length; - while (length--) { - if (stackA[length] == object) { - return stackB[length] == other; - } - } - // Add `object` and `other` to the stack of traversed objects. - stackA.push(object); - stackB.push(other); + /** + * An implementation of `_.uniq` optimized for sorted arrays without support + * for callback shorthands and `this` binding. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The function invoked per iteration. + * @returns {Array} Returns the new duplicate-value-free array. + */ + function sortedUniq(array, iteratee) { + var seen, + index = -1, + length = array.length, + resIndex = -1, + result = []; + + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value, index, array) : value; + + if (!index || seen !== computed) { + seen = computed; + result[++resIndex] = value; + } + } + return result; + } - var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB); + /** + * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace + * character of `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the index of the first non-whitespace character. + */ + function trimmedLeftIndex(string) { + var index = -1, + length = string.length; + + while (++index < length && isSpace(string.charCodeAt(index))) {} + return index; + } - stackA.pop(); - stackB.pop(); + /** + * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace + * character of `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the index of the last non-whitespace character. + */ + function trimmedRightIndex(string) { + var index = string.length; + + while (index-- && isSpace(string.charCodeAt(index))) {} + return index; + } - return result; - } + /** + * Used by `_.unescape` to convert HTML entities to characters. + * + * @private + * @param {string} chr The matched character to unescape. + * @returns {string} Returns the unescaped character. + */ + function unescapeHtmlChar(chr) { + return htmlUnescapes[chr]; + } - /** - * The base implementation of `_.isMatch` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Object} object The object to inspect. - * @param {Array} matchData The propery names, values, and compare flags to match. - * @param {Function} [customizer] The function to customize comparing objects. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - */ - function baseIsMatch(object, matchData, customizer) { - var index = matchData.length, - length = index, - noCustomizer = !customizer; - - if (object == null) { - return !length; - } - object = toObject(object); - while (index--) { - var data = matchData[index]; - if ((noCustomizer && data[2]) - ? data[1] !== object[data[0]] - : !(data[0] in object) - ) { - return false; - } - } - while (++index < length) { - data = matchData[index]; - var key = data[0], - objValue = object[key], - srcValue = data[1]; - - if (noCustomizer && data[2]) { - if (objValue === undefined && !(key in object)) { - return false; - } - } else { - var result = customizer ? customizer(objValue, srcValue, key) : undefined; - if (!(result === undefined ? baseIsEqual(srcValue, objValue, customizer, true) : result)) { - return false; - } - } - } - return true; - } + /*--------------------------------------------------------------------------*/ + + /** + * Create a new pristine `lodash` function using the given `context` object. + * + * @static + * @memberOf _ + * @category Utility + * @param {Object} [context=root] The context object. + * @returns {Function} Returns a new `lodash` function. + * @example + * + * _.mixin({ 'foo': _.constant('foo') }); + * + * var lodash = _.runInContext(); + * lodash.mixin({ 'bar': lodash.constant('bar') }); + * + * _.isFunction(_.foo); + * // => true + * _.isFunction(_.bar); + * // => false + * + * lodash.isFunction(lodash.foo); + * // => false + * lodash.isFunction(lodash.bar); + * // => true + * + * // using `context` to mock `Date#getTime` use in `_.now` + * var mock = _.runInContext({ + * 'Date': function() { + * return { 'getTime': getTimeMock }; + * } + * }); + * + * // or creating a suped-up `defer` in Node.js + * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; + */ + function runInContext(context) { + // Avoid issues with some ES3 environments that attempt to use values, named + // after built-in constructors like `Object`, for the creation of literals. + // ES5 clears this up by stating that literals must use built-in constructors. + // See https://es5.github.io/#x11.1.5 for more details. + context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root; + + /** Native constructor references. */ + var Array = context.Array, + Date = context.Date, + Error = context.Error, + Function = context.Function, + Math = context.Math, + Number = context.Number, + Object = context.Object, + RegExp = context.RegExp, + String = context.String, + TypeError = context.TypeError; + + /** Used for native method references. */ + var arrayProto = Array.prototype, + objectProto = Object.prototype, + stringProto = String.prototype; + + /** Used to resolve the decompiled source of functions. */ + var fnToString = Function.prototype.toString; + + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto.hasOwnProperty; + + /** Used to generate unique IDs. */ + var idCounter = 0; + + /** + * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) + * of values. + */ + var objToString = objectProto.toString; + + /** Used to restore the original `_` reference in `_.noConflict`. */ + var oldDash = root._; + + /** Used to detect if a method is native. */ + var reIsNative = RegExp( + '^' + + fnToString + .call(hasOwnProperty) + .replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + + '$', + ); + + /** Native method references. */ + var ArrayBuffer = context.ArrayBuffer, + clearTimeout = context.clearTimeout, + parseFloat = context.parseFloat, + pow = Math.pow, + propertyIsEnumerable = objectProto.propertyIsEnumerable, + Set = getNative(context, 'Set'), + setTimeout = context.setTimeout, + splice = arrayProto.splice, + Uint8Array = context.Uint8Array, + WeakMap = getNative(context, 'WeakMap'); + + /* Native method references for those with the same name as other `lodash` methods. */ + var nativeCeil = Math.ceil, + nativeCreate = getNative(Object, 'create'), + nativeFloor = Math.floor, + nativeIsArray = getNative(Array, 'isArray'), + nativeIsFinite = context.isFinite, + nativeKeys = getNative(Object, 'keys'), + nativeMax = Math.max, + nativeMin = Math.min, + nativeNow = getNative(Date, 'now'), + nativeParseInt = context.parseInt, + nativeRandom = Math.random; + + /** Used as references for `-Infinity` and `Infinity`. */ + var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY, + POSITIVE_INFINITY = Number.POSITIVE_INFINITY; + + /** Used as references for the maximum length and index of an array. */ + var MAX_ARRAY_LENGTH = 4294967295, + MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, + HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; + + /** + * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) + * of an array-like value. + */ + var MAX_SAFE_INTEGER = 9007199254740991; + + /** Used to store function metadata. */ + var metaMap = WeakMap && new WeakMap(); + + /** Used to lookup unminified function names. */ + var realNames = {}; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` object which wraps `value` to enable implicit chaining. + * Methods that operate on and return arrays, collections, and functions can + * be chained together. Methods that retrieve a single value or may return a + * primitive value will automatically end the chain returning the unwrapped + * value. Explicit chaining may be enabled using `_.chain`. The execution of + * chained methods is lazy, that is, execution is deferred until `_#value` + * is implicitly or explicitly called. + * + * Lazy evaluation allows several methods to support shortcut fusion. Shortcut + * fusion is an optimization strategy which merge iteratee calls; this can help + * to avoid the creation of intermediate data structures and greatly reduce the + * number of iteratee executions. + * + * Chaining is supported in custom builds as long as the `_#value` method is + * directly or indirectly included in the build. + * + * In addition to lodash methods, wrappers have `Array` and `String` methods. + * + * The wrapper `Array` methods are: + * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, + * `splice`, and `unshift` + * + * The wrapper `String` methods are: + * `replace` and `split` + * + * The wrapper methods that support shortcut fusion are: + * `compact`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, + * `first`, `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, + * `slice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `toArray`, + * and `where` + * + * The chainable wrapper methods are: + * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`, + * `callback`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`, + * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defaultsDeep`, + * `defer`, `delay`, `difference`, `drop`, `dropRight`, `dropRightWhile`, + * `dropWhile`, `fill`, `filter`, `flatten`, `flattenDeep`, `flow`, `flowRight`, + * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, + * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, + * `invoke`, `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, + * `matchesProperty`, `memoize`, `merge`, `method`, `methodOf`, `mixin`, + * `modArgs`, `negate`, `omit`, `once`, `pairs`, `partial`, `partialRight`, + * `partition`, `pick`, `plant`, `pluck`, `property`, `propertyOf`, `pull`, + * `pullAt`, `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`, + * `reverse`, `set`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByAll`, + * `sortByOrder`, `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`, + * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, + * `transform`, `union`, `uniq`, `unshift`, `unzip`, `unzipWith`, `values`, + * `valuesIn`, `where`, `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith` + * + * The wrapper methods that are **not** chainable by default are: + * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clone`, `cloneDeep`, + * `deburr`, `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, + * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, + * `floor`, `get`, `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`, + * `inRange`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, + * `isEmpty`, `isEqual`, `isError`, `isFinite` `isFunction`, `isMatch`, + * `isNative`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, + * `isRegExp`, `isString`, `isUndefined`, `isTypedArray`, `join`, `kebabCase`, + * `last`, `lastIndexOf`, `lt`, `lte`, `max`, `min`, `noConflict`, `noop`, + * `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, `random`, `reduce`, + * `reduceRight`, `repeat`, `result`, `round`, `runInContext`, `shift`, `size`, + * `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`, `startCase`, + * `startsWith`, `sum`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`, + * `unescape`, `uniqueId`, `value`, and `words` + * + * The wrapper method `sample` will return a wrapped value when `n` is provided, + * otherwise an unwrapped value is returned. + * + * @name _ + * @constructor + * @category Chain + * @param {*} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var wrapped = _([1, 2, 3]); + * + * // returns an unwrapped value + * wrapped.reduce(function(total, n) { + * return total + n; + * }); + * // => 6 + * + * // returns a wrapped value + * var squares = wrapped.map(function(n) { + * return n * n; + * }); + * + * _.isArray(squares); + * // => false + * + * _.isArray(squares.value()); + * // => true + */ + function lodash(value) { + if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { + if (value instanceof LodashWrapper) { + return value; + } + if (hasOwnProperty.call(value, '__chain__') && hasOwnProperty.call(value, '__wrapped__')) { + return wrapperClone(value); + } + } + return new LodashWrapper(value); + } - /** - * The base implementation of `_.map` without support for callback shorthands - * and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function baseMap(collection, iteratee) { - var index = -1, - result = isArrayLike(collection) ? Array(collection.length) : []; - - baseEach(collection, function(value, key, collection) { - result[++index] = iteratee(value, key, collection); - }); - return result; - } + /** + * The function whose prototype all chaining wrappers inherit from. + * + * @private + */ + function baseLodash() { + // No operation performed. + } - /** - * The base implementation of `_.matches` which does not clone `source`. - * - * @private - * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new function. - */ - function baseMatches(source) { - var matchData = getMatchData(source); - if (matchData.length == 1 && matchData[0][2]) { - var key = matchData[0][0], - value = matchData[0][1]; - - return function(object) { - if (object == null) { - return false; - } - return object[key] === value && (value !== undefined || (key in toObject(object))); - }; - } - return function(object) { - return baseIsMatch(object, matchData); - }; - } + /** + * The base constructor for creating `lodash` wrapper objects. + * + * @private + * @param {*} value The value to wrap. + * @param {boolean} [chainAll] Enable chaining for all wrapper methods. + * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value. + */ + function LodashWrapper(value, chainAll, actions) { + this.__wrapped__ = value; + this.__actions__ = actions || []; + this.__chain__ = !!chainAll; + } - /** - * The base implementation of `_.matchesProperty` which does not clone `srcValue`. - * - * @private - * @param {string} path The path of the property to get. - * @param {*} srcValue The value to compare. - * @returns {Function} Returns the new function. - */ - function baseMatchesProperty(path, srcValue) { - var isArr = isArray(path), - isCommon = isKey(path) && isStrictComparable(srcValue), - pathKey = (path + ''); - - path = toPath(path); - return function(object) { - if (object == null) { - return false; - } - var key = pathKey; - object = toObject(object); - if ((isArr || !isCommon) && !(key in object)) { - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - if (object == null) { - return false; - } - key = last(path); - object = toObject(object); - } - return object[key] === srcValue - ? (srcValue !== undefined || (key in object)) - : baseIsEqual(srcValue, object[key], undefined, true); - }; - } + /** + * An object environment feature flags. + * + * @static + * @memberOf _ + * @type Object + */ + var support = (lodash.support = {}); + + /** + * By default, the template delimiters used by lodash are like those in + * embedded Ruby (ERB). Change the following template settings to use + * alternative delimiters. + * + * @static + * @memberOf _ + * @type Object + */ + lodash.templateSettings = { + /** + * Used to detect `data` property values to be HTML-escaped. + * + * @memberOf _.templateSettings + * @type RegExp + */ + escape: reEscape, + + /** + * Used to detect code to be evaluated. + * + * @memberOf _.templateSettings + * @type RegExp + */ + evaluate: reEvaluate, + + /** + * Used to detect `data` property values to inject. + * + * @memberOf _.templateSettings + * @type RegExp + */ + interpolate: reInterpolate, + + /** + * Used to reference the data object in the template text. + * + * @memberOf _.templateSettings + * @type string + */ + variable: '', + + /** + * Used to import variables into the compiled template. + * + * @memberOf _.templateSettings + * @type Object + */ + imports: { + /** + * A reference to the `lodash` function. + * + * @memberOf _.templateSettings.imports + * @type Function + */ + _: lodash, + }, + }; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. + * + * @private + * @param {*} value The value to wrap. + */ + function LazyWrapper(value) { + this.__wrapped__ = value; + this.__actions__ = []; + this.__dir__ = 1; + this.__filtered__ = false; + this.__iteratees__ = []; + this.__takeCount__ = POSITIVE_INFINITY; + this.__views__ = []; + } - /** - * The base implementation of `_.merge` without support for argument juggling, - * multiple sources, and `this` binding `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {Function} [customizer] The function to customize merged values. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates values with source counterparts. - * @returns {Object} Returns `object`. - */ - function baseMerge(object, source, customizer, stackA, stackB) { - if (!isObject(object)) { - return object; - } - var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), - props = isSrcArr ? undefined : keys(source); + /** + * Creates a clone of the lazy wrapper object. + * + * @private + * @name clone + * @memberOf LazyWrapper + * @returns {Object} Returns the cloned `LazyWrapper` object. + */ + function lazyClone() { + var result = new LazyWrapper(this.__wrapped__); + result.__actions__ = arrayCopy(this.__actions__); + result.__dir__ = this.__dir__; + result.__filtered__ = this.__filtered__; + result.__iteratees__ = arrayCopy(this.__iteratees__); + result.__takeCount__ = this.__takeCount__; + result.__views__ = arrayCopy(this.__views__); + return result; + } - arrayEach(props || source, function(srcValue, key) { - if (props) { - key = srcValue; - srcValue = source[key]; - } - if (isObjectLike(srcValue)) { - stackA || (stackA = []); - stackB || (stackB = []); - baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); - } - else { - var value = object[key], - result = customizer ? customizer(value, srcValue, key, object, source) : undefined, - isCommon = result === undefined; + /** + * Reverses the direction of lazy iteration. + * + * @private + * @name reverse + * @memberOf LazyWrapper + * @returns {Object} Returns the new reversed `LazyWrapper` object. + */ + function lazyReverse() { + if (this.__filtered__) { + var result = new LazyWrapper(this); + result.__dir__ = -1; + result.__filtered__ = true; + } else { + result = this.clone(); + result.__dir__ *= -1; + } + return result; + } - if (isCommon) { - result = srcValue; - } - if ((result !== undefined || (isSrcArr && !(key in object))) && - (isCommon || (result === result ? (result !== value) : (value === value)))) { - object[key] = result; - } - } - }); - return object; - } + /** + * Extracts the unwrapped value from its lazy wrapper. + * + * @private + * @name value + * @memberOf LazyWrapper + * @returns {*} Returns the unwrapped value. + */ + function lazyValue() { + var array = this.__wrapped__.value(), + dir = this.__dir__, + isArr = isArray(array), + isRight = dir < 0, + arrLength = isArr ? array.length : 0, + view = getView(0, arrLength, this.__views__), + start = view.start, + end = view.end, + length = end - start, + index = isRight ? end : start - 1, + iteratees = this.__iteratees__, + iterLength = iteratees.length, + resIndex = 0, + takeCount = nativeMin(length, this.__takeCount__); + + if (!isArr || arrLength < LARGE_ARRAY_SIZE || (arrLength == length && takeCount == length)) { + return baseWrapperValue(isRight && isArr ? array.reverse() : array, this.__actions__); + } + var result = []; + + outer: while (length-- && resIndex < takeCount) { + index += dir; + + var iterIndex = -1, + value = array[index]; + + while (++iterIndex < iterLength) { + var data = iteratees[iterIndex], + iteratee = data.iteratee, + type = data.type, + computed = iteratee(value); + + if (type == LAZY_MAP_FLAG) { + value = computed; + } else if (!computed) { + if (type == LAZY_FILTER_FLAG) { + continue outer; + } else { + break outer; + } + } + } + result[resIndex++] = value; + } + return result; + } - /** - * A specialized version of `baseMerge` for arrays and objects which performs - * deep merges and tracks traversed objects enabling objects with circular - * references to be merged. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {string} key The key of the value to merge. - * @param {Function} mergeFunc The function to merge values. - * @param {Function} [customizer] The function to customize merged values. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates values with source counterparts. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) { - var length = stackA.length, - srcValue = source[key]; - - while (length--) { - if (stackA[length] == srcValue) { - object[key] = stackB[length]; - return; - } - } - var value = object[key], - result = customizer ? customizer(value, srcValue, key, object, source) : undefined, - isCommon = result === undefined; + /*------------------------------------------------------------------------*/ + + /** + * Creates a cache object to store key/value pairs. + * + * @private + * @static + * @name Cache + * @memberOf _.memoize + */ + function MapCache() { + this.__data__ = {}; + } - if (isCommon) { - result = srcValue; - if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) { - result = isArray(value) - ? value - : (isArrayLike(value) ? arrayCopy(value) : []); - } - else if (isPlainObject(srcValue) || isArguments(srcValue)) { - result = isArguments(value) - ? toPlainObject(value) - : (isPlainObject(value) ? value : {}); - } - else { - isCommon = false; - } - } - // Add the source value to the stack of traversed objects and associate - // it with its merged value. - stackA.push(srcValue); - stackB.push(result); - - if (isCommon) { - // Recursively merge objects and arrays (susceptible to call stack limits). - object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB); - } else if (result === result ? (result !== value) : (value === value)) { - object[key] = result; - } - } + /** + * Removes `key` and its value from the cache. + * + * @private + * @name delete + * @memberOf _.memoize.Cache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`. + */ + function mapDelete(key) { + return this.has(key) && delete this.__data__[key]; + } - /** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new function. - */ - function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; - } + /** + * Gets the cached value for `key`. + * + * @private + * @name get + * @memberOf _.memoize.Cache + * @param {string} key The key of the value to get. + * @returns {*} Returns the cached value. + */ + function mapGet(key) { + return key == '__proto__' ? undefined : this.__data__[key]; + } - /** - * A specialized version of `baseProperty` which supports deep paths. - * - * @private - * @param {Array|string} path The path of the property to get. - * @returns {Function} Returns the new function. - */ - function basePropertyDeep(path) { - var pathKey = (path + ''); - path = toPath(path); - return function(object) { - return baseGet(object, path, pathKey); - }; - } + /** + * Checks if a cached value for `key` exists. + * + * @private + * @name has + * @memberOf _.memoize.Cache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function mapHas(key) { + return key != '__proto__' && hasOwnProperty.call(this.__data__, key); + } - /** - * The base implementation of `_.pullAt` without support for individual - * index arguments and capturing the removed elements. - * - * @private - * @param {Array} array The array to modify. - * @param {number[]} indexes The indexes of elements to remove. - * @returns {Array} Returns `array`. - */ - function basePullAt(array, indexes) { - var length = array ? indexes.length : 0; - while (length--) { - var index = indexes[length]; - if (index != previous && isIndex(index)) { - var previous = index; - splice.call(array, index, 1); - } - } - return array; - } + /** + * Sets `value` to `key` of the cache. + * + * @private + * @name set + * @memberOf _.memoize.Cache + * @param {string} key The key of the value to cache. + * @param {*} value The value to cache. + * @returns {Object} Returns the cache object. + */ + function mapSet(key, value) { + if (key != '__proto__') { + this.__data__[key] = value; + } + return this; + } - /** - * The base implementation of `_.random` without support for argument juggling - * and returning floating-point numbers. - * - * @private - * @param {number} min The minimum possible value. - * @param {number} max The maximum possible value. - * @returns {number} Returns the random number. - */ - function baseRandom(min, max) { - return min + nativeFloor(nativeRandom() * (max - min + 1)); - } + /*------------------------------------------------------------------------*/ + + /** + * + * Creates a cache object to store unique values. + * + * @private + * @param {Array} [values] The values to cache. + */ + function SetCache(values) { + var length = values ? values.length : 0; + + this.data = { hash: nativeCreate(null), set: new Set() }; + while (length--) { + this.push(values[length]); + } + } - /** - * The base implementation of `_.reduce` and `_.reduceRight` without support - * for callback shorthands and `this` binding, which iterates over `collection` - * using the provided `eachFunc`. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} accumulator The initial value. - * @param {boolean} initFromCollection Specify using the first or last element - * of `collection` as the initial value. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the accumulated value. - */ - function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) { - eachFunc(collection, function(value, index, collection) { - accumulator = initFromCollection - ? (initFromCollection = false, value) - : iteratee(accumulator, value, index, collection); - }); - return accumulator; - } + /** + * Checks if `value` is in `cache` mimicking the return signature of + * `_.indexOf` by returning `0` if the value is found, else `-1`. + * + * @private + * @param {Object} cache The cache to search. + * @param {*} value The value to search for. + * @returns {number} Returns `0` if `value` is found, else `-1`. + */ + function cacheIndexOf(cache, value) { + var data = cache.data, + result = typeof value == 'string' || isObject(value) ? data.set.has(value) : data.hash[value]; + + return result ? 0 : -1; + } - /** - * The base implementation of `setData` without support for hot loop detection. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var baseSetData = !metaMap ? identity : function(func, data) { - metaMap.set(func, data); - return func; - }; - - /** - * The base implementation of `_.slice` without an iteratee call guard. - * - * @private - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function baseSlice(array, start, end) { - var index = -1, - length = array.length; - - start = start == null ? 0 : (+start || 0); - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = (end === undefined || end > length) ? length : (+end || 0); - if (end < 0) { - end += length; - } - length = start > end ? 0 : ((end - start) >>> 0); - start >>>= 0; + /** + * Adds `value` to the cache. + * + * @private + * @name push + * @memberOf SetCache + * @param {*} value The value to cache. + */ + function cachePush(value) { + var data = this.data; + if (typeof value == 'string' || isObject(value)) { + data.set.add(value); + } else { + data.hash[value] = true; + } + } - var result = Array(length); - while (++index < length) { - result[index] = array[index + start]; - } - return result; - } + /*------------------------------------------------------------------------*/ + + /** + * Creates a new array joining `array` with `other`. + * + * @private + * @param {Array} array The array to join. + * @param {Array} other The other array to join. + * @returns {Array} Returns the new concatenated array. + */ + function arrayConcat(array, other) { + var index = -1, + length = array.length, + othIndex = -1, + othLength = other.length, + result = Array(length + othLength); + + while (++index < length) { + result[index] = array[index]; + } + while (++othIndex < othLength) { + result[index++] = other[othIndex]; + } + return result; + } - /** - * The base implementation of `_.some` without support for callback shorthands - * and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function baseSome(collection, predicate) { - var result; - - baseEach(collection, function(value, index, collection) { - result = predicate(value, index, collection); - return !result; - }); - return !!result; - } + /** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ + function arrayCopy(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; + } - /** - * The base implementation of `_.sortBy` which uses `comparer` to define - * the sort order of `array` and replaces criteria objects with their - * corresponding values. - * - * @private - * @param {Array} array The array to sort. - * @param {Function} comparer The function to define sort order. - * @returns {Array} Returns `array`. - */ - function baseSortBy(array, comparer) { - var length = array.length; - - array.sort(comparer); - while (length--) { - array[length] = array[length].value; - } - return array; - } + /** + * A specialized version of `_.forEach` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEach(array, iteratee) { + var index = -1, + length = array.length; + + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; + } - /** - * The base implementation of `_.sortByOrder` without param guards. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {boolean[]} orders The sort orders of `iteratees`. - * @returns {Array} Returns the new sorted array. - */ - function baseSortByOrder(collection, iteratees, orders) { - var callback = getCallback(), - index = -1; - - iteratees = arrayMap(iteratees, function(iteratee) { return callback(iteratee); }); - - var result = baseMap(collection, function(value) { - var criteria = arrayMap(iteratees, function(iteratee) { return iteratee(value); }); - return { 'criteria': criteria, 'index': ++index, 'value': value }; - }); - - return baseSortBy(result, function(object, other) { - return compareMultiple(object, other, orders); - }); - } + /** + * A specialized version of `_.forEachRight` for arrays without support for + * callback shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEachRight(array, iteratee) { + var length = array.length; + + while (length--) { + if (iteratee(array[length], length, array) === false) { + break; + } + } + return array; + } - /** - * The base implementation of `_.sum` without support for callback shorthands - * and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the sum. - */ - function baseSum(collection, iteratee) { - var result = 0; - baseEach(collection, function(value, index, collection) { - result += +iteratee(value, index, collection) || 0; - }); - return result; - } + /** + * A specialized version of `_.every` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + */ + function arrayEvery(array, predicate) { + var index = -1, + length = array.length; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } + return true; + } - /** - * The base implementation of `_.uniq` without support for callback shorthands - * and `this` binding. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The function invoked per iteration. - * @returns {Array} Returns the new duplicate-value-free array. - */ - function baseUniq(array, iteratee) { - var index = -1, - indexOf = getIndexOf(), - length = array.length, - isCommon = indexOf == baseIndexOf, - isLarge = isCommon && length >= LARGE_ARRAY_SIZE, - seen = isLarge ? createCache() : null, - result = []; - - if (seen) { - indexOf = cacheIndexOf; - isCommon = false; - } else { - isLarge = false; - seen = iteratee ? [] : result; - } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value, index, array) : value; + /** + * A specialized version of `baseExtremum` for arrays which invokes `iteratee` + * with one argument: (value). + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} comparator The function used to compare values. + * @param {*} exValue The initial extremum value. + * @returns {*} Returns the extremum value. + */ + function arrayExtremum(array, iteratee, comparator, exValue) { + var index = -1, + length = array.length, + computed = exValue, + result = computed; + + while (++index < length) { + var value = array[index], + current = +iteratee(value); + + if (comparator(current, computed)) { + computed = current; + result = value; + } + } + return result; + } + + /** + * A specialized version of `_.filter` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function arrayFilter(array, predicate) { + var index = -1, + length = array.length, + resIndex = -1, + result = []; + + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[++resIndex] = value; + } + } + return result; + } + + /** + * A specialized version of `_.map` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function arrayMap(array, iteratee) { + var index = -1, + length = array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; + } - if (isCommon && value === value) { - var seenIndex = seen.length; - while (seenIndex--) { - if (seen[seenIndex] === computed) { - continue outer; - } - } - if (iteratee) { - seen.push(computed); - } - result.push(value); - } - else if (indexOf(seen, computed, 0) < 0) { - if (iteratee || isLarge) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } + /** + * Appends the elements of `values` to `array`. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to append. + * @returns {Array} Returns `array`. + */ + function arrayPush(array, values) { + var index = -1, + length = values.length, + offset = array.length; + + while (++index < length) { + array[offset + index] = values[index]; + } + return array; + } - /** - * The base implementation of `_.values` and `_.valuesIn` which creates an - * array of `object` property values corresponding to the property names - * of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the array of property values. - */ - function baseValues(object, props) { - var index = -1, - length = props.length, - result = Array(length); - - while (++index < length) { - result[index] = object[props[index]]; - } - return result; - } + /** + * A specialized version of `_.reduce` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initFromArray] Specify using the first element of `array` + * as the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduce(array, iteratee, accumulator, initFromArray) { + var index = -1, + length = array.length; + + if (initFromArray && length) { + accumulator = array[++index]; + } + while (++index < length) { + accumulator = iteratee(accumulator, array[index], index, array); + } + return accumulator; + } - /** - * The base implementation of `_.dropRightWhile`, `_.dropWhile`, `_.takeRightWhile`, - * and `_.takeWhile` without support for callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to query. - * @param {Function} predicate The function invoked per iteration. - * @param {boolean} [isDrop] Specify dropping elements instead of taking them. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the slice of `array`. - */ - function baseWhile(array, predicate, isDrop, fromRight) { - var length = array.length, - index = fromRight ? length : -1; - - while ((fromRight ? index-- : ++index < length) && predicate(array[index], index, array)) {} - return isDrop - ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) - : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); - } + /** + * A specialized version of `_.reduceRight` for arrays without support for + * callback shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initFromArray] Specify using the last element of `array` + * as the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduceRight(array, iteratee, accumulator, initFromArray) { + var length = array.length; + if (initFromArray && length) { + accumulator = array[--length]; + } + while (length--) { + accumulator = iteratee(accumulator, array[length], length, array); + } + return accumulator; + } - /** - * The base implementation of `wrapperValue` which returns the result of - * performing a sequence of actions on the unwrapped `value`, where each - * successive action is supplied the return value of the previous. - * - * @private - * @param {*} value The unwrapped value. - * @param {Array} actions Actions to peform to resolve the unwrapped value. - * @returns {*} Returns the resolved value. - */ - function baseWrapperValue(value, actions) { - var result = value; - if (result instanceof LazyWrapper) { - result = result.value(); - } - var index = -1, - length = actions.length; + /** + * A specialized version of `_.some` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function arraySome(array, predicate) { + var index = -1, + length = array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; + } - while (++index < length) { - var action = actions[index]; - result = action.func.apply(action.thisArg, arrayPush([result], action.args)); - } - return result; - } + /** + * A specialized version of `_.sum` for arrays without support for callback + * shorthands and `this` binding.. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the sum. + */ + function arraySum(array, iteratee) { + var length = array.length, + result = 0; + + while (length--) { + result += +iteratee(array[length]) || 0; + } + return result; + } - /** - * Performs a binary search of `array` to determine the index at which `value` - * should be inserted into `array` in order to maintain its sort order. - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function binaryIndex(array, value, retHighest) { - var low = 0, - high = array ? array.length : low; - - if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { - while (low < high) { - var mid = (low + high) >>> 1, - computed = array[mid]; - - if ((retHighest ? (computed <= value) : (computed < value)) && computed !== null) { - low = mid + 1; - } else { - high = mid; - } - } - return high; - } - return binaryIndexBy(array, value, identity, retHighest); - } + /** + * Used by `_.defaults` to customize its `_.assign` use. + * + * @private + * @param {*} objectValue The destination object property value. + * @param {*} sourceValue The source object property value. + * @returns {*} Returns the value to assign to the destination object. + */ + function assignDefaults(objectValue, sourceValue) { + return objectValue === undefined ? sourceValue : objectValue; + } - /** - * This function is like `binaryIndex` except that it invokes `iteratee` for - * `value` and each element of `array` to compute their sort ranking. The - * iteratee is invoked with one argument; (value). - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} iteratee The function invoked per iteration. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function binaryIndexBy(array, value, iteratee, retHighest) { - value = iteratee(value); - - var low = 0, - high = array ? array.length : 0, - valIsNaN = value !== value, - valIsNull = value === null, - valIsUndef = value === undefined; - - while (low < high) { - var mid = nativeFloor((low + high) / 2), - computed = iteratee(array[mid]), - isDef = computed !== undefined, - isReflexive = computed === computed; - - if (valIsNaN) { - var setLow = isReflexive || retHighest; - } else if (valIsNull) { - setLow = isReflexive && isDef && (retHighest || computed != null); - } else if (valIsUndef) { - setLow = isReflexive && (retHighest || isDef); - } else if (computed == null) { - setLow = false; - } else { - setLow = retHighest ? (computed <= value) : (computed < value); - } - if (setLow) { - low = mid + 1; - } else { - high = mid; - } - } - return nativeMin(high, MAX_ARRAY_INDEX); - } + /** + * Used by `_.template` to customize its `_.assign` use. + * + * **Note:** This function is like `assignDefaults` except that it ignores + * inherited property values when checking if a property is `undefined`. + * + * @private + * @param {*} objectValue The destination object property value. + * @param {*} sourceValue The source object property value. + * @param {string} key The key associated with the object and source values. + * @param {Object} object The destination object. + * @returns {*} Returns the value to assign to the destination object. + */ + function assignOwnDefaults(objectValue, sourceValue, key, object) { + return objectValue === undefined || !hasOwnProperty.call(object, key) ? sourceValue : objectValue; + } - /** - * A specialized version of `baseCallback` which only supports `this` binding - * and specifying the number of arguments to provide to `func`. - * - * @private - * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {number} [argCount] The number of arguments to provide to `func`. - * @returns {Function} Returns the callback. - */ - function bindCallback(func, thisArg, argCount) { - if (typeof func != 'function') { - return identity; - } - if (thisArg === undefined) { - return func; - } - switch (argCount) { - case 1: return function(value) { - return func.call(thisArg, value); - }; - case 3: return function(value, index, collection) { - return func.call(thisArg, value, index, collection); - }; - case 4: return function(accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); - }; - case 5: return function(value, other, key, object, source) { - return func.call(thisArg, value, other, key, object, source); - }; - } - return function() { - return func.apply(thisArg, arguments); - }; - } + /** + * A specialized version of `_.assign` for customizing assigned values without + * support for argument juggling, multiple sources, and `this` binding `customizer` + * functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {Function} customizer The function to customize assigned values. + * @returns {Object} Returns `object`. + */ + function assignWith(object, source, customizer) { + var index = -1, + props = keys(source), + length = props.length; + + while (++index < length) { + var key = props[index], + value = object[key], + result = customizer(value, source[key], key, object, source); + + if ( + (result === result ? result !== value : value === value) || + (value === undefined && !(key in object)) + ) { + object[key] = result; + } + } + return object; + } - /** - * Creates a clone of the given array buffer. - * - * @private - * @param {ArrayBuffer} buffer The array buffer to clone. - * @returns {ArrayBuffer} Returns the cloned array buffer. - */ - function bufferClone(buffer) { - var result = new ArrayBuffer(buffer.byteLength), - view = new Uint8Array(result); - - view.set(new Uint8Array(buffer)); - return result; - } + /** + * The base implementation of `_.assign` without support for argument juggling, + * multiple sources, and `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssign(object, source) { + return source == null ? object : baseCopy(source, keys(source), object); + } - /** - * Creates an array that is the composition of partially applied arguments, - * placeholders, and provided arguments into a single array of arguments. - * - * @private - * @param {Array|Object} args The provided arguments. - * @param {Array} partials The arguments to prepend to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgs(args, partials, holders) { - var holdersLength = holders.length, - argsIndex = -1, - argsLength = nativeMax(args.length - holdersLength, 0), - leftIndex = -1, - leftLength = partials.length, - result = Array(leftLength + argsLength); - - while (++leftIndex < leftLength) { - result[leftIndex] = partials[leftIndex]; - } - while (++argsIndex < holdersLength) { - result[holders[argsIndex]] = args[argsIndex]; - } - while (argsLength--) { - result[leftIndex++] = args[argsIndex++]; - } - return result; - } + /** + * The base implementation of `_.at` without support for string collections + * and individual key arguments. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {number[]|string[]} props The property names or indexes of elements to pick. + * @returns {Array} Returns the new array of picked elements. + */ + function baseAt(collection, props) { + var index = -1, + isNil = collection == null, + isArr = !isNil && isArrayLike(collection), + length = isArr ? collection.length : 0, + propsLength = props.length, + result = Array(propsLength); + + while (++index < propsLength) { + var key = props[index]; + if (isArr) { + result[index] = isIndex(key, length) ? collection[key] : undefined; + } else { + result[index] = isNil ? undefined : collection[key]; + } + } + return result; + } - /** - * This function is like `composeArgs` except that the arguments composition - * is tailored for `_.partialRight`. - * - * @private - * @param {Array|Object} args The provided arguments. - * @param {Array} partials The arguments to append to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgsRight(args, partials, holders) { - var holdersIndex = -1, - holdersLength = holders.length, - argsIndex = -1, - argsLength = nativeMax(args.length - holdersLength, 0), - rightIndex = -1, - rightLength = partials.length, - result = Array(argsLength + rightLength); - - while (++argsIndex < argsLength) { - result[argsIndex] = args[argsIndex]; - } - var offset = argsIndex; - while (++rightIndex < rightLength) { - result[offset + rightIndex] = partials[rightIndex]; - } - while (++holdersIndex < holdersLength) { - result[offset + holders[holdersIndex]] = args[argsIndex++]; - } - return result; - } + /** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property names to copy. + * @param {Object} [object={}] The object to copy properties to. + * @returns {Object} Returns `object`. + */ + function baseCopy(source, props, object) { + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + object[key] = source[key]; + } + return object; + } - /** - * Creates a `_.countBy`, `_.groupBy`, `_.indexBy`, or `_.partition` function. - * - * @private - * @param {Function} setter The function to set keys and values of the accumulator object. - * @param {Function} [initializer] The function to initialize the accumulator object. - * @returns {Function} Returns the new aggregator function. - */ - function createAggregator(setter, initializer) { - return function(collection, iteratee, thisArg) { - var result = initializer ? initializer() : {}; - iteratee = getCallback(iteratee, thisArg, 3); - - if (isArray(collection)) { - var index = -1, - length = collection.length; - - while (++index < length) { - var value = collection[index]; - setter(result, value, iteratee(value, index, collection), collection); - } - } else { - baseEach(collection, function(value, key, collection) { - setter(result, value, iteratee(value, key, collection), collection); - }); - } - return result; - }; - } + /** + * The base implementation of `_.callback` which supports specifying the + * number of arguments to provide to `func`. + * + * @private + * @param {*} [func=_.identity] The value to convert to a callback. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the callback. + */ + function baseCallback(func, thisArg, argCount) { + var type = typeof func; + if (type == 'function') { + return thisArg === undefined ? func : bindCallback(func, thisArg, argCount); + } + if (func == null) { + return identity; + } + if (type == 'object') { + return baseMatches(func); + } + return thisArg === undefined ? property(func) : baseMatchesProperty(func, thisArg); + } - /** - * Creates a `_.assign`, `_.defaults`, or `_.merge` function. - * - * @private - * @param {Function} assigner The function to assign values. - * @returns {Function} Returns the new assigner function. - */ - function createAssigner(assigner) { - return restParam(function(object, sources) { - var index = -1, - length = object == null ? 0 : sources.length, - customizer = length > 2 ? sources[length - 2] : undefined, - guard = length > 2 ? sources[2] : undefined, - thisArg = length > 1 ? sources[length - 1] : undefined; - - if (typeof customizer == 'function') { - customizer = bindCallback(customizer, thisArg, 5); - length -= 2; - } else { - customizer = typeof thisArg == 'function' ? thisArg : undefined; - length -= (customizer ? 1 : 0); - } - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - customizer = length < 3 ? undefined : customizer; - length = 1; - } - while (++index < length) { - var source = sources[index]; - if (source) { - assigner(object, source, customizer); - } - } - return object; - }); - } + /** + * The base implementation of `_.clone` without support for argument juggling + * and `this` binding `customizer` functions. + * + * @private + * @param {*} value The value to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @param {Function} [customizer] The function to customize cloning values. + * @param {string} [key] The key of `value`. + * @param {Object} [object] The object `value` belongs to. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates clones with source counterparts. + * @returns {*} Returns the cloned value. + */ + function baseClone(value, isDeep, customizer, key, object, stackA, stackB) { + var result; + if (customizer) { + result = object ? customizer(value, key, object) : customizer(value); + } + if (result !== undefined) { + return result; + } + if (!isObject(value)) { + return value; + } + var isArr = isArray(value); + if (isArr) { + result = initCloneArray(value); + if (!isDeep) { + return arrayCopy(value, result); + } + } else { + var tag = objToString.call(value), + isFunc = tag == funcTag; + + if (tag == objectTag || tag == argsTag || (isFunc && !object)) { + result = initCloneObject(isFunc ? {} : value); + if (!isDeep) { + return baseAssign(result, value); + } + } else { + return cloneableTags[tag] ? initCloneByTag(value, tag, isDeep) : object ? value : {}; + } + } + // Check for circular references and return its corresponding clone. + stackA || (stackA = []); + stackB || (stackB = []); + + var length = stackA.length; + while (length--) { + if (stackA[length] == value) { + return stackB[length]; + } + } + // Add the source value to the stack of traversed objects and associate it with its clone. + stackA.push(value); + stackB.push(result); + + // Recursively populate clone (susceptible to call stack limits). + (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) { + result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB); + }); + return result; + } - /** - * Creates a `baseEach` or `baseEachRight` function. - * - * @private - * @param {Function} eachFunc The function to iterate over a collection. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseEach(eachFunc, fromRight) { - return function(collection, iteratee) { - var length = collection ? getLength(collection) : 0; - if (!isLength(length)) { - return eachFunc(collection, iteratee); - } - var index = fromRight ? length : -1, - iterable = toObject(collection); - - while ((fromRight ? index-- : ++index < length)) { - if (iteratee(iterable[index], index, iterable) === false) { - break; - } - } - return collection; - }; - } + /** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} prototype The object to inherit from. + * @returns {Object} Returns the new object. + */ + var baseCreate = (function() { + function object() {} + return function(prototype) { + if (isObject(prototype)) { + object.prototype = prototype; + var result = new object(); + object.prototype = undefined; + } + return result || {}; + }; + })(); + + /** + * The base implementation of `_.delay` and `_.defer` which accepts an index + * of where to slice the arguments to provide to `func`. + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {Object} args The arguments provide to `func`. + * @returns {number} Returns the timer id. + */ + function baseDelay(func, wait, args) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return setTimeout(function() { + func.apply(undefined, args); + }, wait); + } - /** - * Creates a base function for `_.forIn` or `_.forInRight`. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseFor(fromRight) { - return function(object, iteratee, keysFunc) { - var iterable = toObject(object), - props = keysFunc(object), - length = props.length, - index = fromRight ? length : -1; - - while ((fromRight ? index-- : ++index < length)) { - var key = props[index]; - if (iteratee(iterable[key], key, iterable) === false) { - break; - } - } - return object; - }; - } + /** + * The base implementation of `_.difference` which accepts a single array + * of values to exclude. + * + * @private + * @param {Array} array The array to inspect. + * @param {Array} values The values to exclude. + * @returns {Array} Returns the new array of filtered values. + */ + function baseDifference(array, values) { + var length = array ? array.length : 0, + result = []; + + if (!length) { + return result; + } + var index = -1, + indexOf = getIndexOf(), + isCommon = indexOf == baseIndexOf, + cache = isCommon && values.length >= LARGE_ARRAY_SIZE ? createCache(values) : null, + valuesLength = values.length; + + if (cache) { + indexOf = cacheIndexOf; + isCommon = false; + values = cache; + } + outer: while (++index < length) { + var value = array[index]; + + if (isCommon && value === value) { + var valuesIndex = valuesLength; + while (valuesIndex--) { + if (values[valuesIndex] === value) { + continue outer; + } + } + result.push(value); + } else if (indexOf(values, value, 0) < 0) { + result.push(value); + } + } + return result; + } - /** - * Creates a function that wraps `func` and invokes it with the `this` - * binding of `thisArg`. - * - * @private - * @param {Function} func The function to bind. - * @param {*} [thisArg] The `this` binding of `func`. - * @returns {Function} Returns the new bound function. - */ - function createBindWrapper(func, thisArg) { - var Ctor = createCtorWrapper(func); - - function wrapper() { - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return fn.apply(thisArg, arguments); - } - return wrapper; - } + /** + * The base implementation of `_.forEach` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object|string} Returns `collection`. + */ + var baseEach = createBaseEach(baseForOwn); + + /** + * The base implementation of `_.forEachRight` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object|string} Returns `collection`. + */ + var baseEachRight = createBaseEach(baseForOwnRight, true); + + /** + * The base implementation of `_.every` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false` + */ + function baseEvery(collection, predicate) { + var result = true; + baseEach(collection, function(value, index, collection) { + result = !!predicate(value, index, collection); + return result; + }); + return result; + } - /** - * Creates a `Set` cache object to optimize linear searches of large arrays. - * - * @private - * @param {Array} [values] The values to cache. - * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`. - */ - function createCache(values) { - return (nativeCreate && Set) ? new SetCache(values) : null; - } + /** + * Gets the extremum value of `collection` invoking `iteratee` for each value + * in `collection` to generate the criterion by which the value is ranked. + * The `iteratee` is invoked with three arguments: (value, index|key, collection). + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} comparator The function used to compare values. + * @param {*} exValue The initial extremum value. + * @returns {*} Returns the extremum value. + */ + function baseExtremum(collection, iteratee, comparator, exValue) { + var computed = exValue, + result = computed; + + baseEach(collection, function(value, index, collection) { + var current = +iteratee(value, index, collection); + if (comparator(current, computed) || (current === exValue && current === result)) { + computed = current; + result = value; + } + }); + return result; + } - /** - * Creates a function that produces compound words out of the words in a - * given string. - * - * @private - * @param {Function} callback The function to combine each word. - * @returns {Function} Returns the new compounder function. - */ - function createCompounder(callback) { - return function(string) { - var index = -1, - array = words(deburr(string)), - length = array.length, - result = ''; - - while (++index < length) { - result = callback(result, array[index], index); - } - return result; - }; - } + /** + * The base implementation of `_.fill` without an iteratee call guard. + * + * @private + * @param {Array} array The array to fill. + * @param {*} value The value to fill `array` with. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns `array`. + */ + function baseFill(array, value, start, end) { + var length = array.length; + + start = start == null ? 0 : +start || 0; + if (start < 0) { + start = -start > length ? 0 : length + start; + } + end = end === undefined || end > length ? length : +end || 0; + if (end < 0) { + end += length; + } + length = start > end ? 0 : end >>> 0; + start >>>= 0; + + while (start < length) { + array[start++] = value; + } + return array; + } - /** - * Creates a function that produces an instance of `Ctor` regardless of - * whether it was invoked as part of a `new` expression or by `call` or `apply`. - * - * @private - * @param {Function} Ctor The constructor to wrap. - * @returns {Function} Returns the new wrapped function. - */ - function createCtorWrapper(Ctor) { - return function() { - // Use a `switch` statement to work with class constructors. - // See http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist - // for more details. - var args = arguments; - switch (args.length) { - case 0: return new Ctor; - case 1: return new Ctor(args[0]); - case 2: return new Ctor(args[0], args[1]); - case 3: return new Ctor(args[0], args[1], args[2]); - case 4: return new Ctor(args[0], args[1], args[2], args[3]); - case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); - case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); - case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - } - var thisBinding = baseCreate(Ctor.prototype), - result = Ctor.apply(thisBinding, args); - - // Mimic the constructor's `return` behavior. - // See https://es5.github.io/#x13.2.2 for more details. - return isObject(result) ? result : thisBinding; - }; - } + /** + * The base implementation of `_.filter` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function baseFilter(collection, predicate) { + var result = []; + baseEach(collection, function(value, index, collection) { + if (predicate(value, index, collection)) { + result.push(value); + } + }); + return result; + } - /** - * Creates a `_.curry` or `_.curryRight` function. - * - * @private - * @param {boolean} flag The curry bit flag. - * @returns {Function} Returns the new curry function. - */ - function createCurry(flag) { - function curryFunc(func, arity, guard) { - if (guard && isIterateeCall(func, arity, guard)) { - arity = undefined; - } - var result = createWrapper(func, flag, undefined, undefined, undefined, undefined, undefined, arity); - result.placeholder = curryFunc.placeholder; - return result; - } - return curryFunc; - } + /** + * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`, + * without support for callback shorthands and `this` binding, which iterates + * over `collection` using the provided `eachFunc`. + * + * @private + * @param {Array|Object|string} collection The collection to search. + * @param {Function} predicate The function invoked per iteration. + * @param {Function} eachFunc The function to iterate over `collection`. + * @param {boolean} [retKey] Specify returning the key of the found element + * instead of the element itself. + * @returns {*} Returns the found element or its key, else `undefined`. + */ + function baseFind(collection, predicate, eachFunc, retKey) { + var result; + eachFunc(collection, function(value, key, collection) { + if (predicate(value, key, collection)) { + result = retKey ? key : value; + return false; + } + }); + return result; + } - /** - * Creates a `_.defaults` or `_.defaultsDeep` function. - * - * @private - * @param {Function} assigner The function to assign values. - * @param {Function} customizer The function to customize assigned values. - * @returns {Function} Returns the new defaults function. - */ - function createDefaults(assigner, customizer) { - return restParam(function(args) { - var object = args[0]; - if (object == null) { - return object; - } - args.push(customizer); - return assigner.apply(undefined, args); - }); - } + /** + * The base implementation of `_.flatten` with added support for restricting + * flattening and specifying the start index. + * + * @private + * @param {Array} array The array to flatten. + * @param {boolean} [isDeep] Specify a deep flatten. + * @param {boolean} [isStrict] Restrict flattening to arrays-like objects. + * @param {Array} [result=[]] The initial result value. + * @returns {Array} Returns the new flattened array. + */ + function baseFlatten(array, isDeep, isStrict, result) { + result || (result = []); + + var index = -1, + length = array.length; + + while (++index < length) { + var value = array[index]; + if (isObjectLike(value) && isArrayLike(value) && (isStrict || isArray(value) || isArguments(value))) { + if (isDeep) { + // Recursively flatten arrays (susceptible to call stack limits). + baseFlatten(value, isDeep, isStrict, result); + } else { + arrayPush(result, value); + } + } else if (!isStrict) { + result[result.length] = value; + } + } + return result; + } - /** - * Creates a `_.max` or `_.min` function. - * - * @private - * @param {Function} comparator The function used to compare values. - * @param {*} exValue The initial extremum value. - * @returns {Function} Returns the new extremum function. - */ - function createExtremum(comparator, exValue) { - return function(collection, iteratee, thisArg) { - if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { - iteratee = undefined; - } - iteratee = getCallback(iteratee, thisArg, 3); - if (iteratee.length == 1) { - collection = isArray(collection) ? collection : toIterable(collection); - var result = arrayExtremum(collection, iteratee, comparator, exValue); - if (!(collection.length && result === exValue)) { - return result; - } - } - return baseExtremum(collection, iteratee, comparator, exValue); - }; - } + /** + * The base implementation of `baseForIn` and `baseForOwn` which iterates + * over `object` properties returned by `keysFunc` invoking `iteratee` for + * each property. Iteratee functions may exit iteration early by explicitly + * returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseFor = createBaseFor(); + + /** + * This function is like `baseFor` except that it iterates over properties + * in the opposite order. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseForRight = createBaseFor(true); + + /** + * The base implementation of `_.forIn` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForIn(object, iteratee) { + return baseFor(object, iteratee, keysIn); + } - /** - * Creates a `_.find` or `_.findLast` function. - * - * @private - * @param {Function} eachFunc The function to iterate over a collection. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new find function. - */ - function createFind(eachFunc, fromRight) { - return function(collection, predicate, thisArg) { - predicate = getCallback(predicate, thisArg, 3); - if (isArray(collection)) { - var index = baseFindIndex(collection, predicate, fromRight); - return index > -1 ? collection[index] : undefined; - } - return baseFind(collection, predicate, eachFunc); - }; - } + /** + * The base implementation of `_.forOwn` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwn(object, iteratee) { + return baseFor(object, iteratee, keys); + } - /** - * Creates a `_.findIndex` or `_.findLastIndex` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new find function. - */ - function createFindIndex(fromRight) { - return function(array, predicate, thisArg) { - if (!(array && array.length)) { - return -1; - } - predicate = getCallback(predicate, thisArg, 3); - return baseFindIndex(array, predicate, fromRight); - }; - } + /** + * The base implementation of `_.forOwnRight` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwnRight(object, iteratee) { + return baseForRight(object, iteratee, keys); + } - /** - * Creates a `_.findKey` or `_.findLastKey` function. - * - * @private - * @param {Function} objectFunc The function to iterate over an object. - * @returns {Function} Returns the new find function. - */ - function createFindKey(objectFunc) { - return function(object, predicate, thisArg) { - predicate = getCallback(predicate, thisArg, 3); - return baseFind(object, predicate, objectFunc, true); - }; - } + /** + * The base implementation of `_.functions` which creates an array of + * `object` function property names filtered from those provided. + * + * @private + * @param {Object} object The object to inspect. + * @param {Array} props The property names to filter. + * @returns {Array} Returns the new array of filtered property names. + */ + function baseFunctions(object, props) { + var index = -1, + length = props.length, + resIndex = -1, + result = []; + + while (++index < length) { + var key = props[index]; + if (isFunction(object[key])) { + result[++resIndex] = key; + } + } + return result; + } - /** - * Creates a `_.flow` or `_.flowRight` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new flow function. - */ - function createFlow(fromRight) { - return function() { - var wrapper, - length = arguments.length, - index = fromRight ? length : -1, - leftIndex = 0, - funcs = Array(length); - - while ((fromRight ? index-- : ++index < length)) { - var func = funcs[leftIndex++] = arguments[index]; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (!wrapper && LodashWrapper.prototype.thru && getFuncName(func) == 'wrapper') { - wrapper = new LodashWrapper([], true); - } - } - index = wrapper ? -1 : length; - while (++index < length) { - func = funcs[index]; - - var funcName = getFuncName(func), - data = funcName == 'wrapper' ? getData(func) : undefined; - - if (data && isLaziable(data[0]) && data[1] == (ARY_FLAG | CURRY_FLAG | PARTIAL_FLAG | REARG_FLAG) && !data[4].length && data[9] == 1) { - wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); - } else { - wrapper = (func.length == 1 && isLaziable(func)) ? wrapper[funcName]() : wrapper.thru(func); - } - } - return function() { - var args = arguments, - value = args[0]; + /** + * The base implementation of `get` without support for string paths + * and default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array} path The path of the property to get. + * @param {string} [pathKey] The key representation of path. + * @returns {*} Returns the resolved value. + */ + function baseGet(object, path, pathKey) { + if (object == null) { + return; + } + if (pathKey !== undefined && pathKey in toObject(object)) { + path = [pathKey]; + } + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[path[index++]]; + } + return index && index == length ? object : undefined; + } - if (wrapper && args.length == 1 && isArray(value) && value.length >= LARGE_ARRAY_SIZE) { - return wrapper.plant(value).value(); - } - var index = 0, - result = length ? funcs[index].apply(this, args) : value; + /** + * The base implementation of `_.isEqual` without support for `this` binding + * `customizer` functions. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparing values. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ + function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) { + if (value === other) { + return true; + } + if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB); + } - while (++index < length) { - result = funcs[index].call(this, result); - } - return result; - }; - }; - } + /** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing objects. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA=[]] Tracks traversed `value` objects. + * @param {Array} [stackB=[]] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = arrayTag, + othTag = arrayTag; + + if (!objIsArr) { + objTag = objToString.call(object); + if (objTag == argsTag) { + objTag = objectTag; + } else if (objTag != objectTag) { + objIsArr = isTypedArray(object); + } + } + if (!othIsArr) { + othTag = objToString.call(other); + if (othTag == argsTag) { + othTag = objectTag; + } else if (othTag != objectTag) { + othIsArr = isTypedArray(other); + } + } + var objIsObj = objTag == objectTag, + othIsObj = othTag == objectTag, + isSameTag = objTag == othTag; + + if (isSameTag && !(objIsArr || objIsObj)) { + return equalByTag(object, other, objTag); + } + if (!isLoose) { + var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), + othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); + + if (objIsWrapped || othIsWrapped) { + return equalFunc( + objIsWrapped ? object.value() : object, + othIsWrapped ? other.value() : other, + customizer, + isLoose, + stackA, + stackB, + ); + } + } + if (!isSameTag) { + return false; + } + // Assume cyclic values are equal. + // For more information on detecting circular references see https://es5.github.io/#JO. + stackA || (stackA = []); + stackB || (stackB = []); + + var length = stackA.length; + while (length--) { + if (stackA[length] == object) { + return stackB[length] == other; + } + } + // Add `object` and `other` to the stack of traversed objects. + stackA.push(object); + stackB.push(other); + + var result = (objIsArr ? equalArrays : equalObjects)( + object, + other, + equalFunc, + customizer, + isLoose, + stackA, + stackB, + ); + + stackA.pop(); + stackB.pop(); - /** - * Creates a function for `_.forEach` or `_.forEachRight`. - * - * @private - * @param {Function} arrayFunc The function to iterate over an array. - * @param {Function} eachFunc The function to iterate over a collection. - * @returns {Function} Returns the new each function. - */ - function createForEach(arrayFunc, eachFunc) { - return function(collection, iteratee, thisArg) { - return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) - ? arrayFunc(collection, iteratee) - : eachFunc(collection, bindCallback(iteratee, thisArg, 3)); - }; - } + return result; + } - /** - * Creates a function for `_.forIn` or `_.forInRight`. - * - * @private - * @param {Function} objectFunc The function to iterate over an object. - * @returns {Function} Returns the new each function. - */ - function createForIn(objectFunc) { - return function(object, iteratee, thisArg) { - if (typeof iteratee != 'function' || thisArg !== undefined) { - iteratee = bindCallback(iteratee, thisArg, 3); - } - return objectFunc(object, iteratee, keysIn); - }; - } + /** + * The base implementation of `_.isMatch` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to inspect. + * @param {Array} matchData The propery names, values, and compare flags to match. + * @param {Function} [customizer] The function to customize comparing objects. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ + function baseIsMatch(object, matchData, customizer) { + var index = matchData.length, + length = index, + noCustomizer = !customizer; + + if (object == null) { + return !length; + } + object = toObject(object); + while (index--) { + var data = matchData[index]; + if (noCustomizer && data[2] ? data[1] !== object[data[0]] : !(data[0] in object)) { + return false; + } + } + while (++index < length) { + data = matchData[index]; + var key = data[0], + objValue = object[key], + srcValue = data[1]; + + if (noCustomizer && data[2]) { + if (objValue === undefined && !(key in object)) { + return false; + } + } else { + var result = customizer ? customizer(objValue, srcValue, key) : undefined; + if (!(result === undefined ? baseIsEqual(srcValue, objValue, customizer, true) : result)) { + return false; + } + } + } + return true; + } - /** - * Creates a function for `_.forOwn` or `_.forOwnRight`. - * - * @private - * @param {Function} objectFunc The function to iterate over an object. - * @returns {Function} Returns the new each function. - */ - function createForOwn(objectFunc) { - return function(object, iteratee, thisArg) { - if (typeof iteratee != 'function' || thisArg !== undefined) { - iteratee = bindCallback(iteratee, thisArg, 3); - } - return objectFunc(object, iteratee); - }; - } + /** + * The base implementation of `_.map` without support for callback shorthands + * and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function baseMap(collection, iteratee) { + var index = -1, + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value, key, collection) { + result[++index] = iteratee(value, key, collection); + }); + return result; + } - /** - * Creates a function for `_.mapKeys` or `_.mapValues`. - * - * @private - * @param {boolean} [isMapKeys] Specify mapping keys instead of values. - * @returns {Function} Returns the new map function. - */ - function createObjectMapper(isMapKeys) { - return function(object, iteratee, thisArg) { - var result = {}; - iteratee = getCallback(iteratee, thisArg, 3); - - baseForOwn(object, function(value, key, object) { - var mapped = iteratee(value, key, object); - key = isMapKeys ? mapped : key; - value = isMapKeys ? value : mapped; - result[key] = value; - }); - return result; - }; - } + /** + * The base implementation of `_.matches` which does not clone `source`. + * + * @private + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new function. + */ + function baseMatches(source) { + var matchData = getMatchData(source); + if (matchData.length == 1 && matchData[0][2]) { + var key = matchData[0][0], + value = matchData[0][1]; + + return function(object) { + if (object == null) { + return false; + } + return object[key] === value && (value !== undefined || key in toObject(object)); + }; + } + return function(object) { + return baseIsMatch(object, matchData); + }; + } - /** - * Creates a function for `_.padLeft` or `_.padRight`. - * - * @private - * @param {boolean} [fromRight] Specify padding from the right. - * @returns {Function} Returns the new pad function. - */ - function createPadDir(fromRight) { - return function(string, length, chars) { - string = baseToString(string); - return (fromRight ? string : '') + createPadding(string, length, chars) + (fromRight ? '' : string); - }; - } + /** + * The base implementation of `_.matchesProperty` which does not clone `srcValue`. + * + * @private + * @param {string} path The path of the property to get. + * @param {*} srcValue The value to compare. + * @returns {Function} Returns the new function. + */ + function baseMatchesProperty(path, srcValue) { + var isArr = isArray(path), + isCommon = isKey(path) && isStrictComparable(srcValue), + pathKey = path + ''; + + path = toPath(path); + return function(object) { + if (object == null) { + return false; + } + var key = pathKey; + object = toObject(object); + if ((isArr || !isCommon) && !(key in object)) { + object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); + if (object == null) { + return false; + } + key = last(path); + object = toObject(object); + } + return object[key] === srcValue + ? srcValue !== undefined || key in object + : baseIsEqual(srcValue, object[key], undefined, true); + }; + } - /** - * Creates a `_.partial` or `_.partialRight` function. - * - * @private - * @param {boolean} flag The partial bit flag. - * @returns {Function} Returns the new partial function. - */ - function createPartial(flag) { - var partialFunc = restParam(function(func, partials) { - var holders = replaceHolders(partials, partialFunc.placeholder); - return createWrapper(func, flag, undefined, partials, holders); - }); - return partialFunc; - } + /** + * The base implementation of `_.merge` without support for argument juggling, + * multiple sources, and `this` binding `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {Function} [customizer] The function to customize merged values. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates values with source counterparts. + * @returns {Object} Returns `object`. + */ + function baseMerge(object, source, customizer, stackA, stackB) { + if (!isObject(object)) { + return object; + } + var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), + props = isSrcArr ? undefined : keys(source); + + arrayEach(props || source, function(srcValue, key) { + if (props) { + key = srcValue; + srcValue = source[key]; + } + if (isObjectLike(srcValue)) { + stackA || (stackA = []); + stackB || (stackB = []); + baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); + } else { + var value = object[key], + result = customizer ? customizer(value, srcValue, key, object, source) : undefined, + isCommon = result === undefined; + + if (isCommon) { + result = srcValue; + } + if ( + (result !== undefined || (isSrcArr && !(key in object))) && + (isCommon || (result === result ? result !== value : value === value)) + ) { + object[key] = result; + } + } + }); + return object; + } - /** - * Creates a function for `_.reduce` or `_.reduceRight`. - * - * @private - * @param {Function} arrayFunc The function to iterate over an array. - * @param {Function} eachFunc The function to iterate over a collection. - * @returns {Function} Returns the new each function. - */ - function createReduce(arrayFunc, eachFunc) { - return function(collection, iteratee, accumulator, thisArg) { - var initFromArray = arguments.length < 3; - return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) - ? arrayFunc(collection, iteratee, accumulator, initFromArray) - : baseReduce(collection, getCallback(iteratee, thisArg, 4), accumulator, initFromArray, eachFunc); - }; - } + /** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize merged values. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates values with source counterparts. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) { + var length = stackA.length, + srcValue = source[key]; + + while (length--) { + if (stackA[length] == srcValue) { + object[key] = stackB[length]; + return; + } + } + var value = object[key], + result = customizer ? customizer(value, srcValue, key, object, source) : undefined, + isCommon = result === undefined; + + if (isCommon) { + result = srcValue; + if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) { + result = isArray(value) ? value : isArrayLike(value) ? arrayCopy(value) : []; + } else if (isPlainObject(srcValue) || isArguments(srcValue)) { + result = isArguments(value) ? toPlainObject(value) : isPlainObject(value) ? value : {}; + } else { + isCommon = false; + } + } + // Add the source value to the stack of traversed objects and associate + // it with its merged value. + stackA.push(srcValue); + stackB.push(result); + + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB); + } else if (result === result ? result !== value : value === value) { + object[key] = result; + } + } - /** - * Creates a function that wraps `func` and invokes it with optional `this` - * binding of, partial application, and currying. - * - * @private - * @param {Function|string} func The function or method name to reference. - * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [partialsRight] The arguments to append to those provided to the new function. - * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { - var isAry = bitmask & ARY_FLAG, - isBind = bitmask & BIND_FLAG, - isBindKey = bitmask & BIND_KEY_FLAG, - isCurry = bitmask & CURRY_FLAG, - isCurryBound = bitmask & CURRY_BOUND_FLAG, - isCurryRight = bitmask & CURRY_RIGHT_FLAG, - Ctor = isBindKey ? undefined : createCtorWrapper(func); - - function wrapper() { - // Avoid `arguments` object use disqualifying optimizations by - // converting it to an array before providing it to other functions. - var length = arguments.length, - index = length, - args = Array(length); - - while (index--) { - args[index] = arguments[index]; - } - if (partials) { - args = composeArgs(args, partials, holders); - } - if (partialsRight) { - args = composeArgsRight(args, partialsRight, holdersRight); - } - if (isCurry || isCurryRight) { - var placeholder = wrapper.placeholder, - argsHolders = replaceHolders(args, placeholder); - - length -= argsHolders.length; - if (length < arity) { - var newArgPos = argPos ? arrayCopy(argPos) : undefined, - newArity = nativeMax(arity - length, 0), - newsHolders = isCurry ? argsHolders : undefined, - newHoldersRight = isCurry ? undefined : argsHolders, - newPartials = isCurry ? args : undefined, - newPartialsRight = isCurry ? undefined : args; - - bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG); - bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG); - - if (!isCurryBound) { - bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG); - } - var newData = [func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity], - result = createHybridWrapper.apply(undefined, newData); - - if (isLaziable(func)) { - setData(result, newData); - } - result.placeholder = placeholder; - return result; - } - } - var thisBinding = isBind ? thisArg : this, - fn = isBindKey ? thisBinding[func] : func; + /** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. + */ + function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; + } - if (argPos) { - args = reorder(args, argPos); - } - if (isAry && ary < args.length) { - args.length = ary; - } - if (this && this !== root && this instanceof wrapper) { - fn = Ctor || createCtorWrapper(func); - } - return fn.apply(thisBinding, args); - } - return wrapper; - } + /** + * A specialized version of `baseProperty` which supports deep paths. + * + * @private + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new function. + */ + function basePropertyDeep(path) { + var pathKey = path + ''; + path = toPath(path); + return function(object) { + return baseGet(object, path, pathKey); + }; + } - /** - * Creates the padding required for `string` based on the given `length`. - * The `chars` string is truncated if the number of characters exceeds `length`. - * - * @private - * @param {string} string The string to create padding for. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the pad for `string`. - */ - function createPadding(string, length, chars) { - var strLength = string.length; - length = +length; - - if (strLength >= length || !nativeIsFinite(length)) { - return ''; - } - var padLength = length - strLength; - chars = chars == null ? ' ' : (chars + ''); - return repeat(chars, nativeCeil(padLength / chars.length)).slice(0, padLength); - } + /** + * The base implementation of `_.pullAt` without support for individual + * index arguments and capturing the removed elements. + * + * @private + * @param {Array} array The array to modify. + * @param {number[]} indexes The indexes of elements to remove. + * @returns {Array} Returns `array`. + */ + function basePullAt(array, indexes) { + var length = array ? indexes.length : 0; + while (length--) { + var index = indexes[length]; + if (index != previous && isIndex(index)) { + var previous = index; + splice.call(array, index, 1); + } + } + return array; + } - /** - * Creates a function that wraps `func` and invokes it with the optional `this` - * binding of `thisArg` and the `partials` prepended to those provided to - * the wrapper. - * - * @private - * @param {Function} func The function to partially apply arguments to. - * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} partials The arguments to prepend to those provided to the new function. - * @returns {Function} Returns the new bound function. - */ - function createPartialWrapper(func, bitmask, thisArg, partials) { - var isBind = bitmask & BIND_FLAG, - Ctor = createCtorWrapper(func); - - function wrapper() { - // Avoid `arguments` object use disqualifying optimizations by - // converting it to an array before providing it `func`. - var argsIndex = -1, - argsLength = arguments.length, - leftIndex = -1, - leftLength = partials.length, - args = Array(leftLength + argsLength); - - while (++leftIndex < leftLength) { - args[leftIndex] = partials[leftIndex]; - } - while (argsLength--) { - args[leftIndex++] = arguments[++argsIndex]; - } - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return fn.apply(isBind ? thisArg : this, args); - } - return wrapper; - } + /** + * The base implementation of `_.random` without support for argument juggling + * and returning floating-point numbers. + * + * @private + * @param {number} min The minimum possible value. + * @param {number} max The maximum possible value. + * @returns {number} Returns the random number. + */ + function baseRandom(min, max) { + return min + nativeFloor(nativeRandom() * (max - min + 1)); + } - /** - * Creates a `_.ceil`, `_.floor`, or `_.round` function. - * - * @private - * @param {string} methodName The name of the `Math` method to use when rounding. - * @returns {Function} Returns the new round function. - */ - function createRound(methodName) { - var func = Math[methodName]; - return function(number, precision) { - precision = precision === undefined ? 0 : (+precision || 0); - if (precision) { - precision = pow(10, precision); - return func(number * precision) / precision; - } - return func(number); - }; - } + /** + * The base implementation of `_.reduce` and `_.reduceRight` without support + * for callback shorthands and `this` binding, which iterates over `collection` + * using the provided `eachFunc`. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} accumulator The initial value. + * @param {boolean} initFromCollection Specify using the first or last element + * of `collection` as the initial value. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the accumulated value. + */ + function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) { + eachFunc(collection, function(value, index, collection) { + accumulator = initFromCollection + ? ((initFromCollection = false), value) + : iteratee(accumulator, value, index, collection); + }); + return accumulator; + } - /** - * Creates a `_.sortedIndex` or `_.sortedLastIndex` function. - * - * @private - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {Function} Returns the new index function. - */ - function createSortedIndex(retHighest) { - return function(array, value, iteratee, thisArg) { - var callback = getCallback(iteratee); - return (iteratee == null && callback === baseCallback) - ? binaryIndex(array, value, retHighest) - : binaryIndexBy(array, value, callback(iteratee, thisArg, 1), retHighest); - }; - } + /** + * The base implementation of `setData` without support for hot loop detection. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var baseSetData = !metaMap + ? identity + : function(func, data) { + metaMap.set(func, data); + return func; + }; + + /** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + start = start == null ? 0 : +start || 0; + if (start < 0) { + start = -start > length ? 0 : length + start; + } + end = end === undefined || end > length ? length : +end || 0; + if (end < 0) { + end += length; + } + length = start > end ? 0 : (end - start) >>> 0; + start >>>= 0; + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; + } - /** - * Creates a function that either curries or invokes `func` with optional - * `this` binding and partially applied arguments. - * - * @private - * @param {Function|string} func The function or method name to reference. - * @param {number} bitmask The bitmask of flags. - * The bitmask may be composed of the following flags: - * 1 - `_.bind` - * 2 - `_.bindKey` - * 4 - `_.curry` or `_.curryRight` of a bound function - * 8 - `_.curry` - * 16 - `_.curryRight` - * 32 - `_.partial` - * 64 - `_.partialRight` - * 128 - `_.rearg` - * 256 - `_.ary` - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to be partially applied. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { - var isBindKey = bitmask & BIND_KEY_FLAG; - if (!isBindKey && typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - var length = partials ? partials.length : 0; - if (!length) { - bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG); - partials = holders = undefined; - } - length -= (holders ? holders.length : 0); - if (bitmask & PARTIAL_RIGHT_FLAG) { - var partialsRight = partials, - holdersRight = holders; + /** + * The base implementation of `_.some` without support for callback shorthands + * and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function baseSome(collection, predicate) { + var result; + + baseEach(collection, function(value, index, collection) { + result = predicate(value, index, collection); + return !result; + }); + return !!result; + } - partials = holders = undefined; - } - var data = isBindKey ? undefined : getData(func), - newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity]; + /** + * The base implementation of `_.sortBy` which uses `comparer` to define + * the sort order of `array` and replaces criteria objects with their + * corresponding values. + * + * @private + * @param {Array} array The array to sort. + * @param {Function} comparer The function to define sort order. + * @returns {Array} Returns `array`. + */ + function baseSortBy(array, comparer) { + var length = array.length; + + array.sort(comparer); + while (length--) { + array[length] = array[length].value; + } + return array; + } - if (data) { - mergeData(newData, data); - bitmask = newData[1]; - arity = newData[9]; - } - newData[9] = arity == null - ? (isBindKey ? 0 : func.length) - : (nativeMax(arity - length, 0) || 0); - - if (bitmask == BIND_FLAG) { - var result = createBindWrapper(newData[0], newData[2]); - } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) { - result = createPartialWrapper.apply(undefined, newData); - } else { - result = createHybridWrapper.apply(undefined, newData); - } - var setter = data ? baseSetData : setData; - return setter(result, newData); - } + /** + * The base implementation of `_.sortByOrder` without param guards. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. + * @param {boolean[]} orders The sort orders of `iteratees`. + * @returns {Array} Returns the new sorted array. + */ + function baseSortByOrder(collection, iteratees, orders) { + var callback = getCallback(), + index = -1; + + iteratees = arrayMap(iteratees, function(iteratee) { + return callback(iteratee); + }); + + var result = baseMap(collection, function(value) { + var criteria = arrayMap(iteratees, function(iteratee) { + return iteratee(value); + }); + return { criteria: criteria, index: ++index, value: value }; + }); + + return baseSortBy(result, function(object, other) { + return compareMultiple(object, other, orders); + }); + } - /** - * A specialized version of `baseIsEqualDeep` for arrays with support for - * partial deep comparisons. - * - * @private - * @param {Array} array The array to compare. - * @param {Array} other The other array to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparing arrays. - * @param {boolean} [isLoose] Specify performing partial comparisons. - * @param {Array} [stackA] Tracks traversed `value` objects. - * @param {Array} [stackB] Tracks traversed `other` objects. - * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. - */ - function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) { - var index = -1, - arrLength = array.length, - othLength = other.length; - - if (arrLength != othLength && !(isLoose && othLength > arrLength)) { - return false; - } - // Ignore non-index properties. - while (++index < arrLength) { - var arrValue = array[index], - othValue = other[index], - result = customizer ? customizer(isLoose ? othValue : arrValue, isLoose ? arrValue : othValue, index) : undefined; + /** + * The base implementation of `_.sum` without support for callback shorthands + * and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the sum. + */ + function baseSum(collection, iteratee) { + var result = 0; + baseEach(collection, function(value, index, collection) { + result += +iteratee(value, index, collection) || 0; + }); + return result; + } - if (result !== undefined) { - if (result) { - continue; - } - return false; - } - // Recursively compare arrays (susceptible to call stack limits). - if (isLoose) { - if (!arraySome(other, function(othValue) { - return arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB); - })) { - return false; - } - } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB))) { - return false; - } - } - return true; - } + /** + * The base implementation of `_.uniq` without support for callback shorthands + * and `this` binding. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The function invoked per iteration. + * @returns {Array} Returns the new duplicate-value-free array. + */ + function baseUniq(array, iteratee) { + var index = -1, + indexOf = getIndexOf(), + length = array.length, + isCommon = indexOf == baseIndexOf, + isLarge = isCommon && length >= LARGE_ARRAY_SIZE, + seen = isLarge ? createCache() : null, + result = []; + + if (seen) { + indexOf = cacheIndexOf; + isCommon = false; + } else { + isLarge = false; + seen = iteratee ? [] : result; + } + outer: while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value, index, array) : value; + + if (isCommon && value === value) { + var seenIndex = seen.length; + while (seenIndex--) { + if (seen[seenIndex] === computed) { + continue outer; + } + } + if (iteratee) { + seen.push(computed); + } + result.push(value); + } else if (indexOf(seen, computed, 0) < 0) { + if (iteratee || isLarge) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } - /** - * A specialized version of `baseIsEqualDeep` for comparing objects of - * the same `toStringTag`. - * - * **Note:** This function only supports comparing values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {string} tag The `toStringTag` of the objects to compare. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalByTag(object, other, tag) { - switch (tag) { - case boolTag: - case dateTag: - // Coerce dates and booleans to numbers, dates to milliseconds and booleans - // to `1` or `0` treating invalid dates coerced to `NaN` as not equal. - return +object == +other; - - case errorTag: - return object.name == other.name && object.message == other.message; - - case numberTag: - // Treat `NaN` vs. `NaN` as equal. - return (object != +object) - ? other != +other - : object == +other; - - case regexpTag: - case stringTag: - // Coerce regexes to strings and treat strings primitives and string - // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details. - return object == (other + ''); - } - return false; - } + /** + * The base implementation of `_.values` and `_.valuesIn` which creates an + * array of `object` property values corresponding to the property names + * of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the array of property values. + */ + function baseValues(object, props) { + var index = -1, + length = props.length, + result = Array(length); + + while (++index < length) { + result[index] = object[props[index]]; + } + return result; + } - /** - * A specialized version of `baseIsEqualDeep` for objects with support for - * partial deep comparisons. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparing values. - * @param {boolean} [isLoose] Specify performing partial comparisons. - * @param {Array} [stackA] Tracks traversed `value` objects. - * @param {Array} [stackB] Tracks traversed `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) { - var objProps = keys(object), - objLength = objProps.length, - othProps = keys(other), - othLength = othProps.length; - - if (objLength != othLength && !isLoose) { - return false; - } - var index = objLength; - while (index--) { - var key = objProps[index]; - if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) { - return false; - } - } - var skipCtor = isLoose; - while (++index < objLength) { - key = objProps[index]; - var objValue = object[key], - othValue = other[key], - result = customizer ? customizer(isLoose ? othValue : objValue, isLoose? objValue : othValue, key) : undefined; - - // Recursively compare objects (susceptible to call stack limits). - if (!(result === undefined ? equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB) : result)) { - return false; - } - skipCtor || (skipCtor = key == 'constructor'); - } - if (!skipCtor) { - var objCtor = object.constructor, - othCtor = other.constructor; - - // Non `Object` object instances with different constructors are not equal. - if (objCtor != othCtor && - ('constructor' in object && 'constructor' in other) && - !(typeof objCtor == 'function' && objCtor instanceof objCtor && - typeof othCtor == 'function' && othCtor instanceof othCtor)) { - return false; - } - } - return true; - } + /** + * The base implementation of `_.dropRightWhile`, `_.dropWhile`, `_.takeRightWhile`, + * and `_.takeWhile` without support for callback shorthands and `this` binding. + * + * @private + * @param {Array} array The array to query. + * @param {Function} predicate The function invoked per iteration. + * @param {boolean} [isDrop] Specify dropping elements instead of taking them. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the slice of `array`. + */ + function baseWhile(array, predicate, isDrop, fromRight) { + var length = array.length, + index = fromRight ? length : -1; + + while ((fromRight ? index-- : ++index < length) && predicate(array[index], index, array)) {} + return isDrop + ? baseSlice(array, fromRight ? 0 : index, fromRight ? index + 1 : length) + : baseSlice(array, fromRight ? index + 1 : 0, fromRight ? length : index); + } - /** - * Gets the appropriate "callback" function. If the `_.callback` method is - * customized this function returns the custom method, otherwise it returns - * the `baseCallback` function. If arguments are provided the chosen function - * is invoked with them and its result is returned. - * - * @private - * @returns {Function} Returns the chosen function or its result. - */ - function getCallback(func, thisArg, argCount) { - var result = lodash.callback || callback; - result = result === callback ? baseCallback : result; - return argCount ? result(func, thisArg, argCount) : result; - } + /** + * The base implementation of `wrapperValue` which returns the result of + * performing a sequence of actions on the unwrapped `value`, where each + * successive action is supplied the return value of the previous. + * + * @private + * @param {*} value The unwrapped value. + * @param {Array} actions Actions to peform to resolve the unwrapped value. + * @returns {*} Returns the resolved value. + */ + function baseWrapperValue(value, actions) { + var result = value; + if (result instanceof LazyWrapper) { + result = result.value(); + } + var index = -1, + length = actions.length; + + while (++index < length) { + var action = actions[index]; + result = action.func.apply(action.thisArg, arrayPush([result], action.args)); + } + return result; + } - /** - * Gets metadata for `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {*} Returns the metadata for `func`. - */ - var getData = !metaMap ? noop : function(func) { - return metaMap.get(func); - }; - - /** - * Gets the name of `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {string} Returns the function name. - */ - function getFuncName(func) { - var result = func.name, - array = realNames[result], - length = array ? array.length : 0; - - while (length--) { - var data = array[length], - otherFunc = data.func; - if (otherFunc == null || otherFunc == func) { - return data.name; - } - } - return result; - } + /** + * Performs a binary search of `array` to determine the index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function binaryIndex(array, value, retHighest) { + var low = 0, + high = array ? array.length : low; + + if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { + while (low < high) { + var mid = (low + high) >>> 1, + computed = array[mid]; + + if ((retHighest ? computed <= value : computed < value) && computed !== null) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + return binaryIndexBy(array, value, identity, retHighest); + } - /** - * Gets the appropriate "indexOf" function. If the `_.indexOf` method is - * customized this function returns the custom method, otherwise it returns - * the `baseIndexOf` function. If arguments are provided the chosen function - * is invoked with them and its result is returned. - * - * @private - * @returns {Function|number} Returns the chosen function or its result. - */ - function getIndexOf(collection, target, fromIndex) { - var result = lodash.indexOf || indexOf; - result = result === indexOf ? baseIndexOf : result; - return collection ? result(collection, target, fromIndex) : result; - } + /** + * This function is like `binaryIndex` except that it invokes `iteratee` for + * `value` and each element of `array` to compute their sort ranking. The + * iteratee is invoked with one argument; (value). + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} iteratee The function invoked per iteration. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function binaryIndexBy(array, value, iteratee, retHighest) { + value = iteratee(value); + + var low = 0, + high = array ? array.length : 0, + valIsNaN = value !== value, + valIsNull = value === null, + valIsUndef = value === undefined; + + while (low < high) { + var mid = nativeFloor((low + high) / 2), + computed = iteratee(array[mid]), + isDef = computed !== undefined, + isReflexive = computed === computed; + + if (valIsNaN) { + var setLow = isReflexive || retHighest; + } else if (valIsNull) { + setLow = isReflexive && isDef && (retHighest || computed != null); + } else if (valIsUndef) { + setLow = isReflexive && (retHighest || isDef); + } else if (computed == null) { + setLow = false; + } else { + setLow = retHighest ? computed <= value : computed < value; + } + if (setLow) { + low = mid + 1; + } else { + high = mid; + } + } + return nativeMin(high, MAX_ARRAY_INDEX); + } - /** - * Gets the "length" property value of `object`. - * - * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) - * that affects Safari on at least iOS 8.1-8.3 ARM64. - * - * @private - * @param {Object} object The object to query. - * @returns {*} Returns the "length" value. - */ - var getLength = baseProperty('length'); - - /** - * Gets the propery names, values, and compare flags of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the match data of `object`. - */ - function getMatchData(object) { - var result = pairs(object), - length = result.length; - - while (length--) { - result[length][2] = isStrictComparable(result[length][1]); - } - return result; - } + /** + * A specialized version of `baseCallback` which only supports `this` binding + * and specifying the number of arguments to provide to `func`. + * + * @private + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the callback. + */ + function bindCallback(func, thisArg, argCount) { + if (typeof func != 'function') { + return identity; + } + if (thisArg === undefined) { + return func; + } + switch (argCount) { + case 1: + return function(value) { + return func.call(thisArg, value); + }; + case 3: + return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; + case 4: + return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + case 5: + return function(value, other, key, object, source) { + return func.call(thisArg, value, other, key, object, source); + }; + } + return function() { + return func.apply(thisArg, arguments); + }; + } - /** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ - function getNative(object, key) { - var value = object == null ? undefined : object[key]; - return isNative(value) ? value : undefined; - } + /** + * Creates a clone of the given array buffer. + * + * @private + * @param {ArrayBuffer} buffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ + function bufferClone(buffer) { + var result = new ArrayBuffer(buffer.byteLength), + view = new Uint8Array(result); + + view.set(new Uint8Array(buffer)); + return result; + } - /** - * Gets the view, applying any `transforms` to the `start` and `end` positions. - * - * @private - * @param {number} start The start of the view. - * @param {number} end The end of the view. - * @param {Array} transforms The transformations to apply to the view. - * @returns {Object} Returns an object containing the `start` and `end` - * positions of the view. - */ - function getView(start, end, transforms) { - var index = -1, - length = transforms.length; - - while (++index < length) { - var data = transforms[index], - size = data.size; - - switch (data.type) { - case 'drop': start += size; break; - case 'dropRight': end -= size; break; - case 'take': end = nativeMin(end, start + size); break; - case 'takeRight': start = nativeMax(start, end - size); break; - } - } - return { 'start': start, 'end': end }; - } + /** + * Creates an array that is the composition of partially applied arguments, + * placeholders, and provided arguments into a single array of arguments. + * + * @private + * @param {Array|Object} args The provided arguments. + * @param {Array} partials The arguments to prepend to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgs(args, partials, holders) { + var holdersLength = holders.length, + argsIndex = -1, + argsLength = nativeMax(args.length - holdersLength, 0), + leftIndex = -1, + leftLength = partials.length, + result = Array(leftLength + argsLength); + + while (++leftIndex < leftLength) { + result[leftIndex] = partials[leftIndex]; + } + while (++argsIndex < holdersLength) { + result[holders[argsIndex]] = args[argsIndex]; + } + while (argsLength--) { + result[leftIndex++] = args[argsIndex++]; + } + return result; + } - /** - * Initializes an array clone. - * - * @private - * @param {Array} array The array to clone. - * @returns {Array} Returns the initialized clone. - */ - function initCloneArray(array) { - var length = array.length, - result = new array.constructor(length); - - // Add array properties assigned by `RegExp#exec`. - if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { - result.index = array.index; - result.input = array.input; - } - return result; - } + /** + * This function is like `composeArgs` except that the arguments composition + * is tailored for `_.partialRight`. + * + * @private + * @param {Array|Object} args The provided arguments. + * @param {Array} partials The arguments to append to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgsRight(args, partials, holders) { + var holdersIndex = -1, + holdersLength = holders.length, + argsIndex = -1, + argsLength = nativeMax(args.length - holdersLength, 0), + rightIndex = -1, + rightLength = partials.length, + result = Array(argsLength + rightLength); + + while (++argsIndex < argsLength) { + result[argsIndex] = args[argsIndex]; + } + var offset = argsIndex; + while (++rightIndex < rightLength) { + result[offset + rightIndex] = partials[rightIndex]; + } + while (++holdersIndex < holdersLength) { + result[offset + holders[holdersIndex]] = args[argsIndex++]; + } + return result; + } - /** - * Initializes an object clone. - * - * @private - * @param {Object} object The object to clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneObject(object) { - var Ctor = object.constructor; - if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) { - Ctor = Object; - } - return new Ctor; - } + /** + * Creates a `_.countBy`, `_.groupBy`, `_.indexBy`, or `_.partition` function. + * + * @private + * @param {Function} setter The function to set keys and values of the accumulator object. + * @param {Function} [initializer] The function to initialize the accumulator object. + * @returns {Function} Returns the new aggregator function. + */ + function createAggregator(setter, initializer) { + return function(collection, iteratee, thisArg) { + var result = initializer ? initializer() : {}; + iteratee = getCallback(iteratee, thisArg, 3); + + if (isArray(collection)) { + var index = -1, + length = collection.length; + + while (++index < length) { + var value = collection[index]; + setter(result, value, iteratee(value, index, collection), collection); + } + } else { + baseEach(collection, function(value, key, collection) { + setter(result, value, iteratee(value, key, collection), collection); + }); + } + return result; + }; + } - /** - * Initializes an object clone based on its `toStringTag`. - * - * **Note:** This function only supports cloning values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to clone. - * @param {string} tag The `toStringTag` of the object to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneByTag(object, tag, isDeep) { - var Ctor = object.constructor; - switch (tag) { - case arrayBufferTag: - return bufferClone(object); - - case boolTag: - case dateTag: - return new Ctor(+object); - - case float32Tag: case float64Tag: - case int8Tag: case int16Tag: case int32Tag: - case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: - var buffer = object.buffer; - return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length); - - case numberTag: - case stringTag: - return new Ctor(object); - - case regexpTag: - var result = new Ctor(object.source, reFlags.exec(object)); - result.lastIndex = object.lastIndex; - } - return result; - } + /** + * Creates a `_.assign`, `_.defaults`, or `_.merge` function. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ + function createAssigner(assigner) { + return restParam(function(object, sources) { + var index = -1, + length = object == null ? 0 : sources.length, + customizer = length > 2 ? sources[length - 2] : undefined, + guard = length > 2 ? sources[2] : undefined, + thisArg = length > 1 ? sources[length - 1] : undefined; + + if (typeof customizer == 'function') { + customizer = bindCallback(customizer, thisArg, 5); + length -= 2; + } else { + customizer = typeof thisArg == 'function' ? thisArg : undefined; + length -= customizer ? 1 : 0; + } + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, customizer); + } + } + return object; + }); + } - /** - * Invokes the method at `path` on `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {Array} args The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. - */ - function invokePath(object, path, args) { - if (object != null && !isKey(path, object)) { - path = toPath(path); - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - path = last(path); - } - var func = object == null ? object : object[path]; - return func == null ? undefined : func.apply(object, args); - } + /** + * Creates a `baseEach` or `baseEachRight` function. + * + * @private + * @param {Function} eachFunc The function to iterate over a collection. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseEach(eachFunc, fromRight) { + return function(collection, iteratee) { + var length = collection ? getLength(collection) : 0; + if (!isLength(length)) { + return eachFunc(collection, iteratee); + } + var index = fromRight ? length : -1, + iterable = toObject(collection); + + while (fromRight ? index-- : ++index < length) { + if (iteratee(iterable[index], index, iterable) === false) { + break; + } + } + return collection; + }; + } - /** - * Checks if `value` is array-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - */ - function isArrayLike(value) { - return value != null && isLength(getLength(value)); - } + /** + * Creates a base function for `_.forIn` or `_.forInRight`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var iterable = toObject(object), + props = keysFunc(object), + length = props.length, + index = fromRight ? length : -1; + + while (fromRight ? index-- : ++index < length) { + var key = props[index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; + } - /** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ - function isIndex(value, length) { - value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1; - length = length == null ? MAX_SAFE_INTEGER : length; - return value > -1 && value % 1 == 0 && value < length; - } + /** + * Creates a function that wraps `func` and invokes it with the `this` + * binding of `thisArg`. + * + * @private + * @param {Function} func The function to bind. + * @param {*} [thisArg] The `this` binding of `func`. + * @returns {Function} Returns the new bound function. + */ + function createBindWrapper(func, thisArg) { + var Ctor = createCtorWrapper(func); + + function wrapper() { + var fn = this && this !== root && this instanceof wrapper ? Ctor : func; + return fn.apply(thisArg, arguments); + } + return wrapper; + } - /** - * Checks if the provided arguments are from an iteratee call. - * - * @private - * @param {*} value The potential iteratee value argument. - * @param {*} index The potential iteratee index or key argument. - * @param {*} object The potential iteratee object argument. - * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. - */ - function isIterateeCall(value, index, object) { - if (!isObject(object)) { - return false; - } - var type = typeof index; - if (type == 'number' - ? (isArrayLike(object) && isIndex(index, object.length)) - : (type == 'string' && index in object)) { - var other = object[index]; - return value === value ? (value === other) : (other !== other); - } - return false; - } + /** + * Creates a `Set` cache object to optimize linear searches of large arrays. + * + * @private + * @param {Array} [values] The values to cache. + * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`. + */ + function createCache(values) { + return nativeCreate && Set ? new SetCache(values) : null; + } - /** - * Checks if `value` is a property name and not a property path. - * - * @private - * @param {*} value The value to check. - * @param {Object} [object] The object to query keys on. - * @returns {boolean} Returns `true` if `value` is a property name, else `false`. - */ - function isKey(value, object) { - var type = typeof value; - if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') { - return true; - } - if (isArray(value)) { - return false; - } - var result = !reIsDeepProp.test(value); - return result || (object != null && value in toObject(object)); - } + /** + * Creates a function that produces compound words out of the words in a + * given string. + * + * @private + * @param {Function} callback The function to combine each word. + * @returns {Function} Returns the new compounder function. + */ + function createCompounder(callback) { + return function(string) { + var index = -1, + array = words(deburr(string)), + length = array.length, + result = ''; + + while (++index < length) { + result = callback(result, array[index], index); + } + return result; + }; + } - /** - * Checks if `func` has a lazy counterpart. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` has a lazy counterpart, else `false`. - */ - function isLaziable(func) { - var funcName = getFuncName(func); - if (!(funcName in LazyWrapper.prototype)) { - return false; - } - var other = lodash[funcName]; - if (func === other) { - return true; - } - var data = getData(other); - return !!data && func === data[0]; - } + /** + * Creates a function that produces an instance of `Ctor` regardless of + * whether it was invoked as part of a `new` expression or by `call` or `apply`. + * + * @private + * @param {Function} Ctor The constructor to wrap. + * @returns {Function} Returns the new wrapped function. + */ + function createCtorWrapper(Ctor) { + return function() { + // Use a `switch` statement to work with class constructors. + // See http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist + // for more details. + var args = arguments; + switch (args.length) { + case 0: + return new Ctor(); + case 1: + return new Ctor(args[0]); + case 2: + return new Ctor(args[0], args[1]); + case 3: + return new Ctor(args[0], args[1], args[2]); + case 4: + return new Ctor(args[0], args[1], args[2], args[3]); + case 5: + return new Ctor(args[0], args[1], args[2], args[3], args[4]); + case 6: + return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: + return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + } + var thisBinding = baseCreate(Ctor.prototype), + result = Ctor.apply(thisBinding, args); + + // Mimic the constructor's `return` behavior. + // See https://es5.github.io/#x13.2.2 for more details. + return isObject(result) ? result : thisBinding; + }; + } - /** - * Checks if `value` is a valid array-like length. - * - * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - */ - function isLength(value) { - return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; - } + /** + * Creates a `_.curry` or `_.curryRight` function. + * + * @private + * @param {boolean} flag The curry bit flag. + * @returns {Function} Returns the new curry function. + */ + function createCurry(flag) { + function curryFunc(func, arity, guard) { + if (guard && isIterateeCall(func, arity, guard)) { + arity = undefined; + } + var result = createWrapper(func, flag, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curryFunc.placeholder; + return result; + } + return curryFunc; + } - /** - * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` if suitable for strict - * equality comparisons, else `false`. - */ - function isStrictComparable(value) { - return value === value && !isObject(value); - } + /** + * Creates a `_.defaults` or `_.defaultsDeep` function. + * + * @private + * @param {Function} assigner The function to assign values. + * @param {Function} customizer The function to customize assigned values. + * @returns {Function} Returns the new defaults function. + */ + function createDefaults(assigner, customizer) { + return restParam(function(args) { + var object = args[0]; + if (object == null) { + return object; + } + args.push(customizer); + return assigner.apply(undefined, args); + }); + } + + /** + * Creates a `_.max` or `_.min` function. + * + * @private + * @param {Function} comparator The function used to compare values. + * @param {*} exValue The initial extremum value. + * @returns {Function} Returns the new extremum function. + */ + function createExtremum(comparator, exValue) { + return function(collection, iteratee, thisArg) { + if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { + iteratee = undefined; + } + iteratee = getCallback(iteratee, thisArg, 3); + if (iteratee.length == 1) { + collection = isArray(collection) ? collection : toIterable(collection); + var result = arrayExtremum(collection, iteratee, comparator, exValue); + if (!(collection.length && result === exValue)) { + return result; + } + } + return baseExtremum(collection, iteratee, comparator, exValue); + }; + } - /** - * Merges the function metadata of `source` into `data`. - * - * Merging metadata reduces the number of wrappers required to invoke a function. - * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` - * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg` - * augment function arguments, making the order in which they are executed important, - * preventing the merging of metadata. However, we make an exception for a safe - * common case where curried functions have `_.ary` and or `_.rearg` applied. - * - * @private - * @param {Array} data The destination metadata. - * @param {Array} source The source metadata. - * @returns {Array} Returns `data`. - */ - function mergeData(data, source) { - var bitmask = data[1], - srcBitmask = source[1], - newBitmask = bitmask | srcBitmask, - isCommon = newBitmask < ARY_FLAG; - - var isCombo = - (srcBitmask == ARY_FLAG && bitmask == CURRY_FLAG) || - (srcBitmask == ARY_FLAG && bitmask == REARG_FLAG && data[7].length <= source[8]) || - (srcBitmask == (ARY_FLAG | REARG_FLAG) && bitmask == CURRY_FLAG); - - // Exit early if metadata can't be merged. - if (!(isCommon || isCombo)) { - return data; - } - // Use source `thisArg` if available. - if (srcBitmask & BIND_FLAG) { - data[2] = source[2]; - // Set when currying a bound function. - newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG; - } - // Compose partial arguments. - var value = source[3]; - if (value) { - var partials = data[3]; - data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value); - data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]); - } - // Compose partial right arguments. - value = source[5]; - if (value) { - partials = data[5]; - data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value); - data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]); - } - // Use source `argPos` if available. - value = source[7]; - if (value) { - data[7] = arrayCopy(value); - } - // Use source `ary` if it's smaller. - if (srcBitmask & ARY_FLAG) { - data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); - } - // Use source `arity` if one is not provided. - if (data[9] == null) { - data[9] = source[9]; - } - // Use source `func` and merge bitmasks. - data[0] = source[0]; - data[1] = newBitmask; + /** + * Creates a `_.find` or `_.findLast` function. + * + * @private + * @param {Function} eachFunc The function to iterate over a collection. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new find function. + */ + function createFind(eachFunc, fromRight) { + return function(collection, predicate, thisArg) { + predicate = getCallback(predicate, thisArg, 3); + if (isArray(collection)) { + var index = baseFindIndex(collection, predicate, fromRight); + return index > -1 ? collection[index] : undefined; + } + return baseFind(collection, predicate, eachFunc); + }; + } - return data; - } + /** + * Creates a `_.findIndex` or `_.findLastIndex` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new find function. + */ + function createFindIndex(fromRight) { + return function(array, predicate, thisArg) { + if (!(array && array.length)) { + return -1; + } + predicate = getCallback(predicate, thisArg, 3); + return baseFindIndex(array, predicate, fromRight); + }; + } - /** - * Used by `_.defaultsDeep` to customize its `_.merge` use. - * - * @private - * @param {*} objectValue The destination object property value. - * @param {*} sourceValue The source object property value. - * @returns {*} Returns the value to assign to the destination object. - */ - function mergeDefaults(objectValue, sourceValue) { - return objectValue === undefined ? sourceValue : merge(objectValue, sourceValue, mergeDefaults); - } + /** + * Creates a `_.findKey` or `_.findLastKey` function. + * + * @private + * @param {Function} objectFunc The function to iterate over an object. + * @returns {Function} Returns the new find function. + */ + function createFindKey(objectFunc) { + return function(object, predicate, thisArg) { + predicate = getCallback(predicate, thisArg, 3); + return baseFind(object, predicate, objectFunc, true); + }; + } - /** - * A specialized version of `_.pick` which picks `object` properties specified - * by `props`. - * - * @private - * @param {Object} object The source object. - * @param {string[]} props The property names to pick. - * @returns {Object} Returns the new object. - */ - function pickByArray(object, props) { - object = toObject(object); - - var index = -1, - length = props.length, - result = {}; - - while (++index < length) { - var key = props[index]; - if (key in object) { - result[key] = object[key]; - } - } - return result; - } + /** + * Creates a `_.flow` or `_.flowRight` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new flow function. + */ + function createFlow(fromRight) { + return function() { + var wrapper, + length = arguments.length, + index = fromRight ? length : -1, + leftIndex = 0, + funcs = Array(length); + + while (fromRight ? index-- : ++index < length) { + var func = (funcs[leftIndex++] = arguments[index]); + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (!wrapper && LodashWrapper.prototype.thru && getFuncName(func) == 'wrapper') { + wrapper = new LodashWrapper([], true); + } + } + index = wrapper ? -1 : length; + while (++index < length) { + func = funcs[index]; + + var funcName = getFuncName(func), + data = funcName == 'wrapper' ? getData(func) : undefined; + + if ( + data && + isLaziable(data[0]) && + data[1] == (ARY_FLAG | CURRY_FLAG | PARTIAL_FLAG | REARG_FLAG) && + !data[4].length && + data[9] == 1 + ) { + wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); + } else { + wrapper = func.length == 1 && isLaziable(func) ? wrapper[funcName]() : wrapper.thru(func); + } + } + return function() { + var args = arguments, + value = args[0]; + + if (wrapper && args.length == 1 && isArray(value) && value.length >= LARGE_ARRAY_SIZE) { + return wrapper.plant(value).value(); + } + var index = 0, + result = length ? funcs[index].apply(this, args) : value; + + while (++index < length) { + result = funcs[index].call(this, result); + } + return result; + }; + }; + } - /** - * A specialized version of `_.pick` which picks `object` properties `predicate` - * returns truthy for. - * - * @private - * @param {Object} object The source object. - * @param {Function} predicate The function invoked per iteration. - * @returns {Object} Returns the new object. - */ - function pickByCallback(object, predicate) { - var result = {}; - baseForIn(object, function(value, key, object) { - if (predicate(value, key, object)) { - result[key] = value; - } - }); - return result; - } + /** + * Creates a function for `_.forEach` or `_.forEachRight`. + * + * @private + * @param {Function} arrayFunc The function to iterate over an array. + * @param {Function} eachFunc The function to iterate over a collection. + * @returns {Function} Returns the new each function. + */ + function createForEach(arrayFunc, eachFunc) { + return function(collection, iteratee, thisArg) { + return typeof iteratee == 'function' && thisArg === undefined && isArray(collection) + ? arrayFunc(collection, iteratee) + : eachFunc(collection, bindCallback(iteratee, thisArg, 3)); + }; + } - /** - * Reorder `array` according to the specified indexes where the element at - * the first index is assigned as the first element, the element at - * the second index is assigned as the second element, and so on. - * - * @private - * @param {Array} array The array to reorder. - * @param {Array} indexes The arranged array indexes. - * @returns {Array} Returns `array`. - */ - function reorder(array, indexes) { - var arrLength = array.length, - length = nativeMin(indexes.length, arrLength), - oldArray = arrayCopy(array); - - while (length--) { - var index = indexes[length]; - array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; - } - return array; - } + /** + * Creates a function for `_.forIn` or `_.forInRight`. + * + * @private + * @param {Function} objectFunc The function to iterate over an object. + * @returns {Function} Returns the new each function. + */ + function createForIn(objectFunc) { + return function(object, iteratee, thisArg) { + if (typeof iteratee != 'function' || thisArg !== undefined) { + iteratee = bindCallback(iteratee, thisArg, 3); + } + return objectFunc(object, iteratee, keysIn); + }; + } - /** - * Sets metadata for `func`. - * - * **Note:** If this function becomes hot, i.e. is invoked a lot in a short - * period of time, it will trip its breaker and transition to an identity function - * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070) - * for more details. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var setData = (function() { - var count = 0, - lastCalled = 0; - - return function(key, value) { - var stamp = now(), - remaining = HOT_SPAN - (stamp - lastCalled); - - lastCalled = stamp; - if (remaining > 0) { - if (++count >= HOT_COUNT) { - return key; - } - } else { - count = 0; - } - return baseSetData(key, value); - }; - }()); - - /** - * A fallback implementation of `Object.keys` which creates an array of the - * own enumerable property names of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function shimKeys(object) { - var props = keysIn(object), - propsLength = props.length, - length = propsLength && object.length; - - var allowIndexes = !!length && isLength(length) && - (isArray(object) || isArguments(object)); - - var index = -1, - result = []; - - while (++index < propsLength) { - var key = props[index]; - if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { - result.push(key); - } - } - return result; - } + /** + * Creates a function for `_.forOwn` or `_.forOwnRight`. + * + * @private + * @param {Function} objectFunc The function to iterate over an object. + * @returns {Function} Returns the new each function. + */ + function createForOwn(objectFunc) { + return function(object, iteratee, thisArg) { + if (typeof iteratee != 'function' || thisArg !== undefined) { + iteratee = bindCallback(iteratee, thisArg, 3); + } + return objectFunc(object, iteratee); + }; + } - /** - * Converts `value` to an array-like object if it's not one. - * - * @private - * @param {*} value The value to process. - * @returns {Array|Object} Returns the array-like object. - */ - function toIterable(value) { - if (value == null) { - return []; - } - if (!isArrayLike(value)) { - return values(value); - } - return isObject(value) ? value : Object(value); - } + /** + * Creates a function for `_.mapKeys` or `_.mapValues`. + * + * @private + * @param {boolean} [isMapKeys] Specify mapping keys instead of values. + * @returns {Function} Returns the new map function. + */ + function createObjectMapper(isMapKeys) { + return function(object, iteratee, thisArg) { + var result = {}; + iteratee = getCallback(iteratee, thisArg, 3); + + baseForOwn(object, function(value, key, object) { + var mapped = iteratee(value, key, object); + key = isMapKeys ? mapped : key; + value = isMapKeys ? value : mapped; + result[key] = value; + }); + return result; + }; + } - /** - * Converts `value` to an object if it's not one. - * - * @private - * @param {*} value The value to process. - * @returns {Object} Returns the object. - */ - function toObject(value) { - return isObject(value) ? value : Object(value); - } + /** + * Creates a function for `_.padLeft` or `_.padRight`. + * + * @private + * @param {boolean} [fromRight] Specify padding from the right. + * @returns {Function} Returns the new pad function. + */ + function createPadDir(fromRight) { + return function(string, length, chars) { + string = baseToString(string); + return (fromRight ? string : '') + createPadding(string, length, chars) + (fromRight ? '' : string); + }; + } - /** - * Converts `value` to property path array if it's not one. - * - * @private - * @param {*} value The value to process. - * @returns {Array} Returns the property path array. - */ - function toPath(value) { - if (isArray(value)) { - return value; - } - var result = []; - baseToString(value).replace(rePropName, function(match, number, quote, string) { - result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); - }); - return result; - } + /** + * Creates a `_.partial` or `_.partialRight` function. + * + * @private + * @param {boolean} flag The partial bit flag. + * @returns {Function} Returns the new partial function. + */ + function createPartial(flag) { + var partialFunc = restParam(function(func, partials) { + var holders = replaceHolders(partials, partialFunc.placeholder); + return createWrapper(func, flag, undefined, partials, holders); + }); + return partialFunc; + } - /** - * Creates a clone of `wrapper`. - * - * @private - * @param {Object} wrapper The wrapper to clone. - * @returns {Object} Returns the cloned wrapper. - */ - function wrapperClone(wrapper) { - return wrapper instanceof LazyWrapper - ? wrapper.clone() - : new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__, arrayCopy(wrapper.__actions__)); - } + /** + * Creates a function for `_.reduce` or `_.reduceRight`. + * + * @private + * @param {Function} arrayFunc The function to iterate over an array. + * @param {Function} eachFunc The function to iterate over a collection. + * @returns {Function} Returns the new each function. + */ + function createReduce(arrayFunc, eachFunc) { + return function(collection, iteratee, accumulator, thisArg) { + var initFromArray = arguments.length < 3; + return typeof iteratee == 'function' && thisArg === undefined && isArray(collection) + ? arrayFunc(collection, iteratee, accumulator, initFromArray) + : baseReduce(collection, getCallback(iteratee, thisArg, 4), accumulator, initFromArray, eachFunc); + }; + } - /*------------------------------------------------------------------------*/ - - /** - * Creates an array of elements split into groups the length of `size`. - * If `collection` can't be split evenly, the final chunk will be the remaining - * elements. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to process. - * @param {number} [size=1] The length of each chunk. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the new array containing chunks. - * @example - * - * _.chunk(['a', 'b', 'c', 'd'], 2); - * // => [['a', 'b'], ['c', 'd']] - * - * _.chunk(['a', 'b', 'c', 'd'], 3); - * // => [['a', 'b', 'c'], ['d']] - */ - function chunk(array, size, guard) { - if (guard ? isIterateeCall(array, size, guard) : size == null) { - size = 1; - } else { - size = nativeMax(nativeFloor(size) || 1, 1); - } - var index = 0, - length = array ? array.length : 0, - resIndex = -1, - result = Array(nativeCeil(length / size)); + /** + * Creates a function that wraps `func` and invokes it with optional `this` + * binding of, partial application, and currying. + * + * @private + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [partialsRight] The arguments to append to those provided to the new function. + * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createHybridWrapper( + func, + bitmask, + thisArg, + partials, + holders, + partialsRight, + holdersRight, + argPos, + ary, + arity, + ) { + var isAry = bitmask & ARY_FLAG, + isBind = bitmask & BIND_FLAG, + isBindKey = bitmask & BIND_KEY_FLAG, + isCurry = bitmask & CURRY_FLAG, + isCurryBound = bitmask & CURRY_BOUND_FLAG, + isCurryRight = bitmask & CURRY_RIGHT_FLAG, + Ctor = isBindKey ? undefined : createCtorWrapper(func); + + function wrapper() { + // Avoid `arguments` object use disqualifying optimizations by + // converting it to an array before providing it to other functions. + var length = arguments.length, + index = length, + args = Array(length); + + while (index--) { + args[index] = arguments[index]; + } + if (partials) { + args = composeArgs(args, partials, holders); + } + if (partialsRight) { + args = composeArgsRight(args, partialsRight, holdersRight); + } + if (isCurry || isCurryRight) { + var placeholder = wrapper.placeholder, + argsHolders = replaceHolders(args, placeholder); + + length -= argsHolders.length; + if (length < arity) { + var newArgPos = argPos ? arrayCopy(argPos) : undefined, + newArity = nativeMax(arity - length, 0), + newsHolders = isCurry ? argsHolders : undefined, + newHoldersRight = isCurry ? undefined : argsHolders, + newPartials = isCurry ? args : undefined, + newPartialsRight = isCurry ? undefined : args; + + bitmask |= isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG; + bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG); + + if (!isCurryBound) { + bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG); + } + var newData = [ + func, + bitmask, + thisArg, + newPartials, + newsHolders, + newPartialsRight, + newHoldersRight, + newArgPos, + ary, + newArity, + ], + result = createHybridWrapper.apply(undefined, newData); + + if (isLaziable(func)) { + setData(result, newData); + } + result.placeholder = placeholder; + return result; + } + } + var thisBinding = isBind ? thisArg : this, + fn = isBindKey ? thisBinding[func] : func; + + if (argPos) { + args = reorder(args, argPos); + } + if (isAry && ary < args.length) { + args.length = ary; + } + if (this && this !== root && this instanceof wrapper) { + fn = Ctor || createCtorWrapper(func); + } + return fn.apply(thisBinding, args); + } + return wrapper; + } - while (index < length) { - result[++resIndex] = baseSlice(array, index, (index += size)); - } - return result; - } + /** + * Creates the padding required for `string` based on the given `length`. + * The `chars` string is truncated if the number of characters exceeds `length`. + * + * @private + * @param {string} string The string to create padding for. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the pad for `string`. + */ + function createPadding(string, length, chars) { + var strLength = string.length; + length = +length; + + if (strLength >= length || !nativeIsFinite(length)) { + return ''; + } + var padLength = length - strLength; + chars = chars == null ? ' ' : chars + ''; + return repeat(chars, nativeCeil(padLength / chars.length)).slice(0, padLength); + } - /** - * Creates an array with all falsey values removed. The values `false`, `null`, - * `0`, `""`, `undefined`, and `NaN` are falsey. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to compact. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.compact([0, 1, false, 2, '', 3]); - * // => [1, 2, 3] - */ - function compact(array) { - var index = -1, - length = array ? array.length : 0, - resIndex = -1, - result = []; - - while (++index < length) { - var value = array[index]; - if (value) { - result[++resIndex] = value; - } - } - return result; - } + /** + * Creates a function that wraps `func` and invokes it with the optional `this` + * binding of `thisArg` and the `partials` prepended to those provided to + * the wrapper. + * + * @private + * @param {Function} func The function to partially apply arguments to. + * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} partials The arguments to prepend to those provided to the new function. + * @returns {Function} Returns the new bound function. + */ + function createPartialWrapper(func, bitmask, thisArg, partials) { + var isBind = bitmask & BIND_FLAG, + Ctor = createCtorWrapper(func); + + function wrapper() { + // Avoid `arguments` object use disqualifying optimizations by + // converting it to an array before providing it `func`. + var argsIndex = -1, + argsLength = arguments.length, + leftIndex = -1, + leftLength = partials.length, + args = Array(leftLength + argsLength); + + while (++leftIndex < leftLength) { + args[leftIndex] = partials[leftIndex]; + } + while (argsLength--) { + args[leftIndex++] = arguments[++argsIndex]; + } + var fn = this && this !== root && this instanceof wrapper ? Ctor : func; + return fn.apply(isBind ? thisArg : this, args); + } + return wrapper; + } - /** - * Creates an array of unique `array` values not included in the other - * provided arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The arrays of values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.difference([1, 2, 3], [4, 2]); - * // => [1, 3] - */ - var difference = restParam(function(array, values) { - return (isObjectLike(array) && isArrayLike(array)) - ? baseDifference(array, baseFlatten(values, false, true)) - : []; - }); - - /** - * Creates a slice of `array` with `n` elements dropped from the beginning. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.drop([1, 2, 3]); - * // => [2, 3] - * - * _.drop([1, 2, 3], 2); - * // => [3] - * - * _.drop([1, 2, 3], 5); - * // => [] - * - * _.drop([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function drop(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (guard ? isIterateeCall(array, n, guard) : n == null) { - n = 1; - } - return baseSlice(array, n < 0 ? 0 : n); - } + /** + * Creates a `_.ceil`, `_.floor`, or `_.round` function. + * + * @private + * @param {string} methodName The name of the `Math` method to use when rounding. + * @returns {Function} Returns the new round function. + */ + function createRound(methodName) { + var func = Math[methodName]; + return function(number, precision) { + precision = precision === undefined ? 0 : +precision || 0; + if (precision) { + precision = pow(10, precision); + return func(number * precision) / precision; + } + return func(number); + }; + } - /** - * Creates a slice of `array` with `n` elements dropped from the end. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.dropRight([1, 2, 3]); - * // => [1, 2] - * - * _.dropRight([1, 2, 3], 2); - * // => [1] - * - * _.dropRight([1, 2, 3], 5); - * // => [] - * - * _.dropRight([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function dropRight(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (guard ? isIterateeCall(array, n, guard) : n == null) { - n = 1; - } - n = length - (+n || 0); - return baseSlice(array, 0, n < 0 ? 0 : n); - } + /** + * Creates a `_.sortedIndex` or `_.sortedLastIndex` function. + * + * @private + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {Function} Returns the new index function. + */ + function createSortedIndex(retHighest) { + return function(array, value, iteratee, thisArg) { + var callback = getCallback(iteratee); + return iteratee == null && callback === baseCallback + ? binaryIndex(array, value, retHighest) + : binaryIndexBy(array, value, callback(iteratee, thisArg, 1), retHighest); + }; + } - /** - * Creates a slice of `array` excluding elements dropped from the end. - * Elements are dropped until `predicate` returns falsey. The predicate is - * bound to `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that match the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.dropRightWhile([1, 2, 3], function(n) { - * return n > 1; - * }); - * // => [1] - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.dropRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); - * // => ['barney', 'fred'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.dropRightWhile(users, 'active', false), 'user'); - * // => ['barney'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.dropRightWhile(users, 'active'), 'user'); - * // => ['barney', 'fred', 'pebbles'] - */ - function dropRightWhile(array, predicate, thisArg) { - return (array && array.length) - ? baseWhile(array, getCallback(predicate, thisArg, 3), true, true) - : []; - } + /** + * Creates a function that either curries or invokes `func` with optional + * `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of flags. + * The bitmask may be composed of the following flags: + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` or `_.curryRight` of a bound function + * 8 - `_.curry` + * 16 - `_.curryRight` + * 32 - `_.partial` + * 64 - `_.partialRight` + * 128 - `_.rearg` + * 256 - `_.ary` + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to be partially applied. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { + var isBindKey = bitmask & BIND_KEY_FLAG; + if (!isBindKey && typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + var length = partials ? partials.length : 0; + if (!length) { + bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG); + partials = holders = undefined; + } + length -= holders ? holders.length : 0; + if (bitmask & PARTIAL_RIGHT_FLAG) { + var partialsRight = partials, + holdersRight = holders; + + partials = holders = undefined; + } + var data = isBindKey ? undefined : getData(func), + newData = [ + func, + bitmask, + thisArg, + partials, + holders, + partialsRight, + holdersRight, + argPos, + ary, + arity, + ]; + + if (data) { + mergeData(newData, data); + bitmask = newData[1]; + arity = newData[9]; + } + newData[9] = arity == null ? (isBindKey ? 0 : func.length) : nativeMax(arity - length, 0) || 0; + + if (bitmask == BIND_FLAG) { + var result = createBindWrapper(newData[0], newData[2]); + } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) { + result = createPartialWrapper.apply(undefined, newData); + } else { + result = createHybridWrapper.apply(undefined, newData); + } + var setter = data ? baseSetData : setData; + return setter(result, newData); + } - /** - * Creates a slice of `array` excluding elements dropped from the beginning. - * Elements are dropped until `predicate` returns falsey. The predicate is - * bound to `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.dropWhile([1, 2, 3], function(n) { - * return n < 3; - * }); - * // => [3] - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.dropWhile(users, { 'user': 'barney', 'active': false }), 'user'); - * // => ['fred', 'pebbles'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.dropWhile(users, 'active', false), 'user'); - * // => ['pebbles'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.dropWhile(users, 'active'), 'user'); - * // => ['barney', 'fred', 'pebbles'] - */ - function dropWhile(array, predicate, thisArg) { - return (array && array.length) - ? baseWhile(array, getCallback(predicate, thisArg, 3), true) - : []; - } + /** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing arrays. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ + function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) { + var index = -1, + arrLength = array.length, + othLength = other.length; + + if (arrLength != othLength && !(isLoose && othLength > arrLength)) { + return false; + } + // Ignore non-index properties. + while (++index < arrLength) { + var arrValue = array[index], + othValue = other[index], + result = customizer + ? customizer(isLoose ? othValue : arrValue, isLoose ? arrValue : othValue, index) + : undefined; + + if (result !== undefined) { + if (result) { + continue; + } + return false; + } + // Recursively compare arrays (susceptible to call stack limits). + if (isLoose) { + if ( + !arraySome(other, function(othValue) { + return ( + arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB) + ); + }) + ) { + return false; + } + } else if ( + !(arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB)) + ) { + return false; + } + } + return true; + } - /** - * Fills elements of `array` with `value` from `start` up to, but not - * including, `end`. - * - * **Note:** This method mutates `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3]; - * - * _.fill(array, 'a'); - * console.log(array); - * // => ['a', 'a', 'a'] - * - * _.fill(Array(3), 2); - * // => [2, 2, 2] - * - * _.fill([4, 6, 8], '*', 1, 2); - * // => [4, '*', 8] - */ - function fill(array, value, start, end) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { - start = 0; - end = length; - } - return baseFill(array, value, start, end); - } + /** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalByTag(object, other, tag) { + switch (tag) { + case boolTag: + case dateTag: + // Coerce dates and booleans to numbers, dates to milliseconds and booleans + // to `1` or `0` treating invalid dates coerced to `NaN` as not equal. + return +object == +other; + + case errorTag: + return object.name == other.name && object.message == other.message; + + case numberTag: + // Treat `NaN` vs. `NaN` as equal. + return object != +object ? other != +other : object == +other; + + case regexpTag: + case stringTag: + // Coerce regexes to strings and treat strings primitives and string + // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details. + return object == other + ''; + } + return false; + } - /** - * This method is like `_.find` except that it returns the index of the first - * element `predicate` returns truthy for instead of the element itself. - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.findIndex(users, function(chr) { - * return chr.user == 'barney'; - * }); - * // => 0 - * - * // using the `_.matches` callback shorthand - * _.findIndex(users, { 'user': 'fred', 'active': false }); - * // => 1 - * - * // using the `_.matchesProperty` callback shorthand - * _.findIndex(users, 'active', false); - * // => 0 - * - * // using the `_.property` callback shorthand - * _.findIndex(users, 'active'); - * // => 2 - */ - var findIndex = createFindIndex(); - - /** - * This method is like `_.findIndex` except that it iterates over elements - * of `collection` from right to left. - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.findLastIndex(users, function(chr) { - * return chr.user == 'pebbles'; - * }); - * // => 2 - * - * // using the `_.matches` callback shorthand - * _.findLastIndex(users, { 'user': 'barney', 'active': true }); - * // => 0 - * - * // using the `_.matchesProperty` callback shorthand - * _.findLastIndex(users, 'active', false); - * // => 2 - * - * // using the `_.property` callback shorthand - * _.findLastIndex(users, 'active'); - * // => 0 - */ - var findLastIndex = createFindIndex(true); - - /** - * Gets the first element of `array`. - * - * @static - * @memberOf _ - * @alias head - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the first element of `array`. - * @example - * - * _.first([1, 2, 3]); - * // => 1 - * - * _.first([]); - * // => undefined - */ - function first(array) { - return array ? array[0] : undefined; - } + /** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing values. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) { + var objProps = keys(object), + objLength = objProps.length, + othProps = keys(other), + othLength = othProps.length; + + if (objLength != othLength && !isLoose) { + return false; + } + var index = objLength; + while (index--) { + var key = objProps[index]; + if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) { + return false; + } + } + var skipCtor = isLoose; + while (++index < objLength) { + key = objProps[index]; + var objValue = object[key], + othValue = other[key], + result = customizer + ? customizer(isLoose ? othValue : objValue, isLoose ? objValue : othValue, key) + : undefined; + + // Recursively compare objects (susceptible to call stack limits). + if ( + !(result === undefined + ? equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB) + : result) + ) { + return false; + } + skipCtor || (skipCtor = key == 'constructor'); + } + if (!skipCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if ( + objCtor != othCtor && + ('constructor' in object && 'constructor' in other) && + !( + typeof objCtor == 'function' && + objCtor instanceof objCtor && + typeof othCtor == 'function' && + othCtor instanceof othCtor + ) + ) { + return false; + } + } + return true; + } - /** - * Flattens a nested array. If `isDeep` is `true` the array is recursively - * flattened, otherwise it is only flattened a single level. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to flatten. - * @param {boolean} [isDeep] Specify a deep flatten. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flatten([1, [2, 3, [4]]]); - * // => [1, 2, 3, [4]] - * - * // using `isDeep` - * _.flatten([1, [2, 3, [4]]], true); - * // => [1, 2, 3, 4] - */ - function flatten(array, isDeep, guard) { - var length = array ? array.length : 0; - if (guard && isIterateeCall(array, isDeep, guard)) { - isDeep = false; - } - return length ? baseFlatten(array, isDeep) : []; - } + /** + * Gets the appropriate "callback" function. If the `_.callback` method is + * customized this function returns the custom method, otherwise it returns + * the `baseCallback` function. If arguments are provided the chosen function + * is invoked with them and its result is returned. + * + * @private + * @returns {Function} Returns the chosen function or its result. + */ + function getCallback(func, thisArg, argCount) { + var result = lodash.callback || callback; + result = result === callback ? baseCallback : result; + return argCount ? result(func, thisArg, argCount) : result; + } - /** - * Recursively flattens a nested array. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to recursively flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flattenDeep([1, [2, 3, [4]]]); - * // => [1, 2, 3, 4] - */ - function flattenDeep(array) { - var length = array ? array.length : 0; - return length ? baseFlatten(array, true) : []; - } + /** + * Gets metadata for `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {*} Returns the metadata for `func`. + */ + var getData = !metaMap + ? noop + : function(func) { + return metaMap.get(func); + }; + + /** + * Gets the name of `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {string} Returns the function name. + */ + function getFuncName(func) { + var result = func.name, + array = realNames[result], + length = array ? array.length : 0; + + while (length--) { + var data = array[length], + otherFunc = data.func; + if (otherFunc == null || otherFunc == func) { + return data.name; + } + } + return result; + } - /** - * Gets the index at which the first occurrence of `value` is found in `array` - * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it is used as the offset - * from the end of `array`. If `array` is sorted providing `true` for `fromIndex` - * performs a faster binary search. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {boolean|number} [fromIndex=0] The index to search from or `true` - * to perform a binary search on a sorted array. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.indexOf([1, 2, 1, 2], 2); - * // => 1 - * - * // using `fromIndex` - * _.indexOf([1, 2, 1, 2], 2, 2); - * // => 3 - * - * // performing a binary search - * _.indexOf([1, 1, 2, 2], 2, true); - * // => 2 - */ - function indexOf(array, value, fromIndex) { - var length = array ? array.length : 0; - if (!length) { - return -1; - } - if (typeof fromIndex == 'number') { - fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex; - } else if (fromIndex) { - var index = binaryIndex(array, value); - if (index < length && - (value === value ? (value === array[index]) : (array[index] !== array[index]))) { - return index; - } - return -1; - } - return baseIndexOf(array, value, fromIndex || 0); - } + /** + * Gets the appropriate "indexOf" function. If the `_.indexOf` method is + * customized this function returns the custom method, otherwise it returns + * the `baseIndexOf` function. If arguments are provided the chosen function + * is invoked with them and its result is returned. + * + * @private + * @returns {Function|number} Returns the chosen function or its result. + */ + function getIndexOf(collection, target, fromIndex) { + var result = lodash.indexOf || indexOf; + result = result === indexOf ? baseIndexOf : result; + return collection ? result(collection, target, fromIndex) : result; + } - /** - * Gets all but the last element of `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.initial([1, 2, 3]); - * // => [1, 2] - */ - function initial(array) { - return dropRight(array, 1); - } + /** + * Gets the "length" property value of `object`. + * + * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) + * that affects Safari on at least iOS 8.1-8.3 ARM64. + * + * @private + * @param {Object} object The object to query. + * @returns {*} Returns the "length" value. + */ + var getLength = baseProperty('length'); + + /** + * Gets the propery names, values, and compare flags of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the match data of `object`. + */ + function getMatchData(object) { + var result = pairs(object), + length = result.length; + + while (length--) { + result[length][2] = isStrictComparable(result[length][1]); + } + return result; + } - /** - * Creates an array of unique values that are included in all of the provided - * arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of shared values. - * @example - * _.intersection([1, 2], [4, 2], [2, 1]); - * // => [2] - */ - var intersection = restParam(function(arrays) { - var othLength = arrays.length, - othIndex = othLength, - caches = Array(length), - indexOf = getIndexOf(), - isCommon = indexOf == baseIndexOf, - result = []; - - while (othIndex--) { - var value = arrays[othIndex] = isArrayLike(value = arrays[othIndex]) ? value : []; - caches[othIndex] = (isCommon && value.length >= 120) ? createCache(othIndex && value) : null; - } - var array = arrays[0], - index = -1, - length = array ? array.length : 0, - seen = caches[0]; + /** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ + function getNative(object, key) { + var value = object == null ? undefined : object[key]; + return isNative(value) ? value : undefined; + } - outer: - while (++index < length) { - value = array[index]; - if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value, 0)) < 0) { - var othIndex = othLength; - while (--othIndex) { - var cache = caches[othIndex]; - if ((cache ? cacheIndexOf(cache, value) : indexOf(arrays[othIndex], value, 0)) < 0) { - continue outer; - } - } - if (seen) { - seen.push(value); - } - result.push(value); - } - } - return result; - }); - - /** - * Gets the last element of `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the last element of `array`. - * @example - * - * _.last([1, 2, 3]); - * // => 3 - */ - function last(array) { - var length = array ? array.length : 0; - return length ? array[length - 1] : undefined; - } + /** + * Gets the view, applying any `transforms` to the `start` and `end` positions. + * + * @private + * @param {number} start The start of the view. + * @param {number} end The end of the view. + * @param {Array} transforms The transformations to apply to the view. + * @returns {Object} Returns an object containing the `start` and `end` + * positions of the view. + */ + function getView(start, end, transforms) { + var index = -1, + length = transforms.length; + + while (++index < length) { + var data = transforms[index], + size = data.size; + + switch (data.type) { + case 'drop': + start += size; + break; + case 'dropRight': + end -= size; + break; + case 'take': + end = nativeMin(end, start + size); + break; + case 'takeRight': + start = nativeMax(start, end - size); + break; + } + } + return { start: start, end: end }; + } - /** - * This method is like `_.indexOf` except that it iterates over elements of - * `array` from right to left. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {boolean|number} [fromIndex=array.length-1] The index to search from - * or `true` to perform a binary search on a sorted array. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.lastIndexOf([1, 2, 1, 2], 2); - * // => 3 - * - * // using `fromIndex` - * _.lastIndexOf([1, 2, 1, 2], 2, 2); - * // => 1 - * - * // performing a binary search - * _.lastIndexOf([1, 1, 2, 2], 2, true); - * // => 3 - */ - function lastIndexOf(array, value, fromIndex) { - var length = array ? array.length : 0; - if (!length) { - return -1; - } - var index = length; - if (typeof fromIndex == 'number') { - index = (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1; - } else if (fromIndex) { - index = binaryIndex(array, value, true) - 1; - var other = array[index]; - if (value === value ? (value === other) : (other !== other)) { - return index; - } - return -1; - } - if (value !== value) { - return indexOfNaN(array, index, true); - } - while (index--) { - if (array[index] === value) { - return index; - } - } - return -1; - } + /** + * Initializes an array clone. + * + * @private + * @param {Array} array The array to clone. + * @returns {Array} Returns the initialized clone. + */ + function initCloneArray(array) { + var length = array.length, + result = new array.constructor(length); + + // Add array properties assigned by `RegExp#exec`. + if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { + result.index = array.index; + result.input = array.input; + } + return result; + } - /** - * Removes all provided values from `array` using - * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. - * - * **Note:** Unlike `_.without`, this method mutates `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to modify. - * @param {...*} [values] The values to remove. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3, 1, 2, 3]; - * - * _.pull(array, 2, 3); - * console.log(array); - * // => [1, 1] - */ - function pull() { - var args = arguments, - array = args[0]; - - if (!(array && array.length)) { - return array; - } - var index = 0, - indexOf = getIndexOf(), - length = args.length; + /** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneObject(object) { + var Ctor = object.constructor; + if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) { + Ctor = Object; + } + return new Ctor(); + } - while (++index < length) { - var fromIndex = 0, - value = args[index]; + /** + * Initializes an object clone based on its `toStringTag`. + * + * **Note:** This function only supports cloning values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to clone. + * @param {string} tag The `toStringTag` of the object to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneByTag(object, tag, isDeep) { + var Ctor = object.constructor; + switch (tag) { + case arrayBufferTag: + return bufferClone(object); + + case boolTag: + case dateTag: + return new Ctor(+object); + + case float32Tag: + case float64Tag: + case int8Tag: + case int16Tag: + case int32Tag: + case uint8Tag: + case uint8ClampedTag: + case uint16Tag: + case uint32Tag: + var buffer = object.buffer; + return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length); + + case numberTag: + case stringTag: + return new Ctor(object); + + case regexpTag: + var result = new Ctor(object.source, reFlags.exec(object)); + result.lastIndex = object.lastIndex; + } + return result; + } - while ((fromIndex = indexOf(array, value, fromIndex)) > -1) { - splice.call(array, fromIndex, 1); - } - } - return array; - } + /** + * Invokes the method at `path` on `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {Array} args The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. + */ + function invokePath(object, path, args) { + if (object != null && !isKey(path, object)) { + path = toPath(path); + object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); + path = last(path); + } + var func = object == null ? object : object[path]; + return func == null ? undefined : func.apply(object, args); + } - /** - * Removes elements from `array` corresponding to the given indexes and returns - * an array of the removed elements. Indexes may be specified as an array of - * indexes or as individual arguments. - * - * **Note:** Unlike `_.at`, this method mutates `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to modify. - * @param {...(number|number[])} [indexes] The indexes of elements to remove, - * specified as individual indexes or arrays of indexes. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = [5, 10, 15, 20]; - * var evens = _.pullAt(array, 1, 3); - * - * console.log(array); - * // => [5, 15] - * - * console.log(evens); - * // => [10, 20] - */ - var pullAt = restParam(function(array, indexes) { - indexes = baseFlatten(indexes); - - var result = baseAt(array, indexes); - basePullAt(array, indexes.sort(baseCompareAscending)); - return result; - }); - - /** - * Removes all elements from `array` that `predicate` returns truthy for - * and returns an array of the removed elements. The predicate is bound to - * `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * **Note:** Unlike `_.filter`, this method mutates `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to modify. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = [1, 2, 3, 4]; - * var evens = _.remove(array, function(n) { - * return n % 2 == 0; - * }); - * - * console.log(array); - * // => [1, 3] - * - * console.log(evens); - * // => [2, 4] - */ - function remove(array, predicate, thisArg) { - var result = []; - if (!(array && array.length)) { - return result; - } - var index = -1, - indexes = [], - length = array.length; + /** + * Checks if `value` is array-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + */ + function isArrayLike(value) { + return value != null && isLength(getLength(value)); + } - predicate = getCallback(predicate, thisArg, 3); - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result.push(value); - indexes.push(index); - } - } - basePullAt(array, indexes); - return result; - } + /** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ + function isIndex(value, length) { + value = typeof value == 'number' || reIsUint.test(value) ? +value : -1; + length = length == null ? MAX_SAFE_INTEGER : length; + return value > -1 && value % 1 == 0 && value < length; + } - /** - * Gets all but the first element of `array`. - * - * @static - * @memberOf _ - * @alias tail - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.rest([1, 2, 3]); - * // => [2, 3] - */ - function rest(array) { - return drop(array, 1); - } + /** + * Checks if the provided arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. + */ + function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if ( + type == 'number' + ? isArrayLike(object) && isIndex(index, object.length) + : type == 'string' && index in object + ) { + var other = object[index]; + return value === value ? value === other : other !== other; + } + return false; + } - /** - * Creates a slice of `array` from `start` up to, but not including, `end`. - * - * **Note:** This method is used instead of `Array#slice` to support node - * lists in IE < 9 and to ensure dense arrays are returned. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function slice(array, start, end) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { - start = 0; - end = length; - } - return baseSlice(array, start, end); - } + /** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ + function isKey(value, object) { + var type = typeof value; + if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') { + return true; + } + if (isArray(value)) { + return false; + } + var result = !reIsDeepProp.test(value); + return result || (object != null && value in toObject(object)); + } - /** - * Uses a binary search to determine the lowest index at which `value` should - * be inserted into `array` in order to maintain its sort order. If an iteratee - * function is provided it is invoked for `value` and each element of `array` - * to compute their sort ranking. The iteratee is bound to `thisArg` and - * invoked with one argument; (value). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedIndex([30, 50], 40); - * // => 1 - * - * _.sortedIndex([4, 4, 5, 5], 5); - * // => 2 - * - * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } }; - * - * // using an iteratee function - * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) { - * return this.data[word]; - * }, dict); - * // => 1 - * - * // using the `_.property` callback shorthand - * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); - * // => 1 - */ - var sortedIndex = createSortedIndex(); - - /** - * This method is like `_.sortedIndex` except that it returns the highest - * index at which `value` should be inserted into `array` in order to - * maintain its sort order. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedLastIndex([4, 4, 5, 5], 5); - * // => 4 - */ - var sortedLastIndex = createSortedIndex(true); - - /** - * Creates a slice of `array` with `n` elements taken from the beginning. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.take([1, 2, 3]); - * // => [1] - * - * _.take([1, 2, 3], 2); - * // => [1, 2] - * - * _.take([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.take([1, 2, 3], 0); - * // => [] - */ - function take(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (guard ? isIterateeCall(array, n, guard) : n == null) { - n = 1; - } - return baseSlice(array, 0, n < 0 ? 0 : n); - } + /** + * Checks if `func` has a lazy counterpart. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` has a lazy counterpart, else `false`. + */ + function isLaziable(func) { + var funcName = getFuncName(func); + if (!(funcName in LazyWrapper.prototype)) { + return false; + } + var other = lodash[funcName]; + if (func === other) { + return true; + } + var data = getData(other); + return !!data && func === data[0]; + } - /** - * Creates a slice of `array` with `n` elements taken from the end. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeRight([1, 2, 3]); - * // => [3] - * - * _.takeRight([1, 2, 3], 2); - * // => [2, 3] - * - * _.takeRight([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.takeRight([1, 2, 3], 0); - * // => [] - */ - function takeRight(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (guard ? isIterateeCall(array, n, guard) : n == null) { - n = 1; - } - n = length - (+n || 0); - return baseSlice(array, n < 0 ? 0 : n); - } + /** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ + function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; + } - /** - * Creates a slice of `array` with elements taken from the end. Elements are - * taken until `predicate` returns falsey. The predicate is bound to `thisArg` - * and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeRightWhile([1, 2, 3], function(n) { - * return n > 1; - * }); - * // => [2, 3] - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.takeRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); - * // => ['pebbles'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.takeRightWhile(users, 'active', false), 'user'); - * // => ['fred', 'pebbles'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.takeRightWhile(users, 'active'), 'user'); - * // => [] - */ - function takeRightWhile(array, predicate, thisArg) { - return (array && array.length) - ? baseWhile(array, getCallback(predicate, thisArg, 3), false, true) - : []; - } + /** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ + function isStrictComparable(value) { + return value === value && !isObject(value); + } - /** - * Creates a slice of `array` with elements taken from the beginning. Elements - * are taken until `predicate` returns falsey. The predicate is bound to - * `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeWhile([1, 2, 3], function(n) { - * return n < 3; - * }); - * // => [1, 2] - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false}, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.takeWhile(users, { 'user': 'barney', 'active': false }), 'user'); - * // => ['barney'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.takeWhile(users, 'active', false), 'user'); - * // => ['barney', 'fred'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.takeWhile(users, 'active'), 'user'); - * // => [] - */ - function takeWhile(array, predicate, thisArg) { - return (array && array.length) - ? baseWhile(array, getCallback(predicate, thisArg, 3)) - : []; - } + /** + * Merges the function metadata of `source` into `data`. + * + * Merging metadata reduces the number of wrappers required to invoke a function. + * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` + * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg` + * augment function arguments, making the order in which they are executed important, + * preventing the merging of metadata. However, we make an exception for a safe + * common case where curried functions have `_.ary` and or `_.rearg` applied. + * + * @private + * @param {Array} data The destination metadata. + * @param {Array} source The source metadata. + * @returns {Array} Returns `data`. + */ + function mergeData(data, source) { + var bitmask = data[1], + srcBitmask = source[1], + newBitmask = bitmask | srcBitmask, + isCommon = newBitmask < ARY_FLAG; + + var isCombo = + (srcBitmask == ARY_FLAG && bitmask == CURRY_FLAG) || + (srcBitmask == ARY_FLAG && bitmask == REARG_FLAG && data[7].length <= source[8]) || + (srcBitmask == (ARY_FLAG | REARG_FLAG) && bitmask == CURRY_FLAG); + + // Exit early if metadata can't be merged. + if (!(isCommon || isCombo)) { + return data; + } + // Use source `thisArg` if available. + if (srcBitmask & BIND_FLAG) { + data[2] = source[2]; + // Set when currying a bound function. + newBitmask |= bitmask & BIND_FLAG ? 0 : CURRY_BOUND_FLAG; + } + // Compose partial arguments. + var value = source[3]; + if (value) { + var partials = data[3]; + data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value); + data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]); + } + // Compose partial right arguments. + value = source[5]; + if (value) { + partials = data[5]; + data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value); + data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]); + } + // Use source `argPos` if available. + value = source[7]; + if (value) { + data[7] = arrayCopy(value); + } + // Use source `ary` if it's smaller. + if (srcBitmask & ARY_FLAG) { + data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); + } + // Use source `arity` if one is not provided. + if (data[9] == null) { + data[9] = source[9]; + } + // Use source `func` and merge bitmasks. + data[0] = source[0]; + data[1] = newBitmask; + + return data; + } - /** - * Creates an array of unique values, in order, from all of the provided arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of combined values. - * @example - * - * _.union([1, 2], [4, 2], [2, 1]); - * // => [1, 2, 4] - */ - var union = restParam(function(arrays) { - return baseUniq(baseFlatten(arrays, false, true)); - }); - - /** - * Creates a duplicate-free version of an array, using - * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons, in which only the first occurence of each element - * is kept. Providing `true` for `isSorted` performs a faster search algorithm - * for sorted arrays. If an iteratee function is provided it is invoked for - * each element in the array to generate the criterion by which uniqueness - * is computed. The `iteratee` is bound to `thisArg` and invoked with three - * arguments: (value, index, array). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias unique - * @category Array - * @param {Array} array The array to inspect. - * @param {boolean} [isSorted] Specify the array is sorted. - * @param {Function|Object|string} [iteratee] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new duplicate-value-free array. - * @example - * - * _.uniq([2, 1, 2]); - * // => [2, 1] - * - * // using `isSorted` - * _.uniq([1, 1, 2], true); - * // => [1, 2] - * - * // using an iteratee function - * _.uniq([1, 2.5, 1.5, 2], function(n) { - * return this.floor(n); - * }, Math); - * // => [1, 2.5] - * - * // using the `_.property` callback shorthand - * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - function uniq(array, isSorted, iteratee, thisArg) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (isSorted != null && typeof isSorted != 'boolean') { - thisArg = iteratee; - iteratee = isIterateeCall(array, isSorted, thisArg) ? undefined : isSorted; - isSorted = false; - } - var callback = getCallback(); - if (!(iteratee == null && callback === baseCallback)) { - iteratee = callback(iteratee, thisArg, 3); - } - return (isSorted && getIndexOf() == baseIndexOf) - ? sortedUniq(array, iteratee) - : baseUniq(array, iteratee); - } + /** + * Used by `_.defaultsDeep` to customize its `_.merge` use. + * + * @private + * @param {*} objectValue The destination object property value. + * @param {*} sourceValue The source object property value. + * @returns {*} Returns the value to assign to the destination object. + */ + function mergeDefaults(objectValue, sourceValue) { + return objectValue === undefined ? sourceValue : merge(objectValue, sourceValue, mergeDefaults); + } - /** - * This method is like `_.zip` except that it accepts an array of grouped - * elements and creates an array regrouping the elements to their pre-zip - * configuration. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array of grouped elements to process. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]); - * // => [['fred', 30, true], ['barney', 40, false]] - * - * _.unzip(zipped); - * // => [['fred', 'barney'], [30, 40], [true, false]] - */ - function unzip(array) { - if (!(array && array.length)) { - return []; - } - var index = -1, - length = 0; + /** + * A specialized version of `_.pick` which picks `object` properties specified + * by `props`. + * + * @private + * @param {Object} object The source object. + * @param {string[]} props The property names to pick. + * @returns {Object} Returns the new object. + */ + function pickByArray(object, props) { + object = toObject(object); + + var index = -1, + length = props.length, + result = {}; + + while (++index < length) { + var key = props[index]; + if (key in object) { + result[key] = object[key]; + } + } + return result; + } - array = arrayFilter(array, function(group) { - if (isArrayLike(group)) { - length = nativeMax(group.length, length); - return true; - } - }); - var result = Array(length); - while (++index < length) { - result[index] = arrayMap(array, baseProperty(index)); - } - return result; - } + /** + * A specialized version of `_.pick` which picks `object` properties `predicate` + * returns truthy for. + * + * @private + * @param {Object} object The source object. + * @param {Function} predicate The function invoked per iteration. + * @returns {Object} Returns the new object. + */ + function pickByCallback(object, predicate) { + var result = {}; + baseForIn(object, function(value, key, object) { + if (predicate(value, key, object)) { + result[key] = value; + } + }); + return result; + } - /** - * This method is like `_.unzip` except that it accepts an iteratee to specify - * how regrouped values should be combined. The `iteratee` is bound to `thisArg` - * and invoked with four arguments: (accumulator, value, index, group). - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array of grouped elements to process. - * @param {Function} [iteratee] The function to combine regrouped values. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip([1, 2], [10, 20], [100, 200]); - * // => [[1, 10, 100], [2, 20, 200]] - * - * _.unzipWith(zipped, _.add); - * // => [3, 30, 300] - */ - function unzipWith(array, iteratee, thisArg) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - var result = unzip(array); - if (iteratee == null) { - return result; - } - iteratee = bindCallback(iteratee, thisArg, 4); - return arrayMap(result, function(group) { - return arrayReduce(group, iteratee, undefined, true); - }); - } + /** + * Reorder `array` according to the specified indexes where the element at + * the first index is assigned as the first element, the element at + * the second index is assigned as the second element, and so on. + * + * @private + * @param {Array} array The array to reorder. + * @param {Array} indexes The arranged array indexes. + * @returns {Array} Returns `array`. + */ + function reorder(array, indexes) { + var arrLength = array.length, + length = nativeMin(indexes.length, arrLength), + oldArray = arrayCopy(array); + + while (length--) { + var index = indexes[length]; + array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; + } + return array; + } - /** - * Creates an array excluding all provided values using - * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to filter. - * @param {...*} [values] The values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.without([1, 2, 1, 3], 1, 2); - * // => [3] - */ - var without = restParam(function(array, values) { - return isArrayLike(array) - ? baseDifference(array, values) - : []; - }); - - /** - * Creates an array of unique values that is the [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) - * of the provided arrays. - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of values. - * @example - * - * _.xor([1, 2], [4, 2]); - * // => [1, 4] - */ - function xor() { - var index = -1, - length = arguments.length; - - while (++index < length) { - var array = arguments[index]; - if (isArrayLike(array)) { - var result = result - ? arrayPush(baseDifference(result, array), baseDifference(array, result)) - : array; - } - } - return result ? baseUniq(result) : []; - } + /** + * Sets metadata for `func`. + * + * **Note:** If this function becomes hot, i.e. is invoked a lot in a short + * period of time, it will trip its breaker and transition to an identity function + * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070) + * for more details. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var setData = (function() { + var count = 0, + lastCalled = 0; + + return function(key, value) { + var stamp = now(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return key; + } + } else { + count = 0; + } + return baseSetData(key, value); + }; + })(); + + /** + * A fallback implementation of `Object.keys` which creates an array of the + * own enumerable property names of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function shimKeys(object) { + var props = keysIn(object), + propsLength = props.length, + length = propsLength && object.length; + + var allowIndexes = !!length && isLength(length) && (isArray(object) || isArguments(object)); + + var index = -1, + result = []; + + while (++index < propsLength) { + var key = props[index]; + if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { + result.push(key); + } + } + return result; + } - /** - * Creates an array of grouped elements, the first of which contains the first - * elements of the given arrays, the second of which contains the second elements - * of the given arrays, and so on. - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zip(['fred', 'barney'], [30, 40], [true, false]); - * // => [['fred', 30, true], ['barney', 40, false]] - */ - var zip = restParam(unzip); - - /** - * The inverse of `_.pairs`; this method returns an object composed from arrays - * of property names and values. Provide either a single two dimensional array, - * e.g. `[[key1, value1], [key2, value2]]` or two arrays, one of property names - * and one of corresponding values. - * - * @static - * @memberOf _ - * @alias object - * @category Array - * @param {Array} props The property names. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObject([['fred', 30], ['barney', 40]]); - * // => { 'fred': 30, 'barney': 40 } - * - * _.zipObject(['fred', 'barney'], [30, 40]); - * // => { 'fred': 30, 'barney': 40 } - */ - function zipObject(props, values) { - var index = -1, - length = props ? props.length : 0, - result = {}; - - if (length && !values && !isArray(props[0])) { - values = []; - } - while (++index < length) { - var key = props[index]; - if (values) { - result[key] = values[index]; - } else if (key) { - result[key[0]] = key[1]; - } - } - return result; - } + /** + * Converts `value` to an array-like object if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Array|Object} Returns the array-like object. + */ + function toIterable(value) { + if (value == null) { + return []; + } + if (!isArrayLike(value)) { + return values(value); + } + return isObject(value) ? value : Object(value); + } - /** - * This method is like `_.zip` except that it accepts an iteratee to specify - * how grouped values should be combined. The `iteratee` is bound to `thisArg` - * and invoked with four arguments: (accumulator, value, index, group). - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @param {Function} [iteratee] The function to combine grouped values. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zipWith([1, 2], [10, 20], [100, 200], _.add); - * // => [111, 222] - */ - var zipWith = restParam(function(arrays) { - var length = arrays.length, - iteratee = length > 2 ? arrays[length - 2] : undefined, - thisArg = length > 1 ? arrays[length - 1] : undefined; - - if (length > 2 && typeof iteratee == 'function') { - length -= 2; - } else { - iteratee = (length > 1 && typeof thisArg == 'function') ? (--length, thisArg) : undefined; - thisArg = undefined; - } - arrays.length = length; - return unzipWith(arrays, iteratee, thisArg); - }); - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` object that wraps `value` with explicit method - * chaining enabled. - * - * @static - * @memberOf _ - * @category Chain - * @param {*} value The value to wrap. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'pebbles', 'age': 1 } - * ]; - * - * var youngest = _.chain(users) - * .sortBy('age') - * .map(function(chr) { - * return chr.user + ' is ' + chr.age; - * }) - * .first() - * .value(); - * // => 'pebbles is 1' - */ - function chain(value) { - var result = lodash(value); - result.__chain__ = true; - return result; - } + /** + * Converts `value` to an object if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Object} Returns the object. + */ + function toObject(value) { + return isObject(value) ? value : Object(value); + } - /** - * This method invokes `interceptor` and returns `value`. The interceptor is - * bound to `thisArg` and invoked with one argument; (value). The purpose of - * this method is to "tap into" a method chain in order to perform operations - * on intermediate results within the chain. - * - * @static - * @memberOf _ - * @category Chain - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @param {*} [thisArg] The `this` binding of `interceptor`. - * @returns {*} Returns `value`. - * @example - * - * _([1, 2, 3]) - * .tap(function(array) { - * array.pop(); - * }) - * .reverse() - * .value(); - * // => [2, 1] - */ - function tap(value, interceptor, thisArg) { - interceptor.call(thisArg, value); - return value; - } + /** + * Converts `value` to property path array if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Array} Returns the property path array. + */ + function toPath(value) { + if (isArray(value)) { + return value; + } + var result = []; + baseToString(value).replace(rePropName, function(match, number, quote, string) { + result.push(quote ? string.replace(reEscapeChar, '$1') : number || match); + }); + return result; + } - /** - * This method is like `_.tap` except that it returns the result of `interceptor`. - * - * @static - * @memberOf _ - * @category Chain - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @param {*} [thisArg] The `this` binding of `interceptor`. - * @returns {*} Returns the result of `interceptor`. - * @example - * - * _(' abc ') - * .chain() - * .trim() - * .thru(function(value) { - * return [value]; - * }) - * .value(); - * // => ['abc'] - */ - function thru(value, interceptor, thisArg) { - return interceptor.call(thisArg, value); - } + /** + * Creates a clone of `wrapper`. + * + * @private + * @param {Object} wrapper The wrapper to clone. + * @returns {Object} Returns the cloned wrapper. + */ + function wrapperClone(wrapper) { + return wrapper instanceof LazyWrapper + ? wrapper.clone() + : new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__, arrayCopy(wrapper.__actions__)); + } - /** - * Enables explicit method chaining on the wrapper object. - * - * @name chain - * @memberOf _ - * @category Chain - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 } - * ]; - * - * // without explicit chaining - * _(users).first(); - * // => { 'user': 'barney', 'age': 36 } - * - * // with explicit chaining - * _(users).chain() - * .first() - * .pick('user') - * .value(); - * // => { 'user': 'barney' } - */ - function wrapperChain() { - return chain(this); - } + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of elements split into groups the length of `size`. + * If `collection` can't be split evenly, the final chunk will be the remaining + * elements. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to process. + * @param {number} [size=1] The length of each chunk. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the new array containing chunks. + * @example + * + * _.chunk(['a', 'b', 'c', 'd'], 2); + * // => [['a', 'b'], ['c', 'd']] + * + * _.chunk(['a', 'b', 'c', 'd'], 3); + * // => [['a', 'b', 'c'], ['d']] + */ + function chunk(array, size, guard) { + if (guard ? isIterateeCall(array, size, guard) : size == null) { + size = 1; + } else { + size = nativeMax(nativeFloor(size) || 1, 1); + } + var index = 0, + length = array ? array.length : 0, + resIndex = -1, + result = Array(nativeCeil(length / size)); + + while (index < length) { + result[++resIndex] = baseSlice(array, index, (index += size)); + } + return result; + } - /** - * Executes the chained sequence and returns the wrapped result. - * - * @name commit - * @memberOf _ - * @category Chain - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2]; - * var wrapped = _(array).push(3); - * - * console.log(array); - * // => [1, 2] - * - * wrapped = wrapped.commit(); - * console.log(array); - * // => [1, 2, 3] - * - * wrapped.last(); - * // => 3 - * - * console.log(array); - * // => [1, 2, 3] - */ - function wrapperCommit() { - return new LodashWrapper(this.value(), this.__chain__); - } + /** + * Creates an array with all falsey values removed. The values `false`, `null`, + * `0`, `""`, `undefined`, and `NaN` are falsey. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to compact. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.compact([0, 1, false, 2, '', 3]); + * // => [1, 2, 3] + */ + function compact(array) { + var index = -1, + length = array ? array.length : 0, + resIndex = -1, + result = []; + + while (++index < length) { + var value = array[index]; + if (value) { + result[++resIndex] = value; + } + } + return result; + } - /** - * Creates a new array joining a wrapped array with any additional arrays - * and/or values. - * - * @name concat - * @memberOf _ - * @category Chain - * @param {...*} [values] The values to concatenate. - * @returns {Array} Returns the new concatenated array. - * @example - * - * var array = [1]; - * var wrapped = _(array).concat(2, [3], [[4]]); - * - * console.log(wrapped.value()); - * // => [1, 2, 3, [4]] - * - * console.log(array); - * // => [1] - */ - var wrapperConcat = restParam(function(values) { - values = baseFlatten(values); - return this.thru(function(array) { - return arrayConcat(isArray(array) ? array : [toObject(array)], values); - }); - }); - - /** - * Creates a clone of the chained sequence planting `value` as the wrapped value. - * - * @name plant - * @memberOf _ - * @category Chain - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2]; - * var wrapped = _(array).map(function(value) { - * return Math.pow(value, 2); - * }); - * - * var other = [3, 4]; - * var otherWrapped = wrapped.plant(other); - * - * otherWrapped.value(); - * // => [9, 16] - * - * wrapped.value(); - * // => [1, 4] - */ - function wrapperPlant(value) { - var result, - parent = this; - - while (parent instanceof baseLodash) { - var clone = wrapperClone(parent); - if (result) { - previous.__wrapped__ = clone; - } else { - result = clone; - } - var previous = clone; - parent = parent.__wrapped__; - } - previous.__wrapped__ = value; - return result; - } + /** + * Creates an array of unique `array` values not included in the other + * provided arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The arrays of values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.difference([1, 2, 3], [4, 2]); + * // => [1, 3] + */ + var difference = restParam(function(array, values) { + return isObjectLike(array) && isArrayLike(array) + ? baseDifference(array, baseFlatten(values, false, true)) + : []; + }); + + /** + * Creates a slice of `array` with `n` elements dropped from the beginning. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.drop([1, 2, 3]); + * // => [2, 3] + * + * _.drop([1, 2, 3], 2); + * // => [3] + * + * _.drop([1, 2, 3], 5); + * // => [] + * + * _.drop([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function drop(array, n, guard) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + return baseSlice(array, n < 0 ? 0 : n); + } - /** - * Reverses the wrapped array so the first element becomes the last, the - * second element becomes the second to last, and so on. - * - * **Note:** This method mutates the wrapped array. - * - * @name reverse - * @memberOf _ - * @category Chain - * @returns {Object} Returns the new reversed `lodash` wrapper instance. - * @example - * - * var array = [1, 2, 3]; - * - * _(array).reverse().value() - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] - */ - function wrapperReverse() { - var value = this.__wrapped__; - - var interceptor = function(value) { - return (wrapped && wrapped.__dir__ < 0) ? value : value.reverse(); - }; - if (value instanceof LazyWrapper) { - var wrapped = value; - if (this.__actions__.length) { - wrapped = new LazyWrapper(this); - } - wrapped = wrapped.reverse(); - wrapped.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined }); - return new LodashWrapper(wrapped, this.__chain__); - } - return this.thru(interceptor); - } + /** + * Creates a slice of `array` with `n` elements dropped from the end. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropRight([1, 2, 3]); + * // => [1, 2] + * + * _.dropRight([1, 2, 3], 2); + * // => [1] + * + * _.dropRight([1, 2, 3], 5); + * // => [] + * + * _.dropRight([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function dropRight(array, n, guard) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + n = length - (+n || 0); + return baseSlice(array, 0, n < 0 ? 0 : n); + } - /** - * Produces the result of coercing the unwrapped value to a string. - * - * @name toString - * @memberOf _ - * @category Chain - * @returns {string} Returns the coerced string value. - * @example - * - * _([1, 2, 3]).toString(); - * // => '1,2,3' - */ - function wrapperToString() { - return (this.value() + ''); - } + /** + * Creates a slice of `array` excluding elements dropped from the end. + * Elements are dropped until `predicate` returns falsey. The predicate is + * bound to `thisArg` and invoked with three arguments: (value, index, array). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that match the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropRightWhile([1, 2, 3], function(n) { + * return n > 1; + * }); + * // => [1] + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * // using the `_.matches` callback shorthand + * _.pluck(_.dropRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); + * // => ['barney', 'fred'] + * + * // using the `_.matchesProperty` callback shorthand + * _.pluck(_.dropRightWhile(users, 'active', false), 'user'); + * // => ['barney'] + * + * // using the `_.property` callback shorthand + * _.pluck(_.dropRightWhile(users, 'active'), 'user'); + * // => ['barney', 'fred', 'pebbles'] + */ + function dropRightWhile(array, predicate, thisArg) { + return array && array.length ? baseWhile(array, getCallback(predicate, thisArg, 3), true, true) : []; + } - /** - * Executes the chained sequence to extract the unwrapped value. - * - * @name value - * @memberOf _ - * @alias run, toJSON, valueOf - * @category Chain - * @returns {*} Returns the resolved unwrapped value. - * @example - * - * _([1, 2, 3]).value(); - * // => [1, 2, 3] - */ - function wrapperValue() { - return baseWrapperValue(this.__wrapped__, this.__actions__); - } + /** + * Creates a slice of `array` excluding elements dropped from the beginning. + * Elements are dropped until `predicate` returns falsey. The predicate is + * bound to `thisArg` and invoked with three arguments: (value, index, array). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropWhile([1, 2, 3], function(n) { + * return n < 3; + * }); + * // => [3] + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * // using the `_.matches` callback shorthand + * _.pluck(_.dropWhile(users, { 'user': 'barney', 'active': false }), 'user'); + * // => ['fred', 'pebbles'] + * + * // using the `_.matchesProperty` callback shorthand + * _.pluck(_.dropWhile(users, 'active', false), 'user'); + * // => ['pebbles'] + * + * // using the `_.property` callback shorthand + * _.pluck(_.dropWhile(users, 'active'), 'user'); + * // => ['barney', 'fred', 'pebbles'] + */ + function dropWhile(array, predicate, thisArg) { + return array && array.length ? baseWhile(array, getCallback(predicate, thisArg, 3), true) : []; + } - /*------------------------------------------------------------------------*/ - - /** - * Creates an array of elements corresponding to the given keys, or indexes, - * of `collection`. Keys may be specified as individual arguments or as arrays - * of keys. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {...(number|number[]|string|string[])} [props] The property names - * or indexes of elements to pick, specified individually or in arrays. - * @returns {Array} Returns the new array of picked elements. - * @example - * - * _.at(['a', 'b', 'c'], [0, 2]); - * // => ['a', 'c'] - * - * _.at(['barney', 'fred', 'pebbles'], 0, 2); - * // => ['barney', 'pebbles'] - */ - var at = restParam(function(collection, props) { - return baseAt(collection, baseFlatten(props)); - }); - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` through `iteratee`. The corresponding value - * of each key is the number of times the key was returned by `iteratee`. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.countBy([4.3, 6.1, 6.4], function(n) { - * return Math.floor(n); - * }); - * // => { '4': 1, '6': 2 } - * - * _.countBy([4.3, 6.1, 6.4], function(n) { - * return this.floor(n); - * }, Math); - * // => { '4': 1, '6': 2 } - * - * _.countBy(['one', 'two', 'three'], 'length'); - * // => { '3': 2, '5': 1 } - */ - var countBy = createAggregator(function(result, value, key) { - hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1); - }); - - /** - * Checks if `predicate` returns truthy for **all** elements of `collection`. - * The predicate is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias all - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - * @example - * - * _.every([true, 1, null, 'yes'], Boolean); - * // => false - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.every(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // using the `_.matchesProperty` callback shorthand - * _.every(users, 'active', false); - * // => true - * - * // using the `_.property` callback shorthand - * _.every(users, 'active'); - * // => false - */ - function every(collection, predicate, thisArg) { - var func = isArray(collection) ? arrayEvery : baseEvery; - if (thisArg && isIterateeCall(collection, predicate, thisArg)) { - predicate = undefined; - } - if (typeof predicate != 'function' || thisArg !== undefined) { - predicate = getCallback(predicate, thisArg, 3); - } - return func(collection, predicate); - } + /** + * Fills elements of `array` with `value` from `start` up to, but not + * including, `end`. + * + * **Note:** This method mutates `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to fill. + * @param {*} value The value to fill `array` with. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3]; + * + * _.fill(array, 'a'); + * console.log(array); + * // => ['a', 'a', 'a'] + * + * _.fill(Array(3), 2); + * // => [2, 2, 2] + * + * _.fill([4, 6, 8], '*', 1, 2); + * // => [4, '*', 8] + */ + function fill(array, value, start, end) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { + start = 0; + end = length; + } + return baseFill(array, value, start, end); + } - /** - * Iterates over elements of `collection`, returning an array of all elements - * `predicate` returns truthy for. The predicate is bound to `thisArg` and - * invoked with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias select - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the new filtered array. - * @example - * - * _.filter([4, 5, 6], function(n) { - * return n % 2 == 0; - * }); - * // => [4, 6] - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.filter(users, { 'age': 36, 'active': true }), 'user'); - * // => ['barney'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.filter(users, 'active', false), 'user'); - * // => ['fred'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.filter(users, 'active'), 'user'); - * // => ['barney'] - */ - function filter(collection, predicate, thisArg) { - var func = isArray(collection) ? arrayFilter : baseFilter; - predicate = getCallback(predicate, thisArg, 3); - return func(collection, predicate); - } + /** + * This method is like `_.find` except that it returns the index of the first + * element `predicate` returns truthy for instead of the element itself. + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.findIndex(users, function(chr) { + * return chr.user == 'barney'; + * }); + * // => 0 + * + * // using the `_.matches` callback shorthand + * _.findIndex(users, { 'user': 'fred', 'active': false }); + * // => 1 + * + * // using the `_.matchesProperty` callback shorthand + * _.findIndex(users, 'active', false); + * // => 0 + * + * // using the `_.property` callback shorthand + * _.findIndex(users, 'active'); + * // => 2 + */ + var findIndex = createFindIndex(); + + /** + * This method is like `_.findIndex` except that it iterates over elements + * of `collection` from right to left. + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.findLastIndex(users, function(chr) { + * return chr.user == 'pebbles'; + * }); + * // => 2 + * + * // using the `_.matches` callback shorthand + * _.findLastIndex(users, { 'user': 'barney', 'active': true }); + * // => 0 + * + * // using the `_.matchesProperty` callback shorthand + * _.findLastIndex(users, 'active', false); + * // => 2 + * + * // using the `_.property` callback shorthand + * _.findLastIndex(users, 'active'); + * // => 0 + */ + var findLastIndex = createFindIndex(true); + + /** + * Gets the first element of `array`. + * + * @static + * @memberOf _ + * @alias head + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the first element of `array`. + * @example + * + * _.first([1, 2, 3]); + * // => 1 + * + * _.first([]); + * // => undefined + */ + function first(array) { + return array ? array[0] : undefined; + } - /** - * Iterates over elements of `collection`, returning the first element - * `predicate` returns truthy for. The predicate is bound to `thisArg` and - * invoked with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias detect - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false }, - * { 'user': 'pebbles', 'age': 1, 'active': true } - * ]; - * - * _.result(_.find(users, function(chr) { - * return chr.age < 40; - * }), 'user'); - * // => 'barney' - * - * // using the `_.matches` callback shorthand - * _.result(_.find(users, { 'age': 1, 'active': true }), 'user'); - * // => 'pebbles' - * - * // using the `_.matchesProperty` callback shorthand - * _.result(_.find(users, 'active', false), 'user'); - * // => 'fred' - * - * // using the `_.property` callback shorthand - * _.result(_.find(users, 'active'), 'user'); - * // => 'barney' - */ - var find = createFind(baseEach); - - /** - * This method is like `_.find` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * _.findLast([1, 2, 3, 4], function(n) { - * return n % 2 == 1; - * }); - * // => 3 - */ - var findLast = createFind(baseEachRight, true); - - /** - * Performs a deep comparison between each element in `collection` and the - * source object, returning the first element that has equivalent property - * values. - * - * **Note:** This method supports comparing arrays, booleans, `Date` objects, - * numbers, `Object` objects, regexes, and strings. Objects are compared by - * their own, not inherited, enumerable properties. For comparing a single - * own or inherited property value see `_.matchesProperty`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Object} source The object of property values to match. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * _.result(_.findWhere(users, { 'age': 36, 'active': true }), 'user'); - * // => 'barney' - * - * _.result(_.findWhere(users, { 'age': 40, 'active': false }), 'user'); - * // => 'fred' - */ - function findWhere(collection, source) { - return find(collection, baseMatches(source)); - } + /** + * Flattens a nested array. If `isDeep` is `true` the array is recursively + * flattened, otherwise it is only flattened a single level. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to flatten. + * @param {boolean} [isDeep] Specify a deep flatten. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flatten([1, [2, 3, [4]]]); + * // => [1, 2, 3, [4]] + * + * // using `isDeep` + * _.flatten([1, [2, 3, [4]]], true); + * // => [1, 2, 3, 4] + */ + function flatten(array, isDeep, guard) { + var length = array ? array.length : 0; + if (guard && isIterateeCall(array, isDeep, guard)) { + isDeep = false; + } + return length ? baseFlatten(array, isDeep) : []; + } - /** - * Iterates over elements of `collection` invoking `iteratee` for each element. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). Iteratee functions may exit iteration early - * by explicitly returning `false`. - * - * **Note:** As with other "Collections" methods, objects with a "length" property - * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` - * may be used for object iteration. - * - * @static - * @memberOf _ - * @alias each - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array|Object|string} Returns `collection`. - * @example - * - * _([1, 2]).forEach(function(n) { - * console.log(n); - * }).value(); - * // => logs each value from left to right and returns the array - * - * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) { - * console.log(n, key); - * }); - * // => logs each value-key pair and returns the object (iteration order is not guaranteed) - */ - var forEach = createForEach(arrayEach, baseEach); - - /** - * This method is like `_.forEach` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @alias eachRight - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array|Object|string} Returns `collection`. - * @example - * - * _([1, 2]).forEachRight(function(n) { - * console.log(n); - * }).value(); - * // => logs each value from right to left and returns the array - */ - var forEachRight = createForEach(arrayEachRight, baseEachRight); - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` through `iteratee`. The corresponding value - * of each key is an array of the elements responsible for generating the key. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.groupBy([4.2, 6.1, 6.4], function(n) { - * return Math.floor(n); - * }); - * // => { '4': [4.2], '6': [6.1, 6.4] } - * - * _.groupBy([4.2, 6.1, 6.4], function(n) { - * return this.floor(n); - * }, Math); - * // => { '4': [4.2], '6': [6.1, 6.4] } - * - * // using the `_.property` callback shorthand - * _.groupBy(['one', 'two', 'three'], 'length'); - * // => { '3': ['one', 'two'], '5': ['three'] } - */ - var groupBy = createAggregator(function(result, value, key) { - if (hasOwnProperty.call(result, key)) { - result[key].push(value); - } else { - result[key] = [value]; - } - }); - - /** - * Checks if `value` is in `collection` using - * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it is used as the offset - * from the end of `collection`. - * - * @static - * @memberOf _ - * @alias contains, include - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {*} target The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. - * @returns {boolean} Returns `true` if a matching element is found, else `false`. - * @example - * - * _.includes([1, 2, 3], 1); - * // => true - * - * _.includes([1, 2, 3], 1, 2); - * // => false - * - * _.includes({ 'user': 'fred', 'age': 40 }, 'fred'); - * // => true - * - * _.includes('pebbles', 'eb'); - * // => true - */ - function includes(collection, target, fromIndex, guard) { - var length = collection ? getLength(collection) : 0; - if (!isLength(length)) { - collection = values(collection); - length = collection.length; - } - if (typeof fromIndex != 'number' || (guard && isIterateeCall(target, fromIndex, guard))) { - fromIndex = 0; - } else { - fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0); - } - return (typeof collection == 'string' || !isArray(collection) && isString(collection)) - ? (fromIndex <= length && collection.indexOf(target, fromIndex) > -1) - : (!!length && getIndexOf(collection, target, fromIndex) > -1); - } + /** + * Recursively flattens a nested array. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to recursively flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flattenDeep([1, [2, 3, [4]]]); + * // => [1, 2, 3, 4] + */ + function flattenDeep(array) { + var length = array ? array.length : 0; + return length ? baseFlatten(array, true) : []; + } - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` through `iteratee`. The corresponding value - * of each key is the last element responsible for generating the key. The - * iteratee function is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * var keyData = [ - * { 'dir': 'left', 'code': 97 }, - * { 'dir': 'right', 'code': 100 } - * ]; - * - * _.indexBy(keyData, 'dir'); - * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } - * - * _.indexBy(keyData, function(object) { - * return String.fromCharCode(object.code); - * }); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - * - * _.indexBy(keyData, function(object) { - * return this.fromCharCode(object.code); - * }, String); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - */ - var indexBy = createAggregator(function(result, value, key) { - result[key] = value; - }); - - /** - * Invokes the method at `path` of each element in `collection`, returning - * an array of the results of each invoked method. Any additional arguments - * are provided to each invoked method. If `methodName` is a function it is - * invoked for, and `this` bound to, each element in `collection`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Array|Function|string} path The path of the method to invoke or - * the function invoked per iteration. - * @param {...*} [args] The arguments to invoke the method with. - * @returns {Array} Returns the array of results. - * @example - * - * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); - * // => [[1, 5, 7], [1, 2, 3]] - * - * _.invoke([123, 456], String.prototype.split, ''); - * // => [['1', '2', '3'], ['4', '5', '6']] - */ - var invoke = restParam(function(collection, path, args) { - var index = -1, - isFunc = typeof path == 'function', - isProp = isKey(path), - result = isArrayLike(collection) ? Array(collection.length) : []; - - baseEach(collection, function(value) { - var func = isFunc ? path : ((isProp && value != null) ? value[path] : undefined); - result[++index] = func ? func.apply(value, args) : invokePath(value, path, args); - }); - return result; - }); - - /** - * Creates an array of values by running each element in `collection` through - * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three - * arguments: (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. - * - * The guarded methods are: - * `ary`, `callback`, `chunk`, `clone`, `create`, `curry`, `curryRight`, - * `drop`, `dropRight`, `every`, `fill`, `flatten`, `invert`, `max`, `min`, - * `parseInt`, `slice`, `sortBy`, `take`, `takeRight`, `template`, `trim`, - * `trimLeft`, `trimRight`, `trunc`, `random`, `range`, `sample`, `some`, - * `sum`, `uniq`, and `words` - * - * @static - * @memberOf _ - * @alias collect - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new mapped array. - * @example - * - * function timesThree(n) { - * return n * 3; - * } - * - * _.map([1, 2], timesThree); - * // => [3, 6] - * - * _.map({ 'a': 1, 'b': 2 }, timesThree); - * // => [3, 6] (iteration order is not guaranteed) - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * // using the `_.property` callback shorthand - * _.map(users, 'user'); - * // => ['barney', 'fred'] - */ - function map(collection, iteratee, thisArg) { - var func = isArray(collection) ? arrayMap : baseMap; - iteratee = getCallback(iteratee, thisArg, 3); - return func(collection, iteratee); - } + /** + * Gets the index at which the first occurrence of `value` is found in `array` + * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. If `fromIndex` is negative, it is used as the offset + * from the end of `array`. If `array` is sorted providing `true` for `fromIndex` + * performs a faster binary search. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {boolean|number} [fromIndex=0] The index to search from or `true` + * to perform a binary search on a sorted array. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.indexOf([1, 2, 1, 2], 2); + * // => 1 + * + * // using `fromIndex` + * _.indexOf([1, 2, 1, 2], 2, 2); + * // => 3 + * + * // performing a binary search + * _.indexOf([1, 1, 2, 2], 2, true); + * // => 2 + */ + function indexOf(array, value, fromIndex) { + var length = array ? array.length : 0; + if (!length) { + return -1; + } + if (typeof fromIndex == 'number') { + fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex; + } else if (fromIndex) { + var index = binaryIndex(array, value); + if (index < length && (value === value ? value === array[index] : array[index] !== array[index])) { + return index; + } + return -1; + } + return baseIndexOf(array, value, fromIndex || 0); + } - /** - * Creates an array of elements split into two groups, the first of which - * contains elements `predicate` returns truthy for, while the second of which - * contains elements `predicate` returns falsey for. The predicate is bound - * to `thisArg` and invoked with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the array of grouped elements. - * @example - * - * _.partition([1, 2, 3], function(n) { - * return n % 2; - * }); - * // => [[1, 3], [2]] - * - * _.partition([1.2, 2.3, 3.4], function(n) { - * return this.floor(n) % 2; - * }, Math); - * // => [[1.2, 3.4], [2.3]] - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true }, - * { 'user': 'pebbles', 'age': 1, 'active': false } - * ]; - * - * var mapper = function(array) { - * return _.pluck(array, 'user'); - * }; - * - * // using the `_.matches` callback shorthand - * _.map(_.partition(users, { 'age': 1, 'active': false }), mapper); - * // => [['pebbles'], ['barney', 'fred']] - * - * // using the `_.matchesProperty` callback shorthand - * _.map(_.partition(users, 'active', false), mapper); - * // => [['barney', 'pebbles'], ['fred']] - * - * // using the `_.property` callback shorthand - * _.map(_.partition(users, 'active'), mapper); - * // => [['fred'], ['barney', 'pebbles']] - */ - var partition = createAggregator(function(result, value, key) { - result[key ? 0 : 1].push(value); - }, function() { return [[], []]; }); - - /** - * Gets the property value of `path` from all elements in `collection`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Array|string} path The path of the property to pluck. - * @returns {Array} Returns the property values. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 } - * ]; - * - * _.pluck(users, 'user'); - * // => ['barney', 'fred'] - * - * var userIndex = _.indexBy(users, 'user'); - * _.pluck(userIndex, 'age'); - * // => [36, 40] (iteration order is not guaranteed) - */ - function pluck(collection, path) { - return map(collection, property(path)); - } + /** + * Gets all but the last element of `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.initial([1, 2, 3]); + * // => [1, 2] + */ + function initial(array) { + return dropRight(array, 1); + } - /** - * Reduces `collection` to a value which is the accumulated result of running - * each element in `collection` through `iteratee`, where each successive - * invocation is supplied the return value of the previous. If `accumulator` - * is not provided the first element of `collection` is used as the initial - * value. The `iteratee` is bound to `thisArg` and invoked with four arguments: - * (accumulator, value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.reduce`, `_.reduceRight`, and `_.transform`. - * - * The guarded methods are: - * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `sortByAll`, - * and `sortByOrder` - * - * @static - * @memberOf _ - * @alias foldl, inject - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {*} Returns the accumulated value. - * @example - * - * _.reduce([1, 2], function(total, n) { - * return total + n; - * }); - * // => 3 - * - * _.reduce({ 'a': 1, 'b': 2 }, function(result, n, key) { - * result[key] = n * 3; - * return result; - * }, {}); - * // => { 'a': 3, 'b': 6 } (iteration order is not guaranteed) - */ - var reduce = createReduce(arrayReduce, baseEach); - - /** - * This method is like `_.reduce` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @alias foldr - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {*} Returns the accumulated value. - * @example - * - * var array = [[0, 1], [2, 3], [4, 5]]; - * - * _.reduceRight(array, function(flattened, other) { - * return flattened.concat(other); - * }, []); - * // => [4, 5, 2, 3, 0, 1] - */ - var reduceRight = createReduce(arrayReduceRight, baseEachRight); - - /** - * The opposite of `_.filter`; this method returns the elements of `collection` - * that `predicate` does **not** return truthy for. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the new filtered array. - * @example - * - * _.reject([1, 2, 3, 4], function(n) { - * return n % 2 == 0; - * }); - * // => [1, 3] - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.reject(users, { 'age': 40, 'active': true }), 'user'); - * // => ['barney'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.reject(users, 'active', false), 'user'); - * // => ['fred'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.reject(users, 'active'), 'user'); - * // => ['barney'] - */ - function reject(collection, predicate, thisArg) { - var func = isArray(collection) ? arrayFilter : baseFilter; - predicate = getCallback(predicate, thisArg, 3); - return func(collection, function(value, index, collection) { - return !predicate(value, index, collection); - }); - } + /** + * Creates an array of unique values that are included in all of the provided + * arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of shared values. + * @example + * _.intersection([1, 2], [4, 2], [2, 1]); + * // => [2] + */ + var intersection = restParam(function(arrays) { + var othLength = arrays.length, + othIndex = othLength, + caches = Array(length), + indexOf = getIndexOf(), + isCommon = indexOf == baseIndexOf, + result = []; + + while (othIndex--) { + var value = (arrays[othIndex] = isArrayLike((value = arrays[othIndex])) ? value : []); + caches[othIndex] = isCommon && value.length >= 120 ? createCache(othIndex && value) : null; + } + var array = arrays[0], + index = -1, + length = array ? array.length : 0, + seen = caches[0]; + + outer: while (++index < length) { + value = array[index]; + if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value, 0)) < 0) { + var othIndex = othLength; + while (--othIndex) { + var cache = caches[othIndex]; + if ((cache ? cacheIndexOf(cache, value) : indexOf(arrays[othIndex], value, 0)) < 0) { + continue outer; + } + } + if (seen) { + seen.push(value); + } + result.push(value); + } + } + return result; + }); + + /** + * Gets the last element of `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the last element of `array`. + * @example + * + * _.last([1, 2, 3]); + * // => 3 + */ + function last(array) { + var length = array ? array.length : 0; + return length ? array[length - 1] : undefined; + } - /** - * Gets a random element or `n` random elements from a collection. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to sample. - * @param {number} [n] The number of elements to sample. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {*} Returns the random sample(s). - * @example - * - * _.sample([1, 2, 3, 4]); - * // => 2 - * - * _.sample([1, 2, 3, 4], 2); - * // => [3, 1] - */ - function sample(collection, n, guard) { - if (guard ? isIterateeCall(collection, n, guard) : n == null) { - collection = toIterable(collection); - var length = collection.length; - return length > 0 ? collection[baseRandom(0, length - 1)] : undefined; - } - var index = -1, - result = toArray(collection), - length = result.length, - lastIndex = length - 1; - - n = nativeMin(n < 0 ? 0 : (+n || 0), length); - while (++index < n) { - var rand = baseRandom(index, lastIndex), - value = result[rand]; - - result[rand] = result[index]; - result[index] = value; - } - result.length = n; - return result; - } + /** + * This method is like `_.indexOf` except that it iterates over elements of + * `array` from right to left. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {boolean|number} [fromIndex=array.length-1] The index to search from + * or `true` to perform a binary search on a sorted array. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.lastIndexOf([1, 2, 1, 2], 2); + * // => 3 + * + * // using `fromIndex` + * _.lastIndexOf([1, 2, 1, 2], 2, 2); + * // => 1 + * + * // performing a binary search + * _.lastIndexOf([1, 1, 2, 2], 2, true); + * // => 3 + */ + function lastIndexOf(array, value, fromIndex) { + var length = array ? array.length : 0; + if (!length) { + return -1; + } + var index = length; + if (typeof fromIndex == 'number') { + index = + (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1; + } else if (fromIndex) { + index = binaryIndex(array, value, true) - 1; + var other = array[index]; + if (value === value ? value === other : other !== other) { + return index; + } + return -1; + } + if (value !== value) { + return indexOfNaN(array, index, true); + } + while (index--) { + if (array[index] === value) { + return index; + } + } + return -1; + } - /** - * Creates an array of shuffled values, using a version of the - * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to shuffle. - * @returns {Array} Returns the new shuffled array. - * @example - * - * _.shuffle([1, 2, 3, 4]); - * // => [4, 1, 3, 2] - */ - function shuffle(collection) { - return sample(collection, POSITIVE_INFINITY); - } + /** + * Removes all provided values from `array` using + * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. + * + * **Note:** Unlike `_.without`, this method mutates `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to modify. + * @param {...*} [values] The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3, 1, 2, 3]; + * + * _.pull(array, 2, 3); + * console.log(array); + * // => [1, 1] + */ + function pull() { + var args = arguments, + array = args[0]; + + if (!(array && array.length)) { + return array; + } + var index = 0, + indexOf = getIndexOf(), + length = args.length; + + while (++index < length) { + var fromIndex = 0, + value = args[index]; + + while ((fromIndex = indexOf(array, value, fromIndex)) > -1) { + splice.call(array, fromIndex, 1); + } + } + return array; + } - /** - * Gets the size of `collection` by returning its length for array-like - * values or the number of own enumerable properties for objects. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @returns {number} Returns the size of `collection`. - * @example - * - * _.size([1, 2, 3]); - * // => 3 - * - * _.size({ 'a': 1, 'b': 2 }); - * // => 2 - * - * _.size('pebbles'); - * // => 7 - */ - function size(collection) { - var length = collection ? getLength(collection) : 0; - return isLength(length) ? length : keys(collection).length; - } + /** + * Removes elements from `array` corresponding to the given indexes and returns + * an array of the removed elements. Indexes may be specified as an array of + * indexes or as individual arguments. + * + * **Note:** Unlike `_.at`, this method mutates `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to modify. + * @param {...(number|number[])} [indexes] The indexes of elements to remove, + * specified as individual indexes or arrays of indexes. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = [5, 10, 15, 20]; + * var evens = _.pullAt(array, 1, 3); + * + * console.log(array); + * // => [5, 15] + * + * console.log(evens); + * // => [10, 20] + */ + var pullAt = restParam(function(array, indexes) { + indexes = baseFlatten(indexes); + + var result = baseAt(array, indexes); + basePullAt(array, indexes.sort(baseCompareAscending)); + return result; + }); + + /** + * Removes all elements from `array` that `predicate` returns truthy for + * and returns an array of the removed elements. The predicate is bound to + * `thisArg` and invoked with three arguments: (value, index, array). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * **Note:** Unlike `_.filter`, this method mutates `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to modify. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = [1, 2, 3, 4]; + * var evens = _.remove(array, function(n) { + * return n % 2 == 0; + * }); + * + * console.log(array); + * // => [1, 3] + * + * console.log(evens); + * // => [2, 4] + */ + function remove(array, predicate, thisArg) { + var result = []; + if (!(array && array.length)) { + return result; + } + var index = -1, + indexes = [], + length = array.length; + + predicate = getCallback(predicate, thisArg, 3); + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result.push(value); + indexes.push(index); + } + } + basePullAt(array, indexes); + return result; + } - /** - * Checks if `predicate` returns truthy for **any** element of `collection`. - * The function returns as soon as it finds a passing value and does not iterate - * over the entire collection. The predicate is bound to `thisArg` and invoked - * with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias any - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - * @example - * - * _.some([null, 0, 'yes', false], Boolean); - * // => true - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.some(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // using the `_.matchesProperty` callback shorthand - * _.some(users, 'active', false); - * // => true - * - * // using the `_.property` callback shorthand - * _.some(users, 'active'); - * // => true - */ - function some(collection, predicate, thisArg) { - var func = isArray(collection) ? arraySome : baseSome; - if (thisArg && isIterateeCall(collection, predicate, thisArg)) { - predicate = undefined; - } - if (typeof predicate != 'function' || thisArg !== undefined) { - predicate = getCallback(predicate, thisArg, 3); - } - return func(collection, predicate); - } + /** + * Gets all but the first element of `array`. + * + * @static + * @memberOf _ + * @alias tail + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.rest([1, 2, 3]); + * // => [2, 3] + */ + function rest(array) { + return drop(array, 1); + } - /** - * Creates an array of elements, sorted in ascending order by the results of - * running each element in a collection through `iteratee`. This method performs - * a stable sort, that is, it preserves the original sort order of equal elements. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new sorted array. - * @example - * - * _.sortBy([1, 2, 3], function(n) { - * return Math.sin(n); - * }); - * // => [3, 1, 2] - * - * _.sortBy([1, 2, 3], function(n) { - * return this.sin(n); - * }, Math); - * // => [3, 1, 2] - * - * var users = [ - * { 'user': 'fred' }, - * { 'user': 'pebbles' }, - * { 'user': 'barney' } - * ]; - * - * // using the `_.property` callback shorthand - * _.pluck(_.sortBy(users, 'user'), 'user'); - * // => ['barney', 'fred', 'pebbles'] - */ - function sortBy(collection, iteratee, thisArg) { - if (collection == null) { - return []; - } - if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { - iteratee = undefined; - } - var index = -1; - iteratee = getCallback(iteratee, thisArg, 3); + /** + * Creates a slice of `array` from `start` up to, but not including, `end`. + * + * **Note:** This method is used instead of `Array#slice` to support node + * lists in IE < 9 and to ensure dense arrays are returned. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function slice(array, start, end) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { + start = 0; + end = length; + } + return baseSlice(array, start, end); + } - var result = baseMap(collection, function(value, key, collection) { - return { 'criteria': iteratee(value, key, collection), 'index': ++index, 'value': value }; - }); - return baseSortBy(result, compareAscending); - } + /** + * Uses a binary search to determine the lowest index at which `value` should + * be inserted into `array` in order to maintain its sort order. If an iteratee + * function is provided it is invoked for `value` and each element of `array` + * to compute their sort ranking. The iteratee is bound to `thisArg` and + * invoked with one argument; (value). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedIndex([30, 50], 40); + * // => 1 + * + * _.sortedIndex([4, 4, 5, 5], 5); + * // => 2 + * + * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } }; + * + * // using an iteratee function + * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) { + * return this.data[word]; + * }, dict); + * // => 1 + * + * // using the `_.property` callback shorthand + * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); + * // => 1 + */ + var sortedIndex = createSortedIndex(); + + /** + * This method is like `_.sortedIndex` except that it returns the highest + * index at which `value` should be inserted into `array` in order to + * maintain its sort order. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedLastIndex([4, 4, 5, 5], 5); + * // => 4 + */ + var sortedLastIndex = createSortedIndex(true); + + /** + * Creates a slice of `array` with `n` elements taken from the beginning. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.take([1, 2, 3]); + * // => [1] + * + * _.take([1, 2, 3], 2); + * // => [1, 2] + * + * _.take([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.take([1, 2, 3], 0); + * // => [] + */ + function take(array, n, guard) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + return baseSlice(array, 0, n < 0 ? 0 : n); + } - /** - * This method is like `_.sortBy` except that it can sort by multiple iteratees - * or property names. - * - * If a property name is provided for an iteratee the created `_.property` - * style callback returns the property value of the given element. - * - * If an object is provided for an iteratee the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {...(Function|Function[]|Object|Object[]|string|string[])} iteratees - * The iteratees to sort by, specified as individual values or arrays of values. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 42 }, - * { 'user': 'barney', 'age': 34 } - * ]; - * - * _.map(_.sortByAll(users, ['user', 'age']), _.values); - * // => [['barney', 34], ['barney', 36], ['fred', 42], ['fred', 48]] - * - * _.map(_.sortByAll(users, 'user', function(chr) { - * return Math.floor(chr.age / 10); - * }), _.values); - * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] - */ - var sortByAll = restParam(function(collection, iteratees) { - if (collection == null) { - return []; - } - var guard = iteratees[2]; - if (guard && isIterateeCall(iteratees[0], iteratees[1], guard)) { - iteratees.length = 1; - } - return baseSortByOrder(collection, baseFlatten(iteratees), []); - }); - - /** - * This method is like `_.sortByAll` except that it allows specifying the - * sort orders of the iteratees to sort by. If `orders` is unspecified, all - * values are sorted in ascending order. Otherwise, a value is sorted in - * ascending order if its corresponding order is "asc", and descending if "desc". - * - * If a property name is provided for an iteratee the created `_.property` - * style callback returns the property value of the given element. - * - * If an object is provided for an iteratee the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {boolean[]} [orders] The sort orders of `iteratees`. - * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 34 }, - * { 'user': 'fred', 'age': 42 }, - * { 'user': 'barney', 'age': 36 } - * ]; - * - * // sort by `user` in ascending order and by `age` in descending order - * _.map(_.sortByOrder(users, ['user', 'age'], ['asc', 'desc']), _.values); - * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] - */ - function sortByOrder(collection, iteratees, orders, guard) { - if (collection == null) { - return []; - } - if (guard && isIterateeCall(iteratees, orders, guard)) { - orders = undefined; - } - if (!isArray(iteratees)) { - iteratees = iteratees == null ? [] : [iteratees]; - } - if (!isArray(orders)) { - orders = orders == null ? [] : [orders]; - } - return baseSortByOrder(collection, iteratees, orders); - } + /** + * Creates a slice of `array` with `n` elements taken from the end. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeRight([1, 2, 3]); + * // => [3] + * + * _.takeRight([1, 2, 3], 2); + * // => [2, 3] + * + * _.takeRight([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.takeRight([1, 2, 3], 0); + * // => [] + */ + function takeRight(array, n, guard) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + n = length - (+n || 0); + return baseSlice(array, n < 0 ? 0 : n); + } - /** - * Performs a deep comparison between each element in `collection` and the - * source object, returning an array of all elements that have equivalent - * property values. - * - * **Note:** This method supports comparing arrays, booleans, `Date` objects, - * numbers, `Object` objects, regexes, and strings. Objects are compared by - * their own, not inherited, enumerable properties. For comparing a single - * own or inherited property value see `_.matchesProperty`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Object} source The object of property values to match. - * @returns {Array} Returns the new filtered array. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false, 'pets': ['hoppy'] }, - * { 'user': 'fred', 'age': 40, 'active': true, 'pets': ['baby puss', 'dino'] } - * ]; - * - * _.pluck(_.where(users, { 'age': 36, 'active': false }), 'user'); - * // => ['barney'] - * - * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user'); - * // => ['fred'] - */ - function where(collection, source) { - return filter(collection, baseMatches(source)); - } + /** + * Creates a slice of `array` with elements taken from the end. Elements are + * taken until `predicate` returns falsey. The predicate is bound to `thisArg` + * and invoked with three arguments: (value, index, array). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeRightWhile([1, 2, 3], function(n) { + * return n > 1; + * }); + * // => [2, 3] + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * // using the `_.matches` callback shorthand + * _.pluck(_.takeRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); + * // => ['pebbles'] + * + * // using the `_.matchesProperty` callback shorthand + * _.pluck(_.takeRightWhile(users, 'active', false), 'user'); + * // => ['fred', 'pebbles'] + * + * // using the `_.property` callback shorthand + * _.pluck(_.takeRightWhile(users, 'active'), 'user'); + * // => [] + */ + function takeRightWhile(array, predicate, thisArg) { + return array && array.length ? baseWhile(array, getCallback(predicate, thisArg, 3), false, true) : []; + } - /*------------------------------------------------------------------------*/ - - /** - * Gets the number of milliseconds that have elapsed since the Unix epoch - * (1 January 1970 00:00:00 UTC). - * - * @static - * @memberOf _ - * @category Date - * @example - * - * _.defer(function(stamp) { - * console.log(_.now() - stamp); - * }, _.now()); - * // => logs the number of milliseconds it took for the deferred function to be invoked - */ - var now = nativeNow || function() { - return new Date().getTime(); - }; - - /*------------------------------------------------------------------------*/ - - /** - * The opposite of `_.before`; this method creates a function that invokes - * `func` once it is called `n` or more times. - * - * @static - * @memberOf _ - * @category Function - * @param {number} n The number of calls before `func` is invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var saves = ['profile', 'settings']; - * - * var done = _.after(saves.length, function() { - * console.log('done saving!'); - * }); - * - * _.forEach(saves, function(type) { - * asyncSave({ 'type': type, 'complete': done }); - * }); - * // => logs 'done saving!' after the two async saves have completed - */ - function after(n, func) { - if (typeof func != 'function') { - if (typeof n == 'function') { - var temp = n; - n = func; - func = temp; - } else { - throw new TypeError(FUNC_ERROR_TEXT); - } - } - n = nativeIsFinite(n = +n) ? n : 0; - return function() { - if (--n < 1) { - return func.apply(this, arguments); - } - }; - } + /** + * Creates a slice of `array` with elements taken from the beginning. Elements + * are taken until `predicate` returns falsey. The predicate is bound to + * `thisArg` and invoked with three arguments: (value, index, array). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeWhile([1, 2, 3], function(n) { + * return n < 3; + * }); + * // => [1, 2] + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false}, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * // using the `_.matches` callback shorthand + * _.pluck(_.takeWhile(users, { 'user': 'barney', 'active': false }), 'user'); + * // => ['barney'] + * + * // using the `_.matchesProperty` callback shorthand + * _.pluck(_.takeWhile(users, 'active', false), 'user'); + * // => ['barney', 'fred'] + * + * // using the `_.property` callback shorthand + * _.pluck(_.takeWhile(users, 'active'), 'user'); + * // => [] + */ + function takeWhile(array, predicate, thisArg) { + return array && array.length ? baseWhile(array, getCallback(predicate, thisArg, 3)) : []; + } - /** - * Creates a function that accepts up to `n` arguments ignoring any - * additional arguments. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to cap arguments for. - * @param {number} [n=func.length] The arity cap. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Function} Returns the new function. - * @example - * - * _.map(['6', '8', '10'], _.ary(parseInt, 1)); - * // => [6, 8, 10] - */ - function ary(func, n, guard) { - if (guard && isIterateeCall(func, n, guard)) { - n = undefined; - } - n = (func && n == null) ? func.length : nativeMax(+n || 0, 0); - return createWrapper(func, ARY_FLAG, undefined, undefined, undefined, undefined, n); - } + /** + * Creates an array of unique values, in order, from all of the provided arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.union([1, 2], [4, 2], [2, 1]); + * // => [1, 2, 4] + */ + var union = restParam(function(arrays) { + return baseUniq(baseFlatten(arrays, false, true)); + }); + + /** + * Creates a duplicate-free version of an array, using + * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons, in which only the first occurence of each element + * is kept. Providing `true` for `isSorted` performs a faster search algorithm + * for sorted arrays. If an iteratee function is provided it is invoked for + * each element in the array to generate the criterion by which uniqueness + * is computed. The `iteratee` is bound to `thisArg` and invoked with three + * arguments: (value, index, array). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias unique + * @category Array + * @param {Array} array The array to inspect. + * @param {boolean} [isSorted] Specify the array is sorted. + * @param {Function|Object|string} [iteratee] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new duplicate-value-free array. + * @example + * + * _.uniq([2, 1, 2]); + * // => [2, 1] + * + * // using `isSorted` + * _.uniq([1, 1, 2], true); + * // => [1, 2] + * + * // using an iteratee function + * _.uniq([1, 2.5, 1.5, 2], function(n) { + * return this.floor(n); + * }, Math); + * // => [1, 2.5] + * + * // using the `_.property` callback shorthand + * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + function uniq(array, isSorted, iteratee, thisArg) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (isSorted != null && typeof isSorted != 'boolean') { + thisArg = iteratee; + iteratee = isIterateeCall(array, isSorted, thisArg) ? undefined : isSorted; + isSorted = false; + } + var callback = getCallback(); + if (!(iteratee == null && callback === baseCallback)) { + iteratee = callback(iteratee, thisArg, 3); + } + return isSorted && getIndexOf() == baseIndexOf + ? sortedUniq(array, iteratee) + : baseUniq(array, iteratee); + } - /** - * Creates a function that invokes `func`, with the `this` binding and arguments - * of the created function, while it is called less than `n` times. Subsequent - * calls to the created function return the result of the last `func` invocation. - * - * @static - * @memberOf _ - * @category Function - * @param {number} n The number of calls at which `func` is no longer invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * jQuery('#add').on('click', _.before(5, addContactToList)); - * // => allows adding up to 4 contacts to the list - */ - function before(n, func) { - var result; - if (typeof func != 'function') { - if (typeof n == 'function') { - var temp = n; - n = func; - func = temp; - } else { - throw new TypeError(FUNC_ERROR_TEXT); - } - } - return function() { - if (--n > 0) { - result = func.apply(this, arguments); - } - if (n <= 1) { - func = undefined; - } - return result; - }; - } + /** + * This method is like `_.zip` except that it accepts an array of grouped + * elements and creates an array regrouping the elements to their pre-zip + * configuration. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array of grouped elements to process. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]); + * // => [['fred', 30, true], ['barney', 40, false]] + * + * _.unzip(zipped); + * // => [['fred', 'barney'], [30, 40], [true, false]] + */ + function unzip(array) { + if (!(array && array.length)) { + return []; + } + var index = -1, + length = 0; + + array = arrayFilter(array, function(group) { + if (isArrayLike(group)) { + length = nativeMax(group.length, length); + return true; + } + }); + var result = Array(length); + while (++index < length) { + result[index] = arrayMap(array, baseProperty(index)); + } + return result; + } - /** - * Creates a function that invokes `func` with the `this` binding of `thisArg` - * and prepends any additional `_.bind` arguments to those provided to the - * bound function. - * - * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for partially applied arguments. - * - * **Note:** Unlike native `Function#bind` this method does not set the "length" - * property of bound functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var greet = function(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * }; - * - * var object = { 'user': 'fred' }; - * - * var bound = _.bind(greet, object, 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * // using placeholders - * var bound = _.bind(greet, object, _, '!'); - * bound('hi'); - * // => 'hi fred!' - */ - var bind = restParam(function(func, thisArg, partials) { - var bitmask = BIND_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, bind.placeholder); - bitmask |= PARTIAL_FLAG; - } - return createWrapper(func, bitmask, thisArg, partials, holders); - }); - - /** - * Binds methods of an object to the object itself, overwriting the existing - * method. Method names may be specified as individual arguments or as arrays - * of method names. If no method names are provided all enumerable function - * properties, own and inherited, of `object` are bound. - * - * **Note:** This method does not set the "length" property of bound functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Object} object The object to bind and assign the bound methods to. - * @param {...(string|string[])} [methodNames] The object method names to bind, - * specified as individual method names or arrays of method names. - * @returns {Object} Returns `object`. - * @example - * - * var view = { - * 'label': 'docs', - * 'onClick': function() { - * console.log('clicked ' + this.label); - * } - * }; - * - * _.bindAll(view); - * jQuery('#docs').on('click', view.onClick); - * // => logs 'clicked docs' when the element is clicked - */ - var bindAll = restParam(function(object, methodNames) { - methodNames = methodNames.length ? baseFlatten(methodNames) : functions(object); - - var index = -1, - length = methodNames.length; - - while (++index < length) { - var key = methodNames[index]; - object[key] = createWrapper(object[key], BIND_FLAG, object); - } - return object; - }); - - /** - * Creates a function that invokes the method at `object[key]` and prepends - * any additional `_.bindKey` arguments to those provided to the bound function. - * - * This method differs from `_.bind` by allowing bound functions to reference - * methods that may be redefined or don't yet exist. - * See [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) - * for more details. - * - * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * @static - * @memberOf _ - * @category Function - * @param {Object} object The object the method belongs to. - * @param {string} key The key of the method. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var object = { - * 'user': 'fred', - * 'greet': function(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * } - * }; - * - * var bound = _.bindKey(object, 'greet', 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * object.greet = function(greeting, punctuation) { - * return greeting + 'ya ' + this.user + punctuation; - * }; - * - * bound('!'); - * // => 'hiya fred!' - * - * // using placeholders - * var bound = _.bindKey(object, 'greet', _, '!'); - * bound('hi'); - * // => 'hiya fred!' - */ - var bindKey = restParam(function(object, key, partials) { - var bitmask = BIND_FLAG | BIND_KEY_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, bindKey.placeholder); - bitmask |= PARTIAL_FLAG; - } - return createWrapper(key, bitmask, object, partials, holders); - }); - - /** - * Creates a function that accepts one or more arguments of `func` that when - * called either invokes `func` returning its result, if all `func` arguments - * have been provided, or returns a function that accepts one or more of the - * remaining `func` arguments, and so on. The arity of `func` may be specified - * if `func.length` is not sufficient. - * - * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for provided arguments. - * - * **Note:** This method does not set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curry(abc); - * - * curried(1)(2)(3); - * // => [1, 2, 3] - * - * curried(1, 2)(3); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // using placeholders - * curried(1)(_, 3)(2); - * // => [1, 2, 3] - */ - var curry = createCurry(CURRY_FLAG); - - /** - * This method is like `_.curry` except that arguments are applied to `func` - * in the manner of `_.partialRight` instead of `_.partial`. - * - * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for provided arguments. - * - * **Note:** This method does not set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curryRight(abc); - * - * curried(3)(2)(1); - * // => [1, 2, 3] - * - * curried(2, 3)(1); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // using placeholders - * curried(3)(1, _)(2); - * // => [1, 2, 3] - */ - var curryRight = createCurry(CURRY_RIGHT_FLAG); - - /** - * Creates a debounced function that delays invoking `func` until after `wait` - * milliseconds have elapsed since the last time the debounced function was - * invoked. The debounced function comes with a `cancel` method to cancel - * delayed invocations. Provide an options object to indicate that `func` - * should be invoked on the leading and/or trailing edge of the `wait` timeout. - * Subsequent calls to the debounced function return the result of the last - * `func` invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked - * on the trailing edge of the timeout only if the the debounced function is - * invoked more than once during the `wait` timeout. - * - * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) - * for details over the differences between `_.debounce` and `_.throttle`. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to debounce. - * @param {number} [wait=0] The number of milliseconds to delay. - * @param {Object} [options] The options object. - * @param {boolean} [options.leading=false] Specify invoking on the leading - * edge of the timeout. - * @param {number} [options.maxWait] The maximum time `func` is allowed to be - * delayed before it is invoked. - * @param {boolean} [options.trailing=true] Specify invoking on the trailing - * edge of the timeout. - * @returns {Function} Returns the new debounced function. - * @example - * - * // avoid costly calculations while the window size is in flux - * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); - * - * // invoke `sendMail` when the click event is fired, debouncing subsequent calls - * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { - * 'leading': true, - * 'trailing': false - * })); - * - * // ensure `batchLog` is invoked once after 1 second of debounced calls - * var source = new EventSource('/stream'); - * jQuery(source).on('message', _.debounce(batchLog, 250, { - * 'maxWait': 1000 - * })); - * - * // cancel a debounced call - * var todoChanges = _.debounce(batchLog, 1000); - * Object.observe(models.todo, todoChanges); - * - * Object.observe(models, function(changes) { - * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { - * todoChanges.cancel(); - * } - * }, ['delete']); - * - * // ...at some point `models.todo` is changed - * models.todo.completed = true; - * - * // ...before 1 second has passed `models.todo` is deleted - * // which cancels the debounced `todoChanges` call - * delete models.todo; - */ - function debounce(func, wait, options) { - var args, - maxTimeoutId, - result, - stamp, - thisArg, - timeoutId, - trailingCall, - lastCalled = 0, - maxWait = false, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - wait = wait < 0 ? 0 : (+wait || 0); - if (options === true) { - var leading = true; - trailing = false; - } else if (isObject(options)) { - leading = !!options.leading; - maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); - trailing = 'trailing' in options ? !!options.trailing : trailing; - } + /** + * This method is like `_.unzip` except that it accepts an iteratee to specify + * how regrouped values should be combined. The `iteratee` is bound to `thisArg` + * and invoked with four arguments: (accumulator, value, index, group). + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array of grouped elements to process. + * @param {Function} [iteratee] The function to combine regrouped values. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip([1, 2], [10, 20], [100, 200]); + * // => [[1, 10, 100], [2, 20, 200]] + * + * _.unzipWith(zipped, _.add); + * // => [3, 30, 300] + */ + function unzipWith(array, iteratee, thisArg) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + var result = unzip(array); + if (iteratee == null) { + return result; + } + iteratee = bindCallback(iteratee, thisArg, 4); + return arrayMap(result, function(group) { + return arrayReduce(group, iteratee, undefined, true); + }); + } - function cancel() { - if (timeoutId) { - clearTimeout(timeoutId); - } - if (maxTimeoutId) { - clearTimeout(maxTimeoutId); - } - lastCalled = 0; - maxTimeoutId = timeoutId = trailingCall = undefined; - } + /** + * Creates an array excluding all provided values using + * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to filter. + * @param {...*} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.without([1, 2, 1, 3], 1, 2); + * // => [3] + */ + var without = restParam(function(array, values) { + return isArrayLike(array) ? baseDifference(array, values) : []; + }); + + /** + * Creates an array of unique values that is the [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) + * of the provided arrays. + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of values. + * @example + * + * _.xor([1, 2], [4, 2]); + * // => [1, 4] + */ + function xor() { + var index = -1, + length = arguments.length; + + while (++index < length) { + var array = arguments[index]; + if (isArrayLike(array)) { + var result = result + ? arrayPush(baseDifference(result, array), baseDifference(array, result)) + : array; + } + } + return result ? baseUniq(result) : []; + } - function complete(isCalled, id) { - if (id) { - clearTimeout(id); - } - maxTimeoutId = timeoutId = trailingCall = undefined; - if (isCalled) { - lastCalled = now(); - result = func.apply(thisArg, args); - if (!timeoutId && !maxTimeoutId) { - args = thisArg = undefined; - } - } - } + /** + * Creates an array of grouped elements, the first of which contains the first + * elements of the given arrays, the second of which contains the second elements + * of the given arrays, and so on. + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zip(['fred', 'barney'], [30, 40], [true, false]); + * // => [['fred', 30, true], ['barney', 40, false]] + */ + var zip = restParam(unzip); + + /** + * The inverse of `_.pairs`; this method returns an object composed from arrays + * of property names and values. Provide either a single two dimensional array, + * e.g. `[[key1, value1], [key2, value2]]` or two arrays, one of property names + * and one of corresponding values. + * + * @static + * @memberOf _ + * @alias object + * @category Array + * @param {Array} props The property names. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObject([['fred', 30], ['barney', 40]]); + * // => { 'fred': 30, 'barney': 40 } + * + * _.zipObject(['fred', 'barney'], [30, 40]); + * // => { 'fred': 30, 'barney': 40 } + */ + function zipObject(props, values) { + var index = -1, + length = props ? props.length : 0, + result = {}; + + if (length && !values && !isArray(props[0])) { + values = []; + } + while (++index < length) { + var key = props[index]; + if (values) { + result[key] = values[index]; + } else if (key) { + result[key[0]] = key[1]; + } + } + return result; + } - function delayed() { - var remaining = wait - (now() - stamp); - if (remaining <= 0 || remaining > wait) { - complete(trailingCall, maxTimeoutId); - } else { - timeoutId = setTimeout(delayed, remaining); - } - } + /** + * This method is like `_.zip` except that it accepts an iteratee to specify + * how grouped values should be combined. The `iteratee` is bound to `thisArg` + * and invoked with four arguments: (accumulator, value, index, group). + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @param {Function} [iteratee] The function to combine grouped values. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zipWith([1, 2], [10, 20], [100, 200], _.add); + * // => [111, 222] + */ + var zipWith = restParam(function(arrays) { + var length = arrays.length, + iteratee = length > 2 ? arrays[length - 2] : undefined, + thisArg = length > 1 ? arrays[length - 1] : undefined; + + if (length > 2 && typeof iteratee == 'function') { + length -= 2; + } else { + iteratee = length > 1 && typeof thisArg == 'function' ? (--length, thisArg) : undefined; + thisArg = undefined; + } + arrays.length = length; + return unzipWith(arrays, iteratee, thisArg); + }); + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` object that wraps `value` with explicit method + * chaining enabled. + * + * @static + * @memberOf _ + * @category Chain + * @param {*} value The value to wrap. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'pebbles', 'age': 1 } + * ]; + * + * var youngest = _.chain(users) + * .sortBy('age') + * .map(function(chr) { + * return chr.user + ' is ' + chr.age; + * }) + * .first() + * .value(); + * // => 'pebbles is 1' + */ + function chain(value) { + var result = lodash(value); + result.__chain__ = true; + return result; + } - function maxDelayed() { - complete(trailing, timeoutId); - } + /** + * This method invokes `interceptor` and returns `value`. The interceptor is + * bound to `thisArg` and invoked with one argument; (value). The purpose of + * this method is to "tap into" a method chain in order to perform operations + * on intermediate results within the chain. + * + * @static + * @memberOf _ + * @category Chain + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @param {*} [thisArg] The `this` binding of `interceptor`. + * @returns {*} Returns `value`. + * @example + * + * _([1, 2, 3]) + * .tap(function(array) { + * array.pop(); + * }) + * .reverse() + * .value(); + * // => [2, 1] + */ + function tap(value, interceptor, thisArg) { + interceptor.call(thisArg, value); + return value; + } - function debounced() { - args = arguments; - stamp = now(); - thisArg = this; - trailingCall = trailing && (timeoutId || !leading); + /** + * This method is like `_.tap` except that it returns the result of `interceptor`. + * + * @static + * @memberOf _ + * @category Chain + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @param {*} [thisArg] The `this` binding of `interceptor`. + * @returns {*} Returns the result of `interceptor`. + * @example + * + * _(' abc ') + * .chain() + * .trim() + * .thru(function(value) { + * return [value]; + * }) + * .value(); + * // => ['abc'] + */ + function thru(value, interceptor, thisArg) { + return interceptor.call(thisArg, value); + } - if (maxWait === false) { - var leadingCall = leading && !timeoutId; - } else { - if (!maxTimeoutId && !leading) { - lastCalled = stamp; - } - var remaining = maxWait - (stamp - lastCalled), - isCalled = remaining <= 0 || remaining > maxWait; + /** + * Enables explicit method chaining on the wrapper object. + * + * @name chain + * @memberOf _ + * @category Chain + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * // without explicit chaining + * _(users).first(); + * // => { 'user': 'barney', 'age': 36 } + * + * // with explicit chaining + * _(users).chain() + * .first() + * .pick('user') + * .value(); + * // => { 'user': 'barney' } + */ + function wrapperChain() { + return chain(this); + } - if (isCalled) { - if (maxTimeoutId) { - maxTimeoutId = clearTimeout(maxTimeoutId); - } - lastCalled = stamp; - result = func.apply(thisArg, args); - } - else if (!maxTimeoutId) { - maxTimeoutId = setTimeout(maxDelayed, remaining); - } - } - if (isCalled && timeoutId) { - timeoutId = clearTimeout(timeoutId); - } - else if (!timeoutId && wait !== maxWait) { - timeoutId = setTimeout(delayed, wait); - } - if (leadingCall) { - isCalled = true; - result = func.apply(thisArg, args); - } - if (isCalled && !timeoutId && !maxTimeoutId) { - args = thisArg = undefined; - } - return result; - } - debounced.cancel = cancel; - return debounced; - } + /** + * Executes the chained sequence and returns the wrapped result. + * + * @name commit + * @memberOf _ + * @category Chain + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2]; + * var wrapped = _(array).push(3); + * + * console.log(array); + * // => [1, 2] + * + * wrapped = wrapped.commit(); + * console.log(array); + * // => [1, 2, 3] + * + * wrapped.last(); + * // => 3 + * + * console.log(array); + * // => [1, 2, 3] + */ + function wrapperCommit() { + return new LodashWrapper(this.value(), this.__chain__); + } - /** - * Defers invoking the `func` until the current call stack has cleared. Any - * additional arguments are provided to `func` when it is invoked. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to defer. - * @param {...*} [args] The arguments to invoke the function with. - * @returns {number} Returns the timer id. - * @example - * - * _.defer(function(text) { - * console.log(text); - * }, 'deferred'); - * // logs 'deferred' after one or more milliseconds - */ - var defer = restParam(function(func, args) { - return baseDelay(func, 1, args); - }); - - /** - * Invokes `func` after `wait` milliseconds. Any additional arguments are - * provided to `func` when it is invoked. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {...*} [args] The arguments to invoke the function with. - * @returns {number} Returns the timer id. - * @example - * - * _.delay(function(text) { - * console.log(text); - * }, 1000, 'later'); - * // => logs 'later' after one second - */ - var delay = restParam(function(func, wait, args) { - return baseDelay(func, wait, args); - }); - - /** - * Creates a function that returns the result of invoking the provided - * functions with the `this` binding of the created function, where each - * successive invocation is supplied the return value of the previous. - * - * @static - * @memberOf _ - * @category Function - * @param {...Function} [funcs] Functions to invoke. - * @returns {Function} Returns the new function. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var addSquare = _.flow(_.add, square); - * addSquare(1, 2); - * // => 9 - */ - var flow = createFlow(); - - /** - * This method is like `_.flow` except that it creates a function that - * invokes the provided functions from right to left. - * - * @static - * @memberOf _ - * @alias backflow, compose - * @category Function - * @param {...Function} [funcs] Functions to invoke. - * @returns {Function} Returns the new function. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var addSquare = _.flowRight(square, _.add); - * addSquare(1, 2); - * // => 9 - */ - var flowRight = createFlow(true); - - /** - * Creates a function that memoizes the result of `func`. If `resolver` is - * provided it determines the cache key for storing the result based on the - * arguments provided to the memoized function. By default, the first argument - * provided to the memoized function is coerced to a string and used as the - * cache key. The `func` is invoked with the `this` binding of the memoized - * function. - * - * **Note:** The cache is exposed as the `cache` property on the memoized - * function. Its creation may be customized by replacing the `_.memoize.Cache` - * constructor with one whose instances implement the [`Map`](http://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-map-prototype-object) - * method interface of `get`, `has`, and `set`. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to have its output memoized. - * @param {Function} [resolver] The function to resolve the cache key. - * @returns {Function} Returns the new memoizing function. - * @example - * - * var upperCase = _.memoize(function(string) { - * return string.toUpperCase(); - * }); - * - * upperCase('fred'); - * // => 'FRED' - * - * // modifying the result cache - * upperCase.cache.set('fred', 'BARNEY'); - * upperCase('fred'); - * // => 'BARNEY' - * - * // replacing `_.memoize.Cache` - * var object = { 'user': 'fred' }; - * var other = { 'user': 'barney' }; - * var identity = _.memoize(_.identity); - * - * identity(object); - * // => { 'user': 'fred' } - * identity(other); - * // => { 'user': 'fred' } - * - * _.memoize.Cache = WeakMap; - * var identity = _.memoize(_.identity); - * - * identity(object); - * // => { 'user': 'fred' } - * identity(other); - * // => { 'user': 'barney' } - */ - function memoize(func, resolver) { - if (typeof func != 'function' || (resolver && typeof resolver != 'function')) { - throw new TypeError(FUNC_ERROR_TEXT); - } - var memoized = function() { - var args = arguments, - key = resolver ? resolver.apply(this, args) : args[0], - cache = memoized.cache; - - if (cache.has(key)) { - return cache.get(key); - } - var result = func.apply(this, args); - memoized.cache = cache.set(key, result); - return result; - }; - memoized.cache = new memoize.Cache; - return memoized; - } + /** + * Creates a new array joining a wrapped array with any additional arrays + * and/or values. + * + * @name concat + * @memberOf _ + * @category Chain + * @param {...*} [values] The values to concatenate. + * @returns {Array} Returns the new concatenated array. + * @example + * + * var array = [1]; + * var wrapped = _(array).concat(2, [3], [[4]]); + * + * console.log(wrapped.value()); + * // => [1, 2, 3, [4]] + * + * console.log(array); + * // => [1] + */ + var wrapperConcat = restParam(function(values) { + values = baseFlatten(values); + return this.thru(function(array) { + return arrayConcat(isArray(array) ? array : [toObject(array)], values); + }); + }); + + /** + * Creates a clone of the chained sequence planting `value` as the wrapped value. + * + * @name plant + * @memberOf _ + * @category Chain + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2]; + * var wrapped = _(array).map(function(value) { + * return Math.pow(value, 2); + * }); + * + * var other = [3, 4]; + * var otherWrapped = wrapped.plant(other); + * + * otherWrapped.value(); + * // => [9, 16] + * + * wrapped.value(); + * // => [1, 4] + */ + function wrapperPlant(value) { + var result, + parent = this; + + while (parent instanceof baseLodash) { + var clone = wrapperClone(parent); + if (result) { + previous.__wrapped__ = clone; + } else { + result = clone; + } + var previous = clone; + parent = parent.__wrapped__; + } + previous.__wrapped__ = value; + return result; + } - /** - * Creates a function that runs each argument through a corresponding - * transform function. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to wrap. - * @param {...(Function|Function[])} [transforms] The functions to transform - * arguments, specified as individual functions or arrays of functions. - * @returns {Function} Returns the new function. - * @example - * - * function doubled(n) { - * return n * 2; - * } - * - * function square(n) { - * return n * n; - * } - * - * var modded = _.modArgs(function(x, y) { - * return [x, y]; - * }, square, doubled); - * - * modded(1, 2); - * // => [1, 4] - * - * modded(5, 10); - * // => [25, 20] - */ - var modArgs = restParam(function(func, transforms) { - transforms = baseFlatten(transforms); - if (typeof func != 'function' || !arrayEvery(transforms, baseIsFunction)) { - throw new TypeError(FUNC_ERROR_TEXT); - } - var length = transforms.length; - return restParam(function(args) { - var index = nativeMin(args.length, length); - while (index--) { - args[index] = transforms[index](args[index]); - } - return func.apply(this, args); - }); - }); - - /** - * Creates a function that negates the result of the predicate `func`. The - * `func` predicate is invoked with the `this` binding and arguments of the - * created function. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} predicate The predicate to negate. - * @returns {Function} Returns the new function. - * @example - * - * function isEven(n) { - * return n % 2 == 0; - * } - * - * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); - * // => [1, 3, 5] - */ - function negate(predicate) { - if (typeof predicate != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return function() { - return !predicate.apply(this, arguments); - }; - } + /** + * Reverses the wrapped array so the first element becomes the last, the + * second element becomes the second to last, and so on. + * + * **Note:** This method mutates the wrapped array. + * + * @name reverse + * @memberOf _ + * @category Chain + * @returns {Object} Returns the new reversed `lodash` wrapper instance. + * @example + * + * var array = [1, 2, 3]; + * + * _(array).reverse().value() + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function wrapperReverse() { + var value = this.__wrapped__; + + var interceptor = function(value) { + return wrapped && wrapped.__dir__ < 0 ? value : value.reverse(); + }; + if (value instanceof LazyWrapper) { + var wrapped = value; + if (this.__actions__.length) { + wrapped = new LazyWrapper(this); + } + wrapped = wrapped.reverse(); + wrapped.__actions__.push({ func: thru, args: [interceptor], thisArg: undefined }); + return new LodashWrapper(wrapped, this.__chain__); + } + return this.thru(interceptor); + } - /** - * Creates a function that is restricted to invoking `func` once. Repeat calls - * to the function return the value of the first call. The `func` is invoked - * with the `this` binding and arguments of the created function. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var initialize = _.once(createApplication); - * initialize(); - * initialize(); - * // `initialize` invokes `createApplication` once - */ - function once(func) { - return before(2, func); - } + /** + * Produces the result of coercing the unwrapped value to a string. + * + * @name toString + * @memberOf _ + * @category Chain + * @returns {string} Returns the coerced string value. + * @example + * + * _([1, 2, 3]).toString(); + * // => '1,2,3' + */ + function wrapperToString() { + return this.value() + ''; + } - /** - * Creates a function that invokes `func` with `partial` arguments prepended - * to those provided to the new function. This method is like `_.bind` except - * it does **not** alter the `this` binding. - * - * The `_.partial.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method does not set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * var greet = function(greeting, name) { - * return greeting + ' ' + name; - * }; - * - * var sayHelloTo = _.partial(greet, 'hello'); - * sayHelloTo('fred'); - * // => 'hello fred' - * - * // using placeholders - * var greetFred = _.partial(greet, _, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - */ - var partial = createPartial(PARTIAL_FLAG); - - /** - * This method is like `_.partial` except that partially applied arguments - * are appended to those provided to the new function. - * - * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method does not set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * var greet = function(greeting, name) { - * return greeting + ' ' + name; - * }; - * - * var greetFred = _.partialRight(greet, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - * - * // using placeholders - * var sayHelloTo = _.partialRight(greet, 'hello', _); - * sayHelloTo('fred'); - * // => 'hello fred' - */ - var partialRight = createPartial(PARTIAL_RIGHT_FLAG); - - /** - * Creates a function that invokes `func` with arguments arranged according - * to the specified indexes where the argument value at the first index is - * provided as the first argument, the argument value at the second index is - * provided as the second argument, and so on. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to rearrange arguments for. - * @param {...(number|number[])} indexes The arranged argument indexes, - * specified as individual indexes or arrays of indexes. - * @returns {Function} Returns the new function. - * @example - * - * var rearged = _.rearg(function(a, b, c) { - * return [a, b, c]; - * }, 2, 0, 1); - * - * rearged('b', 'c', 'a') - * // => ['a', 'b', 'c'] - * - * var map = _.rearg(_.map, [1, 0]); - * map(function(n) { - * return n * 3; - * }, [1, 2, 3]); - * // => [3, 6, 9] - */ - var rearg = restParam(function(func, indexes) { - return createWrapper(func, REARG_FLAG, undefined, undefined, undefined, baseFlatten(indexes)); - }); - - /** - * Creates a function that invokes `func` with the `this` binding of the - * created function and arguments from `start` and beyond provided as an array. - * - * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters). - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.restParam(function(what, names) { - * return what + ' ' + _.initial(names).join(', ') + - * (_.size(names) > 1 ? ', & ' : '') + _.last(names); - * }); - * - * say('hello', 'fred', 'barney', 'pebbles'); - * // => 'hello fred, barney, & pebbles' - */ - function restParam(func, start) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - rest = Array(length); - - while (++index < length) { - rest[index] = args[start + index]; - } - switch (start) { - case 0: return func.call(this, rest); - case 1: return func.call(this, args[0], rest); - case 2: return func.call(this, args[0], args[1], rest); - } - var otherArgs = Array(start + 1); - index = -1; - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = rest; - return func.apply(this, otherArgs); - }; - } + /** + * Executes the chained sequence to extract the unwrapped value. + * + * @name value + * @memberOf _ + * @alias run, toJSON, valueOf + * @category Chain + * @returns {*} Returns the resolved unwrapped value. + * @example + * + * _([1, 2, 3]).value(); + * // => [1, 2, 3] + */ + function wrapperValue() { + return baseWrapperValue(this.__wrapped__, this.__actions__); + } - /** - * Creates a function that invokes `func` with the `this` binding of the created - * function and an array of arguments much like [`Function#apply`](https://es5.github.io/#x15.3.4.3). - * - * **Note:** This method is based on the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator). - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to spread arguments over. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.spread(function(who, what) { - * return who + ' says ' + what; - * }); - * - * say(['fred', 'hello']); - * // => 'fred says hello' - * - * // with a Promise - * var numbers = Promise.all([ - * Promise.resolve(40), - * Promise.resolve(36) - * ]); - * - * numbers.then(_.spread(function(x, y) { - * return x + y; - * })); - * // => a Promise of 76 - */ - function spread(func) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return function(array) { - return func.apply(this, array); - }; - } + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of elements corresponding to the given keys, or indexes, + * of `collection`. Keys may be specified as individual arguments or as arrays + * of keys. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {...(number|number[]|string|string[])} [props] The property names + * or indexes of elements to pick, specified individually or in arrays. + * @returns {Array} Returns the new array of picked elements. + * @example + * + * _.at(['a', 'b', 'c'], [0, 2]); + * // => ['a', 'c'] + * + * _.at(['barney', 'fred', 'pebbles'], 0, 2); + * // => ['barney', 'pebbles'] + */ + var at = restParam(function(collection, props) { + return baseAt(collection, baseFlatten(props)); + }); + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` through `iteratee`. The corresponding value + * of each key is the number of times the key was returned by `iteratee`. + * The `iteratee` is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.countBy([4.3, 6.1, 6.4], function(n) { + * return Math.floor(n); + * }); + * // => { '4': 1, '6': 2 } + * + * _.countBy([4.3, 6.1, 6.4], function(n) { + * return this.floor(n); + * }, Math); + * // => { '4': 1, '6': 2 } + * + * _.countBy(['one', 'two', 'three'], 'length'); + * // => { '3': 2, '5': 1 } + */ + var countBy = createAggregator(function(result, value, key) { + hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1); + }); + + /** + * Checks if `predicate` returns truthy for **all** elements of `collection`. + * The predicate is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias all + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * _.every([true, 1, null, 'yes'], Boolean); + * // => false + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false } + * ]; + * + * // using the `_.matches` callback shorthand + * _.every(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // using the `_.matchesProperty` callback shorthand + * _.every(users, 'active', false); + * // => true + * + * // using the `_.property` callback shorthand + * _.every(users, 'active'); + * // => false + */ + function every(collection, predicate, thisArg) { + var func = isArray(collection) ? arrayEvery : baseEvery; + if (thisArg && isIterateeCall(collection, predicate, thisArg)) { + predicate = undefined; + } + if (typeof predicate != 'function' || thisArg !== undefined) { + predicate = getCallback(predicate, thisArg, 3); + } + return func(collection, predicate); + } - /** - * Creates a throttled function that only invokes `func` at most once per - * every `wait` milliseconds. The throttled function comes with a `cancel` - * method to cancel delayed invocations. Provide an options object to indicate - * that `func` should be invoked on the leading and/or trailing edge of the - * `wait` timeout. Subsequent calls to the throttled function return the - * result of the last `func` call. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked - * on the trailing edge of the timeout only if the the throttled function is - * invoked more than once during the `wait` timeout. - * - * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) - * for details over the differences between `_.throttle` and `_.debounce`. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to throttle. - * @param {number} [wait=0] The number of milliseconds to throttle invocations to. - * @param {Object} [options] The options object. - * @param {boolean} [options.leading=true] Specify invoking on the leading - * edge of the timeout. - * @param {boolean} [options.trailing=true] Specify invoking on the trailing - * edge of the timeout. - * @returns {Function} Returns the new throttled function. - * @example - * - * // avoid excessively updating the position while scrolling - * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); - * - * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes - * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, { - * 'trailing': false - * })); - * - * // cancel a trailing throttled call - * jQuery(window).on('popstate', throttled.cancel); - */ - function throttle(func, wait, options) { - var leading = true, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (options === false) { - leading = false; - } else if (isObject(options)) { - leading = 'leading' in options ? !!options.leading : leading; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - return debounce(func, wait, { 'leading': leading, 'maxWait': +wait, 'trailing': trailing }); - } + /** + * Iterates over elements of `collection`, returning an array of all elements + * `predicate` returns truthy for. The predicate is bound to `thisArg` and + * invoked with three arguments: (value, index|key, collection). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias select + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the new filtered array. + * @example + * + * _.filter([4, 5, 6], function(n) { + * return n % 2 == 0; + * }); + * // => [4, 6] + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * // using the `_.matches` callback shorthand + * _.pluck(_.filter(users, { 'age': 36, 'active': true }), 'user'); + * // => ['barney'] + * + * // using the `_.matchesProperty` callback shorthand + * _.pluck(_.filter(users, 'active', false), 'user'); + * // => ['fred'] + * + * // using the `_.property` callback shorthand + * _.pluck(_.filter(users, 'active'), 'user'); + * // => ['barney'] + */ + function filter(collection, predicate, thisArg) { + var func = isArray(collection) ? arrayFilter : baseFilter; + predicate = getCallback(predicate, thisArg, 3); + return func(collection, predicate); + } - /** - * Creates a function that provides `value` to the wrapper function as its - * first argument. Any additional arguments provided to the function are - * appended to those provided to the wrapper function. The wrapper is invoked - * with the `this` binding of the created function. - * - * @static - * @memberOf _ - * @category Function - * @param {*} value The value to wrap. - * @param {Function} wrapper The wrapper function. - * @returns {Function} Returns the new function. - * @example - * - * var p = _.wrap(_.escape, function(func, text) { - * return '

' + func(text) + '

'; - * }); - * - * p('fred, barney, & pebbles'); - * // => '

fred, barney, & pebbles

' - */ - function wrap(value, wrapper) { - wrapper = wrapper == null ? identity : wrapper; - return createWrapper(wrapper, PARTIAL_FLAG, undefined, [value], []); - } + /** + * Iterates over elements of `collection`, returning the first element + * `predicate` returns truthy for. The predicate is bound to `thisArg` and + * invoked with three arguments: (value, index|key, collection). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias detect + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false }, + * { 'user': 'pebbles', 'age': 1, 'active': true } + * ]; + * + * _.result(_.find(users, function(chr) { + * return chr.age < 40; + * }), 'user'); + * // => 'barney' + * + * // using the `_.matches` callback shorthand + * _.result(_.find(users, { 'age': 1, 'active': true }), 'user'); + * // => 'pebbles' + * + * // using the `_.matchesProperty` callback shorthand + * _.result(_.find(users, 'active', false), 'user'); + * // => 'fred' + * + * // using the `_.property` callback shorthand + * _.result(_.find(users, 'active'), 'user'); + * // => 'barney' + */ + var find = createFind(baseEach); + + /** + * This method is like `_.find` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * _.findLast([1, 2, 3, 4], function(n) { + * return n % 2 == 1; + * }); + * // => 3 + */ + var findLast = createFind(baseEachRight, true); + + /** + * Performs a deep comparison between each element in `collection` and the + * source object, returning the first element that has equivalent property + * values. + * + * **Note:** This method supports comparing arrays, booleans, `Date` objects, + * numbers, `Object` objects, regexes, and strings. Objects are compared by + * their own, not inherited, enumerable properties. For comparing a single + * own or inherited property value see `_.matchesProperty`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Object} source The object of property values to match. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * _.result(_.findWhere(users, { 'age': 36, 'active': true }), 'user'); + * // => 'barney' + * + * _.result(_.findWhere(users, { 'age': 40, 'active': false }), 'user'); + * // => 'fred' + */ + function findWhere(collection, source) { + return find(collection, baseMatches(source)); + } - /*------------------------------------------------------------------------*/ - - /** - * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned, - * otherwise they are assigned by reference. If `customizer` is provided it is - * invoked to produce the cloned values. If `customizer` returns `undefined` - * cloning is handled by the method instead. The `customizer` is bound to - * `thisArg` and invoked with two argument; (value [, index|key, object]). - * - * **Note:** This method is loosely based on the - * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). - * The enumerable properties of `arguments` objects and objects created by - * constructors other than `Object` are cloned to plain `Object` objects. An - * empty object is returned for uncloneable values such as functions, DOM nodes, - * Maps, Sets, and WeakMaps. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @param {Function} [customizer] The function to customize cloning values. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {*} Returns the cloned value. - * @example - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * var shallow = _.clone(users); - * shallow[0] === users[0]; - * // => true - * - * var deep = _.clone(users, true); - * deep[0] === users[0]; - * // => false - * - * // using a customizer callback - * var el = _.clone(document.body, function(value) { - * if (_.isElement(value)) { - * return value.cloneNode(false); - * } - * }); - * - * el === document.body - * // => false - * el.nodeName - * // => BODY - * el.childNodes.length; - * // => 0 - */ - function clone(value, isDeep, customizer, thisArg) { - if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) { - isDeep = false; - } - else if (typeof isDeep == 'function') { - thisArg = customizer; - customizer = isDeep; - isDeep = false; - } - return typeof customizer == 'function' - ? baseClone(value, isDeep, bindCallback(customizer, thisArg, 1)) - : baseClone(value, isDeep); - } + /** + * Iterates over elements of `collection` invoking `iteratee` for each element. + * The `iteratee` is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). Iteratee functions may exit iteration early + * by explicitly returning `false`. + * + * **Note:** As with other "Collections" methods, objects with a "length" property + * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` + * may be used for object iteration. + * + * @static + * @memberOf _ + * @alias each + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array|Object|string} Returns `collection`. + * @example + * + * _([1, 2]).forEach(function(n) { + * console.log(n); + * }).value(); + * // => logs each value from left to right and returns the array + * + * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) { + * console.log(n, key); + * }); + * // => logs each value-key pair and returns the object (iteration order is not guaranteed) + */ + var forEach = createForEach(arrayEach, baseEach); + + /** + * This method is like `_.forEach` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @alias eachRight + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array|Object|string} Returns `collection`. + * @example + * + * _([1, 2]).forEachRight(function(n) { + * console.log(n); + * }).value(); + * // => logs each value from right to left and returns the array + */ + var forEachRight = createForEach(arrayEachRight, baseEachRight); + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` through `iteratee`. The corresponding value + * of each key is an array of the elements responsible for generating the key. + * The `iteratee` is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.groupBy([4.2, 6.1, 6.4], function(n) { + * return Math.floor(n); + * }); + * // => { '4': [4.2], '6': [6.1, 6.4] } + * + * _.groupBy([4.2, 6.1, 6.4], function(n) { + * return this.floor(n); + * }, Math); + * // => { '4': [4.2], '6': [6.1, 6.4] } + * + * // using the `_.property` callback shorthand + * _.groupBy(['one', 'two', 'three'], 'length'); + * // => { '3': ['one', 'two'], '5': ['three'] } + */ + var groupBy = createAggregator(function(result, value, key) { + if (hasOwnProperty.call(result, key)) { + result[key].push(value); + } else { + result[key] = [value]; + } + }); + + /** + * Checks if `value` is in `collection` using + * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. If `fromIndex` is negative, it is used as the offset + * from the end of `collection`. + * + * @static + * @memberOf _ + * @alias contains, include + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {*} target The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. + * @returns {boolean} Returns `true` if a matching element is found, else `false`. + * @example + * + * _.includes([1, 2, 3], 1); + * // => true + * + * _.includes([1, 2, 3], 1, 2); + * // => false + * + * _.includes({ 'user': 'fred', 'age': 40 }, 'fred'); + * // => true + * + * _.includes('pebbles', 'eb'); + * // => true + */ + function includes(collection, target, fromIndex, guard) { + var length = collection ? getLength(collection) : 0; + if (!isLength(length)) { + collection = values(collection); + length = collection.length; + } + if (typeof fromIndex != 'number' || (guard && isIterateeCall(target, fromIndex, guard))) { + fromIndex = 0; + } else { + fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex || 0; + } + return typeof collection == 'string' || (!isArray(collection) && isString(collection)) + ? fromIndex <= length && collection.indexOf(target, fromIndex) > -1 + : !!length && getIndexOf(collection, target, fromIndex) > -1; + } - /** - * Creates a deep clone of `value`. If `customizer` is provided it is invoked - * to produce the cloned values. If `customizer` returns `undefined` cloning - * is handled by the method instead. The `customizer` is bound to `thisArg` - * and invoked with two argument; (value [, index|key, object]). - * - * **Note:** This method is loosely based on the - * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). - * The enumerable properties of `arguments` objects and objects created by - * constructors other than `Object` are cloned to plain `Object` objects. An - * empty object is returned for uncloneable values such as functions, DOM nodes, - * Maps, Sets, and WeakMaps. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to deep clone. - * @param {Function} [customizer] The function to customize cloning values. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {*} Returns the deep cloned value. - * @example - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * var deep = _.cloneDeep(users); - * deep[0] === users[0]; - * // => false - * - * // using a customizer callback - * var el = _.cloneDeep(document.body, function(value) { - * if (_.isElement(value)) { - * return value.cloneNode(true); - * } - * }); - * - * el === document.body - * // => false - * el.nodeName - * // => BODY - * el.childNodes.length; - * // => 20 - */ - function cloneDeep(value, customizer, thisArg) { - return typeof customizer == 'function' - ? baseClone(value, true, bindCallback(customizer, thisArg, 1)) - : baseClone(value, true); - } + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` through `iteratee`. The corresponding value + * of each key is the last element responsible for generating the key. The + * iteratee function is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * var keyData = [ + * { 'dir': 'left', 'code': 97 }, + * { 'dir': 'right', 'code': 100 } + * ]; + * + * _.indexBy(keyData, 'dir'); + * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } + * + * _.indexBy(keyData, function(object) { + * return String.fromCharCode(object.code); + * }); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + * + * _.indexBy(keyData, function(object) { + * return this.fromCharCode(object.code); + * }, String); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + */ + var indexBy = createAggregator(function(result, value, key) { + result[key] = value; + }); + + /** + * Invokes the method at `path` of each element in `collection`, returning + * an array of the results of each invoked method. Any additional arguments + * are provided to each invoked method. If `methodName` is a function it is + * invoked for, and `this` bound to, each element in `collection`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Array|Function|string} path The path of the method to invoke or + * the function invoked per iteration. + * @param {...*} [args] The arguments to invoke the method with. + * @returns {Array} Returns the array of results. + * @example + * + * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); + * // => [[1, 5, 7], [1, 2, 3]] + * + * _.invoke([123, 456], String.prototype.split, ''); + * // => [['1', '2', '3'], ['4', '5', '6']] + */ + var invoke = restParam(function(collection, path, args) { + var index = -1, + isFunc = typeof path == 'function', + isProp = isKey(path), + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value) { + var func = isFunc ? path : isProp && value != null ? value[path] : undefined; + result[++index] = func ? func.apply(value, args) : invokePath(value, path, args); + }); + return result; + }); + + /** + * Creates an array of values by running each element in `collection` through + * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three + * arguments: (value, index|key, collection). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. + * + * The guarded methods are: + * `ary`, `callback`, `chunk`, `clone`, `create`, `curry`, `curryRight`, + * `drop`, `dropRight`, `every`, `fill`, `flatten`, `invert`, `max`, `min`, + * `parseInt`, `slice`, `sortBy`, `take`, `takeRight`, `template`, `trim`, + * `trimLeft`, `trimRight`, `trunc`, `random`, `range`, `sample`, `some`, + * `sum`, `uniq`, and `words` + * + * @static + * @memberOf _ + * @alias collect + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new mapped array. + * @example + * + * function timesThree(n) { + * return n * 3; + * } + * + * _.map([1, 2], timesThree); + * // => [3, 6] + * + * _.map({ 'a': 1, 'b': 2 }, timesThree); + * // => [3, 6] (iteration order is not guaranteed) + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * // using the `_.property` callback shorthand + * _.map(users, 'user'); + * // => ['barney', 'fred'] + */ + function map(collection, iteratee, thisArg) { + var func = isArray(collection) ? arrayMap : baseMap; + iteratee = getCallback(iteratee, thisArg, 3); + return func(collection, iteratee); + } - /** - * Checks if `value` is greater than `other`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, else `false`. - * @example - * - * _.gt(3, 1); - * // => true - * - * _.gt(3, 3); - * // => false - * - * _.gt(1, 3); - * // => false - */ - function gt(value, other) { - return value > other; - } + /** + * Creates an array of elements split into two groups, the first of which + * contains elements `predicate` returns truthy for, while the second of which + * contains elements `predicate` returns falsey for. The predicate is bound + * to `thisArg` and invoked with three arguments: (value, index|key, collection). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the array of grouped elements. + * @example + * + * _.partition([1, 2, 3], function(n) { + * return n % 2; + * }); + * // => [[1, 3], [2]] + * + * _.partition([1.2, 2.3, 3.4], function(n) { + * return this.floor(n) % 2; + * }, Math); + * // => [[1.2, 3.4], [2.3]] + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * var mapper = function(array) { + * return _.pluck(array, 'user'); + * }; + * + * // using the `_.matches` callback shorthand + * _.map(_.partition(users, { 'age': 1, 'active': false }), mapper); + * // => [['pebbles'], ['barney', 'fred']] + * + * // using the `_.matchesProperty` callback shorthand + * _.map(_.partition(users, 'active', false), mapper); + * // => [['barney', 'pebbles'], ['fred']] + * + * // using the `_.property` callback shorthand + * _.map(_.partition(users, 'active'), mapper); + * // => [['fred'], ['barney', 'pebbles']] + */ + var partition = createAggregator( + function(result, value, key) { + result[key ? 0 : 1].push(value); + }, + function() { + return [[], []]; + }, + ); + + /** + * Gets the property value of `path` from all elements in `collection`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Array|string} path The path of the property to pluck. + * @returns {Array} Returns the property values. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * _.pluck(users, 'user'); + * // => ['barney', 'fred'] + * + * var userIndex = _.indexBy(users, 'user'); + * _.pluck(userIndex, 'age'); + * // => [36, 40] (iteration order is not guaranteed) + */ + function pluck(collection, path) { + return map(collection, property(path)); + } - /** - * Checks if `value` is greater than or equal to `other`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than or equal to `other`, else `false`. - * @example - * - * _.gte(3, 1); - * // => true - * - * _.gte(3, 3); - * // => true - * - * _.gte(1, 3); - * // => false - */ - function gte(value, other) { - return value >= other; - } + /** + * Reduces `collection` to a value which is the accumulated result of running + * each element in `collection` through `iteratee`, where each successive + * invocation is supplied the return value of the previous. If `accumulator` + * is not provided the first element of `collection` is used as the initial + * value. The `iteratee` is bound to `thisArg` and invoked with four arguments: + * (accumulator, value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.reduce`, `_.reduceRight`, and `_.transform`. + * + * The guarded methods are: + * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `sortByAll`, + * and `sortByOrder` + * + * @static + * @memberOf _ + * @alias foldl, inject + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {*} Returns the accumulated value. + * @example + * + * _.reduce([1, 2], function(total, n) { + * return total + n; + * }); + * // => 3 + * + * _.reduce({ 'a': 1, 'b': 2 }, function(result, n, key) { + * result[key] = n * 3; + * return result; + * }, {}); + * // => { 'a': 3, 'b': 6 } (iteration order is not guaranteed) + */ + var reduce = createReduce(arrayReduce, baseEach); + + /** + * This method is like `_.reduce` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @alias foldr + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {*} Returns the accumulated value. + * @example + * + * var array = [[0, 1], [2, 3], [4, 5]]; + * + * _.reduceRight(array, function(flattened, other) { + * return flattened.concat(other); + * }, []); + * // => [4, 5, 2, 3, 0, 1] + */ + var reduceRight = createReduce(arrayReduceRight, baseEachRight); + + /** + * The opposite of `_.filter`; this method returns the elements of `collection` + * that `predicate` does **not** return truthy for. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the new filtered array. + * @example + * + * _.reject([1, 2, 3, 4], function(n) { + * return n % 2 == 0; + * }); + * // => [1, 3] + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true } + * ]; + * + * // using the `_.matches` callback shorthand + * _.pluck(_.reject(users, { 'age': 40, 'active': true }), 'user'); + * // => ['barney'] + * + * // using the `_.matchesProperty` callback shorthand + * _.pluck(_.reject(users, 'active', false), 'user'); + * // => ['fred'] + * + * // using the `_.property` callback shorthand + * _.pluck(_.reject(users, 'active'), 'user'); + * // => ['barney'] + */ + function reject(collection, predicate, thisArg) { + var func = isArray(collection) ? arrayFilter : baseFilter; + predicate = getCallback(predicate, thisArg, 3); + return func(collection, function(value, index, collection) { + return !predicate(value, index, collection); + }); + } - /** - * Checks if `value` is classified as an `arguments` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ - function isArguments(value) { - return isObjectLike(value) && isArrayLike(value) && - hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee'); - } + /** + * Gets a random element or `n` random elements from a collection. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to sample. + * @param {number} [n] The number of elements to sample. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {*} Returns the random sample(s). + * @example + * + * _.sample([1, 2, 3, 4]); + * // => 2 + * + * _.sample([1, 2, 3, 4], 2); + * // => [3, 1] + */ + function sample(collection, n, guard) { + if (guard ? isIterateeCall(collection, n, guard) : n == null) { + collection = toIterable(collection); + var length = collection.length; + return length > 0 ? collection[baseRandom(0, length - 1)] : undefined; + } + var index = -1, + result = toArray(collection), + length = result.length, + lastIndex = length - 1; + + n = nativeMin(n < 0 ? 0 : +n || 0, length); + while (++index < n) { + var rand = baseRandom(index, lastIndex), + value = result[rand]; + + result[rand] = result[index]; + result[index] = value; + } + result.length = n; + return result; + } - /** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(function() { return arguments; }()); - * // => false - */ - var isArray = nativeIsArray || function(value) { - return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; - }; - - /** - * Checks if `value` is classified as a boolean primitive or object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isBoolean(false); - * // => true - * - * _.isBoolean(null); - * // => false - */ - function isBoolean(value) { - return value === true || value === false || (isObjectLike(value) && objToString.call(value) == boolTag); - } + /** + * Creates an array of shuffled values, using a version of the + * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to shuffle. + * @returns {Array} Returns the new shuffled array. + * @example + * + * _.shuffle([1, 2, 3, 4]); + * // => [4, 1, 3, 2] + */ + function shuffle(collection) { + return sample(collection, POSITIVE_INFINITY); + } - /** - * Checks if `value` is classified as a `Date` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isDate(new Date); - * // => true - * - * _.isDate('Mon April 23 2012'); - * // => false - */ - function isDate(value) { - return isObjectLike(value) && objToString.call(value) == dateTag; - } + /** + * Gets the size of `collection` by returning its length for array-like + * values or the number of own enumerable properties for objects. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns the size of `collection`. + * @example + * + * _.size([1, 2, 3]); + * // => 3 + * + * _.size({ 'a': 1, 'b': 2 }); + * // => 2 + * + * _.size('pebbles'); + * // => 7 + */ + function size(collection) { + var length = collection ? getLength(collection) : 0; + return isLength(length) ? length : keys(collection).length; + } - /** - * Checks if `value` is a DOM element. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. - * @example - * - * _.isElement(document.body); - * // => true - * - * _.isElement(''); - * // => false - */ - function isElement(value) { - return !!value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value); - } + /** + * Checks if `predicate` returns truthy for **any** element of `collection`. + * The function returns as soon as it finds a passing value and does not iterate + * over the entire collection. The predicate is bound to `thisArg` and invoked + * with three arguments: (value, index|key, collection). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias any + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + * @example + * + * _.some([null, 0, 'yes', false], Boolean); + * // => true + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false } + * ]; + * + * // using the `_.matches` callback shorthand + * _.some(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // using the `_.matchesProperty` callback shorthand + * _.some(users, 'active', false); + * // => true + * + * // using the `_.property` callback shorthand + * _.some(users, 'active'); + * // => true + */ + function some(collection, predicate, thisArg) { + var func = isArray(collection) ? arraySome : baseSome; + if (thisArg && isIterateeCall(collection, predicate, thisArg)) { + predicate = undefined; + } + if (typeof predicate != 'function' || thisArg !== undefined) { + predicate = getCallback(predicate, thisArg, 3); + } + return func(collection, predicate); + } - /** - * Checks if `value` is empty. A value is considered empty unless it is an - * `arguments` object, array, string, or jQuery-like collection with a length - * greater than `0` or an object with own enumerable properties. - * - * @static - * @memberOf _ - * @category Lang - * @param {Array|Object|string} value The value to inspect. - * @returns {boolean} Returns `true` if `value` is empty, else `false`. - * @example - * - * _.isEmpty(null); - * // => true - * - * _.isEmpty(true); - * // => true - * - * _.isEmpty(1); - * // => true - * - * _.isEmpty([1, 2, 3]); - * // => false - * - * _.isEmpty({ 'a': 1 }); - * // => false - */ - function isEmpty(value) { - if (value == null) { - return true; - } - if (isArrayLike(value) && (isArray(value) || isString(value) || isArguments(value) || - (isObjectLike(value) && isFunction(value.splice)))) { - return !value.length; - } - return !keys(value).length; - } + /** + * Creates an array of elements, sorted in ascending order by the results of + * running each element in a collection through `iteratee`. This method performs + * a stable sort, that is, it preserves the original sort order of equal elements. + * The `iteratee` is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new sorted array. + * @example + * + * _.sortBy([1, 2, 3], function(n) { + * return Math.sin(n); + * }); + * // => [3, 1, 2] + * + * _.sortBy([1, 2, 3], function(n) { + * return this.sin(n); + * }, Math); + * // => [3, 1, 2] + * + * var users = [ + * { 'user': 'fred' }, + * { 'user': 'pebbles' }, + * { 'user': 'barney' } + * ]; + * + * // using the `_.property` callback shorthand + * _.pluck(_.sortBy(users, 'user'), 'user'); + * // => ['barney', 'fred', 'pebbles'] + */ + function sortBy(collection, iteratee, thisArg) { + if (collection == null) { + return []; + } + if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { + iteratee = undefined; + } + var index = -1; + iteratee = getCallback(iteratee, thisArg, 3); + + var result = baseMap(collection, function(value, key, collection) { + return { criteria: iteratee(value, key, collection), index: ++index, value: value }; + }); + return baseSortBy(result, compareAscending); + } - /** - * Performs a deep comparison between two values to determine if they are - * equivalent. If `customizer` is provided it is invoked to compare values. - * If `customizer` returns `undefined` comparisons are handled by the method - * instead. The `customizer` is bound to `thisArg` and invoked with three - * arguments: (value, other [, index|key]). - * - * **Note:** This method supports comparing arrays, booleans, `Date` objects, - * numbers, `Object` objects, regexes, and strings. Objects are compared by - * their own, not inherited, enumerable properties. Functions and DOM nodes - * are **not** supported. Provide a customizer function to extend support - * for comparing other values. - * - * @static - * @memberOf _ - * @alias eq - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize value comparisons. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'user': 'fred' }; - * var other = { 'user': 'fred' }; - * - * object == other; - * // => false - * - * _.isEqual(object, other); - * // => true - * - * // using a customizer callback - * var array = ['hello', 'goodbye']; - * var other = ['hi', 'goodbye']; - * - * _.isEqual(array, other, function(value, other) { - * if (_.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/)) { - * return true; - * } - * }); - * // => true - */ - function isEqual(value, other, customizer, thisArg) { - customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined; - var result = customizer ? customizer(value, other) : undefined; - return result === undefined ? baseIsEqual(value, other, customizer) : !!result; - } + /** + * This method is like `_.sortBy` except that it can sort by multiple iteratees + * or property names. + * + * If a property name is provided for an iteratee the created `_.property` + * style callback returns the property value of the given element. + * + * If an object is provided for an iteratee the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {...(Function|Function[]|Object|Object[]|string|string[])} iteratees + * The iteratees to sort by, specified as individual values or arrays of values. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 42 }, + * { 'user': 'barney', 'age': 34 } + * ]; + * + * _.map(_.sortByAll(users, ['user', 'age']), _.values); + * // => [['barney', 34], ['barney', 36], ['fred', 42], ['fred', 48]] + * + * _.map(_.sortByAll(users, 'user', function(chr) { + * return Math.floor(chr.age / 10); + * }), _.values); + * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] + */ + var sortByAll = restParam(function(collection, iteratees) { + if (collection == null) { + return []; + } + var guard = iteratees[2]; + if (guard && isIterateeCall(iteratees[0], iteratees[1], guard)) { + iteratees.length = 1; + } + return baseSortByOrder(collection, baseFlatten(iteratees), []); + }); + + /** + * This method is like `_.sortByAll` except that it allows specifying the + * sort orders of the iteratees to sort by. If `orders` is unspecified, all + * values are sorted in ascending order. Otherwise, a value is sorted in + * ascending order if its corresponding order is "asc", and descending if "desc". + * + * If a property name is provided for an iteratee the created `_.property` + * style callback returns the property value of the given element. + * + * If an object is provided for an iteratee the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. + * @param {boolean[]} [orders] The sort orders of `iteratees`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 34 }, + * { 'user': 'fred', 'age': 42 }, + * { 'user': 'barney', 'age': 36 } + * ]; + * + * // sort by `user` in ascending order and by `age` in descending order + * _.map(_.sortByOrder(users, ['user', 'age'], ['asc', 'desc']), _.values); + * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] + */ + function sortByOrder(collection, iteratees, orders, guard) { + if (collection == null) { + return []; + } + if (guard && isIterateeCall(iteratees, orders, guard)) { + orders = undefined; + } + if (!isArray(iteratees)) { + iteratees = iteratees == null ? [] : [iteratees]; + } + if (!isArray(orders)) { + orders = orders == null ? [] : [orders]; + } + return baseSortByOrder(collection, iteratees, orders); + } - /** - * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, - * `SyntaxError`, `TypeError`, or `URIError` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an error object, else `false`. - * @example - * - * _.isError(new Error); - * // => true - * - * _.isError(Error); - * // => false - */ - function isError(value) { - return isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag; - } + /** + * Performs a deep comparison between each element in `collection` and the + * source object, returning an array of all elements that have equivalent + * property values. + * + * **Note:** This method supports comparing arrays, booleans, `Date` objects, + * numbers, `Object` objects, regexes, and strings. Objects are compared by + * their own, not inherited, enumerable properties. For comparing a single + * own or inherited property value see `_.matchesProperty`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Object} source The object of property values to match. + * @returns {Array} Returns the new filtered array. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false, 'pets': ['hoppy'] }, + * { 'user': 'fred', 'age': 40, 'active': true, 'pets': ['baby puss', 'dino'] } + * ]; + * + * _.pluck(_.where(users, { 'age': 36, 'active': false }), 'user'); + * // => ['barney'] + * + * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user'); + * // => ['fred'] + */ + function where(collection, source) { + return filter(collection, baseMatches(source)); + } - /** - * Checks if `value` is a finite primitive number. - * - * **Note:** This method is based on [`Number.isFinite`](http://ecma-international.org/ecma-262/6.0/#sec-number.isfinite). - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. - * @example - * - * _.isFinite(10); - * // => true - * - * _.isFinite('10'); - * // => false - * - * _.isFinite(true); - * // => false - * - * _.isFinite(Object(10)); - * // => false - * - * _.isFinite(Infinity); - * // => false - */ - function isFinite(value) { - return typeof value == 'number' && nativeIsFinite(value); - } + /*------------------------------------------------------------------------*/ + + /** + * Gets the number of milliseconds that have elapsed since the Unix epoch + * (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @category Date + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => logs the number of milliseconds it took for the deferred function to be invoked + */ + var now = + nativeNow || + function() { + return new Date().getTime(); + }; + + /*------------------------------------------------------------------------*/ + + /** + * The opposite of `_.before`; this method creates a function that invokes + * `func` once it is called `n` or more times. + * + * @static + * @memberOf _ + * @category Function + * @param {number} n The number of calls before `func` is invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var saves = ['profile', 'settings']; + * + * var done = _.after(saves.length, function() { + * console.log('done saving!'); + * }); + * + * _.forEach(saves, function(type) { + * asyncSave({ 'type': type, 'complete': done }); + * }); + * // => logs 'done saving!' after the two async saves have completed + */ + function after(n, func) { + if (typeof func != 'function') { + if (typeof n == 'function') { + var temp = n; + n = func; + func = temp; + } else { + throw new TypeError(FUNC_ERROR_TEXT); + } + } + n = nativeIsFinite((n = +n)) ? n : 0; + return function() { + if (--n < 1) { + return func.apply(this, arguments); + } + }; + } - /** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ - function isFunction(value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in older versions of Chrome and Safari which return 'function' for regexes - // and Safari 8 equivalents which return 'object' for typed array constructors. - return isObject(value) && objToString.call(value) == funcTag; - } + /** + * Creates a function that accepts up to `n` arguments ignoring any + * additional arguments. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to cap arguments for. + * @param {number} [n=func.length] The arity cap. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Function} Returns the new function. + * @example + * + * _.map(['6', '8', '10'], _.ary(parseInt, 1)); + * // => [6, 8, 10] + */ + function ary(func, n, guard) { + if (guard && isIterateeCall(func, n, guard)) { + n = undefined; + } + n = func && n == null ? func.length : nativeMax(+n || 0, 0); + return createWrapper(func, ARY_FLAG, undefined, undefined, undefined, undefined, n); + } - /** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ - function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); - } + /** + * Creates a function that invokes `func`, with the `this` binding and arguments + * of the created function, while it is called less than `n` times. Subsequent + * calls to the created function return the result of the last `func` invocation. + * + * @static + * @memberOf _ + * @category Function + * @param {number} n The number of calls at which `func` is no longer invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * jQuery('#add').on('click', _.before(5, addContactToList)); + * // => allows adding up to 4 contacts to the list + */ + function before(n, func) { + var result; + if (typeof func != 'function') { + if (typeof n == 'function') { + var temp = n; + n = func; + func = temp; + } else { + throw new TypeError(FUNC_ERROR_TEXT); + } + } + return function() { + if (--n > 0) { + result = func.apply(this, arguments); + } + if (n <= 1) { + func = undefined; + } + return result; + }; + } - /** - * Performs a deep comparison between `object` and `source` to determine if - * `object` contains equivalent property values. If `customizer` is provided - * it is invoked to compare values. If `customizer` returns `undefined` - * comparisons are handled by the method instead. The `customizer` is bound - * to `thisArg` and invoked with three arguments: (value, other, index|key). - * - * **Note:** This method supports comparing properties of arrays, booleans, - * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions - * and DOM nodes are **not** supported. Provide a customizer function to extend - * support for comparing other values. - * - * @static - * @memberOf _ - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Function} [customizer] The function to customize value comparisons. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - * @example - * - * var object = { 'user': 'fred', 'age': 40 }; - * - * _.isMatch(object, { 'age': 40 }); - * // => true - * - * _.isMatch(object, { 'age': 36 }); - * // => false - * - * // using a customizer callback - * var object = { 'greeting': 'hello' }; - * var source = { 'greeting': 'hi' }; - * - * _.isMatch(object, source, function(value, other) { - * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined; - * }); - * // => true - */ - function isMatch(object, source, customizer, thisArg) { - customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined; - return baseIsMatch(object, getMatchData(source), customizer); - } + /** + * Creates a function that invokes `func` with the `this` binding of `thisArg` + * and prepends any additional `_.bind` arguments to those provided to the + * bound function. + * + * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for partially applied arguments. + * + * **Note:** Unlike native `Function#bind` this method does not set the "length" + * property of bound functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var greet = function(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * }; + * + * var object = { 'user': 'fred' }; + * + * var bound = _.bind(greet, object, 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * // using placeholders + * var bound = _.bind(greet, object, _, '!'); + * bound('hi'); + * // => 'hi fred!' + */ + var bind = restParam(function(func, thisArg, partials) { + var bitmask = BIND_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, bind.placeholder); + bitmask |= PARTIAL_FLAG; + } + return createWrapper(func, bitmask, thisArg, partials, holders); + }); + + /** + * Binds methods of an object to the object itself, overwriting the existing + * method. Method names may be specified as individual arguments or as arrays + * of method names. If no method names are provided all enumerable function + * properties, own and inherited, of `object` are bound. + * + * **Note:** This method does not set the "length" property of bound functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Object} object The object to bind and assign the bound methods to. + * @param {...(string|string[])} [methodNames] The object method names to bind, + * specified as individual method names or arrays of method names. + * @returns {Object} Returns `object`. + * @example + * + * var view = { + * 'label': 'docs', + * 'onClick': function() { + * console.log('clicked ' + this.label); + * } + * }; + * + * _.bindAll(view); + * jQuery('#docs').on('click', view.onClick); + * // => logs 'clicked docs' when the element is clicked + */ + var bindAll = restParam(function(object, methodNames) { + methodNames = methodNames.length ? baseFlatten(methodNames) : functions(object); + + var index = -1, + length = methodNames.length; + + while (++index < length) { + var key = methodNames[index]; + object[key] = createWrapper(object[key], BIND_FLAG, object); + } + return object; + }); + + /** + * Creates a function that invokes the method at `object[key]` and prepends + * any additional `_.bindKey` arguments to those provided to the bound function. + * + * This method differs from `_.bind` by allowing bound functions to reference + * methods that may be redefined or don't yet exist. + * See [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) + * for more details. + * + * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * @static + * @memberOf _ + * @category Function + * @param {Object} object The object the method belongs to. + * @param {string} key The key of the method. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var object = { + * 'user': 'fred', + * 'greet': function(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * }; + * + * var bound = _.bindKey(object, 'greet', 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * object.greet = function(greeting, punctuation) { + * return greeting + 'ya ' + this.user + punctuation; + * }; + * + * bound('!'); + * // => 'hiya fred!' + * + * // using placeholders + * var bound = _.bindKey(object, 'greet', _, '!'); + * bound('hi'); + * // => 'hiya fred!' + */ + var bindKey = restParam(function(object, key, partials) { + var bitmask = BIND_FLAG | BIND_KEY_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, bindKey.placeholder); + bitmask |= PARTIAL_FLAG; + } + return createWrapper(key, bitmask, object, partials, holders); + }); + + /** + * Creates a function that accepts one or more arguments of `func` that when + * called either invokes `func` returning its result, if all `func` arguments + * have been provided, or returns a function that accepts one or more of the + * remaining `func` arguments, and so on. The arity of `func` may be specified + * if `func.length` is not sufficient. + * + * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for provided arguments. + * + * **Note:** This method does not set the "length" property of curried functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curry(abc); + * + * curried(1)(2)(3); + * // => [1, 2, 3] + * + * curried(1, 2)(3); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // using placeholders + * curried(1)(_, 3)(2); + * // => [1, 2, 3] + */ + var curry = createCurry(CURRY_FLAG); + + /** + * This method is like `_.curry` except that arguments are applied to `func` + * in the manner of `_.partialRight` instead of `_.partial`. + * + * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for provided arguments. + * + * **Note:** This method does not set the "length" property of curried functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curryRight(abc); + * + * curried(3)(2)(1); + * // => [1, 2, 3] + * + * curried(2, 3)(1); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // using placeholders + * curried(3)(1, _)(2); + * // => [1, 2, 3] + */ + var curryRight = createCurry(CURRY_RIGHT_FLAG); + + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. The debounced function comes with a `cancel` method to cancel + * delayed invocations. Provide an options object to indicate that `func` + * should be invoked on the leading and/or trailing edge of the `wait` timeout. + * Subsequent calls to the debounced function return the result of the last + * `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked + * on the trailing edge of the timeout only if the the debounced function is + * invoked more than once during the `wait` timeout. + * + * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] The number of milliseconds to delay. + * @param {Object} [options] The options object. + * @param {boolean} [options.leading=false] Specify invoking on the leading + * edge of the timeout. + * @param {number} [options.maxWait] The maximum time `func` is allowed to be + * delayed before it is invoked. + * @param {boolean} [options.trailing=true] Specify invoking on the trailing + * edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // avoid costly calculations while the window size is in flux + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // invoke `sendMail` when the click event is fired, debouncing subsequent calls + * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // ensure `batchLog` is invoked once after 1 second of debounced calls + * var source = new EventSource('/stream'); + * jQuery(source).on('message', _.debounce(batchLog, 250, { + * 'maxWait': 1000 + * })); + * + * // cancel a debounced call + * var todoChanges = _.debounce(batchLog, 1000); + * Object.observe(models.todo, todoChanges); + * + * Object.observe(models, function(changes) { + * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { + * todoChanges.cancel(); + * } + * }, ['delete']); + * + * // ...at some point `models.todo` is changed + * models.todo.completed = true; + * + * // ...before 1 second has passed `models.todo` is deleted + * // which cancels the debounced `todoChanges` call + * delete models.todo; + */ + function debounce(func, wait, options) { + var args, + maxTimeoutId, + result, + stamp, + thisArg, + timeoutId, + trailingCall, + lastCalled = 0, + maxWait = false, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = wait < 0 ? 0 : +wait || 0; + if (options === true) { + var leading = true; + trailing = false; + } else if (isObject(options)) { + leading = !!options.leading; + maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + + function cancel() { + if (timeoutId) { + clearTimeout(timeoutId); + } + if (maxTimeoutId) { + clearTimeout(maxTimeoutId); + } + lastCalled = 0; + maxTimeoutId = timeoutId = trailingCall = undefined; + } + + function complete(isCalled, id) { + if (id) { + clearTimeout(id); + } + maxTimeoutId = timeoutId = trailingCall = undefined; + if (isCalled) { + lastCalled = now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = undefined; + } + } + } + + function delayed() { + var remaining = wait - (now() - stamp); + if (remaining <= 0 || remaining > wait) { + complete(trailingCall, maxTimeoutId); + } else { + timeoutId = setTimeout(delayed, remaining); + } + } + + function maxDelayed() { + complete(trailing, timeoutId); + } + + function debounced() { + args = arguments; + stamp = now(); + thisArg = this; + trailingCall = trailing && (timeoutId || !leading); + + if (maxWait === false) { + var leadingCall = leading && !timeoutId; + } else { + if (!maxTimeoutId && !leading) { + lastCalled = stamp; + } + var remaining = maxWait - (stamp - lastCalled), + isCalled = remaining <= 0 || remaining > maxWait; + + if (isCalled) { + if (maxTimeoutId) { + maxTimeoutId = clearTimeout(maxTimeoutId); + } + lastCalled = stamp; + result = func.apply(thisArg, args); + } else if (!maxTimeoutId) { + maxTimeoutId = setTimeout(maxDelayed, remaining); + } + } + if (isCalled && timeoutId) { + timeoutId = clearTimeout(timeoutId); + } else if (!timeoutId && wait !== maxWait) { + timeoutId = setTimeout(delayed, wait); + } + if (leadingCall) { + isCalled = true; + result = func.apply(thisArg, args); + } + if (isCalled && !timeoutId && !maxTimeoutId) { + args = thisArg = undefined; + } + return result; + } + debounced.cancel = cancel; + return debounced; + } - /** - * Checks if `value` is `NaN`. - * - * **Note:** This method is not the same as [`isNaN`](https://es5.github.io/#x15.1.2.4) - * which returns `true` for `undefined` and other non-numeric values. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - * @example - * - * _.isNaN(NaN); - * // => true - * - * _.isNaN(new Number(NaN)); - * // => true - * - * isNaN(undefined); - * // => true - * - * _.isNaN(undefined); - * // => false - */ - function isNaN(value) { - // An `NaN` primitive is the only value that is not equal to itself. - // Perform the `toStringTag` check first to avoid errors with some host objects in IE. - return isNumber(value) && value != +value; - } + /** + * Defers invoking the `func` until the current call stack has cleared. Any + * additional arguments are provided to `func` when it is invoked. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to defer. + * @param {...*} [args] The arguments to invoke the function with. + * @returns {number} Returns the timer id. + * @example + * + * _.defer(function(text) { + * console.log(text); + * }, 'deferred'); + * // logs 'deferred' after one or more milliseconds + */ + var defer = restParam(function(func, args) { + return baseDelay(func, 1, args); + }); + + /** + * Invokes `func` after `wait` milliseconds. Any additional arguments are + * provided to `func` when it is invoked. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {...*} [args] The arguments to invoke the function with. + * @returns {number} Returns the timer id. + * @example + * + * _.delay(function(text) { + * console.log(text); + * }, 1000, 'later'); + * // => logs 'later' after one second + */ + var delay = restParam(function(func, wait, args) { + return baseDelay(func, wait, args); + }); + + /** + * Creates a function that returns the result of invoking the provided + * functions with the `this` binding of the created function, where each + * successive invocation is supplied the return value of the previous. + * + * @static + * @memberOf _ + * @category Function + * @param {...Function} [funcs] Functions to invoke. + * @returns {Function} Returns the new function. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var addSquare = _.flow(_.add, square); + * addSquare(1, 2); + * // => 9 + */ + var flow = createFlow(); + + /** + * This method is like `_.flow` except that it creates a function that + * invokes the provided functions from right to left. + * + * @static + * @memberOf _ + * @alias backflow, compose + * @category Function + * @param {...Function} [funcs] Functions to invoke. + * @returns {Function} Returns the new function. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var addSquare = _.flowRight(square, _.add); + * addSquare(1, 2); + * // => 9 + */ + var flowRight = createFlow(true); + + /** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is coerced to a string and used as the + * cache key. The `func` is invoked with the `this` binding of the memoized + * function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the [`Map`](http://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-map-prototype-object) + * method interface of `get`, `has`, and `set`. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoizing function. + * @example + * + * var upperCase = _.memoize(function(string) { + * return string.toUpperCase(); + * }); + * + * upperCase('fred'); + * // => 'FRED' + * + * // modifying the result cache + * upperCase.cache.set('fred', 'BARNEY'); + * upperCase('fred'); + * // => 'BARNEY' + * + * // replacing `_.memoize.Cache` + * var object = { 'user': 'fred' }; + * var other = { 'user': 'barney' }; + * var identity = _.memoize(_.identity); + * + * identity(object); + * // => { 'user': 'fred' } + * identity(other); + * // => { 'user': 'fred' } + * + * _.memoize.Cache = WeakMap; + * var identity = _.memoize(_.identity); + * + * identity(object); + * // => { 'user': 'fred' } + * identity(other); + * // => { 'user': 'barney' } + */ + function memoize(func, resolver) { + if (typeof func != 'function' || (resolver && typeof resolver != 'function')) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var args = arguments, + key = resolver ? resolver.apply(this, args) : args[0], + cache = memoized.cache; + + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, args); + memoized.cache = cache.set(key, result); + return result; + }; + memoized.cache = new memoize.Cache(); + return memoized; + } - /** - * Checks if `value` is a native function. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, else `false`. - * @example - * - * _.isNative(Array.prototype.push); - * // => true - * - * _.isNative(_); - * // => false - */ - function isNative(value) { - if (value == null) { - return false; - } - if (isFunction(value)) { - return reIsNative.test(fnToString.call(value)); - } - return isObjectLike(value) && reIsHostCtor.test(value); - } + /** + * Creates a function that runs each argument through a corresponding + * transform function. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to wrap. + * @param {...(Function|Function[])} [transforms] The functions to transform + * arguments, specified as individual functions or arrays of functions. + * @returns {Function} Returns the new function. + * @example + * + * function doubled(n) { + * return n * 2; + * } + * + * function square(n) { + * return n * n; + * } + * + * var modded = _.modArgs(function(x, y) { + * return [x, y]; + * }, square, doubled); + * + * modded(1, 2); + * // => [1, 4] + * + * modded(5, 10); + * // => [25, 20] + */ + var modArgs = restParam(function(func, transforms) { + transforms = baseFlatten(transforms); + if (typeof func != 'function' || !arrayEvery(transforms, baseIsFunction)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var length = transforms.length; + return restParam(function(args) { + var index = nativeMin(args.length, length); + while (index--) { + args[index] = transforms[index](args[index]); + } + return func.apply(this, args); + }); + }); + + /** + * Creates a function that negates the result of the predicate `func`. The + * `func` predicate is invoked with the `this` binding and arguments of the + * created function. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} predicate The predicate to negate. + * @returns {Function} Returns the new function. + * @example + * + * function isEven(n) { + * return n % 2 == 0; + * } + * + * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); + * // => [1, 3, 5] + */ + function negate(predicate) { + if (typeof predicate != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + return !predicate.apply(this, arguments); + }; + } - /** - * Checks if `value` is `null`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `null`, else `false`. - * @example - * - * _.isNull(null); - * // => true - * - * _.isNull(void 0); - * // => false - */ - function isNull(value) { - return value === null; - } + /** + * Creates a function that is restricted to invoking `func` once. Repeat calls + * to the function return the value of the first call. The `func` is invoked + * with the `this` binding and arguments of the created function. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var initialize = _.once(createApplication); + * initialize(); + * initialize(); + * // `initialize` invokes `createApplication` once + */ + function once(func) { + return before(2, func); + } - /** - * Checks if `value` is classified as a `Number` primitive or object. - * - * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified - * as numbers, use the `_.isFinite` method. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isNumber(8.4); - * // => true - * - * _.isNumber(NaN); - * // => true - * - * _.isNumber('8.4'); - * // => false - */ - function isNumber(value) { - return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag); - } + /** + * Creates a function that invokes `func` with `partial` arguments prepended + * to those provided to the new function. This method is like `_.bind` except + * it does **not** alter the `this` binding. + * + * The `_.partial.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method does not set the "length" property of partially + * applied functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * var greet = function(greeting, name) { + * return greeting + ' ' + name; + * }; + * + * var sayHelloTo = _.partial(greet, 'hello'); + * sayHelloTo('fred'); + * // => 'hello fred' + * + * // using placeholders + * var greetFred = _.partial(greet, _, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + */ + var partial = createPartial(PARTIAL_FLAG); + + /** + * This method is like `_.partial` except that partially applied arguments + * are appended to those provided to the new function. + * + * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method does not set the "length" property of partially + * applied functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * var greet = function(greeting, name) { + * return greeting + ' ' + name; + * }; + * + * var greetFred = _.partialRight(greet, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + * + * // using placeholders + * var sayHelloTo = _.partialRight(greet, 'hello', _); + * sayHelloTo('fred'); + * // => 'hello fred' + */ + var partialRight = createPartial(PARTIAL_RIGHT_FLAG); + + /** + * Creates a function that invokes `func` with arguments arranged according + * to the specified indexes where the argument value at the first index is + * provided as the first argument, the argument value at the second index is + * provided as the second argument, and so on. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to rearrange arguments for. + * @param {...(number|number[])} indexes The arranged argument indexes, + * specified as individual indexes or arrays of indexes. + * @returns {Function} Returns the new function. + * @example + * + * var rearged = _.rearg(function(a, b, c) { + * return [a, b, c]; + * }, 2, 0, 1); + * + * rearged('b', 'c', 'a') + * // => ['a', 'b', 'c'] + * + * var map = _.rearg(_.map, [1, 0]); + * map(function(n) { + * return n * 3; + * }, [1, 2, 3]); + * // => [3, 6, 9] + */ + var rearg = restParam(function(func, indexes) { + return createWrapper(func, REARG_FLAG, undefined, undefined, undefined, baseFlatten(indexes)); + }); + + /** + * Creates a function that invokes `func` with the `this` binding of the + * created function and arguments from `start` and beyond provided as an array. + * + * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters). + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.restParam(function(what, names) { + * return what + ' ' + _.initial(names).join(', ') + + * (_.size(names) > 1 ? ', & ' : '') + _.last(names); + * }); + * + * say('hello', 'fred', 'barney', 'pebbles'); + * // => 'hello fred, barney, & pebbles' + */ + function restParam(func, start) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + start = nativeMax(start === undefined ? func.length - 1 : +start || 0, 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + rest = Array(length); + + while (++index < length) { + rest[index] = args[start + index]; + } + switch (start) { + case 0: + return func.call(this, rest); + case 1: + return func.call(this, args[0], rest); + case 2: + return func.call(this, args[0], args[1], rest); + } + var otherArgs = Array(start + 1); + index = -1; + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = rest; + return func.apply(this, otherArgs); + }; + } - /** - * Checks if `value` is a plain object, that is, an object created by the - * `Object` constructor or one with a `[[Prototype]]` of `null`. - * - * **Note:** This method assumes objects created by the `Object` constructor - * have no inherited enumerable properties. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * _.isPlainObject(new Foo); - * // => false - * - * _.isPlainObject([1, 2, 3]); - * // => false - * - * _.isPlainObject({ 'x': 0, 'y': 0 }); - * // => true - * - * _.isPlainObject(Object.create(null)); - * // => true - */ - function isPlainObject(value) { - var Ctor; - - // Exit early for non `Object` objects. - if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isArguments(value)) || - (!hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) { - return false; - } - // IE < 9 iterates inherited properties before own properties. If the first - // iterated property is an object's own property then there are no inherited - // enumerable properties. - var result; - // In most environments an object's own properties are iterated before - // its inherited properties. If the last iterated property is an object's - // own property then there are no inherited enumerable properties. - baseForIn(value, function(subValue, key) { - result = key; - }); - return result === undefined || hasOwnProperty.call(value, result); - } + /** + * Creates a function that invokes `func` with the `this` binding of the created + * function and an array of arguments much like [`Function#apply`](https://es5.github.io/#x15.3.4.3). + * + * **Note:** This method is based on the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator). + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to spread arguments over. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.spread(function(who, what) { + * return who + ' says ' + what; + * }); + * + * say(['fred', 'hello']); + * // => 'fred says hello' + * + * // with a Promise + * var numbers = Promise.all([ + * Promise.resolve(40), + * Promise.resolve(36) + * ]); + * + * numbers.then(_.spread(function(x, y) { + * return x + y; + * })); + * // => a Promise of 76 + */ + function spread(func) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function(array) { + return func.apply(this, array); + }; + } - /** - * Checks if `value` is classified as a `RegExp` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isRegExp(/abc/); - * // => true - * - * _.isRegExp('/abc/'); - * // => false - */ - function isRegExp(value) { - return isObject(value) && objToString.call(value) == regexpTag; - } + /** + * Creates a throttled function that only invokes `func` at most once per + * every `wait` milliseconds. The throttled function comes with a `cancel` + * method to cancel delayed invocations. Provide an options object to indicate + * that `func` should be invoked on the leading and/or trailing edge of the + * `wait` timeout. Subsequent calls to the throttled function return the + * result of the last `func` call. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked + * on the trailing edge of the timeout only if the the throttled function is + * invoked more than once during the `wait` timeout. + * + * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) + * for details over the differences between `_.throttle` and `_.debounce`. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to throttle. + * @param {number} [wait=0] The number of milliseconds to throttle invocations to. + * @param {Object} [options] The options object. + * @param {boolean} [options.leading=true] Specify invoking on the leading + * edge of the timeout. + * @param {boolean} [options.trailing=true] Specify invoking on the trailing + * edge of the timeout. + * @returns {Function} Returns the new throttled function. + * @example + * + * // avoid excessively updating the position while scrolling + * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); + * + * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes + * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, { + * 'trailing': false + * })); + * + * // cancel a trailing throttled call + * jQuery(window).on('popstate', throttled.cancel); + */ + function throttle(func, wait, options) { + var leading = true, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (options === false) { + leading = false; + } else if (isObject(options)) { + leading = 'leading' in options ? !!options.leading : leading; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + return debounce(func, wait, { leading: leading, maxWait: +wait, trailing: trailing }); + } - /** - * Checks if `value` is classified as a `String` primitive or object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isString('abc'); - * // => true - * - * _.isString(1); - * // => false - */ - function isString(value) { - return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag); - } + /** + * Creates a function that provides `value` to the wrapper function as its + * first argument. Any additional arguments provided to the function are + * appended to those provided to the wrapper function. The wrapper is invoked + * with the `this` binding of the created function. + * + * @static + * @memberOf _ + * @category Function + * @param {*} value The value to wrap. + * @param {Function} wrapper The wrapper function. + * @returns {Function} Returns the new function. + * @example + * + * var p = _.wrap(_.escape, function(func, text) { + * return '

' + func(text) + '

'; + * }); + * + * p('fred, barney, & pebbles'); + * // => '

fred, barney, & pebbles

' + */ + function wrap(value, wrapper) { + wrapper = wrapper == null ? identity : wrapper; + return createWrapper(wrapper, PARTIAL_FLAG, undefined, [value], []); + } - /** - * Checks if `value` is classified as a typed array. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isTypedArray(new Uint8Array); - * // => true - * - * _.isTypedArray([]); - * // => false - */ - function isTypedArray(value) { - return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)]; - } + /*------------------------------------------------------------------------*/ + + /** + * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned, + * otherwise they are assigned by reference. If `customizer` is provided it is + * invoked to produce the cloned values. If `customizer` returns `undefined` + * cloning is handled by the method instead. The `customizer` is bound to + * `thisArg` and invoked with two argument; (value [, index|key, object]). + * + * **Note:** This method is loosely based on the + * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). + * The enumerable properties of `arguments` objects and objects created by + * constructors other than `Object` are cloned to plain `Object` objects. An + * empty object is returned for uncloneable values such as functions, DOM nodes, + * Maps, Sets, and WeakMaps. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @param {Function} [customizer] The function to customize cloning values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {*} Returns the cloned value. + * @example + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * var shallow = _.clone(users); + * shallow[0] === users[0]; + * // => true + * + * var deep = _.clone(users, true); + * deep[0] === users[0]; + * // => false + * + * // using a customizer callback + * var el = _.clone(document.body, function(value) { + * if (_.isElement(value)) { + * return value.cloneNode(false); + * } + * }); + * + * el === document.body + * // => false + * el.nodeName + * // => BODY + * el.childNodes.length; + * // => 0 + */ + function clone(value, isDeep, customizer, thisArg) { + if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) { + isDeep = false; + } else if (typeof isDeep == 'function') { + thisArg = customizer; + customizer = isDeep; + isDeep = false; + } + return typeof customizer == 'function' + ? baseClone(value, isDeep, bindCallback(customizer, thisArg, 1)) + : baseClone(value, isDeep); + } - /** - * Checks if `value` is `undefined`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. - * @example - * - * _.isUndefined(void 0); - * // => true - * - * _.isUndefined(null); - * // => false - */ - function isUndefined(value) { - return value === undefined; - } + /** + * Creates a deep clone of `value`. If `customizer` is provided it is invoked + * to produce the cloned values. If `customizer` returns `undefined` cloning + * is handled by the method instead. The `customizer` is bound to `thisArg` + * and invoked with two argument; (value [, index|key, object]). + * + * **Note:** This method is loosely based on the + * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). + * The enumerable properties of `arguments` objects and objects created by + * constructors other than `Object` are cloned to plain `Object` objects. An + * empty object is returned for uncloneable values such as functions, DOM nodes, + * Maps, Sets, and WeakMaps. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to deep clone. + * @param {Function} [customizer] The function to customize cloning values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {*} Returns the deep cloned value. + * @example + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * var deep = _.cloneDeep(users); + * deep[0] === users[0]; + * // => false + * + * // using a customizer callback + * var el = _.cloneDeep(document.body, function(value) { + * if (_.isElement(value)) { + * return value.cloneNode(true); + * } + * }); + * + * el === document.body + * // => false + * el.nodeName + * // => BODY + * el.childNodes.length; + * // => 20 + */ + function cloneDeep(value, customizer, thisArg) { + return typeof customizer == 'function' + ? baseClone(value, true, bindCallback(customizer, thisArg, 1)) + : baseClone(value, true); + } - /** - * Checks if `value` is less than `other`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, else `false`. - * @example - * - * _.lt(1, 3); - * // => true - * - * _.lt(3, 3); - * // => false - * - * _.lt(3, 1); - * // => false - */ - function lt(value, other) { - return value < other; - } + /** + * Checks if `value` is greater than `other`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than `other`, else `false`. + * @example + * + * _.gt(3, 1); + * // => true + * + * _.gt(3, 3); + * // => false + * + * _.gt(1, 3); + * // => false + */ + function gt(value, other) { + return value > other; + } - /** - * Checks if `value` is less than or equal to `other`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than or equal to `other`, else `false`. - * @example - * - * _.lte(1, 3); - * // => true - * - * _.lte(3, 3); - * // => true - * - * _.lte(3, 1); - * // => false - */ - function lte(value, other) { - return value <= other; - } + /** + * Checks if `value` is greater than or equal to `other`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than or equal to `other`, else `false`. + * @example + * + * _.gte(3, 1); + * // => true + * + * _.gte(3, 3); + * // => true + * + * _.gte(1, 3); + * // => false + */ + function gte(value, other) { + return value >= other; + } - /** - * Converts `value` to an array. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to convert. - * @returns {Array} Returns the converted array. - * @example - * - * (function() { - * return _.toArray(arguments).slice(1); - * }(1, 2, 3)); - * // => [2, 3] - */ - function toArray(value) { - var length = value ? getLength(value) : 0; - if (!isLength(length)) { - return values(value); - } - if (!length) { - return []; - } - return arrayCopy(value); - } + /** + * Checks if `value` is classified as an `arguments` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ + function isArguments(value) { + return ( + isObjectLike(value) && + isArrayLike(value) && + hasOwnProperty.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee') + ); + } - /** - * Converts `value` to a plain object flattening inherited enumerable - * properties of `value` to own properties of the plain object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to convert. - * @returns {Object} Returns the converted plain object. - * @example - * - * function Foo() { - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.assign({ 'a': 1 }, new Foo); - * // => { 'a': 1, 'b': 2 } - * - * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); - * // => { 'a': 1, 'b': 2, 'c': 3 } - */ - function toPlainObject(value) { - return baseCopy(value, keysIn(value)); - } + /** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(function() { return arguments; }()); + * // => false + */ + var isArray = + nativeIsArray || + function(value) { + return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; + }; + + /** + * Checks if `value` is classified as a boolean primitive or object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isBoolean(false); + * // => true + * + * _.isBoolean(null); + * // => false + */ + function isBoolean(value) { + return value === true || value === false || (isObjectLike(value) && objToString.call(value) == boolTag); + } - /*------------------------------------------------------------------------*/ - - /** - * Recursively merges own enumerable properties of the source object(s), that - * don't resolve to `undefined` into the destination object. Subsequent sources - * overwrite property assignments of previous sources. If `customizer` is - * provided it is invoked to produce the merged values of the destination and - * source properties. If `customizer` returns `undefined` merging is handled - * by the method instead. The `customizer` is bound to `thisArg` and invoked - * with five arguments: (objectValue, sourceValue, key, object, source). - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {Object} Returns `object`. - * @example - * - * var users = { - * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] - * }; - * - * var ages = { - * 'data': [{ 'age': 36 }, { 'age': 40 }] - * }; - * - * _.merge(users, ages); - * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } - * - * // using a customizer callback - * var object = { - * 'fruits': ['apple'], - * 'vegetables': ['beet'] - * }; - * - * var other = { - * 'fruits': ['banana'], - * 'vegetables': ['carrot'] - * }; - * - * _.merge(object, other, function(a, b) { - * if (_.isArray(a)) { - * return a.concat(b); - * } - * }); - * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } - */ - var merge = createAssigner(baseMerge); - - /** - * Assigns own enumerable properties of source object(s) to the destination - * object. Subsequent sources overwrite property assignments of previous sources. - * If `customizer` is provided it is invoked to produce the assigned values. - * The `customizer` is bound to `thisArg` and invoked with five arguments: - * (objectValue, sourceValue, key, object, source). - * - * **Note:** This method mutates `object` and is based on - * [`Object.assign`](http://ecma-international.org/ecma-262/6.0/#sec-object.assign). - * - * @static - * @memberOf _ - * @alias extend - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {Object} Returns `object`. - * @example - * - * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' }); - * // => { 'user': 'fred', 'age': 40 } - * - * // using a customizer callback - * var defaults = _.partialRight(_.assign, function(value, other) { - * return _.isUndefined(value) ? other : value; - * }); - * - * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); - * // => { 'user': 'barney', 'age': 36 } - */ - var assign = createAssigner(function(object, source, customizer) { - return customizer - ? assignWith(object, source, customizer) - : baseAssign(object, source); - }); - - /** - * Creates an object that inherits from the given `prototype` object. If a - * `properties` object is provided its own enumerable properties are assigned - * to the created object. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} prototype The object to inherit from. - * @param {Object} [properties] The properties to assign to the object. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Object} Returns the new object. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * function Circle() { - * Shape.call(this); - * } - * - * Circle.prototype = _.create(Shape.prototype, { - * 'constructor': Circle - * }); - * - * var circle = new Circle; - * circle instanceof Circle; - * // => true - * - * circle instanceof Shape; - * // => true - */ - function create(prototype, properties, guard) { - var result = baseCreate(prototype); - if (guard && isIterateeCall(prototype, properties, guard)) { - properties = undefined; - } - return properties ? baseAssign(result, properties) : result; - } + /** + * Checks if `value` is classified as a `Date` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isDate(new Date); + * // => true + * + * _.isDate('Mon April 23 2012'); + * // => false + */ + function isDate(value) { + return isObjectLike(value) && objToString.call(value) == dateTag; + } - /** - * Assigns own enumerable properties of source object(s) to the destination - * object for all destination properties that resolve to `undefined`. Once a - * property is set, additional values of the same property are ignored. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @example - * - * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); - * // => { 'user': 'barney', 'age': 36 } - */ - var defaults = createDefaults(assign, assignDefaults); - - /** - * This method is like `_.defaults` except that it recursively assigns - * default properties. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @example - * - * _.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } }); - * // => { 'user': { 'name': 'barney', 'age': 36 } } - * - */ - var defaultsDeep = createDefaults(merge, mergeDefaults); - - /** - * This method is like `_.find` except that it returns the key of the first - * element `predicate` returns truthy for instead of the element itself. - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {string|undefined} Returns the key of the matched element, else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findKey(users, function(chr) { - * return chr.age < 40; - * }); - * // => 'barney' (iteration order is not guaranteed) - * - * // using the `_.matches` callback shorthand - * _.findKey(users, { 'age': 1, 'active': true }); - * // => 'pebbles' - * - * // using the `_.matchesProperty` callback shorthand - * _.findKey(users, 'active', false); - * // => 'fred' - * - * // using the `_.property` callback shorthand - * _.findKey(users, 'active'); - * // => 'barney' - */ - var findKey = createFindKey(baseForOwn); - - /** - * This method is like `_.findKey` except that it iterates over elements of - * a collection in the opposite order. - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {string|undefined} Returns the key of the matched element, else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findLastKey(users, function(chr) { - * return chr.age < 40; - * }); - * // => returns `pebbles` assuming `_.findKey` returns `barney` - * - * // using the `_.matches` callback shorthand - * _.findLastKey(users, { 'age': 36, 'active': true }); - * // => 'barney' - * - * // using the `_.matchesProperty` callback shorthand - * _.findLastKey(users, 'active', false); - * // => 'fred' - * - * // using the `_.property` callback shorthand - * _.findLastKey(users, 'active'); - * // => 'pebbles' - */ - var findLastKey = createFindKey(baseForOwnRight); - - /** - * Iterates over own and inherited enumerable properties of an object invoking - * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked - * with three arguments: (value, key, object). Iteratee functions may exit - * iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns `object`. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forIn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed) - */ - var forIn = createForIn(baseFor); - - /** - * This method is like `_.forIn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns `object`. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forInRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c' - */ - var forInRight = createForIn(baseForRight); - - /** - * Iterates over own enumerable properties of an object invoking `iteratee` - * for each property. The `iteratee` is bound to `thisArg` and invoked with - * three arguments: (value, key, object). Iteratee functions may exit iteration - * early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns `object`. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => logs 'a' and 'b' (iteration order is not guaranteed) - */ - var forOwn = createForOwn(baseForOwn); - - /** - * This method is like `_.forOwn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns `object`. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwnRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => logs 'b' and 'a' assuming `_.forOwn` logs 'a' and 'b' - */ - var forOwnRight = createForOwn(baseForOwnRight); - - /** - * Creates an array of function property names from all enumerable properties, - * own and inherited, of `object`. - * - * @static - * @memberOf _ - * @alias methods - * @category Object - * @param {Object} object The object to inspect. - * @returns {Array} Returns the new array of property names. - * @example - * - * _.functions(_); - * // => ['after', 'ary', 'assign', ...] - */ - function functions(object) { - return baseFunctions(object, keysIn(object)); - } + /** + * Checks if `value` is a DOM element. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. + * @example + * + * _.isElement(document.body); + * // => true + * + * _.isElement(''); + * // => false + */ + function isElement(value) { + return !!value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value); + } - /** - * Gets the property value at `path` of `object`. If the resolved value is - * `undefined` the `defaultValue` is used in its place. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @param {*} [defaultValue] The value returned if the resolved value is `undefined`. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.get(object, 'a[0].b.c'); - * // => 3 - * - * _.get(object, ['a', '0', 'b', 'c']); - * // => 3 - * - * _.get(object, 'a.b.c', 'default'); - * // => 'default' - */ - function get(object, path, defaultValue) { - var result = object == null ? undefined : baseGet(object, toPath(path), path + ''); - return result === undefined ? defaultValue : result; - } + /** + * Checks if `value` is empty. A value is considered empty unless it is an + * `arguments` object, array, string, or jQuery-like collection with a length + * greater than `0` or an object with own enumerable properties. + * + * @static + * @memberOf _ + * @category Lang + * @param {Array|Object|string} value The value to inspect. + * @returns {boolean} Returns `true` if `value` is empty, else `false`. + * @example + * + * _.isEmpty(null); + * // => true + * + * _.isEmpty(true); + * // => true + * + * _.isEmpty(1); + * // => true + * + * _.isEmpty([1, 2, 3]); + * // => false + * + * _.isEmpty({ 'a': 1 }); + * // => false + */ + function isEmpty(value) { + if (value == null) { + return true; + } + if ( + isArrayLike(value) && + (isArray(value) || + isString(value) || + isArguments(value) || + (isObjectLike(value) && isFunction(value.splice))) + ) { + return !value.length; + } + return !keys(value).length; + } - /** - * Checks if `path` is a direct property. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` is a direct property, else `false`. - * @example - * - * var object = { 'a': { 'b': { 'c': 3 } } }; - * - * _.has(object, 'a'); - * // => true - * - * _.has(object, 'a.b.c'); - * // => true - * - * _.has(object, ['a', 'b', 'c']); - * // => true - */ - function has(object, path) { - if (object == null) { - return false; - } - var result = hasOwnProperty.call(object, path); - if (!result && !isKey(path)) { - path = toPath(path); - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - if (object == null) { - return false; - } - path = last(path); - result = hasOwnProperty.call(object, path); - } - return result || (isLength(object.length) && isIndex(path, object.length) && - (isArray(object) || isArguments(object))); - } + /** + * Performs a deep comparison between two values to determine if they are + * equivalent. If `customizer` is provided it is invoked to compare values. + * If `customizer` returns `undefined` comparisons are handled by the method + * instead. The `customizer` is bound to `thisArg` and invoked with three + * arguments: (value, other [, index|key]). + * + * **Note:** This method supports comparing arrays, booleans, `Date` objects, + * numbers, `Object` objects, regexes, and strings. Objects are compared by + * their own, not inherited, enumerable properties. Functions and DOM nodes + * are **not** supported. Provide a customizer function to extend support + * for comparing other values. + * + * @static + * @memberOf _ + * @alias eq + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize value comparisons. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'user': 'fred' }; + * var other = { 'user': 'fred' }; + * + * object == other; + * // => false + * + * _.isEqual(object, other); + * // => true + * + * // using a customizer callback + * var array = ['hello', 'goodbye']; + * var other = ['hi', 'goodbye']; + * + * _.isEqual(array, other, function(value, other) { + * if (_.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/)) { + * return true; + * } + * }); + * // => true + */ + function isEqual(value, other, customizer, thisArg) { + customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined; + var result = customizer ? customizer(value, other) : undefined; + return result === undefined ? baseIsEqual(value, other, customizer) : !!result; + } - /** - * Creates an object composed of the inverted keys and values of `object`. - * If `object` contains duplicate values, subsequent values overwrite property - * assignments of previous values unless `multiValue` is `true`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to invert. - * @param {boolean} [multiValue] Allow multiple values per key. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invert(object); - * // => { '1': 'c', '2': 'b' } - * - * // with `multiValue` - * _.invert(object, true); - * // => { '1': ['a', 'c'], '2': ['b'] } - */ - function invert(object, multiValue, guard) { - if (guard && isIterateeCall(object, multiValue, guard)) { - multiValue = undefined; - } - var index = -1, - props = keys(object), - length = props.length, - result = {}; - - while (++index < length) { - var key = props[index], - value = object[key]; - - if (multiValue) { - if (hasOwnProperty.call(result, value)) { - result[value].push(key); - } else { - result[value] = [key]; - } - } - else { - result[value] = key; - } - } - return result; - } + /** + * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, + * `SyntaxError`, `TypeError`, or `URIError` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an error object, else `false`. + * @example + * + * _.isError(new Error); + * // => true + * + * _.isError(Error); + * // => false + */ + function isError(value) { + return isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag; + } - /** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) - * for more details. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) - * - * _.keys('hi'); - * // => ['0', '1'] - */ - var keys = !nativeKeys ? shimKeys : function(object) { - var Ctor = object == null ? undefined : object.constructor; - if ((typeof Ctor == 'function' && Ctor.prototype === object) || - (typeof object != 'function' && isArrayLike(object))) { - return shimKeys(object); - } - return isObject(object) ? nativeKeys(object) : []; - }; - - /** - * Creates an array of the own and inherited enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keysIn(new Foo); - * // => ['a', 'b', 'c'] (iteration order is not guaranteed) - */ - function keysIn(object) { - if (object == null) { - return []; - } - if (!isObject(object)) { - object = Object(object); - } - var length = object.length; - length = (length && isLength(length) && - (isArray(object) || isArguments(object)) && length) || 0; - - var Ctor = object.constructor, - index = -1, - isProto = typeof Ctor == 'function' && Ctor.prototype === object, - result = Array(length), - skipIndexes = length > 0; - - while (++index < length) { - result[index] = (index + ''); - } - for (var key in object) { - if (!(skipIndexes && isIndex(key, length)) && - !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - return result; - } + /** + * Checks if `value` is a finite primitive number. + * + * **Note:** This method is based on [`Number.isFinite`](http://ecma-international.org/ecma-262/6.0/#sec-number.isfinite). + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. + * @example + * + * _.isFinite(10); + * // => true + * + * _.isFinite('10'); + * // => false + * + * _.isFinite(true); + * // => false + * + * _.isFinite(Object(10)); + * // => false + * + * _.isFinite(Infinity); + * // => false + */ + function isFinite(value) { + return typeof value == 'number' && nativeIsFinite(value); + } - /** - * The opposite of `_.mapValues`; this method creates an object with the - * same values as `object` and keys generated by running each own enumerable - * property of `object` through `iteratee`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the new mapped object. - * @example - * - * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { - * return key + value; - * }); - * // => { 'a1': 1, 'b2': 2 } - */ - var mapKeys = createObjectMapper(true); - - /** - * Creates an object with the same keys as `object` and values generated by - * running each own enumerable property of `object` through `iteratee`. The - * iteratee function is bound to `thisArg` and invoked with three arguments: - * (value, key, object). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the new mapped object. - * @example - * - * _.mapValues({ 'a': 1, 'b': 2 }, function(n) { - * return n * 3; - * }); - * // => { 'a': 3, 'b': 6 } - * - * var users = { - * 'fred': { 'user': 'fred', 'age': 40 }, - * 'pebbles': { 'user': 'pebbles', 'age': 1 } - * }; - * - * // using the `_.property` callback shorthand - * _.mapValues(users, 'age'); - * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) - */ - var mapValues = createObjectMapper(); - - /** - * The opposite of `_.pick`; this method creates an object composed of the - * own and inherited enumerable properties of `object` that are not omitted. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {Function|...(string|string[])} [predicate] The function invoked per - * iteration or property names to omit, specified as individual property - * names or arrays of property names. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'user': 'fred', 'age': 40 }; - * - * _.omit(object, 'age'); - * // => { 'user': 'fred' } - * - * _.omit(object, _.isNumber); - * // => { 'user': 'fred' } - */ - var omit = restParam(function(object, props) { - if (object == null) { - return {}; - } - if (typeof props[0] != 'function') { - var props = arrayMap(baseFlatten(props), String); - return pickByArray(object, baseDifference(keysIn(object), props)); - } - var predicate = bindCallback(props[0], props[1], 3); - return pickByCallback(object, function(value, key, object) { - return !predicate(value, key, object); - }); - }); - - /** - * Creates a two dimensional array of the key-value pairs for `object`, - * e.g. `[[key1, value1], [key2, value2]]`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the new array of key-value pairs. - * @example - * - * _.pairs({ 'barney': 36, 'fred': 40 }); - * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed) - */ - function pairs(object) { - object = toObject(object); - - var index = -1, - props = keys(object), - length = props.length, - result = Array(length); - - while (++index < length) { - var key = props[index]; - result[index] = [key, object[key]]; - } - return result; - } + /** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ + function isFunction(value) { + // The use of `Object#toString` avoids issues with the `typeof` operator + // in older versions of Chrome and Safari which return 'function' for regexes + // and Safari 8 equivalents which return 'object' for typed array constructors. + return isObject(value) && objToString.call(value) == funcTag; + } - /** - * Creates an object composed of the picked `object` properties. Property - * names may be specified as individual arguments or as arrays of property - * names. If `predicate` is provided it is invoked for each property of `object` - * picking the properties `predicate` returns truthy for. The predicate is - * bound to `thisArg` and invoked with three arguments: (value, key, object). - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {Function|...(string|string[])} [predicate] The function invoked per - * iteration or property names to pick, specified as individual property - * names or arrays of property names. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'user': 'fred', 'age': 40 }; - * - * _.pick(object, 'user'); - * // => { 'user': 'fred' } - * - * _.pick(object, _.isString); - * // => { 'user': 'fred' } - */ - var pick = restParam(function(object, props) { - if (object == null) { - return {}; - } - return typeof props[0] == 'function' - ? pickByCallback(object, bindCallback(props[0], props[1], 3)) - : pickByArray(object, baseFlatten(props)); - }); - - /** - * This method is like `_.get` except that if the resolved value is a function - * it is invoked with the `this` binding of its parent object and its result - * is returned. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to resolve. - * @param {*} [defaultValue] The value returned if the resolved value is `undefined`. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; - * - * _.result(object, 'a[0].b.c1'); - * // => 3 - * - * _.result(object, 'a[0].b.c2'); - * // => 4 - * - * _.result(object, 'a.b.c', 'default'); - * // => 'default' - * - * _.result(object, 'a.b.c', _.constant('default')); - * // => 'default' - */ - function result(object, path, defaultValue) { - var result = object == null ? undefined : object[path]; - if (result === undefined) { - if (object != null && !isKey(path, object)) { - path = toPath(path); - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - result = object == null ? undefined : object[last(path)]; - } - result = result === undefined ? defaultValue : result; - } - return isFunction(result) ? result.call(object) : result; - } + /** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ + function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); + } - /** - * Sets the property value of `path` on `object`. If a portion of `path` - * does not exist it is created. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to augment. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @returns {Object} Returns `object`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.set(object, 'a[0].b.c', 4); - * console.log(object.a[0].b.c); - * // => 4 - * - * _.set(object, 'x[0].y.z', 5); - * console.log(object.x[0].y.z); - * // => 5 - */ - function set(object, path, value) { - if (object == null) { - return object; - } - var pathKey = (path + ''); - path = (object[pathKey] != null || isKey(path, object)) ? [pathKey] : toPath(path); + /** + * Performs a deep comparison between `object` and `source` to determine if + * `object` contains equivalent property values. If `customizer` is provided + * it is invoked to compare values. If `customizer` returns `undefined` + * comparisons are handled by the method instead. The `customizer` is bound + * to `thisArg` and invoked with three arguments: (value, other, index|key). + * + * **Note:** This method supports comparing properties of arrays, booleans, + * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions + * and DOM nodes are **not** supported. Provide a customizer function to extend + * support for comparing other values. + * + * @static + * @memberOf _ + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Function} [customizer] The function to customize value comparisons. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * var object = { 'user': 'fred', 'age': 40 }; + * + * _.isMatch(object, { 'age': 40 }); + * // => true + * + * _.isMatch(object, { 'age': 36 }); + * // => false + * + * // using a customizer callback + * var object = { 'greeting': 'hello' }; + * var source = { 'greeting': 'hi' }; + * + * _.isMatch(object, source, function(value, other) { + * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined; + * }); + * // => true + */ + function isMatch(object, source, customizer, thisArg) { + customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined; + return baseIsMatch(object, getMatchData(source), customizer); + } - var index = -1, - length = path.length, - lastIndex = length - 1, - nested = object; + /** + * Checks if `value` is `NaN`. + * + * **Note:** This method is not the same as [`isNaN`](https://es5.github.io/#x15.1.2.4) + * which returns `true` for `undefined` and other non-numeric values. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * _.isNaN(new Number(NaN)); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ + function isNaN(value) { + // An `NaN` primitive is the only value that is not equal to itself. + // Perform the `toStringTag` check first to avoid errors with some host objects in IE. + return isNumber(value) && value != +value; + } - while (nested != null && ++index < length) { - var key = path[index]; - if (isObject(nested)) { - if (index == lastIndex) { - nested[key] = value; - } else if (nested[key] == null) { - nested[key] = isIndex(path[index + 1]) ? [] : {}; - } - } - nested = nested[key]; - } - return object; - } + /** + * Checks if `value` is a native function. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ + function isNative(value) { + if (value == null) { + return false; + } + if (isFunction(value)) { + return reIsNative.test(fnToString.call(value)); + } + return isObjectLike(value) && reIsHostCtor.test(value); + } - /** - * An alternative to `_.reduce`; this method transforms `object` to a new - * `accumulator` object which is the result of running each of its own enumerable - * properties through `iteratee`, with each invocation potentially mutating - * the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked - * with four arguments: (accumulator, value, key, object). Iteratee functions - * may exit iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Array|Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The custom accumulator value. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {*} Returns the accumulated value. - * @example - * - * _.transform([2, 3, 4], function(result, n) { - * result.push(n *= n); - * return n % 2 == 0; - * }); - * // => [4, 9] - * - * _.transform({ 'a': 1, 'b': 2 }, function(result, n, key) { - * result[key] = n * 3; - * }); - * // => { 'a': 3, 'b': 6 } - */ - function transform(object, iteratee, accumulator, thisArg) { - var isArr = isArray(object) || isTypedArray(object); - iteratee = getCallback(iteratee, thisArg, 4); - - if (accumulator == null) { - if (isArr || isObject(object)) { - var Ctor = object.constructor; - if (isArr) { - accumulator = isArray(object) ? new Ctor : []; - } else { - accumulator = baseCreate(isFunction(Ctor) ? Ctor.prototype : undefined); - } - } else { - accumulator = {}; - } - } - (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) { - return iteratee(accumulator, value, index, object); - }); - return accumulator; - } + /** + * Checks if `value` is `null`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `null`, else `false`. + * @example + * + * _.isNull(null); + * // => true + * + * _.isNull(void 0); + * // => false + */ + function isNull(value) { + return value === null; + } - /** - * Creates an array of the own enumerable property values of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.values(new Foo); - * // => [1, 2] (iteration order is not guaranteed) - * - * _.values('hi'); - * // => ['h', 'i'] - */ - function values(object) { - return baseValues(object, keys(object)); - } + /** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified + * as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isNumber(8.4); + * // => true + * + * _.isNumber(NaN); + * // => true + * + * _.isNumber('8.4'); + * // => false + */ + function isNumber(value) { + return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag); + } - /** - * Creates an array of the own and inherited enumerable property values - * of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.valuesIn(new Foo); - * // => [1, 2, 3] (iteration order is not guaranteed) - */ - function valuesIn(object) { - return baseValues(object, keysIn(object)); - } + /** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * **Note:** This method assumes objects created by the `Object` constructor + * have no inherited enumerable properties. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ + function isPlainObject(value) { + var Ctor; + + // Exit early for non `Object` objects. + if ( + !(isObjectLike(value) && objToString.call(value) == objectTag && !isArguments(value)) || + (!hasOwnProperty.call(value, 'constructor') && + ((Ctor = value.constructor), typeof Ctor == 'function' && !(Ctor instanceof Ctor))) + ) { + return false; + } + // IE < 9 iterates inherited properties before own properties. If the first + // iterated property is an object's own property then there are no inherited + // enumerable properties. + var result; + // In most environments an object's own properties are iterated before + // its inherited properties. If the last iterated property is an object's + // own property then there are no inherited enumerable properties. + baseForIn(value, function(subValue, key) { + result = key; + }); + return result === undefined || hasOwnProperty.call(value, result); + } - /*------------------------------------------------------------------------*/ - - /** - * Checks if `n` is between `start` and up to but not including, `end`. If - * `end` is not specified it is set to `start` with `start` then set to `0`. - * - * @static - * @memberOf _ - * @category Number - * @param {number} n The number to check. - * @param {number} [start=0] The start of the range. - * @param {number} end The end of the range. - * @returns {boolean} Returns `true` if `n` is in the range, else `false`. - * @example - * - * _.inRange(3, 2, 4); - * // => true - * - * _.inRange(4, 8); - * // => true - * - * _.inRange(4, 2); - * // => false - * - * _.inRange(2, 2); - * // => false - * - * _.inRange(1.2, 2); - * // => true - * - * _.inRange(5.2, 4); - * // => false - */ - function inRange(value, start, end) { - start = +start || 0; - if (end === undefined) { - end = start; - start = 0; - } else { - end = +end || 0; - } - return value >= nativeMin(start, end) && value < nativeMax(start, end); - } + /** + * Checks if `value` is classified as a `RegExp` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isRegExp(/abc/); + * // => true + * + * _.isRegExp('/abc/'); + * // => false + */ + function isRegExp(value) { + return isObject(value) && objToString.call(value) == regexpTag; + } - /** - * Produces a random number between `min` and `max` (inclusive). If only one - * argument is provided a number between `0` and the given number is returned. - * If `floating` is `true`, or either `min` or `max` are floats, a floating-point - * number is returned instead of an integer. - * - * @static - * @memberOf _ - * @category Number - * @param {number} [min=0] The minimum possible value. - * @param {number} [max=1] The maximum possible value. - * @param {boolean} [floating] Specify returning a floating-point number. - * @returns {number} Returns the random number. - * @example - * - * _.random(0, 5); - * // => an integer between 0 and 5 - * - * _.random(5); - * // => also an integer between 0 and 5 - * - * _.random(5, true); - * // => a floating-point number between 0 and 5 - * - * _.random(1.2, 5.2); - * // => a floating-point number between 1.2 and 5.2 - */ - function random(min, max, floating) { - if (floating && isIterateeCall(min, max, floating)) { - max = floating = undefined; - } - var noMin = min == null, - noMax = max == null; + /** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ + function isString(value) { + return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag); + } - if (floating == null) { - if (noMax && typeof min == 'boolean') { - floating = min; - min = 1; - } - else if (typeof max == 'boolean') { - floating = max; - noMax = true; - } - } - if (noMin && noMax) { - max = 1; - noMax = false; - } - min = +min || 0; - if (noMax) { - max = min; - min = 0; - } else { - max = +max || 0; - } - if (floating || min % 1 || max % 1) { - var rand = nativeRandom(); - return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand + '').length - 1)))), max); - } - return baseRandom(min, max); - } + /** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ + function isTypedArray(value) { + return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)]; + } - /*------------------------------------------------------------------------*/ - - /** - * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the camel cased string. - * @example - * - * _.camelCase('Foo Bar'); - * // => 'fooBar' - * - * _.camelCase('--foo-bar'); - * // => 'fooBar' - * - * _.camelCase('__foo_bar__'); - * // => 'fooBar' - */ - var camelCase = createCompounder(function(result, word, index) { - word = word.toLowerCase(); - return result + (index ? (word.charAt(0).toUpperCase() + word.slice(1)) : word); - }); - - /** - * Capitalizes the first character of `string`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to capitalize. - * @returns {string} Returns the capitalized string. - * @example - * - * _.capitalize('fred'); - * // => 'Fred' - */ - function capitalize(string) { - string = baseToString(string); - return string && (string.charAt(0).toUpperCase() + string.slice(1)); - } + /** + * Checks if `value` is `undefined`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + * @example + * + * _.isUndefined(void 0); + * // => true + * + * _.isUndefined(null); + * // => false + */ + function isUndefined(value) { + return value === undefined; + } - /** - * Deburrs `string` by converting [latin-1 supplementary letters](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) - * to basic latin letters and removing [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to deburr. - * @returns {string} Returns the deburred string. - * @example - * - * _.deburr('dรฉjร  vu'); - * // => 'deja vu' - */ - function deburr(string) { - string = baseToString(string); - return string && string.replace(reLatin1, deburrLetter).replace(reComboMark, ''); - } + /** + * Checks if `value` is less than `other`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than `other`, else `false`. + * @example + * + * _.lt(1, 3); + * // => true + * + * _.lt(3, 3); + * // => false + * + * _.lt(3, 1); + * // => false + */ + function lt(value, other) { + return value < other; + } - /** - * Checks if `string` ends with the given target string. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to search. - * @param {string} [target] The string to search for. - * @param {number} [position=string.length] The position to search from. - * @returns {boolean} Returns `true` if `string` ends with `target`, else `false`. - * @example - * - * _.endsWith('abc', 'c'); - * // => true - * - * _.endsWith('abc', 'b'); - * // => false - * - * _.endsWith('abc', 'b', 2); - * // => true - */ - function endsWith(string, target, position) { - string = baseToString(string); - target = (target + ''); - - var length = string.length; - position = position === undefined - ? length - : nativeMin(position < 0 ? 0 : (+position || 0), length); - - position -= target.length; - return position >= 0 && string.indexOf(target, position) == position; - } + /** + * Checks if `value` is less than or equal to `other`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than or equal to `other`, else `false`. + * @example + * + * _.lte(1, 3); + * // => true + * + * _.lte(3, 3); + * // => true + * + * _.lte(3, 1); + * // => false + */ + function lte(value, other) { + return value <= other; + } - /** - * Converts the characters "&", "<", ">", '"', "'", and "\`", in `string` to - * their corresponding HTML entities. - * - * **Note:** No other characters are escaped. To escape additional characters - * use a third-party library like [_he_](https://mths.be/he). - * - * Though the ">" character is escaped for symmetry, characters like - * ">" and "/" don't need escaping in HTML and have no special meaning - * unless they're part of a tag or unquoted attribute value. - * See [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) - * (under "semi-related fun fact") for more details. - * - * Backticks are escaped because in Internet Explorer < 9, they can break out - * of attribute values or HTML comments. See [#59](https://html5sec.org/#59), - * [#102](https://html5sec.org/#102), [#108](https://html5sec.org/#108), and - * [#133](https://html5sec.org/#133) of the [HTML5 Security Cheatsheet](https://html5sec.org/) - * for more details. - * - * When working with HTML you should always [quote attribute values](http://wonko.com/post/html-escaping) - * to reduce XSS vectors. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escape('fred, barney, & pebbles'); - * // => 'fred, barney, & pebbles' - */ - function escape(string) { - // Reset `lastIndex` because in IE < 9 `String#replace` does not. - string = baseToString(string); - return (string && reHasUnescapedHtml.test(string)) - ? string.replace(reUnescapedHtml, escapeHtmlChar) - : string; - } + /** + * Converts `value` to an array. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {Array} Returns the converted array. + * @example + * + * (function() { + * return _.toArray(arguments).slice(1); + * }(1, 2, 3)); + * // => [2, 3] + */ + function toArray(value) { + var length = value ? getLength(value) : 0; + if (!isLength(length)) { + return values(value); + } + if (!length) { + return []; + } + return arrayCopy(value); + } - /** - * Escapes the `RegExp` special characters "\", "/", "^", "$", ".", "|", "?", - * "*", "+", "(", ")", "[", "]", "{" and "}" in `string`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escapeRegExp('[lodash](https://lodash.com/)'); - * // => '\[lodash\]\(https:\/\/lodash\.com\/\)' - */ - function escapeRegExp(string) { - string = baseToString(string); - return (string && reHasRegExpChars.test(string)) - ? string.replace(reRegExpChars, escapeRegExpChar) - : (string || '(?:)'); - } + /** + * Converts `value` to a plain object flattening inherited enumerable + * properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ + function toPlainObject(value) { + return baseCopy(value, keysIn(value)); + } - /** - * Converts `string` to [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the kebab cased string. - * @example - * - * _.kebabCase('Foo Bar'); - * // => 'foo-bar' - * - * _.kebabCase('fooBar'); - * // => 'foo-bar' - * - * _.kebabCase('__foo_bar__'); - * // => 'foo-bar' - */ - var kebabCase = createCompounder(function(result, word, index) { - return result + (index ? '-' : '') + word.toLowerCase(); - }); - - /** - * Pads `string` on the left and right sides if it's shorter than `length`. - * Padding characters are truncated if they can't be evenly divided by `length`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.pad('abc', 8); - * // => ' abc ' - * - * _.pad('abc', 8, '_-'); - * // => '_-abc_-_' - * - * _.pad('abc', 3); - * // => 'abc' - */ - function pad(string, length, chars) { - string = baseToString(string); - length = +length; - - var strLength = string.length; - if (strLength >= length || !nativeIsFinite(length)) { - return string; - } - var mid = (length - strLength) / 2, - leftLength = nativeFloor(mid), - rightLength = nativeCeil(mid); + /*------------------------------------------------------------------------*/ + + /** + * Recursively merges own enumerable properties of the source object(s), that + * don't resolve to `undefined` into the destination object. Subsequent sources + * overwrite property assignments of previous sources. If `customizer` is + * provided it is invoked to produce the merged values of the destination and + * source properties. If `customizer` returns `undefined` merging is handled + * by the method instead. The `customizer` is bound to `thisArg` and invoked + * with five arguments: (objectValue, sourceValue, key, object, source). + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {Object} Returns `object`. + * @example + * + * var users = { + * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] + * }; + * + * var ages = { + * 'data': [{ 'age': 36 }, { 'age': 40 }] + * }; + * + * _.merge(users, ages); + * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } + * + * // using a customizer callback + * var object = { + * 'fruits': ['apple'], + * 'vegetables': ['beet'] + * }; + * + * var other = { + * 'fruits': ['banana'], + * 'vegetables': ['carrot'] + * }; + * + * _.merge(object, other, function(a, b) { + * if (_.isArray(a)) { + * return a.concat(b); + * } + * }); + * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } + */ + var merge = createAssigner(baseMerge); + + /** + * Assigns own enumerable properties of source object(s) to the destination + * object. Subsequent sources overwrite property assignments of previous sources. + * If `customizer` is provided it is invoked to produce the assigned values. + * The `customizer` is bound to `thisArg` and invoked with five arguments: + * (objectValue, sourceValue, key, object, source). + * + * **Note:** This method mutates `object` and is based on + * [`Object.assign`](http://ecma-international.org/ecma-262/6.0/#sec-object.assign). + * + * @static + * @memberOf _ + * @alias extend + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {Object} Returns `object`. + * @example + * + * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' }); + * // => { 'user': 'fred', 'age': 40 } + * + * // using a customizer callback + * var defaults = _.partialRight(_.assign, function(value, other) { + * return _.isUndefined(value) ? other : value; + * }); + * + * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); + * // => { 'user': 'barney', 'age': 36 } + */ + var assign = createAssigner(function(object, source, customizer) { + return customizer ? assignWith(object, source, customizer) : baseAssign(object, source); + }); + + /** + * Creates an object that inherits from the given `prototype` object. If a + * `properties` object is provided its own enumerable properties are assigned + * to the created object. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} prototype The object to inherit from. + * @param {Object} [properties] The properties to assign to the object. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Object} Returns the new object. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * function Circle() { + * Shape.call(this); + * } + * + * Circle.prototype = _.create(Shape.prototype, { + * 'constructor': Circle + * }); + * + * var circle = new Circle; + * circle instanceof Circle; + * // => true + * + * circle instanceof Shape; + * // => true + */ + function create(prototype, properties, guard) { + var result = baseCreate(prototype); + if (guard && isIterateeCall(prototype, properties, guard)) { + properties = undefined; + } + return properties ? baseAssign(result, properties) : result; + } - chars = createPadding('', rightLength, chars); - return chars.slice(0, leftLength) + string + chars; - } + /** + * Assigns own enumerable properties of source object(s) to the destination + * object for all destination properties that resolve to `undefined`. Once a + * property is set, additional values of the same property are ignored. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); + * // => { 'user': 'barney', 'age': 36 } + */ + var defaults = createDefaults(assign, assignDefaults); + + /** + * This method is like `_.defaults` except that it recursively assigns + * default properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * _.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } }); + * // => { 'user': { 'name': 'barney', 'age': 36 } } + * + */ + var defaultsDeep = createDefaults(merge, mergeDefaults); + + /** + * This method is like `_.find` except that it returns the key of the first + * element `predicate` returns truthy for instead of the element itself. + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {string|undefined} Returns the key of the matched element, else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findKey(users, function(chr) { + * return chr.age < 40; + * }); + * // => 'barney' (iteration order is not guaranteed) + * + * // using the `_.matches` callback shorthand + * _.findKey(users, { 'age': 1, 'active': true }); + * // => 'pebbles' + * + * // using the `_.matchesProperty` callback shorthand + * _.findKey(users, 'active', false); + * // => 'fred' + * + * // using the `_.property` callback shorthand + * _.findKey(users, 'active'); + * // => 'barney' + */ + var findKey = createFindKey(baseForOwn); + + /** + * This method is like `_.findKey` except that it iterates over elements of + * a collection in the opposite order. + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {string|undefined} Returns the key of the matched element, else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findLastKey(users, function(chr) { + * return chr.age < 40; + * }); + * // => returns `pebbles` assuming `_.findKey` returns `barney` + * + * // using the `_.matches` callback shorthand + * _.findLastKey(users, { 'age': 36, 'active': true }); + * // => 'barney' + * + * // using the `_.matchesProperty` callback shorthand + * _.findLastKey(users, 'active', false); + * // => 'fred' + * + * // using the `_.property` callback shorthand + * _.findLastKey(users, 'active'); + * // => 'pebbles' + */ + var findLastKey = createFindKey(baseForOwnRight); + + /** + * Iterates over own and inherited enumerable properties of an object invoking + * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked + * with three arguments: (value, key, object). Iteratee functions may exit + * iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns `object`. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forIn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed) + */ + var forIn = createForIn(baseFor); + + /** + * This method is like `_.forIn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns `object`. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forInRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c' + */ + var forInRight = createForIn(baseForRight); + + /** + * Iterates over own enumerable properties of an object invoking `iteratee` + * for each property. The `iteratee` is bound to `thisArg` and invoked with + * three arguments: (value, key, object). Iteratee functions may exit iteration + * early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns `object`. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forOwn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => logs 'a' and 'b' (iteration order is not guaranteed) + */ + var forOwn = createForOwn(baseForOwn); + + /** + * This method is like `_.forOwn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns `object`. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forOwnRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => logs 'b' and 'a' assuming `_.forOwn` logs 'a' and 'b' + */ + var forOwnRight = createForOwn(baseForOwnRight); + + /** + * Creates an array of function property names from all enumerable properties, + * own and inherited, of `object`. + * + * @static + * @memberOf _ + * @alias methods + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the new array of property names. + * @example + * + * _.functions(_); + * // => ['after', 'ary', 'assign', ...] + */ + function functions(object) { + return baseFunctions(object, keysIn(object)); + } - /** - * Pads `string` on the left side if it's shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padLeft('abc', 6); - * // => ' abc' - * - * _.padLeft('abc', 6, '_-'); - * // => '_-_abc' - * - * _.padLeft('abc', 3); - * // => 'abc' - */ - var padLeft = createPadDir(); - - /** - * Pads `string` on the right side if it's shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padRight('abc', 6); - * // => 'abc ' - * - * _.padRight('abc', 6, '_-'); - * // => 'abc_-_' - * - * _.padRight('abc', 3); - * // => 'abc' - */ - var padRight = createPadDir(true); - - /** - * Converts `string` to an integer of the specified radix. If `radix` is - * `undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal, - * in which case a `radix` of `16` is used. - * - * **Note:** This method aligns with the [ES5 implementation](https://es5.github.io/#E) - * of `parseInt`. - * - * @static - * @memberOf _ - * @category String - * @param {string} string The string to convert. - * @param {number} [radix] The radix to interpret `value` by. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {number} Returns the converted integer. - * @example - * - * _.parseInt('08'); - * // => 8 - * - * _.map(['6', '08', '10'], _.parseInt); - * // => [6, 8, 10] - */ - function parseInt(string, radix, guard) { - // Firefox < 21 and Opera < 15 follow ES3 for `parseInt`. - // Chrome fails to trim leading whitespace characters. - // See https://code.google.com/p/v8/issues/detail?id=3109 for more details. - if (guard ? isIterateeCall(string, radix, guard) : radix == null) { - radix = 0; - } else if (radix) { - radix = +radix; - } - string = trim(string); - return nativeParseInt(string, radix || (reHasHexPrefix.test(string) ? 16 : 10)); - } + /** + * Gets the property value at `path` of `object`. If the resolved value is + * `undefined` the `defaultValue` is used in its place. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @param {*} [defaultValue] The value returned if the resolved value is `undefined`. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.get(object, 'a[0].b.c'); + * // => 3 + * + * _.get(object, ['a', '0', 'b', 'c']); + * // => 3 + * + * _.get(object, 'a.b.c', 'default'); + * // => 'default' + */ + function get(object, path, defaultValue) { + var result = object == null ? undefined : baseGet(object, toPath(path), path + ''); + return result === undefined ? defaultValue : result; + } - /** - * Repeats the given string `n` times. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to repeat. - * @param {number} [n=0] The number of times to repeat the string. - * @returns {string} Returns the repeated string. - * @example - * - * _.repeat('*', 3); - * // => '***' - * - * _.repeat('abc', 2); - * // => 'abcabc' - * - * _.repeat('abc', 0); - * // => '' - */ - function repeat(string, n) { - var result = ''; - string = baseToString(string); - n = +n; - if (n < 1 || !string || !nativeIsFinite(n)) { - return result; - } - // Leverage the exponentiation by squaring algorithm for a faster repeat. - // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. - do { - if (n % 2) { - result += string; - } - n = nativeFloor(n / 2); - string += string; - } while (n); + /** + * Checks if `path` is a direct property. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` is a direct property, else `false`. + * @example + * + * var object = { 'a': { 'b': { 'c': 3 } } }; + * + * _.has(object, 'a'); + * // => true + * + * _.has(object, 'a.b.c'); + * // => true + * + * _.has(object, ['a', 'b', 'c']); + * // => true + */ + function has(object, path) { + if (object == null) { + return false; + } + var result = hasOwnProperty.call(object, path); + if (!result && !isKey(path)) { + path = toPath(path); + object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); + if (object == null) { + return false; + } + path = last(path); + result = hasOwnProperty.call(object, path); + } + return ( + result || + (isLength(object.length) && isIndex(path, object.length) && (isArray(object) || isArguments(object))) + ); + } - return result; - } + /** + * Creates an object composed of the inverted keys and values of `object`. + * If `object` contains duplicate values, subsequent values overwrite property + * assignments of previous values unless `multiValue` is `true`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to invert. + * @param {boolean} [multiValue] Allow multiple values per key. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Object} Returns the new inverted object. + * @example + * + * var object = { 'a': 1, 'b': 2, 'c': 1 }; + * + * _.invert(object); + * // => { '1': 'c', '2': 'b' } + * + * // with `multiValue` + * _.invert(object, true); + * // => { '1': ['a', 'c'], '2': ['b'] } + */ + function invert(object, multiValue, guard) { + if (guard && isIterateeCall(object, multiValue, guard)) { + multiValue = undefined; + } + var index = -1, + props = keys(object), + length = props.length, + result = {}; + + while (++index < length) { + var key = props[index], + value = object[key]; + + if (multiValue) { + if (hasOwnProperty.call(result, value)) { + result[value].push(key); + } else { + result[value] = [key]; + } + } else { + result[value] = key; + } + } + return result; + } - /** - * Converts `string` to [snake case](https://en.wikipedia.org/wiki/Snake_case). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the snake cased string. - * @example - * - * _.snakeCase('Foo Bar'); - * // => 'foo_bar' - * - * _.snakeCase('fooBar'); - * // => 'foo_bar' - * - * _.snakeCase('--foo-bar'); - * // => 'foo_bar' - */ - var snakeCase = createCompounder(function(result, word, index) { - return result + (index ? '_' : '') + word.toLowerCase(); - }); - - /** - * Converts `string` to [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the start cased string. - * @example - * - * _.startCase('--foo-bar'); - * // => 'Foo Bar' - * - * _.startCase('fooBar'); - * // => 'Foo Bar' - * - * _.startCase('__foo_bar__'); - * // => 'Foo Bar' - */ - var startCase = createCompounder(function(result, word, index) { - return result + (index ? ' ' : '') + (word.charAt(0).toUpperCase() + word.slice(1)); - }); - - /** - * Checks if `string` starts with the given target string. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to search. - * @param {string} [target] The string to search for. - * @param {number} [position=0] The position to search from. - * @returns {boolean} Returns `true` if `string` starts with `target`, else `false`. - * @example - * - * _.startsWith('abc', 'a'); - * // => true - * - * _.startsWith('abc', 'b'); - * // => false - * - * _.startsWith('abc', 'b', 1); - * // => true - */ - function startsWith(string, target, position) { - string = baseToString(string); - position = position == null - ? 0 - : nativeMin(position < 0 ? 0 : (+position || 0), string.length); - - return string.lastIndexOf(target, position) == position; - } + /** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) + * for more details. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ + var keys = !nativeKeys + ? shimKeys + : function(object) { + var Ctor = object == null ? undefined : object.constructor; + if ( + (typeof Ctor == 'function' && Ctor.prototype === object) || + (typeof object != 'function' && isArrayLike(object)) + ) { + return shimKeys(object); + } + return isObject(object) ? nativeKeys(object) : []; + }; + + /** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ + function keysIn(object) { + if (object == null) { + return []; + } + if (!isObject(object)) { + object = Object(object); + } + var length = object.length; + length = (length && isLength(length) && (isArray(object) || isArguments(object)) && length) || 0; + + var Ctor = object.constructor, + index = -1, + isProto = typeof Ctor == 'function' && Ctor.prototype === object, + result = Array(length), + skipIndexes = length > 0; + + while (++index < length) { + result[index] = index + ''; + } + for (var key in object) { + if ( + !(skipIndexes && isIndex(key, length)) && + !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key))) + ) { + result.push(key); + } + } + return result; + } - /** - * Creates a compiled template function that can interpolate data properties - * in "interpolate" delimiters, HTML-escape interpolated data properties in - * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data - * properties may be accessed as free variables in the template. If a setting - * object is provided it takes precedence over `_.templateSettings` values. - * - * **Note:** In the development build `_.template` utilizes - * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) - * for easier debugging. - * - * For more information on precompiling templates see - * [lodash's custom builds documentation](https://lodash.com/custom-builds). - * - * For more information on Chrome extension sandboxes see - * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The template string. - * @param {Object} [options] The options object. - * @param {RegExp} [options.escape] The HTML "escape" delimiter. - * @param {RegExp} [options.evaluate] The "evaluate" delimiter. - * @param {Object} [options.imports] An object to import into the template as free variables. - * @param {RegExp} [options.interpolate] The "interpolate" delimiter. - * @param {string} [options.sourceURL] The sourceURL of the template's compiled source. - * @param {string} [options.variable] The data object variable name. - * @param- {Object} [otherOptions] Enables the legacy `options` param signature. - * @returns {Function} Returns the compiled template function. - * @example - * - * // using the "interpolate" delimiter to create a compiled template - * var compiled = _.template('hello <%= user %>!'); - * compiled({ 'user': 'fred' }); - * // => 'hello fred!' - * - * // using the HTML "escape" delimiter to escape data property values - * var compiled = _.template('<%- value %>'); - * compiled({ 'value': '