Skip to content

Commit

Permalink
feat: alternative withdrawal address
Browse files Browse the repository at this point in the history
  • Loading branch information
notanatol committed Mar 7, 2024
1 parent d3d6685 commit d72bad4
Show file tree
Hide file tree
Showing 12 changed files with 247 additions and 99 deletions.
130 changes: 66 additions & 64 deletions cmd/bee/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,70 +22,71 @@ import (
)

const (
optionNameDataDir = "data-dir"
optionNameCacheCapacity = "cache-capacity"
optionNameDBOpenFilesLimit = "db-open-files-limit"
optionNameDBBlockCacheCapacity = "db-block-cache-capacity"
optionNameDBWriteBufferSize = "db-write-buffer-size"
optionNameDBDisableSeeksCompaction = "db-disable-seeks-compaction"
optionNamePassword = "password"
optionNamePasswordFile = "password-file"
optionNameAPIAddr = "api-addr"
optionNameP2PAddr = "p2p-addr"
optionNameNATAddr = "nat-addr"
optionNameP2PWSEnable = "p2p-ws-enable"
optionNameDebugAPIEnable = "debug-api-enable"
optionNameDebugAPIAddr = "debug-api-addr"
optionNameBootnodes = "bootnode"
optionNameNetworkID = "network-id"
optionWelcomeMessage = "welcome-message"
optionCORSAllowedOrigins = "cors-allowed-origins"
optionNameTracingEnabled = "tracing-enable"
optionNameTracingEndpoint = "tracing-endpoint"
optionNameTracingHost = "tracing-host"
optionNameTracingPort = "tracing-port"
optionNameTracingServiceName = "tracing-service-name"
optionNameVerbosity = "verbosity"
optionNamePaymentThreshold = "payment-threshold"
optionNamePaymentTolerance = "payment-tolerance-percent"
optionNamePaymentEarly = "payment-early-percent"
optionNameResolverEndpoints = "resolver-options"
optionNameBootnodeMode = "bootnode-mode"
optionNameClefSignerEnable = "clef-signer-enable"
optionNameClefSignerEndpoint = "clef-signer-endpoint"
optionNameClefSignerEthereumAddress = "clef-signer-ethereum-address"
optionNameSwapEndpoint = "swap-endpoint" // deprecated: use rpc endpoint instead
optionNameBlockchainRpcEndpoint = "blockchain-rpc-endpoint"
optionNameSwapFactoryAddress = "swap-factory-address"
optionNameSwapInitialDeposit = "swap-initial-deposit"
optionNameSwapEnable = "swap-enable"
optionNameChequebookEnable = "chequebook-enable"
optionNameSwapDeploymentGasPrice = "swap-deployment-gas-price"
optionNameFullNode = "full-node"
optionNamePostageContractAddress = "postage-stamp-address"
optionNamePostageContractStartBlock = "postage-stamp-start-block"
optionNamePriceOracleAddress = "price-oracle-address"
optionNameRedistributionAddress = "redistribution-address"
optionNameStakingAddress = "staking-address"
optionNameBlockTime = "block-time"
optionWarmUpTime = "warmup-time"
optionNameMainNet = "mainnet"
optionNameRetrievalCaching = "cache-retrieval"
optionNameDevReserveCapacity = "dev-reserve-capacity"
optionNameResync = "resync"
optionNamePProfBlock = "pprof-profile"
optionNamePProfMutex = "pprof-mutex"
optionNameStaticNodes = "static-nodes"
optionNameAllowPrivateCIDRs = "allow-private-cidrs"
optionNameSleepAfter = "sleep-after"
optionNameRestrictedAPI = "restricted"
optionNameTokenEncryptionKey = "token-encryption-key"
optionNameAdminPasswordHash = "admin-password"
optionNameUsePostageSnapshot = "use-postage-snapshot"
optionNameStorageIncentivesEnable = "storage-incentives-enable"
optionNameStateStoreCacheCapacity = "statestore-cache-capacity"
optionNameTargetNeighborhood = "target-neighborhood"
optionNameNeighborhoodSuggester = "neighborhood-suggester"
optionNameDataDir = "data-dir"
optionNameCacheCapacity = "cache-capacity"
optionNameDBOpenFilesLimit = "db-open-files-limit"
optionNameDBBlockCacheCapacity = "db-block-cache-capacity"
optionNameDBWriteBufferSize = "db-write-buffer-size"
optionNameDBDisableSeeksCompaction = "db-disable-seeks-compaction"
optionNamePassword = "password"
optionNamePasswordFile = "password-file"
optionNameAPIAddr = "api-addr"
optionNameP2PAddr = "p2p-addr"
optionNameNATAddr = "nat-addr"
optionNameP2PWSEnable = "p2p-ws-enable"
optionNameDebugAPIEnable = "debug-api-enable"
optionNameDebugAPIAddr = "debug-api-addr"
optionNameBootnodes = "bootnode"
optionNameNetworkID = "network-id"
optionWelcomeMessage = "welcome-message"
optionCORSAllowedOrigins = "cors-allowed-origins"
optionNameTracingEnabled = "tracing-enable"
optionNameTracingEndpoint = "tracing-endpoint"
optionNameTracingHost = "tracing-host"
optionNameTracingPort = "tracing-port"
optionNameTracingServiceName = "tracing-service-name"
optionNameVerbosity = "verbosity"
optionNamePaymentThreshold = "payment-threshold"
optionNamePaymentTolerance = "payment-tolerance-percent"
optionNamePaymentEarly = "payment-early-percent"
optionNameResolverEndpoints = "resolver-options"
optionNameBootnodeMode = "bootnode-mode"
optionNameClefSignerEnable = "clef-signer-enable"
optionNameClefSignerEndpoint = "clef-signer-endpoint"
optionNameClefSignerEthereumAddress = "clef-signer-ethereum-address"
optionNameSwapEndpoint = "swap-endpoint" // deprecated: use rpc endpoint instead
optionNameBlockchainRpcEndpoint = "blockchain-rpc-endpoint"
optionNameSwapFactoryAddress = "swap-factory-address"
optionNameSwapInitialDeposit = "swap-initial-deposit"
optionNameSwapEnable = "swap-enable"
optionNameChequebookEnable = "chequebook-enable"
optionNameSwapDeploymentGasPrice = "swap-deployment-gas-price"
optionNameFullNode = "full-node"
optionNamePostageContractAddress = "postage-stamp-address"
optionNamePostageContractStartBlock = "postage-stamp-start-block"
optionNamePriceOracleAddress = "price-oracle-address"
optionNameRedistributionAddress = "redistribution-address"
optionNameStakingAddress = "staking-address"
optionNameBlockTime = "block-time"
optionWarmUpTime = "warmup-time"
optionNameMainNet = "mainnet"
optionNameRetrievalCaching = "cache-retrieval"
optionNameDevReserveCapacity = "dev-reserve-capacity"
optionNameResync = "resync"
optionNamePProfBlock = "pprof-profile"
optionNamePProfMutex = "pprof-mutex"
optionNameStaticNodes = "static-nodes"
optionNameAllowPrivateCIDRs = "allow-private-cidrs"
optionNameSleepAfter = "sleep-after"
optionNameRestrictedAPI = "restricted"
optionNameTokenEncryptionKey = "token-encryption-key"
optionNameAdminPasswordHash = "admin-password"
optionNameUsePostageSnapshot = "use-postage-snapshot"
optionNameStorageIncentivesEnable = "storage-incentives-enable"
optionNameStateStoreCacheCapacity = "statestore-cache-capacity"
optionNameTargetNeighborhood = "target-neighborhood"
optionNameNeighborhoodSuggester = "neighborhood-suggester"
optionNameWhitelistedWithdrawalAddress = "withdrawal-address"
)

// nolint:gochecknoinits
Expand Down Expand Up @@ -304,6 +305,7 @@ func (c *command) setAllFlags(cmd *cobra.Command) {
cmd.Flags().Uint64(optionNameStateStoreCacheCapacity, 100_000, "lru memory caching capacity in number of statestore entries")
cmd.Flags().String(optionNameTargetNeighborhood, "", "neighborhood to target in binary format (ex: 111111001) for mining the initial overlay")
cmd.Flags().String(optionNameNeighborhoodSuggester, "https://api.swarmscan.io/v1/network/neighborhoods/suggestion", "suggester for target neighborhood")
cmd.Flags().String(optionNameWhitelistedWithdrawalAddress, "", "Withdrawal target address")
}

func newLogger(cmd *cobra.Command, verbosity string) (log.Logger, error) {
Expand Down
1 change: 1 addition & 0 deletions cmd/bee/cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ func buildBeeNode(ctx context.Context, c *command, cmd *cobra.Command, logger lo
StatestoreCacheCapacity: c.config.GetUint64(optionNameStateStoreCacheCapacity),
TargetNeighborhood: c.config.GetString(optionNameTargetNeighborhood),
NeighborhoodSuggester: c.config.GetString(optionNameNeighborhoodSuggester),
WhitelistedWithdrawalAddress: c.config.GetStringSlice(optionNameWhitelistedWithdrawalAddress),
})

return b, err
Expand Down
7 changes: 7 additions & 0 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ type Service struct {
erc20Service erc20.Service
chainID int64

whitelistedWithdrawalAddress []common.Address

preMapHooks map[string]func(v string) (string, error)
validate *validator.Validate

Expand Down Expand Up @@ -254,6 +256,7 @@ type ExtraOptions struct {
func New(
publicKey, pssPublicKey ecdsa.PublicKey,
ethereumAddress common.Address,
whitelistedWithdrawalAddress []string,
logger log.Logger,
transaction transaction.Service,
batchStore postage.Storer,
Expand Down Expand Up @@ -303,6 +306,10 @@ func New(
})
s.stamperStore = stamperStore

for _, v := range whitelistedWithdrawalAddress {
s.whitelistedWithdrawalAddress = append(s.whitelistedWithdrawalAddress, common.HexToAddress(v))
}

return s
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ func newTestServer(t *testing.T, o testServerOptions) (*http.Client, *websocket.
o.BeeMode = api.FullMode
}

s := api.New(o.PublicKey, o.PSSPublicKey, o.EthereumAddress, o.Logger, transaction, o.BatchStore, o.BeeMode, true, true, backend, o.CORSAllowedOrigins, inmemstore.New())
s := api.New(o.PublicKey, o.PSSPublicKey, o.EthereumAddress, nil, o.Logger, transaction, o.BatchStore, o.BeeMode, true, true, backend, o.CORSAllowedOrigins, inmemstore.New())
testutil.CleanupCloser(t, s)

s.SetP2P(o.P2P)
Expand Down Expand Up @@ -395,7 +395,7 @@ func TestParseName(t *testing.T) {
pk, _ := crypto.GenerateSecp256k1Key()
signer := crypto.NewDefaultSigner(pk)

s := api.New(pk.PublicKey, pk.PublicKey, common.Address{}, log, nil, nil, 1, false, false, nil, []string{"*"}, inmemstore.New())
s := api.New(pk.PublicKey, pk.PublicKey, common.Address{}, nil, log, nil, nil, 1, false, false, nil, []string{"*"}, inmemstore.New())
s.Configure(signer, nil, nil, api.Options{}, api.ExtraOptions{Resolver: tC.res}, 1, nil)
s.MountAPI()

Expand Down
6 changes: 6 additions & 0 deletions pkg/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,12 @@ func (s *Service) mountBusinessDebug(restricted bool) {
handle("/wallet", jsonhttp.MethodHandler{
"GET": http.HandlerFunc(s.walletHandler),
})
handle("/wallet/withdraw/{coin}/{addr}", jsonhttp.MethodHandler{
"POST": web.ChainHandlers(
s.gasConfigMiddleware("wallet withdraw"),
web.FinalHandlerFunc(s.walletWithdrawHandler),
),
})
}
}

Expand Down
94 changes: 94 additions & 0 deletions pkg/api/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@
package api

import (
"context"
"math/big"
"net/http"

"slices"

"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/bee/pkg/bigint"
"github.com/ethersphere/bee/pkg/jsonhttp"
"github.com/ethersphere/bee/pkg/transaction"
"github.com/gorilla/mux"
)

type walletResponse struct {
Expand All @@ -20,6 +26,10 @@ type walletResponse struct {
WalletAddress common.Address `json:"walletAddress"` // the address of the bee wallet
}

type walletTxResponse struct {
TransactionHash common.Hash `json:"transactionHash"`
}

func (s *Service) walletHandler(w http.ResponseWriter, r *http.Request) {
logger := s.logger.WithName("get_wallet").Build()

Expand Down Expand Up @@ -47,3 +57,87 @@ func (s *Service) walletHandler(w http.ResponseWriter, r *http.Request) {
WalletAddress: s.ethereumAddress,
})
}

func (s *Service) walletWithdrawHandler(w http.ResponseWriter, r *http.Request) {
logger := s.logger.WithName("post_wallet_withdraw").Build()

queries := struct {
Amount *big.Int `map:"amount" validate:"required"`
}{}

if response := s.mapStructure(r.URL.Query(), &queries); response != nil {
response("invalid query params", logger, w)
return
}

path := struct {
Coin *string `map:"coin" validate:"required"`
Address *common.Address `map:"address" validate:"required"`
}{}

if response := s.mapStructure(mux.Vars(r), &path); response != nil {
response("invalid query params", logger, w)
return
}

ctx := r.Context()
var bzz bool
// check if coin is xdai or bzz

if !slices.Contains(s.whitelistedWithdrawalAddress, *path.Address) {
logger.Error(nil, "provided address not whitelisted")
jsonhttp.InternalServerError(w, "provided address not whitelisted")
return
}

if bzz {
currentBalance, err := s.erc20Service.BalanceOf(ctx, s.ethereumAddress)
if err != nil {
logger.Error(err, "unable to get balance")
jsonhttp.InternalServerError(w, "unable to get balance")
return
}

if queries.Amount.Cmp(currentBalance) > 0 {
logger.Error(err, "not enough balance")
jsonhttp.InternalServerError(w, "not enough balance")
return
}

txHash, err := s.erc20Service.Withdraw(ctx, *path.Address, queries.Amount)
if err != nil {
logger.Error(err, "unable to transfer")
jsonhttp.InternalServerError(w, "unable to transfer amount")
return
}
jsonhttp.OK(w, walletTxResponse{TransactionHash: txHash})
return
}

nativeToken, err := s.chainBackend.BalanceAt(r.Context(), s.ethereumAddress, nil)
if err != nil {
logger.Debug("unable to acquire balance from the chain backend", "error", err)
logger.Error(nil, "unable to acquire balance from the chain backend")
jsonhttp.InternalServerError(w, "unable to acquire balance from the chain backend")
return
}

if queries.Amount.Cmp(nativeToken) > 0 {
logger.Error(err, "not enough balance")
jsonhttp.InternalServerError(w, "not enough balance")
return
}

txHash, err := withdraw(ctx, s.chainBackend, *path.Address, queries.Amount)
if err != nil {
logger.Error(err, "withdraw")
jsonhttp.InternalServerError(w, "withdraw")
return
}

jsonhttp.OK(w, walletTxResponse{TransactionHash: txHash})
}

func withdraw(context.Context, transaction.Backend, common.Address, *big.Int) (common.Hash, error) {
return common.Hash{}, nil
}
4 changes: 2 additions & 2 deletions pkg/node/devnode.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func NewDevBee(logger log.Logger, o *DevOptions) (b *DevBee, err error) {
return nil, fmt.Errorf("debug api listener: %w", err)
}

debugApiService = api.New(mockKey.PublicKey, mockKey.PublicKey, overlayEthAddress, logger, mockTransaction, batchStore, api.DevMode, true, true, chainBackend, o.CORSAllowedOrigins, inmemstore.New())
debugApiService = api.New(mockKey.PublicKey, mockKey.PublicKey, overlayEthAddress, nil, logger, mockTransaction, batchStore, api.DevMode, true, true, chainBackend, o.CORSAllowedOrigins, inmemstore.New())
debugAPIServer := &http.Server{
IdleTimeout: 30 * time.Second,
ReadHeaderTimeout: 3 * time.Second,
Expand Down Expand Up @@ -398,7 +398,7 @@ func NewDevBee(logger log.Logger, o *DevOptions) (b *DevBee, err error) {
}),
)

apiService := api.New(mockKey.PublicKey, mockKey.PublicKey, overlayEthAddress, logger, mockTransaction, batchStore, api.DevMode, true, true, chainBackend, o.CORSAllowedOrigins, inmemstore.New())
apiService := api.New(mockKey.PublicKey, mockKey.PublicKey, overlayEthAddress, nil, logger, mockTransaction, batchStore, api.DevMode, true, true, chainBackend, o.CORSAllowedOrigins, inmemstore.New())

apiService.Configure(signer, authenticator, tracer, api.Options{
CORSAllowedOrigins: o.CORSAllowedOrigins,
Expand Down
5 changes: 4 additions & 1 deletion pkg/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ type Options struct {
StatestoreCacheCapacity uint64
TargetNeighborhood string
NeighborhoodSuggester string
WhitelistedWithdrawalAddress []string
}

const (
Expand Down Expand Up @@ -421,6 +422,7 @@ func NewBee(
*publicKey,
pssPrivateKey.PublicKey,
overlayEthAddress,
o.WhitelistedWithdrawalAddress,
logger,
transactionService,
batchStore,
Expand Down Expand Up @@ -460,6 +462,7 @@ func NewBee(
*publicKey,
pssPrivateKey.PublicKey,
overlayEthAddress,
o.WhitelistedWithdrawalAddress,
logger,
transactionService,
batchStore,
Expand Down Expand Up @@ -1094,7 +1097,7 @@ func NewBee(

if o.APIAddr != "" {
if apiService == nil {
apiService = api.New(*publicKey, pssPrivateKey.PublicKey, overlayEthAddress, logger, transactionService, batchStore, beeNodeMode, o.ChequebookEnable, o.SwapEnable, chainBackend, o.CORSAllowedOrigins, stamperStore)
apiService = api.New(*publicKey, pssPrivateKey.PublicKey, overlayEthAddress, o.WhitelistedWithdrawalAddress, logger, transactionService, batchStore, beeNodeMode, o.ChequebookEnable, o.SwapEnable, chainBackend, o.CORSAllowedOrigins, stamperStore)
apiService.SetProbe(probe)
apiService.SetRedistributionAgent(agent)
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/settlement/swap/chequebook/chequebook.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ type service struct {
lock sync.Mutex
transactionService transaction.Service

address common.Address
address common.Address

contract *chequebookContract
ownerAddress common.Address

Expand Down
Loading

0 comments on commit d72bad4

Please sign in to comment.