Skip to content

Commit 4d5be44

Browse files
jimtracy1007wtfsayocoderabbitai[bot]
authored
feat:add plugin-lightning (#2429)
* feat:add plugin-lightning * fix:readme * Update packages/plugin-lightning/package.json Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update packages/plugin-lightning/tsup.config.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update packages/plugin-lightning/src/providers/lightning.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update packages/plugin-lightning/src/providers/lightning.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update payInvoice.ts * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update packages/plugin-lightning/src/actions/payInvoice.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update packages/plugin-lightning/src/actions/createInvoice.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update payInvoice.ts * Update package.json * code format * fix:pr 2429 code format --------- Co-authored-by: Sayo <hi@sayo.wtf> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent cfd1f48 commit 4d5be44

File tree

16 files changed

+1038
-257
lines changed

16 files changed

+1038
-257
lines changed

agent/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"@elizaos/plugin-hyperliquid": "workspace:*",
103103
"@elizaos/plugin-akash": "workspace:*",
104104
"@elizaos/plugin-quai": "workspace:*",
105+
"@elizaos/plugin-lightning": "workspace:*",
105106
"@elizaos/plugin-b2": "workspace:*",
106107
"@elizaos/plugin-nft-collections": "workspace:*",
107108
"@elizaos/plugin-pyth-data": "workspace:*",

agent/src/index.ts

+6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { DirectClient } from "@elizaos/client-direct";
1515
import { agentKitPlugin } from "@elizaos/plugin-agentkit";
1616
// import { ReclaimAdapter } from "@elizaos/plugin-reclaim";
1717
import { PrimusAdapter } from "@elizaos/plugin-primus";
18+
import { lightningPlugin } from "@elizaos/plugin-lightning";
1819
import { elizaCodeinPlugin, onchainJson } from "@elizaos/plugin-iq6900";
1920

2021
import {
@@ -1049,6 +1050,11 @@ export async function createAgent(
10491050
getSecret(character, "PYTH_MAINNET_PROGRAM_KEY")
10501051
? pythDataPlugin
10511052
: null,
1053+
getSecret(character, "LND_TLS_CERT") &&
1054+
getSecret(character, "LND_MACAROON") &&
1055+
getSecret(character, "LND_SOCKET")
1056+
? lightningPlugin
1057+
: null,
10521058
getSecret(character, "OPENAI_API_KEY") && getSecret(character, "ENABLE_OPEN_AI_COMMUNITY_PLUGIN")
10531059
? openaiPlugin
10541060
: null,

packages/plugin-lightning/README.md

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# @elizaos/plugin-lightning
2+
3+
This plugin enables create lightning invoice or payInvoice.
4+
5+
## Features
6+
7+
- 💱 Make a new off-chain invoice.
8+
- 📊 Make an off-chain payment.
9+
10+
## Installation
11+
12+
Add the plugin to your Eliza configuration:
13+
14+
```json
15+
{
16+
"plugins": ["@elizaos/plugin-lightning"]
17+
}
18+
```
19+
20+
## Configuration
21+
22+
Set the following environment variables:
23+
24+
```env
25+
LND_TLS_CERT=your_lnnode_tls_cert #Base64 of LND certificate
26+
LND_MACAROON=020..... #Base64 encoded admin.macaroon file
27+
LND_SOCKET='x.x.x.x:10009'
28+
```
29+
30+
## Available Actions
31+
32+
### 1. CREATE_INVOICE
33+
34+
Make a new off-chain invoice.
35+
36+
Examples:
37+
38+
```text
39+
40+
"Help me create an invoice for 1000sats"
41+
"Create an invoice for 1000sats"
42+
43+
```
44+
45+
Returns: lnbcrt....
46+
47+
### 2. PAY_INVOICE
48+
49+
Make an off-chain payment.
50+
51+
Examples:
52+
53+
```text
54+
55+
"Pay invoice lnbcrt10u1pncndjvpp58y77adkngcz3ypx6t39j245ydvk2vu67c8ugvegee3gt5wgs7yjqdxvdec82c33wdmnq73s0qcxwurrxp4nquncxe4h56m9xu6xwetyd3mrq6ehdguxkd35wuurgarex4u8gefkdsekgdtnddehxurrxecxvhmwwp6kyvfexekhxwtv8paryvnpwsuhxdryvachwangw3kn2atddq6kzvrvwfcxzanewce8ja34d43k56rkweu8jdtcwv68zmrsvdescqzzsxqrrsssp5q3hv38wfprvaazzwf8c4t33tzjcac5xz94sk8muehmn5szqaw6ks9qxpqysgqt5pjhna4922s8ayzgu5rh8clx7psp2culdr5r6cxxxqzs3e5ep345p45vggg0qegt6fu3prdrqgpd8v70l9wdhekt8gex5e8pqvxg2sp97fkmd"
56+
57+
58+
```
59+
60+
## Security Notes
61+
62+
- Store your LND_TLS_CERT and LND_MACAROON securely using environment variables
63+
- Test with small amounts first
64+
- Use regtest for initial testing
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import eslintGlobalConfig from "../../eslint.config.mjs";
2+
3+
export default [...eslintGlobalConfig];
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "@elizaos/plugin-lightning",
3+
"version": "0.1.8+build.1",
4+
"type": "module",
5+
"main": "dist/index.js",
6+
"module": "dist/index.js",
7+
"types": "dist/index.d.ts",
8+
"exports": {
9+
"./package.json": "./package.json",
10+
".": {
11+
"import": {
12+
"@elizaos/source": "./src/index.ts",
13+
"types": "./dist/index.d.ts",
14+
"default": "./dist/index.js"
15+
}
16+
}
17+
},
18+
"files": [
19+
"dist"
20+
],
21+
"dependencies": {
22+
"@elizaos/core": "workspace:*",
23+
"@elizaos/plugin-tee": "workspace:*",
24+
"astra-lightning": "^1.1.0"
25+
},
26+
"devDependencies": {
27+
"tsup": "8.3.5"
28+
},
29+
"scripts": {
30+
"build": "tsup --format esm --dts",
31+
"dev": "tsup --format esm --dts --watch",
32+
"lint": "eslint --fix --cache ."
33+
},
34+
"peerDependencies": {
35+
"whatwg-url": "7.1.0"
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import type { IAgentRuntime, Memory, State } from "@elizaos/core";
2+
import {
3+
composeContext,
4+
generateObjectDeprecated,
5+
ModelClass,
6+
elizaLogger,
7+
} from "@elizaos/core";
8+
9+
import {
10+
initLightningProvider,
11+
LightningProvider,
12+
} from "../providers/lightning";
13+
14+
import { createInvoiceTemplate } from "../templates";
15+
import { CreateInvoiceResult } from "astra-lightning";
16+
import { CreateInvoiceArgs } from "../types";
17+
export { createInvoiceTemplate };
18+
19+
export class CreateInvoiceAction {
20+
constructor(private lightningProvider: LightningProvider) {
21+
this.lightningProvider = lightningProvider;
22+
}
23+
24+
async createInvoice(
25+
params: CreateInvoiceArgs,
26+
): Promise<CreateInvoiceResult> {
27+
if (!params.tokens) {
28+
throw new Error("tokens is required.");
29+
}
30+
const retCreateInvoice =
31+
await this.lightningProvider.createInvoice(params);
32+
return retCreateInvoice;
33+
}
34+
}
35+
36+
export const createInvoiceAction = {
37+
name: "CREATE_INVOICE",
38+
description: "Create a Lightning invoice.",
39+
handler: async (
40+
runtime: IAgentRuntime,
41+
_message: Memory,
42+
state: State,
43+
_options: any,
44+
callback?: (response: {
45+
text: string;
46+
content?: { success: boolean; invoice?: string };
47+
}) => void,
48+
) => {
49+
elizaLogger.log("CreateInvoice action handler called");
50+
const lightningProvider = await initLightningProvider(runtime);
51+
const action = new CreateInvoiceAction(lightningProvider);
52+
53+
// Compose bridge context
54+
const createInvoiceContext = composeContext({
55+
state,
56+
template: createInvoiceTemplate,
57+
});
58+
const content = await generateObjectDeprecated({
59+
runtime,
60+
context: createInvoiceContext,
61+
modelClass: ModelClass.LARGE,
62+
});
63+
64+
const createInvoiceOptions = {
65+
tokens: content.tokens,
66+
};
67+
68+
try {
69+
const createInvoiceResp =
70+
await action.createInvoice(createInvoiceOptions);
71+
72+
if (callback) {
73+
callback({
74+
text: `Successfully created invoice for ${createInvoiceResp.tokens.toLocaleString()} sats\r\nInvoice: ${createInvoiceResp.request}`,
75+
content: {
76+
success: true,
77+
invoice: createInvoiceResp.request,
78+
},
79+
});
80+
}
81+
return true;
82+
} catch (error) {
83+
if (callback) {
84+
callback({ text: `Error: ${error.message}` });
85+
}
86+
return false;
87+
}
88+
},
89+
template: createInvoiceTemplate,
90+
validate: async (runtime: IAgentRuntime) => {
91+
const cert = runtime.getSetting("LND_TLS_CERT");
92+
const macaroon = runtime.getSetting("LND_MACAROON");
93+
const socket = runtime.getSetting("LND_SOCKET");
94+
return !!cert && !!macaroon && !!socket;
95+
},
96+
examples: [
97+
[
98+
{
99+
user: "user",
100+
content: {
101+
text: "Create an invoice for 1000 sats",
102+
action: "CREATE_INVOICE",
103+
},
104+
},
105+
],
106+
],
107+
similes: ["CREATE_INVOICE"],
108+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import type { IAgentRuntime, Memory, State } from "@elizaos/core";
2+
import {
3+
composeContext,
4+
generateObjectV2,
5+
ModelClass,
6+
elizaLogger,
7+
} from "@elizaos/core";
8+
9+
import {
10+
initLightningProvider,
11+
LightningProvider,
12+
} from "../providers/lightning";
13+
import { PayResult } from "astra-lightning";
14+
import { PayArgs } from "../types";
15+
import { payInvoiceTemplate } from "../templates";
16+
17+
export { payInvoiceTemplate };
18+
19+
type ExtendedPayResult = PayResult & { outgoing_channel: string };
20+
export class PayInvoiceAction {
21+
constructor(private lightningProvider: LightningProvider) {
22+
this.lightningProvider = lightningProvider;
23+
}
24+
25+
async getAvalibleChannelId(): Promise<string> {
26+
const { channels } = await this.lightningProvider.getLndChannel();
27+
const filteredActiveChannels = channels.filter(
28+
(channel) => channel.is_active === true,
29+
);
30+
const sortedChannels = filteredActiveChannels.sort(
31+
(a, b) => b.local_balance - a.local_balance,
32+
);
33+
if (sortedChannels.length > 0) {
34+
return sortedChannels[0].id;
35+
}
36+
return "";
37+
}
38+
async payInvoice(params: PayArgs): Promise<ExtendedPayResult> {
39+
const outgoing_channel = await this.getAvalibleChannelId();
40+
if (!outgoing_channel) {
41+
throw new Error("no avalible channel");
42+
}
43+
const requestArgs = {
44+
outgoing_channel: outgoing_channel,
45+
...params,
46+
};
47+
const retPayInvoice =
48+
await this.lightningProvider.payInvoice(requestArgs);
49+
return {
50+
...retPayInvoice,
51+
outgoing_channel: outgoing_channel,
52+
};
53+
}
54+
}
55+
56+
export const payInvoiceAction = {
57+
name: "PAY_INVOICE",
58+
description: "Make a payment.",
59+
handler: async (
60+
runtime: IAgentRuntime,
61+
_message: Memory,
62+
state: State,
63+
_options: any,
64+
callback?: any,
65+
) => {
66+
elizaLogger.log("payInvoice action handler called");
67+
const lightningProvider = await initLightningProvider(runtime);
68+
const action = new PayInvoiceAction(lightningProvider);
69+
70+
// Compose bridge context
71+
const payInvoiceContext = composeContext({
72+
state,
73+
template: payInvoiceTemplate,
74+
});
75+
const content = await generateObjectV2({
76+
runtime,
77+
context: payInvoiceContext,
78+
modelClass: ModelClass.LARGE,
79+
});
80+
81+
const payInvoiceOptions: PayArgs = {
82+
request: content.request,
83+
outgoing_channel: content.outgoing_channel,
84+
};
85+
86+
try {
87+
const payInvoiceResp = await action.payInvoice(payInvoiceOptions);
88+
elizaLogger.log("🚀 ~ payInvoiceResp:", payInvoiceResp);
89+
90+
if (callback) {
91+
const text = "";
92+
if (payInvoiceResp.is_confirmed) {
93+
callback({
94+
text: `Successfully paid invoice ${content.request} from ${payInvoiceResp.outgoing_channel};\nAmount: ${payInvoiceResp.tokens};\nFee: ${payInvoiceResp.fee};\nPayment Hash: ${payInvoiceResp.id};`,
95+
content: { success: true },
96+
});
97+
} else {
98+
callback({
99+
text: `Failed to payInvoice ${content.request} from ${content.outgoing_channel};\r\n Amount: ${payInvoiceResp.tokens};`,
100+
content: {
101+
success: false,
102+
},
103+
});
104+
}
105+
}
106+
return true;
107+
} catch (error) {
108+
elizaLogger.error("Error in payInvoice handler:", error);
109+
if (callback) {
110+
callback({
111+
text: `Error: ${error.message || "An error occurred"}`,
112+
});
113+
}
114+
return false;
115+
}
116+
},
117+
template: payInvoiceTemplate,
118+
validate: async (runtime: IAgentRuntime) => {
119+
const cert = runtime.getSetting("LND_TLS_CERT");
120+
const macaroon = runtime.getSetting("LND_MACAROON");
121+
const socket = runtime.getSetting("LND_SOCKET");
122+
return !!cert && !!macaroon && !!socket;
123+
},
124+
examples: [
125+
[
126+
{
127+
user: "user",
128+
content: {
129+
text: "Pay invoice for lnbrc...",
130+
action: "PAY_INVOICE",
131+
},
132+
},
133+
],
134+
],
135+
similes: ["PAY_INVOICE", "MAKE_PAYMENT"],
136+
};
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export * from "./actions/createInvoice";
2+
export * from "./providers/lightning";
3+
export * from "./types";
4+
5+
import type { Plugin } from "@elizaos/core";
6+
import { createInvoiceAction } from "./actions/createInvoice";
7+
import { payInvoiceAction } from "./actions/payInvoice";
8+
9+
export const lightningPlugin: Plugin = {
10+
name: "lightning",
11+
description: "lightning integration plugin",
12+
actions: [createInvoiceAction, payInvoiceAction],
13+
};
14+
15+
export default lightningPlugin;

0 commit comments

Comments
 (0)