-
-
Notifications
You must be signed in to change notification settings - Fork 11
/
p2p_send_transaction.go
129 lines (111 loc) · 3.92 KB
/
p2p_send_transaction.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package paymail
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
)
/*
Example:
{
"hex": "01000000012adda020db81f2155ebba69e7.........154888ac00000000",
"metadata": {
"sender": "[email protected]",
"pubkey": "<sender-pubkey>",
"signature": "signature(txid)",
"note": "Human readable information related to the tx."
},
"reference": "someRefId"
}
*/
// P2PTransaction is the request body for the P2P transaction request
type P2PTransaction struct {
Hex string `json:"hex"` // The raw transaction, encoded as a hexadecimal string
MetaData *P2PMetaData `json:"metadata"` // An object containing data associated with the transaction
Reference string `json:"reference"` // Reference for the payment (from previous P2P Destination request)
}
// P2PMetaData is an object containing data associated with the P2P transaction
type P2PMetaData struct {
Note string `json:"note,omitempty"` // A human-readable bit of information about the payment
PubKey string `json:"pubkey,omitempty"` // Public key to validate the signature (if signature is given)
Sender string `json:"sender,omitempty"` // The paymail of the person that originated the transaction
Signature string `json:"signature,omitempty"` // A signature of the tx id made by the sender
}
// P2PTransactionResponse is the response to the request
type P2PTransactionResponse struct {
StandardResponse
P2PTransactionPayload
}
// P2PTransactionPayload is payload from the request
type P2PTransactionPayload struct {
Note string `json:"note"` // Some human-readable note
TxID string `json:"txid"` // The txid of the broadcasted tx
}
// SendP2PTransaction will submit a transaction hex string (tx_hex) to a paymail provider
//
// Specs: https://docs.moneybutton.com/docs/paymail-06-p2p-transactions.html
func (c *Client) SendP2PTransaction(p2pURL, alias, domain string,
transaction *P2PTransaction) (response *P2PTransactionResponse, err error) {
// Require a valid url
if len(p2pURL) == 0 || !strings.Contains(p2pURL, "https://") {
err = fmt.Errorf("invalid url: %s", p2pURL)
return
} else 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 transaction == nil {
err = errors.New("transaction cannot be nil")
return
} else if len(transaction.Hex) == 0 {
err = errors.New("hex is required")
return
} else if len(transaction.Reference) == 0 {
err = errors.New("reference is required")
return
}
// Set the base url and path, assuming the url is from the prior GetCapabilities() request
// https://<host-discovery-target>/api/rawtx/{alias}@{domain.tld}
// https://<host-discovery-target>/api/receive-transaction/{alias}@{domain.tld}
reqURL := replaceAliasDomain(p2pURL, alias, domain)
// Fire the POST request
var resp StandardResponse
if resp, err = c.postRequest(reqURL, transaction); err != nil {
return
}
// Start the response
response = &P2PTransactionResponse{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
}
if len(serverError.Message) == 0 {
err = fmt.Errorf("bad response from paymail provider: code %d, body: %s", response.StatusCode, string(resp.Body))
} else {
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 a TX ID
if len(response.TxID) == 0 {
err = errors.New("missing a returned txid")
return
}
return
}