RGB smart contracts by example #48
dr-orlovsky
started this conversation in
General
Replies: 0 comments 4 replies
-
Thanks for the great writeup. It was mostly straightforward and easy to understand. I have some questions about the last
|
Beta Was this translation helpful? Give feedback.
3 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
State and operations
RGB smart contract defines state, owners of that state, and operations, which participants of the contract (owners and sometimes more broad public) can execute to update the state.
Operations include genesis operation (issuance of the contract), state transitions updating the existing state (or adding to the state data) and state extension, which represent a mechanism how anybody (public) can participate in the contract operations.
State of the contract consists of state atoms of different data types. Data types are defined in the same terms as variable types in any structural language (C, Rust, Haskell, etc).
RGB contract always have a well-defined parties of the contract, which hold ownership rights over atoms of state. The state owned by a contract party is called owned state.
Let's start with writing a simple contract managing decentralized identity backed by a PGP key. The "smartness" of the contract (comparing to normal PGP/GPG and Web of Trust) comes from the fact that when a revocation operation is executed, everybody in the world will know about it (since thay can see that the UTXO, associated with the key -- the owned state -- was spent), and it can be proven whether at any given moment of time the identity was valid -- or it was already revoked.
Contract business logic in RGB is defined through so-called schema; the specific RGB contract must implement some schema. One may think of a schema as a "class" definition in the OOP world; in that terms specific RGB contracts are "class instance" created by the schema constructor (genesis operation). Such approach allows to separate role of contract developer (in RGB called schema developer) and contract issuer: the first one needs to be an experienced developer, while the second one is not required to know anything about coding or security at all. This also promotes re-use of common codebase by different issuers for the same typical use cases (like fungible assets), reducing the risk of mistakes.
The schema defines a rules of how the contract operates. Now let's put it into a practice by creating a specific identity contract, and then doing a revocation:
Now, let's add some tokens to the contract, in form of "I owe you" obligations provided by the decentralized identity:
Here we see multiple new things, let's try to explain them one by one.
First, it is the
global
keyword used to define asset ticker and name as two strings.We already covered owned state composed of the rights holder and state atoms; but in some situations a contract needs a state which is "global" for the contract and is not "owned" by anyone (i.e. not assigned to a UTXO single-use-seal). The name of the asset (and ticker) is that sort of information: in the examples above it does not "belong" to a contract party but instead is a "property" of the contract itself. Another example could be the name of the identity holder which can't be changed and thus can't be assigned to a UTXO single-use-seal. Such state is defined with the
global
keyword.It is important to note, that while the global state is not "directly owned" by any party, it still may be updated through state transitions -- but only if schema enables that explicitly. In such cases the use of the global state (as compared to the owned state) is reasonable only when the user may opt-out from future state updates (i.e. do not define a new single-use-seals) but still needs to keep the state. The asset name is again such an example, since even if the asset can be renamed, future renames after certain renaming may be prohibited (i.e. no new owned state can be created), but the asset name should stay.
global
allows exactly that.Second, the use of braces, brackets and question mark around and next to the state name. Both braces and brackets mean that the operation works not with a single state atom, but instead an array (braces) or set (brackets) of state atoms. Set differs from an array in the fact that all elements of the set must be unique, while in array they may repeat. Coming back to our operations, asset transfer may spend a number of assets from different owners, but all of them must be unique (to prevent double-spend), i.e. form a set. However, when defining a receivers, multiple state atoms may be equal (i.e. you can send 10 tokens to the same UTXO
N
times, such that the receiver will get10*N
tokens in total, but through different "inputs", which may increase privacy).Question mark is used to inform that the state may be absent, i.e. in case of array or set it can be empty - or in case of a single item, it is optional.
APIs exposed by contracts
But how the wallet makes the sense of the contract? RGB contract can do a lot of things, and if schema developers would need to do a separate wallet for each schema the entrance threshold would be too high. To avoid such situation a concept of contract interface was created. A contract interface is a standard way communicating with RGB Node asking it for a semantically-meaningful state and creating operations. Such concept of interface is similar to the concept of ERC standards and ABI files in Ethereum world; the most common interfaces are called "RGBxx" and are defined as a separate LNP/BP standards.
Here, instead of using existing interface standards we will create an interface for a generic fungible token from scratch to explain the way they work:
RGB smart contract can implemnet multiple interfaces. In our case it would be desirable to expose the identity information as well:
Allowing public participation
At the very beginning we had mentioned so-called state extensions. State extension can be created by anybody without doing an on-chain commitment (i.e. without closing any single-use-seals). In this it is similar to genesis. However, the state created by the extension is not "final" (compare to an non-mined transaction in the bitcoin mempool) until it gets included into a valid state transition (like transaction gets mined by being included into bitcoin valid block).
Probably the simplest way to understand state extensions is by example. Let's assume we'd like to do an asset which can be issued by anybody in the world through burning equivalent amount of bitcoins. Such operation can't be a state transition, since we do not have a predefined set of single-use-seals to define a "rights of issue" for an open and unknown set of participants. We can't also do "multiple geneses", since each genesis will define a new RGB contract and the assets under different RGB contracts are not fungible. State extensions were created exactly to address this issue. A contract using them may look in the following way:
Beta Was this translation helpful? Give feedback.
All reactions