diff --git a/authentication.go b/authentication.go index a8389d85..7e226e03 100644 --- a/authentication.go +++ b/authentication.go @@ -17,7 +17,7 @@ import ( ) // SetSignature will set the signature on the header for the request -func setSignature(header *http.Header, xPriv *bip32.ExtendedKey, bodyString string) *models.SPVError { +func setSignature(header *http.Header, xPriv *bip32.ExtendedKey, bodyString string) error { // Create the signature authData, err := createSignature(xPriv, bodyString) if err != nil { @@ -135,7 +135,7 @@ func getUnlockingScript(tx *bt.Tx, inputIndex uint32, privateKey *bec.PrivateKey func createSignature(xPriv *bip32.ExtendedKey, bodyString string) (payload *models.AuthPayload, err error) { // No key? if xPriv == nil { - err = CreateErrorResponse("error-unauthorized-missing-xpriv", "missing xpriv") + err = ErrMissingXpriv return } diff --git a/errors.go b/errors.go index 3cb84969..eb0bd5d4 100644 --- a/errors.go +++ b/errors.go @@ -2,16 +2,18 @@ package walletclient import ( "encoding/json" - "errors" "github.com/bitcoin-sv/spv-wallet/models" "net/http" ) // ErrAdminKey admin key not set -var ErrAdminKey = errors.New("an admin key must be set to be able to create an xpub") +var ErrAdminKey = models.SPVError{Message: "an admin key must be set to be able to create an xpub", StatusCode: 401, Code: "error-unauthorized-admin-key-not-set"} -// ErrNoClientSet is when no client is set -var ErrNoClientSet = errors.New("no transport client set") +// ErrMissingXpriv is when xpriv is missing +var ErrMissingXpriv = models.SPVError{Message: "xpriv missing", StatusCode: 401, Code: "error-unauthorized-xpriv-missing"} + +// ErrCouldNotFindDraftTransaction is when draft transaction is not found +var ErrCouldNotFindDraftTransaction = models.SPVError{Message: "could not find draft transaction", StatusCode: 404, Code: "error-draft-transaction-not-found"} // WrapError wraps an error into SPVError func WrapError(err error) *models.SPVError { diff --git a/examples/go.sum b/examples/go.sum index c3a93437..76d7b5ab 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -1,5 +1,6 @@ github.com/bitcoin-sv/spv-wallet/models v1.0.0-beta.13 h1:rBscs3Gbz0RWY03eI3Z9AwD7/MxajdJF54oy3xMqKRQ= github.com/bitcoin-sv/spv-wallet/models v1.0.0-beta.13/go.mod h1:i3txysriHpprqYd3u97wEQsC4/jn+KHcyFOmuFYMw8M= +github.com/bitcoin-sv/spv-wallet/models v1.0.0-beta.14.0.20240626082725-2c073c5330a6 h1:ZTEHuSNbXszs+5TKN0uiW6DY7JdWIM5m6NQpBJZyre4= github.com/bitcoin-sv/spv-wallet/models v1.0.0-beta.14.0.20240626082725-2c073c5330a6/go.mod h1:u3gnRDS3uHWZNM2qbYATTpN+mAphyozCJrYIKGwBX7k= github.com/bitcoinschema/go-bitcoin/v2 v2.0.5 h1:Sgh5Eb746Zck/46rFDrZZEXZWyO53fMuWYhNoZa1tck= github.com/bitcoinschema/go-bitcoin/v2 v2.0.5/go.mod h1:JjO1ivfZv6vhK0uAXzyH08AAHlzNMAfnyK1Fiv9r4ZA= diff --git a/http.go b/http.go index 65a2765d..565ec953 100644 --- a/http.go +++ b/http.go @@ -7,6 +7,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/bitcoinschema/go-bitcoin/v2" "net/http" "strconv" @@ -33,7 +34,7 @@ func (wc *WalletClient) SetAdminKey(adminKey *bip32.ExtendedKey) { } // GetXPub will get the xpub of the current xpub -func (wc *WalletClient) GetXPub(ctx context.Context) (*models.Xpub, *models.SPVError) { +func (wc *WalletClient) GetXPub(ctx context.Context) (*models.Xpub, error) { var xPub models.Xpub if err := wc.doHTTPRequest( ctx, http.MethodGet, "/xpub", nil, wc.xPriv, true, &xPub, @@ -45,7 +46,7 @@ func (wc *WalletClient) GetXPub(ctx context.Context) (*models.Xpub, *models.SPVE } // UpdateXPubMetadata update the metadata of the logged in xpub -func (wc *WalletClient) UpdateXPubMetadata(ctx context.Context, metadata map[string]any) (*models.Xpub, *models.SPVError) { +func (wc *WalletClient) UpdateXPubMetadata(ctx context.Context, metadata map[string]any) (*models.Xpub, error) { jsonStr, err := json.Marshal(map[string]interface{}{ FieldMetadata: metadata, }) @@ -64,7 +65,7 @@ func (wc *WalletClient) UpdateXPubMetadata(ctx context.Context, metadata map[str } // GetAccessKey will get an access key by id -func (wc *WalletClient) GetAccessKey(ctx context.Context, id string) (*models.AccessKey, *models.SPVError) { +func (wc *WalletClient) GetAccessKey(ctx context.Context, id string) (*models.AccessKey, error) { var accessKey models.AccessKey if err := wc.doHTTPRequest( ctx, http.MethodGet, "/access-key?"+FieldID+"="+id, nil, wc.xPriv, true, &accessKey, @@ -81,7 +82,7 @@ func (wc *WalletClient) GetAccessKeys( conditions *filter.AccessKeyFilter, metadata map[string]any, queryParams *filter.QueryParams, -) ([]*models.AccessKey, *models.SPVError) { +) ([]*models.AccessKey, error) { return Search[filter.AccessKeyFilter, []*models.AccessKey]( ctx, http.MethodPost, "/access-key/search", @@ -98,7 +99,7 @@ func (wc *WalletClient) GetAccessKeysCount( ctx context.Context, conditions *filter.AccessKeyFilter, metadata map[string]any, -) (int64, *models.SPVError) { +) (int64, error) { return Count[filter.AccessKeyFilter]( ctx, http.MethodPost, "/access-key/count", @@ -110,7 +111,7 @@ func (wc *WalletClient) GetAccessKeysCount( } // RevokeAccessKey will revoke an access key by id -func (wc *WalletClient) RevokeAccessKey(ctx context.Context, id string) (*models.AccessKey, *models.SPVError) { +func (wc *WalletClient) RevokeAccessKey(ctx context.Context, id string) (*models.AccessKey, error) { var accessKey models.AccessKey if err := wc.doHTTPRequest( ctx, http.MethodDelete, "/access-key?"+FieldID+"="+id, nil, wc.xPriv, true, &accessKey, @@ -122,7 +123,7 @@ func (wc *WalletClient) RevokeAccessKey(ctx context.Context, id string) (*models } // CreateAccessKey will create new access key -func (wc *WalletClient) CreateAccessKey(ctx context.Context, metadata map[string]any) (*models.AccessKey, *models.SPVError) { +func (wc *WalletClient) CreateAccessKey(ctx context.Context, metadata map[string]any) (*models.AccessKey, error) { jsonStr, err := json.Marshal(map[string]interface{}{ FieldMetadata: metadata, }) @@ -140,7 +141,7 @@ func (wc *WalletClient) CreateAccessKey(ctx context.Context, metadata map[string } // GetDestinationByID will get a destination by id -func (wc *WalletClient) GetDestinationByID(ctx context.Context, id string) (*models.Destination, *models.SPVError) { +func (wc *WalletClient) GetDestinationByID(ctx context.Context, id string) (*models.Destination, error) { var destination models.Destination if err := wc.doHTTPRequest( ctx, http.MethodGet, fmt.Sprintf("/destination?%s=%s", FieldID, id), nil, wc.xPriv, true, &destination, @@ -152,7 +153,7 @@ func (wc *WalletClient) GetDestinationByID(ctx context.Context, id string) (*mod } // GetDestinationByAddress will get a destination by address -func (wc *WalletClient) GetDestinationByAddress(ctx context.Context, address string) (*models.Destination, *models.SPVError) { +func (wc *WalletClient) GetDestinationByAddress(ctx context.Context, address string) (*models.Destination, error) { var destination models.Destination if err := wc.doHTTPRequest( ctx, http.MethodGet, "/destination?"+FieldAddress+"="+address, nil, wc.xPriv, true, &destination, @@ -164,7 +165,7 @@ func (wc *WalletClient) GetDestinationByAddress(ctx context.Context, address str } // GetDestinationByLockingScript will get a destination by locking script -func (wc *WalletClient) GetDestinationByLockingScript(ctx context.Context, lockingScript string) (*models.Destination, *models.SPVError) { +func (wc *WalletClient) GetDestinationByLockingScript(ctx context.Context, lockingScript string) (*models.Destination, error) { var destination models.Destination if err := wc.doHTTPRequest( ctx, http.MethodGet, "/destination?"+FieldLockingScript+"="+lockingScript, nil, wc.xPriv, true, &destination, @@ -176,7 +177,7 @@ func (wc *WalletClient) GetDestinationByLockingScript(ctx context.Context, locki } // GetDestinations will get all destinations matching the metadata filter -func (wc *WalletClient) GetDestinations(ctx context.Context, conditions *filter.DestinationFilter, metadata map[string]any, queryParams *filter.QueryParams) ([]*models.Destination, *models.SPVError) { +func (wc *WalletClient) GetDestinations(ctx context.Context, conditions *filter.DestinationFilter, metadata map[string]any, queryParams *filter.QueryParams) ([]*models.Destination, error) { return Search[filter.DestinationFilter, []*models.Destination]( ctx, http.MethodPost, "/destination/search", @@ -189,7 +190,7 @@ func (wc *WalletClient) GetDestinations(ctx context.Context, conditions *filter. } // GetDestinationsCount will get the count of destinations matching the metadata filter -func (wc *WalletClient) GetDestinationsCount(ctx context.Context, conditions *filter.DestinationFilter, metadata map[string]any) (int64, *models.SPVError) { +func (wc *WalletClient) GetDestinationsCount(ctx context.Context, conditions *filter.DestinationFilter, metadata map[string]any) (int64, error) { return Count( ctx, http.MethodPost, @@ -202,7 +203,7 @@ func (wc *WalletClient) GetDestinationsCount(ctx context.Context, conditions *fi } // NewDestination will create a new destination and return it -func (wc *WalletClient) NewDestination(ctx context.Context, metadata map[string]any) (*models.Destination, *models.SPVError) { +func (wc *WalletClient) NewDestination(ctx context.Context, metadata map[string]any) (*models.Destination, error) { jsonStr, err := json.Marshal(map[string]interface{}{ FieldMetadata: metadata, }) @@ -220,7 +221,7 @@ func (wc *WalletClient) NewDestination(ctx context.Context, metadata map[string] } // UpdateDestinationMetadataByID updates the destination metadata by id -func (wc *WalletClient) UpdateDestinationMetadataByID(ctx context.Context, id string, metadata map[string]any) (*models.Destination, *models.SPVError) { +func (wc *WalletClient) UpdateDestinationMetadataByID(ctx context.Context, id string, metadata map[string]any) (*models.Destination, error) { jsonStr, err := json.Marshal(map[string]interface{}{ FieldID: id, FieldMetadata: metadata, @@ -240,7 +241,7 @@ func (wc *WalletClient) UpdateDestinationMetadataByID(ctx context.Context, id st } // UpdateDestinationMetadataByAddress updates the destination metadata by address -func (wc *WalletClient) UpdateDestinationMetadataByAddress(ctx context.Context, address string, metadata map[string]any) (*models.Destination, *models.SPVError) { +func (wc *WalletClient) UpdateDestinationMetadataByAddress(ctx context.Context, address string, metadata map[string]any) (*models.Destination, error) { jsonStr, err := json.Marshal(map[string]interface{}{ FieldAddress: address, FieldMetadata: metadata, @@ -260,7 +261,7 @@ func (wc *WalletClient) UpdateDestinationMetadataByAddress(ctx context.Context, } // UpdateDestinationMetadataByLockingScript updates the destination metadata by locking script -func (wc *WalletClient) UpdateDestinationMetadataByLockingScript(ctx context.Context, lockingScript string, metadata map[string]any) (*models.Destination, *models.SPVError) { +func (wc *WalletClient) UpdateDestinationMetadataByLockingScript(ctx context.Context, lockingScript string, metadata map[string]any) (*models.Destination, error) { jsonStr, err := json.Marshal(map[string]interface{}{ FieldLockingScript: lockingScript, FieldMetadata: metadata, @@ -280,7 +281,7 @@ func (wc *WalletClient) UpdateDestinationMetadataByLockingScript(ctx context.Con } // GetTransaction will get a transaction by ID -func (wc *WalletClient) GetTransaction(ctx context.Context, txID string) (*models.Transaction, *models.SPVError) { +func (wc *WalletClient) GetTransaction(ctx context.Context, txID string) (*models.Transaction, error) { var transaction models.Transaction if err := wc.doHTTPRequest(ctx, http.MethodGet, "/transaction?"+FieldID+"="+txID, nil, wc.xPriv, wc.signRequest, &transaction); err != nil { return nil, err @@ -295,7 +296,7 @@ func (wc *WalletClient) GetTransactions( conditions *filter.TransactionFilter, metadata map[string]any, queryParams *filter.QueryParams, -) ([]*models.Transaction, *models.SPVError) { +) ([]*models.Transaction, error) { return Search[filter.TransactionFilter, []*models.Transaction]( ctx, http.MethodPost, "/transaction/search", @@ -312,7 +313,7 @@ func (wc *WalletClient) GetTransactionsCount( ctx context.Context, conditions *filter.TransactionFilter, metadata map[string]any, -) (int64, *models.SPVError) { +) (int64, error) { return Count[filter.TransactionFilter]( ctx, http.MethodPost, "/transaction/count", @@ -324,7 +325,7 @@ func (wc *WalletClient) GetTransactionsCount( } // DraftToRecipients is a draft transaction to a slice of recipients -func (wc *WalletClient) DraftToRecipients(ctx context.Context, recipients []*Recipients, metadata map[string]any) (*models.DraftTransaction, *models.SPVError) { +func (wc *WalletClient) DraftToRecipients(ctx context.Context, recipients []*Recipients, metadata map[string]any) (*models.DraftTransaction, error) { outputs := make([]map[string]interface{}, 0) for _, recipient := range recipients { outputs = append(outputs, map[string]interface{}{ @@ -343,7 +344,7 @@ func (wc *WalletClient) DraftToRecipients(ctx context.Context, recipients []*Rec } // DraftTransaction is a draft transaction -func (wc *WalletClient) DraftTransaction(ctx context.Context, transactionConfig *models.TransactionConfig, metadata map[string]any) (*models.DraftTransaction, *models.SPVError) { +func (wc *WalletClient) DraftTransaction(ctx context.Context, transactionConfig *models.TransactionConfig, metadata map[string]any) (*models.DraftTransaction, error) { return wc.createDraftTransaction(ctx, map[string]interface{}{ FieldConfig: transactionConfig, FieldMetadata: metadata, @@ -353,7 +354,7 @@ func (wc *WalletClient) DraftTransaction(ctx context.Context, transactionConfig // createDraftTransaction will create a draft transaction func (wc *WalletClient) createDraftTransaction(ctx context.Context, jsonData map[string]interface{}, -) (*models.DraftTransaction, *models.SPVError) { +) (*models.DraftTransaction, error) { jsonStr, err := json.Marshal(jsonData) if err != nil { return nil, WrapError(err) @@ -366,14 +367,14 @@ func (wc *WalletClient) createDraftTransaction(ctx context.Context, return nil, err } if draftTransaction == nil { - return nil, CreateErrorResponse("error-draft-transaction-not-found", "draft transaction not found") + return nil, ErrCouldNotFindDraftTransaction } return draftTransaction, nil } // RecordTransaction will record a transaction -func (wc *WalletClient) RecordTransaction(ctx context.Context, hex, referenceID string, metadata map[string]any) (*models.Transaction, *models.SPVError) { +func (wc *WalletClient) RecordTransaction(ctx context.Context, hex, referenceID string, metadata map[string]any) (*models.Transaction, error) { jsonStr, err := json.Marshal(map[string]interface{}{ FieldHex: hex, FieldReferenceID: referenceID, @@ -394,7 +395,7 @@ func (wc *WalletClient) RecordTransaction(ctx context.Context, hex, referenceID } // UpdateTransactionMetadata update the metadata of a transaction -func (wc *WalletClient) UpdateTransactionMetadata(ctx context.Context, txID string, metadata map[string]any) (*models.Transaction, *models.SPVError) { +func (wc *WalletClient) UpdateTransactionMetadata(ctx context.Context, txID string, metadata map[string]any) (*models.Transaction, error) { jsonStr, err := json.Marshal(map[string]interface{}{ FieldID: txID, FieldMetadata: metadata, @@ -414,7 +415,7 @@ func (wc *WalletClient) UpdateTransactionMetadata(ctx context.Context, txID stri } // SetSignatureFromAccessKey will set the signature on the header for the request from an access key -func SetSignatureFromAccessKey(header *http.Header, privateKeyHex, bodyString string) *models.SPVError { +func SetSignatureFromAccessKey(header *http.Header, privateKeyHex, bodyString string) error { // Create the signature authData, err := createSignatureAccessKey(privateKeyHex, bodyString) if err != nil { @@ -430,7 +431,7 @@ func SetSignatureFromAccessKey(header *http.Header, privateKeyHex, bodyString st } // GetUtxo will get a utxo by transaction ID -func (wc *WalletClient) GetUtxo(ctx context.Context, txID string, outputIndex uint32) (*models.Utxo, *models.SPVError) { +func (wc *WalletClient) GetUtxo(ctx context.Context, txID string, outputIndex uint32) (*models.Utxo, error) { outputIndexStr := strconv.FormatUint(uint64(outputIndex), 10) url := fmt.Sprintf("/utxo?%s=%s&%s=%s", FieldTransactionID, txID, FieldOutputIndex, outputIndexStr) @@ -446,7 +447,7 @@ func (wc *WalletClient) GetUtxo(ctx context.Context, txID string, outputIndex ui } // GetUtxos will get a list of utxos filtered by conditions and metadata -func (wc *WalletClient) GetUtxos(ctx context.Context, conditions *filter.UtxoFilter, metadata map[string]any, queryParams *filter.QueryParams) ([]*models.Utxo, *models.SPVError) { +func (wc *WalletClient) GetUtxos(ctx context.Context, conditions *filter.UtxoFilter, metadata map[string]any, queryParams *filter.QueryParams) ([]*models.Utxo, error) { return Search[filter.UtxoFilter, []*models.Utxo]( ctx, http.MethodPost, "/utxo/search", @@ -459,7 +460,7 @@ func (wc *WalletClient) GetUtxos(ctx context.Context, conditions *filter.UtxoFil } // GetUtxosCount will get the count of utxos filtered by conditions and metadata -func (wc *WalletClient) GetUtxosCount(ctx context.Context, conditions *filter.UtxoFilter, metadata map[string]any) (int64, *models.SPVError) { +func (wc *WalletClient) GetUtxosCount(ctx context.Context, conditions *filter.UtxoFilter, metadata map[string]any) (int64, error) { return Count[filter.UtxoFilter]( ctx, http.MethodPost, "/utxo/count", @@ -503,7 +504,7 @@ func createSignatureAccessKey(privateKeyHex, bodyString string) (payload *models // doHTTPRequest will create and submit the HTTP request func (wc *WalletClient) doHTTPRequest(ctx context.Context, method string, path string, rawJSON []byte, xPriv *bip32.ExtendedKey, sign bool, responseJSON interface{}, -) *models.SPVError { +) error { req, err := http.NewRequestWithContext(ctx, method, wc.server+path, bytes.NewBuffer(rawJSON)) if err != nil { return WrapError(err) @@ -546,7 +547,7 @@ func (wc *WalletClient) doHTTPRequest(ctx context.Context, method string, path s return nil } -func (wc *WalletClient) authenticateWithXpriv(sign bool, req *http.Request, xPriv *bip32.ExtendedKey, rawJSON []byte) *models.SPVError { +func (wc *WalletClient) authenticateWithXpriv(sign bool, req *http.Request, xPriv *bip32.ExtendedKey, rawJSON []byte) error { if sign { if err := addSignature(&req.Header, xPriv, string(rawJSON)); err != nil { return err @@ -563,12 +564,12 @@ func (wc *WalletClient) authenticateWithXpriv(sign bool, req *http.Request, xPri return nil } -func (wc *WalletClient) authenticateWithAccessKey(req *http.Request, rawJSON []byte) *models.SPVError { +func (wc *WalletClient) authenticateWithAccessKey(req *http.Request, rawJSON []byte) error { return SetSignatureFromAccessKey(&req.Header, hex.EncodeToString(wc.accessKey.Serialise()), string(rawJSON)) } // AcceptContact will accept the contact associated with the paymail -func (wc *WalletClient) AcceptContact(ctx context.Context, paymail string) *models.SPVError { +func (wc *WalletClient) AcceptContact(ctx context.Context, paymail string) error { if err := wc.doHTTPRequest( ctx, http.MethodPatch, "/contact/accepted/"+paymail, nil, wc.xPriv, wc.signRequest, nil, ); err != nil { @@ -579,7 +580,7 @@ func (wc *WalletClient) AcceptContact(ctx context.Context, paymail string) *mode } // RejectContact will reject the contact associated with the paymail -func (wc *WalletClient) RejectContact(ctx context.Context, paymail string) *models.SPVError { +func (wc *WalletClient) RejectContact(ctx context.Context, paymail string) error { if err := wc.doHTTPRequest( ctx, http.MethodPatch, "/contact/rejected/"+paymail, nil, wc.xPriv, wc.signRequest, nil, ); err != nil { @@ -590,7 +591,7 @@ func (wc *WalletClient) RejectContact(ctx context.Context, paymail string) *mode } // ConfirmContact will confirm the contact associated with the paymail -func (wc *WalletClient) ConfirmContact(ctx context.Context, contact *models.Contact, passcode, requesterPaymail string, period, digits uint) *models.SPVError { +func (wc *WalletClient) ConfirmContact(ctx context.Context, contact *models.Contact, passcode, requesterPaymail string, period, digits uint) error { isTotpValid, err := wc.ValidateTotpForContact(contact, passcode, requesterPaymail, period, digits) if err != nil { return WrapError(fmt.Errorf("totp validation failed: %w", err)) @@ -610,7 +611,7 @@ func (wc *WalletClient) ConfirmContact(ctx context.Context, contact *models.Cont } // GetContacts will get contacts by conditions -func (wc *WalletClient) GetContacts(ctx context.Context, conditions *filter.ContactFilter, metadata map[string]any, queryParams *filter.QueryParams) (*models.SearchContactsResponse, *models.SPVError) { +func (wc *WalletClient) GetContacts(ctx context.Context, conditions *filter.ContactFilter, metadata map[string]any, queryParams *filter.QueryParams) (*models.SearchContactsResponse, error) { return Search[filter.ContactFilter, *models.SearchContactsResponse]( ctx, http.MethodPost, "/contact/search", @@ -623,12 +624,12 @@ func (wc *WalletClient) GetContacts(ctx context.Context, conditions *filter.Cont } // UpsertContact add or update contact. When adding a new contact, the system utilizes Paymail's PIKE capability to dispatch an invitation request, asking the counterparty to include the current user in their contacts. -func (wc *WalletClient) UpsertContact(ctx context.Context, paymail, fullName, requesterPaymail string, metadata map[string]any) (*models.Contact, *spverrors.SPVError) { +func (wc *WalletClient) UpsertContact(ctx context.Context, paymail, fullName, requesterPaymail string, metadata map[string]any) (*models.Contact, error) { return wc.UpsertContactForPaymail(ctx, paymail, fullName, metadata, requesterPaymail) } // UpsertContactForPaymail add or update contact. When adding a new contact, the system utilizes Paymail's PIKE capability to dispatch an invitation request, asking the counterparty to include the current user in their contacts. -func (wc *WalletClient) UpsertContactForPaymail(ctx context.Context, paymail, fullName string, metadata map[string]any, requesterPaymail string) (*models.Contact, *models.SPVError) { +func (wc *WalletClient) UpsertContactForPaymail(ctx context.Context, paymail, fullName string, metadata map[string]any, requesterPaymail string) (*models.Contact, error) { payload := map[string]interface{}{ "fullName": fullName, FieldMetadata: metadata, @@ -654,7 +655,7 @@ func (wc *WalletClient) UpsertContactForPaymail(ctx context.Context, paymail, fu } // GetSharedConfig gets the shared config -func (wc *WalletClient) GetSharedConfig(ctx context.Context) (*models.SharedConfig, *models.SPVError) { +func (wc *WalletClient) GetSharedConfig(ctx context.Context) (*models.SharedConfig, error) { var model *models.SharedConfig key := wc.xPriv @@ -674,7 +675,7 @@ func (wc *WalletClient) GetSharedConfig(ctx context.Context) (*models.SharedConf } // AdminNewXpub will register an xPub -func (wc *WalletClient) AdminNewXpub(ctx context.Context, rawXPub string, metadata map[string]any) *models.SPVError { +func (wc *WalletClient) AdminNewXpub(ctx context.Context, rawXPub string, metadata map[string]any) error { // Adding a xpub needs to be signed by an admin key if wc.adminXPriv == nil { return WrapError(ErrAdminKey) @@ -696,7 +697,7 @@ func (wc *WalletClient) AdminNewXpub(ctx context.Context, rawXPub string, metada } // AdminGetStatus get whether admin key is valid -func (wc *WalletClient) AdminGetStatus(ctx context.Context) (bool, *models.SPVError) { +func (wc *WalletClient) AdminGetStatus(ctx context.Context) (bool, error) { var status bool if err := wc.doHTTPRequest( ctx, http.MethodGet, "/admin/status", nil, wc.adminXPriv, true, &status, @@ -708,7 +709,7 @@ func (wc *WalletClient) AdminGetStatus(ctx context.Context) (bool, *models.SPVEr } // AdminGetStats get admin stats -func (wc *WalletClient) AdminGetStats(ctx context.Context) (*models.AdminStats, *models.SPVError) { +func (wc *WalletClient) AdminGetStats(ctx context.Context) (*models.AdminStats, error) { var stats *models.AdminStats if err := wc.doHTTPRequest( ctx, http.MethodGet, "/admin/stats", nil, wc.adminXPriv, true, &stats, @@ -725,7 +726,7 @@ func (wc *WalletClient) AdminGetAccessKeys( conditions *filter.AdminAccessKeyFilter, metadata map[string]any, queryParams *filter.QueryParams, -) ([]*models.AccessKey, *models.SPVError) { +) ([]*models.AccessKey, error) { return Search[filter.AdminAccessKeyFilter, []*models.AccessKey]( ctx, http.MethodPost, "/admin/access-keys/search", @@ -742,7 +743,7 @@ func (wc *WalletClient) AdminGetAccessKeysCount( ctx context.Context, conditions *filter.AdminAccessKeyFilter, metadata map[string]any, -) (int64, *models.SPVError) { +) (int64, error) { return Count[filter.AdminAccessKeyFilter]( ctx, http.MethodPost, "/admin/access-keys/count", @@ -759,7 +760,7 @@ func (wc *WalletClient) AdminGetBlockHeaders( conditions map[string]interface{}, metadata map[string]any, queryParams *filter.QueryParams, -) ([]*models.BlockHeader, *models.SPVError) { +) ([]*models.BlockHeader, error) { var models []*models.BlockHeader if err := wc.adminGetModels(ctx, conditions, metadata, queryParams, "/admin/block-headers/search", &models); err != nil { return nil, err @@ -773,14 +774,14 @@ func (wc *WalletClient) AdminGetBlockHeadersCount( ctx context.Context, conditions map[string]interface{}, metadata map[string]any, -) (int64, *models.SPVError) { +) (int64, error) { return wc.adminCount(ctx, conditions, metadata, "/admin/block-headers/count") } // AdminGetDestinations get all block destinations filtered by conditions func (wc *WalletClient) AdminGetDestinations(ctx context.Context, conditions *filter.DestinationFilter, metadata map[string]any, queryParams *filter.QueryParams, -) ([]*models.Destination, *models.SPVError) { +) ([]*models.Destination, error) { return Search[filter.DestinationFilter, []*models.Destination]( ctx, http.MethodPost, "/admin/destinations/search", @@ -793,7 +794,7 @@ func (wc *WalletClient) AdminGetDestinations(ctx context.Context, conditions *fi } // AdminGetDestinationsCount get a count of all the destinations filtered by conditions -func (wc *WalletClient) AdminGetDestinationsCount(ctx context.Context, conditions *filter.DestinationFilter, metadata map[string]any) (int64, *models.SPVError) { +func (wc *WalletClient) AdminGetDestinationsCount(ctx context.Context, conditions *filter.DestinationFilter, metadata map[string]any) (int64, error) { return Count( ctx, http.MethodPost, @@ -806,7 +807,7 @@ func (wc *WalletClient) AdminGetDestinationsCount(ctx context.Context, condition } // AdminGetPaymail get a paymail by address -func (wc *WalletClient) AdminGetPaymail(ctx context.Context, address string) (*models.PaymailAddress, *models.SPVError) { +func (wc *WalletClient) AdminGetPaymail(ctx context.Context, address string) (*models.PaymailAddress, error) { jsonStr, err := json.Marshal(map[string]interface{}{ FieldAddress: address, }) @@ -830,7 +831,7 @@ func (wc *WalletClient) AdminGetPaymails( conditions *filter.AdminPaymailFilter, metadata map[string]any, queryParams *filter.QueryParams, -) ([]*models.PaymailAddress, *models.SPVError) { +) ([]*models.PaymailAddress, error) { return Search[filter.AdminPaymailFilter, []*models.PaymailAddress]( ctx, http.MethodPost, "/admin/paymails/search", @@ -843,7 +844,7 @@ func (wc *WalletClient) AdminGetPaymails( } // AdminGetPaymailsCount get a count of all the paymails filtered by conditions -func (wc *WalletClient) AdminGetPaymailsCount(ctx context.Context, conditions *filter.AdminPaymailFilter, metadata map[string]any) (int64, *models.SPVError) { +func (wc *WalletClient) AdminGetPaymailsCount(ctx context.Context, conditions *filter.AdminPaymailFilter, metadata map[string]any) (int64, error) { return Count( ctx, http.MethodPost, "/admin/paymails/count", @@ -855,7 +856,7 @@ func (wc *WalletClient) AdminGetPaymailsCount(ctx context.Context, conditions *f } // AdminCreatePaymail create a new paymail for a xpub -func (wc *WalletClient) AdminCreatePaymail(ctx context.Context, rawXPub string, address string, publicName string, avatar string) (*models.PaymailAddress, *models.SPVError) { +func (wc *WalletClient) AdminCreatePaymail(ctx context.Context, rawXPub string, address string, publicName string, avatar string) (*models.PaymailAddress, error) { jsonStr, err := json.Marshal(map[string]interface{}{ FieldXpubKey: rawXPub, FieldAddress: address, @@ -877,7 +878,7 @@ func (wc *WalletClient) AdminCreatePaymail(ctx context.Context, rawXPub string, } // AdminDeletePaymail delete a paymail address from the database -func (wc *WalletClient) AdminDeletePaymail(ctx context.Context, address string) *models.SPVError { +func (wc *WalletClient) AdminDeletePaymail(ctx context.Context, address string) error { jsonStr, err := json.Marshal(map[string]interface{}{ FieldAddress: address, }) @@ -900,7 +901,7 @@ func (wc *WalletClient) AdminGetTransactions( conditions *filter.TransactionFilter, metadata map[string]any, queryParams *filter.QueryParams, -) ([]*models.Transaction, *models.SPVError) { +) ([]*models.Transaction, error) { return Search[filter.TransactionFilter, []*models.Transaction]( ctx, http.MethodPost, "/admin/transactions/search", @@ -917,7 +918,7 @@ func (wc *WalletClient) AdminGetTransactionsCount( ctx context.Context, conditions *filter.TransactionFilter, metadata map[string]any, -) (int64, *models.SPVError) { +) (int64, error) { return Count[filter.TransactionFilter]( ctx, http.MethodPost, "/admin/transactions/count", @@ -934,7 +935,7 @@ func (wc *WalletClient) AdminGetUtxos( conditions *filter.AdminUtxoFilter, metadata map[string]any, queryParams *filter.QueryParams, -) ([]*models.Utxo, *models.SPVError) { +) ([]*models.Utxo, error) { return Search[filter.AdminUtxoFilter, []*models.Utxo]( ctx, http.MethodPost, "/admin/utxos/search", @@ -951,7 +952,7 @@ func (wc *WalletClient) AdminGetUtxosCount( ctx context.Context, conditions *filter.AdminUtxoFilter, metadata map[string]any, -) (int64, *models.SPVError) { +) (int64, error) { return Count[filter.AdminUtxoFilter]( ctx, http.MethodPost, "/admin/utxos/count", @@ -965,7 +966,7 @@ func (wc *WalletClient) AdminGetUtxosCount( // AdminGetXPubs get all block xpubs filtered by conditions func (wc *WalletClient) AdminGetXPubs(ctx context.Context, conditions *filter.XpubFilter, metadata map[string]any, queryParams *filter.QueryParams, -) ([]*models.Xpub, *models.SPVError) { +) ([]*models.Xpub, error) { return Search[filter.XpubFilter, []*models.Xpub]( ctx, http.MethodPost, "/admin/xpubs/search", @@ -982,7 +983,7 @@ func (wc *WalletClient) AdminGetXPubsCount( ctx context.Context, conditions *filter.XpubFilter, metadata map[string]any, -) (int64, *models.SPVError) { +) (int64, error) { return Count[filter.XpubFilter]( ctx, http.MethodPost, "/admin/xpubs/count", @@ -1000,7 +1001,7 @@ func (wc *WalletClient) adminGetModels( queryParams *filter.QueryParams, path string, models interface{}, -) *models.SPVError { +) error { jsonStr, err := json.Marshal(map[string]interface{}{ FieldConditions: conditions, FieldMetadata: metadata, @@ -1019,7 +1020,7 @@ func (wc *WalletClient) adminGetModels( return nil } -func (wc *WalletClient) adminCount(ctx context.Context, conditions map[string]interface{}, metadata map[string]any, path string) (int64, *models.SPVError) { +func (wc *WalletClient) adminCount(ctx context.Context, conditions map[string]interface{}, metadata map[string]any, path string) (int64, error) { jsonStr, err := json.Marshal(map[string]interface{}{ FieldConditions: conditions, FieldMetadata: metadata, @@ -1039,7 +1040,7 @@ func (wc *WalletClient) adminCount(ctx context.Context, conditions map[string]in } // AdminRecordTransaction will record a transaction as an admin -func (wc *WalletClient) AdminRecordTransaction(ctx context.Context, hex string) (*models.Transaction, *models.SPVError) { +func (wc *WalletClient) AdminRecordTransaction(ctx context.Context, hex string) (*models.Transaction, error) { jsonStr, err := json.Marshal(map[string]interface{}{ FieldHex: hex, }) @@ -1058,7 +1059,7 @@ func (wc *WalletClient) AdminRecordTransaction(ctx context.Context, hex string) } // AdminGetContacts executes an HTTP POST request to search for contacts based on specified conditions, metadata, and query parameters. -func (wc *WalletClient) AdminGetContacts(ctx context.Context, conditions *filter.ContactFilter, metadata map[string]any, queryParams *filter.QueryParams) (*models.SearchContactsResponse, *models.SPVError) { +func (wc *WalletClient) AdminGetContacts(ctx context.Context, conditions *filter.ContactFilter, metadata map[string]any, queryParams *filter.QueryParams) (*models.SearchContactsResponse, error) { return Search[filter.ContactFilter, *models.SearchContactsResponse]( ctx, http.MethodPost, "/admin/contact/search", @@ -1071,7 +1072,7 @@ func (wc *WalletClient) AdminGetContacts(ctx context.Context, conditions *filter } // AdminUpdateContact executes an HTTP PATCH request to update a specific contact's full name using their ID. -func (wc *WalletClient) AdminUpdateContact(ctx context.Context, id, fullName string, metadata map[string]any) (*models.Contact, *models.SPVError) { +func (wc *WalletClient) AdminUpdateContact(ctx context.Context, id, fullName string, metadata map[string]any) (*models.Contact, error) { jsonStr, err := json.Marshal(map[string]interface{}{ "fullName": fullName, FieldMetadata: metadata, @@ -1085,27 +1086,27 @@ func (wc *WalletClient) AdminUpdateContact(ctx context.Context, id, fullName str } // AdminDeleteContact executes an HTTP DELETE request to remove a contact using their ID. -func (wc *WalletClient) AdminDeleteContact(ctx context.Context, id string) *models.SPVError { +func (wc *WalletClient) AdminDeleteContact(ctx context.Context, id string) error { err := wc.doHTTPRequest(ctx, http.MethodDelete, fmt.Sprintf("/admin/contact/%s", id), nil, wc.adminXPriv, true, nil) return WrapError(err) } // AdminAcceptContact executes an HTTP PATCH request to mark a contact as accepted using their ID. -func (wc *WalletClient) AdminAcceptContact(ctx context.Context, id string) (*models.Contact, *models.SPVError) { +func (wc *WalletClient) AdminAcceptContact(ctx context.Context, id string) (*models.Contact, error) { var contact models.Contact err := wc.doHTTPRequest(ctx, http.MethodPatch, fmt.Sprintf("/admin/contact/accepted/%s", id), nil, wc.adminXPriv, true, &contact) return &contact, WrapError(err) } // AdminRejectContact executes an HTTP PATCH request to mark a contact as rejected using their ID. -func (wc *WalletClient) AdminRejectContact(ctx context.Context, id string) (*models.Contact, *models.SPVError) { +func (wc *WalletClient) AdminRejectContact(ctx context.Context, id string) (*models.Contact, error) { var contact models.Contact err := wc.doHTTPRequest(ctx, http.MethodPatch, fmt.Sprintf("/admin/contact/rejected/%s", id), nil, wc.adminXPriv, true, &contact) return &contact, WrapError(err) } // FinalizeTransaction will finalize the transaction -func (wc *WalletClient) FinalizeTransaction(draft *models.DraftTransaction) (string, *models.SPVError) { +func (wc *WalletClient) FinalizeTransaction(draft *models.DraftTransaction) (string, error) { res, err := GetSignedHex(draft, wc.xPriv) if err != nil { return "", WrapError(err) @@ -1115,7 +1116,7 @@ func (wc *WalletClient) FinalizeTransaction(draft *models.DraftTransaction) (str } // SendToRecipients send to recipients -func (wc *WalletClient) SendToRecipients(ctx context.Context, recipients []*Recipients, metadata map[string]any) (*models.Transaction, *models.SPVError) { +func (wc *WalletClient) SendToRecipients(ctx context.Context, recipients []*Recipients, metadata map[string]any) (*models.Transaction, error) { draft, err := wc.DraftToRecipients(ctx, recipients, metadata) if err != nil { return nil, err diff --git a/search.go b/search.go index 585c8df2..e2f93623 100644 --- a/search.go +++ b/search.go @@ -3,14 +3,12 @@ package walletclient import ( "context" "encoding/json" - "github.com/bitcoin-sv/spv-wallet/models" - "github.com/bitcoin-sv/spv-wallet/models/filter" "github.com/libsv/go-bk/bip32" ) // SearchRequester is a function that sends a request to the server and returns the response. -type SearchRequester func(ctx context.Context, method string, path string, rawJSON []byte, xPriv *bip32.ExtendedKey, sign bool, responseJSON interface{}) *models.SPVError +type SearchRequester func(ctx context.Context, method string, path string, rawJSON []byte, xPriv *bip32.ExtendedKey, sign bool, responseJSON interface{}) error // Search prepares and sends a search request to the server. func Search[TFilter any, TResp any]( @@ -22,7 +20,7 @@ func Search[TFilter any, TResp any]( metadata map[string]any, queryParams *filter.QueryParams, requester SearchRequester, -) (TResp, *models.SPVError) { +) (TResp, error) { jsonStr, err := json.Marshal(filter.SearchModel[TFilter]{ ConditionsModel: filter.ConditionsModel[TFilter]{ Conditions: f, @@ -51,7 +49,7 @@ func Count[TFilter any]( f *TFilter, metadata map[string]any, requester SearchRequester, -) (int64, *models.SPVError) { +) (int64, error) { jsonStr, err := json.Marshal(filter.ConditionsModel[TFilter]{ Conditions: f, Metadata: metadata, diff --git a/walletclient.go b/walletclient.go index 61756848..aae8d23f 100644 --- a/walletclient.go +++ b/walletclient.go @@ -1,7 +1,6 @@ package walletclient import ( - "github.com/bitcoin-sv/spv-wallet/spverrors" "net/http" "github.com/libsv/go-bk/bec" @@ -79,7 +78,7 @@ func makeClient(configurators ...configurator) *WalletClient { } // addSignature will add the signature to the request -func addSignature(header *http.Header, xPriv *bip32.ExtendedKey, bodyString string) *spverrors.SPVError { +func addSignature(header *http.Header, xPriv *bip32.ExtendedKey, bodyString string) error { return setSignature(header, xPriv, bodyString) }