Skip to content

Commit

Permalink
create bolt12 offer support
Browse files Browse the repository at this point in the history
  • Loading branch information
JasonCWang committed Jan 9, 2025
1 parent 037c4b0 commit 07e2de8
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 0 deletions.
14 changes: 14 additions & 0 deletions objects/create_offer_input.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright ©, 2024-present, Lightspark Group, Inc. - All Rights Reserved
package objects

type CreateOfferInput struct {

// NodeId The node from which to create the offer.
NodeId string `json:"create_offer_input_node_id"`

// AmountMsats The amount for which the offer should be created, in millisatoshis. Setting the amount to 0 will allow the payer to specify an amount.
AmountMsats int64 `json:"create_offer_input_amount_msats"`

// Description The description of the offer.
Description *string `json:"create_offer_input_description"`
}
8 changes: 8 additions & 0 deletions objects/create_offer_output.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright ©, 2024-present, Lightspark Group, Inc. - All Rights Reserved
package objects

type CreateOfferOutput struct {

// Offer The offer that was created.
Offer Offer `json:"create_offer_output_offer"`
}
76 changes: 76 additions & 0 deletions objects/offer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
package objects

import "time"

// Offer This object represents a BOLT #12 offer (https://github.com/lightning/bolts/blob/master/12-offer-encoding.md) created by a Lightspark Node. You can retrieve this object to receive relevant payment information for a specific offer generated by a Lightspark node.
type Offer struct {

// Id The unique identifier of this entity across all Lightspark systems. Should be treated as an opaque string.
Id string `json:"offer_id"`

// CreatedAt The date and time when the entity was first created.
CreatedAt time.Time `json:"offer_created_at"`

// EncodedOffer The encoded offer string.
EncodedOffer string `json:"offer_encoded_offer"`

// Amount The requested amount in this invoice. If it is equal to 0, the sender should choose the amount to send.
Amount CurrencyAmount `json:"offer_amount"`

// Description The description of the offer.
Description *string `json:"offer_description"`

// Typename The typename of the object
Typename string `json:"__typename"`
}

const (
OfferFragment = `
fragment OfferFragment on Offer {
__typename
offer_id: id
offer_created_at: created_at
offer_encoded_offer: encoded_offer
offer_amount: amount {
__typename
currency_amount_original_value: original_value
currency_amount_original_unit: original_unit
currency_amount_preferred_currency_unit: preferred_currency_unit
currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
}
offer_description: description
}
`
)

// GetId The unique identifier of this entity across all Lightspark systems. Should be treated as an opaque string.
func (obj Offer) GetId() string {
return obj.Id
}

// GetCreatedAt The date and time when the entity was first created.
func (obj Offer) GetCreatedAt() time.Time {
return obj.CreatedAt
}

// GetEncodedOffer The encoded offer string.
func (obj Offer) GetEncodedOffer() string {
return obj.EncodedOffer
}

// GetAmount The requested amount in this invoice.
func (obj Offer) GetAmount() CurrencyAmount {
return obj.Amount
}

// GetDescription The description of the offer.
func (obj Offer) GetDescription() *string {
return obj.Description
}

// GetTypename The typename of the object
func (obj Offer) GetTypename() string {
return obj.Typename
}
23 changes: 23 additions & 0 deletions scripts/create_offer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
package scripts

import "github.com/lightsparkdev/go-sdk/objects"

const CREATE_OFFER_MUTATION = `
mutation CreateOffer(
$node_id: ID!
$amount_msats: Long!
$description: String
) {
create_offer(input: {
node_id: $node_id
amount_msats: $amount_msats
description: $description
}) {
offer {
...OfferFragment
}
}
}
` + objects.OfferFragment
30 changes: 30 additions & 0 deletions services/lightspark_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,36 @@ func (client *LightsparkClient) CreateInvoice(nodeId string, amountMsats int64,
return &invoice, nil
}

// CreateOffer generates a Bolt 12 offer
//
// Args:
//
// nodeId: the id of the node that will create the offer
// amountMsats: the amount of the invoice in millisatoshis
// description: the description of the offer
func (client *LightsparkClient) CreateOffer(nodeId string, amountMsats int64,
description *string) (*objects.Offer, error) {

variables := map[string]interface{}{
"amount_msats": amountMsats,
"node_id": nodeId,
"description": description,
}
response, err := client.Requester.ExecuteGraphql(scripts.CREATE_OFFER_MUTATION, variables, nil)
if err != nil {
return nil, err
}

output := response["create_offer"].(map[string]interface{})
var offer objects.Offer
offerJson, err := json.Marshal(output["offer"].(map[string]interface{}))
if err != nil {
return nil, errors.New("error parsing offer")
}
json.Unmarshal(offerJson, &offer)
return &offer, nil
}

// CreateLnurlInvoice creates a new LNURL invoice. The metadata is hashed and included in the invoice.
// This API generates a Lightning Invoice (follows the Bolt 11 specification) to request a payment
// from another Lightning Node. This should only be used for generating invoices
Expand Down
17 changes: 17 additions & 0 deletions services/test/local/local_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ func TestCreateInvoice(t *testing.T) {
t.Log(invoice)
}

func TestCreateOffer(t *testing.T) {
env := servicestest.NewConfig()
client := services.NewLightsparkClient(env.ApiClientID, env.ApiClientSecret, &env.ApiClientEndpoint)
offer, err := createOfferForNode(client, env.NodeID)
require.NoError(t, err)
require.NotEmpty(t, offer.EncodedOffer)
t.Log(offer)
}

// Create invoice for node 1 and pay it from routing node. You'll need to run this a few
// times the first time you are funding a node to get enough funds in.
// Note: This will only work with REGTEST nodes.
Expand Down Expand Up @@ -156,3 +165,11 @@ func createInvoiceForNode(client *services.LightsparkClient, nodeID string) (*ob
}
return invoice, nil
}

func createOfferForNode(client *services.LightsparkClient, nodeID string) (*objects.Offer, error) {
offer, err := client.CreateOffer(nodeID, 10_000_000, nil)
if err != nil {
return nil, err
}
return offer, nil
}

0 comments on commit 07e2de8

Please sign in to comment.