From f7ac1a2cf7d7f81f4eb32ca40a51f0a977a6eed5 Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Thu, 29 Aug 2024 06:49:21 +0800 Subject: [PATCH 1/7] faucet: with mainnet balance check, 0.05BNB at least --- cmd/faucet/faucet.go | 175 +++++++++++++++++++++++++++---------------- 1 file changed, 111 insertions(+), 64 deletions(-) diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 7c8963dc69..5b410b8868 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -53,9 +53,10 @@ import ( ) var ( - genesisFlag = flag.String("genesis", "", "Genesis json file to seed the chain with") - apiPortFlag = flag.Int("apiport", 8080, "Listener port for the HTTP API connection") - wsEndpoint = flag.String("ws", "http://127.0.0.1:7777/", "Url to ws endpoint") + genesisFlag = flag.String("genesis", "", "Genesis json file to seed the chain with") + apiPortFlag = flag.Int("apiport", 8080, "Listener port for the HTTP API connection") + wsEndpoint = flag.String("ws", "http://127.0.0.1:7777/", "Url to ws endpoint") + wsEndpointMainnet = flag.String("ws.mainnet", "", "Url to ws endpoint of BSC mainnet") netnameFlag = flag.String("faucet.name", "", "Network name to assign to the faucet") payoutFlag = flag.Int("faucet.amount", 1, "Number of Ethers to pay out per user request") @@ -82,6 +83,7 @@ var ( resendBatchSize = 3 resendMaxGasPrice = big.NewInt(50 * params.GWei) wsReadTimeout = 5 * time.Minute + minMainnetBalance = big.NewInt(5 * 1e7 * params.GWei) // 0.05 bnb ) var ( @@ -92,6 +94,11 @@ var ( //go:embed faucet.html var websiteTmpl string +func weiToEtherStringF2(wei *big.Int) string { + f, _ := new(big.Float).Quo(new(big.Float).SetInt(wei), big.NewFloat(params.Ether)).Float64() + return strconv.FormatFloat(f, 'f', 2, 64) +} + func main() { // Parse the flags and set up the logger to print everything requested flag.Parse() @@ -175,7 +182,7 @@ func main() { log.Crit("Failed to unlock faucet signer account", "err", err) } // Assemble and start the faucet light service - faucet, err := newFaucet(genesis, *wsEndpoint, ks, website.Bytes(), bep2eInfos) + faucet, err := newFaucet(genesis, *wsEndpoint, *wsEndpointMainnet, ks, website.Bytes(), bep2eInfos) if err != nil { log.Crit("Failed to start faucet", "err", err) } @@ -202,9 +209,10 @@ type bep2eInfo struct { // faucet represents a crypto faucet backed by an Ethereum light client. type faucet struct { - config *params.ChainConfig // Chain configurations for signing - client *ethclient.Client // Client connection to the Ethereum chain - index []byte // Index page to serve up on the web + config *params.ChainConfig // Chain configurations for signing + client *ethclient.Client // Client connection to the Ethereum chain + clientMainnet *ethclient.Client // Client connection to BSC mainnet for balance check + index []byte // Index page to serve up on the web keystore *keystore.KeyStore // Keystore containing the single signer account accounts.Account // Account funding user faucet requests @@ -233,7 +241,7 @@ type wsConn struct { wlock sync.Mutex } -func newFaucet(genesis *core.Genesis, url string, ks *keystore.KeyStore, index []byte, bep2eInfos map[string]bep2eInfo) (*faucet, error) { +func newFaucet(genesis *core.Genesis, url string, mainnetUrl string, ks *keystore.KeyStore, index []byte, bep2eInfos map[string]bep2eInfo) (*faucet, error) { bep2eAbi, err := abi.JSON(strings.NewReader(bep2eAbiJson)) if err != nil { return nil, err @@ -242,6 +250,11 @@ func newFaucet(genesis *core.Genesis, url string, ks *keystore.KeyStore, index [ if err != nil { return nil, err } + clientMainnet, err := ethclient.Dial(mainnetUrl) + if err != nil { + // skip mainnet balance check if it there is no available mainnet endpoint + log.Warn("dail mainnet endpoint failed", "mainnetUrl", mainnetUrl, "err", err) + } // Allow 1 request per minute with burst of 5, and cache up to 1000 IPs limiter, err := NewIPRateLimiter(rate.Limit(1.0), 5, 1000) @@ -250,16 +263,17 @@ func newFaucet(genesis *core.Genesis, url string, ks *keystore.KeyStore, index [ } return &faucet{ - config: genesis.Config, - client: client, - index: index, - keystore: ks, - account: ks.Accounts()[0], - timeouts: make(map[string]time.Time), - update: make(chan struct{}, 1), - bep2eInfos: bep2eInfos, - bep2eAbi: bep2eAbi, - limiter: limiter, + config: genesis.Config, + client: client, + clientMainnet: clientMainnet, + index: index, + keystore: ks, + account: ks.Accounts()[0], + timeouts: make(map[string]time.Time), + update: make(chan struct{}, 1), + bep2eInfos: bep2eInfos, + bep2eAbi: bep2eAbi, + limiter: limiter, }, nil } @@ -407,7 +421,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { } log.Info("Faucet funds requested", "url", msg.URL, "tier", msg.Tier, "ip", ip) - // If captcha verifications are enabled, make sure we're not dealing with a robot + // check #1: captcha verifications to exclude robot if *captchaToken != "" { form := url.Values{} form.Add("secret", *captchaSecret) @@ -486,7 +500,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { } log.Info("Faucet request valid", "url", msg.URL, "tier", msg.Tier, "user", username, "address", address, "ip", ip) - // Ensure the user didn't request funds too recently + // check #2: check IP and ID(address) to ensure the user didn't request funds too recently, f.lock.Lock() var ( fund bool @@ -494,68 +508,101 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { ) if ipTimeout := f.timeouts[ips[len(ips)-2]]; time.Now().Before(ipTimeout) { + f.lock.Unlock() if err = sendError(wsconn, fmt.Errorf("%s left until next allowance", common.PrettyDuration(time.Until(ipTimeout)))); err != nil { // nolint: gosimple log.Warn("Failed to send funding error to client", "err", err) + return } + continue + } + if timeout = f.timeouts[id]; time.Now().Before(timeout) { f.lock.Unlock() + // Send an error if too frequent funding, otherwise a success + if err = sendError(wsconn, fmt.Errorf("%s left until next allowance", common.PrettyDuration(time.Until(timeout)))); err != nil { // nolint: gosimple + log.Warn("Failed to send funding error to client", "err", err) + return + } continue } - - if timeout = f.timeouts[id]; time.Now().After(timeout) { - var tx *types.Transaction - if msg.Symbol == "BNB" { - // User wasn't funded recently, create the funding transaction - amount := new(big.Int).Div(new(big.Int).Mul(big.NewInt(int64(*payoutFlag)), ether), big.NewInt(10)) - amount = new(big.Int).Mul(amount, new(big.Int).Exp(big.NewInt(5), big.NewInt(int64(msg.Tier)), nil)) - amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil)) - - tx = types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil) + // check #3: minimum mainnet balance check, internal error will bypass the check to avoid blocking the faucet service + if f.clientMainnet != nil { + mainnetAddr := address + balanceMainnet, err := f.clientMainnet.BalanceAt(context.Background(), mainnetAddr, nil) + if err != nil { + log.Warn("check balance failed, call BalanceAt", "err", err) + } else if balanceMainnet == nil { + log.Warn("check balance failed, balanceMainnet is nil") } else { - tokenInfo, ok := f.bep2eInfos[msg.Symbol] - if !ok { + if balanceMainnet.Cmp(minMainnetBalance) < 0 { f.lock.Unlock() - log.Warn("Failed to find symbol", "symbol", msg.Symbol) - continue - } - input, err := f.bep2eAbi.Pack("transfer", address, &tokenInfo.Amount) - if err != nil { - f.lock.Unlock() - log.Warn("Failed to pack transfer transaction", "err", err) + log.Warn("insufficient enough BNB on BSC mainnet", "address", mainnetAddr, + "balanceMainnet", balanceMainnet, "minimum mainnet BNB request", minMainnetBalance) + // Send an error if failed to meet the minimum balance requirement + if err = sendError(wsconn, fmt.Errorf("%s, insufficient BNB on BSC mainnet(should >=%sBNB)", + address.Hex(), weiToEtherStringF2(minMainnetBalance))); err != nil { + log.Warn("Failed to send mainnet minimum balance error to client", "err", err) + return + } continue } - tx = types.NewTransaction(f.nonce+uint64(len(f.reqs)), tokenInfo.Contract, nil, 420000, f.price, input) } - signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID) - if err != nil { + } + + // now, it is ok to send tBNB or other tokens + var tx *types.Transaction + if msg.Symbol == "BNB" { + // User wasn't funded recently, create the funding transaction + amount := new(big.Int).Div(new(big.Int).Mul(big.NewInt(int64(*payoutFlag)), ether), big.NewInt(10)) + amount = new(big.Int).Mul(amount, new(big.Int).Exp(big.NewInt(5), big.NewInt(int64(msg.Tier)), nil)) + amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil)) + + tx = types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil) + } else { + tokenInfo, ok := f.bep2eInfos[msg.Symbol] + if !ok { f.lock.Unlock() - if err = sendError(wsconn, err); err != nil { - log.Warn("Failed to send transaction creation error to client", "err", err) - return - } + log.Warn("Failed to find symbol", "symbol", msg.Symbol) continue } - // Submit the transaction and mark as funded if successful - if err := f.client.SendTransaction(context.Background(), signed); err != nil { + input, err := f.bep2eAbi.Pack("transfer", address, &tokenInfo.Amount) + if err != nil { f.lock.Unlock() - if err = sendError(wsconn, err); err != nil { - log.Warn("Failed to send transaction transmission error to client", "err", err) - return - } + log.Warn("Failed to pack transfer transaction", "err", err) continue } - f.reqs = append(f.reqs, &request{ - Avatar: avatar, - Account: address, - Time: time.Now(), - Tx: signed, - }) - timeout := time.Duration(*minutesFlag*int(math.Pow(3, float64(msg.Tier)))) * time.Minute - grace := timeout / 288 // 24h timeout => 5m grace - - f.timeouts[id] = time.Now().Add(timeout - grace) - f.timeouts[ips[len(ips)-2]] = time.Now().Add(timeout - grace) - fund = true + tx = types.NewTransaction(f.nonce+uint64(len(f.reqs)), tokenInfo.Contract, nil, 420000, f.price, input) + } + signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID) + if err != nil { + f.lock.Unlock() + if err = sendError(wsconn, err); err != nil { + log.Warn("Failed to send transaction creation error to client", "err", err) + return + } + continue } + // Submit the transaction and mark as funded if successful + if err := f.client.SendTransaction(context.Background(), signed); err != nil { + f.lock.Unlock() + if err = sendError(wsconn, err); err != nil { + log.Warn("Failed to send transaction transmission error to client", "err", err) + return + } + continue + } + f.reqs = append(f.reqs, &request{ + Avatar: avatar, + Account: address, + Time: time.Now(), + Tx: signed, + }) + timeoutInt64 := time.Duration(*minutesFlag*int(math.Pow(3, float64(msg.Tier)))) * time.Minute + grace := timeoutInt64 / 288 // 24h timeout => 5m grace + + f.timeouts[id] = time.Now().Add(timeoutInt64 - grace) + f.timeouts[ips[len(ips)-2]] = time.Now().Add(timeoutInt64 - grace) + fund = true + f.lock.Unlock() // Send an error if too frequent funding, otherwise a success From 4dba3d6554b0ab82f5ddd02baa6af50794b5b511 Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:36:49 +0800 Subject: [PATCH 2/7] faucet: fix the terminal format --- cmd/faucet/faucet.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 5b410b8868..6596cc5f4f 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -102,8 +102,8 @@ func weiToEtherStringF2(wei *big.Int) string { func main() { // Parse the flags and set up the logger to print everything requested flag.Parse() - log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.FromLegacyLevel(*logFlag), true))) - + log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.FromLegacyLevel(*logFlag), false))) + log.Info("faucet started") // Construct the payout tiers amounts := make([]string, *tiersFlag) for i := 0; i < *tiersFlag; i++ { @@ -535,8 +535,8 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { } else { if balanceMainnet.Cmp(minMainnetBalance) < 0 { f.lock.Unlock() - log.Warn("insufficient enough BNB on BSC mainnet", "address", mainnetAddr, - "balanceMainnet", balanceMainnet, "minimum mainnet BNB request", minMainnetBalance) + log.Warn("insufficient BNB on BSC mainnet", "address", mainnetAddr, + "balanceMainnet", balanceMainnet, "minMainnetBalance", minMainnetBalance) // Send an error if failed to meet the minimum balance requirement if err = sendError(wsconn, fmt.Errorf("%s, insufficient BNB on BSC mainnet(should >=%sBNB)", address.Hex(), weiToEtherStringF2(minMainnetBalance))); err != nil { From 9e30fc68a9a8bf0c033631fffe2c755f2d88d4e7 Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Mon, 2 Sep 2024 10:27:02 +0800 Subject: [PATCH 3/7] faucet: update the error message --- cmd/faucet/faucet.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 6596cc5f4f..0c324be8ed 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -538,8 +538,8 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { log.Warn("insufficient BNB on BSC mainnet", "address", mainnetAddr, "balanceMainnet", balanceMainnet, "minMainnetBalance", minMainnetBalance) // Send an error if failed to meet the minimum balance requirement - if err = sendError(wsconn, fmt.Errorf("%s, insufficient BNB on BSC mainnet(should >=%sBNB)", - address.Hex(), weiToEtherStringF2(minMainnetBalance))); err != nil { + if err = sendError(wsconn, fmt.Errorf("insufficient BNB on BSC mainnet(require >=%sBNB)", + weiToEtherStringF2(minMainnetBalance))); err != nil { log.Warn("Failed to send mainnet minimum balance error to client", "err", err) return } From 25195291410e3bb65bc8a698f713f20b5ecebc4f Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Mon, 2 Sep 2024 11:58:38 +0800 Subject: [PATCH 4/7] faucet: set the minMainnetBalance to 0.002BNB --- cmd/faucet/faucet.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 0c324be8ed..d30fa06283 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -83,7 +83,7 @@ var ( resendBatchSize = 3 resendMaxGasPrice = big.NewInt(50 * params.GWei) wsReadTimeout = 5 * time.Minute - minMainnetBalance = big.NewInt(5 * 1e7 * params.GWei) // 0.05 bnb + minMainnetBalance = big.NewInt(2 * 1e6 * params.GWei) // 0.002 bnb ) var ( @@ -94,9 +94,9 @@ var ( //go:embed faucet.html var websiteTmpl string -func weiToEtherStringF2(wei *big.Int) string { +func weiToEtherStringFx(wei *big.Int, prec int) string { f, _ := new(big.Float).Quo(new(big.Float).SetInt(wei), big.NewFloat(params.Ether)).Float64() - return strconv.FormatFloat(f, 'f', 2, 64) + return strconv.FormatFloat(f, 'f', prec, 64) } func main() { @@ -538,8 +538,8 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { log.Warn("insufficient BNB on BSC mainnet", "address", mainnetAddr, "balanceMainnet", balanceMainnet, "minMainnetBalance", minMainnetBalance) // Send an error if failed to meet the minimum balance requirement - if err = sendError(wsconn, fmt.Errorf("insufficient BNB on BSC mainnet(require >=%sBNB)", - weiToEtherStringF2(minMainnetBalance))); err != nil { + if err = sendError(wsconn, fmt.Errorf("insufficient BNB on BSC mainnet (require >=%sBNB)", + weiToEtherStringFx(minMainnetBalance, 3))); err != nil { log.Warn("Failed to send mainnet minimum balance error to client", "err", err) return } From 79b1540a684a4b0371f58dbed589b34b2e756afd Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Tue, 3 Sep 2024 16:18:57 +0800 Subject: [PATCH 5/7] faucet: update some log --- cmd/faucet/faucet.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index d30fa06283..70a05386e1 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -401,7 +401,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { // if user did not give response for too long, then the routine will be stuck. conn.SetReadDeadline(time.Now().Add(wsReadTimeout)) if err = conn.ReadJSON(&msg); err != nil { - log.Info("read json message failed", "err", err, "ip", ip) + log.Debug("read json message failed", "err", err, "ip", ip) return } if !*noauthFlag && !strings.HasPrefix(msg.URL, "https://twitter.com/") && !strings.HasPrefix(msg.URL, "https://www.facebook.com/") { @@ -498,7 +498,6 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { } continue } - log.Info("Faucet request valid", "url", msg.URL, "tier", msg.Tier, "user", username, "address", address, "ip", ip) // check #2: check IP and ID(address) to ensure the user didn't request funds too recently, f.lock.Lock() @@ -513,6 +512,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { log.Warn("Failed to send funding error to client", "err", err) return } + log.Info("too frequent funding(ip)", "Wait", common.PrettyDuration(time.Until(timeout)), "ip", ips[len(ips)-2], "ipsStr", ipsStr) continue } if timeout = f.timeouts[id]; time.Now().Before(timeout) { @@ -522,6 +522,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { log.Warn("Failed to send funding error to client", "err", err) return } + log.Info("too frequent funding(id)", "Wait", common.PrettyDuration(time.Until(timeout)), "id", id) continue } // check #3: minimum mainnet balance check, internal error will bypass the check to avoid blocking the faucet service @@ -547,6 +548,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { } } } + log.Info("Faucet request valid", "url", msg.URL, "tier", msg.Tier, "user", username, "address", address, "ip", ip) // now, it is ok to send tBNB or other tokens var tx *types.Transaction From 3e121e7a19b86b4ed9ecc51d5b9599fa727b66f9 Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:15:11 +0800 Subject: [PATCH 6/7] faucet: some code improve --- cmd/faucet/faucet.go | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 70a05386e1..0df6bb676c 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -501,10 +501,6 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { // check #2: check IP and ID(address) to ensure the user didn't request funds too recently, f.lock.Lock() - var ( - fund bool - timeout time.Time - ) if ipTimeout := f.timeouts[ips[len(ips)-2]]; time.Now().Before(ipTimeout) { f.lock.Unlock() @@ -512,17 +508,17 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { log.Warn("Failed to send funding error to client", "err", err) return } - log.Info("too frequent funding(ip)", "Wait", common.PrettyDuration(time.Until(timeout)), "ip", ips[len(ips)-2], "ipsStr", ipsStr) + log.Info("too frequent funding(ip)", "TimeLeft", common.PrettyDuration(time.Until(ipTimeout)), "ip", ips[len(ips)-2], "ipsStr", ipsStr) continue } - if timeout = f.timeouts[id]; time.Now().Before(timeout) { + if idTimeout := f.timeouts[id]; time.Now().Before(idTimeout) { f.lock.Unlock() // Send an error if too frequent funding, otherwise a success - if err = sendError(wsconn, fmt.Errorf("%s left until next allowance", common.PrettyDuration(time.Until(timeout)))); err != nil { // nolint: gosimple + if err = sendError(wsconn, fmt.Errorf("%s left until next allowance", common.PrettyDuration(time.Until(idTimeout)))); err != nil { // nolint: gosimple log.Warn("Failed to send funding error to client", "err", err) return } - log.Info("too frequent funding(id)", "Wait", common.PrettyDuration(time.Until(timeout)), "id", id) + log.Info("too frequent funding(id)", "TimeLeft", common.PrettyDuration(time.Until(idTimeout)), "id", id) continue } // check #3: minimum mainnet balance check, internal error will bypass the check to avoid blocking the faucet service @@ -603,18 +599,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { f.timeouts[id] = time.Now().Add(timeoutInt64 - grace) f.timeouts[ips[len(ips)-2]] = time.Now().Add(timeoutInt64 - grace) - fund = true - f.lock.Unlock() - - // Send an error if too frequent funding, otherwise a success - if !fund { - if err = sendError(wsconn, fmt.Errorf("%s left until next allowance", common.PrettyDuration(time.Until(timeout)))); err != nil { // nolint: gosimple - log.Warn("Failed to send funding error to client", "err", err) - return - } - continue - } if err = sendSuccess(wsconn, fmt.Sprintf("Funding request accepted for %s into %s", username, address.Hex())); err != nil { log.Warn("Failed to send funding success to client", "err", err) return From 5663e52315ed17ae606b9dd874ec8e52a6d7861c Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:51:31 +0800 Subject: [PATCH 7/7] faucet: code improve Co-authored-by: Matus Kysel --- cmd/faucet/faucet.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 0df6bb676c..e83a32835a 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -95,8 +95,9 @@ var ( var websiteTmpl string func weiToEtherStringFx(wei *big.Int, prec int) string { - f, _ := new(big.Float).Quo(new(big.Float).SetInt(wei), big.NewFloat(params.Ether)).Float64() - return strconv.FormatFloat(f, 'f', prec, 64) + etherValue := new(big.Float).Quo(new(big.Float).SetInt(wei), big.NewFloat(params.Ether)) + // Format the big.Float directly to a string with the specified precision + return etherValue.Text('f', prec) } func main() {