-
Notifications
You must be signed in to change notification settings - Fork 1
/
resolve_address.go
113 lines (93 loc) · 3.15 KB
/
resolve_address.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package paymail
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"github.com/bitcoin-sv/go-sdk/script"
)
// ResolutionResponse is the response from the ResolveAddress() request
type ResolutionResponse struct {
StandardResponse
ResolutionPayload
}
// ResolutionPayload is the payload from the response
type ResolutionPayload struct {
Address string `json:"address,omitempty"` // Legacy BSV address derived from the output script (custom for our Go package)
Output string `json:"output"` // hex-encoded Bitcoin script, which the sender MUST use during the construction of a payment transaction
Signature string `json:"signature,omitempty"` // This is used if SenderValidation is enforced (signature of "output" value)
}
// ResolveAddress will return a hex-encoded Bitcoin script if successful
//
// Specs: http://bsvalias.org/04-01-basic-address-resolution.html
func (c *Client) ResolveAddress(resolutionURL, alias, domain string, senderRequest *SenderRequest) (response *ResolutionResponse, err error) {
// Require a valid url
if len(resolutionURL) == 0 || !strings.Contains(resolutionURL, "https://") {
err = fmt.Errorf("invalid url: %s", resolutionURL)
return
}
// Basic requirements for the request
if len(alias) == 0 {
err = errors.New("missing alias")
return
} else if len(domain) == 0 {
err = errors.New("missing domain")
return
}
// Basic requirements for request
if senderRequest == nil {
err = errors.New("senderRequest cannot be nil")
return
} else if len(senderRequest.Dt) == 0 {
err = errors.New("time is required on senderRequest")
return
} else if len(senderRequest.SenderHandle) == 0 {
err = errors.New("sender handle is required on senderRequest")
return
}
// Set the base url and path, assuming the url is from the prior GetCapabilities() request
// https://<host-discovery-target>/{alias}@{domain.tld}/payment-destination
reqURL := replaceAliasDomain(resolutionURL, alias, domain)
// Fire the POST request
var resp StandardResponse
if resp, err = c.postRequest(reqURL, senderRequest); err != nil {
return
}
// Start the response
response = &ResolutionResponse{StandardResponse: resp}
// Test the status code
if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusNotModified {
// Paymail address not found?
if response.StatusCode == http.StatusNotFound {
err = errors.New("paymail address not found")
} else {
serverError := &ServerError{}
if err = json.Unmarshal(resp.Body, serverError); err != nil {
return
}
err = fmt.Errorf("bad response from paymail provider: code %d, message: %s", response.StatusCode, serverError.Message)
}
return
}
// Decode the body of the response
if err = json.Unmarshal(resp.Body, &response); err != nil {
return
}
// Check for an output
if len(response.Output) == 0 {
err = errors.New("missing an output value")
return
}
script, err := script.NewFromHex(response.Output)
if err != nil {
return
}
addresses, err := script.Addresses()
if err != nil || len(addresses) == 0 {
err = errors.New("invalid output script, missing an address")
return
}
response.Address = addresses[0]
return
}