removing lambda

This commit is contained in:
2025-04-30 14:00:52 +02:00
parent 3474ddafc7
commit 5beb151e29
16 changed files with 1 additions and 776 deletions

View File

@@ -8,4 +8,4 @@ Currently implemented endpoints:
## Options
- [fly.io](./fly/README.md) - deploy fly.io app
- [aws lambda](./lambda/README.md) - lambda functions (wip)
- [self hosted](./fly/DEV.md) - deploy anywhere you want

View File

@@ -1,156 +0,0 @@
# Nodeless payments
This is a proof of concept implementation for deploying the Breez SDK (Nodeless implementation) as a lambda function to AWS. It provides a REST api with close to zero cost of hosting.
Currently implemented endpoints:
- /send_payment (bolt11)
- /receive_payment (bolt11)
- /list_payments
### API Key Security
- X-API-KEY header serves as authorization method for accessing the API. Anyone that knows the API url and API_SECRET can access your funds, so make sure to protect this secret and to generate a unique and long string. You can use generators like [this](https://1password.com/password-generator) or [this](https://www.uuidgenerator.net/).
- Encrypted secrets are stored in [AWS Parameter Store](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html) and are accessed each time any endpoint is called (in the background docker container is started for each REST API call).
## Requirements for deployment
- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
- [Access to AWS account](https://signin.aws.amazon.com/signup?request_type=register)
- [Breez SDK - Nodeless implementation API key](https://breez.technology/request-api-key/#contact-us-form-sdk)
- 12 words BIP 39 seed (TBA: use Misty Breez to generate it)
## Deployment
Deployment to AWS with [cloudformation](./cloudformation.yaml).
### Install CLI
Follow [AWS guide](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) to install it on your computer.
### Create credentials
There are several ways of creating credentials to deploy in AWS. Ideally, you want to generate temporary credentials that are gonna be revoked after this deployment. You can create create credentials that have the same permissions as your root account. This will enable you to run all the CLI commands. Follow these steps to create an access key:
* Select *Security Credentials* from your account's menu:
<img src="./docs/screenshot0.jpg" width="50%">
<img src="./docs/screenshot1.jpg" width="30%">
* Follow the steps to create an access key:
<img src="./docs/screenshot2.jpg" width="50%">
<img src="./docs/screenshot3.jpg" width="50%">
<img src="./docs/screenshot4.jpg" width="50%">
### Configure CLI
Now that you have AWS CLI installed and credentials ready, it's time for the last step of the requirements: configuring the AWS CLI to work with your account credentials.
You will also have to choose a default region where you want to deploy your API. You can see the list of all regions [here](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html). You should pick the region that is closest to your business. For quick reference:
* **US**: *us-east-1*, *us-west-1*
* **Europe**: *eu-central-1*, *eu-west-1*
* **LATAM**: *sa-east-1*
* **Asia**: *ap-southeast-1*
Once you have an API key, an API secret and region string, you're ready to configure the CLI.
Open a command line interface in your OS and type `aws configure` and press enter. Now, copy/paste the API key, press enter, then copy/paste the API secret and press enter. Do the same for the region string. You can leave the default output format blank.
Here's an example:
```
# aws configure
AWS Access Key ID [None]: AKIA44HIGHQYZHRTZ7WP
AWS Secret Access Key [None]: qKVd5nMA7y8DbEuvF6kFbKTcYrAow8rH9KDxWGkT
Default region name [None]: us-east-1
Default output format [None]:
```
### Create SSM parameters for Breez credentials
From the command line, run the following commands:
```
aws ssm put-parameter --name "/breez-nodeless/api_key" --value "<REPLACE_WITH_BREEZ_API_KEY>" --type SecureString
```
```
aws ssm put-parameter --name "/breez-nodeless/seed_phrase" --value "<REPLACE_WITH_SEED_WORDS>" --type SecureString
```
```
aws ssm put-parameter --name "/breez-nodeless/api_secret" --value "<REPLACE_WITH_DESIRED_API_AUTHENTICATION_KEY>" --type SecureString
```
### Deploy Cloudformation stack
* Download this configuration file: [cloudformation.yaml](https://raw.githubusercontent.com/breez/nodeless-payments/refs/heads/main/cloudformation.yaml).
* Deploy the stack:
```
aws cloudformation create-stack --stack-name breez-integration --template-body file://cloudformation.yaml --capabilities CAPABILITY_IAM
```
* Monitor the stack creation (wait until it changes to *CREATE_COMPLETE*):
```
aws cloudformation describe-stacks --stack-name breez-integration --query Stacks[0].StackStatus
```
* Retrieve the API endpoints:
```
aws cloudformation describe-stacks --stack-name breez-integration --query 'Stacks[0].Outputs'
```
Output should look like this:
```
root@2edec8635e65:/# aws cloudformation describe-stacks --stack-name breez-integration --query 'Stacks[0].Outputs'
[
{
"OutputKey": "ApiGatewayBaseURL",
"OutputValue": "https://yxzjorems5.execute-api.us-east-1.amazonaws.com/prod",
"Description": "Base URL for API Gateway"
},
{
"OutputKey": "SendEndpoint",
"OutputValue": "https://yxzjorems5.execute-api.us-east-1.amazonaws.com/prod/send_payment",
"Description": "Send endpoint URL"
},
{
"OutputKey": "PaymentsEndpoint",
"OutputValue": "https://yxzjorems5.execute-api.us-east-1.amazonaws.com/prod/list_payments",
"Description": "Payments endpoint URL"
},
{
"OutputKey": "ReceiveEndpoint",
"OutputValue": "https://yxzjorems5.execute-api.us-east-1.amazonaws.com/prod/receive_payment",
"Description": "Receive endpoint URL"
}
]
```
* If the deployment was successful, you should deactivate your API key now.
### Example usage
#### Python
You can use `example-client.py`file from this to test the functionality. Take Base URL from the output of last command (see *ApiGatewayBaseURL* example above) and API_SECRET and edit the `example-client.py` with correct values
```
API_URL = "YOUR-URL-HERE"
API_KEY = "YOUR-SECRET-HERE"
```
For example-client to work, you need to have python installed together with requests library:
```
pip install requests
```
Then run:
```
python example-client.py
```
#### curl
If you don't have python installed, you can also just run a curl command.
For example, for the *list_payments* endpoint, run:
```
curl -X POST "<YOUR-URL-HERE>/list_payments" -H "Content-Type: application/json" -H "x-api-key: <API_SECRET>" -d '{}'
```
### Cleanup
To remove the stack you deployed you need to run the command delete-stack. This command starts the process to delete the stack, but it takes a while.
```
aws cloudformation delete-stack --stack-name breez-integration
```
You can use the same status command to see if its been successfully deleted:
```
aws cloudformation describe-stacks --stack-name breez-integration --query Stacks[0].StackStatus
```
You should also cleanup the parameters:
```
aws ssm delete-parameter --name "/breez-nodeless/api_key"
aws ssm delete-parameter --name "/breez-nodeless/seed_phrase"
aws ssm delete-parameter --name "/breez-nodeless/api_secret"
```

View File

@@ -1,168 +0,0 @@
AWSTemplateFormatVersion: "2010-09-09"
Description: "Deploys an API Gateway, Lambda function, and IAM roles for Breez integration."
Resources:
# IAM Role for Lambda Function
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: LambdaAccessPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: "arn:aws:logs:*:*:*"
- Effect: Allow
Action:
- s3:GetObject
Resource:
- "arn:aws:s3:::lambda-nodeless-payment/*"
- Effect: Allow
Action:
- ssm:GetParameter
Resource:
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/breez-nodeless/api_key"
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/breez-nodeless/seed_phrase"
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/breez-nodeless/api_secret"
# API Gateway
ApiGateway:
Type: AWS::ApiGateway::RestApi
Properties:
Name: BreezAPIGateway
Description: "API Gateway for Breez Lightning Network integration"
# API Resources for each endpoint
ApiListPaymentsResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref ApiGateway
ParentId: !GetAtt ApiGateway.RootResourceId
PathPart: "list_payments"
ApiReceiveResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref ApiGateway
ParentId: !GetAtt ApiGateway.RootResourceId
PathPart: "receive_payment"
ApiSendResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref ApiGateway
ParentId: !GetAtt ApiGateway.RootResourceId
PathPart: "send_payment"
# Lambda Function
BreezLambdaFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: BreezLambda
Runtime: python3.12
Handler: lambda_function.lambda_handler
Role: !GetAtt LambdaExecutionRole.Arn
Code:
S3Bucket: "breez-nodeless-payment"
S3Key: "lambda.zip"
Timeout: 30
Environment:
Variables:
PARAMETER_PREFIX: "/breez/"
# Allow API Gateway to invoke Lambda
LambdaInvokePermission:
Type: AWS::Lambda::Permission
DependsOn: BreezLambdaFunction
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !Ref BreezLambdaFunction
Principal: "apigateway.amazonaws.com"
SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGateway}/*/*/*"
# API Methods
GetPaymentsMethod:
Type: AWS::ApiGateway::Method
DependsOn: BreezLambdaFunction
Properties:
RestApiId: !Ref ApiGateway
ResourceId: !Ref ApiListPaymentsResource
HttpMethod: GET
AuthorizationType: NONE
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub
- "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaArn}/invocations"
- LambdaArn: !GetAtt BreezLambdaFunction.Arn
PostReceiveMethod:
Type: AWS::ApiGateway::Method
DependsOn: BreezLambdaFunction
Properties:
RestApiId: !Ref ApiGateway
ResourceId: !Ref ApiReceiveResource
HttpMethod: POST
AuthorizationType: NONE
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub
- "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaArn}/invocations"
- LambdaArn: !GetAtt BreezLambdaFunction.Arn
PostSendMethod:
Type: AWS::ApiGateway::Method
DependsOn: BreezLambdaFunction
Properties:
RestApiId: !Ref ApiGateway
ResourceId: !Ref ApiSendResource
HttpMethod: POST
AuthorizationType: NONE
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub
- "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaArn}/invocations"
- LambdaArn: !GetAtt BreezLambdaFunction.Arn
# API Deployment
ApiDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn:
- GetPaymentsMethod
- PostReceiveMethod
- PostSendMethod
- LambdaInvokePermission
Properties:
RestApiId: !Ref ApiGateway
StageName: "prod"
Outputs:
ApiGatewayBaseURL:
Description: "Base URL for API Gateway"
Value: !Sub "https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/prod"
PaymentsEndpoint:
Description: "Payments endpoint URL"
Value: !Sub "https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/prod/list_payments"
ReceiveEndpoint:
Description: "Receive endpoint URL"
Value: !Sub "https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/prod/receive_payment"
SendEndpoint:
Description: "Send endpoint URL"
Value: !Sub "https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/prod/send_payment"

View File

@@ -1,6 +0,0 @@
## Deploy lambda function
If you want to deploy your own changes directly to lambda you can use [deploy.sh](./deploy.sh) to package and deploy it for you. Tested on linux.
Requirements:
- aws cli installed and configured (instructions in [README.md](./README.md))
- python3.12 and pip installed

View File

@@ -1,28 +0,0 @@
### Code deployment
New code is automatically packaged and deployed to Breez's S3 bucket for public consumption.
### Create S3 bucket
```
aws s3api create-bucket --bucket breez-nodeless-payment --acl public-read
aws s3api delete-public-access-block --bucket breez-nodeless-payment
aws s3api put-bucket-policy --bucket breez-nodeless-payment --policy '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::breez-nodeless-payment/*"
}
]
}'
```
### Create user for github actions upload
```
aws iam create-user --user-name github-actions-user
aws iam put-user-policy --user-name github-actions-user --policy-name S3UploadPolicy --policy-document file://github-actions-policy.json
aws iam create-access-key --user-name github-actions-user
```

View File

@@ -1,30 +0,0 @@
#!/bin/bash
# Variables
FUNCTION_NAME="BreezLambda" # Match the FunctionName in CloudFormation
ZIP_FILE="lambda.zip"
# Install dependencies
echo "Installing dependencies..."
mkdir -p package
pip install -r requirements.txt -t package/
# Package the function
echo "Packaging the function..."
cp lambda_function.py package/
cd package
zip -r ../$ZIP_FILE .
cd ..
# Update Lambda function code directly
echo "Updating Lambda function code..."
aws lambda update-function-code \
--function-name $FUNCTION_NAME \
--zip-file fileb://$ZIP_FILE
# Clean up
rm -rf package
rm $ZIP_FILE
echo "Deployment complete!"

View File

@@ -1,20 +0,0 @@
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3Upload",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::breez-nodeless-payment/*"
},
{
"Sid": "AllowListBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::breez-nodeless-payment"
}
]
}

View File

@@ -1,5 +0,0 @@
![](./screenshot0.jpg)
![](./screenshot1.jpg)
![](./screenshot2.jpg)
![](./screenshot3.jpg)
![](./screenshot4.jpg)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

View File

@@ -1,68 +0,0 @@
import requests
import json
API_URL = "https://yxzjorems5.execute-api.us-east-1.amazonaws.com/prod"
API_KEY = "1234567890"
class BreezClient:
def __init__(self):
# Load API key from file
self.api_url = API_URL
self.headers = {
'Content-Type': 'application/json',
'x-api-key': API_KEY
}
def list_payments(self, from_timestamp=None, to_timestamp=None, offset=None, limit=None):
"""List all payments with optional filters."""
params = {
"from_timestamp": from_timestamp,
"to_timestamp": to_timestamp,
"offset": offset,
"limit": limit
}
response = requests.get(f"{self.api_url}/list_payments", params=params, headers=self.headers)
print(response.json())
print(self.headers)
return self._handle_response(response)
def receive_payment(self, amount, method="LIGHTNING"):
"""Generate a Lightning/Bitcoin/Liquid invoice to receive payment."""
payload = {
"amount": amount,
"method": method
}
response = requests.post(f"{self.api_url}/receive_payment", json=payload, headers=self.headers)
return self._handle_response(response)
def send_payment(self, destination, amount=None, drain=False):
"""Send a payment via Lightning or Liquid."""
payload = {
"destination": destination,
"amount": amount,
"drain": drain
}
response = requests.post(f"{self.api_url}/send_payment", json=payload, headers=self.headers)
return self._handle_response(response)
def _handle_response(self, response):
"""Helper method to handle API responses."""
if response.status_code == 200:
return response.json()
else:
return {"error": f"Request failed with status {response.status_code}", "details": response.text}
# Initialize client
breez = BreezClient()
# Example Usage
if __name__ == "__main__":
print("🔄 Listing Payments...")
print(breez.list_payments())
#print("\n💰 Receiving Payment...")
#print(breez.receive_payment(amount=1000, method="LIGHTNING"))
#print("\n🚀 Sending Payment...")
#print(breez.send_payment(destination="lnbc...", amount=1000))

View File

@@ -1,288 +0,0 @@
import json
import boto3
from typing import Optional
from breez_sdk_liquid import (
LiquidNetwork,
PayAmount,
ConnectRequest,
PrepareSendRequest,
SendPaymentRequest,
PrepareReceiveRequest,
ReceivePaymentRequest,
EventListener,
SdkEvent,
connect,
default_config,
PaymentMethod,
ListPaymentsRequest
)
import time
import logging
from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.utilities.typing import LambdaContext
logger = Logger()
tracer = Tracer()
app = APIGatewayRestResolver()
class SdkListener(EventListener):
def __init__(self):
self.synced = False
self.paid = []
def on_event(self, event):
if isinstance(event, SdkEvent.SYNCED):
self.synced = True
if isinstance(event, SdkEvent.PAYMENT_SUCCEEDED):
if event.details.destination:
self.paid.append(event.details.destination)
def is_paid(self, destination: str):
return destination in self.paid
class PaymentHandler:
def __init__(self):
self.breez_api_key = self._get_ssm_parameter('/breez-nodeless/api_key')
self.seed_phrase = self._get_ssm_parameter('/breez-nodeless/seed_phrase')
if not self.breez_api_key:
raise Exception("Missing Breez API key in Parameter Store")
if not self.seed_phrase:
raise Exception("Missing seed phrase in Parameter Store")
logger.info("Retrieved encrypted parameters successfully")
config = default_config(LiquidNetwork.MAINNET, self.breez_api_key)
config.working_dir = '/tmp'
connect_request = ConnectRequest(config=config, mnemonic=self.seed_phrase)
self.instance = connect(connect_request)
self.listener = SdkListener()
self.instance.add_event_listener(self.listener)
def _get_ssm_parameter(self, param_name: str) -> str:
"""Get an encrypted parameter from AWS Systems Manager Parameter Store"""
logger.info(f"Retrieving encrypted parameter: {param_name}")
ssm = boto3.client('ssm')
try:
response = ssm.get_parameter(
Name=param_name,
WithDecryption=True
)
return response['Parameter']['Value']
except ssm.exceptions.ParameterNotFound:
logger.error(f"Parameter {param_name} not found in Parameter Store")
raise Exception(f"Parameter {param_name} not found in Parameter Store")
except Exception as e:
logger.error(f"Failed to get parameter {param_name}: {str(e)}", exc_info=True)
raise Exception(f"Failed to get parameter {param_name}: {str(e)}")
def wait_for_sync(self, timeout_seconds: int = 30):
"""Wait for the SDK to sync before proceeding."""
start_time = time.time()
while time.time() - start_time < timeout_seconds:
if self.listener.synced:
return True
time.sleep(1)
raise Exception("Sync timeout: SDK did not sync within the allocated time.")
def wait_for_payment(self, destination: str, timeout_seconds: int = 60) -> bool:
"""Wait for payment to complete or timeout"""
start_time = time.time()
while time.time() - start_time < timeout_seconds:
if self.listener.is_paid(destination):
return True
time.sleep(1)
return False
def list_payments(self, params: dict = None) -> dict:
try:
self.wait_for_sync() # Ensure sync before executing
from_ts = int(params.get('from_timestamp')) if params and params.get('from_timestamp') is not None else None
to_ts = int(params.get('to_timestamp')) if params and params.get('to_timestamp') is not None else None
offset = int(params.get('offset')) if params and params.get('offset') is not None else None
limit = int(params.get('limit')) if params and params.get('limit') is not None else None
req = ListPaymentsRequest(
from_timestamp=from_ts,
to_timestamp=to_ts,
offset=offset,
limit=limit
)
payments = self.instance.list_payments(req)
payment_list = []
for payment in payments:
payment_dict = {
'timestamp': payment.timestamp,
'amount_sat': payment.amount_sat,
'fees_sat': payment.fees_sat,
'payment_type': str(payment.payment_type),
'status': str(payment.status),
'details': str(payment.details),
'destination': payment.destination,
'tx_id': payment.tx_id
}
payment_list.append(payment_dict)
# apply offset, limit and timestamp filters
print(f"payment_list: {payment_list}")
filtered_payments = []
for payment in payment_list:
if from_ts and payment['timestamp'] < from_ts:
continue
if to_ts and payment['timestamp'] > to_ts:
continue
if offset and offset > 0:
offset -= 1
continue
filtered_payments.append(payment)
# apply limit
if limit and limit < len(filtered_payments):
filtered_payments = filtered_payments[:limit]
# apply offset
if offset and offset > 0:
filtered_payments = payment_list[offset:]
if not (offset or limit or from_ts or to_ts):
return {
'statusCode': 200,
'body': json.dumps({
'payments': payment_list
})
}
# apply limit
return {
'statusCode': 200,
'body': json.dumps({
'payments': filtered_payments
})
}
except Exception as e:
return {
'statusCode': 500,
'body': json.dumps({'error': str(e)})
}
def receive_payment(self, amount: int, payment_method: str = 'LIGHTNING') -> dict:
try:
self.wait_for_sync() # Ensure sync before executing
prepare_req = PrepareReceiveRequest(getattr(PaymentMethod, payment_method), amount)
prepare_res = self.instance.prepare_receive_payment(prepare_req)
req = ReceivePaymentRequest(prepare_res)
res = self.instance.receive_payment(req)
# Return the invoice details immediately
return {
'statusCode': 200,
'body': json.dumps({
'destination': res.destination,
'fees_sat': prepare_res.fees_sat
})
}
except Exception as e:
return {'statusCode': 500, 'body': json.dumps({'error': str(e)})}
def send_payment(self, destination: str, amount: Optional[int] = None, drain: bool = False) -> dict:
try:
self.wait_for_sync() # Ensure sync before executing
pay_amount = PayAmount.DRAIN if drain else PayAmount.RECEIVER(amount) if amount else None
prepare_req = PrepareSendRequest(destination, pay_amount)
prepare_res = self.instance.prepare_send_payment(prepare_req)
req = SendPaymentRequest(prepare_res)
res = self.instance.send_payment(req)
return {'statusCode': 200, 'body': json.dumps({'payment_status': 'success', 'destination': res.payment.destination, 'fees_sat': prepare_res.fees_sat})}
except Exception as e:
return {'statusCode': 500, 'body': json.dumps({'error': str(e)})}
def validate_api_key(event):
"""Validate the API key from the request headers"""
try:
logger.info("Headers received: %s", json.dumps(event.get('headers', {})))
api_key = event.get('headers', {}).get('x-api-key')
if not api_key:
logger.warning("No API key provided in request headers")
return False
logger.info("API key found in headers")
# Get the stored API key from SSM
ssm = boto3.client('ssm')
try:
stored_key = ssm.get_parameter(
Name='/breez-nodeless/api_secret',
WithDecryption=True
)['Parameter']['Value']
logger.info("Successfully retrieved stored API key from SSM")
# Compare keys (safely log length but not the actual keys)
keys_match = api_key == stored_key
logger.info("API key validation result: %s (lengths: request=%d, stored=%d)",
keys_match, len(api_key), len(stored_key))
return keys_match
except ssm.exceptions.ParameterNotFound:
logger.error("SSM parameter /breez-nodeless/api_secret not found")
return False
except Exception as e:
logger.error(f"Error validating API key: {str(e)}", exc_info=True)
return False
@app.get("/list_payments")
@tracer.capture_method
def list_payments():
try:
if not validate_api_key(app.current_event):
return {"statusCode": 401, "body": json.dumps({"error": "Unauthorized"})}
logger.info("Processing list_payments request")
handler = PaymentHandler()
return handler.list_payments(app.current_event.query_string_parameters or {})
except Exception as e:
logger.error(f"Error listing payments: {str(e)}", exc_info=True)
return {"statusCode": 500, "body": json.dumps({"error": str(e)})}
@app.post("/receive_payment")
@tracer.capture_method
def receive_payment():
try:
if not validate_api_key(app.current_event):
return {"statusCode": 401, "body": json.dumps({"error": "Unauthorized"})}
body = app.current_event.json_body
logger.info(f"Processing receive_payment request with body: {body}")
handler = PaymentHandler()
return handler.receive_payment(
amount=body['amount'],
payment_method=body.get('method', 'LIGHTNING')
)
except Exception as e:
logger.error(f"Error receiving payment: {str(e)}", exc_info=True)
return {"statusCode": 500, "body": json.dumps({"error": str(e)})}
@app.post("/send_payment")
@tracer.capture_method
def send_payment():
try:
if not validate_api_key(app.current_event):
return {"statusCode": 401, "body": json.dumps({"error": "Unauthorized"})}
body = app.current_event.json_body
logger.info(f"Processing send_payment request with body: {body}")
handler = PaymentHandler()
return handler.send_payment(
destination=body['destination'],
amount=body.get('amount'),
drain=body.get('drain', False)
)
except Exception as e:
logger.error(f"Error sending payment: {str(e)}", exc_info=True)
return {"statusCode": 500, "body": json.dumps({"error": str(e)})}
@logger.inject_lambda_context
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context)

View File

@@ -1,6 +0,0 @@
aws-lambda-powertools
breez-sdk-liquid==0.6.3
boto3
python-dotenv
requests
aws-xray-sdk