damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

WalletConnect+.swift (4241B)


      1 //
      2 //  WalletConnect+.swift
      3 //  damus
      4 //
      5 //  Created by Daniel D’Aquino on 2023-11-27.
      6 //
      7 
      8 import Foundation
      9 
     10 func make_wallet_pay_invoice_request(invoice: String) -> WalletRequest<PayInvoiceRequest> {
     11     let data = PayInvoiceRequest(invoice: invoice)
     12     return WalletRequest(method: "pay_invoice", params: data)
     13 }
     14 
     15 func make_wallet_balance_request() -> WalletRequest<EmptyRequest> {
     16     return WalletRequest(method: "get_balance", params: nil)
     17 }
     18 
     19 struct EmptyRequest: Codable {
     20 }
     21 
     22 struct PayInvoiceRequest: Codable {
     23     let invoice: String
     24 }
     25 
     26 func make_wallet_connect_request<T>(req: WalletRequest<T>, to_pk: Pubkey, keypair: FullKeypair) -> NostrEvent? {
     27     let tags = [to_pk.tag]
     28     let created_at = UInt32(Date().timeIntervalSince1970)
     29     guard let content = encode_json(req) else {
     30         return nil
     31     }
     32     return create_encrypted_event(content, to_pk: to_pk, tags: tags, keypair: keypair, created_at: created_at, kind: 23194)
     33 }
     34 
     35 func subscribe_to_nwc(url: WalletConnectURL, pool: RelayPool) {
     36     var filter = NostrFilter(kinds: [.nwc_response])
     37     filter.authors = [url.pubkey]
     38     filter.limit = 0
     39     let sub = NostrSubscribe(filters: [filter], sub_id: "nwc")
     40 
     41     pool.send(.subscribe(sub), to: [url.relay], skip_ephemeral: false)
     42 }
     43 
     44 @discardableResult
     45 func nwc_pay(url: WalletConnectURL, pool: RelayPool, post: PostBox, invoice: String, delay: TimeInterval? = 5.0, on_flush: OnFlush? = nil) -> NostrEvent? {
     46     let req = make_wallet_pay_invoice_request(invoice: invoice)
     47     guard let ev = make_wallet_connect_request(req: req, to_pk: url.pubkey, keypair: url.keypair) else {
     48         return nil
     49     }
     50 
     51     try? pool.add_relay(.nwc(url: url.relay))
     52     subscribe_to_nwc(url: url, pool: pool)
     53     post.send(ev, to: [url.relay], skip_ephemeral: false, delay: delay, on_flush: on_flush)
     54     return ev
     55 }
     56 
     57 
     58 func nwc_success(state: DamusState, resp: FullWalletResponse) {
     59     // find the pending zap and mark it as pending-confirmed
     60     for kv in state.zaps.our_zaps {
     61         let zaps = kv.value
     62         
     63         for zap in zaps {
     64             guard case .pending(let pzap) = zap,
     65                   case .nwc(let nwc_state) = pzap.state,
     66                   case .postbox_pending(let nwc_req) = nwc_state.state,
     67                   nwc_req.id == resp.req_id
     68             else {
     69                 continue
     70             }
     71             
     72             if nwc_state.update_state(state: .confirmed) {
     73                 // notify the zaps model of an update so it can mark them as paid
     74                 state.events.get_cache_data(NoteId(pzap.target.id)).zaps_model.objectWillChange.send()
     75                 print("NWC success confirmed")
     76             }
     77             
     78             return
     79         }
     80     }
     81 }
     82 
     83 func send_donation_zap(pool: RelayPool, postbox: PostBox, nwc: WalletConnectURL, percent: Int, base_msats: Int64) async {
     84     let percent_f = Double(percent) / 100.0
     85     let donations_msats = Int64(percent_f * Double(base_msats))
     86     
     87     let payreq = LNUrlPayRequest(allowsNostr: true, commentAllowed: nil, nostrPubkey: "", callback: "https://sendsats.lol/@damus")
     88     guard let invoice = await fetch_zap_invoice(payreq, zapreq: nil, msats: donations_msats, zap_type: .non_zap, comment: nil) else {
     89         // we failed... oh well. no donation for us.
     90         print("damus-donation failed to fetch invoice")
     91         return
     92     }
     93     
     94     print("damus-donation donating...")
     95     nwc_pay(url: nwc, pool: pool, post: postbox, invoice: invoice, delay: nil)
     96 }
     97 
     98 func nwc_error(zapcache: Zaps, evcache: EventCache, resp: FullWalletResponse) {
     99     // find a pending zap with the nwc request id associated with this response and remove it
    100     for kv in zapcache.our_zaps {
    101         let zaps = kv.value
    102         
    103         for zap in zaps {
    104             guard case .pending(let pzap) = zap,
    105                   case .nwc(let nwc_state) = pzap.state,
    106                   case .postbox_pending(let req) = nwc_state.state,
    107                   req.id == resp.req_id
    108             else {
    109                 continue
    110             }
    111             
    112             // remove the pending zap if there was an error
    113             let reqid = ZapRequestId(from_pending: pzap)
    114             remove_zap(reqid: reqid, zapcache: zapcache, evcache: evcache)
    115             return
    116         }
    117     }
    118 }