Skip to content

Commit

Permalink
feat: wallet withdraw check (#386)
Browse files Browse the repository at this point in the history
  • Loading branch information
notanatol authored Mar 15, 2024
1 parent 453a168 commit 518ab8a
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 0 deletions.
5 changes: 5 additions & 0 deletions config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,11 @@ checks:
options:
timeout: 5m
type: pingpong
withdraw:
options:
target-address: 0xec44cb15b1b033e74d55ac5d0e24d861bde54532
timeout: 5m
type: withdraw
pss:
options:
address-prefix: 2
Expand Down
6 changes: 6 additions & 0 deletions config/local.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ bee-configs:
welcome-message: "Welcome to the Swarm, this is a local cluster!"
warmup-time: 0s
allow-private-cidrs: true
withdrawal-addresses-whitelist: 0xec44cb15b1b033e74d55ac5d0e24d861bde54532

bootnode-local:
_inherit: "bee-local"
Expand Down Expand Up @@ -263,6 +264,11 @@ checks:
options:
timeout: 5m
type: pingpong
ci-withdraw:
options:
target-address: 0xec44cb15b1b033e74d55ac5d0e24d861bde54532
timeout: 5m
type: withdraw
ci-pss:
options:
count: 3
Expand Down
2 changes: 2 additions & 0 deletions pkg/bee/api/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ var policies = [][]string{
{"maintainer", "/chequebook/cheque", "GET"},
{"maintainer", "/chequebook/address", "GET"},
{"maintainer", "/chequebook/balance", "GET"},
{"maintainer", "/wallet", "GET"},
{"maintainer", "/wallet/withdraw/*", "POST"},
{"maintainer", "/chunks/*", "(GET)|(DELETE)"},
{"maintainer", "/reservestate", "GET"},
{"maintainer", "/chainstate", "GET"},
Expand Down
31 changes: 31 additions & 0 deletions pkg/bee/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"sync"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/bee/pkg/swarm"
"github.com/ethersphere/beekeeper/pkg/bee/api"
"github.com/ethersphere/beekeeper/pkg/bee/debugapi"
Expand Down Expand Up @@ -847,3 +848,33 @@ func (c *Client) GetStake(ctx context.Context) (*big.Int, error) {
func (c *Client) WithdrawStake(ctx context.Context) (string, error) {
return c.debug.Stake.WithdrawStake(ctx)
}

// WalletBalance fetches the balance for the given token
func (c *Client) WalletBalance(ctx context.Context, token string) (*big.Int, error) {
resp, err := c.debug.Node.Wallet(ctx)
if err != nil {
return nil, err
}

if token == "BZZ" {
return resp.BZZ.Int, nil
}

return resp.NativeToken.Int, nil
}

// Withdraw transfers token from eth address to the provided address
func (c *Client) Withdraw(ctx context.Context, token, addr string, amount int64) error {
resp, err := c.debug.Node.Withdraw(ctx, token, addr, amount)
if err != nil {
return err
}

var zeroHash common.Hash

if resp == zeroHash {
return errors.New("withdraw returned zero hash")
}

return nil
}
28 changes: 28 additions & 0 deletions pkg/bee/debugapi/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package debugapi

import (
"context"
"fmt"
"net/http"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/beekeeper/pkg/bigint"

"github.com/ethersphere/bee/pkg/swarm"
Expand Down Expand Up @@ -249,3 +251,29 @@ func (n *NodeService) Topology(ctx context.Context) (resp Topology, err error) {

return
}

type Wallet struct {
BZZ *bigint.BigInt `json:"bzzBalance"`
NativeToken *bigint.BigInt `json:"nativeTokenBalance"`
}

// Wallet returns the wallet state
func (n *NodeService) Wallet(ctx context.Context) (resp Wallet, err error) {
err = n.client.requestJSON(ctx, http.MethodGet, "/wallet", nil, &resp)
return
}

// Withdraw calls wallet withdraw endpoint
func (n *NodeService) Withdraw(ctx context.Context, token, addr string, amount int64) (tx common.Hash, err error) {
endpoint := fmt.Sprintf("/wallet/withdraw/%s?address=%s&amount=%d", token, addr, amount)

r := struct {
TransactionHash common.Hash `json:"transactionHash"`
}{}

if err = n.client.requestJSON(ctx, http.MethodPost, endpoint, nil, &r); err != nil {
return
}

return r.TransactionHash, nil
}
81 changes: 81 additions & 0 deletions pkg/check/withdraw/withdraw.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package withdraw

import (
"context"
"errors"
"fmt"

"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/beekeeper/pkg/beekeeper"
"github.com/ethersphere/beekeeper/pkg/logging"
"github.com/ethersphere/beekeeper/pkg/orchestration"
test "github.com/ethersphere/beekeeper/pkg/test"
)

// Options represents check options
type Options struct {
TargetAddr string
}

// NewDefaultOptions returns new default options
func NewDefaultOptions() Options {
return Options{}
}

// compile check whether Check implements interface
var _ beekeeper.Action = (*Check)(nil)

// Check instance
type Check struct {
logger logging.Logger
}

// NewCheck returns new check
func NewCheck(logger logging.Logger) beekeeper.Action {
return &Check{
logger: logger,
}
}

func (c *Check) Run(ctx context.Context, cluster orchestration.Cluster, opts interface{}) (err error) {
o, ok := opts.(Options)
if !ok {
return fmt.Errorf("invalid options type")
}

var checkCase *test.CheckCase

if checkCase, err = test.NewCheckCase(ctx, cluster, test.CaseOptions{}, c.logger); err != nil {
return err
}

target := checkCase.Bee(1)

c.logger.Infof("target is %s", target.Name())

c.logger.Info("withdrawing native...")

if err := target.Withdraw(ctx, "NativeToken", o.TargetAddr); err != nil {
return fmt.Errorf("withdraw native: %w", err)
}

c.logger.Info("success")
c.logger.Info("withdrawing to a non whitelisted address")

var zeroAddr common.Address

if err := target.Withdraw(ctx, "NativeToken", zeroAddr.String()); err == nil {
return errors.New("withdraw to non-whitelisted address expected to fail")
}

c.logger.Info("success")
c.logger.Info("withdrawing bzz...")

if err := target.Withdraw(ctx, "BZZ", o.TargetAddr); err != nil {
return fmt.Errorf("withdraw bzz: %w", err)
}

c.logger.Info("success")

return nil
}
1 change: 1 addition & 0 deletions pkg/config/bee.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ type BeeConfig struct {
Verbosity *uint64 `yaml:"verbosity"`
WelcomeMessage *string `yaml:"welcome-message"`
WarmupTime *time.Duration `yaml:"warmup-time"`
WithdrawAddress *string `yaml:"withdrawal-addresses-whitelist"`
}

// Export exports BeeConfig to orchestration.Config
Expand Down
19 changes: 19 additions & 0 deletions pkg/config/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/ethersphere/beekeeper/pkg/check/settlements"
"github.com/ethersphere/beekeeper/pkg/check/smoke"
"github.com/ethersphere/beekeeper/pkg/check/soc"
"github.com/ethersphere/beekeeper/pkg/check/withdraw"
"github.com/ethersphere/beekeeper/pkg/logging"
"github.com/ethersphere/beekeeper/pkg/random"
"gopkg.in/yaml.v3"
Expand Down Expand Up @@ -574,6 +575,24 @@ var Checks = map[string]CheckType{
return nil, fmt.Errorf("applying options: %w", err)
}

return opts, nil
},
},
"withdraw": {
NewAction: withdraw.NewCheck,
NewOptions: func(checkGlobalConfig CheckGlobalConfig, check Check) (interface{}, error) {
checkOpts := new(struct {
TargetAddr *string `yaml:"target-address"`
})
if err := check.Options.Decode(checkOpts); err != nil {
return nil, fmt.Errorf("decoding check %s options: %w", check.Type, err)
}
opts := withdraw.NewDefaultOptions()

if err := applyCheckConfig(checkGlobalConfig, checkOpts, &opts); err != nil {
return nil, fmt.Errorf("applying options: %w", err)
}

return opts, nil
},
},
Expand Down
1 change: 1 addition & 0 deletions pkg/orchestration/k8s/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ tracing-service-name: {{.TracingServiceName}}
verbosity: {{.Verbosity}}
welcome-message: {{.WelcomeMessage}}
warmup-time: {{.WarmupTime}}
withdrawal-addresses-whitelist: {{.WithdrawAddress}}
`
)

Expand Down
1 change: 1 addition & 0 deletions pkg/orchestration/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,5 @@ type Config struct {
Verbosity uint64 // log verbosity level 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=trace
WelcomeMessage string // send a welcome message string during handshakes
WarmupTime time.Duration // warmup time pull/pushsync protocols
WithdrawAddress string // allowed addresses for wallet withdrawal
}
34 changes: 34 additions & 0 deletions pkg/test/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"bytes"
"context"
"fmt"
"math/big"
"math/rand"
"time"

"github.com/ethersphere/bee/pkg/swarm"
"github.com/ethersphere/beekeeper/pkg/bee"
Expand Down Expand Up @@ -96,3 +98,35 @@ func (b *BeeV2) NewChunkUploader(ctx context.Context) (*ChunkUploader, error) {
logger: b.logger,
}, nil
}

type Wallet struct {
BZZ, Native *big.Int
}

const amount int64 = 1000000

func (b *BeeV2) Withdraw(ctx context.Context, token, addr string) error {
before, err := b.client.WalletBalance(ctx, token)
if err != nil {
return fmt.Errorf("(%s) wallet balance %w", b.name, err)
}

if err := b.client.Withdraw(ctx, token, addr, amount); err != nil {
return fmt.Errorf("(%s) withdraw balance %w", b.name, err)
}

time.Sleep(3 * time.Second)

after, err := b.client.WalletBalance(ctx, token)
if err != nil {
return fmt.Errorf("(%s) wallet balance %w", b.name, err)
}

want := big.NewInt(0).Sub(before, big.NewInt(amount))

if after.Cmp(want) > 0 {
return fmt.Errorf("incorrect balance after withdraw:\ngot %d\nwant %d", after, want)
}

return nil
}

0 comments on commit 518ab8a

Please sign in to comment.