github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/docs/concepts/effective-gno.md (about)

     1  ---
     2  id: effective-gno
     3  ---
     4  
     5  # Effective Gno
     6  
     7  Welcome to the guide for writing effective Gno code. This document is designed
     8  to help you understand the nuances of Gno and how to use it effectively.
     9  
    10  Before we dive in, it's important to note that Gno shares several similarities
    11  with Go. Therefore, if you haven't already, we highly recommend reading
    12  ["Effective Go"](https://go.dev/doc/effective_go) as a primer.
    13  
    14  ## Disclaimer
    15  
    16  Gno is a young language. The practices we've identified are based on its current
    17  state. As Gno evolves, new practices will emerge and some current ones may
    18  become obsolete. We welcome your contributions and feedback. Stay updated and
    19  help shape Gno's future!
    20  
    21  ## Counter-intuitive good practices
    22  
    23  This section highlights some Gno good practices that might seem
    24  counter-intuitive, especially if you're coming from a Go background.
    25  
    26  ### Embrace global variables in realms
    27  
    28  In Gno, using global variables is not only acceptable, but also encouraged,
    29  specifically when working with realms. This is due to the unique persistence
    30  feature of realms.
    31  
    32  In Go, you would typically write your logic and maintain some state in memory.
    33  However, to persist the state and ensure it survives a restart, you would need
    34  to use a store (like a plain file, custom file structure, a database, a
    35  key-value store, an API, etc.).
    36  
    37  In contrast, Gno simplifies this process. When you declare global variables in
    38  Gno realms, the GnoVM automatically persists and restores them as needed between
    39  each run. This means that the state of these variables is maintained across
    40  different executions of the realm, providing a simple and efficient way to
    41  manage state persistence.
    42  
    43  However, it's important to note that this practice is not a blanket
    44  recommendation for all Gno code. It's specifically beneficial in the context of
    45  realms due to their persistent characteristics. In other Gno code, such as
    46  packages, the use of global variables is actually discouraged and may even be
    47  completely disabled in the future. Instead, packages should use global
    48  constants, which provide a safe and reliable way to define values that don't
    49  change.
    50  
    51  Also, be mindful not to export your global variables. Doing so would make them
    52  accessible for everyone to read and write, potentially leading to unintended
    53  side effects. Instead, consider using getters and setters to control access to
    54  these variables, as shown in the following pattern:
    55  
    56  ```go
    57  // private global variable.
    58  var counter int
    59  
    60  // public getter endpoint.
    61  func GetCounter() int {
    62      return counter
    63  }
    64  
    65  // public setter endpoint.
    66  func IncCounter() {
    67      counter++
    68  }
    69  ```
    70  
    71  In this example, `GetCounter` and `IncCounter` are used to read and increment
    72  the `counter` variable, respectively. This allows you to control how the
    73  `counter` variable is accessed and modified, ensuring that it's used correctly
    74  and securely.
    75  
    76  ### Embrace `panic`
    77  
    78  In Gno, we have a slightly different approach to handling errors compared to Go.
    79  While the famous [quote by Rob
    80  Pike](https://github.com/golang/go/wiki/CodeReviewComments#dont-panic) advises
    81  Go developers "Don't panic.", in Gno, we actually embrace `panic`.
    82  
    83  Panic in Gno is not just for critical errors or programming mistakes as it is in
    84  Go. Instead, it's used as a control flow mechanism to stop the execution of a
    85  [realm](realms.md) when something goes wrong. This could be due to an invalid input, a
    86  failed precondition, or any other situation where it's not possible or desirable
    87  to continue executing the contract.
    88  
    89  So, while in Go, you should avoid `panic` and handle `error`s gracefully, in Gno,
    90  don't be afraid to use `panic` to enforce contract rules and protect the integrity
    91  of your contract's state. Remember, a well-placed panic can save your contract
    92  from a lot of trouble.
    93  
    94  When you return an `error` in Gno, it's like giving back any other piece of data.
    95  It tells you something went wrong, but it doesn't stop your code or undo any
    96  changes you made.
    97  
    98  But, when you use `panic` in Gno, it stops your code right away, says it failed,
    99  and doesn't save any changes you made. This is safer when you want to stop
   100  everything and not save wrong changes.
   101  
   102  In Gno, the use of `panic()` and `error` should be context-dependent to ensure
   103  clarity and proper error handling:
   104  - Use `panic()` to immediately halt execution and roll back the transaction when
   105    encountering critical issues or invalid inputs that cannot be recovered from. 
   106  - Return an `error` when the situation allows for the possibility of recovery or
   107    when the caller should decide how to handle the error.
   108  
   109  Consequently, reusable packages should avoid `panic()` except in assert-like
   110  functions, such as `Must*` or `Assert*`, which are explicit about their
   111  behavior. Packages should be designed to be flexible and not impose restrictions
   112  that could lead to user frustration or the need to fork the code.
   113  
   114  ```go
   115  import "std"
   116  
   117  func Foobar() {
   118      caller := std.PrevRealm().Addr()
   119      if caller != "g1xxxxx" {
   120          panic("permission denied")
   121      }
   122      // ...
   123  }
   124  ```
   125  
   126  - TODO: suggest MustXXX and AssertXXX flows in p/.
   127  
   128  ### Understand the importance of `init()`
   129  
   130  In Gno, the `init()` function isn't just a function, it's a cornerstone. It's
   131  automatically triggered when a new realm is added onchain, making it a one-time
   132  setup tool for the lifetime of a realm. In essence, `init()` acts as a
   133  constructor for your realm.
   134  
   135  Unlike Go, where `init()` is used for tasks like setting up database
   136  connections, configuring logging, or initializing global variables every time
   137  you start a program, in Gno, `init()` is executed once in a realm's lifetime.
   138  
   139  In Gno, `init()` primarily serves two purposes:
   140  1. It establishes the initial state, specifically, setting up global variables.
   141      - Note: global variables can often be set up just by assigning their initial value when you're declaring them. See below for an example! \
   142        Deciding when to initialise the variable directly, and when to set it up in `init` can be non-straightforward. As a rule of thumb, though, `init` visually marks the code as executing only when the realm is started, while assigning the variables can be less straightforward.
   143  2. It communicates with another realm, for example, to register itself in a registry.
   144  
   145  ```go
   146  import "gno.land/r/some/registry"
   147  
   148  func init() {
   149      registry.Register("myID", myCallback)
   150  }
   151  
   152  func myCallback(a, b string) { /* ... */ }
   153  ```
   154  
   155  A common use case could be to set the "admin" as the caller uploading the
   156  package.
   157  
   158  ```go
   159  import (
   160      "std"
   161      "time"
   162  )
   163  
   164  var (
   165      created time.Time
   166      admin   std.Address
   167      list    = []string{"foo", "bar", time.Now().Format("15:04:05")}
   168  )
   169  
   170  func init() {
   171      created = time.Now()
   172      // std.GetOrigCaller in the context of realm initialisation is,
   173      // of course, the publisher of the realm :)
   174      // This can be better than hardcoding an admin address as a constant.
   175      admin = std.GetOrigCaller()
   176      // list is already initialized, so it will already contain "foo", "bar" and
   177      // the current time as existing items.
   178      list = append(list, admin.String())
   179  }
   180  ```
   181  
   182  In essence, `init()` in Gno is your go-to function for setting up and
   183  registering realms. It's a powerful tool that helps keep your realms organized
   184  and properly configured from the get-go. Acting as a constructor, it sets the
   185  stage for the rest of your realm's lifetime.
   186  
   187  ### A little dependency is better than a little copying
   188  
   189  In Go, there's a well-known saying by Rob Pike: ["A little copying is better
   190  than a little dependency"](https://www.youtube.com/watch?v=PAAkCSZUG1c&t=568s).
   191  This philosophy encourages developers to minimize their dependencies and instead
   192  copy small amounts of code where necessary. While this approach often makes
   193  sense in Go, it's not always the best strategy in Gno.
   194  
   195  In Gno, especially for `p/` packages, another philosophy prevails, one that is
   196  more akin to the Node/NPM ecosystem. This philosophy encourages creating small
   197  modules and leveraging multiple dependencies. The main reason for this shift is
   198  code readability and trust.
   199  
   200  A Gno contract is not just its lines of code, but also the imports it uses. More
   201  importantly, Gno contracts are not just for developers. For the first time, it
   202  makes sense for users to see what functionality they are executing too. Code simplicity, transparency, 
   203  explicitness, and trustability are paramount.
   204  
   205  Another good reason for creating simple, focused libraries is the composability
   206  of Go and Gno. Essentially, you can think of each `p/` package as a Lego brick
   207  in an ever-growing collection, giving more power to users. `p/` in Gno is
   208  basically a way to extend the standard libraries in a community-driven manner.
   209  
   210  Unlike other compiled languages where dependencies are not always well-known and
   211  clear metrics are lacking, Gno allows for a reputation system not only for the
   212  called contracts, but also for the dependencies.
   213  
   214  For example, you might choose to use well-crafted `p/` packages that have been
   215  reviewed, audited, and have billions of transactions under their belt, boasting
   216  super high stability. This approach can make your code footprint smaller and more
   217  reliable.
   218  
   219  In other platforms, an audit usually involves auditing everything, including the
   220  dependencies. However, in Gno, we can expect that over time, contracts will
   221  become smaller, more powerful, and partially audited by default, thanks to this
   222  enforced open-source system.
   223  
   224  One key difference between the Go and Gno ecosystem is the trust assumption when
   225  adding a new dependency. Dependency code always needs to be vetted, [regardless
   226  of what programming language or ecosystem you're using][sc-attack]. However, in
   227  Gno, you can have the certainty that the author of a package cannot overwrite an
   228  existing, published contract; as that is simply disallowed by the blockchain. In
   229  other words, using existing and widely-used packages reinforces your security
   230  rather than harming it.
   231  [sc-attack]: https://en.wikipedia.org/wiki/Supply_chain_attack
   232  
   233  So, while you can still adhere to the original philosophy of minimizing
   234  dependencies, ultimately, try to use and write super stable, simple, tested,
   235  and focused `p/` small libraries. This approach can lead to more reliable,
   236  efficient, and trustworthy Gno contracts.
   237  
   238  ```go
   239  import (
   240      "gno.land/p/finance/tokens"
   241      "gno.land/p/finance/exchange"
   242      "gno.land/p/finance/wallet"
   243      "gno.land/p/utils/permissions"
   244  )
   245  
   246  var (
   247      myWallet wallet.Wallet
   248      myToken tokens.Token
   249      myExchange exchange.Exchange
   250  )
   251  
   252  func init() {
   253      myWallet = wallet.NewWallet()
   254      myToken = tokens.NewToken("MyToken", "MTK")
   255      myExchange = exchange.NewExchange(myToken)
   256  }
   257  
   258  func BuyTokens(amount int) {
   259      caller := permissions.GetCaller()
   260      permissions.CheckPermission(caller, "buy")
   261      myWallet.Debit(caller, amount)
   262      myExchange.Buy(caller, amount)
   263  }
   264  
   265  func SellTokens(amount int) {
   266      caller := permissions.GetCaller()
   267      permissions.CheckPermission(caller, "sell")
   268      myWallet.Credit(caller, amount)
   269      myExchange.Sell(caller, amount)
   270  }
   271  ```
   272  
   273  ##  When Gno takes Go practices to the next level
   274  
   275  ### Documentation is for users
   276  
   277  One of the well-known proverbs in Go is: ["Documentation is for
   278  users"](https://www.youtube.com/watch?v=PAAkCSZUG1c&t=1147s), as stated by Rob
   279  Pike. In Go, documentation is for users, but users are often developers. In Gno,
   280  documentation is for users, and users can be other developers but also the end users.
   281  
   282  In Go, we usually have well-written documentation for other developers to
   283  maintain and use our code as a library. Then, we often have another layer of
   284  documentation on our API, sometimes with OpenAPI Specs, Protobuf, or even user
   285  documentation.
   286  
   287  In Gno, the focus shifts towards writing documentation for the end user. You can
   288  even consider that the main reader is an end user, who is not so interested in
   289  technical details, but mostly interested in how and why they should use a
   290  particular endpoint. Comments will be used to aid code source reading, but also to
   291  generate documentation and even for smart wallets that need to understand what
   292  to do.
   293  
   294  Inline comments have the same goal: to guide users (developers or end users)
   295  through the code. While comments are still important for maintainability, their
   296  main purpose in Gno is for discoverability. This shift towards user-centric
   297  documentation reflects the broader shift in Gno towards making code more
   298  accessible and understandable for all users, not just developers.
   299  
   300  TODO: `func ExampleXXX`.
   301  
   302  ### Reflection is never clear
   303  
   304  In Go, there's a well-known saying by Rob Pike: ["Reflection is never
   305  clear."](https://www.youtube.com/watch?v=PAAkCSZUG1c&t=15m22s) This statement
   306  emphasizes the complexity and potential pitfalls of using reflection in Go.
   307  
   308  In Gno, reflection does not exist (yet). There are technical reasons for this,
   309  but also a desire to create a Go alternative that is explicitly safer to use
   310  than Go, with a smaller cognitive difficulty to read, discover, and understand.
   311  
   312  The absence of reflection in Gno is not just about simplicity, but also about
   313  safety. Reflection can be powerful, but it can also lead to code that is hard to
   314  understand, hard to debug, and prone to runtime errors. By not supporting
   315  reflection, Gno encourages you to write code that is explicit, clear, and easy
   316  to understand.
   317  
   318  We're currently in the process of considering whether to add reflection support
   319  or not, or perhaps add it in a privileged mode for very few libraries. But for now,
   320  when you're writing Gno code, remember: explicit is better than implicit, and
   321  clear code is better than clever code.
   322  
   323  ## Gno good practices
   324  
   325  ### Package naming and organization
   326  
   327  Your package name should match the folder name. This helps to prevent having
   328  named imports, which can make your code more difficult to understand and
   329  maintain. By matching the package name with the folder name, you can ensure that
   330  your imports are clear and intuitive.
   331  
   332  Ideally, package names should be short and human-readable. This makes it easier
   333  for other developers to understand what your package does at a glance. Avoid
   334  using abbreviations or acronyms unless they are widely understood.
   335  
   336  Packages and realms can be organized into subdirectories. However, consider that the
   337  best place for your main project will likely be `r/NAMESPACE/DAPP`, similar
   338  to how repositories are organized on GitHub.
   339  
   340  If you have multiple sublevels of realms, remember that they are actually
   341  independent realms and won't share data. A good usage could be to have an
   342  ecosystem of realms, where one realm is about storing the state, another one
   343  about configuration, etc. But in general, a single realm makes sense.
   344  
   345  You can also create small realms to create your ecosystem. For example, you
   346  could centralize all the authentication for your whole company/organization in
   347  `r/NAMESPACE/auth`, and then import it in all your contracts.
   348  
   349  The `p/` prefix is different. In general, you should use top-level `p/` like
   350  `p/NAMESPACE/DAPP` only for things you expect people to use. If your goal is
   351  just to have internal libraries that you created to centralize your helpers and
   352  don't expect that other people will use your helpers, then you should probably
   353  use subdirectories like `p/NAMESPACE/DAPP/foo/bar/baz`.
   354  
   355  ### Define types and interfaces in pure packages (p/)
   356  
   357  In Gno, it's common to create `p/NAMESPACE/DAPP` for defining types and
   358  interfaces, and `r/NAMESPACE/DAPP` for the runtime, especially when the goal 
   359  for the realm is to become a standard that could be imported by `p/`.
   360  
   361  The reason for this is that `p/` can only import `p/`, while `r/` can import
   362  anything. This separation allows you to define standards in `p/` that can be
   363  used across multiple realms and packages.
   364  
   365  In general, you can just write your `r/` to be an app. But if for some reason
   366  you introduce a concept that can be reused, it makes sense to have a
   367  dedicated `p/` so that people can re-use your logic without depending on
   368  your realm's data.
   369  
   370  For instance, if you want to create a token type in a realm, you can use it, and
   371  other realms can import the realm and compose it. But if you want to create a
   372  `p/` helper that will create a pattern, then you need to have your interface and
   373  types defined in `p/` so anything can import it.
   374  
   375  By separating your types and interfaces into `p/` and your runtime into `r/`,
   376  you can create more modular, reusable, and standardized code in Gno. This
   377  approach allows you to leverage the composability of Gno to build more powerful
   378  and flexible applications.
   379  
   380  ### Design your realm as a public API
   381  
   382  In Go, all your packages, including your dependencies, are typically treated as
   383  part of your safe zone, similar to a secure perimeter. The boundary is drawn
   384  between your program and the rest of the world, which means you secure the API
   385  itself, potentially with authentication middlewares.
   386  
   387  However, in Gno, your realm is the public API. It's exposed to the outside
   388  world and can be accessed by other realms. Therefore, it's crucial to design
   389  your realm with the same level of care and security considerations as you would
   390  a public API.
   391  
   392  One approach is to simulate a secure perimeter within your realm by having
   393  private functions for the logic and then writing your API layer by adding some
   394  front-facing API with authentication. This way, you can control access to your
   395  realm's functionality and ensure that only authorized callers can execute
   396  certain operations.
   397  
   398  ```go
   399  import "std"
   400  
   401  func PublicMethod(nb int) {
   402      caller := std.PrevRealm().Addr()
   403      privateMethod(caller, nb)
   404  }
   405  
   406  func privateMethod(caller std.Address, nb int) { /* ... */ }
   407  ```
   408  
   409  In this example, `PublicMethod` is a public function that can be called by other
   410  realms. It retrieves the caller's address using `std.PrevRealm().Addr()`, and
   411  then passes it to `privateMethod`, which is a private function that performs the
   412  actual logic. This way, `privateMethod` can only be called from within the
   413  realm, and it can use the caller's address for authentication or authorization
   414  checks.
   415  
   416  ### Emit Gno events to make life off-chain easier
   417  
   418  Gno provides users the ability to log specific occurrences that happened in their 
   419  on-chain apps. An `event` log is stored in the ABCI results of each block, and
   420  these logs can be indexed, filtered, and searched by external services, allowing 
   421  them to monitor the behaviour of on-chain apps.
   422  
   423  It is good practice to emit events when any major action in your code is 
   424  triggered. For example, good times to emit an event is after a balance transfer,
   425  ownership change, profile created, etc. Alternatively, you can view event emission
   426  as a way to include data for monitoring purposes, given the indexable nature of 
   427  events.
   428  
   429  Events consist of a type and a slice of strings representing `key:value` pairs.
   430  They are emitted with the `Emit()` function, contained in the `std` package in 
   431  the Gno standard library:
   432  
   433  ```go
   434  package events
   435  
   436  import (
   437  	"std"
   438  )
   439  
   440  var owner std.Address
   441  
   442  func init() {
   443  	owner = std.PrevRealm().Addr()
   444  }
   445  
   446  func ChangeOwner(newOwner std.Address) {
   447  	caller := std.PrevRealm().Addr()
   448  
   449  	if caller != owner {
   450  		panic("access denied")
   451  	}
   452  	
   453  	owner = newOwner
   454  	std.Emit("OwnershipChange", "newOwner", newOwner.String())
   455  }
   456  
   457  ```
   458  If `ChangeOwner()` was called in, for example, block #43, getting the `BlockResults`
   459  of block #43 will contain the following data:
   460  
   461  ```json
   462  {
   463    "Events": [
   464      {
   465        "@type": "/tm.gnoEvent",
   466        "type": "OwnershipChange",
   467        "pkg_path": "gno.",
   468        "func": "ChangeOwner",
   469        "attrs": [
   470          {
   471            "key": "newOwner",
   472            "value": "g1zzqd6phlfx0a809vhmykg5c6m44ap9756s7cjj"
   473          }
   474        ]
   475      }
   476      // other events
   477    ]
   478  }
   479  ```
   480  
   481  Read more about events [here](./stdlibs/events.md).
   482  
   483  ### Contract-level access control
   484  
   485  In Gno, it's a good practice to design your contract as an application with its
   486  own access control. This means that different endpoints of your contract should
   487  be accessible to different types of users, such as the public, admins, or
   488  moderators.
   489  
   490  The goal is usually to store the admin address or a list of addresses
   491  (`std.Address`) in a variable, and then create helper functions to update the
   492  owners. These helper functions should check if the caller of a function is
   493  whitelisted or not.
   494  
   495  Let's deep dive into the different access control mechanisms we can use:
   496  
   497  One strategy is to look at the caller with `std.PrevRealm()`, which could be the
   498  EOA (Externally Owned Account), or the preceding realm in the call stack.
   499  
   500  Another approach is to look specifically at the EOA. For this, you should call
   501  `std.GetOrigCaller()`, which returns the public address of the account that
   502  signed the transaction.
   503  
   504  TODO: explain when to use `std.GetOrigCaller`.
   505  
   506  Internally, this call will look at the frame stack, which is basically the stack
   507  of callers including all the functions, anonymous functions, other realms, and
   508  take the initial caller. This allows you to identify the original caller and
   509  implement access control based on their address.
   510  
   511  Here's an example:
   512  
   513  ```go
   514  import "std"
   515  
   516  var admin std.Address = "g1xxxxx"
   517  
   518  func AdminOnlyFunction() {
   519      caller := std.PrevRealm().Addr()
   520      if caller != admin {
   521          panic("permission denied")
   522      }
   523      // ...
   524  }
   525  
   526  // func UpdateAdminAddress(newAddr std.Address) { /* ... */ }
   527  ```
   528  
   529  In this example, `AdminOnlyFunction` is a function that can only be called by
   530  the admin. It retrieves the caller's address using `std.PrevRealm().Addr()`,
   531  this can be either another realm contract, or the calling user if there is no
   532  other intermediary realm. and then checks if the caller is the admin. If not, it
   533  panics and stops the execution.
   534  
   535  The goal of this approach is to allow a contract to own assets (like grc20 or
   536  coins), so that you can create contracts that can be called by another
   537  contract, reducing the risk of stealing money from the original caller. This is
   538  the behavior of the default grc20 implementation.
   539  
   540  Here's an example:
   541  
   542  ```go
   543  import "std"
   544  
   545  func TransferTokens(to std.Address, amount int64) {
   546      caller := std.PrevRealm().Addr()
   547      if caller != admin {
   548          panic("permission denied")
   549      }
   550      // ...
   551  }
   552  ```
   553  
   554  In this example, `TransferTokens` is a function that can only be called by the
   555  admin. It retrieves the caller's address using `std.PrevRealm().Addr()`, and
   556  then checks if the caller is the admin. If not, the function panics and execution is stopped.
   557  
   558  By using these access control mechanisms, you can ensure that your contract's
   559  functionality is accessible only to the intended users, providing a secure and
   560  reliable way to manage access to your contract.
   561  
   562  ### Using avl.Tree for efficient data retrieval
   563  
   564  In Gno, the `avl.Tree` data structure is a powerful tool for optimizing data
   565  retrieval. It works by lazily resolving information, which means it only loads
   566  the data you need when you need it. This allows you to scale your application
   567  and pay less gas for data retrieval.
   568  
   569  [AVL is short for Adelson-Velsky and Landis:][avl-wiki] under the hood, it is an
   570  implementation of a self-balancing binary tree.
   571  [avl-wiki]: https://en.wikipedia.org/wiki/AVL_tree
   572  
   573  The `avl.Tree` can be used like a map, where you can store key-value pairs and
   574  retrieve an entry with a simple key. However, unlike a traditional map, the
   575  `avl.Tree` doesn't load unnecessary data. This makes it particularly efficient
   576  for large data sets where you only need to access a small subset of the data at
   577  a time.
   578  
   579  Here's an example of how you can use `avl.Tree`:
   580  
   581  ```go
   582  import "avl"
   583  
   584  var tree avl.Tree
   585  
   586  func GetPost(id string) *Post {
   587      return tree.Get(id).(*Post)
   588  }
   589  
   590  func AddPost(id string, post *Post) {
   591      tree.Set(id, post)
   592  }
   593  ```
   594  
   595  In this example, `GetPost` is a function that retrieves a post from the
   596  `avl.Tree` using an ID. It only loads the post with the specified ID, without
   597  loading any other posts.
   598  
   599  In the future, we plan to add built-in "map" support that will match the
   600  efficienty of an `avl.Tree` while offering a more intuitive API. Until then, if
   601  you're dealing with a compact dataset, it's probably best to use slices.
   602  For larger datasets where you need to quickly retrieve elements by keys,
   603  `avl.Tree` is the way to go.
   604  
   605  You can also create SQL-like indexes by having multiple `avl.Tree` instances for
   606  different fields. For example, you can have an `avl.Tree` for ID to *post, then
   607  an `avl.Tree` for Tags, etc. Then, you can create reader methods that will just
   608  retrieve what you need, similar to SQL indexes.
   609  
   610  By using `avl.Tree` and other efficient data structures, you can optimize your
   611  Gno code for performance and cost-effectiveness, making your applications more
   612  scalable and efficient.
   613  
   614  TODO: multi-indices example
   615  
   616  ### Construct "safe" objects
   617  
   618  A safe object in Gno is an object that is designed to be tamper-proof and
   619  secure. It's created with the intent of preventing unauthorized access and
   620  modifications. This follows the same principle of making a package an API, but
   621  for a Gno object that can be directly referenced by other realms.
   622  
   623  The goal is to create an object which, once instantiated, can be linked and its
   624  pointer can be "stored" by other realms without issue, because it protects its
   625  usage completely.
   626  
   627  ```go
   628  type MySafeStruct {
   629      counter nb
   630      admin std.Address
   631  }
   632  
   633  func NewSafeStruct() *MySafeStruct {
   634      caller := std.PrevRealm().Addr()
   635      return &MySafeStruct{
   636          counter: 0,
   637          admin: caller,
   638      }
   639  }
   640  
   641  func (s *MySafeStruct) Counter() int { return s.counter }
   642  func (s *MySafeStruct) Inc() {
   643      caller := std.PrevRealm().Addr()
   644      if caller != s.admin {
   645          panic("permission denied")
   646      }
   647      s.counter++
   648  }
   649  ```
   650  
   651  Then, you can register this object in another or several other realms so other
   652  realms can access the object, but still following your own rules.
   653  
   654  ```go 
   655  import "gno.land/r/otherrealm"
   656  
   657  func init() {
   658      mySafeObj := NewSafeStruct()
   659      otherrealm.Register(mySafeObject)
   660  }
   661  
   662  // then, other realm can call the public functions but won't be the "owner" of
   663  // the object.
   664  ```
   665  
   666  ### Choosing between Coins and GRC20 tokens
   667  
   668  In Gno, you've got two primary options: Coins or GRC20. Each option
   669  has its unique advantages and disadvantages, and the ideal choice varies based
   670  on individual requirements.
   671  
   672  #### Coins
   673  
   674  Coins are managed by the banker module, separate from GnoVM. They're
   675  simple, strict, and secure. You can create, transfer, and check balances with an
   676  RPC call, no GnoVM needed.
   677  
   678  For example, if you're creating a coin for cross-chain transfers, Coins
   679  are your best bet. They're IBC-ready and their strict rules offer top-notch
   680  security.
   681  
   682  Read about how to use the Banker module [here](stdlibs/banker).
   683  
   684  #### GRC20 tokens
   685  
   686  GRC20 tokens, on the other hand, are like Ethereum's ERC20 or CosmWasm's CW20.
   687  They're flexible, composable, and perfect for DeFi protocols and DAOs. They
   688  offer more features like token-gating, vaults, and wrapping.
   689  
   690  For instance, if you're creating a voting system for a DAO, GRC20 tokens are
   691  ideal. They're programmable, can be embedded in safe Gno objects, and offer more
   692  control.
   693  
   694  Remember, GRC20 tokens are more gas-intensive and aren't IBC-ready yet. They
   695  also come with shared ownership, meaning the contract retains some control.
   696  
   697  In the end, your choice depends on your needs: simplicity and security with
   698  Coins, or flexibility and control with GRC20 tokens. And if you want the
   699  best of both worlds, you can wrap a Coins into a GRC20 compatible token.
   700  
   701  ```go
   702  import "gno.land/p/demo/grc/grc20"
   703  
   704  var fooToken grc20.AdminToken = grc20.NewAdminToken("Foo Token", "FOO", 4)
   705  
   706  func MyBalance() uint64 {
   707  	caller := std.PrevRealm().Addr()
   708  	balance, _ := fooToken.BalanceOf(caller)
   709  	return balance
   710  }
   711  ```
   712  
   713  See also: https://gno.land/r/demo/foo20
   714  
   715  #### Wrapping Coins
   716  
   717  Want the best of both worlds? Consider wrapping your Coins. This gives
   718  your coins the flexibility of GRC20 while keeping the security of Coins.
   719  It's a bit more complex, but it's a powerful option that offers great
   720  versatility.
   721  
   722  See also: https://github.com/gnolang/gno/tree/master/examples/gno.land/r/demo/wugnot
   723  
   724  <!-- TODO:
   725  
   726  - packages and realms versionning
   727  - code generation
   728  - unit tests, fuzzing tests, example tests, txtar
   729  - shipping non-contract stuff with the realm: client, documentation, assets
   730  - unoptimized / gas inefficient code
   731  - optimized data structures
   732  - using state machines (gaming example)
   733  - TDD and local dev
   734  - contract-contract pattern
   735  - upgrade pattern
   736  - pausable pattern
   737  - flexible DAO pattern
   738  - maketx run to use go as shell script
   739  - when to launch a local testnet, a full node, gnodev, or using testnets,
   740    staging, etc
   741  - go std vs gno std
   742  - use rand
   743  - use time
   744  - use oracles
   745  - subscription model
   746  - forking contracts
   747  - finished packages
   748  - packages for developers, realms for users (NPM vs App Store)
   749  - cross-realm ownership: function pointer, callback, inline function ownership
   750  - advanced usages of the frame stack
   751  -->