Sui
Building the Capy Prototype on Sui
Sui Capys, Mysten Labs’ new prototype, serves as a developer preview and demonstrates key capabilities of the Sui ecosystem. In this decentralized game, players buy, trade, breed, and accessorize Capybaras, the cute South American semi-aquatic rodent. Sui developers can adapt many of the principles and code examples outlined here for their own projects.
As programmable objects on the Sui blockchain, Capys demonstrate principles such as asset ownership, transferability, and dynamic object fields. They appear in a player’s wallet along with accessories, including hats, bicycles, and scarves. To preview Capys now, head to Capy.art.
Developing Sui Capys using Move required defining the basic modules, creating types, and most importantly, building a registry to record and verify Capys. One unique feature of the prototype is the ability to breed two existing Capys, generating a completely new one based on characteristics of the breeding pair.
To reiterate, this is a developer preview to showcase unique aspects of Sui and for developers to reference when building projects of their own. Capys are not for sale.
Disclaimers
This dApp is currently considered an early Alpha, so it may be a little rough around the edges.
The dApp runs on Sui's Devnet which does not have the maturity and stability of a Mainnet.
There is a known Sui Wallet bug on transaction history when using Capys, and we'll be shipping a Wallet fix next week to address this.
We’re planning to update Capy.art to the wallet adapter standard in the near future.
Sui Capys is a demo specifically to inspire our developer community. This is not an airdrop. Please faucet responsibly – do not spam our Devnet faucet.
Capy Architecture
The Capy application (Github) consists of three modules: capy
, capy_items
, and capy_market
. These modules define the Capys, accessories, and trading mechanism.
We began the development process by defining specific principles to make the prototype enjoyable and performant. The following principles helped determine the architecture and implementation choices:
Capys should be freely transferable and usable in any on-chain application.
Types should contain a minimum amount of data to maintain performance.
Events can be used to emit static data to be fetched by the indexer.
The prototype should be extendable so new properties can be added later.
Developers looking to build games and applications on Sui should begin by defining core concepts such as these, which will guide the development process.
Capy Core
The capy
module defines the core functionality of Sui Capys: it defines a Capy
type as well as granting the publisher with a CapyManagerCap
, opening admin functions for the bearer. It defines CapyRegistry
, the centralized prototype state, and ways in which it can evolve.
Type: Capy
Capy
, the main type of the application, is an owned object with a defined set of attributes: 32 genes and additional utility information required for prototype features. Capy
has two abilities, key
and store
. The former makes it an own-able asset and the latter allows free transfer and wrapping.
The
gen
property marks the Capy’s generation. First Capys havegen 0
; newer breeds have their parents’ generation plus one, sogen 1
,gen 2
, etc.The
src
property enables explorer display of the image. Capys themselves don’t store their full image as it is dynamic and can be changed when new items are added.The
genes
property stores the gene sequence, a 32-byte vector which is used to calculate attributes and selecting genes for a newborn during breeding.The
item_count
is a utility property tracking the number of objects attached to each Capy.The
attributes
property stores human-readable attributes generated during breeding. For example,{ “name": "pattern", "value": "panda" }
.
This set of fields is a minimal requirement for Sui Capys functions, including breeding or adding/removing items.
Type: Capy Registry
CapyRegistry
, a shared object required for breeding, stores the total number of Capys ever born and contains a pseudo-random seed, described below in the Gene science section, used for gene selection during breeding. It contains all attribute definitions assigned to newborns at the breeding stage.
New attributes can be added to the prototype, as described in the admin features section below.
Type: CapyManagerCap
The CapyManagerCap
is a capability sent to the module publisher (the sender of the publishing transaction) when a module publishes. It authorizes admin actions in all of the modules, including capy_items
and capy_market
.
Initializer
Capys are a standalone (non-generic) application, so their main logic can be launched in the module initializer. The init
function does two things:
Creates a
CapyManagerCap
and sends it to the module publisher.Creates and shares a
CapyRegistry
.
Admin Functions
For the application to become playable and have some meaning, admin has to perform a set of actions:
The
add_gene
function registers a newGeneDefinition
in theCapyRegistry
. During breeding, all existing attributes in the registry are assigned to a new Capy. If a newGeneDefinition
(Attribute) was added to the prototype, Capys born before this addition won’t get it, but their children will. Each gene definition has a name and a set of selectors which are used to choose the value of each attribute.The
batch
function allows batch creation of Capys with predefined genes. It is used for initialization and in later stages to populate the marketplace with more Capys for new users.
Breeding
The main piece of logic which creates unpredictability and helps prototype evolution is the capy::breed
function. Any player with two Capys can perform this function. Logic for this function is the following:
Based on
CapyRegistry.capy_hash
select parent genes for the newCapy
.Get list of current
GeneDefinitions
from theCapyRegistry
and set attributes.Emit an event with the new Capy’s data.
Return a new
Capy
(usebreed_and_keep
to send to sender).
Gene Science
Before we get to the most interesting part of the application, we must note that this solution does not provide absolute unpredictability, and therefore should not be used for applications with high stakes. But it does create some degree of randomness by turning user input into a pseudo-random modifier.
A really fun and unique feature of this prototype is the ability to breed
two existing Capys to generate a third. The new Capy inherits characteristics of its parents.
The breed function takes two parent Capys and computes genes for the newborn. For this action to be fair and random, we need to have a selection algorithm and a seed. CapyRegistry
provides the seed (stored as capy_hash
) and is updated after each breed. The algorithm is the following:
Use hashing function (
sha3_256
) three times with salt to generate three vectors of 32 bytes (marked as A, B, and C) derived from thecapy_hash
.Use the first vector (A) for parent gene selection. If the value of the Nth byte is more than 126, select the first parent’s gene. Otherwise, select the second parent’s gene. As shown in the diagram above, the first gene will be P2, second P1, third P2, and fourth P1 again (up to N=32).
The second vector (B) defines a chance of mutation. If the value in position N is more than 250, use the same position in the third vector (C) to select a value for mutation. In this example, the third gene will mutate and its value will be 42.
Capy Items
This drastically simple module defines wearable items which can be added to each Capy, and how we implement the frontend display. Items can only be added by the Capy Admin, as it requires authorization with a CapyManagerCap
.
Managing Items
Adding and removing accessories to Capys makes use of dynamic object fields, a more efficient and user-friendly replacement for parent-child objects in Sui. Dynamic Fields allow arbitrary names and can be added and removed on-the-fly.
The following code adds an item to a Capy:
Capy Market
To acquire and sell Capy
s and CapyItems
, we created the Capy Market. This module makes use of dynamic object fields and locks Items to be acquirable after paying their price
. In this marketplace architecture, one marketplace object exists per one item type (CapyMarket<Capy>
sells Capy
s while a different object, CapyMarket<CapyItem>
, sells Capy accessories), listings are attached to the marketplace as dynamic object fields, and listed objects are attached to Listings.
+--> Listing --> T
CapyMarket<T> +--> Listing --> T
+--> Listing --> T
Marketplace and the List Function
Each Marketplace instance serves only one type. In this application, one instance of Marketplace exists for the Capy
type and another for the CapyItem
type.
The List
function makes use of Dynamic Fields. It makes a listed Item a field of a Listing
and then makes Listing
a field of CapyMarket
.
Capy Inspiration
We created the Capy prototype to show off some key Sui features and inspire developers in their own projects. Capys leverage Sui’s object-oriented nature to allow portable accessories that players can trade and buy, and the generation of new Capys based on parental attributes. We designed the prototype to be infinitely extendable so that it will delight users and developers alike.
We hope the examples and code here prove useful to Sui developers. A few implementations that should stand out include the Capy Market, Accessories, and Breeding. The Capy Market serves as a model for any trading or store mechanism. Accessories show a good use of Dynamic Fields. Breeding offers a unique means of automatically generating new objects with infinite applications.
Have fun and happy developing!
Learn more about Sui
Build with us!
We’re excited about how the future unfolds and invite creators and builders to join us.
Blog