Skip to content

Commit

Permalink
feat(gno/dao): create a proposal to post on social feed through dao (#…
Browse files Browse the repository at this point in the history
…1336)

* test: e2e test to create dao creation flow

* wip: e2e test to create dao creation flow

* wip: e2e test handle filling all steps in dao creation form

* wip: e2e test handle filling all steps in dao creation form

* wip: e2e test handle filling all steps in dao creation form

* wip: e2e test handle filling all steps in dao creation form

* fix: remove unused std from gno dao realm generation

* feat: add adena mock deploy pkg function

* fix: finish e2e test organization creation flow on gno

* chore: refactor project structure by moving all e2e test files into gno subfolder

* style: run eslint

* revert: useless modification on e2e test

* fix: delete useless pkg comment

* fix: run lint on networks files

* fix: delete useless console.log

* feat: use enum to handle adena type message value

* fix: delete mint & burn tori token for common dao

* fix(dao): remove modboard related code

* fix(gnovm): remove leftover of tori import

* feat: add a call to members JSON

* feat: add a call to members JSON

* fix: remove tori admin handler

* chore: run eslint

* fix: add a TODO to fix later the groupId

* fix: remove groupId

* fix: keep only e2e related code

* fix: keep only e2e related code

* fix(gno-daos): create proposal for post with DAO

* feat(dao): fix org on gno to post on social feed

* feat(dao): fix not enough funds by using user wallet instead of contract addr & same for proposal

* misc(dao): remove console log statements

* fix(dao): vote value

* chore: lint

* chore: gno lint

* chore: gno lint

* chore: gno lint

* fix: replace function by usage of lodash lib

* fix: check dao have enough money

* fix: look for balance of DAO not of user

* fix: remove double wait on tx causing infinite waiting time

* fix: parse user & network

* fix: simplify ternary operation

* chore: rename poster to author

---------

Co-authored-by: n0izn0iz <[email protected]>
  • Loading branch information
MikaelVallenet and n0izn0iz authored Nov 8, 2024
1 parent dec8594 commit 695c877
Show file tree
Hide file tree
Showing 18 changed files with 216 additions and 82 deletions.
1 change: 0 additions & 1 deletion gno/p/dao_voting_group/voting_group_test.gno
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dao_voting_group

import (
"std"
"testing"

dao_interfaces "gno.land/p/teritori/dao_interfaces"
Expand Down
2 changes: 1 addition & 1 deletion gno/p/markdown_utils/markdown_utils.gno
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ func Indent(markdown string) string {
// thanks copilot this is perfect xD
// I just renamed it, AddIndentationLevelToMarkdownTitles was too long

// blockchain + ai, invest quick!!!!
// blockchain + ai, invest quick!!!!
4 changes: 4 additions & 0 deletions gno/r/dao_realm/dao_realm.gno
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"gno.land/p/teritori/dao_utils"
voting_group "gno.land/p/teritori/dao_voting_group"
"gno.land/r/teritori/dao_registry"
"gno.land/r/teritori/social_feeds"
"gno.land/r/teritori/tori"
)

Expand Down Expand Up @@ -66,6 +67,9 @@ func init() {
func(core dao_interfaces.IDAOCore) dao_interfaces.MessageHandler {
return tori.NewChangeAdminHandler()
},
func(core dao_interfaces.IDAOCore) dao_interfaces.MessageHandler {
return social_feeds.NewCreatePostHandler()
},
}

daoCore = dao_core.NewDAOCore(votingModuleFactory, proposalModulesFactories, messageHandlersFactories)
Expand Down
5 changes: 0 additions & 5 deletions gno/r/dao_realm/dao_realm_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,11 @@ package dao_realm

import (
"fmt"
"std"
"testing"

"gno.land/p/demo/json"
dao_core "gno.land/p/teritori/dao_core"
dao_interfaces "gno.land/p/teritori/dao_interfaces"
proposal_single "gno.land/p/teritori/dao_proposal_single"
"gno.land/p/teritori/dao_voting_group"
"gno.land/p/teritori/havl"
"gno.land/r/demo/users"
)

func TestInit(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion gno/r/dao_realm/gno.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
gno.land/p/teritori/dao_utils v0.0.0-latest
gno.land/p/teritori/dao_voting_group v0.0.0-latest
gno.land/p/teritori/havl v0.0.0-latest
gno.land/r/demo/users v0.0.0-latest
gno.land/r/teritori/dao_registry v0.0.0-latest
gno.land/r/teritori/social_feeds v0.0.0-latest
gno.land/r/teritori/tori v0.0.0-latest
)
1 change: 1 addition & 0 deletions gno/r/social_feeds/feeds.gno
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ var (
//----------------------------------------
// Constants

// Feed name must be 3-30 characters long, starting with a lowercase letter
var reName = regexp.MustCompile(`^[a-z]+[_a-z0-9]{2,29}$`)
4 changes: 0 additions & 4 deletions gno/r/social_feeds/feeds_test.gno
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
package social_feeds

import (
"encoding/base64"
"fmt"
"std"
"strconv"
"strings"
"testing"

"gno.land/p/demo/avl"
"gno.land/p/demo/testutils"
ujson "gno.land/p/teritori/ujson"
)
Expand Down
77 changes: 75 additions & 2 deletions gno/r/social_feeds/messages.gno
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package social_feeds

import (
"strconv"
"strings"

"gno.land/p/demo/json"
Expand Down Expand Up @@ -63,8 +64,7 @@ func (msg *ExecutableMessageBanPost) String() string {
return strings.Join(ss, "\n---\n")
}

type BanPostHandler struct {
}
type BanPostHandler struct{}

var _ dao_interfaces.MessageHandler = (*BanPostHandler)(nil)

Expand All @@ -84,3 +84,76 @@ func (h BanPostHandler) Type() string {
func (h BanPostHandler) Instantiate() dao_interfaces.ExecutableMessage {
return &ExecutableMessageBanPost{}
}

// Create a new post
type ExecutableMessageCreatePost struct {
FeedID FeedID
ParentID PostID
Category uint64
Metadata string
}

var _ dao_interfaces.ExecutableMessage = (*ExecutableMessageCreatePost)(nil)

func (msg ExecutableMessageCreatePost) Type() string {
return "gno.land/r/teritori/social_feeds.CreatePost"
}

func (msg *ExecutableMessageCreatePost) ToJSON() *json.Node {
return json.ObjectNode("", map[string]*json.Node{
"feedId": jsonutil.IntNode(int(msg.FeedID)),
"parentId": jsonutil.IntNode(int(msg.ParentID)),
"category": jsonutil.IntNode(int(msg.Category)),
"metadata": json.StringNode("", msg.Metadata),
})
}

func (msg *ExecutableMessageCreatePost) FromJSON(ast *json.Node) {
obj := ast.MustObject()
msg.FeedID = FeedID(jsonutil.MustInt(obj["feedId"]))
msg.ParentID = PostID(jsonutil.MustInt(obj["parentId"]))
msg.Category = uint64(jsonutil.MustInt(obj["category"]))
msg.Metadata = obj["metadata"].MustString()
}

func (msg *ExecutableMessageCreatePost) String() string {
var ss []string
ss = append(ss, msg.Type())

feed := getFeed(msg.FeedID)
s := ""

if feed != nil {
s += "Feed: " + feed.name + " (" + feed.id.String() + ")"
s += "\nParent: " + msg.ParentID.String()
s += "\nCategory: " + strconv.Itoa(int(msg.Category))
s += "\nMetadata: " + msg.Metadata
} else {
s += "Feed: " + msg.FeedID.String() + " (not found)"
}

ss = append(ss, s)

return strings.Join(ss, "\n---\n")
}

type CreatePostHandler struct{}

var _ dao_interfaces.MessageHandler = (*CreatePostHandler)(nil)

func NewCreatePostHandler() *CreatePostHandler {
return &CreatePostHandler{}
}

func (h *CreatePostHandler) Execute(iMsg dao_interfaces.ExecutableMessage) {
msg := iMsg.(*ExecutableMessageCreatePost)
CreatePost(msg.FeedID, msg.ParentID, msg.Category, msg.Metadata)
}

func (h CreatePostHandler) Type() string {
return ExecutableMessageCreatePost{}.Type()
}

func (h CreatePostHandler) Instantiate() dao_interfaces.ExecutableMessage {
return &ExecutableMessageCreatePost{}
}
43 changes: 17 additions & 26 deletions packages/components/dao/ProposalActions.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { upperFirst } from "lodash";
import { View } from "react-native";

import { useFeedbacks } from "../../context/FeedbacksProvider";
Expand All @@ -10,15 +11,15 @@ import { useIsDAOMember } from "../../hooks/dao/useDAOMember";
import { useDAOFirstProposalModule } from "../../hooks/dao/useDAOProposalModules";
import { useInvalidateDAOProposals } from "../../hooks/dao/useDAOProposals";
import {
useInvalidateDAOVoteInfo,
useDAOVoteInfo,
useInvalidateDAOVoteInfo,
} from "../../hooks/dao/useDAOVoteInfo";
import { useSelectedNetworkId } from "../../hooks/useSelectedNetwork";
import useSelectedWallet from "../../hooks/useSelectedWallet";
import { NetworkKind, getNetwork, parseUserId } from "../../networks";
import { adenaVMCall } from "../../utils/gno";
import { GnoDAOVoteRequest } from "../../utils/gnodao/messages";
import { neutral77, primaryColor, errorColor } from "../../utils/style/colors";
import { errorColor, neutral77, primaryColor } from "../../utils/style/colors";
import { fontSemibold14 } from "../../utils/style/fonts";
import { BrandText } from "../BrandText";
import { PrimaryButton } from "../buttons/PrimaryButton";
Expand Down Expand Up @@ -80,34 +81,24 @@ export const ProposalActions: React.FC<{
case NetworkKind.Gno: {
const walletAddress = selectedWallet.address;
const [, pkgPath] = parseUserId(daoId);
let gnoVote;
switch (v) {
case "yes": {
gnoVote = 0;
break;
}
case "no": {
gnoVote = 1;
break;
}
case "abstain": {
gnoVote = 2;
break;
}
default:
throw new Error("invalid vote");
if (["yes", "no", "abstain"].indexOf(v) === -1) {
throw new Error("invalid vote");
}
const msg: GnoDAOVoteRequest = {
vote: gnoVote,
vote: upperFirst(v),
rationale: "Me like it",
};
await adenaVMCall(networkId, {
caller: walletAddress,
send: "",
pkg_path: pkgPath,
func: "VoteJSON",
args: ["0", proposal.id.toString(), JSON.stringify(msg)],
});
await adenaVMCall(
networkId,
{
caller: walletAddress,
send: "",
pkg_path: pkgPath,
func: "VoteJSON",
args: ["0", proposal.id.toString(), JSON.stringify(msg)],
},
{ gasWanted: 10000000 },
);
break;
}
default:
Expand Down
21 changes: 14 additions & 7 deletions packages/components/modals/NotEnoughFundModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import { Coin } from "../../api/teritori-chain/cosmos/base/v1beta1/coin";
import { useBalances } from "../../hooks/useBalances";
import { useSelectedNetworkInfo } from "../../hooks/useSelectedNetwork";
import useSelectedWallet from "../../hooks/useSelectedWallet";
import { getCurrency, getNativeCurrency, getNetwork } from "../../networks";
import {
getCurrency,
getNativeCurrency,
getNetwork,
parseUserId,
} from "../../networks";
import { prettyPrice } from "../../utils/coins";
import { neutral77 } from "../../utils/style/colors";
import { fontSemibold14, fontSemibold20 } from "../../utils/style/fonts";
Expand All @@ -28,13 +33,15 @@ export const NotEnoughFundsModal: FC<{
cost?: Coin;
label?: string;
visible?: boolean;
userId?: string;
onClose?: () => void;
}> = ({ label = "Not enough funds", cost, visible, onClose }) => {
}> = ({ label = "Not enough funds", cost, visible, onClose, userId }) => {
const selectedWallet = useSelectedWallet();
const selectedNetwork = useSelectedNetworkInfo();
const [userNetwork, userAddress] = parseUserId(userId);
const { balances } = useBalances(
selectedNetwork?.id,
selectedWallet?.address,
userNetwork?.id || selectedNetwork?.id,
userAddress || selectedWallet?.address,
);
const costBalance = balances.find((bal) => bal.denom === cost?.denom);
const currency = getCurrency(selectedNetwork?.id, cost?.denom);
Expand Down Expand Up @@ -75,7 +82,7 @@ export const NotEnoughFundsModal: FC<{
<WalletStatusBox />
<SpacerColumn size={2} />
<View>
{cost && costBalance && selectedNetwork && (
{cost && selectedNetwork && (
<>
<View
style={{
Expand Down Expand Up @@ -105,8 +112,8 @@ export const NotEnoughFundsModal: FC<{
<BrandText style={fontSemibold14}>
{prettyPrice(
selectedNetwork.id,
costBalance.amount,
costBalance.denom,
costBalance?.amount || "0",
cost.denom,
)}
</BrandText>
</View>
Expand Down
2 changes: 1 addition & 1 deletion packages/components/socialFeed/NewsFeed/NewsFeed.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import {
LayoutChangeEvent,
View,
useWindowDimensions,
View,
ViewStyle,
} from "react-native";
import Animated, {
Expand Down
15 changes: 9 additions & 6 deletions packages/components/socialFeed/NewsFeed/NewsFeedInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ import { useIpfs } from "@/hooks/useIpfs";
import { useMaxResolution } from "@/hooks/useMaxResolution";
import { useSelectedNetworkInfo } from "@/hooks/useSelectedNetwork";
import useSelectedWallet from "@/hooks/useSelectedWallet";
import { getNetworkFeature, getUserId, NetworkFeature } from "@/networks";
import { NetworkFeature, getNetworkFeature } from "@/networks";
import { selectNFTStorageAPI } from "@/store/slices/settings";
import { feedPostingStep, FeedPostingStepId } from "@/utils/feed/posting";
import { FeedPostingStepId, feedPostingStep } from "@/utils/feed/posting";
import { generatePostMetadata, getPostCategory } from "@/utils/feed/queries";
import { generateIpfsKey } from "@/utils/ipfs";
import {
Expand Down Expand Up @@ -141,7 +141,7 @@ export const NewsFeedInput = React.forwardRef<
const selectedNetwork = useSelectedNetworkInfo();
const selectedNetworkId = selectedNetwork?.id || "teritori";
const selectedWallet = useSelectedWallet();
const userId = getUserId(selectedNetworkId, selectedWallet?.address);
const authorId = daoId || selectedWallet?.userId;
const inputRef = useRef<TextInput>(null);
const { setToastError } = useFeedbacks();
const [isUploadLoading, setIsUploadLoading] = useState(false);
Expand Down Expand Up @@ -182,7 +182,7 @@ export const NewsFeedInput = React.forwardRef<
setStep,
} = useFeedPosting(
selectedNetwork?.id,
userId,
authorId,
postCategory,
onPostCreationSuccess,
);
Expand Down Expand Up @@ -210,16 +210,19 @@ export const NewsFeedInput = React.forwardRef<
});
return;
}

if (!canPayForPost) {
showNotEnoughFundsModal({
action,
cost: {
amount: publishingFee.toString(),
amount: publishingFee.amount.toString(),
denom: publishingFee.denom || "",
},
userId: authorId,
});
return;
}

setIsUploadLoading(true);
setIsProgressBarShown(true);
onSubmitInProgress && onSubmitInProgress();
Expand Down Expand Up @@ -258,7 +261,7 @@ export const NewsFeedInput = React.forwardRef<
setStep(feedPostingStep(FeedPostingStepId.GENERATING_KEY));

const pinataJWTKey =
userIPFSKey || (await generateIpfsKey(selectedNetworkId, userId));
userIPFSKey || (await generateIpfsKey(selectedNetworkId, authorId));

if (pinataJWTKey) {
setStep(feedPostingStep(FeedPostingStepId.UPLOADING_FILES));
Expand Down
2 changes: 1 addition & 1 deletion packages/components/socialFeed/modals/FlagConfirmModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const FlagConfirmModal: React.FC<FlagConfirmModalProps> = ({
const moduleIndex = "0";

const voteJSON: GnoDAOVoteRequest = {
vote: vote === "banPost" ? 0 : 1,
vote: vote === "banPost" ? "yes" : "no",
rationale: "",
};

Expand Down
Loading

0 comments on commit 695c877

Please sign in to comment.