From fb9f822aed7b0affb7163a4952cf498f03ec49d1 Mon Sep 17 00:00:00 2001 From: creeppak Date: Fri, 18 Oct 2024 19:34:17 +0100 Subject: [PATCH 01/16] Replaced WalletConnect with Reown --- ChainSafe.Gaming.sln | 2 +- ChainSafe.Gaming.sln.DotSettings | 3 +- .../Libraries/ChainSafe.Gaming.HyperPlay.dll | Bin 12288 -> 12800 bytes .../ChainSafe.Gaming.Lootboxes.Chainlink.dll | Bin 30208 -> 33280 bytes .../Libraries/Chainsafe.Gaming.Chainlink.dll | Bin 5632 -> 5632 bytes .../Libraries/ChainSafe.Gaming.Mud.dll | Bin 39424 -> 41984 bytes .../Editor/{WalletConnect.meta => Reown.meta} | 0 .../Editor/Reown/ReownConfigEditor.cs | 10 + .../ReownConfigEditor.cs.meta} | 0 .../Editor/Reown/ReownConfigEditorBase.cs | 58 ++++ .../ReownConfigEditorBase.cs.meta} | 0 .../Reown/ReownConnectionProviderEditor.cs | 10 + .../ReownConnectionProviderEditor.cs.meta} | 0 .../WalletConnectConfigEditor.cs | 70 ----- .../WalletConnectConfigSOEditor.cs | 9 - .../WalletConnectConnectionProviderEditor.cs | 10 - .../Editor/chainsafe.web3-unity.Editor.asmdef | 2 +- .../{Wallet Connect.meta => Reown.meta} | 0 .../Predefined Wallet Button.prefab | 0 .../Predefined Wallet Button.prefab.meta | 0 .../Reown Dialog.prefab} | 2 +- .../Reown Dialog.prefab.meta} | 0 .../dialog-hide.anim | 0 .../dialog-hide.anim.meta | 0 .../dialog-show.anim | 0 .../dialog-show.anim.meta | 0 .../Runtime/Prefabs/Web3Unity.prefab | 2 +- ...Provider.cs => ReownConnectionProvider.cs} | 78 +++--- .../ReownConnectionProvider.cs.meta | 13 + .../WalletConnectConnectionProvider.cs.meta | 11 - .../{WalletConnect.meta => Reown.meta} | 0 .../AotConfiguration.cs | 10 +- .../AotConfiguration.cs.meta | 0 .../{WalletConnect => Reown}/Dialog.meta | 0 .../Dialog/ConnectionDialogBase.cs | 7 +- .../Dialog/ConnectionDialogBase.cs.meta | 0 .../Dialog/ConnectionDialogChainSafe.cs | 3 +- .../Dialog/ConnectionDialogChainSafe.cs.meta | 0 .../Dialog/ConnectionHandlerBehaviour.cs | 4 +- .../Dialog/ConnectionHandlerBehaviour.cs.meta | 0 .../Dialog/ConnectionHandlerProviderAsset.cs | 11 + .../ConnectionHandlerProviderAsset.cs.meta} | 0 .../ConnectionHandlerProviderChainSafe.cs | 8 +- ...ConnectionHandlerProviderChainSafe.cs.meta | 0 .../Dialog/LocalWalletButton.cs | 32 +-- .../Dialog/LocalWalletButton.cs.meta | 0 .../Dialog/QrCodeBuilder.cs | 2 +- .../Dialog/QrCodeBuilder.cs.meta | 0 .../NativeWebSocketConnectionBuilder.cs | 12 +- .../NativeWebSocketConnectionBuilder.cs.meta | 0 .../ReownConfigAsset.cs} | 31 +- .../ReownConfigAsset.cs.meta} | 0 .../Scripts/Reown/ReownConfigExtensions.cs | 19 ++ .../ReownConfigExtensions.cs.meta} | 0 .../ReownWeb3.cs} | 17 +- .../ReownWeb3.cs.meta} | 0 .../WebSocketConnection.cs | 31 +- .../WebSocketConnection.cs.meta | 0 .../Dialog/ConnectionHandlerProviderSO.cs | 11 - .../WalletConnectConfigExtensions.cs | 20 -- .../Tests/Runtime/EvmCustomResponseTests.cs | 2 +- .../Tests/Runtime/SampleTestsBase.cs | 5 +- ...ctProviderConfig.cs => StubReownConfig.cs} | 2 +- ...Config.cs.meta => StubReownConfig.cs.meta} | 0 ...onnectProvider.cs => StubReownProvider.cs} | 8 +- ...ider.cs.meta => StubReownProvider.cs.meta} | 0 .../chainsafe.web3-unity.RuntimeTests.asmdef | 4 +- scripts/data/published_dependencies.txt | 20 +- .../InProcessTransactionExecutor.cs | 3 +- .../NetCoreHttpClient.cs | 87 +++--- .../ChainSafe.Gaming.Reown.csproj} | 5 +- .../Connection/ConnectionHandlerConfig.cs | 4 +- .../Connection/IConnectionHandler.cs | 2 +- .../Connection/IConnectionHandlerProvider.cs | 2 +- .../Delegates.cs | 2 +- .../IConnectionHelper.cs | 4 +- .../IReownConfig.cs} | 62 ++-- .../Methods/EthSendTransaction.cs | 10 +- .../Methods/EthSignMessage.cs | 8 +- .../Methods/EthSignTransaction.cs | 10 +- .../Methods/EthSignTypedData.cs | 9 +- .../Methods/WalletSwitchEthereumChain.cs | 8 +- .../Models/ChainModel.cs | 4 +- .../Models/ImageUrlsModel.cs | 4 +- .../Models/TransactionModel.cs | 4 +- .../Models/WalletLinkModel.cs | 2 +- .../Models/WalletModel.cs | 30 ++ .../RedirectionHandler.cs | 139 +++++++++ src/ChainSafe.Gaming.Reown/ReownExtensions.cs | 78 ++++++ src/ChainSafe.Gaming.Reown/ReownHttpClient.cs | 40 +++ .../ReownIntegrationException.cs | 21 ++ .../ReownLogLevel.cs} | 4 +- .../ReownLogWriter.cs} | 22 +- .../ReownProvider.cs} | 265 ++++++++---------- .../ReownSubCategory.cs} | 6 +- .../Storage/ReownStorageFactory.cs | 55 ++++ .../WalletLocationOption.cs | 2 +- .../WalletLocationOptionsExtensions.cs | 2 +- .../Wallets/IWalletRegistry.cs | 24 ++ .../Wallets/ReownWalletRegistry.cs | 98 +++++++ .../Wallets/WalletRegistryResponse.cs | 13 + .../ChainSafe.Gaming.Tests.csproj | 2 +- .../Core/StubHttpClient.cs | 16 +- .../WalletConnectDeepLinksTests.cs | 5 +- .../ChainSafe.Gaming.Unity.csproj | 2 +- src/ChainSafe.Gaming.Unity/UnityHttpClient.cs | 108 +++---- src/ChainSafe.Gaming.Unity/link.xml | 2 +- .../Models/WalletModel.cs | 52 ---- .../RedirectionHandler.cs | 180 ------------ .../Storage/DataStorage.cs | 116 -------- .../Storage/LocalData.cs | 18 -- .../WalletConnectException.cs | 21 -- .../WalletConnectExtensions.cs | 81 ------ .../Wallets/IWalletRegistry.cs | 26 -- .../Wallets/WalletRegistry.cs | 107 ------- .../Wallets/WalletRegistryResponse.cs | 12 - .../Web3/Core/Environment/Http/HttpHeader.cs | 9 + .../Web3/Core/Environment/IHttpClient.cs | 50 +++- .../Resources/ReownConnectionProvider.asset | 35 +++ ...eta => ReownConnectionProvider.asset.meta} | 4 +- .../WalletConnectConnectionProvider.asset | 44 --- src/UnitySampleProject/Assets/link.xml | 12 +- .../UnitySampleProject.sln.DotSettings | 3 +- 123 files changed, 1138 insertions(+), 1335 deletions(-) rename Packages/io.chainsafe.web3-unity/Editor/{WalletConnect.meta => Reown.meta} (100%) create mode 100644 Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditor.cs rename Packages/io.chainsafe.web3-unity/Editor/{WalletConnect/WalletConnectConfigSOEditor.cs.meta => Reown/ReownConfigEditor.cs.meta} (100%) create mode 100644 Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditorBase.cs rename Packages/io.chainsafe.web3-unity/Editor/{WalletConnect/WalletConnectConfigEditor.cs.meta => Reown/ReownConfigEditorBase.cs.meta} (100%) create mode 100644 Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConnectionProviderEditor.cs rename Packages/io.chainsafe.web3-unity/Editor/{WalletConnect/WalletConnectConnectionProviderEditor.cs.meta => Reown/ReownConnectionProviderEditor.cs.meta} (100%) delete mode 100644 Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConfigEditor.cs delete mode 100644 Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConfigSOEditor.cs delete mode 100644 Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConnectionProviderEditor.cs rename Packages/io.chainsafe.web3-unity/Runtime/Prefabs/{Wallet Connect.meta => Reown.meta} (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Prefabs/{Wallet Connect => Reown}/Predefined Wallet Button.prefab (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Prefabs/{Wallet Connect => Reown}/Predefined Wallet Button.prefab.meta (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Prefabs/{Wallet Connect/WalletConnect Dialog.prefab => Reown/Reown Dialog.prefab} (99%) rename Packages/io.chainsafe.web3-unity/Runtime/Prefabs/{Wallet Connect/WalletConnect Dialog.prefab.meta => Reown/Reown Dialog.prefab.meta} (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Prefabs/{Wallet Connect => Reown}/dialog-hide.anim (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Prefabs/{Wallet Connect => Reown}/dialog-hide.anim.meta (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Prefabs/{Wallet Connect => Reown}/dialog-show.anim (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Prefabs/{Wallet Connect => Reown}/dialog-show.anim.meta (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/{WalletConnectConnectionProvider.cs => ReownConnectionProvider.cs} (60%) create mode 100644 Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs.meta delete mode 100644 Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/WalletConnectConnectionProvider.cs.meta rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect.meta => Reown.meta} (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/AotConfiguration.cs (80%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/AotConfiguration.cs.meta (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/Dialog.meta (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/Dialog/ConnectionDialogBase.cs (95%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/Dialog/ConnectionDialogBase.cs.meta (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/Dialog/ConnectionDialogChainSafe.cs (97%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/Dialog/ConnectionDialogChainSafe.cs.meta (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/Dialog/ConnectionHandlerBehaviour.cs (74%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/Dialog/ConnectionHandlerBehaviour.cs.meta (100%) create mode 100644 Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerProviderAsset.cs rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect/Dialog/ConnectionHandlerProviderSO.cs.meta => Reown/Dialog/ConnectionHandlerProviderAsset.cs.meta} (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/Dialog/ConnectionHandlerProviderChainSafe.cs (75%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/Dialog/ConnectionHandlerProviderChainSafe.cs.meta (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/Dialog/LocalWalletButton.cs (70%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/Dialog/LocalWalletButton.cs.meta (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/Dialog/QrCodeBuilder.cs (95%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/Dialog/QrCodeBuilder.cs.meta (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/NativeWebSocketConnectionBuilder.cs (74%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/NativeWebSocketConnectionBuilder.cs.meta (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect/WalletConnectConfigSO.cs => Reown/ReownConfigAsset.cs} (70%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect/WalletConnectConfigSO.cs.meta => Reown/ReownConfigAsset.cs.meta} (100%) create mode 100644 Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect/WalletConnectConfigExtensions.cs.meta => Reown/ReownConfigExtensions.cs.meta} (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect/WalletConnectWeb3.cs => Reown/ReownWeb3.cs} (60%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect/WalletConnectWeb3.cs.meta => Reown/ReownWeb3.cs.meta} (100%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/WebSocketConnection.cs (90%) rename Packages/io.chainsafe.web3-unity/Runtime/Scripts/{WalletConnect => Reown}/WebSocketConnection.cs.meta (100%) delete mode 100644 Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerProviderSO.cs delete mode 100644 Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigExtensions.cs rename Packages/io.chainsafe.web3-unity/Tests/Runtime/{StubWalletConnectProviderConfig.cs => StubReownConfig.cs} (89%) rename Packages/io.chainsafe.web3-unity/Tests/Runtime/{StubWalletConnectProviderConfig.cs.meta => StubReownConfig.cs.meta} (100%) rename Packages/io.chainsafe.web3-unity/Tests/Runtime/{StubWalletConnectProvider.cs => StubReownProvider.cs} (83%) rename Packages/io.chainsafe.web3-unity/Tests/Runtime/{StubWalletConnectProvider.cs.meta => StubReownProvider.cs.meta} (100%) rename src/{ChainSafe.Gaming.WalletConnect/ChainSafe.Gaming.WalletConnect.csproj => ChainSafe.Gaming.Reown/ChainSafe.Gaming.Reown.csproj} (74%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/Connection/ConnectionHandlerConfig.cs (94%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/Connection/IConnectionHandler.cs (87%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/Connection/IConnectionHandlerProvider.cs (81%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/Delegates.cs (82%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/IConnectionHelper.cs (74%) rename src/{ChainSafe.Gaming.WalletConnect/IWalletConnectConfig.cs => ChainSafe.Gaming.Reown/IReownConfig.cs} (64%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/Methods/EthSendTransaction.cs (84%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/Methods/EthSignMessage.cs (82%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/Methods/EthSignTransaction.cs (77%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/Methods/EthSignTypedData.cs (80%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/Methods/WalletSwitchEthereumChain.cs (82%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/Models/ChainModel.cs (92%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/Models/ImageUrlsModel.cs (81%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/Models/TransactionModel.cs (87%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/Models/WalletLinkModel.cs (94%) create mode 100644 src/ChainSafe.Gaming.Reown/Models/WalletModel.cs create mode 100644 src/ChainSafe.Gaming.Reown/RedirectionHandler.cs create mode 100644 src/ChainSafe.Gaming.Reown/ReownExtensions.cs create mode 100644 src/ChainSafe.Gaming.Reown/ReownHttpClient.cs create mode 100644 src/ChainSafe.Gaming.Reown/ReownIntegrationException.cs rename src/{ChainSafe.Gaming.WalletConnect/WalletConnectLogLevel.cs => ChainSafe.Gaming.Reown/ReownLogLevel.cs} (50%) rename src/{ChainSafe.Gaming.WalletConnect/WCLogWriter.cs => ChainSafe.Gaming.Reown/ReownLogWriter.cs} (65%) rename src/{ChainSafe.Gaming.WalletConnect/WalletConnectProvider.cs => ChainSafe.Gaming.Reown/ReownProvider.cs} (60%) rename src/{ChainSafe.Gaming.WalletConnect/WalletConnectSubCategory.cs => ChainSafe.Gaming.Reown/ReownSubCategory.cs} (54%) create mode 100644 src/ChainSafe.Gaming.Reown/Storage/ReownStorageFactory.cs rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/WalletLocationOption.cs (81%) rename src/{ChainSafe.Gaming.WalletConnect => ChainSafe.Gaming.Reown}/WalletLocationOptionsExtensions.cs (96%) create mode 100644 src/ChainSafe.Gaming.Reown/Wallets/IWalletRegistry.cs create mode 100644 src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs create mode 100644 src/ChainSafe.Gaming.Reown/Wallets/WalletRegistryResponse.cs delete mode 100644 src/ChainSafe.Gaming.WalletConnect/Models/WalletModel.cs delete mode 100644 src/ChainSafe.Gaming.WalletConnect/RedirectionHandler.cs delete mode 100644 src/ChainSafe.Gaming.WalletConnect/Storage/DataStorage.cs delete mode 100644 src/ChainSafe.Gaming.WalletConnect/Storage/LocalData.cs delete mode 100644 src/ChainSafe.Gaming.WalletConnect/WalletConnectException.cs delete mode 100644 src/ChainSafe.Gaming.WalletConnect/WalletConnectExtensions.cs delete mode 100644 src/ChainSafe.Gaming.WalletConnect/Wallets/IWalletRegistry.cs delete mode 100644 src/ChainSafe.Gaming.WalletConnect/Wallets/WalletRegistry.cs delete mode 100644 src/ChainSafe.Gaming.WalletConnect/Wallets/WalletRegistryResponse.cs create mode 100644 src/ChainSafe.Gaming/Web3/Core/Environment/Http/HttpHeader.cs create mode 100644 src/UnitySampleProject/Assets/Resources/ReownConnectionProvider.asset rename src/UnitySampleProject/Assets/Resources/{WalletConnectConnectionProvider.asset.meta => ReownConnectionProvider.asset.meta} (64%) delete mode 100644 src/UnitySampleProject/Assets/Resources/WalletConnectConnectionProvider.asset diff --git a/ChainSafe.Gaming.sln b/ChainSafe.Gaming.sln index dcbc2726a..58c9d95e1 100644 --- a/ChainSafe.Gaming.sln +++ b/ChainSafe.Gaming.sln @@ -21,7 +21,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChainSafe.Gaming.Unity.ThirdParty", "src\ChainSafe.Gaming.Unity.ThirdParty\ChainSafe.Gaming.Unity.ThirdParty.csproj", "{9EC71CB4-9401-4E02-AC63-FC13B3D1AA53}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChainSafe.Gaming.WalletConnect", "src\ChainSafe.Gaming.WalletConnect\ChainSafe.Gaming.WalletConnect.csproj", "{99E7A645-CAC5-441B-848D-1253405D6400}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChainSafe.Gaming.Reown", "src\ChainSafe.Gaming.Reown\ChainSafe.Gaming.Reown.csproj", "{99E7A645-CAC5-441B-848D-1253405D6400}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChainSafe.Gaming.InProcessSigner", "src\ChainSafe.Gaming.InProcessSigner\ChainSafe.Gaming.InProcessSigner.csproj", "{3C01FD36-4D44-4886-A971-4786D99CBFCC}" EndProject diff --git a/ChainSafe.Gaming.sln.DotSettings b/ChainSafe.Gaming.sln.DotSettings index f1d07a668..52ba3def7 100644 --- a/ChainSafe.Gaming.sln.DotSettings +++ b/ChainSafe.Gaming.sln.DotSettings @@ -1,3 +1,4 @@  True - True \ No newline at end of file + True + True \ No newline at end of file diff --git a/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Libraries/ChainSafe.Gaming.HyperPlay.dll b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Libraries/ChainSafe.Gaming.HyperPlay.dll index 17ff05bd69dee101aea61f27b9aad8576f6fd9ab..73925ca3357f1ff79ae1c459496fa630f48fb3e2 100644 GIT binary patch literal 12800 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 delta 5328 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 diff --git a/Packages/io.chainsafe.web3-unity.lootboxes/Chainlink/Runtime/Libraries/ChainSafe.Gaming.Lootboxes.Chainlink.dll b/Packages/io.chainsafe.web3-unity.lootboxes/Chainlink/Runtime/Libraries/ChainSafe.Gaming.Lootboxes.Chainlink.dll index 08b4cbed004b22a4d03ac67c3d199b873a88d3d3..46ec98cc4de312cc4ce9449c9d684419b810f0a1 100644 GIT binary patch literal 33280 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 literal 30208 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 E3kLkbC zjC?*9pD$rg;x{{4m@`(M*<}F^bCXcTkFj$0j8C%ht*aGKpF@NKGLbL>cd`M-U**)a zlnT3Z0bRw(zg93T6jEqsk>=7U12QUVQ-00=Qc$9$LR1TAm8?8Eg+CN(+Se&!9s_zb zz!EKUdo0o$>W->SWYI1n=8kq`5T{KrAMEfPAX`X!iE5hn4-EO#WTjuQPQx;<(=_l| z&0D_(yU;4^feE9qq1C9Q&1`usFfbfVt6Eaww5lUDo>ofiys8!v7aB+{ren=i?>c{; zF*#lhEA;3jEI=1wF=RqBrU@&tK{d#$}?)OGr%iu8*k zvd>{14)w;){7a(|zsO%?Zz~ape0^f-Q^b%Qi^ja6fHxAbTO}o-n78EU?WszAA5xX5 z-^$ab{`F5Qb8|QDdLA#Oeg|p*4-{^Un~KNj8njCNBr!CJ}SfP`s2UlMTQ}TB4|pe2R5ZmXl5hCg0^-1mS6IGQaRE70CJnj10}+ diff --git a/Packages/io.chainsafe.web3-unity.mud/Runtime/Libraries/ChainSafe.Gaming.Mud.dll b/Packages/io.chainsafe.web3-unity.mud/Runtime/Libraries/ChainSafe.Gaming.Mud.dll index 02db90cff9352c2b10d18ec49238f38a16a1bd07..0aeb986957424bb6a8392474eca05180887969a0 100644 GIT binary patch literal 41984 zcmeIbdwf*Y)i=J*IWuRjnIw}N2}ziU*pWaafLs(YAqf)YCIQ73g&{M*NXW#Q2?$|q zQoK>GsI}e;URrI%YSqX4Q>bXQ)q1zyg?edyv`=r3ZSB+I@4MDMXJ&H2`n-Mq_kf;5C{4=$o2!F6RfGuVFh(TKq3k3p->V^RK}OD&RF z_$-FrMU3nr`VBi`=x0BXAG}o$6D=K@_eFGw$eow(20bs2Zb-+@PJ_PvdI01}TP?dm z$tQ$r8PmLk3D6<7e9$#xNQ-JI2@Qedq_r z_``G~VZR^f??GA71IdA7O&+)2Q5Jv{$yL_G!hjsO&OS&4%rMm zgJvd1ft`U57_S2E2slzJmijP&!W+SEP%sL@KLFVkwxF?PDQhX#QyA!(ix=;-%8@eo7t>zojq$ z%`ND5X;NYad?4}0I$<}L;kFtHI9Yj8^*zUz?aU@`}nZeNKp@xaT zA$KC;V z->oRaAG=O85o3y*g%O9AX3zl+hknpJ5js-m0wmI`jaer#tDjjLnFSvhbR=}aN5y(y zB?@{?pUViN4sRNE>VADIbKR~m`ljA%x~9B49`c7OH}`*34#R(h`k4F0_2tUt*Y`!` z5DI7?yq#YkI)>ZFT-1k98{WR5<)pqtmBUEq9!Q)D*TPBcBXkUpR~~EJD@wpfY=ML| zcPbf#&QO`Ye3=^P87>pXxHS`5LFpG=7Iv6eocca%FvBOHXa-@*F%6t!8r|zK9ho*x zoEbEVBODt7L^ul~!ZFV3tu`!zUW7t%>UPnmXPO{_#Ua<&Fa{wndOp_#gX+hbx+6Rv zvKfpfG?|0bJZRnlPU=M1l0Xn*S0MiR8g#=kSZfj};k6e|Ua9MS^>eIB!Z)ETFWdED z7~?$$gTpayV#N{X91G;2c`IvPjEr&poD)Vc*N4$_&_FKUL}12OLs1YgFjy5s5HLbE zLl7|PY=$6U9A+~F;d!(kwxhohSJlWHH?i&rT@NpSEjn8XxQwkvPnhGp85TiMa7>_1 zjti7SucBNTm-{NqB2wxh%WO+_B4jcCic`Ch??ul+ze5k73<@s23rT7T8qT%U`+{0{ zDTwj2#~e)k5Lx5&3+$=@=41v!}TjzGc-ER$-1g>Ag2L+{&bEawedW4RB!VvCg3 z`&g5~ZZh+iTj?(ZjlJGVwfVAnORu!?i}fNpv+JZo;sBElkNaVI^OoeS-hxBQ&d$?o z$o>Y4-H3YgmTKsA5<Rqd`+F*MV-7D)J*#w{z&g=b*13rj zBeRi{vP_zjt(*mAFr!}f(p-KVmwzd*{CO;@XD;Bx$ehnfS>{|$wsIEAqsmXM#!PC64-X za#bwH*7?%-K}U(R*g5gV3UH}d?gb{JDmlfl5bJJ5%?(&Sc@JKk`jyzNXTA$*#1kh8 zEa1G-zlTJv^k`xIIkzE8HbA!mIcOf>+-?{&uAg(lXoa=#a=VU#e#A|2>U~T9_aFoP zoFq^=>;Hf?z#-l+EKy|-v$qPPv3AeUz=jUJZwgA`a6_-x>(3_Kt{=@>Fj1T1Ci;)i z`=){HD+0(&2e9ZuK@~&f%ORgY|CtH&h}R#~!{{LI#1_3A+aIn$cV~{_q(E1l)WlgDSO{r2OCKWrv7yw>+XY3bAxxyGS*z9U>37?~K>bpc!3=3q6IP zGc)rbp!X?w0`LqQj;?AIK66IAVKC|KPgzM`NxiQP(&`pMHI}tXyDy!2Gpg15L>;0C zHD)y{6(W|qF-n{be{z6rMrs8ZHw6JUpA!UF3(_D57y=vt_6@OyGZA2%94xD_158Rn zSs#>TPUP}>A19f1#!H1Y<6DQcFpQv6_iJKSi6iJxcD3mh2w%}&>=1{b;InI&M?NAvS7QOKKmA7>{9P-y|WkF5(&Kydlp6KZ+R z&*!G1qWYYu%p*TW{YOdtOCf8mA1CU4%R%XVrwBY1P)Bvi9448?_pcZk3z`$nX6W(n2!QO%xSqYiGBLVWn!&iHM%Dg;e=<86+nUprk_Uf-XeZ|f&ram~Ydc3;BNa8$<+?`Ml`c(B`eU1d{}|%Vy#lkT-{~1vC@a0rJC*`ds!6 z*=)(+Cm!`am);jeo#7ji>35&g30!tnY{)@#FKn`ol{hDNtW;1>o}8W81#=_rf!9D# z?^_F~ZU>Hq4mK)p=pas9be%y20}&_dAnP^ToM;&4H<|1Z0%)Nej8T2%jCX*}h-m=7 zWzY+;8GmD0y{}8ETMwAQKtRokaVGF|Er$ulr^QX(ghpmCG?NSE40)A7}dXt(@dVAD4tKEBeHyda#uJ2TeqqnYtCVR$Ou#0(M-v zYR%33tg2otkrh@7%gRD`T94jd5m;*@Dhij=^{v(HQ3;jltM3Q&^CPc?Ro%E;K<*9oPzOsI<7kSLCsm&VK4LkIp{1*DHzWQ z_-N36qP>1S`Y{Q1-voff51@XeVZsG5Oj4X+A?rbkVWNj;!b|jaNTPu=F-$ng8zx-R z9wxjy=X|)U(`%tmOGuRR%YY74!y4eH_=8-J1 zmJ51klv#dMiEW3p{fDUW2ztwM2PX1EnKpo!A$xrmd&D7FpRsJB>q@z2bNt+%5d)d0 z#&6)d7*_yp8->*V@LqBrc#CjV0UzF%CY=NYP=mfq!$8c<=yy@-K{0JCNiuWS5?m<{JdV32e=3y7u z-sa?B*;so^BPF5iJ}Ap<=JI+UCz-Pu7h8q|+K}!Q1)fYFi`!Lm_hPL=pe>fFITPK> zNnW6FNsPj)P&1k}3W4UF(VufcpNh4S{9w7{ew4J(f6Ji{08Ko|ULRIB20BtPhV!hIy?okw%%V>$HS zfhK;;V5ATg%Mqf3Oy>|)rtcI>IFmzkB-@9DXwF;N5EYgR(UDuyj|zr`sF)_*I5s9HUM;4tdigMsX+lrDF5~$mxB!Z*(N~h`$Bh3-pjN z%Bm5g-{b^=f+4A5bhZS_V-hHwi5TT1FGi)L9i!X1yxzx2=0e8%*p@GjQBmN@Ah>c> zbBrD@RnL*CITJC;NnVU{$-yzI*Y_eorA`%~BRRox%};W!d7PtgAA^xXQ4B;V4ziF# zQCYYX{i^qICWqokCJqb5oKv!)C@d9Qf;ZY0hL&FN#RmeM%sY=*3VH7z0>&R%ecbNaFOwY_RntgMIkQC4I`{=1|0-{ zhV<39VXD`4#ulI41xqNxKm5GsRCkQ6cuG4sHl8 zPCd8+xay1R`(`-d?HM~5jOKj3?`8<~)dMJW#M@_)ISMj2Ct9Irq}!C8tihGJg%kL0 z7gE_Ew25CGs7vqTOiaF<p!${^>XAHO%lf!&bCY_E`{5vG1 z>*;HD{QO8)PgFZl?WGf{^C+thIikm^ zRj*a#S;Xh(*w+xzv22qrk4=rlY0!dqpB$DkK9_4`V_eD@`(5lg9VcRwfT+aBk89)9 zhDi-mCQWI?pys!(y8s=NiN>CT7f6u)wGMbkIvMX?n_`J|a6%9KICfbFy>^QF{=(Q3 zmbGKF(r-YQmLhLXS7J2_;{#Fc)G`0&^VEX)n>K}Cw&U8@9ok5nWKqb-+V(eDSPGlb#cJOpx&f zMNf??p%@C8^xsAImzY!+Oq7}Qtzw2t1SSOjPT-|Q%&#iqvI~QEl$z9A!|>>$J4(Iu zN8fmFfW{kReJ1&g6;%OpIv77FGH(?=HOizEY7EkSWeXi96_?*p8l-`;fHz2691HRM z|LTe-YfU;(!jc<}HZw>c*PK!lq)!CyEoXcoWP(%@x~$ry`=l);4%YL#F_%@BQ&Yu0 z*!FyYt-4L@d4ts{Da0FrByUBbROD%WjW`T7LThkDdcD~P1++G z{-HA-E?}L%s<;RBu7hnRRTnV6r;zzOY8h6QGCaC;1vH$2)|vG63f9?D@gQ3L(~9R{ z=eUaVYfQSkbXiG&9 zr2i5-pDVeeG(cq)tp90g#W!8cfY%g^FGsYLag9F?v5X-y$A||$5dK@z-k%75JA7!; zylRG3f(HQ)qxGdLQ1*A_Yf6rwlp~5Bca(9f??9^&X^`>K(S_Xh4uQW9FkS+@oF-N` zkFFwrU?m4Logz@iDi&pTQCrnaL_FdeR0Ms*6pt?CA+BcvchD}p%l&vT;Nx-Q6sp6k zC==2}v=4d9kmnKVwX%ROf>M4OfR=&Loaev-&XQyNibAX+Z%Y+Zh!fHIz2KXpc=VKu z#nF=hPRQY3-vQUQ{{BLP;Wb#s-^`( z-BrodSXx0E8hlOR6_p>+5wuFEyDTayl6O~at6GM{2@=WXz}`40eo;{3pp(dZo4N639d z;0f;E0-xu)5wNlH4}i<0u7?C(@A(v*`#ic=qjAt_YkREH^r{-`Xm9mn;48}&+*Tey z?q){`;FO9{fNutBpkZOjVSq2z9RaA-aJ!DJtq1;@>nOlx&lImoe=3{-_^a|`0T-6E z0*UtuKTq4k!?gVv+E(h1OTD+{NwPP}OP>N9UBxmV>%()O&E{UO zb6ox2VED2ABIN&K43~f7e<=U%mzIAYl7s!pHt*B_6Yx>vPk=``{sDNkz~>#z`B*ox z-?9B%23+<2rULGL)#?-V8lOflNV}RGjDM^jmRE}Xnez`v-2`7by`VKhM%lw~aR`H+ z&L4HgC|(Co%Tn#om&{TNL46}jai01-S@2qLX&&{TzSDA)v$F1tLDV`>SBRDmJzP$w z>y%FSe+1K@Zc&ujV$hvJZ39(=)%Afa)r0kPpHNrRY~L2N=D#ee5tN%s>j)ptdjo6c zDvN6NZS(nPgHYVsZ~FXnp`vJ>_X_NfUb7@;xNh_nlH)L?<(`5gwIHMTJXsK^Ia$MI zTs}`0{JA8by4sgd9qC`{%Smn@bsMM|qLXXC3)D4=qCfc`^^Kx^S?VXgN_yX-9;tfT zH=2sZa)sy9BUQfuHA$!e`nzAl+J34~A9_BmK3S`#sG_ttO1=u}T#NcfXn>U{TMHAPslH(7b?r784vE6*$~!is&NmB&7tN|#%CKkyad8Qry39((X;+GXXn z_|u@iZ{@K+r_qnByz5524C)a@N%TyoeOc-q-*o!DqUdn+^s#j8IBws7NY0`*p{{nP zOF!|=qWMCd@BVeD4fjP$m8APGp+6w+bSv)%6@T^}M=>k!p^Ex2kfe&kyRq6y;v)s_@Styqt&6`R+}iS}1B!H-l=W8!YNRP;Kc-nGQP5ML2i)Z3vm{EO+ALY?pKM30?J?^@JZ=&_UOHx|`jaI&_9es58i z78Kzd#GhHzFRSAI4njELbH4k%s!jf-$23n{#X5HW+^V$O*@q>sPBD$f*uq~jrX(YDMiV6KZ|~2 zQ9Rz0RElFk9>qM~d#TB$Fy1#&mqqb--$K_|6p#0FXrD##ctO&9v^M`b~MX^8crl%~5 z{dteP1d5*aus?r9Ga9&(4>k7Zy>zifu|Myp=Pio;c|RSFLt&yFw5K9j@BrN|)Bydw z=7NHU>F*ZxiTB$DkJ7A3EIB|S^QMBwh`-px)CT8m1^-TuTGVUaI}3hHe;4XXnxx-b zu!oj6vgC&zZtdf=N~rVQCzd}3Dy}HB9lIe)3w1Re7ur{_k6yN@6`-D=LY$eYsMF|4 z8YR>LZF7jJt|^>%K>Jm}Y*5`osd@LOv_&ZPu7>-oZ9;9so#hJ!Kc$QE@}8orti0*C zHGYa7vZ$ZyOuaKm^4C`0e_*%t6q!?VmOVv9LMh9hqC2PMEPIOX5=z*r{yoM$Ru zKS$GqQd*v;CM%C6pQp3=7}DyM=V^;js#jj1^Mz97UZBf_+D1P8g@PC8+j)5}(oQRH zhxW&U7pZ}dF0GyFOEi5D)g%=9R{LAQOLRtF-pjO3DAg-3(}d%5mc2|3LMdBbp&3>l zx8W7~Yg11075bY{O7c~5G^;$8e3dS5$w|ISR|usfe@Qo3c`W%$nmRWp`AeE6l#+an znyfsQe2w2ZApw;oNPg%fNXA&ggL-!DVkKu%S*YkGm{^(`tn8Eh^IK zm1@>`uuySWPck%8F1L9kK5FrDslj@b=A2HIyS22a$YIr`{BtO{RXo668r&josqI@; zR(bmqXU+qv?T6Bw&mSW_rJ&NY(#3ihH*hw=b>%pNdzSU6&tQ9${_l$Ce=usORr8=< z^#b=M<7~M`PCNktM`~1-Fw}{^h>p`*mdB*V@IVj~AR7yq5r_%5L zf9QQ>iHgSj9?8e~2M2VV$k<-eapp1<&zIST$k%X=lPi_)tNeb<;UoEK;1?OB)yn2g5;NuKUkxWmLm~IRPC8~7 zgI*KAsajNwDfmaxpvJhu-xfRngc)G?N294CuOt=Z-(A4GB(bVuFF*Io;9Mhq*-GqJ zwexskjtfr_3Mhl;43lvBpTTp3b@;`AD1MD#6@}<*Tv2?xc{k2=cjMcz_6Nt*&%S3$lRlC$Ij>>$h6`7B_htuLwtLSNMF?Kpo<1?`pb3A6wSeyeKCQo9b0px$B}WN9 zRrBCJ_}Cn9{WV2c7R#i?!2(JM^ja1on=f>3^uZ z1G$fd?$b5n?a)*DEO_Q3aQw9&>a7;uS@{~W2wbCB9t^%2p$znqGCx@Ea?(X zmvFj-)2z)e*lSdxb|*#j9fhA55uL4y=#8a+HPRxV7WuTuZ?$UKSleh^EV&m;?!}T@ zY;X_WL8+?C9Utkh1a5I$Wy$+%f8n@6@LTDkib>8psn*?wZ@9YLbAaDeyBK(&{Hx9h zbbIY8=YV#8?J~MgBp(&Y?HWryDw5kZmfWu0j)@=QDI>?eCn8#xbR2zAXCR68%xJkgCJXtR`uQ%I`Tl_nL zyQ{7@KSHG44qOBOWaGD$d(Ap{UZXhRAIwkSpH;LL}zbAboNH2{yX!p#%7}fr!Jd~GYhVC)#+E7H@GVG?!w#j0pSk_ zzZ9*Q&@-Pb7L51 z`8s`-Io7>HBzK794w2j;l6CqPGvcn(A2%;@A1?Jykb2YNy$MqLRB20Ee3%v=UTZuM z`W;GL8~QWgZ6qzTeu_rn8I(P^U7T%T@v(hZ(-bHy-f#!Up`xO;?}+Pl(R~98FsQ$I`Wc^>j1f z6nY)-So#xS3mpVJiF_#4A^fiaP7!S_)CoN;I8pBkv^3NvGhQBGXCh z>Bf?nNS-N@DZ#gi%r=qP2AO>&=L!E7tWW-;+XR1H@FxU+8u0kS_k{DFa6SxkY4d5t-Wr-XSu3#HzibZLdf^E|QOn%o76li_Ck% ze@{3c2*giMLcgI)+jVZcQ(#E=V}(CfIO7Di2&YBxHh~eHEsW^WQpxQUeoWwikR2N zgDn{=GUG(1S#p~tw^?#qB)3g+Ba$1D+=%3MN^Ym*4j4aR{|nqJGJ8elagjM7oCCsn zPdM*MDb2wx(j07$=3sm31g{f(EFK8?i^k&Jq88s+2m8NSa+@W$Met66+XUVs@K#43 zeOz)YG&@Tl7tVVE4JX$!R$!CB7J;h-b_(nlxJ}?rfwu_U<79vC5&Ut1`-QV#@b?6g z$ueY0TP(;eG6WAvZb!)ZxYz-s-jgTErPES7!jF%!3PB2C2+4u z9uP=wX}eo$aZ9`jCnTIYH|uN?PLps}3BF43e!=?%ACR&;g|kyQyQJ&^;cJ*{TYPmM z(dOAk-zaSIaI2ez6A?H7xV~hkhb`G9@_Pi|FOa;<4+*Tpn`VNZ3Tq9;8DQ`1m7jFF2FL)0{a8p-kk#X2;3|D{emA* zl7*tPkVj2xA&;6>h1)1tw5m`dN^~B_X>VMU~@6^`-`P^ zfxC*U=<5oc-Wz5AGKZm29KmmD~dYL#4MMw;6Bw!6$gPuEjSX_%4Ba1?~g% z7ab7%eZl+7xYV99mftTpl{2SF;3|Rr0(T1BBakXsepQ8(6&M=DoIL{f;Z4RCpQBRR zSjjR`!TSY2SMXZ}?ibGcf;*~MzNw1k&lP;9;I|6CPvH9kX*A0?Mzj3k0$T;H5`I+h zJ%Wd-#ZG}c1#Y67>GxEkjni7RdD;SPnYKzhTRT^~Q+rnXjaH#o>n-}p`q%Ug`Zc=S zC@{*63yo`y-Nw(1*NhL1gND~J#?k6H)zRrlIQkqHIKJihi=)E1#(A6bWoL=G#2heR zF#BBJcYW%b?oPVjcGr8_J!g4}aXv5#Cs1SX<{#mWr=@_82t2{P82GWZX~551J%ey3 zO5wMY$wdbFQMv$k=>hDoitvtLF?LA^CY%XW;eLHI&IGD)7Ep_O{xQ(eR8k%wylp!g zP~k_^gn)ZX8UE16@B}~0+%)QNzy`_vVwtl`CqnYSLz4j?tC$9OoasESPr~h;KK4VfGhZ$+9>dGW7Y-S)Pz>!y+1(yWpe|+ z**pjBFQOJe9X@e_(~7hRyK(lA2R_o^85j6zTt)cRH#hj@$Z^v~@!2Lo9lrqT1LtD+ zvxqJM)X^^m;9N=pa4rMX;m<(&ry%%BG)_^Yznk!8$YC@``wC8xP62)dEe9T^RoYR2 ztF=bJs5S*~jdnEPI&C`Onc7UiF6~%&Cyi3$X(LM2(-z?Mv=#Uyx*YfzR#{#i6{hC^=NytvHDtDtA$6I8VLNjAQWZ=Mv9p)x+gh;Jk3Cz9>#t34SR=bQR;w ztQhfCj2*;R&M*4|<3u(rUf(MQ7(Olzt z{IbI>wBFcF+dywK?xpV;578sWMf4J`1IFX@M_dla(^Tnrj%GQo$Mq7O?ASr4)^+H|v0o8|b5cD6Yk^o_9T1nmgd zN!mPIr{Y?JtJn1@eG}I+xL(8Mb$?3bxaQ+p?%tt2;J$@kao-3VZqsT!yHWN8tqJL= zuH7iV8|8V9H!wHJXV#+bj&vd!>*(ok#xMXHIk0Zj;>rec@oWFSLwj^MAGpqgZAQE$4Z*A{{kmnII8cXDqmxq0^5l`EGfmP9rw zTk)2};C^b|+#T7VI;w4BtUKMhbdhveqw26pD}j6oOIVCM7>);~YKA`)Ikd~*aR^yn zfPH90+gZJluGChQ6FWPeO5=M-%H-KcLl4bLacs>`tX-T;bjDICWOu}p8xd)F`RJ0C zME9EbT8kIA(xmiL8>>wX7RMK!BI(%L%@%j|45@46KH(;&B!6}H>WmtcXH7MvGlq` zbWU%)D;i6Rd}@93rbrx}56Z3z?f^9(O+wPrari8@9e<4lZiJ!MSX7~D`H{!rWNPnD zPnoRT33qY3LB+axL`IdMxCqRlUIR;vlK4=*0E>MwndbI(cdnY8-!xDXxJ!F`;G)Td zPPPI$o&-57X@{g#H$~~2q7+S`mUWSMcSmGRtlA&_Z}7mW=goP-MF> zy9I9I{8{bY@pL@W72gtLBO9mEtTi&$1~m;_?nfj`V@W7S0EqO_dF=zvGDuV`v$km* zv)xfNq`fbXa)#Xj**SuT^`M*>IJthom+~-ttjbhSusApi6472v zCV5S7p3_cN_o}IOgdt2L&cyZrSGoDIF*qk{T9&<_H!4xv(YY?RAwp>mbPHb_ORwZ< zo&?FwCPL>{fx#x{@mnHYT~RKNnVmW|r_!+v4VZAcVlrG(4JX99W63zOV(DScl_8VM z$!S#?`7Kl&OwP*b*^>EWHaDfRt*NHDt4rL8nCxB~v+_>GcvMo{?v~zU5|ihGNH=;s zx^!IlMC7QIwY1hf45l`H2&I@e<^m>Z9E!MClk zHId$~^cP5QuVt5nMH^$uWIQ^8B5^UR8D7UA4a2js*kJwWOgFEN56?u{3}?2d7Ohz$ zliTpTxyi%^e4(~;{leZ2tFb>A)?&;&)}lEqOWL4DWNLUpYXKjg0gZ>u%Qh|=MNE#M zl_$efBMcSN7 z#gb`j^#D~uH$o5R;HG-YtZ$u>2{S<6zAbo8!HbtdDhV}v1;#h1jeFYb)VAj*b2 zr7)y&)Crg#W%5kTO(b({9(O|rij*A2j1C!2)NKzvg6<`;vwGvnSk&^mm?B+cGh~L8 z^&&OWCXLX@xslFDRJCHzxUxs4*fnyFx?>;?2ulF_m<59E@ovR~UlgJu za;Qt2H%8*JLCo&iuxe5}-{vGzyn?DpotE@=r{f!9e1k9#(Fr~)2E`MC#gScz+8BuM zG3I1rMeA*Zds?jF&KFnas5I9m{7$(S5tM;Ut-N=W;lc&sv(@o#m??`Juc)yFk?AG}&4Tjdod1k`BdOZnM=aB-F5}1O3rp^?IryF9g&8 zva{@+{Qr>-HrlFUke*X{yGa~ZF||B)VEfav4rKlgYlIEhoJeYr2s>`@T~TY;PJ@u9PSs>_L*7lDI{oHmqH|GigrawMGb%}e9yd>zArI#;3{o2CdlTAF5s zd@k3nsv{li!A>sGyLMeJb7=(gN_sBepl?bf*XJ@8L^iLEvE4bAt!Q2xPU_C_+s;nM zx>H!RaxA+ISo342;KqN%%=YdziR1=Z?jl`>l(N?vk;~N}Q%GA^Yy}vEh-JdQBc!=qk+rgf$ik&u zLg=ursD<;~Vxb$dSl-lN$iHK!HOTQNc|EFVJ#>06jlJ9@Om~y(t<^j=@f7M zq$kiYdlxJ-em3A1$NC?6zu+64;iqBfOieXJ`;MF6F43@*saYPu9VjBZtHcF!;F$=w3LZu@S)Ivt_~ z@y=u-l~|K*$W92UhSpdQ_P=lu4j#@__r=+si>;-sOxcB>VbZZ_g3E-3|v@>1$RFe@X0cS<529dx3m;&IqP8@1bUYn{9i z#-PNtP0yO0Ub%9$I+jysTQaa>Nwqso@)6e%j(wkRv9S^4Ggfs>kfc~XF)w!ZocLP4 zcgI4DX^MB5a*lw(3D?qwp$wjevM0YdM#vr#^7hd>FQj%1;8S^BPEuDE=EEDapQknOOYYnh09Za!v8*)400 zN7i;HpcbqVccik2q$qcc$y;%?jkS&k#S(bdCI=rLvbddN*Mg=v@p*k6 zBs@RXy*9lrg?-}Gl`GTuEA1mV7gK69*4!QG+MGguZu%R<9=Z%RaI~jLJv899@M>^~ z2CK5U7U$76inz4Vl)8uJoAWdVoNA8hRqh6y^vMmB;-hbElC$#2Tsyva8qb^MhdUoO zU{{UsPUVZCwbE%Sesk*C4SAFmJFw4M2rR~M5qr8EE|8rH@(S^+Fidw|{;<5aISY@g4Sg&Cip)MY2t z6y`nqsT-frWc^`Hiz*7Ry7Bp#+DY03Pq7?Bayn=UsPGxg!#SuF&Z?IEie2&$&B$eE zH__@AWCZyoi(4Ahu}ofoAyo3t-DFe4vqsDkRJV-kc?M5YP@CxPjHC%iOPFPID`j?x zq(!TFV?x;Oanga?OeAQWbuir#OAkIpX2y^cWM-*h2;1za#SMRM$!NfG3ZX>L%66P9 z$2;RFfVr?Mwg^kG90tpj3n|>oS|=D5fgx^TsK&yQN)BBnaS_MLJbbE`ZC_jW#&|N( z&9_M-nP@$t$TxM!%4aSuotlr!;SzH)*&&f0`PR97)ZIBH1_$d@i@DoeQ4l(sG8}Y>h z?@-UWd1E#FDK{nLK{zeIt>41f*)WmoUKrby7wDL0ICgm&6&+YvH$*zvI6jBq+@%Qx zo0G}NW?BjTCht4b5>{ z%YTn-ps*d}0;t;{Lg*S)8O3Wnm{6b&&o8Aa?8@;Ky!|@jUmzh#dWHtvd!%B zoE5!RonNM%4Wvz3kJ5-pSk;C0Za}-ZWE9r0)4AnrR|xn9bVVAn)IYEo6%O{i-QPnU z$uzr_8@3jOxyhTM$aV`?(Tz8|*coxDf*r>_&yHpnjMPCIrB()0?SG53JrX+o9DVPl z>&Xa_=D-&p-A;hwGDZV}9%q&X+qGKFT^2l9uhnXG;hx5@CSU>v`**2iH+1Nb?mwWp z9U;7A2D+N*S2VXLM3PZL&JYFr-!?D7blf?dqr$_gRt1U}%zFW3d+Ah_DkSaU5S zMJ^-QTNYfP1*a;Ax8{Pq5Go#s;BBlxpt>3r25OuR!mk+M4bvKDAYi!Q6Vd~L0NkU4 z3%NkR71D$K1K^=8tqhh!PDk5?lYygxnSk4+aXmHFfskP#HPylXOCVoU4QC)DP^4ta ziu=C>I@o`0xsuH>0#e4K5dJ-0sikV(hR&lT8no`Yw^S8 zT5u_gE#`krEw*f^sevD%@*2F%Sls`FsK3T^!IZ1?V3DTl5+1c29Iv2f46o*NA~dQ; zNk|QB=3a+`%7UA<8Yg_}M&DA62v!%MGl5z~MfG01tIM*%{=KS54KNQR9z%_LtE-Ca z3eg)+%U!MXG3p*i=KsF3q;l;^imj~t=rO~d%T*J&mQJNJPtId z3Rp(W3$}7iNQz)R+n80tZfkXMjkg9{G1}PXR$aVzyXr9blDp@2;oWI<;ws_Y=|-6M z? z*L5CX)dlQ~_oX`YO(i@oc-CX$Bm9BRqO#z?OvCcH8=|8}=x0dOlDk&(dv!|^f>Oh8 z>>9kHC%_ueNdY9qE~gtaL~;K;T5uHxMlgm@#H6u`=QHMFsK~CuD#8%1DF@$QIF8u0+v!=#5YNR0GnFBBE+eMu`=*PG`ZsyozseIZrj>Di2Z?wP`<2i5;yBp zA>rTvhw(s}on0wprA^idS!0uRLe>S~XBZaj-^Va!*Rf9~VV?F1c!Bv;xu(Wh3crf` z!F)QSL5_^<7~1(+GtZjtEpMK z|78qfo;e4`VK`x?<&;OU8g_`NVE=1~My%pBP94AN9pI=zTS5pQ4D5j;v7lR+ax++V zl&jLE7{uID{couTGoJ0Ww|uB85C{$&hZuB+oY*{olvsX2=32E^8aU45GHj`5`bs{3 zcH-M7yDwOG+f`?u`S3#b?uRzdIP&egR%!U20X~KaTTQ272BWxU;W`V~3S9FY2-gAK z#9))?p9kJL=AFl2JE$hz)KR_~=qg++uoTx~@Z5eW1c&l`0*0-nl?#6cFyLh1VNifV zXERa^B#o=bVPahArrWJ%{NPkDCkeqbA4K~v_M!r7=|v{gVhf-w#ju9J<(4>R6s4r5 z+F>FnJSvib*~;1WE-wEME_b)n&9#NOad?D=jNS6yH+f{b>+CjF0_qaDz-tvw~-N)i4N74dTzw8od3~tr;OW zuOQ^mf|GbfIuE@JJ;7FN#j#zG4M%V}bCw4@utG(J$gc~QDtW|Iu!-%&DoZ@k!dU!~ z0_^k6w4M0+Vg{s5tSt%j*%_{t$??d z*<~wWnP|lz+rwL?8r(nd$YEJ@ksF(4t0iI;){1~JYUEN_Wza_pg&+I4SV~4 z%Ra2B#`46I4zg4xbFruoD4_vqRa#(=Tc+4xG=RC*ZsfdRli#AM;f^MIidY3PrQ)+< zrC%1U8qBYMs1EWp``fG&n1x}Ff#Q+%#);7+We1$4gc|`g4z|s+k)}dbAyz%*EhSr~ zl1i1-sHDzA1~y$aSfiPND*RZ~C8GQH2IqkXkL-o#vl|BSChpD9WQ2-~`vk$y6nhG* z#a^o$-0&2rfZKtu3q={U8Td&dcUZbEIM3lm0D+?;3nLc5S)lUlegrGPe76&YvDSy# z1t{UhRqfz`;@0q;JO1G3NARUKz5LW zt!2;ravJN0e~W?ti0p~~g2L>ZT;gtY*-0AB{TKAfk*4Uv4}mVxXu-drEB|4G9Sx^w zbn?HT(*AaY{d%sbok?`MM$7*f)QWTP`1D1Ip)t1QqwocWeK_<4j#9ih>=>-l@AOZ5W0sFT5QC)Rvg%?IXutk0jrrPNY6^X|skc9)!e$C2AD`9ya+K7mqA z9yuhT0dI$mpy?@*nS^$$e^Y5S`+!a){vJOc*Yj~aKZe+xeOAI1wBXkjBcinf=^9wq zfbTBzvlLZRgLR(HvP(pl-3opJgJ<8cJT3?QIh+3{IwxUQgjEGP*fXc#N=pnCMdk5%xdpI99GAGD_dk1V?Ik3ZPhLFatby;iibw|d|wZrNJ+hkvOe zgzKwP_ackW{^7c9+nM6$5MSP>`8KG2QqM`En0Y!;YpzvaUMH%@-)i&R=HKHZLRfng@Vs&l~yfneL#J+_txIp+Iw&NyVBoxt$ohS+z++0 zUme%JKAH@4C*tc8p{_tjC>D#S0&60HL{BUbjRjg3wFSE3;YeLUf%|yV^x{^cvo(YI zraktFRofvtF5uDXiLM97p}5l?!99R$4=$oY!FA;~GuVIirxAhAe+I3-j8*yn?A;`p zg})EJL$rvIJw(6ZKn(pmM3fKS+Yb}950xE@4iLF=?X1Vf2x1~|k2LE8lRzpSgcA9}m z!4+Sy7TRvTk0nNY8XVF4SUCYPj z*^q6LOLqk8SpoM3zF%$V3DnjdoB}G|2ryAMY81~1PGuFbWuwKo^PlOp-H4Z>dgVm? zBq*lQSTrME26h@PWE>7SY+hUPJmw)LHeK&ywPb=Bh?T8otsV@3(ECK(#|4e}1>m4( zg=dj#EJZG+i()*mZ66x!>xMqr~mP6=fefGhKpUl)Old{?4 z)0sxCBDKX4mqFrFhR~-Dp=S;*ej1afTh{DeTYMICkdbcGE*U8Z7#@ou2pI5MX$S&F zfyEF646nry#LDV#nZ4t+rTtLQ?P(w1Y;k0bBaKYvJVRbfp6P@L@m%fmQxK>-jsCXz zNlzn8xEpD7EAGW<vlLB->ZTC(aN>_ zUF9$cMyQXu$F471F1Nm8l|wJ1ePajLhc4juF&FhAp@z3_XgR6xXyq`LIR5b!9NC3> zANPV{8S#rp;Po+Y%^Ol;RTAn`*Ivw^fo%oXX!>-$*r%|8H$niUfQBylft8wVI;MvegV`!og zoL-J2jt9U=&VwWI`2a`+wz&{C`Oku^n;jVuLW?p3u*dAO>Y^5CgQ9$4V7AGFAiuquOE!0!F}M2m;19iy;UY$5{+P z;IEBp;VULGW~Zmy-)qLDbBuK9YP0q6vB$ z!_-!DrXIu)tW9%U)IhI!IWyoVFw>SE&o=`DdllPkW1C33+8`3KHhnx>kv@VpVF3G* zk3o(7L3`1ytN?$0z-7^DcM$zt%L}@#L;?^zACj7d=u4@mk1I{iW?puU{t8<%(kI}? zs|k~t)r1LiHMvlU^gdQJxM2=!VOcwZNUbp=7dnN5HL~c`ql;t_8nG&j0e4Me1Sc{} z6Sh+5TsN8-(y)Mgak^dZ zTa;RGjH-jF;JI8!-RnqbJ$N4Dm+PfTbhSG@5n{8gwloF`_bjTnVGB4+BXK`(BQQ4I z7fX)uI)d2)LZt?zVJ?+>6tz<-SF!asF^0GZlmclPCA-$%vUR z$L6(CMo)jkv~i8Hq1e1FXB$lA*x=m5l*zdV>+bY`X=AJ0jr7;#ZcAS#_u_QF+_xw- z-r%!Mrh@QX{Ibb&8fGn0IUj=8(N0k_dr2 z7=T5ObE2p88boXCgc9dHHNkP<)flSH>@Vg$_IEA&dnGJz9IukQk-l2)w)EHKUYx!{ z?pu^v5c4?u%Ty4<&x~UuY!)k6s2nsYZbyg5-$1G!dA?#x2@Fm}rJkZlOK-ba7FpfEm7qhpx;}^qn z@GEfVlItOo1%5k_BaSy%ig06rX9+*=!DX?H8(}i=C4X+(z7YzJK8Eo&W&0qPM&G%E zC#rH|v3|dYau}+ZXBwf3hrnsLc^nfj(ECo}vWSCY!X)Pj&OYRyt-#rb!EVblh3I5Q zJk1~uvqg5lJ=hIo(k#6MD>xg}efBhlrA=46db=KkqqXnG^*-hn+4U`aKT?cz8><(a zg{=!E9F$S%bXR;6Bf& zyB?+TQar^@Qyv+?9v0Un?}63+>9CJJRF4@|2JhwTv{F8lfklk^j6^uAL; z>wPl;;}Mjvu~g8>=(Z76ENfUHPh)Fnjiow^?S$A4_a*j%ztxB^)1hx>LxjF*#?9lH z@k7WRrKeUytS9dUo^F9a?^BSK((I|;HwVy}-A1eJsQsObxu9q}^}e~#QJYiM8a5&g zyLMu)Q+D0Tf+`@A?7ljF5h7IJH-ejSpEO&#oqg5w(x>xnOB0~q(D{U+_MHl;mjwm- z7QP)RMpvkQ=Tfk9G3?~mcIH+bM6ak_{LtD;kuOKD?O{Yo@B8A~RKr|p?nb>26P|5i zl~eZUN^-<;9~{VT)N3mSOTRTp`fdPei^LSaMyrmIDEMr_J~Zy#F(XQYm=lquM9mnC z{O85B1MzwoR{*$~vrTZ%2x7=(^K#)REqDnSdfyok2LFj=IPE~<@D^(xw<_2VB7G*% z8cr^L&bSRWt0cEr1BK7R4ddS7D6LyrQll43NoSDfj%#_E(@WB4L#1}9;yGpet@kl6 zJ^=IieqG!MPDEEvtiTBji_-G}^inZaYFSmH0zI#ErPx%ovKYrg>z;B)2~VY5wq^`J za=S0aW|+xsYcO^>PS$!~ooPe$k;XE;j~f}}<~DlZv9#V@TT~*C0(eA|X37JBg9rBa z(7Mb3zubr;TO548Rjcn?RM;0vw zl&94Al_<;uQs;nupb=O+{}$KW#9HG;RYye|1PobNvuoJ<-G zT{k#a?bM4HVz=cp;<0gW{B*9JU{TMF}vp2pCzIg>l!W4eyf zK2(58Svk2ATxXwRvtAsd!@*0i+ix5x#>_P~FSrX-plQx1s-6>L@2na*?nv$)q3V-IsJi@^ zRlh`kU#l^E9Lawkq3Y?ws-CHjIaby0F8LDCw&qLeHc1tXf6U|VcZ+!ZXW79A!9=R& zuEYC~Ob2k4qmAYqz{zF=A5yx!CM-edkC$vu`4(_`^^inoGP< z<`PKb3;Cv=Mv%rc5Qle;NK{#XH0E1Q8gnT#jj4$(MPz}M@Oid z)A;CBZ~byrzw2|9OwKnO_+8X;!rRV1Owt(YBRVpGet);LfP*e|OMCOw)=0V{%gyeI zFr*QF+JtKhu0P`P;j;d`K*|vR6L6t_tUluBI&-hYbDINm710FgqYV%tK3%wBZZlA3 zA+8_ddK(w!u^1%r?@15^{XWp(jqpAG7%*PYe}KEW<7I1DsJi*4o`$hdox=ThD?HNs zSb(*PZ%2y9!xverxD@O>4m>c~WHa+ths5taEQkMLt`4BXrH0u(`t&Ui(g+ z)Wia847Tt+Csm{>o6LCRD689KrOHUHG~13?AV8w7G#X#6P#yk6(J#}m^r+`}#d zf%szgMog!AZtjR(qW5vwN{(pp%Q&yf@j!{h5}#nzBl7x8UN z5|B5FGr70FCB4l8AYN8#jnq)RPq_b*ZT_=abWaxD3pD;C2G;`&&9Y-StFr8iojpdDjqEoEacGu_ zAJQ#@vMkFUHh*!RJ&fzyi0RNg;~e`9uADsM9?!`$JN-B0YX0hl2zl0r+sJu_Y0?(o zCm|JdKhUGjUu+F|b_w6MTnxy0Hj8`z8q}!wu>g6-x12oVQaO2+2KhzvmsEs2`zPp{ zH6hPtb4}x=CKhm>@jWNcq^eAw)orknY@}A|eZqY%+xF*y#$RACQaT;OCzVcL?9(yQ zX=D#MRzuTC{E+AmN~bJarBm*lbrW*wdc`zcyJ@XBdx`MAkSd)F`d-1Kz zGv5GeFoLfuIq&zLfa^G-#dFdX5W&N%a6|l-SdqCJbZPJaO6YxG2Oj(>(D=_7yaB*l zh&ORJpLN*?hTt~7sl#~;!MSM6yUX=H=3@Nu?MQLZiVqiok)OlJ=p#nvL_jQw3G8qW zLa0szvTRrI7vQ3qnP*#kIAEO#TnVE_@Rv$~_e}gCrS`SgK!mnnQ1F~%L;01s&>&if zTzVeY(VwQAeUnk_o_GsdG|~>3ZDS9Fd_eQB1>^_0Rw%#o4D9NCEWi$!Z#mNfmm2yY zcQdER1MuH^kh7{jeT1rcPj&RF=lq>j-@;Yz9--_CTbjlqQo@n?Q?E|kzldAHVyyBAjg*G%({J`g*3xR>Fw<3f_j^BGZF5!ZpR zkf+d9=Ab(SI(&>T8Fgc65jCKYgI*Xl;CIj`g{O{oP)J~vz*7Z2CGetAEUg;FWykn> ziX3<*XEnk1fkpIR~2fe2+xBKbwisLH$^h1Hy6f-^sI(~Yu>fEso>KFf48*Jw(a7rk@ z-c`jcJv8c5z%FCC-9fv> z!diHOcIC6phfC6^_keIF(FZ0i@WcZPvp;i=*b9pqJjto9gz`x67u$w{vy2wn;qPB0e{l zj0Wd;MBY!|8&i!$I=R$8x{7`_<`?Bv6duj^xnumJ{dD)3JBq6465tNnQ^a=efS+DE zT+Eg~5dZIRj00Ym{~yrtpkEyH^=j66O?1wZwm&NT2c)If3a-Hu2aO)faI1LO2Y4Kv zTogpvr%={Sg`QZ&3G{$*8+!b8X>|`;?Vzin>88bAZhK6iM_?Ub3H@bE!I&{rS*rb-8fFKb5f?k{E8 zSkeN8l!9y--i*TOK4fJ9rbf|8LjAh>g0f{)gm)rX_A3ulC3q8)so&d}s-OizU0lZ0 zcsh?XH28bo3(5{-XSiCZmrN=wnp?^jl`n&Ay-=M(1u>)Sgv}mL6GrxlloIMipQ5%1 zby7f4X(=}i)G}yZV%FD$`f8}(tWQywO1WS9KCLFmu9R{Eo=>Znfx23#UqQBvrqJyY zv#Dd4YNT(Hf#|+%5Xv{w-DHd_q@|dmmeF)@Scc6ls8i@(q23VcG`e4?YGlDq#Avrr z*Nf~7eA>h1{tTPTFw;FG)H;zZpvQz-Cgm2=<3dfB+S{>1%+`J`JtZc=9xhF;I{Y&-o_WT%NQH_)3xVOfQrH`341+s~J6cbz~n-%T!!K6Kvd z8b`svoq$~>I{>dQzZdYTvIhY7Ry+uJ!2Jj`54#xJ1P(YE--WUoUF-TDbmj$~0<`$Yes24@siV<19KV9}6@e?A?*Tu@u^sU9 z()R(^N?k7te9-kVIM2C01Dxi1C1dTXvi~xzjiYPEJ_1~MuHd3#${R-y8+O3I6}tid zqhM5?Mws3J?+TOwzKT*BIV&rHyPe|zm%1k8Ip{yVHGmHnPXZj{p9c7G*`3gA*H6it zMoVmS^GYZ{^Mv09cvtmnE(gu=G5okJ%dzaN$Y^$>jShOZ`aIM%RS$#jb#s*3^(gSi z^VuIRrO~BT3@13)laI@O&VCwAYEQoQ_Abm$_zCcAJTSbsB%#Ml%ZIr{+=(m z7pqT}`kVXsEM@<&`ouw0BdBY|%13!zPN$odP1g^6vq9ahDDlOh`-R#Hst~K&BN^&K ztY=RObu%q;w_-1L(4^*oa?x)xvX`)CRg5G2-Aqf}3*8<%Q7CThGIu^TDT>a?J0JU# zD^1P$j`i+Q^sq_&DBq!B%PW7+7yNQ;wKh6K{m7q7-S5t&PQhB6)m&EE4eE_d?Y*Gt zk7GlZbW5rOUMw>2DTgU#m?d z?|An5Bkf>SmsUpsMdfi^rVziHhZebhKeiAnW`il?C^gayQ}$DTAy&*eri^1YmCiI} zPrD0gDz%w1j^Igjt|@Ex%mx)UWgO3G)M?7rmfi)bM^TbJClkM8t@8Q-_sR5tqUa>_ z^r`eGp$0^ACjBp=Zgw>lJ?5TC`thm_->aUDXA$)^yaCs~>L(#9GG!N)JnKG<#tJpy zx~ybBsN;pYnGROJ?4Ct4gxX$KUwXhjo93xT7{hh8zMD?!c0N9<

qC88X$Cl7EllmHZYzfUa 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 OFR=6f#s5!6;C}<3YA%ET diff --git a/Packages/io.chainsafe.web3-unity/Editor/WalletConnect.meta b/Packages/io.chainsafe.web3-unity/Editor/Reown.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Editor/WalletConnect.meta rename to Packages/io.chainsafe.web3-unity/Editor/Reown.meta diff --git a/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditor.cs b/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditor.cs new file mode 100644 index 000000000..f78c3fd0b --- /dev/null +++ b/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditor.cs @@ -0,0 +1,10 @@ +using ChainSafe.Gaming.Reown; +using UnityEditor; + +namespace ChainSafe.Gaming.Editor.Reown +{ + [CustomEditor(typeof(ReownConfigAsset))] + public class ReownConfigEditor : ReownConfigEditorBase + { + } +} \ No newline at end of file diff --git a/Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConfigSOEditor.cs.meta b/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditor.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConfigSOEditor.cs.meta rename to Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditor.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditorBase.cs b/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditorBase.cs new file mode 100644 index 000000000..a1b90f37c --- /dev/null +++ b/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditorBase.cs @@ -0,0 +1,58 @@ +using ChainSafe.Gaming.Reown.Wallets; +using UnityEditor; +using UnityEngine; + +namespace ChainSafe.Gaming.Editor.Reown +{ + public class ReownConfigEditorBase : UnityEditor.Editor + { + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + GUILayout.Space(10); + + using (new EditorGUILayout.HorizontalScope()) + { + if (GUILayout.Button("List Wallet Providers", GUILayout.ExpandWidth(false))) + { + ListWalletProviders(); + } + + // if (GUILayout.Button("Clear cache", GUILayout.ExpandWidth(false))) + // { + // DeleteStorage(); + // } + } + } + + private void ListWalletProviders() + { + Application.OpenURL(ReownWalletRegistry.RegistryUri); + } + + // private void DeleteStorage() // todo check if this is needed, remove otherwise + // { + // var config = (IReownConfig)target; + // + // if (string.IsNullOrEmpty(config.StoragePath)) + // { + // Debug.LogError("StoragePath is empty."); + // return; + // } + // + // var storageFolderPath = + // DataStorage.BuildStoragePath(Application.persistentDataPath, config.StoragePath); + // + // if (!Directory.Exists(storageFolderPath)) + // { + // Debug.Log("Reown cache is already cleared."); + // return; + // } + // + // Directory.Delete(storageFolderPath, true); + // + // Debug.Log("Reown cache cleared."); + // } + } +} \ No newline at end of file diff --git a/Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConfigEditor.cs.meta b/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditorBase.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConfigEditor.cs.meta rename to Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditorBase.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConnectionProviderEditor.cs b/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConnectionProviderEditor.cs new file mode 100644 index 000000000..5576d10fd --- /dev/null +++ b/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConnectionProviderEditor.cs @@ -0,0 +1,10 @@ +using ChainSafe.Gaming.UnityPackage.Connection; +using UnityEditor; + +namespace ChainSafe.Gaming.Editor.Reown +{ + [CustomEditor(typeof(ReownConnectionProvider))] + public class ReownConnectionProviderEditor : ReownConfigEditorBase + { + } +} \ No newline at end of file diff --git a/Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConnectionProviderEditor.cs.meta b/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConnectionProviderEditor.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConnectionProviderEditor.cs.meta rename to Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConnectionProviderEditor.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConfigEditor.cs b/Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConfigEditor.cs deleted file mode 100644 index 0ab11633e..000000000 --- a/Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConfigEditor.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.IO; -using ChainSafe.Gaming.UnityPackage.Connection; -using ChainSafe.Gaming.WalletConnect.Storage; -using ChainSafe.Gaming.WalletConnect.Wallets; -using UnityEditor; -using UnityEngine; - -namespace ChainSafe.Gaming.WalletConnect.Editor -{ - public class WalletConnectConfigEditor : UnityEditor.Editor - { - public override void OnInspectorGUI() - { - base.OnInspectorGUI(); - - GUILayout.Space(10); - - using (new EditorGUILayout.HorizontalScope()) - { - if (GUILayout.Button("List Wallet Providers", GUILayout.ExpandWidth(false))) - { - ListWalletProviders(); - } - - if (GUILayout.Button("Clear cache", GUILayout.ExpandWidth(false))) - { - DeleteStorage(); - } - } - } - - private void ListWalletProviders() - { - var config = (IWalletConnectConfig)target; - - if (string.IsNullOrWhiteSpace(config.ProjectId)) - { - Debug.LogError("Project Id required."); - return; - } - - var uri = WalletRegistry.BuildRegistryUri(config.ProjectId); - Application.OpenURL(uri); - } - - private void DeleteStorage() - { - var config = (IWalletConnectConfig)target; - - if (string.IsNullOrEmpty(config.StoragePath)) - { - Debug.LogError("StoragePath is empty."); - return; - } - - var storageFolderPath = - DataStorage.BuildStoragePath(Application.persistentDataPath, config.StoragePath); - - if (!Directory.Exists(storageFolderPath)) - { - Debug.Log("WalletConnect cache is already cleared."); - return; - } - - Directory.Delete(storageFolderPath, true); - - Debug.Log("WalletConnect cache cleared."); - } - } -} \ No newline at end of file diff --git a/Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConfigSOEditor.cs b/Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConfigSOEditor.cs deleted file mode 100644 index f60f4ec1d..000000000 --- a/Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConfigSOEditor.cs +++ /dev/null @@ -1,9 +0,0 @@ -using UnityEditor; - -namespace ChainSafe.Gaming.WalletConnect.Editor -{ - [CustomEditor(typeof(WalletConnectConfigSO))] - public class WalletConnectConfigSOEditor : WalletConnectConfigEditor - { - } -} \ No newline at end of file diff --git a/Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConnectionProviderEditor.cs b/Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConnectionProviderEditor.cs deleted file mode 100644 index aed82d9fb..000000000 --- a/Packages/io.chainsafe.web3-unity/Editor/WalletConnect/WalletConnectConnectionProviderEditor.cs +++ /dev/null @@ -1,10 +0,0 @@ -using ChainSafe.Gaming.UnityPackage.Connection; -using UnityEditor; - -namespace ChainSafe.Gaming.WalletConnect.Editor -{ - [CustomEditor(typeof(WalletConnectConnectionProvider))] - public class WalletConnectConnectionProviderEditor : WalletConnectConfigEditor - { - } -} \ No newline at end of file diff --git a/Packages/io.chainsafe.web3-unity/Editor/chainsafe.web3-unity.Editor.asmdef b/Packages/io.chainsafe.web3-unity/Editor/chainsafe.web3-unity.Editor.asmdef index 52bf03291..6f2a43992 100644 --- a/Packages/io.chainsafe.web3-unity/Editor/chainsafe.web3-unity.Editor.asmdef +++ b/Packages/io.chainsafe.web3-unity/Editor/chainsafe.web3-unity.Editor.asmdef @@ -1,6 +1,6 @@ { "name": "chainsafe.web3-unity.Editor", - "rootNamespace": "", + "rootNamespace": "ChainSafe.Gaming.Editor", "references": [ "GUID:5426c6b788696eb4c88f4198b59839eb" ], diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect.meta b/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/Predefined Wallet Button.prefab b/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/Predefined Wallet Button.prefab similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/Predefined Wallet Button.prefab rename to Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/Predefined Wallet Button.prefab diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/Predefined Wallet Button.prefab.meta b/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/Predefined Wallet Button.prefab.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/Predefined Wallet Button.prefab.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/Predefined Wallet Button.prefab.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/WalletConnect Dialog.prefab b/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/Reown Dialog.prefab similarity index 99% rename from Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/WalletConnect Dialog.prefab rename to Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/Reown Dialog.prefab index 93eb7d2df..19edec7ac 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/WalletConnect Dialog.prefab +++ b/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/Reown Dialog.prefab @@ -1027,7 +1027,7 @@ GameObject: - component: {fileID: 5250797134093199903} - component: {fileID: 8916565415885596037} m_Layer: 5 - m_Name: WalletConnect Dialog + m_Name: Reown Dialog m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/WalletConnect Dialog.prefab.meta b/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/Reown Dialog.prefab.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/WalletConnect Dialog.prefab.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/Reown Dialog.prefab.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/dialog-hide.anim b/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/dialog-hide.anim similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/dialog-hide.anim rename to Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/dialog-hide.anim diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/dialog-hide.anim.meta b/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/dialog-hide.anim.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/dialog-hide.anim.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/dialog-hide.anim.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/dialog-show.anim b/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/dialog-show.anim similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/dialog-show.anim rename to Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/dialog-show.anim diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/dialog-show.anim.meta b/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/dialog-show.anim.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/dialog-show.anim.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Reown/dialog-show.anim.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Web3Unity.prefab b/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Web3Unity.prefab index c55e17dc4..e2f0d3282 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Web3Unity.prefab +++ b/Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Web3Unity.prefab @@ -49,8 +49,8 @@ MonoBehaviour: providers: - {fileID: 11400000, guid: 835338196b5038d4b9351fadba9dac38, type: 2} - {fileID: 11400000, guid: e5b50e2ca9fe0504daf70376bceb84ac, type: 2} - - {fileID: 11400000, guid: 0d7bd7ae4b3e79d489bbc54514343f5c, type: 2} - {fileID: 11400000, guid: e56cb66917f860e489d3ed4480b4681c, type: 2} + - {fileID: 11400000, guid: cad6fa48701480044a2a6f2d9c9dae1e, type: 2} --- !u!114 &29625373239180716 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/WalletConnectConnectionProvider.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs similarity index 60% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/WalletConnectConnectionProvider.cs rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs index cf2631fb4..62552d5ac 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/WalletConnectConnectionProvider.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs @@ -1,24 +1,28 @@ using System.Collections.Generic; using System.Threading.Tasks; -using ChainSafe.Gaming.WalletConnect; -using ChainSafe.Gaming.WalletConnect.Connection; -using ChainSafe.Gaming.WalletConnect.Dialog; +using ChainSafe.Gaming.Reown; +using ChainSafe.Gaming.Reown.Connection; +using ChainSafe.Gaming.Reown.Dialog; using ChainSafe.Gaming.Web3.Build; using ChainSafe.Gaming.Web3.Evm.Wallet; +using Reown.Core; +using Reown.Core.Network; +using Reown.Core.Network.Interfaces; using UnityEngine; -using WalletConnectSharp.Core; -using WalletConnectSharp.Network.Interfaces; -using WConnectionHandler = ChainSafe.Gaming.WalletConnect.Connection.IConnectionHandler; -using UnityEngine.UI; +using ReownConnectionHandler = ChainSafe.Gaming.Reown.Connection.IConnectionHandler; namespace ChainSafe.Gaming.UnityPackage.Connection { ///

- /// WalletConnect connection provider used for connecting to a wallet using WalletConnect. + /// Reown connection provider used for connecting to a wallet using Reown. /// - [CreateAssetMenu(menuName = "ChainSafe/Connection Provider/Wallet Connect", fileName = nameof(WalletConnectConnectionProvider))] - public class WalletConnectConnectionProvider : ConnectionProvider, IWalletConnectConfig, IConnectionHandlerProvider + [CreateAssetMenu(menuName = "ChainSafe/Connection Provider/Reown", fileName = nameof(ReownConnectionProvider))] + public class ReownConnectionProvider : ConnectionProvider, IReownConfig, IConnectionHandlerProvider { + [SerializeField] private ConnectionHandlerBehaviour handlerPrefab; + [SerializeField] private List includeWalletIds; + [SerializeField] private List excludeWalletIds; + [field: SerializeField] public string ProjectId { get; private set; } [field: SerializeField] public string ProjectName { get; private set; } @@ -29,49 +33,34 @@ public class WalletConnectConnectionProvider : ConnectionProvider, IWalletConnec [field: SerializeField] public Metadata Metadata { get; private set; } - [field: SerializeField] public string StoragePath { get; private set; } = "wallet-connect/"; - [field: SerializeField] public string OverrideRegistryUri { get; private set; } - [DefaultAssetValue("Packages/io.chainsafe.web3-unity/Runtime/Prefabs/Wallet Connect/WalletConnect Dialog.prefab")] - [SerializeField] private ConnectionHandlerBehaviour handlerPrefab; - - [SerializeField] private List enabledWallets; - - [SerializeField] private List disabledWallets; - - [field: SerializeField] public WalletConnectLogLevel LogLevel { get; private set; } = WalletConnectLogLevel.ErrorOnly; + [field: SerializeField] public ReownLogLevel LogLevel { get; private set; } = ReownLogLevel.ErrorOnly; [field: SerializeField] public WalletLocationOption WalletLocationOption { get; private set; } = WalletLocationOption.LocalAndRemote; - [field: SerializeField, DefaultAssetValue("Packages/io.chainsafe.web3-unity/Runtime/Sprites/Logo_WalletConnect.png")] + [field: SerializeField] public override Sprite ButtonIcon { get; protected set; } - [field: SerializeField] public override string ButtonText { get; protected set; } = "WalletConnect"; - - public override bool DisplayLoadingOnConnection => true; + [field: SerializeField] public override string ButtonText { get; protected set; } = "Reown"; private bool _storedSessionAvailable; - private ConnectionHandlerBehaviour _loadedHandler; - - public string SignMessageRpcMethodName => "personal_sign"; - public string SignTypedMessageRpcMethodName => "eth_signTypedData"; - - public IList EnabledWallets => enabledWallets; - public IList DisabledWallets => disabledWallets; - - bool IWalletConnectConfig.RememberSession => RememberSession || _storedSessionAvailable; - - public IConnectionHandlerProvider ConnectionHandlerProvider => this; + private IConnectionBuilder _connectionBuilder; public bool ForceNewSession { get; set; } + bool IReownConfig.RememberSession => RememberSession || _storedSessionAvailable; + public override bool DisplayLoadingOnConnection => true; + public IList IncludeWalletIds => includeWalletIds; + public IList ExcludeWalletIds => excludeWalletIds; + public IConnectionHandlerProvider ConnectionHandlerProvider => this; + public IRelayUrlBuilder RelayUrlBuilder => null; + public string SignMessageRpcMethodName => "personal_sign"; + public string SignTypedMessageRpcMethodName => "eth_signTypedData"; public override bool IsAvailable => true; - private IConnectionBuilder _connectionBuilder; - public IConnectionBuilder ConnectionBuilder { get @@ -105,29 +94,30 @@ public IConnectionBuilder ConnectionBuilder protected override void ConfigureServices(IWeb3ServiceCollection services) { - services.UseWalletConnect(this) - .UseWalletSigner().UseWalletTransactionExecutor(); + services.UseReown(this) + .UseWalletSigner() + .UseWalletTransactionExecutor(); } public override async Task SavedSessionAvailable() { - await using (var lightWeb3 = await WalletConnectWeb3.BuildLightweightWeb3(this)) + await using (var lightWeb3 = await ReownWeb3.BuildLightweightWeb3(this)) { - _storedSessionAvailable = lightWeb3.WalletConnect().ConnectionHelper().StoredSessionAvailable; + _storedSessionAvailable = lightWeb3.Reown().ConnectionHelper().StoredSessionAvailable; } return _storedSessionAvailable; } - public Task ProvideHandler() + public Task ProvideHandler() { if (_loadedHandler != null) { - return Task.FromResult((WConnectionHandler)_loadedHandler); + return Task.FromResult((ReownConnectionHandler)_loadedHandler); } _loadedHandler = Instantiate(handlerPrefab); - return Task.FromResult((WConnectionHandler)_loadedHandler); + return Task.FromResult((ReownConnectionHandler)_loadedHandler); } } } diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs.meta new file mode 100644 index 000000000..7709a95c6 --- /dev/null +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 582efc0fde77aab43a77ee4237ba305a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - handlerPrefab: {fileID: 5250797134093199901, guid: 0c7c312ad6c521f4b8346ed8e9d7c664, type: 3} + - k__BackingField: {fileID: 21300000, guid: 7bb02b1b8d270114fa77d28d426c8c1c, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/WalletConnectConnectionProvider.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/WalletConnectConnectionProvider.cs.meta deleted file mode 100644 index 339cfb980..000000000 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/WalletConnectConnectionProvider.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 582efc0fde77aab43a77ee4237ba305a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/AotConfiguration.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/AotConfiguration.cs similarity index 80% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/AotConfiguration.cs rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/AotConfiguration.cs index 66d59f08b..57d8a327f 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/AotConfiguration.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/AotConfiguration.cs @@ -1,12 +1,10 @@ using System; +using Reown.Core.Controllers; +using Reown.Sign.Models.Engine.Methods; using UnityEngine; using UnityEngine.Scripting; -using WalletConnectSharp.Core.Controllers; -using WalletConnectSharp.Events; -using WalletConnectSharp.Events.Model; -using WalletConnectSharp.Sign.Models.Engine.Methods; -namespace ChainSafe.Gaming.WalletConnect +namespace ChainSafe.Gaming.Reown { [Preserve] internal class AotConfiguration @@ -26,7 +24,7 @@ void SetupAOT() Debug.Log(historyFactory.JsonRpcHistoryOfType().GetType().FullName); Debug.Log(historyFactory.JsonRpcHistoryOfType().GetType().FullName); Debug.Log(historyFactory.JsonRpcHistoryOfType().GetType().FullName); - EventManager>.InstanceOf(null).PropagateEvent(null, null); + // EventManager>.InstanceOf(null).PropagateEvent(null, null); todo there is no "Events" nuget package for Reown, this might break something throw new InvalidOperationException("This method is only for AOT code generation."); } #endif diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/AotConfiguration.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/AotConfiguration.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/AotConfiguration.cs.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/AotConfiguration.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionDialogBase.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs similarity index 95% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionDialogBase.cs rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs index dc5b43872..0b551c9c6 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionDialogBase.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs @@ -2,12 +2,11 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using ChainSafe.Gaming.WalletConnect.Connection; -using ChainSafe.Gaming.WalletConnect.Models; -using ChainSafe.Gaming.WalletConnect.Storage; +using ChainSafe.Gaming.Reown.Connection; +using ChainSafe.Gaming.Reown.Models; using UnityEngine; -namespace ChainSafe.Gaming.WalletConnect.Dialog +namespace ChainSafe.Gaming.Reown.Dialog { public abstract class ConnectionDialogBase : ConnectionHandlerBehaviour { diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionDialogBase.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionDialogBase.cs.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionDialogChainSafe.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogChainSafe.cs similarity index 97% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionDialogChainSafe.cs rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogChainSafe.cs index 0c06062fe..2900c5533 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionDialogChainSafe.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogChainSafe.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -6,7 +5,7 @@ using UnityEngine.UI; using ZXing.QrCode; -namespace ChainSafe.Gaming.WalletConnect.Dialog +namespace ChainSafe.Gaming.Reown.Dialog { public class ConnectionDialogChainSafe : ConnectionDialogBase { diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionDialogChainSafe.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogChainSafe.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionDialogChainSafe.cs.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogChainSafe.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerBehaviour.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerBehaviour.cs similarity index 74% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerBehaviour.cs rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerBehaviour.cs index 55d69c6a9..d159f2e2f 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerBehaviour.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerBehaviour.cs @@ -1,8 +1,8 @@ using System.Threading.Tasks; -using ChainSafe.Gaming.WalletConnect.Connection; +using ChainSafe.Gaming.Reown.Connection; using UnityEngine; -namespace ChainSafe.Gaming.WalletConnect.Dialog +namespace ChainSafe.Gaming.Reown.Dialog { public abstract class ConnectionHandlerBehaviour : MonoBehaviour, IConnectionHandler { diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerBehaviour.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerBehaviour.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerBehaviour.cs.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerBehaviour.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerProviderAsset.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerProviderAsset.cs new file mode 100644 index 000000000..c364046f5 --- /dev/null +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerProviderAsset.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; +using ChainSafe.Gaming.Reown.Connection; +using UnityEngine; + +namespace ChainSafe.Gaming.Reown.Dialog +{ + public abstract class ConnectionHandlerProviderAsset : ScriptableObject, IConnectionHandlerProvider + { + public abstract Task ProvideHandler(); + } +} \ No newline at end of file diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerProviderSO.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerProviderAsset.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerProviderSO.cs.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerProviderAsset.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerProviderChainSafe.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerProviderChainSafe.cs similarity index 75% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerProviderChainSafe.cs rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerProviderChainSafe.cs index b6d72e966..75fca54e7 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerProviderChainSafe.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerProviderChainSafe.cs @@ -1,15 +1,15 @@ using System.Threading.Tasks; -using ChainSafe.Gaming.WalletConnect.Connection; +using ChainSafe.Gaming.Reown.Connection; using UnityEngine; -namespace ChainSafe.Gaming.WalletConnect.Dialog +namespace ChainSafe.Gaming.Reown.Dialog { /// /// Simple version of connection handler provider. /// Lacking Pool functionality and loading from Addressables. /// - [CreateAssetMenu(menuName = "ChainSafe/WalletConnect/Connection Handler Provider", fileName = "ConnectionHandlerProvider", order = 0)] - public class ConnectionHandlerProviderChainSafe : ConnectionHandlerProviderSO + [CreateAssetMenu(menuName = "ChainSafe/Reown/Connection Handler Provider", fileName = "ConnectionHandlerProvider", order = 0)] + public class ConnectionHandlerProviderChainSafe : ConnectionHandlerProviderAsset { [SerializeField] private ConnectionHandlerBehaviour handlerPrefab; diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerProviderChainSafe.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerProviderChainSafe.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerProviderChainSafe.cs.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionHandlerProviderChainSafe.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/LocalWalletButton.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/LocalWalletButton.cs similarity index 70% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/LocalWalletButton.cs rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/LocalWalletButton.cs index dc7dc54f0..205fd0d76 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/LocalWalletButton.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/LocalWalletButton.cs @@ -1,12 +1,12 @@ using System; using System.Threading.Tasks; -using ChainSafe.Gaming.WalletConnect.Models; +using ChainSafe.Gaming.Reown.Models; using TMPro; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; -namespace ChainSafe.Gaming.WalletConnect.Dialog +namespace ChainSafe.Gaming.Reown.Dialog { public class LocalWalletButton : MonoBehaviour { @@ -28,20 +28,20 @@ public async void Set(WalletModel data, Action onClick) IconStub.gameObject.SetActive(true); Icon.gameObject.SetActive(false); - if (data.Images == null || string.IsNullOrEmpty(data.Images.SmallUrl)) - { - return; - } - - var icon = await DownloadIcon(data.Images.SmallUrl); - if (icon == null) - { - return; - } - - Icon.sprite = icon; - Icon.gameObject.SetActive(true); - IconStub.gameObject.SetActive(false); + // if (data.Images == null || string.IsNullOrEmpty(data.Images.SmallUrl)) // todo implement image downloading + // { + // return; + // } + // + // var icon = await DownloadIcon(data.Images.SmallUrl); + // if (icon == null) + // { + // return; + // } + // + // Icon.sprite = icon; + // Icon.gameObject.SetActive(true); + // IconStub.gameObject.SetActive(false); } private static async Task DownloadIcon(string url) diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/LocalWalletButton.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/LocalWalletButton.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/LocalWalletButton.cs.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/LocalWalletButton.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/QrCodeBuilder.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/QrCodeBuilder.cs similarity index 95% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/QrCodeBuilder.cs rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/QrCodeBuilder.cs index c35ffa6a4..e461cfd05 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/QrCodeBuilder.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/QrCodeBuilder.cs @@ -2,7 +2,7 @@ using ZXing; using ZXing.QrCode; -namespace ChainSafe.Gaming.WalletConnect.Dialog +namespace ChainSafe.Gaming.Reown.Dialog { public class QrCodeBuilder { diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/QrCodeBuilder.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/QrCodeBuilder.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/QrCodeBuilder.cs.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/QrCodeBuilder.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/NativeWebSocketConnectionBuilder.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/NativeWebSocketConnectionBuilder.cs similarity index 74% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/NativeWebSocketConnectionBuilder.cs rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/NativeWebSocketConnectionBuilder.cs index b42f49f63..312d3c229 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/NativeWebSocketConnectionBuilder.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/NativeWebSocketConnectionBuilder.cs @@ -1,21 +1,19 @@ - using System.Threading.Tasks; -using ChainSafe.Gaming.Evm.Unity; +using Reown.Core.Network; +using Reown.Core.Network.Interfaces; using UnityEngine; -using WalletConnectSharp.Network; -using WalletConnectSharp.Network.Interfaces; -namespace ChainSafe.Gaming.WalletConnect +namespace ChainSafe.Gaming.Reown { /// - /// This is a custom connection builder for Wallet Connect. + /// This is a custom connection builder for Reown. /// We need this because of Unity's IL2CPP build code stripping and reachability issue. /// For version 2022 and above this issue has been fixed by Unity as stated here https://blog.unity.com/engine-platform/il2cpp-full-generic-sharing-in-unity-2022-1-beta so this custom implementation isn't needed. /// public class NativeWebSocketConnectionBuilder : MonoBehaviour, IConnectionBuilder { /// - /// Create WebSocket connection for Wallet Connect. + /// Create WebSocket connection for Reown. /// /// /// Created connection. diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/NativeWebSocketConnectionBuilder.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/NativeWebSocketConnectionBuilder.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/NativeWebSocketConnectionBuilder.cs.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/NativeWebSocketConnectionBuilder.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigSO.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigAsset.cs similarity index 70% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigSO.cs rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigAsset.cs index 42f70cdc4..124dd1035 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigSO.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigAsset.cs @@ -1,35 +1,40 @@ using System.Collections.Generic; -using ChainSafe.Gaming.WalletConnect.Connection; -using ChainSafe.Gaming.WalletConnect.Dialog; +using ChainSafe.Gaming.Reown.Connection; +using ChainSafe.Gaming.Reown.Dialog; +using Reown.Core; +using Reown.Core.Network; +using Reown.Core.Network.Interfaces; using UnityEngine; -using WalletConnectSharp.Core; -using WalletConnectSharp.Network.Interfaces; -namespace ChainSafe.Gaming.WalletConnect +namespace ChainSafe.Gaming.Reown { - [CreateAssetMenu(menuName = "ChainSafe/WalletConnect/WalletConnect Config", fileName = "WalletConnectConfig", order = 0)] - public class WalletConnectConfigSO : ScriptableObject, IWalletConnectConfig + [CreateAssetMenu(menuName = "ChainSafe/Reown/Reown Config", fileName = "ReownConfig", order = 0)] + public class ReownConfigAsset : ScriptableObject, IReownConfig { public string SignMessageRpcMethodName => "personal_sign"; public string SignTypedMessageRpcMethodName => "eth_signTypedData"; + [SerializeField] private List includeWalletIds; + [SerializeField] private List excludeWalletIds; + [field: SerializeField] public bool AutoRenewSession { get; set; } = true; [field: SerializeField] public string ProjectName { get; set; } [field: SerializeField] public string ProjectId { get; set; } [field: SerializeField] public string BaseContext { get; set; } = "unity-game"; [field: SerializeField] public Metadata Metadata { get; set; } + [field: SerializeField] public string StoragePath { get; set; } = "wallet-connect/"; [field: SerializeField] public string OverrideRegistryUri { get; set; } - [field: SerializeField] public WalletConnectLogLevel LogLevel { get; set; } = WalletConnectLogLevel.ErrorOnly; - [SerializeField] private List enabledWallets; - [SerializeField] private List disabledWallets; - [SerializeField] private ConnectionHandlerProviderSO connectionHandlerProvider; + [field: SerializeField] public ReownLogLevel LogLevel { get; set; } = ReownLogLevel.ErrorOnly; + [SerializeField] private ConnectionHandlerProviderAsset connectionHandlerProvider; [field: SerializeField] public WalletLocationOption WalletLocationOption { get; set; } public bool RememberSession { get; set; } public bool ForceNewSession { get; set; } - public IList EnabledWallets => enabledWallets; - public IList DisabledWallets => disabledWallets; + public IRelayUrlBuilder RelayUrlBuilder => null; // todo; + + public IList IncludeWalletIds => includeWalletIds; + public IList ExcludeWalletIds => excludeWalletIds; public IConnectionHandlerProvider ConnectionHandlerProvider => connectionHandlerProvider; private IConnectionBuilder connectionBuilder; diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigSO.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigAsset.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigSO.cs.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigAsset.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs new file mode 100644 index 000000000..482d908ca --- /dev/null +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs @@ -0,0 +1,19 @@ +using ChainSafe.Gaming.UnityPackage.Connection; + +namespace ChainSafe.Gaming.Reown +{ + public static class ReownConfigExtensions + { + /// + /// Sets property of this config object. + /// + /// The config object. + /// New value for ForceNewSession property. + /// Updated object. + public static ReownConnectionProvider WithForceNewSession(this ReownConnectionProvider provider, bool forceNewSession) + { + provider.ForceNewSession = forceNewSession; + return provider; + } + } +} \ No newline at end of file diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigExtensions.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigExtensions.cs.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectWeb3.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownWeb3.cs similarity index 60% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectWeb3.cs rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownWeb3.cs index fba83c645..329dd37e8 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectWeb3.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownWeb3.cs @@ -1,25 +1,24 @@ using System.Threading.Tasks; -using ChainSafe.Gaming.EVM.Events; using ChainSafe.Gaming.Evm.JsonRpc; using ChainSafe.Gaming.UnityPackage; using ChainSafe.Gaming.Web3; using ChainSafe.Gaming.Web3.Build; using ChainSafe.Gaming.Web3.Unity; -namespace ChainSafe.Gaming.WalletConnect +namespace ChainSafe.Gaming.Reown { /// - /// Helper class to build preconfigured Web3 clients for WalletConnect. + /// Helper class to build preconfigured Web3 clients for Reown. /// - public static class WalletConnectWeb3 + public static class ReownWeb3 { /// - /// Builds a lightweight Web3 client with basic WalletConnect functionality. + /// Builds a lightweight Web3 client with basic Reown functionality. /// - /// Your WalletConnect config. + /// Your Reown config. /// ChainSafe SDK project configuration (optional). - /// A lightweight version of Web3 client with basic WalletConnect functionality. - public static ValueTask BuildLightweightWeb3(IWalletConnectConfig wcConfig, ICompleteProjectConfig projectConfig = null) + /// A lightweight version of Web3 client with basic Reown functionality. + public static ValueTask BuildLightweightWeb3(IReownConfig reownConfig, ICompleteProjectConfig projectConfig = null) { projectConfig ??= ProjectConfigUtilities.Load(); @@ -27,7 +26,7 @@ public static class WalletConnectWeb3 { services.UseUnityEnvironment(); services.UseRpcProvider(); - services.UseWalletConnect(wcConfig); + services.UseReown(reownConfig); }).LaunchAsync(); } } diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectWeb3.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownWeb3.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectWeb3.cs.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownWeb3.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WebSocketConnection.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/WebSocketConnection.cs similarity index 90% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WebSocketConnection.cs rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/WebSocketConnection.cs index f5ac9d18b..f19745ba9 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WebSocketConnection.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/WebSocketConnection.cs @@ -1,25 +1,18 @@ - using System; using System.IO; -using System.Text; using System.Threading.Tasks; using ChainSafe.Gaming.Evm.Unity; using NativeWebSocket; using Newtonsoft.Json; -using UnityEngine; -using WalletConnectSharp.Common; -using WalletConnectSharp.Common.Logging; -using WalletConnectSharp.Common.Utils; -using WalletConnectSharp.Events; -using WalletConnectSharp.Events.Model; -using WalletConnectSharp.Network; -using WalletConnectSharp.Network.Models; -using WalletConnectSharp.Network.Websocket; - -namespace ChainSafe.Gaming.WalletConnect +using Reown.Core.Common; +using Reown.Core.Common.Logging; +using Reown.Core.Network; +using Reown.Core.Network.Models; + +namespace ChainSafe.Gaming.Reown { /// - /// Custom web socket implementation for Wallet Connect, based on NativeWebSocket https://github.com/endel/NativeWebSocket. + /// Custom web socket implementation for Reown, based on NativeWebSocket https://github.com/endel/NativeWebSocket. /// public class WebSocketConnection : IJsonRpcConnection, IModule { @@ -88,7 +81,7 @@ async Task IJsonRpcConnection.Close() if (_disposed) throw new ObjectDisposedException(nameof(WebSocketConnection)); - WCLogger.Log("Closing websocket due to Close() being called"); + ReownLogger.Log("Closing websocket due to Close() being called"); await _socket.Close(); OnClose(WebSocketCloseCode.Normal); @@ -105,7 +98,7 @@ async Task IJsonRpcConnection.SendRequest(IJsonRpcRequest requestPayload, try { var json = JsonConvert.SerializeObject(requestPayload); - WCLogger.Log($"[WebSocketConnection-{Context}] Sending request {json}"); + ReownLogger.Log($"[WebSocketConnection-{Context}] Sending request {json}"); await _socket.SendText(json); @@ -206,7 +199,7 @@ private void OnMessage(byte[] data) { var json = System.Text.Encoding.UTF8.GetString(data); - WCLogger.Log($"[WebSocketConnection-{Context}] Got payload: \n{json}"); + ReownLogger.Log($"[WebSocketConnection-{Context}] Got payload: \n{json}"); if (string.IsNullOrWhiteSpace(json)) return; @@ -225,7 +218,7 @@ private void OnDisconnect(WebSocketCloseCode obj) private void OnError(string message) { ErrorReceived?.Invoke(this, new Exception(message)); - WCLogger.LogError(Connecting + ReownLogger.LogError(Connecting ? $"[{Name}-{Context}] Error happened during connection. Make sure Project ID is valid. Error message: {message}" : $"[{Name}-{Context}] Error: {message}"); } @@ -247,7 +240,7 @@ private void OnError(IJsonRpcPayload ogPayload, Exception e) PayloadReceived?.Invoke(this, json); } - WCLogger.LogError(e); + ReownLogger.LogError(e); } private void OnClose(WebSocketCloseCode obj) diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WebSocketConnection.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/WebSocketConnection.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WebSocketConnection.cs.meta rename to Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/WebSocketConnection.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerProviderSO.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerProviderSO.cs deleted file mode 100644 index 9d880667c..000000000 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/Dialog/ConnectionHandlerProviderSO.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Threading.Tasks; -using ChainSafe.Gaming.WalletConnect.Connection; -using UnityEngine; - -namespace ChainSafe.Gaming.WalletConnect.Dialog -{ - public abstract class ConnectionHandlerProviderSO : ScriptableObject, IConnectionHandlerProvider - { - public abstract Task ProvideHandler(); - } -} \ No newline at end of file diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigExtensions.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigExtensions.cs deleted file mode 100644 index ffc63ac3f..000000000 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using ChainSafe.Gaming.UnityPackage.Connection; -using UnityEngine; - -namespace ChainSafe.Gaming.WalletConnect -{ - public static class WalletConnectConfigExtensions - { - /// - /// Sets property of this config object. - /// - /// The config object. - /// New value for ForceNewSession property. - /// Updated object. - public static WalletConnectConnectionProvider WithForceNewSession(this WalletConnectConnectionProvider provider, bool forceNewSession) - { - provider.ForceNewSession = forceNewSession; - return provider; - } - } -} \ No newline at end of file diff --git a/Packages/io.chainsafe.web3-unity/Tests/Runtime/EvmCustomResponseTests.cs b/Packages/io.chainsafe.web3-unity/Tests/Runtime/EvmCustomResponseTests.cs index b7e303344..b61140bee 100644 --- a/Packages/io.chainsafe.web3-unity/Tests/Runtime/EvmCustomResponseTests.cs +++ b/Packages/io.chainsafe.web3-unity/Tests/Runtime/EvmCustomResponseTests.cs @@ -177,7 +177,7 @@ private IEnumerator BuildWeb3WithTestResponse(string testResponse) { var buildWeb3Task = SampleTestsBase.BuildTestWeb3(services => { - services.Replace(ServiceDescriptor.Singleton(new StubWalletConnectProviderConfig + services.Replace(ServiceDescriptor.Singleton(new StubReownConfig { StubResponse = testResponse })); }); diff --git a/Packages/io.chainsafe.web3-unity/Tests/Runtime/SampleTestsBase.cs b/Packages/io.chainsafe.web3-unity/Tests/Runtime/SampleTestsBase.cs index 1ef2a3b8d..ae68f9988 100644 --- a/Packages/io.chainsafe.web3-unity/Tests/Runtime/SampleTestsBase.cs +++ b/Packages/io.chainsafe.web3-unity/Tests/Runtime/SampleTestsBase.cs @@ -5,7 +5,6 @@ using ChainSafe.Gaming.Evm.JsonRpc; using ChainSafe.Gaming.MultiCall; using ChainSafe.Gaming.UnityPackage; -using ChainSafe.Gaming.WalletConnect; using ChainSafe.Gaming.Web3; using ChainSafe.Gaming.Web3.Build; using ChainSafe.Gaming.Web3.Evm.Wallet; @@ -64,9 +63,9 @@ internal static ValueTask BuildTestWeb3(Web3Builder.ConfigureServicesDeleg services.UseMultiCall(); services.UseRpcProvider(); - var config = new StubWalletConnectProviderConfig(); + var config = new StubReownConfig(); services.AddSingleton(config); // can be replaced - services.UseWalletProvider(config); + services.UseWalletProvider(config); services.UseWalletSigner(); services.UseWalletTransactionExecutor(); services.UseEvents(); diff --git a/Packages/io.chainsafe.web3-unity/Tests/Runtime/StubWalletConnectProviderConfig.cs b/Packages/io.chainsafe.web3-unity/Tests/Runtime/StubReownConfig.cs similarity index 89% rename from Packages/io.chainsafe.web3-unity/Tests/Runtime/StubWalletConnectProviderConfig.cs rename to Packages/io.chainsafe.web3-unity/Tests/Runtime/StubReownConfig.cs index ab0ed0823..a7d25d3d7 100644 --- a/Packages/io.chainsafe.web3-unity/Tests/Runtime/StubWalletConnectProviderConfig.cs +++ b/Packages/io.chainsafe.web3-unity/Tests/Runtime/StubReownConfig.cs @@ -2,7 +2,7 @@ namespace Tests.Runtime { - public class StubWalletConnectProviderConfig : IWalletProviderConfig + public class StubReownConfig : IWalletProviderConfig { public const string DefaultWalletAddress = "0x55ffe9E30347266f02b9BdAe20aD3a86493289ea"; public const string DefaultProjectId = "f4bff60eb260841f46b1c77588cd8acb"; diff --git a/Packages/io.chainsafe.web3-unity/Tests/Runtime/StubWalletConnectProviderConfig.cs.meta b/Packages/io.chainsafe.web3-unity/Tests/Runtime/StubReownConfig.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Tests/Runtime/StubWalletConnectProviderConfig.cs.meta rename to Packages/io.chainsafe.web3-unity/Tests/Runtime/StubReownConfig.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Tests/Runtime/StubWalletConnectProvider.cs b/Packages/io.chainsafe.web3-unity/Tests/Runtime/StubReownProvider.cs similarity index 83% rename from Packages/io.chainsafe.web3-unity/Tests/Runtime/StubWalletConnectProvider.cs rename to Packages/io.chainsafe.web3-unity/Tests/Runtime/StubReownProvider.cs index 26857b6cd..0fa0dc96a 100644 --- a/Packages/io.chainsafe.web3-unity/Tests/Runtime/StubWalletConnectProvider.cs +++ b/Packages/io.chainsafe.web3-unity/Tests/Runtime/StubReownProvider.cs @@ -9,13 +9,13 @@ namespace Tests.Runtime { - public class StubWalletConnectProvider : WalletProvider + public class StubReownProvider : WalletProvider { - private readonly StubWalletConnectProviderConfig config; + private readonly StubReownConfig config; private readonly IChainConfig chainConfig; private readonly IHttpClient httpClient; - public StubWalletConnectProvider(StubWalletConnectProviderConfig config, Web3Environment environment, IChainConfig chainConfig) : base(environment, chainConfig) + public StubReownProvider(StubReownConfig config, Web3Environment environment, IChainConfig chainConfig) : base(environment, chainConfig) { this.config = config; this.chainConfig = chainConfig; @@ -42,7 +42,7 @@ public override async Task Request(string method, params object[] paramete case "eth_sendTransaction": return (T)Convert.ChangeType(config.StubResponse, typeof(T)); default: - // Direct RPC request via WalletConnect RPC url. + // Direct RPC request via Reown RPC url. // Using WalletConnect Blockchain API: https://docs.walletconnect.com/cloud/blockchain-api var url = $"https://rpc.walletconnect.com/v1?chainId=eip155:{chainConfig.ChainId}&projectId={config.ProjectId}"; diff --git a/Packages/io.chainsafe.web3-unity/Tests/Runtime/StubWalletConnectProvider.cs.meta b/Packages/io.chainsafe.web3-unity/Tests/Runtime/StubReownProvider.cs.meta similarity index 100% rename from Packages/io.chainsafe.web3-unity/Tests/Runtime/StubWalletConnectProvider.cs.meta rename to Packages/io.chainsafe.web3-unity/Tests/Runtime/StubReownProvider.cs.meta diff --git a/Packages/io.chainsafe.web3-unity/Tests/Runtime/chainsafe.web3-unity.RuntimeTests.asmdef b/Packages/io.chainsafe.web3-unity/Tests/Runtime/chainsafe.web3-unity.RuntimeTests.asmdef index 017811d11..46a5d29c2 100644 --- a/Packages/io.chainsafe.web3-unity/Tests/Runtime/chainsafe.web3-unity.RuntimeTests.asmdef +++ b/Packages/io.chainsafe.web3-unity/Tests/Runtime/chainsafe.web3-unity.RuntimeTests.asmdef @@ -18,9 +18,9 @@ "ChainSafe.Gaming.dll", "ChainSafe.Gaming.Unity.dll", "ChainSafe.Gaming.Gelato.dll", - "ChainSafe.Gaming.WalletConnect.dll", "Nethereum.RPC.dll", - "Newtonsoft.Json.dll" + "Newtonsoft.Json.dll", + "ChainSafe.Gaming.Reown.dll" ], "autoReferenced": false, "defineConstraints": [ diff --git a/scripts/data/published_dependencies.txt b/scripts/data/published_dependencies.txt index 44cf01d1f..76ede2175 100644 --- a/scripts/data/published_dependencies.txt +++ b/scripts/data/published_dependencies.txt @@ -18,7 +18,6 @@ Packages/io.chainsafe.web3-unity/Runtime/Libraries/: Nethereum.Web3 ChainSafe.Gaming.Unity System.Buffers - ChainSafe.Gaming.WalletConnect System.Memory ChainSafe.Gaming System.Numerics.Vectors @@ -39,24 +38,14 @@ Packages/io.chainsafe.web3-unity/Runtime/Libraries/: NBitcoin System.Threading.Tasks.Extensions Nethereum.ABI - WalletConnectSharp.Auth Nethereum.Accounts - WalletConnectSharp.Common - WalletConnectSharp.Events Nethereum.BlockchainProcessing - WalletConnectSharp.Core Nethereum.Contracts - WalletConnectSharp.Crypto Nethereum.Hex Nethereum.JsonRpc.Client - WalletConnectSharp.Network.Websocket - WalletConnectSharp.Network Nethereum.JsonRpc.RpcClient - WalletConnectSharp.Sign Nethereum.KeyStore - WalletConnectSharp.Storage Nethereum.Merkle.Patricia - WalletConnectSharp.Web3Wallet Nethereum.Merkle Websocket.Client Nethereum.Siwe.Core @@ -65,6 +54,15 @@ Packages/io.chainsafe.web3-unity/Runtime/Libraries/: ChainSafe.Gaming.Unity.MetaMask ChainSafe.Gaming.Marketplace ChainSafe.Gaming.Unity.EthereumWindow + ChainSafe.Gaming.Reown + Reown.Core + Reown.Core.Common + Reown.Core.Crypto + Reown.Core.Network + Reown.Core.Network.WebSocket + Reown.Core.Storage + Reown.Sign + Reown.WalletKit Packages/io.chainsafe.web3-unity.lootboxes/Chainlink/Runtime/Libraries/: Chainsafe.Gaming.Chainlink ChainSafe.Gaming.Lootboxes.Chainlink diff --git a/src/ChainSafe.Gaming.InProcessTransactionExecutor/InProcessTransactionExecutor.cs b/src/ChainSafe.Gaming.InProcessTransactionExecutor/InProcessTransactionExecutor.cs index 6a86f2e4b..2e887876c 100644 --- a/src/ChainSafe.Gaming.InProcessTransactionExecutor/InProcessTransactionExecutor.cs +++ b/src/ChainSafe.Gaming.InProcessTransactionExecutor/InProcessTransactionExecutor.cs @@ -36,8 +36,7 @@ public InProcessTransactionExecutor(IAccountProvider accountProvider, IRpcProvid /// /// Implementation of . - /// Send a transaction using Wallet Connect. - /// This prompts user to approve a transaction on a connected wallet. + /// Sends a transaction. /// /// Transaction to send. /// Hash response of a successfully executed transaction. diff --git a/src/ChainSafe.Gaming.NetCore/NetCoreHttpClient.cs b/src/ChainSafe.Gaming.NetCore/NetCoreHttpClient.cs index a666b4b5d..37559beba 100644 --- a/src/ChainSafe.Gaming.NetCore/NetCoreHttpClient.cs +++ b/src/ChainSafe.Gaming.NetCore/NetCoreHttpClient.cs @@ -1,9 +1,9 @@ -using System.IO; -using System.Net.Http; +using System.Net.Http; +using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; using ChainSafe.Gaming.Web3.Environment; -using Newtonsoft.Json; +using ChainSafe.Gaming.Web3.Environment.Http; namespace ChainSafe.Gaming.NetCore { @@ -22,68 +22,49 @@ public NetCoreHttpClient() originalClient = new HttpClient(); } - private static async ValueTask> ResponseToNetworkResponse(HttpResponseMessage response) + public async ValueTask> GetRaw(string url, params HttpHeader[] headers) { - if (response.IsSuccessStatusCode) - { - return NetworkResponse.Success(await response.Content.ReadAsStringAsync()); - } - else + var request = new HttpRequestMessage(HttpMethod.Get, url); + request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + + foreach (var header in headers) { - return NetworkResponse.Failure($"{response.StatusCode}: {await response.Content.ReadAsStringAsync()}"); + request.Headers.Add(header.Name, header.Value); } - } - /// - /// Get Raw response from http request with a GET method. - /// - /// Url of request to be made. - /// Raw response to the request. - public async ValueTask> GetRaw(string url) - { - var response = await originalClient.GetAsync(url); + var response = await originalClient.SendAsync(request); return await ResponseToNetworkResponse(response); } - /// - /// Get Raw response from http request with a POST method. - /// - /// Url of request to be made. - /// Request data/body. - /// Content type request header. - /// Raw response to the request. - public async ValueTask> PostRaw(string url, string data, string contentType) + public async ValueTask> PostRaw( + string url, + string data, + string contentType, + params HttpHeader[] headers) { - var requestContent = new StringContent(data, Encoding.UTF8, contentType); - var response = await originalClient.PostAsync(url, requestContent); - return await ResponseToNetworkResponse(response); - } + var request = new HttpRequestMessage(HttpMethod.Post, url); + request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - /// - /// Get response as from http request with a GET method. - /// - /// Url of request to be made. - /// Response body model type. - /// Response as a . - public async ValueTask> Get(string url) - { - var response = await GetRaw(url); - return response.Map(x => JsonConvert.DeserializeObject(x)); + foreach (var header in headers) + { + request.Headers.Add(header.Name, header.Value); + } + + request.Content = new StringContent(data, Encoding.UTF8, contentType); + var response = await originalClient.SendAsync(request); + return await ResponseToNetworkResponse(response); } - /// - /// Get response as from http request with a GET method. - /// - /// Url of request to be made. - /// Request data/body. - /// Request data/body model type. - /// Response data/body type. - /// Response as a . - public async ValueTask> Post(string url, TRequest data) + private static async ValueTask> ResponseToNetworkResponse(HttpResponseMessage response) { - var requestJson = JsonConvert.SerializeObject(data); - var response = await PostRaw(url, requestJson, "application/json"); - return response.Map(x => JsonConvert.DeserializeObject(x)); + if (response.IsSuccessStatusCode) + { + return NetworkResponse.Success(await response.Content.ReadAsStringAsync()); + } + else + { + return NetworkResponse.Failure($"{response.StatusCode}: {await response.Content.ReadAsStringAsync()}"); + } } } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/ChainSafe.Gaming.WalletConnect.csproj b/src/ChainSafe.Gaming.Reown/ChainSafe.Gaming.Reown.csproj similarity index 74% rename from src/ChainSafe.Gaming.WalletConnect/ChainSafe.Gaming.WalletConnect.csproj rename to src/ChainSafe.Gaming.Reown/ChainSafe.Gaming.Reown.csproj index cb6b3a307..526176303 100644 --- a/src/ChainSafe.Gaming.WalletConnect/ChainSafe.Gaming.WalletConnect.csproj +++ b/src/ChainSafe.Gaming.Reown/ChainSafe.Gaming.Reown.csproj @@ -3,7 +3,7 @@ netstandard2.1 9.0 - ChainSafe.Gaming.WalletConnect + ChainSafe.Gaming.Reown True ../../global.ruleset Debug;Release;Test @@ -16,8 +16,7 @@ - - + diff --git a/src/ChainSafe.Gaming.WalletConnect/Connection/ConnectionHandlerConfig.cs b/src/ChainSafe.Gaming.Reown/Connection/ConnectionHandlerConfig.cs similarity index 94% rename from src/ChainSafe.Gaming.WalletConnect/Connection/ConnectionHandlerConfig.cs rename to src/ChainSafe.Gaming.Reown/Connection/ConnectionHandlerConfig.cs index 5aded5eff..4dc1ef611 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Connection/ConnectionHandlerConfig.cs +++ b/src/ChainSafe.Gaming.Reown/Connection/ConnectionHandlerConfig.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -using ChainSafe.Gaming.WalletConnect.Models; +using ChainSafe.Gaming.Reown.Models; -namespace ChainSafe.Gaming.WalletConnect.Connection +namespace ChainSafe.Gaming.Reown.Connection { /// /// The config object class used to configure the . diff --git a/src/ChainSafe.Gaming.WalletConnect/Connection/IConnectionHandler.cs b/src/ChainSafe.Gaming.Reown/Connection/IConnectionHandler.cs similarity index 87% rename from src/ChainSafe.Gaming.WalletConnect/Connection/IConnectionHandler.cs rename to src/ChainSafe.Gaming.Reown/Connection/IConnectionHandler.cs index 3befea056..7ed15a675 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Connection/IConnectionHandler.cs +++ b/src/ChainSafe.Gaming.Reown/Connection/IConnectionHandler.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -namespace ChainSafe.Gaming.WalletConnect.Connection +namespace ChainSafe.Gaming.Reown.Connection { /// /// Connection handler used to choose a wallet when connecting a new session. diff --git a/src/ChainSafe.Gaming.WalletConnect/Connection/IConnectionHandlerProvider.cs b/src/ChainSafe.Gaming.Reown/Connection/IConnectionHandlerProvider.cs similarity index 81% rename from src/ChainSafe.Gaming.WalletConnect/Connection/IConnectionHandlerProvider.cs rename to src/ChainSafe.Gaming.Reown/Connection/IConnectionHandlerProvider.cs index fad6eb33e..a170c8027 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Connection/IConnectionHandlerProvider.cs +++ b/src/ChainSafe.Gaming.Reown/Connection/IConnectionHandlerProvider.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -namespace ChainSafe.Gaming.WalletConnect.Connection +namespace ChainSafe.Gaming.Reown.Connection { /// /// Provider of . diff --git a/src/ChainSafe.Gaming.WalletConnect/Delegates.cs b/src/ChainSafe.Gaming.Reown/Delegates.cs similarity index 82% rename from src/ChainSafe.Gaming.WalletConnect/Delegates.cs rename to src/ChainSafe.Gaming.Reown/Delegates.cs index f500ecdd2..d48f8572f 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Delegates.cs +++ b/src/ChainSafe.Gaming.Reown/Delegates.cs @@ -1,4 +1,4 @@ -namespace ChainSafe.Gaming.WalletConnect +namespace ChainSafe.Gaming.Reown { /// /// Delegate used to redirect user to one of the locally installed wallets. diff --git a/src/ChainSafe.Gaming.WalletConnect/IConnectionHelper.cs b/src/ChainSafe.Gaming.Reown/IConnectionHelper.cs similarity index 74% rename from src/ChainSafe.Gaming.WalletConnect/IConnectionHelper.cs rename to src/ChainSafe.Gaming.Reown/IConnectionHelper.cs index 4fafe1499..4f8411421 100644 --- a/src/ChainSafe.Gaming.WalletConnect/IConnectionHelper.cs +++ b/src/ChainSafe.Gaming.Reown/IConnectionHelper.cs @@ -1,7 +1,7 @@ -namespace ChainSafe.Gaming.WalletConnect +namespace ChainSafe.Gaming.Reown { /// - /// Helper class for the WalletConnect login procedure. + /// Helper class for the Reown login procedure. /// public interface IConnectionHelper { diff --git a/src/ChainSafe.Gaming.WalletConnect/IWalletConnectConfig.cs b/src/ChainSafe.Gaming.Reown/IReownConfig.cs similarity index 64% rename from src/ChainSafe.Gaming.WalletConnect/IWalletConnectConfig.cs rename to src/ChainSafe.Gaming.Reown/IReownConfig.cs index 5269fbf99..2f945c7cc 100644 --- a/src/ChainSafe.Gaming.WalletConnect/IWalletConnectConfig.cs +++ b/src/ChainSafe.Gaming.Reown/IReownConfig.cs @@ -1,16 +1,18 @@ #nullable enable using System.Collections.Generic; -using ChainSafe.Gaming.WalletConnect.Connection; +using ChainSafe.Gaming.Reown.Connection; +using ChainSafe.Gaming.Web3.Environment; using ChainSafe.Gaming.Web3.Evm.Wallet; -using WalletConnectSharp.Core; -using WalletConnectSharp.Network.Interfaces; +using Reown.Core; +using Reown.Core.Network; +using Reown.Core.Network.Interfaces; -namespace ChainSafe.Gaming.WalletConnect +namespace ChainSafe.Gaming.Reown { /// - /// Interface for WalletConnect configuration. + /// Interface for Reown configuration. /// - public interface IWalletConnectConfig : IWalletProviderConfig + public interface IReownConfig : IWalletProviderConfig { /// /// Set to true if you want to store this session on a disk for the next time. @@ -33,50 +35,31 @@ public interface IWalletConnectConfig : IWalletProviderConfig string ProjectName { get; } /// - /// Project ID provided to you by WalletConnect. + /// Project ID provided to you by Reown. /// string ProjectId { get; } /// - /// Name of the context to be used by WalletConnect. + /// Name of the context to be used by Reown. /// string BaseContext { get; } /// - /// Used to set custom to support Unity versions before 2022.1. - /// - IConnectionBuilder ConnectionBuilder { get; } - - /// - /// WalletConnect metadata. + /// Reown metadata. /// Metadata Metadata { get; } - /// - /// Relative path to folder where storage files should be place. - /// - /// The path is relative to the app's data folder. - string StoragePath { get; } - /// /// List of the wallets that you want to show to your user as local wallet connect options. /// Keep this empty to enable all of the wallets supported for the platform. /// - /// - /// Use either or . - /// If both are provided will be ignored. - /// - IList? EnabledWallets { get; } + IList? IncludeWalletIds { get; } /// /// List of the wallets that you want to disable. - /// Disabled wallet won't be shown to the user as local connect options. + /// Disabled wallet won't be shown to the user as local connect option. /// - /// - /// Use either or . - /// If both are provided will be ignored. - /// - IList? DisabledWallets { get; } + IList? ExcludeWalletIds { get; } /// /// Use this to set Local, Remote or Both wallet connection options for the user. @@ -91,10 +74,23 @@ public interface IWalletConnectConfig : IWalletProviderConfig IConnectionHandlerProvider ConnectionHandlerProvider { get; } /// - /// Override for the registry URI used to download the list of wallets supported by WalletConnect. + /// Override for the registry URI used to download the list of wallets supported by Reown. /// string? OverrideRegistryUri { get; } - WalletConnectLogLevel LogLevel { get; } + /// + /// Configure log level filter for Reown logs. + /// + ReownLogLevel LogLevel { get; } + + /// + /// I honestly don't know what this is for. + /// + IRelayUrlBuilder RelayUrlBuilder { get; } + + /// + /// Used to set custom to support Unity versions before 2022.1. + /// + IConnectionBuilder ConnectionBuilder { get; } } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs b/src/ChainSafe.Gaming.Reown/Methods/EthSendTransaction.cs similarity index 84% rename from src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs rename to src/ChainSafe.Gaming.Reown/Methods/EthSendTransaction.cs index 3b87f2235..ee769d09f 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs +++ b/src/ChainSafe.Gaming.Reown/Methods/EthSendTransaction.cs @@ -1,14 +1,14 @@ using System; using System.Collections.Generic; -using ChainSafe.Gaming.WalletConnect.Models; +using ChainSafe.Gaming.Reown.Models; using Nethereum.RPC.Eth.DTOs; -using WalletConnectSharp.Common.Utils; -using WalletConnectSharp.Network.Models; +using Reown.Core.Common.Utils; +using Reown.Core.Network.Models; -namespace ChainSafe.Gaming.WalletConnect.Methods +namespace ChainSafe.Gaming.Reown.Methods { /// - /// Send Transaction Wallet Connect Json RPC method params. + /// Send Transaction Reown Json RPC method params. /// [RpcMethod("eth_sendTransaction")] [RpcRequestOptions(Clock.ONE_MINUTE, 99999)] diff --git a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignMessage.cs b/src/ChainSafe.Gaming.Reown/Methods/EthSignMessage.cs similarity index 82% rename from src/ChainSafe.Gaming.WalletConnect/Methods/EthSignMessage.cs rename to src/ChainSafe.Gaming.Reown/Methods/EthSignMessage.cs index 8726ebbfd..72e8df274 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignMessage.cs +++ b/src/ChainSafe.Gaming.Reown/Methods/EthSignMessage.cs @@ -1,11 +1,11 @@ using System.Collections.Generic; -using WalletConnectSharp.Common.Utils; -using WalletConnectSharp.Network.Models; +using Reown.Core.Common.Utils; +using Reown.Core.Network.Models; -namespace ChainSafe.Gaming.WalletConnect.Methods +namespace ChainSafe.Gaming.Reown.Methods { /// - /// Sign message Wallet Connect Json RPC method params. + /// Sign message Reown Json RPC method params. /// [RpcMethod("personal_sign")] [RpcRequestOptions(Clock.ONE_MINUTE, 99997)] diff --git a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTransaction.cs b/src/ChainSafe.Gaming.Reown/Methods/EthSignTransaction.cs similarity index 77% rename from src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTransaction.cs rename to src/ChainSafe.Gaming.Reown/Methods/EthSignTransaction.cs index 01c08682d..95bce9039 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTransaction.cs +++ b/src/ChainSafe.Gaming.Reown/Methods/EthSignTransaction.cs @@ -1,12 +1,12 @@ using System.Collections.Generic; -using ChainSafe.Gaming.WalletConnect.Models; -using WalletConnectSharp.Common.Utils; -using WalletConnectSharp.Network.Models; +using ChainSafe.Gaming.Reown.Models; +using Reown.Core.Common.Utils; +using Reown.Core.Network.Models; -namespace ChainSafe.Gaming.WalletConnect.Methods +namespace ChainSafe.Gaming.Reown.Methods { /// - /// Sign Transaction Wallet Connect Json RPC method params. + /// Sign Transaction Reown Json RPC method params. /// [RpcMethod("eth_signTransaction")] [RpcRequestOptions(Clock.ONE_MINUTE, 99996)] diff --git a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTypedData.cs b/src/ChainSafe.Gaming.Reown/Methods/EthSignTypedData.cs similarity index 80% rename from src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTypedData.cs rename to src/ChainSafe.Gaming.Reown/Methods/EthSignTypedData.cs index e2da8bf78..a5bc26237 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTypedData.cs +++ b/src/ChainSafe.Gaming.Reown/Methods/EthSignTypedData.cs @@ -1,12 +1,11 @@ using System.Collections.Generic; -using ChainSafe.Gaming.Web3.Core.Evm; -using WalletConnectSharp.Common.Utils; -using WalletConnectSharp.Network.Models; +using Reown.Core.Common.Utils; +using Reown.Core.Network.Models; -namespace ChainSafe.Gaming.WalletConnect.Methods +namespace ChainSafe.Gaming.Reown.Methods { /// - /// Sign Typed Data Wallet Connect Json RPC method params. + /// Sign Typed Data Reown Json RPC method params. /// [RpcMethod("eth_signTypedData")] [RpcRequestOptions(Clock.ONE_MINUTE, 99998)] diff --git a/src/ChainSafe.Gaming.WalletConnect/Methods/WalletSwitchEthereumChain.cs b/src/ChainSafe.Gaming.Reown/Methods/WalletSwitchEthereumChain.cs similarity index 82% rename from src/ChainSafe.Gaming.WalletConnect/Methods/WalletSwitchEthereumChain.cs rename to src/ChainSafe.Gaming.Reown/Methods/WalletSwitchEthereumChain.cs index de58f7500..412c0a1af 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Methods/WalletSwitchEthereumChain.cs +++ b/src/ChainSafe.Gaming.Reown/Methods/WalletSwitchEthereumChain.cs @@ -1,11 +1,11 @@ using System.Collections.Generic; -using WalletConnectSharp.Common.Utils; -using WalletConnectSharp.Network.Models; +using Reown.Core.Common.Utils; +using Reown.Core.Network.Models; -namespace ChainSafe.Gaming.WalletConnect.Methods +namespace ChainSafe.Gaming.Reown.Methods { /// - /// Switch Ethereum Chain Wallet Connect Json RPC method params. + /// Switch Ethereum Chain Reown Json RPC method params. /// [RpcMethod("wallet_switchEthereumChain")] [RpcRequestOptions(Clock.ONE_MINUTE, 99995)] diff --git a/src/ChainSafe.Gaming.WalletConnect/Models/ChainModel.cs b/src/ChainSafe.Gaming.Reown/Models/ChainModel.cs similarity index 92% rename from src/ChainSafe.Gaming.WalletConnect/Models/ChainModel.cs rename to src/ChainSafe.Gaming.Reown/Models/ChainModel.cs index 1111b1f19..99abbcf6a 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Models/ChainModel.cs +++ b/src/ChainSafe.Gaming.Reown/Models/ChainModel.cs @@ -1,7 +1,7 @@ -namespace ChainSafe.Gaming.WalletConnect.Models +namespace ChainSafe.Gaming.Reown.Models { /// - /// Chain model containing fields used for Wallet Connect. + /// Chain model containing fields used for Reown. /// public class ChainModel { diff --git a/src/ChainSafe.Gaming.WalletConnect/Models/ImageUrlsModel.cs b/src/ChainSafe.Gaming.Reown/Models/ImageUrlsModel.cs similarity index 81% rename from src/ChainSafe.Gaming.WalletConnect/Models/ImageUrlsModel.cs rename to src/ChainSafe.Gaming.Reown/Models/ImageUrlsModel.cs index 36a943e12..bd01ff2b7 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Models/ImageUrlsModel.cs +++ b/src/ChainSafe.Gaming.Reown/Models/ImageUrlsModel.cs @@ -1,9 +1,9 @@ using Newtonsoft.Json; -namespace ChainSafe.Gaming.WalletConnect.Models +namespace ChainSafe.Gaming.Reown.Models { /// - /// Wallet Connect Model used in for Wallet's image url if any. + /// Reown Model used in for Wallet's image url if any. /// public class ImageUrlsModel { diff --git a/src/ChainSafe.Gaming.WalletConnect/Models/TransactionModel.cs b/src/ChainSafe.Gaming.Reown/Models/TransactionModel.cs similarity index 87% rename from src/ChainSafe.Gaming.WalletConnect/Models/TransactionModel.cs rename to src/ChainSafe.Gaming.Reown/Models/TransactionModel.cs index 31673cfc2..41a726dfd 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Models/TransactionModel.cs +++ b/src/ChainSafe.Gaming.Reown/Models/TransactionModel.cs @@ -1,9 +1,9 @@ using Newtonsoft.Json; -namespace ChainSafe.Gaming.WalletConnect.Models +namespace ChainSafe.Gaming.Reown.Models { /// - /// Transaction Model used for Wallet Connect Json RPC params, see https://docs.walletconnect.com/advanced/rpc-reference/ethereum-rpc#eth_sendtransaction. + /// Transaction Model used for Reown Json RPC params, see https://docs.walletconnect.com/advanced/rpc-reference/ethereum-rpc#eth_sendtransaction. /// public class TransactionModel { diff --git a/src/ChainSafe.Gaming.WalletConnect/Models/WalletLinkModel.cs b/src/ChainSafe.Gaming.Reown/Models/WalletLinkModel.cs similarity index 94% rename from src/ChainSafe.Gaming.WalletConnect/Models/WalletLinkModel.cs rename to src/ChainSafe.Gaming.Reown/Models/WalletLinkModel.cs index ba2264433..9f83acdd5 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Models/WalletLinkModel.cs +++ b/src/ChainSafe.Gaming.Reown/Models/WalletLinkModel.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace ChainSafe.Gaming.WalletConnect.Models +namespace ChainSafe.Gaming.Reown.Models { /// /// Wallet linking model used for opening/redirecting to wallets using a deeplink from either a Native or a Universal/http protocol. diff --git a/src/ChainSafe.Gaming.Reown/Models/WalletModel.cs b/src/ChainSafe.Gaming.Reown/Models/WalletModel.cs new file mode 100644 index 000000000..0ff171b9d --- /dev/null +++ b/src/ChainSafe.Gaming.Reown/Models/WalletModel.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json; + +namespace ChainSafe.Gaming.Reown.Models +{ + /// + /// Reown wallet model used for identifying and redirecting wallets. + /// + public class WalletModel + { + [JsonProperty("id")] public string Id { get; set; } + + [JsonProperty("name")] public string Name { get; set; } + + [JsonProperty("homepage")] public string Homepage { get; set; } + + [JsonProperty("image_id")] public string ImageId { get; set; } + + [JsonProperty("order")] public int Order { get; set; } + + [JsonProperty("mobile_link")] public string MobileLink { get; set; } + + [JsonProperty("desktop_link")] public string DesktopLink { get; set; } + + [JsonProperty("webapp_link")] public string WebappLink { get; set; } + + [JsonProperty("app_store")] public string AppStore { get; set; } + + [JsonProperty("play_store")] public string PlayStore { get; set; } + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.Reown/RedirectionHandler.cs b/src/ChainSafe.Gaming.Reown/RedirectionHandler.cs new file mode 100644 index 000000000..fe57badd3 --- /dev/null +++ b/src/ChainSafe.Gaming.Reown/RedirectionHandler.cs @@ -0,0 +1,139 @@ +using System; +using ChainSafe.Gaming.Reown.Models; +using ChainSafe.Gaming.Reown.Wallets; +using ChainSafe.Gaming.Web3.Environment; + +namespace ChainSafe.Gaming.Reown +{ + /// + /// Component responsible for redirection to a wallet app. + /// + public class RedirectionHandler + { + private readonly IWalletRegistry walletRegistry; + private readonly IOperatingSystemMediator osMediator; + private readonly ILogWriter logWriter; + + public RedirectionHandler(IWalletRegistry walletRegistry, IOperatingSystemMediator osMediator, ILogWriter logWriter) + { + this.logWriter = logWriter; + this.osMediator = osMediator; + this.walletRegistry = walletRegistry; + } + + private static bool NativeProtocolAvailable(WalletLinkModel linkData) + { + return !string.IsNullOrWhiteSpace(linkData.NativeProtocol) && linkData.NativeProtocol != ":"; + } + + private static bool UniversalProtocolAvailable(WalletLinkModel linkData) + { + return !string.IsNullOrWhiteSpace(linkData.UniversalUrl); + } + + /// + /// Redirect for connection using the pre-selected wallet. + /// + /// The connection URI provided by Reown. + /// The name of the wallet to redirect user to. + public void RedirectConnection(string connectionUri, string walletId) + { + var walletData = walletRegistry.GetWallet(walletId); + var deeplink = BuildConnectionDeeplink(walletData, connectionUri); + + logWriter.Log($"Generated deep link: {deeplink}"); + + if (osMediator.IsMobilePlatform && osMediator.IsEditor) + { + logWriter.LogError("Can't open mobile deeplink in editor. Ignoring..."); + return; + } + + osMediator.OpenUrl(deeplink); + } + + /// + /// Delegate redirection for connection to the OS. + /// + /// The connection URI provided by Reown. + public void RedirectConnectionOsManaged(string connectionUri) + { + if (osMediator.IsMobilePlatform && osMediator.IsEditor) + { + logWriter.LogError($"Can't open mobile connection URI in editor. Ignoring... Connection URI: {connectionUri}"); + return; + } + + logWriter.Log($"Connection URI: {connectionUri}"); + + osMediator.OpenUrl(connectionUri); + } + + /// + /// Redirect to the pre-selected wallet using the wallet name. + /// + public void Redirect(string walletId) + { + var walletData = walletRegistry.GetWallet(walletId); + Redirect(walletData); + } + + /// + /// Redirect to the pre-selected wallet. + /// + public void Redirect(WalletModel walletData) + { + var deepLink = GetWalletAppDeeplink(walletData); + osMediator.OpenUrl(deepLink); + } + + /// + /// Used to get a redirection deeplink for the . + /// + /// Data of the wallet that we want to redirect to. + /// Deeplink for redirection. + public string GetWalletAppDeeplink(WalletModel walletData) + { + return osMediator.IsMobilePlatform ? walletData.MobileLink : walletData.DesktopLink; + } + + /// + /// Used to get a connection deeplink for the particular wallet. + /// + /// Data of the wallet that we want to connect. + /// The connection URI provided by Reown. + /// Deeplink for connection. + /// Invalid format of deeplink registered for the provided wallet. + public string BuildConnectionDeeplink(WalletModel walletData, string wcUri) + { + if (string.IsNullOrWhiteSpace(wcUri)) + { + throw new ReownIntegrationException( + "Can not build a connection deep link. The connection URI is empty."); + } + + var appLink = GetWalletAppDeeplink(walletData); + + if (string.IsNullOrWhiteSpace(appLink)) + { + throw new ReownIntegrationException("[Linker] Native link cannot be empty."); + } + + var safeAppUrl = appLink; + if (!safeAppUrl.Contains("://")) + { + safeAppUrl = safeAppUrl.Replace("/", string.Empty).Replace(":", string.Empty); + safeAppUrl = $"{safeAppUrl}://"; + } + + if (!safeAppUrl.EndsWith('/')) + { + safeAppUrl = $"{safeAppUrl}/"; + } + + var encodedWcUrl = Uri.EscapeDataString(wcUri); + + return $"{safeAppUrl}wc?uri={encodedWcUrl}"; + } + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.Reown/ReownExtensions.cs b/src/ChainSafe.Gaming.Reown/ReownExtensions.cs new file mode 100644 index 000000000..2078c2e50 --- /dev/null +++ b/src/ChainSafe.Gaming.Reown/ReownExtensions.cs @@ -0,0 +1,78 @@ +using ChainSafe.Gaming.Reown.Wallets; +using ChainSafe.Gaming.Web3.Build; +using ChainSafe.Gaming.Web3.Core; +using ChainSafe.Gaming.Web3.Evm.Wallet; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace ChainSafe.Gaming.Reown +{ + public static class ReownExtensions + { + /// + /// Use this to configure Reown for this instance of Web3. + /// + /// The same service collection that was passed in. This enables fluent style. + public static IWeb3ServiceCollection ConfigureReown(this IWeb3ServiceCollection services, IReownConfig config) + { + services.Replace(ServiceDescriptor.Singleton(typeof(IReownConfig), config)); + + return services; + } + + /// + /// Use this to enable Reown functionality for this instance of Web3. + /// + /// The same service collection that was passed in. This enables fluent style. + public static IWeb3ServiceCollection UseReown(this IWeb3ServiceCollection services, IReownConfig config) + { + services.AssertServiceNotBound(); + + services.ConfigureReown(config); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.UseWalletProvider(config); + + return services; + } + + /// + /// Access additional services related to Reown. + /// + /// The Reown subcategory of services. + public static ReownSubCategory Reown(this Web3.Web3 web3) + { + return new ReownSubCategory(web3); + } + + /// + /// Access the service. + /// + /// The service. + public static IWalletRegistry WalletRegistry(this ReownSubCategory reown) + { + return ((IWeb3SubCategory)reown).Web3.ServiceProvider.GetRequiredService(); + } + + /// + /// Access the service. + /// + /// The service. + public static RedirectionHandler RedirectionHandler(this ReownSubCategory reown) + { + return ((IWeb3SubCategory)reown).Web3.ServiceProvider.GetRequiredService(); + } + + /// + /// Access the service. + /// + /// The service. + public static IConnectionHelper ConnectionHelper(this ReownSubCategory reown) + { + return ((IWeb3SubCategory)reown).Web3.ServiceProvider.GetRequiredService(); + } + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.Reown/ReownHttpClient.cs b/src/ChainSafe.Gaming.Reown/ReownHttpClient.cs new file mode 100644 index 000000000..22179caf8 --- /dev/null +++ b/src/ChainSafe.Gaming.Reown/ReownHttpClient.cs @@ -0,0 +1,40 @@ +using System.Linq; +using System.Threading.Tasks; +using ChainSafe.Gaming.Web3.Environment; +using ChainSafe.Gaming.Web3.Environment.Http; + +namespace ChainSafe.Gaming.Reown +{ + public class ReownHttpClient : IHttpClient + { + private readonly IHttpClient originalClient; + private readonly HttpHeader[] reownHeaders; + + public ReownHttpClient(IHttpClient originalClient, IReownConfig reownConfig) + { + this.originalClient = originalClient; + + reownHeaders = new[] + { + new HttpHeader { Name = "x-project-id", Value = reownConfig.ProjectId }, + new HttpHeader { Name = "x-sdk-type", Value = "appkit" }, + new HttpHeader { Name = "x-sdk-version", Value = "unity-appkit-v1.0.0" }, + }; + } + + public ValueTask> GetRaw(string url, params HttpHeader[] headers) + { + return originalClient.GetRaw(url, AppendReownHeaders(headers)); + } + + public ValueTask> PostRaw(string url, string data, string contentType, params HttpHeader[] headers) + { + return originalClient.PostRaw(url, data, contentType, AppendReownHeaders(headers)); + } + + private HttpHeader[] AppendReownHeaders(HttpHeader[] originalHeaders) + { + return reownHeaders.Concat(originalHeaders).ToArray(); + } + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.Reown/ReownIntegrationException.cs b/src/ChainSafe.Gaming.Reown/ReownIntegrationException.cs new file mode 100644 index 000000000..7460a1922 --- /dev/null +++ b/src/ChainSafe.Gaming.Reown/ReownIntegrationException.cs @@ -0,0 +1,21 @@ +using System; +using ChainSafe.Gaming.Web3; + +namespace ChainSafe.Gaming.Reown +{ + /// + /// Represents exception related to the Reown integration. + /// + public class ReownIntegrationException : Web3Exception + { + public ReownIntegrationException(string message) + : base(message) + { + } + + public ReownIntegrationException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectLogLevel.cs b/src/ChainSafe.Gaming.Reown/ReownLogLevel.cs similarity index 50% rename from src/ChainSafe.Gaming.WalletConnect/WalletConnectLogLevel.cs rename to src/ChainSafe.Gaming.Reown/ReownLogLevel.cs index bce982750..6c1e567f5 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectLogLevel.cs +++ b/src/ChainSafe.Gaming.Reown/ReownLogLevel.cs @@ -1,6 +1,6 @@ -namespace ChainSafe.Gaming.WalletConnect +namespace ChainSafe.Gaming.Reown { - public enum WalletConnectLogLevel + public enum ReownLogLevel { Disabled = 0, ErrorOnly = 1, diff --git a/src/ChainSafe.Gaming.WalletConnect/WCLogWriter.cs b/src/ChainSafe.Gaming.Reown/ReownLogWriter.cs similarity index 65% rename from src/ChainSafe.Gaming.WalletConnect/WCLogWriter.cs rename to src/ChainSafe.Gaming.Reown/ReownLogWriter.cs index 495ea4a2c..ac0d399fb 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WCLogWriter.cs +++ b/src/ChainSafe.Gaming.Reown/ReownLogWriter.cs @@ -1,24 +1,24 @@ using System; using ChainSafe.Gaming.Web3.Environment; -using ILogger = WalletConnectSharp.Common.Logging.ILogger; +using Reown.Core.Common.Logging; -namespace ChainSafe.Gaming.WalletConnect +namespace ChainSafe.Gaming.Reown { /// - /// Writes Wallet Connect logs to the . + /// Writes Reown logs to the . /// - public class WCLogWriter : ILogger + public class ReownLogWriter : ILogger { - private const string Label = "[WalletConnect SDK]"; + private const string Label = "[Reown]"; private readonly ILogWriter logWriter; - private readonly IWalletConnectConfig config; + private readonly IReownConfig config; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Log Writer used for logging. - public WCLogWriter(ILogWriter logWriter, IWalletConnectConfig config) + public ReownLogWriter(ILogWriter logWriter, IReownConfig config) { this.config = config; this.logWriter = logWriter; @@ -30,7 +30,7 @@ public WCLogWriter(ILogWriter logWriter, IWalletConnectConfig config) /// Message to be logged. public void Log(string message) { - if (config.LogLevel < WalletConnectLogLevel.Enabled) + if (config.LogLevel < ReownLogLevel.Enabled) { return; } @@ -44,7 +44,7 @@ public void Log(string message) /// Error message to be logged. public void LogError(string message) { - if (config.LogLevel < WalletConnectLogLevel.ErrorOnly) + if (config.LogLevel < ReownLogLevel.ErrorOnly) { return; } @@ -58,7 +58,7 @@ public void LogError(string message) /// Exception to be logged. public void LogError(Exception e) { - if (config.LogLevel < WalletConnectLogLevel.ErrorOnly) + if (config.LogLevel < ReownLogLevel.ErrorOnly) { return; } diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectProvider.cs b/src/ChainSafe.Gaming.Reown/ReownProvider.cs similarity index 60% rename from src/ChainSafe.Gaming.WalletConnect/WalletConnectProvider.cs rename to src/ChainSafe.Gaming.Reown/ReownProvider.cs index 5366eebd1..1a4ce9bb3 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectProvider.cs +++ b/src/ChainSafe.Gaming.Reown/ReownProvider.cs @@ -2,81 +2,80 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using ChainSafe.Gaming.Evm; -using ChainSafe.Gaming.WalletConnect.Connection; -using ChainSafe.Gaming.WalletConnect.Methods; -using ChainSafe.Gaming.WalletConnect.Models; -using ChainSafe.Gaming.WalletConnect.Storage; -using ChainSafe.Gaming.WalletConnect.Wallets; +using ChainSafe.Gaming.Reown.Connection; +using ChainSafe.Gaming.Reown.Methods; +using ChainSafe.Gaming.Reown.Models; +using ChainSafe.Gaming.Reown.Storage; +using ChainSafe.Gaming.Reown.Wallets; using ChainSafe.Gaming.Web3; using ChainSafe.Gaming.Web3.Analytics; using ChainSafe.Gaming.Web3.Core; +using ChainSafe.Gaming.Web3.Core.Chains; using ChainSafe.Gaming.Web3.Core.Debug; using ChainSafe.Gaming.Web3.Environment; using ChainSafe.Gaming.Web3.Evm.Wallet; -using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.JsonRpc.Client.RpcMessages; using Newtonsoft.Json; -using Org.BouncyCastle.Math; -using WalletConnectSharp.Common.Logging; -using WalletConnectSharp.Common.Model.Errors; -using WalletConnectSharp.Common.Utils; -using WalletConnectSharp.Core; -using WalletConnectSharp.Core.Models; -using WalletConnectSharp.Core.Models.Publisher; -using WalletConnectSharp.Network.Models; -using WalletConnectSharp.Sign; -using WalletConnectSharp.Sign.Models; -using WalletConnectSharp.Sign.Models.Engine; -using BigInteger = System.Numerics.BigInteger; - -namespace ChainSafe.Gaming.WalletConnect +using Reown.Core.Common.Logging; +using Reown.Core.Common.Model.Errors; +using Reown.Core.Common.Utils; +using Reown.Core.Crypto; +using Reown.Core.Models.Publisher; +using Reown.Core.Network.Models; +using Reown.Sign; +using Reown.Sign.Models; +using Reown.Sign.Models.Engine; + +namespace ChainSafe.Gaming.Reown { /// - /// Default implementation of . + /// Reown implementation of . /// - public class WalletConnectProvider : WalletProvider, ILifecycleParticipant, IConnectionHelper + public class ReownProvider : WalletProvider, ILifecycleParticipant, IConnectionHelper { private readonly ILogWriter logWriter; - private readonly IWalletConnectConfig config; - private readonly DataStorage storage; + private readonly IReownConfig config; private readonly IChainConfig chainConfig; private readonly IOperatingSystemMediator osMediator; private readonly IWalletRegistry walletRegistry; private readonly RedirectionHandler redirection; - private readonly IHttpClient httpClient; + private readonly IHttpClient reownHttpClient; private readonly IAnalyticsClient analyticsClient; + private readonly Web3Environment environment; + private readonly IChainConfigSet chainConfigSet; - private WalletConnectCore core; - private WalletConnectSignClient signClient; - private RequiredNamespaces requiredNamespaces; - private LocalData localData; + private SignClient signClient; private SessionStruct session; private bool connected; private bool initialized; private ConnectionHandlerConfig connectionHandlerConfig; + private Dictionary optionalNamespaces; + private WalletModel connectedLocalWallet; - public WalletConnectProvider( - IWalletConnectConfig config, - DataStorage storage, + public ReownProvider( + IReownConfig config, IChainConfig chainConfig, + IChainConfigSet chainConfigSet, IWalletRegistry walletRegistry, RedirectionHandler redirection, - Web3Environment environment) + Web3Environment environment, + ReownHttpClient reownHttpClient) : base(environment, chainConfig) { + this.chainConfigSet = chainConfigSet; + this.environment = environment; analyticsClient = environment.AnalyticsClient; this.redirection = redirection; this.walletRegistry = walletRegistry; osMediator = environment.OperatingSystem; this.chainConfig = chainConfig; - this.storage = storage; this.config = config; logWriter = environment.LogWriter; - httpClient = environment.HttpClient; + this.reownHttpClient = reownHttpClient; } - public bool StoredSessionAvailable => localData.SessionTopic != null; + public bool StoredSessionAvailable => signClient.AddressProvider.HasDefaultSession + && !string.IsNullOrWhiteSpace(signClient.AddressProvider.DefaultSession.Topic); private bool OsManageWalletSelection => osMediator.Platform == Platform.Android; @@ -96,62 +95,58 @@ private async Task Initialize() analyticsClient.CaptureEvent(new AnalyticsEvent() { - EventName = "Wallet Connect Initialized", + EventName = "Reown Initialized", PackageName = "io.chainsafe.web3-unity", }); ValidateConfig(); - WCLogger.Logger = new WCLogWriter(logWriter, config); + ReownLogger.Instance = new ReownLogWriter(logWriter, config); - localData = !config.ForceNewSession - ? await storage.LoadLocalData() ?? new LocalData() - : new LocalData(); - - core = new WalletConnectCore(new CoreOptions + var storage = await ReownStorageFactory.Build(environment); + var signClientOptions = new SignClientOptions { - Name = config.ProjectName, ProjectId = config.ProjectId, - Storage = storage.BuildStorage(sessionStored: !string.IsNullOrEmpty(localData.SessionTopic)), + Name = config.ProjectName, + Metadata = config.Metadata, BaseContext = config.BaseContext, + Storage = storage, + KeyChain = new KeyChain(storage), ConnectionBuilder = config.ConnectionBuilder, - }); + RelayUrlBuilder = config.RelayUrlBuilder, + }; - await core.Start(); + signClient = await SignClient.Init(signClientOptions); + await signClient.AddressProvider.LoadDefaultsAsync(); - signClient = await WalletConnectSignClient.Init(new SignClientOptions - { - BaseContext = config.BaseContext, - Core = core, - Metadata = config.Metadata, - Name = config.ProjectName, - ProjectId = config.ProjectId, - Storage = core.Storage, - }); - - requiredNamespaces = new RequiredNamespaces + var optionalNamespace = new ProposedNamespace // todo using optional namespaces like AppKit does, should they be required? { + Chains = chainConfigSet.Configs + .Select(chainEntry => chainEntry.ChainId) + .ToArray(), + Methods = new[] { - ChainModel.EvmNamespace, - new ProposedNamespace - { - Chains = new[] { $"{ChainModel.EvmNamespace}:{chainConfig.ChainId}", }, - Events = new[] { "chainChanged", "accountsChanged" }, - Methods = new[] - { - "eth_sign", - "personal_sign", - "eth_signTypedData", - "eth_signTransaction", - "eth_sendTransaction", - "eth_getTransactionByHash", - "wallet_switchEthereumChain", - "eth_blockNumber", - }, - } + "eth_sign", + "personal_sign", + "eth_signTypedData", + "eth_signTransaction", + "eth_sendTransaction", + "eth_getTransactionByHash", + "wallet_switchEthereumChain", + "eth_blockNumber", + }, + Events = new[] + { + "chainChanged", + "accountsChanged", }, }; + optionalNamespaces = new Dictionary + { + { ChainModel.EvmNamespace, optionalNamespace }, + }; + initialized = true; } @@ -159,19 +154,23 @@ private void ValidateConfig() { if (string.IsNullOrWhiteSpace(config.ProjectId)) { - throw new WalletConnectException("ProjectId was not set."); + throw new ReownIntegrationException("ProjectId was not set."); } - if (string.IsNullOrWhiteSpace(config.StoragePath)) + if (config.ConnectionHandlerProvider == null) { - throw new WalletConnectException("Storage folder path was not set."); + throw new ReownIntegrationException($"No {nameof(IConnectionHandlerProvider)} was provided in the config."); + } + + if (string.IsNullOrWhiteSpace(config.Metadata.Url)) + { + throw new ReownIntegrationException("Your domain URL should be provided in Metadata, otherwise wallets are going to reject the connection."); } } public ValueTask WillStopAsync() { signClient?.Dispose(); - core?.Dispose(); return new ValueTask(Task.CompletedTask); } @@ -180,8 +179,8 @@ public override async Task Connect() { if (connected) { - throw new WalletConnectException( - $"Tried connecting {nameof(WalletConnectProvider)}, but it's already been connected."); + throw new ReownIntegrationException( + $"Tried connecting with {nameof(ReownProvider)}, but was already connected."); } if (!initialized) @@ -191,40 +190,21 @@ public override async Task Connect() try { - var sessionStored = !string.IsNullOrEmpty(localData.SessionTopic); - - session = !sessionStored + session = !config.RememberSession || !StoredSessionAvailable ? await ConnectSession() : await RestoreSession(); - localData.SessionTopic = session.Topic; - - var sessionLocalWallet = GetSessionLocalWallet(); - if (sessionLocalWallet != null) - { - localData.ConnectedLocalWalletName = sessionLocalWallet.Name; - WCLogger.Log($"\"{sessionLocalWallet.Name}\" set as locally connected wallet for the current session."); - } - else - { - localData.ConnectedLocalWalletName = null; - WCLogger.Log("Remote wallet connected."); - } + connectedLocalWallet = GetSessionLocalWallet(); - if (config.RememberSession) - { - await storage.SaveLocalData(localData); - } - else - { - storage.ClearLocalData(); - } + ReownLogger.Log(connectedLocalWallet != null + ? $"Local wallet connected. \"{connectedLocalWallet.Name}\" set as locally connected wallet for the current session." + : "Remote wallet connected."); var address = GetPlayerAddress(); if (!AddressExtensions.IsPublicAddress(address)) { - throw new Web3Exception("Public address provided by WalletConnect is not valid."); + throw new ReownIntegrationException("Public address provided by Reown is not valid."); } connected = true; @@ -235,8 +215,8 @@ public override async Task Connect() } catch (Exception e) { - storage.ClearLocalData(); - throw new WalletConnectException("Error occured during WalletConnect connection process.", e); + signClient.AddressProvider.DefaultSession = default; // reset saved session + throw new ReownIntegrationException("Error occured during Reown connection process.", e); } } @@ -282,34 +262,26 @@ public override async Task Disconnect() return; } - WCLogger.Log("Disconnecting Wallet Connect session..."); + ReownLogger.Log("Disconnecting Reown session..."); try { - storage.ClearLocalData(); - localData = new LocalData(); await signClient.Disconnect(session.Topic, Error.FromErrorType(ErrorType.USER_DISCONNECTED)); - await core.Storage.Clear(); + await signClient.CoreClient.Storage.Clear(); connected = false; } catch (Exception e) { - WCLogger.LogError($"Error occured during disconnect: {e}"); + ReownLogger.LogError($"Error occured during disconnect: {e}"); } } private async Task ConnectSession() { - if (config.ConnectionHandlerProvider == null) - { - throw new WalletConnectException($"Can not connect to a new session. No {nameof(IConnectionHandlerProvider)} was set in config."); - } - - var connectOptions = new ConnectOptions { RequiredNamespaces = requiredNamespaces }; + var connectOptions = new ConnectOptions { OptionalNamespaces = optionalNamespaces }; var connectedData = await signClient.Connect(connectOptions); var connectionHandler = await config.ConnectionHandlerProvider.ProvideHandler(); - Task dialogTask; try { connectionHandlerConfig = new ConnectionHandlerConfig @@ -319,19 +291,18 @@ private async Task ConnectSession() WalletLocationOption = config.WalletLocationOption, LocalWalletOptions = !OsManageWalletSelection - ? walletRegistry.EnumerateSupportedWallets(osMediator.Platform) - .ToList() // todo notify devs that some wallets don't work on Desktop + ? walletRegistry.SupportedWallets.ToList() : null, RedirectToWallet = !OsManageWalletSelection - ? walletName => redirection.RedirectConnection(connectedData.Uri, walletName) + ? walletId => redirection.RedirectConnection(connectedData.Uri, walletId) : null, RedirectOsManaged = OsManageWalletSelection ? () => redirection.RedirectConnectionOsManaged(connectedData.Uri) : null, }; - dialogTask = connectionHandler.ConnectUserWallet(connectionHandlerConfig); + var dialogTask = connectionHandler.ConnectUserWallet(connectionHandlerConfig); // awaiting handler task to catch exceptions, actually awaiting only for approval var combinedTasks = await Task.WhenAny(dialogTask, connectedData.Approval); @@ -355,23 +326,23 @@ private async Task ConnectSession() var newSession = await connectedData.Approval; - WCLogger.Log("Wallet connected using new session."); + ReownLogger.Log("Wallet connected using new session."); return newSession; } private async Task RestoreSession() { - var storedSession = signClient.Find(requiredNamespaces).First(s => s.Topic == localData.SessionTopic); + session = signClient.AddressProvider.DefaultSession; - if (SessionExpired(storedSession)) + if (SessionExpired(session)) { await RenewSession(); } - WCLogger.Log("Wallet connected using stored session."); + ReownLogger.Log("Wallet connected using stored session."); - return storedSession; + return session; } private async Task RenewSession() @@ -384,17 +355,17 @@ private async Task RenewSession() } catch (Exception e) { - throw new WalletConnectException("Auto-renew session failed.", e); + throw new ReownIntegrationException("Session extension failed.", e); } - WCLogger.Log("Renewed session successfully."); + ReownLogger.Log("Renewed session successfully."); } public override async Task Request(string method, params object[] parameters) { if (!connected) { - throw new WalletConnectException("Can't send requests. No session is connected at the moment."); + throw new ReownIntegrationException("Can't send requests. No session is connected at the moment."); } if (SessionExpired(session)) @@ -405,7 +376,7 @@ public override async Task Request(string method, params object[] paramete } else { - throw new WalletConnectException( + throw new ReownIntegrationException( $"Failed to perform {typeof(T)} request - session expired. Please reconnect."); } } @@ -414,12 +385,12 @@ public override async Task Request(string method, params object[] paramete EventUtils.ListenOnce( OnPublishedMessage, - handler => core.Relayer.Publisher.OnPublishedMessage += handler, - handler => core.Relayer.Publisher.OnPublishedMessage -= handler); + handler => signClient.CoreClient.Relayer.Publisher.OnPublishedMessage += handler, + handler => signClient.CoreClient.Relayer.Publisher.OnPublishedMessage -= handler); var chainId = GetChainId(); - return await WalletConnectRequest(sessionTopic, method, chainId, parameters); + return await ReownRequest(sessionTopic, method, chainId, parameters); void OnPublishedMessage(object sender, PublishParams args) { @@ -430,9 +401,9 @@ void OnPublishedMessage(object sender, PublishParams args) return; } - if (localData.ConnectedLocalWalletName != null) + if (connectedLocalWallet != null) { - redirection.Redirect(localData.ConnectedLocalWalletName); + redirection.Redirect(connectedLocalWallet.Id); } } } @@ -442,7 +413,7 @@ private WalletModel GetSessionLocalWallet() var nativeUrl = RemoveSlash(session.Peer.Metadata.Url); var sessionWallet = walletRegistry - .EnumerateSupportedWallets(osMediator.Platform) + .SupportedWallets .FirstOrDefault(w => RemoveSlash(w.Homepage) == nativeUrl); return sessionWallet; @@ -457,7 +428,7 @@ string RemoveSlash(string s) private void TryRedirectToWallet() { - if (localData.ConnectedLocalWalletName == null) + if (connectedLocalWallet == null) { return; } @@ -495,9 +466,9 @@ private string GetFullAddress() return defaultNamespace.Accounts[0]; } - private async Task WalletConnectRequest(string topic, string method, string chainId, params object[] parameters) + private async Task ReownRequest(string topic, string method, string chainId, params object[] parameters) { - // Helper method to make a request using WalletConnectSignClient. + // Helper method to make a request using ReownSignClient. async Task MakeRequest() { var data = (TRequest)Activator.CreateInstance(typeof(TRequest), parameters); @@ -519,15 +490,15 @@ async Task MakeRequest() default: try { - // Direct RPC request via http, WalletConnect RPC url. + // Direct RPC request via http, Reown RPC url. string chain = session.Namespaces.First().Value.Chains[0]; - // Using WalletConnect Blockchain API: https://docs.walletconnect.com/cloud/blockchain-api + // Using Reown Blockchain API: https://docs.Reown.com/cloud/blockchain-api var url = $"https://rpc.walletconnect.com/v1?chainId={chain}&projectId={config.ProjectId}"; string body = JsonConvert.SerializeObject(new RpcRequestMessage(Guid.NewGuid().ToString(), method, parameters)); - var rawResult = await httpClient.PostRaw(url, body, "application/json"); + var rawResult = await reownHttpClient.PostRaw(url, body, "application/json"); RpcResponseMessage response = JsonConvert.DeserializeObject(rawResult.Response); @@ -535,7 +506,7 @@ async Task MakeRequest() } catch (Exception e) { - throw new WalletConnectException($"{method} RPC method currently not implemented.", e); + throw new ReownIntegrationException($"{method} RPC method currently not implemented.", e); } } } diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectSubCategory.cs b/src/ChainSafe.Gaming.Reown/ReownSubCategory.cs similarity index 54% rename from src/ChainSafe.Gaming.WalletConnect/WalletConnectSubCategory.cs rename to src/ChainSafe.Gaming.Reown/ReownSubCategory.cs index 18a16a607..7afaeb705 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectSubCategory.cs +++ b/src/ChainSafe.Gaming.Reown/ReownSubCategory.cs @@ -1,12 +1,12 @@ using ChainSafe.Gaming.Web3.Core; -namespace ChainSafe.Gaming.WalletConnect +namespace ChainSafe.Gaming.Reown { - public class WalletConnectSubCategory : IWeb3SubCategory + public class ReownSubCategory : IWeb3SubCategory { private readonly Web3.Web3 web3; - public WalletConnectSubCategory(Web3.Web3 web3) + public ReownSubCategory(Web3.Web3 web3) { this.web3 = web3; } diff --git a/src/ChainSafe.Gaming.Reown/Storage/ReownStorageFactory.cs b/src/ChainSafe.Gaming.Reown/Storage/ReownStorageFactory.cs new file mode 100644 index 000000000..67bf99f85 --- /dev/null +++ b/src/ChainSafe.Gaming.Reown/Storage/ReownStorageFactory.cs @@ -0,0 +1,55 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using ChainSafe.Gaming.Web3.Environment; +using Newtonsoft.Json; +using Reown.Core.Storage; +using Reown.Core.Storage.Interfaces; + +namespace ChainSafe.Gaming.Reown.Storage +{ + public class ReownStorageFactory + { + public static string RelativeFilePath = "Reown/storage.json"; + + public static async Task Build(Web3Environment environment) + { + switch (environment.OperatingSystem.Platform) + { + case Platform.Editor: + case Platform.Android: + case Platform.IOS: + case Platform.Desktop: + return await BuildFileSystemStorage(environment); + case Platform.WebGL: + return BuildWebGlStorage(); + default: + throw new ReownIntegrationException($"{environment.OperatingSystem.Platform} is not supported."); + } + } + + private static async Task BuildFileSystemStorage(Web3Environment environment) + { + var storageFilePath = Path.Combine(environment.OperatingSystem.AppPersistentDataPath, RelativeFilePath); + var storage = new FileSystemStorage(storageFilePath); + + try + { + await storage.Init(); + } + catch (JsonException) + { + environment.LogWriter.LogError($"Failed to deserialize storage. Deleting it and creating a new one at {storageFilePath}"); + await storage.Clear(); + await storage.Init(); + } + + return storage; + } + + private static IKeyValueStorage BuildWebGlStorage() + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletLocationOption.cs b/src/ChainSafe.Gaming.Reown/WalletLocationOption.cs similarity index 81% rename from src/ChainSafe.Gaming.WalletConnect/WalletLocationOption.cs rename to src/ChainSafe.Gaming.Reown/WalletLocationOption.cs index 1e8c3b7e8..1933fe86d 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletLocationOption.cs +++ b/src/ChainSafe.Gaming.Reown/WalletLocationOption.cs @@ -1,4 +1,4 @@ -namespace ChainSafe.Gaming.WalletConnect +namespace ChainSafe.Gaming.Reown { /// /// Wallet location options. diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletLocationOptionsExtensions.cs b/src/ChainSafe.Gaming.Reown/WalletLocationOptionsExtensions.cs similarity index 96% rename from src/ChainSafe.Gaming.WalletConnect/WalletLocationOptionsExtensions.cs rename to src/ChainSafe.Gaming.Reown/WalletLocationOptionsExtensions.cs index eea8e8d06..173c8d037 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletLocationOptionsExtensions.cs +++ b/src/ChainSafe.Gaming.Reown/WalletLocationOptionsExtensions.cs @@ -1,6 +1,6 @@ using System; -namespace ChainSafe.Gaming.WalletConnect +namespace ChainSafe.Gaming.Reown { public static class WalletLocationOptionsExtensions { diff --git a/src/ChainSafe.Gaming.Reown/Wallets/IWalletRegistry.cs b/src/ChainSafe.Gaming.Reown/Wallets/IWalletRegistry.cs new file mode 100644 index 000000000..246006d32 --- /dev/null +++ b/src/ChainSafe.Gaming.Reown/Wallets/IWalletRegistry.cs @@ -0,0 +1,24 @@ +using System.Collections.ObjectModel; +using ChainSafe.Gaming.Reown.Models; + +namespace ChainSafe.Gaming.Reown.Wallets +{ + /// + /// Registry of the wallets supported by Reown. + /// + public interface IWalletRegistry + { + /// + /// Get all wallets supported on the current platform. + /// + /// Sequence of that the platform supports. + ReadOnlyCollection SupportedWallets { get; } + + /// + /// Return model for the wallet by it's ID. + /// + /// Wallet ID. + /// Wallet model. + WalletModel GetWallet(string id); + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs b/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs new file mode 100644 index 000000000..b4153d69f --- /dev/null +++ b/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading.Tasks; +using ChainSafe.Gaming.Reown.Models; +using ChainSafe.Gaming.Web3.Core; +using ChainSafe.Gaming.Web3.Environment; + +namespace ChainSafe.Gaming.Reown.Wallets +{ + /// + /// The registry of the wallets supported by Reown. + /// + public class ReownWalletRegistry : ILifecycleParticipant, IWalletRegistry // todo provide pre-downloaded registry with option to update + { + private const string Host = "https://api.web3modal.com"; + + private readonly IHttpClient reownHttpClient; + private readonly IReownConfig config; + private readonly IOperatingSystemMediator systemMediator; + + private List platformWallets; + + public ReownWalletRegistry(ReownHttpClient reownHttpClient, IReownConfig config, IOperatingSystemMediator systemMediator) + { + this.systemMediator = systemMediator; + this.config = config; + this.reownHttpClient = reownHttpClient; + } + + public static string RegistryUri => $"{Host}/getWallets"; + + public ReadOnlyCollection SupportedWallets => platformWallets.AsReadOnly(); + + async ValueTask ILifecycleParticipant.WillStartAsync() + { + var registryUri = !string.IsNullOrWhiteSpace(config.OverrideRegistryUri) + ? config.OverrideRegistryUri + : RegistryUri; + + var parameters = new Dictionary() + { + { "page", 1.ToString() }, + { "entries", 100.ToString() }, // get as many wallets as we can with one api call (when too many wallets return 400) + { "search", null }, + { "platform", GetPlatformFilter() }, + { "include", BuildWalletIdsFilter(config.IncludeWalletIds) }, + { "exclude", BuildWalletIdsFilter(config.ExcludeWalletIds) }, + }; + + var parametersRaw = BuildUriParameters(parameters); + + var response = await reownHttpClient.Get(registryUri + parametersRaw); + platformWallets = response.AssertSuccess().Data; + + /* todo implement and utilize IsWalletInstalled functionality + * + var walletClosure = wallet; + var isWalletInstalled = WalletUtils.IsWalletInstalled(wallet); + */ + + return; + + string GetPlatformFilter() + { + return systemMediator.Platform switch + { + Platform.Android => "android", + Platform.IOS => "ios", + _ => null + }; + } + + string BuildWalletIdsFilter(IList walletIds) + { + return walletIds is { Count: > 0 } + ? string.Join(",", walletIds) + : null; + } + } + + private static string BuildUriParameters(Dictionary parameters) + { + var parametersRaw = parameters + .Where(p => !string.IsNullOrWhiteSpace(p.Value)) + .Select(pair => $"{pair.Key}={pair.Value}"); + + return $"?{string.Join("&", parametersRaw)}"; + } + + ValueTask ILifecycleParticipant.WillStopAsync() => new(Task.CompletedTask); + + public WalletModel GetWallet(string id) + { + return platformWallets.Find(w => w.Id == id); + } + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.Reown/Wallets/WalletRegistryResponse.cs b/src/ChainSafe.Gaming.Reown/Wallets/WalletRegistryResponse.cs new file mode 100644 index 000000000..b1b609bef --- /dev/null +++ b/src/ChainSafe.Gaming.Reown/Wallets/WalletRegistryResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using ChainSafe.Gaming.Reown.Models; +using Newtonsoft.Json; + +namespace ChainSafe.Gaming.Reown.Wallets +{ + public class WalletRegistryResponse + { + [JsonProperty("count")] public int Count { get; set; } + + [JsonProperty("data")] public List Data { get; set; } + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.Tests/ChainSafe.Gaming.Tests.csproj b/src/ChainSafe.Gaming.Tests/ChainSafe.Gaming.Tests.csproj index c2006ba78..ae9d69019 100644 --- a/src/ChainSafe.Gaming.Tests/ChainSafe.Gaming.Tests.csproj +++ b/src/ChainSafe.Gaming.Tests/ChainSafe.Gaming.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/ChainSafe.Gaming.Tests/Core/StubHttpClient.cs b/src/ChainSafe.Gaming.Tests/Core/StubHttpClient.cs index 288a23761..8ae9a5bd4 100644 --- a/src/ChainSafe.Gaming.Tests/Core/StubHttpClient.cs +++ b/src/ChainSafe.Gaming.Tests/Core/StubHttpClient.cs @@ -1,29 +1,37 @@ using System.Threading.Tasks; using ChainSafe.Gaming.Web3.Environment; +using ChainSafe.Gaming.Web3.Environment.Http; namespace ChainSafe.Gaming.Tests.Core { public sealed class StubHttpClient : IHttpClient { - public ValueTask> GetRaw(string url) + public ValueTask> GetRaw(string url, params HttpHeader[] headers) { // do nothing return new ValueTask>(Task.FromResult(NetworkResponse.Success("Skipped"))); } - public ValueTask> PostRaw(string url, string data, string contentType) + public ValueTask> PostRaw( + string url, + string data, + string contentType, + params HttpHeader[] headers) { // do nothing return new ValueTask>(Task.FromResult(NetworkResponse.Success("Skipped"))); } - public ValueTask> Get(string url) + public ValueTask> Get(string url, params HttpHeader[] headers) { // do nothing return new ValueTask>(Task.FromResult(NetworkResponse.Success(default))); } - public ValueTask> Post(string url, TRequest data) + public ValueTask> Post( + string url, + TRequest data, + params HttpHeader[] headers) { // do nothing return new ValueTask>(Task.FromResult(NetworkResponse.Success(default))); diff --git a/src/ChainSafe.Gaming.Tests/WalletConnectDeepLinksTests.cs b/src/ChainSafe.Gaming.Tests/WalletConnectDeepLinksTests.cs index 23241e678..b5121651d 100644 --- a/src/ChainSafe.Gaming.Tests/WalletConnectDeepLinksTests.cs +++ b/src/ChainSafe.Gaming.Tests/WalletConnectDeepLinksTests.cs @@ -7,9 +7,6 @@ using ChainSafe.Gaming.Evm.Providers; using ChainSafe.Gaming.NetCore; using ChainSafe.Gaming.Tests.Core; -using ChainSafe.Gaming.WalletConnect; -using ChainSafe.Gaming.WalletConnect.Models; -using ChainSafe.Gaming.WalletConnect.Wallets; using ChainSafe.Gaming.Web3.Build; using ChainSafe.Gaming.Web3.Core; using ChainSafe.Gaming.Web3.Environment; @@ -18,7 +15,7 @@ namespace ChainSafe.Gaming.Tests { - // [TestFixture] // todo unstable currently; uncomment after new version of WalletRegistry with pre-downloaded, filtered list of wallets introduced + // [TestFixture] // todo unstable currently; uncomment after new version of WalletRegistry with pre-downloaded filtered list of wallets gets introduced // public class WalletConnectDeepLinksTests // { // private static readonly List KnownBrokenWalletsIos = new() // todo note in the documentation diff --git a/src/ChainSafe.Gaming.Unity/ChainSafe.Gaming.Unity.csproj b/src/ChainSafe.Gaming.Unity/ChainSafe.Gaming.Unity.csproj index 72c0e1294..1304c7f28 100644 --- a/src/ChainSafe.Gaming.Unity/ChainSafe.Gaming.Unity.csproj +++ b/src/ChainSafe.Gaming.Unity/ChainSafe.Gaming.Unity.csproj @@ -20,7 +20,7 @@ - + diff --git a/src/ChainSafe.Gaming.Unity/UnityHttpClient.cs b/src/ChainSafe.Gaming.Unity/UnityHttpClient.cs index 95c7b1f78..85b25265d 100644 --- a/src/ChainSafe.Gaming.Unity/UnityHttpClient.cs +++ b/src/ChainSafe.Gaming.Unity/UnityHttpClient.cs @@ -1,8 +1,7 @@ using System.Text; using System.Threading.Tasks; -using ChainSafe.Gaming.Unity; using ChainSafe.Gaming.Web3.Environment; -using Newtonsoft.Json; +using ChainSafe.Gaming.Web3.Environment.Http; using UnityEngine.Assertions; using UnityEngine.Networking; @@ -25,60 +24,38 @@ public UnityHttpClient(IMainThreadRunner mainThreadRunner) this.mainThreadRunner = mainThreadRunner; } - /// - /// Converts the UnityWebRequest response to a structured NetworkResponse. - /// - /// The Unity web request instance. - /// Converted Network Response. - private static NetworkResponse UnityWebRequestToNetworkResponse(UnityWebRequest request) + public ValueTask> GetRaw(string url, params HttpHeader[] headers) { - // Assert response is successful + return new ValueTask>(mainThreadRunner.EnqueueTask(async () => { - Assert.AreNotEqual(UnityWebRequest.Result.InProgress, request.result); + using var request = UnityWebRequest.Get(url); - if (request.result == UnityWebRequest.Result.ConnectionError) + foreach (var header in headers) { - throw new Web3Exception($"HTTP.{request.method} to '{request.url}' - connection error."); + request.SetRequestHeader(header.Name, header.Value); } - if (request.result != UnityWebRequest.Result.Success) - { - throw new Web3Exception( - $"HTTP.{request.method} to '{request.url}' responded with error: {request.downloadHandler.text}"); - } - } - - return NetworkResponse.Success(request.downloadHandler.text); - } - - /// - /// Sends a GET request to the specified URL and retrieves the raw response. - /// - /// The target URL. - /// A value task that completes with the network response. - public ValueTask> GetRaw(string url) - { - return new ValueTask>(mainThreadRunner.EnqueueTask(async () => - { - using var request = UnityWebRequest.Get(url); request.downloadHandler = new DownloadHandlerBuffer(); await request.SendWebRequest(); return UnityWebRequestToNetworkResponse(request); })); } - /// - /// Sends a POST request to the specified URL with the provided raw data. - /// - /// The target URL. - /// The raw data to be sent as the request body. - /// The MIME type of the request data. - /// A value task that completes with the network response. - public ValueTask> PostRaw(string url, string data, string contentType) + public ValueTask> PostRaw( + string url, + string data, + string contentType, + params HttpHeader[] headers) { return new ValueTask>(mainThreadRunner.EnqueueTask(async () => { using var request = new UnityWebRequest(url, "POST"); + + foreach (var header in headers) + { + request.SetRequestHeader(header.Name, header.Value); + } + request.uploadHandler = new UploadHandlerRaw(new UTF8Encoding().GetBytes(data)); request.downloadHandler = new DownloadHandlerBuffer(); request.SetRequestHeader("Content-Type", contentType); @@ -88,50 +65,29 @@ public ValueTask> PostRaw(string url, string data, strin } /// - /// Sends a GET request to the specified URL and deserializes the response into the desired type. + /// Converts the UnityWebRequest response to a structured NetworkResponse. /// - /// The type to deserialize the response into. - /// The target URL. - /// A value task that completes with the network response. - public async ValueTask> Get(string url) + /// The Unity web request instance. + /// Converted Network Response. + private static NetworkResponse UnityWebRequestToNetworkResponse(UnityWebRequest request) { - var response = await GetRaw(url); - return response.Map(x => + // Assert response is successful { - try - { - return JsonConvert.DeserializeObject(x); - } - catch (JsonReaderException e) - { - throw new Web3Exception($"Tried deserializing response, but failed.\nMessage:{e.Message}\nResponse body:\n{x}"); - } - }); - } + Assert.AreNotEqual(UnityWebRequest.Result.InProgress, request.result); - /// - /// Sends a POST request to the specified URL with the provided data and deserializes the response into the desired type. - /// - /// The type of the request data. - /// The type to deserialize the response into. - /// The target URL. - /// The data to be sent as the request body. - /// A value task that completes with the network response. - public async ValueTask> Post(string url, TRequest data) - { - var requestJson = JsonConvert.SerializeObject(data); - var response = await PostRaw(url, requestJson, "application/json"); - return response.Map(x => - { - try + if (request.result == UnityWebRequest.Result.ConnectionError) { - return JsonConvert.DeserializeObject(x); + throw new Web3Exception($"HTTP.{request.method} to '{request.url}' - connection error."); } - catch (JsonReaderException e) + + if (request.result != UnityWebRequest.Result.Success) { - throw new Web3Exception($"Tried deserializing response, but failed.\nMessage:{e.Message}\nResponse body:\n{x}"); + throw new Web3Exception( + $"HTTP.{request.method} to '{request.url}' responded with error: {request.downloadHandler.text}"); } - }); + } + + return NetworkResponse.Success(request.downloadHandler.text); } } } diff --git a/src/ChainSafe.Gaming.Unity/link.xml b/src/ChainSafe.Gaming.Unity/link.xml index aab5532f7..9b1f50c70 100644 --- a/src/ChainSafe.Gaming.Unity/link.xml +++ b/src/ChainSafe.Gaming.Unity/link.xml @@ -19,7 +19,7 @@ - + diff --git a/src/ChainSafe.Gaming.WalletConnect/Models/WalletModel.cs b/src/ChainSafe.Gaming.WalletConnect/Models/WalletModel.cs deleted file mode 100644 index 201e113c8..000000000 --- a/src/ChainSafe.Gaming.WalletConnect/Models/WalletModel.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Newtonsoft.Json; - -namespace ChainSafe.Gaming.WalletConnect.Models -{ - /// - /// WalletConnect wallet model used for identifying and redirecting wallets. - /// - public class WalletModel - { - /// - /// Id of the wallet. - /// - [JsonProperty("id")] - public string Id { get; private set; } - - /// - /// Name of the wallet. - /// - [JsonProperty("name")] - public string Name { get; private set; } - - /// - /// Description of the wallet. - /// - [JsonProperty("description")] - public string Description { get; private set; } - - /// - /// Homepage of the wallet. - /// - [JsonProperty("homepage")] - public string Homepage { get; private set; } - - /// - /// for mobile platforms. - /// - [JsonProperty("mobile")] - public WalletLinkModel Mobile { get; private set; } - - /// - /// for desktop platforms. - /// - [JsonProperty("desktop")] - public WalletLinkModel Desktop { get; private set; } - - /// - /// wallet icons urls. - /// - [JsonProperty("image_url")] - public ImageUrlsModel Images { get; private set; } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/RedirectionHandler.cs b/src/ChainSafe.Gaming.WalletConnect/RedirectionHandler.cs deleted file mode 100644 index 33ca9e7eb..000000000 --- a/src/ChainSafe.Gaming.WalletConnect/RedirectionHandler.cs +++ /dev/null @@ -1,180 +0,0 @@ -using System.Web; -using ChainSafe.Gaming.WalletConnect.Models; -using ChainSafe.Gaming.WalletConnect.Wallets; -using ChainSafe.Gaming.Web3.Environment; - -namespace ChainSafe.Gaming.WalletConnect -{ - /// - /// Component responsible for redirection of a user to a wallet app. - /// - public class RedirectionHandler - { - private readonly IWalletRegistry walletRegistry; - private readonly IOperatingSystemMediator osMediator; - private readonly ILogWriter logWriter; - - public RedirectionHandler(IWalletRegistry walletRegistry, IOperatingSystemMediator osMediator, ILogWriter logWriter) - { - this.logWriter = logWriter; - this.osMediator = osMediator; - this.walletRegistry = walletRegistry; - } - - private static bool NativeProtocolAvailable(WalletLinkModel linkData) - { - return !string.IsNullOrWhiteSpace(linkData.NativeProtocol) && linkData.NativeProtocol != ":"; - } - - private static bool UniversalProtocolAvailable(WalletLinkModel linkData) - { - return !string.IsNullOrWhiteSpace(linkData.UniversalUrl); - } - - /// - /// Redirect for connection using the pre-selected wallet. - /// - /// The connection URI provided by WalletConnect. - /// The name of the wallet to redirect user to. - public void RedirectConnection(string connectionUri, string walletName) - { - var walletData = walletRegistry.GetWallet(walletName); - var deeplink = BuildConnectionDeeplink(walletData, connectionUri); - - logWriter.Log($"Generated deep link: {deeplink}"); - - if (osMediator.IsMobilePlatform && osMediator.IsEditor) - { - logWriter.Log("Can't open mobile deeplink in editor. Ignoring.."); - return; - } - - osMediator.OpenUrl(deeplink); - } - - /// - /// Delegate redirection for connection to the OS. - /// - /// The connection URI provided by WalletConnect. - public void RedirectConnectionOsManaged(string connectionUri) - { - logWriter.Log($"Connection URI: {connectionUri}"); - - if (osMediator.IsMobilePlatform && osMediator.IsEditor) - { - logWriter.Log($"Can't open mobile connection URI in editor. Ignoring.."); - return; - } - - osMediator.OpenUrl(connectionUri); - } - - /// - /// Redirect to the pre-selected wallet using the wallet name. - /// - public void Redirect(string walletName) - { - var walletData = walletRegistry.GetWallet(walletName); - Redirect(walletData); - } - - /// - /// Redirect to the pre-selected wallet. - /// - public void Redirect(WalletModel walletData) - { - var deepLink = GetRedirectionDeeplink(walletData); - osMediator.OpenUrl(deepLink); - } - - /// - /// Used to get a redirection deeplink for the . - /// - /// Data of the wallet that we want to redirect to. - /// Deeplink for redirection. - public string GetRedirectionDeeplink(WalletModel walletData) - { - var linkData = GetPlatformLinkData(walletData); - var deeplink = GetPlatformDeeplink(); - return deeplink; - - string GetPlatformDeeplink() - { - if (osMediator.Platform != Platform.IOS) - { - return NativeProtocolAvailable(linkData) ? linkData.NativeProtocol : linkData.UniversalUrl; - } - else - { - return UniversalProtocolAvailable(linkData) ? linkData.UniversalUrl : linkData.NativeProtocol; - } - } - } - - /// - /// Used to get a connection deeplink for the particular wallet. - /// - /// Data of the wallet that we want to connect. - /// The connection URI provided by WalletConnect. - /// Deeplink for connection. - /// Invalid format of deeplink registered for the provided wallet. - public string BuildConnectionDeeplink(WalletModel walletData, string connectionUri) - { - if (string.IsNullOrWhiteSpace(connectionUri)) - { - throw new WalletConnectException("Can not build a connection deep link. The connection URI is empty."); - } - - var linkData = GetPlatformLinkData(walletData); - var platformUrl = BuildPlatformUrl(); - - var finalUrl = $"{platformUrl}wc?uri={HttpUtility.UrlEncode(connectionUri)}"; // use System.Uri.EscapeDataString(uri) if this doesn't work - - return finalUrl; - - string BuildPlatformUrl() - { - if (osMediator.Platform != Platform.IOS) - { - return NativeProtocolAvailable(linkData) ? BuildNativeUrl() : BuildUniversalUrl(); - } - else - { - return UniversalProtocolAvailable(linkData) ? BuildUniversalUrl() : BuildNativeUrl(); - } - } - - string BuildNativeUrl() - { - var nativeUrl = linkData.NativeProtocol; - - if (!nativeUrl.Contains(':')) - { - throw new WalletConnectException( - $"Native protocol deeplink for {walletData.Name} had incorrect format: no \":\" symbol."); - } - - var pureProtocolStringLength = nativeUrl.IndexOf(':') + 1; - var pureProtocol = nativeUrl[..pureProtocolStringLength]; - return $"{pureProtocol}//"; - } - - string BuildUniversalUrl() - { - var universalUrl = linkData.UniversalUrl; - - if (!universalUrl.EndsWith('/')) - { - universalUrl += '/'; - } - - return universalUrl; - } - } - - private WalletLinkModel GetPlatformLinkData(WalletModel walletData) - { - return osMediator.IsMobilePlatform ? walletData.Mobile : walletData.Desktop; - } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/Storage/DataStorage.cs b/src/ChainSafe.Gaming.WalletConnect/Storage/DataStorage.cs deleted file mode 100644 index 04366b4ae..000000000 --- a/src/ChainSafe.Gaming.WalletConnect/Storage/DataStorage.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using ChainSafe.Gaming.Web3.Environment; -using Newtonsoft.Json; -using WalletConnectSharp.Common.Logging; -using WalletConnectSharp.Storage; - -namespace ChainSafe.Gaming.WalletConnect.Storage -{ - /// - /// Default implementation of the component responsible for storage of WalletConnect-related data. - /// - public class DataStorage - { - private const string StorageFileName = "walletconnect-storage.json"; - private const string LocalDataFileName = "walletconnect-local.json"; - - private readonly IWalletConnectConfig config; - private readonly IOperatingSystemMediator osMediator; - private readonly ILogWriter logWriter; - - public DataStorage(IWalletConnectConfig config, IOperatingSystemMediator osMediator, ILogWriter logWriter) - { - this.logWriter = logWriter; - this.osMediator = osMediator; - this.config = config; - } - - /// - /// Loads local data for the WalletConnect integration. - /// - /// Local data for the WalletConnect integration. - public async Task LoadLocalData() - { - var path = BuildLocalDataPath(); - if (!File.Exists(path)) - { - return null; - } - - try - { - var json = await File.ReadAllTextAsync(path); - return JsonConvert.DeserializeObject(json); - } - catch - { - logWriter.LogError("WalletConnect local data file is corrupted. Removing.."); - File.Delete(path); - return null; - } - } - - /// - /// Saves local data for the WalletConnect integration. - /// - /// The data. - /// A representing the asynchronous operation. - public async Task SaveLocalData(LocalData localData) - { - var path = BuildLocalDataPath(); - var json = JsonConvert.SerializeObject(localData); - await File.WriteAllTextAsync(path, json); - } - - /// - /// Clears local data for the WalletConnect integration from the disk. - /// - public void ClearLocalData() - { - var path = BuildLocalDataPath(); - if (!File.Exists(path)) - { - return; - } - - File.Delete(path); - } - - /// - /// Builds storage for WalletConnectCSharp. - /// - /// True if the session was already stored. - /// Storage object used by WalletConnectCSharp. - public FileSystemStorage BuildStorage(bool sessionStored) - { - var absStoragePath = BuildStoragePath(osMediator.AppPersistentDataPath, config.StoragePath); - var path = Path.Combine(absStoragePath, StorageFileName); - - // If we're not restoring a session and save WC file exists remove it. - // This is done to mitigate for a WC error that happens intermittently where generated Uri doesn't connect wallet. - if (!sessionStored && File.Exists(path)) - { - File.Delete(path); - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - WCLogger.Log($"Wallet Connect Storage set to {path}"); - - return new FileSystemStorage(path); - } - - private string BuildLocalDataPath() - { - var absStoragePath = BuildStoragePath(osMediator.AppPersistentDataPath, config.StoragePath); - return Path.Combine(absStoragePath, LocalDataFileName); - } - - public static string BuildStoragePath(string appDataPath, string storageRelativePath) - { - return Path.Combine(appDataPath, storageRelativePath); - } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/Storage/LocalData.cs b/src/ChainSafe.Gaming.WalletConnect/Storage/LocalData.cs deleted file mode 100644 index 0096a274b..000000000 --- a/src/ChainSafe.Gaming.WalletConnect/Storage/LocalData.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace ChainSafe.Gaming.WalletConnect.Storage -{ - /// - /// A class representing a local data used by the WalletConnect integration. - /// - public class LocalData - { - /// - /// Session topic used to restore previously connected session. - /// - public string SessionTopic { get; set; } - - /// - /// The name of the locally connected wallet. - /// - public string ConnectedLocalWalletName { get; set; } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectException.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectException.cs deleted file mode 100644 index c3ba6de16..000000000 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectException.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using ChainSafe.Gaming.Web3; - -namespace ChainSafe.Gaming.WalletConnect -{ - /// - /// Represents exception related to the WalletConnect integration. - /// - public class WalletConnectException : Web3Exception - { - public WalletConnectException(string message) - : base(message) - { - } - - public WalletConnectException(string message, Exception innerException) - : base(message, innerException) - { - } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectExtensions.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectExtensions.cs deleted file mode 100644 index fa1a83d36..000000000 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectExtensions.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System.Linq; -using ChainSafe.Gaming.Evm.Providers; -using ChainSafe.Gaming.Evm.Signers; -using ChainSafe.Gaming.WalletConnect.Storage; -using ChainSafe.Gaming.WalletConnect.Wallets; -using ChainSafe.Gaming.Web3.Build; -using ChainSafe.Gaming.Web3.Core; -using ChainSafe.Gaming.Web3.Core.Evm; -using ChainSafe.Gaming.Web3.Core.Logout; -using ChainSafe.Gaming.Web3.Evm.Wallet; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; - -namespace ChainSafe.Gaming.WalletConnect -{ - public static class WalletConnectExtensions - { - /// - /// Use this to enable WalletConnect functionality for this instance of Web3. - /// - /// The same service collection that was passed in. This enables fluent style. - private static IWeb3ServiceCollection UseWalletConnect(this IWeb3ServiceCollection services) - { - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - return services; - } - - /// - /// Use this to enable WalletConnect functionality for this instance of Web3. - /// - /// The same service collection that was passed in. This enables fluent style. - public static IWeb3ServiceCollection UseWalletConnect(this IWeb3ServiceCollection services, IWalletConnectConfig config) - { - services = UseWalletConnect(services); - - services.Replace(ServiceDescriptor.Singleton(typeof(IWalletConnectConfig), config)); - - return services.UseWalletProvider(config); - } - - /// - /// Access additional services related to WalletConnect. - /// - /// The WalletConnect subcategory of services. - public static WalletConnectSubCategory WalletConnect(this Web3.Web3 web3) - { - return new WalletConnectSubCategory(web3); - } - - /// - /// Access the service. - /// - /// The service. - public static IWalletRegistry WalletRegistry(this WalletConnectSubCategory walletConnect) - { - return ((IWeb3SubCategory)walletConnect).Web3.ServiceProvider.GetRequiredService(); - } - - /// - /// Access the service. - /// - /// The service. - public static RedirectionHandler RedirectionHandler(this WalletConnectSubCategory walletConnect) - { - return ((IWeb3SubCategory)walletConnect).Web3.ServiceProvider.GetRequiredService(); - } - - /// - /// Access the service. - /// - /// The service. - public static IConnectionHelper ConnectionHelper(this WalletConnectSubCategory walletConnect) - { - return ((IWeb3SubCategory)walletConnect).Web3.ServiceProvider.GetRequiredService(); - } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/Wallets/IWalletRegistry.cs b/src/ChainSafe.Gaming.WalletConnect/Wallets/IWalletRegistry.cs deleted file mode 100644 index d2540769a..000000000 --- a/src/ChainSafe.Gaming.WalletConnect/Wallets/IWalletRegistry.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Collections.Generic; -using ChainSafe.Gaming.WalletConnect.Models; -using ChainSafe.Gaming.Web3.Environment; - -namespace ChainSafe.Gaming.WalletConnect.Wallets -{ - /// - /// Registry of the wallets supported by WalletConnect. - /// - public interface IWalletRegistry - { - /// - /// Return model for the wallet by it's name. - /// - /// The name of the wallet. - /// Wallet model. - WalletModel GetWallet(string name); - - /// - /// Enumerates through all wallets supported on the specified platform. - /// - /// The platform. - /// Sequence of that the platform supports. - IEnumerable EnumerateSupportedWallets(Platform platform); - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/Wallets/WalletRegistry.cs b/src/ChainSafe.Gaming.WalletConnect/Wallets/WalletRegistry.cs deleted file mode 100644 index 5d788c698..000000000 --- a/src/ChainSafe.Gaming.WalletConnect/Wallets/WalletRegistry.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using ChainSafe.Gaming.WalletConnect.Models; -using ChainSafe.Gaming.Web3.Core; -using ChainSafe.Gaming.Web3.Environment; -using WalletConnectSharp.Common.Logging; - -namespace ChainSafe.Gaming.WalletConnect.Wallets -{ - /// - /// The registry of the wallets supported by WalletConnect. - /// - public class WalletRegistry : ILifecycleParticipant, IWalletRegistry // todo provide pre-downloaded registry with option to update - { - private readonly IHttpClient httpClient; - private readonly IWalletConnectConfig config; - - private List enabledWallets; - - public WalletRegistry(IHttpClient httpClient, IWalletConnectConfig config) - { - this.config = config; - this.httpClient = httpClient; - } - - public static string BuildRegistryUri(string projectId) => - $"https://explorer-api.walletconnect.com/v3/wallets?projectId={projectId}"; - - async ValueTask ILifecycleParticipant.WillStartAsync() - { - var registryUri = !string.IsNullOrWhiteSpace(config.OverrideRegistryUri) - ? config.OverrideRegistryUri - : BuildRegistryUri(config.ProjectId); - - var response = await httpClient.Get(registryUri); - var allWallets = response.AssertSuccess().Listings; - - if (config.EnabledWallets != null && config.EnabledWallets.Any()) - { - enabledWallets = allWallets.Values - .Where(w => config.EnabledWallets.Contains(w.Name)) - .ToList(); - - return; - } - - if (config.DisabledWallets != null && config.DisabledWallets.Any()) - { - enabledWallets = allWallets.Values - .Where(w => !config.DisabledWallets.Contains(w.Name)) - .ToList(); - - return; - } - - enabledWallets = allWallets.Values.ToList(); - } - - ValueTask ILifecycleParticipant.WillStopAsync() => new(Task.CompletedTask); - - public WalletModel GetWallet(string name) // todo refactor this class to use walletId for identification - { - return enabledWallets.Find(w => w.Name == name); - } - - public IEnumerable EnumerateSupportedWallets(Platform platform) - { - return enabledWallets.Where(w => IsAvailableForPlatform(w, platform)); - } - - /// - /// Is a wallet available for . - /// - /// Platform to wallet app availability. - /// True if wallet is available for . - private bool IsAvailableForPlatform(WalletModel wallet, Platform platform) - { - switch (platform) - { - case Platform.Editor: - case Platform.Desktop: - return CanUseNativeProtocol(false) || !string.IsNullOrEmpty(wallet.Desktop.UniversalUrl); - - case Platform.Android: - case Platform.IOS: - return CanUseNativeProtocol(true) || !string.IsNullOrEmpty(wallet.Mobile.UniversalUrl); - - // currently Wallet Connect doesn't support WebGL. - default: - WCLogger.Log($"Unsupported Platform {platform}"); - return false; - } - - bool CanUseNativeProtocol(bool isMobilePlatform) - { - var nativeUrl = GetLinkData(isMobilePlatform).NativeProtocol; - return !string.IsNullOrWhiteSpace(nativeUrl) && nativeUrl != ":"; - } - - WalletLinkModel GetLinkData(bool isMobilePlatform) - { - return isMobilePlatform ? wallet.Mobile : wallet.Desktop; - } - } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/Wallets/WalletRegistryResponse.cs b/src/ChainSafe.Gaming.WalletConnect/Wallets/WalletRegistryResponse.cs deleted file mode 100644 index 3f99d67d3..000000000 --- a/src/ChainSafe.Gaming.WalletConnect/Wallets/WalletRegistryResponse.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using ChainSafe.Gaming.WalletConnect.Models; -using Newtonsoft.Json; - -namespace ChainSafe.Gaming.WalletConnect.Wallets -{ - public class WalletRegistryResponse - { - [JsonProperty("listings")] - public Dictionary Listings { get; set; } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming/Web3/Core/Environment/Http/HttpHeader.cs b/src/ChainSafe.Gaming/Web3/Core/Environment/Http/HttpHeader.cs new file mode 100644 index 000000000..603e625e7 --- /dev/null +++ b/src/ChainSafe.Gaming/Web3/Core/Environment/Http/HttpHeader.cs @@ -0,0 +1,9 @@ +namespace ChainSafe.Gaming.Web3.Environment.Http +{ + public struct HttpHeader + { + public string Name { get; set; } + + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming/Web3/Core/Environment/IHttpClient.cs b/src/ChainSafe.Gaming/Web3/Core/Environment/IHttpClient.cs index f596d5fa9..03674e6d1 100644 --- a/src/ChainSafe.Gaming/Web3/Core/Environment/IHttpClient.cs +++ b/src/ChainSafe.Gaming/Web3/Core/Environment/IHttpClient.cs @@ -1,5 +1,7 @@ using System; using System.Threading.Tasks; +using ChainSafe.Gaming.Web3.Environment.Http; +using Newtonsoft.Json; namespace ChainSafe.Gaming.Web3.Environment { @@ -12,8 +14,9 @@ public interface IHttpClient /// Makes a GET request. /// /// URL to send request to. + /// Set of headers to use with the HTTP request. /// Server response. - ValueTask> GetRaw(string url); + ValueTask> GetRaw(string url, params HttpHeader[] headers); /// /// Makes a POST request. @@ -21,26 +24,65 @@ public interface IHttpClient /// URL to send request to. /// Data to send. /// Content type of the data (ex. 'application/json'). + /// Set of headers to use with the HTTP request. /// Server response. - ValueTask> PostRaw(string url, string data, string contentType); + ValueTask> PostRaw( + string url, + string data, + string contentType, + params HttpHeader[] headers); /// /// Makes a GET request. Deserializes response from JSON to the specified type. /// /// URL to send request to. + /// Set of headers to use with the HTTP request. /// Type of the response data. /// Server response. - ValueTask> Get(string url); + async ValueTask> Get(string url, params HttpHeader[] headers) + { + var response = await GetRaw(url, headers); + return response.Map(x => + { + try + { + return JsonConvert.DeserializeObject(x); + } + catch (JsonReaderException e) + { + throw new Web3Exception($"Tried deserializing response, but failed.\nMessage:{e.Message}\nResponse body:\n{x}"); + } + }); + } /// /// Makes a POST request. Handles JSON serialization/deserialization of request and response for the specified types. /// /// URL to send request to. /// Data object to send. + /// Set of headers to use with the HTTP request. /// Type of content used for request. /// Type of content expected as the response. /// Server response. - ValueTask> Post(string url, TRequest data); + async ValueTask> Post( + string url, + TRequest data, + params HttpHeader[] headers) + { + var requestJson = JsonConvert.SerializeObject(data); + var response = await PostRaw(url, requestJson, "application/json", headers); + return response.Map(x => + { + try + { + return JsonConvert.DeserializeObject(x); + } + catch (JsonReaderException e) + { + throw new Web3Exception($"Tried deserializing response, but failed.\nMessage:{e.Message}\nResponse body:\n{x}"); + } + }); + } } /// diff --git a/src/UnitySampleProject/Assets/Resources/ReownConnectionProvider.asset b/src/UnitySampleProject/Assets/Resources/ReownConnectionProvider.asset new file mode 100644 index 000000000..5489c2af9 --- /dev/null +++ b/src/UnitySampleProject/Assets/Resources/ReownConnectionProvider.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 582efc0fde77aab43a77ee4237ba305a, type: 3} + m_Name: ReownConnectionProvider + m_EditorClassIdentifier: + handlerPrefab: {fileID: 5250797134093199901, guid: 0c7c312ad6c521f4b8346ed8e9d7c664, type: 3} + includeWalletIds: [] + excludeWalletIds: [] + k__BackingField: 214bf16d1d17a589e2d54d49fefa2259 + k__BackingField: Web3.Unity + k__BackingField: 1 + k__BackingField: unity-game + k__BackingField: + Description: web3.unity is an open-source gaming SDK. + Icons: [] + Name: Web3.Unity + Redirect: + Native: + Universal: + Url: https://chainsafe.io/ + VerifyUrl: + k__BackingField: + k__BackingField: 1 + k__BackingField: 0 + k__BackingField: {fileID: 21300000, guid: 7bb02b1b8d270114fa77d28d426c8c1c, type: 3} + k__BackingField: Reown diff --git a/src/UnitySampleProject/Assets/Resources/WalletConnectConnectionProvider.asset.meta b/src/UnitySampleProject/Assets/Resources/ReownConnectionProvider.asset.meta similarity index 64% rename from src/UnitySampleProject/Assets/Resources/WalletConnectConnectionProvider.asset.meta rename to src/UnitySampleProject/Assets/Resources/ReownConnectionProvider.asset.meta index 144f2e5ed..86c09a5da 100644 --- a/src/UnitySampleProject/Assets/Resources/WalletConnectConnectionProvider.asset.meta +++ b/src/UnitySampleProject/Assets/Resources/ReownConnectionProvider.asset.meta @@ -1,8 +1,8 @@ fileFormatVersion: 2 -guid: 0d7bd7ae4b3e79d489bbc54514343f5c +guid: cad6fa48701480044a2a6f2d9c9dae1e NativeFormatImporter: externalObjects: {} - mainObjectFileID: 0 + mainObjectFileID: 11400000 userData: assetBundleName: assetBundleVariant: diff --git a/src/UnitySampleProject/Assets/Resources/WalletConnectConnectionProvider.asset b/src/UnitySampleProject/Assets/Resources/WalletConnectConnectionProvider.asset deleted file mode 100644 index 898e6651f..000000000 --- a/src/UnitySampleProject/Assets/Resources/WalletConnectConnectionProvider.asset +++ /dev/null @@ -1,44 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 582efc0fde77aab43a77ee4237ba305a, type: 3} - m_Name: WalletConnectConnectionProvider - m_EditorClassIdentifier: - k__BackingField: WalletConnect - k__BackingField: {fileID: 8599114313589093787, guid: 4591cfadb2bf9824da90ebf4005728a8, type: 3} - k__BackingField: 1 - k__BackingField: f4bff60eb260841f46b1c77588cd8acb - k__BackingField: Web3.Unity - k__BackingField: 1 - k__BackingField: unity-game - k__BackingField: - Name: Web3.Unity - Description: web3.unity is an open-source gaming SDK written in C# and developed - by ChainSafe Gaming. It connects games built in the Unity game engine to the - blockchain. The library currently supports games built for web browsers (WebGL), - iOS/Android mobile, and desktop. web3.unity is compatible with most EVM-based - chains such as Ethereum, Polygon, Moonbeam, Cronos, Nervos, and Binance Smart - Chain, letting developers easily choose and switch between them to create the - best in-game experience. - Url: https://chainsafe.io/ - Icons: [] - Redirect: - Native: - Universal: - VerifyUrl: - k__BackingField: wallet-connect/ - k__BackingField: - handlerPrefab: {fileID: 5250797134093199901, guid: 0c7c312ad6c521f4b8346ed8e9d7c664, type: 3} - enabledWallets: [] - disabledWallets: [] - k__BackingField: 1 - connectionHandlerProvider: {fileID: 11400000, guid: cdc198015a446e54794e5921e5aa81ef, type: 2} - k__BackingField: 0 diff --git a/src/UnitySampleProject/Assets/link.xml b/src/UnitySampleProject/Assets/link.xml index 269e4a760..e9a2ce145 100644 --- a/src/UnitySampleProject/Assets/link.xml +++ b/src/UnitySampleProject/Assets/link.xml @@ -1,13 +1,13 @@ - + - - + + - - - + + + \ No newline at end of file diff --git a/src/UnitySampleProject/UnitySampleProject.sln.DotSettings b/src/UnitySampleProject/UnitySampleProject.sln.DotSettings index ef25ec43b..3dfca1812 100644 --- a/src/UnitySampleProject/UnitySampleProject.sln.DotSettings +++ b/src/UnitySampleProject/UnitySampleProject.sln.DotSettings @@ -1,2 +1,3 @@  - True \ No newline at end of file + True + True \ No newline at end of file From 24f596e8e59a82187664957a8b44eba80f0f4c07 Mon Sep 17 00:00:00 2001 From: creeppak Date: Mon, 21 Oct 2024 12:24:06 +0100 Subject: [PATCH 02/16] Added 'Set Primary Chain' functionality to Web3 Settings Editor --- .../Web3SettingsEditor.ChainSettings.cs | 10 +++++++ .../Editor/Web3SettingsEditor.cs | 27 ++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Packages/io.chainsafe.web3-unity/Editor/Web3SettingsEditor.ChainSettings.cs b/Packages/io.chainsafe.web3-unity/Editor/Web3SettingsEditor.ChainSettings.cs index 5b28e9677..76a49e18c 100644 --- a/Packages/io.chainsafe.web3-unity/Editor/Web3SettingsEditor.ChainSettings.cs +++ b/Packages/io.chainsafe.web3-unity/Editor/Web3SettingsEditor.ChainSettings.cs @@ -40,6 +40,16 @@ public void OnGUI() EditorGUILayout.BeginHorizontal(); GUILayout.Label(title, EditorStyles.boldLabel); GUILayout.FlexibleSpace(); + if (window.IsPrimaryChain(chainConfig)) + { + GUI.enabled = false; + GUILayout.Button("Primary Chain"); + GUI.enabled = true; + } + else if (GUILayout.Button("Set as Primary")) + { + window.SetPrimaryChain(chainConfig); + } if (GUILayout.Button("Remove")) { OnRemoveClick(); diff --git a/Packages/io.chainsafe.web3-unity/Editor/Web3SettingsEditor.cs b/Packages/io.chainsafe.web3-unity/Editor/Web3SettingsEditor.cs index 526d970fb..fea3604b1 100644 --- a/Packages/io.chainsafe.web3-unity/Editor/Web3SettingsEditor.cs +++ b/Packages/io.chainsafe.web3-unity/Editor/Web3SettingsEditor.cs @@ -221,6 +221,22 @@ private void DrawFooter() GUILayout.Label("ChainSafe Gaming", EditorStyles.centeredGreyMiniLabel); } + private bool IsPrimaryChain(ChainConfigEntry entry) + { + return web3Config.ChainConfigs.Any() && web3Config.ChainConfigs[0] == entry; + } + + private void SetPrimaryChain(ChainConfigEntry entry) + { + var indexOf = web3Config.ChainConfigs.IndexOf(entry); + + web3Config.ChainConfigs.RemoveAt(indexOf); + web3Config.ChainConfigs.Insert(0, entry); + + InitializeChainItems(); + chainsScrollPosition = Vector2.zero; + } + private void RemoveChainConfigEntry(string chainId) { var index = web3Config.ChainConfigs.FindIndex(entry => entry.ChainId == chainId); @@ -315,9 +331,7 @@ private void OnChainListFetched() { if (web3Config.ChainConfigs.Count != 0) { - chainSettingPanels = web3Config.ChainConfigs - .Select((chainConfig) => new ChainSettingsPanel(this, chainConfig)) - .ToList(); + InitializeChainItems(); } else { @@ -332,6 +346,13 @@ private void OnChainListFetched() } } + private void InitializeChainItems() + { + chainSettingPanels = web3Config.ChainConfigs + .Select((chainConfig) => new ChainSettingsPanel(this, chainConfig)) + .ToList(); + } + private class ValidateProjectIDResponse { [JsonProperty("response")] public bool Response { get; set; } From 4c6585512768bafb28a61ea039b415f9587bb8ae Mon Sep 17 00:00:00 2001 From: creeppak Date: Mon, 21 Oct 2024 12:24:25 +0100 Subject: [PATCH 03/16] Fixed local wallet connection --- .../Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs index 0b551c9c6..67af022bc 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs @@ -59,7 +59,7 @@ public override Task ConnectUserWallet(ConnectionHandlerConfig config) SetRedirectOptionsVisible(true); var walletOptionConfigs = config.LocalWalletOptions - .Select(data => new WalletOptionConfig(data, () => OnLocalWalletButtonClick(data.Name))) + .Select(data => new WalletOptionConfig(data, () => OnLocalWalletButtonClick(data.Id))) .ToList(); SpawnRedirectOptions(walletOptionConfigs); @@ -120,11 +120,11 @@ private void ResetDialog() ClearDynamicElements(); } - private void OnLocalWalletButtonClick(string walletName) + private void OnLocalWalletButtonClick(string walletId) { try { - config.RedirectToWallet(walletName); + config.RedirectToWallet(walletId); } catch (Exception e) { From 649c6b2ed4efa75f07c4f25a78651259becf545e Mon Sep 17 00:00:00 2001 From: creeppak Date: Mon, 21 Oct 2024 12:24:57 +0100 Subject: [PATCH 04/16] Fixed namespace building process for Reown --- src/ChainSafe.Gaming.Reown/ReownProvider.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ChainSafe.Gaming.Reown/ReownProvider.cs b/src/ChainSafe.Gaming.Reown/ReownProvider.cs index 1a4ce9bb3..a35af3148 100644 --- a/src/ChainSafe.Gaming.Reown/ReownProvider.cs +++ b/src/ChainSafe.Gaming.Reown/ReownProvider.cs @@ -122,7 +122,7 @@ private async Task Initialize() var optionalNamespace = new ProposedNamespace // todo using optional namespaces like AppKit does, should they be required? { Chains = chainConfigSet.Configs - .Select(chainEntry => chainEntry.ChainId) + .Select(chainEntry => $"{ChainModel.EvmNamespace}:{chainEntry.ChainId}") .ToArray(), Methods = new[] { @@ -388,9 +388,9 @@ public override async Task Request(string method, params object[] paramete handler => signClient.CoreClient.Relayer.Publisher.OnPublishedMessage += handler, handler => signClient.CoreClient.Relayer.Publisher.OnPublishedMessage -= handler); - var chainId = GetChainId(); + // var chainId = GetChainId(); - return await ReownRequest(sessionTopic, method, chainId, parameters); + return await ReownRequest(sessionTopic, method, parameters); void OnPublishedMessage(object sender, PublishParams args) { @@ -403,7 +403,7 @@ void OnPublishedMessage(object sender, PublishParams args) if (connectedLocalWallet != null) { - redirection.Redirect(connectedLocalWallet.Id); + redirection.Redirect(connectedLocalWallet); } } } @@ -466,13 +466,13 @@ private string GetFullAddress() return defaultNamespace.Accounts[0]; } - private async Task ReownRequest(string topic, string method, string chainId, params object[] parameters) + private async Task ReownRequest(string topic, string method, params object[] parameters) { // Helper method to make a request using ReownSignClient. async Task MakeRequest() { var data = (TRequest)Activator.CreateInstance(typeof(TRequest), parameters); - return await signClient.Request(topic, data, chainId); + return await signClient.Request(topic, data); } switch (method) From ff87fda53b23f924ec613f80f71aea3fb04635c3 Mon Sep 17 00:00:00 2001 From: creeppak Date: Mon, 21 Oct 2024 16:28:57 +0100 Subject: [PATCH 05/16] Improved Reown session management and redirection to local wallet procedure --- src/ChainSafe.Gaming.Reown/ReownProvider.cs | 99 +++++++++++++++------ 1 file changed, 71 insertions(+), 28 deletions(-) diff --git a/src/ChainSafe.Gaming.Reown/ReownProvider.cs b/src/ChainSafe.Gaming.Reown/ReownProvider.cs index a35af3148..fb9ba45f7 100644 --- a/src/ChainSafe.Gaming.Reown/ReownProvider.cs +++ b/src/ChainSafe.Gaming.Reown/ReownProvider.cs @@ -50,7 +50,7 @@ public class ReownProvider : WalletProvider, ILifecycleParticipant, IConnectionH private bool initialized; private ConnectionHandlerConfig connectionHandlerConfig; private Dictionary optionalNamespaces; - private WalletModel connectedLocalWallet; + private WalletModel sessionWallet; public ReownProvider( IReownConfig config, @@ -74,8 +74,28 @@ public ReownProvider( this.reownHttpClient = reownHttpClient; } - public bool StoredSessionAvailable => signClient.AddressProvider.HasDefaultSession - && !string.IsNullOrWhiteSpace(signClient.AddressProvider.DefaultSession.Topic); + public bool StoredSessionAvailable + { + get + { + if (!signClient.AddressProvider.HasDefaultSession) + { + return false; // no session stored + } + + if (string.IsNullOrWhiteSpace(signClient.AddressProvider.DefaultSession.Topic)) + { + return false; // session topic is empty + } + + if (!signClient.Session.Keys.Contains(signClient.AddressProvider.DefaultSession.Topic)) + { + return false; // usually happens when session was closed on the wallet side + } + + return true; + } + } private bool OsManageWalletSelection => osMediator.Platform == Platform.Android; @@ -194,12 +214,6 @@ public override async Task Connect() ? await ConnectSession() : await RestoreSession(); - connectedLocalWallet = GetSessionLocalWallet(); - - ReownLogger.Log(connectedLocalWallet != null - ? $"Local wallet connected. \"{connectedLocalWallet.Name}\" set as locally connected wallet for the current session." - : "Remote wallet connected."); - var address = GetPlayerAddress(); if (!AddressExtensions.IsPublicAddress(address)) @@ -207,6 +221,13 @@ public override async Task Connect() throw new ReownIntegrationException("Public address provided by Reown is not valid."); } + sessionWallet = GetSessionWallet(); + + if (sessionWallet is null) + { + ReownLogger.LogError("Couldn't identify the wallet used to connect the session. Redirection is disabled."); + } + connected = true; await CheckAndSwitchNetwork(); @@ -295,13 +316,20 @@ private async Task ConnectSession() : null, RedirectToWallet = !OsManageWalletSelection - ? walletId => redirection.RedirectConnection(connectedData.Uri, walletId) + ? OnRedirectToWallet : null, RedirectOsManaged = OsManageWalletSelection ? () => redirection.RedirectConnectionOsManaged(connectedData.Uri) : null, }; + + void OnRedirectToWallet(string walletId) + { + signClient.CoreClient.Storage.SetItem("ChainSafe_RecentLocalWalletId", walletId); // saving wallet id to enable future redirection + redirection.RedirectConnection(connectedData.Uri, walletId); + } + var dialogTask = connectionHandler.ConnectUserWallet(connectionHandlerConfig); // awaiting handler task to catch exceptions, actually awaiting only for approval @@ -401,22 +429,19 @@ void OnPublishedMessage(object sender, PublishParams args) return; } - if (connectedLocalWallet != null) - { - redirection.Redirect(connectedLocalWallet); - } + TryRedirectToWallet(); } } - private WalletModel GetSessionLocalWallet() + private WalletModel GetSessionWallet() { var nativeUrl = RemoveSlash(session.Peer.Metadata.Url); - var sessionWallet = walletRegistry + var wallet = walletRegistry .SupportedWallets .FirstOrDefault(w => RemoveSlash(w.Homepage) == nativeUrl); - return sessionWallet; + return wallet; string RemoveSlash(string s) { @@ -426,15 +451,28 @@ string RemoveSlash(string s) } } - private void TryRedirectToWallet() + private async void TryRedirectToWallet() { - if (connectedLocalWallet == null) + if (sessionWallet is null) + { + return; // session wallet couldn't be determined, ignore redirection + } + + if (!await signClient.CoreClient.Storage.HasItem("ChainSafe_RecentLocalWalletId")) + { + return; // no local wallets connected - ignore redirection + } + + var recentLocalWalletId = await signClient.CoreClient.Storage.GetItem("ChainSafe_RecentLocalWalletId"); + + if (recentLocalWalletId != sessionWallet.Id) { + ReownLogger.Log("Last clicked local wallet was not used to connect the session. " + + "Assuming the wallet was connected remotely. No redirection is going to happen."); return; } - var sessionLocalWallet = GetSessionLocalWallet(); - redirection.Redirect(sessionLocalWallet); + redirection.Redirect(sessionWallet); // safe to redirect } private string GetPlayerAddress() @@ -472,7 +510,14 @@ private async Task ReownRequest(string topic, string method, params object async Task MakeRequest() { var data = (TRequest)Activator.CreateInstance(typeof(TRequest), parameters); - return await signClient.Request(topic, data); + try + { + return await signClient.Request(topic, data); + } + catch (KeyNotFoundException e) + { + throw new ReownIntegrationException("Can't execute request. The session was most likely terminated on the wallet side.", e); + } } switch (method) @@ -491,16 +536,14 @@ async Task MakeRequest() try { // Direct RPC request via http, Reown RPC url. - string chain = session.Namespaces.First().Value.Chains[0]; + var chain = session.Namespaces.First().Value.Chains[0]; - // Using Reown Blockchain API: https://docs.Reown.com/cloud/blockchain-api + // Using Reown Blockchain API: https://docs.reown.com/cloud/blockchain-api var url = $"https://rpc.walletconnect.com/v1?chainId={chain}&projectId={config.ProjectId}"; - string body = JsonConvert.SerializeObject(new RpcRequestMessage(Guid.NewGuid().ToString(), method, parameters)); - + var body = JsonConvert.SerializeObject(new RpcRequestMessage(Guid.NewGuid().ToString(), method, parameters)); var rawResult = await reownHttpClient.PostRaw(url, body, "application/json"); - - RpcResponseMessage response = JsonConvert.DeserializeObject(rawResult.Response); + var response = JsonConvert.DeserializeObject(rawResult.Response); return response.Result.ToObject(); } From 30d2fa94f1d75e19a494b923ea616d58cda98f30 Mon Sep 17 00:00:00 2001 From: creeppak Date: Tue, 22 Oct 2024 09:42:57 +0100 Subject: [PATCH 06/16] Added wallet filters for Desktop and Mobile for Reown --- .../Wallets/IWalletRegistry.cs | 3 ++- .../Wallets/ReownWalletRegistry.cs | 22 ++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/ChainSafe.Gaming.Reown/Wallets/IWalletRegistry.cs b/src/ChainSafe.Gaming.Reown/Wallets/IWalletRegistry.cs index 246006d32..de777a499 100644 --- a/src/ChainSafe.Gaming.Reown/Wallets/IWalletRegistry.cs +++ b/src/ChainSafe.Gaming.Reown/Wallets/IWalletRegistry.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Collections.ObjectModel; using ChainSafe.Gaming.Reown.Models; @@ -12,7 +13,7 @@ public interface IWalletRegistry /// Get all wallets supported on the current platform. /// /// Sequence of that the platform supports. - ReadOnlyCollection SupportedWallets { get; } + IEnumerable SupportedWallets { get; } /// /// Return model for the wallet by it's ID. diff --git a/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs b/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs index b4153d69f..6e9c9a1c3 100644 --- a/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs +++ b/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using ChainSafe.Gaming.Reown.Models; @@ -30,7 +29,7 @@ public ReownWalletRegistry(ReownHttpClient reownHttpClient, IReownConfig config, public static string RegistryUri => $"{Host}/getWallets"; - public ReadOnlyCollection SupportedWallets => platformWallets.AsReadOnly(); + public IEnumerable SupportedWallets => platformWallets.AsReadOnly(); async ValueTask ILifecycleParticipant.WillStartAsync() { @@ -51,7 +50,24 @@ async ValueTask ILifecycleParticipant.WillStartAsync() var parametersRaw = BuildUriParameters(parameters); var response = await reownHttpClient.Get(registryUri + parametersRaw); - platformWallets = response.AssertSuccess().Data; + var apiFilteredWallets = platformWallets = response.AssertSuccess().Data; + platformWallets = apiFilteredWallets + .Where(w => + { + switch (systemMediator.Platform) + { + case Platform.Editor: + case Platform.Desktop: + return !string.IsNullOrWhiteSpace(w.DesktopLink); + case Platform.IOS: + case Platform.Android: + return !string.IsNullOrWhiteSpace(w.MobileLink); + case Platform.WebGL: + default: + return true; + } + }) + .ToList(); /* todo implement and utilize IsWalletInstalled functionality * From d6551181398055dcc9dbd8271799d429f54f16d1 Mon Sep 17 00:00:00 2001 From: creeppak Date: Tue, 22 Oct 2024 09:43:14 +0100 Subject: [PATCH 07/16] Removed commented out code --- .../Editor/Reown/ReownConfigEditorBase.cs | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditorBase.cs b/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditorBase.cs index a1b90f37c..8cfe568bb 100644 --- a/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditorBase.cs +++ b/Packages/io.chainsafe.web3-unity/Editor/Reown/ReownConfigEditorBase.cs @@ -18,11 +18,6 @@ public override void OnInspectorGUI() { ListWalletProviders(); } - - // if (GUILayout.Button("Clear cache", GUILayout.ExpandWidth(false))) - // { - // DeleteStorage(); - // } } } @@ -30,29 +25,5 @@ private void ListWalletProviders() { Application.OpenURL(ReownWalletRegistry.RegistryUri); } - - // private void DeleteStorage() // todo check if this is needed, remove otherwise - // { - // var config = (IReownConfig)target; - // - // if (string.IsNullOrEmpty(config.StoragePath)) - // { - // Debug.LogError("StoragePath is empty."); - // return; - // } - // - // var storageFolderPath = - // DataStorage.BuildStoragePath(Application.persistentDataPath, config.StoragePath); - // - // if (!Directory.Exists(storageFolderPath)) - // { - // Debug.Log("Reown cache is already cleared."); - // return; - // } - // - // Directory.Delete(storageFolderPath, true); - // - // Debug.Log("Reown cache cleared."); - // } } } \ No newline at end of file From 57f5ff54d104d0202dccbcea607e54d4c086377e Mon Sep 17 00:00:00 2001 From: creeppak Date: Tue, 22 Oct 2024 09:43:36 +0100 Subject: [PATCH 08/16] Added WithForceNewSession extension method for ReownConfigAsset also --- .../Runtime/Scripts/Reown/ReownConfigExtensions.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs index 482d908ca..4ab6aed59 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs @@ -15,5 +15,17 @@ public static ReownConnectionProvider WithForceNewSession(this ReownConnectionPr provider.ForceNewSession = forceNewSession; return provider; } + + /// + /// Sets property of this config object. + /// + /// The config object. + /// New value for ForceNewSession property. + /// Updated object. + public static ReownConfigAsset WithForceNewSession(this ReownConfigAsset config, bool forceNewSession) + { + config.ForceNewSession = forceNewSession; + return config; + } } } \ No newline at end of file From 940899a8f22b763296fc4495c9f4c9fec547736f Mon Sep 17 00:00:00 2001 From: creeppak Date: Tue, 22 Oct 2024 10:06:10 +0100 Subject: [PATCH 09/16] Added Reown logo --- .../ReownConnectionProvider.cs.meta | 2 +- .../Runtime/Sprites/reown-logo.png | Bin 0 -> 4453 bytes .../Runtime/Sprites/reown-logo.png.meta | 127 ++++++++++++++++++ .../Resources/ReownConnectionProvider.asset | 2 +- 4 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 Packages/io.chainsafe.web3-unity/Runtime/Sprites/reown-logo.png create mode 100644 Packages/io.chainsafe.web3-unity/Runtime/Sprites/reown-logo.png.meta diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs.meta index 7709a95c6..88ae9c564 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs.meta +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs.meta @@ -5,7 +5,7 @@ MonoImporter: serializedVersion: 2 defaultReferences: - handlerPrefab: {fileID: 5250797134093199901, guid: 0c7c312ad6c521f4b8346ed8e9d7c664, type: 3} - - k__BackingField: {fileID: 21300000, guid: 7bb02b1b8d270114fa77d28d426c8c1c, type: 3} + - k__BackingField: {fileID: 21300000, guid: 9af22e71d3035844ca8ae6e9f2a538f5, type: 3} executionOrder: 0 icon: {instanceID: 0} userData: diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Sprites/reown-logo.png b/Packages/io.chainsafe.web3-unity/Runtime/Sprites/reown-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..58282b63ef51efba8f59c88a93ae2e68549a8f75 GIT binary patch literal 4453 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 literal 0 HcmV?d00001 diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Sprites/reown-logo.png.meta b/Packages/io.chainsafe.web3-unity/Runtime/Sprites/reown-logo.png.meta new file mode 100644 index 000000000..98b0937a4 --- /dev/null +++ b/Packages/io.chainsafe.web3-unity/Runtime/Sprites/reown-logo.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 9af22e71d3035844ca8ae6e9f2a538f5 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/UnitySampleProject/Assets/Resources/ReownConnectionProvider.asset b/src/UnitySampleProject/Assets/Resources/ReownConnectionProvider.asset index 5489c2af9..ecc61d490 100644 --- a/src/UnitySampleProject/Assets/Resources/ReownConnectionProvider.asset +++ b/src/UnitySampleProject/Assets/Resources/ReownConnectionProvider.asset @@ -31,5 +31,5 @@ MonoBehaviour: k__BackingField: k__BackingField: 1 k__BackingField: 0 - k__BackingField: {fileID: 21300000, guid: 7bb02b1b8d270114fa77d28d426c8c1c, type: 3} + k__BackingField: {fileID: 21300000, guid: 9af22e71d3035844ca8ae6e9f2a538f5, type: 3} k__BackingField: Reown From 3875060374db2df84ffbd2bf8de2c86aa348dfd5 Mon Sep 17 00:00:00 2001 From: creeppak Date: Tue, 22 Oct 2024 12:15:52 +0100 Subject: [PATCH 10/16] Moved the BuildUriParameters method into HttpUtils.cs --- .../Wallets/ReownWalletRegistry.cs | 12 ++---------- .../Web3/Core/Environment/Http/HttpUtils.cs | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 src/ChainSafe.Gaming/Web3/Core/Environment/Http/HttpUtils.cs diff --git a/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs b/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs index 6e9c9a1c3..dffdae562 100644 --- a/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs +++ b/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs @@ -4,6 +4,7 @@ using ChainSafe.Gaming.Reown.Models; using ChainSafe.Gaming.Web3.Core; using ChainSafe.Gaming.Web3.Environment; +using ChainSafe.Gaming.Web3.Environment.Http; namespace ChainSafe.Gaming.Reown.Wallets { @@ -47,7 +48,7 @@ async ValueTask ILifecycleParticipant.WillStartAsync() { "exclude", BuildWalletIdsFilter(config.ExcludeWalletIds) }, }; - var parametersRaw = BuildUriParameters(parameters); + var parametersRaw = HttpUtils.BuildUriParameters(parameters); var response = await reownHttpClient.Get(registryUri + parametersRaw); var apiFilteredWallets = platformWallets = response.AssertSuccess().Data; @@ -95,15 +96,6 @@ string BuildWalletIdsFilter(IList walletIds) } } - private static string BuildUriParameters(Dictionary parameters) - { - var parametersRaw = parameters - .Where(p => !string.IsNullOrWhiteSpace(p.Value)) - .Select(pair => $"{pair.Key}={pair.Value}"); - - return $"?{string.Join("&", parametersRaw)}"; - } - ValueTask ILifecycleParticipant.WillStopAsync() => new(Task.CompletedTask); public WalletModel GetWallet(string id) diff --git a/src/ChainSafe.Gaming/Web3/Core/Environment/Http/HttpUtils.cs b/src/ChainSafe.Gaming/Web3/Core/Environment/Http/HttpUtils.cs new file mode 100644 index 000000000..a6e56cd0e --- /dev/null +++ b/src/ChainSafe.Gaming/Web3/Core/Environment/Http/HttpUtils.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Linq; + +namespace ChainSafe.Gaming.Web3.Environment.Http +{ + public static class HttpUtils + { + public static string BuildUriParameters(Dictionary parameters) + { + var parametersRaw = parameters + .Where(p => !string.IsNullOrWhiteSpace(p.Value)) + .Select(pair => $"{pair.Key}={pair.Value}"); + + return $"?{string.Join("&", parametersRaw)}"; + } + } +} \ No newline at end of file From 9273001c65ec2b4da8f0d5faa9c8fd983f6d1067 Mon Sep 17 00:00:00 2001 From: creeppak Date: Tue, 22 Oct 2024 13:54:12 +0100 Subject: [PATCH 11/16] Updated Packages build process to include Reown --- Setup/dependencies.json | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Setup/dependencies.json b/Setup/dependencies.json index 0ca9b64ca..50da88bd8 100644 --- a/Setup/dependencies.json +++ b/Setup/dependencies.json @@ -22,7 +22,6 @@ "Nethereum.Web3", "ChainSafe.Gaming.Unity", "System.Buffers", - "ChainSafe.Gaming.WalletConnect", "System.Memory", "ChainSafe.Gaming", "System.Numerics.Vectors", @@ -43,24 +42,14 @@ "NBitcoin", "System.Threading.Tasks.Extensions", "Nethereum.ABI", - "WalletConnectSharp.Auth", "Nethereum.Accounts", - "WalletConnectSharp.Common", - "WalletConnectSharp.Events", "Nethereum.BlockchainProcessing", - "WalletConnectSharp.Core", "Nethereum.Contracts", - "WalletConnectSharp.Crypto", "Nethereum.Hex", "Nethereum.JsonRpc.Client", - "WalletConnectSharp.Network.Websocket", - "WalletConnectSharp.Network", "Nethereum.JsonRpc.RpcClient", - "WalletConnectSharp.Sign", "Nethereum.KeyStore", - "WalletConnectSharp.Storage", "Nethereum.Merkle.Patricia", - "WalletConnectSharp.Web3Wallet", "Nethereum.Merkle", "Websocket.Client", "Nethereum.Siwe.Core", @@ -68,7 +57,16 @@ "Nethereum.UI", "ChainSafe.Gaming.Unity.MetaMask", "ChainSafe.Gaming.Marketplace", - "ChainSafe.Gaming.Unity.EthereumWindow" + "ChainSafe.Gaming.Unity.EthereumWindow", + "ChainSafe.Gaming.Reown", + "Reown.Core", + "Reown.Core.Common", + "Reown.Core.Crypto", + "Reown.Core.Network", + "Reown.Core.Network.WebSocket", + "Reown.Core.Storage", + "Reown.Sign", + "Reown.WalletKit" ] }, { From c60f419cd9572f95b6310ad742b5e593bdb4c541 Mon Sep 17 00:00:00 2001 From: creeppak Date: Tue, 22 Oct 2024 15:59:15 +0100 Subject: [PATCH 12/16] Updated a Reown log message --- src/ChainSafe.Gaming.Reown/ReownProvider.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ChainSafe.Gaming.Reown/ReownProvider.cs b/src/ChainSafe.Gaming.Reown/ReownProvider.cs index fb9ba45f7..a7c787881 100644 --- a/src/ChainSafe.Gaming.Reown/ReownProvider.cs +++ b/src/ChainSafe.Gaming.Reown/ReownProvider.cs @@ -225,7 +225,9 @@ public override async Task Connect() if (sessionWallet is null) { - ReownLogger.LogError("Couldn't identify the wallet used to connect the session. Redirection is disabled."); + ReownLogger.LogError("Couldn't identify the wallet used to connect the session. " + + "Redirection is disabled. " + + $"URL from wallet metadata is \"{session.Peer.Metadata.Url}\"."); } connected = true; From 1c26c7e0ea6ade21122f74b03f0f6aa6bef331c5 Mon Sep 17 00:00:00 2001 From: creeppak Date: Tue, 22 Oct 2024 16:03:38 +0100 Subject: [PATCH 13/16] Linter fixes --- .../Editor/ConnectionHandlerEditor.cs | 2 +- .../Editor/Web3SettingsEditor.cs | 4 +-- .../Runtime/GUI/GuiCoordinationSystem.cs | 16 +++++----- .../Runtime/GUI/GuiInfoOverlay.cs | 6 ++-- .../Runtime/GUI/GuiLayer.cs | 4 +-- .../Runtime/GUI/GuiManager.cs | 12 ++++---- .../Runtime/GUI/GuiOrientationSystem.cs | 2 +- .../Runtime/GUI/GuiOverlayManager.cs | 6 ++-- .../Runtime/GUI/GuiScreen.cs | 10 +++---- .../Runtime/GUI/GuiScreenFactory.cs | 2 +- .../Runtime/GUI/IGuiScreen.cs | 2 +- .../Runtime/Scripts/ConnectToWallet.cs | 6 ++-- .../Scripts/Connection/ConnectionProvider.cs | 12 ++++---- .../Connection/ReownConnectionProvider.cs | 4 +-- .../Scripts/Reown/ReownConfigExtensions.cs | 2 +- .../Runtime/Scripts/Samples/Samples.cs | 2 +- .../Runtime/Scripts/UI/ConnectScreen.cs | 10 +++---- .../Scripts/UI/ConnectionProviderButton.cs | 2 +- .../Runtime/Scripts/Web3Unity.cs | 4 +-- .../Models/WalletModel.cs | 30 ++++++++++++------- .../Wallets/WalletRegistryResponse.cs | 6 ++-- 21 files changed, 78 insertions(+), 66 deletions(-) diff --git a/Packages/io.chainsafe.web3-unity/Editor/ConnectionHandlerEditor.cs b/Packages/io.chainsafe.web3-unity/Editor/ConnectionHandlerEditor.cs index b50d22fff..841ecaeb6 100644 --- a/Packages/io.chainsafe.web3-unity/Editor/ConnectionHandlerEditor.cs +++ b/Packages/io.chainsafe.web3-unity/Editor/ConnectionHandlerEditor.cs @@ -171,7 +171,7 @@ public override void OnInspectorGUI() _allProviders.Add(newProvider); _editorFoldouts[providerType] = true; - + providersProperty.InsertArrayElementAtIndex(providersProperty.arraySize); providersProperty.GetArrayElementAtIndex(providersProperty.arraySize - 1).objectReferenceValue = newProvider; diff --git a/Packages/io.chainsafe.web3-unity/Editor/Web3SettingsEditor.cs b/Packages/io.chainsafe.web3-unity/Editor/Web3SettingsEditor.cs index fea3604b1..be391366d 100644 --- a/Packages/io.chainsafe.web3-unity/Editor/Web3SettingsEditor.cs +++ b/Packages/io.chainsafe.web3-unity/Editor/Web3SettingsEditor.cs @@ -229,10 +229,10 @@ private bool IsPrimaryChain(ChainConfigEntry entry) private void SetPrimaryChain(ChainConfigEntry entry) { var indexOf = web3Config.ChainConfigs.IndexOf(entry); - + web3Config.ChainConfigs.RemoveAt(indexOf); web3Config.ChainConfigs.Insert(0, entry); - + InitializeChainItems(); chainsScrollPosition = Vector2.zero; } diff --git a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiCoordinationSystem.cs b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiCoordinationSystem.cs index d19f48372..714b4ec1d 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiCoordinationSystem.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiCoordinationSystem.cs @@ -16,16 +16,16 @@ public ScreenRecord(IGuiScreen screen) Visible = false; } } - + private readonly List activeScreens = new(); private int currentVisibleSortOrder = int.MinValue; - + public void Register(IGuiScreen screen) { activeScreens.Add(new ScreenRecord(screen)); UpdateStackVisibility(); } - + public void Unregister(IGuiScreen screen) { var record = activeScreens.Find(r => r.Screen == screen); @@ -50,11 +50,11 @@ private void UpdateStackVisibility() var opaqueScreenLayers = activeScreens .Select(r => r.Screen.Layer) .Where(l => !l.Transparent); - + var newVisibleSortOrder = opaqueScreenLayers.Any() ? opaqueScreenLayers.Max(l => l.SortOrder) : int.MinValue; - + if (newVisibleSortOrder == currentVisibleSortOrder) return; currentVisibleSortOrder = newVisibleSortOrder; @@ -62,19 +62,19 @@ private void UpdateStackVisibility() foreach (var activeScreen in activeScreens) { var show = activeScreen.Screen.Layer.SortOrder >= currentVisibleSortOrder; - + if (show && !activeScreen.Visible) { ShowScreen(activeScreen); continue; } - + if (!show && activeScreen.Visible) { HideScreen(activeScreen); continue; } - + // ignore } } diff --git a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiInfoOverlay.cs b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiInfoOverlay.cs index 7d6628fed..653b93758 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiInfoOverlay.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiInfoOverlay.cs @@ -11,7 +11,7 @@ public class GuiInfoOverlay : MonoBehaviour public GameObject ErrorIcon; public GameObject LoadingIcon; public Button CloseButton; - + private bool closeOnClick; private Action onClose; private Action onRelease; @@ -29,7 +29,7 @@ public void Initialize(int id, GuiOverlayType type, string message, bool closeOn this.onClose = onClose; this.closeOnClick = closeOnClick; onRelease = release; - + ErrorIcon.SetActive(type == GuiOverlayType.Error); LoadingIcon.SetActive(type == GuiOverlayType.Loading); Message.text = message; @@ -41,7 +41,7 @@ private void OnScreenClick() { return; } - + Hide(); } diff --git a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiLayer.cs b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiLayer.cs index 4384d9ad6..bff70c6a8 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiLayer.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiLayer.cs @@ -3,6 +3,6 @@ [CreateAssetMenu(menuName = "ChainSafe/Misc/GUI Layer", fileName = "New GUI Layer", order = 1000)] public class GuiLayer : ScriptableObject { - [field:SerializeField] public int SortOrder { get; private set; } - [field:SerializeField] public bool Transparent { get; private set; } + [field: SerializeField] public int SortOrder { get; private set; } + [field: SerializeField] public bool Transparent { get; private set; } } \ No newline at end of file diff --git a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiManager.cs b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiManager.cs index a319ae115..38409c459 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiManager.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiManager.cs @@ -14,21 +14,21 @@ private static GuiManager LoadPrefab() { var prefab = Resources.Load(ResourceName); var manager = Instantiate(prefab); - + if (manager.HideInHierarchy) { manager.gameObject.hideFlags = HideFlags.HideInHierarchy; } - + DontDestroyOnLoad(manager); return manager; } - + [SerializeField] private bool HideInHierarchy = true; - [field:SerializeField] public GuiOrientationSystem Orientation { get; private set; } - [field:SerializeField] public GuiOverlayManager Overlays { get; private set; } - + [field: SerializeField] public GuiOrientationSystem Orientation { get; private set; } + [field: SerializeField] public GuiOverlayManager Overlays { get; private set; } + public GuiCoordinationSystem Coordination { get; } = new(); } } \ No newline at end of file diff --git a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiOrientationSystem.cs b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiOrientationSystem.cs index d604a52b1..e04c0421a 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiOrientationSystem.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiOrientationSystem.cs @@ -7,7 +7,7 @@ public class GuiOrientationSystem : MonoBehaviour public float AspectRatioThreshold = 1f; public bool Debug; public GuiOrientation DebugOrientationValue; - + public GuiOrientation Initial { get; private set; } private void Awake() diff --git a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiOverlayManager.cs b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiOverlayManager.cs index 4fc85d51c..6858a6f9b 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiOverlayManager.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiOverlayManager.cs @@ -9,11 +9,11 @@ public class GuiOverlayManager : MonoBehaviour { public GuiScreenFactory screenFactory; public Transform container; - + private readonly List activeOverlays = new(); private ObjectPool pool; - + private int overlayCounter = 1000; // offset to detect when default integer value is sent to one of the methods private void Awake() @@ -37,7 +37,7 @@ public void Hide(int overlayId) { throw new InvalidOperationException($"There is no active Overlay with id {overlayId} to hide."); } - + overlay.Hide(); activeOverlays.Remove(overlay); } diff --git a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiScreen.cs b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiScreen.cs index da1e18ab2..6c8dc67fe 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiScreen.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiScreen.cs @@ -4,12 +4,12 @@ namespace ChainSafe.Gaming.GUI { public class GuiScreen : MonoBehaviour, IGuiScreen { - [field:SerializeField] public GuiLayer Layer { get; set; } - + [field: SerializeField] public GuiLayer Layer { get; set; } + public Canvas Canvas; // set layer sort order to canvas sort order? public GameObject Content; public Animation Animation; - + private void OnEnable() { GuiManager.Instance.Coordination.Register(this); @@ -33,7 +33,7 @@ public void OnShowing() { Canvas.enabled = true; Content.gameObject.SetActive(true); - + if (Animation) { Animation.Play(); @@ -44,7 +44,7 @@ public void OnHiding() { Canvas.enabled = false; Content.gameObject.SetActive(false); - + if (Animation) { Animation.Stop(); diff --git a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiScreenFactory.cs b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiScreenFactory.cs index 0da5dffba..ddfac124e 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiScreenFactory.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/GUI/GuiScreenFactory.cs @@ -17,7 +17,7 @@ public T GetSingle() singleScreen = BuildInternal(); singleScreen.gameObject.SetActive(false); } - + return singleScreen.GetComponent(); } diff --git a/Packages/io.chainsafe.web3-unity/Runtime/GUI/IGuiScreen.cs b/Packages/io.chainsafe.web3-unity/Runtime/GUI/IGuiScreen.cs index 4d10b3fef..8d8b3f9db 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/GUI/IGuiScreen.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/GUI/IGuiScreen.cs @@ -3,7 +3,7 @@ public interface IGuiScreen { GuiLayer Layer { get; } - + void OnShowing(); void OnHiding(); } diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/ConnectToWallet.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/ConnectToWallet.cs index f944beb42..f36cb3d8d 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/ConnectToWallet.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/ConnectToWallet.cs @@ -16,15 +16,15 @@ public class ConnectToWallet : ServiceAdapter, IWeb3InitializedHandler, ILogoutH { [SerializeField] private bool rememberMe = true; - [Space] [SerializeField] private Button connectButton; + [Space][SerializeField] private Button connectButton; [SerializeField] private Button disconnectButton; - [Space] [SerializeField] private TextMeshProUGUI addressText; + [Space][SerializeField] private TextMeshProUGUI addressText; [SerializeField] private Button copyAddressButton; - [Space] [SerializeField] private Transform connectedTransform; + [Space][SerializeField] private Transform connectedTransform; [SerializeField] private Transform disconnectedTransform; diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ConnectionProvider.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ConnectionProvider.cs index de6e2a04a..74b7fe875 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ConnectionProvider.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ConnectionProvider.cs @@ -18,22 +18,22 @@ public abstract class ConnectionProvider : ScriptableObject, IServiceAdapter /// Could be platform specific or other conditions. /// public abstract bool IsAvailable { get; } - + /// /// Icon of the button to connect to the wallet. /// public abstract Sprite ButtonIcon { get; protected set; } - + /// /// Text of the button to connect to the wallet. /// public abstract string ButtonText { get; protected set; } - + /// /// Should loading overlay be shown when initiating a connection using this ConnectionProvider; /// public abstract bool DisplayLoadingOnConnection { get; } - + protected bool RememberSession { get; private set; } /// @@ -76,13 +76,13 @@ public Web3Builder ConfigureServices(Web3Builder web3Builder) /// /// Service collection to add services to. protected abstract void ConfigureServices(IWeb3ServiceCollection services); - + /// /// Check if a saved session is available. /// /// True if a saved session is available. public abstract Task SavedSessionAvailable(); - + /// /// Handle exception thrown during connection. /// Different providers might handler it differently. diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs index 62552d5ac..1c80e6b37 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs @@ -22,7 +22,7 @@ public class ReownConnectionProvider : ConnectionProvider, IReownConfig, IConnec [SerializeField] private ConnectionHandlerBehaviour handlerPrefab; [SerializeField] private List includeWalletIds; [SerializeField] private List excludeWalletIds; - + [field: SerializeField] public string ProjectId { get; private set; } [field: SerializeField] public string ProjectName { get; private set; } @@ -44,7 +44,7 @@ public class ReownConnectionProvider : ConnectionProvider, IReownConfig, IConnec public override Sprite ButtonIcon { get; protected set; } [field: SerializeField] public override string ButtonText { get; protected set; } = "Reown"; - + private bool _storedSessionAvailable; private ConnectionHandlerBehaviour _loadedHandler; private IConnectionBuilder _connectionBuilder; diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs index 4ab6aed59..9b84871c6 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigExtensions.cs @@ -15,7 +15,7 @@ public static ReownConnectionProvider WithForceNewSession(this ReownConnectionPr provider.ForceNewSession = forceNewSession; return provider; } - + /// /// Sets property of this config object. /// diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Samples/Samples.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Samples/Samples.cs index a1c8db595..db8bb9af7 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Samples/Samples.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Samples/Samples.cs @@ -85,7 +85,7 @@ private async void TryExecute(MethodInfo method, ISample instance) || e is ServiceNotBoundWeb3Exception) { Web3Unity.ConnectScreen.Open(); - + throw new AggregateException(new Web3Exception("Connection not found. Please connect your wallet first."), e); } diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/ConnectScreen.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/ConnectScreen.cs index 0f8240eb7..e597aee49 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/ConnectScreen.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/ConnectScreen.cs @@ -15,7 +15,7 @@ public class ConnectScreen : MonoBehaviour [SerializeField] private RectTransform providerContainer; [SerializeField] private ConnectionProviderButton providerButtonPrefab; [SerializeField] private Button closeButton; - + private int loadingOverlayId; private void Awake() @@ -39,7 +39,7 @@ async void ConnectClicked(ConnectionProvider provider) await TryConnect(provider); } } - + /// /// Try to Connect and displays error and throws exception on a failed attempt. /// @@ -60,7 +60,7 @@ private async Task TryConnect(ConnectionProvider provider) { DisplayError( "Connection failed, please try again."); - + Debug.LogException(e); } } @@ -82,7 +82,7 @@ public void Close() { gameObject.SetActive(false); } - + /// /// Display Error. /// @@ -101,7 +101,7 @@ private void ShowLoading(string message) DisableButtons(); loadingOverlayId = GuiManager.Instance.Overlays.Show(GuiOverlayType.Loading, message, false, EnableButtons); } - + /// /// Hide Loading overlay. /// diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/ConnectionProviderButton.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/ConnectionProviderButton.cs index 2bd351273..3b27d811e 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/ConnectionProviderButton.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/ConnectionProviderButton.cs @@ -10,7 +10,7 @@ public class ConnectionProviderButton : MonoBehaviour public Image Icon; public TMP_Text Text; public Button Button; - + private Action onClick; private void Awake() diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Web3Unity.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Web3Unity.cs index d41132293..61225ad00 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Web3Unity.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Web3Unity.cs @@ -74,7 +74,7 @@ public static ConnectScreen ConnectScreen } [SerializeField] private GuiScreenFactory connectScreenFactory; - + private CWeb3 _web3; private ConnectionHandler _connectionHandler; private ConnectScreen _connectScreen; @@ -272,7 +272,7 @@ public Task OnWeb3Initialized(CWeb3 web3) { _connectScreen.Close(); } - + Web3Initialized?.Invoke((_web3, _web3.ServiceProvider.GetService(typeof(ISigner)) == null)); return Task.CompletedTask; diff --git a/src/ChainSafe.Gaming.Reown/Models/WalletModel.cs b/src/ChainSafe.Gaming.Reown/Models/WalletModel.cs index 0ff171b9d..8818587a8 100644 --- a/src/ChainSafe.Gaming.Reown/Models/WalletModel.cs +++ b/src/ChainSafe.Gaming.Reown/Models/WalletModel.cs @@ -7,24 +7,34 @@ namespace ChainSafe.Gaming.Reown.Models /// public class WalletModel { - [JsonProperty("id")] public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("homepage")] public string Homepage { get; set; } + [JsonProperty("homepage")] + public string Homepage { get; set; } - [JsonProperty("image_id")] public string ImageId { get; set; } + [JsonProperty("image_id")] + public string ImageId { get; set; } - [JsonProperty("order")] public int Order { get; set; } + [JsonProperty("order")] + public int Order { get; set; } - [JsonProperty("mobile_link")] public string MobileLink { get; set; } + [JsonProperty("mobile_link")] + public string MobileLink { get; set; } - [JsonProperty("desktop_link")] public string DesktopLink { get; set; } + [JsonProperty("desktop_link")] + public string DesktopLink { get; set; } - [JsonProperty("webapp_link")] public string WebappLink { get; set; } + [JsonProperty("webapp_link")] + public string WebappLink { get; set; } - [JsonProperty("app_store")] public string AppStore { get; set; } + [JsonProperty("app_store")] + public string AppStore { get; set; } - [JsonProperty("play_store")] public string PlayStore { get; set; } + [JsonProperty("play_store")] + public string PlayStore { get; set; } } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming.Reown/Wallets/WalletRegistryResponse.cs b/src/ChainSafe.Gaming.Reown/Wallets/WalletRegistryResponse.cs index b1b609bef..390bb44fb 100644 --- a/src/ChainSafe.Gaming.Reown/Wallets/WalletRegistryResponse.cs +++ b/src/ChainSafe.Gaming.Reown/Wallets/WalletRegistryResponse.cs @@ -6,8 +6,10 @@ namespace ChainSafe.Gaming.Reown.Wallets { public class WalletRegistryResponse { - [JsonProperty("count")] public int Count { get; set; } + [JsonProperty("count")] + public int Count { get; set; } - [JsonProperty("data")] public List Data { get; set; } + [JsonProperty("data")] + public List Data { get; set; } } } \ No newline at end of file From 4ea40b298b55837433fb03008779f9d3ba270ec3 Mon Sep 17 00:00:00 2001 From: creeppak Date: Tue, 22 Oct 2024 16:03:52 +0100 Subject: [PATCH 14/16] Removed commented out code --- src/ChainSafe.Gaming.Reown/ReownProvider.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ChainSafe.Gaming.Reown/ReownProvider.cs b/src/ChainSafe.Gaming.Reown/ReownProvider.cs index a7c787881..5f6a79a95 100644 --- a/src/ChainSafe.Gaming.Reown/ReownProvider.cs +++ b/src/ChainSafe.Gaming.Reown/ReownProvider.cs @@ -419,7 +419,6 @@ public override async Task Request(string method, params object[] paramete handler => signClient.CoreClient.Relayer.Publisher.OnPublishedMessage -= handler); // var chainId = GetChainId(); - return await ReownRequest(sessionTopic, method, parameters); void OnPublishedMessage(object sender, PublishParams args) From 555f53581fe25a200d9ab0cf2d59f9101e03cbf2 Mon Sep 17 00:00:00 2001 From: creeppak Date: Tue, 22 Oct 2024 16:27:48 +0100 Subject: [PATCH 15/16] Reown integration polishing --- .../Connection/ReownConnectionProvider.cs | 1 + .../Reown/Dialog/ConnectionDialogBase.cs | 1 + .../Runtime/Scripts/Reown/ReownConfigAsset.cs | 1 + .../Connection/ConnectionHandlerConfig.cs | 1 + src/ChainSafe.Gaming.Reown/IReownConfig.cs | 1 + .../Models/ChainModel.cs | 48 ------------------- .../Models/ImageUrlsModel.cs | 28 ----------- .../Models/WalletLinkModel.cs | 24 ---------- .../RedirectionHandler.cs | 10 ---- src/ChainSafe.Gaming.Reown/ReownHttpClient.cs | 3 ++ src/ChainSafe.Gaming.Reown/ReownProvider.cs | 8 ++-- .../Wallets/ReownWalletRegistry.cs | 4 +- .../{ => Wallets}/WalletLocationOption.cs | 2 +- .../WalletLocationOptionsExtensions.cs | 2 +- 14 files changed, 17 insertions(+), 117 deletions(-) delete mode 100644 src/ChainSafe.Gaming.Reown/Models/ChainModel.cs delete mode 100644 src/ChainSafe.Gaming.Reown/Models/ImageUrlsModel.cs delete mode 100644 src/ChainSafe.Gaming.Reown/Models/WalletLinkModel.cs rename src/ChainSafe.Gaming.Reown/{ => Wallets}/WalletLocationOption.cs (81%) rename src/ChainSafe.Gaming.Reown/{ => Wallets}/WalletLocationOptionsExtensions.cs (96%) diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs index 1c80e6b37..e44c880f1 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Connection/ReownConnectionProvider.cs @@ -3,6 +3,7 @@ using ChainSafe.Gaming.Reown; using ChainSafe.Gaming.Reown.Connection; using ChainSafe.Gaming.Reown.Dialog; +using ChainSafe.Gaming.Reown.Wallets; using ChainSafe.Gaming.Web3.Build; using ChainSafe.Gaming.Web3.Evm.Wallet; using Reown.Core; diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs index 67af022bc..854cfabba 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/Dialog/ConnectionDialogBase.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using ChainSafe.Gaming.Reown.Connection; using ChainSafe.Gaming.Reown.Models; +using ChainSafe.Gaming.Reown.Wallets; using UnityEngine; namespace ChainSafe.Gaming.Reown.Dialog diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigAsset.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigAsset.cs index 124dd1035..cdca5a59e 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigAsset.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/Reown/ReownConfigAsset.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using ChainSafe.Gaming.Reown.Connection; using ChainSafe.Gaming.Reown.Dialog; +using ChainSafe.Gaming.Reown.Wallets; using Reown.Core; using Reown.Core.Network; using Reown.Core.Network.Interfaces; diff --git a/src/ChainSafe.Gaming.Reown/Connection/ConnectionHandlerConfig.cs b/src/ChainSafe.Gaming.Reown/Connection/ConnectionHandlerConfig.cs index 4dc1ef611..eeee9afea 100644 --- a/src/ChainSafe.Gaming.Reown/Connection/ConnectionHandlerConfig.cs +++ b/src/ChainSafe.Gaming.Reown/Connection/ConnectionHandlerConfig.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using ChainSafe.Gaming.Reown.Models; +using ChainSafe.Gaming.Reown.Wallets; namespace ChainSafe.Gaming.Reown.Connection { diff --git a/src/ChainSafe.Gaming.Reown/IReownConfig.cs b/src/ChainSafe.Gaming.Reown/IReownConfig.cs index 2f945c7cc..d9b47bd68 100644 --- a/src/ChainSafe.Gaming.Reown/IReownConfig.cs +++ b/src/ChainSafe.Gaming.Reown/IReownConfig.cs @@ -1,6 +1,7 @@ #nullable enable using System.Collections.Generic; using ChainSafe.Gaming.Reown.Connection; +using ChainSafe.Gaming.Reown.Wallets; using ChainSafe.Gaming.Web3.Environment; using ChainSafe.Gaming.Web3.Evm.Wallet; using Reown.Core; diff --git a/src/ChainSafe.Gaming.Reown/Models/ChainModel.cs b/src/ChainSafe.Gaming.Reown/Models/ChainModel.cs deleted file mode 100644 index 99abbcf6a..000000000 --- a/src/ChainSafe.Gaming.Reown/Models/ChainModel.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace ChainSafe.Gaming.Reown.Models -{ - /// - /// Chain model containing fields used for Reown. - /// - public class ChainModel - { - /// - /// Default namespace for EVM. - /// - public const string EvmNamespace = "eip155"; - - /// - /// Initializes a new instance of the class. - /// - /// Chain Namespace - example "eip155:" for EVMs. - /// Chain Id. - /// Name of the network. - public ChainModel(string chainNamespace, string chainId, string name) - { - ChainNamespace = chainNamespace; - - ChainId = chainId; - - Name = name; - } - - /// - /// Chain Namespace - example "eip155:" for EVMs. - /// - public string ChainNamespace { get; private set; } - - /// - /// Chain Id. - /// - public string ChainId { get; private set; } - - /// - /// Name of the network. - /// - public string Name { get; private set; } - - /// - /// Full chain Id, together with . - /// - public string FullChainId => $"{ChainNamespace}:{ChainId}"; - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.Reown/Models/ImageUrlsModel.cs b/src/ChainSafe.Gaming.Reown/Models/ImageUrlsModel.cs deleted file mode 100644 index bd01ff2b7..000000000 --- a/src/ChainSafe.Gaming.Reown/Models/ImageUrlsModel.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Newtonsoft.Json; - -namespace ChainSafe.Gaming.Reown.Models -{ - /// - /// Reown Model used in for Wallet's image url if any. - /// - public class ImageUrlsModel - { - /// - /// Small size wallet icon image url. - /// - [JsonProperty("sm")] - public string SmallUrl { get; private set; } - - /// - /// Medium size wallet icon image url. - /// - [JsonProperty("md")] - public string MediumUrl { get; private set; } - - /// - /// Large size wallet icon image url. - /// - [JsonProperty("lg")] - public string LargeUrl { get; private set; } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.Reown/Models/WalletLinkModel.cs b/src/ChainSafe.Gaming.Reown/Models/WalletLinkModel.cs deleted file mode 100644 index 9f83acdd5..000000000 --- a/src/ChainSafe.Gaming.Reown/Models/WalletLinkModel.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Newtonsoft.Json; - -namespace ChainSafe.Gaming.Reown.Models -{ - /// - /// Wallet linking model used for opening/redirecting to wallets using a deeplink from either a Native or a Universal/http protocol. - /// - public struct WalletLinkModel - { - /// - /// Native protocol deeplink for redirecting to wallet. - /// If available this redirects without opening a browser. - /// - [JsonProperty("native")] - public string NativeProtocol { get; private set; } - - /// - /// Universal url deeplink for redirecting to wallet. - /// If available this opens a browser that triggers a native deeplink. - /// - [JsonProperty("universal")] - public string UniversalUrl { get; private set; } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.Reown/RedirectionHandler.cs b/src/ChainSafe.Gaming.Reown/RedirectionHandler.cs index fe57badd3..32ab59e35 100644 --- a/src/ChainSafe.Gaming.Reown/RedirectionHandler.cs +++ b/src/ChainSafe.Gaming.Reown/RedirectionHandler.cs @@ -21,16 +21,6 @@ public RedirectionHandler(IWalletRegistry walletRegistry, IOperatingSystemMediat this.walletRegistry = walletRegistry; } - private static bool NativeProtocolAvailable(WalletLinkModel linkData) - { - return !string.IsNullOrWhiteSpace(linkData.NativeProtocol) && linkData.NativeProtocol != ":"; - } - - private static bool UniversalProtocolAvailable(WalletLinkModel linkData) - { - return !string.IsNullOrWhiteSpace(linkData.UniversalUrl); - } - /// /// Redirect for connection using the pre-selected wallet. /// diff --git a/src/ChainSafe.Gaming.Reown/ReownHttpClient.cs b/src/ChainSafe.Gaming.Reown/ReownHttpClient.cs index 22179caf8..da10d73ae 100644 --- a/src/ChainSafe.Gaming.Reown/ReownHttpClient.cs +++ b/src/ChainSafe.Gaming.Reown/ReownHttpClient.cs @@ -5,6 +5,9 @@ namespace ChainSafe.Gaming.Reown { + /// + /// An HTTP client wrapper that adds the HTTP headers required by the Reown API to each request. + /// public class ReownHttpClient : IHttpClient { private readonly IHttpClient originalClient; diff --git a/src/ChainSafe.Gaming.Reown/ReownProvider.cs b/src/ChainSafe.Gaming.Reown/ReownProvider.cs index 5f6a79a95..0a3f7dac4 100644 --- a/src/ChainSafe.Gaming.Reown/ReownProvider.cs +++ b/src/ChainSafe.Gaming.Reown/ReownProvider.cs @@ -33,6 +33,8 @@ namespace ChainSafe.Gaming.Reown /// public class ReownProvider : WalletProvider, ILifecycleParticipant, IConnectionHelper { + private const string EvmNamespace = "eip155"; + private readonly ILogWriter logWriter; private readonly IReownConfig config; private readonly IChainConfig chainConfig; @@ -142,7 +144,7 @@ private async Task Initialize() var optionalNamespace = new ProposedNamespace // todo using optional namespaces like AppKit does, should they be required? { Chains = chainConfigSet.Configs - .Select(chainEntry => $"{ChainModel.EvmNamespace}:{chainEntry.ChainId}") + .Select(chainEntry => $"{EvmNamespace}:{chainEntry.ChainId}") .ToArray(), Methods = new[] { @@ -164,7 +166,7 @@ private async Task Initialize() optionalNamespaces = new Dictionary { - { ChainModel.EvmNamespace, optionalNamespace }, + { EvmNamespace, optionalNamespace }, }; initialized = true; @@ -246,7 +248,7 @@ public override async Task Connect() private async Task CheckAndSwitchNetwork() { var chainId = GetChainId(); - if (chainId != $"{ChainModel.EvmNamespace}:{chainConfig.ChainId}") + if (chainId != $"{EvmNamespace}:{chainConfig.ChainId}") { await SwitchChain(chainConfig.ChainId); UpdateSessionChainId(); diff --git a/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs b/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs index dffdae562..7ffd11e62 100644 --- a/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs +++ b/src/ChainSafe.Gaming.Reown/Wallets/ReownWalletRegistry.cs @@ -41,7 +41,7 @@ async ValueTask ILifecycleParticipant.WillStartAsync() var parameters = new Dictionary() { { "page", 1.ToString() }, - { "entries", 100.ToString() }, // get as many wallets as we can with one api call (when too many wallets return 400) + { "entries", 100.ToString() }, // get as many wallets as we can with one api call (when too many wallets returns 400) { "search", null }, { "platform", GetPlatformFilter() }, { "include", BuildWalletIdsFilter(config.IncludeWalletIds) }, @@ -50,7 +50,7 @@ async ValueTask ILifecycleParticipant.WillStartAsync() var parametersRaw = HttpUtils.BuildUriParameters(parameters); - var response = await reownHttpClient.Get(registryUri + parametersRaw); + var response = await reownHttpClient.Get(registryUri + parametersRaw); // todo download all the available wallets in a loop var apiFilteredWallets = platformWallets = response.AssertSuccess().Data; platformWallets = apiFilteredWallets .Where(w => diff --git a/src/ChainSafe.Gaming.Reown/WalletLocationOption.cs b/src/ChainSafe.Gaming.Reown/Wallets/WalletLocationOption.cs similarity index 81% rename from src/ChainSafe.Gaming.Reown/WalletLocationOption.cs rename to src/ChainSafe.Gaming.Reown/Wallets/WalletLocationOption.cs index 1933fe86d..275cf3ac2 100644 --- a/src/ChainSafe.Gaming.Reown/WalletLocationOption.cs +++ b/src/ChainSafe.Gaming.Reown/Wallets/WalletLocationOption.cs @@ -1,4 +1,4 @@ -namespace ChainSafe.Gaming.Reown +namespace ChainSafe.Gaming.Reown.Wallets { /// /// Wallet location options. diff --git a/src/ChainSafe.Gaming.Reown/WalletLocationOptionsExtensions.cs b/src/ChainSafe.Gaming.Reown/Wallets/WalletLocationOptionsExtensions.cs similarity index 96% rename from src/ChainSafe.Gaming.Reown/WalletLocationOptionsExtensions.cs rename to src/ChainSafe.Gaming.Reown/Wallets/WalletLocationOptionsExtensions.cs index 173c8d037..d0aef8e44 100644 --- a/src/ChainSafe.Gaming.Reown/WalletLocationOptionsExtensions.cs +++ b/src/ChainSafe.Gaming.Reown/Wallets/WalletLocationOptionsExtensions.cs @@ -1,6 +1,6 @@ using System; -namespace ChainSafe.Gaming.Reown +namespace ChainSafe.Gaming.Reown.Wallets { public static class WalletLocationOptionsExtensions { From b07ea5675c4275fba74de97806d6666de6882fb8 Mon Sep 17 00:00:00 2001 From: creeppak Date: Tue, 22 Oct 2024 16:33:50 +0100 Subject: [PATCH 16/16] Linter --- src/ChainSafe.Gaming.Reown/Storage/ReownStorageFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ChainSafe.Gaming.Reown/Storage/ReownStorageFactory.cs b/src/ChainSafe.Gaming.Reown/Storage/ReownStorageFactory.cs index 67bf99f85..5b603d186 100644 --- a/src/ChainSafe.Gaming.Reown/Storage/ReownStorageFactory.cs +++ b/src/ChainSafe.Gaming.Reown/Storage/ReownStorageFactory.cs @@ -10,7 +10,7 @@ namespace ChainSafe.Gaming.Reown.Storage { public class ReownStorageFactory { - public static string RelativeFilePath = "Reown/storage.json"; + private const string RelativeFilePath = "Reown/storage.json"; public static async Task Build(Web3Environment environment) {