Skip to content
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

refactor(SPV-1213): Admin API access with user xpubs implementation. #20

Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ linters-settings:
wrapcheck:
ignoreSigRegexps:
- spverrors\.(Newf|Wrapf)
- errutil\.HTTPErrorFormatter
ignorePackageGlobs:
- "github.com/go-ozzo/ozzo-validation"
revive:
Expand Down
84 changes: 84 additions & 0 deletions admin_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package spvwallet

import (
"context"
"fmt"
"net/url"

bip32 "github.com/bitcoin-sv/go-sdk/compat/bip32"
"github.com/bitcoin-sv/spv-wallet-go-client/commands"
"github.com/bitcoin-sv/spv-wallet-go-client/config"
xpubs "github.com/bitcoin-sv/spv-wallet-go-client/internal/api/v1/admin/users"
"github.com/bitcoin-sv/spv-wallet-go-client/internal/auth"
"github.com/bitcoin-sv/spv-wallet-go-client/internal/restyutil"
"github.com/bitcoin-sv/spv-wallet-go-client/queries"
"github.com/bitcoin-sv/spv-wallet/models/response"
)

// AdminAPI provides a simplified interface for interacting with admin-related APIs.
// It abstracts the complexities of making HTTP requests and handling responses,
// allowing developers to easily interact with admin API endpoints.
//
// A zero-value AdminAPI is not usable. Use the NewAdminAPI function to create
// a properly initialized instance.
//
// Methods may return wrapped errors, including models.SPVError or
// ErrUnrecognizedAPIResponse, depending on the behavior of the SPV Wallet API.
type AdminAPI struct {
xpubsAPI *xpubs.API // Internal API for managing operations related to XPubs.
}

// CreateXPub creates a new XPub record via the Admin XPubs API.
// The provided command contains the necessary parameters to define the XPub record.
//
// The API response is unmarshaled into a *response.Xpub struct.
// Returns an error if the API request fails or the response cannot be decoded.
func (a *AdminAPI) CreateXPub(ctx context.Context, cmd *commands.CreateUserXpub) (*response.Xpub, error) {
res, err := a.xpubsAPI.CreateXPub(ctx, cmd)
if err != nil {
return nil, xpubs.HTTPErrorFormatter("failed to create XPub", err).FormatPostErr()
}

return res, nil
}

// XPubs retrieves a paginated list of user XPubs via the Admin XPubs API.
// The response includes user XPubs along with pagination metadata, such as
// the current page number, sort order, and the field used for sorting (sortBy).
//
// Query parameters can be configured using optional query options. These options allow
// filtering based on metadata, pagination settings, or specific XPub attributes.
//
// The API response is unmarshaled into a *queries.XPubPage struct.
// Returns an error if the API request fails or the response cannot be decoded.
func (a *AdminAPI) XPubs(ctx context.Context, opts ...queries.XPubQueryOption) (*queries.XPubPage, error) {
res, err := a.xpubsAPI.XPubs(ctx, opts...)
if err != nil {
return nil, xpubs.HTTPErrorFormatter("failed to retrieve XPubs page", err).FormatGetErr()
}

return res, nil
}

// NewAdminAPI initializes a new instance of AdminAPI.
// It configures the API client using the provided configuration and xPub key for authentication.
// If any step fails, an appropriate error is returned.
func NewAdminAPI(cfg config.Config, xPub string) (*AdminAPI, error) {
mgosek-4chain marked this conversation as resolved.
Show resolved Hide resolved
url, err := url.Parse(cfg.Addr)
if err != nil {
return nil, fmt.Errorf("failed to parse address as url.URL: %w", err)
}

key, err := bip32.GetHDKeyFromExtendedPublicKey(xPub)
if err != nil {
return nil, fmt.Errorf("failed to generate HD key from xPub: %w", err)
}

authenticator, err := auth.NewXpubOnlyAuthenticator(key)
if err != nil {
return nil, fmt.Errorf("failed to initialize xPub authenticator: %w", err)
}

httpClient := restyutil.NewHTTPClient(cfg, authenticator)
return &AdminAPI{xpubsAPI: xpubs.NewAPI(url, httpClient)}, nil
}
Loading
Loading