Skip to content
This repository has been archived by the owner on Sep 2, 2024. It is now read-only.

moonpay v2 #397

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
aa47b00
revamp onchain address screen to deposit bitcoin screen
pavanjoshi914 May 22, 2024
8c484eb
feat: moonpay integration
pavanjoshi914 May 23, 2024
7130ab5
Merge remote-tracking branch 'upstream/master' into moonpay-integration
pavanjoshi914 May 23, 2024
b072034
feat: api request handlers for topup
pavanjoshi914 May 24, 2024
8ae702f
feat: cleanup
pavanjoshi914 May 24, 2024
6747637
feat: remove provider selection step
pavanjoshi914 May 27, 2024
06b96a9
feat: add wails handler for topup
pavanjoshi914 May 27, 2024
aec4a2d
Merge remote-tracking branch 'upstream/master' into moonpay
pavanjoshi914 May 27, 2024
55382a6
feat: wails handlers + remove hardcoded btc address
pavanjoshi914 May 28, 2024
35a397f
Merge remote-tracking branch 'upstream/master' into moonpay
pavanjoshi914 Jun 3, 2024
4360b77
fix: cleanup
pavanjoshi914 Jun 3, 2024
4312115
fix: typings + open moonpay url in separate tab
pavanjoshi914 Jun 3, 2024
ca8cec2
fix: correct response type to array of objects
pavanjoshi914 Jun 4, 2024
5d0acb3
feat: update frontend
pavanjoshi914 Jun 4, 2024
9525f0c
fix: remove crypto-js
pavanjoshi914 Jun 4, 2024
f670fa2
feat: refactoring and cleanup
pavanjoshi914 Jun 6, 2024
599fa66
feat: remove combobox and use simple select
pavanjoshi914 Jun 7, 2024
3d711c5
Merge remote-tracking branch 'upstream/master' into moonpay-v2
pavanjoshi914 Jun 7, 2024
beacae8
fix: moonpay currency handling
rolznz Jun 8, 2024
a0f12c8
chore: remove unused code
rolznz Jun 8, 2024
49dbdeb
fix: use platform-specific openLink
rolznz Jun 8, 2024
0d929f7
chore: code cleanup
rolznz Jun 8, 2024
e73ab1b
chore: code cleanup
rolznz Jun 8, 2024
d8c9bbd
chore: remove unused code
rolznz Jun 8, 2024
c44a21c
chore: move moonpay image
rolznz Jun 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ Follow the steps to integrate Mutinynet with your NWC Next setup:

3. During onboarding, after setting your password and authorizing via Alby OAuth, you'll be directed to `/onboarding/lightning/migrate-alby`. Click "Skip For Now" to access your wallet interface

4. Navigate to `channels/onchain/new-address`, copy your On-Chain Address, then visit the [Mutinynet Faucet](https://faucet.mutinynet.com/) to deposit sats. Ensure the transaction confirms on [mempool.space](https://mutinynet.com/)
4. Navigate to `channels/onchain/deposit-bitcoin`, copy your On-Chain Address, then visit the [Mutinynet Faucet](https://faucet.mutinynet.com/) to deposit sats. Ensure the transaction confirms on [mempool.space](https://mutinynet.com/)

5. Your On-chain balance will update under `/channels`

Expand Down
20 changes: 20 additions & 0 deletions alby/alby_http_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func NewAlbyHttpService(albyOAuthSvc AlbyOAuthService, logger *logrus.Logger, ap
func (albyHttpSvc *AlbyHttpService) RegisterSharedRoutes(e *echo.Echo, authMiddleware func(next echo.HandlerFunc) echo.HandlerFunc) {
e.GET("/api/alby/callback", albyHttpSvc.albyCallbackHandler, authMiddleware)
e.GET("/api/alby/me", albyHttpSvc.albyMeHandler, authMiddleware)
e.POST("/api/alby/topup", albyHttpSvc.albyTopupHandler, authMiddleware)
e.GET("/api/alby/balance", albyHttpSvc.albyBalanceHandler, authMiddleware)
e.POST("/api/alby/pay", albyHttpSvc.albyPayHandler, authMiddleware)
e.POST("/api/alby/link-account", albyHttpSvc.albyLinkAccountHandler, authMiddleware)
Expand Down Expand Up @@ -68,6 +69,25 @@ func (albyHttpSvc *AlbyHttpService) albyMeHandler(c echo.Context) error {
return c.JSON(http.StatusOK, me)
}

func (albyHttpSvc *AlbyHttpService) albyTopupHandler(c echo.Context) error {
var topupParams AlbyTopupRequest
if err := c.Bind(&topupParams); err != nil {
return c.JSON(http.StatusBadRequest, ErrorResponse{
Message: fmt.Sprintf("Bad request: %s", err.Error()),
})
}

topup, err := albyHttpSvc.albyOAuthSvc.GetTopupUrl(c.Request().Context(), topupParams.Amount, topupParams.Address, topupParams.Currency)
if err != nil {
albyHttpSvc.logger.WithError(err).Error("Failed to request alby /topups endpoint")
return c.JSON(http.StatusInternalServerError, ErrorResponse{
Message: fmt.Sprintf("Failed to request alby topups endpoint: %s", err.Error()),
})
}

return c.JSON(http.StatusOK, topup)
}

func (albyHttpSvc *AlbyHttpService) albyBalanceHandler(c echo.Context) error {
balance, err := albyHttpSvc.albyOAuthSvc.GetBalance(c.Request().Context())
if err != nil {
Expand Down
73 changes: 73 additions & 0 deletions alby/alby_oauth_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strconv"
"strings"
Expand Down Expand Up @@ -209,6 +210,78 @@ func (svc *albyOAuthService) GetMe(ctx context.Context) (*AlbyMe, error) {
return me, nil
}

func (svc *albyOAuthService) GetTopupUrl(ctx context.Context, amount int64, address string, currency string) ([]AlbyTopupProvider, error) {

token, err := svc.fetchUserToken(ctx)
if err != nil {
svc.logger.WithError(err).Error("Failed to fetch user token")
return nil, err
}

client := svc.oauthConf.Client(ctx, token)

type topupParams struct {
Address string `json:"address"`
Amount int64 `json:"amount"`
// Currency string `json:"currency"` // TODO: enable when backend supports it
}

body := bytes.NewBuffer([]byte{})
payload := &topupParams{
Address: address,
Amount: amount,
// Currency: currency, // TODO: enable when backend supports it
}
err = json.NewEncoder(body).Encode(payload)

if err != nil {
svc.logger.WithError(err).Error("Failed to encode request payload")
return nil, err
}

req, err := http.NewRequest("POST", fmt.Sprintf("%s/internal/topups", svc.appConfig.AlbyAPIURL), body)
if err != nil {
svc.logger.WithError(err).Error("Error creating request /topups")
return nil, err
}

req.Header.Set("User-Agent", "NWC-next")
req.Header.Set("Content-Type", "application/json")

res, err := client.Do(req)
if err != nil {
svc.logger.WithError(err).Error("Failed to fetch /topups")
return nil, err
}

if res.StatusCode >= 300 {
body, err := io.ReadAll(res.Body)
if err != nil {
svc.logger.WithFields(logrus.Fields{
"status_code": res.StatusCode,
}).WithError(err).Error("Failed to read response body")
return nil, fmt.Errorf("failed to read topup response body %s", string(body))
}

svc.logger.WithFields(logrus.Fields{
"body": body,
"status_code": res.StatusCode,
}).Error("Topups endpoint returned non-success code")
return nil, fmt.Errorf("failed to retrieve topup url %s", string(body))
}

var topup []AlbyTopupProvider

err = json.NewDecoder(res.Body).Decode(&topup)
if err != nil {
svc.logger.WithError(err).Error("Failed to decode API response")
return nil, err
}

svc.logger.WithFields(logrus.Fields{"topup": topup}).Info("Alby topup response")
return topup, nil
}

func (svc *albyOAuthService) GetBalance(ctx context.Context) (*AlbyBalance, error) {

token, err := svc.fetchUserToken(ctx)
Expand Down
12 changes: 12 additions & 0 deletions alby/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type AlbyOAuthService interface {
GetBalance(ctx context.Context) (*AlbyBalance, error)
GetMe(ctx context.Context) (*AlbyMe, error)
SendPayment(ctx context.Context, invoice string) error
GetTopupUrl(ctx context.Context, amount int64, address string, currency string) ([]AlbyTopupProvider, error)
}

type AlbyBalanceResponse struct {
Expand All @@ -38,12 +39,23 @@ type AlbyMe struct {
SharedNode bool `json:"shared_node"`
}

type AlbyTopupProvider struct {
Name string `json:"name"`
Url string `json:"url"`
}

type AlbyBalance struct {
Balance int64 `json:"balance"`
Unit string `json:"unit"`
Currency string `json:"currency"`
}

type AlbyTopupRequest struct {
Amount int64 `json:"amount"`
Address string `json:"address"`
Currency string `json:"currency"`
}

type ChannelPeerSuggestion struct {
Network string `json:"network"`
PaymentMethod string `json:"paymentMethod"`
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import AppStore from "src/screens/appstore/AppStore";
import Channels from "src/screens/channels/Channels";
import NewChannel from "src/screens/channels/NewChannel";
import MigrateAlbyFunds from "src/screens/onboarding/MigrateAlbyFunds";
import NewOnchainAddress from "src/screens/onchain/NewAddress";
import ConnectPeer from "src/screens/peers/ConnectPeer";
import Settings from "src/screens/settings/Settings";
import { ImportMnemonic } from "src/screens/setup/ImportMnemonic";
Expand All @@ -43,6 +42,8 @@ import AppConnect from "src/screens/appstore/AppConnect";
import AppDetail from "src/screens/appstore/AppDetail";
import { CurrentChannelOrder } from "src/screens/channels/CurrentChannelOrder";
import { Success } from "src/screens/onboarding/Success";
import BuyBitcoin from "src/screens/onchain/BuyBitcoin";
import DepositBitcoin from "src/screens/onchain/DepositBitcoin";
import Peers from "src/screens/peers/Peers";
import { ChangeUnlockPassword } from "src/screens/settings/ChangeUnlockPassword";
import DebugTools from "src/screens/settings/DebugTools";
Expand Down Expand Up @@ -96,9 +97,10 @@ function App() {
<Route path="new" element={<NewChannel />} />
<Route path="order" element={<CurrentChannelOrder />} />
<Route
path="onchain/new-address"
element={<NewOnchainAddress />}
path="onchain/deposit-bitcoin"
element={<DepositBitcoin />}
/>
<Route path="onchain/buy-bitcoin" element={<BuyBitcoin />} />
</Route>
<Route path="peers" element={<DefaultRedirect />}>
<Route index element={<Peers />} />
Expand Down
Binary file added frontend/src/assets/topup-providers/moonpay.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
142 changes: 142 additions & 0 deletions frontend/src/moonpay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
export const MOONPAY_SUPPORTED_CURRENCIES = [
{
value: "usd",
label: "USD - US Dollar",
},
{
value: "ars",
label: "ARS - Argentine Peso",
},
{
value: "aud",
label: "AUD - Australian Dollar",
},
{
value: "bgn",
label: "BGN - Bulgarian Lev",
},
{
value: "brl",
label: "BRL - Brazilian Real",
},
{
value: "cad",
label: "CAD - Canadian Dollar",
},
{
value: "chf",
label: "CHF - Swiss Franc",
},
{
value: "cop",
label: "COP - Colombian Peso",
},
{
value: "czk",
label: "CZK - Czech Koruna",
},
{
value: "dkk",
label: "DKK - Danish Krone",
},
{
value: "dop",
label: "DOP - Dominican Peso",
},
{
value: "egp",
label: "EGP - Egyptian Pound",
},
{
value: "eur",
label: "EUR - Euro",
},
{
value: "gbp",
label: "GBP - Pound Sterling",
},
{
value: "hkd",
label: "HKD - Hong Kong Dollar",
},
{
value: "idr",
label: "IDR - Indonesian Rupiah",
},
{
value: "ils",
label: "ILS - Israeli New Shekel",
},
{
value: "jod",
label: "JOD - Jordanian Dollar",
},
{
value: "kes",
label: "KES - Kenyan Shilling",
},
{
value: "kwd",
label: "KWD - Kuwaiti Dinar",
},
{
value: "lkr",
label: "LKR - Sri Lankan Rupee",
},
{
value: "mxn",
label: "MXN - Mexican Peso",
},
{
value: "ngn",
label: "NGN - Nigerian Naira",
},
{
value: "nok",
label: "NOK - Norwegian Krone",
},
{
value: "nzd",
label: "NZD - New Zealand Dollar",
},
{
value: "omr",
label: "OMR - Omani Rial",
},
{
value: "pen",
label: "PEN - Peruvian Sol",
},
{
value: "pln",
label: "PLN - Polish Złoty",
},
{
value: "ron",
label: "RON - Romanian Leu",
},
{
value: "sek",
label: "SEK - Swedish Krona",
},
{
value: "thb",
label: "THB - Thai Baht",
},
{
value: "try",
label: "TRY - Turkish Lira",
},
{
value: "twd",
label: "TWD - Taiwan Dollar",
},
{
value: "vnd",
label: "VND - Vietnamese Dong",
},
{
value: "zar",
label: "ZAR - South African Rand",
},
];
6 changes: 3 additions & 3 deletions frontend/src/screens/channels/Channels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,8 @@ export default function Channels() {
<DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuItem>
<Link to="/channels/onchain/new-address" className="w-full">
On-Chain Address
<Link to="/channels/onchain/deposit-bitcoin">
Deposit Bitcoin
</Link>
</DropdownMenuItem>
{(balances?.onchain.spendable || 0) > ONCHAIN_DUST_SATS && (
Expand Down Expand Up @@ -337,7 +337,7 @@ export default function Channels() {
</div>
</CardContent>
<CardFooter className="flex justify-end">
<Link to="onchain/new-address">
<Link to="onchain/deposit-bitcoin">
<Button variant="outline">Deposit</Button>
</Link>
</CardFooter>
Expand Down
Loading
Loading