User-defined objects #1068
Replies: 1 comment 1 reply
-
Thank you for such a detailed write up! I really like the idea of adding more customizability/programmability to assets, and have been trying to think in this direction as well. There are a few things, however, that are not yet clear to me in the proposal. One such thing is who/how keeps track of the "bookkeeping data" about created objects. By bookkeeping data I mean things like the total number of issued coins for a fungible asset, or all issued non-fungible assets. Currently, we have a dedicated storage slot in the faucet accounts to keep track of this data - but how would this be handled in the model where any account can create objects of different types? Somewhat related to the above: in the current model, the assets are "static". That is, once issued they don't really change (an exception to this is the amount part of the fungible asset). One reason for this is that the original issuer needs to make sure they don't create "duplicate" assets. But if an asset can be modified after it is issued, this may become complicated. Another way to think about this is that we need to make sure that an asset's "vault key" remains stable throughout its lifetime while some other attributes of an asset are allowed to change. Also, it seems to me that we need to route most interactions with the objects through the vault. That is, instead of calling procedures on an object directly, we'd call a procedure on an object that is stored in a vault. This way, we can ensure that an object can be modified only via its "native" procedures. So, for example, instead of first removing an asset from the vault and then adding it to a note (via two separate procedures), we'd have to provide kernel procedures like:
With this setup it would be possible to define assets generically. For example, the asset definition itself would know how to insert an asset into the vault and so, for example, for fungible assets Another question is what should be the capabilities of the native asset procedures. For example, it would be great to have the ability to define an asset that can only be transferred to accounts which meet certain criteria (e.g., the owner of the account is 18 years old or older). For this, native asset procedures should be able to call methods on the account itself (maybe via FPI?). |
Beta Was this translation helpful? Give feedback.
-
Motivation
The current asset model in Miden supports fungible and non-fungible assets, which are a way for users to represent value and ownership on-chain. This model couples the transaction kernel to these specific asset types as it handles construction, modification, and destruction of these assets. I think this coupling is undesirable as it makes the protocol hardcoded to those two asset types and makes extension from users impossible.
A more generic and decoupled approach would be to adopt an object-based model, where asset types are represented as user-defined objects defined outside the kernel but managed by it. The kernel would operate on these objects as opaque entities, focusing solely on object management rather than specific asset logic. This change would make the programming model more adaptable and better at handling diverse use cases. At the same time it would make the transaction kernel and protocol at large agnostic to the concrete assets/objects that are represented.
Idea
The basic idea is to have the transaction kernel manage objects. An object represents value or ownership, just like assets, but is user-defined. The details of each object would be implemented outside the kernel, keeping the kernel decoupled. In this model the kernel would only know about objects as black boxes and offer generic methods for creating, setting and getting fields as well as destroying them.
To illustrate this further, here are a few bullet points to hopefully get the idea across. I might be missing some details of how the current asset model has evolved and whether some of its limitations are byproducts of constraints I don't know about. I might even be thinking incorrectly about the asset model. It's intended both as a proposal but also as a way to learn more about the design choices that led to the current model in case I have misunderstandings.
I'll try to explain what I mean in more detail with an example. Let's say we want to represent a fungible asset issued by a faucet in this object model.
miden_std
library (i.e. aMastForest
) which is published as a package on-chain. It could contain amiden_std::Coin
type to represent what are now fungible assets.0
to differentiate between different object types from the same package.miden_std::Coin
objects have different IDs.miden_std::Coin
can only be modified throughmiden_std::Coin::*
procedures.Here is a more concrete visual example for how issuing a new type of
Coin
might work, which builds on the proposed VM component model.In this example, a user wants to issue a
Coin
of theExample
flavor, i.e. a type they defined. To do so, they execute a transaction against their own account whose code package isuser_package
. Here, every package is run in a separate VM component whose ID is the package ID (assuming that's feasible). When the account callsmiden_std::Coin::new
, it passes a pre-existingExample
object (just to keep this simple) from its vault andmiden_std::Coin::new
would verify that the issuer of thisuser_package::Example
object is the calling component, i.e. that the issuer account ID and the component ID are equal. This might still require something like thecaller
instruction. This is something only theCoin::new
procedure would do. ACoin::get_amount
procedure could be executed by any caller as it does not require any kind of authentication.In the second step,
kernel::create_object
would create a newCoin
object whose issuer is set to the component ID ofmiden_std
which is the same as themiden_std
package ID. So more generally, this allows objects of typepackage_id::Type
to be created/modified/destroyed only by procedures that are defined in the package with IDpackage_id
.The
Coin
object would store in one of its fields that it is of flavorExample
. Then, twoCoin<Example>
objects could be merged into one by aCoin::merge
procedure, but it would fail if called onCoin<Example>
andCoin<OtherType>
.The
Coin
object is returned to the control of the user account component and it can choose to store it in its vault or transfer it to a note via a call to another kernel procedure.I hope this covers a rough, high level idea of this approach.
Advantages
NameObject { name: Word }
type which represents ownership over a name and the capability to update it.StakedExample
object which represents a receipt for having stakedCoin<Example>
and represents the capability to unstake and retrieve the staked coins.Coin
type there could be aTreasuryCapability
object type which gives whoever owns it, the right to increase or decrease the supply of aCoin<T>
. Burning the object would make the supply verifiably fixed. This is the kind of stuff we could technically have with the asset model as well, by introducing a "fungible faucet treasury capability", but we wouldn't realistically do it because it would be a manual extension of the protocol. With an object based model this would be comparatively easy.Coin
andTreasuryCapability
).NameObject
as a non-fungible asset, which must be hashed first to verify it is the actual pre-image. This must be done for every user-defined asset in the current model, iiuc.NameObject
rather than a name object which is hashed into aNonFungibleAsset
. E.g. a name service could describe in its API docs that to change the ID to which a name points, aNameObject
must be provided to prove ownership over it rather thanNonFungibleAsset
, which is less clear.miden_std
and the kernel can evolve independently over time.NonFungibleAsset
object, that works the same as the current one, i.e. it commits to something. In the future, new object types could be defined without having to upgrade the protocol.Drawbacks
Inspiration
The above is an idea for an object-based model on Miden, replacing the current asset model. It is inspired by Sui Move's object-based programming model. I personally really enjoyed using their object model as a developer and think that Miden could benefit from something similar, so the above is an adaptation to hopefully fit into Miden's architecture. Here is a link to Sui's
Coin
type to get an idea of what methods could be possible and how different object types could be used together.Conclusion
There are probably many details I haven't though of, as this would be a pretty big change. I would be interested if anyone sees the merits in something like this, especially from a developer perspective and if we should explore this further. Thanks for taking the time to read and I would be happy to receive feedback on this!
Beta Was this translation helpful? Give feedback.
All reactions