diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 98ff9ec12fa..0906f3914da 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -37,3 +37,6 @@ PHILOSOPHY.md @jaekwon @moul
CONTRIBUTING.md @jaekwon @moul
LICENSE.md @jaekwon @moul
.github/CODEOWNERS @jaekwon @moul
+
+# Documentation.
+docs/* @gnolang/devrels
\ No newline at end of file
diff --git a/docs/assets/explanation/packages/pkg-1.gno b/docs/assets/explanation/packages/pkg-1.gno
new file mode 100644
index 00000000000..e68d506612a
--- /dev/null
+++ b/docs/assets/explanation/packages/pkg-1.gno
@@ -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
diff --git a/docs/assets/explanation/packages/pkg-2.gno b/docs/assets/explanation/packages/pkg-2.gno
new file mode 100644
index 00000000000..0054cc95e3d
--- /dev/null
+++ b/docs/assets/explanation/packages/pkg-2.gno
@@ -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
diff --git a/docs/assets/explanation/packages/pkg-3.gno b/docs/assets/explanation/packages/pkg-3.gno
new file mode 100644
index 00000000000..f1ba5609d6b
--- /dev/null
+++ b/docs/assets/explanation/packages/pkg-3.gno
@@ -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))
+}
diff --git a/docs/assets/explanation/packages/pkg-4.gno b/docs/assets/explanation/packages/pkg-4.gno
new file mode 100644
index 00000000000..edd34b5cc5d
--- /dev/null
+++ b/docs/assets/explanation/packages/pkg-4.gno
@@ -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"))
diff --git a/docs/assets/getting-started/browsing-gno-source-code/gnoweb-avl.png b/docs/assets/getting-started/browsing-gno-source-code/gnoweb-avl.png
new file mode 100644
index 00000000000..3754ccfe88e
Binary files /dev/null and b/docs/assets/getting-started/browsing-gno-source-code/gnoweb-avl.png differ
diff --git a/docs/assets/getting-started/browsing-gno-source-code/gnoweb-boards-source.png b/docs/assets/getting-started/browsing-gno-source-code/gnoweb-boards-source.png
new file mode 100644
index 00000000000..65e0f880bc9
Binary files /dev/null and b/docs/assets/getting-started/browsing-gno-source-code/gnoweb-boards-source.png differ
diff --git a/docs/assets/getting-started/browsing-gno-source-code/gnoweb-boards.png b/docs/assets/getting-started/browsing-gno-source-code/gnoweb-boards.png
new file mode 100644
index 00000000000..dca226c3ec9
Binary files /dev/null and b/docs/assets/getting-started/browsing-gno-source-code/gnoweb-boards.png differ
diff --git a/docs/assets/getting-started/browsing-gno-source-code/gnoweb.png b/docs/assets/getting-started/browsing-gno-source-code/gnoweb.png
new file mode 100644
index 00000000000..3ba9035889d
Binary files /dev/null and b/docs/assets/getting-started/browsing-gno-source-code/gnoweb.png differ
diff --git a/docs/assets/getting-started/creating-a-key-pair/gnokey-add-mnemonic.gif b/docs/assets/getting-started/creating-a-key-pair/gnokey-add-mnemonic.gif
new file mode 100644
index 00000000000..641acc9f825
Binary files /dev/null and b/docs/assets/getting-started/creating-a-key-pair/gnokey-add-mnemonic.gif differ
diff --git a/docs/assets/getting-started/creating-a-key-pair/gnokey-add-random.gif b/docs/assets/getting-started/creating-a-key-pair/gnokey-add-random.gif
new file mode 100644
index 00000000000..dba61a6b287
Binary files /dev/null and b/docs/assets/getting-started/creating-a-key-pair/gnokey-add-random.gif differ
diff --git a/docs/assets/getting-started/creating-a-key-pair/gnokey-export.gif b/docs/assets/getting-started/creating-a-key-pair/gnokey-export.gif
new file mode 100644
index 00000000000..e56938866f9
Binary files /dev/null and b/docs/assets/getting-started/creating-a-key-pair/gnokey-export.gif differ
diff --git a/docs/assets/getting-started/creating-a-key-pair/gnokey-generate.gif b/docs/assets/getting-started/creating-a-key-pair/gnokey-generate.gif
new file mode 100644
index 00000000000..ce371487c6c
Binary files /dev/null and b/docs/assets/getting-started/creating-a-key-pair/gnokey-generate.gif differ
diff --git a/docs/assets/getting-started/creating-a-key-pair/gnokey-import.gif b/docs/assets/getting-started/creating-a-key-pair/gnokey-import.gif
new file mode 100644
index 00000000000..8ec80519372
Binary files /dev/null and b/docs/assets/getting-started/creating-a-key-pair/gnokey-import.gif differ
diff --git a/docs/assets/getting-started/creating-a-key-pair/gnokey-list.gif b/docs/assets/getting-started/creating-a-key-pair/gnokey-list.gif
new file mode 100644
index 00000000000..ad050da585c
Binary files /dev/null and b/docs/assets/getting-started/creating-a-key-pair/gnokey-list.gif differ
diff --git a/docs/assets/getting-started/local-setup/gno-help.gif b/docs/assets/getting-started/local-setup/gno-help.gif
new file mode 100644
index 00000000000..ebd7d4cfcb0
Binary files /dev/null and b/docs/assets/getting-started/local-setup/gno-help.gif differ
diff --git a/docs/assets/getting-started/local-setup/gnokey-help.gif b/docs/assets/getting-started/local-setup/gnokey-help.gif
new file mode 100644
index 00000000000..d96d2424679
Binary files /dev/null and b/docs/assets/getting-started/local-setup/gnokey-help.gif differ
diff --git a/docs/assets/getting-started/local-setup/make-build-gnoland.gif b/docs/assets/getting-started/local-setup/make-build-gnoland.gif
new file mode 100644
index 00000000000..fe12670be2c
Binary files /dev/null and b/docs/assets/getting-started/local-setup/make-build-gnoland.gif differ
diff --git a/docs/assets/getting-started/local-setup/make-build-gnovm.gif b/docs/assets/getting-started/local-setup/make-build-gnovm.gif
new file mode 100644
index 00000000000..54f133796d6
Binary files /dev/null and b/docs/assets/getting-started/local-setup/make-build-gnovm.gif differ
diff --git a/docs/assets/getting-started/setting-up-a-local-chain/gnoland-start.gif b/docs/assets/getting-started/setting-up-a-local-chain/gnoland-start.gif
new file mode 100644
index 00000000000..4da21bc863b
Binary files /dev/null and b/docs/assets/getting-started/setting-up-a-local-chain/gnoland-start.gif differ
diff --git a/docs/assets/getting-started/setting-up-funds/faucet-page.png b/docs/assets/getting-started/setting-up-funds/faucet-page.png
new file mode 100644
index 00000000000..f1a5420659f
Binary files /dev/null and b/docs/assets/getting-started/setting-up-funds/faucet-page.png differ
diff --git a/docs/assets/getting-started/setting-up-funds/gnofaucet-serve.gif b/docs/assets/getting-started/setting-up-funds/gnofaucet-serve.gif
new file mode 100644
index 00000000000..79f46e7563c
Binary files /dev/null and b/docs/assets/getting-started/setting-up-funds/gnofaucet-serve.gif differ
diff --git a/docs/assets/getting-started/setting-up-funds/gnokey-query.gif b/docs/assets/getting-started/setting-up-funds/gnokey-query.gif
new file mode 100644
index 00000000000..9f58c638624
Binary files /dev/null and b/docs/assets/getting-started/setting-up-funds/gnokey-query.gif differ
diff --git a/docs/assets/getting-started/setting-up-funds/gnoland-start.gif b/docs/assets/getting-started/setting-up-funds/gnoland-start.gif
new file mode 100644
index 00000000000..3c323c40410
Binary files /dev/null and b/docs/assets/getting-started/setting-up-funds/gnoland-start.gif differ
diff --git a/docs/assets/getting-started/setting-up-funds/gnoweb.gif b/docs/assets/getting-started/setting-up-funds/gnoweb.gif
new file mode 100644
index 00000000000..ce4202dcca4
Binary files /dev/null and b/docs/assets/getting-started/setting-up-funds/gnoweb.gif differ
diff --git a/docs/assets/how-to-guides/creating-grc20/mytoken-1.gno b/docs/assets/how-to-guides/creating-grc20/mytoken-1.gno
new file mode 100644
index 00000000000..5500f019886
--- /dev/null
+++ b/docs/assets/how-to-guides/creating-grc20/mytoken-1.gno
@@ -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)
+}
diff --git a/docs/assets/how-to-guides/creating-grc20/mytoken-2.gno b/docs/assets/how-to-guides/creating-grc20/mytoken-2.gno
new file mode 100644
index 00000000000..25ff85c55ab
--- /dev/null
+++ b/docs/assets/how-to-guides/creating-grc20/mytoken-2.gno
@@ -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")
+ }
+}
diff --git a/docs/assets/how-to-guides/creating-grc721/mynonfungibletoken-1.gno b/docs/assets/how-to-guides/creating-grc721/mynonfungibletoken-1.gno
new file mode 100644
index 00000000000..14e25bd7264
--- /dev/null
+++ b/docs/assets/how-to-guides/creating-grc721/mynonfungibletoken-1.gno
@@ -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)
+}
diff --git a/docs/assets/how-to-guides/creating-grc721/mynonfungibletoken-2.gno b/docs/assets/how-to-guides/creating-grc721/mynonfungibletoken-2.gno
new file mode 100644
index 00000000000..8092596ae0a
--- /dev/null
+++ b/docs/assets/how-to-guides/creating-grc721/mynonfungibletoken-2.gno
@@ -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")
+ }
+}
diff --git a/docs/assets/how-to-guides/porting-solidity-to-gno/porting-1.gno b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-1.gno
new file mode 100644
index 00000000000..1e1dee77a86
--- /dev/null
+++ b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-1.gno
@@ -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()
+}
diff --git a/docs/assets/how-to-guides/porting-solidity-to-gno/porting-10.sol b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-10.sol
new file mode 100644
index 00000000000..8d7aff1794b
--- /dev/null
+++ b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-10.sol
@@ -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);
+}
\ No newline at end of file
diff --git a/docs/assets/how-to-guides/porting-solidity-to-gno/porting-11.gno b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-11.gno
new file mode 100644
index 00000000000..e48ebf919a0
--- /dev/null
+++ b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-11.gno
@@ -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)}})
+}
diff --git a/docs/assets/how-to-guides/porting-solidity-to-gno/porting-12.gno b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-12.gno
new file mode 100644
index 00000000000..55817537298
--- /dev/null
+++ b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-12.gno
@@ -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)
+}
diff --git a/docs/assets/how-to-guides/porting-solidity-to-gno/porting-13.gno b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-13.gno
new file mode 100644
index 00000000000..0e5f2d57de9
--- /dev/null
+++ b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-13.gno
@@ -0,0 +1,74 @@
+// The whole test
+func TestFull(t *testing.T) {
+ bidder01 := testutils.TestAddress("bidder01") // g1vf5kger9wgcrzh6lta047h6lta047h6lufftkw
+ bidder02 := testutils.TestAddress("bidder02") // g1vf5kger9wgcryh6lta047h6lta047h6lnhe2x2
+
+ // Variables test
+ {
+ shouldEqual(t, highestBidder, "")
+ shouldEqual(t, receiver, "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")
+ shouldEqual(t, auctionEndBlock, 423)
+ shouldEqual(t, highestBid, 0)
+ shouldEqual(t, pendingReturns.Size(), 0)
+ shouldEqual(t, ended, false)
+ }
+
+ // Send two or more types of coins
+ {
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 0}, {"test", 1}}, nil)
+ shouldPanic(t, Bid)
+ }
+
+ // Send less than the highest bid
+ {
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 0}}, nil)
+ shouldPanic(t, Bid)
+ }
+
+ // Send more than the highest bid
+ {
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 1}}, nil)
+ shouldNoPanic(t, Bid)
+
+ shouldEqual(t, pendingReturns.Size(), 0)
+ shouldEqual(t, highestBid, 1)
+ shouldEqual(t, highestBidder, "g1vf5kger9wgcrzh6lta047h6lta047h6lufftkw")
+ }
+
+ // Other participants in the auction
+ {
+
+ // Send less amount than the current highest bid (current: 1)
+ std.TestSetOrigCaller(bidder02)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 1}}, nil)
+ shouldPanic(t, Bid)
+
+ // Send more amount than the current highest bid (exceeded)
+ std.TestSetOrigCaller(bidder02)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 2}}, nil)
+ shouldNoPanic(t, Bid)
+
+ shouldEqual(t, highestBid, 2)
+ shouldEqual(t, highestBidder, "g1vf5kger9wgcryh6lta047h6lta047h6lnhe2x2")
+
+ shouldEqual(t, pendingReturns.Size(), 1) // Return to the existing bidder
+ shouldEqual(t, pendingReturns.Has("g1vf5kger9wgcrzh6lta047h6lta047h6lufftkw"), true)
+ }
+
+ // Auction ends
+ {
+ std.TestSkipHeights(150)
+ shouldPanic(t, AuctionEnd)
+ shouldEqual(t, ended, false)
+
+ std.TestSkipHeights(301)
+ shouldNoPanic(t, AuctionEnd)
+ shouldEqual(t, ended, true)
+
+ banker := std.GetBanker(std.BankerTypeRealmSend)
+ shouldEqual(t, banker.GetCoins(receiver).String(), "2ugnot")
+ }
+}
diff --git a/docs/assets/how-to-guides/porting-solidity-to-gno/porting-2.sol b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-2.sol
new file mode 100644
index 00000000000..0040c3ca75f
--- /dev/null
+++ b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-2.sol
@@ -0,0 +1,47 @@
+// Parameters of the auction. Times are either
+// absolute unix timestamps (seconds since 1970-01-01)
+// or time periods in seconds.
+address payable public beneficiary;
+uint public auctionEndTime;
+
+// Current state of the auction.
+address public highestBidder;
+uint public highestBid;
+
+// Allowed withdrawals of previous bids
+mapping(address => uint) pendingReturns;
+
+// Set to true at the end, disallows any change.
+// By default initialized to `false`.
+bool ended;
+
+// Events that will be emitted on changes.
+event HighestBidIncreased(address bidder, uint amount);
+event AuctionEnded(address winner, uint amount);
+
+// Errors that describe failures.
+
+// The triple-slash comments are so-called natspec
+// comments. They will be shown when the user
+// is asked to confirm a transaction or
+// when an error is displayed.
+
+/// The auction has already ended.
+error AuctionAlreadyEnded();
+/// There is already a higher or equal bid.
+error BidNotHighEnough(uint highestBid);
+/// The auction has not ended yet.
+error AuctionNotYetEnded();
+/// The function auctionEnd has already been called.
+error AuctionEndAlreadyCalled();
+
+/// Create a simple auction with `biddingTime`
+/// seconds bidding time on behalf of the
+/// beneficiary address `beneficiaryAddress`.
+constructor(
+ uint biddingTime,
+ address payable beneficiaryAddress
+) {
+ beneficiary = beneficiaryAddress;
+ auctionEndTime = block.timestamp + biddingTime;
+}
\ No newline at end of file
diff --git a/docs/assets/how-to-guides/porting-solidity-to-gno/porting-3.gno b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-3.gno
new file mode 100644
index 00000000000..af8137b4044
--- /dev/null
+++ b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-3.gno
@@ -0,0 +1,8 @@
+var (
+ receiver = std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")
+ auctionEndBlock = std.GetHeight() + uint(300) // in blocks
+ highestBidder std.Address
+ highestBid = uint(0)
+ pendingReturns avl.Tree
+ ended = false
+)
diff --git a/docs/assets/how-to-guides/porting-solidity-to-gno/porting-4.sol b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-4.sol
new file mode 100644
index 00000000000..0e3ab6d7e0d
--- /dev/null
+++ b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-4.sol
@@ -0,0 +1,32 @@
+function bid() external payable {
+ // No arguments are necessary, all
+ // information is already part of
+ // the transaction. The keyword payable
+ // is required for the function to
+ // be able to receive Ether.
+
+ // Revert the call if the bidding
+ // period is over.
+ if (block.timestamp > auctionEndTime)
+ revert AuctionAlreadyEnded();
+
+ // If the bid is not higher, send the
+ // money back (the revert statement
+ // will revert all changes in this
+ // function execution including
+ // it having received the money).
+ if (msg.value <= highestBid)
+ revert BidNotHighEnough(highestBid);
+
+ if (highestBid != 0) {
+ // Sending back the money by simply using
+ // highestBidder.send(highestBid) is a security risk
+ // because it could execute an untrusted contract.
+ // It is always safer to let the recipients
+ // withdraw their money themselves.
+ pendingReturns[highestBidder] += highestBid;
+ }
+ highestBidder = msg.sender;
+ highestBid = msg.value;
+ emit HighestBidIncreased(msg.sender, msg.value);
+}
\ No newline at end of file
diff --git a/docs/assets/how-to-guides/porting-solidity-to-gno/porting-5.gno b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-5.gno
new file mode 100644
index 00000000000..43f0b43b397
--- /dev/null
+++ b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-5.gno
@@ -0,0 +1,30 @@
+func Bid() {
+ if std.GetHeight() > auctionEndBlock {
+ panic("Exceeded auction end block")
+ }
+
+ sentCoins := std.GetOrigSend()
+ if len(sentCoins) != 1 {
+ panic("Send only one type of coin")
+ }
+
+ sentAmount := uint(sentCoins[0].Amount)
+ if sentAmount <= highestBid {
+ panic("Too few coins sent")
+ }
+
+ // A new bid is higher than the current highest bid
+ if sentAmount > highestBid {
+ // If the highest bid is greater than 0,
+ if highestBid > 0 {
+ // Need to return the bid amount to the existing highest bidder
+ // Create an AVL tree and save
+ pendingReturns.Set(highestBidder.String(), highestBid)
+ }
+
+ // Update the top bidder address
+ highestBidder = std.GetOrigCaller()
+ // Update the top bid amount
+ highestBid = sentAmount
+ }
+}
diff --git a/docs/assets/how-to-guides/porting-solidity-to-gno/porting-6.gno b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-6.gno
new file mode 100644
index 00000000000..b544d0017c4
--- /dev/null
+++ b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-6.gno
@@ -0,0 +1,41 @@
+// Bid Function Test - Send Coin
+func TestBidCoins(t *testing.T) {
+ // Sending two types of coins
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 0}, {"test", 1}}, nil)
+ shouldPanic(t, Bid)
+
+ // Sending lower amount than the current highest bid
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 0}}, nil)
+ shouldPanic(t, Bid)
+
+ // Sending more amount than the current highest bid (exceeded)
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 1}}, nil)
+ shouldNoPanic(t, Bid)
+}
+
+// Bid Function Test - Bid by two or more people
+func TestBidCoins(t *testing.T) {
+ // bidder01 bidding with 1 coin
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 1}}, nil)
+ shouldNoPanic(t, Bid)
+ shouldEqual(t, highestBid, 1)
+ shouldEqual(t, highestBidder, bidder01)
+ shouldEqual(t, pendingReturns.Size(), 0)
+
+ // bidder02 bidding with 1 coin
+ std.TestSetOrigCaller(bidder02)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 1}}, nil)
+ shouldPanic(t, Bid)
+
+ // bidder02 bidding with 2 coins
+ std.TestSetOrigCaller(bidder02)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 2}}, nil)
+ shouldNoPanic(t, Bid)
+ shouldEqual(t, highestBid, 2)
+ shouldEqual(t, highestBidder, bidder02)
+ shouldEqual(t, pendingReturns.Size(), 1)
+}
diff --git a/docs/assets/how-to-guides/porting-solidity-to-gno/porting-7.sol b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-7.sol
new file mode 100644
index 00000000000..b28ecec1f52
--- /dev/null
+++ b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-7.sol
@@ -0,0 +1,20 @@
+/// Withdraw a bid that was overbid.
+function withdraw() external returns (bool) {
+ uint amount = pendingReturns[msg.sender];
+ if (amount > 0) {
+ // It is important to set this to zero because the recipient
+ // can call this function again as part of the receiving call
+ // before `send` returns.
+ pendingReturns[msg.sender] = 0;
+
+ // msg.sender is not of type `address payable` and must be
+ // explicitly converted using `payable(msg.sender)` in order
+ // use the member function `send()`.
+ if (!payable(msg.sender).send(amount)) {
+ // No need to call throw here, just reset the amount owing
+ pendingReturns[msg.sender] = amount;
+ return false;
+ }
+ }
+ return true;
+}
\ No newline at end of file
diff --git a/docs/assets/how-to-guides/porting-solidity-to-gno/porting-8.gno b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-8.gno
new file mode 100644
index 00000000000..7cb6bbd8d90
--- /dev/null
+++ b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-8.gno
@@ -0,0 +1,15 @@
+func Withdraw() {
+ // Query the return amount to non-highest bidders
+ amount, _ := pendingReturns.Get(std.GetOrigCaller().String())
+
+ if amount > 0 {
+ // If there's an amount, reset the amount first,
+ pendingReturns.Set(std.GetOrigCaller().String(), 0)
+
+ // Return the exceeded amount
+ banker := std.GetBanker(std.BankerTypeRealmSend)
+ pkgAddr := std.GetOrigPkgAddr()
+
+ banker.SendCoins(pkgAddr, std.GetOrigCaller(), std.Coins{{"ugnot", amount.(int64)}})
+ }
+}
diff --git a/docs/assets/how-to-guides/porting-solidity-to-gno/porting-9.gno b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-9.gno
new file mode 100644
index 00000000000..fbc06792ce4
--- /dev/null
+++ b/docs/assets/how-to-guides/porting-solidity-to-gno/porting-9.gno
@@ -0,0 +1,17 @@
+// Withdraw Function Test
+func TestWithdraw(t *testing.T) {
+ // If there's no participants for return
+ shouldEqual(t, pendingReturns.Size(), 0)
+
+ // If there's participants for return (data generation
+ returnAddr := bidder01.String()
+ returnAmount := int64(3)
+ pendingReturns.Set(returnAddr, returnAmount)
+ shouldEqual(t, pendingReturns.Size(), 1)
+ shouldEqual(t, pendingReturns.Has(returnAddr), true)
+
+ banker := std.GetBanker(std.BankerTypeRealmSend)
+ pkgAddr := std.GetOrigPkgAddr()
+ banker.SendCoins(pkgAddr, std.Address(returnAddr), std.Coins{{"ugnot", returnAmount}})
+ shouldEqual(t, banker.GetCoins(std.Address(returnAddr)).String(), "3ugnot")
+}
diff --git a/docs/assets/how-to-guides/simple-contract/counter.gno b/docs/assets/how-to-guides/simple-contract/counter.gno
new file mode 100644
index 00000000000..cf17b0c6fdc
--- /dev/null
+++ b/docs/assets/how-to-guides/simple-contract/counter.gno
@@ -0,0 +1,17 @@
+package counter
+
+import "fmt"
+
+var count int
+
+func Increment() {
+ count++
+}
+
+func Decrement() {
+ count--
+}
+
+func Render(_ string) string {
+ return fmt.Sprintf("Count: %d", count)
+}
diff --git a/docs/assets/how-to-guides/simple-contract/init.gno b/docs/assets/how-to-guides/simple-contract/init.gno
new file mode 100644
index 00000000000..823c394dfa0
--- /dev/null
+++ b/docs/assets/how-to-guides/simple-contract/init.gno
@@ -0,0 +1,11 @@
+package counter
+
+var count int
+
+// ...
+
+func init() {
+ count = 2 * 10 // arbitrary value
+}
+
+// ...
diff --git a/docs/assets/how-to-guides/simple-library/tapas.gno b/docs/assets/how-to-guides/simple-library/tapas.gno
new file mode 100644
index 00000000000..7d8eb184898
--- /dev/null
+++ b/docs/assets/how-to-guides/simple-library/tapas.gno
@@ -0,0 +1,40 @@
+package tapas
+
+import (
+ "gno.land/p/demo/rand"
+)
+
+// List of tapas suggestions
+var listOfTapas = []string{
+ "Patatas Bravas",
+ "Gambas al Ajillo",
+ "Croquetas",
+ "Tortilla Española",
+ "Pimientos de Padrón",
+ "Jamon Serrano",
+ "Boquerones en Vinagre",
+ "Calamares a la Romana",
+ "Pulpo a la Gallega",
+ "Tostada con Tomate",
+ "Mejillones en Escabeche",
+ "Chorizo a la Sidra",
+ "Cazón en Adobo",
+ "Banderillas",
+ "Espárragos a la Parrilla",
+ "Huevos Rellenos",
+ "Tuna Empanada",
+ "Sardinas a la Plancha",
+}
+
+// GetTapaSuggestion randomly selects and returns a tapa suggestion
+func GetTapaSuggestion() string {
+ // Create a new instance of the random number generator.
+ // Notice that this is from an imported Gno library
+ generator := rand.New()
+
+ // Generate a random index
+ randomIndex := generator.Intn(len(listOfTapas))
+
+ // Return the random suggestion
+ return listOfTapas[randomIndex]
+}
diff --git a/docs/assets/how-to-guides/testing-gno/counter-1.gno b/docs/assets/how-to-guides/testing-gno/counter-1.gno
new file mode 100644
index 00000000000..1741f677480
--- /dev/null
+++ b/docs/assets/how-to-guides/testing-gno/counter-1.gno
@@ -0,0 +1,19 @@
+// counter-app/r/counter/counter.gno
+
+package counter
+
+import "fmt"
+
+var count int
+
+func Increment() {
+ count++
+}
+
+func Decrement() {
+ count--
+}
+
+func Render(_ string) string {
+ return fmt.Sprintf("Count: %d", count)
+}
diff --git a/docs/assets/how-to-guides/testing-gno/counter-2.gno b/docs/assets/how-to-guides/testing-gno/counter-2.gno
new file mode 100644
index 00000000000..1298432bc03
--- /dev/null
+++ b/docs/assets/how-to-guides/testing-gno/counter-2.gno
@@ -0,0 +1,51 @@
+// counter-app/r/counter/counter_test.gno
+
+package counter
+
+import "testing"
+
+func TestCounter_Increment(t *testing.T) {
+ // Reset the value
+ count = 0
+
+ // Verify the initial value is 0
+ if count != 0 {
+ t.Fatalf("initial value != 0")
+ }
+
+ // Increment the value
+ Increment()
+
+ // Verify the initial value is 1
+ if count != 1 {
+ t.Fatalf("initial value != 1")
+ }
+}
+
+func TestCounter_Decrement(t *testing.T) {
+ // Reset the value
+ count = 0
+
+ // Verify the initial value is 0
+ if count != 0 {
+ t.Fatalf("initial value != 0")
+ }
+
+ // Decrement the value
+ Decrement()
+
+ // Verify the initial value is 1
+ if count != -1 {
+ t.Fatalf("initial value != -1")
+ }
+}
+
+func TestCounter_Render(t *testing.T) {
+ // Reset the value
+ count = 0
+
+ // Verify the Render output
+ if Render("") != "Count: 0" {
+ t.Fatalf("invalid Render value")
+ }
+}
diff --git a/docs/assets/how-to-guides/write-simple-dapp/poll-1.gno b/docs/assets/how-to-guides/write-simple-dapp/poll-1.gno
new file mode 100644
index 00000000000..45ac073a387
--- /dev/null
+++ b/docs/assets/how-to-guides/write-simple-dapp/poll-1.gno
@@ -0,0 +1,69 @@
+package poll
+
+import (
+ "std"
+
+ "gno.land/p/demo/avl"
+)
+
+// Main struct
+type Poll struct {
+ title string
+ description string
+ deadline int64 // block height
+ voters *avl.Tree // addr -> yes / no (bool)
+}
+
+// Getters
+func (p Poll) Title() string {
+ return p.title
+}
+
+func (p Poll) Description() string {
+ return p.description
+}
+
+func (p Poll) Deadline() int64 {
+ return p.deadline
+}
+
+func (p Poll) Voters() *avl.Tree {
+ return p.voters
+}
+
+// Poll instance constructor
+func NewPoll(title, description string, deadline int64) *Poll {
+ return &Poll{
+ title: title,
+ description: description,
+ deadline: deadline,
+ voters: avl.NewTree(),
+ }
+}
+
+// Vote Votes for a user
+func (p *Poll) Vote(voter std.Address, vote bool) {
+ p.Voters().Set(string(voter), vote)
+}
+
+// HasVoted vote: yes - true, no - false
+func (p *Poll) HasVoted(address std.Address) (bool, bool) {
+ vote, exists := p.Voters().Get(string(address))
+ if exists {
+ return true, vote.(bool)
+ }
+ return false, false
+}
+
+// VoteCount Returns the number of yay & nay votes
+func (p Poll) VoteCount() (int, int) {
+ var yay int
+
+ p.Voters().Iterate("", "", func(key string, value interface{}) bool {
+ vote := value.(bool)
+ if vote == true {
+ yay = yay + 1
+ }
+ })
+ return yay, p.Voters().Size() - yay
+}
diff --git a/docs/assets/how-to-guides/write-simple-dapp/poll-2.gno b/docs/assets/how-to-guides/write-simple-dapp/poll-2.gno
new file mode 100644
index 00000000000..7720c042f98
--- /dev/null
+++ b/docs/assets/how-to-guides/write-simple-dapp/poll-2.gno
@@ -0,0 +1,78 @@
+package poll
+
+import (
+ "std"
+
+ "gno.land/p/demo/avl"
+ "gno.land/p/demo/poll"
+ "gno.land/p/demo/ufmt"
+)
+
+// state variables
+var (
+ polls *avl.Tree // id -> Poll
+ pollIDCounter int
+)
+
+func init() {
+ polls = avl.NewTree()
+ pollIDCounter = 0
+}
+
+// NewPoll - Creates a new Poll instance
+func NewPoll(title, description string, deadline int64) string {
+ // get block height
+ if deadline <= std.GetHeight() {
+ return "Error: Deadline has to be in the future."
+ }
+
+ // convert int ID to string used in AVL tree
+ id := ufmt.Sprintf("%d", pollIDCounter)
+ p := poll.NewPoll(title, description, deadline)
+
+ // add new poll in avl tree
+ polls.Set(id, p)
+
+ // increment ID counter
+ pollIDCounter = pollIDCounter + 1
+
+ return ufmt.Sprintf("Successfully created poll #%s!", id)
+}
+
+// Vote - vote for a specific Poll
+// yes - true, no - false
+func Vote(pollID int, vote bool) string {
+ // get txSender
+ txSender := std.GetOrigCaller()
+
+ id := ufmt.Sprintf("%d", pollID)
+ // get specific Poll from AVL tree
+ pollRaw, exists := polls.Get(id)
+
+ if !exists {
+ return "Error: Poll with specified doesn't exist."
+ }
+
+ // cast Poll into proper format
+ poll, _ := pollRaw.(*poll.Poll)
+
+ voted, _ := poll.HasVoted(txSender)
+ if voted {
+ return "Error: You've already voted!"
+ }
+
+ if poll.Deadline() <= std.GetHeight() {
+ return "Error: Voting for this poll is closed."
+ }
+
+ // record vote
+ poll.Vote(txSender, vote)
+
+ // update Poll in tree
+ polls.Set(id, poll)
+
+ if vote == true {
+ return ufmt.Sprintf("Successfully voted YAY for poll #%s!", id)
+ }
+ return ufmt.Sprintf("Successfully voted NAY for poll #%s!", id)
+}
diff --git a/docs/assets/how-to-guides/write-simple-dapp/poll-3.gno b/docs/assets/how-to-guides/write-simple-dapp/poll-3.gno
new file mode 100644
index 00000000000..281c209c1ff
--- /dev/null
+++ b/docs/assets/how-to-guides/write-simple-dapp/poll-3.gno
@@ -0,0 +1,74 @@
+func Render(path string) string {
+ var b bytes.Buffer
+
+ b.WriteString("# Polls!\n\n")
+
+ if polls.Size() == 0 {
+ b.WriteString("### No active polls currently!")
+ return b.String()
+ }
+ polls.Iterate("", "", func(key string, value interface{}) bool {
+
+ // cast raw data from tree into Poll struct
+ p := value.(*poll.Poll)
+ ddl := p.Deadline()
+
+ yay, nay := p.VoteCount()
+ yayPercent := 0
+ nayPercent := 0
+
+ if yay+nay != 0 {
+ yayPercent = yay * 100 / (yay + nay)
+ nayPercent = nay * 100 / (yay + nay)
+ }
+
+ b.WriteString(
+ ufmt.Sprintf(
+ "## Poll #%s: %s\n",
+ key, // poll ID
+ p.Title(),
+ ),
+ )
+
+ dropdown := "\nPoll details "
+
+ b.WriteString(dropdown + "Description: " + p.Description())
+
+ b.WriteString(
+ ufmt.Sprintf(" Voting until block: %d Current vote count: %d",
+ p.Deadline(),
+ p.Voters().Size()),
+ )
+
+ b.WriteString(
+ ufmt.Sprintf(" YAY votes: %d (%d%%)", yay, yayPercent),
+ )
+ b.WriteString(
+ ufmt.Sprintf(" NAY votes: %d (%d%%)", nay, nayPercent),
+ )
+
+ dropdown = " \nVote details"
+ b.WriteString(dropdown)
+
+ p.Voters().Iterate("", "", func(key string, value interface{}) bool {
+
+ voter := key
+ vote := value.(bool)
+
+ if vote == true {
+ b.WriteString(
+ ufmt.Sprintf(" %s voted YAY!", voter),
+ )
+ } else {
+ b.WriteString(
+ ufmt.Sprintf(" %s voted NAY!", voter),
+ )
+ }
+ return false
+ })
+
+ b.WriteString("\n\n")
+ return false
+ })
+ return b.String()
+}
diff --git a/docs/assets/reference/standard-library/std-1.gno b/docs/assets/reference/standard-library/std-1.gno
new file mode 100644
index 00000000000..5f5a5d86b76
--- /dev/null
+++ b/docs/assets/reference/standard-library/std-1.gno
@@ -0,0 +1,14 @@
+// returns the list of coins owned by the address
+GetCoins(addr Address) (dst Coins)
+
+// sends coins from one address to another
+SendCoins(from, to Address, amt Coins)
+
+// returns the total supply of the coin
+TotalCoin(denom string) int64
+
+// issues coins to the address
+IssueCoin(addr Address, denom string, amount int64)
+
+// burns coins from the address
+RemoveCoin(addr Address, denom string, amount int64)
diff --git a/docs/assets/reference/standard-library/std-2.gno b/docs/assets/reference/standard-library/std-2.gno
new file mode 100644
index 00000000000..1ef9a0a1af1
--- /dev/null
+++ b/docs/assets/reference/standard-library/std-2.gno
@@ -0,0 +1,4 @@
+type Coin struct {
+ Denom string `json:"denom"` // the symbol of the coin
+ Amount int64 `json:"amount"` // the quantity of the coin
+}
diff --git a/docs/from-go-to-gno.md b/docs/explanation/from-go-to-gno.md
similarity index 97%
rename from docs/from-go-to-gno.md
rename to docs/explanation/from-go-to-gno.md
index fc7f28ab73a..41cccc6e971 100644
--- a/docs/from-go-to-gno.md
+++ b/docs/explanation/from-go-to-gno.md
@@ -1,3 +1,7 @@
+---
+id: from-go-to-gno
+---
+
# From Go to Gno
## Runtime comparison
@@ -69,5 +73,5 @@ TODO
## See also
-- [go-gno-compatibility.md](./go-gno-compatibility.md)
+- [go-gno-compatibility.md](../reference/go-gno-compatibility.md)
- ["go -> gno" presentation by Zack Scholl](https://github.com/gnolang/workshops/tree/main/presentations/2023-06-26--go-to-gno--schollz)
diff --git a/docs/explanation/gno-language.md b/docs/explanation/gno-language.md
new file mode 100644
index 00000000000..4e0605a6fac
--- /dev/null
+++ b/docs/explanation/gno-language.md
@@ -0,0 +1,68 @@
+---
+id: gno-language
+---
+
+# The Gno Language
+
+Gno (Gnolang) is an interpretation of the widely-used Go (Golang) programming language for blockchain created by Cosmos
+co-founder Jae Kwon in 2021 to mark a new era in smart contracting. Gno is almost identical to Go, so Go developers can
+quickly start using it, with minimal effort. For example, Gno comes with blockchain-specific standard libraries, but any
+code that doesn’t use blockchain-specific logic can run in Go with minimal processing. Libraries that could lead to
+non-deterministic behaviour when executed by thousands of validators are not available in Gno, such as network access,
+or determining system time. Otherwise, Gno loads and uses many standard libraries that power Go, so the experience
+writing code feels very similar to Go's.
+
+Under the hood, the Gno code is parsed into an abstract syntax tree (AST) and the AST itself is used in the interpreter,
+rather than bytecode as in many virtual machines such as Java, Python, or Wasm. The design aims to make reading &
+understanding the source code of the GnoVM accessible to any Go programmer. The novel design of the intuitive GnoVM
+interpreter allows Gno to freeze and resume the program by persisting and loading the memory state automatically. Gno is
+deterministic, auto-persisted, and auto-Merkle-ized, allowing programs to be succinct, as the programmer doesn’t have to
+serialize and deserialize objects to persist them into a database (unlike programming applications with the Cosmos SDK).
+
+## How Gno Differs from Go
+
+The composable nature of Go/Gno allows for type-checked interactions between contracts, making Gno.land safer and more
+powerful, as well as operationally cheaper and faster. Smart contracts on Gno.land are light, simple, more focused, and
+easily interoperable - they represent a network of interconnected contracts rather than siloed monoliths that limit
+interactions with other contracts.
+
+## Gno Inherits Go’s Built-in Security Features
+
+Go supports secure programming through exported/non-exported fields, enabling a “least-authority” design. It is easy to
+create objects and APIs that expose only what should be accessible to callers while hiding what should not be simply by
+the capitalization of letters, thus allowing a succinct representation of secure logic that can be called by multiple
+users.
+
+Another major advantage of Go is that the language comes with an ecosystem of great tooling, like the compiler and
+third-party tools that statically analyze code. Gno inherits these advantages from Go directly to create a smart
+contract programming language that provides embedding, composability, type-check safety, and garbage collection, helping
+developers to write secure code relying on the compiler, parser, and interpreter to give warning alerts for common
+mistakes.
+
+## Gno vs Solidity
+
+The most widely-adopted smart contract language today is Ethereum’s EVM-compatible Solidity. With bytecode built from
+the ground up and Turing complete, Solidity opened up a world of possibilities for decentralized applications (dApps)
+and there are currently more than 10 million contracts deployed on Ethereum. However, Solidity provides limited tooling
+and its EVM has a stack limit and computational inefficiencies.
+
+Solidity is designed for one purpose only (writing smart contracts) and is bound by the limitations of the EVM. In
+addition, developers have to learn several languages if they want to understand the whole stack or work across different
+ecosystems. Gno aspires to exceed Solidity on multiple fronts (and other smart contract languages like CosmWasm or
+Substrate) as every part of the stack is written in Go (or Gno!). It’s easy for developers to understand the entire system just
+by studying a relatively small code base.
+
+## Gno Is Essential for the Wider Adoption of Web3
+
+Gno makes imports as easy as they are in web2 with runtime-based imports for seamless dependency flow comprehension, and
+support for complex structs, beyond primitive types. Gno is ultimately cost-effective as dependencies are loaded once,
+enabling remote function calls as local, and providing automatic and independent per-realm state persistence.
+
+Using Gno, developers can rapidly accelerate application development and adopt a modular structure by reusing and
+reassembling existing modules without building from scratch. They can embed one structure inside another in an intuitive
+way while preserving localism, and the language specification is simple, successfully balancing practicality and
+minimalism.
+
+Building on top of the excellent design of Go, the aim for Gno programming is to become the new gold standard for smart
+contract development, not just in our ecosystem but blockchain as a whole. Combining Go's large success, together with
+type safety and composability, Gno aims to kickstart a broader adoption of Web3 and its growth.
diff --git a/docs/explanation/gno-modules.md b/docs/explanation/gno-modules.md
new file mode 100644
index 00000000000..30f1de7b714
--- /dev/null
+++ b/docs/explanation/gno-modules.md
@@ -0,0 +1,42 @@
+---
+id: gno-modules
+---
+
+# Gno Modules
+
+The packages and realms containing `gno.mod` file can be reffered as Gno modules. `gno.mod` file is introduced to enhance local testing and handle dependency management while testing Gno packages/realms locally. At the time of writing, `gno.mod` is only used by the `gno` tool for local development, and it is disregarded on the Gno.land chain.
+
+## What is the gno.mod file for?
+
+`gno.mod` file is very useful for local testing and development. Its primary purposes include:
+
+- **Working outside of the monorepo**: by adding a `gno.mod` file to your directory, all gno tooling will recognise it and understand the implicit import path of your current directory (marked by the `module` directive in your `gno.mod` file).
+- **Local dependency management**: the gno.mod file allows you to manage and download local dependencies effectively when developing Go Modules.
+- **Configuration and metadata (WIP)**: while the gno.mod file is currently used for specifying dependencies, it's worth noting that in the future, it might also serve as a container for additional configuration and metadata related to Gno Modules. For more information, see: [issue #498](https://github.com/gnolang/gno/issues/498).
+
+## Gno Modules and Subdirectories
+
+It's important to note that Gno Modules do not include subdirectories. Each directory within your project is treated as an individual Gno Module, and each should contain its own gno.mod file, even if it's located within an existing Gno Module directory.
+
+## Available gno Commands
+
+The gno command-line tool provides several commands to work with the gno.mod file and manage dependencies in Gno Modules:
+
+- **gno mod init**: small helper to initialize a new `gno.mod` file.
+- **gno mod download**: downloads the dependencies specified in the gno.mod file. This command fetches the required dependencies from chain and ensures they are available for local testing and development.
+- **gno mod tidy**: removes any unused dependency and adds any required but not yet listed in the file -- most of the maintenance you'll usually need to do!
+
+## Sample `gno.mod` file
+
+```
+module gno.land/p/demo/sample
+
+require (
+ gno.land/p/demo/avl v0.0.0-latest
+ gno.land/p/demo/testutils v0.0.0-latest
+)
+
+```
+
+- **`module gno.land/p/demo/sample`**: specifies the package/realm import path.
+- **`require` Block**: lists the required dependencies. Here using the latest available versions of "gno.land/p/demo/avl" and "gno.land/p/demo/testutils". These dependencies should be specified with the version "v0.0.0-latest" since on-chain packages currently do not support versioning.
diff --git a/docs/explanation/gno-test.md b/docs/explanation/gno-test.md
new file mode 100644
index 00000000000..cd585298b9d
--- /dev/null
+++ b/docs/explanation/gno-test.md
@@ -0,0 +1,82 @@
+---
+id: gno-test
+---
+
+# Gno Test
+
+There are two methods for testing a realm or package during the development phase:
+
+1. Calling the realm/package after deploying it on a local network (or testnet).
+2. Using the `test` option within the [`gno`](./gno-tooling/cli/gno.md) CLI.
+
+While the first method is recommended for its accuracy and similarity to the actual deployment environment, it is more efficient to initially utilize the second method for composing test cases and then proceed to the first method if no errors are detected.
+
+This section will teach you how to use the second method.
+
+Writing test cases in Gnolang is similar to that of Golang, with general rules as the following:
+
+* Test file naming conventions must be adhered to (ex: `xxx_test.gno`).
+* Test functions must start with `Test`.
+* The `t *testing.T` argument must be included in each test function.
+ * The `testing` package must be imported.
+* Tests must be run with the `gno test` command.
+
+Let's write a sample code and test it.
+
+```go
+// contract.gno
+
+package demo
+
+func Hello(name string) string {
+ return "Hello " + name + "!"
+}
+```
+
+This is a simple code that returns the string-typed argument in a specific format.
+
+Next, we'll write a test case that looks like the following:
+
+```go
+// contract_test.gno
+
+package demo
+
+import "testing"
+
+func Test(t *testing.T) {
+ {
+ got := Hello("People")
+ expected := "Hello People!"
+ if got != expected {
+ t.Fatalf("expected %q, got %q.", expected, got)
+ }
+ }
+ {
+ got := Hello("")
+ expected := "Hello People!"
+ if got != expected {
+ t.Fatalf("expected %q, got %q.", expected, got)
+ }
+ }
+}
+```
+
+Two conditions exist in the test case above.
+
+1. "Hello People!" should be returned when calling `Hello("People")`.
+2. "Hello People!" should be returned when calling `Hello("")`.
+
+Upon examination of our realm code and the associated test results, the initial condition exhibited the desired behavior; however, an error was identified in the second condition. Despite the expected outcome of "Hello" being returned, the test case incorrectly specified that the expected output should be "Hello People!" instead.
+
+Replacing the second test case with the following will successfully fix the issue and allow the test to pass.
+
+```go
+ {
+ got := Hello("")
+ expected := "Hello !"
+ if expected != got {
+ t.Fatalf("expected %q, got %q.", expected, got)
+ }
+ }
+```
diff --git a/docs/explanation/gno-tooling/cli/gno.md b/docs/explanation/gno-tooling/cli/gno.md
new file mode 100644
index 00000000000..3141476f02a
--- /dev/null
+++ b/docs/explanation/gno-tooling/cli/gno.md
@@ -0,0 +1,66 @@
+---
+id: gno-tooling-gno
+---
+
+# gno
+
+`gno` is a handy tool for developing and prototyping Gno packages and realms. You may use `gno` to use the GnoVM without an actual blockchain to build or test realms in a local environment.
+
+## Run `gno` Commands
+
+The following command will run `gno`.
+
+```bash
+gno {SUB_COMMAND}
+```
+
+**Subcommands**
+
+| Name | Description |
+| ------------ | ------------------------------------------ |
+| `build` | Builds a gno package. |
+| `test` | Tests a gno package. |
+| `precompile` | Precompiles a `.gno` file to a `.go` file. |
+| `repl` | Starts a GnoVM REPL. |
+
+### `build`
+
+#### **Options**
+
+| Name | Type | Description |
+| --------- | ------- | ---------------------------------------------- |
+| `verbose` | Boolean | Displays extended information. |
+| go-binary | String | Go binary to use for building (default: `go`). |
+
+### `test`
+
+#### **Options**
+
+| Name | Type | Description |
+| ------------ | ------------- | ------------------------------------------------------------------ |
+| `verbose` | Boolean | Displays extended information. |
+| `root-dir` | String | Clones location of github.com/gnolang/gno (gno tries to guess it). |
+| `run` | String | Test name filtering pattern. |
+| `timeout` | time.Duration | The maximum execution time in ns. |
+| `precompile` | Boolean | Precompiles a `.gno` file to a `.go` file before testing. |
+
+### `precompile`
+
+#### **Options**
+
+| Name | Type | Description |
+| ----------- | ------- | --------------------------------------------------------------- |
+| `verbose` | Boolean | Displays extended information. |
+| `skip-fmt` | Boolean | Skips the syntax checking of generated `.go` files. |
+| `go-binary` | String | The go binary to use for building (default: `go`). |
+| `go-binary` | String | The gofmt binary to use for syntax checking (default: `gofmt`). |
+| `output` | String | The output directory (default: `.`). |
+
+### `repl`
+
+#### **Options**
+
+| Name | Type | Description |
+| ---------- | ------- | ------------------------------------------------------------------ |
+| `verbose` | Boolean | Displays extended information. |
+| `root-dir` | String | Clones location of github.com/gnolang/gno (gno tries to guess it). |
diff --git a/docs/explanation/gno-tooling/cli/gnofaucet.md b/docs/explanation/gno-tooling/cli/gnofaucet.md
new file mode 100644
index 00000000000..3e70add89c0
--- /dev/null
+++ b/docs/explanation/gno-tooling/cli/gnofaucet.md
@@ -0,0 +1,61 @@
+---
+id: gno-tooling-gnofaucet
+---
+
+# gnofaucet
+
+`gnofaucet` is a server for distributing GNOT, the gas currency of Gnoland, to specific addresses in a local chain.
+Interact with the `gnofaucet` from an address with an empty balance in your locally built testnet to fuel it with GNOT
+to pay for transactions.
+
+## Run `gnofaucet` Commands
+
+Enable the faucet using the following command.
+
+```bash
+gnofaucet serve
+```
+
+#### **Options**
+
+| Name | Type | Description |
+|---------------------------|---------|--------------------------------------------------------------------------------------|
+| `chain-id` | String | The id of the chain (required). |
+| `gas-wanted` | Int64 | The maximum amount of gas to use for the transaction (default: `50000`) |
+| `gas-fee` | String | The gas fee to pay for the transaction. |
+| `memo` | String | Any descriptive text (default: `""`) |
+| `test-to` | String | Test address (optional) |
+| `send` | String | Coins to send (default: `"1000000ugnot"`). |
+| `captcha-secret` | String | The secret key for the recaptcha. If empty, the captcha is disabled (default: `""`). |
+| `is-behind-proxy` | Boolean | Uses X-Forwarded-For IP for throttling (default: `false`). |
+| `insecure-password-stdin` | Boolean | INSECURE! Takes password from stdin (default: `false`). |
+
+## Example
+
+### Step 1. Create an account named `test1` with the test seed phrase below.
+
+```bash
+gnokey add test1 --recover
+```
+
+> **Test Seed Phrase:** source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate
+> oppose farm nothing bullet exhibit title speed wink action roast
+
+### **Step 2. Run `gnofaucet`**
+
+```bash
+gnofaucet serve test1 --chain-id dev --send 500000000ugnot
+```
+
+### **Step 3. Receive GNOTs from the faucet**
+
+To receive funds through the `gnoweb` form GUI, you can request them on:
+`http://localhost:8888/faucet` (given `http://localhost:8888/` is the location where `gnoweb` is serving pages).
+
+Alternatively, you can request funds from the faucet by directly invoking a CURL command:
+
+```bash
+curl --location --request POST 'http://localhost:5050' \
+--header 'Content-Type: application/x-www-form-urlencoded' \
+--data-urlencode 'toaddr={address to receive}'
+```
diff --git a/docs/explanation/gno-tooling/cli/gnokey.md b/docs/explanation/gno-tooling/cli/gnokey.md
new file mode 100644
index 00000000000..dffee356509
--- /dev/null
+++ b/docs/explanation/gno-tooling/cli/gnokey.md
@@ -0,0 +1,290 @@
+---
+id: gno-tooling-gnokey
+---
+
+# gnokey
+
+Used for account & key management and general interactions with the Gnoland blockchain.
+
+## Generate a New Seed Phrase
+
+Generate a new seed phrase and add it to your keybase with the following command.
+
+```bash
+gnokey generate
+```
+
+## Add a New Key
+
+You can add a new private key to the keybase using the following command.
+
+```bash
+gnokey add {KEY_NAME}
+```
+
+#### **Options**
+
+| Name | Type | Description |
+| ----------- | ---------- | -------------------------------------------------------------------------------------- |
+| `account` | UInt | Account number for HD derivation. |
+| `dryrun` | Boolean | Performs action, but doesn't add key to local keystore. |
+| `index` | UInt | Address index number for HD derivation. |
+| `ledger` | Boolean | Stores a local reference to a private key on a Ledger device. |
+| `multisig` | String \[] | Constructs and stores a multisig public key (implies `--pubkey`). |
+| `nobackup` | Boolean | Doesn't print out seed phrase (if others are watching the terminal). |
+| `nosort` | Boolean | Keys passed to `--multisig` are taken in the order they're supplied. |
+| `pubkey` | String | Parses a public key in bech32 format and save it to disk. |
+| `recover` | Boolean | Provides seed phrase to recover existing key instead of creating. |
+| `threshold` | Int | K out of N required signatures. For use in conjunction with --multisig (default: `1`). |
+
+> **Test Seed Phrase:** source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast
+
+## List all Known Keys
+
+List all keys stored in your keybase with the following command.
+
+```bash
+gnokey list
+```
+
+## Delete a Key
+
+Delete a key from your keybase with the following command.
+
+```bash
+gnokey delete {KEY_NAME}
+```
+
+#### **Options**
+
+| Name | Type | Description |
+| ------- | ------- | ---------------------------- |
+| `yes` | Boolean | Skips confirmation prompt. |
+| `force` | Boolean | Removes key unconditionally. |
+
+
+## Export a Private Key (Encrypted & Unencrypted)
+
+Export a private key's (encrypted or unencrypted) armor using the following command.
+
+```bash
+gnokey export
+```
+
+#### **Options**
+
+| Name | Type | Description |
+| ------------- | ------ | ------------------------------------------- |
+| `key` | String | Name or Bech32 address of the private key |
+| `output-path` | String | The desired output path for the armor file |
+| `unsafe` | Bool | Export the private key armor as unencrypted |
+
+
+## Import a Private Key (Encrypted & Unencrypted)
+
+Import a private key's (encrypted or unencrypted) armor with the following command.
+
+```bash
+gnokey import
+```
+
+#### **Options**
+
+| Name | Type | Description |
+| ------------ | ------ | ------------------------------------------- |
+| `armor-path` | String | The path to the encrypted armor file. |
+| `name` | String | The name of the private key. |
+| `unsafe` | Bool | Import the private key armor as unencrypted |
+
+
+## Make an ABCI Query
+
+Make an ABCI Query with the following command.
+
+```bash
+gnokey query {QUERY_PATH}
+```
+
+#### **Query**
+
+| Query Path | Description | Example |
+| ------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
+| `auth/accounts/{ADDRESS}` | Returns information about an account. | `gnokey query auth/accounts/g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` |
+| `bank/balances/{ADDRESS}` | Returns balances of an account. | `gnokey query bank/balances/g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` |
+| `vm/qfuncs` | Returns public facing function signatures as JSON. | `gnokey query vm/qfuncs --data "gno.land/r/demo/boards"` |
+| `vm/qfile` | Returns the file bytes, or list of files if directory. | `gnokey query vm/qfile --data "gno.land/r/demo/boards"` |
+| `vm/qrender` | Calls .Render(path) in readonly mode. | `gnokey query vm/qrender --data "gno.land/r/demo/boards"` |
+| `vm/qeval` | Evaluates any expression in readonly mode and returns the results. | `gnokey query vm/qeval --data "gno.land/r/demo/boards GetBoardIDFromName("my_board")"` |
+| `vm/store` | (not yet supported) Fetches items from the store. | - |
+| `vm/package` | (not yet supported) Fetches a package's files. | - |
+
+#### **Options**
+
+| Name | Type | Description |
+| -------- | --------- | ---------------------------------------- |
+| `data` | UInt8 \[] | Queries data bytes. |
+| `height` | Int64 | (not yet supported) Queries height. |
+| `prove` | Boolean | (not yet supported) Proves query result. |
+
+
+## Sign and Broadcast a Transaction
+
+You can sign and broadcast a transaction with the following command.
+
+```bash
+gnokey maketx {SUB_COMMAND} {ADDRESS or KeyName}
+```
+
+#### **Subcommands**
+
+| Name | Description |
+| -------- | ---------------------------- |
+| `addpkg` | Uploads a new package. |
+| `call` | Calls a public function. |
+| `send` | The amount of coins to send. |
+
+### `addpkg`
+
+This subcommand lets you upload a new package.
+
+```bash
+gnokey maketx addpkg \
+ -deposit="1ugnot" \
+ -gas-fee="1ugnot" \
+ -gas-wanted="5000000" \
+ -pkgpath={Registered Realm path} \
+ -pkgdir={Package folder path} \
+ {ADDRESS} \
+ > unsigned.tx
+```
+
+#### **SignBroadcast Options**
+
+| Name | Type | Description |
+| ------------ | ------- | ------------------------------------------------------------------------ |
+| `gas-wanted` | Int64 | The maximum amount of gas to use for the transaction. |
+| `gas-fee` | String | The gas fee to pay for the transaction. |
+| `memo` | String | Any descriptive text. |
+| `broadcast` | Boolean | Broadcasts the transaction. |
+| `chainid` | String | Defines the chainid to sign for (should only be used with `--broadcast`) |
+
+#### **makeAddPackageTx Options**
+
+| Name | Type | Description |
+| --------- | ------ | ------------------------------------- |
+| `pkgpath` | String | The package path (required). |
+| `pkgdir` | String | The path to package files (required). |
+| `deposit` | String | The amount of coins to send. |
+
+
+### `call`
+
+This subcommand lets you call a public function.
+
+```bash
+# Register
+gnokey maketx call \
+ -gas-fee="1ugnot" \
+ -gas-wanted="5000000" \
+ -pkgpath="gno.land/r/demo/users" \
+ -send="200000000ugnot" \
+ -func="Register" \
+ -args="" \
+ -args={NAME} \
+ -args="" \
+ {ADDRESS} \
+ > unsigned.tx
+```
+
+#### **SignBroadcast Options**
+
+| Name | Type | Description |
+| ------------ | ------- | ---------------------------------------------------------------- |
+| `gas-wanted` | Int64 | The maximum amount of gas to use for the transaction. |
+| `gas-fee` | String | The gas fee to pay for the transaction. |
+| `memo` | String | Any descriptive text. |
+| `broadcast` | Boolean | Broadcasts the transaction. |
+| `chainid` | String | The chainid to sign for (should only be used with `--broadcast`) |
+
+#### **makeCallTx Options**
+
+| Name | Type | Description |
+| --------- | ---------- | -------------------------------- |
+| `send` | String | The amount of coins to send. |
+| `pkgpath` | String | The package path (required). |
+| `func` | String | The contract to call (required). |
+| `args` | String \[] | The arguments of the contract. |
+
+
+### `send`
+
+This subcommand lets you send a native currency to an address.
+
+```bash
+gnokey maketx send \
+ -gas-fee="1ugnot" \
+ -gas-wanted="5000000" \
+ -send={SEND_AMOUNT} \
+ -to={TO_ADDRESS} \
+ {ADDRESS} \
+ > unsigned.tx
+```
+
+#### **SignBroadcast Options**
+
+| Name | Type | Description |
+| ------------ | ------- | ----------------------------------------------------- |
+| `gas-wanted` | Int64 | The maximum amount of gas to use for the transaction. |
+| `gas-fee` | String | The gas fee to pay for the transaction. |
+| `memo` | String | Any descriptive text. |
+| `broadcast` | Boolean | Broadcasts the transaction. |
+| `chainid` | String | The chainid to sign for (implies `--broadcast`) |
+
+#### **makeSendTx Options**
+
+| Name | Type | Description |
+| ------ | ------ | ------------------------ |
+| `send` | String | Amount of coins to send. |
+| `to` | String | The destination address. |
+
+
+## Sign a Document
+
+Sign a document with the following command.
+
+```bash
+gnokey sign
+```
+
+#### **Options**
+
+| Name | Type | Description |
+| ---------------- | ------- | ---------------------------------------------------------- |
+| `txpath` | String | The path to file of tx to sign (default: `-`). |
+| `chainid` | String | The chainid to sign for (default: `dev`). |
+| `number` | UInt | The account number of the account to sign with (required) |
+| `sequence` | UInt | The sequence number of the account to sign with (required) |
+| `show-signbytes` | Boolean | Shows signature bytes. |
+
+
+## Verify a Document Signature
+
+Verify a document signature with the following command.
+
+```bash
+gnokey verify
+```
+
+#### **Options**
+
+| Name | Type | Description |
+| --------- | ------ | ---------------------------------------- |
+| `docpath` | String | The path of the document file to verify. |
+
+## Broadcast a Signed Document
+
+Broadcast a signed document with the following command.
+
+```bash
+gnokey broadcast {signed transaction file document}
+```
diff --git a/docs/explanation/gno-tooling/cli/gnoland.md b/docs/explanation/gno-tooling/cli/gnoland.md
new file mode 100644
index 00000000000..3c05897646b
--- /dev/null
+++ b/docs/explanation/gno-tooling/cli/gnoland.md
@@ -0,0 +1,31 @@
+---
+id: gno-tooling-gnoland
+---
+
+# gnoland
+
+## Run a Gnoland Node
+
+Start a node on the Gnoland blockchain with the following command.
+
+```bash
+gnoland
+```
+
+### **Sub Commands**
+| Command | Description |
+| --------- | ----------------- |
+| `start` | Run the full node |
+
+
+### **Options**
+
+| Name | Type | Description |
+| -------------------------- | ------- | --------------------------------------------------------------------------------------- |
+| `chainid` | String | The id of the chain (default: `dev`). |
+| `genesis-balances-file` | String | The initial GNOT distribution file (default: `./gnoland/genesis/genesis_balances.txt`). |
+| `genesis-remote` | String | Replacement '%%REMOTE%%' in genesis (default: `"localhost:26657"`). |
+| `genesis-txs-file` | String | Initial txs to be executed (default: `"./gnoland/genesis/genesis_txs.txt"`). |
+| `root-dir` | String | directory for config and data (default: `testdir`). |
+| `skip-failing-genesis-txs` | Boolean | Skips transactions that fail from the `genesis-txs-file` |
+| `skip-start` | Boolean | Quits after initialization without starting the node. |
diff --git a/docs/explanation/gno-tooling/cli/tm2txsync.md b/docs/explanation/gno-tooling/cli/tm2txsync.md
new file mode 100644
index 00000000000..e9d616bcea5
--- /dev/null
+++ b/docs/explanation/gno-tooling/cli/tm2txsync.md
@@ -0,0 +1,45 @@
+---
+id: gno-tooling-tm2txsync
+---
+
+# tm2txsync
+
+`tm2txsync` is used for backing up a local node's transactions.
+
+## Import Transaction Data To (or Export It From) a Node
+
+You may import or export transaction data with the following command.
+
+```bash
+tm2txsync {SUB_COMMAND}
+```
+
+#### **Subcommands**
+
+| Name | Description |
+| -------- | -------------------------- |
+| `export` | Exports txs from the node. |
+| `import` | Imports txs to the node. |
+
+### Import
+
+#### **Options**
+
+| Name | Type | Description |
+| -------- | ------ | ----------------------------------------------------------------- |
+| `remote` | String | The Remote RPC in `addr:port` format (default: `localhost:26657`) |
+| `in` | String | The input file path (default: `txexport.log`) |
+
+### Export
+
+#### **Options**
+
+| Name | Type | Description |
+| -------- | ------- | ----------------------------------------------------------------- |
+| `remote` | String | The Remote RPC in `addr:port` format (default: `localhost:26657`) |
+| `start` | Int64 | Starting height (default: `1`) |
+| `tail` | Int64 | Start at LAST - N. |
+| `end` | Int64 | End height (optional) |
+| `out` | String | The output file path (default: `txexport.log`) |
+| `quiet` | Boolean | Quiet mode. |
+| `follow` | Boolean | Keep attached and follow new events. |
diff --git a/docs/explanation/gnovm.md b/docs/explanation/gnovm.md
new file mode 100644
index 00000000000..fb767ff316a
--- /dev/null
+++ b/docs/explanation/gnovm.md
@@ -0,0 +1,27 @@
+---
+id: gnovm
+---
+
+# GnoVM
+
+GnoVM is a virtual machine that interprets Gnolang, a custom version of Golang optimized for blockchains, featuring automatic state management, full determinism, and idiomatic Go.
+It works with Tendermint2 and enables smarter, more modular, and transparent appchains with embedded smart-contracts.
+It can be adapted for use in TendermintCore, forks, and non-Cosmos blockchains.
+
+Read the ["Intro to Gnoland"](https://test3.gno.land/r/gnoland/blog:p/intro) blogpost.
+
+This folder focuses on the VM, language, stdlibs, tests, and tools, independent of the blockchain.
+This enables non-web3 developers to contribute without requiring an understanding of the broader context.
+
+## Language Features
+
+* Like interpreted Go, but more ambitious.
+* Completely deterministic, for complete accountability.
+* Transactional persistence across data realms.
+* Designed for concurrent blockchain smart contracts systems.
+
+## Getting started
+
+Install [`gno`](./cmd/gno) and refer to the [`examples`](../examples) folder to start developing contracts.
+
+Check the [Makefile](./Makefile) to enhance GnoVM, Gnolang, and stdlibs.
diff --git a/docs/explanation/packages.md b/docs/explanation/packages.md
new file mode 100644
index 00000000000..85443052a6a
--- /dev/null
+++ b/docs/explanation/packages.md
@@ -0,0 +1,113 @@
+---
+id: packages
+---
+
+# Packages
+
+Packages encompass functionalities that are more closely aligned with the characteristics and capabilities of realms, as opposed to standard libraries.
+
+The full list of available packages can be found in [the demo package](https://github.com/gnolang/gno/tree/master/examples/gno.land/p/demo). Below are some of the most commonly used packages.
+
+## `avl`
+
+In Golang, the classic key/value data type is represented by the `map` construct. However, while Gnolang also supports the use of `map`, it is not a viable option as it lacks determinism due to its non-sequential nature.
+
+To address this issue, Gnolang implements the [AVL Tree](https://en.wikipedia.org/wiki/AVL\_tree) (Adelson-Velsky-Landis Tree) as a solution. The AVL Tree is a self-balancing binary search tree.
+
+The `avl` package comprises a set of functions that can manipulate the leaves and nodes of the AVL Tree.
+
+## `grc20`
+
+Gnolang includes an implementation of the `erc20` fungible token standard referred to as `grc20`. The interfaces of `grc20` are as follows:
+
+[embedmd]:# (../assets/explanation/packages/pkg-1.gno go)
+```go
+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
+```
+
+The role of each function is as follows:
+
+* `TotalSupply`: Returns the total supply of the token.
+* `BalanceOf`: Returns the balance of tokens of an account.
+* `Transfer`: Transfers specific `amount` of tokens from the `caller` of the function to the `to` address.
+* `Approve`: Grants the `spender`(also referred to as `operator`) with the ability to send specific `amount` of the `caller`'s (also referred to as `owner`) tokens on behalf of the `caller`.
+* `TransferFrom`: Can be called by the `operator` to send specific `amount` of `owner`'s tokens from the `owner`'s address to the `to` address.
+* `Allowance`: Returns the number of tokens approved to the `spender` by the `owner`.
+
+Two types of contracts exist in`grc20`:
+
+1. `AdminToken`\
+ \- Implements the token factory with `Helper` functions.\
+ \- The underlying struct should not be exposed to users. However, it can be typecasted as UserToken using the `GRC20()` method.
+2. `UserToken`\
+ \- Implements the `IGRC20` interface.\
+ \- The underlying struct can be exposed to users. Created with the `GRC20()` method of `adminToken`.
+
+## `grc721`
+
+Gnolang includes an implementation of the `erc721` non-fungible token standard referred to as `grc721`. The interfaces of `grc721` are as follows:
+
+[embedmd]:# (../assets/explanation/packages/pkg-2.gno go)
+```go
+// 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
+```
+
+`grc721` contains a new set of functions:
+
+* `OwnerOf`: Returns the `owner`'s address of a token specified by its `TokenID`.
+* `SafeTransferFrom`: Equivalent to the `TransferFrom` function of `grc20`.
+ * The `Safe` prefix indicates that the function runs a check to ensure that the `to` address is a valid address that can receive tokens.
+ * As you can see from the [code](https://github.com/gnolang/gno/blob/master/examples/gno.land/p/demo/grc/grc721/basic\_nft.gno#L341), the concept of `Safe` has yet to be implemented.
+* `SetApprovalForAll`: Approves all tokens owned by the `owner` to an `operator`.
+ * You may not set multiple `operator`s.
+* `GetApproved`: Returns the `address` of the `operator` for a token, specified with its `ID`.
+* `IsApprovedForAll`: Returns if all NFTs of the `owner` have been approved to the `operator`.
+
+## `testutils`
+
+The `testutils` package contains a set of functions that comes in handy when testing realms. The sample function below is the commonly used `TestAddress` function that generates a random address.
+
+[embedmd]:# (../assets/explanation/packages/pkg-3.gno go)
+```go
+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))
+}
+```
+
+The code takes the `name` as the input and creates a random address. Below is a list of examples where it's used in the test case of the `foo20` realm.
+
+[embedmd]:# (../assets/explanation/packages/pkg-4.gno go)
+```go
+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"))
+```
diff --git a/docs/proof-of-contribution.md b/docs/explanation/proof-of-contribution.md
similarity index 99%
rename from docs/proof-of-contribution.md
rename to docs/explanation/proof-of-contribution.md
index e839a3cdf1f..364a5eb254d 100644
--- a/docs/proof-of-contribution.md
+++ b/docs/explanation/proof-of-contribution.md
@@ -1,3 +1,7 @@
+---
+id: proof-of-contribution
+---
+
# Proof of Contribution
The gno.land chain utilizes a reputation-based consensus mechanism instead of proof-of-stake.
diff --git a/docs/explanation/realms.md b/docs/explanation/realms.md
new file mode 100644
index 00000000000..fd6969db3f1
--- /dev/null
+++ b/docs/explanation/realms.md
@@ -0,0 +1,49 @@
+---
+id: realms
+---
+
+# Realms
+
+A realm refers to a specific instance of a smart contract that can be written
+in [Gnolang](./gno-language.md). The potentials of realms are endless - you can create virtually any
+application in your mind with built-in composability,
+transparency, and censorship resistance. Here are some ideas of what you can build with realms:
+
+* Self-custodial financial exchanges (decentralized exchanges).
+* Lending platforms with better rates.
+* Transparent insurance systems.
+* Fair and accessible voting systems.
+* Logistics and supply chain networks.
+
+## Packages vs Realms
+
+#### [**Pure Packages**](https://github.com/gnolang/gno/tree/master/examples/gno.land/p)
+
+* A unit that contains functionalities and utilities that can be used in realms.
+* Packages are stateless.
+* The default import path is `gno.land/p/~~~`.
+* Can be imported to other realms or packages.
+* Cannot import realms.
+
+#### [**Realms**](https://github.com/gnolang/gno/tree/master/examples/gno.land/r)
+
+* Smart contracts in Gnolang.
+* Realms are stateful.
+* Realms can own assets (tokens).
+* The default import path is `gno.land/r/~~~`.
+* Realms can implement `Render(path string) string` to simplify dapp frontend development by allowing users to request
+ markdown renderings from validators and full nodes without a transaction.
+
+A notable feature of realms is the `Render()` function.
+
+```go
+package demo
+
+func Render(path string) string {
+ return "# Hello Gno!"
+}
+```
+
+Upon calling the realm above, `# Hello Gno!` is printed with a string-typed `path` declared in an argument. It should be
+noted that while the `path` argument included in the sample code is not utilized, it serves the purpose of
+distinguishing the path during the rendering process.
diff --git a/docs/explanation/tendermint2.md b/docs/explanation/tendermint2.md
new file mode 100644
index 00000000000..3c86a46922a
--- /dev/null
+++ b/docs/explanation/tendermint2.md
@@ -0,0 +1,122 @@
+---
+id: tendermint2
+---
+
+# Tendermint2
+
+**Disclaimer: Tendermint2 is currently part of the Gno monorepo for streamlined development.**
+
+**Once Gno.land is on the mainnet, Tendermint2 will operate independently, including for governance,
+on https://github.com/tendermint/tendermint2.**
+
+## Problems
+
+* Open source is open for subversion.
+* Incentives and mission are misaligned.
+* Need directory & forum for Tendermint/SDK forks.
+
+## Partial Solution: adopt principles
+
+* Simplicity of design.
+* The code is the spec.
+* Minimal code - keep total footprint small.
+* Minimal dependencies - all dependencies must get audited, and become part of
+ the repo.
+* Modular dependencies - whereever reasonable, make components modular.
+* Completeness - software projects that don't become finished are projects
+ that are forever vulnerable. One of the primary goals of the Gno language
+ and related works is to become finished within a reasonable timeframe.
+
+## What is already proposed for Tendermint2:
+
+* Complete Amino. -> multiplier of productivity for SDK development, to not
+ have to think about protobuf at all. Use "genproto" to even auto-generate
+ proto3 for encoding/decoding optimization through protoc.
+ - MISSION: be the basis for improving the encoding standard from proto3, because
+ proto3 length-prefixing is slow, and we need "proto4" or "amino2".
+ - LOOK at the auto-generated proto files!
+ https://github.com/gnolang/gno/blob/master/pkgs/bft/consensus/types/cstypes.proto
+ for example.
+ - There was work to remove this from the CosmosSDK because
+ Amino wasn't ready, but now that it is, it makes sense to incorporate it into
+ Tendermint2.
+
+
+* Remove EvidenceReactor, Evidence, Violation:
+
+ We need to make it easy to create alt mempool reactors.
+
+ We "kill two birds with one stone" by implementing evidence as a first-class mempool lane.
+
+ The authors of "ABCI++" have a different set of problems to solve, so we should do both! Tendermint++
+ and Tendermint2.
+
+
+* Fix address size to 20 bytes -> 160 is sufficient, and fixing it brings optimizations.
+
+
+* General versionset system for handshake negotiation. -> So Tendermint2 can be
+ used as basis for other P2P applications.
+
+
+* EventBus -> EventSwitch. -> For indexing, use an external system.
+
+ To ensure Tendermint2 remains minimal and easily integrated with plugin modules, there is no internal implementation.
+
+ The use of an EventSwitch makes the process simpler and synchronous, which maintains the determinism of Tendermint
+ tests.
+
+ Keeping the Tendermint protocol synchronous is sufficient for optimal performance.
+
+ However, if there is a need for asynchronous processing due to an exceptionally large number of validators, it should
+ be a separate fork with a unique name under the same taxonomy as Tendermint.
+
+
+* Fix nondeterminism in consensus tests -> in relation to the above.
+
+* Add "MaxDataBytes" for total tx data size limitation.
+
+ To avoid unexpected behavior caused by changes in validator size, it's best to allocate room for each module
+ separately instead of limiting the total block size as we did before.
+
+This way, we can ensure that there's enough space for all modules.
+
+* Remove external dependencies like prometheus
+ To ensure accuracy, all metrics and events should be integrated through interfaces. This may require extracting client
+ logic from Prometheus, but it will be incorporated into Tendermint2 and undergo the same auditing process as
+ everything else.
+
+* General consensus/WAL -> a WAL is useful enough to warrant being a re-usable
+ module.
+
+* Remove GRPC -> GRPC support should be plugged in (say in a GRPC fork of
+ Tendermint2), so alternative RPC protocols can likewise be. Tendermint2 aims
+ to be independent of the Protobuf stack so that it can retain freedom for
+ improving its codec.
+
+* Remove dependency on viper/cobra -> I have tried to strip out what we don't
+ use of viper/cobra for minimalism, but could not; and viper/cobra is one
+ prime target for malware to be introduced. Rather than audit viper/cobra,
+ Tendermint2 implements a cli convention for Go-structure-based flags and cli;
+ so if you still want to use viper/cobra you can do so by translating flags to
+ an options struct.
+
+* Question: Which projects use ABCI sockets besides CosmosSDK derived chains?
+
+## Roadmap
+
+First, we create a multi-organizational team for Tendermint2 &
+TendermintCore/++ development. We will maintain a fork of the Tendermint++ repo
+and suggest changes upstream based on our work on Tendermint2, while also
+porting necessary fixes from Tendermint++ over to Tendermint2.
+
+We will also reach out to ecosystem partners and survey and create a
+directory/taxonomy for Tendermint and CosmosSDK derivatives and manage a forum
+for interfork collaboration.
+
+Ideally, Tendermint2 and TendermintCore/++ merge into one.
+
+## Challenge
+
+Either make a PR to Gaia/CosmosSDK/TendermintCore to be like Tendermint2, or
+make a PR to Tendermint2 to import a feature or fix of TendermintCore.
diff --git a/docs/getting-started/browsing-gno-source-code.md b/docs/getting-started/browsing-gno-source-code.md
new file mode 100644
index 00000000000..24e7c173f95
--- /dev/null
+++ b/docs/getting-started/browsing-gno-source-code.md
@@ -0,0 +1,96 @@
+---
+id: browsing-gno-source-code
+---
+
+# Browsing Gno Source Code
+
+## Overview
+
+In this tutorial, you will learn how to browse deployed Gno [Realms](../explanation/realms.md)
+and [Packages](../explanation/packages.md). Additionally, you will understand how the `Render` method is utilized
+to achieve Realm state visibility.
+
+## Prerequisites
+
+- **`gnoweb` set up. Reference the [Local Setup](local-setup.md#3-installing-other-gno-tools) guide for steps**
+
+## 1. Start the local chain
+
+In order for `gnoweb` to fetch realm and package source code, it needs to connect a running Gno node. For a better
+overview on running a local node, please reference the [Starting a Local Chain](setting-up-a-local-chain.md) guide.
+
+In this guide, we will start a local node with the default configuration. Navigate to the `gno.land` sub-folder and run:
+
+```bash
+gnoland start
+```
+
+## 2. Start `gnoweb`
+
+Now that the chain is running, we can start the `gnoweb` tool:
+
+```bash
+gnoweb
+```
+
+:::info Different JSON-RPC URL
+
+In case you are running a node on a different JSON-RPC URL from the default one (`http://127.0.0.1:26657`),
+you can specify the remote URL with the `gnoweb` flag named `--remote`
+
+:::
+
+We should be able to access the website locally on http://127.0.0.1:8888/.
+
+![gnoweb screen](../assets/getting-started/browsing-gno-source-code/gnoweb.png)
+
+## 3. Browse Package source code
+
+Packages in Gno.land usually have names resembling `gno.land/p/`. Since packages do not contain state, we can only
+view their source code on-chain. To learn more about Packages, please check out
+the [Packages](../explanation/packages.md) explanation document.
+
+Using `gnoweb`, we can browse the source code in our browser.
+For example, the `avl` package is deployed at `gno.land/p/demo/avl`.
+
+To access the source code of the `avl` package, we can append the `/p/demo/avl` to our browser URL (from the homepage).
+
+The final URL for the `avl` package source could be viewable at http://127.0.0.1:8888/p/demo/avl, if we followed
+default setup params, as we did in this guide.
+
+![gnoweb avl](../assets/getting-started/browsing-gno-source-code/gnoweb-avl.png)
+
+From here, we can open any source code file of the deployed on-chain package and inspect its API.
+
+## 4. Browse Realm source code
+
+In contrast to Packages, Realms in Gno.land usually have names resembling `gno.land/r/`.
+
+Realms _do_ contain state, and in addition to being able to view their source code on-chain, users can also view their
+internal state representation in the form of the `Render()` output. To learn more about Realms, please
+check out the [Realms](../explanation/realms.md) explanation document.
+
+Using `gnoweb`, we can browse the Realm `Render()` method output and source code in our browser.
+For example, the `boards` Realm is deployed at `gno.land/r/demo/boards`.
+
+To view the internal Realm state of the `boards` package, we can append the `/r/demo/boards` to our browser URL (from
+the homepage).
+
+The final URL for the `boards` Realm internal state could be viewable at http://127.0.0.1:8888/r/demo/boards, if we
+followed
+default setup params, as we did in this guide.
+
+![gnoweb boards](../assets/getting-started/browsing-gno-source-code/gnoweb-boards.png)
+
+:::info Render() is not required
+
+Internal Realm state does not have to be exposed through the `Render()` method of the realm, as it is
+not a requirement for deploying a Realm.
+
+:::
+
+Additionally, to view the source code for the realm, we simply need to append the `/` to the full realm path:
+
+http://127.0.0.1:8888/r/demo/boards/
+
+![gnoweb boards source](../assets/getting-started/browsing-gno-source-code/gnoweb-boards-source.png)
diff --git a/docs/getting-started/local-setup.md b/docs/getting-started/local-setup.md
new file mode 100644
index 00000000000..cbef4522477
--- /dev/null
+++ b/docs/getting-started/local-setup.md
@@ -0,0 +1,111 @@
+---
+id: local-setup
+---
+
+# Local Setup
+
+## Overview
+
+In this tutorial, you will learn how to set up the Gno development environment locally, so you
+can get up and running writing Gno code. You will download and install all the necessary tooling,
+and validate that they are correctly configured to run on your machine.
+
+## Prerequisites
+
+- **Git**
+- **`make` (for running Makefiles)**
+- **Go 19+**
+
+## 1. Cloning the repository
+
+To get started with a local Gno.land development environment, you must clone the GitHub repository
+somewhere on disk:
+
+```bash
+git clone https://github.com/gnolang/gno.git
+```
+
+## 2. Installing the `gno` development toolkit
+
+Next, we are going to build and install the `gno` development toolkit.
+`gno` provides ample functionality to the user, among which is running, precompiling, testing and building `.gno` files.
+
+To install the toolkit, navigate to the `gnovm` folder from the repository root, and run the `build` make directive:
+
+```bash
+cd gnovm
+make build
+```
+
+This will build out the necessary `gno` binary into the `gnovm/cmd` sub-folder:
+
+![gno tool build](../assets/getting-started/local-setup/make-build-gnovm.gif)
+
+Next, to make development easier, we need to make the binary available system-wide.
+From the same `gnovm` sub-folder, you can run:
+
+```bash
+make install
+```
+
+To verify the `gno` binary is installed system-wide, you can run:
+
+```bash
+gno --help
+```
+
+You should get the help output from the command:
+
+![gno help](../assets/getting-started/local-setup/gno-help.gif)
+
+Alternatively, if you don't want to have the binary callable system-wide, you can run the binary directly:
+
+```bash
+go run ./cmd/gno --help
+```
+
+## 3. Installing other `gno` tools
+
+The next step is to install several other tools that are required for the Gno development environment, like
+
+- `gnoland` - the Gno [blockchain node](setting-up-a-local-chain.md)
+- `gnokey` - the Gno [private key manager](working-with-key-pairs.md)
+- `gnoweb` - the Gno [source code viewer](browsing-gno-source-code.md)
+- `gnofaucet` - the Gno [native currency faucet](setting-up-funds/running-a-faucet.md)
+
+To build these tools, from the root directory navigate to the `gno.land` sub-folder, and run the `build` make
+directive:
+
+```bash
+cd gno.land
+make build
+```
+
+This will build out the necessary binaries into the `gno.land/cmd` sub-folder:
+
+![gno tools build](../assets/getting-started/local-setup/make-build-gnoland.gif)
+
+Same as with the `gno` tool, we can make these binaries available system-wide.
+From the same `gno.land` sub-folder, you can run:
+
+```bash
+make install
+```
+
+To verify that, for example, the `gnokey` binary is installed system-wide, you can run:
+
+```bash
+gnokey --help
+```
+
+You should get the help output from the command:
+
+![gnokey help](../assets/getting-started/local-setup/gnokey-help.gif)
+
+## Conclusion
+
+That's it 🎉
+
+You have successfully built out and installed the necessary tools for Gno development!
+
+In further documents, you will gain a better understanding on how they are used to make Gno work.
diff --git a/docs/getting-started/setting-up-a-local-chain.md b/docs/getting-started/setting-up-a-local-chain.md
new file mode 100644
index 00000000000..51fe1fd45a6
--- /dev/null
+++ b/docs/getting-started/setting-up-a-local-chain.md
@@ -0,0 +1,142 @@
+---
+id: setting-up-a-local-chain
+---
+
+# Setting up a Local Chain
+
+## Overview
+
+In this tutorial, you will learn how to start a local Gno node (and chain!).
+Additionally, you will see the different options you can use to make your Gno instance unique.
+
+## Prerequisites
+
+- [`gnoland` installed](local-setup.md#3-installing-other-gno-tools).
+
+## Starting a node with a default configuration
+
+You can start a Gno blockchain node with the default configuration by navigating to the `gno.land` sub-folder and
+running the following command:
+
+```bash
+gnoland start
+```
+
+The command will trigger a chain initialization process (if you haven't run the node before), and start the Gno node,
+which is ready to accept transactions and interact with other Gno nodes.
+
+![gnoland start](../assets/getting-started/setting-up-a-local-chain/gnoland-start.gif)
+
+To view the command defaults, simply run the `help` command:
+
+```bash
+gnoland start --help
+```
+
+Let's break down the most important default settings:
+
+- `chainid` - the ID of the Gno chain. This is used for Gno clients, and distinguishing the chain from other Gno
+ chains (ex. through IBC)
+- `config` - the custom node configuration file
+ for more details on utilizing this file
+- `genesis-balances-file` - the initial premine balances file, which contains initial native currency allocations for
+ the chain. By default, the genesis balances file is located in `gno.land/genesis/genesis_txs.txt`, this is also the
+ reason why we need to navigate to the `gno.land` sub-folder to run the command with default settings
+- `root-dir` - the working directory for the node configuration and node data (state DB)
+
+:::info Resetting the chain
+
+As mentioned, the working directory for the node is located in `root-dir`. To reset the chain, you need
+to delete this directory and start the node up again. If you are using the default node configuration, you can run
+`make fclean` from the `gno.land` sub-folder to delete the `tempdir` working directory.
+
+:::
+
+## Changing the chain ID
+
+:::info Changing the Gno chain ID has several implications
+
+- It affects how the Gno node communicates with other Gno nodes / chains
+- Gno clients that communicate through JSON-RPC need to match this value
+
+It's important to configure your node properly before launching it in a distributed network.
+Keep in mind that changes may not be applicable once connected.
+
+:::
+
+To change the Gno chain ID, run the following command:
+
+```bash
+gnoland start --chainid NewChainID
+```
+
+We can verify the chain ID has been changed, by fetching the status of the node and seeing the
+associated chain ID. By default, the node exposes the JSON-RPC API on `http://127.0.0.1:26657`:
+
+```bash
+curl -H "Content-type: application/json" -d '{
+ "jsonrpc": "2.0",
+ "method": "status",
+ "params": [],
+ "id": 1
+}' 'http://127.0.0.1:26657'
+```
+
+We should get a response similar to this:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 1,
+ "result": {
+ "node_info": {
+ "version_set": [
+ // ...
+ ],
+ "net_address": "g10g9r37g9xa54a6clttzmhk2gmdkzsntzty0cvr@0.0.0.0:26656",
+ "network": "NewChainID"
+ // ...
+ }
+ }
+}
+```
+
+:::danger Chain ID can be set only once
+
+Since the chain ID information is something bound to a chain, you can
+only change it once upon chain initialization, and further attempts to change it will
+have no effect.
+
+:::
+
+## Changing the node configuration
+
+You can specify a node configuration file using the `--config` flag.
+
+```bash
+gnoland start --config config.toml
+```
+
+## Changing the premine list
+
+You do not need to use the `gno.land/genesis/genesis_balances.txt` file as the source of truth for initial network
+funds.
+
+To specify a custom balance sheet for a fresh local chain, you can use the `-genesis-balances-file`:
+
+```bash
+gnoland start -genesis-balances-file custom-balances.txt
+```
+
+Make sure the balances file follows the following format:
+
+```text
+=ugnot
+```
+
+Following this pattern, potential entries into the genesis balances file would look like:
+
+```text
+g1qpymzwx4l4cy6cerdyajp9ksvjsf20rk5y9rtt=10000000000ugnot
+g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq=10000000000ugnot
+```
diff --git a/docs/getting-started/setting-up-funds/premining-balances.md b/docs/getting-started/setting-up-funds/premining-balances.md
new file mode 100644
index 00000000000..00076cdfda1
--- /dev/null
+++ b/docs/getting-started/setting-up-funds/premining-balances.md
@@ -0,0 +1,106 @@
+---
+id: premining-balances
+---
+
+# Premining Balances
+
+## Overview
+
+In this tutorial, you will gain an understanding on how to premine native currency on a local Gno.land chain.
+Additionally, you will understand how to query the account balance after you premine it.
+
+Premining balance is the process of making sure some accounts (addresses) have specific funds when the chain initially
+launches. In the context of local chain deployments, premine balances are used to ensure the user accounts (developers)
+have ample funds to interact with the chain and facilitate contract deployments.
+
+## Prerequisites
+
+- **`gnoland` and `gnokey` set up. Reference the [Installation](../local-setup.md#3-installing-other-gno-tools) guide
+ for steps**
+
+## 1. Clean chain data
+
+In order for us to premine funds on a fresh chain, we need to make sure we do not have any leftover blockchain data
+from previous chain runs.
+
+The blockchain node, when it runs, works with an embedded DB locally on disk to store execution data (such as
+configuration files, or the state DB). For Gno blockchain nodes, this working directory is labeled as `testdir` by
+default.
+
+To clean out old blockchain data, navigate to the `gno.land` folder and run the appropriate make command:
+
+```bash
+cd gno.land
+make fclean
+```
+
+## 2. Change the `genesis_balances.txt` file
+
+When the Gno node boots up, among other things, it reads a file called `genesis_balances.txt` to generate the initial
+balance set for the blockchain.
+
+An example of how this looks like in the initial `genesis.json` file after the chain starts:
+
+```bash
+ "app_state": {
+ "@type": "/gno.GenesisState",
+ "balances": [
+ "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5=10000000000000ugnot",
+ "g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj=10000000000000ugnot",
+ "g1f4v282mwyhu29afke4vq5r2xzcm6z3ftnugcnv=1000000000000ugnot",
+ "g127jydsh6cms3lrtdenydxsckh23a8d6emqcvfa=1000000000000ugnot"
+ ],
+```
+
+The `genesis_balances.txt` file is located at `./gno.land/genesis/genesis_balances.txt`.
+
+To add a new entry to the premine table, simply append a line to the end of the file:
+
+```bash
+g1qpymzwx4l4cy6cerdyajp9ksvjsf20rk5y9rtt=10000000000ugnot # My address
+```
+
+Replace `g1qpymzwx4l4cy6cerdyajp9ksvjsf20rk5y9rtt` with the address you want balance on, and `10000000000ugnot` with the
+desired `ugnot` balance.
+
+## 3. Start the local chain
+
+Now that our address and the desired premine balance are located in the `genesis_balances.txt` file, we can start the
+local Gno node.
+
+To run the local Gno node, make sure you are in the `gno.land` sub-folder, and run the appropriate make command:
+
+```bash
+cd gno.land
+gnoland start
+```
+
+This command will initialize the Gno node, generate the `genesis.json` with our newly added premine information, and
+start the chain.
+
+![gnoland start](../../assets/getting-started/setting-up-funds/gnoland-start.gif)
+
+## 3. Check the account balance
+
+To check the balance of any account (or the account we just premined), we can use the following ABCI query:
+
+```bash
+gnokey query --remote localhost:26657 bank/balances/g1qpymzwx4l4cy6cerdyajp9ksvjsf20rk5y9rtt
+```
+
+Let's break down this command:
+
+- **`--remote`** - the JSON-RPC URL of the running Gno node. In the case of a local deployment, the default value
+ is `localhost:26657`
+- **`bank/balances/g1qpymzwx4l4cy6cerdyajp9ksvjsf20rk5y9rtt`** - the ABCI query targets the `bank` module to find
+ the `balances` for address `g1qpymzwx4l4cy6cerdyajp9ksvjsf20rk5y9rtt`. Replace the address with your desired address
+
+![gnokey query](../../assets/getting-started/setting-up-funds/gnokey-query.gif)
+
+## Conclusion
+
+That's it 🎉
+
+You have successfully premined a native currency balance on a locally-running Gno chain!
+Additionally, you have also learned how to query the native currency balance for an address, using built-in ABCI queries
+and the `gnokey` tool.
diff --git a/docs/getting-started/setting-up-funds/running-a-faucet.md b/docs/getting-started/setting-up-funds/running-a-faucet.md
new file mode 100644
index 00000000000..3bd0e55b791
--- /dev/null
+++ b/docs/getting-started/setting-up-funds/running-a-faucet.md
@@ -0,0 +1,100 @@
+---
+id: running-a-faucet
+---
+
+# Running a Faucet
+
+## Overview
+
+In this tutorial, we will cover how to run a local native currency faucet that works seamlessly with a Gno node.
+Using the faucet, any address can get a hold of native currency funds in case they
+haven't [premined a balance beforehand](premining-balances.md).
+
+## Prerequisites
+
+- **`gnoland`, `gnofaucet` and `gnoweb` set up. Reference
+ the [Installation](../local-setup.md#3-installing-other-gno-tools) guide for steps**
+
+## 1. Ensure a topped-up faucet address
+
+The Gno faucet works by designating a single address as a faucet address that will distribute funds.
+
+Ensure the faucet account will have enough funds by [premining its balance](premining-balances.md) to a high value.
+In case you do not have an existing address added to `gnokey`, you can consult
+the [Working with Key Pairs](../working-with-key-pairs.md) guide.
+
+## 2. Start the local chain
+
+After ensuring the faucet address will have enough funds in the premine, we
+can [run the local blockchain node](../setting-up-a-local-chain.md).
+Navigate to the `gno.land` sub-folder and run the appropriate make command:
+
+```bash
+cd gno.land
+gnoland start
+```
+
+## 3. Start the faucet
+
+After the chain is up and running locally, you can start the faucet by running the following command:
+
+```bash
+gnofaucet serve --chain-id dev MyKey
+```
+
+The command will prompt you to enter the decryption password for the key you've provided.
+
+- **`--chain-id`** - the chain ID of the local running node. The default value is `dev`
+- **`MyKey`** - the name of the faucet key (you can also use the address) we premined in
+ the [previous steps](#1-ensure-a-topped-up-faucet-address)
+
+This will initialize the faucet to listen on port `5050`, by default.
+
+![gnofaucet serve](../../assets/getting-started/setting-up-funds/gnofaucet-serve.gif)
+
+## 4. Start the `gnoweb` interface
+
+To access the faucet UI, we need to start the local `gnoweb` interface.
+
+Navigate to the `gno.land` subfolder, and run the appropriate binary:
+
+```bash
+cd gno.land
+gnoweb
+```
+
+This will initialize the `gnoweb` interface on `http://127.0.0.1:8888`.
+
+![gnoweb](../../assets/getting-started/setting-up-funds/gnoweb.gif)
+
+## 5. Use the deployed faucet
+
+Once `gnoweb` has been started, you can navigate to http://127.0.0.1:8888/faucet.
+
+Simply input the desired address you wish to receive funds on (`1 GNOT` by default), and press the `GO` button.
+
+![gnofaucet page](../../assets/getting-started/setting-up-funds/faucet-page.png)
+
+After you've added the address, you should see a success message in the browser:
+
+```
+faucet success
+```
+
+In the terminal where `gnofaucet` is running, you should see a success message as well, something along the lines of:
+
+```bash
+will deliver: {"msg":[{"@type":"/bank.MsgSend","from_address":"g155n659f89cfak0zgy575yqma64sm4tv6exqk99","to_address":"g1qpymzwx4l4cy6cerdyajp9ksvjsf20rk5y9rtt","amount":"1000000ugnot"}],"fee":{"gas_wanted":"50000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A10ufcOV5WP71K+KvLagJi+3TSCkx8EWKep3NbjVclU8"},"signature":"7Y0hkdPBruzMiANAHXWx3luAMhQN6SF3AQtstvOSZJI5P4uep8RIntw2c8W5blFiCd9HoMiEZFNf5dgWYwkjmA=="}],"memo":""}
+
+OK!
+GAS WANTED: 50000
+GAS USED: 41971
+127.0.0.1 faucet success
+```
+
+## Conclusion
+
+That's it 🎉
+
+You have successfully set up a GNOT faucet on a locally-running Gno chain!
+Additionally, you have also learned how to utilize the `gnoweb` tool for a visual faucet UI.
diff --git a/docs/getting-started/working-with-key-pairs.md b/docs/getting-started/working-with-key-pairs.md
new file mode 100644
index 00000000000..5617e8339eb
--- /dev/null
+++ b/docs/getting-started/working-with-key-pairs.md
@@ -0,0 +1,191 @@
+---
+id: working-with-key-pairs
+---
+
+# Working with Key Pairs
+
+## Overview
+
+In this tutorial, you will learn how to manage private user keys, which are required for interacting with the Gno.land
+blockchain. You will understand what mnemonics are, how they are used, and how you can make interaction seamless with
+Gno.
+
+## Prerequisites
+
+- **`gnokey` set up. Reference the [Local Setup](local-setup.md#3-installing-other-gno-tools) guide for steps**
+
+## Listing available keys
+
+`gnokey` works by creating a local directory in the filesystem for storing (encrypted!) user private keys.
+
+You can find this repository by checking the value of the `--home` flag when running the following command:
+
+```bash
+gnokey --help
+```
+
+Example output:
+
+```bash
+USAGE
+ [flags] [...]
+
+Manages private keys for the node
+
+SUBCOMMANDS
+ add Adds key to the keybase
+ delete Deletes a key from the keybase
+ generate Generates a bip39 mnemonic
+ export Exports private key armor
+ import Imports encrypted private key armor
+ list Lists all keys in the keybase
+ sign Signs the document
+ verify Verifies the document signature
+ query Makes an ABCI query
+ broadcast Broadcasts a signed document
+ maketx Composes a tx document to sign
+
+FLAGS
+ -config ... config file (optional)
+ -home $XDG_CONFIG/gno home directory
+ -insecure-password-stdin=false WARNING! take password from stdin
+ -quiet=false suppress output during execution
+ -remote 127.0.0.1:26657 remote node URL
+
+error parsing commandline arguments: flag: help requested
+```
+
+In this example, the directory where `gnokey` will store working data
+is `/Users/zmilos/Library/Application Support/gno`.
+
+Keep note of this directory, in case you need to reset the keystore, or migrate it for some reason.
+You can provide a specific `gnokey` working directory using the `--home` flag.
+
+To list keys currently present in the keystore, we can run:
+
+```bash
+gnokey list
+```
+
+In case there are no keys present in the keystore, the command will simply return an empty response.
+Otherwise, it will return the list of keys and their accompanying metadata as a list, for example:
+
+```bash
+0. Manfred (local) - addr: g15uk9d6feap7z078ttcnwc94k60ullrvhmynxjt pub: gpub1pgfj7ard9eg82cjtv4u4xetrwqer2dntxyfzxz3pqvn87u43scec4zfgn4la3nt237nehzydzayqxe43fx63lq6rty9c5almet4, path:
+1. Milos (local) - addr: g15lppu0tuxets0c0t80tncs4enqzgxt7v4eftcj pub: gpub1pgfj7ard9eg82cjtv4u4xetrwqer2dntxyfzxz3pqw2kkzujprgrfg7vumg85mccsf790n5ep6htpygkuwedwuumf2g7ydm4vqf, path:
+```
+
+The key response consists of a few pieces of information:
+
+- The name of the private key
+- The derived address (`addr`)
+- The public key (`pub`)
+
+Using these pieces of information, we can interact with Gno.land tools and write blockchain applications.
+
+## Generating a BIP39 mnemonic
+
+Using `gnokey`, we can generate a [mnemonic phrase](https://en.bitcoin.it/wiki/Seed_phrase) based on
+the [BIP39 standard](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki).
+
+To generate the mnemonic phrase in the console, you can run:
+
+```bash
+gnokey generate
+```
+
+![gnokey generate](../assets/getting-started/creating-a-key-pair/gnokey-generate.gif)
+
+## Adding a random private key
+
+If we wanted to add a new private key to the keystore, we can run the following command:
+
+```bash
+gnokey add MyKey
+```
+
+Of course, you can replace `MyKey` with whatever name you want for your key.
+
+The `gnokey` tool will prompt you to enter a password to encrypt the key on disk (don't forget this!).
+After you enter the password, the `gnokey` tool will add the key to the keystore, and return the accompanying [mnemonic
+phrase](https://en.bitcoin.it/wiki/Seed_phrase), which you should remember somewhere if you want to recover the key at a
+future point in time.
+
+![gnokey add random](../assets/getting-started/creating-a-key-pair/gnokey-add-random.gif)
+
+You can check that the key was indeed added to the keystore, by listing available keys:
+
+```bash
+gnokey list
+```
+
+![gnokey list](../assets/getting-started/creating-a-key-pair/gnokey-list.gif)
+
+## Adding a private key using a mnemonic
+
+To add a private key to the `gnokey` keystore [using an existing mnemonic](#generating-a-bip39-mnemonic), we can run the
+following command with the
+`--recover` flag:
+
+```bash
+gnokey add --recover MyKey
+```
+
+Of course, you can replace `MyKey` with whatever name you want for your key.
+
+By following the prompts to encrypt the key on disk, and providing a BIP39 mnemonic, we can successfully add
+the key to the keystore.
+
+![gnokey add mnemonic](../assets/getting-started/creating-a-key-pair/gnokey-add-mnemonic.gif)
+
+## Deleting a private key
+
+To delete a private key from the `gnokey` keystore, we need to know the name or address of the key to remove.
+After we have this information, we can run the following command:
+
+```bash
+gnokey delete MyKey
+```
+
+After entering the key decryption password, the key will be deleted from the keystore.
+
+:::caution Recovering a private key
+In case you delete or lose access to your private key in the `gnokey` keystore, you
+can recover it using the key's mnemonic, or by importing it if it was exported at a previous point in time.
+:::
+
+## Exporting a private key
+
+Private keys stored in the `gnokey` keystore can be exported to a desired place
+on the user's filesystem.
+
+Keys are exported in their original armor, encrypted or unencrypted.
+
+To export a key from the keystore, you can run:
+
+```bash
+gnokey export -key MyKey -output-path ~/Work/gno-key.asc
+```
+
+Follow the prompts presented in the terminal. Namely, you will be asked to decrypt the key in the keystore,
+and later to encrypt the armor file on disk. It is worth noting that you can also export unencrypted key armor, using
+the `--unsafe` flag.
+
+![gnokey export](../assets/getting-started/creating-a-key-pair/gnokey-export.gif)
+
+## Importing a private key
+
+If you have an exported private key file, you can import it into `gnokey` fairly easily.
+
+For example, if the key is exported at `~/Work/gno-key.asc`, you can run the following command:
+
+```bash
+gnokey import -armor-path ~/Work/gno-key.asc -name ImportedKey
+```
+
+You will be asked to decrypt the encrypted private key armor on disk (if it is encrypted, if not, use the `--unsafe`
+flag), and then to provide an encryption password for storing the key in the keystore.
+
+After executing the previous command, the `gnokey` keystore will have imported `ImportedKey`.
+
+![gnokey import](../assets/getting-started/creating-a-key-pair/gnokey-import.gif)
diff --git a/docs/go-gno-compatibility.md b/docs/go-gno-compatibility.md
deleted file mode 120000
index a15871f0340..00000000000
--- a/docs/go-gno-compatibility.md
+++ /dev/null
@@ -1 +0,0 @@
-../gnovm/docs/go-gno-compatibility.md
\ No newline at end of file
diff --git a/docs/how-to-guides/connect-wallet-dapp.md b/docs/how-to-guides/connect-wallet-dapp.md
new file mode 100644
index 00000000000..294323b5560
--- /dev/null
+++ b/docs/how-to-guides/connect-wallet-dapp.md
@@ -0,0 +1,115 @@
+---
+id: connect-wallet-dapp
+---
+
+# How to connect a wallet to a dApp
+
+As a dapp developer, you must integrate a web3 wallet with your application to enable users to interact with your
+application. Upon integration, you may retrieve account information of the connected user or request to sign & send
+transactions from the user's account.
+
+:::warning Wallets on gno.land
+
+Here is a list of available wallets for Gnoland.
+Note that none of these wallets are official or exclusive, so please
+use them at your own diligence:
+
+- [Adena Wallet](https://adena.app/)
+
+:::
+
+## Adena Wallet
+
+[Adena](https://adena.app/) is a web extension wallet that supports the Gnoland blockchain. Below is the basic Adena
+APIs that you can use for your application. For more detailed information, check out
+Adena's [developer's docs](https://docs.adena.app/) to integrate Adena to your application.
+
+### Adena Connect For React App
+
+Check if Adena wallet exists.
+
+```javascript
+// checks the existence of the adena object in window
+
+const existsWallet = () => {
+ if (window.adena) {
+ return true;
+ }
+ return false;
+};
+
+```
+
+Register your website as a trusted domain.
+
+```javascript
+// calls the AddEstablish of the adena object
+
+const addEstablish = (siteName) => {
+ return window?.adena?.AddEstablish(siteName);
+};
+
+```
+
+Retrieve information about the connected account.
+
+```javascript
+// calls the GetAccount function of the adena object
+
+const getAccount = () => {
+ return window.adena?.GetAccount();
+};
+
+```
+
+Request approval of a transaction that transfers tokens.
+
+```javascript
+// Execute the DoContract function of the adena object to request transaction.
+
+const sendToken = (fromAddress, toAddress, sendAmount) => {
+ const message = {
+ type: "/bank.MsgSend",
+ value: {
+ from_address: fromAddress,
+ to_address: toAddress,
+ amount: sendAmount
+ }
+ };
+
+ return window.adena?.DoContract({
+ messages: [message],
+ gasFee: 1,
+ gasWanted: 3000000
+ });
+};
+
+```
+
+Request approval of a transaction that calls a function from a realm.
+
+```javascript
+// Execute the DoContract function of the adena object to request transaction.
+
+const doContractPackageFunction = (caller, func, pkgPath, argument) => {
+
+ // Setup Transaction Message
+ const message = {
+ type: "/vm.m_call",
+ value: {
+ caller,
+ func,
+ send: "",
+ pkg_path: pkgPath,
+ args: argument.split(',')
+ }
+ };
+
+ // Request Transaction
+ return window.adena?.DoContract({
+ messages: [message],
+ gasFee: 1,
+ gasWanted: 3000000
+ });
+};
+```
diff --git a/docs/how-to-guides/creating-grc20.md b/docs/how-to-guides/creating-grc20.md
new file mode 100644
index 00000000000..d91499afb39
--- /dev/null
+++ b/docs/how-to-guides/creating-grc20.md
@@ -0,0 +1,164 @@
+---
+id: creating-grc20
+---
+
+# How to create a GRC20 Token
+
+## Overview
+
+This guide shows you how to write a simple _GRC20_ Smart Contract, or rather a [Realm](../explanation/realms.md), in [Gno (Gnolang)](../explanation/gno-language.md). For actually deploying the Realm, please see the [deployment](deploy.md) guide.
+
+Our _GRC20_ Realm will have the following functionality:
+
+- Minting a configurable amount of token.
+- Keeping track of total token supply.
+- Fetching the balance of an account.
+
+## Prerequisites
+
+We will proceed using the typical directory structure for a Realm found within the [simple-contract guide](simple-contract.md). It is also worthwhile to consult the [GRC20 interface](../../examples/gno.land/p/demo/grc/grc20/igrc20.gno) which we will be importing and utilizing within this guide.
+
+## 1. Importing token package
+For this realm, we'll want to import the `grc20` package as this will include the main functionality of our token factory realm.
+
+[embedmd]:# (../assets/how-to-guides/creating-grc20/mytoken-1.gno go)
+```go
+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)
+}
+```
+
+In this code preview, we have:
+- Defined a new local variable `mytoken` and assigned that the type of pointer to `grc20.AdminToken`.
+- Defined and set the value of local variable `admin` to point to a specific gno.land address of type `std.Address`.
+- Set the value of `mytoken` (type `*AdminToken`) to equal the result of creating a new token and configuring its name, symbol + decimal representation.
+- Minted 1 million `Mytoken` and set the administrator as the owner of these tokens.
+
+## 2. Adding token functionality
+
+The following section will be about introducing Public functions to expose functionality imported from the [grc20 package](../../examples/gno.land/p/demo/grc/grc20).
+
+[embedmd]:# (../assets/how-to-guides/creating-grc20/mytoken-2.gno go)
+```go
+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")
+ }
+}
+```
+
+Detailing what is happening in the above code:
+- Calling the `TotalSupply` method would return the total number of tokens minted.
+- Calling the `BalanceOf` method would return the total balance of an account.
+- Calling the `Allowance` method would set an account as an allowed spender to serve on behalf of the owner.
+- Calling the `transfer` method would transfer a configurable amount of token from the calling account to another account, either owned or unowned.
+- Calling the `Approve` method would approve a calling account to spend a configurable amount of token on behalf of the token owner.
+- Calling the `TransferFrom` method would transfer a configurable amount of token from an account that granted approval to another account, either owned or unowned.
+- Calling the `Mint` method would create a configurable number of tokens by the administrator.
+- Calling the `Burn` method would destroy a configurable number of tokens by the administrator.
+- Calling the `Render` method would return a user's `balance` as a formatted string. Learn more about the `Render`
+ method and how it's used [here](../explanation/realms.md).
+- Finally, we provide a local function to assert that the calling account is in fact the owner, otherwise panic. This is a very important function that serves to prevent abuse by non-administrators.
+
+## Conclusion
+
+That's it 🎉
+
+You have successfully built a simple GRC20 Realm that is ready to be deployed on the Gno chain and called by users.
+In the upcoming guides, we will see how we can develop more complex Realm logic and have them interact with outside tools like a wallet application.
diff --git a/docs/how-to-guides/creating-grc721.md b/docs/how-to-guides/creating-grc721.md
new file mode 100644
index 00000000000..afaa2da0ef3
--- /dev/null
+++ b/docs/how-to-guides/creating-grc721.md
@@ -0,0 +1,199 @@
+---
+id: creating-grc721
+---
+
+# How to create a GRC721 Token (NFT)
+
+## Overview
+
+This guide shows you how to write a simple _GRC721_ Smart Contract, or rather a [Realm](../explanation/realms.md),
+in [Gno (Gnolang)](../explanation/gno-language.md). For actually deploying the Realm, please see
+the [deployment](deploy.md) guide.
+
+Our _GRC721_ Realm will have the following functionality:
+
+- Minting a configurable amount of token.
+- Keeping track of total token supply.
+- Fetching the balance of an account.
+
+## Prerequisites
+
+We will proceed using the typical directory structure for a Realm found within
+the [simple-contract guide](simple-contract.md). It is also worthwhile to consult
+the [GRC721 interface](../../examples/gno.land/p/demo/grc/grc721/igrc721.gno) which we will be borrowing from within
+this guide.
+
+## 1. Importing token package
+
+For this realm, we'll want to import the `grc20` package as this will include the main functionality of our token
+factory realm.
+
+[embedmd]:# (../assets/how-to-guides/creating-grc721/mynonfungibletoken-1.gno go)
+```go
+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)
+}
+```
+
+In this code preview, we have:
+
+- Defined and set the value of `mynonfungibletoken` (type `*grc721.basicNFT`) to equal the result of creating a new
+ token and configuring its name and symbol.
+- Defined and set the value of local variable `admin` to point to a specific gno.land address of type `std.Address`.
+- Minted 5 `mynonfungibletoken (MNFT)` and set the administrator as the owner of these tokens
+
+## 2. Adding token functionality
+
+The following section will be about introducing Public functions to expose functionality imported from
+the [grc721 package](../../examples/gno.land/p/demo/grc/grc721).
+
+[embedmd]:# (../assets/how-to-guides/creating-grc721/mynonfungibletoken-2.gno go)
+```go
+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")
+ }
+}
+```
+
+Detailing what is happening in the above code:
+
+- Calling the **local** `mintNNFT` method would mint a configurable number of tokens to the provided owner's account.
+- Calling the `BalanceOf` method would return the total balance of an account.
+- Calling the `OwnerOf` method would return the owner of the token based on the ID that is passed into the method.
+- Calling the `IsApprovedByAll` method will return true if an operator is approved for all operations by the owner;
+ otherwise, returns false.
+- Calling the `GetApproved` method will return the address approved to operate on the token.
+- Calling the `Approve` method would approve the input address for a particular token.
+- Calling the `SetApprovalForAll` method would approve an operating account to operate on all tokens.
+- Calling the `TransferFrom` method would transfer a configurable amount of token from an account that granted approval
+ to another account, either owned or unowned.
+- Calling the `Mint` method would create a configurable number of tokens by the administrator.
+- Calling the `Burn` method would destroy a configurable number of tokens by the administrator.
+- Calling the `Render` method on success would invoke
+ a [`RenderHome`](https://github.com/gnolang/gno/blob/master/examples/gno.land/p/demo/grc/grc721/basic_nft.gno#L353)
+ method on the `grc721` instance we instantiated at the top of the file; this method returns a formatted string that
+ includes the token: symbol, supply and account balances (`balances avl.Tree`) which is a mapping denoted
+ as: `OwnerAddress -> TokenCount`; otherwise returns false and renders a `404`; you can find more information about
+ this `Render` method and how it's used [here](../explanation/realms.md).
+- Finally, we provide a local function to assert that the calling account is in fact the owner, otherwise panic. This is
+ a very important function that serves to prevent abuse by non-administrators.
+
+## Conclusion
+
+That's it 🎉
+
+You have successfully built a simple GRC721 Realm that is ready to be deployed on the Gno chain and called by users.
+In the upcoming guides, we will see how we can develop more complex Realm logic and have them interact with outside
+tools like a wallet application.
diff --git a/docs/how-to-guides/deploy.md b/docs/how-to-guides/deploy.md
new file mode 100644
index 00000000000..ab31716f014
--- /dev/null
+++ b/docs/how-to-guides/deploy.md
@@ -0,0 +1,74 @@
+---
+id: deploy
+---
+
+# How to deploy a Realm / Package
+
+## Overview
+
+This guide shows you how to deploy any realm or package to the Gno chain. Deployment is be done by utilizing `gnokey`'s `maketx addpkg` API.
+
+:::info
+Regardless of whether you're deploying a realm or a package, you will be using `gnokey`'s `maketx addpkg` - the usage of `maketx addpkg` in both cases is identical.
+:::
+
+## Prerequisites
+
+- **Have `gnokey` installed**
+- **Have access to a `gnoland` node (local or remote)**
+- **Have generated a keypair with `gnokey` & funded it with `gnot`**
+- **Have a Realm or Package ready to deploy**
+
+## Deploying
+
+To illustrate deployment, we will use a realm. Consider the following folder structure:
+
+```
+counter-app/
+├─ r/
+│ ├─ counter/
+│ │ ├─ counter.gno
+```
+
+We would like to deploy the realm found in `counter.gno`. To do this, open a terminal at `counter-app/` and use the following `gnokey` command:
+
+```bash
+gnokey maketx addpkg \
+--pkgpath "gno.land/r/demo/counter" \
+--pkgdir "./r/counter" \
+--gas-fee 10000000ugnot \
+--gas-wanted 800000 \
+--broadcast \
+--chainid dev \
+--remote localhost:26657 \
+MyKey
+```
+
+Let's analyze all of the flags in detail:
+- `--pkgpath` - path where the package/realm will be placed on-chain
+- `--pkgdir` - local path where the package/realm is located
+- `--gas-wanted` - the upper limit for units of gas for the execution of the transaction - similar to Solidity's gas limit
+- `--gas-fee` - similar to Solidity's gas-price
+- `--broadcast` - broadcast the transaction on-chain
+- `--chain-id` - id of the chain to connect to - local or remote
+- `--remote` - `gnoland` node endpoint - local or remote
+- `MyKey` - the keypair to use for the transaction
+
+:::info
+As of October 2023, `--gas-fee` is fixed to 1gnot (10000000ugnot), with plans to change it down the line.
+:::
+
+Next, confirm the transaction with your keypair passphrase. If deployment was successful, you will be presented with a message similar to the following:
+
+```
+OK!
+GAS WANTED: 800000
+GAS USED: 775097
+```
+Depending on the size of the package/realm, you might need to increase amount given in the `--gas-wanted` flag to cover the deployment cost.
+
+## Conclusion
+
+That's it 🎉
+
+You have now successfully deployed a realm/package to a Gno.land chain.
diff --git a/docs/how-to-guides/interact-with-gnoland.md b/docs/how-to-guides/interact-with-gnoland.md
new file mode 100644
index 00000000000..dacfead2957
--- /dev/null
+++ b/docs/how-to-guides/interact-with-gnoland.md
@@ -0,0 +1,94 @@
+---
+id: interact-with-gnoland
+---
+
+# Interact with Gno.land
+
+This tutorial will teach you how to interact with the gno.land blockchain by creating an account and calling various realms to send transactions on the network.
+
+## Prerequisites
+
+- [Installation](../getting-started/local-setup.md)
+
+## Create an Account
+
+In order to interact with Gnoland, you need an account that you will use to sign and send transactions. You may create a new account with `gnokey generate` or recover an existing one with `gnokey add`. Confirm that your account was successfully added with `gnokey list` to display all accounts registered in the key base of your device.
+
+```bash
+gnokey generate # create a new seed phrase (mnemonic)
+
+gnokey add -recover {your_account_name} # registers a key with the name set as the value you put in {your_account_name} with a seed phrase
+
+gnokey list # check the list of keys
+```
+
+## Register As a User
+
+```bash
+gnokey maketx call \
+ -gas-fee="1ugnot" \
+ -gas-wanted="5000000" \
+ -broadcast="true" \
+ -remote="staging.gno.land:36657" \
+ -chainid="test3" \
+ -pkgpath="gno.land/r/demo/users" \
+ -func="Register" \
+ -args="" \
+ -args="my_account" \ # (must be at least 6 characters, lowercase alphanumeric with underscore)
+ -args="" \
+ -send="200000000ugnot" \
+ my-account
+
+# username: must be at least 6 characters, lowercase alphanumeric with underscore
+```
+
+> **Note:** With a user registration fee of 200 GNOT and a gas fee that ranges up to 2 GNOT, you must have around 202 GNOT to complete this transaction. After registering as a user, you may replace your address with your `username` when developing or publishing a realm package.
+
+## Get Account Information
+
+```bash
+# Get account information
+gnokey query -remote="staging.gno.land:36657" "auth/accounts/{address}"
+
+# Get account balance
+gnokey query -remote="staging.gno.land:36657" "bank/balances/{address}"
+
+# Get /r/demo/boards user information
+gnokey query -remote="staging.gno.land:36657" -data "gno.land/r/demo/users
+my_account" "vm/qrender"
+```
+
+## Send Tokens
+
+The following command will send 1,000,000 ugnot (= 1 GNOT) to the address specified in the `to` argument.
+
+```bash
+# Creates and broadcast a token transfer transaction
+gnokey maketx send \
+ -gas-fee="1ugnot" \
+ -gas-wanted="5000000" \
+ -broadcast="true" \
+ -remote="staging.gno.land:36657" \
+ -chainid="test3" \
+ -to="{address}" \ # g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5
+ -send="{amount}{denom}" \ # 1234ugnot
+ my-account
+```
+
+## Create a Board
+
+Try creating a board called `my_board` on the `gno.land/r/demo/boards` realm with the following command:
+
+```bash
+# Calls the CreateBoard function of gno.land/r/demo/boards
+gnokey maketx call \
+ -gas-fee="1ugnot" \
+ -gas-wanted="5000000" \
+ -broadcast="true" \
+ -remote "staging.gno.land:36657" \
+ -chainid="test3" \
+ -pkgpath="gno.land/r/demo/boards" \
+ -func="CreateBoard" \
+ -args="my_board" \
+ my-account
+```
diff --git a/docs/how-to-guides/porting-solidity-to-gno.md b/docs/how-to-guides/porting-solidity-to-gno.md
new file mode 100644
index 00000000000..39c6910eda6
--- /dev/null
+++ b/docs/how-to-guides/porting-solidity-to-gno.md
@@ -0,0 +1,680 @@
+---
+id: port-solidity-to-gno
+---
+
+# Port a Solidity Contract to a Gnolang Realm
+
+
+## Overview
+
+This guide shows you how to port a Solidity contract `Simple Auction` to a Gnolang Realm `auction.gno` with test cases (Test Driven Development (TDD) approach).
+
+You can check the Solidity contract in this [link](https://docs.soliditylang.org/en/latest/solidity-by-example.html#simple-open-auction), and here's the code for porting.
+
+```solidity
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity ^0.8.4;
+contract SimpleAuction {
+ // Parameters of the auction. Times are either
+ // absolute unix timestamps (seconds since 1970-01-01)
+ // or time periods in seconds.
+ address payable public beneficiary;
+ uint public auctionEndTime;
+
+ // Current state of the auction.
+ address public highestBidder;
+ uint public highestBid;
+
+ // Allowed withdrawals of previous bids
+ mapping(address => uint) pendingReturns;
+
+ // Set to true at the end, disallows any change.
+ // By default initialized to `false`.
+ bool ended;
+
+ // Events that will be emitted on changes.
+ event HighestBidIncreased(address bidder, uint amount);
+ event AuctionEnded(address winner, uint amount);
+
+ // Errors that describe failures.
+
+ // The triple-slash comments are so-called natspec
+ // comments. They will be shown when the user
+ // is asked to confirm a transaction or
+ // when an error is displayed.
+
+ /// The auction has already ended.
+ error AuctionAlreadyEnded();
+ /// There is already a higher or equal bid.
+ error BidNotHighEnough(uint highestBid);
+ /// The auction has not ended yet.
+ error AuctionNotYetEnded();
+ /// The function auctionEnd has already been called.
+ error AuctionEndAlreadyCalled();
+
+ /// Create a simple auction with `biddingTime`
+ /// seconds bidding time on behalf of the
+ /// beneficiary address `beneficiaryAddress`.
+ constructor(
+ uint biddingTime,
+ address payable beneficiaryAddress
+ ) {
+ beneficiary = beneficiaryAddress;
+ auctionEndTime = block.timestamp + biddingTime;
+ }
+
+ /// Bid on the auction with the value sent
+ /// together with this transaction.
+ /// The value will only be refunded if the
+ /// auction is not won.
+ function bid() external payable {
+ // No arguments are necessary, all
+ // information is already part of
+ // the transaction. The keyword payable
+ // is required for the function to
+ // be able to receive Ether.
+
+ // Revert the call if the bidding
+ // period is over.
+ if (block.timestamp > auctionEndTime)
+ revert AuctionAlreadyEnded();
+
+ // If the bid is not higher, send the
+ // money back (the revert statement
+ // will revert all changes in this
+ // function execution including
+ // it having received the money).
+ if (msg.value <= highestBid)
+ revert BidNotHighEnough(highestBid);
+
+ if (highestBid != 0) {
+ // Sending back the money by simply using
+ // highestBidder.send(highestBid) is a security risk
+ // because it could execute an untrusted contract.
+ // It is always safer to let the recipients
+ // withdraw their money themselves.
+ pendingReturns[highestBidder] += highestBid;
+ }
+ highestBidder = msg.sender;
+ highestBid = msg.value;
+ emit HighestBidIncreased(msg.sender, msg.value);
+ }
+
+ /// Withdraw a bid that was overbid.
+ function withdraw() external returns (bool) {
+ uint amount = pendingReturns[msg.sender];
+ if (amount > 0) {
+ // It is important to set this to zero because the recipient
+ // can call this function again as part of the receiving call
+ // before `send` returns.
+ pendingReturns[msg.sender] = 0;
+
+ // msg.sender is not of type `address payable` and must be
+ // explicitly converted using `payable(msg.sender)` in order
+ // use the member function `send()`.
+ if (!payable(msg.sender).send(amount)) {
+ // No need to call throw here, just reset the amount owing
+ pendingReturns[msg.sender] = amount;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /// 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);
+ }
+}
+```
+
+These are the basic concepts of the Simple Auction contract:
+
+* Everyone can send their bids during a bidding period.
+* The bids already include sending money / Ether in order to bind the bidders to their bids.
+* If the highest bid is raised, the previous highest bidder gets their money back.
+* After the end of the bidding period, the contract has to be called manually for the beneficiary to receive their money - contracts cannot activate themselves.
+
+The contract consists of:
+
+* A variable declaration
+* Initialization by a constructor
+* Three functions
+
+Let's dive into the details of the role of each function, and learn how to port each function into Gnolang with test cases.
+
+When writing a test case, the following conditions are often used to determine whether the function has been properly executed:
+
+* Value matching
+* Error status
+* Panic status
+
+Below is a test case helper that will help implement each condition.
+
+### Gnolang - Testcase Helper
+
+[embedmd]:# (../assets/how-to-guides/porting-solidity-to-gno/porting-1.gno go)
+```go
+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()
+}
+```
+
+## Variable init - Solidity
+
+[embedmd]:# (../assets/how-to-guides/porting-solidity-to-gno/porting-2.sol solidity)
+```solidity
+// Parameters of the auction. Times are either
+// absolute unix timestamps (seconds since 1970-01-01)
+// or time periods in seconds.
+address payable public beneficiary;
+uint public auctionEndTime;
+
+// Current state of the auction.
+address public highestBidder;
+uint public highestBid;
+
+// Allowed withdrawals of previous bids
+mapping(address => uint) pendingReturns;
+
+// Set to true at the end, disallows any change.
+// By default initialized to `false`.
+bool ended;
+
+// Events that will be emitted on changes.
+event HighestBidIncreased(address bidder, uint amount);
+event AuctionEnded(address winner, uint amount);
+
+// Errors that describe failures.
+
+// The triple-slash comments are so-called natspec
+// comments. They will be shown when the user
+// is asked to confirm a transaction or
+// when an error is displayed.
+
+/// The auction has already ended.
+error AuctionAlreadyEnded();
+/// There is already a higher or equal bid.
+error BidNotHighEnough(uint highestBid);
+/// The auction has not ended yet.
+error AuctionNotYetEnded();
+/// The function auctionEnd has already been called.
+error AuctionEndAlreadyCalled();
+
+/// Create a simple auction with `biddingTime`
+/// seconds bidding time on behalf of the
+/// beneficiary address `beneficiaryAddress`.
+constructor(
+ uint biddingTime,
+ address payable beneficiaryAddress
+) {
+ beneficiary = beneficiaryAddress;
+ auctionEndTime = block.timestamp + biddingTime;
+}
+```
+
+* `address payable public beneficiary;` : Address to receive the amount after the auction's ending.
+* `uint public auctionEndTime;` : Auction ending time.
+* `address public highestBidder;` : The highest bidder.
+* `uint public highestBid;` : The highest bid.
+* `mapping(address => uint) pendingReturns;` : Bidder's address and amount to be returned (in case of the highest bid changes).
+* `bool ended;` : Whether the auction is closed.
+
+### Variable init - Gnolang
+
+[embedmd]:# (../assets/how-to-guides/porting-solidity-to-gno/porting-3.gno go)
+```go
+var (
+ receiver = std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")
+ auctionEndBlock = std.GetHeight() + uint(300) // in blocks
+ highestBidder std.Address
+ highestBid = uint(0)
+ pendingReturns avl.Tree
+ ended = false
+)
+```
+
+> **Note:** In Solidity, the Auction ending time is set by a time basis, but in the above case, it's set by a block basis.
+
+###
+
+## bid() - Solidity
+
+[embedmd]:# (../assets/how-to-guides/porting-solidity-to-gno/porting-4.sol solidity)
+```solidity
+function bid() external payable {
+ // No arguments are necessary, all
+ // information is already part of
+ // the transaction. The keyword payable
+ // is required for the function to
+ // be able to receive Ether.
+
+ // Revert the call if the bidding
+ // period is over.
+ if (block.timestamp > auctionEndTime)
+ revert AuctionAlreadyEnded();
+
+ // If the bid is not higher, send the
+ // money back (the revert statement
+ // will revert all changes in this
+ // function execution including
+ // it having received the money).
+ if (msg.value <= highestBid)
+ revert BidNotHighEnough(highestBid);
+
+ if (highestBid != 0) {
+ // Sending back the money by simply using
+ // highestBidder.send(highestBid) is a security risk
+ // because it could execute an untrusted contract.
+ // It is always safer to let the recipients
+ // withdraw their money themselves.
+ pendingReturns[highestBidder] += highestBid;
+ }
+ highestBidder = msg.sender;
+ highestBid = msg.value;
+ emit HighestBidIncreased(msg.sender, msg.value);
+}
+```
+
+`bid()` function is for participating in an auction and includes:
+
+* Determining whether an auction is closed.
+* Comparing a new bid with the current highest bid.
+* Prepare data to return the bid amount to the existing highest bidder in case of the highest bid is increased.
+* Update variables with the top bidder & top bid amount.
+
+### bid() - Gnolang
+
+[embedmd]:# (../assets/how-to-guides/porting-solidity-to-gno/porting-5.gno go)
+```go
+func Bid() {
+ if std.GetHeight() > auctionEndBlock {
+ panic("Exceeded auction end block")
+ }
+
+ sentCoins := std.GetOrigSend()
+ if len(sentCoins) != 1 {
+ panic("Send only one type of coin")
+ }
+
+ sentAmount := uint(sentCoins[0].Amount)
+ if sentAmount <= highestBid {
+ panic("Too few coins sent")
+ }
+
+ // A new bid is higher than the current highest bid
+ if sentAmount > highestBid {
+ // If the highest bid is greater than 0,
+ if highestBid > 0 {
+ // Need to return the bid amount to the existing highest bidder
+ // Create an AVL tree and save
+ pendingReturns.Set(highestBidder.String(), highestBid)
+ }
+
+ // Update the top bidder address
+ highestBidder = std.GetOrigCaller()
+ // Update the top bid amount
+ highestBid = sentAmount
+ }
+}
+```
+
+### bid() - Gnolang Testcase
+
+[embedmd]:# (../assets/how-to-guides/porting-solidity-to-gno/porting-6.gno go)
+```go
+// Bid Function Test - Send Coin
+func TestBidCoins(t *testing.T) {
+ // Sending two types of coins
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 0}, {"test", 1}}, nil)
+ shouldPanic(t, Bid)
+
+ // Sending lower amount than the current highest bid
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 0}}, nil)
+ shouldPanic(t, Bid)
+
+ // Sending more amount than the current highest bid (exceeded)
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 1}}, nil)
+ shouldNoPanic(t, Bid)
+}
+
+// Bid Function Test - Bid by two or more people
+func TestBidCoins(t *testing.T) {
+ // bidder01 bidding with 1 coin
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 1}}, nil)
+ shouldNoPanic(t, Bid)
+ shouldEqual(t, highestBid, 1)
+ shouldEqual(t, highestBidder, bidder01)
+ shouldEqual(t, pendingReturns.Size(), 0)
+
+ // bidder02 bidding with 1 coin
+ std.TestSetOrigCaller(bidder02)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 1}}, nil)
+ shouldPanic(t, Bid)
+
+ // bidder02 bidding with 2 coins
+ std.TestSetOrigCaller(bidder02)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 2}}, nil)
+ shouldNoPanic(t, Bid)
+ shouldEqual(t, highestBid, 2)
+ shouldEqual(t, highestBidder, bidder02)
+ shouldEqual(t, pendingReturns.Size(), 1)
+}
+```
+
+###
+
+## withdraw() - Solidity
+
+[embedmd]:# (../assets/how-to-guides/porting-solidity-to-gno/porting-7.sol solidity)
+```solidity
+/// Withdraw a bid that was overbid.
+function withdraw() external returns (bool) {
+ uint amount = pendingReturns[msg.sender];
+ if (amount > 0) {
+ // It is important to set this to zero because the recipient
+ // can call this function again as part of the receiving call
+ // before `send` returns.
+ pendingReturns[msg.sender] = 0;
+
+ // msg.sender is not of type `address payable` and must be
+ // explicitly converted using `payable(msg.sender)` in order
+ // use the member function `send()`.
+ if (!payable(msg.sender).send(amount)) {
+ // No need to call throw here, just reset the amount owing
+ pendingReturns[msg.sender] = amount;
+ return false;
+ }
+ }
+ return true;
+}
+```
+
+`withdraw()` is to return the bid amount to the existing highest bidder in case of the highest bid changes and includes:
+
+* When called, determine if there's a bid amount to be returned to the address.
+* (If there's an amount to be returned) Before returning, set the previously recorded amount to `0` and return the actual amount.
+
+### withdraw() - Gnolang
+
+[embedmd]:# (../assets/how-to-guides/porting-solidity-to-gno/porting-8.gno go)
+```go
+func Withdraw() {
+ // Query the return amount to non-highest bidders
+ amount, _ := pendingReturns.Get(std.GetOrigCaller().String())
+
+ if amount > 0 {
+ // If there's an amount, reset the amount first,
+ pendingReturns.Set(std.GetOrigCaller().String(), 0)
+
+ // Return the exceeded amount
+ banker := std.GetBanker(std.BankerTypeRealmSend)
+ pkgAddr := std.GetOrigPkgAddr()
+
+ banker.SendCoins(pkgAddr, std.GetOrigCaller(), std.Coins{{"ugnot", amount.(int64)}})
+ }
+}
+```
+
+###
+
+### withdraw() - Gnolang Testcase
+
+[embedmd]:# (../assets/how-to-guides/porting-solidity-to-gno/porting-9.gno go)
+```go
+// Withdraw Function Test
+func TestWithdraw(t *testing.T) {
+ // If there's no participants for return
+ shouldEqual(t, pendingReturns.Size(), 0)
+
+ // If there's participants for return (data generation
+ returnAddr := bidder01.String()
+ returnAmount := int64(3)
+ pendingReturns.Set(returnAddr, returnAmount)
+ shouldEqual(t, pendingReturns.Size(), 1)
+ shouldEqual(t, pendingReturns.Has(returnAddr), true)
+
+ banker := std.GetBanker(std.BankerTypeRealmSend)
+ pkgAddr := std.GetOrigPkgAddr()
+ banker.SendCoins(pkgAddr, std.Address(returnAddr), std.Coins{{"ugnot", returnAmount}})
+ shouldEqual(t, banker.GetCoins(std.Address(returnAddr)).String(), "3ugnot")
+}
+```
+
+## auctionEnd() - Solidity
+
+[embedmd]:# (../assets/how-to-guides/porting-solidity-to-gno/porting-10.sol solidity)
+```solidity
+/// 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);
+}
+```
+
+`auctionEnd()` function is for ending the auction and includes:
+
+* Determines if the auction should end by comparing the end time.
+* Determines if the auction has already ended or not.
+ * (If not ended) End the auction.
+ * (If not ended) Send the highest bid amount to the recipient.
+
+### auctionEnd() - Gnolang
+
+[embedmd]:# (../assets/how-to-guides/porting-solidity-to-gno/porting-11.gno go)
+```go
+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)}})
+}
+```
+
+### auctionEnd() - Gnolang Testcase
+
+[embedmd]:# (../assets/how-to-guides/porting-solidity-to-gno/porting-12.gno go)
+```go
+// 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)
+}
+```
+
+## Precautions for Running Test Cases
+
+* Each test function should be executed separately one by one, to return all passes without any errors.
+* Same as Golang, Gnolang doesn't support `setup()` & `teardown()` functions. So running two or more test functions simultaneously can result in tainted data.
+* If you want to do the whole test at once, make it into a single function as below:
+
+[embedmd]:# (../assets/how-to-guides/porting-solidity-to-gno/porting-13.gno go)
+```go
+// The whole test
+func TestFull(t *testing.T) {
+ bidder01 := testutils.TestAddress("bidder01") // g1vf5kger9wgcrzh6lta047h6lta047h6lufftkw
+ bidder02 := testutils.TestAddress("bidder02") // g1vf5kger9wgcryh6lta047h6lta047h6lnhe2x2
+
+ // Variables test
+ {
+ shouldEqual(t, highestBidder, "")
+ shouldEqual(t, receiver, "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")
+ shouldEqual(t, auctionEndBlock, 423)
+ shouldEqual(t, highestBid, 0)
+ shouldEqual(t, pendingReturns.Size(), 0)
+ shouldEqual(t, ended, false)
+ }
+
+ // Send two or more types of coins
+ {
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 0}, {"test", 1}}, nil)
+ shouldPanic(t, Bid)
+ }
+
+ // Send less than the highest bid
+ {
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 0}}, nil)
+ shouldPanic(t, Bid)
+ }
+
+ // Send more than the highest bid
+ {
+ std.TestSetOrigCaller(bidder01)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 1}}, nil)
+ shouldNoPanic(t, Bid)
+
+ shouldEqual(t, pendingReturns.Size(), 0)
+ shouldEqual(t, highestBid, 1)
+ shouldEqual(t, highestBidder, "g1vf5kger9wgcrzh6lta047h6lta047h6lufftkw")
+ }
+
+ // Other participants in the auction
+ {
+
+ // Send less amount than the current highest bid (current: 1)
+ std.TestSetOrigCaller(bidder02)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 1}}, nil)
+ shouldPanic(t, Bid)
+
+ // Send more amount than the current highest bid (exceeded)
+ std.TestSetOrigCaller(bidder02)
+ std.TestSetOrigSend(std.Coins{{"ugnot", 2}}, nil)
+ shouldNoPanic(t, Bid)
+
+ shouldEqual(t, highestBid, 2)
+ shouldEqual(t, highestBidder, "g1vf5kger9wgcryh6lta047h6lta047h6lnhe2x2")
+
+ shouldEqual(t, pendingReturns.Size(), 1) // Return to the existing bidder
+ shouldEqual(t, pendingReturns.Has("g1vf5kger9wgcrzh6lta047h6lta047h6lufftkw"), true)
+ }
+
+ // Auction ends
+ {
+ std.TestSkipHeights(150)
+ shouldPanic(t, AuctionEnd)
+ shouldEqual(t, ended, false)
+
+ std.TestSkipHeights(301)
+ shouldNoPanic(t, AuctionEnd)
+ shouldEqual(t, ended, true)
+
+ banker := std.GetBanker(std.BankerTypeRealmSend)
+ shouldEqual(t, banker.GetCoins(receiver).String(), "2ugnot")
+ }
+}
+```
diff --git a/docs/how-to-guides/simple-contract.md b/docs/how-to-guides/simple-contract.md
new file mode 100644
index 00000000000..0e77a6a75e1
--- /dev/null
+++ b/docs/how-to-guides/simple-contract.md
@@ -0,0 +1,149 @@
+---
+id: simple-contract
+---
+
+# How to write a simple Gno Smart Contract (Realm)
+
+## Overview
+
+This guide shows you how to write a simple _Counter_ Smart Contract, or rather a [Realm](../explanation/realms.md),
+in [Gno (Gnolang)](../explanation/gno-language.md). For actually deploying the Realm, please see
+the [deployment](deploy.md) guide.
+
+Our _Counter_ Realm will have the following functionality:
+
+- Keeping track of the current count.
+- Incrementing / decrementing the count.
+- Fetching the current count value.
+
+## Prerequisites
+
+- **Text editor**
+
+:::info Editor support
+The Gno language is based on Golang, but it does not have all the bells and whistles in major text editors like Go.
+Advanced language features like IntelliSense are still in the works.
+
+Currently, we officially have language support
+for [ViM](https://github.com/gnolang/gno/blob/master/CONTRIBUTING.md#vim-support),
+[Emacs](https://github.com/gnolang/gno/blob/master/CONTRIBUTING.md#emacs-support)
+and [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=harry-hov.gno).
+:::
+
+## 1. Setting up the work directory
+
+Gno Realms can be typically written anywhere, under any structure, just like regular Go code.
+However, Gno developers have adopted a standard of organizing Gno logic under a specific directory hierarchy, which we
+will explore here.
+
+Create the main working directory for our Realm:
+
+```bash
+mkdir counter-app
+```
+
+Since we are building a simple _Counter_ Realm, inside our created `counter-app` directory, we can create another
+directory named `r`, which stands for `realm`:
+
+```bash
+cd counter-app
+mkdir r
+```
+
+Alternatively, if we were writing a [Gno Package](../explanation/packages.md), we would denote this directory name
+as `p` (for `package`). You can learn more about Packages in our [Package development guide](simple-library.md).
+
+Additionally, we will create another sub-folder that will house our Realm code, named `counter`:
+
+```bash
+cd r
+mkdir counter
+```
+
+After setting up our work directory structure, we should have something like this:
+
+```text
+counter-app/
+├─ r/
+│ ├─ counter/
+│ │ ├─ // source code here
+```
+
+## 2. Create `counter.gno`
+
+Now that the work directory structure is set up, we can go into the `counter` sub-folder, and actually create
+our _Counter_ Smart Contract:
+
+```bash
+cd counter
+touch counter.gno
+```
+
+:::info Gno file extension
+All Gno (Gnolang) source code has the file extension `.gno`.
+
+This file extension is required for existing gno tools and processes to work.
+:::
+
+We can finally write out the logic of the _Counter_ Smart Contract in `counter.gno`:
+
+[embedmd]:# (../assets/how-to-guides/simple-contract/counter.gno go)
+```go
+package counter
+
+import "fmt"
+
+var count int
+
+func Increment() {
+ count++
+}
+
+func Decrement() {
+ count--
+}
+
+func Render(_ string) string {
+ return fmt.Sprintf("Count: %d", count)
+}
+```
+
+There are a few things happening here, so let's dissect them:
+
+- We defined the logic of our Realm into a package called `counter`.
+- The package-level `count` variable stores the active count for the Realm (it is stateful).
+- `Increment` and `Decrement` are public Realm (Smart Contract) methods, and as such are callable by users.
+- `Increment` and `Decrement` directly modify the `count` value by making it go up or down (change state).
+- Calling the `Render` method would return the `count` value as a formatted string. Learn more about the `Render`
+ method and how it's used [here](../explanation/realms.md).
+
+:::info A note on constructors
+Gno Realms support a concept taken from other programming languages - _constructors_.
+
+For example, to initialize the `count` variable with custom logic, we can specify that
+logic within an `init` method, that is run **only once** on Realm deployment:
+
+[embedmd]:# (../assets/how-to-guides/simple-contract/init.gno go)
+```go
+package counter
+
+var count int
+
+// ...
+
+func init() {
+ count = 2 * 10 // arbitrary value
+}
+
+// ...
+```
+
+:::
+
+## Conclusion
+
+That's it 🎉
+
+You have successfully built a simple _Counter_ Realm that is ready to be deployed on the Gno chain and called by users.
+In the upcoming guides, we will see how we can develop more complex Realm logic and have them interact
+with outside tools like a wallet application.
diff --git a/docs/how-to-guides/simple-library.md b/docs/how-to-guides/simple-library.md
new file mode 100644
index 00000000000..3ed4ad11754
--- /dev/null
+++ b/docs/how-to-guides/simple-library.md
@@ -0,0 +1,133 @@
+---
+id: simple-library
+---
+
+# How to write a simple Gno Library (Package)
+
+## Overview
+
+This guide shows you how to write a simple library (Package) in Gnolang, which can be used by other Packages and Realms.
+Packages are _stateless_, meaning they do not hold state like regular Realms (Smart Contracts). To learn more about the
+intricacies of Packages, please see the [Packages reference](../explanation/packages.md).
+
+The Package we will be writing today will be a simple library for suggesting a random tapas dish.
+We will define a set list of tapas, and define a method that randomly selects a dish from the list.
+
+## Prerequisites
+
+- **Text editor**
+
+:::info Editor support
+The Gno language is based on Golang, but it does not have all the bells and whistles in major text editors like Go.
+Advanced language features like IntelliSense are still in the works.
+
+Currently, we officially have language support
+for [ViM](https://github.com/gnolang/gno/blob/master/CONTRIBUTING.md#vim-support),
+[Emacs](https://github.com/gnolang/gno/blob/master/CONTRIBUTING.md#emacs-support)
+and [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=harry-hov.gno).
+:::
+
+## 1. Setting up the work directory
+
+We discussed Gno folder structures more in detail in
+the [simple Smart Contract guide](simple-contract.md#1-setting-up-the-work-directory).
+For now, we will just follow some rules outlined there.
+
+Create the main working directory for our Package:
+
+```bash
+mkdir tapas-lib
+```
+
+Since we are building a simple tapas Package, inside our created `tapas-lib` directory, we can create another
+directory named `p`, which stands for `package`:
+
+```bash
+cd tapas-lib
+mkdir p
+```
+
+Additionally, we will create another subdirectory that will house our Package code, named `tapas`:
+
+```bash
+cd p
+mkdir tapas
+```
+
+After setting up our work directory structure, we should have something like this:
+
+```text
+tapas-lib/
+├─ p/
+│ ├─ tapas/
+│ │ ├─ // source code here
+```
+
+## 2. Create `tapas.gno`
+
+Now that the work directory structure is set up, we can go into the `tapas` sub-folder, and actually create
+our tapas suggestion library logic:
+
+```bash
+cd tapas
+touch tapas.gno
+```
+
+Inside `tapas.gno`, we will define our library logic:
+
+[embedmd]:# (../assets/how-to-guides/simple-library/tapas.gno go)
+```go
+package tapas
+
+import (
+ "gno.land/p/demo/rand"
+)
+
+// List of tapas suggestions
+var listOfTapas = []string{
+ "Patatas Bravas",
+ "Gambas al Ajillo",
+ "Croquetas",
+ "Tortilla Española",
+ "Pimientos de Padrón",
+ "Jamon Serrano",
+ "Boquerones en Vinagre",
+ "Calamares a la Romana",
+ "Pulpo a la Gallega",
+ "Tostada con Tomate",
+ "Mejillones en Escabeche",
+ "Chorizo a la Sidra",
+ "Cazón en Adobo",
+ "Banderillas",
+ "Espárragos a la Parrilla",
+ "Huevos Rellenos",
+ "Tuna Empanada",
+ "Sardinas a la Plancha",
+}
+
+// GetTapaSuggestion randomly selects and returns a tapa suggestion
+func GetTapaSuggestion() string {
+ // Create a new instance of the random number generator.
+ // Notice that this is from an imported Gno library
+ generator := rand.New()
+
+ // Generate a random index
+ randomIndex := generator.Intn(len(listOfTapas))
+
+ // Return the random suggestion
+ return listOfTapas[randomIndex]
+}
+```
+
+There are a few things happening here, so let's dissect them:
+
+- We defined the logic of our library into a package called `tapas`.
+- The package imports another gno package, which is deployed at `gno.land/p/demo/rand`
+- We use the imported package inside of `GetTapaSuggestion` to generate a random index value for a tapa
+
+## Conclusion
+
+That's it 🎉
+
+You have successfully built a simple tapas suggestion Package that is ready to be deployed on the Gno chain and imported
+by other Packages and Realms.
diff --git a/docs/how-to-guides/testing-gno.md b/docs/how-to-guides/testing-gno.md
new file mode 100644
index 00000000000..8bb6f1bf451
--- /dev/null
+++ b/docs/how-to-guides/testing-gno.md
@@ -0,0 +1,185 @@
+---
+id: testing-gno
+---
+
+# How to test Gno Code
+
+## Overview
+
+In this guide, we will explore the available tooling in testing out the Gno Realms and Packages we write.
+We will go over different CLI tools available to developers, gno testing libraries as well as
+testing techniques that involve data mocking.
+
+## Prerequisites
+
+- **`gno` set up. Reference the [Installation](../getting-started/local-setup.md#3-installing-other-gno-tools) guide
+ for steps**
+
+## Example Realm
+
+For the purpose of this guide, we will be testing the simple *Counter* Realm created in
+the [How to write a simple Gno Smart Contract (Realm)](simple-contract.md) guide.
+
+[embedmd]:# (../assets/how-to-guides/testing-gno/counter-1.gno go)
+```go
+// counter-app/r/counter/counter.gno
+
+package counter
+
+import "fmt"
+
+var count int
+
+func Increment() {
+ count++
+}
+
+func Decrement() {
+ count--
+}
+
+func Render(_ string) string {
+ return fmt.Sprintf("Count: %d", count)
+}
+```
+
+## 1. Writing the Gno test
+
+Gno tests are written in the same manner and format as regular Go tests, just in `_test.gno` files.
+
+We can place the Gno tests for the `Counter` Realm in the same directory as `counter.gno`:
+
+```text
+counter-app/
+├─ r/
+│ ├─ counter/
+│ │ ├─ counter.gno
+│ │ ├─ counter_test.gno <--- the test source code
+```
+
+```bash
+cd counter
+touch counter_test.gno
+```
+
+What should be tested in this _Counter_ Realm example?
+Mainly, we want to verify that:
+
+- Increment increments the value.
+- Decrement decrements the value.
+- Render returns a valid formatted value.
+
+Let's write the required unit tests:
+
+[embedmd]:# (../assets/how-to-guides/testing-gno/counter-2.gno go)
+```go
+// counter-app/r/counter/counter_test.gno
+
+package counter
+
+import "testing"
+
+func TestCounter_Increment(t *testing.T) {
+ // Reset the value
+ count = 0
+
+ // Verify the initial value is 0
+ if count != 0 {
+ t.Fatalf("initial value != 0")
+ }
+
+ // Increment the value
+ Increment()
+
+ // Verify the initial value is 1
+ if count != 1 {
+ t.Fatalf("initial value != 1")
+ }
+}
+
+func TestCounter_Decrement(t *testing.T) {
+ // Reset the value
+ count = 0
+
+ // Verify the initial value is 0
+ if count != 0 {
+ t.Fatalf("initial value != 0")
+ }
+
+ // Decrement the value
+ Decrement()
+
+ // Verify the initial value is 1
+ if count != -1 {
+ t.Fatalf("initial value != -1")
+ }
+}
+
+func TestCounter_Render(t *testing.T) {
+ // Reset the value
+ count = 0
+
+ // Verify the Render output
+ if Render("") != "Count: 0" {
+ t.Fatalf("invalid Render value")
+ }
+}
+```
+
+:::warning Testing package-level variables
+
+In practice, it is not advisable to test and validate package level variables like this, as their value is mutated
+between test runs. For the sake of keeping this guide simple, we went ahead and reset the variable value for each test,
+however,
+you should employ more robust test strategies.
+
+:::
+
+## 2. Running the Gno test
+
+To run the prepared Gno tests, we can utilize the `gno test` CLI tool.
+
+Simply point it to the location containing our testing source code, and the tests will execute.
+For example, we can run the following command from the `counter-app/r/counter` directory:
+
+```bash
+gno test -verbose -root-dir /Users/zmilos/Work/gno .
+```
+
+Let's look into the different parts of this command:
+
+- `-verbose` enables the verbose output.
+- `-root-dir` specifies the root directory to our cloned `gno` GitHub repository
+- `.` specifies the location containing our test files. Since we are already located in that directory, we specify
+ a `.`.
+
+Running the test command should produce a successful output:
+
+```bash
+=== RUN TestCounter_Increment
+--- PASS: TestCounter_Increment (0.00s)
+=== RUN TestCounter_Decrement
+--- PASS: TestCounter_Decrement (0.00s)
+=== RUN TestCounter_Render
+--- PASS: TestCounter_Render (0.00s)
+ok ./. 1.00s
+```
+
+## Additional test support
+
+As we grow more familiar with Gno development, our Realm / Package logic can become more complex. As such, we need
+more robust testing support in the form of mocking values ahead of time that would normally be only available on a
+live (deployed) Realm / Package.
+
+Luckily, the Gno standard library provides ample support for functionality such as setting predefined values ahead of
+time, such as the request caller address, or the calling package address.
+
+You can learn more about these methods, that are importable using the `std` import declaration,
+in the [Standard Library](../reference/standard-library.md) reference section.
+
+## Conclusion
+
+That's it 🎉
+
+You have successfully written and tested Gno code. Additionally, you have utilized the `gno test` tool, and understood
+how it can be configured to make the developer experience smooth.
diff --git a/docs/how-to-guides/write-simple-dapp.md b/docs/how-to-guides/write-simple-dapp.md
new file mode 100644
index 00000000000..4c5c5fce032
--- /dev/null
+++ b/docs/how-to-guides/write-simple-dapp.md
@@ -0,0 +1,301 @@
+---
+id: write-simple-dapp
+---
+
+# How to write a simple dApp on Gno.land
+
+## Overview
+
+This guide will show you how to write a complete dApp that combines both a package and a realm.
+Our app will allow any user to create a poll, and subsequently vote
+YAY or NAY for any poll that has not exceeded the voting deadline.
+
+## Prerequisites
+
+- **Text editor**
+
+## Defining dApp functionality
+
+Our dApp will consist of a Poll package, which will handle all things related to the Poll struct,
+and a Poll Factory realm, which will handle the user-facing functionality and rendering.
+
+For simplicity, we will define the functionality in plain text, and leave comments explaining the code.
+
+### Poll Package
+
+- Defines a `Poll` struct
+- Defines a `NewPoll` constructor
+- Defines `Poll` field getters
+- Defines a `Vote` function
+- Defines a `HasVoted` check method
+- Defines a `VoteCount` getter method
+
+[embedmd]:# (../assets/how-to-guides/write-simple-dapp/poll-1.gno go)
+```go
+package poll
+
+import (
+ "std"
+
+ "gno.land/p/demo/avl"
+)
+
+// Main struct
+type Poll struct {
+ title string
+ description string
+ deadline int64 // block height
+ voters *avl.Tree // addr -> yes / no (bool)
+}
+
+// Getters
+func (p Poll) Title() string {
+ return p.title
+}
+
+func (p Poll) Description() string {
+ return p.description
+}
+
+func (p Poll) Deadline() int64 {
+ return p.deadline
+}
+
+func (p Poll) Voters() *avl.Tree {
+ return p.voters
+}
+
+// Poll instance constructor
+func NewPoll(title, description string, deadline int64) *Poll {
+ return &Poll{
+ title: title,
+ description: description,
+ deadline: deadline,
+ voters: avl.NewTree(),
+ }
+}
+
+// Vote Votes for a user
+func (p *Poll) Vote(voter std.Address, vote bool) {
+ p.Voters().Set(string(voter), vote)
+}
+
+// HasVoted vote: yes - true, no - false
+func (p *Poll) HasVoted(address std.Address) (bool, bool) {
+ vote, exists := p.Voters().Get(string(address))
+ if exists {
+ return true, vote.(bool)
+ }
+ return false, false
+}
+
+// VoteCount Returns the number of yay & nay votes
+func (p Poll) VoteCount() (int, int) {
+ var yay int
+
+ p.Voters().Iterate("", "", func(key string, value interface{}) bool {
+ vote := value.(bool)
+ if vote == true {
+ yay = yay + 1
+ }
+ })
+ return yay, p.Voters().Size() - yay
+}
+```
+
+A few remarks:
+
+- We are using the `std` library for accessing blockchain-related functionality and types, such as `std.Address`.
+- Since the `map` data type is not deterministic in Go, we need to use the AVL tree structure, defined
+ under `p/demo/avl`.
+ It behaves similarly to a map; it maps a key of type `string` onto a value of any type - `interface{}`.
+- We are importing the `p/demo/avl` package directly from on-chain storage, which can be accessed through the
+ path `gno.land/`.
+ As of October 2023, you can find already-deployed packages & libraries which provide additional Gno functionality in
+ the [monorepo](https://github.com/gnolang/gno), under the `examples/gno.land` folder.
+
+:::info
+After testing the `Poll` package, we need to deploy it in order to use it in our realm.
+Check out the [deployment](deploy.md) guide to learn how to do this.
+:::
+
+### Poll Factory Realm
+
+Moving on, we can create the Poll Factory realm.
+
+The realm will contain the following functionality:
+
+- An exported `NewPoll` method, to allow users to create polls
+- An exported `Vote` method, to allow users to pledge votes for any active poll
+- A `Render` function to display the realm state
+
+[embedmd]:# (../assets/how-to-guides/write-simple-dapp/poll-2.gno go)
+```go
+package poll
+
+import (
+ "std"
+
+ "gno.land/p/demo/avl"
+ "gno.land/p/demo/poll"
+ "gno.land/p/demo/ufmt"
+)
+
+// state variables
+var (
+ polls *avl.Tree // id -> Poll
+ pollIDCounter int
+)
+
+func init() {
+ polls = avl.NewTree()
+ pollIDCounter = 0
+}
+
+// NewPoll - Creates a new Poll instance
+func NewPoll(title, description string, deadline int64) string {
+ // get block height
+ if deadline <= std.GetHeight() {
+ return "Error: Deadline has to be in the future."
+ }
+
+ // convert int ID to string used in AVL tree
+ id := ufmt.Sprintf("%d", pollIDCounter)
+ p := poll.NewPoll(title, description, deadline)
+
+ // add new poll in avl tree
+ polls.Set(id, p)
+
+ // increment ID counter
+ pollIDCounter = pollIDCounter + 1
+
+ return ufmt.Sprintf("Successfully created poll #%s!", id)
+}
+
+// Vote - vote for a specific Poll
+// yes - true, no - false
+func Vote(pollID int, vote bool) string {
+ // get txSender
+ txSender := std.GetOrigCaller()
+
+ id := ufmt.Sprintf("%d", pollID)
+ // get specific Poll from AVL tree
+ pollRaw, exists := polls.Get(id)
+
+ if !exists {
+ return "Error: Poll with specified doesn't exist."
+ }
+
+ // cast Poll into proper format
+ poll, _ := pollRaw.(*poll.Poll)
+
+ voted, _ := poll.HasVoted(txSender)
+ if voted {
+ return "Error: You've already voted!"
+ }
+
+ if poll.Deadline() <= std.GetHeight() {
+ return "Error: Voting for this poll is closed."
+ }
+
+ // record vote
+ poll.Vote(txSender, vote)
+
+ // update Poll in tree
+ polls.Set(id, poll)
+
+ if vote == true {
+ return ufmt.Sprintf("Successfully voted YAY for poll #%s!", id)
+ }
+ return ufmt.Sprintf("Successfully voted NAY for poll #%s!", id)
+}
+```
+
+With that we have written the core functionality of the realm, and all that is left is
+the [Render function](http://localhost:3000/explanation/realms).
+Its purpose is to help us display the state of the realm in Markdown, by formatting the state into a string buffer:
+
+[embedmd]:# (../assets/how-to-guides/write-simple-dapp/poll-3.gno go)
+```go
+func Render(path string) string {
+ var b bytes.Buffer
+
+ b.WriteString("# Polls!\n\n")
+
+ if polls.Size() == 0 {
+ b.WriteString("### No active polls currently!")
+ return b.String()
+ }
+ polls.Iterate("", "", func(key string, value interface{}) bool {
+
+ // cast raw data from tree into Poll struct
+ p := value.(*poll.Poll)
+ ddl := p.Deadline()
+
+ yay, nay := p.VoteCount()
+ yayPercent := 0
+ nayPercent := 0
+
+ if yay+nay != 0 {
+ yayPercent = yay * 100 / (yay + nay)
+ nayPercent = nay * 100 / (yay + nay)
+ }
+
+ b.WriteString(
+ ufmt.Sprintf(
+ "## Poll #%s: %s\n",
+ key, // poll ID
+ p.Title(),
+ ),
+ )
+
+ dropdown := "\nPoll details "
+
+ b.WriteString(dropdown + "Description: " + p.Description())
+
+ b.WriteString(
+ ufmt.Sprintf(" Voting until block: %d Current vote count: %d",
+ p.Deadline(),
+ p.Voters().Size()),
+ )
+
+ b.WriteString(
+ ufmt.Sprintf(" YAY votes: %d (%d%%)", yay, yayPercent),
+ )
+ b.WriteString(
+ ufmt.Sprintf(" NAY votes: %d (%d%%)", nay, nayPercent),
+ )
+
+ dropdown = " \nVote details"
+ b.WriteString(dropdown)
+
+ p.Voters().Iterate("", "", func(key string, value interface{}) bool {
+
+ voter := key
+ vote := value.(bool)
+
+ if vote == true {
+ b.WriteString(
+ ufmt.Sprintf(" %s voted YAY!", voter),
+ )
+ } else {
+ b.WriteString(
+ ufmt.Sprintf(" %s voted NAY!", voter),
+ )
+ }
+ return false
+ })
+
+ b.WriteString("\n\n")
+ return false
+ })
+ return b.String()
+}
+```
+
+## Conclusion
+
+That's it 🎉
+
+You have successfully built a simple but fully-fledged dApp using Gno!
+Now you're ready to conquer new, more complex dApps in Gno.
diff --git a/docs/overview.md b/docs/overview.md
new file mode 100644
index 00000000000..50e07442ea0
--- /dev/null
+++ b/docs/overview.md
@@ -0,0 +1,45 @@
+---
+id: overview
+slug: /
+---
+
+# Overview
+
+## What is Gno.land?
+
+Gno.land is a Layer 1 blockchain platform that enables the execution of Smart Contracts using an interpreted
+version of the Go programming language called Gnolang (Gno for short).
+
+### Key Features and Technology
+
+1. **Interpreted Gnolang**: Gno.land utilizes the Gnolang programming language, which is based on Go. It is executed
+ through a specialized virtual machine called the GnoVM, purpose-built for blockchain development with built-in
+ determinism and a modified standard library. While Gnolang
+ shares similarities with Go in terms of syntax, it currently lacks go routine support. However, this feature is
+ planned for future development, ensuring deterministic GnoVM executions.
+2. **Consensus Protocol - Tendermint2**: Gno.land achieves consensus between blockchain nodes using the Tendermint2
+ consensus protocol. This approach ensures secure and reliable network operation.
+3. **Inter-Blockchain Communication (IBC)**: In the future, Gno.land will be able to communicate and exchange data with
+ other blockchain networks within the Cosmos ecosystem through the Inter-Blockchain Communication (IBC) protocol.
+
+### Why Go-based?
+
+The decision to base Gno.land's language on Go was influenced by the following factors:
+
+1. **Standard and Secure Language**: Go is a well-established and secure programming language, widely adopted in the
+ software development community. By leveraging Go's features, Gno.land benefits from a robust and proven foundation.
+2. **User-Friendly**: Go's simplicity and ease of understanding make it beginner-friendly. This accessibility lowers the
+ entry barrier for developers to create Smart Contracts on the Gno.land platform.
+
+### How does it compare with Ethereum?
+
+In comparison to Ethereum, Gno.land offers distinct advantages:
+
+1. **Transparent and Auditable Smart Contracts**: Gno.land Smart Contracts are fully transparent and auditable by users
+ because the actual source code is uploaded to the blockchain. In contrast, Ethereum requires contracts to be
+ precompiled into bytecode, leading to less transparency as bytecode is stored on the blockchain, not the
+ human-readable source code.
+
+2. **General-Purpose Language**: Gno.land's Gnolang is a general-purpose language, similar to Go, extending its
+ usability beyond the context of blockchain. In contrast, Solidity is designed specifically for Smart Contracts on the
+ Ethereum platform.
diff --git a/docs/peace.md b/docs/peace.md
index e76faae1ca3..5eb876ecac8 100644
--- a/docs/peace.md
+++ b/docs/peace.md
@@ -1,3 +1,7 @@
+---
+id: peace
+---
+
# Peace!
_or, Everyone is Invited to Gno.land, if you want!_
diff --git a/docs/reference/gno-js-client/getting-started.md b/docs/reference/gno-js-client/getting-started.md
new file mode 100644
index 00000000000..188f084bd56
--- /dev/null
+++ b/docs/reference/gno-js-client/getting-started.md
@@ -0,0 +1,25 @@
+---
+id: gno-js-getting-started
+---
+
+# Getting Started
+
+[@gnolang/gno-js-client](https://github.com/gnolang/gno-js-client) is a JavaScript/TypeScript client implementation for Gno chains. It is an extension of the
+[tm2-js-client](https://github.com/gnolang/tm2-js-client), but with Gno-specific functionality.
+
+## Key Features
+
+- Provides the ability to interact with Gno Realms / Packages
+- Easy interaction with VM-specific ABCI queries
+
+## Installation
+
+To install `@gnolang/gno-js-client`, use your preferred package manager:
+
+```bash
+yarn add @gnolang/gno-js-client
+```
+
+```bash
+npm install @gnolang/gno-js-client
+```
diff --git a/docs/reference/gno-js-client/gno-provider.md b/docs/reference/gno-js-client/gno-provider.md
new file mode 100644
index 00000000000..a5248349d35
--- /dev/null
+++ b/docs/reference/gno-js-client/gno-provider.md
@@ -0,0 +1,124 @@
+---
+id: gno-js-provider
+---
+
+# Gno Provider
+
+The `Gno Provider` is an extension on the `tm2-js-client` `Provider`,
+outlined [here](../tm2-js-client/Provider/provider.md). Both JSON-RPC and WS providers are included with the package.
+
+## Realm Methods
+
+### getRenderOutput
+
+Executes the Render(path) method in read-only mode
+
+#### Parameters
+
+* `packagePath` **string** the gno package path
+* `path` **string** the render path
+* `height` **number** the height for querying.
+ If omitted, the latest height is used (optional, default `0`)
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.getRenderOutput('gno.land/r/demo/demo_realm', '');
+// ## Hello World!
+```
+
+### getFunctionSignatures
+
+Fetches public facing function signatures
+
+#### Parameters
+
+* `packagePath` **string** the gno package path
+* `height` **number** the height for querying.
+ If omitted, the latest height is used (optional, default `0`)
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.getFunctionSignatures('gno.land/r/demo/foo20');
+/*
+[
+ { FuncName: 'TotalSupply', Params: null, Results: [ [Object] ] },
+ {
+ FuncName: 'BalanceOf',
+ Params: [ [Object] ],
+ Results: [ [Object] ]
+ },
+ {
+ FuncName: 'Allowance',
+ Params: [ [Object], [Object] ],
+ Results: [ [Object] ]
+ },
+ {
+ FuncName: 'Transfer',
+ Params: [ [Object], [Object] ],
+ Results: null
+ },
+ {
+ FuncName: 'Approve',
+ Params: [ [Object], [Object] ],
+ Results: null
+ },
+ {
+ FuncName: 'TransferFrom',
+ Params: [ [Object], [Object], [Object] ],
+ Results: null
+ },
+ { FuncName: 'Faucet', Params: null, Results: null },
+ { FuncName: 'Mint', Params: [ [Object], [Object] ], Results: null },
+ { FuncName: 'Burn', Params: [ [Object], [Object] ], Results: null },
+ { FuncName: 'Render', Params: [ [Object] ], Results: [ [Object] ] }
+]
+ */
+```
+
+### evaluateExpression
+
+Evaluates any expression in readonly mode and returns the results
+
+#### Parameters
+
+* `packagePath` **string** the gno package path
+* `expression` **string** the expression to be evaluated
+* `height` **number** the height for querying.
+ If omitted, the latest height is used (optional, default `0`)
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.evaluateExpression('gno.land/r/demo/foo20', 'TotalSupply()')
+// (10100000000 uint64)
+```
+
+### getFileContent
+
+Fetches the file content, or the list of files if the path is a directory
+
+#### Parameters
+
+* `packagePath` **string** the gno package path
+* `height` **number** the height for querying.
+ If omitted, the latest height is used (optional, default `0`)
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.getFileContent('gno.land/r/demo/foo20', 'TotalSupply()')
+/*
+foo20.gno
+foo20_test.gno
+ */
+```
diff --git a/docs/reference/gno-js-client/gno-wallet.md b/docs/reference/gno-js-client/gno-wallet.md
new file mode 100644
index 00000000000..7f7c44cd9b0
--- /dev/null
+++ b/docs/reference/gno-js-client/gno-wallet.md
@@ -0,0 +1,78 @@
+---
+id: gno-js-wallet
+---
+
+# Gno Wallet
+
+The `Gno Wallet` is an extension on the `tm2-js-client` `Wallet`, outlined [here](../tm2-js-client/wallet.md).
+
+## Account Methods
+
+### transferFunds
+
+Initiates a native currency transfer transaction between accounts
+
+#### Parameters
+
+* `to` **string** the bech32 address of the receiver
+* `funds` **Map** the denomination -> value map for funds
+* `fee` **TxFee** the custom transaction fee, if any
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+let fundsMap = new Map([
+ ["ugnot", 10],
+]);
+
+await wallet.transferFunds('g1flk9z2qmkgqeyrl654r3639rzgz7xczdfwwqw7', fundsMap);
+// returns the transaction hash
+```
+
+### callMethod
+
+Invokes the specified method on a GNO contract
+
+#### Parameters
+
+* `path` **string** the gno package / realm path
+* `method` **string** the method name
+* `args` **string[]** the method arguments, if any
+* `funds` **Map** the denomination -> value map for funds
+* `fee` **TxFee** the custom transaction fee, if any
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+let fundsMap = new Map([
+ ["ugnot", 10],
+]);
+
+await wallet.callMethod('gno.land/r/demo/foo20', 'TotalBalance', []);
+// returns the transaction hash
+```
+
+### deployPackage
+
+Deploys the specified package / realm
+
+#### Parameters
+
+* `gnoPackage` **MemPackage** the package / realm to be deployed
+* `funds` **Map** the denomination -> value map for funds
+* `fee` **TxFee** the custom transaction fee, if any
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+const memPackage: MemPackage = // ...
+
+ await wallet.deployPackage(memPackage);
+// returns the transaction hash
+```
diff --git a/gnovm/docs/go-gno-compatibility.md b/docs/reference/go-gno-compatibility.md
similarity index 99%
rename from gnovm/docs/go-gno-compatibility.md
rename to docs/reference/go-gno-compatibility.md
index 6ff433c056f..101c83a05c9 100644
--- a/gnovm/docs/go-gno-compatibility.md
+++ b/docs/reference/go-gno-compatibility.md
@@ -1,4 +1,8 @@
-# Go<>Gno compatibility
+---
+id: go-gno-compatibility
+---
+
+# Go - Gno compatibility
## Native keywords
diff --git a/docs/reference/rpc-endpoints.md b/docs/reference/rpc-endpoints.md
new file mode 100644
index 00000000000..790e4c49142
--- /dev/null
+++ b/docs/reference/rpc-endpoints.md
@@ -0,0 +1,502 @@
+---
+id: rpc-endpoints
+---
+
+# Gno RPC Endpoints
+
+## Common Parameters
+
+#### Response
+
+| Name | Type | Description |
+| --------------- | ------ | --------------------------------- |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | Object | (upon success) The result object. |
+| `error` | Object | (upon failure) The error object. |
+| `error.code` | Number | The error code. |
+| `error.message` | String | The error message. |
+| `error.data` | String | The error data. |
+
+## Health Check
+
+Call with the `/health` path when verifying that the node is running.
+
+#### Response
+
+| Name | Type | Description |
+| --------- | ------ | ---------------- |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | Object | {} |
+
+## Check Node Server Status
+
+Call with the `/status` path to check the information from a node.
+
+#### Response
+
+| Name | Type | Description |
+| --------- | ---------------- | ------------------------------------- |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[Status Result] | The result of the node server status. |
+
+#### Status Result
+
+| Name | Type | Description |
+| ---------------- | ------ | ----------------------------------- |
+| `node_info` | Object | General information about the node. |
+| `sync_info` | Object | The sync information. |
+| `validator_info` | Object | The validator information. |
+
+## Get Network Information
+
+Call with the `/net_info` path to check the network information from the node.
+
+#### Response
+
+| Name | Type | Description |
+| --------- | ----------------- | ------------------------ |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[NetInfo Result] | The network information. |
+
+#### NetInfo Result
+
+| Name | Type | Description |
+| ----------- | ---------- | ------------------ |
+| `listening` | Boolean | Enables listening. |
+| `listeners` | String \[] | List of listeners. |
+| `n_peers` | String | Number of peers. |
+| `peers` | String \[] | List of peers. |
+
+## Get Genesis Block Information
+
+Call with the `/genesis` path to retrieve information about the Genesis block from the node.
+
+#### Response
+
+| name | Type | Description |
+| --------- | ------ | ------------------------------ |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | Object | The Genesis block information. |
+
+## Get Consensus Parameters
+
+Call with the /consensus\_params path to check the consensus algorithm parameters at the specified height.
+
+#### Parameters
+
+| Name | Description |
+| -------- | ----------------- |
+| `height` | The block height. |
+
+#### Response
+
+| Name | Type | Description |
+| --------- | -------------------------- | ------------------------------------ |
+| `jsonrpc` | String | The RPC Version. |
+| `id` | String | The response ID. |
+| `result` | \[Consensus Params Result] | The consensus parameter information. |
+
+#### Consensus Params Result
+
+| Name | Type | Description |
+| ----------------------------- | ------ | -------------------------- |
+| `block_height` | String | The block height. |
+| `consensus_params` | Object | The parameter information. |
+| `consensus_params.Block` | Object | The block parameters. |
+| `consensus_params.Validattor` | Object | The validator parameters. |
+
+## Get Consensus State
+
+Call with the `/consensus_state` to get the consensus state of the Gnoland blockchain
+
+#### Response
+
+| Name | Type | Description |
+| ------- | --------------------------- | -------------------------------- |
+| jsonrpc | String | The RPC version. |
+| id | String | The response ID. |
+| result | \[Consensus State Response] | The consensus state information. |
+
+#### Consensus State Response
+
+| Name | Type | Description |
+| --------------------------------- | ------ | -------------------------------- |
+| `round_state` | Object | The consensus state object. |
+| `round_state.height/round/step` | String | The block height / round / step. |
+| `round_state.start_time` | String | The round start time. |
+| `round_state.proposal_block_hash` | String | The proposal block hash. |
+| `round_state.locked_block_hash` | String | The locked block hash. |
+| `round_state.valid_block_hash` | String | The valid block hash. |
+| `round_state.height_vote_set` | Object | - |
+
+## Get Commit
+
+Call with the `/commit` path to retrieve commit information at the specified block height.
+
+#### Parameters
+
+| Name | Description |
+| -------- | ----------------- |
+| `height` | The block height. |
+
+#### Response
+
+| Name | Type | Description |
+| --------- | ---------------- | ----------------------- |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[Commit Result] | The commit information. |
+
+#### Commit Result
+
+| Name | Type | Description |
+| -------------- | ------- | ------------------------- |
+| signed\_header | Object | The signed header object. |
+| canonical | Boolean | Returns commit state. |
+
+## Get Block Information
+
+Call with the `/block` path to retrieve block information at the specified height.
+
+#### Parameters
+
+| Name | Description |
+| -------- | ----------------- |
+| `height` | The block height. |
+
+#### Response
+
+| Name | Type | Description |
+| --------- | --------------- | ----------------------- |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[Block Result] | The commit information. |
+
+#### Block Result
+
+| Name | Type | Description |
+| ------------ | ------ | ---------------------- |
+| `block_meta` | Object | The block metadata. |
+| `block` | Object | The block information. |
+
+## Get Block Results
+
+Call with the `/block_results` path to retrieve block processing information at the specified height.
+
+#### Parameters
+
+| Name | Description |
+| -------- | ----------------- |
+| `height` | The block height. |
+
+#### Response
+
+| Name | Type | Description |
+| --------- | --------------- | ------------------ |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[Block Result] | The result object. |
+
+#### Block Result
+
+| Name | Type | Description |
+| --------- | ------------------------ | ------------------------------------- |
+| `height` | Object | The block height. |
+| `results` | \[Block Result Info] \[] | The list of block processing results. |
+
+#### Block Result Info
+
+| Name | Type | Description |
+| --------------------------- | ---------- | -------------------------------- |
+| `deliver_tx` | Object \[] | The list of transaction results. |
+| `deliver_tx[].ResponseBase` | Object | The transaction response object. |
+| `deliver_tx[].GasWanted` | String | Maximum amount of gas to use. |
+| `deliver_tx[].GasUsed` | String | Actual gas used. |
+| `begin_block` | Object | Previous block information. |
+| `end_block` | Object | Next block information. |
+
+## Get Block List
+
+Call with the `/blockchain` path to retrieve information about blocks within a specified range.
+
+#### Parameters
+
+| Name | Description |
+| ----------- | ------------------------- |
+| `minHeight` | The minimum block height. |
+| `maxHeight` | The maximum block height. |
+
+#### Response
+
+| Name | Type | Description |
+| --------- | -------------------- | ------------------ |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[Blockchain Result] | The result object. |
+
+#### Blockchain Result
+
+| Name | Type | Description |
+| ------------- | ---------- | --------------------------- |
+| `last_height` | String | The latest block height. |
+| `block_meta` | Object \[] | The list of block metadata. |
+
+## Get a No. of Unconfirmed Transactions
+
+Call with the `/num_unconfirmed_txs` path to get data about unconfirmed transactions.
+
+#### Response
+
+| Name | Type | Description |
+| --------- | ----------------------------- | ------------------ |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[Num Unconfirmed Txs Result] | The result object. |
+
+#### Num Unconfirmed Txs Result
+
+| Name | Type | Description |
+| ------------- | ------ | --------------------------- |
+| `n_txs` | String | The number of transactions. |
+| `total` | String | The total number. |
+| `total_bytes` | String | Total bytes. |
+| `txs` | null | - |
+
+## Get a List of Unconfirmed Transactions
+
+Call with the `/unconfirmed_txs` path to get a list of unconfirmed transactions.
+
+#### Parameters
+
+| Name | Description |
+| ------- | --------------------------------------- |
+| `limit` | The maximum transaction numbers to get. |
+
+#### Response
+
+| Name | Type | Description |
+| --------- | ------------------------- | ------------------ |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[Unconfirmed Txs Result] | The result object. |
+
+#### Unconfirmed Txs Result
+
+| Name | Type | Description |
+| ------------- | ---------- | ----------------------------------- |
+| `n_txs` | String | The number of transactions. |
+| `total` | String | The total number. |
+| `total_bytes` | String | Total bytes. |
+| `txs` | Object \[] | A list of unconfirmed transactions. |
+
+## Get a List of Validators
+
+Call with the `/validators` path to get a list of validators at a specific height.
+
+#### Parameters
+
+| Name | Description |
+| -------- | ----------------------------------------- |
+| `height` | The block height (default: newest block). |
+
+#### Response
+
+| Name | Type | Description |
+| --------- | -------------------- | ------------------ |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[Validators Result] | The result object. |
+
+#### Validators Result
+
+| Name | Type | Description |
+| -------------- | ---------------- | ----------------------- |
+| `block_height` | Object | The block height. |
+| `validators` | \[Validator] \[] | The list of validators. |
+
+#### Validator
+
+| Name | Type | Description |
+| ------------------- | ---------- | ---------------------------------------- |
+| `address` | String | The address of the validator. |
+| `pub_key` | Object \[] | The public key object of the validator. |
+| `pub_key.@type` | String | The type of validator's public key. |
+| `pub_key.value` | String | The value of the validator's public key. |
+| `voting_power` | String | Voting power of the validator. |
+| `proposer_priority` | String | The priority of the proposer. |
+
+## Broadcast a Transaction - Asynchronous
+
+Call with the `/broadcast_tx_async` path to create and broadcast a transaction without waiting for the transaction response.
+
+#### Parameters
+
+| Name | Description |
+| ---- | ------------------------------------------- |
+| `tx` | The value of the signed transaction binary. |
+
+#### Response
+
+| Name | Type | Description |
+| --------- | --------------------- | ------------------ |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[Transaction Result] | The result object. |
+
+#### Transaction Result
+
+| Name | Type | Description |
+| ----- | ------ | ---------------------------- |
+| hash | String | The transaction hash. |
+| data | Object | The transaction data object. |
+| error | Object | The error object. |
+| log | String | The log information. |
+
+## Broadcast a Transaction - Synchronous
+
+Call with the `/broadcast_tx_sync` path to create and broadcast a transaction, then wait for the transaction response.
+
+#### Parameters
+
+| Name | Description |
+| ---- | ------------------------------------------- |
+| `tx` | The value of the signed transaction binary. |
+
+#### Response
+
+| Name | Type | Description |
+| --------- | --------------------- | ------------------ |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[Transaction Result] | The result object. |
+
+#### Transaction Result
+
+| Name | Type | Description |
+| ----- | ------ | ---------------------------- |
+| hash | String | The transaction hash. |
+| data | Object | The transaction data object. |
+| error | Object | The error object. |
+| log | String | The log information. |
+
+## (NOT RECOMMENDED) Broadcast Transaction and Get Commit Information
+
+Call with the `/broadcast_tx_commit` path to create and broadcast a transaction, then wait for the transaction response and the commit response.
+
+#### Parameters
+
+| Name | Description |
+| ---- | ------------------------------------------- |
+| `tx` | The value of the signed transaction binary. |
+
+#### Response
+
+| Name | Type | Description |
+| --------- | ---------------------------- | ------------------ |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[Transaction Commit Result] | The result object. |
+
+#### Transaction Commit Result
+
+| Name | Type | Description |
+| ------------ | ------ | ----------------------------------------------------------- |
+| `height` | String | The height of the block when the transaction was committed. |
+| hash | String | The transaction hash. |
+| `deliver_tx` | Object | The delivered transaction information. |
+| `check_tx` | Object | The committed transaction information. |
+
+## ABCI
+
+### Get ABCI Information
+
+Call with the `/abci_info` path to get the latest information about the ABCI.
+
+#### Response
+
+| Name | Type | Description |
+| --------- | ------------------- | ----------------------- |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[ABCI Info Result] | The commit information. |
+
+#### ABCI Info Result
+
+| Name | Type | Description |
+| --------------------------- | ---------------- | -------------------------- |
+| `response` | Object | The metadata of the block. |
+| `response.ResponseBase` | \[ABCI Response] | The ABCI response data. |
+| `response.ABCIVersion` | String | The ABCI version. |
+| `response.AppVersion` | String | The app version. |
+| `response.LastBlockHeight` | String | The latest block height. |
+| `response.LastBlockAppHash` | String | The latest block hash. |
+
+#### ABCI Response
+
+| Name | Type | Description |
+| ------ | ---------- | --------------------------------- |
+| Data | String | The Base64-encoded response data. |
+| Error | Object | The ABCI response error object. |
+| Events | Object \[] | The list of event objects. |
+| Log | String | The ABCI response log. |
+| Info | String | The ABCI response information. |
+
+### Get ABCI Query
+
+Call with the `/abci_query` to get information via the ABCI Query.
+
+#### Query
+
+| Name | Description |
+| ------------------------- | ------------------------------------------------------------------ |
+| `auth/accounts/{ADDRESS}` | Returns the account information. |
+| `bank/balances/{ADDRESS}` | Returns the balance information about the account. |
+| `vm/qfuncs` | Returns public facing function signatures as JSON. |
+| `vm/qfile` | Returns the file bytes, or list of files if directory. |
+| `vm/qrender` | Calls `.Render()` in readonly mode. |
+| `vm/qeval` | Evaluates any expression in readonly mode and returns the results. |
+| `vm/store` | (not yet supported) Fetches items from the store. |
+| `vm/package` | (not yet supported) Fetches a package's files. |
+
+#### Parameters
+
+| Name | Description |
+| ------------------- | ------------------------------------------------ |
+| `path` | The query path. |
+| `data` | The data from the query path. |
+| (optional) `height` | The block height (default: latest block height). |
+| (optional) `prove` | The validation status. |
+
+#### Response
+
+| Name | Type | Description |
+| --------- | -------------------- | ----------------------- |
+| `jsonrpc` | String | The RPC version. |
+| `id` | String | The response ID. |
+| `result` | \[ABCI Query Result] | The commit information. |
+
+#### ABCI Query Result
+
+| Name | Type | Description |
+| ----------------------- | ---------------- | -------------------------- |
+| `response` | Object | The metadata of the block. |
+| `response.ResponseBase` | \[ABCI Response] | The ABCI response data. |
+| `response.Key` | String | The key. |
+| `response.Value` | String | The value. |
+| `response.Proof` | String | The validation ID. |
+| `response.Height` | String | The block height. |
+
+#### ABCI Response
+
+| Name | Type | Description |
+| ------ | ---------- | --------------------------------- |
+| Data | String | The Base64-encoded response data. |
+| Error | Object | The ABCI response error object. |
+| Events | Object \[] | The list of event objects. |
+| Log | String | The ABCI response log. |
+| Info | String | The ABCI response information. |
diff --git a/docs/reference/standard-library.md b/docs/reference/standard-library.md
new file mode 100644
index 00000000000..71fad4943e6
--- /dev/null
+++ b/docs/reference/standard-library.md
@@ -0,0 +1,68 @@
+---
+id: standard-library
+---
+
+# Gno Standard Library
+
+When developing a realm in Gnolang, developers may utilize libraries in [stdlibs](https://github.com/gnolang/gno/tree/master/stdlibs). These are the core standard packages provided for Gnolang [Realms ](../explanation/realms.md)& [Packages](../explanation/packages.md).
+
+Libraries can be imported in a manner similar to how libraries are imported in Golang.
+
+An example of importing a `std` library in Gnolang is demonstrated in the following command:
+
+```go
+import "std"
+```
+
+Let's explore some of the most commonly used modules in the library.
+
+## `stdshim`
+
+### `banker.gno`
+
+A library for manipulating `Coins`. Interfaces that must be implemented when using this library are as follows:
+
+[embedmd]:# (../assets/reference/standard-library/std-1.gno go)
+```go
+// returns the list of coins owned by the address
+GetCoins(addr Address) (dst Coins)
+
+// sends coins from one address to another
+SendCoins(from, to Address, amt Coins)
+
+// returns the total supply of the coin
+TotalCoin(denom string) int64
+
+// issues coins to the address
+IssueCoin(addr Address, denom string, amount int64)
+
+// burns coins from the address
+RemoveCoin(addr Address, denom string, amount int64)
+```
+
+### `coins.gno`
+
+A library that declares structs for expressing `Coins`. The struct looks like the following:
+
+[embedmd]:# (../assets/reference/standard-library/std-2.gno go)
+```go
+type Coin struct {
+ Denom string `json:"denom"` // the symbol of the coin
+ Amount int64 `json:"amount"` // the quantity of the coin
+}
+```
+
+### `testing`
+
+A library that declares `*testing`, which is a tool used for the creation and execution of test cases during the development and testing phase of realms utilizing the `gno` CLI tool with the `test` option.
+
+There are 3 types of testing in `gno`.
+
+* Type `T`
+ * Type passed to Test functions to manage test state and support formatted test logs.
+* Type `B`
+ * Type passed to Benchmark functions.
+ * Manage benchmark timing.
+ * Specify the number of iterations to run.
+* Type `PB`
+ * Used by `RunParallel` for running parallel benchmarks.
diff --git a/docs/reference/tm2-js-client/Provider/json-rpc-provider.md b/docs/reference/tm2-js-client/Provider/json-rpc-provider.md
new file mode 100644
index 00000000000..b7700e1d97c
--- /dev/null
+++ b/docs/reference/tm2-js-client/Provider/json-rpc-provider.md
@@ -0,0 +1,22 @@
+---
+id: tm2-js-json-rpc-provider
+---
+
+# JSON-RPC Provider
+
+Provider based on JSON-RPC HTTP requests.
+
+### new JSONRPCProvider
+
+Creates a new instance of the JSON-RPC Provider
+
+#### Parameters
+
+* `baseURL` **string** the JSON-RPC URL of the node
+
+#### Usage
+
+```ts
+new JSONRPCProvider('http://staging.gno.land:36657');
+// provider is created
+```
diff --git a/docs/reference/tm2-js-client/Provider/provider.md b/docs/reference/tm2-js-client/Provider/provider.md
new file mode 100644
index 00000000000..da6168eb6c2
--- /dev/null
+++ b/docs/reference/tm2-js-client/Provider/provider.md
@@ -0,0 +1,443 @@
+---
+id: tm2-js-provider
+---
+
+# Overview
+
+A `Provider` is an interface that abstracts the interaction with the Tendermint2 chain, making it easier for users to
+communicate with it. Rather than requiring users to understand which endpoints are exposed, what their return types are,
+and how they are parsed, the `Provider` abstraction handles all of this behind the scenes. It exposes useful API methods
+that users can use and expects concrete types in return.
+
+Currently, the `tm2-js-client` package provides support for two Provider implementations:
+
+- [JSON-RPC Provider](json-rpc-provider.md): executes each call as a separate HTTP RPC call.
+- [WS Provider](ws-provider.md): executes each call through an active WebSocket connection, which requires closing when
+ not needed anymore.
+
+## Account Methods
+
+### getBalance
+
+Fetches the denomination balance of the account
+
+#### Parameters
+
+* `address` **string** the bech32 address of the account
+* `denomination` **string** the balance denomination (optional, default `ugnot`)
+* `height` **number** the height for querying.
+ If omitted, the latest height is used (optional, default `0`)
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.getBalance('g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq', 'atom');
+// 100
+```
+
+### getAccountSequence
+
+Fetches the account sequence
+
+#### Parameters
+
+* `address` **string** the bech32 address of the account
+* `height` **number** the height for querying.
+ If omitted, the latest height is used. (optional, default `0`)
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.getAccountSequence('g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq');
+// 42
+```
+
+### getAccountNumber
+
+Fetches the account number. Errors out if the account
+is not initialized
+
+#### Parameters
+
+* `address` **string** the bech32 address of the account
+* `height` **number** the height for querying.
+ If omitted, the latest height is used (optional, default `0`)
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.getAccountNumber('g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq');
+// 100
+```
+
+## Block methods
+
+### getBlock
+
+Fetches the block at the specific height, if any
+
+#### Parameters
+
+* `height` **number** the height for querying
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.getBlock(1);
+/*
+{
+ block_meta: {
+ block_id: {
+ hash: "TxHKEGxFm/4+D7gxOJdVUaR+xTDZzlPrCVXuVm7SqHw=",
+ parts: {
+ total: "1",
+ hash: "+dqI9oyngnnlKyno7y+RxCLEPA9FxWA/MmXyJ4uoJAY="
+ }
+ },
+ header: {
+ version: "v1.0.0-rc.0",
+ chain_id: "dev",
+ height: "1",
+ time: "2023-05-01T10:32:20.807541Z",
+ num_txs: "0",
+ total_txs: "0",
+ app_version: "",
+ last_block_id: {
+ hash: null,
+ parts: {
+ total: "0",
+ hash: null
+ }
+ },
+ last_commit_hash: null,
+ data_hash: null,
+ validators_hash: "FnuBaDvDLg4FotGRcZAFvhLkEjkb+kNLaAZrAVhL5Aw=",
+ next_validators_hash: "FnuBaDvDLg4FotGRcZAFvhLkEjkb+kNLaAZrAVhL5Aw=",
+ consensus_hash: "uKhnXFmGUkxgQSJf17ogbYLNXDo3UEPwQvzddo4Vkuw=",
+ app_hash: null,
+ last_results_hash: null,
+ proposer_address: "g1vsqzyy9a4h9ah8cxzkaw09rpzy369mkl70lfdk"
+ }
+ },
+ block: {
+ header: {
+ version: "v1.0.0-rc.0",
+ chain_id: "dev",
+ height: "1",
+ time: "2023-05-01T10:32:20.807541Z",
+ num_txs: "0",
+ total_txs: "0",
+ app_version: "",
+ last_block_id: {
+ hash: null,
+ parts: {
+ total: "0",
+ hash: null
+ }
+ },
+ last_commit_hash: null,
+ data_hash: null,
+ validators_hash: "FnuBaDvDLg4FotGRcZAFvhLkEjkb+kNLaAZrAVhL5Aw=",
+ next_validators_hash: "FnuBaDvDLg4FotGRcZAFvhLkEjkb+kNLaAZrAVhL5Aw=",
+ consensus_hash: "uKhnXFmGUkxgQSJf17ogbYLNXDo3UEPwQvzddo4Vkuw=",
+ app_hash: null,
+ last_results_hash: null,
+ proposer_address: "g1vsqzyy9a4h9ah8cxzkaw09rpzy369mkl70lfdk"
+ },
+ data: {
+ txs: null
+ },
+ last_commit: {
+ block_id: {
+ hash: null,
+ parts: {
+ total: "0",
+ hash: null
+ }
+ },
+ precommits: null
+ }
+ }
+}
+*/
+```
+
+### getBlockResult
+
+Fetches the block at the specific height, if any
+
+#### Parameters
+
+* `height` **number** the height for querying
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.getBlockResult(1);
+/*
+{
+ height: "1",
+ results: {
+ deliver_tx: null,
+ end_block: {
+ ResponseBase: {
+ Error: null,
+ Data: null,
+ Events: null,
+ Log: "",
+ Info: ""
+ },
+ ValidatorUpdates: null,
+ ConsensusParams: null,
+ Events: null
+ },
+ begin_block: {
+ ResponseBase: {
+ Error: null,
+ Data: null,
+ Events: null,
+ Log: "",
+ Info: ""
+ }
+ }
+ }
+}
+*/
+```
+
+### getBlockNumber
+
+Fetches the latest block number from the chain
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.getBlockNumber();
+// 1300
+```
+
+## Network methods
+
+### getNetwork
+
+Fetches the network information
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.getNetwork();
+/*
+{
+ listening: true,
+ listeners: [
+ "Listener(@)"
+ ],
+ n_peers: "0",
+ peers: []
+}
+*/
+```
+
+### getConsensusParams
+
+Fetches the consensus params for the specific block height
+
+#### Parameters
+
+* `height` **number** the height for querying
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.getConsensusParams(1);
+/*
+{
+ block_height: "1",
+ consensus_params: {
+ Block: {
+ MaxTxBytes: "1000000",
+ MaxDataBytes: "2000000",
+ MaxBlockBytes: "0",
+ MaxGas: "10000000",
+ TimeIotaMS: "100"
+ },
+ Validator: {
+ PubKeyTypeURLs: [
+ "/tm.PubKeyEd25519"
+ ]
+ }
+ }
+}
+*/
+```
+
+### getStatus
+
+Fetches the current node status
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.getStatus();
+/*
+{
+ node_info: {
+ version_set: [
+ {
+ Name: "abci",
+ Version: "v1.0.0-rc.0",
+ Optional: false
+ },
+ {
+ Name: "app",
+ Version: "",
+ Optional: false
+ },
+ {
+ Name: "bft",
+ Version: "v1.0.0-rc.0",
+ Optional: false
+ },
+ {
+ Name: "blockchain",
+ Version: "v1.0.0-rc.0",
+ Optional: false
+ },
+ {
+ Name: "p2p",
+ Version: "v1.0.0-rc.0",
+ Optional: false
+ }
+ ],
+ net_address: "g1z0wa6rspsshkm2k7jlqvnjs8jdt4kvg4e9j640@0.0.0.0:26656",
+ network: "dev",
+ software: "",
+ version: "v1.0.0-rc.0",
+ channels: "QCAhIiMw",
+ moniker: "voyager.lan",
+ other: {
+ tx_index: "off",
+ rpc_address: "tcp://127.0.0.1:26657"
+ }
+ },
+ sync_info: {
+ latest_block_hash: "x5ewEBhf9+MGXbEFkUdOm3RsE40D+plUia2u0PuVfHs=",
+ latest_app_hash: "7dB/+EmqLqEX2RkH2Zx+GcFo8c2vTs2ttW8urYyyFT4=",
+ latest_block_height: "55",
+ latest_block_time: "2023-05-06T11:28:35.643575Z",
+ catching_up: false
+ },
+ validator_info: {
+ address: "g1vsqzyy9a4h9ah8cxzkaw09rpzy369mkl70lfdk",
+ pub_key: {
+ "@type": "/tm.PubKeyEd25519",
+ value: "X8ZS1DYu1eJ3HYnZ0OWk+0GgCdI7zA++kgWiprWMs3w="
+ },
+ voting_power: "0"
+ }
+}
+*/
+```
+
+### getGasPrice
+
+**NOTE: Not supported yet**
+
+Fetches the current (recommended) average gas price
+
+Returns **Promise**
+
+### estimateGas
+
+**NOTE: Not supported yet**
+
+Estimates the gas limit for the transaction
+
+#### Parameters
+
+* `tx` **Tx** the transaction that needs estimating
+
+Returns **Promise**
+
+## Transaction methods
+
+### sendTransaction
+
+Sends the transaction to the node for committing and returns the transaction hash.
+The transaction needs to be signed beforehand.
+
+#### Parameters
+
+* `tx` **string** the base64-encoded signed transaction
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.sendTransaction('ZXhhbXBsZSBzaWduZWQgdHJhbnNhY3Rpb24');
+// "dHggaGFzaA=="
+```
+
+### waitForTransaction
+
+Waits for the transaction to be committed on the chain.
+NOTE: This method will not take in the fromHeight parameter once
+proper transaction indexing is added - the implementation should
+simply try to fetch the transaction first to see if it's included in a block
+before starting to wait for it; Until then, this method should be used
+in the sequence:
+get latest block -> send transaction -> waitForTransaction(block before send)
+
+#### Parameters
+
+* `hash` **string** The transaction hash
+* `fromHeight` **number** The block height used to begin the search (optional, default `latest`)
+* `timeout` **number** Optional wait timeout in MS (optional, default `15000`)
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await provider.waitForTransaction('ZXhhbXBsZSBzaWduZWQgdHJhbnNhY3Rpb24');
+/*
+{
+ messages:[], // should be filled with the appropriate message type
+ fee:{
+ gasWanted: "100",
+ gasFee: "1ugnot"
+ },
+ signatures:[
+ {
+ pubKey:[
+ {
+ type: "/tm.PubKeySecp256k1"
+ value: "X8ZS1DYu1eJ3HYnZ0OWk+0GgCdI7zA++kgWiprWMs3w="
+ }
+ ],
+ signature: "X8ZS1DYu1eJ3HYnZ0OWk+0GgCdI7zA++kgWiprWMs3w="
+ }
+ ],
+ memo: "check out gno.land!"
+}
+*/
+```
diff --git a/docs/reference/tm2-js-client/Provider/utility.md b/docs/reference/tm2-js-client/Provider/utility.md
new file mode 100644
index 00000000000..3f0181ccc39
--- /dev/null
+++ b/docs/reference/tm2-js-client/Provider/utility.md
@@ -0,0 +1,116 @@
+---
+id: tm2-js-utility
+---
+
+# Utility Helpers
+
+## Provider Helpers
+
+### extractBalanceFromResponse
+
+Extracts the specific balance denomination from the ABCI response
+
+#### Parameters
+
+* `abciData` **(string | null)** the base64-encoded ABCI data
+* `denomination` **string** the required denomination
+
+### extractSequenceFromResponse
+
+Extracts the account sequence from the ABCI response
+
+#### Parameters
+
+* `abciData` **(string | null)** the base64-encoded ABCI data
+
+Returns **number**
+
+### extractAccountNumberFromResponse
+
+Extracts the account number from the ABCI response
+
+#### Parameters
+
+* `abciData` **(string | null)** the base64-encoded ABCI data
+
+Returns **number**
+
+### waitForTransaction
+
+Waits for the transaction to be committed to a block in the chain
+of the specified provider. This helper does a search for incoming blocks
+and checks if a transaction
+
+#### Parameters
+
+* `provider` **Provider** the provider instance
+* `hash` **string** the base64-encoded hash of the transaction
+* `fromHeight` **number** the starting height for the search. If omitted, it is the latest block in the chain (
+ optional, default `latest`)
+* `timeout` **number** the timeout in MS for the search (optional, default `15000`)
+
+Returns **Promise**
+
+## Request Helpers
+
+### newRequest
+
+Creates a new JSON-RPC 2.0 request
+
+#### Parameters
+
+* `method` **string** the requested method
+* `params` **Array?** the requested params, if any
+
+Returns **RPCRequest**
+
+### newResponse
+
+Creates a new JSON-RPC 2.0 response
+
+#### Parameters
+
+* `result` **Result** the response result, if any
+* `error` **RPCError** the response error, if any
+
+Returns **RPCResponse**
+
+### parseABCI
+
+Parses the base64 encoded ABCI JSON into a concrete type
+
+#### Parameters
+
+* `data` **string** the base64-encoded JSON
+
+Returns **Result**
+
+### stringToBase64
+
+Converts a string into base64 representation
+
+#### Parameters
+
+* `str` **string** the raw string
+
+Returns **string**
+
+### base64ToUint8Array
+
+Converts a base64 string into a Uint8Array representation
+
+#### Parameters
+
+* `str` **string** the base64-encoded string
+
+Returns **Uint8Array**
+
+### uint8ArrayToBase64
+
+Converts a Uint8Array into base64 representation
+
+#### Parameters
+
+* `data` **Uint8Array** the Uint8Array to be encoded
+
+Returns **string**
diff --git a/docs/reference/tm2-js-client/Provider/ws-provider.md b/docs/reference/tm2-js-client/Provider/ws-provider.md
new file mode 100644
index 00000000000..ef91f45d4e2
--- /dev/null
+++ b/docs/reference/tm2-js-client/Provider/ws-provider.md
@@ -0,0 +1,95 @@
+---
+id: tm2-js-ws-provider
+---
+
+# WebSocket Provider
+
+Provider based on WS JSON-RPC requests.
+
+### new WSProvider
+
+Creates a new instance of the WebSocket Provider
+
+#### Parameters
+
+* `baseURL` **string** the WS URL of the node
+* `requestTimeout` **number** the timeout for the WS request (in MS)
+
+#### Usage
+
+```ts
+new WSProvider('ws://staging.gno.land:36657/ws');
+// provider with WS connection is created
+```
+
+### closeConnection
+
+Closes the WS connection. Required when done working
+with the WS provider
+
+#### Usage
+
+```ts
+const wsProvider = new WSProvider('ws://staging.gno.land:36657/ws');
+
+wsProvider.closeConnection();
+// WS connection is now closed
+```
+
+### sendRequest
+
+Sends a request to the WS connection, and resolves
+upon receiving the response
+
+#### Parameters
+
+* `request` **RPCRequest** the RPC request
+
+Returns **Promise>**
+
+#### Usage
+
+```ts
+const request: RPCRequest = // ...
+
+const wsProvider = new WSProvider('ws://staging.gno.land:36657/ws');
+
+wsProvider.sendRequest(request);
+// request is sent over the open WS connection
+```
+
+### parseResponse
+
+Parses the result from the response
+
+#### Parameters
+
+* `response` **RPCResponse** the response to be parsed
+
+Returns **Result**
+
+#### Usage
+
+```ts
+const response: RPCResponse = // ...
+
+const wsProvider = new WSProvider('ws://staging.gno.land:36657/ws');
+
+wsProvider.parseResponse(response);
+// response is parsed
+```
+
+### waitForOpenConnection
+
+Waits for the WS connection to be established
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+const wsProvider = new WSProvider('ws://staging.gno.land:36657/ws');
+
+await wsProvider.waitForOpenConnection()
+// status of the connection is: CONNECTED
+```
diff --git a/docs/reference/tm2-js-client/Signer/key.md b/docs/reference/tm2-js-client/Signer/key.md
new file mode 100644
index 00000000000..3c40fa427d2
--- /dev/null
+++ b/docs/reference/tm2-js-client/Signer/key.md
@@ -0,0 +1,30 @@
+---
+id: tm2-js-key
+---
+
+# Key Signer
+
+Private key-based signer instance
+
+### new KeySigner
+
+Creates a new instance of the private-key KeySigner
+
+#### Parameters
+
+* `privateKey` **Uint8Array** the raw Secp256k1 private key
+* `publicKey` **Uint8Array** the raw Secp256k1 public key
+* `addressPrefix` **string** the address prefix
+
+#### Usage
+
+```ts
+// Generate the public / private key from somewhere
+const {publicKey, privateKey} = await generateKeyPair(
+ entropyToMnemonic(generateEntropy()),
+ index ? index : 0
+);
+
+new KeySigner(privateKey, publicKey);
+// new Secp256k1 key signer created
+```
diff --git a/docs/reference/tm2-js-client/Signer/ledger.md b/docs/reference/tm2-js-client/Signer/ledger.md
new file mode 100644
index 00000000000..71a7682c3e3
--- /dev/null
+++ b/docs/reference/tm2-js-client/Signer/ledger.md
@@ -0,0 +1,27 @@
+---
+id: tm2-js-ledger
+---
+
+# Ledger Signer
+
+Ledger device-based signer instance
+
+### new LedgerSigner
+
+Creates a new instance of the Ledger device signer, using the provided `LedgerConnector`
+
+#### Parameters
+
+* `connector` **LedgerConnector** the Ledger connector
+* `accountIndex` **number** the desired account index
+* `addressPrefix` **string** the address prefix
+
+#### Usage
+
+```ts
+const accountIndex: number = 10 // for ex. 10th account in the derivation
+const connector: LedgerConnector = // ...
+
+new LedgerSigner(connector, accountIndex);
+// new Ledger device signer created
+```
diff --git a/docs/reference/tm2-js-client/Signer/signer.md b/docs/reference/tm2-js-client/Signer/signer.md
new file mode 100644
index 00000000000..fd3945cc2ae
--- /dev/null
+++ b/docs/reference/tm2-js-client/Signer/signer.md
@@ -0,0 +1,96 @@
+---
+id: tm2-js-signer
+---
+
+# Overview
+
+A `Signer` is an interface that abstracts the interaction with a single Secp256k1 key pair. It exposes methods for
+signing data, verifying signatures, and getting metadata associated with the key pair, such as the address.
+
+Currently, the `tm2-js-client` package provides support for two `Signer` implementations:
+
+- [Key](key.md): a signer that is based on a raw Secp256k1 key pair.
+- [Ledger](ledger.md): a signer that is based on a Ledger device, with all interaction flowing through the user's
+ device.
+
+## API
+
+### getAddress
+
+Returns the address associated with the signer's public key
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await signer.getAddress();
+// "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq"
+```
+
+### getPublicKey
+
+Returns the signer's Secp256k1-compressed public key
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await signer.getPublicKey();
+//
+```
+
+### getPrivateKey
+
+Returns the signer's actual raw private key
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await signer.getPrivateKey();
+//
+```
+
+### signData
+
+Generates a data signature for arbitrary input
+
+#### Parameters
+
+* `data` **Uint8Array** the data to be signed
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+const dataToSign: Uint8Array = // ...
+
+ await signer.signData(dataToSign);
+//
+```
+
+### verifySignature
+
+Verifies if the signature matches the provided raw data
+
+#### Parameters
+
+* `data` **Uint8Array** the raw data (not-hashed)
+* `signature` **Uint8Array** the hashed-data signature
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+const signedData: Uint8Array = // ...
+const rawData: Uint8Array = // ...
+
+ await signer.verifySignature(rawData, signedData);
+//
+```
+
diff --git a/docs/reference/tm2-js-client/getting-started.md b/docs/reference/tm2-js-client/getting-started.md
new file mode 100644
index 00000000000..4a20ce2684f
--- /dev/null
+++ b/docs/reference/tm2-js-client/getting-started.md
@@ -0,0 +1,65 @@
+---
+id: tm2-js-getting-started
+---
+
+# Getting Started
+
+[@gnolang/tm2-js-client](https://github.com/gnolang/tm2-js-client) is a JavaScript/TypeScript client implementation for
+Tendermint2-based chains. It is designed to make it
+easy for developers to interact with TM2 chains, providing a simplified API for account and transaction management. By
+doing all the heavy lifting behind the scenes, `@gnolang/tm2-js-client` enables developers to focus on what really
+matters -
+building their dApps.
+
+## Key Features
+
+- JSON-RPC and WebSocket client support via a `Provider`
+- Simple account and transaction management API with a `Wallet`
+- Designed for easy extension for custom TM2 chains, such as [Gnoland](https://gno.land)
+
+## Installation
+
+To install `@gnolang/tm2-js-client`, use your preferred package manager:
+
+```bash
+yarn add @gnolang/tm2-js-client
+```
+
+```bash
+npm install @gnolang/tm2-js-client
+```
+
+## Common Terminology
+
+### Provider
+
+A `Provider` is an interface that abstracts the interaction with the Tendermint2 chain, making it easier for users to
+communicate with it. Rather than requiring users to understand which endpoints are exposed, what their return types are,
+and how they are parsed, the `Provider` abstraction handles all of this behind the scenes. It exposes useful API methods
+that users can use and expects concrete types in return.
+
+Currently, the `@gnolang/tm2-js-client` package provides support for two Provider implementations:
+
+- `JSON-RPC Provider`: executes each call as a separate HTTP RPC call.
+- `WS Provider`: executes each call through an active WebSocket connection, which requires closing when not needed
+ anymore.
+
+### Signer
+
+A `Signer` is an interface that abstracts the interaction with a single Secp256k1 key pair. It exposes methods for
+signing data, verifying signatures, and getting metadata associated with the key pair, such as the address.
+
+Currently, the `@gnolang/tm2-js-client` package provides support for two `Signer` implementations:
+
+- `Key`: a signer that is based on a raw Secp256k1 key pair.
+- `Ledger`: a signer that is based on a Ledger device, with all interaction flowing through the user's device.
+
+### Wallet
+
+A `Wallet` is a user-facing API that is used to interact with an account. A `Wallet` instance is tied to a single key
+pair and essentially wraps the given `Provider` for that specific account.
+
+A wallet can be generated from a randomly generated seed, a private key, or instantiated using a Ledger device.
+
+Using the `Wallet`, users can easily interact with the Tendermint2 chain using their account without having to worry
+about account management.
diff --git a/docs/reference/tm2-js-client/wallet.md b/docs/reference/tm2-js-client/wallet.md
new file mode 100644
index 00000000000..8a6943dfc9a
--- /dev/null
+++ b/docs/reference/tm2-js-client/wallet.md
@@ -0,0 +1,275 @@
+---
+id: tm2-js-wallet
+---
+
+# Wallet
+
+A `Wallet` is a user-facing API that is used to interact with an account. A `Wallet` instance is tied to a single key
+pair and essentially wraps the given `Provider` for that specific account.
+
+A wallet can be generated from a randomly generated seed, a private key, or instantiated using a Ledger device.
+
+Using the `Wallet`, users can easily interact with the Tendermint2 chain using their account without having to worry
+about account management.
+
+## Initialization
+
+### createRandom
+
+Generates a private key-based wallet, using a random seed
+
+#### Parameters
+
+* `options?` **AccountWalletOption** the account options
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+const wallet: Wallet = await Wallet.createRandom();
+// random wallet created
+```
+
+### fromMnemonic
+
+Generates a bip39 mnemonic-based wallet
+
+#### Parameters
+
+* `mnemonic` **string** the bip39 mnemonic
+* `options?` **CreateWalletOptions** the wallet generation options
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+const mnemonic: string = // ...
+const wallet: Wallet = await Wallet.fromMnemonic(mnemonic);
+// wallet created from mnemonic
+```
+
+### fromPrivateKey
+
+Generates a private key-based wallet
+
+#### Parameters
+
+* `privateKey` **string** the private key
+* `options?` **AccountWalletOption** the wallet generation options
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+// Generate the private key from somewhere
+const {publicKey, privateKey} = await generateKeyPair(
+ entropyToMnemonic(generateEntropy()),
+ index ? index : 0
+);
+
+const wallet: Wallet = await Wallet.fromPrivateKey(privateKey);
+// wallet created from private key
+```
+
+### fromLedger
+
+Creates a Ledger-based wallet
+
+#### Parameters
+
+* `connector` **LedgerConnector** the Ledger device connector
+* `options?` **CreateWalletOptions** the wallet generation options
+
+Returns **Wallet**
+
+#### Usage
+
+```ts
+const connector: LedgerConnector = // ...
+
+const wallet: Wallet = await Wallet.fromLedger(connector);
+// wallet created from Ledger device connection
+```
+
+## Provider Methods
+
+### connect
+
+Connects the wallet to the specified Provider
+
+#### Parameters
+
+* `provider` **Provider** the active Provider, if any
+
+#### Usage
+
+```ts
+const provider: Provider = // ...
+
+ wallet.connect(provider);
+// Provider connected to Wallet
+```
+
+### getProvider
+
+Returns the connected provider, if any
+
+Returns **Provider**
+
+#### Usage
+
+```ts
+wallet.getProvider();
+// connected provider, if any (undefined if not)
+```
+
+## Account Methods
+
+### getAddress
+
+Fetches the address associated with the wallet
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await wallet.getAddress();
+// "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq"
+```
+
+### getSequence
+
+Fetches the account sequence for the wallet
+
+#### Parameters
+
+* `height` **number** the block height (optional, default `latest`)
+
+#### Usage
+
+```ts
+await wallet.getSequence();
+// 42
+```
+
+Returns **Promise**
+
+### getAccountNumber
+
+Fetches the account number for the wallet. Errors out if the
+account is not initialized
+
+#### Parameters
+
+* `height` **number** the block height (optional, default `latest`)
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await wallet.getAccountNumber();
+// 10
+```
+
+### getBalance
+
+Fetches the account balance for the specific denomination
+
+#### Parameters
+
+* `denomination` **string** the fund denomination (optional, default `ugnot`)
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await wallet.getBalance('ugnot');
+// 5000
+```
+
+### getGasPrice
+
+Fetches the current (recommended) average gas price
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await wallet.getGasPrice();
+// 63000
+```
+
+### estimateGas
+
+Estimates the gas limit for the transaction
+
+#### Parameters
+
+* `tx` **Tx** the transaction that needs estimating
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+const tx: Tx = // ...
+
+ await wallet.estimateGas(tx);
+// 120000
+```
+
+### signTransaction
+
+Generates a transaction signature, and appends it to the transaction
+
+#### Parameters
+
+* `tx` **Tx** the transaction to be signed
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+const tx: Tx = // ...
+
+ await wallet.signTransaction(tx);
+// transaction with appended signature
+```
+
+### sendTransaction
+
+Signs and sends the transaction. Returns the transaction hash (base-64)
+
+#### Parameters
+
+* `tx` **Tx** the unsigned transaction
+
+Returns **Promise**
+
+#### Usage
+
+```ts
+await wallet.sendTransaction(tx);
+// returns the transaction hash
+```
+
+### getSigner
+
+Returns the associated signer
+
+Returns **Signer**
+
+#### Usage
+
+```ts
+wallet.getSigner(tx);
+// Signer instance
+```
diff --git a/misc/docusaurus/.gitignore b/misc/docusaurus/.gitignore
new file mode 100644
index 00000000000..b2d6de30624
--- /dev/null
+++ b/misc/docusaurus/.gitignore
@@ -0,0 +1,20 @@
+# Dependencies
+/node_modules
+
+# Production
+/build
+
+# Generated files
+.docusaurus
+.cache-loader
+
+# Misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/misc/docusaurus/babel.config.js b/misc/docusaurus/babel.config.js
new file mode 100644
index 00000000000..e00595dae7d
--- /dev/null
+++ b/misc/docusaurus/babel.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+ presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
+};
diff --git a/misc/docusaurus/docusaurus.config.js b/misc/docusaurus/docusaurus.config.js
new file mode 100644
index 00000000000..0ff9e920acd
--- /dev/null
+++ b/misc/docusaurus/docusaurus.config.js
@@ -0,0 +1,158 @@
+// @ts-check
+// Note: type annotations allow type checking and IDEs autocompletion
+
+const lightCodeTheme = require("prism-react-renderer/themes/github");
+const darkCodeTheme = require("prism-react-renderer/themes/dracula");
+
+/** @type {import('@docusaurus/types').Config} */
+const config = {
+ title: "Gno.land Documentation",
+ favicon: "img/favicon.ico",
+ url: "https://docs.gno.land",
+ baseUrl: "/",
+
+ organizationName: "gnolang",
+ projectName: "gno",
+
+ onBrokenLinks: "throw",
+ onBrokenMarkdownLinks: "warn",
+
+ i18n: {
+ defaultLocale: "en",
+ locales: ["en"],
+ },
+
+ presets: [
+ [
+ "classic",
+ /** @type {import('@docusaurus/preset-classic').Options} */
+ ({
+ docs: {
+ path: "../../docs",
+ routeBasePath: "/",
+ sidebarPath: require.resolve("./sidebars.js"),
+ },
+ blog: false,
+ theme: {
+ customCss: require.resolve("./src/css/custom.css"),
+ },
+ }),
+ ],
+ ],
+
+ themeConfig:
+ /** @type {import('@docusaurus/preset-classic').ThemeConfig} */
+ ({
+ navbar: {
+ hideOnScroll: true,
+ title: "Gno.land",
+ logo: {
+ alt: "Gno.land Logo",
+ src: "img/logo.svg",
+ srcDark: "img/logo_light.svg",
+ },
+ items: [
+ {
+ type: "docSidebar",
+ sidebarId: "tutorialSidebar",
+ position: "left",
+ label: "Docs",
+ },
+ {
+ href: "https://github.com/gnolang/gno",
+ html: `
+ `,
+ position: "right",
+ },
+ ],
+ },
+ footer: {
+ style: "dark",
+
+ links: [
+ {
+ items: [
+ {
+ html: `
+