Oak

Check-in [56e9d9ba16]
Login

Check-in [56e9d9ba16]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:ref(deps): Bump ln-sdk and powpub dependencies
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 56e9d9ba16396d4b2a0a4402516420e0de3e538a425316b0554d80e21c03d381
User & Date: carlos 2023-10-19 08:37:33
Context
2023-10-22
09:46
ref(deps): Bump ln-sdk and powpub dependencies check-in: 8321f1314c user: carlos tags: trunk
2023-10-19
08:37
ref(deps): Bump ln-sdk and powpub dependencies check-in: 56e9d9ba16 user: carlos tags: trunk
2023-09-24
11:19
ref(deps): Bump dependency versions check-in: d02cac6ce0 user: carlos tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Cargo.lock.

2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"

[[package]]
name = "ln-sdk"
version = "0.2.0-SNAPSHOT"
source = "git+https://oak-node.net/cgit/ln-sdk.git?rev=8a0594cd359fca13bda40ae59199f3bc2b743edb#8a0594cd359fca13bda40ae59199f3bc2b743edb"
dependencies = [
 "anyhow",
 "async-trait",
 "base64 0.20.0",
 "bech32",
 "cfg_aliases",
 "hex",







|







2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"

[[package]]
name = "ln-sdk"
version = "0.2.0-SNAPSHOT"
source = "git+https://oak-node.net/cgit/ln-sdk.git?rev=7c7fa4a10700d564de26d3d98515aa031f177ac1#7c7fa4a10700d564de26d3d98515aa031f177ac1"
dependencies = [
 "anyhow",
 "async-trait",
 "base64 0.20.0",
 "bech32",
 "cfg_aliases",
 "hex",
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
 "flate2",
 "miniz_oxide",
]

[[package]]
name = "powpub"
version = "0.1.4-SNAPSHOT"
source = "git+https://oak-node.net/cgit/powpub.git?rev=1a82c6ea2daa04ac8d728457cd0ce6ff9169fe5b#1a82c6ea2daa04ac8d728457cd0ce6ff9169fe5b"
dependencies = [
 "anyhow",
 "async-trait",
 "base64 0.20.0",
 "bech32",
 "cfg_aliases",
 "env_logger",







|







3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
 "flate2",
 "miniz_oxide",
]

[[package]]
name = "powpub"
version = "0.1.4-SNAPSHOT"
source = "git+https://oak-node.net/cgit/powpub.git?rev=bce7286270055ec85ff77cac19cd3df36228782a#bce7286270055ec85ff77cac19cd3df36228782a"
dependencies = [
 "anyhow",
 "async-trait",
 "base64 0.20.0",
 "bech32",
 "cfg_aliases",
 "env_logger",

Changes to Cargo.toml.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
chrono = { version = "*", default-features = false }
deltachat = { git = "https://github.com/deltachat/deltachat-core-rust", tag="1.108.0"}
futures-lite = "*"
futures-util = "*"
hex = "*"
itertools = "*"
lightning-invoice = "*"
ln-sdk = { git = "https://oak-node.net/cgit/ln-sdk.git", rev = "8a0594cd359fca13bda40ae59199f3bc2b743edb", features = [ "client-lnd", "utoipa" ] }
log = "*"
log4rs = "*"
qrcode-generator = "*"
nostr = { git = "https://github.com/rust-nostr/nostr", default-features = false, features = ["nip04", "nip05", "nip47"], tag = "v0.24.0" }
nostr-sdk = { git = "https://github.com/rust-nostr/nostr", default-features = false, tag = "v0.24.0" }
powpub = { git = "https://oak-node.net/cgit/powpub.git", rev = "1a82c6ea2daa04ac8d728457cd0ce6ff9169fe5b", features = [ "client-lnd", "utoipa" ] }
reqwest = { version = "*", default-features = false, features = ["json", "native-tls", "socks"] }
rocket = { version = "0.5.0-rc.3", features = ["json"] }
rocket_db_pools = { version = "0.1.0-rc.3", features = ["sqlx_sqlite"] }
rocket_dyn_templates = { version = "0.1.0-rc.3", features = ["tera"] }
serde = "*"
serde_json = "*"
serde_with = "*"







|





|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
chrono = { version = "*", default-features = false }
deltachat = { git = "https://github.com/deltachat/deltachat-core-rust", tag="1.108.0"}
futures-lite = "*"
futures-util = "*"
hex = "*"
itertools = "*"
lightning-invoice = "*"
ln-sdk = { git = "https://oak-node.net/cgit/ln-sdk.git", rev = "7c7fa4a10700d564de26d3d98515aa031f177ac1", features = [ "client-lnd", "utoipa" ] }
log = "*"
log4rs = "*"
qrcode-generator = "*"
nostr = { git = "https://github.com/rust-nostr/nostr", default-features = false, features = ["nip04", "nip05", "nip47"], tag = "v0.24.0" }
nostr-sdk = { git = "https://github.com/rust-nostr/nostr", default-features = false, tag = "v0.24.0" }
powpub = { git = "https://oak-node.net/cgit/powpub.git", rev = "bce7286270055ec85ff77cac19cd3df36228782a", features = [ "client-lnd", "utoipa" ] }
reqwest = { version = "*", default-features = false, features = ["json", "native-tls", "socks"] }
rocket = { version = "0.5.0-rc.3", features = ["json"] }
rocket_db_pools = { version = "0.1.0-rc.3", features = ["sqlx_sqlite"] }
rocket_dyn_templates = { version = "0.1.0-rc.3", features = ["tera"] }
serde = "*"
serde_json = "*"
serde_with = "*"

Changes to src/api/bot.rs.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

21




22
23
24
25
26
27
28



use ::hex::ToHex;
use deltachat::context::Context;
use deltachat::securejoin;
use nostr::prelude::*;
use std::collections::HashSet;
use std::str::FromStr;

use crate::{bot::delta, db, Db, DeltaBotStatus, NostrBotStateTransitions, NostrBotStatus};
use rocket::{serde::json::Json, State};
use rocket_db_pools::Connection;

use crate::model::bot::delta::*;
use crate::model::bot::nostr::*;

use crate::model::api::{ApiError, ApiErrorLogged, ValidationError};
use crate::params::StartupParamsOptional;
use crate::util::oak::{CONFIG_KEY_NOSTR_BOT_OWNER_PUB_KEY, CONFIG_KEY_NOSTR_WS_ENDPOINT};

use crate::bot::ons::nip47::{Nip47InnerConfig, SecretConfig};
use crate::model::api::ApiError::GenericError;

use utoipa::OpenApi;





#[derive(OpenApi)]
#[openapi(
    paths(
        setup_email,
        get_pairing_code,
        enable_disable_ons,
>
>
>




<
<
<
<


|
<
<
<
<
<
<



>
|
>
>
>
>







1
2
3
4
5
6
7




8
9
10






11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
use std::collections::HashSet;
use std::str::FromStr;

use ::hex::ToHex;
use deltachat::context::Context;
use deltachat::securejoin;
use nostr::prelude::*;




use rocket::{serde::json::Json, State};
use rocket_db_pools::Connection;
use utoipa::OpenApi;







use crate::bot::ons::nip47::{Nip47InnerConfig, SecretConfig};
use crate::model::api::ApiError::GenericError;
use crate::model::api::{ApiError, ApiErrorLogged, ValidationError};
use crate::model::bot::delta::*;
use crate::model::bot::nostr::*;
use crate::params::StartupParamsOptional;
use crate::util::oak::{CONFIG_KEY_NOSTR_BOT_OWNER_PUB_KEY, CONFIG_KEY_NOSTR_WS_ENDPOINT};
use crate::{bot::delta, db, Db, DeltaBotStatus, NostrBotStateTransitions, NostrBotStatus};

#[derive(OpenApi)]
#[openapi(
    paths(
        setup_email,
        get_pairing_code,
        enable_disable_ons,

Changes to src/api/onetime.rs.

1
2
3
4
5
6
7
8
9
10
11

12

13
14
15
16
17
18
19
20
use crate::model::api::{ApiError, ApiErrorLogged, ValidationError};
use crate::{db, Db};
use ln_sdk::client::lnd::LndClient;
use ln_sdk::lnurl::*;
use ln_sdk::lnurlp::*;
use ln_sdk::HttpConfig;
use rocket::http::Status;
use rocket::response::status::Custom;
use rocket::serde::json::Json;
use rocket::State;
use rocket_db_pools::Connection;



use utoipa::OpenApi;

#[derive(OpenApi)]
#[openapi(
    paths(
        get_lnurl_pay_request,
        get_validate_pay_lnurl_invoice,
        get_known_addresses,
<
|
|
|
|
|





>

>
|








1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

use ln_sdk::client_v2::lnd::{LndClient, LndClientOps};
use ln_sdk::client_v2::{CanFetchLnUrlInvoice, CanPayLnUrl};
use ln_sdk::http::HttpConfig;
use ln_sdk::lnurl::*;
use ln_sdk::lnurlp::*;
use rocket::http::Status;
use rocket::response::status::Custom;
use rocket::serde::json::Json;
use rocket::State;
use rocket_db_pools::Connection;
use utoipa::OpenApi;

use crate::model::api::{ApiError, ApiErrorLogged, ValidationError};
use crate::{db, Db};

#[derive(OpenApi)]
#[openapi(
    paths(
        get_lnurl_pay_request,
        get_validate_pay_lnurl_invoice,
        get_known_addresses,
72
73
74
75
76
77
78
79



80
81
82
83


84





85
86
87
88
89
90
91
    )
)]
#[post("/", data = "<onetime_pay_request>")]
pub(crate) async fn get_validate_pay_lnurl_invoice(
    onetime_pay_request: Json<OneTimePayRequest>,
    lnd_client: &State<LndClient>,
    http_config: &State<HttpConfig>,
) -> Result<Custom<Json<String>>, ApiErrorLogged> {



    if let Err(e) = onetime_pay_request.0.validate() {
        return Err(ApiErrorLogged::from(ValidationError::of(&e.to_string())));
    }



    lnurl_pay_get_validate_pay_invoice(lnd_client.inner(), &onetime_pay_request.0, http_config)





        .await
        .map(|payment_info| Ok(Custom(Status::Ok, Json(payment_info))))
        .map_err(|e| {
            ApiError::GenericError(format!("Failed to call API: {e}")).to_logged_with_debug(&e)
        })?
}








|
>
>
>




>
>
|
>
>
>
>
>







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
    )
)]
#[post("/", data = "<onetime_pay_request>")]
pub(crate) async fn get_validate_pay_lnurl_invoice(
    onetime_pay_request: Json<OneTimePayRequest>,
    lnd_client: &State<LndClient>,
    http_config: &State<HttpConfig>,
) -> Result<Custom<Json<String>>, ApiErrorLogged>
where
    LndClient: CanPayLnUrl,
{
    if let Err(e) = onetime_pay_request.0.validate() {
        return Err(ApiErrorLogged::from(ValidationError::of(&e.to_string())));
    }

    let invoice = lnd_client
        .inner()
        .lnurl_pay_get_validate_invoice(&onetime_pay_request.0, http_config)
        .await?;

    lnd_client
        .inner()
        .handle_lnd_command_send_payment_sync(&invoice)
        .await
        .map(|payment_info| Ok(Custom(Status::Ok, Json(payment_info))))
        .map_err(|e| {
            ApiError::GenericError(format!("Failed to call API: {e}")).to_logged_with_debug(&e)
        })?
}

Changes to src/api/payment_job_schedule.rs.



1
2
3
4
5
6

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24


use rocket::{
    delete, get, http::Status, post, put, response::status::Custom, serde::json::Json, State,
};
use rocket_db_pools::Connection;
use std::sync::Arc;
use tokio::sync::Mutex;


use crate::bcron::BCronType::{Fixed, RepeatForever, RepeatFrom, RepeatFromUntil, RepeatUntil};
use crate::bcron::{categorize, get_next_ten_ticks};
use crate::model::api::{ApiError, ApiErrorLogged, Validated};
use crate::model::bcron::*;
use crate::model::lnd::LndStatus;
use crate::model::payment_job::*;
use crate::{db, Db, ScheduledPaymentJob};

use utoipa::OpenApi;

#[derive(OpenApi)]
#[openapi(
    paths(
        describe,
        get_jobs,
        create_job,
        update_job,
>
>




<

>









<
<







1
2
3
4
5
6

7
8
9
10
11
12
13
14
15
16
17


18
19
20
21
22
23
24
use std::sync::Arc;

use rocket::{
    delete, get, http::Status, post, put, response::status::Custom, serde::json::Json, State,
};
use rocket_db_pools::Connection;

use tokio::sync::Mutex;
use utoipa::OpenApi;

use crate::bcron::BCronType::{Fixed, RepeatForever, RepeatFrom, RepeatFromUntil, RepeatUntil};
use crate::bcron::{categorize, get_next_ten_ticks};
use crate::model::api::{ApiError, ApiErrorLogged, Validated};
use crate::model::bcron::*;
use crate::model::lnd::LndStatus;
use crate::model::payment_job::*;
use crate::{db, Db, ScheduledPaymentJob};



#[derive(OpenApi)]
#[openapi(
    paths(
        describe,
        get_jobs,
        create_job,
        update_job,

Changes to src/api/powpub.rs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


16
17
18

19
20
21
22
23
24
25
26
use rocket::{get, serde::json::Json, State};
use std::sync::Arc;
use std::time::Duration;

use crate::model::api::{ApiErrorLogged, ValidationError};
use crate::model::powpub::*;

use ::powpub::client::PowPubClient;
use anyhow::anyhow;
use lightning_invoice::Bolt11Invoice;
use ln_sdk::client::lnd::LndConfig;
use ln_sdk::HttpConfig;
use nostr::prelude::*;
use powpub::client::{validate_ask_hex, validate_ask_npub, validate_ask_pow};
use powpub::reputation::ProviderRep;



use crate::bot::nostr::NostrContext;
use crate::model::api::ApiError::GenericError;

use utoipa::OpenApi;

#[derive(OpenApi)]
#[openapi(
    paths(
        get_mined_key_details, get_my_trades, post_ask, post_pay
    ),
    components(
<



<
<
<



|
|



>
>



>
|








1
2
3



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

use std::sync::Arc;
use std::time::Duration;




use ::powpub::client::PowPubClient;
use anyhow::anyhow;
use lightning_invoice::Bolt11Invoice;
use ln_sdk::client_v2::lnd::LndConfig;
use ln_sdk::http::HttpConfig;
use nostr::prelude::*;
use powpub::client::{validate_ask_hex, validate_ask_npub, validate_ask_pow};
use powpub::reputation::ProviderRep;
use rocket::{get, serde::json::Json, State};
use utoipa::OpenApi;

use crate::bot::nostr::NostrContext;
use crate::model::api::ApiError::GenericError;
use crate::model::api::{ApiErrorLogged, ValidationError};
use crate::model::powpub::*;

#[derive(OpenApi)]
#[openapi(
    paths(
        get_mined_key_details, get_my_trades, post_ask, post_pay
    ),
    components(

Changes to src/api/status.rs.

1
2
3
4
5

6
7
8

9

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use itertools::Itertools;
use nostr_sdk::RelayStatus;
use std::collections::HashMap;
use std::sync::Arc;


use crate::bot::nostr::NostrContext;
use rocket::{get, serde::json::Json, State};
use tokio::sync::Mutex;



use crate::model::api::ApiErrorLogged;
use crate::model::bot::delta::*;
use crate::model::bot::nostr::*;
use crate::model::lnd::LndStatus;
use crate::model::oak::*;

use utoipa::OpenApi;

#[derive(OpenApi)]
#[openapi(
    paths(
        get_status,
    ),
    components(
        schemas(
<
<



>
|


>

>






<
<









1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


17
18
19
20
21
22
23


use std::collections::HashMap;
use std::sync::Arc;

use itertools::Itertools;
use nostr_sdk::RelayStatus;
use rocket::{get, serde::json::Json, State};
use tokio::sync::Mutex;
use utoipa::OpenApi;

use crate::bot::nostr::NostrContext;
use crate::model::api::ApiErrorLogged;
use crate::model::bot::delta::*;
use crate::model::bot::nostr::*;
use crate::model::lnd::LndStatus;
use crate::model::oak::*;



#[derive(OpenApi)]
#[openapi(
    paths(
        get_status,
    ),
    components(
        schemas(

Changes to src/bcron.rs.

1
2
3
4

5
6
7
8
9
10
11
12
13
14
use std::cmp::max;

use anyhow::Result;
use serde::{Deserialize, Serialize};


use crate::model::api::ValidationError;
use BCronType::{Fixed, RepeatForever, RepeatFrom, RepeatFromUntil, RepeatUntil};

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum BCronType {
    Fixed(i64),                     // target block height
    RepeatForever(i64),             // interval
    RepeatFrom(i64, i64),           // // from, interval
    RepeatUntil(i64, i64),          // until, interval




>


<







1
2
3
4
5
6
7

8
9
10
11
12
13
14
use std::cmp::max;

use anyhow::Result;
use serde::{Deserialize, Serialize};
use BCronType::{Fixed, RepeatForever, RepeatFrom, RepeatFromUntil, RepeatUntil};

use crate::model::api::ValidationError;


#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum BCronType {
    Fixed(i64),                     // target block height
    RepeatForever(i64),             // interval
    RepeatFrom(i64, i64),           // // from, interval
    RepeatUntil(i64, i64),          // until, interval

Changes to src/bot/delta.rs.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use deltachat::context::Context;
use deltachat::key::{DcKey, SignedPublicKey};
use deltachat::message::{Message, MsgId, Viewtype};
use deltachat::peerstate::Peerstate;
use deltachat::stock_str::StockStrings;
use deltachat::{EventType, Events};
use futures_lite::future::FutureExt;
use ln_sdk::HttpConfig;
use log::{error, info, warn};
use qrcode_generator::QrCodeEcc;
use tokio::sync::{broadcast, mpsc};

use crate::bot::*;
use crate::model::bot::delta::*;
use crate::{DeltaBotStatus, StartupParamsOptional};







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use deltachat::context::Context;
use deltachat::key::{DcKey, SignedPublicKey};
use deltachat::message::{Message, MsgId, Viewtype};
use deltachat::peerstate::Peerstate;
use deltachat::stock_str::StockStrings;
use deltachat::{EventType, Events};
use futures_lite::future::FutureExt;
use ln_sdk::http::HttpConfig;
use log::{error, info, warn};
use qrcode_generator::QrCodeEcc;
use tokio::sync::{broadcast, mpsc};

use crate::bot::*;
use crate::model::bot::delta::*;
use crate::{DeltaBotStatus, StartupParamsOptional};

Changes to src/bot/mod.rs.

1
2
3
4
5
6
7
8
9
10
11
12
pub mod delta;
pub mod nostr;
pub(crate) mod ons;

use ln_sdk::client::lnd::{LndClient, LndConfig};

/// Generic trait for private communication between the bot and its owner
#[async_trait]
pub trait BotSender {
    /// Send a message to the bot owner, using this bot platform's comm medium
    async fn send(&mut self, msg: String);





|







1
2
3
4
5
6
7
8
9
10
11
12
pub mod delta;
pub mod nostr;
pub(crate) mod ons;

use ln_sdk::client_v2::lnd::{LndClient, LndConfig};

/// Generic trait for private communication between the bot and its owner
#[async_trait]
pub trait BotSender {
    /// Send a message to the bot owner, using this bot platform's comm medium
    async fn send(&mut self, msg: String);

Changes to src/bot/nostr.rs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use std::collections::{HashMap, HashSet};
use std::sync::{Arc, OnceLock};
use std::time::Duration;

use anyhow::{anyhow, Result};
use ln_sdk::client::lnd::{LndClient, LndConfig};
use ln_sdk::HttpConfig;
use nostr::{
    message::relay::RelayMessage,
    prelude::{decrypt, ToBech32},
    Event, EventBuilder, Filter, Keys, Profile, Url,
};
use nostr_sdk::{Client, RelayPoolNotification};






|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
use std::collections::{HashMap, HashSet};
use std::sync::{Arc, OnceLock};
use std::time::Duration;

use anyhow::{anyhow, Result};
use ln_sdk::client_v2::lnd::{LndClient, LndConfig};
use ln_sdk::http::HttpConfig;
use nostr::{
    message::relay::RelayMessage,
    prelude::{decrypt, ToBech32},
    Event, EventBuilder, Filter, Keys, Profile, Url,
};
use nostr_sdk::{Client, RelayPoolNotification};

Changes to src/bot/ons/mod.rs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
pub(crate) mod ons1;
// pub(crate) mod ons2;
pub(crate) mod nip47;
pub(crate) mod ons3;
pub(crate) mod ons4;

use crate::bot::nostr::NostrContext;
use crate::db;
use crate::model::bot::nostr::OnsMetadata;
use crate::params::StartupParamsOptional;
use anyhow::{anyhow, Result};
use ln_sdk::client::lnd::{LndClient, LndConfig};
use ln_sdk::HttpConfig;
use nostr::prelude::*;
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;

#[async_trait]
pub trait Ons {
    fn id(&self) -> String;











|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
pub(crate) mod ons1;
// pub(crate) mod ons2;
pub(crate) mod nip47;
pub(crate) mod ons3;
pub(crate) mod ons4;

use crate::bot::nostr::NostrContext;
use crate::db;
use crate::model::bot::nostr::OnsMetadata;
use crate::params::StartupParamsOptional;
use anyhow::{anyhow, Result};
use ln_sdk::client_v2::lnd::{LndClient, LndConfig};
use ln_sdk::http::HttpConfig;
use nostr::prelude::*;
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;

#[async_trait]
pub trait Ons {
    fn id(&self) -> String;

Changes to src/bot/ons/nip47.rs.

1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
18
19
20
21
22
23








24
25
26
27
28
29
30
use crate::bot::nostr::NostrContext;
use crate::bot::ons::Ons;
use crate::model::api::ApiError::GenericError;
use crate::model::api::ApiErrorLogged;
use crate::model::bot::nostr::OnsMetadata;
use crate::params::StartupParamsOptional;
use crate::Db;
use anyhow::{anyhow, Result};
use hex::ToHex;
use lightning_invoice::Bolt11Invoice;

use ln_sdk::client::lnd::{LndClient, LndClientOps, LndConfig};
use ln_sdk::HttpConfig;
use nostr::nips::nip47::*;
use nostr::prelude::{decrypt, encrypt, FromSkStr};
use nostr::{Event, EventBuilder, Filter, Keys, Kind, Tag, Timestamp};
use rocket_db_pools::Connection;
use serde::{Deserialize, Serialize};
use serde_json::{from_str, to_string};
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;
use std::collections::HashSet;
use std::string::ToString;
use utoipa::ToSchema;









pub const ID: &str = "nip47";

#[derive(Default, Serialize, Deserialize, Debug, Clone)]
pub struct Nip47Config {
    pub enabled: bool,

|
|
|
<
<
<
<



>
|
|








<
<

>
>
>
>
>
>
>
>







1
2
3




4
5
6
7
8
9
10
11
12
13
14
15
16
17


18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
use std::collections::HashSet;
use std::string::ToString;





use anyhow::{anyhow, Result};
use hex::ToHex;
use lightning_invoice::Bolt11Invoice;
use ln_sdk::client_v2::lnd::{LndClient, LndConfig};
use ln_sdk::client_v2::CanPayInvoices;
use ln_sdk::http::HttpConfig;
use nostr::nips::nip47::*;
use nostr::prelude::{decrypt, encrypt, FromSkStr};
use nostr::{Event, EventBuilder, Filter, Keys, Kind, Tag, Timestamp};
use rocket_db_pools::Connection;
use serde::{Deserialize, Serialize};
use serde_json::{from_str, to_string};
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;


use utoipa::ToSchema;

use crate::bot::nostr::NostrContext;
use crate::bot::ons::Ons;
use crate::model::api::ApiError::GenericError;
use crate::model::api::ApiErrorLogged;
use crate::model::bot::nostr::OnsMetadata;
use crate::params::StartupParamsOptional;
use crate::Db;

pub const ID: &str = "nip47";

#[derive(Default, Serialize, Deserialize, Debug, Clone)]
pub struct Nip47Config {
    pub enabled: bool,

170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

                    let req = Request::from_json(&decrypted)?;
                    match (req.method, req.params) {
                        (
                            Method::PayInvoice,
                            RequestParams::PayInvoice(PayInvoiceRequestParams { invoice }),
                        ) => {
                            let resp = match lnd_client.pay_invoice_simple(&invoice).await {
                                Ok(preimage_base64) => {
                                    let preimage_decoded = base64::decode(preimage_base64)?;
                                    let preimage = hex::encode(preimage_decoded);

                                    let invoice_parsed = invoice.parse::<Bolt11Invoice>()?;

                                    info!("Payment was successful, amt={:?} msat, preimage: {preimage}",







|







173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

                    let req = Request::from_json(&decrypted)?;
                    match (req.method, req.params) {
                        (
                            Method::PayInvoice,
                            RequestParams::PayInvoice(PayInvoiceRequestParams { invoice }),
                        ) => {
                            let resp = match lnd_client.pay(&invoice).await {
                                Ok(preimage_base64) => {
                                    let preimage_decoded = base64::decode(preimage_base64)?;
                                    let preimage = hex::encode(preimage_decoded);

                                    let invoice_parsed = invoice.parse::<Bolt11Invoice>()?;

                                    info!("Payment was successful, amt={:?} msat, preimage: {preimage}",

Changes to src/bot/ons/ons1.rs.












1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22











use crate::bot::nostr::NostrContext;
use crate::bot::ons::Ons;
use crate::bot::BotSender;
use crate::model::bot::nostr::OnsMetadata;
use crate::params::StartupParamsOptional;
use crate::{db, lnd, util};
use ::hex::ToHex;
use anyhow::Result;
use ln_sdk::client::lnd::{LndClient, LndClientOps, LndConfig};
use ln_sdk::lnurl::handle_lnd_command_send_payment_sync;
use ln_sdk::HttpConfig;
use nostr::prelude::*;
use serde::{Deserialize, Serialize};
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;

/// Sent each time the user sets up or updates the pubkey
const GREETING: &str =
    "Hello, this is your Nostr Bot. Type H or Help to find out what commands I can respond to.";

/// DB Config field tracking whether owner pubkey was greeted
const KEY_GREETING_SENT: &str = "nostr_bot_greeting_last_sent_to_pubkey";
>
>
>
>
>
>
>
>
>
>
>






<
<
<
<
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17









18
19
20
21
22
23
24
use ::hex::ToHex;
use anyhow::Result;
use ln_sdk::client_v2::lnd::LndClientOps;
use ln_sdk::client_v2::lnd::{LndClient, LndConfig};
use ln_sdk::client_v2::CanCreateInvoices;
use ln_sdk::http::HttpConfig;
use nostr::prelude::*;
use serde::{Deserialize, Serialize};
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;

use crate::bot::nostr::NostrContext;
use crate::bot::ons::Ons;
use crate::bot::BotSender;
use crate::model::bot::nostr::OnsMetadata;
use crate::params::StartupParamsOptional;
use crate::{db, lnd, util};










/// Sent each time the user sets up or updates the pubkey
const GREETING: &str =
    "Hello, this is your Nostr Bot. Type H or Help to find out what commands I can respond to.";

/// DB Config field tracking whether owner pubkey was greeted
const KEY_GREETING_SENT: &str = "nostr_bot_greeting_last_sent_to_pubkey";
157
158
159
160
161
162
163

164


165
166
167
168
169
170
171
            };

            sender.send(resp).await
        }
        "p" | "pay" => {
            let resp = match msg_split.next() {
                Some(invoice_from_input) => {

                    match handle_lnd_command_send_payment_sync(client, invoice_from_input).await {


                        Ok(pay_msg) => pay_msg,
                        Err(error) => format!("Error: {error}"),
                    }
                }
                None => "Error: Expected one argument but found none".to_string(),
            };








>
|
>
>







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
            };

            sender.send(resp).await
        }
        "p" | "pay" => {
            let resp = match msg_split.next() {
                Some(invoice_from_input) => {
                    match client
                        .handle_lnd_command_send_payment_sync(invoice_from_input)
                        .await
                    {
                        Ok(pay_msg) => pay_msg,
                        Err(error) => format!("Error: {error}"),
                    }
                }
                None => "Error: Expected one argument but found none".to_string(),
            };

Changes to src/bot/ons/ons3.rs.










1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19









use crate::bot::nostr::NostrContext;
use crate::bot::ons::Ons;
use crate::lnd::handle_command_pay_lightning_address_or_lnurlp;
use crate::model::bot::nostr::OnsMetadata;
use crate::params::StartupParamsOptional;
use ::hex::ToHex;
use anyhow::Result;
use ln_sdk::client::lnd::{LndClient, LndConfig};
use ln_sdk::HttpConfig;
use nostr::prelude::*;
use serde::{Deserialize, Serialize};
use std::time::Duration;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Ons3Config {
    pub enabled: bool,
    pub tip_amount_sat: u64,
}

>
>
>
>
>
>
>
>
>





<
<
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14







15
16
17
18
19
20
21
use std::time::Duration;

use ::hex::ToHex;
use anyhow::Result;
use ln_sdk::client_v2::lnd::{LndClient, LndConfig};
use ln_sdk::http::HttpConfig;
use nostr::prelude::*;
use serde::{Deserialize, Serialize};

use crate::bot::nostr::NostrContext;
use crate::bot::ons::Ons;
use crate::lnd::handle_command_pay_lightning_address_or_lnurlp;
use crate::model::bot::nostr::OnsMetadata;
use crate::params::StartupParamsOptional;








#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Ons3Config {
    pub enabled: bool,
    pub tip_amount_sat: u64,
}

Changes to src/bot/ons/ons4.rs.













1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21












use crate::bot::nostr::NostrContext;
use crate::bot::ons::Ons;
use crate::model::bot::nostr::OnsMetadata;
use crate::params::StartupParamsOptional;
use ::hex::ToHex;
use anyhow::{anyhow, Result};
use ln_sdk::client::lnd::model::InvoiceState;
use ln_sdk::client::lnd::model::LookupInvoiceResult;
use ln_sdk::client::lnd::{LndClient, LndClientOps, LndConfig};
use ln_sdk::HttpConfig;
use nostr::nips::nip04;
use nostr::prelude::*;
use serde::{Deserialize, Serialize};
use std::time::SystemTime;

#[derive(Default, Serialize, Deserialize, Debug, Clone)]
pub struct Ons4Config {
    pub enabled: bool,
    /// If empty, it falls back to the paired account (pubkey and relays)
    pub deck_nprofile: Option<String>,
}
>
>
>
>
>
>
>
>
>
>
>
>




<
<
<
<
<
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16










17
18
19
20
21
22
23
use std::time::SystemTime;

use ::hex::ToHex;
use anyhow::{anyhow, Result};
use ln_sdk::client_v2::lnd::model::InvoiceState;
use ln_sdk::client_v2::lnd::model::LookupInvoiceResult;
use ln_sdk::client_v2::lnd::{LndClient, LndClientOps, LndConfig};
use ln_sdk::http::HttpConfig;
use nostr::nips::nip04;
use nostr::prelude::*;
use serde::{Deserialize, Serialize};

use crate::bot::nostr::NostrContext;
use crate::bot::ons::Ons;
use crate::model::bot::nostr::OnsMetadata;
use crate::params::StartupParamsOptional;











#[derive(Default, Serialize, Deserialize, Debug, Clone)]
pub struct Ons4Config {
    pub enabled: bool,
    /// If empty, it falls back to the paired account (pubkey and relays)
    pub deck_nprofile: Option<String>,
}

Changes to src/lnd.rs.



1
2
3


4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56


use anyhow::{anyhow, Result};
use lightning_invoice::Bolt11Invoice;
use ln_sdk::client::lnd::{LndClient, LndClientOps, LndConfig};


use ln_sdk::lnurl::{lnurl_pay_get_validate_pay_invoice, lnurl_pay_lookup_request};
use ln_sdk::lnurlp::OneTimePayRequest;
use ln_sdk::HttpConfig;
use log::error;
use std::str::FromStr;

use crate::{LndStatus, CARGO_PKG_VERSION};

pub async fn init_lnd(
    params_lnd: &LndConfig,
    params_http: &HttpConfig,
    lnd_status: &mut LndStatus,
) -> LndClient {
    let lnd_client = LndClient::build_client(params_lnd, params_http)
        .map_err(|e| error!("Could not create LND REST client: {}", e))
        .unwrap();

    lnd_client
        .get_info()
        .await
        .map(|info| lnd_status.blockheight = info.block_height)
        .map_err(|e| error!("Failed to lookup LND blockheight: {}", e))
        .unwrap();

    lnd_client
}

pub async fn handle_command_lnd_version(lnd_client: &LndClient) -> Result<String> {
    lnd_client
        .get_info()
        .await
        .map_err(|e| anyhow!("Failed to call LND get_info: {}", e.to_string()))
        .map(|info| {
            Ok(format!(
                "Oak version: {}\nLND version: {}",
                CARGO_PKG_VERSION.unwrap(),
                info.version.split_whitespace().next().unwrap()
            ))
        })?
}

pub async fn handle_command_lnd_balance(lnd_client: &LndClient) -> Result<String> {
    lnd_client
        .get_channels_balance()
        .await
        .map_err(|e| anyhow!("Failed to call LND channel_balance: {}", e.to_string()))
        .map(|channel_balance_res| {
            Ok(format!(
                "Max send: {} sats\nMax receive: {} sats",
                channel_balance_res.local_balance.sat, channel_balance_res.remote_balance.sat
            ))
        })?
}
>
>


|
>
>
|

<

<









|






|









|













|







1
2
3
4
5
6
7
8
9

10

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
use std::str::FromStr;

use anyhow::{anyhow, Result};
use lightning_invoice::Bolt11Invoice;
use ln_sdk::client_v2::lnd::{LndClient, LndClientOps, LndConfig};
use ln_sdk::client_v2::CanFetchLnUrlInvoice;
use ln_sdk::http::HttpConfig;
use ln_sdk::lnurl::lnurl_pay_lookup_request;
use ln_sdk::lnurlp::OneTimePayRequest;

use log::error;


use crate::{LndStatus, CARGO_PKG_VERSION};

pub async fn init_lnd(
    params_lnd: &LndConfig,
    params_http: &HttpConfig,
    lnd_status: &mut LndStatus,
) -> LndClient {
    let lnd_client = LndClient::build_client(params_lnd, params_http)
        .map_err(|e| error!("Could not create LND REST client: {e}"))
        .unwrap();

    lnd_client
        .get_info()
        .await
        .map(|info| lnd_status.blockheight = info.block_height)
        .map_err(|e| error!("Failed to lookup LND blockheight: {e}"))
        .unwrap();

    lnd_client
}

pub async fn handle_command_lnd_version(lnd_client: &LndClient) -> Result<String> {
    lnd_client
        .get_info()
        .await
        .map_err(|e| anyhow!("Failed to call LND get_info: {e}"))
        .map(|info| {
            Ok(format!(
                "Oak version: {}\nLND version: {}",
                CARGO_PKG_VERSION.unwrap(),
                info.version.split_whitespace().next().unwrap()
            ))
        })?
}

pub async fn handle_command_lnd_balance(lnd_client: &LndClient) -> Result<String> {
    lnd_client
        .get_channels_balance()
        .await
        .map_err(|e| anyhow!("Failed to call LND channel_balance: {e}"))
        .map(|channel_balance_res| {
            Ok(format!(
                "Max send: {} sats\nMax receive: {} sats",
                channel_balance_res.local_balance.sat, channel_balance_res.remote_balance.sat
            ))
        })?
}
80
81
82
83
84
85
86

87
88
89
90
91
92
93
94
95




96
97
            .and_then(
                |(max_len, user_comment)| match user_comment.chars().count() <= max_len {
                    true => Some(user_comment),
                    false => None,
                },
            );


    lnurl_pay_get_validate_pay_invoice(
        lnd_client,
        &OneTimePayRequest {
            request: lnurl_resp,
            amount_sats: num_satoshis_as_per_user_request,
            comment,
        },
        http_config,
    )




    .await
}







>
|
<
|
|
|
|
|
|
|
>
>
>
>
|

82
83
84
85
86
87
88
89
90

91
92
93
94
95
96
97
98
99
100
101
102
103
            .and_then(
                |(max_len, user_comment)| match user_comment.chars().count() <= max_len {
                    true => Some(user_comment),
                    false => None,
                },
            );

    let invoice = lnd_client
        .lnurl_pay_get_validate_invoice(

            &OneTimePayRequest {
                request: lnurl_resp,
                amount_sats: num_satoshis_as_per_user_request,
                comment,
            },
            http_config,
        )
        .await?;

    lnd_client
        .handle_lnd_command_send_payment_sync(&invoice)
        .await
}

Changes to src/main.rs.

1
2
3
4
5
6
7
8
9
10

11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#[macro_use]
extern crate rocket;

use std::env;
use std::env::current_dir;
use std::path::PathBuf;
use std::sync::Arc;

// use ::nostr::hashes::sha256::Hash as Sha256Hash;
use ::sqlx::SqlitePool;

use deltachat::context::Context;
use ln_sdk::client::lnd::{LndClient, LndConfig};
use ln_sdk::HttpConfig;

use log::info;
use rocket::fairing::AdHoc;
use rocket::figment::providers::Serialized;
use rocket::fs::{relative, FileServer};
use rocket::http::hyper::header::CACHE_CONTROL;
use rocket::http::{Header, Method, Status};
use rocket::response::status;
use rocket::tokio::sync::{broadcast, mpsc};
use rocket::{routes, Build, Request, Rocket, State};
use rocket_db_pools::Database;
use rocket_dyn_templates::{context, Template};
use tokio::sync::Mutex;
use utoipa::OpenApi;
use utoipa_swagger_ui::SwaggerUi;

use bcron::get_next_tick;
use lnd::init_lnd;

use crate::api::ApiDoc;
use crate::bot::delta;
use crate::bot::nostr;
use crate::bot::nostr::NostrContext;
use crate::model::bot::delta::DeltaBotStatus;
use crate::model::bot::nostr::{NostrBotStateTransitions, NostrBotStatus};
use crate::model::lnd::LndStatus;










>

|
|
>















<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30



31
32
33
34
35
36
37
#[macro_use]
extern crate rocket;

use std::env;
use std::env::current_dir;
use std::path::PathBuf;
use std::sync::Arc;

// use ::nostr::hashes::sha256::Hash as Sha256Hash;
use ::sqlx::SqlitePool;
use bcron::get_next_tick;
use deltachat::context::Context;
use ln_sdk::client_v2::lnd::{LndClient, LndConfig};
use ln_sdk::http::HttpConfig;
use lnd::init_lnd;
use log::info;
use rocket::fairing::AdHoc;
use rocket::figment::providers::Serialized;
use rocket::fs::{relative, FileServer};
use rocket::http::hyper::header::CACHE_CONTROL;
use rocket::http::{Header, Method, Status};
use rocket::response::status;
use rocket::tokio::sync::{broadcast, mpsc};
use rocket::{routes, Build, Request, Rocket, State};
use rocket_db_pools::Database;
use rocket_dyn_templates::{context, Template};
use tokio::sync::Mutex;
use utoipa::OpenApi;
use utoipa_swagger_ui::SwaggerUi;




use crate::api::ApiDoc;
use crate::bot::delta;
use crate::bot::nostr;
use crate::bot::nostr::NostrContext;
use crate::model::bot::delta::DeltaBotStatus;
use crate::model::bot::nostr::{NostrBotStateTransitions, NostrBotStatus};
use crate::model::lnd::LndStatus;

Changes to src/model/api.rs.

1
2
3
4



5
6
7
8
9
10
11
use anyhow::Error;
use serde::Serialize;
use std::fmt::Debug;
use std::sync::{MutexGuard, PoisonError};



use utoipa::ToSchema;

/// Simple wrapper around `ApiError`, which logs the error when wrapping
#[derive(Responder)]
pub struct ApiErrorLogged {
    e: ApiError,
}
<
<


>
>
>









1
2
3
4
5
6
7
8
9
10
11
12


use std::fmt::Debug;
use std::sync::{MutexGuard, PoisonError};

use anyhow::Error;
use serde::Serialize;
use utoipa::ToSchema;

/// Simple wrapper around `ApiError`, which logs the error when wrapping
#[derive(Responder)]
pub struct ApiErrorLogged {
    e: ApiError,
}

Changes to src/model/bot/delta.rs.



1
2
3
4
5
6
7
8
9
10


use anyhow::anyhow;
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
use utoipa::ToSchema;

use crate::model::bot::delta::DeltaBotState::*;

/// Current status of the deltachat bot submodule
#[derive(Clone, Serialize, ToSchema)]
pub struct DeltaBotStatus {
>
>


<







1
2
3
4

5
6
7
8
9
10
11
use std::sync::{Arc, Mutex};

use anyhow::anyhow;
use serde::{Deserialize, Serialize};

use utoipa::ToSchema;

use crate::model::bot::delta::DeltaBotState::*;

/// Current status of the deltachat bot submodule
#[derive(Clone, Serialize, ToSchema)]
pub struct DeltaBotStatus {
117
118
119
120
121
122
123


124
125
126
127
128
129
130
131
132
133
    pub email_password: String,
    pub imap_server: Option<String>,
    pub smtp_server: Option<String>,
}

#[cfg(test)]
pub(crate) mod tests {


    use anyhow::anyhow;
    use pretty_assertions::assert_eq;
    use std::sync::{Arc, Mutex};

    use crate::model::bot::delta::DeltaBotState::*;
    use crate::model::bot::delta::{DeltaBotState, DeltaBotStateTransitions, VerifiedEmailInfo};
    use crate::DeltaBotStatus;

    #[test]
    fn check_email_bot_state_transitions() {







>
>


<







118
119
120
121
122
123
124
125
126
127
128

129
130
131
132
133
134
135
    pub email_password: String,
    pub imap_server: Option<String>,
    pub smtp_server: Option<String>,
}

#[cfg(test)]
pub(crate) mod tests {
    use std::sync::{Arc, Mutex};

    use anyhow::anyhow;
    use pretty_assertions::assert_eq;


    use crate::model::bot::delta::DeltaBotState::*;
    use crate::model::bot::delta::{DeltaBotState, DeltaBotStateTransitions, VerifiedEmailInfo};
    use crate::DeltaBotStatus;

    #[test]
    fn check_email_bot_state_transitions() {

Changes to src/model/bot/nostr.rs.

1
2
3
4
5
6
7
8
9
10
11




12
13
14
15
16
17
18
use crate::model::api::ApiError::GenericError;
use crate::model::api::ApiErrorLogged;
use crate::model::bot::nostr::NostrBotState::*;
use anyhow::{anyhow, Result};
use hex::ToHex;
use nostr::secp256k1::XOnlyPublicKey;
use nostr::ToBech32;
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
use utoipa::ToSchema;





/// Current status of the deltachat bot submodule
#[derive(Clone, Serialize, ToSchema)]
pub struct NostrBotStatus {
    #[schema(value_type = NostrBotState)]
    pub(crate) state: Arc<Mutex<NostrBotState>>,

    #[schema(value_type = String)]
<
|
|





<


>
>
>
>








1
2
3
4
5
6
7

8
9
10
11
12
13
14
15
16
17
18
19
20

use std::sync::{Arc, Mutex};

use anyhow::{anyhow, Result};
use hex::ToHex;
use nostr::secp256k1::XOnlyPublicKey;
use nostr::ToBech32;
use serde::{Deserialize, Serialize};

use utoipa::ToSchema;

use crate::model::api::ApiError::GenericError;
use crate::model::api::ApiErrorLogged;
use crate::model::bot::nostr::NostrBotState::*;

/// Current status of the deltachat bot submodule
#[derive(Clone, Serialize, ToSchema)]
pub struct NostrBotStatus {
    #[schema(value_type = NostrBotState)]
    pub(crate) state: Arc<Mutex<NostrBotState>>,

    #[schema(value_type = String)]
190
191
192
193
194
195
196
197
198
199
200
201


202
203
204
205
206
207
208

        Ok(())
    }
}

#[cfg(test)]
pub(crate) mod tests {
    use crate::model::bot::nostr::NostrBotState::*;
    use crate::model::bot::nostr::{NostrBotState, NostrBotStateTransitions, NostrBotStatus};
    use anyhow::{anyhow, Result};
    use pretty_assertions::assert_eq;
    use std::sync::{Arc, Mutex};



    #[test]
    fn check_nostr_bot_state_transitions() {
        check_transition(false, PendingBotKeySetup, PendingBotKeySetup);
        // If user pubkey missing
        check_transition(true, PendingBotKeySetup, PendingOwnerPairing);
        check_transition(false, PendingBotKeySetup, PendingRestart);







|
|


|
>
>







192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212

        Ok(())
    }
}

#[cfg(test)]
pub(crate) mod tests {
    use std::sync::{Arc, Mutex};

    use anyhow::{anyhow, Result};
    use pretty_assertions::assert_eq;

    use crate::model::bot::nostr::NostrBotState::*;
    use crate::model::bot::nostr::{NostrBotState, NostrBotStateTransitions, NostrBotStatus};

    #[test]
    fn check_nostr_bot_state_transitions() {
        check_transition(false, PendingBotKeySetup, PendingBotKeySetup);
        // If user pubkey missing
        check_transition(true, PendingBotKeySetup, PendingOwnerPairing);
        check_transition(false, PendingBotKeySetup, PendingRestart);

Changes to src/model/oak.rs.



1
2
3
4
5
6
7
8
9
10


use nostr_sdk::RelayStatus;
use serde::{Serialize, Serializer};
use std::collections::HashMap;
use utoipa::ToSchema;

use crate::{DeltaBotStatus, LndStatus, NostrBotStatus};

/// Current status of the node and its submodules
#[derive(Serialize, ToSchema)]
pub struct OakNodeStatus {
>
>


<







1
2
3
4

5
6
7
8
9
10
11
use std::collections::HashMap;

use nostr_sdk::RelayStatus;
use serde::{Serialize, Serializer};

use utoipa::ToSchema;

use crate::{DeltaBotStatus, LndStatus, NostrBotStatus};

/// Current status of the node and its submodules
#[derive(Serialize, ToSchema)]
pub struct OakNodeStatus {

Changes to src/params.rs.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20



use ::hex::ToHex;
use anyhow::{anyhow, Result};
use nostr::nips;
use nostr::prelude::*;
use std::str::FromStr;
use std::time::Duration;

use crate::bot::ons::ons1::Ons1Config;
// use crate::bot::ons::ons2::Ons2Config;
use crate::bot::ons::nip47::Nip47Config;
use crate::bot::ons::ons3::Ons3Config;
use crate::bot::ons::ons4::Ons4Config;
use serde::{Deserialize, Serialize};

/// Can be specified as env variables with an OAK_ prefix
/// For example: OAK_LND_POLLING_INTERVAL_SECONDS=10 cargo run
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct StartupParamsOptional {
    /// The directory where all DB files will be stored
    /// If not specified, the DB files will be saved in the same folder from which the node is started
>
>
>




|
<






<







1
2
3
4
5
6
7
8

9
10
11
12
13
14

15
16
17
18
19
20
21
use std::str::FromStr;
use std::time::Duration;

use ::hex::ToHex;
use anyhow::{anyhow, Result};
use nostr::nips;
use nostr::prelude::*;
use serde::{Deserialize, Serialize};


use crate::bot::ons::ons1::Ons1Config;
// use crate::bot::ons::ons2::Ons2Config;
use crate::bot::ons::nip47::Nip47Config;
use crate::bot::ons::ons3::Ons3Config;
use crate::bot::ons::ons4::Ons4Config;


/// Can be specified as env variables with an OAK_ prefix
/// For example: OAK_LND_POLLING_INTERVAL_SECONDS=10 cargo run
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct StartupParamsOptional {
    /// The directory where all DB files will be stored
    /// If not specified, the DB files will be saved in the same folder from which the node is started

Changes to src/scheduler.rs.

1
2
3
4
5


6
7
8
9
10
11
12
use ln_sdk::client::lnd::{LndClient, LndClientOps};
use ln_sdk::HttpConfig;
use std::sync::Arc;
use std::time::Duration;



use log::{error, info};
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;
use tokio::sync::{broadcast, mpsc, Mutex};

use crate::{db, get_next_tick, lnd, ExecutedPaymentJob, LndStatus};

<
<



>
>









1
2
3
4
5
6
7
8
9
10
11
12


use std::sync::Arc;
use std::time::Duration;

use ln_sdk::client_v2::lnd::{LndClient, LndClientOps};
use ln_sdk::http::HttpConfig;
use log::{error, info};
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;
use tokio::sync::{broadcast, mpsc, Mutex};

use crate::{db, get_next_tick, lnd, ExecutedPaymentJob, LndStatus};

29
30
31
32
33
34
35





36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
                lnd_client,
                &bcron_job.destination,
                bcron_job.amount_sats as u64,
                bcron_job.memo,
                http_config,
            )
            .await;






            let execution_job = ExecutedPaymentJob {
                id: 1, // Will be overwritten by DB
                triggered_at_block_height: current_block,
                destination: bcron_job.destination.clone(),
                amount_sats: bcron_job.amount_sats,
                success: lnd_result.is_ok(),
                error_message: match lnd_result {
                    Ok(_) => None,
                    Err(e) => {
                        error!("Payment job encountered error: {}", e);
                        Some(e.to_string())
                    }
                },
            };

            match db::executions::create_job(execution_job, &mut c1).await {
                Ok(_) => info!(
                    "Successfully stored job execution for destination {} / bcron {}",
                    bcron_job.destination, bcron_job.bcron
                ),
                Err(e) => error!(
                    "Failed to store job execution for destination {} / bcron {} because {}",
                    bcron_job.destination,
                    bcron_job.bcron,







>
>
>
>
>







|
<
<
<
<
<
<



|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48






49
50
51
52
53
54
55
56
57
58
59
                lnd_client,
                &bcron_job.destination,
                bcron_job.amount_sats as u64,
                bcron_job.memo,
                http_config,
            )
            .await;

            match &lnd_result {
                Ok(res) => info!("{res}"),
                Err(e) => error!("Payment job encountered error: {e}"),
            };

            let execution_job = ExecutedPaymentJob {
                id: 1, // Will be overwritten by DB
                triggered_at_block_height: current_block,
                destination: bcron_job.destination.clone(),
                amount_sats: bcron_job.amount_sats,
                success: lnd_result.is_ok(),
                error_message: lnd_result.err().map(|e| e.to_string()),






            };

            match db::executions::create_job(execution_job, &mut c1).await {
                Ok(_) => debug!(
                    "Successfully stored job execution for destination {} / bcron {}",
                    bcron_job.destination, bcron_job.bcron
                ),
                Err(e) => error!(
                    "Failed to store job execution for destination {} / bcron {} because {}",
                    bcron_job.destination,
                    bcron_job.bcron,

Changes to src/util/oak.rs.

1
2
3
4


5
6
7
8
9
10
11
use nostr::prelude::rand::rngs::OsRng;
use nostr::prelude::*;
use std::env;



use rocket::figment::providers::Env;
use rocket::figment::Figment;
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;

use crate::StartupParamsOptional;

<
<


>
>









1
2
3
4
5
6
7
8
9
10
11


use std::env;

use nostr::prelude::rand::rngs::OsRng;
use nostr::prelude::*;
use rocket::figment::providers::Env;
use rocket::figment::Figment;
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;

use crate::StartupParamsOptional;