Skip to content

Commit 434532c

Browse files
committed
Define base transfer support
1 parent 2c18df0 commit 434532c

File tree

17 files changed

+617
-9
lines changed

17 files changed

+617
-9
lines changed

broadcast.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package faucet
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/gnolang/faucet/client"
7+
"github.com/gnolang/gno/tm2/pkg/std"
8+
)
9+
10+
// broadcastTransaction broadcasts the transaction using a COMMIT send
11+
func broadcastTransaction(client client.Client, tx *std.Tx) error {
12+
// Send the transaction.
13+
// NOTE: Commit sends are temporary. Once
14+
// there is support for event indexing, this
15+
// call will change to a sync send
16+
response, err := client.SendTransactionCommit(tx)
17+
if err != nil {
18+
return fmt.Errorf("unable to send transaction, %w", err)
19+
}
20+
21+
// Check the errors
22+
if response.CheckTx.IsErr() {
23+
return fmt.Errorf("transaction failed initial validation, %w", response.CheckTx.Error)
24+
}
25+
26+
if response.DeliverTx.IsErr() {
27+
return fmt.Errorf("transaction failed during execution, %w", response.DeliverTx.Error)
28+
}
29+
30+
return nil
31+
}

client/client.go

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package client
2+
3+
import (
4+
coreTypes "github.com/gnolang/gno/tm2/pkg/bft/rpc/core/types"
5+
"github.com/gnolang/gno/tm2/pkg/crypto"
6+
"github.com/gnolang/gno/tm2/pkg/std"
7+
)
8+
9+
// Client defines the TM2 client functionality
10+
type Client interface {
11+
// Account methods //
12+
13+
// GetAccount fetches the account if it has been initialized
14+
GetAccount(address crypto.Address) (std.Account, error)
15+
16+
// Transaction methods //
17+
18+
// SendTransactionSync sends the specified transaction to the network,
19+
// and does not wait for it to be committed to the chain
20+
SendTransactionSync(tx *std.Tx) (*coreTypes.ResultBroadcastTx, error)
21+
22+
// SendTransactionCommit sends the specified transaction to the network,
23+
// and wait for it to be committed to the chain
24+
SendTransactionCommit(tx *std.Tx) (*coreTypes.ResultBroadcastTxCommit, error)
25+
}

client/http/http.go

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package http
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/gnolang/gno/tm2/pkg/amino"
7+
rpcClient "github.com/gnolang/gno/tm2/pkg/bft/rpc/client"
8+
coreTypes "github.com/gnolang/gno/tm2/pkg/bft/rpc/core/types"
9+
"github.com/gnolang/gno/tm2/pkg/crypto"
10+
"github.com/gnolang/gno/tm2/pkg/std"
11+
)
12+
13+
// Client is the TM2 HTTP client
14+
type Client struct {
15+
client rpcClient.Client
16+
}
17+
18+
// NewClient creates a new TM2 HTTP client
19+
func NewClient(remote string) *Client {
20+
return &Client{
21+
client: rpcClient.NewHTTP(remote, ""),
22+
}
23+
}
24+
25+
func (c *Client) GetAccount(address crypto.Address) (std.Account, error) {
26+
path := fmt.Sprintf("auth/accounts/%s", address.String())
27+
28+
queryResponse, err := c.client.ABCIQuery(path, []byte{})
29+
if err != nil {
30+
return nil, fmt.Errorf("unable to execute ABCI query, %w", err)
31+
}
32+
33+
var queryData struct{ BaseAccount std.BaseAccount }
34+
35+
if err := amino.UnmarshalJSON(queryResponse.Response.Data, &queryData); err != nil {
36+
return nil, err
37+
}
38+
39+
return &queryData.BaseAccount, nil
40+
}
41+
42+
func (c *Client) SendTransactionSync(tx *std.Tx) (*coreTypes.ResultBroadcastTx, error) {
43+
aminoTx, err := amino.Marshal(tx)
44+
if err != nil {
45+
return nil, fmt.Errorf("unable to marshal transaction, %w", err)
46+
}
47+
48+
return c.client.BroadcastTxSync(aminoTx)
49+
}
50+
51+
func (c *Client) SendTransactionCommit(tx *std.Tx) (*coreTypes.ResultBroadcastTxCommit, error) {
52+
aminoTx, err := amino.Marshal(tx)
53+
if err != nil {
54+
return nil, fmt.Errorf("unable to marshal transaction, %w", err)
55+
}
56+
57+
return c.client.BroadcastTxCommit(aminoTx)
58+
}

cmd/root/root.go

+14
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,20 @@ func registerFlags(cfg *faucetCfg, fs *flag.FlagSet) {
8787
"the chain ID associated with the remote Gno chain",
8888
)
8989

90+
fs.StringVar(
91+
&cfg.Mnemonic,
92+
"mnemonic",
93+
config.DefaultMnemonic,
94+
"the mnemonic for faucet keys",
95+
)
96+
97+
fs.Uint64Var(
98+
&cfg.NumAccounts,
99+
"num-accounts",
100+
config.DefaultNumAccounts,
101+
"the number of faucet accounts, based on the mnemonic",
102+
)
103+
90104
fs.StringVar(
91105
&cfg.SendAmount,
92106
"send-amount",

config/config.go

+24
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package config
22

33
import (
44
"errors"
5+
"fmt"
56
"regexp"
7+
8+
"github.com/gnolang/gno/tm2/pkg/crypto/bip39"
69
)
710

811
const (
@@ -12,6 +15,8 @@ const (
1215
DefaultSendAmount = "1000000ugnot"
1316
DefaultGasFee = "1000000ugnot"
1417
DefaultGasWanted = "100000"
18+
DefaultMnemonic = "source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast"
19+
DefaultNumAccounts = uint64(1)
1520
)
1621

1722
var (
@@ -33,6 +38,13 @@ type Config struct {
3338
// The chain ID associated with the remote Gno chain
3439
ChainID string `toml:"chain_id"`
3540

41+
// The mnemonic for the faucet
42+
Mnemonic string `toml:"mnemonic"`
43+
44+
// The number of faucet accounts,
45+
// based on the mnemonic (account 0, index x)
46+
NumAccounts uint64 `toml:"num_accounts"`
47+
3648
// The static send amount (native currency).
3749
// Format should be: <AMOUNT>ugnot
3850
SendAmount string `toml:"send_amount"`
@@ -58,6 +70,8 @@ func DefaultConfig() *Config {
5870
SendAmount: DefaultSendAmount,
5971
GasFee: DefaultGasFee,
6072
GasWanted: DefaultGasWanted,
73+
Mnemonic: DefaultMnemonic,
74+
NumAccounts: DefaultNumAccounts,
6175
CORSConfig: DefaultCORSConfig(),
6276
}
6377
}
@@ -94,5 +108,15 @@ func ValidateConfig(config *Config) error {
94108
return errors.New("invalid gas wanted")
95109
}
96110

111+
// validate the mnemonic is bip39-compliant
112+
if !bip39.IsMnemonicValid(config.Mnemonic) {
113+
return fmt.Errorf("invalid mnemonic, %s", config.Mnemonic)
114+
}
115+
116+
// validate at least one faucet account is set
117+
if config.NumAccounts < 1 {
118+
return errors.New("invalid number of faucet accounts")
119+
}
120+
97121
return nil
98122
}

estimate/estimate.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import "github.com/gnolang/gno/tm2/pkg/std"
44

55
// Estimator defines the transaction gas estimator
66
type Estimator interface {
7-
// EstimateGasFee estimates the optimal gas fee for the specified transaction
8-
EstimateGasFee(tx std.Tx) std.Coins
7+
// EstimateGasFee estimates the current network gas fee for transactions
8+
EstimateGasFee() std.Coin
99

1010
// EstimateGasWanted estimates the optimal gas wanted for the specified transaction
1111
EstimateGasWanted(tx std.Tx) int64

estimate/static/static.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ import (
66

77
// Estimator is a static gas estimator (returns static values)
88
type Estimator struct {
9-
gasFee std.Coins
9+
gasFee std.Coin
1010
gasWanted int64
1111
}
1212

1313
// New creates a new static gas estimator
14-
func New(gasFee std.Coins, gasWanted int64) *Estimator {
14+
func New(gasFee std.Coin, gasWanted int64) *Estimator {
1515
return &Estimator{
1616
gasFee: gasFee,
1717
gasWanted: gasWanted,
1818
}
1919
}
2020

21-
func (e Estimator) EstimateGasFee(_ std.Tx) std.Coins {
21+
func (e Estimator) EstimateGasFee() std.Coin {
2222
return e.gasFee
2323
}
2424

faucet.go

+24-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"net/http"
88
"time"
99

10+
"github.com/gnolang/faucet/client"
11+
tm2Client "github.com/gnolang/faucet/client/http"
1012
"github.com/gnolang/faucet/config"
1113
"github.com/gnolang/faucet/estimate"
1214
"github.com/gnolang/faucet/log"
@@ -20,12 +22,15 @@ import (
2022
type Faucet struct {
2123
estimator estimate.Estimator // gas pricing estimations
2224
logger log.Logger // log feedback
25+
client client.Client // TM2 client
2326

2427
mux *chi.Mux // HTTP routing
2528

2629
config *config.Config // faucet configuration
2730
middlewares []Middleware // request middlewares
2831
handlers []Handler // request handlers
32+
33+
keyring keyring // the faucet keyring
2934
}
3035

3136
// NewFaucet creates a new instance of the Gno faucet server
@@ -35,21 +40,39 @@ func NewFaucet(estimator estimate.Estimator, opts ...Option) (*Faucet, error) {
3540
logger: nul.New(),
3641
config: config.DefaultConfig(),
3742
middlewares: nil, // no middlewares by default
38-
handlers: nil, // TODO single default handler
3943

4044
mux: chi.NewMux(),
4145
}
4246

47+
// Set the single default HTTP handler
48+
f.handlers = []Handler{
49+
{
50+
"/",
51+
f.defaultHTTPHandler,
52+
},
53+
}
54+
4355
// Apply the options
4456
for _, opt := range opts {
4557
opt(f)
4658
}
4759

60+
// Set the faucet client
61+
f.client = tm2Client.NewClient(f.config.Remote)
62+
4863
// Validate the configuration
4964
if err := config.ValidateConfig(f.config); err != nil {
5065
return nil, fmt.Errorf("invalid configuration, %w", err)
5166
}
5267

68+
// Generate the keyring
69+
keyring, err := newKeyring(f.config.Mnemonic, f.config.NumAccounts)
70+
if err != nil {
71+
return nil, fmt.Errorf("unable to generate keyring, %w", err)
72+
}
73+
74+
f.keyring = keyring
75+
5376
// Set up the CORS middleware
5477
if f.config.CORSConfig != nil {
5578
corsMiddleware := cors.New(cors.Options{

0 commit comments

Comments
 (0)