aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/_locales/en/messages.json2
-rw-r--r--app/_locales/index.json1
-rw-r--r--app/_locales/tr/messages.json912
-rw-r--r--app/manifest.json2
-rw-r--r--app/scripts/background.js54
-rw-r--r--app/scripts/contentscript.js6
-rw-r--r--app/scripts/controllers/transactions.js60
-rw-r--r--app/scripts/lib/get-first-preferred-lang-code.js6
-rw-r--r--app/scripts/lib/getObjStructure.js33
-rw-r--r--app/scripts/lib/is-popup-or-notification.js3
-rw-r--r--app/scripts/lib/migrator/index.js27
-rw-r--r--app/scripts/lib/tx-gas-utils.js35
-rw-r--r--app/scripts/lib/tx-state-manager.js22
-rw-r--r--app/scripts/migrations/013.js7
-rw-r--r--app/scripts/migrations/015.js15
-rw-r--r--app/scripts/migrations/016.js22
-rw-r--r--app/scripts/migrations/017.js21
-rw-r--r--app/scripts/migrations/018.js39
-rw-r--r--app/scripts/migrations/019.js44
-rw-r--r--app/scripts/migrations/022.js17
-rw-r--r--app/scripts/migrations/023.js38
-rw-r--r--app/scripts/migrations/024.js41
-rw-r--r--app/scripts/migrations/025.js61
-rw-r--r--app/scripts/migrations/index.js2
-rw-r--r--app/scripts/migrations/template.js29
25 files changed, 1356 insertions, 143 deletions
diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index 34575b4dd..b372326ee 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -56,7 +56,7 @@
"message": "Balance:"
},
"balances": {
- "message": "Your balances"
+ "message": "Token balance(s)"
},
"balanceIsInsufficientGas": {
"message": "Insufficient balance for current gas total"
diff --git a/app/_locales/index.json b/app/_locales/index.json
index c085deb72..727504bda 100644
--- a/app/_locales/index.json
+++ b/app/_locales/index.json
@@ -13,6 +13,7 @@
{ "code": "ru", "name": "Russian" },
{ "code": "sl", "name": "Slovenian" },
{ "code": "th", "name": "Thai" },
+ { "code": "tr", "name": "Turkish" },
{ "code": "vi", "name": "Vietnamese" },
{ "code": "zh_CN", "name": "Mandarin" },
{ "code": "zh_TW", "name": "Taiwanese" }
diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json
new file mode 100644
index 000000000..c2c09bc91
--- /dev/null
+++ b/app/_locales/tr/messages.json
@@ -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"
+ }
+} \ No newline at end of file
diff --git a/app/manifest.json b/app/manifest.json
index 73496adfa..dc46f1ca4 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -1,7 +1,7 @@
{
"name": "__MSG_appName__",
"short_name": "__MSG_appName__",
- "version": "4.5.0",
+ "version": "4.5.5",
"manifest_version": 2,
"author": "https://metamask.io",
"description": "__MSG_appDescription__",
diff --git a/app/scripts/background.js b/app/scripts/background.js
index 3ad0a7863..5878cd2e8 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -20,6 +20,7 @@ const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry')
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 STORAGE_KEY = 'metamask-config'
const METAMASK_DEBUG = process.env.METAMASK_DEBUG
@@ -77,6 +78,38 @@ 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
+ const vaultStructure = getObjStructure(versionedData)
+ raven.captureException(err, {
+ // "extra" key is required by Sentry
+ extra: { vaultStructure },
+ })
+ })
+
// migrate data
versionedData = await migrator.migrateData(versionedData)
if (!versionedData) {
@@ -84,7 +117,14 @@ async function loadStateFromPersistence () {
}
// write to disk
- if (localStore.isSupported) localStore.set(versionedData)
+ if (localStore.isSupported) {
+ localStore.set(versionedData)
+ } else {
+ // throw in setTimeout so as to not block boot
+ setTimeout(() => {
+ throw new Error('MetaMask - Localstore not supported')
+ })
+ }
// return just the data
return versionedData.data
@@ -122,9 +162,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)
}
)
@@ -133,7 +173,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) => {
diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js
index 2098fae27..fe1766273 100644
--- a/app/scripts/contentscript.js
+++ b/app/scripts/contentscript.js
@@ -131,7 +131,11 @@ function documentElementCheck () {
}
function blacklistedDomainCheck () {
- var blacklistedDomains = ['uscourts.gov', 'dropbox.com']
+ var blacklistedDomains = [
+ 'uscourts.gov',
+ 'dropbox.com',
+ 'webbyawards.com',
+ ]
var currentUrl = window.location.href
var currentRegex
for (let i = 0; i < blacklistedDomains.length; i++) {
diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js
index 31e53554d..336b0d8f7 100644
--- a/app/scripts/controllers/transactions.js
+++ b/app/scripts/controllers/transactions.js
@@ -185,9 +185,10 @@ module.exports = class TransactionController extends EventEmitter {
async addUnapprovedTransaction (txParams) {
// validate
- await this.txGasUtil.validateTxParams(txParams)
+ const normalizedTxParams = this._normalizeTxParams(txParams)
+ this._validateTxParams(normalizedTxParams)
// construct txMeta
- let txMeta = this.txStateManager.generateTxMeta({txParams})
+ let txMeta = this.txStateManager.generateTxMeta({ txParams: normalizedTxParams })
this.addTx(txMeta)
this.emit('newUnapprovedTx', txMeta)
// add default tx params
@@ -215,7 +216,6 @@ module.exports = class TransactionController extends EventEmitter {
}
txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16))
txParams.value = txParams.value || '0x0'
- if (txParams.to === null) delete txParams.to
// set gasLimit
return await this.txGasUtil.analyzeGasUsage(txMeta)
}
@@ -314,6 +314,60 @@ module.exports = class TransactionController extends EventEmitter {
// 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
diff --git a/app/scripts/lib/get-first-preferred-lang-code.js b/app/scripts/lib/get-first-preferred-lang-code.js
index 28612f763..e3635434e 100644
--- a/app/scripts/lib/get-first-preferred-lang-code.js
+++ b/app/scripts/lib/get-first-preferred-lang-code.js
@@ -2,14 +2,16 @@ const extension = require('extensionizer')
const promisify = require('pify')
const allLocales = require('../../_locales/index.json')
-const existingLocaleCodes = allLocales.map(locale => locale.code)
+const existingLocaleCodes = allLocales.map(locale => locale.code.toLowerCase().replace('_', '-'))
async function getFirstPreferredLangCode () {
const userPreferredLocaleCodes = await promisify(
extension.i18n.getAcceptLanguages,
{ errorFirst: false }
)()
- const firstPreferredLangCode = userPreferredLocaleCodes.find(code => existingLocaleCodes.includes(code))
+ const firstPreferredLangCode = userPreferredLocaleCodes
+ .map(code => code.toLowerCase())
+ .find(code => existingLocaleCodes.includes(code))
return firstPreferredLangCode || 'en'
}
diff --git a/app/scripts/lib/getObjStructure.js b/app/scripts/lib/getObjStructure.js
new file mode 100644
index 000000000..3db389507
--- /dev/null
+++ b/app/scripts/lib/getObjStructure.js
@@ -0,0 +1,33 @@
+const clone = require('clone')
+
+module.exports = getObjStructure
+
+// This will create an object that represents the structure of the given object
+// it replaces all values with the result of their type
+
+// {
+// "data": {
+// "CurrencyController": {
+// "conversionDate": "number",
+// "conversionRate": "number",
+// "currentCurrency": "string"
+// }
+// }
+
+function getObjStructure(obj) {
+ const structure = clone(obj)
+ return deepMap(structure, (value) => {
+ return value === null ? 'null' : typeof value
+ })
+}
+
+function deepMap(target = {}, visit) {
+ Object.entries(target).forEach(([key, value]) => {
+ if (typeof value === 'object' && value !== null) {
+ target[key] = deepMap(value, visit)
+ } else {
+ target[key] = visit(value)
+ }
+ })
+ return target
+}
diff --git a/app/scripts/lib/is-popup-or-notification.js b/app/scripts/lib/is-popup-or-notification.js
index e2999411f..ad3e825c0 100644
--- a/app/scripts/lib/is-popup-or-notification.js
+++ b/app/scripts/lib/is-popup-or-notification.js
@@ -3,7 +3,8 @@ module.exports = function isPopupOrNotification () {
// 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(?:\?.+)*$/)) {
+ if (url.match(/popup.html(?:\?.+)*$/) ||
+ url.match(/home.html(?:\?.+)*$/) || url.match(/home.html(?:#.*)*$/)) {
return 'popup'
} else {
return 'notification'
diff --git a/app/scripts/lib/migrator/index.js b/app/scripts/lib/migrator/index.js
index 4fd2cae92..85c2717ea 100644
--- a/app/scripts/lib/migrator/index.js
+++ b/app/scripts/lib/migrator/index.js
@@ -1,6 +1,9 @@
-class Migrator {
+const EventEmitter = require('events')
+
+class Migrator extends EventEmitter {
constructor (opts = {}) {
+ super()
const migrations = opts.migrations || []
// sort migrations by version
this.migrations = migrations.sort((a, b) => a.version - b.version)
@@ -12,13 +15,29 @@ class Migrator {
// run all pending migrations on meta in place
async migrateData (versionedData = this.generateInitialState()) {
+ // get all migrations that have not yet been run
const pendingMigrations = this.migrations.filter(migrationIsPending)
+ // perform each migration
for (const index in pendingMigrations) {
const migration = pendingMigrations[index]
- versionedData = await migration.migrate(versionedData)
- if (!versionedData.data) throw new Error('Migrator - migration returned empty data')
- if (versionedData.version !== undefined && versionedData.meta.version !== migration.version) throw new Error('Migrator - Migration did not update version number correctly')
+ try {
+ // attempt migration and validate
+ const migratedData = await migration.migrate(versionedData)
+ if (!migratedData.data) throw new Error('Migrator - migration returned empty data')
+ if (migratedData.version !== undefined && migratedData.meta.version !== migration.version) throw new Error('Migrator - Migration did not update version number correctly')
+ // accept the migration as good
+ versionedData = migratedData
+ } catch (err) {
+ // rewrite error message to add context without clobbering stack
+ const originalErrorMessage = err.message
+ err.message = `MetaMask Migration Error #${migration.version}: ${originalErrorMessage}`
+ console.warn(err.stack)
+ // emit error instead of throw so as to not break the run (gracefully fail)
+ this.emit('error', err)
+ // stop migrating and use state as is
+ return versionedData
+ }
}
return versionedData
diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js
index 829b4c421..c579e462a 100644
--- a/app/scripts/lib/tx-gas-utils.js
+++ b/app/scripts/lib/tx-gas-utils.js
@@ -4,7 +4,7 @@ const {
BnMultiplyByFraction,
bnToHex,
} = require('./util')
-const { addHexPrefix, isValidAddress } = require('ethereumjs-util')
+const { addHexPrefix } = require('ethereumjs-util')
const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send.
/*
@@ -100,37 +100,4 @@ module.exports = class TxGasUtil {
// otherwise use blockGasLimit
return bnToHex(upperGasLimitBn)
}
-
- async 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 (!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 && !isValidAddress(txParams.to) ) {
- throw new Error('Invalid recipient address')
- }
- return txParams
- }
} \ No newline at end of file
diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js
index 23c915a61..c6d10ee62 100644
--- a/app/scripts/lib/tx-state-manager.js
+++ b/app/scripts/lib/tx-state-manager.js
@@ -92,8 +92,10 @@ module.exports = class TransactionStateManager extends EventEmitter {
// or rejected tx's.
// not tx's that are pending or unapproved
if (txCount > txHistoryLimit - 1) {
- const index = transactions.findIndex((metaTx) => metaTx.status === 'confirmed' || metaTx.status === 'rejected')
- transactions.splice(index, 1)
+ let index = transactions.findIndex((metaTx) => metaTx.status === 'confirmed' || metaTx.status === 'rejected')
+ if (index !== -1) {
+ transactions.splice(index, 1)
+ }
}
transactions.push(txMeta)
this._saveTxList(transactions)
@@ -108,6 +110,10 @@ module.exports = class TransactionStateManager extends EventEmitter {
updateTx (txMeta, note) {
// validate txParams
if (txMeta.txParams) {
+ if (typeof txMeta.txParams.data === 'undefined') {
+ delete txMeta.txParams.data
+ }
+
this.validateTxParams(txMeta.txParams)
}
@@ -140,8 +146,16 @@ module.exports = class TransactionStateManager extends EventEmitter {
validateTxParams(txParams) {
Object.keys(txParams).forEach((key) => {
const value = txParams[key]
- if (typeof value !== 'string') throw new Error(`${key}: ${value} in txParams is not a string`)
- if (!ethUtil.isHexPrefixed(value)) throw new Error('is not hex prefixed, everything on txParams must be hex prefixed')
+ // validate types
+ switch (key) {
+ case 'chainId':
+ if (typeof value !== 'number' && typeof value !== 'string') throw new Error(`${key} in txParams is not a Number or hex string. got: (${value})`)
+ break
+ default:
+ if (typeof value !== 'string') throw new Error(`${key} in txParams is not a string. got: (${value})`)
+ if (!ethUtil.isHexPrefixed(value)) throw new Error(`${key} in txParams is not hex prefixed. got: (${value})`)
+ break
+ }
})
}
diff --git a/app/scripts/migrations/013.js b/app/scripts/migrations/013.js
index 8f11e510e..15a9b28d4 100644
--- a/app/scripts/migrations/013.js
+++ b/app/scripts/migrations/013.js
@@ -27,8 +27,11 @@ module.exports = {
function transformState (state) {
const newState = state
- if (newState.config.provider.type === 'testnet') {
- newState.config.provider.type = 'ropsten'
+ const { config } = newState
+ if ( config && config.provider ) {
+ if (config.provider.type === 'testnet') {
+ newState.config.provider.type = 'ropsten'
+ }
}
return newState
}
diff --git a/app/scripts/migrations/015.js b/app/scripts/migrations/015.js
index 4b839580b..5e2f9e63b 100644
--- a/app/scripts/migrations/015.js
+++ b/app/scripts/migrations/015.js
@@ -28,11 +28,14 @@ module.exports = {
function transformState (state) {
const newState = state
- const transactions = newState.TransactionController.transactions
- newState.TransactionController.transactions = transactions.map((txMeta) => {
- if (!txMeta.err) return txMeta
- else if (txMeta.err.message === 'Gave up submitting tx.') txMeta.status = 'failed'
- return txMeta
- })
+ const { TransactionController } = newState
+ if (TransactionController && TransactionController.transactions) {
+ const transactions = TransactionController.transactions
+ newState.TransactionController.transactions = transactions.map((txMeta) => {
+ if (!txMeta.err) return txMeta
+ else if (txMeta.err.message === 'Gave up submitting tx.') txMeta.status = 'failed'
+ return txMeta
+ })
+ }
return newState
}
diff --git a/app/scripts/migrations/016.js b/app/scripts/migrations/016.js
index 4fc534f1c..048c7a40e 100644
--- a/app/scripts/migrations/016.js
+++ b/app/scripts/migrations/016.js
@@ -28,14 +28,18 @@ module.exports = {
function transformState (state) {
const newState = state
- const transactions = newState.TransactionController.transactions
- newState.TransactionController.transactions = transactions.map((txMeta) => {
- if (!txMeta.err) return txMeta
- if (txMeta.err === 'transaction with the same hash was already imported.') {
- txMeta.status = 'submitted'
- delete txMeta.err
- }
- return txMeta
- })
+ const { TransactionController } = newState
+ if (TransactionController && TransactionController.transactions) {
+ const transactions = newState.TransactionController.transactions
+
+ newState.TransactionController.transactions = transactions.map((txMeta) => {
+ if (!txMeta.err) return txMeta
+ if (txMeta.err === 'transaction with the same hash was already imported.') {
+ txMeta.status = 'submitted'
+ delete txMeta.err
+ }
+ return txMeta
+ })
+ }
return newState
}
diff --git a/app/scripts/migrations/017.js b/app/scripts/migrations/017.js
index 24959cd3a..5f6d906d6 100644
--- a/app/scripts/migrations/017.js
+++ b/app/scripts/migrations/017.js
@@ -27,14 +27,17 @@ module.exports = {
function transformState (state) {
const newState = state
- const transactions = newState.TransactionController.transactions
- newState.TransactionController.transactions = transactions.map((txMeta) => {
- if (!txMeta.status === 'failed') return txMeta
- if (txMeta.retryCount > 0 && txMeta.retryCount < 2) {
- txMeta.status = 'submitted'
- delete txMeta.err
- }
- return txMeta
- })
+ const { TransactionController } = newState
+ if (TransactionController && TransactionController.transactions) {
+ const transactions = newState.TransactionController.transactions
+ newState.TransactionController.transactions = transactions.map((txMeta) => {
+ if (!txMeta.status === 'failed') return txMeta
+ if (txMeta.retryCount > 0 && txMeta.retryCount < 2) {
+ txMeta.status = 'submitted'
+ delete txMeta.err
+ }
+ return txMeta
+ })
+ }
return newState
}
diff --git a/app/scripts/migrations/018.js b/app/scripts/migrations/018.js
index d27fe3f46..bea1fe3da 100644
--- a/app/scripts/migrations/018.js
+++ b/app/scripts/migrations/018.js
@@ -29,24 +29,27 @@ module.exports = {
function transformState (state) {
const newState = state
- const transactions = newState.TransactionController.transactions
- newState.TransactionController.transactions = transactions.map((txMeta) => {
- // no history: initialize
- if (!txMeta.history || txMeta.history.length === 0) {
- const snapshot = txStateHistoryHelper.snapshotFromTxMeta(txMeta)
- txMeta.history = [snapshot]
+ const { TransactionController } = newState
+ if (TransactionController && TransactionController.transactions) {
+ const transactions = newState.TransactionController.transactions
+ newState.TransactionController.transactions = transactions.map((txMeta) => {
+ // no history: initialize
+ if (!txMeta.history || txMeta.history.length === 0) {
+ const snapshot = txStateHistoryHelper.snapshotFromTxMeta(txMeta)
+ txMeta.history = [snapshot]
+ return txMeta
+ }
+ // has history: migrate
+ const newHistory = (
+ txStateHistoryHelper.migrateFromSnapshotsToDiffs(txMeta.history)
+ // remove empty diffs
+ .filter((entry) => {
+ return !Array.isArray(entry) || entry.length > 0
+ })
+ )
+ txMeta.history = newHistory
return txMeta
- }
- // has history: migrate
- const newHistory = (
- txStateHistoryHelper.migrateFromSnapshotsToDiffs(txMeta.history)
- // remove empty diffs
- .filter((entry) => {
- return !Array.isArray(entry) || entry.length > 0
- })
- )
- txMeta.history = newHistory
- return txMeta
- })
+ })
+ }
return newState
}
diff --git a/app/scripts/migrations/019.js b/app/scripts/migrations/019.js
index 072c96370..ce5da6859 100644
--- a/app/scripts/migrations/019.js
+++ b/app/scripts/migrations/019.js
@@ -29,32 +29,36 @@ module.exports = {
function transformState (state) {
const newState = state
- const transactions = newState.TransactionController.transactions
+ const { TransactionController } = newState
+ if (TransactionController && TransactionController.transactions) {
- newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => {
- if (txMeta.status !== 'submitted') return txMeta
+ const transactions = newState.TransactionController.transactions
- const confirmedTxs = txList.filter((tx) => tx.status === 'confirmed')
- .filter((tx) => tx.txParams.from === txMeta.txParams.from)
- .filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
- const highestConfirmedNonce = getHighestNonce(confirmedTxs)
+ newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => {
+ if (txMeta.status !== 'submitted') return txMeta
- const pendingTxs = txList.filter((tx) => tx.status === 'submitted')
- .filter((tx) => tx.txParams.from === txMeta.txParams.from)
- .filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
- const highestContinuousNonce = getHighestContinuousFrom(pendingTxs, highestConfirmedNonce)
+ const confirmedTxs = txList.filter((tx) => tx.status === 'confirmed')
+ .filter((tx) => tx.txParams.from === txMeta.txParams.from)
+ .filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
+ const highestConfirmedNonce = getHighestNonce(confirmedTxs)
- const maxNonce = Math.max(highestContinuousNonce, highestConfirmedNonce)
+ const pendingTxs = txList.filter((tx) => tx.status === 'submitted')
+ .filter((tx) => tx.txParams.from === txMeta.txParams.from)
+ .filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
+ const highestContinuousNonce = getHighestContinuousFrom(pendingTxs, highestConfirmedNonce)
- if (parseInt(txMeta.txParams.nonce, 16) > maxNonce + 1) {
- txMeta.status = 'failed'
- txMeta.err = {
- message: 'nonce too high',
- note: 'migration 019 custom error',
+ const maxNonce = Math.max(highestContinuousNonce, highestConfirmedNonce)
+
+ if (parseInt(txMeta.txParams.nonce, 16) > maxNonce + 1) {
+ txMeta.status = 'failed'
+ txMeta.err = {
+ message: 'nonce too high',
+ note: 'migration 019 custom error',
+ }
}
- }
- return txMeta
- })
+ return txMeta
+ })
+ }
return newState
}
diff --git a/app/scripts/migrations/022.js b/app/scripts/migrations/022.js
index c3c0d53ef..1fbe241e6 100644
--- a/app/scripts/migrations/022.js
+++ b/app/scripts/migrations/022.js
@@ -28,12 +28,15 @@ module.exports = {
function transformState (state) {
const newState = state
- const transactions = newState.TransactionController.transactions
-
- newState.TransactionController.transactions = transactions.map((txMeta) => {
- if (txMeta.status !== 'submitted' || txMeta.submittedTime) return txMeta
- txMeta.submittedTime = (new Date()).getTime()
- return txMeta
- })
+ const { TransactionController } = newState
+ if (TransactionController && TransactionController.transactions) {
+ const transactions = newState.TransactionController.transactions
+
+ newState.TransactionController.transactions = transactions.map((txMeta) => {
+ if (txMeta.status !== 'submitted' || txMeta.submittedTime) return txMeta
+ txMeta.submittedTime = (new Date()).getTime()
+ return txMeta
+ })
+ }
return newState
}
diff --git a/app/scripts/migrations/023.js b/app/scripts/migrations/023.js
index bce0a5bea..151496b06 100644
--- a/app/scripts/migrations/023.js
+++ b/app/scripts/migrations/023.js
@@ -28,23 +28,27 @@ module.exports = {
function transformState (state) {
const newState = state
- const transactions = newState.TransactionController.transactions
-
- if (transactions.length <= 40) return newState
-
- let reverseTxList = transactions.reverse()
- let stripping = true
- while (reverseTxList.length > 40 && stripping) {
- let txIndex = reverseTxList.findIndex((txMeta) => {
- return (txMeta.status === 'failed' ||
- txMeta.status === 'rejected' ||
- txMeta.status === 'confirmed' ||
- txMeta.status === 'dropped')
- })
- if (txIndex < 0) stripping = false
- else reverseTxList.splice(txIndex, 1)
- }
- newState.TransactionController.transactions = reverseTxList.reverse()
+ const { TransactionController } = newState
+ if (TransactionController && TransactionController.transactions) {
+ const transactions = newState.TransactionController.transactions
+
+ if (transactions.length <= 40) return newState
+
+ let reverseTxList = transactions.reverse()
+ let stripping = true
+ while (reverseTxList.length > 40 && stripping) {
+ let txIndex = reverseTxList.findIndex((txMeta) => {
+ return (txMeta.status === 'failed' ||
+ txMeta.status === 'rejected' ||
+ txMeta.status === 'confirmed' ||
+ txMeta.status === 'dropped')
+ })
+ if (txIndex < 0) stripping = false
+ else reverseTxList.splice(txIndex, 1)
+ }
+
+ newState.TransactionController.transactions = reverseTxList.reverse()
+ }
return newState
}
diff --git a/app/scripts/migrations/024.js b/app/scripts/migrations/024.js
new file mode 100644
index 000000000..d0b276a79
--- /dev/null
+++ b/app/scripts/migrations/024.js
@@ -0,0 +1,41 @@
+
+const version = 24
+
+/*
+
+This migration ensures that the from address in txParams is to lower case for
+all unapproved transactions
+
+*/
+
+const clone = require('clone')
+
+module.exports = {
+ version,
+
+ migrate: async function (originalVersionedData) {
+ const versionedData = clone(originalVersionedData)
+ versionedData.meta.version = version
+ const state = versionedData.data
+ const newState = transformState(state)
+ versionedData.data = newState
+ return versionedData
+ },
+}
+
+function transformState (state) {
+ const newState = state
+ if (!newState.TransactionController) return newState
+ const transactions = newState.TransactionController.transactions
+ newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => {
+ if (
+ txMeta.status === 'unapproved' &&
+ txMeta.txParams &&
+ txMeta.txParams.from
+ ) {
+ txMeta.txParams.from = txMeta.txParams.from.toLowerCase()
+ }
+ return txMeta
+ })
+ return newState
+}
diff --git a/app/scripts/migrations/025.js b/app/scripts/migrations/025.js
new file mode 100644
index 000000000..fc3b20a44
--- /dev/null
+++ b/app/scripts/migrations/025.js
@@ -0,0 +1,61 @@
+// next version number
+const version = 25
+
+/*
+
+normalizes txParams on unconfirmed txs
+
+*/
+const ethUtil = require('ethereumjs-util')
+const clone = require('clone')
+
+module.exports = {
+ version,
+
+ migrate: async function (originalVersionedData) {
+ const versionedData = clone(originalVersionedData)
+ versionedData.meta.version = version
+ const state = versionedData.data
+ const newState = transformState(state)
+ versionedData.data = newState
+ return versionedData
+ },
+}
+
+function transformState (state) {
+ const newState = state
+
+ if (newState.TransactionController) {
+ if (newState.TransactionController.transactions) {
+ const transactions = newState.TransactionController.transactions
+ newState.TransactionController.transactions = transactions.map((txMeta) => {
+ if (txMeta.status !== 'unapproved') return txMeta
+ txMeta.txParams = normalizeTxParams(txMeta.txParams)
+ return txMeta
+ })
+ }
+ }
+
+ return newState
+}
+
+function 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
+}
diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js
index 811e06b6b..6c4a51b32 100644
--- a/app/scripts/migrations/index.js
+++ b/app/scripts/migrations/index.js
@@ -34,4 +34,6 @@ module.exports = [
require('./021'),
require('./022'),
require('./023'),
+ require('./024'),
+ require('./025'),
]
diff --git a/app/scripts/migrations/template.js b/app/scripts/migrations/template.js
new file mode 100644
index 000000000..0915c6bdf
--- /dev/null
+++ b/app/scripts/migrations/template.js
@@ -0,0 +1,29 @@
+// next version number
+const version = 0
+
+/*
+
+description of migration and what it does
+
+*/
+
+const clone = require('clone')
+
+module.exports = {
+ version,
+
+ migrate: async function (originalVersionedData) {
+ const versionedData = clone(originalVersionedData)
+ versionedData.meta.version = version
+ const state = versionedData.data
+ const newState = transformState(state)
+ versionedData.data = newState
+ return versionedData
+ },
+}
+
+function transformState (state) {
+ const newState = state
+ // transform state here
+ return newState
+}