Ethereum Unity3D Boilerplate Questions

Oh yes I’m sure it did go through ! Thanks!!
It’s showing well on polygonscan, so probably just metamask being metamask :slight_smile:

Curious why it doesn’t show who the receiver is. Thinking it’s probably just mumbai polygonscan

1 Like

Yes I have tested where address is non-null, token address is non-null.
And I think MoralisInterface has been initialized because before calling GetNFTsForContract(), I am fetching address using
var user = await MoralisInterface.GetUserAsync();
address = user.authData[“moralisEth”][“id”].ToString();
And getting proper address.

Can you please test it on android real device ?

public async void MoralisTest()
    {
        var user = await MoralisInterface.GetUserAsync();
        address = user.authData["moralisEth"]["id"].ToString();
        NftOwnerCollection noc =
                         await MoralisInterface.GetClient().Web3Api.Account.GetNFTsForContract(address.ToLower(),
                       swordTokenAddress,
                       ChainList.rinkeby);
    }
1 Like

I did. I have a Pixel 4 and tested it on that.
I had it connected to my PC with android studio which is how I captured the log.

check if the nft moved :sweat_smile: and where it moved to

1 Like

Is there error because of async function, because I think async works differently on each OS.
Or what should be wrong ? What should I check now. I am stuck with this for more than 48 hours.

1 Like

I do not know as it worked on an Android device for me. The call I made was async and awaited.

Send me the actual address, and contract address and I can try.

I also just realized I assumed that you are building for Android and not WebGL. Is this correct?

Also what version of Unity are you building with?

1 Like

public address : 0xB65f5Ac5eAD9598f7Ec61c8C89033B970dA7B77D
contract address : 0x81437356a6143f7c344d8569a09607e294ef17a4
on rinkeby testnet.
Unity version : 2021.2.9f1
Yes I am building for Android OS.

Hmm… Still no luck with getting the callbacks to fire. Can you think of anything else I should look at?

Here’s the full context of the code:

     public class PlayerData : MoralisObject
     {
         public long TokenCount { get; set; }
         public string WalletAddress { get; set; }
         public PlayerData() : base("PlayerData") { }
     }

    private async void Start()
    {
        var user = await MoralisInterface.GetUserAsync();

        if (WalletConnect.Instance.Connected && user != null)
        {
            setupPlayer(user);
            monitorPlayerData();
        }
    }
    private async void setupPlayer(MoralisUser user)
    {
        var walletAddress = user.authData["moralisEth"]["id"].ToString();
        var playerDataQuery = await MoralisInterface.GetClient().Query<PlayerData>();

        playerDataQuery = playerDataQuery.WhereEqualTo("WalletAddress", walletAddress);

        var queryResult = await playerDataQuery.FindAsync();

        PlayerData playerData = queryResult.FirstOrDefault();

        if (playerData == null)
        {
            playerData = MoralisInterface.GetClient().Create<PlayerData>();
            playerData.WalletAddress = walletAddress;
            playerData.TokenCount = 0;
            await playerData.SaveAsync();
        }

        TokensCollected = playerData.TokenCount;
        OnTokenCountChanged?.Invoke(TokensCollected);
    }

   private async void monitorPlayerData()
    {
        var query = await MoralisInterface.GetClient().Query<PlayerData>();

        MoralisLiveQueryCallbacks<PlayerData> callbacks = new MoralisLiveQueryCallbacks<PlayerData>();

        callbacks.OnConnectedEvent += (() => { Console.WriteLine("Connection Established."); });
        callbacks.OnSubscribedEvent += ((requestId) => { Console.WriteLine($"Subscription {requestId} created."); });
        callbacks.OnUnsubscribedEvent += ((requestId) => { Console.WriteLine($"Unsubscribed from {requestId}."); });
        callbacks.OnErrorEvent += ((ErrorMessage em) =>
        {
            Debug.Log($"***** ERROR: code: {em.code}, msg: {em.error}, requestId: {em.requestId}");
        });
        callbacks.OnCreateEvent += ((item, requestId) =>
        {
            Debug.Log($"***** Created");
        });
        callbacks.OnUpdateEvent += ((item, requestId) =>
        {
            Debug.Log($"***** Updated");
        });
        callbacks.OnDeleteEvent += ((item, requestId) =>
        {
            Debug.Log($"***** Deleted");
        });
        callbacks.OnGeneralMessageEvent += ((text) =>
        {
            Debug.Log($"***** Websocket message: {text}");
        });

        MoralisLiveQueryController.AddSubscription<PlayerData>("PlayerData", query, callbacks);
    }

1 Like

Hi guys !

Everything working smoothly on desktop and android ! Thank you!

However it isn’t working for iOS…
When I try to authenticate, WalletConnect don’t seem to do the job and get stuck on this screen:

Any idea why is that ?
Thanks!

1 Like

did you select wallets in the ios gameobject in unity
there will be a choice to select wallets, that you want your users to use.
and if there is an error, you can show us

well, idk if this is correct, but you are only calling the function onStart, is anything supposed to be fired then ? i assume you will want to keep this in an update so it will be running throughout the life span of your game and be constantly check if any event is been fired

@0xprof, @dgoodrich can you please check it on Android build ? I am getting APIException till now. :sob:

We have encountered this error when we are trying to sign in with certain accounts while everything works perfectly with other accounts that we have. We are not exactly sure what or why this happens?

Thanks in advance!

PS: Using Unity Web GL

you can get that error if you use an older version of the SDK or if the user doesn’t sign the message in reasonable time

1 Like

The latest SDK v1.0.8 gives me this error:

EntryPointNotFoundException: ConnectWeb3
Moralis.WebGL.Web3GL+d__14.MoveNext () (at Assets/MoralisWeb3ApiSdk/Moralis/Moralis.WebGL/Web3GL.cs:73)
— End of stack trace from previous location where exception was thrown —
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <695d1cc93cca45069c528c15c9fdd749>:0)
Cysharp.Threading.Tasks.UniTask+ExceptionResultSource1[T].GetResult (System.Int16 token) (at Assets/MoralisWeb3ApiSdk/Plugins/UniTask/Runtime/UniTask.Factory.cs:235) Cysharp.Threading.Tasks.UniTask 1+Awaiter[T].GetResult () (at Assets/MoralisWeb3ApiSdk/Plugins/UniTask/Runtime/UniTask.cs:653)
MoralisWeb3ApiSdk.MoralisInterface+d__21.MoveNext () (at Assets/MoralisWeb3ApiSdk/MoralisInterface.cs:250)
— End of stack trace from previous location where exception was thrown —
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <695d1cc93cca45069c528c15c9fdd749>:0)
Cysharp.Threading.Tasks.UniTask+ExceptionResultSource1[T].GetResult (System.Int16 token) (at Assets/MoralisWeb3ApiSdk/Plugins/UniTask/Runtime/UniTask.Factory.cs:235) Cysharp.Threading.Tasks.UniTask 1+Awaiter[T].GetResult () (at Assets/MoralisWeb3ApiSdk/Plugins/UniTask/Runtime/UniTask.cs:653)
MainMenuScript+d__11.MoveNext () (at Assets/MoralisWeb3ApiSdk/Example/Scripts/MainMenuScript.cs:165)
— End of stack trace from previous location where exception was thrown —
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <695d1cc93cca45069c528c15c9fdd749>:0)
Cysharp.Threading.Tasks.UniTask+ExceptionResultSource.GetResult (System.Int16 token) (at Assets/MoralisWeb3ApiSdk/Plugins/UniTask/Runtime/UniTask.Factory.cs:205)
Cysharp.Threading.Tasks.UniTask+Awaiter.GetResult () (at Assets/MoralisWeb3ApiSdk/Plugins/UniTask/Runtime/UniTask.cs:312)
MainMenuScript+d__10.MoveNext () (at Assets/MoralisWeb3ApiSdk/Example/Scripts/MainMenuScript.cs:148)
— End of stack trace from previous location where exception was thrown —
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.b__6_0 (System.Object state) (at <695d1cc93cca45069c528c15c9fdd749>:0)
UnityEngine.UnitySynchronizationContext+WorkRequest.Invoke () (at :0)
UnityEngine.UnitySynchronizationContext:ExecuteTasks()

also trying to log in immediately.

1 Like

hey, can you take a look at the test scene provided with webgl support, and see if it works
and which unity version are you using ?
and what does the browser console say ?
and did you pick the moralis webgl template ?
and you cannot test the webgl login except if it is on build on webgl and it is running in your browser and you have to select the moralis webgl template.

2 Likes

Make sure you are selecting wallets in the iOS Menu Object

This is required because, for iOS, Wallet Connect attempts to load over 110 wallet definitions with images before displaying the view. This can take over a minute so I added the wallet filter for iOS. Select what you consider to be the top 10 or so wallets by checking off the box next to the desired wallet. When you re-build, the wallet list should show in iOS.

1 Like

Most likely you did not select the Moralis WebGL Template in Player Preferences.

Looks like 0xprof listed this as a solution as well.

1 Like

I changed you code only slightly (Name instead of address and logged name with create and update).

These messages were logged:


***** Websocket message: Received message $create

***** Created Alesdair the Blessed

***** Websocket message: Result received.

***** Websocket message: Received message $create

***** Created Bob

***** Websocket message: Listening, status: Open

***** Websocket message: Received message $update

***** Websocket message: Listening, status: Open

***** Updated Alesdair the Blessed

***** Websocket message: Listening, status: Open

***** Websocket message: Result received.

***** Websocket message: Received message $update

***** Websocket message: Listening, status: Open

***** Updated Bob

***** Websocket message: Result received.

***** Websocket message: Listening, status: Open

***** Websocket message: Result received.

***** Websocket message: Received message $delete

***** Websocket message: Listening, status: Open

***** Deleted

***** Websocket message: Result received.

***** Websocket message: Listening, status: Open

***** Websocket message: Result received.

***** Websocket message: Received message $delete

***** Deleted

Here is the whole class I used:

using Assets.Scripts;
using MoralisWeb3ApiSdk;
using System;
using UnityEngine;
using System.Collections.Generic;
using System.Threading;
#if UNITY_WEBGL
using Cysharp.Threading.Tasks;
using Moralis;
using Moralis.WebGL.Platform.Objects;
using Moralis.WebGL.Platform.Queries;
using Moralis.WebGL.Platform.Queries.Live;
#else
using System.Threading.Tasks;
using Moralis;
using Moralis.Platform.Objects;
using Moralis.Platform.Queries;
using Moralis.Platform.Queries.Live;

#endif

public class PlayerData : MoralisObject
{
    public long TokenCount { get; set; }
    public string Name { get; set; }
    public PlayerData() : base("PlayerData") { }
}

public class LiveQueryTest
{
#if UNITY_WEBGL
    public async static UniTask TestLiveQuery()
    {
        MoralisQuery<PlayerData> query = await MoralisInterface.GetClient().Query<PlayerData>();
        // Setup subscription
        SetupLiveQuerySubscription(query);

        Thread.Sleep(2000);
#else
    public async static Task TestLiveQuery()
    {
        MoralisQuery<PlayerData> query = MoralisInterface.GetClient().Query<PlayerData>();
        // Setup subscription
        SetupLiveQuerySubscription(query);

        Thread.Sleep(2000);
#endif
        // Setup subscription
        SetupLiveQuerySubscription(query);

        Thread.Sleep(2000);

        System.Random rand = new System.Random((int)DateTime.Now.Ticks);

        int x = rand.Next(25) + 3;

        // Create some data
        PlayerData p1 = MoralisInterface.GetClient().Create<PlayerData>();
        p1.Name = GetTestName();
        p1.TokenCount = x;
        await p1.SaveAsync();

        x = rand.Next(25) + 3;
        PlayerData p2 = MoralisInterface.GetClient().Create<PlayerData>();
        p2.Name = GetTestName();
        p2.TokenCount = x;
        await p2.SaveAsync();


        // Get the records created
        IEnumerable<PlayerData> recs = await query.FindAsync();

        // Update dtat
        foreach (PlayerData pd in recs)
        {
            x = rand.Next(25) + 3;
            pd.TokenCount = x;
            await pd.SaveAsync();
        }

        // Delete data
        foreach (PlayerData pd in recs)
        {
            await pd.DeleteAsync();
        }
    }

    private static void SetupLiveQuerySubscription(MoralisQuery<PlayerData> query)
    {
        MoralisLiveQueryCallbacks<PlayerData> callbacks = new MoralisLiveQueryCallbacks<PlayerData>();

        callbacks.OnConnectedEvent += (() => { Console.WriteLine("Connection Established."); });
        callbacks.OnSubscribedEvent += ((requestId) => { Console.WriteLine($"Subscription {requestId} created."); });
        callbacks.OnUnsubscribedEvent += ((requestId) => { Console.WriteLine($"Unsubscribed from {requestId}."); });
        callbacks.OnErrorEvent += ((ErrorMessage em) =>
        {
            Debug.Log($"***** ERROR: code: {em.code}, msg: {em.error}, requestId: {em.requestId}");
        });
        callbacks.OnCreateEvent += ((item, requestId) =>
        {
            Debug.Log($"***** Created {item.Name}");
        });
        callbacks.OnUpdateEvent += ((item, requestId) =>
        {
            Debug.Log($"***** Updated {item.Name}");
        });
        callbacks.OnDeleteEvent += ((item, requestId) =>
        {
            Debug.Log($"***** Deleted");
        });
        callbacks.OnGeneralMessageEvent += ((text) =>
        {
            Debug.Log($"***** Websocket message: {text}");
        });

        MoralisLiveQueryController.AddSubscription<PlayerData>("PlayerData", query, callbacks);
    }

    private static string GetTestName()
    {
        string[] names = { "Clem the Great", "Sion the Bold", "Bob", "D@ve", "Oogmar the Deft", "Alesdair the Blessed", "Seviel the Mighty", "Master Adept Xactant", "Semaphore the Beautiful", "Gamemaster Nexnang" };

        System.Random rand = new System.Random((int)DateTime.Now.Ticks);

        int x = rand.Next(names.Length);

        x = rand.Next(names.Length);

        return names[x];
    }
}

Note, I only tested this in desktop.

Hello, everything is working perfectly except whenever I try the RunContractFunction() it keeps throwing:
" ApiException: Error calling RunContractFunction: {“code”:141,“error”:" is required"}
Moralis.Web3Api.CloudApi.NativeApi+d__14.MoveNext () (at Assets/MoralisWeb3ApiSdk/Moralis/Moralis.Web3Api/CloudApi/NativeApi.cs:480) ".
Any help would be appreciated. Thanks.

private async UniTask RunContract()
    {
        // Function ABI input parameters
        object[] inputParams = new object[1];
        inputParams[0] = new { internalType = "uint256", name = "", type = "uint256" };
        // Function ABI Output parameters
        object[] outputParams = new object[1];
        outputParams[0] = new { internalType = "string", name = "", type = "string" };
        // Function ABI
        object[] abi = new object[1];
        abi[0] = new { inputs = inputParams, name = "getCount", outputs = outputParams, stateMutability = "view", type = "function" };
        //abi[1] = new { inputs = inputParams, name = "increment", outputs = outputParams, stateMutability = "nonpayable", type = "function" };


        // Define request object
        RunContractDto rcd = new RunContractDto()
        {
            Abi = abi
            //Params = new { id = "15310200874782" }
        };

        try
        {
            // Call contract function, response is always a string.
            String resp = await MoralisInterface.GetClient().Web3Api.Native.RunContractFunction("0xc1c1dD559161A527305B276c4C9e156E887368Ce", "getCount", rcd, ChainList.mumbai);
            print(resp);
        }
        catch (Exception)
        {

            throw;
        }
        
    }