Skip to content

Commit 3a56071

Browse files
feat: add custom message support for subwallet transfers
- Add optional message field to TransferRequest model - Update Transfer function to use custom message with 'transfer' as fallback - Update HTTP and Wails handlers to extract and pass message parameter - Add message input field to IsolatedAppTopupDialog and IsolatedAppDrawDownDialog - Maintains backward compatibility with empty message defaulting to 'transfer' Closes #2066
1 parent 4d563eb commit 3a56071

File tree

6 files changed

+56
-8
lines changed

6 files changed

+56
-8
lines changed

api/models.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
type API interface {
1515
CreateApp(createAppRequest *CreateAppRequest) (*CreateAppResponse, error)
1616
UpdateApp(app *db.App, updateAppRequest *UpdateAppRequest) error
17-
Transfer(ctx context.Context, fromAppId *uint, toAppId *uint, amountMsat uint64) error
17+
Transfer(ctx context.Context, fromAppId *uint, toAppId *uint, amountMsat uint64, message string) error
1818
DeleteApp(app *db.App) error
1919
GetApp(app *db.App) *App
2020
ListApps(limit uint64, offset uint64, filters ListAppsFilters, orderBy string) (*ListAppsResponse, error)
@@ -129,9 +129,10 @@ type UpdateAppRequest struct {
129129
}
130130

131131
type TransferRequest struct {
132-
AmountSat uint64 `json:"amountSat"`
133-
FromAppId *uint `json:"fromAppId"`
134-
ToAppId *uint `json:"toAppId"`
132+
AmountSat uint64 `json:"amountSat"`
133+
FromAppId *uint `json:"fromAppId"`
134+
ToAppId *uint `json:"toAppId"`
135+
Message *string `json:"message"`
135136
}
136137

137138
type CreateAppRequest struct {

api/transactions.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ func toApiTransaction(transaction *transactions.Transaction) *Transaction {
127127
}
128128
}
129129

130-
func (api *api) Transfer(ctx context.Context, fromAppId *uint, toAppId *uint, amountMsat uint64) error {
130+
func (api *api) Transfer(ctx context.Context, fromAppId *uint, toAppId *uint, amountMsat uint64, message string) error {
131131
if api.svc.GetLNClient() == nil {
132132
return errors.New("LNClient not started")
133133
}
@@ -144,7 +144,13 @@ func (api *api) Transfer(ctx context.Context, fromAppId *uint, toAppId *uint, am
144144
}
145145
}
146146

147-
transaction, err := api.svc.GetTransactionsService().MakeInvoice(ctx, amountMsat, "transfer", "", 0, nil, api.svc.GetLNClient(), toAppId, nil, nil)
147+
// Use custom message or default to "transfer"
148+
description := message
149+
if description == "" {
150+
description = "transfer"
151+
}
152+
153+
transaction, err := api.svc.GetTransactionsService().MakeInvoice(ctx, amountMsat, description, "", 0, nil, api.svc.GetLNClient(), toAppId, nil, nil)
148154

149155
if err != nil {
150156
return err

frontend/src/components/IsolatedAppDrawDownDialog.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export function IsolatedAppDrawDownDialog({
2626
}: React.PropsWithChildren<IsolatedAppTopupProps>) {
2727
const { mutate: reloadApp } = useApp(appId);
2828
const [amountSat, setAmountSat] = React.useState("");
29+
const [message, setMessage] = React.useState("");
2930
const [loading, setLoading] = React.useState(false);
3031
const [open, setOpen] = React.useState(false);
3132
async function onSubmit(e: React.FormEvent) {
@@ -40,6 +41,7 @@ export function IsolatedAppDrawDownDialog({
4041
body: JSON.stringify({
4142
fromAppId: appId,
4243
amountSat: +amountSat,
44+
...(message && { message }), // Only include if not empty
4345
}),
4446
});
4547
await reloadApp();
@@ -54,6 +56,7 @@ export function IsolatedAppDrawDownDialog({
5456
function reset() {
5557
setOpen(false);
5658
setAmountSat("");
59+
setMessage("");
5760
}
5861

5962
return (
@@ -80,6 +83,18 @@ export function IsolatedAppDrawDownDialog({
8083
}}
8184
/>
8285
</div>
86+
<div className="grid gap-2 mt-3">
87+
<Label htmlFor="message">Message (optional)</Label>
88+
<Input
89+
id="message"
90+
type="text"
91+
placeholder="e.g., Returning unused funds"
92+
value={message}
93+
onChange={(e) => {
94+
setMessage(e.target.value);
95+
}}
96+
/>
97+
</div>
8398
<DialogFooter className="mt-5">
8499
<LoadingButton loading={loading}>Decrease</LoadingButton>
85100
</DialogFooter>

frontend/src/components/IsolatedAppTopupDialog.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export function IsolatedAppTopupDialog({
2626
}: React.PropsWithChildren<IsolatedAppTopupProps>) {
2727
const { mutate: reloadApp } = useApp(appId);
2828
const [amountSat, setAmountSat] = React.useState("");
29+
const [message, setMessage] = React.useState("");
2930
const [loading, setLoading] = React.useState(false);
3031
const [open, setOpen] = React.useState(false);
3132
async function onSubmit(e: React.FormEvent) {
@@ -40,6 +41,7 @@ export function IsolatedAppTopupDialog({
4041
body: JSON.stringify({
4142
toAppId: appId,
4243
amountSat: +amountSat,
44+
...(message && { message }), // Only include if not empty
4345
}),
4446
});
4547
await reloadApp();
@@ -54,6 +56,7 @@ export function IsolatedAppTopupDialog({
5456
function reset() {
5557
setOpen(false);
5658
setAmountSat("");
59+
setMessage("");
5760
}
5861

5962
return (
@@ -82,6 +85,18 @@ export function IsolatedAppTopupDialog({
8285
}}
8386
/>
8487
</div>
88+
<div className="grid gap-2 mt-3">
89+
<Label htmlFor="message">Message (optional)</Label>
90+
<Input
91+
id="message"
92+
type="text"
93+
placeholder="e.g., Weekly allowance"
94+
value={message}
95+
onChange={(e) => {
96+
setMessage(e.target.value);
97+
}}
98+
/>
99+
</div>
85100
<DialogFooter className="mt-5">
86101
<LoadingButton loading={loading}>Increase</LoadingButton>
87102
</DialogFooter>

http/http_service.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,12 @@ func (httpSvc *HttpService) transfersHandler(c echo.Context) error {
11201120
})
11211121
}
11221122

1123-
err := httpSvc.api.Transfer(c.Request().Context(), requestData.FromAppId, requestData.ToAppId, requestData.AmountSat*1000)
1123+
message := ""
1124+
if requestData.Message != nil {
1125+
message = *requestData.Message
1126+
}
1127+
1128+
err := httpSvc.api.Transfer(c.Request().Context(), requestData.FromAppId, requestData.ToAppId, requestData.AmountSat*1000, message)
11241129

11251130
if err != nil {
11261131
logger.Logger.WithError(err).Error("Failed to transfer funds")

wails/wails_handlers.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,13 @@ func (app *WailsApp) WailsRequestRouter(route string, method string, body string
358358
}).WithError(err).Error("Failed to decode request to wails router")
359359
return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
360360
}
361-
err = app.api.Transfer(ctx, transferRequest.FromAppId, transferRequest.ToAppId, transferRequest.AmountSat*1000)
361+
362+
message := ""
363+
if transferRequest.Message != nil {
364+
message = *transferRequest.Message
365+
}
366+
367+
err = app.api.Transfer(ctx, transferRequest.FromAppId, transferRequest.ToAppId, transferRequest.AmountSat*1000, message)
362368
if err != nil {
363369
return WailsRequestRouterResponse{Body: nil, Error: err.Error()}
364370
}

0 commit comments

Comments
 (0)