|
| 1 | +# HTTP Wallet Example |
| 2 | + |
| 3 | +This example demonstrates how to use the `substrates.HTTPWalletJSON` to interact with a wallet service over HTTP. It specifically shows how to make a `CreateAction` call to a mock HTTP server that simulates a wallet backend. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The `substrates.HTTPWalletJSON` provides a client implementation for wallet operations that are exposed via an HTTP JSON API. This example focuses on the `CreateAction` method, which is typically used to initiate the creation of a transaction. |
| 8 | + |
| 9 | +The example includes: |
| 10 | +1. Setting up a mock HTTP server to handle wallet API requests. |
| 11 | +2. Initializing an `HTTPWalletJSON` client to communicate with the mock server. |
| 12 | +3. Preparing `CreateActionArgs` with transaction details. |
| 13 | +4. Calling the `CreateAction` method on the HTTP wallet client. |
| 14 | +5. Processing the `CreateActionResult` received from the mock server. |
| 15 | + |
| 16 | +## Code Walkthrough |
| 17 | + |
| 18 | +### 1. Mock HTTP Server Setup |
| 19 | + |
| 20 | +To simulate a backend wallet service, a mock HTTP server is created using `net/http/httptest`. This server will respond to the `/createAction` endpoint. |
| 21 | + |
| 22 | +```go |
| 23 | +// Mock server setup |
| 24 | +mux := http.NewServeMux() |
| 25 | + |
| 26 | +// Mock CreateAction |
| 27 | +var mockCreateActionReference = []byte("mock-tx-reference-123") |
| 28 | +mockCreateActionTxId, _ := chainhash.NewHashFromHex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") |
| 29 | +mux.HandleFunc("/createAction", func(w http.ResponseWriter, r *http.Request) { |
| 30 | + var args wallet.CreateActionArgs |
| 31 | + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { |
| 32 | + http.Error(w, "Failed to decode request for createAction", http.StatusBadRequest) |
| 33 | + return |
| 34 | + } |
| 35 | + fmt.Printf("Mock Server: Received CreateAction with Description: %s\n", args.Description) |
| 36 | + |
| 37 | + // Use an anonymous struct for the JSON response to send Txid as a string |
| 38 | + jsonResponse := struct { |
| 39 | + Txid string `json:"txid"` |
| 40 | + SignableTransaction *wallet.SignableTransaction `json:"signableTransaction,omitempty"` |
| 41 | + }{ |
| 42 | + Txid: mockCreateActionTxId.String(), // Marshal as hex string |
| 43 | + SignableTransaction: &wallet.SignableTransaction{ |
| 44 | + Reference: mockCreateActionReference, |
| 45 | + }, |
| 46 | + } |
| 47 | + writeJSONResponse(w, jsonResponse) |
| 48 | +}) |
| 49 | + |
| 50 | +server := httptest.NewServer(mux) |
| 51 | +defer server.Close() |
| 52 | + |
| 53 | +// Helper to write JSON responses for the mock server |
| 54 | +func writeJSONResponse(w http.ResponseWriter, data interface{}) { |
| 55 | + w.Header().Set("Content-Type", "application/json") |
| 56 | + if err := json.NewEncoder(w).Encode(data); err != nil { |
| 57 | + http.Error(w, "Failed to encode response", http.StatusInternalServerError) |
| 58 | + } |
| 59 | +} |
| 60 | +``` |
| 61 | +The mock server listens for POST requests on `/createAction`. When a request is received, it decodes the `wallet.CreateActionArgs`, prints the description, and sends back a mocked `CreateActionResult` containing a `Txid` and a `SignableTransaction` with a reference. |
| 62 | + |
| 63 | +### 2. Initialize HTTPWalletJSON Client |
| 64 | + |
| 65 | +An `HTTPWalletJSON` client is initialized with the URL of the mock server. |
| 66 | + |
| 67 | +```go |
| 68 | +originator := "my-app-example" |
| 69 | +// Use the mock server's URL |
| 70 | +baseURL := server.URL |
| 71 | +httpClient := server.Client() |
| 72 | + |
| 73 | +w := substrates.NewHTTPWalletJSON(originator, baseURL, httpClient) |
| 74 | +ctx := context.Background() |
| 75 | +``` |
| 76 | +The `originator` string is an identifier for the application making the request. The `httpClient` from the `httptest.Server` is used to ensure requests go to the mock server. |
| 77 | + |
| 78 | +### 3. Prepare and Call CreateAction |
| 79 | + |
| 80 | +Arguments for `CreateAction` are prepared, including a description, output details (amount and locking script), and labels. |
| 81 | + |
| 82 | +```go |
| 83 | +// --- CreateAction --- |
| 84 | +fmt.Println("\n--- CreateAction ---") |
| 85 | +// Create a P2PKH script for the output |
| 86 | +mockToAddress, err := script.NewAddressFromString("mfZQtGMnf2aP17fF3a9TzWMRw2NXp25hN2") // Using a valid testnet address format |
| 87 | +if err != nil { |
| 88 | + fmt.Printf("Error creating mock address: %v\n", err) |
| 89 | + return |
| 90 | +} |
| 91 | +p2pkhScript, _ := p2pkh.Lock(mockToAddress) |
| 92 | + |
| 93 | +createActionArgs := wallet.CreateActionArgs{ |
| 94 | + Description: "Test transaction from example", |
| 95 | + Outputs: []wallet.CreateActionOutput{ |
| 96 | + { |
| 97 | + Satoshis: 1000, // Amount in satoshis |
| 98 | + LockingScript: p2pkhScript.Bytes(), |
| 99 | + }, |
| 100 | + }, |
| 101 | + Labels: []string{"test", "example"}, |
| 102 | +} |
| 103 | +createActionResult, err := w.CreateAction(ctx, createActionArgs) |
| 104 | +if err != nil { |
| 105 | + fmt.Printf("Error creating action: %v\n", err) |
| 106 | +} |
| 107 | +var currentActionReference []byte |
| 108 | +if createActionResult != nil { |
| 109 | + fmt.Printf("CreateAction Result - TxID: %s\n", createActionResult.Txid.String()) |
| 110 | + if createActionResult.SignableTransaction != nil { |
| 111 | + currentActionReference = createActionResult.SignableTransaction.Reference |
| 112 | + fmt.Printf("CreateAction Result - Reference: %s\n", string(currentActionReference)) |
| 113 | + } else { |
| 114 | + fmt.Println("CreateAction Result - No SignableTransaction returned by mock.") |
| 115 | + } |
| 116 | +} else { |
| 117 | + fmt.Println("CreateAction failed or mock returned nil.") |
| 118 | +} |
| 119 | +``` |
| 120 | +A P2PKH (Pay-to-Public-Key-Hash) script is created for the transaction output. The `CreateAction` method is then called on the `HTTPWalletJSON` client. The result, including the transaction ID and any signable transaction reference, is printed. |
| 121 | + |
| 122 | +## Running the Example |
| 123 | + |
| 124 | +To run this example: |
| 125 | + |
| 126 | +```bash |
| 127 | +cd go-sdk/docs/examples/http_wallet |
| 128 | +go mod tidy |
| 129 | +go run http_wallet.go |
| 130 | +``` |
| 131 | + |
| 132 | +This will start the mock server, send a `CreateAction` request to it, and print the results to the console. |
| 133 | + |
| 134 | +## Key Concepts |
| 135 | + |
| 136 | +- **`substrates.HTTPWalletJSON`**: A client for interacting with a wallet service that exposes a JSON HTTP API. It implements the `wallet.Wallet` interface. |
| 137 | +- **Mock Server**: The example uses `net/http/httptest` to create a mock HTTP server that simulates the behavior of a real wallet backend for the `/createAction` endpoint. This is useful for testing client integrations without needing a live wallet service. |
| 138 | +- **`wallet.CreateActionArgs`**: This struct encapsulates the parameters needed to create a transaction, such as outputs (amount and script), description, and labels. |
| 139 | +- **`wallet.CreateActionResult`**: This struct represents the response from a `CreateAction` call, typically including the `Txid` of the created transaction and, if applicable, a `SignableTransaction` object which might contain a reference for further signing steps. |
| 140 | +- **Originator**: An identifier for the client application making the wallet requests. |
| 141 | + |
| 142 | +## Additional Resources |
| 143 | + |
| 144 | +- [go-sdk `wallet/substrates` package documentation](https://pkg.go.dev/github.com/bsv-blockchain/go-sdk/wallet/substrates) |
| 145 | +- [go-sdk `wallet` package documentation](https://pkg.go.dev/github.com/bsv-blockchain/go-sdk/wallet) |
0 commit comments