diff options
66 files changed, 1809 insertions, 1692 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index 00ba9ffa2..60867e181 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -324,7 +324,7 @@ jobs: command: > git config user.name metamaskbot && git config user.email admin@metamask.io && - gh-pages -d docs/jsdocs + npm run publish-docs test-unit: docker: diff --git a/CHANGELOG.md b/CHANGELOG.md index e09cd47dd..37d9f26b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## Current Develop Branch - [#5283](https://github.com/MetaMask/metamask-extension/pull/5283): Fix bug when eth.getCode() called with no contract +- [#5563](https://github.com/MetaMask/metamask-extension/pull/5563#pullrequestreview-166769174) Feature: improve Hatian Creole translations +- [#5559](https://github.com/MetaMask/metamask-extension/pull/5559) Localize language names in translation select list ## 4.16.0 Wednesday October 17 2018 diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index e2fb3fc13..aea66845f 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -1169,6 +1169,9 @@ "transactionUpdatedGas": { "message": "Transaction updated with a gas price of $1 on $2." }, + "transactionErrored": { + "message": "Transaction encountered an error." + }, "transactions": { "message": "transactions" }, diff --git a/app/_locales/ht/messages.json b/app/_locales/ht/messages.json index 50a0ec2bb..81ce18018 100644 --- a/app/_locales/ht/messages.json +++ b/app/_locales/ht/messages.json @@ -1,1237 +1,1312 @@ { - "accept": { - "message": "Aksepte" - }, - "accessingYourCamera": { - "message": "Aksè a Kamera" - }, - "account": { - "message": "Kont" - }, - "accountDetails": { - "message": "Detay Kont" - }, - "accountName": { - "message": "Non Kont" - }, - "accountSelectionRequired": { - "message": "Ou bezwen chwazi yon kont!" - }, - "activityLog": { - "message": "aktivite ki fèt" - }, - "address": { - "message": "Adrès" - }, - "addCustomToken": { - "message": "Ajoute token" - }, - "addToken": { - "message": "Ajoute Token" - }, - "addTokens": { - "message": "Ajoute Token" - }, - "addSuggestedTokens": { - "message": "Ajoute Token Yo Sikjere W" - }, - "addAcquiredTokens": { - "message": "Ajoute tokens yo ou te achte lè l sèvi avèk MetaMask" - }, - "amount": { - "message": "Kantite lajan" - }, - "amountPlusGas": { - "message": "Kantite lajan + Gaz" - }, - "appDescription": { - "message": "Ethereum Ekstansyon Navigatè", - "description": "The description of the application" - }, - "appName": { - "message": "MetaMask", - "description": "The name of the application" - }, - "approve": { - "message": "Apwouve" - }, - "approved": { - "message": "Apwouve" - }, - "attemptingConnect": { - "message": "Eseye konekte nan blockchain." - }, - "attributions": { - "message": "Atribisyon" - }, - "available": { - "message": "Disponib" - }, - "back": { - "message": "Retounen" - }, - "balance": { - "message": "Balans" - }, - "balances": { - "message": "Balans Token" - }, - "balanceIsInsufficientGas": { - "message": "Ensifizan balans pou total gaz aktyèl la" - }, - "beta": { - "message": "BETA" - }, - "betweenMinAndMax": { - "message": "dwe plis pase oswa egal a $ 1 mwens ke oswa egal a $ 2.", - "description": "helper for inputting hex as decimal input" - }, - "blockiesIdenticon": { - "message": "Itilize Blockies Identicon" - }, - "borrowDharma": { - "message": "Prete Avèk Dharma (Beta)" - }, - "browserNotSupported": { - "message": "Navigatè ou a pa sipòte..." - }, - "builtInCalifornia": { - "message": "MetaMask fèt e bati nan California." - }, - "buy": { - "message": "Achte" - }, - "buyCoinbase": { - "message": "Achte sou Coinbase" - }, - "buyCoinbaseExplainer": { - "message": "Coinbase se fason ki pi popilè nan mond lan yo achte ak vann Bitcoin, Ethereum, ak Litecoin." - }, - "bytes": { - "message": "Bytes" - }, - "ok": { - "message": "Oke" - }, - "cancel": { - "message": "Anile" - }, - "classicInterface": { - "message": "Sèvi ak fas klasik la" - }, - "clickCopy": { - "message": "Klike sou kopi" - }, - "close": { - "message": "Fèmen" - }, - "chromeRequiredForHardwareWallets": { - "message": "Ou bezwen sèvi ak MetaMask sou Google Chrome yo nan lòd yo konekte sou Hardware Wallet." - }, - "confirm": { - "message": "Konfime" - }, - "confirmed": { - "message": "Konfime" - }, - "confirmContract": { - "message": "Konfime Kontra" - }, - "confirmPassword": { - "message": "Konfime Modpas" - }, - "confirmTransaction": { - "message": "Konfime Tranzaksyon" - }, - "connectHardwareWallet": { - "message": "Konekte Hardware Wallet" - }, - "connect": { - "message": "Konekte" - }, - "connecting": { - "message": "Koneksyon..." - }, - "connectToLedger": { - "message": "Konekte ak Ledger" - }, - "connectToTrezor": { - "message": "Konekte ak Trezor" - }, - "continue": { - "message": "Kontinye" - }, - "continueToCoinbase": { - "message": "Kontinye Coinbase" - }, - "contractDeployment": { - "message": "Kontra Deplwaman" - }, - "conversionProgress": { - "message": "Konvèsyon nan Pwogrè" - }, - "copiedButton": { - "message": "Kopye" - }, - "copiedClipboard": { - "message": "Kopi nan Clipboard" - }, - "copiedExclamation": { - "message": "Kopye!" - }, - "copiedSafe": { - "message": "Mwen te kopye li yon kote ki san danje" - }, - "copy": { - "message": "Kopye" - }, - "copyAddress": { - "message": "Kopi adrès clipboard" - }, - "copyToClipboard": { - "message": "Kopi clipboard" - }, - "copyButton": { - "message": " Kopi " - }, - "copyPrivateKey": { - "message": "Sa a se kle prive ou (klike pou ou kopye)" - }, - "create": { - "message": "Kreye" - }, - "createAccount": { - "message": "Kreye Kont" - }, - "createDen": { - "message": "Kreye" - }, - "crypto": { - "message": "Crypto", - "description": "Change tip (cryptocurrencies)" - }, - "currentConversion": { - "message": "Konvèsyon aktyèl" - }, - "currentNetwork": { - "message": "Rezo aktyèl" - }, - "customGas": { - "message": "Koutim Gaz" - }, - "customToken": { - "message": "Koutim Token" - }, - "customize": { - "message": "Koutim" - }, - "customRPC": { - "message": "Koutim RPC" - }, - "decimalsMustZerotoTen": { - "message": "Desimal yo dwe omwen 0, epi pa dwe plis pase 36." - }, - "decimal": { - "message": "Presizyon desimal la" - }, - "defaultNetwork": { - "message": "Dfo rezo a pou tranzaksyon Ether se Mainnet." - }, - "denExplainer": { - "message": "DEN ou se depo modpas avèk chif ou nan MetaMask." - }, - "deposit": { - "message": "Depo" - }, - "depositBTC": { - "message": "Depoze BTC ou nan adrès ki anba a:" - }, - "depositCoin": { - "message": "Depoze $1 ou nan adrès ki anba a", - "description": "Tells the user what coin they have selected to deposit with shapeshift" - }, - "depositEth": { - "message": "Depo Eth" - }, - "depositEther": { - "message": "Depo Ether" - }, - "depositFiat": { - "message": "Depo ak Fiat" - }, - "depositFromAccount": { - "message": "Depo nan yon lòt kont" - }, - "depositShapeShift": { - "message": "Depo avèk ShapeShift" - }, - "depositShapeShiftExplainer": { - "message": "Si ou posede lòt cryptocurrencies, ou ka chanje ak depo Ether dirèkteman nan Wallet MetaMask ou. Pa gen kont ki nesesè." - }, - "details": { - "message": "Detay yo" - }, - "directDeposit": { - "message": "Depo Dirèk" - }, - "directDepositEther": { - "message": "Dirèkteman Depo Ether" - }, - "directDepositEtherExplainer": { - "message": "Si ou deja gen kèk Ether, fason ki pi rapid yo ka resevwa Ether nan nouvo Wallet ou pa depo dirèk." - }, - "done": { - "message": "Fini" - }, - "downloadGoogleChrome": { - "message": "Telechaje Google Chrome" - }, - "downloadStateLogs": { - "message": "Telechaje State Logs" - }, - "dontHaveAHardwareWallet": { - "message": "Pa gen yon materyèl bous?" - }, - "dropped": { - "message": "Tonbe" - }, - "edit": { - "message": "Korije" - }, - "editAccountName": { - "message": "Korije Non Kont" - }, - "editingTransaction": { - "message": "Fè chanjman nan tranzaksyon ou" - }, - "emailUs": { - "message": "Imèl nou!" - }, - "encryptNewDen": { - "message": "Ankripte nouvo DEN ou" - }, - "ensNameNotFound": { - "message": "Nou pa jwenn non ENS ou a" - }, - "enterPassword": { - "message": "Mete modpas" - }, - "enterPasswordConfirm": { - "message": "Antre nan modpas ou a konfime" - }, - "enterPasswordContinue": { - "message": "Mete modpas pou kontinye" - }, - "parameters": { - "message": "Paramèt" - }, - "passwordNotLongEnough": { - "message": "Modpas la pa ase" - }, - "passwordsDontMatch": { - "message": "Modpas Pa Koresponn ak" - }, - "etherscanView": { - "message": "Gade kont sou Etherscan" - }, - "exchangeRate": { - "message": "Chanje to" - }, - "exportPrivateKey": { - "message": "Voye Kòd Prive" - }, - "exportPrivateKeyWarning": { - "message": "Voye kle prive ak pwòp risk ou." - }, - "failed": { - "message": "Tonbe" - }, - "fiat": { - "message": "FIAT", - "description": "Exchange type" - }, - "fileImportFail": { - "message": "Enpòte dosye ki pa travay? Klike la a!", - "description": "Helps user import their account from a JSON file" - }, - "followTwitter": { - "message": "Swiv nou sou Twitter" - }, - "forgetDevice": { - "message": "Bliye aparèy sa a" - }, - "from": { - "message": "Soti nan" - }, - "fromToSame": { - "message": "Adrès orijinal le ak sa ou resevwa pake menm" - }, - "fromShapeShift": { - "message": "Soti nan ShapeShift" - }, - "functionType": { - "message": "Kalite Fonksyon" - }, - "gas": { - "message": "Gaz", - "description": "Short indication of gas cost" - }, - "gasFee": { - "message": "Frè gaz" - }, - "gasLimit": { - "message": "Limit gaz" - }, - "gasLimitCalculation": { - "message": "Nou kalkile gaz limit sijere a ki baze sou pousantaj siksè rezo a." - }, - "gasLimitRequired": { - "message": "Limit gaz nesesè" - }, - "gasLimitTooLow": { - "message": "Limit gaz dwe omwen 21000" - }, - "generatingSeed": { - "message": "Génération Seed..." - }, - "gasPrice": { - "message": "Pri gaz (GWEI)" - }, - "gasPriceCalculation": { - "message": "Nou kalkile pri yo gaz ki sijere ki baze sou pousantaj siksè rezo." - }, - "gasPriceRequired": { - "message": "Pri Gaz la Egzije" - }, - "generatingTransaction": { - "message": "Tranzaksyon kap fè" - }, - "getEther": { - "message": "Jwenn Ether" - }, - "getEtherFromFaucet": { - "message": "Jwenn Ether nan yon tiyo pou $1 la", - "description": "Displays network name for Ether faucet" - }, - "getHelp": { - "message": "Jwenn èd." - }, - "greaterThanMin": { - "message": "dwe pi gran pase oswa egal a $ 1.", - "description": "helper for inputting hex as decimal input" - }, - "hardware": { - "message": "hardware" - }, - "hardwareWalletConnected": { - "message": "Hardware Wallet konekte" - }, - "hardwareWallets": { - "message": "Hardware Wallet konekte" - }, - "hardwareWalletsMsg": { - "message": "Chwazi yon Hardware Wallet ou ta renmen itilize ak MetaMask" - }, - "havingTroubleConnecting": { - "message": "Èske w gen pwoblèm pou konekte?" - }, - "here": { - "message": "isit la", - "description": "as in -click here- for more information (goes with troubleTokenBalances)" - }, - "hereList": { - "message": "Isit la nan yon lis !!!!" - }, - "hexData": { - "message": "Hex Data" - }, - "hide": { - "message": "Kache" - }, - "hideToken": { - "message": "Kache Token" - }, - "hideTokenPrompt": { - "message": "Kache Token?" - }, - "history": { - "message": "Istwa" - }, - "howToDeposit": { - "message": "Ki jan ou ta renmen depo Ether?" - }, - "holdEther": { - "message": "Li pèmèt ou kenbe ether & tokens, epi sèvi kòm on pon pou desantralize aplikasyon." - }, - "import": { - "message": "Pòte", - "description": "Button to import an account from a selected file" - }, - "importAccount": { - "message": "Pòte Kont" - }, - "importAccountMsg": { - "message": " Kont pòte pa pral asosye avèk orijinal ou te kreye nan kont MetaMask seed fraz. Aprann plis sou kont enpòte " - }, - "importAnAccount": { - "message": "Pòte yon kont" - }, - "importDen": { - "message": "Pòte ki deja egziste DEN" - }, - "imported": { - "message": "Pòte", - "description": "status showing that an account has been fully loaded into the keyring" - }, - "importUsingSeed": { - "message": "Pòte lè sèvi avèk seed fraz" - }, - "infoHelp": { - "message": "Enfo & Èd" - }, - "initialTransactionConfirmed": { - "message": "Premye tranzaksyon ou konfime sou rezo a. Klike sou OK pou tounen." - }, - "insufficientFunds": { - "message": "Lajan ensifizan." - }, - "insufficientTokens": { - "message": "Tokens pa valab." - }, - "invalidAddress": { - "message": "Adrès pa valab" - }, - "invalidAddressRecipient": { - "message": "Moun ki resevwa adrès la pa valab" - }, - "invalidGasParams": { - "message": "Gaz Paramèt la pa valab" - }, - "invalidInput": { - "message": "Sa ou rantre a pa valab" - }, - "invalidRequest": { - "message": "Demann pa valab" - }, - "invalidRPC": { - "message": "RPC URI pa valab" - }, - "invalidSeedPhrase": { - "message": "Seed fraz pa valab" - }, - "jsonFail": { - "message": "Yon bagay ale mal. Tanpri, asire w ke dosye JSON ou an byen fòmate." - }, - "jsonFile": { - "message": "JSON Dosye", - "description": "format for importing an account" - }, - "keepTrackTokens": { - "message": "Gade tokens yo ou te achte ak kont MetaMask ou." - }, - "kovan": { - "message": "Kovan Tès Rezo" - }, - "knowledgeDataBase": { - "message": "Vizite baz nou an" - }, - "max": { - "message": "Maksimòm" - }, - "learnMore": { - "message": "Aprann plis" - }, - "ledgerAccountRestriction": { - "message": "Ou bezwen sèvi ak dènye kont ou anvan ou ka ajoute yon nouvo." - }, - "lessThanMax": { - "message": "dwe mwens pase oswa egal a $ 1.", - "description": "helper for inputting hex as decimal input" - }, - "likeToAddTokens": { - "message": "Èske ou ta renmen ajoute sa nan tokens?" - }, - "links": { - "message": "Lyen" - }, - "limit": { - "message": "Limitasyon" - }, - "loading": { - "message": "Telechaje..." - }, - "loadingTokens": { - "message": "Telechaje Tokens..." - }, - "localhost": { - "message": "Localhost 8545" - }, - "login": { - "message": "Ouvri" - }, - "logout": { - "message": "Dekonekte" - }, - "loose": { - "message": "Pèdi" - }, - "loweCaseWords": { - "message": "seed mo sèlman gen karaktè miniskil" - }, - "mainnet": { - "message": "Main Ethereum Network" - }, - "menu": { - "message": "Opsyon" - }, - "message": { - "message": "Mesaje" - }, - "metamaskDescription": { - "message": "MetaMask sekirize idantite pou Ethereum." - }, - "metamaskSeedWords": { - "message": "MetaMask Seed Mo" - }, - "min": { - "message": "Minimòm" - }, - "myAccounts": { - "message": "Kont mwen" - }, - "mustSelectOne": { - "message": "Ou dwe chwazi omwen 1 token." - }, - "needEtherInWallet": { - "message": "Pou kominike avèk aplikasyon desantralize ou dwe itilize MetaMask, ou pral bezwen Ether nan Wallet ou." - }, - "needImportFile": { - "message": "Ou dwe chwazi yon dosye pou enpòte.", - "description": "User is important an account and needs to add a file to continue" - }, - "needImportPassword": { - "message": "Ou dwe antre nan yon modpas pou dosye ou te chwazi a.", - "description": "Password and file needed to import an account" - }, - "negativeETH": { - "message": "Pa ka voye kantite lajan negatif ETH." - }, - "networks": { - "message": "Rezo" - }, - "nevermind": { - "message": "Pa pwoblèm" - }, - "newAccount": { - "message": "Nouvo Kont" - }, - "newAccountNumberName": { - "message": "Kont $1", - "description": "Default name of next account to be created on create account screen" - }, - "newContract": { - "message": "Nouvo Kontra" - }, - "newPassword": { - "message": "Nouvo modpas (minit 8)" - }, - "newRecipient": { - "message": "Nouvo Benefisyè" - }, - "newRPC": { - "message": "Nouvo RPC URL" - }, - "next": { - "message": "Aprè sa" - }, - "noAddressForName": { - "message": "Pa gen adrès ki etabli pou non sa a." - }, - "noDeposits": { - "message": "Pa gen depo ou te resevwa" - }, - "noConversionRateAvailable": { - "message": "Pa gen okenn Konvèsyon Disponib" - }, - "noTransactionHistory": { - "message": "Pa gen istwa tranzaksyon." - }, - "noTransactions": { - "message": "Pa gen tranzaksyon" - }, - "notFound": { - "message": "Pa jwenn" - }, - "notStarted": { - "message": "Pa kòmanse" - }, - "noWebcamFoundTitle": { - "message": "Pa jwenn webcam" - }, - "noWebcamFound": { - "message": "Nou pakay jwenn webcam òdinatè ou. Tanpri eseye ankò." - }, - "oldUI": { - "message": "Ansyen Itilizatè kouòdone" - }, - "oldUIMessage": { - "message": "Ou te retounen nan Ansyen Itilizatè kouòdone. Ou ka chanje tounen nan nouvo Ansyen Itilizatè nan opsyon a nan meni an tèt la." - }, - "openInTab": { - "message": "Louvri nan etikèt" - }, - "or": { - "message": "oubyen", - "description": "choice between creating or importing a new account" - }, - "origin": { - "message": "Orijin" - }, - "password": { - "message": "Modpas" - }, - "passwordCorrect": { - "message": "Tanpri asire ke modpas ou kòrèk." - }, - "passwordMismatch": { - "message": "modpas sa pa menm", - "description": "in password creation process, the two new password fields did not match" - }, - "passwordShort": { - "message": "modpas pa sifi", - "description": "in password creation process, the password is not long enough to be secure" - }, - "pastePrivateKey": { - "message": "Kole fraz prive ou a la:", - "description": "For importing an account from a private key" - }, - "pasteSeed": { - "message": "Kole seed fraz ou a la!" - }, - "pending": { - "message": "l ap mache" - }, - "personalAddressDetected": { - "message": "Adrès pèsonèl detekte. Antre adrès kontra token la." - }, - "pleaseReviewTransaction": { - "message": "Tanpri revize tranzaksyon ou." - }, - "popularTokens": { - "message": "Popilè Tokens" - }, - "prev": { - "message": "Avan" - }, - "privacyMsg": { - "message": "Règleman sou enfòmasyon prive" - }, - "privateKey": { - "message": "Prive kle", - "description": "select this type of file to use to import an account" - }, - "privateKeyWarning": { - "message": "Atansyon: pa janm divilge kle sa. Nenpòt moun kapab avèk kle prive ou a vòlè sa ou gen ou sou kont ou a." - }, - "privateNetwork": { - "message": "Rezo Prive" - }, - "qrCode": { - "message": "Montre QR Kòd" - }, - "queue": { - "message": "Queue" - }, - "readdToken": { - "message": "Ou ka ajoute token sa aprè sa ankò ou prale nan \"Ajoute token\" nan opsyon meni kont ou an." - }, - "readMore": { - "message": "Li plis isit la." - }, - "readMore2": { - "message": "Li plis isit la." - }, - "receive": { - "message": "Resevwa" - }, - "recipientAddress": { - "message": "Adrès pou resevwa" - }, - "refundAddress": { - "message": "Adrès pou resevwa" - }, - "rejected": { - "message": "Rejte" - }, - "reset": { - "message": "Repwograme" - }, - "resetAccount": { - "message": "Repwograme Kont" - }, - "resetAccountDescription": { - "message": "Repwograme kont a netwaye tranzaksyon ou yo." - }, - "restoreFromSeed": { - "message": "Restore kont?" - }, - "restoreVault": { - "message": "Retabli kazye" - }, - "restoreAccountWithSeed": { - "message": "Retabli kont ou avèk yo Seed Fraz" - }, - "required": { - "message": "Egzije" - }, - "retryWithMoreGas": { - "message": "Reseye ak yon pri gaz pi wo isit la" - }, - "walletSeed": { - "message": "Wallet Seed" - }, - "restore": { - "message": "Retabli" - }, - "revealSeedWords": { - "message": "Revele Seed Mo Yo" - }, - "revealSeedWordsTitle": { - "message": "Seed Fraz" - }, - "revealSeedWordsDescription": { - "message": "Si ou pa janm chanje navigatè ou deplase òdinatè, ou pral bezwen fraz seed la pou ka gen aksè a kont ou. Sere yo on kote an sekirite e an sekrè." - }, - "revealSeedWordsWarningTitle": { - "message": "PA pataje fraz sa a avèk nenpòt moun!" - }, - "revealSeedWordsWarning": { - "message": "Yo ka itilize mo sa pou vòlè kont ou." - }, - "revert": { - "message": "Retounen" - }, - "remove": { - "message": "retire" - }, - "removeAccount": { - "message": "Retire kont" - }, - "removeAccountDescription": { - "message": "Kont sa a pral retire nan Wallet ou. Tanpri, asire ou ke ou gen orijinal fraz seed la oubyen kle prive pou rantre kont lan avan ou kontinye. Oubyen ou ka rantre kont ou ankò apati kont \"drop-down\" ou an." - }, - "readyToConnect": { - "message": "Pare pou konekte?" - }, - "rinkeby": { - "message": "Rinkeby Tès Rezo" - }, - "ropsten": { - "message": "Ropsten Tès Rezo" - }, - "rpc": { - "message": "Koutim RPC" - }, - "currentRpc": { - "message": "Kounya RPC" - }, - "connectingToMainnet": { - "message": "Konekte ak Main (Prensipal) Ethereum Rezo a" - }, - "connectingToRopsten": { - "message": "Konekte ak Ropsten Tès Rezo a" - }, - "connectingToKovan": { - "message": "Konekte nan Kovan Tès Rezo a" - }, - "connectingToRinkeby": { - "message": "Konekte nan Rinkeby Tès Rezo a" - }, - "connectingToUnknown": { - "message": "Konekte nan rezo enkoni" - }, - "sampleAccountName": { - "message": "Pa egzanp, Nouvo kont mwen an", - "description": "Help user understand concept of adding a human-readable name to their account" - }, - "save": { - "message": "Sove" - }, - "speedUp": { - "message": "pi vit" - }, - "speedUpTitle": { - "message": "Monte vitès tranzaksyon" - }, - "speedUpSubtitle": { - "message": "Ogmante pri gaz ou pou eseye efase tranzaksyon ou pi vit" - }, - "saveAsCsvFile": { - "message": "Sove kòm dosye CSV" - }, - "saveAsFile": { - "message": "Sove kòm dosye", - "description": "Account export process" - }, - "saveSeedAsFile": { - "message": "Sove pawòl seed kòm dosye" - }, - "search": { - "message": "Rechèch" - }, - "searchResults": { - "message": "Rezilta rechèch" - }, - "secretPhrase": { - "message": "Antre fraz sekrè douz mo ou a pou w restore kòf ou a." - }, - "showHexData": { - "message": "Montre Hex Data" - }, - "showHexDataDescription": { - "message": "Pran sa pouw ka montre chan entèfas hex data a" - }, - "newPassword8Chars": { - "message": "Nouvo modpas (pou pi pit 8)" - }, - "seedPhraseReq": { - "message": "Seed fraz yo se 12 long mo" - }, - "select": { - "message": "Chwazi" - }, - "selectCurrency": { - "message": "Chwazi Lajan" - }, - "selectService": { - "message": "Chwazi Sèvis" - }, - "selectType": { - "message": "Chwazi Kalite" - }, - "send": { - "message": "Voye" - }, - "sendETH": { - "message": "Voye ETH" - }, - "sendTokens": { - "message": "Voye Tokens" - }, - "sentEther": { - "message": "Voye ether" - }, - "sentTokens": { - "message": "tokens deja voye" - }, - "separateEachWord": { - "message": "Separe chak mo ak yon sèl espas" - }, - "onlySendToEtherAddress": { - "message": "Sèlman voye ETH nan yon adrès Ethereum." - }, - "onlySendTokensToAccountAddress": { - "message": "Sèlman voye $ 1 nan yon adrès kont Ethereum.", - "description": "displays token symbol" - }, - "orderOneHere": { - "message": "Mete nan lòd on Trezor oswa Ledger epi kenbe lajan ou nan yon stòk frèt." - }, - "outgoing": { - "message": "Ap kite" - }, - "searchTokens": { - "message": "Rechèch Tokens" - }, - "selectAnAddress": { - "message": "Chwazi yon adrès" - }, - "selectAnAccount": { - "message": "Chwazi yon kont" - }, - "selectAnAccountHelp": { - "message": "Chwazi kont pou wè nan MetaMask" - }, - "selectHdPath": { - "message": "Chwazi chemen HD" - }, - "selectPathHelp": { - "message": "Si ou pa wè kont Ledger ou te genyen an anba a, eseye chanje chemen an \"Eritaj (MEW / MyCrypto)\"" - }, - "sendTokensAnywhere": { - "message": "Voye Tokens pou nenpòt moun ki gen yon kont Ethereum" - }, - "settings": { - "message": "Paramèt" - }, - "step1HardwareWallet": { - "message": "1. Konekte Materyèl bous" - }, - "step1HardwareWalletMsg": { - "message": "Konekte materyèl bous ou dirèkteman nan òdinatè ou." - }, - "step2HardwareWallet": { - "message": "2. Chwazi yon kont" - }, - "step2HardwareWalletMsg": { - "message": "Chwazi kont ou vle wè a. Ou ka chwazi youn sèlman nan yon moman." - }, - "step3HardwareWallet": { - "message": "3. Kòmanse itilize dApps ak plis ankò!" - }, - "step3HardwareWalletMsg": { - "message": "Sèvi ak kont materyèl ou menm jan ou t ap fè pou kont Etherum. Ouvri sesyon an nan dApps, voye Eth, achte ak stòke ERC20 tokens ak e ki pake chanje tokens tankou CryptoKitties." - }, - "info": { - "message": "Enfòmasyon" - }, - "scanInstructions": { - "message": "Mete kòd QR la devan kamera ou" - }, - "scanQrCode": { - "message": "Enspeksyon QR Kòd" - }, - "shapeshiftBuy": { - "message": "Achte avèk Shapeshift" - }, - "showPrivateKeys": { - "message": "Montre Kle Prive" - }, - "showQRCode": { - "message": "Montre Kòd QR" - }, - "sign": { - "message": "Siyen" - }, - "signatureRequest": { - "message": "Siyati Mande" - }, - "signed": { - "message": "Te Siyen" - }, - "signMessage": { - "message": "Siyen mesaj" - }, - "signNotice": { - "message": "Lè w siyen mesaj sa a ka gen efè segondè ki \ndanjere. Sèlman \nsit mesaj ki soti nan sit ou konplètman fè konfyans ak tout kont ou. \n Metòd danjere sa yo pral retire nan yon vèsyon fiti. " - }, - "sigRequest": { - "message": "Demann Siyati" - }, - "sigRequested": { - "message": "Demann Siyati" - }, - "spaceBetween": { - "message": "ka gen sèlman yon espas ant mo yo" - }, - "status": { - "message": "Kondisyon" - }, - "stateLogs": { - "message": "State Logs" - }, - "stateLogsDescription": { - "message": "State logs gen adrès kont piblik ou yo epi tranzaksyon ou te voye yo." - }, - "stateLogError": { - "message": "Erè nan retwouve State Logs yo." - }, - "submit": { - "message": "Soumèt" - }, - "submitted": { - "message": "Te Soumèt" - }, - "supportCenter": { - "message": "Vizite Sant Sipò Nou" - }, - "symbolBetweenZeroTen": { - "message": "Senbòl yo dwe ant 0 ak 10 karaktè." - }, - "takesTooLong": { - "message": "Pran twò lontan?" - }, - "terms": { - "message": "Tèm pou itilize" - }, - "testFaucet": { - "message": "Tès Tiyo" - }, - "to": { - "message": "Pou" - }, - "toETHviaShapeShift": { - "message": "$1 pou ETH pa ShapeShift", - "description": "system will fill in deposit type in start of message" - }, - "token": { - "message": "Token" - }, - "tokenAddress": { - "message": "Adrès Token" - }, - "tokenAlreadyAdded": { - "message": "Ou te deja ajoute token." - }, - "tokenBalance": { - "message": "Balans Token ou se:" - }, - "tokenSelection": { - "message": "Chache Tokens oswa chwazi nan lis Tokens popilè nou an." - }, - "tokenSymbol": { - "message": "Token Senbòl" - }, - "tokenWarning1": { - "message": "Kenbe tras token yo ou te achte ak kont MetaMask ou. Si ou te achte tokens pandan wap itilize yon kont diferan tokens sa yo pa pral parèt la." - }, - "total": { - "message": "Total" - }, - "transactions": { - "message": "tranzaksyon yo" - }, - "transactionConfirmed": { - "message": "Tranzaksyon ou te konfime pou $2." - }, - "transactionCreated": { - "message": "Tranzaksyon ou te kreye avèk on valè de $1 pou $2." - }, - "transactionDropped": { - "message": "Tranzaksyon ou te tonbe a $2." - }, - "transactionSubmitted": { - "message": "Tranzaksyon ou te soumèt a $2." - }, - "transactionUpdated": { - "message": "Tranzaksyon ou te aktyalize a $2." - }, - "transactionUpdatedGas": { - "message": "Tranzaksyon ou te aktyalize avèk on pri gaz de $1 a $2." - }, - "transactionError": { - "message": "Erè tranzaksyon. Eksepsyon jete nan kòd kontra." - }, - "transactionMemo": { - "message": "Memo tranzaksyon (opsyonèl)" - }, - "transactionNumber": { - "message": "Nimewo Tranzaksyon" - }, - "transfer": { - "message": "Transfè" - }, - "transfers": { - "message": "Transfè yo" - }, - "trezorHardwareWallet": { - "message": "TREZOR Materyèl Bous" - }, - "troubleTokenBalances": { - "message": "Nou te gen pwoblèm chaje balans token ou. Ou ka wè yo ", - "description": "Followed by a link (here) to view token balances" - }, - "tryAgain": { - "message": "Eseye anko" - }, - "twelveWords": { - "message": "12 mo sa yo se sèl fason pou retabli kont MetaMask ou yo. \nKenbe yo yon kote ki an sekirite ak sekrè." - }, - "typePassword": { - "message": "Tape modpas ou" - }, - "uiWelcome": { - "message": "Byenveni nan New itilizatè koòdone (Beta)" - }, - "uiWelcomeMessage": { - "message": "Kounya w ap itilize nouvo MetaMask UI (itilizatè koòdone) a." - }, - "unapproved": { - "message": "Pa apwouve" - }, - "unavailable": { - "message": "Pa disponib" - }, - "units": { - "message": "inite yo" - }, - "unknown": { - "message": "Enkoni" - }, - "unknownFunction": { - "message": "Fonksyon enkoni" - }, - "unknownNetwork": { - "message": "Rezo Prive Enkoni" - }, - "unknownNetworkId": { - "message": "Rezo ID Enkoni" - }, - "unknownQrCode": { - "message": "Erè: Nou pa t kapab idantifye QR kòd sa" - }, - "unknownCameraErrorTitle": { - "message": "Ooops! Yon bagay te ale mal...." - }, - "unknownCameraError": { - "message": "Te gen yon erè pandan y ap eseye jwenn aksè nan kamera ou. Tanpri eseye ankò..." - }, - "unlock": { - "message": "Debloke" - }, - "unlockMessage": { - "message": "Entènèt desantralize a ap tann" - }, - "uriErrorMsg": { - "message": "URIs mande pou apwopriye prefiks HTTP / HTTPS a." - }, - "usaOnly": { - "message": "USA sèlman", - "description": "Using this exchange is limited to people inside the USA" - }, - "usedByClients": { - "message": "Itilize pa yon varyete de kliyan diferan" - }, - "useOldUI": { - "message": "Itilizasyon ansyen UI (itilizatè koòdone)" - }, - "validFileImport": { - "message": "Ou dwe chwazi yon dosye ki valab pou enpòte." - }, - "vaultCreated": { - "message": "Kòf Kreye" - }, - "viewAccount": { - "message": "Wè Kont" - }, - "viewOnEtherscan": { - "message": "Wè sou Etherscan" - }, - "visitWebSite": { - "message": "Vizite sit entènèt nou an" - }, - "warning": { - "message": "Avètisman" - }, - "welcomeBack": { - "message": "Bon retou!" - }, - "welcomeBeta": { - "message": "Byenveni nan MetaMask Beta" - }, - "whatsThis": { - "message": "Kisa sa ye?" - }, - "youNeedToAllowCameraAccess": { - "message": "Ou bezwen bay kamera aksè pou sèvi ak fonksyon sa." - }, - "yourSigRequested": { - "message": "Yo mande siyati ou" - }, - "youSign": { - "message": "Ou ap siyen kounya" - }, - "yourPrivateSeedPhrase": { - "message": "Seed fraz prive ou a" - } + "accept": { + "message": "Aksepte" + }, + "accessingYourCamera": { + "message": "Aksè a Kamera" + }, + "account": { + "message": "Kont" + }, + "accountDetails": { + "message": "Detay Kont" + }, + "accountName": { + "message": "Non Kont" + }, + "accountOptions": { + "message": "Opsyon kont" + }, + "accountSelectionRequired": { + "message": "Ou bezwen chwazi yon kont!" + }, + "activityLog": { + "message": "aktivite ki fèt" + }, + "address": { + "message": "Adrès" + }, + "addCustomToken": { + "message": "Ajoute token" + }, + "addToken": { + "message": "Ajoute Token" + }, + "addTokens": { + "message": "Ajoute Token" + }, + "addSuggestedTokens": { + "message": "Ajoute Token Yo Sikjere W" + }, + "addAcquiredTokens": { + "message": "Ajoute tokens yo ou te achte lè l sèvi avèk MetaMask" + }, + "amount": { + "message": "Kantite lajan" + }, + "amountPlusGas": { + "message": "Kantite lajan + Gaz" + }, + "appDescription": { + "message": "Ekstansyon Navigatè Ethereum", + "description": "The description of the application" + }, + "appName": { + "message": "MetaMask", + "description": "The name of the application" + }, + "approve": { + "message": "Apwouve" + }, + "approved": { + "message": "Apwouve" + }, + "attemptingConnect": { + "message": "Eseye konekte nan blockchain." + }, + "attemptToCancel": { + "message": "Eseye anile?" + }, + "attemptToCancelDescription": { + "message": "Soumèt tantativ sa a pa garanti ke yo pral anile tranzaksyon ou anile. Si tantativ anile an gen siksè, ou pral chaje frè yo tranzaksyon pi wo a." + }, + "attributions": { + "message": "Atribisyon" + }, + "available": { + "message": "Disponib" + }, + "back": { + "message": "Retounen" + }, + "balance": { + "message": "Balans" + }, + "balances": { + "message": "Balans Token" + }, + "balanceIsInsufficientGas": { + "message": "Ensifizan balans pou total gaz aktyèl la" + }, + "beta": { + "message": "BETA" + }, + "betweenMinAndMax": { + "message": "dwe plis pase oswa egal a $ 1 mwens ke oswa egal a $ 2.", + "description": "helper for inputting hex as decimal input" + }, + "blockiesIdenticon": { + "message": "Itilize Blockies Identicon" + }, + "borrowDharma": { + "message": "Prete Avèk Dharma (Beta)" + }, + "browserNotSupported": { + "message": "Navigatè ou a pa sipòte..." + }, + "builtInCalifornia": { + "message": "MetaMask fèt e bati nan California." + }, + "buy": { + "message": "Achte" + }, + "buyCoinbase": { + "message": "Achte sou Coinbase" + }, + "buyCoinbaseExplainer": { + "message": "Coinbase se fason ki pi popilè nan mond lan yo achte ak vann Bitcoin, Ethereum, ak Litecoin." + }, + "bytes": { + "message": "Bytes" + }, + "ok": { + "message": "Oke" + }, + "cancel": { + "message": "Anile" + }, + "cancelAttempt": { + "message": "Teste Anile" + }, + "cancellationGasFee": { + "message": "Anilasyon Gaz Chaj" + }, + "cancelN": { + "message": "Anile tout $ 1 tranzaksyon" + }, + "classicInterface": { + "message": "Sèvi ak fas klasik la" + }, + "clickCopy": { + "message": "Klike sou kopi" + }, + "clickToAdd": { + "message": "Klike sou $ 1 pou ajoute yo nan kont ou" + }, + "close": { + "message": "Fèmen" + }, + "chromeRequiredForHardwareWallets": { + "message": "Ou bezwen sèvi ak MetaMask sou Google Chrome yo nan lòd yo konekte sou Hardware Wallet." + }, + "confirm": { + "message": "Konfime" + }, + "confirmed": { + "message": "Konfime" + }, + "confirmContract": { + "message": "Konfime Kontra" + }, + "confirmPassword": { + "message": "Konfime Modpas" + }, + "confirmTransaction": { + "message": "Konfime Tranzaksyon" + }, + "connectHardwareWallet": { + "message": "Konekte Materyèl Wallet" + }, + "connect": { + "message": "Konekte" + }, + "connecting": { + "message": "Koneksyon..." + }, + "connectingToKovan": { + "message": "Konekte nan Kovan Tès Rezo a" + }, + "connectingToMainnet": { + "message": "Konekte ak Prensipal Ethereum Rezo a" + }, + "connectingToRopsten": { + "message": "Konekte ak Ropsten Tès Rezo a" + }, + "connectingToRinkeby": { + "message": "Konekte nan Rinkeby Tès Rezo a" + }, + "connectingToUnknown": { + "message": "Konekte nan rezo enkoni" + }, + "connectToLedger": { + "message": "Konekte ak Ledger" + }, + "connectToTrezor": { + "message": "Konekte ak Trezor" + }, + "continue": { + "message": "Kontinye" + }, + "continueToCoinbase": { + "message": "Kontinye Coinbase" + }, + "contractDeployment": { + "message": "Kontra Deplwaman" + }, + "conversionProgress": { + "message": "Konvèsyon nan Pwogrè" + }, + "copiedButton": { + "message": "Kopye" + }, + "copiedClipboard": { + "message": "Kopi nan Clipboard" + }, + "copiedExclamation": { + "message": "Kopye!" + }, + "copiedSafe": { + "message": "Mwen te kopye li yon kote ki san danje" + }, + "copy": { + "message": "Kopye" + }, + "copyAddress": { + "message": "Kopi adrès clipboard" + }, + "copyToClipboard": { + "message": "Kopi clipboard" + }, + "copyButton": { + "message": " Kopi " + }, + "copyPrivateKey": { + "message": "Sa a se kle prive ou (klike pou ou kopye)" + }, + "create": { + "message": "Kreye" + }, + "createAccount": { + "message": "Kreye Kont" + }, + "createDen": { + "message": "Kreye" + }, + "crypto": { + "message": "Crypto", + "description": "Exchange type (cryptocurrencies)" + }, + "currentConversion": { + "message": "Konvèsyon aktyèl" + }, + "currentLanguage": { + "message": "Lang Aktyèl" + }, + "currentNetwork": { + "message": "Rezo aktyèl" + }, + "currentRpc": { + "message": "Aktyèl RPC" + }, + "customGas": { + "message": "Koutim Gaz" + }, + "customToken": { + "message": "Koutim Token" + }, + "customize": { + "message": "Koutim" + }, + "customRPC": { + "message": "Koutim RPC" + }, + "decimalsMustZerotoTen": { + "message": "Desimal yo dwe omwen 0, epi pa dwe plis pase 36." + }, + "decimal": { + "message": "Presizyon desimal la" + }, + "defaultNetwork": { + "message": "Dfo rezo a pou tranzaksyon Ether se Mainnet." + }, + "denExplainer": { + "message": "DEN ou se depo modpas avèk chif ou nan MetaMask." + }, + "deposit": { + "message": "Depo" + }, + "depositBTC": { + "message": "Depoze BTC ou nan adrès ki anba a:" + }, + "depositCoin": { + "message": "Depoze $1 ou nan adrès ki anba a", + "description": "Tells the user what coin they have selected to deposit with shapeshift" + }, + "depositEth": { + "message": "Depo Eth" + }, + "depositEther": { + "message": "Depo Ether" + }, + "depositFiat": { + "message": "Depo ak Fiat" + }, + "depositFromAccount": { + "message": "Depo nan yon lòt kont" + }, + "depositShapeShift": { + "message": "Depo avèk ShapeShift" + }, + "depositShapeShiftExplainer": { + "message": "Si ou posede lòt cryptocurrencies, ou ka chanje ak depo Ether dirèkteman nan Wallet MetaMask ou. Pa gen kont ki nesesè." + }, + "details": { + "message": "Detay yo" + }, + "directDeposit": { + "message": "Depo Dirèk" + }, + "directDepositEther": { + "message": "Dirèkteman Depo Ether" + }, + "directDepositEtherExplainer": { + "message": "Si ou deja gen kèk Ether, fason ki pi rapid yo ka resevwa Ether nan nouvo Wallet ou pa depo dirèk." + }, + "done": { + "message": "Fini" + }, + "downloadGoogleChrome": { + "message": "Telechaje Google Chrome" + }, + "downloadStateLogs": { + "message": "Telechaje State Logs" + }, + "dontHaveAHardwareWallet": { + "message": "Pa gen yon materyèl bous?" + }, + "dropped": { + "message": "Tonbe" + }, + "edit": { + "message": "Korije" + }, + "editAccountName": { + "message": "Korije Non Kont" + }, + "editingTransaction": { + "message": "Fè chanjman nan tranzaksyon ou" + }, + "emailUs": { + "message": "Imèl nou!" + }, + "encryptNewDen": { + "message": "Ankripte nouvo DEN ou" + }, + "ensNameNotFound": { + "message": "Nou pa jwenn non ENS ou a" + }, + "enterPassword": { + "message": "Mete modpas" + }, + "enterPasswordConfirm": { + "message": "Antre nan modpas ou a konfime" + }, + "enterPasswordContinue": { + "message": "Mete modpas pou kontinye" + }, + "eth": { + "message": "ETH" + }, + "etherscanView": { + "message": "Gade kont sou Etherscan" + }, + "exchangeRate": { + "message": "Chanje to" + }, + "expandView": { + "message": "Elaji Wè" + }, + "exportPrivateKey": { + "message": "Voye Kòd Prive" + }, + "exportPrivateKeyWarning": { + "message": "Voye kle prive ak pwòp risk ou." + }, + "failed": { + "message": "Tonbe" + }, + "fiat": { + "message": "FIAT", + "description": "Exchange type" + }, + "fileImportFail": { + "message": "Enpòte dosye ki pa travay? Klike la a!", + "description": "Helps user import their account from a JSON file" + }, + "followTwitter": { + "message": "Swiv nou sou Twitter" + }, + "forgetDevice": { + "message": "Bliye aparèy sa a" + }, + "from": { + "message": "Soti nan" + }, + "fromToSame": { + "message": "Adrès orijinal le ak sa ou resevwa pake menm" + }, + "fromShapeShift": { + "message": "Soti nan ShapeShift" + }, + "functionType": { + "message": "Kalite Fonksyon" + }, + "gas": { + "message": "Gaz", + "description": "Short indication of gas cost" + }, + "gasFee": { + "message": "Frè gaz" + }, + "gasLimit": { + "message": "Limit gaz" + }, + "gasLimitCalculation": { + "message": "Nou kalkile gaz limit sijere a ki baze sou pousantaj siksè rezo a." + }, + "gasLimitRequired": { + "message": "Limit gaz nesesè" + }, + "gasLimitTooLow": { + "message": "Limit gaz dwe omwen 21000" + }, + "gasUsed": { + "message": "Gaz yo Itilize" + }, + "generatingSeed": { + "message": "Grenn jenerasyon..." + }, + "gasPrice": { + "message": "Pri gaz (GWEI)" + }, + "gasPriceCalculation": { + "message": "Nou kalkile pri yo gaz ki sijere ki baze sou pousantaj siksè rezo." + }, + "gasPriceRequired": { + "message": "Pri Gaz la Egzije" + }, + "generatingTransaction": { + "message": "Tranzaksyon kap fè" + }, + "getEther": { + "message": "Jwenn Ether" + }, + "getEtherFromFaucet": { + "message": "Jwenn Ether nan yon tiyo pou $1 la", + "description": "Displays network name for Ether faucet" + }, + "getHelp": { + "message": "Jwenn èd." + }, + "greaterThanMin": { + "message": "dwe pi gran pase oswa egal a $ 1.", + "description": "helper for inputting hex as decimal input" + }, + "hardware": { + "message": "materyèl" + }, + "hardwareWalletConnected": { + "message": "Materyèl Wallet konekte" + }, + "hardwareWallets": { + "message": "Materyèl Wallet konekte" + }, + "hardwareWalletsMsg": { + "message": "Chwazi yon Materyèl Wallet ou ta renmen itilize ak MetaMask" + }, + "havingTroubleConnecting": { + "message": "Èske w gen pwoblèm pou konekte?" + }, + "here": { + "message": "isit la", + "description": "as in -click here- for more information (goes with troubleTokenBalances)" + }, + "hereList": { + "message": "Isit la nan yon lis !!!!" + }, + "hexData": { + "message": "Hex Data" + }, + "hide": { + "message": "Kache" + }, + "hideToken": { + "message": "Kache Token" + }, + "hideTokenPrompt": { + "message": "Kache Token?" + }, + "history": { + "message": "Istwa" + }, + "howToDeposit": { + "message": "Ki jan ou ta renmen depo Ether?" + }, + "holdEther": { + "message": "Li pèmèt ou kenbe ether & tokens, epi sèvi kòm on pon pou desantralize aplikasyon." + }, + "import": { + "message": "Pòte", + "description": "Button to import an account from a selected file" + }, + "importAccount": { + "message": "Pòte Kont" + }, + "importAccountMsg": { + "message": " Kont pòte pa pral asosye avèk orijinal ou te kreye nan kont MetaMask seed fraz. Aprann plis sou kont enpòte " + }, + "importAnAccount": { + "message": "Pòte yon kont" + }, + "importDen": { + "message": "Pòte ki deja egziste DEN" + }, + "imported": { + "message": "Pòte", + "description": "status showing that an account has been fully loaded into the keyring" + }, + "importUsingSeed": { + "message": "Pòte lè sèvi avèk seed fraz" + }, + "info": { + "message": "Enfo" + }, + "infoHelp": { + "message": "Enfo & Èd" + }, + "initialTransactionConfirmed": { + "message": "Premye tranzaksyon ou konfime sou rezo a. Klike sou OK pou tounen." + }, + "insufficientFunds": { + "message": "Lajan ensifizan." + }, + "insufficientTokens": { + "message": "Tokens pa valab." + }, + "invalidAddress": { + "message": "Adrès pa valab" + }, + "invalidAddressRecipient": { + "message": "Moun ki resevwa adrès la pa valab" + }, + "invalidGasParams": { + "message": "Gaz Paramèt la pa valab" + }, + "invalidInput": { + "message": "Sa ou rantre a pa valab" + }, + "invalidRequest": { + "message": "Demann pa valab" + }, + "invalidRPC": { + "message": "RPC URI pa valab" + }, + "invalidSeedPhrase": { + "message": "Seed fraz pa valab" + }, + "jsonFail": { + "message": "Yon bagay ale mal. Tanpri, asire w ke dosye JSON ou an byen fòmate." + }, + "jsonFile": { + "message": "JSON Dosye", + "description": "format for importing an account" + }, + "keepTrackTokens": { + "message": "Gade tokens yo ou te achte ak kont MetaMask ou." + }, + "kovan": { + "message": "Kovan Tès Rezo" + }, + "knowledgeDataBase": { + "message": "Vizite baz nou an" + }, + "max": { + "message": "Maksimòm" + }, + "learnMore": { + "message": "Aprann plis" + }, + "ledgerAccountRestriction": { + "message": "Ou bezwen sèvi ak dènye kont ou anvan ou ka ajoute yon nouvo." + }, + "lessThanMax": { + "message": "dwe mwens pase oswa egal a $ 1.", + "description": "helper for inputting hex as decimal input" + }, + "likeToAddTokens": { + "message": "Èske ou ta renmen ajoute sa nan tokens?" + }, + "links": { + "message": "Lyen" + }, + "limit": { + "message": "Limitasyon" + }, + "loading": { + "message": "Telechaje..." + }, + "loadingTokens": { + "message": "Telechaje Tokens..." + }, + "localhost": { + "message": "Localhost 8545" + }, + "login": { + "message": "Ouvri" + }, + "logout": { + "message": "Dekonekte" + }, + "loose": { + "message": "Pèdi" + }, + "loweCaseWords": { + "message": "seed mo sèlman gen karaktè miniskil" + }, + "mainnet": { + "message": "Prensipal Ethereum Rezo a" + }, + "menu": { + "message": "Opsyon" + }, + "message": { + "message": "Mesaje" + }, + "metamaskDescription": { + "message": "MetaMask sekirize idantite pou Ethereum." + }, + "metamaskSeedWords": { + "message": "MetaMask Seed Mo" + }, + "metamaskVersion": { + "message": "MetaMask Vèsyon" + }, + "min": { + "message": "Minimòm" + }, + "missingYourTokens": { + "message": "Ou pa wè token ou a?" + }, + "myAccounts": { + "message": "Kont mwen" + }, + "mustSelectOne": { + "message": "Ou dwe chwazi omwen 1 token." + }, + "needEtherInWallet": { + "message": "Pou kominike avèk aplikasyon desantralize ou dwe itilize MetaMask, ou pral bezwen Ether nan Wallet ou." + }, + "needImportFile": { + "message": "Ou dwe chwazi yon dosye pou enpòte.", + "description": "User is important an account and needs to add a file to continue" + }, + "needImportPassword": { + "message": "Ou dwe antre nan yon modpas pou dosye ou te chwazi a.", + "description": "Password and file needed to import an account" + }, + "negativeETH": { + "message": "Pa ka voye kantite lajan negatif ETH." + }, + "networks": { + "message": "Rezo" + }, + "nevermind": { + "message": "Pa pwoblèm" + }, + "newAccount": { + "message": "Nouvo Kont" + }, + "newAccountNumberName": { + "message": "Kont $1", + "description": "Default name of next account to be created on create account screen" + }, + "newContract": { + "message": "Nouvo Kontra" + }, + "newPassword": { + "message": "Nouvo modpas (minit 8)" + }, + "newPassword8Chars": { + "message": "Nouvo modpas (minit 8)" + }, + "newRecipient": { + "message": "Nouvo Benefisyè" + }, + "newRPC": { + "message": "Nouvo RPC URL" + }, + "next": { + "message": "Aprè sa" + }, + "noAddressForName": { + "message": "Pa gen adrès ki etabli pou non sa a." + }, + "noDeposits": { + "message": "Pa gen depo ou te resevwa" + }, + "noConversionRateAvailable": { + "message": "Pa gen okenn Konvèsyon Disponib" + }, + "noTransactionHistory": { + "message": "Pa gen istwa tranzaksyon." + }, + "noTransactions": { + "message": "Pa gen tranzaksyon" + }, + "notFound": { + "message": "Pa jwenn" + }, + "notStarted": { + "message": "Pa kòmanse" + }, + "noWebcamFoundTitle": { + "message": "Pa jwenn webcam" + }, + "noWebcamFound": { + "message": "Nou pakay jwenn webcam òdinatè ou. Tanpri eseye ankò." + }, + "oldUI": { + "message": "Ansyen Itilizatè kouòdone" + }, + "oldUIMessage": { + "message": "Ou te retounen nan Ansyen Itilizatè kouòdone. Ou ka chanje tounen nan nouvo Ansyen Itilizatè nan opsyon a nan meni an tèt la." + }, + "onlySendToEtherAddress": { + "message": "Sèlman voye ETH nan yon adrès Ethereum." + }, + "onlySendTokensToAccountAddress": { + "message": "Sèlman voye $ 1 nan yon adrès kont Ethereum.", + "description": "displays token symbol" + }, + "openInTab": { + "message": "Louvri nan etikèt" + }, + "or": { + "message": "oubyen", + "description": "choice between creating or importing a new account" + }, + "orderOneHere": { + "message": "Mete nan lòd on Trezor oswa Ledger epi kenbe lajan ou nan yon stòk frèt." + }, + "origin": { + "message": "Orijin" + }, + "outgoing": { + "message": "Ap kite" + }, + "parameters": { + "message": "Paramèt" + }, + "password": { + "message": "Modpas" + }, + "passwordCorrect": { + "message": "Tanpri asire ke modpas ou kòrèk." + }, + "passwordsDontMatch": { + "message": "Modpas pa matche" + }, + "passwordMismatch": { + "message": "modpas sa pa menm", + "description": "in password creation process, the two new password fields did not match" + }, + "passwordNotLongEnough": { + "message": "Modpas pa lontan ase" + }, + "passwordShort": { + "message": "modpas pa sifi", + "description": "in password creation process, the password is not long enough to be secure" + }, + "pastePrivateKey": { + "message": "Kole fraz prive ou a la:", + "description": "For importing an account from a private key" + }, + "pasteSeed": { + "message": "Kole seed fraz ou a la!" + }, + "pending": { + "message": "l ap mache" + }, + "personalAddressDetected": { + "message": "Adrès pèsonèl detekte. Antre adrès kontra token la." + }, + "pleaseReviewTransaction": { + "message": "Tanpri revize tranzaksyon ou." + }, + "popularTokens": { + "message": "Popilè Tokens" + }, + "prev": { + "message": "Avan" + }, + "primaryCurrencySetting": { + "message": "Lajan ou itilize pi plis la" + }, + "primaryCurrencySettingDescription": { + "message": "Chwazi ETH pou bay priyorite montre valè nan ETH. Chwazi Fiat priyorite montre valè nan lajan ou chwazi a." + }, + "privacyMsg": { + "message": "Règleman sou enfòmasyon prive" + }, + "privateKey": { + "message": "Prive kle", + "description": "select this type of file to use to import an account" + }, + "privateKeyWarning": { + "message": "Atansyon: pa janm divilge kle sa. Nenpòt moun kapab avèk kle prive ou a vòlè sa ou gen ou sou kont ou a." + }, + "privateNetwork": { + "message": "Rezo Prive" + }, + "qrCode": { + "message": "Montre QR Kòd" + }, + "queue": { + "message": "Queue" + }, + "readdToken": { + "message": "Ou ka ajoute token sa aprè sa ankò ou prale nan \"Ajoute token\" nan opsyon meni kont ou an." + }, + "readMore": { + "message": "Li plis isit la." + }, + "readMore2": { + "message": "Li plis isit la." + }, + "receive": { + "message": "Resevwa" + }, + "recipientAddress": { + "message": "Adrès pou resevwa" + }, + "refundAddress": { + "message": "Adrès pou resevwa" + }, + "reject": { + "message": "Rejte" + }, + "rejectAll": { + "message": "Rejte Tout" + }, + "rejectTxsN": { + "message": "Rejete $ 1 tranzaksyon" + }, + "rejectTxsDescription": { + "message": "Ou se sou rejte $ 1 yon anpil nan tranzaksyon yo." + }, + "rejected": { + "message": "Rejete" + }, + "reset": { + "message": "Repwograme" + }, + "resetAccount": { + "message": "Repwograme Kont" + }, + "resetAccountDescription": { + "message": "Repwograme kont a netwaye tranzaksyon ou yo." + }, + "restoreFromSeed": { + "message": "Restore kont?" + }, + "restoreVault": { + "message": "Retabli kazye" + }, + "restoreAccountWithSeed": { + "message": "Retabli kont ou avèk yo Seed Fraz" + }, + "required": { + "message": "Egzije" + }, + "retryWithMoreGas": { + "message": "Reseye ak yon pri gaz pi wo isit la" + }, + "restore": { + "message": "Retabli" + }, + "revealSeedWords": { + "message": "Revele Seed Mo Yo" + }, + "revealSeedWordsTitle": { + "message": "Seed Fraz" + }, + "revealSeedWordsDescription": { + "message": "Si ou pa janm chanje navigatè ou deplase òdinatè, ou pral bezwen fraz seed la pou ka gen aksè a kont ou. Sere yo on kote an sekirite e an sekrè." + }, + "revealSeedWordsWarningTitle": { + "message": "PA pataje fraz sa a avèk nenpòt moun!" + }, + "revealSeedWordsWarning": { + "message": "Yo ka itilize mo sa pou vòlè kont ou." + }, + "revert": { + "message": "Retounen" + }, + "remove": { + "message": "retire" + }, + "removeAccount": { + "message": "Retire kont" + }, + "removeAccountDescription": { + "message": "Kont sa a pral retire nan Wallet ou. Tanpri, asire ou ke ou gen orijinal fraz seed la oubyen kle prive pou rantre kont lan avan ou kontinye. Oubyen ou ka rantre kont ou ankò apati kont \"drop-down\" ou an." + }, + "readyToConnect": { + "message": "Pare pou konekte?" + }, + "rinkeby": { + "message": "Rinkeby Tès Rezo" + }, + "ropsten": { + "message": "Ropsten Tès Rezo" + }, + "rpc": { + "message": "Koutim RPC" + }, + "sampleAccountName": { + "message": "Pa egzanp, Nouvo kont mwen an", + "description": "Help user understand concept of adding a human-readable name to their account" + }, + "save": { + "message": "Sove" + }, + "saveAsCsvFile": { + "message": "Sove kòm dosye CSV" + }, + "saveAsFile": { + "message": "Sove kòm dosye", + "description": "Account export process" + }, + "saveSeedAsFile": { + "message": "Sove pawòl seed kòm dosye" + }, + "scanInstructions": { + "message": "Mete kòd QR la devan kamera ou" + }, + "scanQrCode": { + "message": "Enspeksyon QR Kòd" + }, + "search": { + "message": "Rechèch" + }, + "searchResults": { + "message": "Rezilta rechèch" + }, + "secretPhrase": { + "message": "Antre fraz sekrè douz mo ou a pou w restore kòf ou a." + }, + "seedPhraseReq": { + "message": "Seed fraz yo se 12 long mo" + }, + "select": { + "message": "Chwazi" + }, + "selectCurrency": { + "message": "Chwazi Lajan" + }, + "selectLocale": { + "message": "Chwazi Lokasyon" + }, + "selectService": { + "message": "Chwazi Sèvis" + }, + "selectType": { + "message": "Chwazi Kalite" + }, + "send": { + "message": "Voye" + }, + "sendETH": { + "message": "Voye ETH" + }, + "sendTokens": { + "message": "Voye Tokens" + }, + "sentEther": { + "message": "Voye ether" + }, + "sentTokens": { + "message": "tokens deja voye" + }, + "separateEachWord": { + "message": "Separe chak mo ak yon sèl espas" + }, + "searchTokens": { + "message": "Rechèch Tokens" + }, + "selectAnAddress": { + "message": "Chwazi yon adrès" + }, + "selectAnAccount": { + "message": "Chwazi yon kont" + }, + "selectAnAccountHelp": { + "message": "Chwazi kont pou wè nan MetaMask" + }, + "selectHdPath": { + "message": "Chwazi chemen HD" + }, + "selectPathHelp": { + "message": "Si ou pa wè kont Ledger ou te genyen an anba a, eseye chanje chemen an \"Eritaj (MEW / MyCrypto)\"" + }, + "sendTokensAnywhere": { + "message": "Voye Tokens pou nenpòt moun ki gen yon kont Ethereum" + }, + "settings": { + "message": "Paramèt" + }, + "shapeshiftBuy": { + "message": "Achte avèk Shapeshift" + }, + "showPrivateKeys": { + "message": "Montre Kle Prive" + }, + "showQRCode": { + "message": "Montre Kòd QR" + }, + "showHexData": { + "message": "Montre Hex Data" + }, + "showHexDataDescription": { + "message": "Pran sa pouw ka montre chan entèfas hex data a" + }, + "sign": { + "message": "Siyen" + }, + "signatureRequest": { + "message": "Siyati Mande" + }, + "signed": { + "message": "Te Siyen" + }, + "signMessage": { + "message": "Siyen mesaj" + }, + "signNotice": { + "message": "Lè w siyen mesaj sa a ka gen efè segondè ki \ndanjere. Sèlman \nsit mesaj ki soti nan sit ou konplètman fè konfyans ak tout kont ou. \n Metòd danjere sa yo pral retire nan yon vèsyon fiti. " + }, + "sigRequest": { + "message": "Demann Siyati" + }, + "sigRequested": { + "message": "Demann Siyati" + }, + "spaceBetween": { + "message": "ka gen sèlman yon espas ant mo yo" + }, + "speedUp": { + "message": "pi vit" + }, + "speedUpTitle": { + "message": "Monte vitès tranzaksyon" + }, + "speedUpSubtitle": { + "message": "Ogmante pri gaz ou pou eseye efase tranzaksyon ou pi vit" + }, + "status": { + "message": "Kondisyon" + }, + "stateLogs": { + "message": "State Logs" + }, + "stateLogsDescription": { + "message": "State logs gen adrès kont piblik ou yo epi tranzaksyon ou te voye yo." + }, + "stateLogError": { + "message": "Erè nan retwouve State Logs yo." + }, + "step1HardwareWallet": { + "message": "1. Konekte Materyèl bous" + }, + "step1HardwareWalletMsg": { + "message": "Konekte materyèl bous ou dirèkteman nan òdinatè ou." + }, + "step2HardwareWallet": { + "message": "2. Chwazi yon kont" + }, + "step2HardwareWalletMsg": { + "message": "Chwazi kont ou vle wè a. Ou ka chwazi youn sèlman nan yon moman." + }, + "step3HardwareWallet": { + "message": "3. Kòmanse itilize dApps ak plis ankò!" + }, + "step3HardwareWalletMsg": { + "message": "Sèvi ak kont materyèl ou menm jan ou t ap fè pou kont Etherum. Ouvri sesyon an nan dApps, voye Eth, achte ak stòke ERC20 tokens ak e ki pake chanje tokens tankou CryptoKitties." + }, + "submit": { + "message": "Soumèt" + }, + "submitted": { + "message": "Te Soumèt" + }, + "supportCenter": { + "message": "Vizite Sant Sipò Nou" + }, + "symbolBetweenZeroTen": { + "message": "Senbòl yo dwe ant 0 ak 10 karaktè." + }, + "takesTooLong": { + "message": "Pran twò lontan?" + }, + "terms": { + "message": "Tèm pou itilize" + }, + "testFaucet": { + "message": "Tès Tiyo" + }, + "to": { + "message": "Pou" + }, + "toETHviaShapeShift": { + "message": "$1 pou ETH pa ShapeShift", + "description": "system will fill in deposit type in start of message" + }, + "token": { + "message": "Token" + }, + "tokenAddress": { + "message": "Adrès Token" + }, + "tokenAlreadyAdded": { + "message": "Ou te deja ajoute token." + }, + "tokenBalance": { + "message": "Balans Token ou se:" + }, + "tokenSelection": { + "message": "Chache Tokens oswa chwazi nan lis Tokens popilè nou an." + }, + "tokenSymbol": { + "message": "Token Senbòl" + }, + "tokenWarning1": { + "message": "Kenbe tras token yo ou te achte ak kont MetaMask ou. Si ou te achte tokens pandan wap itilize yon kont diferan tokens sa yo pa pral parèt la." + }, + "total": { + "message": "Total" + }, + "transaction": { + "message": "tranzaksyon yo" + }, + "transactionConfirmed": { + "message": "Tranzaksyon ou te konfime pou $2." + }, + "transactionCreated": { + "message": "Tranzaksyon ou te kreye avèk on valè de $1 pou $2." + }, + "transactionWithNonce": { + "message": "Tranzaksyon $1" + }, + "transactionDropped": { + "message": "Tranzaksyon ou te tonbe a $2." + }, + "transactionSubmitted": { + "message": "Tranzaksyon ou te soumèt a $2." + }, + "transactionUpdated": { + "message": "Tranzaksyon ou te aktyalize a $2." + }, + "transactionUpdatedGas": { + "message": "Tranzaksyon ou te aktyalize avèk on pri gaz de $1 a $2." + }, + "transactions": { + "message": "transactions" + }, + "transactionError": { + "message": "Erè tranzaksyon. Eksepsyon jete nan kòd kontra." + }, + "transactionMemo": { + "message": "Memo tranzaksyon (opsyonèl)" + }, + "transactionNumber": { + "message": "Nimewo Tranzaksyon" + }, + "transfer": { + "message": "Transfè" + }, + "transferFrom": { + "message": "Transfer From" + }, + "transfers": { + "message": "Transfè yo" + }, + "trezorHardwareWallet": { + "message": "TREZOR Materyèl Bous" + }, + "troubleTokenBalances": { + "message": "Nou te gen pwoblèm chaje balans token ou. Ou ka wè yo ", + "description": "Followed by a link (here) to view token balances" + }, + "tryAgain": { + "message": "Eseye anko" + }, + "twelveWords": { + "message": "12 mo sa yo se sèl fason pou retabli kont MetaMask ou yo. \nKenbe yo yon kote ki an sekirite ak sekrè." + }, + "typePassword": { + "message": "Tape modpas ou" + }, + "uiWelcome": { + "message": "Byenveni nan New itilizatè koòdone (Beta)" + }, + "uiWelcomeMessage": { + "message": "Kounya w ap itilize nouvo MetaMask UI (itilizatè koòdone) a." + }, + "unapproved": { + "message": "Pa apwouve" + }, + "unavailable": { + "message": "Pa disponib" + }, + "units": { + "message": "inite yo" + }, + "unknown": { + "message": "Enkoni" + }, + "unknownFunction": { + "message": "Fonksyon enkoni" + }, + "unknownNetwork": { + "message": "Rezo Prive Enkoni" + }, + "unknownNetworkId": { + "message": "Rezo ID Enkoni" + }, + "unknownQrCode": { + "message": "Erè: Nou pa t kapab idantifye QR kòd sa" + }, + "unknownCameraErrorTitle": { + "message": "Ooops! Yon bagay te ale mal...." + }, + "unknownCameraError": { + "message": "Te gen yon erè pandan y ap eseye jwenn aksè nan kamera ou. Tanpri eseye ankò..." + }, + "unlock": { + "message": "Debloke" + }, + "unlockMessage": { + "message": "Entènèt desantralize a ap tann" + }, + "updatedWithDate": { + "message": "Mete ajou $1" + }, + "uriErrorMsg": { + "message": "URIs mande pou apwopriye prefiks HTTP / HTTPS a." + }, + "usaOnly": { + "message": "USA sèlman", + "description": "Using this exchange is limited to people inside the USA" + }, + "usedByClients": { + "message": "Itilize pa yon varyete de kliyan diferan" + }, + "useOldUI": { + "message": "Itilizasyon ansyen UI (itilizatè koòdone)" + }, + "validFileImport": { + "message": "Ou dwe chwazi yon dosye ki valab pou enpòte." + }, + "vaultCreated": { + "message": "Kòf Kreye" + }, + "viewAccount": { + "message": "Wè Kont" + }, + "viewOnEtherscan": { + "message": "Wè sou Etherscan" + }, + "visitWebSite": { + "message": "Vizite sit entènèt nou an" + }, + "walletSeed": { + "message": "Bous Seed" + }, + "warning": { + "message": "Avètisman" + }, + "welcomeBack": { + "message": "Bon Retou!" + }, + "welcomeBeta": { + "message": "Byenveni nan MetaMask Beta" + }, + "whatsThis": { + "message": "Kisa sa ye?" + }, + "yesLetsTry": { + "message": "Wi, ann eseye" + }, + "youNeedToAllowCameraAccess": { + "message": "Ou bezwen bay kamera aksè pou sèvi ak fonksyon sa." + }, + "yourSigRequested": { + "message": "Yo mande siyati ou" + }, + "youSign": { + "message": "Ou ap siyen kounya" + }, + "yourPrivateSeedPhrase": { + "message": "Seed fraz prive ou a" + } } diff --git a/app/_locales/index.json b/app/_locales/index.json index 46933dc3f..234215e39 100644 --- a/app/_locales/index.json +++ b/app/_locales/index.json @@ -1,24 +1,24 @@ [ - { "code": "cs", "name": "Czech" }, - { "code": "de", "name": "German" }, + { "code": "cs", "name": "Čeština" }, + { "code": "de", "name": "Deutsche" }, { "code": "en", "name": "English" }, - { "code": "es", "name": "Spanish" }, - { "code": "fr", "name": "French" }, - { "code": "ht", "name": "Haitian Creole" }, - { "code": "hn", "name": "Hindi" }, - { "code": "it", "name": "Italian" }, - { "code": "ja", "name": "Japanese" }, - { "code": "ko", "name": "Korean" }, - { "code": "nl", "name": "Dutch" }, - { "code": "ph", "name": "Tagalog" }, - { "code": "pl", "name": "Polish" }, - { "code": "pt", "name": "Portuguese" }, - { "code": "ru", "name": "Russian" }, - { "code": "sl", "name": "Slovenian" }, - { "code": "th", "name": "Thai" }, - { "code": "tml", "name": "Tamil" }, - { "code": "tr", "name": "Turkish" }, - { "code": "vi", "name": "Vietnamese" }, - { "code": "zh_CN", "name": "Chinese (Simplified)" }, - { "code": "zh_TW", "name": "Chinese (Traditional)" } + { "code": "es", "name": "Español" }, + { "code": "fr", "name": "Français" }, + { "code": "ht", "name": "Kreyòl ayisyen" }, + { "code": "hn", "name": "हिन्दी" }, + { "code": "it", "name": "Italiano" }, + { "code": "ja", "name": "日本語" }, + { "code": "ko", "name": "한국어" }, + { "code": "nl", "name": "Nederlands" }, + { "code": "ph", "name": "Pilipino" }, + { "code": "pl", "name": "Polskie" }, + { "code": "pt", "name": "Português" }, + { "code": "ru", "name": "Русский" }, + { "code": "sl", "name": "Slovenščina" }, + { "code": "th", "name": "ไทย" }, + { "code": "tml", "name": "தமிழ்" }, + { "code": "tr", "name": "Türkçe" }, + { "code": "vi", "name": "Tiếng Việt" }, + { "code": "zh_CN", "name": "中文(简体)" }, + { "code": "zh_TW", "name": "中文(繁體)" } ] diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json index e6d09c123..fc3450290 100644 --- a/app/_locales/nl/messages.json +++ b/app/_locales/nl/messages.json @@ -435,7 +435,7 @@ "message": "back-up woorden hebben alleen kleine letters" }, "mainnet": { - "message": "belangrijkste Ethereum-netwerk" + "message": "Main Netwerk" }, "message": { "message": "Bericht" diff --git a/app/loading.html b/app/loading.html index aef5d9607..71403a5ac 100644 --- a/app/loading.html +++ b/app/loading.html @@ -1,5 +1,9 @@ -<html> +<!DOCTYPE html> +<html lang="en"> <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>MetaMask Loading</title> <style> #div-logo { @@ -31,5 +35,11 @@ <div id="div-logo"> <img id="logo" src="./images/loginglogo.svg"> </div> + <script type="text/javascript"> + // redirect to 404 after one minute + setTimeout(() => { + location.href = './404.html' + }, 60000) + </script> </body> </html> diff --git a/app/scripts/background.js b/app/scripts/background.js index 509a0001d..6b3ac2664 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -29,7 +29,7 @@ const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics') const EdgeEncryptor = require('./edge-encryptor') const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code') const getObjStructure = require('./lib/getObjStructure') -const ipfsContent = require('./lib/ipfsContent.js') +const setupEnsIpfsResolver = require('./lib/ens-ipfs/setup') const { ENVIRONMENT_TYPE_POPUP, @@ -58,7 +58,6 @@ const isIE = !!document.documentMode // Edge 20+ const isEdge = !isIE && !!window.StyleMedia -let ipfsHandle let popupIsOpen = false let notificationIsOpen = false const openMetamaskTabsIDs = {} @@ -164,7 +163,6 @@ async function initialize () { const initLangCode = await getFirstPreferredLangCode() await setupController(initState, initLangCode) log.debug('MetaMask initialization complete.') - ipfsHandle = ipfsContent(initState.NetworkController.provider) } // @@ -269,10 +267,8 @@ function setupController (initState, initLangCode) { }) global.metamaskController = controller - controller.networkController.on('networkDidChange', () => { - ipfsHandle && ipfsHandle.remove() - ipfsHandle = ipfsContent(controller.networkController.providerStore.getState()) - }) + const provider = controller.provider + setupEnsIpfsResolver({ provider }) // report failed transactions to Sentry controller.txController.on(`tx:status-update`, (txId, status) => { diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 689506a7a..20b13398c 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -104,7 +104,7 @@ class PreferencesController { * @param {Function} - end */ async requestWatchAsset (req, res, next, end) { - if (req.method === 'metamask_watchAsset') { + if (req.method === 'metamask_watchAsset' || req.method === 'wallet_watchAsset') { const { type, options } = req.params switch (type) { case 'ERC20': diff --git a/app/scripts/lib/contracts/registrar.js b/app/scripts/lib/ens-ipfs/contracts/registrar.js index 99ca24458..99ca24458 100644 --- a/app/scripts/lib/contracts/registrar.js +++ b/app/scripts/lib/ens-ipfs/contracts/registrar.js diff --git a/app/scripts/lib/contracts/resolver.js b/app/scripts/lib/ens-ipfs/contracts/resolver.js index 1bf3f90ce..1bf3f90ce 100644 --- a/app/scripts/lib/contracts/resolver.js +++ b/app/scripts/lib/ens-ipfs/contracts/resolver.js diff --git a/app/scripts/lib/ens-ipfs/resolver.js b/app/scripts/lib/ens-ipfs/resolver.js new file mode 100644 index 000000000..fe2dc1134 --- /dev/null +++ b/app/scripts/lib/ens-ipfs/resolver.js @@ -0,0 +1,54 @@ +const namehash = require('eth-ens-namehash') +const multihash = require('multihashes') +const Eth = require('ethjs-query') +const EthContract = require('ethjs-contract') +const registrarAbi = require('./contracts/registrar') +const resolverAbi = require('./contracts/resolver') + +module.exports = resolveEnsToIpfsContentId + + +async function resolveEnsToIpfsContentId ({ provider, name }) { + const eth = new Eth(provider) + const hash = namehash.hash(name) + const contract = new EthContract(eth) + // lookup registrar + const chainId = Number.parseInt(await eth.net_version(), 10) + const registrarAddress = getRegistrarForChainId(chainId) + if (!registrarAddress) { + throw new Error(`EnsIpfsResolver - no known ens-ipfs registrar for chainId "${chainId}"`) + } + const Registrar = contract(registrarAbi).at(registrarAddress) + // lookup resolver + const resolverLookupResult = await Registrar.resolver(hash) + const resolverAddress = resolverLookupResult[0] + if (hexValueIsEmpty(resolverAddress)) { + throw new Error(`EnsIpfsResolver - no resolver found for name "${name}"`) + } + const Resolver = contract(resolverAbi).at(resolverAddress) + // lookup content id + const contentLookupResult = await Resolver.content(hash) + const contentHash = contentLookupResult[0] + if (hexValueIsEmpty(contentHash)) { + throw new Error(`EnsIpfsResolver - no content ID found for name "${name}"`) + } + const nonPrefixedHex = contentHash.slice(2) + const buffer = multihash.fromHexString(nonPrefixedHex) + const contentId = multihash.toB58String(multihash.encode(buffer, 'sha2-256')) + return contentId +} + +function hexValueIsEmpty(value) { + return [undefined, null, '0x', '0x0', '0x0000000000000000000000000000000000000000000000000000000000000000'].includes(value) +} + +function getRegistrarForChainId (chainId) { + switch (chainId) { + // mainnet + case 1: + return '0x314159265dd8dbb310642f98f50c066173c1259b' + // ropsten + case 3: + return '0x112234455c3a32fd11230c42e7bccd4a84e02010' + } +} diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js new file mode 100644 index 000000000..45eb1ce14 --- /dev/null +++ b/app/scripts/lib/ens-ipfs/setup.js @@ -0,0 +1,63 @@ +const urlUtil = require('url') +const extension = require('extensionizer') +const resolveEnsToIpfsContentId = require('./resolver.js') + +const supportedTopLevelDomains = ['eth'] + +module.exports = setupEnsIpfsResolver + +function setupEnsIpfsResolver({ provider }) { + + // install listener + const urlPatterns = supportedTopLevelDomains.map(tld => `*://*.${tld}/*`) + extension.webRequest.onErrorOccurred.addListener(webRequestDidFail, { urls: urlPatterns }) + + // return api object + return { + // uninstall listener + remove () { + extension.webRequest.onErrorOccurred.removeListener(webRequestDidFail) + }, + } + + async function webRequestDidFail (details) { + const { tabId, url } = details + // ignore requests that are not associated with tabs + if (tabId === -1) return + // parse ens name + const urlData = urlUtil.parse(url) + const { hostname: name, path, search } = urlData + const domainParts = name.split('.') + const topLevelDomain = domainParts[domainParts.length - 1] + // if unsupported TLD, abort + if (!supportedTopLevelDomains.includes(topLevelDomain)) return + // otherwise attempt resolve + attemptResolve({ tabId, name, path, search }) + } + + async function attemptResolve({ tabId, name, path, search }) { + extension.tabs.update(tabId, { url: `loading.html` }) + try { + const ipfsContentId = await resolveEnsToIpfsContentId({ provider, name }) + let url = `https://gateway.ipfs.io/ipfs/${ipfsContentId}${path}${search || ''}` + try { + // check if ipfs gateway has result + const response = await fetch(url, { method: 'HEAD' }) + // if failure, redirect to 404 page + if (response.status !== 200) { + extension.tabs.update(tabId, { url: '404.html' }) + return + } + // otherwise redirect to the correct page + extension.tabs.update(tabId, { url }) + } catch (err) { + console.warn(err) + // if HEAD fetch failed, redirect so user can see relevant error page + extension.tabs.update(tabId, { url }) + } + } catch (err) { + console.warn(err) + extension.tabs.update(tabId, { url: `error.html?name=${name}` }) + } + } +} diff --git a/app/scripts/lib/ipfsContent.js b/app/scripts/lib/ipfsContent.js deleted file mode 100644 index 8b08453c4..000000000 --- a/app/scripts/lib/ipfsContent.js +++ /dev/null @@ -1,46 +0,0 @@ -const extension = require('extensionizer') -const resolver = require('./resolver.js') - -module.exports = function (provider) { - function ipfsContent (details) { - const name = details.url.substring(7, details.url.length - 1) - let clearTime = null - if (/^.+\.eth$/.test(name) === false) return - - extension.tabs.query({active: true}, tab => { - extension.tabs.update(tab.id, { url: 'loading.html' }) - - clearTime = setTimeout(() => { - return extension.tabs.update(tab.id, { url: '404.html' }) - }, 60000) - - resolver.resolve(name, provider).then(ipfsHash => { - clearTimeout(clearTime) - let url = 'https://ipfs.infura.io/ipfs/' + ipfsHash - return fetch(url, { method: 'HEAD' }).then(response => response.status).then(statusCode => { - if (statusCode !== 200) return extension.tabs.update(tab.id, { url: '404.html' }) - extension.tabs.update(tab.id, { url: url }) - }) - .catch(err => { - url = 'https://ipfs.infura.io/ipfs/' + ipfsHash - extension.tabs.update(tab.id, {url: url}) - return err - }) - }) - .catch(err => { - clearTimeout(clearTime) - const url = err === 'unsupport' ? 'unsupport' : 'error' - extension.tabs.update(tab.id, {url: `${url}.html?name=${name}`}) - }) - }) - return { cancel: true } - } - - extension.webRequest.onErrorOccurred.addListener(ipfsContent, {urls: ['*://*.eth/'], types: ['main_frame']}) - - return { - remove () { - extension.webRequest.onErrorOccurred.removeListener(ipfsContent) - }, - } -} diff --git a/app/scripts/lib/resolver.js b/app/scripts/lib/resolver.js deleted file mode 100644 index ff0fed161..000000000 --- a/app/scripts/lib/resolver.js +++ /dev/null @@ -1,71 +0,0 @@ -const namehash = require('eth-ens-namehash') -const multihash = require('multihashes') -const HttpProvider = require('ethjs-provider-http') -const Eth = require('ethjs-query') -const EthContract = require('ethjs-contract') -const registrarAbi = require('./contracts/registrar') -const resolverAbi = require('./contracts/resolver') - -function ens (name, provider) { - const eth = new Eth(new HttpProvider(getProvider(provider.type))) - const hash = namehash.hash(name) - const contract = new EthContract(eth) - const Registrar = contract(registrarAbi).at(getRegistrar(provider.type)) - return new Promise((resolve, reject) => { - if (provider.type === 'mainnet' || provider.type === 'ropsten') { - Registrar.resolver(hash).then((address) => { - if (address === '0x0000000000000000000000000000000000000000') { - reject(null) - } else { - const Resolver = contract(resolverAbi).at(address['0']) - return Resolver.content(hash) - } - }).then((contentHash) => { - if (contentHash['0'] === '0x0000000000000000000000000000000000000000000000000000000000000000') reject(null) - if (contentHash.ret !== '0x') { - const hex = contentHash['0'].substring(2) - const buf = multihash.fromHexString(hex) - resolve(multihash.toB58String(multihash.encode(buf, 'sha2-256'))) - } else { - reject(null) - } - }) - } else { - return reject('unsupport') - } - }) -} - -function getProvider (type) { - switch (type) { - case 'mainnet': - return 'https://mainnet.infura.io/' - case 'ropsten': - return 'https://ropsten.infura.io/' - default: - return 'http://localhost:8545/' - } -} - -function getRegistrar (type) { - switch (type) { - case 'mainnet': - return '0x314159265dd8dbb310642f98f50c066173c1259b' - case 'ropsten': - return '0x112234455c3a32fd11230c42e7bccd4a84e02010' - default: - return '0x0000000000000000000000000000000000000000' - } -} - -module.exports.resolve = function (name, provider) { - const path = name.split('.') - const topLevelDomain = path[path.length - 1] - if (topLevelDomain === 'eth' || topLevelDomain === 'test') { - return ens(name, provider) - } else { - return new Promise((resolve, reject) => { - reject(null) - }) - } -} diff --git a/package-lock.json b/package-lock.json index e3322d21d..22f0f3ab9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35267,4 +35267,4 @@ "dev": true } } -} +}
\ No newline at end of file diff --git a/test/e2e/beta/from-import-beta-ui.spec.js b/test/e2e/beta/from-import-beta-ui.spec.js index b782a1c40..d2c3f8958 100644 --- a/test/e2e/beta/from-import-beta-ui.spec.js +++ b/test/e2e/beta/from-import-beta-ui.spec.js @@ -319,7 +319,7 @@ describe('Using MetaMask with an existing account', function () { const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary')) assert.equal(txValues.length, 1) - assert.equal(await txValues[0].getText(), '-1 ETH') + assert.ok(/-1\s*ETH/.test(await txValues[0].getText())) }) }) diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index f29f242c1..eaa7d18cd 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -371,7 +371,7 @@ describe('MetaMask', function () { it('balance renders', async () => { const balance = await findElement(driver, By.css('.balance-display .token-amount')) - await driver.wait(until.elementTextMatches(balance, /100.+ETH/)) + await driver.wait(until.elementTextMatches(balance, /100\s*ETH/)) await delay(regularDelayMs) }) }) @@ -420,7 +420,7 @@ describe('MetaMask', function () { if (process.env.SELENIUM_BROWSER !== 'firefox') { const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txValues, /-1\sETH/), 10000) + await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/), 10000) } }) }) @@ -462,7 +462,7 @@ describe('MetaMask', function () { assert.equal(transactions.length, 2) const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txValues, /-3\sETH/), 10000) + await driver.wait(until.elementTextMatches(txValues, /-3\s*ETH/), 10000) }) }) @@ -540,7 +540,7 @@ describe('MetaMask', function () { await findElements(driver, By.css('.transaction-list-item')) const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txListValue, /-4\sETH/), 10000) + await driver.wait(until.elementTextMatches(txListValue, /-4\s*ETH/), 10000) await txListValue.click() await delay(regularDelayMs) @@ -574,7 +574,7 @@ describe('MetaMask', function () { }, 10000) const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txValues[0], /-4\sETH/), 10000) + await driver.wait(until.elementTextMatches(txValues[0], /-4\s*ETH/), 10000) // const txAccounts = await findElements(driver, By.css('.tx-list-account')) // const firstTxAddress = await txAccounts[0].getText() @@ -606,7 +606,7 @@ describe('MetaMask', function () { }, 10000) const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txValues, /-0\sETH/), 10000) + await driver.wait(until.elementTextMatches(txValues, /-0\s*ETH/), 10000) await closeAllWindowHandlesExcept(driver, [extension, dapp]) await driver.switchTo().window(extension) @@ -616,9 +616,9 @@ describe('MetaMask', function () { const balance = await findElement(driver, By.css('.transaction-view-balance__primary-balance')) await delay(regularDelayMs) if (process.env.SELENIUM_BROWSER !== 'firefox') { - await driver.wait(until.elementTextMatches(balance, /^92.*ETH.*$/), 10000) + await driver.wait(until.elementTextMatches(balance, /^92.*\s*ETH.*$/), 10000) const tokenAmount = await balance.getText() - assert.ok(/^92.*ETH.*$/.test(tokenAmount)) + assert.ok(/^92.*\s*ETH.*$/.test(tokenAmount)) await delay(regularDelayMs) } }) @@ -764,7 +764,7 @@ describe('MetaMask', function () { // test cancelled on firefox until https://github.com/mozilla/geckodriver/issues/906 is resolved, // or possibly until we use latest version of firefox in the tests if (process.env.SELENIUM_BROWSER !== 'firefox') { - await driver.wait(until.elementTextMatches(txValues[0], /-50\sTST/), 10000) + await driver.wait(until.elementTextMatches(txValues[0], /-50\s*TST/), 10000) } driver.wait(async () => { @@ -798,7 +798,7 @@ describe('MetaMask', function () { await findElements(driver, By.css('.transaction-list__pending-transactions')) const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txListValue, /-7\sTST/), 10000) + await driver.wait(until.elementTextMatches(txListValue, /-7\s*TST/), 10000) await txListValue.click() await delay(regularDelayMs) @@ -851,7 +851,7 @@ describe('MetaMask', function () { }, 10000) const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txValues[0], /-7\sTST/)) + await driver.wait(until.elementTextMatches(txValues[0], /-7\s*TST/)) const txStatuses = await findElements(driver, By.css('.transaction-list-item__action')) await driver.wait(until.elementTextMatches(txStatuses[0], /Sent\sToken/)) @@ -897,7 +897,7 @@ describe('MetaMask', function () { const [txListItem] = await findElements(driver, By.css('.transaction-list-item')) const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txListValue, /-7\sTST/)) + await driver.wait(until.elementTextMatches(txListValue, /-7\s*TST/)) await txListItem.click() await delay(regularDelayMs) }) @@ -974,7 +974,7 @@ describe('MetaMask', function () { }, 10000) const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txValues[0], /-7\sTST/)) + await driver.wait(until.elementTextMatches(txValues[0], /-7\s*TST/)) const txStatuses = await findElements(driver, By.css('.transaction-list-item__action')) await driver.wait(until.elementTextMatches(txStatuses[0], /Approve/)) }) @@ -1027,7 +1027,7 @@ describe('MetaMask', function () { it('renders the balance for the chosen token', async () => { const balance = await findElement(driver, By.css('.transaction-view-balance__token-balance')) - await driver.wait(until.elementTextMatches(balance, /0\sBAT/)) + await driver.wait(until.elementTextMatches(balance, /0\s*BAT/)) await delay(regularDelayMs) }) }) diff --git a/test/e2e/beta/run-drizzle.sh b/test/e2e/beta/run-drizzle.sh index 7bfffd7e6..bfb7e6fdb 100755 --- a/test/e2e/beta/run-drizzle.sh +++ b/test/e2e/beta/run-drizzle.sh @@ -11,7 +11,7 @@ sleep 5 cd test/e2e/beta/ rm -rf drizzle-test mkdir drizzle-test && cd drizzle-test -npm install truffle +sudo npm install -g truffle truffle unbox drizzle echo "Deploying contracts for Drizzle test..." truffle compile && truffle migrate diff --git a/test/integration/lib/currency-localization.js b/test/integration/lib/currency-localization.js index 8d5acf5d0..f6b751ba2 100644 --- a/test/integration/lib/currency-localization.js +++ b/test/integration/lib/currency-localization.js @@ -25,5 +25,5 @@ async function runCurrencyLocalizationTest (assert, done) { const txView = await queryAsync($, '.transaction-view') const heroBalance = await findAsync($(txView), '.transaction-view-balance__balance') const fiatAmount = await findAsync($(heroBalance), '.transaction-view-balance__secondary-balance') - assert.equal(fiatAmount[0].textContent, '₱102,707.97 PHP') + assert.equal(fiatAmount[0].textContent, '₱102,707.97PHP') } diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js index e13016e68..271dd91cf 100644 --- a/test/integration/lib/send-new-ui.js +++ b/test/integration/lib/send-new-ui.js @@ -112,9 +112,9 @@ async function runSendFlowTest (assert, done) { errorMessage = $('.send-v2__error') assert.equal(errorMessage.length, 0, 'send should stop rendering amount error message after amount is corrected') - await customizeGas(assert, 0, 21000, '0 ETH', '$0.00 USD') - await customizeGas(assert, 1, 21000, '0.000021 ETH', '$0.03 USD') - await customizeGas(assert, 500, 60000, '0.03 ETH', '$36.03 USD') + await customizeGas(assert, 0, 21000, '0ETH', '$0.00USD') + await customizeGas(assert, 1, 21000, '0.000021ETH', '$0.03USD') + await customizeGas(assert, 500, 60000, '0.03ETH', '$36.03USD') const sendButton = await queryAsync($, 'button.btn-primary.btn--large.page-container__footer-button') assert.equal(sendButton[0].textContent, 'Next', 'next button rendered') diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js index 02f421de2..7f2804a83 100644 --- a/test/unit/app/controllers/preferences-controller-test.js +++ b/test/unit/app/controllers/preferences-controller-test.js @@ -375,6 +375,11 @@ describe('preferences controller', function () { await preferencesController.requestWatchAsset(req, res, asy.next, asy.end) sandbox.assert.called(stubEnd) sandbox.assert.notCalled(stubNext) + req.method = 'wallet_watchAsset' + req.params.type = 'someasset' + await preferencesController.requestWatchAsset(req, res, asy.next, asy.end) + sandbox.assert.calledTwice(stubEnd) + sandbox.assert.notCalled(stubNext) }) it('should through error if method is supported but asset type is not', async function () { req.method = 'metamask_watchAsset' diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index 043008a36..06376e48b 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -6,10 +6,11 @@ const genAccountLink = require('etherscan-link').createAccountLink const connect = require('react-redux').connect const Dropdown = require('./dropdown').Dropdown const DropdownMenuItem = require('./dropdown').DropdownMenuItem -const Identicon = require('./identicon') const copyToClipboard = require('copy-to-clipboard') const { checksumAddress } = require('../util') +import Identicon from './identicon' + class AccountDropdowns extends Component { constructor (props) { super(props) diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js index c9c5b60e1..94eae8d07 100644 --- a/ui/app/components/account-menu/index.js +++ b/ui/app/components/account-menu/index.js @@ -7,10 +7,10 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const actions = require('../../actions') const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu') -const Identicon = require('../identicon') const { ENVIRONMENT_TYPE_POPUP } = require('../../../../app/scripts/lib/enums') const { getEnvironmentType } = require('../../../../app/scripts/lib/util') const Tooltip = require('../tooltip') +import Identicon from '../identicon' import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display' import { PRIMARY } from '../../constants/common' diff --git a/ui/app/components/account-panel.js b/ui/app/components/account-panel.js index abaaf8163..a379ed3ac 100644 --- a/ui/app/components/account-panel.js +++ b/ui/app/components/account-panel.js @@ -1,7 +1,7 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const Identicon = require('./identicon') +import Identicon from './identicon' const formatBalance = require('../util').formatBalance const addressSummary = require('../util').addressSummary diff --git a/ui/app/components/app-header/app-header.component.js b/ui/app/components/app-header/app-header.component.js index b8b002dcc..c82dc1de9 100644 --- a/ui/app/components/app-header/app-header.component.js +++ b/ui/app/components/app-header/app-header.component.js @@ -2,13 +2,13 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import { matchPath } from 'react-router-dom' +import Identicon from '../identicon' const { ENVIRONMENT_TYPE_NOTIFICATION, ENVIRONMENT_TYPE_POPUP, } = require('../../../../app/scripts/lib/enums') const { DEFAULT_ROUTE, INITIALIZE_ROUTE, CONFIRM_TRANSACTION_ROUTE } = require('../../routes') -const Identicon = require('../identicon') const NetworkIndicator = require('../network') export default class AppHeader extends PureComponent { diff --git a/ui/app/components/balance-component.js b/ui/app/components/balance-component.js index e1fcf08e0..799ed20db 100644 --- a/ui/app/components/balance-component.js +++ b/ui/app/components/balance-component.js @@ -2,8 +2,8 @@ const Component = require('react').Component const connect = require('react-redux').connect const h = require('react-hyperscript') const inherits = require('util').inherits -const TokenBalance = require('./token-balance') -const Identicon = require('./identicon') +import TokenBalance from './token-balance' +import Identicon from './identicon' import UserPreferencedCurrencyDisplay from './user-preferenced-currency-display' import { PRIMARY, SECONDARY } from '../constants/common' const { getAssetImages, conversionRateSelector, getCurrentCurrency} = require('../selectors') @@ -81,11 +81,12 @@ BalanceComponent.prototype.renderBalance = function () { } return h('div.flex-column.balance-display', {}, [ - h('div.token-amount', {}, h(UserPreferencedCurrencyDisplay, { + h(UserPreferencedCurrencyDisplay, { + className: 'token-amount', value: balanceValue, type: PRIMARY, ethNumberOfDecimals: 3, - })), + }), showFiat && h(UserPreferencedCurrencyDisplay, { value: balanceValue, diff --git a/ui/app/components/currency-display/currency-display.component.js b/ui/app/components/currency-display/currency-display.component.js index 5f5717be3..f39e60269 100644 --- a/ui/app/components/currency-display/currency-display.component.js +++ b/ui/app/components/currency-display/currency-display.component.js @@ -10,6 +10,7 @@ export default class CurrencyDisplay extends PureComponent { prefix: PropTypes.string, prefixComponent: PropTypes.node, style: PropTypes.object, + suffix: PropTypes.string, // Used in container currency: PropTypes.oneOf([ETH]), denomination: PropTypes.oneOf([GWEI]), @@ -19,17 +20,25 @@ export default class CurrencyDisplay extends PureComponent { } render () { - const { className, displayValue, prefix, prefixComponent, style } = this.props + const { className, displayValue, prefix, prefixComponent, style, suffix } = this.props const text = `${prefix || ''}${displayValue}` + const title = `${text} ${suffix}` return ( <div className={classnames('currency-display-component', className)} style={style} - title={text} + title={title} > { prefixComponent} <span className="currency-display-component__text">{ text }</span> + { + suffix && ( + <span className="currency-display-component__suffix"> + { suffix } + </span> + ) + } </div> ) } diff --git a/ui/app/components/currency-display/currency-display.container.js b/ui/app/components/currency-display/currency-display.container.js index b387229b5..1b3fe74da 100644 --- a/ui/app/components/currency-display/currency-display.container.js +++ b/ui/app/components/currency-display/currency-display.container.js @@ -26,14 +26,15 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { const convertedValue = getValueFromWeiHex({ value, toCurrency, conversionRate, numberOfDecimals, toDenomination: denomination, }) - const formattedValue = formatCurrency(convertedValue, toCurrency) - const displayValue = hideLabel ? formattedValue : `${formattedValue} ${toCurrency.toUpperCase()}` + const displayValue = formatCurrency(convertedValue, toCurrency) + const suffix = hideLabel ? undefined : toCurrency.toUpperCase() return { ...restStateProps, ...dispatchProps, ...restOwnProps, displayValue, + suffix, } } diff --git a/ui/app/components/currency-display/index.scss b/ui/app/components/currency-display/index.scss index 8c0196102..313c932b8 100644 --- a/ui/app/components/currency-display/index.scss +++ b/ui/app/components/currency-display/index.scss @@ -7,4 +7,8 @@ overflow: hidden; text-overflow: ellipsis; } + + &__suffix { + padding-left: 4px; + } } diff --git a/ui/app/components/currency-display/tests/currency-display.container.test.js b/ui/app/components/currency-display/tests/currency-display.container.test.js index b9f98c543..fb6678776 100644 --- a/ui/app/components/currency-display/tests/currency-display.container.test.js +++ b/ui/app/components/currency-display/tests/currency-display.container.test.js @@ -45,7 +45,8 @@ describe('CurrencyDisplay container', () => { currency: 'usd', }, result: { - displayValue: '$2.80 USD', + displayValue: '$2.80', + suffix: 'USD', }, }, { @@ -53,7 +54,8 @@ describe('CurrencyDisplay container', () => { value: '0x2386f26fc10000', }, result: { - displayValue: '$2.80 USD', + displayValue: '$2.80', + suffix: 'USD', }, }, { @@ -63,7 +65,8 @@ describe('CurrencyDisplay container', () => { numberOfDecimals: 3, }, result: { - displayValue: '1.266 ETH', + displayValue: '1.266', + suffix: 'ETH', }, }, { @@ -75,6 +78,7 @@ describe('CurrencyDisplay container', () => { }, result: { displayValue: '1.266', + suffix: undefined, }, }, { @@ -86,6 +90,7 @@ describe('CurrencyDisplay container', () => { }, result: { displayValue: '1', + suffix: undefined, }, }, { @@ -97,6 +102,7 @@ describe('CurrencyDisplay container', () => { }, result: { displayValue: '1000000000', + suffix: undefined, }, }, { @@ -108,6 +114,7 @@ describe('CurrencyDisplay container', () => { }, result: { displayValue: '1e-9', + suffix: undefined, }, }, ] diff --git a/ui/app/components/currency-input/tests/currency-input.component.test.js b/ui/app/components/currency-input/tests/currency-input.component.test.js index 8de0ef863..5db53066f 100644 --- a/ui/app/components/currency-input/tests/currency-input.component.test.js +++ b/ui/app/components/currency-input/tests/currency-input.component.test.js @@ -69,7 +69,7 @@ describe('CurrencyInput Component', () => { assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'ETH') assert.equal(wrapper.find('.unit-input__input').props().value, '1') - assert.equal(wrapper.find('.currency-display-component').text(), '$231.06 USD') + assert.equal(wrapper.find('.currency-display-component').text(), '$231.06USD') }) it('should render properly with a fiat value', () => { @@ -100,7 +100,7 @@ describe('CurrencyInput Component', () => { assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'USD') assert.equal(wrapper.find('.unit-input__input').props().value, '1') - assert.equal(wrapper.find('.currency-display-component').text(), '0.004328 ETH') + assert.equal(wrapper.find('.currency-display-component').text(), '0.004328ETH') }) }) @@ -140,14 +140,14 @@ describe('CurrencyInput Component', () => { const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance() assert.equal(currencyInputInstance.state.decimalValue, 0) assert.equal(currencyInputInstance.state.hexValue, undefined) - assert.equal(wrapper.find('.currency-display-component').text(), '$0.00 USD') + assert.equal(wrapper.find('.currency-display-component').text(), '$0.00USD') const input = wrapper.find('input') assert.equal(input.props().value, 0) input.simulate('change', { target: { value: 1 } }) assert.equal(handleChangeSpy.callCount, 1) assert.ok(handleChangeSpy.calledWith('de0b6b3a7640000')) - assert.equal(wrapper.find('.currency-display-component').text(), '$231.06 USD') + assert.equal(wrapper.find('.currency-display-component').text(), '$231.06USD') assert.equal(currencyInputInstance.state.decimalValue, 1) assert.equal(currencyInputInstance.state.hexValue, 'de0b6b3a7640000') @@ -185,14 +185,14 @@ describe('CurrencyInput Component', () => { const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance() assert.equal(currencyInputInstance.state.decimalValue, 0) assert.equal(currencyInputInstance.state.hexValue, undefined) - assert.equal(wrapper.find('.currency-display-component').text(), '0 ETH') + assert.equal(wrapper.find('.currency-display-component').text(), '0ETH') const input = wrapper.find('input') assert.equal(input.props().value, 0) input.simulate('change', { target: { value: 1 } }) assert.equal(handleChangeSpy.callCount, 1) assert.ok(handleChangeSpy.calledWith('f602f2234d0ea')) - assert.equal(wrapper.find('.currency-display-component').text(), '0.004328 ETH') + assert.equal(wrapper.find('.currency-display-component').text(), '0.004328ETH') assert.equal(currencyInputInstance.state.decimalValue, 1) assert.equal(currencyInputInstance.state.hexValue, 'f602f2234d0ea') diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index b497f5c09..9ffcb12cb 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -6,7 +6,7 @@ const genAccountLink = require('../../../../lib/account-link.js') const connect = require('react-redux').connect const Dropdown = require('./dropdown').Dropdown const DropdownMenuItem = require('./dropdown').DropdownMenuItem -const Identicon = require('../../identicon') +import Identicon from '../../identicon' const { checksumAddress } = require('../../../util') const copyToClipboard = require('copy-to-clipboard') const { formatBalance } = require('../../../util') diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js deleted file mode 100644 index 7bd921892..000000000 --- a/ui/app/components/identicon.js +++ /dev/null @@ -1,124 +0,0 @@ -const Component = require('react').Component -const h = require('react-hyperscript') -const inherits = require('util').inherits -const connect = require('react-redux').connect -const isNode = require('detect-node') -const findDOMNode = require('react-dom').findDOMNode -const jazzicon = require('jazzicon') -const iconFactoryGen = require('../../lib/icon-factory') -const iconFactory = iconFactoryGen(jazzicon) -const { toDataUrl } = require('../../lib/blockies') - -module.exports = connect(mapStateToProps)(IdenticonComponent) - -inherits(IdenticonComponent, Component) -function IdenticonComponent () { - Component.call(this) - - this.defaultDiameter = 46 -} - -function mapStateToProps (state) { - return { - useBlockie: state.metamask.useBlockie, - } -} - -IdenticonComponent.prototype.render = function () { - var props = this.props - const { className = '', address, image } = props - var diameter = props.diameter || this.defaultDiameter - const style = { - height: diameter, - width: diameter, - borderRadius: diameter / 2, - } - if (image) { - return h('img', { - className: `${className} identicon`, - src: image, - style: { - ...style, - }, - }) - } else if (address) { - return h('div', { - className: `${className} identicon`, - key: 'identicon-' + address, - style: { - display: 'flex', - flexShrink: 0, - alignItems: 'center', - justifyContent: 'center', - ...style, - overflow: 'hidden', - }, - }) - } else { - return h('img.balance-icon', { - className, - src: './images/eth_logo.svg', - style: { - ...style, - }, - }) - } -} - -IdenticonComponent.prototype.componentDidMount = function () { - var props = this.props - const { address, useBlockie } = props - - if (!address) return - - if (!isNode) { - // eslint-disable-next-line react/no-find-dom-node - var container = findDOMNode(this) - - const diameter = props.diameter || this.defaultDiameter - - if (useBlockie) { - _generateBlockie(container, address, diameter) - } else { - _generateJazzicon(container, address, diameter) - } - } -} - -IdenticonComponent.prototype.componentDidUpdate = function () { - var props = this.props - const { address, useBlockie } = props - - if (!address) return - - if (!isNode) { - // eslint-disable-next-line react/no-find-dom-node - var container = findDOMNode(this) - - var children = container.children - for (var i = 0; i < children.length; i++) { - container.removeChild(children[i]) - } - - const diameter = props.diameter || this.defaultDiameter - - if (useBlockie) { - _generateBlockie(container, address, diameter) - } else { - _generateJazzicon(container, address, diameter) - } - } -} - -function _generateBlockie (container, address, diameter) { - const img = new Image() - img.src = toDataUrl(address) - img.height = diameter - img.width = diameter - container.appendChild(img) -} - -function _generateJazzicon (container, address, diameter) { - const img = iconFactory.iconForAddress(address, diameter) - container.appendChild(img) -} diff --git a/ui/app/components/identicon/identicon.component.js b/ui/app/components/identicon/identicon.component.js new file mode 100644 index 000000000..b892e5ae5 --- /dev/null +++ b/ui/app/components/identicon/identicon.component.js @@ -0,0 +1,99 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' +import { toDataUrl } from '../../../lib/blockies' +import contractMap from 'eth-contract-metadata' +import { checksumAddress } from '../../../app/util' +import Jazzicon from '../jazzicon' + +const getStyles = diameter => ( + { + height: diameter, + width: diameter, + borderRadius: diameter / 2, + } +) + +export default class Identicon extends PureComponent { + static propTypes = { + address: PropTypes.string, + className: PropTypes.string, + diameter: PropTypes.number, + image: PropTypes.string, + useBlockie: PropTypes.bool, + } + + static defaultProps = { + diameter: 46, + } + + renderImage () { + const { className, diameter, image } = this.props + + return ( + <img + className={classnames('identicon', className)} + src={image} + style={getStyles(diameter)} + /> + ) + } + + renderJazzicon () { + const { address, className, diameter } = this.props + + return ( + <Jazzicon + address={address} + diameter={diameter} + className={classnames('identicon', className)} + style={getStyles(diameter)} + /> + ) + } + + renderBlockie () { + const { address, className, diameter } = this.props + + return ( + <div + className={classnames('identicon', className)} + style={getStyles(diameter)} + > + <img + src={toDataUrl(address)} + height={diameter} + width={diameter} + /> + </div> + ) + } + + render () { + const { className, address, image, diameter, useBlockie } = this.props + + if (image) { + return this.renderImage() + } + + if (address) { + const checksummedAddress = checksumAddress(address) + + if (contractMap[checksummedAddress] && contractMap[checksummedAddress].logo) { + return this.renderJazzicon() + } + + return useBlockie + ? this.renderBlockie() + : this.renderJazzicon() + } + + return ( + <img + className={classnames('balance-icon', className)} + src="./images/eth_logo.svg" + style={getStyles(diameter)} + /> + ) + } +} diff --git a/ui/app/components/identicon/identicon.container.js b/ui/app/components/identicon/identicon.container.js new file mode 100644 index 000000000..bc49bc18e --- /dev/null +++ b/ui/app/components/identicon/identicon.container.js @@ -0,0 +1,12 @@ +import { connect } from 'react-redux' +import Identicon from './identicon.component' + +const mapStateToProps = state => { + const { metamask: { useBlockie } } = state + + return { + useBlockie, + } +} + +export default connect(mapStateToProps)(Identicon) diff --git a/ui/app/components/identicon/index.js b/ui/app/components/identicon/index.js new file mode 100644 index 000000000..799c886f2 --- /dev/null +++ b/ui/app/components/identicon/index.js @@ -0,0 +1 @@ +export { default } from './identicon.container' diff --git a/ui/app/components/identicon/index.scss b/ui/app/components/identicon/index.scss new file mode 100644 index 000000000..657afc48f --- /dev/null +++ b/ui/app/components/identicon/index.scss @@ -0,0 +1,7 @@ +.identicon { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + overflow: hidden; +} diff --git a/test/unit/ui/app/components/identicon.spec.js b/ui/app/components/identicon/tests/identicon.component.test.js index a2f8d8246..2944818f5 100644 --- a/test/unit/ui/app/components/identicon.spec.js +++ b/ui/app/components/identicon/tests/identicon.component.test.js @@ -3,11 +3,9 @@ import assert from 'assert' import thunk from 'redux-thunk' import configureMockStore from 'redux-mock-store' import { mount } from 'enzyme' +import Identicon from '../identicon.component' -import IdenticonComponent from '../../../../../ui/app/components/identicon' - -describe('Identicon Component', () => { - +describe('Identicon', () => { const state = { metamask: { useBlockie: false, @@ -19,18 +17,35 @@ describe('Identicon Component', () => { const store = mockStore(state) it('renders default eth_logo identicon with no props', () => { - const wrapper = mount(<IdenticonComponent store={store}/>) + const wrapper = mount( + <Identicon store={store}/> + ) + assert.equal(wrapper.find('img.balance-icon').prop('src'), './images/eth_logo.svg') }) it('renders custom image and add className props', () => { - const wrapper = mount(<IdenticonComponent store={store} className={'test-image'} image={'test-image'} />) - assert.equal(wrapper.find('img.test-image').prop('className'), 'test-image identicon') + const wrapper = mount( + <Identicon + store={store} + className="test-image" + image="test-image" + /> + ) + + assert.equal(wrapper.find('img.test-image').prop('className'), 'identicon test-image') assert.equal(wrapper.find('img.test-image').prop('src'), 'test-image') }) it('renders div with address prop', () => { - const wrapper = mount(<IdenticonComponent store={store} className={'test-address'} address={'0xTest'} />) - assert.equal(wrapper.find('div.test-address').prop('className'), 'test-address identicon') + const wrapper = mount( + <Identicon + store={store} + className="test-address" + address="0xTest" + /> + ) + + assert.equal(wrapper.find('div.test-address').prop('className'), 'identicon test-address') }) }) diff --git a/ui/app/components/index.scss b/ui/app/components/index.scss index beffdb221..72de6cb93 100644 --- a/ui/app/components/index.scss +++ b/ui/app/components/index.scss @@ -16,6 +16,8 @@ @import './export-text-container/index'; +@import './identicon/index'; + @import './info-box/index'; @import './menu-bar/index'; diff --git a/ui/app/components/jazzicon/index.js b/ui/app/components/jazzicon/index.js new file mode 100644 index 000000000..bea900ab9 --- /dev/null +++ b/ui/app/components/jazzicon/index.js @@ -0,0 +1 @@ +export { default } from './jazzicon.component' diff --git a/ui/app/components/jazzicon/jazzicon.component.js b/ui/app/components/jazzicon/jazzicon.component.js new file mode 100644 index 000000000..fcb1c59b1 --- /dev/null +++ b/ui/app/components/jazzicon/jazzicon.component.js @@ -0,0 +1,69 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import isNode from 'detect-node' +import { findDOMNode } from 'react-dom' +import jazzicon from 'jazzicon' +import iconFactoryGenerator from '../../../lib/icon-factory' +const iconFactory = iconFactoryGenerator(jazzicon) + +/** + * Wrapper around the jazzicon library to return a React component, as the library returns an + * HTMLDivElement which needs to be appended. + */ +export default class Jazzicon extends PureComponent { + static propTypes = { + address: PropTypes.string.isRequired, + className: PropTypes.string, + diameter: PropTypes.number, + style: PropTypes.object, + } + + static defaultProps = { + diameter: 46, + } + + componentDidMount () { + if (!isNode) { + this.appendJazzicon() + } + } + + componentDidUpdate (prevProps) { + const { address: prevAddress } = prevProps + const { address } = this.props + + if (!isNode && address !== prevAddress) { + this.removeExistingChildren() + this.appendJazzicon() + } + } + + removeExistingChildren () { + // eslint-disable-next-line react/no-find-dom-node + const container = findDOMNode(this) + const { children } = container + + for (let i = 0; i < children.length; i++) { + container.removeChild(children[i]) + } + } + + appendJazzicon () { + // eslint-disable-next-line react/no-find-dom-node + const container = findDOMNode(this) + const { address, diameter } = this.props + const image = iconFactory.iconForAddress(address, diameter) + container.appendChild(image) + } + + render () { + const { className, style } = this.props + + return ( + <div + className={className} + style={style} + /> + ) + } +} diff --git a/ui/app/components/modals/account-modal-container.js b/ui/app/components/modals/account-modal-container.js index aa0593df8..2a6c655e1 100644 --- a/ui/app/components/modals/account-modal-container.js +++ b/ui/app/components/modals/account-modal-container.js @@ -5,7 +5,7 @@ const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') const { getSelectedIdentity } = require('../../selectors') -const Identicon = require('../identicon') +import Identicon from '../identicon' function mapStateToProps (state, ownProps) { return { diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js index fb38516d3..43f3009a5 100644 --- a/ui/app/components/modals/hide-token-confirmation-modal.js +++ b/ui/app/components/modals/hide-token-confirmation-modal.js @@ -4,7 +4,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') -const Identicon = require('../identicon') +import Identicon from '../identicon' function mapStateToProps (state) { return { diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index 15ca9deaa..338229a28 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -27,7 +27,6 @@ import TransactionConfirmed from './transaction-confirmed' import ConfirmCustomizeGasModal from './customize-gas' import CancelTransaction from './cancel-transaction' import WelcomeBeta from './welcome-beta' -import TransactionDetails from './transaction-details' import RejectTransactions from './reject-transactions' const modalContainerBaseStyle = { @@ -366,19 +365,6 @@ const MODALS = { }, }, - TRANSACTION_DETAILS: { - contents: h(TransactionDetails), - mobileModalStyle: { - ...modalContainerMobileStyle, - }, - laptopModalStyle: { - ...modalContainerLaptopStyle, - }, - contentStyle: { - borderRadius: '8px', - }, - }, - REJECT_TRANSACTIONS: { contents: h(RejectTransactions), mobileModalStyle: { diff --git a/ui/app/components/modals/transaction-details/index.js b/ui/app/components/modals/transaction-details/index.js deleted file mode 100644 index 1fc42c662..000000000 --- a/ui/app/components/modals/transaction-details/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './transaction-details.container' diff --git a/ui/app/components/modals/transaction-details/transaction-details.component.js b/ui/app/components/modals/transaction-details/transaction-details.component.js deleted file mode 100644 index f2fec3409..000000000 --- a/ui/app/components/modals/transaction-details/transaction-details.component.js +++ /dev/null @@ -1,54 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import Modal from '../../modal' -import TransactionListItemDetails from '../../transaction-list-item-details' -import { hexToDecimal } from '../../../helpers/conversions.util' - -export default class TransactionConfirmed extends PureComponent { - static contextTypes = { - t: PropTypes.func, - } - - static propTypes = { - hideModal: PropTypes.func, - transaction: PropTypes.object, - onRetry: PropTypes.func, - showRetry: PropTypes.bool, - onCancel: PropTypes.func, - showCancel: PropTypes.bool, - } - - handleSubmit = () => { - this.props.hideModal() - } - - handleRetry = () => { - const { onRetry, hideModal } = this.props - - Promise.resolve(onRetry()).then(() => hideModal()) - } - - render () { - const { t } = this.context - const { transaction, showRetry, onCancel, showCancel } = this.props - const { txParams: { nonce } = {} } = transaction - const decimalNonce = nonce && hexToDecimal(nonce) - - return ( - <Modal - onSubmit={this.handleSubmit} - onClose={this.handleSubmit} - submitText={t('ok')} - headerText={t('transactionWithNonce', [`#${decimalNonce}`])} - > - <TransactionListItemDetails - transaction={transaction} - onRetry={this.handleRetry} - showRetry={showRetry} - onCancel={() => onCancel()} - showCancel={showCancel} - /> - </Modal> - ) - } -} diff --git a/ui/app/components/modals/transaction-details/transaction-details.container.js b/ui/app/components/modals/transaction-details/transaction-details.container.js deleted file mode 100644 index f212920bb..000000000 --- a/ui/app/components/modals/transaction-details/transaction-details.container.js +++ /dev/null @@ -1,4 +0,0 @@ -import TransactionDetails from './transaction-details.component' -import withModalProps from '../../../higher-order-components/with-modal-props' - -export default withModalProps(TransactionDetails) diff --git a/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js b/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js index e63db4a2d..56e80cb83 100644 --- a/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js +++ b/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js @@ -151,7 +151,6 @@ describe('SendAmountRow Component', function () { }) it('should render a UserPreferencedTokenInput as the second child of the SendRowWrapper', () => { - console.log('HI', wrapper.find(SendRowWrapper).childAt(1)) assert(wrapper.find(SendRowWrapper).childAt(1).is(UserPreferencedTokenInput)) }) diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index d76eb5ef8..85af3b00b 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -2,7 +2,7 @@ const Component = require('react').Component const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const Identicon = require('./identicon') +import Identicon from './identicon' const connect = require('react-redux').connect const ethUtil = require('ethereumjs-util') const classnames = require('classnames') diff --git a/ui/app/components/token-cell.js b/ui/app/components/token-cell.js index 477d97597..75ba347fa 100644 --- a/ui/app/components/token-cell.js +++ b/ui/app/components/token-cell.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect -const Identicon = require('./identicon') +import Identicon from './identicon' const prefixForNetwork = require('../../lib/etherscan-prefix-for-network') const selectors = require('../selectors') const actions = require('../actions') diff --git a/ui/app/components/token-input/tests/token-input.component.test.js b/ui/app/components/token-input/tests/token-input.component.test.js index 2131e7705..2dacb9bc4 100644 --- a/ui/app/components/token-input/tests/token-input.component.test.js +++ b/ui/app/components/token-input/tests/token-input.component.test.js @@ -122,7 +122,7 @@ describe('TokenInput Component', () => { assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'ABC') assert.equal(wrapper.find('.unit-input__input').props().value, '1') - assert.equal(wrapper.find('.currency-display-component').text(), '2 ETH') + assert.equal(wrapper.find('.currency-display-component').text(), '2ETH') }) it('should render properly with a token value for fiat', () => { @@ -157,7 +157,7 @@ describe('TokenInput Component', () => { assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'ABC') assert.equal(wrapper.find('.unit-input__input').props().value, '1') - assert.equal(wrapper.find('.currency-display-component').text(), '$462.12 USD') + assert.equal(wrapper.find('.currency-display-component').text(), '$462.12USD') }) }) @@ -201,14 +201,14 @@ describe('TokenInput Component', () => { const tokenInputInstance = wrapper.find(TokenInput).at(0).instance() assert.equal(tokenInputInstance.state.decimalValue, 0) assert.equal(tokenInputInstance.state.hexValue, undefined) - assert.equal(wrapper.find('.currency-display-component').text(), '0 ETH') + assert.equal(wrapper.find('.currency-display-component').text(), '0ETH') const input = wrapper.find('input') assert.equal(input.props().value, 0) input.simulate('change', { target: { value: 1 } }) assert.equal(handleChangeSpy.callCount, 1) assert.ok(handleChangeSpy.calledWith('2710')) - assert.equal(wrapper.find('.currency-display-component').text(), '2 ETH') + assert.equal(wrapper.find('.currency-display-component').text(), '2ETH') assert.equal(tokenInputInstance.state.decimalValue, 1) assert.equal(tokenInputInstance.state.hexValue, '2710') @@ -250,14 +250,14 @@ describe('TokenInput Component', () => { const tokenInputInstance = wrapper.find(TokenInput).at(0).instance() assert.equal(tokenInputInstance.state.decimalValue, 0) assert.equal(tokenInputInstance.state.hexValue, undefined) - assert.equal(wrapper.find('.currency-display-component').text(), '$0.00 USD') + assert.equal(wrapper.find('.currency-display-component').text(), '$0.00USD') const input = wrapper.find('input') assert.equal(input.props().value, 0) input.simulate('change', { target: { value: 1 } }) assert.equal(handleChangeSpy.callCount, 1) assert.ok(handleChangeSpy.calledWith('2710')) - assert.equal(wrapper.find('.currency-display-component').text(), '$462.12 USD') + assert.equal(wrapper.find('.currency-display-component').text(), '$462.12USD') assert.equal(tokenInputInstance.state.decimalValue, 1) assert.equal(tokenInputInstance.state.hexValue, '2710') diff --git a/ui/app/components/transaction-activity-log/transaction-activity-log.component.js b/ui/app/components/transaction-activity-log/transaction-activity-log.component.js index c4cf57d14..0e6c2376f 100644 --- a/ui/app/components/transaction-activity-log/transaction-activity-log.component.js +++ b/ui/app/components/transaction-activity-log/transaction-activity-log.component.js @@ -27,10 +27,14 @@ export default class TransactionActivityLog extends PureComponent { } componentDidUpdate (prevProps) { - const { transaction: { history: prevHistory = [] } = {} } = prevProps - const { transaction: { history = [] } = {} } = this.props + const { + transaction: { history: prevHistory = [], txReceipt: { status: prevStatus } = {} } = {}, + } = prevProps + const { + transaction: { history = [], txReceipt: { status } = {} } = {}, + } = this.props - if (prevHistory.length !== history.length) { + if (prevHistory.length !== history.length || prevStatus !== status) { this.setActivites() } } diff --git a/ui/app/components/transaction-activity-log/transaction-activity-log.util.js b/ui/app/components/transaction-activity-log/transaction-activity-log.util.js index 97aa9a8f1..16597ae1a 100644 --- a/ui/app/components/transaction-activity-log/transaction-activity-log.util.js +++ b/ui/app/components/transaction-activity-log/transaction-activity-log.util.js @@ -18,6 +18,7 @@ const TRANSACTION_SUBMITTED_EVENT = 'transactionSubmitted' const TRANSACTION_CONFIRMED_EVENT = 'transactionConfirmed' const TRANSACTION_DROPPED_EVENT = 'transactionDropped' const TRANSACTION_UPDATED_EVENT = 'transactionUpdated' +const TRANSACTION_ERRORED_EVENT = 'transactionErrored' const eventPathsHash = { [STATUS_PATH]: true, @@ -39,9 +40,9 @@ function eventCreator (eventKey, timestamp, value) { } export function getActivities (transaction) { - const { history = [] } = transaction + const { history = [], txReceipt: { status } = {} } = transaction - return history.reduce((acc, base) => { + const historyActivities = history.reduce((acc, base) => { // First history item should be transaction creation if (!Array.isArray(base) && base.status === UNAPPROVED_STATUS && base.txParams) { const { time, txParams: { value } = {} } = base @@ -83,4 +84,10 @@ export function getActivities (transaction) { return acc }, []) + + // If txReceipt.status is '0x0', that means that an on-chain error occured for the transaction, + // so we add an error entry to the Activity Log. + return status === '0x0' + ? historyActivities.concat(eventCreator(TRANSACTION_ERRORED_EVENT)) + : historyActivities } diff --git a/ui/app/components/transaction-list-item/index.scss b/ui/app/components/transaction-list-item/index.scss index 9d694546b..ac0e7beeb 100644 --- a/ui/app/components/transaction-list-item/index.scss +++ b/ui/app/components/transaction-list-item/index.scss @@ -85,6 +85,7 @@ text-align: end; grid-area: primary-amount; align-self: end; + justify-self: end; @media screen and (max-width: $break-small) { padding-bottom: 2px; @@ -97,6 +98,7 @@ color: #5e6064; grid-area: secondary-amount; align-self: start; + justify-self: end; } } diff --git a/ui/app/components/transaction-list-item/transaction-list-item.component.js b/ui/app/components/transaction-list-item/transaction-list-item.component.js index 88573d2d5..696634fe0 100644 --- a/ui/app/components/transaction-list-item/transaction-list-item.component.js +++ b/ui/app/components/transaction-list-item/transaction-list-item.component.js @@ -10,7 +10,6 @@ import TransactionListItemDetails from '../transaction-list-item-details' import { CONFIRM_TRANSACTION_ROUTE } from '../../routes' import { UNAPPROVED_STATUS, TOKEN_METHOD_TRANSFER } from '../../constants/transactions' import { PRIMARY, SECONDARY } from '../../constants/common' -import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../app/scripts/lib/enums' import { getStatusKey } from '../../helpers/transactions.util' export default class TransactionListItem extends PureComponent { @@ -24,7 +23,6 @@ export default class TransactionListItem extends PureComponent { showCancelModal: PropTypes.func, showCancel: PropTypes.bool, showRetry: PropTypes.bool, - showTransactionDetailsModal: PropTypes.func, token: PropTypes.object, tokenData: PropTypes.object, transaction: PropTypes.object, @@ -39,31 +37,16 @@ export default class TransactionListItem extends PureComponent { const { transaction, history, - showTransactionDetailsModal, - methodData, - showCancel, - showRetry, } = this.props const { id, status } = transaction const { showTransactionDetails } = this.state - const windowType = window.METAMASK_UI_TYPE if (status === UNAPPROVED_STATUS) { history.push(`${CONFIRM_TRANSACTION_ROUTE}/${id}`) return } - if (windowType === ENVIRONMENT_TYPE_FULLSCREEN) { - this.setState({ showTransactionDetails: !showTransactionDetails }) - } else { - showTransactionDetailsModal({ - transaction, - onRetry: this.handleRetry, - showRetry: showRetry && methodData.done, - onCancel: this.handleCancel, - showCancel, - }) - } + this.setState({ showTransactionDetails: !showTransactionDetails }) } handleCancel = () => { diff --git a/ui/app/components/transaction-list-item/transaction-list-item.container.js b/ui/app/components/transaction-list-item/transaction-list-item.container.js index 72f5f5d61..62ed7a73f 100644 --- a/ui/app/components/transaction-list-item/transaction-list-item.container.js +++ b/ui/app/components/transaction-list-item/transaction-list-item.container.js @@ -28,16 +28,6 @@ const mapDispatchToProps = dispatch => { showCancelModal: (transactionId, originalGasPrice) => { return dispatch(showModal({ name: 'CANCEL_TRANSACTION', transactionId, originalGasPrice })) }, - showTransactionDetailsModal: ({ transaction, onRetry, showRetry, onCancel, showCancel }) => { - return dispatch(showModal({ - name: 'TRANSACTION_DETAILS', - transaction, - onRetry, - showRetry, - onCancel, - showCancel, - })) - }, } } diff --git a/ui/app/components/transaction-list/index.scss b/ui/app/components/transaction-list/index.scss index 777f701f9..ba7ffd87b 100644 --- a/ui/app/components/transaction-list/index.scss +++ b/ui/app/components/transaction-list/index.scss @@ -2,9 +2,7 @@ display: flex; flex-direction: column; flex: 1; - overflow-y: hidden; margin-top: 8px; - border-top: 1px solid $geyser; &__completed-transactions { display: flex; @@ -26,7 +24,6 @@ &__transactions { flex: 1; - overflow-y: auto; } &__pending-transactions { diff --git a/ui/app/components/transaction-view-balance/index.scss b/ui/app/components/transaction-view-balance/index.scss index 12045ab6d..659f896ff 100644 --- a/ui/app/components/transaction-view-balance/index.scss +++ b/ui/app/components/transaction-view-balance/index.scss @@ -4,11 +4,13 @@ align-items: center; flex: 1; height: 54px; + min-width: 0; &__balance { - margin-left: 12px; + margin: 0 12px; display: flex; flex-direction: column; + min-width: 0; @media screen and (max-width: $break-small) { align-items: center; @@ -21,7 +23,8 @@ font-size: 1.5rem; @media screen and (max-width: $break-small) { - margin-bottom: 12px; + margin: 12px 0; + margin-left: 0; font-size: 1.75rem; } } @@ -30,7 +33,6 @@ font-size: 1.5rem; @media screen and (max-width: $break-small) { - margin-bottom: 12px; font-size: 1.75rem; } } @@ -45,6 +47,7 @@ display: flex; flex-direction: row; align-items: center; + min-width: 0; @media screen and (max-width: $break-small) { flex-direction: column; diff --git a/ui/app/components/transaction-view/index.scss b/ui/app/components/transaction-view/index.scss index af9771ce0..13187f0e5 100644 --- a/ui/app/components/transaction-view/index.scss +++ b/ui/app/components/transaction-view/index.scss @@ -4,6 +4,7 @@ min-width: 0; display: flex; flex-direction: column; + overflow-y: auto; &__balance-wrapper { @media screen and (max-width: $break-small) { diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js index 8a7cb0f8d..e050e0ee6 100644 --- a/ui/app/components/wallet-view.js +++ b/ui/app/components/wallet-view.js @@ -7,7 +7,7 @@ const { compose } = require('recompose') const inherits = require('util').inherits const classnames = require('classnames') const { checksumAddress } = require('../util') -const Identicon = require('./identicon') +import Identicon from './identicon' // const AccountDropdowns = require('./dropdowns/index.js').AccountDropdowns const Tooltip = require('./tooltip-v2.js').default const copyToClipboard = require('copy-to-clipboard') @@ -127,7 +127,6 @@ WalletView.prototype.render = function () { identities, } = this.props // temporary logs + fake extra wallets - // console.log('walletview, selectedAccount:', selectedAccount) const checksummedAddress = checksumAddress(selectedAddress) diff --git a/ui/app/css/itcss/components/buttons.scss b/ui/app/css/itcss/components/buttons.scss index 655188a3e..e4d379a02 100644 --- a/ui/app/css/itcss/components/buttons.scss +++ b/ui/app/css/itcss/components/buttons.scss @@ -3,7 +3,7 @@ */ .button { - height: 44px; + min-height: 44px; background: $white; display: flex; justify-content: center; @@ -87,7 +87,7 @@ } .btn--large { - height: 54px; + min-height: 54px; } .btn-green { diff --git a/ui/app/css/itcss/components/request-signature.scss b/ui/app/css/itcss/components/request-signature.scss index 445b9ebf5..6c950d846 100644 --- a/ui/app/css/itcss/components/request-signature.scss +++ b/ui/app/css/itcss/components/request-signature.scss @@ -19,7 +19,7 @@ } @media screen and (min-width: $break-large) { - max-height: 620px; + height: 620px; } } diff --git a/ui/app/css/itcss/components/wallet-balance.scss b/ui/app/css/itcss/components/wallet-balance.scss index 293771550..3c3349ae0 100644 --- a/ui/app/css/itcss/components/wallet-balance.scss +++ b/ui/app/css/itcss/components/wallet-balance.scss @@ -29,7 +29,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( align-items: center; margin: 20px 24px; flex-direction: row; - flex-grow: 3; + min-width: 0; @media #{$wallet-balance-breakpoint-range} { margin: 10% 4%; @@ -38,8 +38,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( .balance-display { margin-left: 15px; - justify-content: flex-start; - align-items: flex-start; + min-width: 0; .token-amount { font-size: 1.5rem; diff --git a/ui/app/ducks/confirm-transaction.duck.js b/ui/app/ducks/confirm-transaction.duck.js index 2ceafbe08..328943cd3 100644 --- a/ui/app/ducks/confirm-transaction.duck.js +++ b/ui/app/ducks/confirm-transaction.duck.js @@ -329,7 +329,6 @@ export function updateTxDataAndCalculate (txData) { const fiatTransactionTotal = addFiat(fiatTransactionFee, fiatTransactionAmount) const ethTransactionTotal = addEth(ethTransactionFee, ethTransactionAmount) - console.log('HIHIH', value, hexTransactionFee) const hexTransactionTotal = sumHexes(value, hexTransactionFee) dispatch(updateTransactionTotals({ diff --git a/ui/app/helpers/transactions.util.js b/ui/app/helpers/transactions.util.js index cfe2c4229..2f4b1d095 100644 --- a/ui/app/helpers/transactions.util.js +++ b/ui/app/helpers/transactions.util.js @@ -27,10 +27,21 @@ export function getTokenData (data = '') { const registry = new MethodRegistry({ provider: global.ethereumProvider }) +/** + * Attempts to return the method data from the MethodRegistry library, if the method exists in the + * registry. Otherwise, returns an empty object. + * @param {string} data - The hex data (@code txParams.data) of a transaction + * @returns {Object} + */ export async function getMethodData (data = '') { const prefixedData = ethUtil.addHexPrefix(data) const fourBytePrefix = prefixedData.slice(0, 10) const sig = await registry.lookup(fourBytePrefix) + + if (!sig) { + return {} + } + const parsedResult = registry.parse(sig) return { |