Skip to content

Commit

Permalink
feat: official documentation (#1046)
Browse files Browse the repository at this point in the history
## Description

This PR introduces the official Gno documentation, which will be hosted
at `docs.gno.land`, using the Docusaurus framework.

As discussed with @moul, the docs are supposed to be framework agnostic,
with Docusaurus living in the `misc/docusaurus` directory.

This documentation also includes work done by @alexiscolin, @leohhhn,
@waymobetta, @harry-hov, and the Onbloc team (@dongwon8247 and @r3v4s,
migrated from their Developer Portal).
Thank you to everyone who contributed and got us to this point, for the
v1 of the docs 🙏

@leohhhn @waymobetta (and DevRels reading this in the future), full
ownership of the documentation will be relinquished to you after this PR
is merged out.

To run the docs locally:
- `cd misc/docusaurus`
- `yarn install`
- `yarn start`

<details><summary>Contributors' checklist...</summary>

- [x] Added new tests, or not needed, or not feasible
- [x] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [x] Updated the official documentation or not needed
- [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message
was included in the description
- [ ] Added references to related issues and PRs
- [ ] Provided any useful hints for running manual tests
- [ ] Added new benchmarks to [generated
graphs](https://gnoland.github.io/benchmarks), if any. More info
[here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
</details>

---------

Co-authored-by: jon roethke <waymobetta@users.noreply.github.com>
Co-authored-by: Blake <104744707+r3v4s@users.noreply.github.com>
Co-authored-by: Dongwon <74406335+dongwon8247@users.noreply.github.com>
Co-authored-by: Leon Hudak <33522493+leohhhn@users.noreply.github.com>
Co-authored-by: Hariom Verma <hariom18599@gmail.com>
Co-authored-by: Alexis Colin <alexis@jaunebleu.co>
Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com>
Co-authored-by: Morgan <git@howl.moe>
  • Loading branch information
9 people authored Nov 9, 2023
1 parent afcdc66 commit bc5af65
Show file tree
Hide file tree
Showing 112 changed files with 15,270 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ PHILOSOPHY.md @jaekwon @moul
CONTRIBUTING.md @jaekwon @moul
LICENSE.md @jaekwon @moul
.github/CODEOWNERS @jaekwon @moul

# Documentation.
docs/* @gnolang/devrels
6 changes: 6 additions & 0 deletions docs/assets/explanation/packages/pkg-1.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
func TotalSupply() uint64
func BalanceOf(account std.Address) uint64
func Transfer(to std.Address, amount uint64)
func Approve(spender std.Address, amount uint64)
func TransferFrom(from, to std.Address, amount uint64)
func Allowance(owner, spender std.Address) uint64
11 changes: 11 additions & 0 deletions docs/assets/explanation/packages/pkg-2.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// functions that work similarly to those of grc20
func BalanceOf(owner std.Address) (uint64, error)
func Approve(approved std.Address, tid TokenID) error
func TransferFrom(from, to std.Address, tid TokenID) error

// functions unique to grc721
func OwnerOf(tid TokenID) (std.Address, error)
func SafeTransferFrom(from, to std.Address, tid TokenID) error
func SetApprovalForAll(operator std.Address, approved bool) error
func GetApproved(tid TokenID) (std.Address, error)
func IsApprovedForAll(owner, operator std.Address) bool
12 changes: 12 additions & 0 deletions docs/assets/explanation/packages/pkg-3.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
func TestAddress(name string) std.Address {
if len(name) > std.RawAddressSize {
panic("address name cannot be greater than std.AddressSize bytes")
}
addr := std.RawAddress{}
// TODO: use strings.RepeatString or similar.
// NOTE: I miss python's "".Join().
blanks := "____________________"
copy(addr[:], []byte(blanks))
copy(addr[:], []byte(name))
return std.Address(std.EncodeBech32("g", addr))
}
8 changes: 8 additions & 0 deletions docs/assets/explanation/packages/pkg-4.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
admin := users.AddressOrName("g1tntwtvzrkt2gex69f0pttan0fp05zmeg5yykv8")
test2 := users.AddressOrName(testutils.TestAddress("test2"))
recv := users.AddressOrName(testutils.TestAddress("recv"))
normal := users.AddressOrName(testutils.TestAddress("normal"))
owner := users.AddressOrName(testutils.TestAddress("owner"))
spender := users.AddressOrName(testutils.TestAddress("spender"))
recv2 := users.AddressOrName(testutils.TestAddress("recv2"))
mibu := users.AddressOrName(testutils.TestAddress("mint_burn"))
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions docs/assets/how-to-guides/creating-grc20/mytoken-1.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package mytoken

import (
"std"

"gno.land/p/demo/grc/grc20"
)

var (
mytoken *grc20.AdminToken
admin std.Address = "g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj" // set admin account
)

// init is a constructor function that runs only once (at time of deployment)
func init() {
// provision the token's name, symbol and number of decimals
mytoken = grc20.NewAdminToken("Mytoken", "MTKN", 4)

// set the total supply
mytoken.Mint(admin, 1000000*10000) // @administrator (supply = 1 million)
}
83 changes: 83 additions & 0 deletions docs/assets/how-to-guides/creating-grc20/mytoken-2.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
func TotalSupply() uint64 {
return mytoken.TotalSupply()
}

func BalanceOf(owner users.AddressOrName) uint64 {
balance, err := mytoken.BalanceOf(owner.Resolve())
if err != nil {
panic(err)
}
return balance
}

func Allowance(owner, spender users.AddressOrName) uint64 {
allowance, err := mytoken.Allowance(owner.Resolve(), spender.Resolve())
if err != nil {
panic(err)
}
return allowance
}

func Transfer(to users.AddressOrName, amount uint64) {
caller := std.PrevRealm().Addr()
err := mytoken.Transfer(caller, to.Resolve(), amount)
if err != nil {
panic(err)
}
}

func Approve(spender users.AddressOrName, amount uint64) {
caller := std.PrevRealm().Addr()
err := mytoken.Approve(caller, spender.Resolve(), amount)
if err != nil {
panic(err)
}
}

func TransferFrom(from, to users.AddressOrName, amount uint64) {
caller := std.PrevRealm().Addr()
err := mytoken.TransferFrom(caller, from.Resolve(), to.Resolve(), amount)
if err != nil {
panic(err)
}
}

func Mint(address users.AddressOrName, amount uint64) {
caller := std.PrevRealm().Addr()
assertIsAdmin(caller)
err := mytoken.Mint(address.Resolve(), amount)
if err != nil {
panic(err)
}
}

func Burn(address users.AddressOrName, amount uint64) {
caller := std.PrevRealm().Addr()
assertIsAdmin(caller)
err := mytoken.Burn(address.Resolve(), amount)
if err != nil {
panic(err)
}
}

func Render(path string) string {
parts := strings.Split(path, "/")
c := len(parts)

switch {
case path == "":
return mytoken.RenderHome()
case c == 2 && parts[0] == "balance":
owner := users.AddressOrName(parts[1])
balance, _ := mytoken.BalanceOf(owner.Resolve())
return ufmt.Sprintf("%d\n", balance)
default:
return "404\n"
}
}

func assertIsAdmin(address std.Address) {
if address != admin {
panic("restricted access")
}
}
17 changes: 17 additions & 0 deletions docs/assets/how-to-guides/creating-grc721/mynonfungibletoken-1.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package mynonfungibletoken

import (
"std"

"gno.land/p/demo/grc/grc721"
)

var (
admin std.Address = "g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj" // set admin account
// provision the token's name and symbol
mynonfungibletoken = grc721.NewBasicNFT("mynonfungibletoken", "MNFT")
)

func init() {
mintNNFT(admin, 10) // @administrator (supply = 10)
}
102 changes: 102 additions & 0 deletions docs/assets/how-to-guides/creating-grc721/mynonfungibletoken-2.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
func mintNNFT(owner std.Address, n uint64) {
count := my.TokenCount()
for i := count; i < count+n; i++ {
tid := grc721.TokenID(ufmt.Sprintf("%d", i))
mynonfungibletoken.Mint(owner, tid)
}
}

// Getters

func BalanceOf(user users.AddressOrName) uint64 {
balance, err := mynonfungibletoken.BalanceOf(user.Resolve())
if err != nil {
panic(err)
}

return balance
}

func OwnerOf(tid grc721.TokenID) std.Address {
owner, err := mynonfungibletoken.OwnerOf(tid)
if err != nil {
panic(err)
}

return owner
}

func IsApprovedForAll(owner, user users.AddressOrName) bool {
return mynonfungibletoken.IsApprovedForAll(owner.Resolve(), user.Resolve())
}

func GetApproved(tid grc721.TokenID) std.Address {
addr, err := mynonfungibletoken.GetApproved(tid)
if err != nil {
panic(err)
}

return addr
}

// Setters

func Approve(user users.AddressOrName, tid grc721.TokenID) {
err := mynonfungibletoken.Approve(user.Resolve(), tid)
if err != nil {
panic(err)
}
}

func SetApprovalForAll(user users.AddressOrName, approved bool) {
err := mynonfungibletoken.SetApprovalForAll(user.Resolve(), approved)
if err != nil {
panic(err)
}
}

func TransferFrom(from, to users.AddressOrName, tid grc721.TokenID) {
err := mynonfungibletoken.TransferFrom(from.Resolve(), to.Resolve(), tid)
if err != nil {
panic(err)
}
}

// Admin

func Mint(to users.AddressOrName, tid grc721.TokenID) {
caller := std.PrevRealm().Addr()
assertIsAdmin(caller)
err := mynonfungibletoken.Mint(to.Resolve(), tid)
if err != nil {
panic(err)
}
}

func Burn(tid grc721.TokenID) {
caller := std.PrevRealm().Addr()
assertIsAdmin(caller)
err := mynonfungibletoken.Burn(tid)
if err != nil {
panic(err)
}
}

// Render

func Render(path string) string {
switch {
case path == "":
return mynonfungibletoken.RenderHome()
default:
return "404\n"
}
}

// Util

func assertIsAdmin(address std.Address) {
if address != admin {
panic("restricted access")
}
}
39 changes: 39 additions & 0 deletions docs/assets/how-to-guides/porting-solidity-to-gno/porting-1.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
func shouldEqual(t *testing.T, got interface{}, expected interface{}) {
t.Helper()

if got != expected {
t.Errorf("expected %v(%T), got %v(%T)", expected, expected, got, got)
}
}

func shouldErr(t *testing.T, err error) {
t.Helper()
if err == nil {
t.Errorf("expected an error, but got nil.")
}
}

func shouldNoErr(t *testing.T, err error) {
t.Helper()
if err != nil {
t.Errorf("expected no error, but got err: %s.", err.Error())
}
}

func shouldPanic(t *testing.T, f func()) {
defer func() {
if r := recover(); r == nil {
t.Errorf("should have panic")
}
}()
f()
}

func shouldNoPanic(t *testing.T, f func()) {
defer func() {
if r := recover(); r != nil {
t.Errorf("should not have panic")
}
}()
f()
}
29 changes: 29 additions & 0 deletions docs/assets/how-to-guides/porting-solidity-to-gno/porting-10.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/// End the auction and send the highest bid
/// to the beneficiary.
function auctionEnd() external {
// It is a good guideline to structure functions that interact
// with other contracts (i.e. they call functions or send Ether)
// into three phases:
// 1. checking conditions
// 2. performing actions (potentially changing conditions)
// 3. interacting with other contracts
// If these phases are mixed up, the other contract could call
// back into the current contract and modify the state or cause
// effects (ether payout) to be performed multiple times.
// If functions called internally include interaction with external
// contracts, they also have to be considered interaction with
// external contracts.

// 1. Conditions
if (block.timestamp < auctionEndTime)
revert AuctionNotYetEnded();
if (ended)
revert AuctionEndAlreadyCalled();

// 2. Effects
ended = true;
emit AuctionEnded(highestBidder, highestBid);

// 3. Interaction
beneficiary.transfer(highestBid);
}
17 changes: 17 additions & 0 deletions docs/assets/how-to-guides/porting-solidity-to-gno/porting-11.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
func AuctionEnd() {
if std.GetHeight() < auctionEndBlock {
panic("Auction hasn't ended")
}

if ended {
panic("Auction has ended")

}
ended = true

// Send the highest bid to the recipient
banker := std.GetBanker(std.BankerTypeRealmSend)
pkgAddr := std.GetOrigPkgAddr()

banker.SendCoins(pkgAddr, receiver, std.Coins{{"ugnot", int64(highestBid)}})
}
18 changes: 18 additions & 0 deletions docs/assets/how-to-guides/porting-solidity-to-gno/porting-12.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// AuctionEnd() Function Test
func TestAuctionEnd(t *testing.T) {
// Auction is ongoing
shouldPanic(t, AuctionEnd)

// Auction ends
highestBid = 3
std.TestSkipHeights(500)
shouldNoPanic(t, AuctionEnd)
shouldEqual(t, ended, true)

banker := std.GetBanker(std.BankerTypeRealmSend)
shouldEqual(t, banker.GetCoins(receiver).String(), "3ugnot")

// Auction has already ended
shouldPanic(t, AuctionEnd)
shouldEqual(t, ended, true)
}
Loading

0 comments on commit bc5af65

Please sign in to comment.