trilitech / tezos-unity-sdk Goto Github PK
View Code? Open in Web Editor NEWTezos Unity SDK for developers. Discover the future of Web3 gaming.
Home Page: https://tezos.com/unity
License: MIT License
Tezos Unity SDK for developers. Discover the future of Web3 gaming.
Home Page: https://tezos.com/unity
License: MIT License
Hello,
I wanted to use the OnDisconnect
event to detect wallet changes/disconnects so the user could be prompted. However due to the below error, I can't do that. Unless I'm doing something stupidly wrong (in which case, please let me know how I can correctly do this), please confirm the issue.
I'm using SDK version 1.2.0, but this is reproduced in 1.2.1 as well.
The error comes from walletbeacon.min.js apparently. The game loop doesn't have a chance to be triggered since it never reaches there, it happens on the web app itself.
Steps to reproduce:
The below error log is from firefox, but similar logs would be available from other browsers.
Uncaught Error: Permission denied to access property "apply"
onerror moz-extension://253c8873-2f90-4700-92e8-08c01dca50f1/content_script/inpage_sol.js:143
inpage_sol.js:143:16115
onerror moz-extension://253c8873-2f90-4700-92e8-08c01dca50f1/content_script/inpage_sol.js:143
-----------------------------------------------------------------------------------------------------------------------------
Uncaught Error: Permission denied to access property "apply"
onunhandledrejection moz-extension://253c8873-2f90-4700-92e8-08c01dca50f1/content_script/inpage_sol.js:143
inpage_sol.js:143:16268
onunhandledrejection moz-extension://253c8873-2f90-4700-92e8-08c01dca50f1/content_script/inpage_sol.js:143
-----------------------------------------------------------------------------------------------------------------------------
Uncaught (in promise) TypeError: typedMessage.message is undefined
DAppClient http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
verb http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
handleResponse http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
Client http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
verb http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
fulfilled http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
promise callback*step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
Client http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
Transport http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
Transport http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
verb http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
notifyListeners http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
P2PTransport http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
callbackFunction http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
verb http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
fulfilled http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
promise callback*step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
fulfilled http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
promise callback*step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
fulfilled http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
promise callback*step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
fulfilled http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
promise callback*step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
callbackFunction http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
emit http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
emit http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
emitClientEvent http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
emitMessage http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
emitMessage http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
emitIfEvent http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
onStateChanged http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
MatrixClient http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
notifyListeners http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
notifyListeners http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
MatrixClientStore http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
verb http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
fulfilled http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
promise callback*step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
update http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
initialPollingResult http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
verb http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
initialPollingResult http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
pollSync http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
verb http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
fulfilled http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
promise callback*step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
pollSync http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
pollSync http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
verb http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
pollSync http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
setTimeout handler*[274]</MatrixClient.prototype.poll/MatrixClient</</pollSync/</< http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
verb http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
fulfilled http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
promise callback*step http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
__awaiter http://127.0.0.1/StreamingAssets/walletbeacon.min.js:1
walletbeacon.min.js:1:1369870
Most likely an issue with serialization (Newtonsoft)
Authentication is a popular use case of Web3. So popular I suggest it be solved at the SDK level.
Current
The repo contains a "Demo Example. unity" scene that shows authentication. That's great.
See image.
There are many ways to solve it well. May the following be inspiration for those assigned. I recommend to address the optional prerequisites first to provide a foundation for the suggestion below.
Prerequisites
Suggestion
Authentication.prefab
and include it in the SDK. It includes a Unity Canvas and the components scripts within for a generalized authentication solution meant for production.Scoping
Connect()
, Disconnect()
and OnAuthenticationStateChanged.AddEventListener()
, yet do not offer custom customization of any visual elements like the color of the QR image.Definition of Done
Something like this.
Authentication.prefab
from /Packages/Blah/Foo/ to the Unity Scene Hierarchy. This does not render in the Scene View (e.g. visual elements are not enabled)Authentication.prefab
instance in the scene and modifies the custom properties. (e.g. Set "WillConnectOnAwake=true")Authentication.prefab
instance connects upon AwakeAuthentication.prefab
instance is now visibleAuthentication.prefab
instance is now not visibleTAG
#PriorityForSam
Steps to reproduce:
Full error text:
A meta data file (.meta) exists but its asset 'Packages/com.trilitech.tezos-unity-sdk/CHANGELOG.md' can't be found. When moving or deleting files outside of Unity, please ensure that the corresponding .meta file is moved or deleted along with it.
Couldn't delete Packages/com.trilitech.tezos-unity-sdk/CHANGELOG.md.meta because it's in an immutable folder.
There is an important crash in the Beacon SDK that affects some of the users.
Exception java.lang.Error: FATAL EXCEPTION [DefaultDispatcher-worker-6]
Unity version : 2021.3.20f1
Device model : realme RMX3231
Device fingerprint: realme/RMX3231/RMX3231:11/RP1A.201005.001/1675674151082:user/release-keys
Build Type : Release
Scripting Backend : IL2CPP
ABI : armeabi-v7a
Strip Engine Code : true
Caused by: it.airgap.beaconsdk.core.exception.InternalException: No reachable Matrix node found.
at it.airgap.beaconsdk.core.internal.utils.ErrorKt.failWith (Error.kt:18)
at it.airgap.beaconsdk.core.internal.utils.ErrorKt.failWith$default (Error.kt:16)
at it.airgap.beaconsdk.transport.p2p.matrix.internal.store.P2pMatrixStore.failWithUnreachableNodes (P2pMatrixStore.kt:164)
at it.airgap.beaconsdk.transport.p2p.matrix.internal.store.P2pMatrixStore.relayServer-IoAF18A (P2pMatrixStore.kt:152)
at it.airgap.beaconsdk.transport.p2p.matrix.internal.store.P2pMatrixStore.access$relayServer-IoAF18A (P2pMatrixStore.kt:18)
at it.airgap.beaconsdk.transport.p2p.matrix.internal.store.P2pMatrixStore$relayServer$1.invokeSuspend
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33)
at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith (SuspendFunctionGun.kt:194)
at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith (SuspendFunctionGun.kt:15)
at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith (SuspendFunctionGun.kt:89)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:46)
at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith (SuspendFunctionGun.kt:194)
at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith (SuspendFunctionGun.kt:15)
at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith (SuspendFunctionGun.kt:89)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:46)
at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith (SuspendFunctionGun.kt:194)
at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith (SuspendFunctionGun.kt:15)
at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith (SuspendFunctionGun.kt:89)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:46)
at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith (SuspendFunctionGun.kt:194)
at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith (SuspendFunctionGun.kt:15)
at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith (SuspendFunctionGun.kt:89)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:46)
at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith (SuspendFunctionGun.kt:194)
at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith (SuspendFunctionGun.kt:15)
at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith (SuspendFunctionGun.kt:89)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:46)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:104)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely (CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask (CoroutineScheduler.kt:749)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker (CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run (CoroutineScheduler.kt:664)`
Sharing the logs of the app while it crashes below, Crashlytics:
`# Crashlytics - Stack trace
Fatal Exception: java.lang.Error: FATAL EXCEPTION [DefaultDispatcher-worker-1]
Unity version : 2021.3.20f1
Device model : samsung SM-A605G
Device fingerprint: samsung/a6pltedx/a6plte:10/QP1A.190711.020/A605GDXU9CVB1:user/release-keys
Build Type : Release
Scripting Backend : IL2CPP
ABI : armeabi-v7a
Strip Engine Code : true
Caused by it.airgap.beaconsdk.core.exception.InternalException: No reachable Matrix node found.
at it.airgap.beaconsdk.core.internal.utils.ErrorKt.failWith(Error.kt:18)
at it.airgap.beaconsdk.core.internal.utils.ErrorKt.failWith$default(Error.kt:16)
at it.airgap.beaconsdk.transport.p2p.matrix.internal.store.P2pMatrixStore.failWithUnreachableNodes(P2pMatrixStore.kt:164)
at it.airgap.beaconsdk.transport.p2p.matrix.internal.store.P2pMatrixStore.relayServer-IoAF18A(P2pMatrixStore.kt:152)
at it.airgap.beaconsdk.transport.p2p.matrix.internal.store.P2pMatrixStore.access$relayServer-IoAF18A(P2pMatrixStore.kt:18)
at it.airgap.beaconsdk.transport.p2p.matrix.internal.store.P2pMatrixStore$relayServer$1.invokeSuspend(:14)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
FinalizerWatchdogDaemon:
at java.lang.Object.wait(Object.java)
at java.lang.Object.wait(Object.java:442)
at java.lang.Object.wait(Object.java:568)
at java.lang.Daemons$FinalizerWatchdogDaemon.sleepUntilNeeded(Daemons.java:339)
at java.lang.Daemons$FinalizerWatchdogDaemon.runInternal(Daemons.java:319)
at java.lang.Daemons$Daemon.run(Daemons.java:137)
at java.lang.Thread.run(Thread.java:919)
UnityMain:
at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
at android.os.MessageQueue.next(MessageQueue.java:336)
at android.os.Looper.loop(Looper.java:197)
at com.unity3d.player.UnityPlayer$e.run(:20)
ktor-okhttp-dispatcher-worker-2:
at sun.misc.Unsafe.park(Unsafe.java)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:353)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:794)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:739)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:710)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
main:
at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
at android.os.MessageQueue.next(MessageQueue.java:336)
at android.os.Looper.loop(Looper.java:197)
at android.app.ActivityThread.main(ActivityThread.java:7860)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
pool-33-thread-1:
at sun.misc.Unsafe.park(Unsafe.java)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2067)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1092)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
ReferenceQueueDaemon:
at java.lang.Object.wait(Object.java)
at java.lang.Object.wait(Object.java:442)
at java.lang.Object.wait(Object.java:568)
at java.lang.Daemons$ReferenceQueueDaemon.runInternal(Daemons.java:215)
at java.lang.Daemons$Daemon.run(Daemons.java:137)
at java.lang.Thread.run(Thread.java:919)
pool-31-thread-1:
at sun.misc.Unsafe.park(Unsafe.java)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2067)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1092)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
ktor-okhttp-dispatcher-worker-3:
at sun.misc.Unsafe.park(Unsafe.java)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:353)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:794)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:739)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:710)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
UnityChoreographer:
at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
at android.os.MessageQueue.next(MessageQueue.java:336)
at android.os.Looper.loop(Looper.java:197)
at android.os.HandlerThread.run(HandlerThread.java:67)
pool-34-thread-1:
at sun.misc.Unsafe.park(Unsafe.java)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2067)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1120)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:849)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1092)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
pool-24-thread-1:
at sun.misc.Unsafe.park(Unsafe.java)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:230)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2109)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1132)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:849)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1092)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
pool-23-thread-1:
at sun.misc.Unsafe.park(Unsafe.java)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2067)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1120)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:849)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1092)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
ConnectivityThread:
at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
at android.os.MessageQueue.next(MessageQueue.java:336)
at android.os.Looper.loop(Looper.java:197)
at android.os.HandlerThread.run(HandlerThread.java:67)
Okio Watchdog:
at java.lang.Object.wait(Object.java)
at java.lang.Object.wait(Object.java:442)
at java.lang.Object.wait(Object.java:568)
at com.android.okhttp.okio.AsyncTimeout.awaitTimeout(AsyncTimeout.java:313)
at com.android.okhttp.okio.AsyncTimeout.access$000(AsyncTimeout.java:42)
at com.android.okhttp.okio.AsyncTimeout$Watchdog.run(AsyncTimeout.java:288)
Timer-0:
at java.lang.Object.wait(Object.java)
at java.lang.Object.wait(Object.java:442)
at java.lang.Object.wait(Object.java:568)
at java.util.TimerThread.mainLoop(Timer.java:533)
at java.util.TimerThread.run(Timer.java:512)
queue-1-2:
at sun.misc.Unsafe.park(Unsafe.java)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2067)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1092)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
pool-25-thread-1:
at sun.misc.Unsafe.park(Unsafe.java)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2067)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1120)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQu...`
Marketplace is not getting loaded on WebGL.
WebGLFrontend/output
and copy the StreamingAssets
and WebGLTemplates
folders. Navigate to the Assets
folder and paste copied folders.Auto Graphics API
from ProjectSettings/Player/Other Settings
Airgap
WebGL Template from ProjectSettings/Player/Resolution and Presentation
MARKET
button to load Market PanelThis seems to happen when you don't select iOS as one of your target when installing Unity.
Workarounds:
It seems like something needs to be changed to avoid this error when people didn't select iOS as one of the dependencies.
Authentication is a popular use case of Web3.
Current
The repo contains a "Demo Example. unity" scene that shows authentication. That's great.
See image.
Current UX
I assume there is zero cross-session-persistence to the authentication. This limits the end-player experience using apps built on top of the SDK. This also limits the quality of life for developers working on top of the SDK. The current requirement to auth every time a developer hits play is a time-sink.
Suggestion
Suggested UX
Ideally the session persists as long as is feasible per any security concerns (e.g. days/weeks)
Ideally, the SDK supports an API to disconnect/end the authenticated session (e.g. User clicks a logout button). This is a must-have feature.
Before this task is fully complete, a hacky workaround that would help user-devs would be to add functionality to the API to hardcode an authenticated web3 address and thus bypass the need to auth.
Pseudocode
if (isWorkaround)
{
//Fake auth. Or perhaps there is a legit long-term use case of this API
FakeTezosSDK.blah.FakeAuthWithAddress ("0x123...ABC");
}
else
{
// Do full auth with QR code
}
// Full API is ready for use
TAG
#PriorityForSam
The repo contains a Unity Project.
In the Assets Folder, there are folders and files that relate to 2 concerns...
Concerns
Suggestion
Solution Paths to Suggestion, Either
NOTE: Currently any/all prefabs related to the "QR code functionality" are within "DemoExample". Separately I'll suggest how to address that.
TAG
#PriorityForSam
Assets\TezosUnitySDK\Scripts\Helpers\NetezosExtensions.cs(21,37): warning CS0436: The type 'ContractScript' in 'C:\Users\mathi\My project (2)\Assets/TezosUnitySDK/Scripts/Netezos/Contracts/ContractScript.cs' conflicts with the imported type 'ContractScript' in 'Netezos, Version=2.6.2.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'C:\Users\mathi\My project (2)\Assets/TezosUnitySDK/Scripts/Netezos/Contracts/ContractScript.cs'.
The SDK currently provides a low level API on top of which a lot can be built, with some effort.
To make things easier for most devs, key use cases should be supported directly by the SDK using a higher-level API.
One such important use case, is accessing the list of tokens of a given user address in a given FA2 contract, along with their metadata. This would be an API that handles aspects of tzip-12 (FA2), tzip-16 (Contract metadata) and tzip-21 (Rich Metadata).
A very first version of the API would support just enough to interact with the contracts created by the Objkt's minting Factory. Here is an example of such contract: KT1AXCXcYiV1ACc6diBfHq1TVynj8KvqeoUZ
The API would make it possible to:
Fetching these can be done through tzkt, with a query like this:
https://api.tzkt.io/v1/tokens/balances?token.contract=KT1AXCXcYiV1ACc6diBfHq1TVynj8KvqeoUZ&account=tz1ZuhCMnA1gZHfNzgKNFm1B2mjSDKJsQfJN
Performance issues need to be taken into account, to avoid putting unnecessary load on tzkt. In the initial use case, the intent is not for the game to get real time updates on these, but maybe load them at startup or when the user explicitly requests to refresh the data. For real time updates, a system of events would later need to be added.
Support for pagination and filtering / requesting only a subset of the fields could be a good idea to improve performance, but a version without it would already be great.
I followed the instructions to use the sdk in unity (on opentezos), I import the Tezos SDK package and also the Newtonsoft package because I use a recent version of unity.
Then i have this error: Assets\tezos-unity-sdk-main\Runtime\Scripts\BeaconSDK\BeaconConnectorDotNet.cs(150,56): error CS0012: The type 'JObject' is defined in an assembly that is not referenced. You must add a reference to assembly 'Newtonsoft.Json.
Temporary workaround: https://github.com/jilleJr/Newtonsoft.Json-for-Unity/wiki/Install-official-via-UPM
SingletonMonoBehavor.cs is misspelled.
After #71 is merged into master
As Objkt or DNS don't have a version on ghostnet, we need to prepare a tutorial that shows how to do it.
An initial version was created that uses octez-client. We will do one that uses the BCD, starting from https://better-call.dev/deploy
SDK 1.4.0
Unity 2021.3.23f1
Game of 3 scences
Home scene i have a script behind with the following
NOTE: I was using your singleton patteren (Which was not working, same error) but moved code.
private ITezos _tezos;
void Start()
{
_tezos = TezosSingleton.Instance;
_tezos.Wallet.MessageReceiver.AccountConnected += OnAccountConnected;
_tezos.Wallet.MessageReceiver.AccountDisconnected += OnAccountDisconnected;
}
public void ConnectWallet()
{
_tezos.Wallet.Connect();
}
private void OnAccountConnected(string account)
{
if (!string.IsNullOrEmpty(account))
{
welcomeText.text = _tezos.Wallet.GetActiveAddress();
}
}
When this screen first loads, i am able to connect and disconnect as the MessageReciever events are firing.
When i return to Home scene,
_tezos.Wallet.GetActiveAddress() is set correctly
but none of the MessageReciever events are getting fired
In Chrome DevTools i am seeing this error when i try to "Connect" again. (Temple, opens and i log in etc and confirm but then nothing.)
SendMessage: object UnityBeacon not found!
This was reported during the solution verification process:
The following error is thrown when attempting to build for WebGL:
Plugin 'System.Threading.Tasks.Extensions.dll' is used from several locations:
Assets/Plugins/BeaconDotNet/System.Threading.Tasks.Extensions.dll would be copied to /System.Threading.Tasks.Extensions.dll
Assets/Plugins/Netezos/System.Threading.Tasks.Extensions.dll would be copied to /System.Threading.Tasks.Extensions.dll
Plugin 'System.Buffers.dll' is used from several locations:
Assets/Plugins/Netezos/System.Buffers.dll would be copied to /System.Buffers.dll
Assets/Plugins/BeaconDotNet/System.Buffers.dll would be copied to /System.Buffers.dll
Plugin 'System.Numerics.Vectors.dll' is used from several locations:
Assets/Plugins/Netezos/System.Numerics.Vectors.dll would be copied to /System.Numerics.Vectors.dll
Assets/Plugins/BeaconDotNet/System.Numerics.Vectors.dll would be copied to /System.Numerics.Vectors.dll
Plugin 'System.Memory.dll' is used from several locations:
Assets/Plugins/BeaconDotNet/System.Memory.dll would be copied to /System.Memory.dll
Assets/Plugins/Netezos/System.Memory.dll would be copied to /System.Memory.dll
Please fix plugin settings and try again.
The SDK includes a Tezos API. Great.
However, the API is relatively low level and includes no single entry point to the Tezos API.
This requires more setup for the user to create the lifecycle, maintain it, and dispose it.
I suggest the SDK be updated to provide that.
Video
Here is a Slack video of me talking about this ticket repeating the same info. https://tezos-dev.slack.com/archives/C04JEV96Q2H/p1678109676203329
Text
Moreover, by providing a single point of entry, more quality-of-life functionality can be built on top of that established single entry point. Tangentially-related tickets such as #12 and #13 will benefit from the ticket below.
What would this feature look like?
What would this feature allow on top of it?
A definition of done, is that with no preceding code, the following snippet will create, maintain, and dispose of the lifecycle of the TezosSingleton
on behalf of the developer.
Here is a demonstration of that with some additional API on top of it.
bool isAuthenticated = TezosSingleton.Instance.IsAuthenticated;
await TezosSingleton.Instance.AuthenticateAsync();
await TezosSingleton.Instance.DeauthenticateAsync();
Possible Solution Paths
Often for Unity-C#-facing API's this is done with a custom Singleton implementation. There are alternatives, but that one is pretty decent and recommended.
Pseudocode
For conversations' sake, here is the approach to API shape I have used when solving something similar in non-Tezos SDKs.
The following is pseudocode for one of my own non-Tezos SDKs.
It is not meant as a specific solution to this ticket, but rather an inspiration that demonstrates evidence of a single entry point.
Notice below that all calls utilize the single entry point of CustomWeb3System
. It is a singleton.
namespace RMC.Core.Samples
{
public class Example01_SmartContractCallAsync : MonoBehaviour
{
// Unity Methods --------------------------------
protected async void Start()
{
// Initialize the API
await CustomWeb3System.Instance.InitializeAsync();
// Check Authentication in API
bool isAuthenticated = CustomWeb3System.Instance.IsAuthenticated;
if (!isAuthenticated)
{
await CustomWeb3System.Instance.AuthenticateAsync();
}
// Now the API features are ready to be used, etc...
var foo = await CustomWeb3System.Instance.GetBlahAsync();
}
}
}
TAG
#PriorityForSam
MichelinePrim
might be causing issues with WebGL due to its use of certain .NET features that might not be fully supported in Unity's WebGL runtime, such as the complex binary serialization logic.
view_items_on_market
request.MichelinPrim
as an input, an exception being thrown at this line, blocks the request from being sent."{\"prim\": \"Unit\"}"
as an input instead of MichelinePrim
, it gets serialized successfully and the request being sent.We are trying to sign a payload and our backend validates it. On the webgl this works fine but on the android our backend validation fails to validate. Since validation works for webgl we thought maybe this is related to tezos sdk.
Below is an payload example
Sign this for authorization s2asd45asf75as6d76
We have tried all 3 signing types. All gives same signature.
Also when we tried tezos sdk's VerifySignedPayload method, we get an error about Invalid Hex string. We are not sure about the behaviour change between webgl and android. We have tried converting payload to hex aswell but that only helped about VerifySignedPayload method and not backend validation.
The repo is currently structured as a Unity Project. (link)
To improve integration with user's new and existing Unity Projects, I suggest...
Suggestion
Optional Additions
NOTE: This request does not directly relate to any current or future release of the Tezos Unity SDK on the ASSET STORE. That is a separate subject matter.
TAG
#PriorityForSam
When we send a request with a coroutine, we cannot see whether
that coroutine is a failed or not. There are no individual events that give their result for
each call (for each coroutine). It is essential to provide comprehensive error
handling to help developers diagnose issues and ensure a smooth user experience.
When using the SDK on iOS, I get a JSON serialization error.
JsonSerializationException: Unable to find a constructor to use for type Matrix.Sdk.Core.Infrastructure.Dto.ClientVersion.MatrixServerVersionsResponse. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'versions', line 1, position 12.
I think this is the reason because iOS authentication is buggy.
I think that we need to put a default constructor here:
Matrix.Sdk/Core/Infrastructure/Dto/ClientVersion/MatrixServerVersionsResponse.cs
Edit:
Actually, changing Managed Stripping Level from Low to Minimal fix it!
Maybe we should add a link.xml in the sample folder to force it or write in the README that only works on iOS with Managed Stripping Level selected to Minimal.
Library\PackageCache\com.trilitech.tezos-unity-sdk@a5b7a15f52\Runtime\Scripts\BeaconSDK\BeaconConnectorWebGl.cs(12,38): error CS0535: 'BeaconConnectorWebGl' does not implement interface member 'IBeaconConnector.RequestTezosSignPayload(SignPayloadType, string)'
Workaround: change enum type to int
Debug.Log()
calls) or instructions in the docs on how to enable debug mode.This line of code is redundant because the while loop condition already checks the success variable, and the loop will not continue if success is true.
public IEnumerator TrackTransaction(string transactionHash)
{
var success = false;
const float timeout = 30f; // seconds
var timestamp = Time.time;
// keep making requests until time out or success
while (!success && Time.time - timestamp < timeout)
{
if (success) break; <---
Logger.LogDebug($"Checking tx status: {transactionHash}");
yield return TezosSingleton.Instance.GetOperationStatus(result =>
{
if (result != null)
success = JsonSerializer.Deserialize<bool>(result);
}, transactionHash);
yield return new WaitForSecondsRealtime(3);
}
ContractCallInjectionResult result;
result.success = success;
result.transactionHash = transactionHash;
ContractCallCompleted?.Invoke(JsonUtility.ToJson(result));
}
This fix will not affect the functionality of the method.
Multiple developers reported that when displaying the QR Code through the method SetQrCode of the class QRCodeView, the displayed QRCode is too condensed and unusable.
Some reported that by changing the "Game view Scale", it helped, so the issue seems to be related to display dimensions, but others tried different ratios/dimensions and couldn't get it to work.
I was working on a live-minting tool with Netezos & Unity. And since now the UnitySDK released, I'm porting my codes from Netezos to UnitySDK version of Netezos (the main different is the IEnumerator wrapper)
And I found an issue when I try to send transactions with private key, there's a "Invalid Private Key" warning in the UnitySDK version, and made my code fail. (I made a check that my length is 64 so the check failed)
It is in the Key.cs line 39 & 40
https://github.com/trilitech/tezos-unity-sdk/blob/main/Assets/Scripts/Netezos/Keys/Key.cs
I simply remove the length check, and it worked. The transaction also successfully sent to the blockchain. So I guess the check is unnecessary?
And here is my code:
`
// This part will fail if the length check exists
Key testKey = Key.FromBase58("my private key from Temple wallet");
var address = testKey.Address;
// RPC part
TezosRpc rpc = new TezosRpc("https://mainnet.api.tez.ie");
//var headBlockData = await rpc.Blocks.Head.Header.GetAsync();
CoroutineWrapper<string> headCoroutine = new CoroutineWrapper<string>(rpc.Blocks.Head.Hash.GetAsync<string>());
yield return headCoroutine;
string headHash = headCoroutine.Result;
CoroutineWrapper<int> counterCoroutine = new CoroutineWrapper<int>(rpc.Blocks.Head.Context.Contracts[address].Counter.GetAsync<int>());
yield return counterCoroutine;
int addressCounter = counterCoroutine.Result + 1;
// call fxhash contract 'mint' entrypoint
var operation = new TransactionContent
{
Source = testKey.Address,
Destination = "KT1BJC12dG17CVvPKJ1VYaNnaT5mzfnUTwXv",
Counter = addressCounter,
Amount = 0,
GasLimit = 46000,
Fee = 6000,
StorageLimit = 1000,
Parameters = new Parameters
{
Entrypoint = "mint",
Value = new MichelinePrim
{
Prim = PrimType.Pair,
Args = new List<IMicheline>
{
new MichelineInt(14176),
new MichelinePrim
{
Prim = PrimType.Pair,
Args = new List<IMicheline>
{
new MichelinePrim{ Prim = PrimType.None },
new MichelinePrim{ Prim = PrimType.None }
}
}
}
}
}
};
CoroutineWrapper<byte[]> forgeCoroutine = new CoroutineWrapper<byte[]>(new LocalForge().ForgeOperationAsync(headHash, operation));
yield return forgeCoroutine;
var operationBytes = forgeCoroutine.Result;
byte[] signature = testKey.SignOperation(operationBytes);
CoroutineWrapper<dynamic> transactionCoroutine = new CoroutineWrapper<dynamic>(rpc.Inject.Operation.PostAsync(Combine(operationBytes, signature)));
yield return transactionCoroutine;
dynamic opResult = transactionCoroutine.Result;
`
The current repo name is "tezos-unity-sdk". We should change the repo name to "tezos-sdk-for-unity" in order to follow the same branding and SEO purposes.
Unity gives these errors when the SDK is imported from the Package Manager with Git URL.
These assets lack corresponding .meta files, causing Unity to ignore them. As a result, they are not being imported into the project.
This error message appears and could not play:
Assets/TezosUnitySDK/Scripts/BeaconSDK/BeaconConnectorDotNet.cs(17,7): error CS0246: The type or namespace name 'Newtonsoft' could not be found (are you missing a using directive or an assembly reference?)
Tested with a clean project with just TezosSDK 1.0 intalled.
Also try replacing Scripts with the current repo, but still not working.
Unity Version: 2021.3.20f1
macOS Version: 13.2.1
OS: Windows 10
Unity version: 2021.3.23f1
Unity SDK version: 1.3.0
Target platform: Windows Standalone
Steps to reproduce:
Sometimes it works, sometimes it fails.
Error:
IOException: Sharing violation on path C:\Users\xxx\AppData\LocalLow\Tezos\Examples Project\beacon.db
Workaround:
If close and open the Unity editor it works well once afterwards
Hint:
Most likely the c# code leaves a file open somethimes, but it should never do so.
Reproducing:
This was after creating a new project from scratch in Unity, then dragging the TezosUnitySDK folder into the assets. Basically following this:
https://opentezos.com/gaming/unity-sdk/getting-started/
Environment:
With Unity Editor Version 2021.3.18f1 - Silicon - LTS
Workarounds:
"com.unity.collab-proxy": "2.0.0"
with "com.unity.collab-proxy": "1.17.2"
, Then the error is gone, and the project builds correctlyTo add support for Nairobi
Both projects will include a custom implementation of ReadMe within Unity.
I suggest that the Tezos SDK itself also have this functionality. It provides good FTUE orientation and provides consistency with the projects above.
If the team agrees, please complete this ticket. Here are steps to complete and further below are some helpful demo resources.
While not strictly required, I recommend to complete the following before starting this ticket.
Add new scene to the samples that will showcase the usage of the Authentication prefab and NFT API.
It should include:
IsHolderOfToken (+ GetActiveWalletAddress)
IsHolderOfToken
GetTokensForOwner
NFT examples not necessarily should be accompanied with UI, a simple debug log would be enough
It is needed to add Newtonsoft dependency manually to build on IOS.
We already have the dependency as a DLL for WebGL, we just need to enable it to IOS as well.
The WebGLSupport.unitypackage was present before this commit, but it appears to have been removed. Could it have been accidentally deleted?
To collect bug reports from the users, I think we should add a convenient way, without having to visit an external link or platform.
The most ideal would be connecting this prompt to our Asana board and gather all the feedbacks under "Reported Bugs" section. It would help us to filter all the bugs reported and open issues for high-priority ones, as well as keep a record of what's been reported so far.
Authentication is a popular use case of Web3.
The repo contains a "Demo Example. unity" scene that shows authentication. That's great.
Sometimes it works.
Sometimes it doesn't. Here is info on failing scenarios with both Temple Wallet and Umami Wallet.
Test Scenario
Sometimes it succeeds per EXPECTED RESULTS above. Sometimes it fails per either of the 2 ways below.
Failure Type # 1
Failure Type # 2
Workarounds: All testing is done without any workarounds. No workarounds have been discovered for temple wallet.
Test Scenario
Sometimes it succeeds per EXPECTED RESULTS above. Sometimes it fails per below.
Failure Type # 3
Images
NOTE: Neither image necessarily indicates a failure. But if we start with 0 dapps, and you register and it fails, the result will still show 0 dapps. And if we start with 1 dapps, and you register and it fails, the result will still show 1 dapps.
With No Dapps
With One Dapps
Workarounds: All testing is done without any workarounds. However, a short-term workaround with Umami I found is to remove all registered 'dapps' within the mobile wallet before each attempt at authentication.
TAG
#PriorityForSam
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.