diff --git a/CHANGELOG.md b/CHANGELOG.md index 1df04810..f6fa9244 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.3.0-beta01 + +- One-Click Auth support + ## 2.2.3 - Full web support diff --git a/README.md b/README.md index 665e5535..a332a9a6 100644 --- a/README.md +++ b/README.md @@ -12,38 +12,44 @@ WalletConnect Dart v2 library for Flutter, heavily inspired by the WalletConnect // If you just need one of the other, replace Web3App with SignClient or AuthClient // SignClient wcClient = await SignClient.createInstance( // AuthClient wcClient = await AuthClient.createInstance( +// BE MINDFUL THAT AuthClient is currently deprecated and will be removed soon. +// Authentication methods, including One-Click Auth, are now withing SignClient Web3App wcClient = await Web3App.createInstance( - relayUrl: 'wss://relay.walletconnect.com', // The relay websocket URL, leave blank to use the default projectId: '123', + relayUrl: 'wss://relay.walletconnect.com', // The relay websocket URL, leave blank to use the default metadata: PairingMetadata( - name: 'dApp (Requester)', + name: 'Your dApp Name (Requester)', description: 'A dapp that can request that transactions be signed', url: 'https://walletconnect.com', icons: ['https://avatars.githubusercontent.com/u/37784886'], + redirect: Redirect( // Specially important object if you the Wallet to navigate back to your dapp + native: 'mydapp://', + universal: 'https://mydapp.com/app', + ), ), ); // For a dApp, you would connect with specific parameters, then display // the returned URI. ConnectResponse resp = await wcClient.connect( - requiredNamespaces: { - 'eip155': RequiredNamespace( - chains: ['eip155:1'], // Ethereum chain - methods: ['personal_sign'], // Requestable Methods, see MethodsConstants for reference - events: ['chainChanged'], // Requestable Events, see EventsConstants for reference - ), - }, optionalNamespaces: { 'eip155': RequiredNamespace( - chains: ['eip155:1', 'eip155:5'], // Any other optional Ethereum chain - methods: ['eth_signTransaction'], // Optional requestable Methods, see MethodsConstants for reference - events: ['accountsChanged'], // Optional requestable events, see EventsConstants for reference + // Any Ethereum chain you want to connect with + chains: ['eip155:1', 'eip155:5'], + // Requestable Methods, see MethodsConstants class for reference + methods: ['personal_sign', 'eth_sendTransaction'], + // Optional requestable events, see EventsConstants for reference + events: ['accountsChanged'], ), }, ); +// display connection uri withih a QR code or use it to launch a wallet Uri? uri = resp.uri; +// Example: +// final encodedUri = Uri.encodeComponent(uri.toString()); +// launchUrlString('metamask://wc?uri=$encodedUri', mode: LaunchMode.externalApplication); -// Once you've display the URI, you can wait for the future, and hide the QR code once you've received session data +// Once you've displayed the URI, you can wait for the future, and hide the QR code once you've received session data final SessionData session = await resp.session.future; // Now that you have a session, you can request signatures @@ -59,6 +65,7 @@ final dynamic signResponse = await wcClient.request( // Structure is dependant upon the JSON RPC call you made. +// [DEPRECATED] // You can also request authentication final AuthRequestResponse authReq = await wcClient.requestAuth( params: AuthRequestParams( @@ -71,7 +78,7 @@ final AuthRequestResponse authReq = await wcClient.requestAuth( ); // Await the auth response using the provided completer -final AuthResponse authResponse = await authResponse.completer.future; +final AuthResponse authResponse = await authReq.completer.future; if (authResponse.result != null) { // Having a result means you have the signature and it is verified. @@ -85,6 +92,39 @@ else { final JsonRpcError? error = authResponse.jsonRpcError; } +// Instead of connect() and then requestAuth() you can leverage One-Click Auth +// Which is connection (session proposal) and authentication (SIWE) in just 1 step +final SessionAuthRequestResponse authReq = await wcClient.authenticate( + params: SessionAuthRequestParams( + chains: ['eip155:1', 'eip155:5'], + domain: 'yourdomain.com', + uri: 'https://yourdomain.com/login', + nonce: AuthUtils.generateNonce(), + statement: 'Welcome to my example dApp.', + methods: ['personal_sign', 'eth_sendTransaction'], + ), +); +// display authentication uri withih a QR code or use it to launch a wallet +Uri? uri = authReq.uri; +// Example: +// final encodedUri = Uri.encodeComponent(uri.toString()); +// launchUrlString('metamask://wc?uri=$encodedUri', mode: LaunchMode.externalApplication); +// IMPORTANT: Not every wallet supports One-Click Auth yet but don't worry, if wallet does not support it, +// it will fallback to regular session proposal automatically + +// Once you've displayed the URI, you can wait for the future, and hide the QR code once you've received session data +final SessionAuthResponse authResponse = await authReq.completer.future; +if (authResponse.session != null) { + // Having a result means you have succesfully authenticated and created a session +} +else { + // Otherwise, you might have gotten a WalletConnectError if there was un issue verifying the signature. + final WalletConnectError? error = authResponse.error; + // Of a JsonRpcError if something went wrong when signing with the wallet. + final JsonRpcError? error = authResponse.jsonRpcError; +} + + // You can also respond to events from the wallet, like session events wcClient.registerEventHandler( @@ -99,13 +139,17 @@ wcClient.onSessionEvent.subscribe((SessionEvent? session) { ### Wallet Flow ```dart Web3Wallet wcClient = await Web3Wallet.createInstance( - relayUrl: 'wss://relay.walletconnect.com', // The relay websocket URL, leave blank to use the default projectId: '123', + relayUrl: 'wss://relay.walletconnect.com', // The relay websocket URL, leave blank to use the default metadata: PairingMetadata( - name: 'Wallet (Responder)', + name: 'Your Wallet Name (Responder)', description: 'A wallet that can be requested to sign transactions', url: 'https://walletconnect.com', icons: ['https://avatars.githubusercontent.com/u/37784886'], + redirect: Redirect( // Specially important object if you want dApps to be able to open you wallet + native: 'mywallet://', + universal: 'https://mywallet.com/app', + ), ), ); @@ -122,6 +166,72 @@ wcClient.onSessionProposal.subscribe((SessionProposal? args) async { final isInvalidApp = args.verifyContext?.validation.invalid; final isValidApp = args.verifyContext?.validation.valid; final unknown = args.verifyContext?.validation.unknown; + // + // Present the UI to the user, and allow them to reject or approve the proposal + await wcClient.approveSession( + id: args.id, + namespaces: args.params.generatedNamespaces!, + sessionProperties: args.params.sessionProperties, + ); + // Or to reject... + // Error codes and reasons can be found here: https://docs.walletconnect.com/2.0/specs/clients/sign/error-codes + await wcClient.rejectSession( + id: id, + reason: Errors.getSdkError(Errors.USER_REJECTED), + ); + } +}); + +// If you are planning to support One-Click Auth then you would have to subscribe to onSessionAuthRequest events +wcClient.onSessionAuthRequest.subscribe((SessionAuthRequest? args) async { + // Handle UI updates using the args.params + // Keep track of the args.id for the approval response + if (args != null) { + id = args!.id; + // To check VerifyAPI validation in regards of the dApp is trying to connnect you can check verifyContext + // More info about VerifyAPI https://docs.walletconnect.com/web3wallet/verify + final isScamApp = args.verifyContext?.validation.scam; + final isInvalidApp = args.verifyContext?.validation.invalid; + final isValidApp = args.verifyContext?.validation.valid; + final unknown = args.verifyContext?.validation.unknown; + // + // Process Authentication request + final SessionAuthPayload requestPayload = args.authPayload; + final responsePayload = AuthSignature.populateAuthPayload( + authPayload: requestPayload, + chains: ['eip155:1', 'eip155:5'], // Your supported EVM chains + methods: ['personal_sign', 'etg_sendTransaction'], // Your supported methods + ); + // For every chain you support you decide to sign a the message + final message = _web3Wallet!.formatAuthMessage( + iss: 'did:pkh:eip155:1:0xADDRESS.....', + cacaoPayload: CacaoRequestPayload.fromSessionAuthPayload( + responsePayload, + ), + ); + // final hexSignature = * signMessage(message) * + // And creates a Cacao object with it + final cacao = AuthSignature.buildAuthObject( + requestPayload: CacaoRequestPayload.fromSessionAuthPayload( + responsePayload, + ), + signature: CacaoSignature( + t: CacaoSignature.EIP191, + s: hexSignature, + ), + iss: 'did:pkh:eip155:1:0xADDRESS.....', + ); + // + // To respond with the signed messages and create a session for the dapp you use approveSessionAuthenticate + await _web3Wallet!.approveSessionAuthenticate( + id: args.id, + auths: [cacao], // You would have here as many cacaos as messages your wallet signed + ); + // To reject to session authenticate request you use rejectSessionAuthenticate + await _web3Wallet!.rejectSessionAuthenticate( + id: args.id, + reason: Errors.getSdkError(Errors.USER_REJECTED_AUTH), + ); } }); @@ -173,6 +283,7 @@ final signRequestHandler = (String topic, dynamic parameters) async { throw Errors.getSdkError(Errors.USER_REJECTED_SIGN); } } + wcClient.registerRequestHandler( chainId: 'eip155:1', method: 'eth_sendTransaction', @@ -196,6 +307,7 @@ wcClient.onSessionProposalError.subscribe((SessionProposalError? args) { // Handle the error }); +/* [DEPRECATED] */ // Setup the auth handling clientB.onAuthRequest.subscribe((AuthRequest? args) async { @@ -212,31 +324,6 @@ clientB.onAuthRequest.subscribe((AuthRequest? args) async { ); }); -// Then, scan the QR code and parse the URI, and pair with the dApp -// On the first pairing, you will immediately receive onSessionProposal and onAuthRequest events. -Uri uri = Uri.parse(scannedUriString); -final PairingInfo pairing = await wcClient.pair(uri: uri); - -// Present the UI to the user, and allow them to reject or approve the proposal -final walletNamespaces = { - 'eip155': Namespace( - accounts: ['eip155:1:abc'], - methods: ['eth_signTransaction'], - events: ['accountsChanged'], - ), -} -await wcClient.approveSession( - id: id, - namespaces: walletNamespaces // This will have the accounts requested in params - // If you registered correctly events emitters, methods handlers and accounts for your supported chains you can just us `args.params.generatedNamespaces!` value from SessionProposalEvent -); -// Or to reject... -// Error codes and reasons can be found here: https://docs.walletconnect.com/2.0/specs/clients/sign/error-codes -await wcClient.rejectSession( - id: id, - reason: Errors.getSdkError(Errors.USER_REJECTED), -); - // For auth, you can do the same thing: Present the UI to them, and have them approve the signature. // Then respond with that signature. In this example I use EthSigUtil, but you can use any library that can perform // a personal eth sign. @@ -256,6 +343,7 @@ await wcClient.respondAuthRequest( iss: 'did:pkh:eip155:1:ETH_ADDRESS', error: Errors.getSdkError(Errors.USER_REJECTED_AUTH), ); +// // You can also emit events for the dApp await wcClient.emitSessionEvent( diff --git a/example/dapp/android/app/src/main/AndroidManifest.xml b/example/dapp/android/app/src/main/AndroidManifest.xml index 2b63c4b5..aad3033b 100644 --- a/example/dapp/android/app/src/main/AndroidManifest.xml +++ b/example/dapp/android/app/src/main/AndroidManifest.xml @@ -4,7 +4,7 @@ android:name="${applicationName}" android:icon="@mipmap/ic_launcher"> LSApplicationQueriesSchemes wcflutterwallet + walletapp LSRequiresIPhoneOS diff --git a/example/dapp/lib/main.dart b/example/dapp/lib/main.dart index b4c54505..802e6827 100644 --- a/example/dapp/lib/main.dart +++ b/example/dapp/lib/main.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:developer'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; import 'package:walletconnect_flutter_v2_dapp/models/chain_metadata.dart'; @@ -57,11 +58,9 @@ class _MyHomePageState extends State { } Future initialize() async { - // try { - debugPrint('Project ID: ${DartDefines.projectId}'); _web3App = await Web3App.createInstance( projectId: DartDefines.projectId, - logLevel: LogLevel.info, + logLevel: LogLevel.error, metadata: const PairingMetadata( name: 'Sample dApp Flutter', description: 'WalletConnect\'s sample dapp with Flutter', @@ -80,7 +79,6 @@ class _MyHomePageState extends State { for (final ChainMetadata chain in ChainData.allChains) { // Loop through the events for that chain for (final event in getChainEvents(chain.type)) { - debugPrint('registerEventHandler $event for chain ${chain.chainId}'); _web3App!.registerEventHandler( chainId: chain.chainId, event: event, @@ -89,16 +87,18 @@ class _MyHomePageState extends State { } // Register event handlers - _web3App!.onSessionPing.subscribe(_onSessionPing); - _web3App!.onSessionEvent.subscribe(_onSessionEvent); - _web3App!.onSessionUpdate.subscribe(_onSessionUpdate); - + _web3App!.core.addLogListener(_logListener); _web3App!.core.relayClient.onRelayClientConnect.subscribe(_setState); _web3App!.core.relayClient.onRelayClientDisconnect.subscribe(_setState); - _web3App!.core.relayClient.onRelayClientMessage.subscribe(_onRelayMessage); + _web3App!.core.relayClient.onRelayClientMessage.subscribe( + _onRelayMessage, + ); - _web3App!.signEngine.onSessionEvent.subscribe(_onSessionEvent); - _web3App!.signEngine.onSessionUpdate.subscribe(_onSessionUpdate); + _web3App!.onSessionPing.subscribe(_onSessionPing); + _web3App!.onSessionEvent.subscribe(_onSessionEvent); + _web3App!.onSessionUpdate.subscribe(_onSessionUpdate); + _web3App!.onSessionConnect.subscribe(_onSessionConnect); + _web3App!.onSessionAuthResponse.subscribe(_onSessionAuthResponse); setState(() { _pageDatas = [ @@ -126,9 +126,14 @@ class _MyHomePageState extends State { _initializing = false; }); - // } on WalletConnectError catch (e) { - // print(e.message); - // } + } + + void _onSessionConnect(SessionConnect? event) { + log('[SampleDapp] _onSessionConnect $event'); + } + + void _onSessionAuthResponse(SessionAuthResponse? response) { + log('[SampleDapp] _onSessionAuthResponse $response'); } void _setState(dynamic args) => setState(() {}); @@ -136,20 +141,29 @@ class _MyHomePageState extends State { @override void dispose() { // Unregister event handlers + _web3App!.core.removeLogListener(_logListener); + _web3App!.core.relayClient.onRelayClientConnect.unsubscribe(_setState); + _web3App!.core.relayClient.onRelayClientDisconnect.unsubscribe(_setState); + _web3App!.core.relayClient.onRelayClientMessage.unsubscribe( + _onRelayMessage, + ); + _web3App!.onSessionPing.unsubscribe(_onSessionPing); _web3App!.onSessionEvent.unsubscribe(_onSessionEvent); _web3App!.onSessionUpdate.unsubscribe(_onSessionUpdate); + _web3App!.onSessionConnect.subscribe(_onSessionConnect); + _web3App!.onSessionAuthResponse.subscribe(_onSessionAuthResponse); - _web3App!.core.relayClient.onRelayClientConnect.unsubscribe(_setState); - _web3App!.core.relayClient.onRelayClientDisconnect.unsubscribe(_setState); - _web3App!.core.relayClient.onRelayClientMessage - .unsubscribe(_onRelayMessage); - - _web3App!.signEngine.onSessionEvent.unsubscribe(_onSessionEvent); - _web3App!.signEngine.onSessionUpdate.unsubscribe(_onSessionUpdate); super.dispose(); } + void _logListener(LogEvent event) { + debugPrint('[Logger] ${event.level.name}: ${event.message}'); + if (event.level == Level.error) { + // TODO send to mixpanel + } + } + @override Widget build(BuildContext context) { if (_initializing) { @@ -231,7 +245,7 @@ class _MyHomePageState extends State { } void _onSessionPing(SessionPing? args) { - debugPrint('[$runtimeType] _onSessionPing $args'); + debugPrint('[SampleDapp] _onSessionPing $args'); showDialog( context: context, builder: (BuildContext context) { @@ -244,7 +258,7 @@ class _MyHomePageState extends State { } void _onSessionEvent(SessionEvent? args) { - debugPrint('[$runtimeType] _onSessionEvent $args'); + debugPrint('[SampleDapp] _onSessionEvent $args'); showDialog( context: context, builder: (BuildContext context) { @@ -258,7 +272,7 @@ class _MyHomePageState extends State { } void _onSessionUpdate(SessionUpdate? args) { - debugPrint('[$runtimeType] _onSessionUpdate $args'); + debugPrint('[SampleDapp] _onSessionUpdate $args'); } void _onRelayMessage(MessageEvent? args) async { @@ -269,9 +283,9 @@ class _MyHomePageState extends State { args.message, ); final data = jsonDecode(payloadString ?? '{}') as Map; - debugPrint('[$runtimeType] _onRelayMessage data $data'); + debugPrint('[SampleDapp] _onRelayMessage data $data'); } catch (e) { - debugPrint('[$runtimeType] _onRelayMessage error $e'); + debugPrint('[SampleDapp] _onRelayMessage error $e'); } } } diff --git a/example/dapp/lib/pages/connect_page.dart b/example/dapp/lib/pages/connect_page.dart index b1e476ec..dad3c545 100644 --- a/example/dapp/lib/pages/connect_page.dart +++ b/example/dapp/lib/pages/connect_page.dart @@ -1,6 +1,5 @@ -// ignore_for_file: use_build_context_synchronously - import 'dart:async'; +import 'dart:convert'; import 'package:fl_toast/fl_toast.dart'; import 'package:flutter/foundation.dart'; @@ -63,7 +62,7 @@ class ConnectPageState extends State { } _updateNamespaces(); - debugPrint('$optionalNamespaces'); + debugPrint('[SampleDapp] ${jsonEncode(optionalNamespaces)}'); }); } @@ -165,6 +164,50 @@ class ConnectPageState extends State { ), ); + children.add(const SizedBox(height: 16.0)); + + children.add( + ElevatedButton( + onPressed: _selectedChains.isEmpty + ? null + : () => _oneClickAuth( + closeModal: () { + if (Navigator.canPop(context)) { + Navigator.of(context).pop(); + } + }, + showToast: (message) { + showPlatformToast(child: Text(message), context: context); + }, + ), + style: ButtonStyle( + backgroundColor: MaterialStateProperty.resolveWith( + (states) { + if (states.contains(MaterialState.disabled)) { + return StyleConstants.grayColor; + } + return StyleConstants.primaryColor; + }, + ), + minimumSize: MaterialStateProperty.all(const Size( + 1000.0, + StyleConstants.linear48, + )), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + StyleConstants.linear8, + ), + ), + ), + ), + child: const Text( + 'One-Click Auth', + style: StyleConstants.buttonText, + ), + ), + ); + children.add(const SizedBox.square(dimension: 12.0)); return Center( @@ -243,7 +286,7 @@ class ConnectPageState extends State { Function(String message)? showToast, VoidCallback? closeModal, }) async { - debugPrint('Creating connection and session'); + debugPrint('[SampleDapp] Creating connection and session'); // It is currently safer to send chains approvals on optionalNamespaces // but depending on Wallet implementation you may need to send some (for innstance eip155:1) as required final connectResponse = await widget.web3App.connect( @@ -255,6 +298,7 @@ class ConnectPageState extends State { // final uri = 'metamask://wc?uri=$encodedUri'; if (await canLaunchUrlString(uri)) { final openApp = await showDialog( + // ignore: use_build_context_synchronously context: context, builder: (BuildContext context) { return AlertDialog( @@ -275,21 +319,22 @@ class ConnectPageState extends State { if (openApp) { launchUrlString(uri, mode: LaunchMode.externalApplication); } else { - _showQrCode(connectResponse); + _showQrCode(connectResponse.uri.toString()); } } else { - _showQrCode(connectResponse); + _showQrCode(connectResponse.uri.toString()); } - debugPrint('Awaiting session proposal settlement'); + debugPrint('[SampleDapp] Awaiting session proposal settlement'); final _ = await connectResponse.session.future; showToast?.call(StringConstants.connectionEstablished); + closeModal?.call(); } - Future _showQrCode(ConnectResponse response) async { + Future _showQrCode(String uri) async { // Show the QR code - debugPrint('Showing QR Code: ${response.uri}'); + debugPrint('[SampleDapp] Showing QR Code: $uri'); _shouldDismissQrCode = true; if (kIsWeb) { await showDialog( @@ -307,7 +352,7 @@ class ConnectPageState extends State { child: Padding( padding: const EdgeInsets.all(20.0), child: _QRCodeView( - uri: response.uri.toString(), + uri: uri, ), ), ), @@ -328,19 +373,15 @@ class ConnectPageState extends State { context, MaterialPageRoute( fullscreenDialog: true, - builder: (context) => QRCodeScreen(response: response), + builder: (context) => QRCodeScreen(uri: uri), ), ); } - void _onSessionConnect(SessionConnect? event) async { - if (event == null) return; - - if (_shouldDismissQrCode && Navigator.canPop(context)) { - _shouldDismissQrCode = false; - Navigator.pop(context); - } - + void _requestAuth( + SessionConnect? event, { + Function(String message)? showToast, + }) async { final shouldAuth = await showDialog( context: context, barrierDismissible: false, @@ -365,52 +406,128 @@ class ConnectPageState extends State { ); }, ); - if (!shouldAuth) return; + if (shouldAuth != true) return; try { - final scheme = event.session.peer.metadata.redirect?.native ?? ''; - launchUrlString(scheme, mode: LaunchMode.externalApplication); - - final pairingTopic = event.session.pairingTopic; + final pairingTopic = event?.session.pairingTopic; // Send off an auth request now that the pairing/session is established - debugPrint('Requesting authentication'); - final authRes = await widget.web3App.requestAuth( + final authResponse = await widget.web3App.requestAuth( pairingTopic: pairingTopic, params: AuthRequestParams( chainId: _selectedChains[0].chainId, domain: Constants.domain, aud: Constants.aud, - // statement: 'Welcome to example flutter app', + statement: 'Welcome to example flutter app', ), ); - debugPrint('Awaiting authentication response'); - final authResponse = await authRes.completer.future; + final scheme = event?.session.peer.metadata.redirect?.native; + launchUrlString( + scheme ?? 'wcflutterwallet://', + mode: LaunchMode.externalApplication, + ); - if (authResponse.error != null) { - debugPrint('Authentication failed: ${authResponse.error}'); - showPlatformToast( - child: const Text(StringConstants.authFailed), - context: context, - ); + debugPrint('[SampleDapp] Awaiting authentication response'); + final response = await authResponse.completer.future; + if (response.result != null) { + showToast?.call(StringConstants.authSucceeded); } else { - showPlatformToast( - child: const Text(StringConstants.authSucceeded), - context: context, - ); + final error = response.error ?? response.jsonRpcError; + showToast?.call(error.toString()); } } catch (e) { - showPlatformToast( - child: const Text(StringConstants.connectionFailed), + debugPrint('[SampleDapp] auth $e'); + showToast?.call(StringConstants.connectionFailed); + } + } + + void _oneClickAuth({ + VoidCallback? closeModal, + Function(String message)? showToast, + }) async { + final methods = optionalNamespaces['eip155']?.methods ?? []; + final authResponse = await widget.web3App.authenticate( + params: SessionAuthRequestParams( + chains: _selectedChains.map((e) => e.chainId).toList(), + domain: Constants.domain, + nonce: AuthUtils.generateNonce(), + uri: Constants.aud, + statement: 'Welcome to example flutter app', + methods: methods, + ), + ); + + final encodedUri = Uri.encodeComponent(authResponse.uri.toString()); + final uri = 'wcflutterwallet://wc?uri=$encodedUri'; + + if (await canLaunchUrlString(uri)) { + final openApp = await showDialog( + // ignore: use_build_context_synchronously context: context, + builder: (BuildContext context) { + return AlertDialog( + content: const Text('Do you want to open with Web3Wallet Flutter'), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: const Text('Show QR'), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: const Text('Open'), + ), + ], + ); + }, ); + if (openApp) { + launchUrlString(uri, mode: LaunchMode.externalApplication); + } else { + _showQrCode(authResponse.uri.toString()); + } + } else { + _showQrCode(authResponse.uri.toString()); } + + try { + debugPrint('[SampleDapp] Awaiting 1-CA session'); + final response = await authResponse.completer.future; + + if (response.session != null) { + showToast?.call( + '${StringConstants.authSucceeded} and ${StringConstants.connectionEstablished}', + ); + } else { + final error = response.error ?? response.jsonRpcError; + showToast?.call(error.toString()); + } + } catch (e) { + debugPrint('[SampleDapp] 1-CA $e'); + showToast?.call(StringConstants.connectionFailed); + } + closeModal?.call(); + } + + void _onSessionConnect(SessionConnect? event) async { + if (event == null) return; + + if (_shouldDismissQrCode && Navigator.canPop(context)) { + _shouldDismissQrCode = false; + Navigator.pop(context); + } + + _requestAuth( + event, + showToast: (message) { + showPlatformToast(child: Text(message), context: context); + }, + ); } } class QRCodeScreen extends StatefulWidget { - const QRCodeScreen({super.key, required this.response}); - final ConnectResponse response; + const QRCodeScreen({super.key, required this.uri}); + final String uri; @override State createState() => _QRCodeScreenState(); @@ -423,7 +540,7 @@ class _QRCodeScreenState extends State { child: Scaffold( appBar: AppBar(title: const Text(StringConstants.scanQrCode)), body: _QRCodeView( - uri: widget.response.uri!.toString(), + uri: widget.uri, ), ), ); diff --git a/example/dapp/lib/pages/pairings_page.dart b/example/dapp/lib/pages/pairings_page.dart index 50f67183..4a58f75a 100644 --- a/example/dapp/lib/pages/pairings_page.dart +++ b/example/dapp/lib/pages/pairings_page.dart @@ -75,7 +75,7 @@ class PairingsPageState extends State { ); Navigator.of(context).pop(); } catch (e) { - debugPrint(e.toString()); + debugPrint('[SampleDapp] ${e.toString()}'); } }, ), diff --git a/example/dapp/lib/pages/sessions_page.dart b/example/dapp/lib/pages/sessions_page.dart index 7f346c60..8309e730 100644 --- a/example/dapp/lib/pages/sessions_page.dart +++ b/example/dapp/lib/pages/sessions_page.dart @@ -61,7 +61,7 @@ class SessionsPageState extends State { (session) => ExpansionPanel( canTapOnHeader: true, isExpanded: _selectedSession == session.topic, - backgroundColor: Colors.black12, + backgroundColor: Colors.blue.withOpacity(0.2), headerBuilder: (context, isExpanded) { return SessionItem( key: ValueKey(session.topic), diff --git a/example/dapp/lib/utils/crypto/helpers.dart b/example/dapp/lib/utils/crypto/helpers.dart index 64705660..a37dfbbb 100644 --- a/example/dapp/lib/utils/crypto/helpers.dart +++ b/example/dapp/lib/utils/crypto/helpers.dart @@ -12,7 +12,7 @@ String getChainName(String chain) { .first .name; } catch (e) { - debugPrint('Invalid chain'); + debugPrint('[SampleDapp] Invalid chain'); } return 'Unknown'; } @@ -23,7 +23,7 @@ ChainMetadata getChainMetadataFromChain(String chain) { .where((element) => element.chainId == chain) .first; } catch (e) { - debugPrint('Invalid chain'); + debugPrint('[SampleDapp] Invalid chain'); } return ChainData.eip155Chains[0]; } diff --git a/example/dapp/lib/widgets/auth_item.dart b/example/dapp/lib/widgets/auth_item.dart index 26c1151d..df27fd61 100644 --- a/example/dapp/lib/widgets/auth_item.dart +++ b/example/dapp/lib/widgets/auth_item.dart @@ -18,7 +18,7 @@ class AuthItem extends StatelessWidget { onTap: onTap, child: Container( padding: const EdgeInsets.all(12.0), - color: Colors.green.withOpacity(0.2), + color: Colors.blue.withOpacity(0.2), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -26,9 +26,8 @@ class AuthItem extends StatelessWidget { auth.p.domain, style: StyleConstants.paragraph, ), - Text( - auth.p.iss, - ), + Text(auth.p.iss), + Text('iat: ${auth.p.iat}'), ], ), ), diff --git a/example/dapp/lib/widgets/pairing_item.dart b/example/dapp/lib/widgets/pairing_item.dart index 11205c86..74e1f1b2 100644 --- a/example/dapp/lib/widgets/pairing_item.dart +++ b/example/dapp/lib/widgets/pairing_item.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; import 'package:walletconnect_flutter_v2_dapp/utils/constants.dart'; @@ -14,11 +15,19 @@ class PairingItem extends StatelessWidget { @override Widget build(BuildContext context) { + final expiryTimestamp = DateTime.fromMillisecondsSinceEpoch( + pairing.expiry * 1000, + ); + final dateFormat = DateFormat.yMd().add_jm(); + final expiryDate = dateFormat.format(expiryTimestamp); + final inDays = expiryTimestamp.difference(DateTime.now()).inDays + 1; return InkWell( onTap: onTap, child: Container( padding: const EdgeInsets.all(12.0), - color: Colors.blue.withOpacity(0.2), + color: pairing.active + ? Colors.blue.withOpacity(0.2) + : Colors.red.withOpacity(0.2), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -27,7 +36,7 @@ class PairingItem extends StatelessWidget { style: StyleConstants.paragraph, ), Text( - pairing.peerMetadata?.url ?? 'Unknown', + pairing.peerMetadata?.url ?? 'Expiry: $expiryDate ($inDays days)', ), ], ), diff --git a/example/dapp/lib/widgets/session_item.dart b/example/dapp/lib/widgets/session_item.dart index 01e6a584..93a42531 100644 --- a/example/dapp/lib/widgets/session_item.dart +++ b/example/dapp/lib/widgets/session_item.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; import 'package:walletconnect_flutter_v2_dapp/utils/constants.dart'; @@ -12,6 +13,12 @@ class SessionItem extends StatelessWidget { @override Widget build(BuildContext context) { + final expiryTimestamp = DateTime.fromMillisecondsSinceEpoch( + session.expiry * 1000, + ); + final dateFormat = DateFormat.yMd().add_jm(); + final expiryDate = dateFormat.format(expiryTimestamp); + final inDays = expiryTimestamp.difference(DateTime.now()).inDays + 1; return Container( padding: const EdgeInsets.all(12.0), child: Column( @@ -21,9 +28,7 @@ class SessionItem extends StatelessWidget { session.peer.metadata.name, style: StyleConstants.paragraph, ), - Text( - session.peer.metadata.url, - ), + Text('Expiry: $expiryDate ($inDays days)'), ], ), ); diff --git a/example/wallet/lib/dependencies/bottom_sheet/i_bottom_sheet_service.dart b/example/wallet/lib/dependencies/bottom_sheet/i_bottom_sheet_service.dart index 5ccca104..48d88c52 100644 --- a/example/wallet/lib/dependencies/bottom_sheet/i_bottom_sheet_service.dart +++ b/example/wallet/lib/dependencies/bottom_sheet/i_bottom_sheet_service.dart @@ -2,6 +2,12 @@ import 'dart:async'; import 'package:flutter/material.dart'; +enum WCBottomSheetResult { + reject, + one, + all, +} + class BottomSheetQueueItem { final Widget widget; final Completer completer; diff --git a/example/wallet/lib/dependencies/chains/common.dart b/example/wallet/lib/dependencies/chains/common.dart index 81d46fb8..1b5be74c 100644 --- a/example/wallet/lib/dependencies/chains/common.dart +++ b/example/wallet/lib/dependencies/chains/common.dart @@ -30,22 +30,23 @@ class CommonMethods { static Future requestApproval(String text, {String? title}) async { final bottomSheetService = GetIt.I(); - final approved = await bottomSheetService.queueBottomSheet( - widget: WCRequestWidget( - child: WCConnectionWidget( - title: 'Approve Request', - info: [ - WCConnectionModel( - title: title, - elements: [ - text, + final WCBottomSheetResult rs = (await bottomSheetService.queueBottomSheet( + widget: WCRequestWidget( + child: WCConnectionWidget( + title: 'Approve Request', + info: [ + WCConnectionModel( + title: title, + elements: [ + text, + ], + ), ], ), - ], - ), - ), - ); + ), + )) ?? + WCBottomSheetResult.reject; - return approved ?? false; + return rs != WCBottomSheetResult.reject; } } diff --git a/example/wallet/lib/dependencies/chains/evm_service.dart b/example/wallet/lib/dependencies/chains/evm_service.dart index 06c05144..38ecad84 100644 --- a/example/wallet/lib/dependencies/chains/evm_service.dart +++ b/example/wallet/lib/dependencies/chains/evm_service.dart @@ -16,6 +16,35 @@ import 'package:walletconnect_flutter_v2_wallet/widgets/wc_connection_widget/wc_ import 'package:walletconnect_flutter_v2_wallet/widgets/wc_connection_widget/wc_connection_widget.dart'; import 'package:walletconnect_flutter_v2_wallet/widgets/wc_request_widget.dart/wc_request_widget.dart'; +enum SupportedEVMMethods { + ethSign, + ethSignTransaction, + ethSignTypedData, + ethSignTypedDataV4, + switchChain, + personalSign, + ethSendTransaction; + + String get name { + switch (this) { + case ethSign: + return 'eth_sign'; + case ethSignTransaction: + return 'eth_signTransaction'; + case ethSignTypedData: + return 'eth_signTypedData'; + case ethSignTypedDataV4: + return 'eth_signTypedData_v4'; + case switchChain: + return 'wallet_switchEthereumChain'; + case personalSign: + return 'personal_sign'; + case ethSendTransaction: + return 'eth_sendTransaction'; + } + } +} + class EVMService { final _bottomSheetService = GetIt.I(); final _web3Wallet = GetIt.I().web3wallet; @@ -24,17 +53,17 @@ class EVMService { late final Web3Client ethClient; Map get sessionRequestHandlers => { - 'eth_sign': ethSign, - 'eth_signTransaction': ethSignTransaction, - 'eth_signTypedData': ethSignTypedData, - 'eth_signTypedData_v4': ethSignTypedDataV4, - 'wallet_switchEthereumChain': switchChain, + SupportedEVMMethods.ethSign.name: ethSign, + SupportedEVMMethods.ethSignTransaction.name: ethSignTransaction, + SupportedEVMMethods.ethSignTypedData.name: ethSignTypedData, + SupportedEVMMethods.ethSignTypedDataV4.name: ethSignTypedDataV4, + SupportedEVMMethods.switchChain.name: switchChain, // 'wallet_addEthereumChain': addChain, }; Map get methodRequestHandlers => { - 'personal_sign': personalSign, - 'eth_sendTransaction': ethSendTransaction, + SupportedEVMMethods.personalSign.name: personalSign, + SupportedEVMMethods.ethSendTransaction.name: ethSendTransaction, }; EVMService({required this.chainSupported}) { @@ -451,22 +480,23 @@ class EVMService { final gweiGasPrice = (transaction.gasPrice?.getInWei ?? BigInt.zero) / BigInt.from(1000000000); - final approved = await _bottomSheetService.queueBottomSheet( - widget: WCRequestWidget( - child: WCConnectionWidget( - title: 'Approve Transaction', - info: [ - WCConnectionModel(elements: [jsonEncode(tJson)]), - WCConnectionModel( - title: 'Gas price', - elements: ['${gweiGasPrice.toStringAsFixed(2)} GWEI'], + final WCBottomSheetResult rs = (await _bottomSheetService.queueBottomSheet( + widget: WCRequestWidget( + child: WCConnectionWidget( + title: 'Approve Transaction', + info: [ + WCConnectionModel(elements: [jsonEncode(tJson)]), + WCConnectionModel( + title: 'Gas price', + elements: ['${gweiGasPrice.toStringAsFixed(2)} GWEI'], + ), + ], ), - ], - ), - ), - ); + ), + )) ?? + WCBottomSheetResult.reject; - if (approved == true) { + if (rs != WCBottomSheetResult.reject) { return transaction; } diff --git a/example/wallet/lib/dependencies/chains/kadena_service.dart b/example/wallet/lib/dependencies/chains/kadena_service.dart index 469c1504..f7fd84fb 100644 --- a/example/wallet/lib/dependencies/chains/kadena_service.dart +++ b/example/wallet/lib/dependencies/chains/kadena_service.dart @@ -112,7 +112,7 @@ class KadenaService { ); try { - final chain = ChainData.allChains.firstWhere( + final chain = ChainData.kadenaChains.firstWhere( (c) => c.chainId == chainSupported.chainId, ); final uri = Uri.parse(chain.rpc.first); diff --git a/example/wallet/lib/dependencies/key_service/key_service.dart b/example/wallet/lib/dependencies/key_service/key_service.dart index a65fbca8..5e0093b9 100644 --- a/example/wallet/lib/dependencies/key_service/key_service.dart +++ b/example/wallet/lib/dependencies/key_service/key_service.dart @@ -9,7 +9,6 @@ import 'package:walletconnect_flutter_v2_wallet/dependencies/bip39/bip39_base.da as bip39; import 'package:walletconnect_flutter_v2_wallet/dependencies/bip32/bip32_base.dart' as bip32; -import 'package:walletconnect_flutter_v2_wallet/models/chain_metadata.dart'; import 'package:walletconnect_flutter_v2_wallet/utils/dart_defines.dart'; class KeyService extends IKeyService { @@ -116,10 +115,7 @@ class KeyService extends IKeyService { final private = EthPrivateKey.fromHex(keyPair.privateKey); final address = private.address.hex; final evmChainKey = ChainKey( - chains: ChainData.allChains - .where((c) => c.type == ChainType.eip155) - .map((e) => e.chainId) - .toList(), + chains: ChainData.eip155Chains.map((e) => e.chainId).toList(), privateKey: keyPair.privateKey, publicKey: keyPair.publicKey, address: address, @@ -148,10 +144,7 @@ class KeyService extends IKeyService { ChainKey _kadenaKeyPair() { return ChainKey( - chains: ChainData.allChains - .where((c) => c.type == ChainType.kadena) - .map((e) => e.chainId) - .toList(), + chains: ChainData.kadenaChains.map((e) => e.chainId).toList(), privateKey: DartDefines.kadenaSecretKey, publicKey: DartDefines.kadenaAddress, address: DartDefines.kadenaAddress, @@ -159,21 +152,8 @@ class KeyService extends IKeyService { } ChainKey _polkadotKeyPair() { - // final keyring = Keyring(); - // final keyPair1 = await KeyPair.sr25519.fromMnemonic( - // DartDefines.polkadotMnemonic1, - // ); - // keyPair1.ss58Format = 1; - // keyring.add(keyPair1); - - // final publicKey = keyPair1.publicKey.bytes; - // final encodedPublicKey = hex.encode(publicKey); - return ChainKey( - chains: ChainData.allChains - .where((c) => c.type == ChainType.polkadot) - .map((e) => e.chainId) - .toList(), + chains: ChainData.polkadotChains.map((e) => e.chainId).toList(), privateKey: DartDefines.polkadotMnemonic, publicKey: '', address: DartDefines.polkadotAddress, @@ -182,10 +162,7 @@ class KeyService extends IKeyService { ChainKey _solanaKeyPair() { return ChainKey( - chains: ChainData.allChains - .where((c) => c.type == ChainType.solana) - .map((e) => e.chainId) - .toList(), + chains: ChainData.solanaChains.map((e) => e.chainId).toList(), privateKey: DartDefines.solanaSecretKey, publicKey: DartDefines.solanaAddress, address: DartDefines.solanaAddress, diff --git a/example/wallet/lib/dependencies/web3wallet_service.dart b/example/wallet/lib/dependencies/web3wallet_service.dart index e9a5d582..210ee07e 100644 --- a/example/wallet/lib/dependencies/web3wallet_service.dart +++ b/example/wallet/lib/dependencies/web3wallet_service.dart @@ -7,17 +7,18 @@ import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; import 'package:walletconnect_flutter_v2_wallet/dependencies/bottom_sheet/i_bottom_sheet_service.dart'; +import 'package:walletconnect_flutter_v2_wallet/dependencies/chains/evm_service.dart'; import 'package:walletconnect_flutter_v2_wallet/dependencies/deep_link_handler.dart'; import 'package:walletconnect_flutter_v2_wallet/dependencies/i_web3wallet_service.dart'; import 'package:walletconnect_flutter_v2_wallet/dependencies/key_service/chain_key.dart'; import 'package:walletconnect_flutter_v2_wallet/dependencies/key_service/i_key_service.dart'; +import 'package:walletconnect_flutter_v2_wallet/models/chain_data.dart'; import 'package:walletconnect_flutter_v2_wallet/utils/constants.dart'; import 'package:walletconnect_flutter_v2_wallet/utils/dart_defines.dart'; import 'package:walletconnect_flutter_v2_wallet/utils/eth_utils.dart'; -import 'package:walletconnect_flutter_v2_wallet/widgets/wc_connection_request/wc_auth_request_model.dart'; import 'package:walletconnect_flutter_v2_wallet/widgets/wc_connection_request/wc_connection_request_widget.dart'; -import 'package:walletconnect_flutter_v2_wallet/widgets/wc_connection_request/wc_session_request_model.dart'; import 'package:walletconnect_flutter_v2_wallet/widgets/wc_request_widget.dart/wc_request_widget.dart'; +import 'package:walletconnect_flutter_v2_wallet/widgets/wc_request_widget.dart/wc_session_auth_request_widget.dart'; class Web3WalletService extends IWeb3WalletService { final _bottomSheetHandler = GetIt.I(); @@ -26,11 +27,9 @@ class Web3WalletService extends IWeb3WalletService { @override Future create() async { // Create the web3wallet - _web3Wallet = Web3Wallet( - core: Core( - projectId: DartDefines.projectId, - logLevel: LogLevel.error, - ), + _web3Wallet = await Web3Wallet.createInstance( + projectId: DartDefines.projectId, + logLevel: LogLevel.error, metadata: const PairingMetadata( name: 'Sample Wallet Flutter', description: 'WalletConnect\'s sample wallet with Flutter', @@ -55,14 +54,14 @@ class Web3WalletService extends IWeb3WalletService { for (final chainId in chainKey.chains) { if (chainId.startsWith('kadena')) { final account = '$chainId:k**${chainKey.address}'; - debugPrint('[$runtimeType] registerAccount $account'); + debugPrint('[SampleWallet] registerAccount $account'); _web3Wallet!.registerAccount( chainId: chainId, accountAddress: 'k**${chainKey.address}', ); } else { final account = '$chainId:${chainKey.address}'; - debugPrint('[$runtimeType] registerAccount $account'); + debugPrint('[SampleWallet] registerAccount $account'); _web3Wallet!.registerAccount( chainId: chainId, accountAddress: chainKey.address, @@ -72,43 +71,56 @@ class Web3WalletService extends IWeb3WalletService { } // Setup our listeners - debugPrint('[WALLET] [$runtimeType] create'); + debugPrint('[SampleWallet] create'); + _web3Wallet!.core.addLogListener(_logListener); _web3Wallet!.core.pairing.onPairingInvalid.subscribe(_onPairingInvalid); _web3Wallet!.core.pairing.onPairingCreate.subscribe(_onPairingCreate); - _web3Wallet!.onSessionProposal.subscribe(_onSessionProposal); - _web3Wallet!.onSessionConnect.subscribe(_onSessionConnect); - _web3Wallet!.onSessionProposalError.subscribe(_onSessionProposalError); - _web3Wallet!.onAuthRequest.subscribe(_onAuthRequest); _web3Wallet!.core.relayClient.onRelayClientError.subscribe( _onRelayClientError, ); _web3Wallet!.core.relayClient.onRelayClientMessage.subscribe( _onRelayClientMessage, ); + + _web3Wallet!.onSessionProposal.subscribe(_onSessionProposal); + _web3Wallet!.onSessionProposalError.subscribe(_onSessionProposalError); + _web3Wallet!.onSessionConnect.subscribe(_onSessionConnect); + _web3Wallet!.onSessionAuthRequest.subscribe(_onSessionAuthRequest); + + _web3Wallet!.onAuthRequest.subscribe(_onAuthRequest); } @override Future init() async { // Await the initialization of the web3wallet - debugPrint('[$runtimeType] [WALLET] init'); await _web3Wallet!.init(); } + void _logListener(LogEvent event) { + debugPrint('[Logger] ${event.level.name}: ${event.message}'); + if (event.level == Level.error) { + // TODO send to mixpanel + } + } + @override FutureOr onDispose() { - debugPrint('[$runtimeType] [WALLET] dispose'); + _web3Wallet!.core.removeLogListener(_logListener); _web3Wallet!.core.pairing.onPairingInvalid.unsubscribe(_onPairingInvalid); _web3Wallet!.core.pairing.onPairingCreate.unsubscribe(_onPairingCreate); - _web3Wallet!.onSessionProposal.unsubscribe(_onSessionProposal); - _web3Wallet!.onSessionConnect.unsubscribe(_onSessionConnect); - _web3Wallet!.onSessionProposalError.unsubscribe(_onSessionProposalError); - _web3Wallet!.onAuthRequest.unsubscribe(_onAuthRequest); _web3Wallet!.core.relayClient.onRelayClientError.unsubscribe( _onRelayClientError, ); _web3Wallet!.core.relayClient.onRelayClientMessage.unsubscribe( _onRelayClientMessage, ); + + _web3Wallet!.onSessionProposal.unsubscribe(_onSessionProposal); + _web3Wallet!.onSessionProposalError.unsubscribe(_onSessionProposalError); + _web3Wallet!.onSessionConnect.unsubscribe(_onSessionConnect); + _web3Wallet!.onSessionAuthRequest.unsubscribe(_onSessionAuthRequest); + + _web3Wallet!.onAuthRequest.unsubscribe(_onAuthRequest); } @override @@ -117,7 +129,7 @@ class Web3WalletService extends IWeb3WalletService { void _onRelayClientMessage(MessageEvent? event) async { if (event != null) { final jsonObject = await EthUtils.decodeMessageEvent(event); - debugPrint('[$runtimeType] [WALLET] _onRelayClientMessage $jsonObject'); + debugPrint('[SampleWallet] _onRelayClientMessage $jsonObject'); if (jsonObject is JsonRpcRequest) { if (jsonObject.method == 'wc_sessionPropose' || jsonObject.method == 'wc_sessionRequest') { @@ -141,20 +153,20 @@ class Web3WalletService extends IWeb3WalletService { void _onSessionProposal(SessionProposalEvent? args) async { if (args != null) { - log('[$runtimeType] [WALLET] _onSessionProposal ${jsonEncode(args.params)}'); - final approved = await _bottomSheetHandler.queueBottomSheet( - widget: WCRequestWidget( - child: WCConnectionRequestWidget( - wallet: _web3Wallet!, - sessionProposal: WCSessionRequestModel( - request: args.params, - verifyContext: args.verifyContext, - ), - ), - ), - ); + log('[SampleWallet] _onSessionProposal ${jsonEncode(args.params)}'); + final WCBottomSheetResult rs = + (await _bottomSheetHandler.queueBottomSheet( + widget: WCRequestWidget( + child: WCConnectionRequestWidget( + proposalData: args.params, + verifyContext: args.verifyContext, + metadata: args.params.proposer, + ), + ), + )) ?? + WCBottomSheetResult.reject; - if (approved == true) { + if (rs != WCBottomSheetResult.reject) { // generatedNamespaces is constructed based on registered methods handlers // so if you want to handle requests using onSessionRequest event then you would need to manually add that method in the approved namespaces await _web3Wallet!.approveSession( @@ -182,7 +194,7 @@ class Web3WalletService extends IWeb3WalletService { } void _onSessionProposalError(SessionProposalErrorEvent? args) async { - debugPrint('[$runtimeType] [WALLET] _onSessionProposalError $args'); + log('[SampleWallet] _onSessionProposalError $args'); DeepLinkHandler.waiting.value = false; if (args != null) { String errorMessage = args.error.message; @@ -221,53 +233,142 @@ class Web3WalletService extends IWeb3WalletService { void _onSessionConnect(SessionConnect? args) { if (args != null) { - log('[$runtimeType] [WALLET] _onSessionConnect ${jsonEncode(args.session)}'); + log('[SampleWallet] _onSessionConnect ${jsonEncode(args.session)}'); final scheme = args.session.peer.metadata.redirect?.native ?? ''; DeepLinkHandler.goTo(scheme); } } void _onRelayClientError(ErrorEvent? args) { - debugPrint('[$runtimeType] [WALLET] _onRelayClientError ${args?.error}'); + debugPrint('[SampleWallet] _onRelayClientError ${args?.error}'); } void _onPairingInvalid(PairingInvalidEvent? args) { - debugPrint('[$runtimeType] [WALLET] _onPairingInvalid $args'); + debugPrint('[SampleWallet] _onPairingInvalid $args'); } void _onPairingCreate(PairingEvent? args) { - debugPrint('[$runtimeType] [WALLET] _onPairingCreate $args'); + debugPrint('[SampleWallet] _onPairingCreate $args'); } - Future _onAuthRequest(AuthRequest? args) async { - debugPrint('[$runtimeType] [WALLET] _onAuthRequest $args'); + void _onSessionAuthRequest(SessionAuthRequest? args) async { + log('[SampleWallet] _onSessionAuthRequest ${jsonEncode(args?.authPayload.toJson())}'); if (args != null) { - final chainKeys = GetIt.I().getKeysForChain('eip155:1'); - // Create the message to be signed - final iss = 'did:pkh:eip155:1:${chainKeys.first.address}'; + final SessionAuthPayload authPayload = args.authPayload; + final supportedChains = ChainData.eip155Chains.map((e) => e.chainId); + final supportedMethods = SupportedEVMMethods.values.map((e) => e.name); + final newAuthPayload = AuthSignature.populateAuthPayload( + authPayload: authPayload, + chains: supportedChains.toList(), + methods: supportedMethods.toList(), + ); + final cacaoRequestPayload = CacaoRequestPayload.fromSessionAuthPayload( + newAuthPayload, + ); + final List> formattedMessages = []; + for (var chain in newAuthPayload.chains) { + final chainKeys = GetIt.I().getKeysForChain(chain); + final iss = 'did:pkh:$chain:${chainKeys.first.address}'; + final message = _web3Wallet!.formatAuthMessage( + iss: iss, + cacaoPayload: cacaoRequestPayload, + ); + formattedMessages.add({iss: message}); + } - final bool? auth = await _bottomSheetHandler.queueBottomSheet( - widget: WCRequestWidget( - child: WCConnectionRequestWidget( - wallet: _web3Wallet!, - authRequest: WCAuthRequestModel( + final WCBottomSheetResult rs = + (await _bottomSheetHandler.queueBottomSheet( + widget: WCSessionAuthRequestWidget( + child: WCConnectionRequestWidget( + sessionAuthPayload: newAuthPayload, + verifyContext: args.verifyContext, + metadata: args.requester, + ), + ), + )) ?? + WCBottomSheetResult.reject; + + if (rs != WCBottomSheetResult.reject) { + const chain = 'eip155:1'; + final chainKeys = GetIt.I().getKeysForChain(chain); + final privateKey = '0x${chainKeys[0].privateKey}'; + final credentials = EthPrivateKey.fromHex(privateKey); + // + final messageToSign = formattedMessages.length; + final count = (rs == WCBottomSheetResult.one) ? 1 : messageToSign; + // + final List cacaos = []; + for (var i = 0; i < count; i++) { + final iss = formattedMessages[i].keys.first; + final message = formattedMessages[i].values.first; + final signature = credentials.signPersonalMessageToUint8List( + Uint8List.fromList(message.codeUnits), + ); + final hexSignature = bytesToHex(signature, include0x: true); + cacaos.add( + AuthSignature.buildAuthObject( + requestPayload: cacaoRequestPayload, + signature: CacaoSignature( + t: CacaoSignature.EIP191, + s: hexSignature, + ), iss: iss, - request: args, ), - ), - ), - ); + ); + } + // + final _ = await _web3Wallet!.approveSessionAuthenticate( + id: args.id, + auths: cacaos, + ); + final scheme = args.requester.metadata.redirect?.native ?? ''; + DeepLinkHandler.goTo(scheme); + } else { + await _web3Wallet!.rejectSessionAuthenticate( + id: args.id, + reason: Errors.getSdkError(Errors.USER_REJECTED_AUTH), + ); + final scheme = args.requester.metadata.redirect?.native ?? ''; + DeepLinkHandler.goTo( + scheme, + modalTitle: 'Error', + modalMessage: 'User rejected', + success: false, + ); + } + } + } + + Future _onAuthRequest(AuthRequest? args) async { + log('[SampleWallet] _onAuthRequest $args'); + if (args != null) { + // + final WCBottomSheetResult rs = + (await _bottomSheetHandler.queueBottomSheet( + widget: WCRequestWidget( + child: WCConnectionRequestWidget( + authPayloadParams: args.payloadParams, + metadata: args.requester, + ), + ), + )) ?? + WCBottomSheetResult.reject; + + const chain = 'eip155:1'; + final chainKeys = GetIt.I().getKeysForChain(chain); + final privateKey = '0x${chainKeys[0].privateKey}'; + final credentials = EthPrivateKey.fromHex(privateKey); + final iss = 'did:pkh:$chain:${credentials.address.hex}'; - if (auth != null && auth) { - final String message = _web3Wallet!.formatAuthMessage( + if (rs != WCBottomSheetResult.reject) { + // + final message = _web3Wallet!.formatAuthMessage( iss: iss, cacaoPayload: CacaoRequestPayload.fromPayloadParams( args.payloadParams, ), ); - final pk = '0x${chainKeys.first.privateKey}'; - final credentials = EthPrivateKey.fromHex(pk); final signature = credentials.signPersonalMessageToUint8List( Uint8List.fromList(message.codeUnits), ); diff --git a/example/wallet/lib/main.dart b/example/wallet/lib/main.dart index 56f7a03e..39cff46d 100644 --- a/example/wallet/lib/main.dart +++ b/example/wallet/lib/main.dart @@ -14,7 +14,6 @@ import 'package:walletconnect_flutter_v2_wallet/dependencies/key_service/i_key_s import 'package:walletconnect_flutter_v2_wallet/dependencies/key_service/key_service.dart'; import 'package:walletconnect_flutter_v2_wallet/dependencies/web3wallet_service.dart'; import 'package:walletconnect_flutter_v2_wallet/models/chain_data.dart'; -import 'package:walletconnect_flutter_v2_wallet/models/chain_metadata.dart'; import 'package:walletconnect_flutter_v2_wallet/models/page_data.dart'; import 'package:walletconnect_flutter_v2_wallet/pages/apps_page.dart'; import 'package:walletconnect_flutter_v2_wallet/pages/settings_page.dart'; @@ -69,9 +68,7 @@ class _MyHomePageState extends State with GetItStateMixin { GetIt.I.registerSingleton(web3WalletService); // Support EVM Chains - final evmChains = - ChainData.allChains.where((c) => c.type == ChainType.eip155).toList(); - for (final chainData in evmChains) { + for (final chainData in ChainData.eip155Chains) { GetIt.I.registerSingleton( EVMService(chainSupported: chainData), instanceName: chainData.chainId, @@ -79,9 +76,7 @@ class _MyHomePageState extends State with GetItStateMixin { } // Support Kadena Chains - final kadenaChains = - ChainData.allChains.where((c) => c.type == ChainType.kadena).toList(); - for (final chainData in kadenaChains) { + for (final chainData in ChainData.kadenaChains) { GetIt.I.registerSingleton( KadenaService(chainSupported: chainData), instanceName: chainData.chainId, @@ -89,9 +84,7 @@ class _MyHomePageState extends State with GetItStateMixin { } // Support Polkadot Chains - final polkadotChains = - ChainData.allChains.where((c) => c.type == ChainType.polkadot).toList(); - for (final chainData in polkadotChains) { + for (final chainData in ChainData.polkadotChains) { GetIt.I.registerSingleton( PolkadotService(chainSupported: chainData), instanceName: chainData.chainId, @@ -99,9 +92,7 @@ class _MyHomePageState extends State with GetItStateMixin { } // Support Solana Chains - final solanaChains = - ChainData.allChains.where((c) => c.type == ChainType.solana).toList(); - for (final chainData in solanaChains) { + for (final chainData in ChainData.solanaChains) { GetIt.I.registerSingleton( SolanaService(chainSupported: chainData), instanceName: chainData.chainId, @@ -109,9 +100,7 @@ class _MyHomePageState extends State with GetItStateMixin { } // Support Cosmos Chains - final cosmosChains = - ChainData.allChains.where((c) => c.type == ChainType.cosmos).toList(); - for (final chainData in cosmosChains) { + for (final chainData in ChainData.cosmosChains) { GetIt.I.registerSingleton( CosmosService(chainSupported: chainData), instanceName: chainData.chainId, @@ -127,16 +116,16 @@ class _MyHomePageState extends State with GetItStateMixin { title: StringConstants.connectPageTitle, icon: Icons.swap_vert_circle_outlined, ), - PageData( - page: const Center( - child: Text( - 'Inbox (Not Implemented)', - style: StyleConstants.bodyText, - ), - ), - title: 'Inbox', - icon: Icons.inbox_rounded, - ), + // PageData( + // page: const Center( + // child: Text( + // 'Inbox (Not Implemented)', + // style: StyleConstants.bodyText, + // ), + // ), + // title: 'Inbox', + // icon: Icons.inbox_rounded, + // ), PageData( page: const SettingsPage(), title: 'Settings', diff --git a/example/wallet/lib/models/chain_data.dart b/example/wallet/lib/models/chain_data.dart index 6440ce7b..f69380ca 100644 --- a/example/wallet/lib/models/chain_data.dart +++ b/example/wallet/lib/models/chain_data.dart @@ -195,12 +195,4 @@ class ChainData { ], ), ]; - - static final List allChains = [ - ...eip155Chains, - ...solanaChains, - ...polkadotChains, - ...kadenaChains, - // ...cosmosChains, - ]; } diff --git a/example/wallet/lib/pages/app_detail_page.dart b/example/wallet/lib/pages/app_detail_page.dart index 632244e8..eaf348b7 100644 --- a/example/wallet/lib/pages/app_detail_page.dart +++ b/example/wallet/lib/pages/app_detail_page.dart @@ -45,6 +45,7 @@ class AppDetailPageState extends State { @override Widget build(BuildContext context) { + final metadata = widget.pairing.peerMetadata; DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(widget.pairing.expiry * 1000); int year = dateTime.year; @@ -104,10 +105,10 @@ class AppDetailPageState extends State { ), ); } - final scheme = widget.pairing.peerMetadata?.redirect?.native ?? ''; + final scheme = metadata?.redirect?.native ?? ''; return Scaffold( appBar: AppBar( - title: Text(widget.pairing.peerMetadata?.name ?? 'Unknown'), + title: Text(metadata?.name ?? 'Unknown'), actions: [ Visibility( visible: scheme.isNotEmpty, @@ -131,33 +132,39 @@ class AppDetailPageState extends State { ), child: Column( children: [ - Row( - children: [ - CircleAvatar( - radius: 40.0, - backgroundImage: (widget - .pairing.peerMetadata!.icons.isNotEmpty - ? NetworkImage(widget.pairing.peerMetadata!.icons[0]) - : const AssetImage('assets/images/default_icon.png')) - as ImageProvider, - ), - const SizedBox(width: 10.0), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(widget.pairing.peerMetadata!.url), - Text('Expires on: $expiryDate'), - ], + Visibility( + visible: metadata != null, + child: Row( + children: [ + CircleAvatar( + radius: 40.0, + backgroundImage: ((metadata?.icons ?? []).isNotEmpty + ? NetworkImage(metadata!.icons[0]) + : const AssetImage( + 'assets/images/default_icon.png')) + as ImageProvider, ), - ), - ], + const SizedBox(width: 10.0), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(metadata?.url ?? ''), + Text('Expires on: $expiryDate'), + ], + ), + ), + ], + ), ), const SizedBox(height: 20.0), - Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: sessionWidgets, + Visibility( + visible: metadata != null, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: sessionWidgets, + ), ), const SizedBox(height: 20.0), Row( diff --git a/example/wallet/lib/pages/settings_page.dart b/example/wallet/lib/pages/settings_page.dart index 3c4f6c47..65a05c4d 100644 --- a/example/wallet/lib/pages/settings_page.dart +++ b/example/wallet/lib/pages/settings_page.dart @@ -6,6 +6,7 @@ import 'package:flutter/services.dart'; import 'package:get_it/get_it.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; import 'package:walletconnect_flutter_v2_wallet/dependencies/bottom_sheet/i_bottom_sheet_service.dart'; +import 'package:walletconnect_flutter_v2_wallet/dependencies/i_web3wallet_service.dart'; import 'package:walletconnect_flutter_v2_wallet/dependencies/key_service/i_key_service.dart'; import 'package:walletconnect_flutter_v2_wallet/utils/constants.dart'; import 'package:walletconnect_flutter_v2_wallet/widgets/custom_button.dart'; @@ -37,6 +38,7 @@ class _SettingsPageState extends State { Widget build(BuildContext context) { final keysService = GetIt.I(); final chainKeys = keysService.getKeysForChain('eip155:1'); + final web3Wallet = GetIt.I().web3wallet; return Padding( padding: const EdgeInsets.all(12.0), child: Column( @@ -45,6 +47,7 @@ class _SettingsPageState extends State { Expanded( child: SingleChildScrollView( child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ const Padding( padding: EdgeInsets.only(left: 8.0, bottom: 8.0), @@ -83,68 +86,92 @@ class _SettingsPageState extends State { ); }, ), - ], - ), - ), - ), - const SizedBox(height: 8.0), - Row( - children: [ - Expanded( - child: Text( - version ?? '', - textAlign: TextAlign.center, - style: const TextStyle(fontSize: 11.0), - ), - ) - ], - ), - const SizedBox(height: 8.0), - Row( - children: [ - CustomButton( - onTap: () async { - final mnemonic = - await GetIt.I().queueBottomSheet( - widget: RecoverFromSeed(), - ); - if (mnemonic is String) { - await keysService.restoreWallet(mnemonic: mnemonic); - setState(() {}); - } - }, - child: const Center( - child: Text( - 'Import account', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, + const SizedBox(height: 20.0), + const Divider(height: 1.0), + const Padding( + padding: EdgeInsets.only(left: 8.0, bottom: 8.0, top: 20.0), + child: Text( + 'Device', + style: TextStyle( + color: Colors.black, + fontSize: 16.0, + fontWeight: FontWeight.w500, + ), ), ), - ), - ), - ], - ), - const SizedBox(height: 12.0), - Row( - children: [ - CustomButton( - type: CustomButtonType.invalid, - onTap: () async { - await keysService.loadDefaultWallet(); - setState(() {}); - }, - child: const Center( - child: Text( - 'Restore default', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - ), + FutureBuilder( + future: web3Wallet.core.crypto.getClientId(), + builder: (context, snapshot) { + return _DataContainer( + title: 'Client ID', + data: snapshot.data ?? '', + ); + }, ), - ), + const SizedBox(height: 20.0), + const Divider(height: 1.0), + const SizedBox(height: 20.0), + Row( + children: [ + CustomButton( + onTap: () async { + final mnemonic = await GetIt.I() + .queueBottomSheet( + widget: RecoverFromSeed(), + ); + if (mnemonic is String) { + await keysService.restoreWallet(mnemonic: mnemonic); + setState(() {}); + } + }, + child: const Center( + child: Text( + 'Import account', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + const SizedBox(height: 12.0), + Row( + children: [ + CustomButton( + type: CustomButtonType.invalid, + onTap: () async { + await keysService.loadDefaultWallet(); + setState(() {}); + }, + child: const Center( + child: Text( + 'Restore default', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + const SizedBox(height: 12.0), + Row( + children: [ + Expanded( + child: Text( + version ?? '', + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 11.0), + ), + ) + ], + ), + ], ), - ], + ), ), ], ), diff --git a/example/wallet/lib/widgets/custom_button.dart b/example/wallet/lib/widgets/custom_button.dart index d7c9cf94..f8c79f8f 100644 --- a/example/wallet/lib/widgets/custom_button.dart +++ b/example/wallet/lib/widgets/custom_button.dart @@ -40,7 +40,7 @@ class CustomButton extends StatelessWidget { borderRadius: BorderRadius.circular(16), ), padding: const EdgeInsets.symmetric( - horizontal: 24, + horizontal: 8, vertical: 12, ), child: child, diff --git a/example/wallet/lib/widgets/pairing_item.dart b/example/wallet/lib/widgets/pairing_item.dart index 7195ff3c..95f332d3 100644 --- a/example/wallet/lib/widgets/pairing_item.dart +++ b/example/wallet/lib/widgets/pairing_item.dart @@ -18,9 +18,10 @@ class PairingItem extends StatelessWidget { Widget build(BuildContext context) { PairingMetadata? metadata = pairing.peerMetadata; if (metadata == null) { - return const ListTile( - title: Text('Unknown'), - subtitle: Text('No metadata available'), + return ListTile( + title: const Text('Unknown'), + subtitle: const Text('No metadata available'), + onTap: onTap, ); } final sessions = GetIt.I() diff --git a/example/wallet/lib/widgets/wc_connection_request/wc_auth_request_model.dart b/example/wallet/lib/widgets/wc_connection_request/wc_auth_request_model.dart deleted file mode 100644 index cf5efd26..00000000 --- a/example/wallet/lib/widgets/wc_connection_request/wc_auth_request_model.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; - -class WCAuthRequestModel { - final String iss; - final AuthRequest request; - - WCAuthRequestModel({ - required this.iss, - required this.request, - }); -} diff --git a/example/wallet/lib/widgets/wc_connection_request/wc_connection_request_widget.dart b/example/wallet/lib/widgets/wc_connection_request/wc_connection_request_widget.dart index cca9deeb..3155bb42 100644 --- a/example/wallet/lib/widgets/wc_connection_request/wc_connection_request_widget.dart +++ b/example/wallet/lib/widgets/wc_connection_request/wc_connection_request_widget.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:walletconnect_flutter_v2/apis/core/verify/models/verify_context.dart'; +import 'package:get_it/get_it.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; +import 'package:walletconnect_flutter_v2_wallet/dependencies/i_web3wallet_service.dart'; +import 'package:walletconnect_flutter_v2_wallet/dependencies/key_service/i_key_service.dart'; import 'package:walletconnect_flutter_v2_wallet/utils/constants.dart'; import 'package:walletconnect_flutter_v2_wallet/utils/namespace_model_builder.dart'; import 'package:walletconnect_flutter_v2_wallet/utils/string_constants.dart'; -import 'package:walletconnect_flutter_v2_wallet/widgets/wc_connection_request/wc_auth_request_model.dart'; -import 'package:walletconnect_flutter_v2_wallet/widgets/wc_connection_request/wc_session_request_model.dart'; import 'package:walletconnect_flutter_v2_wallet/widgets/wc_connection_widget/wc_connection_widget.dart'; import '../wc_connection_widget/wc_connection_model.dart'; @@ -13,21 +13,21 @@ import '../wc_connection_widget/wc_connection_model.dart'; class WCConnectionRequestWidget extends StatelessWidget { const WCConnectionRequestWidget({ Key? key, - required this.wallet, - this.authRequest, - this.sessionProposal, + this.authPayloadParams, + this.sessionAuthPayload, + this.proposalData, + this.metadata, + this.verifyContext, }) : super(key: key); - final Web3Wallet wallet; - final WCAuthRequestModel? authRequest; - final WCSessionRequestModel? sessionProposal; + final AuthPayloadParams? authPayloadParams; + final SessionAuthPayload? sessionAuthPayload; + final ProposalData? proposalData; + final ConnectionMetadata? metadata; + final VerifyContext? verifyContext; @override Widget build(BuildContext context) { - // Get the connection metadata - final proposerMetadata = sessionProposal?.request.proposer; - final metadata = authRequest?.request.requester ?? proposerMetadata; - if (metadata == null) { return const Text('ERROR'); } @@ -35,16 +35,14 @@ class WCConnectionRequestWidget extends StatelessWidget { return Container( decoration: BoxDecoration( color: Colors.white, - borderRadius: BorderRadius.circular( - StyleConstants.linear8, - ), + borderRadius: BorderRadius.circular(StyleConstants.linear8), ), child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ Text( - '${metadata.metadata.name}\n${StringConstants.wouldLikeToConnect}', + '${metadata!.metadata.name}\n${StringConstants.wouldLikeToConnect}', style: StyleConstants.subtitleText.copyWith( fontSize: 18, color: Colors.black, @@ -53,30 +51,73 @@ class WCConnectionRequestWidget extends StatelessWidget { ), const SizedBox(height: StyleConstants.linear8), VerifyContextWidget( - verifyContext: sessionProposal?.verifyContext, + verifyContext: verifyContext, ), const SizedBox(height: StyleConstants.linear8), - authRequest != null + (authPayloadParams != null) ? _buildAuthRequestView() - : _buildSessionProposalView(context), + : (sessionAuthPayload != null) + ? _buildSessionAuthRequestView() + : _buildSessionProposalView(context), ], ), ); } Widget _buildAuthRequestView() { - final model = WCConnectionModel( - text: wallet.formatAuthMessage( - iss: 'did:pkh:eip155:1:${authRequest!.iss}', - cacaoPayload: CacaoRequestPayload.fromPayloadParams( - authRequest!.request.payloadParams, - ), - ), + final web3Wallet = GetIt.I().web3wallet; + // + final cacaoPayload = CacaoRequestPayload.fromPayloadParams( + authPayloadParams!, + ); + const chain = 'eip155:1'; + final chainKeys = GetIt.I().getKeysForChain(chain); + final iss = 'did:pkh:$chain:${chainKeys.first.address}'; + final message = web3Wallet.formatAuthMessage( + iss: iss, + cacaoPayload: cacaoPayload, + ); + // + final messageModel = WCConnectionModel( + text: message, ); return WCConnectionWidget( - title: StringConstants.message, - info: [model], + title: 'Message', + info: [ + messageModel, + ], + ); + } + + Widget _buildSessionAuthRequestView() { + final web3Wallet = GetIt.I().web3wallet; + // + final cacaoPayload = CacaoRequestPayload.fromSessionAuthPayload( + sessionAuthPayload!, + ); + // + final List messagesModels = []; + for (var chain in sessionAuthPayload!.chains) { + final chainKeys = GetIt.I().getKeysForChain(chain); + final iss = 'did:pkh:$chain:${chainKeys.first.address}'; + final message = web3Wallet.formatAuthMessage( + iss: iss, + cacaoPayload: cacaoPayload, + ); + messagesModels.add( + WCConnectionModel( + title: 'Message ${messagesModels.length + 1}', + elements: [ + message, + ], + ), + ); + } + // + return WCConnectionWidget( + title: '${messagesModels.length} Messages', + info: messagesModels, ); } @@ -84,7 +125,7 @@ class WCConnectionRequestWidget extends StatelessWidget { // Create the connection models using the required and optional namespaces provided by the proposal data // The key is the title and the list of values is the data final views = ConnectionWidgetBuilder.buildFromRequiredNamespaces( - sessionProposal!.request.generatedNamespaces!, + proposalData!.generatedNamespaces!, ); return Column( diff --git a/example/wallet/lib/widgets/wc_connection_request/wc_session_request_model.dart b/example/wallet/lib/widgets/wc_connection_request/wc_session_request_model.dart deleted file mode 100644 index 5afd07a2..00000000 --- a/example/wallet/lib/widgets/wc_connection_request/wc_session_request_model.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:walletconnect_flutter_v2/apis/core/verify/models/verify_context.dart'; -import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; - -class WCSessionRequestModel { - final ProposalData request; - final VerifyContext? verifyContext; - - WCSessionRequestModel({ - required this.request, - this.verifyContext, - }); -} diff --git a/example/wallet/lib/widgets/wc_request_widget.dart/wc_request_widget.dart b/example/wallet/lib/widgets/wc_request_widget.dart/wc_request_widget.dart index 4e9a91e8..adbdc543 100644 --- a/example/wallet/lib/widgets/wc_request_widget.dart/wc_request_widget.dart +++ b/example/wallet/lib/widgets/wc_request_widget.dart/wc_request_widget.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:walletconnect_flutter_v2_wallet/dependencies/bottom_sheet/i_bottom_sheet_service.dart'; import 'package:walletconnect_flutter_v2_wallet/utils/constants.dart'; import 'package:walletconnect_flutter_v2_wallet/utils/string_constants.dart'; import 'package:walletconnect_flutter_v2_wallet/widgets/custom_button.dart'; @@ -29,7 +30,8 @@ class WCRequestWidget extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ CustomButton( - onTap: onReject ?? () => Navigator.of(context).pop(false), + onTap: onReject ?? + () => Navigator.of(context).pop(WCBottomSheetResult.reject), type: CustomButtonType.invalid, child: const Text( StringConstants.reject, @@ -41,7 +43,8 @@ class WCRequestWidget extends StatelessWidget { width: StyleConstants.linear16, ), CustomButton( - onTap: onAccept ?? () => Navigator.of(context).pop(true), + onTap: onAccept ?? + () => Navigator.of(context).pop(WCBottomSheetResult.one), type: CustomButtonType.valid, child: const Text( StringConstants.approve, diff --git a/example/wallet/lib/widgets/wc_request_widget.dart/wc_session_auth_request_widget.dart b/example/wallet/lib/widgets/wc_request_widget.dart/wc_session_auth_request_widget.dart new file mode 100644 index 00000000..6cd4cbf8 --- /dev/null +++ b/example/wallet/lib/widgets/wc_request_widget.dart/wc_session_auth_request_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:walletconnect_flutter_v2_wallet/dependencies/bottom_sheet/i_bottom_sheet_service.dart'; +import 'package:walletconnect_flutter_v2_wallet/utils/constants.dart'; +import 'package:walletconnect_flutter_v2_wallet/widgets/custom_button.dart'; + +class WCSessionAuthRequestWidget extends StatelessWidget { + const WCSessionAuthRequestWidget({ + super.key, + required this.child, + }); + + final Widget child; + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + child, + const SizedBox(height: StyleConstants.linear16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + CustomButton( + onTap: () => + Navigator.of(context).pop(WCBottomSheetResult.reject), + type: CustomButtonType.invalid, + child: const Text( + 'Cancel', + style: StyleConstants.buttonText, + textAlign: TextAlign.center, + ), + ), + const SizedBox(width: StyleConstants.linear8), + CustomButton( + onTap: () => Navigator.of(context).pop(WCBottomSheetResult.one), + type: CustomButtonType.normal, + child: const Text( + 'Sign One', + style: StyleConstants.buttonText, + textAlign: TextAlign.center, + ), + ), + const SizedBox(width: StyleConstants.linear8), + CustomButton( + onTap: () => Navigator.of(context).pop(WCBottomSheetResult.all), + type: CustomButtonType.valid, + child: const Text( + 'Sign All', + style: StyleConstants.buttonText, + textAlign: TextAlign.center, + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/apis/auth_api/auth_client.dart b/lib/apis/auth_api/auth_client.dart index 1d773cef..3cbfb4ea 100644 --- a/lib/apis/auth_api/auth_client.dart +++ b/lib/apis/auth_api/auth_client.dart @@ -2,16 +2,17 @@ import 'package:event/event.dart'; import 'package:walletconnect_flutter_v2/apis/auth_api/auth_engine.dart'; import 'package:walletconnect_flutter_v2/apis/auth_api/i_auth_client.dart'; import 'package:walletconnect_flutter_v2/apis/auth_api/i_auth_engine.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_events.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_events.dart'; import 'package:walletconnect_flutter_v2/apis/core/core.dart'; import 'package:walletconnect_flutter_v2/apis/core/relay_client/websocket/http_client.dart'; import 'package:walletconnect_flutter_v2/apis/core/relay_client/websocket/i_http_client.dart'; import 'package:walletconnect_flutter_v2/apis/core/store/generic_store.dart'; import 'package:walletconnect_flutter_v2/apis/core/store/i_generic_store.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_models.dart'; import 'package:walletconnect_flutter_v2/apis/core/i_core.dart'; import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; import 'package:walletconnect_flutter_v2/apis/core/pairing/utils/pairing_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/common_auth_models.dart'; import 'package:walletconnect_flutter_v2/apis/utils/constants.dart'; import 'package:walletconnect_flutter_v2/apis/utils/log_level.dart'; @@ -126,7 +127,7 @@ class AuthClient implements IAuthClient { Future request({ required AuthRequestParams params, String? pairingTopic, - List>? methods = AuthEngine.defaultMethods, + List>? methods = AuthEngine.DEFAULT_METHODS, }) async { try { return engine.requestAuth( diff --git a/lib/apis/auth_api/auth_engine.dart b/lib/apis/auth_api/auth_engine.dart index c9eba970..926fb952 100644 --- a/lib/apis/auth_api/auth_engine.dart +++ b/lib/apis/auth_api/auth_engine.dart @@ -2,14 +2,15 @@ import 'dart:async'; import 'package:event/event.dart'; import 'package:walletconnect_flutter_v2/apis/auth_api/i_auth_engine.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_events.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_models.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/json_rpc_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_events.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/common_auth_models.dart'; import 'package:walletconnect_flutter_v2/apis/core/store/i_generic_store.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/utils/address_utils.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/utils/auth_api_validators.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/utils/auth_constants.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/utils/auth_signature.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/json_rpc_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/utils/auth/address_utils.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/utils/auth/auth_api_validators.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/utils/auth/auth_constants.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/utils/auth/auth_signature.dart'; import 'package:walletconnect_flutter_v2/apis/core/crypto/crypto_models.dart'; import 'package:walletconnect_flutter_v2/apis/core/i_core.dart'; import 'package:walletconnect_flutter_v2/apis/core/pairing/utils/pairing_models.dart'; @@ -22,7 +23,7 @@ import 'package:walletconnect_flutter_v2/apis/utils/errors.dart'; import 'package:walletconnect_flutter_v2/apis/utils/method_constants.dart'; class AuthEngine implements IAuthEngine { - static const List> defaultMethods = [ + static const List> DEFAULT_METHODS = [ [ MethodConstants.WC_AUTH_REQUEST, ] @@ -80,7 +81,7 @@ class AuthEngine implements IAuthEngine { Future requestAuth({ required AuthRequestParams params, String? pairingTopic, - List>? methods = defaultMethods, + List>? methods = DEFAULT_METHODS, }) async { _checkInitialized(); diff --git a/lib/apis/auth_api/i_auth_engine_app.dart b/lib/apis/auth_api/i_auth_engine_app.dart index 925a49b6..c1aae64c 100644 --- a/lib/apis/auth_api/i_auth_engine_app.dart +++ b/lib/apis/auth_api/i_auth_engine_app.dart @@ -1,12 +1,11 @@ import 'package:event/event.dart'; import 'package:walletconnect_flutter_v2/apis/auth_api/i_auth_engine_common.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_events.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_events.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_models.dart'; abstract class IAuthEngineApp extends IAuthEngineCommon { abstract final Event onAuthResponse; - // request wallet authentication Future requestAuth({ required AuthRequestParams params, String? pairingTopic, diff --git a/lib/apis/auth_api/i_auth_engine_common.dart b/lib/apis/auth_api/i_auth_engine_common.dart index d51c4690..016b7b2f 100644 --- a/lib/apis/auth_api/i_auth_engine_common.dart +++ b/lib/apis/auth_api/i_auth_engine_common.dart @@ -1,4 +1,4 @@ -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/common_auth_models.dart'; import 'package:walletconnect_flutter_v2/apis/core/store/i_generic_store.dart'; import 'package:walletconnect_flutter_v2/apis/core/i_core.dart'; import 'package:walletconnect_flutter_v2/apis/core/pairing/utils/pairing_models.dart'; diff --git a/lib/apis/auth_api/i_auth_engine_wallet.dart b/lib/apis/auth_api/i_auth_engine_wallet.dart index 323aa30c..91a2cee2 100644 --- a/lib/apis/auth_api/i_auth_engine_wallet.dart +++ b/lib/apis/auth_api/i_auth_engine_wallet.dart @@ -1,7 +1,8 @@ import 'package:event/event.dart'; import 'package:walletconnect_flutter_v2/apis/auth_api/i_auth_engine_common.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_events.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_events.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/common_auth_models.dart'; import 'package:walletconnect_flutter_v2/apis/core/store/i_generic_store.dart'; import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; diff --git a/lib/apis/auth_api/models/auth_client_events.dart b/lib/apis/auth_api/models/auth_client_events.dart index aa6f0b67..29ae6bce 100644 --- a/lib/apis/auth_api/models/auth_client_events.dart +++ b/lib/apis/auth_api/models/auth_client_events.dart @@ -1,44 +1,44 @@ -import 'package:event/event.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_models.dart'; -import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; -import 'package:walletconnect_flutter_v2/apis/models/json_rpc_error.dart'; +// import 'package:event/event.dart'; +// import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_models.dart'; +// import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; +// import 'package:walletconnect_flutter_v2/apis/models/json_rpc_error.dart'; -class AuthRequest extends EventArgs { - final int id; - final String topic; - final AuthPayloadParams payloadParams; - final ConnectionMetadata requester; +// class AuthRequest extends EventArgs { +// final int id; +// final String topic; +// final AuthPayloadParams payloadParams; +// final ConnectionMetadata requester; - AuthRequest({ - required this.id, - required this.topic, - required this.payloadParams, - required this.requester, - }); +// AuthRequest({ +// required this.id, +// required this.topic, +// required this.payloadParams, +// required this.requester, +// }); - @override - String toString() { - return 'AuthRequest(id: $id, topic: $topic, payloadParams: $payloadParams, requester: $requester)'; - } -} +// @override +// String toString() { +// return 'AuthRequest(id: $id, topic: $topic, payloadParams: $payloadParams, requester: $requester)'; +// } +// } -class AuthResponse extends EventArgs { - final int id; - final String topic; - final Cacao? result; - final WalletConnectError? error; - final JsonRpcError? jsonRpcError; +// class AuthResponse extends EventArgs { +// final int id; +// final String topic; +// final Cacao? result; +// final WalletConnectError? error; +// final JsonRpcError? jsonRpcError; - AuthResponse({ - required this.id, - required this.topic, - this.result, - this.error, - this.jsonRpcError, - }); +// AuthResponse({ +// required this.id, +// required this.topic, +// this.result, +// this.error, +// this.jsonRpcError, +// }); - @override - String toString() { - return 'AuthResponse(id: $id, topic: $topic, result: $result, error: $error, jsonRpcError: $jsonRpcError)'; - } -} +// @override +// String toString() { +// return 'AuthResponse(id: $id, topic: $topic, result: $result, error: $error, jsonRpcError: $jsonRpcError)'; +// } +// } diff --git a/lib/apis/auth_api/models/auth_client_models.dart b/lib/apis/auth_api/models/auth_client_models.dart index 20fc75e1..94e751cf 100644 --- a/lib/apis/auth_api/models/auth_client_models.dart +++ b/lib/apis/auth_api/models/auth_client_models.dart @@ -1,312 +1,326 @@ -import 'dart:async'; - -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_events.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/utils/auth_utils.dart'; -import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; - -part 'auth_client_models.g.dart'; -part 'auth_client_models.freezed.dart'; - -class AuthRequestResponse { - final int id; - final String pairingTopic; - final Completer completer; - final Uri? uri; - - AuthRequestResponse({ - required this.id, - required this.pairingTopic, - required this.completer, - this.uri, - }); -} - -@freezed -class AuthPublicKey with _$AuthPublicKey { - @JsonSerializable(includeIfNull: false) - const factory AuthPublicKey({ - required String publicKey, - }) = _AuthPublicKey; - - factory AuthPublicKey.fromJson(Map json) => - _$AuthPublicKeyFromJson(json); -} - -class AuthRequestParams { - /// The Chain ID. - /// Examples: eip155:1 (Eth Mainnet), eip155:43114 (Avalanche) - final String chainId; - - /// The complete URL you are logging into. - /// Example: https://example.com/login - final String aud; - - /// The domain you are logging in to. - /// Example: example.com - /// Domain must exist within the aud, or validation will fail - final String domain; - final String nonce; - final String? type; - final String? nbf; - final String? exp; - final String? statement; - final String? requestId; - final List? resources; - final int? expiry; - - AuthRequestParams({ - required this.chainId, - required this.domain, - required this.aud, - String? nonce, - this.type = CacaoHeader.EIP4361, - this.nbf, - this.exp, - this.statement, - this.requestId, - this.resources, - this.expiry, - }) : nonce = nonce ?? AuthUtils.generateNonce(); -} - -@freezed -class AuthPayloadParams with _$AuthPayloadParams { - @JsonSerializable(includeIfNull: false) - const factory AuthPayloadParams({ - required String type, - required String chainId, - required String domain, - required String aud, - required String version, - required String nonce, - required String iat, - String? nbf, - String? exp, - String? statement, - String? requestId, - List? resources, - }) = _AuthPayloadParams; - - factory AuthPayloadParams.fromRequestParams(AuthRequestParams params) { - return AuthPayloadParams( - type: params.type ?? CacaoHeader.EIP4361, - chainId: params.chainId, - domain: params.domain, - aud: params.aud, - version: '1', - nonce: params.nonce, - iat: DateTime.now().toIso8601String(), - nbf: params.nbf, - exp: params.exp, - statement: params.statement, - requestId: params.requestId, - resources: params.resources, - ); - } - - factory AuthPayloadParams.fromJson(Map json) => - _$AuthPayloadParamsFromJson(json); -} - -@freezed -class CacaoRequestPayload with _$CacaoRequestPayload { - @JsonSerializable(includeIfNull: false) - const factory CacaoRequestPayload({ - required String domain, - required String aud, - required String version, - required String nonce, - required String iat, - String? nbf, - String? exp, - String? statement, - String? requestId, - List? resources, - }) = _CacaoRequestPayload; - - factory CacaoRequestPayload.fromPayloadParams(AuthPayloadParams params) { - return CacaoRequestPayload( - domain: params.domain, - aud: params.aud, - version: params.version, - nonce: params.nonce, - iat: params.iat, - nbf: params.nbf, - exp: params.exp, - statement: params.statement, - requestId: params.requestId, - resources: params.resources, - ); - } - - factory CacaoRequestPayload.fromCacaoPayload(CacaoPayload payload) { - return CacaoRequestPayload( - domain: payload.domain, - aud: payload.aud, - version: payload.version, - nonce: payload.nonce, - iat: payload.iat, - nbf: payload.nbf, - exp: payload.exp, - statement: payload.statement, - requestId: payload.requestId, - resources: payload.resources, - ); - } - - factory CacaoRequestPayload.fromJson(Map json) => - _$CacaoRequestPayloadFromJson(json); -} - -@freezed -class CacaoPayload with _$CacaoPayload { - @JsonSerializable(includeIfNull: false) - const factory CacaoPayload({ - required String iss, - required String domain, - required String aud, - required String version, - required String nonce, - required String iat, - String? nbf, - String? exp, - String? statement, - String? requestId, - List? resources, - }) = _CacaoPayload; - - factory CacaoPayload.fromRequestPayload({ - required String issuer, - required CacaoRequestPayload payload, - }) { - return CacaoPayload( - iss: issuer, - domain: payload.domain, - aud: payload.aud, - version: payload.version, - nonce: payload.nonce, - iat: payload.iat, - nbf: payload.nbf, - exp: payload.exp, - statement: payload.statement, - requestId: payload.requestId, - resources: payload.resources, - ); - } - - factory CacaoPayload.fromJson(Map json) => - _$CacaoPayloadFromJson(json); -} - -@freezed -class CacaoHeader with _$CacaoHeader { - static const EIP4361 = 'eip4361'; - - @JsonSerializable(includeIfNull: false) - const factory CacaoHeader({ - @Default('eip4361') String t, - }) = _CacaoHeader; - - factory CacaoHeader.fromJson(Map json) => - _$CacaoHeaderFromJson(json); -} - -@freezed -class CacaoSignature with _$CacaoSignature { - static const EIP191 = 'eip191'; - static const EIP1271 = 'eip1271'; - - @JsonSerializable(includeIfNull: false) - const factory CacaoSignature({ - required String t, - required String s, - String? m, - }) = _CacaoSignature; - - factory CacaoSignature.fromJson(Map json) => - _$CacaoSignatureFromJson(json); -} - -@freezed -class Cacao with _$Cacao { - @JsonSerializable(includeIfNull: false) - const factory Cacao({ - required CacaoHeader h, - required CacaoPayload p, - required CacaoSignature s, - }) = _Cacao; - - factory Cacao.fromJson(Map json) => _$CacaoFromJson(json); -} - -@freezed -class StoredCacao with _$StoredCacao { - @JsonSerializable(includeIfNull: false) - const factory StoredCacao({ - required int id, - required String pairingTopic, - required CacaoHeader h, - required CacaoPayload p, - required CacaoSignature s, - }) = _StoredCacao; - - factory StoredCacao.fromCacao({ - required int id, - required String pairingTopic, - required Cacao cacao, - }) { - return StoredCacao( - id: id, - pairingTopic: pairingTopic, - h: cacao.h, - p: cacao.p, - s: cacao.s, - ); - } - - factory StoredCacao.fromJson(Map json) => - _$StoredCacaoFromJson(json); -} - -@freezed -class PendingAuthRequest with _$PendingAuthRequest { - @JsonSerializable(includeIfNull: false) - const factory PendingAuthRequest({ - required int id, - required String pairingTopic, - required ConnectionMetadata metadata, - required CacaoRequestPayload cacaoPayload, - }) = _PendingAuthRequest; - - factory PendingAuthRequest.fromJson(Map json) => - _$PendingAuthRequestFromJson(json); -} - -class AuthRequestCompleter { - final int id; - final String pairingTopic; - final String responseTopic; - final PendingAuthRequest request; - final Completer completer; - - AuthRequestCompleter({ - required this.id, - required this.pairingTopic, - required this.responseTopic, - required this.request, - required this.completer, - }); -} - -class RespondParams { - final int id; - final CacaoSignature? signature; - final WalletConnectError? error; - - RespondParams({ - required this.id, - this.signature, - this.error, - }); -} +// import 'dart:async'; + +// import 'package:freezed_annotation/freezed_annotation.dart'; +// import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_events.dart'; +// import 'package:walletconnect_flutter_v2/apis/auth_api/utils/auth_utils.dart'; +// import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; + +// part 'auth_client_models.g.dart'; +// part 'auth_client_models.freezed.dart'; + +// class AuthRequestResponse { +// final int id; +// final String pairingTopic; +// final Completer completer; +// final Uri? uri; + +// AuthRequestResponse({ +// required this.id, +// required this.pairingTopic, +// required this.completer, +// this.uri, +// }); +// } + +// @freezed +// class AuthPublicKey with _$AuthPublicKey { +// @JsonSerializable(includeIfNull: false) +// const factory AuthPublicKey({ +// required String publicKey, +// }) = _AuthPublicKey; + +// factory AuthPublicKey.fromJson(Map json) => +// _$AuthPublicKeyFromJson(json); +// } + +// class AuthRequestParams { +// /// The Chain ID. +// /// Examples: eip155:1 (Eth Mainnet), eip155:43114 (Avalanche) +// final String chainId; + +// /// The complete URL you are logging into. +// /// Example: https://example.com/login +// final String aud; + +// /// The domain you are logging in to. +// /// Example: example.com +// /// Domain must exist within the aud, or validation will fail +// final String domain; +// final String nonce; +// final String? type; +// final String? nbf; +// final String? exp; +// final String? statement; +// final String? requestId; +// final List? resources; +// final int? expiry; + +// AuthRequestParams({ +// required this.chainId, +// required this.domain, +// required this.aud, +// String? nonce, +// this.type = CacaoHeader.EIP4361, +// this.nbf, +// this.exp, +// this.statement, +// this.requestId, +// this.resources, +// this.expiry, +// }) : nonce = nonce ?? AuthUtils.generateNonce(); + +// Map toJson() => { +// 'chainId': chainId, +// 'aud': aud, +// 'domain': domain, +// 'nonce': nonce, +// if (type != null) 'type': type, +// if (nbf != null) 'nbf': nbf, +// if (exp != null) 'exp': exp, +// if (statement != null) 'statement': statement, +// if (requestId != null) 'requestId': requestId, +// if (resources != null) 'resources': resources, +// if (expiry != null) 'expiry': expiry, +// }; +// } + +// @freezed +// class AuthPayloadParams with _$AuthPayloadParams { +// @JsonSerializable(includeIfNull: false) +// const factory AuthPayloadParams({ +// required String type, +// required String chainId, +// required String domain, +// required String aud, +// required String version, +// required String nonce, +// required String iat, +// String? nbf, +// String? exp, +// String? statement, +// String? requestId, +// List? resources, +// }) = _AuthPayloadParams; + +// factory AuthPayloadParams.fromRequestParams(AuthRequestParams params) { +// return AuthPayloadParams( +// type: params.type ?? CacaoHeader.EIP4361, +// chainId: params.chainId, +// domain: params.domain, +// aud: params.aud, +// version: '1', +// nonce: params.nonce, +// iat: DateTime.now().toIso8601String(), +// nbf: params.nbf, +// exp: params.exp, +// statement: params.statement, +// requestId: params.requestId, +// resources: params.resources, +// ); +// } + +// factory AuthPayloadParams.fromJson(Map json) => +// _$AuthPayloadParamsFromJson(json); +// } + +// @freezed +// class CacaoRequestPayload with _$CacaoRequestPayload { +// @JsonSerializable(includeIfNull: false) +// const factory CacaoRequestPayload({ +// required String domain, +// required String aud, +// required String version, +// required String nonce, +// required String iat, +// String? nbf, +// String? exp, +// String? statement, +// String? requestId, +// List? resources, +// }) = _CacaoRequestPayload; + +// factory CacaoRequestPayload.fromPayloadParams(AuthPayloadParams params) { +// return CacaoRequestPayload( +// domain: params.domain, +// aud: params.aud, +// version: params.version, +// nonce: params.nonce, +// iat: params.iat, +// nbf: params.nbf, +// exp: params.exp, +// statement: params.statement, +// requestId: params.requestId, +// resources: params.resources, +// ); +// } + +// factory CacaoRequestPayload.fromCacaoPayload(CacaoPayload payload) { +// return CacaoRequestPayload( +// domain: payload.domain, +// aud: payload.aud, +// version: payload.version, +// nonce: payload.nonce, +// iat: payload.iat, +// nbf: payload.nbf, +// exp: payload.exp, +// statement: payload.statement, +// requestId: payload.requestId, +// resources: payload.resources, +// ); +// } + +// factory CacaoRequestPayload.fromJson(Map json) => +// _$CacaoRequestPayloadFromJson(json); +// } + +// @freezed +// class CacaoPayload with _$CacaoPayload { +// @JsonSerializable(includeIfNull: false) +// const factory CacaoPayload({ +// required String iss, +// required String domain, +// required String aud, +// required String version, +// required String nonce, +// required String iat, +// String? nbf, +// String? exp, +// String? statement, +// String? requestId, +// List? resources, +// }) = _CacaoPayload; + +// factory CacaoPayload.fromRequestPayload({ +// required String issuer, +// required CacaoRequestPayload payload, +// }) { +// return CacaoPayload( +// iss: issuer, +// domain: payload.domain, +// aud: payload.aud, +// version: payload.version, +// nonce: payload.nonce, +// iat: payload.iat, +// nbf: payload.nbf, +// exp: payload.exp, +// statement: payload.statement, +// requestId: payload.requestId, +// resources: payload.resources, +// ); +// } + +// factory CacaoPayload.fromJson(Map json) => +// _$CacaoPayloadFromJson(json); +// } + +// @freezed +// class CacaoHeader with _$CacaoHeader { +// static const EIP4361 = 'eip4361'; + +// @JsonSerializable(includeIfNull: false) +// const factory CacaoHeader({ +// @Default('eip4361') String t, +// }) = _CacaoHeader; + +// factory CacaoHeader.fromJson(Map json) => +// _$CacaoHeaderFromJson(json); +// } + +// @freezed +// class CacaoSignature with _$CacaoSignature { +// static const EIP191 = 'eip191'; +// static const EIP1271 = 'eip1271'; + +// @JsonSerializable(includeIfNull: false) +// const factory CacaoSignature({ +// required String t, +// required String s, +// String? m, +// }) = _CacaoSignature; + +// factory CacaoSignature.fromJson(Map json) => +// _$CacaoSignatureFromJson(json); +// } + +// @freezed +// class Cacao with _$Cacao { +// @JsonSerializable(includeIfNull: false) +// const factory Cacao({ +// required CacaoHeader h, +// required CacaoPayload p, +// required CacaoSignature s, +// }) = _Cacao; + +// factory Cacao.fromJson(Map json) => _$CacaoFromJson(json); +// } + +// @freezed +// class StoredCacao with _$StoredCacao { +// @JsonSerializable(includeIfNull: false) +// const factory StoredCacao({ +// required int id, +// required String pairingTopic, +// required CacaoHeader h, +// required CacaoPayload p, +// required CacaoSignature s, +// }) = _StoredCacao; + +// factory StoredCacao.fromCacao({ +// required int id, +// required String pairingTopic, +// required Cacao cacao, +// }) { +// return StoredCacao( +// id: id, +// pairingTopic: pairingTopic, +// h: cacao.h, +// p: cacao.p, +// s: cacao.s, +// ); +// } + +// factory StoredCacao.fromJson(Map json) => +// _$StoredCacaoFromJson(json); +// } + +// @freezed +// class PendingAuthRequest with _$PendingAuthRequest { +// @JsonSerializable(includeIfNull: false) +// const factory PendingAuthRequest({ +// required int id, +// required String pairingTopic, +// required ConnectionMetadata metadata, +// required CacaoRequestPayload cacaoPayload, +// }) = _PendingAuthRequest; + +// factory PendingAuthRequest.fromJson(Map json) => +// _$PendingAuthRequestFromJson(json); +// } + +// class AuthRequestCompleter { +// final int id; +// final String pairingTopic; +// final String responseTopic; +// final PendingAuthRequest request; +// final Completer completer; + +// AuthRequestCompleter({ +// required this.id, +// required this.pairingTopic, +// required this.responseTopic, +// required this.request, +// required this.completer, +// }); +// } + +// class RespondParams { +// final int id; +// final CacaoSignature? signature; +// final WalletConnectError? error; + +// RespondParams({ +// required this.id, +// this.signature, +// this.error, +// }); +// } diff --git a/lib/apis/auth_api/models/json_rpc_models.dart b/lib/apis/auth_api/models/json_rpc_models.dart index 4ca5e008..2b86511f 100644 --- a/lib/apis/auth_api/models/json_rpc_models.dart +++ b/lib/apis/auth_api/models/json_rpc_models.dart @@ -1,29 +1,29 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_models.dart'; -import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; +// import 'package:freezed_annotation/freezed_annotation.dart'; +// import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_models.dart'; +// import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; -part 'json_rpc_models.g.dart'; -part 'json_rpc_models.freezed.dart'; +// part 'json_rpc_models.g.dart'; +// part 'json_rpc_models.freezed.dart'; -@freezed -class WcAuthRequestRequest with _$WcAuthRequestRequest { - @JsonSerializable() - const factory WcAuthRequestRequest({ - required AuthPayloadParams payloadParams, - required ConnectionMetadata requester, - }) = _WcAuthRequestRequest; +// @freezed +// class WcAuthRequestRequest with _$WcAuthRequestRequest { +// @JsonSerializable() +// const factory WcAuthRequestRequest({ +// required AuthPayloadParams payloadParams, +// required ConnectionMetadata requester, +// }) = _WcAuthRequestRequest; - factory WcAuthRequestRequest.fromJson(Map json) => - _$WcAuthRequestRequestFromJson(json); -} +// factory WcAuthRequestRequest.fromJson(Map json) => +// _$WcAuthRequestRequestFromJson(json); +// } -@freezed -class WcAuthRequestResult with _$WcAuthRequestResult { - @JsonSerializable() - const factory WcAuthRequestResult({ - required Cacao cacao, - }) = _WcAuthRequestResult; +// @freezed +// class WcAuthRequestResult with _$WcAuthRequestResult { +// @JsonSerializable() +// const factory WcAuthRequestResult({ +// required Cacao cacao, +// }) = _WcAuthRequestResult; - factory WcAuthRequestResult.fromJson(Map json) => - _$WcAuthRequestResultFromJson(json); -} +// factory WcAuthRequestResult.fromJson(Map json) => +// _$WcAuthRequestResultFromJson(json); +// } diff --git a/lib/apis/auth_api/models/json_rpc_models.freezed.dart b/lib/apis/auth_api/models/json_rpc_models.freezed.dart deleted file mode 100644 index c78feec1..00000000 --- a/lib/apis/auth_api/models/json_rpc_models.freezed.dart +++ /dev/null @@ -1,353 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'json_rpc_models.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); - -WcAuthRequestRequest _$WcAuthRequestRequestFromJson(Map json) { - return _WcAuthRequestRequest.fromJson(json); -} - -/// @nodoc -mixin _$WcAuthRequestRequest { - AuthPayloadParams get payloadParams => throw _privateConstructorUsedError; - ConnectionMetadata get requester => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $WcAuthRequestRequestCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $WcAuthRequestRequestCopyWith<$Res> { - factory $WcAuthRequestRequestCopyWith(WcAuthRequestRequest value, - $Res Function(WcAuthRequestRequest) then) = - _$WcAuthRequestRequestCopyWithImpl<$Res, WcAuthRequestRequest>; - @useResult - $Res call({AuthPayloadParams payloadParams, ConnectionMetadata requester}); - - $AuthPayloadParamsCopyWith<$Res> get payloadParams; - $ConnectionMetadataCopyWith<$Res> get requester; -} - -/// @nodoc -class _$WcAuthRequestRequestCopyWithImpl<$Res, - $Val extends WcAuthRequestRequest> - implements $WcAuthRequestRequestCopyWith<$Res> { - _$WcAuthRequestRequestCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? payloadParams = null, - Object? requester = null, - }) { - return _then(_value.copyWith( - payloadParams: null == payloadParams - ? _value.payloadParams - : payloadParams // ignore: cast_nullable_to_non_nullable - as AuthPayloadParams, - requester: null == requester - ? _value.requester - : requester // ignore: cast_nullable_to_non_nullable - as ConnectionMetadata, - ) as $Val); - } - - @override - @pragma('vm:prefer-inline') - $AuthPayloadParamsCopyWith<$Res> get payloadParams { - return $AuthPayloadParamsCopyWith<$Res>(_value.payloadParams, (value) { - return _then(_value.copyWith(payloadParams: value) as $Val); - }); - } - - @override - @pragma('vm:prefer-inline') - $ConnectionMetadataCopyWith<$Res> get requester { - return $ConnectionMetadataCopyWith<$Res>(_value.requester, (value) { - return _then(_value.copyWith(requester: value) as $Val); - }); - } -} - -/// @nodoc -abstract class _$$WcAuthRequestRequestImplCopyWith<$Res> - implements $WcAuthRequestRequestCopyWith<$Res> { - factory _$$WcAuthRequestRequestImplCopyWith(_$WcAuthRequestRequestImpl value, - $Res Function(_$WcAuthRequestRequestImpl) then) = - __$$WcAuthRequestRequestImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({AuthPayloadParams payloadParams, ConnectionMetadata requester}); - - @override - $AuthPayloadParamsCopyWith<$Res> get payloadParams; - @override - $ConnectionMetadataCopyWith<$Res> get requester; -} - -/// @nodoc -class __$$WcAuthRequestRequestImplCopyWithImpl<$Res> - extends _$WcAuthRequestRequestCopyWithImpl<$Res, _$WcAuthRequestRequestImpl> - implements _$$WcAuthRequestRequestImplCopyWith<$Res> { - __$$WcAuthRequestRequestImplCopyWithImpl(_$WcAuthRequestRequestImpl _value, - $Res Function(_$WcAuthRequestRequestImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? payloadParams = null, - Object? requester = null, - }) { - return _then(_$WcAuthRequestRequestImpl( - payloadParams: null == payloadParams - ? _value.payloadParams - : payloadParams // ignore: cast_nullable_to_non_nullable - as AuthPayloadParams, - requester: null == requester - ? _value.requester - : requester // ignore: cast_nullable_to_non_nullable - as ConnectionMetadata, - )); - } -} - -/// @nodoc - -@JsonSerializable() -class _$WcAuthRequestRequestImpl implements _WcAuthRequestRequest { - const _$WcAuthRequestRequestImpl( - {required this.payloadParams, required this.requester}); - - factory _$WcAuthRequestRequestImpl.fromJson(Map json) => - _$$WcAuthRequestRequestImplFromJson(json); - - @override - final AuthPayloadParams payloadParams; - @override - final ConnectionMetadata requester; - - @override - String toString() { - return 'WcAuthRequestRequest(payloadParams: $payloadParams, requester: $requester)'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$WcAuthRequestRequestImpl && - (identical(other.payloadParams, payloadParams) || - other.payloadParams == payloadParams) && - (identical(other.requester, requester) || - other.requester == requester)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => Object.hash(runtimeType, payloadParams, requester); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$WcAuthRequestRequestImplCopyWith<_$WcAuthRequestRequestImpl> - get copyWith => - __$$WcAuthRequestRequestImplCopyWithImpl<_$WcAuthRequestRequestImpl>( - this, _$identity); - - @override - Map toJson() { - return _$$WcAuthRequestRequestImplToJson( - this, - ); - } -} - -abstract class _WcAuthRequestRequest implements WcAuthRequestRequest { - const factory _WcAuthRequestRequest( - {required final AuthPayloadParams payloadParams, - required final ConnectionMetadata requester}) = - _$WcAuthRequestRequestImpl; - - factory _WcAuthRequestRequest.fromJson(Map json) = - _$WcAuthRequestRequestImpl.fromJson; - - @override - AuthPayloadParams get payloadParams; - @override - ConnectionMetadata get requester; - @override - @JsonKey(ignore: true) - _$$WcAuthRequestRequestImplCopyWith<_$WcAuthRequestRequestImpl> - get copyWith => throw _privateConstructorUsedError; -} - -WcAuthRequestResult _$WcAuthRequestResultFromJson(Map json) { - return _WcAuthRequestResult.fromJson(json); -} - -/// @nodoc -mixin _$WcAuthRequestResult { - Cacao get cacao => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $WcAuthRequestResultCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $WcAuthRequestResultCopyWith<$Res> { - factory $WcAuthRequestResultCopyWith( - WcAuthRequestResult value, $Res Function(WcAuthRequestResult) then) = - _$WcAuthRequestResultCopyWithImpl<$Res, WcAuthRequestResult>; - @useResult - $Res call({Cacao cacao}); - - $CacaoCopyWith<$Res> get cacao; -} - -/// @nodoc -class _$WcAuthRequestResultCopyWithImpl<$Res, $Val extends WcAuthRequestResult> - implements $WcAuthRequestResultCopyWith<$Res> { - _$WcAuthRequestResultCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? cacao = null, - }) { - return _then(_value.copyWith( - cacao: null == cacao - ? _value.cacao - : cacao // ignore: cast_nullable_to_non_nullable - as Cacao, - ) as $Val); - } - - @override - @pragma('vm:prefer-inline') - $CacaoCopyWith<$Res> get cacao { - return $CacaoCopyWith<$Res>(_value.cacao, (value) { - return _then(_value.copyWith(cacao: value) as $Val); - }); - } -} - -/// @nodoc -abstract class _$$WcAuthRequestResultImplCopyWith<$Res> - implements $WcAuthRequestResultCopyWith<$Res> { - factory _$$WcAuthRequestResultImplCopyWith(_$WcAuthRequestResultImpl value, - $Res Function(_$WcAuthRequestResultImpl) then) = - __$$WcAuthRequestResultImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({Cacao cacao}); - - @override - $CacaoCopyWith<$Res> get cacao; -} - -/// @nodoc -class __$$WcAuthRequestResultImplCopyWithImpl<$Res> - extends _$WcAuthRequestResultCopyWithImpl<$Res, _$WcAuthRequestResultImpl> - implements _$$WcAuthRequestResultImplCopyWith<$Res> { - __$$WcAuthRequestResultImplCopyWithImpl(_$WcAuthRequestResultImpl _value, - $Res Function(_$WcAuthRequestResultImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? cacao = null, - }) { - return _then(_$WcAuthRequestResultImpl( - cacao: null == cacao - ? _value.cacao - : cacao // ignore: cast_nullable_to_non_nullable - as Cacao, - )); - } -} - -/// @nodoc - -@JsonSerializable() -class _$WcAuthRequestResultImpl implements _WcAuthRequestResult { - const _$WcAuthRequestResultImpl({required this.cacao}); - - factory _$WcAuthRequestResultImpl.fromJson(Map json) => - _$$WcAuthRequestResultImplFromJson(json); - - @override - final Cacao cacao; - - @override - String toString() { - return 'WcAuthRequestResult(cacao: $cacao)'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$WcAuthRequestResultImpl && - (identical(other.cacao, cacao) || other.cacao == cacao)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => Object.hash(runtimeType, cacao); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$WcAuthRequestResultImplCopyWith<_$WcAuthRequestResultImpl> get copyWith => - __$$WcAuthRequestResultImplCopyWithImpl<_$WcAuthRequestResultImpl>( - this, _$identity); - - @override - Map toJson() { - return _$$WcAuthRequestResultImplToJson( - this, - ); - } -} - -abstract class _WcAuthRequestResult implements WcAuthRequestResult { - const factory _WcAuthRequestResult({required final Cacao cacao}) = - _$WcAuthRequestResultImpl; - - factory _WcAuthRequestResult.fromJson(Map json) = - _$WcAuthRequestResultImpl.fromJson; - - @override - Cacao get cacao; - @override - @JsonKey(ignore: true) - _$$WcAuthRequestResultImplCopyWith<_$WcAuthRequestResultImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/apis/auth_api/models/json_rpc_models.g.dart b/lib/apis/auth_api/models/json_rpc_models.g.dart deleted file mode 100644 index a7bde781..00000000 --- a/lib/apis/auth_api/models/json_rpc_models.g.dart +++ /dev/null @@ -1,35 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'json_rpc_models.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_$WcAuthRequestRequestImpl _$$WcAuthRequestRequestImplFromJson( - Map json) => - _$WcAuthRequestRequestImpl( - payloadParams: AuthPayloadParams.fromJson( - json['payloadParams'] as Map), - requester: ConnectionMetadata.fromJson( - json['requester'] as Map), - ); - -Map _$$WcAuthRequestRequestImplToJson( - _$WcAuthRequestRequestImpl instance) => - { - 'payloadParams': instance.payloadParams.toJson(), - 'requester': instance.requester.toJson(), - }; - -_$WcAuthRequestResultImpl _$$WcAuthRequestResultImplFromJson( - Map json) => - _$WcAuthRequestResultImpl( - cacao: Cacao.fromJson(json['cacao'] as Map), - ); - -Map _$$WcAuthRequestResultImplToJson( - _$WcAuthRequestResultImpl instance) => - { - 'cacao': instance.cacao.toJson(), - }; diff --git a/lib/apis/auth_api/utils/address_utils.dart b/lib/apis/auth_api/utils/address_utils.dart index 77acd45e..2126c1f0 100644 --- a/lib/apis/auth_api/utils/address_utils.dart +++ b/lib/apis/auth_api/utils/address_utils.dart @@ -1,13 +1,13 @@ -class AddressUtils { - static String getDidAddress(String iss) { - return iss.split(':').last; - } +// class AddressUtils { +// static String getDidAddress(String iss) { +// return iss.split(':').last; +// } - static String getDidChainId(String iss) { - return iss.split(':')[3]; - } +// static String getDidChainId(String iss) { +// return iss.split(':')[3]; +// } - static String getNamespaceDidChainId(String iss) { - return iss.substring(iss.indexOf(RegExp(r':')) + 1); - } -} +// static String getNamespaceDidChainId(String iss) { +// return iss.substring(iss.indexOf(RegExp(r':')) + 1); +// } +// } diff --git a/lib/apis/auth_api/utils/auth_api_validators.dart b/lib/apis/auth_api/utils/auth_api_validators.dart index 8d43c28c..3be9009b 100644 --- a/lib/apis/auth_api/utils/auth_api_validators.dart +++ b/lib/apis/auth_api/utils/auth_api_validators.dart @@ -1,78 +1,78 @@ -import 'package:walletconnect_flutter_v2/apis/auth_api/utils/auth_constants.dart'; -import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; +// import 'package:walletconnect_flutter_v2/apis/auth_api/utils/auth_constants.dart'; +// import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; -class AuthApiValidators { - static bool isValidRequestExpiry(int expiry) { - return AuthConstants.AUTH_REQUEST_EXPIRY_MIN <= expiry && - expiry <= AuthConstants.AUTH_REQUEST_EXPIRY_MAX; - } +// class AuthApiValidators { +// static bool isValidRequestExpiry(int expiry) { +// return AuthConstants.AUTH_REQUEST_EXPIRY_MIN <= expiry && +// expiry <= AuthConstants.AUTH_REQUEST_EXPIRY_MAX; +// } - static bool isValidRequest(AuthRequestParams params) { - if (!NamespaceUtils.isValidUrl(params.aud)) { - throw Errors.getInternalError( - Errors.MISSING_OR_INVALID, - context: - 'requestAuth() invalid aud: ${params.aud}. Must be a valid url.', - ); - } - // final validChainId = true; //NamespaceUtils.isValidChainId(params.chainId); +// static bool isValidRequest(AuthRequestParams params) { +// if (!NamespaceUtils.isValidUrl(params.aud)) { +// throw Errors.getInternalError( +// Errors.MISSING_OR_INVALID, +// context: +// 'requestAuth() invalid aud: ${params.aud}. Must be a valid url.', +// ); +// } +// // final validChainId = true; //NamespaceUtils.isValidChainId(params.chainId); - if (!params.aud.contains(params.domain)) { - throw Errors.getInternalError( - Errors.MISSING_OR_INVALID, - context: - 'requestAuth() invalid domain: ${params.domain}. aud must contain domain.', - ); - } +// if (!params.aud.contains(params.domain)) { +// throw Errors.getInternalError( +// Errors.MISSING_OR_INVALID, +// context: +// 'requestAuth() invalid domain: ${params.domain}. aud must contain domain.', +// ); +// } - if (params.nonce.isEmpty) { - throw Errors.getInternalError( - Errors.MISSING_OR_INVALID, - context: 'requestAuth() nonce must be nonempty.', - ); - } +// if (params.nonce.isEmpty) { +// throw Errors.getInternalError( +// Errors.MISSING_OR_INVALID, +// context: 'requestAuth() nonce must be nonempty.', +// ); +// } - // params.type == null || params.type == CacaoHeader.EIP4361 - if (params.type != null && params.type != CacaoHeader.EIP4361) { - throw Errors.getInternalError( - Errors.MISSING_OR_INVALID, - context: 'requestAuth() type must null or ${CacaoHeader.EIP4361}.', - ); - } +// // params.type == null || params.type == CacaoHeader.EIP4361 +// if (params.type != null && params.type != CacaoHeader.EIP4361) { +// throw Errors.getInternalError( +// Errors.MISSING_OR_INVALID, +// context: 'requestAuth() type must null or ${CacaoHeader.EIP4361}.', +// ); +// } - final expiry = params.expiry; - if (expiry != null && !isValidRequestExpiry(expiry)) { - throw Errors.getInternalError( - Errors.MISSING_OR_INVALID, - context: - 'requestAuth() expiry: $expiry. Expiry must be a number (in seconds) between ${AuthConstants.AUTH_REQUEST_EXPIRY_MIN} and ${AuthConstants.AUTH_REQUEST_EXPIRY_MAX}', - ); - } +// final expiry = params.expiry; +// if (expiry != null && !isValidRequestExpiry(expiry)) { +// throw Errors.getInternalError( +// Errors.MISSING_OR_INVALID, +// context: +// 'requestAuth() expiry: $expiry. Expiry must be a number (in seconds) between ${AuthConstants.AUTH_REQUEST_EXPIRY_MIN} and ${AuthConstants.AUTH_REQUEST_EXPIRY_MAX}', +// ); +// } - return true; - } +// return true; +// } - static bool isValidRespond({ - required int id, - required Map pendingRequests, - CacaoSignature? signature, - WalletConnectError? error, - }) { - if (!pendingRequests.containsKey(id)) { - throw Errors.getInternalError( - Errors.MISSING_OR_INVALID, - context: 'respondAuth() invalid id: $id. No pending request found.', - ); - } +// static bool isValidRespond({ +// required int id, +// required Map pendingRequests, +// CacaoSignature? signature, +// WalletConnectError? error, +// }) { +// if (!pendingRequests.containsKey(id)) { +// throw Errors.getInternalError( +// Errors.MISSING_OR_INVALID, +// context: 'respondAuth() invalid id: $id. No pending request found.', +// ); +// } - if (signature == null && error == null) { - throw Errors.getInternalError( - Errors.MISSING_OR_INVALID, - context: - 'respondAuth() invalid response. Must contain either signature or error.', - ); - } +// if (signature == null && error == null) { +// throw Errors.getInternalError( +// Errors.MISSING_OR_INVALID, +// context: +// 'respondAuth() invalid response. Must contain either signature or error.', +// ); +// } - return true; - } -} +// return true; +// } +// } diff --git a/lib/apis/auth_api/utils/auth_constants.dart b/lib/apis/auth_api/utils/auth_constants.dart index 9450479c..a558c25c 100644 --- a/lib/apis/auth_api/utils/auth_constants.dart +++ b/lib/apis/auth_api/utils/auth_constants.dart @@ -1,10 +1,10 @@ -import 'package:walletconnect_flutter_v2/apis/utils/constants.dart'; +// import 'package:walletconnect_flutter_v2/apis/utils/constants.dart'; -class AuthConstants { - static const AUTH_REQUEST_EXPIRY_MIN = WalletConnectConstants.FIVE_MINUTES; - static const AUTH_REQUEST_EXPIRY_MAX = WalletConnectConstants.SEVEN_DAYS; +// class AuthConstants { +// static const AUTH_REQUEST_EXPIRY_MIN = WalletConnectConstants.FIVE_MINUTES; +// static const AUTH_REQUEST_EXPIRY_MAX = WalletConnectConstants.SEVEN_DAYS; - static const AUTH_DEFAULT_URL = 'https://rpc.walletconnect.com/v1'; +// static const AUTH_DEFAULT_URL = 'https://rpc.walletconnect.com/v1'; - static const AUTH_CLIENT_PUBLIC_KEY_NAME = 'PUB_KEY'; -} +// static const AUTH_CLIENT_PUBLIC_KEY_NAME = 'PUB_KEY'; +// } diff --git a/lib/apis/auth_api/utils/auth_signature.dart b/lib/apis/auth_api/utils/auth_signature.dart index fa706de2..93a8adfe 100644 --- a/lib/apis/auth_api/utils/auth_signature.dart +++ b/lib/apis/auth_api/utils/auth_signature.dart @@ -1,188 +1,190 @@ -import 'dart:convert'; -import 'dart:typed_data'; -import 'package:convert/convert.dart'; -import 'package:http/http.dart' as http; - -import 'package:pointycastle/digests/keccak.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_models.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/utils/auth_constants.dart'; -import 'package:walletconnect_flutter_v2/apis/core/pairing/utils/json_rpc_utils.dart'; -import 'package:web3dart/crypto.dart' as crypto; - -class AuthSignature { - static final KeccakDigest keccakDigest = KeccakDigest(256); - static Uint8List keccak256(Uint8List input) { - keccakDigest.reset(); - return keccakDigest.process(input); - } - - static Uint8List hashMessage(String message) { - return keccak256( - Uint8List.fromList( - utf8.encode( - [ - '\x19Ethereum Signed Message:\n', - message.length.toString(), - message, - ].join(), - ), - ), - ); - } - - static int getNormalizedV(int v) { - if (v == 0 || v == 27) { - return 27; - } - if (v == 1 || v == 28) { - return 28; - } - return v & 1 == 1 ? 27 : 28; - } - - static bool isValidEip191Signature( - String address, - String message, - String sig, - ) { - // Get the sig bytes - // print(sig); - final sigBytes = Uint8List.fromList( - hex.decode(sig.substring(2)), - ); - - // If the sig bytes aren't 65 bytes long, throw an error - if (sigBytes.length != 65) { - throw Exception('Invalid signature length'); - } - - // Get the r and s values from the sig bytes - final r = BigInt.parse( - hex.encode(sigBytes.sublist(0, 32)), - radix: 16, - ); - final s = BigInt.parse( - hex.encode(sigBytes.sublist(32, 64)), - radix: 16, - ); - // print(sigBytes[64]); - final v = getNormalizedV(sigBytes[64]); - // print(r); - // print(s); - // print(v); - - // // Recover the public key from the signature - // Uint8List? publicKeyBytes = AuthSecp256k1.recoverPublicKeyFromSignature( - // v - 27, - // r, - // s, - // hashMessage(message), - // ); - - // // If the public key is null, return false - // if (publicKeyBytes == null) { - // print('Could not derive publicKey'); - // return false; - // } - - // Convert the public key to an address - final publicKeyBytes = crypto.ecRecover( - hashMessage(message), - crypto.MsgSignature(r, s, v), - ); - // print(hex.encode(publicKeyBytes)); - final hashedPubKeyBytes = keccak256(publicKeyBytes); - final addressBytes = hashedPubKeyBytes.sublist(12, 32); - final recoveredAddress = '0x${hex.encode(addressBytes)}'; - - // final String recoveredAddress = EthSigUtil.recoverSignature( - // signature: sig, - // message: hashMessage(message), - // // Uint8List.fromList( - // // ascii.encode(message), - // // ), - // ); - - // print(recoveredAddress.toLowerCase()); - // print(address.toLowerCase()); - - return recoveredAddress.toLowerCase() == address.toLowerCase(); - } - - static Future isValidEip1271Signature( - String address, - String reconstructedMessage, - String cacaoSignature, - String chainId, - String projectId, - ) async { - try { - const String eip1271MagicValue = '0x1626ba7e'; - const String dynamicTypeOffset = - '0000000000000000000000000000000000000000000000000000000000000040'; - const String dynamicTypeLength = - '0000000000000000000000000000000000000000000000000000000000000041'; - final String nonPrefixedSignature = cacaoSignature.substring(2); - final String nonPrefixedHashedMessage = - hex.encode(hashMessage(reconstructedMessage)).substring(2); - - final String data = eip1271MagicValue + - nonPrefixedHashedMessage + - dynamicTypeOffset + - dynamicTypeLength + - nonPrefixedSignature; - - final Uri url = Uri.parse( - '${AuthConstants.AUTH_DEFAULT_URL}/?chainId=$chainId&projectId=$projectId', - ); - final Map body = JsonRpcUtils.formatJsonRpcRequest( - 'eth_call', - { - 'to': address, - 'data': data, - }, - ); - - final http.Response response = await http.post( - url, - body: body, - ); - - // print(response.body); - // final jsonBody = jsonDecode(response.body); - final String recoveredValue = - response.body.substring(0, eip1271MagicValue.length); - return recoveredValue.toLowerCase() == eip1271MagicValue.toLowerCase(); - } catch (e) { - return false; - } - } - - static Future verifySignature( - String address, - String reconstructedMessage, - CacaoSignature cacaoSignature, - String chainId, - String projectId, - ) async { - if (cacaoSignature.t == 'eip191') { - return isValidEip191Signature( - address, - reconstructedMessage, - cacaoSignature.s, - ); - } else if (cacaoSignature.t == 'eip1271') { - return await isValidEip1271Signature( - address, - reconstructedMessage, - cacaoSignature.s, - chainId, - projectId, - ); - } else { - throw Exception( - 'verifySignature failed: Attempted to verify CacaoSignature with unknown type: ${cacaoSignature.t}', - ); - } - } -} +// import 'dart:convert'; +// import 'dart:typed_data'; +// import 'package:convert/convert.dart'; +// import 'package:http/http.dart' as http; + +// import 'package:pointycastle/digests/keccak.dart'; +// import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_models.dart'; +// import 'package:walletconnect_flutter_v2/apis/auth_api/utils/auth_constants.dart'; +// import 'package:walletconnect_flutter_v2/apis/core/pairing/utils/json_rpc_utils.dart'; +// import 'package:web3dart/crypto.dart' as crypto; + +// class AuthSignature { +// static final KeccakDigest keccakDigest = KeccakDigest(256); +// static Uint8List keccak256(Uint8List input) { +// keccakDigest.reset(); +// return keccakDigest.process(input); +// } + +// static Uint8List hashMessage(String message) { +// return keccak256( +// Uint8List.fromList( +// utf8.encode( +// [ +// '\x19Ethereum Signed Message:\n', +// message.length.toString(), +// message, +// ].join(), +// ), +// ), +// ); +// } + +// static int getNormalizedV(int v) { +// if (v == 0 || v == 27) { +// return 27; +// } +// if (v == 1 || v == 28) { +// return 28; +// } +// return v & 1 == 1 ? 27 : 28; +// } + +// static bool isValidEip191Signature( +// String address, +// String message, +// String sig, +// ) { +// // Get the sig bytes +// // print(sig); +// final sigBytes = Uint8List.fromList( +// hex.decode(sig.substring(2)), +// ); + +// // If the sig bytes aren't 65 bytes long, throw an error +// if (sigBytes.length != 65) { +// throw Exception('Invalid signature length'); +// } + +// // Get the r and s values from the sig bytes +// final r = BigInt.parse( +// hex.encode(sigBytes.sublist(0, 32)), +// radix: 16, +// ); +// final s = BigInt.parse( +// hex.encode(sigBytes.sublist(32, 64)), +// radix: 16, +// ); +// // print(sigBytes[64]); +// final v = getNormalizedV(sigBytes[64]); +// // print(r); +// // print(s); +// // print(v); + +// // // Recover the public key from the signature +// // Uint8List? publicKeyBytes = AuthSecp256k1.recoverPublicKeyFromSignature( +// // v - 27, +// // r, +// // s, +// // hashMessage(message), +// // ); + +// // // If the public key is null, return false +// // if (publicKeyBytes == null) { +// // print('Could not derive publicKey'); +// // return false; +// // } + +// // Convert the public key to an address +// final publicKeyBytes = crypto.ecRecover( +// hashMessage(message), +// crypto.MsgSignature(r, s, v), +// ); +// // print(hex.encode(publicKeyBytes)); +// final hashedPubKeyBytes = keccak256(publicKeyBytes); +// final addressBytes = hashedPubKeyBytes.sublist(12, 32); +// final recoveredAddress = '0x${hex.encode(addressBytes)}'; + +// // final String recoveredAddress = EthSigUtil.recoverSignature( +// // signature: sig, +// // message: hashMessage(message), +// // // Uint8List.fromList( +// // // ascii.encode(message), +// // // ), +// // ); + +// // print(recoveredAddress.toLowerCase()); +// // print(address.toLowerCase()); + +// return recoveredAddress.toLowerCase() == address.toLowerCase(); +// } + +// static Future isValidEip1271Signature( +// String address, +// String reconstructedMessage, +// String cacaoSignature, +// String chainId, +// String projectId, +// ) async { +// try { +// const String eip1271MagicValue = '0x1626ba7e'; +// const String dynamicTypeOffset = +// '0000000000000000000000000000000000000000000000000000000000000040'; +// const String dynamicTypeLength = +// '0000000000000000000000000000000000000000000000000000000000000041'; +// final String nonPrefixedSignature = cacaoSignature.substring(2); +// final String nonPrefixedHashedMessage = +// hex.encode(hashMessage(reconstructedMessage)).substring(2); + +// final String data = eip1271MagicValue + +// nonPrefixedHashedMessage + +// dynamicTypeOffset + +// dynamicTypeLength + +// nonPrefixedSignature; + +// final Uri url = Uri.parse( +// '${AuthConstants.AUTH_DEFAULT_URL}/?chainId=$chainId&projectId=$projectId', +// ); +// final Map body = JsonRpcUtils.formatJsonRpcRequest( +// 'eth_call', +// { +// 'to': address, +// 'data': data, +// }, +// ); + +// final http.Response response = await http.post( +// url, +// body: body, +// ); + +// // print(response.body); +// // final jsonBody = jsonDecode(response.body); +// final String recoveredValue = +// response.body.substring(0, eip1271MagicValue.length); +// return recoveredValue.toLowerCase() == eip1271MagicValue.toLowerCase(); +// } catch (e) { +// return false; +// } +// } + +// // verifies CACAO signature +// // Used by the wallet after formatting the message +// static Future verifySignature( +// String address, +// String reconstructedMessage, +// CacaoSignature cacaoSignature, +// String chainId, +// String projectId, +// ) async { +// if (cacaoSignature.t == 'eip191') { +// return isValidEip191Signature( +// address, +// reconstructedMessage, +// cacaoSignature.s, +// ); +// } else if (cacaoSignature.t == 'eip1271') { +// return await isValidEip1271Signature( +// address, +// reconstructedMessage, +// cacaoSignature.s, +// chainId, +// projectId, +// ); +// } else { +// throw Exception( +// 'verifySignature failed: Attempted to verify CacaoSignature with unknown type: ${cacaoSignature.t}', +// ); +// } +// } +// } diff --git a/lib/apis/auth_api/utils/auth_utils.dart b/lib/apis/auth_api/utils/auth_utils.dart index 7f4e8016..6f641c6f 100644 --- a/lib/apis/auth_api/utils/auth_utils.dart +++ b/lib/apis/auth_api/utils/auth_utils.dart @@ -1,5 +1,5 @@ -class AuthUtils { - static String generateNonce() { - return DateTime.now().millisecondsSinceEpoch.toString(); - } -} +// class AuthUtils { +// static String generateNonce() { +// return DateTime.now().millisecondsSinceEpoch.toString(); +// } +// } diff --git a/lib/apis/auth_api/utils/secp256k1/auth_secp256k1.dart b/lib/apis/auth_api/utils/secp256k1/auth_secp256k1.dart index 20475249..607f21eb 100644 --- a/lib/apis/auth_api/utils/secp256k1/auth_secp256k1.dart +++ b/lib/apis/auth_api/utils/secp256k1/auth_secp256k1.dart @@ -1,115 +1,115 @@ -import 'dart:math'; -import 'dart:typed_data'; - -import 'package:convert/convert.dart'; -import 'package:pointycastle/ecc/api.dart'; -import 'package:pointycastle/ecc/curves/secp256k1.dart'; - -enum Endian { - be, -} - -class AuthSecp256k1 { - static final ECDomainParameters _params = ECCurve_secp256k1(); - static final BigInt _byteMask = BigInt.from(0xff); - - static BigInt decodeBigInt(List bytes) { - BigInt result = BigInt.from(0); - for (int i = 0; i < bytes.length; i++) { - result += BigInt.from(bytes[bytes.length - i - 1]) << (8 * i); - } - return result; - } - - static Uint8List encodeBigInt( - BigInt input, { - Endian endian = Endian.be, - int length = 0, - }) { - int byteLength = (input.bitLength + 7) >> 3; - int reqLength = length > 0 ? length : max(1, byteLength); - assert(byteLength <= reqLength, 'byte array longer than desired length'); - assert(reqLength > 0, 'Requested array length <= 0'); - - var res = Uint8List(reqLength); - res.fillRange(0, reqLength - byteLength, 0); - - var q = input; - if (endian == Endian.be) { - for (int i = 0; i < byteLength; i++) { - res[reqLength - i - 1] = (q & _byteMask).toInt(); - q = q >> 8; - } - return res; - } - - return Uint8List(0); - } - - static ECPoint _decompressKey(BigInt xBN, bool yBit, ECCurve c) { - List x9IntegerToBytes(BigInt s, int qLength) { - //https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java#L45 - String hexString = s.toRadixString(16); - if (hexString.length % 2 == 1) { - hexString = '0$hexString'; - } - final bytes = hex.decode(hexString); - - if (qLength < bytes.length) { - return bytes.sublist(0, bytes.length - qLength); - } else if (qLength > bytes.length) { - final tmp = List.filled(qLength, 0); - - final offset = qLength - bytes.length; - for (var i = 0; i < bytes.length; i++) { - tmp[i + offset] = bytes[i]; - } - - return tmp; - } - - return bytes; - } - - final compEnc = x9IntegerToBytes(xBN, 1 + ((c.fieldSize + 7) ~/ 8)); - compEnc[0] = yBit ? 0x03 : 0x02; - return c.decodePoint(compEnc)!; - } - - static Uint8List? recoverPublicKeyFromSignature( - int recId, - BigInt r, - BigInt s, - Uint8List message, - ) { - final n = _params.n; - final i = BigInt.from(recId ~/ 2); - final x = r + (i * n); - - //Parameter q of curve - final prime = BigInt.parse( - 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', - radix: 16); - if (x.compareTo(prime) >= 0) return null; - - final R = _decompressKey(x, (recId & 1) == 1, _params.curve); - final ECPoint? ecPoint = R * n; - if (ecPoint == null || !ecPoint.isInfinity) return null; - - // print(bytesToHex(message)); - // final e = BigInt.parse(bytesToHex(message).substring(1)); - final e = decodeBigInt(message.toList()); - - final eInv = (BigInt.zero - e) % n; - final rInv = r.modInverse(n); - final srInv = (rInv * s) % n; - final eInvrInv = (rInv * eInv) % n; - - final preQ = (_params.G * eInvrInv); - if (preQ == null) return null; - final q = preQ + (R * srInv); - - final bytes = q?.getEncoded(false); - return bytes?.sublist(1); - } -} +// import 'dart:math'; +// import 'dart:typed_data'; + +// import 'package:convert/convert.dart'; +// import 'package:pointycastle/ecc/api.dart'; +// import 'package:pointycastle/ecc/curves/secp256k1.dart'; + +// enum Endian { +// be, +// } + +// class AuthSecp256k1 { +// static final ECDomainParameters _params = ECCurve_secp256k1(); +// static final BigInt _byteMask = BigInt.from(0xff); + +// static BigInt decodeBigInt(List bytes) { +// BigInt result = BigInt.from(0); +// for (int i = 0; i < bytes.length; i++) { +// result += BigInt.from(bytes[bytes.length - i - 1]) << (8 * i); +// } +// return result; +// } + +// static Uint8List encodeBigInt( +// BigInt input, { +// Endian endian = Endian.be, +// int length = 0, +// }) { +// int byteLength = (input.bitLength + 7) >> 3; +// int reqLength = length > 0 ? length : max(1, byteLength); +// assert(byteLength <= reqLength, 'byte array longer than desired length'); +// assert(reqLength > 0, 'Requested array length <= 0'); + +// var res = Uint8List(reqLength); +// res.fillRange(0, reqLength - byteLength, 0); + +// var q = input; +// if (endian == Endian.be) { +// for (int i = 0; i < byteLength; i++) { +// res[reqLength - i - 1] = (q & _byteMask).toInt(); +// q = q >> 8; +// } +// return res; +// } + +// return Uint8List(0); +// } + +// static ECPoint _decompressKey(BigInt xBN, bool yBit, ECCurve c) { +// List x9IntegerToBytes(BigInt s, int qLength) { +// //https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java#L45 +// String hexString = s.toRadixString(16); +// if (hexString.length % 2 == 1) { +// hexString = '0$hexString'; +// } +// final bytes = hex.decode(hexString); + +// if (qLength < bytes.length) { +// return bytes.sublist(0, bytes.length - qLength); +// } else if (qLength > bytes.length) { +// final tmp = List.filled(qLength, 0); + +// final offset = qLength - bytes.length; +// for (var i = 0; i < bytes.length; i++) { +// tmp[i + offset] = bytes[i]; +// } + +// return tmp; +// } + +// return bytes; +// } + +// final compEnc = x9IntegerToBytes(xBN, 1 + ((c.fieldSize + 7) ~/ 8)); +// compEnc[0] = yBit ? 0x03 : 0x02; +// return c.decodePoint(compEnc)!; +// } + +// static Uint8List? recoverPublicKeyFromSignature( +// int recId, +// BigInt r, +// BigInt s, +// Uint8List message, +// ) { +// final n = _params.n; +// final i = BigInt.from(recId ~/ 2); +// final x = r + (i * n); + +// //Parameter q of curve +// final prime = BigInt.parse( +// 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', +// radix: 16); +// if (x.compareTo(prime) >= 0) return null; + +// final R = _decompressKey(x, (recId & 1) == 1, _params.curve); +// final ECPoint? ecPoint = R * n; +// if (ecPoint == null || !ecPoint.isInfinity) return null; + +// // print(bytesToHex(message)); +// // final e = BigInt.parse(bytesToHex(message).substring(1)); +// final e = decodeBigInt(message.toList()); + +// final eInv = (BigInt.zero - e) % n; +// final rInv = r.modInverse(n); +// final srInv = (rInv * s) % n; +// final eInvrInv = (rInv * eInv) % n; + +// final preQ = (_params.G * eInvrInv); +// if (preQ == null) return null; +// final q = preQ + (R * srInv); + +// final bytes = q?.getEncoded(false); +// return bytes?.sublist(1); +// } +// } diff --git a/lib/apis/core/core.dart b/lib/apis/core/core.dart index 13766119..97296705 100644 --- a/lib/apis/core/core.dart +++ b/lib/apis/core/core.dart @@ -72,6 +72,16 @@ class Core implements ICore { @override Logger get logger => _logger; + @override + void addLogListener(LogCallback callback) { + Logger.addLogListener(callback); + } + + @override + bool removeLogListener(LogCallback callback) { + return Logger.removeLogListener(callback); + } + @override late IStore> storage; @@ -86,7 +96,7 @@ class Core implements ICore { }) { _logger = Logger( level: logLevel.toLevel(), - printer: PrettyPrinter(), + printer: PrettyPrinter(methodCount: null), ); heartbeat = HeartBeat(); storage = SharedPrefsStores( diff --git a/lib/apis/core/crypto/crypto.dart b/lib/apis/core/crypto/crypto.dart index 34a381d9..ca8c7162 100644 --- a/lib/apis/core/crypto/crypto.dart +++ b/lib/apis/core/crypto/crypto.dart @@ -189,8 +189,8 @@ class Crypto implements ICrypto { final Uint8List seed = await _getClientSeed(); final RelayAuthKeyPair keyPair = await relayAuth.generateKeyPair(seed); - String sub = utils.generateRandomBytes32(); - String jwt = await relayAuth.signJWT( + final String sub = utils.generateRandomBytes32(); + final jwt = await relayAuth.signJWT( sub: sub, aud: aud, ttl: WalletConnectConstants.ONE_DAY, diff --git a/lib/apis/core/i_core.dart b/lib/apis/core/i_core.dart index b713ad22..85f067ad 100644 --- a/lib/apis/core/i_core.dart +++ b/lib/apis/core/i_core.dart @@ -27,5 +27,8 @@ abstract class ICore { abstract final Logger logger; abstract IVerify verify; + void addLogListener(LogCallback callback); + bool removeLogListener(LogCallback callback); + Future start(); } diff --git a/lib/apis/core/pairing/i_pairing.dart b/lib/apis/core/pairing/i_pairing.dart index ea0150a3..c4894624 100644 --- a/lib/apis/core/pairing/i_pairing.dart +++ b/lib/apis/core/pairing/i_pairing.dart @@ -3,6 +3,7 @@ import 'package:walletconnect_flutter_v2/apis/core/crypto/crypto_models.dart'; import 'package:walletconnect_flutter_v2/apis/core/pairing/i_pairing_store.dart'; import 'package:walletconnect_flutter_v2/apis/core/pairing/utils/pairing_models.dart'; +import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; import 'package:walletconnect_flutter_v2/apis/models/json_rpc_error.dart'; import 'package:walletconnect_flutter_v2/apis/models/json_rpc_request.dart'; @@ -69,6 +70,7 @@ abstract class IPairing { String method, JsonRpcError error, { EncodeOptions? encodeOptions, + RpcOptions? rpcOptions, }); Future isValidPairingTopic({ diff --git a/lib/apis/core/pairing/pairing.dart b/lib/apis/core/pairing/pairing.dart index b97a3d22..4ea2e633 100644 --- a/lib/apis/core/pairing/pairing.dart +++ b/lib/apis/core/pairing/pairing.dart @@ -113,6 +113,7 @@ class Pairing implements IPairing { expiry: expiry, relay: relay, active: false, + methods: methods?.expand((e) => e).toList() ?? [], ); final Uri uri = WalletConnectUtils.formatUri( protocol: core.protocol, @@ -121,6 +122,7 @@ class Pairing implements IPairing { symKey: symKey, relay: relay, methods: methods, + expiry: expiry, ); onPairingCreate.broadcast( @@ -167,6 +169,7 @@ class Pairing implements IPairing { expiry: expiry, relay: relay, active: false, + methods: parsedUri.v2Data!.methods, ); try { @@ -239,10 +242,13 @@ class Pairing implements IPairing { required ProtocolType type, }) { if (routerMapRequest.containsKey(method)) { - throw const WalletConnectError( - code: -1, - message: 'Method already exists', - ); + final registered = routerMapRequest[method]; + if (registered!.type == type) { + throw const WalletConnectError( + code: -1, + message: 'Method already exists', + ); + } } routerMapRequest[method] = RegisteredFunction( @@ -495,6 +501,7 @@ class Pairing implements IPairing { String method, JsonRpcError error, { EncodeOptions? encodeOptions, + RpcOptions? rpcOptions, }) async { core.logger.t( 'pairing sendError, id: $id topic: $topic, method: $method, error: $error', @@ -514,10 +521,13 @@ class Pairing implements IPairing { return; } - final RpcOptions opts = MethodConstants.RPC_OPTS.containsKey(method) - ? MethodConstants.RPC_OPTS[method]!['res']! - : MethodConstants - .RPC_OPTS[MethodConstants.UNREGISTERED_METHOD]!['res']!; + final fallbackMethod = MethodConstants.UNREGISTERED_METHOD; + final fallbackRpcOpts = MethodConstants.RPC_OPTS[method] ?? + MethodConstants.RPC_OPTS[fallbackMethod]!; + final fallbackOpts = fallbackRpcOpts['reject'] ?? fallbackRpcOpts['res']!; + + final RpcOptions opts = rpcOptions ?? fallbackOpts; + await core.relayClient.publish( topic: topic, message: message, diff --git a/lib/apis/core/pairing/utils/pairing_models.dart b/lib/apis/core/pairing/utils/pairing_models.dart index d7fda7ef..b4f9499d 100644 --- a/lib/apis/core/pairing/utils/pairing_models.dart +++ b/lib/apis/core/pairing/utils/pairing_models.dart @@ -21,6 +21,7 @@ class PairingInfo with _$PairingInfo { required int expiry, required Relay relay, required bool active, + List? methods, PairingMetadata? peerMetadata, }) = _PairingInfo; @@ -76,7 +77,7 @@ class CreateResponse { @override String toString() { - return 'CreateResponse(topic: $topic, uri: $uri)'; + return 'CreateResponse(topic: $topic, uri: $uri, pairingInfo: ${pairingInfo.toJson()})'; } } diff --git a/lib/apis/core/pairing/utils/pairing_models.freezed.dart b/lib/apis/core/pairing/utils/pairing_models.freezed.dart index 72ccd707..0275658d 100644 --- a/lib/apis/core/pairing/utils/pairing_models.freezed.dart +++ b/lib/apis/core/pairing/utils/pairing_models.freezed.dart @@ -24,6 +24,7 @@ mixin _$PairingInfo { int get expiry => throw _privateConstructorUsedError; Relay get relay => throw _privateConstructorUsedError; bool get active => throw _privateConstructorUsedError; + List? get methods => throw _privateConstructorUsedError; PairingMetadata? get peerMetadata => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @@ -43,6 +44,7 @@ abstract class $PairingInfoCopyWith<$Res> { int expiry, Relay relay, bool active, + List? methods, PairingMetadata? peerMetadata}); $PairingMetadataCopyWith<$Res>? get peerMetadata; @@ -65,6 +67,7 @@ class _$PairingInfoCopyWithImpl<$Res, $Val extends PairingInfo> Object? expiry = null, Object? relay = null, Object? active = null, + Object? methods = freezed, Object? peerMetadata = freezed, }) { return _then(_value.copyWith( @@ -84,6 +87,10 @@ class _$PairingInfoCopyWithImpl<$Res, $Val extends PairingInfo> ? _value.active : active // ignore: cast_nullable_to_non_nullable as bool, + methods: freezed == methods + ? _value.methods + : methods // ignore: cast_nullable_to_non_nullable + as List?, peerMetadata: freezed == peerMetadata ? _value.peerMetadata : peerMetadata // ignore: cast_nullable_to_non_nullable @@ -117,6 +124,7 @@ abstract class _$$PairingInfoImplCopyWith<$Res> int expiry, Relay relay, bool active, + List? methods, PairingMetadata? peerMetadata}); @override @@ -138,6 +146,7 @@ class __$$PairingInfoImplCopyWithImpl<$Res> Object? expiry = null, Object? relay = null, Object? active = null, + Object? methods = freezed, Object? peerMetadata = freezed, }) { return _then(_$PairingInfoImpl( @@ -157,6 +166,10 @@ class __$$PairingInfoImplCopyWithImpl<$Res> ? _value.active : active // ignore: cast_nullable_to_non_nullable as bool, + methods: freezed == methods + ? _value._methods + : methods // ignore: cast_nullable_to_non_nullable + as List?, peerMetadata: freezed == peerMetadata ? _value.peerMetadata : peerMetadata // ignore: cast_nullable_to_non_nullable @@ -174,7 +187,9 @@ class _$PairingInfoImpl implements _PairingInfo { required this.expiry, required this.relay, required this.active, - this.peerMetadata}); + final List? methods, + this.peerMetadata}) + : _methods = methods; factory _$PairingInfoImpl.fromJson(Map json) => _$$PairingInfoImplFromJson(json); @@ -187,12 +202,22 @@ class _$PairingInfoImpl implements _PairingInfo { final Relay relay; @override final bool active; + final List? _methods; + @override + List? get methods { + final value = _methods; + if (value == null) return null; + if (_methods is EqualUnmodifiableListView) return _methods; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + @override final PairingMetadata? peerMetadata; @override String toString() { - return 'PairingInfo(topic: $topic, expiry: $expiry, relay: $relay, active: $active, peerMetadata: $peerMetadata)'; + return 'PairingInfo(topic: $topic, expiry: $expiry, relay: $relay, active: $active, methods: $methods, peerMetadata: $peerMetadata)'; } @override @@ -204,14 +229,15 @@ class _$PairingInfoImpl implements _PairingInfo { (identical(other.expiry, expiry) || other.expiry == expiry) && (identical(other.relay, relay) || other.relay == relay) && (identical(other.active, active) || other.active == active) && + const DeepCollectionEquality().equals(other._methods, _methods) && (identical(other.peerMetadata, peerMetadata) || other.peerMetadata == peerMetadata)); } @JsonKey(ignore: true) @override - int get hashCode => - Object.hash(runtimeType, topic, expiry, relay, active, peerMetadata); + int get hashCode => Object.hash(runtimeType, topic, expiry, relay, active, + const DeepCollectionEquality().hash(_methods), peerMetadata); @JsonKey(ignore: true) @override @@ -233,6 +259,7 @@ abstract class _PairingInfo implements PairingInfo { required final int expiry, required final Relay relay, required final bool active, + final List? methods, final PairingMetadata? peerMetadata}) = _$PairingInfoImpl; factory _PairingInfo.fromJson(Map json) = @@ -247,6 +274,8 @@ abstract class _PairingInfo implements PairingInfo { @override bool get active; @override + List? get methods; + @override PairingMetadata? get peerMetadata; @override @JsonKey(ignore: true) diff --git a/lib/apis/core/pairing/utils/pairing_models.g.dart b/lib/apis/core/pairing/utils/pairing_models.g.dart index 4f064249..78975b35 100644 --- a/lib/apis/core/pairing/utils/pairing_models.g.dart +++ b/lib/apis/core/pairing/utils/pairing_models.g.dart @@ -12,6 +12,8 @@ _$PairingInfoImpl _$$PairingInfoImplFromJson(Map json) => expiry: json['expiry'] as int, relay: Relay.fromJson(json['relay'] as Map), active: json['active'] as bool, + methods: + (json['methods'] as List?)?.map((e) => e as String).toList(), peerMetadata: json['peerMetadata'] == null ? null : PairingMetadata.fromJson( @@ -24,6 +26,7 @@ Map _$$PairingInfoImplToJson(_$PairingInfoImpl instance) => 'expiry': instance.expiry, 'relay': instance.relay.toJson(), 'active': instance.active, + 'methods': instance.methods, 'peerMetadata': instance.peerMetadata?.toJson(), }; diff --git a/lib/apis/sign_api/i_sign_client.dart b/lib/apis/sign_api/i_sign_client.dart index 10f7b318..b8482cd9 100644 --- a/lib/apis/sign_api/i_sign_client.dart +++ b/lib/apis/sign_api/i_sign_client.dart @@ -21,15 +21,30 @@ abstract class ISignClient { abstract final ISessions sessions; abstract final IGenericStore pendingRequests; + // FORMER AUTH ENGINE PROPERTIES + abstract final IGenericStore authKeys; + abstract final IGenericStore pairingTopics; + abstract final IGenericStore completeRequests; + // Wallet abstract final Event onSessionProposal; abstract final Event onSessionProposalError; abstract final Event onSessionRequest; + // FORMER AUTH ENGINE METHODS + abstract final Event onAuthRequest; + abstract final IGenericStore authRequests; + // NEW 1-CA METHODS + abstract final Event onSessionAuthRequest; + abstract final IGenericStore sessionAuthRequests; // App abstract final Event onSessionUpdate; abstract final Event onSessionExtend; abstract final Event onSessionEvent; + // FORMER AUTH ENGINE METHOD + abstract final Event onAuthResponse; + // NEW 1-CA METHOD + abstract final Event onSessionAuthResponse; Future init(); Future connect({ @@ -133,4 +148,61 @@ abstract class ISignClient { required String chainId, required String accountAddress, }); + + // FORMER AUTH ENGINE COMMON METHODS + + String formatAuthMessage({ + required String iss, + required CacaoRequestPayload cacaoPayload, + }); + + Map getCompletedRequestsForPairing({ + required String pairingTopic, + }); + + // FORMER AUTH ENGINE WALLET METHODS + + Future respondAuthRequest({ + required int id, + required String iss, + CacaoSignature? signature, + WalletConnectError? error, + }); + + Map getPendingAuthRequests(); + + // FORMER AUTH ENGINE DAPP METHODS + + Future requestAuth({ + required AuthRequestParams params, + String? pairingTopic, + List>? methods, + }); + + // NEW 1-CA WALLET METHODS + + Future approveSessionAuthenticate({ + required int id, + List? auths, + }); + + Future rejectSessionAuthenticate({ + required int id, + required WalletConnectError reason, + }); + + Map getPendingSessionAuthRequests(); + + // NEW 1-CA DAPP METHODS + + Future authenticate({ + required SessionAuthRequestParams params, + String? pairingTopic, + List>? methods, + }); + + Future validateSignedCacao({ + required Cacao cacao, + required String projectId, + }); } diff --git a/lib/apis/sign_api/i_sign_engine_app.dart b/lib/apis/sign_api/i_sign_engine_app.dart index df93ba67..c7ced660 100644 --- a/lib/apis/sign_api/i_sign_engine_app.dart +++ b/lib/apis/sign_api/i_sign_engine_app.dart @@ -5,6 +5,10 @@ abstract class ISignEngineApp extends ISignEngineCommon { abstract final Event onSessionUpdate; abstract final Event onSessionExtend; abstract final Event onSessionEvent; + // FORMER AUTH ENGINE PROPERTY + abstract final Event onAuthResponse; + // NEW 1-CA PROPERTY + abstract final Event onSessionAuthResponse; Future connect({ Map? requiredNamespaces, @@ -44,4 +48,18 @@ abstract class ISignEngineApp extends ISignEngineCommon { Future ping({ required String topic, }); + + // FORMER AUTH ENGINE METHOD + Future requestAuth({ + required AuthRequestParams params, + String? pairingTopic, + List>? methods, + }); + + // NEW 1-CA METHOD + Future authenticate({ + required SessionAuthRequestParams params, + String? pairingTopic, + List>? methods, + }); } diff --git a/lib/apis/sign_api/i_sign_engine_common.dart b/lib/apis/sign_api/i_sign_engine_common.dart index b4d4ae91..0acd8f0d 100644 --- a/lib/apis/sign_api/i_sign_engine_common.dart +++ b/lib/apis/sign_api/i_sign_engine_common.dart @@ -8,6 +8,7 @@ import 'package:walletconnect_flutter_v2/apis/sign_api/i_sessions.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/models/proposal_models.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/models/session_models.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/models/sign_client_events.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/common_auth_models.dart'; abstract class ISignEngineCommon { abstract final Event onSessionConnect; @@ -22,6 +23,12 @@ abstract class ISignEngineCommon { abstract final ISessions sessions; abstract final IGenericStore pendingRequests; + // FORMER AUTH ENGINE PROPERTY + abstract final IPairingStore pairings; + abstract final IGenericStore authKeys; + abstract final IGenericStore pairingTopics; + abstract final IGenericStore completeRequests; + Future init(); Future disconnectSession({ required String topic, @@ -33,5 +40,18 @@ abstract class ISignEngineCommon { }); Map getPendingSessionProposals(); - abstract final IPairingStore pairings; + // FORMER AUTH ENGINE METHOD + String formatAuthMessage({ + required String iss, + required CacaoRequestPayload cacaoPayload, + }); + Map getCompletedRequestsForPairing({ + required String pairingTopic, + }); + + // NEW 1-CA METHOD + Future validateSignedCacao({ + required Cacao cacao, + required String projectId, + }); } diff --git a/lib/apis/sign_api/i_sign_engine_wallet.dart b/lib/apis/sign_api/i_sign_engine_wallet.dart index 86244be5..c2f125d6 100644 --- a/lib/apis/sign_api/i_sign_engine_wallet.dart +++ b/lib/apis/sign_api/i_sign_engine_wallet.dart @@ -3,17 +3,31 @@ import 'package:walletconnect_flutter_v2/apis/core/pairing/utils/pairing_models. import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; import 'package:walletconnect_flutter_v2/apis/models/json_rpc_response.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/i_sign_engine_common.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/common_auth_models.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/models/json_rpc_models.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/models/proposal_models.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/models/session_models.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/models/sign_client_events.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/models/sign_client_models.dart'; +import 'package:walletconnect_flutter_v2/apis/core/store/i_generic_store.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_events.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_models.dart'; + +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/session_auth_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/session_auth_events.dart'; abstract class ISignEngineWallet extends ISignEngineCommon { abstract final Event onSessionProposal; abstract final Event onSessionProposalError; abstract final Event onSessionRequest; + // FORMER AUTH ENGINE PROPERTY + abstract final Event onAuthRequest; + abstract final IGenericStore authRequests; + // NEW 1-CA METHOD + abstract final Event onSessionAuthRequest; + abstract final IGenericStore sessionAuthRequests; + Future pair({ required Uri uri, }); @@ -76,4 +90,29 @@ abstract class ISignEngineWallet extends ISignEngineCommon { // required Map requiredNamespaces, // Map? optionalNamespaces, // }); + + // FORMER AUTH ENGINE METHODS + + Future respondAuthRequest({ + required int id, + required String iss, + CacaoSignature? signature, + WalletConnectError? error, + }); + + Map getPendingAuthRequests(); + + // NEW 1-CA METHODS + + Future approveSessionAuthenticate({ + required int id, + List? auths, + }); + + Future rejectSessionAuthenticate({ + required int id, + required WalletConnectError reason, + }); + + Map getPendingSessionAuthRequests(); } diff --git a/lib/apis/sign_api/models/auth/auth_client_events.dart b/lib/apis/sign_api/models/auth/auth_client_events.dart new file mode 100644 index 00000000..3741e014 --- /dev/null +++ b/lib/apis/sign_api/models/auth/auth_client_events.dart @@ -0,0 +1,55 @@ +import 'dart:convert'; + +import 'package:event/event.dart'; +import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; +import 'package:walletconnect_flutter_v2/apis/models/json_rpc_error.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/common_auth_models.dart'; + +class AuthRequest extends EventArgs { + final int id; + final String topic; + final AuthPayloadParams payloadParams; + final ConnectionMetadata requester; + + AuthRequest({ + required this.id, + required this.topic, + required this.payloadParams, + required this.requester, + }); + + @override + String toString() { + return 'AuthRequest(id: $id, topic: $topic, payloadParams: $payloadParams, requester: $requester)'; + } +} + +class AuthResponse extends EventArgs { + final int id; + final String topic; + final Cacao? result; + final WalletConnectError? error; + final JsonRpcError? jsonRpcError; + + AuthResponse({ + required this.id, + required this.topic, + this.result, + this.error, + this.jsonRpcError, + }); + + Map toJson() => { + 'id': id, + 'topic': topic, + if (result != null) 'result': result?.toJson(), + if (error != null) 'error': error!.toJson(), + if (jsonRpcError != null) 'jsonRpcError': jsonRpcError!.toJson(), + }; + + @override + String toString() { + return 'AuthResponse(${jsonEncode(toJson())})'; + } +} diff --git a/lib/apis/sign_api/models/auth/auth_client_models.dart b/lib/apis/sign_api/models/auth/auth_client_models.dart new file mode 100644 index 00000000..272cf1b3 --- /dev/null +++ b/lib/apis/sign_api/models/auth/auth_client_models.dart @@ -0,0 +1,167 @@ +import 'dart:async'; + +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_events.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/common_auth_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/utils/auth/auth_utils.dart'; + +part 'auth_client_models.g.dart'; +part 'auth_client_models.freezed.dart'; + +class AuthRequestResponse { + final int id; + final String pairingTopic; + final Completer completer; + final Uri? uri; + + AuthRequestResponse({ + required this.id, + required this.pairingTopic, + required this.completer, + this.uri, + }); +} + +class AuthRequestParams { + /// The Chain ID. + /// Examples: eip155:1 (Eth Mainnet), eip155:43114 (Avalanche) + final String chainId; + + /// The complete URL you are logging into. + /// Example: https://example.com/login + final String aud; + + /// The domain you are logging in to. + /// Example: example.com + /// Domain must exist within the aud, or validation will fail + final String domain; + final String nonce; + final String? type; + final String? nbf; + final String? exp; + final String? statement; + final String? requestId; + final List? resources; + final int? expiry; + + AuthRequestParams({ + required this.chainId, + required this.domain, + required this.aud, + String? nonce, + this.type = CacaoHeader.EIP4361, + this.nbf, + this.exp, + this.statement, + this.requestId, + this.resources, + this.expiry, + }) : nonce = nonce ?? AuthUtils.generateNonce(); + + Map toJson() => { + 'chainId': chainId, + 'aud': aud, + 'domain': domain, + 'nonce': nonce, + if (type != null) 'type': type, + if (nbf != null) 'nbf': nbf, + if (exp != null) 'exp': exp, + if (statement != null) 'statement': statement, + if (requestId != null) 'requestId': requestId, + if (resources != null) 'resources': resources, + if (expiry != null) 'expiry': expiry, + }; +} + +@freezed +class AuthPayloadParams with _$AuthPayloadParams { + @JsonSerializable(includeIfNull: false) + const factory AuthPayloadParams({ + required String chainId, + required String aud, + required String domain, + required String nonce, + required String type, + // + required String version, + required String iat, + // + String? nbf, + String? exp, + String? statement, + String? requestId, + List? resources, + }) = _AuthPayloadParams; + + factory AuthPayloadParams.fromRequestParams(AuthRequestParams params) { + final now = DateTime.now(); + return AuthPayloadParams( + type: params.type ?? CacaoHeader.EIP4361, + chainId: params.chainId, + domain: params.domain, + aud: params.aud, + version: '1', + nonce: params.nonce, + iat: DateTime.utc( + now.year, + now.month, + now.day, + now.hour, + now.minute, + now.second, + now.millisecond, + ).toIso8601String(), + nbf: params.nbf, + exp: params.exp, + statement: params.statement, + requestId: params.requestId, + resources: params.resources, + ); + } + + factory AuthPayloadParams.fromJson(Map json) => + _$AuthPayloadParamsFromJson(json); +} + +@freezed +class PendingAuthRequest with _$PendingAuthRequest { + @JsonSerializable(includeIfNull: false) + const factory PendingAuthRequest({ + required int id, + required String pairingTopic, + required ConnectionMetadata metadata, + required CacaoRequestPayload cacaoPayload, + }) = _PendingAuthRequest; + + factory PendingAuthRequest.fromJson(Map json) => + _$PendingAuthRequestFromJson(json); +} + +class AuthRequestCompleter { + final int id; + final String pairingTopic; + final String responseTopic; + final PendingAuthRequest request; + final Completer completer; + + AuthRequestCompleter({ + required this.id, + required this.pairingTopic, + required this.responseTopic, + required this.request, + required this.completer, + }); +} + +class RespondParams { + final int id; + final CacaoSignature? signature; + final WalletConnectError? error; + + RespondParams({ + required this.id, + this.signature, + this.error, + }); +} diff --git a/lib/apis/sign_api/models/auth/auth_client_models.freezed.dart b/lib/apis/sign_api/models/auth/auth_client_models.freezed.dart new file mode 100644 index 00000000..05fbc985 --- /dev/null +++ b/lib/apis/sign_api/models/auth/auth_client_models.freezed.dart @@ -0,0 +1,634 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'auth_client_models.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +AuthPayloadParams _$AuthPayloadParamsFromJson(Map json) { + return _AuthPayloadParams.fromJson(json); +} + +/// @nodoc +mixin _$AuthPayloadParams { + String get chainId => throw _privateConstructorUsedError; + String get aud => throw _privateConstructorUsedError; + String get domain => throw _privateConstructorUsedError; + String get nonce => throw _privateConstructorUsedError; + String get type => throw _privateConstructorUsedError; // + String get version => throw _privateConstructorUsedError; + String get iat => throw _privateConstructorUsedError; // + String? get nbf => throw _privateConstructorUsedError; + String? get exp => throw _privateConstructorUsedError; + String? get statement => throw _privateConstructorUsedError; + String? get requestId => throw _privateConstructorUsedError; + List? get resources => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $AuthPayloadParamsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AuthPayloadParamsCopyWith<$Res> { + factory $AuthPayloadParamsCopyWith( + AuthPayloadParams value, $Res Function(AuthPayloadParams) then) = + _$AuthPayloadParamsCopyWithImpl<$Res, AuthPayloadParams>; + @useResult + $Res call( + {String chainId, + String aud, + String domain, + String nonce, + String type, + String version, + String iat, + String? nbf, + String? exp, + String? statement, + String? requestId, + List? resources}); +} + +/// @nodoc +class _$AuthPayloadParamsCopyWithImpl<$Res, $Val extends AuthPayloadParams> + implements $AuthPayloadParamsCopyWith<$Res> { + _$AuthPayloadParamsCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? chainId = null, + Object? aud = null, + Object? domain = null, + Object? nonce = null, + Object? type = null, + Object? version = null, + Object? iat = null, + Object? nbf = freezed, + Object? exp = freezed, + Object? statement = freezed, + Object? requestId = freezed, + Object? resources = freezed, + }) { + return _then(_value.copyWith( + chainId: null == chainId + ? _value.chainId + : chainId // ignore: cast_nullable_to_non_nullable + as String, + aud: null == aud + ? _value.aud + : aud // ignore: cast_nullable_to_non_nullable + as String, + domain: null == domain + ? _value.domain + : domain // ignore: cast_nullable_to_non_nullable + as String, + nonce: null == nonce + ? _value.nonce + : nonce // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as String, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as String, + iat: null == iat + ? _value.iat + : iat // ignore: cast_nullable_to_non_nullable + as String, + nbf: freezed == nbf + ? _value.nbf + : nbf // ignore: cast_nullable_to_non_nullable + as String?, + exp: freezed == exp + ? _value.exp + : exp // ignore: cast_nullable_to_non_nullable + as String?, + statement: freezed == statement + ? _value.statement + : statement // ignore: cast_nullable_to_non_nullable + as String?, + requestId: freezed == requestId + ? _value.requestId + : requestId // ignore: cast_nullable_to_non_nullable + as String?, + resources: freezed == resources + ? _value.resources + : resources // ignore: cast_nullable_to_non_nullable + as List?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$AuthPayloadParamsImplCopyWith<$Res> + implements $AuthPayloadParamsCopyWith<$Res> { + factory _$$AuthPayloadParamsImplCopyWith(_$AuthPayloadParamsImpl value, + $Res Function(_$AuthPayloadParamsImpl) then) = + __$$AuthPayloadParamsImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String chainId, + String aud, + String domain, + String nonce, + String type, + String version, + String iat, + String? nbf, + String? exp, + String? statement, + String? requestId, + List? resources}); +} + +/// @nodoc +class __$$AuthPayloadParamsImplCopyWithImpl<$Res> + extends _$AuthPayloadParamsCopyWithImpl<$Res, _$AuthPayloadParamsImpl> + implements _$$AuthPayloadParamsImplCopyWith<$Res> { + __$$AuthPayloadParamsImplCopyWithImpl(_$AuthPayloadParamsImpl _value, + $Res Function(_$AuthPayloadParamsImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? chainId = null, + Object? aud = null, + Object? domain = null, + Object? nonce = null, + Object? type = null, + Object? version = null, + Object? iat = null, + Object? nbf = freezed, + Object? exp = freezed, + Object? statement = freezed, + Object? requestId = freezed, + Object? resources = freezed, + }) { + return _then(_$AuthPayloadParamsImpl( + chainId: null == chainId + ? _value.chainId + : chainId // ignore: cast_nullable_to_non_nullable + as String, + aud: null == aud + ? _value.aud + : aud // ignore: cast_nullable_to_non_nullable + as String, + domain: null == domain + ? _value.domain + : domain // ignore: cast_nullable_to_non_nullable + as String, + nonce: null == nonce + ? _value.nonce + : nonce // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as String, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as String, + iat: null == iat + ? _value.iat + : iat // ignore: cast_nullable_to_non_nullable + as String, + nbf: freezed == nbf + ? _value.nbf + : nbf // ignore: cast_nullable_to_non_nullable + as String?, + exp: freezed == exp + ? _value.exp + : exp // ignore: cast_nullable_to_non_nullable + as String?, + statement: freezed == statement + ? _value.statement + : statement // ignore: cast_nullable_to_non_nullable + as String?, + requestId: freezed == requestId + ? _value.requestId + : requestId // ignore: cast_nullable_to_non_nullable + as String?, + resources: freezed == resources + ? _value._resources + : resources // ignore: cast_nullable_to_non_nullable + as List?, + )); + } +} + +/// @nodoc + +@JsonSerializable(includeIfNull: false) +class _$AuthPayloadParamsImpl implements _AuthPayloadParams { + const _$AuthPayloadParamsImpl( + {required this.chainId, + required this.aud, + required this.domain, + required this.nonce, + required this.type, + required this.version, + required this.iat, + this.nbf, + this.exp, + this.statement, + this.requestId, + final List? resources}) + : _resources = resources; + + factory _$AuthPayloadParamsImpl.fromJson(Map json) => + _$$AuthPayloadParamsImplFromJson(json); + + @override + final String chainId; + @override + final String aud; + @override + final String domain; + @override + final String nonce; + @override + final String type; +// + @override + final String version; + @override + final String iat; +// + @override + final String? nbf; + @override + final String? exp; + @override + final String? statement; + @override + final String? requestId; + final List? _resources; + @override + List? get resources { + final value = _resources; + if (value == null) return null; + if (_resources is EqualUnmodifiableListView) return _resources; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + String toString() { + return 'AuthPayloadParams(chainId: $chainId, aud: $aud, domain: $domain, nonce: $nonce, type: $type, version: $version, iat: $iat, nbf: $nbf, exp: $exp, statement: $statement, requestId: $requestId, resources: $resources)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AuthPayloadParamsImpl && + (identical(other.chainId, chainId) || other.chainId == chainId) && + (identical(other.aud, aud) || other.aud == aud) && + (identical(other.domain, domain) || other.domain == domain) && + (identical(other.nonce, nonce) || other.nonce == nonce) && + (identical(other.type, type) || other.type == type) && + (identical(other.version, version) || other.version == version) && + (identical(other.iat, iat) || other.iat == iat) && + (identical(other.nbf, nbf) || other.nbf == nbf) && + (identical(other.exp, exp) || other.exp == exp) && + (identical(other.statement, statement) || + other.statement == statement) && + (identical(other.requestId, requestId) || + other.requestId == requestId) && + const DeepCollectionEquality() + .equals(other._resources, _resources)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + chainId, + aud, + domain, + nonce, + type, + version, + iat, + nbf, + exp, + statement, + requestId, + const DeepCollectionEquality().hash(_resources)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$AuthPayloadParamsImplCopyWith<_$AuthPayloadParamsImpl> get copyWith => + __$$AuthPayloadParamsImplCopyWithImpl<_$AuthPayloadParamsImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$AuthPayloadParamsImplToJson( + this, + ); + } +} + +abstract class _AuthPayloadParams implements AuthPayloadParams { + const factory _AuthPayloadParams( + {required final String chainId, + required final String aud, + required final String domain, + required final String nonce, + required final String type, + required final String version, + required final String iat, + final String? nbf, + final String? exp, + final String? statement, + final String? requestId, + final List? resources}) = _$AuthPayloadParamsImpl; + + factory _AuthPayloadParams.fromJson(Map json) = + _$AuthPayloadParamsImpl.fromJson; + + @override + String get chainId; + @override + String get aud; + @override + String get domain; + @override + String get nonce; + @override + String get type; + @override // + String get version; + @override + String get iat; + @override // + String? get nbf; + @override + String? get exp; + @override + String? get statement; + @override + String? get requestId; + @override + List? get resources; + @override + @JsonKey(ignore: true) + _$$AuthPayloadParamsImplCopyWith<_$AuthPayloadParamsImpl> get copyWith => + throw _privateConstructorUsedError; +} + +PendingAuthRequest _$PendingAuthRequestFromJson(Map json) { + return _PendingAuthRequest.fromJson(json); +} + +/// @nodoc +mixin _$PendingAuthRequest { + int get id => throw _privateConstructorUsedError; + String get pairingTopic => throw _privateConstructorUsedError; + ConnectionMetadata get metadata => throw _privateConstructorUsedError; + CacaoRequestPayload get cacaoPayload => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $PendingAuthRequestCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PendingAuthRequestCopyWith<$Res> { + factory $PendingAuthRequestCopyWith( + PendingAuthRequest value, $Res Function(PendingAuthRequest) then) = + _$PendingAuthRequestCopyWithImpl<$Res, PendingAuthRequest>; + @useResult + $Res call( + {int id, + String pairingTopic, + ConnectionMetadata metadata, + CacaoRequestPayload cacaoPayload}); + + $ConnectionMetadataCopyWith<$Res> get metadata; + $CacaoRequestPayloadCopyWith<$Res> get cacaoPayload; +} + +/// @nodoc +class _$PendingAuthRequestCopyWithImpl<$Res, $Val extends PendingAuthRequest> + implements $PendingAuthRequestCopyWith<$Res> { + _$PendingAuthRequestCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? pairingTopic = null, + Object? metadata = null, + Object? cacaoPayload = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + pairingTopic: null == pairingTopic + ? _value.pairingTopic + : pairingTopic // ignore: cast_nullable_to_non_nullable + as String, + metadata: null == metadata + ? _value.metadata + : metadata // ignore: cast_nullable_to_non_nullable + as ConnectionMetadata, + cacaoPayload: null == cacaoPayload + ? _value.cacaoPayload + : cacaoPayload // ignore: cast_nullable_to_non_nullable + as CacaoRequestPayload, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $ConnectionMetadataCopyWith<$Res> get metadata { + return $ConnectionMetadataCopyWith<$Res>(_value.metadata, (value) { + return _then(_value.copyWith(metadata: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $CacaoRequestPayloadCopyWith<$Res> get cacaoPayload { + return $CacaoRequestPayloadCopyWith<$Res>(_value.cacaoPayload, (value) { + return _then(_value.copyWith(cacaoPayload: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$PendingAuthRequestImplCopyWith<$Res> + implements $PendingAuthRequestCopyWith<$Res> { + factory _$$PendingAuthRequestImplCopyWith(_$PendingAuthRequestImpl value, + $Res Function(_$PendingAuthRequestImpl) then) = + __$$PendingAuthRequestImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int id, + String pairingTopic, + ConnectionMetadata metadata, + CacaoRequestPayload cacaoPayload}); + + @override + $ConnectionMetadataCopyWith<$Res> get metadata; + @override + $CacaoRequestPayloadCopyWith<$Res> get cacaoPayload; +} + +/// @nodoc +class __$$PendingAuthRequestImplCopyWithImpl<$Res> + extends _$PendingAuthRequestCopyWithImpl<$Res, _$PendingAuthRequestImpl> + implements _$$PendingAuthRequestImplCopyWith<$Res> { + __$$PendingAuthRequestImplCopyWithImpl(_$PendingAuthRequestImpl _value, + $Res Function(_$PendingAuthRequestImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? pairingTopic = null, + Object? metadata = null, + Object? cacaoPayload = null, + }) { + return _then(_$PendingAuthRequestImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + pairingTopic: null == pairingTopic + ? _value.pairingTopic + : pairingTopic // ignore: cast_nullable_to_non_nullable + as String, + metadata: null == metadata + ? _value.metadata + : metadata // ignore: cast_nullable_to_non_nullable + as ConnectionMetadata, + cacaoPayload: null == cacaoPayload + ? _value.cacaoPayload + : cacaoPayload // ignore: cast_nullable_to_non_nullable + as CacaoRequestPayload, + )); + } +} + +/// @nodoc + +@JsonSerializable(includeIfNull: false) +class _$PendingAuthRequestImpl implements _PendingAuthRequest { + const _$PendingAuthRequestImpl( + {required this.id, + required this.pairingTopic, + required this.metadata, + required this.cacaoPayload}); + + factory _$PendingAuthRequestImpl.fromJson(Map json) => + _$$PendingAuthRequestImplFromJson(json); + + @override + final int id; + @override + final String pairingTopic; + @override + final ConnectionMetadata metadata; + @override + final CacaoRequestPayload cacaoPayload; + + @override + String toString() { + return 'PendingAuthRequest(id: $id, pairingTopic: $pairingTopic, metadata: $metadata, cacaoPayload: $cacaoPayload)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PendingAuthRequestImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.pairingTopic, pairingTopic) || + other.pairingTopic == pairingTopic) && + (identical(other.metadata, metadata) || + other.metadata == metadata) && + (identical(other.cacaoPayload, cacaoPayload) || + other.cacaoPayload == cacaoPayload)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => + Object.hash(runtimeType, id, pairingTopic, metadata, cacaoPayload); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$PendingAuthRequestImplCopyWith<_$PendingAuthRequestImpl> get copyWith => + __$$PendingAuthRequestImplCopyWithImpl<_$PendingAuthRequestImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$PendingAuthRequestImplToJson( + this, + ); + } +} + +abstract class _PendingAuthRequest implements PendingAuthRequest { + const factory _PendingAuthRequest( + {required final int id, + required final String pairingTopic, + required final ConnectionMetadata metadata, + required final CacaoRequestPayload cacaoPayload}) = + _$PendingAuthRequestImpl; + + factory _PendingAuthRequest.fromJson(Map json) = + _$PendingAuthRequestImpl.fromJson; + + @override + int get id; + @override + String get pairingTopic; + @override + ConnectionMetadata get metadata; + @override + CacaoRequestPayload get cacaoPayload; + @override + @JsonKey(ignore: true) + _$$PendingAuthRequestImplCopyWith<_$PendingAuthRequestImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/apis/sign_api/models/auth/auth_client_models.g.dart b/lib/apis/sign_api/models/auth/auth_client_models.g.dart new file mode 100644 index 00000000..d75b386a --- /dev/null +++ b/lib/apis/sign_api/models/auth/auth_client_models.g.dart @@ -0,0 +1,72 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'auth_client_models.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$AuthPayloadParamsImpl _$$AuthPayloadParamsImplFromJson( + Map json) => + _$AuthPayloadParamsImpl( + chainId: json['chainId'] as String, + aud: json['aud'] as String, + domain: json['domain'] as String, + nonce: json['nonce'] as String, + type: json['type'] as String, + version: json['version'] as String, + iat: json['iat'] as String, + nbf: json['nbf'] as String?, + exp: json['exp'] as String?, + statement: json['statement'] as String?, + requestId: json['requestId'] as String?, + resources: (json['resources'] as List?) + ?.map((e) => e as String) + .toList(), + ); + +Map _$$AuthPayloadParamsImplToJson( + _$AuthPayloadParamsImpl instance) { + final val = { + 'chainId': instance.chainId, + 'aud': instance.aud, + 'domain': instance.domain, + 'nonce': instance.nonce, + 'type': instance.type, + 'version': instance.version, + 'iat': instance.iat, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('nbf', instance.nbf); + writeNotNull('exp', instance.exp); + writeNotNull('statement', instance.statement); + writeNotNull('requestId', instance.requestId); + writeNotNull('resources', instance.resources); + return val; +} + +_$PendingAuthRequestImpl _$$PendingAuthRequestImplFromJson( + Map json) => + _$PendingAuthRequestImpl( + id: json['id'] as int, + pairingTopic: json['pairingTopic'] as String, + metadata: + ConnectionMetadata.fromJson(json['metadata'] as Map), + cacaoPayload: CacaoRequestPayload.fromJson( + json['cacaoPayload'] as Map), + ); + +Map _$$PendingAuthRequestImplToJson( + _$PendingAuthRequestImpl instance) => + { + 'id': instance.id, + 'pairingTopic': instance.pairingTopic, + 'metadata': instance.metadata.toJson(), + 'cacaoPayload': instance.cacaoPayload.toJson(), + }; diff --git a/lib/apis/sign_api/models/auth/common_auth_models.dart b/lib/apis/sign_api/models/auth/common_auth_models.dart new file mode 100644 index 00000000..973760fc --- /dev/null +++ b/lib/apis/sign_api/models/auth/common_auth_models.dart @@ -0,0 +1,196 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/session_auth_models.dart'; + +part 'common_auth_models.g.dart'; +part 'common_auth_models.freezed.dart'; + +@freezed +class AuthPublicKey with _$AuthPublicKey { + @JsonSerializable(includeIfNull: false) + const factory AuthPublicKey({ + required String publicKey, + }) = _AuthPublicKey; + + factory AuthPublicKey.fromJson(Map json) => + _$AuthPublicKeyFromJson(json); +} + +@freezed +class CacaoRequestPayload with _$CacaoRequestPayload { + @JsonSerializable(includeIfNull: false) + const factory CacaoRequestPayload({ + required String domain, + required String aud, + required String version, + required String nonce, + required String iat, + String? nbf, + String? exp, + String? statement, + String? requestId, + List? resources, + }) = _CacaoRequestPayload; + + factory CacaoRequestPayload.fromPayloadParams(AuthPayloadParams params) { + return CacaoRequestPayload( + domain: params.domain, + aud: params.aud, + version: params.version, + nonce: params.nonce, + iat: params.iat, + nbf: params.nbf, + exp: params.exp, + statement: params.statement, + requestId: params.requestId, + resources: params.resources, + ); + } + + factory CacaoRequestPayload.fromSessionAuthPayload( + SessionAuthPayload params, + ) { + return CacaoRequestPayload( + domain: params.domain, + aud: params.aud, + version: params.version, + nonce: params.nonce, + iat: params.iat, + nbf: params.nbf, + exp: params.exp, + statement: params.statement, + requestId: params.requestId, + resources: params.resources, + ); + } + + factory CacaoRequestPayload.fromCacaoPayload(CacaoPayload payload) { + return CacaoRequestPayload( + domain: payload.domain, + aud: payload.aud, + version: payload.version, + nonce: payload.nonce, + iat: payload.iat, + nbf: payload.nbf, + exp: payload.exp, + statement: payload.statement, + requestId: payload.requestId, + resources: payload.resources, + ); + } + + factory CacaoRequestPayload.fromJson(Map json) => + _$CacaoRequestPayloadFromJson(json); +} + +@freezed +class CacaoPayload with _$CacaoPayload { + @JsonSerializable(includeIfNull: false) + const factory CacaoPayload({ + required String iss, + required String domain, + required String aud, + required String version, + required String nonce, + required String iat, + String? nbf, + String? exp, + String? statement, + String? requestId, + List? resources, + }) = _CacaoPayload; + + factory CacaoPayload.fromRequestPayload({ + required String issuer, + required CacaoRequestPayload payload, + }) { + return CacaoPayload( + iss: issuer, + domain: payload.domain, + aud: payload.aud, + version: payload.version, + nonce: payload.nonce, + iat: payload.iat, + nbf: payload.nbf, + exp: payload.exp, + statement: payload.statement, + requestId: payload.requestId, + resources: payload.resources, + ); + } + + factory CacaoPayload.fromJson(Map json) => + _$CacaoPayloadFromJson(json); +} + +@freezed +class CacaoHeader with _$CacaoHeader { + static const EIP4361 = 'eip4361'; + static const CAIP122 = 'caip122'; + + @JsonSerializable(includeIfNull: false) + const factory CacaoHeader({ + @Default('eip4361') String t, + }) = _CacaoHeader; + + factory CacaoHeader.fromJson(Map json) => + _$CacaoHeaderFromJson(json); +} + +@freezed +class CacaoSignature with _$CacaoSignature { + static const EIP191 = 'eip191'; + static const EIP1271 = 'eip1271'; + + @JsonSerializable(includeIfNull: false) + const factory CacaoSignature({ + required String t, + required String s, + String? m, + }) = _CacaoSignature; + + factory CacaoSignature.fromJson(Map json) => + _$CacaoSignatureFromJson(json); +} + +@freezed +class Cacao with _$Cacao { + @JsonSerializable(includeIfNull: false) + const factory Cacao({ + required CacaoHeader h, + required CacaoPayload p, + required CacaoSignature s, + }) = _Cacao; + + factory Cacao.fromJson(Map json) => _$CacaoFromJson(json); +} + +@freezed +class StoredCacao with _$StoredCacao { + @JsonSerializable(includeIfNull: false) + const factory StoredCacao({ + required int id, + required String pairingTopic, + required CacaoHeader h, + required CacaoPayload p, + required CacaoSignature s, + }) = _StoredCacao; + + factory StoredCacao.fromCacao({ + required int id, + required String pairingTopic, + required Cacao cacao, + }) { + return StoredCacao( + id: id, + pairingTopic: pairingTopic, + h: cacao.h, + p: cacao.p, + s: cacao.s, + ); + } + + factory StoredCacao.fromJson(Map json) => + _$StoredCacaoFromJson(json); +} diff --git a/lib/apis/auth_api/models/auth_client_models.freezed.dart b/lib/apis/sign_api/models/auth/common_auth_models.freezed.dart similarity index 71% rename from lib/apis/auth_api/models/auth_client_models.freezed.dart rename to lib/apis/sign_api/models/auth/common_auth_models.freezed.dart index ad9219b0..55109512 100644 --- a/lib/apis/auth_api/models/auth_client_models.freezed.dart +++ b/lib/apis/sign_api/models/auth/common_auth_models.freezed.dart @@ -3,7 +3,7 @@ // ignore_for_file: type=lint // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark -part of 'auth_client_models.dart'; +part of 'common_auth_models.dart'; // ************************************************************************** // FreezedGenerator @@ -153,392 +153,6 @@ abstract class _AuthPublicKey implements AuthPublicKey { throw _privateConstructorUsedError; } -AuthPayloadParams _$AuthPayloadParamsFromJson(Map json) { - return _AuthPayloadParams.fromJson(json); -} - -/// @nodoc -mixin _$AuthPayloadParams { - String get type => throw _privateConstructorUsedError; - String get chainId => throw _privateConstructorUsedError; - String get domain => throw _privateConstructorUsedError; - String get aud => throw _privateConstructorUsedError; - String get version => throw _privateConstructorUsedError; - String get nonce => throw _privateConstructorUsedError; - String get iat => throw _privateConstructorUsedError; - String? get nbf => throw _privateConstructorUsedError; - String? get exp => throw _privateConstructorUsedError; - String? get statement => throw _privateConstructorUsedError; - String? get requestId => throw _privateConstructorUsedError; - List? get resources => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $AuthPayloadParamsCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $AuthPayloadParamsCopyWith<$Res> { - factory $AuthPayloadParamsCopyWith( - AuthPayloadParams value, $Res Function(AuthPayloadParams) then) = - _$AuthPayloadParamsCopyWithImpl<$Res, AuthPayloadParams>; - @useResult - $Res call( - {String type, - String chainId, - String domain, - String aud, - String version, - String nonce, - String iat, - String? nbf, - String? exp, - String? statement, - String? requestId, - List? resources}); -} - -/// @nodoc -class _$AuthPayloadParamsCopyWithImpl<$Res, $Val extends AuthPayloadParams> - implements $AuthPayloadParamsCopyWith<$Res> { - _$AuthPayloadParamsCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? type = null, - Object? chainId = null, - Object? domain = null, - Object? aud = null, - Object? version = null, - Object? nonce = null, - Object? iat = null, - Object? nbf = freezed, - Object? exp = freezed, - Object? statement = freezed, - Object? requestId = freezed, - Object? resources = freezed, - }) { - return _then(_value.copyWith( - type: null == type - ? _value.type - : type // ignore: cast_nullable_to_non_nullable - as String, - chainId: null == chainId - ? _value.chainId - : chainId // ignore: cast_nullable_to_non_nullable - as String, - domain: null == domain - ? _value.domain - : domain // ignore: cast_nullable_to_non_nullable - as String, - aud: null == aud - ? _value.aud - : aud // ignore: cast_nullable_to_non_nullable - as String, - version: null == version - ? _value.version - : version // ignore: cast_nullable_to_non_nullable - as String, - nonce: null == nonce - ? _value.nonce - : nonce // ignore: cast_nullable_to_non_nullable - as String, - iat: null == iat - ? _value.iat - : iat // ignore: cast_nullable_to_non_nullable - as String, - nbf: freezed == nbf - ? _value.nbf - : nbf // ignore: cast_nullable_to_non_nullable - as String?, - exp: freezed == exp - ? _value.exp - : exp // ignore: cast_nullable_to_non_nullable - as String?, - statement: freezed == statement - ? _value.statement - : statement // ignore: cast_nullable_to_non_nullable - as String?, - requestId: freezed == requestId - ? _value.requestId - : requestId // ignore: cast_nullable_to_non_nullable - as String?, - resources: freezed == resources - ? _value.resources - : resources // ignore: cast_nullable_to_non_nullable - as List?, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$AuthPayloadParamsImplCopyWith<$Res> - implements $AuthPayloadParamsCopyWith<$Res> { - factory _$$AuthPayloadParamsImplCopyWith(_$AuthPayloadParamsImpl value, - $Res Function(_$AuthPayloadParamsImpl) then) = - __$$AuthPayloadParamsImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String type, - String chainId, - String domain, - String aud, - String version, - String nonce, - String iat, - String? nbf, - String? exp, - String? statement, - String? requestId, - List? resources}); -} - -/// @nodoc -class __$$AuthPayloadParamsImplCopyWithImpl<$Res> - extends _$AuthPayloadParamsCopyWithImpl<$Res, _$AuthPayloadParamsImpl> - implements _$$AuthPayloadParamsImplCopyWith<$Res> { - __$$AuthPayloadParamsImplCopyWithImpl(_$AuthPayloadParamsImpl _value, - $Res Function(_$AuthPayloadParamsImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? type = null, - Object? chainId = null, - Object? domain = null, - Object? aud = null, - Object? version = null, - Object? nonce = null, - Object? iat = null, - Object? nbf = freezed, - Object? exp = freezed, - Object? statement = freezed, - Object? requestId = freezed, - Object? resources = freezed, - }) { - return _then(_$AuthPayloadParamsImpl( - type: null == type - ? _value.type - : type // ignore: cast_nullable_to_non_nullable - as String, - chainId: null == chainId - ? _value.chainId - : chainId // ignore: cast_nullable_to_non_nullable - as String, - domain: null == domain - ? _value.domain - : domain // ignore: cast_nullable_to_non_nullable - as String, - aud: null == aud - ? _value.aud - : aud // ignore: cast_nullable_to_non_nullable - as String, - version: null == version - ? _value.version - : version // ignore: cast_nullable_to_non_nullable - as String, - nonce: null == nonce - ? _value.nonce - : nonce // ignore: cast_nullable_to_non_nullable - as String, - iat: null == iat - ? _value.iat - : iat // ignore: cast_nullable_to_non_nullable - as String, - nbf: freezed == nbf - ? _value.nbf - : nbf // ignore: cast_nullable_to_non_nullable - as String?, - exp: freezed == exp - ? _value.exp - : exp // ignore: cast_nullable_to_non_nullable - as String?, - statement: freezed == statement - ? _value.statement - : statement // ignore: cast_nullable_to_non_nullable - as String?, - requestId: freezed == requestId - ? _value.requestId - : requestId // ignore: cast_nullable_to_non_nullable - as String?, - resources: freezed == resources - ? _value._resources - : resources // ignore: cast_nullable_to_non_nullable - as List?, - )); - } -} - -/// @nodoc - -@JsonSerializable(includeIfNull: false) -class _$AuthPayloadParamsImpl implements _AuthPayloadParams { - const _$AuthPayloadParamsImpl( - {required this.type, - required this.chainId, - required this.domain, - required this.aud, - required this.version, - required this.nonce, - required this.iat, - this.nbf, - this.exp, - this.statement, - this.requestId, - final List? resources}) - : _resources = resources; - - factory _$AuthPayloadParamsImpl.fromJson(Map json) => - _$$AuthPayloadParamsImplFromJson(json); - - @override - final String type; - @override - final String chainId; - @override - final String domain; - @override - final String aud; - @override - final String version; - @override - final String nonce; - @override - final String iat; - @override - final String? nbf; - @override - final String? exp; - @override - final String? statement; - @override - final String? requestId; - final List? _resources; - @override - List? get resources { - final value = _resources; - if (value == null) return null; - if (_resources is EqualUnmodifiableListView) return _resources; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(value); - } - - @override - String toString() { - return 'AuthPayloadParams(type: $type, chainId: $chainId, domain: $domain, aud: $aud, version: $version, nonce: $nonce, iat: $iat, nbf: $nbf, exp: $exp, statement: $statement, requestId: $requestId, resources: $resources)'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$AuthPayloadParamsImpl && - (identical(other.type, type) || other.type == type) && - (identical(other.chainId, chainId) || other.chainId == chainId) && - (identical(other.domain, domain) || other.domain == domain) && - (identical(other.aud, aud) || other.aud == aud) && - (identical(other.version, version) || other.version == version) && - (identical(other.nonce, nonce) || other.nonce == nonce) && - (identical(other.iat, iat) || other.iat == iat) && - (identical(other.nbf, nbf) || other.nbf == nbf) && - (identical(other.exp, exp) || other.exp == exp) && - (identical(other.statement, statement) || - other.statement == statement) && - (identical(other.requestId, requestId) || - other.requestId == requestId) && - const DeepCollectionEquality() - .equals(other._resources, _resources)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => Object.hash( - runtimeType, - type, - chainId, - domain, - aud, - version, - nonce, - iat, - nbf, - exp, - statement, - requestId, - const DeepCollectionEquality().hash(_resources)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$AuthPayloadParamsImplCopyWith<_$AuthPayloadParamsImpl> get copyWith => - __$$AuthPayloadParamsImplCopyWithImpl<_$AuthPayloadParamsImpl>( - this, _$identity); - - @override - Map toJson() { - return _$$AuthPayloadParamsImplToJson( - this, - ); - } -} - -abstract class _AuthPayloadParams implements AuthPayloadParams { - const factory _AuthPayloadParams( - {required final String type, - required final String chainId, - required final String domain, - required final String aud, - required final String version, - required final String nonce, - required final String iat, - final String? nbf, - final String? exp, - final String? statement, - final String? requestId, - final List? resources}) = _$AuthPayloadParamsImpl; - - factory _AuthPayloadParams.fromJson(Map json) = - _$AuthPayloadParamsImpl.fromJson; - - @override - String get type; - @override - String get chainId; - @override - String get domain; - @override - String get aud; - @override - String get version; - @override - String get nonce; - @override - String get iat; - @override - String? get nbf; - @override - String? get exp; - @override - String? get statement; - @override - String? get requestId; - @override - List? get resources; - @override - @JsonKey(ignore: true) - _$$AuthPayloadParamsImplCopyWith<_$AuthPayloadParamsImpl> get copyWith => - throw _privateConstructorUsedError; -} - CacaoRequestPayload _$CacaoRequestPayloadFromJson(Map json) { return _CacaoRequestPayload.fromJson(json); } @@ -2017,234 +1631,3 @@ abstract class _StoredCacao implements StoredCacao { _$$StoredCacaoImplCopyWith<_$StoredCacaoImpl> get copyWith => throw _privateConstructorUsedError; } - -PendingAuthRequest _$PendingAuthRequestFromJson(Map json) { - return _PendingAuthRequest.fromJson(json); -} - -/// @nodoc -mixin _$PendingAuthRequest { - int get id => throw _privateConstructorUsedError; - String get pairingTopic => throw _privateConstructorUsedError; - ConnectionMetadata get metadata => throw _privateConstructorUsedError; - CacaoRequestPayload get cacaoPayload => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $PendingAuthRequestCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $PendingAuthRequestCopyWith<$Res> { - factory $PendingAuthRequestCopyWith( - PendingAuthRequest value, $Res Function(PendingAuthRequest) then) = - _$PendingAuthRequestCopyWithImpl<$Res, PendingAuthRequest>; - @useResult - $Res call( - {int id, - String pairingTopic, - ConnectionMetadata metadata, - CacaoRequestPayload cacaoPayload}); - - $ConnectionMetadataCopyWith<$Res> get metadata; - $CacaoRequestPayloadCopyWith<$Res> get cacaoPayload; -} - -/// @nodoc -class _$PendingAuthRequestCopyWithImpl<$Res, $Val extends PendingAuthRequest> - implements $PendingAuthRequestCopyWith<$Res> { - _$PendingAuthRequestCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? pairingTopic = null, - Object? metadata = null, - Object? cacaoPayload = null, - }) { - return _then(_value.copyWith( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as int, - pairingTopic: null == pairingTopic - ? _value.pairingTopic - : pairingTopic // ignore: cast_nullable_to_non_nullable - as String, - metadata: null == metadata - ? _value.metadata - : metadata // ignore: cast_nullable_to_non_nullable - as ConnectionMetadata, - cacaoPayload: null == cacaoPayload - ? _value.cacaoPayload - : cacaoPayload // ignore: cast_nullable_to_non_nullable - as CacaoRequestPayload, - ) as $Val); - } - - @override - @pragma('vm:prefer-inline') - $ConnectionMetadataCopyWith<$Res> get metadata { - return $ConnectionMetadataCopyWith<$Res>(_value.metadata, (value) { - return _then(_value.copyWith(metadata: value) as $Val); - }); - } - - @override - @pragma('vm:prefer-inline') - $CacaoRequestPayloadCopyWith<$Res> get cacaoPayload { - return $CacaoRequestPayloadCopyWith<$Res>(_value.cacaoPayload, (value) { - return _then(_value.copyWith(cacaoPayload: value) as $Val); - }); - } -} - -/// @nodoc -abstract class _$$PendingAuthRequestImplCopyWith<$Res> - implements $PendingAuthRequestCopyWith<$Res> { - factory _$$PendingAuthRequestImplCopyWith(_$PendingAuthRequestImpl value, - $Res Function(_$PendingAuthRequestImpl) then) = - __$$PendingAuthRequestImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {int id, - String pairingTopic, - ConnectionMetadata metadata, - CacaoRequestPayload cacaoPayload}); - - @override - $ConnectionMetadataCopyWith<$Res> get metadata; - @override - $CacaoRequestPayloadCopyWith<$Res> get cacaoPayload; -} - -/// @nodoc -class __$$PendingAuthRequestImplCopyWithImpl<$Res> - extends _$PendingAuthRequestCopyWithImpl<$Res, _$PendingAuthRequestImpl> - implements _$$PendingAuthRequestImplCopyWith<$Res> { - __$$PendingAuthRequestImplCopyWithImpl(_$PendingAuthRequestImpl _value, - $Res Function(_$PendingAuthRequestImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? pairingTopic = null, - Object? metadata = null, - Object? cacaoPayload = null, - }) { - return _then(_$PendingAuthRequestImpl( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as int, - pairingTopic: null == pairingTopic - ? _value.pairingTopic - : pairingTopic // ignore: cast_nullable_to_non_nullable - as String, - metadata: null == metadata - ? _value.metadata - : metadata // ignore: cast_nullable_to_non_nullable - as ConnectionMetadata, - cacaoPayload: null == cacaoPayload - ? _value.cacaoPayload - : cacaoPayload // ignore: cast_nullable_to_non_nullable - as CacaoRequestPayload, - )); - } -} - -/// @nodoc - -@JsonSerializable(includeIfNull: false) -class _$PendingAuthRequestImpl implements _PendingAuthRequest { - const _$PendingAuthRequestImpl( - {required this.id, - required this.pairingTopic, - required this.metadata, - required this.cacaoPayload}); - - factory _$PendingAuthRequestImpl.fromJson(Map json) => - _$$PendingAuthRequestImplFromJson(json); - - @override - final int id; - @override - final String pairingTopic; - @override - final ConnectionMetadata metadata; - @override - final CacaoRequestPayload cacaoPayload; - - @override - String toString() { - return 'PendingAuthRequest(id: $id, pairingTopic: $pairingTopic, metadata: $metadata, cacaoPayload: $cacaoPayload)'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$PendingAuthRequestImpl && - (identical(other.id, id) || other.id == id) && - (identical(other.pairingTopic, pairingTopic) || - other.pairingTopic == pairingTopic) && - (identical(other.metadata, metadata) || - other.metadata == metadata) && - (identical(other.cacaoPayload, cacaoPayload) || - other.cacaoPayload == cacaoPayload)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => - Object.hash(runtimeType, id, pairingTopic, metadata, cacaoPayload); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$PendingAuthRequestImplCopyWith<_$PendingAuthRequestImpl> get copyWith => - __$$PendingAuthRequestImplCopyWithImpl<_$PendingAuthRequestImpl>( - this, _$identity); - - @override - Map toJson() { - return _$$PendingAuthRequestImplToJson( - this, - ); - } -} - -abstract class _PendingAuthRequest implements PendingAuthRequest { - const factory _PendingAuthRequest( - {required final int id, - required final String pairingTopic, - required final ConnectionMetadata metadata, - required final CacaoRequestPayload cacaoPayload}) = - _$PendingAuthRequestImpl; - - factory _PendingAuthRequest.fromJson(Map json) = - _$PendingAuthRequestImpl.fromJson; - - @override - int get id; - @override - String get pairingTopic; - @override - ConnectionMetadata get metadata; - @override - CacaoRequestPayload get cacaoPayload; - @override - @JsonKey(ignore: true) - _$$PendingAuthRequestImplCopyWith<_$PendingAuthRequestImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/apis/auth_api/models/auth_client_models.g.dart b/lib/apis/sign_api/models/auth/common_auth_models.g.dart similarity index 70% rename from lib/apis/auth_api/models/auth_client_models.g.dart rename to lib/apis/sign_api/models/auth/common_auth_models.g.dart index db73cc6d..23fd94e6 100644 --- a/lib/apis/auth_api/models/auth_client_models.g.dart +++ b/lib/apis/sign_api/models/auth/common_auth_models.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'auth_client_models.dart'; +part of 'common_auth_models.dart'; // ************************************************************************** // JsonSerializableGenerator @@ -16,51 +16,6 @@ Map _$$AuthPublicKeyImplToJson(_$AuthPublicKeyImpl instance) => 'publicKey': instance.publicKey, }; -_$AuthPayloadParamsImpl _$$AuthPayloadParamsImplFromJson( - Map json) => - _$AuthPayloadParamsImpl( - type: json['type'] as String, - chainId: json['chainId'] as String, - domain: json['domain'] as String, - aud: json['aud'] as String, - version: json['version'] as String, - nonce: json['nonce'] as String, - iat: json['iat'] as String, - nbf: json['nbf'] as String?, - exp: json['exp'] as String?, - statement: json['statement'] as String?, - requestId: json['requestId'] as String?, - resources: (json['resources'] as List?) - ?.map((e) => e as String) - .toList(), - ); - -Map _$$AuthPayloadParamsImplToJson( - _$AuthPayloadParamsImpl instance) { - final val = { - 'type': instance.type, - 'chainId': instance.chainId, - 'domain': instance.domain, - 'aud': instance.aud, - 'version': instance.version, - 'nonce': instance.nonce, - 'iat': instance.iat, - }; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('nbf', instance.nbf); - writeNotNull('exp', instance.exp); - writeNotNull('statement', instance.statement); - writeNotNull('requestId', instance.requestId); - writeNotNull('resources', instance.resources); - return val; -} - _$CacaoRequestPayloadImpl _$$CacaoRequestPayloadImplFromJson( Map json) => _$CacaoRequestPayloadImpl( @@ -207,23 +162,3 @@ Map _$$StoredCacaoImplToJson(_$StoredCacaoImpl instance) => 'p': instance.p.toJson(), 's': instance.s.toJson(), }; - -_$PendingAuthRequestImpl _$$PendingAuthRequestImplFromJson( - Map json) => - _$PendingAuthRequestImpl( - id: json['id'] as int, - pairingTopic: json['pairingTopic'] as String, - metadata: - ConnectionMetadata.fromJson(json['metadata'] as Map), - cacaoPayload: CacaoRequestPayload.fromJson( - json['cacaoPayload'] as Map), - ); - -Map _$$PendingAuthRequestImplToJson( - _$PendingAuthRequestImpl instance) => - { - 'id': instance.id, - 'pairingTopic': instance.pairingTopic, - 'metadata': instance.metadata.toJson(), - 'cacaoPayload': instance.cacaoPayload.toJson(), - }; diff --git a/lib/apis/sign_api/models/auth/session_auth_events.dart b/lib/apis/sign_api/models/auth/session_auth_events.dart new file mode 100644 index 00000000..3c7cce32 --- /dev/null +++ b/lib/apis/sign_api/models/auth/session_auth_events.dart @@ -0,0 +1,71 @@ +import 'dart:convert'; + +import 'package:event/event.dart'; +import 'package:walletconnect_flutter_v2/apis/core/verify/models/verify_context.dart'; +import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; +import 'package:walletconnect_flutter_v2/apis/models/json_rpc_error.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/common_auth_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/session_models.dart'; + +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/session_auth_models.dart'; + +class SessionAuthRequest extends EventArgs { + final int id; + final String topic; + final SessionAuthPayload authPayload; + final ConnectionMetadata requester; + final VerifyContext? verifyContext; + + SessionAuthRequest({ + required this.id, + required this.topic, + required this.authPayload, + required this.requester, + this.verifyContext, + }); + + Map toJson() => { + 'id': id, + 'topic': topic, + 'authPayload': authPayload.toJson(), + 'requester': requester.toJson(), + 'verifyContext': verifyContext?.toJson(), + }; + + @override + String toString() { + return 'SessionAuthRequest(${jsonEncode(toJson())})'; + } +} + +class SessionAuthResponse extends EventArgs { + final int id; + final String topic; + final List? auths; + final SessionData? session; + final WalletConnectError? error; + final JsonRpcError? jsonRpcError; + + SessionAuthResponse({ + required this.id, + required this.topic, + this.auths, + this.session, + this.error, + this.jsonRpcError, + }); + + Map toJson() => { + 'id': id, + 'topic': topic, + if (auths != null) 'auths': auths, + if (session != null) 'session': session!.toJson(), + if (error != null) 'error': error!.toJson(), + if (jsonRpcError != null) 'jsonRpcError': jsonRpcError!.toJson(), + }; + + @override + String toString() { + return 'SessionAuthResponse(${jsonEncode(toJson())})'; + } +} diff --git a/lib/apis/sign_api/models/auth/session_auth_models.dart b/lib/apis/sign_api/models/auth/session_auth_models.dart new file mode 100644 index 00000000..4bd920c0 --- /dev/null +++ b/lib/apis/sign_api/models/auth/session_auth_models.dart @@ -0,0 +1,117 @@ +import 'dart:async'; + +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:walletconnect_flutter_v2/apis/core/verify/models/verify_context.dart'; +import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; + +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/common_auth_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/session_auth_events.dart'; + +part 'session_auth_models.g.dart'; +part 'session_auth_models.freezed.dart'; + +// TODO this should be under sign_client_models.dart probably +class SessionAuthRequestResponse { + final int id; + final String pairingTopic; + final Completer completer; + final Uri? uri; + + SessionAuthRequestResponse({ + required this.id, + required this.pairingTopic, + required this.completer, + this.uri, + }); +} + +@freezed +class SessionAuthRequestParams with _$SessionAuthRequestParams { + @JsonSerializable(includeIfNull: false) + const factory SessionAuthRequestParams({ + required List chains, + required String domain, + required String nonce, + required String uri, + // + CacaoHeader? type, + String? nbf, + String? exp, + String? statement, + String? requestId, + List? resources, + int? expiry, + @Default([]) List? methods, + }) = _SessionAuthRequestParams; + // + factory SessionAuthRequestParams.fromJson(Map json) => + _$SessionAuthRequestParamsFromJson(json); +} + +@freezed +class SessionAuthPayload with _$SessionAuthPayload { + @JsonSerializable(includeIfNull: false) + const factory SessionAuthPayload({ + required List chains, + required String domain, + required String nonce, + required String aud, + required String type, + // + required String version, + required String iat, + // + String? nbf, + String? exp, + String? statement, + String? requestId, + List? resources, + }) = _SessionAuthPayload; + + factory SessionAuthPayload.fromRequestParams( + SessionAuthRequestParams params, + ) { + final now = DateTime.now(); + return SessionAuthPayload( + chains: params.chains, + domain: params.domain, + nonce: params.nonce, + aud: params.uri, + type: params.type?.t ?? 'eip4361', + version: '1', + iat: DateTime.utc( + now.year, + now.month, + now.day, + now.hour, + now.minute, + now.second, + now.millisecond, + ).toIso8601String(), + nbf: params.nbf, + exp: params.exp, + statement: params.statement, + requestId: params.requestId, + resources: params.resources, + ); + } + + factory SessionAuthPayload.fromJson(Map json) => + _$SessionAuthPayloadFromJson(json); +} + +@freezed +class PendingSessionAuthRequest with _$PendingSessionAuthRequest { + @JsonSerializable(includeIfNull: false) + const factory PendingSessionAuthRequest({ + required int id, + required String pairingTopic, + required ConnectionMetadata requester, + required int expiryTimestamp, + required CacaoRequestPayload authPayload, + required VerifyContext verifyContext, + }) = _PendingSessionAuthRequest; + + factory PendingSessionAuthRequest.fromJson(Map json) => + _$PendingSessionAuthRequestFromJson(json); +} diff --git a/lib/apis/sign_api/models/auth/session_auth_models.freezed.dart b/lib/apis/sign_api/models/auth/session_auth_models.freezed.dart new file mode 100644 index 00000000..c8ab6514 --- /dev/null +++ b/lib/apis/sign_api/models/auth/session_auth_models.freezed.dart @@ -0,0 +1,1125 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'session_auth_models.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +SessionAuthRequestParams _$SessionAuthRequestParamsFromJson( + Map json) { + return _SessionAuthRequestParams.fromJson(json); +} + +/// @nodoc +mixin _$SessionAuthRequestParams { + List get chains => throw _privateConstructorUsedError; + String get domain => throw _privateConstructorUsedError; + String get nonce => throw _privateConstructorUsedError; + String get uri => throw _privateConstructorUsedError; // + CacaoHeader? get type => throw _privateConstructorUsedError; + String? get nbf => throw _privateConstructorUsedError; + String? get exp => throw _privateConstructorUsedError; + String? get statement => throw _privateConstructorUsedError; + String? get requestId => throw _privateConstructorUsedError; + List? get resources => throw _privateConstructorUsedError; + int? get expiry => throw _privateConstructorUsedError; + List? get methods => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $SessionAuthRequestParamsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SessionAuthRequestParamsCopyWith<$Res> { + factory $SessionAuthRequestParamsCopyWith(SessionAuthRequestParams value, + $Res Function(SessionAuthRequestParams) then) = + _$SessionAuthRequestParamsCopyWithImpl<$Res, SessionAuthRequestParams>; + @useResult + $Res call( + {List chains, + String domain, + String nonce, + String uri, + CacaoHeader? type, + String? nbf, + String? exp, + String? statement, + String? requestId, + List? resources, + int? expiry, + List? methods}); + + $CacaoHeaderCopyWith<$Res>? get type; +} + +/// @nodoc +class _$SessionAuthRequestParamsCopyWithImpl<$Res, + $Val extends SessionAuthRequestParams> + implements $SessionAuthRequestParamsCopyWith<$Res> { + _$SessionAuthRequestParamsCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? chains = null, + Object? domain = null, + Object? nonce = null, + Object? uri = null, + Object? type = freezed, + Object? nbf = freezed, + Object? exp = freezed, + Object? statement = freezed, + Object? requestId = freezed, + Object? resources = freezed, + Object? expiry = freezed, + Object? methods = freezed, + }) { + return _then(_value.copyWith( + chains: null == chains + ? _value.chains + : chains // ignore: cast_nullable_to_non_nullable + as List, + domain: null == domain + ? _value.domain + : domain // ignore: cast_nullable_to_non_nullable + as String, + nonce: null == nonce + ? _value.nonce + : nonce // ignore: cast_nullable_to_non_nullable + as String, + uri: null == uri + ? _value.uri + : uri // ignore: cast_nullable_to_non_nullable + as String, + type: freezed == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as CacaoHeader?, + nbf: freezed == nbf + ? _value.nbf + : nbf // ignore: cast_nullable_to_non_nullable + as String?, + exp: freezed == exp + ? _value.exp + : exp // ignore: cast_nullable_to_non_nullable + as String?, + statement: freezed == statement + ? _value.statement + : statement // ignore: cast_nullable_to_non_nullable + as String?, + requestId: freezed == requestId + ? _value.requestId + : requestId // ignore: cast_nullable_to_non_nullable + as String?, + resources: freezed == resources + ? _value.resources + : resources // ignore: cast_nullable_to_non_nullable + as List?, + expiry: freezed == expiry + ? _value.expiry + : expiry // ignore: cast_nullable_to_non_nullable + as int?, + methods: freezed == methods + ? _value.methods + : methods // ignore: cast_nullable_to_non_nullable + as List?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $CacaoHeaderCopyWith<$Res>? get type { + if (_value.type == null) { + return null; + } + + return $CacaoHeaderCopyWith<$Res>(_value.type!, (value) { + return _then(_value.copyWith(type: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$SessionAuthRequestParamsImplCopyWith<$Res> + implements $SessionAuthRequestParamsCopyWith<$Res> { + factory _$$SessionAuthRequestParamsImplCopyWith( + _$SessionAuthRequestParamsImpl value, + $Res Function(_$SessionAuthRequestParamsImpl) then) = + __$$SessionAuthRequestParamsImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {List chains, + String domain, + String nonce, + String uri, + CacaoHeader? type, + String? nbf, + String? exp, + String? statement, + String? requestId, + List? resources, + int? expiry, + List? methods}); + + @override + $CacaoHeaderCopyWith<$Res>? get type; +} + +/// @nodoc +class __$$SessionAuthRequestParamsImplCopyWithImpl<$Res> + extends _$SessionAuthRequestParamsCopyWithImpl<$Res, + _$SessionAuthRequestParamsImpl> + implements _$$SessionAuthRequestParamsImplCopyWith<$Res> { + __$$SessionAuthRequestParamsImplCopyWithImpl( + _$SessionAuthRequestParamsImpl _value, + $Res Function(_$SessionAuthRequestParamsImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? chains = null, + Object? domain = null, + Object? nonce = null, + Object? uri = null, + Object? type = freezed, + Object? nbf = freezed, + Object? exp = freezed, + Object? statement = freezed, + Object? requestId = freezed, + Object? resources = freezed, + Object? expiry = freezed, + Object? methods = freezed, + }) { + return _then(_$SessionAuthRequestParamsImpl( + chains: null == chains + ? _value._chains + : chains // ignore: cast_nullable_to_non_nullable + as List, + domain: null == domain + ? _value.domain + : domain // ignore: cast_nullable_to_non_nullable + as String, + nonce: null == nonce + ? _value.nonce + : nonce // ignore: cast_nullable_to_non_nullable + as String, + uri: null == uri + ? _value.uri + : uri // ignore: cast_nullable_to_non_nullable + as String, + type: freezed == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as CacaoHeader?, + nbf: freezed == nbf + ? _value.nbf + : nbf // ignore: cast_nullable_to_non_nullable + as String?, + exp: freezed == exp + ? _value.exp + : exp // ignore: cast_nullable_to_non_nullable + as String?, + statement: freezed == statement + ? _value.statement + : statement // ignore: cast_nullable_to_non_nullable + as String?, + requestId: freezed == requestId + ? _value.requestId + : requestId // ignore: cast_nullable_to_non_nullable + as String?, + resources: freezed == resources + ? _value._resources + : resources // ignore: cast_nullable_to_non_nullable + as List?, + expiry: freezed == expiry + ? _value.expiry + : expiry // ignore: cast_nullable_to_non_nullable + as int?, + methods: freezed == methods + ? _value._methods + : methods // ignore: cast_nullable_to_non_nullable + as List?, + )); + } +} + +/// @nodoc + +@JsonSerializable(includeIfNull: false) +class _$SessionAuthRequestParamsImpl implements _SessionAuthRequestParams { + const _$SessionAuthRequestParamsImpl( + {required final List chains, + required this.domain, + required this.nonce, + required this.uri, + this.type, + this.nbf, + this.exp, + this.statement, + this.requestId, + final List? resources, + this.expiry, + final List? methods = const []}) + : _chains = chains, + _resources = resources, + _methods = methods; + + factory _$SessionAuthRequestParamsImpl.fromJson(Map json) => + _$$SessionAuthRequestParamsImplFromJson(json); + + final List _chains; + @override + List get chains { + if (_chains is EqualUnmodifiableListView) return _chains; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_chains); + } + + @override + final String domain; + @override + final String nonce; + @override + final String uri; +// + @override + final CacaoHeader? type; + @override + final String? nbf; + @override + final String? exp; + @override + final String? statement; + @override + final String? requestId; + final List? _resources; + @override + List? get resources { + final value = _resources; + if (value == null) return null; + if (_resources is EqualUnmodifiableListView) return _resources; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + final int? expiry; + final List? _methods; + @override + @JsonKey() + List? get methods { + final value = _methods; + if (value == null) return null; + if (_methods is EqualUnmodifiableListView) return _methods; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + String toString() { + return 'SessionAuthRequestParams(chains: $chains, domain: $domain, nonce: $nonce, uri: $uri, type: $type, nbf: $nbf, exp: $exp, statement: $statement, requestId: $requestId, resources: $resources, expiry: $expiry, methods: $methods)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SessionAuthRequestParamsImpl && + const DeepCollectionEquality().equals(other._chains, _chains) && + (identical(other.domain, domain) || other.domain == domain) && + (identical(other.nonce, nonce) || other.nonce == nonce) && + (identical(other.uri, uri) || other.uri == uri) && + (identical(other.type, type) || other.type == type) && + (identical(other.nbf, nbf) || other.nbf == nbf) && + (identical(other.exp, exp) || other.exp == exp) && + (identical(other.statement, statement) || + other.statement == statement) && + (identical(other.requestId, requestId) || + other.requestId == requestId) && + const DeepCollectionEquality() + .equals(other._resources, _resources) && + (identical(other.expiry, expiry) || other.expiry == expiry) && + const DeepCollectionEquality().equals(other._methods, _methods)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_chains), + domain, + nonce, + uri, + type, + nbf, + exp, + statement, + requestId, + const DeepCollectionEquality().hash(_resources), + expiry, + const DeepCollectionEquality().hash(_methods)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SessionAuthRequestParamsImplCopyWith<_$SessionAuthRequestParamsImpl> + get copyWith => __$$SessionAuthRequestParamsImplCopyWithImpl< + _$SessionAuthRequestParamsImpl>(this, _$identity); + + @override + Map toJson() { + return _$$SessionAuthRequestParamsImplToJson( + this, + ); + } +} + +abstract class _SessionAuthRequestParams implements SessionAuthRequestParams { + const factory _SessionAuthRequestParams( + {required final List chains, + required final String domain, + required final String nonce, + required final String uri, + final CacaoHeader? type, + final String? nbf, + final String? exp, + final String? statement, + final String? requestId, + final List? resources, + final int? expiry, + final List? methods}) = _$SessionAuthRequestParamsImpl; + + factory _SessionAuthRequestParams.fromJson(Map json) = + _$SessionAuthRequestParamsImpl.fromJson; + + @override + List get chains; + @override + String get domain; + @override + String get nonce; + @override + String get uri; + @override // + CacaoHeader? get type; + @override + String? get nbf; + @override + String? get exp; + @override + String? get statement; + @override + String? get requestId; + @override + List? get resources; + @override + int? get expiry; + @override + List? get methods; + @override + @JsonKey(ignore: true) + _$$SessionAuthRequestParamsImplCopyWith<_$SessionAuthRequestParamsImpl> + get copyWith => throw _privateConstructorUsedError; +} + +SessionAuthPayload _$SessionAuthPayloadFromJson(Map json) { + return _SessionAuthPayload.fromJson(json); +} + +/// @nodoc +mixin _$SessionAuthPayload { + List get chains => throw _privateConstructorUsedError; + String get domain => throw _privateConstructorUsedError; + String get nonce => throw _privateConstructorUsedError; + String get aud => throw _privateConstructorUsedError; + String get type => throw _privateConstructorUsedError; // + String get version => throw _privateConstructorUsedError; + String get iat => throw _privateConstructorUsedError; // + String? get nbf => throw _privateConstructorUsedError; + String? get exp => throw _privateConstructorUsedError; + String? get statement => throw _privateConstructorUsedError; + String? get requestId => throw _privateConstructorUsedError; + List? get resources => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $SessionAuthPayloadCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SessionAuthPayloadCopyWith<$Res> { + factory $SessionAuthPayloadCopyWith( + SessionAuthPayload value, $Res Function(SessionAuthPayload) then) = + _$SessionAuthPayloadCopyWithImpl<$Res, SessionAuthPayload>; + @useResult + $Res call( + {List chains, + String domain, + String nonce, + String aud, + String type, + String version, + String iat, + String? nbf, + String? exp, + String? statement, + String? requestId, + List? resources}); +} + +/// @nodoc +class _$SessionAuthPayloadCopyWithImpl<$Res, $Val extends SessionAuthPayload> + implements $SessionAuthPayloadCopyWith<$Res> { + _$SessionAuthPayloadCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? chains = null, + Object? domain = null, + Object? nonce = null, + Object? aud = null, + Object? type = null, + Object? version = null, + Object? iat = null, + Object? nbf = freezed, + Object? exp = freezed, + Object? statement = freezed, + Object? requestId = freezed, + Object? resources = freezed, + }) { + return _then(_value.copyWith( + chains: null == chains + ? _value.chains + : chains // ignore: cast_nullable_to_non_nullable + as List, + domain: null == domain + ? _value.domain + : domain // ignore: cast_nullable_to_non_nullable + as String, + nonce: null == nonce + ? _value.nonce + : nonce // ignore: cast_nullable_to_non_nullable + as String, + aud: null == aud + ? _value.aud + : aud // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as String, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as String, + iat: null == iat + ? _value.iat + : iat // ignore: cast_nullable_to_non_nullable + as String, + nbf: freezed == nbf + ? _value.nbf + : nbf // ignore: cast_nullable_to_non_nullable + as String?, + exp: freezed == exp + ? _value.exp + : exp // ignore: cast_nullable_to_non_nullable + as String?, + statement: freezed == statement + ? _value.statement + : statement // ignore: cast_nullable_to_non_nullable + as String?, + requestId: freezed == requestId + ? _value.requestId + : requestId // ignore: cast_nullable_to_non_nullable + as String?, + resources: freezed == resources + ? _value.resources + : resources // ignore: cast_nullable_to_non_nullable + as List?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$SessionAuthPayloadImplCopyWith<$Res> + implements $SessionAuthPayloadCopyWith<$Res> { + factory _$$SessionAuthPayloadImplCopyWith(_$SessionAuthPayloadImpl value, + $Res Function(_$SessionAuthPayloadImpl) then) = + __$$SessionAuthPayloadImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {List chains, + String domain, + String nonce, + String aud, + String type, + String version, + String iat, + String? nbf, + String? exp, + String? statement, + String? requestId, + List? resources}); +} + +/// @nodoc +class __$$SessionAuthPayloadImplCopyWithImpl<$Res> + extends _$SessionAuthPayloadCopyWithImpl<$Res, _$SessionAuthPayloadImpl> + implements _$$SessionAuthPayloadImplCopyWith<$Res> { + __$$SessionAuthPayloadImplCopyWithImpl(_$SessionAuthPayloadImpl _value, + $Res Function(_$SessionAuthPayloadImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? chains = null, + Object? domain = null, + Object? nonce = null, + Object? aud = null, + Object? type = null, + Object? version = null, + Object? iat = null, + Object? nbf = freezed, + Object? exp = freezed, + Object? statement = freezed, + Object? requestId = freezed, + Object? resources = freezed, + }) { + return _then(_$SessionAuthPayloadImpl( + chains: null == chains + ? _value._chains + : chains // ignore: cast_nullable_to_non_nullable + as List, + domain: null == domain + ? _value.domain + : domain // ignore: cast_nullable_to_non_nullable + as String, + nonce: null == nonce + ? _value.nonce + : nonce // ignore: cast_nullable_to_non_nullable + as String, + aud: null == aud + ? _value.aud + : aud // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as String, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as String, + iat: null == iat + ? _value.iat + : iat // ignore: cast_nullable_to_non_nullable + as String, + nbf: freezed == nbf + ? _value.nbf + : nbf // ignore: cast_nullable_to_non_nullable + as String?, + exp: freezed == exp + ? _value.exp + : exp // ignore: cast_nullable_to_non_nullable + as String?, + statement: freezed == statement + ? _value.statement + : statement // ignore: cast_nullable_to_non_nullable + as String?, + requestId: freezed == requestId + ? _value.requestId + : requestId // ignore: cast_nullable_to_non_nullable + as String?, + resources: freezed == resources + ? _value._resources + : resources // ignore: cast_nullable_to_non_nullable + as List?, + )); + } +} + +/// @nodoc + +@JsonSerializable(includeIfNull: false) +class _$SessionAuthPayloadImpl implements _SessionAuthPayload { + const _$SessionAuthPayloadImpl( + {required final List chains, + required this.domain, + required this.nonce, + required this.aud, + required this.type, + required this.version, + required this.iat, + this.nbf, + this.exp, + this.statement, + this.requestId, + final List? resources}) + : _chains = chains, + _resources = resources; + + factory _$SessionAuthPayloadImpl.fromJson(Map json) => + _$$SessionAuthPayloadImplFromJson(json); + + final List _chains; + @override + List get chains { + if (_chains is EqualUnmodifiableListView) return _chains; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_chains); + } + + @override + final String domain; + @override + final String nonce; + @override + final String aud; + @override + final String type; +// + @override + final String version; + @override + final String iat; +// + @override + final String? nbf; + @override + final String? exp; + @override + final String? statement; + @override + final String? requestId; + final List? _resources; + @override + List? get resources { + final value = _resources; + if (value == null) return null; + if (_resources is EqualUnmodifiableListView) return _resources; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + String toString() { + return 'SessionAuthPayload(chains: $chains, domain: $domain, nonce: $nonce, aud: $aud, type: $type, version: $version, iat: $iat, nbf: $nbf, exp: $exp, statement: $statement, requestId: $requestId, resources: $resources)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SessionAuthPayloadImpl && + const DeepCollectionEquality().equals(other._chains, _chains) && + (identical(other.domain, domain) || other.domain == domain) && + (identical(other.nonce, nonce) || other.nonce == nonce) && + (identical(other.aud, aud) || other.aud == aud) && + (identical(other.type, type) || other.type == type) && + (identical(other.version, version) || other.version == version) && + (identical(other.iat, iat) || other.iat == iat) && + (identical(other.nbf, nbf) || other.nbf == nbf) && + (identical(other.exp, exp) || other.exp == exp) && + (identical(other.statement, statement) || + other.statement == statement) && + (identical(other.requestId, requestId) || + other.requestId == requestId) && + const DeepCollectionEquality() + .equals(other._resources, _resources)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_chains), + domain, + nonce, + aud, + type, + version, + iat, + nbf, + exp, + statement, + requestId, + const DeepCollectionEquality().hash(_resources)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SessionAuthPayloadImplCopyWith<_$SessionAuthPayloadImpl> get copyWith => + __$$SessionAuthPayloadImplCopyWithImpl<_$SessionAuthPayloadImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$SessionAuthPayloadImplToJson( + this, + ); + } +} + +abstract class _SessionAuthPayload implements SessionAuthPayload { + const factory _SessionAuthPayload( + {required final List chains, + required final String domain, + required final String nonce, + required final String aud, + required final String type, + required final String version, + required final String iat, + final String? nbf, + final String? exp, + final String? statement, + final String? requestId, + final List? resources}) = _$SessionAuthPayloadImpl; + + factory _SessionAuthPayload.fromJson(Map json) = + _$SessionAuthPayloadImpl.fromJson; + + @override + List get chains; + @override + String get domain; + @override + String get nonce; + @override + String get aud; + @override + String get type; + @override // + String get version; + @override + String get iat; + @override // + String? get nbf; + @override + String? get exp; + @override + String? get statement; + @override + String? get requestId; + @override + List? get resources; + @override + @JsonKey(ignore: true) + _$$SessionAuthPayloadImplCopyWith<_$SessionAuthPayloadImpl> get copyWith => + throw _privateConstructorUsedError; +} + +PendingSessionAuthRequest _$PendingSessionAuthRequestFromJson( + Map json) { + return _PendingSessionAuthRequest.fromJson(json); +} + +/// @nodoc +mixin _$PendingSessionAuthRequest { + int get id => throw _privateConstructorUsedError; + String get pairingTopic => throw _privateConstructorUsedError; + ConnectionMetadata get requester => throw _privateConstructorUsedError; + int get expiryTimestamp => throw _privateConstructorUsedError; + CacaoRequestPayload get authPayload => throw _privateConstructorUsedError; + VerifyContext get verifyContext => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $PendingSessionAuthRequestCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PendingSessionAuthRequestCopyWith<$Res> { + factory $PendingSessionAuthRequestCopyWith(PendingSessionAuthRequest value, + $Res Function(PendingSessionAuthRequest) then) = + _$PendingSessionAuthRequestCopyWithImpl<$Res, PendingSessionAuthRequest>; + @useResult + $Res call( + {int id, + String pairingTopic, + ConnectionMetadata requester, + int expiryTimestamp, + CacaoRequestPayload authPayload, + VerifyContext verifyContext}); + + $ConnectionMetadataCopyWith<$Res> get requester; + $CacaoRequestPayloadCopyWith<$Res> get authPayload; + $VerifyContextCopyWith<$Res> get verifyContext; +} + +/// @nodoc +class _$PendingSessionAuthRequestCopyWithImpl<$Res, + $Val extends PendingSessionAuthRequest> + implements $PendingSessionAuthRequestCopyWith<$Res> { + _$PendingSessionAuthRequestCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? pairingTopic = null, + Object? requester = null, + Object? expiryTimestamp = null, + Object? authPayload = null, + Object? verifyContext = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + pairingTopic: null == pairingTopic + ? _value.pairingTopic + : pairingTopic // ignore: cast_nullable_to_non_nullable + as String, + requester: null == requester + ? _value.requester + : requester // ignore: cast_nullable_to_non_nullable + as ConnectionMetadata, + expiryTimestamp: null == expiryTimestamp + ? _value.expiryTimestamp + : expiryTimestamp // ignore: cast_nullable_to_non_nullable + as int, + authPayload: null == authPayload + ? _value.authPayload + : authPayload // ignore: cast_nullable_to_non_nullable + as CacaoRequestPayload, + verifyContext: null == verifyContext + ? _value.verifyContext + : verifyContext // ignore: cast_nullable_to_non_nullable + as VerifyContext, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $ConnectionMetadataCopyWith<$Res> get requester { + return $ConnectionMetadataCopyWith<$Res>(_value.requester, (value) { + return _then(_value.copyWith(requester: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $CacaoRequestPayloadCopyWith<$Res> get authPayload { + return $CacaoRequestPayloadCopyWith<$Res>(_value.authPayload, (value) { + return _then(_value.copyWith(authPayload: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $VerifyContextCopyWith<$Res> get verifyContext { + return $VerifyContextCopyWith<$Res>(_value.verifyContext, (value) { + return _then(_value.copyWith(verifyContext: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$PendingSessionAuthRequestImplCopyWith<$Res> + implements $PendingSessionAuthRequestCopyWith<$Res> { + factory _$$PendingSessionAuthRequestImplCopyWith( + _$PendingSessionAuthRequestImpl value, + $Res Function(_$PendingSessionAuthRequestImpl) then) = + __$$PendingSessionAuthRequestImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int id, + String pairingTopic, + ConnectionMetadata requester, + int expiryTimestamp, + CacaoRequestPayload authPayload, + VerifyContext verifyContext}); + + @override + $ConnectionMetadataCopyWith<$Res> get requester; + @override + $CacaoRequestPayloadCopyWith<$Res> get authPayload; + @override + $VerifyContextCopyWith<$Res> get verifyContext; +} + +/// @nodoc +class __$$PendingSessionAuthRequestImplCopyWithImpl<$Res> + extends _$PendingSessionAuthRequestCopyWithImpl<$Res, + _$PendingSessionAuthRequestImpl> + implements _$$PendingSessionAuthRequestImplCopyWith<$Res> { + __$$PendingSessionAuthRequestImplCopyWithImpl( + _$PendingSessionAuthRequestImpl _value, + $Res Function(_$PendingSessionAuthRequestImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? pairingTopic = null, + Object? requester = null, + Object? expiryTimestamp = null, + Object? authPayload = null, + Object? verifyContext = null, + }) { + return _then(_$PendingSessionAuthRequestImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + pairingTopic: null == pairingTopic + ? _value.pairingTopic + : pairingTopic // ignore: cast_nullable_to_non_nullable + as String, + requester: null == requester + ? _value.requester + : requester // ignore: cast_nullable_to_non_nullable + as ConnectionMetadata, + expiryTimestamp: null == expiryTimestamp + ? _value.expiryTimestamp + : expiryTimestamp // ignore: cast_nullable_to_non_nullable + as int, + authPayload: null == authPayload + ? _value.authPayload + : authPayload // ignore: cast_nullable_to_non_nullable + as CacaoRequestPayload, + verifyContext: null == verifyContext + ? _value.verifyContext + : verifyContext // ignore: cast_nullable_to_non_nullable + as VerifyContext, + )); + } +} + +/// @nodoc + +@JsonSerializable(includeIfNull: false) +class _$PendingSessionAuthRequestImpl implements _PendingSessionAuthRequest { + const _$PendingSessionAuthRequestImpl( + {required this.id, + required this.pairingTopic, + required this.requester, + required this.expiryTimestamp, + required this.authPayload, + required this.verifyContext}); + + factory _$PendingSessionAuthRequestImpl.fromJson(Map json) => + _$$PendingSessionAuthRequestImplFromJson(json); + + @override + final int id; + @override + final String pairingTopic; + @override + final ConnectionMetadata requester; + @override + final int expiryTimestamp; + @override + final CacaoRequestPayload authPayload; + @override + final VerifyContext verifyContext; + + @override + String toString() { + return 'PendingSessionAuthRequest(id: $id, pairingTopic: $pairingTopic, requester: $requester, expiryTimestamp: $expiryTimestamp, authPayload: $authPayload, verifyContext: $verifyContext)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PendingSessionAuthRequestImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.pairingTopic, pairingTopic) || + other.pairingTopic == pairingTopic) && + (identical(other.requester, requester) || + other.requester == requester) && + (identical(other.expiryTimestamp, expiryTimestamp) || + other.expiryTimestamp == expiryTimestamp) && + (identical(other.authPayload, authPayload) || + other.authPayload == authPayload) && + (identical(other.verifyContext, verifyContext) || + other.verifyContext == verifyContext)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, id, pairingTopic, requester, + expiryTimestamp, authPayload, verifyContext); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$PendingSessionAuthRequestImplCopyWith<_$PendingSessionAuthRequestImpl> + get copyWith => __$$PendingSessionAuthRequestImplCopyWithImpl< + _$PendingSessionAuthRequestImpl>(this, _$identity); + + @override + Map toJson() { + return _$$PendingSessionAuthRequestImplToJson( + this, + ); + } +} + +abstract class _PendingSessionAuthRequest implements PendingSessionAuthRequest { + const factory _PendingSessionAuthRequest( + {required final int id, + required final String pairingTopic, + required final ConnectionMetadata requester, + required final int expiryTimestamp, + required final CacaoRequestPayload authPayload, + required final VerifyContext verifyContext}) = + _$PendingSessionAuthRequestImpl; + + factory _PendingSessionAuthRequest.fromJson(Map json) = + _$PendingSessionAuthRequestImpl.fromJson; + + @override + int get id; + @override + String get pairingTopic; + @override + ConnectionMetadata get requester; + @override + int get expiryTimestamp; + @override + CacaoRequestPayload get authPayload; + @override + VerifyContext get verifyContext; + @override + @JsonKey(ignore: true) + _$$PendingSessionAuthRequestImplCopyWith<_$PendingSessionAuthRequestImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/apis/sign_api/models/auth/session_auth_models.g.dart b/lib/apis/sign_api/models/auth/session_auth_models.g.dart new file mode 100644 index 00000000..b0193a8b --- /dev/null +++ b/lib/apis/sign_api/models/auth/session_auth_models.g.dart @@ -0,0 +1,129 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'session_auth_models.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$SessionAuthRequestParamsImpl _$$SessionAuthRequestParamsImplFromJson( + Map json) => + _$SessionAuthRequestParamsImpl( + chains: + (json['chains'] as List).map((e) => e as String).toList(), + domain: json['domain'] as String, + nonce: json['nonce'] as String, + uri: json['uri'] as String, + type: json['type'] == null + ? null + : CacaoHeader.fromJson(json['type'] as Map), + nbf: json['nbf'] as String?, + exp: json['exp'] as String?, + statement: json['statement'] as String?, + requestId: json['requestId'] as String?, + resources: (json['resources'] as List?) + ?.map((e) => e as String) + .toList(), + expiry: json['expiry'] as int?, + methods: (json['methods'] as List?) + ?.map((e) => e as String) + .toList() ?? + const [], + ); + +Map _$$SessionAuthRequestParamsImplToJson( + _$SessionAuthRequestParamsImpl instance) { + final val = { + 'chains': instance.chains, + 'domain': instance.domain, + 'nonce': instance.nonce, + 'uri': instance.uri, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('type', instance.type?.toJson()); + writeNotNull('nbf', instance.nbf); + writeNotNull('exp', instance.exp); + writeNotNull('statement', instance.statement); + writeNotNull('requestId', instance.requestId); + writeNotNull('resources', instance.resources); + writeNotNull('expiry', instance.expiry); + writeNotNull('methods', instance.methods); + return val; +} + +_$SessionAuthPayloadImpl _$$SessionAuthPayloadImplFromJson( + Map json) => + _$SessionAuthPayloadImpl( + chains: + (json['chains'] as List).map((e) => e as String).toList(), + domain: json['domain'] as String, + nonce: json['nonce'] as String, + aud: json['aud'] as String, + type: json['type'] as String, + version: json['version'] as String, + iat: json['iat'] as String, + nbf: json['nbf'] as String?, + exp: json['exp'] as String?, + statement: json['statement'] as String?, + requestId: json['requestId'] as String?, + resources: (json['resources'] as List?) + ?.map((e) => e as String) + .toList(), + ); + +Map _$$SessionAuthPayloadImplToJson( + _$SessionAuthPayloadImpl instance) { + final val = { + 'chains': instance.chains, + 'domain': instance.domain, + 'nonce': instance.nonce, + 'aud': instance.aud, + 'type': instance.type, + 'version': instance.version, + 'iat': instance.iat, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('nbf', instance.nbf); + writeNotNull('exp', instance.exp); + writeNotNull('statement', instance.statement); + writeNotNull('requestId', instance.requestId); + writeNotNull('resources', instance.resources); + return val; +} + +_$PendingSessionAuthRequestImpl _$$PendingSessionAuthRequestImplFromJson( + Map json) => + _$PendingSessionAuthRequestImpl( + id: json['id'] as int, + pairingTopic: json['pairingTopic'] as String, + requester: ConnectionMetadata.fromJson( + json['requester'] as Map), + expiryTimestamp: json['expiryTimestamp'] as int, + authPayload: CacaoRequestPayload.fromJson( + json['authPayload'] as Map), + verifyContext: + VerifyContext.fromJson(json['verifyContext'] as Map), + ); + +Map _$$PendingSessionAuthRequestImplToJson( + _$PendingSessionAuthRequestImpl instance) => + { + 'id': instance.id, + 'pairingTopic': instance.pairingTopic, + 'requester': instance.requester.toJson(), + 'expiryTimestamp': instance.expiryTimestamp, + 'authPayload': instance.authPayload.toJson(), + 'verifyContext': instance.verifyContext.toJson(), + }; diff --git a/lib/apis/sign_api/models/json_rpc_models.dart b/lib/apis/sign_api/models/json_rpc_models.dart index 35babd28..bc88c75f 100644 --- a/lib/apis/sign_api/models/json_rpc_models.dart +++ b/lib/apis/sign_api/models/json_rpc_models.dart @@ -1,6 +1,9 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:walletconnect_flutter_v2/apis/core/relay_client/relay_client_models.dart'; import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/common_auth_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/session_auth_models.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/models/proposal_models.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/models/session_models.dart'; @@ -167,3 +170,53 @@ class SessionEventParams with _$SessionEventParams { factory SessionEventParams.fromJson(Map json) => _$SessionEventParamsFromJson(json); } + +/* AUTHENTICATION MODELS */ + +@freezed +class WcAuthRequestRequest with _$WcAuthRequestRequest { + @JsonSerializable() + const factory WcAuthRequestRequest({ + required AuthPayloadParams payloadParams, + required ConnectionMetadata requester, + }) = _WcAuthRequestRequest; + + factory WcAuthRequestRequest.fromJson(Map json) => + _$WcAuthRequestRequestFromJson(json); +} + +@freezed +class WcAuthRequestResult with _$WcAuthRequestResult { + @JsonSerializable() + const factory WcAuthRequestResult({ + required Cacao cacao, + }) = _WcAuthRequestResult; + + factory WcAuthRequestResult.fromJson(Map json) => + _$WcAuthRequestResultFromJson(json); +} + +@freezed +class WcSessionAuthRequestParams with _$WcSessionAuthRequestParams { + @JsonSerializable() + const factory WcSessionAuthRequestParams({ + required SessionAuthPayload authPayload, + required ConnectionMetadata requester, + required int expiryTimestamp, + }) = _WcSessionAuthRequestParams; + + factory WcSessionAuthRequestParams.fromJson(Map json) => + _$WcSessionAuthRequestParamsFromJson(json); +} + +@freezed +class WcSessionAuthRequestResult with _$WcSessionAuthRequestResult { + @JsonSerializable() + const factory WcSessionAuthRequestResult({ + required List cacaos, + required ConnectionMetadata responder, + }) = _WcSessionAuthRequestResult; + + factory WcSessionAuthRequestResult.fromJson(Map json) => + _$WcSessionAuthRequestResultFromJson(json); +} diff --git a/lib/apis/sign_api/models/json_rpc_models.freezed.dart b/lib/apis/sign_api/models/json_rpc_models.freezed.dart index 0c40331e..f72335a4 100644 --- a/lib/apis/sign_api/models/json_rpc_models.freezed.dart +++ b/lib/apis/sign_api/models/json_rpc_models.freezed.dart @@ -2413,3 +2413,747 @@ abstract class _SessionEventParams implements SessionEventParams { _$$SessionEventParamsImplCopyWith<_$SessionEventParamsImpl> get copyWith => throw _privateConstructorUsedError; } + +WcAuthRequestRequest _$WcAuthRequestRequestFromJson(Map json) { + return _WcAuthRequestRequest.fromJson(json); +} + +/// @nodoc +mixin _$WcAuthRequestRequest { + AuthPayloadParams get payloadParams => throw _privateConstructorUsedError; + ConnectionMetadata get requester => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $WcAuthRequestRequestCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $WcAuthRequestRequestCopyWith<$Res> { + factory $WcAuthRequestRequestCopyWith(WcAuthRequestRequest value, + $Res Function(WcAuthRequestRequest) then) = + _$WcAuthRequestRequestCopyWithImpl<$Res, WcAuthRequestRequest>; + @useResult + $Res call({AuthPayloadParams payloadParams, ConnectionMetadata requester}); + + $AuthPayloadParamsCopyWith<$Res> get payloadParams; + $ConnectionMetadataCopyWith<$Res> get requester; +} + +/// @nodoc +class _$WcAuthRequestRequestCopyWithImpl<$Res, + $Val extends WcAuthRequestRequest> + implements $WcAuthRequestRequestCopyWith<$Res> { + _$WcAuthRequestRequestCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? payloadParams = null, + Object? requester = null, + }) { + return _then(_value.copyWith( + payloadParams: null == payloadParams + ? _value.payloadParams + : payloadParams // ignore: cast_nullable_to_non_nullable + as AuthPayloadParams, + requester: null == requester + ? _value.requester + : requester // ignore: cast_nullable_to_non_nullable + as ConnectionMetadata, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $AuthPayloadParamsCopyWith<$Res> get payloadParams { + return $AuthPayloadParamsCopyWith<$Res>(_value.payloadParams, (value) { + return _then(_value.copyWith(payloadParams: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $ConnectionMetadataCopyWith<$Res> get requester { + return $ConnectionMetadataCopyWith<$Res>(_value.requester, (value) { + return _then(_value.copyWith(requester: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$WcAuthRequestRequestImplCopyWith<$Res> + implements $WcAuthRequestRequestCopyWith<$Res> { + factory _$$WcAuthRequestRequestImplCopyWith(_$WcAuthRequestRequestImpl value, + $Res Function(_$WcAuthRequestRequestImpl) then) = + __$$WcAuthRequestRequestImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({AuthPayloadParams payloadParams, ConnectionMetadata requester}); + + @override + $AuthPayloadParamsCopyWith<$Res> get payloadParams; + @override + $ConnectionMetadataCopyWith<$Res> get requester; +} + +/// @nodoc +class __$$WcAuthRequestRequestImplCopyWithImpl<$Res> + extends _$WcAuthRequestRequestCopyWithImpl<$Res, _$WcAuthRequestRequestImpl> + implements _$$WcAuthRequestRequestImplCopyWith<$Res> { + __$$WcAuthRequestRequestImplCopyWithImpl(_$WcAuthRequestRequestImpl _value, + $Res Function(_$WcAuthRequestRequestImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? payloadParams = null, + Object? requester = null, + }) { + return _then(_$WcAuthRequestRequestImpl( + payloadParams: null == payloadParams + ? _value.payloadParams + : payloadParams // ignore: cast_nullable_to_non_nullable + as AuthPayloadParams, + requester: null == requester + ? _value.requester + : requester // ignore: cast_nullable_to_non_nullable + as ConnectionMetadata, + )); + } +} + +/// @nodoc + +@JsonSerializable() +class _$WcAuthRequestRequestImpl implements _WcAuthRequestRequest { + const _$WcAuthRequestRequestImpl( + {required this.payloadParams, required this.requester}); + + factory _$WcAuthRequestRequestImpl.fromJson(Map json) => + _$$WcAuthRequestRequestImplFromJson(json); + + @override + final AuthPayloadParams payloadParams; + @override + final ConnectionMetadata requester; + + @override + String toString() { + return 'WcAuthRequestRequest(payloadParams: $payloadParams, requester: $requester)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$WcAuthRequestRequestImpl && + (identical(other.payloadParams, payloadParams) || + other.payloadParams == payloadParams) && + (identical(other.requester, requester) || + other.requester == requester)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, payloadParams, requester); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$WcAuthRequestRequestImplCopyWith<_$WcAuthRequestRequestImpl> + get copyWith => + __$$WcAuthRequestRequestImplCopyWithImpl<_$WcAuthRequestRequestImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$WcAuthRequestRequestImplToJson( + this, + ); + } +} + +abstract class _WcAuthRequestRequest implements WcAuthRequestRequest { + const factory _WcAuthRequestRequest( + {required final AuthPayloadParams payloadParams, + required final ConnectionMetadata requester}) = + _$WcAuthRequestRequestImpl; + + factory _WcAuthRequestRequest.fromJson(Map json) = + _$WcAuthRequestRequestImpl.fromJson; + + @override + AuthPayloadParams get payloadParams; + @override + ConnectionMetadata get requester; + @override + @JsonKey(ignore: true) + _$$WcAuthRequestRequestImplCopyWith<_$WcAuthRequestRequestImpl> + get copyWith => throw _privateConstructorUsedError; +} + +WcAuthRequestResult _$WcAuthRequestResultFromJson(Map json) { + return _WcAuthRequestResult.fromJson(json); +} + +/// @nodoc +mixin _$WcAuthRequestResult { + Cacao get cacao => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $WcAuthRequestResultCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $WcAuthRequestResultCopyWith<$Res> { + factory $WcAuthRequestResultCopyWith( + WcAuthRequestResult value, $Res Function(WcAuthRequestResult) then) = + _$WcAuthRequestResultCopyWithImpl<$Res, WcAuthRequestResult>; + @useResult + $Res call({Cacao cacao}); + + $CacaoCopyWith<$Res> get cacao; +} + +/// @nodoc +class _$WcAuthRequestResultCopyWithImpl<$Res, $Val extends WcAuthRequestResult> + implements $WcAuthRequestResultCopyWith<$Res> { + _$WcAuthRequestResultCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? cacao = null, + }) { + return _then(_value.copyWith( + cacao: null == cacao + ? _value.cacao + : cacao // ignore: cast_nullable_to_non_nullable + as Cacao, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $CacaoCopyWith<$Res> get cacao { + return $CacaoCopyWith<$Res>(_value.cacao, (value) { + return _then(_value.copyWith(cacao: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$WcAuthRequestResultImplCopyWith<$Res> + implements $WcAuthRequestResultCopyWith<$Res> { + factory _$$WcAuthRequestResultImplCopyWith(_$WcAuthRequestResultImpl value, + $Res Function(_$WcAuthRequestResultImpl) then) = + __$$WcAuthRequestResultImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({Cacao cacao}); + + @override + $CacaoCopyWith<$Res> get cacao; +} + +/// @nodoc +class __$$WcAuthRequestResultImplCopyWithImpl<$Res> + extends _$WcAuthRequestResultCopyWithImpl<$Res, _$WcAuthRequestResultImpl> + implements _$$WcAuthRequestResultImplCopyWith<$Res> { + __$$WcAuthRequestResultImplCopyWithImpl(_$WcAuthRequestResultImpl _value, + $Res Function(_$WcAuthRequestResultImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? cacao = null, + }) { + return _then(_$WcAuthRequestResultImpl( + cacao: null == cacao + ? _value.cacao + : cacao // ignore: cast_nullable_to_non_nullable + as Cacao, + )); + } +} + +/// @nodoc + +@JsonSerializable() +class _$WcAuthRequestResultImpl implements _WcAuthRequestResult { + const _$WcAuthRequestResultImpl({required this.cacao}); + + factory _$WcAuthRequestResultImpl.fromJson(Map json) => + _$$WcAuthRequestResultImplFromJson(json); + + @override + final Cacao cacao; + + @override + String toString() { + return 'WcAuthRequestResult(cacao: $cacao)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$WcAuthRequestResultImpl && + (identical(other.cacao, cacao) || other.cacao == cacao)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, cacao); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$WcAuthRequestResultImplCopyWith<_$WcAuthRequestResultImpl> get copyWith => + __$$WcAuthRequestResultImplCopyWithImpl<_$WcAuthRequestResultImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$WcAuthRequestResultImplToJson( + this, + ); + } +} + +abstract class _WcAuthRequestResult implements WcAuthRequestResult { + const factory _WcAuthRequestResult({required final Cacao cacao}) = + _$WcAuthRequestResultImpl; + + factory _WcAuthRequestResult.fromJson(Map json) = + _$WcAuthRequestResultImpl.fromJson; + + @override + Cacao get cacao; + @override + @JsonKey(ignore: true) + _$$WcAuthRequestResultImplCopyWith<_$WcAuthRequestResultImpl> get copyWith => + throw _privateConstructorUsedError; +} + +WcSessionAuthRequestParams _$WcSessionAuthRequestParamsFromJson( + Map json) { + return _WcSessionAuthRequestParams.fromJson(json); +} + +/// @nodoc +mixin _$WcSessionAuthRequestParams { + SessionAuthPayload get authPayload => throw _privateConstructorUsedError; + ConnectionMetadata get requester => throw _privateConstructorUsedError; + int get expiryTimestamp => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $WcSessionAuthRequestParamsCopyWith + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $WcSessionAuthRequestParamsCopyWith<$Res> { + factory $WcSessionAuthRequestParamsCopyWith(WcSessionAuthRequestParams value, + $Res Function(WcSessionAuthRequestParams) then) = + _$WcSessionAuthRequestParamsCopyWithImpl<$Res, + WcSessionAuthRequestParams>; + @useResult + $Res call( + {SessionAuthPayload authPayload, + ConnectionMetadata requester, + int expiryTimestamp}); + + $SessionAuthPayloadCopyWith<$Res> get authPayload; + $ConnectionMetadataCopyWith<$Res> get requester; +} + +/// @nodoc +class _$WcSessionAuthRequestParamsCopyWithImpl<$Res, + $Val extends WcSessionAuthRequestParams> + implements $WcSessionAuthRequestParamsCopyWith<$Res> { + _$WcSessionAuthRequestParamsCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? authPayload = null, + Object? requester = null, + Object? expiryTimestamp = null, + }) { + return _then(_value.copyWith( + authPayload: null == authPayload + ? _value.authPayload + : authPayload // ignore: cast_nullable_to_non_nullable + as SessionAuthPayload, + requester: null == requester + ? _value.requester + : requester // ignore: cast_nullable_to_non_nullable + as ConnectionMetadata, + expiryTimestamp: null == expiryTimestamp + ? _value.expiryTimestamp + : expiryTimestamp // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $SessionAuthPayloadCopyWith<$Res> get authPayload { + return $SessionAuthPayloadCopyWith<$Res>(_value.authPayload, (value) { + return _then(_value.copyWith(authPayload: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $ConnectionMetadataCopyWith<$Res> get requester { + return $ConnectionMetadataCopyWith<$Res>(_value.requester, (value) { + return _then(_value.copyWith(requester: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$WcSessionAuthRequestParamsImplCopyWith<$Res> + implements $WcSessionAuthRequestParamsCopyWith<$Res> { + factory _$$WcSessionAuthRequestParamsImplCopyWith( + _$WcSessionAuthRequestParamsImpl value, + $Res Function(_$WcSessionAuthRequestParamsImpl) then) = + __$$WcSessionAuthRequestParamsImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {SessionAuthPayload authPayload, + ConnectionMetadata requester, + int expiryTimestamp}); + + @override + $SessionAuthPayloadCopyWith<$Res> get authPayload; + @override + $ConnectionMetadataCopyWith<$Res> get requester; +} + +/// @nodoc +class __$$WcSessionAuthRequestParamsImplCopyWithImpl<$Res> + extends _$WcSessionAuthRequestParamsCopyWithImpl<$Res, + _$WcSessionAuthRequestParamsImpl> + implements _$$WcSessionAuthRequestParamsImplCopyWith<$Res> { + __$$WcSessionAuthRequestParamsImplCopyWithImpl( + _$WcSessionAuthRequestParamsImpl _value, + $Res Function(_$WcSessionAuthRequestParamsImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? authPayload = null, + Object? requester = null, + Object? expiryTimestamp = null, + }) { + return _then(_$WcSessionAuthRequestParamsImpl( + authPayload: null == authPayload + ? _value.authPayload + : authPayload // ignore: cast_nullable_to_non_nullable + as SessionAuthPayload, + requester: null == requester + ? _value.requester + : requester // ignore: cast_nullable_to_non_nullable + as ConnectionMetadata, + expiryTimestamp: null == expiryTimestamp + ? _value.expiryTimestamp + : expiryTimestamp // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +@JsonSerializable() +class _$WcSessionAuthRequestParamsImpl implements _WcSessionAuthRequestParams { + const _$WcSessionAuthRequestParamsImpl( + {required this.authPayload, + required this.requester, + required this.expiryTimestamp}); + + factory _$WcSessionAuthRequestParamsImpl.fromJson( + Map json) => + _$$WcSessionAuthRequestParamsImplFromJson(json); + + @override + final SessionAuthPayload authPayload; + @override + final ConnectionMetadata requester; + @override + final int expiryTimestamp; + + @override + String toString() { + return 'WcSessionAuthRequestParams(authPayload: $authPayload, requester: $requester, expiryTimestamp: $expiryTimestamp)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$WcSessionAuthRequestParamsImpl && + (identical(other.authPayload, authPayload) || + other.authPayload == authPayload) && + (identical(other.requester, requester) || + other.requester == requester) && + (identical(other.expiryTimestamp, expiryTimestamp) || + other.expiryTimestamp == expiryTimestamp)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => + Object.hash(runtimeType, authPayload, requester, expiryTimestamp); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$WcSessionAuthRequestParamsImplCopyWith<_$WcSessionAuthRequestParamsImpl> + get copyWith => __$$WcSessionAuthRequestParamsImplCopyWithImpl< + _$WcSessionAuthRequestParamsImpl>(this, _$identity); + + @override + Map toJson() { + return _$$WcSessionAuthRequestParamsImplToJson( + this, + ); + } +} + +abstract class _WcSessionAuthRequestParams + implements WcSessionAuthRequestParams { + const factory _WcSessionAuthRequestParams( + {required final SessionAuthPayload authPayload, + required final ConnectionMetadata requester, + required final int expiryTimestamp}) = _$WcSessionAuthRequestParamsImpl; + + factory _WcSessionAuthRequestParams.fromJson(Map json) = + _$WcSessionAuthRequestParamsImpl.fromJson; + + @override + SessionAuthPayload get authPayload; + @override + ConnectionMetadata get requester; + @override + int get expiryTimestamp; + @override + @JsonKey(ignore: true) + _$$WcSessionAuthRequestParamsImplCopyWith<_$WcSessionAuthRequestParamsImpl> + get copyWith => throw _privateConstructorUsedError; +} + +WcSessionAuthRequestResult _$WcSessionAuthRequestResultFromJson( + Map json) { + return _WcSessionAuthRequestResult.fromJson(json); +} + +/// @nodoc +mixin _$WcSessionAuthRequestResult { + List get cacaos => throw _privateConstructorUsedError; + ConnectionMetadata get responder => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $WcSessionAuthRequestResultCopyWith + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $WcSessionAuthRequestResultCopyWith<$Res> { + factory $WcSessionAuthRequestResultCopyWith(WcSessionAuthRequestResult value, + $Res Function(WcSessionAuthRequestResult) then) = + _$WcSessionAuthRequestResultCopyWithImpl<$Res, + WcSessionAuthRequestResult>; + @useResult + $Res call({List cacaos, ConnectionMetadata responder}); + + $ConnectionMetadataCopyWith<$Res> get responder; +} + +/// @nodoc +class _$WcSessionAuthRequestResultCopyWithImpl<$Res, + $Val extends WcSessionAuthRequestResult> + implements $WcSessionAuthRequestResultCopyWith<$Res> { + _$WcSessionAuthRequestResultCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? cacaos = null, + Object? responder = null, + }) { + return _then(_value.copyWith( + cacaos: null == cacaos + ? _value.cacaos + : cacaos // ignore: cast_nullable_to_non_nullable + as List, + responder: null == responder + ? _value.responder + : responder // ignore: cast_nullable_to_non_nullable + as ConnectionMetadata, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $ConnectionMetadataCopyWith<$Res> get responder { + return $ConnectionMetadataCopyWith<$Res>(_value.responder, (value) { + return _then(_value.copyWith(responder: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$WcSessionAuthRequestResultImplCopyWith<$Res> + implements $WcSessionAuthRequestResultCopyWith<$Res> { + factory _$$WcSessionAuthRequestResultImplCopyWith( + _$WcSessionAuthRequestResultImpl value, + $Res Function(_$WcSessionAuthRequestResultImpl) then) = + __$$WcSessionAuthRequestResultImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({List cacaos, ConnectionMetadata responder}); + + @override + $ConnectionMetadataCopyWith<$Res> get responder; +} + +/// @nodoc +class __$$WcSessionAuthRequestResultImplCopyWithImpl<$Res> + extends _$WcSessionAuthRequestResultCopyWithImpl<$Res, + _$WcSessionAuthRequestResultImpl> + implements _$$WcSessionAuthRequestResultImplCopyWith<$Res> { + __$$WcSessionAuthRequestResultImplCopyWithImpl( + _$WcSessionAuthRequestResultImpl _value, + $Res Function(_$WcSessionAuthRequestResultImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? cacaos = null, + Object? responder = null, + }) { + return _then(_$WcSessionAuthRequestResultImpl( + cacaos: null == cacaos + ? _value._cacaos + : cacaos // ignore: cast_nullable_to_non_nullable + as List, + responder: null == responder + ? _value.responder + : responder // ignore: cast_nullable_to_non_nullable + as ConnectionMetadata, + )); + } +} + +/// @nodoc + +@JsonSerializable() +class _$WcSessionAuthRequestResultImpl implements _WcSessionAuthRequestResult { + const _$WcSessionAuthRequestResultImpl( + {required final List cacaos, required this.responder}) + : _cacaos = cacaos; + + factory _$WcSessionAuthRequestResultImpl.fromJson( + Map json) => + _$$WcSessionAuthRequestResultImplFromJson(json); + + final List _cacaos; + @override + List get cacaos { + if (_cacaos is EqualUnmodifiableListView) return _cacaos; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_cacaos); + } + + @override + final ConnectionMetadata responder; + + @override + String toString() { + return 'WcSessionAuthRequestResult(cacaos: $cacaos, responder: $responder)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$WcSessionAuthRequestResultImpl && + const DeepCollectionEquality().equals(other._cacaos, _cacaos) && + (identical(other.responder, responder) || + other.responder == responder)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_cacaos), responder); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$WcSessionAuthRequestResultImplCopyWith<_$WcSessionAuthRequestResultImpl> + get copyWith => __$$WcSessionAuthRequestResultImplCopyWithImpl< + _$WcSessionAuthRequestResultImpl>(this, _$identity); + + @override + Map toJson() { + return _$$WcSessionAuthRequestResultImplToJson( + this, + ); + } +} + +abstract class _WcSessionAuthRequestResult + implements WcSessionAuthRequestResult { + const factory _WcSessionAuthRequestResult( + {required final List cacaos, + required final ConnectionMetadata responder}) = + _$WcSessionAuthRequestResultImpl; + + factory _WcSessionAuthRequestResult.fromJson(Map json) = + _$WcSessionAuthRequestResultImpl.fromJson; + + @override + List get cacaos; + @override + ConnectionMetadata get responder; + @override + @JsonKey(ignore: true) + _$$WcSessionAuthRequestResultImplCopyWith<_$WcSessionAuthRequestResultImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/apis/sign_api/models/json_rpc_models.g.dart b/lib/apis/sign_api/models/json_rpc_models.g.dart index c86c93c5..8008131a 100644 --- a/lib/apis/sign_api/models/json_rpc_models.g.dart +++ b/lib/apis/sign_api/models/json_rpc_models.g.dart @@ -275,3 +275,66 @@ Map _$$SessionEventParamsImplToJson( 'name': instance.name, 'data': instance.data, }; + +_$WcAuthRequestRequestImpl _$$WcAuthRequestRequestImplFromJson( + Map json) => + _$WcAuthRequestRequestImpl( + payloadParams: AuthPayloadParams.fromJson( + json['payloadParams'] as Map), + requester: ConnectionMetadata.fromJson( + json['requester'] as Map), + ); + +Map _$$WcAuthRequestRequestImplToJson( + _$WcAuthRequestRequestImpl instance) => + { + 'payloadParams': instance.payloadParams.toJson(), + 'requester': instance.requester.toJson(), + }; + +_$WcAuthRequestResultImpl _$$WcAuthRequestResultImplFromJson( + Map json) => + _$WcAuthRequestResultImpl( + cacao: Cacao.fromJson(json['cacao'] as Map), + ); + +Map _$$WcAuthRequestResultImplToJson( + _$WcAuthRequestResultImpl instance) => + { + 'cacao': instance.cacao.toJson(), + }; + +_$WcSessionAuthRequestParamsImpl _$$WcSessionAuthRequestParamsImplFromJson( + Map json) => + _$WcSessionAuthRequestParamsImpl( + authPayload: SessionAuthPayload.fromJson( + json['authPayload'] as Map), + requester: ConnectionMetadata.fromJson( + json['requester'] as Map), + expiryTimestamp: json['expiryTimestamp'] as int, + ); + +Map _$$WcSessionAuthRequestParamsImplToJson( + _$WcSessionAuthRequestParamsImpl instance) => + { + 'authPayload': instance.authPayload.toJson(), + 'requester': instance.requester.toJson(), + 'expiryTimestamp': instance.expiryTimestamp, + }; + +_$WcSessionAuthRequestResultImpl _$$WcSessionAuthRequestResultImplFromJson( + Map json) => + _$WcSessionAuthRequestResultImpl( + cacaos: (json['cacaos'] as List) + .map((e) => Cacao.fromJson(e as Map)) + .toList(), + responder: ConnectionMetadata.fromJson( + json['responder'] as Map), + ); + +Map _$$WcSessionAuthRequestResultImplToJson( + _$WcSessionAuthRequestResultImpl instance) => + { + 'cacaos': instance.cacaos.map((e) => e.toJson()).toList(), + 'responder': instance.responder.toJson(), + }; diff --git a/lib/apis/sign_api/models/sign_client_events.dart b/lib/apis/sign_api/models/sign_client_events.dart index 5eb125ee..c2e49a97 100644 --- a/lib/apis/sign_api/models/sign_client_events.dart +++ b/lib/apis/sign_api/models/sign_client_events.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:event/event.dart'; import 'package:walletconnect_flutter_v2/apis/core/verify/models/verify_context.dart'; import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; @@ -15,9 +17,15 @@ class SessionProposalEvent extends EventArgs { this.verifyContext, ]); + Map toJson() => { + 'id': id, + 'params': params.toJson(), + 'verifyContext': verifyContext?.toJson(), + }; + @override String toString() { - return 'SessionProposalEvent(id: $id, params: $params)'; + return 'SessionProposalEvent(${jsonEncode(toJson())})'; } } diff --git a/lib/apis/sign_api/models/sign_client_models.dart b/lib/apis/sign_api/models/sign_client_models.dart index 3bb4b94e..54828ebc 100644 --- a/lib/apis/sign_api/models/sign_client_models.dart +++ b/lib/apis/sign_api/models/sign_client_models.dart @@ -21,7 +21,7 @@ class ConnectResponse { class ApproveResponse { final String topic; - final SessionData session; + final SessionData? session; ApproveResponse({ required this.topic, diff --git a/lib/apis/sign_api/sign_client.dart b/lib/apis/sign_api/sign_client.dart index c5cc5aee..6b939421 100644 --- a/lib/apis/sign_api/sign_client.dart +++ b/lib/apis/sign_api/sign_client.dart @@ -102,6 +102,46 @@ class SignClient implements ISignClient { return SessionRequest.fromJson(value); }, ), + authKeys: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_AUTH_KEYS, + version: StoreVersions.VERSION_AUTH_KEYS, + fromJson: (dynamic value) { + return AuthPublicKey.fromJson(value); + }, + ), + pairingTopics: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_PAIRING_TOPICS, + version: StoreVersions.VERSION_PAIRING_TOPICS, + fromJson: (dynamic value) { + return value; + }, + ), + authRequests: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_AUTH_REQUESTS, + version: StoreVersions.VERSION_AUTH_REQUESTS, + fromJson: (dynamic value) { + return PendingAuthRequest.fromJson(value); + }, + ), + completeRequests: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_COMPLETE_REQUESTS, + version: StoreVersions.VERSION_COMPLETE_REQUESTS, + fromJson: (dynamic value) { + return StoredCacao.fromJson(value); + }, + ), + sessionAuthRequests: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_AUTH_REQUESTS, + version: StoreVersions.VERSION_AUTH_REQUESTS, + fromJson: (dynamic value) { + return PendingSessionAuthRequest.fromJson(value); + }, + ), ); } @@ -451,4 +491,184 @@ class SignClient implements ISignClient { @override IPairingStore get pairings => core.pairing.getStore(); + + // FORMER AUTH ENGINE METHODS + + @override + IGenericStore get authRequests => engine.authRequests; + + @override + Map getPendingAuthRequests() { + try { + return engine.getPendingAuthRequests(); + } catch (e) { + rethrow; + } + } + + @override + Map getPendingSessionAuthRequests() { + try { + return engine.getPendingSessionAuthRequests(); + } catch (e) { + rethrow; + } + } + + @override + IGenericStore get sessionAuthRequests => + engine.sessionAuthRequests; + + @override + Event get onAuthRequest => engine.onAuthRequest; + + @override + Event get onAuthResponse => engine.onAuthResponse; + + // NEW 1-CLICK AUTH METHOD + @override + Event get onSessionAuthResponse => + engine.onSessionAuthResponse; + + @override + Event get onSessionAuthRequest => + engine.onSessionAuthRequest; + + @override + Future requestAuth({ + required AuthRequestParams params, + String? pairingTopic, + List>? methods = SignEngine.DEFAULT_METHODS_AUTH, + }) { + try { + return engine.requestAuth( + params: params, + pairingTopic: pairingTopic, + methods: methods, + ); + } catch (e) { + rethrow; + } + } + + // NEW ONE-CLICK AUTH METHOD FOR DAPPS + @override + Future authenticate({ + required SessionAuthRequestParams params, + String? pairingTopic, + List>? methods = const [ + [MethodConstants.WC_SESSION_AUTHENTICATE] + ], + }) { + try { + return engine.authenticate( + params: params, + pairingTopic: pairingTopic, + methods: methods, + ); + } catch (e) { + rethrow; + } + } + + @override + Future respondAuthRequest({ + required int id, + required String iss, + CacaoSignature? signature, + WalletConnectError? error, + }) { + try { + return engine.respondAuthRequest( + id: id, + iss: iss, + signature: signature, + error: error, + ); + } catch (e) { + rethrow; + } + } + + @override + Future approveSessionAuthenticate({ + required int id, + List? auths, + }) { + try { + return engine.approveSessionAuthenticate( + id: id, + auths: auths, + ); + } catch (e) { + rethrow; + } + } + + @override + Future rejectSessionAuthenticate({ + required int id, + required WalletConnectError reason, + }) { + try { + return engine.rejectSessionAuthenticate( + id: id, + reason: reason, + ); + } catch (e) { + rethrow; + } + } + + @override + IGenericStore get authKeys => engine.authKeys; + + @override + IGenericStore get completeRequests => engine.completeRequests; + + @override + Future validateSignedCacao({ + required Cacao cacao, + required String projectId, + }) { + try { + return engine.validateSignedCacao( + cacao: cacao, + projectId: projectId, + ); + } catch (e) { + rethrow; + } + } + + @override + String formatAuthMessage({ + required String iss, + required CacaoRequestPayload cacaoPayload, + }) { + try { + return engine.formatAuthMessage( + iss: iss, + cacaoPayload: cacaoPayload, + ); + } catch (e) { + rethrow; + } + } + + @override + Map getCompletedRequestsForPairing({ + required String pairingTopic, + }) { + try { + return engine.getCompletedRequestsForPairing( + pairingTopic: pairingTopic, + ); + } catch (e) { + rethrow; + } + } + + @override + IGenericStore get pairingTopics => engine.pairingTopics; } diff --git a/lib/apis/sign_api/sign_engine.dart b/lib/apis/sign_api/sign_engine.dart index 19d0aaad..5266da74 100644 --- a/lib/apis/sign_api/sign_engine.dart +++ b/lib/apis/sign_api/sign_engine.dart @@ -1,14 +1,17 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:math'; import 'package:http/http.dart' as http; import 'package:walletconnect_flutter_v2/apis/core/pairing/utils/json_rpc_utils.dart'; import 'package:walletconnect_flutter_v2/apis/core/store/i_generic_store.dart'; -import 'package:walletconnect_flutter_v2/apis/core/verify/models/verify_context.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/i_sessions.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/utils/custom_credentials.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/utils/sign_api_validator_utils.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/utils/auth/recaps_utils.dart'; +import 'package:walletconnect_flutter_v2/apis/core/crypto/crypto_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/utils/auth/auth_constants.dart'; class SignEngine implements ISignEngine { static const List> DEFAULT_METHODS = [ @@ -18,6 +21,12 @@ class SignEngine implements ISignEngine { ], ]; + static const List> DEFAULT_METHODS_AUTH = [ + [ + MethodConstants.WC_AUTH_REQUEST, + ] + ]; + bool _initialized = false; @override @@ -60,12 +69,46 @@ class SignEngine implements ISignEngine { List pendingProposals = []; + // FORMER AUTH ENGINE PROPERTY + @override + late IGenericStore authKeys; + @override + late IGenericStore authRequests; + @override + IGenericStore completeRequests; + @override + final Event onAuthRequest = Event(); + @override + final Event onAuthResponse = Event(); + @override + late IGenericStore pairingTopics; + + // NEW 1-CA METHOD + @override + late IGenericStore sessionAuthRequests; + @override + final Event onSessionAuthRequest = + Event(); + @override + final Event onSessionAuthResponse = + Event(); + + // FORMER AUTH ENGINE PROPERTY (apparently not used before and not used now) + List pendingAuthRequests = []; + SignEngine({ required this.core, required this.metadata, required this.proposals, required this.sessions, required this.pendingRequests, + // FORMER AUTH ENGINE PROPERTIES + required this.authKeys, + required this.pairingTopics, + required this.authRequests, + required this.completeRequests, + // NEW 1-CA PROPERTY + required this.sessionAuthRequests, }); @override @@ -80,6 +123,14 @@ class SignEngine implements ISignEngine { await sessions.init(); await pendingRequests.init(); + // FORMER AUTH ENGINE PROPERTIES + await authKeys.init(); + await pairingTopics.init(); + await authRequests.init(); + await completeRequests.init(); + // NEW 1-CA PROPERTY + await sessionAuthRequests.init(); + _registerInternalEvents(); _registerRelayClientFunctions(); await _cleanup(); @@ -131,7 +182,7 @@ class SignEngine implements ISignEngine { final publicKey = await core.crypto.generateKeyPair(); final int id = JsonRpcUtils.payloadId(); - final WcSessionProposeRequest request = WcSessionProposeRequest( + final request = WcSessionProposeRequest( relays: relays ?? [Relay(WalletConnectConstants.RELAYER_DEFAULT_PROTOCOL)], requiredNamespaces: requiredNamespaces ?? {}, @@ -197,13 +248,13 @@ class SignEngine implements ISignEngine { // print("sending proposal for $topic"); // print('connectResponseHandler requestId: $requestId'); try { - final Map resp = await core.pairing.sendRequest( + final Map response = await core.pairing.sendRequest( topic, MethodConstants.WC_SESSION_PROPOSE, - request, + request.toJson(), id: requestId, ); - final String peerPublicKey = resp['responderPublicKey']; + final String peerPublicKey = response['responderPublicKey']; final ProposalData proposal = proposals.get( requestId.toString(), @@ -310,7 +361,6 @@ class SignEngine implements ISignEngine { sessionProperties: proposal.sessionProperties, ); - // print('session connect'); onSessionConnect.broadcast(SessionConnect(session)); await sessions.set(sessionTopic, session); @@ -373,13 +423,14 @@ class SignEngine implements ISignEngine { // Attempt to send a response, if the pairing is not active, this will fail // but we don't care try { + final method = MethodConstants.WC_SESSION_PROPOSE; + final rpcOpts = MethodConstants.RPC_OPTS[method]; await core.pairing.sendError( id, proposal.pairingTopic, - MethodConstants.WC_SESSION_PROPOSE, - JsonRpcError.fromJson( - reason.toJson(), - ), + method, + JsonRpcError(code: reason.code, message: reason.message), + rpcOptions: rpcOpts?['reject'], ); } catch (_) { // print('got here'); @@ -474,14 +525,12 @@ class SignEngine implements ISignEngine { List parameters = const [], }) async { try { - core.logger.i('readContractCall: with function $functionName'); final results = await Web3Client(rpcUrl, http.Client()).call( contract: deployedContract, function: deployedContract.function(functionName), params: parameters, ); - core.logger.i('readContractCall: $functionName - results: $results'); return results; } catch (e) { rethrow; @@ -929,12 +978,38 @@ class SignEngine implements ISignEngine { function: _onSessionEventRequest, type: ProtocolType.sign, ); + // FORMER AUTH ENGINE PROPERTY + core.pairing.register( + method: MethodConstants.WC_AUTH_REQUEST, + function: _onAuthRequest, + type: ProtocolType.sign, + ); + core.pairing.register( + method: MethodConstants.WC_SESSION_AUTHENTICATE, + function: _onSessionAuthRequest, + type: ProtocolType.sign, + ); + } + + bool _shouldIgnoreSessionPropose(String topic) { + final PairingInfo? pairingInfo = core.pairing.getPairing(topic: topic); + final implementSessionAuth = onSessionAuthRequest.subscriberCount > 0; + final method = MethodConstants.WC_SESSION_AUTHENTICATE; + final containsMethod = (pairingInfo?.methods ?? []).contains(method); + + return implementSessionAuth && containsMethod; } Future _onSessionProposeRequest( String topic, JsonRpcRequest payload, ) async { + if (_shouldIgnoreSessionPropose(topic)) { + core.logger.t( + 'Session Propose ignored. Session Authenticate will be used instead', + ); + return; + } try { core.logger.t( '_onSessionProposeRequest, topic: $topic, payload: $payload', @@ -971,13 +1046,13 @@ class SignEngine implements ISignEngine { core.logger.t( '_onSessionProposeRequest WalletConnectError: $err', ); + final rpcOpts = MethodConstants.RPC_OPTS[payload.method]; await core.pairing.sendError( payload.id, topic, payload.method, - JsonRpcError.fromJson( - err.toJson(), - ), + JsonRpcError(code: err.code, message: err.message), + rpcOptions: rpcOpts?['autoReject'], ); // Broadcast that a session proposal error has occurred @@ -1024,13 +1099,13 @@ class SignEngine implements ISignEngine { ); } on WalletConnectError catch (err) { core.logger.e('_onSessionProposeRequest Error: $err'); + final rpcOpts = MethodConstants.RPC_OPTS[payload.method]; await core.pairing.sendError( payload.id, topic, payload.method, - JsonRpcError.fromJson( - err.toJson(), - ), + JsonRpcError(code: err.code, message: err.message), + rpcOptions: rpcOpts?['autoReject'], ); } } @@ -1772,4 +1847,930 @@ class SignEngine implements ISignEngine { ); } } + + // NEW 1-CA METHOD (Should this be private?) + + @override + Future validateSignedCacao({ + required Cacao cacao, + required String projectId, + }) async { + final CacaoSignature signature = cacao.s; + final CacaoPayload payload = cacao.p; + + final reconstructed = formatAuthMessage( + iss: payload.iss, + cacaoPayload: CacaoRequestPayload.fromCacaoPayload(payload), + ); + + final walletAddress = AddressUtils.getDidAddress(payload.iss); + final chainId = AddressUtils.getDidChainId(payload.iss); + + final isValid = await AuthSignature.verifySignature( + walletAddress, + reconstructed, + signature, + chainId, + projectId, + ); + + return isValid; + } + + // FORMER AUTH ENGINE PROPERTY + @override + String formatAuthMessage({ + required String iss, + required CacaoRequestPayload cacaoPayload, + }) { + final header = + '${cacaoPayload.domain} wants you to sign in with your Ethereum account:'; + final walletAddress = AddressUtils.getDidAddress(iss); + + if (cacaoPayload.aud.isEmpty) { + throw WalletConnectError(code: -1, message: 'aud is required'); + } + + String statement = cacaoPayload.statement ?? ''; + final uri = 'URI: ${cacaoPayload.aud}'; + final version = 'Version: ${cacaoPayload.version}'; + final chainId = 'Chain ID: ${AddressUtils.getDidChainId(iss)}'; + final nonce = 'Nonce: ${cacaoPayload.nonce}'; + final issuedAt = 'Issued At: ${cacaoPayload.iat}'; + final resources = cacaoPayload.resources != null && + cacaoPayload.resources!.isNotEmpty + ? 'Resources:\n${cacaoPayload.resources!.map((resource) => '- $resource').join('\n')}' + : null; + final recap = ReCapsUtils.getRecapFromResources( + resources: cacaoPayload.resources, + ); + if (recap != null) { + final decoded = ReCapsUtils.decodeRecap(recap); + statement = ReCapsUtils.formatStatementFromRecap( + statement: statement, + recap: decoded, + ); + } + + final message = [ + header, + walletAddress, + '', + statement, + '', + uri, + version, + chainId, + nonce, + issuedAt, + resources, + ].where((element) => element != null).join('\n'); + + return message; + } + + // FORMER AUTH ENGINE PROPERTY + @override + Map getCompletedRequestsForPairing({ + required String pairingTopic, + }) { + Map completedRequests = {}; + completeRequests + .getAll() + .where( + (e) => e.pairingTopic == pairingTopic, + ) + .forEach((key) { + completedRequests[key.id] = key; + }); + return completedRequests; + } + + // FORMER AUTH ENGINE PROPERTY + @override + Map getPendingAuthRequests() { + Map pendingRequests = {}; + authRequests.getAll().forEach((key) { + pendingRequests[key.id] = key; + }); + return pendingRequests; + } + + // FORMER AUTH ENGINE PROPERTY + @override + Future requestAuth({ + required AuthRequestParams params, + String? pairingTopic, + List>? methods = DEFAULT_METHODS_AUTH, + }) async { + _checkInitialized(); + + AuthApiValidators.isValidRequest(params); + String? pTopic = pairingTopic; + Uri? uri; + + if (pTopic == null) { + final CreateResponse newTopicAndUri = await core.pairing.create( + methods: methods, + ); + pTopic = newTopicAndUri.topic; + uri = newTopicAndUri.uri; + } else { + // TODO this should be used when pairingTopic is passed (existent pairing topic case) + // but it does not seems right + core.pairing.isValidPairingTopic(topic: pTopic); + } + + final publicKey = await core.crypto.generateKeyPair(); + // print('requestAuth, publicKey: $publicKey'); + final String responseTopic = core.crypto.getUtils().hashKey(publicKey); + final int id = JsonRpcUtils.payloadId(); + + final request = WcAuthRequestRequest( + payloadParams: AuthPayloadParams.fromRequestParams( + params, + ), + requester: ConnectionMetadata( + publicKey: publicKey, + metadata: metadata, + ), + ); + + final int expiry = params.expiry ?? WalletConnectConstants.FIVE_MINUTES; + + await authKeys.set( + AuthConstants.AUTH_CLIENT_PUBLIC_KEY_NAME, + AuthPublicKey(publicKey: publicKey), + ); + + await pairingTopics.set( + responseTopic, + pTopic, + ); + + // Set the one time use receiver public key for decoding the Type 1 envelope + await core.pairing.setReceiverPublicKey( + topic: responseTopic, + publicKey: publicKey, + expiry: expiry, + ); + + Completer completer = Completer(); + + _requestAuthResponseHandler( + pairingTopic: pTopic, + responseTopic: responseTopic, + request: request, + id: id, + expiry: expiry, + completer: completer, + ); + + return AuthRequestResponse( + id: id, + pairingTopic: pTopic, + completer: completer, + uri: uri, + ); + } + + // FORMER AUTH ENGINE PROPERTY + Future _requestAuthResponseHandler({ + required String pairingTopic, + required String responseTopic, + required WcAuthRequestRequest request, + required int id, + required int expiry, + required Completer completer, + }) async { + // Subscribe to the responseTopic because we expect the response to use this topic + await core.relayClient.subscribe(topic: responseTopic); + + late WcAuthRequestResult result; + try { + final Map response = await core.pairing.sendRequest( + pairingTopic, + MethodConstants.WC_AUTH_REQUEST, + request.toJson(), + id: id, + ttl: expiry, + ); + result = WcAuthRequestResult.fromJson({'cacao': response}); + } catch (error) { + final response = AuthResponse( + id: id, + topic: responseTopic, + jsonRpcError: (error is JsonRpcError) ? error : null, + error: (error is! JsonRpcError) + ? WalletConnectError( + code: -1, + message: error.toString(), + ) + : null, + ); + onAuthResponse.broadcast(response); + completer.complete(response); + return; + } + + await core.pairing.activate(topic: pairingTopic); + + final Cacao cacao = result.cacao; + await completeRequests.set( + id.toString(), + StoredCacao.fromCacao( + id: id, + pairingTopic: pairingTopic, + cacao: cacao, + ), + ); + + final isValid = await validateSignedCacao( + cacao: cacao, + projectId: core.projectId, + ); + + if (!isValid) { + final resp = AuthResponse( + id: id, + topic: responseTopic, + error: const WalletConnectError( + code: -1, + message: 'Invalid signature', + ), + ); + onAuthResponse.broadcast(resp); + completer.complete(resp); + } else { + final resp = AuthResponse( + id: id, + topic: responseTopic, + result: cacao, + ); + onAuthResponse.broadcast(resp); + completer.complete(resp); + } + } + + // NEW ONE-CLICK AUTH METHOD FOR DAPPS + @override + Map getPendingSessionAuthRequests() { + Map pendingRequests = {}; + sessionAuthRequests.getAll().forEach((key) { + pendingRequests[key.id] = key; + }); + return pendingRequests; + } + + @override + Future authenticate({ + required SessionAuthRequestParams params, + String? pairingTopic, + List>? methods = const [ + [MethodConstants.WC_SESSION_AUTHENTICATE] + ], + }) async { + _checkInitialized(); + + AuthApiValidators.isValidAuthenticate(params); + + final chains = params.chains; + final resources = params.resources ?? []; + final requestMethods = params.methods ?? []; + + String? pTopic = pairingTopic; + Uri? connectionUri; + + if (pTopic == null) { + final CreateResponse pairing = await core.pairing.create( + methods: methods, + ); + pTopic = pairing.topic; + connectionUri = pairing.uri; + } else { + core.pairing.isValidPairingTopic(topic: pTopic); + } + + final publicKey = await core.crypto.generateKeyPair(); + final responseTopic = core.crypto.getUtils().hashKey(publicKey); + + await Future.wait([ + authKeys.set( + AuthConstants.OCAUTH_CLIENT_PUBLIC_KEY_NAME, + AuthPublicKey(publicKey: publicKey), + ), + pairingTopics.set(responseTopic, pTopic), + ]); + + if (requestMethods.isNotEmpty) { + final namespace = NamespaceUtils.getNamespaceFromChain(chains.first); + String recap = ReCapsUtils.createEncodedRecap( + namespace, + 'request', + requestMethods, + ); + final existingRecap = ReCapsUtils.getRecapFromResources( + resources: resources, + ); + if (existingRecap != null) { + // per Recaps spec, recap must occupy the last position in the resources array + // using .removeLast() to remove the element given we already checked it's a recap and will replace it + recap = ReCapsUtils.mergeEncodedRecaps(recap, resources.removeLast()); + } + resources.add(recap); + } + + // Subscribe to the responseTopic because we expect the response to use this topic + await core.relayClient.subscribe(topic: responseTopic); + + final id = JsonRpcUtils.payloadId(); + final proposalId = JsonRpcUtils.payloadId(); + + // Ensure the expiry is greater than the minimum required for the request - currently 1h + final method = MethodConstants.WC_SESSION_AUTHENTICATE; + final opts = MethodConstants.RPC_OPTS[method]!['req']!; + final authRequestExpiry = max((params.expiry ?? 0), opts.ttl); + final expiryTimestamp = DateTime.now().add( + Duration(seconds: authRequestExpiry), + ); + + final request = WcSessionAuthRequestParams( + authPayload: SessionAuthPayload.fromRequestParams(params).copyWith( + resources: resources, + ), + requester: ConnectionMetadata( + publicKey: publicKey, + metadata: metadata, + ), + expiryTimestamp: expiryTimestamp.millisecondsSinceEpoch, + ); + + // Set the one time use receiver public key for decoding the Type 1 envelope + await core.pairing.setReceiverPublicKey( + topic: responseTopic, + publicKey: publicKey, + expiry: authRequestExpiry, + ); + + Completer completer = Completer(); + + // ----- build fallback session proposal request ----- // + + final fallbackMethod = MethodConstants.WC_SESSION_PROPOSE; + final fallbackOpts = MethodConstants.RPC_OPTS[fallbackMethod]!['req']!; + final fallbackExpiryTimestamp = DateTime.now().add( + Duration(seconds: fallbackOpts.ttl), + ); + final proposalData = ProposalData( + id: proposalId, + requiredNamespaces: {}, + optionalNamespaces: { + 'eip155': RequiredNamespace( + chains: chains, + methods: {'personal_sign', ...requestMethods}.toList(), + events: EventsConstants.requiredEvents, + ), + }, + relays: [Relay(WalletConnectConstants.RELAYER_DEFAULT_PROTOCOL)], + expiry: fallbackExpiryTimestamp.millisecondsSinceEpoch, + proposer: ConnectionMetadata( + publicKey: publicKey, + metadata: metadata, + ), + pairingTopic: pTopic, + ); + final proposeRequest = WcSessionProposeRequest( + relays: proposalData.relays, + requiredNamespaces: proposalData.requiredNamespaces, + optionalNamespaces: proposalData.optionalNamespaces, + proposer: proposalData.proposer, + ); + await _setProposal(proposalData.id, proposalData); + + Completer completerFallback = Completer(); + + pendingProposals.add( + SessionProposalCompleter( + id: proposalData.id, + selfPublicKey: proposalData.proposer.publicKey, + pairingTopic: proposalData.pairingTopic, + requiredNamespaces: proposalData.requiredNamespaces, + optionalNamespaces: proposalData.optionalNamespaces, + completer: completerFallback, + ), + ); + + // ------------------------------------------------------- // + + // Send One-Click Auth request + _sessionAuthResponseHandler( + id: id, + publicKey: publicKey, + pairingTopic: pTopic, + responseTopic: responseTopic, + request: request, + expiry: authRequestExpiry, + completer: completer, + ); + + // Send Session Proposal request + _connectResponseHandler( + pTopic, + proposeRequest, + proposalData.id, + ); + + return SessionAuthRequestResponse( + id: id, + pairingTopic: pTopic, + completer: completer, + uri: connectionUri, + ); + } + + Future _sessionAuthResponseHandler({ + required int id, + required String publicKey, + required String pairingTopic, + required String responseTopic, + required int expiry, + required WcSessionAuthRequestParams request, + required Completer completer, + }) async { + // + late WcSessionAuthRequestResult result; + try { + final Map response = await core.pairing.sendRequest( + pairingTopic, + MethodConstants.WC_SESSION_AUTHENTICATE, + request.toJson(), + id: id, + ttl: expiry, + ); + result = WcSessionAuthRequestResult.fromJson(response); + } catch (error) { + final response = SessionAuthResponse( + id: id, + topic: responseTopic, + jsonRpcError: (error is JsonRpcError) ? error : null, + error: (error is! JsonRpcError) + ? WalletConnectError( + code: -1, + message: error.toString(), + ) + : null, + ); + onSessionAuthResponse.broadcast(response); + completer.complete(response); + return; + } + + await core.pairing.activate(topic: pairingTopic); + + final List cacaos = result.cacaos; + final ConnectionMetadata responder = result.responder; + + final approvedMethods = {}; + final approvedAccounts = {}; + + try { + for (final Cacao cacao in cacaos) { + final isValid = await validateSignedCacao( + cacao: cacao, + projectId: core.projectId, + ); + if (!isValid) { + throw Errors.getSdkError( + Errors.SIGNATURE_VERIFICATION_FAILED, + context: 'Invalid signature', + ); + } + + // This is used on Auth request, would it be needed on 1-CA? + // await completeRequests.set( + // id.toString(), + // StoredCacao.fromCacao( + // id: id, + // pairingTopic: pairingTopic, + // cacao: cacao, + // ), + // ); + + final CacaoPayload payload = cacao.p; + final chainId = AddressUtils.getDidChainId(payload.iss); + final approvedChains = ['eip155:$chainId']; + + final recap = ReCapsUtils.getRecapFromResources( + resources: payload.resources, + ); + if (recap != null) { + final methodsfromRecap = ReCapsUtils.getMethodsFromRecap(recap); + final chainsFromRecap = ReCapsUtils.getChainsFromRecap(recap); + approvedMethods.addAll(methodsfromRecap); + approvedChains.addAll(chainsFromRecap); + } + + final parsedAddress = AddressUtils.getDidAddress(payload.iss); + for (var chain in approvedChains.toSet()) { + approvedAccounts.add('$chain:$parsedAddress'); + } + } + } on WalletConnectError catch (e) { + final resp = SessionAuthResponse( + id: id, + topic: responseTopic, + error: WalletConnectError( + code: e.code, + message: e.message, + ), + ); + onSessionAuthResponse.broadcast(resp); + completer.complete(resp); + return; + } + + final sessionTopic = await core.crypto.generateSharedKey( + publicKey, + responder.publicKey, + ); + + SessionData? session; + if (approvedMethods.isNotEmpty) { + session = SessionData( + topic: sessionTopic, + acknowledged: true, + self: ConnectionMetadata( + publicKey: publicKey, + metadata: metadata, + ), + peer: responder, + controller: publicKey, + expiry: WalletConnectUtils.calculateExpiry( + WalletConnectConstants.SEVEN_DAYS, + ), + relay: Relay(WalletConnectConstants.RELAYER_DEFAULT_PROTOCOL), + pairingTopic: pairingTopic, + namespaces: NamespaceUtils.buildNamespacesFromAuth( + accounts: approvedAccounts, + methods: approvedMethods, + ), + ); + + await core.relayClient.subscribe(topic: sessionTopic); + await sessions.set(sessionTopic, session); + + await core.pairing.updateMetadata( + topic: pairingTopic, + metadata: responder.metadata, + ); + + session = sessions.get(sessionTopic); + } + + final resp = SessionAuthResponse( + id: id, + topic: responseTopic, + auths: cacaos, + session: session, + ); + onSessionAuthResponse.broadcast(resp); + completer.complete(resp); + } + + // FORMER AUTH ENGINE PROPERTY + @override + Future respondAuthRequest({ + required int id, + required String iss, + CacaoSignature? signature, + WalletConnectError? error, + }) async { + _checkInitialized(); + + Map pendingRequests = getPendingAuthRequests(); + AuthApiValidators.isValidRespond( + id: id, + pendingRequests: pendingRequests, + signature: signature, + error: error, + ); + + final PendingAuthRequest pendingRequest = pendingRequests[id]!; + final String receiverPublicKey = pendingRequest.metadata.publicKey; + final String senderPublicKey = await core.crypto.generateKeyPair(); + final String responseTopic = core.crypto.getUtils().hashKey( + receiverPublicKey, + ); + final EncodeOptions encodeOpts = EncodeOptions( + type: EncodeOptions.TYPE_1, + receiverPublicKey: receiverPublicKey, + senderPublicKey: senderPublicKey, + ); + + if (error != null) { + await core.pairing.sendError( + id, + responseTopic, + MethodConstants.WC_AUTH_REQUEST, + JsonRpcError.serverError(error.message), + encodeOptions: encodeOpts, + ); + } else { + final Cacao cacao = Cacao( + h: const CacaoHeader(), + p: CacaoPayload.fromRequestPayload( + issuer: iss, + payload: pendingRequest.cacaoPayload, + ), + s: signature!, + ); + + // print('auth res id: $id'); + await core.pairing.sendResult( + id, + responseTopic, + MethodConstants.WC_AUTH_REQUEST, + cacao.toJson(), + encodeOptions: encodeOpts, + ); + + await authRequests.delete(id.toString()); + + await completeRequests.set( + id.toString(), + StoredCacao.fromCacao( + id: id, + pairingTopic: pendingRequest.pairingTopic, + cacao: cacao, + ), + ); + } + } + + @override + Future approveSessionAuthenticate({ + required int id, + List? auths, + }) async { + _checkInitialized(); + + final pendingRequests = getPendingSessionAuthRequests(); + + AuthApiValidators.isValidRespondAuthenticate( + id: id, + pendingRequests: pendingRequests, + auths: auths, + ); + + final PendingSessionAuthRequest pendingRequest = pendingRequests[id]!; + final receiverPublicKey = pendingRequest.requester.publicKey; + final senderPublicKey = await core.crypto.generateKeyPair(); + final responseTopic = core.crypto.getUtils().hashKey(receiverPublicKey); + + final encodeOpts = EncodeOptions( + type: EncodeOptions.TYPE_1, + receiverPublicKey: receiverPublicKey, + senderPublicKey: senderPublicKey, + ); + + final approvedMethods = {}; + final approvedAccounts = {}; + for (final Cacao cacao in auths!) { + final isValid = await validateSignedCacao( + cacao: cacao, + projectId: core.projectId, + ); + if (!isValid) { + final error = Errors.getSdkError( + Errors.SIGNATURE_VERIFICATION_FAILED, + context: 'Signature verification failed', + ); + await core.pairing.sendError( + id, + responseTopic, + MethodConstants.WC_SESSION_AUTHENTICATE, + JsonRpcError(code: error.code, message: error.message), + encodeOptions: encodeOpts, + ); + throw error; + } + + final CacaoPayload payload = cacao.p; + final chainId = AddressUtils.getDidChainId(payload.iss); + final approvedChains = ['eip155:$chainId']; + + final recap = ReCapsUtils.getRecapFromResources( + resources: payload.resources, + ); + if (recap != null) { + final methodsfromRecap = ReCapsUtils.getMethodsFromRecap(recap); + final chainsFromRecap = ReCapsUtils.getChainsFromRecap(recap); + approvedMethods.addAll(methodsfromRecap); + approvedChains.addAll(chainsFromRecap); + } + + final parsedAddress = AddressUtils.getDidAddress(payload.iss); + for (var chain in approvedChains.toSet()) { + approvedAccounts.add('$chain:$parsedAddress'); + } + } + + final sessionTopic = await core.crypto.generateSharedKey( + senderPublicKey, + receiverPublicKey, + ); + + SessionData? session; + if (approvedMethods.isNotEmpty) { + session = SessionData( + topic: sessionTopic, + acknowledged: true, + self: ConnectionMetadata( + publicKey: senderPublicKey, + metadata: metadata, + ), + peer: pendingRequest.requester, + controller: receiverPublicKey, + expiry: WalletConnectUtils.calculateExpiry( + WalletConnectConstants.SEVEN_DAYS, + ), + relay: Relay(WalletConnectConstants.RELAYER_DEFAULT_PROTOCOL), + pairingTopic: pendingRequest.pairingTopic, + namespaces: NamespaceUtils.buildNamespacesFromAuth( + accounts: approvedAccounts, + methods: approvedMethods, + ), + ); + + await core.relayClient.subscribe(topic: sessionTopic); + await sessions.set(sessionTopic, session); + + session = sessions.get(sessionTopic); + } + + final result = WcSessionAuthRequestResult( + cacaos: auths, + responder: ConnectionMetadata( + publicKey: senderPublicKey, + metadata: metadata, + ), + ); + await core.pairing.sendResult( + id, + responseTopic, + MethodConstants.WC_SESSION_AUTHENTICATE, + result.toJson(), + encodeOptions: encodeOpts, + ); + + await sessionAuthRequests.delete(id.toString()); + await core.pairing.activate(topic: pendingRequest.pairingTopic); + await core.pairing.updateMetadata( + topic: pendingRequest.pairingTopic, + metadata: pendingRequest.requester.metadata, + ); + + return ApproveResponse( + topic: sessionTopic, + session: session, + ); + } + + @override + Future rejectSessionAuthenticate({ + required int id, + required WalletConnectError reason, + }) async { + _checkInitialized(); + + final pendingRequests = getPendingSessionAuthRequests(); + + if (!pendingRequests.containsKey(id)) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: + 'rejectSessionAuthenticate() Could not find pending auth request with id $id', + ); + } + + final PendingSessionAuthRequest pendingRequest = pendingRequests[id]!; + final receiverPublicKey = pendingRequest.requester.publicKey; + final senderPublicKey = await core.crypto.generateKeyPair(); + final responseTopic = core.crypto.getUtils().hashKey(receiverPublicKey); + + final encodeOpts = EncodeOptions( + type: EncodeOptions.TYPE_1, + receiverPublicKey: receiverPublicKey, + senderPublicKey: senderPublicKey, + ); + + final method = MethodConstants.WC_SESSION_AUTHENTICATE; + final rpcOpts = MethodConstants.RPC_OPTS[method]; + await core.pairing.sendError( + id, + responseTopic, + method, + JsonRpcError(code: reason.code, message: reason.message), + encodeOptions: encodeOpts, + rpcOptions: rpcOpts?['reject'], + ); + + await sessionAuthRequests.delete(id.toString()); + await _deleteProposal(id); + } + + // FORMER AUTH ENGINE PROPERTY + void _onAuthRequest(String topic, JsonRpcRequest payload) async { + try { + final request = WcAuthRequestRequest.fromJson(payload.params); + + final CacaoRequestPayload cacaoPayload = + CacaoRequestPayload.fromPayloadParams( + request.payloadParams, + ); + + authRequests.set( + payload.id.toString(), + PendingAuthRequest( + id: payload.id, + pairingTopic: topic, + metadata: request.requester, + cacaoPayload: cacaoPayload, + ), + ); + + onAuthRequest.broadcast( + AuthRequest( + id: payload.id, + topic: topic, + requester: request.requester, + payloadParams: request.payloadParams, + ), + ); + } on WalletConnectError catch (err) { + await core.pairing.sendError( + payload.id, + topic, + payload.method, + JsonRpcError.invalidParams( + err.message, + ), + ); + } + } + + void _onSessionAuthRequest(String topic, JsonRpcRequest payload) async { + core.logger.t('_onSessionAuthRequest, topic: $topic, payload: $payload'); + + final sessionAuthRequest = WcSessionAuthRequestParams.fromJson( + payload.params, + ); + try { + final cacaoPayload = CacaoRequestPayload.fromSessionAuthPayload( + sessionAuthRequest.authPayload, + ); + + final verifyContext = await _getVerifyContext(payload, metadata); + + sessionAuthRequests.set( + payload.id.toString(), + PendingSessionAuthRequest( + id: payload.id, + pairingTopic: topic, + requester: sessionAuthRequest.requester, + authPayload: cacaoPayload, + expiryTimestamp: sessionAuthRequest.expiryTimestamp, + verifyContext: verifyContext, + ), + ); + + onSessionAuthRequest.broadcast( + SessionAuthRequest( + id: payload.id, + topic: topic, + requester: sessionAuthRequest.requester, + authPayload: sessionAuthRequest.authPayload, + verifyContext: verifyContext, + ), + ); + } on WalletConnectError catch (err) { + final receiverPublicKey = sessionAuthRequest.requester.publicKey; + final senderPublicKey = await core.crypto.generateKeyPair(); + + final encodeOpts = EncodeOptions( + type: EncodeOptions.TYPE_1, + receiverPublicKey: receiverPublicKey, + senderPublicKey: senderPublicKey, + ); + final rpcOpts = MethodConstants.RPC_OPTS[payload.method]; + await core.pairing.sendError( + payload.id, + topic, + payload.method, + JsonRpcError.invalidParams(err.message), + encodeOptions: encodeOpts, + rpcOptions: rpcOpts?['autoReject'], + ); + } + } } diff --git a/lib/apis/sign_api/utils/auth/address_utils.dart b/lib/apis/sign_api/utils/auth/address_utils.dart new file mode 100644 index 00000000..77acd45e --- /dev/null +++ b/lib/apis/sign_api/utils/auth/address_utils.dart @@ -0,0 +1,13 @@ +class AddressUtils { + static String getDidAddress(String iss) { + return iss.split(':').last; + } + + static String getDidChainId(String iss) { + return iss.split(':')[3]; + } + + static String getNamespaceDidChainId(String iss) { + return iss.substring(iss.indexOf(RegExp(r':')) + 1); + } +} diff --git a/lib/apis/sign_api/utils/auth/auth_api_validators.dart b/lib/apis/sign_api/utils/auth/auth_api_validators.dart new file mode 100644 index 00000000..7d5a39e7 --- /dev/null +++ b/lib/apis/sign_api/utils/auth/auth_api_validators.dart @@ -0,0 +1,163 @@ +import 'package:walletconnect_flutter_v2/apis/sign_api/utils/auth/auth_constants.dart'; +import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; + +class AuthApiValidators { + static bool isValidRequestExpiry(int expiry) { + return AuthConstants.AUTH_REQUEST_EXPIRY_MIN <= expiry && + expiry <= AuthConstants.AUTH_REQUEST_EXPIRY_MAX; + } + + static bool isValidRequest(AuthRequestParams params) { + if (!NamespaceUtils.isValidUrl(params.aud)) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: + 'requestAuth() invalid aud: ${params.aud}. Must be a valid url.', + ); + } + // final validChainId = true; //NamespaceUtils.isValidChainId(params.chainId); + + if (!params.aud.contains(params.domain)) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: + 'requestAuth() invalid domain: ${params.domain}. aud must contain domain.', + ); + } + + if (params.nonce.isEmpty) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: 'requestAuth() nonce must be nonempty.', + ); + } + + // params.type == null || params.type == CacaoHeader.EIP4361 + if (params.type != null && params.type != CacaoHeader.EIP4361) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: 'requestAuth() type must null or ${CacaoHeader.EIP4361}.', + ); + } + + final expiry = params.expiry; + if (expiry != null && !isValidRequestExpiry(expiry)) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: + 'requestAuth() expiry: $expiry. Expiry must be a number (in seconds) between ${AuthConstants.AUTH_REQUEST_EXPIRY_MIN} and ${AuthConstants.AUTH_REQUEST_EXPIRY_MAX}', + ); + } + + return true; + } + + static bool isValidRespond({ + required int id, + required Map pendingRequests, + CacaoSignature? signature, + WalletConnectError? error, + }) { + if (!pendingRequests.containsKey(id)) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: 'respondAuth() invalid id: $id. No pending request found.', + ); + } + + if (signature == null && error == null) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: + 'respondAuth() invalid response. Must contain either signature or error.', + ); + } + + return true; + } + + static bool isValidAuthenticate(SessionAuthRequestParams params) { + if (params.chains.isEmpty) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: 'authenticate() invalid chains: Must not be emtpy.', + ); + } + + if (!NamespaceUtils.isValidUrl(params.uri)) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: + 'authenticate() invalid uri: ${params.uri}. Must be a valid url.', + ); + } + + if (!params.uri.contains(params.domain)) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: + 'authenticate() invalid domain: ${params.domain}. aud must contain domain.', + ); + } + + if (params.nonce.isEmpty) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: 'authenticate() nonce must be nonempty.', + ); + } + + if (params.type != null && params.type!.t != CacaoHeader.EIP4361) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: 'authenticate() type must null or ${CacaoHeader.EIP4361}.', + ); + } + + final uniqueNamespaces = params.chains.map((chain) { + return NamespaceUtils.getNamespaceFromChain(chain); + }).toSet(); + if (uniqueNamespaces.length > 1) { + throw Errors.getInternalError( + Errors.NON_CONFORMING_NAMESPACES, + context: + 'authenticate() Multi-namespace requests are not supported. Please request single namespace only.', + ); + } + + final namespace = NamespaceUtils.getNamespaceFromChain(params.chains.first); + if (namespace != 'eip155') { + throw Errors.getInternalError( + Errors.NON_CONFORMING_NAMESPACES, + context: + 'authenticate() Only eip155 namespace is supported for authenticated sessions. Please use .connect() for non-eip155 chains.', + ); + } + + return true; + } + + static bool isValidRespondAuthenticate({ + required int id, + required Map pendingRequests, + List? auths, + }) { + if (!pendingRequests.containsKey(id)) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: + 'approveSessionAuthenticate() Could not find pending auth request with id $id', + ); + } + + if (auths == null || auths.isEmpty) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: + 'approveSessionAuthenticate() invalid response. Must contain Cacao signatures.', + ); + } + + return true; + } +} diff --git a/lib/apis/sign_api/utils/auth/auth_constants.dart b/lib/apis/sign_api/utils/auth/auth_constants.dart new file mode 100644 index 00000000..cdddca3e --- /dev/null +++ b/lib/apis/sign_api/utils/auth/auth_constants.dart @@ -0,0 +1,19 @@ +import 'package:walletconnect_flutter_v2/apis/utils/constants.dart'; + +class AuthConstants { + static const AUTH_REQUEST_EXPIRY_MIN = WalletConnectConstants.FIVE_MINUTES; + static const AUTH_REQUEST_EXPIRY_MAX = WalletConnectConstants.SEVEN_DAYS; + + static const AUTH_DEFAULT_URL = 'https://rpc.walletconnect.com/v1'; + + static const AUTH_PROTOCOL = 'wc'; + static const AUTH_VERSION = 1.5; + static const AUTH_CONTEXT = 'auth'; + static const AUTH_STORAGE_PREFIX = + '$AUTH_PROTOCOL@$AUTH_VERSION:$AUTH_CONTEXT:'; + + static const AUTH_CLIENT_PUBLIC_KEY_NAME = 'PUB_KEY'; + + static const OCAUTH_CLIENT_PUBLIC_KEY_NAME = + '$AUTH_STORAGE_PREFIX:$AUTH_CLIENT_PUBLIC_KEY_NAME'; +} diff --git a/lib/apis/sign_api/utils/auth/auth_signature.dart b/lib/apis/sign_api/utils/auth/auth_signature.dart new file mode 100644 index 00000000..bdd7ea50 --- /dev/null +++ b/lib/apis/sign_api/utils/auth/auth_signature.dart @@ -0,0 +1,303 @@ +import 'dart:convert'; +import 'dart:typed_data'; +import 'package:convert/convert.dart'; +import 'package:http/http.dart' as http; + +import 'package:pointycastle/digests/keccak.dart'; +import 'package:walletconnect_flutter_v2/apis/core/pairing/utils/json_rpc_utils.dart'; +import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/common_auth_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/session_auth_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/utils/auth/auth_constants.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/utils/auth/recaps_utils.dart'; +import 'package:web3dart/crypto.dart' as crypto; + +class AuthSignature { + static final KeccakDigest keccakDigest = KeccakDigest(256); + static Uint8List keccak256(Uint8List input) { + keccakDigest.reset(); + return keccakDigest.process(input); + } + + static Uint8List hashMessage(String message) { + return keccak256( + Uint8List.fromList( + utf8.encode( + [ + '\x19Ethereum Signed Message:\n', + message.length.toString(), + message, + ].join(), + ), + ), + ); + } + + static int getNormalizedV(int v) { + if (v == 0 || v == 27) { + return 27; + } + if (v == 1 || v == 28) { + return 28; + } + return v & 1 == 1 ? 27 : 28; + } + + static bool isValidEip191Signature( + String address, + String message, + String sig, + ) { + // Get the sig bytes + // print(sig); + final sigBytes = Uint8List.fromList( + hex.decode(sig.substring(2)), + ); + + // If the sig bytes aren't 65 bytes long, throw an error + if (sigBytes.length != 65) { + throw Exception('Invalid signature length'); + } + + // Get the r and s values from the sig bytes + final r = BigInt.parse( + hex.encode(sigBytes.sublist(0, 32)), + radix: 16, + ); + final s = BigInt.parse( + hex.encode(sigBytes.sublist(32, 64)), + radix: 16, + ); + // print(sigBytes[64]); + final v = getNormalizedV(sigBytes[64]); + // print(r); + // print(s); + // print(v); + + // // Recover the public key from the signature + // Uint8List? publicKeyBytes = AuthSecp256k1.recoverPublicKeyFromSignature( + // v - 27, + // r, + // s, + // hashMessage(message), + // ); + + // // If the public key is null, return false + // if (publicKeyBytes == null) { + // print('Could not derive publicKey'); + // return false; + // } + + // Convert the public key to an address + final publicKeyBytes = crypto.ecRecover( + hashMessage(message), + crypto.MsgSignature(r, s, v), + ); + // print(hex.encode(publicKeyBytes)); + final hashedPubKeyBytes = keccak256(publicKeyBytes); + final addressBytes = hashedPubKeyBytes.sublist(12, 32); + final recoveredAddress = '0x${hex.encode(addressBytes)}'; + + // final String recoveredAddress = EthSigUtil.recoverSignature( + // signature: sig, + // message: hashMessage(message), + // // Uint8List.fromList( + // // ascii.encode(message), + // // ), + // ); + + // print(recoveredAddress.toLowerCase()); + // print(address.toLowerCase()); + + return recoveredAddress.toLowerCase() == address.toLowerCase(); + } + + static Future isValidEip1271Signature( + String address, + String reconstructedMessage, + String cacaoSignature, + String chainId, + String projectId, + ) async { + try { + const String eip1271MagicValue = '0x1626ba7e'; + const String dynamicTypeOffset = + '0000000000000000000000000000000000000000000000000000000000000040'; + const String dynamicTypeLength = + '0000000000000000000000000000000000000000000000000000000000000041'; + final String nonPrefixedSignature = cacaoSignature.substring(2); + final String nonPrefixedHashedMessage = + hex.encode(hashMessage(reconstructedMessage)).substring(2); + + final String data = eip1271MagicValue + + nonPrefixedHashedMessage + + dynamicTypeOffset + + dynamicTypeLength + + nonPrefixedSignature; + + final Uri url = Uri.parse( + '${AuthConstants.AUTH_DEFAULT_URL}/?chainId=$chainId&projectId=$projectId', + ); + final Map body = JsonRpcUtils.formatJsonRpcRequest( + 'eth_call', + { + 'to': address, + 'data': data, + }, + ); + + final http.Response response = await http.post( + url, + body: body, + ); + + // print(response.body); + // final jsonBody = jsonDecode(response.body); + final String recoveredValue = + response.body.substring(0, eip1271MagicValue.length); + return recoveredValue.toLowerCase() == eip1271MagicValue.toLowerCase(); + } catch (e) { + return false; + } + } + + // verifies CACAO signature + // Used by the wallet after formatting the message + static Future verifySignature( + String address, + String reconstructedMessage, + CacaoSignature cacaoSignature, + String chainId, + String projectId, + ) async { + if (cacaoSignature.t == 'eip191') { + return isValidEip191Signature( + address, + reconstructedMessage, + cacaoSignature.s, + ); + } else if (cacaoSignature.t == 'eip1271') { + return await isValidEip1271Signature( + address, + reconstructedMessage, + cacaoSignature.s, + chainId, + projectId, + ); + } else { + throw Exception( + 'verifySignature failed: Attempted to verify CacaoSignature with unknown type: ${cacaoSignature.t}', + ); + } + } + + static Cacao buildAuthObject({ + required CacaoRequestPayload requestPayload, + required CacaoSignature signature, + required String iss, + }) { + if (!iss.contains('did:pkh:')) { + iss = 'did:pkh:$iss'; + } + return Cacao( + h: const CacaoHeader(t: CacaoHeader.CAIP122), + p: CacaoPayload.fromRequestPayload( + issuer: iss, + payload: requestPayload, + ), + s: signature, + ); + } + + static SessionAuthPayload populateAuthPayload({ + required SessionAuthPayload authPayload, + required List chains, + required List methods, + }) { + final statement = authPayload.statement ?? ''; + + if (chains.isEmpty) return authPayload; + + final requested = authPayload.chains; + final supported = chains; + + final approvedChains = + supported.where((value) => requested.contains(value)).toList(); + if (approvedChains.isEmpty) { + throw WalletConnectError(code: -1, message: 'No supported chains'); + } + + final requestedRecaps = ReCapsUtils.getDecodedRecapFromResources( + resources: authPayload.resources, + ); + if (requestedRecaps == null) return authPayload; + + ReCapsUtils.isValidRecap(requestedRecaps); + + final resource = ReCapsUtils.getRecapResource( + recap: requestedRecaps, + resource: 'eip155', + ); + List updatedResources = authPayload.resources ?? []; + + if (resource.isNotEmpty) { + final actions = ReCapsUtils.getReCapActions(abilities: resource); + final approvedActions = + actions.where((value) => methods.contains(value)).toList(); + if (approvedActions.isEmpty) { + throw WalletConnectError( + code: -1, + message: 'Supported methods don\'t satisfy the requested: $actions, ' + 'supported: $methods', + ); + } + final formattedActions = ReCapsUtils.assignAbilityToActions( + 'request', + approvedActions, + limits: {'chains': approvedChains}, + ); + final updatedRecap = ReCapsUtils.addResourceToRecap( + recap: requestedRecaps, + resource: 'eip155', + actions: formattedActions, + ); + // remove recap from resources as we will add the updated one + updatedResources = List.from((authPayload.resources ?? [])) + ..removeLast(); + updatedResources.add(ReCapsUtils.encodeRecap(updatedRecap)); + } + // + return SessionAuthPayload.fromJson(authPayload.toJson()).copyWith( + statement: ReCapsUtils.buildRecapStatement( + statement, + ReCapsUtils.getRecapFromResources(resources: updatedResources), + ), + chains: approvedChains, + resources: updatedResources.isNotEmpty ? updatedResources : null, + ); + } + + static String getAddressFromMessage(String message) { + try { + final regexp = RegExp('0x[a-fA-F0-9]{40}'); + final matches = regexp.allMatches(message); + for (final Match m in matches) { + return m[0]!; + } + return ''; + } catch (_) {} + return ''; + } + + static String getChainIdFromMessage(String message) { + try { + final pattern = 'Chain ID: '; + final regexp = RegExp('$pattern(?\\d+)'); + final matches = regexp.allMatches(message); + for (final Match m in matches) { + return m[0]!.toString().replaceAll(pattern, ''); + } + } catch (_) {} + return ''; + } +} diff --git a/lib/apis/sign_api/utils/auth/auth_utils.dart b/lib/apis/sign_api/utils/auth/auth_utils.dart new file mode 100644 index 00000000..7f4e8016 --- /dev/null +++ b/lib/apis/sign_api/utils/auth/auth_utils.dart @@ -0,0 +1,5 @@ +class AuthUtils { + static String generateNonce() { + return DateTime.now().millisecondsSinceEpoch.toString(); + } +} diff --git a/lib/apis/sign_api/utils/auth/recaps_utils.dart b/lib/apis/sign_api/utils/auth/recaps_utils.dart new file mode 100644 index 00000000..0c8a20fa --- /dev/null +++ b/lib/apis/sign_api/utils/auth/recaps_utils.dart @@ -0,0 +1,348 @@ +import 'dart:convert'; + +import 'package:flutter/foundation.dart'; +import 'package:walletconnect_flutter_v2/apis/utils/errors.dart'; + +class ReCapsUtils { + // + static String? getRecapFromResources({List? resources}) { + final resourcesList = resources ?? []; + if (resourcesList.isEmpty) return null; + // per spec, recap is always the last resource + final recap = resourcesList.last; + return isRecap(recap) ? recap : null; + } + + static bool isRecap(String resource) { + return resource.contains('urn:recap:'); + } + + static List getMethodsFromRecap(String recap) { + final decodedRecap = decodeRecap(recap); + if (!isValidRecap(decodedRecap)) return []; + + try { + // methods are only available for eip155 as per the current implementation + final resource = decodedRecap['att']?['eip155'] as Map?; + if (resource == null) return []; + + return resource.keys.map((k) => k.split('/').last).toList(); + } catch (e) { + return []; + } + } + + static List getChainsFromRecap(String recap) { + final decodedRecap = decodeRecap(recap); + if (!isValidRecap(decodedRecap)) return []; + + final List recapChains = []; + try { + final att = + decodedRecap['att'] as Map? ?? {}; + + for (var resources in att.values) { + final resourcesMap = resources as Map; + final resourcesValues = resourcesMap.values.first as List; + for (var value in resourcesValues) { + final chainValues = value as Map; + final chains = chainValues['chains'] as List; + recapChains.addAll(chains); + } + } + return recapChains.map((e) => e.toString()).toSet().toList(); + } catch (e) { + return []; + } + } + + static Map decodeRecap(String recap) { + // Add the padding that was removed during encoding + String paddedRecap = recap.replaceAll('urn:recap:', ''); + final padding = paddedRecap.length % 4; + if (padding > 0) { + paddedRecap += '=' * (4 - padding); + } + + final decoded = utf8.decode(base64.decode(paddedRecap)); + final decodedRecap = jsonDecode(decoded) as Map; + isValidRecap(decodedRecap); + return decodedRecap; + } + + static bool isValidRecap(Map recap) { + final att = recap['att'] as Map?; + if (att == null) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: 'Invalid ReCap. No `att` property found', + ); + } + // + final resources = att.keys; + if (resources.isEmpty) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: 'Invalid ReCap. No resources found in `att` property', + ); + } + // + for (var resource in resources) { + final abilities = att[resource]; + if (abilities is! Map) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: 'Invalid ReCap. Resource must be an object: $resource', + ); + } + final resourceAbilities = (abilities as Map).keys; + if (resourceAbilities.isEmpty) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: 'Invalid ReCap. Resource object is empty: $resource', + ); + } + // + for (var ability in resourceAbilities) { + final limits = abilities[ability]; + if (limits is! List) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: 'Invalid ReCap. Ability limits $ability must be an array ' + 'of objects, found: $limits', + ); + } + if ((limits).isEmpty) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: 'Invalid ReCap. Value of $ability is empty array, must be ' + 'an array with objects', + ); + } + // + for (var limit in limits) { + if (limit is! Map) { + throw Errors.getInternalError( + Errors.MISSING_OR_INVALID, + context: + 'Invalid ReCap. Ability limits ($ability) must be an array ' + 'of objects, found: $limit', + ); + } + } + } + } + + return true; + } + + static String createEncodedRecap( + String namespace, + String ability, + List methods, + ) { + final recap = createRecap(namespace, ability, methods); + return encodeRecap(recap); + } + + static String encodeRecap(Map recap) { + isValidRecap(recap); + final jsonRecap = jsonEncode(recap); + final bytes = utf8.encode(jsonRecap).toList(); + // remove the padding from the base64 string as per recap spec + return 'urn:recap:${base64.encode(bytes).replaceAll('=', '')}'; + } + + static Map createRecap( + String namespace, + String ability, + List methods, { + Map limits = const {}, + }) { + try { + final sortedMethods = List.from(methods) + ..sort((a, b) => a.compareTo(b)); + + Map abilities = {}; + for (var method in sortedMethods) { + abilities['$ability/$method'] = [ + ...(abilities['$ability/$method'] ?? []), + limits, + ]; + } + + return { + 'att': { + namespace: Map.fromEntries(abilities.entries), + } + }; + } catch (e) { + rethrow; + } + } + + static String mergeEncodedRecaps(String recap1, String recap2) { + final decoded1 = decodeRecap(recap1); + final decoded2 = decodeRecap(recap2); + final merged = mergeRecaps(decoded1, decoded2); + return encodeRecap(merged); + } + + static Map mergeRecaps( + Map recap1, + Map recap2, + ) { + isValidRecap(recap1); + isValidRecap(recap2); + final att1 = recap1['att'] as Map; + final att2 = recap2['att'] as Map; + final keys = [...att1.keys, ...att2.keys]..sort( + (a, b) => a.compareTo(b), + ); + final mergedRecap = {'att': {}}; + + for (var key in keys) { + final actions1 = att1[key] as Map? ?? {}; + final actions1Keys = actions1.keys; + final actions2 = att2[key] as Map? ?? {}; + final actions2Keys = actions2.keys; + final actions = [...actions1Keys, ...actions2Keys]..sort( + (a, b) => a.compareTo(b), + ); + + for (var action in actions) { + mergedRecap['att']![key] = { + ...mergedRecap['att']?[key], + [action]: recap1['att'][key]?[action] || recap2['att'][key]?[action], + }; + } + } + + return mergedRecap; + } + + static Map? getDecodedRecapFromResources({ + List? resources, + }) { + final resource = getRecapFromResources(resources: resources); + if (resource == null) return null; + if (!isRecap(resource)) return null; + return decodeRecap(resource); + } + + static String formatStatementFromRecap({ + String statement = '', + Map recap = const {}, + }) { + isValidRecap(recap); + // + final baseStatement = + 'I further authorize the stated URI to perform the following actions on my behalf: '; + if (statement.contains(baseStatement)) return statement; + // + final List statementForRecap = []; + int currentCounter = 0; + final att = recap['att'] as Map; + final resources = att.keys; + for (var resource in resources) { + final abilities = att[resource]; + final resourceAbilities = (abilities as Map).keys; + final actions = resourceAbilities.map((ability) { + return { + 'ability': ability.split('/')[0], + 'action': ability.split('/')[1], + }; + }).toList(); + actions.sort((a, b) => a['action']!.compareTo(b['action']!)); + // + final uniqueAbilities = {}; + for (var actionMap in actions) { + final ability = actionMap['ability']!; + final action = actionMap['action']!; + if (uniqueAbilities[ability] == null) { + uniqueAbilities[ability] = []; + } + uniqueAbilities[ability].add(action); + } + // + final abilitiesStatements = uniqueAbilities.keys.map((ability) { + currentCounter++; + final abilities = (uniqueAbilities[ability] as List).join('\', \''); + return '($currentCounter) \'$ability\': \'$abilities\' for \'$resource\'.'; + }).toList(); + + statementForRecap.add( + abilitiesStatements.join(', ').replaceAll('.,', '.'), + ); + } + // + final recapStatemet = statementForRecap.join(' '); + final recapStatement = '$baseStatement$recapStatemet'; + // add a space if there is a statement + return '${statement.isNotEmpty ? "$statement " : ""}$recapStatement'; + } + + static List getRecapResource({ + required Map recap, + required String resource, + }) { + try { + final att = recap['att'] as Map?; + final abilities = att?[resource] as Map?; + if (abilities != null) { + return abilities.keys.toList(); + } + } catch (e) { + debugPrint(e.toString()); + } + return []; + } + + static List getReCapActions({required List abilities}) { + try { + return abilities.map((ability) => ability.split('/')[1]).toList(); + } catch (e) { + debugPrint(e.toString()); + } + return []; + } + + static Map assignAbilityToActions( + String ability, + List actions, { + Map limits = const {}, + }) { + final sortedActions = List.from(actions) + ..sort((a, b) => a.compareTo(b)); + + Map abilities = {}; + for (var method in sortedActions) { + abilities['$ability/$method'] = [ + ...(abilities['$ability/$method'] ?? []), + limits, + ]; + } + + return Map.fromEntries(abilities.entries); + } + + static Map addResourceToRecap({ + required Map recap, + required String resource, + required Map actions, + }) { + // + final sortedRecap = Map.from(recap); + sortedRecap['att']![resource] = actions; + sortedRecap.keys.toList().sort((a, b) => a.compareTo(b)); + isValidRecap(sortedRecap); + return sortedRecap; + } + + static String buildRecapStatement(String statement, String? recap) { + if ((recap ?? '').isEmpty) return statement; + final decoded = decodeRecap(recap!); + isValidRecap(decoded); + return formatStatementFromRecap(statement: statement, recap: decoded); + } +} diff --git a/lib/apis/sign_api/utils/auth/secp256k1/LICENSE b/lib/apis/sign_api/utils/auth/secp256k1/LICENSE new file mode 100644 index 00000000..5c8f2ec8 --- /dev/null +++ b/lib/apis/sign_api/utils/auth/secp256k1/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2021 Wakumo Vietnam + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/lib/apis/sign_api/utils/auth/secp256k1/auth_secp256k1.dart b/lib/apis/sign_api/utils/auth/secp256k1/auth_secp256k1.dart new file mode 100644 index 00000000..20475249 --- /dev/null +++ b/lib/apis/sign_api/utils/auth/secp256k1/auth_secp256k1.dart @@ -0,0 +1,115 @@ +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:convert/convert.dart'; +import 'package:pointycastle/ecc/api.dart'; +import 'package:pointycastle/ecc/curves/secp256k1.dart'; + +enum Endian { + be, +} + +class AuthSecp256k1 { + static final ECDomainParameters _params = ECCurve_secp256k1(); + static final BigInt _byteMask = BigInt.from(0xff); + + static BigInt decodeBigInt(List bytes) { + BigInt result = BigInt.from(0); + for (int i = 0; i < bytes.length; i++) { + result += BigInt.from(bytes[bytes.length - i - 1]) << (8 * i); + } + return result; + } + + static Uint8List encodeBigInt( + BigInt input, { + Endian endian = Endian.be, + int length = 0, + }) { + int byteLength = (input.bitLength + 7) >> 3; + int reqLength = length > 0 ? length : max(1, byteLength); + assert(byteLength <= reqLength, 'byte array longer than desired length'); + assert(reqLength > 0, 'Requested array length <= 0'); + + var res = Uint8List(reqLength); + res.fillRange(0, reqLength - byteLength, 0); + + var q = input; + if (endian == Endian.be) { + for (int i = 0; i < byteLength; i++) { + res[reqLength - i - 1] = (q & _byteMask).toInt(); + q = q >> 8; + } + return res; + } + + return Uint8List(0); + } + + static ECPoint _decompressKey(BigInt xBN, bool yBit, ECCurve c) { + List x9IntegerToBytes(BigInt s, int qLength) { + //https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java#L45 + String hexString = s.toRadixString(16); + if (hexString.length % 2 == 1) { + hexString = '0$hexString'; + } + final bytes = hex.decode(hexString); + + if (qLength < bytes.length) { + return bytes.sublist(0, bytes.length - qLength); + } else if (qLength > bytes.length) { + final tmp = List.filled(qLength, 0); + + final offset = qLength - bytes.length; + for (var i = 0; i < bytes.length; i++) { + tmp[i + offset] = bytes[i]; + } + + return tmp; + } + + return bytes; + } + + final compEnc = x9IntegerToBytes(xBN, 1 + ((c.fieldSize + 7) ~/ 8)); + compEnc[0] = yBit ? 0x03 : 0x02; + return c.decodePoint(compEnc)!; + } + + static Uint8List? recoverPublicKeyFromSignature( + int recId, + BigInt r, + BigInt s, + Uint8List message, + ) { + final n = _params.n; + final i = BigInt.from(recId ~/ 2); + final x = r + (i * n); + + //Parameter q of curve + final prime = BigInt.parse( + 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', + radix: 16); + if (x.compareTo(prime) >= 0) return null; + + final R = _decompressKey(x, (recId & 1) == 1, _params.curve); + final ECPoint? ecPoint = R * n; + if (ecPoint == null || !ecPoint.isInfinity) return null; + + // print(bytesToHex(message)); + // final e = BigInt.parse(bytesToHex(message).substring(1)); + final e = decodeBigInt(message.toList()); + + final eInv = (BigInt.zero - e) % n; + final rInv = r.modInverse(n); + final srInv = (rInv * s) % n; + final eInvrInv = (rInv * eInv) % n; + + final preQ = (_params.G * eInvrInv); + if (preQ == null) return null; + final q = preQ + (R * srInv); + + final bytes = q?.getEncoded(false); + return bytes?.sublist(1); + } +} diff --git a/lib/apis/utils/method_constants.dart b/lib/apis/utils/method_constants.dart index d80b141e..82592401 100644 --- a/lib/apis/utils/method_constants.dart +++ b/lib/apis/utils/method_constants.dart @@ -17,6 +17,8 @@ class MethodConstants { static const WC_AUTH_REQUEST = 'wc_authRequest'; + static const WC_SESSION_AUTHENTICATE = 'wc_sessionAuthenticate'; + static const Map> RPC_OPTS = { WC_PAIRING_PING: { 'req': RpcOptions( @@ -65,6 +67,16 @@ class MethodConstants { prompt: false, tag: 1101, ), + 'reject': RpcOptions( + ttl: WalletConnectConstants.FIVE_MINUTES, + prompt: false, + tag: 1120, + ), + 'autoReject': RpcOptions( + ttl: WalletConnectConstants.FIVE_MINUTES, + prompt: false, + tag: 1121, + ), }, WC_SESSION_SETTLE: { 'req': RpcOptions( @@ -150,6 +162,28 @@ class MethodConstants { tag: 1115, ), }, + WC_SESSION_AUTHENTICATE: { + 'req': RpcOptions( + ttl: WalletConnectConstants.ONE_HOUR, + prompt: false, + tag: 1116, + ), + 'res': RpcOptions( + ttl: WalletConnectConstants.ONE_HOUR, + prompt: false, + tag: 1117, + ), + 'reject': RpcOptions( + ttl: WalletConnectConstants.FIVE_MINUTES, + prompt: false, + tag: 1118, + ), + 'autoReject': RpcOptions( + ttl: WalletConnectConstants.FIVE_MINUTES, + prompt: false, + tag: 1119, + ), + }, WC_AUTH_REQUEST: { 'req': RpcOptions( ttl: WalletConnectConstants.ONE_DAY, diff --git a/lib/apis/utils/namespace_utils.dart b/lib/apis/utils/namespace_utils.dart index 243cdb29..e1ad9c7f 100644 --- a/lib/apis/utils/namespace_utils.dart +++ b/lib/apis/utils/namespace_utils.dart @@ -1,5 +1,6 @@ import 'package:walletconnect_flutter_v2/apis/sign_api/models/proposal_models.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/models/session_models.dart'; +import 'package:walletconnect_flutter_v2/apis/utils/constants.dart'; class NamespaceUtils { /// Checks if the string is a chain @@ -75,18 +76,34 @@ class NamespaceUtils { /// Gets all unique namespaces from the provided list of accounts /// This function assumes that all accounts are valid - // static List getNamespacesFromAccounts(List accounts) { - // Set namespaces = {}; - // accounts.forEach((account) { - // chains.add( - // getChainFromAccount( - // account, - // ), - // ); - // }); - - // return chains.toList(); - // } + static Map getNamespacesFromAccounts( + List accounts, + ) { + Map namespaces = {}; + for (var account in accounts) { + final ns = account.split(':')[0]; + final cid = account.split(':')[1]; + if (namespaces[ns] == null) { + namespaces[ns] = Namespace( + accounts: [], + methods: [], + events: [], + ); + } + namespaces[ns] = namespaces[ns]!.copyWith( + accounts: [ + ...namespaces[ns]!.accounts, + account, + ], + chains: [ + ...(namespaces[ns]?.chains ?? []), + '$ns:$cid', + ], + ); + } + + return namespaces; + } /// Gets the chains from the namespace. /// If the namespace is a chain, then it returns the chain. @@ -271,6 +288,29 @@ class NamespaceUtils { }; } + static Map buildNamespacesFromAuth({ + required Set methods, + required Set accounts, + }) { + final parsedAccounts = accounts.map( + (account) => account.replaceAll('did:pkh:', ''), + ); + + final namespaces = getNamespacesFromAccounts(parsedAccounts.toList()); + + final entries = namespaces.entries.map((e) { + return MapEntry( + e.key, + Namespace.fromJson(e.value.toJson()).copyWith( + methods: methods.toList(), + events: EventsConstants.allEvents, + ), + ); + }); + + return Map.fromEntries(entries); + } + /// Gets the matching items from the available items using the chainId /// This function assumes that each element in the available items is in the format of chainId:itemId static Set _getMatching({ diff --git a/lib/apis/utils/walletconnect_utils.dart b/lib/apis/utils/walletconnect_utils.dart index fd5c01c0..901b26f2 100644 --- a/lib/apis/utils/walletconnect_utils.dart +++ b/lib/apis/utils/walletconnect_utils.dart @@ -184,21 +184,18 @@ class WalletConnectUtils { required String symKey, required Relay relay, required List>? methods, + int? expiry, }) { Map params = formatRelayParams(relay); params['symKey'] = symKey; if (methods != null) { - params['methods'] = methods - .map((e) => jsonEncode(e)) - .join( - ',', - ) - .replaceAll( - '"', - '', - ); - } else { - params['methods'] = '[]'; + final uriMethods = methods.expand((e) => e).toList(); + params['methods'] = + uriMethods.map((e) => jsonEncode(e)).join(',').replaceAll('"', ''); + } + + if (expiry != null) { + params['expiryTimestamp'] = expiry.toString(); } return Uri( diff --git a/lib/apis/web3app/i_web3app.dart b/lib/apis/web3app/i_web3app.dart index 300a4df3..4e8b9f2f 100644 --- a/lib/apis/web3app/i_web3app.dart +++ b/lib/apis/web3app/i_web3app.dart @@ -1,7 +1,8 @@ -import 'package:walletconnect_flutter_v2/apis/auth_api/i_auth_engine_app.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/i_sign_engine_app.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; +import 'package:walletconnect_flutter_v2/apis/auth_api/i_auth_engine_app.dart'; + abstract class IWeb3App implements ISignEngineApp, IAuthEngineApp { final String protocol = 'wc'; final int version = 2; diff --git a/lib/apis/web3app/web3app.dart b/lib/apis/web3app/web3app.dart index 5252c7ac..28be6cb8 100644 --- a/lib/apis/web3app/web3app.dart +++ b/lib/apis/web3app/web3app.dart @@ -85,11 +85,6 @@ class Web3App implements IWeb3App { return SessionRequest.fromJson(value); }, ), - ); - - authEngine = AuthEngine( - core: core, - metadata: metadata, authKeys: GenericStore( storage: core.storage, context: StoreVersions.CONTEXT_AUTH_KEYS, @@ -122,6 +117,23 @@ class Web3App implements IWeb3App { return StoredCacao.fromJson(value); }, ), + sessionAuthRequests: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_AUTH_REQUESTS, + version: StoreVersions.VERSION_AUTH_REQUESTS, + fromJson: (dynamic value) { + return PendingSessionAuthRequest.fromJson(value); + }, + ), + ); + + authEngine = AuthEngine( + core: core, + metadata: metadata, + authKeys: signEngine.authKeys, + pairingTopics: signEngine.pairingTopics, + authRequests: signEngine.authRequests, + completeRequests: signEngine.completeRequests, ); } @@ -333,7 +345,8 @@ class Web3App implements IWeb3App { @override IPairingStore get pairings => core.pairing.getStore(); - ///---------- AUTH ENGINE ----------/// + ///---------- (DEPRECATED) AUTH ENGINE ----------/// + @override Event get onAuthResponse => authEngine.onAuthResponse; @@ -345,6 +358,10 @@ class Web3App implements IWeb3App { IGenericStore get completeRequests => authEngine.completeRequests; + @Deprecated( + 'AuthEngine/AuthClient is deprecated and will be removed soon.\n' + 'Please use authentication methods from SignEngine/SignClient instead', + ) @override late IAuthEngine authEngine; @@ -378,13 +395,53 @@ class Web3App implements IWeb3App { } } + ///---------- ONE-CLICK AUTH SIGN ENGINE ----------/// + + @override + Event get onSessionAuthResponse => + signEngine.onSessionAuthResponse; + + @override + Future authenticate({ + required SessionAuthRequestParams params, + String? pairingTopic, + List>? methods = const [ + [MethodConstants.WC_SESSION_AUTHENTICATE] + ], + }) async { + try { + return signEngine.authenticate( + params: params, + pairingTopic: pairingTopic, + methods: methods, + ); + } catch (e) { + rethrow; + } + } + + @override + Future validateSignedCacao({ + required Cacao cacao, + required String projectId, + }) { + try { + return signEngine.validateSignedCacao( + cacao: cacao, + projectId: projectId, + ); + } catch (e) { + rethrow; + } + } + @override String formatAuthMessage({ required String iss, required CacaoRequestPayload cacaoPayload, }) { try { - return authEngine.formatAuthMessage( + return signEngine.formatAuthMessage( iss: iss, cacaoPayload: cacaoPayload, ); diff --git a/lib/apis/web3wallet/i_web3wallet.dart b/lib/apis/web3wallet/i_web3wallet.dart index 20f0a0b8..86b07a66 100644 --- a/lib/apis/web3wallet/i_web3wallet.dart +++ b/lib/apis/web3wallet/i_web3wallet.dart @@ -1,7 +1,8 @@ -import 'package:walletconnect_flutter_v2/apis/auth_api/i_auth_engine_wallet.dart'; import 'package:walletconnect_flutter_v2/apis/sign_api/i_sign_engine_wallet.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; +import 'package:walletconnect_flutter_v2/apis/auth_api/i_auth_engine_wallet.dart'; + abstract class IWeb3Wallet implements ISignEngineWallet, IAuthEngineWallet { final String protocol = 'wc'; final int version = 2; diff --git a/lib/apis/web3wallet/web3wallet.dart b/lib/apis/web3wallet/web3wallet.dart index fe11ac3c..75c95cce 100644 --- a/lib/apis/web3wallet/web3wallet.dart +++ b/lib/apis/web3wallet/web3wallet.dart @@ -78,11 +78,6 @@ class Web3Wallet implements IWeb3Wallet { return SessionRequest.fromJson(value); }, ), - ); - - authEngine = AuthEngine( - core: core, - metadata: metadata, authKeys: GenericStore( storage: core.storage, context: StoreVersions.CONTEXT_AUTH_KEYS, @@ -115,6 +110,23 @@ class Web3Wallet implements IWeb3Wallet { return StoredCacao.fromJson(value); }, ), + sessionAuthRequests: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_AUTH_REQUESTS, + version: StoreVersions.VERSION_AUTH_REQUESTS, + fromJson: (dynamic value) { + return PendingSessionAuthRequest.fromJson(value); + }, + ), + ); + + authEngine = AuthEngine( + core: core, + metadata: metadata, + authKeys: signEngine.authKeys, + pairingTopics: signEngine.pairingTopics, + authRequests: signEngine.authRequests, + completeRequests: signEngine.completeRequests, ); } @@ -385,7 +397,8 @@ class Web3Wallet implements IWeb3Wallet { @override IPairingStore get pairings => core.pairing.getStore(); - ///---------- AUTH ENGINE ----------/// + ///---------- (DEPRECATED) AUTH ENGINE ----------/// + @override Event get onAuthRequest => authEngine.onAuthRequest; @@ -399,6 +412,10 @@ class Web3Wallet implements IWeb3Wallet { IGenericStore get completeRequests => authEngine.completeRequests; + @Deprecated( + 'AuthEngine/AuthClient is deprecated and will be removed soon.\n' + 'Please use authentication methods from SignEngine/SignClient instead', + ) @override late IAuthEngine authEngine; @@ -408,7 +425,7 @@ class Web3Wallet implements IWeb3Wallet { required String iss, CacaoSignature? signature, WalletConnectError? error, - }) async { + }) { try { return authEngine.respondAuthRequest( id: id, @@ -443,13 +460,61 @@ class Web3Wallet implements IWeb3Wallet { } } + ///---------- ONE-CLICK AUTH SIGN ENGINE ----------/// + + @override + IGenericStore get sessionAuthRequests => + signEngine.sessionAuthRequests; + @override + Event get onSessionAuthRequest => + signEngine.onSessionAuthRequest; + + @override + Future approveSessionAuthenticate({ + required int id, + List? auths, + }) { + try { + return signEngine.approveSessionAuthenticate( + id: id, + auths: auths, + ); + } catch (e) { + rethrow; + } + } + + @override + Future rejectSessionAuthenticate({ + required int id, + required WalletConnectError reason, + }) { + try { + return signEngine.rejectSessionAuthenticate( + id: id, + reason: reason, + ); + } catch (e) { + rethrow; + } + } + + @override + Map getPendingSessionAuthRequests() { + try { + return signEngine.getPendingSessionAuthRequests(); + } catch (e) { + rethrow; + } + } + @override String formatAuthMessage({ required String iss, required CacaoRequestPayload cacaoPayload, }) { try { - return authEngine.formatAuthMessage( + return signEngine.formatAuthMessage( iss: iss, cacaoPayload: cacaoPayload, ); @@ -457,4 +522,19 @@ class Web3Wallet implements IWeb3Wallet { rethrow; } } + + @override + Future validateSignedCacao({ + required Cacao cacao, + required String projectId, + }) { + try { + return signEngine.validateSignedCacao( + cacao: cacao, + projectId: projectId, + ); + } catch (e) { + rethrow; + } + } } diff --git a/lib/src/version.dart b/lib/src/version.dart index c168df12..65b3d782 100644 --- a/lib/src/version.dart +++ b/lib/src/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '2.2.3'; +const packageVersion = '2.3.0-beta01'; diff --git a/lib/walletconnect_flutter_v2.dart b/lib/walletconnect_flutter_v2.dart index 4e6f2ba0..9d04f292 100644 --- a/lib/walletconnect_flutter_v2.dart +++ b/lib/walletconnect_flutter_v2.dart @@ -9,6 +9,7 @@ export 'apis/core/relay_client/relay_client_models.dart'; export 'apis/core/pairing/i_pairing_store.dart'; export 'apis/core/pairing/utils/pairing_models.dart'; export 'apis/core/store/store_models.dart'; +export 'apis/core/verify/models/verify_context.dart'; export 'apis/models/basic_models.dart'; export 'apis/utils/errors.dart'; export 'apis/utils/walletconnect_utils.dart'; @@ -32,15 +33,25 @@ export 'apis/sign_api/models/session_models.dart'; export 'apis/sign_api/models/json_rpc_models.dart'; export 'apis/sign_api/models/sign_client_models.dart'; export 'apis/sign_api/models/sign_client_events.dart'; +// Former Auth API +export 'apis/sign_api/models/auth/auth_client_models.dart'; +export 'apis/sign_api/models/auth/auth_client_events.dart'; +export 'apis/sign_api/models/auth/common_auth_models.dart'; +export 'apis/sign_api/models/auth/session_auth_events.dart'; +export 'apis/sign_api/models/auth/session_auth_models.dart'; +export 'apis/sign_api/utils/auth/auth_utils.dart'; +export 'apis/sign_api/utils/auth/address_utils.dart'; +export 'apis/sign_api/utils/auth/auth_signature.dart'; +export 'apis/sign_api/utils/auth/auth_api_validators.dart'; // Auth API -export 'apis/auth_api/models/auth_client_models.dart'; -export 'apis/auth_api/models/auth_client_events.dart'; -export 'apis/auth_api/models/json_rpc_models.dart'; -export 'apis/auth_api/utils/auth_utils.dart'; -export 'apis/auth_api/utils/address_utils.dart'; -export 'apis/auth_api/utils/auth_signature.dart'; -export 'apis/auth_api/utils/auth_api_validators.dart'; +// export 'apis/auth_api/models/auth_client_models.dart'; +// export 'apis/auth_api/models/auth_client_events.dart'; +// export 'apis/auth_api/models/json_rpc_models.dart'; +// export 'apis/auth_api/utils/auth_utils.dart'; +// export 'apis/auth_api/utils/address_utils.dart'; +// export 'apis/auth_api/utils/auth_signature.dart'; +// export 'apis/auth_api/utils/auth_api_validators.dart'; export 'apis/auth_api/i_auth_engine.dart'; export 'apis/auth_api/i_auth_client.dart'; export 'apis/auth_api/auth_client.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index e3f176a7..8a5b26a7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: walletconnect_flutter_v2 description: This repository contains oficial implementation of WalletConnect v2 protocols for Flutter applications. The communications protocol for web3. -version: 2.2.3 +version: 2.3.0-beta01 repository: https://github.com/WalletConnect/WalletConnectFlutterV2 environment: diff --git a/test/auth_api/auth_client_test.dart b/test/auth_api/auth_client_test.dart index 2333782d..9a795561 100644 --- a/test/auth_api/auth_client_test.dart +++ b/test/auth_api/auth_client_test.dart @@ -249,12 +249,29 @@ void runTests({ expect(args != null, true); // Create the message to be signed - String message = clientB.formatAuthMessage( - iss: TEST_ISSUER_EIP191, - cacaoPayload: CacaoRequestPayload.fromPayloadParams( - args!.payloadParams, - ), - ); + late String message; + if (clientB is Web3Wallet) { + message = (clientB as Web3Wallet).authEngine.formatAuthMessage( + iss: TEST_ISSUER_EIP191, + cacaoPayload: CacaoRequestPayload.fromPayloadParams( + args!.payloadParams, + ), + ); + } else if (clientB is Web3Wallet) { + message = (clientB as Web3App).authEngine.formatAuthMessage( + iss: TEST_ISSUER_EIP191, + cacaoPayload: CacaoRequestPayload.fromPayloadParams( + args!.payloadParams, + ), + ); + } else { + message = clientB.formatAuthMessage( + iss: TEST_ISSUER_EIP191, + cacaoPayload: CacaoRequestPayload.fromPayloadParams( + args!.payloadParams, + ), + ); + } String sig = EthSigUtil.signPersonalMessage( message: Uint8List.fromList(message.codeUnits), diff --git a/test/auth_api/signature_test.dart b/test/auth_api/signature_test.dart index 884a504d..112c9abd 100644 --- a/test/auth_api/signature_test.dart +++ b/test/auth_api/signature_test.dart @@ -5,6 +5,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; import '../shared/shared_test_values.dart'; +import 'utils/engine_constants.dart'; import 'utils/signature_constants.dart'; void main() { @@ -71,6 +72,40 @@ void main() { expect(bool2, false); }); + test('getAddressFromMessage', () { + final address = AuthSignature.getAddressFromMessage( + TEST_MESSAGE_EIP1271, + ); + expect(address, TEST_ADDRESS_EIP1271); + + final address2 = AuthSignature.getAddressFromMessage( + TEST_FORMATTED_MESSAGE, + ); + expect(address2, '0x06C6A22feB5f8CcEDA0db0D593e6F26A3611d5fa'); + + final address3 = AuthSignature.getAddressFromMessage( + TEST_MESSAGE_EIP1271_2, + ); + expect(address3, '0x59e2f66C0E96803206B6486cDb39029abAE834c0'); + }); + + test('getChainIdFromMessage', () { + final chainId = AuthSignature.getChainIdFromMessage( + TEST_MESSAGE_EIP1271, + ); + expect(chainId, '1'); + + final chainId2 = AuthSignature.getChainIdFromMessage( + TEST_FORMATTED_MESSAGE, + ); + expect(chainId2, '1'); + + final chainId3 = AuthSignature.getChainIdFromMessage( + TEST_MESSAGE_EIP1271_2, + ); + expect(chainId3, '465321'); + }); + // TODO: Fix this test, can't call http requests from within the test // test('isValidEip1271Signature', () async { // final cacaoSig = CacaoSignature( diff --git a/test/auth_api/utils/auth_client_test_wrapper.dart b/test/auth_api/utils/auth_client_test_wrapper.dart index b3d68eb6..d0aa1c3a 100644 --- a/test/auth_api/utils/auth_client_test_wrapper.dart +++ b/test/auth_api/utils/auth_client_test_wrapper.dart @@ -3,12 +3,13 @@ import 'package:walletconnect_flutter_v2/apis/auth_api/auth_client.dart'; import 'package:walletconnect_flutter_v2/apis/auth_api/auth_engine.dart'; import 'package:walletconnect_flutter_v2/apis/auth_api/i_auth_client.dart'; import 'package:walletconnect_flutter_v2/apis/auth_api/i_auth_engine.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_events.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_events.dart'; import 'package:walletconnect_flutter_v2/apis/core/core.dart'; import 'package:walletconnect_flutter_v2/apis/core/relay_client/websocket/http_client.dart'; import 'package:walletconnect_flutter_v2/apis/core/relay_client/websocket/i_http_client.dart'; import 'package:walletconnect_flutter_v2/apis/core/store/i_generic_store.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/models/auth_client_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/auth_client_models.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/models/auth/common_auth_models.dart'; import 'package:walletconnect_flutter_v2/apis/core/i_core.dart'; import 'package:walletconnect_flutter_v2/apis/models/basic_models.dart'; import 'package:walletconnect_flutter_v2/apis/core/pairing/utils/pairing_models.dart'; @@ -87,7 +88,7 @@ class AuthClientTestWrapper implements IAuthEngine { Future requestAuth({ required AuthRequestParams params, String? pairingTopic, - List>? methods = AuthEngine.defaultMethods, + List>? methods = AuthEngine.DEFAULT_METHODS, }) async { try { return client.request( diff --git a/test/auth_api/utils/signature_constants.dart b/test/auth_api/utils/signature_constants.dart index 699a1170..b15be0ad 100644 --- a/test/auth_api/utils/signature_constants.dart +++ b/test/auth_api/utils/signature_constants.dart @@ -15,6 +15,18 @@ Nonce: 1665443015700 Issued At: 2022-10-10T23:03:35.700Z Expiration Time: 2022-10-11T23:03:35.700Z'''; +const TEST_MESSAGE_EIP1271_2 = + '''walletconnect.com wants you to sign in with your Ethereum account: +0x59e2f66C0E96803206B6486cDb39029abAE834c0 + +Welcome to AppKit for Flutter. + +URI: https://walletconnect.com/login +Version: 1 +Chain ID: 465321 +Nonce: 1719392409504 +Issued At: 2024-06-26T11:00:41.043Z'''; + const TEST_SIG_EIP191 = '0x560a65deed4aaf332d9dbab82af897245c93139773b483072d5e59afdc5788d76e1dcbefaef36b11a52755bfd152241b4ea03d2cc08638818c5105cba9beb83d1c'; const TEST_PRIVATE_KEY_EIP191 = diff --git a/test/auth_api/validation_test.dart b/test/auth_api/validation_test.dart index 72b1bb0a..1f556964 100644 --- a/test/auth_api/validation_test.dart +++ b/test/auth_api/validation_test.dart @@ -1,5 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:walletconnect_flutter_v2/apis/auth_api/utils/auth_constants.dart'; +import 'package:walletconnect_flutter_v2/apis/sign_api/utils/auth/auth_constants.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; import 'utils/engine_constants.dart'; diff --git a/test/core_api/pairing_test.dart b/test/core_api/pairing_test.dart index d67990ca..a38c0c80 100644 --- a/test/core_api/pairing_test.dart +++ b/test/core_api/pairing_test.dart @@ -39,7 +39,7 @@ void main() { ]); expect( Uri.decodeFull(response.toString()), - 'wc:abc@2?relay-protocol=irn&symKey=xyz&methods=[wc_sessionPropose],[wc_authRequest,wc_authBatchRequest]', + 'wc:abc@2?relay-protocol=irn&symKey=xyz&methods=wc_sessionPropose,wc_authRequest,wc_authBatchRequest', ); URIParseResult parsed = WalletConnectUtils.parseUri(response); @@ -63,7 +63,7 @@ void main() { ); expect( Uri.decodeFull(response.toString()), - 'wc:abc@2?relay-protocol=irn&symKey=xyz&methods=[]', + 'wc:abc@2?relay-protocol=irn&symKey=xyz', ); parsed = WalletConnectUtils.parseUri(response); diff --git a/test/shared/shared_test_utils.mocks.dart b/test/shared/shared_test_utils.mocks.dart index f2f7f851..f0475a40 100644 --- a/test/shared/shared_test_utils.mocks.dart +++ b/test/shared/shared_test_utils.mocks.dart @@ -1337,6 +1337,24 @@ class MockCore extends _i1.Mock implements _i26.Core { ), ) as _i17.Logger); + @override + void addLogListener(_i17.LogCallback? callback) => super.noSuchMethod( + Invocation.method( + #addLogListener, + [callback], + ), + returnValueForMissingStub: null, + ); + + @override + bool removeLogListener(_i17.LogCallback? callback) => (super.noSuchMethod( + Invocation.method( + #removeLogListener, + [callback], + ), + returnValue: false, + ) as bool); + @override _i21.Future start() => (super.noSuchMethod( Invocation.method( diff --git a/test/sign_api/sign_engine_test.dart b/test/sign_api/sign_engine_test.dart index 99e3c707..d6b4b433 100644 --- a/test/sign_api/sign_engine_test.dart +++ b/test/sign_api/sign_engine_test.dart @@ -55,6 +55,46 @@ void main() { return SessionRequest.fromJson(value); }, ), + authKeys: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_AUTH_KEYS, + version: StoreVersions.VERSION_AUTH_KEYS, + fromJson: (dynamic value) { + return AuthPublicKey.fromJson(value); + }, + ), + pairingTopics: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_PAIRING_TOPICS, + version: StoreVersions.VERSION_PAIRING_TOPICS, + fromJson: (dynamic value) { + return value; + }, + ), + authRequests: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_AUTH_REQUESTS, + version: StoreVersions.VERSION_AUTH_REQUESTS, + fromJson: (dynamic value) { + return PendingAuthRequest.fromJson(value); + }, + ), + completeRequests: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_COMPLETE_REQUESTS, + version: StoreVersions.VERSION_COMPLETE_REQUESTS, + fromJson: (dynamic value) { + return StoredCacao.fromJson(value); + }, + ), + sessionAuthRequests: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_AUTH_REQUESTS, + version: StoreVersions.VERSION_AUTH_REQUESTS, + fromJson: (dynamic value) { + return PendingSessionAuthRequest.fromJson(value); + }, + ), ); await core.start(); await e.init(); @@ -96,6 +136,46 @@ void main() { return SessionRequest.fromJson(value); }, ), + authKeys: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_AUTH_KEYS, + version: StoreVersions.VERSION_AUTH_KEYS, + fromJson: (dynamic value) { + return AuthPublicKey.fromJson(value); + }, + ), + pairingTopics: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_PAIRING_TOPICS, + version: StoreVersions.VERSION_PAIRING_TOPICS, + fromJson: (dynamic value) { + return value; + }, + ), + authRequests: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_AUTH_REQUESTS, + version: StoreVersions.VERSION_AUTH_REQUESTS, + fromJson: (dynamic value) { + return PendingAuthRequest.fromJson(value); + }, + ), + completeRequests: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_COMPLETE_REQUESTS, + version: StoreVersions.VERSION_COMPLETE_REQUESTS, + fromJson: (dynamic value) { + return StoredCacao.fromJson(value); + }, + ), + sessionAuthRequests: GenericStore( + storage: core.storage, + context: StoreVersions.CONTEXT_AUTH_REQUESTS, + version: StoreVersions.VERSION_AUTH_REQUESTS, + fromJson: (dynamic value) { + return PendingSessionAuthRequest.fromJson(value); + }, + ), ); await core.start(); await e.init(); diff --git a/test/sign_api/utils/sign_client_test_wrapper.dart b/test/sign_api/utils/sign_client_test_wrapper.dart index 6b260a19..11f74f0c 100644 --- a/test/sign_api/utils/sign_client_test_wrapper.dart +++ b/test/sign_api/utils/sign_client_test_wrapper.dart @@ -429,4 +429,179 @@ class SignClientTestWrapper implements ISignEngine { await core.expirer.checkAndExpire(session.topic); } } + + @override + IGenericStore get authKeys => client.authKeys; + + @override + IGenericStore get authRequests => client.authRequests; + + @override + IGenericStore get completeRequests => client.completeRequests; + + @override + Future validateSignedCacao({ + required Cacao cacao, + required String projectId, + }) { + try { + return client.validateSignedCacao( + cacao: cacao, + projectId: projectId, + ); + } catch (e) { + rethrow; + } + } + + @override + String formatAuthMessage({ + required String iss, + required CacaoRequestPayload cacaoPayload, + }) { + try { + return client.formatAuthMessage( + iss: iss, + cacaoPayload: cacaoPayload, + ); + } catch (e) { + rethrow; + } + } + + @override + Map getCompletedRequestsForPairing({ + required String pairingTopic, + }) { + try { + return client.getCompletedRequestsForPairing( + pairingTopic: pairingTopic, + ); + } catch (e) { + rethrow; + } + } + + @override + Map getPendingAuthRequests() { + try { + return client.getPendingAuthRequests(); + } catch (e) { + rethrow; + } + } + + @override + Event get onAuthRequest => client.onAuthRequest; + + @override + Event get onAuthResponse => client.onAuthResponse; + + @override + Event get onSessionAuthResponse => + client.onSessionAuthResponse; + + @override + IGenericStore get pairingTopics => client.pairingTopics; + + @override + IGenericStore get sessionAuthRequests => + client.sessionAuthRequests; + + @override + Event get onSessionAuthRequest => + client.onSessionAuthRequest; + + @override + Future requestAuth({ + required AuthRequestParams params, + String? pairingTopic, + List>? methods, + }) async { + try { + return await client.requestAuth( + params: params, + pairingTopic: pairingTopic, + methods: methods, + ); + } catch (e) { + rethrow; + } + } + + // NEW ONE-CLICK AUTH METHOD FOR DAPPS + @override + Future authenticate({ + required SessionAuthRequestParams params, + String? pairingTopic, + List>? methods, + }) async { + try { + return await client.authenticate( + params: params, + pairingTopic: pairingTopic, + methods: methods, + ); + } catch (e) { + rethrow; + } + } + + @override + Future respondAuthRequest({ + required int id, + required String iss, + CacaoSignature? signature, + WalletConnectError? error, + }) async { + try { + return await client.respondAuthRequest( + id: id, + iss: iss, + signature: signature, + error: error, + ); + } catch (e) { + rethrow; + } + } + + @override + Future approveSessionAuthenticate({ + required int id, + List? auths, + }) async { + try { + return await client.approveSessionAuthenticate( + id: id, + auths: auths, + ); + } catch (e) { + rethrow; + } + } + + @override + Future rejectSessionAuthenticate({ + required int id, + required WalletConnectError reason, + }) async { + try { + return await client.rejectSessionAuthenticate( + id: id, + reason: reason, + ); + } catch (e) { + rethrow; + } + } + + @override + Map getPendingSessionAuthRequests() { + try { + return client.getPendingSessionAuthRequests(); + } catch (e) { + rethrow; + } + } } diff --git a/test/web3wallet/web3wallet_helpers.dart b/test/web3wallet/web3wallet_helpers.dart index 4977545e..0d1aee82 100644 --- a/test/web3wallet/web3wallet_helpers.dart +++ b/test/web3wallet/web3wallet_helpers.dart @@ -77,7 +77,7 @@ class Web3WalletHelpers { expect(b.getPendingAuthRequests().length, 1); // Create the message to be signed - String message = b.formatAuthMessage( + String message = b.authEngine.formatAuthMessage( iss: TEST_ISSUER_EIP191, cacaoPayload: CacaoRequestPayload.fromPayloadParams( args!.payloadParams,