Create & Evolve
Creation and Evolution queries
Creating and evolving Living Assets are queries that require the signature of the owner of the corresponding Universe where the affected assets live.
Generate your Universe
When on-boarded to the Living Assets platform, clients are asked to provide a web3 address, and a new Universe will be created, controlled by such web3 address.
The initial Universe will be created first in the L2 testnet; when ready to go live, a new Universe will be created in the L2 mainnet.
The provided web3 address can be controlled by whatever means desired, from a simple web3 wallet under one person's control, to a sophisticated multisig approach that implements certain business logic and governance. All options are identical from the point of view of the Living Assets platform: all complexity is encapsulated in the provided signature.
Straight-to-Code Examples
To get your hands on working code quickly, please visit the Examples repository, and go straight to the asset_create
and asset_evolve
scripts inside the nodejs
folder.
As shown in the examples, the main class that helps build the query parameters easily is AtomicAssetOps
, which can be found in the API Signer NPM package.
The Execute Mutation
Creating and evolving assets in a given universe is done via a GraphQL mutation which requires three input parameters:
ops
: a string, in JSON format, with the modification operation wished to be executed in the corresponding Universe.signature
: the result of signing the operations string with your account.universe
: your universe id.
The mutation will fail if the passed signature does not match with the owner of the universe.
The state of the newly created/updated assets can be readily queried. The following query returns both the already synchronized (settled) state, as well as the newest (possible pending) state; they both will coincide when the verse
returned in the response's receipt is reached.
Building the mutation with AtomicAssetOps
AtomicAssetOps
Instantiate the class AtomicAssetOps
to build the three parameters required by the mutation. The following example code build a create_asset
operation (via the createAssetOp
method), inserts it in the mutation (via the push
method), and signs
the operation.
The content of mutation
is to be sent to the GraphQL endpoint. In the example, it looks as follows:
Signing the Mutation
Universe Owners can use their own web3-compatible method to sign the mutation, instead of using the sign()
method provided by the AtomicAssetOps
class. Just use the digest()
method to get the exact string that needs to be signed:
Details on the Mutation Parameters
Here are all the details on the ops
field required by the Execute Mutation, as well as the parameters it requires.
ops [JSON]
ops [JSON]
type
"create_asset" "set_asset_props"
msg
JSON object. See message options below.
msg [JSON]
msg [JSON]
nonce
Target owner's user nonce for create_asset
Asset nonce for set_asset_props
id
The ID of the asset (mandatory for set_asset_props
)
owner_id
The web3 address of the asset owner (mandatory for create_asset
)
props
metadata
A string containing JSON object with the private metadata of this asset
props [JSON]
props [JSON]
The props
string parameter is a JSON object that contains any public property wished to be assigned to the asset. We advice to follow a de-facto standard, as detailed in Asset Properties Standard. If you wish to follow the standard, the typical fields would include, at least, the following:
name
The name of the asset
description
The description of the asset
image
A link to the asset image; an ipfs://
route is recommended for decentralization
attributes
a JSON array with each entry containing trait_type
and value
animation_url
A link to asset media: video, sound, etc.; an ipfs://
route is recommended for decentralization
Once an asset is created, the number of attributes does not need to remain constant. New attributes can be added as part of the set_asset_props
mutation. Examples: adding the charisma
attribute to assets that were created without it, or adding a specific license
field making explicit the rights transferred to asset owners.
Images, videos, and media in general, can be in any format that the applications/marketplaces that will show the assets are compatible with. Media can be uploaded separately to IPFS and linked in the corresponding image/animation_url
fields. The Customizable Marketplace currently supports these formats: jpeg, png, gif, webp, tiff
.
metadata [JSON]
metadata [JSON]
The metadata JSON object is intended to expand the asset properties with data that will not be stored in the blockchain. Specific applications or marketplaces may parse this field to implement client-side business logic.
nonce [uint]
nonce [uint]
All users and assets within a universe are assigned a Number-Used-Once (NOnce) value. Creation and evolution queries require the correct nonce
value as parameter, otherwise the mutation will fail. The nonce
value prevents replay attacks, whereby the same signed operation is held by an attacker, and relayed multiple times.
create_asset
operations require passing the user nonce, in a given universe, corresponding to the initial owner to whom the created asset will be assigned.set_asset_props
operations require passing the asset nonce.
Applications can either keep track of user and asset nonces themselves, or query them when needed before building Execute Mutations, as detailed in these examples:
The Response to the Execute Mutation
The API responses to execute mutations contain a Receipt
Json object, which includes the signature of the L2 relayer, confirming that the changes will be applied at the current verse.
If the mutation contains one or several create_asset
operations, the receipt contains the assetId
of the corresponding created assets.
This is the anatomy of a Receipt
:
ops
an array with the operations applied
results
an array, with entries aligned with ops
, containing the unique Ids
of the assets created for each create_asset
, and a bool confirming the update for each set_asset_props
universe
the universe Id where the ops are applied
signature
the signature provided as input to the query
verse
the verse at which ops
will be synchronized with the Layer 1 (= currentVerse + 1
)
receiptSignature
the Layer 2 signature committing to the rest of returned parameters
Here's an example of the return of a query that created an asset, and evolved another asset, in one single atomic call:
Here's a code example showing how to verify the signer of the receipt signature.
Last updated