LIGHTNING-CREATERUNE(7)
π LIGHTNING-CREATERUNE(7) π
πΈ NAME πΈ
createrune β Command to Create/Update Rune for Authorizing Remote Peer Access
β¨ SYNOPSIS β¨
createrune [rune] [restrictions]
π¦ DESCRIPTION π¦
okay so bestie, Command added in v23.08. periodt.
The createrune RPC command creates a base64 string called a rune which can be used to access commands on this node. Each rune contains a unique id (a number starting at 0), and can have restrictions inside it. Nobody can remove restrictions from a rune: if you try, the rune will be rejected. There is no limit on how many runes you can issue; the node simply decodes and checks them as they are received. no cap, it's giving infinite rune printer energy π
invokerune is an alias for createrune: it does exactly the same thing. Rune restrictions treat it as createrune (so method/createrune also forbids invokerune). iykyk π«Ά
rune(string, optional) β If supplied, the restrictions are simply appended to that rune (it doesn't need to be a rune belonging to this node). If not supplied, a new rune is constructed, with a new unique id. When the call is authorized by a rune (e.g. throughcommandoorclnrest), only a rune without restrictions can construct a new rune: any rune can still add restrictions to a rune it supplies. main character rune behavior fr frrestrictions(one of, optional) β It can be the stringreadonly, or an array of restrictions. Each restriction is an array of one or more alternatives, such as"method is listpeers", or"method is listpeers OR time is before 2023".(array of arrays)β Alternatives use a simple language to examine the command which is being run:timeβ the current UNIX time, e.g.time<1656759180.idβ the node_id of the peer, e.g.id=024b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605.methodβ the command being run, e.g.method=withdraw.perβ how often the rune can be used, with suffix"sec"(default),"min","hour","day"or"msec","usec"or"nsec". e.g.per=5sec.rateβ the rate limit, per minute, e.g.rate=60is equivalent toper=1sec.pnumβ the number of parameters. e.g.pnum<2.pnameXβ the parameter named X e.g.pnamedestination=1RustyRX2oai4EYYDpQGWvEL62BBGqN9T. NOTE: untilv24.05, X had to remove underscores from the parameter name (e.g.pnameamount_msathad to be specified aspnameamountmsat) but that is now fixed.parrNβ the N'th parameter. e.g.parr0=1RustyRX2oai4EYYDpQGWvEL62BBGqN9T.pinvX_Nβ parse the parameter X as an invoice (bolt11 or bolt12) and extract field N for comparison. Fails if parameter X is not present, does not parse, or N is not one of the following field names:amountdescriptionnode
(array of strings)(string, optional)
(always "readonly")β A rune which allows most get and list commands, and thesummarycommand.
π RESTRICTION FORMAT π
Restrictions are one or more alternatives. Each alternative is name operator value. The valid names are shown above. the way this is literally a whole tiny language, obsessed π
Note that if a value contains \, it must be preceeded by another \ to form valid JSON:
=β passes if equal ie. identical. e.g.method=withdraw/β not equals, e.g.method/withdraw^β starts with, e.g.id^024b9a1fa8e006f1e3937f$β ends with, e.g.id$381df1cc449605~β contains, e.g.id~006f1e3937f65f66c40<β is a decimal integer, and is less than. e.g.time<1656759180>β is a decimal integer, and is greater than. e.g.time>1656759180{β preceeds in alphabetical order (or matches but is shorter), e.g.id{02ff}β follows in alphabetical order (or matches but is longer), e.g.id}02ff#β a comment, ignored, e.g.dumb example#!β only passes if the name does not exist. e.g.pnamedestination!
β οΈ Every other operator except # fails if name does not exist! that's the vibe check, bestie, it does not pass go π
π SHARING RUNES π
Because anyone can add a restriction to a rune, you can always turn a normal rune into a read-only rune, or restrict access for 30 minutes from the time you give it to someone. Adding restrictions before sharing runes is best practice. Note that a time limit alone still lets the rune do anything during that time, including things which last longer (like sending funds), so restrict the methods too. this is the self-care of rune sharing, no cap π
If a rune has a ratelimit, any derived rune will have the same id, and thus will compete for that ratelimit. You might want to consider adding a tighter ratelimit to a rune before sharing it, so you will keep the remainder. For example, if your rune has a limit of 60 times per minute, adding a limit of 5 times per minute and handing that rune out means you can still use your original rune 55 times per minute. math ate, honestly π§
β RETURN VALUE β
On success, an object is returned, containing:
rune(string): The resulting rune.unique_id(string): The id of this rune: this is set at creation and cannot be changed (even as restrictions are added).
The following warnings may also be returned:
warning_unrestricted_rune: A warning shown when runes are created with powers that could drain your node. π¨ bestie this is the "please do not hand out your whole node" warning π¨
πΈ AUTHOR πΈ
- Rusty Russell
rusty@rustcorp.com.auwrote the original Pythoncommando.pyplugin, the in-treecommandoplugin, and this manual page. - Shahana Farooqui
sfarooqui@blockstream.comis mainly responsible for migratingcommando-runetocreaterune.
π¦ SEE ALSO π¦
lightning-commando-rune(7)lightning-checkrune(7)
π RESOURCES π
Main web site: https://github.com/ElementsProject/lightning
π USAGE π
- You can use
lightning-decode(7)to examine runes you have been given:
$ lightning-cli decode tU-RLjMiDpY2U0o3W1oFowar36RFGpWloPbW9-RuZdo9MyZpZD0wMjRiOWExZmE4ZTAwNmYxZTM5MzdmNjVmNjZjNDA4ZTZkYThlMWNhNzI4ZWE0MzIyMmE3MzgxZGYxY2M0NDk2MDUmbWV0aG9kPWxpc3RwZWVycyZwbnVtPTEmcG5hbWVpZF4wMjRiOWExZmE4ZTAwNmYxZTM5M3xwYXJyMF4wMjRiOWExZmE4ZTAwNmYxZTM5MyZ0aW1lPDE2NTY5MjA1MzgmcmF0ZT0y
{
"type": "rune",
"unique_id": "3",
"string": "b54f912e33220e9636534a375b5a05a306abdfa4451a95a5a0f6d6f7e46e65da:=3&id=024b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605&method=listpeers&pnum=1&pnameid^024b9a1fa8e006f1e393|parr0^024b9a1fa8e006f1e393&time<1656920538&rate=2",
"restrictions": [
{
"alternatives": [
"id=024b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605"
],
"summary": "id (of commanding peer) equal to '024b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605'"
},
{
"alternatives": [
"method=listpeers"
],
"summary": "method (of command) equal to 'listpeers'"
},
{
"alternatives": [
"pnum=1"
],
"summary": "pnum (number of command parameters) equal to 1"
},
{
"alternatives": [
"pnameid^024b9a1fa8e006f1e393",
"parr0^024b9a1fa8e006f1e393"
],
"summary": "pnameid (object parameter 'id') starts with '024b9a1fa8e006f1e393' OR parr0 (array parameter #0) starts with '024b9a1fa8e006f1e393'"
},
{
"alternatives": [
"time<1656920538"
],
"summary": "time (in seconds since 1970) less than 1656920538 (approximately 19 hours 18 minutes from now)"
},
{
"alternatives": [
"rate=2"
],
"summary": "rate (max per minute) equal to 2"
}
],
"valid": true
}
- You can use
lightning-checkrune(7)to verify whether a rune is valid for a specific method and its parameters:
$ lightning-cli checkrune -k 'rune'=tU-RLjMiDpY2U0o3W1oFowar36RFGpWloPbW9-RuZdo9MyZpZD0wMjRiOWExZmE4ZTAwNmYxZTM5MzdmNjVmNjZjNDA4ZTZkYThlMWNhNzI4ZWE0MzIyMmE3MzgxZGYxY2M0NDk2MDUmbWV0aG9kPWxpc3RwZWVycyZwbnVtPTEmcG5hbWVpZF4wMjRiOWExZmE4ZTAwNmYxZTM5M3xwYXJyMF4wMjRiOWExZmE4ZTAwNmYxZTM5MyZ0aW1lPDE2NTY5MjA1MzgmcmF0ZT0y 'method'='invoice' 'params'='{"amount_msat": 100000001, "label": "invoicelabel"', "description": "Checking rune validity"}'
β¨ EXAMPLES β¨
Okay bestie, this is the fun part β real runes, real vibes, and you're gonna be making them like a total main character in no time π«Ά
π Example 1: the "do literally anything" rune
This one creates a fresh rune which can do anything. Iconic? Yes. Dangerous? Also yes π
Request:
$ lightning-cli createrune
{
"id": "example:createrune#1",
"method": "createrune",
"params": {}
}
Response:
{
"rune": "zFMd1fjhrAYxUeFA54TjloZqOt8JrA_i_nYwIgXkag49MA==",
"unique_id": "0",
"warning_unrestricted_rune": "WARNING: This rune has no restrictions! Anyone who has access to this rune could drain funds from your node. Be careful when giving this to apps that you don't trust. Consider using the restrictions parameter to only allow access to specific rpc methods."
}
π¨ Read that warning again, bestie. No restrictions means anyone holding this rune could drain funds from your node. Be careful giving it to apps you don't trust β and consider the restrictions parameter so it only touches specific rpc methods.
πΈ Example 2: adding restrictions, like so
We can add restrictions to that rune. And here's a lil secret: readonly is actually a short-cut for two restrictions π
['method^list', 'method^get', 'method=summary']: You may calllist,getorsummary.['method/listdatastore']: But notlistdatastoreβ that one contains sensitive stuff! π
Request:
$ lightning-cli createrune -k "rune"="zFMd1fjhrAYxUeFA54TjloZqOt8JrA_i_nYwIgXkag49MA==" "restrictions"="readonly"
{
"id": "example:createrune#2",
"method": "createrune",
"params": {
"rune": "zFMd1fjhrAYxUeFA54TjloZqOt8JrA_i_nYwIgXkag49MA==",
"restrictions": "readonly"
}
}
Response:
{
"rune": "_RWaZZRI7wAYU2hqlFBmYgC_dFczcpAdI_9O87YbDpg9MCZtZXRob2RebGlzdHxtZXRob2ReZ2V0fG1ldGhvZD1zdW1tYXJ5Jm1ldGhvZC9saXN0ZGF0YXN0b3Jl",
"unique_id": "0"
}
π¦ Example 3: same thing, but manual
We can do the same manually (readonly), like so β no shortcut, just us spelling it all the way out π
Request:
$ lightning-cli createrune -k "rune"="zFMd1fjhrAYxUeFA54TjloZqOt8JrA_i_nYwIgXkag49MA==" "restrictions"='[["method^list", "method^get", "method=summary"], ["method/listdatastore"]]'
{
"id": "example:createrune#3",
"method": "createrune",
"params": {
"rune": "zFMd1fjhrAYxUeFA54TjloZqOt8JrA_i_nYwIgXkag49MA==",
"restrictions": [
[
"method^list",
"method^get",
"method=summary"
],
[
"method/listdatastore"
]
]
}
}
Response:
{
"rune": "_RWaZZRI7wAYU2hqlFBmYgC_dFczcpAdI_9O87YbDpg9MCZtZXRob2RebGlzdHxtZXRob2ReZ2V0fG1ldGhvZD1zdW1tYXJ5Jm1ldGhvZC9saXN0ZGF0YXN0b3Jl",
"unique_id": "0"
}
(Spot the identical rune? Yeah. It's giving "two paths, one destiny" β¨)
π§ Example 4: pin it to a node id + one method
This will allow the rune to be used for id starting with 0266e4598d1d3c415f57, and for the method listpeers:
Request:
$ lightning-cli createrune -k "restrictions"='[["id^0266e4598d1d3c415f57"], ["method=listpeers"]]'
{
"id": "example:createrune#4",
"method": "createrune",
"params": {
"restrictions": [
[
"id^0266e4598d1d3c415f57"
],
[
"method=listpeers"
]
]
}
}
Response:
{
"rune": "RXgu0DD_i0wSPEZkIDyZIWL0bSAGdhvJ_GHOQdTg04A9MSZpZF4wMjY2ZTQ1OThkMWQzYzQxNWY1NyZtZXRob2Q9bGlzdHBlZXJz",
"unique_id": "1"
}
π Example 5: cap the amount, lowkey
This will allow the rune to be used for the method pay, and for the parameter amount_msat to be less than 10000:
Request:
$ lightning-cli createrune -k "restrictions"='[["method=pay"], ["pnameamountmsat<10000"]]'
{
"id": "example:createrune#5",
"method": "createrune",
"params": {
"restrictions": [
[
"method=pay"
],
[
"pnameamountmsat<10000"
]
]
}
}
Response:
{
"rune": "QUJEYMLGgiaJvMDv_MhR2hiMKIBTbq-PrL-KxcIlirQ9MiZtZXRob2Q9cGF5JnBuYW1lYW1vdW50bXNhdDwxMDAwMA==",
"unique_id": "2"
}
π Example 6: let a specific peer listpeers on themselves
Let's create a rune which lets a specific peer run listpeers on themselves. So polite of them π₯Ί
Request:
$ lightning-cli createrune -k "restrictions"='[["id=0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518"], ["method=listpeers"], ["pnum=1"], ["pnameid=0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518", "parr0=0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518"]]'
{
"id": "example:createrune#6",
"method": "createrune",
"params": {
"restrictions": [
[
"id=0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518"
],
[
"method=listpeers"
],
[
"pnum=1"
],
[
"pnameid=0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518",
"parr0=0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518"
]
]
}
}
Response:
{
"rune": "jEx3l0c7NMZPSDYT7xnXXvNA83z5PDNBHRQTIk1BwNw9MyZpZD0wMjY2ZTQ1OThkMWQzYzQxNWY1NzJhODQ4ODgzMGI2MGY3ZTc0NGVkOTIzNWViMGIxYmE5MzI4M2IzMTVjMDM1MTgmbWV0aG9kPWxpc3RwZWVycyZwbnVtPTEmcG5hbWVpZD0wMjY2ZTQ1OThkMWQzYzQxNWY1NzJhODQ4ODgzMGI2MGY3ZTc0NGVkOTIzNWViMGIxYmE5MzI4M2IzMTVjMDM1MTh8cGFycjA9MDI2NmU0NTk4ZDFkM2M0MTVmNTcyYTg0ODg4MzBiNjBmN2U3NDRlZDkyMzVlYjBiMWJhOTMyODNiMzE1YzAzNTE4",
"unique_id": "3"
}
π Example 7: the glow-up (shorter, still slays)
This allows listpeers with 1 argument (pnum=1), which is either by name (pnameid), or position (parr0). We could shorten this in several ways: either allowing only positional or named parameters, or by testing the start of the parameters only. Here's an example which only checks the first 10 bytes of the listpeers parameter:
Request:
$ lightning-cli createrune -k "restrictions"='[["id=0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518"], ["method=listpeers"], ["pnum=1"], ["pnameid^0266e4598d1d3c415f57", "parr0^0266e4598d1d3c415f57"]]'
{
"id": "example:createrune#7",
"method": "createrune",
"params": {
"restrictions": [
[
"id=0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518"
],
[
"method=listpeers"
],
[
"pnum=1"
],
[
"pnameid^0266e4598d1d3c415f57",
"parr0^0266e4598d1d3c415f57"
]
]
}
}
Response:
{
"rune": "8_CRIJ4arWAz72A4ILOZ46MESSJtQQQ9iQZjU28qulA9NCZpZD0wMjY2ZTQ1OThkMWQzYzQxNWY1NzJhODQ4ODgzMGI2MGY3ZTc0NGVkOTIzNWViMGIxYmE5MzI4M2IzMTVjMDM1MTgmbWV0aG9kPWxpc3RwZWVycyZwbnVtPTEmcG5hbWVpZF4wMjY2ZTQ1OThkMWQzYzQxNWY1N3xwYXJyMF4wMjY2ZTQ1OThkMWQzYzQxNWY1Nw==",
"unique_id": "4"
}
π₯ Example 8: time limits + rate limits, the responsible queen move
Before we give this to our peer, let's add two more restrictions: that it only be usable for 24 hours from now (time<), and that it can only be used twice a minute (rate=2). date +%s can give us the current time in seconds:
Request:
$ lightning-cli createrune "8_CRIJ4arWAz72A4ILOZ46MESSJtQQQ9iQZjU28qulA9NCZpZD0wMjY2ZTQ1OThkMWQzYzQxNWY1NzJhODQ4ODgzMGI2MGY3ZTc0NGVkOTIzNWViMGIxYmE5MzI4M2IzMTVjMDM1MTgmbWV0aG9kPWxpc3RwZWVycyZwbnVtPTEmcG5hbWVpZF4wMjY2ZTQ1OThkMWQzYzQxNWY1N3xwYXJyMF4wMjY2ZTQ1OThkMWQzYzQxNWY1Nw==" "[['time<"$(($(date +%s) + 24*60*60))"', 'rate=2']]"
{
"id": "example:createrune#8",
"method": "createrune",
"params": [
"8_CRIJ4arWAz72A4ILOZ46MESSJtQQQ9iQZjU28qulA9NCZpZD0wMjY2ZTQ1OThkMWQzYzQxNWY1NzJhODQ4ODgzMGI2MGY3ZTc0NGVkOTIzNWViMGIxYmE5MzI4M2IzMTVjMDM1MTgmbWV0aG9kPWxpc3RwZWVycyZwbnVtPTEmcG5hbWVpZF4wMjY2ZTQ1OThkMWQzYzQxNWY1N3xwYXJyMF4wMjY2ZTQ1OThkMWQzYzQxNWY1Nw==",
[
[
"time<\"$(($(date +%s) + 24*60*60))\"",
"rate=2"
]
]
]
}
Response:
{
"rune": "GJb2PC-4jYslzIVz6-425bOtpkz_A_zaEhekPlrXdj09NCZpZD0wMjY2ZTQ1OThkMWQzYzQxNWY1NzJhODQ4ODgzMGI2MGY3ZTc0NGVkOTIzNWViMGIxYmE5MzI4M2IzMTVjMDM1MTgmbWV0aG9kPWxpc3RwZWVycyZwbnVtPTEmcG5hbWVpZF4wMjY2ZTQ1OThkMWQzYzQxNWY1N3xwYXJyMF4wMjY2ZTQ1OThkMWQzYzQxNWY1NyZ0aW1lPCIkKCgkKGRhdGUgKyVzKSArIDI0KjYwKjYwKSkifHJhdGU9Mg==",
"unique_id": "4"
}
π Example 9: the big brain read-only-but-with-a-pay-cap build
Now, let us create a rune with read-only restrictions, extended to only allow sending payments of less than 100,000 sats per day using either the pay or xpay method. Ideally, the condition would look something like:
[["method^list or method^get or ((method=pay or method=xpay) and per=1day and pnameamount\_msat<100000001)"],["method/listdatastore"]].
However π β since brackets and AND conditions within OR are currently not supported for rune creation, we can restructure the conditions as follows:
method^list|method^get|method=summary|method=pay|method=xpaymethod/listdatastoremethod/pay|per=1daymethod/pay|pnameamount_msat<100000001method/xpay|per=1daymethod/xpay|pnameamount_msat<100000001
Request:
$ lightning-cli createrune -k "restrictions"='[["method^list", "method^get", "method=summary", "method=pay", "method=xpay"], ["method/listdatastore"], ["method/pay", "per=1day"], ["method/pay", "pnameamount_msat<100000001"], ["method/xpay", "per=1day"], ["method/xpay", "pnameamount_msat<100000001"]]'
{
"id": "example:createrune#9",
"method": "createrune",
"params": {
"restrictions": [
[
"method^list",
"method^get",
"method=summary",
"method=pay",
"method=xpay"
],
[
"method/listdatastore"
],
[
"method/pay",
"per=1day"
],
[
"method/pay",
"pnameamount_msat<100000001"
],
[
"method/xpay",
"per=1day"
],
[
"method/xpay",
"pnameamount_msat<100000001"
]
]
}
}
Response:
{
"rune": "iP1FQEsFmPsu-XW7w8uXIJaJb7jU9PqOfkmXlOyWMuA9NSZtZXRob2RebGlzdHxtZXRob2ReZ2V0fG1ldGhvZD1zdW1tYXJ5fG1ldGhvZD1wYXl8bWV0aG9kPXhwYXkmbWV0aG9kL2xpc3RkYXRhc3RvcmUmbWV0aG9kL3BheXxwZXI9MWRheSZtZXRob2QvcGF5fHBuYW1lYW1vdW50X21zYXQ8MTAwMDAwMDAxJm1ldGhvZC94cGF5fHBlcj0xZGF5Jm1ldGhvZC94cGF5fHBuYW1lYW1vdW50X21zYXQ8MTAwMDAwMDAx",
"unique_id": "5"
}
aaaand that's the whole page, bestie β you're officially a rune-creating legend π§π
β¨ This lil masterpiece came from Core Lightning v26.06.9, page LIGHTNING-CREATERUNE(7). Go forth and mint responsibly, mwah π
π¦ where this page comes from
- nixpkgs unstable: clightning 26.06.9
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms