diff --git a/lib/src/dap.dart b/lib/src/dap.dart index e25e6c3..f927a73 100644 --- a/lib/src/dap.dart +++ b/lib/src/dap.dart @@ -85,12 +85,3 @@ class Dap { (codeUnit >= 123 && codeUnit <= 126); } } - -class DapResolver { - /// default constructor with http client and a web5 did resolver - /// can construct yourself for mocking purposes etc. - /// getRegistryEndpoint() -> resolve registry did, find DAPRegistry service endpoint - /// dereferenceHandle() -> makes GET request to registry endpoint to get DAP's DID - /// resolveDid() -> resolve DAP's DID, get back did document - /// getMoneyAddresses(dap) -> getRegistryEndpoint() -> dereferenceHandle() -> resolveDid() -> parse out money addresses from did document -> return list of money addrrsses -} diff --git a/lib/src/dap_resolver.dart b/lib/src/dap_resolver.dart new file mode 100644 index 0000000..d97c3b0 --- /dev/null +++ b/lib/src/dap_resolver.dart @@ -0,0 +1,19 @@ +import 'package:dap/dap.dart'; +import 'package:http/http.dart' as http; +import 'package:web5/web5.dart'; + +class DapResolver { + http.Client client; + DidResolver didResolver; + + DapResolver(this.didResolver, {http.Client? client}) + : client = client ?? http.Client(); + + Future getMoneyAddresses(Dap dap) async {} + + /// can construct yourself for mocking purposes etc. + /// getRegistryEndpoint() -> resolve registry did, find DAPRegistry service endpoint + /// dereferenceHandle() -> makes GET request to registry endpoint to get DAP's DID + /// resolveDid() -> resolve DAP's DID, get back did document + /// getMoneyAddresses(dap) -> getRegistryEndpoint() -> dereferenceHandle() -> resolveDid() -> parse out money addresses from did document -> return list of money addrrsses +} diff --git a/lib/src/money_address.dart b/lib/src/money_address.dart new file mode 100644 index 0000000..6184f1b --- /dev/null +++ b/lib/src/money_address.dart @@ -0,0 +1,39 @@ +/// A money address is a Uniform Resource Name (URN) that represents a means +/// through which an individual can be payed a specific currency. +/// The URN is structured as follows: +/// `urn::` +/// More info [here](https://github.com/TBD54566975/dap?tab=readme-ov-file#money-address) +class MoneyAddress { + final String currency; + final String css; + + String get urn => 'urn:$currency:$css'; + + MoneyAddress({required this.currency, required this.css}); + + factory MoneyAddress.parse(String input) { + if (!input.startsWith('urn:')) { + throw FormatException('Expected urn. Got $input'); + } + + final urnless = input.substring(4); + final delimIdx = urnless.indexOf(':'); + if (delimIdx == -1) { + throw FormatException( + 'Invalid money address. Expected urn:[currency]:[css]. Got $input'); + } + + final nid = urnless.substring(0, delimIdx); + final nss = urnless.substring(delimIdx + 1); + + return MoneyAddress( + currency: nid, + css: nss, + ); + } + + @override + String toString() { + return urn; + } +} diff --git a/test/money_address_test.dart b/test/money_address_test.dart new file mode 100644 index 0000000..746df7d --- /dev/null +++ b/test/money_address_test.dart @@ -0,0 +1,63 @@ +import 'package:test/test.dart'; +import 'package:dap/src/money_address.dart'; + +class Vector { + final String input; + final MoneyAddress expected; + final bool err; + + Vector({required this.input, required this.expected, required this.err}); +} + +void main() { + group('MoneyAddress.parse', () { + final testCases = [ + Vector( + input: 'urn:usdc:eth:0x2345y7432', + expected: MoneyAddress( + currency: 'usdc', + css: 'eth:0x2345y7432', + ), + err: false, + ), + Vector( + input: 'urn:btc:addr:m12345677axcv2345', + expected: MoneyAddress( + currency: 'btc', + css: 'addr:m12345677axcv2345', + ), + err: false, + ), + Vector( + input: 'urn:btc:lnurl:https://someurl.com', + expected: MoneyAddress( + currency: 'btc', + css: 'lnurl:https://someurl.com', + ), + err: false, + ), + Vector( + input: 'urn:btc:spaddr:sp1234abcd5678', + expected: MoneyAddress( + currency: 'btc', + css: 'spaddr:sp1234abcd5678', + ), + err: false, + ), + ]; + + for (var testCase in testCases) { + test(testCase.input, () { + if (testCase.err) { + expect( + () => MoneyAddress.parse(testCase.input), throwsFormatException); + } else { + final actual = MoneyAddress.parse(testCase.input); + expect(actual.currency, testCase.expected.currency); + expect(actual.css, testCase.expected.css); + expect(actual.urn, testCase.input); + } + }); + } + }); +}