mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge branch 'master' into tx-controller-rewrite-v3
This commit is contained in:
commit
c20c97ce62
@ -35,7 +35,6 @@
|
||||
|
||||
"globals": {
|
||||
"document": false,
|
||||
"log": true,
|
||||
"navigator": false,
|
||||
"web3": true,
|
||||
"window": false
|
||||
|
27
.jshintrc
27
.jshintrc
@ -1,27 +0,0 @@
|
||||
{
|
||||
"node": true,
|
||||
"browser": true,
|
||||
"esnext": true,
|
||||
"bitwise": true,
|
||||
"camelcase": true,
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
"immed": true,
|
||||
"indent": 2,
|
||||
"latedef": true,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"quotmark": "single",
|
||||
"regexp": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"strict": true,
|
||||
"trailing": true,
|
||||
"smarttabs": true,
|
||||
"globals" : {
|
||||
"chrome": true,
|
||||
"crypto": true,
|
||||
"describe": true,
|
||||
"it": true
|
||||
}
|
||||
}
|
@ -2,6 +2,12 @@
|
||||
|
||||
## Current Master
|
||||
|
||||
- Correctly format currency conversion for locally selected preferred currency.
|
||||
- Improved performance of 3D fox logo.
|
||||
- Fetch token prices based on contract address, not symbol
|
||||
- Fix bug that prevents setting language locale in settings.
|
||||
- Show checksum addresses throughout the UI
|
||||
|
||||
## 4.5.5 Fri Apr 06 2018
|
||||
|
||||
- Graceful handling of unknown keys in txParams
|
||||
|
@ -1,6 +1,7 @@
|
||||
# MetaMask Browser Extension
|
||||
[![Build Status](https://circleci.com/gh/MetaMask/metamask-extension.svg?style=shield&circle-token=a1ddcf3cd38e29267f254c9c59d556d513e3a1fd)](https://circleci.com/gh/MetaMask/metamask-extension) [![Coverage Status](https://coveralls.io/repos/github/MetaMask/metamask-extension/badge.svg?branch=master)](https://coveralls.io/github/MetaMask/metamask-extension?branch=master) [![Greenkeeper badge](https://badges.greenkeeper.io/MetaMask/metamask-extension.svg)](https://greenkeeper.io/) [![Stories in Ready](https://badge.waffle.io/MetaMask/metamask-extension.png?label=in%20progress&title=waffle.io)](https://waffle.io/MetaMask/metamask-extension)
|
||||
|
||||
[Internal documentation](./docs/jsdocs)
|
||||
|
||||
## Support
|
||||
|
||||
@ -68,6 +69,7 @@ To write tests that will be run in the browser using QUnit, add your test files
|
||||
- [How to develop a live-reloading UI](./docs/ui-dev-mode.md)
|
||||
- [How to add a new translation to MetaMask](./docs/translating-guide.md)
|
||||
- [Publishing Guide](./docs/publishing.md)
|
||||
- [The MetaMask Team](./docs/team.md)
|
||||
- [How to develop an in-browser mocked UI](./docs/ui-mock-mode.md)
|
||||
- [How to live reload on local dependency changes](./docs/developing-on-deps.md)
|
||||
- [How to add new networks to the Provider Menu](./docs/adding-new-networks.md)
|
||||
|
912
app/_locales/cs/messages.json
Normal file
912
app/_locales/cs/messages.json
Normal file
@ -0,0 +1,912 @@
|
||||
{
|
||||
"accept": {
|
||||
"message": "Přijmout"
|
||||
},
|
||||
"account": {
|
||||
"message": "Účet"
|
||||
},
|
||||
"accountDetails": {
|
||||
"message": "Detaily účtu"
|
||||
},
|
||||
"accountName": {
|
||||
"message": "Název účtu"
|
||||
},
|
||||
"address": {
|
||||
"message": "Adresa"
|
||||
},
|
||||
"addCustomToken": {
|
||||
"message": "Přidat vlastní token"
|
||||
},
|
||||
"addToken": {
|
||||
"message": "Přidat token"
|
||||
},
|
||||
"addTokens": {
|
||||
"message": "Přidat tokeny"
|
||||
},
|
||||
"amount": {
|
||||
"message": "Částka"
|
||||
},
|
||||
"amountPlusGas": {
|
||||
"message": "Částka + palivo"
|
||||
},
|
||||
"appDescription": {
|
||||
"message": "Ethereum rozšíření prohlížeče",
|
||||
"description": "The description of the application"
|
||||
},
|
||||
"appName": {
|
||||
"message": "MetaMask",
|
||||
"description": "The name of the application"
|
||||
},
|
||||
"approved": {
|
||||
"message": "Schváleno"
|
||||
},
|
||||
"attemptingConnect": {
|
||||
"message": "Pokouším se připojit k blockchainu."
|
||||
},
|
||||
"attributions": {
|
||||
"message": "Zásluhy"
|
||||
},
|
||||
"available": {
|
||||
"message": "Dostupné"
|
||||
},
|
||||
"back": {
|
||||
"message": "Zpět"
|
||||
},
|
||||
"balance": {
|
||||
"message": "Zůstatek:"
|
||||
},
|
||||
"balances": {
|
||||
"message": "Zůstatek tokenu"
|
||||
},
|
||||
"balanceIsInsufficientGas": {
|
||||
"message": "Nedostatek prostředků pro aktuální množství paliva"
|
||||
},
|
||||
"beta": {
|
||||
"message": "BETA"
|
||||
},
|
||||
"betweenMinAndMax": {
|
||||
"message": "musí být větší nebo roven $1 a menší nebo roven $2.",
|
||||
"description": "helper for inputting hex as decimal input"
|
||||
},
|
||||
"blockiesIdenticon": {
|
||||
"message": "Použít Blockies Identicon"
|
||||
},
|
||||
"borrowDharma": {
|
||||
"message": "Pújčit si přes Dharma (Beta)"
|
||||
},
|
||||
"builtInCalifornia": {
|
||||
"message": "MetaMask je navržen a vytvořen v Kalifornii."
|
||||
},
|
||||
"buy": {
|
||||
"message": "Koupit"
|
||||
},
|
||||
"buyCoinbase": {
|
||||
"message": "Nákup na Coinbase"
|
||||
},
|
||||
"buyCoinbaseExplainer": {
|
||||
"message": "Coinbase je světově nejoblíbenější místo k nákupu a prodeji bitcoinu, etherea nebo litecoinu."
|
||||
},
|
||||
"ok": {
|
||||
"message": "Ok"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "Zrušit"
|
||||
},
|
||||
"classicInterface": {
|
||||
"message": "Použít klasické rozhraní"
|
||||
},
|
||||
"clickCopy": {
|
||||
"message": "Kliknutím zkopírovat"
|
||||
},
|
||||
"confirm": {
|
||||
"message": "Potvrdit"
|
||||
},
|
||||
"confirmed": {
|
||||
"message": "Potvrzeno"
|
||||
},
|
||||
"confirmContract": {
|
||||
"message": "Potvrdit kontrakt"
|
||||
},
|
||||
"confirmPassword": {
|
||||
"message": "Potvrdit heslo"
|
||||
},
|
||||
"confirmTransaction": {
|
||||
"message": "Potvrdit transakci"
|
||||
},
|
||||
"continue": {
|
||||
"message": "Pokračovat"
|
||||
},
|
||||
"continueToCoinbase": {
|
||||
"message": "Přejít na Coinbase"
|
||||
},
|
||||
"contractDeployment": {
|
||||
"message": "Nasazení kontraktu"
|
||||
},
|
||||
"conversionProgress": {
|
||||
"message": "Provádí se převod"
|
||||
},
|
||||
"copiedButton": {
|
||||
"message": "Zkopírováno"
|
||||
},
|
||||
"copiedClipboard": {
|
||||
"message": "Zkopírováno do schránky"
|
||||
},
|
||||
"copiedExclamation": {
|
||||
"message": "Zkopírováno!"
|
||||
},
|
||||
"copiedSafe": {
|
||||
"message": "Zkopíroval jsem to na bezpečné místo"
|
||||
},
|
||||
"copy": {
|
||||
"message": "Kopírovat"
|
||||
},
|
||||
"copyToClipboard": {
|
||||
"message": "Kopírovat do schránky"
|
||||
},
|
||||
"copyButton": {
|
||||
"message": " Kopírovat "
|
||||
},
|
||||
"copyPrivateKey": {
|
||||
"message": "Toto je váš privátní klíč (kliknutím zkopírujte)"
|
||||
},
|
||||
"create": {
|
||||
"message": "Vytvořit"
|
||||
},
|
||||
"createAccount": {
|
||||
"message": "Vytvořit účet"
|
||||
},
|
||||
"createDen": {
|
||||
"message": "Vytvořit"
|
||||
},
|
||||
"crypto": {
|
||||
"message": "Krypto",
|
||||
"description": "Exchange type (cryptocurrencies)"
|
||||
},
|
||||
"currentConversion": {
|
||||
"message": "Aktuální převod"
|
||||
},
|
||||
"currentNetwork": {
|
||||
"message": "Aktuální síť"
|
||||
},
|
||||
"customGas": {
|
||||
"message": "Nastavit palivo"
|
||||
},
|
||||
"customToken": {
|
||||
"message": "Vlastní token"
|
||||
},
|
||||
"customize": {
|
||||
"message": "Nastavit"
|
||||
},
|
||||
"customRPC": {
|
||||
"message": "Vlastní RPC"
|
||||
},
|
||||
"decimalsMustZerotoTen": {
|
||||
"message": "Desetinných míst musí být od 0 do 36."
|
||||
},
|
||||
"decimal": {
|
||||
"message": "Počet desetinných míst přesnosti"
|
||||
},
|
||||
"defaultNetwork": {
|
||||
"message": "Výchozí síť pro Etherové transakce je Main Net."
|
||||
},
|
||||
"denExplainer": {
|
||||
"message": "Váš DEN je heslem šifrované uložiště v MetaMasku."
|
||||
},
|
||||
"deposit": {
|
||||
"message": "Vklad"
|
||||
},
|
||||
"depositBTC": {
|
||||
"message": "Vložte BTC na níže uvedenou adresu:"
|
||||
},
|
||||
"depositCoin": {
|
||||
"message": "Vložte $1 na níže uvedenou adresu",
|
||||
"description": "Tells the user what coin they have selected to deposit with shapeshift"
|
||||
},
|
||||
"depositEth": {
|
||||
"message": "Vložit Eth"
|
||||
},
|
||||
"depositEther": {
|
||||
"message": "Vložit Ether"
|
||||
},
|
||||
"depositFiat": {
|
||||
"message": "Vklad s fiat měnou"
|
||||
},
|
||||
"depositFromAccount": {
|
||||
"message": "Vložte z jiného účtu"
|
||||
},
|
||||
"depositShapeShift": {
|
||||
"message": "Vklad přes ShapeShift"
|
||||
},
|
||||
"depositShapeShiftExplainer": {
|
||||
"message": "Pokud vlastníte jiné kryptoměny, můžete je směnit Ether a vložit ho přímo do peněženky MetaMask. Bez založení účtu."
|
||||
},
|
||||
"details": {
|
||||
"message": "Podrobnosti"
|
||||
},
|
||||
"directDeposit": {
|
||||
"message": "Přímý vklad"
|
||||
},
|
||||
"directDepositEther": {
|
||||
"message": "Vložit Ether přímo"
|
||||
},
|
||||
"directDepositEtherExplainer": {
|
||||
"message": "Pokud už vlastníte nějaký Ether, nejrychleji ho dostanete do peněženky přímým vkladem."
|
||||
},
|
||||
"done": {
|
||||
"message": "Hotovo"
|
||||
},
|
||||
"downloadStateLogs": {
|
||||
"message": "Stáhnout stavové protokoly"
|
||||
},
|
||||
"dropped": {
|
||||
"message": "Zrušeno"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Upravit"
|
||||
},
|
||||
"editAccountName": {
|
||||
"message": "Upravit název účtu"
|
||||
},
|
||||
"emailUs": {
|
||||
"message": "Napište nám e-mail!"
|
||||
},
|
||||
"encryptNewDen": {
|
||||
"message": "Zašifrujte svůj nový DEN"
|
||||
},
|
||||
"enterPassword": {
|
||||
"message": "Zadejte heslo"
|
||||
},
|
||||
"enterPasswordConfirm": {
|
||||
"message": "Zadejte heslo k potvrzení"
|
||||
},
|
||||
"passwordNotLongEnough": {
|
||||
"message": "Heslo není dost dlouhé"
|
||||
},
|
||||
"passwordsDontMatch": {
|
||||
"message": "Hesla nejsou stejná"
|
||||
},
|
||||
"etherscanView": {
|
||||
"message": "Prohlédněte si účet na Etherscan"
|
||||
},
|
||||
"exchangeRate": {
|
||||
"message": "Směnný kurz"
|
||||
},
|
||||
"exportPrivateKey": {
|
||||
"message": "Exportovat privátní klíč"
|
||||
},
|
||||
"exportPrivateKeyWarning": {
|
||||
"message": "Exportujte privátní klíč na vlastní riziko."
|
||||
},
|
||||
"failed": {
|
||||
"message": "Neúspěšné"
|
||||
},
|
||||
"fiat": {
|
||||
"message": "FIAT",
|
||||
"description": "Exchange type"
|
||||
},
|
||||
"fileImportFail": {
|
||||
"message": "Import souboru nefunguje? Klikněte sem!",
|
||||
"description": "Helps user import their account from a JSON file"
|
||||
},
|
||||
"followTwitter": {
|
||||
"message": "Sledujte nás na Twitteru"
|
||||
},
|
||||
"from": {
|
||||
"message": "Od"
|
||||
},
|
||||
"fromToSame": {
|
||||
"message": "Adresy odesílatele a příjemce nemohou být stejné"
|
||||
},
|
||||
"fromShapeShift": {
|
||||
"message": "Z ShapeShift"
|
||||
},
|
||||
"gas": {
|
||||
"message": "Palivo",
|
||||
"description": "Short indication of gas cost"
|
||||
},
|
||||
"gasFee": {
|
||||
"message": "Poplatek za palivo"
|
||||
},
|
||||
"gasLimit": {
|
||||
"message": "Limit paliva"
|
||||
},
|
||||
"gasLimitCalculation": {
|
||||
"message": "Počítáme doporučený limit paliva na základě úspěšnosti v síti."
|
||||
},
|
||||
"gasLimitRequired": {
|
||||
"message": "Limit paliva je povinný"
|
||||
},
|
||||
"gasLimitTooLow": {
|
||||
"message": "Limit paliva musí být alespoň 21000"
|
||||
},
|
||||
"generatingSeed": {
|
||||
"message": "Generuji klíčovou frázi..."
|
||||
},
|
||||
"gasPrice": {
|
||||
"message": "Cena paliva (GWEI)"
|
||||
},
|
||||
"gasPriceCalculation": {
|
||||
"message": "Počítáme doporučenou cenu paliva na základě úspěšnosti v síti."
|
||||
},
|
||||
"gasPriceRequired": {
|
||||
"message": "Cena paliva je povinná"
|
||||
},
|
||||
"getEther": {
|
||||
"message": "Získejte Ether"
|
||||
},
|
||||
"getEtherFromFaucet": {
|
||||
"message": "Získejte Ether z faucetu za $1.",
|
||||
"description": "Displays network name for Ether faucet"
|
||||
},
|
||||
"greaterThanMin": {
|
||||
"message": "musí být větší nebo roven $1.",
|
||||
"description": "helper for inputting hex as decimal input"
|
||||
},
|
||||
"here": {
|
||||
"message": "zde",
|
||||
"description": "as in -click here- for more information (goes with troubleTokenBalances)"
|
||||
},
|
||||
"hereList": {
|
||||
"message": "Tady je seznam!!!!"
|
||||
},
|
||||
"hide": {
|
||||
"message": "Skrýt"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Skrýt token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Skrýt token?"
|
||||
},
|
||||
"howToDeposit": {
|
||||
"message": "Jakým způsobem chcete vložit Ether?"
|
||||
},
|
||||
"holdEther": {
|
||||
"message": "Dovoluje vám držet ether a tokeny a slouží jako most k decentralizovaným aplikacím."
|
||||
},
|
||||
"import": {
|
||||
"message": "Import",
|
||||
"description": "Button to import an account from a selected file"
|
||||
},
|
||||
"importAccount": {
|
||||
"message": "Import účtu"
|
||||
},
|
||||
"importAccountMsg": {
|
||||
"message":"Importované účty nebudou spojeny s vaší původní MetaMaskovou klíčovou frází. Zjistěte více o importovaných účtech "
|
||||
},
|
||||
"importAnAccount": {
|
||||
"message": "Import účtu"
|
||||
},
|
||||
"importDen": {
|
||||
"message": "Import existujícího DEN"
|
||||
},
|
||||
"imported": {
|
||||
"message": "Importováno",
|
||||
"description": "status showing that an account has been fully loaded into the keyring"
|
||||
},
|
||||
"infoHelp": {
|
||||
"message": "Informace a nápověda"
|
||||
},
|
||||
"insufficientFunds": {
|
||||
"message": "Nedostatek finančních prostředků."
|
||||
},
|
||||
"insufficientTokens": {
|
||||
"message": "Nedostatek tokenů."
|
||||
},
|
||||
"invalidAddress": {
|
||||
"message": "Neplatná adresa"
|
||||
},
|
||||
"invalidAddressRecipient": {
|
||||
"message": "Adresa příjemce je neplatná"
|
||||
},
|
||||
"invalidGasParams": {
|
||||
"message": "Neplatná parametry paliva"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Neplatný vstup."
|
||||
},
|
||||
"invalidRequest": {
|
||||
"message": "Neplatný požadavek"
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Neplatné RPC URI"
|
||||
},
|
||||
"jsonFail": {
|
||||
"message": "Něco se pokazilo. Prosím, ujistěte se, že váš JSON soubor má správný formát."
|
||||
},
|
||||
"jsonFile": {
|
||||
"message": "JSON soubor",
|
||||
"description": "format for importing an account"
|
||||
},
|
||||
"keepTrackTokens": {
|
||||
"message": "Udržujte si záznamy o tokenech, které jste koupili s účtem v MetaMasku."
|
||||
},
|
||||
"kovan": {
|
||||
"message": "Kovan Test Network"
|
||||
},
|
||||
"knowledgeDataBase": {
|
||||
"message": "Navštivte naši Knowledge Base"
|
||||
},
|
||||
"max": {
|
||||
"message": "Max"
|
||||
},
|
||||
"learnMore": {
|
||||
"message": "Zjistěte více."
|
||||
},
|
||||
"lessThanMax": {
|
||||
"message": "musí být menší nebo roven $1.",
|
||||
"description": "helper for inputting hex as decimal input"
|
||||
},
|
||||
"likeToAddTokens": {
|
||||
"message": "Chcete přidat tyto tokeny?"
|
||||
},
|
||||
"links": {
|
||||
"message": "Odkazy"
|
||||
},
|
||||
"limit": {
|
||||
"message": "Limit"
|
||||
},
|
||||
"loading": {
|
||||
"message": "Načítám..."
|
||||
},
|
||||
"loadingTokens": {
|
||||
"message": "Načítám tokeny..."
|
||||
},
|
||||
"localhost": {
|
||||
"message": "Localhost 8545"
|
||||
},
|
||||
"login": {
|
||||
"message": "Přihlásit"
|
||||
},
|
||||
"logout": {
|
||||
"message": "Odhlásit"
|
||||
},
|
||||
"loose": {
|
||||
"message": "Nevázané"
|
||||
},
|
||||
"loweCaseWords": {
|
||||
"message": "slova klíčové fráze mají pouze malá písmena"
|
||||
},
|
||||
"mainnet": {
|
||||
"message": "Main Ethereum Network"
|
||||
},
|
||||
"message": {
|
||||
"message": "Zpráva"
|
||||
},
|
||||
"metamaskDescription": {
|
||||
"message": "MetaMask je bezpečný osobní trezor pro Ethereum."
|
||||
},
|
||||
"min": {
|
||||
"message": "Minimum"
|
||||
},
|
||||
"myAccounts": {
|
||||
"message": "Moje účty"
|
||||
},
|
||||
"mustSelectOne": {
|
||||
"message": "Musíte zvolit aspoň 1 token."
|
||||
},
|
||||
"needEtherInWallet": {
|
||||
"message": "Potřebujete Ether v peněžence, abyste mohli pomocí MetaMasku interagovat s decentralizovanými aplikacemi."
|
||||
},
|
||||
"needImportFile": {
|
||||
"message": "Musíte zvolit soubor k importu.",
|
||||
"description": "User is important an account and needs to add a file to continue"
|
||||
},
|
||||
"needImportPassword": {
|
||||
"message": "Musíte zadat heslo pro zvolený soubor.",
|
||||
"description": "Password and file needed to import an account"
|
||||
},
|
||||
"negativeETH": {
|
||||
"message": "Nelze odeslat zápornou částku ETH."
|
||||
},
|
||||
"networks": {
|
||||
"message": "Sítě"
|
||||
},
|
||||
"newAccount": {
|
||||
"message": "Nový účet"
|
||||
},
|
||||
"newAccountNumberName": {
|
||||
"message": "Účet $1",
|
||||
"description": "Default name of next account to be created on create account screen"
|
||||
},
|
||||
"newContract": {
|
||||
"message": "Nový kontrakt"
|
||||
},
|
||||
"newPassword": {
|
||||
"message": "Nové heslo (min 8 znaků)"
|
||||
},
|
||||
"newRecipient": {
|
||||
"message": "Nový příjemce"
|
||||
},
|
||||
"newRPC": {
|
||||
"message": "Nová RPC URL"
|
||||
},
|
||||
"next": {
|
||||
"message": "Další"
|
||||
},
|
||||
"noAddressForName": {
|
||||
"message": "Pro toto jméno nebyla nastavena žádná adresa."
|
||||
},
|
||||
"noDeposits": {
|
||||
"message": "Žádný vklad"
|
||||
},
|
||||
"noTransactionHistory": {
|
||||
"message": "Žádná historie transakcí."
|
||||
},
|
||||
"noTransactions": {
|
||||
"message": "Žádné transakce"
|
||||
},
|
||||
"notStarted": {
|
||||
"message": "Nezačalo"
|
||||
},
|
||||
"oldUI": {
|
||||
"message": "Staré rozhraní"
|
||||
},
|
||||
"oldUIMessage": {
|
||||
"message": "Vrátili jste se ke starému rozhraní. Můžete přepnout na nové rozhraní v nastavení v pravém horním menu."
|
||||
},
|
||||
"or": {
|
||||
"message": "nebo",
|
||||
"description": "choice between creating or importing a new account"
|
||||
},
|
||||
"passwordCorrect": {
|
||||
"message": "Ujistěte se, že je vaše heslo správně."
|
||||
},
|
||||
"passwordMismatch": {
|
||||
"message": "hesla nesouhlasí",
|
||||
"description": "in password creation process, the two new password fields did not match"
|
||||
},
|
||||
"passwordShort": {
|
||||
"message": "heslo je krátké",
|
||||
"description": "in password creation process, the password is not long enough to be secure"
|
||||
},
|
||||
"pastePrivateKey": {
|
||||
"message": "Vložte zde svůj privátní klíč:",
|
||||
"description": "For importing an account from a private key"
|
||||
},
|
||||
"pasteSeed": {
|
||||
"message": "Svou klíčovou frázi vložte zde!"
|
||||
},
|
||||
"personalAddressDetected": {
|
||||
"message": "Detekována osobní adresa. Zadejte adresu kontraktu tokenu."
|
||||
},
|
||||
"pleaseReviewTransaction": {
|
||||
"message": "Zkontrolujte si transakci."
|
||||
},
|
||||
"popularTokens": {
|
||||
"message": "Oblíbené tokeny"
|
||||
},
|
||||
"privacyMsg": {
|
||||
"message": "Zásady ochrany osobních údajů"
|
||||
},
|
||||
"privateKey": {
|
||||
"message": "Privátní klíč",
|
||||
"description": "select this type of file to use to import an account"
|
||||
},
|
||||
"privateKeyWarning": {
|
||||
"message": "Upozornění: Nikdy nezveřejněte tento klíč. Kdokoli může s vaším privátním klíčem odcizit vaše aktiva z účtu."
|
||||
},
|
||||
"privateNetwork": {
|
||||
"message": "Soukromá síť"
|
||||
},
|
||||
"qrCode": {
|
||||
"message": "Ukázat QR kód"
|
||||
},
|
||||
"readdToken": {
|
||||
"message": "Tento token můžete v budoucnu přidat zpět s „Přidat token“ v nastavení účtu."
|
||||
},
|
||||
"readMore": {
|
||||
"message": "Přečtěte si více zde."
|
||||
},
|
||||
"readMore2": {
|
||||
"message": "Přečtěte si více."
|
||||
},
|
||||
"receive": {
|
||||
"message": "Obrdžet"
|
||||
},
|
||||
"recipientAddress": {
|
||||
"message": "Adresa příjemce"
|
||||
},
|
||||
"refundAddress": {
|
||||
"message": "Adresa pro vrácení peněz"
|
||||
},
|
||||
"rejected": {
|
||||
"message": "Odmítnuto"
|
||||
},
|
||||
"resetAccount": {
|
||||
"message": "Resetovat účet"
|
||||
},
|
||||
"restoreFromSeed": {
|
||||
"message": "Obnovit z seed fráze"
|
||||
},
|
||||
"restoreVault": {
|
||||
"message": "Obnovit trezor"
|
||||
},
|
||||
"required": {
|
||||
"message": "Povinné"
|
||||
},
|
||||
"retryWithMoreGas": {
|
||||
"message": "Opakujte s vyšší cenou paliva"
|
||||
},
|
||||
"walletSeed": {
|
||||
"message": "Klíčová fráze peněženky"
|
||||
},
|
||||
"revealSeedWords": {
|
||||
"message": "Zobrazit slova klíčové fráze"
|
||||
},
|
||||
"revealSeedWordsWarning": {
|
||||
"message": "Nebnovujte slova klíčové fráze na veřejnosti! Tato slova mohou být použita k odcizení veškerých vyašich účtů."
|
||||
},
|
||||
"revert": {
|
||||
"message": "Zvrátit"
|
||||
},
|
||||
"rinkeby": {
|
||||
"message": "Rinkeby Test Network"
|
||||
},
|
||||
"ropsten": {
|
||||
"message": "Ropsten Test Network"
|
||||
},
|
||||
"currentRpc": {
|
||||
"message": "Současné RPC"
|
||||
},
|
||||
"connectingToMainnet": {
|
||||
"message": "Připojuji se k Main Ethereum Network"
|
||||
},
|
||||
"connectingToRopsten": {
|
||||
"message": "Připojuji se k Ropsten Test Network"
|
||||
},
|
||||
"connectingToKovan": {
|
||||
"message": "Připojuji se k Kovan Test Network"
|
||||
},
|
||||
"connectingToRinkeby": {
|
||||
"message": "Připojuji se k Rinkeby Test Network"
|
||||
},
|
||||
"connectingToUnknown": {
|
||||
"message": "Připojuji se k neznámé síti"
|
||||
},
|
||||
"sampleAccountName": {
|
||||
"message": "Např. můj nový účet",
|
||||
"description": "Help user understand concept of adding a human-readable name to their account"
|
||||
},
|
||||
"save": {
|
||||
"message": "Uložit"
|
||||
},
|
||||
"reprice_title": {
|
||||
"message": "Změnit cenu transakce"
|
||||
},
|
||||
"reprice_subtitle": {
|
||||
"message": "Navyšte cenu paliva ve snaze k přepsání a urychlení vyší transakce"
|
||||
},
|
||||
"saveAsFile": {
|
||||
"message": "Uložit do souboru",
|
||||
"description": "Account export process"
|
||||
},
|
||||
"saveSeedAsFile": {
|
||||
"message": "Uložit slova klíčové fráze do souboru"
|
||||
},
|
||||
"search": {
|
||||
"message": "Hledat"
|
||||
},
|
||||
"secretPhrase": {
|
||||
"message": "Zadejte svých 12 slov tajné fráze k obnovení trezoru."
|
||||
},
|
||||
"newPassword8Chars": {
|
||||
"message": "Nové heslo (min 8 znaků)"
|
||||
},
|
||||
"seedPhraseReq": {
|
||||
"message": "klíčové fráze mají 12 slov"
|
||||
},
|
||||
"select": {
|
||||
"message": "Vybrat"
|
||||
},
|
||||
"selectCurrency": {
|
||||
"message": "Vybrat měnu"
|
||||
},
|
||||
"selectService": {
|
||||
"message": "Vybrat službu"
|
||||
},
|
||||
"selectType": {
|
||||
"message": "Vybrat typ"
|
||||
},
|
||||
"send": {
|
||||
"message": "Odeslat"
|
||||
},
|
||||
"sendETH": {
|
||||
"message": "Odeslat ETH"
|
||||
},
|
||||
"sendTokens": {
|
||||
"message": "Odeslat tokeny"
|
||||
},
|
||||
"onlySendToEtherAddress": {
|
||||
"message": "Posílejte jen ETH na Ethereum adresu."
|
||||
},
|
||||
"searchTokens": {
|
||||
"message": "Hledat tokeny"
|
||||
},
|
||||
"sendTokensAnywhere": {
|
||||
"message": "Posílejte tokeny komukoli s Ethereum účtem"
|
||||
},
|
||||
"settings": {
|
||||
"message": "Nastavení"
|
||||
},
|
||||
"info": {
|
||||
"message": "Informace"
|
||||
},
|
||||
"shapeshiftBuy": {
|
||||
"message": "Nakoupit na ShapeShift"
|
||||
},
|
||||
"showPrivateKeys": {
|
||||
"message": "Zobrazit privátní klíče"
|
||||
},
|
||||
"showQRCode": {
|
||||
"message": "Zobrazit QR kód"
|
||||
},
|
||||
"sign": {
|
||||
"message": "Podepsat"
|
||||
},
|
||||
"signed": {
|
||||
"message": "Podepsáno"
|
||||
},
|
||||
"signMessage": {
|
||||
"message": "Podepsat zprávu"
|
||||
},
|
||||
"signNotice": {
|
||||
"message": "Podepsání zprávy může mít \nnebezpečný vedlejší učinek. Podepisujte zprávy pouze ze \nstránek, kterým plně důvěřujete celým svým účtem.\n Tato nebezpečná metoda bude odebrána v budoucí verzi. "
|
||||
},
|
||||
"sigRequest": {
|
||||
"message": "Požadavek podpisu"
|
||||
},
|
||||
"sigRequested": {
|
||||
"message": "Požádáno o podpis"
|
||||
},
|
||||
"spaceBetween": {
|
||||
"message": "mezi slovy může být pouze mezera"
|
||||
},
|
||||
"status": {
|
||||
"message": "Stav"
|
||||
},
|
||||
"stateLogs": {
|
||||
"message": "Stavové protokoly"
|
||||
},
|
||||
"stateLogsDescription": {
|
||||
"message": "Stavové protokoly obsahují vaše veřejné adresy účtů a odeslané transakce."
|
||||
},
|
||||
"stateLogError": {
|
||||
"message": "Chyba během získávání stavových protokolů."
|
||||
},
|
||||
"submit": {
|
||||
"message": "Odeslat"
|
||||
},
|
||||
"submitted": {
|
||||
"message": "Odesláno"
|
||||
},
|
||||
"supportCenter": {
|
||||
"message": "Navštivte naše centrum podpory"
|
||||
},
|
||||
"symbolBetweenZeroTen": {
|
||||
"message": "Symbol musí být mezi 0 a 10 znaky."
|
||||
},
|
||||
"takesTooLong": {
|
||||
"message": "Trvá to dlouho?"
|
||||
},
|
||||
"terms": {
|
||||
"message": "Podmínky použití"
|
||||
},
|
||||
"testFaucet": {
|
||||
"message": "Testovací faucet"
|
||||
},
|
||||
"to": {
|
||||
"message": "Komu: "
|
||||
},
|
||||
"toETHviaShapeShift": {
|
||||
"message": "$1 na ETH přes ShapeShift",
|
||||
"description": "system will fill in deposit type in start of message"
|
||||
},
|
||||
"tokenAddress": {
|
||||
"message": "Adresa tokenu"
|
||||
},
|
||||
"tokenAlreadyAdded": {
|
||||
"message": "Token byl už přidán."
|
||||
},
|
||||
"tokenBalance": {
|
||||
"message": "Váš zůstatek tokenu je:"
|
||||
},
|
||||
"tokenSelection": {
|
||||
"message": "Vyhledejte token nebo je vyberte z našeho seznamu oblíbených tokenů."
|
||||
},
|
||||
"tokenSymbol": {
|
||||
"message": "Symbol tokenu"
|
||||
},
|
||||
"tokenWarning1": {
|
||||
"message": "Mějte přehled o tokenech, které jste koupili s účtem MetaMasku. Pokud jste koupili tokeny s jiným účtem, tyto tokeny se zde nezobrazí."
|
||||
},
|
||||
"total": {
|
||||
"message": "Celkem"
|
||||
},
|
||||
"transactions": {
|
||||
"message": "transakce"
|
||||
},
|
||||
"transactionError": {
|
||||
"message": "Chyba transakce. Vyhozena výjimka v kódu kontraktu."
|
||||
},
|
||||
"transactionMemo": {
|
||||
"message": "Poznámka transakce (nepovinné)"
|
||||
},
|
||||
"transactionNumber": {
|
||||
"message": "Číslo transakce"
|
||||
},
|
||||
"transfers": {
|
||||
"message": "Převody"
|
||||
},
|
||||
"troubleTokenBalances": {
|
||||
"message": "Měli jsme problém s načtením vašich tokenových zůstatků. Můžete je vidět ",
|
||||
"description": "Followed by a link (here) to view token balances"
|
||||
},
|
||||
"twelveWords": {
|
||||
"message": "Těchto 12 slov je jedinou možností, jak obnovit MetaMask účet. \nUložte je na bezpečné a neveřejné místo."
|
||||
},
|
||||
"typePassword": {
|
||||
"message": "Zadejte své heslo"
|
||||
},
|
||||
"uiWelcome": {
|
||||
"message": "Vítejte v novém rozhraní (Beta)"
|
||||
},
|
||||
"uiWelcomeMessage": {
|
||||
"message": "Používáte nyní nové rozhraní MetaMasku. Rozhlédněte se kolem, vyzkoušejte nové funkce, jako jsou zasílání tokenů, a dejte nám vědět, pokud narazíte na problém."
|
||||
},
|
||||
"unapproved": {
|
||||
"message": "Neschváleno"
|
||||
},
|
||||
"unavailable": {
|
||||
"message": "Nedostupné"
|
||||
},
|
||||
"unknown": {
|
||||
"message": "Neznámé"
|
||||
},
|
||||
"unknownNetwork": {
|
||||
"message": "Neznámá soukromá síť"
|
||||
},
|
||||
"unknownNetworkId": {
|
||||
"message": "Neznámé ID sítě"
|
||||
},
|
||||
"uriErrorMsg": {
|
||||
"message": "URI vyžadují korektní HTTP/HTTPS prefix."
|
||||
},
|
||||
"usaOnly": {
|
||||
"message": "jen v USA",
|
||||
"description": "Using this exchange is limited to people inside the USA"
|
||||
},
|
||||
"usedByClients": {
|
||||
"message": "Používána různými klienty"
|
||||
},
|
||||
"useOldUI": {
|
||||
"message": "Použijte staré rozhraní"
|
||||
},
|
||||
"validFileImport": {
|
||||
"message": "Musíte vybrat validní soubor k importu."
|
||||
},
|
||||
"vaultCreated": {
|
||||
"message": "Trezor vytvořen"
|
||||
},
|
||||
"viewAccount": {
|
||||
"message": "Zobrazit účet"
|
||||
},
|
||||
"visitWebSite": {
|
||||
"message": "Navštivte naši stránku"
|
||||
},
|
||||
"warning": {
|
||||
"message": "Varování"
|
||||
},
|
||||
"welcomeBeta": {
|
||||
"message": "Vítejte v MetaMask Beta"
|
||||
},
|
||||
"whatsThis": {
|
||||
"message": "Co to je?"
|
||||
},
|
||||
"yourSigRequested": {
|
||||
"message": "Je vyžadován váš podpis"
|
||||
},
|
||||
"youSign": {
|
||||
"message": "Podepisujete"
|
||||
}
|
||||
}
|
@ -908,5 +908,8 @@
|
||||
},
|
||||
"youSign": {
|
||||
"message": "You are signing"
|
||||
},
|
||||
"generatingTransaction": {
|
||||
"message": "Generating transaction"
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
"message": "खाता विवरण"
|
||||
},
|
||||
"accountName": {
|
||||
"message": "खाता का नाम"
|
||||
"message": "खाते का नाम"
|
||||
},
|
||||
"address": {
|
||||
"message": "खाते का पता"
|
||||
@ -21,7 +21,7 @@
|
||||
"message": "टोकन जोड़ें"
|
||||
},
|
||||
"addTokens": {
|
||||
"message": "टोकनो को जोड़ें"
|
||||
"message": "टोकनों को जोड़ें"
|
||||
},
|
||||
"amount": {
|
||||
"message": "राशि"
|
||||
@ -30,7 +30,7 @@
|
||||
"message": "राशि + गैस"
|
||||
},
|
||||
"appDescription": {
|
||||
"message": "एथरेम ब्राउज़र एक्सटेंशन",
|
||||
"message": "इथीरियम ब्राउज़र एक्सटेंशन",
|
||||
"description": "आवेदन का विवरण"
|
||||
},
|
||||
"appName": {
|
||||
@ -53,7 +53,7 @@
|
||||
"message": "उपलब्ध बैलेंस।"
|
||||
},
|
||||
"balances": {
|
||||
"message": "ापके उपलब्ध बैलेंस"
|
||||
"message": "आपके उपलब्ध बैलेंस"
|
||||
},
|
||||
"balanceIsInsufficientGas": {
|
||||
"message": "वर्तमान गैस कुल के लिए अपर्याप्त शेष"
|
||||
@ -78,10 +78,10 @@
|
||||
"message": "खरीदें"
|
||||
},
|
||||
"buyCoinbase": {
|
||||
"message": "कॉनबेस पर खरीदें"
|
||||
"message": "कॉइनबेस पर खरीदें"
|
||||
},
|
||||
"buyCoinbaseExplainer": {
|
||||
"message": "बिल्टकोइन, एथरेम और लाइटकोइन खरीदने और बेचने के लिए दुनिया का सबसे लोकप्रिय तरीका Coinbase है।"
|
||||
"message": "बिल्टकोइन, इथीरियम और लाइटकोइन खरीदने और बेचने के लिए दुनिया का सबसे लोकप्रिय तरीका कॉइनबेस है।"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "रद्द करें"
|
||||
@ -108,7 +108,7 @@
|
||||
"message": "जारी रखें"
|
||||
},
|
||||
"continueToCoinbase": {
|
||||
"message": "कॉ्ोनबेस को ब्हेजना जारी रखें"
|
||||
"message": "कॉइनबेस को ब्हेजना जारी रखें"
|
||||
},
|
||||
"contractDeployment": {
|
||||
"message": "अनुबंध परिनियोजन व तैनाती"
|
||||
@ -435,13 +435,13 @@
|
||||
"message": "बीज शब्द में केवल लोअरकेस वर्ण होते हैं"
|
||||
},
|
||||
"mainnet": {
|
||||
"message": "मुख्य ईथरम नेटवर्क"
|
||||
"message": "मुख्य इथीरियम नेटवर्क"
|
||||
},
|
||||
"message": {
|
||||
"message": "संदेश"
|
||||
},
|
||||
"metamaskDescription": {
|
||||
"message": "मेटामास्क एथर्मम के लिए एक सुरक्षित पहचान वॉल्ट है।"
|
||||
"message": "मेटामास्क इथीरियम के लिए एक सुरक्षित पहचान वॉल्ट है।"
|
||||
},
|
||||
"min": {
|
||||
"message": "न्यूनतम"
|
||||
@ -649,7 +649,7 @@
|
||||
"message": "भेजें टोकन"
|
||||
},
|
||||
"sendTokensAnywhere": {
|
||||
"message": "इटोरम खाते वाले किसी को भी टोकन भेजें"
|
||||
"message": "इथीरियम खाते वाले किसी को भी टोकन भेजें"
|
||||
},
|
||||
"settings": {
|
||||
"message": "सेटिंग्स"
|
||||
|
@ -1,4 +1,5 @@
|
||||
[
|
||||
{ "code": "cs", "name": "Czech" },
|
||||
{ "code": "de", "name": "German" },
|
||||
{ "code": "en", "name": "English" },
|
||||
{ "code": "es", "name": "Spanish" },
|
||||
@ -13,6 +14,8 @@
|
||||
{ "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": "Mandarin" },
|
||||
{ "code": "zh_TW", "name": "Taiwanese" }
|
||||
|
@ -20,6 +20,9 @@
|
||||
"addToken": {
|
||||
"message": "トークンを追加"
|
||||
},
|
||||
"addTokens": {
|
||||
"message": "トークンを追加"
|
||||
},
|
||||
"amount": {
|
||||
"message": "金額"
|
||||
},
|
||||
@ -46,6 +49,9 @@
|
||||
"balance": {
|
||||
"message": "残高:"
|
||||
},
|
||||
"balances": {
|
||||
"message": "トークン残高"
|
||||
},
|
||||
"balanceIsInsufficientGas": {
|
||||
"message": "現在のガス総量に対して残高が不足しています"
|
||||
},
|
||||
@ -63,10 +69,10 @@
|
||||
"message": "購入"
|
||||
},
|
||||
"buyCoinbase": {
|
||||
"message": "Coinbaseで購入"
|
||||
"message": "Coinbaseのサイトで購入"
|
||||
},
|
||||
"buyCoinbaseExplainer": {
|
||||
"message": "Coinbaseは、世界的なBitcoin、Ethereum、そしてLitecoinの取引所です。"
|
||||
"message": "Etherを購入できます。Coinbaseは、世界的なBitcoin、Ethereum、そしてLitecoinの取引所です。"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "キャンセル"
|
||||
@ -90,7 +96,7 @@
|
||||
"message": "トランザクションの確認"
|
||||
},
|
||||
"continueToCoinbase": {
|
||||
"message": "Coinbaseで続行"
|
||||
"message": "Coinbaseを開く"
|
||||
},
|
||||
"contractDeployment": {
|
||||
"message": "コントラクトのデプロイ"
|
||||
@ -138,6 +144,9 @@
|
||||
"customGas": {
|
||||
"message": "ガスのカスタマイズ"
|
||||
},
|
||||
"customToken": {
|
||||
"message": "カスタムトークン"
|
||||
},
|
||||
"customize": {
|
||||
"message": "カスタマイズ"
|
||||
},
|
||||
@ -154,20 +163,20 @@
|
||||
"message": "DENとは、あなたのパスワードが暗号化されたMetaMask内のストレージです。"
|
||||
},
|
||||
"deposit": {
|
||||
"message": "受取り"
|
||||
"message": "振込"
|
||||
},
|
||||
"depositBTC": {
|
||||
"message": "あなたのBTCを次のアドレスへデポジット:"
|
||||
"message": "BTCを下記のアドレスへ振込んでください:"
|
||||
},
|
||||
"depositCoin": {
|
||||
"message": "あなたの $1を次のアドレスへデポジット",
|
||||
"message": "$1を下記のアドレスへ振込んでください",
|
||||
"description": "Tells the user what coin they have selected to deposit with shapeshift"
|
||||
},
|
||||
"depositEth": {
|
||||
"message": "ETHをデポジット"
|
||||
"message": "ETHを入金"
|
||||
},
|
||||
"depositEther": {
|
||||
"message": "Etherをデポジット"
|
||||
"message": "Etherを振込"
|
||||
},
|
||||
"depositFiat": {
|
||||
"message": "法定通貨でデポジット"
|
||||
@ -176,10 +185,10 @@
|
||||
"message": "別のアカウントから入金"
|
||||
},
|
||||
"depositShapeShift": {
|
||||
"message": "ShapeShiftで入金"
|
||||
"message": "ShapeShiftで交換"
|
||||
},
|
||||
"depositShapeShiftExplainer": {
|
||||
"message": "他の暗号通貨をEtherと交換してMetaMaskのウォレットへ入金できます。アカウント作成は不要です。"
|
||||
"message": "他の暗号通貨とEtherを交換して、MetaMaskのウォレットへ入金できます。アカウント作成は不要です。"
|
||||
},
|
||||
"details": {
|
||||
"message": "詳細"
|
||||
@ -188,10 +197,10 @@
|
||||
"message": "ダイレクトデポジット"
|
||||
},
|
||||
"directDepositEther": {
|
||||
"message": "Etherを直接受け取り"
|
||||
"message": "Etherを直接入金"
|
||||
},
|
||||
"directDepositEtherExplainer": {
|
||||
"message": "Etherをすでにお持ちなら、MetaMaskの新しいウォレットにEtherを送信することができます。"
|
||||
"message": "既にEtherをお持ちなら、MetaMaskの新しいウォレットにEtherを送信することができます。"
|
||||
},
|
||||
"done": {
|
||||
"message": "完了"
|
||||
@ -209,7 +218,7 @@
|
||||
"message": "パスワードを入力"
|
||||
},
|
||||
"etherscanView": {
|
||||
"message": "Etherscanでアカウントを参照"
|
||||
"message": "Etherscanでアカウントを確認"
|
||||
},
|
||||
"exchangeRate": {
|
||||
"message": "交換レート"
|
||||
@ -266,7 +275,7 @@
|
||||
"message": "必要ガスプライス"
|
||||
},
|
||||
"getEther": {
|
||||
"message": "Etherをゲット"
|
||||
"message": "Etherを取得する"
|
||||
},
|
||||
"getEtherFromFaucet": {
|
||||
"message": "フォーセットで $1のEtherを得ることができます。",
|
||||
@ -287,7 +296,7 @@
|
||||
"message": "トークンを隠す"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "トークンを隠しますか??"
|
||||
"message": "トークンを隠しますか?"
|
||||
},
|
||||
"howToDeposit": {
|
||||
"message": "どのようにEtherをデポジットしますか?"
|
||||
@ -300,7 +309,7 @@
|
||||
"message": "アカウントのインポート"
|
||||
},
|
||||
"importAccountMsg": {
|
||||
"message":"追加したアカウントはMetaMaskのアカウントシードフレーズとは関連付けられません。インポートしたアカウントについての詳細は"
|
||||
"message":"追加したアカウントはMetaMaskのアカウントパスフレーズとは関連付けられません。インポートしたアカウントについての詳細は"
|
||||
},
|
||||
"importAnAccount": {
|
||||
"message": "アカウントをインポート"
|
||||
@ -334,13 +343,22 @@
|
||||
"message": "JSONファイル",
|
||||
"description": "format for importing an account"
|
||||
},
|
||||
"keepTrackTokens": {
|
||||
"message": "MetaMaskアカウントで入手したトークンを検索できます。"
|
||||
},
|
||||
"kovan": {
|
||||
"message": "Kovanテストネットワーク"
|
||||
},
|
||||
"learnMore": {
|
||||
"message": "詳細"
|
||||
},
|
||||
"lessThanMax": {
|
||||
"message": " $1以下にして下さい。",
|
||||
"description": "helper for inputting hex as decimal input"
|
||||
},
|
||||
"likeToAddTokens": {
|
||||
"message": "トークンを追加しますか?"
|
||||
},
|
||||
"limit": {
|
||||
"message": "リミット"
|
||||
},
|
||||
@ -371,8 +389,11 @@
|
||||
"myAccounts": {
|
||||
"message": "マイアカウント"
|
||||
},
|
||||
"mustSelectOne": {
|
||||
"message": "一つ以上のトークンを選択してください。"
|
||||
},
|
||||
"needEtherInWallet": {
|
||||
"message": "MetaMaskを使って分散型アプリケーションを使用するためには、このウォレットにEtherが必要です。"
|
||||
"message": "MetaMaskで分散型アプリケーションを使用するためには、このウォレットにEtherが必要です。"
|
||||
},
|
||||
"needImportFile": {
|
||||
"message": "インポートするファイルを選択してください。",
|
||||
@ -411,7 +432,7 @@
|
||||
"message": "この名前にはアドレスが設定されていません。"
|
||||
},
|
||||
"noDeposits": {
|
||||
"message": "デポジットがありません。"
|
||||
"message": "振込みがありません。"
|
||||
},
|
||||
"noTransactionHistory": {
|
||||
"message": "トランザクション履歴がありません。"
|
||||
@ -445,10 +466,13 @@
|
||||
"description": "For importing an account from a private key"
|
||||
},
|
||||
"pasteSeed": {
|
||||
"message": "シードをここにペーストして下さい!"
|
||||
"message": "パスフレーズをここにペーストして下さい!"
|
||||
},
|
||||
"pleaseReviewTransaction": {
|
||||
"message": "トランザクションをレビューして下さい。"
|
||||
"message": "トランザクションを確認して下さい。"
|
||||
},
|
||||
"popularTokens": {
|
||||
"message": "人気のトークン"
|
||||
},
|
||||
"privateKey": {
|
||||
"message": "秘密鍵",
|
||||
@ -470,13 +494,13 @@
|
||||
"message": "もっと読む"
|
||||
},
|
||||
"receive": {
|
||||
"message": "受け取る"
|
||||
"message": "受取"
|
||||
},
|
||||
"recipientAddress": {
|
||||
"message": "受取人アドレス"
|
||||
},
|
||||
"refundAddress": {
|
||||
"message": "あなたの返金先アドレス"
|
||||
"message": "受取アドレス"
|
||||
},
|
||||
"rejected": {
|
||||
"message": "拒否されました"
|
||||
@ -487,12 +511,18 @@
|
||||
"restoreFromSeed": {
|
||||
"message": "パスフレーズから復元する"
|
||||
},
|
||||
"restoreVault": {
|
||||
"message": "ウォレットを復元する"
|
||||
},
|
||||
"required": {
|
||||
"message": "必要です。"
|
||||
},
|
||||
"retryWithMoreGas": {
|
||||
"message": "より高いガスプライスで再度試して下さい。"
|
||||
},
|
||||
"walletSeed": {
|
||||
"message": "ウォレットのパスフレーズ"
|
||||
},
|
||||
"revealSeedWords": {
|
||||
"message": "パスフレーズを表示"
|
||||
},
|
||||
@ -519,23 +549,35 @@
|
||||
"selectService": {
|
||||
"message": "サービスを選択"
|
||||
},
|
||||
"selectType": {
|
||||
"message": "キーの種類"
|
||||
},
|
||||
"send": {
|
||||
"message": "送信"
|
||||
},
|
||||
"sendETH": {
|
||||
"message": "ETHの送信"
|
||||
},
|
||||
"sendTokens": {
|
||||
"message": "トークンを送る"
|
||||
},
|
||||
"onlySendToEtherAddress": {
|
||||
"message": "ETHはイーサリウムアカウントのみに送信できます。"
|
||||
},
|
||||
"searchTokens": {
|
||||
"message": "トークンの検索"
|
||||
},
|
||||
"sendTokensAnywhere": {
|
||||
"message": "イーサリアムアカウントを持っている人にトークンを送る"
|
||||
},
|
||||
"settings": {
|
||||
"message": "設定"
|
||||
},
|
||||
"info": {
|
||||
"message": "情報"
|
||||
},
|
||||
"shapeshiftBuy": {
|
||||
"message": "Shapeshiftで買う"
|
||||
"message": "Shapeshiftで交換"
|
||||
},
|
||||
"showPrivateKeys": {
|
||||
"message": "秘密鍵を表示"
|
||||
@ -565,13 +607,13 @@
|
||||
"message": "送信"
|
||||
},
|
||||
"takesTooLong": {
|
||||
"message": "長くかかりすぎていますか?"
|
||||
"message": "送信に時間がかかりますか?"
|
||||
},
|
||||
"testFaucet": {
|
||||
"message": "Faucetをテスト"
|
||||
},
|
||||
"to": {
|
||||
"message": "宛先"
|
||||
"message": "送信先"
|
||||
},
|
||||
"toETHviaShapeShift": {
|
||||
"message": "ShapeShiftで $1をETHにする",
|
||||
@ -595,6 +637,9 @@
|
||||
"total": {
|
||||
"message": "合計"
|
||||
},
|
||||
"transactions": {
|
||||
"message": "トランザクション"
|
||||
},
|
||||
"transactionMemo": {
|
||||
"message": "トランザクションメモ (オプション)"
|
||||
},
|
||||
@ -609,7 +654,7 @@
|
||||
"description": "Followed by a link (here) to view token balances"
|
||||
},
|
||||
"typePassword": {
|
||||
"message": "パスワードタイプ"
|
||||
"message": "パスワードの入力"
|
||||
},
|
||||
"uiWelcome": {
|
||||
"message": "新UIへようこそ!(ベータ版)"
|
||||
@ -646,7 +691,7 @@
|
||||
"message": "警告"
|
||||
},
|
||||
"whatsThis": {
|
||||
"message": "これは何でしょう?"
|
||||
"message": "この機能について"
|
||||
},
|
||||
"yourSigRequested": {
|
||||
"message": "あなたの署名がリクエストされています。"
|
||||
|
912
app/_locales/tml/messages.json
Normal file
912
app/_locales/tml/messages.json
Normal file
@ -0,0 +1,912 @@
|
||||
{
|
||||
"accept": {
|
||||
"message": "ஏற்கவும்"
|
||||
},
|
||||
"account": {
|
||||
"message": "கணக்கு"
|
||||
},
|
||||
"accountDetails": {
|
||||
"message": "கணக்கு விவரங்கள்"
|
||||
},
|
||||
"accountName": {
|
||||
"message": "கணக்கின் பெயர்"
|
||||
},
|
||||
"address": {
|
||||
"message": "முகவரி"
|
||||
},
|
||||
"addCustomToken": {
|
||||
"message": "தனிப்பயன் டோக்கனைச் சேர்க்கவும்"
|
||||
},
|
||||
"addToken": {
|
||||
"message": "டோக்கனைச் சேர்"
|
||||
},
|
||||
"addTokens": {
|
||||
"message": "டோக்கன்களைச் சேர்"
|
||||
},
|
||||
"amount": {
|
||||
"message": "தொகை"
|
||||
},
|
||||
"amountPlusGas": {
|
||||
"message": "தொகை + எரிவாயு"
|
||||
},
|
||||
"appDescription": {
|
||||
"message": "எதெரியும் பிரௌசர் நீட்டிப்பு",
|
||||
"description": "பயன்பாட்டின் விளக்கம்"
|
||||
},
|
||||
"appName": {
|
||||
"message": "மேடமஸ்க் ",
|
||||
"description": "பயன்பாட்டின் பெயர்"
|
||||
},
|
||||
"approved": {
|
||||
"message": "அங்கீகரிக்கப்பட்ட"
|
||||
},
|
||||
"attemptingConnect": {
|
||||
"message": "இணைக்க முயற்சி செய்க ப்ளாக்சைன்"
|
||||
},
|
||||
"attributions": {
|
||||
"message": "பண்புகளும்"
|
||||
},
|
||||
"available": {
|
||||
"message": "கிடைக்கும்"
|
||||
},
|
||||
"back": {
|
||||
"message": "மீண்டும்"
|
||||
},
|
||||
"balance": {
|
||||
"message": "இருப்பு:"
|
||||
},
|
||||
"balances": {
|
||||
"message": "உங்கள் இருப்பு"
|
||||
},
|
||||
"balanceIsInsufficientGas": {
|
||||
"message": "நடப்பு வாயு மொத்தம் போதுமான சமநிலை"
|
||||
},
|
||||
"beta": {
|
||||
"message": "பீட்டா"
|
||||
},
|
||||
"betweenMinAndMax": {
|
||||
"message": "$ 1 க்கும் அதிகமாகவும் அல்லது $ 2 க்கு சமமாகவும் இருக்க வேண்டும்.",
|
||||
"description": "ஹெக்ஸ் உள்ளீடு தசம உள்ளீடு என உதவி"
|
||||
},
|
||||
"blockiesIdenticon": {
|
||||
"message": "ப்ளாக்கிஸ் ஐடென்டிகோன் பயன்பாட்டு"
|
||||
},
|
||||
"borrowDharma": {
|
||||
"message": "தர்மத்துடன் கடன் வாங்குங்கள் (பீட்டா)"
|
||||
},
|
||||
"builtInCalifornia": {
|
||||
"message": "மேடமஸ்க் வடிவமைக்கப்பட்டு கலிபோர்னியாவில் கட்டப்பட்டுள்ளது."
|
||||
},
|
||||
"buy": {
|
||||
"message": "வாங்க"
|
||||
},
|
||||
"buyCoinbase": {
|
||||
"message": "கோஇன்பசே வாங்கவும்"
|
||||
},
|
||||
"buyCoinbaseExplainer": {
|
||||
"message": "கோஇன்பசே பிறகாய்ன் , எதெரியும் மற்றும் ளிட்டசோன் வாங்க மற்றும் விற்க உலகின் மிகவும் பிரபலமான வழி"
|
||||
},
|
||||
"ok": {
|
||||
"message": "சரி"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "ரத்து"
|
||||
},
|
||||
"classicInterface": {
|
||||
"message": "கிளாசிக் இடைமுகத்தைப் பயன்படுத்தவும்"
|
||||
},
|
||||
"clickCopy": {
|
||||
"message": "நகலெடுக்க கிளிக் செய்யவும்"
|
||||
},
|
||||
"confirm": {
|
||||
"message": "உறுதிப்படுத்தவும்"
|
||||
},
|
||||
"confirmed": {
|
||||
"message": "உறுதி"
|
||||
},
|
||||
"confirmContract": {
|
||||
"message": "ஒப்பந்தத்தை உறுதிப்படுத்துக"
|
||||
},
|
||||
"confirmPassword": {
|
||||
"message": "கடவுச்சொல்லை உறுதிப்படுத்துக"
|
||||
},
|
||||
"confirmTransaction": {
|
||||
"message": "பரிவர்த்தனை உறுதிபடுத்தவும்"
|
||||
},
|
||||
"continue": {
|
||||
"message": "தொடர்ந்து"
|
||||
},
|
||||
"continueToCoinbase": {
|
||||
"message": "கோஇன்பசே ஐத் தொடரவும்"
|
||||
},
|
||||
"contractDeployment": {
|
||||
"message": "ஒப்பந்த வரிசைப்படுத்தல்"
|
||||
},
|
||||
"conversionProgress": {
|
||||
"message": "மாற்றம் முன்னேற்றம்"
|
||||
},
|
||||
"copiedButton": {
|
||||
"message": "நகலெடுக்கப்பட்டன"
|
||||
},
|
||||
"copiedClipboard": {
|
||||
"message": "கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது"
|
||||
},
|
||||
"copiedExclamation": {
|
||||
"message": "நகலெடுக்கப்பட்டன!"
|
||||
},
|
||||
"copiedSafe": {
|
||||
"message": "நான் எங்காவது பாதுகாப்பாக நகலெடுத்திருக்கிறேன்"
|
||||
},
|
||||
"copy": {
|
||||
"message": "நகல்"
|
||||
},
|
||||
"copyToClipboard": {
|
||||
"message": "கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது"
|
||||
},
|
||||
"copyButton": {
|
||||
"message": " நகல் "
|
||||
},
|
||||
"copyPrivateKey": {
|
||||
"message": "இது உங்கள் தனிப்பட்ட விசை (நகலெடுக்க கிளிக் செய்யவும்)"
|
||||
},
|
||||
"create": {
|
||||
"message": "உருவாக்கவும்"
|
||||
},
|
||||
"createAccount": {
|
||||
"message": "உங்கள் கணக்கை துவங்குங்கள்"
|
||||
},
|
||||
"createDen": {
|
||||
"message": "உருவாக்கவும்"
|
||||
},
|
||||
"crypto": {
|
||||
"message": "கிரிப்டோ",
|
||||
"description": "பரிமாற்ற வகை (கிரிப்டோசுர்ரென்சிஸ்)"
|
||||
},
|
||||
"currentConversion": {
|
||||
"message": "தற்போதைய மாற்றம்"
|
||||
},
|
||||
"currentNetwork": {
|
||||
"message": "தற்போதைய நெட்வொர்க்"
|
||||
},
|
||||
"customGas": {
|
||||
"message": "எரிவாயுவைத் தனிப்பயனாக்குங்கள்"
|
||||
},
|
||||
"customToken": {
|
||||
"message": "தனிப்பயன் டோக்கன்"
|
||||
},
|
||||
"customize": {
|
||||
"message": "தனிப்பயனாக்கலாம்"
|
||||
},
|
||||
"customRPC": {
|
||||
"message": "விருப்ப RPC ஐ"
|
||||
},
|
||||
"decimalsMustZerotoTen": {
|
||||
"message": "தசமங்கள் குறைந்தபட்சம் 0, மற்றும் 36 க்கு மேல் இருக்க வேண்டும்."
|
||||
},
|
||||
"decimal": {
|
||||
"message": "துல்லியத்தின் முடிவு"
|
||||
},
|
||||
"defaultNetwork": {
|
||||
"message": "எதிர் பரிவர்த்தனைகளுக்கான முன்னிருப்பு வலையமைப்பு முதன்மை நிகரமாகும்."
|
||||
},
|
||||
"denExplainer": {
|
||||
"message": "உங்கள் DEN என்பது உங்கள் கடவுச்சொல்-மறைகுறியாக்கப்பட்ட சேமிப்பகம் மெட்டாமாஸ்க்கிற்குள்."
|
||||
},
|
||||
"deposit": {
|
||||
"message": "வைப்புத்தொகை"
|
||||
},
|
||||
"depositBTC": {
|
||||
"message": "கீழே உங்கள் முகவரிக்கு உங்கள் BTC வைப்போம்:"
|
||||
},
|
||||
"depositCoin": {
|
||||
"message": "உங்கள் முகவரிக்கு $ 1 ஐ கீழே உள்ளிடவும்",
|
||||
"description": "சேபஷிபிட் உடன் வைப்புக்குத் தேர்ந்தெடுக்கப்பட்ட நாணயத்தை பயனரிடம் கூறுகிறார்"
|
||||
},
|
||||
"depositEth": {
|
||||
"message": "வைப்புத்தொகை எது "
|
||||
},
|
||||
"depositEther": {
|
||||
"message": "வைப்புத்தொகை எதிர் "
|
||||
},
|
||||
"depositFiat": {
|
||||
"message": "ஃபியட் உடன் வைப்பு"
|
||||
},
|
||||
"depositFromAccount": {
|
||||
"message": "மற்றொரு கணக்கிலிருந்து வைப்பு"
|
||||
},
|
||||
"depositShapeShift": {
|
||||
"message": "ShapeShift உடன் வைப்பு"
|
||||
},
|
||||
"depositShapeShiftExplainer": {
|
||||
"message": "நீங்கள் மற்ற கிரிப்டோகிராரன்கள் சொந்தமாக வைத்திருந்தால், உங்கள் மெட்டாமாஸ்க் பணப்பையில் நேரடியாக ஈதரை வர்த்தகம் செய்யலாம் மற்றும் வைப்பு செய்யலாம். கணக்கு தேவையில்லை."
|
||||
},
|
||||
"details": {
|
||||
"message": "விவரங்கள்"
|
||||
},
|
||||
"directDeposit": {
|
||||
"message": "நேரடி வைப்பு"
|
||||
},
|
||||
"directDepositEther": {
|
||||
"message": "நேரடியாக வைப்புத்தொகை"
|
||||
},
|
||||
"directDepositEtherExplainer": {
|
||||
"message": "நீங்கள் ஏற்கனவே ஏதெர் இருந்தால், நேரடி வைப்பு மூலம் உங்கள் புதிய பணப்பையில் ஈத்தர் பெற விரைவான வழி."
|
||||
},
|
||||
"done": {
|
||||
"message": "முடிந்தது"
|
||||
},
|
||||
"downloadStateLogs": {
|
||||
"message": "மாநில பதிவுகள் பதிவிறக்க"
|
||||
},
|
||||
"dropped": {
|
||||
"message": "நீக்கப்பட்டார்"
|
||||
},
|
||||
"edit": {
|
||||
"message": "தொகு"
|
||||
},
|
||||
"editAccountName": {
|
||||
"message": "கணக்கு பெயரை மாற்றுக"
|
||||
},
|
||||
"emailUs": {
|
||||
"message": "எங்களுக்கு மின்னஞ்சல்!"
|
||||
},
|
||||
"encryptNewDen": {
|
||||
"message": "உங்கள் புதிய DEN ஐ குறியாக்குக"
|
||||
},
|
||||
"enterPassword": {
|
||||
"message": "கடவுச்சொல்லை உள்ளிடவும்"
|
||||
},
|
||||
"enterPasswordConfirm": {
|
||||
"message": "உறுதிப்படுத்த உங்கள் கடவுச்சொல்லை உள்ளிடவும்"
|
||||
},
|
||||
"passwordNotLongEnough": {
|
||||
"message": "கடவுச்சொல் போதாது"
|
||||
},
|
||||
"passwordsDontMatch": {
|
||||
"message": "கடவுச்சொற்கள் பொருந்தாதே"
|
||||
},
|
||||
"etherscanView": {
|
||||
"message": "Etherscan கணக்கைப் பார்க்கவும்"
|
||||
},
|
||||
"exchangeRate": {
|
||||
"message": "மாற்று விகிதம்"
|
||||
},
|
||||
"exportPrivateKey": {
|
||||
"message": "தனியார் விசை ஐ ஏற்றுமதி செய்க"
|
||||
},
|
||||
"exportPrivateKeyWarning": {
|
||||
"message": "தனிப்பட்ட விசைகளை உங்கள் சொந்த ஆபத்தில் ஏற்றுமதி செய்யுங்கள்."
|
||||
},
|
||||
"failed": {
|
||||
"message": "தோல்வி"
|
||||
},
|
||||
"fiat": {
|
||||
"message": "FIAT",
|
||||
"description": "பரிமாற்ற வகை"
|
||||
},
|
||||
"fileImportFail": {
|
||||
"message": "கோப்பு இறக்குமதி வேலை செய்யவில்லையா? இங்கே கிளிக் செய்யவும்!",
|
||||
"description": "JSON கோப்பில் பயனர் கணக்கை தங்கள் கணக்கை இறக்குமதி செய்ய உதவுகிறது"
|
||||
},
|
||||
"followTwitter": {
|
||||
"message": "Twitter இல் எங்களைப் பின்தொடரவும்"
|
||||
},
|
||||
"from": {
|
||||
"message": "இருந்து"
|
||||
},
|
||||
"fromToSame": {
|
||||
"message": "இருந்து மற்றும் முகவரி அதே இருக்க முடியாது"
|
||||
},
|
||||
"fromShapeShift": {
|
||||
"message": "ShapeShift இலிருந்து"
|
||||
},
|
||||
"gas": {
|
||||
"message": "எரிவாயு",
|
||||
"description": "எரிவாயு விலை குறையும்"
|
||||
},
|
||||
"gasFee": {
|
||||
"message": "எரிவாயு கட்டணம்"
|
||||
},
|
||||
"gasLimit": {
|
||||
"message": "எரிவாயு வரம்பு"
|
||||
},
|
||||
"gasLimitCalculation": {
|
||||
"message": "நெட்வொர்க் வெற்றி விகிதங்களின் அடிப்படையில் பரிந்துரைக்கப்பட்ட எரிவாயு வரம்பை நாங்கள் கணக்கிடுகிறோம்."
|
||||
},
|
||||
"gasLimitRequired": {
|
||||
"message": "எரிவாயு வரம்பு தேவை"
|
||||
},
|
||||
"gasLimitTooLow": {
|
||||
"message": "எரிவாயு வரம்பு குறைந்தது 21000 ஆக இருக்க வேண்டும்"
|
||||
},
|
||||
"generatingSeed": {
|
||||
"message": "விதை உருவாக்குகிறது ..."
|
||||
},
|
||||
"gasPrice": {
|
||||
"message": "எரிவாயு விலை (GWEI)"
|
||||
},
|
||||
"gasPriceCalculation": {
|
||||
"message": "நெட்வொர்க் வெற்றி விகிதங்களின் அடிப்படையில் பரிந்துரைக்கப்பட்ட எரிவாயு விலைகளை நாங்கள் கணக்கிடுகிறோம்."
|
||||
},
|
||||
"gasPriceRequired": {
|
||||
"message": "எரிவாயு விலை தேவைப்படுகிறது"
|
||||
},
|
||||
"getEther": {
|
||||
"message": "ஈத்தர் கிடைக்கும்"
|
||||
},
|
||||
"getEtherFromFaucet": {
|
||||
"message": "$ 1 க்கு ஒரு குழாய் இருந்து ஈதர் கிடைக்கும்$1",
|
||||
"description": "ஈத்தர் குழாய் ஐந்து பிணைய பெயர் காட்டுகிறது"
|
||||
},
|
||||
"greaterThanMin": {
|
||||
"message": "$ 1 க்கும் அதிகமாகவோ அல்லது சமமாகவோ இருக்க வேண்டும்",
|
||||
"description": "ஹெக்ஸ் உள்ளீடு தசம உள்ளீடு என உதவி"
|
||||
},
|
||||
"here": {
|
||||
"message": "இங்கே",
|
||||
"description": "இங்கே-கிளிக் செய்யவும்- மேலும் தகவலுக்கு (troubleTokenBalances செல்கிறது)"
|
||||
},
|
||||
"hereList": {
|
||||
"message": "இங்கே ஒரு பட்டியல் !!!!"
|
||||
},
|
||||
"hide": {
|
||||
"message": "மறை"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "டோக்கனை மறை"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "டோக்கனை மறை?"
|
||||
},
|
||||
"howToDeposit": {
|
||||
"message": "எப்படி ஈத்தர் வைப்பது?"
|
||||
},
|
||||
"holdEther": {
|
||||
"message": "இது நீங்கள் ஈத்தர் மற்றும் டோக்கன்களை வைத்திருக்க உதவுகிறது, மற்றும் பரவலாக்கப்பட்ட பயன்பாடுகளுக்கு உங்கள் பாலமாக செயல்படுகிறது."
|
||||
},
|
||||
"import": {
|
||||
"message": "இறக்குமதி",
|
||||
"description": "தேர்ந்தெடுக்கப்பட்ட கோப்பிலிருந்து ஒரு கணக்கை இறக்குமதி செய்ய பொத்தானை அழுத்தவும்"
|
||||
},
|
||||
"importAccount": {
|
||||
"message": "கணக்கை இறக்குமதி செய்க"
|
||||
},
|
||||
"importAccountMsg": {
|
||||
"message":" இறக்குமதி செய்யப்பட்ட கணக்கு உங்கள் முதலில் உருவாக்கப்பட்ட மெட்டாமாஸ்க் கணக்கு விதை மூலம் தொடர்புடையதாக இருக்காது. இறக்குமதி செய்யப்பட்ட கணக்குகள் பற்றி மேலும் அறிக "
|
||||
},
|
||||
"importAnAccount": {
|
||||
"message": "ஒரு கணக்கை இறக்குமதி செய்க"
|
||||
},
|
||||
"importDen": {
|
||||
"message": "இறக்குமதி DEN இறக்குமதி"
|
||||
},
|
||||
"imported": {
|
||||
"message": "இறக்குமதி",
|
||||
"description": "ஒரு கணக்கு முழுமையாக விசைப்பலகையில் ஏற்றப்பட்டதைக் காட்டுகிறது"
|
||||
},
|
||||
"infoHelp": {
|
||||
"message": "தகவல் மற்றும் உதவி"
|
||||
},
|
||||
"insufficientFunds": {
|
||||
"message": "போதுமான பணம் இல்லை."
|
||||
},
|
||||
"insufficientTokens": {
|
||||
"message": "போதுமான டோக்கன்கள்."
|
||||
},
|
||||
"invalidAddress": {
|
||||
"message": "தவறான முகவரி"
|
||||
},
|
||||
"invalidAddressRecipient": {
|
||||
"message": "பெறுநர் முகவரி தவறானது"
|
||||
},
|
||||
"invalidGasParams": {
|
||||
"message": "தவறான எரிவாயு அளவுருக்கள்"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "தவறான உள்ளீடு.."
|
||||
},
|
||||
"invalidRequest": {
|
||||
"message": "தவறான கோரிக்கை"
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "தவறான RPC URI"
|
||||
},
|
||||
"jsonFail": {
|
||||
"message": "ஏதோ தவறு நடந்துவிட்டது. உங்கள் JSON கோப்பு ஒழுங்காக வடிவமைக்கப்பட்டுள்ளது என்பதை உறுதிப்படுத்தவும்"
|
||||
},
|
||||
"jsonFile": {
|
||||
"message": "JSON கோப்பு",
|
||||
"description": "ஒரு கணக்கை இறக்குமதி செய்ய வடிவமைக்கப்பட்டுள்ளது"
|
||||
},
|
||||
"keepTrackTokens": {
|
||||
"message": "உங்கள் மேடமஸ்க் கணக்குடன் நீங்கள் வாங்கிய டோக்கன்களை கண்காணியுங்கள்."
|
||||
},
|
||||
"kovan": {
|
||||
"message": "கோவன் டெஸ்ட் நெட்வொர்க்"
|
||||
},
|
||||
"knowledgeDataBase": {
|
||||
"message": "எங்கள் அறிவுத் தளத்தைப் பார்வையிடவும்"
|
||||
},
|
||||
"max": {
|
||||
"message": "மேக்ஸ்"
|
||||
},
|
||||
"learnMore": {
|
||||
"message": "மேலும் அறிக"
|
||||
},
|
||||
"lessThanMax": {
|
||||
"message": "$ 1 க்கும் குறைவாகவோ அல்லது சமமாகவோ இருக்க வேண்டும்.",
|
||||
"description": "ஹெக்ஸ் உள்ளீடு தசம உள்ளீடு என உதவி"
|
||||
},
|
||||
"likeToAddTokens": {
|
||||
"message": "இந்த டோக்கன்களைச் சேர்க்க விரும்புகிறீர்களா?"
|
||||
},
|
||||
"links": {
|
||||
"message": "இணைப்புகள்"
|
||||
},
|
||||
"limit": {
|
||||
"message": "அளவு"
|
||||
},
|
||||
"loading": {
|
||||
"message": "ஏற்றுதல் ..."
|
||||
},
|
||||
"loadingTokens": {
|
||||
"message": "டோக்கன்களை ஏற்றுகிறது ..."
|
||||
},
|
||||
"localhost": {
|
||||
"message": "லோக்கல் ஹோஸ்ட் 8545"
|
||||
},
|
||||
"login": {
|
||||
"message": "உள் நுழை"
|
||||
},
|
||||
"logout": {
|
||||
"message": "வெளியேறு"
|
||||
},
|
||||
"loose": {
|
||||
"message": "லூஸ்"
|
||||
},
|
||||
"loweCaseWords": {
|
||||
"message": "விதை வார்த்தைகள் ஸ்மால் எழுத்துகள் மட்டுமே"
|
||||
},
|
||||
"mainnet": {
|
||||
"message": "முதன்மை எதெரியும் நெட்வொர்க்"
|
||||
},
|
||||
"message": {
|
||||
"message": "செய்தி"
|
||||
},
|
||||
"metamaskDescription": {
|
||||
"message": "மேடமஸ்க் என்பது ஒரு பாதுகாப்பான அடையாள வால்ட் எதெரியும்"
|
||||
},
|
||||
"min": {
|
||||
"message": "குறைந்தபட்ச"
|
||||
},
|
||||
"myAccounts": {
|
||||
"message": "எனது கணக்குகள்"
|
||||
},
|
||||
"mustSelectOne": {
|
||||
"message": "குறைந்தது 1 டோக்கனை தேர்ந்தெடுக்க வேண்டும்."
|
||||
},
|
||||
"needEtherInWallet": {
|
||||
"message": "மேடமஸ்க் ஐ பயன்படுத்தி பரவலாக்கப்பட்ட பயன்பாடுகளுடன் தொடர்பு கொள்ள, உங்கள் பணப்பரிமாற்றத்தில் ஈதர் தேவை."
|
||||
},
|
||||
"needImportFile": {
|
||||
"message": "இறக்குமதி செய்ய ஒரு கோப்பை நீங்கள் தேர்ந்தெடுக்க வேண்டும்.",
|
||||
"description": "பயனர் ஒரு கணக்கு முக்கியம் மற்றும் தொடர ஒரு கோப்பு சேர்க்க வேண்டும்"
|
||||
},
|
||||
"needImportPassword": {
|
||||
"message": "நீங்கள் தேர்ந்தெடுத்த கோப்புக்கு ஒரு கடவுச்சொல்லை உள்ளிட வேண்டும்.",
|
||||
"description": "ஒரு கணக்கை இறக்குமதி செய்ய கடவுச்சொல் மற்றும் கோப்பு தேவை"
|
||||
},
|
||||
"negativeETH": {
|
||||
"message": "ETH எதிர்மறை அளவுகளை அனுப்ப முடியாது."
|
||||
},
|
||||
"networks": {
|
||||
"message": "நெட்வொர்க்ஸ்"
|
||||
},
|
||||
"newAccount": {
|
||||
"message": "புதிய கணக்கு"
|
||||
},
|
||||
"newAccountNumberName": {
|
||||
"message": "கணக்கு $ 1",
|
||||
"description": "கணக்கு கணக்கை உருவாக்குவதற்கு அடுத்த கணக்கின் இயல்புநிலை பெயர் உருவாக்கப்படும்"
|
||||
},
|
||||
"newContract": {
|
||||
"message": "புதிய ஒப்பந்தம்"
|
||||
},
|
||||
"newPassword": {
|
||||
"message": "புதிய கடவுச்சொல் (min 8 எழுத்துகள்)"
|
||||
},
|
||||
"newRecipient": {
|
||||
"message": "புதிய பெறுநர்"
|
||||
},
|
||||
"newRPC": {
|
||||
"message": "புதிய RPC URL"
|
||||
},
|
||||
"next": {
|
||||
"message": "அடுத்த"
|
||||
},
|
||||
"noAddressForName": {
|
||||
"message": "இந்த பெயருக்கான முகவரி அமைக்கப்படவில்லை."
|
||||
},
|
||||
"noDeposits": {
|
||||
"message": "எந்த வைப்புகளும் கிடைக்கவில்லை"
|
||||
},
|
||||
"noTransactionHistory": {
|
||||
"message": "பரிவர்த்தனை வரலாறு இல்லை."
|
||||
},
|
||||
"noTransactions": {
|
||||
"message": "பரிவர்த்தனைகள் இல்லை"
|
||||
},
|
||||
"notStarted": {
|
||||
"message": "துவங்கவில்லை"
|
||||
},
|
||||
"oldUI": {
|
||||
"message": "பழைய UI"
|
||||
},
|
||||
"oldUIMessage": {
|
||||
"message": "நீங்கள் பழைய UI க்கு திரும்பியுள்ளீர்கள். மேல் வலது கீழ்தோன்றும் மெனுவில் உள்ள விருப்பத்தின் மூலம் புதிய UI ஐ மீண்டும் மாறலாம்."
|
||||
},
|
||||
"or": {
|
||||
"message": "அல்லது",
|
||||
"description": "ஒரு புதிய கணக்கை உருவாக்க அல்லது இறக்குமதி செய்வதற்கு இடையே தேர்வு"
|
||||
},
|
||||
"passwordCorrect": {
|
||||
"message": "தயவுசெய்து உங்கள் கடவுச்சொல் சரியானதா என உறுதிப்படுத்தவும்."
|
||||
},
|
||||
"passwordMismatch": {
|
||||
"message": "கடவுச்சொற்கள் பொருந்தவில்லை",
|
||||
"description": "கடவுச்சொல் உருவாக்கத்தில், இரண்டு புதிய கடவுச்சொல் புலங்கள் பொருந்தவில்லை"
|
||||
},
|
||||
"passwordShort": {
|
||||
"message": "கடவுச்சொல் நீண்ட காலமாக இல்லை",
|
||||
"description": "கடவுச்சொல் உருவாக்கத்தில், பாதுகாப்பானதாக இருக்கும் கடவுச்சொல் போதும்"
|
||||
},
|
||||
"pastePrivateKey": {
|
||||
"message": "இங்கே உங்கள் தனிப்பட்ட விசை சரத்தை ஒட்டுக:",
|
||||
"description": "ஒரு தனிப்பட்ட விசை ஒரு கணக்கை இறக்குமதி செய்ய"
|
||||
},
|
||||
"pasteSeed": {
|
||||
"message": "இங்கே உங்கள் விதை சொற்றொடரை ஒட்டவும்!"
|
||||
},
|
||||
"personalAddressDetected": {
|
||||
"message": "தனிப்பட்ட முகவரி கண்டறியப்பட்டது. டோக்கன் ஒப்பந்த முகவரியை உள்ளிடவும்."
|
||||
},
|
||||
"pleaseReviewTransaction": {
|
||||
"message": "உங்கள் பரிவர்த்தனை மதிப்பாய்வு செய்யவும்."
|
||||
},
|
||||
"popularTokens": {
|
||||
"message": "பிரபலமான டோக்கன்கள்"
|
||||
},
|
||||
"privacyMsg": {
|
||||
"message": "தனியுரிமை கொள்கை"
|
||||
},
|
||||
"privateKey": {
|
||||
"message": "தனிப்பட்ட விசை",
|
||||
"description": "ஒரு கணக்கை இறக்குமதி செய்ய பயன்படுத்த இந்த வகை கோப்பை தேர்ந்தெடுக்கவும்"
|
||||
},
|
||||
"privateKeyWarning": {
|
||||
"message": "எச்சரிக்கை: இந்த விசையை எப்போதும் வெளியிட வேண்டாம். உங்கள் தனிப்பட்ட விசைகளைக் கொண்ட எவரும் உங்கள் கணக்கில் உள்ள எந்த சொத்துக்களையும் திருடலாம்."
|
||||
},
|
||||
"privateNetwork": {
|
||||
"message": "தனியார் நெட்வொர்க்"
|
||||
},
|
||||
"qrCode": {
|
||||
"message": "QR குறியீட்டைக் காட்டு"
|
||||
},
|
||||
"readdToken": {
|
||||
"message": "உங்கள் கணக்கு விருப்பங்கள் மெனுவில் \"டோக்கனைச் சேர்\" என்பதன் மூலம் நீங்கள் எதிர்காலத்தில் இந்த டோக்கனை மீண்டும் சேர்க்கலாம்."
|
||||
},
|
||||
"readMore": {
|
||||
"message": "மேலும் வாசிக்க இங்கே."
|
||||
},
|
||||
"readMore2": {
|
||||
"message": "மேலும் வாசிக்க."
|
||||
},
|
||||
"receive": {
|
||||
"message": "பெறுக"
|
||||
},
|
||||
"recipientAddress": {
|
||||
"message": "பெறுநர் முகவரி"
|
||||
},
|
||||
"refundAddress": {
|
||||
"message": "உங்கள் பணத்தை திருப்பி அனுப்பும் முகவரி"
|
||||
},
|
||||
"rejected": {
|
||||
"message": "நிராகரிக்கப்பட்டது"
|
||||
},
|
||||
"resetAccount": {
|
||||
"message": "கணக்கை மீட்டமை"
|
||||
},
|
||||
"restoreFromSeed": {
|
||||
"message": "விதை வாக்கியத்திலிருந்து மீட்கவும்"
|
||||
},
|
||||
"restoreVault": {
|
||||
"message": "வால்ட் மீட்கவும்"
|
||||
},
|
||||
"required": {
|
||||
"message": "தேவையான"
|
||||
},
|
||||
"retryWithMoreGas": {
|
||||
"message": "இங்கே அதிக எரிவாயு விலை மீண்டும் முயற்சிக்கவும்"
|
||||
},
|
||||
"walletSeed": {
|
||||
"message": "வால்ட் விதை"
|
||||
},
|
||||
"revealSeedWords": {
|
||||
"message": "விதை வார்த்தைகள் வெளிப்படுத்த"
|
||||
},
|
||||
"revealSeedWordsWarning": {
|
||||
"message": "உங்கள் விதை வார்த்தைகள் ஒரு பொது இடத்தில் மீட்க வேண்டாம்! உங்கள் எல்லா கணக்குகளையும் திருட இந்த வார்த்தைகள் பயன்படுத்தப்படலாம்."
|
||||
},
|
||||
"revert": {
|
||||
"message": "மாற்றியமை"
|
||||
},
|
||||
"rinkeby": {
|
||||
"message": "ரிங்கெப்ய டெஸ்ட் நெட்வொர்க்"
|
||||
},
|
||||
"ropsten": {
|
||||
"message": "ரொப்ஸ்டென் டெஸ்ட் நெட்வொர்க்"
|
||||
},
|
||||
"currentRpc": {
|
||||
"message": "தற்போதைய RPC"
|
||||
},
|
||||
"connectingToMainnet": {
|
||||
"message": "முக்கிய எதெரியும் நெட்வொர்க் இணைக்கும்"
|
||||
},
|
||||
"connectingToRopsten": {
|
||||
"message": "ரொப்ஸ்டென் டெஸ்ட் நெட்வொர்க்குடன் இணைக்கிறது"
|
||||
},
|
||||
"connectingToKovan": {
|
||||
"message": "கோவன் டெஸ்ட் நெட்வொர்க்குடன் இணைத்தல்"
|
||||
},
|
||||
"connectingToRinkeby": {
|
||||
"message": "ரிங்கெப்ய டெஸ்ட் நெட்வொர்க்குடன் இணைக்கிறது"
|
||||
},
|
||||
"connectingToUnknown": {
|
||||
"message": "தெரியாத நெட்வொர்க்குடன் இணைக்கிறது"
|
||||
},
|
||||
"sampleAccountName": {
|
||||
"message": "உதாரணமாக எனது புதிய கணக்கு",
|
||||
"description": "தங்கள் கணக்கில் மனிதர் படிக்கக்கூடிய பெயரைச் சேர்க்கும் கருத்தை பயனர் புரிந்து கொள்ள உதவுங்கள்"
|
||||
},
|
||||
"save": {
|
||||
"message": "சேமி"
|
||||
},
|
||||
"reprice_title": {
|
||||
"message": "ரெப்ரிஸ் பரிவர்த்தனை"
|
||||
},
|
||||
"reprice_subtitle": {
|
||||
"message": "உங்கள் பரிவர்த்தனைகளை மேலெழுதும் முயற்சியை அதிகரிக்க உங்கள் எரிவாயு விலையை அதிகரிக்கவும்"
|
||||
},
|
||||
"saveAsFile": {
|
||||
"message": "கோப்பாக சேமிக்கவும்",
|
||||
"description": "கணக்கு ஏற்றுமதி செயல்முறை"
|
||||
},
|
||||
"saveSeedAsFile": {
|
||||
"message": "கோப்பு என விதை வார்த்தைகள் சேமிக்கவும்"
|
||||
},
|
||||
"search": {
|
||||
"message": "தேடல்"
|
||||
},
|
||||
"secretPhrase": {
|
||||
"message": "உங்கள் பெட்டகத்தை மீட்டெடுப்பதற்காக இங்கே உங்கள் ரகசிய பன்னிரண்டு வார்த்தை சொற்றொடரை உள்ளிடவும்."
|
||||
},
|
||||
"newPassword8Chars": {
|
||||
"message": "புதிய கடவுச்சொல் (குறைந்தபட்சம் 8 எழுத்துகள்)"
|
||||
},
|
||||
"seedPhraseReq": {
|
||||
"message": "விதை வாக்கியங்கள் 12 வார்த்தைகள் நீண்டவை"
|
||||
},
|
||||
"select": {
|
||||
"message": "தேர்வு"
|
||||
},
|
||||
"selectCurrency": {
|
||||
"message": "நாணயத்தைத் தேர்ந்தெடு"
|
||||
},
|
||||
"selectService": {
|
||||
"message": "சேவை தேர்ந்தெடுக்கவும்"
|
||||
},
|
||||
"selectType": {
|
||||
"message": "வகை தேர்ந்தெடு"
|
||||
},
|
||||
"send": {
|
||||
"message": "அனுப்பு"
|
||||
},
|
||||
"sendETH": {
|
||||
"message": "ETH ஐ அனுப்பு"
|
||||
},
|
||||
"sendTokens": {
|
||||
"message": "டோக்கன்களை அனுப்பவும்"
|
||||
},
|
||||
"onlySendToEtherAddress": {
|
||||
"message": "ETH ஐ ஒரு எதரியும் முகவரிக்கு மட்டும் அனுப்பவும்."
|
||||
},
|
||||
"searchTokens": {
|
||||
"message": "தேடல் டோக்கன்ஸ்"
|
||||
},
|
||||
"sendTokensAnywhere": {
|
||||
"message": "யாருடனும் டோக்கன்களை அனுப்பவும் எதெரியும் கணக்கு"
|
||||
},
|
||||
"settings": {
|
||||
"message": "அமைப்புகள்"
|
||||
},
|
||||
"info": {
|
||||
"message": "தகவல்"
|
||||
},
|
||||
"shapeshiftBuy": {
|
||||
"message": "Shapeshift உடன் வாங்கவும்"
|
||||
},
|
||||
"showPrivateKeys": {
|
||||
"message": "தனிப்பட்ட விசைகளைக் காண்பி"
|
||||
},
|
||||
"showQRCode": {
|
||||
"message": "QR குறியீட்டைக் காட்டு"
|
||||
},
|
||||
"sign": {
|
||||
"message": "உள்நுழை"
|
||||
},
|
||||
"signed": {
|
||||
"message": "கையொப்பமிடப்பட்ட"
|
||||
},
|
||||
"signMessage": {
|
||||
"message": "செய்தியை பதிவு செய்க"
|
||||
},
|
||||
"signNotice": {
|
||||
"message": "இந்த செய்தியில் கையொப்பமிடலாம் \nஆபத்தான பக்க விளைவுகள் இருக்கலாம். \n உங்கள் மொத்த கணக்கில் முழுமையாக நம்பக்கூடிய தளங்களில் செய்திகளை மட்டுமே கையொப்பமிடுங்கள். \n இந்த ஆபத்தான முறை எதிர்கால பதிப்பில் அகற்றப்படும்."
|
||||
},
|
||||
"sigRequest": {
|
||||
"message": "கையொப்பம் கோரிக்கை"
|
||||
},
|
||||
"sigRequested": {
|
||||
"message": "கையொப்பம் கோரப்பட்டது"
|
||||
},
|
||||
"spaceBetween": {
|
||||
"message": "வார்த்தைகள் இடையே இடைவெளி மட்டுமே இருக்க முடியும்"
|
||||
},
|
||||
"status": {
|
||||
"message": "நிலைமை"
|
||||
},
|
||||
"stateLogs": {
|
||||
"message": "மாநில பதிவுகள்"
|
||||
},
|
||||
"stateLogsDescription": {
|
||||
"message": "மாநில பதிவுகள் உங்கள் பொது கணக்கு முகவரிகள் மற்றும் பரிமாற்றங்களை அனுப்பியுள்ளன."
|
||||
},
|
||||
"stateLogError": {
|
||||
"message": "மாநில பதிவுகளை மீட்டெடுப்பதில் பிழை."
|
||||
},
|
||||
"submit": {
|
||||
"message": "சமர்ப்பி"
|
||||
},
|
||||
"submitted": {
|
||||
"message": "சமர்ப்பிக்கப்பட்டது"
|
||||
},
|
||||
"supportCenter": {
|
||||
"message": "எங்கள் ஆதரவு மையத்தைப் பார்வையிடவும்"
|
||||
},
|
||||
"symbolBetweenZeroTen": {
|
||||
"message": "குறியீடு 0 மற்றும் 10 எழுத்துகளுக்கு இடையில் இருக்க வேண்டும்."
|
||||
},
|
||||
"takesTooLong": {
|
||||
"message": "நீண்ட நேரம் எடுத்துக்கொள்கிறது?"
|
||||
},
|
||||
"terms": {
|
||||
"message": "பயன்பாட்டு விதிமுறைகளை"
|
||||
},
|
||||
"testFaucet": {
|
||||
"message": "சோதனை குழாய்"
|
||||
},
|
||||
"to": {
|
||||
"message": "பெறுநர்: "
|
||||
},
|
||||
"toETHviaShapeShift": {
|
||||
"message": "$ 1 முதல் ETH வரை வடிவம்",
|
||||
"description": "செய்தி தொடக்கத்தில் வைப்பு வகைகளில் நிரப்பப்படும்"
|
||||
},
|
||||
"tokenAddress": {
|
||||
"message": "டோக்கன் முகவரி"
|
||||
},
|
||||
"tokenAlreadyAdded": {
|
||||
"message": "டோக்கன் ஏற்கனவே சேர்க்கப்பட்டது."
|
||||
},
|
||||
"tokenBalance": {
|
||||
"message": "உங்கள் டோக்கன் இருப்பு:"
|
||||
},
|
||||
"tokenSelection": {
|
||||
"message": "டோக்கன்களைத் தேடு அல்லது பிரபல டோக்கன்களின் பட்டியலிலிருந்து தேர்ந்தெடுக்கவும்."
|
||||
},
|
||||
"tokenSymbol": {
|
||||
"message": "டோக்கன் சின்னம்"
|
||||
},
|
||||
"tokenWarning1": {
|
||||
"message": "உங்கள் மேடமஸ்க் கணக்குடன் நீங்கள் வாங்கிய டோக்கன்களை கண்காணியுங்கள். வேறு கணக்கைப் பயன்படுத்தி டோக்கன்களை வாங்கிவிட்டால், அந்த டோக்கன்கள் இங்கே தோன்றாது."
|
||||
},
|
||||
"total": {
|
||||
"message": "மொத்த"
|
||||
},
|
||||
"transactions": {
|
||||
"message": "பரிவர்த்தனைகள்"
|
||||
},
|
||||
"transactionError": {
|
||||
"message": "பரிவர்த்தனை பிழை. விதிமுறை ஒப்பந்தத்தில் விதிவிலக்கு."
|
||||
},
|
||||
"transactionMemo": {
|
||||
"message": "பரிவர்த்தனை குறிப்பு (விருப்பம்)"
|
||||
},
|
||||
"transactionNumber": {
|
||||
"message": "பரிவர்த்தனை எண்"
|
||||
},
|
||||
"transfers": {
|
||||
"message": "இடமாற்றங்கள்"
|
||||
},
|
||||
"troubleTokenBalances": {
|
||||
"message": "உங்கள் டோக்கன் நிலுவைகளை ஏற்றுவதில் சிக்கல் ஏற்பட்டது. நீங்கள் அவர்களை பார்க்க முடியும்.",
|
||||
"description": "டோக்கன் நிலுவைகளை காண ஒரு இணைப்பு (இங்கே) தொடர்ந்து"
|
||||
},
|
||||
"twelveWords": {
|
||||
"message": "இந்த 12 வார்த்தைகள் உங்கள் மெட்டாமாஸ்க் கணக்கை மீட்க ஒரே வழி. \n அவற்றை எங்காவது பாதுகாப்பாகவும் ரகசியமாகவும் சேமிக்கவும்."
|
||||
},
|
||||
"typePassword": {
|
||||
"message": "உங்கள் கடவுச்சொல்லை தட்டச்சு செய்யவும்"
|
||||
},
|
||||
"uiWelcome": {
|
||||
"message": "புதிய UI (பீட்டா) க்கு வரவேற்கிறோம்"
|
||||
},
|
||||
"uiWelcomeMessage": {
|
||||
"message": "இப்போது நீங்கள் புதிய மெட்டாமாஸ்க்கு UI ஐ பயன்படுத்துகிறீர்கள். சுற்றி பாருங்கள், டோக்கன்களை அனுப்பும் புதிய அம்சங்களை முயற்சிக்கவும், உங்களிடம் ஏதேனும் சிக்கல் இருந்தால் எங்களுக்குத் தெரியப்படுத்தவும்."
|
||||
},
|
||||
"unapproved": {
|
||||
"message": "அங்கீகரிக்கப்படாத"
|
||||
},
|
||||
"unavailable": {
|
||||
"message": "கிடைக்கவில்லை"
|
||||
},
|
||||
"unknown": {
|
||||
"message": "தெரியாத"
|
||||
},
|
||||
"unknownNetwork": {
|
||||
"message": "அறியப்படாத தனியார் நெட்வொர்க்"
|
||||
},
|
||||
"unknownNetworkId": {
|
||||
"message": "தெரியாத நெட்வொர்க் ஐடி"
|
||||
},
|
||||
"uriErrorMsg": {
|
||||
"message": "URI கள் சரியான HTTP / HTTPS முன்னொட்டு தேவை."
|
||||
},
|
||||
"usaOnly": {
|
||||
"message": "அமெரிக்கா மட்டும்",
|
||||
"description": "இந்த பரிமாற்றத்தைப் பயன்படுத்தி அமெரிக்காவில் உள்ளவர்களுக்கு மட்டுமே இது வரையறுக்கப்படுகிறது"
|
||||
},
|
||||
"usedByClients": {
|
||||
"message": "பல்வேறு வாடிக்கையாளர்கள் பல்வேறு பயன்படுத்திய"
|
||||
},
|
||||
"useOldUI": {
|
||||
"message": "உஸ் ஓல்ட் உய் "
|
||||
},
|
||||
"validFileImport": {
|
||||
"message": "இறக்குமதி செய்ய சரியான கோப்பு தேர்ந்தெடுக்க வேண்டும்."
|
||||
},
|
||||
"vaultCreated": {
|
||||
"message": "வால்ட் உருவாக்கப்பட்டது"
|
||||
},
|
||||
"viewAccount": {
|
||||
"message": "கணக்கைக் காட்டு"
|
||||
},
|
||||
"visitWebSite": {
|
||||
"message": "எங்கள் வலைத்தளத்தைப் பார்வையிடவும்"
|
||||
},
|
||||
"warning": {
|
||||
"message": "எச்சரிக்கை"
|
||||
},
|
||||
"welcomeBeta": {
|
||||
"message": "மெட்டாமாஸ்க் பீட்டாவுக்கு வருக"
|
||||
},
|
||||
"whatsThis": {
|
||||
"message": "இது என்ன?"
|
||||
},
|
||||
"yourSigRequested": {
|
||||
"message": "உங்கள் கையொப்பம் கோரப்படுகிறது"
|
||||
},
|
||||
"youSign": {
|
||||
"message": "நீங்கள் கையெழுத்திடுகிறீர்கள்"
|
||||
}
|
||||
}
|
912
app/_locales/tr/messages.json
Normal file
912
app/_locales/tr/messages.json
Normal file
@ -0,0 +1,912 @@
|
||||
{
|
||||
"accept": {
|
||||
"message": "Kabul et"
|
||||
},
|
||||
"account": {
|
||||
"message": "Hesap"
|
||||
},
|
||||
"accountDetails": {
|
||||
"message": "Hesap Detayları"
|
||||
},
|
||||
"accountName": {
|
||||
"message": "Hesap İsmi"
|
||||
},
|
||||
"address": {
|
||||
"message": "Adres"
|
||||
},
|
||||
"addCustomToken": {
|
||||
"message": "Özel jeton ekle"
|
||||
},
|
||||
"addToken": {
|
||||
"message": "Jeton ekle"
|
||||
},
|
||||
"addTokens": {
|
||||
"message": "Jetonlar ekle"
|
||||
},
|
||||
"amount": {
|
||||
"message": "Tutar"
|
||||
},
|
||||
"amountPlusGas": {
|
||||
"message": "Tutar + Gas"
|
||||
},
|
||||
"appDescription": {
|
||||
"message": "Ethereum Tarayıcı Uzantısı",
|
||||
"description": "Uygulama açıklaması"
|
||||
},
|
||||
"appName": {
|
||||
"message": "MetaMask",
|
||||
"description": "Uygulama ismi"
|
||||
},
|
||||
"approved": {
|
||||
"message": "Onaylandı"
|
||||
},
|
||||
"attemptingConnect": {
|
||||
"message": "Blockchain'e bağlanmayı deniyor"
|
||||
},
|
||||
"attributions": {
|
||||
"message": "Atıflar"
|
||||
},
|
||||
"available": {
|
||||
"message": "Müsait"
|
||||
},
|
||||
"back": {
|
||||
"message": "Geri"
|
||||
},
|
||||
"balance": {
|
||||
"message": "Bakiye:"
|
||||
},
|
||||
"balances": {
|
||||
"message": "Jeton bakiyesi"
|
||||
},
|
||||
"balanceIsInsufficientGas": {
|
||||
"message": "Toplam gas için yetersiz bakiye"
|
||||
},
|
||||
"beta": {
|
||||
"message": "BETA"
|
||||
},
|
||||
"betweenMinAndMax": {
|
||||
"message": "$1'e eşit veya daha büyük olmalı ve $2'den küçük veya eşit olmalı",
|
||||
"description": "Onaltılık sayının ondalık sayı olarak girişi için yardımcı"
|
||||
},
|
||||
"blockiesIdenticon": {
|
||||
"message": "Blockies Identicon kullan"
|
||||
},
|
||||
"borrowDharma": {
|
||||
"message": "Dharma (Beta) ile ödünç al"
|
||||
},
|
||||
"builtInCalifornia": {
|
||||
"message": "MetaMask California'da tasarlandı ve yaratıldı"
|
||||
},
|
||||
"buy": {
|
||||
"message": "Satın al"
|
||||
},
|
||||
"buyCoinbase": {
|
||||
"message": "Coinbase'de satın al"
|
||||
},
|
||||
"buyCoinbaseExplainer": {
|
||||
"message": "Coinbase bitcoin, ethereum, and litecoin alıp satmanın dünyadaki en popüler yolu"
|
||||
},
|
||||
"ok": {
|
||||
"message": "Tamam"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "Vazgeç"
|
||||
},
|
||||
"classicInterface": {
|
||||
"message": "Klasik arayüzü kullan"
|
||||
},
|
||||
"clickCopy": {
|
||||
"message": "Kopyalamak için tıkla"
|
||||
},
|
||||
"confirm": {
|
||||
"message": "Onayla"
|
||||
},
|
||||
"confirmed": {
|
||||
"message": "Onaylandı"
|
||||
},
|
||||
"confirmContract": {
|
||||
"message": "Sözleşmeyi onayla"
|
||||
},
|
||||
"confirmPassword": {
|
||||
"message": "Şifreyi onayla"
|
||||
},
|
||||
"confirmTransaction": {
|
||||
"message": "İşlemi onayla"
|
||||
},
|
||||
"continue": {
|
||||
"message": "Devam et"
|
||||
},
|
||||
"continueToCoinbase": {
|
||||
"message": "Coinbase'e devam et"
|
||||
},
|
||||
"contractDeployment": {
|
||||
"message": "Sözleşme kurulumu"
|
||||
},
|
||||
"conversionProgress": {
|
||||
"message": "Çevirim devam ediyor"
|
||||
},
|
||||
"copiedButton": {
|
||||
"message": "Kopyalandı"
|
||||
},
|
||||
"copiedClipboard": {
|
||||
"message": "Panoya kopyalandı"
|
||||
},
|
||||
"copiedExclamation": {
|
||||
"message": "Kopyalandı!"
|
||||
},
|
||||
"copiedSafe": {
|
||||
"message": "Güvenli bir yere kopyaladım"
|
||||
},
|
||||
"copy": {
|
||||
"message": "Kopyala"
|
||||
},
|
||||
"copyToClipboard": {
|
||||
"message": "Panoya kopyala"
|
||||
},
|
||||
"copyButton": {
|
||||
"message": " Kopyala "
|
||||
},
|
||||
"copyPrivateKey": {
|
||||
"message": "Bu sizin özel anahtarınız (kopyalamak için tıklayın)"
|
||||
},
|
||||
"create": {
|
||||
"message": "Yarat"
|
||||
},
|
||||
"createAccount": {
|
||||
"message": "Hesap Oluştur"
|
||||
},
|
||||
"createDen": {
|
||||
"message": "Yarat"
|
||||
},
|
||||
"crypto": {
|
||||
"message": "Kripto",
|
||||
"description": "Kambiyo tipi (kripto para)"
|
||||
},
|
||||
"currentConversion": {
|
||||
"message": "Geçerli çevirme"
|
||||
},
|
||||
"currentNetwork": {
|
||||
"message": "Geçerli Ağ"
|
||||
},
|
||||
"customGas": {
|
||||
"message": "Gas'i özelleştir"
|
||||
},
|
||||
"customToken": {
|
||||
"message": "Özel Jeton"
|
||||
},
|
||||
"customize": {
|
||||
"message": "Özelleştir"
|
||||
},
|
||||
"customRPC": {
|
||||
"message": "Özel RPC"
|
||||
},
|
||||
"decimalsMustZerotoTen": {
|
||||
"message": "Ondalıklar en azından 0 olmalı ve 36'dan büyük olmamalı."
|
||||
},
|
||||
"decimal": {
|
||||
"message": "Ondalık hassasiyeti"
|
||||
},
|
||||
"defaultNetwork": {
|
||||
"message": "Ether işlemleri için varsayılan ağ Main Net."
|
||||
},
|
||||
"denExplainer": {
|
||||
"message": "DEN'iniz MetaMask içersinde parola-şifrelenmiş deponuzdur."
|
||||
},
|
||||
"deposit": {
|
||||
"message": "Yatır"
|
||||
},
|
||||
"depositBTC": {
|
||||
"message": "BTC'inizi aşağıdaki adrese yatırın:"
|
||||
},
|
||||
"depositCoin": {
|
||||
"message": "$1'nızı aşağıdaki adrese yatırın",
|
||||
"description": "Kullanıcıya hangi jetonu seçtiyse onu yatırmasını shapeshift ile söyler."
|
||||
},
|
||||
"depositEth": {
|
||||
"message": "Eth yatır"
|
||||
},
|
||||
"depositEther": {
|
||||
"message": "Ether yatır"
|
||||
},
|
||||
"depositFiat": {
|
||||
"message": "Para yatır"
|
||||
},
|
||||
"depositFromAccount": {
|
||||
"message": "Başka bir hesaptan yatır"
|
||||
},
|
||||
"depositShapeShift": {
|
||||
"message": "ShapeShift ile yatır"
|
||||
},
|
||||
"depositShapeShiftExplainer": {
|
||||
"message": "Eğer başka kripto paralara sahipseniz, MetaMask cüzdanınıza direk olarak Ether yatırabilirsiniz. Hesaba gerek yoktur."
|
||||
},
|
||||
"details": {
|
||||
"message": "Ayrıntılar"
|
||||
},
|
||||
"directDeposit": {
|
||||
"message": "Direk Yatırma"
|
||||
},
|
||||
"directDepositEther": {
|
||||
"message": "Direk Ether Yatırma"
|
||||
},
|
||||
"directDepositEtherExplainer": {
|
||||
"message": "Eğer çoktan Etheriniz varsa, yeni hesabınıza Ether aktarmanın en kolay yolu direk yatırmadır."
|
||||
},
|
||||
"done": {
|
||||
"message": "Bitti"
|
||||
},
|
||||
"downloadStateLogs": {
|
||||
"message": "Durum kayıtlarını indir"
|
||||
},
|
||||
"dropped": {
|
||||
"message": "Bırakıldı"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Düzenle"
|
||||
},
|
||||
"editAccountName": {
|
||||
"message": "Hesap ismini düzenle"
|
||||
},
|
||||
"emailUs": {
|
||||
"message": "Bize e-posta atın!"
|
||||
},
|
||||
"encryptNewDen": {
|
||||
"message": "Yeni DEN'inizi şifreleyin"
|
||||
},
|
||||
"enterPassword": {
|
||||
"message": "Parolanızı girin"
|
||||
},
|
||||
"enterPasswordConfirm": {
|
||||
"message": "Onaylamak için parolanızı girin"
|
||||
},
|
||||
"passwordNotLongEnough": {
|
||||
"message": "Parola yeterince uzun değil"
|
||||
},
|
||||
"passwordsDontMatch": {
|
||||
"message": "Parolalar eşleşmiyor"
|
||||
},
|
||||
"etherscanView": {
|
||||
"message": "Hesabı Etherscan üzerinde izle"
|
||||
},
|
||||
"exchangeRate": {
|
||||
"message": "Döviz kuru"
|
||||
},
|
||||
"exportPrivateKey": {
|
||||
"message": "Özel anahtarı ver"
|
||||
},
|
||||
"exportPrivateKeyWarning": {
|
||||
"message": "Özel anahtarınızı vermek sizin sorumluluğunuzdadır."
|
||||
},
|
||||
"failed": {
|
||||
"message": "Başarısız oldu"
|
||||
},
|
||||
"fiat": {
|
||||
"message": "Para",
|
||||
"description": "Döviz türü"
|
||||
},
|
||||
"fileImportFail": {
|
||||
"message": "Dosya alma çalışmıyor mu? Buraya tıklayın!",
|
||||
"description": "Kullanıcıların hesaplarını JSON dosyasından almalarına yardım eder"
|
||||
},
|
||||
"followTwitter": {
|
||||
"message": "Bizi twitter'da takip edin"
|
||||
},
|
||||
"from": {
|
||||
"message": "Kimden"
|
||||
},
|
||||
"fromToSame": {
|
||||
"message": "Kimden ve kime adresi aynı olamaz"
|
||||
},
|
||||
"fromShapeShift": {
|
||||
"message": "ShapeShift'den"
|
||||
},
|
||||
"gas": {
|
||||
"message": "Gas",
|
||||
"description": "Gas maliyetinin kısa indikatörü"
|
||||
},
|
||||
"gasFee": {
|
||||
"message": "Gas Ücreti"
|
||||
},
|
||||
"gasLimit": {
|
||||
"message": "Gas Limiti"
|
||||
},
|
||||
"gasLimitCalculation": {
|
||||
"message": "Önerilen gas limitini ağ başarı oranını baz alarak hesaplıyoruz."
|
||||
},
|
||||
"gasLimitRequired": {
|
||||
"message": "Gas limiti gereklidir"
|
||||
},
|
||||
"gasLimitTooLow": {
|
||||
"message": "Gas limiti en az 21000 olmalıdır"
|
||||
},
|
||||
"generatingSeed": {
|
||||
"message": "Kaynak Oluşturuyor..."
|
||||
},
|
||||
"gasPrice": {
|
||||
"message": "Gas Fiyatı (GWEI)"
|
||||
},
|
||||
"gasPriceCalculation": {
|
||||
"message": "Önerilen gas fiyatını ağ başarı oranını baz alarak hesaplıyoruz."
|
||||
},
|
||||
"gasPriceRequired": {
|
||||
"message": "Gas Fiyatı Gereklidir"
|
||||
},
|
||||
"getEther": {
|
||||
"message": "Ether Al"
|
||||
},
|
||||
"getEtherFromFaucet": {
|
||||
"message": "Musluktan $1 karşılığı Ether alın",
|
||||
"description": "Ether musluğunun ağ ismini gösterir"
|
||||
},
|
||||
"greaterThanMin": {
|
||||
"message": "must be greater than or equal to $1.",
|
||||
"description": "helper for inputting hex as decimal input"
|
||||
},
|
||||
"here": {
|
||||
"message": "burada",
|
||||
"description": "daha fazla bilgi için -buraya tıklayın- (troubleTokenBalances ile gidiyor)"
|
||||
},
|
||||
"hereList": {
|
||||
"message": "İşte bir liste!!!!"
|
||||
},
|
||||
"hide": {
|
||||
"message": "Gizle"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Jetonu gizle"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Jetonu gizle?"
|
||||
},
|
||||
"howToDeposit": {
|
||||
"message": "Ether'i nasıl yatırmak istersiniz?"
|
||||
},
|
||||
"holdEther": {
|
||||
"message": "Ether ve jeton tutmanızı sağlar ve merkezi olmayan uygulamalar ve sizin aranızda köprü vazifesi görür."
|
||||
},
|
||||
"import": {
|
||||
"message": "Al",
|
||||
"description": "Seçilen dosyadan hesap alma düğmesi. "
|
||||
},
|
||||
"importAccount": {
|
||||
"message": "Hesap Al"
|
||||
},
|
||||
"importAccountMsg": {
|
||||
"message":" Alınan hesaplar orjinal kaynakifadenizle yarattığınız MetaMask hesabınızla ilişkilendirilmez. Alınan hesaplar ile ilgili daha fazla bilgi edinin "
|
||||
},
|
||||
"importAnAccount": {
|
||||
"message": "Hesap al"
|
||||
},
|
||||
"importDen": {
|
||||
"message": "Varolan DEN al"
|
||||
},
|
||||
"imported": {
|
||||
"message": "Alındı",
|
||||
"description": "Hesabın keyringe başarı ile alındığını gösteren durum"
|
||||
},
|
||||
"infoHelp": {
|
||||
"message": "Bilgi ve yardım"
|
||||
},
|
||||
"insufficientFunds": {
|
||||
"message": "Yetersiz kaynak."
|
||||
},
|
||||
"insufficientTokens": {
|
||||
"message": "Yetersiz Jeton."
|
||||
},
|
||||
"invalidAddress": {
|
||||
"message": "Geçersiz adres"
|
||||
},
|
||||
"invalidAddressRecipient": {
|
||||
"message": "Alıcı adresi geçersiz"
|
||||
},
|
||||
"invalidGasParams": {
|
||||
"message": "Geçersiz gas parametreleri"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Geçersiz giriş."
|
||||
},
|
||||
"invalidRequest": {
|
||||
"message": "Geçersiz istek"
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Geçersiz RPC URI"
|
||||
},
|
||||
"jsonFail": {
|
||||
"message": "Birşeyler yanlış gitti. JSON dosyanızın düzgün derlendiğinden emin olun."
|
||||
},
|
||||
"jsonFile": {
|
||||
"message": "JSON Dosyası",
|
||||
"description": "Hesap alımı için düzenle"
|
||||
},
|
||||
"keepTrackTokens": {
|
||||
"message": "MetaMask hesabınızla satın aldığınız jetonların kaydını tutun."
|
||||
},
|
||||
"kovan": {
|
||||
"message": "Kovan Test Ağı"
|
||||
},
|
||||
"knowledgeDataBase": {
|
||||
"message": "Bilgi veritabanımızı ziyaret edin"
|
||||
},
|
||||
"max": {
|
||||
"message": "Maksimum"
|
||||
},
|
||||
"learnMore": {
|
||||
"message": "Daha fazla bilgi."
|
||||
},
|
||||
"lessThanMax": {
|
||||
"message": "$1'den az veya eşit olmalıdır.",
|
||||
"description": "Onaltılık sayıyı ondalık olarak girmek için yardımcı"
|
||||
},
|
||||
"likeToAddTokens": {
|
||||
"message": "Bu jetonlara adres eklemek ister misiniz?"
|
||||
},
|
||||
"links": {
|
||||
"message": "Bağlantılar"
|
||||
},
|
||||
"limit": {
|
||||
"message": "Limit"
|
||||
},
|
||||
"loading": {
|
||||
"message": "Yükleniyor..."
|
||||
},
|
||||
"loadingTokens": {
|
||||
"message": "Jetonlar yükleniyor..."
|
||||
},
|
||||
"localhost": {
|
||||
"message": "Localhost 8545"
|
||||
},
|
||||
"login": {
|
||||
"message": "Giriş yap"
|
||||
},
|
||||
"logout": {
|
||||
"message": "Çıkış"
|
||||
},
|
||||
"loose": {
|
||||
"message": "Gevşek"
|
||||
},
|
||||
"loweCaseWords": {
|
||||
"message": "kaynak kelimeleri sadece küçük harflerden oluşabilir."
|
||||
},
|
||||
"mainnet": {
|
||||
"message": "Main Ethereum Ağı"
|
||||
},
|
||||
"message": {
|
||||
"message": "Mesaj"
|
||||
},
|
||||
"metamaskDescription": {
|
||||
"message": "MetaMask Ethereum için güvenli bir kimlik kasasıdır."
|
||||
},
|
||||
"min": {
|
||||
"message": "Minimum"
|
||||
},
|
||||
"myAccounts": {
|
||||
"message": "Hesaplarım"
|
||||
},
|
||||
"mustSelectOne": {
|
||||
"message": "En az bir jeton seçilmeli"
|
||||
},
|
||||
"needEtherInWallet": {
|
||||
"message": "MetaMask kullanarak merkezi olamayan uygulamalarla etkileşmek için cüzdanınızda Ether bulunmalıdır."
|
||||
},
|
||||
"needImportFile": {
|
||||
"message": "Almak için bir dosya seçmelisiniz.",
|
||||
"description": "Kullanıcı bir hesap alır ve devam etmek içinbir dosya seçmelidir."
|
||||
},
|
||||
"needImportPassword": {
|
||||
"message": "Seçilen dosya için bir parola girmelisiniz.",
|
||||
"description": "Hesap almak için parola ve dosya gerekiyor."
|
||||
},
|
||||
"negativeETH": {
|
||||
"message": "Negatif ETH miktarları gönderilemez."
|
||||
},
|
||||
"networks": {
|
||||
"message": "Ağlar"
|
||||
},
|
||||
"newAccount": {
|
||||
"message": "Yeni Hesap"
|
||||
},
|
||||
"newAccountNumberName": {
|
||||
"message": "Hesap $1",
|
||||
"description": "Hesap yaratma ekranındaki bir sonraki hesabın varsayılan ismi"
|
||||
},
|
||||
"newContract": {
|
||||
"message": "Yeni Sözleşme"
|
||||
},
|
||||
"newPassword": {
|
||||
"message": "Yeni Parola (min 8 karakter)"
|
||||
},
|
||||
"newRecipient": {
|
||||
"message": "Yeni alıcı"
|
||||
},
|
||||
"newRPC": {
|
||||
"message": "Yeni RPC URL"
|
||||
},
|
||||
"next": {
|
||||
"message": "Sonraki"
|
||||
},
|
||||
"noAddressForName": {
|
||||
"message": "Bu isim için bir adres tanımlanmamış."
|
||||
},
|
||||
"noDeposits": {
|
||||
"message": "Yatırma alınmadı"
|
||||
},
|
||||
"noTransactionHistory": {
|
||||
"message": "İşlem geçmişi yok."
|
||||
},
|
||||
"noTransactions": {
|
||||
"message": "İşlem yok"
|
||||
},
|
||||
"notStarted": {
|
||||
"message": "Başlamadı"
|
||||
},
|
||||
"oldUI": {
|
||||
"message": "Eski UI"
|
||||
},
|
||||
"oldUIMessage": {
|
||||
"message": "Eski UI'a döndünüz. Yeni UI'a üst sağ sekme menüsündeki seçenek ile dönebilirsiniz."
|
||||
},
|
||||
"or": {
|
||||
"message": "veya",
|
||||
"description": "Yeni bir hesap yaratmak veya almak arasındaki seçim"
|
||||
},
|
||||
"passwordCorrect": {
|
||||
"message": "Lütfen parolanın doğru olduğuna emin olun."
|
||||
},
|
||||
"passwordMismatch": {
|
||||
"message": "parolalar eşleşmiyor",
|
||||
"description": "parola yaratma işleminde, iki yeni parola alanı eşleşmiyor."
|
||||
},
|
||||
"passwordShort": {
|
||||
"message": "parola yeterince uzun değil",
|
||||
"description": "parola yaratma işleminde, parola güvenli olacak kadar uzun değil."
|
||||
},
|
||||
"pastePrivateKey": {
|
||||
"message": "Özel anahtar dizinizi buraya yapıştırın:",
|
||||
"description": "Özel anahtardan hesap almak için"
|
||||
},
|
||||
"pasteSeed": {
|
||||
"message": "Kaynak ifadenizi buraya yapıştırın!"
|
||||
},
|
||||
"personalAddressDetected": {
|
||||
"message": "Kişisel adres tespit edilidi. Jeton sözleşme adresini girin."
|
||||
},
|
||||
"pleaseReviewTransaction": {
|
||||
"message": "Lütfen işleminizi gözden geçirin."
|
||||
},
|
||||
"popularTokens": {
|
||||
"message": "Popüler Jetonlar"
|
||||
},
|
||||
"privacyMsg": {
|
||||
"message": "Gizlilik Şartları"
|
||||
},
|
||||
"privateKey": {
|
||||
"message": "Özel Anahtar",
|
||||
"description": "Hesap alırken bu tip bir dosya seçin"
|
||||
},
|
||||
"privateKeyWarning": {
|
||||
"message": "Uyarı: Bu anahtarı kimse ile paylaşmayın. Özel anahtarlarınıza sahip herkes hesaplarınızıdaki tüm varlığınızı çalabilir."
|
||||
},
|
||||
"privateNetwork": {
|
||||
"message": "Özel Ağ"
|
||||
},
|
||||
"qrCode": {
|
||||
"message": "QR Kodunu göster"
|
||||
},
|
||||
"readdToken": {
|
||||
"message": "Gelecekte Bu jetonu hesap seçenekleri menüsünde “Jeton ekle”'ye giderek geri ekleyebilirsiniz."
|
||||
},
|
||||
"readMore": {
|
||||
"message": "Burada daha fazla okuyun."
|
||||
},
|
||||
"readMore2": {
|
||||
"message": "Daha fazla okuyun."
|
||||
},
|
||||
"receive": {
|
||||
"message": "Al"
|
||||
},
|
||||
"recipientAddress": {
|
||||
"message": "Alıcı adresi"
|
||||
},
|
||||
"refundAddress": {
|
||||
"message": "İade adresiniz"
|
||||
},
|
||||
"rejected": {
|
||||
"message": "Rededildi"
|
||||
},
|
||||
"resetAccount": {
|
||||
"message": "Hesabı sıfıla"
|
||||
},
|
||||
"restoreFromSeed": {
|
||||
"message": "Kaynak ifadeden geri getir. Restore from seed phrase"
|
||||
},
|
||||
"restoreVault": {
|
||||
"message": "Kasayı geri getir"
|
||||
},
|
||||
"required": {
|
||||
"message": "Gerekli"
|
||||
},
|
||||
"retryWithMoreGas": {
|
||||
"message": "Daha yüksek bir gas fiyatı ile tekrar dene"
|
||||
},
|
||||
"walletSeed": {
|
||||
"message": "Cüzdan Kaynağı"
|
||||
},
|
||||
"revealSeedWords": {
|
||||
"message": "Kaynak kelimelerini göster"
|
||||
},
|
||||
"revealSeedWordsWarning": {
|
||||
"message": "Açık bir yerde kaynak kelimeliriniz geri getirmeyin! Bu kelimeler tüm hesaplarınızı çalmak için kullanılabilir."
|
||||
},
|
||||
"revert": {
|
||||
"message": "Geri döndür"
|
||||
},
|
||||
"rinkeby": {
|
||||
"message": "Rinkeby Test Ağı"
|
||||
},
|
||||
"ropsten": {
|
||||
"message": "Ropsten Test Ağı"
|
||||
},
|
||||
"currentRpc": {
|
||||
"message": "Geçerli RPC"
|
||||
},
|
||||
"connectingToMainnet": {
|
||||
"message": "Main Ethereum Ağına bağlanıyor"
|
||||
},
|
||||
"connectingToRopsten": {
|
||||
"message": "Ropsten Test Ağına bağlanıyor"
|
||||
},
|
||||
"connectingToKovan": {
|
||||
"message": "Kovan Test Ağına bağlanıyor"
|
||||
},
|
||||
"connectingToRinkeby": {
|
||||
"message": "Rinkeby Test Ağına bağlanıyor"
|
||||
},
|
||||
"connectingToUnknown": {
|
||||
"message": "Bilinmeyen Ağa bağlanıyor"
|
||||
},
|
||||
"sampleAccountName": {
|
||||
"message": "E.g. Yeni hesabım",
|
||||
"description": "Kullanıcının hesabına okunabilir isim ekleme konseptini anlamasına yardımcı olmak."
|
||||
},
|
||||
"save": {
|
||||
"message": "Kaydet"
|
||||
},
|
||||
"reprice_title": {
|
||||
"message": "İşlemi Yeniden Fiyatlandır"
|
||||
},
|
||||
"reprice_subtitle": {
|
||||
"message": "İşlemizi hızlandırmayı denemek için gas fiyatınızı yükseltin."
|
||||
},
|
||||
"saveAsFile": {
|
||||
"message": "Dosya olarak kaydet",
|
||||
"description": "Hesap verme işlemi"
|
||||
},
|
||||
"saveSeedAsFile": {
|
||||
"message": "Kaynak Kelimelerini Dosya olarak Kaydet"
|
||||
},
|
||||
"search": {
|
||||
"message": "Ara"
|
||||
},
|
||||
"secretPhrase": {
|
||||
"message": "Kasanızı geri getirmek için gizli 12 kelimelik ifadenizi giriniz."
|
||||
},
|
||||
"newPassword8Chars": {
|
||||
"message": "Yeni Parola (minumum 8 karakter)"
|
||||
},
|
||||
"seedPhraseReq": {
|
||||
"message": "Kaynak ifadeleri 12 kelimedir."
|
||||
},
|
||||
"select": {
|
||||
"message": "Seç"
|
||||
},
|
||||
"selectCurrency": {
|
||||
"message": "Döviz Seç"
|
||||
},
|
||||
"selectService": {
|
||||
"message": "Servis Seç"
|
||||
},
|
||||
"selectType": {
|
||||
"message": "Tip Seç"
|
||||
},
|
||||
"send": {
|
||||
"message": "Gönder"
|
||||
},
|
||||
"sendETH": {
|
||||
"message": "ETH Gönder"
|
||||
},
|
||||
"sendTokens": {
|
||||
"message": "Jeton Gönder"
|
||||
},
|
||||
"onlySendToEtherAddress": {
|
||||
"message": "Ethereum adresine sadece ETH gönder."
|
||||
},
|
||||
"searchTokens": {
|
||||
"message": "Jeton ara"
|
||||
},
|
||||
"sendTokensAnywhere": {
|
||||
"message": "Ethereum hesabı olan birine Jeton gönder"
|
||||
},
|
||||
"settings": {
|
||||
"message": "Ayarlar"
|
||||
},
|
||||
"info": {
|
||||
"message": "Bilgi"
|
||||
},
|
||||
"shapeshiftBuy": {
|
||||
"message": "Shapeshift ile satın al"
|
||||
},
|
||||
"showPrivateKeys": {
|
||||
"message": "Özel anahtarları göster"
|
||||
},
|
||||
"showQRCode": {
|
||||
"message": "QR Kodu göster"
|
||||
},
|
||||
"sign": {
|
||||
"message": "İmza"
|
||||
},
|
||||
"signed": {
|
||||
"message": "İmzalandı"
|
||||
},
|
||||
"signMessage": {
|
||||
"message": "Mesajı İmzala"
|
||||
},
|
||||
"signNotice": {
|
||||
"message": "Bu mesajı imzalamanın tehlikeli \nyan etkileri olabilir. Tamamen güvendiğiniz sitelerden \ngelen mesajları hesabınızla imzalayınız.\n Bu tehlikeli metod gelecek versiyonlarda çıkarılacaktır. "
|
||||
},
|
||||
"sigRequest": {
|
||||
"message": "İmza isteği"
|
||||
},
|
||||
"sigRequested": {
|
||||
"message": "İmza isteniyor"
|
||||
},
|
||||
"spaceBetween": {
|
||||
"message": "Kelimeler arası sadece bir boşluk olabilir."
|
||||
},
|
||||
"status": {
|
||||
"message": "Durum"
|
||||
},
|
||||
"stateLogs": {
|
||||
"message": "Durum Kayıtları"
|
||||
},
|
||||
"stateLogsDescription": {
|
||||
"message": "Durum kayıtları açık hesap adresinizi ve gönderilen işlemleri içerir."
|
||||
},
|
||||
"stateLogError": {
|
||||
"message": "Durum kayıtlarını alma hatası"
|
||||
},
|
||||
"submit": {
|
||||
"message": "Gönder"
|
||||
},
|
||||
"submitted": {
|
||||
"message": "Gönderildi"
|
||||
},
|
||||
"supportCenter": {
|
||||
"message": "Destek merkezimizi ziyaret edin"
|
||||
},
|
||||
"symbolBetweenZeroTen": {
|
||||
"message": "Sembol 0 ve 10 karakter aralığında olmalıdır."
|
||||
},
|
||||
"takesTooLong": {
|
||||
"message": "Çok mu uzun sürüyor?"
|
||||
},
|
||||
"terms": {
|
||||
"message": "Kullanım şartları"
|
||||
},
|
||||
"testFaucet": {
|
||||
"message": "Test Musluğu"
|
||||
},
|
||||
"to": {
|
||||
"message": "Kime: "
|
||||
},
|
||||
"toETHviaShapeShift": {
|
||||
"message": "ShapeShift üstünden $1'dan ETH'e",
|
||||
"description": "system will fill in deposit type in start of message"
|
||||
},
|
||||
"tokenAddress": {
|
||||
"message": "Jeton Adresi"
|
||||
},
|
||||
"tokenAlreadyAdded": {
|
||||
"message": "Jeton çoktan eklenmiş."
|
||||
},
|
||||
"tokenBalance": {
|
||||
"message": "Jeton bakiyeniz:"
|
||||
},
|
||||
"tokenSelection": {
|
||||
"message": "Jeton arayın veya popüler jeton listemizden seçin."
|
||||
},
|
||||
"tokenSymbol": {
|
||||
"message": "Jeton Sembolü"
|
||||
},
|
||||
"tokenWarning1": {
|
||||
"message": "MetaMask hesabınızla aldığınız jetonların kaydını tutun. Başka bir hesapla jetonlar satın aldıysanız, o jetonlar burada gözükmeyecektir."
|
||||
},
|
||||
"total": {
|
||||
"message": "Toplam"
|
||||
},
|
||||
"transactions": {
|
||||
"message": "işlemler"
|
||||
},
|
||||
"transactionError": {
|
||||
"message": "İşlem Hatası. Sözleşme kodundan kural dışı durum fırlatıldı."
|
||||
},
|
||||
"transactionMemo": {
|
||||
"message": "İşlem notu (opsiyonel)"
|
||||
},
|
||||
"transactionNumber": {
|
||||
"message": "İşlem numarası"
|
||||
},
|
||||
"transfers": {
|
||||
"message": "Transferler"
|
||||
},
|
||||
"troubleTokenBalances": {
|
||||
"message": "Jeton bakiyelerinizi yüklerken sorun yaşadık. Buradan izleyebilirsiniz ",
|
||||
"description": "Jeton bakiyelerini görmek için bir link (burası) ile takip ediliyor"
|
||||
},
|
||||
"twelveWords": {
|
||||
"message": "MetaMask hesaplarınızı geri getirmenin tek yolu bu 12 kelimedir.\nBu kelimeleri güvenli ve gizli bir yerde saklayın."
|
||||
},
|
||||
"typePassword": {
|
||||
"message": "Parolanızı girin"
|
||||
},
|
||||
"uiWelcome": {
|
||||
"message": "Yeni UI (Beta)'ya hoşgeldiniz"
|
||||
},
|
||||
"uiWelcomeMessage": {
|
||||
"message": "Şu anda yeni Metamask UI kullanmaktasınız. Gözatın, jeton gönderme gibi yeni özellikleri deneyin ve herhangi bir sorunlar karşılaşırsanız bize haber verin"
|
||||
},
|
||||
"unapproved": {
|
||||
"message": "Onaylanmadı"
|
||||
},
|
||||
"unavailable": {
|
||||
"message": "Mevcut değil"
|
||||
},
|
||||
"unknown": {
|
||||
"message": "Bilinmeyen"
|
||||
},
|
||||
"unknownNetwork": {
|
||||
"message": "Bilinmeyen özel ağ"
|
||||
},
|
||||
"unknownNetworkId": {
|
||||
"message": "Bilinmeyen ağ IDsi"
|
||||
},
|
||||
"uriErrorMsg": {
|
||||
"message": "URIler için HTTP/HTTPS öneki gerekmektedir."
|
||||
},
|
||||
"usaOnly": {
|
||||
"message": "Sadece ABD",
|
||||
"description": "Bu dövizi sadece ABD ikamet edenler kullanabilir"
|
||||
},
|
||||
"usedByClients": {
|
||||
"message": "Farklı istemciler tarafından kullanılmakta"
|
||||
},
|
||||
"useOldUI": {
|
||||
"message": "Eski UI kullan"
|
||||
},
|
||||
"validFileImport": {
|
||||
"message": "Almak için geçerli bir dosya seçmelisiniz"
|
||||
},
|
||||
"vaultCreated": {
|
||||
"message": "Kasa Yaratıldı"
|
||||
},
|
||||
"viewAccount": {
|
||||
"message": "Hesabı İncele"
|
||||
},
|
||||
"visitWebSite": {
|
||||
"message": "Web sitemizi ziyaret edin"
|
||||
},
|
||||
"warning": {
|
||||
"message": "Uyarı"
|
||||
},
|
||||
"welcomeBeta": {
|
||||
"message": "MetaMask Beta'ya Hoşgeldiniz"
|
||||
},
|
||||
"whatsThis": {
|
||||
"message": "Bu nedir?"
|
||||
},
|
||||
"yourSigRequested": {
|
||||
"message": "İmzanız isteniyor"
|
||||
},
|
||||
"youSign": {
|
||||
"message": "İmzalıyorsunuz"
|
||||
}
|
||||
}
|
@ -21,12 +21,16 @@ 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 {
|
||||
ENVIRONMENT_TYPE_POPUP,
|
||||
ENVIRONMENT_TYPE_NOTIFICATION,
|
||||
ENVIRONMENT_TYPE_FULLSCREEN,
|
||||
} = require('./lib/enums')
|
||||
|
||||
const STORAGE_KEY = 'metamask-config'
|
||||
const METAMASK_DEBUG = process.env.METAMASK_DEBUG
|
||||
|
||||
window.log = log
|
||||
log.setDefaultLevel(METAMASK_DEBUG ? 'debug' : 'warn')
|
||||
log.setDefaultLevel(process.env.METAMASK_DEBUG ? 'debug' : 'warn')
|
||||
|
||||
const platform = new ExtensionPlatform()
|
||||
const notificationManager = new NotificationManager()
|
||||
@ -44,7 +48,7 @@ const isEdge = !isIE && !!window.StyleMedia
|
||||
|
||||
let popupIsOpen = false
|
||||
let notificationIsOpen = false
|
||||
let openMetamaskTabsIDs = {}
|
||||
const openMetamaskTabsIDs = {}
|
||||
|
||||
// state persistence
|
||||
const diskStore = new LocalStorageStore({ storageKey: STORAGE_KEY })
|
||||
@ -78,6 +82,28 @@ async function loadStateFromPersistence () {
|
||||
diskStore.getState() ||
|
||||
migrator.generateInitialState(firstTimeState)
|
||||
|
||||
// check if somehow state is empty
|
||||
// this should never happen but new error reporting suggests that it has
|
||||
// for a small number of users
|
||||
// https://github.com/metamask/metamask-extension/issues/3919
|
||||
if (versionedData && !versionedData.data) {
|
||||
// try to recover from diskStore incase only localStore is bad
|
||||
const diskStoreState = diskStore.getState()
|
||||
if (diskStoreState && diskStoreState.data) {
|
||||
// we were able to recover (though it might be old)
|
||||
versionedData = diskStoreState
|
||||
const vaultStructure = getObjStructure(versionedData)
|
||||
raven.captureMessage('MetaMask - Empty vault found - recovered from diskStore', {
|
||||
// "extra" key is required by Sentry
|
||||
extra: { vaultStructure },
|
||||
})
|
||||
} else {
|
||||
// unable to recover, clear state
|
||||
versionedData = migrator.generateInitialState(firstTimeState)
|
||||
raven.captureMessage('MetaMask - Empty vault found - unable to recover')
|
||||
}
|
||||
}
|
||||
|
||||
// report migration errors to sentry
|
||||
migrator.on('error', (err) => {
|
||||
// get vault structure without secrets
|
||||
@ -140,9 +166,9 @@ function setupController (initState, initLangCode) {
|
||||
asStream(controller.store),
|
||||
debounce(1000),
|
||||
storeTransform(versionifyData),
|
||||
storeTransform(syncDataWithExtension),
|
||||
storeTransform(persistData),
|
||||
(error) => {
|
||||
log.error('pump hit error', error)
|
||||
log.error('MetaMask - Persistence pipeline failed', error)
|
||||
}
|
||||
)
|
||||
|
||||
@ -151,7 +177,13 @@ function setupController (initState, initLangCode) {
|
||||
return versionedData
|
||||
}
|
||||
|
||||
function syncDataWithExtension(state) {
|
||||
function persistData (state) {
|
||||
if (!state) {
|
||||
throw new Error('MetaMask - updated state is missing', state)
|
||||
}
|
||||
if (!state.data) {
|
||||
throw new Error('MetaMask - updated state does not have data', state)
|
||||
}
|
||||
if (localStore.isSupported) {
|
||||
localStore.set(state)
|
||||
.catch((err) => {
|
||||
@ -164,30 +196,53 @@ function setupController (initState, initLangCode) {
|
||||
//
|
||||
// connect to other contexts
|
||||
//
|
||||
|
||||
extension.runtime.onConnect.addListener(connectRemote)
|
||||
|
||||
const metamaskInternalProcessHash = {
|
||||
[ENVIRONMENT_TYPE_POPUP]: true,
|
||||
[ENVIRONMENT_TYPE_NOTIFICATION]: true,
|
||||
[ENVIRONMENT_TYPE_FULLSCREEN]: true,
|
||||
}
|
||||
|
||||
const isClientOpenStatus = () => {
|
||||
return popupIsOpen || Boolean(Object.keys(openMetamaskTabsIDs).length) || notificationIsOpen
|
||||
}
|
||||
|
||||
function connectRemote (remotePort) {
|
||||
const isMetaMaskInternalProcess = remotePort.name === 'popup' || remotePort.name === 'notification'
|
||||
const processName = remotePort.name
|
||||
const isMetaMaskInternalProcess = metamaskInternalProcessHash[processName]
|
||||
const portStream = new PortStream(remotePort)
|
||||
|
||||
if (isMetaMaskInternalProcess) {
|
||||
// communication with popup
|
||||
popupIsOpen = popupIsOpen || (remotePort.name === 'popup')
|
||||
controller.isClientOpen = true
|
||||
controller.setupTrustedCommunication(portStream, 'MetaMask')
|
||||
// record popup as closed
|
||||
if (remotePort.sender.url.match(/home.html$/)) {
|
||||
openMetamaskTabsIDs[remotePort.sender.tab.id] = true
|
||||
}
|
||||
if (remotePort.name === 'popup') {
|
||||
|
||||
if (processName === ENVIRONMENT_TYPE_POPUP) {
|
||||
popupIsOpen = true
|
||||
|
||||
endOfStream(portStream, () => {
|
||||
popupIsOpen = false
|
||||
if (remotePort.sender.url.match(/home.html$/)) {
|
||||
openMetamaskTabsIDs[remotePort.sender.tab.id] = false
|
||||
}
|
||||
controller.isClientOpen = isClientOpenStatus()
|
||||
})
|
||||
}
|
||||
if (remotePort.name === 'notification') {
|
||||
|
||||
if (processName === ENVIRONMENT_TYPE_NOTIFICATION) {
|
||||
notificationIsOpen = true
|
||||
|
||||
endOfStream(portStream, () => {
|
||||
notificationIsOpen = false
|
||||
controller.isClientOpen = isClientOpenStatus()
|
||||
})
|
||||
}
|
||||
|
||||
if (processName === ENVIRONMENT_TYPE_FULLSCREEN) {
|
||||
const tabId = remotePort.sender.tab.id
|
||||
openMetamaskTabsIDs[tabId] = true
|
||||
|
||||
endOfStream(portStream, () => {
|
||||
delete openMetamaskTabsIDs[tabId]
|
||||
controller.isClientOpen = isClientOpenStatus()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
@ -230,10 +285,11 @@ function setupController (initState, initLangCode) {
|
||||
|
||||
// popup trigger
|
||||
function triggerUi () {
|
||||
extension.tabs.query({ active: true }, (tabs) => {
|
||||
const currentlyActiveMetamaskTab = tabs.find(tab => openMetamaskTabsIDs[tab.id])
|
||||
if (!popupIsOpen && !currentlyActiveMetamaskTab && !notificationIsOpen) notificationManager.showPopup()
|
||||
notificationIsOpen = true
|
||||
extension.tabs.query({ active: true }, tabs => {
|
||||
const currentlyActiveMetamaskTab = Boolean(tabs.find(tab => openMetamaskTabsIDs[tab.id]))
|
||||
if (!popupIsOpen && !currentlyActiveMetamaskTab && !notificationIsOpen) {
|
||||
notificationManager.showPopup()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,22 @@ const extend = require('xtend')
|
||||
class AddressBookController {
|
||||
|
||||
|
||||
// Controller in charge of managing the address book functionality from the
|
||||
// recipients field on the send screen. Manages a history of all saved
|
||||
// addresses and all currently owned addresses.
|
||||
/**
|
||||
* Controller in charge of managing the address book functionality from the
|
||||
* recipients field on the send screen. Manages a history of all saved
|
||||
* addresses and all currently owned addresses.
|
||||
*
|
||||
* @typedef {Object} AddressBookController
|
||||
* @param {object} opts Overrides the defaults for the initial state of this.store
|
||||
* @property {array} opts.initState initializes the the state of the AddressBookController. Can contain an
|
||||
* addressBook property to initialize the addressBook array
|
||||
* @param {KeyringController} keyringController (Soon to be deprecated) The keyringController used in the current
|
||||
* MetamaskController. Contains the identities used in this AddressBookController.
|
||||
* @property {object} store The the store of the current users address book
|
||||
* @property {array} store.addressBook An array of addresses and nicknames. These are set by the user when sending
|
||||
* to a new address.
|
||||
*
|
||||
*/
|
||||
constructor (opts = {}, keyringController) {
|
||||
const initState = extend({
|
||||
addressBook: [],
|
||||
@ -19,7 +32,14 @@ class AddressBookController {
|
||||
// PUBLIC METHODS
|
||||
//
|
||||
|
||||
// Sets a new address book in store by accepting a new address and nickname.
|
||||
/**
|
||||
* Sets a new address book in store by accepting a new address and nickname.
|
||||
*
|
||||
* @param {string} address A hex address of a new account that the user is sending to.
|
||||
* @param {string} name The name the user wishes to associate with the new account
|
||||
* @returns {Promise<void>} Promise resolves with undefined
|
||||
*
|
||||
*/
|
||||
setAddressBook (address, name) {
|
||||
return this._addToAddressBook(address, name)
|
||||
.then((addressBook) => {
|
||||
@ -30,14 +50,16 @@ class AddressBookController {
|
||||
})
|
||||
}
|
||||
|
||||
//
|
||||
// PRIVATE METHODS
|
||||
//
|
||||
|
||||
|
||||
// Performs the logic to add the address and name into the address book. The
|
||||
// pushed object is an object of two fields. Current behavior does not set an
|
||||
// upper limit to the number of addresses.
|
||||
/**
|
||||
* Performs the logic to add the address and name into the address book. The pushed object is an object of two
|
||||
* fields. Current behavior does not set an upper limit to the number of addresses.
|
||||
*
|
||||
* @private
|
||||
* @param {string} address A hex address of a new account that the user is sending to.
|
||||
* @param {string} name The name the user wishes to associate with the new account
|
||||
* @returns {Promise<array>} Promises the updated addressBook array
|
||||
*
|
||||
*/
|
||||
_addToAddressBook (address, name) {
|
||||
const addressBook = this._getAddressBook()
|
||||
const identities = this._getIdentities()
|
||||
@ -62,14 +84,26 @@ class AddressBookController {
|
||||
return Promise.resolve(addressBook)
|
||||
}
|
||||
|
||||
// Internal method to get the address book. Current persistence behavior
|
||||
// should not require that this method be called from the UI directly.
|
||||
/**
|
||||
* Internal method to get the address book. Current persistence behavior should not require that this method be
|
||||
* called from the UI directly.
|
||||
*
|
||||
* @private
|
||||
* @returns {array} The addressBook array from the store.
|
||||
*
|
||||
*/
|
||||
_getAddressBook () {
|
||||
return this.store.getState().addressBook
|
||||
}
|
||||
|
||||
// Retrieves identities from the keyring controller in order to avoid
|
||||
// duplication
|
||||
/**
|
||||
* Retrieves identities from the keyring controller in order to avoid
|
||||
* duplication
|
||||
*
|
||||
* @deprecated
|
||||
* @returns {array} Returns the identies array from the keyringContoller's state
|
||||
*
|
||||
*/
|
||||
_getIdentities () {
|
||||
return this.keyringController.memStore.getState().identities
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
const ObservableStore = require('obs-store')
|
||||
const extend = require('xtend')
|
||||
const PhishingDetector = require('eth-phishing-detect/src/detector')
|
||||
const log = require('loglevel')
|
||||
|
||||
// compute phishing lists
|
||||
const PHISHING_DETECTION_CONFIG = require('eth-phishing-detect/src/config.json')
|
||||
|
@ -1,11 +1,28 @@
|
||||
const ObservableStore = require('obs-store')
|
||||
const ObservableStore = require('obs-store')
|
||||
const extend = require('xtend')
|
||||
const log = require('loglevel')
|
||||
|
||||
// every ten minutes
|
||||
const POLLING_INTERVAL = 600000
|
||||
|
||||
class CurrencyController {
|
||||
|
||||
/**
|
||||
* Controller responsible for managing data associated with the currently selected currency.
|
||||
*
|
||||
* @typedef {Object} CurrencyController
|
||||
* @param {object} opts Overrides the defaults for the initial state of this.store
|
||||
* @property {array} opts.initState initializes the the state of the CurrencyController. Can contain an
|
||||
* currentCurrency, conversionRate and conversionDate properties
|
||||
* @property {string} currentCurrency A 2-4 character shorthand that describes a specific currency, currently
|
||||
* selected by the user
|
||||
* @property {number} conversionRate The conversion rate from ETH to the selected currency.
|
||||
* @property {string} conversionDate The date at which the conversion rate was set. Expressed in in milliseconds
|
||||
* since midnight of January 1, 1970
|
||||
* @property {number} conversionInterval The id of the interval created by the scheduleConversionInterval method.
|
||||
* Used to clear an existing interval on subsequent calls of that method.
|
||||
*
|
||||
*/
|
||||
constructor (opts = {}) {
|
||||
const initState = extend({
|
||||
currentCurrency: 'usd',
|
||||
@ -19,30 +36,73 @@ class CurrencyController {
|
||||
// PUBLIC METHODS
|
||||
//
|
||||
|
||||
/**
|
||||
* A getter for the currentCurrency property
|
||||
*
|
||||
* @returns {string} A 2-4 character shorthand that describes a specific currency, currently selected by the user
|
||||
*
|
||||
*/
|
||||
getCurrentCurrency () {
|
||||
return this.store.getState().currentCurrency
|
||||
}
|
||||
|
||||
/**
|
||||
* A setter for the currentCurrency property
|
||||
*
|
||||
* @param {string} currentCurrency The new currency to set as the currentCurrency in the store
|
||||
*
|
||||
*/
|
||||
setCurrentCurrency (currentCurrency) {
|
||||
this.store.updateState({ currentCurrency })
|
||||
}
|
||||
|
||||
/**
|
||||
* A getter for the conversionRate property
|
||||
*
|
||||
* @returns {string} The conversion rate from ETH to the selected currency.
|
||||
*
|
||||
*/
|
||||
getConversionRate () {
|
||||
return this.store.getState().conversionRate
|
||||
}
|
||||
|
||||
/**
|
||||
* A setter for the conversionRate property
|
||||
*
|
||||
* @param {number} conversionRate The new rate to set as the conversionRate in the store
|
||||
*
|
||||
*/
|
||||
setConversionRate (conversionRate) {
|
||||
this.store.updateState({ conversionRate })
|
||||
}
|
||||
|
||||
/**
|
||||
* A getter for the conversionDate property
|
||||
*
|
||||
* @returns {string} The date at which the conversion rate was set. Expressed in milliseconds since midnight of
|
||||
* January 1, 1970
|
||||
*
|
||||
*/
|
||||
getConversionDate () {
|
||||
return this.store.getState().conversionDate
|
||||
}
|
||||
|
||||
/**
|
||||
* A setter for the conversionDate property
|
||||
*
|
||||
* @param {number} conversionDate The date, expressed in milliseconds since midnight of January 1, 1970, that the
|
||||
* conversionRate was set
|
||||
*
|
||||
*/
|
||||
setConversionDate (conversionDate) {
|
||||
this.store.updateState({ conversionDate })
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the conversionRate and conversionDate properties associated with the currentCurrency. Updated info is
|
||||
* fetched from an external API
|
||||
*
|
||||
*/
|
||||
async updateConversionRate () {
|
||||
let currentCurrency
|
||||
try {
|
||||
@ -58,6 +118,12 @@ class CurrencyController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new poll, using setInterval, to periodically call updateConversionRate. The id of the interval is
|
||||
* stored at the controller's conversionInterval property. If it is called and such an id already exists, the
|
||||
* previous interval is clear and a new one is created.
|
||||
*
|
||||
*/
|
||||
scheduleConversionInterval () {
|
||||
if (this.conversionInterval) {
|
||||
clearInterval(this.conversionInterval)
|
||||
|
@ -1,5 +1,6 @@
|
||||
const ObservableStore = require('obs-store')
|
||||
const extend = require('xtend')
|
||||
const log = require('loglevel')
|
||||
|
||||
// every ten minutes
|
||||
const POLLING_INTERVAL = 10 * 60 * 1000
|
||||
|
@ -9,6 +9,7 @@ const extend = require('xtend')
|
||||
const EthQuery = require('eth-query')
|
||||
const createEventEmitterProxy = require('../lib/events-proxy.js')
|
||||
const networkConfig = require('../config.js')
|
||||
const log = require('loglevel')
|
||||
const { OLD_UI_NETWORK_TYPE, DEFAULT_RPC } = networkConfig.enums
|
||||
const INFURA_PROVIDER_TYPES = ['ropsten', 'rinkeby', 'kovan', 'mainnet']
|
||||
|
||||
|
@ -4,6 +4,21 @@ const extend = require('xtend')
|
||||
|
||||
class PreferencesController {
|
||||
|
||||
/**
|
||||
*
|
||||
* @typedef {Object} PreferencesController
|
||||
* @param {object} opts Overrides the defaults for the initial state of this.store
|
||||
* @property {object} store The an object containing a users preferences, stored in local storage
|
||||
* @property {array} store.frequentRpcList A list of custom rpcs to provide the user
|
||||
* @property {string} store.currentAccountTab Indicates the selected tab in the ui
|
||||
* @property {array} store.tokens The tokens the user wants display in their token lists
|
||||
* @property {boolean} store.useBlockie The users preference for blockie identicons within the UI
|
||||
* @property {object} store.featureFlags A key-boolean map, where keys refer to features and booleans to whether the
|
||||
* user wishes to see that feature
|
||||
* @property {string} store.currentLocale The preferred language locale key
|
||||
* @property {string} store.selectedAddress A hex string that matches the currently selected address in the app
|
||||
*
|
||||
*/
|
||||
constructor (opts = {}) {
|
||||
const initState = extend({
|
||||
frequentRpcList: [],
|
||||
@ -17,18 +32,43 @@ class PreferencesController {
|
||||
}
|
||||
// PUBLIC METHODS
|
||||
|
||||
/**
|
||||
* Setter for the `useBlockie` property
|
||||
*
|
||||
* @param {boolean} val Whether or not the user prefers blockie indicators
|
||||
*
|
||||
*/
|
||||
setUseBlockie (val) {
|
||||
this.store.updateState({ useBlockie: val })
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the `useBlockie` property
|
||||
*
|
||||
* @returns {boolean} this.store.useBlockie
|
||||
*
|
||||
*/
|
||||
getUseBlockie () {
|
||||
return this.store.getState().useBlockie
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the `currentLocale` property
|
||||
*
|
||||
* @param {string} key he preferred language locale key
|
||||
*
|
||||
*/
|
||||
setCurrentLocale (key) {
|
||||
this.store.updateState({ currentLocale: key })
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the `selectedAddress` property
|
||||
*
|
||||
* @param {string} _address A new hex address for an account
|
||||
* @returns {Promise<void>} Promise resolves with undefined
|
||||
*
|
||||
*/
|
||||
setSelectedAddress (_address) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const address = normalizeAddress(_address)
|
||||
@ -37,10 +77,37 @@ class PreferencesController {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the `selectedAddress` property
|
||||
*
|
||||
* @returns {string} The hex address for the currently selected account
|
||||
*
|
||||
*/
|
||||
getSelectedAddress () {
|
||||
return this.store.getState().selectedAddress
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains data about tokens users add to their account.
|
||||
* @typedef {Object} AddedToken
|
||||
* @property {string} address - The hex address for the token contract. Will be all lower cased and hex-prefixed.
|
||||
* @property {string} symbol - The symbol of the token, usually 3 or 4 capitalized letters
|
||||
* {@link https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#symbol}
|
||||
* @property {boolean} decimals - The number of decimals the token uses.
|
||||
* {@link https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#decimals}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds a new token to the token array, or updates the token if passed an address that already exists.
|
||||
* Modifies the existing tokens array from the store. All objects in the tokens array array AddedToken objects.
|
||||
* @see AddedToken {@link AddedToken}
|
||||
*
|
||||
* @param {string} rawAddress Hex address of the token contract. May or may not be a checksum address.
|
||||
* @param {string} symbol The symbol of the token
|
||||
* @param {number} decimals The number of decimals the token uses.
|
||||
* @returns {Promise<array>} Promises the new array of AddedToken objects.
|
||||
*
|
||||
*/
|
||||
async addToken (rawAddress, symbol, decimals) {
|
||||
const address = normalizeAddress(rawAddress)
|
||||
const newEntry = { address, symbol, decimals }
|
||||
@ -62,6 +129,13 @@ class PreferencesController {
|
||||
return Promise.resolve(tokens)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a specified token from the tokens array.
|
||||
*
|
||||
* @param {string} rawAddress Hex address of the token contract to remove.
|
||||
* @returns {Promise<array>} The new array of AddedToken objects
|
||||
*
|
||||
*/
|
||||
removeToken (rawAddress) {
|
||||
const tokens = this.store.getState().tokens
|
||||
|
||||
@ -71,10 +145,23 @@ class PreferencesController {
|
||||
return Promise.resolve(updatedTokens)
|
||||
}
|
||||
|
||||
/**
|
||||
* A getter for the `tokens` property
|
||||
*
|
||||
* @returns {array} The current array of AddedToken objects
|
||||
*
|
||||
*/
|
||||
getTokens () {
|
||||
return this.store.getState().tokens
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an updated rpc list from this.addToFrequentRpcList() and sets the `frequentRpcList` to this update list.
|
||||
*
|
||||
* @param {string} _url The the new rpc url to add to the updated list
|
||||
* @returns {Promise<void>} Promise resolves with undefined
|
||||
*
|
||||
*/
|
||||
updateFrequentRpcList (_url) {
|
||||
return this.addToFrequentRpcList(_url)
|
||||
.then((rpcList) => {
|
||||
@ -83,6 +170,13 @@ class PreferencesController {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the `currentAccountTab` property
|
||||
*
|
||||
* @param {string} currentAccountTab Specifies the new tab to be marked as current
|
||||
* @returns {Promise<void>} Promise resolves with undefined
|
||||
*
|
||||
*/
|
||||
setCurrentAccountTab (currentAccountTab) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.store.updateState({ currentAccountTab })
|
||||
@ -90,6 +184,15 @@ class PreferencesController {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an updated rpcList based on the passed url and the current list.
|
||||
* The returned list will have a max length of 2. If the _url currently exists it the list, it will be moved to the
|
||||
* end of the list. The current list is modified and returned as a promise.
|
||||
*
|
||||
* @param {string} _url The rpc url to add to the frequentRpcList.
|
||||
* @returns {Promise<array>} The updated frequentRpcList.
|
||||
*
|
||||
*/
|
||||
addToFrequentRpcList (_url) {
|
||||
const rpcList = this.getFrequentRpcList()
|
||||
const index = rpcList.findIndex((element) => { return element === _url })
|
||||
@ -105,10 +208,24 @@ class PreferencesController {
|
||||
return Promise.resolve(rpcList)
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the `frequentRpcList` property.
|
||||
*
|
||||
* @returns {array<string>} An array of one or two rpc urls.
|
||||
*
|
||||
*/
|
||||
getFrequentRpcList () {
|
||||
return this.store.getState().frequentRpcList
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the `featureFlags` property, which is an object. One property within that object will be set to a boolean.
|
||||
*
|
||||
* @param {string} feature A key that corresponds to a UI feature.
|
||||
* @param {boolean} activated Indicates whether or not the UI feature should be displayed
|
||||
* @returns {Promise<object>} Promises a new object; the updated featureFlags object.
|
||||
*
|
||||
*/
|
||||
setFeatureFlag (feature, activated) {
|
||||
const currentFeatureFlags = this.store.getState().featureFlags
|
||||
const updatedFeatureFlags = {
|
||||
@ -121,6 +238,13 @@ class PreferencesController {
|
||||
return Promise.resolve(updatedFeatureFlags)
|
||||
}
|
||||
|
||||
/**
|
||||
* A getter for the `featureFlags` property
|
||||
*
|
||||
* @returns {object} A key-boolean map, where keys refer to features and booleans to whether the
|
||||
* user wishes to see that feature
|
||||
*
|
||||
*/
|
||||
getFeatureFlags () {
|
||||
return this.store.getState().featureFlags
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ const ObservableStore = require('obs-store')
|
||||
const extend = require('xtend')
|
||||
const BN = require('ethereumjs-util').BN
|
||||
const EthQuery = require('eth-query')
|
||||
const log = require('loglevel')
|
||||
|
||||
class RecentBlocksController {
|
||||
|
||||
|
@ -1,11 +1,23 @@
|
||||
const ObservableStore = require('obs-store')
|
||||
const extend = require('xtend')
|
||||
const log = require('loglevel')
|
||||
|
||||
// every three seconds when an incomplete tx is waiting
|
||||
const POLLING_INTERVAL = 3000
|
||||
|
||||
class ShapeshiftController {
|
||||
|
||||
/**
|
||||
* Controller responsible for managing the list of shapeshift transactions. On construction, it initiates a poll
|
||||
* that queries a shapeshift.io API for updates to any pending shapeshift transactions
|
||||
*
|
||||
* @typedef {Object} ShapeshiftController
|
||||
* @param {object} opts Overrides the defaults for the initial state of this.store
|
||||
* @property {array} opts.initState initializes the the state of the ShapeshiftController. Can contain an
|
||||
* shapeShiftTxList array.
|
||||
* @property {array} shapeShiftTxList An array of ShapeShiftTx objects
|
||||
*
|
||||
*/
|
||||
constructor (opts = {}) {
|
||||
const initState = extend({
|
||||
shapeShiftTxList: [],
|
||||
@ -14,21 +26,54 @@ class ShapeshiftController {
|
||||
this.pollForUpdates()
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents, and contains data about, a single shapeshift transaction.
|
||||
* @typedef {Object} ShapeShiftTx
|
||||
* @property {string} depositAddress - An address at which to send a crypto deposit, so that eth can be sent to the
|
||||
* user's Metamask account
|
||||
* @property {string} depositType - An abbreviation of the type of crypto currency to be deposited.
|
||||
* @property {string} key - The 'shapeshift' key differentiates this from other types of txs in Metamask
|
||||
* @property {number} time - The time at which the tx was created
|
||||
* @property {object} response - Initiated as an empty object, which will be replaced by a Response object. @see {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/Response}
|
||||
*/
|
||||
|
||||
//
|
||||
// PUBLIC METHODS
|
||||
//
|
||||
|
||||
/**
|
||||
* A getter for the shapeShiftTxList property
|
||||
*
|
||||
* @returns {array<ShapeShiftTx>}
|
||||
*
|
||||
*/
|
||||
getShapeShiftTxList () {
|
||||
const shapeShiftTxList = this.store.getState().shapeShiftTxList
|
||||
return shapeShiftTxList
|
||||
}
|
||||
|
||||
/**
|
||||
* A getter for all ShapeShiftTx in the shapeShiftTxList that have not successfully completed a deposit.
|
||||
*
|
||||
* @returns {array<ShapeShiftTx>} Only includes ShapeShiftTx which has a response property with a status !== complete
|
||||
*
|
||||
*/
|
||||
getPendingTxs () {
|
||||
const txs = this.getShapeShiftTxList()
|
||||
const pending = txs.filter(tx => tx.response && tx.response.status !== 'complete')
|
||||
return pending
|
||||
}
|
||||
|
||||
/**
|
||||
* A poll that exists as long as there are pending transactions. Each call attempts to update the data of any
|
||||
* pendingTxs, and then calls itself again. If there are no pending txs, the recursive call is not made and
|
||||
* the polling stops.
|
||||
*
|
||||
* this.updateTx is used to attempt the update to the pendingTxs in the ShapeShiftTxList, and that updated data
|
||||
* is saved with saveTx.
|
||||
*
|
||||
*/
|
||||
pollForUpdates () {
|
||||
const pendingTxs = this.getPendingTxs()
|
||||
|
||||
@ -45,6 +90,15 @@ class ShapeshiftController {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to update a ShapeShiftTx with data from a shapeshift.io API. Both the response and time properties
|
||||
* can be updated. The response property is updated with every call, but the time property is only updated when
|
||||
* the response status updates to 'complete'. This will occur once the user makes a deposit as the ShapeShiftTx
|
||||
* depositAddress
|
||||
*
|
||||
* @param {ShapeShiftTx} tx The tx to update
|
||||
*
|
||||
*/
|
||||
async updateTx (tx) {
|
||||
try {
|
||||
const url = `https://shapeshift.io/txStat/${tx.depositAddress}`
|
||||
@ -60,6 +114,13 @@ class ShapeshiftController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves an updated to a ShapeShiftTx in the shapeShiftTxList. If the passed ShapeShiftTx is not in the
|
||||
* shapeShiftTxList, nothing happens.
|
||||
*
|
||||
* @param {ShapeShiftTx} tx The updated tx to save, if it exists in the current shapeShiftTxList
|
||||
*
|
||||
*/
|
||||
saveTx (tx) {
|
||||
const { shapeShiftTxList } = this.store.getState()
|
||||
const index = shapeShiftTxList.indexOf(tx)
|
||||
@ -69,6 +130,12 @@ class ShapeshiftController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a ShapeShiftTx from the shapeShiftTxList
|
||||
*
|
||||
* @param {ShapeShiftTx} tx The tx to remove
|
||||
*
|
||||
*/
|
||||
removeShapeShiftTx (tx) {
|
||||
const { shapeShiftTxList } = this.store.getState()
|
||||
const index = shapeShiftTxList.indexOf(index)
|
||||
@ -78,6 +145,14 @@ class ShapeshiftController {
|
||||
this.updateState({ shapeShiftTxList })
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ShapeShiftTx, adds it to the shapeShiftTxList, and initiates a new poll for updates of pending txs
|
||||
*
|
||||
* @param {string} depositAddress - An address at which to send a crypto deposit, so that eth can be sent to the
|
||||
* user's Metamask account
|
||||
* @param {string} depositType - An abbreviation of the type of crypto currency to be deposited.
|
||||
*
|
||||
*/
|
||||
createShapeShiftTx (depositAddress, depositType) {
|
||||
const state = this.store.getState()
|
||||
let { shapeShiftTxList } = state
|
||||
|
77
app/scripts/controllers/token-rates.js
Normal file
77
app/scripts/controllers/token-rates.js
Normal file
@ -0,0 +1,77 @@
|
||||
const ObservableStore = require('obs-store')
|
||||
|
||||
// By default, poll every 3 minutes
|
||||
const DEFAULT_INTERVAL = 180 * 1000
|
||||
|
||||
/**
|
||||
* A controller that polls for token exchange
|
||||
* rates based on a user's current token list
|
||||
*/
|
||||
class TokenRatesController {
|
||||
/**
|
||||
* Creates a TokenRatesController
|
||||
*
|
||||
* @param {Object} [config] - Options to configure controller
|
||||
*/
|
||||
constructor ({ interval = DEFAULT_INTERVAL, preferences } = {}) {
|
||||
this.store = new ObservableStore()
|
||||
this.preferences = preferences
|
||||
this.interval = interval
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates exchange rates for all tokens
|
||||
*/
|
||||
async updateExchangeRates () {
|
||||
if (!this.isActive) { return }
|
||||
const contractExchangeRates = {}
|
||||
for (const i in this._tokens) {
|
||||
const address = this._tokens[i].address
|
||||
contractExchangeRates[address] = await this.fetchExchangeRate(address)
|
||||
}
|
||||
this.store.putState({ contractExchangeRates })
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a token exchange rate by address
|
||||
*
|
||||
* @param {String} address - Token contract address
|
||||
*/
|
||||
async fetchExchangeRate (address) {
|
||||
try {
|
||||
const response = await fetch(`https://exchanges.balanc3.net/prices?from=${address}&to=ETH&autoConversion=false&summaryOnly=true`)
|
||||
const json = await response.json()
|
||||
return json && json.length ? json[0].averagePrice : 0
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Number} - Interval used to poll for exchange rates
|
||||
*/
|
||||
set interval (interval) {
|
||||
this._handle && clearInterval(this._handle)
|
||||
if (!interval) { return }
|
||||
this._handle = setInterval(() => { this.updateExchangeRates() }, interval)
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Object} - Preferences controller instance
|
||||
*/
|
||||
set preferences (preferences) {
|
||||
this._preferences && this._preferences.unsubscribe()
|
||||
if (!preferences) { return }
|
||||
this._preferences = preferences
|
||||
this.tokens = preferences.getState().tokens
|
||||
preferences.subscribe(({ tokens = [] }) => { this.tokens = tokens })
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Array} - Array of token objects with contract addresses
|
||||
*/
|
||||
set tokens (tokens) {
|
||||
this._tokens = tokens
|
||||
this.updateExchangeRates()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TokenRatesController
|
@ -8,6 +8,7 @@ const TxGasUtil = require('./tx-gas-utils')
|
||||
const PendingTransactionTracker = require('./pending-tx-tracker')
|
||||
const NonceTracker = require('./nonce-tracker')
|
||||
const txUtils = require('./lib/util')
|
||||
const log = require('loglevel')
|
||||
|
||||
/**
|
||||
Transaction Controller is an aggregate of sub-controllers and trackers
|
||||
|
@ -3,16 +3,11 @@ cleanContextForImports()
|
||||
require('web3/dist/web3.min.js')
|
||||
const log = require('loglevel')
|
||||
const LocalMessageDuplexStream = require('post-message-stream')
|
||||
// const PingStream = require('ping-pong-stream/ping')
|
||||
// const endOfStream = require('end-of-stream')
|
||||
const setupDappAutoReload = require('./lib/auto-reload.js')
|
||||
const MetamaskInpageProvider = require('./lib/inpage-provider.js')
|
||||
restoreContextAfterImports()
|
||||
|
||||
const METAMASK_DEBUG = process.env.METAMASK_DEBUG
|
||||
window.log = log
|
||||
log.setDefaultLevel(METAMASK_DEBUG ? 'debug' : 'warn')
|
||||
|
||||
log.setDefaultLevel(process.env.METAMASK_DEBUG ? 'debug' : 'warn')
|
||||
|
||||
//
|
||||
// setup plugin communication
|
||||
|
49
app/scripts/lib/ComposableObservableStore.js
Normal file
49
app/scripts/lib/ComposableObservableStore.js
Normal file
@ -0,0 +1,49 @@
|
||||
const ObservableStore = require('obs-store')
|
||||
|
||||
/**
|
||||
* An ObservableStore that can composes a flat
|
||||
* structure of child stores based on configuration
|
||||
*/
|
||||
class ComposableObservableStore extends ObservableStore {
|
||||
/**
|
||||
* Create a new store
|
||||
*
|
||||
* @param {Object} [initState] - The initial store state
|
||||
* @param {Object} [config] - Map of internal state keys to child stores
|
||||
*/
|
||||
constructor (initState, config) {
|
||||
super(initState)
|
||||
this.updateStructure(config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Composes a new internal store subscription structure
|
||||
*
|
||||
* @param {Object} [config] - Map of internal state keys to child stores
|
||||
*/
|
||||
updateStructure (config) {
|
||||
this.config = config
|
||||
this.removeAllListeners()
|
||||
for (const key in config) {
|
||||
config[key].subscribe((state) => {
|
||||
this.updateState({ [key]: state })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges all child store state into a single object rather than
|
||||
* returning an object keyed by child store class name
|
||||
*
|
||||
* @returns {Object} - Object containing merged child store state
|
||||
*/
|
||||
getFlatState () {
|
||||
let flatState = {}
|
||||
for (const key in this.config) {
|
||||
flatState = { ...flatState, ...this.config[key].getState() }
|
||||
}
|
||||
return flatState
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ComposableObservableStore
|
@ -1,5 +1,16 @@
|
||||
module.exports = getBuyEthUrl
|
||||
|
||||
/**
|
||||
* Gives the caller a url at which the user can acquire eth, depending on the network they are in
|
||||
*
|
||||
* @param {object} opts Options required to determine the correct url
|
||||
* @param {string} opts.network The network for which to return a url
|
||||
* @param {string} opts.amount The amount of ETH to buy on coinbase. Only relevant if network === '1'.
|
||||
* @param {string} opts.address The address the bought ETH should be sent to. Only relevant if network === '1'.
|
||||
* @returns {string|undefined} The url at which the user can access ETH, while in the given network. If the passed
|
||||
* network does not match any of the specified cases, or if no network is given, returns undefined.
|
||||
*
|
||||
*/
|
||||
function getBuyEthUrl ({ network, amount, address }) {
|
||||
let url
|
||||
switch (network) {
|
||||
|
@ -102,7 +102,6 @@ ConfigManager.prototype.setShowSeedWords = function (should) {
|
||||
this.setData(data)
|
||||
}
|
||||
|
||||
|
||||
ConfigManager.prototype.getShouldShowSeedWords = function () {
|
||||
var data = this.getData()
|
||||
return data.showSeedWords
|
||||
@ -118,6 +117,27 @@ ConfigManager.prototype.getSeedWords = function () {
|
||||
var data = this.getData()
|
||||
return data.seedWords
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to set the isRevealingSeedWords flag. This happens only when the user chooses to reveal
|
||||
* the seed words and not during the first time flow.
|
||||
* @param {boolean} reveal - Value to set the isRevealingSeedWords flag.
|
||||
*/
|
||||
ConfigManager.prototype.setIsRevealingSeedWords = function (reveal = false) {
|
||||
const data = this.getData()
|
||||
data.isRevealingSeedWords = reveal
|
||||
this.setData(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the isRevealingSeedWords flag.
|
||||
* @returns {boolean|undefined}
|
||||
*/
|
||||
ConfigManager.prototype.getIsRevealingSeedWords = function () {
|
||||
const data = this.getData()
|
||||
return data.isRevealingSeedWords
|
||||
}
|
||||
|
||||
ConfigManager.prototype.setRpcTarget = function (rpcUrl) {
|
||||
var config = this.getConfig()
|
||||
config.provider = {
|
||||
|
@ -1,14 +1,20 @@
|
||||
// log rpc activity
|
||||
const log = require('loglevel')
|
||||
|
||||
module.exports = createLoggerMiddleware
|
||||
|
||||
function createLoggerMiddleware ({ origin }) {
|
||||
return function loggerMiddleware (req, res, next, end) {
|
||||
next((cb) => {
|
||||
/**
|
||||
* Returns a middleware that logs RPC activity
|
||||
* @param {{ origin: string }} opts - The middleware options
|
||||
* @returns {Function}
|
||||
*/
|
||||
function createLoggerMiddleware (opts) {
|
||||
return function loggerMiddleware (/** @type {any} */ req, /** @type {any} */ res, /** @type {Function} */ next) {
|
||||
next((/** @type {Function} */ cb) => {
|
||||
if (res.error) {
|
||||
log.error('Error in RPC response:\n', res)
|
||||
}
|
||||
if (req.isMetamaskInternal) return
|
||||
log.info(`RPC (${origin}):`, req, '->', res)
|
||||
log.info(`RPC (${opts.origin}):`, req, '->', res)
|
||||
cb()
|
||||
})
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
// append dapp origin domain to request
|
||||
module.exports = createOriginMiddleware
|
||||
|
||||
function createOriginMiddleware ({ origin }) {
|
||||
return function originMiddleware (req, res, next, end) {
|
||||
req.origin = origin
|
||||
/**
|
||||
* Returns a middleware that appends the DApp origin to request
|
||||
* @param {{ origin: string }} opts - The middleware options
|
||||
* @returns {Function}
|
||||
*/
|
||||
function createOriginMiddleware (opts) {
|
||||
return function originMiddleware (/** @type {any} */ req, /** @type {any} */ _, /** @type {Function} */ next) {
|
||||
req.origin = opts.origin
|
||||
next()
|
||||
}
|
||||
}
|
||||
|
9
app/scripts/lib/enums.js
Normal file
9
app/scripts/lib/enums.js
Normal file
@ -0,0 +1,9 @@
|
||||
const ENVIRONMENT_TYPE_POPUP = 'popup'
|
||||
const ENVIRONMENT_TYPE_NOTIFICATION = 'notification'
|
||||
const ENVIRONMENT_TYPE_FULLSCREEN = 'fullscreen'
|
||||
|
||||
module.exports = {
|
||||
ENVIRONMENT_TYPE_POPUP,
|
||||
ENVIRONMENT_TYPE_NOTIFICATION,
|
||||
ENVIRONMENT_TYPE_FULLSCREEN,
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
module.exports = function environmentType () {
|
||||
const url = window.location.href
|
||||
if (url.match(/popup.html$/)) {
|
||||
return 'popup'
|
||||
} else if (url.match(/home.html$/)) {
|
||||
return 'responsive'
|
||||
} else {
|
||||
return 'notification'
|
||||
}
|
||||
}
|
@ -1,26 +1,37 @@
|
||||
/**
|
||||
* Returns an EventEmitter that proxies events from the given event emitter
|
||||
* @param {any} eventEmitter
|
||||
* @param {object} listeners - The listeners to proxy to
|
||||
* @returns {any}
|
||||
*/
|
||||
module.exports = function createEventEmitterProxy (eventEmitter, listeners) {
|
||||
let target = eventEmitter
|
||||
const eventHandlers = listeners || {}
|
||||
const proxy = new Proxy({}, {
|
||||
get: (obj, name) => {
|
||||
const proxy = /** @type {any} */ (new Proxy({}, {
|
||||
get: (_, name) => {
|
||||
// intercept listeners
|
||||
if (name === 'on') return addListener
|
||||
if (name === 'setTarget') return setTarget
|
||||
if (name === 'proxyEventHandlers') return eventHandlers
|
||||
return target[name]
|
||||
return (/** @type {any} */ (target))[name]
|
||||
},
|
||||
set: (obj, name, value) => {
|
||||
set: (_, name, value) => {
|
||||
target[name] = value
|
||||
return true
|
||||
},
|
||||
})
|
||||
function setTarget (eventEmitter) {
|
||||
}))
|
||||
function setTarget (/** @type {EventEmitter} */ eventEmitter) {
|
||||
target = eventEmitter
|
||||
// migrate listeners
|
||||
Object.keys(eventHandlers).forEach((name) => {
|
||||
eventHandlers[name].forEach((handler) => target.on(name, handler))
|
||||
/** @type {Array<Function>} */ (eventHandlers[name]).forEach((handler) => target.on(name, handler))
|
||||
})
|
||||
}
|
||||
/**
|
||||
* Attaches a function to be called whenever the specified event is emitted
|
||||
* @param {string} name
|
||||
* @param {Function} handler
|
||||
*/
|
||||
function addListener (name, handler) {
|
||||
if (!eventHandlers[name]) eventHandlers[name] = []
|
||||
eventHandlers[name].push(handler)
|
||||
|
@ -4,6 +4,13 @@ const allLocales = require('../../_locales/index.json')
|
||||
|
||||
const existingLocaleCodes = allLocales.map(locale => locale.code.toLowerCase().replace('_', '-'))
|
||||
|
||||
/**
|
||||
* Returns a preferred language code, based on settings within the user's browser. If we have no translations for the
|
||||
* users preferred locales, 'en' is returned.
|
||||
*
|
||||
* @returns {Promise<string>} Promises a locale code, either one from the user's preferred list that we have a translation for, or 'en'
|
||||
*
|
||||
*/
|
||||
async function getFirstPreferredLangCode () {
|
||||
const userPreferredLocaleCodes = await promisify(
|
||||
extension.i18n.getAcceptLanguages,
|
||||
|
@ -1,6 +1,11 @@
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const ethUtil = (/** @type {object} */ (require('ethereumjs-util')))
|
||||
const BN = ethUtil.BN
|
||||
|
||||
/**
|
||||
* Returns a [BinaryNumber]{@link BN} representation of the given hex value
|
||||
* @param {string} hex
|
||||
* @return {any}
|
||||
*/
|
||||
module.exports = function hexToBn (hex) {
|
||||
return new BN(ethUtil.stripHexPrefix(hex), 16)
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
module.exports = function isPopupOrNotification () {
|
||||
const url = window.location.href
|
||||
// if (url.match(/popup.html$/) || url.match(/home.html$/)) {
|
||||
// Below regexes needed for feature toggles (e.g. see line ~340 in ui/app/app.js)
|
||||
// Revert below regexes to above commented out regexes before merge to master
|
||||
if (url.match(/popup.html(?:\?.+)*$/) || url.match(/home.html(?:\?.+)*$/)) {
|
||||
return 'popup'
|
||||
} else {
|
||||
return 'notification'
|
||||
}
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
// We should not rely on local storage in an extension!
|
||||
// We should use this instead!
|
||||
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/local
|
||||
|
||||
const extension = require('extensionizer')
|
||||
const log = require('loglevel')
|
||||
|
||||
/**
|
||||
* A wrapper around the extension's storage local API
|
||||
*/
|
||||
module.exports = class ExtensionStore {
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
constructor() {
|
||||
this.isSupported = !!(extension.storage.local)
|
||||
if (!this.isSupported) {
|
||||
@ -12,6 +15,10 @@ module.exports = class ExtensionStore {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all of the keys currently saved
|
||||
* @return {Promise<*>}
|
||||
*/
|
||||
async get() {
|
||||
if (!this.isSupported) return undefined
|
||||
const result = await this._get()
|
||||
@ -24,14 +31,24 @@ module.exports = class ExtensionStore {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key in local state
|
||||
* @param {object} state - The state to set
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async set(state) {
|
||||
return this._set(state)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all of the keys currently saved
|
||||
* @private
|
||||
* @return {object} the key-value map from local storage
|
||||
*/
|
||||
_get() {
|
||||
const local = extension.storage.local
|
||||
return new Promise((resolve, reject) => {
|
||||
local.get(null, (result) => {
|
||||
local.get(null, (/** @type {any} */ result) => {
|
||||
const err = extension.runtime.lastError
|
||||
if (err) {
|
||||
reject(err)
|
||||
@ -42,6 +59,12 @@ module.exports = class ExtensionStore {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key in local state
|
||||
* @param {object} obj - The key to set
|
||||
* @return {Promise<void>}
|
||||
* @private
|
||||
*/
|
||||
_set(obj) {
|
||||
const local = extension.storage.local
|
||||
return new Promise((resolve, reject) => {
|
||||
@ -57,6 +80,11 @@ module.exports = class ExtensionStore {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the given object contains no keys
|
||||
* @param {object} obj - The object to check
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isEmpty(obj) {
|
||||
return Object.keys(obj).length === 0
|
||||
}
|
||||
|
@ -1,7 +1,23 @@
|
||||
const EventEmitter = require('events')
|
||||
|
||||
/**
|
||||
* @typedef {object} Migration
|
||||
* @property {number} version - The migration version
|
||||
* @property {Function} migrate - Returns a promise of the migrated data
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {object} MigratorOptions
|
||||
* @property {Array<Migration>} [migrations] - The list of migrations to apply
|
||||
* @property {number} [defaultVersion] - The version to use in the initial state
|
||||
*/
|
||||
|
||||
class Migrator extends EventEmitter {
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {MigratorOptions} opts
|
||||
*/
|
||||
constructor (opts = {}) {
|
||||
super()
|
||||
const migrations = opts.migrations || []
|
||||
@ -42,19 +58,30 @@ class Migrator extends EventEmitter {
|
||||
|
||||
return versionedData
|
||||
|
||||
// migration is "pending" if it has a higher
|
||||
// version number than currentVersion
|
||||
/**
|
||||
* Returns whether or not the migration is pending
|
||||
*
|
||||
* A migration is considered "pending" if it has a higher
|
||||
* version number than the current version.
|
||||
* @param {Migration} migration
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function migrationIsPending (migration) {
|
||||
return migration.version > versionedData.meta.version
|
||||
}
|
||||
}
|
||||
|
||||
generateInitialState (initState) {
|
||||
/**
|
||||
* Returns the initial state for the migrator
|
||||
* @param {object} [data] - The data for the initial state
|
||||
* @returns {{meta: {version: number}, data: any}}
|
||||
*/
|
||||
generateInitialState (data) {
|
||||
return {
|
||||
meta: {
|
||||
version: this.defaultVersion,
|
||||
},
|
||||
data: initState,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,14 @@
|
||||
const promiseToCallback = require('promise-to-callback')
|
||||
const noop = function () {}
|
||||
|
||||
/**
|
||||
* A generator that returns a function which, when passed a promise, can treat that promise as a node style callback.
|
||||
* The prime advantage being that callbacks are better for error handling.
|
||||
*
|
||||
* @param {Function} fn The function to handle as a callback
|
||||
* @param {Object} context The context in which the fn is to be called, most often a this reference
|
||||
*
|
||||
*/
|
||||
module.exports = function nodeify (fn, context) {
|
||||
return function () {
|
||||
const args = [].slice.call(arguments)
|
||||
|
@ -3,6 +3,7 @@ const ObservableStore = require('obs-store')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const createId = require('./random-id')
|
||||
const hexRe = /^[0-9A-Fa-f]+$/g
|
||||
const log = require('loglevel')
|
||||
|
||||
|
||||
module.exports = class PersonalMessageManager extends EventEmitter {
|
||||
|
@ -1,4 +1,5 @@
|
||||
const KeyringController = require('eth-keyring-controller')
|
||||
const log = require('loglevel')
|
||||
|
||||
const seedPhraseVerifier = {
|
||||
|
||||
|
@ -8,20 +8,34 @@ module.exports = {
|
||||
setupMultiplex: setupMultiplex,
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream transform that parses JSON strings passing through
|
||||
* @return {stream.Transform}
|
||||
*/
|
||||
function jsonParseStream () {
|
||||
return Through.obj(function (serialized, encoding, cb) {
|
||||
return Through.obj(function (serialized, _, cb) {
|
||||
this.push(JSON.parse(serialized))
|
||||
cb()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream transform that calls {@code JSON.stringify}
|
||||
* on objects passing through
|
||||
* @return {stream.Transform} the stream transform
|
||||
*/
|
||||
function jsonStringifyStream () {
|
||||
return Through.obj(function (obj, encoding, cb) {
|
||||
return Through.obj(function (obj, _, cb) {
|
||||
this.push(JSON.stringify(obj))
|
||||
cb()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up stream multiplexing for the given stream
|
||||
* @param {any} connectionStream - the stream to mux
|
||||
* @return {stream.Stream} the multiplexed stream
|
||||
*/
|
||||
function setupMultiplex (connectionStream) {
|
||||
const mux = new ObjectMultiplex()
|
||||
pump(
|
||||
|
@ -3,7 +3,7 @@ const ObservableStore = require('obs-store')
|
||||
const createId = require('./random-id')
|
||||
const assert = require('assert')
|
||||
const sigUtil = require('eth-sig-util')
|
||||
|
||||
const log = require('loglevel')
|
||||
|
||||
module.exports = class TypedMessageManager extends EventEmitter {
|
||||
constructor (opts) {
|
||||
|
@ -1,20 +1,53 @@
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const assert = require('assert')
|
||||
const BN = require('bn.js')
|
||||
const {
|
||||
ENVIRONMENT_TYPE_POPUP,
|
||||
ENVIRONMENT_TYPE_NOTIFICATION,
|
||||
ENVIRONMENT_TYPE_FULLSCREEN,
|
||||
} = require('./enums')
|
||||
|
||||
module.exports = {
|
||||
getStack,
|
||||
sufficientBalance,
|
||||
hexToBn,
|
||||
bnToHex,
|
||||
BnMultiplyByFraction,
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an example stack trace
|
||||
*
|
||||
* @returns {string} A stack trace
|
||||
*
|
||||
*/
|
||||
function getStack () {
|
||||
const stack = new Error('Stack trace generator - not an error').stack
|
||||
return stack
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine the window type through which the app is being viewed.
|
||||
* - 'popup' refers to the extension opened through the browser app icon (in top right corner in chrome and firefox)
|
||||
* - 'responsive' refers to the main browser window
|
||||
* - 'notification' refers to the popup that appears in its own window when taking action outside of metamask
|
||||
*
|
||||
* @returns {string} A single word label that represents the type of window through which the app is being viewed
|
||||
*
|
||||
*/
|
||||
const getEnvironmentType = (url = window.location.href) => {
|
||||
if (url.match(/popup.html(?:\?.+)*$/)) {
|
||||
return ENVIRONMENT_TYPE_POPUP
|
||||
} else if (url.match(/home.html(?:\?.+)*$/) || url.match(/home.html(?:#.*)*$/)) {
|
||||
return ENVIRONMENT_TYPE_FULLSCREEN
|
||||
} else {
|
||||
return ENVIRONMENT_TYPE_NOTIFICATION
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given balance of ETH, represented as a hex string, is sufficient to pay a value plus a gas fee
|
||||
*
|
||||
* @param {object} txParams Contains data about a transaction
|
||||
* @param {string} txParams.gas The gas for a transaction
|
||||
* @param {string} txParams.gasPrice The price per gas for the transaction
|
||||
* @param {string} txParams.value The value of ETH to send
|
||||
* @param {string} hexBalance A balance of ETH represented as a hex string
|
||||
* @returns {boolean} Whether the balance is greater than or equal to the value plus the value of gas times gasPrice
|
||||
*
|
||||
*/
|
||||
function sufficientBalance (txParams, hexBalance) {
|
||||
// validate hexBalance is a hex string
|
||||
assert.equal(typeof hexBalance, 'string', 'sufficientBalance - hexBalance is not a hex string')
|
||||
@ -29,16 +62,48 @@ function sufficientBalance (txParams, hexBalance) {
|
||||
return balance.gte(maxCost)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a BN object to a hex string with a '0x' prefix
|
||||
*
|
||||
* @param {BN} inputBn The BN to convert to a hex string
|
||||
* @returns {string} A '0x' prefixed hex string
|
||||
*
|
||||
*/
|
||||
function bnToHex (inputBn) {
|
||||
return ethUtil.addHexPrefix(inputBn.toString(16))
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a hex string to a BN object
|
||||
*
|
||||
* @param {string} inputHex A number represented as a hex string
|
||||
* @returns {Object} A BN object
|
||||
*
|
||||
*/
|
||||
function hexToBn (inputHex) {
|
||||
return new BN(ethUtil.stripHexPrefix(inputHex), 16)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to multiply a BN by a fraction
|
||||
*
|
||||
* @param {BN} targetBN The number to multiply by a fraction
|
||||
* @param {number|string} numerator The numerator of the fraction multiplier
|
||||
* @param {number|string} denominator The denominator of the fraction multiplier
|
||||
* @returns {BN} The product of the multiplication
|
||||
*
|
||||
*/
|
||||
function BnMultiplyByFraction (targetBN, numerator, denominator) {
|
||||
const numBN = new BN(numerator)
|
||||
const denomBN = new BN(denominator)
|
||||
return targetBN.mul(numBN).div(denomBN)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getStack,
|
||||
getEnvironmentType,
|
||||
sufficientBalance,
|
||||
hexToBn,
|
||||
bnToHex,
|
||||
BnMultiplyByFraction,
|
||||
}
|
||||
|
@ -5,10 +5,10 @@
|
||||
*/
|
||||
|
||||
const EventEmitter = require('events')
|
||||
const extend = require('xtend')
|
||||
const pump = require('pump')
|
||||
const Dnode = require('dnode')
|
||||
const ObservableStore = require('obs-store')
|
||||
const ComposableObservableStore = require('./lib/ComposableObservableStore')
|
||||
const asStream = require('obs-store/lib/asStream')
|
||||
const AccountTracker = require('./lib/account-tracker')
|
||||
const RpcEngine = require('json-rpc-engine')
|
||||
@ -34,6 +34,7 @@ const PersonalMessageManager = require('./lib/personal-message-manager')
|
||||
const TypedMessageManager = require('./lib/typed-message-manager')
|
||||
const TransactionController = require('./controllers/transactions')
|
||||
const BalancesController = require('./controllers/computed-balances')
|
||||
const TokenRatesController = require('./controllers/token-rates')
|
||||
const ConfigManager = require('./lib/config-manager')
|
||||
const nodeify = require('./lib/nodeify')
|
||||
const accountImporter = require('./account-import-strategies')
|
||||
@ -44,6 +45,7 @@ const BN = require('ethereumjs-util').BN
|
||||
const GWEI_BN = new BN('1000000000')
|
||||
const percentile = require('percentile')
|
||||
const seedPhraseVerifier = require('./lib/seed-phrase-verifier')
|
||||
const log = require('loglevel')
|
||||
|
||||
module.exports = class MetamaskController extends EventEmitter {
|
||||
|
||||
@ -65,7 +67,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
this.platform = opts.platform
|
||||
|
||||
// observable state store
|
||||
this.store = new ObservableStore(initState)
|
||||
this.store = new ComposableObservableStore(initState)
|
||||
|
||||
// lock to ensure only one vault created at once
|
||||
this.createVaultMutex = new Mutex()
|
||||
@ -104,6 +106,11 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
this.provider = this.initializeProvider()
|
||||
this.blockTracker = this.provider._blockTracker
|
||||
|
||||
// token exchange rate tracker
|
||||
this.tokenRatesController = new TokenRatesController({
|
||||
preferences: this.preferencesController.store,
|
||||
})
|
||||
|
||||
this.recentBlocksController = new RecentBlocksController({
|
||||
blockTracker: this.blockTracker,
|
||||
provider: this.provider,
|
||||
@ -184,53 +191,37 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
this.typedMessageManager = new TypedMessageManager()
|
||||
this.publicConfigStore = this.initPublicConfigStore()
|
||||
|
||||
// manual disk state subscriptions
|
||||
this.txController.store.subscribe((state) => {
|
||||
this.store.updateState({ TransactionController: state })
|
||||
})
|
||||
this.keyringController.store.subscribe((state) => {
|
||||
this.store.updateState({ KeyringController: state })
|
||||
})
|
||||
this.preferencesController.store.subscribe((state) => {
|
||||
this.store.updateState({ PreferencesController: state })
|
||||
})
|
||||
this.addressBookController.store.subscribe((state) => {
|
||||
this.store.updateState({ AddressBookController: state })
|
||||
})
|
||||
this.currencyController.store.subscribe((state) => {
|
||||
this.store.updateState({ CurrencyController: state })
|
||||
})
|
||||
this.noticeController.store.subscribe((state) => {
|
||||
this.store.updateState({ NoticeController: state })
|
||||
})
|
||||
this.shapeshiftController.store.subscribe((state) => {
|
||||
this.store.updateState({ ShapeShiftController: state })
|
||||
})
|
||||
this.networkController.store.subscribe((state) => {
|
||||
this.store.updateState({ NetworkController: state })
|
||||
this.store.updateStructure({
|
||||
TransactionController: this.txController.store,
|
||||
KeyringController: this.keyringController.store,
|
||||
PreferencesController: this.preferencesController.store,
|
||||
AddressBookController: this.addressBookController.store,
|
||||
CurrencyController: this.currencyController.store,
|
||||
NoticeController: this.noticeController.store,
|
||||
ShapeShiftController: this.shapeshiftController.store,
|
||||
NetworkController: this.networkController.store,
|
||||
InfuraController: this.infuraController.store,
|
||||
})
|
||||
|
||||
this.infuraController.store.subscribe((state) => {
|
||||
this.store.updateState({ InfuraController: state })
|
||||
this.memStore = new ComposableObservableStore(null, {
|
||||
NetworkController: this.networkController.store,
|
||||
AccountTracker: this.accountTracker.store,
|
||||
TxController: this.txController.memStore,
|
||||
BalancesController: this.balancesController.store,
|
||||
TokenRatesController: this.tokenRatesController.store,
|
||||
MessageManager: this.messageManager.memStore,
|
||||
PersonalMessageManager: this.personalMessageManager.memStore,
|
||||
TypesMessageManager: this.typedMessageManager.memStore,
|
||||
KeyringController: this.keyringController.memStore,
|
||||
PreferencesController: this.preferencesController.store,
|
||||
RecentBlocksController: this.recentBlocksController.store,
|
||||
AddressBookController: this.addressBookController.store,
|
||||
CurrencyController: this.currencyController.store,
|
||||
NoticeController: this.noticeController.memStore,
|
||||
ShapeshiftController: this.shapeshiftController.store,
|
||||
InfuraController: this.infuraController.store,
|
||||
})
|
||||
|
||||
// manual mem state subscriptions
|
||||
const sendUpdate = this.sendUpdate.bind(this)
|
||||
this.networkController.store.subscribe(sendUpdate)
|
||||
this.accountTracker.store.subscribe(sendUpdate)
|
||||
this.txController.memStore.subscribe(sendUpdate)
|
||||
this.balancesController.store.subscribe(sendUpdate)
|
||||
this.messageManager.memStore.subscribe(sendUpdate)
|
||||
this.personalMessageManager.memStore.subscribe(sendUpdate)
|
||||
this.typedMessageManager.memStore.subscribe(sendUpdate)
|
||||
this.keyringController.memStore.subscribe(sendUpdate)
|
||||
this.preferencesController.store.subscribe(sendUpdate)
|
||||
this.recentBlocksController.store.subscribe(sendUpdate)
|
||||
this.addressBookController.store.subscribe(sendUpdate)
|
||||
this.currencyController.store.subscribe(sendUpdate)
|
||||
this.noticeController.memStore.subscribe(sendUpdate)
|
||||
this.shapeshiftController.store.subscribe(sendUpdate)
|
||||
this.infuraController.store.subscribe(sendUpdate)
|
||||
this.memStore.subscribe(this.sendUpdate.bind(this))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -279,6 +270,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
|
||||
// memStore -> transform -> publicConfigStore
|
||||
this.on('update', (memState) => {
|
||||
this.isClientOpenAndUnlocked = memState.isUnlocked && this._isClientOpen
|
||||
const publicState = selectPublicState(memState)
|
||||
publicConfigStore.putState(publicState)
|
||||
})
|
||||
@ -308,33 +300,17 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
const vault = this.keyringController.store.getState().vault
|
||||
const isInitialized = (!!wallet || !!vault)
|
||||
|
||||
return extend(
|
||||
{
|
||||
isInitialized,
|
||||
},
|
||||
this.networkController.store.getState(),
|
||||
this.accountTracker.store.getState(),
|
||||
this.txController.memStore.getState(),
|
||||
this.messageManager.memStore.getState(),
|
||||
this.personalMessageManager.memStore.getState(),
|
||||
this.typedMessageManager.memStore.getState(),
|
||||
this.keyringController.memStore.getState(),
|
||||
this.balancesController.store.getState(),
|
||||
this.preferencesController.store.getState(),
|
||||
this.addressBookController.store.getState(),
|
||||
this.currencyController.store.getState(),
|
||||
this.noticeController.memStore.getState(),
|
||||
this.infuraController.store.getState(),
|
||||
this.recentBlocksController.store.getState(),
|
||||
// config manager
|
||||
this.configManager.getConfig(),
|
||||
this.shapeshiftController.store.getState(),
|
||||
{
|
||||
return {
|
||||
...{ isInitialized },
|
||||
...this.memStore.getFlatState(),
|
||||
...this.configManager.getConfig(),
|
||||
...{
|
||||
lostAccounts: this.configManager.getLostAccounts(),
|
||||
seedWords: this.configManager.getSeedWords(),
|
||||
forgottenPassword: this.configManager.getPasswordForgotten(),
|
||||
}
|
||||
)
|
||||
isRevealingSeedWords: Boolean(this.configManager.getIsRevealingSeedWords()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -372,6 +348,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
clearSeedWordCache: this.clearSeedWordCache.bind(this),
|
||||
resetAccount: nodeify(this.resetAccount, this),
|
||||
importAccountWithStrategy: this.importAccountWithStrategy.bind(this),
|
||||
setIsRevealingSeedWords: this.configManager.setIsRevealingSeedWords.bind(this.configManager),
|
||||
|
||||
// vault management
|
||||
submitPassword: nodeify(keyringController.submitPassword, keyringController),
|
||||
@ -1057,4 +1034,12 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
set isClientOpen (open) {
|
||||
this._isClientOpen = open
|
||||
this.isClientOpenAndUnlocked = this.getState().isUnlocked && open
|
||||
}
|
||||
|
||||
set isClientOpenAndUnlocked (active) {
|
||||
this.tokenRatesController.isActive = active
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,25 @@
|
||||
|
||||
class SwPlatform {
|
||||
|
||||
//
|
||||
// Public
|
||||
//
|
||||
|
||||
/**
|
||||
* Reloads the platform
|
||||
*/
|
||||
reload () {
|
||||
// you cant actually do this
|
||||
global.location.reload()
|
||||
// TODO: you can't actually do this
|
||||
/** @type {any} */ (global).location.reload()
|
||||
}
|
||||
|
||||
openWindow ({ url }) {
|
||||
// this doesnt actually work
|
||||
global.open(url, '_blank')
|
||||
/**
|
||||
* Opens a window
|
||||
* @param {{url: string}} opts - The window options
|
||||
*/
|
||||
openWindow (opts) {
|
||||
// TODO: this doesn't actually work
|
||||
/** @type {any} */ (global).open(opts.url, '_blank')
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the platform version
|
||||
* @returns {string}
|
||||
*/
|
||||
getVersion () {
|
||||
return '<unable to read version>'
|
||||
}
|
||||
|
@ -1,18 +1,23 @@
|
||||
|
||||
class WindowPlatform {
|
||||
|
||||
//
|
||||
// Public
|
||||
//
|
||||
|
||||
/**
|
||||
* Reload the platform
|
||||
*/
|
||||
reload () {
|
||||
global.location.reload()
|
||||
/** @type {any} */ (global).location.reload()
|
||||
}
|
||||
|
||||
openWindow ({ url }) {
|
||||
global.open(url, '_blank')
|
||||
/**
|
||||
* Opens a window
|
||||
* @param {{url: string}} opts - The window options
|
||||
*/
|
||||
openWindow (opts) {
|
||||
/** @type {any} */ (global).open(opts.url, '_blank')
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the platform version
|
||||
* @returns {string}
|
||||
*/
|
||||
getVersion () {
|
||||
return '<unable to read version>'
|
||||
}
|
||||
|
@ -3,12 +3,14 @@ const OldMetaMaskUiCss = require('../../old-ui/css')
|
||||
const NewMetaMaskUiCss = require('../../ui/css')
|
||||
const startPopup = require('./popup-core')
|
||||
const PortStream = require('./lib/port-stream.js')
|
||||
const isPopupOrNotification = require('./lib/is-popup-or-notification')
|
||||
const { getEnvironmentType } = require('./lib/util')
|
||||
const { ENVIRONMENT_TYPE_NOTIFICATION } = require('./lib/enums')
|
||||
const extension = require('extensionizer')
|
||||
const ExtensionPlatform = require('./platforms/extension')
|
||||
const NotificationManager = require('./lib/notification-manager')
|
||||
const notificationManager = new NotificationManager()
|
||||
const setupRaven = require('./lib/setupRaven')
|
||||
const log = require('loglevel')
|
||||
|
||||
start().catch(log.error)
|
||||
|
||||
@ -26,7 +28,7 @@ async function start() {
|
||||
// injectCss(css)
|
||||
|
||||
// identify window type (popup, notification)
|
||||
const windowType = isPopupOrNotification()
|
||||
const windowType = getEnvironmentType(window.location.href)
|
||||
global.METAMASK_UI_TYPE = windowType
|
||||
closePopupIfOpen(windowType)
|
||||
|
||||
@ -68,7 +70,7 @@ async function start() {
|
||||
|
||||
|
||||
function closePopupIfOpen (windowType) {
|
||||
if (windowType !== 'notification') {
|
||||
if (windowType !== ENVIRONMENT_TYPE_NOTIFICATION) {
|
||||
// should close only chrome popup
|
||||
notificationManager.closePopup()
|
||||
}
|
||||
|
@ -36,15 +36,28 @@ log.setLevel('debug')
|
||||
//
|
||||
|
||||
const qs = require('qs')
|
||||
let queryString = qs.parse(window.location.href.split('#')[1])
|
||||
let selectedView = queryString.view || 'first time'
|
||||
const routerPath = window.location.href.split('#')[1]
|
||||
let queryString = {}
|
||||
let selectedView
|
||||
|
||||
if (routerPath) {
|
||||
queryString = qs.parse(routerPath.split('?')[1])
|
||||
}
|
||||
|
||||
selectedView = queryString.view || 'first time'
|
||||
const firstState = states[selectedView]
|
||||
updateQueryParams(selectedView)
|
||||
|
||||
function updateQueryParams(newView) {
|
||||
function updateQueryParams (newView) {
|
||||
queryString.view = newView
|
||||
const params = qs.stringify(queryString)
|
||||
window.location.href = window.location.href.split('#')[0] + `#${params}`
|
||||
const locationPaths = window.location.href.split('#')
|
||||
const routerPath = locationPaths[1] || ''
|
||||
const newPath = locationPaths[0] + '#' + routerPath.split('?')[0] + `?${params}`
|
||||
|
||||
if (window.location.href !== newPath) {
|
||||
window.location.href = newPath
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
134
development/states/currency-localization.json
Normal file
134
development/states/currency-localization.json
Normal file
@ -0,0 +1,134 @@
|
||||
{
|
||||
"metamask": {
|
||||
"isInitialized": true,
|
||||
"isUnlocked": true,
|
||||
"featureFlags": {"betaUI": true},
|
||||
"rpcTarget": "https://rawtestrpc.metamask.io/",
|
||||
"identities": {
|
||||
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
|
||||
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
|
||||
"name": "Send Account 1"
|
||||
},
|
||||
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
|
||||
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb",
|
||||
"name": "Send Account 2"
|
||||
},
|
||||
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
|
||||
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d",
|
||||
"name": "Send Account 3"
|
||||
},
|
||||
"0xd85a4b6a394794842887b8284293d69163007bbb": {
|
||||
"address": "0xd85a4b6a394794842887b8284293d69163007bbb",
|
||||
"name": "Send Account 4"
|
||||
}
|
||||
},
|
||||
"unapprovedTxs": {},
|
||||
"currentCurrency": "USD",
|
||||
"conversionRate": 19855,
|
||||
"conversionDate": 1489013762,
|
||||
"noActiveNotices": true,
|
||||
"frequentRpcList": [],
|
||||
"network": "3",
|
||||
"accounts": {
|
||||
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
|
||||
"code": "0x",
|
||||
"balance": "0x47c9d71831c76efe",
|
||||
"nonce": "0x1b",
|
||||
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825"
|
||||
},
|
||||
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
|
||||
"code": "0x",
|
||||
"balance": "0x37452b1315889f80",
|
||||
"nonce": "0xa",
|
||||
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb"
|
||||
},
|
||||
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
|
||||
"code": "0x",
|
||||
"balance": "0x30c9d71831c76efe",
|
||||
"nonce": "0x1c",
|
||||
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d"
|
||||
},
|
||||
"0xd85a4b6a394794842887b8284293d69163007bbb": {
|
||||
"code": "0x",
|
||||
"balance": "0x0",
|
||||
"nonce": "0x0",
|
||||
"address": "0xd85a4b6a394794842887b8284293d69163007bbb"
|
||||
}
|
||||
},
|
||||
"addressBook": [
|
||||
{
|
||||
"address": "0x06195827297c7a80a443b6894d3bdb8824b43896",
|
||||
"name": "Address Book Account 1"
|
||||
}
|
||||
],
|
||||
"tokens": [],
|
||||
"transactions": {},
|
||||
"selectedAddressTxList": [],
|
||||
"unapprovedMsgs": {},
|
||||
"unapprovedMsgCount": 0,
|
||||
"unapprovedPersonalMsgs": {},
|
||||
"unapprovedPersonalMsgCount": 0,
|
||||
"keyringTypes": [
|
||||
"Simple Key Pair",
|
||||
"HD Key Tree"
|
||||
],
|
||||
"keyrings": [
|
||||
{
|
||||
"type": "HD Key Tree",
|
||||
"accounts": [
|
||||
"fdea65c8e26263f6d9a1b5de9555d2931a33b825",
|
||||
"c5b8dbac4c1d3f152cdeb400e2313f309c410acb",
|
||||
"2f8d4a878cfa04a6e60d46362f5644deab66572d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Simple Key Pair",
|
||||
"accounts": [
|
||||
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825"
|
||||
]
|
||||
}
|
||||
],
|
||||
"selectedAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
|
||||
"currentCurrency": "PHP",
|
||||
"provider": {
|
||||
"type": "testnet"
|
||||
},
|
||||
"shapeShiftTxList": [],
|
||||
"lostAccounts": [],
|
||||
"send": {
|
||||
"gasLimit": null,
|
||||
"gasPrice": null,
|
||||
"gasTotal": "0xb451dc41b578",
|
||||
"tokenBalance": null,
|
||||
"from": "",
|
||||
"to": "",
|
||||
"amount": "0x0",
|
||||
"memo": "",
|
||||
"errors": {},
|
||||
"maxModeOn": false,
|
||||
"editingTransactionId": null
|
||||
},
|
||||
"currentLocale": "en"
|
||||
},
|
||||
"appState": {
|
||||
"menuOpen": false,
|
||||
"currentView": {
|
||||
"name": "accountDetail",
|
||||
"detailView": null,
|
||||
"context": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
|
||||
},
|
||||
"accountDetail": {
|
||||
"subview": "transactions"
|
||||
},
|
||||
"modal": {
|
||||
"modalState": {},
|
||||
"previousModalState": {}
|
||||
},
|
||||
"transForward": true,
|
||||
"isLoading": false,
|
||||
"warning": null,
|
||||
"scrollToBottom": false,
|
||||
"forgottenPassword": null
|
||||
},
|
||||
"identities": {}
|
||||
}
|
25
development/tools/.jsdoc.json
Normal file
25
development/tools/.jsdoc.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"tags": {
|
||||
"allowUnknownTags": false
|
||||
},
|
||||
"source": {
|
||||
"include": "app/scripts/",
|
||||
"includePattern": ".js$",
|
||||
"excludePattern": "(node_modules/|docs)"
|
||||
},
|
||||
"plugins": [
|
||||
"plugins/markdown"
|
||||
],
|
||||
"opts": {
|
||||
"template": "node_modules/radgrad-jsdoc-template/",
|
||||
"encoding": "utf8",
|
||||
"destination": "docs/jsdocs",
|
||||
"recurse": true,
|
||||
"verbose": true
|
||||
},
|
||||
"templates": {
|
||||
"cleverLinks": false,
|
||||
"monospaceLinks": false
|
||||
}
|
||||
}
|
||||
|
15
development/tools/README.md
Normal file
15
development/tools/README.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Development Tools & Configurations
|
||||
|
||||
This folder contains configuration files which are used by the the different
|
||||
development-tools, like e.g. JsDoc.
|
||||
|
||||
|
||||
## Appveyor
|
||||
|
||||
|
||||
https://www.appveyor.com/docs/build-configuration/#alternative-yaml-file-location
|
||||
|
||||
Withtin the configuration, point to a weblocation of a txt config file:
|
||||
|
||||
https://ci.appveyor.com/project/lazaridiscom/mm-vault/settings
|
||||
https://raw.githubusercontent.com/lazaridiscom/mm-vault/master/dev/tools/appveyor.txt
|
21
development/tools/appveyor.txt
Normal file
21
development/tools/appveyor.txt
Normal file
@ -0,0 +1,21 @@
|
||||
# Test against the latest version of this Node.js version
|
||||
environment:
|
||||
nodejs_version: "8"
|
||||
|
||||
# Install scripts. (runs after repo cloning)
|
||||
install:
|
||||
# Get the latest stable version of Node.js or io.js
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
# install modules
|
||||
- npm install
|
||||
|
||||
# Post-install test scripts.
|
||||
test_script:
|
||||
# Output useful info for debugging.
|
||||
- node --version
|
||||
- npm --version
|
||||
# run tests
|
||||
- npm test
|
||||
|
||||
# Don't actually build.
|
||||
build: off
|
471
docs/jsdocs/controllers_transactions.js.html
Normal file
471
docs/jsdocs/controllers_transactions.js.html
Normal file
@ -0,0 +1,471 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="google" content="notranslate">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<title>controllers/transactions.js - Documentation</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"></script>
|
||||
<script src="scripts/prettify/lang-css.js"></script>
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.1.1.min.js"
|
||||
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="scripts/semantic.min.js"></script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/semantic.min.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/override.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
||||
<label for="nav-trigger" class="navicon-button x">
|
||||
<div class="navicon"></div>
|
||||
</label>
|
||||
|
||||
<label for="nav-trigger" class="overlay"></label>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><div class="ui vertical accordion"><div class="title"><div class="ui list"><div class="item"><i class="inverted dropdown icon"></i><a href="module.exports_module.exports.html">exports</a></div></div></div></li></div></ul><h3><a href="global.html">Global</a></h3>
|
||||
</nav>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">controllers/transactions.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>const EventEmitter = require('events')
|
||||
const ObservableStore = require('obs-store')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
/**
|
||||
* @file The transaction controller. Receives incoming transactions, and emits events for various states of their processing.
|
||||
* @copyright Copyright (c) 2018 MetaMask
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
|
||||
const Transaction = require('ethereumjs-tx')
|
||||
const EthQuery = require('ethjs-query')
|
||||
const TransactionStateManager = require('../lib/tx-state-manager')
|
||||
const TxGasUtil = require('../lib/tx-gas-utils')
|
||||
const PendingTransactionTracker = require('../lib/pending-tx-tracker')
|
||||
const NonceTracker = require('../lib/nonce-tracker')
|
||||
|
||||
/*
|
||||
Transaction Controller is an aggregate of sub-controllers and trackers
|
||||
composing them in a way to be exposed to the metamask controller
|
||||
- txStateManager
|
||||
responsible for the state of a transaction and
|
||||
storing the transaction
|
||||
- pendingTxTracker
|
||||
watching blocks for transactions to be include
|
||||
and emitting confirmed events
|
||||
- txGasUtil
|
||||
gas calculations and safety buffering
|
||||
- nonceTracker
|
||||
calculating nonces
|
||||
*/
|
||||
|
||||
module.exports = class TransactionController extends EventEmitter {
|
||||
constructor (opts) {
|
||||
super()
|
||||
this.networkStore = opts.networkStore || new ObservableStore({})
|
||||
this.preferencesStore = opts.preferencesStore || new ObservableStore({})
|
||||
this.provider = opts.provider
|
||||
this.blockTracker = opts.blockTracker
|
||||
this.signEthTx = opts.signTransaction
|
||||
this.getGasPrice = opts.getGasPrice
|
||||
|
||||
this.memStore = new ObservableStore({})
|
||||
this.query = new EthQuery(this.provider)
|
||||
this.txGasUtil = new TxGasUtil(this.provider)
|
||||
|
||||
this.txStateManager = new TransactionStateManager({
|
||||
initState: opts.initState,
|
||||
txHistoryLimit: opts.txHistoryLimit,
|
||||
getNetwork: this.getNetwork.bind(this),
|
||||
})
|
||||
|
||||
this.txStateManager.getFilteredTxList({
|
||||
status: 'unapproved',
|
||||
loadingDefaults: true,
|
||||
}).forEach((tx) => {
|
||||
this.addTxDefaults(tx)
|
||||
.then((txMeta) => {
|
||||
txMeta.loadingDefaults = false
|
||||
this.txStateManager.updateTx(txMeta, 'transactions: gas estimation for tx on boot')
|
||||
}).catch((error) => {
|
||||
this.txStateManager.setTxStatusFailed(tx.id, error)
|
||||
})
|
||||
})
|
||||
|
||||
this.txStateManager.getFilteredTxList({
|
||||
status: 'approved',
|
||||
}).forEach((txMeta) => {
|
||||
const txSignError = new Error('Transaction found as "approved" during boot - possibly stuck during signing')
|
||||
this.txStateManager.setTxStatusFailed(txMeta.id, txSignError)
|
||||
})
|
||||
|
||||
|
||||
this.store = this.txStateManager.store
|
||||
this.txStateManager.on('tx:status-update', this.emit.bind(this, 'tx:status-update'))
|
||||
this.nonceTracker = new NonceTracker({
|
||||
provider: this.provider,
|
||||
getPendingTransactions: this.txStateManager.getPendingTransactions.bind(this.txStateManager),
|
||||
getConfirmedTransactions: (address) => {
|
||||
return this.txStateManager.getFilteredTxList({
|
||||
from: address,
|
||||
status: 'confirmed',
|
||||
err: undefined,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
this.pendingTxTracker = new PendingTransactionTracker({
|
||||
provider: this.provider,
|
||||
nonceTracker: this.nonceTracker,
|
||||
publishTransaction: (rawTx) => this.query.sendRawTransaction(rawTx),
|
||||
getPendingTransactions: this.txStateManager.getPendingTransactions.bind(this.txStateManager),
|
||||
getCompletedTransactions: this.txStateManager.getConfirmedTransactions.bind(this.txStateManager),
|
||||
})
|
||||
|
||||
this.txStateManager.store.subscribe(() => this.emit('update:badge'))
|
||||
|
||||
this.pendingTxTracker.on('tx:warning', (txMeta) => {
|
||||
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning')
|
||||
})
|
||||
this.pendingTxTracker.on('tx:confirmed', (txId) => this._markNonceDuplicatesDropped(txId))
|
||||
this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager))
|
||||
this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => {
|
||||
if (!txMeta.firstRetryBlockNumber) {
|
||||
txMeta.firstRetryBlockNumber = latestBlockNumber
|
||||
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:block-update')
|
||||
}
|
||||
})
|
||||
this.pendingTxTracker.on('tx:retry', (txMeta) => {
|
||||
if (!('retryCount' in txMeta)) txMeta.retryCount = 0
|
||||
txMeta.retryCount++
|
||||
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry')
|
||||
})
|
||||
|
||||
this.blockTracker.on('block', this.pendingTxTracker.checkForTxInBlock.bind(this.pendingTxTracker))
|
||||
// this is a little messy but until ethstore has been either
|
||||
// removed or redone this is to guard against the race condition
|
||||
this.blockTracker.on('latest', this.pendingTxTracker.resubmitPendingTxs.bind(this.pendingTxTracker))
|
||||
this.blockTracker.on('sync', this.pendingTxTracker.queryPendingTxs.bind(this.pendingTxTracker))
|
||||
// memstore is computed from a few different stores
|
||||
this._updateMemstore()
|
||||
this.txStateManager.store.subscribe(() => this._updateMemstore())
|
||||
this.networkStore.subscribe(() => this._updateMemstore())
|
||||
this.preferencesStore.subscribe(() => this._updateMemstore())
|
||||
}
|
||||
|
||||
getState () {
|
||||
return this.memStore.getState()
|
||||
}
|
||||
|
||||
getNetwork () {
|
||||
return this.networkStore.getState()
|
||||
}
|
||||
|
||||
getSelectedAddress () {
|
||||
return this.preferencesStore.getState().selectedAddress
|
||||
}
|
||||
|
||||
getUnapprovedTxCount () {
|
||||
return Object.keys(this.txStateManager.getUnapprovedTxList()).length
|
||||
}
|
||||
|
||||
getPendingTxCount (account) {
|
||||
return this.txStateManager.getPendingTransactions(account).length
|
||||
}
|
||||
|
||||
getFilteredTxList (opts) {
|
||||
return this.txStateManager.getFilteredTxList(opts)
|
||||
}
|
||||
|
||||
getChainId () {
|
||||
const networkState = this.networkStore.getState()
|
||||
const getChainId = parseInt(networkState)
|
||||
if (Number.isNaN(getChainId)) {
|
||||
return 0
|
||||
} else {
|
||||
return getChainId
|
||||
}
|
||||
}
|
||||
|
||||
wipeTransactions (address) {
|
||||
this.txStateManager.wipeTransactions(address)
|
||||
}
|
||||
|
||||
// Adds a tx to the txlist
|
||||
addTx (txMeta) {
|
||||
this.txStateManager.addTx(txMeta)
|
||||
this.emit(`${txMeta.id}:unapproved`, txMeta)
|
||||
}
|
||||
|
||||
async newUnapprovedTransaction (txParams, opts = {}) {
|
||||
log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`)
|
||||
const initialTxMeta = await this.addUnapprovedTransaction(txParams)
|
||||
initialTxMeta.origin = opts.origin
|
||||
this.txStateManager.updateTx(initialTxMeta, '#newUnapprovedTransaction - adding the origin')
|
||||
// listen for tx completion (success, fail)
|
||||
return new Promise((resolve, reject) => {
|
||||
this.txStateManager.once(`${initialTxMeta.id}:finished`, (finishedTxMeta) => {
|
||||
switch (finishedTxMeta.status) {
|
||||
case 'submitted':
|
||||
return resolve(finishedTxMeta.hash)
|
||||
case 'rejected':
|
||||
return reject(new Error('MetaMask Tx Signature: User denied transaction signature.'))
|
||||
case 'failed':
|
||||
return reject(new Error(finishedTxMeta.err.message))
|
||||
default:
|
||||
return reject(new Error(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finishedTxMeta.txParams)}`))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async addUnapprovedTransaction (txParams) {
|
||||
// validate
|
||||
const normalizedTxParams = this._normalizeTxParams(txParams)
|
||||
this._validateTxParams(normalizedTxParams)
|
||||
// construct txMeta
|
||||
let txMeta = this.txStateManager.generateTxMeta({ txParams: normalizedTxParams })
|
||||
this.addTx(txMeta)
|
||||
this.emit('newUnapprovedTx', txMeta)
|
||||
// add default tx params
|
||||
try {
|
||||
txMeta = await this.addTxDefaults(txMeta)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
this.txStateManager.setTxStatusFailed(txMeta.id, error)
|
||||
throw error
|
||||
}
|
||||
txMeta.loadingDefaults = false
|
||||
// save txMeta
|
||||
this.txStateManager.updateTx(txMeta)
|
||||
|
||||
return txMeta
|
||||
}
|
||||
|
||||
async addTxDefaults (txMeta) {
|
||||
const txParams = txMeta.txParams
|
||||
// ensure value
|
||||
txMeta.gasPriceSpecified = Boolean(txParams.gasPrice)
|
||||
let gasPrice = txParams.gasPrice
|
||||
if (!gasPrice) {
|
||||
gasPrice = this.getGasPrice ? this.getGasPrice() : await this.query.gasPrice()
|
||||
}
|
||||
txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16))
|
||||
txParams.value = txParams.value || '0x0'
|
||||
// set gasLimit
|
||||
return await this.txGasUtil.analyzeGasUsage(txMeta)
|
||||
}
|
||||
|
||||
async retryTransaction (originalTxId) {
|
||||
const originalTxMeta = this.txStateManager.getTx(originalTxId)
|
||||
const lastGasPrice = originalTxMeta.txParams.gasPrice
|
||||
const txMeta = this.txStateManager.generateTxMeta({
|
||||
txParams: originalTxMeta.txParams,
|
||||
lastGasPrice,
|
||||
loadingDefaults: false,
|
||||
})
|
||||
this.addTx(txMeta)
|
||||
this.emit('newUnapprovedTx', txMeta)
|
||||
return txMeta
|
||||
}
|
||||
|
||||
async updateTransaction (txMeta) {
|
||||
this.txStateManager.updateTx(txMeta, 'confTx: user updated transaction')
|
||||
}
|
||||
|
||||
async updateAndApproveTransaction (txMeta) {
|
||||
this.txStateManager.updateTx(txMeta, 'confTx: user approved transaction')
|
||||
await this.approveTransaction(txMeta.id)
|
||||
}
|
||||
|
||||
async approveTransaction (txId) {
|
||||
let nonceLock
|
||||
try {
|
||||
// approve
|
||||
this.txStateManager.setTxStatusApproved(txId)
|
||||
// get next nonce
|
||||
const txMeta = this.txStateManager.getTx(txId)
|
||||
const fromAddress = txMeta.txParams.from
|
||||
// wait for a nonce
|
||||
nonceLock = await this.nonceTracker.getNonceLock(fromAddress)
|
||||
// add nonce to txParams
|
||||
// if txMeta has lastGasPrice then it is a retry at same nonce with higher
|
||||
// gas price transaction and their for the nonce should not be calculated
|
||||
const nonce = txMeta.lastGasPrice ? txMeta.txParams.nonce : nonceLock.nextNonce
|
||||
txMeta.txParams.nonce = ethUtil.addHexPrefix(nonce.toString(16))
|
||||
// add nonce debugging information to txMeta
|
||||
txMeta.nonceDetails = nonceLock.nonceDetails
|
||||
this.txStateManager.updateTx(txMeta, 'transactions#approveTransaction')
|
||||
// sign transaction
|
||||
const rawTx = await this.signTransaction(txId)
|
||||
await this.publishTransaction(txId, rawTx)
|
||||
// must set transaction to submitted/failed before releasing lock
|
||||
nonceLock.releaseLock()
|
||||
} catch (err) {
|
||||
this.txStateManager.setTxStatusFailed(txId, err)
|
||||
// must set transaction to submitted/failed before releasing lock
|
||||
if (nonceLock) nonceLock.releaseLock()
|
||||
// continue with error chain
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async signTransaction (txId) {
|
||||
const txMeta = this.txStateManager.getTx(txId)
|
||||
// add network/chain id
|
||||
const chainId = this.getChainId()
|
||||
const txParams = Object.assign({}, txMeta.txParams, { chainId })
|
||||
// sign tx
|
||||
const fromAddress = txParams.from
|
||||
const ethTx = new Transaction(txParams)
|
||||
await this.signEthTx(ethTx, fromAddress)
|
||||
// set state to signed
|
||||
this.txStateManager.setTxStatusSigned(txMeta.id)
|
||||
const rawTx = ethUtil.bufferToHex(ethTx.serialize())
|
||||
return rawTx
|
||||
}
|
||||
|
||||
async publishTransaction (txId, rawTx) {
|
||||
const txMeta = this.txStateManager.getTx(txId)
|
||||
txMeta.rawTx = rawTx
|
||||
this.txStateManager.updateTx(txMeta, 'transactions#publishTransaction')
|
||||
const txHash = await this.query.sendRawTransaction(rawTx)
|
||||
this.setTxHash(txId, txHash)
|
||||
this.txStateManager.setTxStatusSubmitted(txId)
|
||||
}
|
||||
|
||||
async cancelTransaction (txId) {
|
||||
this.txStateManager.setTxStatusRejected(txId)
|
||||
}
|
||||
|
||||
// receives a txHash records the tx as signed
|
||||
setTxHash (txId, txHash) {
|
||||
// Add the tx hash to the persisted meta-tx object
|
||||
const txMeta = this.txStateManager.getTx(txId)
|
||||
txMeta.hash = txHash
|
||||
this.txStateManager.updateTx(txMeta, 'transactions#setTxHash')
|
||||
}
|
||||
|
||||
//
|
||||
// PRIVATE METHODS
|
||||
//
|
||||
|
||||
_normalizeTxParams (txParams) {
|
||||
// functions that handle normalizing of that key in txParams
|
||||
const whiteList = {
|
||||
from: from => ethUtil.addHexPrefix(from).toLowerCase(),
|
||||
to: to => ethUtil.addHexPrefix(txParams.to).toLowerCase(),
|
||||
nonce: nonce => ethUtil.addHexPrefix(nonce),
|
||||
value: value => ethUtil.addHexPrefix(value),
|
||||
data: data => ethUtil.addHexPrefix(data),
|
||||
gas: gas => ethUtil.addHexPrefix(gas),
|
||||
gasPrice: gasPrice => ethUtil.addHexPrefix(gasPrice),
|
||||
}
|
||||
|
||||
// apply only keys in the whiteList
|
||||
const normalizedTxParams = {}
|
||||
Object.keys(whiteList).forEach((key) => {
|
||||
if (txParams[key]) normalizedTxParams[key] = whiteList[key](txParams[key])
|
||||
})
|
||||
|
||||
return normalizedTxParams
|
||||
}
|
||||
|
||||
_validateTxParams (txParams) {
|
||||
this._validateFrom(txParams)
|
||||
this._validateRecipient(txParams)
|
||||
if ('value' in txParams) {
|
||||
const value = txParams.value.toString()
|
||||
if (value.includes('-')) {
|
||||
throw new Error(`Invalid transaction value of ${txParams.value} not a positive number.`)
|
||||
}
|
||||
|
||||
if (value.includes('.')) {
|
||||
throw new Error(`Invalid transaction value of ${txParams.value} number must be in wei`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_validateFrom (txParams) {
|
||||
if ( !(typeof txParams.from === 'string') ) throw new Error(`Invalid from address ${txParams.from} not a string`)
|
||||
if (!ethUtil.isValidAddress(txParams.from)) throw new Error('Invalid from address')
|
||||
}
|
||||
|
||||
_validateRecipient (txParams) {
|
||||
if (txParams.to === '0x' || txParams.to === null ) {
|
||||
if (txParams.data) {
|
||||
delete txParams.to
|
||||
} else {
|
||||
throw new Error('Invalid recipient address')
|
||||
}
|
||||
} else if ( txParams.to !== undefined && !ethUtil.isValidAddress(txParams.to) ) {
|
||||
throw new Error('Invalid recipient address')
|
||||
}
|
||||
return txParams
|
||||
}
|
||||
|
||||
_markNonceDuplicatesDropped (txId) {
|
||||
this.txStateManager.setTxStatusConfirmed(txId)
|
||||
// get the confirmed transactions nonce and from address
|
||||
const txMeta = this.txStateManager.getTx(txId)
|
||||
const { nonce, from } = txMeta.txParams
|
||||
const sameNonceTxs = this.txStateManager.getFilteredTxList({nonce, from})
|
||||
if (!sameNonceTxs.length) return
|
||||
// mark all same nonce transactions as dropped and give i a replacedBy hash
|
||||
sameNonceTxs.forEach((otherTxMeta) => {
|
||||
if (otherTxMeta.id === txId) return
|
||||
otherTxMeta.replacedBy = txMeta.hash
|
||||
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:confirmed reference to confirmed txHash with same nonce')
|
||||
this.txStateManager.setTxStatusDropped(otherTxMeta.id)
|
||||
})
|
||||
}
|
||||
|
||||
_updateMemstore () {
|
||||
const unapprovedTxs = this.txStateManager.getUnapprovedTxList()
|
||||
const selectedAddressTxList = this.txStateManager.getFilteredTxList({
|
||||
from: this.getSelectedAddress(),
|
||||
metamaskNetworkId: this.getNetwork(),
|
||||
})
|
||||
this.memStore.updateState({ unapprovedTxs, selectedAddressTxList })
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Apr 12 2018 14:37:39 GMT-0700 (PDT) using the radgrad jsdoc theme. Derived from docdash.
|
||||
</footer>
|
||||
|
||||
<script>prettyPrint();</script>
|
||||
<script src="scripts/linenumber.js"></script>
|
||||
<script>$('.ui.accordion').accordion();</script>
|
||||
</body>
|
||||
</html>
|
486
docs/jsdocs/global.html
Normal file
486
docs/jsdocs/global.html
Normal file
@ -0,0 +1,486 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="google" content="notranslate">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<title>Global - Documentation</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"></script>
|
||||
<script src="scripts/prettify/lang-css.js"></script>
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.1.1.min.js"
|
||||
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="scripts/semantic.min.js"></script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/semantic.min.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/override.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
||||
<label for="nav-trigger" class="navicon-button x">
|
||||
<div class="navicon"></div>
|
||||
</label>
|
||||
|
||||
<label for="nav-trigger" class="overlay"></label>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><div class="ui vertical accordion"><div class="title"><div class="ui list"><div class="item"><i class="inverted dropdown icon"></i><a href="module.exports_module.exports.html">exports</a></div></div></div></li></div></ul><h3><a href="global.html">Global</a></h3>
|
||||
</nav>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Global</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2>
|
||||
|
||||
</h2>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Type Definitions</h3>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="MetaMaskOptions">MetaMaskOptions</h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="metamask-controller.js.html">metamask-controller.js</a>, <a href="metamask-controller.js.html#line48">line 48</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
<h5 class="subsection-title">Properties:</h5>
|
||||
|
||||
|
||||
|
||||
<table class="props">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>platform</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="global.html#Platform">Platform</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"><p>An object including platform-specific functions.</p></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Type:</h5>
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
<span class="param-type">object</span>
|
||||
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="Platform">Platform</h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="platforms_extension.js.html">platforms/extension.js</a>, <a href="platforms_extension.js.html#line3">line 3</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
<h5 class="subsection-title">Properties:</h5>
|
||||
|
||||
|
||||
|
||||
<table class="props">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>reload</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">function</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"><p>A function to reload the application.</p></td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>openWindow</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">function</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"><p>Opens a URL in the web browser.</p></td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>getVersion</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">function</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"><p>Gets the current version of MetaMask.</p></td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>openExtensionInBrowser</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">function</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"><p>Opens the MetaMask UI in a full window.</p></td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>getPlatformInfo</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">function</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"><p>Callback function that returns info about the current platform.</p></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
<p>An object that provides a variety of platform-specific functions.</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<h5>Type:</h5>
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
<span class="param-type">object</span>
|
||||
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Apr 12 2018 14:37:39 GMT-0700 (PDT) using the radgrad jsdoc theme. Derived from docdash.
|
||||
</footer>
|
||||
|
||||
<script>prettyPrint();</script>
|
||||
<script src="scripts/linenumber.js"></script>
|
||||
<script>$('.ui.accordion').accordion();</script>
|
||||
</body>
|
||||
</html>
|
275
docs/jsdocs/index.html
Normal file
275
docs/jsdocs/index.html
Normal file
@ -0,0 +1,275 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="google" content="notranslate">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<title>Home - Documentation</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"></script>
|
||||
<script src="scripts/prettify/lang-css.js"></script>
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.1.1.min.js"
|
||||
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="scripts/semantic.min.js"></script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/semantic.min.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/override.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
||||
<label for="nav-trigger" class="navicon-button x">
|
||||
<div class="navicon"></div>
|
||||
</label>
|
||||
|
||||
<label for="nav-trigger" class="overlay"></label>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><div class="ui vertical accordion"><div class="title"><div class="ui list"><div class="item"><i class="inverted dropdown icon"></i><a href="module.exports_module.exports.html">exports</a></div></div></div></li></div></ul><h3><a href="global.html">Global</a></h3>
|
||||
</nav>
|
||||
|
||||
<div id="main">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2>
|
||||
controllers/transactions.js
|
||||
</h2>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="controllers_transactions.js.html">controllers/transactions.js</a>, <a href="controllers_transactions.js.html#line4">line 4</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-copyright">Copyright:</dt>
|
||||
<dd class="tag-copyright"><ul class="dummy"><li>Copyright (c) 2018 MetaMask</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
<dt class="tag-license">License:</dt>
|
||||
<dd class="tag-license"><ul class="dummy"><li>MIT</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description"><p>The transaction controller. Receives incoming transactions, and emits events for various states of their processing.</p></div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2>
|
||||
metamask-controller.js
|
||||
</h2>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="metamask-controller.js.html">metamask-controller.js</a>, <a href="metamask-controller.js.html#line1">line 1</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-copyright">Copyright:</dt>
|
||||
<dd class="tag-copyright"><ul class="dummy"><li>Copyright (c) 2018 MetaMask</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
<dt class="tag-license">License:</dt>
|
||||
<dd class="tag-license"><ul class="dummy"><li>MIT</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description"><p>The central metamask controller. Aggregates other controllers and exports an api.</p></div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Apr 12 2018 14:37:39 GMT-0700 (PDT) using the radgrad jsdoc theme. Derived from docdash.
|
||||
</footer>
|
||||
|
||||
<script>prettyPrint();</script>
|
||||
<script src="scripts/linenumber.js"></script>
|
||||
<script>$('.ui.accordion').accordion();</script>
|
||||
</body>
|
||||
</html>
|
1144
docs/jsdocs/metamask-controller.js.html
Normal file
1144
docs/jsdocs/metamask-controller.js.html
Normal file
File diff suppressed because it is too large
Load Diff
229
docs/jsdocs/module.exports_module.exports.html
Normal file
229
docs/jsdocs/module.exports_module.exports.html
Normal file
@ -0,0 +1,229 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="google" content="notranslate">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<title>exports - Documentation</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"></script>
|
||||
<script src="scripts/prettify/lang-css.js"></script>
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.1.1.min.js"
|
||||
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="scripts/semantic.min.js"></script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/semantic.min.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/override.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
||||
<label for="nav-trigger" class="navicon-button x">
|
||||
<div class="navicon"></div>
|
||||
</label>
|
||||
|
||||
<label for="nav-trigger" class="overlay"></label>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><div class="ui vertical accordion"><div class="title"><div class="ui list"><div class="item"><i class="inverted dropdown icon"></i><a href="module.exports_module.exports.html">exports</a></div></div></div></li></div></ul><h3><a href="global.html">Global</a></h3>
|
||||
</nav>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">exports</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2>
|
||||
exports
|
||||
</h2>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="exports"><span class="type-signature"></span>new exports<span class="signature">(opts)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="metamask-controller.js.html">metamask-controller.js</a>, <a href="metamask-controller.js.html#line59">line 59</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>opts</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Object</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Apr 12 2018 14:37:39 GMT-0700 (PDT) using the radgrad jsdoc theme. Derived from docdash.
|
||||
</footer>
|
||||
|
||||
<script>prettyPrint();</script>
|
||||
<script src="scripts/linenumber.js"></script>
|
||||
<script>$('.ui.accordion').accordion();</script>
|
||||
</body>
|
||||
</html>
|
117
docs/jsdocs/platforms_extension.js.html
Normal file
117
docs/jsdocs/platforms_extension.js.html
Normal file
@ -0,0 +1,117 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="google" content="notranslate">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<title>platforms/extension.js - Documentation</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"></script>
|
||||
<script src="scripts/prettify/lang-css.js"></script>
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.1.1.min.js"
|
||||
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="scripts/semantic.min.js"></script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/semantic.min.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/override.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
||||
<label for="nav-trigger" class="navicon-button x">
|
||||
<div class="navicon"></div>
|
||||
</label>
|
||||
|
||||
<label for="nav-trigger" class="overlay"></label>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><div class="ui vertical accordion"><div class="title"><div class="ui list"><div class="item"><i class="inverted dropdown icon"></i><a href="module.exports_module.exports.html">exports</a></div></div></div></li></div></ul><h3><a href="global.html">Global</a></h3>
|
||||
</nav>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">platforms/extension.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>const extension = require('extensionizer')
|
||||
|
||||
/**
|
||||
* An object that provides a variety of platform-specific functions.
|
||||
*
|
||||
* @typedef {object} Platform
|
||||
*
|
||||
* @property {Function} reload - A function to reload the application.
|
||||
* @property {Function} openWindow - Opens a URL in the web browser.
|
||||
* @property {Function} getVersion - Gets the current version of MetaMask.
|
||||
* @property {Function} openExtensionInBrowser - Opens the MetaMask UI in a full window.
|
||||
* @property {Function} getPlatformInfo - Callback function that returns info about the current platform.
|
||||
*/
|
||||
|
||||
class ExtensionPlatform {
|
||||
|
||||
//
|
||||
// Public
|
||||
//
|
||||
reload () {
|
||||
extension.runtime.reload()
|
||||
}
|
||||
|
||||
openWindow ({ url }) {
|
||||
extension.tabs.create({ url })
|
||||
}
|
||||
|
||||
getVersion () {
|
||||
return extension.runtime.getManifest().version
|
||||
}
|
||||
|
||||
openExtensionInBrowser () {
|
||||
const extensionURL = extension.runtime.getURL('home.html')
|
||||
this.openWindow({ url: extensionURL })
|
||||
}
|
||||
|
||||
getPlatformInfo (cb) {
|
||||
try {
|
||||
extension.runtime.getPlatformInfo((platform) => {
|
||||
cb(null, platform)
|
||||
})
|
||||
} catch (e) {
|
||||
cb(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ExtensionPlatform
|
||||
</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Apr 12 2018 14:37:39 GMT-0700 (PDT) using the radgrad jsdoc theme. Derived from docdash.
|
||||
</footer>
|
||||
|
||||
<script>prettyPrint();</script>
|
||||
<script src="scripts/linenumber.js"></script>
|
||||
<script>$('.ui.accordion').accordion();</script>
|
||||
</body>
|
||||
</html>
|
25
docs/jsdocs/scripts/linenumber.js
Normal file
25
docs/jsdocs/scripts/linenumber.js
Normal file
@ -0,0 +1,25 @@
|
||||
/*global document */
|
||||
(function() {
|
||||
var source = document.getElementsByClassName('prettyprint source linenums');
|
||||
var i = 0;
|
||||
var lineNumber = 0;
|
||||
var lineId;
|
||||
var lines;
|
||||
var totalLines;
|
||||
var anchorHash;
|
||||
|
||||
if (source && source[0]) {
|
||||
anchorHash = document.location.hash.substring(1);
|
||||
lines = source[0].getElementsByTagName('li');
|
||||
totalLines = lines.length;
|
||||
|
||||
for (; i < totalLines; i++) {
|
||||
lineNumber++;
|
||||
lineId = 'line' + lineNumber;
|
||||
lines[i].id = lineId;
|
||||
if (lineId === anchorHash) {
|
||||
lines[i].className += ' selected';
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
202
docs/jsdocs/scripts/prettify/Apache-License-2.0.txt
Normal file
202
docs/jsdocs/scripts/prettify/Apache-License-2.0.txt
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
2
docs/jsdocs/scripts/prettify/lang-css.js
Normal file
2
docs/jsdocs/scripts/prettify/lang-css.js
Normal file
@ -0,0 +1,2 @@
|
||||
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com",
|
||||
/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);
|
28
docs/jsdocs/scripts/prettify/prettify.js
Normal file
28
docs/jsdocs/scripts/prettify/prettify.js
Normal file
@ -0,0 +1,28 @@
|
||||
var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
|
||||
(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
|
||||
[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
|
||||
f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
|
||||
(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
|
||||
{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
|
||||
t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
|
||||
"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
|
||||
l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
|
||||
q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
|
||||
q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
|
||||
"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
|
||||
a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
|
||||
for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
|
||||
m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
|
||||
a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
|
||||
j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
|
||||
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
|
||||
H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
|
||||
J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
|
||||
I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
|
||||
["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
|
||||
/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
|
||||
["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
|
||||
hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
|
||||
!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
|
||||
250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
|
||||
PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();
|
19
docs/jsdocs/scripts/semantic.min.js
vendored
Normal file
19
docs/jsdocs/scripts/semantic.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
626
docs/jsdocs/styles/jsdoc.css
Normal file
626
docs/jsdocs/styles/jsdoc.css
Normal file
@ -0,0 +1,626 @@
|
||||
@import url(https://fonts.googleapis.com/css?family=Montserrat:400,700);
|
||||
|
||||
* {
|
||||
box-sizing: border-box
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #4d4e53;
|
||||
background-color: white;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
font-family: 'Helvetica Neue', Helvetica, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 160%;
|
||||
}
|
||||
|
||||
a,
|
||||
a:active {
|
||||
color: #606;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
article a {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
article a:hover, article a:active {
|
||||
border-bottom-color: #222;
|
||||
}
|
||||
|
||||
p, ul, ol, blockquote {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #000;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 300;
|
||||
font-size: 48px;
|
||||
margin: 1em 0 .5em;
|
||||
}
|
||||
|
||||
h1.page-title {
|
||||
font-size: 48px;
|
||||
margin: 1em 30px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
margin: 1.5em 0 .3em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
margin: 1.2em 0 .3em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 18px;
|
||||
margin: 1em 0 .2em;
|
||||
color: #4d4e53;
|
||||
}
|
||||
|
||||
h4.name {
|
||||
color: #fff;
|
||||
background: #6d426d;
|
||||
box-shadow: 0 .25em .5em #d3d3d3;
|
||||
border-top: 1px solid #d3d3d3;
|
||||
border-bottom: 1px solid #d3d3d3;
|
||||
margin: 1.5em 0 0.5em;
|
||||
padding: .75em 0 .75em 10px;
|
||||
}
|
||||
|
||||
h5, .container-overview .subsection-title {
|
||||
font-size: 120%;
|
||||
letter-spacing: -0.01em;
|
||||
margin: 8px 0 3px 0;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 100%;
|
||||
letter-spacing: -0.01em;
|
||||
margin: 6px 0 3px 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
tt, code, kbd, samp {
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
||||
background: #f4f4f4;
|
||||
padding: 1px 5px;
|
||||
}
|
||||
|
||||
.class-description {
|
||||
font-size: 130%;
|
||||
line-height: 140%;
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.class-description:empty {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
#main {
|
||||
float: right;
|
||||
min-width: 360px;
|
||||
width: calc(100% - 240px);
|
||||
}
|
||||
|
||||
header {
|
||||
display: block
|
||||
}
|
||||
|
||||
section {
|
||||
display: block;
|
||||
background-color: #fff;
|
||||
padding: 5px 20px;
|
||||
}
|
||||
|
||||
.variation {
|
||||
display: none
|
||||
}
|
||||
|
||||
.signature-attributes {
|
||||
font-size: 60%;
|
||||
color: #eee;
|
||||
font-style: italic;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
nav {
|
||||
float: left;
|
||||
display: block;
|
||||
width: 250px;
|
||||
background: #fff;
|
||||
overflow: auto;
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
padding: 5px 20px;
|
||||
}
|
||||
|
||||
nav h3 {
|
||||
margin-top: 12px;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
font-weight: 700;
|
||||
line-height: 24px;
|
||||
margin: 15px 0 10px;
|
||||
padding: 0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
/* font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; */
|
||||
font-size: 100%;
|
||||
line-height: 17px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
nav ul a,
|
||||
nav ul a:active {
|
||||
/* font-family: 'Montserrat', sans-serif; */
|
||||
line-height: 18px;
|
||||
padding: 0;
|
||||
/* display: block; */
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
nav a:hover,
|
||||
nav a:active {
|
||||
color: #606;
|
||||
}
|
||||
|
||||
nav > ul {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
nav > ul > li > a {
|
||||
color: #606;
|
||||
}
|
||||
|
||||
nav ul ul {
|
||||
margin-bottom: 10px
|
||||
}
|
||||
|
||||
nav ul ul a {
|
||||
color: hsl(207, 1%, 60%);
|
||||
border-left: 1px solid hsl(207, 10%, 86%);
|
||||
}
|
||||
|
||||
nav ul ul a,
|
||||
nav ul ul a:active {
|
||||
padding-left: 20px
|
||||
}
|
||||
|
||||
nav h2 {
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
nav > h2 > a {
|
||||
display: block;
|
||||
margin: 10px 0 -10px;
|
||||
color: #606 !important;
|
||||
}
|
||||
|
||||
footer {
|
||||
color: hsl(0, 0%, 28%);
|
||||
margin-left: 250px;
|
||||
display: block;
|
||||
padding: 15px;
|
||||
font-style: italic;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
.ancestors {
|
||||
color: #999
|
||||
}
|
||||
|
||||
.ancestors a {
|
||||
color: #999 !important;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both
|
||||
}
|
||||
|
||||
.important {
|
||||
font-weight: bold;
|
||||
color: #950B02;
|
||||
}
|
||||
|
||||
.yes-def {
|
||||
text-indent: -1000px
|
||||
}
|
||||
|
||||
.type-signature {
|
||||
color: #CA79CA
|
||||
}
|
||||
|
||||
.type-signature:last-child {
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.name, .signature {
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace
|
||||
}
|
||||
|
||||
.signature {
|
||||
color: #fc83ff;
|
||||
}
|
||||
|
||||
.details {
|
||||
margin-top: 6px;
|
||||
border-left: 2px solid #DDD;
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.details dt {
|
||||
width: 120px;
|
||||
float: left;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.details dd {
|
||||
margin-left: 70px;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.details ul {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
.details ul {
|
||||
list-style-type: none
|
||||
}
|
||||
|
||||
.details pre.prettyprint {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
.details .object-value {
|
||||
padding-top: 0
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.code-caption {
|
||||
font-style: italic;
|
||||
font-size: 107%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.prettyprint {
|
||||
font-size: 14px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.prettyprint.source {
|
||||
width: inherit;
|
||||
line-height: 18px;
|
||||
display: block;
|
||||
background-color: #0d152a;
|
||||
color: #aeaeae;
|
||||
}
|
||||
|
||||
.prettyprint code {
|
||||
line-height: 18px;
|
||||
display: block;
|
||||
background-color: #0d152a;
|
||||
color: #4D4E53;
|
||||
}
|
||||
|
||||
.prettyprint > code {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.prettyprint .linenums code {
|
||||
padding: 0 15px
|
||||
}
|
||||
|
||||
.prettyprint .linenums li:first-of-type code {
|
||||
padding-top: 15px
|
||||
}
|
||||
|
||||
.prettyprint code span.line {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
.prettyprint.linenums {
|
||||
padding-left: 70px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.prettyprint.linenums ol {
|
||||
padding-left: 0
|
||||
}
|
||||
|
||||
.prettyprint.linenums li {
|
||||
border-left: 3px #34446B solid;
|
||||
}
|
||||
|
||||
.prettyprint.linenums li.selected, .prettyprint.linenums li.selected * {
|
||||
background-color: #34446B;
|
||||
}
|
||||
|
||||
.prettyprint.linenums li * {
|
||||
-webkit-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.params, .props {
|
||||
border-spacing: 0;
|
||||
border: 1px solid #ddd;
|
||||
border-collapse: collapse;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.params .type {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.params code {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.params td, .params .name, .props .name, .name code {
|
||||
color: #4D4E53;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.params td, .params th, .props td, .props th {
|
||||
margin: 0px;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
padding: 10px;
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.params td {
|
||||
border-top: 1px solid #eee
|
||||
}
|
||||
|
||||
.params thead tr, .props thead tr {
|
||||
background-color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.params .params thead tr, .props .props thead tr {
|
||||
background-color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.params td.description > p:first-child, .props td.description > p:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.params td.description > p:last-child, .props td.description > p:last-child {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
span.param-type, .params td .param-type, .param-type dd {
|
||||
color: #606;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace
|
||||
}
|
||||
|
||||
.param-type dt, .param-type dd {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
.param-type {
|
||||
margin: 14px 0;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: #454545
|
||||
}
|
||||
|
||||
/* navicon button */
|
||||
.navicon-button {
|
||||
display: none;
|
||||
position: relative;
|
||||
padding: 2.0625rem 1.5rem;
|
||||
transition: 0.25s;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
opacity: .8;
|
||||
}
|
||||
.navicon-button .navicon:before, .navicon-button .navicon:after {
|
||||
transition: 0.25s;
|
||||
}
|
||||
.navicon-button:hover {
|
||||
transition: 0.5s;
|
||||
opacity: 1;
|
||||
}
|
||||
.navicon-button:hover .navicon:before, .navicon-button:hover .navicon:after {
|
||||
transition: 0.25s;
|
||||
}
|
||||
.navicon-button:hover .navicon:before {
|
||||
top: .825rem;
|
||||
}
|
||||
.navicon-button:hover .navicon:after {
|
||||
top: -.825rem;
|
||||
}
|
||||
|
||||
/* navicon */
|
||||
.navicon {
|
||||
position: relative;
|
||||
width: 2.5em;
|
||||
height: .3125rem;
|
||||
background: #000;
|
||||
transition: 0.3s;
|
||||
border-radius: 2.5rem;
|
||||
}
|
||||
.navicon:before, .navicon:after {
|
||||
display: block;
|
||||
content: "";
|
||||
height: .3125rem;
|
||||
width: 2.5rem;
|
||||
background: #000;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
transition: 0.3s 0.25s;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
.navicon:before {
|
||||
top: .625rem;
|
||||
}
|
||||
.navicon:after {
|
||||
top: -.625rem;
|
||||
}
|
||||
|
||||
/* open */
|
||||
.nav-trigger:checked + label:not(.steps) .navicon:before,
|
||||
.nav-trigger:checked + label:not(.steps) .navicon:after {
|
||||
top: 0 !important;
|
||||
}
|
||||
|
||||
.nav-trigger:checked + label .navicon:before,
|
||||
.nav-trigger:checked + label .navicon:after {
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
/* Minus */
|
||||
.nav-trigger:checked + label {
|
||||
-webkit-transform: scale(0.75);
|
||||
transform: scale(0.75);
|
||||
}
|
||||
|
||||
/* × and + */
|
||||
.nav-trigger:checked + label.plus .navicon,
|
||||
.nav-trigger:checked + label.x .navicon {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.nav-trigger:checked + label.plus .navicon:before,
|
||||
.nav-trigger:checked + label.x .navicon:before {
|
||||
-webkit-transform: rotate(-45deg);
|
||||
transform: rotate(-45deg);
|
||||
background: #FFF;
|
||||
}
|
||||
|
||||
.nav-trigger:checked + label.plus .navicon:after,
|
||||
.nav-trigger:checked + label.x .navicon:after {
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
background: #FFF;
|
||||
}
|
||||
|
||||
.nav-trigger:checked + label.plus {
|
||||
-webkit-transform: scale(0.75) rotate(45deg);
|
||||
transform: scale(0.75) rotate(45deg);
|
||||
}
|
||||
|
||||
.nav-trigger:checked ~ nav {
|
||||
left: 0 !important;
|
||||
}
|
||||
|
||||
.nav-trigger:checked ~ .overlay {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav-trigger {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: hsla(0, 0%, 0%, 0.5);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 320px) and (max-width: 680px) {
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
nav {
|
||||
background: #FFF;
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: -250px;
|
||||
z-index: 3;
|
||||
padding: 0 10px;
|
||||
transition: left 0.2s;
|
||||
}
|
||||
|
||||
.navicon-button {
|
||||
display: inline-block;
|
||||
position: fixed;
|
||||
top: 1.5em;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#main {
|
||||
width: 100%;
|
||||
min-width: 360px;
|
||||
}
|
||||
|
||||
#main h1.page-title {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
#main section {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
3
docs/jsdocs/styles/override.css
Normal file
3
docs/jsdocs/styles/override.css
Normal file
@ -0,0 +1,3 @@
|
||||
.ui.accordion .title:not(.ui) {
|
||||
padding: 0px;
|
||||
}
|
79
docs/jsdocs/styles/prettify.css
Normal file
79
docs/jsdocs/styles/prettify.css
Normal file
@ -0,0 +1,79 @@
|
||||
.pln {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
/* string content */
|
||||
.str {
|
||||
color: #61ce3c;
|
||||
}
|
||||
|
||||
/* a keyword */
|
||||
.kwd {
|
||||
color: #fbde2d;
|
||||
}
|
||||
|
||||
/* a comment */
|
||||
.com {
|
||||
color: #aeaeae;
|
||||
}
|
||||
|
||||
/* a type name */
|
||||
.typ {
|
||||
color: #8da6ce;
|
||||
}
|
||||
|
||||
/* a literal value */
|
||||
.lit {
|
||||
color: #fbde2d;
|
||||
}
|
||||
|
||||
/* punctuation */
|
||||
.pun {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
/* lisp open bracket */
|
||||
.opn {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
/* lisp close bracket */
|
||||
.clo {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
/* a markup tag name */
|
||||
.tag {
|
||||
color: #8da6ce;
|
||||
}
|
||||
|
||||
/* a markup attribute name */
|
||||
.atn {
|
||||
color: #fbde2d;
|
||||
}
|
||||
|
||||
/* a markup attribute value */
|
||||
.atv {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
/* a declaration */
|
||||
.dec {
|
||||
color: #EF5050;
|
||||
}
|
||||
|
||||
/* a variable name */
|
||||
.var {
|
||||
color: #c82829;
|
||||
}
|
||||
|
||||
/* a function name */
|
||||
.fun {
|
||||
color: #4271ae;
|
||||
}
|
||||
|
||||
/* Specify class=linenums on a pre to get line numbering */
|
||||
ol.linenums {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
364
docs/jsdocs/styles/semantic.min.css
vendored
Normal file
364
docs/jsdocs/styles/semantic.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
78
docs/team.md
Normal file
78
docs/team.md
Normal file
@ -0,0 +1,78 @@
|
||||
# The Team
|
||||
|
||||
Here is an overview of the current MetaMask team, and their primary roles and responsibilities, in the order they joined the team.
|
||||
|
||||
## Core Team Members
|
||||
|
||||
The core team maintains aspects of the main product (the extension) and the core libraries (the MetaMask Controller, provider-engine, etc).
|
||||
|
||||
### Aaron Davis
|
||||
|
||||
@kumavis
|
||||
Founder / Technical Lead
|
||||
|
||||
Especially in charge of connection to the blockchain. Wrote [provider-engine](https://github.com/MetaMask/provider-engine), and is currently working with @hermanjunge on our JavaScript light-client.
|
||||
|
||||
### Dan Finlay
|
||||
|
||||
@danfinlay
|
||||
Software Engineer / Product Lead
|
||||
|
||||
Focused on the deliverable, user-valuable aspects of MetaMask, including usability and documentation. Coordinates efforts between different branches of the team, and integrations with other projects.
|
||||
|
||||
### Frankie Pangilinan
|
||||
|
||||
@frankiebee
|
||||
Software Engineer / Transaction Manager Lead
|
||||
|
||||
Frankie contributes code throughout MetaMask, but has become especially specialized in the way MetaMask manages transactions. She is also the original lead of the [Mascara](https://github.com/MetaMask/mascara) project.
|
||||
|
||||
### Kevin Serrano
|
||||
|
||||
@Zanibas
|
||||
Software Engineer / Project Management Lead
|
||||
|
||||
Kevin is a software engineer, but also spends a lot of his time keeping the team's administrative operations running smoothly.
|
||||
|
||||
### Thomas Huang
|
||||
|
||||
@tmashuang
|
||||
QA Engineer
|
||||
|
||||
Thomas is the head of MetaMask Quality Assurance. He both takes the final pass of branches of code before we ship to production, and is also in charge of continuously improving our automated quality assurance process.
|
||||
|
||||
### Christian Jeria
|
||||
|
||||
@cjeria
|
||||
User Experience Designer
|
||||
|
||||
Christian is the lead of MetaMask's user experience. He is continuously designing prototypes, testing them with users, and refining them with our developers for production.
|
||||
|
||||
### Paul Bouchon
|
||||
|
||||
@bitpshr
|
||||
Software Engineer
|
||||
|
||||
The newest member of the team! Paul is currently being onboarded, and finding his niche within the team.
|
||||
|
||||
## Laboratory Team Members
|
||||
|
||||
These team members are working on projects that will benefit MetaMask, but are not directly working on the product itself.
|
||||
|
||||
### Herman Junge
|
||||
|
||||
@hermanjunge
|
||||
Software Engineer
|
||||
|
||||
Herman is currently leading the Mustekala project, a JavaScript, IPFS-based Ethereum light client.
|
||||
|
||||
## Kyokan Team Members
|
||||
|
||||
[Kyokan](http://kyokan.io/) is a consulting firm that has been working closely with the MetaMask team on the latest version of our user interface. Their team members are not members of ConsenSys LLC, but they contribute a lot to the project.
|
||||
|
||||
- Daniel Tsui (@sdsui)
|
||||
- Chi Kei Chan (@chikeichan)
|
||||
- Dan Miller (@danjm)
|
||||
- David Yoo (@yookd)
|
||||
- Whymarrh Whitby (@whymarrh)
|
||||
|
161
mascara/src/app/first-time/confirm-seed-screen.js
Normal file
161
mascara/src/app/first-time/confirm-seed-screen.js
Normal file
@ -0,0 +1,161 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import classnames from 'classnames'
|
||||
import shuffle from 'lodash.shuffle'
|
||||
import { compose } from 'recompose'
|
||||
import Identicon from '../../../../ui/app/components/identicon'
|
||||
import { confirmSeedWords, showModal } from '../../../../ui/app/actions'
|
||||
import Breadcrumbs from './breadcrumbs'
|
||||
import LoadingScreen from './loading-screen'
|
||||
import { DEFAULT_ROUTE, INITIALIZE_BACKUP_PHRASE_ROUTE } from '../../../../ui/app/routes'
|
||||
|
||||
class ConfirmSeedScreen extends Component {
|
||||
static propTypes = {
|
||||
isLoading: PropTypes.bool,
|
||||
address: PropTypes.string,
|
||||
seedWords: PropTypes.string,
|
||||
confirmSeedWords: PropTypes.func,
|
||||
history: PropTypes.object,
|
||||
openBuyEtherModal: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
seedWords: '',
|
||||
}
|
||||
|
||||
constructor (props) {
|
||||
super(props)
|
||||
const { seedWords } = props
|
||||
this.state = {
|
||||
selectedSeeds: [],
|
||||
shuffledSeeds: seedWords && shuffle(seedWords.split(' ')) || [],
|
||||
}
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
const { seedWords, history } = this.props
|
||||
|
||||
if (!seedWords) {
|
||||
history.push(DEFAULT_ROUTE)
|
||||
}
|
||||
}
|
||||
|
||||
handleClick () {
|
||||
const { confirmSeedWords, history, openBuyEtherModal } = this.props
|
||||
|
||||
confirmSeedWords()
|
||||
.then(() => {
|
||||
history.push(DEFAULT_ROUTE)
|
||||
openBuyEtherModal()
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
const { seedWords, history } = this.props
|
||||
const { selectedSeeds, shuffledSeeds } = this.state
|
||||
const isValid = seedWords === selectedSeeds.map(([_, seed]) => seed).join(' ')
|
||||
|
||||
return (
|
||||
<div className="first-time-flow">
|
||||
{
|
||||
this.props.isLoading
|
||||
? <LoadingScreen loadingMessage="Creating your new account" />
|
||||
: (
|
||||
<div className="first-view-main-wrapper">
|
||||
<div className="first-view-main">
|
||||
<div className="backup-phrase">
|
||||
<a
|
||||
className="backup-phrase__back-button"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
history.push(INITIALIZE_BACKUP_PHRASE_ROUTE)
|
||||
}}
|
||||
href="#"
|
||||
>
|
||||
{`< Back`}
|
||||
</a>
|
||||
<Identicon address={this.props.address} diameter={70} />
|
||||
<div className="backup-phrase__content-wrapper">
|
||||
<div>
|
||||
<div className="backup-phrase__title">
|
||||
Confirm your Secret Backup Phrase
|
||||
</div>
|
||||
<div className="backup-phrase__body-text">
|
||||
Please select each phrase in order to make sure it is correct.
|
||||
</div>
|
||||
<div className="backup-phrase__confirm-secret">
|
||||
{selectedSeeds.map(([_, word], i) => (
|
||||
<button
|
||||
key={i}
|
||||
className="backup-phrase__confirm-seed-option"
|
||||
>
|
||||
{word}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="backup-phrase__confirm-seed-options">
|
||||
{shuffledSeeds.map((word, i) => {
|
||||
const isSelected = selectedSeeds
|
||||
.filter(([index, seed]) => seed === word && index === i)
|
||||
.length
|
||||
|
||||
return (
|
||||
<button
|
||||
key={i}
|
||||
className={classnames('backup-phrase__confirm-seed-option', {
|
||||
'backup-phrase__confirm-seed-option--selected': isSelected,
|
||||
})}
|
||||
onClick={() => {
|
||||
if (!isSelected) {
|
||||
this.setState({
|
||||
selectedSeeds: [...selectedSeeds, [i, word]],
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
selectedSeeds: selectedSeeds
|
||||
.filter(([index, seed]) => !(seed === word && index === i)),
|
||||
})
|
||||
}
|
||||
}}
|
||||
>
|
||||
{word}
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
onClick={() => isValid && this.handleClick()}
|
||||
disabled={!isValid}
|
||||
>
|
||||
Confirm
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<Breadcrumbs total={3} currentIndex={1} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withRouter,
|
||||
connect(
|
||||
({ metamask: { selectedAddress, seedWords }, appState: { isLoading } }) => ({
|
||||
seedWords,
|
||||
isLoading,
|
||||
address: selectedAddress,
|
||||
}),
|
||||
dispatch => ({
|
||||
confirmSeedWords: () => dispatch(confirmSeedWords()),
|
||||
openBuyEtherModal: () => dispatch(showModal({ name: 'DEPOSIT_ETHER'})),
|
||||
})
|
||||
)
|
||||
)(ConfirmSeedScreen)
|
@ -1,20 +1,26 @@
|
||||
import EventEmitter from 'events'
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {connect} from 'react-redux'
|
||||
import classnames from 'classnames'
|
||||
import {createNewVaultAndKeychain} from '../../../../ui/app/actions'
|
||||
import LoadingScreen from './loading-screen'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { compose } from 'recompose'
|
||||
import { createNewVaultAndKeychain } from '../../../../ui/app/actions'
|
||||
import Breadcrumbs from './breadcrumbs'
|
||||
import EventEmitter from 'events'
|
||||
import Mascot from '../../../../ui/app/components/mascot'
|
||||
import classnames from 'classnames'
|
||||
import {
|
||||
INITIALIZE_UNIQUE_IMAGE_ROUTE,
|
||||
INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE,
|
||||
INITIALIZE_NOTICE_ROUTE,
|
||||
} from '../../../../ui/app/routes'
|
||||
|
||||
class CreatePasswordScreen extends Component {
|
||||
static propTypes = {
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
createAccount: PropTypes.func.isRequired,
|
||||
goToImportWithSeedPhrase: PropTypes.func.isRequired,
|
||||
goToImportAccount: PropTypes.func.isRequired,
|
||||
next: PropTypes.func.isRequired,
|
||||
history: PropTypes.object.isRequired,
|
||||
isInitialized: PropTypes.bool,
|
||||
isUnlocked: PropTypes.bool,
|
||||
isMascara: PropTypes.bool.isRequired,
|
||||
}
|
||||
|
||||
@ -23,13 +29,21 @@ class CreatePasswordScreen extends Component {
|
||||
confirmPassword: '',
|
||||
}
|
||||
|
||||
constructor () {
|
||||
super()
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.animationEventEmitter = new EventEmitter()
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
const { isInitialized, history } = this.props
|
||||
|
||||
if (isInitialized) {
|
||||
history.push(INITIALIZE_NOTICE_ROUTE)
|
||||
}
|
||||
}
|
||||
|
||||
isValid () {
|
||||
const {password, confirmPassword} = this.state
|
||||
const { password, confirmPassword } = this.state
|
||||
|
||||
if (!password || !confirmPassword) {
|
||||
return false
|
||||
@ -47,93 +61,182 @@ class CreatePasswordScreen extends Component {
|
||||
return
|
||||
}
|
||||
|
||||
const {password} = this.state
|
||||
const {createAccount, next} = this.props
|
||||
const { password } = this.state
|
||||
const { createAccount, history } = this.props
|
||||
|
||||
this.setState({ isLoading: true })
|
||||
createAccount(password)
|
||||
.then(next)
|
||||
.then(() => history.push(INITIALIZE_UNIQUE_IMAGE_ROUTE))
|
||||
}
|
||||
|
||||
renderFields () {
|
||||
const { isMascara, history } = this.props
|
||||
|
||||
return (
|
||||
<div className={classnames({ 'first-view-main-wrapper': !isMascara })}>
|
||||
<div className={classnames({
|
||||
'first-view-main': !isMascara,
|
||||
'first-view-main__mascara': isMascara,
|
||||
})}>
|
||||
{isMascara && <div className="mascara-info first-view-phone-invisible">
|
||||
<Mascot
|
||||
animationEventEmitter={this.animationEventEmitter}
|
||||
width="225"
|
||||
height="225"
|
||||
/>
|
||||
<div className="info">
|
||||
MetaMask is a secure identity vault for Ethereum.
|
||||
</div>
|
||||
<div className="info">
|
||||
It allows you to hold ether & tokens, and interact with decentralized applications.
|
||||
</div>
|
||||
</div>}
|
||||
<div className="create-password">
|
||||
<div className="create-password__title">
|
||||
Create Password
|
||||
</div>
|
||||
<input
|
||||
className="first-time-flow__input"
|
||||
type="password"
|
||||
placeholder="New Password (min 8 characters)"
|
||||
onChange={e => this.setState({password: e.target.value})}
|
||||
/>
|
||||
<input
|
||||
className="first-time-flow__input create-password__confirm-input"
|
||||
type="password"
|
||||
placeholder="Confirm Password"
|
||||
onChange={e => this.setState({confirmPassword: e.target.value})}
|
||||
/>
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
disabled={!this.isValid()}
|
||||
onClick={this.createAccount}
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
<a
|
||||
href=""
|
||||
className="first-time-flow__link create-password__import-link"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
history.push(INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE)
|
||||
}}
|
||||
>
|
||||
Import with seed phrase
|
||||
</a>
|
||||
{ /* }
|
||||
<a
|
||||
href=""
|
||||
className="first-time-flow__link create-password__import-link"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
history.push(INITIALIZE_IMPORT_ACCOUNT_ROUTE)
|
||||
}}
|
||||
>
|
||||
Import an account
|
||||
</a>
|
||||
{ */ }
|
||||
<Breadcrumbs total={3} currentIndex={0} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
const { isLoading, goToImportWithSeedPhrase, isMascara } = this.props
|
||||
const { history, isMascara } = this.props
|
||||
|
||||
return isLoading
|
||||
? <LoadingScreen loadingMessage="Creating your new account" />
|
||||
: (
|
||||
<div className={classnames({ 'first-view-main-wrapper': !isMascara })}>
|
||||
<div className={classnames({
|
||||
'first-view-main': !isMascara,
|
||||
'first-view-main__mascara': isMascara,
|
||||
})}>
|
||||
{isMascara && <div className="mascara-info first-view-phone-invisible">
|
||||
<Mascot
|
||||
animationEventEmitter={this.animationEventEmitter}
|
||||
width="225"
|
||||
height="225"
|
||||
/>
|
||||
<div className="info">
|
||||
MetaMask is a secure identity vault for Ethereum.
|
||||
</div>
|
||||
<div className="info">
|
||||
It allows you to hold ether & tokens, and interact with decentralized applications.
|
||||
</div>
|
||||
</div>}
|
||||
<div className="create-password">
|
||||
<div className="create-password__title">
|
||||
Create Password
|
||||
</div>
|
||||
<input
|
||||
className="first-time-flow__input"
|
||||
type="password"
|
||||
placeholder="New Password (min 8 characters)"
|
||||
onChange={e => this.setState({password: e.target.value})}
|
||||
/>
|
||||
<input
|
||||
className="first-time-flow__input create-password__confirm-input"
|
||||
type="password"
|
||||
placeholder="Confirm Password"
|
||||
onChange={e => this.setState({confirmPassword: e.target.value})}
|
||||
/>
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
disabled={!this.isValid()}
|
||||
onClick={this.createAccount}
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
<a
|
||||
href=""
|
||||
className="first-time-flow__link create-password__import-link"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
goToImportWithSeedPhrase()
|
||||
}}
|
||||
>
|
||||
Import with seed phrase
|
||||
</a>
|
||||
{ /* }
|
||||
<a
|
||||
href=""
|
||||
className="first-time-flow__link create-password__import-link"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
goToImportAccount()
|
||||
}}
|
||||
>
|
||||
Import an account
|
||||
</a>
|
||||
{ */ }
|
||||
<Breadcrumbs total={3} currentIndex={0} />
|
||||
return (
|
||||
<div className={classnames({ 'first-view-main-wrapper': !isMascara })}>
|
||||
<div className={classnames({
|
||||
'first-view-main': !isMascara,
|
||||
'first-view-main__mascara': isMascara,
|
||||
})}>
|
||||
{isMascara && <div className="mascara-info first-view-phone-invisible">
|
||||
<Mascot
|
||||
animationEventEmitter={this.animationEventEmitter}
|
||||
width="225"
|
||||
height="225"
|
||||
/>
|
||||
<div className="info">
|
||||
MetaMask is a secure identity vault for Ethereum.
|
||||
</div>
|
||||
<div className="info">
|
||||
It allows you to hold ether & tokens, and interact with decentralized applications.
|
||||
</div>
|
||||
</div>}
|
||||
<div className="create-password">
|
||||
<div className="create-password__title">
|
||||
Create Password
|
||||
</div>
|
||||
<input
|
||||
className="first-time-flow__input"
|
||||
type="password"
|
||||
placeholder="New Password (min 8 characters)"
|
||||
onChange={e => this.setState({password: e.target.value})}
|
||||
/>
|
||||
<input
|
||||
className="first-time-flow__input create-password__confirm-input"
|
||||
type="password"
|
||||
placeholder="Confirm Password"
|
||||
onChange={e => this.setState({confirmPassword: e.target.value})}
|
||||
/>
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
disabled={!this.isValid()}
|
||||
onClick={this.createAccount}
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
<a
|
||||
href=""
|
||||
className="first-time-flow__link create-password__import-link"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
history.push(INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE)
|
||||
}}
|
||||
>
|
||||
Import with seed phrase
|
||||
</a>
|
||||
{ /* }
|
||||
<a
|
||||
href=""
|
||||
className="first-time-flow__link create-password__import-link"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
history.push(INITIALIZE_IMPORT_ACCOUNT_ROUTE)
|
||||
}}
|
||||
>
|
||||
Import an account
|
||||
</a>
|
||||
{ */ }
|
||||
<Breadcrumbs total={3} currentIndex={0} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
({ appState: { isLoading }, metamask: { isMascara } }) => ({ isLoading, isMascara }),
|
||||
dispatch => ({
|
||||
createAccount: password => dispatch(createNewVaultAndKeychain(password)),
|
||||
})
|
||||
const mapStateToProps = ({ metamask, appState }) => {
|
||||
const { isInitialized, isUnlocked, isMascara, noActiveNotices } = metamask
|
||||
const { isLoading } = appState
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
isInitialized,
|
||||
isUnlocked,
|
||||
isMascara,
|
||||
noActiveNotices,
|
||||
}
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withRouter,
|
||||
connect(
|
||||
mapStateToProps,
|
||||
dispatch => ({
|
||||
createAccount: password => dispatch(createNewVaultAndKeychain(password)),
|
||||
})
|
||||
)
|
||||
)(CreatePasswordScreen)
|
||||
|
@ -8,16 +8,16 @@ import {
|
||||
displayWarning,
|
||||
unMarkPasswordForgotten,
|
||||
} from '../../../../ui/app/actions'
|
||||
import { DEFAULT_ROUTE, INITIALIZE_NOTICE_ROUTE } from '../../../../ui/app/routes'
|
||||
|
||||
class ImportSeedPhraseScreen extends Component {
|
||||
static propTypes = {
|
||||
warning: PropTypes.string,
|
||||
back: PropTypes.func.isRequired,
|
||||
next: PropTypes.func.isRequired,
|
||||
createNewVaultAndRestore: PropTypes.func.isRequired,
|
||||
hideWarning: PropTypes.func.isRequired,
|
||||
displayWarning: PropTypes.func,
|
||||
leaveImportSeedScreenState: PropTypes.func,
|
||||
history: PropTypes.object,
|
||||
};
|
||||
|
||||
state = {
|
||||
@ -64,20 +64,21 @@ class ImportSeedPhraseScreen extends Component {
|
||||
const { password, seedPhrase } = this.state
|
||||
const {
|
||||
createNewVaultAndRestore,
|
||||
next,
|
||||
displayWarning,
|
||||
leaveImportSeedScreenState,
|
||||
history,
|
||||
} = this.props
|
||||
|
||||
leaveImportSeedScreenState()
|
||||
createNewVaultAndRestore(password, this.parseSeedPhrase(seedPhrase))
|
||||
.then(next)
|
||||
.then(() => history.push(INITIALIZE_NOTICE_ROUTE))
|
||||
}
|
||||
|
||||
render () {
|
||||
const { seedPhrase, password, confirmPassword } = this.state
|
||||
const { warning } = this.props
|
||||
const importDisabled = warning || !seedPhrase || !password || !confirmPassword
|
||||
const { warning, isLoading } = this.props
|
||||
const importDisabled = warning || !seedPhrase || !password || !confirmPassword || isLoading
|
||||
|
||||
return (
|
||||
<div className="first-view-main-wrapper">
|
||||
<div className="first-view-main">
|
||||
@ -86,7 +87,7 @@ class ImportSeedPhraseScreen extends Component {
|
||||
className="import-account__back-button"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
this.props.back()
|
||||
this.props.history.goBack()
|
||||
}}
|
||||
href="#"
|
||||
>
|
||||
@ -152,7 +153,7 @@ class ImportSeedPhraseScreen extends Component {
|
||||
}
|
||||
|
||||
export default connect(
|
||||
({ appState: { warning } }) => ({ warning }),
|
||||
({ appState: { warning, isLoading } }) => ({ warning, isLoading }),
|
||||
dispatch => ({
|
||||
leaveImportSeedScreenState: () => {
|
||||
dispatch(unMarkPasswordForgotten())
|
||||
|
@ -1,17 +1,26 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {connect} from 'react-redux'
|
||||
import { withRouter, Switch, Route } from 'react-router-dom'
|
||||
import { compose } from 'recompose'
|
||||
import CreatePasswordScreen from './create-password-screen'
|
||||
import UniqueImageScreen from './unique-image-screen'
|
||||
import NoticeScreen from './notice-screen'
|
||||
import BackupPhraseScreen from './backup-phrase-screen'
|
||||
import BackupPhraseScreen from './seed-screen'
|
||||
import ImportAccountScreen from './import-account-screen'
|
||||
import ImportSeedPhraseScreen from './import-seed-phrase-screen'
|
||||
import ConfirmSeed from './confirm-seed-screen'
|
||||
import {
|
||||
onboardingBuyEthView,
|
||||
unMarkPasswordForgotten,
|
||||
showModal,
|
||||
} from '../../../../ui/app/actions'
|
||||
INITIALIZE_ROUTE,
|
||||
INITIALIZE_IMPORT_ACCOUNT_ROUTE,
|
||||
INITIALIZE_UNIQUE_IMAGE_ROUTE,
|
||||
INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE,
|
||||
INITIALIZE_NOTICE_ROUTE,
|
||||
INITIALIZE_BACKUP_PHRASE_ROUTE,
|
||||
INITIALIZE_CONFIRM_SEED_ROUTE,
|
||||
INITIALIZE_CREATE_PASSWORD_ROUTE,
|
||||
} from '../../../../ui/app/routes'
|
||||
import WelcomeScreen from '../../../../ui/app/welcome-screen'
|
||||
|
||||
class FirstTimeFlow extends Component {
|
||||
|
||||
@ -20,6 +29,10 @@ class FirstTimeFlow extends Component {
|
||||
seedWords: PropTypes.string,
|
||||
address: PropTypes.string,
|
||||
noActiveNotices: PropTypes.bool,
|
||||
goToBuyEtherView: PropTypes.func,
|
||||
isUnlocked: PropTypes.bool,
|
||||
history: PropTypes.object,
|
||||
welcomeScreenSeen: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
@ -28,145 +41,53 @@ class FirstTimeFlow extends Component {
|
||||
noActiveNotices: false,
|
||||
};
|
||||
|
||||
static SCREEN_TYPE = {
|
||||
CREATE_PASSWORD: 'create_password',
|
||||
IMPORT_ACCOUNT: 'import_account',
|
||||
IMPORT_SEED_PHRASE: 'import_seed_phrase',
|
||||
UNIQUE_IMAGE: 'unique_image',
|
||||
NOTICE: 'notice',
|
||||
BACK_UP_PHRASE: 'back_up_phrase',
|
||||
CONFIRM_BACK_UP_PHRASE: 'confirm_back_up_phrase',
|
||||
LOADING: 'loading',
|
||||
};
|
||||
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
screenType: this.getScreenType(),
|
||||
}
|
||||
}
|
||||
|
||||
setScreenType (screenType) {
|
||||
this.setState({ screenType })
|
||||
}
|
||||
|
||||
getScreenType () {
|
||||
const {
|
||||
isInitialized,
|
||||
seedWords,
|
||||
noActiveNotices,
|
||||
forgottenPassword,
|
||||
} = this.props
|
||||
const {SCREEN_TYPE} = FirstTimeFlow
|
||||
|
||||
// return SCREEN_TYPE.NOTICE
|
||||
|
||||
if (forgottenPassword) {
|
||||
return SCREEN_TYPE.IMPORT_SEED_PHRASE
|
||||
}
|
||||
if (!isInitialized) {
|
||||
return SCREEN_TYPE.CREATE_PASSWORD
|
||||
}
|
||||
|
||||
if (!noActiveNotices) {
|
||||
return SCREEN_TYPE.NOTICE
|
||||
}
|
||||
|
||||
if (seedWords) {
|
||||
return SCREEN_TYPE.BACK_UP_PHRASE
|
||||
}
|
||||
};
|
||||
|
||||
renderScreen () {
|
||||
const {SCREEN_TYPE} = FirstTimeFlow
|
||||
const {
|
||||
openBuyEtherModal,
|
||||
address,
|
||||
restoreCreatePasswordScreen,
|
||||
forgottenPassword,
|
||||
leaveImportSeedScreenState,
|
||||
} = this.props
|
||||
|
||||
switch (this.state.screenType) {
|
||||
case SCREEN_TYPE.CREATE_PASSWORD:
|
||||
return (
|
||||
<CreatePasswordScreen
|
||||
next={() => this.setScreenType(SCREEN_TYPE.UNIQUE_IMAGE)}
|
||||
goToImportAccount={() => this.setScreenType(SCREEN_TYPE.IMPORT_ACCOUNT)}
|
||||
goToImportWithSeedPhrase={() => this.setScreenType(SCREEN_TYPE.IMPORT_SEED_PHRASE)}
|
||||
/>
|
||||
)
|
||||
case SCREEN_TYPE.IMPORT_ACCOUNT:
|
||||
return (
|
||||
<ImportAccountScreen
|
||||
back={() => this.setScreenType(SCREEN_TYPE.CREATE_PASSWORD)}
|
||||
next={() => this.setScreenType(SCREEN_TYPE.NOTICE)}
|
||||
/>
|
||||
)
|
||||
case SCREEN_TYPE.IMPORT_SEED_PHRASE:
|
||||
return (
|
||||
<ImportSeedPhraseScreen
|
||||
back={() => {
|
||||
leaveImportSeedScreenState()
|
||||
this.setScreenType(SCREEN_TYPE.CREATE_PASSWORD)
|
||||
}}
|
||||
next={() => {
|
||||
const newScreenType = forgottenPassword ? null : SCREEN_TYPE.NOTICE
|
||||
this.setScreenType(newScreenType)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
case SCREEN_TYPE.UNIQUE_IMAGE:
|
||||
return (
|
||||
<UniqueImageScreen
|
||||
next={() => this.setScreenType(SCREEN_TYPE.NOTICE)}
|
||||
/>
|
||||
)
|
||||
case SCREEN_TYPE.NOTICE:
|
||||
return (
|
||||
<NoticeScreen
|
||||
next={() => this.setScreenType(SCREEN_TYPE.BACK_UP_PHRASE)}
|
||||
/>
|
||||
)
|
||||
case SCREEN_TYPE.BACK_UP_PHRASE:
|
||||
return (
|
||||
<BackupPhraseScreen
|
||||
next={() => openBuyEtherModal()}
|
||||
/>
|
||||
)
|
||||
default:
|
||||
return <noscript />
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className="first-time-flow">
|
||||
{this.renderScreen()}
|
||||
<Switch>
|
||||
<Route exact path={INITIALIZE_IMPORT_ACCOUNT_ROUTE} component={ImportAccountScreen} />
|
||||
<Route
|
||||
exact
|
||||
path={INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE}
|
||||
component={ImportSeedPhraseScreen}
|
||||
/>
|
||||
<Route exact path={INITIALIZE_UNIQUE_IMAGE_ROUTE} component={UniqueImageScreen} />
|
||||
<Route exact path={INITIALIZE_NOTICE_ROUTE} component={NoticeScreen} />
|
||||
<Route exact path={INITIALIZE_BACKUP_PHRASE_ROUTE} component={BackupPhraseScreen} />
|
||||
<Route exact path={INITIALIZE_CONFIRM_SEED_ROUTE} component={ConfirmSeed} />
|
||||
<Route exact path={INITIALIZE_CREATE_PASSWORD_ROUTE} component={CreatePasswordScreen} />
|
||||
<Route exact path={INITIALIZE_ROUTE} component={WelcomeScreen} />
|
||||
</Switch>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(
|
||||
({
|
||||
metamask: {
|
||||
isInitialized,
|
||||
seedWords,
|
||||
noActiveNotices,
|
||||
selectedAddress,
|
||||
forgottenPassword,
|
||||
}
|
||||
}) => ({
|
||||
const mapStateToProps = ({ metamask }) => {
|
||||
const {
|
||||
isInitialized,
|
||||
seedWords,
|
||||
noActiveNotices,
|
||||
selectedAddress,
|
||||
forgottenPassword,
|
||||
isMascara,
|
||||
isUnlocked,
|
||||
welcomeScreenSeen,
|
||||
} = metamask
|
||||
|
||||
return {
|
||||
isMascara,
|
||||
isInitialized,
|
||||
seedWords,
|
||||
noActiveNotices,
|
||||
address: selectedAddress,
|
||||
forgottenPassword,
|
||||
}),
|
||||
dispatch => ({
|
||||
leaveImportSeedScreenState: () => dispatch(unMarkPasswordForgotten()),
|
||||
openBuyEtherModal: () => dispatch(showModal({ name: 'DEPOSIT_ETHER'})),
|
||||
})
|
||||
isUnlocked,
|
||||
welcomeScreenSeen,
|
||||
}
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withRouter,
|
||||
connect(mapStateToProps)
|
||||
)(FirstTimeFlow)
|
||||
|
@ -1,11 +1,14 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Markdown from 'react-markdown'
|
||||
import {connect} from 'react-redux'
|
||||
import { connect } from 'react-redux'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { compose } from 'recompose'
|
||||
import debounce from 'lodash.debounce'
|
||||
import {markNoticeRead} from '../../../../ui/app/actions'
|
||||
import { markNoticeRead } from '../../../../ui/app/actions'
|
||||
import Identicon from '../../../../ui/app/components/identicon'
|
||||
import Breadcrumbs from './breadcrumbs'
|
||||
import { INITIALIZE_BACKUP_PHRASE_ROUTE } from '../../../../ui/app/routes'
|
||||
import LoadingScreen from './loading-screen'
|
||||
|
||||
class NoticeScreen extends Component {
|
||||
@ -16,8 +19,15 @@ class NoticeScreen extends Component {
|
||||
date: PropTypes.string,
|
||||
body: PropTypes.string,
|
||||
}),
|
||||
next: PropTypes.func.isRequired,
|
||||
location: PropTypes.shape({
|
||||
state: PropTypes.shape({
|
||||
next: PropTypes.func.isRequired,
|
||||
}),
|
||||
}),
|
||||
markNoticeRead: PropTypes.func,
|
||||
history: PropTypes.object,
|
||||
isLoading: PropTypes.bool,
|
||||
noActiveNotices: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
@ -29,17 +39,24 @@ class NoticeScreen extends Component {
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
if (this.props.noActiveNotices) {
|
||||
this.props.history.push(INITIALIZE_BACKUP_PHRASE_ROUTE)
|
||||
}
|
||||
|
||||
this.onScroll()
|
||||
}
|
||||
|
||||
acceptTerms = () => {
|
||||
const { markNoticeRead, lastUnreadNotice, next } = this.props
|
||||
const defer = markNoticeRead(lastUnreadNotice)
|
||||
.then(() => this.setState({ atBottom: false }))
|
||||
|
||||
if ((/terms/gi).test(lastUnreadNotice.title)) {
|
||||
defer.then(next)
|
||||
}
|
||||
const { markNoticeRead, lastUnreadNotice, history } = this.props
|
||||
markNoticeRead(lastUnreadNotice)
|
||||
.then(hasActiveNotices => {
|
||||
if (!hasActiveNotices) {
|
||||
history.push(INITIALIZE_BACKUP_PHRASE_ROUTE)
|
||||
} else {
|
||||
this.setState({ atBottom: false })
|
||||
this.onScroll()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onScroll = debounce(() => {
|
||||
@ -64,27 +81,29 @@ class NoticeScreen extends Component {
|
||||
isLoading
|
||||
? <LoadingScreen />
|
||||
: (
|
||||
<div className="first-view-main-wrapper">
|
||||
<div className="first-view-main">
|
||||
<div
|
||||
className="tou"
|
||||
onScroll={this.onScroll}
|
||||
>
|
||||
<Identicon address={address} diameter={70} />
|
||||
<div className="tou__title">{title}</div>
|
||||
<Markdown
|
||||
className="tou__body markdown"
|
||||
source={body}
|
||||
skipHtml
|
||||
/>
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
onClick={atBottom && this.acceptTerms}
|
||||
disabled={!atBottom}
|
||||
<div className="first-time-flow">
|
||||
<div className="first-view-main-wrapper">
|
||||
<div className="first-view-main">
|
||||
<div
|
||||
className="tou"
|
||||
onScroll={this.onScroll}
|
||||
>
|
||||
Accept
|
||||
</button>
|
||||
<Breadcrumbs total={3} currentIndex={2} />
|
||||
<Identicon address={address} diameter={70} />
|
||||
<div className="tou__title">{title}</div>
|
||||
<Markdown
|
||||
className="tou__body markdown"
|
||||
source={body}
|
||||
skipHtml
|
||||
/>
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
onClick={atBottom && this.acceptTerms}
|
||||
disabled={!atBottom}
|
||||
>
|
||||
Accept
|
||||
</button>
|
||||
<Breadcrumbs total={3} currentIndex={2} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -93,12 +112,24 @@ class NoticeScreen extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
({ metamask: { selectedAddress, lastUnreadNotice }, appState: { isLoading } }) => ({
|
||||
lastUnreadNotice,
|
||||
const mapStateToProps = ({ metamask, appState }) => {
|
||||
const { selectedAddress, lastUnreadNotice, noActiveNotices } = metamask
|
||||
const { isLoading } = appState
|
||||
|
||||
return {
|
||||
address: selectedAddress,
|
||||
}),
|
||||
dispatch => ({
|
||||
markNoticeRead: notice => dispatch(markNoticeRead(notice)),
|
||||
})
|
||||
lastUnreadNotice,
|
||||
noActiveNotices,
|
||||
isLoading,
|
||||
}
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withRouter,
|
||||
connect(
|
||||
mapStateToProps,
|
||||
dispatch => ({
|
||||
markNoticeRead: notice => dispatch(markNoticeRead(notice)),
|
||||
})
|
||||
)
|
||||
)(NoticeScreen)
|
||||
|
@ -1,13 +1,14 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {connect} from 'react-redux'
|
||||
import { connect } from 'react-redux'
|
||||
import classnames from 'classnames'
|
||||
import shuffle from 'lodash.shuffle'
|
||||
import {compose, onlyUpdateForPropTypes} from 'recompose'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { compose } from 'recompose'
|
||||
import Identicon from '../../../../ui/app/components/identicon'
|
||||
import {confirmSeedWords} from '../../../../ui/app/actions'
|
||||
import Breadcrumbs from './breadcrumbs'
|
||||
import LoadingScreen from './loading-screen'
|
||||
import { DEFAULT_ROUTE, INITIALIZE_CONFIRM_SEED_ROUTE } from '../../../../ui/app/routes'
|
||||
import { confirmSeedWords } from '../../../../ui/app/actions'
|
||||
|
||||
const LockIcon = props => (
|
||||
<svg
|
||||
@ -36,34 +37,42 @@ const LockIcon = props => (
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
)
|
||||
|
||||
class BackupPhraseScreen extends Component {
|
||||
static propTypes = {
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
address: PropTypes.string.isRequired,
|
||||
seedWords: PropTypes.string.isRequired,
|
||||
next: PropTypes.func.isRequired,
|
||||
confirmSeedWords: PropTypes.func.isRequired,
|
||||
seedWords: PropTypes.string,
|
||||
history: PropTypes.object,
|
||||
isRevealingSeedWords: PropTypes.bool,
|
||||
clearSeedWords: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
seedWords: ''
|
||||
};
|
||||
seedWords: '',
|
||||
}
|
||||
|
||||
static PAGE = {
|
||||
SECRET: 'secret',
|
||||
CONFIRM: 'confirm'
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
const {seedWords} = props
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
isShowingSecret: false,
|
||||
page: BackupPhraseScreen.PAGE.SECRET,
|
||||
selectedSeeds: [],
|
||||
shuffledSeeds: seedWords && shuffle(seedWords.split(' ')),
|
||||
}
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
this.checkSeedWords()
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
this.checkSeedWords()
|
||||
}
|
||||
|
||||
checkSeedWords () {
|
||||
const { seedWords, history } = this.props
|
||||
|
||||
if (!seedWords) {
|
||||
history.push(DEFAULT_ROUTE)
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +82,7 @@ class BackupPhraseScreen extends Component {
|
||||
return (
|
||||
<div className="backup-phrase__secret">
|
||||
<div className={classnames('backup-phrase__secret-words', {
|
||||
'backup-phrase__secret-words--hidden': !isShowingSecret
|
||||
'backup-phrase__secret-words--hidden': !isShowingSecret,
|
||||
})}>
|
||||
{this.props.seedWords}
|
||||
</div>
|
||||
@ -94,9 +103,30 @@ class BackupPhraseScreen extends Component {
|
||||
)
|
||||
}
|
||||
|
||||
renderSecretScreen () {
|
||||
renderSubmitButton () {
|
||||
const { isRevealingSeedWords, clearSeedWords, history } = this.props
|
||||
const { isShowingSecret } = this.state
|
||||
|
||||
return isRevealingSeedWords
|
||||
? <button
|
||||
className="first-time-flow__button"
|
||||
onClick={() => clearSeedWords().then(() => history.push(DEFAULT_ROUTE))}
|
||||
disabled={!isShowingSecret}
|
||||
>
|
||||
Done
|
||||
</button>
|
||||
: <button
|
||||
className="first-time-flow__button"
|
||||
onClick={() => isShowingSecret && history.push(INITIALIZE_CONFIRM_SEED_ROUTE)}
|
||||
disabled={!isShowingSecret}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
}
|
||||
|
||||
renderSecretScreen () {
|
||||
const { isRevealingSeedWords } = this.props
|
||||
|
||||
return (
|
||||
<div className="backup-phrase__content-wrapper">
|
||||
<div className="backup-phrase__phrase">
|
||||
@ -122,115 +152,13 @@ class BackupPhraseScreen extends Component {
|
||||
</div>
|
||||
</div>
|
||||
<div className="backup-phrase__next-button">
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
onClick={() => isShowingSecret && this.setState({
|
||||
isShowingSecret: false,
|
||||
page: BackupPhraseScreen.PAGE.CONFIRM,
|
||||
})}
|
||||
disabled={!isShowingSecret}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
<Breadcrumbs total={3} currentIndex={1} />
|
||||
{ this.renderSubmitButton() }
|
||||
{ !isRevealingSeedWords && <Breadcrumbs total={3} currentIndex={1} />}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderConfirmationScreen() {
|
||||
const { seedWords, confirmSeedWords, next } = this.props;
|
||||
const { selectedSeeds, shuffledSeeds } = this.state;
|
||||
const isValid = seedWords === selectedSeeds.map(([_, seed]) => seed).join(' ')
|
||||
|
||||
return (
|
||||
<div className="backup-phrase__content-wrapper">
|
||||
<div>
|
||||
<div className="backup-phrase__title">Confirm your Secret Backup Phrase</div>
|
||||
<div className="backup-phrase__body-text">
|
||||
Please select each phrase in order to make sure it is correct.
|
||||
</div>
|
||||
<div className="backup-phrase__confirm-secret">
|
||||
{selectedSeeds.map(([_, word], i) => (
|
||||
<button
|
||||
key={i}
|
||||
className="backup-phrase__confirm-seed-option"
|
||||
>
|
||||
{word}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="backup-phrase__confirm-seed-options">
|
||||
{shuffledSeeds.map((word, i) => {
|
||||
const isSelected = selectedSeeds
|
||||
.filter(([index, seed]) => seed === word && index === i)
|
||||
.length
|
||||
|
||||
return (
|
||||
<button
|
||||
key={i}
|
||||
className={classnames('backup-phrase__confirm-seed-option', {
|
||||
'backup-phrase__confirm-seed-option--selected': isSelected
|
||||
})}
|
||||
onClick={() => {
|
||||
if (!isSelected) {
|
||||
this.setState({
|
||||
selectedSeeds: [...selectedSeeds, [i, word]]
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
selectedSeeds: selectedSeeds
|
||||
.filter(([index, seed]) => !(seed === word && index === i))
|
||||
})
|
||||
}
|
||||
}}
|
||||
>
|
||||
{word}
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
onClick={() => isValid && confirmSeedWords().then(next)}
|
||||
disabled={!isValid}
|
||||
>
|
||||
Confirm
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderBack () {
|
||||
return this.state.page === BackupPhraseScreen.PAGE.CONFIRM
|
||||
? (
|
||||
<a
|
||||
className="backup-phrase__back-button"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
this.setState({
|
||||
page: BackupPhraseScreen.PAGE.SECRET
|
||||
})
|
||||
}}
|
||||
href="#"
|
||||
>
|
||||
{`< Back`}
|
||||
</a>
|
||||
)
|
||||
: null
|
||||
}
|
||||
|
||||
renderContent () {
|
||||
switch (this.state.page) {
|
||||
case BackupPhraseScreen.PAGE.CONFIRM:
|
||||
return this.renderConfirmationScreen()
|
||||
case BackupPhraseScreen.PAGE.SECRET:
|
||||
default:
|
||||
return this.renderSecretScreen()
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return this.props.isLoading
|
||||
? <LoadingScreen loadingMessage="Creating your new account" />
|
||||
@ -238,9 +166,8 @@ class BackupPhraseScreen extends Component {
|
||||
<div className="first-view-main-wrapper">
|
||||
<div className="first-view-main">
|
||||
<div className="backup-phrase">
|
||||
{this.renderBack()}
|
||||
<Identicon address={this.props.address} diameter={70} />
|
||||
{this.renderContent()}
|
||||
{this.renderSecretScreen()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -248,16 +175,25 @@ class BackupPhraseScreen extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({ metamask, appState }) => {
|
||||
const { selectedAddress, seedWords, isRevealingSeedWords } = metamask
|
||||
const { isLoading } = appState
|
||||
|
||||
return {
|
||||
seedWords,
|
||||
isRevealingSeedWords,
|
||||
isLoading,
|
||||
address: selectedAddress,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
clearSeedWords: () => dispatch(confirmSeedWords()),
|
||||
}
|
||||
}
|
||||
|
||||
export default compose(
|
||||
onlyUpdateForPropTypes,
|
||||
connect(
|
||||
({ metamask: { selectedAddress, seedWords }, appState: { isLoading } }) => ({
|
||||
seedWords,
|
||||
isLoading,
|
||||
address: selectedAddress,
|
||||
}),
|
||||
dispatch => ({
|
||||
confirmSeedWords: () => dispatch(confirmSeedWords()),
|
||||
})
|
||||
)
|
||||
withRouter,
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
)(BackupPhraseScreen)
|
@ -1,13 +1,16 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { compose } from 'recompose'
|
||||
import {connect} from 'react-redux'
|
||||
import Identicon from '../../../../ui/app/components/identicon'
|
||||
import Breadcrumbs from './breadcrumbs'
|
||||
import { INITIALIZE_NOTICE_ROUTE } from '../../../../ui/app/routes'
|
||||
|
||||
class UniqueImageScreen extends Component {
|
||||
static propTypes = {
|
||||
address: PropTypes.string,
|
||||
next: PropTypes.func.isRequired,
|
||||
history: PropTypes.object,
|
||||
}
|
||||
|
||||
render () {
|
||||
@ -25,7 +28,7 @@ class UniqueImageScreen extends Component {
|
||||
</div>
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
onClick={this.props.next}
|
||||
onClick={() => this.props.history.push(INITIALIZE_NOTICE_ROUTE)}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
@ -37,8 +40,11 @@ class UniqueImageScreen extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
({ metamask: { selectedAddress } }) => ({
|
||||
address: selectedAddress,
|
||||
})
|
||||
export default compose(
|
||||
withRouter,
|
||||
connect(
|
||||
({ metamask: { selectedAddress } }) => ({
|
||||
address: selectedAddress,
|
||||
})
|
||||
)
|
||||
)(UniqueImageScreen)
|
||||
|
@ -3,6 +3,7 @@ const Component = require('react').Component
|
||||
const connect = require('react-redux').connect
|
||||
const h = require('react-hyperscript')
|
||||
const actions = require('../../ui/app/actions')
|
||||
const log = require('loglevel')
|
||||
// mascara
|
||||
const MascaraFirstTime = require('../../mascara/src/app/first-time').default
|
||||
const MascaraBuyEtherScreen = require('../../mascara/src/app/first-time/buy-ether-screen').default
|
||||
|
@ -8,6 +8,7 @@ const ENS = require('ethjs-ens')
|
||||
const networkMap = require('ethjs-ens/lib/network-map.json')
|
||||
const ensRE = /.+\..+$/
|
||||
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
|
||||
const log = require('loglevel')
|
||||
|
||||
|
||||
module.exports = EnsInput
|
||||
|
@ -3,6 +3,7 @@ const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const actions = require('../../../ui/app/actions')
|
||||
const clone = require('clone')
|
||||
const log = require('loglevel')
|
||||
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const BN = ethUtil.BN
|
||||
|
@ -3,6 +3,7 @@ const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const TokenTracker = require('eth-token-tracker')
|
||||
const TokenCell = require('./token-cell.js')
|
||||
const log = require('loglevel')
|
||||
|
||||
module.exports = TokenList
|
||||
|
||||
|
@ -6,7 +6,9 @@ const actions = require('../../ui/app/actions')
|
||||
const NetworkIndicator = require('./components/network')
|
||||
const LoadingIndicator = require('./components/loading')
|
||||
const txHelper = require('../lib/tx-helper')
|
||||
const isPopupOrNotification = require('../../app/scripts/lib/is-popup-or-notification')
|
||||
const log = require('loglevel')
|
||||
const { ENVIRONMENT_TYPE_NOTIFICATION } = require('../../app/scripts/lib/enums')
|
||||
const { getEnvironmentType } = require('../../app/scripts/lib/util')
|
||||
|
||||
const PendingTx = require('./components/pending-tx')
|
||||
const PendingMsg = require('./components/pending-msg')
|
||||
@ -50,7 +52,7 @@ ConfirmTxScreen.prototype.render = function () {
|
||||
|
||||
var txData = unconfTxList[props.index] || {}
|
||||
var txParams = txData.params || {}
|
||||
var isNotification = isPopupOrNotification() === 'notification'
|
||||
var isNotification = getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION
|
||||
|
||||
log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`)
|
||||
if (unconfTxList.length === 0) return h(Loading, { isLoading: true })
|
||||
|
@ -1,4 +1,5 @@
|
||||
const valuesFor = require('../app/util').valuesFor
|
||||
const log = require('loglevel')
|
||||
|
||||
module.exports = function (unapprovedTxs, unapprovedMsgs, personalMsgs, typedMessages, network) {
|
||||
log.debug('tx-helper called with params:')
|
||||
|
812
package-lock.json
generated
812
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@ -7,8 +7,9 @@
|
||||
"start": "gulp dev:extension",
|
||||
"mascara": "gulp dev:mascara & node ./mascara/example/server",
|
||||
"dist": "gulp dist",
|
||||
"doc": "jsdoc -c development/tools/.jsdoc.json",
|
||||
"test": "npm run test:unit && npm run test:integration && npm run lint",
|
||||
"test:unit": "cross-env METAMASK_ENV=test mocha --exit --require babel-core/register --require test/helper.js --recursive \"test/unit/**/*.js\"",
|
||||
"test:unit": "cross-env METAMASK_ENV=test mocha --exit --require test/setup.js --recursive \"test/unit/**/*.js\"",
|
||||
"test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js",
|
||||
"test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara",
|
||||
"test:integration:build": "gulp build:scss",
|
||||
@ -75,6 +76,7 @@
|
||||
"classnames": "^2.2.5",
|
||||
"clone": "^2.1.1",
|
||||
"copy-to-clipboard": "^3.0.8",
|
||||
"currency-formatter": "^1.4.2",
|
||||
"debounce": "^1.0.0",
|
||||
"debounce-stream": "^2.0.0",
|
||||
"deep-extend": "^0.5.0",
|
||||
@ -90,7 +92,7 @@
|
||||
"eth-hd-keyring": "^1.2.1",
|
||||
"eth-json-rpc-filters": "^1.2.5",
|
||||
"eth-json-rpc-infura": "^3.0.0",
|
||||
"eth-keyring-controller": "^2.1.4",
|
||||
"eth-keyring-controller": "^2.2.0",
|
||||
"eth-phishing-detect": "^1.1.4",
|
||||
"eth-query": "^2.1.2",
|
||||
"eth-sig-util": "^1.4.2",
|
||||
@ -100,7 +102,7 @@
|
||||
"ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
|
||||
"ethereumjs-wallet": "^0.6.0",
|
||||
"etherscan-link": "^1.0.2",
|
||||
"ethjs": "^0.2.8",
|
||||
"ethjs": "^0.3.4",
|
||||
"ethjs-contract": "^0.1.9",
|
||||
"ethjs-ens": "^2.0.0",
|
||||
"ethjs-query": "^0.3.4",
|
||||
@ -114,7 +116,7 @@
|
||||
"gulp-autoprefixer": "^5.0.0",
|
||||
"gulp-debug": "^3.2.0",
|
||||
"gulp-eslint": "^4.0.0",
|
||||
"gulp-sass": "^3.1.0",
|
||||
"gulp-sass": "^4.0.0",
|
||||
"hat": "0.0.3",
|
||||
"human-standard-token-abi": "^1.0.2",
|
||||
"idb-global": "^2.1.0",
|
||||
@ -131,7 +133,7 @@
|
||||
"lodash.uniqby": "^4.7.0",
|
||||
"loglevel": "^1.4.1",
|
||||
"metamascara": "^2.0.0",
|
||||
"metamask-logo": "^2.1.2",
|
||||
"metamask-logo": "^2.1.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"multiplex": "^6.7.0",
|
||||
"number-to-bn": "^1.7.0",
|
||||
@ -145,6 +147,7 @@
|
||||
"post-message-stream": "^3.0.0",
|
||||
"promise-filter": "^1.1.0",
|
||||
"promise-to-callback": "^1.0.0",
|
||||
"prop-types": "^15.6.1",
|
||||
"pump": "^3.0.0",
|
||||
"pumpify": "^1.3.4",
|
||||
"qrcode-npm": "0.0.3",
|
||||
@ -156,6 +159,7 @@
|
||||
"react-hyperscript": "^3.0.0",
|
||||
"react-markdown": "^3.0.0",
|
||||
"react-redux": "^5.0.5",
|
||||
"react-router-dom": "^4.2.2",
|
||||
"react-select": "^1.0.0",
|
||||
"react-simple-file-input": "^2.0.0",
|
||||
"react-tippy": "^1.2.2",
|
||||
@ -234,6 +238,7 @@
|
||||
"gulp-zip": "^4.0.0",
|
||||
"image-size": "^0.6.2",
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"jsdoc": "^3.5.5",
|
||||
"jsdom": "^11.2.0",
|
||||
"jsdom-global": "^3.0.2",
|
||||
"jshint-stylish": "~2.2.1",
|
||||
@ -255,6 +260,7 @@
|
||||
"prompt": "^1.0.0",
|
||||
"qs": "^6.2.0",
|
||||
"qunitjs": "^2.4.1",
|
||||
"radgrad-jsdoc-template": "^1.1.3",
|
||||
"react-addons-test-utils": "^15.5.1",
|
||||
"react-test-renderer": "^15.6.2",
|
||||
"react-testutils-additions": "^15.2.0",
|
||||
|
@ -21,11 +21,22 @@ async function runConfirmSigRequestsTest(assert, done) {
|
||||
selectState.val('confirm sig requests')
|
||||
reactTriggerChange(selectState[0])
|
||||
|
||||
// await timeout(1000000)
|
||||
|
||||
const pendingRequestItem = $.find('.tx-list-item.tx-list-pending-item-container.tx-list-clickable')
|
||||
|
||||
if (pendingRequestItem[0]) {
|
||||
pendingRequestItem[0].click()
|
||||
}
|
||||
|
||||
let confirmSigHeadline = await queryAsync($, '.request-signature__headline')
|
||||
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
|
||||
|
||||
let confirmSigMessage = await queryAsync($, '.request-signature__notice')
|
||||
assert.ok(confirmSigMessage[0].textContent.match(/^Signing\sthis\smessage/))
|
||||
|
||||
let confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
|
||||
assert.ok(confirmSigRowValue[0].textContent.match(/^\#\sTerms\sof\sUse/))
|
||||
assert.equal(confirmSigRowValue[0].textContent, '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0')
|
||||
|
||||
let confirmSigSignButton = await queryAsync($, 'button.btn-primary--lg')
|
||||
confirmSigSignButton[0].click()
|
||||
@ -33,11 +44,8 @@ async function runConfirmSigRequestsTest(assert, done) {
|
||||
confirmSigHeadline = await queryAsync($, '.request-signature__headline')
|
||||
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
|
||||
|
||||
let confirmSigMessage = await queryAsync($, '.request-signature__notice')
|
||||
assert.ok(confirmSigMessage[0].textContent.match(/^Signing\sthis\smessage/))
|
||||
|
||||
confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
|
||||
assert.equal(confirmSigRowValue[0].textContent, '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0')
|
||||
assert.ok(confirmSigRowValue[0].textContent.match(/^\#\sTerms\sof\sUse/))
|
||||
|
||||
confirmSigSignButton = await queryAsync($, 'button.btn-primary--lg')
|
||||
confirmSigSignButton[0].click()
|
||||
|
28
test/integration/lib/currency-localization.js
Normal file
28
test/integration/lib/currency-localization.js
Normal file
@ -0,0 +1,28 @@
|
||||
const reactTriggerChange = require('../../lib/react-trigger-change')
|
||||
const {
|
||||
timeout,
|
||||
queryAsync,
|
||||
findAsync,
|
||||
} = require('../../lib/util')
|
||||
|
||||
QUnit.module('currency localization')
|
||||
|
||||
QUnit.test('renders localized currency', (assert) => {
|
||||
const done = assert.async()
|
||||
runCurrencyLocalizationTest(assert).then(done).catch((err) => {
|
||||
assert.notOk(err, `Error was thrown: ${err.stack}`)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
async function runCurrencyLocalizationTest(assert, done) {
|
||||
console.log('*** start runCurrencyLocalizationTest')
|
||||
const selectState = await queryAsync($, 'select')
|
||||
selectState.val('currency localization')
|
||||
reactTriggerChange(selectState[0])
|
||||
await timeout(1000)
|
||||
const txView = await queryAsync($, '.tx-view')
|
||||
const heroBalance = await findAsync($(txView), '.hero-balance')
|
||||
const fiatAmount = await findAsync($(heroBalance), '.fiat-amount')
|
||||
assert.equal(fiatAmount[0].textContent, '₱102,707.97')
|
||||
}
|
@ -13,6 +13,9 @@ async function runFirstTimeUsageTest (assert, done) {
|
||||
|
||||
await skipNotices(app)
|
||||
|
||||
const welcomeButton = (await findAsync(app, '.welcome-screen__button'))[0]
|
||||
welcomeButton.click()
|
||||
|
||||
// Scroll through terms
|
||||
const title = (await findAsync(app, '.create-password__title')).text()
|
||||
assert.equal(title, 'Create Password', 'create password screen')
|
||||
|
@ -53,7 +53,7 @@ async function runSendFlowTest(assert, done) {
|
||||
assert.equal(sendFromDropdownList.children().length, 4, 'send from dropdown shows all accounts')
|
||||
sendFromDropdownList.children()[1].click()
|
||||
|
||||
sendFromFieldItemAddress = await queryAsync($, '.account-list-item__account-name')
|
||||
sendFromFieldItemAddress = await queryAsync($, '.account-list-item__account-name')
|
||||
assert.equal(sendFromFieldItemAddress[0].textContent, 'Send Account 2', 'send from field dropdown changes account name')
|
||||
|
||||
let sendToFieldInput = await queryAsync($, '.send-v2__to-autocomplete__input')
|
||||
@ -91,7 +91,7 @@ async function runSendFlowTest(assert, done) {
|
||||
)
|
||||
assert.equal(
|
||||
sendGasField.find('.currency-display__converted-value')[0].textContent,
|
||||
'0.24 USD',
|
||||
'$0.24 USD',
|
||||
'send gas field should show estimated gas total converted to USD'
|
||||
)
|
||||
|
||||
@ -118,7 +118,7 @@ async function runSendFlowTest(assert, done) {
|
||||
)
|
||||
assert.equal(
|
||||
(await findAsync(sendGasField, '.currency-display__converted-value'))[0].textContent,
|
||||
'3.60 USD',
|
||||
'$3.60 USD',
|
||||
'send gas field should show customized gas total converted to USD'
|
||||
)
|
||||
|
||||
@ -138,9 +138,9 @@ async function runSendFlowTest(assert, done) {
|
||||
|
||||
const confirmScreenRows = await queryAsync($, '.confirm-screen-rows')
|
||||
const confirmScreenGas = confirmScreenRows.find('.currency-display__converted-value')[0]
|
||||
assert.equal(confirmScreenGas.textContent, '3.60 USD', 'confirm screen should show correct gas')
|
||||
assert.equal(confirmScreenGas.textContent, '$3.60 USD', 'confirm screen should show correct gas')
|
||||
const confirmScreenTotal = confirmScreenRows.find('.confirm-screen-row-info')[2]
|
||||
assert.equal(confirmScreenTotal.textContent, '2405.36 USD', 'confirm screen should show correct total')
|
||||
assert.equal(confirmScreenTotal.textContent, '$2,405.36 USD', 'confirm screen should show correct total')
|
||||
|
||||
const confirmScreenBackButton = await queryAsync($, '.page-container__back-button')
|
||||
confirmScreenBackButton[0].click()
|
||||
@ -164,17 +164,27 @@ async function runSendFlowTest(assert, done) {
|
||||
|
||||
const sendButtonInEdit = await queryAsync($, '.btn-primary--lg.page-container__footer-button')
|
||||
assert.equal(sendButtonInEdit[0].textContent, 'Next', 'next button in edit rendered')
|
||||
sendButtonInEdit[0].click()
|
||||
|
||||
// TODO: Need a way to mock background so that we can test correct transition from editing to confirm
|
||||
selectState.val('confirm new ui')
|
||||
selectState.val('send new ui')
|
||||
reactTriggerChange(selectState[0])
|
||||
const confirmScreenConfirmButton = await queryAsync($, '.btn-confirm.page-container__footer-button')
|
||||
console.log(`+++++++++++++++++++++++++++++++= confirmScreenConfirmButton[0]`, confirmScreenConfirmButton[0]);
|
||||
confirmScreenConfirmButton[0].click()
|
||||
|
||||
const txView = await queryAsync($, '.tx-view')
|
||||
console.log(`++++++++++++++++++++++++++++++++ txView[0]`, txView[0]);
|
||||
const cancelButtonInEdit = await queryAsync($, '.btn-secondary--lg.page-container__footer-button')
|
||||
cancelButtonInEdit[0].click()
|
||||
// sendButtonInEdit[0].click()
|
||||
|
||||
assert.ok(txView[0], 'Should return to the account details screen after confirming')
|
||||
// // TODO: Need a way to mock background so that we can test correct transition from editing to confirm
|
||||
// selectState.val('confirm new ui')
|
||||
// reactTriggerChange(selectState[0])
|
||||
|
||||
|
||||
// const confirmScreenConfirmButton = await queryAsync($, '.btn-confirm.page-container__footer-button')
|
||||
// console.log(`+++++++++++++++++++++++++++++++= confirmScreenConfirmButton[0]`, confirmScreenConfirmButton[0]);
|
||||
// confirmScreenConfirmButton[0].click()
|
||||
|
||||
// await timeout(10000000)
|
||||
|
||||
// const txView = await queryAsync($, '.tx-view')
|
||||
// console.log(`++++++++++++++++++++++++++++++++ txView[0]`, txView[0]);
|
||||
|
||||
// assert.ok(txView[0], 'Should return to the account details screen after confirming')
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ async function runTxListItemsTest(assert, done) {
|
||||
|
||||
const confirmedTokenTx = txListItems[6]
|
||||
const confirmedTokenTxAddress = await findAsync($(confirmedTokenTx), '.tx-list-account')
|
||||
assert.equal(confirmedTokenTxAddress[0].textContent, '0xe7884118...81a9', 'confirmedTokenTx has correct address')
|
||||
assert.equal(confirmedTokenTxAddress[0].textContent, '0xE7884118...81a9', 'confirmedTokenTx has correct address')
|
||||
|
||||
const rejectedTx = txListItems[7]
|
||||
const rejectedTxRenderedStatus = await findAsync($(rejectedTx), '.tx-list-status')
|
||||
|
5
test/setup.js
Normal file
5
test/setup.js
Normal file
@ -0,0 +1,5 @@
|
||||
require('babel-register')({
|
||||
ignore: name => name.includes('node_modules') && !name.includes('obs-store'),
|
||||
})
|
||||
|
||||
require('./helper')
|
35
test/unit/ComposableObservableStore.js
Normal file
35
test/unit/ComposableObservableStore.js
Normal file
@ -0,0 +1,35 @@
|
||||
const assert = require('assert')
|
||||
const ComposableObservableStore = require('../../app/scripts/lib/ComposableObservableStore')
|
||||
const ObservableStore = require('obs-store')
|
||||
|
||||
describe('ComposableObservableStore', () => {
|
||||
it('should register initial state', () => {
|
||||
const store = new ComposableObservableStore('state')
|
||||
assert.strictEqual(store.getState(), 'state')
|
||||
})
|
||||
|
||||
it('should register initial structure', () => {
|
||||
const testStore = new ObservableStore()
|
||||
const store = new ComposableObservableStore(null, { TestStore: testStore })
|
||||
testStore.putState('state')
|
||||
assert.deepEqual(store.getState(), { TestStore: 'state' })
|
||||
})
|
||||
|
||||
it('should update structure', () => {
|
||||
const testStore = new ObservableStore()
|
||||
const store = new ComposableObservableStore()
|
||||
store.updateStructure({ TestStore: testStore })
|
||||
testStore.putState('state')
|
||||
assert.deepEqual(store.getState(), { TestStore: 'state' })
|
||||
})
|
||||
|
||||
it('should return flattened state', () => {
|
||||
const fooStore = new ObservableStore({ foo: 'foo' })
|
||||
const barStore = new ObservableStore({ bar: 'bar' })
|
||||
const store = new ComposableObservableStore(null, {
|
||||
FooStore: fooStore,
|
||||
BarStore: barStore,
|
||||
})
|
||||
assert.deepEqual(store.getFlatState(), { foo: 'foo', bar: 'bar' })
|
||||
})
|
||||
})
|
27
test/unit/balance-formatter-test.js
Normal file
27
test/unit/balance-formatter-test.js
Normal file
@ -0,0 +1,27 @@
|
||||
const assert = require('assert')
|
||||
const currencyFormatter = require('currency-formatter')
|
||||
const infuraConversion = require('../../ui/app/infura-conversion.json')
|
||||
|
||||
describe('currencyFormatting', function () {
|
||||
it('be able to format any infura currency', function (done) {
|
||||
const number = 10000
|
||||
|
||||
infuraConversion.objects.forEach((conversion) => {
|
||||
const code = conversion.quote.code.toUpperCase()
|
||||
const result = currencyFormatter.format(number, { code })
|
||||
|
||||
switch (code) {
|
||||
case 'USD':
|
||||
assert.equal(result, '$10,000.00')
|
||||
break
|
||||
case 'JPY':
|
||||
assert.equal(result, '¥10,000')
|
||||
break
|
||||
default:
|
||||
assert.ok(result, `Currency ${code} formatted as ${result}`)
|
||||
}
|
||||
})
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
29
test/unit/token-rates-controller.js
Normal file
29
test/unit/token-rates-controller.js
Normal file
@ -0,0 +1,29 @@
|
||||
const assert = require('assert')
|
||||
const sinon = require('sinon')
|
||||
const TokenRatesController = require('../../app/scripts/controllers/token-rates')
|
||||
const ObservableStore = require('obs-store')
|
||||
|
||||
describe('TokenRatesController', () => {
|
||||
it('should listen for preferences store updates', () => {
|
||||
const preferences = new ObservableStore({ tokens: [] })
|
||||
const controller = new TokenRatesController({ preferences })
|
||||
preferences.putState({ tokens: ['foo'] })
|
||||
assert.deepEqual(controller._tokens, ['foo'])
|
||||
})
|
||||
|
||||
it('should poll on correct interval', async () => {
|
||||
const stub = sinon.stub(global, 'setInterval')
|
||||
new TokenRatesController({ interval: 1337 }) // eslint-disable-line no-new
|
||||
assert.strictEqual(stub.getCall(0).args[1], 1337)
|
||||
stub.restore()
|
||||
})
|
||||
|
||||
it('should fetch each token rate based on address', async () => {
|
||||
const controller = new TokenRatesController()
|
||||
controller.isActive = true
|
||||
controller.fetchExchangeRate = address => address
|
||||
controller.tokens = [{ address: 'foo' }, { address: 'bar' }]
|
||||
await controller.updateExchangeRates()
|
||||
assert.deepEqual(controller.store.getState().contractExchangeRates, { foo: 'foo', bar: 'bar' })
|
||||
})
|
||||
})
|
@ -3,6 +3,7 @@ const getBuyEthUrl = require('../../app/scripts/lib/buy-eth-url')
|
||||
const { getTokenAddressFromTokenObject } = require('./util')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const { fetchLocale } = require('../i18n-helper')
|
||||
const log = require('loglevel')
|
||||
|
||||
var actions = {
|
||||
_setBackgroundConnection: _setBackgroundConnection,
|
||||
@ -220,8 +221,6 @@ var actions = {
|
||||
coinBaseSubview: coinBaseSubview,
|
||||
SHAPESHIFT_SUBVIEW: 'SHAPESHIFT_SUBVIEW',
|
||||
shapeShiftSubview: shapeShiftSubview,
|
||||
UPDATE_TOKEN_EXCHANGE_RATE: 'UPDATE_TOKEN_EXCHANGE_RATE',
|
||||
updateTokenExchangeRate,
|
||||
PAIR_UPDATE: 'PAIR_UPDATE',
|
||||
pairUpdate: pairUpdate,
|
||||
coinShiftRquest: coinShiftRquest,
|
||||
@ -346,16 +345,14 @@ function transitionBackward () {
|
||||
}
|
||||
}
|
||||
|
||||
function confirmSeedWords () {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
log.debug(`background.clearSeedWordCache`)
|
||||
function clearSeedWordCache () {
|
||||
log.debug(`background.clearSeedWordCache`)
|
||||
return dispatch => {
|
||||
return new Promise((resolve, reject) => {
|
||||
background.clearSeedWordCache((err, account) => {
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
if (err) {
|
||||
dispatch(actions.displayWarning(err.message))
|
||||
reject(err)
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
log.info('Seed word cache cleared. ' + account)
|
||||
@ -366,6 +363,22 @@ function confirmSeedWords () {
|
||||
}
|
||||
}
|
||||
|
||||
function confirmSeedWords () {
|
||||
return async dispatch => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
const account = await dispatch(clearSeedWordCache())
|
||||
return dispatch(setIsRevealingSeedWords(false))
|
||||
.then(() => {
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
return account
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
return account
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function createNewVaultAndRestore (password, seed) {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
@ -447,11 +460,13 @@ function requestRevealSeed (password) {
|
||||
}
|
||||
|
||||
dispatch(actions.showNewVaultSeed(result))
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
.then(() => dispatch(setIsRevealingSeedWords(true)))
|
||||
.then(() => dispatch(actions.hideLoadingIndication()))
|
||||
.catch(() => dispatch(actions.hideLoadingIndication()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -571,35 +586,47 @@ function signMsg (msgData) {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
log.debug(`actions calling background.signMessage`)
|
||||
background.signMessage(msgData, (err, newState) => {
|
||||
log.debug('signMessage called back')
|
||||
dispatch(actions.updateMetamaskState(newState))
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
return new Promise((resolve, reject) => {
|
||||
log.debug(`actions calling background.signMessage`)
|
||||
background.signMessage(msgData, (err, newState) => {
|
||||
log.debug('signMessage called back')
|
||||
dispatch(actions.updateMetamaskState(newState))
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
|
||||
if (err) log.error(err)
|
||||
if (err) return dispatch(actions.displayWarning(err.message))
|
||||
if (err) {
|
||||
log.error(err)
|
||||
dispatch(actions.displayWarning(err.message))
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
dispatch(actions.completedTx(msgData.metamaskId))
|
||||
dispatch(actions.completedTx(msgData.metamaskId))
|
||||
return resolve(msgData)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function signPersonalMsg (msgData) {
|
||||
log.debug('action - signPersonalMsg')
|
||||
return (dispatch) => {
|
||||
return dispatch => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
log.debug(`actions calling background.signPersonalMessage`)
|
||||
background.signPersonalMessage(msgData, (err, newState) => {
|
||||
log.debug('signPersonalMessage called back')
|
||||
dispatch(actions.updateMetamaskState(newState))
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
return new Promise((resolve, reject) => {
|
||||
log.debug(`actions calling background.signPersonalMessage`)
|
||||
background.signPersonalMessage(msgData, (err, newState) => {
|
||||
log.debug('signPersonalMessage called back')
|
||||
dispatch(actions.updateMetamaskState(newState))
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
|
||||
if (err) log.error(err)
|
||||
if (err) return dispatch(actions.displayWarning(err.message))
|
||||
if (err) {
|
||||
log.error(err)
|
||||
dispatch(actions.displayWarning(err.message))
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
dispatch(actions.completedTx(msgData.metamaskId))
|
||||
dispatch(actions.completedTx(msgData.metamaskId))
|
||||
return resolve(msgData)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -609,16 +636,22 @@ function signTypedMsg (msgData) {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
log.debug(`actions calling background.signTypedMessage`)
|
||||
background.signTypedMessage(msgData, (err, newState) => {
|
||||
log.debug('signTypedMessage called back')
|
||||
dispatch(actions.updateMetamaskState(newState))
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
return new Promise((resolve, reject) => {
|
||||
log.debug(`actions calling background.signTypedMessage`)
|
||||
background.signTypedMessage(msgData, (err, newState) => {
|
||||
log.debug('signTypedMessage called back')
|
||||
dispatch(actions.updateMetamaskState(newState))
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
|
||||
if (err) log.error(err)
|
||||
if (err) return dispatch(actions.displayWarning(err.message))
|
||||
if (err) {
|
||||
log.error(err)
|
||||
dispatch(actions.displayWarning(err.message))
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
dispatch(actions.completedTx(msgData.metamaskId))
|
||||
dispatch(actions.completedTx(msgData.metamaskId))
|
||||
return resolve(msgData)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -798,17 +831,24 @@ function updateTransaction (txData) {
|
||||
function updateAndApproveTx (txData) {
|
||||
log.info('actions: updateAndApproveTx: ' + JSON.stringify(txData))
|
||||
return (dispatch) => {
|
||||
log.debug(`actions calling background.updateAndApproveTx.`)
|
||||
background.updateAndApproveTransaction(txData, (err) => {
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
dispatch(actions.updateTransactionParams(txData.id, txData.txParams))
|
||||
dispatch(actions.clearSend())
|
||||
if (err) {
|
||||
dispatch(actions.txError(err))
|
||||
dispatch(actions.goHome())
|
||||
return log.error(err.message)
|
||||
}
|
||||
dispatch(actions.completedTx(txData.id))
|
||||
log.debug(`actions calling background.updateAndApproveTx`)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
background.updateAndApproveTransaction(txData, err => {
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
dispatch(actions.updateTransactionParams(txData.id, txData.txParams))
|
||||
dispatch(actions.clearSend())
|
||||
|
||||
if (err) {
|
||||
dispatch(actions.txError(err))
|
||||
dispatch(actions.goHome())
|
||||
log.error(err.message)
|
||||
reject(err)
|
||||
}
|
||||
|
||||
dispatch(actions.completedTx(txData.id))
|
||||
resolve(txData)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -836,29 +876,77 @@ function txError (err) {
|
||||
}
|
||||
|
||||
function cancelMsg (msgData) {
|
||||
log.debug(`background.cancelMessage`)
|
||||
background.cancelMessage(msgData.id)
|
||||
return actions.completedTx(msgData.id)
|
||||
return dispatch => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
log.debug(`background.cancelMessage`)
|
||||
background.cancelMessage(msgData.id, (err, newState) => {
|
||||
dispatch(actions.updateMetamaskState(newState))
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
dispatch(actions.completedTx(msgData.id))
|
||||
return resolve(msgData)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function cancelPersonalMsg (msgData) {
|
||||
const id = msgData.id
|
||||
background.cancelPersonalMessage(id)
|
||||
return actions.completedTx(id)
|
||||
return dispatch => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = msgData.id
|
||||
background.cancelPersonalMessage(id, (err, newState) => {
|
||||
dispatch(actions.updateMetamaskState(newState))
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
dispatch(actions.completedTx(id))
|
||||
return resolve(msgData)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function cancelTypedMsg (msgData) {
|
||||
const id = msgData.id
|
||||
background.cancelTypedMessage(id)
|
||||
return actions.completedTx(id)
|
||||
return dispatch => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = msgData.id
|
||||
background.cancelTypedMessage(id, (err, newState) => {
|
||||
dispatch(actions.updateMetamaskState(newState))
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
dispatch(actions.completedTx(id))
|
||||
return resolve(msgData)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function cancelTx (txData) {
|
||||
return (dispatch) => {
|
||||
return dispatch => {
|
||||
log.debug(`background.cancelTransaction`)
|
||||
background.cancelTransaction(txData.id, () => {
|
||||
dispatch(actions.clearSend())
|
||||
dispatch(actions.completedTx(txData.id))
|
||||
return new Promise((resolve, reject) => {
|
||||
background.cancelTransaction(txData.id, () => {
|
||||
dispatch(actions.clearSend())
|
||||
dispatch(actions.completedTx(txData.id))
|
||||
resolve(txData)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1249,12 +1337,13 @@ function markNoticeRead (notice) {
|
||||
dispatch(actions.displayWarning(err))
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
if (notice) {
|
||||
dispatch(actions.showNotice(notice))
|
||||
resolve()
|
||||
resolve(true)
|
||||
} else {
|
||||
dispatch(actions.clearNotices())
|
||||
resolve()
|
||||
resolve(false)
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -1677,28 +1766,6 @@ function shapeShiftRequest (query, options, cb) {
|
||||
}
|
||||
}
|
||||
|
||||
function updateTokenExchangeRate (token = '') {
|
||||
const pair = `${token.toLowerCase()}_eth`
|
||||
|
||||
return dispatch => {
|
||||
if (!token) {
|
||||
return
|
||||
}
|
||||
|
||||
shapeShiftRequest('marketinfo', { pair }, marketinfo => {
|
||||
if (!marketinfo.error) {
|
||||
dispatch({
|
||||
type: actions.UPDATE_TOKEN_EXCHANGE_RATE,
|
||||
payload: {
|
||||
pair,
|
||||
marketinfo,
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function setFeatureFlag (feature, activated, notificationType) {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
@ -1773,7 +1840,7 @@ function forceUpdateMetamaskState (dispatch) {
|
||||
}
|
||||
|
||||
dispatch(actions.updateMetamaskState(newState))
|
||||
resolve()
|
||||
resolve(newState)
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -1856,3 +1923,11 @@ function updateNetworkEndpointType (networkEndpointType) {
|
||||
value: networkEndpointType,
|
||||
}
|
||||
}
|
||||
|
||||
function setIsRevealingSeedWords (reveal) {
|
||||
return dispatch => {
|
||||
log.debug(`background.setIsRevealingSeedWords`)
|
||||
background.setIsRevealingSeedWords(reveal)
|
||||
return forceUpdateMetamaskState(dispatch)
|
||||
}
|
||||
}
|
||||
|
934
ui/app/app.js
934
ui/app/app.js
@ -1,62 +1,420 @@
|
||||
const inherits = require('util').inherits
|
||||
const Component = require('react').Component
|
||||
const connect = require('react-redux').connect
|
||||
const h = require('react-hyperscript')
|
||||
const { Component } = require('react')
|
||||
const PropTypes = require('prop-types')
|
||||
const connect = require('react-redux').connect
|
||||
const { Route, Switch, withRouter } = require('react-router-dom')
|
||||
const { compose } = require('recompose')
|
||||
const h = require('react-hyperscript')
|
||||
const actions = require('./actions')
|
||||
const classnames = require('classnames')
|
||||
const log = require('loglevel')
|
||||
|
||||
// mascara
|
||||
const MascaraFirstTime = require('../../mascara/src/app/first-time').default
|
||||
const MascaraBuyEtherScreen = require('../../mascara/src/app/first-time/buy-ether-screen').default
|
||||
// init
|
||||
const OldUIInitializeMenuScreen = require('./first-time/init-menu')
|
||||
const InitializeMenuScreen = MascaraFirstTime
|
||||
const NewKeyChainScreen = require('./new-keychain')
|
||||
const WelcomeScreen = require('./welcome-screen').default
|
||||
|
||||
const InitializeScreen = require('../../mascara/src/app/first-time').default
|
||||
// accounts
|
||||
const MainContainer = require('./main-container')
|
||||
const SendTransactionScreen2 = require('./components/send/send-v2-container')
|
||||
const ConfirmTxScreen = require('./conf-tx')
|
||||
// notice
|
||||
const NoticeScreen = require('./components/notice')
|
||||
const generateLostAccountsNotice = require('../lib/lost-accounts-notice')
|
||||
|
||||
// slideout menu
|
||||
const WalletView = require('./components/wallet-view')
|
||||
|
||||
// other views
|
||||
const Settings = require('./settings')
|
||||
const AddTokenScreen = require('./add-token')
|
||||
const Import = require('./accounts/import')
|
||||
const NewAccount = require('./accounts/new-account')
|
||||
const Home = require('./components/pages/home')
|
||||
const Authenticated = require('./components/pages/authenticated')
|
||||
const Initialized = require('./components/pages/initialized')
|
||||
const Settings = require('./components/pages/settings')
|
||||
const UnlockPage = require('./components/pages/unlock')
|
||||
const RestoreVaultPage = require('./components/pages/keychains/restore-vault')
|
||||
const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation')
|
||||
const AddTokenPage = require('./components/pages/add-token')
|
||||
const CreateAccountPage = require('./components/pages/create-account')
|
||||
const NoticeScreen = require('./components/pages/notice')
|
||||
|
||||
const Loading = require('./components/loading')
|
||||
const NetworkIndicator = require('./components/network')
|
||||
const Identicon = require('./components/identicon')
|
||||
const BuyView = require('./components/buy-button-subview')
|
||||
const HDCreateVaultComplete = require('./keychains/hd/create-vault-complete')
|
||||
const HDRestoreVaultScreen = require('./keychains/hd/restore-vault')
|
||||
const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation')
|
||||
const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
|
||||
const NetworkDropdown = require('./components/dropdowns/network-dropdown')
|
||||
const AccountMenu = require('./components/account-menu')
|
||||
const QrView = require('./components/qr-code')
|
||||
|
||||
// Global Modals
|
||||
const Modal = require('./components/modals/index').Modal
|
||||
|
||||
App.contextTypes = {
|
||||
t: PropTypes.func,
|
||||
// Routes
|
||||
const {
|
||||
DEFAULT_ROUTE,
|
||||
UNLOCK_ROUTE,
|
||||
SETTINGS_ROUTE,
|
||||
REVEAL_SEED_ROUTE,
|
||||
RESTORE_VAULT_ROUTE,
|
||||
ADD_TOKEN_ROUTE,
|
||||
NEW_ACCOUNT_ROUTE,
|
||||
SEND_ROUTE,
|
||||
CONFIRM_TRANSACTION_ROUTE,
|
||||
INITIALIZE_ROUTE,
|
||||
NOTICE_ROUTE,
|
||||
} = require('./routes')
|
||||
|
||||
class App extends Component {
|
||||
componentWillMount () {
|
||||
const {
|
||||
currentCurrency,
|
||||
setCurrentCurrencyToUSD,
|
||||
isRevealingSeedWords,
|
||||
clearSeedWords,
|
||||
} = this.props
|
||||
|
||||
if (!currentCurrency) {
|
||||
setCurrentCurrencyToUSD()
|
||||
}
|
||||
|
||||
if (isRevealingSeedWords) {
|
||||
clearSeedWords()
|
||||
}
|
||||
}
|
||||
|
||||
renderRoutes () {
|
||||
const exact = true
|
||||
|
||||
return (
|
||||
h(Switch, [
|
||||
h(Route, { path: INITIALIZE_ROUTE, component: InitializeScreen }),
|
||||
h(Initialized, { path: REVEAL_SEED_ROUTE, exact, component: RevealSeedConfirmation }),
|
||||
h(Initialized, { path: UNLOCK_ROUTE, exact, component: UnlockPage }),
|
||||
h(Initialized, { path: SETTINGS_ROUTE, component: Settings }),
|
||||
h(Initialized, { path: RESTORE_VAULT_ROUTE, exact, component: RestoreVaultPage }),
|
||||
h(Initialized, { path: NOTICE_ROUTE, exact, component: NoticeScreen }),
|
||||
h(Authenticated, { path: CONFIRM_TRANSACTION_ROUTE, component: ConfirmTxScreen }),
|
||||
h(Authenticated, { path: SEND_ROUTE, exact, component: SendTransactionScreen2 }),
|
||||
h(Authenticated, { path: ADD_TOKEN_ROUTE, exact, component: AddTokenPage }),
|
||||
h(Authenticated, { path: NEW_ACCOUNT_ROUTE, component: CreateAccountPage }),
|
||||
h(Authenticated, { path: DEFAULT_ROUTE, exact, component: Home }),
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
isLoading,
|
||||
loadingMessage,
|
||||
network,
|
||||
isMouseUser,
|
||||
provider,
|
||||
frequentRpcList,
|
||||
currentView,
|
||||
setMouseUserState,
|
||||
} = this.props
|
||||
const isLoadingNetwork = network === 'loading' && currentView.name !== 'config'
|
||||
const loadMessage = loadingMessage || isLoadingNetwork ?
|
||||
this.getConnectingLabel() : null
|
||||
log.debug('Main ui render function')
|
||||
|
||||
return (
|
||||
h('.flex-column.full-height', {
|
||||
className: classnames({ 'mouse-user-styles': isMouseUser }),
|
||||
style: {
|
||||
overflowX: 'hidden',
|
||||
position: 'relative',
|
||||
alignItems: 'center',
|
||||
},
|
||||
tabIndex: '0',
|
||||
onClick: () => setMouseUserState(true),
|
||||
onKeyDown: (e) => {
|
||||
if (e.keyCode === 9) {
|
||||
setMouseUserState(false)
|
||||
}
|
||||
},
|
||||
}, [
|
||||
|
||||
// global modal
|
||||
h(Modal, {}, []),
|
||||
|
||||
// app bar
|
||||
this.renderAppBar(),
|
||||
|
||||
// sidebar
|
||||
this.renderSidebar(),
|
||||
|
||||
// network dropdown
|
||||
h(NetworkDropdown, {
|
||||
provider,
|
||||
frequentRpcList,
|
||||
}, []),
|
||||
|
||||
h(AccountMenu),
|
||||
|
||||
(isLoading || isLoadingNetwork) && h(Loading, {
|
||||
loadingMessage: loadMessage,
|
||||
}),
|
||||
|
||||
// content
|
||||
this.renderRoutes(),
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
renderGlobalModal () {
|
||||
return h(Modal, {
|
||||
ref: 'modalRef',
|
||||
}, [
|
||||
// h(BuyOptions, {}, []),
|
||||
])
|
||||
}
|
||||
|
||||
renderSidebar () {
|
||||
return h('div', [
|
||||
h('style', `
|
||||
.sidebar-enter {
|
||||
transition: transform 300ms ease-in-out;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
.sidebar-enter.sidebar-enter-active {
|
||||
transition: transform 300ms ease-in-out;
|
||||
transform: translateX(0%);
|
||||
}
|
||||
.sidebar-leave {
|
||||
transition: transform 200ms ease-out;
|
||||
transform: translateX(0%);
|
||||
}
|
||||
.sidebar-leave.sidebar-leave-active {
|
||||
transition: transform 200ms ease-out;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
`),
|
||||
|
||||
h(ReactCSSTransitionGroup, {
|
||||
transitionName: 'sidebar',
|
||||
transitionEnterTimeout: 300,
|
||||
transitionLeaveTimeout: 200,
|
||||
}, [
|
||||
// A second instance of Walletview is used for non-mobile viewports
|
||||
this.props.sidebarOpen ? h(WalletView, {
|
||||
responsiveDisplayClassname: '.sidebar',
|
||||
style: {},
|
||||
}) : undefined,
|
||||
|
||||
]),
|
||||
|
||||
// overlay
|
||||
// TODO: add onClick for overlay to close sidebar
|
||||
this.props.sidebarOpen ? h('div.sidebar-overlay', {
|
||||
style: {},
|
||||
onClick: () => {
|
||||
this.props.hideSidebar()
|
||||
},
|
||||
}, []) : undefined,
|
||||
])
|
||||
}
|
||||
|
||||
renderAppBar () {
|
||||
const {
|
||||
isUnlocked,
|
||||
network,
|
||||
provider,
|
||||
networkDropdownOpen,
|
||||
showNetworkDropdown,
|
||||
hideNetworkDropdown,
|
||||
isInitialized,
|
||||
welcomeScreenSeen,
|
||||
isPopup,
|
||||
betaUI,
|
||||
} = this.props
|
||||
|
||||
if (window.METAMASK_UI_TYPE === 'notification') {
|
||||
return null
|
||||
}
|
||||
|
||||
const props = this.props
|
||||
const {isMascara, isOnboarding} = props
|
||||
|
||||
// Do not render header if user is in mascara onboarding
|
||||
if (isMascara && isOnboarding) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Do not render header if user is in mascara buy ether
|
||||
if (isMascara && props.currentView.name === 'buyEth') {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
h('.full-width', {
|
||||
style: {},
|
||||
}, [
|
||||
|
||||
(isInitialized || welcomeScreenSeen || isPopup || !betaUI) && h('.app-header.flex-row.flex-space-between', {
|
||||
className: classnames({
|
||||
'app-header--initialized': !isOnboarding,
|
||||
}),
|
||||
}, [
|
||||
h('div.app-header-contents', {}, [
|
||||
h('div.left-menu-wrapper', {
|
||||
onClick: () => props.history.push(DEFAULT_ROUTE),
|
||||
}, [
|
||||
// mini logo
|
||||
h('img.metafox-icon', {
|
||||
height: 42,
|
||||
width: 42,
|
||||
src: '/images/metamask-fox.svg',
|
||||
}),
|
||||
|
||||
// metamask name
|
||||
h('.flex-row', [
|
||||
h('h1', this.context.t('appName')),
|
||||
h('div.beta-label', this.context.t('beta')),
|
||||
]),
|
||||
|
||||
]),
|
||||
|
||||
betaUI && isInitialized && h('div.header__right-actions', [
|
||||
h('div.network-component-wrapper', {
|
||||
style: {},
|
||||
}, [
|
||||
// Network Indicator
|
||||
h(NetworkIndicator, {
|
||||
network,
|
||||
provider,
|
||||
disabled: this.props.location.pathname === CONFIRM_TRANSACTION_ROUTE,
|
||||
onClick: (event) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
return networkDropdownOpen === false
|
||||
? showNetworkDropdown()
|
||||
: hideNetworkDropdown()
|
||||
},
|
||||
}),
|
||||
|
||||
]),
|
||||
|
||||
isUnlocked && h('div.account-menu__icon', { onClick: this.props.toggleAccountMenu }, [
|
||||
h(Identicon, {
|
||||
address: this.props.selectedAddress,
|
||||
diameter: 32,
|
||||
}),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
|
||||
!isInitialized && !isPopup && betaUI && h('.alpha-warning__container', {}, [
|
||||
h('h2', {
|
||||
className: classnames({
|
||||
'alpha-warning': welcomeScreenSeen,
|
||||
'alpha-warning-welcome-screen': !welcomeScreenSeen,
|
||||
}),
|
||||
}, 'Please be aware that this version is still under development'),
|
||||
]),
|
||||
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
toggleMetamaskActive () {
|
||||
if (!this.props.isUnlocked) {
|
||||
// currently inactive: redirect to password box
|
||||
var passwordBox = document.querySelector('input[type=password]')
|
||||
if (!passwordBox) return
|
||||
passwordBox.focus()
|
||||
} else {
|
||||
// currently active: deactivate
|
||||
this.props.dispatch(actions.lockMetamask(false))
|
||||
}
|
||||
}
|
||||
|
||||
getConnectingLabel = function () {
|
||||
const { provider } = this.props
|
||||
const providerName = provider.type
|
||||
|
||||
let name
|
||||
|
||||
if (providerName === 'mainnet') {
|
||||
name = this.context.t('connectingToMainnet')
|
||||
} else if (providerName === 'ropsten') {
|
||||
name = this.context.t('connectingToRopsten')
|
||||
} else if (providerName === 'kovan') {
|
||||
name = this.context.t('connectingToRopsten')
|
||||
} else if (providerName === 'rinkeby') {
|
||||
name = this.context.t('connectingToRinkeby')
|
||||
} else {
|
||||
name = this.context.t('connectingToUnknown')
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
getNetworkName () {
|
||||
const { provider } = this.props
|
||||
const providerName = provider.type
|
||||
|
||||
let name
|
||||
|
||||
if (providerName === 'mainnet') {
|
||||
name = this.context.t('mainnet')
|
||||
} else if (providerName === 'ropsten') {
|
||||
name = this.context.t('ropsten')
|
||||
} else if (providerName === 'kovan') {
|
||||
name = this.context.t('kovan')
|
||||
} else if (providerName === 'rinkeby') {
|
||||
name = this.context.t('rinkeby')
|
||||
} else {
|
||||
name = this.context.t('unknownNetwork')
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(App)
|
||||
|
||||
|
||||
inherits(App, Component)
|
||||
function App () { Component.call(this) }
|
||||
App.propTypes = {
|
||||
currentCurrency: PropTypes.string,
|
||||
setCurrentCurrencyToUSD: PropTypes.func,
|
||||
isLoading: PropTypes.bool,
|
||||
loadingMessage: PropTypes.string,
|
||||
network: PropTypes.string,
|
||||
provider: PropTypes.object,
|
||||
frequentRpcList: PropTypes.array,
|
||||
currentView: PropTypes.object,
|
||||
sidebarOpen: PropTypes.bool,
|
||||
hideSidebar: PropTypes.func,
|
||||
isMascara: PropTypes.bool,
|
||||
isOnboarding: PropTypes.bool,
|
||||
isUnlocked: PropTypes.bool,
|
||||
networkDropdownOpen: PropTypes.bool,
|
||||
showNetworkDropdown: PropTypes.func,
|
||||
hideNetworkDropdown: PropTypes.func,
|
||||
history: PropTypes.object,
|
||||
location: PropTypes.object,
|
||||
dispatch: PropTypes.func,
|
||||
toggleAccountMenu: PropTypes.func,
|
||||
selectedAddress: PropTypes.string,
|
||||
noActiveNotices: PropTypes.bool,
|
||||
lostAccounts: PropTypes.array,
|
||||
isInitialized: PropTypes.bool,
|
||||
forgottenPassword: PropTypes.bool,
|
||||
activeAddress: PropTypes.string,
|
||||
unapprovedTxs: PropTypes.object,
|
||||
seedWords: PropTypes.string,
|
||||
unapprovedMsgCount: PropTypes.number,
|
||||
unapprovedPersonalMsgCount: PropTypes.number,
|
||||
unapprovedTypedMessagesCount: PropTypes.number,
|
||||
welcomeScreenSeen: PropTypes.bool,
|
||||
isPopup: PropTypes.bool,
|
||||
betaUI: PropTypes.bool,
|
||||
isMouseUser: PropTypes.bool,
|
||||
setMouseUserState: PropTypes.func,
|
||||
t: PropTypes.func,
|
||||
isRevealingSeedWords: PropTypes.bool,
|
||||
clearSeedWords: PropTypes.func,
|
||||
}
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const { appState, metamask } = state
|
||||
const {
|
||||
networkDropdownOpen,
|
||||
sidebarOpen,
|
||||
isLoading,
|
||||
loadingMessage,
|
||||
} = appState
|
||||
|
||||
const {
|
||||
identities,
|
||||
accounts,
|
||||
@ -65,17 +423,23 @@ function mapStateToProps (state) {
|
||||
isInitialized,
|
||||
noActiveNotices,
|
||||
seedWords,
|
||||
} = state.metamask
|
||||
unapprovedTxs,
|
||||
lastUnreadNotice,
|
||||
lostAccounts,
|
||||
unapprovedMsgCount,
|
||||
unapprovedPersonalMsgCount,
|
||||
unapprovedTypedMessagesCount,
|
||||
} = metamask
|
||||
const selected = address || Object.keys(accounts)[0]
|
||||
|
||||
return {
|
||||
// state from plugin
|
||||
networkDropdownOpen: state.appState.networkDropdownOpen,
|
||||
sidebarOpen: state.appState.sidebarOpen,
|
||||
isLoading: state.appState.isLoading,
|
||||
loadingMessage: state.appState.loadingMessage,
|
||||
noActiveNotices: state.metamask.noActiveNotices,
|
||||
isInitialized: state.metamask.isInitialized,
|
||||
networkDropdownOpen,
|
||||
sidebarOpen,
|
||||
isLoading,
|
||||
loadingMessage,
|
||||
noActiveNotices,
|
||||
isInitialized,
|
||||
isUnlocked: state.metamask.isUnlocked,
|
||||
selectedAddress: state.metamask.selectedAddress,
|
||||
currentView: state.appState.currentView,
|
||||
@ -85,14 +449,17 @@ function mapStateToProps (state) {
|
||||
isOnboarding: Boolean(!noActiveNotices || seedWords || !isInitialized),
|
||||
isPopup: state.metamask.isPopup,
|
||||
seedWords: state.metamask.seedWords,
|
||||
unapprovedTxs: state.metamask.unapprovedTxs,
|
||||
unapprovedTxs,
|
||||
unapprovedMsgs: state.metamask.unapprovedMsgs,
|
||||
unapprovedMsgCount,
|
||||
unapprovedPersonalMsgCount,
|
||||
unapprovedTypedMessagesCount,
|
||||
menuOpen: state.appState.menuOpen,
|
||||
network: state.metamask.network,
|
||||
provider: state.metamask.provider,
|
||||
forgottenPassword: state.metamask.forgottenPassword,
|
||||
lastUnreadNotice: state.metamask.lastUnreadNotice,
|
||||
lostAccounts: state.metamask.lostAccounts,
|
||||
forgottenPassword: state.appState.forgottenPassword,
|
||||
lastUnreadNotice,
|
||||
lostAccounts,
|
||||
frequentRpcList: state.metamask.frequentRpcList || [],
|
||||
currentCurrency: state.metamask.currentCurrency,
|
||||
isMouseUser: state.appState.isMouseUser,
|
||||
@ -117,482 +484,15 @@ function mapDispatchToProps (dispatch, ownProps) {
|
||||
setCurrentCurrencyToUSD: () => dispatch(actions.setCurrentCurrency('usd')),
|
||||
toggleAccountMenu: () => dispatch(actions.toggleAccountMenu()),
|
||||
setMouseUserState: (isMouseUser) => dispatch(actions.setMouseUserState(isMouseUser)),
|
||||
clearSeedWords: () => dispatch(actions.confirmSeedWords()),
|
||||
}
|
||||
}
|
||||
|
||||
App.prototype.componentWillMount = function () {
|
||||
if (!this.props.currentCurrency) {
|
||||
this.props.setCurrentCurrencyToUSD()
|
||||
}
|
||||
App.contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
||||
App.prototype.render = function () {
|
||||
var props = this.props
|
||||
const {
|
||||
isLoading,
|
||||
loadingMessage,
|
||||
network,
|
||||
isMouseUser,
|
||||
setMouseUserState,
|
||||
} = props
|
||||
const isLoadingNetwork = network === 'loading' && props.currentView.name !== 'config'
|
||||
const loadMessage = loadingMessage || isLoadingNetwork ?
|
||||
this.getConnectingLabel() : null
|
||||
log.debug('Main ui render function')
|
||||
|
||||
return (
|
||||
h('.flex-column.full-height', {
|
||||
className: classnames({ 'mouse-user-styles': isMouseUser }),
|
||||
style: {
|
||||
overflowX: 'hidden',
|
||||
position: 'relative',
|
||||
alignItems: 'center',
|
||||
},
|
||||
tabIndex: '0',
|
||||
onClick: () => setMouseUserState(true),
|
||||
onKeyDown: (e) => {
|
||||
if (e.keyCode === 9) {
|
||||
setMouseUserState(false)
|
||||
}
|
||||
},
|
||||
}, [
|
||||
|
||||
// global modal
|
||||
h(Modal, {}, []),
|
||||
|
||||
// app bar
|
||||
this.renderAppBar(),
|
||||
|
||||
// sidebar
|
||||
this.renderSidebar(),
|
||||
|
||||
// network dropdown
|
||||
h(NetworkDropdown, {
|
||||
provider: this.props.provider,
|
||||
frequentRpcList: this.props.frequentRpcList,
|
||||
}, []),
|
||||
|
||||
h(AccountMenu),
|
||||
|
||||
(isLoading || isLoadingNetwork) && h(Loading, {
|
||||
loadingMessage: loadMessage,
|
||||
}),
|
||||
|
||||
// this.renderLoadingIndicator({ isLoading, isLoadingNetwork, loadMessage }),
|
||||
|
||||
// content
|
||||
this.renderPrimary(),
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
App.prototype.renderGlobalModal = function () {
|
||||
return h(Modal, {
|
||||
ref: 'modalRef',
|
||||
}, [
|
||||
// h(BuyOptions, {}, []),
|
||||
])
|
||||
}
|
||||
|
||||
App.prototype.renderSidebar = function () {
|
||||
|
||||
return h('div', {
|
||||
}, [
|
||||
h('style', `
|
||||
.sidebar-enter {
|
||||
transition: transform 300ms ease-in-out;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
.sidebar-enter.sidebar-enter-active {
|
||||
transition: transform 300ms ease-in-out;
|
||||
transform: translateX(0%);
|
||||
}
|
||||
.sidebar-leave {
|
||||
transition: transform 200ms ease-out;
|
||||
transform: translateX(0%);
|
||||
}
|
||||
.sidebar-leave.sidebar-leave-active {
|
||||
transition: transform 200ms ease-out;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
`),
|
||||
|
||||
h(ReactCSSTransitionGroup, {
|
||||
transitionName: 'sidebar',
|
||||
transitionEnterTimeout: 300,
|
||||
transitionLeaveTimeout: 200,
|
||||
}, [
|
||||
// A second instance of Walletview is used for non-mobile viewports
|
||||
this.props.sidebarOpen ? h(WalletView, {
|
||||
responsiveDisplayClassname: '.sidebar',
|
||||
style: {},
|
||||
}) : undefined,
|
||||
|
||||
]),
|
||||
|
||||
// overlay
|
||||
// TODO: add onClick for overlay to close sidebar
|
||||
this.props.sidebarOpen ? h('div.sidebar-overlay', {
|
||||
style: {},
|
||||
onClick: () => {
|
||||
this.props.hideSidebar()
|
||||
},
|
||||
}, []) : undefined,
|
||||
])
|
||||
}
|
||||
|
||||
App.prototype.renderAppBar = function () {
|
||||
const {
|
||||
isUnlocked,
|
||||
network,
|
||||
provider,
|
||||
networkDropdownOpen,
|
||||
showNetworkDropdown,
|
||||
hideNetworkDropdown,
|
||||
currentView,
|
||||
isInitialized,
|
||||
betaUI,
|
||||
isPopup,
|
||||
welcomeScreenSeen,
|
||||
} = this.props
|
||||
|
||||
if (window.METAMASK_UI_TYPE === 'notification') {
|
||||
return null
|
||||
}
|
||||
|
||||
const props = this.props
|
||||
const {isMascara, isOnboarding} = props
|
||||
|
||||
// Do not render header if user is in mascara onboarding
|
||||
if (isMascara && isOnboarding) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Do not render header if user is in mascara buy ether
|
||||
if (isMascara && props.currentView.name === 'buyEth') {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
h('.full-width', {
|
||||
style: {},
|
||||
}, [
|
||||
|
||||
(isInitialized || welcomeScreenSeen || isPopup || !betaUI) && h('.app-header.flex-row.flex-space-between', {
|
||||
className: classnames({
|
||||
'app-header--initialized': !isOnboarding,
|
||||
}),
|
||||
}, [
|
||||
h('div.app-header-contents', {}, [
|
||||
h('div.left-menu-wrapper', {
|
||||
onClick: () => {
|
||||
props.dispatch(actions.backToAccountDetail(props.activeAddress))
|
||||
},
|
||||
}, [
|
||||
// mini logo
|
||||
h('img.metafox-icon', {
|
||||
height: 42,
|
||||
width: 42,
|
||||
src: './images/metamask-fox.svg',
|
||||
}),
|
||||
|
||||
// metamask name
|
||||
h('.flex-row', [
|
||||
h('h1', this.context.t('appName')),
|
||||
h('div.beta-label', this.context.t('beta')),
|
||||
]),
|
||||
]),
|
||||
|
||||
betaUI && isInitialized && h('div.header__right-actions', [
|
||||
h('div.network-component-wrapper', {
|
||||
style: {},
|
||||
}, [
|
||||
// Network Indicator
|
||||
h(NetworkIndicator, {
|
||||
network,
|
||||
provider,
|
||||
disabled: currentView.name === 'confTx',
|
||||
onClick: (event) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
return networkDropdownOpen === false
|
||||
? showNetworkDropdown()
|
||||
: hideNetworkDropdown()
|
||||
},
|
||||
}),
|
||||
|
||||
]),
|
||||
|
||||
isUnlocked && h('div.account-menu__icon', { onClick: this.props.toggleAccountMenu }, [
|
||||
h(Identicon, {
|
||||
address: this.props.selectedAddress,
|
||||
diameter: 32,
|
||||
}),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
|
||||
!isInitialized && !isPopup && betaUI && h('.alpha-warning__container', {}, [
|
||||
h('h2', {
|
||||
className: classnames({
|
||||
'alpha-warning': welcomeScreenSeen,
|
||||
'alpha-warning-welcome-screen': !welcomeScreenSeen,
|
||||
}),
|
||||
}, 'Please be aware that this version is still under development'),
|
||||
]),
|
||||
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
App.prototype.renderLoadingIndicator = function ({ isLoading, isLoadingNetwork, loadMessage }) {
|
||||
const { isMascara } = this.props
|
||||
|
||||
return isMascara
|
||||
? null
|
||||
: h(Loading, {
|
||||
isLoading: isLoading || isLoadingNetwork,
|
||||
loadingMessage: loadMessage,
|
||||
})
|
||||
}
|
||||
|
||||
App.prototype.renderBackButton = function (style, justArrow = false) {
|
||||
var props = this.props
|
||||
return (
|
||||
h('.flex-row', {
|
||||
key: 'leftArrow',
|
||||
style: style,
|
||||
onClick: () => props.dispatch(actions.goBackToInitView()),
|
||||
}, [
|
||||
h('i.fa.fa-arrow-left.cursor-pointer'),
|
||||
justArrow ? null : h('div.cursor-pointer', {
|
||||
style: {
|
||||
marginLeft: '3px',
|
||||
},
|
||||
onClick: () => props.dispatch(actions.goBackToInitView()),
|
||||
}, 'BACK'),
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
App.prototype.renderPrimary = function () {
|
||||
log.debug('rendering primary')
|
||||
var props = this.props
|
||||
const {
|
||||
isMascara,
|
||||
isOnboarding,
|
||||
betaUI,
|
||||
isRevealingSeedWords,
|
||||
welcomeScreenSeen,
|
||||
Qr,
|
||||
isInitialized,
|
||||
isUnlocked,
|
||||
} = props
|
||||
const isMascaraOnboarding = isMascara && isOnboarding
|
||||
const isBetaUIOnboarding = betaUI && isOnboarding
|
||||
|
||||
if (!welcomeScreenSeen && betaUI && !isInitialized && !isUnlocked) {
|
||||
return h(WelcomeScreen)
|
||||
}
|
||||
|
||||
if (isMascaraOnboarding || isBetaUIOnboarding) {
|
||||
return h(MascaraFirstTime)
|
||||
}
|
||||
|
||||
// notices
|
||||
if (!props.noActiveNotices && !betaUI) {
|
||||
log.debug('rendering notice screen for unread notices.')
|
||||
return h(NoticeScreen, {
|
||||
notice: props.lastUnreadNotice,
|
||||
key: 'NoticeScreen',
|
||||
onConfirm: () => props.dispatch(actions.markNoticeRead(props.lastUnreadNotice)),
|
||||
})
|
||||
} else if (props.lostAccounts && props.lostAccounts.length > 0) {
|
||||
log.debug('rendering notice screen for lost accounts view.')
|
||||
return h(NoticeScreen, {
|
||||
notice: generateLostAccountsNotice(props.lostAccounts),
|
||||
key: 'LostAccountsNotice',
|
||||
onConfirm: () => props.dispatch(actions.markAccountsFound()),
|
||||
})
|
||||
}
|
||||
|
||||
if (props.isInitialized && props.forgottenPassword) {
|
||||
log.debug('rendering restore vault screen')
|
||||
return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'})
|
||||
} else if (!props.isInitialized && !props.isUnlocked && !isRevealingSeedWords) {
|
||||
log.debug('rendering menu screen')
|
||||
return !betaUI
|
||||
? h(OldUIInitializeMenuScreen, {key: 'menuScreenInit'})
|
||||
: h(InitializeMenuScreen, {key: 'menuScreenInit'})
|
||||
}
|
||||
|
||||
// show unlock screen
|
||||
if (!props.isUnlocked) {
|
||||
return h(MainContainer, {
|
||||
currentViewName: props.currentView.name,
|
||||
isUnlocked: props.isUnlocked,
|
||||
})
|
||||
}
|
||||
|
||||
// show seed words screen
|
||||
if (props.seedWords) {
|
||||
log.debug('rendering seed words')
|
||||
return h(HDCreateVaultComplete, {key: 'HDCreateVaultComplete'})
|
||||
}
|
||||
|
||||
// show current view
|
||||
switch (props.currentView.name) {
|
||||
|
||||
case 'accountDetail':
|
||||
log.debug('rendering main container')
|
||||
return h(MainContainer, {key: 'account-detail'})
|
||||
|
||||
case 'sendTransaction':
|
||||
log.debug('rendering send tx screen')
|
||||
|
||||
// Going to leave this here until we are ready to delete SendTransactionScreen v1
|
||||
// const SendComponentToRender = checkFeatureToggle('send-v2')
|
||||
// ? SendTransactionScreen2
|
||||
// : SendTransactionScreen
|
||||
|
||||
return h(SendTransactionScreen2, {key: 'send-transaction'})
|
||||
|
||||
case 'sendToken':
|
||||
log.debug('rendering send token screen')
|
||||
|
||||
// Going to leave this here until we are ready to delete SendTransactionScreen v1
|
||||
// const SendTokenComponentToRender = checkFeatureToggle('send-v2')
|
||||
// ? SendTransactionScreen2
|
||||
// : SendTokenScreen
|
||||
|
||||
return h(SendTransactionScreen2, {key: 'sendToken'})
|
||||
|
||||
case 'newKeychain':
|
||||
log.debug('rendering new keychain screen')
|
||||
return h(NewKeyChainScreen, {key: 'new-keychain'})
|
||||
|
||||
case 'confTx':
|
||||
log.debug('rendering confirm tx screen')
|
||||
return h(ConfirmTxScreen, {key: 'confirm-tx'})
|
||||
|
||||
case 'add-token':
|
||||
log.debug('rendering add-token screen from unlock screen.')
|
||||
return h(AddTokenScreen, {key: 'add-token'})
|
||||
|
||||
case 'config':
|
||||
log.debug('rendering config screen')
|
||||
return h(Settings, {key: 'config'})
|
||||
|
||||
case 'import-menu':
|
||||
log.debug('rendering import screen')
|
||||
return h(Import, {key: 'import-menu'})
|
||||
|
||||
case 'new-account-page':
|
||||
log.debug('rendering new account screen')
|
||||
return h(NewAccount, {key: 'new-account'})
|
||||
|
||||
case 'reveal-seed-conf':
|
||||
log.debug('rendering reveal seed confirmation screen')
|
||||
return h(RevealSeedConfirmation, {key: 'reveal-seed-conf'})
|
||||
|
||||
case 'info':
|
||||
log.debug('rendering info screen')
|
||||
return h(Settings, {key: 'info', tab: 'info'})
|
||||
|
||||
case 'buyEth':
|
||||
log.debug('rendering buy ether screen')
|
||||
return h(BuyView, {key: 'buyEthView'})
|
||||
|
||||
case 'onboardingBuyEth':
|
||||
log.debug('rendering onboarding buy ether screen')
|
||||
return h(MascaraBuyEtherScreen, {key: 'buyEthView'})
|
||||
|
||||
case 'qr':
|
||||
log.debug('rendering show qr screen')
|
||||
return h('div', {
|
||||
style: {
|
||||
position: 'absolute',
|
||||
height: '100%',
|
||||
top: '0px',
|
||||
left: '0px',
|
||||
},
|
||||
}, [
|
||||
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', {
|
||||
onClick: () => props.dispatch(actions.backToAccountDetail(props.activeAddress)),
|
||||
style: {
|
||||
marginLeft: '10px',
|
||||
marginTop: '50px',
|
||||
},
|
||||
}),
|
||||
h('div', {
|
||||
style: {
|
||||
position: 'absolute',
|
||||
left: '44px',
|
||||
width: '285px',
|
||||
},
|
||||
}, [
|
||||
h(QrView, {key: 'qr', Qr}),
|
||||
]),
|
||||
])
|
||||
|
||||
default:
|
||||
log.debug('rendering default, account detail screen')
|
||||
return h(MainContainer, {key: 'account-detail'})
|
||||
}
|
||||
}
|
||||
|
||||
App.prototype.toggleMetamaskActive = function () {
|
||||
if (!this.props.isUnlocked) {
|
||||
// currently inactive: redirect to password box
|
||||
var passwordBox = document.querySelector('input[type=password]')
|
||||
if (!passwordBox) return
|
||||
passwordBox.focus()
|
||||
} else {
|
||||
// currently active: deactivate
|
||||
this.props.dispatch(actions.lockMetamask(false))
|
||||
}
|
||||
}
|
||||
|
||||
App.prototype.getConnectingLabel = function () {
|
||||
const { provider } = this.props
|
||||
const providerName = provider.type
|
||||
|
||||
let name
|
||||
|
||||
if (providerName === 'mainnet') {
|
||||
name = this.context.t('connectingToMainnet')
|
||||
} else if (providerName === 'ropsten') {
|
||||
name = this.context.t('connectingToRopsten')
|
||||
} else if (providerName === 'kovan') {
|
||||
name = this.context.t('connectingToRopsten')
|
||||
} else if (providerName === 'rinkeby') {
|
||||
name = this.context.t('connectingToRinkeby')
|
||||
} else {
|
||||
name = this.context.t('connectingToUnknown')
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
App.prototype.getNetworkName = function () {
|
||||
const { provider } = this.props
|
||||
const providerName = provider.type
|
||||
|
||||
let name
|
||||
|
||||
if (providerName === 'mainnet') {
|
||||
name = this.context.t('mainnet')
|
||||
} else if (providerName === 'ropsten') {
|
||||
name = this.context.t('ropsten')
|
||||
} else if (providerName === 'kovan') {
|
||||
name = this.context.t('kovan')
|
||||
} else if (providerName === 'rinkeby') {
|
||||
name = this.context.t('rinkeby')
|
||||
} else {
|
||||
name = this.context.t('unknownNetwork')
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
module.exports = compose(
|
||||
withRouter,
|
||||
connect(mapStateToProps, mapDispatchToProps)
|
||||
)(App)
|
||||
|
@ -7,8 +7,8 @@ const connect = require('react-redux').connect
|
||||
const Dropdown = require('./dropdown').Dropdown
|
||||
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
|
||||
const Identicon = require('./identicon')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const copyToClipboard = require('copy-to-clipboard')
|
||||
const { checksumAddress } = require('../util')
|
||||
|
||||
class AccountDropdowns extends Component {
|
||||
constructor (props) {
|
||||
@ -212,8 +212,7 @@ class AccountDropdowns extends Component {
|
||||
closeMenu: () => {},
|
||||
onClick: () => {
|
||||
const { selected } = this.props
|
||||
const checkSumAddress = selected && ethUtil.toChecksumAddress(selected)
|
||||
copyToClipboard(checkSumAddress)
|
||||
copyToClipboard(checksumAddress(selected))
|
||||
},
|
||||
},
|
||||
this.context.t('copyAddress'),
|
||||
|
@ -1,20 +1,31 @@
|
||||
const inherits = require('util').inherits
|
||||
const Component = require('react').Component
|
||||
const PropTypes = require('prop-types')
|
||||
const connect = require('react-redux').connect
|
||||
const { compose } = require('recompose')
|
||||
const { withRouter } = require('react-router-dom')
|
||||
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 { formatBalance } = require('../../util')
|
||||
const {
|
||||
SETTINGS_ROUTE,
|
||||
INFO_ROUTE,
|
||||
NEW_ACCOUNT_ROUTE,
|
||||
IMPORT_ACCOUNT_ROUTE,
|
||||
DEFAULT_ROUTE,
|
||||
} = require('../../routes')
|
||||
|
||||
module.exports = compose(
|
||||
withRouter,
|
||||
connect(mapStateToProps, mapDispatchToProps)
|
||||
)(AccountMenu)
|
||||
|
||||
AccountMenu.contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountMenu)
|
||||
|
||||
|
||||
inherits(AccountMenu, Component)
|
||||
function AccountMenu () { Component.call(this) }
|
||||
|
||||
@ -25,7 +36,6 @@ function mapStateToProps (state) {
|
||||
keyrings: state.metamask.keyrings,
|
||||
identities: state.metamask.identities,
|
||||
accounts: state.metamask.accounts,
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,11 +58,6 @@ function mapDispatchToProps (dispatch) {
|
||||
dispatch(actions.hideSidebar())
|
||||
dispatch(actions.toggleAccountMenu())
|
||||
},
|
||||
showNewAccountPage: (formToSelect) => {
|
||||
dispatch(actions.showNewAccountPage(formToSelect))
|
||||
dispatch(actions.hideSidebar())
|
||||
dispatch(actions.toggleAccountMenu())
|
||||
},
|
||||
showInfoPage: () => {
|
||||
dispatch(actions.showInfoPage())
|
||||
dispatch(actions.hideSidebar())
|
||||
@ -65,10 +70,8 @@ AccountMenu.prototype.render = function () {
|
||||
const {
|
||||
isAccountMenuOpen,
|
||||
toggleAccountMenu,
|
||||
showNewAccountPage,
|
||||
lockMetamask,
|
||||
showConfigPage,
|
||||
showInfoPage,
|
||||
history,
|
||||
} = this.props
|
||||
|
||||
return h(Menu, { className: 'account-menu', isShowing: isAccountMenuOpen }, [
|
||||
@ -78,30 +81,45 @@ AccountMenu.prototype.render = function () {
|
||||
}, [
|
||||
this.context.t('myAccounts'),
|
||||
h('button.account-menu__logout-button', {
|
||||
onClick: lockMetamask,
|
||||
onClick: () => {
|
||||
lockMetamask()
|
||||
history.push(DEFAULT_ROUTE)
|
||||
},
|
||||
}, this.context.t('logout')),
|
||||
]),
|
||||
h(Divider),
|
||||
h('div.account-menu__accounts', this.renderAccounts()),
|
||||
h(Divider),
|
||||
h(Item, {
|
||||
onClick: () => showNewAccountPage('CREATE'),
|
||||
onClick: () => {
|
||||
toggleAccountMenu()
|
||||
history.push(NEW_ACCOUNT_ROUTE)
|
||||
},
|
||||
icon: h('img.account-menu__item-icon', { src: 'images/plus-btn-white.svg' }),
|
||||
text: this.context.t('createAccount'),
|
||||
}),
|
||||
h(Item, {
|
||||
onClick: () => showNewAccountPage('IMPORT'),
|
||||
onClick: () => {
|
||||
toggleAccountMenu()
|
||||
history.push(IMPORT_ACCOUNT_ROUTE)
|
||||
},
|
||||
icon: h('img.account-menu__item-icon', { src: 'images/import-account.svg' }),
|
||||
text: this.context.t('importAccount'),
|
||||
}),
|
||||
h(Divider),
|
||||
h(Item, {
|
||||
onClick: showInfoPage,
|
||||
onClick: () => {
|
||||
toggleAccountMenu()
|
||||
history.push(INFO_ROUTE)
|
||||
},
|
||||
icon: h('img', { src: 'images/mm-info-icon.svg' }),
|
||||
text: this.context.t('infoHelp'),
|
||||
}),
|
||||
h(Item, {
|
||||
onClick: showConfigPage,
|
||||
onClick: () => {
|
||||
toggleAccountMenu()
|
||||
history.push(SETTINGS_ROUTE)
|
||||
},
|
||||
icon: h('img.account-menu__item-icon', { src: 'images/settings.svg' }),
|
||||
text: this.context.t('settings'),
|
||||
}),
|
||||
|
@ -4,6 +4,8 @@ const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const TokenBalance = require('./token-balance')
|
||||
const Identicon = require('./identicon')
|
||||
const currencyFormatter = require('currency-formatter')
|
||||
const currencies = require('currency-formatter/currencies')
|
||||
|
||||
const { formatBalance, generateBalanceObject } = require('../util')
|
||||
|
||||
@ -97,9 +99,17 @@ BalanceComponent.prototype.renderFiatAmount = function (fiatDisplayNumber, fiatS
|
||||
const shouldNotRenderFiat = fiatDisplayNumber === 'N/A' || Number(fiatDisplayNumber) === 0
|
||||
if (shouldNotRenderFiat) return null
|
||||
|
||||
const upperCaseFiatSuffix = fiatSuffix.toUpperCase()
|
||||
|
||||
const display = currencies.find(currency => currency.code === upperCaseFiatSuffix)
|
||||
? currencyFormatter.format(Number(fiatDisplayNumber), {
|
||||
code: upperCaseFiatSuffix,
|
||||
})
|
||||
: `${fiatPrefix}${fiatDisplayNumber} ${upperCaseFiatSuffix}`
|
||||
|
||||
return h('div.fiat-amount', {
|
||||
style: {},
|
||||
}, `${fiatPrefix}${fiatDisplayNumber} ${fiatSuffix}`)
|
||||
}, display)
|
||||
}
|
||||
|
||||
BalanceComponent.prototype.getTokenBalance = function (formattedBalance, shorten) {
|
||||
@ -117,5 +127,9 @@ BalanceComponent.prototype.getFiatDisplayNumber = function (formattedBalance, co
|
||||
|
||||
const splitBalance = formattedBalance.split(' ')
|
||||
|
||||
return (Number(splitBalance[0]) * conversionRate).toFixed(2)
|
||||
const convertedNumber = (Number(splitBalance[0]) * conversionRate)
|
||||
const wholePart = Math.floor(convertedNumber)
|
||||
const decimalPart = convertedNumber - wholePart
|
||||
|
||||
return wholePart + Number(decimalPart.toPrecision(2))
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ const connect = require('react-redux').connect
|
||||
const Dropdown = require('./dropdown').Dropdown
|
||||
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
|
||||
const Identicon = require('../../identicon')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const { checksumAddress } = require('../../../util')
|
||||
const copyToClipboard = require('copy-to-clipboard')
|
||||
const { formatBalance } = require('../../../util')
|
||||
|
||||
@ -311,8 +311,7 @@ class AccountDropdowns extends Component {
|
||||
closeMenu: () => {},
|
||||
onClick: () => {
|
||||
const { selected } = this.props
|
||||
const checkSumAddress = selected && ethUtil.toChecksumAddress(selected)
|
||||
copyToClipboard(checkSumAddress)
|
||||
copyToClipboard(checksumAddress(selected))
|
||||
},
|
||||
style: Object.assign(
|
||||
dropdownMenuItemStyle,
|
||||
|
@ -11,6 +11,7 @@ const ensRE = /.+\..+$/
|
||||
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
|
||||
const connect = require('react-redux').connect
|
||||
const ToAutoComplete = require('./send/to-autocomplete')
|
||||
const log = require('loglevel')
|
||||
|
||||
EnsInput.contextTypes = {
|
||||
t: PropTypes.func,
|
||||
|
@ -1,6 +1,7 @@
|
||||
const { Component } = require('react')
|
||||
const h = require('react-hyperscript')
|
||||
const PropTypes = require('prop-types')
|
||||
const classnames = require('classnames')
|
||||
|
||||
class LoadingIndicator extends Component {
|
||||
renderMessage () {
|
||||
@ -10,14 +11,16 @@ class LoadingIndicator extends Component {
|
||||
|
||||
render () {
|
||||
return (
|
||||
h('.full-flex-height.loading-overlay', {}, [
|
||||
h('img', {
|
||||
src: 'images/loading.svg',
|
||||
}),
|
||||
h('.loading-overlay', {
|
||||
className: classnames({ 'loading-overlay--full-screen': this.props.fullScreen }),
|
||||
}, [
|
||||
h('.flex-center.flex-column', [
|
||||
h('img', {
|
||||
src: 'images/loading.svg',
|
||||
}),
|
||||
|
||||
h('br'),
|
||||
|
||||
this.renderMessage(),
|
||||
this.renderMessage(),
|
||||
]),
|
||||
])
|
||||
)
|
||||
}
|
||||
@ -25,6 +28,7 @@ class LoadingIndicator extends Component {
|
||||
|
||||
LoadingIndicator.propTypes = {
|
||||
loadingMessage: PropTypes.string,
|
||||
fullScreen: PropTypes.bool,
|
||||
}
|
||||
|
||||
module.exports = LoadingIndicator
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user