Skip to content

Commit

Permalink
Merge pull request #1326 from onflow/ianthpun/testnet-faucet
Browse files Browse the repository at this point in the history
move create-interactive, support flow-cli testnet link with flow account fund
  • Loading branch information
ianthpun authored Jan 4, 2024
2 parents e2d337a + e3d85e8 commit 63643d1
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 15 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/onflow/flow-emulator v0.59.0
github.com/onflow/flow-go-sdk v0.41.17
github.com/onflowser/flowser/v3 v3.1.3
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/pkg/errors v0.9.1
github.com/psiemens/sconfig v0.1.0
github.com/radovskyb/watcher v1.0.7
Expand Down Expand Up @@ -87,6 +88,7 @@ require (
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-redis/redis/v8 v8.11.5 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/gobwas/ws v1.3.0 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.1.2 // indirect
Expand Down
12 changes: 9 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -378,12 +378,15 @@ github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-test/deep v1.0.5/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/gobwas/ws v1.3.0 h1:sbeU3Y4Qzlb+MOzIe6mQGf7QR4Hkv6ZD0qhGkBFL2O0=
github.com/gobwas/ws v1.3.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
Expand Down Expand Up @@ -944,6 +947,8 @@ github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down Expand Up @@ -1498,6 +1503,7 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
14 changes: 14 additions & 0 deletions internal/accounts/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,18 @@ var Cmd = &cobra.Command{
GroupID: "resources",
}

func testnetFaucetURL(address flow.Address) string {
return fmt.Sprintf("https://testnet-faucet.onflow.org/fund-account?address=%s", address)
}

func init() {
addContractCommand.AddToParent(Cmd)
removeCommand.AddToParent(Cmd)
updateCommand.AddToParent(Cmd)
createCommand.AddToParent(Cmd)
stakingCommand.AddToParent(Cmd)
getCommand.AddToParent(Cmd)
fundCommand.AddToParent(Cmd)
}

// accountResult represent result from all account commands.
Expand Down Expand Up @@ -86,6 +91,15 @@ func (r *accountResult) String() string {
var b bytes.Buffer
writer := util.CreateTabWriter(&b)

if r.Address.IsValid(flow.Testnet) {
_, _ = fmt.Fprintf(
writer,
"If you would like to fund the account with 1000 FLOW tokens for testing,"+
" visit %s\n\n",
testnetFaucetURL(r.Address),
)
}

_, _ = fmt.Fprintf(writer, "Address\t 0x%s\n", r.Address)
_, _ = fmt.Fprintf(writer, "Balance\t %s\n", cadence.UFix64(r.Balance))

Expand Down
22 changes: 14 additions & 8 deletions internal/accounts/create-interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@ import (
"strings"
"time"

"github.com/onflow/flow-cli/flowkit/accounts"

flowsdk "github.com/onflow/flow-go-sdk"
"github.com/onflow/flow-go-sdk/crypto"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/onflow/flow-cli/flowkit"
"github.com/onflow/flow-cli/flowkit/accounts"
"github.com/onflow/flow-cli/flowkit/config"
"github.com/onflow/flow-cli/flowkit/gateway"
"github.com/onflow/flow-cli/flowkit/output"
Expand All @@ -48,7 +47,7 @@ import (
//
// This process takes the user through couple of steps with prompts asking for them to provide name and network,
// and it then uses account creation APIs to automatically create the account on the network as well as save it.
func createInteractive(state *flowkit.State) error {
func createInteractive(state *flowkit.State) (*accountResult, error) {
log := output.NewStdoutLogger(output.InfoLog)
name := util.AccountNamePrompt(state.Accounts().Names())
networkName, selectedNetwork := util.CreateAccountNetworkPrompt()
Expand All @@ -57,13 +56,13 @@ func createInteractive(state *flowkit.State) error {
// create new gateway based on chosen network
gw, err := gateway.NewGrpcGateway(selectedNetwork)
if err != nil {
return err
return nil, err
}
flow := flowkit.NewFlowkit(state, selectedNetwork, gw, output.NewStdoutLogger(output.NoneLog))

key, err := flow.GenerateKey(context.Background(), defaultSignAlgo, "")
if err != nil {
return err
return nil, err
}

log.StartProgress(fmt.Sprintf("Creating account %s on %s...", name, networkName))
Expand All @@ -79,7 +78,7 @@ func createInteractive(state *flowkit.State) error {
log.StopProgress()
}
if err != nil {
return err
return nil, err
}

log.Info(fmt.Sprintf(
Expand All @@ -93,7 +92,7 @@ func createInteractive(state *flowkit.State) error {
state.Accounts().AddOrUpdate(account)
err = state.SaveDefault()
if err != nil {
return err
return nil, err
}

items := []string{
Expand All @@ -108,7 +107,14 @@ func createInteractive(state *flowkit.State) error {
}
outputList(log, items, false)

return nil
return &accountResult{
Account: &flowsdk.Account{
Address: account.Address,
Balance: 0,
Keys: []*flowsdk.AccountKey{flowsdk.NewAccountKey().FromPrivateKey(key)},
},
include: nil,
}, nil
}

// createNetworkAccount using the account creation API and return the newly created account address.
Expand Down
15 changes: 11 additions & 4 deletions internal/accounts/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,22 @@ func create(
flow flowkit.Services,
state *flowkit.State,
) (command.Result, error) {
if len(createFlags.Keys) == 0 { // if user doesn't provide any flags go into interactive mode
return createInteractive(state)
} else {
return createManual(state, flow)
}
}

func createManual(
state *flowkit.State,
flow flowkit.Services,
) (*accountResult, error) {
sigsFlag := createFlags.SigAlgo
hashFlag := createFlags.HashAlgo
keysFlag := createFlags.Keys
weightFlag := createFlags.Weights

if len(keysFlag) == 0 { // if user doesn't provide any flags go into interactive mode
return nil, createInteractive(state)
}

signer, err := state.Accounts().ByName(createFlags.Signer)
if err != nil {
return nil, err
Expand Down
79 changes: 79 additions & 0 deletions internal/accounts/fund.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Flow CLI
*
* Copyright 2019 Dapper Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package accounts

import (
"fmt"
"time"

flowsdk "github.com/onflow/flow-go-sdk"

"github.com/pkg/browser"
"github.com/spf13/cobra"

"github.com/onflow/flow-cli/flowkit"
"github.com/onflow/flow-cli/flowkit/output"
"github.com/onflow/flow-cli/internal/command"
)

type flagsFund struct {
Include []string `default:"" flag:"include" info:"Fields to include in the output. Valid values: contracts."`
}

var fundFlags = flagsFund{}

var fundCommand = &command.Command{
Cmd: &cobra.Command{
Use: "fund <address>",
Short: "Funds an account by address through the Testnet Faucet",
Example: "flow accounts fund 8e94eaa81771313a",
Args: cobra.ExactArgs(1),
},
Flags: &fundFlags,
Run: fund,
}

func fund(
args []string,
_ command.GlobalFlags,
logger output.Logger,
_ flowkit.ReaderWriter,
flow flowkit.Services,
) (command.Result, error) {
address := flowsdk.HexToAddress(args[0])
if !address.IsValid(flowsdk.Testnet) {
return nil, fmt.Errorf("unsupported address %s, faucet can only work for valid Testnet addresses", address.String())
}

logger.Info(
fmt.Sprintf(
"Opening the Testnet faucet to fund 0x%s on your native browser."+
"\n\nIf there is an issue, please use this link instead: %s",
address.String(),
testnetFaucetURL(address),
))
// wait for the user to read the message
time.Sleep(5 * time.Second)

if err := browser.OpenURL(testnetFaucetURL(address)); err != nil {
return nil, err
}

return nil, nil
}

0 comments on commit 63643d1

Please sign in to comment.