Skip to content

Commit

Permalink
feat: social feed and moderation dao by @hthieu1110
Browse files Browse the repository at this point in the history
  • Loading branch information
n0izn0iz committed Sep 18, 2023
1 parent ec523e7 commit fd76513
Show file tree
Hide file tree
Showing 59 changed files with 6,462 additions and 2 deletions.
42 changes: 42 additions & 0 deletions examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,45 @@ clean:
GOFMT_FLAGS ?= -w
fmt:
go run -modfile ../misc/devdeps/go.mod mvdan.cc/gofumpt $(GOFMT_FLAGS) `find . -name "*.gno"`

.PHONY: create.pkg
create.pkg:
gnokey maketx addpkg \
-deposit="1ugnot" \
-gas-fee="1ugnot" \
-gas-wanted="5000000" \
-broadcast="true" \
-pkgdir="." \
-pkgpath="gno.land/r/demo/social_feeds_v3" \
-chainid "teritori-1" \
-remote "https://testnet.gno.teritori.com:26657" \
test1

.PHONY: create.feed
create.feed:
gnokey maketx call \
-pkgpath "gno.land/r/demo/social_feeds_v4" \
-func "CreateFeed" \
-gas-fee 1000000ugnot \
-gas-wanted 3000000 \
-send "" \
-broadcast \
-args "teritori" \
-chainid "teritori-1" \
-remote "https://testnet.gno.teritori.com:26657" \
test1

.PHONE: create.post
create.post:
gnokey maketx call \
-pkgpath "gno.land/r/demo/social_feeds_v3" \
-func "CreatePost" \
-gas-fee 1000000ugnot \
-gas-wanted 2000000 \
-send "" \
-broadcast \
-args "1" \
-args "0" \
-args "2" \
-args '{"gifs": [], "files": [], "title": "", "message": "Hello world !", "hashtags": [], "mentions": [], "createdAt": "2023-08-03T01:39:45.522Z", "updatedAt": "2023-08-03T01:39:45.522Z"}' \
test1
34 changes: 34 additions & 0 deletions examples/gno.land/p/demo/binutils/binutils.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package binutils

import (
"encoding/binary"
"errors"
)

var ErrInvalidLengthPrefixedString = errors.New("invalid length-prefixed string")

func EncodeLengthPrefixedStringUint16BE(s string) []byte {
b := make([]byte, 2+len(s))
binary.BigEndian.PutUint16(b, uint16(len(s)))
copy(b[2:], s)
return b
}

func DecodeLengthPrefixedStringUint16BE(b []byte) (string, []byte, error) {
if len(b) < 2 {
return "", nil, ErrInvalidLengthPrefixedString
}
l := binary.BigEndian.Uint16(b)
if len(b) < 2+int(l) {
return "", nil, ErrInvalidLengthPrefixedString
}
return string(b[2 : 2+l]), b[l+2:], nil
}

func MustDecodeLengthPrefixedStringUint16BE(b []byte) (string, []byte) {
s, r, err := DecodeLengthPrefixedStringUint16BE(b)
if err != nil {
panic(err)
}
return s, r
}
1 change: 1 addition & 0 deletions examples/gno.land/p/demo/binutils/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module gno.land/p/demo/binutils
70 changes: 70 additions & 0 deletions examples/gno.land/p/demo/daodao/core_v6/dao_core.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package core

import (
"std"
"strings"

dao_interfaces "gno.land/p/demo/daodao/interfaces_v6"
"gno.land/p/demo/markdown_utils"
)

// TODO: add wrapper message handler to handle multiple proposal modules messages

type IDAOCore interface {
AddProposalModule(proposalMod dao_interfaces.IProposalModule)

VotingModule() dao_interfaces.IVotingModule
ProposalModules() []dao_interfaces.IProposalModule

Render(path string) string
}

type daoCore struct {
IDAOCore

votingModule dao_interfaces.IVotingModule
proposalModules []dao_interfaces.IProposalModule
}

func NewDAOCore(
votingModule dao_interfaces.IVotingModule,
proposalModules []dao_interfaces.IProposalModule,
) IDAOCore {
return &daoCore{
votingModule: votingModule,
proposalModules: proposalModules,
}
}

func (d *daoCore) VotingModule() dao_interfaces.IVotingModule {
return d.votingModule
}

func (d *daoCore) ProposalModules() []dao_interfaces.IProposalModule {
return d.proposalModules
}

func (d *daoCore) AddProposalModule(proposalMod dao_interfaces.IProposalModule) {
d.proposalModules = append(d.proposalModules, proposalMod)
}

func (d *daoCore) Render(path string) string {
s := "# DAO Core\n"
s += "This is a port of [DA0-DA0 contracts](https://github.com/DA0-DA0/dao-contracts)\n"
s += markdown_utils.Indent(d.votingModule.Render(path)) + "\n"
for _, propMod := range d.proposalModules {
s += markdown_utils.Indent(propMod.Render(path)) + "\n"
}
return s
}

func GetProposalModule(core IDAOCore, moduleIndex int) dao_interfaces.IProposalModule {
if moduleIndex < 0 {
panic("Module index must be >= 0")
}
mods := core.ProposalModules()
if moduleIndex >= len(mods) {
panic("invalid module index")
}
return mods[moduleIndex]
}
6 changes: 6 additions & 0 deletions examples/gno.land/p/demo/daodao/core_v6/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module gno.land/p/demo/daodao/core_v6

require (
"gno.land/p/demo/daodao/interfaces_v6" v0.0.0-latest
"gno.land/p/demo/markdown_utils" v0.0.0-latest
)
172 changes: 172 additions & 0 deletions examples/gno.land/p/demo/daodao/interfaces_v6/dao_interfaces.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package dao_interfaces

import (
"std"
"strconv"

"gno.land/p/demo/avl"
"gno.land/p/demo/jsonutil_v4"
)

type IVotingModule interface {
VotingPower(addr std.Address) uint64
TotalPower() uint64
Render(path string) string
}

type Ballot struct {
Power uint64
Vote Vote
Rationale string
}

func (b Ballot) ToJSON() string {
return jsonutil.FormatObject([]jsonutil.KeyValue{
{Key: "power", Value: b.Power},
{Key: "vote", Value: b.Vote},
{Key: "rationale", Value: b.Rationale},
})
}

type Votes struct {
Yes uint64
No uint64
Abstain uint64
}

func (v *Votes) Add(vote Vote, power uint64) {
switch vote {
case VoteYes:
v.Yes += power
case VoteNo:
v.No += power
case VoteAbstain:
v.Abstain += power
default:
panic("unknown vote kind")
}
}

func (v *Votes) Remove(vote Vote, power uint64) {
switch vote {
case VoteYes:
v.Yes -= power
case VoteNo:
v.No -= power
case VoteAbstain:
v.Abstain -= power
default:
panic("unknown vote kind")
}
}

func (v *Votes) Total() uint64 {
return v.Yes + v.No + v.Abstain
}

func (v Votes) ToJSON() string {
return jsonutil.FormatObject([]jsonutil.KeyValue{
{Key: "yes", Value: v.Yes},
{Key: "no", Value: v.No},
{Key: "abstain", Value: v.Abstain},
})
}

type Proposal struct {
ID int
Title string
Description string
Proposer std.Address
Messages []ExecutableMessage
Ballots *avl.Tree // dev
// Ballots *avl.MutTree // test3
Votes Votes
Status ProposalStatus
}

var _ jsonutil.JSONAble = (*Proposal)(nil)

func (p Proposal) ToJSON() string {
return jsonutil.FormatObject([]jsonutil.KeyValue{
{Key: "id", Value: p.ID},
{Key: "title", Value: p.Title},
{Key: "description", Value: p.Description},
{Key: "proposer", Value: p.Proposer},
{Key: "messages", Value: jsonutil.FormatSlice(p.Messages), Raw: true},
{Key: "ballots", Value: p.Ballots},
{Key: "votes", Value: p.Votes},
{Key: "status", Value: p.Status},
})
}

type ProposalStatus int

const (
ProposalStatusOpen ProposalStatus = iota
ProposalStatusPassed
ProposalStatusExecuted
)

func (p ProposalStatus) ToJSON() string {
return jsonutil.FormatString(p.String())
}

func (p ProposalStatus) String() string {
switch p {
case ProposalStatusOpen:
return "Open"
case ProposalStatusPassed:
return "Passed"
case ProposalStatusExecuted:
return "Executed"
default:
return "Unknown(" + strconv.Itoa(int(p)) + ")"
}
}

type Vote int

const (
VoteYes Vote = iota
VoteNo
VoteAbstain
)

func (v Vote) ToJSON() string {
return jsonutil.FormatString(v.String())
}

func (v Vote) String() string {
switch v {
case VoteYes:
return "Yes"
case VoteNo:
return "No"
case VoteAbstain:
return "Abstain"
default:
return "Unknown(" + strconv.Itoa(int(v)) + ")"
}
}

type IProposalModule interface {
Propose(
title string,
description string,
actions []ExecutableMessage,
)
Vote(proposalId int, vote Vote, rationale string)
Execute(proposalId int)
Threshold() Threshold

Proposals() []Proposal
GetBallot(proposalId int, addr std.Address) Ballot

Render(path string) string
}

type ExecutableMessage interface {
String() string
Binary() []byte
Type() string
}
Loading

0 comments on commit fd76513

Please sign in to comment.