WalletConnectTests.swift (9943B)
1 // 2 // WalletConnectTests.swift 3 // damusTests 4 // 5 // Created by William Casarin on 2023-04-02. 6 // 7 8 import XCTest 9 @testable import damus 10 11 final class WalletConnectTests: XCTestCase { 12 13 override func setUpWithError() throws { 14 // Put setup code here. This method is called before the invocation of each test method in the class. 15 } 16 17 override func tearDownWithError() throws { 18 // Put teardown code here. This method is called after the invocation of each test method in the class. 19 } 20 21 func testWalletBalanceRequest() throws { 22 // This is an example of a functional test case. 23 // Use XCTAssert and related functions to verify your tests produce the correct results. 24 // Any test you write for XCTest can be annotated as throws and async. 25 // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. 26 // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. 27 } 28 29 func get_test_nwc() -> WalletConnectURL { 30 let pk = "9d088f4760422443d4699b485e2ac66e565a2f5da1198c55ddc5679458e3f67a" 31 let sec = "ff2eefd57196d42089e1b42acc39916d7ecac52e0625bd70597bbd5be14aff18" 32 let relay = "wss://relay.getalby.com/v1" 33 let str = "nostrwalletconnect://\(pk)?relay=\(relay)&secret=\(sec)" 34 35 return WalletConnectURL(str: str)! 36 } 37 38 func testDoesNWCParse() { 39 // Test an NWC url format which is not technically NIP-47 and RFC 3986 compliant, but still commonly used (by Alby, for example) 40 // See Github issue #1547 for details on why this URL is non-compliant 41 // This test URL also features: 42 // - `nostrwalletconnect` scheme 43 // - A non-url-encoded relay parameter 44 // - lud16 parameter 45 let pk = Pubkey(hex: "9d088f4760422443d4699b485e2ac66e565a2f5da1198c55ddc5679458e3f67a")! 46 let sec = Privkey(hex: "ff2eefd57196d42089e1b42acc39916d7ecac52e0625bd70597bbd5be14aff18")! 47 let relay = "wss://relay.getalby.com/v1" 48 let str = "nostrwalletconnect://\(pk)?relay=\(relay)&secret=\(sec)&lud16=jb55@jb55.com" 49 50 let url = WalletConnectURL(str: str) 51 XCTAssertNotNil(url) 52 guard let url else { 53 return 54 } 55 XCTAssertEqual(url.pubkey, pk) 56 XCTAssertEqual(url.keypair.privkey, sec) 57 XCTAssertEqual(url.keypair.pubkey, privkey_to_pubkey(privkey: sec)) 58 XCTAssertEqual(url.relay.url.absoluteString, relay) 59 XCTAssertEqual(url.lud16, "jb55@jb55.com") 60 61 // Test an NWC url format which is NIP-47 and RFC 3986 compliant 62 // This test URL also features: 63 // - `nostr+walletconnect` scheme 64 // - A url-encoded relay parameter 65 // - No lud16 parameter 66 let pk_2 = Pubkey(hex: "b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4")! 67 let sec_2 = Privkey(hex: "71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100e4f3c")! 68 let relay_2 = "wss://relay.damus.io" 69 let str_2 = "nostr+walletconnect:b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io&secret=71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100e4f3c" 70 71 let url_2 = WalletConnectURL(str: str_2) 72 XCTAssertNotNil(url_2) 73 guard let url_2 else { 74 return 75 } 76 XCTAssertEqual(url_2.pubkey, pk_2) 77 XCTAssertEqual(url_2.keypair.privkey, sec_2) 78 XCTAssertEqual(url_2.keypair.pubkey, privkey_to_pubkey(privkey: sec_2)) 79 XCTAssertEqual(url_2.relay.url.absoluteString, relay_2) 80 } 81 82 func testNWCEphemeralRelay() { 83 let sec = "8ba3a6b3b57d0f4211bb1ea4d8d1e351a367e9b4ea694746e0a4a452b2bc4d37" 84 let pk = "89446b900c70d62438dcf66756405eea6225ad94dc61f3856f62f9699111a9a6" 85 let nwc = WalletConnectURL(str: "nostrwalletconnect://\(pk)?relay=ws://127.0.0.1&secret=\(sec)&lud16=jb55@jb55.com")! 86 87 let pool = RelayPool(ndb: .empty) 88 let box = PostBox(pool: pool) 89 90 WalletConnect.pay(url: nwc, pool: pool, post: box, invoice: "invoice", zap_request: nil) 91 92 XCTAssertEqual(pool.our_descriptors.count, 0) 93 XCTAssertEqual(pool.all_descriptors.count, 1) 94 XCTAssertEqual(pool.all_descriptors[0].variant, .nwc) 95 XCTAssertEqual(pool.all_descriptors[0].url.url.absoluteString, "ws://127.0.0.1") 96 XCTAssertEqual(box.events.count, 1) 97 let ev = box.events.first!.value 98 XCTAssertEqual(ev.skip_ephemeral, false) 99 XCTAssertEqual(ev.remaining.count, 1) 100 XCTAssertEqual(ev.remaining[0].relay.url.absoluteString, "ws://127.0.0.1") 101 } 102 103 let testBolt11 = "lnbc15u1p3xnhl2pp5jptserfk3zk4qy42tlucycrfwxhydvlemu9pqr93tuzlv9cc7g3sdqsvfhkcap3xyhx7un8cqzpgxqzjcsp5f8c52y2stc300gl6s4xswtjpc37hrnnr3c9wvtgjfuvqmpm35evq9qyyssqy4lgd8tj637qcjp05rdpxxykjenthxftej7a2zzmwrmrl70fyj9hvj0rewhzj7jfyuwkwcg9g2jpwtk3wkjtwnkdks84hsnu8xps5vsq4gj5hs" 104 let testStringEncodedZapRequest = """ 105 {"content":"","created_at":1746235486,"id":"faf5192c6805dea002e50cd52c7e553e3ee66ac42f30f41f1fe62b924f68fb22","kind":9734,"pubkey":"056b5b5966f500defb3b790a14633e5ec4a0e8883ca29bc23d0030553edb084a","sig":"21076018677656a220977c77e34bfa7427e1056a49b633afd3653d1d7466846cf6b35cf3fbf5908c712ebd647119cfadb1fa47e83121a238d77b1996f0fa26ee","tags":[["p","e8361082333142fc7f483b7dbd9bb36d671f2fbcf0a28015b2304fed79365fe8"],["relays","wss://nos.lol","wss://notify.damus.io","wss://relay.damus.io"]]} 106 """ 107 let testDoubleStringEncodedZapRequest = """ 108 "{\\\"content\\\":\\\"\\\",\\\"created_at\\\":1746235486,\\\"id\\\":\\\"faf5192c6805dea002e50cd52c7e553e3ee66ac42f30f41f1fe62b924f68fb22\\\",\\\"kind\\\":9734,\\\"pubkey\\\":\\\"056b5b5966f500defb3b790a14633e5ec4a0e8883ca29bc23d0030553edb084a\\\",\\\"sig\\\":\\\"21076018677656a220977c77e34bfa7427e1056a49b633afd3653d1d7466846cf6b35cf3fbf5908c712ebd647119cfadb1fa47e83121a238d77b1996f0fa26ee\\\",\\\"tags\\\":[[\\\"p\\\",\\\"e8361082333142fc7f483b7dbd9bb36d671f2fbcf0a28015b2304fed79365fe8\\\"],[\\\"relays\\\",\\\"wss://nos.lol\\\",\\\"wss://notify.damus.io\\\",\\\"wss://relay.damus.io\\\"]]}" 109 """ 110 111 func testEncodingPayInvoiceRequest() throws { 112 let testZapRequest = decode_nostr_event_json(json: testStringEncodedZapRequest)! 113 let metadata = WalletConnect.Request.Metadata(nostr: testZapRequest) 114 let request = WalletConnect.Request.payInvoice(invoice: "lntest", description: testStringEncodedZapRequest, metadata: metadata) 115 116 let encodedData = try JSONEncoder().encode(request) 117 let encodedString = String(data: encodedData, encoding: .utf8)! 118 119 XCTAssertTrue(encodedString.contains("\"method\":\"pay_invoice\"")) 120 XCTAssertTrue(encodedString.contains("\"invoice\":\"lntest\"")) 121 XCTAssertTrue(encodedString.contains("\"description\":\"{")) 122 XCTAssertTrue(encodedString.contains("\"nostr\":{")) 123 } 124 125 func testDecodingPayInvoiceRequest() throws { 126 let testZapRequest = decode_nostr_event_json(json: testStringEncodedZapRequest)! 127 128 let jsonText = """ 129 { 130 "method": "pay_invoice", 131 "params": { 132 "invoice": "\(testBolt11)", 133 "description": \(testDoubleStringEncodedZapRequest), 134 "metadata": { 135 "nostr": \(testStringEncodedZapRequest) 136 } 137 } 138 } 139 """ 140 141 let jsonData = jsonText.data(using: .utf8)! 142 143 let decodedRequest = try JSONDecoder().decode(WalletConnect.Request.self, from: jsonData) 144 145 switch decodedRequest { 146 case .payInvoice(let invoice, let description, let metadata): 147 XCTAssertEqual(invoice, testBolt11) 148 XCTAssertEqual(description, testStringEncodedZapRequest) 149 XCTAssertNotNil(metadata) 150 XCTAssertEqual(metadata!.nostr, testZapRequest) 151 default: 152 XCTFail("Decoded to the wrong case") 153 } 154 } 155 156 func testDecodingPayInvoiceRequestWithoutMetadata() throws { 157 let jsonData = """ 158 { 159 "method": "pay_invoice", 160 "params": { 161 "invoice": "\(testBolt11)", 162 "description": \(testDoubleStringEncodedZapRequest) 163 } 164 } 165 """.data(using: .utf8)! 166 167 let decodedRequest = try JSONDecoder().decode(WalletConnect.Request.self, from: jsonData) 168 169 switch decodedRequest { 170 case .payInvoice(let invoice, let description, let metadata): 171 XCTAssertEqual(invoice, testBolt11) 172 XCTAssertEqual(description, testStringEncodedZapRequest) 173 XCTAssertNil(metadata) 174 default: 175 XCTFail("Decoded to the wrong case") 176 } 177 } 178 179 func testDecodingPayInvoiceRequestWithCrazyMetadata() throws { 180 let jsonText = """ 181 { 182 "method": "pay_invoice", 183 "params": { 184 "invoice": "\(testBolt11)", 185 "description": \(testDoubleStringEncodedZapRequest), 186 "metadata": { 187 "nostr": "totally not a zap request because this metadata is crazy", 188 "lorem": "ipsum" 189 } 190 } 191 } 192 """ 193 194 let jsonData = jsonText.data(using: .utf8)! 195 196 let decodedRequest = try JSONDecoder().decode(WalletConnect.Request.self, from: jsonData) 197 198 switch decodedRequest { 199 case .payInvoice(let invoice, let description, let metadata): 200 XCTAssertEqual(invoice, testBolt11) 201 XCTAssertEqual(description, testStringEncodedZapRequest) 202 XCTAssertEqual(metadata?.nostr, nil) 203 default: 204 XCTFail("Decoded to the wrong case") 205 } 206 } 207 }