|
|
@ -4,6 +4,7 @@ import ( |
|
|
|
"encoding/json" |
|
|
|
"errors" |
|
|
|
"fmt" |
|
|
|
"io" |
|
|
|
"io/ioutil" |
|
|
|
"net/http" |
|
|
|
"os" |
|
|
@ -15,7 +16,7 @@ import ( |
|
|
|
"github.com/grvlle/constellation_wallet/backend/models" |
|
|
|
) |
|
|
|
|
|
|
|
// ImportWallet is triggered when a user logs into a new Molly wallet for the first time
|
|
|
|
// ImportWallet 在用户首次登录新的 Molly 钱包时触发
|
|
|
|
func (a *WalletApplication) ImportWallet(keystorePath, keystorePassword, keyPassword, alias string) bool { |
|
|
|
|
|
|
|
alias = strings.ToLower(alias) |
|
|
@ -25,7 +26,7 @@ func (a *WalletApplication) ImportWallet(keystorePath, keystorePassword, keyPass |
|
|
|
Currency: "USD"} |
|
|
|
|
|
|
|
if runtime.GOOS == "windows" && !a.javaInstalled() { |
|
|
|
a.LoginError("Unable to detect your Java path. Please make sure that Java has been installed.") |
|
|
|
a.LoginError("无法检测到 Java 路径。请确保已安装 Java。") |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
@ -36,12 +37,12 @@ func (a *WalletApplication) ImportWallet(keystorePath, keystorePassword, keyPass |
|
|
|
} |
|
|
|
|
|
|
|
if keystorePath == "" { |
|
|
|
a.LoginError("Please provide a path to the KeyStore file.") |
|
|
|
a.LoginError("请提供 KeyStore 文件的路径。") |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
if !a.passwordsProvided(keystorePassword, keyPassword, alias) { |
|
|
|
a.log.Warnln("One or more passwords were not provided.") |
|
|
|
a.log.Warnln("未提供一个或多个密码。") |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
@ -55,21 +56,21 @@ func (a *WalletApplication) ImportWallet(keystorePath, keystorePassword, keyPass |
|
|
|
if !a.DB.NewRecord(&a.wallet) { |
|
|
|
keystorePasswordHashed, err := a.GenerateSaltedHash(keystorePassword) |
|
|
|
if err != nil { |
|
|
|
a.log.Errorln("Unable to generate password hash. Reason: ", err) |
|
|
|
a.LoginError("Unable to generate password hash.") |
|
|
|
a.log.Errorln("无法生成密码哈希。原因: ", err) |
|
|
|
a.LoginError("无法生成密码哈希。") |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
keyPasswordHashed, err := a.GenerateSaltedHash(keyPassword) |
|
|
|
if err != nil { |
|
|
|
a.log.Errorln("Unable to generate password hash. Reason: ", err) |
|
|
|
a.LoginError("Unable to generate password hash.") |
|
|
|
a.log.Errorln("无法生成密码哈希。原因: ", err) |
|
|
|
a.LoginError("无法生成密码哈希。") |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
if err := a.DB.Create(&a.wallet).Error; err != nil { |
|
|
|
a.log.Errorln("Unable to create database object for the imported wallet. Reason: ", err) |
|
|
|
a.LoginError("Unable to create database object for the imported wallet. Maybe it has already been imported? Try to login.") |
|
|
|
a.log.Errorln("无法为导入的 wallet 创建数据库对象。原因: ", err) |
|
|
|
a.LoginError("无法为导入的 wallet 创建数据库对象。也许它已经被导入了?尝试登录。") |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
@ -79,18 +80,18 @@ func (a *WalletApplication) ImportWallet(keystorePath, keystorePassword, keyPass |
|
|
|
|
|
|
|
err = a.createTXFiles() |
|
|
|
if err != nil { |
|
|
|
a.log.Fatalln("Unable to create TX files. Check fs permissions. Reason: ", err) |
|
|
|
a.sendError("Unable to create TX files. Check fs permissions. Reason: ", err) |
|
|
|
a.log.Fatalln("无法创建 TX 文件。检查 fs 权限。原因: ", err) |
|
|
|
a.sendError("无法创建 TX 文件。检查 fs 权限。原因: ", err) |
|
|
|
} |
|
|
|
|
|
|
|
if err := a.DB.Model(&a.wallet).Where("wallet_alias = ?", a.wallet.WalletAlias).Update("Path", models.Path{LastTXFile: a.paths.LastTXFile, PrevTXFile: a.paths.PrevTXFile, EmptyTXFile: a.paths.EmptyTXFile}).Error; err != nil { |
|
|
|
a.log.Errorln("Unable to update the DB record with the tmp tx-paths. Reason: ", err) |
|
|
|
a.sendError("Unable to update the DB record with the tmp tx-paths. Reason: ", err) |
|
|
|
a.log.Errorln("无法使用 tmp tx-paths 更新数据库记录。原因: ", err) |
|
|
|
a.sendError("无法使用 tmp tx-paths 更新数据库记录。原因: ", err) |
|
|
|
} |
|
|
|
|
|
|
|
if err := a.DB.Where("wallet_alias = ?", a.wallet.WalletAlias).First(&a.wallet).Updates(&models.Wallet{KeyStorePath: keystorePath, KeystorePasswordHash: keystorePasswordHashed, KeyPasswordHash: keyPasswordHashed}).Error; err != nil { |
|
|
|
a.log.Errorln("Unable to query database object for the imported wallet. Reason: ", err) |
|
|
|
a.LoginError("Unable to query database object for the imported wallet.") |
|
|
|
a.log.Errorln("无法查询导入的 wallet 的数据库对象。原因: ", err) |
|
|
|
a.LoginError("无法查询导入的 wallet 的数据库对象。") |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
@ -99,10 +100,10 @@ func (a *WalletApplication) ImportWallet(keystorePath, keystorePassword, keyPass |
|
|
|
a.WalletImported = true |
|
|
|
err = a.initWallet(keystorePath) |
|
|
|
if err != nil { |
|
|
|
a.log.Errorln("Failed to initialize wallet. Reason: ", err) |
|
|
|
// If unable to import previous transactions, remove wallet from DB and logout.
|
|
|
|
a.log.Errorln("初始化 wallet 失败。原因: ", err) |
|
|
|
// 如果无法导入以前的交易,请从 DB 中删除钱包并注销。
|
|
|
|
if err := a.DB.Model(&a.wallet).Where("wallet_alias = ?", a.wallet.WalletAlias).Delete(&a.wallet).Error; err != nil { |
|
|
|
a.log.Errorln("Unable to delete wallet upon failed import. Reason: ", err) |
|
|
|
a.log.Errorln("导入失败时无法删除 wallet。原因: ", err) |
|
|
|
return false |
|
|
|
} |
|
|
|
return false |
|
|
@ -110,7 +111,7 @@ func (a *WalletApplication) ImportWallet(keystorePath, keystorePassword, keyPass |
|
|
|
|
|
|
|
return true |
|
|
|
|
|
|
|
} else if a.DB.NewRecord(&a.wallet) { // There may already be an existing DB record in some circumstances.
|
|
|
|
} else if a.DB.NewRecord(&a.wallet) { // 在某些情况下,可能已经存在 DB 记录。
|
|
|
|
a.DB.First(&a.wallet) |
|
|
|
|
|
|
|
a.UserLoggedIn = false |
|
|
@ -118,7 +119,7 @@ func (a *WalletApplication) ImportWallet(keystorePath, keystorePassword, keyPass |
|
|
|
a.WalletImported = true |
|
|
|
err := a.initWallet(a.wallet.KeyStorePath) |
|
|
|
if err != nil { |
|
|
|
a.log.Errorln("Faled to initialize wallet. Reason: ", err) |
|
|
|
a.log.Errorln("初始化 wallet。原因: ", err) |
|
|
|
return false |
|
|
|
} |
|
|
|
return true |
|
|
@ -128,29 +129,29 @@ func (a *WalletApplication) ImportWallet(keystorePath, keystorePassword, keyPass |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
// CreateWallet is called when creating a new wallet in frontend component Login.vue
|
|
|
|
// CreateWallet 在前端组件 Login.vue 中创建新钱包时调用
|
|
|
|
func (a *WalletApplication) CreateWallet(keystorePath, keystorePassword, keyPassword, alias, label string) bool { |
|
|
|
|
|
|
|
alias = strings.ToLower(alias) |
|
|
|
|
|
|
|
if runtime.GOOS == "windows" && !a.javaInstalled() { |
|
|
|
a.LoginError("Unable to detect your Java path. Please make sure that Java has been installed.") |
|
|
|
a.LoginError("无法检测到 Java 路径。请确保已安装 Java。") |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
if !a.TransactionFinished { |
|
|
|
a.log.Warn("Cannot Create wallet in a pending transaction.") |
|
|
|
a.LoginError("Cannot create a new wallet while there's a pending transaction.") |
|
|
|
a.log.Warn("无法在待处理交易中创建钱包。") |
|
|
|
a.LoginError("当有待处理交易时,无法创建新钱包。") |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
if keystorePath == "" { |
|
|
|
a.LoginError("Please provide a path to store the KeyStore file.") |
|
|
|
a.LoginError("请提供用于存储 KeyStore 文件的路径。") |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
if !a.passwordsProvided(keystorePassword, keyPassword, alias) { |
|
|
|
a.log.Warnln("One or more passwords were not provided.") |
|
|
|
a.log.Warnln("未提供一个或多个密码。") |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
@ -163,15 +164,15 @@ func (a *WalletApplication) CreateWallet(keystorePath, keystorePassword, keyPass |
|
|
|
|
|
|
|
keystorePasswordHashed, err := a.GenerateSaltedHash(keystorePassword) |
|
|
|
if err != nil { |
|
|
|
a.log.Errorln("Unable to generate password hash. Reason: ", err) |
|
|
|
a.sendError("Unable to generate password hash. Reason: ", err) |
|
|
|
a.log.Errorln("无法生成密码哈希。原因: ", err) |
|
|
|
a.sendError("无法生成密码哈希。原因: ", err) |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
keyPasswordHashed, err := a.GenerateSaltedHash(keyPassword) |
|
|
|
if err != nil { |
|
|
|
a.log.Errorln("Unable to generate password hash. Reason: ", err) |
|
|
|
a.sendError("Unable to generate password hash. Reason: ", err) |
|
|
|
a.log.Errorln("无法生成密码哈希。原因: ", err) |
|
|
|
a.sendError("无法生成密码哈希。原因: ", err) |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
@ -184,14 +185,14 @@ func (a *WalletApplication) CreateWallet(keystorePath, keystorePassword, keyPass |
|
|
|
|
|
|
|
if !a.DB.NewRecord(&a.wallet) { |
|
|
|
if err := a.DB.Create(&a.wallet).Error; err != nil { |
|
|
|
a.log.Errorln("Unable to create database object for new wallet. Reason: ", err) |
|
|
|
a.LoginError("Unable to create new wallet. Alias already exists.") |
|
|
|
a.log.Errorln("无法为新钱包创建数据库对象。原因: ", err) |
|
|
|
a.LoginError("无法创建新钱包。别名 已存在。") |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
if err := a.DB.Where("wallet_alias = ?", alias).First(&a.wallet).Updates(&models.Wallet{KeyStorePath: keystorePath, KeystorePasswordHash: keystorePasswordHashed, KeyPasswordHash: keyPasswordHashed}).Error; err != nil { |
|
|
|
a.log.Errorln("Unable to query database object for new wallet after wallet creation. Reason: ", err) |
|
|
|
a.sendError("Unable to query database object for new wallet after wallet creation. Reason: ", err) |
|
|
|
a.log.Errorln("创建钱包后,无法查询新钱包的数据库对象。原因: ", err) |
|
|
|
a.sendError("创建钱包后,无法查询新钱包的数据库对象。原因: ", err) |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
@ -203,8 +204,8 @@ func (a *WalletApplication) CreateWallet(keystorePath, keystorePassword, keyPass |
|
|
|
a.wallet.Address = a.GenerateDAGAddress() |
|
|
|
|
|
|
|
if err := a.DB.Model(&a.wallet).Where("wallet_alias = ?", a.wallet.WalletAlias).Update("Address", a.wallet.Address).Error; err != nil { |
|
|
|
a.log.Errorln("Unable to update db object new wallet, with the DAG address. Reason: ", err) |
|
|
|
a.sendError("Unable to update db object new wallet, with the DAG address. Reason. Reason: ", err) |
|
|
|
a.log.Errorln("无法使用 DAG 地址更新 db 对象 new wallet。原因: ", err) |
|
|
|
a.sendError("无法使用 DAG 地址更新 db 对象 new wallet。原因. Reason: ", err) |
|
|
|
} |
|
|
|
a.KeyStoreAccess = a.WalletKeystoreAccess() |
|
|
|
|
|
|
@ -215,8 +216,8 @@ func (a *WalletApplication) CreateWallet(keystorePath, keystorePassword, keyPass |
|
|
|
|
|
|
|
err := a.createTXFiles() |
|
|
|
if err != nil { |
|
|
|
a.log.Fatalln("Unable to create TX files. Check fs permissions. Reason: ", err) |
|
|
|
a.sendError("Unable to create TX files. Check fs permissions. Reason: ", err) |
|
|
|
a.log.Fatalln("无法创建 TX 文件。检查 fs 权限。原因: ", err) |
|
|
|
a.sendError("无法创建 TX 文件。检查 fs 权限。原因: ", err) |
|
|
|
} |
|
|
|
|
|
|
|
if err := a.DB.Where("wallet_alias = ?", a.wallet.WalletAlias).First(&a.wallet).Update("Path", models.Path{LastTXFile: a.paths.LastTXFile, PrevTXFile: a.paths.PrevTXFile, EmptyTXFile: a.paths.EmptyTXFile}).Error; err != nil { |
|
|
@ -344,73 +345,79 @@ func (a *WalletApplication) initTXFilePath() { |
|
|
|
|
|
|
|
func (a *WalletApplication) initTXFromDB() { |
|
|
|
if err := a.DB.Model(&a.wallet).Where("alias = ?", a.wallet.WalletAlias).Association("TXHistory").Find(&a.wallet.TXHistory).Error; err != nil { |
|
|
|
a.log.Error("Unable to initialize historic transactions from DB. Reason: ", err) |
|
|
|
a.sendError("Unable to initialize historic transactions from DB. Reason: ", err) |
|
|
|
a.log.Error("无法从 DB 初始化历史事务。原因: ", err) |
|
|
|
a.sendError("无法从 DB 初始化历史事务。原因: ", err) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
allTX := []models.TXHistory{} |
|
|
|
|
|
|
|
for i, tx := range a.wallet.TXHistory { |
|
|
|
allTX = append([]models.TXHistory{tx}, allTX...) // prepend to reverse list for FE
|
|
|
|
allTX = append([]models.TXHistory{tx}, allTX...) // 在 FE 的 reverse list 之前
|
|
|
|
|
|
|
|
if a.wallet.TXHistory[i].Status == "Pending" { |
|
|
|
a.TxPending(a.wallet.TXHistory[i].Hash) |
|
|
|
} |
|
|
|
} |
|
|
|
a.RT.Events.Emit("update_tx_history", allTX) // Pass the tx to the frontend as a new transaction.
|
|
|
|
a.RT.Events.Emit("update_tx_history", allTX) // 将 tx 作为新交易传递给前端。
|
|
|
|
} |
|
|
|
|
|
|
|
// initTXFromBlockExplorer is called when an existing wallet is imported.
|
|
|
|
// initTXFromBlockExplorer 在导入现有 wallet 时调用。
|
|
|
|
func (a *WalletApplication) initTXFromBlockExplorer() error { |
|
|
|
a.log.Info("Sending API call to block explorer on: " + a.Network.BlockExplorer.URL + a.Network.BlockExplorer.Handles.CollectTX + a.wallet.Address) |
|
|
|
a.log.Info("向区块浏览器发送 API 调用: " + a.Network.BlockExplorer.URL + a.Network.BlockExplorer.Handles.CollectTX + a.wallet.Address) |
|
|
|
|
|
|
|
resp, err := http.Get(a.Network.BlockExplorer.URL + a.Network.BlockExplorer.Handles.CollectTX + a.wallet.Address) |
|
|
|
if err != nil { |
|
|
|
a.log.Errorln("Failed to send HTTP request. Reason: ", err) |
|
|
|
a.LoginError("Unable to collect previous transactions from blockexplorer.") |
|
|
|
a.log.Errorln("发送 HTTP 请求失败。原因: ", err) |
|
|
|
a.LoginError("无法从 BlockExplorer 收集以前的交易。") |
|
|
|
return err |
|
|
|
} |
|
|
|
defer resp.Body.Close() |
|
|
|
defer func(Body io.ReadCloser) { |
|
|
|
err := Body.Close() |
|
|
|
if err != nil { |
|
|
|
return |
|
|
|
} |
|
|
|
}(resp.Body) |
|
|
|
|
|
|
|
if resp.Body != nil { |
|
|
|
bodyBytes, err := ioutil.ReadAll(resp.Body) |
|
|
|
// bodyBytes, err := ioutil.ReadAll(resp.Body)
|
|
|
|
bodyBytes, err := io.ReadAll(resp.Body) |
|
|
|
if err != nil { |
|
|
|
a.LoginError("Unable to collect previous transactions from blockexplorer. Try again later.") |
|
|
|
a.log.Errorln("Unable to collect previous transactions from blockexplorer. Reason: ", err) |
|
|
|
a.LoginError("无法从 BlockExplorer 收集以前的交易。 请稍后重试。") |
|
|
|
a.log.Errorln("无法从 BlockExplorer 收集以前的交易。 原因: ", err) |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
ok, error := a.verifyAPIResponse(bodyBytes) |
|
|
|
// Blockexplorer returns below string when no previous transactions are found
|
|
|
|
if !ok && error != "Cannot find transactions for sender" { |
|
|
|
a.log.Errorln("API returned the following error", error) |
|
|
|
a.LoginError("The wallet import failed. Please check your internet connection and try again.") |
|
|
|
return errors.New(error) |
|
|
|
} |
|
|
|
|
|
|
|
// If no previous transactions for imported wallet - proceed
|
|
|
|
if !ok && error == "Cannot find transactions for sender" { |
|
|
|
a.log.Info("Unable to detect any previous transactions.") |
|
|
|
return nil |
|
|
|
ok, e := a.verifyAPIResponse(bodyBytes) |
|
|
|
// 当没有找到以前的交易时,BlockExplorer 返回以下字符串
|
|
|
|
if !ok { |
|
|
|
if e != "Cannot find transactions for sender" { |
|
|
|
a.log.Errorln("API 返回以下错误", e) |
|
|
|
a.LoginError("钱包导入失败。请检查您的互联网连接,然后重试。") |
|
|
|
return errors.New(e) |
|
|
|
} else { |
|
|
|
// 如果导入的钱包之前没有发生过交易 - 继续
|
|
|
|
a.log.Info("无法检测到任何以前的交易。") |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
allTX := []models.TXHistory{} |
|
|
|
var allTX []models.TXHistory |
|
|
|
|
|
|
|
err = json.Unmarshal(bodyBytes, &allTX) |
|
|
|
if err != nil { |
|
|
|
a.log.Errorln("Unable to fetch TX history from block explorer. Reason: ", err) |
|
|
|
a.sendError("Unable to fetch TX history from block explorer. Reason: ", err) |
|
|
|
a.log.Errorln("无法从区块浏览器获取 TX 历史记录。原因: ", err) |
|
|
|
a.sendError("无法从区块浏览器获取 TX 历史记录。原因: ", err) |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
// Reverse order
|
|
|
|
// 倒序
|
|
|
|
for i := len(allTX)/2 - 1; i >= 0; i-- { |
|
|
|
opp := len(allTX) - 1 - i |
|
|
|
allTX[i], allTX[opp] = allTX[opp], allTX[i] |
|
|
|
} |
|
|
|
|
|
|
|
a.log.Infof("Successfully collected %d previous transactions. Updating local state...", len(allTX)) |
|
|
|
a.log.Infof("已成功收集 %d 笔以前的交易。更新本地状态...", len(allTX)) |
|
|
|
|
|
|
|
for i, tx := range allTX { |
|
|
|
|
|
|
@ -428,31 +435,31 @@ func (a *WalletApplication) initTXFromBlockExplorer() error { |
|
|
|
|
|
|
|
if i+1 == len(allTX) { |
|
|
|
|
|
|
|
// 向区块链发送信息
|
|
|
|
err := a.rebuildTxChainState(tx.Hash) |
|
|
|
if err != nil { |
|
|
|
a.log.Errorln(err) |
|
|
|
// If unable to import previous transactions, remove wallet from DB and logout.
|
|
|
|
//TODO: logout
|
|
|
|
// 如何无法导入以前的交易, 从 DB 中删除钱包并注销。
|
|
|
|
// TODO logout
|
|
|
|
if err := a.DB.Model(&a.wallet).Where("wallet_alias = ?", a.wallet.WalletAlias).Delete(&a.wallet).Error; err != nil { |
|
|
|
a.log.Errorln("Unable to delete wallet upon failed import. Reason: ", err) |
|
|
|
a.log.Errorln("导入失败时无法删除 wallet。原因: ", err) |
|
|
|
return err |
|
|
|
} |
|
|
|
a.log.Panicln("Unable to import previous transactions") |
|
|
|
a.LoginError("Unable to collect previous TX's from blockexplorer. Please try again later.") |
|
|
|
a.log.Panicln("无法导入以前的交易") |
|
|
|
a.LoginError("无法从 BlockExplorer 收集以前的 TX。请稍后重试。") |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
a.log.Info("Unable to detect any previous transactions.") |
|
|
|
a.log.Info("无法检测到任何以前的交易。") |
|
|
|
return nil |
|
|
|
} |
|
|
|
return nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// PassKeysToFrontend emits the keys to the settings.Vue component on a
|
|
|
|
// 5 second interval
|
|
|
|
// passKeysToFrontend 将键发送到设置中。Vue 组件 5 秒间隔
|
|
|
|
func (a *WalletApplication) passKeysToFrontend() { |
|
|
|
if a.wallet.KeyStorePath != "" && a.wallet.Address != "" { |
|
|
|
go func() { |
|
|
@ -469,43 +476,43 @@ func (a *WalletApplication) passKeysToFrontend() { |
|
|
|
|
|
|
|
func (a *WalletApplication) passwordsProvided(keystorePassword, keyPassword, alias string) bool { |
|
|
|
if keystorePassword == "" { |
|
|
|
a.LoginError("Please provide a Key Store password.") |
|
|
|
a.LoginError("请提供密钥库密码。") |
|
|
|
return false |
|
|
|
} else if keyPassword == "" { |
|
|
|
a.LoginError("Please provide a Key Password.") |
|
|
|
a.LoginError("请提供密钥密码。") |
|
|
|
return false |
|
|
|
} else if alias == "" { |
|
|
|
a.LoginError("An Alias has not been provided.") |
|
|
|
a.LoginError("尚未提供别名。") |
|
|
|
return false |
|
|
|
} |
|
|
|
return true |
|
|
|
} |
|
|
|
|
|
|
|
// GetTokenBalance polls and parses the token balance of a wallet and returns it as a float64.
|
|
|
|
// GetTokenBalance 轮询并解析钱包的代币余额,并将其返回为 float64。
|
|
|
|
func (a *WalletApplication) GetTokenBalance() (float64, error) { |
|
|
|
a.log.Debug("Contacting mainnet on: " + a.Network.URL + a.Network.Handles.Balance + " Sending the following payload: " + a.wallet.Address) |
|
|
|
a.log.Debug("通过以下方式联系主网: " + a.Network.URL + a.Network.Handles.Balance + " 发送以下有效负载:" + a.wallet.Address) |
|
|
|
|
|
|
|
resp, err := http.Get(a.Network.URL + a.Network.Handles.Balance + a.wallet.Address) |
|
|
|
if err != nil { |
|
|
|
a.log.Errorln("Failed to send HTTP request. Reason: ", err) |
|
|
|
a.log.Errorln("发送 HTTP 请求失败。原因: ", err) |
|
|
|
return 0, err |
|
|
|
} |
|
|
|
if resp == nil { |
|
|
|
a.log.Errorln("Killing pollTokenBalance after 10 failed attempts to get balance from mainnet, Reason: ", err) |
|
|
|
a.sendWarning("Unable to showcase current balance. Please check your internet connectivity and restart the wallet application.") |
|
|
|
a.log.Errorln("在尝试从主网获取余额 10 次失败后杀死 pollTokenBalance,原因: ", err) |
|
|
|
a.sendWarning("无法显示当前余额。请检查您的互联网连接并重新启动钱包应用程序。") |
|
|
|
return 0, err |
|
|
|
} |
|
|
|
defer resp.Body.Close() |
|
|
|
|
|
|
|
bodyBytes, err := ioutil.ReadAll(resp.Body) |
|
|
|
if err != nil { |
|
|
|
a.log.Warn("Unable to update token balance. Reason: ", err) |
|
|
|
a.log.Warn("无法更新 Token 余额。原因: ", err) |
|
|
|
return 0, err |
|
|
|
} |
|
|
|
|
|
|
|
var result map[string]interface{} |
|
|
|
|
|
|
|
// Unmarshal or Decode the JSON to the interface.
|
|
|
|
// 将 JSON 解组或解码到接口。
|
|
|
|
err = json.Unmarshal(bodyBytes, &result) |
|
|
|
if err != nil { |
|
|
|
return 0, err |
|
|
@ -516,27 +523,24 @@ func (a *WalletApplication) GetTokenBalance() (float64, error) { |
|
|
|
s = "0" // Empty means zero
|
|
|
|
} |
|
|
|
|
|
|
|
a.log.Infoln("Parsed the following balance: ", s) |
|
|
|
a.log.Infoln("解析了以下余额: ", s) |
|
|
|
|
|
|
|
b, ok := s.(float64) |
|
|
|
if !ok { |
|
|
|
if err != nil { |
|
|
|
a.log.Warnln("Unable to parse balance. Reason:", err) |
|
|
|
} |
|
|
|
return 0, err |
|
|
|
} |
|
|
|
|
|
|
|
f := fmt.Sprintf("%.2f", b/1e8) // Reverse normalized float
|
|
|
|
|
|
|
|
a.log.Infoln("Normalized the following balance: ", f) |
|
|
|
a.log.Infoln("规范化以下余额: ", f) |
|
|
|
|
|
|
|
balance, err := strconv.ParseFloat(f, 64) |
|
|
|
if err != nil { |
|
|
|
a.log.Warnln("Unable to type cast string to float for token balance poller. Check your internet connectivity") |
|
|
|
a.log.Warnln("无法为令牌余额 poller 键入将字符串转换为浮点数。检查您的互联网连接") |
|
|
|
return 0, err |
|
|
|
} |
|
|
|
|
|
|
|
a.log.Infoln("Returning the following balance: ", balance) |
|
|
|
a.log.Infoln("返回以下余额: ", balance) |
|
|
|
|
|
|
|
return balance, nil |
|
|
|
} |
|
|
|