-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add support for realm faucet #180
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,12 +15,15 @@ import ( | |
"strconv" | ||
"strings" | ||
"syscall" | ||
"time" | ||
|
||
"github.com/gnolang/faucet" | ||
"github.com/gnolang/faucet/client" | ||
tm2Client "github.com/gnolang/faucet/client/http" | ||
"github.com/gnolang/faucet/config" | ||
"github.com/gnolang/faucet/estimate/static" | ||
"github.com/gnolang/gno/gno.land/pkg/sdk/vm" | ||
"github.com/gnolang/gno/tm2/pkg/sdk/bank" | ||
"github.com/peterbourgon/ff/v3" | ||
"github.com/peterbourgon/ff/v3/fftoml" | ||
"github.com/redis/go-redis/v9" | ||
|
@@ -61,6 +64,9 @@ type rootCfg struct { | |
|
||
redisURL string | ||
|
||
tokenFundMethod string | ||
tokenFundRealm string | ||
|
||
allowedTokens stringArr // TODO temporary | ||
} | ||
|
||
|
@@ -180,6 +186,20 @@ func registerFlags(fs *flag.FlagSet, c *rootCfg) { | |
"redis connection string", | ||
) | ||
|
||
fs.StringVar( | ||
&c.tokenFundRealm, | ||
"token-fund-realm", | ||
"", | ||
"the path to the Realm that can fund the player", | ||
) | ||
|
||
fs.StringVar( | ||
&c.tokenFundMethod, | ||
"token-fund-method", | ||
"", | ||
"the Realm method that can fund the player", | ||
) | ||
|
||
// TODO temporary | ||
fs.Var( | ||
&c.allowedTokens, | ||
|
@@ -221,20 +241,49 @@ func execMain(cfg *rootCfg) error { | |
// Create the client (HTTP) | ||
cli := tm2Client.NewClient(cfg.remote) | ||
|
||
// Prepare the middlewares | ||
var middlewares []faucet.Middleware | ||
// Prepare the faucet values | ||
var ( | ||
middlewares []faucet.Middleware | ||
prepareTxFn faucet.PrepareTxMessageFn | ||
) | ||
|
||
if len(cfg.allowedTokens) != 0 { | ||
// TODO temporary for testing purpose without redis | ||
// TODO temporary for testing purposes without redis | ||
middlewares = append(middlewares, prepareTokenListMiddleware(cfg.allowedTokens)) | ||
|
||
// By default, for testing purposes, the transaction is a MsgSend | ||
prepareTxFn = func(cfg faucet.PrepareCfg) std.Msg { | ||
return bank.MsgSend{ | ||
FromAddress: cfg.FromAddress, | ||
ToAddress: cfg.ToAddress, | ||
Amount: cfg.SendAmount, | ||
} | ||
} | ||
} else { | ||
redisOpts, err := redis.ParseURL(cfg.redisURL) | ||
if err != nil { | ||
return err | ||
} | ||
redisClient := redis.NewClient(redisOpts) | ||
|
||
// Prepare the middlewares | ||
middlewares = append(middlewares, prepareTokenMiddleware(redisClient)) | ||
|
||
// Validate the realm values | ||
if cfg.tokenFundMethod == "" { | ||
return errors.New("invalid token Realm method supplied") | ||
} | ||
|
||
if cfg.tokenFundRealm == "" { | ||
return errors.New("invalid token Realm path supplied") | ||
} | ||
|
||
// Prepare the tx message creation | ||
prepareTxFn = prepareTxMessage( | ||
redisClient, | ||
cfg.tokenFundRealm, | ||
cfg.tokenFundMethod, | ||
) | ||
} | ||
// Call prepareFundMiddleware last to avoid funding users with invalid tokens | ||
middlewares = append(middlewares, prepareFundMiddleware(cli, fundLimit)) | ||
|
@@ -247,6 +296,7 @@ func execMain(cfg *rootCfg) error { | |
faucet.WithLogger(newCommandLogger(logger)), | ||
faucet.WithConfig(cfg.generateFaucetConfig()), | ||
faucet.WithMiddlewares(middlewares), | ||
faucet.WithPrepareTxMessageFn(prepareTxFn), | ||
) | ||
if err != nil { | ||
return fmt.Errorf("unable to create faucet, %w", err) | ||
|
@@ -262,6 +312,39 @@ func execMain(cfg *rootCfg) error { | |
return w.wait() | ||
} | ||
|
||
// prepareTxMessage returns the Realm fund call message creator. | ||
// NOTE: This prepare method assumes the token was previously saved | ||
// in the redis storage, through a middleware | ||
func prepareTxMessage(redisClient *redis.Client, fundRealm, fundMethod string) faucet.PrepareTxMessageFn { | ||
return func(cfg faucet.PrepareCfg) std.Msg { | ||
var ( | ||
token string | ||
err error | ||
|
||
ctx, cancelFn = context.WithTimeout(context.Background(), time.Second*10) | ||
) | ||
|
||
defer cancelFn() | ||
|
||
// Fetch the token from Redis | ||
token, err = redisClient.HGet(ctx, "GNO:"+cfg.ToAddress.String(), "token").Result() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
if err != nil { | ||
// Invalid token request, pass it | ||
// to the Realm as an empty value | ||
token = "" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we really want that ? |
||
} | ||
|
||
// Prepare the method call | ||
return vm.MsgCall{ | ||
Caller: cfg.FromAddress, | ||
PkgPath: fundRealm, | ||
Func: fundMethod, | ||
Args: []string{cfg.ToAddress.String(), token}, | ||
Send: cfg.SendAmount, | ||
} | ||
} | ||
} | ||
|
||
type cmdLogger struct { | ||
logger *zap.Logger | ||
} | ||
|
@@ -499,7 +582,7 @@ func prepareTokenMiddleware(redisClient *redis.Client) faucet.Middleware { | |
http.Error(w, "Unable to read token email", http.StatusInternalServerError) | ||
return | ||
} | ||
// Store gno adress, email and token, so they are retrievable via the | ||
// Store gno address, email and token, so they are retrievable via the | ||
// getEmail middleware. | ||
err = redisClient.HSet(r.Context(), "GNO:"+request.To, "email", email, "token", token).Err() | ||
if err != nil { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering that
bank.MsgSend
is already the default behavior of the faucet when noprepareTxFn
is provided, I don't think it's required to fillprepareTxFn
here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I've just looked at the faucet code, and if you provide a
prepareTxFn=nil
, it will probably panic when transferring funds.The proper way is so to deal with a
[]faucet.Option
rather than aprepareTxFn
directly. WhenallowedTokens
is not empty, you add thefaucet.WithPrepareTxFn
option, if it's empty you don't.