Ethereum Unity3D Boilerplate Questions

++++ for this question been willing to ask that one for a while.

1 Like

Unfortunately no. When the user is re-directed, WalletConnect / Unity goes to sleep. So the navigation back to the app allows it to wake so it can process the response and then send the signature request.

Hi there.

managed to get ERC20 transaction work perfectly with the SendEvmTransactionAsync.
Now I am trying to get infos about my NFT pricing.
My contract function has one input argument (OfferID) and should return 5 outputs like shown below:
Capture d’écran 2022-03-05 à 19.59.34

Was thinking of using the SendEvmTransactionAsync but I am not trying to make a transaction, just need to run a specific contract function. Despite the readme git, I can’t figure out how to use the RunContractFunction method.

Any help would be super greatful as my marketplace will need lots of function calls :slight_smile:

Thnaks

So my suspicion was correct, but wanted to ask anyway if I miss some possible solution :wink: thanks for answer

thanks for the clarification !
What if we build a unity webgl dapp set to run in background ?

Hello again. Thanks for all your help on this. We’re still struggling to figure out what we might be doing wrong. The code works perfectly in the Unity Editor with the build target set to PC / Mac / Linux stand-alone, but not with WebGL as the build target (both as an actual build and in the editor).

What we see when we run with WebGL as the build target is the following:

  1. Two new records are created in the DB but are not updated or deleted.
  2. There is a NullReferenceException thrown on line 108 of UniversalWebClient.cs
  3. None of the Debug.Log($"***** …") statements appear in the console (although we do see several WebRequest entries in the log).

Here’s the final test code based on what you posted with just a few minor adjustments to the WebGL portions. (Also, to make the compiler happy, we had to put the MoralisLiveQueryController.cs and MoralisSubscriptionQuery.cs in the WebGL namespace):

Thank you!

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

public class LiveQueryTest
{
#if UNITY_WEBGL
    public async void TestLiveQuery()
    {
        var moralisQueryPlayerData = await MoralisInterface.GetClient().Query<PlayerData>();

        // Setup subscription
        setupLiveQuerySubscription(moralisQueryPlayerData);

        Thread.Sleep(2000);
#else
    public async void TestLiveQuery()
    {
        var moralisQueryPlayerData = MoralisInterface.GetClient().Query<PlayerData>();

        // Setup subscription
        setupLiveQuerySubscription(moralisQueryPlayerData);

        Thread.Sleep(2000);
#endif
        System.Random rand = new System.Random((int)DateTime.Now.Ticks);

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

        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 moralisQueryPlayerData.FindAsync();

        // Update data
        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 void setupLiveQuerySubscription(MoralisQuery<PlayerData> playerData)
    {
        MoralisLiveQueryCallbacks<PlayerData> moralisLiveQueryCallbacks = new MoralisLiveQueryCallbacks<PlayerData>();

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

        MoralisLiveQueryController.AddSubscription<PlayerData>("PlayerData", playerData, moralisLiveQueryCallbacks);
    }

    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];
    }
}

** Software Versions Used
Unity 2020.3.24f1
Moralis Ethereum Unity Boilerplate v1.0.8

1 Like

Hi there,
took this from the git :

// No parameters
object[] pars = new object[0];
string jsonResult = await f.CallAsync(pars);

show an error :

Argument 1: cannot convert from ‘object[]’ to ‘Nethereum.RPC.Eth.DTOs.CallInput’

what am I missing ? :confused:

1 Like

Which Web3API operation are you trying to call?

I will check this out …

Based on this statement you included, while I am setting this up, please check the logs on your server to see if there were any errors (esp. table permissions for update / delete)

  1. So it looks like create and update were working fine as was the delete. However it looks like for the Delete function the response is null with a status of 200 but the WebGL UniversalWebClient did not handle that properly.

I need to create an update for this. To get you by for now, in the WebGL UniversalWebClient make these two changes:
A) Change line 94 to

string responseText = "{}";

B) Change line 108 to:

responseText = webRequest.downloadHandler == null ? responseText : webRequest.downloadHandler.text;
  1. The Callbacks are not firing for WebGL, digging into that next.

Hey, some of the readme are out dated
what are you trying to do ?

1 Like

@jcm

Opened issue #81 for the callbacks not working for WebGL.

1 Like

OK - just checked the logs & they look good. Nothing in there from yesterday or today, just a few unrelated errors that were logged on the 6th. Thanks!

1 Like

Thank you very much!

1 Like

Arf Ok !

I am struggling hard to communicate with my marketplace smart contract.
It works well on remix, everything seems ready. But I can’t get it to work.

I made a listing of NFTs (with token price and IDs) and trying to fetch infos.
Capture d’écran 2022-03-09 à 01.34.18
This “offers” function takes in one input (the listing ID) and returns the token price that should be displayed within unity.

More generally I need to understand how to use the RunContractFunction. And the readme is very unclear to me.

Thanks for your support.

1 Like

Is it on a test network?

If so, please provide the chain, the function ABI, the contract address and a listing ID for which you expect to receive data?

Thank you,

David

it’s on mumbai test net.

The abi is this:

[
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "_nftCollection",
				"type": "address"
			},
			{
				"internalType": "address",
				"name": "_tokenCollection",
				"type": "address"
			}
		],
		"stateMutability": "nonpayable",
		"type": "constructor"
	},
	{
		"anonymous": false,
		"inputs": [
			{
				"indexed": false,
				"internalType": "address",
				"name": "user",
				"type": "address"
			},
			{
				"indexed": false,
				"internalType": "uint256",
				"name": "amount",
				"type": "uint256"
			}
		],
		"name": "ClaimFunds",
		"type": "event"
	},
	{
		"anonymous": false,
		"inputs": [
			{
				"indexed": false,
				"internalType": "uint256",
				"name": "offerId",
				"type": "uint256"
			},
			{
				"indexed": false,
				"internalType": "uint256",
				"name": "token_id",
				"type": "uint256"
			},
			{
				"indexed": false,
				"internalType": "address",
				"name": "user",
				"type": "address"
			},
			{
				"indexed": false,
				"internalType": "uint256",
				"name": "price",
				"type": "uint256"
			},
			{
				"indexed": false,
				"internalType": "bool",
				"name": "fulfilled",
				"type": "bool"
			}
		],
		"name": "Offer",
		"type": "event"
	},
	{
		"anonymous": false,
		"inputs": [
			{
				"indexed": false,
				"internalType": "uint256",
				"name": "offerId",
				"type": "uint256"
			},
			{
				"indexed": false,
				"internalType": "uint256",
				"name": "id",
				"type": "uint256"
			},
			{
				"indexed": false,
				"internalType": "address",
				"name": "owner",
				"type": "address"
			}
		],
		"name": "OfferCancelled",
		"type": "event"
	},
	{
		"anonymous": false,
		"inputs": [
			{
				"indexed": false,
				"internalType": "uint256",
				"name": "offerId",
				"type": "uint256"
			},
			{
				"indexed": false,
				"internalType": "uint256",
				"name": "id",
				"type": "uint256"
			},
			{
				"indexed": false,
				"internalType": "address",
				"name": "newOwner",
				"type": "address"
			}
		],
		"name": "OfferFilled",
		"type": "event"
	},
	{
		"anonymous": false,
		"inputs": [
			{
				"indexed": true,
				"internalType": "address",
				"name": "previousOwner",
				"type": "address"
			},
			{
				"indexed": true,
				"internalType": "address",
				"name": "newOwner",
				"type": "address"
			}
		],
		"name": "OwnershipTransferred",
		"type": "event"
	},
	{
		"stateMutability": "nonpayable",
		"type": "fallback"
	},
	{
		"inputs": [
			{
				"internalType": "uint256",
				"name": "_offerId",
				"type": "uint256"
			},
			{
				"internalType": "uint256",
				"name": "price",
				"type": "uint256"
			}
		],
		"name": "BuyNFT",
		"outputs": [],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "string",
				"name": "_tokenURI",
				"type": "string"
			},
			{
				"internalType": "uint256",
				"name": "amount",
				"type": "uint256"
			},
			{
				"internalType": "uint256",
				"name": "price",
				"type": "uint256"
			}
		],
		"name": "SetPrice",
		"outputs": [],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "to",
				"type": "address"
			},
			{
				"internalType": "uint256",
				"name": "amount",
				"type": "uint256"
			}
		],
		"name": "Withdraw",
		"outputs": [],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "offerCount",
		"outputs": [
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			}
		],
		"name": "offers",
		"outputs": [
			{
				"internalType": "uint256",
				"name": "offerId",
				"type": "uint256"
			},
			{
				"internalType": "uint256",
				"name": "id",
				"type": "uint256"
			},
			{
				"internalType": "address",
				"name": "user",
				"type": "address"
			},
			{
				"internalType": "uint256",
				"name": "price",
				"type": "uint256"
			},
			{
				"internalType": "bool",
				"name": "fulfilled",
				"type": "bool"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "",
				"type": "address"
			},
			{
				"internalType": "address",
				"name": "",
				"type": "address"
			},
			{
				"internalType": "uint256[]",
				"name": "",
				"type": "uint256[]"
			},
			{
				"internalType": "uint256[]",
				"name": "",
				"type": "uint256[]"
			},
			{
				"internalType": "bytes",
				"name": "",
				"type": "bytes"
			}
		],
		"name": "onERC1155BatchReceived",
		"outputs": [
			{
				"internalType": "bytes4",
				"name": "",
				"type": "bytes4"
			}
		],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "",
				"type": "address"
			},
			{
				"internalType": "address",
				"name": "",
				"type": "address"
			},
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			},
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			},
			{
				"internalType": "bytes",
				"name": "",
				"type": "bytes"
			}
		],
		"name": "onERC1155Received",
		"outputs": [
			{
				"internalType": "bytes4",
				"name": "",
				"type": "bytes4"
			}
		],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "owner",
		"outputs": [
			{
				"internalType": "address",
				"name": "",
				"type": "address"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "renounceOwnership",
		"outputs": [],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "bytes4",
				"name": "interfaceId",
				"type": "bytes4"
			}
		],
		"name": "supportsInterface",
		"outputs": [
			{
				"internalType": "bool",
				"name": "",
				"type": "bool"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "tokenCount",
		"outputs": [
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "newOwner",
				"type": "address"
			}
		],
		"name": "transferOwnership",
		"outputs": [],
		"stateMutability": "nonpayable",
		"type": "function"
	}
]

The contract address is : 0x383cAe6B39ad82305242EFcfDa6EC5B2a52B4620

and listing function is called “Offers” with ID = 1.

Thank you so very much!

1 Like

First - an issue I see is that the single input for the offers function does not have a name.

I used the contract address you sent on etherscan to find the contract and decompile it. This function decompiles to

def offers(uint256 _param1) payable: 
  require calldata.size - 4 >=′ 32
  require _param1 == _param1
  return offers[_param1].field_0, 
         offers[_param1].field_256,
         offers[_param1].field_512,
         offers[_param1].field_768,
         bool(offers[_param1].field_1024)

_param1 is not the actual name. Guessing based on this statement:

That _param1 is “id”. Is this correct?

Thanks a lot for the clarification:
That _param1 is indeed the “offerId”.

1 Like