Basic Living Assets Server
Create a brand new server application with endpoints to mint and evolve Living Assets
Last updated
Create a brand new server application with endpoints to mint and evolve Living Assets
Last updated
freeverse.io
In this tutorial, we are going to create a simple server application from scratch, that offers two endpoints - one to create a new Living Asset (a dynamic NFT) and assign it to a user, and the other to evolve the properties of an existing asset. The server will use GraphQL to interact with the Living Assets API.
Creating and evolving Living Assets requires proof of authority - for example, for an asset that is going to be used in a game, only the game developer should have the authority to create that asset and verify its utility in the game. For this reason, all Freeverse clients get created for them their own 'universe' - a dedicated area within our Layer-2 where they have control. To demonstrate authority, any transaction that modifies the content of the universe must be cryptographically signed by the universe owner's private key.
As the creation or evolution of Living Assets requires signing with the game developer's private key, these actions must be executed within a server application which stores that key. Doing it from the client would require storing the private key within the game binary, thus handing it to every app installation, with all the attack vectors associated to it.
The figure below shows an example of how the server this tutorial will start to build will fit into a typical game.
To follow this tutorial you should have:
Basic knowledge of development in NodeJS, and basic knowledge of how POST operations work in RESTful applications. Knowledge of GraphQL is useful, but not mandatory; an introduction can be found here.
A development machine with the latest version of NodeJS and Node Package Manager installed.
A sandbox universe (and associated private key) within the Living Assets API. If you do not have one of these, please contact us.
A basic knowledge of the Create & Evolve functions described here.
While there are many different server application frameworks, in many different languages, for this tutorial we will ExpressJS. While this framework has perhaps gone out of fashion recently, it serves the purpose of a quick way of creating a server with different routes for endpoints. Feel free to adapt to your favourite framework! The rest of the code (creating mutations, signing etc.) is framework agnostic.
All identification in the Living Assets API is done by Ethereum compatible wallet addresses. Each of your users must be identified via a public Ethereum compatible wallet address - like the ones created in this tutorial.
Create a new NodeJS application from the console, and install the packages as shown below. We will need Express for server routing, GraphQL-Request for connecting to the Living Assets API, and two of Freeverse's packages to simplify signing transactions. Navigate to a new folder in your terminal and run the following commands, one at a time:
On project initialization, give your project a name and accept all of the defaults.
Now create a starting javascript file called index.js, add a simple console.log("hello, world!"); and test it by running
The very simple server in this tutorial only needs to expose two endpoints, both of which will accept JSON data via POST. One will use this data to create (mint) a new Living Asset, the other will use the data to evolve (update) the properties of an existing asset.
Overwrite the content of index.js with the following code:
Here, there is a simple Express server which accepts two POST endpoints, both of which simply echo the received JSON back as a response.
Run the example from the terminal as above, then test it with the following CURL command from the terminal (or by sending the JSON object via a REST testing application such as Postman):
You should see this response in the Terminal:
Congratulations, you have a server up and running!
Now we have our server endpoints, let's create and sign a mutation that creates an asset for a user. For this example, we'll simply create an asset and assigns it to the same account as the universe owner (using the public address as the identifier).
Getting the User Nonce
Modify the first half of index.js (up to the end of the '/create/' route, with the following code, which queries the Living Assets API to get the nonce value of a specific user.
Run this example with the same CURL command as above, and you should see the user nonce printed in the terminal. We will use this nonce when building the mutation to create the asset.
Signing and Creating the Create Asset Mutation
We will use two Freeverse NPM packages to sign transactions and build the mutation strings (the repositories for these packages are freely available here).
Create a new file in your project directory called freeverse.js and type the following code:
Make sure to paste your universe ID and private key in the relevant variables.
This function accepts as arguments the four parameters that we must supply to the create_asset transaction in the Freeverse API.
The first two commands of the function use these passed parameters to create an "operations string" with the correct format (if you want, you can output the operation variable to the console to see what it looks like).
The sign command takes that operations string and signs it using the supplied private key.
Finally, the mutation command parses the operations string (including escape characters where required), combines it with the signature, and outputs the final GraphQL mutation.
Now, return to index.js and add this newly created file to the list of dependencies at the beginning.
Then, in the route for '/create/', replace the final response.send() command with the following code:
As you can see, while we are creating a new asset for owner, the properties and metadata are simply empty objects, for the time being.
Upon calling the same CURL function, the response should be a string of text which represents the mutation that must be sent to the API to create the asset.
You can test this mutation directly now in the playground below (for staging scenarios only). Paste the output code into the left-hand window and press the play button. The right-hand window should show a successful result, with the ID of the newly created asset, as illustrated in the image below.
If you try to run this mutation again (by pressing the Play button again) you will see it returns an error! This is because the nonce for this user has changed as a result of the previous transaction. This is why we need to query the nonce each time before minting an asset.
Sending the mutation to the Living Assets API
All that remains for us to do is to automatically send this mutation to the Living Assets API. We have already created a GraphQLClient object to request the asset nonce, so we can reuse that to send the mutation. Replace the final lines of the '/create/' route to be:
Upon executing the CURL request again, this time the successful result of the mutation will be returned, which contains the newly created asset ID.
You can parse this response to extract the newly created asset ID to store elsewhere in your server application (for example, for tracking which user owns which assets).
Including POSTed data in the mutation
Currently, the user ID for whom we are minting the asset is hardcoded, as are the asset properties and metadata. Let's change that to feed this data from the POST request into the mutation. To avoid long multiline CURL requests, we'll put our JSON data into a file, and pass the filename to the CURL request. Remember to call the CURL request from the same directory as the JSON file!
While the asset properties can be anything you want, for full compatibility with the other elements of the API (Living Assets Scan app, marketplace etc.) Freeverse recommends the use of a standard format for NFT properties, demonstrated below. The metadata, which is not viewable by the end user, can be any data you want.
testCreate.json
To pipe this data into the mutation, we must change the first lines of the '/create/' route to the following:
You can now use the returned asset ID to see the asset details in the Sandbox Living Assets Scan app. In the production Living Assets Scan app, from here you can also verify ownership and properties on Polygon.
The steps to change the properties of an existing asset are very similar to those for creating a new one. The principal difference is that the nonce required is associated with the asset, rather than with the user. However, almost everything else is the same.
Note that when you update the asset properties you are overwriting the old ones i.e. you must pass the entire asset properties JSON.
First, we need to add a new function to freeverse.js, which creates and signs the mutation to update the asset properties. This code is almost identical to that which creates and signs the 'create' mutation, only changing the user ID for asset ID, and changing the operation type:
We then modify the '/evolve/' route - again, very similar to the '/create/', but changing the nonce query and only a few key variables:
Finally, we create a new JSON file, changing the 'owner' property for 'asset', and pasting the assetID that was returned in the terminal from the response to the 'create' call.
Feel free to change any of the properties to see how they are updated!
Let's call our new route, making sure to specify the new JSON filename:
And then check out the updated asset in the Sandbox Living Assets Scan!
In this tutorial we created a basic server that allows you to mint and evolve Living Assets. For practical use, several steps are now available:
add authentication to the endpoints (in our demo, anybody with access to the endpoint can mint as many Living Assets as they want, for any owner!). In the next tutorial, we'll learn how to add a JSON Web Token for authentication, and also add a second layer of encryption to the payload requests of both the '/create'/ and '/evolve/' routes
create functionality to add various other queries to the Living Assets API to the application - a comprehensive set of examples is available here.
connect to a database to track ownership independently on the Living Assets API
The full code for this tutorial is available here.
Thanks for following along!