mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Fix merge conflicts. Modify send workflow
This commit is contained in:
commit
35875863d2
@ -17,8 +17,17 @@ workflows:
|
|||||||
- prep-deps-npm
|
- prep-deps-npm
|
||||||
- test-e2e:
|
- test-e2e:
|
||||||
requires:
|
requires:
|
||||||
- prep-build
|
|
||||||
- prep-deps-npm
|
- prep-deps-npm
|
||||||
|
- prep-build
|
||||||
|
- job-screens:
|
||||||
|
requires:
|
||||||
|
- prep-deps-npm
|
||||||
|
- prep-build
|
||||||
|
- job-announce:
|
||||||
|
requires:
|
||||||
|
- prep-deps-npm
|
||||||
|
- prep-build
|
||||||
|
- job-screens
|
||||||
- test-unit:
|
- test-unit:
|
||||||
requires:
|
requires:
|
||||||
- prep-deps-npm
|
- prep-deps-npm
|
||||||
@ -45,6 +54,7 @@ workflows:
|
|||||||
- test-lint
|
- test-lint
|
||||||
- test-unit
|
- test-unit
|
||||||
- test-e2e
|
- test-e2e
|
||||||
|
- job-screens
|
||||||
- test-integration-mascara-chrome
|
- test-integration-mascara-chrome
|
||||||
- test-integration-mascara-firefox
|
- test-integration-mascara-firefox
|
||||||
- test-integration-flat-chrome
|
- test-integration-flat-chrome
|
||||||
@ -98,32 +108,7 @@ jobs:
|
|||||||
key: build-cache-{{ .Revision }}
|
key: build-cache-{{ .Revision }}
|
||||||
paths:
|
paths:
|
||||||
- dist
|
- dist
|
||||||
- store_artifacts:
|
- builds
|
||||||
path: dist/mascara
|
|
||||||
destination: builds/mascara
|
|
||||||
- store_artifacts:
|
|
||||||
path: builds
|
|
||||||
destination: builds
|
|
||||||
- run:
|
|
||||||
name: build:announce
|
|
||||||
command: |
|
|
||||||
CIRCLE_PR_NUMBER="${CIRCLE_PR_NUMBER:-${CIRCLE_PULL_REQUEST##*/}}"
|
|
||||||
SHORT_SHA1=$(echo $CIRCLE_SHA1 | cut -c 1-7)
|
|
||||||
BUILD_LINK_BASE="https://$CIRCLE_BUILD_NUM-42009758-gh.circle-artifacts.com/0/builds"
|
|
||||||
VERSION=$(node -p 'require("./dist/chrome/manifest.json").version')
|
|
||||||
MASCARA="$BUILD_LINK_BASE/mascara/home.html"
|
|
||||||
CHROME="$BUILD_LINK_BASE/metamask-chrome-$VERSION.zip"
|
|
||||||
FIREFOX="$BUILD_LINK_BASE/metamask-firefox-$VERSION.zip"
|
|
||||||
OPERA="$BUILD_LINK_BASE/metamask-opera-$VERSION.zip"
|
|
||||||
EDGE="$BUILD_LINK_BASE/metamask-edge-$VERSION.zip"
|
|
||||||
COMMENT_MAIN="Builds ready [$SHORT_SHA1]: [mascara][mascara], [chrome][chrome], [firefox][firefox], [edge][edge], [opera][opera]"
|
|
||||||
COMMENT_LINKS="[mascara]:$MASCARA\n[chrome]:$CHROME\n[firefox]:$FIREFOX\n[opera]:$OPERA\n[edge]:$EDGE\n"
|
|
||||||
COMMENT_BODY="$COMMENT_MAIN\n\n$COMMENT_LINKS"
|
|
||||||
JSON_PAYLOAD="{\"body\":\"$COMMENT_BODY\"}"
|
|
||||||
POST_COMMENT_URI="https://api.github.com/repos/metamask/metamask-extension/issues/$CIRCLE_PR_NUMBER/comments"
|
|
||||||
echo "Announcement:\n$COMMENT_BODY"
|
|
||||||
echo "Posting to $POST_COMMENT_URI"
|
|
||||||
curl -d "$JSON_PAYLOAD" -H "Authorization: token $GITHUB_COMMENT_TOKEN" $POST_COMMENT_URI
|
|
||||||
|
|
||||||
prep-scss:
|
prep-scss:
|
||||||
docker:
|
docker:
|
||||||
@ -171,6 +156,47 @@ jobs:
|
|||||||
path: test-artifacts
|
path: test-artifacts
|
||||||
destination: test-artifacts
|
destination: test-artifacts
|
||||||
|
|
||||||
|
job-screens:
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:8-browsers
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- restore_cache:
|
||||||
|
key: dependency-cache-{{ checksum "package-lock.json" }}
|
||||||
|
- restore_cache:
|
||||||
|
key: build-cache-{{ .Revision }}
|
||||||
|
- run:
|
||||||
|
name: Test
|
||||||
|
command: npm run test:screens
|
||||||
|
- save_cache:
|
||||||
|
key: job-screens-{{ .Revision }}
|
||||||
|
paths:
|
||||||
|
- test-artifacts
|
||||||
|
|
||||||
|
job-announce:
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:8-browsers
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- restore_cache:
|
||||||
|
key: dependency-cache-{{ checksum "package-lock.json" }}
|
||||||
|
- restore_cache:
|
||||||
|
key: build-cache-{{ .Revision }}
|
||||||
|
- restore_cache:
|
||||||
|
key: job-screens-{{ .Revision }}
|
||||||
|
- store_artifacts:
|
||||||
|
path: dist/mascara
|
||||||
|
destination: builds/mascara
|
||||||
|
- store_artifacts:
|
||||||
|
path: builds
|
||||||
|
destination: builds
|
||||||
|
- store_artifacts:
|
||||||
|
path: test-artifacts
|
||||||
|
destination: test-artifacts
|
||||||
|
- run:
|
||||||
|
name: build:announce
|
||||||
|
command: ./development/metamaskbot-build-announce.js
|
||||||
|
|
||||||
test-unit:
|
test-unit:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/node:8-browsers
|
- image: circleci/node:8-browsers
|
||||||
|
@ -29,7 +29,8 @@
|
|||||||
"plugins": [
|
"plugins": [
|
||||||
"mocha",
|
"mocha",
|
||||||
"chai",
|
"chai",
|
||||||
"react"
|
"react",
|
||||||
|
"json"
|
||||||
],
|
],
|
||||||
|
|
||||||
"globals": {
|
"globals": {
|
||||||
@ -41,6 +42,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"no-restricted-globals": ["error", "event"],
|
||||||
"accessor-pairs": 2,
|
"accessor-pairs": 2,
|
||||||
"arrow-spacing": [2, { "before": true, "after": true }],
|
"arrow-spacing": [2, { "before": true, "after": true }],
|
||||||
"block-spacing": [2, "always"],
|
"block-spacing": [2, "always"],
|
||||||
|
@ -232,7 +232,7 @@
|
|||||||
"done": {
|
"done": {
|
||||||
"message": "Fertig"
|
"message": "Fertig"
|
||||||
},
|
},
|
||||||
"downloadStatelogs": {
|
"downloadStateLogs": {
|
||||||
"message": "Statelogs herunterladen"
|
"message": "Statelogs herunterladen"
|
||||||
},
|
},
|
||||||
"dropped": {
|
"dropped": {
|
||||||
|
@ -826,6 +826,9 @@
|
|||||||
"transactions": {
|
"transactions": {
|
||||||
"message": "transactions"
|
"message": "transactions"
|
||||||
},
|
},
|
||||||
|
"transactionError": {
|
||||||
|
"message": "Transaction Error. Exception thrown in contract code."
|
||||||
|
},
|
||||||
"transactionMemo": {
|
"transactionMemo": {
|
||||||
"message": "Transaction memo (optional)"
|
"message": "Transaction memo (optional)"
|
||||||
},
|
},
|
||||||
|
@ -247,7 +247,7 @@
|
|||||||
"done": {
|
"done": {
|
||||||
"message": "Completo"
|
"message": "Completo"
|
||||||
},
|
},
|
||||||
"downloadStatelogs": {
|
"downloadStateLogs": {
|
||||||
"message": "Descargar logs de estado"
|
"message": "Descargar logs de estado"
|
||||||
},
|
},
|
||||||
"dropped": {
|
"dropped": {
|
||||||
|
@ -223,7 +223,7 @@
|
|||||||
"done": {
|
"done": {
|
||||||
"message": "संपन्न"
|
"message": "संपन्न"
|
||||||
},
|
},
|
||||||
"downloadStatelogs": {
|
"downloadStateLogs": {
|
||||||
"message": "राज्य लॉग डाउनलोड करें"
|
"message": "राज्य लॉग डाउनलोड करें"
|
||||||
},
|
},
|
||||||
"edit": {
|
"edit": {
|
||||||
|
@ -223,7 +223,7 @@
|
|||||||
"done": {
|
"done": {
|
||||||
"message": "Gedaan"
|
"message": "Gedaan"
|
||||||
},
|
},
|
||||||
"downloadStatelogs": {
|
"downloadStateLogs": {
|
||||||
"message": "Staatslogboeken downloaden"
|
"message": "Staatslogboeken downloaden"
|
||||||
},
|
},
|
||||||
"edit": {
|
"edit": {
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
"message": "Принять"
|
"message": "Принять"
|
||||||
},
|
},
|
||||||
"account": {
|
"account": {
|
||||||
"message": "Аккаунт"
|
"message": "Счет"
|
||||||
},
|
},
|
||||||
"accountDetails": {
|
"accountDetails": {
|
||||||
"message": "Детали Аккаунта"
|
"message": "Детали счета"
|
||||||
},
|
},
|
||||||
"accountName": {
|
"accountName": {
|
||||||
"message": "Имя Пользователя"
|
"message": "Название счета"
|
||||||
},
|
},
|
||||||
"address": {
|
"address": {
|
||||||
"message": "Адрес"
|
"message": "Адрес"
|
||||||
@ -21,13 +21,13 @@
|
|||||||
"message": "Добавить токен"
|
"message": "Добавить токен"
|
||||||
},
|
},
|
||||||
"addTokens": {
|
"addTokens": {
|
||||||
"message": "Добавить Токены"
|
"message": "Добавить токены"
|
||||||
},
|
},
|
||||||
"amount": {
|
"amount": {
|
||||||
"message": "Количество"
|
"message": "Сумма"
|
||||||
},
|
},
|
||||||
"amountPlusGas": {
|
"amountPlusGas": {
|
||||||
"message": "Количество + газ"
|
"message": "Сумма + газ"
|
||||||
},
|
},
|
||||||
"appDescription": {
|
"appDescription": {
|
||||||
"message": "Расширение браузера для Ethereum",
|
"message": "Расширение браузера для Ethereum",
|
||||||
@ -37,11 +37,14 @@
|
|||||||
"message": "MetaMask",
|
"message": "MetaMask",
|
||||||
"description": "The name of the application"
|
"description": "The name of the application"
|
||||||
},
|
},
|
||||||
|
"approved": {
|
||||||
|
"message": "Одобрена"
|
||||||
|
},
|
||||||
"attemptingConnect": {
|
"attemptingConnect": {
|
||||||
"message": "Попытка подключиться к блокчейн сети."
|
"message": "Попытка подключиться к блокчейн сети."
|
||||||
},
|
},
|
||||||
"attributions": {
|
"attributions": {
|
||||||
"message": "Опознания"
|
"message": "Атрибуция"
|
||||||
},
|
},
|
||||||
"available": {
|
"available": {
|
||||||
"message": "Доступный"
|
"message": "Доступный"
|
||||||
@ -53,13 +56,13 @@
|
|||||||
"message": "Баланс:"
|
"message": "Баланс:"
|
||||||
},
|
},
|
||||||
"balances": {
|
"balances": {
|
||||||
"message": "Ваши балансы"
|
"message": "Ваш баланс"
|
||||||
},
|
},
|
||||||
"balanceIsInsufficientGas": {
|
"balanceIsInsufficientGas": {
|
||||||
"message": "Недостаточный баланс для текущего объема газа"
|
"message": "Недостаточный баланс для текущего объема газа"
|
||||||
},
|
},
|
||||||
"beta": {
|
"beta": {
|
||||||
"message": "БЕТА"
|
"message": "BETA"
|
||||||
},
|
},
|
||||||
"betweenMinAndMax": {
|
"betweenMinAndMax": {
|
||||||
"message": "должно быть больше или равно $1 и меньше или равно $2.",
|
"message": "должно быть больше или равно $1 и меньше или равно $2.",
|
||||||
@ -69,10 +72,10 @@
|
|||||||
"message": "Использовать Blockies Identicon"
|
"message": "Использовать Blockies Identicon"
|
||||||
},
|
},
|
||||||
"borrowDharma": {
|
"borrowDharma": {
|
||||||
"message": "Заимствовать с Dharma (бета)"
|
"message": "Взять в долг на Dharma (Beta)"
|
||||||
},
|
},
|
||||||
"builtInCalifornia": {
|
"builtInCalifornia": {
|
||||||
"message": "MetaMask спроектирован и построен в Калифорнии."
|
"message": "MetaMask спроектирован и разработан в Калифорнии."
|
||||||
},
|
},
|
||||||
"buy": {
|
"buy": {
|
||||||
"message": "Купить"
|
"message": "Купить"
|
||||||
@ -81,7 +84,10 @@
|
|||||||
"message": "Купить на Coinbase"
|
"message": "Купить на Coinbase"
|
||||||
},
|
},
|
||||||
"buyCoinbaseExplainer": {
|
"buyCoinbaseExplainer": {
|
||||||
"message": "Coinbase - самый популярный в мире способ купить и продать биткойн, ethereum и litecoin."
|
"message": "Биржа Coinbase – это наиболее популярный способ купить или продать bitcoin, ethereum и litecoin."
|
||||||
|
},
|
||||||
|
"ok": {
|
||||||
|
"message": "ОК"
|
||||||
},
|
},
|
||||||
"cancel": {
|
"cancel": {
|
||||||
"message": "Отмена"
|
"message": "Отмена"
|
||||||
@ -95,14 +101,17 @@
|
|||||||
"confirm": {
|
"confirm": {
|
||||||
"message": "Подтвердить"
|
"message": "Подтвердить"
|
||||||
},
|
},
|
||||||
|
"confirmed": {
|
||||||
|
"message": "Подтверждена"
|
||||||
|
},
|
||||||
"confirmContract": {
|
"confirmContract": {
|
||||||
"message": "Подтвердить Контракт"
|
"message": "Подтвердить контракт"
|
||||||
},
|
},
|
||||||
"confirmPassword": {
|
"confirmPassword": {
|
||||||
"message": "Подтвердите Пароль"
|
"message": "Подтвердите пароль"
|
||||||
},
|
},
|
||||||
"confirmTransaction": {
|
"confirmTransaction": {
|
||||||
"message": "Подтвердить Транзакцию"
|
"message": "Подтвердить транзакцию"
|
||||||
},
|
},
|
||||||
"continue": {
|
"continue": {
|
||||||
"message": "Продолжить"
|
"message": "Продолжить"
|
||||||
@ -114,7 +123,7 @@
|
|||||||
"message": "Развертывание контракта"
|
"message": "Развертывание контракта"
|
||||||
},
|
},
|
||||||
"conversionProgress": {
|
"conversionProgress": {
|
||||||
"message": "Выполняется конверсия"
|
"message": "Выполняется конвертация"
|
||||||
},
|
},
|
||||||
"copiedButton": {
|
"copiedButton": {
|
||||||
"message": "Скопировано"
|
"message": "Скопировано"
|
||||||
@ -126,7 +135,7 @@
|
|||||||
"message": "Скопировано!"
|
"message": "Скопировано!"
|
||||||
},
|
},
|
||||||
"copiedSafe": {
|
"copiedSafe": {
|
||||||
"message": "Я скопировал его где-то в безопасности"
|
"message": "Я скопировал это в безопасное место"
|
||||||
},
|
},
|
||||||
"copy": {
|
"copy": {
|
||||||
"message": "Скопировать"
|
"message": "Скопировать"
|
||||||
@ -138,29 +147,32 @@
|
|||||||
"message": " Скопировать "
|
"message": " Скопировать "
|
||||||
},
|
},
|
||||||
"copyPrivateKey": {
|
"copyPrivateKey": {
|
||||||
"message": "Это ваш личный ключ (нажмите, чтобы скопировать)"
|
"message": "Это ваш закрытый ключ (нажмите, чтобы скопировать)"
|
||||||
},
|
},
|
||||||
"create": {
|
"create": {
|
||||||
"message": "Создать"
|
"message": "Создать"
|
||||||
},
|
},
|
||||||
"createAccount": {
|
"createAccount": {
|
||||||
"message": "Регистрация"
|
"message": "Создать счет"
|
||||||
},
|
},
|
||||||
"createDen": {
|
"createDen": {
|
||||||
"message": "Создать"
|
"message": "Создать"
|
||||||
},
|
},
|
||||||
"crypto": {
|
"crypto": {
|
||||||
"message": "Крипто",
|
"message": "Криптовалюта",
|
||||||
"description": "Exchange type (cryptocurrencies)"
|
"description": "Exchange type (cryptocurrencies)"
|
||||||
},
|
},
|
||||||
"currentConversion": {
|
"currentConversion": {
|
||||||
"message": "Текущая конверсия"
|
"message": "Текущая конвертация"
|
||||||
},
|
},
|
||||||
"currentNetwork": {
|
"currentNetwork": {
|
||||||
"message": "Текущая сеть"
|
"message": "Текущая сеть"
|
||||||
},
|
},
|
||||||
"customGas": {
|
"customGas": {
|
||||||
"message": "Настроить Газ"
|
"message": "Настроить газ"
|
||||||
|
},
|
||||||
|
"customToken": {
|
||||||
|
"message": "Пользовательский токен"
|
||||||
},
|
},
|
||||||
"customize": {
|
"customize": {
|
||||||
"message": "Настроить"
|
"message": "Настроить"
|
||||||
@ -169,112 +181,115 @@
|
|||||||
"message": "Пользовательский RPC"
|
"message": "Пользовательский RPC"
|
||||||
},
|
},
|
||||||
"decimalsMustZerotoTen": {
|
"decimalsMustZerotoTen": {
|
||||||
"message": "Десятичные числа должны быть не менее 0, и не более 36."
|
"message": "Количество десятичных разрядов должно быть минимум 0 и максимум 36."
|
||||||
},
|
},
|
||||||
"decimal": {
|
"decimal": {
|
||||||
"message": "Десятичные значения точности"
|
"message": "Количество десятичных разрядов"
|
||||||
},
|
},
|
||||||
"defaultNetwork": {
|
"defaultNetwork": {
|
||||||
"message": "Сеть по умолчанию для транзакций Ether - это Main Net."
|
"message": "Основная сеть Ethereum – это сеть по умолчанию для Ether транзакций."
|
||||||
},
|
},
|
||||||
"denExplainer": {
|
"denExplainer": {
|
||||||
"message": "Ваш DEN - это ваше зашифрованное паролем хранилище в MetaMask."
|
"message": "DEN – это зашифрованное паролем хранилище внутри MetaMask."
|
||||||
},
|
},
|
||||||
"deposit": {
|
"deposit": {
|
||||||
"message": "Депозит"
|
"message": "Пополнить"
|
||||||
},
|
},
|
||||||
"depositBTC": {
|
"depositBTC": {
|
||||||
"message": "Депозит BTC по адресу:"
|
"message": "Отправьте ваш BTC на адрес ниже:"
|
||||||
},
|
},
|
||||||
"depositCoin": {
|
"depositCoin": {
|
||||||
"message": "Депозит $1 по указанному ниже адресу",
|
"message": "Отправьте ваш $1 на адрес ниже",
|
||||||
"description": "Tells the user what coin they have selected to deposit with shapeshift"
|
"description": "Tells the user what coin they have selected to deposit with shapeshift"
|
||||||
},
|
},
|
||||||
"depositEth": {
|
"depositEth": {
|
||||||
"message": "Депозит Eth"
|
"message": "Пополнить Eth"
|
||||||
},
|
},
|
||||||
"depositEther": {
|
"depositEther": {
|
||||||
"message": "Депозит Эфир"
|
"message": "Пополнить Ether"
|
||||||
},
|
},
|
||||||
"depositFiat": {
|
"depositFiat": {
|
||||||
"message": "Депозит с деньгами"
|
"message": "Пополнить деньгами"
|
||||||
},
|
},
|
||||||
"depositFromAccount": {
|
"depositFromAccount": {
|
||||||
"message": "Депозит с другого счета"
|
"message": "Пополнить с другого счета"
|
||||||
},
|
},
|
||||||
"depositShapeShift": {
|
"depositShapeShift": {
|
||||||
"message": "Депозит с ShapeShift"
|
"message": "Пополнить через ShapeShift"
|
||||||
},
|
},
|
||||||
"depositShapeShiftExplainer": {
|
"depositShapeShiftExplainer": {
|
||||||
"message": "Если у вас есть другие крипторесурсы, вы можете торговать и вносить Эфир непосредственно в кошелек MetaMask. Нет необходимости в аккаунте."
|
"message": "Если у вас есть другие криптовалюты, вы можете торговать и пополнять Ether напрямую в ваш MetaMask кошелек. Нет необходимости в счете."
|
||||||
},
|
},
|
||||||
"details": {
|
"details": {
|
||||||
"message": "Детали"
|
"message": "Детали"
|
||||||
},
|
},
|
||||||
"directDeposit": {
|
"directDeposit": {
|
||||||
"message": "Прямой Депозит"
|
"message": "Прямое пополнение"
|
||||||
},
|
},
|
||||||
"directDepositEther": {
|
"directDepositEther": {
|
||||||
"message": "Прямой Депозит Эфира"
|
"message": "Прямое пополнение Ether"
|
||||||
},
|
},
|
||||||
"directDepositEtherExplainer": {
|
"directDepositEtherExplainer": {
|
||||||
"message": "Если у вас уже есть Эфир, самый быстрый способ получить Эфир в вашем новом кошельке это прямым депозитом."
|
"message": "Если у вас уже есть Ether, то самый быстрый способ получить Ether в ваш новый кошелек – это прямое пополнение."
|
||||||
},
|
},
|
||||||
"done": {
|
"done": {
|
||||||
"message": "Готово"
|
"message": "Готово"
|
||||||
},
|
},
|
||||||
"downloadStatelogs": {
|
"downloadStateLogs": {
|
||||||
"message": "Загрузить логи статус"
|
"message": "Скачать журнал состояния"
|
||||||
|
},
|
||||||
|
"dropped": {
|
||||||
|
"message": "Отброшена"
|
||||||
},
|
},
|
||||||
"edit": {
|
"edit": {
|
||||||
"message": "Редактировать"
|
"message": "Редактировать"
|
||||||
},
|
},
|
||||||
"editAccountName": {
|
"editAccountName": {
|
||||||
"message": "Изменить Имя Аккаунта"
|
"message": "Редактировать название счета"
|
||||||
},
|
},
|
||||||
"emailUs": {
|
"emailUs": {
|
||||||
"message": "Свяжитесь с нами по электронной почте!"
|
"message": "Свяжитесь с нами по электронной почте!"
|
||||||
},
|
},
|
||||||
"encryptNewDen": {
|
"encryptNewDen": {
|
||||||
"message": "Шифруйте новый DEN"
|
"message": "Зашифровать ваш новый DEN"
|
||||||
},
|
},
|
||||||
"enterPassword": {
|
"enterPassword": {
|
||||||
"message": "Введите пароль"
|
"message": "Введите пароль"
|
||||||
},
|
},
|
||||||
"enterPasswordConfirm": {
|
"enterPasswordConfirm": {
|
||||||
"message": "Введите свой пароль для подтверждения"
|
"message": "Введите ваш пароль для подтверждения"
|
||||||
},
|
},
|
||||||
"etherscanView": {
|
"etherscanView": {
|
||||||
"message": "Просмотреть аккаунт на Etherscan"
|
"message": "Просмотреть счет на Etherscan"
|
||||||
},
|
},
|
||||||
"exchangeRate": {
|
"exchangeRate": {
|
||||||
"message": "Обменный Курс"
|
"message": "Обменный курс"
|
||||||
},
|
},
|
||||||
"exportPrivateKey": {
|
"exportPrivateKey": {
|
||||||
"message": "Экспорт закрытого ключа"
|
"message": "Экспортировать закрытый ключ"
|
||||||
},
|
},
|
||||||
"exportPrivateKeyWarning": {
|
"exportPrivateKeyWarning": {
|
||||||
"message": "Экспорт секретных ключей на свой страх и риск."
|
"message": "Вы экспортируете закрытые ключи на свой страх и риск."
|
||||||
},
|
},
|
||||||
"failed": {
|
"failed": {
|
||||||
"message": "Не смогли"
|
"message": "Неудачна"
|
||||||
},
|
},
|
||||||
"fiat": {
|
"fiat": {
|
||||||
"message": "Бумажные деньги",
|
"message": "Валюта",
|
||||||
"description": "Exchange type"
|
"description": "Exchange type"
|
||||||
},
|
},
|
||||||
"fileImportFail": {
|
"fileImportFail": {
|
||||||
"message": "Ошибка импорта файлов? Кликните сюда!",
|
"message": "Не работает импорт файла? Нажмите тут!",
|
||||||
"description": "Helps user import their account from a JSON file"
|
"description": "Helps user import their account from a JSON file"
|
||||||
},
|
},
|
||||||
"followTwitter": {
|
"followTwitter": {
|
||||||
"message": "Следуйте за нами на Twitter"
|
"message": "Читайте нас в Twitter"
|
||||||
},
|
},
|
||||||
"from": {
|
"from": {
|
||||||
"message": "Из"
|
"message": "Отправитель"
|
||||||
},
|
},
|
||||||
"fromToSame": {
|
"fromToSame": {
|
||||||
"message": "От и до адреса не могут быть одинаковым"
|
"message": "Адрес отправителя и получателя не могут быть одинаковыми"
|
||||||
},
|
},
|
||||||
"fromShapeShift": {
|
"fromShapeShift": {
|
||||||
"message": "Из ShapeShift"
|
"message": "Из ShapeShift"
|
||||||
@ -284,37 +299,37 @@
|
|||||||
"description": "Short indication of gas cost"
|
"description": "Short indication of gas cost"
|
||||||
},
|
},
|
||||||
"gasFee": {
|
"gasFee": {
|
||||||
"message": "Плата за Газ"
|
"message": "Комиссия за газ"
|
||||||
},
|
},
|
||||||
"gasLimit": {
|
"gasLimit": {
|
||||||
"message": "Газовый Предел"
|
"message": "Лимит газа"
|
||||||
},
|
},
|
||||||
"gasLimitCalculation": {
|
"gasLimitCalculation": {
|
||||||
"message": "Мы рассчитываем предполагаемый предел газа на основе коэффициентов успешности сети."
|
"message": "Мы расчитываем предлагаемый лимит газа на основании успешных ставок в сети."
|
||||||
},
|
},
|
||||||
"gasLimitRequired": {
|
"gasLimitRequired": {
|
||||||
"message": "Требуется ограничение на Газ"
|
"message": "Установите лимит газа"
|
||||||
},
|
},
|
||||||
"gasLimitTooLow": {
|
"gasLimitTooLow": {
|
||||||
"message": "Предел газа должен быть не менее 21000"
|
"message": "Лимит газа должен быть как минимум 21000"
|
||||||
},
|
},
|
||||||
"generatingSeed": {
|
"generatingSeed": {
|
||||||
"message": "Создание Семян ..."
|
"message": "Генерируем фразу..."
|
||||||
},
|
},
|
||||||
"gasPrice": {
|
"gasPrice": {
|
||||||
"message": "Цена на Газ (GWEI)"
|
"message": "Цена за газ (GWEI)"
|
||||||
},
|
},
|
||||||
"gasPriceCalculation": {
|
"gasPriceCalculation": {
|
||||||
"message": "Мы вычисляем предлагаемые цены на газ на основе коэффициентов успеха сети."
|
"message": "Мы расчитываем предлагаемые цены за газ на основании успешных ставок в сети."
|
||||||
},
|
},
|
||||||
"gasPriceRequired": {
|
"gasPriceRequired": {
|
||||||
"message": "Требуется цена на Газ"
|
"message": "Установите стоимость газа"
|
||||||
},
|
},
|
||||||
"getEther": {
|
"getEther": {
|
||||||
"message": "Получить Эфир"
|
"message": "Получить Ether"
|
||||||
},
|
},
|
||||||
"getEtherFromFaucet": {
|
"getEtherFromFaucet": {
|
||||||
"message": "Получите Эфир из крана $1",
|
"message": "Получить Ether из крана для $1",
|
||||||
"description": "Displays network name for Ether faucet"
|
"description": "Displays network name for Ether faucet"
|
||||||
},
|
},
|
||||||
"greaterThanMin": {
|
"greaterThanMin": {
|
||||||
@ -322,14 +337,14 @@
|
|||||||
"description": "helper for inputting hex as decimal input"
|
"description": "helper for inputting hex as decimal input"
|
||||||
},
|
},
|
||||||
"here": {
|
"here": {
|
||||||
"message": "здесь",
|
"message": "тут",
|
||||||
"description": "as in -click here- for more information (goes with troubleTokenBalances)"
|
"description": "as in -click here- for more information (goes with troubleTokenBalances)"
|
||||||
},
|
},
|
||||||
"hereList": {
|
"hereList": {
|
||||||
"message": "Вот список !!!!"
|
"message": "Вот список!!!!"
|
||||||
},
|
},
|
||||||
"hide": {
|
"hide": {
|
||||||
"message": "Спрятать"
|
"message": "Скрыть"
|
||||||
},
|
},
|
||||||
"hideToken": {
|
"hideToken": {
|
||||||
"message": "Скрыть токен"
|
"message": "Скрыть токен"
|
||||||
@ -338,33 +353,33 @@
|
|||||||
"message": "Скрыть токен?"
|
"message": "Скрыть токен?"
|
||||||
},
|
},
|
||||||
"howToDeposit": {
|
"howToDeposit": {
|
||||||
"message": "Как бы вы хотели поместить Эфир?"
|
"message": "Как бы вы хотели пополнить Ether?"
|
||||||
},
|
},
|
||||||
"holdEther": {
|
"holdEther": {
|
||||||
"message": "Это позволяет вам использовать эфир и токены и служит мостом для децентрализованных приложений."
|
"message": "Позволяет вам хранить ether и токены и служит в качестве моста в децентрализированные приложения."
|
||||||
},
|
},
|
||||||
"import": {
|
"import": {
|
||||||
"message": "Импортировать",
|
"message": "Импортировать",
|
||||||
"description": "Button to import an account from a selected file"
|
"description": "Button to import an account from a selected file"
|
||||||
},
|
},
|
||||||
"importAccount": {
|
"importAccount": {
|
||||||
"message": "Импорт Аккаунта"
|
"message": "Импортировать счет"
|
||||||
},
|
},
|
||||||
"importAccountMsg": {
|
"importAccountMsg": {
|
||||||
"message": " Импортированные аккаунты не будут связаны с вашей первоначально созданным аккаунтом MetaMask. Подробнее о импортированных аккаунтах "
|
"message":" Импортированные счета не будут ассоциированы с вашей ключевой фразой, созданной MetaMask. Узнать больше про импорт счетов "
|
||||||
},
|
},
|
||||||
"importAnAccount": {
|
"importAnAccount": {
|
||||||
"message": "Импортировать аккаунт"
|
"message": "Импортировать аккаунт"
|
||||||
},
|
},
|
||||||
"importDen": {
|
"importDen": {
|
||||||
"message": "Импорт существующих DEN"
|
"message": "Импортировать существующий DEN"
|
||||||
},
|
},
|
||||||
"imported": {
|
"imported": {
|
||||||
"message": "Импортирован",
|
"message": "Импортирован",
|
||||||
"description": "status showing that an account has been fully loaded into the keyring"
|
"description": "status showing that an account has been fully loaded into the keyring"
|
||||||
},
|
},
|
||||||
"infoHelp": {
|
"infoHelp": {
|
||||||
"message": "Информация и Помощь"
|
"message": "Информация и помощь"
|
||||||
},
|
},
|
||||||
"insufficientFunds": {
|
"insufficientFunds": {
|
||||||
"message": "Недостаточно средств."
|
"message": "Недостаточно средств."
|
||||||
@ -373,35 +388,44 @@
|
|||||||
"message": "Недостаточно токенов."
|
"message": "Недостаточно токенов."
|
||||||
},
|
},
|
||||||
"invalidAddress": {
|
"invalidAddress": {
|
||||||
"message": "Недействительный адрес"
|
"message": "Неверный адрес"
|
||||||
},
|
},
|
||||||
"invalidAddressRecipient": {
|
"invalidAddressRecipient": {
|
||||||
"message": "Недопустимый адрес получателя."
|
"message": "Неверный адрес получателя"
|
||||||
},
|
},
|
||||||
"invalidGasParams": {
|
"invalidGasParams": {
|
||||||
"message": "Недопустимые параметры Газа"
|
"message": "Неверные параметры газа"
|
||||||
},
|
},
|
||||||
"invalidInput": {
|
"invalidInput": {
|
||||||
"message": "Неправильный ввод."
|
"message": "Неверный ввод."
|
||||||
},
|
},
|
||||||
"invalidRequest": {
|
"invalidRequest": {
|
||||||
"message": "Неверный Запрос"
|
"message": "Неверный запрос"
|
||||||
},
|
},
|
||||||
"invalidRPC": {
|
"invalidRPC": {
|
||||||
"message": "Недопустимый URI RPC"
|
"message": "Неверный RPC URI"
|
||||||
},
|
},
|
||||||
"jsonFail": {
|
"jsonFail": {
|
||||||
"message": "Что-то пошло не так. Убедитесь, что ваш файл JSON правильно отформатирован."
|
"message": "Что-то пошло не так. Убедитесь, что ваш JSON файл правильно отформатирован."
|
||||||
},
|
},
|
||||||
"jsonFile": {
|
"jsonFile": {
|
||||||
"message": "Файл JSON",
|
"message": "JSON файл",
|
||||||
"description": "format for importing an account"
|
"description": "format for importing an account"
|
||||||
},
|
},
|
||||||
|
"keepTrackTokens": {
|
||||||
|
"message": "Следите за купленными вами токенами с помощью аккаунта MetaMask."
|
||||||
|
},
|
||||||
"kovan": {
|
"kovan": {
|
||||||
"message": "Kovan тестовая сеть"
|
"message": "Тестовая сеть Kovan"
|
||||||
},
|
},
|
||||||
"knowledgeDataBase": {
|
"knowledgeDataBase": {
|
||||||
"message": "Посетите нашу базу знаний"
|
"message": "Посмотрите нашу Базу Знаний"
|
||||||
|
},
|
||||||
|
"max": {
|
||||||
|
"message": "Максимум"
|
||||||
|
},
|
||||||
|
"learnMore": {
|
||||||
|
"message": "Узнать больше."
|
||||||
},
|
},
|
||||||
"lessThanMax": {
|
"lessThanMax": {
|
||||||
"message": "должно быть меньше или равно $1.",
|
"message": "должно быть меньше или равно $1.",
|
||||||
@ -410,29 +434,32 @@
|
|||||||
"likeToAddTokens": {
|
"likeToAddTokens": {
|
||||||
"message": "Вы хотите добавить эти токены?"
|
"message": "Вы хотите добавить эти токены?"
|
||||||
},
|
},
|
||||||
|
"links": {
|
||||||
|
"message": "Ссылки"
|
||||||
|
},
|
||||||
"limit": {
|
"limit": {
|
||||||
"message": "Предел"
|
"message": "Лимит"
|
||||||
},
|
},
|
||||||
"loading": {
|
"loading": {
|
||||||
"message": "Загрузка..."
|
"message": "Загрузка..."
|
||||||
},
|
},
|
||||||
"loadingTokens": {
|
"loadingTokens": {
|
||||||
"message": "Загрузка токенов ..."
|
"message": "Загрузка токенов..."
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"message": "Локальный адрес 8545"
|
"message": "Localhost 8545"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"message": "Авторизоваться"
|
"message": "Вход"
|
||||||
},
|
},
|
||||||
"logout": {
|
"logout": {
|
||||||
"message": "Выйти"
|
"message": "Выход"
|
||||||
},
|
},
|
||||||
"loose": {
|
"loose": {
|
||||||
"message": "Рыхлый"
|
"message": "Несвязанный"
|
||||||
},
|
},
|
||||||
"loweCaseWords": {
|
"loweCaseWords": {
|
||||||
"message": "семенные слова имеют только символы нижнего регистра"
|
"message": "ключевая фраза может содержать только символы нижнего регистра"
|
||||||
},
|
},
|
||||||
"mainnet": {
|
"mainnet": {
|
||||||
"message": "Основная сеть Ethereum"
|
"message": "Основная сеть Ethereum"
|
||||||
@ -441,19 +468,19 @@
|
|||||||
"message": "Сообщение"
|
"message": "Сообщение"
|
||||||
},
|
},
|
||||||
"metamaskDescription": {
|
"metamaskDescription": {
|
||||||
"message": "MetaMask - это безопасное хранилище для Ethereum."
|
"message": "MetaMask – безопасный кошелек для Ethereum."
|
||||||
},
|
},
|
||||||
"min": {
|
"min": {
|
||||||
"message": "Минимум"
|
"message": "Минимум"
|
||||||
},
|
},
|
||||||
"myAccounts": {
|
"myAccounts": {
|
||||||
"message": "Мои Аккаунты"
|
"message": "Мои счета"
|
||||||
},
|
},
|
||||||
"mustSelectOne": {
|
"mustSelectOne": {
|
||||||
"message": "Необходимо выбрать не менее 1 токена."
|
"message": "Необходимо выбрать как минимум 1 токен."
|
||||||
},
|
},
|
||||||
"needEtherInWallet": {
|
"needEtherInWallet": {
|
||||||
"message": "Чтобы взаимодействовать с децентрализованными приложениями с помощью MetaMask, вам понадобится Эфир в вашем кошельке."
|
"message": "Для взаимодействия с децентрализованными приложениями с помощью MetaMask нужен Ether в вашем кошельке."
|
||||||
},
|
},
|
||||||
"needImportFile": {
|
"needImportFile": {
|
||||||
"message": "Вы должны выбрать файл для импорта.",
|
"message": "Вы должны выбрать файл для импорта.",
|
||||||
@ -464,60 +491,60 @@
|
|||||||
"description": "Password and file needed to import an account"
|
"description": "Password and file needed to import an account"
|
||||||
},
|
},
|
||||||
"negativeETH": {
|
"negativeETH": {
|
||||||
"message": "Невозможно отправить отрицательные количества ETH."
|
"message": "Невозможно отправить отрицательную сумму ETH."
|
||||||
},
|
},
|
||||||
"networks": {
|
"networks": {
|
||||||
"message": "Сети"
|
"message": "Сети"
|
||||||
},
|
},
|
||||||
"newAccount": {
|
"newAccount": {
|
||||||
"message": "Новый Аккаунт"
|
"message": "Новый счет"
|
||||||
},
|
},
|
||||||
"newAccountNumberName": {
|
"newAccountNumberName": {
|
||||||
"message": "Аккаунт $1",
|
"message": "Счет $1",
|
||||||
"description": "Default name of next account to be created on create account screen"
|
"description": "Default name of next account to be created on create account screen"
|
||||||
},
|
},
|
||||||
"newContract": {
|
"newContract": {
|
||||||
"message": "Новый Контракт"
|
"message": "Новый контракт"
|
||||||
},
|
},
|
||||||
"newPassword": {
|
"newPassword": {
|
||||||
"message": "Новый пароль (мин. 8 символов)"
|
"message": "Новый пароль (мин. 8 символов)"
|
||||||
},
|
},
|
||||||
"newRecipient": {
|
"newRecipient": {
|
||||||
"message": "Новый Получатель"
|
"message": "Новый получатель"
|
||||||
},
|
},
|
||||||
"newRPC": {
|
"newRPC": {
|
||||||
"message": "Новый URL-адрес RPC"
|
"message": "Новый RPC URL"
|
||||||
},
|
},
|
||||||
"next": {
|
"next": {
|
||||||
"message": "Далее"
|
"message": "Далее"
|
||||||
},
|
},
|
||||||
"noAddressForName": {
|
"noAddressForName": {
|
||||||
"message": "Для этого имени не задан адрес."
|
"message": "Дла этого названия не установлен адрес."
|
||||||
},
|
},
|
||||||
"noDeposits": {
|
"noDeposits": {
|
||||||
"message": "Не было получено никаких депозитов"
|
"message": "Пополнения не получены"
|
||||||
},
|
},
|
||||||
"noTransactionHistory": {
|
"noTransactionHistory": {
|
||||||
"message": "Нет истории транзакций."
|
"message": "Нет истории транзакций."
|
||||||
},
|
},
|
||||||
"noTransactions": {
|
"noTransactions": {
|
||||||
"message": "Нет Транзакций"
|
"message": "Нет транзакций"
|
||||||
},
|
},
|
||||||
"notStarted": {
|
"notStarted": {
|
||||||
"message": "Не Начался"
|
"message": "Не запущен"
|
||||||
},
|
},
|
||||||
"oldUI": {
|
"oldUI": {
|
||||||
"message": "Старый Интерфейс"
|
"message": "Старая версия интерфейса"
|
||||||
},
|
},
|
||||||
"oldUIMessage": {
|
"oldUIMessage": {
|
||||||
"message": "Вы вернулись к старому интерфейсу. Вы можете вернуться к новому с помощью опции в раскрывающемся меню в правом верхнем углу."
|
"message": "Вы вернулись к старой версии интерфейса пользователя. Вы можете переключиться на новую с помощью опции выпадающего меню в правом верхнем углу."
|
||||||
},
|
},
|
||||||
"or": {
|
"or": {
|
||||||
"message": "или",
|
"message": "или",
|
||||||
"description": "choice between creating or importing a new account"
|
"description": "choice between creating or importing a new account"
|
||||||
},
|
},
|
||||||
"passwordCorrect": {
|
"passwordCorrect": {
|
||||||
"message": "Убедитесь, что ваш пароль правильный."
|
"message": "Убедитесь, что ваш пароль верный."
|
||||||
},
|
},
|
||||||
"passwordMismatch": {
|
"passwordMismatch": {
|
||||||
"message": "пароли не совпадают",
|
"message": "пароли не совпадают",
|
||||||
@ -528,27 +555,30 @@
|
|||||||
"description": "in password creation process, the password is not long enough to be secure"
|
"description": "in password creation process, the password is not long enough to be secure"
|
||||||
},
|
},
|
||||||
"pastePrivateKey": {
|
"pastePrivateKey": {
|
||||||
"message": "Вставьте свою личную строку:",
|
"message": "Вставьте ваш закрытый ключ тут:",
|
||||||
"description": "For importing an account from a private key"
|
"description": "For importing an account from a private key"
|
||||||
},
|
},
|
||||||
"pasteSeed": {
|
"pasteSeed": {
|
||||||
"message": "Вставьте здесь свою семенную фразу!"
|
"message": "Вставьте вашу ключевую фразу!"
|
||||||
},
|
},
|
||||||
"personalAddressDetected": {
|
"personalAddressDetected": {
|
||||||
"message": "Персональный адрес обнаружен. Введите адрес контракта токена."
|
"message": "Обнаружен персональный адрес. Введите адрес контракта токена."
|
||||||
},
|
},
|
||||||
"pleaseReviewTransaction": {
|
"pleaseReviewTransaction": {
|
||||||
"message": "Проверьте транзакцию."
|
"message": "Проверьте транзакцию."
|
||||||
},
|
},
|
||||||
|
"popularTokens": {
|
||||||
|
"message": "Популярные токены"
|
||||||
|
},
|
||||||
"privacyMsg": {
|
"privacyMsg": {
|
||||||
"message": "Политика Конфиденциальности"
|
"message": "Политика конфиденциальности"
|
||||||
},
|
},
|
||||||
"privateKey": {
|
"privateKey": {
|
||||||
"message": "Закрытый ключ",
|
"message": "Закрытый ключ",
|
||||||
"description": "select this type of file to use to import an account"
|
"description": "select this type of file to use to import an account"
|
||||||
},
|
},
|
||||||
"privateKeyWarning": {
|
"privateKeyWarning": {
|
||||||
"message": "Предупреждение: никогда не раскрывайте этот ключ. Любой, у кого есть ваши личные ключи, может украсть любые активы, хранящиеся в вашем аккаунте."
|
"message": "Предупреждение: Никогда не раскрывайте этот ключ. Любой, у кого есть ваши закрытые ключи, может украсть любые активы, хранящиеся на счету."
|
||||||
},
|
},
|
||||||
"privateNetwork": {
|
"privateNetwork": {
|
||||||
"message": "Частная сеть"
|
"message": "Частная сеть"
|
||||||
@ -557,126 +587,165 @@
|
|||||||
"message": "Показать QR-код"
|
"message": "Показать QR-код"
|
||||||
},
|
},
|
||||||
"readdToken": {
|
"readdToken": {
|
||||||
"message": "Вы можете добавить этот токен в будущем, перейдя в “Добавить токен” в меню параметров вашего аккаунта."
|
"message": "Вы можете в будущем добавить обратно этот токен, выбрав пункт меню “Добавить токен”."
|
||||||
},
|
},
|
||||||
"readMore": {
|
"readMore": {
|
||||||
"message": "Подробнее читайте здесь."
|
"message": "Узнать больше тут."
|
||||||
},
|
},
|
||||||
"readMore2": {
|
"readMore2": {
|
||||||
"message": "Прочитайте больше."
|
"message": "Узнать больше."
|
||||||
},
|
},
|
||||||
"receive": {
|
"receive": {
|
||||||
"message": "Получить"
|
"message": "Получить"
|
||||||
},
|
},
|
||||||
"recipientAddress": {
|
"recipientAddress": {
|
||||||
"message": "Адрес Получателя"
|
"message": "Адрес получателя"
|
||||||
},
|
},
|
||||||
"refundAddress": {
|
"refundAddress": {
|
||||||
"message": "Ваш Адрес Возврата"
|
"message": "Ваш адрес для возврата средств"
|
||||||
},
|
},
|
||||||
"rejected": {
|
"rejected": {
|
||||||
"message": "Отклонено"
|
"message": "Отклонена"
|
||||||
},
|
},
|
||||||
"resetAccount": {
|
"resetAccount": {
|
||||||
"message": "Сбросить аккаунт"
|
"message": "Сбросить аккаунт"
|
||||||
},
|
},
|
||||||
"restoreFromSeed": {
|
"restoreFromSeed": {
|
||||||
"message": "Восстановить от семенной фразы"
|
"message": "Восстановить из ключевой фразы"
|
||||||
|
},
|
||||||
|
"restoreVault": {
|
||||||
|
"message": "Восстановить кошелек"
|
||||||
},
|
},
|
||||||
"required": {
|
"required": {
|
||||||
"message": "Необходимо"
|
"message": "Обязательное поле"
|
||||||
},
|
},
|
||||||
"retryWithMoreGas": {
|
"retryWithMoreGas": {
|
||||||
"message": "Повторите попытку с более высокой ценой на газ здесь"
|
"message": "Повторите попытку с большей ценой за газRetry with a higher gas price here"
|
||||||
|
},
|
||||||
|
"walletSeed": {
|
||||||
|
"message": "Ключевая фраза кошелька"
|
||||||
},
|
},
|
||||||
"revealSeedWords": {
|
"revealSeedWords": {
|
||||||
"message": "Раскрыть семенные слова"
|
"message": "Показать ключевую фразу"
|
||||||
},
|
},
|
||||||
"revealSeedWordsWarning": {
|
"revealSeedWordsWarning": {
|
||||||
"message": "Не восстанавливайте семенные слова в общественном месте! Эти слова могут использоваться для кражи всех ваших аккаунтах."
|
"message": "Не восстанавливайте ключевую фразу в общественном месте! Она может быть использована для кражи всех ваших счетов."
|
||||||
},
|
},
|
||||||
"revert": {
|
"revert": {
|
||||||
"message": "Откат"
|
"message": "Восстановить"
|
||||||
},
|
},
|
||||||
"rinkeby": {
|
"rinkeby": {
|
||||||
"message": "Rinkeby тестовая сеть"
|
"message": "Тестовая сеть Rinkeby"
|
||||||
},
|
},
|
||||||
"ropsten": {
|
"ropsten": {
|
||||||
"message": "Ropsten тестовая сеть"
|
"message": "Тестовая сеть Ropsten"
|
||||||
|
},
|
||||||
|
"currentRpc": {
|
||||||
|
"message": "Current RPC"
|
||||||
|
},
|
||||||
|
"connectingToMainnet": {
|
||||||
|
"message": "Соединение с основной сетью Ethereum"
|
||||||
|
},
|
||||||
|
"connectingToRopsten": {
|
||||||
|
"message": "Соединение с тестовой сетью Ropsten"
|
||||||
|
},
|
||||||
|
"connectingToKovan": {
|
||||||
|
"message": "Соединение с тестовой сетью Kovan"
|
||||||
|
},
|
||||||
|
"connectingToRinkeby": {
|
||||||
|
"message": "Соединение с тестовой сетью Rinkeby"
|
||||||
|
},
|
||||||
|
"connectingToUnknown": {
|
||||||
|
"message": "Соединение с неизвестной сетью"
|
||||||
},
|
},
|
||||||
"sampleAccountName": {
|
"sampleAccountName": {
|
||||||
"message": "Например, Мой новый аккаунт",
|
"message": "Например, Мой новый счет",
|
||||||
"description": "Help user understand concept of adding a human-readable name to their account"
|
"description": "Help user understand concept of adding a human-readable name to their account"
|
||||||
},
|
},
|
||||||
"save": {
|
"save": {
|
||||||
"message": "Сохранить"
|
"message": "Сохранить"
|
||||||
},
|
},
|
||||||
"saveAsFile": {
|
"saveAsFile": {
|
||||||
"message": "Сохранить как Файл",
|
"message": "Сохранить в виде файла",
|
||||||
"description": "Account export process"
|
"description": "Account export process"
|
||||||
},
|
},
|
||||||
"saveSeedAsFile": {
|
"saveSeedAsFile": {
|
||||||
"message": "Сохранить Семенные Слова Как Файл"
|
"message": "Сохранить ключевую фразу в виде файла"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"message": "Поиск"
|
"message": "Поиск"
|
||||||
},
|
},
|
||||||
"secretPhrase": {
|
"secretPhrase": {
|
||||||
"message": "Введите свою секретную двенадцатисловную фразу здесь, чтобы восстановить хранилище."
|
"message": "Введите вашу ключевую фразу из 12 слов, чтобы восстановить кошелек."
|
||||||
|
},
|
||||||
|
"newPassword8Chars": {
|
||||||
|
"message": "Новый пароль (мин. 8 символов)"
|
||||||
},
|
},
|
||||||
"seedPhraseReq": {
|
"seedPhraseReq": {
|
||||||
"message": "семенные фразы длиной 12 слов"
|
"message": "ключевые фразы имеют длину 12 слов"
|
||||||
},
|
},
|
||||||
"select": {
|
"select": {
|
||||||
"message": "Выбрать"
|
"message": "Выбрать"
|
||||||
},
|
},
|
||||||
"selectCurrency": {
|
"selectCurrency": {
|
||||||
"message": "Выберите Валюту"
|
"message": "Выберите валюту"
|
||||||
},
|
},
|
||||||
"selectService": {
|
"selectService": {
|
||||||
"message": "Выберите Сервис"
|
"message": "Выберите сервис"
|
||||||
},
|
},
|
||||||
"selectType": {
|
"selectType": {
|
||||||
"message": "Выберите Тип"
|
"message": "Выберите тип"
|
||||||
},
|
},
|
||||||
"send": {
|
"send": {
|
||||||
"message": "Послать"
|
"message": "Отправить"
|
||||||
},
|
},
|
||||||
"sendETH": {
|
"sendETH": {
|
||||||
"message": "Отправить ETH"
|
"message": "Отправить ETH"
|
||||||
},
|
},
|
||||||
"sendTokens": {
|
"sendTokens": {
|
||||||
"message": "Отправить Токены"
|
"message": "Отправить токены"
|
||||||
|
},
|
||||||
|
"onlySendToEtherAddress": {
|
||||||
|
"message": "Отправляйте ETH только на Ethereum адреса."
|
||||||
|
},
|
||||||
|
"searchTokens": {
|
||||||
|
"message": "Поиск токенов"
|
||||||
},
|
},
|
||||||
"sendTokensAnywhere": {
|
"sendTokensAnywhere": {
|
||||||
"message": "Отправить Токены кому-либо с аккаунтом Ethereum"
|
"message": "Отправить токены любому, у кого есть счет Ethereum"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"message": "Настройки"
|
"message": "Настройки"
|
||||||
},
|
},
|
||||||
|
"info": {
|
||||||
|
"message": "Информация"
|
||||||
|
},
|
||||||
"shapeshiftBuy": {
|
"shapeshiftBuy": {
|
||||||
"message": "Купить с помощью Shapeshift"
|
"message": "Купить через Shapeshift"
|
||||||
},
|
},
|
||||||
"showPrivateKeys": {
|
"showPrivateKeys": {
|
||||||
"message": "Показать приватные ключи"
|
"message": "Показать закрытые ключи"
|
||||||
},
|
},
|
||||||
"showQRCode": {
|
"showQRCode": {
|
||||||
"message": "Показать QR-код"
|
"message": "Показать QR-код"
|
||||||
},
|
},
|
||||||
"sign": {
|
"sign": {
|
||||||
"message": "Знак"
|
"message": "Подпись"
|
||||||
|
},
|
||||||
|
"signed": {
|
||||||
|
"message": "Подписана"
|
||||||
},
|
},
|
||||||
"signMessage": {
|
"signMessage": {
|
||||||
"message": "Нодписать сообщение"
|
"message": "Подписать сообщение"
|
||||||
},
|
},
|
||||||
"signNotice": {
|
"signNotice": {
|
||||||
"message": "Подписание этого сообщения может иметь \nопасные побочные эффекты. Только подписывайте сообщения \nс сайтов, которым вы полностью доверяете своим аккаунтом. Этот опасный метод будет удален в будущей версии."
|
"message": "Подпись этого сообщения может иметь \nопасные побочные эффекты. Подписывайте только сообщения \nс сайтов, которым вы полностью доверяете свой аккаунт. Этот опасный метод будет удален в будущей версии."
|
||||||
},
|
},
|
||||||
"sigRequest": {
|
"sigRequest": {
|
||||||
"message": "Запрос на подпись"
|
"message": "Запрос подписи"
|
||||||
},
|
},
|
||||||
"sigRequested": {
|
"sigRequested": {
|
||||||
"message": "Подпись Запрошена"
|
"message": "Подпись запрошена"
|
||||||
},
|
},
|
||||||
"spaceBetween": {
|
"spaceBetween": {
|
||||||
"message": "между словами может быть только пробел"
|
"message": "между словами может быть только пробел"
|
||||||
@ -685,53 +754,59 @@
|
|||||||
"message": "Статус"
|
"message": "Статус"
|
||||||
},
|
},
|
||||||
"stateLogs": {
|
"stateLogs": {
|
||||||
"message": "Логи Статуса"
|
"message": "Журнал состояния"
|
||||||
},
|
},
|
||||||
"stateLogsDescription": {
|
"stateLogsDescription": {
|
||||||
"message": "Логи статуса содержат ваши общедоступные адреса и отправленные транзакции."
|
"message": "Журнал состояния содержит ваши публичные адреса счетов и совершенные транзакции."
|
||||||
|
},
|
||||||
|
"stateLogError": {
|
||||||
|
"message": "Ошибка при получении журнала состояния."
|
||||||
},
|
},
|
||||||
"submit": {
|
"submit": {
|
||||||
"message": "Отправить"
|
"message": "Отправить"
|
||||||
},
|
},
|
||||||
|
"submitted": {
|
||||||
|
"message": "Отправлена"
|
||||||
|
},
|
||||||
"supportCenter": {
|
"supportCenter": {
|
||||||
"message": "Посетите наш Центр поддержки"
|
"message": "Перейти в наш Центр поддержки"
|
||||||
},
|
},
|
||||||
"symbolBetweenZeroTen": {
|
"symbolBetweenZeroTen": {
|
||||||
"message": "Символ должен быть от 0 до 10 символов."
|
"message": "Символ должен быть от 0 до 10 символов."
|
||||||
},
|
},
|
||||||
"takesTooLong": {
|
"takesTooLong": {
|
||||||
"message": "Занимает слишком долго?"
|
"message": "Слишком долго?"
|
||||||
},
|
},
|
||||||
"terms": {
|
"terms": {
|
||||||
"message": "Условия Эксплуатации"
|
"message": "Условия пользования"
|
||||||
},
|
},
|
||||||
"testFaucet": {
|
"testFaucet": {
|
||||||
"message": "Тестовый Кран"
|
"message": "Тестовый кран"
|
||||||
},
|
},
|
||||||
"to": {
|
"to": {
|
||||||
"message": "К"
|
"message": "Получатель: "
|
||||||
},
|
},
|
||||||
"toETHviaShapeShift": {
|
"toETHviaShapeShift": {
|
||||||
"message": "$1 в ETH через ShapeShift",
|
"message": "$1 в ETH через ShapeShift",
|
||||||
"description": "system will fill in deposit type in start of message"
|
"description": "system will fill in deposit type in start of message"
|
||||||
},
|
},
|
||||||
"tokenAddress": {
|
"tokenAddress": {
|
||||||
"message": "Адрес Токена"
|
"message": "Адрес токена"
|
||||||
},
|
},
|
||||||
"tokenAlreadyAdded": {
|
"tokenAlreadyAdded": {
|
||||||
"message": "Токен уже добавлен."
|
"message": "Токен уже был добавлен."
|
||||||
},
|
},
|
||||||
"tokenBalance": {
|
"tokenBalance": {
|
||||||
"message": "Баланс Вашых Tокенов:"
|
"message": "Баланс ваших токенов:"
|
||||||
},
|
},
|
||||||
"tokenSelection": {
|
"tokenSelection": {
|
||||||
"message": "Поиск токенов или выбор из нашего списка популярных токенов."
|
"message": "Поищите токен или выберите из нашего списка популярных токенов."
|
||||||
},
|
},
|
||||||
"tokenSymbol": {
|
"tokenSymbol": {
|
||||||
"message": "Символ Токена"
|
"message": "Символ токена"
|
||||||
},
|
},
|
||||||
"tokenWarning1": {
|
"tokenWarning1": {
|
||||||
"message": "Следите за токенами, которые вы купили с помощью аккаунта MetaMask. Если вы купили токены, используя другой аккаунт, эти токены здесь не появятся."
|
"message": "Отслеживаются токены, купленные на счет в MetaMask. Если вы купили токены, используя другой счет, такие токены не будут тут отображены."
|
||||||
},
|
},
|
||||||
"total": {
|
"total": {
|
||||||
"message": "Всего"
|
"message": "Всего"
|
||||||
@ -740,35 +815,38 @@
|
|||||||
"message": "транзакции"
|
"message": "транзакции"
|
||||||
},
|
},
|
||||||
"transactionMemo": {
|
"transactionMemo": {
|
||||||
"message": "Транзакционная записка (необязательно)"
|
"message": "Транзакционные данные (необязательный)"
|
||||||
},
|
},
|
||||||
"transactionNumber": {
|
"transactionNumber": {
|
||||||
"message": "Номер Транзакции"
|
"message": "Номер транзакции"
|
||||||
},
|
},
|
||||||
"transfers": {
|
"transfers": {
|
||||||
"message": "Переводы"
|
"message": "Переводы"
|
||||||
},
|
},
|
||||||
"troubleTokenBalances": {
|
"troubleTokenBalances": {
|
||||||
"message": "У нас были проблемы с загрузкой ваших токенов. Вы можете просмотреть их ",
|
"message": "Возникли проблемы при загрузке балансов токенов. Вы можете посмотреть их ",
|
||||||
"description": "Followed by a link (here) to view token balances"
|
"description": "Followed by a link (here) to view token balances"
|
||||||
},
|
},
|
||||||
"twelveWords": {
|
"twelveWords": {
|
||||||
"message": "Эти 12 слов - единственный способ восстановить ваши учетные записи MetaMask.\nСохраните их где-нибудь в безопасности и в тайне."
|
"message": "Эти 12 слов являются единственной возможностью восстановить ваши счета в MetaMask.\nСохраните из в надежном секретном месте."
|
||||||
},
|
},
|
||||||
"typePassword": {
|
"typePassword": {
|
||||||
"message": "Введите Пароль"
|
"message": "Введите пароль"
|
||||||
},
|
},
|
||||||
"uiWelcome": {
|
"uiWelcome": {
|
||||||
"message": "Добро пожаловать в новый интерфейс (бета-версия)"
|
"message": "Новый интерфейс (Beta)"
|
||||||
},
|
},
|
||||||
"uiWelcomeMessage": {
|
"uiWelcomeMessage": {
|
||||||
"message": "Теперь вы используете новый интерфейс Metamask. Осмотритесь, попробуйте новые функции, такие как отправку токенов, и сообщите нам, есть ли у вас какие-либо проблемы."
|
"message": "Теперь вы используете новый интерфейс пользователя MetaMask. Осмотритесь, попробуйте новые функции, например, отправить токены и, если возникнут проблемы, сообщите нам."
|
||||||
|
},
|
||||||
|
"unapproved": {
|
||||||
|
"message": "Не одобрена"
|
||||||
},
|
},
|
||||||
"unavailable": {
|
"unavailable": {
|
||||||
"message": "Недоступен"
|
"message": "Недоступный"
|
||||||
},
|
},
|
||||||
"unknown": {
|
"unknown": {
|
||||||
"message": "Неизвестный"
|
"message": "Неизвестно"
|
||||||
},
|
},
|
||||||
"unknownNetwork": {
|
"unknownNetwork": {
|
||||||
"message": "Неизвестная частная сеть"
|
"message": "Неизвестная частная сеть"
|
||||||
@ -777,7 +855,7 @@
|
|||||||
"message": "Неизвестный идентификатор сети"
|
"message": "Неизвестный идентификатор сети"
|
||||||
},
|
},
|
||||||
"uriErrorMsg": {
|
"uriErrorMsg": {
|
||||||
"message": "Для URI требуется соответствующий префикс HTTP / HTTPS."
|
"message": "Для URI требуется соответствующий префикс HTTP/HTTPS."
|
||||||
},
|
},
|
||||||
"usaOnly": {
|
"usaOnly": {
|
||||||
"message": "Только США",
|
"message": "Только США",
|
||||||
@ -787,19 +865,19 @@
|
|||||||
"message": "Используется различными клиентами"
|
"message": "Используется различными клиентами"
|
||||||
},
|
},
|
||||||
"useOldUI": {
|
"useOldUI": {
|
||||||
"message": "Использовать старый интерфейс"
|
"message": "Использовать старый интерфейс пользователя"
|
||||||
},
|
},
|
||||||
"validFileImport": {
|
"validFileImport": {
|
||||||
"message": "Вы должны выбрать действительный файл для импорта."
|
"message": "Вам нужно выбрать правильный файл для импорта."
|
||||||
},
|
},
|
||||||
"vaultCreated": {
|
"vaultCreated": {
|
||||||
"message": "Создано хранилище"
|
"message": "Кошелек был создан"
|
||||||
},
|
},
|
||||||
"viewAccount": {
|
"viewAccount": {
|
||||||
"message": "Посмотреть аккаунт"
|
"message": "Посмотреть счет"
|
||||||
},
|
},
|
||||||
"visitWebSite": {
|
"visitWebSite": {
|
||||||
"message": "Посетите наш сайт"
|
"message": "Перейти на наш сайт"
|
||||||
},
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
"message": "Предупреждение"
|
"message": "Предупреждение"
|
||||||
@ -811,7 +889,7 @@
|
|||||||
"message": "Что это?"
|
"message": "Что это?"
|
||||||
},
|
},
|
||||||
"yourSigRequested": {
|
"yourSigRequested": {
|
||||||
"message": "Ваша подпись запрашивается"
|
"message": "Запрашивается ваша подпись"
|
||||||
},
|
},
|
||||||
"youSign": {
|
"youSign": {
|
||||||
"message": "Вы подписываете"
|
"message": "Вы подписываете"
|
||||||
|
@ -223,7 +223,7 @@
|
|||||||
"done": {
|
"done": {
|
||||||
"message": "Končano"
|
"message": "Končano"
|
||||||
},
|
},
|
||||||
"downloadStatelogs": {
|
"downloadStateLogs": {
|
||||||
"message": "Prenesi state dnevnike"
|
"message": "Prenesi state dnevnike"
|
||||||
},
|
},
|
||||||
"edit": {
|
"edit": {
|
||||||
|
@ -223,7 +223,7 @@
|
|||||||
"done": {
|
"done": {
|
||||||
"message": "เสร็จสิ้น"
|
"message": "เสร็จสิ้น"
|
||||||
},
|
},
|
||||||
"downloadStatelogs": {
|
"downloadStateLogs": {
|
||||||
"message": "ดาวน์โหลดล็อกสถานะ"
|
"message": "ดาวน์โหลดล็อกสถานะ"
|
||||||
},
|
},
|
||||||
"edit": {
|
"edit": {
|
||||||
|
@ -235,7 +235,7 @@
|
|||||||
"done": {
|
"done": {
|
||||||
"message": "完成"
|
"message": "完成"
|
||||||
},
|
},
|
||||||
"downloadStatelogs": {
|
"downloadStateLogs": {
|
||||||
"message": "下載狀態紀錄"
|
"message": "下載狀態紀錄"
|
||||||
},
|
},
|
||||||
"dropped": {
|
"dropped": {
|
||||||
|
@ -187,12 +187,12 @@ module.exports = class TransactionController extends EventEmitter {
|
|||||||
// validate
|
// validate
|
||||||
await this.txGasUtil.validateTxParams(txParams)
|
await this.txGasUtil.validateTxParams(txParams)
|
||||||
// construct txMeta
|
// construct txMeta
|
||||||
const txMeta = this.txStateManager.generateTxMeta({txParams})
|
let txMeta = this.txStateManager.generateTxMeta({txParams})
|
||||||
this.addTx(txMeta)
|
this.addTx(txMeta)
|
||||||
this.emit('newUnapprovedTx', txMeta)
|
this.emit('newUnapprovedTx', txMeta)
|
||||||
// add default tx params
|
// add default tx params
|
||||||
try {
|
try {
|
||||||
await this.addTxDefaults(txMeta)
|
txMeta = await this.addTxDefaults(txMeta)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
this.txStateManager.setTxStatusFailed(txMeta.id, error)
|
this.txStateManager.setTxStatusFailed(txMeta.id, error)
|
||||||
@ -215,6 +215,7 @@ module.exports = class TransactionController extends EventEmitter {
|
|||||||
}
|
}
|
||||||
txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16))
|
txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16))
|
||||||
txParams.value = txParams.value || '0x0'
|
txParams.value = txParams.value || '0x0'
|
||||||
|
if (txParams.to === null) delete txParams.to
|
||||||
// set gasLimit
|
// set gasLimit
|
||||||
return await this.txGasUtil.analyzeGasUsage(txMeta)
|
return await this.txGasUtil.analyzeGasUsage(txMeta)
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,9 @@ module.exports = class TxGasUtil {
|
|||||||
// if recipient has no code, gas is 21k max:
|
// if recipient has no code, gas is 21k max:
|
||||||
const recipient = txParams.to
|
const recipient = txParams.to
|
||||||
const hasRecipient = Boolean(recipient)
|
const hasRecipient = Boolean(recipient)
|
||||||
const code = await this.query.getCode(recipient)
|
let code
|
||||||
|
if (recipient) code = await this.query.getCode(recipient)
|
||||||
|
|
||||||
if (hasRecipient && (!code || code === '0x')) {
|
if (hasRecipient && (!code || code === '0x')) {
|
||||||
txParams.gas = SIMPLE_GAS_COST
|
txParams.gas = SIMPLE_GAS_COST
|
||||||
txMeta.simpleSend = true // Prevents buffer addition
|
txMeta.simpleSend = true // Prevents buffer addition
|
||||||
@ -100,6 +102,7 @@ module.exports = class TxGasUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async validateTxParams (txParams) {
|
async validateTxParams (txParams) {
|
||||||
|
this.validateFrom(txParams)
|
||||||
this.validateRecipient(txParams)
|
this.validateRecipient(txParams)
|
||||||
if ('value' in txParams) {
|
if ('value' in txParams) {
|
||||||
const value = txParams.value.toString()
|
const value = txParams.value.toString()
|
||||||
@ -112,6 +115,12 @@ module.exports = class TxGasUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validateFrom (txParams) {
|
||||||
|
if ( !(typeof txParams.from === 'string') ) throw new Error(`Invalid from address ${txParams.from} not a string`)
|
||||||
|
if (!isValidAddress(txParams.from)) throw new Error('Invalid from address')
|
||||||
|
}
|
||||||
|
|
||||||
validateRecipient (txParams) {
|
validateRecipient (txParams) {
|
||||||
if (txParams.to === '0x' || txParams.to === null ) {
|
if (txParams.to === '0x' || txParams.to === null ) {
|
||||||
if (txParams.data) {
|
if (txParams.data) {
|
||||||
@ -124,4 +133,4 @@ module.exports = class TxGasUtil {
|
|||||||
}
|
}
|
||||||
return txParams
|
return txParams
|
||||||
}
|
}
|
||||||
}
|
}
|
52
development/metamaskbot-build-announce.js
Executable file
52
development/metamaskbot-build-announce.js
Executable file
@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
const request = require('request-promise')
|
||||||
|
const { version } = require('../dist/chrome/manifest.json')
|
||||||
|
|
||||||
|
const GITHUB_COMMENT_TOKEN = process.env.GITHUB_COMMENT_TOKEN
|
||||||
|
console.log('GITHUB_COMMENT_TOKEN', GITHUB_COMMENT_TOKEN)
|
||||||
|
const CIRCLE_PULL_REQUEST = process.env.CIRCLE_PULL_REQUEST
|
||||||
|
console.log('CIRCLE_PULL_REQUEST', CIRCLE_PULL_REQUEST)
|
||||||
|
const CIRCLE_SHA1 = process.env.CIRCLE_SHA1
|
||||||
|
console.log('CIRCLE_SHA1', CIRCLE_SHA1)
|
||||||
|
const CIRCLE_BUILD_NUM = process.env.CIRCLE_BUILD_NUM
|
||||||
|
console.log('CIRCLE_BUILD_NUM', CIRCLE_BUILD_NUM)
|
||||||
|
|
||||||
|
const CIRCLE_PR_NUMBER = CIRCLE_PULL_REQUEST.split('/').pop()
|
||||||
|
const SHORT_SHA1 = CIRCLE_SHA1.slice(0,7)
|
||||||
|
const BUILD_LINK_BASE = `https://${CIRCLE_BUILD_NUM}-42009758-gh.circle-artifacts.com/0`
|
||||||
|
|
||||||
|
const MASCARA = `${BUILD_LINK_BASE}/builds/mascara/home.html`
|
||||||
|
const CHROME = `${BUILD_LINK_BASE}/builds/metamask-chrome-${version}.zip`
|
||||||
|
const FIREFOX = `${BUILD_LINK_BASE}/builds/metamask-firefox-${version}.zip`
|
||||||
|
const EDGE = `${BUILD_LINK_BASE}/builds/metamask-edge-${version}.zip`
|
||||||
|
const OPERA = `${BUILD_LINK_BASE}/builds/metamask-opera-${version}.zip`
|
||||||
|
const WALKTHROUGH = `${BUILD_LINK_BASE}/test-artifacts/screens/walkthrough%20%28en%29.gif`
|
||||||
|
|
||||||
|
const commentBody = `
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
Builds ready [${SHORT_SHA1}]:
|
||||||
|
<a href="${MASCARA}">mascara</a>,
|
||||||
|
<a href="${CHROME}">chrome</a>,
|
||||||
|
<a href="${FIREFOX}">firefox</a>,
|
||||||
|
<a href="${EDGE}">edge</a>,
|
||||||
|
<a href="${OPERA}">opera</a>
|
||||||
|
</summary>
|
||||||
|
<image src="${WALKTHROUGH}">
|
||||||
|
</details>
|
||||||
|
`
|
||||||
|
|
||||||
|
const JSON_PAYLOAD = JSON.stringify({ body: commentBody })
|
||||||
|
const POST_COMMENT_URI = `https://api.github.com/repos/metamask/metamask-extension/issues/${CIRCLE_PR_NUMBER}/comments`
|
||||||
|
console.log(`Announcement:\n${commentBody}`)
|
||||||
|
console.log(`Posting to: ${POST_COMMENT_URI}`)
|
||||||
|
|
||||||
|
request({
|
||||||
|
method: 'POST',
|
||||||
|
uri: POST_COMMENT_URI,
|
||||||
|
body: JSON_PAYLOAD,
|
||||||
|
headers: {
|
||||||
|
'User-Agent': 'metamaskbot',
|
||||||
|
'Authorization': `token ${GITHUB_COMMENT_TOKEN}`,
|
||||||
|
},
|
||||||
|
})
|
128
development/states/tx-list-items.js
Normal file
128
development/states/tx-list-items.js
Normal file
File diff suppressed because one or more lines are too long
@ -10,87 +10,88 @@
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
var fs = require('fs')
|
const fs = require('fs')
|
||||||
var path = require('path')
|
const path = require('path')
|
||||||
|
const localeIndex = require('../app/_locales/index.json')
|
||||||
|
|
||||||
console.log('Locale Verification')
|
console.log('Locale Verification')
|
||||||
|
|
||||||
var locale = process.argv[2]
|
const specifiedLocale = process.argv[2]
|
||||||
if (!locale || locale == '') {
|
if (specifiedLocale) {
|
||||||
console.log('Must enter a locale as argument. exitting')
|
console.log(`Verifying selected locale "${specifiedLocale}":\n\n`)
|
||||||
process.exit(1)
|
const locale = localeIndex.find(localeMeta => localeMeta.code === specifiedLocale)
|
||||||
}
|
verifyLocale({ localeMeta })
|
||||||
|
|
||||||
console.log("verifying for locale " + locale)
|
|
||||||
|
|
||||||
localeFilePath = path.join(process.cwd(), 'app', '_locales', locale, 'messages.json')
|
|
||||||
try {
|
|
||||||
localeObj = JSON.parse(fs.readFileSync(localeFilePath, 'utf8'));
|
|
||||||
} catch (e) {
|
|
||||||
if(e.code == 'ENOENT') {
|
|
||||||
console.log('Locale file not found')
|
|
||||||
} else {
|
|
||||||
console.log('Error opening your locale file: ', e)
|
|
||||||
}
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
englishFilePath = path.join(process.cwd(), 'app', '_locales', 'en', 'messages.json')
|
|
||||||
try {
|
|
||||||
englishObj = JSON.parse(fs.readFileSync(englishFilePath, 'utf8'));
|
|
||||||
} catch (e) {
|
|
||||||
if(e.code == 'ENOENT') {
|
|
||||||
console.log("English File not found")
|
|
||||||
} else {
|
|
||||||
console.log("Error opening english locale file: ", e)
|
|
||||||
}
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('\tverifying whether all your locale strings are contained in the english one')
|
|
||||||
|
|
||||||
var counter = 0
|
|
||||||
var foundErrorA = false
|
|
||||||
var notFound = [];
|
|
||||||
Object.keys(localeObj).forEach(function(key){
|
|
||||||
if (!englishObj[key]) {
|
|
||||||
foundErrorA = true
|
|
||||||
notFound.push(key)
|
|
||||||
}
|
|
||||||
counter++
|
|
||||||
})
|
|
||||||
|
|
||||||
if (foundErrorA) {
|
|
||||||
console.log('\nThe following string(s) is(are) not found in the english locale:')
|
|
||||||
notFound.forEach(function(key) {
|
|
||||||
console.log(key)
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
console.log('\tall ' + counter +' strings declared in your locale were found in the english one')
|
console.log('Verifying all locales:\n\n')
|
||||||
}
|
localeIndex.forEach(localeMeta => {
|
||||||
|
verifyLocale({ localeMeta })
|
||||||
console.log('\n\tverifying whether your locale contains all english strings')
|
console.log('\n')
|
||||||
|
|
||||||
var counter = 0
|
|
||||||
var foundErrorB = false
|
|
||||||
var notFound = [];
|
|
||||||
Object.keys(englishObj).forEach(function(key){
|
|
||||||
if (!localeObj[key]) {
|
|
||||||
foundErrorB = true
|
|
||||||
notFound.push(key)
|
|
||||||
}
|
|
||||||
counter++
|
|
||||||
})
|
|
||||||
|
|
||||||
if (foundErrorB) {
|
|
||||||
console.log('\nThe following string(s) is(are) not found in the your locale:')
|
|
||||||
notFound.forEach(function(key) {
|
|
||||||
console.log(key)
|
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
console.log('\tall ' + counter +' english strings were found in your locale!')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foundErrorA && !foundErrorB) {
|
|
||||||
console.log('You are good to go')
|
|
||||||
}
|
function verifyLocale({ localeMeta }) {
|
||||||
|
const localeCode = localeMeta.code
|
||||||
|
const localeName = localeMeta.name
|
||||||
|
|
||||||
|
try {
|
||||||
|
const localeFilePath = path.join(process.cwd(), 'app', '_locales', localeCode, 'messages.json')
|
||||||
|
targetLocale = JSON.parse(fs.readFileSync(localeFilePath, 'utf8'));
|
||||||
|
} catch (e) {
|
||||||
|
if (e.code == 'ENOENT') {
|
||||||
|
console.log('Locale file not found')
|
||||||
|
} else {
|
||||||
|
console.log(`Error opening your locale ("${localeCode}") file: `, e)
|
||||||
|
}
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const englishFilePath = path.join(process.cwd(), 'app', '_locales', 'en', 'messages.json')
|
||||||
|
englishLocale = JSON.parse(fs.readFileSync(englishFilePath, 'utf8'));
|
||||||
|
} catch (e) {
|
||||||
|
if(e.code == 'ENOENT') {
|
||||||
|
console.log('English File not found')
|
||||||
|
} else {
|
||||||
|
console.log('Error opening english locale file: ', e)
|
||||||
|
}
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(' verifying whether all your locale ("${localeCode}") strings are contained in the english one')
|
||||||
|
const extraItems = compareLocalesForMissingItems({ base: targetLocale, subject: englishLocale })
|
||||||
|
// console.log('\n verifying whether your locale ("${localeCode}") contains all english strings')
|
||||||
|
const missingItems = compareLocalesForMissingItems({ base: englishLocale, subject: targetLocale })
|
||||||
|
|
||||||
|
const englishEntryCount = Object.keys(englishLocale).length
|
||||||
|
const coveragePercent = 100 * (englishEntryCount - missingItems.length) / englishEntryCount
|
||||||
|
|
||||||
|
console.log(`Status of **${localeName} (${localeCode})** ${coveragePercent.toFixed(2)}% coverage:`)
|
||||||
|
|
||||||
|
if (extraItems.length) {
|
||||||
|
console.log('\nMissing from english locale:')
|
||||||
|
extraItems.forEach(function(key) {
|
||||||
|
console.log(` - [ ] ${key}`)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// console.log(` all ${counter} strings declared in your locale ("${localeCode}") were found in the english one`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingItems.length) {
|
||||||
|
console.log(`\nMissing:`)
|
||||||
|
missingItems.forEach(function(key) {
|
||||||
|
console.log(` - [ ] ${key}`)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// console.log(` all ${counter} english strings were found in your locale ("${localeCode}")!`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!extraItems.length && !missingItems.length) {
|
||||||
|
console.log('Full coverage : )')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareLocalesForMissingItems({ base, subject }) {
|
||||||
|
return Object.keys(base).filter((key) => !subject[key])
|
||||||
|
}
|
||||||
|
@ -6,9 +6,12 @@ The MetaMask browser extension supports new translations added in the form of ne
|
|||||||
|
|
||||||
## Adding a new Language
|
## Adding a new Language
|
||||||
|
|
||||||
Each supported language is represented by a folder in `app/_locales` whose name is that language's subtag ([look up a language subtag using this tool](https://r12a.github.io/app-subtags/)).
|
- Each supported language is represented by a folder in `app/_locales` whose name is that language's subtag (example: `app/_locales/es/`). (look up a language subtag using the [r12a "Find" tool](https://r12a.github.io/app-subtags/) or this [wikipedia list](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)).
|
||||||
|
- Inside that folder there should be a `messages.json`.
|
||||||
|
- An easy way to start your translation is to first **make a copy** of `app/_locales/en/messages.json` (the english translation), and then **translate the `message` key** for each in-app message.
|
||||||
|
- **The `description` key** is just to add context for what the translation is about, it **does not need to be translated**.
|
||||||
|
- Add the language to the [locales index](https://github.com/MetaMask/metamask-extension/blob/master/app/_locales/index.json) `app/_locales/index.json`
|
||||||
|
|
||||||
Inside that folder there should be a `messages.json` file that follows the specified format. An easy way to start your translation is to first duplicate `app/_locales/en/messages.json` (the english translation), and then update the `message` key for each in-app message.
|
|
||||||
|
|
||||||
That's it! When MetaMask is loaded on a computer with that language set as the system language, they will see your translation instead of the default one.
|
That's it! When MetaMask is loaded on a computer with that language set as the system language, they will see your translation instead of the default one.
|
||||||
|
|
||||||
@ -20,7 +23,7 @@ To automatically see if you are missing any phrases to translate, we have a scri
|
|||||||
node development/verify-locale-strings.js $YOUR_LOCALE
|
node development/verify-locale-strings.js $YOUR_LOCALE
|
||||||
```
|
```
|
||||||
|
|
||||||
Where `$YOUR_LOCALE` is your [locale string](https://r12a.github.io/app-subtags/), i.e. the name of your language folder.
|
Where `$YOUR_LOCALE` is your locale string (example: `es`), i.e. the name of your language folder.
|
||||||
|
|
||||||
To verify that your translation works in the app, you will need to [build a local copy](https://github.com/MetaMask/metamask-extension#building-locally) of MetaMask. You will need to change your browser language, your operating system language, and restart your browser (sorry it's so much work!).
|
To verify that your translation works in the app, you will need to [build a local copy](https://github.com/MetaMask/metamask-extension#building-locally) of MetaMask. You will need to change your browser language, your operating system language, and restart your browser (sorry it's so much work!).
|
||||||
|
|
||||||
|
@ -207,9 +207,11 @@ gulp.task('dev:copy',
|
|||||||
|
|
||||||
// lint js
|
// lint js
|
||||||
|
|
||||||
|
const lintTargets = ['app/**/*.json', 'app/**/*.js', '!app/scripts/vendor/**/*.js', 'ui/**/*.js', 'old-ui/**/*.js', 'mascara/src/*.js', 'mascara/server/*.js', '!node_modules/**', '!dist/firefox/**', '!docs/**', '!app/scripts/chromereload.js', '!mascara/test/jquery-3.1.0.min.js']
|
||||||
|
|
||||||
gulp.task('lint', function () {
|
gulp.task('lint', function () {
|
||||||
// Ignoring node_modules, dist/firefox, and docs folders:
|
// Ignoring node_modules, dist/firefox, and docs folders:
|
||||||
return gulp.src(['app/**/*.js', '!app/scripts/vendor/**/*.js', 'ui/**/*.js', 'mascara/src/*.js', 'mascara/server/*.js', '!node_modules/**', '!dist/firefox/**', '!docs/**', '!app/scripts/chromereload.js', '!mascara/test/jquery-3.1.0.min.js'])
|
return gulp.src(lintTargets)
|
||||||
.pipe(eslint(fs.readFileSync(path.join(__dirname, '.eslintrc'))))
|
.pipe(eslint(fs.readFileSync(path.join(__dirname, '.eslintrc'))))
|
||||||
// eslint.format() outputs the lint results to the console.
|
// eslint.format() outputs the lint results to the console.
|
||||||
// Alternatively use eslint.formatEach() (see Docs).
|
// Alternatively use eslint.formatEach() (see Docs).
|
||||||
@ -220,7 +222,7 @@ gulp.task('lint', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('lint:fix', function () {
|
gulp.task('lint:fix', function () {
|
||||||
return gulp.src(['app/**/*.js', 'ui/**/*.js', 'mascara/src/*.js', 'mascara/server/*.js', '!node_modules/**', '!dist/firefox/**', '!docs/**', '!app/scripts/chromereload.js', '!mascara/test/jquery-3.1.0.min.js'])
|
return gulp.src(lintTargets)
|
||||||
.pipe(eslint(Object.assign(fs.readFileSync(path.join(__dirname, '.eslintrc')), {fix: true})))
|
.pipe(eslint(Object.assign(fs.readFileSync(path.join(__dirname, '.eslintrc')), {fix: true})))
|
||||||
.pipe(eslint.format())
|
.pipe(eslint.format())
|
||||||
.pipe(eslint.failAfterError())
|
.pipe(eslint.failAfterError())
|
||||||
|
@ -581,7 +581,6 @@ App.prototype.renderPrimary = function () {
|
|||||||
|
|
||||||
case 'qr':
|
case 'qr':
|
||||||
log.debug('rendering show qr screen')
|
log.debug('rendering show qr screen')
|
||||||
console.log(`QrView`, QrView);
|
|
||||||
return h('div', {
|
return h('div', {
|
||||||
style: {
|
style: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
@ -247,7 +247,6 @@ BuyButtonSubview.prototype.backButtonContext = function () {
|
|||||||
if (this.props.context === 'confTx') {
|
if (this.props.context === 'confTx') {
|
||||||
this.props.dispatch(actions.showConfTxPage(false))
|
this.props.dispatch(actions.showConfTxPage(false))
|
||||||
} else {
|
} else {
|
||||||
console.log(`actions.goHome`, actions.goHome);
|
|
||||||
this.props.dispatch(actions.goHome())
|
this.props.dispatch(actions.goHome())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ function QrCodeView () {
|
|||||||
QrCodeView.prototype.render = function () {
|
QrCodeView.prototype.render = function () {
|
||||||
const props = this.props
|
const props = this.props
|
||||||
const Qr = props.Qr
|
const Qr = props.Qr
|
||||||
console.log(`QrCodeView Qr`, Qr);
|
|
||||||
const address = `${isHexPrefixed(Qr.data) ? 'ethereum:' : ''}${Qr.data}`
|
const address = `${isHexPrefixed(Qr.data) ? 'ethereum:' : ''}${Qr.data}`
|
||||||
const qrImage = qrCode(4, 'M')
|
const qrImage = qrCode(4, 'M')
|
||||||
qrImage.addData(address)
|
qrImage.addData(address)
|
||||||
|
@ -35,7 +35,7 @@ RangeSlider.prototype.render = function () {
|
|||||||
step: increment,
|
step: increment,
|
||||||
style: range,
|
style: range,
|
||||||
value: state.value || defaultValue,
|
value: state.value || defaultValue,
|
||||||
onChange: mirrorInput ? this.mirrorInputs.bind(this, event) : onInput,
|
onChange: mirrorInput ? this.mirrorInputs.bind(this) : onInput,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// Mirrored input for range
|
// Mirrored input for range
|
||||||
@ -47,7 +47,7 @@ RangeSlider.prototype.render = function () {
|
|||||||
value: state.value || defaultValue,
|
value: state.value || defaultValue,
|
||||||
step: increment,
|
step: increment,
|
||||||
style: input,
|
style: input,
|
||||||
onChange: this.mirrorInputs.bind(this, event),
|
onChange: this.mirrorInputs.bind(this),
|
||||||
}) : null,
|
}) : null,
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
|
@ -30,7 +30,12 @@ function TransactionListItem () {
|
|||||||
|
|
||||||
TransactionListItem.prototype.showRetryButton = function () {
|
TransactionListItem.prototype.showRetryButton = function () {
|
||||||
const { transaction = {}, transactions } = this.props
|
const { transaction = {}, transactions } = this.props
|
||||||
const { status, submittedTime, txParams } = transaction
|
const { submittedTime, txParams } = transaction
|
||||||
|
|
||||||
|
if (!txParams) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
const currentNonce = txParams.nonce
|
const currentNonce = txParams.nonce
|
||||||
const currentNonceTxs = transactions.filter(tx => tx.txParams.nonce === currentNonce)
|
const currentNonceTxs = transactions.filter(tx => tx.txParams.nonce === currentNonce)
|
||||||
const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted')
|
const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted')
|
||||||
|
@ -42,7 +42,7 @@ ConfigScreen.prototype.render = function () {
|
|||||||
// subtitle and nav
|
// subtitle and nav
|
||||||
h('.section-title.flex-row.flex-center', [
|
h('.section-title.flex-row.flex-center', [
|
||||||
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
|
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
|
||||||
onClick: (event) => {
|
onClick: () => {
|
||||||
state.dispatch(actions.goHome())
|
state.dispatch(actions.goHome())
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
3243
package-lock.json
generated
3243
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@ -12,7 +12,10 @@
|
|||||||
"test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js",
|
"test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js",
|
||||||
"test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara",
|
"test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara",
|
||||||
"test:integration:build": "gulp build:scss",
|
"test:integration:build": "gulp build:scss",
|
||||||
"test:e2e": "METAMASK_ENV=test mocha test/e2e/metamask.spec --recursive",
|
"test:e2e": "shell-parallel -s 'npm run ganache:start' -x 'sleep 3 && npm run test:e2e:run'",
|
||||||
|
"test:e2e:run": "mocha test/e2e/metamask.spec --recursive",
|
||||||
|
"test:screens": "shell-parallel -s 'npm run ganache:start' -x 'sleep 3 && npm run test:screens:run'",
|
||||||
|
"test:screens:run": "node test/screens/new-ui.js",
|
||||||
"test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload",
|
"test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload",
|
||||||
"test:coveralls-upload": "if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi",
|
"test:coveralls-upload": "if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi",
|
||||||
"test:flat": "npm run test:flat:build && karma start test/flat.conf.js",
|
"test:flat": "npm run test:flat:build && karma start test/flat.conf.js",
|
||||||
@ -27,6 +30,7 @@
|
|||||||
"test:mascara:build:locales": "mkdirp dist/chrome && cp -R app/_locales dist/chrome/_locales",
|
"test:mascara:build:locales": "mkdirp dist/chrome && cp -R app/_locales dist/chrome/_locales",
|
||||||
"test:mascara:build:background": "browserify mascara/src/background.js -o dist/mascara/background.js",
|
"test:mascara:build:background": "browserify mascara/src/background.js -o dist/mascara/background.js",
|
||||||
"test:mascara:build:tests": "browserify test/integration/lib/first-time.js -o dist/mascara/tests.js",
|
"test:mascara:build:tests": "browserify test/integration/lib/first-time.js -o dist/mascara/tests.js",
|
||||||
|
"ganache:start": "ganache-cli -m 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'",
|
||||||
"sentry": "export RELEASE=`cat app/manifest.json| jq -r .version` && npm run sentry:release && npm run sentry:upload",
|
"sentry": "export RELEASE=`cat app/manifest.json| jq -r .version` && npm run sentry:release && npm run sentry:upload",
|
||||||
"sentry:release": "npm run sentry:release:new && npm run sentry:release:clean",
|
"sentry:release": "npm run sentry:release:new && npm run sentry:release:clean",
|
||||||
"sentry:release:new": "sentry-cli releases --org 'metamask' --project 'metamask' new $RELEASE",
|
"sentry:release:new": "sentry-cli releases --org 'metamask' --project 'metamask' new $RELEASE",
|
||||||
@ -140,7 +144,6 @@
|
|||||||
"number-to-bn": "^1.7.0",
|
"number-to-bn": "^1.7.0",
|
||||||
"obj-multiplex": "^1.0.0",
|
"obj-multiplex": "^1.0.0",
|
||||||
"obs-store": "^3.0.0",
|
"obs-store": "^3.0.0",
|
||||||
"once": "^1.3.3",
|
|
||||||
"percentile": "^1.2.0",
|
"percentile": "^1.2.0",
|
||||||
"pify": "^3.0.0",
|
"pify": "^3.0.0",
|
||||||
"ping-pong-stream": "^1.0.0",
|
"ping-pong-stream": "^1.0.0",
|
||||||
@ -216,10 +219,13 @@
|
|||||||
"enzyme": "^3.3.0",
|
"enzyme": "^3.3.0",
|
||||||
"enzyme-adapter-react-15": "^1.0.5",
|
"enzyme-adapter-react-15": "^1.0.5",
|
||||||
"eslint-plugin-chai": "0.0.1",
|
"eslint-plugin-chai": "0.0.1",
|
||||||
|
"eslint-plugin-json": "^1.2.0",
|
||||||
"eslint-plugin-mocha": "^5.0.0",
|
"eslint-plugin-mocha": "^5.0.0",
|
||||||
"eslint-plugin-react": "^7.4.0",
|
"eslint-plugin-react": "^7.4.0",
|
||||||
"eth-json-rpc-middleware": "^1.2.7",
|
"eth-json-rpc-middleware": "^1.2.7",
|
||||||
"fs-promise": "^2.0.3",
|
"fs-promise": "^2.0.3",
|
||||||
|
"ganache-cli": "^6.1.0",
|
||||||
|
"gifencoder": "^1.1.0",
|
||||||
"gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed",
|
"gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed",
|
||||||
"gulp-babel": "^7.0.0",
|
"gulp-babel": "^7.0.0",
|
||||||
"gulp-eslint": "^4.0.0",
|
"gulp-eslint": "^4.0.0",
|
||||||
@ -234,6 +240,7 @@
|
|||||||
"gulp-util": "^3.0.7",
|
"gulp-util": "^3.0.7",
|
||||||
"gulp-watch": "^5.0.0",
|
"gulp-watch": "^5.0.0",
|
||||||
"gulp-zip": "^4.0.0",
|
"gulp-zip": "^4.0.0",
|
||||||
|
"image-size": "^0.6.2",
|
||||||
"isomorphic-fetch": "^2.2.1",
|
"isomorphic-fetch": "^2.2.1",
|
||||||
"jsdom": "^11.2.0",
|
"jsdom": "^11.2.0",
|
||||||
"jsdom-global": "^3.0.2",
|
"jsdom-global": "^3.0.2",
|
||||||
@ -252,6 +259,7 @@
|
|||||||
"node-sass": "^4.7.2",
|
"node-sass": "^4.7.2",
|
||||||
"nyc": "^11.0.3",
|
"nyc": "^11.0.3",
|
||||||
"open": "0.0.5",
|
"open": "0.0.5",
|
||||||
|
"png-file-stream": "^1.0.0",
|
||||||
"prompt": "^1.0.0",
|
"prompt": "^1.0.0",
|
||||||
"qs": "^6.2.0",
|
"qs": "^6.2.0",
|
||||||
"qunitjs": "^2.4.1",
|
"qunitjs": "^2.4.1",
|
||||||
@ -259,7 +267,9 @@
|
|||||||
"react-test-renderer": "^15.6.2",
|
"react-test-renderer": "^15.6.2",
|
||||||
"react-testutils-additions": "^15.2.0",
|
"react-testutils-additions": "^15.2.0",
|
||||||
"redux-test-utils": "^0.2.2",
|
"redux-test-utils": "^0.2.2",
|
||||||
|
"rimraf": "^2.6.2",
|
||||||
"selenium-webdriver": "^3.5.0",
|
"selenium-webdriver": "^3.5.0",
|
||||||
|
"shell-parallel": "^1.0.3",
|
||||||
"sinon": "^5.0.0",
|
"sinon": "^5.0.0",
|
||||||
"stylelint-config-standard": "^18.2.0",
|
"stylelint-config-standard": "^18.2.0",
|
||||||
"tape": "^4.5.1",
|
"tape": "^4.5.1",
|
||||||
|
@ -38,6 +38,8 @@ describe('Metamask popup page', function () {
|
|||||||
const tabs = await driver.getAllWindowHandles()
|
const tabs = await driver.getAllWindowHandles()
|
||||||
await driver.switchTo().window(tabs[0])
|
await driver.switchTo().window(tabs[0])
|
||||||
await delay(300)
|
await delay(300)
|
||||||
|
await setProviderType('localhost')
|
||||||
|
await delay(300)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should match title', async () => {
|
it('should match title', async () => {
|
||||||
@ -124,6 +126,10 @@ describe('Metamask popup page', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
async function setProviderType(type) {
|
||||||
|
await driver.executeScript('window.metamask.setProviderType(arguments[0])', type)
|
||||||
|
}
|
||||||
|
|
||||||
async function verboseReportOnFailure(test) {
|
async function verboseReportOnFailure(test) {
|
||||||
const artifactDir = `./test-artifacts/${test.title}`
|
const artifactDir = `./test-artifacts/${test.title}`
|
||||||
const filepathBase = `${artifactDir}/test-failure`
|
const filepathBase = `${artifactDir}/test-failure`
|
||||||
|
61
test/integration/lib/tx-list-items.js
Normal file
61
test/integration/lib/tx-list-items.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
const reactTriggerChange = require('../../lib/react-trigger-change')
|
||||||
|
const {
|
||||||
|
timeout,
|
||||||
|
queryAsync,
|
||||||
|
findAsync,
|
||||||
|
} = require('../../lib/util')
|
||||||
|
|
||||||
|
QUnit.module('tx list items')
|
||||||
|
|
||||||
|
QUnit.test('renders list items successfully', (assert) => {
|
||||||
|
const done = assert.async()
|
||||||
|
runTxListItemsTest(assert).then(done).catch((err) => {
|
||||||
|
assert.notOk(err, `Error was thrown: ${err.stack}`)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
async function runTxListItemsTest(assert, done) {
|
||||||
|
console.log('*** start runTxListItemsTest')
|
||||||
|
const selectState = await queryAsync($, 'select')
|
||||||
|
selectState.val('tx list items')
|
||||||
|
reactTriggerChange(selectState[0])
|
||||||
|
|
||||||
|
const metamaskLogo = await queryAsync($, '.left-menu-wrapper')
|
||||||
|
assert.ok(metamaskLogo[0], 'metamask logo present')
|
||||||
|
metamaskLogo[0].click()
|
||||||
|
|
||||||
|
const txListItems = await queryAsync($, '.tx-list-item')
|
||||||
|
assert.equal(txListItems.length, 8, 'all tx list items are rendered')
|
||||||
|
|
||||||
|
const unapprovedTx = txListItems[0]
|
||||||
|
assert.equal($(unapprovedTx).hasClass('tx-list-pending-item-container'), true, 'unapprovedTx has the correct class')
|
||||||
|
|
||||||
|
const retryTx = txListItems[1]
|
||||||
|
const retryTxLink = await findAsync($(retryTx), '.tx-list-item-retry-link')
|
||||||
|
assert.equal(retryTxLink[0].textContent, 'Increase the gas price on your transaction', 'retryTx has expected link')
|
||||||
|
|
||||||
|
const approvedTx = txListItems[2]
|
||||||
|
const approvedTxRenderedStatus = await findAsync($(approvedTx), '.tx-list-status')
|
||||||
|
assert.equal(approvedTxRenderedStatus[0].textContent, 'Approved', 'approvedTx has correct label')
|
||||||
|
|
||||||
|
const unapprovedMsg = txListItems[3]
|
||||||
|
const unapprovedMsgDescription = await findAsync($(unapprovedMsg), '.tx-list-account')
|
||||||
|
assert.equal(unapprovedMsgDescription[0].textContent, 'Signature Request', 'unapprovedMsg has correct description')
|
||||||
|
|
||||||
|
const failedTx = txListItems[4]
|
||||||
|
const failedTxRenderedStatus = await findAsync($(failedTx), '.tx-list-status')
|
||||||
|
assert.equal(failedTxRenderedStatus[0].textContent, 'Failed', 'failedTx has correct label')
|
||||||
|
|
||||||
|
const shapeShiftTx = txListItems[5]
|
||||||
|
const shapeShiftTxStatus = await findAsync($(shapeShiftTx), '.flex-column div:eq(1)')
|
||||||
|
assert.equal(shapeShiftTxStatus[0].textContent, 'No deposits received', 'shapeShiftTx has correct status')
|
||||||
|
|
||||||
|
const confirmedTokenTx = txListItems[6]
|
||||||
|
const confirmedTokenTxAddress = await findAsync($(confirmedTokenTx), '.tx-list-account')
|
||||||
|
assert.equal(confirmedTokenTxAddress[0].textContent, '0xe7884118...81a9', 'confirmedTokenTx has correct address')
|
||||||
|
|
||||||
|
const rejectedTx = txListItems[7]
|
||||||
|
const rejectedTxRenderedStatus = await findAsync($(rejectedTx), '.tx-list-status')
|
||||||
|
assert.equal(rejectedTxRenderedStatus[0].textContent, 'Rejected', 'rejectedTx has correct label')
|
||||||
|
}
|
18
test/screens/func.js
Normal file
18
test/screens/func.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
require('chromedriver')
|
||||||
|
const webdriver = require('selenium-webdriver')
|
||||||
|
|
||||||
|
exports.delay = function delay (time) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, time))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exports.buildWebDriver = function buildWebDriver (extPath) {
|
||||||
|
return new webdriver.Builder()
|
||||||
|
.withCapabilities({
|
||||||
|
chromeOptions: {
|
||||||
|
args: [`load-extension=${extPath}`],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.forBrowser('chrome')
|
||||||
|
.build()
|
||||||
|
}
|
230
test/screens/new-ui.js
Normal file
230
test/screens/new-ui.js
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
const path = require('path')
|
||||||
|
const fs = require('fs')
|
||||||
|
const pify = require('pify')
|
||||||
|
const mkdirp = require('mkdirp')
|
||||||
|
const rimraf = require('rimraf')
|
||||||
|
const webdriver = require('selenium-webdriver')
|
||||||
|
const endOfStream = require('end-of-stream')
|
||||||
|
const GIFEncoder = require('gifencoder')
|
||||||
|
const pngFileStream = require('png-file-stream')
|
||||||
|
const sizeOfPng = require('image-size/lib/types/png')
|
||||||
|
const By = webdriver.By
|
||||||
|
const { delay, buildWebDriver } = require('./func')
|
||||||
|
const localesIndex = require('../../app/_locales/index.json')
|
||||||
|
|
||||||
|
let driver
|
||||||
|
|
||||||
|
captureAllScreens().catch((err) => {
|
||||||
|
try {
|
||||||
|
console.error(err)
|
||||||
|
verboseReportOnFailure()
|
||||||
|
driver.quit()
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
async function captureAllScreens() {
|
||||||
|
let screenshotCount = 0
|
||||||
|
|
||||||
|
// common names
|
||||||
|
let button
|
||||||
|
let tabs
|
||||||
|
let element
|
||||||
|
|
||||||
|
await cleanScreenShotDir()
|
||||||
|
|
||||||
|
// setup selenium and install extension
|
||||||
|
const extPath = path.resolve('dist/chrome')
|
||||||
|
driver = buildWebDriver(extPath)
|
||||||
|
await driver.get('chrome://extensions-frame')
|
||||||
|
const elems = await driver.findElements(By.css('.extension-list-item-wrapper'))
|
||||||
|
const extensionId = await elems[1].getAttribute('id')
|
||||||
|
await driver.get(`chrome-extension://${extensionId}/home.html`)
|
||||||
|
await delay(500)
|
||||||
|
tabs = await driver.getAllWindowHandles()
|
||||||
|
await driver.switchTo().window(tabs[0])
|
||||||
|
await delay(1000)
|
||||||
|
await setProviderType('localhost')
|
||||||
|
await delay(300)
|
||||||
|
|
||||||
|
// click try new ui
|
||||||
|
await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-row.flex-center.flex-grow > p')).click()
|
||||||
|
await delay(300)
|
||||||
|
|
||||||
|
// close metamask homepage and extra home.html
|
||||||
|
tabs = await driver.getAllWindowHandles()
|
||||||
|
// metamask homepage is opened on prod, not dev
|
||||||
|
if (tabs.length > 2) {
|
||||||
|
await driver.switchTo().window(tabs[2])
|
||||||
|
driver.close()
|
||||||
|
}
|
||||||
|
await driver.switchTo().window(tabs[1])
|
||||||
|
driver.close()
|
||||||
|
await driver.switchTo().window(tabs[0])
|
||||||
|
await delay(300)
|
||||||
|
await captureLanguageScreenShots('welcome-new-ui')
|
||||||
|
|
||||||
|
// setup account
|
||||||
|
await delay(1000)
|
||||||
|
await driver.findElement(By.css('body')).click()
|
||||||
|
await delay(300)
|
||||||
|
await captureLanguageScreenShots('welcome')
|
||||||
|
|
||||||
|
await driver.findElement(By.css('button')).click()
|
||||||
|
await captureLanguageScreenShots('create password')
|
||||||
|
|
||||||
|
const passwordBox = await driver.findElement(By.css('input[type=password]:nth-of-type(1)'))
|
||||||
|
const passwordBoxConfirm = await driver.findElement(By.css('input[type=password]:nth-of-type(2)'))
|
||||||
|
passwordBox.sendKeys('123456789')
|
||||||
|
passwordBoxConfirm.sendKeys('123456789')
|
||||||
|
await delay(500)
|
||||||
|
await captureLanguageScreenShots('choose-password-filled')
|
||||||
|
|
||||||
|
await driver.findElement(By.css('button')).click()
|
||||||
|
await delay(500)
|
||||||
|
await captureLanguageScreenShots('unique account image')
|
||||||
|
|
||||||
|
await driver.findElement(By.css('button')).click()
|
||||||
|
await delay(500)
|
||||||
|
await captureLanguageScreenShots('privacy note')
|
||||||
|
|
||||||
|
await driver.findElement(By.css('button')).click()
|
||||||
|
await delay(300)
|
||||||
|
await captureLanguageScreenShots('terms')
|
||||||
|
|
||||||
|
await delay(300)
|
||||||
|
element = driver.findElement(By.linkText('Attributions'))
|
||||||
|
await driver.executeScript('arguments[0].scrollIntoView(true)', element)
|
||||||
|
await delay(300)
|
||||||
|
await captureLanguageScreenShots('terms-scrolled')
|
||||||
|
|
||||||
|
await driver.findElement(By.css('button')).click()
|
||||||
|
await delay(300)
|
||||||
|
await captureLanguageScreenShots('secret backup phrase')
|
||||||
|
|
||||||
|
await driver.findElement(By.css('button')).click()
|
||||||
|
await delay(300)
|
||||||
|
await captureLanguageScreenShots('secret backup phrase')
|
||||||
|
|
||||||
|
await driver.findElement(By.css('.backup-phrase__reveal-button')).click()
|
||||||
|
await delay(300)
|
||||||
|
await captureLanguageScreenShots('secret backup phrase - reveal')
|
||||||
|
|
||||||
|
await driver.findElement(By.css('button')).click()
|
||||||
|
await delay(300)
|
||||||
|
await captureLanguageScreenShots('confirm secret backup phrase')
|
||||||
|
|
||||||
|
// finish up
|
||||||
|
console.log('building gif...')
|
||||||
|
await generateGif()
|
||||||
|
await driver.quit()
|
||||||
|
return
|
||||||
|
|
||||||
|
//
|
||||||
|
// await button.click()
|
||||||
|
// await delay(700)
|
||||||
|
// this.seedPhase = await driver.findElement(By.css('.twelve-word-phrase')).getText()
|
||||||
|
// await captureScreenShot('seed phrase')
|
||||||
|
//
|
||||||
|
// const continueAfterSeedPhrase = await driver.findElement(By.css('button'))
|
||||||
|
// await continueAfterSeedPhrase.click()
|
||||||
|
// await delay(300)
|
||||||
|
// await captureScreenShot('main screen')
|
||||||
|
//
|
||||||
|
// await driver.findElement(By.css('.sandwich-expando')).click()
|
||||||
|
// await delay(500)
|
||||||
|
// await captureScreenShot('menu')
|
||||||
|
|
||||||
|
// await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)')).click()
|
||||||
|
// await captureScreenShot('main screen')
|
||||||
|
// it('should accept account password after lock', async () => {
|
||||||
|
// await delay(500)
|
||||||
|
// await driver.findElement(By.id('password-box')).sendKeys('123456789')
|
||||||
|
// await driver.findElement(By.css('button')).click()
|
||||||
|
// await delay(500)
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// it('should show QR code option', async () => {
|
||||||
|
// await delay(300)
|
||||||
|
// await driver.findElement(By.css('.fa-ellipsis-h')).click()
|
||||||
|
// await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div > div:nth-child(1) > flex-column > div.name-label > div > span > i > div > div > li:nth-child(3)')).click()
|
||||||
|
// await delay(300)
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// it('should show the account address', async () => {
|
||||||
|
// this.accountAddress = await driver.findElement(By.css('.ellip-address')).getText()
|
||||||
|
// await driver.findElement(By.css('.fa-arrow-left')).click()
|
||||||
|
// await delay(500)
|
||||||
|
// })
|
||||||
|
|
||||||
|
async function captureLanguageScreenShots(label) {
|
||||||
|
const nonEnglishLocales = localesIndex.filter(localeMeta => localeMeta.code !== 'en')
|
||||||
|
// take english shot
|
||||||
|
await captureScreenShot(`${label} (en)`)
|
||||||
|
for (let localeMeta of nonEnglishLocales) {
|
||||||
|
// set locale and take shot
|
||||||
|
await setLocale(localeMeta.code)
|
||||||
|
await delay(300)
|
||||||
|
await captureScreenShot(`${label} (${localeMeta.code})`)
|
||||||
|
}
|
||||||
|
// return locale to english
|
||||||
|
await setLocale('en')
|
||||||
|
await delay(300)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setLocale(code) {
|
||||||
|
await driver.executeScript('window.metamask.updateCurrentLocale(arguments[0])', code)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setProviderType(type) {
|
||||||
|
await driver.executeScript('window.metamask.setProviderType(arguments[0])', type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
await driver.quit()
|
||||||
|
|
||||||
|
async function cleanScreenShotDir() {
|
||||||
|
await pify(rimraf)(`./test-artifacts/screens/`)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function captureScreenShot(label) {
|
||||||
|
const shotIndex = screenshotCount.toString().padStart(4, '0')
|
||||||
|
screenshotCount++
|
||||||
|
const artifactDir = `./test-artifacts/screens/`
|
||||||
|
await pify(mkdirp)(artifactDir)
|
||||||
|
// capture screenshot
|
||||||
|
const screenshot = await driver.takeScreenshot()
|
||||||
|
await pify(fs.writeFile)(`${artifactDir}/${shotIndex} - ${label}.png`, screenshot, { encoding: 'base64' })
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateGif(){
|
||||||
|
// calculate screenshot size
|
||||||
|
const screenshot = await driver.takeScreenshot()
|
||||||
|
const pngBuffer = Buffer.from(screenshot, 'base64')
|
||||||
|
const size = sizeOfPng.calculate(pngBuffer)
|
||||||
|
|
||||||
|
// read only the english pngs into gif
|
||||||
|
const encoder = new GIFEncoder(size.width, size.height)
|
||||||
|
const stream = pngFileStream('./test-artifacts/screens/* (en).png')
|
||||||
|
.pipe(encoder.createWriteStream({ repeat: 0, delay: 1000, quality: 10 }))
|
||||||
|
.pipe(fs.createWriteStream('./test-artifacts/screens/walkthrough (en).gif'))
|
||||||
|
|
||||||
|
// wait for end
|
||||||
|
await pify(endOfStream)(stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verboseReportOnFailure(test) {
|
||||||
|
const artifactDir = `./test-artifacts/${test.title}`
|
||||||
|
const filepathBase = `${artifactDir}/test-failure`
|
||||||
|
await pify(mkdirp)(artifactDir)
|
||||||
|
// capture screenshot
|
||||||
|
const screenshot = await driver.takeScreenshot()
|
||||||
|
await pify(fs.writeFile)(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' })
|
||||||
|
// capture dom source
|
||||||
|
const htmlSource = await driver.getPageSource()
|
||||||
|
await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource)
|
||||||
|
}
|
@ -162,7 +162,7 @@ describe('Transaction Controller', function () {
|
|||||||
describe('#addUnapprovedTransaction', function () {
|
describe('#addUnapprovedTransaction', function () {
|
||||||
|
|
||||||
it('should add an unapproved transaction and return a valid txMeta', function (done) {
|
it('should add an unapproved transaction and return a valid txMeta', function (done) {
|
||||||
txController.addUnapprovedTransaction({})
|
txController.addUnapprovedTransaction({ from: '0x1678a085c290ebd122dc42cba69373b5953b831d' })
|
||||||
.then((txMeta) => {
|
.then((txMeta) => {
|
||||||
assert(('id' in txMeta), 'should have a id')
|
assert(('id' in txMeta), 'should have a id')
|
||||||
assert(('time' in txMeta), 'should have a time stamp')
|
assert(('time' in txMeta), 'should have a time stamp')
|
||||||
@ -182,7 +182,7 @@ describe('Transaction Controller', function () {
|
|||||||
assert(txMetaFromEmit, 'txMeta is falsey')
|
assert(txMetaFromEmit, 'txMeta is falsey')
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
txController.addUnapprovedTransaction({})
|
txController.addUnapprovedTransaction({ from: '0x1678a085c290ebd122dc42cba69373b5953b831d' })
|
||||||
.catch(done)
|
.catch(done)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -213,6 +213,7 @@ describe('Transaction Controller', function () {
|
|||||||
describe('#validateTxParams', function () {
|
describe('#validateTxParams', function () {
|
||||||
it('does not throw for positive values', function (done) {
|
it('does not throw for positive values', function (done) {
|
||||||
var sample = {
|
var sample = {
|
||||||
|
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
|
||||||
value: '0x01',
|
value: '0x01',
|
||||||
}
|
}
|
||||||
txController.txGasUtil.validateTxParams(sample).then(() => {
|
txController.txGasUtil.validateTxParams(sample).then(() => {
|
||||||
@ -222,6 +223,7 @@ describe('Transaction Controller', function () {
|
|||||||
|
|
||||||
it('returns error for negative values', function (done) {
|
it('returns error for negative values', function (done) {
|
||||||
var sample = {
|
var sample = {
|
||||||
|
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
|
||||||
value: '-0x01',
|
value: '-0x01',
|
||||||
}
|
}
|
||||||
txController.txGasUtil.validateTxParams(sample)
|
txController.txGasUtil.validateTxParams(sample)
|
||||||
|
@ -29,4 +29,28 @@ describe('Tx Gas Util', function () {
|
|||||||
}
|
}
|
||||||
assert.throws(() => { txGasUtil.validateRecipient(zeroRecipientTxParams) }, Error, 'Invalid recipient address')
|
assert.throws(() => { txGasUtil.validateRecipient(zeroRecipientTxParams) }, Error, 'Invalid recipient address')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should error when from is not a hex string', function () {
|
||||||
|
|
||||||
|
// where from is undefined
|
||||||
|
const txParams = {}
|
||||||
|
assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`)
|
||||||
|
|
||||||
|
// where from is array
|
||||||
|
txParams.from = []
|
||||||
|
assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`)
|
||||||
|
|
||||||
|
// where from is a object
|
||||||
|
txParams.from = {}
|
||||||
|
assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`)
|
||||||
|
|
||||||
|
// where from is a invalid address
|
||||||
|
txParams.from = 'im going to fail'
|
||||||
|
assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address`)
|
||||||
|
|
||||||
|
// should run
|
||||||
|
txParams.from ='0x1678a085c290ebd122dc42cba69373b5953b831d'
|
||||||
|
txGasUtil.validateFrom(txParams)
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@ -1374,7 +1374,7 @@ function retryTransaction (txId) {
|
|||||||
|
|
||||||
function setProviderType (type) {
|
function setProviderType (type) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
log.debug(`background.setProviderType`)
|
log.debug(`background.setProviderType`, type)
|
||||||
background.setProviderType(type, (err, result) => {
|
background.setProviderType(type, (err, result) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
log.error(err)
|
log.error(err)
|
||||||
@ -1395,13 +1395,14 @@ function updateProviderType (type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setRpcTarget (newRpc) {
|
function setRpcTarget (newRpc) {
|
||||||
log.debug(`background.setRpcTarget: ${newRpc}`)
|
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
|
log.debug(`background.setRpcTarget: ${newRpc}`)
|
||||||
background.setCustomRpc(newRpc, (err, result) => {
|
background.setCustomRpc(newRpc, (err, result) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
log.error(err)
|
log.error(err)
|
||||||
return dispatch(self.displayWarning('Had a problem changing networks!'))
|
return dispatch(self.displayWarning('Had a problem changing networks!'))
|
||||||
}
|
}
|
||||||
|
dispatch(actions.setSelectedToken())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,6 @@ class App extends Component {
|
|||||||
component: RevealSeedPage,
|
component: RevealSeedPage,
|
||||||
mascaraComponent: MascaraSeedScreen,
|
mascaraComponent: MascaraSeedScreen,
|
||||||
}),
|
}),
|
||||||
// h(Initialized, { path: CONFIRM_SEED_ROUTE, exact, component: MascaraConfirmSeedScreen }),
|
|
||||||
h(Initialized, { path: UNLOCK_ROUTE, exact, component: UnlockPage }),
|
h(Initialized, { path: UNLOCK_ROUTE, exact, component: UnlockPage }),
|
||||||
h(Initialized, { path: SETTINGS_ROUTE, component: Settings }),
|
h(Initialized, { path: SETTINGS_ROUTE, component: Settings }),
|
||||||
h(Initialized, { path: RESTORE_VAULT_ROUTE, exact, component: RestoreVaultPage }),
|
h(Initialized, { path: RESTORE_VAULT_ROUTE, exact, component: RestoreVaultPage }),
|
||||||
@ -214,7 +213,6 @@ class App extends Component {
|
|||||||
networkDropdownOpen,
|
networkDropdownOpen,
|
||||||
showNetworkDropdown,
|
showNetworkDropdown,
|
||||||
hideNetworkDropdown,
|
hideNetworkDropdown,
|
||||||
currentView,
|
|
||||||
isInitialized,
|
isInitialized,
|
||||||
welcomeScreenSeen,
|
welcomeScreenSeen,
|
||||||
isPopup,
|
isPopup,
|
||||||
@ -276,7 +274,7 @@ class App extends Component {
|
|||||||
h(NetworkIndicator, {
|
h(NetworkIndicator, {
|
||||||
network,
|
network,
|
||||||
provider,
|
provider,
|
||||||
disabled: currentView.name === 'confTx',
|
disabled: this.props.location.pathname === CONFIRM_TRANSACTION_ROUTE,
|
||||||
onClick: (event) => {
|
onClick: (event) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
@ -395,6 +393,7 @@ App.propTypes = {
|
|||||||
showNetworkDropdown: PropTypes.func,
|
showNetworkDropdown: PropTypes.func,
|
||||||
hideNetworkDropdown: PropTypes.func,
|
hideNetworkDropdown: PropTypes.func,
|
||||||
history: PropTypes.object,
|
history: PropTypes.object,
|
||||||
|
location: PropTypes.object,
|
||||||
dispatch: PropTypes.func,
|
dispatch: PropTypes.func,
|
||||||
toggleAccountMenu: PropTypes.func,
|
toggleAccountMenu: PropTypes.func,
|
||||||
selectedAddress: PropTypes.string,
|
selectedAddress: PropTypes.string,
|
||||||
|
@ -65,6 +65,7 @@ function mapDispatchToProps (dispatch) {
|
|||||||
updateGasLimit: newGasLimit => dispatch(actions.updateGasLimit(newGasLimit)),
|
updateGasLimit: newGasLimit => dispatch(actions.updateGasLimit(newGasLimit)),
|
||||||
updateGasTotal: newGasTotal => dispatch(actions.updateGasTotal(newGasTotal)),
|
updateGasTotal: newGasTotal => dispatch(actions.updateGasTotal(newGasTotal)),
|
||||||
updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)),
|
updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)),
|
||||||
|
updateSendErrors: error => dispatch(actions.updateSendErrors(error)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +113,7 @@ CustomizeGasModal.prototype.save = function (gasPrice, gasLimit, gasTotal) {
|
|||||||
selectedToken,
|
selectedToken,
|
||||||
balance,
|
balance,
|
||||||
updateSendAmount,
|
updateSendAmount,
|
||||||
|
updateSendErrors,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
if (maxModeOn && !selectedToken) {
|
if (maxModeOn && !selectedToken) {
|
||||||
@ -126,6 +128,7 @@ CustomizeGasModal.prototype.save = function (gasPrice, gasLimit, gasTotal) {
|
|||||||
updateGasPrice(ethUtil.addHexPrefix(gasPrice))
|
updateGasPrice(ethUtil.addHexPrefix(gasPrice))
|
||||||
updateGasLimit(ethUtil.addHexPrefix(gasLimit))
|
updateGasLimit(ethUtil.addHexPrefix(gasLimit))
|
||||||
updateGasTotal(ethUtil.addHexPrefix(gasTotal))
|
updateGasTotal(ethUtil.addHexPrefix(gasTotal))
|
||||||
|
updateSendErrors({ insufficientFunds: false })
|
||||||
hideModal()
|
hideModal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,18 +203,18 @@ NetworkDropdown.prototype.render = function () {
|
|||||||
{
|
{
|
||||||
key: 'default',
|
key: 'default',
|
||||||
closeMenu: () => this.props.hideNetworkDropdown(),
|
closeMenu: () => this.props.hideNetworkDropdown(),
|
||||||
onClick: () => props.setRpcTarget('http://localhost:8545'),
|
onClick: () => props.setProviderType('localhost'),
|
||||||
style: dropdownMenuItemStyle,
|
style: dropdownMenuItemStyle,
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
activeNetwork === 'http://localhost:8545' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'),
|
providerType === 'localhost' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'),
|
||||||
h(NetworkDropdownIcon, {
|
h(NetworkDropdownIcon, {
|
||||||
isSelected: activeNetwork === 'http://localhost:8545',
|
isSelected: providerType === 'localhost',
|
||||||
innerBorder: '1px solid #9b9b9b',
|
innerBorder: '1px solid #9b9b9b',
|
||||||
}),
|
}),
|
||||||
h('span.network-name-item', {
|
h('span.network-name-item', {
|
||||||
style: {
|
style: {
|
||||||
color: activeNetwork === 'http://localhost:8545' ? '#ffffff' : '#9b9b9b',
|
color: providerType === 'localhost' ? '#ffffff' : '#9b9b9b',
|
||||||
},
|
},
|
||||||
}, this.context.t('localhost')),
|
}, this.context.t('localhost')),
|
||||||
]
|
]
|
||||||
|
@ -105,9 +105,8 @@ IdenticonComponent.prototype.componentDidUpdate = function () {
|
|||||||
function _generateBlockie (container, address, diameter) {
|
function _generateBlockie (container, address, diameter) {
|
||||||
const img = new Image()
|
const img = new Image()
|
||||||
img.src = toDataUrl(address)
|
img.src = toDataUrl(address)
|
||||||
const dia = !diameter || diameter < 50 ? 50 : diameter
|
img.height = diameter
|
||||||
img.height = dia * 1.25
|
img.width = diameter
|
||||||
img.width = dia * 1.25
|
|
||||||
container.appendChild(img)
|
container.appendChild(img)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,21 +27,6 @@ const {
|
|||||||
} = require('../../routes')
|
} = require('../../routes')
|
||||||
|
|
||||||
class Home extends Component {
|
class Home extends Component {
|
||||||
componentDidMount () {
|
|
||||||
const {
|
|
||||||
unapprovedTxs = {},
|
|
||||||
unapprovedMsgCount = 0,
|
|
||||||
unapprovedPersonalMsgCount = 0,
|
|
||||||
unapprovedTypedMessagesCount = 0,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
// unapprovedTxs and unapproved messages
|
|
||||||
if (Object.keys(unapprovedTxs).length ||
|
|
||||||
unapprovedTypedMessagesCount + unapprovedMsgCount + unapprovedPersonalMsgCount > 0) {
|
|
||||||
this.props.history.push(CONFIRM_TRANSACTION_ROUTE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
log.debug('rendering primary')
|
log.debug('rendering primary')
|
||||||
const {
|
const {
|
||||||
@ -51,6 +36,10 @@ class Home extends Component {
|
|||||||
currentView,
|
currentView,
|
||||||
activeAddress,
|
activeAddress,
|
||||||
seedWords,
|
seedWords,
|
||||||
|
unapprovedTxs = {},
|
||||||
|
unapprovedMsgCount = 0,
|
||||||
|
unapprovedPersonalMsgCount = 0,
|
||||||
|
unapprovedTypedMessagesCount = 0,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
// notices
|
// notices
|
||||||
@ -81,6 +70,16 @@ class Home extends Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unapprovedTxs and unapproved messages
|
||||||
|
if (Object.keys(unapprovedTxs).length ||
|
||||||
|
unapprovedTypedMessagesCount + unapprovedMsgCount + unapprovedPersonalMsgCount > 0) {
|
||||||
|
return h(Redirect, {
|
||||||
|
to: {
|
||||||
|
pathname: CONFIRM_TRANSACTION_ROUTE,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// if (!props.noActiveNotices) {
|
// if (!props.noActiveNotices) {
|
||||||
// log.debug('rendering notice screen for unread notices.')
|
// log.debug('rendering notice screen for unread notices.')
|
||||||
// return h(NoticeScreen, {
|
// return h(NoticeScreen, {
|
||||||
|
@ -10,11 +10,16 @@ const clone = require('clone')
|
|||||||
const ethUtil = require('ethereumjs-util')
|
const ethUtil = require('ethereumjs-util')
|
||||||
const BN = ethUtil.BN
|
const BN = ethUtil.BN
|
||||||
const hexToBn = require('../../../../app/scripts/lib/hex-to-bn')
|
const hexToBn = require('../../../../app/scripts/lib/hex-to-bn')
|
||||||
|
const classnames = require('classnames')
|
||||||
const {
|
const {
|
||||||
conversionUtil,
|
conversionUtil,
|
||||||
addCurrencies,
|
addCurrencies,
|
||||||
multiplyCurrencies,
|
multiplyCurrencies,
|
||||||
} = require('../../conversion-util')
|
} = require('../../conversion-util')
|
||||||
|
const {
|
||||||
|
getGasTotal,
|
||||||
|
isBalanceSufficient,
|
||||||
|
} = require('../send/send-utils')
|
||||||
const GasFeeDisplay = require('../send/gas-fee-display-v2')
|
const GasFeeDisplay = require('../send/gas-fee-display-v2')
|
||||||
const SenderToRecipient = require('../sender-to-recipient')
|
const SenderToRecipient = require('../sender-to-recipient')
|
||||||
const NetworkDisplay = require('../network-display')
|
const NetworkDisplay = require('../network-display')
|
||||||
@ -41,12 +46,14 @@ function mapStateToProps (state) {
|
|||||||
} = state.metamask
|
} = state.metamask
|
||||||
const accounts = state.metamask.accounts
|
const accounts = state.metamask.accounts
|
||||||
const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
|
const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
|
||||||
|
const { balance } = accounts[selectedAddress]
|
||||||
return {
|
return {
|
||||||
conversionRate,
|
conversionRate,
|
||||||
identities,
|
identities,
|
||||||
selectedAddress,
|
selectedAddress,
|
||||||
currentCurrency,
|
currentCurrency,
|
||||||
send,
|
send,
|
||||||
|
balance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +103,7 @@ function mapDispatchToProps (dispatch) {
|
|||||||
}))
|
}))
|
||||||
dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' }))
|
dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' }))
|
||||||
},
|
},
|
||||||
|
updateSendErrors: error => dispatch(actions.updateSendErrors(error)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +114,52 @@ function ConfirmSendEther () {
|
|||||||
this.onSubmit = this.onSubmit.bind(this)
|
this.onSubmit = this.onSubmit.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfirmSendEther.prototype.updateComponentSendErrors = function (prevProps) {
|
||||||
|
const {
|
||||||
|
balance: oldBalance,
|
||||||
|
conversionRate: oldConversionRate,
|
||||||
|
} = prevProps
|
||||||
|
const {
|
||||||
|
updateSendErrors,
|
||||||
|
balance,
|
||||||
|
conversionRate,
|
||||||
|
send: {
|
||||||
|
errors: {
|
||||||
|
simulationFails,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} = this.props
|
||||||
|
const txMeta = this.gatherTxMeta()
|
||||||
|
|
||||||
|
const shouldUpdateBalanceSendErrors = balance && [
|
||||||
|
balance !== oldBalance,
|
||||||
|
conversionRate !== oldConversionRate,
|
||||||
|
].some(x => Boolean(x))
|
||||||
|
|
||||||
|
if (shouldUpdateBalanceSendErrors) {
|
||||||
|
const balanceIsSufficient = this.isBalanceSufficient(txMeta)
|
||||||
|
updateSendErrors({
|
||||||
|
insufficientFunds: balanceIsSufficient ? false : this.context.t('insufficientFunds'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldUpdateSimulationSendError = Boolean(txMeta.simulationFails) !== Boolean(simulationFails)
|
||||||
|
|
||||||
|
if (shouldUpdateSimulationSendError) {
|
||||||
|
updateSendErrors({
|
||||||
|
simulationFails: !txMeta.simulationFails ? false : this.context.t('transactionError'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfirmSendEther.prototype.componentWillMount = function () {
|
||||||
|
this.updateComponentSendErrors({})
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfirmSendEther.prototype.componentDidUpdate = function (prevProps) {
|
||||||
|
this.updateComponentSendErrors(prevProps)
|
||||||
|
}
|
||||||
|
|
||||||
ConfirmSendEther.prototype.getAmount = function () {
|
ConfirmSendEther.prototype.getAmount = function () {
|
||||||
const { conversionRate, currentCurrency } = this.props
|
const { conversionRate, currentCurrency } = this.props
|
||||||
const txMeta = this.gatherTxMeta()
|
const txMeta = this.gatherTxMeta()
|
||||||
@ -234,7 +288,12 @@ ConfirmSendEther.prototype.render = function () {
|
|||||||
conversionRate,
|
conversionRate,
|
||||||
currentCurrency: convertedCurrency,
|
currentCurrency: convertedCurrency,
|
||||||
showCustomizeGasModal,
|
showCustomizeGasModal,
|
||||||
send: { gasTotal, gasLimit: sendGasLimit, gasPrice: sendGasPrice },
|
send: {
|
||||||
|
gasTotal,
|
||||||
|
gasLimit: sendGasLimit,
|
||||||
|
gasPrice: sendGasPrice,
|
||||||
|
errors,
|
||||||
|
},
|
||||||
} = this.props
|
} = this.props
|
||||||
const txMeta = this.gatherTxMeta()
|
const txMeta = this.gatherTxMeta()
|
||||||
const txParams = txMeta.txParams || {}
|
const txParams = txMeta.txParams || {}
|
||||||
@ -342,7 +401,12 @@ ConfirmSendEther.prototype.render = function () {
|
|||||||
]),
|
]),
|
||||||
|
|
||||||
h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [
|
h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [
|
||||||
h('div.confirm-screen-section-column', [
|
h('div', {
|
||||||
|
className: classnames({
|
||||||
|
'confirm-screen-section-column--with-error': errors['insufficientFunds'],
|
||||||
|
'confirm-screen-section-column': !errors['insufficientFunds'],
|
||||||
|
}),
|
||||||
|
}, [
|
||||||
h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]),
|
h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]),
|
||||||
h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]),
|
h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]),
|
||||||
]),
|
]),
|
||||||
@ -351,6 +415,8 @@ ConfirmSendEther.prototype.render = function () {
|
|||||||
h('div.confirm-screen-row-info', `${totalInFIAT} ${currentCurrency.toUpperCase()}`),
|
h('div.confirm-screen-row-info', `${totalInFIAT} ${currentCurrency.toUpperCase()}`),
|
||||||
h('div.confirm-screen-row-detail', `${totalInETH} ETH`),
|
h('div.confirm-screen-row-detail', `${totalInETH} ETH`),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
this.renderErrorMessage('insufficientFunds'),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
@ -436,8 +502,10 @@ ConfirmSendEther.prototype.render = function () {
|
|||||||
]),
|
]),
|
||||||
|
|
||||||
h('form#pending-tx-form', {
|
h('form#pending-tx-form', {
|
||||||
|
className: 'confirm-screen-form',
|
||||||
onSubmit: this.onSubmit,
|
onSubmit: this.onSubmit,
|
||||||
}, [
|
}, [
|
||||||
|
this.renderErrorMessage('simulationFails'),
|
||||||
h('.page-container__footer', [
|
h('.page-container__footer', [
|
||||||
// Cancel Button
|
// Cancel Button
|
||||||
h('button.btn-cancel.page-container__footer-button.allcaps', {
|
h('button.btn-cancel.page-container__footer-button.allcaps', {
|
||||||
@ -455,16 +523,28 @@ ConfirmSendEther.prototype.render = function () {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfirmSendEther.prototype.renderErrorMessage = function (message) {
|
||||||
|
const { send: { errors } } = this.props
|
||||||
|
|
||||||
|
return errors[message]
|
||||||
|
? h('div.confirm-screen-error', [ errors[message] ])
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
|
||||||
ConfirmSendEther.prototype.onSubmit = function (event) {
|
ConfirmSendEther.prototype.onSubmit = function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
const { updateSendErrors } = this.props
|
||||||
const txMeta = this.gatherTxMeta()
|
const txMeta = this.gatherTxMeta()
|
||||||
const valid = this.checkValidity()
|
const valid = this.checkValidity()
|
||||||
|
const balanceIsSufficient = this.isBalanceSufficient(txMeta)
|
||||||
this.setState({ valid, submitting: true })
|
this.setState({ valid, submitting: true })
|
||||||
|
|
||||||
if (valid && this.verifyGasParams()) {
|
if (valid && this.verifyGasParams() && balanceIsSufficient) {
|
||||||
this.props.sendTransaction(txMeta, event)
|
this.props.sendTransaction(txMeta, event)
|
||||||
|
} else if (!balanceIsSufficient) {
|
||||||
|
updateSendErrors({ insufficientFunds: this.context.t('insufficientFunds') })
|
||||||
} else {
|
} else {
|
||||||
this.props.dispatch(actions.displayWarning(this.context.t('invalidGasParams')))
|
updateSendErrors({ invalidGasParams: this.context.t('invalidGasParams') })
|
||||||
this.setState({ submitting: false })
|
this.setState({ submitting: false })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,6 +557,28 @@ ConfirmSendEther.prototype.cancel = function (event, txMeta) {
|
|||||||
.then(() => this.props.history.push(DEFAULT_ROUTE))
|
.then(() => this.props.history.push(DEFAULT_ROUTE))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfirmSendEther.prototype.isBalanceSufficient = function (txMeta) {
|
||||||
|
const {
|
||||||
|
balance,
|
||||||
|
conversionRate,
|
||||||
|
} = this.props
|
||||||
|
const {
|
||||||
|
txParams: {
|
||||||
|
gas,
|
||||||
|
gasPrice,
|
||||||
|
value: amount,
|
||||||
|
},
|
||||||
|
} = txMeta
|
||||||
|
const gasTotal = getGasTotal(gas, gasPrice)
|
||||||
|
|
||||||
|
return isBalanceSufficient({
|
||||||
|
amount,
|
||||||
|
gasTotal,
|
||||||
|
balance,
|
||||||
|
conversionRate,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
ConfirmSendEther.prototype.checkValidity = function () {
|
ConfirmSendEther.prototype.checkValidity = function () {
|
||||||
const form = this.getFormEl()
|
const form = this.getFormEl()
|
||||||
const valid = form.checkValidity()
|
const valid = form.checkValidity()
|
||||||
|
@ -19,9 +19,14 @@ const {
|
|||||||
multiplyCurrencies,
|
multiplyCurrencies,
|
||||||
addCurrencies,
|
addCurrencies,
|
||||||
} = require('../../conversion-util')
|
} = require('../../conversion-util')
|
||||||
|
const {
|
||||||
|
getGasTotal,
|
||||||
|
isBalanceSufficient,
|
||||||
|
} = require('../send/send-utils')
|
||||||
const {
|
const {
|
||||||
calcTokenAmount,
|
calcTokenAmount,
|
||||||
} = require('../../token-util')
|
} = require('../../token-util')
|
||||||
|
const classnames = require('classnames')
|
||||||
|
|
||||||
const { MIN_GAS_PRICE_HEX } = require('../send/send-constants')
|
const { MIN_GAS_PRICE_HEX } = require('../send/send-constants')
|
||||||
|
|
||||||
@ -52,9 +57,10 @@ function mapStateToProps (state, ownProps) {
|
|||||||
identities,
|
identities,
|
||||||
currentCurrency,
|
currentCurrency,
|
||||||
} = state.metamask
|
} = state.metamask
|
||||||
|
const accounts = state.metamask.accounts
|
||||||
const selectedAddress = getSelectedAddress(state)
|
const selectedAddress = getSelectedAddress(state)
|
||||||
const tokenExchangeRate = getTokenExchangeRate(state, symbol)
|
const tokenExchangeRate = getTokenExchangeRate(state, symbol)
|
||||||
|
const { balance } = accounts[selectedAddress]
|
||||||
return {
|
return {
|
||||||
conversionRate,
|
conversionRate,
|
||||||
identities,
|
identities,
|
||||||
@ -64,6 +70,7 @@ function mapStateToProps (state, ownProps) {
|
|||||||
currentCurrency: currentCurrency.toUpperCase(),
|
currentCurrency: currentCurrency.toUpperCase(),
|
||||||
send: state.metamask.send,
|
send: state.metamask.send,
|
||||||
tokenContract: getSelectedTokenContract(state),
|
tokenContract: getSelectedTokenContract(state),
|
||||||
|
balance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +142,7 @@ function mapDispatchToProps (dispatch, ownProps) {
|
|||||||
}))
|
}))
|
||||||
dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' }))
|
dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' }))
|
||||||
},
|
},
|
||||||
|
updateSendErrors: error => dispatch(actions.updateSendErrors(error)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +159,44 @@ ConfirmSendToken.prototype.editTransaction = function (txMeta) {
|
|||||||
history.push(SEND_ROUTE)
|
history.push(SEND_ROUTE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfirmSendToken.prototype.updateComponentSendErrors = function (prevProps) {
|
||||||
|
const {
|
||||||
|
balance: oldBalance,
|
||||||
|
conversionRate: oldConversionRate,
|
||||||
|
} = prevProps
|
||||||
|
const {
|
||||||
|
updateSendErrors,
|
||||||
|
balance,
|
||||||
|
conversionRate,
|
||||||
|
send: {
|
||||||
|
errors: {
|
||||||
|
simulationFails,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} = this.props
|
||||||
|
const txMeta = this.gatherTxMeta()
|
||||||
|
|
||||||
|
const shouldUpdateBalanceSendErrors = balance && [
|
||||||
|
balance !== oldBalance,
|
||||||
|
conversionRate !== oldConversionRate,
|
||||||
|
].some(x => Boolean(x))
|
||||||
|
|
||||||
|
if (shouldUpdateBalanceSendErrors) {
|
||||||
|
const balanceIsSufficient = this.isBalanceSufficient(txMeta)
|
||||||
|
updateSendErrors({
|
||||||
|
insufficientFunds: balanceIsSufficient ? false : this.context.t('insufficientFunds'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldUpdateSimulationSendError = Boolean(txMeta.simulationFails) !== Boolean(simulationFails)
|
||||||
|
|
||||||
|
if (shouldUpdateSimulationSendError) {
|
||||||
|
updateSendErrors({
|
||||||
|
simulationFails: !txMeta.simulationFails ? false : this.context.t('transactionError'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ConfirmSendToken.prototype.componentWillMount = function () {
|
ConfirmSendToken.prototype.componentWillMount = function () {
|
||||||
const { tokenContract, selectedAddress } = this.props
|
const { tokenContract, selectedAddress } = this.props
|
||||||
tokenContract && tokenContract
|
tokenContract && tokenContract
|
||||||
@ -158,6 +204,11 @@ ConfirmSendToken.prototype.componentWillMount = function () {
|
|||||||
.then(usersToken => {
|
.then(usersToken => {
|
||||||
})
|
})
|
||||||
this.props.updateTokenExchangeRate()
|
this.props.updateTokenExchangeRate()
|
||||||
|
this.updateComponentSendErrors({})
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfirmSendToken.prototype.componentDidUpdate = function (prevProps) {
|
||||||
|
this.updateComponentSendErrors(prevProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfirmSendToken.prototype.getAmount = function () {
|
ConfirmSendToken.prototype.getAmount = function () {
|
||||||
@ -318,7 +369,7 @@ ConfirmSendToken.prototype.renderGasFee = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConfirmSendToken.prototype.renderTotalPlusGas = function () {
|
ConfirmSendToken.prototype.renderTotalPlusGas = function () {
|
||||||
const { token: { symbol }, currentCurrency } = this.props
|
const { token: { symbol }, currentCurrency, send: { errors } } = this.props
|
||||||
const { fiat: fiatAmount, token: tokenAmount } = this.getAmount()
|
const { fiat: fiatAmount, token: tokenAmount } = this.getAmount()
|
||||||
const { fiat: fiatGas, token: tokenGas } = this.getGasFee()
|
const { fiat: fiatGas, token: tokenGas } = this.getGasFee()
|
||||||
|
|
||||||
@ -338,7 +389,12 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () {
|
|||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [
|
h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [
|
||||||
h('div.confirm-screen-section-column', [
|
h('div', {
|
||||||
|
className: classnames({
|
||||||
|
'confirm-screen-section-column--with-error': errors['insufficientFunds'],
|
||||||
|
'confirm-screen-section-column': !errors['insufficientFunds'],
|
||||||
|
}),
|
||||||
|
}, [
|
||||||
h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]),
|
h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]),
|
||||||
h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]),
|
h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]),
|
||||||
]),
|
]),
|
||||||
@ -347,12 +403,21 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () {
|
|||||||
h('div.confirm-screen-row-info', `${tokenAmount} ${symbol}`),
|
h('div.confirm-screen-row-info', `${tokenAmount} ${symbol}`),
|
||||||
h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} ${this.context.t('gas')}`),
|
h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} ${this.context.t('gas')}`),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
this.renderErrorMessage('insufficientFunds'),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfirmSendToken.prototype.renderErrorMessage = function (message) {
|
||||||
|
const { send: { errors } } = this.props
|
||||||
|
|
||||||
|
return errors[message]
|
||||||
|
? h('div.confirm-screen-error', [ errors[message] ])
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
|
||||||
ConfirmSendToken.prototype.render = function () {
|
ConfirmSendToken.prototype.render = function () {
|
||||||
const { editTransaction } = this.props
|
|
||||||
const txMeta = this.gatherTxMeta()
|
const txMeta = this.gatherTxMeta()
|
||||||
const {
|
const {
|
||||||
from: {
|
from: {
|
||||||
@ -379,7 +444,7 @@ ConfirmSendToken.prototype.render = function () {
|
|||||||
h('div.page-container', [
|
h('div.page-container', [
|
||||||
h('div.page-container__header', [
|
h('div.page-container__header', [
|
||||||
!txMeta.lastGasPrice && h('button.confirm-screen-back-button', {
|
!txMeta.lastGasPrice && h('button.confirm-screen-back-button', {
|
||||||
onClick: () => editTransaction(txMeta),
|
onClick: () => this.editTransaction(txMeta),
|
||||||
}, this.context.t('edit')),
|
}, this.context.t('edit')),
|
||||||
h('div.page-container__title', title),
|
h('div.page-container__title', title),
|
||||||
h('div.page-container__subtitle', subtitle),
|
h('div.page-container__subtitle', subtitle),
|
||||||
@ -448,8 +513,10 @@ ConfirmSendToken.prototype.render = function () {
|
|||||||
]),
|
]),
|
||||||
|
|
||||||
h('form#pending-tx-form', {
|
h('form#pending-tx-form', {
|
||||||
|
className: 'confirm-screen-form',
|
||||||
onSubmit: this.onSubmit,
|
onSubmit: this.onSubmit,
|
||||||
}, [
|
}, [
|
||||||
|
this.renderErrorMessage('simulationFails'),
|
||||||
h('.page-container__footer', [
|
h('.page-container__footer', [
|
||||||
// Cancel Button
|
// Cancel Button
|
||||||
h('button.btn-cancel.page-container__footer-button.allcaps', {
|
h('button.btn-cancel.page-container__footer-button.allcaps', {
|
||||||
@ -467,18 +534,44 @@ ConfirmSendToken.prototype.render = function () {
|
|||||||
|
|
||||||
ConfirmSendToken.prototype.onSubmit = function (event) {
|
ConfirmSendToken.prototype.onSubmit = function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
const { updateSendErrors } = this.props
|
||||||
const txMeta = this.gatherTxMeta()
|
const txMeta = this.gatherTxMeta()
|
||||||
const valid = this.checkValidity()
|
const valid = this.checkValidity()
|
||||||
|
const balanceIsSufficient = this.isBalanceSufficient(txMeta)
|
||||||
this.setState({ valid, submitting: true })
|
this.setState({ valid, submitting: true })
|
||||||
|
|
||||||
if (valid && this.verifyGasParams()) {
|
if (valid && this.verifyGasParams() && balanceIsSufficient) {
|
||||||
this.props.sendTransaction(txMeta, event)
|
this.props.sendTransaction(txMeta, event)
|
||||||
|
} else if (!balanceIsSufficient) {
|
||||||
|
updateSendErrors({ insufficientFunds: this.context.t('insufficientFunds') })
|
||||||
} else {
|
} else {
|
||||||
this.props.dispatch(actions.displayWarning(this.context.t('invalidGasParams')))
|
updateSendErrors({ invalidGasParams: this.context.t('invalidGasParams') })
|
||||||
this.setState({ submitting: false })
|
this.setState({ submitting: false })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfirmSendToken.prototype.isBalanceSufficient = function (txMeta) {
|
||||||
|
const {
|
||||||
|
balance,
|
||||||
|
conversionRate,
|
||||||
|
} = this.props
|
||||||
|
const {
|
||||||
|
txParams: {
|
||||||
|
gas,
|
||||||
|
gasPrice,
|
||||||
|
},
|
||||||
|
} = txMeta
|
||||||
|
const gasTotal = getGasTotal(gas, gasPrice)
|
||||||
|
|
||||||
|
return isBalanceSufficient({
|
||||||
|
amount: '0',
|
||||||
|
gasTotal,
|
||||||
|
balance,
|
||||||
|
conversionRate,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ConfirmSendToken.prototype.cancel = function (event, txMeta) {
|
ConfirmSendToken.prototype.cancel = function (event, txMeta) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const { cancelTransaction } = this.props
|
const { cancelTransaction } = this.props
|
||||||
|
@ -2,6 +2,7 @@ const {
|
|||||||
addCurrencies,
|
addCurrencies,
|
||||||
conversionUtil,
|
conversionUtil,
|
||||||
conversionGTE,
|
conversionGTE,
|
||||||
|
multiplyCurrencies,
|
||||||
} = require('../../conversion-util')
|
} = require('../../conversion-util')
|
||||||
const {
|
const {
|
||||||
calcTokenAmount,
|
calcTokenAmount,
|
||||||
@ -31,7 +32,7 @@ function isBalanceSufficient ({
|
|||||||
{
|
{
|
||||||
value: totalAmount,
|
value: totalAmount,
|
||||||
fromNumericBase: 'hex',
|
fromNumericBase: 'hex',
|
||||||
conversionRate: amountConversionRate,
|
conversionRate: amountConversionRate || conversionRate,
|
||||||
fromCurrency: primaryCurrency,
|
fromCurrency: primaryCurrency,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -62,7 +63,16 @@ function isTokenBalanceSufficient ({
|
|||||||
return tokenBalanceIsSufficient
|
return tokenBalanceIsSufficient
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getGasTotal (gasLimit, gasPrice) {
|
||||||
|
return multiplyCurrencies(gasLimit, gasPrice, {
|
||||||
|
toNumericBase: 'hex',
|
||||||
|
multiplicandBase: 16,
|
||||||
|
multiplierBase: 16,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
getGasTotal,
|
||||||
isBalanceSufficient,
|
isBalanceSufficient,
|
||||||
isTokenBalanceSufficient,
|
isTokenBalanceSufficient,
|
||||||
}
|
}
|
||||||
|
@ -68,20 +68,24 @@ TxListItem.prototype.getAddressText = function () {
|
|||||||
const {
|
const {
|
||||||
address,
|
address,
|
||||||
txParams = {},
|
txParams = {},
|
||||||
|
isMsg,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data)
|
const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data)
|
||||||
const { name: txDataName, params = [] } = decodedData || {}
|
const { name: txDataName, params = [] } = decodedData || {}
|
||||||
const { value } = params[0] || {}
|
const { value } = params[0] || {}
|
||||||
|
|
||||||
switch (txDataName) {
|
let addressText
|
||||||
case 'transfer':
|
if (txDataName === 'transfer' || address) {
|
||||||
return `${value.slice(0, 10)}...${value.slice(-4)}`
|
const addressToRender = txDataName === 'transfer' ? value : address
|
||||||
default:
|
addressText = `${addressToRender.slice(0, 10)}...${addressToRender.slice(-4)}`
|
||||||
return address
|
} else if (isMsg) {
|
||||||
? `${address.slice(0, 10)}...${address.slice(-4)}`
|
addressText = this.context.t('sigRequest')
|
||||||
: this.context.t('contractDeployment')
|
} else {
|
||||||
|
addressText = this.context.t('contractDeployment')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return addressText
|
||||||
}
|
}
|
||||||
|
|
||||||
TxListItem.prototype.getSendEtherTotal = function () {
|
TxListItem.prototype.getSendEtherTotal = function () {
|
||||||
@ -191,6 +195,9 @@ TxListItem.prototype.showRetryButton = function () {
|
|||||||
transactionId,
|
transactionId,
|
||||||
txParams,
|
txParams,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
if (!txParams) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
const currentNonce = txParams.nonce
|
const currentNonce = txParams.nonce
|
||||||
const currentNonceTxs = selectedAddressTxList.filter(tx => tx.txParams.nonce === currentNonce)
|
const currentNonceTxs = selectedAddressTxList.filter(tx => tx.txParams.nonce === currentNonce)
|
||||||
const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted')
|
const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted')
|
||||||
|
@ -82,9 +82,9 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa
|
|||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
dateString: formatDate(transaction.time),
|
dateString: formatDate(transaction.time),
|
||||||
address: transaction.txParams.to,
|
address: transaction.txParams && transaction.txParams.to,
|
||||||
transactionStatus: transaction.status,
|
transactionStatus: transaction.status,
|
||||||
transactionAmount: transaction.txParams.value,
|
transactionAmount: transaction.txParams && transaction.txParams.value,
|
||||||
transactionId: transaction.id,
|
transactionId: transaction.id,
|
||||||
transactionHash: transaction.hash,
|
transactionHash: transaction.hash,
|
||||||
transactionNetworkId: transaction.metamaskNetworkId,
|
transactionNetworkId: transaction.metamaskNetworkId,
|
||||||
@ -106,6 +106,7 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa
|
|||||||
const opts = {
|
const opts = {
|
||||||
key: transactionId || transactionHash,
|
key: transactionId || transactionHash,
|
||||||
txParams: transaction.txParams,
|
txParams: transaction.txParams,
|
||||||
|
isMsg: Boolean(transaction.msgParams),
|
||||||
transactionStatus,
|
transactionStatus,
|
||||||
transactionId,
|
transactionId,
|
||||||
dateString,
|
dateString,
|
||||||
|
@ -55,11 +55,25 @@ function ConfirmTxScreen () {
|
|||||||
Component.call(this)
|
Component.call(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfirmTxScreen.prototype.componentDidMount = function () {
|
||||||
|
const {
|
||||||
|
unapprovedTxs = {},
|
||||||
|
network,
|
||||||
|
send,
|
||||||
|
} = this.props
|
||||||
|
const unconfTxList = txHelper(unapprovedTxs, {}, {}, {}, network)
|
||||||
|
|
||||||
|
if (unconfTxList.length === 0 && !send.to) {
|
||||||
|
this.props.history.push(DEFAULT_ROUTE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.componentDidUpdate = function (prevProps) {
|
ConfirmTxScreen.prototype.componentDidUpdate = function (prevProps) {
|
||||||
const {
|
const {
|
||||||
unapprovedTxs,
|
unapprovedTxs = {},
|
||||||
network,
|
network,
|
||||||
selectedAddressTxList,
|
selectedAddressTxList,
|
||||||
|
send,
|
||||||
} = this.props
|
} = this.props
|
||||||
const { index: prevIndex, unapprovedTxs: prevUnapprovedTxs } = prevProps
|
const { index: prevIndex, unapprovedTxs: prevUnapprovedTxs } = prevProps
|
||||||
const prevUnconfTxList = txHelper(prevUnapprovedTxs, {}, {}, {}, network)
|
const prevUnconfTxList = txHelper(prevUnapprovedTxs, {}, {}, {}, network)
|
||||||
@ -67,7 +81,7 @@ ConfirmTxScreen.prototype.componentDidUpdate = function (prevProps) {
|
|||||||
const prevTx = selectedAddressTxList.find(({ id }) => id === prevTxData.id) || {}
|
const prevTx = selectedAddressTxList.find(({ id }) => id === prevTxData.id) || {}
|
||||||
const unconfTxList = txHelper(unapprovedTxs, {}, {}, {}, network)
|
const unconfTxList = txHelper(unapprovedTxs, {}, {}, {}, network)
|
||||||
|
|
||||||
if (prevTx.status === 'dropped' && unconfTxList.length === 0) {
|
if (unconfTxList.length === 0 && (prevTx.status === 'dropped' || !send.to)) {
|
||||||
this.props.history.push(DEFAULT_ROUTE)
|
this.props.history.push(DEFAULT_ROUTE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,13 +123,6 @@ ConfirmTxScreen.prototype.render = function () {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`)
|
log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`)
|
||||||
if (unconfTxList.length === 0) {
|
|
||||||
return h(Redirect, {
|
|
||||||
to: {
|
|
||||||
pathname: DEFAULT_ROUTE,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentTxView({
|
return currentTxView({
|
||||||
// Properties
|
// Properties
|
||||||
|
@ -266,6 +266,7 @@ section .confirm-screen-account-number,
|
|||||||
|
|
||||||
.confirm-screen-total-box {
|
.confirm-screen-total-box {
|
||||||
background-color: $wild-sand;
|
background-color: $wild-sand;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
.confirm-screen-label {
|
.confirm-screen-label {
|
||||||
line-height: 21px;
|
line-height: 21px;
|
||||||
@ -287,6 +288,41 @@ section .confirm-screen-account-number,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.confirm-screen-error {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 12px;
|
||||||
|
color: #f00;
|
||||||
|
position: absolute;
|
||||||
|
right: 12px;
|
||||||
|
width: 80px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-screen-row.confirm-screen-total-box {
|
||||||
|
.confirm-screen-section-column--with-error {
|
||||||
|
flex: 0.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 379px) {
|
||||||
|
.confirm-screen-row.confirm-screen-total-box {
|
||||||
|
.confirm-screen-section-column--with-error {
|
||||||
|
flex: 0.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-screen-form {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.confirm-screen-error {
|
||||||
|
right: 0;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 7px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.confirm-screen-confirm-button {
|
.confirm-screen-confirm-button {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
@ -27,6 +27,7 @@ const {
|
|||||||
const {
|
const {
|
||||||
isBalanceSufficient,
|
isBalanceSufficient,
|
||||||
isTokenBalanceSufficient,
|
isTokenBalanceSufficient,
|
||||||
|
getGasTotal,
|
||||||
} = require('./components/send/send-utils')
|
} = require('./components/send/send-utils')
|
||||||
const { isValidAddress } = require('./util')
|
const { isValidAddress } = require('./util')
|
||||||
const { CONFIRM_TRANSACTION_ROUTE, DEFAULT_ROUTE } = require('./routes')
|
const { CONFIRM_TRANSACTION_ROUTE, DEFAULT_ROUTE } = require('./routes')
|
||||||
@ -133,7 +134,7 @@ SendTransactionScreen.prototype.updateGas = function () {
|
|||||||
estimateGas(estimateGasParams),
|
estimateGas(estimateGasParams),
|
||||||
])
|
])
|
||||||
.then(([gasPrice, gas]) => {
|
.then(([gasPrice, gas]) => {
|
||||||
const newGasTotal = this.getGasTotal(gas, gasPrice)
|
const newGasTotal = getGasTotal(gas, gasPrice)
|
||||||
updateGasTotal(newGasTotal)
|
updateGasTotal(newGasTotal)
|
||||||
this.setState({ gasLoadingError: false })
|
this.setState({ gasLoadingError: false })
|
||||||
})
|
})
|
||||||
@ -141,19 +142,11 @@ SendTransactionScreen.prototype.updateGas = function () {
|
|||||||
this.setState({ gasLoadingError: true })
|
this.setState({ gasLoadingError: true })
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
const newGasTotal = this.getGasTotal(gasLimit, gasPrice)
|
const newGasTotal = getGasTotal(gasLimit, gasPrice)
|
||||||
updateGasTotal(newGasTotal)
|
updateGasTotal(newGasTotal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SendTransactionScreen.prototype.getGasTotal = function (gasLimit, gasPrice) {
|
|
||||||
return multiplyCurrencies(gasLimit, gasPrice, {
|
|
||||||
toNumericBase: 'hex',
|
|
||||||
multiplicandBase: 16,
|
|
||||||
multiplierBase: 16,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) {
|
SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) {
|
||||||
const {
|
const {
|
||||||
from: { balance },
|
from: { balance },
|
||||||
@ -642,6 +635,10 @@ SendTransactionScreen.prototype.onSubmit = function (event) {
|
|||||||
txParams.to = to
|
txParams.to = to
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object.keys(txParams).forEach(key => {
|
||||||
|
txParams[key] = ethUtil.addHexPrefix(txParams[key])
|
||||||
|
})
|
||||||
|
|
||||||
selectedToken
|
selectedToken
|
||||||
? signTokenTx(selectedToken.address, to, amount, txParams)
|
? signTokenTx(selectedToken.address, to, amount, txParams)
|
||||||
: signTx(txParams)
|
: signTx(txParams)
|
||||||
|
10
ui/index.js
10
ui/index.js
@ -69,6 +69,16 @@ async function startApp (metamaskState, accountManager, opts) {
|
|||||||
store.dispatch(actions.updateMetamaskState(metamaskState))
|
store.dispatch(actions.updateMetamaskState(metamaskState))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// global metamask api - used by tooling
|
||||||
|
global.metamask = {
|
||||||
|
updateCurrentLocale: (code) => {
|
||||||
|
store.dispatch(actions.updateCurrentLocale(code))
|
||||||
|
},
|
||||||
|
setProviderType: (type) => {
|
||||||
|
store.dispatch(actions.setProviderType(type))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// start app
|
// start app
|
||||||
render(
|
render(
|
||||||
h(Root, {
|
h(Root, {
|
||||||
|
Loading…
Reference in New Issue
Block a user