Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: lock token transfer and parameter module #3176

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 13 additions & 15 deletions contribs/gnodev/pkg/dev/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,9 @@
}

// generate genesis state
genesis := gnoland.GnoGenesisState{
Balances: cfg.BalancesList,
Txs: append(pkgsTxs, cfg.InitialTxs...),
}
genesis := gnoland.DefaultGenState()
genesis.Balances = cfg.BalancesList
genesis.Txs = append(pkgsTxs, cfg.InitialTxs...)

if err := devnode.rebuildNode(ctx, genesis); err != nil {
return nil, fmt.Errorf("unable to initialize the node: %w", err)
Expand Down Expand Up @@ -276,10 +275,9 @@

// Append initialTxs
txs := append(pkgsTxs, n.initialState...)
genesis := gnoland.GnoGenesisState{
Balances: n.config.BalancesList,
Txs: txs,
}
genesis := gnoland.DefaultGenState()
genesis.Balances = n.config.BalancesList
genesis.Txs = txs

// Reset the node with the new genesis state.
err = n.rebuildNode(ctx, genesis)
Expand Down Expand Up @@ -402,9 +400,10 @@
return fmt.Errorf("unable to load pkgs: %w", err)
}

return n.rebuildNode(ctx, gnoland.GnoGenesisState{
Balances: n.config.BalancesList, Txs: txs,
})
genesis := gnoland.DefaultGenState()
genesis.Balances = n.config.BalancesList
genesis.Txs = txs
return n.rebuildNode(ctx, genesis)

Check warning on line 406 in contribs/gnodev/pkg/dev/node.go

View check run for this annotation

Codecov / codecov/patch

contribs/gnodev/pkg/dev/node.go#L403-L406

Added lines #L403 - L406 were not covered by tests
}

state, err := n.getBlockStoreState(ctx)
Expand All @@ -419,10 +418,9 @@
}

// Create genesis with loaded pkgs + previous state
genesis := gnoland.GnoGenesisState{
Balances: n.config.BalancesList,
Txs: append(pkgsTxs, state...),
}
genesis := gnoland.DefaultGenState()
genesis.Balances = n.config.BalancesList
genesis.Txs = append(pkgsTxs, state...)

// Reset the node with the new genesis state.
err = n.rebuildNode(ctx, genesis)
Expand Down
15 changes: 7 additions & 8 deletions contribs/gnodev/pkg/dev/node_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,9 @@ func (n *Node) MoveBy(ctx context.Context, x int) error {
newState := n.state[:newIndex]

// Create genesis with loaded pkgs + previous state
genesis := gnoland.GnoGenesisState{
Balances: n.config.BalancesList,
Txs: append(pkgsTxs, newState...),
}
genesis := gnoland.DefaultGenState()
genesis.Balances = n.config.BalancesList
genesis.Txs = append(pkgsTxs, newState...)

// Reset the node with the new genesis state.
if err = n.rebuildNode(ctx, genesis); err != nil {
Expand Down Expand Up @@ -132,10 +131,10 @@ func (n *Node) ExportStateAsGenesis(ctx context.Context) (*bft.GenesisDoc, error

// Get current blockstore state
doc := *n.Node.GenesisDoc() // copy doc
doc.AppState = gnoland.GnoGenesisState{
Balances: n.config.BalancesList,
Txs: state,
}
genState := doc.AppState.(gnoland.GnoGenesisState)
genState.Balances = n.config.BalancesList
genState.Txs = state
doc.AppState = genState

return &doc, nil
}
1 change: 0 additions & 1 deletion examples/gno.land/r/sys/params/gno.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
module gno.land/r/sys/params

require (
gno.land/p/demo/dao v0.0.0-latest
gno.land/r/gov/dao/bridge v0.0.0-latest
Expand Down
54 changes: 0 additions & 54 deletions examples/gno.land/r/sys/params/params.gno

This file was deleted.

15 changes: 0 additions & 15 deletions examples/gno.land/r/sys/params/params_test.gno

This file was deleted.

39 changes: 39 additions & 0 deletions examples/gno.land/r/sys/params/unlock.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package params

import (
"std"

"gno.land/p/demo/dao"
"gno.land/r/gov/dao/bridge"
)

const lockSendKey = "lockSend.bool"
piux2 marked this conversation as resolved.
Show resolved Hide resolved
const UnlockSendDesc = "Proposal to unlock the sending functionality for ugnot."
const LockSendDesc = "Proposal to lock the sending functionality for ugnot."

func ProposeUnlockSend() uint64 {
callback := func() error {
std.SetParamBool(lockSendKey, false)
return nil
}
return propose(callback, UnlockSendDesc)
}

func ProposeLockSend() uint64 {
callback := func() error {
std.SetParamBool(lockSendKey, true)
return nil
}
return propose(callback, LockSendDesc)
}

func propose(callback func() error, desc string) uint64 {
// The callback function is executed only after the proposal is voted on
// and approved by the GovDAO.
exe := bridge.GovDAO().NewGovDAOExecutor(callback)
prop := dao.ProposalRequest{
Description: desc,
Executor: exe,
}
return bridge.GovDAO().Propose(prop)
}
49 changes: 49 additions & 0 deletions examples/gno.land/r/sys/params/unlock_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package params

import (
"testing"

"gno.land/p/demo/dao"
"gno.land/p/demo/simpledao"
"gno.land/p/demo/urequire"
"gno.land/r/gov/dao/bridge"
)

func TestProUnlockSend(t *testing.T) {
govdao := bridge.GovDAO()
id := ProposeUnlockSend()
p, err := govdao.GetPropStore().ProposalByID(id)
urequire.NoError(t, err)
urequire.Equal(t, UnlockSendDesc, p.Description())
}

func TestFailUnlockSend(t *testing.T) {
govdao := bridge.GovDAO()
id := ProposeUnlockSend()
urequire.PanicsWithMessage(
t,
simpledao.ErrProposalNotAccepted.Error(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we should standardize errors like these, to avoid having to import simpledao?
It would mean that the dao package would need to know about specific implementation details like errors, so I'm not sure if this is the way to go

cc @moul

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, GovDAO is a wrapper around the SimpleDAO. All voting and proposal functionality are implemented in SimpleDAO. I'm not sure if using the proposal errors defined in SimpleDAO will cause any issues down the line unless we decide to flatten the GovDAO implementation and stop wrapping the SimpleDAO package entirely.

On the other hand, whether GovDAO should be implemented as a SimpleDAO wrapper or not can be a separate topic.

func() {
govdao.ExecuteProposal(id)
},
)
}

func TestExeUnlockSend(t *testing.T) {
govdao := bridge.GovDAO()
id := ProposeUnlockSend()
p, err := govdao.GetPropStore().ProposalByID(id)
urequire.NoError(t, err)
urequire.True(t, dao.Active == p.Status())

govdao.VoteOnProposal(id, dao.YesVote)
urequire.True(t, dao.Accepted == p.Status())
urequire.NotPanics(
t,
func() {
govdao.ExecuteProposal(id)
},
)

urequire.True(t, dao.ExecutionSuccessful == p.Status())
}
8 changes: 4 additions & 4 deletions gno.land/cmd/gnoland/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,10 +410,10 @@ func generateGenesisFile(genesisFile string, pk crypto.PubKey, c *startCfg) erro
genesisTxs = append(pkgsTxs, genesisTxs...)

// Construct genesis AppState.
gen.AppState = gnoland.GnoGenesisState{
Balances: balances,
Txs: genesisTxs,
}
defaultGenState := gnoland.DefaultGenState()
defaultGenState.Balances = balances
defaultGenState.Txs = genesisTxs
gen.AppState = defaultGenState

// Write genesis state
if err := gen.SaveAs(genesisFile); err != nil {
Expand Down
54 changes: 54 additions & 0 deletions gno.land/cmd/gnoland/testdata/transfer_lock.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
## It tests locking token transfers while allowing the payment of gas fees.

## locking transfer applies to regular acocunts
adduser regular1


loadpkg gno.land/r/demo/wugnot
loadpkg gno.land/r/demo/echo

## start a new node.
## The -lock-transfer flag is intended for integration testing purposes
## and is not a valid application flag for gnoland.

gnoland start -lock-transfer

## User test1 is an unrestricted account specified in the genesis state
gnokey maketx send -send "9999999ugnot" -to $USER_ADDR_regular1 -gas-fee 1ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1

stdout 'OK!'

## Restricted simple token transfer
! gnokey maketx send -send "9999999ugnot" -to g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 -gas-fee 1ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test regular1
stderr 'restricted token transfer error'

## Restricted token transfer by calling a realm deposit function.
! gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Deposit -gas-fee 1000000ugnot -send "10000ugnot" -gas-wanted 2000000 -broadcast -chainid=tendermint_test regular1
stderr 'restricted token transfer error'


## Restricted token transfer with depositing to a realm package while adding a package.
! gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/bank -deposit "1000ugnot" -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test regular1
stderr 'restricted token transfer error'

## paying gas fees to add a package is acceptable.
gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/bank -gas-fee 1000000ugnot -gas-wanted 2500000 -broadcast -chainid=tendermint_test regular1
stdout 'OK!'

## paying gas fees to call a realm function is acceptable.
gnokey maketx call -pkgpath gno.land/r/demo/echo -func Render -args "Hello!" -gas-fee 1000000ugnot -gas-wanted 2500000 -broadcast -chainid=tendermint_test regular1
stdout 'Hello!'

-- bank.gno --
package bank
import (
"std"
)
func Withdraw(denom string, amt int64) string{
caller := std.GetOrigCaller()
coin := std.Coins{{denom, amt}}
banker := std.GetBanker(std.BankerTypeOrigSend)
pkgaddr := std.GetOrigPkgAddr()
banker.SendCoins(pkgaddr, caller, coin)
return "Withdrawed!"
}
42 changes: 42 additions & 0 deletions gno.land/cmd/gnoland/testdata/transfer_unlock.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
## It tests unlocking token transfers through GovDAO voting
loadpkg gno.land/r/sys/params
loadpkg gno.land/r/gov/dao/v2

patchpkg "g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm" "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5"

adduser regular1

## start a new node
gnoland start -lock-transfer

## User test1 is an unrestricted account specified in the genesis state
gnokey maketx send -send "9999999ugnot" -to $USER_ADDR_regular1 -gas-fee 1ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1

stdout 'OK!'

## Restricted simple token transfer for a regular account
! gnokey maketx send -send "100ugnot" -to g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 -gas-fee 1ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test regular1

stderr 'restricted token transfer error'

## Submit a proposal to unlock the transfer. When token transfer is locked, only the predefined unrestricted account test1 in the genesis state can
## pay the fee and submit a proposal to unlock the transfer.
gnokey maketx call -pkgpath gno.land/r/sys/params -func ProposeUnlockSend -send 250000000ugnot -gas-fee 1ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1

stdout '(0 uint64)'


## vote unlock proposal with unrestricted account test1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which accounts are going to be unrestricted in the initial version of the chain?

Copy link
Contributor Author

@piux2 piux2 Dec 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, all GovDAO accounts that need to vote must be unrestricted from token transfer locking, as voting on a proposal requires sending fees to the contract.

gnokey maketx call -pkgpath gno.land/r/gov/dao/v2 -func VoteOnProposal -args 0 -args "YES" -send 250000000ugnot -gas-fee 1ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1

stdout 'OK!'

## vote unlock proposal with unrestricted account test1
gnokey maketx call -pkgpath gno.land/r/gov/dao/v2 -func ExecuteProposal -args 0 -send 250000000ugnot -gas-fee 1ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1

stdout 'OK!'

## Restricted transfer is unlocked, allowing simple token transfers for regular accounts.
gnokey maketx send -send "100ugnot" -to g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 -gas-fee 1ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test regular1

stdout 'OK!'
Loading
Loading