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 -->